@within-7/minto 0.1.7 → 0.3.0

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 (601) hide show
  1. package/cli.js +155 -37
  2. package/dist/Tool.js +38 -0
  3. package/dist/Tool.js.map +3 -3
  4. package/dist/commands/agents/AgentsCommand.js +73 -49
  5. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  6. package/dist/commands/agents/constants.js +1 -1
  7. package/dist/commands/agents/constants.js.map +1 -1
  8. package/dist/commands/agents/index.js +1 -1
  9. package/dist/commands/bug.js +74 -7
  10. package/dist/commands/bug.js.map +3 -3
  11. package/dist/commands/clear.js +3 -0
  12. package/dist/commands/clear.js.map +2 -2
  13. package/dist/commands/compact.js +37 -0
  14. package/dist/commands/compact.js.map +2 -2
  15. package/dist/commands/context.js +85 -0
  16. package/dist/commands/context.js.map +7 -0
  17. package/dist/commands/ctx_viz.js +18 -10
  18. package/dist/commands/ctx_viz.js.map +2 -2
  19. package/dist/commands/doctor.js +158 -12
  20. package/dist/commands/doctor.js.map +2 -2
  21. package/dist/commands/export.js +157 -0
  22. package/dist/commands/export.js.map +7 -0
  23. package/dist/commands/mcp-interactive.js +28 -18
  24. package/dist/commands/mcp-interactive.js.map +2 -2
  25. package/dist/commands/model.js +9 -7
  26. package/dist/commands/model.js.map +2 -2
  27. package/dist/commands/permissions.js +87 -0
  28. package/dist/commands/permissions.js.map +7 -0
  29. package/dist/commands/plugin/AddMarketplaceForm.js +3 -2
  30. package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
  31. package/dist/commands/plugin/ConfirmDialog.js +2 -1
  32. package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
  33. package/dist/commands/plugin/ErrorView.js +2 -1
  34. package/dist/commands/plugin/ErrorView.js.map +2 -2
  35. package/dist/commands/plugin/InstalledPluginsByMarketplace.js +5 -4
  36. package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
  37. package/dist/commands/plugin/InstalledPluginsManager.js +5 -4
  38. package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
  39. package/dist/commands/plugin/MainMenu.js +2 -1
  40. package/dist/commands/plugin/MainMenu.js.map +2 -2
  41. package/dist/commands/plugin/MarketplaceManager.js +5 -4
  42. package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
  43. package/dist/commands/plugin/MarketplaceSelector.js +4 -3
  44. package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
  45. package/dist/commands/plugin/PlaceholderScreen.js +3 -2
  46. package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
  47. package/dist/commands/plugin/PluginBrowser.js +6 -5
  48. package/dist/commands/plugin/PluginBrowser.js.map +2 -2
  49. package/dist/commands/plugin/PluginDetailsInstall.js +5 -4
  50. package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
  51. package/dist/commands/plugin/PluginDetailsManage.js +4 -3
  52. package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
  53. package/dist/commands/plugin.js +16 -15
  54. package/dist/commands/plugin.js.map +2 -2
  55. package/dist/commands/quit.js +3 -1
  56. package/dist/commands/quit.js.map +2 -2
  57. package/dist/commands/sandbox.js +105 -0
  58. package/dist/commands/sandbox.js.map +7 -0
  59. package/dist/commands/setup.js +2 -1
  60. package/dist/commands/setup.js.map +2 -2
  61. package/dist/commands/status.js +59 -0
  62. package/dist/commands/status.js.map +7 -0
  63. package/dist/commands/tasks.js +108 -0
  64. package/dist/commands/tasks.js.map +7 -0
  65. package/dist/commands/todos.js +123 -0
  66. package/dist/commands/todos.js.map +7 -0
  67. package/dist/commands/undo.js +245 -0
  68. package/dist/commands/undo.js.map +7 -0
  69. package/dist/commands.js +22 -2
  70. package/dist/commands.js.map +2 -2
  71. package/dist/components/AgentThinkingBlock.js +10 -18
  72. package/dist/components/AgentThinkingBlock.js.map +2 -2
  73. package/dist/components/AsciiLogo.js +7 -8
  74. package/dist/components/AsciiLogo.js.map +2 -2
  75. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
  76. package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
  77. package/dist/components/AskUserQuestionDialog/QuestionView.js +2 -1
  78. package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
  79. package/dist/components/BackgroundTasksPanel.js +78 -29
  80. package/dist/components/BackgroundTasksPanel.js.map +2 -2
  81. package/dist/components/BashStreamingProgress.js +24 -0
  82. package/dist/components/BashStreamingProgress.js.map +7 -0
  83. package/dist/components/CollapsibleHint.js +15 -0
  84. package/dist/components/CollapsibleHint.js.map +7 -0
  85. package/dist/components/Config.js +3 -2
  86. package/dist/components/Config.js.map +2 -2
  87. package/dist/components/ConsoleOAuthFlow.js +2 -1
  88. package/dist/components/ConsoleOAuthFlow.js.map +2 -2
  89. package/dist/components/Cost.js +2 -1
  90. package/dist/components/Cost.js.map +2 -2
  91. package/dist/components/FileEditToolUpdatedMessage.js +1 -1
  92. package/dist/components/FileEditToolUpdatedMessage.js.map +2 -2
  93. package/dist/components/HeaderBar.js +13 -8
  94. package/dist/components/HeaderBar.js.map +2 -2
  95. package/dist/components/HistorySearchOverlay.js +4 -3
  96. package/dist/components/HistorySearchOverlay.js.map +2 -2
  97. package/dist/components/HotkeyHelpPanel.js +134 -0
  98. package/dist/components/HotkeyHelpPanel.js.map +7 -0
  99. package/dist/components/InvalidConfigDialog.js +2 -1
  100. package/dist/components/InvalidConfigDialog.js.map +2 -2
  101. package/dist/components/Logo.js +24 -68
  102. package/dist/components/Logo.js.map +2 -2
  103. package/dist/components/MCPServerApprovalDialog.js +2 -1
  104. package/dist/components/MCPServerApprovalDialog.js.map +2 -2
  105. package/dist/components/MCPServerDialogCopy.js +2 -1
  106. package/dist/components/MCPServerDialogCopy.js.map +2 -2
  107. package/dist/components/MCPServerMultiselectDialog.js +2 -1
  108. package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
  109. package/dist/components/Message.js +23 -7
  110. package/dist/components/Message.js.map +3 -3
  111. package/dist/components/MessageSelector.js +4 -3
  112. package/dist/components/MessageSelector.js.map +2 -2
  113. package/dist/components/ModeIndicator.js +2 -1
  114. package/dist/components/ModeIndicator.js.map +2 -2
  115. package/dist/components/ModelConfig.js +20 -6
  116. package/dist/components/ModelConfig.js.map +2 -2
  117. package/dist/components/ModelListManager.js +7 -6
  118. package/dist/components/ModelListManager.js.map +2 -2
  119. package/dist/components/ModelSelector/ModelSelector.js +27 -14
  120. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  121. package/dist/components/Onboarding.js +22 -16
  122. package/dist/components/Onboarding.js.map +2 -2
  123. package/dist/components/OperationSummary.js +130 -0
  124. package/dist/components/OperationSummary.js.map +7 -0
  125. package/dist/components/ProgressBar.js +74 -0
  126. package/dist/components/ProgressBar.js.map +7 -0
  127. package/dist/components/PromptInput.js +210 -87
  128. package/dist/components/PromptInput.js.map +2 -2
  129. package/dist/components/RequestStatusIndicator.js +194 -0
  130. package/dist/components/RequestStatusIndicator.js.map +7 -0
  131. package/dist/components/SensitiveFileWarning.js +31 -0
  132. package/dist/components/SensitiveFileWarning.js.map +7 -0
  133. package/dist/components/Spinner.js +141 -27
  134. package/dist/components/Spinner.js.map +2 -2
  135. package/dist/components/SpinnerSymbol.js +21 -27
  136. package/dist/components/SpinnerSymbol.js.map +2 -2
  137. package/dist/components/StreamingBashOutput.js +9 -8
  138. package/dist/components/StreamingBashOutput.js.map +2 -2
  139. package/dist/components/StructuredDiff.js +6 -8
  140. package/dist/components/StructuredDiff.js.map +2 -2
  141. package/dist/components/SubagentBlock.js +5 -3
  142. package/dist/components/SubagentBlock.js.map +2 -2
  143. package/dist/components/SubagentProgress.js +17 -15
  144. package/dist/components/SubagentProgress.js.map +2 -2
  145. package/dist/components/TaskCard.js +30 -24
  146. package/dist/components/TaskCard.js.map +2 -2
  147. package/dist/components/TextInput.js +9 -1
  148. package/dist/components/TextInput.js.map +2 -2
  149. package/dist/components/TodoChangeBlock.js +1 -1
  150. package/dist/components/TodoChangeBlock.js.map +2 -2
  151. package/dist/components/TodoPanel.js +140 -31
  152. package/dist/components/TodoPanel.js.map +3 -3
  153. package/dist/components/TokenCounter.js +74 -0
  154. package/dist/components/TokenCounter.js.map +7 -0
  155. package/dist/components/TokenWarning.js +2 -1
  156. package/dist/components/TokenWarning.js.map +2 -2
  157. package/dist/components/ToolUseLoader.js +2 -2
  158. package/dist/components/ToolUseLoader.js.map +2 -2
  159. package/dist/components/TreeConnector.js +26 -0
  160. package/dist/components/TreeConnector.js.map +7 -0
  161. package/dist/components/TrustDialog.js +2 -1
  162. package/dist/components/TrustDialog.js.map +2 -2
  163. package/dist/components/TurnCompletionIndicator.js +18 -0
  164. package/dist/components/TurnCompletionIndicator.js.map +7 -0
  165. package/dist/components/binary-feedback/BinaryFeedbackView.js +2 -1
  166. package/dist/components/binary-feedback/BinaryFeedbackView.js.map +2 -2
  167. package/dist/components/messages/AssistantTextMessage.js +20 -9
  168. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  169. package/dist/components/messages/AssistantThinkingMessage.js +18 -3
  170. package/dist/components/messages/AssistantThinkingMessage.js.map +2 -2
  171. package/dist/components/messages/AssistantToolUseMessage.js +17 -10
  172. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  173. package/dist/components/messages/GroupRenderer.js +54 -0
  174. package/dist/components/messages/GroupRenderer.js.map +7 -0
  175. package/dist/components/messages/NestedTasksPreview.js +24 -0
  176. package/dist/components/messages/NestedTasksPreview.js.map +7 -0
  177. package/dist/components/messages/ParallelTasksGroupView.js +93 -0
  178. package/dist/components/messages/ParallelTasksGroupView.js.map +7 -0
  179. package/dist/components/messages/TaskInModuleView.js +218 -0
  180. package/dist/components/messages/TaskInModuleView.js.map +7 -0
  181. package/dist/components/messages/TaskOutputContent.js +56 -0
  182. package/dist/components/messages/TaskOutputContent.js.map +7 -0
  183. package/dist/components/messages/UserPromptMessage.js +2 -2
  184. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  185. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +2 -3
  186. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  187. package/dist/components/permissions/FallbackPermissionRequest.js +4 -4
  188. package/dist/components/permissions/FallbackPermissionRequest.js.map +2 -2
  189. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +4 -4
  190. package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +2 -2
  191. package/dist/constants/colors.js +120 -54
  192. package/dist/constants/colors.js.map +2 -2
  193. package/dist/constants/formatRules.js +102 -0
  194. package/dist/constants/formatRules.js.map +7 -0
  195. package/dist/constants/prompts.js +12 -34
  196. package/dist/constants/prompts.js.map +2 -2
  197. package/dist/constants/symbols.js +64 -6
  198. package/dist/constants/symbols.js.map +2 -2
  199. package/dist/constants/timing.js +5 -0
  200. package/dist/constants/timing.js.map +2 -2
  201. package/dist/constants/toolInputExamples.js +84 -0
  202. package/dist/constants/toolInputExamples.js.map +7 -0
  203. package/dist/core/backupManager.js +321 -0
  204. package/dist/core/backupManager.js.map +7 -0
  205. package/dist/core/config/defaults.js +84 -0
  206. package/dist/core/config/defaults.js.map +7 -0
  207. package/dist/core/config/index.js +111 -0
  208. package/dist/core/config/index.js.map +7 -0
  209. package/dist/core/config/loader.js +221 -0
  210. package/dist/core/config/loader.js.map +7 -0
  211. package/dist/core/config/migrations.js +128 -0
  212. package/dist/core/config/migrations.js.map +7 -0
  213. package/dist/core/config/schema.js +178 -0
  214. package/dist/core/config/schema.js.map +7 -0
  215. package/dist/core/costTracker.js +129 -0
  216. package/dist/core/costTracker.js.map +7 -0
  217. package/dist/core/gitAutoCommit.js +287 -0
  218. package/dist/core/gitAutoCommit.js.map +7 -0
  219. package/dist/core/index.js +8 -0
  220. package/dist/core/index.js.map +7 -0
  221. package/dist/core/operationTracker.js +212 -0
  222. package/dist/core/operationTracker.js.map +7 -0
  223. package/dist/core/permissions/auditLog.js +204 -0
  224. package/dist/core/permissions/auditLog.js.map +7 -0
  225. package/dist/core/permissions/engine/index.js +3 -0
  226. package/dist/core/permissions/engine/index.js.map +7 -0
  227. package/dist/core/permissions/engine/permissionEngine.js +106 -0
  228. package/dist/core/permissions/engine/permissionEngine.js.map +7 -0
  229. package/dist/core/permissions/engine/types.js +1 -0
  230. package/dist/core/permissions/engine/types.js.map +7 -0
  231. package/dist/core/permissions/index.js +84 -0
  232. package/dist/core/permissions/index.js.map +7 -0
  233. package/dist/core/permissions/ruleEngine.js +259 -0
  234. package/dist/core/permissions/ruleEngine.js.map +7 -0
  235. package/dist/core/permissions/rules/allowedToolsRule.js +62 -0
  236. package/dist/core/permissions/rules/allowedToolsRule.js.map +7 -0
  237. package/dist/core/permissions/rules/autoEscalationRule.js +296 -0
  238. package/dist/core/permissions/rules/autoEscalationRule.js.map +7 -0
  239. package/dist/core/permissions/rules/index.js +46 -0
  240. package/dist/core/permissions/rules/index.js.map +7 -0
  241. package/dist/core/permissions/rules/planModeRule.js +55 -0
  242. package/dist/core/permissions/rules/planModeRule.js.map +7 -0
  243. package/dist/core/permissions/rules/projectBoundaryRule.js +173 -0
  244. package/dist/core/permissions/rules/projectBoundaryRule.js.map +7 -0
  245. package/dist/core/permissions/rules/safeModeRule.js +65 -0
  246. package/dist/core/permissions/rules/safeModeRule.js.map +7 -0
  247. package/dist/core/permissions/rules/sensitivePathsRule.js +345 -0
  248. package/dist/core/permissions/rules/sensitivePathsRule.js.map +7 -0
  249. package/dist/core/permissions/types.js +127 -0
  250. package/dist/core/permissions/types.js.map +7 -0
  251. package/dist/core/tokenStats.js +9 -0
  252. package/dist/core/tokenStats.js.map +7 -0
  253. package/dist/core/tokenStatsManager.js +331 -0
  254. package/dist/core/tokenStatsManager.js.map +7 -0
  255. package/dist/core/tools/executor.js +143 -0
  256. package/dist/core/tools/executor.js.map +7 -0
  257. package/dist/core/tools/index.js +15 -0
  258. package/dist/core/tools/index.js.map +7 -0
  259. package/dist/core/tools/registry.js +183 -0
  260. package/dist/core/tools/registry.js.map +7 -0
  261. package/dist/core/tools/types.js +1 -0
  262. package/dist/core/tools/types.js.map +7 -0
  263. package/dist/cost-tracker.js +23 -15
  264. package/dist/cost-tracker.js.map +2 -2
  265. package/dist/entrypoints/cli.js +158 -130
  266. package/dist/entrypoints/cli.js.map +2 -2
  267. package/dist/entrypoints/mcp.js +12 -4
  268. package/dist/entrypoints/mcp.js.map +2 -2
  269. package/dist/history.js +14 -3
  270. package/dist/history.js.map +2 -2
  271. package/dist/hooks/useAgentTokenStats.js +72 -0
  272. package/dist/hooks/useAgentTokenStats.js.map +7 -0
  273. package/dist/hooks/useAgentTranscripts.js +140 -0
  274. package/dist/hooks/useAgentTranscripts.js.map +7 -0
  275. package/dist/hooks/useAnimationSync.js +53 -0
  276. package/dist/hooks/useAnimationSync.js.map +7 -0
  277. package/dist/hooks/useArrowKeyHistory.js +4 -2
  278. package/dist/hooks/useArrowKeyHistory.js.map +2 -2
  279. package/dist/hooks/useCanUseTool.js +3 -1
  280. package/dist/hooks/useCanUseTool.js.map +2 -2
  281. package/dist/hooks/useExitOnCtrlCD.js +9 -5
  282. package/dist/hooks/useExitOnCtrlCD.js.map +2 -2
  283. package/dist/hooks/useHookStatus.js +40 -0
  284. package/dist/hooks/useHookStatus.js.map +7 -0
  285. package/dist/hooks/useLogMessages.js +29 -2
  286. package/dist/hooks/useLogMessages.js.map +2 -2
  287. package/dist/hooks/useMessageGroups.js +43 -0
  288. package/dist/hooks/useMessageGroups.js.map +7 -0
  289. package/dist/hooks/useTerminalSize.js +62 -6
  290. package/dist/hooks/useTerminalSize.js.map +2 -2
  291. package/dist/hooks/useUnifiedCompletion.js +69 -0
  292. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  293. package/dist/i18n/index.js +109 -0
  294. package/dist/i18n/index.js.map +7 -0
  295. package/dist/i18n/locales/en.js +348 -0
  296. package/dist/i18n/locales/en.js.map +7 -0
  297. package/dist/i18n/locales/index.js +7 -0
  298. package/dist/i18n/locales/index.js.map +7 -0
  299. package/dist/i18n/locales/zh-CN.js +348 -0
  300. package/dist/i18n/locales/zh-CN.js.map +7 -0
  301. package/dist/i18n/types.js +8 -0
  302. package/dist/i18n/types.js.map +7 -0
  303. package/dist/permissions.js +28 -1
  304. package/dist/permissions.js.map +2 -2
  305. package/dist/query.js +253 -21
  306. package/dist/query.js.map +3 -3
  307. package/dist/screens/REPL.js +523 -194
  308. package/dist/screens/REPL.js.map +3 -3
  309. package/dist/services/adapters/chatCompletions.js +3 -1
  310. package/dist/services/adapters/chatCompletions.js.map +2 -2
  311. package/dist/services/adapters/messageNormalizer.js +354 -0
  312. package/dist/services/adapters/messageNormalizer.js.map +7 -0
  313. package/dist/services/adapters/responsesAPI.js +6 -3
  314. package/dist/services/adapters/responsesAPI.js.map +2 -2
  315. package/dist/services/checkpointManager.js +386 -0
  316. package/dist/services/checkpointManager.js.map +7 -0
  317. package/dist/services/claude.js +192 -14
  318. package/dist/services/claude.js.map +3 -3
  319. package/dist/services/compressionService.js +50 -1
  320. package/dist/services/compressionService.js.map +2 -2
  321. package/dist/services/contextMonitor.js +162 -0
  322. package/dist/services/contextMonitor.js.map +7 -0
  323. package/dist/services/customCommands.js +60 -41
  324. package/dist/services/customCommands.js.map +2 -2
  325. package/dist/services/hookExecutor.js +173 -1
  326. package/dist/services/hookExecutor.js.map +2 -2
  327. package/dist/services/intelligentCompactor.js +281 -0
  328. package/dist/services/intelligentCompactor.js.map +7 -0
  329. package/dist/services/lspConfig.js +109 -0
  330. package/dist/services/lspConfig.js.map +7 -0
  331. package/dist/services/mcpClient.js +338 -43
  332. package/dist/services/mcpClient.js.map +2 -2
  333. package/dist/services/modelOrchestrator.js +310 -0
  334. package/dist/services/modelOrchestrator.js.map +7 -0
  335. package/dist/services/openai.js +8 -1
  336. package/dist/services/openai.js.map +2 -2
  337. package/dist/services/outputStyles.js +138 -0
  338. package/dist/services/outputStyles.js.map +7 -0
  339. package/dist/services/plugins/index.js +5 -0
  340. package/dist/services/plugins/index.js.map +7 -0
  341. package/dist/services/plugins/lspServers.js +188 -0
  342. package/dist/services/plugins/lspServers.js.map +7 -0
  343. package/dist/services/plugins/pluginRuntime.js +229 -0
  344. package/dist/services/plugins/pluginRuntime.js.map +7 -0
  345. package/dist/services/plugins/pluginValidation.js +219 -0
  346. package/dist/services/plugins/pluginValidation.js.map +7 -0
  347. package/dist/services/plugins/skillMarketplace.js +556 -0
  348. package/dist/services/plugins/skillMarketplace.js.map +7 -0
  349. package/dist/services/responseStateManager.js +37 -3
  350. package/dist/services/responseStateManager.js.map +2 -2
  351. package/dist/services/sandbox/filesystemBoundary.js +341 -0
  352. package/dist/services/sandbox/filesystemBoundary.js.map +7 -0
  353. package/dist/services/sandbox/index.js +14 -0
  354. package/dist/services/sandbox/index.js.map +7 -0
  355. package/dist/services/sandbox/networkProxy.js +293 -0
  356. package/dist/services/sandbox/networkProxy.js.map +7 -0
  357. package/dist/services/sandbox/sandboxController.js +574 -0
  358. package/dist/services/sandbox/sandboxController.js.map +7 -0
  359. package/dist/services/sandbox/types.js +50 -0
  360. package/dist/services/sandbox/types.js.map +7 -0
  361. package/dist/services/sessionMemory.js +266 -0
  362. package/dist/services/sessionMemory.js.map +7 -0
  363. package/dist/services/taskRouter.js +324 -0
  364. package/dist/services/taskRouter.js.map +7 -0
  365. package/dist/tools/ArchitectTool/ArchitectTool.js +7 -1
  366. package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
  367. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +6 -2
  368. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  369. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +2 -1
  370. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
  371. package/dist/tools/BaseTool.js +72 -0
  372. package/dist/tools/BaseTool.js.map +7 -0
  373. package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js +3 -0
  374. package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js.map +2 -2
  375. package/dist/tools/BashTool/BashTool.js +79 -3
  376. package/dist/tools/BashTool/BashTool.js.map +2 -2
  377. package/dist/tools/BashTool/BashToolResultMessage.js +3 -0
  378. package/dist/tools/BashTool/BashToolResultMessage.js.map +2 -2
  379. package/dist/tools/BashTool/OutputLine.js +54 -0
  380. package/dist/tools/BashTool/OutputLine.js.map +2 -2
  381. package/dist/tools/BashTool/prompt.js +336 -3
  382. package/dist/tools/BashTool/prompt.js.map +2 -2
  383. package/dist/tools/FileEditTool/FileEditTool.js +29 -4
  384. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  385. package/dist/tools/FileEditTool/prompt.js +6 -3
  386. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  387. package/dist/tools/FileWriteTool/FileWriteTool.js +5 -5
  388. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  389. package/dist/tools/FileWriteTool/prompt.js +4 -2
  390. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  391. package/dist/tools/GlobTool/GlobTool.js +4 -2
  392. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  393. package/dist/tools/GrepTool/GrepTool.js +36 -7
  394. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  395. package/dist/tools/KillShellTool/KillShellToolResultMessage.js +3 -0
  396. package/dist/tools/KillShellTool/KillShellToolResultMessage.js.map +2 -2
  397. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +109 -0
  398. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +7 -0
  399. package/dist/tools/ListMcpResourcesTool/prompt.js +19 -0
  400. package/dist/tools/ListMcpResourcesTool/prompt.js.map +7 -0
  401. package/dist/tools/LspTool/LspTool.js +664 -0
  402. package/dist/tools/LspTool/LspTool.js.map +7 -0
  403. package/dist/tools/LspTool/prompt.js +27 -0
  404. package/dist/tools/LspTool/prompt.js.map +7 -0
  405. package/dist/tools/MCPTool/MCPTool.js +9 -1
  406. package/dist/tools/MCPTool/MCPTool.js.map +2 -2
  407. package/dist/tools/MemoryReadTool/MemoryReadTool.js +19 -6
  408. package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
  409. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +6 -6
  410. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
  411. package/dist/tools/MultiEditTool/MultiEditTool.js +19 -2
  412. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  413. package/dist/tools/MultiEditTool/prompt.js +5 -3
  414. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  415. package/dist/tools/NotebookEditTool/NotebookEditTool.js +7 -2
  416. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  417. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
  418. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +75 -0
  419. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +7 -0
  420. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +109 -0
  421. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +7 -0
  422. package/dist/tools/PlanModeTool/prompt.js +94 -0
  423. package/dist/tools/PlanModeTool/prompt.js.map +7 -0
  424. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +130 -0
  425. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +7 -0
  426. package/dist/tools/ReadMcpResourceTool/prompt.js +17 -0
  427. package/dist/tools/ReadMcpResourceTool/prompt.js.map +7 -0
  428. package/dist/tools/SkillTool/SkillTool.js +10 -4
  429. package/dist/tools/SkillTool/SkillTool.js.map +2 -2
  430. package/dist/tools/SkillTool/prompt.js +1 -1
  431. package/dist/tools/SkillTool/prompt.js.map +1 -1
  432. package/dist/tools/SlashCommandTool/SlashCommandTool.js +260 -0
  433. package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +7 -0
  434. package/dist/tools/SlashCommandTool/prompt.js +35 -0
  435. package/dist/tools/SlashCommandTool/prompt.js.map +7 -0
  436. package/dist/tools/TaskOutputTool/TaskOutputTool.js +190 -0
  437. package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +7 -0
  438. package/dist/tools/TaskOutputTool/prompt.js +15 -0
  439. package/dist/tools/TaskOutputTool/prompt.js.map +7 -0
  440. package/dist/tools/TaskTool/TaskTool.js +310 -104
  441. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  442. package/dist/tools/TaskTool/prompt.js.map +2 -2
  443. package/dist/tools/TodoWriteTool/TodoWriteTool.js +42 -77
  444. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
  445. package/dist/tools/URLFetcherTool/URLFetcherTool.js +4 -1
  446. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  447. package/dist/tools/URLFetcherTool/cache.js +55 -8
  448. package/dist/tools/URLFetcherTool/cache.js.map +2 -2
  449. package/dist/tools.js +31 -2
  450. package/dist/tools.js.map +2 -2
  451. package/dist/types/hooks.js +4 -0
  452. package/dist/types/hooks.js.map +2 -2
  453. package/dist/types/marketplace.js.map +2 -2
  454. package/dist/types/messageGroup.js +36 -0
  455. package/dist/types/messageGroup.js.map +7 -0
  456. package/dist/types/plugin.js.map +2 -2
  457. package/dist/types/thinking.js +1 -0
  458. package/dist/types/thinking.js.map +7 -0
  459. package/dist/utils/BackgroundShellManager.js +136 -39
  460. package/dist/utils/BackgroundShellManager.js.map +2 -2
  461. package/dist/utils/CircuitBreaker.js +242 -0
  462. package/dist/utils/CircuitBreaker.js.map +7 -0
  463. package/dist/utils/MessageBatchBuffer.js +102 -0
  464. package/dist/utils/MessageBatchBuffer.js.map +7 -0
  465. package/dist/utils/PersistentShell.js +151 -1
  466. package/dist/utils/PersistentShell.js.map +2 -2
  467. package/dist/utils/agentLoader.js +1 -23
  468. package/dist/utils/agentLoader.js.map +2 -2
  469. package/dist/utils/agentTranscripts.js +641 -0
  470. package/dist/utils/agentTranscripts.js.map +7 -0
  471. package/dist/utils/animationManager.js +213 -0
  472. package/dist/utils/animationManager.js.map +7 -0
  473. package/dist/utils/animationSync.js +110 -0
  474. package/dist/utils/animationSync.js.map +7 -0
  475. package/dist/utils/ask.js +2 -0
  476. package/dist/utils/ask.js.map +2 -2
  477. package/dist/utils/asyncFile.js +215 -0
  478. package/dist/utils/asyncFile.js.map +7 -0
  479. package/dist/utils/backgroundAgentManager.js +231 -0
  480. package/dist/utils/backgroundAgentManager.js.map +7 -0
  481. package/dist/utils/config.js +108 -10
  482. package/dist/utils/config.js.map +2 -2
  483. package/dist/utils/conversationRecovery.js +19 -0
  484. package/dist/utils/conversationRecovery.js.map +2 -2
  485. package/dist/utils/credentials/CredentialStore.js +1 -0
  486. package/dist/utils/credentials/CredentialStore.js.map +7 -0
  487. package/dist/utils/credentials/EncryptedFileStore.js +157 -0
  488. package/dist/utils/credentials/EncryptedFileStore.js.map +7 -0
  489. package/dist/utils/credentials/index.js +37 -0
  490. package/dist/utils/credentials/index.js.map +7 -0
  491. package/dist/utils/credentials/migration.js +82 -0
  492. package/dist/utils/credentials/migration.js.map +7 -0
  493. package/dist/utils/exit.js +73 -0
  494. package/dist/utils/exit.js.map +7 -0
  495. package/dist/utils/format.js +73 -5
  496. package/dist/utils/format.js.map +2 -2
  497. package/dist/utils/generators.js +76 -6
  498. package/dist/utils/generators.js.map +2 -2
  499. package/dist/utils/globalErrorHandler.js +149 -0
  500. package/dist/utils/globalErrorHandler.js.map +7 -0
  501. package/dist/utils/groupHandlers/index.js +8 -0
  502. package/dist/utils/groupHandlers/index.js.map +7 -0
  503. package/dist/utils/groupHandlers/parallelTasksHandler.js +140 -0
  504. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +7 -0
  505. package/dist/utils/groupHandlers/taskHandler.js +104 -0
  506. package/dist/utils/groupHandlers/taskHandler.js.map +7 -0
  507. package/dist/utils/groupHandlers/types.js +1 -0
  508. package/dist/utils/groupHandlers/types.js.map +7 -0
  509. package/dist/utils/logRotation.js +224 -0
  510. package/dist/utils/logRotation.js.map +7 -0
  511. package/dist/utils/markdown.js +13 -1
  512. package/dist/utils/markdown.js.map +2 -2
  513. package/dist/utils/marketplaceManager.js +3 -5
  514. package/dist/utils/marketplaceManager.js.map +2 -2
  515. package/dist/utils/memSafety.js +264 -0
  516. package/dist/utils/memSafety.js.map +7 -0
  517. package/dist/utils/messageGroupManager.js +274 -0
  518. package/dist/utils/messageGroupManager.js.map +7 -0
  519. package/dist/utils/messages.js +13 -4
  520. package/dist/utils/messages.js.map +2 -2
  521. package/dist/utils/model.js +119 -15
  522. package/dist/utils/model.js.map +3 -3
  523. package/dist/utils/permissions/filesystem.js +162 -6
  524. package/dist/utils/permissions/filesystem.js.map +2 -2
  525. package/dist/utils/plan/planMode.js +143 -0
  526. package/dist/utils/plan/planMode.js.map +7 -0
  527. package/dist/utils/pluginLoader.js +17 -21
  528. package/dist/utils/pluginLoader.js.map +2 -2
  529. package/dist/utils/ripgrep.js +55 -2
  530. package/dist/utils/ripgrep.js.map +2 -2
  531. package/dist/utils/safePath.js +132 -0
  532. package/dist/utils/safePath.js.map +7 -0
  533. package/dist/utils/sanitizeInput.js +32 -0
  534. package/dist/utils/sanitizeInput.js.map +7 -0
  535. package/dist/utils/secureKeyStorage.js +312 -0
  536. package/dist/utils/secureKeyStorage.js.map +7 -0
  537. package/dist/utils/sensitiveFiles.js +125 -0
  538. package/dist/utils/sensitiveFiles.js.map +7 -0
  539. package/dist/utils/session/sessionPlugins.js +67 -0
  540. package/dist/utils/session/sessionPlugins.js.map +7 -0
  541. package/dist/utils/taskDisplayUtils.js +257 -0
  542. package/dist/utils/taskDisplayUtils.js.map +7 -0
  543. package/dist/utils/teamConfig.js +2 -1
  544. package/dist/utils/teamConfig.js.map +2 -2
  545. package/dist/utils/theme.js +6 -6
  546. package/dist/utils/theme.js.map +1 -1
  547. package/dist/utils/todoStorage.js +92 -2
  548. package/dist/utils/todoStorage.js.map +2 -2
  549. package/dist/utils/toolRiskClassification.js +207 -0
  550. package/dist/utils/toolRiskClassification.js.map +7 -0
  551. package/dist/utils/toolTimeout.js +136 -0
  552. package/dist/utils/toolTimeout.js.map +7 -0
  553. package/dist/utils/tooling/safeRender.js +116 -0
  554. package/dist/utils/tooling/safeRender.js.map +7 -0
  555. package/dist/utils/userFriendlyError.js +346 -0
  556. package/dist/utils/userFriendlyError.js.map +7 -0
  557. package/dist/utils/vendor/ripgrep/arm64-darwin/rg +0 -0
  558. package/dist/version.js +2 -2
  559. package/dist/version.js.map +1 -1
  560. package/package.json +17 -5
  561. package/scripts/postinstall.js +128 -38
  562. package/dist/commands/agents.js +0 -2086
  563. package/dist/commands/agents.js.map +0 -7
  564. package/dist/commands/build.js +0 -74
  565. package/dist/commands/build.js.map +0 -7
  566. package/dist/commands/compression.js +0 -57
  567. package/dist/commands/compression.js.map +0 -7
  568. package/dist/commands/listen.js +0 -37
  569. package/dist/commands/listen.js.map +0 -7
  570. package/dist/commands/login.js +0 -37
  571. package/dist/commands/login.js.map +0 -7
  572. package/dist/commands/logout.js +0 -33
  573. package/dist/commands/logout.js.map +0 -7
  574. package/dist/commands/mcp.js +0 -40
  575. package/dist/commands/mcp.js.map +0 -7
  576. package/dist/commands/mcp_refresh.js +0 -40
  577. package/dist/commands/mcp_refresh.js.map +0 -7
  578. package/dist/commands/modelstatus.js +0 -21
  579. package/dist/commands/modelstatus.js.map +0 -7
  580. package/dist/commands/onboarding.js +0 -36
  581. package/dist/commands/onboarding.js.map +0 -7
  582. package/dist/commands/plugin-interactive.js +0 -446
  583. package/dist/commands/plugin-interactive.js.map +0 -7
  584. package/dist/commands/pr_comments.js +0 -61
  585. package/dist/commands/pr_comments.js.map +0 -7
  586. package/dist/commands/release-notes.js +0 -30
  587. package/dist/commands/release-notes.js.map +0 -7
  588. package/dist/commands/review.js +0 -51
  589. package/dist/commands/review.js.map +0 -7
  590. package/dist/components/Bug.js +0 -147
  591. package/dist/components/Bug.js.map +0 -7
  592. package/dist/components/ModelSelector.js +0 -2062
  593. package/dist/components/ModelSelector.js.map +0 -7
  594. package/dist/components/ModelStatusDisplay.js +0 -87
  595. package/dist/components/ModelStatusDisplay.js.map +0 -7
  596. package/dist/entrypoints/cli-wrapper.js +0 -61
  597. package/dist/entrypoints/cli-wrapper.js.map +0 -7
  598. package/dist/hooks/useCancelRequest.js +0 -28
  599. package/dist/hooks/useCancelRequest.js.map +0 -7
  600. package/dist/screens/Doctor.js +0 -22
  601. package/dist/screens/Doctor.js.map +0 -7
