@within-7/minto 0.4.0 → 0.4.2

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 (391) hide show
  1. package/dist/Tool.js +7 -0
  2. package/dist/Tool.js.map +2 -2
  3. package/dist/commands/agents/AgentsCommand.js +1 -1
  4. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  5. package/dist/commands/agents/constants.js +2 -2
  6. package/dist/commands/agents/constants.js.map +2 -2
  7. package/dist/commands/clear.js +4 -3
  8. package/dist/commands/clear.js.map +2 -2
  9. package/dist/commands/compact.js +2 -2
  10. package/dist/commands/compact.js.map +1 -1
  11. package/dist/commands/context.js +3 -1
  12. package/dist/commands/context.js.map +2 -2
  13. package/dist/commands/login.js +128 -0
  14. package/dist/commands/login.js.map +7 -0
  15. package/dist/commands/memory.js +33 -82
  16. package/dist/commands/memory.js.map +2 -2
  17. package/dist/commands/quit.js +3 -1
  18. package/dist/commands/quit.js.map +2 -2
  19. package/dist/commands/resume.js +39 -239
  20. package/dist/commands/resume.js.map +2 -2
  21. package/dist/commands/tasks.js +1 -1
  22. package/dist/commands/tasks.js.map +2 -2
  23. package/dist/commands/terminalSetup.js +6 -2
  24. package/dist/commands/terminalSetup.js.map +2 -2
  25. package/dist/commands.js +2 -0
  26. package/dist/commands.js.map +2 -2
  27. package/dist/components/AgentDetailView.js +126 -0
  28. package/dist/components/AgentDetailView.js.map +7 -0
  29. package/dist/components/AgentThinkingBlock.js +1 -1
  30. package/dist/components/AgentThinkingBlock.js.map +2 -2
  31. package/dist/components/AgentViewBanner.js +22 -0
  32. package/dist/components/AgentViewBanner.js.map +7 -0
  33. package/dist/components/HeaderBar.js +1 -1
  34. package/dist/components/HeaderBar.js.map +2 -2
  35. package/dist/components/Help.js +8 -1
  36. package/dist/components/Help.js.map +2 -2
  37. package/dist/components/HotkeyHelpPanel.js +26 -8
  38. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  39. package/dist/components/IdleNotificationBar.js +10 -0
  40. package/dist/components/IdleNotificationBar.js.map +7 -0
  41. package/dist/components/ModelSelector/ModelSelector.js +55 -20
  42. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  43. package/dist/components/PromptInput.js +186 -115
  44. package/dist/components/PromptInput.js.map +2 -2
  45. package/dist/components/RewindPanel.js +272 -0
  46. package/dist/components/RewindPanel.js.map +7 -0
  47. package/dist/components/Spinner.js +10 -21
  48. package/dist/components/Spinner.js.map +2 -2
  49. package/dist/components/StreamingTextPreview.js +29 -0
  50. package/dist/components/StreamingTextPreview.js.map +7 -0
  51. package/dist/components/SubagentBlock.js +3 -2
  52. package/dist/components/SubagentBlock.js.map +2 -2
  53. package/dist/components/SubagentProgress.js +4 -4
  54. package/dist/components/SubagentProgress.js.map +2 -2
  55. package/dist/components/TabbedListView/SearchInput.js +1 -1
  56. package/dist/components/TabbedListView/SearchInput.js.map +2 -2
  57. package/dist/components/TabbedListView/TabbedListView.js +87 -41
  58. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  59. package/dist/components/TaskCard.js +4 -4
  60. package/dist/components/TaskCard.js.map +2 -2
  61. package/dist/components/TeamMemberPanel.js +107 -0
  62. package/dist/components/TeamMemberPanel.js.map +7 -0
  63. package/dist/components/ThinkingSelector.js +84 -0
  64. package/dist/components/ThinkingSelector.js.map +7 -0
  65. package/dist/components/TitledDivider.js +26 -0
  66. package/dist/components/TitledDivider.js.map +7 -0
  67. package/dist/components/TodoPanel.js +31 -30
  68. package/dist/components/TodoPanel.js.map +2 -2
  69. package/dist/components/TokenWarning.js +28 -7
  70. package/dist/components/TokenWarning.js.map +2 -2
  71. package/dist/components/messages/AssistantTextMessage.js +5 -2
  72. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  73. package/dist/components/messages/AssistantToolUseMessage.js +9 -1
  74. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  75. package/dist/components/messages/DefaultToolResultFallback.js +11 -0
  76. package/dist/components/messages/DefaultToolResultFallback.js.map +7 -0
  77. package/dist/components/messages/ParallelTasksGroupView.js +14 -6
  78. package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
  79. package/dist/components/messages/TaskInModuleView.js +27 -27
  80. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  81. package/dist/components/messages/UserGuidanceMessage.js +26 -0
  82. package/dist/components/messages/UserGuidanceMessage.js.map +7 -0
  83. package/dist/components/messages/UserPromptMessage.js +2 -1
  84. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  85. package/dist/components/messages/UserTeamNotificationMessage.js +91 -0
  86. package/dist/components/messages/UserTeamNotificationMessage.js.map +7 -0
  87. package/dist/components/messages/UserTextMessage.js +8 -0
  88. package/dist/components/messages/UserTextMessage.js.map +2 -2
  89. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +4 -2
  90. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +2 -2
  91. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +18 -1
  92. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +2 -2
  93. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +12 -1
  94. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  95. package/dist/components/permissions/PermissionRequest.js +4 -0
  96. package/dist/components/permissions/PermissionRequest.js.map +2 -2
  97. package/dist/components/permissions/PlanApprovalRequest.js +164 -0
  98. package/dist/components/permissions/PlanApprovalRequest.js.map +7 -0
  99. package/dist/constants/agentTeams.js +17 -0
  100. package/dist/constants/agentTeams.js.map +7 -0
  101. package/dist/constants/macros.js +2 -1
  102. package/dist/constants/macros.js.map +2 -2
  103. package/dist/constants/prompts/agentPrompt.js +1 -0
  104. package/dist/constants/prompts/agentPrompt.js.map +2 -2
  105. package/dist/constants/prompts/autoMemory.js +39 -0
  106. package/dist/constants/prompts/autoMemory.js.map +7 -0
  107. package/dist/constants/prompts/codeConventions.js +1 -13
  108. package/dist/constants/prompts/codeConventions.js.map +2 -2
  109. package/dist/constants/prompts/doingTasks.js +21 -2
  110. package/dist/constants/prompts/doingTasks.js.map +2 -2
  111. package/dist/constants/prompts/envInfo.js +6 -7
  112. package/dist/constants/prompts/envInfo.js.map +2 -2
  113. package/dist/constants/prompts/index.js +27 -5
  114. package/dist/constants/prompts/index.js.map +2 -2
  115. package/dist/constants/prompts/taskManagement.js +2 -43
  116. package/dist/constants/prompts/taskManagement.js.map +2 -2
  117. package/dist/constants/prompts/teamOverlays.js +50 -0
  118. package/dist/constants/prompts/teamOverlays.js.map +7 -0
  119. package/dist/constants/prompts/toneAndStyle.js +4 -29
  120. package/dist/constants/prompts/toneAndStyle.js.map +2 -2
  121. package/dist/constants/prompts/toolUsagePolicy.js +7 -22
  122. package/dist/constants/prompts/toolUsagePolicy.js.map +2 -2
  123. package/dist/constants/toolInputExamples.js +2 -2
  124. package/dist/constants/toolInputExamples.js.map +2 -2
  125. package/dist/context.js +39 -6
  126. package/dist/context.js.map +2 -2
  127. package/dist/core/backupManager.js +1 -1
  128. package/dist/core/backupManager.js.map +2 -2
  129. package/dist/core/permissions/rules/planModeRule.js +1 -1
  130. package/dist/core/permissions/rules/planModeRule.js.map +1 -1
  131. package/dist/core/permissions/rules/safeModeRule.js +1 -1
  132. package/dist/core/permissions/rules/safeModeRule.js.map +1 -1
  133. package/dist/engine/AgentEngine.js +902 -0
  134. package/dist/engine/AgentEngine.js.map +7 -0
  135. package/dist/engine/EngineRegistry.js +89 -0
  136. package/dist/engine/EngineRegistry.js.map +7 -0
  137. package/dist/engine/foregroundAdapter.js +191 -0
  138. package/dist/engine/foregroundAdapter.js.map +7 -0
  139. package/dist/engine/index.js +15 -0
  140. package/dist/engine/index.js.map +7 -0
  141. package/dist/engine/types.js +1 -0
  142. package/dist/engine/types.js.map +7 -0
  143. package/dist/entrypoints/cli.js +410 -79
  144. package/dist/entrypoints/cli.js.map +3 -3
  145. package/dist/hooks/useAgentEngine.js +129 -0
  146. package/dist/hooks/useAgentEngine.js.map +7 -0
  147. package/dist/hooks/useAgentTokenStats.js +0 -16
  148. package/dist/hooks/useAgentTokenStats.js.map +2 -2
  149. package/dist/hooks/useCanUseTool.js +47 -2
  150. package/dist/hooks/useCanUseTool.js.map +2 -2
  151. package/dist/hooks/useDeferredLoading.js +4 -1
  152. package/dist/hooks/useDeferredLoading.js.map +2 -2
  153. package/dist/hooks/useIdleNotifications.js +66 -0
  154. package/dist/hooks/useIdleNotifications.js.map +7 -0
  155. package/dist/hooks/useSessionTracking.js +9 -7
  156. package/dist/hooks/useSessionTracking.js.map +2 -2
  157. package/dist/hooks/useTeamMembers.js +51 -0
  158. package/dist/hooks/useTeamMembers.js.map +7 -0
  159. package/dist/i18n/locales/en.js +77 -12
  160. package/dist/i18n/locales/en.js.map +2 -2
  161. package/dist/i18n/locales/zh-CN.js +77 -12
  162. package/dist/i18n/locales/zh-CN.js.map +2 -2
  163. package/dist/i18n/types.js.map +1 -1
  164. package/dist/messages.js.map +2 -2
  165. package/dist/permissions.js +113 -7
  166. package/dist/permissions.js.map +2 -2
  167. package/dist/query.js +135 -37
  168. package/dist/query.js.map +2 -2
  169. package/dist/screens/REPL.js +504 -361
  170. package/dist/screens/REPL.js.map +3 -3
  171. package/dist/screens/ResumeConversation.js +199 -14
  172. package/dist/screens/ResumeConversation.js.map +2 -2
  173. package/dist/services/adapters/base.js.map +1 -1
  174. package/dist/services/agentTeams/backends/headless.js +108 -0
  175. package/dist/services/agentTeams/backends/headless.js.map +7 -0
  176. package/dist/services/agentTeams/backends/inProcess.js +102 -0
  177. package/dist/services/agentTeams/backends/inProcess.js.map +7 -0
  178. package/dist/services/agentTeams/backends/resolver.js +18 -0
  179. package/dist/services/agentTeams/backends/resolver.js.map +7 -0
  180. package/dist/services/agentTeams/backends/tmux.js +168 -0
  181. package/dist/services/agentTeams/backends/tmux.js.map +7 -0
  182. package/dist/services/agentTeams/backends/types.js +1 -0
  183. package/dist/services/agentTeams/backends/types.js.map +7 -0
  184. package/dist/services/agentTeams/heartbeat.js +88 -0
  185. package/dist/services/agentTeams/heartbeat.js.map +7 -0
  186. package/dist/services/agentTeams/index.js +42 -2
  187. package/dist/services/agentTeams/index.js.map +2 -2
  188. package/dist/services/agentTeams/injectionChannel.js +105 -0
  189. package/dist/services/agentTeams/injectionChannel.js.map +7 -0
  190. package/dist/services/agentTeams/mailbox.js +410 -30
  191. package/dist/services/agentTeams/mailbox.js.map +2 -2
  192. package/dist/services/agentTeams/messageFormatter.js +80 -0
  193. package/dist/services/agentTeams/messageFormatter.js.map +7 -0
  194. package/dist/services/agentTeams/permissionDelegation.js +71 -0
  195. package/dist/services/agentTeams/permissionDelegation.js.map +7 -0
  196. package/dist/services/agentTeams/teamEvents.js +45 -0
  197. package/dist/services/agentTeams/teamEvents.js.map +7 -0
  198. package/dist/services/agentTeams/teamManager.js +251 -34
  199. package/dist/services/agentTeams/teamManager.js.map +2 -2
  200. package/dist/services/agentTeams/teamTaskStore.js +290 -61
  201. package/dist/services/agentTeams/teamTaskStore.js.map +2 -2
  202. package/dist/services/agentTeams/teammateSpawner.js +99 -18
  203. package/dist/services/agentTeams/teammateSpawner.js.map +2 -2
  204. package/dist/services/hookExecutor.js +51 -8
  205. package/dist/services/hookExecutor.js.map +2 -2
  206. package/dist/services/llm/anthropicProvider.js +56 -59
  207. package/dist/services/llm/anthropicProvider.js.map +2 -2
  208. package/dist/services/llm/dispatch.js +24 -5
  209. package/dist/services/llm/dispatch.js.map +2 -2
  210. package/dist/services/llm/openaiProvider.js +115 -136
  211. package/dist/services/llm/openaiProvider.js.map +3 -3
  212. package/dist/services/llm/types.js +89 -15
  213. package/dist/services/llm/types.js.map +2 -2
  214. package/dist/services/mcpClient.js +80 -4
  215. package/dist/services/mcpClient.js.map +2 -2
  216. package/dist/services/mintoAuth.js +299 -0
  217. package/dist/services/mintoAuth.js.map +7 -0
  218. package/dist/services/oauth.js +3 -3
  219. package/dist/services/oauth.js.map +2 -2
  220. package/dist/services/openai.js +91 -20
  221. package/dist/services/openai.js.map +2 -2
  222. package/dist/services/plugins/pluginRuntime.js +11 -5
  223. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  224. package/dist/services/plugins/pluginValidation.js +4 -2
  225. package/dist/services/plugins/pluginValidation.js.map +2 -2
  226. package/dist/services/sandbox/sandboxController.js +11 -3
  227. package/dist/services/sandbox/sandboxController.js.map +2 -2
  228. package/dist/services/sessionMemoryInjector.js +77 -0
  229. package/dist/services/sessionMemoryInjector.js.map +7 -0
  230. package/dist/services/systemReminder.js +130 -8
  231. package/dist/services/systemReminder.js.map +2 -2
  232. package/dist/services/taskStore.js +199 -8
  233. package/dist/services/taskStore.js.map +3 -3
  234. package/dist/services/topicDetector.js +169 -0
  235. package/dist/services/topicDetector.js.map +7 -0
  236. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +0 -13
  237. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  238. package/dist/tools/BashTool/BashTool.js +51 -28
  239. package/dist/tools/BashTool/BashTool.js.map +2 -2
  240. package/dist/tools/BashTool/prompt.js +95 -118
  241. package/dist/tools/BashTool/prompt.js.map +2 -2
  242. package/dist/tools/BashTool/utils.js +39 -1
  243. package/dist/tools/BashTool/utils.js.map +2 -2
  244. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js +121 -0
  245. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js.map +7 -0
  246. package/dist/tools/EnterWorktreeTool/prompt.js +22 -0
  247. package/dist/tools/EnterWorktreeTool/prompt.js.map +7 -0
  248. package/dist/tools/FileEditTool/FileEditTool.js +9 -4
  249. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  250. package/dist/tools/FileEditTool/prompt.js +3 -7
  251. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  252. package/dist/tools/FileReadTool/FileReadTool.js +125 -3
  253. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  254. package/dist/tools/FileReadTool/prompt.js +1 -2
  255. package/dist/tools/FileReadTool/prompt.js.map +2 -2
  256. package/dist/tools/FileWriteTool/prompt.js +3 -5
  257. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  258. package/dist/tools/GlobTool/GlobTool.js +3 -2
  259. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  260. package/dist/tools/GrepTool/GrepTool.js +16 -5
  261. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  262. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
  263. package/dist/tools/MCPSearchTool/MCPSearchTool.js +172 -0
  264. package/dist/tools/MCPSearchTool/MCPSearchTool.js.map +7 -0
  265. package/dist/tools/MCPSearchTool/prompt.js +77 -0
  266. package/dist/tools/MCPSearchTool/prompt.js.map +7 -0
  267. package/dist/tools/MultiEditTool/prompt.js +4 -7
  268. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  269. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +12 -8
  270. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  271. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +54 -1
  272. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  273. package/dist/tools/PlanModeTool/prompt.js +23 -74
  274. package/dist/tools/PlanModeTool/prompt.js.map +2 -2
  275. package/dist/tools/SendMessageTool/SendMessageTool.js +341 -0
  276. package/dist/tools/SendMessageTool/SendMessageTool.js.map +7 -0
  277. package/dist/tools/SendMessageTool/prompt.js +44 -0
  278. package/dist/tools/SendMessageTool/prompt.js.map +7 -0
  279. package/dist/tools/TaskCreateTool/prompt.js +15 -4
  280. package/dist/tools/TaskCreateTool/prompt.js.map +2 -2
  281. package/dist/tools/TaskListTool/prompt.js +18 -3
  282. package/dist/tools/TaskListTool/prompt.js.map +2 -2
  283. package/dist/tools/TaskOutputTool/prompt.js +4 -3
  284. package/dist/tools/TaskOutputTool/prompt.js.map +2 -2
  285. package/dist/tools/TaskTool/TaskTool.js +762 -98
  286. package/dist/tools/TaskTool/TaskTool.js.map +3 -3
  287. package/dist/tools/TaskTool/constants.js +8 -2
  288. package/dist/tools/TaskTool/constants.js.map +2 -2
  289. package/dist/tools/TaskTool/prompt.js +74 -70
  290. package/dist/tools/TaskTool/prompt.js.map +2 -2
  291. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +15 -1
  292. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +2 -2
  293. package/dist/tools/TeamCreateTool/TeamCreateTool.js +129 -0
  294. package/dist/tools/TeamCreateTool/TeamCreateTool.js.map +7 -0
  295. package/dist/tools/TeamCreateTool/prompt.js +58 -0
  296. package/dist/tools/TeamCreateTool/prompt.js.map +7 -0
  297. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js +151 -0
  298. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js.map +7 -0
  299. package/dist/tools/TeamDeleteTool/prompt.js +16 -0
  300. package/dist/tools/TeamDeleteTool/prompt.js.map +7 -0
  301. package/dist/tools/URLFetcherTool/URLFetcherTool.js +106 -15
  302. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  303. package/dist/tools/URLFetcherTool/prompt.js +3 -2
  304. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  305. package/dist/tools/WebSearchTool/WebSearchTool.js +2 -1
  306. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  307. package/dist/tools/WebSearchTool/prompt.js +5 -4
  308. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  309. package/dist/tools.js +100 -20
  310. package/dist/tools.js.map +2 -2
  311. package/dist/types/PermissionMode.js +35 -6
  312. package/dist/types/PermissionMode.js.map +2 -2
  313. package/dist/types/hooks.js +2 -0
  314. package/dist/types/hooks.js.map +2 -2
  315. package/dist/types/plugin.js +2 -0
  316. package/dist/types/plugin.js.map +3 -3
  317. package/dist/utils/CircuitBreaker.js +15 -9
  318. package/dist/utils/CircuitBreaker.js.map +2 -2
  319. package/dist/utils/agentLoader.js +249 -112
  320. package/dist/utils/agentLoader.js.map +2 -2
  321. package/dist/utils/animationManager.js +40 -3
  322. package/dist/utils/animationManager.js.map +2 -2
  323. package/dist/utils/ask.js +7 -6
  324. package/dist/utils/ask.js.map +2 -2
  325. package/dist/utils/atomicWrite.js +23 -0
  326. package/dist/utils/atomicWrite.js.map +7 -0
  327. package/dist/utils/autoCompactCore.js +73 -56
  328. package/dist/utils/autoCompactCore.js.map +2 -2
  329. package/dist/utils/autoMemoryPaths.js +89 -0
  330. package/dist/utils/autoMemoryPaths.js.map +7 -0
  331. package/dist/utils/config.js +63 -38
  332. package/dist/utils/config.js.map +2 -2
  333. package/dist/utils/configSchema.js +13 -8
  334. package/dist/utils/configSchema.js.map +2 -2
  335. package/dist/utils/credentials/index.js +14 -0
  336. package/dist/utils/credentials/index.js.map +2 -2
  337. package/dist/utils/dualPath.js +24 -0
  338. package/dist/utils/dualPath.js.map +7 -0
  339. package/dist/utils/exit.js +66 -7
  340. package/dist/utils/exit.js.map +2 -2
  341. package/dist/utils/externalEditor.js +155 -0
  342. package/dist/utils/externalEditor.js.map +7 -0
  343. package/dist/utils/fileLock.js +67 -0
  344. package/dist/utils/fileLock.js.map +7 -0
  345. package/dist/utils/format.js +24 -14
  346. package/dist/utils/format.js.map +2 -2
  347. package/dist/utils/globalErrorHandler.js +5 -96
  348. package/dist/utils/globalErrorHandler.js.map +3 -3
  349. package/dist/utils/groupHandlers/parallelTasksHandler.js +5 -3
  350. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +2 -2
  351. package/dist/utils/groupHandlers/taskHandler.js +2 -2
  352. package/dist/utils/groupHandlers/taskHandler.js.map +2 -2
  353. package/dist/utils/hookManager.js +64 -6
  354. package/dist/utils/hookManager.js.map +2 -2
  355. package/dist/utils/log.js +6 -2
  356. package/dist/utils/log.js.map +2 -2
  357. package/dist/utils/markdown.js +237 -19
  358. package/dist/utils/markdown.js.map +2 -2
  359. package/dist/utils/messageContextManager.js +18 -5
  360. package/dist/utils/messageContextManager.js.map +2 -2
  361. package/dist/utils/messageGroupManager.js +1 -1
  362. package/dist/utils/messageGroupManager.js.map +2 -2
  363. package/dist/utils/messages.js +104 -46
  364. package/dist/utils/messages.js.map +2 -2
  365. package/dist/utils/model.js +2 -2
  366. package/dist/utils/model.js.map +2 -2
  367. package/dist/utils/pasteCache.js +8 -4
  368. package/dist/utils/pasteCache.js.map +2 -2
  369. package/dist/utils/pluginLoader.js +18 -0
  370. package/dist/utils/pluginLoader.js.map +2 -2
  371. package/dist/utils/secureKeyStorage.js +36 -7
  372. package/dist/utils/secureKeyStorage.js.map +2 -2
  373. package/dist/utils/simpleMode.js +7 -0
  374. package/dist/utils/simpleMode.js.map +7 -0
  375. package/dist/utils/streamingState.js +11 -1
  376. package/dist/utils/streamingState.js.map +2 -2
  377. package/dist/utils/taskDisplayUtils.js +2 -1
  378. package/dist/utils/taskDisplayUtils.js.map +2 -2
  379. package/dist/utils/teamConfig.js +2 -2
  380. package/dist/utils/teamConfig.js.map +2 -2
  381. package/dist/utils/thinking.js +6 -2
  382. package/dist/utils/thinking.js.map +3 -3
  383. package/dist/utils/tokenProgress.js +55 -0
  384. package/dist/utils/tokenProgress.js.map +7 -0
  385. package/dist/utils/toolRiskClassification.js +26 -17
  386. package/dist/utils/toolRiskClassification.js.map +2 -2
  387. package/dist/utils/tooling/toolError.js +12 -0
  388. package/dist/utils/tooling/toolError.js.map +7 -0
  389. package/dist/version.js +2 -2
  390. package/dist/version.js.map +1 -1
  391. package/package.json +10 -8
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/permissions.ts"],
4
- "sourcesContent": ["import type { CanUseToolFn } from './hooks/useCanUseTool'\nimport { Tool, ToolUseContext } from './Tool'\nimport { BashTool, inputSchema } from './tools/BashTool/BashTool'\nimport { FileEditTool } from './tools/FileEditTool/FileEditTool'\nimport { FileWriteTool } from './tools/FileWriteTool/FileWriteTool'\nimport { NotebookEditTool } from './tools/NotebookEditTool/NotebookEditTool'\nimport { getCommandSubcommandPrefix, splitCommand } from './utils/commands'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n type SafetyMode,\n} from '@utils/config'\nimport { AbortError } from './utils/errors'\nimport { logError } from './utils/log'\nimport { grantWritePermissionForOriginalDir } from './utils/permissions/filesystem'\nimport { getCwd } from './utils/state'\nimport { PRODUCT_NAME } from './constants/product'\nimport {\n getToolRiskLevel,\n type RiskLevel,\n} from './utils/toolRiskClassification'\nimport { resolve, relative, isAbsolute, join } from 'path'\nimport { getHookManager } from './utils/hookManager'\nimport { existsSync, readFileSync } from 'fs'\nimport { homedir } from 'os'\nimport { CONFIG_BASE_DIR } from './constants/product'\n\n// Commands that are known to be safe for execution\nconst SAFE_COMMANDS = new Set([\n 'git status',\n 'git diff',\n 'git log',\n 'git branch',\n 'pwd',\n 'tree',\n 'date',\n 'which',\n])\n\nexport const bashToolCommandHasExactMatchPermission = (\n tool: Tool,\n command: string,\n allowedTools: string[],\n): boolean => {\n if (SAFE_COMMANDS.has(command)) {\n return true\n }\n // Check exact match first\n if (allowedTools.includes(getPermissionKey(tool, { command }, null))) {\n return true\n }\n // Check if command is an exact match with an approved prefix\n if (allowedTools.includes(getPermissionKey(tool, { command }, command))) {\n return true\n }\n return false\n}\n\nexport const bashToolCommandHasPermission = (\n tool: Tool,\n command: string,\n prefix: string | null,\n allowedTools: string[],\n): boolean => {\n // Check exact match first\n if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) {\n return true\n }\n return allowedTools.includes(getPermissionKey(tool, { command }, prefix))\n}\n\nexport const bashToolHasPermission = async (\n tool: Tool,\n command: string,\n context: ToolUseContext,\n allowedTools: string[],\n getCommandSubcommandPrefixFn = getCommandSubcommandPrefix,\n): Promise<PermissionResult> => {\n if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) {\n // This is an exact match for a command that is allowed, so we can skip the prefix check\n return { result: true }\n }\n\n const subCommands = splitCommand(command).filter(_ => {\n // Denim likes to add this, we strip it out so we don't need to prompt the user each time\n if (_ === `cd ${getCwd()}`) {\n return false\n }\n return true\n })\n const commandSubcommandPrefix = await getCommandSubcommandPrefixFn(\n command,\n context.abortController.signal,\n )\n if (context.abortController.signal.aborted) {\n throw new AbortError()\n }\n\n if (commandSubcommandPrefix === null) {\n // Fail closed and ask for user approval if the command prefix query failed (e.g. due to network error)\n // This is NOT the same as `fullCommandPrefix.commandPrefix === null`, which means no prefix was detected\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n\n if (commandSubcommandPrefix.commandInjectionDetected) {\n // Only allow exact matches for potential command injections\n if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) {\n return { result: true }\n } else {\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n }\n\n // After the commandInjectionDetected check above, TypeScript still sees the union type.\n // We know commandInjectionDetected is false here, so commandPrefix exists.\n // Use 'in' check for proper type narrowing\n const commandPrefix =\n 'commandPrefix' in commandSubcommandPrefix\n ? commandSubcommandPrefix.commandPrefix\n : null\n\n // If there is only one command, no need to process subCommands\n if (subCommands.length < 2) {\n if (\n bashToolCommandHasPermission(tool, command, commandPrefix, allowedTools)\n ) {\n return { result: true }\n } else {\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n }\n if (\n subCommands.every(subCommand => {\n const prefixResult =\n commandSubcommandPrefix.subcommandPrefixes.get(subCommand)\n if (prefixResult === undefined || prefixResult.commandInjectionDetected) {\n // If prefix result is missing or command injection is detected, always ask for permission\n return false\n }\n // After the check above, we know commandInjectionDetected is false\n // Use 'in' check for proper type narrowing\n const subCommandPrefix =\n 'commandPrefix' in prefixResult ? prefixResult.commandPrefix : null\n const hasPermission = bashToolCommandHasPermission(\n tool,\n subCommand,\n subCommandPrefix,\n allowedTools,\n )\n return hasPermission\n })\n ) {\n return { result: true }\n }\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n}\n\ntype PermissionResult = { result: true } | { result: false; message: string }\n\n/**\n * Get effective safety mode from context options\n * Handles backward compatibility with legacy safeMode boolean\n */\nfunction getEffectiveSafetyMode(options: {\n safeMode?: boolean\n safetyMode?: SafetyMode\n}): SafetyMode {\n // New safetyMode takes precedence\n if (options.safetyMode) {\n return options.safetyMode\n }\n // Backward compatibility: convert legacy safeMode boolean\n // safeMode: true \u2192 'strict' (old behavior)\n // safeMode: false \u2192 'yolo' (permissive)\n if (options.safeMode === true) {\n return 'strict'\n }\n // Default to 'yolo' for non-technical users (zero interruption)\n return 'yolo'\n}\n\n/**\n * Check if a path is within the project directory\n * Used by Free mode to allow operations within project boundaries\n */\nfunction isPathWithinProject(targetPath: string, projectDir: string): boolean {\n // Resolve to absolute path\n const absolutePath = isAbsolute(targetPath)\n ? resolve(targetPath)\n : resolve(projectDir, targetPath)\n\n // Get relative path from project directory\n const relativePath = relative(projectDir, absolutePath)\n\n // Path is within project if:\n // 1. It doesn't start with '..' (not escaping project)\n // 2. It's not an absolute path (after relative calculation)\n return !relativePath.startsWith('..') && !isAbsolute(relativePath)\n}\n\n/**\n * System critical paths that should NEVER be auto-allowed, even in Free mode\n * These paths require explicit user confirmation regardless of safety mode\n */\nconst SYSTEM_CRITICAL_PATHS = [\n '/etc',\n '/bin',\n '/sbin',\n '/usr/bin',\n '/usr/sbin',\n '/var',\n '/System',\n '/Library',\n '/Applications',\n '/private',\n 'C:\\\\Windows',\n 'C:\\\\Program Files',\n 'C:\\\\Program Files (x86)',\n]\n\n/**\n * Check if a path is a system critical path\n */\nfunction isSystemCriticalPath(targetPath: string): boolean {\n const normalizedPath = resolve(targetPath).toLowerCase()\n return SYSTEM_CRITICAL_PATHS.some(criticalPath =>\n normalizedPath.startsWith(criticalPath.toLowerCase()),\n )\n}\n\n/**\n * Extract paths from tool input for boundary checking in Free mode\n */\nfunction extractPathsFromToolInput(\n toolName: string,\n input: { [k: string]: unknown },\n): string[] {\n const paths: string[] = []\n\n // File tools\n if (toolName === 'Read' || toolName === 'Write' || toolName === 'Edit') {\n if (typeof input.file_path === 'string') {\n paths.push(input.file_path)\n }\n }\n\n // Glob/Grep tools\n if (toolName === 'Glob' || toolName === 'Grep') {\n if (typeof input.path === 'string') {\n paths.push(input.path)\n }\n }\n\n // LS tool\n if (toolName === 'LS') {\n if (typeof input.path === 'string') {\n paths.push(input.path)\n }\n }\n\n // NotebookEdit\n if (toolName === 'NotebookEdit') {\n if (typeof input.notebook_path === 'string') {\n paths.push(input.notebook_path)\n }\n }\n\n return paths\n}\n\n/**\n * Extract paths from a Bash command for boundary checking\n * This is a simplified extraction - complex commands may need manual review\n */\nfunction extractPathsFromBashCommand(command: string): string[] {\n const paths: string[] = []\n\n // Extract quoted paths\n const quotedMatches = command.matchAll(/[\"']([^\"']+)[\"']/g)\n for (const match of quotedMatches) {\n if (match[1] && (match[1].includes('/') || match[1].startsWith('.'))) {\n paths.push(match[1])\n }\n }\n\n // Extract unquoted paths (starting with ./ or / or ../)\n const unquotedMatches = command.matchAll(\n /(?:^|\\s)((?:\\.\\/|\\/|\\.\\.\\/)[^\\s;&|>]+)/g,\n )\n for (const match of unquotedMatches) {\n if (match[1]) {\n paths.push(match[1])\n }\n }\n\n // Extract redirect targets\n const redirectMatches = command.matchAll(/>\\s*[\"']?([^\\s\"';&|]+)[\"']?/g)\n for (const match of redirectMatches) {\n if (match[1] && !match[1].startsWith('&')) {\n paths.push(match[1])\n }\n }\n\n return [...new Set(paths)] // Deduplicate\n}\n\n/**\n * Check if all paths in an operation are within the project directory\n * Used by Free mode for path-based permission decisions\n */\nfunction areAllPathsWithinProject(\n toolName: string,\n input: { [k: string]: unknown },\n projectDir: string,\n): { withinProject: boolean; outsidePaths: string[] } {\n let paths: string[] = []\n\n // For Bash tool, extract paths from command\n if (toolName === 'Bash' && typeof input.command === 'string') {\n paths = extractPathsFromBashCommand(input.command)\n } else {\n paths = extractPathsFromToolInput(toolName, input)\n }\n\n // If no paths detected, allow by default (e.g., pwd, date, etc.)\n if (paths.length === 0) {\n return { withinProject: true, outsidePaths: [] }\n }\n\n const outsidePaths: string[] = []\n for (const path of paths) {\n // Check system critical paths first\n if (isSystemCriticalPath(path)) {\n outsidePaths.push(path)\n continue\n }\n\n // Check if path is within project\n if (!isPathWithinProject(path, projectDir)) {\n outsidePaths.push(path)\n }\n }\n\n return {\n withinProject: outsidePaths.length === 0,\n outsidePaths,\n }\n}\n\n/**\n * Check if a tool should be allowed based on safety mode and risk level\n *\n * Safety Mode Matrix:\n * | Mode | Safe Tools | Monitored Tools | Dangerous Tools |\n * |--------|------------|-----------------|-----------------|\n * | yolo | \u2713 allow | \u2713 allow | \u2713 allow |\n * | smart | \u2713 allow | \u2713 allow | \u26A0 ask |\n * | strict | \u2713 allow | \u26A0 ask | \u26A0 ask |\n * | free | Path-based: within project = allow, outside = ask |\n */\nfunction shouldAllowByRiskLevel(\n safetyMode: SafetyMode,\n riskLevel: RiskLevel,\n toolName?: string,\n input?: { [k: string]: unknown },\n): boolean {\n switch (safetyMode) {\n case 'yolo':\n // YOLO mode: allow everything\n return true\n case 'smart':\n // Smart mode: allow safe and monitored, ask for dangerous\n return riskLevel === 'safe' || riskLevel === 'monitored'\n case 'strict':\n // Strict mode: only allow safe tools\n return riskLevel === 'safe'\n case 'free':\n // Free mode: path-based decision\n // Safe tools (read-only) are always allowed\n if (riskLevel === 'safe') {\n return true\n }\n // For tools with side effects, check path boundaries\n if (toolName && input) {\n const projectDir = getCwd()\n const { withinProject } = areAllPathsWithinProject(\n toolName,\n input,\n projectDir,\n )\n return withinProject\n }\n // If we can't determine paths, ask for confirmation\n return false\n }\n}\n\n/**\n * Load permission deny/allow rules from settings.json files.\n * Checks: .minto/settings.json, .claude/settings.json, ~/.minto/settings.json, ~/.claude/settings.json\n */\nlet settingsPermissionsCache: {\n deny: string[]\n allow: string[]\n} | null = null\n\nfunction loadSettingsPermissions(): { deny: string[]; allow: string[] } {\n if (settingsPermissionsCache) return settingsPermissionsCache\n\n const deny: string[] = []\n const allow: string[] = []\n\n const cwd = getCwd()\n const home = homedir()\n\n // Check settings files in priority order (later overrides earlier)\n const settingsFiles = [\n join(home, '.claude', 'settings.json'),\n join(home, CONFIG_BASE_DIR, 'settings.json'),\n join(cwd, '.claude', 'settings.json'),\n join(cwd, CONFIG_BASE_DIR, 'settings.json'),\n ]\n\n for (const file of settingsFiles) {\n if (!existsSync(file)) continue\n try {\n const content = JSON.parse(readFileSync(file, 'utf-8'))\n if (\n content?.permissions?.deny &&\n Array.isArray(content.permissions.deny)\n ) {\n deny.push(...content.permissions.deny)\n }\n if (\n content?.permissions?.allow &&\n Array.isArray(content.permissions.allow)\n ) {\n allow.push(...content.permissions.allow)\n }\n } catch {\n // Ignore malformed settings files\n }\n }\n\n settingsPermissionsCache = { deny, allow }\n return settingsPermissionsCache\n}\n\n/**\n * Check if tool matches any pattern in a permission list.\n * Patterns can be exact tool names or tool(pattern) for Bash commands.\n */\nfunction matchesPermissionPattern(\n toolName: string,\n input: { [k: string]: unknown } | undefined,\n patterns: string[],\n): boolean {\n for (const pattern of patterns) {\n // Exact tool name match\n if (pattern === toolName) return true\n\n // Bash command pattern: Bash(command:*)\n if (toolName === 'Bash' && pattern.startsWith('Bash(') && input?.command) {\n const cmdPattern = pattern.slice(5, -1) // Remove Bash( and )\n const command = String(input.command)\n if (cmdPattern.endsWith(':*')) {\n const prefix = cmdPattern.slice(0, -2)\n if (command.startsWith(prefix)) return true\n } else if (command === cmdPattern) {\n return true\n }\n }\n }\n return false\n}\n\nexport const hasPermissionsToUseTool: CanUseToolFn = async (\n tool,\n input,\n context,\n _assistantMessage,\n): Promise<PermissionResult> => {\n // Step 0: Check settings.json deny rules (highest priority - block immediately)\n const settingsPerms = loadSettingsPermissions()\n if (\n matchesPermissionPattern(\n tool.name,\n input as { [k: string]: unknown },\n settingsPerms.deny,\n )\n ) {\n return {\n result: false,\n message: `Tool \"${tool.name}\" is denied by settings configuration.`,\n }\n }\n\n // Step 0b: Check settings.json allow rules (explicit allow)\n if (\n matchesPermissionPattern(\n tool.name,\n input as { [k: string]: unknown },\n settingsPerms.allow,\n )\n ) {\n return { result: true }\n }\n\n const safetyMode = getEffectiveSafetyMode(context.options)\n\n // Get risk level for this tool (with command-specific classification for Bash)\n const riskLevel = getToolRiskLevel(\n tool.name,\n input as { command?: string } | undefined,\n )\n\n // Check if this tool should be auto-allowed based on safety mode and risk level\n // For Free mode, we also pass tool name and input for path-based decisions\n if (\n shouldAllowByRiskLevel(\n safetyMode,\n riskLevel,\n tool.name,\n input as { [k: string]: unknown },\n )\n ) {\n return { result: true }\n }\n\n if (context.abortController.signal.aborted) {\n throw new AbortError()\n }\n\n // Check if the tool needs permissions\n try {\n if (!tool.needsPermissions(input as never)) {\n return { result: true }\n }\n } catch (e) {\n logError(`Error checking permissions: ${e}`)\n return { result: false, message: 'Error checking permissions' }\n }\n\n const projectConfig = getCurrentProjectConfig()\n const allowedTools = projectConfig.allowedTools ?? []\n // Special case for BashTool to allow blanket commands without exposing them in the UI\n if (tool === BashTool && allowedTools.includes(BashTool.name)) {\n return { result: true }\n }\n\n // TODO: Move this into tool definitions (done for read tools!)\n switch (tool) {\n // For bash tool, check each sub-command's permissions separately\n case BashTool: {\n // The types have already been validated by the tool,\n // so we can safely parse the input (as opposed to safeParse).\n const { command } = inputSchema.parse(input)\n return await bashToolHasPermission(tool, command, context, allowedTools)\n }\n // For file editing tools, check session-only permissions\n case FileEditTool:\n case FileWriteTool:\n case NotebookEditTool: {\n // The types have already been validated by the tool,\n // so we can safely pass this in\n if (!tool.needsPermissions(input)) {\n return { result: true }\n }\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n // For other tools, check persistent permissions\n default: {\n const permissionKey = getPermissionKey(tool, input, null)\n if (allowedTools.includes(permissionKey)) {\n return { result: true }\n }\n\n // Fire PermissionRequest hook before denying\n const hookDecision = await firePermissionRequestHook(\n tool.name,\n input as Record<string, unknown>,\n )\n if (hookDecision === 'approve') {\n return { result: true }\n }\n\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n }\n}\n\n/**\n * Fire PermissionRequest hook when a tool needs permission\n * Returns 'approve' to auto-grant, 'block' to deny, or 'ask' to proceed normally\n */\nasync function firePermissionRequestHook(\n toolName: string,\n toolInput: Record<string, unknown>,\n): Promise<'approve' | 'block' | 'ask'> {\n try {\n const hookMgr = getHookManager()\n if (!hookMgr) return 'ask'\n\n const result = await hookMgr.executePermissionRequest(\n toolName,\n toolInput,\n 'other',\n )\n\n if (!result.shouldContinue && !result.shouldAskUser) {\n return 'block'\n }\n if (result.shouldContinue && !result.shouldAskUser) {\n // Check if hook explicitly approved (vs just no hooks matched)\n if (result.reason) return 'approve'\n }\n } catch {\n // Hook errors don't block permission flow\n }\n return 'ask'\n}\n\nexport async function savePermission(\n tool: Tool,\n input: { [k: string]: unknown },\n prefix: string | null,\n): Promise<void> {\n const key = getPermissionKey(tool, input, prefix)\n\n // For file editing tools, store write permissions only in memory\n if (\n tool === FileEditTool ||\n tool === FileWriteTool ||\n tool === NotebookEditTool\n ) {\n grantWritePermissionForOriginalDir()\n return\n }\n\n // For other tools, store permissions on disk\n const projectConfig = getCurrentProjectConfig()\n if (projectConfig.allowedTools.includes(key)) {\n return\n }\n\n projectConfig.allowedTools.push(key)\n projectConfig.allowedTools.sort()\n\n saveCurrentProjectConfig(projectConfig)\n}\n\nfunction getPermissionKey(\n tool: Tool,\n input: { [k: string]: unknown },\n prefix: string | null,\n): string {\n switch (tool) {\n case BashTool:\n if (prefix) {\n return `${BashTool.name}(${prefix}:*)`\n }\n return `${BashTool.name}(${BashTool.renderToolUseMessage(input as never)})`\n default:\n return tool.name\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { CanUseToolFn } from './hooks/useCanUseTool'\nimport { Tool, ToolUseContext } from './Tool'\nimport { BashTool, inputSchema } from './tools/BashTool/BashTool'\nimport { FileEditTool } from './tools/FileEditTool/FileEditTool'\nimport { FileWriteTool } from './tools/FileWriteTool/FileWriteTool'\nimport { NotebookEditTool } from './tools/NotebookEditTool/NotebookEditTool'\nimport { getCommandSubcommandPrefix, splitCommand } from './utils/commands'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n type SafetyMode,\n} from '@utils/config'\nimport { AbortError } from './utils/errors'\nimport { logError } from './utils/log'\nimport { grantWritePermissionForOriginalDir } from './utils/permissions/filesystem'\nimport { getCwd } from './utils/state'\nimport { PRODUCT_NAME } from './constants/product'\nimport {\n getToolRiskLevel,\n type RiskLevel,\n} from './utils/toolRiskClassification'\nimport { resolve, relative, isAbsolute, join } from 'path'\nimport { getHookManager } from './utils/hookManager'\nimport { isPlanModeEnabled } from '@utils/plan/planMode'\nimport { existsSync, readFileSync } from 'fs'\nimport { homedir } from 'os'\nimport { CONFIG_BASE_DIR } from './constants/product'\n\n// Commands that are known to be safe for execution\nconst SAFE_COMMANDS = new Set([\n 'git status',\n 'git diff',\n 'git log',\n 'git branch',\n 'pwd',\n 'tree',\n 'date',\n 'which',\n])\n\nexport const bashToolCommandHasExactMatchPermission = (\n tool: Tool,\n command: string,\n allowedTools: string[],\n): boolean => {\n if (SAFE_COMMANDS.has(command)) {\n return true\n }\n // Check exact match first\n if (allowedTools.includes(getPermissionKey(tool, { command }, null))) {\n return true\n }\n // Check if command is an exact match with an approved prefix\n if (allowedTools.includes(getPermissionKey(tool, { command }, command))) {\n return true\n }\n return false\n}\n\n/**\n * Match a permission key against a wildcard pattern.\n * Supports `*` as a glob wildcard matching any sequence of characters.\n * Example: `Bash(*--help*)` matches `Bash(npm install --help)`\n */\nfunction matchesPermissionWildcard(key: string, pattern: string): boolean {\n // Escape regex special chars except *, then convert * to .*\n const escaped = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n const regexStr = `^${escaped.replace(/\\*/g, '.*')}$`\n try {\n return new RegExp(regexStr).test(key)\n } catch {\n return false\n }\n}\n\nexport const bashToolCommandHasPermission = (\n tool: Tool,\n command: string,\n prefix: string | null,\n allowedTools: string[],\n): boolean => {\n // Check exact match first\n if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) {\n return true\n }\n const prefixKey = getPermissionKey(tool, { command }, prefix)\n if (allowedTools.includes(prefixKey)) {\n return true\n }\n // Check wildcard patterns in allowedTools (e.g. Bash(*--help*))\n const commandKey = getPermissionKey(tool, { command }, null)\n for (const allowed of allowedTools) {\n if (\n allowed.includes('*') &&\n matchesPermissionWildcard(commandKey, allowed)\n ) {\n return true\n }\n }\n return false\n}\n\nexport const bashToolHasPermission = async (\n tool: Tool,\n command: string,\n context: ToolUseContext,\n allowedTools: string[],\n getCommandSubcommandPrefixFn = getCommandSubcommandPrefix,\n): Promise<PermissionResult> => {\n if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) {\n // This is an exact match for a command that is allowed, so we can skip the prefix check\n return { result: true }\n }\n\n const subCommands = splitCommand(command).filter(_ => {\n // Denim likes to add this, we strip it out so we don't need to prompt the user each time\n if (_ === `cd ${getCwd()}`) {\n return false\n }\n return true\n })\n const commandSubcommandPrefix = await getCommandSubcommandPrefixFn(\n command,\n context.abortController.signal,\n )\n if (context.abortController.signal.aborted) {\n throw new AbortError()\n }\n\n if (commandSubcommandPrefix === null) {\n // Fail closed and ask for user approval if the command prefix query failed (e.g. due to network error)\n // This is NOT the same as `fullCommandPrefix.commandPrefix === null`, which means no prefix was detected\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n\n if (commandSubcommandPrefix.commandInjectionDetected) {\n // Only allow exact matches for potential command injections\n if (bashToolCommandHasExactMatchPermission(tool, command, allowedTools)) {\n return { result: true }\n } else {\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n }\n\n // After the commandInjectionDetected check above, TypeScript still sees the union type.\n // We know commandInjectionDetected is false here, so commandPrefix exists.\n // Use 'in' check for proper type narrowing\n const commandPrefix =\n 'commandPrefix' in commandSubcommandPrefix\n ? commandSubcommandPrefix.commandPrefix\n : null\n\n // If there is only one command, no need to process subCommands\n if (subCommands.length < 2) {\n if (\n bashToolCommandHasPermission(tool, command, commandPrefix, allowedTools)\n ) {\n return { result: true }\n } else {\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n }\n if (\n subCommands.every(subCommand => {\n const prefixResult =\n commandSubcommandPrefix.subcommandPrefixes.get(subCommand)\n if (prefixResult === undefined || prefixResult.commandInjectionDetected) {\n // If prefix result is missing or command injection is detected, always ask for permission\n return false\n }\n // After the check above, we know commandInjectionDetected is false\n // Use 'in' check for proper type narrowing\n const subCommandPrefix =\n 'commandPrefix' in prefixResult ? prefixResult.commandPrefix : null\n const hasPermission = bashToolCommandHasPermission(\n tool,\n subCommand,\n subCommandPrefix,\n allowedTools,\n )\n return hasPermission\n })\n ) {\n return { result: true }\n }\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n}\n\ntype PermissionResult = { result: true } | { result: false; message: string }\n\n/**\n * Get effective safety mode from context options\n * Handles backward compatibility with legacy safeMode boolean\n */\nfunction getEffectiveSafetyMode(options: {\n safeMode?: boolean\n safetyMode?: SafetyMode\n}): SafetyMode {\n // New safetyMode takes precedence\n if (options.safetyMode) {\n return options.safetyMode\n }\n // Backward compatibility: convert legacy safeMode boolean\n // safeMode: true \u2192 'strict' (old behavior)\n // safeMode: false \u2192 'free' (permissive, device-wide)\n if (options.safeMode === true) {\n return 'strict'\n }\n // Default to 'smart' for safety (dangerous tools require confirmation)\n return 'smart'\n}\n\n/**\n * Check if a path is within the project directory\n * Used by Free mode to allow operations within project boundaries\n */\nfunction isPathWithinProject(targetPath: string, projectDir: string): boolean {\n // Resolve to absolute path\n const absolutePath = isAbsolute(targetPath)\n ? resolve(targetPath)\n : resolve(projectDir, targetPath)\n\n // Get relative path from project directory\n const relativePath = relative(projectDir, absolutePath)\n\n // Path is within project if:\n // 1. It doesn't start with '..' (not escaping project)\n // 2. It's not an absolute path (after relative calculation)\n return !relativePath.startsWith('..') && !isAbsolute(relativePath)\n}\n\n/**\n * System critical paths that should NEVER be auto-allowed, even in Free mode\n * These paths require explicit user confirmation regardless of safety mode\n */\nconst SYSTEM_CRITICAL_PATHS = [\n '/etc',\n '/bin',\n '/sbin',\n '/usr/bin',\n '/usr/sbin',\n '/var',\n '/System',\n '/Library',\n '/Applications',\n '/private',\n 'C:\\\\Windows',\n 'C:\\\\Program Files',\n 'C:\\\\Program Files (x86)',\n]\n\n/**\n * Check if a path is a system critical path\n */\nfunction isSystemCriticalPath(targetPath: string): boolean {\n const normalizedPath = resolve(targetPath).toLowerCase()\n return SYSTEM_CRITICAL_PATHS.some(criticalPath =>\n normalizedPath.startsWith(criticalPath.toLowerCase()),\n )\n}\n\n/**\n * Extract paths from tool input for boundary checking in Free mode\n */\nfunction extractPathsFromToolInput(\n toolName: string,\n input: { [k: string]: unknown },\n): string[] {\n const paths: string[] = []\n\n // File tools\n if (toolName === 'Read' || toolName === 'Write' || toolName === 'Edit') {\n if (typeof input.file_path === 'string') {\n paths.push(input.file_path)\n }\n }\n\n // Glob/Grep tools\n if (toolName === 'Glob' || toolName === 'Grep') {\n if (typeof input.path === 'string') {\n paths.push(input.path)\n }\n }\n\n // LS tool\n if (toolName === 'LS') {\n if (typeof input.path === 'string') {\n paths.push(input.path)\n }\n }\n\n // NotebookEdit\n if (toolName === 'NotebookEdit') {\n if (typeof input.notebook_path === 'string') {\n paths.push(input.notebook_path)\n }\n }\n\n return paths\n}\n\n/**\n * Extract paths from a Bash command for boundary checking\n * This is a simplified extraction - complex commands may need manual review\n */\nfunction extractPathsFromBashCommand(command: string): string[] {\n const paths: string[] = []\n\n // Extract quoted paths\n const quotedMatches = command.matchAll(/[\"']([^\"']+)[\"']/g)\n for (const match of quotedMatches) {\n if (match[1] && (match[1].includes('/') || match[1].startsWith('.'))) {\n paths.push(match[1])\n }\n }\n\n // Extract unquoted paths (starting with ./ or / or ../)\n const unquotedMatches = command.matchAll(\n /(?:^|\\s)((?:\\.\\/|\\/|\\.\\.\\/)[^\\s;&|>]+)/g,\n )\n for (const match of unquotedMatches) {\n if (match[1]) {\n paths.push(match[1])\n }\n }\n\n // Extract redirect targets\n const redirectMatches = command.matchAll(/>\\s*[\"']?([^\\s\"';&|]+)[\"']?/g)\n for (const match of redirectMatches) {\n if (match[1] && !match[1].startsWith('&')) {\n paths.push(match[1])\n }\n }\n\n return [...new Set(paths)] // Deduplicate\n}\n\n/**\n * Check if all paths in an operation are within the project directory\n * Used by Free mode for path-based permission decisions\n */\nfunction areAllPathsWithinProject(\n toolName: string,\n input: { [k: string]: unknown },\n projectDir: string,\n): { withinProject: boolean; outsidePaths: string[] } {\n let paths: string[] = []\n\n // For Bash tool, extract paths from command\n if (toolName === 'Bash' && typeof input.command === 'string') {\n paths = extractPathsFromBashCommand(input.command)\n } else {\n paths = extractPathsFromToolInput(toolName, input)\n }\n\n // If no paths detected, allow by default (e.g., pwd, date, etc.)\n if (paths.length === 0) {\n return { withinProject: true, outsidePaths: [] }\n }\n\n const outsidePaths: string[] = []\n for (const path of paths) {\n // Check system critical paths first\n if (isSystemCriticalPath(path)) {\n outsidePaths.push(path)\n continue\n }\n\n // Check if path is within project\n if (!isPathWithinProject(path, projectDir)) {\n outsidePaths.push(path)\n }\n }\n\n return {\n withinProject: outsidePaths.length === 0,\n outsidePaths,\n }\n}\n\n/**\n * Check if a tool should be allowed based on safety mode and risk level\n *\n * Safety Mode Matrix:\n * | Mode | Safe Tools | Monitored Tools | Dangerous Tools |\n * |--------|------------|-----------------|-----------------|\n * | free | \u2713 allow | \u2713 allow | \u2713 allow |\n * | smart | \u2713 allow | \u2713 allow | \u26A0 ask |\n * | strict | \u2713 allow | \u26A0 ask | \u26A0 ask |\n * | yolo | Path-based: within project = allow, outside = ask |\n *\n * free = Device-wide full permission (no restrictions)\n * yolo = Project-scoped full permission (auto-allow within project dir)\n * smart = Balanced (safe + monitored auto-allow, dangerous requires confirm)\n * strict = Conservative (only safe auto-allowed)\n */\nfunction shouldAllowByRiskLevel(\n safetyMode: SafetyMode,\n riskLevel: RiskLevel,\n toolName?: string,\n input?: { [k: string]: unknown },\n): boolean {\n switch (safetyMode) {\n case 'free':\n // Free mode: device-wide full permission, allow everything\n return true\n case 'smart':\n // Smart mode: allow safe and monitored, ask for dangerous\n return riskLevel === 'safe' || riskLevel === 'monitored'\n case 'strict':\n // Strict mode: only allow safe tools\n return riskLevel === 'safe'\n case 'yolo':\n // YOLO mode: project-scoped full permission\n // Safe tools (read-only) are always allowed\n if (riskLevel === 'safe') {\n return true\n }\n // For tools with side effects, check path boundaries\n if (toolName && input) {\n const projectDir = getCwd()\n const { withinProject } = areAllPathsWithinProject(\n toolName,\n input,\n projectDir,\n )\n return withinProject\n }\n // If we can't determine paths, ask for confirmation\n return false\n }\n}\n\n/**\n * Load permission deny/allow rules from settings.json files.\n * Checks: .minto/settings.json, .claude/settings.json, ~/.minto/settings.json, ~/.claude/settings.json\n */\nlet settingsPermissionsCache: {\n deny: string[]\n allow: string[]\n} | null = null\nlet settingsPermissionsCacheTimestamp = 0\nconst SETTINGS_CACHE_TTL = 30_000 // Invalidate every 30 seconds\n\n/**\n * Force invalidation of the settings permissions cache.\n * Call this when settings files change (e.g., ConfigChange hook).\n */\nexport function invalidateSettingsPermissionsCache(): void {\n settingsPermissionsCache = null\n settingsPermissionsCacheTimestamp = 0\n}\n\nfunction loadSettingsPermissions(): { deny: string[]; allow: string[] } {\n const now = Date.now()\n if (\n settingsPermissionsCache &&\n now - settingsPermissionsCacheTimestamp < SETTINGS_CACHE_TTL\n ) {\n return settingsPermissionsCache\n }\n\n const deny: string[] = []\n const allow: string[] = []\n\n const cwd = getCwd()\n const home = homedir()\n\n // Check settings files in priority order (later overrides earlier)\n const settingsFiles = [\n join(home, '.claude', 'settings.json'),\n join(home, CONFIG_BASE_DIR, 'settings.json'),\n join(cwd, '.claude', 'settings.json'),\n join(cwd, CONFIG_BASE_DIR, 'settings.json'),\n ]\n\n // Track which files are project-level (not user home)\n const homeDir = home\n for (const file of settingsFiles) {\n if (!existsSync(file)) continue\n const isProjectLevel =\n !file.startsWith(homeDir + '/.claude') &&\n !file.startsWith(homeDir + '/' + CONFIG_BASE_DIR)\n try {\n const content = JSON.parse(readFileSync(file, 'utf-8'))\n if (\n content?.permissions?.deny &&\n Array.isArray(content.permissions.deny)\n ) {\n deny.push(...content.permissions.deny)\n }\n if (\n content?.permissions?.allow &&\n Array.isArray(content.permissions.allow)\n ) {\n if (isProjectLevel) {\n // Security: project-level settings can only allow safe operations\n // (read-only tools). Dangerous tool auto-approval requires user-level config.\n const safeProjectAllows = content.permissions.allow.filter(\n (pattern: string) =>\n ['Read', 'Glob', 'Grep', 'LS', 'NotebookRead'].includes(pattern),\n )\n allow.push(...safeProjectAllows)\n } else {\n allow.push(...content.permissions.allow)\n }\n }\n } catch {\n // Ignore malformed settings files\n }\n }\n\n settingsPermissionsCache = { deny, allow }\n settingsPermissionsCacheTimestamp = Date.now()\n return settingsPermissionsCache\n}\n\n/**\n * Check if tool matches any pattern in a permission list.\n * Patterns can be exact tool names or tool(pattern) for Bash commands.\n */\nfunction matchesPermissionPattern(\n toolName: string,\n input: { [k: string]: unknown } | undefined,\n patterns: string[],\n): boolean {\n for (const pattern of patterns) {\n // Exact tool name match\n if (pattern === toolName) return true\n\n // Bash command pattern: Bash(command:*)\n if (toolName === 'Bash' && pattern.startsWith('Bash(') && input?.command) {\n const cmdPattern = pattern.slice(5, -1) // Remove Bash( and )\n const command = String(input.command)\n if (cmdPattern.endsWith(':*')) {\n const prefix = cmdPattern.slice(0, -2)\n if (command.startsWith(prefix)) return true\n } else if (command === cmdPattern) {\n return true\n }\n }\n }\n return false\n}\n\nexport const hasPermissionsToUseTool: CanUseToolFn = async (\n tool,\n input,\n context,\n _assistantMessage,\n): Promise<PermissionResult> => {\n // Bypass Permissions mode: team agents run non-interactively\n if (context?.options?.permissionMode === 'bypassPermissions') {\n return { result: true }\n }\n\n // Plan Mode restriction: block write tools\n const planMode = isPlanModeEnabled(context)\n if (planMode) {\n const PLAN_MODE_BLOCKED_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'MultiEdit',\n 'NotebookEdit',\n 'Bash',\n ])\n if (PLAN_MODE_BLOCKED_TOOLS.has(tool.name)) {\n return {\n result: false,\n message: `Tool \"${tool.name}\" is not available in plan mode. Only read-only tools are allowed. Use ExitPlanMode to start implementing changes.`,\n }\n }\n }\n\n // Delegate Mode restriction: only team/task tools allowed\n if (\n context?.options?.permissionMode === 'delegate' ||\n context?.options?.mode === 'delegate'\n ) {\n const DELEGATE_ALLOWED_TOOLS = new Set([\n 'TeamCreate',\n 'TeamDelete',\n 'SendMessage',\n 'TaskCreate',\n 'TaskGet',\n 'TaskUpdate',\n 'TaskList',\n ])\n if (!DELEGATE_ALLOWED_TOOLS.has(tool.name)) {\n return {\n result: false,\n message: `Tool \"${tool.name}\" is not available in delegate mode. Only team/task coordination tools are allowed (TeamCreate, TeamDelete, SendMessage, TaskCreate, TaskGet, TaskUpdate, TaskList).`,\n }\n }\n }\n\n // Step 0: Check settings.json deny rules (highest priority - block immediately)\n const settingsPerms = loadSettingsPermissions()\n if (\n matchesPermissionPattern(\n tool.name,\n input as { [k: string]: unknown },\n settingsPerms.deny,\n )\n ) {\n return {\n result: false,\n message: `Tool \"${tool.name}\" is denied by settings configuration.`,\n }\n }\n\n // Step 0b: Check settings.json allow rules (explicit allow)\n if (\n matchesPermissionPattern(\n tool.name,\n input as { [k: string]: unknown },\n settingsPerms.allow,\n )\n ) {\n return { result: true }\n }\n\n // Get permission mode and risk level for mode-specific checks\n const permissionMode = context?.options?.permissionMode as string | undefined\n\n const riskLevel = getToolRiskLevel(\n tool.name,\n input as { command?: string } | undefined,\n )\n\n // Step 1: acceptEdits mode \u2014 auto-approve file edits within working directory\n // Matches Claude Code behavior: only Edit/Write/NotebookEdit are auto-approved,\n // only when the target file is within the project directory.\n // Bash and other tools still go through normal permission flow.\n if (permissionMode === 'acceptEdits') {\n const FILE_EDIT_TOOLS = new Set([\n 'Edit',\n 'Write',\n 'NotebookEdit',\n 'MultiEdit',\n ])\n if (FILE_EDIT_TOOLS.has(tool.name)) {\n const paths = extractPathsFromToolInput(\n tool.name,\n input as { [k: string]: unknown },\n )\n const projectDir = getCwd()\n const allWithinProject =\n paths.length === 0 ||\n paths.every(\n p => !isSystemCriticalPath(p) && isPathWithinProject(p, projectDir),\n )\n if (allWithinProject) {\n return { result: true }\n }\n }\n // Non-edit tools fall through to normal Safety Mode checks\n }\n\n // Step 2: dontAsk mode \u2014 auto-deny tools not pre-approved via settings.json allow rules\n // If we reach here, the tool was NOT matched by settings.json allow rules (step 0b).\n // In dontAsk mode: safe/read-only tools are still allowed, everything else is auto-denied.\n // This matches Claude Code's CI/CD behavior: no prompting, silent denial.\n if (permissionMode === 'dontAsk') {\n if (riskLevel !== 'safe') {\n return {\n result: false,\n message: `Permission to use ${tool.name} has been auto-denied in dontAsk mode. Add it to permissions.allow in settings to enable it.`,\n }\n }\n // Safe tools continue through \u2014 they don't need permission\n }\n\n const safetyMode = getEffectiveSafetyMode(context.options)\n\n // Step 3: Check if this tool should be auto-allowed based on safety mode and risk level\n // For YOLO mode, we also pass tool name and input for path-based decisions\n if (\n shouldAllowByRiskLevel(\n safetyMode,\n riskLevel,\n tool.name,\n input as { [k: string]: unknown },\n )\n ) {\n return { result: true }\n }\n\n if (context.abortController.signal.aborted) {\n throw new AbortError()\n }\n\n // Check if the tool needs permissions\n try {\n if (!tool.needsPermissions(input as never)) {\n return { result: true }\n }\n } catch (e) {\n logError(`Error checking permissions: ${e}`)\n return { result: false, message: 'Error checking permissions' }\n }\n\n const projectConfig = getCurrentProjectConfig()\n const allowedTools = projectConfig.allowedTools ?? []\n // Special case for BashTool to allow blanket commands without exposing them in the UI\n if (tool === BashTool && allowedTools.includes(BashTool.name)) {\n return { result: true }\n }\n\n // TODO: Move this into tool definitions (done for read tools!)\n switch (tool) {\n // For bash tool, check each sub-command's permissions separately\n case BashTool: {\n // The types have already been validated by the tool,\n // so we can safely parse the input (as opposed to safeParse).\n const { command } = inputSchema.parse(input)\n return await bashToolHasPermission(tool, command, context, allowedTools)\n }\n // For file editing tools, check session-only permissions\n case FileEditTool:\n case FileWriteTool:\n case NotebookEditTool: {\n // The types have already been validated by the tool,\n // so we can safely pass this in\n if (!tool.needsPermissions(input)) {\n return { result: true }\n }\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n // For other tools, check persistent permissions\n default: {\n const permissionKey = getPermissionKey(tool, input, null)\n if (allowedTools.includes(permissionKey)) {\n return { result: true }\n }\n\n // Fire PermissionRequest hook before denying\n const hookDecision = await firePermissionRequestHook(\n tool.name,\n input as Record<string, unknown>,\n )\n if (hookDecision === 'approve') {\n return { result: true }\n }\n\n return {\n result: false,\n message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`,\n }\n }\n }\n}\n\n/**\n * Fire PermissionRequest hook when a tool needs permission\n * Returns 'approve' to auto-grant, 'block' to deny, or 'ask' to proceed normally\n */\nasync function firePermissionRequestHook(\n toolName: string,\n toolInput: Record<string, unknown>,\n): Promise<'approve' | 'block' | 'ask'> {\n try {\n const hookMgr = getHookManager()\n if (!hookMgr) return 'ask'\n\n const result = await hookMgr.executePermissionRequest(\n toolName,\n toolInput,\n 'other',\n )\n\n if (!result.shouldContinue && !result.shouldAskUser) {\n return 'block'\n }\n if (result.shouldContinue && !result.shouldAskUser) {\n // Check if hook explicitly approved (vs just no hooks matched)\n if (result.reason) return 'approve'\n }\n } catch {\n // Hook errors don't block permission flow\n }\n return 'ask'\n}\n\nexport async function savePermission(\n tool: Tool,\n input: { [k: string]: unknown },\n prefix: string | null,\n): Promise<void> {\n const key = getPermissionKey(tool, input, prefix)\n\n // For file editing tools, store write permissions only in memory\n if (\n tool === FileEditTool ||\n tool === FileWriteTool ||\n tool === NotebookEditTool\n ) {\n grantWritePermissionForOriginalDir()\n return\n }\n\n // For other tools, store permissions on disk\n const projectConfig = getCurrentProjectConfig()\n if (projectConfig.allowedTools.includes(key)) {\n return\n }\n\n projectConfig.allowedTools.push(key)\n projectConfig.allowedTools.sort()\n\n saveCurrentProjectConfig(projectConfig)\n}\n\nfunction getPermissionKey(\n tool: Tool,\n input: { [k: string]: unknown },\n prefix: string | null,\n): string {\n switch (tool) {\n case BashTool:\n if (prefix) {\n return `${BashTool.name}(${prefix}:*)`\n }\n return `${BashTool.name}(${BashTool.renderToolUseMessage(input as never)})`\n default:\n return tool.name\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/query.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  queryLLM
8
8
  } from "./services/claude.js";
