@within-7/minto 0.3.9 → 0.4.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 (383) hide show
  1. package/dist/Tool.js.map +2 -2
  2. package/dist/commands/agents/AgentsCommand.js +461 -657
  3. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  4. package/dist/commands/agents/types.js +1 -0
  5. package/dist/commands/agents/types.js.map +2 -2
  6. package/dist/commands/agents/utils/fileOperations.js +96 -36
  7. package/dist/commands/agents/utils/fileOperations.js.map +3 -3
  8. package/dist/commands/agents/utils/index.js +3 -1
  9. package/dist/commands/agents/utils/index.js.map +2 -2
  10. package/dist/commands/context.js +54 -23
  11. package/dist/commands/context.js.map +2 -2
  12. package/dist/commands/ctx_viz.js +1 -1
  13. package/dist/commands/effort.js +87 -0
  14. package/dist/commands/effort.js.map +7 -0
  15. package/dist/commands/export.js +684 -94
  16. package/dist/commands/export.js.map +2 -2
  17. package/dist/commands/ide.js +18 -0
  18. package/dist/commands/ide.js.map +7 -0
  19. package/dist/commands/language.js +19 -46
  20. package/dist/commands/language.js.map +2 -2
  21. package/dist/commands/mcp-interactive.js +425 -217
  22. package/dist/commands/mcp-interactive.js.map +2 -2
  23. package/dist/commands/memory.js +168 -0
  24. package/dist/commands/memory.js.map +7 -0
  25. package/dist/commands/model.js +457 -65
  26. package/dist/commands/model.js.map +2 -2
  27. package/dist/commands/outputStyle.js +64 -0
  28. package/dist/commands/outputStyle.js.map +7 -0
  29. package/dist/commands/permissions.js +75 -49
  30. package/dist/commands/permissions.js.map +2 -2
  31. package/dist/commands/plugin/utils.js +33 -1
  32. package/dist/commands/plugin/utils.js.map +2 -2
  33. package/dist/commands/plugin.js +891 -185
  34. package/dist/commands/plugin.js.map +3 -3
  35. package/dist/commands/refreshCommands.js +2 -0
  36. package/dist/commands/refreshCommands.js.map +2 -2
  37. package/dist/commands/resume.js +1 -1
  38. package/dist/commands/resume.js.map +1 -1
  39. package/dist/commands/review.js +51 -0
  40. package/dist/commands/review.js.map +7 -0
  41. package/dist/commands/sandbox.js +168 -70
  42. package/dist/commands/sandbox.js.map +2 -2
  43. package/dist/commands/setup.js +593 -107
  44. package/dist/commands/setup.js.map +2 -2
  45. package/dist/commands/stats.js +188 -131
  46. package/dist/commands/stats.js.map +2 -2
  47. package/dist/commands/status.js +75 -13
  48. package/dist/commands/status.js.map +2 -2
  49. package/dist/commands/terminalSetup.js +6 -0
  50. package/dist/commands/terminalSetup.js.map +2 -2
  51. package/dist/commands/undo.js +146 -174
  52. package/dist/commands/undo.js.map +2 -2
  53. package/dist/commands/vim.js +22 -0
  54. package/dist/commands/vim.js.map +7 -0
  55. package/dist/commands.js +12 -0
  56. package/dist/commands.js.map +2 -2
  57. package/dist/components/Help.js +165 -32
  58. package/dist/components/Help.js.map +2 -2
  59. package/dist/components/HighlightedCode.js +1 -0
  60. package/dist/components/HighlightedCode.js.map +2 -2
  61. package/dist/components/InfoPanel/InfoPanel.js +123 -0
  62. package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
  63. package/dist/components/InfoPanel/index.js +5 -0
  64. package/dist/components/InfoPanel/index.js.map +7 -0
  65. package/dist/components/InfoPanel/types.js +1 -0
  66. package/dist/components/InfoPanel/types.js.map +7 -0
  67. package/dist/components/ModelSelector/BrandTextInput.js +43 -0
  68. package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
  69. package/dist/components/ModelSelector/ModelSelector.js +590 -565
  70. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  71. package/dist/components/ModelSelector/WizardContainer.js +45 -0
  72. package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
  73. package/dist/components/ModelSelector/index.js +1 -3
  74. package/dist/components/ModelSelector/index.js.map +2 -2
  75. package/dist/components/PromptInput.js +26 -11
  76. package/dist/components/PromptInput.js.map +2 -2
  77. package/dist/components/PulseLabel.js +44 -0
  78. package/dist/components/PulseLabel.js.map +7 -0
  79. package/dist/components/RequestStatusIndicator.js +1 -1
  80. package/dist/components/RequestStatusIndicator.js.map +1 -1
  81. package/dist/components/SimpleSelector/SimpleSelector.js +154 -0
  82. package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
  83. package/dist/components/SimpleSelector/index.js +5 -0
  84. package/dist/components/SimpleSelector/index.js.map +7 -0
  85. package/dist/components/SimpleSelector/types.js +1 -0
  86. package/dist/components/SimpleSelector/types.js.map +7 -0
  87. package/dist/components/Spinner.js +12 -42
  88. package/dist/components/Spinner.js.map +3 -3
  89. package/dist/components/StartupStatus.js +57 -0
  90. package/dist/components/StartupStatus.js.map +7 -0
  91. package/dist/components/StatusOverlayContent.js +21 -0
  92. package/dist/components/StatusOverlayContent.js.map +7 -0
  93. package/dist/components/SubagentBlock.js +43 -6
  94. package/dist/components/SubagentBlock.js.map +2 -2
  95. package/dist/components/TabbedListView/ScrollableList.js +31 -5
  96. package/dist/components/TabbedListView/ScrollableList.js.map +2 -2
  97. package/dist/components/TabbedListView/TabBar.js +13 -8
  98. package/dist/components/TabbedListView/TabBar.js.map +2 -2
  99. package/dist/components/TabbedListView/TabbedListView.js +123 -48
  100. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  101. package/dist/components/TodoPanel.js +1 -1
  102. package/dist/components/TodoPanel.js.map +1 -1
  103. package/dist/components/ToolUseLoader.js +5 -0
  104. package/dist/components/ToolUseLoader.js.map +2 -2
  105. package/dist/components/TrustDialog.js +0 -2
  106. package/dist/components/TrustDialog.js.map +2 -2
  107. package/dist/components/messages/TaskInModuleView.js +1 -1
  108. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  109. package/dist/components/messages/TaskToolMessage.js +1 -1
  110. package/dist/components/messages/TaskToolMessage.js.map +2 -2
  111. package/dist/components/messages/UserPromptMessage.js +6 -1
  112. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  113. package/dist/constants/modelCapabilities.js +103 -18
  114. package/dist/constants/modelCapabilities.js.map +2 -2
  115. package/dist/constants/product.js +2 -0
  116. package/dist/constants/product.js.map +2 -2
  117. package/dist/constants/prompts/agentPrompt.js +30 -0
  118. package/dist/constants/prompts/agentPrompt.js.map +7 -0
  119. package/dist/constants/prompts/codeConventions.js +27 -0
  120. package/dist/constants/prompts/codeConventions.js.map +7 -0
  121. package/dist/constants/prompts/doingTasks.js +15 -0
  122. package/dist/constants/prompts/doingTasks.js.map +7 -0
  123. package/dist/constants/prompts/envInfo.js +17 -0
  124. package/dist/constants/prompts/envInfo.js.map +7 -0
  125. package/dist/constants/prompts/executingWithCare.js +17 -0
  126. package/dist/constants/prompts/executingWithCare.js.map +7 -0
  127. package/dist/constants/prompts/identity.js +10 -0
  128. package/dist/constants/prompts/identity.js.map +7 -0
  129. package/dist/constants/prompts/index.js +78 -0
  130. package/dist/constants/prompts/index.js.map +7 -0
  131. package/dist/constants/prompts/taskManagement.js +60 -0
  132. package/dist/constants/prompts/taskManagement.js.map +7 -0
  133. package/dist/constants/prompts/toneAndStyle.js +62 -0
  134. package/dist/constants/prompts/toneAndStyle.js.map +7 -0
  135. package/dist/constants/prompts/toolUsagePolicy.js +38 -0
  136. package/dist/constants/prompts/toolUsagePolicy.js.map +7 -0
  137. package/dist/constants/prompts.js +5 -176
  138. package/dist/constants/prompts.js.map +2 -2
  139. package/dist/constants/providerRegistry.js +235 -0
  140. package/dist/constants/providerRegistry.js.map +7 -0
  141. package/dist/constants/providers.js +35 -0
  142. package/dist/constants/providers.js.map +7 -0
  143. package/dist/context/PermissionContext.js +0 -1
  144. package/dist/context/PermissionContext.js.map +2 -2
  145. package/dist/context.js +87 -31
  146. package/dist/context.js.map +2 -2
  147. package/dist/core/backupHook.js +29 -0
  148. package/dist/core/backupHook.js.map +7 -0
  149. package/dist/core/config/defaults.js +11 -2
  150. package/dist/core/config/defaults.js.map +2 -2
  151. package/dist/core/config/schema.js +21 -3
  152. package/dist/core/config/schema.js.map +2 -2
  153. package/dist/core/costTracker.js +18 -16
  154. package/dist/core/costTracker.js.map +2 -2
  155. package/dist/core/index.js +0 -1
  156. package/dist/core/index.js.map +2 -2
  157. package/dist/core/tokenStatsManager.js +22 -4
  158. package/dist/core/tokenStatsManager.js.map +2 -2
  159. package/dist/cost-tracker.js +0 -16
  160. package/dist/cost-tracker.js.map +2 -2
  161. package/dist/entrypoints/bootstrap.js +3 -1
  162. package/dist/entrypoints/bootstrap.js.map +2 -2
  163. package/dist/entrypoints/cli.js +81 -68
  164. package/dist/entrypoints/cli.js.map +2 -2
  165. package/dist/hooks/useAgentTokenStats.js +1 -1
  166. package/dist/hooks/useAgentTokenStats.js.map +2 -2
  167. package/dist/hooks/useAgentTranscripts.js +2 -1
  168. package/dist/hooks/useAgentTranscripts.js.map +2 -2
  169. package/dist/hooks/useBackgroundShells.js +29 -0
  170. package/dist/hooks/useBackgroundShells.js.map +7 -0
  171. package/dist/hooks/useCanUseTool.js +1 -1
  172. package/dist/hooks/useCanUseTool.js.map +2 -2
  173. package/dist/hooks/useDeferredLoading.js +64 -0
  174. package/dist/hooks/useDeferredLoading.js.map +7 -0
  175. package/dist/hooks/useHookStatus.js +1 -1
  176. package/dist/hooks/useHookStatus.js.map +2 -2
  177. package/dist/hooks/useSessionTracking.js +55 -0
  178. package/dist/hooks/useSessionTracking.js.map +7 -0
  179. package/dist/hooks/useTerminalSize.js +21 -0
  180. package/dist/hooks/useTerminalSize.js.map +2 -2
  181. package/dist/hooks/useTextInput.js +1 -0
  182. package/dist/hooks/useTextInput.js.map +2 -2
  183. package/dist/hooks/useUnifiedCompletion.js +3 -2
  184. package/dist/hooks/useUnifiedCompletion.js.map +2 -2
  185. package/dist/i18n/locales/en.js +299 -1
  186. package/dist/i18n/locales/en.js.map +2 -2
  187. package/dist/i18n/locales/zh-CN.js +300 -2
  188. package/dist/i18n/locales/zh-CN.js.map +2 -2
  189. package/dist/i18n/types.js.map +1 -1
  190. package/dist/messages.js +41 -17
  191. package/dist/messages.js.map +2 -2
  192. package/dist/permissions.js +94 -1
  193. package/dist/permissions.js.map +2 -2
  194. package/dist/query.js +27 -19
  195. package/dist/query.js.map +2 -2
  196. package/dist/screens/REPL.js +83 -74
  197. package/dist/screens/REPL.js.map +2 -2
  198. package/dist/services/adapters/responsesAPI.js +6 -0
  199. package/dist/services/adapters/responsesAPI.js.map +2 -2
  200. package/dist/services/agentTeams/index.js +35 -0
  201. package/dist/services/agentTeams/index.js.map +7 -0
  202. package/dist/services/agentTeams/mailbox.js +114 -0
  203. package/dist/services/agentTeams/mailbox.js.map +7 -0
  204. package/dist/services/agentTeams/teamManager.js +149 -0
  205. package/dist/services/agentTeams/teamManager.js.map +7 -0
  206. package/dist/services/agentTeams/teamTaskStore.js +114 -0
  207. package/dist/services/agentTeams/teamTaskStore.js.map +7 -0
  208. package/dist/services/agentTeams/teammateSpawner.js +80 -0
  209. package/dist/services/agentTeams/teammateSpawner.js.map +7 -0
  210. package/dist/services/checkpointManager.js +16 -3
  211. package/dist/services/checkpointManager.js.map +2 -2
  212. package/dist/services/claude.js +19 -1728
  213. package/dist/services/claude.js.map +3 -3
  214. package/dist/services/customCommands.js +30 -8
  215. package/dist/services/customCommands.js.map +2 -2
  216. package/dist/services/gpt5ConnectionTest.js +4 -2
  217. package/dist/services/gpt5ConnectionTest.js.map +2 -2
  218. package/dist/services/hookExecutor.js +411 -127
  219. package/dist/services/hookExecutor.js.map +2 -2
  220. package/dist/services/llm/anthropicProvider.js +807 -0
  221. package/dist/services/llm/anthropicProvider.js.map +7 -0
  222. package/dist/services/llm/dispatch.js +218 -0
  223. package/dist/services/llm/dispatch.js.map +7 -0
  224. package/dist/services/llm/index.js +44 -0
  225. package/dist/services/llm/index.js.map +7 -0
  226. package/dist/services/llm/mintoContext.js +69 -0
  227. package/dist/services/llm/mintoContext.js.map +7 -0
  228. package/dist/services/llm/openaiProvider.js +622 -0
  229. package/dist/services/llm/openaiProvider.js.map +7 -0
  230. package/dist/services/llm/types.js +157 -0
  231. package/dist/services/llm/types.js.map +7 -0
  232. package/dist/services/mcpClient.js +183 -33
  233. package/dist/services/mcpClient.js.map +2 -2
  234. package/dist/services/notifier.js +14 -0
  235. package/dist/services/notifier.js.map +2 -2
  236. package/dist/services/oauth.js +4 -2
  237. package/dist/services/oauth.js.map +2 -2
  238. package/dist/services/openai.js +66 -56
  239. package/dist/services/openai.js.map +3 -3
  240. package/dist/services/outputStyles.js +102 -21
  241. package/dist/services/outputStyles.js.map +2 -2
  242. package/dist/services/plugins/lspServers.js +1 -1
  243. package/dist/services/plugins/lspServers.js.map +2 -2
  244. package/dist/services/plugins/pluginRuntime.js +2 -1
  245. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  246. package/dist/services/plugins/pluginValidation.js +10 -3
  247. package/dist/services/plugins/pluginValidation.js.map +2 -2
  248. package/dist/services/plugins/skillMarketplace.js +20 -9
  249. package/dist/services/plugins/skillMarketplace.js.map +2 -2
  250. package/dist/services/sentry.js +1 -1
  251. package/dist/services/sentry.js.map +2 -2
  252. package/dist/services/sessionMemory.js +16 -3
  253. package/dist/services/sessionMemory.js.map +2 -2
  254. package/dist/services/systemReminder.js +367 -9
  255. package/dist/services/systemReminder.js.map +2 -2
  256. package/dist/services/taskStore.js +19 -0
  257. package/dist/services/taskStore.js.map +2 -2
  258. package/dist/tools/ArchitectTool/ArchitectTool.js.map +1 -1
  259. package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +1 -1
  260. package/dist/tools/BashOutputTool/BashOutputTool.js.map +1 -1
  261. package/dist/tools/BashTool/BashTool.js +28 -0
  262. package/dist/tools/BashTool/BashTool.js.map +2 -2
  263. package/dist/tools/FileEditTool/FileEditTool.js +8 -1
  264. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  265. package/dist/tools/FileReadTool/FileReadTool.js +14 -0
  266. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  267. package/dist/tools/FileWriteTool/FileWriteTool.js +10 -1
  268. package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
  269. package/dist/tools/GlobTool/GlobTool.js.map +1 -1
  270. package/dist/tools/GrepTool/GrepTool.js.map +1 -1
  271. package/dist/tools/KillShellTool/KillShellTool.js.map +1 -1
  272. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
  273. package/dist/tools/LspTool/LspTool.js +11 -2
  274. package/dist/tools/LspTool/LspTool.js.map +2 -2
  275. package/dist/tools/MCPTool/MCPTool.js.map +1 -1
  276. package/dist/tools/MemoryReadTool/MemoryReadTool.js +2 -1
  277. package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
  278. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +2 -1
  279. package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
  280. package/dist/tools/MultiEditTool/MultiEditTool.js +7 -0
  281. package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
  282. package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
  283. package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
  284. package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +1 -1
  285. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +8 -2
  286. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  287. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +2 -0
  288. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  289. package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +1 -1
  290. package/dist/tools/SlashCommandTool/SlashCommandTool.js +174 -18
  291. package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +3 -3
  292. package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +1 -1
  293. package/dist/tools/TaskGetTool/TaskGetTool.js.map +1 -1
  294. package/dist/tools/TaskListTool/TaskListTool.js.map +1 -1
  295. package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +1 -1
  296. package/dist/tools/TaskStopTool/TaskStopTool.js.map +1 -1
  297. package/dist/tools/TaskTool/TaskTool.js +84 -11
  298. package/dist/tools/TaskTool/TaskTool.js.map +2 -2
  299. package/dist/tools/TaskTool/prompt.js +12 -6
  300. package/dist/tools/TaskTool/prompt.js.map +2 -2
  301. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +1 -1
  302. package/dist/tools/ThinkTool/ThinkTool.js.map +1 -1
  303. package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +1 -1
  304. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +1 -1
  305. package/dist/tools/WebSearchTool/WebSearchTool.js.map +1 -1
  306. package/dist/tools/WebSearchTool/searchProviders.js +2 -1
  307. package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
  308. package/dist/tools/lsTool/lsTool.js.map +2 -2
  309. package/dist/tools/lsTool/prompt.js.map +1 -1
  310. package/dist/tools.js +14 -3
  311. package/dist/tools.js.map +2 -2
  312. package/dist/types/PermissionMode.js +21 -1
  313. package/dist/types/PermissionMode.js.map +2 -2
  314. package/dist/types/agentTeams.js +1 -0
  315. package/dist/types/agentTeams.js.map +7 -0
  316. package/dist/types/hooks.js +8 -2
  317. package/dist/types/hooks.js.map +2 -2
  318. package/dist/types/plugin.js +3 -5
  319. package/dist/types/plugin.js.map +2 -2
  320. package/dist/utils/agentHookExecutor.js +1 -4
  321. package/dist/utils/agentHookExecutor.js.map +2 -2
  322. package/dist/utils/agentLoader.js +91 -15
  323. package/dist/utils/agentLoader.js.map +2 -2
  324. package/dist/utils/agentMemory.js.map +2 -2
  325. package/dist/utils/animationManager.js +1 -1
  326. package/dist/utils/animationManager.js.map +2 -2
  327. package/dist/utils/ask.js +1 -1
  328. package/dist/utils/async.js +5 -1
  329. package/dist/utils/async.js.map +2 -2
  330. package/dist/utils/autoCompactCore.js +60 -0
  331. package/dist/utils/autoCompactCore.js.map +2 -2
  332. package/dist/utils/claudeCodeSync.js +439 -0
  333. package/dist/utils/claudeCodeSync.js.map +7 -0
  334. package/dist/utils/config.js +27 -151
  335. package/dist/utils/config.js.map +2 -2
  336. package/dist/utils/configSchema.js +227 -0
  337. package/dist/utils/configSchema.js.map +7 -0
  338. package/dist/utils/debugLogger.js.map +2 -2
  339. package/dist/utils/env.js +4 -3
  340. package/dist/utils/env.js.map +2 -2
  341. package/dist/utils/envConfig.js +34 -0
  342. package/dist/utils/envConfig.js.map +3 -3
  343. package/dist/utils/execFileNoThrow.js +2 -1
  344. package/dist/utils/execFileNoThrow.js.map +2 -2
  345. package/dist/utils/gpt5.js +146 -0
  346. package/dist/utils/gpt5.js.map +7 -0
  347. package/dist/utils/hookManager.js +374 -140
  348. package/dist/utils/hookManager.js.map +2 -2
  349. package/dist/utils/markdown.js +47 -0
  350. package/dist/utils/markdown.js.map +2 -2
  351. package/dist/utils/marketplaceManager.js +80 -43
  352. package/dist/utils/marketplaceManager.js.map +2 -2
  353. package/dist/utils/memoizeWithTTL.js +25 -0
  354. package/dist/utils/memoizeWithTTL.js.map +7 -0
  355. package/dist/utils/messages.js +2 -2
  356. package/dist/utils/messages.js.map +2 -2
  357. package/dist/utils/model.js +34 -9
  358. package/dist/utils/model.js.map +2 -2
  359. package/dist/utils/pluginInstaller.js +68 -29
  360. package/dist/utils/pluginInstaller.js.map +2 -2
  361. package/dist/utils/pluginLoader.js +249 -57
  362. package/dist/utils/pluginLoader.js.map +2 -2
  363. package/dist/utils/repoFetcher.js +110 -0
  364. package/dist/utils/repoFetcher.js.map +7 -0
  365. package/dist/utils/safeFetch.js +45 -0
  366. package/dist/utils/safeFetch.js.map +7 -0
  367. package/dist/utils/skillLoader.js +77 -12
  368. package/dist/utils/skillLoader.js.map +2 -2
  369. package/dist/utils/streamingState.js +52 -0
  370. package/dist/utils/streamingState.js.map +7 -0
  371. package/dist/utils/stringSubstitution.js +4 -5
  372. package/dist/utils/stringSubstitution.js.map +2 -2
  373. package/dist/utils/style.js +6 -3
  374. package/dist/utils/style.js.map +2 -2
  375. package/dist/utils/teamConfig.js +162 -16
  376. package/dist/utils/teamConfig.js.map +2 -2
  377. package/dist/utils/terminal.js +1 -1
  378. package/dist/utils/terminal.js.map +2 -2
  379. package/dist/utils/toolRiskClassification.js +0 -6
  380. package/dist/utils/toolRiskClassification.js.map +2 -2
  381. package/dist/version.js +2 -2
  382. package/dist/version.js.map +1 -1
  383. package/package.json +7 -6