@@ -0,0 +1,157 @@
1
+ import {
2
+ createCipheriv,
3
+ createDecipheriv,
4
+ randomBytes,
5
+ scryptSync
6
+ } from "crypto";
7
+ import {
8
+ readFileSync,
9
+ writeFileSync,
10
+ existsSync,
11
+ chmodSync,
12
+ mkdirSync
13
+ } from "fs";
14
+ import { join } from "path";
15
+ import { homedir, hostname } from "os";
16
+ import { debug as debugLogger } from "../debugLogger.js";
17
+ const ALGORITHM = "aes-256-gcm";
18
+ const SALT = "minto-credentials-salt-v1";
19
+ const CREDENTIALS_DIR = join(homedir(), ".minto");
20
+ const CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.enc");
21
+ function getMachineId() {
22
+ const username = process.env.USER || process.env.USERNAME || "unknown";
23
+ const machineHostname = hostname();
24
+ const homeDir = homedir();
25
+ return `${machineHostname}:${username}:${homeDir}`;
26
+ }
27
+ class EncryptedFileStore {
28
+ /**
29
+ * Derive a consistent encryption key from the machine ID using scrypt KDF
30
+ */
31
+ getEncryptionKey() {
32
+ const machineId = getMachineId();
33
+ return scryptSync(machineId, SALT, 32);
34
+ }
35
+ /**
36
+ * Ensure credentials directory exists with proper permissions
37
+ */
38
+ ensureCredentialsDir() {
39
+ if (!existsSync(CREDENTIALS_DIR)) {
40
+ mkdirSync(CREDENTIALS_DIR, { mode: 448, recursive: true });
41
+ }
42
+ }
43
+ /**
44
+ * Load and decrypt credentials from disk
45
+ */
46
+ loadCredentials() {
47
+ if (!existsSync(CREDENTIALS_FILE)) {
48
+ debugLogger.state("CREDENTIALS_FILE_NOT_FOUND", {
49
+ path: CREDENTIALS_FILE
50
+ });
51
+ return {};
52
+ }
53
+ try {
54
+ const encryptedData = readFileSync(CREDENTIALS_FILE);
55
+ if (encryptedData.length < 32) {
56
+ debugLogger.warn("CREDENTIALS_FILE_TOO_SHORT", {
57
+ path: CREDENTIALS_FILE,
58
+ size: encryptedData.length
59
+ });
60
+ return {};
61
+ }
62
+ const iv = encryptedData.subarray(0, 16);
63
+ const authTag = encryptedData.subarray(16, 32);
64
+ const encrypted = encryptedData.subarray(32);
65
+ const key = this.getEncryptionKey();
66
+ const decipher = createDecipheriv(ALGORITHM, key, iv);
67
+ decipher.setAuthTag(authTag);
68
+ const decrypted = Buffer.concat([
69
+ decipher.update(encrypted),
70
+ decipher.final()
71
+ ]);
72
+ const credentials = JSON.parse(decrypted.toString("utf-8"));
73
+ debugLogger.state("CREDENTIALS_LOADED", {
74
+ path: CREDENTIALS_FILE,
75
+ count: Object.keys(credentials).length
76
+ });
77
+ return credentials;
78
+ } catch (error) {
79
+ const errorMsg = error instanceof Error ? error.message : String(error);
80
+ debugLogger.error("CREDENTIALS_LOAD_ERROR", {
81
+ path: CREDENTIALS_FILE,
82
+ error: errorMsg,
83
+ errorType: error instanceof Error ? error.constructor.name : typeof error
84
+ });
85
+ return {};
86
+ }
87
+ }
88
+ /**
89
+ * Encrypt and save credentials to disk
90
+ */
91
+ saveCredentials(credentials) {
92
+ try {
93
+ this.ensureCredentialsDir();
94
+ const key = this.getEncryptionKey();
95
+ const iv = randomBytes(16);
96
+ const cipher = createCipheriv(ALGORITHM, key, iv);
97
+ const plaintext = JSON.stringify(credentials);
98
+ const encrypted = Buffer.concat([
99
+ cipher.update(plaintext, "utf-8"),
100
+ cipher.final()
101
+ ]);
102
+ const authTag = cipher.getAuthTag();
103
+ const combined = Buffer.concat([iv, authTag, encrypted]);
104
+ writeFileSync(CREDENTIALS_FILE, combined);
105
+ chmodSync(CREDENTIALS_FILE, 384);
106
+ debugLogger.state("CREDENTIALS_SAVED", {
107
+ path: CREDENTIALS_FILE,
108
+ size: combined.length
109
+ });
110
+ } catch (error) {
111
+ const errorMsg = error instanceof Error ? error.message : String(error);
112
+ debugLogger.error("CREDENTIALS_SAVE_ERROR", {
113
+ path: CREDENTIALS_FILE,
114
+ error: errorMsg
115
+ });
116
+ throw error;
117
+ }
118
+ }
119
+ /**
120
+ * Generate a composite key for storing credentials
121
+ */
122
+ makeKey(service, account) {
123
+ return `${service}:${account}`;
124
+ }
125
+ async get(service, account) {
126
+ const credentials = this.loadCredentials();
127
+ const key = this.makeKey(service, account);
128
+ return credentials[key] ?? null;
129
+ }
130
+ async set(service, account, password) {
131
+ const credentials = this.loadCredentials();
132
+ credentials[this.makeKey(service, account)] = password;
133
+ this.saveCredentials(credentials);
134
+ }
135
+ async delete(service, account) {
136
+ const credentials = this.loadCredentials();
137
+ const key = this.makeKey(service, account);
138
+ delete credentials[key];
139
+ this.saveCredentials(credentials);
140
+ }
141
+ async findCredentials(service) {
142
+ const credentials = this.loadCredentials();
143
+ const prefix = `${service}:`;
144
+ const results = [];
145
+ for (const [key, password] of Object.entries(credentials)) {
146
+ if (key.startsWith(prefix)) {
147
+ const account = key.slice(prefix.length);
148
+ results.push({ account, password });
149
+ }
150
+ }
151
+ return results;
152
+ }
153
+ }
154
+ export {
155
+ EncryptedFileStore
156
+ };
157
+ //# sourceMappingURL=EncryptedFileStore.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/utils/credentials/EncryptedFileStore.ts"],
4
+ "sourcesContent": ["import {\n createCipheriv,\n createDecipheriv,\n randomBytes,\n scryptSync,\n} from 'crypto'\nimport {\n readFileSync,\n writeFileSync,\n existsSync,\n chmodSync,\n mkdirSync,\n} from 'fs'\nimport { join, dirname } from 'path'\nimport { homedir, hostname } from 'os'\nimport type { CredentialStore } from './CredentialStore'\nimport { debug as debugLogger } from '../debugLogger'\n\nconst ALGORITHM = 'aes-256-gcm'\nconst SALT = 'minto-credentials-salt-v1'\nconst CREDENTIALS_DIR = join(homedir(), '.minto')\nconst CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.enc')\n\n/**\n * Get a machine identifier for deterministic key derivation.\n * Uses hostname + username + homedir to create a stable machine-specific identifier.\n */\nfunction getMachineId(): string {\n const username = process.env.USER || process.env.USERNAME || 'unknown'\n const machineHostname = hostname()\n const homeDir = homedir()\n return `${machineHostname}:${username}:${homeDir}`\n}\n\n/**\n * Encrypted file-based credential store using AES-256-GCM encryption.\n * Credentials are stored in ~/.minto/credentials.enc with machine-specific encryption.\n */\nexport class EncryptedFileStore implements CredentialStore {\n /**\n * Derive a consistent encryption key from the machine ID using scrypt KDF\n */\n private getEncryptionKey(): Buffer {\n const machineId = getMachineId()\n // scrypt(password, salt, keylen, options)\n return scryptSync(machineId, SALT, 32)\n }\n\n /**\n * Ensure credentials directory exists with proper permissions\n */\n private ensureCredentialsDir(): void {\n if (!existsSync(CREDENTIALS_DIR)) {\n mkdirSync(CREDENTIALS_DIR, { mode: 0o700, recursive: true })\n }\n }\n\n /**\n * Load and decrypt credentials from disk\n */\n private loadCredentials(): Record<string, string> {\n if (!existsSync(CREDENTIALS_FILE)) {\n debugLogger.state('CREDENTIALS_FILE_NOT_FOUND', {\n path: CREDENTIALS_FILE,\n })\n return {}\n }\n\n try {\n const encryptedData = readFileSync(CREDENTIALS_FILE)\n\n // Format: iv (16) + authTag (16) + encryptedContent\n if (encryptedData.length < 32) {\n debugLogger.warn('CREDENTIALS_FILE_TOO_SHORT', {\n path: CREDENTIALS_FILE,\n size: encryptedData.length,\n })\n return {}\n }\n\n const iv = encryptedData.subarray(0, 16)\n const authTag = encryptedData.subarray(16, 32)\n const encrypted = encryptedData.subarray(32)\n\n const key = this.getEncryptionKey()\n const decipher = createDecipheriv(ALGORITHM, key, iv)\n decipher.setAuthTag(authTag)\n\n const decrypted = Buffer.concat([\n decipher.update(encrypted),\n decipher.final(),\n ])\n\n const credentials = JSON.parse(decrypted.toString('utf-8'))\n debugLogger.state('CREDENTIALS_LOADED', {\n path: CREDENTIALS_FILE,\n count: Object.keys(credentials).length,\n })\n\n return credentials as Record<string, string>\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n debugLogger.error('CREDENTIALS_LOAD_ERROR', {\n path: CREDENTIALS_FILE,\n error: errorMsg,\n errorType:\n error instanceof Error ? error.constructor.name : typeof error,\n })\n return {}\n }\n }\n\n /**\n * Encrypt and save credentials to disk\n */\n private saveCredentials(credentials: Record<string, string>): void {\n try {\n this.ensureCredentialsDir()\n\n const key = this.getEncryptionKey()\n const iv = randomBytes(16)\n const cipher = createCipheriv(ALGORITHM, key, iv)\n\n const plaintext = JSON.stringify(credentials)\n const encrypted = Buffer.concat([\n cipher.update(plaintext, 'utf-8'),\n cipher.final(),\n ])\n const authTag = cipher.getAuthTag()\n\n // Format: iv (16) + authTag (16) + encryptedContent\n const combined = Buffer.concat([iv, authTag, encrypted])\n\n writeFileSync(CREDENTIALS_FILE, combined)\n // Set strict permissions: readable/writable only by owner\n chmodSync(CREDENTIALS_FILE, 0o600)\n\n debugLogger.state('CREDENTIALS_SAVED', {\n path: CREDENTIALS_FILE,\n size: combined.length,\n })\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n debugLogger.error('CREDENTIALS_SAVE_ERROR', {\n path: CREDENTIALS_FILE,\n error: errorMsg,\n })\n throw error\n }\n }\n\n /**\n * Generate a composite key for storing credentials\n */\n private makeKey(service: string, account: string): string {\n return `${service}:${account}`\n }\n\n async get(service: string, account: string): Promise<string | null> {\n const credentials = this.loadCredentials()\n const key = this.makeKey(service, account)\n return credentials[key] ?? null\n }\n\n async set(service: string, account: string, password: string): Promise<void> {\n const credentials = this.loadCredentials()\n credentials[this.makeKey(service, account)] = password\n this.saveCredentials(credentials)\n }\n\n async delete(service: string, account: string): Promise<void> {\n const credentials = this.loadCredentials()\n const key = this.makeKey(service, account)\n delete credentials[key]\n this.saveCredentials(credentials)\n }\n\n async findCredentials(\n service: string,\n ): Promise<{ account: string; password: string }[]> {\n const credentials = this.loadCredentials()\n const prefix = `${service}:`\n const results: { account: string; password: string }[] = []\n\n for (const [key, password] of Object.entries(credentials)) {\n if (key.startsWith(prefix)) {\n const account = key.slice(prefix.length)\n results.push({ account, password })\n }\n }\n\n return results\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,37 @@
1
+ import { EncryptedFileStore } from "./EncryptedFileStore.js";
2
+ let store = null;
3
+ const SERVICE_NAME = "minto-api";
4
+ function getCredentialStore() {
5
+ if (!store) {
6
+ store = new EncryptedFileStore();
7
+ }
8
+ return store;
9
+ }
10
+ function resetCredentialStore() {
11
+ store = null;
12
+ }
13
+ async function getApiKey(modelName) {
14
+ return getCredentialStore().get(SERVICE_NAME, modelName);
15
+ }
16
+ async function setApiKey(modelName, apiKey) {
17
+ return getCredentialStore().set(SERVICE_NAME, modelName, apiKey);
18
+ }
19
+ async function deleteApiKey(modelName) {
20
+ return getCredentialStore().delete(SERVICE_NAME, modelName);
21
+ }
22
+ async function findAllApiKeys() {
23
+ const credentials = await getCredentialStore().findCredentials(SERVICE_NAME);
24
+ return credentials.map(({ account, password }) => ({
25
+ modelName: account,
26
+ apiKey: password
27
+ }));
28
+ }
29
+ export {
30
+ deleteApiKey,
31
+ findAllApiKeys,
32
+ getApiKey,
33
+ getCredentialStore,
34
+ resetCredentialStore,
35
+ setApiKey
36
+ };
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/utils/credentials/index.ts"],
4
+ "sourcesContent": ["import { EncryptedFileStore } from './EncryptedFileStore'\nimport type { CredentialStore } from './CredentialStore'\n\n// Current credential store implementation (using encrypted files)\n// In Phase 2, this can be extended to support keytar for native OS keychains\nlet store: CredentialStore | null = null\n\nconst SERVICE_NAME = 'minto-api'\n\n/**\n * Get the current credential store instance\n * Currently uses encrypted file storage; will be extended to support keytar in Phase 2\n */\nexport function getCredentialStore(): CredentialStore {\n if (!store) {\n store = new EncryptedFileStore()\n }\n return store\n}\n\n/**\n * Reset the credential store (primarily for testing)\n */\nexport function resetCredentialStore(): void {\n store = null\n}\n\n/**\n * Retrieve an API key for a specific model from the credential store.\n * Returns null if the key is not found.\n *\n * @param modelName The name of the model to retrieve the API key for\n * @returns The API key or null if not stored in credential store\n */\nexport async function getApiKey(modelName: string): Promise<string | null> {\n return getCredentialStore().get(SERVICE_NAME, modelName)\n}\n\n/**\n * Store an API key for a specific model in the credential store.\n * This stores the key securely in encrypted storage.\n *\n * @param modelName The name of the model\n * @param apiKey The API key to store\n */\nexport async function setApiKey(\n modelName: string,\n apiKey: string,\n): Promise<void> {\n return getCredentialStore().set(SERVICE_NAME, modelName, apiKey)\n}\n\n/**\n * Delete an API key for a specific model from the credential store.\n *\n * @param modelName The name of the model\n */\nexport async function deleteApiKey(modelName: string): Promise<void> {\n return getCredentialStore().delete(SERVICE_NAME, modelName)\n}\n\n/**\n * Find all stored API keys for the service\n *\n * @returns Array of model names and their API keys\n */\nexport async function findAllApiKeys(): Promise<\n { modelName: string; apiKey: string }[]\n> {\n const credentials = await getCredentialStore().findCredentials(SERVICE_NAME)\n return credentials.map(({ account, password }) => ({\n modelName: account,\n apiKey: password,\n }))\n}\n"],
5
+ "mappings": "AAAA,SAAS,0BAA0B;AAKnC,IAAI,QAAgC;AAEpC,MAAM,eAAe;AAMd,SAAS,qBAAsC;AACpD,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,mBAAmB;AAAA,EACjC;AACA,SAAO;AACT;AAKO,SAAS,uBAA6B;AAC3C,UAAQ;AACV;AASA,eAAsB,UAAU,WAA2C;AACzE,SAAO,mBAAmB,EAAE,IAAI,cAAc,SAAS;AACzD;AASA,eAAsB,UACpB,WACA,QACe;AACf,SAAO,mBAAmB,EAAE,IAAI,cAAc,WAAW,MAAM;AACjE;AAOA,eAAsB,aAAa,WAAkC;AACnE,SAAO,mBAAmB,EAAE,OAAO,cAAc,SAAS;AAC5D;AAOA,eAAsB,iBAEpB;AACA,QAAM,cAAc,MAAM,mBAAmB,EAAE,gBAAgB,YAAY;AAC3E,SAAO,YAAY,IAAI,CAAC,EAAE,SAAS,SAAS,OAAO;AAAA,IACjD,WAAW;AAAA,IACX,QAAQ;AAAA,EACV,EAAE;AACJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,82 @@
1
+ import { getGlobalConfig, saveGlobalConfig } from "../config.js";
2
+ import { setApiKey } from "./index.js";
3
+ import { debug as debugLogger } from "../debugLogger.js";
4
+ async function migrateApiKeysToEncrypted() {
5
+ const config = getGlobalConfig();
6
+ let migrated = 0;
7
+ let skipped = 0;
8
+ const errors = [];
9
+ if (!config.modelProfiles || config.modelProfiles.length === 0) {
10
+ debugLogger.state("MIGRATION_NO_PROFILES", {});
11
+ return { migrated: 0, errors: [], skipped: 0 };
12
+ }
13
+ try {
14
+ debugLogger.state("MIGRATION_START", {
15
+ profileCount: config.modelProfiles.length
16
+ });
17
+ const migratedProfiles = await Promise.all(
18
+ config.modelProfiles.map(async (profile) => {
19
+ if (!profile.apiKey) {
20
+ skipped++;
21
+ return profile;
22
+ }
23
+ if (profile.apiKey.startsWith("encrypted:")) {
24
+ debugLogger.state("MIGRATION_SKIP_ALREADY_ENCRYPTED", {
25
+ modelName: profile.modelName
26
+ });
27
+ skipped++;
28
+ return profile;
29
+ }
30
+ try {
31
+ await setApiKey(profile.modelName, profile.apiKey);
32
+ const migratedProfile = {
33
+ ...profile,
34
+ apiKey: `encrypted:${profile.modelName}`
35
+ };
36
+ debugLogger.state("MIGRATION_SUCCESS", {
37
+ modelName: profile.modelName,
38
+ provider: profile.provider
39
+ });
40
+ migrated++;
41
+ return migratedProfile;
42
+ } catch (error) {
43
+ const errorMsg = error instanceof Error ? error.message : String(error);
44
+ const errorText = `Failed to migrate ${profile.modelName}: ${errorMsg}`;
45
+ errors.push(errorText);
46
+ debugLogger.error("MIGRATION_PROFILE_ERROR", {
47
+ modelName: profile.modelName,
48
+ error: errorMsg
49
+ });
50
+ return profile;
51
+ }
52
+ })
53
+ );
54
+ if (migrated > 0) {
55
+ const updatedConfig = {
56
+ ...config,
57
+ modelProfiles: migratedProfiles
58
+ };
59
+ saveGlobalConfig(updatedConfig);
60
+ debugLogger.state("MIGRATION_CONFIG_SAVED", {
61
+ profilesMigrated: migrated,
62
+ profilesSkipped: skipped
63
+ });
64
+ }
65
+ debugLogger.state("MIGRATION_COMPLETE", {
66
+ migrated,
67
+ skipped,
68
+ errors: errors.length
69
+ });
70
+ } catch (error) {
71
+ const errorMsg = error instanceof Error ? error.message : String(error);
72
+ debugLogger.error("MIGRATION_FATAL_ERROR", {
73
+ error: errorMsg
74
+ });
75
+ errors.push(`Fatal migration error: ${errorMsg}`);
76
+ }
77
+ return { migrated, errors, skipped };
78
+ }
79
+ export {
80
+ migrateApiKeysToEncrypted
81
+ };
82
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/utils/credentials/migration.ts"],
4
+ "sourcesContent": ["import { getGlobalConfig, saveGlobalConfig, type GlobalConfig } from '../config'\nimport { setApiKey } from './index'\nimport { debug as debugLogger } from '../debugLogger'\n\nexport interface MigrationResult {\n migrated: number\n errors: string[]\n skipped: number\n}\n\n/**\n * Migrate API keys from plaintext config to encrypted credential store.\n * This function:\n * 1. Reads all model profiles from the global config\n * 2. For each profile with a plaintext apiKey (not already encrypted):\n * - Stores the key in the encrypted credential store\n * - Updates the config to use the `encrypted:modelName` reference\n * 3. Saves the updated config\n *\n * After migration, the actual API keys are removed from the config file and stored\n * securely in ~/.minto/credentials.enc\n *\n * @returns Migration result with counts of migrated, skipped, and error entries\n */\nexport async function migrateApiKeysToEncrypted(): Promise<MigrationResult> {\n const config = getGlobalConfig()\n let migrated = 0\n let skipped = 0\n const errors: string[] = []\n\n if (!config.modelProfiles || config.modelProfiles.length === 0) {\n debugLogger.state('MIGRATION_NO_PROFILES', {})\n return { migrated: 0, errors: [], skipped: 0 }\n }\n\n try {\n debugLogger.state('MIGRATION_START', {\n profileCount: config.modelProfiles.length,\n })\n\n // Process each model profile\n const migratedProfiles = await Promise.all(\n config.modelProfiles.map(async profile => {\n if (!profile.apiKey) {\n skipped++\n return profile\n }\n\n // Skip if already encrypted\n if (profile.apiKey.startsWith('encrypted:')) {\n debugLogger.state('MIGRATION_SKIP_ALREADY_ENCRYPTED', {\n modelName: profile.modelName,\n })\n skipped++\n return profile\n }\n\n try {\n // Store the plaintext key in encrypted credential store\n await setApiKey(profile.modelName, profile.apiKey)\n\n // Update the profile to reference the encrypted key\n const migratedProfile = {\n ...profile,\n apiKey: `encrypted:${profile.modelName}`,\n }\n\n debugLogger.state('MIGRATION_SUCCESS', {\n modelName: profile.modelName,\n provider: profile.provider,\n })\n\n migrated++\n return migratedProfile\n } catch (error) {\n const errorMsg =\n error instanceof Error ? error.message : String(error)\n const errorText = `Failed to migrate ${profile.modelName}: ${errorMsg}`\n errors.push(errorText)\n debugLogger.error('MIGRATION_PROFILE_ERROR', {\n modelName: profile.modelName,\n error: errorMsg,\n })\n // Return unchanged profile on error\n return profile\n }\n }),\n )\n\n // Save the migrated config only if something changed\n if (migrated > 0) {\n const updatedConfig: GlobalConfig = {\n ...config,\n modelProfiles: migratedProfiles,\n }\n saveGlobalConfig(updatedConfig)\n debugLogger.state('MIGRATION_CONFIG_SAVED', {\n profilesMigrated: migrated,\n profilesSkipped: skipped,\n })\n }\n\n debugLogger.state('MIGRATION_COMPLETE', {\n migrated,\n skipped,\n errors: errors.length,\n })\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error)\n debugLogger.error('MIGRATION_FATAL_ERROR', {\n error: errorMsg,\n })\n errors.push(`Fatal migration error: ${errorMsg}`)\n }\n\n return { migrated, errors, skipped }\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAiB,wBAA2C;AACrE,SAAS,iBAAiB;AAC1B,SAAS,SAAS,mBAAmB;AAsBrC,eAAsB,4BAAsD;AAC1E,QAAM,SAAS,gBAAgB;AAC/B,MAAI,WAAW;AACf,MAAI,UAAU;AACd,QAAM,SAAmB,CAAC;AAE1B,MAAI,CAAC,OAAO,iBAAiB,OAAO,cAAc,WAAW,GAAG;AAC9D,gBAAY,MAAM,yBAAyB,CAAC,CAAC;AAC7C,WAAO,EAAE,UAAU,GAAG,QAAQ,CAAC,GAAG,SAAS,EAAE;AAAA,EAC/C;AAEA,MAAI;AACF,gBAAY,MAAM,mBAAmB;AAAA,MACnC,cAAc,OAAO,cAAc;AAAA,IACrC,CAAC;AAGD,UAAM,mBAAmB,MAAM,QAAQ;AAAA,MACrC,OAAO,cAAc,IAAI,OAAM,YAAW;AACxC,YAAI,CAAC,QAAQ,QAAQ;AACnB;AACA,iBAAO;AAAA,QACT;AAGA,YAAI,QAAQ,OAAO,WAAW,YAAY,GAAG;AAC3C,sBAAY,MAAM,oCAAoC;AAAA,YACpD,WAAW,QAAQ;AAAA,UACrB,CAAC;AACD;AACA,iBAAO;AAAA,QACT;AAEA,YAAI;AAEF,gBAAM,UAAU,QAAQ,WAAW,QAAQ,MAAM;AAGjD,gBAAM,kBAAkB;AAAA,YACtB,GAAG;AAAA,YACH,QAAQ,aAAa,QAAQ,SAAS;AAAA,UACxC;AAEA,sBAAY,MAAM,qBAAqB;AAAA,YACrC,WAAW,QAAQ;AAAA,YACnB,UAAU,QAAQ;AAAA,UACpB,CAAC;AAED;AACA,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,WACJ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACvD,gBAAM,YAAY,qBAAqB,QAAQ,SAAS,KAAK,QAAQ;AACrE,iBAAO,KAAK,SAAS;AACrB,sBAAY,MAAM,2BAA2B;AAAA,YAC3C,WAAW,QAAQ;AAAA,YACnB,OAAO;AAAA,UACT,CAAC;AAED,iBAAO;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI,WAAW,GAAG;AAChB,YAAM,gBAA8B;AAAA,QAClC,GAAG;AAAA,QACH,eAAe;AAAA,MACjB;AACA,uBAAiB,aAAa;AAC9B,kBAAY,MAAM,0BAA0B;AAAA,QAC1C,kBAAkB;AAAA,QAClB,iBAAiB;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,gBAAY,MAAM,sBAAsB;AAAA,MACtC;AAAA,MACA;AAAA,MACA,QAAQ,OAAO;AAAA,IACjB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,WAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACtE,gBAAY,MAAM,yBAAyB;AAAA,MACzC,OAAO;AAAA,IACT,CAAC;AACD,WAAO,KAAK,0BAA0B,QAAQ,EAAE;AAAA,EAClD;AAEA,SAAO,EAAE,UAAU,QAAQ,QAAQ;AACrC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,73 @@
1
+ import { PersistentShell } from "./PersistentShell.js";
2
+ import { shutdownMCPClients } from "../services/mcpClient.js";
3
+ let isShuttingDown = false;
4
+ function resetCursor() {
5
+ const cursorShow = "\x1B[?25h";
6
+ const terminal = process.stderr.isTTY ? process.stderr : process.stdout.isTTY ? process.stdout : void 0;
7
+ terminal?.write(`\x1B[?25h${cursorShow}`);
8
+ }
9
+ async function gracefulExit(code = 0) {
10
+ if (isShuttingDown) {
11
+ return;
12
+ }
13
+ isShuttingDown = true;
14
+ try {
15
+ resetCursor();
16
+ } catch {
17
+ }
18
+ try {
19
+ PersistentShell.getInstance().close();
20
+ } catch {
21
+ }
22
+ try {
23
+ await shutdownMCPClients();
24
+ } catch {
25
+ }
26
+ process.exit(code);
27
+ }
28
+ function setupExitHandlers() {
29
+ process.on("SIGINT", () => {
30
+ gracefulExit(0);
31
+ });
32
+ process.on("SIGTERM", () => {
33
+ gracefulExit(0);
34
+ });
35
+ process.on("SIGBREAK", () => {
36
+ gracefulExit(0);
37
+ });
38
+ process.on("exit", () => {
39
+ try {
40
+ resetCursor();
41
+ } catch {
42
+ }
43
+ try {
44
+ PersistentShell.getInstance().close();
45
+ } catch {
46
+ }
47
+ });
48
+ process.on("unhandledRejection", (err) => {
49
+ const isTimeoutError = err instanceof Error && (err.name === "TimeoutError" || err.message?.includes("timed out") || err.message?.includes("timeout"));
50
+ const isDOMTimeoutError = err && typeof err === "object" && "name" in err && err.name === "TimeoutError";
51
+ if (isTimeoutError || isDOMTimeoutError) {
52
+ console.error(
53
+ "\u26A0\uFE0F Operation timed out:",
54
+ err instanceof Error ? err.message : err
55
+ );
56
+ console.error(
57
+ " The operation will be retried or skipped. You can continue working."
58
+ );
59
+ return;
60
+ }
61
+ console.error("Unhandled rejection:", err);
62
+ gracefulExit(1);
63
+ });
64
+ process.on("uncaughtException", (err) => {
65
+ console.error("Uncaught exception:", err);
66
+ gracefulExit(1);
67
+ });
68
+ }
69
+ export {
70
+ gracefulExit,
71
+ setupExitHandlers
72
+ };
73
+ //# sourceMappingURL=exit.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/exit.ts"],
4
+ "sourcesContent": ["/**\n * Graceful exit utilities\n *\n * Provides a centralized way to exit the application gracefully,\n * ensuring resources are cleaned up properly.\n *\n * NOTE: Cost summary is now handled by useCostSummary() in cost-tracker.ts\n * which matches Kode-cli's implementation exactly.\n */\n\nimport { PersistentShell } from './PersistentShell'\nimport { shutdownMCPClients } from '../services/mcpClient'\n\n// Track if we're already shutting down to prevent multiple cleanup attempts\nlet isShuttingDown = false\n\n/**\n * Reset cursor visibility\n */\nfunction resetCursor() {\n const cursorShow = '\\x1B[?25h'\n const terminal = process.stderr.isTTY\n ? process.stderr\n : process.stdout.isTTY\n ? process.stdout\n : undefined\n terminal?.write(`\\u001B[?25h${cursorShow}`)\n}\n\n/**\n * Exit gracefully with proper cleanup\n *\n * NOTE: Cost summary is NOT printed here. It's handled by useCostSummary()\n * hook's process.on('exit') handler, matching Kode-cli's pattern.\n *\n * @param code Exit code (default: 0)\n */\nexport async function gracefulExit(code = 0): Promise<void> {\n if (isShuttingDown) {\n return\n }\n isShuttingDown = true\n\n try {\n resetCursor()\n } catch {}\n\n try {\n PersistentShell.getInstance().close()\n } catch {}\n\n try {\n await shutdownMCPClients()\n } catch {}\n\n process.exit(code)\n}\n\n/**\n * Setup exit handlers for various signals and events\n * Should be called once during application initialization\n *\n * NOTE: Cost summary output is handled by useCostSummary() in cost-tracker.ts,\n * NOT here. This matches Kode-cli's architecture.\n */\nexport function setupExitHandlers(): void {\n // Handle graceful shutdown signals\n process.on('SIGINT', () => {\n gracefulExit(0)\n })\n\n process.on('SIGTERM', () => {\n gracefulExit(0)\n })\n\n // Windows CTRL+BREAK\n process.on('SIGBREAK', () => {\n gracefulExit(0)\n })\n\n // Final cleanup on exit (cost summary handled by useCostSummary)\n process.on('exit', () => {\n try {\n resetCursor()\n } catch {}\n try {\n PersistentShell.getInstance().close()\n } catch {}\n })\n\n // Handle unhandled rejections\n process.on('unhandledRejection', err => {\n // Check if this is a timeout error that we can handle gracefully\n const isTimeoutError =\n err instanceof Error &&\n (err.name === 'TimeoutError' ||\n err.message?.includes('timed out') ||\n err.message?.includes('timeout'))\n\n const isDOMTimeoutError =\n err &&\n typeof err === 'object' &&\n 'name' in err &&\n (err as { name: string }).name === 'TimeoutError'\n\n if (isTimeoutError || isDOMTimeoutError) {\n // Log timeout errors but don't exit - they're often recoverable\n console.error(\n '\u26A0\uFE0F Operation timed out:',\n err instanceof Error ? err.message : err,\n )\n console.error(\n ' The operation will be retried or skipped. You can continue working.',\n )\n return\n }\n\n // For other unhandled rejections, log and exit\n console.error('Unhandled rejection:', err)\n gracefulExit(1)\n })\n\n // Handle uncaught exceptions\n process.on('uncaughtException', err => {\n console.error('Uncaught exception:', err)\n gracefulExit(1)\n })\n}\n"],
5
+ "mappings": "AAUA,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AAGnC,IAAI,iBAAiB;AAKrB,SAAS,cAAc;AACrB,QAAM,aAAa;AACnB,QAAM,WAAW,QAAQ,OAAO,QAC5B,QAAQ,SACR,QAAQ,OAAO,QACb,QAAQ,SACR;AACN,YAAU,MAAM,YAAc,UAAU,EAAE;AAC5C;AAUA,eAAsB,aAAa,OAAO,GAAkB;AAC1D,MAAI,gBAAgB;AAClB;AAAA,EACF;AACA,mBAAiB;AAEjB,MAAI;AACF,gBAAY;AAAA,EACd,QAAQ;AAAA,EAAC;AAET,MAAI;AACF,oBAAgB,YAAY,EAAE,MAAM;AAAA,EACtC,QAAQ;AAAA,EAAC;AAET,MAAI;AACF,UAAM,mBAAmB;AAAA,EAC3B,QAAQ;AAAA,EAAC;AAET,UAAQ,KAAK,IAAI;AACnB;AASO,SAAS,oBAA0B;AAExC,UAAQ,GAAG,UAAU,MAAM;AACzB,iBAAa,CAAC;AAAA,EAChB,CAAC;AAED,UAAQ,GAAG,WAAW,MAAM;AAC1B,iBAAa,CAAC;AAAA,EAChB,CAAC;AAGD,UAAQ,GAAG,YAAY,MAAM;AAC3B,iBAAa,CAAC;AAAA,EAChB,CAAC;AAGD,UAAQ,GAAG,QAAQ,MAAM;AACvB,QAAI;AACF,kBAAY;AAAA,IACd,QAAQ;AAAA,IAAC;AACT,QAAI;AACF,sBAAgB,YAAY,EAAE,MAAM;AAAA,IACtC,QAAQ;AAAA,IAAC;AAAA,EACX,CAAC;AAGD,UAAQ,GAAG,sBAAsB,SAAO;AAEtC,UAAM,iBACJ,eAAe,UACd,IAAI,SAAS,kBACZ,IAAI,SAAS,SAAS,WAAW,KACjC,IAAI,SAAS,SAAS,SAAS;AAEnC,UAAM,oBACJ,OACA,OAAO,QAAQ,YACf,UAAU,OACT,IAAyB,SAAS;AAErC,QAAI,kBAAkB,mBAAmB;AAEvC,cAAQ;AAAA,QACN;AAAA,QACA,eAAe,QAAQ,IAAI,UAAU;AAAA,MACvC;AACA,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AAGA,YAAQ,MAAM,wBAAwB,GAAG;AACzC,iBAAa,CAAC;AAAA,EAChB,CAAC;AAGD,UAAQ,GAAG,qBAAqB,SAAO;AACrC,YAAQ,MAAM,uBAAuB,GAAG;AACxC,iBAAa,CAAC;AAAA,EAChB,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -13,12 +13,13 @@ function wrapText(text, width) {
13
13
  return lines;
14
14
  }
15
15
  function formatDuration(ms) {
16
- if (ms < 6e4) {
17
- return `${(ms / 1e3).toFixed(1)}s`;
16
+ const totalSeconds = Math.floor(ms / 1e3);
17
+ if (totalSeconds < 60) {
18
+ return `${totalSeconds}s`;
18
19
  }
19
- const hours = Math.floor(ms / 36e5);
20
- const minutes = Math.floor(ms % 36e5 / 6e4);
21
- const seconds = (ms % 6e4 / 1e3).toFixed(1);
20
+ const hours = Math.floor(totalSeconds / 3600);
21
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
22
+ const seconds = totalSeconds % 60;
22
23
  if (hours > 0) {
23
24
  return `${hours}h ${minutes}m ${seconds}s`;
24
25
  }
@@ -33,9 +34,76 @@ function formatNumber(number) {
33
34
  maximumFractionDigits: 1
34
35
  }).format(number).toLowerCase();
35
36
  }
37
+ function formatTokens(tokens) {
38
+ if (tokens < 1e3) {
39
+ return `${tokens} tokens`;
40
+ }
41
+ return `${formatNumber(tokens)} tokens`;
42
+ }
43
+ function formatContextUsage(usedTokens, maxTokens) {
44
+ const percentage = usedTokens / maxTokens * 100;
45
+ const formatted = formatNumber(usedTokens);
46
+ if (percentage <= 50) {
47
+ return `${formatted}/${formatNumber(maxTokens)} (${percentage.toFixed(0)}%)`;
48
+ } else if (percentage <= 80) {
49
+ return `${formatted}/${formatNumber(maxTokens)} (${percentage.toFixed(0)}% \u26A0\uFE0F)`;
50
+ } else {
51
+ return `${formatted}/${formatNumber(maxTokens)} (${percentage.toFixed(0)}% \u{1F534})`;
52
+ }
53
+ }
54
+ function formatTimestamp(timestamp) {
55
+ const date = typeof timestamp === "number" ? new Date(timestamp) : timestamp;
56
+ return date.toLocaleTimeString("en-US", {
57
+ hour: "numeric",
58
+ minute: "2-digit",
59
+ hour12: true
60
+ });
61
+ }
62
+ function formatUrl(url, maxLength = 60) {
63
+ try {
64
+ const decoded = decodeURIComponent(url);
65
+ if (decoded.length <= maxLength) {
66
+ return decoded;
67
+ }
68
+ const urlObj = new URL(decoded);
69
+ const host = urlObj.host;
70
+ const pathStart = urlObj.pathname.slice(0, 20);
71
+ const remaining = maxLength - host.length - pathStart.length - 6;
72
+ if (remaining > 10) {
73
+ const pathEnd = urlObj.pathname.slice(-remaining);
74
+ return `${host}${pathStart}...${pathEnd}`;
75
+ }
76
+ return decoded.slice(0, maxLength - 3) + "...";
77
+ } catch {
78
+ if (url.length <= maxLength) return url;
79
+ return url.slice(0, maxLength - 3) + "...";
80
+ }
81
+ }
82
+ function truncateText(text, maxLength = 80) {
83
+ if (!text) return "";
84
+ const trimmed = text.trim().replace(/\n+/g, " ").replace(/\s+/g, " ");
85
+ if (trimmed.length <= maxLength) return trimmed;
86
+ return trimmed.slice(0, maxLength - 3) + "...";
87
+ }
88
+ function formatTokenUsage(inputTokens, outputTokens) {
89
+ const parts = [];
90
+ if (inputTokens != null && inputTokens > 0) {
91
+ parts.push(`\u2191 ${formatNumber(inputTokens)}`);
92
+ }
93
+ if (outputTokens != null && outputTokens > 0) {
94
+ parts.push(`\u2193 ${formatNumber(outputTokens)}`);
95
+ }
96
+ return parts.join(" \xB7 ");
97
+ }
36
98
  export {
99
+ formatContextUsage,
37
100
  formatDuration,
38
101
  formatNumber,
102
+ formatTimestamp,
103
+ formatTokenUsage,
104
+ formatTokens,
105
+ formatUrl,
106
+ truncateText,
39
107
  wrapText
40
108
  };
41
109
  //# sourceMappingURL=format.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/format.tsx"],
4
- "sourcesContent": ["export function wrapText(text: string, width: number): string[] {\n const lines: string[] = []\n let currentLine = ''\n\n for (const char of text) {\n // Important: we need the spread to properly count multi-plane UTF-8 characters (eg. \uD805\uDE96)\n if ([...currentLine].length < width) {\n currentLine += char\n } else {\n lines.push(currentLine)\n currentLine = char\n }\n }\n\n if (currentLine) lines.push(currentLine)\n return lines\n}\n\nexport function formatDuration(ms: number): string {\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(1)}s`\n }\n\n const hours = Math.floor(ms / 3600000)\n const minutes = Math.floor((ms % 3600000) / 60000)\n const seconds = ((ms % 60000) / 1000).toFixed(1)\n\n if (hours > 0) {\n return `${hours}h ${minutes}m ${seconds}s`\n }\n if (minutes > 0) {\n return `${minutes}m ${seconds}s`\n }\n return `${seconds}s`\n}\n\nexport function formatNumber(number: number): string {\n return new Intl.NumberFormat('en', {\n notation: 'compact',\n maximumFractionDigits: 1,\n })\n .format(number) // eg. \"1321\" => \"1.3K\"\n .toLowerCase() // eg. \"1.3K\" => \"1.3k\"\n}\n"],
5
- "mappings": "AAAO,SAAS,SAAS,MAAc,OAAyB;AAC9D,QAAM,QAAkB,CAAC;AACzB,MAAI,cAAc;AAElB,aAAW,QAAQ,MAAM;AAEvB,QAAI,CAAC,GAAG,WAAW,EAAE,SAAS,OAAO;AACnC,qBAAe;AAAA,IACjB,OAAO;AACL,YAAM,KAAK,WAAW;AACtB,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,YAAa,OAAM,KAAK,WAAW;AACvC,SAAO;AACT;AAEO,SAAS,eAAe,IAAoB;AACjD,MAAI,KAAK,KAAO;AACd,WAAO,IAAI,KAAK,KAAM,QAAQ,CAAC,CAAC;AAAA,EAClC;AAEA,QAAM,QAAQ,KAAK,MAAM,KAAK,IAAO;AACrC,QAAM,UAAU,KAAK,MAAO,KAAK,OAAW,GAAK;AACjD,QAAM,WAAY,KAAK,MAAS,KAAM,QAAQ,CAAC;AAE/C,MAAI,QAAQ,GAAG;AACb,WAAO,GAAG,KAAK,KAAK,OAAO,KAAK,OAAO;AAAA,EACzC;AACA,MAAI,UAAU,GAAG;AACf,WAAO,GAAG,OAAO,KAAK,OAAO;AAAA,EAC/B;AACA,SAAO,GAAG,OAAO;AACnB;AAEO,SAAS,aAAa,QAAwB;AACnD,SAAO,IAAI,KAAK,aAAa,MAAM;AAAA,IACjC,UAAU;AAAA,IACV,uBAAuB;AAAA,EACzB,CAAC,EACE,OAAO,MAAM,EACb,YAAY;AACjB;",
4
+ "sourcesContent": ["export function wrapText(text: string, width: number): string[] {\n const lines: string[] = []\n let currentLine = ''\n\n for (const char of text) {\n // Important: we need the spread to properly count multi-plane UTF-8 characters (eg. \uD805\uDE96)\n if ([...currentLine].length < width) {\n currentLine += char\n } else {\n lines.push(currentLine)\n currentLine = char\n }\n }\n\n if (currentLine) lines.push(currentLine)\n return lines\n}\n\nexport function formatDuration(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000)\n\n if (totalSeconds < 60) {\n return `${totalSeconds}s`\n }\n\n const hours = Math.floor(totalSeconds / 3600)\n const minutes = Math.floor((totalSeconds % 3600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) {\n return `${hours}h ${minutes}m ${seconds}s`\n }\n if (minutes > 0) {\n return `${minutes}m ${seconds}s`\n }\n return `${seconds}s`\n}\n\nexport function formatNumber(number: number): string {\n return new Intl.NumberFormat('en', {\n notation: 'compact',\n maximumFractionDigits: 1,\n })\n .format(number) // eg. \"1321\" => \"1.3K\"\n .toLowerCase() // eg. \"1.3K\" => \"1.3k\"\n}\n\n/**\n * Format token count for display (e.g., 42000 -> \"42k tokens\")\n * More descriptive than formatNumber for token-specific contexts\n */\nexport function formatTokens(tokens: number): string {\n if (tokens < 1000) {\n return `${tokens} tokens`\n }\n return `${formatNumber(tokens)} tokens`\n}\n\n/**\n * Format context usage as percentage with visual indicator\n */\nexport function formatContextUsage(\n usedTokens: number,\n maxTokens: number,\n): string {\n const percentage = (usedTokens / maxTokens) * 100\n const formatted = formatNumber(usedTokens)\n\n if (percentage <= 50) {\n return `${formatted}/${formatNumber(maxTokens)} (${percentage.toFixed(0)}%)`\n } else if (percentage <= 80) {\n return `${formatted}/${formatNumber(maxTokens)} (${percentage.toFixed(0)}% \u26A0\uFE0F)`\n } else {\n return `${formatted}/${formatNumber(maxTokens)} (${percentage.toFixed(0)}% \uD83D\uDD34)`\n }\n}\n\n/**\n * Format timestamp for display (e.g., \"12:20 AM\")\n * Uses 12-hour format with AM/PM indicator like Claude Code\n */\nexport function formatTimestamp(timestamp: number | Date): string {\n const date = typeof timestamp === 'number' ? new Date(timestamp) : timestamp\n return date.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n })\n}\n\n/**\n * Format URL for display\n * - Decodes URL-encoded characters for readability\n * - Truncates to max length with ellipsis\n * - Shows host + path truncated\n */\nexport function formatUrl(url: string, maxLength: number = 60): string {\n try {\n // Decode URL-encoded characters\n const decoded = decodeURIComponent(url)\n\n // Truncate if too long\n if (decoded.length <= maxLength) {\n return decoded\n }\n\n // Try to preserve host and beginning of path\n const urlObj = new URL(decoded)\n const host = urlObj.host\n const pathStart = urlObj.pathname.slice(0, 20)\n\n // Format: host/path.../end\n const remaining = maxLength - host.length - pathStart.length - 6 // \"...\" x2\n if (remaining > 10) {\n const pathEnd = urlObj.pathname.slice(-remaining)\n return `${host}${pathStart}...${pathEnd}`\n }\n\n // Fallback: simple truncation\n return decoded.slice(0, maxLength - 3) + '...'\n } catch {\n // If URL parsing fails, just truncate\n if (url.length <= maxLength) return url\n return url.slice(0, maxLength - 3) + '...'\n }\n}\n\n/**\n * Truncate text to a maximum length with ellipsis\n */\nexport function truncateText(text: string, maxLength: number = 80): string {\n if (!text) return ''\n const trimmed = text.trim().replace(/\\n+/g, ' ').replace(/\\s+/g, ' ')\n if (trimmed.length <= maxLength) return trimmed\n return trimmed.slice(0, maxLength - 3) + '...'\n}\n\n/**\n * Format token usage with up/down arrows for input/output\n * e.g., \"\u2191 8.2k \u00B7 \u2193 1.2k\"\n */\nexport function formatTokenUsage(\n inputTokens?: number,\n outputTokens?: number,\n): string {\n const parts: string[] = []\n if (inputTokens != null && inputTokens > 0) {\n parts.push(`\u2191 ${formatNumber(inputTokens)}`)\n }\n if (outputTokens != null && outputTokens > 0) {\n parts.push(`\u2193 ${formatNumber(outputTokens)}`)\n }\n return parts.join(' \u00B7 ')\n}\n"],
5
+ "mappings": "AAAO,SAAS,SAAS,MAAc,OAAyB;AAC9D,QAAM,QAAkB,CAAC;AACzB,MAAI,cAAc;AAElB,aAAW,QAAQ,MAAM;AAEvB,QAAI,CAAC,GAAG,WAAW,EAAE,SAAS,OAAO;AACnC,qBAAe;AAAA,IACjB,OAAO;AACL,YAAM,KAAK,WAAW;AACtB,oBAAc;AAAA,IAChB;AAAA,EACF;AAEA,MAAI,YAAa,OAAM,KAAK,WAAW;AACvC,SAAO;AACT;AAEO,SAAS,eAAe,IAAoB;AACjD,QAAM,eAAe,KAAK,MAAM,KAAK,GAAI;AAEzC,MAAI,eAAe,IAAI;AACrB,WAAO,GAAG,YAAY;AAAA,EACxB;AAEA,QAAM,QAAQ,KAAK,MAAM,eAAe,IAAI;AAC5C,QAAM,UAAU,KAAK,MAAO,eAAe,OAAQ,EAAE;AACrD,QAAM,UAAU,eAAe;AAE/B,MAAI,QAAQ,GAAG;AACb,WAAO,GAAG,KAAK,KAAK,OAAO,KAAK,OAAO;AAAA,EACzC;AACA,MAAI,UAAU,GAAG;AACf,WAAO,GAAG,OAAO,KAAK,OAAO;AAAA,EAC/B;AACA,SAAO,GAAG,OAAO;AACnB;AAEO,SAAS,aAAa,QAAwB;AACnD,SAAO,IAAI,KAAK,aAAa,MAAM;AAAA,IACjC,UAAU;AAAA,IACV,uBAAuB;AAAA,EACzB,CAAC,EACE,OAAO,MAAM,EACb,YAAY;AACjB;AAMO,SAAS,aAAa,QAAwB;AACnD,MAAI,SAAS,KAAM;AACjB,WAAO,GAAG,MAAM;AAAA,EAClB;AACA,SAAO,GAAG,aAAa,MAAM,CAAC;AAChC;AAKO,SAAS,mBACd,YACA,WACQ;AACR,QAAM,aAAc,aAAa,YAAa;AAC9C,QAAM,YAAY,aAAa,UAAU;AAEzC,MAAI,cAAc,IAAI;AACpB,WAAO,GAAG,SAAS,IAAI,aAAa,SAAS,CAAC,KAAK,WAAW,QAAQ,CAAC,CAAC;AAAA,EAC1E,WAAW,cAAc,IAAI;AAC3B,WAAO,GAAG,SAAS,IAAI,aAAa,SAAS,CAAC,KAAK,WAAW,QAAQ,CAAC,CAAC;AAAA,EAC1E,OAAO;AACL,WAAO,GAAG,SAAS,IAAI,aAAa,SAAS,CAAC,KAAK,WAAW,QAAQ,CAAC,CAAC;AAAA,EAC1E;AACF;AAMO,SAAS,gBAAgB,WAAkC;AAChE,QAAM,OAAO,OAAO,cAAc,WAAW,IAAI,KAAK,SAAS,IAAI;AACnE,SAAO,KAAK,mBAAmB,SAAS;AAAA,IACtC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACH;AAQO,SAAS,UAAU,KAAa,YAAoB,IAAY;AACrE,MAAI;AAEF,UAAM,UAAU,mBAAmB,GAAG;AAGtC,QAAI,QAAQ,UAAU,WAAW;AAC/B,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,IAAI,IAAI,OAAO;AAC9B,UAAM,OAAO,OAAO;AACpB,UAAM,YAAY,OAAO,SAAS,MAAM,GAAG,EAAE;AAG7C,UAAM,YAAY,YAAY,KAAK,SAAS,UAAU,SAAS;AAC/D,QAAI,YAAY,IAAI;AAClB,YAAM,UAAU,OAAO,SAAS,MAAM,CAAC,SAAS;AAChD,aAAO,GAAG,IAAI,GAAG,SAAS,MAAM,OAAO;AAAA,IACzC;AAGA,WAAO,QAAQ,MAAM,GAAG,YAAY,CAAC,IAAI;AAAA,EAC3C,QAAQ;AAEN,QAAI,IAAI,UAAU,UAAW,QAAO;AACpC,WAAO,IAAI,MAAM,GAAG,YAAY,CAAC,IAAI;AAAA,EACvC;AACF;AAKO,SAAS,aAAa,MAAc,YAAoB,IAAY;AACzE,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,KAAK,KAAK,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ,QAAQ,GAAG;AACpE,MAAI,QAAQ,UAAU,UAAW,QAAO;AACxC,SAAO,QAAQ,MAAM,GAAG,YAAY,CAAC,IAAI;AAC3C;AAMO,SAAS,iBACd,aACA,cACQ;AACR,QAAM,QAAkB,CAAC;AACzB,MAAI,eAAe,QAAQ,cAAc,GAAG;AAC1C,UAAM,KAAK,UAAK,aAAa,WAAW,CAAC,EAAE;AAAA,EAC7C;AACA,MAAI,gBAAgB,QAAQ,eAAe,GAAG;AAC5C,UAAM,KAAK,UAAK,aAAa,YAAY,CAAC,EAAE;AAAA,EAC9C;AACA,SAAO,MAAM,KAAK,QAAK;AACzB;",
6
6
  "names": []
7
7
  }
