@within-7/minto 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/dist/Tool.js +7 -0
  2. package/dist/Tool.js.map +2 -2
  3. package/dist/commands/agents/AgentsCommand.js +1 -1
  4. package/dist/commands/agents/AgentsCommand.js.map +2 -2
  5. package/dist/commands/agents/constants.js +2 -2
  6. package/dist/commands/agents/constants.js.map +2 -2
  7. package/dist/commands/clear.js +4 -3
  8. package/dist/commands/clear.js.map +2 -2
  9. package/dist/commands/compact.js +2 -2
  10. package/dist/commands/compact.js.map +1 -1
  11. package/dist/commands/context.js +3 -1
  12. package/dist/commands/context.js.map +2 -2
  13. package/dist/commands/login.js +128 -0
  14. package/dist/commands/login.js.map +7 -0
  15. package/dist/commands/memory.js +33 -82
  16. package/dist/commands/memory.js.map +2 -2
  17. package/dist/commands/quit.js +3 -1
  18. package/dist/commands/quit.js.map +2 -2
  19. package/dist/commands/resume.js +39 -239
  20. package/dist/commands/resume.js.map +2 -2
  21. package/dist/commands/tasks.js +1 -1
  22. package/dist/commands/tasks.js.map +2 -2
  23. package/dist/commands/terminalSetup.js +6 -2
  24. package/dist/commands/terminalSetup.js.map +2 -2
  25. package/dist/commands.js +2 -0
  26. package/dist/commands.js.map +2 -2
  27. package/dist/components/AgentDetailView.js +126 -0
  28. package/dist/components/AgentDetailView.js.map +7 -0
  29. package/dist/components/AgentThinkingBlock.js +1 -1
  30. package/dist/components/AgentThinkingBlock.js.map +2 -2
  31. package/dist/components/AgentViewBanner.js +22 -0
  32. package/dist/components/AgentViewBanner.js.map +7 -0
  33. package/dist/components/HeaderBar.js +1 -1
  34. package/dist/components/HeaderBar.js.map +2 -2
  35. package/dist/components/Help.js +8 -1
  36. package/dist/components/Help.js.map +2 -2
  37. package/dist/components/HotkeyHelpPanel.js +26 -8
  38. package/dist/components/HotkeyHelpPanel.js.map +2 -2
  39. package/dist/components/IdleNotificationBar.js +10 -0
  40. package/dist/components/IdleNotificationBar.js.map +7 -0
  41. package/dist/components/ModelSelector/ModelSelector.js +55 -20
  42. package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
  43. package/dist/components/PromptInput.js +186 -115
  44. package/dist/components/PromptInput.js.map +2 -2
  45. package/dist/components/RewindPanel.js +272 -0
  46. package/dist/components/RewindPanel.js.map +7 -0
  47. package/dist/components/Spinner.js +10 -21
  48. package/dist/components/Spinner.js.map +2 -2
  49. package/dist/components/StreamingTextPreview.js +29 -0
  50. package/dist/components/StreamingTextPreview.js.map +7 -0
  51. package/dist/components/SubagentBlock.js +3 -2
  52. package/dist/components/SubagentBlock.js.map +2 -2
  53. package/dist/components/SubagentProgress.js +4 -4
  54. package/dist/components/SubagentProgress.js.map +2 -2
  55. package/dist/components/TabbedListView/SearchInput.js +1 -1
  56. package/dist/components/TabbedListView/SearchInput.js.map +2 -2
  57. package/dist/components/TabbedListView/TabbedListView.js +87 -41
  58. package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
  59. package/dist/components/TaskCard.js +4 -4
  60. package/dist/components/TaskCard.js.map +2 -2
  61. package/dist/components/TeamMemberPanel.js +107 -0
  62. package/dist/components/TeamMemberPanel.js.map +7 -0
  63. package/dist/components/ThinkingSelector.js +84 -0
  64. package/dist/components/ThinkingSelector.js.map +7 -0
  65. package/dist/components/TitledDivider.js +26 -0
  66. package/dist/components/TitledDivider.js.map +7 -0
  67. package/dist/components/TodoPanel.js +31 -30
  68. package/dist/components/TodoPanel.js.map +2 -2
  69. package/dist/components/TokenWarning.js +28 -7
  70. package/dist/components/TokenWarning.js.map +2 -2
  71. package/dist/components/messages/AssistantTextMessage.js +5 -2
  72. package/dist/components/messages/AssistantTextMessage.js.map +2 -2
  73. package/dist/components/messages/AssistantToolUseMessage.js +9 -1
  74. package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
  75. package/dist/components/messages/DefaultToolResultFallback.js +11 -0
  76. package/dist/components/messages/DefaultToolResultFallback.js.map +7 -0
  77. package/dist/components/messages/ParallelTasksGroupView.js +14 -6
  78. package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
  79. package/dist/components/messages/TaskInModuleView.js +27 -27
  80. package/dist/components/messages/TaskInModuleView.js.map +2 -2
  81. package/dist/components/messages/UserGuidanceMessage.js +26 -0
  82. package/dist/components/messages/UserGuidanceMessage.js.map +7 -0
  83. package/dist/components/messages/UserPromptMessage.js +2 -1
  84. package/dist/components/messages/UserPromptMessage.js.map +2 -2
  85. package/dist/components/messages/UserTeamNotificationMessage.js +91 -0
  86. package/dist/components/messages/UserTeamNotificationMessage.js.map +7 -0
  87. package/dist/components/messages/UserTextMessage.js +8 -0
  88. package/dist/components/messages/UserTextMessage.js.map +2 -2
  89. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +4 -2
  90. package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +2 -2
  91. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +18 -1
  92. package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +2 -2
  93. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +12 -1
  94. package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
  95. package/dist/components/permissions/PermissionRequest.js +4 -0
  96. package/dist/components/permissions/PermissionRequest.js.map +2 -2
  97. package/dist/components/permissions/PlanApprovalRequest.js +164 -0
  98. package/dist/components/permissions/PlanApprovalRequest.js.map +7 -0
  99. package/dist/constants/agentTeams.js +17 -0
  100. package/dist/constants/agentTeams.js.map +7 -0
  101. package/dist/constants/macros.js +2 -1
  102. package/dist/constants/macros.js.map +2 -2
  103. package/dist/constants/prompts/agentPrompt.js +1 -0
  104. package/dist/constants/prompts/agentPrompt.js.map +2 -2
  105. package/dist/constants/prompts/autoMemory.js +39 -0
  106. package/dist/constants/prompts/autoMemory.js.map +7 -0
  107. package/dist/constants/prompts/codeConventions.js +1 -13
  108. package/dist/constants/prompts/codeConventions.js.map +2 -2
  109. package/dist/constants/prompts/doingTasks.js +21 -2
  110. package/dist/constants/prompts/doingTasks.js.map +2 -2
  111. package/dist/constants/prompts/envInfo.js +6 -7
  112. package/dist/constants/prompts/envInfo.js.map +2 -2
  113. package/dist/constants/prompts/index.js +27 -5
  114. package/dist/constants/prompts/index.js.map +2 -2
  115. package/dist/constants/prompts/taskManagement.js +2 -43
  116. package/dist/constants/prompts/taskManagement.js.map +2 -2
  117. package/dist/constants/prompts/teamOverlays.js +50 -0
  118. package/dist/constants/prompts/teamOverlays.js.map +7 -0
  119. package/dist/constants/prompts/toneAndStyle.js +4 -29
  120. package/dist/constants/prompts/toneAndStyle.js.map +2 -2
  121. package/dist/constants/prompts/toolUsagePolicy.js +7 -22
  122. package/dist/constants/prompts/toolUsagePolicy.js.map +2 -2
  123. package/dist/constants/toolInputExamples.js +2 -2
  124. package/dist/constants/toolInputExamples.js.map +2 -2
  125. package/dist/context.js +39 -6
  126. package/dist/context.js.map +2 -2
  127. package/dist/core/backupManager.js +1 -1
  128. package/dist/core/backupManager.js.map +2 -2
  129. package/dist/core/permissions/rules/planModeRule.js +1 -1
  130. package/dist/core/permissions/rules/planModeRule.js.map +1 -1
  131. package/dist/core/permissions/rules/safeModeRule.js +1 -1
  132. package/dist/core/permissions/rules/safeModeRule.js.map +1 -1
  133. package/dist/engine/AgentEngine.js +902 -0
  134. package/dist/engine/AgentEngine.js.map +7 -0
  135. package/dist/engine/EngineRegistry.js +89 -0
  136. package/dist/engine/EngineRegistry.js.map +7 -0
  137. package/dist/engine/foregroundAdapter.js +191 -0
  138. package/dist/engine/foregroundAdapter.js.map +7 -0
  139. package/dist/engine/index.js +15 -0
  140. package/dist/engine/index.js.map +7 -0
  141. package/dist/engine/types.js +1 -0
  142. package/dist/engine/types.js.map +7 -0
  143. package/dist/entrypoints/cli.js +410 -79
  144. package/dist/entrypoints/cli.js.map +3 -3
  145. package/dist/hooks/useAgentEngine.js +129 -0
  146. package/dist/hooks/useAgentEngine.js.map +7 -0
  147. package/dist/hooks/useAgentTokenStats.js +0 -16
  148. package/dist/hooks/useAgentTokenStats.js.map +2 -2
  149. package/dist/hooks/useCanUseTool.js +47 -2
  150. package/dist/hooks/useCanUseTool.js.map +2 -2
  151. package/dist/hooks/useDeferredLoading.js +4 -1
  152. package/dist/hooks/useDeferredLoading.js.map +2 -2
  153. package/dist/hooks/useIdleNotifications.js +66 -0
  154. package/dist/hooks/useIdleNotifications.js.map +7 -0
  155. package/dist/hooks/useSessionTracking.js +9 -7
  156. package/dist/hooks/useSessionTracking.js.map +2 -2
  157. package/dist/hooks/useTeamMembers.js +51 -0
  158. package/dist/hooks/useTeamMembers.js.map +7 -0
  159. package/dist/i18n/locales/en.js +77 -12
  160. package/dist/i18n/locales/en.js.map +2 -2
  161. package/dist/i18n/locales/zh-CN.js +77 -12
  162. package/dist/i18n/locales/zh-CN.js.map +2 -2
  163. package/dist/i18n/types.js.map +1 -1
  164. package/dist/messages.js.map +2 -2
  165. package/dist/permissions.js +113 -7
  166. package/dist/permissions.js.map +2 -2
  167. package/dist/query.js +135 -37
  168. package/dist/query.js.map +2 -2
  169. package/dist/screens/REPL.js +504 -361
  170. package/dist/screens/REPL.js.map +3 -3
  171. package/dist/screens/ResumeConversation.js +199 -14
  172. package/dist/screens/ResumeConversation.js.map +2 -2
  173. package/dist/services/adapters/base.js.map +1 -1
  174. package/dist/services/agentTeams/backends/headless.js +108 -0
  175. package/dist/services/agentTeams/backends/headless.js.map +7 -0
  176. package/dist/services/agentTeams/backends/inProcess.js +102 -0
  177. package/dist/services/agentTeams/backends/inProcess.js.map +7 -0
  178. package/dist/services/agentTeams/backends/resolver.js +18 -0
  179. package/dist/services/agentTeams/backends/resolver.js.map +7 -0
  180. package/dist/services/agentTeams/backends/tmux.js +168 -0
  181. package/dist/services/agentTeams/backends/tmux.js.map +7 -0
  182. package/dist/services/agentTeams/backends/types.js +1 -0
  183. package/dist/services/agentTeams/backends/types.js.map +7 -0
  184. package/dist/services/agentTeams/heartbeat.js +88 -0
  185. package/dist/services/agentTeams/heartbeat.js.map +7 -0
  186. package/dist/services/agentTeams/index.js +42 -2
  187. package/dist/services/agentTeams/index.js.map +2 -2
  188. package/dist/services/agentTeams/injectionChannel.js +105 -0
  189. package/dist/services/agentTeams/injectionChannel.js.map +7 -0
  190. package/dist/services/agentTeams/mailbox.js +410 -30
  191. package/dist/services/agentTeams/mailbox.js.map +2 -2
  192. package/dist/services/agentTeams/messageFormatter.js +80 -0
  193. package/dist/services/agentTeams/messageFormatter.js.map +7 -0
  194. package/dist/services/agentTeams/permissionDelegation.js +71 -0
  195. package/dist/services/agentTeams/permissionDelegation.js.map +7 -0
  196. package/dist/services/agentTeams/teamEvents.js +45 -0
  197. package/dist/services/agentTeams/teamEvents.js.map +7 -0
  198. package/dist/services/agentTeams/teamManager.js +251 -34
  199. package/dist/services/agentTeams/teamManager.js.map +2 -2
  200. package/dist/services/agentTeams/teamTaskStore.js +290 -61
  201. package/dist/services/agentTeams/teamTaskStore.js.map +2 -2
  202. package/dist/services/agentTeams/teammateSpawner.js +99 -18
  203. package/dist/services/agentTeams/teammateSpawner.js.map +2 -2
  204. package/dist/services/hookExecutor.js +51 -8
  205. package/dist/services/hookExecutor.js.map +2 -2
  206. package/dist/services/llm/anthropicProvider.js +56 -59
  207. package/dist/services/llm/anthropicProvider.js.map +2 -2
  208. package/dist/services/llm/dispatch.js +24 -5
  209. package/dist/services/llm/dispatch.js.map +2 -2
  210. package/dist/services/llm/openaiProvider.js +115 -136
  211. package/dist/services/llm/openaiProvider.js.map +3 -3
  212. package/dist/services/llm/types.js +89 -15
  213. package/dist/services/llm/types.js.map +2 -2
  214. package/dist/services/mcpClient.js +80 -4
  215. package/dist/services/mcpClient.js.map +2 -2
  216. package/dist/services/mintoAuth.js +299 -0
  217. package/dist/services/mintoAuth.js.map +7 -0
  218. package/dist/services/oauth.js +3 -3
  219. package/dist/services/oauth.js.map +2 -2
  220. package/dist/services/openai.js +91 -20
  221. package/dist/services/openai.js.map +2 -2
  222. package/dist/services/plugins/pluginRuntime.js +11 -5
  223. package/dist/services/plugins/pluginRuntime.js.map +2 -2
  224. package/dist/services/plugins/pluginValidation.js +4 -2
  225. package/dist/services/plugins/pluginValidation.js.map +2 -2
  226. package/dist/services/sandbox/sandboxController.js +11 -3
  227. package/dist/services/sandbox/sandboxController.js.map +2 -2
  228. package/dist/services/sessionMemoryInjector.js +77 -0
  229. package/dist/services/sessionMemoryInjector.js.map +7 -0
  230. package/dist/services/systemReminder.js +130 -8
  231. package/dist/services/systemReminder.js.map +2 -2
  232. package/dist/services/taskStore.js +199 -8
  233. package/dist/services/taskStore.js.map +3 -3
  234. package/dist/services/topicDetector.js +169 -0
  235. package/dist/services/topicDetector.js.map +7 -0
  236. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +0 -13
  237. package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
  238. package/dist/tools/BashTool/BashTool.js +51 -28
  239. package/dist/tools/BashTool/BashTool.js.map +2 -2
  240. package/dist/tools/BashTool/prompt.js +95 -118
  241. package/dist/tools/BashTool/prompt.js.map +2 -2
  242. package/dist/tools/BashTool/utils.js +39 -1
  243. package/dist/tools/BashTool/utils.js.map +2 -2
  244. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js +121 -0
  245. package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js.map +7 -0
  246. package/dist/tools/EnterWorktreeTool/prompt.js +22 -0
  247. package/dist/tools/EnterWorktreeTool/prompt.js.map +7 -0
  248. package/dist/tools/FileEditTool/FileEditTool.js +9 -4
  249. package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
  250. package/dist/tools/FileEditTool/prompt.js +3 -7
  251. package/dist/tools/FileEditTool/prompt.js.map +2 -2
  252. package/dist/tools/FileReadTool/FileReadTool.js +125 -3
  253. package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
  254. package/dist/tools/FileReadTool/prompt.js +1 -2
  255. package/dist/tools/FileReadTool/prompt.js.map +2 -2
  256. package/dist/tools/FileWriteTool/prompt.js +3 -5
  257. package/dist/tools/FileWriteTool/prompt.js.map +2 -2
  258. package/dist/tools/GlobTool/GlobTool.js +3 -2
  259. package/dist/tools/GlobTool/GlobTool.js.map +2 -2
  260. package/dist/tools/GrepTool/GrepTool.js +16 -5
  261. package/dist/tools/GrepTool/GrepTool.js.map +2 -2
  262. package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
  263. package/dist/tools/MCPSearchTool/MCPSearchTool.js +172 -0
  264. package/dist/tools/MCPSearchTool/MCPSearchTool.js.map +7 -0
  265. package/dist/tools/MCPSearchTool/prompt.js +77 -0
  266. package/dist/tools/MCPSearchTool/prompt.js.map +7 -0
  267. package/dist/tools/MultiEditTool/prompt.js +4 -7
  268. package/dist/tools/MultiEditTool/prompt.js.map +2 -2
  269. package/dist/tools/PlanModeTool/EnterPlanModeTool.js +12 -8
  270. package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
  271. package/dist/tools/PlanModeTool/ExitPlanModeTool.js +54 -1
  272. package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
  273. package/dist/tools/PlanModeTool/prompt.js +23 -74
  274. package/dist/tools/PlanModeTool/prompt.js.map +2 -2
  275. package/dist/tools/SendMessageTool/SendMessageTool.js +341 -0
  276. package/dist/tools/SendMessageTool/SendMessageTool.js.map +7 -0
  277. package/dist/tools/SendMessageTool/prompt.js +44 -0
  278. package/dist/tools/SendMessageTool/prompt.js.map +7 -0
  279. package/dist/tools/TaskCreateTool/prompt.js +15 -4
  280. package/dist/tools/TaskCreateTool/prompt.js.map +2 -2
  281. package/dist/tools/TaskListTool/prompt.js +18 -3
  282. package/dist/tools/TaskListTool/prompt.js.map +2 -2
  283. package/dist/tools/TaskOutputTool/prompt.js +4 -3
  284. package/dist/tools/TaskOutputTool/prompt.js.map +2 -2
  285. package/dist/tools/TaskTool/TaskTool.js +762 -98
  286. package/dist/tools/TaskTool/TaskTool.js.map +3 -3
  287. package/dist/tools/TaskTool/constants.js +8 -2
  288. package/dist/tools/TaskTool/constants.js.map +2 -2
  289. package/dist/tools/TaskTool/prompt.js +74 -70
  290. package/dist/tools/TaskTool/prompt.js.map +2 -2
  291. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +15 -1
  292. package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +2 -2
  293. package/dist/tools/TeamCreateTool/TeamCreateTool.js +129 -0
  294. package/dist/tools/TeamCreateTool/TeamCreateTool.js.map +7 -0
  295. package/dist/tools/TeamCreateTool/prompt.js +58 -0
  296. package/dist/tools/TeamCreateTool/prompt.js.map +7 -0
  297. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js +151 -0
  298. package/dist/tools/TeamDeleteTool/TeamDeleteTool.js.map +7 -0
  299. package/dist/tools/TeamDeleteTool/prompt.js +16 -0
  300. package/dist/tools/TeamDeleteTool/prompt.js.map +7 -0
  301. package/dist/tools/URLFetcherTool/URLFetcherTool.js +106 -15
  302. package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
  303. package/dist/tools/URLFetcherTool/prompt.js +3 -2
  304. package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
  305. package/dist/tools/WebSearchTool/WebSearchTool.js +2 -1
  306. package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
  307. package/dist/tools/WebSearchTool/prompt.js +5 -4
  308. package/dist/tools/WebSearchTool/prompt.js.map +2 -2
  309. package/dist/tools.js +100 -20
  310. package/dist/tools.js.map +2 -2
  311. package/dist/types/PermissionMode.js +35 -6
  312. package/dist/types/PermissionMode.js.map +2 -2
  313. package/dist/types/hooks.js +2 -0
  314. package/dist/types/hooks.js.map +2 -2
  315. package/dist/types/plugin.js +2 -0
  316. package/dist/types/plugin.js.map +3 -3
  317. package/dist/utils/CircuitBreaker.js +15 -9
  318. package/dist/utils/CircuitBreaker.js.map +2 -2
  319. package/dist/utils/agentLoader.js +249 -112
  320. package/dist/utils/agentLoader.js.map +2 -2
  321. package/dist/utils/animationManager.js +40 -3
  322. package/dist/utils/animationManager.js.map +2 -2
  323. package/dist/utils/ask.js +7 -6
  324. package/dist/utils/ask.js.map +2 -2
  325. package/dist/utils/atomicWrite.js +23 -0
  326. package/dist/utils/atomicWrite.js.map +7 -0
  327. package/dist/utils/autoCompactCore.js +73 -56
  328. package/dist/utils/autoCompactCore.js.map +2 -2
  329. package/dist/utils/autoMemoryPaths.js +89 -0
  330. package/dist/utils/autoMemoryPaths.js.map +7 -0
  331. package/dist/utils/config.js +63 -38
  332. package/dist/utils/config.js.map +2 -2
  333. package/dist/utils/configSchema.js +13 -8
  334. package/dist/utils/configSchema.js.map +2 -2
  335. package/dist/utils/credentials/index.js +14 -0
  336. package/dist/utils/credentials/index.js.map +2 -2
  337. package/dist/utils/dualPath.js +24 -0
  338. package/dist/utils/dualPath.js.map +7 -0
  339. package/dist/utils/exit.js +66 -7
  340. package/dist/utils/exit.js.map +2 -2
  341. package/dist/utils/externalEditor.js +155 -0
  342. package/dist/utils/externalEditor.js.map +7 -0
  343. package/dist/utils/fileLock.js +67 -0
  344. package/dist/utils/fileLock.js.map +7 -0
  345. package/dist/utils/format.js +24 -14
  346. package/dist/utils/format.js.map +2 -2
  347. package/dist/utils/globalErrorHandler.js +5 -96
  348. package/dist/utils/globalErrorHandler.js.map +3 -3
  349. package/dist/utils/groupHandlers/parallelTasksHandler.js +5 -3
  350. package/dist/utils/groupHandlers/parallelTasksHandler.js.map +2 -2
  351. package/dist/utils/groupHandlers/taskHandler.js +2 -2
  352. package/dist/utils/groupHandlers/taskHandler.js.map +2 -2
  353. package/dist/utils/hookManager.js +64 -6
  354. package/dist/utils/hookManager.js.map +2 -2
  355. package/dist/utils/log.js +6 -2
  356. package/dist/utils/log.js.map +2 -2
  357. package/dist/utils/markdown.js +237 -19
  358. package/dist/utils/markdown.js.map +2 -2
  359. package/dist/utils/messageContextManager.js +18 -5
  360. package/dist/utils/messageContextManager.js.map +2 -2
  361. package/dist/utils/messageGroupManager.js +1 -1
  362. package/dist/utils/messageGroupManager.js.map +2 -2
  363. package/dist/utils/messages.js +104 -46
  364. package/dist/utils/messages.js.map +2 -2
  365. package/dist/utils/model.js +2 -2
  366. package/dist/utils/model.js.map +2 -2
  367. package/dist/utils/pasteCache.js +8 -4
  368. package/dist/utils/pasteCache.js.map +2 -2
  369. package/dist/utils/pluginLoader.js +18 -0
  370. package/dist/utils/pluginLoader.js.map +2 -2
  371. package/dist/utils/secureKeyStorage.js +36 -7
  372. package/dist/utils/secureKeyStorage.js.map +2 -2
  373. package/dist/utils/simpleMode.js +7 -0
  374. package/dist/utils/simpleMode.js.map +7 -0
  375. package/dist/utils/streamingState.js +11 -1
  376. package/dist/utils/streamingState.js.map +2 -2
  377. package/dist/utils/taskDisplayUtils.js +2 -1
  378. package/dist/utils/taskDisplayUtils.js.map +2 -2
  379. package/dist/utils/teamConfig.js +2 -2
  380. package/dist/utils/teamConfig.js.map +2 -2
  381. package/dist/utils/thinking.js +6 -2
  382. package/dist/utils/thinking.js.map +3 -3
  383. package/dist/utils/tokenProgress.js +55 -0
  384. package/dist/utils/tokenProgress.js.map +7 -0
  385. package/dist/utils/toolRiskClassification.js +26 -17
  386. package/dist/utils/toolRiskClassification.js.map +2 -2
  387. package/dist/utils/tooling/toolError.js +12 -0
  388. package/dist/utils/tooling/toolError.js.map +7 -0
  389. package/dist/version.js +2 -2
  390. package/dist/version.js.map +1 -1
  391. package/package.json +10 -8