package/dist/messages.js CHANGED
@@ -1,39 +1,63 @@
1
- let getMessages = () => [];
2
- let setMessages = () => {
3
- };
1
+ class MessageBus {
2
+ messagesGetter = () => [];
3
+ messagesSetter = () => {
4
+ };
5
+ modelConfigChangeHandler = null;
6
+ languageChangeHandler = null;
7
+ registerMessagesGetter(getter) {
8
+ this.messagesGetter = getter;
9
+ }
10
+ getMessagesGetter() {
11
+ return this.messagesGetter;
12
+ }
13
+ registerMessagesSetter(setter) {
14
+ this.messagesSetter = setter;
15
+ }
16
+ getMessagesSetter() {
17
+ return this.messagesSetter;
18
+ }
19
+ setModelConfigChangeHandler(handler) {
20
+ this.modelConfigChangeHandler = handler;
21
+ }
22
+ triggerModelConfigChange() {
23
+ this.modelConfigChangeHandler?.();
24
+ }
25
+ setLanguageChangeHandler(handler) {
26
+ this.languageChangeHandler = handler;
27
+ }
28
+ async triggerLanguageChange() {
29
+ await this.languageChangeHandler?.();
30
+ }
31
+ }
32
+ const messageBus = new MessageBus();
4
33
  function setMessagesGetter(getter) {
5
- getMessages = getter;
34
+ messageBus.registerMessagesGetter(getter);
6
35
  }
