@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.
- package/dist/Tool.js +7 -0
- package/dist/Tool.js.map +2 -2
- package/dist/commands/agents/AgentsCommand.js +1 -1
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/constants.js +2 -2
- package/dist/commands/agents/constants.js.map +2 -2
- package/dist/commands/clear.js +4 -3
- package/dist/commands/clear.js.map +2 -2
- package/dist/commands/compact.js +2 -2
- package/dist/commands/compact.js.map +1 -1
- package/dist/commands/context.js +3 -1
- package/dist/commands/context.js.map +2 -2
- package/dist/commands/login.js +128 -0
- package/dist/commands/login.js.map +7 -0
- package/dist/commands/memory.js +33 -82
- package/dist/commands/memory.js.map +2 -2
- package/dist/commands/quit.js +3 -1
- package/dist/commands/quit.js.map +2 -2
- package/dist/commands/resume.js +39 -239
- package/dist/commands/resume.js.map +2 -2
- package/dist/commands/tasks.js +1 -1
- package/dist/commands/tasks.js.map +2 -2
- package/dist/commands/terminalSetup.js +6 -2
- package/dist/commands/terminalSetup.js.map +2 -2
- package/dist/commands.js +2 -0
- package/dist/commands.js.map +2 -2
- package/dist/components/AgentDetailView.js +126 -0
- package/dist/components/AgentDetailView.js.map +7 -0
- package/dist/components/AgentThinkingBlock.js +1 -1
- package/dist/components/AgentThinkingBlock.js.map +2 -2
- package/dist/components/AgentViewBanner.js +22 -0
- package/dist/components/AgentViewBanner.js.map +7 -0
- package/dist/components/HeaderBar.js +1 -1
- package/dist/components/HeaderBar.js.map +2 -2
- package/dist/components/Help.js +8 -1
- package/dist/components/Help.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +26 -8
- package/dist/components/HotkeyHelpPanel.js.map +2 -2
- package/dist/components/IdleNotificationBar.js +10 -0
- package/dist/components/IdleNotificationBar.js.map +7 -0
- package/dist/components/ModelSelector/ModelSelector.js +55 -20
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/PromptInput.js +186 -115
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/RewindPanel.js +272 -0
- package/dist/components/RewindPanel.js.map +7 -0
- package/dist/components/Spinner.js +10 -21
- package/dist/components/Spinner.js.map +2 -2
- package/dist/components/StreamingTextPreview.js +29 -0
- package/dist/components/StreamingTextPreview.js.map +7 -0
- package/dist/components/SubagentBlock.js +3 -2
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/SubagentProgress.js +4 -4
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TabbedListView/SearchInput.js +1 -1
- package/dist/components/TabbedListView/SearchInput.js.map +2 -2
- package/dist/components/TabbedListView/TabbedListView.js +87 -41
- package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
- package/dist/components/TaskCard.js +4 -4
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TeamMemberPanel.js +107 -0
- package/dist/components/TeamMemberPanel.js.map +7 -0
- package/dist/components/ThinkingSelector.js +84 -0
- package/dist/components/ThinkingSelector.js.map +7 -0
- package/dist/components/TitledDivider.js +26 -0
- package/dist/components/TitledDivider.js.map +7 -0
- package/dist/components/TodoPanel.js +31 -30
- package/dist/components/TodoPanel.js.map +2 -2
- package/dist/components/TokenWarning.js +28 -7
- package/dist/components/TokenWarning.js.map +2 -2
- package/dist/components/messages/AssistantTextMessage.js +5 -2
- package/dist/components/messages/AssistantTextMessage.js.map +2 -2
- package/dist/components/messages/AssistantToolUseMessage.js +9 -1
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/DefaultToolResultFallback.js +11 -0
- package/dist/components/messages/DefaultToolResultFallback.js.map +7 -0
- package/dist/components/messages/ParallelTasksGroupView.js +14 -6
- package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
- package/dist/components/messages/TaskInModuleView.js +27 -27
- package/dist/components/messages/TaskInModuleView.js.map +2 -2
- package/dist/components/messages/UserGuidanceMessage.js +26 -0
- package/dist/components/messages/UserGuidanceMessage.js.map +7 -0
- package/dist/components/messages/UserPromptMessage.js +2 -1
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/components/messages/UserTeamNotificationMessage.js +91 -0
- package/dist/components/messages/UserTeamNotificationMessage.js.map +7 -0
- package/dist/components/messages/UserTextMessage.js +8 -0
- package/dist/components/messages/UserTextMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +4 -2
- package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +18 -1
- package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +12 -1
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
- package/dist/components/permissions/PermissionRequest.js +4 -0
- package/dist/components/permissions/PermissionRequest.js.map +2 -2
- package/dist/components/permissions/PlanApprovalRequest.js +164 -0
- package/dist/components/permissions/PlanApprovalRequest.js.map +7 -0
- package/dist/constants/agentTeams.js +17 -0
- package/dist/constants/agentTeams.js.map +7 -0
- package/dist/constants/macros.js +2 -1
- package/dist/constants/macros.js.map +2 -2
- package/dist/constants/prompts/agentPrompt.js +1 -0
- package/dist/constants/prompts/agentPrompt.js.map +2 -2
- package/dist/constants/prompts/autoMemory.js +39 -0
- package/dist/constants/prompts/autoMemory.js.map +7 -0
- package/dist/constants/prompts/codeConventions.js +1 -13
- package/dist/constants/prompts/codeConventions.js.map +2 -2
- package/dist/constants/prompts/doingTasks.js +21 -2
- package/dist/constants/prompts/doingTasks.js.map +2 -2
- package/dist/constants/prompts/envInfo.js +6 -7
- package/dist/constants/prompts/envInfo.js.map +2 -2
- package/dist/constants/prompts/index.js +27 -5
- package/dist/constants/prompts/index.js.map +2 -2
- package/dist/constants/prompts/taskManagement.js +2 -43
- package/dist/constants/prompts/taskManagement.js.map +2 -2
- package/dist/constants/prompts/teamOverlays.js +50 -0
- package/dist/constants/prompts/teamOverlays.js.map +7 -0
- package/dist/constants/prompts/toneAndStyle.js +4 -29
- package/dist/constants/prompts/toneAndStyle.js.map +2 -2
- package/dist/constants/prompts/toolUsagePolicy.js +7 -22
- package/dist/constants/prompts/toolUsagePolicy.js.map +2 -2
- package/dist/constants/toolInputExamples.js +2 -2
- package/dist/constants/toolInputExamples.js.map +2 -2
- package/dist/context.js +39 -6
- package/dist/context.js.map +2 -2
- package/dist/core/backupManager.js +1 -1
- package/dist/core/backupManager.js.map +2 -2
- package/dist/core/permissions/rules/planModeRule.js +1 -1
- package/dist/core/permissions/rules/planModeRule.js.map +1 -1
- package/dist/core/permissions/rules/safeModeRule.js +1 -1
- package/dist/core/permissions/rules/safeModeRule.js.map +1 -1
- package/dist/engine/AgentEngine.js +902 -0
- package/dist/engine/AgentEngine.js.map +7 -0
- package/dist/engine/EngineRegistry.js +89 -0
- package/dist/engine/EngineRegistry.js.map +7 -0
- package/dist/engine/foregroundAdapter.js +191 -0
- package/dist/engine/foregroundAdapter.js.map +7 -0
- package/dist/engine/index.js +15 -0
- package/dist/engine/index.js.map +7 -0
- package/dist/engine/types.js +1 -0
- package/dist/engine/types.js.map +7 -0
- package/dist/entrypoints/cli.js +410 -79
- package/dist/entrypoints/cli.js.map +3 -3
- package/dist/hooks/useAgentEngine.js +129 -0
- package/dist/hooks/useAgentEngine.js.map +7 -0
- package/dist/hooks/useAgentTokenStats.js +0 -16
- package/dist/hooks/useAgentTokenStats.js.map +2 -2
- package/dist/hooks/useCanUseTool.js +47 -2
- package/dist/hooks/useCanUseTool.js.map +2 -2
- package/dist/hooks/useDeferredLoading.js +4 -1
- package/dist/hooks/useDeferredLoading.js.map +2 -2
- package/dist/hooks/useIdleNotifications.js +66 -0
- package/dist/hooks/useIdleNotifications.js.map +7 -0
- package/dist/hooks/useSessionTracking.js +9 -7
- package/dist/hooks/useSessionTracking.js.map +2 -2
- package/dist/hooks/useTeamMembers.js +51 -0
- package/dist/hooks/useTeamMembers.js.map +7 -0
- package/dist/i18n/locales/en.js +77 -12
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +77 -12
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/messages.js.map +2 -2
- package/dist/permissions.js +113 -7
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +135 -37
- package/dist/query.js.map +2 -2
- package/dist/screens/REPL.js +504 -361
- package/dist/screens/REPL.js.map +3 -3
- package/dist/screens/ResumeConversation.js +199 -14
- package/dist/screens/ResumeConversation.js.map +2 -2
- package/dist/services/adapters/base.js.map +1 -1
- package/dist/services/agentTeams/backends/headless.js +108 -0
- package/dist/services/agentTeams/backends/headless.js.map +7 -0
- package/dist/services/agentTeams/backends/inProcess.js +102 -0
- package/dist/services/agentTeams/backends/inProcess.js.map +7 -0
- package/dist/services/agentTeams/backends/resolver.js +18 -0
- package/dist/services/agentTeams/backends/resolver.js.map +7 -0
- package/dist/services/agentTeams/backends/tmux.js +168 -0
- package/dist/services/agentTeams/backends/tmux.js.map +7 -0
- package/dist/services/agentTeams/backends/types.js +1 -0
- package/dist/services/agentTeams/backends/types.js.map +7 -0
- package/dist/services/agentTeams/heartbeat.js +88 -0
- package/dist/services/agentTeams/heartbeat.js.map +7 -0
- package/dist/services/agentTeams/index.js +42 -2
- package/dist/services/agentTeams/index.js.map +2 -2
- package/dist/services/agentTeams/injectionChannel.js +105 -0
- package/dist/services/agentTeams/injectionChannel.js.map +7 -0
- package/dist/services/agentTeams/mailbox.js +410 -30
- package/dist/services/agentTeams/mailbox.js.map +2 -2
- package/dist/services/agentTeams/messageFormatter.js +80 -0
- package/dist/services/agentTeams/messageFormatter.js.map +7 -0
- package/dist/services/agentTeams/permissionDelegation.js +71 -0
- package/dist/services/agentTeams/permissionDelegation.js.map +7 -0
- package/dist/services/agentTeams/teamEvents.js +45 -0
- package/dist/services/agentTeams/teamEvents.js.map +7 -0
- package/dist/services/agentTeams/teamManager.js +251 -34
- package/dist/services/agentTeams/teamManager.js.map +2 -2
- package/dist/services/agentTeams/teamTaskStore.js +290 -61
- package/dist/services/agentTeams/teamTaskStore.js.map +2 -2
- package/dist/services/agentTeams/teammateSpawner.js +99 -18
- package/dist/services/agentTeams/teammateSpawner.js.map +2 -2
- package/dist/services/hookExecutor.js +51 -8
- package/dist/services/hookExecutor.js.map +2 -2
- package/dist/services/llm/anthropicProvider.js +56 -59
- package/dist/services/llm/anthropicProvider.js.map +2 -2
- package/dist/services/llm/dispatch.js +24 -5
- package/dist/services/llm/dispatch.js.map +2 -2
- package/dist/services/llm/openaiProvider.js +115 -136
- package/dist/services/llm/openaiProvider.js.map +3 -3
- package/dist/services/llm/types.js +89 -15
- package/dist/services/llm/types.js.map +2 -2
- package/dist/services/mcpClient.js +80 -4
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/mintoAuth.js +299 -0
- package/dist/services/mintoAuth.js.map +7 -0
- package/dist/services/oauth.js +3 -3
- package/dist/services/oauth.js.map +2 -2
- package/dist/services/openai.js +91 -20
- package/dist/services/openai.js.map +2 -2
- package/dist/services/plugins/pluginRuntime.js +11 -5
- package/dist/services/plugins/pluginRuntime.js.map +2 -2
- package/dist/services/plugins/pluginValidation.js +4 -2
- package/dist/services/plugins/pluginValidation.js.map +2 -2
- package/dist/services/sandbox/sandboxController.js +11 -3
- package/dist/services/sandbox/sandboxController.js.map +2 -2
- package/dist/services/sessionMemoryInjector.js +77 -0
- package/dist/services/sessionMemoryInjector.js.map +7 -0
- package/dist/services/systemReminder.js +130 -8
- package/dist/services/systemReminder.js.map +2 -2
- package/dist/services/taskStore.js +199 -8
- package/dist/services/taskStore.js.map +3 -3
- package/dist/services/topicDetector.js +169 -0
- package/dist/services/topicDetector.js.map +7 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +0 -13
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +51 -28
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +95 -118
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/BashTool/utils.js +39 -1
- package/dist/tools/BashTool/utils.js.map +2 -2
- package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js +121 -0
- package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js.map +7 -0
- package/dist/tools/EnterWorktreeTool/prompt.js +22 -0
- package/dist/tools/EnterWorktreeTool/prompt.js.map +7 -0
- package/dist/tools/FileEditTool/FileEditTool.js +9 -4
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileEditTool/prompt.js +3 -7
- package/dist/tools/FileEditTool/prompt.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js +125 -3
- package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
- package/dist/tools/FileReadTool/prompt.js +1 -2
- package/dist/tools/FileReadTool/prompt.js.map +2 -2
- package/dist/tools/FileWriteTool/prompt.js +3 -5
- package/dist/tools/FileWriteTool/prompt.js.map +2 -2
- package/dist/tools/GlobTool/GlobTool.js +3 -2
- package/dist/tools/GlobTool/GlobTool.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +16 -5
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
- package/dist/tools/MCPSearchTool/MCPSearchTool.js +172 -0
- package/dist/tools/MCPSearchTool/MCPSearchTool.js.map +7 -0
- package/dist/tools/MCPSearchTool/prompt.js +77 -0
- package/dist/tools/MCPSearchTool/prompt.js.map +7 -0
- package/dist/tools/MultiEditTool/prompt.js +4 -7
- package/dist/tools/MultiEditTool/prompt.js.map +2 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +12 -8
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +54 -1
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/prompt.js +23 -74
- package/dist/tools/PlanModeTool/prompt.js.map +2 -2
- package/dist/tools/SendMessageTool/SendMessageTool.js +341 -0
- package/dist/tools/SendMessageTool/SendMessageTool.js.map +7 -0
- package/dist/tools/SendMessageTool/prompt.js +44 -0
- package/dist/tools/SendMessageTool/prompt.js.map +7 -0
- package/dist/tools/TaskCreateTool/prompt.js +15 -4
- package/dist/tools/TaskCreateTool/prompt.js.map +2 -2
- package/dist/tools/TaskListTool/prompt.js +18 -3
- package/dist/tools/TaskListTool/prompt.js.map +2 -2
- package/dist/tools/TaskOutputTool/prompt.js +4 -3
- package/dist/tools/TaskOutputTool/prompt.js.map +2 -2
- package/dist/tools/TaskTool/TaskTool.js +762 -98
- package/dist/tools/TaskTool/TaskTool.js.map +3 -3
- package/dist/tools/TaskTool/constants.js +8 -2
- package/dist/tools/TaskTool/constants.js.map +2 -2
- package/dist/tools/TaskTool/prompt.js +74 -70
- package/dist/tools/TaskTool/prompt.js.map +2 -2
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +15 -1
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +2 -2
- package/dist/tools/TeamCreateTool/TeamCreateTool.js +129 -0
- package/dist/tools/TeamCreateTool/TeamCreateTool.js.map +7 -0
- package/dist/tools/TeamCreateTool/prompt.js +58 -0
- package/dist/tools/TeamCreateTool/prompt.js.map +7 -0
- package/dist/tools/TeamDeleteTool/TeamDeleteTool.js +151 -0
- package/dist/tools/TeamDeleteTool/TeamDeleteTool.js.map +7 -0
- package/dist/tools/TeamDeleteTool/prompt.js +16 -0
- package/dist/tools/TeamDeleteTool/prompt.js.map +7 -0
- package/dist/tools/URLFetcherTool/URLFetcherTool.js +106 -15
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/prompt.js +3 -2
- package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
- package/dist/tools/WebSearchTool/WebSearchTool.js +2 -1
- package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
- package/dist/tools/WebSearchTool/prompt.js +5 -4
- package/dist/tools/WebSearchTool/prompt.js.map +2 -2
- package/dist/tools.js +100 -20
- package/dist/tools.js.map +2 -2
- package/dist/types/PermissionMode.js +35 -6
- package/dist/types/PermissionMode.js.map +2 -2
- package/dist/types/hooks.js +2 -0
- package/dist/types/hooks.js.map +2 -2
- package/dist/types/plugin.js +2 -0
- package/dist/types/plugin.js.map +3 -3
- package/dist/utils/CircuitBreaker.js +15 -9
- package/dist/utils/CircuitBreaker.js.map +2 -2
- package/dist/utils/agentLoader.js +249 -112
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/animationManager.js +40 -3
- package/dist/utils/animationManager.js.map +2 -2
- package/dist/utils/ask.js +7 -6
- package/dist/utils/ask.js.map +2 -2
- package/dist/utils/atomicWrite.js +23 -0
- package/dist/utils/atomicWrite.js.map +7 -0
- package/dist/utils/autoCompactCore.js +73 -56
- package/dist/utils/autoCompactCore.js.map +2 -2
- package/dist/utils/autoMemoryPaths.js +89 -0
- package/dist/utils/autoMemoryPaths.js.map +7 -0
- package/dist/utils/config.js +63 -38
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/configSchema.js +13 -8
- package/dist/utils/configSchema.js.map +2 -2
- package/dist/utils/credentials/index.js +14 -0
- package/dist/utils/credentials/index.js.map +2 -2
- package/dist/utils/dualPath.js +24 -0
- package/dist/utils/dualPath.js.map +7 -0
- package/dist/utils/exit.js +66 -7
- package/dist/utils/exit.js.map +2 -2
- package/dist/utils/externalEditor.js +155 -0
- package/dist/utils/externalEditor.js.map +7 -0
- package/dist/utils/fileLock.js +67 -0
- package/dist/utils/fileLock.js.map +7 -0
- package/dist/utils/format.js +24 -14
- package/dist/utils/format.js.map +2 -2
- package/dist/utils/globalErrorHandler.js +5 -96
- package/dist/utils/globalErrorHandler.js.map +3 -3
- package/dist/utils/groupHandlers/parallelTasksHandler.js +5 -3
- package/dist/utils/groupHandlers/parallelTasksHandler.js.map +2 -2
- package/dist/utils/groupHandlers/taskHandler.js +2 -2
- package/dist/utils/groupHandlers/taskHandler.js.map +2 -2
- package/dist/utils/hookManager.js +64 -6
- package/dist/utils/hookManager.js.map +2 -2
- package/dist/utils/log.js +6 -2
- package/dist/utils/log.js.map +2 -2
- package/dist/utils/markdown.js +237 -19
- package/dist/utils/markdown.js.map +2 -2
- package/dist/utils/messageContextManager.js +18 -5
- package/dist/utils/messageContextManager.js.map +2 -2
- package/dist/utils/messageGroupManager.js +1 -1
- package/dist/utils/messageGroupManager.js.map +2 -2
- package/dist/utils/messages.js +104 -46
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/model.js +2 -2
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/pasteCache.js +8 -4
- package/dist/utils/pasteCache.js.map +2 -2
- package/dist/utils/pluginLoader.js +18 -0
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/secureKeyStorage.js +36 -7
- package/dist/utils/secureKeyStorage.js.map +2 -2
- package/dist/utils/simpleMode.js +7 -0
- package/dist/utils/simpleMode.js.map +7 -0
- package/dist/utils/streamingState.js +11 -1
- package/dist/utils/streamingState.js.map +2 -2
- package/dist/utils/taskDisplayUtils.js +2 -1
- package/dist/utils/taskDisplayUtils.js.map +2 -2
- package/dist/utils/teamConfig.js +2 -2
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/thinking.js +6 -2
- package/dist/utils/thinking.js.map +3 -3
- package/dist/utils/tokenProgress.js +55 -0
- package/dist/utils/tokenProgress.js.map +7 -0
- package/dist/utils/toolRiskClassification.js +26 -17
- package/dist/utils/toolRiskClassification.js.map +2 -2
- package/dist/utils/tooling/toolError.js +12 -0
- package/dist/utils/tooling/toolError.js.map +7 -0
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +10 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/agentLoader.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Agent configuration loader\n * Loads agent configurations from markdown files with YAML frontmatter.\n * Implements Claude Code Subagent specification for agent configuration.\n */\n\nimport {\n existsSync,\n readFileSync,\n readdirSync,\n statSync,\n watch,\n FSWatcher,\n} from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\nimport matter from 'gray-matter'\nimport { getCwd } from './state'\nimport { memoize } from 'lodash-es'\nimport { loadAllPlugins } from './pluginLoader'\nimport type { PermissionMode } from '@minto-types/PermissionMode'\nimport type { HookDefinition } from '@minto-types/hooks'\n\n// Track warned agents to avoid spam\nconst warnedAgents = new Set<string>()\n\n/**\n * Agent lifecycle hooks configuration\n * Claude Code specification compliant\n */\nexport interface AgentHooks {\n onStart?: HookDefinition[]\n onComplete?: HookDefinition[]\n onError?: HookDefinition[]\n}\n\n/**\n * Agent memory persistence configuration\n * Claude Code specification compliant\n */\nexport interface AgentMemory {\n scope: 'user' | 'project' | 'local'\n key?: string // Optional namespace key for memory storage\n}\n\n/**\n * Agent configuration interface\n * Extended for Claude Code specification compliance\n */\nexport interface AgentConfig {\n // Identity\n agentType: string // Agent identifier (matches subagent_type)\n whenToUse: string // Description of when to use this agent\n systemPrompt: string // System prompt content\n location: 'built-in' | 'user' | 'project' | 'plugin'\n\n // Tool access control\n tools: string[] | '*' // Tool allowlist (or '*' for all)\n disallowedTools?: string[] // Tool denylist (takes precedence over tools)\n\n // Execution configuration\n model_name?: string // Model override (e.g., 'quick', 'main', 'reasoning')\n permissionMode?: PermissionMode // Permission handling mode\n maxThinkingTokens?: number // Extended thinking token limit\n\n // Skill preloading\n skills?: string[] // Skills to preload into agent context\n\n // Lifecycle hooks\n hooks?: AgentHooks // Agent lifecycle hooks\n\n // Memory persistence\n memory?: AgentMemory // Memory configuration for cross-session persistence\n\n // Isolation and execution modes (Claude Code spec)\n isolation?: 'worktree' // Git worktree isolation for parallel file edits\n background?: boolean // Run agent in background (fire-and-forget)\n mcpServers?: Record<\n string,\n { command: string; args?: string[]; env?: Record<string, string> }\n > // Per-agent MCP servers\n\n // UI/Display\n color?: string // Optional UI color\n pluginName?: string // Source plugin name (if loaded from plugin)\n\n // File origin\n sourcePath?: string // Absolute path to the .md file (user/project/plugin agents)\n}\n\n/**\n * Built-in agents for Claude Code specification compliance\n */\nconst BUILTIN_AGENTS: AgentConfig[] = [\n // general-purpose: Default agent for multi-step tasks\n {\n agentType: 'general-purpose',\n whenToUse:\n 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent.',\n tools: '*',\n systemPrompt: `You are a general-purpose agent. Given the user's task, use the tools available to complete it efficiently and thoroughly.\n\nWhen to use your capabilities:\n- Searching for code, configurations, and patterns across large codebases\n- Analyzing multiple files to understand system architecture\n- Investigating complex questions that require exploring many files\n- Performing multi-step research tasks\n\nGuidelines:\n- For file searches: Use Grep or Glob when you need to search broadly. Use Read when you know the specific file path.\n- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.\n- Be thorough: Check multiple locations, consider different naming conventions, look for related files.\n- Complete tasks directly using your capabilities.`,\n location: 'built-in',\n },\n\n // Explore: Fast read-only codebase exploration (Claude Code spec)\n {\n agentType: 'Explore',\n whenToUse:\n 'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns, search code for keywords, or answer questions about the codebase. Specify thoroughness: \"quick\" for basic searches, \"medium\" for moderate exploration, \"very thorough\" for comprehensive analysis.',\n tools: ['Read', 'Glob', 'Grep', 'LS', 'WebSearch', 'WebFetch'],\n disallowedTools: ['Edit', 'Write', 'Bash', 'NotebookEdit'],\n model_name: 'quick', // Maps to haiku equivalent\n permissionMode: 'plan', // Read-only mode\n systemPrompt: `You are an exploration agent optimized for fast codebase searches and understanding.\n\nYour role:\n- Quickly find files, functions, classes, and patterns\n- Understand code structure and architecture\n- Answer questions about how code works\n- Identify relevant files for a given task\n\nGuidelines:\n- Use Glob for finding files by pattern (e.g., \"**/*.tsx\", \"src/**/*.ts\")\n- Use Grep for searching code content (e.g., function names, imports, patterns)\n- Use Read to examine specific files you've identified\n- Start broad, then narrow down based on results\n- Report findings with specific file paths and line numbers\n- Be thorough but efficient - check multiple locations and naming conventions\n\nYou are READ-ONLY. You cannot modify any files.`,\n location: 'built-in',\n },\n\n // Plan: Research and planning agent (Claude Code spec)\n {\n agentType: 'Plan',\n whenToUse:\n 'Software architect agent for designing implementation plans. Use this when you need to plan the implementation strategy for a task. Returns step-by-step plans, identifies critical files, and considers architectural trade-offs.',\n tools: ['Read', 'Glob', 'Grep', 'LS', 'WebSearch', 'WebFetch', 'Think'],\n disallowedTools: ['Edit', 'Write', 'Bash', 'NotebookEdit'],\n model_name: 'inherit', // Inherit caller's model\n permissionMode: 'plan', // Read-only mode\n systemPrompt: `You are a planning agent specialized in analyzing codebases and creating implementation plans.\n\nYour role:\n- Understand requirements and constraints\n- Analyze existing code patterns and architecture\n- Create detailed, step-by-step implementation plans\n- Identify potential issues and trade-offs\n- Recommend best approaches based on codebase conventions\n\nGuidelines:\n- Read relevant files to understand current patterns\n- Identify all files that will need modification\n- Consider edge cases and error handling\n- Note any dependencies or prerequisites\n- Provide specific, actionable steps\n\nOutput format:\n1. Summary of the task\n2. Files to modify/create (with paths)\n3. Step-by-step implementation plan\n4. Potential challenges or considerations\n5. Testing approach\n\nYou are READ-ONLY. You cannot modify any files. Focus on planning, not execution.`,\n location: 'built-in',\n },\n\n // Bash: Shell command execution agent (Claude Code spec)\n {\n agentType: 'Bash',\n whenToUse:\n 'Command execution specialist for running bash commands. Use this for git operations, command execution, and other terminal tasks.',\n tools: ['Bash', 'Read', 'LS'],\n systemPrompt: `You are a bash execution agent specialized in running shell commands.\n\nYour role:\n- Execute shell commands safely and effectively\n- Handle build, test, and deployment tasks\n- Manage git operations\n- Run scripts and automation\n\nGuidelines:\n- Check command syntax before execution\n- Handle errors gracefully with clear messages\n- Report command output and exit codes\n- Be cautious with destructive commands (rm, git reset, etc.)\n- Use appropriate flags for verbose output when debugging\n- Chain commands with && for dependent operations\n\nAlways explain what a command will do before running it if it modifies the system.`,\n location: 'built-in',\n },\n]\n\n/**\n * Parse tools field from frontmatter\n */\nfunction parseTools(tools: any): string[] | '*' {\n if (!tools) return '*'\n if (tools === '*') return '*'\n if (Array.isArray(tools)) {\n // Ensure all items are strings and filter out non-strings\n const filteredTools = tools.filter(\n (t): t is string => typeof t === 'string',\n )\n return filteredTools.length > 0 ? filteredTools : '*'\n }\n if (typeof tools === 'string') {\n // Handle comma-separated string: \"Read, Grep, Glob\"\n if (tools.includes(',')) {\n return tools\n .split(',')\n .map((t: string) => t.trim())\n .filter(Boolean)\n }\n return [tools]\n }\n return '*'\n}\n\n/**\n * Parse disallowedTools field from frontmatter\n */\nfunction parseDisallowedTools(disallowedTools: any): string[] | undefined {\n if (!disallowedTools) return undefined\n if (Array.isArray(disallowedTools)) {\n const filtered = disallowedTools.filter(\n (t): t is string => typeof t === 'string',\n )\n return filtered.length > 0 ? filtered : undefined\n }\n if (typeof disallowedTools === 'string') {\n // Handle comma-separated string\n if (disallowedTools.includes(',')) {\n return disallowedTools\n .split(',')\n .map((t: string) => t.trim())\n .filter(Boolean)\n }\n return [disallowedTools]\n }\n return undefined\n}\n\n/**\n * Parse skills field from frontmatter\n */\nfunction parseSkills(skills: any): string[] | undefined {\n if (!skills) return undefined\n if (Array.isArray(skills)) {\n const filtered = skills.filter((s): s is string => typeof s === 'string')\n return filtered.length > 0 ? filtered : undefined\n }\n if (typeof skills === 'string') {\n if (skills.includes(',')) {\n return skills\n .split(',')\n .map((s: string) => s.trim())\n .filter(Boolean)\n }\n return [skills]\n }\n return undefined\n}\n\n/**\n * Parse memory field from frontmatter\n */\nfunction parseMemory(memory: any): AgentMemory | undefined {\n if (!memory) return undefined\n if (typeof memory === 'string') {\n // Simple format: \"user\" | \"project\" | \"local\"\n if (['user', 'project', 'local'].includes(memory)) {\n return { scope: memory as AgentMemory['scope'] }\n }\n return undefined\n }\n if (typeof memory === 'object') {\n const scope = memory.scope\n if (['user', 'project', 'local'].includes(scope)) {\n return {\n scope: scope as AgentMemory['scope'],\n ...(memory.key && { key: String(memory.key) }),\n }\n }\n }\n return undefined\n}\n\n/**\n * Parse permissionMode field from frontmatter\n */\nfunction parsePermissionMode(mode: any): PermissionMode | undefined {\n if (!mode) return undefined\n const validModes: PermissionMode[] = [\n 'default',\n 'acceptEdits',\n 'dontAsk',\n 'plan',\n 'bypassPermissions',\n ]\n if (typeof mode === 'string' && validModes.includes(mode as PermissionMode)) {\n return mode as PermissionMode\n }\n return undefined\n}\n\n/**\n * Scan a directory for agent configuration files\n */\nasync function scanAgentDirectory(\n dirPath: string,\n location: 'user' | 'project',\n): Promise<AgentConfig[]> {\n if (!existsSync(dirPath)) {\n return []\n }\n\n const agents: AgentConfig[] = []\n\n try {\n const files = readdirSync(dirPath)\n\n for (const file of files) {\n if (!file.endsWith('.md')) continue\n\n const filePath = join(dirPath, file)\n const stat = statSync(filePath)\n\n if (!stat.isFile()) continue\n\n try {\n const content = readFileSync(filePath, 'utf-8')\n if (!content.trim()) continue // Skip empty files silently\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields \u2014 fallback to markdown heading/first paragraph\n // for CC-style agent files without YAML frontmatter\n if (!frontmatter.name || !frontmatter.description) {\n const headingMatch = body.match(/^#\\s+(.+)/m)\n const firstParagraph = body\n .split(/\\n\\n/)\n .find(p => p.trim() && !p.trim().startsWith('#'))\n if (headingMatch) {\n if (!frontmatter.name) {\n frontmatter.name = headingMatch[1].trim()\n }\n if (!frontmatter.description) {\n frontmatter.description =\n firstParagraph?.trim() || frontmatter.name\n }\n } else {\n console.warn(\n `Skipping ${filePath}: missing required fields (name, description)`,\n )\n continue\n }\n }\n\n // Silently ignore deprecated 'model' field - no warnings by default\n // Only warn if MINTO_DEBUG_AGENTS environment variable is set\n if (\n frontmatter.model &&\n !frontmatter.model_name &&\n !warnedAgents.has(frontmatter.name) &&\n process.env.MINTO_DEBUG_AGENTS\n ) {\n console.warn(\n `\u26A0\uFE0F Agent ${frontmatter.name}: 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`,\n )\n warnedAgents.add(frontmatter.name)\n }\n\n // Parse optional fields\n const disallowedTools = parseDisallowedTools(\n frontmatter.disallowedTools,\n )\n const skills = parseSkills(frontmatter.skills)\n const memory = parseMemory(frontmatter.memory)\n const permissionMode = parsePermissionMode(frontmatter.permissionMode)\n\n // Build agent config with all Claude Code spec fields\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location,\n sourcePath: filePath,\n // Optional fields - only include if defined\n ...(frontmatter.color && { color: frontmatter.color }),\n ...(frontmatter.model_name && { model_name: frontmatter.model_name }),\n ...(disallowedTools && { disallowedTools }),\n ...(permissionMode && { permissionMode }),\n ...(skills && { skills }),\n ...(memory && { memory }),\n ...(frontmatter.maxThinkingTokens && {\n maxThinkingTokens: Number(frontmatter.maxThinkingTokens),\n }),\n ...(frontmatter.hooks && { hooks: frontmatter.hooks as AgentHooks }),\n ...(frontmatter.isolation && { isolation: frontmatter.isolation }),\n ...(frontmatter.background && {\n background: frontmatter.background === true,\n }),\n ...(frontmatter.mcpServers && { mcpServers: frontmatter.mcpServers }),\n }\n\n agents.push(agent)\n } catch (error) {\n console.warn(`Failed to parse agent file ${filePath}:`, error)\n }\n }\n } catch (error) {\n console.warn(`Failed to scan directory ${dirPath}:`, error)\n }\n\n return agents\n}\n\n/**\n * Load agents from installed plugins\n */\nasync function loadPluginAgents(): Promise<AgentConfig[]> {\n const agents: AgentConfig[] = []\n\n try {\n const plugins = loadAllPlugins()\n\n for (const plugin of plugins) {\n // Skip disabled plugins\n if (!plugin.enabled) continue\n\n for (const pluginAgent of plugin.agents) {\n try {\n // Read the agent file to parse frontmatter and content\n const content = readFileSync(pluginAgent.filePath, 'utf-8')\n if (!content.trim()) continue // Skip empty files silently\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields \u2014 fallback to markdown heading/first paragraph\n if (!frontmatter.name || !frontmatter.description) {\n const headingMatch = body.match(/^#\\s+(.+)/m)\n const firstParagraph = body\n .split(/\\n\\n/)\n .find(p => p.trim() && !p.trim().startsWith('#'))\n if (headingMatch) {\n if (!frontmatter.name) {\n frontmatter.name = headingMatch[1].trim()\n }\n if (!frontmatter.description) {\n frontmatter.description =\n firstParagraph?.trim() || frontmatter.name\n }\n } else {\n console.warn(\n `Skipping plugin agent ${pluginAgent.filePath}: missing required fields (name, description)`,\n )\n continue\n }\n }\n\n // Warn about deprecated 'model' field if debug mode is enabled\n if (\n frontmatter.model &&\n !frontmatter.model_name &&\n !warnedAgents.has(frontmatter.name) &&\n process.env.MINTO_DEBUG_AGENTS\n ) {\n console.warn(\n `\u26A0\uFE0F Plugin agent ${frontmatter.name} (from ${plugin.manifest.name}): 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`,\n )\n warnedAgents.add(frontmatter.name)\n }\n\n // Parse optional fields\n const disallowedTools = parseDisallowedTools(\n frontmatter.disallowedTools,\n )\n const skills = parseSkills(frontmatter.skills)\n const memory = parseMemory(frontmatter.memory)\n const permissionMode = parsePermissionMode(frontmatter.permissionMode)\n\n // Build agent config with all Claude Code spec fields\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location: 'plugin',\n pluginName: plugin.manifest.name,\n sourcePath: pluginAgent.filePath,\n // Optional fields\n ...(frontmatter.color && { color: frontmatter.color }),\n ...(frontmatter.model_name && {\n model_name: frontmatter.model_name,\n }),\n ...(disallowedTools && { disallowedTools }),\n ...(permissionMode && { permissionMode }),\n ...(skills && { skills }),\n ...(memory && { memory }),\n ...(frontmatter.maxThinkingTokens && {\n maxThinkingTokens: Number(frontmatter.maxThinkingTokens),\n }),\n ...(frontmatter.hooks && {\n hooks: frontmatter.hooks as AgentHooks,\n }),\n ...(frontmatter.isolation && { isolation: frontmatter.isolation }),\n ...(frontmatter.background && {\n background: frontmatter.background === true,\n }),\n ...(frontmatter.mcpServers && {\n mcpServers: frontmatter.mcpServers,\n }),\n }\n\n agents.push(agent)\n } catch (error) {\n console.warn(\n `Failed to load plugin agent ${pluginAgent.name} from ${plugin.manifest.name}:`,\n error,\n )\n }\n }\n }\n } catch (error) {\n console.warn('Failed to load plugin agents:', error)\n }\n\n return agents\n}\n\n/**\n * Load all agent configurations\n *\n * Directory Priority (later overrides earlier):\n * 1. Built-in agents (general-purpose, Explore, Plan, Bash)\n * 2. Plugin agents\n * 3. ~/.minto/agents (Minto user directory)\n * 4. ./.minto/agents (Minto project directory - highest priority)\n */\nasync function loadAllAgents(): Promise<{\n activeAgents: AgentConfig[]\n allAgents: AgentConfig[]\n}> {\n try {\n const home = homedir()\n const cwd = getCwd()\n\n // Define directories in priority order (later overrides earlier)\n // .claude/ dirs are legacy fallbacks, .minto/ dirs take precedence\n const userClaudeDir = join(home, '.claude', 'agents')\n const userMintoDir = join(home, '.minto', 'agents')\n const projectClaudeDir = join(cwd, '.claude', 'agents')\n const projectMintoDir = join(cwd, '.minto', 'agents')\n\n // Load from all sources in parallel\n const [\n pluginAgents,\n userClaudeAgents,\n userMintoAgents,\n projectClaudeAgents,\n projectMintoAgents,\n ] = await Promise.all([\n loadPluginAgents(),\n scanAgentDirectory(userClaudeDir, 'user'),\n scanAgentDirectory(userMintoDir, 'user'),\n scanAgentDirectory(projectClaudeDir, 'project'),\n scanAgentDirectory(projectMintoDir, 'project'),\n ])\n\n // Apply priority override: built-in < plugin < user/.claude < user/.minto < project/.claude < project/.minto\n // Later entries override earlier ones with the same agentType\n // Plugin agents are namespaced as \"pluginName:agentType\"\n const agentMap = new Map<string, AgentConfig>()\n\n // Add in priority order (later entries override earlier ones)\n for (const agent of BUILTIN_AGENTS) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of pluginAgents) {\n // Namespace plugin agents as \"pluginName:agentType\"\n const namespacedType = agent.pluginName\n ? `${agent.pluginName}:${agent.agentType}`\n : agent.agentType\n agentMap.set(namespacedType, { ...agent, agentType: namespacedType })\n }\n for (const agent of userClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of userMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n\n const activeAgents = Array.from(agentMap.values())\n const allAgents = [\n ...BUILTIN_AGENTS,\n ...pluginAgents,\n ...userClaudeAgents,\n ...userMintoAgents,\n ...projectClaudeAgents,\n ...projectMintoAgents,\n ]\n\n return { activeAgents, allAgents }\n } catch (error) {\n console.error('Failed to load agents, falling back to built-in:', error)\n return {\n activeAgents: [...BUILTIN_AGENTS],\n allAgents: [...BUILTIN_AGENTS],\n }\n }\n}\n\n// Memoized version for performance\nexport const getActiveAgents = memoize(async (): Promise<AgentConfig[]> => {\n const { activeAgents } = await loadAllAgents()\n return activeAgents\n})\n\n// Get all agents (both active and overridden)\nexport const getAllAgents = memoize(async (): Promise<AgentConfig[]> => {\n const { allAgents } = await loadAllAgents()\n return allAgents\n})\n\n// Clear cache when needed\nexport function clearAgentCache() {\n getActiveAgents.cache?.clear?.()\n getAllAgents.cache?.clear?.()\n getAgentByType.cache?.clear?.()\n getAvailableAgentTypes.cache?.clear?.()\n}\n\n// Get a specific agent by type\n// Supports both namespaced (\"plugin:agent\") and bare (\"agent\") lookups.\n// Bare names match non-plugin agents first; if not found, searches plugin agents by component name.\nexport const getAgentByType = memoize(\n async (agentType: string): Promise<AgentConfig | undefined> => {\n const agents = await getActiveAgents()\n\n // Direct match (exact agentType including namespace)\n const direct = agents.find(agent => agent.agentType === agentType)\n if (direct) return direct\n\n // If no colon in name, try to find among plugin agents by bare component name\n if (!agentType.includes(':')) {\n for (const agent of agents) {\n if (\n agent.agentType.includes(':') &&\n agent.agentType.split(':').pop() === agentType\n ) {\n return agent\n }\n }\n }\n\n return undefined\n },\n)\n\n// Get all available agent types for validation\nexport const getAvailableAgentTypes = memoize(async (): Promise<string[]> => {\n const agents = await getActiveAgents()\n return agents.map(agent => agent.agentType)\n})\n\n// File watcher for hot reload\nlet watchers: FSWatcher[] = []\n\n/**\n * Start watching agent configuration directories for changes\n */\nexport async function startAgentWatcher(onChange?: () => void): Promise<void> {\n await stopAgentWatcher() // Clean up any existing watchers\n\n const home = homedir()\n const cwd = getCwd()\n\n // Watch .minto and .claude (legacy) directories\n const directories = [\n { path: join(home, '.claude', 'agents'), label: 'user/.claude' },\n { path: join(home, '.minto', 'agents'), label: 'user/.minto' },\n { path: join(cwd, '.claude', 'agents'), label: 'project/.claude' },\n { path: join(cwd, '.minto', 'agents'), label: 'project/.minto' },\n ]\n\n const watchDirectory = (dirPath: string, label: string) => {\n if (existsSync(dirPath)) {\n const watcher = watch(\n dirPath,\n { recursive: false },\n async (eventType, filename) => {\n if (filename && filename.endsWith('.md')) {\n console.log(\n `\uD83D\uDD04 Agent configuration changed in ${label}: ${filename}`,\n )\n clearAgentCache()\n // Also clear any other related caches\n getAllAgents.cache?.clear?.()\n onChange?.()\n }\n },\n )\n watchers.push(watcher)\n }\n }\n\n // Watch all directories\n for (const { path, label } of directories) {\n watchDirectory(path, label)\n }\n}\n\n/**\n * Stop watching agent configuration directories\n */\nexport async function stopAgentWatcher(): Promise<void> {\n // FSWatcher.close() is synchronous and does not accept a callback on Node 18/20\n try {\n for (const watcher of watchers) {\n try {\n watcher.close()\n } catch (err) {\n console.error('Failed to close file watcher:', err)\n }\n }\n } finally {\n watchers = []\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Agent configuration loader\n * Loads agent configurations from markdown files with YAML frontmatter.\n * Implements Claude Code Subagent specification for agent configuration.\n */\n\nimport { existsSync, readFileSync, watch, FSWatcher } from 'fs'\nimport { readdir, stat, readFile } from 'fs/promises'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\nimport matter from 'gray-matter'\nimport { getCwd } from './state'\nimport { memoize } from 'lodash-es'\nimport { LRUCache } from 'lru-cache'\nimport { loadAllPlugins } from './pluginLoader'\nimport { debug as debugLog } from './debugLogger'\nimport type { PermissionMode } from '@minto-types/PermissionMode'\nimport type { HookDefinition } from '@minto-types/hooks'\n\n// Track warned agents to avoid spam\nconst warnedAgents = new Set<string>()\n\n/**\n * Agent lifecycle hooks configuration\n * Claude Code specification compliant\n */\nexport interface AgentHooks {\n onStart?: HookDefinition[]\n onComplete?: HookDefinition[]\n onError?: HookDefinition[]\n}\n\n/**\n * Agent memory persistence configuration\n * Claude Code specification compliant\n */\nexport interface AgentMemory {\n scope: 'user' | 'project' | 'local'\n key?: string // Optional namespace key for memory storage\n}\n\n/**\n * Agent configuration interface\n * Extended for Claude Code specification compliance\n */\nexport interface AgentConfig {\n // Identity\n agentType: string // Agent identifier (matches subagent_type)\n whenToUse: string // Description of when to use this agent\n systemPrompt: string // System prompt content\n location: 'built-in' | 'user' | 'project' | 'plugin'\n\n // Tool access control\n tools: string[] | '*' // Tool allowlist (or '*' for all)\n disallowedTools?: string[] // Tool denylist (takes precedence over tools)\n\n // Execution configuration\n model_name?: string // Model override (e.g., 'quick', 'main', 'reasoning')\n permissionMode?: PermissionMode // Permission handling mode\n maxThinkingTokens?: number // Extended thinking token limit\n maxTurns?: number // Maximum conversation turns for this agent\n\n // Skill preloading\n skills?: string[] // Skills to preload into agent context\n\n // Lifecycle hooks\n hooks?: AgentHooks // Agent lifecycle hooks\n\n // Memory persistence\n memory?: AgentMemory // Memory configuration for cross-session persistence\n\n // Isolation and execution modes (Claude Code spec)\n isolation?: 'worktree' // Git worktree isolation for parallel file edits\n background?: boolean // Run agent in background (fire-and-forget)\n mcpServers?: Record<\n string,\n { command: string; args?: string[]; env?: Record<string, string> }\n > // Per-agent MCP servers\n\n // UI/Display\n color?: string // Optional UI color\n pluginName?: string // Source plugin name (if loaded from plugin)\n\n // File origin\n sourcePath?: string // Absolute path to the .md file (user/project/plugin agents)\n}\n\n/**\n * Built-in agents for Claude Code specification compliance\n */\nconst BUILTIN_AGENTS: AgentConfig[] = [\n // general-purpose: Default agent for multi-step tasks\n {\n agentType: 'general-purpose',\n whenToUse:\n 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent.',\n tools: '*',\n systemPrompt: `You are a general-purpose agent. Given the user's task, use the tools available to complete it efficiently and thoroughly.\n\nWhen to use your capabilities:\n- Searching for code, configurations, and patterns across large codebases\n- Analyzing multiple files to understand system architecture\n- Investigating complex questions that require exploring many files\n- Performing multi-step research tasks\n\nGuidelines:\n- For file searches: Use Grep or Glob when you need to search broadly. Use Read when you know the specific file path.\n- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.\n- Be thorough: Check multiple locations, consider different naming conventions, look for related files.\n- Complete tasks directly using your capabilities.`,\n location: 'built-in',\n },\n\n // Explore: Fast read-only codebase exploration (Claude Code spec)\n {\n agentType: 'Explore',\n whenToUse:\n 'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns, search code for keywords, or answer questions about the codebase. Specify thoroughness: \"quick\" for basic searches, \"medium\" for moderate exploration, \"very thorough\" for comprehensive analysis.',\n tools: ['Read', 'Glob', 'Grep', 'LS', 'WebSearch', 'WebFetch'],\n disallowedTools: ['Edit', 'Write', 'Bash', 'NotebookEdit'],\n model_name: 'quick', // Maps to haiku equivalent\n permissionMode: 'plan', // Read-only mode\n systemPrompt: `You are an exploration agent optimized for fast codebase searches and understanding.\n\nYour role:\n- Quickly find files, functions, classes, and patterns\n- Understand code structure and architecture\n- Answer questions about how code works\n- Identify relevant files for a given task\n\nGuidelines:\n- Use Glob for finding files by pattern (e.g., \"**/*.tsx\", \"src/**/*.ts\")\n- Use Grep for searching code content (e.g., function names, imports, patterns)\n- Use Read to examine specific files you've identified\n- Start broad, then narrow down based on results\n- Report findings with specific file paths and line numbers\n- Be thorough but efficient - check multiple locations and naming conventions\n\nYou are READ-ONLY. You cannot modify any files.`,\n location: 'built-in',\n },\n\n // Plan: Research and planning agent (Claude Code spec)\n {\n agentType: 'Plan',\n whenToUse:\n 'Software architect agent for designing implementation plans. Use this when you need to plan the implementation strategy for a task. Returns step-by-step plans, identifies critical files, and considers architectural trade-offs.',\n tools: ['Read', 'Glob', 'Grep', 'LS', 'WebSearch', 'WebFetch', 'Think'],\n disallowedTools: ['Edit', 'Write', 'Bash', 'NotebookEdit'],\n model_name: 'inherit', // Inherit caller's model\n permissionMode: 'plan', // Read-only mode\n systemPrompt: `You are a planning agent. Analyze the codebase and create an implementation plan.\n\nYour output must include:\n1. Context \u2014 Problem being solved, motivation, intended outcome\n2. Critical file paths \u2014 All files to modify/create\n3. Recommended approach \u2014 Step-by-step plan referencing existing utilities and patterns\n4. Verification \u2014 Testing procedures for end-to-end validation\n\nGuidelines:\n- Read relevant files to understand current patterns before designing\n- Identify reusable utilities and existing conventions\n- Consider edge cases and dependencies\n- Be specific and actionable \u2014 reference exact file paths and function names\n\nYou are READ-ONLY. You cannot modify any files. Focus on planning, not execution.`,\n location: 'built-in',\n },\n\n // output-style-setup: Agent for creating custom output styles\n {\n agentType: 'output-style-setup',\n whenToUse:\n 'Agent for creating and customizing output display styles. Use this when you need to help the user configure how Minto formats and displays tool results, assistant responses, or status messages.',\n tools: ['Read', 'Write', 'Edit', 'Glob', 'Grep'],\n model_name: 'main',\n systemPrompt: `You are an output style configuration agent for Minto CLI.\n\nYour role:\n- Help users create custom output styles for Minto's terminal display\n- Modify style configuration files to adjust formatting, colors, and layout\n- Read existing style files to understand current configuration\n\nGuidelines:\n- Check existing style files in .minto/ and src/utils/style.ts first\n- Follow the existing code style pattern exactly\n- Make minimal, focused changes\n- Validate that style changes won't break existing functionality`,\n location: 'built-in',\n },\n\n // statusline-setup: Agent for configuring the status line\n {\n agentType: 'statusline-setup',\n whenToUse:\n 'Agent for configuring the Minto CLI status line. Use this when the user wants to customize what information appears in the bottom status bar (model name, token count, costs, git branch, etc.).',\n tools: ['Read', 'Edit'],\n model_name: 'main',\n systemPrompt: `You are a status line configuration agent for Minto CLI.\n\nYour role:\n- Help users configure the status line (bottom bar) display\n- Modify status line settings to show/hide specific information segments\n- Adjust the layout and formatting of the status line\n\nGuidelines:\n- Read existing status line configuration first\n- The status line is rendered by Ink components in src/screens/\n- Make minimal changes to configuration values\n- Preserve existing formatting patterns`,\n location: 'built-in',\n },\n\n // minto-guide: Agent for answering questions about Minto CLI features\n {\n agentType: 'minto-guide',\n whenToUse:\n 'Knowledge agent for answering questions about Minto CLI features, configuration, and usage. Use this when the user asks how to use a feature, what commands are available, or needs help understanding Minto capabilities.',\n tools: ['Glob', 'Grep', 'Read', 'WebFetch', 'WebSearch'],\n disallowedTools: ['Edit', 'Write', 'Bash', 'NotebookEdit'],\n model_name: 'quick',\n permissionMode: 'plan',\n systemPrompt: `You are a Minto CLI guide and knowledge agent.\n\nYour role:\n- Answer questions about Minto CLI features and capabilities\n- Explain how to configure models, agents, plugins, and hooks\n- Help users understand available commands and slash commands\n- Provide usage examples and best practices\n\nGuidelines:\n- Search the codebase to find accurate, up-to-date information\n- Check CLAUDE.md and MINTO.md files for project documentation\n- Look at src/commands/ for available commands\n- Look at src/tools/ for available tools\n- Look at src/utils/agentLoader.ts for agent configuration\n- Provide specific file paths and code references when helpful\n- Be concise but thorough in explanations\n\nYou are READ-ONLY. You cannot modify any files.`,\n location: 'built-in',\n },\n\n // Bash: Shell command execution agent (Claude Code spec)\n {\n agentType: 'Bash',\n whenToUse:\n 'Command execution specialist for running bash commands. Use this for git operations, command execution, and other terminal tasks.',\n tools: ['Bash', 'Read', 'LS'],\n systemPrompt: `You are a bash execution agent specialized in running shell commands.\n\nYour role:\n- Execute shell commands safely and effectively\n- Handle build, test, and deployment tasks\n- Manage git operations\n- Run scripts and automation\n\nGuidelines:\n- Check command syntax before execution\n- Handle errors gracefully with clear messages\n- Report command output and exit codes\n- Be cautious with destructive commands (rm, git reset, etc.)\n- Use appropriate flags for verbose output when debugging\n- Chain commands with && for dependent operations\n\nAlways explain what a command will do before running it if it modifies the system.`,\n location: 'built-in',\n },\n]\n\n/**\n * Parse tools field from frontmatter\n */\nfunction parseTools(tools: any): string[] | '*' {\n if (!tools) return '*'\n if (tools === '*') return '*'\n if (Array.isArray(tools)) {\n // Ensure all items are strings and filter out non-strings\n const filteredTools = tools.filter(\n (t): t is string => typeof t === 'string',\n )\n return filteredTools.length > 0 ? filteredTools : '*'\n }\n if (typeof tools === 'string') {\n // Handle comma-separated string: \"Read, Grep, Glob\"\n if (tools.includes(',')) {\n return tools\n .split(',')\n .map((t: string) => t.trim())\n .filter(Boolean)\n }\n return [tools]\n }\n return '*'\n}\n\n/**\n * Parse disallowedTools field from frontmatter\n */\nfunction parseDisallowedTools(disallowedTools: any): string[] | undefined {\n if (!disallowedTools) return undefined\n if (Array.isArray(disallowedTools)) {\n const filtered = disallowedTools.filter(\n (t): t is string => typeof t === 'string',\n )\n return filtered.length > 0 ? filtered : undefined\n }\n if (typeof disallowedTools === 'string') {\n // Handle comma-separated string\n if (disallowedTools.includes(',')) {\n return disallowedTools\n .split(',')\n .map((t: string) => t.trim())\n .filter(Boolean)\n }\n return [disallowedTools]\n }\n return undefined\n}\n\n/**\n * Parse skills field from frontmatter\n */\nfunction parseSkills(skills: any): string[] | undefined {\n if (!skills) return undefined\n if (Array.isArray(skills)) {\n const filtered = skills.filter((s): s is string => typeof s === 'string')\n return filtered.length > 0 ? filtered : undefined\n }\n if (typeof skills === 'string') {\n if (skills.includes(',')) {\n return skills\n .split(',')\n .map((s: string) => s.trim())\n .filter(Boolean)\n }\n return [skills]\n }\n return undefined\n}\n\n/**\n * Parse memory field from frontmatter\n */\nfunction parseMemory(memory: any): AgentMemory | undefined {\n if (!memory) return undefined\n if (typeof memory === 'string') {\n // Simple format: \"user\" | \"project\" | \"local\"\n if (['user', 'project', 'local'].includes(memory)) {\n return { scope: memory as AgentMemory['scope'] }\n }\n return undefined\n }\n if (typeof memory === 'object') {\n const scope = memory.scope\n if (['user', 'project', 'local'].includes(scope)) {\n return {\n scope: scope as AgentMemory['scope'],\n ...(memory.key && { key: String(memory.key) }),\n }\n }\n }\n return undefined\n}\n\n/**\n * Parse permissionMode field from frontmatter\n */\nfunction parsePermissionMode(mode: any): PermissionMode | undefined {\n if (!mode) return undefined\n const validModes: PermissionMode[] = [\n 'default',\n 'acceptEdits',\n 'dontAsk',\n 'plan',\n 'delegate',\n 'bypassPermissions',\n ]\n if (typeof mode === 'string' && validModes.includes(mode as PermissionMode)) {\n return mode as PermissionMode\n }\n return undefined\n}\n\n/**\n * Scan a directory for agent configuration files\n */\nasync function scanAgentDirectory(\n dirPath: string,\n location: 'user' | 'project',\n): Promise<AgentConfig[]> {\n if (!existsSync(dirPath)) {\n return []\n }\n\n const agents: AgentConfig[] = []\n\n try {\n const files = await readdir(dirPath)\n const mdFiles = files.filter(f => f.endsWith('.md'))\n\n // Read all .md files in parallel\n const fileResults = await Promise.all(\n mdFiles.map(async (file): Promise<AgentConfig | null> => {\n const filePath = join(dirPath, file)\n try {\n const fileStat = await stat(filePath)\n if (!fileStat.isFile()) return null\n\n const content = await readFile(filePath, 'utf-8')\n if (!content.trim()) return null // Skip empty files silently\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields \u2014 fallback to markdown heading/first paragraph\n // for CC-style agent files without YAML frontmatter\n if (!frontmatter.name || !frontmatter.description) {\n const headingMatch = body.match(/^#\\s+(.+)/m)\n const firstParagraph = body\n .split(/\\n\\n/)\n .find(p => p.trim() && !p.trim().startsWith('#'))\n if (headingMatch) {\n if (!frontmatter.name) {\n frontmatter.name = headingMatch[1].trim()\n }\n if (!frontmatter.description) {\n frontmatter.description =\n firstParagraph?.trim() || frontmatter.name\n }\n } else {\n debugLog.warn('AGENT_MISSING_FIELDS', {\n filePath,\n message: 'missing required fields (name, description)',\n })\n return null\n }\n }\n\n // Silently ignore deprecated 'model' field - no warnings by default\n // Only warn if MINTO_DEBUG_AGENTS environment variable is set\n if (\n frontmatter.model &&\n !frontmatter.model_name &&\n !warnedAgents.has(frontmatter.name) &&\n process.env.MINTO_DEBUG_AGENTS\n ) {\n debugLog.warn('AGENT_DEPRECATED_MODEL_FIELD', {\n agent: frontmatter.name,\n message:\n \"'model' field is deprecated and ignored. Use 'model_name' instead.\",\n })\n warnedAgents.add(frontmatter.name)\n }\n\n // Parse optional fields\n const disallowedTools = parseDisallowedTools(\n frontmatter.disallowedTools,\n )\n const skills = parseSkills(frontmatter.skills)\n const memory = parseMemory(frontmatter.memory)\n const permissionMode = parsePermissionMode(frontmatter.permissionMode)\n\n // Build agent config with all Claude Code spec fields\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location,\n sourcePath: filePath,\n // Optional fields - only include if defined\n ...(frontmatter.color && { color: frontmatter.color }),\n ...(frontmatter.model_name && {\n model_name: frontmatter.model_name,\n }),\n ...(disallowedTools && { disallowedTools }),\n ...(permissionMode && { permissionMode }),\n ...(skills && { skills }),\n ...(memory && { memory }),\n ...(frontmatter.maxThinkingTokens && {\n maxThinkingTokens: Number(frontmatter.maxThinkingTokens),\n }),\n ...(frontmatter.hooks && {\n hooks: frontmatter.hooks as AgentHooks,\n }),\n ...(frontmatter.isolation && { isolation: frontmatter.isolation }),\n ...(frontmatter.background && {\n background: frontmatter.background === true,\n }),\n ...(frontmatter.mcpServers && {\n mcpServers: frontmatter.mcpServers,\n }),\n ...(frontmatter.maxTurns && {\n maxTurns: Number(frontmatter.maxTurns),\n }),\n }\n\n // Security: Cap permission modes for project-scoped agents.\n // Only user-level agents (~/.minto/agents/) can use dontAsk or bypassPermissions.\n // Project agents are limited to 'acceptEdits' maximum to prevent\n // malicious repos from escalating permissions.\n // Note: Plugin agents are capped separately in loadPluginAgents().\n const MAX_PROJECT_PERM_LEVEL = 2 // 'acceptEdits'\n if (location === 'project' && agent.permissionMode) {\n const { PERMISSION_LEVELS } = await import(\n '../types/PermissionMode'\n )\n const currentLevel = PERMISSION_LEVELS[agent.permissionMode] ?? 1\n if (currentLevel > MAX_PROJECT_PERM_LEVEL) {\n if (!warnedAgents.has(agent.agentType + ':perm')) {\n debugLog.warn('AGENT_PERMISSION_CAPPED', {\n agent: agent.agentType,\n requested: agent.permissionMode,\n capped: 'acceptEdits',\n })\n warnedAgents.add(agent.agentType + ':perm')\n }\n agent.permissionMode = 'acceptEdits' as PermissionMode\n }\n }\n\n // Security: Strip mcpServers from project-scoped agents.\n // Only user-level agents (~/.minto/agents/) can define MCP servers.\n // Project agents could be from untrusted repos.\n if (location === 'project' && agent.mcpServers) {\n debugLog.warn('AGENT_MCPSERVERS_STRIPPED', {\n agent: agent.agentType,\n message:\n 'mcpServers from project agents are ignored for security. Move to ~/.minto/agents/ to enable.',\n })\n delete agent.mcpServers\n }\n\n return agent\n } catch (error) {\n debugLog.warn('AGENT_PARSE_FAILED', { filePath, error })\n return null\n }\n }),\n )\n\n // Filter out nulls and collect valid agents\n for (const agent of fileResults) {\n if (agent) agents.push(agent)\n }\n } catch (error) {\n debugLog.warn('AGENT_SCAN_FAILED', { dirPath, error })\n }\n\n return agents\n}\n\n/**\n * Load agents from installed plugins\n */\nasync function loadPluginAgents(): Promise<AgentConfig[]> {\n const agents: AgentConfig[] = []\n\n try {\n const plugins = loadAllPlugins()\n\n for (const plugin of plugins) {\n // Skip disabled plugins\n if (!plugin.enabled) continue\n\n for (const pluginAgent of plugin.agents) {\n try {\n // Read the agent file to parse frontmatter and content\n const content = readFileSync(pluginAgent.filePath, 'utf-8')\n if (!content.trim()) continue // Skip empty files silently\n const { data: frontmatter, content: body } = matter(content)\n\n // Validate required fields \u2014 fallback to markdown heading/first paragraph\n if (!frontmatter.name || !frontmatter.description) {\n const headingMatch = body.match(/^#\\s+(.+)/m)\n const firstParagraph = body\n .split(/\\n\\n/)\n .find(p => p.trim() && !p.trim().startsWith('#'))\n if (headingMatch) {\n if (!frontmatter.name) {\n frontmatter.name = headingMatch[1].trim()\n }\n if (!frontmatter.description) {\n frontmatter.description =\n firstParagraph?.trim() || frontmatter.name\n }\n } else {\n debugLog.warn('PLUGIN_AGENT_MISSING_FIELDS', {\n filePath: pluginAgent.filePath,\n message: 'missing required fields (name, description)',\n })\n continue\n }\n }\n\n // Warn about deprecated 'model' field if debug mode is enabled\n if (\n frontmatter.model &&\n !frontmatter.model_name &&\n !warnedAgents.has(frontmatter.name) &&\n process.env.MINTO_DEBUG_AGENTS\n ) {\n debugLog.warn('PLUGIN_AGENT_DEPRECATED_MODEL_FIELD', {\n agent: frontmatter.name,\n plugin: plugin.manifest.name,\n message:\n \"'model' field is deprecated and ignored. Use 'model_name' instead.\",\n })\n warnedAgents.add(frontmatter.name)\n }\n\n // Parse optional fields\n const disallowedTools = parseDisallowedTools(\n frontmatter.disallowedTools,\n )\n const skills = parseSkills(frontmatter.skills)\n const memory = parseMemory(frontmatter.memory)\n const permissionMode = parsePermissionMode(frontmatter.permissionMode)\n\n // Build agent config with all Claude Code spec fields\n const agent: AgentConfig = {\n agentType: frontmatter.name,\n whenToUse: frontmatter.description.replace(/\\\\n/g, '\\n'),\n tools: parseTools(frontmatter.tools),\n systemPrompt: body.trim(),\n location: 'plugin',\n pluginName: plugin.manifest.name,\n sourcePath: pluginAgent.filePath,\n // Optional fields\n ...(frontmatter.color && { color: frontmatter.color }),\n ...(frontmatter.model_name && {\n model_name: frontmatter.model_name,\n }),\n ...(disallowedTools && { disallowedTools }),\n ...(permissionMode && { permissionMode }),\n ...(skills && { skills }),\n ...(memory && { memory }),\n ...(frontmatter.maxThinkingTokens && {\n maxThinkingTokens: Number(frontmatter.maxThinkingTokens),\n }),\n ...(frontmatter.hooks && {\n hooks: frontmatter.hooks as AgentHooks,\n }),\n ...(frontmatter.isolation && { isolation: frontmatter.isolation }),\n ...(frontmatter.background && {\n background: frontmatter.background === true,\n }),\n ...(frontmatter.mcpServers && {\n mcpServers: frontmatter.mcpServers,\n }),\n }\n\n // Security: Cap permission modes for plugin agents (same as project agents).\n // Only user-level agents (~/.minto/agents/) can use dontAsk or bypassPermissions.\n const MAX_PLUGIN_PERM_LEVEL = 2 // 'acceptEdits'\n if (agent.permissionMode) {\n const { PERMISSION_LEVELS } = await import(\n '../types/PermissionMode'\n )\n const currentLevel = PERMISSION_LEVELS[agent.permissionMode] ?? 1\n if (currentLevel > MAX_PLUGIN_PERM_LEVEL) {\n if (!warnedAgents.has(agent.agentType + ':perm')) {\n debugLog.warn('PLUGIN_AGENT_PERMISSION_CAPPED', {\n agent: agent.agentType,\n plugin: plugin.manifest.name,\n requested: agent.permissionMode,\n capped: 'acceptEdits',\n })\n warnedAgents.add(agent.agentType + ':perm')\n }\n agent.permissionMode = 'acceptEdits' as PermissionMode\n }\n }\n\n // Security: Strip mcpServers from plugin agents.\n // Only user-level agents (~/.minto/agents/) can define MCP servers.\n // Plugin agents could be from untrusted sources.\n if (agent.mcpServers) {\n debugLog.warn('AGENT_MCPSERVERS_STRIPPED', {\n agent: agent.agentType,\n message:\n 'mcpServers from plugin agents are ignored for security. Move to ~/.minto/agents/ to enable.',\n })\n delete agent.mcpServers\n }\n\n agents.push(agent)\n } catch (error) {\n debugLog.warn('PLUGIN_AGENT_LOAD_FAILED', {\n agent: pluginAgent.name,\n plugin: plugin.manifest.name,\n error,\n })\n }\n }\n }\n } catch (error) {\n debugLog.warn('PLUGIN_AGENTS_LOAD_FAILED', { error })\n }\n\n return agents\n}\n\n/**\n * Load all agent configurations\n *\n * Directory Priority (later overrides earlier):\n * 1. Built-in agents (general-purpose, Explore, Plan, Bash)\n * 2. Plugin agents\n * 3. ~/.minto/agents (Minto user directory)\n * 4. ./.minto/agents (Minto project directory - highest priority)\n */\nasync function loadAllAgents(): Promise<{\n activeAgents: AgentConfig[]\n allAgents: AgentConfig[]\n}> {\n try {\n const home = homedir()\n const cwd = getCwd()\n\n // Define directories in priority order (later overrides earlier)\n // .claude/ dirs are legacy fallbacks, .minto/ dirs take precedence\n const userClaudeDir = join(home, '.claude', 'agents')\n const userMintoDir = join(home, '.minto', 'agents')\n const projectClaudeDir = join(cwd, '.claude', 'agents')\n const projectMintoDir = join(cwd, '.minto', 'agents')\n\n // Load from all sources in parallel\n const [\n pluginAgents,\n userClaudeAgents,\n userMintoAgents,\n projectClaudeAgents,\n projectMintoAgents,\n ] = await Promise.all([\n loadPluginAgents(),\n scanAgentDirectory(userClaudeDir, 'user'),\n scanAgentDirectory(userMintoDir, 'user'),\n scanAgentDirectory(projectClaudeDir, 'project'),\n scanAgentDirectory(projectMintoDir, 'project'),\n ])\n\n // Apply priority override: built-in < plugin < user/.claude < user/.minto < project/.claude < project/.minto\n // Later entries override earlier ones with the same agentType\n // Plugin agents are namespaced as \"pluginName:agentType\"\n const agentMap = new Map<string, AgentConfig>()\n\n // Add in priority order (later entries override earlier ones)\n for (const agent of BUILTIN_AGENTS) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of pluginAgents) {\n // Namespace plugin agents as \"pluginName:agentType\"\n const namespacedType = agent.pluginName\n ? `${agent.pluginName}:${agent.agentType}`\n : agent.agentType\n agentMap.set(namespacedType, { ...agent, agentType: namespacedType })\n }\n for (const agent of userClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of userMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectClaudeAgents) {\n agentMap.set(agent.agentType, agent)\n }\n for (const agent of projectMintoAgents) {\n agentMap.set(agent.agentType, agent)\n }\n\n const activeAgents = Array.from(agentMap.values())\n const allAgents = [\n ...BUILTIN_AGENTS,\n ...pluginAgents,\n ...userClaudeAgents,\n ...userMintoAgents,\n ...projectClaudeAgents,\n ...projectMintoAgents,\n ]\n\n return { activeAgents, allAgents }\n } catch (error) {\n console.error('Failed to load agents, falling back to built-in:', error)\n return {\n activeAgents: [...BUILTIN_AGENTS],\n allAgents: [...BUILTIN_AGENTS],\n }\n }\n}\n\n// Memoized version for performance\nexport const getActiveAgents = memoize(async (): Promise<AgentConfig[]> => {\n const { activeAgents } = await loadAllAgents()\n return activeAgents\n})\n\n// Get all agents (both active and overridden)\nexport const getAllAgents = memoize(async (): Promise<AgentConfig[]> => {\n const { allAgents } = await loadAllAgents()\n return allAgents\n})\n\n// LRU cache for getAgentByType \u2014 unbounded agentType strings could leak with lodash memoize\nconst _agentByTypeCache = new LRUCache<string, AgentConfig | undefined>({\n max: 64,\n ttl: 5 * 60 * 1000, // 5 min TTL\n ttlAutopurge: false,\n})\n\n// Clear cache when needed\nexport function clearAgentCache() {\n getActiveAgents.cache?.clear?.()\n getAllAgents.cache?.clear?.()\n _agentByTypeCache.clear()\n getAvailableAgentTypes.cache?.clear?.()\n}\n\n// Get a specific agent by type\n// Supports both namespaced (\"plugin:agent\") and bare (\"agent\") lookups.\n// Bare names match non-plugin agents first; if not found, searches plugin agents by component name.\nexport async function getAgentByType(\n agentType: string,\n): Promise<AgentConfig | undefined> {\n const cached = _agentByTypeCache.get(agentType)\n if (cached !== undefined) return cached\n\n // Check for explicit undefined sentinel (we stored undefined for a miss)\n if (_agentByTypeCache.has(agentType)) return undefined\n\n const agents = await getActiveAgents()\n\n // Direct match (exact agentType including namespace)\n const direct = agents.find(agent => agent.agentType === agentType)\n if (direct) {\n _agentByTypeCache.set(agentType, direct)\n return direct\n }\n\n // If no colon in name, try to find among plugin agents by bare component name\n if (!agentType.includes(':')) {\n for (const agent of agents) {\n if (\n agent.agentType.includes(':') &&\n agent.agentType.split(':').pop() === agentType\n ) {\n _agentByTypeCache.set(agentType, agent)\n return agent\n }\n }\n }\n\n _agentByTypeCache.set(agentType, undefined)\n return undefined\n}\n\n// Get all available agent types for validation\nexport const getAvailableAgentTypes = memoize(async (): Promise<string[]> => {\n const agents = await getActiveAgents()\n return agents.map(agent => agent.agentType)\n})\n\n// File watcher for hot reload\nlet watchers: FSWatcher[] = []\n\n/**\n * Start watching agent configuration directories for changes\n */\nexport async function startAgentWatcher(onChange?: () => void): Promise<void> {\n await stopAgentWatcher() // Clean up any existing watchers\n\n const home = homedir()\n const cwd = getCwd()\n\n // Watch .minto and .claude (legacy) directories\n const directories = [\n { path: join(home, '.claude', 'agents'), label: 'user/.claude' },\n { path: join(home, '.minto', 'agents'), label: 'user/.minto' },\n { path: join(cwd, '.claude', 'agents'), label: 'project/.claude' },\n { path: join(cwd, '.minto', 'agents'), label: 'project/.minto' },\n ]\n\n const watchDirectory = (dirPath: string, label: string) => {\n if (existsSync(dirPath)) {\n const watcher = watch(\n dirPath,\n { recursive: false },\n async (eventType, filename) => {\n if (filename && filename.endsWith('.md')) {\n console.log(\n `\uD83D\uDD04 Agent configuration changed in ${label}: ${filename}`,\n )\n clearAgentCache()\n // Also clear any other related caches\n getAllAgents.cache?.clear?.()\n onChange?.()\n }\n },\n )\n watchers.push(watcher)\n }\n }\n\n // Watch all directories\n for (const { path, label } of directories) {\n watchDirectory(path, label)\n }\n}\n\n/**\n * Stop watching agent configuration directories\n */\nexport async function stopAgentWatcher(): Promise<void> {\n // FSWatcher.close() is synchronous and does not accept a callback on Node 18/20\n try {\n for (const watcher of watchers) {\n try {\n watcher.close()\n } catch (err) {\n console.error('Failed to close file watcher:', err)\n }\n }\n } finally {\n watchers = []\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,10 +4,17 @@ class AnimationManager {
|
|
|
4
4
|
rafId = null;
|
|
5
5
|
lastFrameTime = 0;
|
|
6
6
|
isRunning = false;
|
|
7
|
+
resumeCallbacks = /* @__PURE__ */ new Set();
|
|
7
8
|
// Use 30fps as base rate to reduce terminal render load
|
|
8
9
|
// Terminal rendering is expensive, unlike browser canvas rendering
|
|
9
10
|
FRAME_INTERVAL = 33;
|
|
10
11
|
// ~30fps (was 16ms/60fps)
|
|
12
|
+
// If tick gap exceeds this threshold, the process was likely backgrounded
|
|
13
|
+
// (tab switch, app nap, system sleep). Skip animation and notify listeners
|
|
14
|
+
// to do a full re-render, preventing ghost artifacts from Ink's differential
|
|
15
|
+
// rendering getting out of sync while the terminal was invisible.
|
|
16
|
+
BACKGROUND_THRESHOLD = 2e3;
|
|
17
|
+
// 2 seconds
|
|
11
18
|
constructor() {
|
|
12
19
|
}
|
|
13
20
|
static getInstance() {
|
|
@@ -44,6 +51,16 @@ class AnimationManager {
|
|
|
44
51
|
this.stop();
|
|
45
52
|
}
|
|
46
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Register a callback for when the process resumes from background.
|
|
56
|
+
* Fires when a tick gap exceeds BACKGROUND_THRESHOLD, indicating the
|
|
57
|
+
* terminal was likely inactive (tab switch, app nap, system sleep).
|
|
58
|
+
* @returns Unsubscribe function
|
|
59
|
+
*/
|
|
60
|
+
onResume(callback) {
|
|
61
|
+
this.resumeCallbacks.add(callback);
|
|
62
|
+
return () => this.resumeCallbacks.delete(callback);
|
|
63
|
+
}
|
|
47
64
|
/**
|
|
48
65
|
* Start the animation loop
|
|
49
66
|
*/
|
|
@@ -72,6 +89,16 @@ class AnimationManager {
|
|
|
72
89
|
const now = Date.now();
|
|
73
90
|
const deltaTime = now - this.lastFrameTime;
|
|
74
91
|
this.lastFrameTime = now;
|
|
92
|
+
if (deltaTime > this.BACKGROUND_THRESHOLD && this.resumeCallbacks.size > 0) {
|
|
93
|
+
for (const cb of this.resumeCallbacks) {
|
|
94
|
+
try {
|
|
95
|
+
cb();
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
this.rafId = setTimeout(this.tick, this.FRAME_INTERVAL);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
75
102
|
const callbacksToRun = [];
|
|
76
103
|
for (const sub of this.subscriptions.values()) {
|
|
77
104
|
const timeSinceLastUpdate = now - sub.lastUpdate;
|
|
@@ -114,18 +141,21 @@ function useUnifiedAnimation({
|
|
|
114
141
|
const [animState, setAnimState] = useState(() => ({
|
|
115
142
|
spinnerFrame: 0,
|
|
116
143
|
dotVisible: true,
|
|
117
|
-
elapsedTime: Math.floor((Date.now() - startTime) / 1e3)
|
|
144
|
+
elapsedTime: Math.floor((Date.now() - startTime) / 1e3),
|
|
145
|
+
dataTick: 0
|
|
118
146
|
}));
|
|
119
147
|
const startTimeRef = useRef(startTime);
|
|
120
148
|
startTimeRef.current = startTime;
|
|
121
149
|
const timingRef = useRef({
|
|
122
150
|
lastSpinnerUpdate: 0,
|
|
123
151
|
lastDotUpdate: 0,
|
|
124
|
-
lastElapsedUpdate: 0
|
|
152
|
+
lastElapsedUpdate: 0,
|
|
153
|
+
lastDataTickUpdate: 0
|
|
125
154
|
});
|
|
126
155
|
const SPINNER_INTERVAL = 200;
|
|
127
156
|
const DOT_INTERVAL = 800;
|
|
128
157
|
const ELAPSED_INTERVAL = 1e3;
|
|
158
|
+
const DATA_TICK_INTERVAL = 100;
|
|
129
159
|
useEffect(() => {
|
|
130
160
|
if (!enabled) {
|
|
131
161
|
return void 0;
|
|
@@ -141,6 +171,7 @@ function useUnifiedAnimation({
|
|
|
141
171
|
let newSpinnerFrame = prevState.spinnerFrame;
|
|
142
172
|
let newDotVisible = prevState.dotVisible;
|
|
143
173
|
let newElapsedTime = prevState.elapsedTime;
|
|
174
|
+
let newDataTick = prevState.dataTick;
|
|
144
175
|
if (now - timing.lastSpinnerUpdate >= SPINNER_INTERVAL) {
|
|
145
176
|
timing.lastSpinnerUpdate = now;
|
|
146
177
|
newSpinnerFrame = (newSpinnerFrame + 1) % spinnerFrameCount;
|
|
@@ -156,13 +187,19 @@ function useUnifiedAnimation({
|
|
|
156
187
|
newElapsedTime = Math.floor((now - startTimeRef.current) / 1e3);
|
|
157
188
|
needsUpdate = true;
|
|
158
189
|
}
|
|
190
|
+
if (now - timing.lastDataTickUpdate >= DATA_TICK_INTERVAL) {
|
|
191
|
+
timing.lastDataTickUpdate = now;
|
|
192
|
+
newDataTick = newDataTick + 1;
|
|
193
|
+
needsUpdate = true;
|
|
194
|
+
}
|
|
159
195
|
if (!needsUpdate) {
|
|
160
196
|
return prevState;
|
|
161
197
|
}
|
|
162
198
|
return {
|
|
163
199
|
spinnerFrame: newSpinnerFrame,
|
|
164
200
|
dotVisible: newDotVisible,
|
|
165
|
-
elapsedTime: newElapsedTime
|
|
201
|
+
elapsedTime: newElapsedTime,
|
|
202
|
+
dataTick: newDataTick
|
|
166
203
|
};
|
|
167
204
|
});
|
|
168
205
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/animationManager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Unified Animation Manager\n *\n * Consolidates multiple animation timers into a single requestAnimationFrame loop\n * to prevent render thrashing and screen flickering.\n *\n * Benefits:\n * - Single animation frame callback instead of multiple setInterval timers\n * - Batched state updates reduce React re-renders\n * - Configurable frame rates for different animation types\n * - Automatic cleanup on unmount\n */\n\ntype AnimationCallback = (deltaTime: number) => void\n\ninterface AnimationSubscription {\n id: string\n callback: AnimationCallback\n interval: number // Minimum interval between updates in ms\n lastUpdate: number\n}\n\nclass AnimationManager {\n private static instance: AnimationManager\n private subscriptions: Map<string, AnimationSubscription> = new Map()\n private rafId: ReturnType<typeof setTimeout> | null = null\n private lastFrameTime: number = 0\n private isRunning: boolean = false\n\n // Use 30fps as base rate to reduce terminal render load\n // Terminal rendering is expensive, unlike browser canvas rendering\n private readonly FRAME_INTERVAL = 33 // ~30fps (was 16ms/60fps)\n\n private constructor() {}\n\n static getInstance(): AnimationManager {\n if (!AnimationManager.instance) {\n AnimationManager.instance = new AnimationManager()\n }\n return AnimationManager.instance\n }\n\n /**\n * Subscribe to animation updates\n * @param id Unique identifier for this subscription\n * @param callback Function to call on each animation frame\n * @param interval Minimum interval between callback invocations (ms)\n * @returns Unsubscribe function\n */\n subscribe(\n id: string,\n callback: AnimationCallback,\n interval: number,\n ): () => void {\n this.subscriptions.set(id, {\n id,\n callback,\n interval,\n lastUpdate: 0,\n })\n\n if (!this.isRunning) {\n this.start()\n }\n\n return () => this.unsubscribe(id)\n }\n\n /**\n * Unsubscribe from animation updates\n */\n unsubscribe(id: string): void {\n this.subscriptions.delete(id)\n\n if (this.subscriptions.size === 0) {\n this.stop()\n }\n }\n\n /**\n * Start the animation loop\n */\n private start(): void {\n if (this.isRunning) return\n\n this.isRunning = true\n this.lastFrameTime = Date.now()\n this.tick()\n }\n\n /**\n * Stop the animation loop\n */\n private stop(): void {\n if (!this.isRunning) return\n\n this.isRunning = false\n if (this.rafId !== null) {\n clearTimeout(this.rafId)\n this.rafId = null\n }\n }\n\n /**\n * Main animation tick\n */\n private tick = (): void => {\n if (!this.isRunning) return\n\n const now = Date.now()\n const deltaTime = now - this.lastFrameTime\n this.lastFrameTime = now\n\n // Batch all callbacks that need to run this frame\n const callbacksToRun: AnimationCallback[] = []\n\n for (const sub of this.subscriptions.values()) {\n const timeSinceLastUpdate = now - sub.lastUpdate\n\n if (timeSinceLastUpdate >= sub.interval) {\n sub.lastUpdate = now\n callbacksToRun.push(sub.callback)\n }\n }\n\n // Execute all callbacks in a single batch\n // This allows React to batch the state updates\n if (callbacksToRun.length > 0) {\n for (const callback of callbacksToRun) {\n try {\n callback(deltaTime)\n } catch (error) {\n // Silently ignore callback errors to prevent animation loop from breaking\n }\n }\n }\n\n // Schedule next frame using setTimeout (works in Node.js/Bun)\n this.rafId = setTimeout(this.tick, this.FRAME_INTERVAL)\n }\n\n /**\n * Get the number of active subscriptions\n */\n getSubscriptionCount(): number {\n return this.subscriptions.size\n }\n\n /**\n * Check if animation loop is running\n */\n isAnimating(): boolean {\n return this.isRunning\n }\n}\n\n// Export singleton instance\nexport const animationManager = AnimationManager.getInstance()\n\n/**\n * React hook for unified animation updates\n *\n * Usage:\n * ```typescript\n * const { spinnerFrame, dotVisible, elapsedTime } = useUnifiedAnimation({\n * enabled: hasRunningTasks,\n * startTime: Date.now(),\n * spinnerFrameCount: 12,\n * })\n * ```\n */\nexport interface UnifiedAnimationState {\n spinnerFrame: number\n dotVisible: boolean\n elapsedTime: number\n}\n\nexport interface UseUnifiedAnimationOptions {\n enabled: boolean\n startTime: number\n spinnerFrameCount: number\n componentId: string\n}\n\nimport { useState, useEffect, useRef, useCallback } from 'react'\n\nexport function useUnifiedAnimation({\n enabled,\n startTime,\n spinnerFrameCount,\n componentId,\n}: UseUnifiedAnimationOptions): UnifiedAnimationState {\n // Use a single state object to batch updates\n const [animState, setAnimState] = useState<UnifiedAnimationState>(() => ({\n spinnerFrame: 0,\n dotVisible: true,\n elapsedTime: Math.floor((Date.now() - startTime) / 1000),\n }))\n\n // Store startTime in ref to avoid closure issues\n const startTimeRef = useRef(startTime)\n startTimeRef.current = startTime\n\n // Track timing internally to reduce state updates\n const timingRef = useRef({\n lastSpinnerUpdate: 0,\n lastDotUpdate: 0,\n lastElapsedUpdate: 0,\n })\n\n // Animation intervals - optimized for less flicker\n // Slower spinner reduces terminal re-render frequency\n const SPINNER_INTERVAL = 200 // 200ms (was 120ms) - reduces flicker by ~40%\n const DOT_INTERVAL = 800 // 800ms (was 600ms) - less visual noise\n const ELAPSED_INTERVAL = 1000 // 1s - unchanged\n\n useEffect(() => {\n if (!enabled) {\n return undefined\n }\n\n const uniqueId = `${componentId}-unified-animation`\n\n const unsubscribe = animationManager.subscribe(\n uniqueId,\n () => {\n const now = Date.now()\n const timing = timingRef.current\n\n // Use functional state update to avoid closure issues\n setAnimState(prevState => {\n let needsUpdate = false\n let newSpinnerFrame = prevState.spinnerFrame\n let newDotVisible = prevState.dotVisible\n let newElapsedTime = prevState.elapsedTime\n\n // Check spinner update\n if (now - timing.lastSpinnerUpdate >= SPINNER_INTERVAL) {\n timing.lastSpinnerUpdate = now\n newSpinnerFrame = (newSpinnerFrame + 1) % spinnerFrameCount\n needsUpdate = true\n }\n\n // Check dot update\n if (now - timing.lastDotUpdate >= DOT_INTERVAL) {\n timing.lastDotUpdate = now\n newDotVisible = !newDotVisible\n needsUpdate = true\n }\n\n // Check elapsed time update\n if (now - timing.lastElapsedUpdate >= ELAPSED_INTERVAL) {\n timing.lastElapsedUpdate = now\n newElapsedTime = Math.floor((now - startTimeRef.current) / 1000)\n needsUpdate = true\n }\n\n // Return same object if no update needed (prevents unnecessary re-render)\n if (!needsUpdate) {\n return prevState\n }\n\n return {\n spinnerFrame: newSpinnerFrame,\n dotVisible: newDotVisible,\n elapsedTime: newElapsedTime,\n }\n })\n },\n // Use fastest needed interval for checking\n Math.min(SPINNER_INTERVAL, DOT_INTERVAL, ELAPSED_INTERVAL),\n )\n\n return unsubscribe\n }, [enabled, spinnerFrameCount, componentId])\n\n return animState\n}\n\n/**\n * Throttle utility for event handlers\n */\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number,\n): (...args: Parameters<T>) => void {\n let inThrottle = false\n let lastArgs: Parameters<T> | null = null\n\n return function (this: any, ...args: Parameters<T>) {\n if (!inThrottle) {\n func.apply(this, args)\n inThrottle = true\n setTimeout(() => {\n inThrottle = false\n if (lastArgs) {\n func.apply(this, lastArgs)\n lastArgs = null\n }\n }, limit)\n } else {\n lastArgs = args\n }\n }\n}\n\n/**\n * Debounce utility for event handlers\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number,\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n return function (this: any, ...args: Parameters<T>) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId)\n }\n timeoutId = setTimeout(() => {\n func.apply(this, args)\n timeoutId = null\n }, wait)\n }\n}\n"],
|
|
5
|
-
"mappings": "AAsBA,MAAM,iBAAiB;AAAA,EACrB,OAAe;AAAA,EACP,gBAAoD,oBAAI,IAAI;AAAA,EAC5D,QAA8C;AAAA,EAC9C,gBAAwB;AAAA,EACxB,YAAqB;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["/**\n * Unified Animation Manager\n *\n * Consolidates multiple animation timers into a single requestAnimationFrame loop\n * to prevent render thrashing and screen flickering.\n *\n * Benefits:\n * - Single animation frame callback instead of multiple setInterval timers\n * - Batched state updates reduce React re-renders\n * - Configurable frame rates for different animation types\n * - Automatic cleanup on unmount\n */\n\ntype AnimationCallback = (deltaTime: number) => void\n\ninterface AnimationSubscription {\n id: string\n callback: AnimationCallback\n interval: number // Minimum interval between updates in ms\n lastUpdate: number\n}\n\nclass AnimationManager {\n private static instance: AnimationManager\n private subscriptions: Map<string, AnimationSubscription> = new Map()\n private rafId: ReturnType<typeof setTimeout> | null = null\n private lastFrameTime: number = 0\n private isRunning: boolean = false\n private resumeCallbacks: Set<() => void> = new Set()\n\n // Use 30fps as base rate to reduce terminal render load\n // Terminal rendering is expensive, unlike browser canvas rendering\n private readonly FRAME_INTERVAL = 33 // ~30fps (was 16ms/60fps)\n\n // If tick gap exceeds this threshold, the process was likely backgrounded\n // (tab switch, app nap, system sleep). Skip animation and notify listeners\n // to do a full re-render, preventing ghost artifacts from Ink's differential\n // rendering getting out of sync while the terminal was invisible.\n private readonly BACKGROUND_THRESHOLD = 2000 // 2 seconds\n\n private constructor() {}\n\n static getInstance(): AnimationManager {\n if (!AnimationManager.instance) {\n AnimationManager.instance = new AnimationManager()\n }\n return AnimationManager.instance\n }\n\n /**\n * Subscribe to animation updates\n * @param id Unique identifier for this subscription\n * @param callback Function to call on each animation frame\n * @param interval Minimum interval between callback invocations (ms)\n * @returns Unsubscribe function\n */\n subscribe(\n id: string,\n callback: AnimationCallback,\n interval: number,\n ): () => void {\n this.subscriptions.set(id, {\n id,\n callback,\n interval,\n lastUpdate: 0,\n })\n\n if (!this.isRunning) {\n this.start()\n }\n\n return () => this.unsubscribe(id)\n }\n\n /**\n * Unsubscribe from animation updates\n */\n unsubscribe(id: string): void {\n this.subscriptions.delete(id)\n\n if (this.subscriptions.size === 0) {\n this.stop()\n }\n }\n\n /**\n * Register a callback for when the process resumes from background.\n * Fires when a tick gap exceeds BACKGROUND_THRESHOLD, indicating the\n * terminal was likely inactive (tab switch, app nap, system sleep).\n * @returns Unsubscribe function\n */\n onResume(callback: () => void): () => void {\n this.resumeCallbacks.add(callback)\n return () => this.resumeCallbacks.delete(callback)\n }\n\n /**\n * Start the animation loop\n */\n private start(): void {\n if (this.isRunning) return\n\n this.isRunning = true\n this.lastFrameTime = Date.now()\n this.tick()\n }\n\n /**\n * Stop the animation loop\n */\n private stop(): void {\n if (!this.isRunning) return\n\n this.isRunning = false\n if (this.rafId !== null) {\n clearTimeout(this.rafId)\n this.rafId = null\n }\n }\n\n /**\n * Main animation tick\n */\n private tick = (): void => {\n if (!this.isRunning) return\n\n const now = Date.now()\n const deltaTime = now - this.lastFrameTime\n this.lastFrameTime = now\n\n // Detect resume from background: if tick gap is abnormally large,\n // the process was likely backgrounded (tab switch, app nap, etc.).\n // Skip this animation frame to avoid burst renders, and notify\n // listeners so they can do a full screen clear + re-render.\n if (\n deltaTime > this.BACKGROUND_THRESHOLD &&\n this.resumeCallbacks.size > 0\n ) {\n for (const cb of this.resumeCallbacks) {\n try {\n cb()\n } catch {\n // Silently ignore callback errors\n }\n }\n this.rafId = setTimeout(this.tick, this.FRAME_INTERVAL)\n return\n }\n\n // Batch all callbacks that need to run this frame\n const callbacksToRun: AnimationCallback[] = []\n\n for (const sub of this.subscriptions.values()) {\n const timeSinceLastUpdate = now - sub.lastUpdate\n\n if (timeSinceLastUpdate >= sub.interval) {\n sub.lastUpdate = now\n callbacksToRun.push(sub.callback)\n }\n }\n\n // Execute all callbacks in a single batch\n // This allows React to batch the state updates\n if (callbacksToRun.length > 0) {\n for (const callback of callbacksToRun) {\n try {\n callback(deltaTime)\n } catch (error) {\n // Silently ignore callback errors to prevent animation loop from breaking\n }\n }\n }\n\n // Schedule next frame using setTimeout (works in Node.js/Bun)\n this.rafId = setTimeout(this.tick, this.FRAME_INTERVAL)\n }\n\n /**\n * Get the number of active subscriptions\n */\n getSubscriptionCount(): number {\n return this.subscriptions.size\n }\n\n /**\n * Check if animation loop is running\n */\n isAnimating(): boolean {\n return this.isRunning\n }\n}\n\n// Export singleton instance\nexport const animationManager = AnimationManager.getInstance()\n\n/**\n * React hook for unified animation updates\n *\n * Usage:\n * ```typescript\n * const { spinnerFrame, dotVisible, elapsedTime } = useUnifiedAnimation({\n * enabled: hasRunningTasks,\n * startTime: Date.now(),\n * spinnerFrameCount: 12,\n * })\n * ```\n */\nexport interface UnifiedAnimationState {\n spinnerFrame: number\n dotVisible: boolean\n elapsedTime: number\n dataTick: number // 100ms tick for streaming data refresh\n}\n\nexport interface UseUnifiedAnimationOptions {\n enabled: boolean\n startTime: number\n spinnerFrameCount: number\n componentId: string\n}\n\nimport { useState, useEffect, useRef, useCallback } from 'react'\n\nexport function useUnifiedAnimation({\n enabled,\n startTime,\n spinnerFrameCount,\n componentId,\n}: UseUnifiedAnimationOptions): UnifiedAnimationState {\n // Use a single state object to batch updates\n const [animState, setAnimState] = useState<UnifiedAnimationState>(() => ({\n spinnerFrame: 0,\n dotVisible: true,\n elapsedTime: Math.floor((Date.now() - startTime) / 1000),\n dataTick: 0,\n }))\n\n // Store startTime in ref to avoid closure issues\n const startTimeRef = useRef(startTime)\n startTimeRef.current = startTime\n\n // Track timing internally to reduce state updates\n const timingRef = useRef({\n lastSpinnerUpdate: 0,\n lastDotUpdate: 0,\n lastElapsedUpdate: 0,\n lastDataTickUpdate: 0,\n })\n\n // Animation intervals - optimized for less flicker\n // Slower spinner reduces terminal re-render frequency\n const SPINNER_INTERVAL = 200 // 200ms (was 120ms) - reduces flicker by ~40%\n const DOT_INTERVAL = 800 // 800ms (was 600ms) - less visual noise\n const ELAPSED_INTERVAL = 1000 // 1s - unchanged\n const DATA_TICK_INTERVAL = 100 // 100ms - streaming data refresh (10 FPS)\n\n useEffect(() => {\n if (!enabled) {\n return undefined\n }\n\n const uniqueId = `${componentId}-unified-animation`\n\n const unsubscribe = animationManager.subscribe(\n uniqueId,\n () => {\n const now = Date.now()\n const timing = timingRef.current\n\n // Use functional state update to avoid closure issues\n setAnimState(prevState => {\n let needsUpdate = false\n let newSpinnerFrame = prevState.spinnerFrame\n let newDotVisible = prevState.dotVisible\n let newElapsedTime = prevState.elapsedTime\n let newDataTick = prevState.dataTick\n\n // Check spinner update\n if (now - timing.lastSpinnerUpdate >= SPINNER_INTERVAL) {\n timing.lastSpinnerUpdate = now\n newSpinnerFrame = (newSpinnerFrame + 1) % spinnerFrameCount\n needsUpdate = true\n }\n\n // Check dot update\n if (now - timing.lastDotUpdate >= DOT_INTERVAL) {\n timing.lastDotUpdate = now\n newDotVisible = !newDotVisible\n needsUpdate = true\n }\n\n // Check elapsed time update\n if (now - timing.lastElapsedUpdate >= ELAPSED_INTERVAL) {\n timing.lastElapsedUpdate = now\n newElapsedTime = Math.floor((now - startTimeRef.current) / 1000)\n needsUpdate = true\n }\n\n // Check data tick update (100ms \u2014 for streaming data refresh)\n if (now - timing.lastDataTickUpdate >= DATA_TICK_INTERVAL) {\n timing.lastDataTickUpdate = now\n newDataTick = newDataTick + 1\n needsUpdate = true\n }\n\n // Return same object if no update needed (prevents unnecessary re-render)\n if (!needsUpdate) {\n return prevState\n }\n\n return {\n spinnerFrame: newSpinnerFrame,\n dotVisible: newDotVisible,\n elapsedTime: newElapsedTime,\n dataTick: newDataTick,\n }\n })\n },\n // Use fastest needed interval for checking\n Math.min(SPINNER_INTERVAL, DOT_INTERVAL, ELAPSED_INTERVAL),\n )\n\n return unsubscribe\n }, [enabled, spinnerFrameCount, componentId])\n\n return animState\n}\n\n/**\n * Throttle utility for event handlers\n */\nexport function throttle<T extends (...args: any[]) => any>(\n func: T,\n limit: number,\n): (...args: Parameters<T>) => void {\n let inThrottle = false\n let lastArgs: Parameters<T> | null = null\n\n return function (this: any, ...args: Parameters<T>) {\n if (!inThrottle) {\n func.apply(this, args)\n inThrottle = true\n setTimeout(() => {\n inThrottle = false\n if (lastArgs) {\n func.apply(this, lastArgs)\n lastArgs = null\n }\n }, limit)\n } else {\n lastArgs = args\n }\n }\n}\n\n/**\n * Debounce utility for event handlers\n */\nexport function debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number,\n): (...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n\n return function (this: any, ...args: Parameters<T>) {\n if (timeoutId !== null) {\n clearTimeout(timeoutId)\n }\n timeoutId = setTimeout(() => {\n func.apply(this, args)\n timeoutId = null\n }, wait)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/utils/ask.js
CHANGED
|
@@ -56,19 +56,20 @@ async function ask({
|
|
|
56
56
|
if (!result || result.type !== "assistant") {
|
|
57
57
|
throw new Error("Expected content to be an assistant message");
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
const textBlock = result.message.content.find(
|
|
60
|
+
(block) => block.type === "text"
|
|
61
|
+
);
|
|
62
|
+
if (!textBlock || textBlock.type !== "text") {
|
|
60
63
|
throw new Error(
|
|
61
|
-
`Expected
|
|
62
|
-
result.message.content
|
|
63
|
-
null,
|
|
64
|
-
2
|
|
64
|
+
`Expected at least one text content item, but got ${JSON.stringify(
|
|
65
|
+
result.message.content.map((b) => b.type)
|
|
65
66
|
)}`
|
|
66
67
|
);
|
|
67
68
|
}
|
|
68
69
|
const messageHistoryFile = getMessagesPath(messageLogName, 0, 0);
|
|
69
70
|
overwriteLog(messageHistoryFile, messages);
|
|
70
71
|
return {
|
|
71
|
-
resultText:
|
|
72
|
+
resultText: textBlock.text,
|
|
72
73
|
totalCost: getTotalCost(),
|
|
73
74
|
messageHistoryFile
|
|
74
75
|
};
|
package/dist/utils/ask.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/ask.tsx"],
|
|
4
|
-
"sourcesContent": ["import { last } from 'lodash-es'\nimport { Command } from '@commands'\nimport { getSystemPrompt } from '@constants/prompts'\nimport { getContext } from '@context'\nimport { getTotalCost } from '@costTracker'\nimport { Message, query } from '@query'\nimport { CanUseToolFn } from '@hooks/useCanUseTool'\nimport { Tool } from '@tool'\nimport { getModelManager } from '@utils/model'\nimport { setCwd } from './state'\nimport { getMessagesPath, overwriteLog } from './log'\nimport { createUserMessage } from './messages'\nimport type { SafetyMode } from './config'\n\ntype Props = {\n commands: Command[]\n /** @deprecated Use safetyMode instead */\n safeMode?: boolean\n /** Safety mode: 'yolo' | 'smart' | 'strict' */\n safetyMode?: SafetyMode\n hasPermissionsToUseTool: CanUseToolFn\n messageLogName: string\n prompt: string\n cwd: string\n tools: Tool[]\n verbose?: boolean\n}\n\n// Sends a single prompt to the Anthropic Messages API and returns the response.\n// Assumes that claude is being used non-interactively -- will not\n// ask the user for permissions or further input.\nexport async function ask({\n commands,\n safeMode,\n safetyMode = 'yolo',\n hasPermissionsToUseTool,\n messageLogName,\n prompt,\n cwd,\n tools,\n verbose = false,\n}: Props): Promise<{\n resultText: string\n totalCost: number\n messageHistoryFile: string\n}> {\n await setCwd(cwd)\n const message = createUserMessage(prompt)\n const messages: Message[] = [message]\n\n const [systemPrompt, context, model] = await Promise.all([\n getSystemPrompt(),\n getContext(),\n getModelManager().getModelName('main'),\n ])\n\n for await (const m of query(\n messages,\n systemPrompt,\n context,\n hasPermissionsToUseTool,\n {\n options: {\n commands,\n tools,\n verbose,\n safeMode,\n safetyMode,\n forkNumber: 0,\n messageLogName: 'unused',\n maxThinkingTokens: 0,\n },\n abortController: new AbortController(),\n messageId: undefined,\n readFileTimestamps: {},\n setToolJSX: () => {}, // No-op function for non-interactive use\n },\n )) {\n messages.push(m)\n }\n\n const result = last(messages)\n if (!result || result.type !== 'assistant') {\n throw new Error('Expected content to be an assistant message')\n }\n
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY;AAErB,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAkB,aAAa;AAG/B,SAAS,uBAAuB;AAChC,SAAS,cAAc;AACvB,SAAS,iBAAiB,oBAAoB;AAC9C,SAAS,yBAAyB;AAoBlC,eAAsB,IAAI;AAAA,EACxB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAIG;AACD,QAAM,OAAO,GAAG;AAChB,QAAM,UAAU,kBAAkB,MAAM;AACxC,QAAM,WAAsB,CAAC,OAAO;AAEpC,QAAM,CAAC,cAAc,SAAS,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IACvD,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,gBAAgB,EAAE,aAAa,MAAM;AAAA,EACvC,CAAC;AAED,mBAAiB,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,MACE,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,mBAAmB;AAAA,MACrB;AAAA,MACA,iBAAiB,IAAI,gBAAgB;AAAA,MACrC,WAAW;AAAA,MACX,oBAAoB,CAAC;AAAA,MACrB,YAAY,MAAM;AAAA,MAAC;AAAA;AAAA,IACrB;AAAA,EACF,GAAG;AACD,aAAS,KAAK,CAAC;AAAA,EACjB;AAEA,QAAM,SAAS,KAAK,QAAQ;AAC5B,MAAI,CAAC,UAAU,OAAO,SAAS,aAAa;AAC1C,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;
|
|
4
|
+
"sourcesContent": ["import { last } from 'lodash-es'\nimport { Command } from '@commands'\nimport { getSystemPrompt } from '@constants/prompts'\nimport { getContext } from '@context'\nimport { getTotalCost } from '@costTracker'\nimport { Message, query } from '@query'\nimport { CanUseToolFn } from '@hooks/useCanUseTool'\nimport { Tool } from '@tool'\nimport { getModelManager } from '@utils/model'\nimport { setCwd } from './state'\nimport { getMessagesPath, overwriteLog } from './log'\nimport { createUserMessage } from './messages'\nimport type { SafetyMode } from './config'\n\ntype Props = {\n commands: Command[]\n /** @deprecated Use safetyMode instead */\n safeMode?: boolean\n /** Safety mode: 'yolo' | 'smart' | 'strict' */\n safetyMode?: SafetyMode\n hasPermissionsToUseTool: CanUseToolFn\n messageLogName: string\n prompt: string\n cwd: string\n tools: Tool[]\n verbose?: boolean\n}\n\n// Sends a single prompt to the Anthropic Messages API and returns the response.\n// Assumes that claude is being used non-interactively -- will not\n// ask the user for permissions or further input.\nexport async function ask({\n commands,\n safeMode,\n safetyMode = 'yolo',\n hasPermissionsToUseTool,\n messageLogName,\n prompt,\n cwd,\n tools,\n verbose = false,\n}: Props): Promise<{\n resultText: string\n totalCost: number\n messageHistoryFile: string\n}> {\n await setCwd(cwd)\n const message = createUserMessage(prompt)\n const messages: Message[] = [message]\n\n const [systemPrompt, context, model] = await Promise.all([\n getSystemPrompt(),\n getContext(),\n getModelManager().getModelName('main'),\n ])\n\n for await (const m of query(\n messages,\n systemPrompt,\n context,\n hasPermissionsToUseTool,\n {\n options: {\n commands,\n tools,\n verbose,\n safeMode,\n safetyMode,\n forkNumber: 0,\n messageLogName: 'unused',\n maxThinkingTokens: 0,\n },\n abortController: new AbortController(),\n messageId: undefined,\n readFileTimestamps: {},\n setToolJSX: () => {}, // No-op function for non-interactive use\n },\n )) {\n messages.push(m)\n }\n\n const result = last(messages)\n if (!result || result.type !== 'assistant') {\n throw new Error('Expected content to be an assistant message')\n }\n\n // Find first text block (skip thinking/redacted_thinking blocks)\n const textBlock = result.message.content.find(\n (block: any) => block.type === 'text',\n )\n if (!textBlock || textBlock.type !== 'text') {\n throw new Error(\n `Expected at least one text content item, but got ${JSON.stringify(\n result.message.content.map((b: any) => b.type),\n )}`,\n )\n }\n\n // Write log that can be retrieved with `claude log`\n const messageHistoryFile = getMessagesPath(messageLogName, 0, 0)\n overwriteLog(messageHistoryFile, messages)\n\n return {\n resultText: textBlock.text,\n totalCost: getTotalCost(),\n messageHistoryFile,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,YAAY;AAErB,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAC7B,SAAkB,aAAa;AAG/B,SAAS,uBAAuB;AAChC,SAAS,cAAc;AACvB,SAAS,iBAAiB,oBAAoB;AAC9C,SAAS,yBAAyB;AAoBlC,eAAsB,IAAI;AAAA,EACxB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AACZ,GAIG;AACD,QAAM,OAAO,GAAG;AAChB,QAAM,UAAU,kBAAkB,MAAM;AACxC,QAAM,WAAsB,CAAC,OAAO;AAEpC,QAAM,CAAC,cAAc,SAAS,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IACvD,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,gBAAgB,EAAE,aAAa,MAAM;AAAA,EACvC,CAAC;AAED,mBAAiB,KAAK;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,MACE,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,mBAAmB;AAAA,MACrB;AAAA,MACA,iBAAiB,IAAI,gBAAgB;AAAA,MACrC,WAAW;AAAA,MACX,oBAAoB,CAAC;AAAA,MACrB,YAAY,MAAM;AAAA,MAAC;AAAA;AAAA,IACrB;AAAA,EACF,GAAG;AACD,aAAS,KAAK,CAAC;AAAA,EACjB;AAEA,QAAM,SAAS,KAAK,QAAQ;AAC5B,MAAI,CAAC,UAAU,OAAO,SAAS,aAAa;AAC1C,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAGA,QAAM,YAAY,OAAO,QAAQ,QAAQ;AAAA,IACvC,CAAC,UAAe,MAAM,SAAS;AAAA,EACjC;AACA,MAAI,CAAC,aAAa,UAAU,SAAS,QAAQ;AAC3C,UAAM,IAAI;AAAA,MACR,oDAAoD,KAAK;AAAA,QACvD,OAAO,QAAQ,QAAQ,IAAI,CAAC,MAAW,EAAE,IAAI;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,qBAAqB,gBAAgB,gBAAgB,GAAG,CAAC;AAC/D,eAAa,oBAAoB,QAAQ;AAEzC,SAAO;AAAA,IACL,YAAY,UAAU;AAAA,IACtB,WAAW,aAAa;AAAA,IACxB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { writeFileSync, renameSync, rmSync } from "fs";
|
|
2
|
+
import { dirname, join } from "path";
|
|
3
|
+
function atomicWriteFileSync(filePath, content, mode = 420) {
|
|
4
|
+
const dir = dirname(filePath);
|
|
5
|
+
const tempPath = join(
|
|
6
|
+
dir,
|
|
7
|
+
`.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`
|
|
8
|
+
);
|
|
9
|
+
try {
|
|
10
|
+
writeFileSync(tempPath, content, { encoding: "utf-8", mode });
|
|
11
|
+
renameSync(tempPath, filePath);
|
|
12
|
+
} catch (error) {
|
|
13
|
+
try {
|
|
14
|
+
rmSync(tempPath, { force: true });
|
|
15
|
+
} catch {
|
|
16
|
+
}
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
atomicWriteFileSync
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=atomicWrite.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/atomicWrite.ts"],
|
|
4
|
+
"sourcesContent": ["import { writeFileSync, renameSync, rmSync } from 'fs'\nimport { dirname, join } from 'path'\n\n/**\n * Atomically write content to a file using temp file + rename pattern.\n * This prevents data corruption if writes are interrupted or multiple processes\n * attempt to write concurrently.\n *\n * @param filePath - The target file path to write to\n * @param content - The content to write\n * @throws {Error} If write or rename operation fails\n */\nexport function atomicWriteFileSync(\n filePath: string,\n content: string,\n mode: number = 0o644,\n): void {\n const dir = dirname(filePath)\n const tempPath = join(\n dir,\n `.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`,\n )\n\n try {\n // Write to temporary file with specified permissions\n writeFileSync(tempPath, content, { encoding: 'utf-8', mode })\n // Atomically rename temp to target (atomic on most filesystems)\n renameSync(tempPath, filePath)\n } catch (error) {\n // Clean up temporary file on failure\n try {\n rmSync(tempPath, { force: true })\n } catch {\n // Ignore cleanup errors\n }\n throw error\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe,YAAY,cAAc;AAClD,SAAS,SAAS,YAAY;AAWvB,SAAS,oBACd,UACA,SACA,OAAe,KACT;AACN,QAAM,MAAM,QAAQ,QAAQ;AAC5B,QAAM,WAAW;AAAA,IACf;AAAA,IACA,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAAA,EACvD;AAEA,MAAI;AAEF,kBAAc,UAAU,SAAS,EAAE,UAAU,SAAS,KAAK,CAAC;AAE5D,eAAW,UAAU,QAAQ;AAAA,EAC/B,SAAS,OAAO;AAEd,QAAI;AACF,aAAO,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,IAClC,QAAQ;AAAA,IAER;AACA,UAAM;AAAA,EACR;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|