@within-7/minto 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.js +155 -37
- package/dist/Tool.js +38 -0
- package/dist/Tool.js.map +3 -3
- package/dist/commands/agents/AgentsCommand.js +52 -26
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/constants.js +1 -1
- package/dist/commands/agents/constants.js.map +1 -1
- package/dist/commands/agents/index.js +1 -1
- package/dist/commands/bug.js +74 -7
- package/dist/commands/bug.js.map +3 -3
- package/dist/commands/clear.js +3 -0
- package/dist/commands/clear.js.map +2 -2
- package/dist/commands/compact.js +37 -0
- package/dist/commands/compact.js.map +2 -2
- package/dist/commands/context.js +84 -0
- package/dist/commands/context.js.map +7 -0
- package/dist/commands/ctx_viz.js +18 -10
- package/dist/commands/ctx_viz.js.map +2 -2
- package/dist/commands/doctor.js +158 -12
- package/dist/commands/doctor.js.map +2 -2
- package/dist/commands/export.js +156 -0
- package/dist/commands/export.js.map +7 -0
- package/dist/commands/mcp-interactive.js +21 -12
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +6 -5
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/permissions.js +86 -0
- package/dist/commands/permissions.js.map +7 -0
- package/dist/commands/quit.js +3 -1
- package/dist/commands/quit.js.map +2 -2
- package/dist/commands/sandbox.js +104 -0
- package/dist/commands/sandbox.js.map +7 -0
- package/dist/commands/status.js +58 -0
- package/dist/commands/status.js.map +7 -0
- package/dist/commands/tasks.js +108 -0
- package/dist/commands/tasks.js.map +7 -0
- package/dist/commands/todos.js +123 -0
- package/dist/commands/todos.js.map +7 -0
- package/dist/commands.js +20 -2
- package/dist/commands.js.map +2 -2
- package/dist/components/AgentThinkingBlock.js +10 -18
- package/dist/components/AgentThinkingBlock.js.map +2 -2
- package/dist/components/BackgroundTasksPanel.js +78 -29
- package/dist/components/BackgroundTasksPanel.js.map +2 -2
- package/dist/components/BashStreamingProgress.js +24 -0
- package/dist/components/BashStreamingProgress.js.map +7 -0
- package/dist/components/CollapsibleHint.js +14 -0
- package/dist/components/CollapsibleHint.js.map +7 -0
- package/dist/components/FileEditToolUpdatedMessage.js +1 -1
- package/dist/components/FileEditToolUpdatedMessage.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +137 -0
- package/dist/components/HotkeyHelpPanel.js.map +7 -0
- package/dist/components/Logo.js +5 -5
- package/dist/components/Logo.js.map +2 -2
- package/dist/components/Message.js +23 -7
- package/dist/components/Message.js.map +3 -3
- package/dist/components/ModelConfig.js +16 -3
- package/dist/components/ModelConfig.js.map +2 -2
- package/dist/components/ModelListManager.js +3 -3
- package/dist/components/ModelListManager.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +1 -1
- package/dist/components/Onboarding.js +19 -14
- package/dist/components/Onboarding.js.map +2 -2
- package/dist/components/ProgressBar.js +74 -0
- package/dist/components/ProgressBar.js.map +7 -0
- package/dist/components/PromptInput.js +156 -46
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/RequestStatusIndicator.js +194 -0
- package/dist/components/RequestStatusIndicator.js.map +7 -0
- package/dist/components/Spinner.js +92 -27
- package/dist/components/Spinner.js.map +2 -2
- package/dist/components/SpinnerSymbol.js +21 -27
- package/dist/components/SpinnerSymbol.js.map +2 -2
- package/dist/components/StreamingBashOutput.js +9 -8
- package/dist/components/StreamingBashOutput.js.map +2 -2
- package/dist/components/SubagentBlock.js +1 -1
- package/dist/components/SubagentBlock.js.map +1 -1
- package/dist/components/SubagentProgress.js +10 -11
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TaskCard.js +16 -13
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TodoChangeBlock.js +1 -1
- package/dist/components/TodoChangeBlock.js.map +2 -2
- package/dist/components/TodoPanel.js +120 -29
- package/dist/components/TodoPanel.js.map +3 -3
- package/dist/components/TokenCounter.js +74 -0
- package/dist/components/TokenCounter.js.map +7 -0
- package/dist/components/TokenWarning.js +2 -1
- package/dist/components/TokenWarning.js.map +2 -2
- package/dist/components/TreeConnector.js +25 -0
- package/dist/components/TreeConnector.js.map +7 -0
- package/dist/components/TurnCompletionIndicator.js +18 -0
- package/dist/components/TurnCompletionIndicator.js.map +7 -0
- package/dist/components/messages/AssistantTextMessage.js +5 -2
- package/dist/components/messages/AssistantTextMessage.js.map +2 -2
- package/dist/components/messages/AssistantThinkingMessage.js +18 -3
- package/dist/components/messages/AssistantThinkingMessage.js.map +2 -2
- package/dist/components/messages/AssistantToolUseMessage.js +11 -8
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/GroupRenderer.js +53 -0
- package/dist/components/messages/GroupRenderer.js.map +7 -0
- package/dist/components/messages/NestedTasksPreview.js +12 -0
- package/dist/components/messages/NestedTasksPreview.js.map +7 -0
- package/dist/components/messages/ParallelTasksGroupView.js +92 -0
- package/dist/components/messages/ParallelTasksGroupView.js.map +7 -0
- package/dist/components/messages/TaskInModuleView.js +198 -0
- package/dist/components/messages/TaskInModuleView.js.map +7 -0
- package/dist/components/messages/TaskOutputContent.js +53 -0
- package/dist/components/messages/TaskOutputContent.js.map +7 -0
- package/dist/components/messages/UserPromptMessage.js +1 -1
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +2 -3
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
- package/dist/components/permissions/FallbackPermissionRequest.js +4 -4
- package/dist/components/permissions/FallbackPermissionRequest.js.map +2 -2
- package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js +4 -4
- package/dist/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.js.map +2 -2
- package/dist/constants/colors.js +48 -0
- package/dist/constants/colors.js.map +2 -2
- package/dist/constants/formatRules.js +102 -0
- package/dist/constants/formatRules.js.map +7 -0
- package/dist/constants/prompts.js +12 -34
- package/dist/constants/prompts.js.map +2 -2
- package/dist/constants/symbols.js +64 -6
- package/dist/constants/symbols.js.map +2 -2
- package/dist/constants/timing.js +5 -0
- package/dist/constants/timing.js.map +2 -2
- package/dist/core/config/defaults.js +84 -0
- package/dist/core/config/defaults.js.map +7 -0
- package/dist/core/config/index.js +111 -0
- package/dist/core/config/index.js.map +7 -0
- package/dist/core/config/loader.js +221 -0
- package/dist/core/config/loader.js.map +7 -0
- package/dist/core/config/migrations.js +128 -0
- package/dist/core/config/migrations.js.map +7 -0
- package/dist/core/config/schema.js +178 -0
- package/dist/core/config/schema.js.map +7 -0
- package/dist/core/costTracker.js +138 -0
- package/dist/core/costTracker.js.map +7 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +7 -0
- package/dist/core/permissions/auditLog.js +204 -0
- package/dist/core/permissions/auditLog.js.map +7 -0
- package/dist/core/permissions/engine/index.js +3 -0
- package/dist/core/permissions/engine/index.js.map +7 -0
- package/dist/core/permissions/engine/permissionEngine.js +106 -0
- package/dist/core/permissions/engine/permissionEngine.js.map +7 -0
- package/dist/core/permissions/engine/types.js +1 -0
- package/dist/core/permissions/engine/types.js.map +7 -0
- package/dist/core/permissions/index.js +84 -0
- package/dist/core/permissions/index.js.map +7 -0
- package/dist/core/permissions/ruleEngine.js +259 -0
- package/dist/core/permissions/ruleEngine.js.map +7 -0
- package/dist/core/permissions/rules/allowedToolsRule.js +62 -0
- package/dist/core/permissions/rules/allowedToolsRule.js.map +7 -0
- package/dist/core/permissions/rules/autoEscalationRule.js +291 -0
- package/dist/core/permissions/rules/autoEscalationRule.js.map +7 -0
- package/dist/core/permissions/rules/index.js +46 -0
- package/dist/core/permissions/rules/index.js.map +7 -0
- package/dist/core/permissions/rules/planModeRule.js +55 -0
- package/dist/core/permissions/rules/planModeRule.js.map +7 -0
- package/dist/core/permissions/rules/projectBoundaryRule.js +168 -0
- package/dist/core/permissions/rules/projectBoundaryRule.js.map +7 -0
- package/dist/core/permissions/rules/safeModeRule.js +65 -0
- package/dist/core/permissions/rules/safeModeRule.js.map +7 -0
- package/dist/core/permissions/rules/sensitivePathsRule.js +340 -0
- package/dist/core/permissions/rules/sensitivePathsRule.js.map +7 -0
- package/dist/core/permissions/types.js +127 -0
- package/dist/core/permissions/types.js.map +7 -0
- package/dist/core/tools/executor.js +143 -0
- package/dist/core/tools/executor.js.map +7 -0
- package/dist/core/tools/index.js +15 -0
- package/dist/core/tools/index.js.map +7 -0
- package/dist/core/tools/registry.js +183 -0
- package/dist/core/tools/registry.js.map +7 -0
- package/dist/core/tools/types.js +1 -0
- package/dist/core/tools/types.js.map +7 -0
- package/dist/cost-tracker.js +23 -15
- package/dist/cost-tracker.js.map +2 -2
- package/dist/entrypoints/cli.js +43 -43
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/entrypoints/mcp.js +12 -4
- package/dist/entrypoints/mcp.js.map +2 -2
- package/dist/history.js +14 -3
- package/dist/history.js.map +2 -2
- package/dist/hooks/useAgentTranscripts.js +116 -0
- package/dist/hooks/useAgentTranscripts.js.map +7 -0
- package/dist/hooks/useAnimationSync.js +53 -0
- package/dist/hooks/useAnimationSync.js.map +7 -0
- package/dist/hooks/useArrowKeyHistory.js +4 -2
- package/dist/hooks/useArrowKeyHistory.js.map +2 -2
- package/dist/hooks/useCanUseTool.js +3 -1
- package/dist/hooks/useCanUseTool.js.map +2 -2
- package/dist/hooks/useCancelRequest.js +4 -1
- package/dist/hooks/useCancelRequest.js.map +2 -2
- package/dist/hooks/useExitOnCtrlCD.js +9 -5
- package/dist/hooks/useExitOnCtrlCD.js.map +2 -2
- package/dist/hooks/useHookStatus.js +40 -0
- package/dist/hooks/useHookStatus.js.map +7 -0
- package/dist/hooks/useLogMessages.js +17 -1
- package/dist/hooks/useLogMessages.js.map +2 -2
- package/dist/hooks/useMessageGroups.js +43 -0
- package/dist/hooks/useMessageGroups.js.map +7 -0
- package/dist/hooks/useTerminalSize.js +62 -6
- package/dist/hooks/useTerminalSize.js.map +2 -2
- package/dist/hooks/useUnifiedCompletion.js +69 -0
- package/dist/hooks/useUnifiedCompletion.js.map +2 -2
- package/dist/i18n/index.js +109 -0
- package/dist/i18n/index.js.map +7 -0
- package/dist/i18n/locales/en.js +347 -0
- package/dist/i18n/locales/en.js.map +7 -0
- package/dist/i18n/locales/index.js +7 -0
- package/dist/i18n/locales/index.js.map +7 -0
- package/dist/i18n/locales/zh-CN.js +347 -0
- package/dist/i18n/locales/zh-CN.js.map +7 -0
- package/dist/i18n/types.js +8 -0
- package/dist/i18n/types.js.map +7 -0
- package/dist/query.js +175 -17
- package/dist/query.js.map +3 -3
- package/dist/screens/REPL.js +501 -192
- package/dist/screens/REPL.js.map +3 -3
- package/dist/services/adapters/chatCompletions.js +3 -1
- package/dist/services/adapters/chatCompletions.js.map +2 -2
- package/dist/services/adapters/messageNormalizer.js +354 -0
- package/dist/services/adapters/messageNormalizer.js.map +7 -0
- package/dist/services/adapters/responsesAPI.js +6 -3
- package/dist/services/adapters/responsesAPI.js.map +2 -2
- package/dist/services/checkpointManager.js +386 -0
- package/dist/services/checkpointManager.js.map +7 -0
- package/dist/services/claude.js +138 -11
- package/dist/services/claude.js.map +3 -3
- package/dist/services/compressionService.js +50 -1
- package/dist/services/compressionService.js.map +2 -2
- package/dist/services/contextMonitor.js +162 -0
- package/dist/services/contextMonitor.js.map +7 -0
- package/dist/services/customCommands.js +60 -41
- package/dist/services/customCommands.js.map +2 -2
- package/dist/services/hookExecutor.js +173 -1
- package/dist/services/hookExecutor.js.map +2 -2
- package/dist/services/intelligentCompactor.js +281 -0
- package/dist/services/intelligentCompactor.js.map +7 -0
- package/dist/services/lspConfig.js +109 -0
- package/dist/services/lspConfig.js.map +7 -0
- package/dist/services/mcpClient.js +273 -34
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/modelOrchestrator.js +310 -0
- package/dist/services/modelOrchestrator.js.map +7 -0
- package/dist/services/openai.js +8 -1
- package/dist/services/openai.js.map +2 -2
- package/dist/services/outputStyles.js +138 -0
- package/dist/services/outputStyles.js.map +7 -0
- package/dist/services/plugins/index.js +5 -0
- package/dist/services/plugins/index.js.map +7 -0
- package/dist/services/plugins/lspServers.js +188 -0
- package/dist/services/plugins/lspServers.js.map +7 -0
- package/dist/services/plugins/pluginRuntime.js +229 -0
- package/dist/services/plugins/pluginRuntime.js.map +7 -0
- package/dist/services/plugins/pluginValidation.js +219 -0
- package/dist/services/plugins/pluginValidation.js.map +7 -0
- package/dist/services/plugins/skillMarketplace.js +556 -0
- package/dist/services/plugins/skillMarketplace.js.map +7 -0
- package/dist/services/responseStateManager.js +37 -3
- package/dist/services/responseStateManager.js.map +2 -2
- package/dist/services/sandbox/filesystemBoundary.js +300 -0
- package/dist/services/sandbox/filesystemBoundary.js.map +7 -0
- package/dist/services/sandbox/index.js +14 -0
- package/dist/services/sandbox/index.js.map +7 -0
- package/dist/services/sandbox/networkProxy.js +293 -0
- package/dist/services/sandbox/networkProxy.js.map +7 -0
- package/dist/services/sandbox/sandboxController.js +574 -0
- package/dist/services/sandbox/sandboxController.js.map +7 -0
- package/dist/services/sandbox/types.js +50 -0
- package/dist/services/sandbox/types.js.map +7 -0
- package/dist/services/sessionMemory.js +266 -0
- package/dist/services/sessionMemory.js.map +7 -0
- package/dist/services/taskRouter.js +324 -0
- package/dist/services/taskRouter.js.map +7 -0
- package/dist/tools/ArchitectTool/ArchitectTool.js +7 -1
- package/dist/tools/ArchitectTool/ArchitectTool.js.map +2 -2
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +3 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
- package/dist/tools/BaseTool.js +72 -0
- package/dist/tools/BaseTool.js.map +7 -0
- package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js +3 -0
- package/dist/tools/BashOutputTool/BashOutputToolResultMessage.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +60 -3
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/BashToolResultMessage.js +3 -0
- package/dist/tools/BashTool/BashToolResultMessage.js.map +2 -2
- package/dist/tools/BashTool/OutputLine.js +54 -0
- package/dist/tools/BashTool/OutputLine.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +192 -3
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +29 -4
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +5 -5
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
- package/dist/tools/GlobTool/GlobTool.js +4 -2
- package/dist/tools/GlobTool/GlobTool.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +36 -7
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/KillShellTool/KillShellToolResultMessage.js +3 -0
- package/dist/tools/KillShellTool/KillShellToolResultMessage.js.map +2 -2
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js +109 -0
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +7 -0
- package/dist/tools/ListMcpResourcesTool/prompt.js +19 -0
- package/dist/tools/ListMcpResourcesTool/prompt.js.map +7 -0
- package/dist/tools/LspTool/LspTool.js +664 -0
- package/dist/tools/LspTool/LspTool.js.map +7 -0
- package/dist/tools/LspTool/prompt.js +27 -0
- package/dist/tools/LspTool/prompt.js.map +7 -0
- package/dist/tools/MCPTool/MCPTool.js +9 -1
- package/dist/tools/MCPTool/MCPTool.js.map +2 -2
- package/dist/tools/MemoryReadTool/MemoryReadTool.js +19 -6
- package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +6 -6
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js +19 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +5 -1
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +2 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +74 -0
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +7 -0
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +108 -0
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +7 -0
- package/dist/tools/PlanModeTool/prompt.js +94 -0
- package/dist/tools/PlanModeTool/prompt.js.map +7 -0
- package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js +130 -0
- package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +7 -0
- package/dist/tools/ReadMcpResourceTool/prompt.js +17 -0
- package/dist/tools/ReadMcpResourceTool/prompt.js.map +7 -0
- package/dist/tools/SkillTool/SkillTool.js +6 -1
- package/dist/tools/SkillTool/SkillTool.js.map +2 -2
- package/dist/tools/SlashCommandTool/SlashCommandTool.js +260 -0
- package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +7 -0
- package/dist/tools/SlashCommandTool/prompt.js +35 -0
- package/dist/tools/SlashCommandTool/prompt.js.map +7 -0
- package/dist/tools/TaskOutputTool/TaskOutputTool.js +189 -0
- package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +7 -0
- package/dist/tools/TaskOutputTool/prompt.js +15 -0
- package/dist/tools/TaskOutputTool/prompt.js.map +7 -0
- package/dist/tools/TaskTool/TaskTool.js +302 -104
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskTool/prompt.js.map +2 -2
- package/dist/tools/TodoWriteTool/TodoWriteTool.js +42 -77
- package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/URLFetcherTool.js +4 -1
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/cache.js +55 -8
- package/dist/tools/URLFetcherTool/cache.js.map +2 -2
- package/dist/tools.js +31 -2
- package/dist/tools.js.map +2 -2
- package/dist/types/hooks.js +4 -0
- package/dist/types/hooks.js.map +2 -2
- package/dist/types/marketplace.js.map +2 -2
- package/dist/types/messageGroup.js +36 -0
- package/dist/types/messageGroup.js.map +7 -0
- package/dist/types/plugin.js.map +2 -2
- package/dist/types/thinking.js +1 -0
- package/dist/types/thinking.js.map +7 -0
- package/dist/utils/BackgroundShellManager.js +136 -39
- package/dist/utils/BackgroundShellManager.js.map +2 -2
- package/dist/utils/MessageBatchBuffer.js +102 -0
- package/dist/utils/MessageBatchBuffer.js.map +7 -0
- package/dist/utils/PersistentShell.js +151 -1
- package/dist/utils/PersistentShell.js.map +2 -2
- package/dist/utils/agentLoader.js +1 -23
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/agentTranscripts.js +641 -0
- package/dist/utils/agentTranscripts.js.map +7 -0
- package/dist/utils/animationManager.js +213 -0
- package/dist/utils/animationManager.js.map +7 -0
- package/dist/utils/animationSync.js +110 -0
- package/dist/utils/animationSync.js.map +7 -0
- package/dist/utils/asyncFile.js +215 -0
- package/dist/utils/asyncFile.js.map +7 -0
- package/dist/utils/backgroundAgentManager.js +231 -0
- package/dist/utils/backgroundAgentManager.js.map +7 -0
- package/dist/utils/config.js +63 -7
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/conversationRecovery.js +19 -0
- package/dist/utils/conversationRecovery.js.map +2 -2
- package/dist/utils/exit.js +73 -0
- package/dist/utils/exit.js.map +7 -0
- package/dist/utils/format.js +73 -5
- package/dist/utils/format.js.map +2 -2
- package/dist/utils/generators.js +76 -6
- package/dist/utils/generators.js.map +2 -2
- package/dist/utils/globalErrorHandler.js +149 -0
- package/dist/utils/globalErrorHandler.js.map +7 -0
- package/dist/utils/groupHandlers/index.js +8 -0
- package/dist/utils/groupHandlers/index.js.map +7 -0
- package/dist/utils/groupHandlers/parallelTasksHandler.js +140 -0
- package/dist/utils/groupHandlers/parallelTasksHandler.js.map +7 -0
- package/dist/utils/groupHandlers/taskHandler.js +104 -0
- package/dist/utils/groupHandlers/taskHandler.js.map +7 -0
- package/dist/utils/groupHandlers/types.js +1 -0
- package/dist/utils/groupHandlers/types.js.map +7 -0
- package/dist/utils/logRotation.js +224 -0
- package/dist/utils/logRotation.js.map +7 -0
- package/dist/utils/marketplaceManager.js +3 -5
- package/dist/utils/marketplaceManager.js.map +2 -2
- package/dist/utils/memSafety.js +264 -0
- package/dist/utils/memSafety.js.map +7 -0
- package/dist/utils/messageGroupManager.js +274 -0
- package/dist/utils/messageGroupManager.js.map +7 -0
- package/dist/utils/messages.js +13 -4
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/model.js +119 -15
- package/dist/utils/model.js.map +3 -3
- package/dist/utils/permissions/filesystem.js +157 -5
- package/dist/utils/permissions/filesystem.js.map +2 -2
- package/dist/utils/plan/planMode.js +143 -0
- package/dist/utils/plan/planMode.js.map +7 -0
- package/dist/utils/pluginLoader.js +17 -21
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/ripgrep.js +55 -2
- package/dist/utils/ripgrep.js.map +2 -2
- package/dist/utils/sanitizeInput.js +32 -0
- package/dist/utils/sanitizeInput.js.map +7 -0
- package/dist/utils/secureKeyStorage.js +312 -0
- package/dist/utils/secureKeyStorage.js.map +7 -0
- package/dist/utils/session/sessionPlugins.js +67 -0
- package/dist/utils/session/sessionPlugins.js.map +7 -0
- package/dist/utils/taskDisplayUtils.js +257 -0
- package/dist/utils/taskDisplayUtils.js.map +7 -0
- package/dist/utils/teamConfig.js +2 -1
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/todoStorage.js +92 -2
- package/dist/utils/todoStorage.js.map +2 -2
- package/dist/utils/toolTimeout.js +136 -0
- package/dist/utils/toolTimeout.js.map +7 -0
- package/dist/utils/tooling/safeRender.js +115 -0
- package/dist/utils/tooling/safeRender.js.map +7 -0
- package/dist/utils/userFriendlyError.js +346 -0
- package/dist/utils/userFriendlyError.js.map +7 -0
- package/dist/utils/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +14 -4
- package/scripts/postinstall.js +128 -38
- package/dist/commands/agents.js +0 -2086
- package/dist/commands/agents.js.map +0 -7
- package/dist/commands/build.js +0 -74
- package/dist/commands/build.js.map +0 -7
- package/dist/commands/compression.js +0 -57
- package/dist/commands/compression.js.map +0 -7
- package/dist/commands/listen.js +0 -37
- package/dist/commands/listen.js.map +0 -7
- package/dist/commands/login.js +0 -37
- package/dist/commands/login.js.map +0 -7
- package/dist/commands/logout.js +0 -33
- package/dist/commands/logout.js.map +0 -7
- package/dist/commands/mcp.js +0 -40
- package/dist/commands/mcp.js.map +0 -7
- package/dist/commands/mcp_refresh.js +0 -40
- package/dist/commands/mcp_refresh.js.map +0 -7
- package/dist/commands/modelstatus.js +0 -21
- package/dist/commands/modelstatus.js.map +0 -7
- package/dist/commands/onboarding.js +0 -36
- package/dist/commands/onboarding.js.map +0 -7
- package/dist/commands/plugin-interactive.js +0 -446
- package/dist/commands/plugin-interactive.js.map +0 -7
- package/dist/commands/pr_comments.js +0 -61
- package/dist/commands/pr_comments.js.map +0 -7
- package/dist/commands/release-notes.js +0 -30
- package/dist/commands/release-notes.js.map +0 -7
- package/dist/commands/review.js +0 -51
- package/dist/commands/review.js.map +0 -7
- package/dist/components/Bug.js +0 -147
- package/dist/components/Bug.js.map +0 -7
- package/dist/components/ModelSelector.js +0 -2062
- package/dist/components/ModelSelector.js.map +0 -7
- package/dist/components/ModelStatusDisplay.js +0 -87
- package/dist/components/ModelStatusDisplay.js.map +0 -7
- package/dist/entrypoints/cli-wrapper.js +0 -61
- package/dist/entrypoints/cli-wrapper.js.map +0 -7
- package/dist/screens/Doctor.js +0 -22
- package/dist/screens/Doctor.js.map +0 -7
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { Box, Text } from "ink";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { useRef, useMemo } from "react";
|
|
4
4
|
import { getTheme } from "../utils/theme.js";
|
|
5
5
|
import { sample } from "lodash-es";
|
|
6
6
|
import { getSessionState } from "../utils/sessionState.js";
|
|
7
|
+
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
8
|
+
import { formatNumber, formatTokenUsage } from "../utils/format.js";
|
|
7
9
|
const CHARACTERS = process.platform === "darwin" ? ["\xB7", "\u2722", "\u2733", "\u2217", "\u273B", "\u273D"] : ["\xB7", "\u2722", "*", "\u2217", "\u273B", "\u273D"];
|
|
10
|
+
let currentStreamingState = { phase: "thinking" };
|
|
11
|
+
function setStreamingState(state) {
|
|
12
|
+
currentStreamingState = { ...currentStreamingState, ...state };
|
|
13
|
+
}
|
|
14
|
+
function resetStreamingState() {
|
|
15
|
+
currentStreamingState = { phase: "thinking" };
|
|
16
|
+
}
|
|
17
|
+
function getStreamingState() {
|
|
18
|
+
return currentStreamingState;
|
|
19
|
+
}
|
|
8
20
|
const MESSAGES = [
|
|
9
21
|
"Accomplishing",
|
|
10
22
|
"Actioning",
|
|
@@ -63,39 +75,92 @@ const MESSAGES = [
|
|
|
63
75
|
"Vibing",
|
|
64
76
|
"Working"
|
|
65
77
|
];
|
|
66
|
-
function Spinner() {
|
|
78
|
+
function Spinner({ isActive = true }) {
|
|
67
79
|
const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()];
|
|
68
|
-
const [frame, setFrame] = useState(0);
|
|
69
|
-
const [elapsedTime, setElapsedTime] = useState(0);
|
|
70
80
|
const message = useRef(sample(MESSAGES));
|
|
71
81
|
const startTime = useRef(Date.now());
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
const theme = getTheme();
|
|
83
|
+
const { spinnerFrame, elapsedTime } = useUnifiedAnimation({
|
|
84
|
+
enabled: isActive,
|
|
85
|
+
startTime: startTime.current,
|
|
86
|
+
spinnerFrameCount: frames.length,
|
|
87
|
+
componentId: "main-spinner"
|
|
88
|
+
});
|
|
89
|
+
const streamState = useMemo(() => getStreamingState(), [spinnerFrame]);
|
|
90
|
+
const getPhaseDisplay = () => {
|
|
91
|
+
switch (streamState.phase) {
|
|
92
|
+
case "deep_thinking": {
|
|
93
|
+
const elapsed = streamState.thinkingStartTime ? Math.floor((Date.now() - streamState.thinkingStartTime) / 1e3) : 0;
|
|
94
|
+
const charInfo = streamState.tokenCount ? `${formatNumber(streamState.tokenCount)} chars` : "";
|
|
95
|
+
if (streamState.thinkingMaxTokens && streamState.tokenCount) {
|
|
96
|
+
return `Deep thinking (${elapsed}s \xB7 ${charInfo} / ${formatNumber(streamState.thinkingMaxTokens)})`;
|
|
97
|
+
}
|
|
98
|
+
return `Deep thinking (${elapsed}s${charInfo ? " \xB7 " + charInfo : ""})`;
|
|
99
|
+
}
|
|
100
|
+
case "retrying":
|
|
101
|
+
return streamState.retryCount && streamState.maxRetries ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \xB7 ${streamState.errorName}` : ""}` : streamState.errorName ? `Retrying \xB7 ${streamState.errorName}` : "Retrying...";
|
|
102
|
+
case "permission":
|
|
103
|
+
return "Waiting for permission...";
|
|
104
|
+
case "compacting":
|
|
105
|
+
return "Compacting context...";
|
|
106
|
+
case "concurrent":
|
|
107
|
+
return streamState.concurrentCount ? `Running ${streamState.concurrentCount} concurrent tasks...` : "Running concurrent tasks...";
|
|
108
|
+
case "tool_use":
|
|
109
|
+
return streamState.toolName ? `Using ${streamState.toolName}` : "Executing tool";
|
|
110
|
+
case "generating":
|
|
111
|
+
return "Receiving";
|
|
112
|
+
case "waiting":
|
|
113
|
+
return "Waiting for response";
|
|
114
|
+
case "thinking":
|
|
115
|
+
default:
|
|
116
|
+
return message.current;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const phaseColors = {
|
|
120
|
+
thinking: theme.minto,
|
|
121
|
+
deep_thinking: theme.minto,
|
|
122
|
+
generating: theme.success,
|
|
123
|
+
tool_use: theme.warning,
|
|
124
|
+
waiting: theme.secondaryText,
|
|
125
|
+
retrying: theme.error,
|
|
126
|
+
permission: theme.info,
|
|
127
|
+
compacting: theme.info,
|
|
128
|
+
concurrent: theme.success
|
|
129
|
+
};
|
|
130
|
+
const getTokenDisplay = () => {
|
|
131
|
+
if (streamState.inputTokens || streamState.outputTokens) {
|
|
132
|
+
return formatTokenUsage(streamState.inputTokens, streamState.outputTokens);
|
|
133
|
+
}
|
|
134
|
+
if (streamState.receivedChars && streamState.receivedChars > 0) {
|
|
135
|
+
const approxTokens = Math.round(streamState.receivedChars / 3);
|
|
136
|
+
return `\u2193 ~${formatNumber(approxTokens)}`;
|
|
137
|
+
}
|
|
138
|
+
return "";
|
|
139
|
+
};
|
|
140
|
+
const tokenUsage = getTokenDisplay();
|
|
141
|
+
const thinkingDuration = streamState.thinkingDurationMs ? Math.floor(streamState.thinkingDurationMs / 1e3) : null;
|
|
142
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexWrap: "nowrap", height: 1, width: 2 }, /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, frames[spinnerFrame])), /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, getPhaseDisplay(), "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "(", /* @__PURE__ */ React.createElement(Text, { bold: true }, "esc"), " to interrupt \xB7 ", elapsedTime, "s", tokenUsage && /* @__PURE__ */ React.createElement(Text, null, " \xB7 ", tokenUsage, " tokens"), thinkingDuration !== null && thinkingDuration > 0 && /* @__PURE__ */ React.createElement(Text, null, " \xB7 thought for ", thinkingDuration, "s"), ")"), getSessionState("currentError") && /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "\xB7 ", getSessionState("currentError")));
|
|
85
143
|
}
|
|
86
|
-
function SimpleSpinner(
|
|
144
|
+
function SimpleSpinner({
|
|
145
|
+
isActive = true,
|
|
146
|
+
label
|
|
147
|
+
}) {
|
|
87
148
|
const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()];
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
149
|
+
const startTime = useRef(Date.now());
|
|
150
|
+
const theme = getTheme();
|
|
151
|
+
const { spinnerFrame } = useUnifiedAnimation({
|
|
152
|
+
enabled: isActive,
|
|
153
|
+
startTime: startTime.current,
|
|
154
|
+
spinnerFrameCount: frames.length,
|
|
155
|
+
componentId: "simple-spinner"
|
|
156
|
+
});
|
|
157
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Box, { flexWrap: "nowrap", height: 1, width: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.minto }, frames[spinnerFrame])), label && /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, " ", label));
|
|
96
158
|
}
|
|
97
159
|
export {
|
|
98
160
|
SimpleSpinner,
|
|
99
|
-
Spinner
|
|
161
|
+
Spinner,
|
|
162
|
+
getStreamingState,
|
|
163
|
+
resetStreamingState,
|
|
164
|
+
setStreamingState
|
|
100
165
|
};
|
|
101
166
|
//# sourceMappingURL=Spinner.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/Spinner.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useEffect, useRef, useState } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { sample } from 'lodash-es'\nimport { getSessionState } from '@utils/sessionState'\n// NB: The third character in this string is an emoji that\n// renders on Windows consoles with a green background\nconst CHARACTERS =\n process.platform === 'darwin'\n ? ['\u00B7', '\u2722', '\u2733', '\u2217', '\u273B', '\u273D']\n : ['\u00B7', '\u2722', '*', '\u2217', '\u273B', '\u273D']\n\nconst MESSAGES = [\n 'Accomplishing',\n 'Actioning',\n 'Actualizing',\n 'Baking',\n 'Brewing',\n 'Calculating',\n 'Cerebrating',\n 'Churning',\n 'Coding',\n 'Coalescing',\n 'Cogitating',\n 'Computing',\n 'Conjuring',\n 'Considering',\n 'Cooking',\n 'Crafting',\n 'Creating',\n 'Crunching',\n 'Deliberating',\n 'Determining',\n 'Doing',\n 'Effecting',\n 'Finagling',\n 'Forging',\n 'Forming',\n 'Generating',\n 'Hatching',\n 'Herding',\n 'Honking',\n 'Hustling',\n 'Ideating',\n 'Inferring',\n 'Manifesting',\n 'Marinating',\n 'Moseying',\n 'Mulling',\n 'Mustering',\n 'Musing',\n 'Noodling',\n 'Percolating',\n 'Pondering',\n 'Processing',\n 'Puttering',\n 'Reticulating',\n 'Ruminating',\n 'Schlepping',\n 'Shucking',\n 'Simmering',\n 'Smooshing',\n 'Spinning',\n 'Stewing',\n 'Synthesizing',\n 'Thinking',\n 'Transmuting',\n 'Vibing',\n 'Working',\n]\n\nexport function Spinner(): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const
|
|
5
|
-
"mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useEffect, useRef, useState, useMemo } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { sample } from 'lodash-es'\nimport { getSessionState, setSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { formatNumber, formatTokenUsage } from '@utils/format'\n\n// NB: The third character in this string is an emoji that\n// renders on Windows consoles with a green background\nconst CHARACTERS =\n process.platform === 'darwin'\n ? ['\u00B7', '\u2722', '\u2733', '\u2217', '\u273B', '\u273D']\n : ['\u00B7', '\u2722', '*', '\u2217', '\u273B', '\u273D']\n\n// Streaming phases for better UX feedback\nexport type StreamingPhase =\n | 'thinking' // Initial thinking phase\n | 'generating' // Generating response content\n | 'tool_use' // Executing a tool\n | 'waiting' // Waiting for API response\n | 'deep_thinking' // Extended thinking mode (Claude thinking blocks)\n | 'retrying' // API retry in progress\n | 'permission' // Waiting for user permission\n | 'compacting' // Compacting conversation context\n | 'concurrent' // Running concurrent tasks\n\n// Store streaming state for display\nlet currentStreamingState: {\n phase: StreamingPhase\n toolName?: string\n tokenCount?: number\n chunkCount?: number\n // New fields for enhanced feedback\n retryCount?: number\n maxRetries?: number\n errorName?: string\n concurrentCount?: number\n thinkingMaxTokens?: number\n // Token usage from API (real-time streaming)\n inputTokens?: number\n outputTokens?: number\n // Character counts for approximate token estimation\n sentChars?: number // Characters sent to API (input)\n receivedChars?: number // Characters received from API (output)\n // Thinking timing\n thinkingStartTime?: number\n thinkingDurationMs?: number\n} = { phase: 'thinking' }\n\nexport function setStreamingState(\n state: Partial<typeof currentStreamingState>,\n): void {\n currentStreamingState = { ...currentStreamingState, ...state }\n}\n\nexport function resetStreamingState(): void {\n currentStreamingState = { phase: 'thinking' }\n}\n\nexport function getStreamingState(): typeof currentStreamingState {\n return currentStreamingState\n}\n\nconst MESSAGES = [\n 'Accomplishing',\n 'Actioning',\n 'Actualizing',\n 'Baking',\n 'Brewing',\n 'Calculating',\n 'Cerebrating',\n 'Churning',\n 'Coding',\n 'Coalescing',\n 'Cogitating',\n 'Computing',\n 'Conjuring',\n 'Considering',\n 'Cooking',\n 'Crafting',\n 'Creating',\n 'Crunching',\n 'Deliberating',\n 'Determining',\n 'Doing',\n 'Effecting',\n 'Finagling',\n 'Forging',\n 'Forming',\n 'Generating',\n 'Hatching',\n 'Herding',\n 'Honking',\n 'Hustling',\n 'Ideating',\n 'Inferring',\n 'Manifesting',\n 'Marinating',\n 'Moseying',\n 'Mulling',\n 'Mustering',\n 'Musing',\n 'Noodling',\n 'Percolating',\n 'Pondering',\n 'Processing',\n 'Puttering',\n 'Reticulating',\n 'Ruminating',\n 'Schlepping',\n 'Shucking',\n 'Simmering',\n 'Smooshing',\n 'Spinning',\n 'Stewing',\n 'Synthesizing',\n 'Thinking',\n 'Transmuting',\n 'Vibing',\n 'Working',\n]\n\ninterface SpinnerProps {\n /** Whether the spinner should be active (animating) */\n isActive?: boolean\n}\n\nexport function Spinner({ isActive = true }: SpinnerProps): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const message = useRef(sample(MESSAGES))\n const startTime = useRef(Date.now())\n const theme = getTheme()\n\n // Use unified animation manager instead of separate setInterval timers\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTime.current,\n spinnerFrameCount: frames.length,\n componentId: 'main-spinner',\n })\n\n // Get streaming state on each render (updates when spinnerFrame changes)\n const streamState = useMemo(() => getStreamingState(), [spinnerFrame])\n\n // Get phase-specific display\n const getPhaseDisplay = () => {\n switch (streamState.phase) {\n case 'deep_thinking': {\n // Show elapsed time and char count for thinking phase\n const elapsed = streamState.thinkingStartTime\n ? Math.floor((Date.now() - streamState.thinkingStartTime) / 1000)\n : 0\n const charInfo = streamState.tokenCount\n ? `${formatNumber(streamState.tokenCount)} chars`\n : ''\n\n if (streamState.thinkingMaxTokens && streamState.tokenCount) {\n return `Deep thinking (${elapsed}s \u00B7 ${charInfo} / ${formatNumber(streamState.thinkingMaxTokens)})`\n }\n return `Deep thinking (${elapsed}s${charInfo ? ' \u00B7 ' + charInfo : ''})`\n }\n\n case 'retrying':\n return streamState.retryCount && streamState.maxRetries\n ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \u00B7 ${streamState.errorName}` : ''}`\n : streamState.errorName\n ? `Retrying \u00B7 ${streamState.errorName}`\n : 'Retrying...'\n\n case 'permission':\n return 'Waiting for permission...'\n\n case 'compacting':\n return 'Compacting context...'\n\n case 'concurrent':\n return streamState.concurrentCount\n ? `Running ${streamState.concurrentCount} concurrent tasks...`\n : 'Running concurrent tasks...'\n\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n\n case 'generating':\n return 'Receiving'\n\n case 'waiting':\n return 'Waiting for response'\n\n case 'thinking':\n default:\n return message.current\n }\n }\n\n const phaseColors: Record<StreamingPhase, string> = {\n thinking: theme.minto,\n deep_thinking: theme.minto,\n generating: theme.success,\n tool_use: theme.warning,\n waiting: theme.secondaryText,\n retrying: theme.error,\n permission: theme.info,\n compacting: theme.info,\n concurrent: theme.success,\n }\n\n // Get token usage from streaming state (API values or approximate from chars)\n const getTokenDisplay = () => {\n // Prefer API-provided token counts\n if (streamState.inputTokens || streamState.outputTokens) {\n return formatTokenUsage(streamState.inputTokens, streamState.outputTokens)\n }\n // Fallback: approximate from received characters (~3 chars per token for mixed content)\n if (streamState.receivedChars && streamState.receivedChars > 0) {\n const approxTokens = Math.round(streamState.receivedChars / 3)\n return `\u2193 ~${formatNumber(approxTokens)}`\n }\n return ''\n }\n\n const tokenUsage = getTokenDisplay()\n\n // Get thinking duration if available\n const thinkingDuration = streamState.thinkingDurationMs\n ? Math.floor(streamState.thinkingDurationMs / 1000)\n : null\n\n return (\n <Box flexDirection=\"row\" marginTop={1}>\n <Box flexWrap=\"nowrap\" height={1} width={2}>\n <Text color={phaseColors[streamState.phase]}>\n {frames[spinnerFrame]}\n </Text>\n </Box>\n <Text color={phaseColors[streamState.phase]}>{getPhaseDisplay()}\u2026 </Text>\n <Text color={theme.secondaryText}>\n (<Text bold>esc</Text> to interrupt \u00B7 {elapsedTime}s\n {tokenUsage && <Text> \u00B7 {tokenUsage} tokens</Text>}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text> \u00B7 thought for {thinkingDuration}s</Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={theme.secondaryText}>\n \u00B7 {getSessionState('currentError')}\n </Text>\n )}\n </Box>\n )\n}\n\ninterface SimpleSpinnerProps {\n /** Whether the spinner should be active (animating) */\n isActive?: boolean\n /** Optional label to display next to spinner */\n label?: string\n}\n\nexport function SimpleSpinner({\n isActive = true,\n label,\n}: SimpleSpinnerProps): React.ReactNode {\n const frames = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n const startTime = useRef(Date.now())\n const theme = getTheme()\n\n // Use unified animation manager\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTime.current,\n spinnerFrameCount: frames.length,\n componentId: 'simple-spinner',\n })\n\n return (\n <Box flexDirection=\"row\">\n <Box flexWrap=\"nowrap\" height={1} width={2}>\n <Text color={theme.minto}>{frames[spinnerFrame]}</Text>\n </Box>\n {label && <Text color={theme.secondaryText}> {label}</Text>}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,27 +1,25 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
2
|
import { Text } from "ink";
|
|
3
3
|
import { SYMBOLS } from "../constants/symbols.js";
|
|
4
4
|
import { getAgentColor } from "../constants/colors.js";
|
|
5
5
|
import { getTheme } from "../utils/theme.js";
|
|
6
|
+
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
6
7
|
function SpinnerSymbol({
|
|
7
8
|
isRunning,
|
|
8
9
|
color,
|
|
9
|
-
symbol = SYMBOLS.TASK_INDICATOR
|
|
10
|
-
interval = 500
|
|
10
|
+
symbol = SYMBOLS.TASK_INDICATOR
|
|
11
11
|
}) {
|
|
12
12
|
const theme = getTheme();
|
|
13
13
|
const baseColor = getAgentColor(color, theme);
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return () => clearInterval(timer);
|
|
24
|
-
}, [isRunning, interval]);
|
|
14
|
+
const startTimeRef = useRef(Date.now());
|
|
15
|
+
const { dotVisible } = useUnifiedAnimation({
|
|
16
|
+
enabled: isRunning,
|
|
17
|
+
startTime: startTimeRef.current,
|
|
18
|
+
spinnerFrameCount: 2,
|
|
19
|
+
// Just for alternation
|
|
20
|
+
componentId: "spinner-symbol"
|
|
21
|
+
});
|
|
22
|
+
const isBright = isRunning ? dotVisible : true;
|
|
25
23
|
const displayColor = isRunning && !isBright ? dimColor(baseColor) : baseColor;
|
|
26
24
|
return /* @__PURE__ */ React.createElement(Text, { color: displayColor }, symbol);
|
|
27
25
|
}
|
|
@@ -51,23 +49,19 @@ function getBlinkingSymbols() {
|
|
|
51
49
|
}
|
|
52
50
|
function SpinnerSymbolAlternative({
|
|
53
51
|
isRunning,
|
|
54
|
-
color
|
|
55
|
-
interval = 500
|
|
52
|
+
color
|
|
56
53
|
}) {
|
|
57
54
|
const theme = getTheme();
|
|
58
55
|
const displayColor = getAgentColor(color, theme);
|
|
56
|
+
const startTimeRef = useRef(Date.now());
|
|
59
57
|
const symbols = getBlinkingSymbols();
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
setFrameIndex((prev) => (prev + 1) % symbols.length);
|
|
68
|
-
}, interval);
|
|
69
|
-
return () => clearInterval(timer);
|
|
70
|
-
}, [isRunning, interval, symbols.length]);
|
|
58
|
+
const { spinnerFrame } = useUnifiedAnimation({
|
|
59
|
+
enabled: isRunning,
|
|
60
|
+
startTime: startTimeRef.current,
|
|
61
|
+
spinnerFrameCount: symbols.length,
|
|
62
|
+
componentId: "spinner-symbol-alt"
|
|
63
|
+
});
|
|
64
|
+
const frameIndex = isRunning ? spinnerFrame : 0;
|
|
71
65
|
return /* @__PURE__ */ React.createElement(Text, { color: displayColor }, symbols[frameIndex]);
|
|
72
66
|
}
|
|
73
67
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/SpinnerSymbol.tsx"],
|
|
4
|
-
"sourcesContent": ["import React, {
|
|
5
|
-
"mappings": "AAAA,OAAO,SAAS,
|
|
4
|
+
"sourcesContent": ["import React, { useRef, useMemo } from 'react'\nimport { Text } from 'ink'\nimport { SYMBOLS } from '@constants/symbols'\nimport { getAgentColor } from '@constants/colors'\nimport { getTheme } from '@utils/theme'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport type { AgentColor } from '@constants/colors'\n\ninterface SpinnerSymbolProps {\n /** \u662F\u5426\u6B63\u5728\u8FD0\u884C\uFF08\u63A7\u5236\u95EA\u70C1\uFF09 */\n isRunning: boolean\n /** Agent \u989C\u8272 */\n color?: AgentColor\n /** \u81EA\u5B9A\u4E49\u7B26\u53F7\uFF08\u9ED8\u8BA4\u4F7F\u7528 TASK_INDICATOR \u23FA\uFF09 */\n symbol?: string\n /** \u95EA\u70C1\u95F4\u9694\uFF08\u6BEB\u79D2\uFF0C\u9ED8\u8BA4 500ms\uFF09- \u4E0D\u518D\u4F7F\u7528\uFF0C\u4FDD\u7559\u7528\u4E8E\u5411\u540E\u517C\u5BB9 */\n interval?: number\n}\n\n/**\n * \u95EA\u70C1\u7684\u4EFB\u52A1\u6307\u793A\u5668\u7EC4\u4EF6\n *\n * \u529F\u80FD\uFF1A\n * - \u4EFB\u52A1\u6267\u884C\u4E2D\uFF1A\u23FA \u7B26\u53F7\u4EE5\u6307\u5B9A\u989C\u8272\u95EA\u70C1\uFF08\u4EAE \u2192 \u6697\u4EA4\u66FF\uFF09\n * - \u4EFB\u52A1\u5B8C\u6210\u540E\uFF1A\u23FA \u7B26\u53F7\u505C\u6B62\u95EA\u70C1\uFF0C\u4FDD\u6301\u56FA\u5B9A\u989C\u8272\n * - \u652F\u6301\u81EA\u5B9A\u4E49\u989C\u8272\u548C\u95EA\u70C1\u9891\u7387\n *\n * \u5B9E\u73B0\u539F\u7406\uFF1A\n * \u4F7F\u7528\u7EDF\u4E00\u52A8\u753B\u7BA1\u7406\u5668\u4EE3\u66FF setInterval\uFF0C\u51CF\u5C11\u5C4F\u5E55\u95EA\u70C1\n */\nexport function SpinnerSymbol({\n isRunning,\n color,\n symbol = SYMBOLS.TASK_INDICATOR,\n}: SpinnerSymbolProps) {\n const theme = getTheme()\n const baseColor = getAgentColor(color, theme)\n const startTimeRef = useRef(Date.now())\n\n // Use unified animation manager with 2 frames (bright/dim)\n const { dotVisible } = useUnifiedAnimation({\n enabled: isRunning,\n startTime: startTimeRef.current,\n spinnerFrameCount: 2, // Just for alternation\n componentId: 'spinner-symbol',\n })\n\n // dotVisible alternates at 600ms, perfect for blink effect\n const isBright = isRunning ? dotVisible : true\n\n // \u6839\u636E\u95EA\u70C1\u72B6\u6001\u8C03\u6574\u989C\u8272\u4EAE\u5EA6\n const displayColor = isRunning && !isBright ? dimColor(baseColor) : baseColor\n\n return <Text color={displayColor}>{symbol}</Text>\n}\n\n/**\n * \u964D\u4F4E\u989C\u8272\u4EAE\u5EA6\uFF08\u6A21\u62DF\u6697\u72B6\u6001\uFF09\n *\n * @param color - Hex \u989C\u8272\u503C\uFF08\u5982 #FF5555\uFF09\n * @returns \u964D\u4F4E\u4EAE\u5EA6\u540E\u7684 Hex \u989C\u8272\u503C\n */\nfunction dimColor(color: string): string {\n // \u79FB\u9664 # \u524D\u7F00\n const hex = color.replace('#', '')\n\n // \u8F6C\u6362\u4E3A RGB\n const r = parseInt(hex.substring(0, 2), 16)\n const g = parseInt(hex.substring(2, 4), 16)\n const b = parseInt(hex.substring(4, 6), 16)\n\n // \u964D\u4F4E\u4EAE\u5EA6\u5230 40%\n const dimFactor = 0.4\n const dimR = Math.floor(r * dimFactor)\n const dimG = Math.floor(g * dimFactor)\n const dimB = Math.floor(b * dimFactor)\n\n // \u8F6C\u6362\u56DE Hex\n const toHex = (n: number) => n.toString(16).padStart(2, '0')\n return `#${toHex(dimR)}${toHex(dimG)}${toHex(dimB)}`\n}\n\n/**\n * \u83B7\u53D6\u95EA\u70C1\u5E27\u7B26\u53F7\uFF08\u5907\u9009\u65B9\u6848\uFF1A\u4F7F\u7528\u4E0D\u540C\u7B26\u53F7\u6A21\u62DF\u95EA\u70C1\uFF09\n *\n * \u5982\u679C\u7EC8\u7AEF\u4E0D\u652F\u6301\u989C\u8272\u8C03\u6574\uFF0C\u53EF\u4EE5\u4F7F\u7528\u4E0D\u540C\u7B26\u53F7\u4EA4\u66FF\u663E\u793A\n */\nexport function getBlinkingSymbols(): string[] {\n return [\n '\u23FA', // \u5B9E\u5FC3\u5706\n '\u25C9', // \u5927\u5706\u70B9\n '\u25CF', // \u4E2D\u5706\u70B9\n '\u25CB', // \u7A7A\u5FC3\u5706\n ]\n}\n\n/**\n * \u95EA\u70C1\u7684\u4EFB\u52A1\u6307\u793A\u5668\uFF08\u5907\u9009\u65B9\u6848\uFF1A\u7B26\u53F7\u4EA4\u66FF\uFF09\n *\n * \u4F7F\u7528\u4E0D\u540C\u7B26\u53F7\u6A21\u62DF\u95EA\u70C1\u6548\u679C\uFF0C\u9002\u7528\u4E8E\u4E0D\u652F\u6301\u989C\u8272\u8C03\u6574\u7684\u7EC8\u7AEF\n * \u4F7F\u7528\u7EDF\u4E00\u52A8\u753B\u7BA1\u7406\u5668\u4EE3\u66FF setInterval\n */\nexport function SpinnerSymbolAlternative({\n isRunning,\n color,\n}: Omit<SpinnerSymbolProps, 'symbol'>) {\n const theme = getTheme()\n const displayColor = getAgentColor(color, theme)\n const startTimeRef = useRef(Date.now())\n\n const symbols = getBlinkingSymbols()\n\n // Use unified animation manager\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isRunning,\n startTime: startTimeRef.current,\n spinnerFrameCount: symbols.length,\n componentId: 'spinner-symbol-alt',\n })\n\n const frameIndex = isRunning ? spinnerFrame : 0\n\n return <Text color={displayColor}>{symbols[frameIndex]}</Text>\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,SAAS,cAAuB;AACvC,SAAS,YAAY;AACrB,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAC9B,SAAS,gBAAgB;AACzB,SAAS,2BAA2B;AAyB7B,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,SAAS,QAAQ;AACnB,GAAuB;AACrB,QAAM,QAAQ,SAAS;AACvB,QAAM,YAAY,cAAc,OAAO,KAAK;AAC5C,QAAM,eAAe,OAAO,KAAK,IAAI,CAAC;AAGtC,QAAM,EAAE,WAAW,IAAI,oBAAoB;AAAA,IACzC,SAAS;AAAA,IACT,WAAW,aAAa;AAAA,IACxB,mBAAmB;AAAA;AAAA,IACnB,aAAa;AAAA,EACf,CAAC;AAGD,QAAM,WAAW,YAAY,aAAa;AAG1C,QAAM,eAAe,aAAa,CAAC,WAAW,SAAS,SAAS,IAAI;AAEpE,SAAO,oCAAC,QAAK,OAAO,gBAAe,MAAO;AAC5C;AAQA,SAAS,SAAS,OAAuB;AAEvC,QAAM,MAAM,MAAM,QAAQ,KAAK,EAAE;AAGjC,QAAM,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE;AAC1C,QAAM,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE;AAC1C,QAAM,IAAI,SAAS,IAAI,UAAU,GAAG,CAAC,GAAG,EAAE;AAG1C,QAAM,YAAY;AAClB,QAAM,OAAO,KAAK,MAAM,IAAI,SAAS;AACrC,QAAM,OAAO,KAAK,MAAM,IAAI,SAAS;AACrC,QAAM,OAAO,KAAK,MAAM,IAAI,SAAS;AAGrC,QAAM,QAAQ,CAAC,MAAc,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAC3D,SAAO,IAAI,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;AACpD;AAOO,SAAS,qBAA+B;AAC7C,SAAO;AAAA,IACL;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACF;AAQO,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AACF,GAAuC;AACrC,QAAM,QAAQ,SAAS;AACvB,QAAM,eAAe,cAAc,OAAO,KAAK;AAC/C,QAAM,eAAe,OAAO,KAAK,IAAI,CAAC;AAEtC,QAAM,UAAU,mBAAmB;AAGnC,QAAM,EAAE,aAAa,IAAI,oBAAoB;AAAA,IAC3C,SAAS;AAAA,IACT,WAAW,aAAa;AAAA,IACxB,mBAAmB,QAAQ;AAAA,IAC3B,aAAa;AAAA,EACf,CAAC;AAED,QAAM,aAAa,YAAY,eAAe;AAE9C,SAAO,oCAAC,QAAK,OAAO,gBAAe,QAAQ,UAAU,CAAE;AACzD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,6 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { useState, useEffect, useRef } from "react";
|
|
4
4
|
import { getTheme } from "../utils/theme.js";
|
|
5
5
|
import { BackgroundShellManager } from "../utils/BackgroundShellManager.js";
|
|
6
|
+
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
6
7
|
const MAX_SUMMARY_LINES = 5;
|
|
7
8
|
const MAX_DETAIL_LINES = 50;
|
|
8
9
|
function StreamingBashOutput({
|
|
@@ -13,11 +14,17 @@ function StreamingBashOutput({
|
|
|
13
14
|
}) {
|
|
14
15
|
const [outputLines, setOutputLines] = useState([]);
|
|
15
16
|
const [hiddenLineCount, setHiddenLineCount] = useState(0);
|
|
16
|
-
const [elapsedTime, setElapsedTime] = useState(0);
|
|
17
17
|
const [isComplete, setIsComplete] = useState(false);
|
|
18
18
|
const [showDetail, setShowDetail] = useState(false);
|
|
19
|
-
const
|
|
19
|
+
const startTimeRef = useRef(Date.now());
|
|
20
20
|
const theme = getTheme();
|
|
21
|
+
const { elapsedTime } = useUnifiedAnimation({
|
|
22
|
+
enabled: !isComplete,
|
|
23
|
+
startTime: startTimeRef.current,
|
|
24
|
+
spinnerFrameCount: 1,
|
|
25
|
+
// Not used but required
|
|
26
|
+
componentId: `streaming-bash-${shellId}`
|
|
27
|
+
});
|
|
21
28
|
useInput((input, key) => {
|
|
22
29
|
if (key.ctrl && input === "b") {
|
|
23
30
|
onMoveToBackground();
|
|
@@ -25,12 +32,6 @@ function StreamingBashOutput({
|
|
|
25
32
|
setShowDetail((prev) => !prev);
|
|
26
33
|
}
|
|
27
34
|
});
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
const interval = setInterval(() => {
|
|
30
|
-
setElapsedTime(Math.floor((Date.now() - startTime.current) / 1e3));
|
|
31
|
-
}, 1e3);
|
|
32
|
-
return () => clearInterval(interval);
|
|
33
|
-
}, []);
|
|
34
35
|
useEffect(() => {
|
|
35
36
|
const manager = BackgroundShellManager.getInstance();
|
|
36
37
|
const interval = setInterval(() => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/StreamingBashOutput.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useState, useEffect, useRef } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { BackgroundShellManager } from '@utils/BackgroundShellManager'\n\ntype Props = {\n shellId: string\n command: string\n onMoveToBackground: () => void\n onComplete: (stdout: string, stderr: string, exitCode: number) => void\n}\n\nconst MAX_SUMMARY_LINES = 5 // Show only first few lines in summary mode\nconst MAX_DETAIL_LINES = 50 // Show more lines in detail mode\n\nexport function StreamingBashOutput({\n shellId,\n command,\n onMoveToBackground,\n onComplete,\n}: Props) {\n const [outputLines, setOutputLines] = useState<string[]>([])\n const [hiddenLineCount, setHiddenLineCount] = useState(0)\n const [
|
|
5
|
-
"mappings": "AAAA,SAAS,KAAK,MAAM,gBAAgB;AACpC,YAAY,WAAW;AACvB,SAAS,UAAU,WAAW,cAAc;AAC5C,SAAS,gBAAgB;AACzB,SAAS,8BAA8B;
|
|
4
|
+
"sourcesContent": ["import { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useState, useEffect, useRef } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { BackgroundShellManager } from '@utils/BackgroundShellManager'\nimport { useUnifiedAnimation } from '@utils/animationManager'\n\ntype Props = {\n shellId: string\n command: string\n onMoveToBackground: () => void\n onComplete: (stdout: string, stderr: string, exitCode: number) => void\n}\n\nconst MAX_SUMMARY_LINES = 5 // Show only first few lines in summary mode\nconst MAX_DETAIL_LINES = 50 // Show more lines in detail mode\n\nexport function StreamingBashOutput({\n shellId,\n command,\n onMoveToBackground,\n onComplete,\n}: Props) {\n const [outputLines, setOutputLines] = useState<string[]>([])\n const [hiddenLineCount, setHiddenLineCount] = useState(0)\n const [isComplete, setIsComplete] = useState(false)\n const [showDetail, setShowDetail] = useState(false) // Ctrl+O toggle\n const startTimeRef = useRef(Date.now())\n const theme = getTheme()\n\n // Use unified animation manager for elapsed time instead of setInterval\n const { elapsedTime } = useUnifiedAnimation({\n enabled: !isComplete,\n startTime: startTimeRef.current,\n spinnerFrameCount: 1, // Not used but required\n componentId: `streaming-bash-${shellId}`,\n })\n\n // Listen for keyboard shortcuts\n useInput((input, key) => {\n if (key.ctrl && input === 'b') {\n onMoveToBackground()\n } else if (key.ctrl && input === 'o') {\n setShowDetail(prev => !prev)\n }\n })\n\n // Poll for output from background shell\n useEffect(() => {\n const manager = BackgroundShellManager.getInstance()\n\n const interval = setInterval(() => {\n const shell = manager.get(shellId)\n if (!shell) return\n\n // Get all output\n const allLines = [...shell.stdout, ...shell.stderr].filter(\n line => line.trim().length > 0,\n )\n setOutputLines(allLines)\n\n // Calculate hidden lines based on current mode\n const maxLines = showDetail ? MAX_DETAIL_LINES : MAX_SUMMARY_LINES\n if (allLines.length > maxLines) {\n setHiddenLineCount(allLines.length - maxLines)\n } else {\n setHiddenLineCount(0)\n }\n\n // Check if complete\n if (shell.status !== 'running' && !isComplete) {\n setIsComplete(true)\n clearInterval(interval)\n\n // Clean up the shell after getting final output\n const stdout = shell.stdout.join('\\n')\n const stderr = shell.stderr.join('\\n')\n const exitCode = shell.exitCode ?? 0\n\n // Remove from manager after a short delay\n setTimeout(() => {\n manager.remove(shellId)\n }, 1000)\n\n onComplete(stdout, stderr, exitCode)\n }\n }, 100)\n\n return () => clearInterval(interval)\n }, [shellId, isComplete, onComplete, showDetail])\n\n const maxLines = showDetail ? MAX_DETAIL_LINES : MAX_SUMMARY_LINES\n const visibleLines = outputLines.slice(0, maxLines) // Show first N lines, not last N\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box>\n <Text color={theme.bashBorder}>! </Text>\n <Text>{command}</Text>\n </Box>\n\n {visibleLines.length > 0 && (\n <Box flexDirection=\"column\" paddingLeft={2}>\n <Text color={theme.secondaryText}>\u23BF </Text>\n {visibleLines.map((line, index) => (\n <Box key={index}>\n <Text>{line}</Text>\n </Box>\n ))}\n </Box>\n )}\n\n {hiddenLineCount > 0 && (\n <Box paddingLeft={2}>\n <Text color={theme.secondaryText}>\n +{hiddenLineCount} more lines ({elapsedTime}s)\n </Text>\n </Box>\n )}\n\n {!isComplete && (\n <Box paddingLeft={2} marginTop={1} flexDirection=\"row\" gap={1}>\n <Text color={theme.secondaryText}>\n ctrl+o {showDetail ? 'hide details' : 'show details'}\n </Text>\n <Text color={theme.secondaryText}>\u00B7</Text>\n <Text color={theme.warning}>ctrl+b run in background</Text>\n </Box>\n )}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["maxLines"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/SubagentBlock.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * SubagentBlock - Embedded subagent execution display\n *\n * Renders a complete subagent execution hierarchically with:\n * - Header (task name, agent type, status)\n * - Optional: Subtasks (if subagent has todos)\n * - Optional: Thinking phase\n * - Optional: Tool executions\n * - Optional: Response\n * - Footer (completion status)\n *\n * Supports collapsible internal content\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { SYMBOLS, getTodoStatusSymbol } from '@constants/symbols'\nimport { AgentThinkingBlock } from './AgentThinkingBlock'\nimport { ToolExecutionBlock } from './ToolExecutionBlock'\nimport { AgentResponseBlock } from './AgentResponseBlock'\nimport type { SubagentState } from '@minto-types/subagent'\nimport type { TodoItem } from '@utils/todoStorage'\nimport type { AssistantMessage } from '@minto-types/conversation'\nimport type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\n\ninterface Props {\n subagent: SubagentState\n indent?: number\n isExpanded?: boolean\n}\n\n/**\n * SubagentBlock - Hierarchical embedded subagent display\n *\n * Visual format (indent=1):\n * ```\n * \uD83E\uDD16 Launching subagent: backend-architect\n * \u251C\u2500 Task: Design authentication system\n * \u2502\n * \u2502 \uD83E\uDD14 Analyzing requirements... (300ms)\n * \u2502\n * \u2502 \uD83D\uDD27 Tool: Read package.json\n * \u2502 \u2514\u2500 \u2713 Read 50 lines (80ms)\n * \u2502\n * \u2502 \uD83D\uDCAC I recommend using JWT...\n * \u2502\n * \u2514\u2500 \u2713 Completed (2.5s, 1200 tokens)\n * ```\n */\nexport function SubagentBlock({\n subagent,\n indent = 0,\n isExpanded = false,\n}: Props): React.ReactNode {\n const theme = getTheme()\n const [expanded, setExpanded] = useState(isExpanded)\n const marginLeft = indent * 2\n\n // Extract todos if present (from subagent execution)\n const todos = extractSubagentTodos(subagent)\n const thinking = extractThinkingMessage(subagent)\n const toolExecutions = extractToolExecutions(subagent)\n const response = extractResponse(subagent)\n\n // Calculate metrics\n const duration = subagent.metrics.endTime\n ? ((subagent.metrics.endTime - subagent.metrics.startTime) / 1000).toFixed(\n 1,\n )\n : '...'\n const tokenCount = subagent.metrics.tokenCount || 0\n\n // Status indicator\n const statusIndicator = getStatusIndicator(subagent.status)\n const statusColor = getStatusColor(subagent.status, theme)\n\n return (\n <Box flexDirection=\"column\" marginLeft={marginLeft} marginTop={1}>\n {/* Subagent Header */}\n <Box flexDirection=\"row\">\n <Text color={theme.brand}>\uD83E\uDD16 </Text>\n <Text>\n Launching subagent: <Text bold>{subagent.agentType}</Text>\n </Text>\n </Box>\n\n {/* Task description */}\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u251C\u2500 </Text>\n <Text>Task: {subagent.taskName}</Text>\n </Box>\n\n {/* Collapsible internal content */}\n {expanded && (\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2502</Text>\n\n {/* Subagent subtasks (if present) */}\n {todos && todos.length > 0 && (\n <SubagentTodosSection todos={todos} theme={theme} />\n )}\n\n {/* Subagent thinking */}\n {thinking && (\n <Box flexDirection=\"column\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <AgentThinkingBlock\n message={thinking.message}\n startTime={thinking.startTime}\n showSpinner={subagent.status === 'running'}\n showElapsedTime={false}\n />\n </Box>\n )}\n\n {/* Subagent tool executions */}\n {toolExecutions.map((tool, idx) => (\n <Box key={idx} flexDirection=\"column\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <ToolExecutionBlock tool={tool} indent={0} />\n </Box>\n ))}\n\n {/* Subagent response */}\n {response && (\n <Box flexDirection=\"column\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <AgentResponseBlock\n message={response}\n indent={0}\n isSubagent={true}\n />\n </Box>\n )}\n\n <Text color={theme.dimmedText}>\u2502</Text>\n </Box>\n )}\n\n {/* Subagent Footer (completion status) */}\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2514\u2500 </Text>\n <Text color={statusColor}>\n {statusIndicator} {getStatusLabel(subagent.status)}\n </Text>\n {subagent.status === 'completed' && (\n <Text color={theme.mutedText}>\n {' '}\n ({duration}s, {tokenCount} tokens)\n </Text>\n )}\n </Box>\n\n {/* Expand/collapse hint (only when collapsed) */}\n {!expanded && (\n <Box flexDirection=\"row\" marginLeft={4}>\n <Text color={theme.mutedText}>\n Press <Text bold>Ctrl+O</Text> to expand details\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * SubagentTodosSection - Renders subagent's subtasks\n */\nfunction SubagentTodosSection({\n todos,\n theme,\n}: {\n todos: TodoItem[]\n theme: ReturnType<typeof getTheme>\n}) {\n return (\n <Box flexDirection=\"column\" marginLeft={1} marginY={1}>\n <Box flexDirection=\"row\">\n <Text color={theme.dimmedText}>\u2502 </Text>\n <Text color={theme.dimmedText}>Subtasks:</Text>\n </Box>\n {todos.map((todo, idx) => (\n <Box key={idx} flexDirection=\"row\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <Text>{getTodoStatusSymbol(todo.status)} </Text>\n <Text\n color={todo.status === 'completed' ? theme.dim : undefined}\n strikethrough={todo.status === 'completed'}\n >\n {todo.content}\n </Text>\n </Box>\n ))}\n </Box>\n )\n}\n\n/**\n * Helper: Extract todos from subagent messages\n * (This would be populated from TodoWriteTool calls within the subagent)\n */\nfunction extractSubagentTodos(subagent: SubagentState): TodoItem[] | null {\n // TODO: Implement extraction of todos from subagent messages\n // For now, return null (will be implemented in Phase 4)\n return null\n}\n\n/**\n * Helper: Extract thinking message from subagent\n */\nfunction extractThinkingMessage(\n subagent: SubagentState,\n): { message: string; startTime: number } | null {\n // Find thinking blocks in messages\n for (const msg of subagent.messages) {\n if (msg.type === 'assistant' && 'message' in msg) {\n const thinkingBlock = msg.message.content.find(\n (block: any) => block.type === 'thinking',\n )\n if (thinkingBlock && 'thinking' in thinkingBlock) {\n return {\n message: thinkingBlock.thinking || 'Thinking...',\n startTime: subagent.metrics.startTime,\n }\n }\n }\n }\n return null\n}\n\n/**\n * Helper: Extract tool executions from subagent\n */\nfunction extractToolExecutions(subagent: SubagentState): Array<{\n id: string\n name: string\n input: any\n status: 'pending' | 'running' | 'completed' | 'error'\n startTime: number\n durationMs?: number\n}> {\n const tools: Array<any> = []\n\n // Extract tool_use blocks from messages\n for (const msg of subagent.messages) {\n if (msg.type === 'assistant' && 'message' in msg) {\n const toolBlocks = msg.message.content.filter(\n (block: any) => block.type === 'tool_use',\n )\n for (const toolBlock of toolBlocks) {\n if ('name' in toolBlock && 'id' in toolBlock) {\n tools.push({\n id: toolBlock.id,\n name: toolBlock.name,\n input: toolBlock.input,\n status: 'completed', // Simplified for now\n startTime: subagent.metrics.startTime,\n durationMs: 100, // Placeholder\n })\n }\n }\n }\n }\n\n return tools\n}\n\n/**\n * Helper: Extract response message from subagent\n */\nfunction extractResponse(subagent: SubagentState): AssistantMessage | null {\n // Find last assistant message with text content\n for (let i = subagent.messages.length - 1; i >= 0; i--) {\n const msg = subagent.messages[i]\n if (msg.type === 'assistant' && 'message' in msg) {\n const hasText = msg.message.content.some(\n (block: any) => block.type === 'text' && block.text.trim(),\n )\n if (hasText) {\n return msg as AssistantMessage\n }\n }\n }\n return null\n}\n\n/**\n * Helper: Get status indicator symbol\n */\nfunction getStatusIndicator(status: SubagentState['status']): string {\n switch (status) {\n case 'initializing':\n return '\u25CB'\n case 'queued':\n return '\u2139'\n case 'running':\n return '\u22EF'\n case 'completed':\n return '\u2713'\n case 'error':\n return '\u2716'\n }\n}\n\n/**\n * Helper: Get status color\n */\nfunction getStatusColor(\n status: SubagentState['status'],\n theme: ReturnType<typeof getTheme>,\n): string {\n switch (status) {\n case 'completed':\n return theme.success\n case 'error':\n return theme.error\n case 'running':\n return theme.brand\n default:\n return theme.dimmedText\n }\n}\n\n/**\n * Helper: Get status label\n */\nfunction getStatusLabel(status: SubagentState['status']): string {\n switch (status) {\n case 'initializing':\n return 'Initializing...'\n case 'queued':\n return 'Queued'\n case 'running':\n return 'Running...'\n case 'completed':\n return 'Completed'\n case 'error':\n return 'Error'\n }\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * SubagentBlock - Embedded subagent execution display\n *\n * Renders a complete subagent execution hierarchically with:\n * - Header (task name, agent type, status)\n * - Optional: Subtasks (if subagent has todos)\n * - Optional: Thinking phase\n * - Optional: Tool executions\n * - Optional: Response\n * - Footer (completion status)\n *\n * Supports collapsible internal content\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { SYMBOLS, getTodoStatusSymbol } from '@constants/symbols'\nimport { AgentThinkingBlock } from './AgentThinkingBlock'\nimport { ToolExecutionBlock } from './ToolExecutionBlock'\nimport { AgentResponseBlock } from './AgentResponseBlock'\nimport type { SubagentState } from '@minto-types/subagent'\nimport type { TodoItem } from '@utils/todoStorage'\nimport type { AssistantMessage } from '@minto-types/conversation'\nimport type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'\n\ninterface Props {\n subagent: SubagentState\n indent?: number\n isExpanded?: boolean\n}\n\n/**\n * SubagentBlock - Hierarchical embedded subagent display\n *\n * Visual format (indent=1):\n * ```\n * \uD83E\uDD16 Launching subagent: backend-architect\n * \u251C\u2500 Task: Design authentication system\n * \u2502\n * \u2502 \uD83E\uDD14 Analyzing requirements... (300ms)\n * \u2502\n * \u2502 \uD83D\uDD27 Tool: Read package.json\n * \u2502 \u2514\u2500 \u2713 Read 50 lines (80ms)\n * \u2502\n * \u2502 \uD83D\uDCAC I recommend using JWT...\n * \u2502\n * \u2514\u2500 \u2713 Completed (2.5s, 1200 tokens)\n * ```\n */\nexport function SubagentBlock({\n subagent,\n indent = 0,\n isExpanded = false,\n}: Props): React.ReactNode {\n const theme = getTheme()\n const [expanded, setExpanded] = useState(isExpanded)\n const marginLeft = indent * 2\n\n // Extract todos if present (from subagent execution)\n const todos = extractSubagentTodos(subagent)\n const thinking = extractThinkingMessage(subagent)\n const toolExecutions = extractToolExecutions(subagent)\n const response = extractResponse(subagent)\n\n // Calculate metrics\n const duration = subagent.metrics.endTime\n ? ((subagent.metrics.endTime - subagent.metrics.startTime) / 1000).toFixed(\n 1,\n )\n : '...'\n const tokenCount = subagent.metrics.tokenCount || 0\n\n // Status indicator\n const statusIndicator = getStatusIndicator(subagent.status)\n const statusColor = getStatusColor(subagent.status, theme)\n\n return (\n <Box flexDirection=\"column\" marginLeft={marginLeft} marginTop={1}>\n {/* Subagent Header */}\n <Box flexDirection=\"row\">\n <Text color={theme.brand}>\uD83E\uDD16 </Text>\n <Text>\n Launching subagent: <Text bold>{subagent.agentType}</Text>\n </Text>\n </Box>\n\n {/* Task description */}\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u251C\u2500 </Text>\n <Text>Task: {subagent.taskName}</Text>\n </Box>\n\n {/* Collapsible internal content */}\n {expanded && (\n <Box flexDirection=\"column\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2502</Text>\n\n {/* Subagent subtasks (if present) */}\n {todos && todos.length > 0 && (\n <SubagentTodosSection todos={todos} theme={theme} />\n )}\n\n {/* Subagent thinking */}\n {thinking && (\n <Box flexDirection=\"column\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <AgentThinkingBlock\n message={thinking.message}\n startTime={thinking.startTime}\n showSpinner={subagent.status === 'running'}\n showElapsedTime={false}\n />\n </Box>\n )}\n\n {/* Subagent tool executions */}\n {toolExecutions.map((tool, idx) => (\n <Box key={idx} flexDirection=\"column\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <ToolExecutionBlock tool={tool} indent={0} />\n </Box>\n ))}\n\n {/* Subagent response */}\n {response && (\n <Box flexDirection=\"column\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <AgentResponseBlock\n message={response}\n indent={0}\n isSubagent={true}\n />\n </Box>\n )}\n\n <Text color={theme.dimmedText}>\u2502</Text>\n </Box>\n )}\n\n {/* Subagent Footer (completion status) */}\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2514\u2500 </Text>\n <Text color={statusColor}>\n {statusIndicator} {getStatusLabel(subagent.status)}\n </Text>\n {subagent.status === 'completed' && (\n <Text color={theme.mutedText}>\n {' '}\n ({duration}s, {tokenCount} tokens)\n </Text>\n )}\n </Box>\n\n {/* Expand/collapse hint (only when collapsed) */}\n {!expanded && (\n <Box flexDirection=\"row\" marginLeft={4}>\n <Text color={theme.mutedText}>\n Press <Text bold>Ctrl+O</Text> to expand details\n </Text>\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * SubagentTodosSection - Renders subagent's subtasks\n */\nfunction SubagentTodosSection({\n todos,\n theme,\n}: {\n todos: TodoItem[]\n theme: ReturnType<typeof getTheme>\n}) {\n return (\n <Box flexDirection=\"column\" marginLeft={1} marginY={1}>\n <Box flexDirection=\"row\">\n <Text color={theme.dimmedText}>\u2502 </Text>\n <Text color={theme.dimmedText}>Subtasks:</Text>\n </Box>\n {todos.map((todo, idx) => (\n <Box key={idx} flexDirection=\"row\" marginLeft={1}>\n <Text color={theme.dimmedText}>\u2502 </Text>\n <Text>{getTodoStatusSymbol(todo.status)} </Text>\n <Text\n color={todo.status === 'completed' ? theme.dim : undefined}\n strikethrough={todo.status === 'completed'}\n >\n {todo.content}\n </Text>\n </Box>\n ))}\n </Box>\n )\n}\n\n/**\n * Helper: Extract todos from subagent messages\n * (This would be populated from TodoWriteTool calls within the subagent)\n */\nfunction extractSubagentTodos(subagent: SubagentState): TodoItem[] | null {\n // TODO: Implement extraction of todos from subagent messages\n // For now, return null (will be implemented in Phase 4)\n return null\n}\n\n/**\n * Helper: Extract thinking message from subagent\n */\nfunction extractThinkingMessage(\n subagent: SubagentState,\n): { message: string; startTime: number } | null {\n // Find thinking blocks in messages\n for (const msg of subagent.messages) {\n if (msg.type === 'assistant' && 'message' in msg) {\n const thinkingBlock = msg.message.content.find(\n (block: any) => block.type === 'thinking',\n )\n if (thinkingBlock && 'thinking' in thinkingBlock) {\n return {\n message: thinkingBlock.thinking || 'Thinking...',\n startTime: subagent.metrics.startTime,\n }\n }\n }\n }\n return null\n}\n\n/**\n * Helper: Extract tool executions from subagent\n */\nfunction extractToolExecutions(subagent: SubagentState): Array<{\n id: string\n name: string\n input: any\n status: 'pending' | 'running' | 'completed' | 'error'\n startTime: number\n durationMs?: number\n}> {\n const tools: Array<any> = []\n\n // Extract tool_use blocks from messages\n for (const msg of subagent.messages) {\n if (msg.type === 'assistant' && 'message' in msg) {\n const toolBlocks = msg.message.content.filter(\n (block: any) => block.type === 'tool_use',\n )\n for (const toolBlock of toolBlocks) {\n if ('name' in toolBlock && 'id' in toolBlock) {\n tools.push({\n id: toolBlock.id,\n name: toolBlock.name,\n input: toolBlock.input,\n status: 'completed', // Simplified for now\n startTime: subagent.metrics.startTime,\n durationMs: 100, // Placeholder\n })\n }\n }\n }\n }\n\n return tools\n}\n\n/**\n * Helper: Extract response message from subagent\n */\nfunction extractResponse(subagent: SubagentState): AssistantMessage | null {\n // Find last assistant message with text content\n for (let i = subagent.messages.length - 1; i >= 0; i--) {\n const msg = subagent.messages[i]\n if (msg.type === 'assistant' && 'message' in msg) {\n const hasText = msg.message.content.some(\n (block: any) => block.type === 'text' && block.text.trim(),\n )\n if (hasText) {\n return msg as AssistantMessage\n }\n }\n }\n return null\n}\n\n/**\n * Helper: Get status indicator symbol\n */\nfunction getStatusIndicator(status: SubagentState['status']): string {\n switch (status) {\n case 'initializing':\n return '\u25CB'\n case 'queued':\n return '\u2139'\n case 'running':\n return '\u22EF'\n case 'completed':\n return '\u2713'\n case 'error':\n return '\u2716'\n }\n}\n\n/**\n * Helper: Get status color\n */\nfunction getStatusColor(\n status: SubagentState['status'],\n theme: ReturnType<typeof getTheme>,\n): string {\n switch (status) {\n case 'completed':\n return theme.success\n case 'error':\n return theme.error\n case 'running':\n return theme.brand\n default:\n return theme.dimmedText\n }\n}\n\n/**\n * Helper: Get status label\n */\nfunction getStatusLabel(status: SubagentState['status']): string {\n switch (status) {\n case 'initializing':\n return 'Initializing...'\n case 'queued':\n return 'Queued'\n case 'running':\n return 'Running...'\n case 'completed':\n return 'Done'\n case 'error':\n return 'Error'\n }\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { getTheme } from "../utils/theme.js";
|
|
4
4
|
import { formatNumber, formatDuration } from "../utils/format.js";
|
|
5
5
|
import { getAgentColor } from "../constants/colors.js";
|
|
6
6
|
import { SpinnerSymbol } from "./SpinnerSymbol.js";
|
|
7
7
|
import { Message } from "./Message.js";
|
|
8
|
+
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
8
9
|
function SubagentProgress({
|
|
9
10
|
subagent,
|
|
10
11
|
isExpanded,
|
|
@@ -16,15 +17,13 @@ function SubagentProgress({
|
|
|
16
17
|
const { metrics, taskName, status, messages, agentType, agentColor } = subagent;
|
|
17
18
|
const color = getAgentColor(agentColor, theme);
|
|
18
19
|
const isRunning = status === "initializing" || status === "running" || status === "queued";
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}, [isRunning]);
|
|
20
|
+
const startTimeRef = useRef(metrics.startTime);
|
|
21
|
+
const { elapsedTime } = useUnifiedAnimation({
|
|
22
|
+
enabled: isRunning,
|
|
23
|
+
startTime: startTimeRef.current,
|
|
24
|
+
spinnerFrameCount: 1,
|
|
25
|
+
componentId: `subagent-${subagent.id}`
|
|
26
|
+
});
|
|
28
27
|
const duration = metrics.endTime ? metrics.endTime - metrics.startTime : Date.now() - metrics.startTime;
|
|
29
28
|
const statusText = getStatusText(status);
|
|
30
29
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 0 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(SpinnerSymbol, { isRunning, color: agentColor }), /* @__PURE__ */ React.createElement(Text, null, " Task(", taskName, ")")), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: theme.dim }, " \u23BFS1 "), /* @__PURE__ */ React.createElement(Text, { color: getStatusColor(status, theme) }, statusText), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, metrics.toolUseCount, " tool use", metrics.toolUseCount !== 1 ? "s" : ""), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, formatNumber(metrics.tokenCount), " tokens"), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, formatDuration(duration)), !isExpanded && /* @__PURE__ */ React.createElement(Text, { color: theme.dim }, " \xB7 (ctrl-o to expand)")), isExpanded && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 0 }, renderExpandedView(subagent, theme, tools, verbose)));
|
|
@@ -70,7 +69,7 @@ function getStatusText(status) {
|
|
|
70
69
|
case "running":
|
|
71
70
|
return "In progress\u2026";
|
|
72
71
|
case "completed":
|
|
73
|
-
return "
|
|
72
|
+
return "Done";
|
|
74
73
|
case "error":
|
|
75
74
|
return "Error";
|
|
76
75
|
}
|