7
36
  function getMessagesGetter() {
8
- return getMessages;
37
+ return messageBus.getMessagesGetter();
9
38
  }
10
39
  function setMessagesSetter(setter) {
11
- setMessages = setter;
40
+ messageBus.registerMessagesSetter(setter);
12
41
  }
13
42
  function getMessagesSetter() {
14
- return setMessages;
43
+ return messageBus.getMessagesSetter();
15
44
  }
16
- let onModelConfigChange = null;
17
45
  function setModelConfigChangeHandler(handler) {
18
- onModelConfigChange = handler;
46
+ messageBus.setModelConfigChangeHandler(handler);
19
47
  }
20
48
  function triggerModelConfigChange() {
21
- if (onModelConfigChange) {
22
- onModelConfigChange();
23
- }
49
+ messageBus.triggerModelConfigChange();
24
50
  }
25
- let onLanguageChange = null;
26
51
  function setLanguageChangeHandler(handler) {
27
- onLanguageChange = handler;
52
+ messageBus.setLanguageChangeHandler(handler);
28
53
  }
29
54
  async function triggerLanguageChange() {
30
- if (onLanguageChange) {
31
- await onLanguageChange();
32
- }
55
+ await messageBus.triggerLanguageChange();
33
56
  }
34
57
  export {
35
58
  getMessagesGetter,
36
59
  getMessagesSetter,
60
+ messageBus,
37
61
  setLanguageChangeHandler,
38
62
  setMessagesGetter,
39
63
  setMessagesSetter,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/messages.ts"],
4
- "sourcesContent": ["import React from 'react'\nimport type { Message } from './query'\n\nlet getMessages: () => Message[] = () => []\nlet setMessages: React.Dispatch<React.SetStateAction<Message[]>> = () => {}\n\nexport function setMessagesGetter(getter: () => Message[]) {\n getMessages = getter\n}\n\nexport function getMessagesGetter(): () => Message[] {\n return getMessages\n}\n\nexport function setMessagesSetter(\n setter: React.Dispatch<React.SetStateAction<Message[]>>,\n) {\n setMessages = setter\n}\n\nexport function getMessagesSetter(): React.Dispatch<\n React.SetStateAction<Message[]>\n> {\n return setMessages\n}\n\n// Global UI refresh mechanism for model configuration changes\nlet onModelConfigChange: (() => void) | null = null\n\nexport function setModelConfigChangeHandler(handler: () => void) {\n onModelConfigChange = handler\n}\n\nexport function triggerModelConfigChange() {\n if (onModelConfigChange) {\n onModelConfigChange()\n }\n}\n\n// Global UI refresh mechanism for language changes\n// Similar to model config change, but preserves conversation history\nlet onLanguageChange: (() => Promise<void>) | null = null\n\nexport function setLanguageChangeHandler(handler: () => Promise<void>) {\n onLanguageChange = handler\n}\n\nexport async function triggerLanguageChange() {\n if (onLanguageChange) {\n await onLanguageChange()\n }\n}\n"],
5
- "mappings": "AAGA,IAAI,cAA+B,MAAM,CAAC;AAC1C,IAAI,cAA+D,MAAM;AAAC;AAEnE,SAAS,kBAAkB,QAAyB;AACzD,gBAAc;AAChB;AAEO,SAAS,oBAAqC;AACnD,SAAO;AACT;AAEO,SAAS,kBACd,QACA;AACA,gBAAc;AAChB;AAEO,SAAS,oBAEd;AACA,SAAO;AACT;AAGA,IAAI,sBAA2C;AAExC,SAAS,4BAA4B,SAAqB;AAC/D,wBAAsB;AACxB;AAEO,SAAS,2BAA2B;AACzC,MAAI,qBAAqB;AACvB,wBAAoB;AAAA,EACtB;AACF;AAIA,IAAI,mBAAiD;AAE9C,SAAS,yBAAyB,SAA8B;AACrE,qBAAmB;AACrB;AAEA,eAAsB,wBAAwB;AAC5C,MAAI,kBAAkB;AACpB,UAAM,iBAAiB;AAAA,EACzB;AACF;",
4
+ "sourcesContent": ["import React from 'react'\nimport type { Message } from './query'\n\n/**\n * MessageBus \u2014 encapsulates global message state and UI refresh handlers.\n *\n * Replaces loose module-level variables with a single owning object.\n * Provides getter/setter registration for React state binding,\n * plus event-style hooks for model config and language changes.\n */\nclass MessageBus {\n private messagesGetter: () => Message[] = () => []\n private messagesSetter: React.Dispatch<React.SetStateAction<Message[]>> =\n () => {}\n private modelConfigChangeHandler: (() => void) | null = null\n private languageChangeHandler: (() => Promise<void>) | null = null\n\n registerMessagesGetter(getter: () => Message[]): void {\n this.messagesGetter = getter\n }\n\n getMessagesGetter(): () => Message[] {\n return this.messagesGetter\n }\n\n registerMessagesSetter(\n setter: React.Dispatch<React.SetStateAction<Message[]>>,\n ): void {\n this.messagesSetter = setter\n }\n\n getMessagesSetter(): React.Dispatch<React.SetStateAction<Message[]>> {\n return this.messagesSetter\n }\n\n setModelConfigChangeHandler(handler: () => void): void {\n this.modelConfigChangeHandler = handler\n }\n\n triggerModelConfigChange(): void {\n this.modelConfigChangeHandler?.()\n }\n\n setLanguageChangeHandler(handler: () => Promise<void>): void {\n this.languageChangeHandler = handler\n }\n\n async triggerLanguageChange(): Promise<void> {\n await this.languageChangeHandler?.()\n }\n}\n\nexport const messageBus = new MessageBus()\n\n// Backward-compatible function exports (thin wrappers)\nexport function setMessagesGetter(getter: () => Message[]) {\n messageBus.registerMessagesGetter(getter)\n}\n\nexport function getMessagesGetter(): () => Message[] {\n return messageBus.getMessagesGetter()\n}\n\nexport function setMessagesSetter(\n setter: React.Dispatch<React.SetStateAction<Message[]>>,\n) {\n messageBus.registerMessagesSetter(setter)\n}\n\nexport function getMessagesSetter(): React.Dispatch<\n React.SetStateAction<Message[]>\n> {\n return messageBus.getMessagesSetter()\n}\n\nexport function setModelConfigChangeHandler(handler: () => void) {\n messageBus.setModelConfigChangeHandler(handler)\n}\n\nexport function triggerModelConfigChange() {\n messageBus.triggerModelConfigChange()\n}\n\nexport function setLanguageChangeHandler(handler: () => Promise<void>) {\n messageBus.setLanguageChangeHandler(handler)\n}\n\nexport async function triggerLanguageChange() {\n await messageBus.triggerLanguageChange()\n}\n"],
5
+ "mappings": "AAUA,MAAM,WAAW;AAAA,EACP,iBAAkC,MAAM,CAAC;AAAA,EACzC,iBACN,MAAM;AAAA,EAAC;AAAA,EACD,2BAAgD;AAAA,EAChD,wBAAsD;AAAA,EAE9D,uBAAuB,QAA+B;AACpD,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,oBAAqC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,uBACE,QACM;AACN,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,oBAAqE;AACnE,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,4BAA4B,SAA2B;AACrD,SAAK,2BAA2B;AAAA,EAClC;AAAA,EAEA,2BAAiC;AAC/B,SAAK,2BAA2B;AAAA,EAClC;AAAA,EAEA,yBAAyB,SAAoC;AAC3D,SAAK,wBAAwB;AAAA,EAC/B;AAAA,EAEA,MAAM,wBAAuC;AAC3C,UAAM,KAAK,wBAAwB;AAAA,EACrC;AACF;AAEO,MAAM,aAAa,IAAI,WAAW;AAGlC,SAAS,kBAAkB,QAAyB;AACzD,aAAW,uBAAuB,MAAM;AAC1C;AAEO,SAAS,oBAAqC;AACnD,SAAO,WAAW,kBAAkB;AACtC;AAEO,SAAS,kBACd,QACA;AACA,aAAW,uBAAuB,MAAM;AAC1C;AAEO,SAAS,oBAEd;AACA,SAAO,WAAW,kBAAkB;AACtC;AAEO,SAAS,4BAA4B,SAAqB;AAC/D,aAAW,4BAA4B,OAAO;AAChD;AAEO,SAAS,2BAA2B;AACzC,aAAW,yBAAyB;AACtC;AAEO,SAAS,yBAAyB,SAA8B;AACrE,aAAW,yBAAyB,OAAO;AAC7C;AAEA,eAAsB,wBAAwB;AAC5C,QAAM,WAAW,sBAAsB;AACzC;",
6
6
  "names": []
7
7
  }