9
9
  import { emitReminderEvent } from "./services/systemReminder.js";
10
+ import { getDeferredMCPTools } from "./services/mcpClient.js";
10
11
  import {
11
12
  TOOL_INPUT_EXAMPLES,
12
13
  TOOL_DESCRIPTIONS,
@@ -31,25 +32,44 @@ import {
31
32
  normalizeMessagesForAPI
32
33
  } from "./utils/messages.js";
33
34
  import { withTimeout, ToolTimeoutError } from "./utils/toolTimeout.js";
34
- import { setStreamingState, resetStreamingState } from "./utils/streamingState.js";
35
+ import {
36
+ setStreamingState,
37
+ resetStreamingState,
38
+ getStreamingState
39
+ } from "./utils/streamingState.js";
35
40
  import { BashTool } from "./tools/BashTool/BashTool.js";
41
+ const TOOL_RESULT_STRIPPED_TAGS = [
42
+ "user-guidance",
43
+ "team-message",
44
+ "task-notification",
45
+ "system-reminder"
46
+ ];
47
+ const TOOL_RESULT_TAG_REGEX = new RegExp(
48
+ `<(${TOOL_RESULT_STRIPPED_TAGS.join("|")})>[\\s\\S]*?</\\1>\\n?`,
49
+ "g"
50
+ );
51
+ function stripToolResultTags(text) {
52
+ return text.replace(TOOL_RESULT_TAG_REGEX, "").trim() || text;
53
+ }
36
54
  function normalizeToolResultContent(content) {
37
55
  if (content === null || content === void 0) {
38
56
  return "(no content)";
39
57
  }
40
58
  if (typeof content === "string") {
41
- return content || "(no content)";
59
+ return stripToolResultTags(content) || "(no content)";
42
60
  }
43
61
  if (Array.isArray(content)) {
44
- return content.map((item) => {
62
+ const joined = content.map((item) => {
45
63
  if (typeof item === "string") return item;
46
64
  if (item && typeof item === "object" && "text" in item)
47
65
  return String(item.text);
48
66
  return JSON.stringify(item);
49
67
  }).join("\n");
68
+ return stripToolResultTags(joined);
50
69
  }
51
70
  if (typeof content === "object") {
52
- if ("text" in content) return String(content.text);
71
+ if ("text" in content)
72
+ return stripToolResultTags(String(content.text));
53
73
  return JSON.stringify(content);
54
74
  }
55
75
  return String(content);
@@ -94,7 +114,8 @@ async function queryWithBinaryFeedback(toolUseContext, getAssistantResponse, get
94
114
  }
95
115
  return await getBinaryFeedbackResponse(m1, m2);
96
116
  }
97
- async function* query(messages, systemPrompt, context, canUseTool, toolUseContext, getBinaryFeedbackResponse, _depth = 0) {
117
+ async function* query(messages, systemPrompt, context, canUseTool, toolUseContext, getBinaryFeedbackResponse, _depth = 0, _normalizeCache) {
118
+ const normalizeCache = _normalizeCache ?? { length: -1, result: [] };
98
119
  if (_depth > MAX_QUERY_DEPTH) {
99
120
  const error = new QueryDepthExceededError(_depth);
100
121
  logError(error);
@@ -103,33 +124,77 @@ async function* query(messages, systemPrompt, context, canUseTool, toolUseContex
103
124
  }
104
125
  const currentRequest = getCurrentRequest();
105
126
  markPhase("QUERY_INIT");
106
- setStreamingState({ phase: "compacting" });
107
- const { messages: processedMessages, wasCompacted } = await checkAutoCompact(
108
- messages,
109
- toolUseContext
110
- );
111
- if (wasCompacted) {
112
- messages = processedMessages;
113
- debug.flow("CONTEXT_COMPACTED", {
114
- originalCount: messages.length,
115
- compactedCount: processedMessages.length
116
- });
127
+ if (_depth === 0) {
128
+ try {
129
+ const { getGlobalConfig } = await import("./utils/config.js");
130
+ const config = getGlobalConfig();
131
+ if (config.enableTopicDetection && messages.length >= 3) {
132
+ const { detectTopic, isDefinitiveNewTopic } = await import("./services/topicDetector.js");
133
+ const lastMsg = messages[messages.length - 1];
134
+ const newMessageText = lastMsg?.type === "user" && typeof lastMsg.message.content === "string" ? lastMsg.message.content : null;
135
+ if (newMessageText) {
136
+ const contextMessages = messages.slice(0, -1);
137
+ const topicResult = await detectTopic(contextMessages, newMessageText);
138
+ if (isDefinitiveNewTopic(topicResult)) {
139
+ debug.flow("NEW_TOPIC_DETECTED", {
140
+ confidence: topicResult.confidence,
141
+ reason: topicResult.reason ?? "none"
142
+ });
143
+ }
144
+ }
145
+ }
146
+ } catch (error) {
147
+ debug.warn(
148
+ "TOPIC_DETECTION_PREFLIGHT_ERROR",
149
+ error instanceof Error ? error.message : String(error)
150
+ );
151
+ }
152
+ }
153
+ if (_depth === 0) {
154
+ const { messages: processedMessages, wasCompacted } = await checkAutoCompact(messages, toolUseContext);
155
+ if (wasCompacted) {
156
+ setStreamingState({ phase: "compacting" });
157
+ messages = processedMessages;
158
+ debug.flow("CONTEXT_COMPACTED", {
159
+ originalCount: messages.length,
160
+ compactedCount: processedMessages.length
161
+ });
162
+ }
117
163
  }
118
164
  markPhase("SYSTEM_PROMPT_BUILD");
119
165
  const { systemPrompt: fullSystemPrompt, reminders } = formatSystemPromptWithContext(systemPrompt, context, toolUseContext.agentId);
120
- emitReminderEvent("session:startup", {
121
- agentId: toolUseContext.agentId,
122
- messages: messages.length,
123
- timestamp: Date.now()
124
- });
166
+ if (_depth === 0) {
167
+ emitReminderEvent("session:startup", {
168
+ agentId: toolUseContext.agentId,
169
+ messages: messages.length,
170
+ timestamp: Date.now()
171
+ });
172
+ }
125
173
  if (reminders) {
126
174
  fullSystemPrompt.push(reminders);
127
175
  }
176
+ const deferredTools = getDeferredMCPTools();
177
+ if (deferredTools.size > 0) {
178
+ const toolNames = Array.from(deferredTools.keys()).join("\n");
179
+ fullSystemPrompt.push(
180
+ `<available-deferred-tools>
181
+ ${toolNames}
182
+ </available-deferred-tools>`
183
+ );
184
+ }
128
185
  markPhase("LLM_PREPARATION");
129
- setStreamingState({ phase: "waiting" });
186
+ const currentState = getStreamingState();
187
+ setStreamingState({
188
+ phase: "waiting",
189
+ ...currentState.phase !== "tool_use" && currentState.phase !== "generating" && { turnStartedAt: Date.now() }
190
+ });
130
191
  function getAssistantResponse() {
192
+ if (messages.length !== normalizeCache.length) {
193
+ normalizeCache.result = normalizeMessagesForAPI(messages);
194
+ normalizeCache.length = messages.length;
195
+ }
131
196
  return queryLLM(
132
- normalizeMessagesForAPI(messages),
197
+ normalizeCache.result,
133
198
  fullSystemPrompt,
134
199
  toolUseContext.options.maxThinkingTokens,
135
200
  toolUseContext.options.tools,
@@ -148,16 +213,18 @@ async function* query(messages, systemPrompt, context, canUseTool, toolUseContex
148
213
  getBinaryFeedbackResponse
149
214
  );
150
215
  if (toolUseContext.abortController.signal.aborted) {
216
+ resetStreamingState();
151
217
  yield createAssistantMessage(INTERRUPT_MESSAGE);
152
218
  return;
153
219
  }
154
220
  if (result.message === null) {
221
+ resetStreamingState();
155
222
  yield createAssistantMessage(INTERRUPT_MESSAGE);
156
223
  return;
157
224
  }
158
225
  const assistantMessage = result.message;
159
226
  const shouldSkipPermissionCheck = result.shouldSkipPermissionCheck;
160
- setStreamingState({ phase: "generating" });
227
+ setStreamingState({ phase: "generating", streamingText: void 0 });
161
228
  yield assistantMessage;
162
229
  const toolUseMessages = assistantMessage.message.content.filter(
163
230
  (_) => _.type === "tool_use"
@@ -166,7 +233,8 @@ async function* query(messages, systemPrompt, context, canUseTool, toolUseContex
166
233
  resetStreamingState();
167
234
  const hookManager = getHookManager();
168
235
  if (hookManager) {
169
- hookManager.executeStop().catch(() => {
236
+ hookManager.executeStop().catch((err) => {
237
+ debug.trace("HOOK_ERROR", { hook: "Stop", error: err });
170
238
  });
171
239
  }
172
240
  return;
@@ -278,36 +346,57 @@ async function* query(messages, systemPrompt, context, canUseTool, toolUseContex
278
346
  });
279
347
  }
280
348
  }
349
+ debug.trace("QUERY_TOOL_BOUNDARY_INJECT", {
350
+ hasMessages: toolUseContext.injectionChannel?.hasMessages(),
351
+ channelSize: toolUseContext.injectionChannel?.size
352
+ });
353
+ if (toolUseContext.injectionChannel?.hasMessages()) {
354
+ const pending = toolUseContext.injectionChannel.drain();
355
+ if (pending.length > 0) {
356
+ const guidanceText = pending.map((m) => m.text).join("\n\n");
357
+ const guidanceMessage = createUserMessage([
358
+ { type: "text", text: guidanceText }
359
+ ]);
360
+ additionalMessages.push(guidanceMessage);
361
+ yield guidanceMessage;
362
+ debug.flow("GUIDANCE_INJECTED", {
363
+ messageCount: pending.length,
364
+ textLength: guidanceText.length
365
+ });
366
+ }
367
+ }
281
368
  try {
369
+ messages.push(
370
+ assistantMessage,
371
+ ...orderedToolResults,
372
+ ...additionalMessages
373
+ );
282
374
  yield* await query(
283
- [
284
- ...messages,
285
- assistantMessage,
286
- ...orderedToolResults,
287
- ...additionalMessages
288
- ],
375
+ messages,
289
376
  systemPrompt,
290
377
  context,
291
378
  canUseTool,
292
379
  modifiedContext,
293
380
  // Use modified context if contextModifier was applied
294
381
  getBinaryFeedbackResponse,
295
- _depth + 1
382
+ _depth + 1,
296
383
  // Increment depth for recursion tracking
384
+ normalizeCache
385
+ // Pass through per-call-chain cache
297
386
  );
298
387
  } catch (error) {
299
388
  const errorMessage = error instanceof Error ? error.message : String(error);
300
389
  logError(`Recursive query error: ${errorMessage}`);
301
390
  yield createAssistantAPIErrorMessage(`Query failed: ${errorMessage}`);
302
- throw error;
303
391
  }
304
392
  }
305
393
  async function* runToolsConcurrently(toolUseMessages, assistantMessage, canUseTool, toolUseContext, shouldSkipPermissionCheck) {
394
+ const toolUseIds = new Set(toolUseMessages.map((_) => _.id));
306
395
  yield* all(
307
396
  toolUseMessages.map(
308
397
  (toolUse) => runToolUse(
309
398
  toolUse,
310
- new Set(toolUseMessages.map((_) => _.id)),
399
+ toolUseIds,
311
400
  assistantMessage,
312
401
  canUseTool,
313
402
  toolUseContext,
@@ -320,10 +409,11 @@ async function* runToolsConcurrently(toolUseMessages, assistantMessage, canUseTo
320
409
  );
321
410
  }
322
411
  async function* runToolsSerially(toolUseMessages, assistantMessage, canUseTool, toolUseContext, shouldSkipPermissionCheck) {
412
+ const toolUseIds = new Set(toolUseMessages.map((_) => _.id));
323
413
  for (const toolUse of toolUseMessages) {
324
414
  yield* runToolUse(
325
415
  toolUse,
326
- new Set(toolUseMessages.map((_) => _.id)),
416
+ toolUseIds,
327
417
  assistantMessage,
328
418
  canUseTool,
329
419
  toolUseContext,
@@ -432,7 +522,11 @@ async function* runToolUse(toolUse, siblingToolUseIDs, assistantMessage, canUseT
432
522
  toolName,
433
523
  toolInput,
434
524
  e instanceof Error ? e.message : String(e)
435
- ).catch(() => {
525
+ ).catch((err) => {
526
+ debug.trace("HOOK_ERROR", {
527
+ hook: "PostToolUseFailure",
528
+ error: err
529
+ });
436
530
  });
437
531
  }
438
532
  const errorMessage = createUserMessage([
@@ -689,7 +783,11 @@ async function* checkPermissionsAndCallTool(tool, toolUseID, siblingToolUseIDs,
689
783
  normalizedInput,
690
784
  error instanceof Error ? error.message : String(error),
691
785
  error instanceof ToolTimeoutError ? "timeout" : void 0
692
- ).catch(() => {
786
+ ).catch((err) => {
787
+ debug.trace("HOOK_ERROR", {
788
+ hook: "PostToolUseFailure",
789
+ error: err
790
+ });
693
791
  });
694
792
  }
695
793
  if (error instanceof ToolTimeoutError) {