@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
@@ -306,20 +306,28 @@ ${validation.violations.map((v) => `- ${v.details}`).join("\n")}`,
306
306
  };
307
307
  }
308
308
  }
309
+ /**
310
+ * Escape a path for use in seatbelt profile strings.
311
+ * Prevents injection via backslashes or double quotes in directory names.
312
+ */
313
+ escapeSbplPath(path) {
314
+ return path.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
315
+ }
309
316
  /**
310
317
  * Generate macOS seatbelt profile
311
318
  */
312
319
  generateSeatbeltProfile() {
313
320
  const writeAllowed = this.config.filesystem.writeAllowed.map((p) => {
314
- if (p === "./") return `(subpath "${this.workingDir}")`;
321
+ if (p === "./")
322
+ return `(subpath "${this.escapeSbplPath(this.workingDir)}")`;
315
323
  if (p === "*") return '(subpath "/")';
316
324
  const absPath = resolve(this.workingDir, p);
317
- return `(subpath "${absPath}")`;
325
+ return `(subpath "${this.escapeSbplPath(absPath)}")`;
318
326
  }).join("\n ");
319
327
  const readAllowed = this.config.filesystem.readAllowed.map((p) => {
320
328
  if (p === "*") return '(subpath "/")';
321
329
  const absPath = resolve(this.workingDir, p);
322
- return `(subpath "${absPath}")`;
330
+ return `(subpath "${this.escapeSbplPath(absPath)}")`;
323
331
  }).join("\n ");
324
332
  const networkRules = this.config.network.blockAll ? "(deny network*)" : this.config.network.allowedDomains.length > 0 ? `(allow network-outbound
325
333
  (remote tcp "${this.config.network.allowedDomains.join('", "')}"))` : "(allow network-outbound)";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/services/sandbox/sandboxController.ts"],
4
- "sourcesContent": ["/**\n * Sandbox Controller\n *\n * Main controller for the sandbox execution system.\n * Coordinates filesystem, network, and process isolation.\n */\n\nimport { spawn, type ChildProcess } from 'child_process'\nimport { platform } from 'os'\nimport { existsSync } from 'fs'\nimport { resolve } from 'path'\nimport type {\n ISandboxController,\n SandboxConfig,\n SandboxExecutionResult,\n SandboxImplementation,\n SandboxViolation,\n} from './types'\nimport { DEFAULT_SANDBOX_CONFIG } from './types'\nimport { FilesystemBoundary } from './filesystemBoundary'\nimport { NetworkProxy } from './networkProxy'\n\n/**\n * Sandbox Controller Implementation\n *\n * Provides unified sandbox management with OS-specific implementations.\n */\nexport class SandboxController implements ISandboxController {\n private config: SandboxConfig\n private implementation: SandboxImplementation\n private filesystemBoundary: FilesystemBoundary\n private networkProxy: NetworkProxy\n private violations: SandboxViolation[] = []\n private workingDir: string\n\n constructor(workingDir: string, config?: Partial<SandboxConfig>) {\n this.workingDir = resolve(workingDir)\n this.config = { ...DEFAULT_SANDBOX_CONFIG, ...config }\n this.implementation = this.detectImplementation()\n this.filesystemBoundary = new FilesystemBoundary(\n this.config.filesystem,\n this.workingDir,\n )\n this.networkProxy = new NetworkProxy(this.config.network)\n }\n\n /**\n * Check if sandbox is available on this system\n */\n async isAvailable(): Promise<boolean> {\n if (!this.config.enabled) {\n return false\n }\n\n switch (this.implementation) {\n case 'seatbelt':\n return this.isSeatbeltAvailable()\n case 'bubblewrap':\n return this.isBubblewrapAvailable()\n case 'docker':\n return this.isDockerAvailable()\n default:\n return false\n }\n }\n\n /**\n * Get the implementation type\n */\n getImplementationType(): SandboxImplementation {\n return this.implementation\n }\n\n /**\n * Initialize the sandbox\n */\n async initialize(config: SandboxConfig): Promise<void> {\n this.config = config\n this.filesystemBoundary = new FilesystemBoundary(\n config.filesystem,\n this.workingDir,\n )\n this.networkProxy = new NetworkProxy(config.network)\n this.violations = []\n }\n\n /**\n * Pre-validate a command against policies\n */\n async validateCommand(command: string): Promise<{\n valid: boolean\n violations: SandboxViolation[]\n }> {\n const violations: SandboxViolation[] = []\n\n // Check if command is excluded from sandboxing\n if (this.isExcludedCommand(command)) {\n return { valid: true, violations: [] }\n }\n\n // Validate filesystem access\n const fsResult = this.filesystemBoundary.analyzeCommand(command)\n for (const violation of fsResult.violations) {\n violation.command = command\n violations.push(violation)\n }\n\n // Validate network access\n const netResult = this.networkProxy.analyzeCommand(command)\n for (const violation of netResult.violations) {\n violation.command = command\n violations.push(violation)\n }\n\n // Store all violations\n this.violations.push(...violations)\n\n return {\n valid: violations.length === 0,\n violations,\n }\n }\n\n /**\n * Execute a command in the sandbox\n */\n async execute(\n command: string,\n workingDir: string,\n signal?: AbortSignal,\n timeout?: number,\n ): Promise<SandboxExecutionResult> {\n const startTime = Date.now()\n this.workingDir = resolve(workingDir)\n this.filesystemBoundary.setWorkingDir(this.workingDir)\n\n // If sandbox is disabled, execute directly\n if (!this.config.enabled) {\n return this.executeDirectly(command, signal, timeout)\n }\n\n // Validate command first\n const validation = await this.validateCommand(command)\n if (!validation.valid) {\n return {\n stdout: '',\n stderr: `Sandbox blocked command:\\n${validation.violations\n .map(v => `- ${v.details}`)\n .join('\\n')}`,\n exitCode: 1,\n interrupted: false,\n blocked: true,\n blockReason: validation.violations[0]?.details,\n duration: Date.now() - startTime,\n }\n }\n\n // Check if command is excluded from sandboxing\n if (this.isExcludedCommand(command)) {\n return this.executeDirectly(command, signal, timeout)\n }\n\n // Execute with appropriate sandbox\n switch (this.implementation) {\n case 'seatbelt':\n return this.executeWithSeatbelt(command, signal, timeout, startTime)\n case 'bubblewrap':\n return this.executeWithBubblewrap(command, signal, timeout, startTime)\n case 'docker':\n return this.executeWithDocker(command, signal, timeout, startTime)\n default:\n // No sandbox available, execute directly with validation only\n return this.executeDirectly(command, signal, timeout)\n }\n }\n\n /**\n * Get current configuration\n */\n getConfig(): SandboxConfig {\n return { ...this.config }\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<SandboxConfig>): void {\n this.config = { ...this.config, ...config }\n if (config.filesystem) {\n this.filesystemBoundary.updatePolicy(config.filesystem)\n }\n if (config.network) {\n this.networkProxy.updatePolicy(config.network)\n }\n }\n\n /**\n * Get violation history\n */\n getViolations(): SandboxViolation[] {\n return [\n ...this.violations,\n ...this.filesystemBoundary.getViolations(),\n ...this.networkProxy.getViolations(),\n ]\n }\n\n /**\n * Clear violation history\n */\n clearViolations(): void {\n this.violations = []\n this.filesystemBoundary.clearViolations()\n this.networkProxy.clearViolations()\n }\n\n /**\n * Get filesystem boundary instance\n */\n getFilesystemBoundary(): FilesystemBoundary {\n return this.filesystemBoundary\n }\n\n /**\n * Get network proxy instance\n */\n getNetworkProxy(): NetworkProxy {\n return this.networkProxy\n }\n\n /**\n * Detect the best available sandbox implementation\n */\n private detectImplementation(): SandboxImplementation {\n const os = platform()\n\n if (os === 'darwin') {\n // macOS - use seatbelt/sandbox-exec\n return 'seatbelt'\n } else if (os === 'linux') {\n // Linux - prefer bubblewrap, fallback to docker\n if (this.hasBubblewrap()) {\n return 'bubblewrap'\n } else if (this.hasDocker()) {\n return 'docker'\n }\n }\n\n return 'none'\n }\n\n /**\n * Check if bubblewrap is installed\n */\n private hasBubblewrap(): boolean {\n return existsSync('/usr/bin/bwrap') || existsSync('/usr/local/bin/bwrap')\n }\n\n /**\n * Check if docker is available\n */\n private hasDocker(): boolean {\n return existsSync('/usr/bin/docker') || existsSync('/usr/local/bin/docker')\n }\n\n /**\n * Check if seatbelt (macOS sandbox-exec) is available\n */\n private async isSeatbeltAvailable(): Promise<boolean> {\n return platform() === 'darwin' && existsSync('/usr/bin/sandbox-exec')\n }\n\n /**\n * Check if bubblewrap is available and working\n */\n private async isBubblewrapAvailable(): Promise<boolean> {\n if (!this.hasBubblewrap()) return false\n try {\n const result = await this.spawnAsync('bwrap', ['--version'])\n return result.exitCode === 0\n } catch {\n return false\n }\n }\n\n /**\n * Check if docker is available and running\n */\n private async isDockerAvailable(): Promise<boolean> {\n if (!this.hasDocker()) return false\n try {\n const result = await this.spawnAsync('docker', ['info'])\n return result.exitCode === 0\n } catch {\n return false\n }\n }\n\n /**\n * Check if a command is excluded from sandboxing\n */\n private isExcludedCommand(command: string): boolean {\n const firstWord = command.trim().split(/\\s+/)[0]?.toLowerCase()\n if (!firstWord) return false\n return this.config.process.excludedCommands.some(\n excluded => firstWord === excluded.toLowerCase(),\n )\n }\n\n /**\n * Execute command directly without sandboxing\n */\n private async executeDirectly(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n ): Promise<SandboxExecutionResult> {\n const startTime = Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n try {\n const result = await this.spawnAsync('sh', ['-c', command], {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n })\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - startTime,\n }\n } catch (error) {\n const err = error as Error\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: false,\n duration: Date.now() - startTime,\n }\n }\n }\n\n /**\n * Execute command with macOS seatbelt sandbox\n */\n private async executeWithSeatbelt(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n startTime?: number,\n ): Promise<SandboxExecutionResult> {\n const start = startTime || Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n // Generate seatbelt profile\n const profile = this.generateSeatbeltProfile()\n\n try {\n const result = await this.spawnAsync(\n 'sandbox-exec',\n ['-p', profile, 'sh', '-c', command],\n {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n },\n )\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - start,\n }\n } catch (error) {\n const err = error as Error\n const isBlocked =\n err.message.includes('sandbox') || err.message.includes('denied')\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: isBlocked,\n blockReason: isBlocked ? 'Sandbox policy violation' : undefined,\n duration: Date.now() - start,\n }\n }\n }\n\n /**\n * Generate macOS seatbelt profile\n */\n private generateSeatbeltProfile(): string {\n const writeAllowed = this.config.filesystem.writeAllowed\n .map(p => {\n if (p === './') return `(subpath \"${this.workingDir}\")`\n if (p === '*') return '(subpath \"/\")'\n const absPath = resolve(this.workingDir, p)\n return `(subpath \"${absPath}\")`\n })\n .join('\\n ')\n\n const readAllowed = this.config.filesystem.readAllowed\n .map(p => {\n if (p === '*') return '(subpath \"/\")'\n const absPath = resolve(this.workingDir, p)\n return `(subpath \"${absPath}\")`\n })\n .join('\\n ')\n\n const networkRules = this.config.network.blockAll\n ? '(deny network*)'\n : this.config.network.allowedDomains.length > 0\n ? `(allow network-outbound\n (remote tcp \"${this.config.network.allowedDomains.join('\", \"')}\"))`\n : '(allow network-outbound)'\n\n return `\n(version 1)\n(deny default)\n\n; Allow basic system operations\n(allow process-exec*)\n(allow process-fork)\n(allow file-read-metadata)\n(allow sysctl-read)\n\n; Allow reading system libraries and executables\n(allow file-read*\n (subpath \"/usr\")\n (subpath \"/bin\")\n (subpath \"/sbin\")\n (subpath \"/System\")\n (subpath \"/Library\")\n (subpath \"/private/var\")\n (subpath \"/private/tmp\")\n (subpath \"/dev\")\n (subpath \"/tmp\")\n ${readAllowed}\n)\n\n; Allow writing to specific paths\n(allow file-write*\n (subpath \"/dev\")\n (subpath \"/private/tmp\")\n (subpath \"/tmp\")\n ${writeAllowed}\n)\n\n; Network rules\n${networkRules}\n\n; Allow stdout/stderr\n(allow file-write-data\n (literal \"/dev/null\")\n (literal \"/dev/zero\")\n (literal \"/dev/random\")\n (literal \"/dev/urandom\")\n (literal \"/dev/tty\")\n (literal \"/dev/console\")\n)\n\n; Allow process management\n(allow signal)\n(allow mach-lookup)\n(allow ipc-posix-shm-read-data)\n(allow ipc-posix-shm-write-data)\n`\n }\n\n /**\n * Execute command with Linux bubblewrap sandbox\n */\n private async executeWithBubblewrap(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n startTime?: number,\n ): Promise<SandboxExecutionResult> {\n const start = startTime || Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n // Build bubblewrap arguments\n const bwrapArgs = this.buildBubblewrapArgs()\n\n try {\n const result = await this.spawnAsync(\n 'bwrap',\n [...bwrapArgs, 'sh', '-c', command],\n {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n },\n )\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - start,\n }\n } catch (error) {\n const err = error as Error\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: false,\n duration: Date.now() - start,\n }\n }\n }\n\n /**\n * Build bubblewrap command arguments\n */\n private buildBubblewrapArgs(): string[] {\n const args: string[] = []\n\n // Basic sandboxing\n args.push('--unshare-all')\n args.push('--die-with-parent')\n\n // Mount system directories read-only\n args.push('--ro-bind', '/usr', '/usr')\n args.push('--ro-bind', '/bin', '/bin')\n args.push('--ro-bind', '/lib', '/lib')\n if (existsSync('/lib64')) {\n args.push('--ro-bind', '/lib64', '/lib64')\n }\n args.push('--ro-bind', '/etc', '/etc')\n\n // Allow /tmp\n args.push('--tmpfs', '/tmp')\n\n // Set working directory with read-write access\n args.push('--bind', this.workingDir, this.workingDir)\n args.push('--chdir', this.workingDir)\n\n // Add additional read paths\n for (const path of this.config.filesystem.readAllowed) {\n if (path !== '*' && path !== './' && existsSync(path)) {\n const absPath = resolve(this.workingDir, path)\n if (existsSync(absPath)) {\n args.push('--ro-bind', absPath, absPath)\n }\n }\n }\n\n // Add additional write paths\n for (const path of this.config.filesystem.writeAllowed) {\n if (path !== './' && path !== '*') {\n const absPath = resolve(this.workingDir, path)\n if (existsSync(absPath)) {\n args.push('--bind', absPath, absPath)\n }\n }\n }\n\n // Network isolation (if blocking all)\n if (this.config.network.blockAll) {\n args.push('--unshare-net')\n }\n\n // Process limits\n if (this.config.process.maxProcesses > 0) {\n args.push(\n '--setenv',\n 'MINTO_MAX_PROCS',\n String(this.config.process.maxProcesses),\n )\n }\n\n return args\n }\n\n /**\n * Execute command with Docker sandbox\n */\n private async executeWithDocker(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n startTime?: number,\n ): Promise<SandboxExecutionResult> {\n const start = startTime || Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n // Build docker run arguments\n const dockerArgs = [\n 'run',\n '--rm',\n '-i',\n '--network',\n this.config.network.blockAll ? 'none' : 'bridge',\n '-v',\n `${this.workingDir}:/workspace`,\n '-w',\n '/workspace',\n ]\n\n // Add memory limit\n if (this.config.process.maxMemory > 0) {\n dockerArgs.push('--memory', `${this.config.process.maxMemory}`)\n }\n\n // Use a minimal image\n dockerArgs.push('alpine:latest')\n dockerArgs.push('sh', '-c', command)\n\n try {\n const result = await this.spawnAsync('docker', dockerArgs, {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n })\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - start,\n }\n } catch (error) {\n const err = error as Error\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: false,\n duration: Date.now() - start,\n }\n }\n }\n\n /**\n * Spawn a process with promise wrapper\n */\n private spawnAsync(\n cmd: string,\n args: string[],\n options?: {\n cwd?: string\n signal?: AbortSignal\n timeout?: number\n },\n ): Promise<{\n stdout: string\n stderr: string\n exitCode: number\n interrupted: boolean\n }> {\n return new Promise((resolve, reject) => {\n let stdout = ''\n let stderr = ''\n let interrupted = false\n let child: ChildProcess | null = null\n\n const timeoutId = options?.timeout\n ? setTimeout(() => {\n interrupted = true\n child?.kill('SIGTERM')\n }, options.timeout)\n : null\n\n // Handle abort signal\n if (options?.signal) {\n options.signal.addEventListener('abort', () => {\n interrupted = true\n child?.kill('SIGTERM')\n })\n }\n\n child = spawn(cmd, args, {\n cwd: options?.cwd || this.workingDir,\n shell: false,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString()\n })\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString()\n })\n\n child.on('error', (error: Error) => {\n if (timeoutId) clearTimeout(timeoutId)\n reject(error)\n })\n\n child.on('close', (code: number | null) => {\n if (timeoutId) clearTimeout(timeoutId)\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n interrupted,\n })\n })\n })\n }\n}\n\n// Global singleton instance\nlet globalSandboxController: SandboxController | null = null\n\n/**\n * Get the global sandbox controller instance\n */\nexport function getSandboxController(workingDir?: string): SandboxController {\n if (!globalSandboxController) {\n globalSandboxController = new SandboxController(workingDir || process.cwd())\n } else if (workingDir) {\n // Update working directory if provided\n globalSandboxController = new SandboxController(\n workingDir,\n globalSandboxController.getConfig(),\n )\n }\n return globalSandboxController\n}\n\n/**\n * Reset the global sandbox controller (for testing)\n */\nexport function resetSandboxController(): void {\n globalSandboxController = null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Sandbox Controller\n *\n * Main controller for the sandbox execution system.\n * Coordinates filesystem, network, and process isolation.\n */\n\nimport { spawn, type ChildProcess } from 'child_process'\nimport { platform } from 'os'\nimport { existsSync } from 'fs'\nimport { resolve } from 'path'\nimport type {\n ISandboxController,\n SandboxConfig,\n SandboxExecutionResult,\n SandboxImplementation,\n SandboxViolation,\n} from './types'\nimport { DEFAULT_SANDBOX_CONFIG } from './types'\nimport { FilesystemBoundary } from './filesystemBoundary'\nimport { NetworkProxy } from './networkProxy'\n\n/**\n * Sandbox Controller Implementation\n *\n * Provides unified sandbox management with OS-specific implementations.\n */\nexport class SandboxController implements ISandboxController {\n private config: SandboxConfig\n private implementation: SandboxImplementation\n private filesystemBoundary: FilesystemBoundary\n private networkProxy: NetworkProxy\n private violations: SandboxViolation[] = []\n private workingDir: string\n\n constructor(workingDir: string, config?: Partial<SandboxConfig>) {\n this.workingDir = resolve(workingDir)\n this.config = { ...DEFAULT_SANDBOX_CONFIG, ...config }\n this.implementation = this.detectImplementation()\n this.filesystemBoundary = new FilesystemBoundary(\n this.config.filesystem,\n this.workingDir,\n )\n this.networkProxy = new NetworkProxy(this.config.network)\n }\n\n /**\n * Check if sandbox is available on this system\n */\n async isAvailable(): Promise<boolean> {\n if (!this.config.enabled) {\n return false\n }\n\n switch (this.implementation) {\n case 'seatbelt':\n return this.isSeatbeltAvailable()\n case 'bubblewrap':\n return this.isBubblewrapAvailable()\n case 'docker':\n return this.isDockerAvailable()\n default:\n return false\n }\n }\n\n /**\n * Get the implementation type\n */\n getImplementationType(): SandboxImplementation {\n return this.implementation\n }\n\n /**\n * Initialize the sandbox\n */\n async initialize(config: SandboxConfig): Promise<void> {\n this.config = config\n this.filesystemBoundary = new FilesystemBoundary(\n config.filesystem,\n this.workingDir,\n )\n this.networkProxy = new NetworkProxy(config.network)\n this.violations = []\n }\n\n /**\n * Pre-validate a command against policies\n */\n async validateCommand(command: string): Promise<{\n valid: boolean\n violations: SandboxViolation[]\n }> {\n const violations: SandboxViolation[] = []\n\n // Check if command is excluded from sandboxing\n if (this.isExcludedCommand(command)) {\n return { valid: true, violations: [] }\n }\n\n // Validate filesystem access\n const fsResult = this.filesystemBoundary.analyzeCommand(command)\n for (const violation of fsResult.violations) {\n violation.command = command\n violations.push(violation)\n }\n\n // Validate network access\n const netResult = this.networkProxy.analyzeCommand(command)\n for (const violation of netResult.violations) {\n violation.command = command\n violations.push(violation)\n }\n\n // Store all violations\n this.violations.push(...violations)\n\n return {\n valid: violations.length === 0,\n violations,\n }\n }\n\n /**\n * Execute a command in the sandbox\n */\n async execute(\n command: string,\n workingDir: string,\n signal?: AbortSignal,\n timeout?: number,\n ): Promise<SandboxExecutionResult> {\n const startTime = Date.now()\n this.workingDir = resolve(workingDir)\n this.filesystemBoundary.setWorkingDir(this.workingDir)\n\n // If sandbox is disabled, execute directly\n if (!this.config.enabled) {\n return this.executeDirectly(command, signal, timeout)\n }\n\n // Validate command first\n const validation = await this.validateCommand(command)\n if (!validation.valid) {\n return {\n stdout: '',\n stderr: `Sandbox blocked command:\\n${validation.violations\n .map(v => `- ${v.details}`)\n .join('\\n')}`,\n exitCode: 1,\n interrupted: false,\n blocked: true,\n blockReason: validation.violations[0]?.details,\n duration: Date.now() - startTime,\n }\n }\n\n // Check if command is excluded from sandboxing\n if (this.isExcludedCommand(command)) {\n return this.executeDirectly(command, signal, timeout)\n }\n\n // Execute with appropriate sandbox\n switch (this.implementation) {\n case 'seatbelt':\n return this.executeWithSeatbelt(command, signal, timeout, startTime)\n case 'bubblewrap':\n return this.executeWithBubblewrap(command, signal, timeout, startTime)\n case 'docker':\n return this.executeWithDocker(command, signal, timeout, startTime)\n default:\n // No sandbox available, execute directly with validation only\n return this.executeDirectly(command, signal, timeout)\n }\n }\n\n /**\n * Get current configuration\n */\n getConfig(): SandboxConfig {\n return { ...this.config }\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<SandboxConfig>): void {\n this.config = { ...this.config, ...config }\n if (config.filesystem) {\n this.filesystemBoundary.updatePolicy(config.filesystem)\n }\n if (config.network) {\n this.networkProxy.updatePolicy(config.network)\n }\n }\n\n /**\n * Get violation history\n */\n getViolations(): SandboxViolation[] {\n return [\n ...this.violations,\n ...this.filesystemBoundary.getViolations(),\n ...this.networkProxy.getViolations(),\n ]\n }\n\n /**\n * Clear violation history\n */\n clearViolations(): void {\n this.violations = []\n this.filesystemBoundary.clearViolations()\n this.networkProxy.clearViolations()\n }\n\n /**\n * Get filesystem boundary instance\n */\n getFilesystemBoundary(): FilesystemBoundary {\n return this.filesystemBoundary\n }\n\n /**\n * Get network proxy instance\n */\n getNetworkProxy(): NetworkProxy {\n return this.networkProxy\n }\n\n /**\n * Detect the best available sandbox implementation\n */\n private detectImplementation(): SandboxImplementation {\n const os = platform()\n\n if (os === 'darwin') {\n // macOS - use seatbelt/sandbox-exec\n return 'seatbelt'\n } else if (os === 'linux') {\n // Linux - prefer bubblewrap, fallback to docker\n if (this.hasBubblewrap()) {\n return 'bubblewrap'\n } else if (this.hasDocker()) {\n return 'docker'\n }\n }\n\n return 'none'\n }\n\n /**\n * Check if bubblewrap is installed\n */\n private hasBubblewrap(): boolean {\n return existsSync('/usr/bin/bwrap') || existsSync('/usr/local/bin/bwrap')\n }\n\n /**\n * Check if docker is available\n */\n private hasDocker(): boolean {\n return existsSync('/usr/bin/docker') || existsSync('/usr/local/bin/docker')\n }\n\n /**\n * Check if seatbelt (macOS sandbox-exec) is available\n */\n private async isSeatbeltAvailable(): Promise<boolean> {\n return platform() === 'darwin' && existsSync('/usr/bin/sandbox-exec')\n }\n\n /**\n * Check if bubblewrap is available and working\n */\n private async isBubblewrapAvailable(): Promise<boolean> {\n if (!this.hasBubblewrap()) return false\n try {\n const result = await this.spawnAsync('bwrap', ['--version'])\n return result.exitCode === 0\n } catch {\n return false\n }\n }\n\n /**\n * Check if docker is available and running\n */\n private async isDockerAvailable(): Promise<boolean> {\n if (!this.hasDocker()) return false\n try {\n const result = await this.spawnAsync('docker', ['info'])\n return result.exitCode === 0\n } catch {\n return false\n }\n }\n\n /**\n * Check if a command is excluded from sandboxing\n */\n private isExcludedCommand(command: string): boolean {\n const firstWord = command.trim().split(/\\s+/)[0]?.toLowerCase()\n if (!firstWord) return false\n return this.config.process.excludedCommands.some(\n excluded => firstWord === excluded.toLowerCase(),\n )\n }\n\n /**\n * Execute command directly without sandboxing\n */\n private async executeDirectly(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n ): Promise<SandboxExecutionResult> {\n const startTime = Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n try {\n const result = await this.spawnAsync('sh', ['-c', command], {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n })\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - startTime,\n }\n } catch (error) {\n const err = error as Error\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: false,\n duration: Date.now() - startTime,\n }\n }\n }\n\n /**\n * Execute command with macOS seatbelt sandbox\n */\n private async executeWithSeatbelt(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n startTime?: number,\n ): Promise<SandboxExecutionResult> {\n const start = startTime || Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n // Generate seatbelt profile\n const profile = this.generateSeatbeltProfile()\n\n try {\n const result = await this.spawnAsync(\n 'sandbox-exec',\n ['-p', profile, 'sh', '-c', command],\n {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n },\n )\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - start,\n }\n } catch (error) {\n const err = error as Error\n const isBlocked =\n err.message.includes('sandbox') || err.message.includes('denied')\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: isBlocked,\n blockReason: isBlocked ? 'Sandbox policy violation' : undefined,\n duration: Date.now() - start,\n }\n }\n }\n\n /**\n * Escape a path for use in seatbelt profile strings.\n * Prevents injection via backslashes or double quotes in directory names.\n */\n private escapeSbplPath(path: string): string {\n return path.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n }\n\n /**\n * Generate macOS seatbelt profile\n */\n private generateSeatbeltProfile(): string {\n const writeAllowed = this.config.filesystem.writeAllowed\n .map(p => {\n if (p === './')\n return `(subpath \"${this.escapeSbplPath(this.workingDir)}\")`\n if (p === '*') return '(subpath \"/\")'\n const absPath = resolve(this.workingDir, p)\n return `(subpath \"${this.escapeSbplPath(absPath)}\")`\n })\n .join('\\n ')\n\n const readAllowed = this.config.filesystem.readAllowed\n .map(p => {\n if (p === '*') return '(subpath \"/\")'\n const absPath = resolve(this.workingDir, p)\n return `(subpath \"${this.escapeSbplPath(absPath)}\")`\n })\n .join('\\n ')\n\n const networkRules = this.config.network.blockAll\n ? '(deny network*)'\n : this.config.network.allowedDomains.length > 0\n ? `(allow network-outbound\n (remote tcp \"${this.config.network.allowedDomains.join('\", \"')}\"))`\n : '(allow network-outbound)'\n\n return `\n(version 1)\n(deny default)\n\n; Allow basic system operations\n(allow process-exec*)\n(allow process-fork)\n(allow file-read-metadata)\n(allow sysctl-read)\n\n; Allow reading system libraries and executables\n(allow file-read*\n (subpath \"/usr\")\n (subpath \"/bin\")\n (subpath \"/sbin\")\n (subpath \"/System\")\n (subpath \"/Library\")\n (subpath \"/private/var\")\n (subpath \"/private/tmp\")\n (subpath \"/dev\")\n (subpath \"/tmp\")\n ${readAllowed}\n)\n\n; Allow writing to specific paths\n(allow file-write*\n (subpath \"/dev\")\n (subpath \"/private/tmp\")\n (subpath \"/tmp\")\n ${writeAllowed}\n)\n\n; Network rules\n${networkRules}\n\n; Allow stdout/stderr\n(allow file-write-data\n (literal \"/dev/null\")\n (literal \"/dev/zero\")\n (literal \"/dev/random\")\n (literal \"/dev/urandom\")\n (literal \"/dev/tty\")\n (literal \"/dev/console\")\n)\n\n; Allow process management\n(allow signal)\n(allow mach-lookup)\n(allow ipc-posix-shm-read-data)\n(allow ipc-posix-shm-write-data)\n`\n }\n\n /**\n * Execute command with Linux bubblewrap sandbox\n */\n private async executeWithBubblewrap(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n startTime?: number,\n ): Promise<SandboxExecutionResult> {\n const start = startTime || Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n // Build bubblewrap arguments\n const bwrapArgs = this.buildBubblewrapArgs()\n\n try {\n const result = await this.spawnAsync(\n 'bwrap',\n [...bwrapArgs, 'sh', '-c', command],\n {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n },\n )\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - start,\n }\n } catch (error) {\n const err = error as Error\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: false,\n duration: Date.now() - start,\n }\n }\n }\n\n /**\n * Build bubblewrap command arguments\n */\n private buildBubblewrapArgs(): string[] {\n const args: string[] = []\n\n // Basic sandboxing\n args.push('--unshare-all')\n args.push('--die-with-parent')\n\n // Mount system directories read-only\n args.push('--ro-bind', '/usr', '/usr')\n args.push('--ro-bind', '/bin', '/bin')\n args.push('--ro-bind', '/lib', '/lib')\n if (existsSync('/lib64')) {\n args.push('--ro-bind', '/lib64', '/lib64')\n }\n args.push('--ro-bind', '/etc', '/etc')\n\n // Allow /tmp\n args.push('--tmpfs', '/tmp')\n\n // Set working directory with read-write access\n args.push('--bind', this.workingDir, this.workingDir)\n args.push('--chdir', this.workingDir)\n\n // Add additional read paths\n for (const path of this.config.filesystem.readAllowed) {\n if (path !== '*' && path !== './' && existsSync(path)) {\n const absPath = resolve(this.workingDir, path)\n if (existsSync(absPath)) {\n args.push('--ro-bind', absPath, absPath)\n }\n }\n }\n\n // Add additional write paths\n for (const path of this.config.filesystem.writeAllowed) {\n if (path !== './' && path !== '*') {\n const absPath = resolve(this.workingDir, path)\n if (existsSync(absPath)) {\n args.push('--bind', absPath, absPath)\n }\n }\n }\n\n // Network isolation (if blocking all)\n if (this.config.network.blockAll) {\n args.push('--unshare-net')\n }\n\n // Process limits\n if (this.config.process.maxProcesses > 0) {\n args.push(\n '--setenv',\n 'MINTO_MAX_PROCS',\n String(this.config.process.maxProcesses),\n )\n }\n\n return args\n }\n\n /**\n * Execute command with Docker sandbox\n */\n private async executeWithDocker(\n command: string,\n signal?: AbortSignal,\n timeout?: number,\n startTime?: number,\n ): Promise<SandboxExecutionResult> {\n const start = startTime || Date.now()\n const effectiveTimeout = timeout || this.config.process.maxExecutionTime\n\n // Build docker run arguments\n const dockerArgs = [\n 'run',\n '--rm',\n '-i',\n '--network',\n this.config.network.blockAll ? 'none' : 'bridge',\n '-v',\n `${this.workingDir}:/workspace`,\n '-w',\n '/workspace',\n ]\n\n // Add memory limit\n if (this.config.process.maxMemory > 0) {\n dockerArgs.push('--memory', `${this.config.process.maxMemory}`)\n }\n\n // Use a minimal image\n dockerArgs.push('alpine:latest')\n dockerArgs.push('sh', '-c', command)\n\n try {\n const result = await this.spawnAsync('docker', dockerArgs, {\n cwd: this.workingDir,\n signal,\n timeout: effectiveTimeout,\n })\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n interrupted: result.interrupted,\n blocked: false,\n duration: Date.now() - start,\n }\n } catch (error) {\n const err = error as Error\n return {\n stdout: '',\n stderr: err.message,\n exitCode: 1,\n interrupted: signal?.aborted || false,\n blocked: false,\n duration: Date.now() - start,\n }\n }\n }\n\n /**\n * Spawn a process with promise wrapper\n */\n private spawnAsync(\n cmd: string,\n args: string[],\n options?: {\n cwd?: string\n signal?: AbortSignal\n timeout?: number\n },\n ): Promise<{\n stdout: string\n stderr: string\n exitCode: number\n interrupted: boolean\n }> {\n return new Promise((resolve, reject) => {\n let stdout = ''\n let stderr = ''\n let interrupted = false\n let child: ChildProcess | null = null\n\n const timeoutId = options?.timeout\n ? setTimeout(() => {\n interrupted = true\n child?.kill('SIGTERM')\n }, options.timeout)\n : null\n\n // Handle abort signal\n if (options?.signal) {\n options.signal.addEventListener('abort', () => {\n interrupted = true\n child?.kill('SIGTERM')\n })\n }\n\n child = spawn(cmd, args, {\n cwd: options?.cwd || this.workingDir,\n shell: false,\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n\n child.stdout?.on('data', (data: Buffer) => {\n stdout += data.toString()\n })\n\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString()\n })\n\n child.on('error', (error: Error) => {\n if (timeoutId) clearTimeout(timeoutId)\n reject(error)\n })\n\n child.on('close', (code: number | null) => {\n if (timeoutId) clearTimeout(timeoutId)\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n interrupted,\n })\n })\n })\n }\n}\n\n// Global singleton instance\nlet globalSandboxController: SandboxController | null = null\n\n/**\n * Get the global sandbox controller instance\n */\nexport function getSandboxController(workingDir?: string): SandboxController {\n if (!globalSandboxController) {\n globalSandboxController = new SandboxController(workingDir || process.cwd())\n } else if (workingDir) {\n // Update working directory if provided\n globalSandboxController = new SandboxController(\n workingDir,\n globalSandboxController.getConfig(),\n )\n }\n return globalSandboxController\n}\n\n/**\n * Reset the global sandbox controller (for testing)\n */\nexport function resetSandboxController(): void {\n globalSandboxController = null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["resolve"]
7
7
  }