@@ -15,7 +15,11 @@ import { PRODUCT_NAME } from "./constants/product.js";
15
15
  import {
16
16
  getToolRiskLevel
17
17
  } from "./utils/toolRiskClassification.js";
18
- import { resolve, relative, isAbsolute } from "path";
18
+ import { resolve, relative, isAbsolute, join } from "path";
19
+ import { getHookManager } from "./utils/hookManager.js";
20
+ import { existsSync, readFileSync } from "fs";
21
+ import { homedir } from "os";
22
+ import { CONFIG_BASE_DIR } from "./constants/product.js";
19
23
  const SAFE_COMMANDS = /* @__PURE__ */ new Set([
20
24
  "git status",
21
25
  "git diff",
@@ -241,7 +245,70 @@ function shouldAllowByRiskLevel(safetyMode, riskLevel, toolName, input) {
241
245
  return false;
242
246
  }
243
247
  }
248
+ let settingsPermissionsCache = null;
249
+ function loadSettingsPermissions() {
250
+ if (settingsPermissionsCache) return settingsPermissionsCache;
251
+ const deny = [];
252
+ const allow = [];
253
+ const cwd = getCwd();
254
+ const home = homedir();
255
+ const settingsFiles = [
256
+ join(home, ".claude", "settings.json"),
257
+ join(home, CONFIG_BASE_DIR, "settings.json"),
258
+ join(cwd, ".claude", "settings.json"),
259
+ join(cwd, CONFIG_BASE_DIR, "settings.json")
260
+ ];
261
+ for (const file of settingsFiles) {
262
+ if (!existsSync(file)) continue;
263
+ try {
264
+ const content = JSON.parse(readFileSync(file, "utf-8"));
265
+ if (content?.permissions?.deny && Array.isArray(content.permissions.deny)) {
266
+ deny.push(...content.permissions.deny);
267
+ }
268
+ if (content?.permissions?.allow && Array.isArray(content.permissions.allow)) {
269
+ allow.push(...content.permissions.allow);
270
+ }
271
+ } catch {
272
+ }
273
+ }
274
+ settingsPermissionsCache = { deny, allow };
275
+ return settingsPermissionsCache;
276
+ }
277
+ function matchesPermissionPattern(toolName, input, patterns) {
278
+ for (const pattern of patterns) {
279
+ if (pattern === toolName) return true;
280
+ if (toolName === "Bash" && pattern.startsWith("Bash(") && input?.command) {
281
+ const cmdPattern = pattern.slice(5, -1);
282
+ const command = String(input.command);
283
+ if (cmdPattern.endsWith(":*")) {
284
+ const prefix = cmdPattern.slice(0, -2);
285
+ if (command.startsWith(prefix)) return true;
286
+ } else if (command === cmdPattern) {
287
+ return true;
288
+ }
289
+ }
290
+ }
291
+ return false;
292
+ }
244
293
  const hasPermissionsToUseTool = async (tool, input, context, _assistantMessage) => {
294
+ const settingsPerms = loadSettingsPermissions();
295
+ if (matchesPermissionPattern(
296
+ tool.name,
297
+ input,
298
+ settingsPerms.deny
299
+ )) {
300
+ return {
301
+ result: false,
302
+ message: `Tool "${tool.name}" is denied by settings configuration.`
303
+ };
304
+ }
305
+ if (matchesPermissionPattern(
306
+ tool.name,
307
+ input,
308
+ settingsPerms.allow
309
+ )) {
310
+ return { result: true };
311
+ }
245
312
  const safetyMode = getEffectiveSafetyMode(context.options);
246
313
  const riskLevel = getToolRiskLevel(
247
314
  tool.name,
@@ -295,6 +362,13 @@ const hasPermissionsToUseTool = async (tool, input, context, _assistantMessage)
295
362
  if (allowedTools.includes(permissionKey)) {
296
363
  return { result: true };
297
364
  }
365
+ const hookDecision = await firePermissionRequestHook(
366
+ tool.name,
367
+ input
368
+ );
369
+ if (hookDecision === "approve") {
370
+ return { result: true };
371
+ }
298
372
  return {
299
373
  result: false,
300
374
  message: `${PRODUCT_NAME} requested permissions to use ${tool.name}, but you haven't granted it yet.`
@@ -302,6 +376,25 @@ const hasPermissionsToUseTool = async (tool, input, context, _assistantMessage)
302
376
  }
303
377
  }
304
378
  };
379
+ async function firePermissionRequestHook(toolName, toolInput) {
380
+ try {
381
+ const hookMgr = getHookManager();
382
+ if (!hookMgr) return "ask";
383
+ const result = await hookMgr.executePermissionRequest(
384
+ toolName,
385
+ toolInput,
386
+ "other"
387
+ );
388
+ if (!result.shouldContinue && !result.shouldAskUser) {
389
+ return "block";
390
+ }
391
+ if (result.shouldContinue && !result.shouldAskUser) {
392
+ if (result.reason) return "approve";
393
+ }
394
+ } catch {
395
+ }
396
+ return "ask";
397
+ }
305
398
  async function savePermission(tool, input, prefix) {
306
399
  const key = getPermissionKey(tool, input, prefix);
307
400
  if (tool === FileEditTool || tool === FileWriteTool || tool === NotebookEditTool) {
@@ -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 } from 'path'\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\nexport const hasPermissionsToUseTool: CanUseToolFn = async (\n tool,\n input,\n context,\n _assistantMessage,\n): Promise<PermissionResult> => {\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 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\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": "AAEA,SAAS,UAAU,mBAAmB;AACtC,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,wBAAwB;AACjC,SAAS,4BAA4B,oBAAoB;AACzD;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,0CAA0C;AACnD,SAAS,cAAc;AACvB,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,OAEK;AACP,SAAS,SAAS,UAAU,kBAAkB;AAG9C,MAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAM,yCAAyC,CACpD,MACA,SACA,iBACY;AACZ,MAAI,cAAc,IAAI,OAAO,GAAG;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI,aAAa,SAAS,iBAAiB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,MAAI,aAAa,SAAS,iBAAiB,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,MAAM,+BAA+B,CAC1C,MACA,SACA,QACA,iBACY;AAEZ,MAAI,uCAAuC,MAAM,SAAS,YAAY,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO,aAAa,SAAS,iBAAiB,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;AAC1E;AAEO,MAAM,wBAAwB,OACnC,MACA,SACA,SACA,cACA,+BAA+B,+BACD;AAC9B,MAAI,uCAAuC,MAAM,SAAS,YAAY,GAAG;AAEvE,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAEA,QAAM,cAAc,aAAa,OAAO,EAAE,OAAO,OAAK;AAEpD,QAAI,MAAM,MAAM,OAAO,CAAC,IAAI;AAC1B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AACD,QAAM,0BAA0B,MAAM;AAAA,IACpC;AAAA,IACA,QAAQ,gBAAgB;AAAA,EAC1B;AACA,MAAI,QAAQ,gBAAgB,OAAO,SAAS;AAC1C,UAAM,IAAI,WAAW;AAAA,EACvB;AAEA,MAAI,4BAA4B,MAAM;AAGpC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,SAAS,GAAG,YAAY,iCAAiC,KAAK,IAAI;AAAA,IACpE;AAAA,EACF;AAEA,MAAI,wBAAwB,0BAA0B;AAEpD,QAAI,uCAAuC,MAAM,SAAS,YAAY,GAAG;AACvE,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB,OAAO;AACL,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS,GAAG,YAAY,iCAAiC,KAAK,IAAI;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAKA,QAAM,gBACJ,mBAAmB,0BACf,wBAAwB,gBACxB;AAGN,MAAI,YAAY,SAAS,GAAG;AAC1B,QACE,6BAA6B,MAAM,SAAS,eAAe,YAAY,GACvE;AACA,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB,OAAO;AACL,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS,GAAG,YAAY,iCAAiC,KAAK,IAAI;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AACA,MACE,YAAY,MAAM,gBAAc;AAC9B,UAAM,eACJ,wBAAwB,mBAAmB,IAAI,UAAU;AAC3D,QAAI,iBAAiB,UAAa,aAAa,0BAA0B;AAEvE,aAAO;AAAA,IACT;AAGA,UAAM,mBACJ,mBAAmB,eAAe,aAAa,gBAAgB;AACjE,UAAM,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC,GACD;AACA,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AACA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS,GAAG,YAAY,iCAAiC,KAAK,IAAI;AAAA,EACpE;AACF;AAQA,SAAS,uBAAuB,SAGjB;AAEb,MAAI,QAAQ,YAAY;AACtB,WAAO,QAAQ;AAAA,EACjB;AAIA,MAAI,QAAQ,aAAa,MAAM;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMA,SAAS,oBAAoB,YAAoB,YAA6B;AAE5E,QAAM,eAAe,WAAW,UAAU,IACtC,QAAQ,UAAU,IAClB,QAAQ,YAAY,UAAU;AAGlC,QAAM,eAAe,SAAS,YAAY,YAAY;AAKtD,SAAO,CAAC,aAAa,WAAW,IAAI,KAAK,CAAC,WAAW,YAAY;AACnE;AAMA,MAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKA,SAAS,qBAAqB,YAA6B;AACzD,QAAM,iBAAiB,QAAQ,UAAU,EAAE,YAAY;AACvD,SAAO,sBAAsB;AAAA,IAAK,kBAChC,eAAe,WAAW,aAAa,YAAY,CAAC;AAAA,EACtD;AACF;AAKA,SAAS,0BACP,UACA,OACU;AACV,QAAM,QAAkB,CAAC;AAGzB,MAAI,aAAa,UAAU,aAAa,WAAW,aAAa,QAAQ;AACtE,QAAI,OAAO,MAAM,cAAc,UAAU;AACvC,YAAM,KAAK,MAAM,SAAS;AAAA,IAC5B;AAAA,EACF;AAGA,MAAI,aAAa,UAAU,aAAa,QAAQ;AAC9C,QAAI,OAAO,MAAM,SAAS,UAAU;AAClC,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB;AAAA,EACF;AAGA,MAAI,aAAa,MAAM;AACrB,QAAI,OAAO,MAAM,SAAS,UAAU;AAClC,YAAM,KAAK,MAAM,IAAI;AAAA,IACvB;AAAA,EACF;AAGA,MAAI,aAAa,gBAAgB;AAC/B,QAAI,OAAO,MAAM,kBAAkB,UAAU;AAC3C,YAAM,KAAK,MAAM,aAAa;AAAA,IAChC;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,4BAA4B,SAA2B;AAC9D,QAAM,QAAkB,CAAC;AAGzB,QAAM,gBAAgB,QAAQ,SAAS,mBAAmB;AAC1D,aAAW,SAAS,eAAe;AACjC,QAAI,MAAM,CAAC,MAAM,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI;AACpE,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB;AAAA,EACF;AAGA,QAAM,kBAAkB,QAAQ;AAAA,IAC9B;AAAA,EACF;AACA,aAAW,SAAS,iBAAiB;AACnC,QAAI,MAAM,CAAC,GAAG;AACZ,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB;AAAA,EACF;AAGA,QAAM,kBAAkB,QAAQ,SAAS,8BAA8B;AACvE,aAAW,SAAS,iBAAiB;AACnC,QAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,GAAG;AACzC,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAC3B;AAMA,SAAS,yBACP,UACA,OACA,YACoD;AACpD,MAAI,QAAkB,CAAC;AAGvB,MAAI,aAAa,UAAU,OAAO,MAAM,YAAY,UAAU;AAC5D,YAAQ,4BAA4B,MAAM,OAAO;AAAA,EACnD,OAAO;AACL,YAAQ,0BAA0B,UAAU,KAAK;AAAA,EACnD;AAGA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,EAAE,eAAe,MAAM,cAAc,CAAC,EAAE;AAAA,EACjD;AAEA,QAAM,eAAyB,CAAC;AAChC,aAAW,QAAQ,OAAO;AAExB,QAAI,qBAAqB,IAAI,GAAG;AAC9B,mBAAa,KAAK,IAAI;AACtB;AAAA,IACF;AAGA,QAAI,CAAC,oBAAoB,MAAM,UAAU,GAAG;AAC1C,mBAAa,KAAK,IAAI;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe,aAAa,WAAW;AAAA,IACvC;AAAA,EACF;AACF;AAaA,SAAS,uBACP,YACA,WACA,UACA,OACS;AACT,UAAQ,YAAY;AAAA,IAClB,KAAK;AAEH,aAAO;AAAA,IACT,KAAK;AAEH,aAAO,cAAc,UAAU,cAAc;AAAA,IAC/C,KAAK;AAEH,aAAO,cAAc;AAAA,IACvB,KAAK;AAGH,UAAI,cAAc,QAAQ;AACxB,eAAO;AAAA,MACT;AAEA,UAAI,YAAY,OAAO;AACrB,cAAM,aAAa,OAAO;AAC1B,cAAM,EAAE,cAAc,IAAI;AAAA,UACxB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,EACX;AACF;AAEO,MAAM,0BAAwC,OACnD,MACA,OACA,SACA,sBAC8B;AAC9B,QAAM,aAAa,uBAAuB,QAAQ,OAAO;AAGzD,QAAM,YAAY;AAAA,IAChB,KAAK;AAAA,IACL;AAAA,EACF;AAIA,MACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL;AAAA,EACF,GACA;AACA,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAEA,MAAI,QAAQ,gBAAgB,OAAO,SAAS;AAC1C,UAAM,IAAI,WAAW;AAAA,EACvB;AAGA,MAAI;AACF,QAAI,CAAC,KAAK,iBAAiB,KAAc,GAAG;AAC1C,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB;AAAA,EACF,SAAS,GAAG;AACV,aAAS,+BAA+B,CAAC,EAAE;AAC3C,WAAO,EAAE,QAAQ,OAAO,SAAS,6BAA6B;AAAA,EAChE;AAEA,QAAM,gBAAgB,wBAAwB;AAC9C,QAAM,eAAe,cAAc,gBAAgB,CAAC;AAEpD,MAAI,SAAS,YAAY,aAAa,SAAS,SAAS,IAAI,GAAG;AAC7D,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAGA,UAAQ,MAAM;AAAA;AAAA,IAEZ,KAAK,UAAU;AAGb,YAAM,EAAE,QAAQ,IAAI,YAAY,MAAM,KAAK;AAC3C,aAAO,MAAM,sBAAsB,MAAM,SAAS,SAAS,YAAY;AAAA,IACzE;AAAA;AAAA,IAEA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,kBAAkB;AAGrB,UAAI,CAAC,KAAK,iBAAiB,KAAK,GAAG;AACjC,eAAO,EAAE,QAAQ,KAAK;AAAA,MACxB;AACA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS,GAAG,YAAY,iCAAiC,KAAK,IAAI;AAAA,MACpE;AAAA,IACF;AAAA;AAAA,IAEA,SAAS;AACP,YAAM,gBAAgB,iBAAiB,MAAM,OAAO,IAAI;AACxD,UAAI,aAAa,SAAS,aAAa,GAAG;AACxC,eAAO,EAAE,QAAQ,KAAK;AAAA,MACxB;AAEA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS,GAAG,YAAY,iCAAiC,KAAK,IAAI;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAsB,eACpB,MACA,OACA,QACe;AACf,QAAM,MAAM,iBAAiB,MAAM,OAAO,MAAM;AAGhD,MACE,SAAS,gBACT,SAAS,iBACT,SAAS,kBACT;AACA,uCAAmC;AACnC;AAAA,EACF;AAGA,QAAM,gBAAgB,wBAAwB;AAC9C,MAAI,cAAc,aAAa,SAAS,GAAG,GAAG;AAC5C;AAAA,EACF;AAEA,gBAAc,aAAa,KAAK,GAAG;AACnC,gBAAc,aAAa,KAAK;AAEhC,2BAAyB,aAAa;AACxC;AAEA,SAAS,iBACP,MACA,OACA,QACQ;AACR,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,UAAI,QAAQ;AACV,eAAO,GAAG,SAAS,IAAI,IAAI,MAAM;AAAA,MACnC;AACA,aAAO,GAAG,SAAS,IAAI,IAAI,SAAS,qBAAqB,KAAc,CAAC;AAAA,IAC1E;AACE,aAAO,KAAK;AAAA,EAChB;AACF;",
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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",
6
6
  "names": []
7
7
  }
package/dist/query.js CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  normalizeMessagesForAPI
32
32
  } from "./utils/messages.js";
33
33
  import { withTimeout, ToolTimeoutError } from "./utils/toolTimeout.js";
34
- import { setStreamingState, resetStreamingState } from "./components/Spinner.js";
34
+ import { setStreamingState, resetStreamingState } from "./utils/streamingState.js";
35
35
  import { BashTool } from "./tools/BashTool/BashTool.js";
36
36
  function normalizeToolResultContent(content) {
37
37
  if (content === null || content === void 0) {
@@ -122,24 +122,8 @@ async function* query(messages, systemPrompt, context, canUseTool, toolUseContex
122
122
  messages: messages.length,
123
123
  timestamp: Date.now()
124
124
  });
125
- if (reminders && messages.length > 0) {
126
- for (let i = messages.length - 1; i >= 0; i--) {
127
- const msg = messages[i];
128
- if (msg?.type === "user") {
129
- const lastUserMessage = msg;
130
- messages[i] = {
131
- ...lastUserMessage,
132
- message: {
133
- ...lastUserMessage.message,
134
- content: typeof lastUserMessage.message.content === "string" ? reminders + lastUserMessage.message.content : [
135
- ...Array.isArray(lastUserMessage.message.content) ? lastUserMessage.message.content : [],
136
- { type: "text", text: reminders }
137
- ]
138
- }
139
- };
140
- break;
141
- }
142
- }
125
+ if (reminders) {
126
+ fullSystemPrompt.push(reminders);
143
127
  }
144
128
  markPhase("LLM_PREPARATION");
145
129
  setStreamingState({ phase: "waiting" });
@@ -180,6 +164,11 @@ async function* query(messages, systemPrompt, context, canUseTool, toolUseContex
180
164
  );
181
165
  if (!toolUseMessages.length) {
182
166
  resetStreamingState();
167
+ const hookManager = getHookManager();
168
+ if (hookManager) {
169
+ hookManager.executeStop().catch(() => {
170
+ });
171
+ }
183
172
  return;
184
173
  }
185
174
  const toolResults = [];
@@ -437,6 +426,15 @@ async function* runToolUse(toolUse, siblingToolUseIDs, assistantMessage, canUseT
437
426
  }
438
427
  } catch (e) {
439
428
  logError(e);
429
+ const hookManager = getHookManager();
430
+ if (hookManager) {
431
+ hookManager.executePostToolUseFailure(
432
+ toolName,
433
+ toolInput,
434
+ e instanceof Error ? e.message : String(e)
435
+ ).catch(() => {
436
+ });
437
+ }
440
438
  const errorMessage = createUserMessage([
441
439
  {
442
440
  type: "tool_result",
@@ -684,6 +682,16 @@ async function* checkPermissionsAndCallTool(tool, toolUseID, siblingToolUseIDs,
684
682
  recordToolCall(tool.name, true);
685
683
  } catch {
686
684
  }
685
+ const hookMgr = getHookManager();
686
+ if (hookMgr) {
687
+ hookMgr.executePostToolUseFailure(
688
+ tool.name,
689
+ normalizedInput,
690
+ error instanceof Error ? error.message : String(error),
691
+ error instanceof ToolTimeoutError ? "timeout" : void 0
692
+ ).catch(() => {
693
+ });
694
+ }
687
695
  if (error instanceof ToolTimeoutError) {
688
696
  debug.error("TOOL_TIMEOUT", {
689
697
  toolName: tool.name,