@@ -1,3 +1,4 @@
1
+ import { debug } from "./debugLogger.js";
1
2
  const NO_VALUE = Symbol("NO_VALUE");
2
3
  async function lastX(as) {
3
4
  let lastValue = NO_VALUE;
@@ -9,35 +10,104 @@ async function lastX(as) {
9
10
  }
10
11
  return lastValue;
11
12
  }
12
- async function* all(generators, concurrencyCap = Infinity) {
13
+ async function* all(generators, concurrencyCap = Infinity, abortSignal) {
14
+ let generatorIdCounter = 0;
15
+ const generatorIds = /* @__PURE__ */ new Map();
16
+ const activeGenerators = /* @__PURE__ */ new Set();
13
17
  const next = (generator) => {
18
+ let id = generatorIds.get(generator);
19
+ if (id === void 0) {
20
+ id = generatorIdCounter++;
21
+ generatorIds.set(generator, id);
22
+ }
23
+ activeGenerators.add(generator);
14
24
  const promise = generator.next().then(({ done, value }) => ({
15
25
  done,
16
26
  value,
17
27
  generator,
18
- promise
28
+ promise,
29
+ id
19
30
  }));
20
31
  return promise;
21
32
  };
33
+ const terminateAll = async () => {
34
+ debug.flow("ALL_GENERATORS_ABORT", {
35
+ activeCount: activeGenerators.size
36
+ });
37
+ for (const gen of activeGenerators) {
38
+ try {
39
+ await gen.return(void 0);
40
+ } catch {
41
+ }
42
+ }
43
+ activeGenerators.clear();
44
+ };
22
45
  const waiting = [...generators];
23
46
  const promises = /* @__PURE__ */ new Set();
47
+ debug.flow("ALL_GENERATORS_START", {
48
+ totalGenerators: generators.length,
49
+ concurrencyCap,
50
+ hasAbortSignal: !!abortSignal
51
+ });
52
+ if (abortSignal?.aborted) {
53
+ debug.flow("ALL_GENERATORS_ALREADY_ABORTED", {});
54
+ return;
55
+ }
24
56
  while (promises.size < concurrencyCap && waiting.length > 0) {
25
57
  const gen = waiting.shift();
26
58
  promises.add(next(gen));
27
59
  }
60
+ debug.flow("ALL_GENERATORS_INITIAL_BATCH", {
61
+ activeCount: promises.size,
62
+ waitingCount: waiting.length
63
+ });
64
+ let yieldCount = 0;
65
+ let completedCount = 0;
28
66
  while (promises.size > 0) {
29
- const { done, value, generator, promise } = await Promise.race(promises);
67
+ if (abortSignal?.aborted) {
68
+ debug.flow("ALL_GENERATORS_ABORT_DETECTED", {
69
+ completedCount,
70
+ remainingActive: promises.size
71
+ });
72
+ await terminateAll();
73
+ return;
74
+ }
75
+ const { done, value, generator, promise, id } = await Promise.race(promises);
30
76
  promises.delete(promise);
77
+ if (abortSignal?.aborted) {
78
+ debug.flow("ALL_GENERATORS_ABORT_AFTER_RACE", {
79
+ completedCount,
80
+ remainingActive: promises.size
81
+ });
82
+ await terminateAll();
83
+ return;
84
+ }
31
85
  if (!done) {
32
86
  promises.add(next(generator));
33
87
  if (value !== void 0) {
88
+ yieldCount++;
34
89
  yield value;
35
90
  }
36
- } else if (waiting.length > 0) {
37
- const nextGen = waiting.shift();
38
- promises.add(next(nextGen));
91
+ } else {
92
+ completedCount++;
93
+ activeGenerators.delete(generator);
94
+ debug.flow("ALL_GENERATOR_COMPLETED", {
95
+ generatorId: id,
96
+ completedCount,
97
+ remainingActive: promises.size,
98
+ waitingCount: waiting.length
99
+ });
100
+ if (waiting.length > 0) {
101
+ const nextGen = waiting.shift();
102
+ promises.add(next(nextGen));
103
+ }
39
104
  }
40
105
  }
106
+ debug.flow("ALL_GENERATORS_DONE", {
107
+ totalGenerators: generators.length,
108
+ totalYields: yieldCount,
109
+ totalCompleted: completedCount
110
+ });
41
111
  }
42
112
  export {
43
113
  all,