@@ -0,0 +1,77 @@
1
+ import { getGlobalConfig } from "../utils/config.js";
2
+ import { getOriginalCwd } from "../utils/state.js";
3
+ import { debug as debugLogger } from "../utils/debugLogger.js";
4
+ import { SessionMemoryManager } from "./sessionMemory.js";
5
+ let sessionMemoryLoaded = false;
6
+ let cachedSessionMemoryBlock = null;
7
+ function getSessionMemoryBlock() {
8
+ if (sessionMemoryLoaded) {
9
+ return cachedSessionMemoryBlock;
10
+ }
11
+ sessionMemoryLoaded = true;
12
+ try {
13
+ const config = getGlobalConfig();
14
+ if (config.enableSessionMemory === false) {
15
+ debugLogger.state("SESSION_MEMORY", { status: "disabled_by_config" });
16
+ return null;
17
+ }
18
+ const projectPath = getOriginalCwd();
19
+ if (!projectPath) {
20
+ return null;
21
+ }
22
+ const manager = new SessionMemoryManager(projectPath);
23
+ try {
24
+ manager.cleanupOldSessions(5);
25
+ } catch {
26
+ }
27
+ const recentSession = manager.getMostRecentSession();
28
+ if (!recentSession?.memory?.summary) {
29
+ debugLogger.state("SESSION_MEMORY", { status: "no_previous_session" });
30
+ return null;
31
+ }
32
+ const block = formatSessionMemoryBlock(recentSession.memory);
33
+ if (!block) {
34
+ return null;
35
+ }
36
+ cachedSessionMemoryBlock = block;
37
+ debugLogger.state("SESSION_MEMORY", {
38
+ status: "injected",
39
+ summaryLength: String(recentSession.memory.summary.length),
40
+ decisionsCount: String(recentSession.memory.decisions?.length ?? 0)
41
+ });
42
+ return cachedSessionMemoryBlock;
43
+ } catch (error) {
44
+ debugLogger.warn(
45
+ "SESSION_MEMORY",
46
+ `Failed to load session memory: ${error instanceof Error ? error.message : String(error)}`
47
+ );
48
+ return null;
49
+ }
50
+ }
51
+ function formatSessionMemoryBlock(memory) {
52
+ const parts = [];
53
+ if (!memory.summary || memory.summary.trim().length === 0) {
54
+ return null;
55
+ }
56
+ parts.push(memory.summary);
57
+ if (memory.decisions && memory.decisions.length > 0) {
58
+ const decisionsText = memory.decisions.slice(0, 10).map((d) => `- ${d.description}`).join("\n");
59
+ parts.push(`Key decisions:
60
+ ${decisionsText}`);
61
+ }
62
+ if (memory.focusAreas && memory.focusAreas.length > 0) {
63
+ parts.push(`Focus areas: ${memory.focusAreas.join(", ")}`);
64
+ }
65
+ return `<session-memory>
66
+ ${parts.join("\n")}
67
+ </session-memory>`;
68
+ }
69
+ function resetSessionMemoryCache() {
70
+ sessionMemoryLoaded = false;
71
+ cachedSessionMemoryBlock = null;
72
+ }
73
+ export {
74
+ getSessionMemoryBlock,
75
+ resetSessionMemoryCache
76
+ };
77
+ //# sourceMappingURL=sessionMemoryInjector.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/services/sessionMemoryInjector.ts"],
4
+ "sourcesContent": ["/**\n * Session Memory Injector\n *\n * Loads the most recent session memory for the current project\n * and formats it as a system prompt block for injection into new sessions.\n *\n * This mirrors Claude Code's behavior of injecting <session-memory> tags\n * from past sessions into new conversations.\n */\n\nimport { getGlobalConfig } from '@utils/config'\nimport { getOriginalCwd } from '@utils/state'\nimport { debug as debugLogger } from '@utils/debugLogger'\nimport { SessionMemoryManager, type SessionMemoryData } from './sessionMemory'\n\n/**\n * Whether session memory has been loaded for this process.\n * We only load once per session to avoid repeated disk I/O.\n */\nlet sessionMemoryLoaded = false\nlet cachedSessionMemoryBlock: string | null = null\n\n/**\n * Load and format the most recent session memory as a system prompt block.\n *\n * Called once per session (at first query). Returns null if:\n * - enableSessionMemory config is false\n * - No previous sessions exist for this project\n * - The most recent session has no meaningful content\n */\nexport function getSessionMemoryBlock(): string | null {\n if (sessionMemoryLoaded) {\n return cachedSessionMemoryBlock\n }\n\n sessionMemoryLoaded = true\n\n try {\n const config = getGlobalConfig()\n\n // enableSessionMemory defaults to true when not explicitly set\n if (config.enableSessionMemory === false) {\n debugLogger.state('SESSION_MEMORY', { status: 'disabled_by_config' })\n return null\n }\n\n const projectPath = getOriginalCwd()\n if (!projectPath) {\n return null\n }\n\n const manager = new SessionMemoryManager(projectPath)\n\n // Cleanup old sessions (keep last 5) - non-blocking best-effort\n try {\n manager.cleanupOldSessions(5)\n } catch {\n // Non-critical\n }\n\n const recentSession = manager.getMostRecentSession()\n if (!recentSession?.memory?.summary) {\n debugLogger.state('SESSION_MEMORY', { status: 'no_previous_session' })\n return null\n }\n\n const block = formatSessionMemoryBlock(recentSession.memory)\n if (!block) {\n return null\n }\n\n cachedSessionMemoryBlock = block\n\n debugLogger.state('SESSION_MEMORY', {\n status: 'injected',\n summaryLength: String(recentSession.memory.summary.length),\n decisionsCount: String(recentSession.memory.decisions?.length ?? 0),\n })\n\n return cachedSessionMemoryBlock\n } catch (error) {\n debugLogger.warn(\n 'SESSION_MEMORY',\n `Failed to load session memory: ${error instanceof Error ? error.message : String(error)}`,\n )\n return null\n }\n}\n\n/**\n * Format a SessionMemoryData into a <session-memory> prompt block.\n */\nfunction formatSessionMemoryBlock(memory: SessionMemoryData): string | null {\n const parts: string[] = []\n\n // Summary is required\n if (!memory.summary || memory.summary.trim().length === 0) {\n return null\n }\n\n parts.push(memory.summary)\n\n // Key decisions\n if (memory.decisions && memory.decisions.length > 0) {\n const decisionsText = memory.decisions\n .slice(0, 10) // Limit to 10 most recent decisions\n .map(d => `- ${d.description}`)\n .join('\\n')\n parts.push(`Key decisions:\\n${decisionsText}`)\n }\n\n // Focus areas\n if (memory.focusAreas && memory.focusAreas.length > 0) {\n parts.push(`Focus areas: ${memory.focusAreas.join(', ')}`)\n }\n\n return `<session-memory>\\n${parts.join('\\n')}\\n</session-memory>`\n}\n\n/**\n * Reset the cached session memory (for testing or session reset).\n */\nexport function resetSessionMemoryCache(): void {\n sessionMemoryLoaded = false\n cachedSessionMemoryBlock = null\n}\n"],
5
+ "mappings": "AAUA,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,SAAS,mBAAmB;AACrC,SAAS,4BAAoD;AAM7D,IAAI,sBAAsB;AAC1B,IAAI,2BAA0C;AAUvC,SAAS,wBAAuC;AACrD,MAAI,qBAAqB;AACvB,WAAO;AAAA,EACT;AAEA,wBAAsB;AAEtB,MAAI;AACF,UAAM,SAAS,gBAAgB;AAG/B,QAAI,OAAO,wBAAwB,OAAO;AACxC,kBAAY,MAAM,kBAAkB,EAAE,QAAQ,qBAAqB,CAAC;AACpE,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,eAAe;AACnC,QAAI,CAAC,aAAa;AAChB,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,IAAI,qBAAqB,WAAW;AAGpD,QAAI;AACF,cAAQ,mBAAmB,CAAC;AAAA,IAC9B,QAAQ;AAAA,IAER;AAEA,UAAM,gBAAgB,QAAQ,qBAAqB;AACnD,QAAI,CAAC,eAAe,QAAQ,SAAS;AACnC,kBAAY,MAAM,kBAAkB,EAAE,QAAQ,sBAAsB,CAAC;AACrE,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,yBAAyB,cAAc,MAAM;AAC3D,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,+BAA2B;AAE3B,gBAAY,MAAM,kBAAkB;AAAA,MAClC,QAAQ;AAAA,MACR,eAAe,OAAO,cAAc,OAAO,QAAQ,MAAM;AAAA,MACzD,gBAAgB,OAAO,cAAc,OAAO,WAAW,UAAU,CAAC;AAAA,IACpE,CAAC;AAED,WAAO;AAAA,EACT,SAAS,OAAO;AACd,gBAAY;AAAA,MACV;AAAA,MACA,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAC1F;AACA,WAAO;AAAA,EACT;AACF;AAKA,SAAS,yBAAyB,QAA0C;AAC1E,QAAM,QAAkB,CAAC;AAGzB,MAAI,CAAC,OAAO,WAAW,OAAO,QAAQ,KAAK,EAAE,WAAW,GAAG;AACzD,WAAO;AAAA,EACT;AAEA,QAAM,KAAK,OAAO,OAAO;AAGzB,MAAI,OAAO,aAAa,OAAO,UAAU,SAAS,GAAG;AACnD,UAAM,gBAAgB,OAAO,UAC1B,MAAM,GAAG,EAAE,EACX,IAAI,OAAK,KAAK,EAAE,WAAW,EAAE,EAC7B,KAAK,IAAI;AACZ,UAAM,KAAK;AAAA,EAAmB,aAAa,EAAE;AAAA,EAC/C;AAGA,MAAI,OAAO,cAAc,OAAO,WAAW,SAAS,GAAG;AACrD,UAAM,KAAK,gBAAgB,OAAO,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EAC3D;AAEA,SAAO;AAAA,EAAqB,MAAM,KAAK,IAAI,CAAC;AAAA;AAC9C;AAKO,SAAS,0BAAgC;AAC9C,wBAAsB;AACtB,6BAA2B;AAC7B;",
6
+ "names": []
7
+ }
@@ -1,4 +1,8 @@
1
+ import { homedir } from "os";
1
2
  import { getTodos } from "../utils/todoStorage.js";