@@ -1,112 +1,341 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
1
+ import {
2
+ existsSync,
3
+ readFileSync,
4
+ writeFileSync,
5
+ mkdirSync,
6
+ unlinkSync,
7
+ readdirSync,
8
+ renameSync
9
+ } from "fs";
2
10
  import { join } from "path";
3
11
  import { homedir } from "os";
12
+ import { z } from "zod";
13
+ import { acquireFileLock, releaseFileLock } from "../../utils/fileLock.js";
14
+ import { debug as debugLog } from "../../utils/debugLogger.js";
15
+ const TeamTaskSchema = z.object({
16
+ id: z.string(),
17
+ subject: z.string(),
18
+ description: z.string(),
19
+ status: z.enum(["pending", "in_progress", "completed"]),
20
+ assignee: z.string().optional(),
21
+ activeForm: z.string().optional(),
22
+ metadata: z.record(z.unknown()).optional(),
23
+ blocks: z.array(z.string()).optional(),
24
+ blockedBy: z.array(z.string()).optional(),
25
+ createdAt: z.number(),
26
+ updatedAt: z.number()
27
+ });
4
28
  class TeamTaskStore {
5
29
  storePath;
6
30
  tasks = [];
31
+ /** TTL-based read cache to avoid redundant disk reads */
32
+ cachedTasks = null;
33
+ cacheTime = 0;
34
+ static CACHE_TTL_MS = 2e3;
7
35
  constructor(teamName) {
8
- this.storePath = join(homedir(), ".minto", "tasks", teamName, "tasks.json");
36
+ this.storePath = join(homedir(), ".minto", "tasks", teamName);
9
37
  }
10
38
  /**
11
- * Load tasks from disk
39
+ * Get the lock file path (directory-level lock)
12
40
  */
13
- load() {
41
+ get lockPath() {
42
+ return join(this.storePath, ".lock");
43
+ }
44
+ /**
45
+ * Get the file path for a specific task
46
+ */
47
+ taskFilePath(taskId) {
48
+ return join(this.storePath, `${taskId}.json`);
49
+ }
50
+ /**
51
+ * Save a single task to its individual file (atomic write)
52
+ */
53
+ saveTaskFile(task) {
14
54
  if (!existsSync(this.storePath)) {
15
- this.tasks = [];
16
- return;
55
+ mkdirSync(this.storePath, { recursive: true, mode: 448 });
17
56
  }
18
- try {
19
- const content = readFileSync(this.storePath, "utf-8");
20
- this.tasks = JSON.parse(content);
21
- } catch {
22
- this.tasks = [];
57
+ const filePath = this.taskFilePath(task.id);
58
+ const tmpPath = `${filePath}.tmp.${process.pid}`;
59
+ writeFileSync(tmpPath, JSON.stringify(task), {
60
+ encoding: "utf-8",
61
+ mode: 384
62
+ });
63
+ renameSync(tmpPath, filePath);
64
+ this.invalidateCache();
65
+ }
66
+ /**
67
+ * Load all task files from the store directory, with TTL-based caching.
68
+ */
69
+ loadAllTaskFiles() {
70
+ const now = Date.now();
71
+ if (this.cachedTasks && now - this.cacheTime < TeamTaskStore.CACHE_TTL_MS) {
72
+ return this.cachedTasks;
23
73
  }
74
+ if (!existsSync(this.storePath)) return [];
75
+ const files = readdirSync(this.storePath).filter(
76
+ (f) => f.endsWith(".json") && !f.startsWith(".") && f !== "tasks.json"
77
+ );
78
+ const tasks = [];
79
+ for (const f of files) {
80
+ try {
81
+ const raw = JSON.parse(readFileSync(join(this.storePath, f), "utf-8"));
82
+ const parsed = TeamTaskSchema.safeParse(raw);
83
+ if (parsed.success) {
84
+ tasks.push(parsed.data);
85
+ } else {
86
+ debugLog.warn("TASK_STORE_VALIDATION_FAILED", {
87
+ file: f,
88
+ error: parsed.error.message
89
+ });
90
+ }
91
+ } catch {
92
+ }
93
+ }
94
+ this.cachedTasks = tasks;
95
+ this.cacheTime = now;
96
+ return tasks;
97
+ }
98
+ /** Invalidate the read cache (called after writes) */
99
+ invalidateCache() {
100
+ this.cachedTasks = null;
101
+ this.cacheTime = 0;
24
102
  }
25
103
  /**
26
- * Save tasks to disk (atomic write)
104
+ * Load a single task file by ID
27
105
  */
28
- save() {
106
+ loadTaskFile(taskId) {
107
+ const filePath = this.taskFilePath(taskId);
108
+ if (!existsSync(filePath)) return null;
29
109
  try {
30
- const dir = join(this.storePath, "..");
31
- if (!existsSync(dir)) {
32
- mkdirSync(dir, { recursive: true });
110
+ const raw = JSON.parse(readFileSync(filePath, "utf-8"));
111
+ const parsed = TeamTaskSchema.safeParse(raw);
112
+ if (!parsed.success) {
113
+ debugLog.warn("TASK_STORE_FILE_VALIDATION_FAILED", {
114
+ taskId,
115
+ error: parsed.error.message
116
+ });
117
+ return null;
33
118
  }
34
- const tmpPath = `${this.storePath}.tmp`;
35
- writeFileSync(tmpPath, JSON.stringify(this.tasks, null, 2), "utf-8");
36
- const { renameSync } = require("fs");
37
- renameSync(tmpPath, this.storePath);
119
+ return parsed.data;
38
120
  } catch {
39
- writeFileSync(
40
- this.storePath,
41
- JSON.stringify(this.tasks, null, 2),
42
- "utf-8"
43
- );
121
+ return null;
122
+ }
123
+ }
124
+ /**
125
+ * Load tasks from disk.
126
+ * Includes migration: if an old monolithic tasks.json exists,
127
+ * migrate each task to its own file and remove tasks.json.
128
+ */
129
+ load() {
130
+ if (!existsSync(this.storePath)) {
131
+ mkdirSync(this.storePath, { recursive: true, mode: 448 });
132
+ this.tasks = [];
133
+ return;
134
+ }
135
+ const oldFile = join(this.storePath, "tasks.json");
136
+ if (existsSync(oldFile)) {
137
+ try {
138
+ const data = JSON.parse(readFileSync(oldFile, "utf-8"));
139
+ const parsed = z.array(TeamTaskSchema).safeParse(data);
140
+ if (parsed.success) {
141
+ for (const task of parsed.data) {
142
+ this.saveTaskFile(task);
143
+ }
144
+ unlinkSync(oldFile);
145
+ } else {
146
+ debugLog.warn("TASK_STORE_MIGRATION_VALIDATION_FAILED", {
147
+ error: parsed.error.message
148
+ });
149
+ }
150
+ } catch {
151
+ }
44
152
  }
153
+ this.tasks = this.loadAllTaskFiles();
45
154
  }
46
155
  /**
47
156
  * Create a new task
48
157
  */
49
- create(subject, description) {
50
- this.load();
51
- const maxId = this.tasks.reduce(
52
- (max, t) => Math.max(max, parseInt(t.id, 10) || 0),
53
- 0
54
- );
55
- const task = {
56
- id: String(maxId + 1),
57
- subject,
58
- description,
59
- status: "pending",
60
- createdAt: Date.now(),
61
- updatedAt: Date.now()
62
- };
63
- this.tasks.push(task);
64
- this.save();
65
- return task;
158
+ create(subject, description, options) {
159
+ if (!acquireFileLock(this.lockPath)) {
160
+ throw new Error("Could not acquire task store lock for create");
161
+ }
162
+ try {
163
+ this.tasks = this.loadAllTaskFiles();
164
+ const maxId = this.tasks.reduce(
165
+ (max, t) => Math.max(max, parseInt(t.id, 10) || 0),
166
+ 0
167
+ );
168
+ const task = {
169
+ id: String(maxId + 1),
170
+ subject,
171
+ description,
172
+ status: "pending",
173
+ ...options?.activeForm && { activeForm: options.activeForm },
174
+ ...options?.metadata && { metadata: options.metadata },
175
+ createdAt: Date.now(),
176
+ updatedAt: Date.now()
177
+ };
178
+ this.saveTaskFile(task);
179
+ this.tasks.push(task);
180
+ return task;
181
+ } finally {
182
+ releaseFileLock(this.lockPath);
183
+ }
66
184
  }
67
185
  /**
68
186
  * Claim a task (compare-and-swap to prevent double-claiming)
69
187
  */
70
188
  claim(taskId, assignee) {
71
- this.load();
72
- const task = this.tasks.find((t) => t.id === taskId);
73
- if (!task) return false;
74
- if (task.status !== "pending" || task.assignee) {
189
+ if (!acquireFileLock(this.lockPath)) {
75
190
  return false;
76
191
  }
77
- task.assignee = assignee;
78
- task.status = "in_progress";
79
- task.updatedAt = Date.now();
80
- this.save();
81
- return true;
192
+ try {
193
+ const task = this.loadTaskFile(taskId);
194
+ if (!task) return false;
195
+ if (task.status !== "pending" || task.assignee) {
196
+ return false;
197
+ }
198
+ task.assignee = assignee;
199
+ task.status = "in_progress";
200
+ task.updatedAt = Date.now();
201
+ this.saveTaskFile(task);
202
+ const idx = this.tasks.findIndex((t) => t.id === taskId);
203
+ if (idx >= 0) {
204
+ this.tasks[idx] = task;
205
+ } else {
206
+ this.tasks.push(task);
207
+ }
208
+ return true;
209
+ } finally {
210
+ releaseFileLock(this.lockPath);
211
+ }
82
212
  }
83
213
  /**
84
214
  * Complete a task
85
215
  */
86
216
  complete(taskId, assignee) {
87
- this.load();
88
- const task = this.tasks.find((t) => t.id === taskId);
89
- if (!task) return false;
90
- if (task.assignee !== assignee) return false;
91
- task.status = "completed";
92
- task.updatedAt = Date.now();
93
- this.save();
94
- return true;
217
+ if (!acquireFileLock(this.lockPath)) {
218
+ return false;
219
+ }
220
+ try {
221
+ const task = this.loadTaskFile(taskId);
222
+ if (!task) return false;
223
+ if (task.assignee !== assignee) return false;
224
+ task.status = "completed";
225
+ task.updatedAt = Date.now();
226
+ this.saveTaskFile(task);
227
+ const idx = this.tasks.findIndex((t) => t.id === taskId);
228
+ if (idx >= 0) {
229
+ this.tasks[idx] = task;
230
+ } else {
231
+ this.tasks.push(task);
232
+ }
233
+ return true;
234
+ } finally {
235
+ releaseFileLock(this.lockPath);
236
+ }
95
237
  }
96
238
  /**
97
239
  * Get all tasks
98
240
  */
99
241
  getAll() {
100
- this.load();
242
+ this.tasks = this.loadAllTaskFiles();
101
243
  return [...this.tasks];
102
244
  }
103
245
  /**
104
246
  * Get unclaimed tasks
105
247
  */
106
248
  getUnclaimed() {
107
- this.load();
249
+ this.tasks = this.loadAllTaskFiles();
108
250
  return this.tasks.filter((t) => t.status === "pending" && !t.assignee);
109
251
  }
252
+ /**
253
+ * Get tasks that are pending AND not blocked by incomplete tasks.
254
+ * This is the set of tasks a teammate can claim.
255
+ */
256
+ getUnblocked() {
257
+ this.tasks = this.loadAllTaskFiles();
258
+ return this.tasks.filter((t) => {
259
+ if (t.status !== "pending" || t.assignee) return false;
260
+ if (!t.blockedBy?.length) return true;
261
+ return t.blockedBy.every((blockerId) => {
262
+ const blocker = this.tasks.find((b) => b.id === blockerId);
263
+ return blocker && blocker.status === "completed";
264
+ });
265
+ });
266
+ }
267
+ /**
268
+ * General-purpose update for a task (status, subject, description, assignee).
269
+ * Uses file locking for cross-process safety.
270
+ */
271
+ update(taskId, fields) {
272
+ if (!acquireFileLock(this.lockPath)) {
273
+ return null;
274
+ }
275
+ try {
276
+ const task = this.loadTaskFile(taskId);
277
+ if (!task) return null;
278
+ if (fields.status !== void 0) task.status = fields.status;
279
+ if (fields.subject !== void 0) task.subject = fields.subject;
280
+ if (fields.description !== void 0)
281
+ task.description = fields.description;
282
+ if (fields.assignee !== void 0) task.assignee = fields.assignee;
283
+ if (fields.activeForm !== void 0) task.activeForm = fields.activeForm;
284
+ if (fields.metadata !== void 0) {
285
+ const merged = { ...task.metadata };
286
+ for (const [key, value] of Object.entries(fields.metadata)) {
287
+ if (value === null) {
288
+ delete merged[key];
289
+ } else {
290
+ merged[key] = value;
291
+ }
292
+ }
293
+ task.metadata = Object.keys(merged).length > 0 ? merged : void 0;
294
+ }
295
+ if (fields.addBlocks?.length) {
296
+ const current = new Set(task.blocks || []);
297
+ for (const id of fields.addBlocks) current.add(id);
298
+ task.blocks = Array.from(current);
299
+ }
300
+ if (fields.addBlockedBy?.length) {
301
+ const current = new Set(task.blockedBy || []);
302
+ for (const id of fields.addBlockedBy) current.add(id);
303
+ task.blockedBy = Array.from(current);
304
+ }
305
+ task.updatedAt = Date.now();
306
+ this.saveTaskFile(task);
307
+ const idx = this.tasks.findIndex((t) => t.id === taskId);
308
+ if (idx >= 0) {
309
+ this.tasks[idx] = task;
310
+ } else {
311
+ this.tasks.push(task);
312
+ }
313
+ return { ...task };
314
+ } finally {
315
+ releaseFileLock(this.lockPath);
316
+ }
317
+ }
318
+ /**
319
+ * Delete a task by ID.
320
+ */
321
+ delete(taskId) {
322
+ if (!acquireFileLock(this.lockPath)) {
323
+ return false;
324
+ }
325
+ try {
326
+ const filePath = this.taskFilePath(taskId);
327
+ if (!existsSync(filePath)) return false;
328
+ unlinkSync(filePath);
329
+ this.invalidateCache();
330
+ const idx = this.tasks.findIndex((t) => t.id === taskId);
331
+ if (idx >= 0) {
332
+ this.tasks.splice(idx, 1);
333
+ }
334
+ return true;
335
+ } finally {
336
+ releaseFileLock(this.lockPath);
337
+ }
338
+ }
110
339
  }
111
340
  export {
112
341
  TeamTaskStore
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/services/agentTeams/teamTaskStore.ts"],
4
- "sourcesContent": ["/**\n * Team Task Store\n *\n * Shared task storage for agent teams.\n * File-based with atomic writes for cross-process safety.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\n\n/**\n * Team task (simplified version of Task for cross-process sharing)\n */\nexport interface TeamTask {\n id: string\n subject: string\n description: string\n status: 'pending' | 'in_progress' | 'completed'\n assignee?: string\n createdAt: number\n updatedAt: number\n}\n\n/**\n * Shared task store for a team\n */\nexport class TeamTaskStore {\n private storePath: string\n private tasks: TeamTask[] = []\n\n constructor(teamName: string) {\n this.storePath = join(homedir(), '.minto', 'tasks', teamName, 'tasks.json')\n }\n\n /**\n * Load tasks from disk\n */\n load(): void {\n if (!existsSync(this.storePath)) {\n this.tasks = []\n return\n }\n\n try {\n const content = readFileSync(this.storePath, 'utf-8')\n this.tasks = JSON.parse(content)\n } catch {\n this.tasks = []\n }\n }\n\n /**\n * Save tasks to disk (atomic write)\n */\n private save(): void {\n try {\n const dir = join(this.storePath, '..')\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n // Atomic write: write to temp file then rename\n const tmpPath = `${this.storePath}.tmp`\n writeFileSync(tmpPath, JSON.stringify(this.tasks, null, 2), 'utf-8')\n\n // On most systems, rename is atomic within the same filesystem\n const { renameSync } = require('fs')\n renameSync(tmpPath, this.storePath)\n } catch {\n // Fallback: direct write\n writeFileSync(\n this.storePath,\n JSON.stringify(this.tasks, null, 2),\n 'utf-8',\n )\n }\n }\n\n /**\n * Create a new task\n */\n create(subject: string, description: string): TeamTask {\n // Reload to get latest state (cross-process safety)\n this.load()\n\n const maxId = this.tasks.reduce(\n (max, t) => Math.max(max, parseInt(t.id, 10) || 0),\n 0,\n )\n\n const task: TeamTask = {\n id: String(maxId + 1),\n subject,\n description,\n status: 'pending',\n createdAt: Date.now(),\n updatedAt: Date.now(),\n }\n\n this.tasks.push(task)\n this.save()\n return task\n }\n\n /**\n * Claim a task (compare-and-swap to prevent double-claiming)\n */\n claim(taskId: string, assignee: string): boolean {\n // Reload to get latest state\n this.load()\n\n const task = this.tasks.find(t => t.id === taskId)\n if (!task) return false\n\n // CAS: only claim if still pending and unassigned\n if (task.status !== 'pending' || task.assignee) {\n return false\n }\n\n task.assignee = assignee\n task.status = 'in_progress'\n task.updatedAt = Date.now()\n this.save()\n return true\n }\n\n /**\n * Complete a task\n */\n complete(taskId: string, assignee: string): boolean {\n this.load()\n\n const task = this.tasks.find(t => t.id === taskId)\n if (!task) return false\n\n // Only the assignee can complete\n if (task.assignee !== assignee) return false\n\n task.status = 'completed'\n task.updatedAt = Date.now()\n this.save()\n return true\n }\n\n /**\n * Get all tasks\n */\n getAll(): TeamTask[] {\n this.load()\n return [...this.tasks]\n }\n\n /**\n * Get unclaimed tasks\n */\n getUnclaimed(): TeamTask[] {\n this.load()\n return this.tasks.filter(t => t.status === 'pending' && !t.assignee)\n }\n}\n"],
5
- "mappings": "AAOA,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AAkBjB,MAAM,cAAc;AAAA,EACjB;AAAA,EACA,QAAoB,CAAC;AAAA,EAE7B,YAAY,UAAkB;AAC5B,SAAK,YAAY,KAAK,QAAQ,GAAG,UAAU,SAAS,UAAU,YAAY;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,QAAI,CAAC,WAAW,KAAK,SAAS,GAAG;AAC/B,WAAK,QAAQ,CAAC;AACd;AAAA,IACF;AAEA,QAAI;AACF,YAAM,UAAU,aAAa,KAAK,WAAW,OAAO;AACpD,WAAK,QAAQ,KAAK,MAAM,OAAO;AAAA,IACjC,QAAQ;AACN,WAAK,QAAQ,CAAC;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,OAAa;AACnB,QAAI;AACF,YAAM,MAAM,KAAK,KAAK,WAAW,IAAI;AACrC,UAAI,CAAC,WAAW,GAAG,GAAG;AACpB,kBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,MACpC;AAGA,YAAM,UAAU,GAAG,KAAK,SAAS;AACjC,oBAAc,SAAS,KAAK,UAAU,KAAK,OAAO,MAAM,CAAC,GAAG,OAAO;AAGnE,YAAM,EAAE,WAAW,IAAI,QAAQ,IAAI;AACnC,iBAAW,SAAS,KAAK,SAAS;AAAA,IACpC,QAAQ;AAEN;AAAA,QACE,KAAK;AAAA,QACL,KAAK,UAAU,KAAK,OAAO,MAAM,CAAC;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,SAAiB,aAA+B;AAErD,SAAK,KAAK;AAEV,UAAM,QAAQ,KAAK,MAAM;AAAA,MACvB,CAAC,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC;AAAA,MACjD;AAAA,IACF;AAEA,UAAM,OAAiB;AAAA,MACrB,IAAI,OAAO,QAAQ,CAAC;AAAA,MACpB;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,WAAW,KAAK,IAAI;AAAA,MACpB,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,MAAM,KAAK,IAAI;AACpB,SAAK,KAAK;AACV,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAgB,UAA2B;AAE/C,SAAK,KAAK;AAEV,UAAM,OAAO,KAAK,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM;AACjD,QAAI,CAAC,KAAM,QAAO;AAGlB,QAAI,KAAK,WAAW,aAAa,KAAK,UAAU;AAC9C,aAAO;AAAA,IACT;AAEA,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,YAAY,KAAK,IAAI;AAC1B,SAAK,KAAK;AACV,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,QAAgB,UAA2B;AAClD,SAAK,KAAK;AAEV,UAAM,OAAO,KAAK,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM;AACjD,QAAI,CAAC,KAAM,QAAO;AAGlB,QAAI,KAAK,aAAa,SAAU,QAAO;AAEvC,SAAK,SAAS;AACd,SAAK,YAAY,KAAK,IAAI;AAC1B,SAAK,KAAK;AACV,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,SAAqB;AACnB,SAAK,KAAK;AACV,WAAO,CAAC,GAAG,KAAK,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,eAA2B;AACzB,SAAK,KAAK;AACV,WAAO,KAAK,MAAM,OAAO,OAAK,EAAE,WAAW,aAAa,CAAC,EAAE,QAAQ;AAAA,EACrE;AACF;",
4
+ "sourcesContent": ["/**\n * Team Task Store\n *\n * Shared task storage for agent teams.\n * Each task is stored as an individual JSON file: {storePath}/{taskId}.json\n * This matches Claude Code's per-task storage model.\n *\n * File-based with atomic writes for cross-process safety.\n */\n\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n mkdirSync,\n unlinkSync,\n readdirSync,\n renameSync,\n} from 'fs'\nimport { join } from 'path'\nimport { homedir } from 'os'\nimport { z } from 'zod'\nimport { acquireFileLock, releaseFileLock } from '@utils/fileLock'\nimport { debug as debugLog } from '@utils/debugLogger'\n\n/** Zod schema for TeamTask \u2014 used to validate JSON parsed from task files */\nconst TeamTaskSchema = z.object({\n id: z.string(),\n subject: z.string(),\n description: z.string(),\n status: z.enum(['pending', 'in_progress', 'completed']),\n assignee: z.string().optional(),\n activeForm: z.string().optional(),\n metadata: z.record(z.unknown()).optional(),\n blocks: z.array(z.string()).optional(),\n blockedBy: z.array(z.string()).optional(),\n createdAt: z.number(),\n updatedAt: z.number(),\n})\n\n/**\n * Team task (simplified version of Task for cross-process sharing)\n */\nexport interface TeamTask {\n id: string\n subject: string\n description: string\n status: 'pending' | 'in_progress' | 'completed'\n assignee?: string\n activeForm?: string\n metadata?: Record<string, unknown>\n blocks?: string[] // Task IDs that this task blocks (unblocked when this completes)\n blockedBy?: string[] // Task IDs that block this task\n createdAt: number\n updatedAt: number\n}\n\n// acquireFileLock and releaseFileLock imported from @utils/fileLock\n\n/**\n * Shared task store for a team.\n *\n * Storage layout:\n * ~/.minto/tasks/{teamName}/ <- storePath (directory)\n * ~/.minto/tasks/{teamName}/1.json <- individual task file\n * ~/.minto/tasks/{teamName}/2.json\n * ~/.minto/tasks/{teamName}/.lock <- directory-level lock\n */\nexport class TeamTaskStore {\n private storePath: string\n private tasks: TeamTask[] = []\n /** TTL-based read cache to avoid redundant disk reads */\n private cachedTasks: TeamTask[] | null = null\n private cacheTime = 0\n private static readonly CACHE_TTL_MS = 2000\n\n constructor(teamName: string) {\n this.storePath = join(homedir(), '.minto', 'tasks', teamName)\n }\n\n /**\n * Get the lock file path (directory-level lock)\n */\n private get lockPath(): string {\n return join(this.storePath, '.lock')\n }\n\n /**\n * Get the file path for a specific task\n */\n private taskFilePath(taskId: string): string {\n return join(this.storePath, `${taskId}.json`)\n }\n\n /**\n * Save a single task to its individual file (atomic write)\n */\n private saveTaskFile(task: TeamTask): void {\n if (!existsSync(this.storePath)) {\n mkdirSync(this.storePath, { recursive: true, mode: 0o700 })\n }\n const filePath = this.taskFilePath(task.id)\n const tmpPath = `${filePath}.tmp.${process.pid}`\n writeFileSync(tmpPath, JSON.stringify(task), {\n encoding: 'utf-8',\n mode: 0o600,\n })\n renameSync(tmpPath, filePath)\n this.invalidateCache()\n }\n\n /**\n * Load all task files from the store directory, with TTL-based caching.\n */\n private loadAllTaskFiles(): TeamTask[] {\n const now = Date.now()\n if (this.cachedTasks && now - this.cacheTime < TeamTaskStore.CACHE_TTL_MS) {\n return this.cachedTasks\n }\n\n if (!existsSync(this.storePath)) return []\n const files = readdirSync(this.storePath).filter(\n f => f.endsWith('.json') && !f.startsWith('.') && f !== 'tasks.json',\n )\n const tasks: TeamTask[] = []\n for (const f of files) {\n try {\n const raw = JSON.parse(readFileSync(join(this.storePath, f), 'utf-8'))\n const parsed = TeamTaskSchema.safeParse(raw)\n if (parsed.success) {\n tasks.push(parsed.data as TeamTask)\n } else {\n debugLog.warn('TASK_STORE_VALIDATION_FAILED', {\n file: f,\n error: parsed.error.message,\n })\n }\n } catch {\n /* skip corrupted files */\n }\n }\n\n this.cachedTasks = tasks\n this.cacheTime = now\n return tasks\n }\n\n /** Invalidate the read cache (called after writes) */\n private invalidateCache(): void {\n this.cachedTasks = null\n this.cacheTime = 0\n }\n\n /**\n * Load a single task file by ID\n */\n private loadTaskFile(taskId: string): TeamTask | null {\n const filePath = this.taskFilePath(taskId)\n if (!existsSync(filePath)) return null\n try {\n const raw = JSON.parse(readFileSync(filePath, 'utf-8'))\n const parsed = TeamTaskSchema.safeParse(raw)\n if (!parsed.success) {\n debugLog.warn('TASK_STORE_FILE_VALIDATION_FAILED', {\n taskId,\n error: parsed.error.message,\n })\n return null\n }\n return parsed.data as TeamTask\n } catch {\n return null\n }\n }\n\n /**\n * Load tasks from disk.\n * Includes migration: if an old monolithic tasks.json exists,\n * migrate each task to its own file and remove tasks.json.\n */\n load(): void {\n if (!existsSync(this.storePath)) {\n mkdirSync(this.storePath, { recursive: true, mode: 0o700 })\n this.tasks = []\n return\n }\n\n // Migration: if old tasks.json exists, migrate to per-file\n const oldFile = join(this.storePath, 'tasks.json')\n if (existsSync(oldFile)) {\n try {\n const data = JSON.parse(readFileSync(oldFile, 'utf-8'))\n const parsed = z.array(TeamTaskSchema).safeParse(data)\n if (parsed.success) {\n for (const task of parsed.data) {\n this.saveTaskFile(task as TeamTask)\n }\n unlinkSync(oldFile)\n } else {\n debugLog.warn('TASK_STORE_MIGRATION_VALIDATION_FAILED', {\n error: parsed.error.message,\n })\n }\n } catch {\n /* ignore migration errors */\n }\n }\n\n // Load all task files\n this.tasks = this.loadAllTaskFiles()\n }\n\n /**\n * Create a new task\n */\n create(\n subject: string,\n description: string,\n options?: {\n activeForm?: string\n metadata?: Record<string, unknown>\n },\n ): TeamTask {\n if (!acquireFileLock(this.lockPath)) {\n throw new Error('Could not acquire task store lock for create')\n }\n try {\n // Reload to get latest state (cross-process safety)\n this.tasks = this.loadAllTaskFiles()\n\n const maxId = this.tasks.reduce(\n (max, t) => Math.max(max, parseInt(t.id, 10) || 0),\n 0,\n )\n\n const task: TeamTask = {\n id: String(maxId + 1),\n subject,\n description,\n status: 'pending',\n ...(options?.activeForm && { activeForm: options.activeForm }),\n ...(options?.metadata && { metadata: options.metadata }),\n createdAt: Date.now(),\n updatedAt: Date.now(),\n }\n\n this.saveTaskFile(task)\n this.tasks.push(task)\n return task\n } finally {\n releaseFileLock(this.lockPath)\n }\n }\n\n /**\n * Claim a task (compare-and-swap to prevent double-claiming)\n */\n claim(taskId: string, assignee: string): boolean {\n if (!acquireFileLock(this.lockPath)) {\n return false // Could not acquire lock\n }\n try {\n // Reload specific task from disk for cross-process safety\n const task = this.loadTaskFile(taskId)\n if (!task) return false\n\n // CAS: only claim if still pending and unassigned\n if (task.status !== 'pending' || task.assignee) {\n return false\n }\n\n task.assignee = assignee\n task.status = 'in_progress'\n task.updatedAt = Date.now()\n this.saveTaskFile(task)\n\n // Update in-memory array\n const idx = this.tasks.findIndex(t => t.id === taskId)\n if (idx >= 0) {\n this.tasks[idx] = task\n } else {\n this.tasks.push(task)\n }\n return true\n } finally {\n releaseFileLock(this.lockPath)\n }\n }\n\n /**\n * Complete a task\n */\n complete(taskId: string, assignee: string): boolean {\n if (!acquireFileLock(this.lockPath)) {\n return false // Could not acquire lock\n }\n try {\n // Reload specific task from disk\n const task = this.loadTaskFile(taskId)\n if (!task) return false\n\n // Only the assignee can complete\n if (task.assignee !== assignee) return false\n\n task.status = 'completed'\n task.updatedAt = Date.now()\n this.saveTaskFile(task)\n\n // Update in-memory array\n const idx = this.tasks.findIndex(t => t.id === taskId)\n if (idx >= 0) {\n this.tasks[idx] = task\n } else {\n this.tasks.push(task)\n }\n return true\n } finally {\n releaseFileLock(this.lockPath)\n }\n }\n\n /**\n * Get all tasks\n */\n getAll(): TeamTask[] {\n this.tasks = this.loadAllTaskFiles()\n return [...this.tasks]\n }\n\n /**\n * Get unclaimed tasks\n */\n getUnclaimed(): TeamTask[] {\n this.tasks = this.loadAllTaskFiles()\n return this.tasks.filter(t => t.status === 'pending' && !t.assignee)\n }\n\n /**\n * Get tasks that are pending AND not blocked by incomplete tasks.\n * This is the set of tasks a teammate can claim.\n */\n getUnblocked(): TeamTask[] {\n this.tasks = this.loadAllTaskFiles()\n return this.tasks.filter(t => {\n if (t.status !== 'pending' || t.assignee) return false\n if (!t.blockedBy?.length) return true\n return t.blockedBy.every(blockerId => {\n const blocker = this.tasks.find(b => b.id === blockerId)\n return blocker && blocker.status === 'completed'\n })\n })\n }\n\n /**\n * General-purpose update for a task (status, subject, description, assignee).\n * Uses file locking for cross-process safety.\n */\n update(\n taskId: string,\n fields: Partial<\n Pick<\n TeamTask,\n | 'status'\n | 'subject'\n | 'description'\n | 'assignee'\n | 'activeForm'\n | 'metadata'\n >\n > & {\n addBlocks?: string[]\n addBlockedBy?: string[]\n },\n ): TeamTask | null {\n if (!acquireFileLock(this.lockPath)) {\n return null\n }\n try {\n // Reload specific task from disk\n const task = this.loadTaskFile(taskId)\n if (!task) return null\n\n if (fields.status !== undefined) task.status = fields.status\n if (fields.subject !== undefined) task.subject = fields.subject\n if (fields.description !== undefined)\n task.description = fields.description\n if (fields.assignee !== undefined) task.assignee = fields.assignee\n if (fields.activeForm !== undefined) task.activeForm = fields.activeForm\n if (fields.metadata !== undefined) {\n const merged = { ...task.metadata }\n for (const [key, value] of Object.entries(fields.metadata)) {\n if (value === null) {\n delete merged[key]\n } else {\n merged[key] = value\n }\n }\n task.metadata = Object.keys(merged).length > 0 ? merged : undefined\n }\n if (fields.addBlocks?.length) {\n const current = new Set(task.blocks || [])\n for (const id of fields.addBlocks) current.add(id)\n task.blocks = Array.from(current)\n }\n if (fields.addBlockedBy?.length) {\n const current = new Set(task.blockedBy || [])\n for (const id of fields.addBlockedBy) current.add(id)\n task.blockedBy = Array.from(current)\n }\n task.updatedAt = Date.now()\n\n this.saveTaskFile(task)\n\n // Update in-memory array\n const idx = this.tasks.findIndex(t => t.id === taskId)\n if (idx >= 0) {\n this.tasks[idx] = task\n } else {\n this.tasks.push(task)\n }\n return { ...task }\n } finally {\n releaseFileLock(this.lockPath)\n }\n }\n\n /**\n * Delete a task by ID.\n */\n delete(taskId: string): boolean {\n if (!acquireFileLock(this.lockPath)) {\n return false\n }\n try {\n const filePath = this.taskFilePath(taskId)\n if (!existsSync(filePath)) return false\n\n unlinkSync(filePath)\n this.invalidateCache()\n\n // Update in-memory array\n const idx = this.tasks.findIndex(t => t.id === taskId)\n if (idx >= 0) {\n this.tasks.splice(idx, 1)\n }\n return true\n } finally {\n releaseFileLock(this.lockPath)\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,18 +4,7 @@ let teammateCounter = 0;
4
4
  function generateTeammateId() {
5
5
  return `teammate-${Date.now()}-${++teammateCounter}`;
6
6
  }
7
- const TEAMMATE_COLORS = [
8
- "cyan",
9
- "magenta",
10
- "yellow",
11
- "green",
12
- "blue",
13
- "red",
14
- "white"
15
- ];
16
- function getTeammateColor(index) {
17
- return TEAMMATE_COLORS[index % TEAMMATE_COLORS.length];
18
- }
7
+ import { getTeammateColor } from "../../constants/agentTeams.js";
19
8
  async function spawnTeammate(teamName, agentType, prompt, options) {
20
9
  const entry = getTeam(teamName);
21
10
  if (!entry) return null;
@@ -29,7 +18,11 @@ async function spawnTeammate(teamName, agentType, prompt, options) {
29
18
  agentType,
30
19
  status: "idle",
31
20
  prompt,
32
- color: getTeammateColor(team.members.length)
21
+ color: getTeammateColor(team.members.length),
22
+ joinedAt: Date.now(),
23
+ backendType: mode,
24
+ isActive: true,
25
+ parentSessionId: team.leadSessionId
33
26
  });
34
27
  if (mode === "tmux") {
35
28
  await spawnTmuxTeammate(teamName, teammate);
@@ -38,9 +31,17 @@ async function spawnTeammate(teamName, agentType, prompt, options) {
38
31
  }
39
32
  async function spawnTmuxTeammate(teamName, teammate) {
40
33
  try {
41
- const { execSync } = await import("child_process");
42
- const cmd = `minto --resume --prompt "${teammate.prompt.replace(/"/g, '\\"')}" --agent-type "${teammate.agentType}"`;
43
- execSync(`tmux split-window -h -t "${teamName}" "${cmd}"`, {
34
+ const { execFileSync } = await import("child_process");
35
+ const { safeQuote } = await import("./index.js");
36
+ const safeCmd = [
37
+ "minto",
38
+ "--resume",
39
+ "--prompt",
40
+ teammate.prompt,
41
+ "--agent-type",
42
+ teammate.agentType
43
+ ].map(safeQuote).join(" ");
44
+ execFileSync("tmux", ["split-window", "-h", "-t", teamName, safeCmd], {
44
45
  stdio: "pipe"
45
46
  });
46
47
  updateTeammateStatus(teamName, teammate.id, "working");
@@ -48,12 +49,91 @@ async function spawnTmuxTeammate(teamName, teammate) {
48
49
  updateTeammateStatus(teamName, teammate.id, "stopped");
49
50
  }
50
51
  }
51
- async function markTeammateIdle(teamName, teammateId, teammateName) {
52
+ async function markTeammateIdle(teamName, teammateId, teammateName, completedInfo) {
53
+ const teamEntry = getTeam(teamName);
54
+ if (teamEntry) {
55
+ const member = teamEntry.team.members.find(
56
+ (m) => m.id === teammateId || m.name === teammateName
57
+ );
58
+ if (member && (member.status === "idle" || member.status === "stopped")) {
59
+ return true;
60
+ }
61
+ }
62
+ const hookMgr = getHookManager();
63
+ if (hookMgr) {
64
+ try {
65
+ const hookResult = await hookMgr.executeTeammateIdle(
66
+ teammateName,
67
+ teamName
68
+ );
69
+ if (hookResult && !hookResult.shouldContinue) {
70
+ return false;
71
+ }
72
+ } catch {
73
+ }
74
+ }
52
75
  updateTeammateStatus(teamName, teammateId, "idle");
76
+ const entry = getTeam(teamName);
77
+ if (entry) {
78
+ const { mailbox } = entry;
79
+ const leadId = `team-lead@${teamName}`;
80
+ const idleNotification = JSON.stringify({
81
+ type: "idle_notification",
82
+ from: teammateName,
83
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
84
+ idleReason: "available",
85
+ ...completedInfo?.taskId && {
86
+ completedTaskId: completedInfo.taskId,
87
+ completedStatus: completedInfo.status || "completed"
88
+ },
89
+ ...completedInfo?.summary && {
90
+ summary: completedInfo.summary
91
+ },
92
+ ...completedInfo?.failureReason && {
93
+ failureReason: completedInfo.failureReason
94
+ }
95
+ });
96
+ mailbox.send(teammateId, leadId, idleNotification);
97
+ }
98
+ return true;
99
+ }
100
+ async function markTeammateCompleted(teamName, teammateId, teammateName, completedInfo) {
101
+ const teamEntry = getTeam(teamName);
102
+ if (teamEntry) {
103
+ const member = teamEntry.team.members.find(
104
+ (m) => m.id === teammateId || m.name === teammateName
105
+ );
106
+ if (member && member.status === "stopped") {
107
+ return;
108
+ }
109
+ }
110
+ updateTeammateStatus(teamName, teammateId, "stopped");
53
111
  const hookMgr = getHookManager();
54
112
  if (hookMgr) {
55
- hookMgr.executeTeammateIdle(teammateName, teamName).catch(() => {
113
+ try {
114
+ await hookMgr.executeTeammateIdle(teammateName, teamName);
115
+ } catch {
116
+ }
117
+ }
118
+ const entry = getTeam(teamName);
119
+ if (entry) {
120
+ const { mailbox } = entry;
121
+ const leadId = `team-lead@${teamName}`;
122
+ const allDone = entry.team.members.filter(
123
+ (m) => !m.name.startsWith("team-lead") && m.id !== `team-lead@${teamName}`
124
+ ).every((m) => m.status === "stopped");
125
+ const completionNotification = JSON.stringify({
126
+ type: "task_completed",
127
+ from: teammateName,
128
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
129
+ status: "completed",
130
+ ...completedInfo?.taskId && { taskId: completedInfo.taskId },
131
+ ...completedInfo?.summary && { summary: completedInfo.summary },
132
+ ...allDone && {
133
+ message: `All teammates have completed. You MUST now compose your final answer and call TeamDelete to clean up.`
134
+ }
56
135
  });
136
+ mailbox.send(teammateId, leadId, completionNotification);
57
137
  }
58
138
  }
59
139
  function getTeamSummary(teamName) {
@@ -74,6 +154,7 @@ function getTeamSummary(teamName) {
74
154
  }
75
155
  export {
76
156
  getTeamSummary,
157
+ markTeammateCompleted,
77
158
  markTeammateIdle,
78
159
  spawnTeammate
79
160
  };