3
+ function escapeXml(s) {
4
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5
+ }
2
6
  class SystemReminderService {
3
7
  sessionState = {
4
8
  lastTodoUpdate: 0,
@@ -33,13 +37,18 @@ class SystemReminderService {
33
37
  }
34
38
  const reminders = [];
35
39
  const currentTime = Date.now();
40
+ if (this.sessionState.remindersSent.size > 100) {
41
+ this.pruneOldReminders(currentTime);
42
+ }
36
43
  const reminderGenerators = [
44
+ () => this.getPlanModeActiveReminder(),
37
45
  () => this.dispatchTodoEvent(agentId),
38
46
  () => this.dispatchTaskToolsReminder(),
39
47
  () => this.dispatchSecurityEvent(),
40
48
  () => this.dispatchPerformanceEvent(),
41
49
  () => this.getMentionReminders(),
42
- () => this.getEventReminders()
50
+ () => this.getEventReminders(),
51
+ () => this.getTeamMessageReminders(agentId)
43
52
  ];
44
53
  for (const generator of reminderGenerators) {
45
54
  if (reminders.length >= 8) break;
@@ -52,6 +61,35 @@ class SystemReminderService {
52
61
  }
53
62
  return reminders;
54
63
  }
64
+ /**
65
+ * Plan mode persistent reminder — injected EVERY turn while plan mode is active (CC behavior).
66
+ * Not gated by remindersSent because it must appear on every generateReminders() call.
67
+ */
68
+ getPlanModeActiveReminder() {
69
+ try {
70
+ const {
71
+ isPlanModeEnabled,
72
+ getPlanFilePath
73
+ } = require("../utils/plan/planMode");
74
+ if (!isPlanModeEnabled()) return null;
75
+ const planPath = getPlanFilePath();
76
+ return this.createReminderMessage(
77
+ "plan_mode_active",
78
+ "general",
79
+ "high",
80
+ `Plan mode is active. You MUST NOT make any edits or changes except to the plan file at: ${planPath}
81
+
82
+ End every turn with either:
83
+ - AskUserQuestion (to clarify requirements)
84
+ - ExitPlanMode (to present your plan for approval)
85
+
86
+ Do NOT write code, edit files, or run commands other than read-only exploration.`,
87
+ Date.now()
88
+ );
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
55
93
  dispatchTodoEvent(agentId) {
56
94
  if (!this.sessionState.config.todoEmptyReminder) return null;
57
95
  const todos = getTodos(agentId);
@@ -103,9 +141,9 @@ ${todoContent}. Continue on with the tasks at hand if applicable.`,
103
141
  if (this.sessionState.remindersSent.has(key)) return null;
104
142
  const sessionDuration = Date.now() - this.sessionState.sessionStartTime;
105
143
  if (sessionDuration < 5 * 60 * 1e3) return null;
106
- const hasTaskActivity = Array.from(
107
- this.sessionState.remindersSent
108
- ).some((k) => k.startsWith("task_"));
144
+ const hasTaskActivity = Array.from(this.sessionState.remindersSent).some(
145
+ (k) => k.startsWith("task_")
146
+ );
109
147
  if (hasTaskActivity) return null;
110
148
  this.emitEvent("task:tools_reminder", {});
111
149
  return null;
@@ -188,6 +226,8 @@ ${todoContent}. Continue on with the tasks at hand if applicable.`,
188
226
  "plan_file_reference",
189
227
  "plan_mode_reentry",
190
228
  "plan_exited",
229
+ "plan_verify",
230
+ "plan_mode_active",
191
231
  "skill_invoked",
192
232
  "mcp_resource_no_content",
193
233
  "compact_file_reference",
@@ -224,6 +264,47 @@ ${todoContent}. Continue on with the tasks at hand if applicable.`,
224
264
  expiredKeys.forEach((key) => this.reminderCache.delete(key));
225
265
  return reminders;
226
266
  }
267
+ /**
268
+ * Deliver pending team mailbox messages to the current agent as reminders.
269
+ * Checks unread messages for the agent's team-scoped ID and formats them
270
+ * as <team-message> blocks for conversation injection.
271
+ */
272
+ getTeamMessageReminders(agentId) {
273
+ if (!agentId) return null;
274
+ const teamName = process.env.MINTO_TEAM_NAME || agentId.split("@")[1];
275
+ if (!teamName) return null;
276
+ try {
277
+ const { getTeam } = require("./agentTeams/teamManager");
278
+ const entry = getTeam(teamName);
279
+ if (!entry) return null;
280
+ const { mailbox } = entry;
281
+ const unread = mailbox.getUnread(agentId);
282
+ if (unread.length === 0) return null;
283
+ mailbox.markRead(unread.map((m) => m.id));
284
+ const currentTime = Date.now();
285
+ const reminders = [];
286
+ for (const msg of unread) {
287
+ const senderName = msg.from.split("@")[0] || msg.from;
288
+ const summaryText = msg.summary || msg.text.slice(0, 60).replace(/"/g, "'");
289
+ const colorAttr = msg.color ? ` color="${escapeXml(msg.color)}"` : "";
290
+ const content = `<team-message from="${escapeXml(senderName)}"${colorAttr} summary="${escapeXml(summaryText)}">
291
+ ${escapeXml(msg.text)}
292
+ </team-message>`;
293
+ reminders.push(
294
+ this.createReminderMessage(
295
+ "team_message",
296
+ "task",
297
+ "high",
298
+ content,
299
+ currentTime
300
+ )
301
+ );
302
+ }
303
+ return reminders;
304
+ } catch {
305
+ return null;
306
+ }
307
+ }
227
308
  /**
228
309
  * Generate reminders for external file changes
229
310
  * Called when todo files are modified externally
@@ -349,7 +430,7 @@ ${content}
349
430
  "hook_additional_context",
350
431
  "general",
351
432
  "medium",
352
- `Additional context from hook "${context.hookName}": ${context.content}`,
433
+ `Additional context from hook "${escapeXml(context.hookName)}": ${escapeXml(String(context.content))}`,
353
434
  Date.now()
354
435
  );
355
436
  this.reminderCache.set(key, reminder);
@@ -363,7 +444,7 @@ ${content}
363
444
  "hook_blocking_error",
364
445
  "general",
365
446
  "high",
366
- `A hook blocked the action: ${context.reason}`,
447
+ `A hook blocked the action: ${escapeXml(String(context.reason))}`,
367
448
  Date.now()
368
449
  );
369
450
  this.reminderCache.set(key, reminder);
@@ -377,7 +458,7 @@ ${content}
377
458
  "hook_stopped_continuation",
378
459
  "general",
379
460
  "high",
380
- `A hook stopped continuation: ${context.reason}`,
461
+ `A hook stopped continuation: ${escapeXml(String(context.reason))}`,
381
462
  Date.now()
382
463
  );
383
464
  this.reminderCache.set(key, reminder);
@@ -537,6 +618,20 @@ ${content}
537
618
  this.reminderCache.set(key, reminder);
538
619
  }
539
620
  });
621
+ this.addEventListener("plan:verify", (context) => {
622
+ const key = `plan_verify_${context.planPath}`;
623
+ if (!this.sessionState.remindersSent.has(key)) {
624
+ this.sessionState.remindersSent.add(key);
625
+ const reminder = this.createReminderMessage(
626
+ "plan_verify",
627
+ "general",
628
+ "medium",
629
+ `Implementation is complete. Verify against the approved plan at: ${context.planPath}. Check that all planned changes were made, run tests, and confirm the verification procedures from the plan pass.`,
630
+ Date.now()
631
+ );
632
+ this.reminderCache.set(key, reminder);
633
+ }
634
+ });
540
635
  this.addEventListener("token:usage", (context) => {
541
636
  const key = `token_usage_${context.threshold}`;
542
637
  if (!this.sessionState.remindersSent.has(key)) {
@@ -569,11 +664,17 @@ ${content}
569
664
  const key = `team_coord_${context.teamId}_${Date.now()}`;
570
665
  if (!this.sessionState.remindersSent.has(key)) {
571
666
  this.sessionState.remindersSent.add(key);
667
+ const teamId = context.teamId;
668
+ const homeDir = homedir();
669
+ const teamConfigPath = `${homeDir}/.minto/teams/${teamId}/config.json`;
670
+ const taskListPath = `${homeDir}/.minto/tasks/${teamId}`;
572
671
  const reminder = this.createReminderMessage(
573
672
  "team_coordination",
574
673
  "task",
575
674
  "medium",
576
- `Team coordination: ${context.message}`,
675
+ `Team coordination: ${context.message}
676
+ teamConfigPath: ${teamConfigPath}
677
+ taskListPath: ${taskListPath}`,
577
678
  Date.now()
578
679
  );
579
680
  this.reminderCache.set(key, reminder);
@@ -656,6 +757,27 @@ ${content}
656
757
  this.reminderCache.set(params.key, reminder);
657
758
  }
658
759
  }
760
+ /**
761
+ * Prune old reminder keys to prevent unbounded Set growth.
762
+ * Keeps keys that contain timestamps or are "sticky" (security, performance).
763
+ * Removes generic keys when the set exceeds threshold.
764
+ */
765
+ pruneOldReminders(_currentTime) {
766
+ const stickyPrefixes = ["file_security", "performance_", "todo_empty_"];
767
+ const toDelete = [];
768
+ for (const key of this.sessionState.remindersSent) {
769
+ if (!stickyPrefixes.some((p) => key.startsWith(p))) {
770
+ toDelete.push(key);
771
+ }
772
+ }
773
+ const removeCount = Math.min(
774
+ toDelete.length,
775
+ Math.floor(toDelete.length / 2)
776
+ );
777
+ for (let i = 0; i < removeCount; i++) {
778
+ this.sessionState.remindersSent.delete(toDelete[i]);
779
+ }
780
+ }
659
781
  resetSession() {
660
782
  this.sessionState = {
661
783
  lastTodoUpdate: 0,