@within-7/minto 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,10 +1,10 @@
|
|
|
1
1
|
import React, { useRef } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { getTheme } from "../utils/theme.js";
|
|
4
|
-
import { formatDuration } from "../utils/format.js";
|
|
4
|
+
import { formatNumber, formatDuration } from "../utils/format.js";
|
|
5
5
|
import { getAgentColor, SYMBOL_COLORS } from "../constants/colors.js";
|
|
6
6
|
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
7
|
-
import { useAgentTokenStats
|
|
7
|
+
import { useAgentTokenStats } from "../hooks/useAgentTokenStats.js";
|
|
8
8
|
function TaskCard({
|
|
9
9
|
subagent,
|
|
10
10
|
isExpanded = false,
|
|
@@ -34,7 +34,7 @@ function TaskCard({
|
|
|
34
34
|
const latestMessage = getLatestMessage(messages);
|
|
35
35
|
const cardBgColor = isHighlighted ? theme.selectionBg : "#6A7B8E";
|
|
36
36
|
const isCompleted = status === "completed" || status === "error";
|
|
37
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 0 }, !isCompleted && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color }, statusIcon, " "), /* @__PURE__ */ React.createElement(Text, { bold: true }, taskName), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, " \xB7 ", agentType)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u251C\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusText), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, metrics.toolUseCount, " tool", metrics.toolUseCount !== 1 ? "s" : ""), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText },
|
|
37
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginY: 0 }, !isCompleted && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color }, statusIcon, " "), /* @__PURE__ */ React.createElement(Text, { bold: true }, taskName), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, " \xB7 ", agentType)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u251C\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusText), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, metrics.toolUseCount, " tool", metrics.toolUseCount !== 1 ? "s" : ""), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, formatNumber(tokenCount), " tokens"), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, formatDuration(duration))), latestMessage && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, latestMessage)), messages.length > 0 && messages.map((msg, idx) => {
|
|
38
38
|
let content = "";
|
|
39
39
|
let prefix = "\u2190 ";
|
|
40
40
|
if (msg.type === "assistant") {
|
|
@@ -61,7 +61,7 @@ function TaskCard({
|
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
63
|
return /* @__PURE__ */ React.createElement(Box, { key: idx, flexDirection: "row", marginLeft: 4 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, prefix), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, content.substring(0, 80), content.length > 80 ? "..." : ""));
|
|
64
|
-
}).filter(Boolean)), isCompleted && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color }, statusIcon, " "), /* @__PURE__ */ React.createElement(Text, { bold: true }, taskName), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, " \xB7 ", agentType)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusText), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, metrics.toolUseCount, " tool", metrics.toolUseCount !== 1 ? "s" : ""), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText },
|
|
64
|
+
}).filter(Boolean)), isCompleted && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color }, statusIcon, " "), /* @__PURE__ */ React.createElement(Text, { bold: true }, taskName), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, " \xB7 ", agentType)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusText), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, metrics.toolUseCount, " tool", metrics.toolUseCount !== 1 ? "s" : ""), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, formatNumber(tokenCount), " tokens"), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " \xB7 "), /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, formatDuration(duration)), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, " (Ctrl+O to expand)")), isExpanded && messages.length > 0 && /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 4, marginTop: 1 }, renderTaskOutputLog(subagent, theme, tools, verbose))), debug && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: theme.info }, "[View Details]"), /* @__PURE__ */ React.createElement(Text, null, " "), isRunning && /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.error }, "[Cancel]")));
|
|
65
65
|
}
|
|
66
66
|
function getStatusIcon(status, isRunning) {
|
|
67
67
|
if (isRunning) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/TaskCard.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * TaskCard - Claude Code CLI \u98CE\u683C\u7684\u4EFB\u52A1\u5361\u7247\u7EC4\u4EF6\n *\n * \u6838\u5FC3\u7279\u6027\uFF1A\n * 1. **\u5361\u7247\u5F0F\u8BBE\u8BA1** - \u72EC\u7ACB\u7684\u89C6\u89C9\u5355\u5143\uFF0C\u4E0E\u4E3B\u5BF9\u8BDD\u6D41\u533A\u5206\n * 2. **\u72B6\u6001\u6E05\u6670** - \u901A\u8FC7\u56FE\u6807\u548C\u989C\u8272\u660E\u786E\u4F20\u8FBE\u4EFB\u52A1\u72B6\u6001\n * 3. **\u53EF\u6298\u53E0** - \u8BE6\u7EC6\u65E5\u5FD7\u53EF\u6298\u53E0\uFF0C\u8282\u7701\u7A7A\u95F4\n * 4. **\u8FDB\u5EA6\u53EF\u89C6\u5316** - \u663E\u793A\u4EFB\u52A1\u8FDB\u5EA6\u767E\u5206\u6BD4\u548C\u6307\u6807\n * 5. **\u5E76\u53D1\u53CB\u597D** - \u591A\u4E2A\u5361\u7247\u5E76\u5217\u663E\u793A\u4E0D\u6DF7\u4E71\n *\n * \u57FA\u4E8E Claude Code CLI \u7684 TaskCardBlock \u89C4\u8303\n * \u4F7F\u7528\u7EDF\u4E00\u52A8\u753B\u7BA1\u7406\u5668\u4EE3\u66FF setInterval\uFF0C\u51CF\u5C11\u5C4F\u5E55\u95EA\u70C1\n */\n\nimport React, { useRef } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { formatNumber, formatDuration } from '@utils/format'\nimport { getAgentColor, SYMBOL_COLORS } from '@constants/colors'\nimport type { SubagentState } from '@minto-types/subagent'\nimport type { Tool } from '@tool'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { useAgentTokenStats, formatTokenCount } from '@hooks/useAgentTokenStats'\n\ninterface TaskCardProps {\n /** \u5B50\u4EFB\u52A1\u72B6\u6001 */\n subagent: SubagentState\n\n /** \u662F\u5426\u5C55\u5F00\u8BE6\u7EC6\u65E5\u5FD7 */\n isExpanded?: boolean\n\n /** \u662F\u5426\u9AD8\u4EAE\uFF08\u9700\u8981\u7528\u6237\u5173\u6CE8\uFF09 */\n isHighlighted?: boolean\n\n /** \u5DE5\u5177\u5217\u8868 */\n tools?: Tool[]\n\n /** \u662F\u5426\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F */\n verbose?: boolean\n\n /** \u8C03\u8BD5\u6A21\u5F0F */\n debug?: boolean\n\n /** \u6298\u53E0/\u5C55\u5F00\u56DE\u8C03 */\n onToggleExpand?: () => void\n}\n\n/**\n * TaskCard - \u5355\u4E2A\u5B50\u4EFB\u52A1\u7684\u52A8\u6001\u5C55\u793A\uFF08\u65E0\u8FB9\u6846\uFF09\n *\n * \u8FD0\u884C\u4E2D\u5E03\u5C40\uFF08\u81EA\u52A8\u5C55\u5F00\uFF09:\n * ```\n * \u280B Feature Implementation \u00B7 backend-architect\n * \u251C\u2500 Running \u00B7 3 tools \u00B7 5.2k tokens \u00B7 12s\n * \u2514\u2500 Analyzing code structure...\n * \u2192 Tool call output message...\n * \u2190 Assistant response...\n * ```\n *\n * \u5B8C\u6210\u540E\u5E03\u5C40\uFF08\u81EA\u52A8\u6298\u53E0\uFF09:\n * ```\n * \u2713 Feature Implementation \u00B7 backend-architect\n * \u2514\u2500 Done \u00B7 5 tools \u00B7 8.3k tokens \u00B7 24s (Ctrl+O to expand)\n * ```\n *\n * \u5B8C\u6210\u540E\u5C55\u5F00\uFF08Ctrl+O\uFF09:\n * ```\n * \u2713 Feature Implementation \u00B7 backend-architect\n * \u2514\u2500 Done \u00B7 5 tools \u00B7 8.3k tokens \u00B7 24s (Ctrl+O to expand)\n * [\u8BE6\u7EC6\u7684\u6267\u884C\u8FC7\u7A0B\u65E5\u5FD7]\n * ```\n */\nexport function TaskCard({\n subagent,\n isExpanded = false,\n isHighlighted = false,\n tools = [],\n verbose = false,\n debug = false,\n onToggleExpand,\n}: TaskCardProps): React.ReactNode {\n const theme = getTheme()\n const { metrics, taskName, status, messages, agentType, agentColor } =\n subagent\n\n // Get real-time token stats from unified TokenStatsManager\n const tokenStats = useAgentTokenStats(subagent.id)\n const tokenCount = tokenStats?.grandTotalTokens ?? 0\n\n // \u83B7\u53D6 agent \u989C\u8272\n const color = getAgentColor(agentColor, theme)\n\n // \u5224\u65AD\u662F\u5426\u6B63\u5728\u8FD0\u884C\n const isRunning =\n status === 'initializing' || status === 'running' || status === 'queued'\n\n // Use unified animation manager for periodic time updates\n const startTimeRef = useRef(metrics.startTime)\n const { elapsedTime } = useUnifiedAnimation({\n enabled: isRunning,\n startTime: startTimeRef.current,\n spinnerFrameCount: 1,\n componentId: `task-card-${subagent.id}`,\n })\n\n // \u8BA1\u7B97\u6301\u7EED\u65F6\u95F4\n const duration = metrics.endTime\n ? metrics.endTime - metrics.startTime\n : Date.now() - metrics.startTime\n\n // \u72B6\u6001\u56FE\u6807\u548C\u6587\u672C\n const statusIcon = getStatusIcon(status, isRunning)\n const statusText = getStatusText(status)\n const statusColor = getStatusColor(status, theme)\n\n // \u83B7\u53D6\u6700\u65B0\u7684\u72B6\u6001\u6D88\u606F\n const latestMessage = getLatestMessage(messages)\n\n // \u5361\u7247\u80CC\u666F\u8272\uFF08\u6839\u636E\u72B6\u6001\u548C\u9AD8\u4EAE\uFF09\n const cardBgColor = isHighlighted\n ? theme.selectionBg // #3C3C3C\n : '#6A7B8E' // Task Card BG\n\n // \u5224\u65AD\u662F\u5426\u5DF2\u5B8C\u6210\uFF08completed \u6216 error\uFF09\n const isCompleted = status === 'completed' || status === 'error'\n\n return (\n <Box flexDirection=\"column\" marginY={0}>\n {/* \u8FD0\u884C\u4E2D\uFF1A\u5C55\u5F00\u663E\u793A\u6240\u6709\u5185\u5BB9 */}\n {!isCompleted && (\n <>\n {/* TaskHeader - \u4EFB\u52A1\u540D\u79F0\u548C Agent \u7C7B\u578B */}\n <Box flexDirection=\"row\">\n <Text color={color}>{statusIcon} </Text>\n <Text bold>{taskName}</Text>\n <Text color={theme.dimmedText}> \u00B7 {agentType}</Text>\n </Box>\n\n {/* TaskProgress - \u72B6\u6001\u548C\u6307\u6807 */}\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u251C\u2500 </Text>\n <Text color={statusColor}>{statusText}</Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {metrics.toolUseCount} tool{metrics.toolUseCount !== 1 ? 's' : ''}\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {formatTokenCount(tokenCount)} tokens\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>{formatDuration(duration)}</Text>\n </Box>\n\n {/* TaskStatusMessage - \u5F53\u524D\u6B63\u5728\u505A\u4EC0\u4E48 */}\n {latestMessage && (\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2514\u2500 </Text>\n <Text color={theme.dimmedText}>{latestMessage}</Text>\n </Box>\n )}\n\n {/* Output messages - \u76F4\u63A5\u663E\u793A\u4E3A\u5B50\u5C42\u7EA7\uFF0C\u65E0 \"Output Log\" \u6807\u9898 */}\n {messages.length > 0 &&\n messages\n .map((msg, idx) => {\n // Extract text content based on message type\n let content = ''\n let prefix = '\u2190 '\n\n if (msg.type === 'assistant') {\n prefix = '\u2192 '\n const blocks = msg.message.content\n content = blocks\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join(' ')\n } else if (msg.type === 'user') {\n const msgParam = msg.message as any\n if (typeof msgParam.content === 'string') {\n content = msgParam.content\n } else if (Array.isArray(msgParam.content)) {\n content = msgParam.content\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join(' ')\n }\n } else if (msg.type === 'progress') {\n prefix = '\u2699 '\n // Handle both AssistantMessage and StreamingProgressContent\n if (\n 'type' in msg.content &&\n msg.content.type === 'streaming'\n ) {\n // StreamingProgressContent - show stdout/stderr preview\n content =\n msg.content.stdout ||\n msg.content.stderr ||\n '(streaming...)'\n } else if ('message' in msg.content) {\n // AssistantMessage\n const blocks = (msg.content as any).message.content\n content = blocks\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join(' ')\n }\n }\n\n if (!content || content.trim().length === 0) {\n return null\n }\n\n return (\n <Box key={idx} flexDirection=\"row\" marginLeft={4}>\n <Text color={theme.dimmedText}>{prefix}</Text>\n <Text color={theme.mutedText}>\n {content.substring(0, 80)}\n {content.length > 80 ? '...' : ''}\n </Text>\n </Box>\n )\n })\n .filter(Boolean)}\n </>\n )}\n\n {/* \u5DF2\u5B8C\u6210\uFF1A\u6298\u53E0\u6210\u4E00\u884C\uFF0C\u5E26\u5C55\u5F00\u63D0\u793A */}\n {isCompleted && (\n <>\n <Box flexDirection=\"row\">\n <Text color={color}>{statusIcon} </Text>\n <Text bold>{taskName}</Text>\n <Text color={theme.dimmedText}> \u00B7 {agentType}</Text>\n </Box>\n\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2514\u2500 </Text>\n <Text color={statusColor}>{statusText}</Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {metrics.toolUseCount} tool{metrics.toolUseCount !== 1 ? 's' : ''}\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {formatTokenCount(tokenCount)} tokens\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>{formatDuration(duration)}</Text>\n <Text color={theme.dimmedText}> (Ctrl+O to expand)</Text>\n </Box>\n\n {/* \u5C55\u5F00\u65F6\u663E\u793A\u8BE6\u7EC6\u8FC7\u7A0B */}\n {isExpanded && messages.length > 0 && (\n <Box flexDirection=\"column\" marginLeft={4} marginTop={1}>\n {renderTaskOutputLog(subagent, theme, tools, verbose)}\n </Box>\n )}\n </>\n )}\n\n {/* TaskActionButtons - \u64CD\u4F5C\u6309\u94AE (\u672A\u6765\u6269\u5C55) */}\n {debug && (\n <Box flexDirection=\"row\" marginTop={1}>\n <Text color={theme.info}>[View Details]</Text>\n <Text> </Text>\n {isRunning && <Text color={SYMBOL_COLORS.error}>[Cancel]</Text>}\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * \u83B7\u53D6\u72B6\u6001\u56FE\u6807\n */\nfunction getStatusIcon(\n status: SubagentState['status'],\n isRunning: boolean,\n): string {\n if (isRunning) {\n // \u4F7F\u7528 Spinner \u5B57\u7B26\u8F6E\u8F6C (\u7B80\u5316\u7248)\n const spinnerFrames = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F']\n const frame = Math.floor(Date.now() / 120) % spinnerFrames.length\n return spinnerFrames[frame] || '\u280B'\n }\n\n switch (status) {\n case 'completed':\n return '\u2713'\n case 'error':\n return '\u2715'\n case 'queued':\n return '\u2026'\n default:\n return '\u25E6'\n }\n}\n\n/**\n * \u83B7\u53D6\u72B6\u6001\u6587\u672C\n */\nfunction getStatusText(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\n/**\n * \u83B7\u53D6\u72B6\u6001\u989C\u8272 - \u4F7F\u7528 SYMBOL_COLORS \u4E0E Logo \u54C1\u724C\u914D\u8272\u4FDD\u6301\u4E00\u81F4\n */\nfunction getStatusColor(\n status: SubagentState['status'],\n theme: ReturnType<typeof getTheme>,\n): string {\n switch (status) {\n case 'initializing':\n case 'queued':\n return SYMBOL_COLORS.pending // \u7070\u8272 - \u7B49\u5F85\n case 'running':\n return SYMBOL_COLORS.running // \u7C89\u7D2B - \u8FDB\u884C\u4E2D\n case 'completed':\n return SYMBOL_COLORS.success // \u7D2B\u84DD - \u5B8C\u6210\n case 'error':\n return SYMBOL_COLORS.error // \u73CA\u745A\u7EA2 - \u9519\u8BEF\n }\n}\n\n/**\n * \u83B7\u53D6\u6700\u65B0\u7684\u72B6\u6001\u6D88\u606F\n */\nfunction getLatestMessage(messages: SubagentState['messages']): string | null {\n if (messages.length === 0) return null\n\n // \u5012\u5E8F\u67E5\u627E\u6700\u65B0\u7684\u6587\u672C\u6D88\u606F\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg?.type === 'assistant' && msg.message?.content) {\n for (const content of msg.message.content) {\n if (content.type === 'text' && content.text.trim()) {\n // \u622A\u53D6\u524D 60 \u4E2A\u5B57\u7B26\n const text = content.text.trim()\n return text.length > 60 ? text.substring(0, 60) + '...' : text\n }\n if (content.type === 'tool_use') {\n return `Using ${content.name}...`\n }\n }\n }\n }\n\n return null\n}\n\n/**\n * \u6E32\u67D3\u8BE6\u7EC6\u7684\u8F93\u51FA\u65E5\u5FD7\n */\nfunction renderTaskOutputLog(\n subagent: SubagentState,\n theme: ReturnType<typeof getTheme>,\n tools: Tool[],\n verbose: boolean,\n): React.ReactNode {\n const { messages } = subagent\n\n return (\n <Box flexDirection=\"column\">\n {messages.map((msg, idx) => {\n if (msg.type === 'assistant') {\n return msg.message.content.map((content, contentIdx) => {\n if (content.type === 'tool_use') {\n const tool = tools.find(t => t.name === content.name)\n const toolName = tool?.userFacingName\n ? typeof tool.userFacingName === 'function'\n ? tool.userFacingName()\n : tool.userFacingName\n : content.name\n\n return (\n <Box key={`${idx}-${contentIdx}`} flexDirection=\"row\">\n <Text color={theme.info}>\uD83D\uDD27 {toolName}</Text>\n </Box>\n )\n } else if (content.type === 'text' && content.text.trim()) {\n const lines = content.text.trim().split('\\n')\n return (\n <Box key={`${idx}-${contentIdx}`} flexDirection=\"column\">\n {lines.map((line, lineIdx) => (\n <Text color={theme.secondaryText}>{line}</Text>\n ))}\n </Box>\n )\n }\n return null\n })\n } else if (msg.type === 'user') {\n return msg.message.content.map((content, contentIdx) => {\n if (content.type === 'tool_result') {\n const resultContent = Array.isArray(content.content)\n ? content.content.find(c => c.type === 'text')?.text\n : typeof content.content === 'string'\n ? content.content\n : ''\n\n if (resultContent && resultContent.trim()) {\n const lines = resultContent.trim().split('\\n')\n const preview =\n lines.length > 5\n ? lines.slice(0, 5).join('\\n') + '\\n...'\n : resultContent.trim()\n\n return (\n <Box key={`${idx}-${contentIdx}`} flexDirection=\"column\">\n {preview.split('\\n').map((line, lineIdx) => (\n <Text color={theme.mutedText}>{line}</Text>\n ))}\n </Box>\n )\n }\n }\n return null\n })\n }\n return null\n })}\n </Box>\n )\n}\n\n/**\n * \u7D27\u51D1\u7248 TaskCard (\u7528\u4E8E\u7A7A\u95F4\u53D7\u9650\u7684\u573A\u666F)\n */\nexport function CompactTaskCard({\n subagent,\n}: {\n subagent: SubagentState\n}): React.ReactNode {\n const theme = getTheme()\n const { taskName, status, agentColor } = subagent\n\n const color = getAgentColor(agentColor, theme)\n const isRunning =\n status === 'initializing' || status === 'running' || status === 'queued'\n const statusIcon = getStatusIcon(status, isRunning)\n\n return (\n <Box flexDirection=\"row\">\n <Text color={color}>\n {statusIcon} {taskName}\n </Text>\n <Text color={theme.dimmedText}> \u00B7 {getStatusText(status)}</Text>\n </Box>\n )\n}\n"],
|
|
5
|
-
"mappings": "AAcA,OAAO,SAAS,cAAc;AAC9B,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB;AACzB,
|
|
4
|
+
"sourcesContent": ["/**\n * TaskCard - Claude Code CLI \u98CE\u683C\u7684\u4EFB\u52A1\u5361\u7247\u7EC4\u4EF6\n *\n * \u6838\u5FC3\u7279\u6027\uFF1A\n * 1. **\u5361\u7247\u5F0F\u8BBE\u8BA1** - \u72EC\u7ACB\u7684\u89C6\u89C9\u5355\u5143\uFF0C\u4E0E\u4E3B\u5BF9\u8BDD\u6D41\u533A\u5206\n * 2. **\u72B6\u6001\u6E05\u6670** - \u901A\u8FC7\u56FE\u6807\u548C\u989C\u8272\u660E\u786E\u4F20\u8FBE\u4EFB\u52A1\u72B6\u6001\n * 3. **\u53EF\u6298\u53E0** - \u8BE6\u7EC6\u65E5\u5FD7\u53EF\u6298\u53E0\uFF0C\u8282\u7701\u7A7A\u95F4\n * 4. **\u8FDB\u5EA6\u53EF\u89C6\u5316** - \u663E\u793A\u4EFB\u52A1\u8FDB\u5EA6\u767E\u5206\u6BD4\u548C\u6307\u6807\n * 5. **\u5E76\u53D1\u53CB\u597D** - \u591A\u4E2A\u5361\u7247\u5E76\u5217\u663E\u793A\u4E0D\u6DF7\u4E71\n *\n * \u57FA\u4E8E Claude Code CLI \u7684 TaskCardBlock \u89C4\u8303\n * \u4F7F\u7528\u7EDF\u4E00\u52A8\u753B\u7BA1\u7406\u5668\u4EE3\u66FF setInterval\uFF0C\u51CF\u5C11\u5C4F\u5E55\u95EA\u70C1\n */\n\nimport React, { useRef } from 'react'\nimport { Box, Text } from 'ink'\nimport { getTheme } from '@utils/theme'\nimport { formatNumber, formatDuration } from '@utils/format'\nimport { getAgentColor, SYMBOL_COLORS } from '@constants/colors'\nimport type { SubagentState } from '@minto-types/subagent'\nimport type { Tool } from '@tool'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { useAgentTokenStats } from '@hooks/useAgentTokenStats'\n\ninterface TaskCardProps {\n /** \u5B50\u4EFB\u52A1\u72B6\u6001 */\n subagent: SubagentState\n\n /** \u662F\u5426\u5C55\u5F00\u8BE6\u7EC6\u65E5\u5FD7 */\n isExpanded?: boolean\n\n /** \u662F\u5426\u9AD8\u4EAE\uFF08\u9700\u8981\u7528\u6237\u5173\u6CE8\uFF09 */\n isHighlighted?: boolean\n\n /** \u5DE5\u5177\u5217\u8868 */\n tools?: Tool[]\n\n /** \u662F\u5426\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F */\n verbose?: boolean\n\n /** \u8C03\u8BD5\u6A21\u5F0F */\n debug?: boolean\n\n /** \u6298\u53E0/\u5C55\u5F00\u56DE\u8C03 */\n onToggleExpand?: () => void\n}\n\n/**\n * TaskCard - \u5355\u4E2A\u5B50\u4EFB\u52A1\u7684\u52A8\u6001\u5C55\u793A\uFF08\u65E0\u8FB9\u6846\uFF09\n *\n * \u8FD0\u884C\u4E2D\u5E03\u5C40\uFF08\u81EA\u52A8\u5C55\u5F00\uFF09:\n * ```\n * \u280B Feature Implementation \u00B7 backend-architect\n * \u251C\u2500 Running \u00B7 3 tools \u00B7 5.2k tokens \u00B7 12s\n * \u2514\u2500 Analyzing code structure...\n * \u2192 Tool call output message...\n * \u2190 Assistant response...\n * ```\n *\n * \u5B8C\u6210\u540E\u5E03\u5C40\uFF08\u81EA\u52A8\u6298\u53E0\uFF09:\n * ```\n * \u2713 Feature Implementation \u00B7 backend-architect\n * \u2514\u2500 Done \u00B7 5 tools \u00B7 8.3k tokens \u00B7 24s (Ctrl+O to expand)\n * ```\n *\n * \u5B8C\u6210\u540E\u5C55\u5F00\uFF08Ctrl+O\uFF09:\n * ```\n * \u2713 Feature Implementation \u00B7 backend-architect\n * \u2514\u2500 Done \u00B7 5 tools \u00B7 8.3k tokens \u00B7 24s (Ctrl+O to expand)\n * [\u8BE6\u7EC6\u7684\u6267\u884C\u8FC7\u7A0B\u65E5\u5FD7]\n * ```\n */\nexport function TaskCard({\n subagent,\n isExpanded = false,\n isHighlighted = false,\n tools = [],\n verbose = false,\n debug = false,\n onToggleExpand,\n}: TaskCardProps): React.ReactNode {\n const theme = getTheme()\n const { metrics, taskName, status, messages, agentType, agentColor } =\n subagent\n\n // Get real-time token stats from unified TokenStatsManager\n const tokenStats = useAgentTokenStats(subagent.id)\n const tokenCount = tokenStats?.grandTotalTokens ?? 0\n\n // \u83B7\u53D6 agent \u989C\u8272\n const color = getAgentColor(agentColor, theme)\n\n // \u5224\u65AD\u662F\u5426\u6B63\u5728\u8FD0\u884C\n const isRunning =\n status === 'initializing' || status === 'running' || status === 'queued'\n\n // Use unified animation manager for periodic time updates\n const startTimeRef = useRef(metrics.startTime)\n const { elapsedTime } = useUnifiedAnimation({\n enabled: isRunning,\n startTime: startTimeRef.current,\n spinnerFrameCount: 1,\n componentId: `task-card-${subagent.id}`,\n })\n\n // \u8BA1\u7B97\u6301\u7EED\u65F6\u95F4\n const duration = metrics.endTime\n ? metrics.endTime - metrics.startTime\n : Date.now() - metrics.startTime\n\n // \u72B6\u6001\u56FE\u6807\u548C\u6587\u672C\n const statusIcon = getStatusIcon(status, isRunning)\n const statusText = getStatusText(status)\n const statusColor = getStatusColor(status, theme)\n\n // \u83B7\u53D6\u6700\u65B0\u7684\u72B6\u6001\u6D88\u606F\n const latestMessage = getLatestMessage(messages)\n\n // \u5361\u7247\u80CC\u666F\u8272\uFF08\u6839\u636E\u72B6\u6001\u548C\u9AD8\u4EAE\uFF09\n const cardBgColor = isHighlighted\n ? theme.selectionBg // #3C3C3C\n : '#6A7B8E' // Task Card BG\n\n // \u5224\u65AD\u662F\u5426\u5DF2\u5B8C\u6210\uFF08completed \u6216 error\uFF09\n const isCompleted = status === 'completed' || status === 'error'\n\n return (\n <Box flexDirection=\"column\" marginY={0}>\n {/* \u8FD0\u884C\u4E2D\uFF1A\u5C55\u5F00\u663E\u793A\u6240\u6709\u5185\u5BB9 */}\n {!isCompleted && (\n <>\n {/* TaskHeader - \u4EFB\u52A1\u540D\u79F0\u548C Agent \u7C7B\u578B */}\n <Box flexDirection=\"row\">\n <Text color={color}>{statusIcon} </Text>\n <Text bold>{taskName}</Text>\n <Text color={theme.dimmedText}> \u00B7 {agentType}</Text>\n </Box>\n\n {/* TaskProgress - \u72B6\u6001\u548C\u6307\u6807 */}\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u251C\u2500 </Text>\n <Text color={statusColor}>{statusText}</Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {metrics.toolUseCount} tool{metrics.toolUseCount !== 1 ? 's' : ''}\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {formatNumber(tokenCount)} tokens\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>{formatDuration(duration)}</Text>\n </Box>\n\n {/* TaskStatusMessage - \u5F53\u524D\u6B63\u5728\u505A\u4EC0\u4E48 */}\n {latestMessage && (\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2514\u2500 </Text>\n <Text color={theme.dimmedText}>{latestMessage}</Text>\n </Box>\n )}\n\n {/* Output messages - \u76F4\u63A5\u663E\u793A\u4E3A\u5B50\u5C42\u7EA7\uFF0C\u65E0 \"Output Log\" \u6807\u9898 */}\n {messages.length > 0 &&\n messages\n .map((msg, idx) => {\n // Extract text content based on message type\n let content = ''\n let prefix = '\u2190 '\n\n if (msg.type === 'assistant') {\n prefix = '\u2192 '\n const blocks = msg.message.content\n content = blocks\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join(' ')\n } else if (msg.type === 'user') {\n const msgParam = msg.message as any\n if (typeof msgParam.content === 'string') {\n content = msgParam.content\n } else if (Array.isArray(msgParam.content)) {\n content = msgParam.content\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join(' ')\n }\n } else if (msg.type === 'progress') {\n prefix = '\u2699 '\n // Handle both AssistantMessage and StreamingProgressContent\n if (\n 'type' in msg.content &&\n msg.content.type === 'streaming'\n ) {\n // StreamingProgressContent - show stdout/stderr preview\n content =\n msg.content.stdout ||\n msg.content.stderr ||\n '(streaming...)'\n } else if ('message' in msg.content) {\n // AssistantMessage\n const blocks = (msg.content as any).message.content\n content = blocks\n .filter((block: any) => block.type === 'text')\n .map((block: any) => block.text)\n .join(' ')\n }\n }\n\n if (!content || content.trim().length === 0) {\n return null\n }\n\n return (\n <Box key={idx} flexDirection=\"row\" marginLeft={4}>\n <Text color={theme.dimmedText}>{prefix}</Text>\n <Text color={theme.mutedText}>\n {content.substring(0, 80)}\n {content.length > 80 ? '...' : ''}\n </Text>\n </Box>\n )\n })\n .filter(Boolean)}\n </>\n )}\n\n {/* \u5DF2\u5B8C\u6210\uFF1A\u6298\u53E0\u6210\u4E00\u884C\uFF0C\u5E26\u5C55\u5F00\u63D0\u793A */}\n {isCompleted && (\n <>\n <Box flexDirection=\"row\">\n <Text color={color}>{statusIcon} </Text>\n <Text bold>{taskName}</Text>\n <Text color={theme.dimmedText}> \u00B7 {agentType}</Text>\n </Box>\n\n <Box flexDirection=\"row\" marginLeft={2}>\n <Text color={theme.dimmedText}>\u2514\u2500 </Text>\n <Text color={statusColor}>{statusText}</Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {metrics.toolUseCount} tool{metrics.toolUseCount !== 1 ? 's' : ''}\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>\n {formatNumber(tokenCount)} tokens\n </Text>\n <Text color={theme.mutedText}> \u00B7 </Text>\n <Text color={theme.mutedText}>{formatDuration(duration)}</Text>\n <Text color={theme.dimmedText}> (Ctrl+O to expand)</Text>\n </Box>\n\n {/* \u5C55\u5F00\u65F6\u663E\u793A\u8BE6\u7EC6\u8FC7\u7A0B */}\n {isExpanded && messages.length > 0 && (\n <Box flexDirection=\"column\" marginLeft={4} marginTop={1}>\n {renderTaskOutputLog(subagent, theme, tools, verbose)}\n </Box>\n )}\n </>\n )}\n\n {/* TaskActionButtons - \u64CD\u4F5C\u6309\u94AE (\u672A\u6765\u6269\u5C55) */}\n {debug && (\n <Box flexDirection=\"row\" marginTop={1}>\n <Text color={theme.info}>[View Details]</Text>\n <Text> </Text>\n {isRunning && <Text color={SYMBOL_COLORS.error}>[Cancel]</Text>}\n </Box>\n )}\n </Box>\n )\n}\n\n/**\n * \u83B7\u53D6\u72B6\u6001\u56FE\u6807\n */\nfunction getStatusIcon(\n status: SubagentState['status'],\n isRunning: boolean,\n): string {\n if (isRunning) {\n // \u4F7F\u7528 Spinner \u5B57\u7B26\u8F6E\u8F6C (\u7B80\u5316\u7248)\n const spinnerFrames = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F']\n const frame = Math.floor(Date.now() / 120) % spinnerFrames.length\n return spinnerFrames[frame] || '\u280B'\n }\n\n switch (status) {\n case 'completed':\n return '\u2713'\n case 'error':\n return '\u2715'\n case 'queued':\n return '\u2026'\n default:\n return '\u25E6'\n }\n}\n\n/**\n * \u83B7\u53D6\u72B6\u6001\u6587\u672C\n */\nfunction getStatusText(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\n/**\n * \u83B7\u53D6\u72B6\u6001\u989C\u8272 - \u4F7F\u7528 SYMBOL_COLORS \u4E0E Logo \u54C1\u724C\u914D\u8272\u4FDD\u6301\u4E00\u81F4\n */\nfunction getStatusColor(\n status: SubagentState['status'],\n theme: ReturnType<typeof getTheme>,\n): string {\n switch (status) {\n case 'initializing':\n case 'queued':\n return SYMBOL_COLORS.pending // \u7070\u8272 - \u7B49\u5F85\n case 'running':\n return SYMBOL_COLORS.running // \u7C89\u7D2B - \u8FDB\u884C\u4E2D\n case 'completed':\n return SYMBOL_COLORS.success // \u7D2B\u84DD - \u5B8C\u6210\n case 'error':\n return SYMBOL_COLORS.error // \u73CA\u745A\u7EA2 - \u9519\u8BEF\n }\n}\n\n/**\n * \u83B7\u53D6\u6700\u65B0\u7684\u72B6\u6001\u6D88\u606F\n */\nfunction getLatestMessage(messages: SubagentState['messages']): string | null {\n if (messages.length === 0) return null\n\n // \u5012\u5E8F\u67E5\u627E\u6700\u65B0\u7684\u6587\u672C\u6D88\u606F\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg?.type === 'assistant' && msg.message?.content) {\n for (const content of msg.message.content) {\n if (content.type === 'text' && content.text.trim()) {\n // \u622A\u53D6\u524D 60 \u4E2A\u5B57\u7B26\n const text = content.text.trim()\n return text.length > 60 ? text.substring(0, 60) + '...' : text\n }\n if (content.type === 'tool_use') {\n return `Using ${content.name}...`\n }\n }\n }\n }\n\n return null\n}\n\n/**\n * \u6E32\u67D3\u8BE6\u7EC6\u7684\u8F93\u51FA\u65E5\u5FD7\n */\nfunction renderTaskOutputLog(\n subagent: SubagentState,\n theme: ReturnType<typeof getTheme>,\n tools: Tool[],\n verbose: boolean,\n): React.ReactNode {\n const { messages } = subagent\n\n return (\n <Box flexDirection=\"column\">\n {messages.map((msg, idx) => {\n if (msg.type === 'assistant') {\n return msg.message.content.map((content, contentIdx) => {\n if (content.type === 'tool_use') {\n const tool = tools.find(t => t.name === content.name)\n const toolName = tool?.userFacingName\n ? typeof tool.userFacingName === 'function'\n ? tool.userFacingName()\n : tool.userFacingName\n : content.name\n\n return (\n <Box key={`${idx}-${contentIdx}`} flexDirection=\"row\">\n <Text color={theme.info}>\uD83D\uDD27 {toolName}</Text>\n </Box>\n )\n } else if (content.type === 'text' && content.text.trim()) {\n const lines = content.text.trim().split('\\n')\n return (\n <Box key={`${idx}-${contentIdx}`} flexDirection=\"column\">\n {lines.map((line, lineIdx) => (\n <Text color={theme.secondaryText}>{line}</Text>\n ))}\n </Box>\n )\n }\n return null\n })\n } else if (msg.type === 'user') {\n return msg.message.content.map((content, contentIdx) => {\n if (content.type === 'tool_result') {\n const resultContent = Array.isArray(content.content)\n ? content.content.find(c => c.type === 'text')?.text\n : typeof content.content === 'string'\n ? content.content\n : ''\n\n if (resultContent && resultContent.trim()) {\n const lines = resultContent.trim().split('\\n')\n const preview =\n lines.length > 5\n ? lines.slice(0, 5).join('\\n') + '\\n...'\n : resultContent.trim()\n\n return (\n <Box key={`${idx}-${contentIdx}`} flexDirection=\"column\">\n {preview.split('\\n').map((line, lineIdx) => (\n <Text color={theme.mutedText}>{line}</Text>\n ))}\n </Box>\n )\n }\n }\n return null\n })\n }\n return null\n })}\n </Box>\n )\n}\n\n/**\n * \u7D27\u51D1\u7248 TaskCard (\u7528\u4E8E\u7A7A\u95F4\u53D7\u9650\u7684\u573A\u666F)\n */\nexport function CompactTaskCard({\n subagent,\n}: {\n subagent: SubagentState\n}): React.ReactNode {\n const theme = getTheme()\n const { taskName, status, agentColor } = subagent\n\n const color = getAgentColor(agentColor, theme)\n const isRunning =\n status === 'initializing' || status === 'running' || status === 'queued'\n const statusIcon = getStatusIcon(status, isRunning)\n\n return (\n <Box flexDirection=\"row\">\n <Text color={color}>\n {statusIcon} {taskName}\n </Text>\n <Text color={theme.dimmedText}> \u00B7 {getStatusText(status)}</Text>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
|
+
import React, { useState, useMemo, useCallback } from "react";
|
|
3
|
+
import { TabbedListView } from "./TabbedListView/TabbedListView.js";
|
|
4
|
+
import { useTeamMembers } from "../hooks/useTeamMembers.js";
|
|
5
|
+
import { getTheme } from "../utils/theme.js";
|
|
6
|
+
const STATUS_ICONS = {
|
|
7
|
+
working: "\u25D0",
|
|
8
|
+
planning: "\u25D1",
|
|
9
|
+
idle: "\u25CB",
|
|
10
|
+
stopped: "\u25CC"
|
|
11
|
+
};
|
|
12
|
+
const STATUS_COLORS = {
|
|
13
|
+
working: "yellow",
|
|
14
|
+
planning: "cyan",
|
|
15
|
+
idle: "green",
|
|
16
|
+
stopped: "gray"
|
|
17
|
+
};
|
|
18
|
+
function mapStatusToListStatus(status) {
|
|
19
|
+
switch (status) {
|
|
20
|
+
case "working":
|
|
21
|
+
return "running";
|
|
22
|
+
case "planning":
|
|
23
|
+
return "running";
|
|
24
|
+
case "idle":
|
|
25
|
+
return "enabled";
|
|
26
|
+
case "stopped":
|
|
27
|
+
return "disabled";
|
|
28
|
+
default:
|
|
29
|
+
return "enabled";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function TeamMemberItem({
|
|
33
|
+
item,
|
|
34
|
+
isFocused
|
|
35
|
+
}) {
|
|
36
|
+
const theme = getTheme();
|
|
37
|
+
const member = item.data;
|
|
38
|
+
if (!member) return null;
|
|
39
|
+
const icon = STATUS_ICONS[member.status] || "?";
|
|
40
|
+
const color = STATUS_COLORS[member.status] || "white";
|
|
41
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", gap: 1 }, /* @__PURE__ */ React.createElement(Text, { color: isFocused ? "cyan" : void 0 }, isFocused ? "\u25B8" : " "), /* @__PURE__ */ React.createElement(Text, { color }, icon), /* @__PURE__ */ React.createElement(Text, { bold: isFocused, color: isFocused ? "white" : void 0 }, member.name), /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "(", member.agentType, ")"), member.currentTaskId ? /* @__PURE__ */ React.createElement(Text, { color: theme.secondaryText }, "#", member.currentTaskId) : null);
|
|
42
|
+
}
|
|
43
|
+
function TeamMemberPanel({ isVisible, onClose, onFocusAgent }) {
|
|
44
|
+
const { members, teamName, hasActiveTeam } = useTeamMembers();
|
|
45
|
+
const [activeTab, setActiveTab] = useState("all");
|
|
46
|
+
const tabs = useMemo(() => {
|
|
47
|
+
const working = members.filter(
|
|
48
|
+
(m) => m.status === "working" || m.status === "planning"
|
|
49
|
+
).length;
|
|
50
|
+
const idle = members.filter((m) => m.status === "idle").length;
|
|
51
|
+
return [
|
|
52
|
+
{ id: "all", label: "All", badge: members.length },
|
|
53
|
+
{ id: "active", label: "Active", badge: working },
|
|
54
|
+
{ id: "idle", label: "Idle", badge: idle }
|
|
55
|
+
];
|
|
56
|
+
}, [members]);
|
|
57
|
+
const items = useMemo(() => {
|
|
58
|
+
const filtered = activeTab === "all" ? members : activeTab === "active" ? members.filter(
|
|
59
|
+
(m) => m.status === "working" || m.status === "planning"
|
|
60
|
+
) : members.filter((m) => m.status === "idle" || m.status === "stopped");
|
|
61
|
+
return filtered.map((m) => ({
|
|
62
|
+
id: m.id,
|
|
63
|
+
label: m.name,
|
|
64
|
+
description: `${m.agentType} \u2022 ${m.status}`,
|
|
65
|
+
status: mapStatusToListStatus(m.status),
|
|
66
|
+
data: m
|
|
67
|
+
}));
|
|
68
|
+
}, [members, activeTab]);
|
|
69
|
+
const isTeamLeadMember = (id) => id === "team-lead" || id.startsWith("team-lead@");
|
|
70
|
+
const handleSelect = useCallback(
|
|
71
|
+
(item) => {
|
|
72
|
+
if (onFocusAgent) {
|
|
73
|
+
onFocusAgent(isTeamLeadMember(item.id) ? null : item.id);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
[onFocusAgent]
|
|
77
|
+
);
|
|
78
|
+
if (!isVisible || !hasActiveTeam) return null;
|
|
79
|
+
return /* @__PURE__ */ React.createElement(
|
|
80
|
+
TabbedListView,
|
|
81
|
+
{
|
|
82
|
+
title: `Team: ${teamName}`,
|
|
83
|
+
tabs,
|
|
84
|
+
activeTab,
|
|
85
|
+
onTabChange: setActiveTab,
|
|
86
|
+
items,
|
|
87
|
+
showTabs: false,
|
|
88
|
+
searchEnabled: false,
|
|
89
|
+
onClose,
|
|
90
|
+
onSelect: handleSelect,
|
|
91
|
+
isActive: isVisible,
|
|
92
|
+
footerHint: "\u2191\u2193 Navigate \xB7 Enter Focus \xB7 Esc Close",
|
|
93
|
+
renderItem: (item, isFocused, isSelected) => /* @__PURE__ */ React.createElement(
|
|
94
|
+
TeamMemberItem,
|
|
95
|
+
{
|
|
96
|
+
item,
|
|
97
|
+
isFocused,
|
|
98
|
+
isSelected: isSelected ?? false
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
TeamMemberPanel
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=TeamMemberPanel.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/TeamMemberPanel.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * TeamMemberPanel Component\n *\n * Displays active team members during an Agent Teams session.\n * Reuses the TabbedListView component for consistent UI.\n * Toggled with Shift+Up keybinding.\n *\n * Selecting a member (Enter) delegates to onFocusAgent callback\n * which switches the REPL to full-screen agent focus mode.\n */\n\nimport { Box, Text } from 'ink'\nimport React, { useState, useMemo, useCallback } from 'react'\nimport { TabbedListView } from './TabbedListView/TabbedListView'\nimport type { ListItem, TabDefinition } from './TabbedListView/types'\nimport { useTeamMembers, type TeamMemberInfo } from '@hooks/useTeamMembers'\nimport { getTheme } from '@utils/theme'\nimport type { TeammateStatus } from '@minto-types/agentTeams'\n\nconst STATUS_ICONS: Record<TeammateStatus, string> = {\n working: '\\u25D0',\n planning: '\\u25D1',\n idle: '\\u25CB',\n stopped: '\\u25CC',\n}\n\nconst STATUS_COLORS: Record<TeammateStatus, string> = {\n working: 'yellow',\n planning: 'cyan',\n idle: 'green',\n stopped: 'gray',\n}\n\nfunction mapStatusToListStatus(status: TeammateStatus): ListItem['status'] {\n switch (status) {\n case 'working':\n return 'running'\n case 'planning':\n return 'running'\n case 'idle':\n return 'enabled'\n case 'stopped':\n return 'disabled'\n default:\n return 'enabled'\n }\n}\n\nfunction TeamMemberItem({\n item,\n isFocused,\n}: {\n item: ListItem\n isFocused: boolean\n isSelected: boolean\n}): React.ReactNode {\n const theme = getTheme()\n const member = item.data as TeamMemberInfo | undefined\n if (!member) return null\n\n const icon = STATUS_ICONS[member.status] || '?'\n const color = STATUS_COLORS[member.status] || 'white'\n\n return (\n <Box flexDirection=\"row\" gap={1}>\n {/* Cursor indicator for focused item */}\n <Text color={isFocused ? 'cyan' : undefined}>\n {isFocused ? '\u25B8' : ' '}\n </Text>\n <Text color={color}>{icon}</Text>\n <Text bold={isFocused} color={isFocused ? 'white' : undefined}>\n {member.name}\n </Text>\n <Text color={theme.secondaryText}>({member.agentType})</Text>\n {member.currentTaskId ? (\n <Text color={theme.secondaryText}>#{member.currentTaskId}</Text>\n ) : null}\n </Box>\n )\n}\n\ntype Props = {\n isVisible: boolean\n onClose: () => void\n onFocusAgent?: (agentId: string | null) => void\n}\n\nexport function TeamMemberPanel({ isVisible, onClose, onFocusAgent }: Props) {\n const { members, teamName, hasActiveTeam } = useTeamMembers()\n const [activeTab, setActiveTab] = useState('all')\n\n const tabs: TabDefinition[] = useMemo(() => {\n const working = members.filter(\n m => m.status === 'working' || m.status === 'planning',\n ).length\n const idle = members.filter(m => m.status === 'idle').length\n return [\n { id: 'all', label: 'All', badge: members.length },\n { id: 'active', label: 'Active', badge: working },\n { id: 'idle', label: 'Idle', badge: idle },\n ]\n }, [members])\n\n const items: ListItem[] = useMemo(() => {\n const filtered =\n activeTab === 'all'\n ? members\n : activeTab === 'active'\n ? members.filter(\n m => m.status === 'working' || m.status === 'planning',\n )\n : members.filter(m => m.status === 'idle' || m.status === 'stopped')\n\n return filtered.map(m => ({\n id: m.id,\n label: m.name,\n description: `${m.agentType} \\u2022 ${m.status}`,\n status: mapStatusToListStatus(m.status),\n data: m,\n }))\n }, [members, activeTab])\n\n // Detect team-lead member by id pattern (registered as \"team-lead@<teamName>\")\n const isTeamLeadMember = (id: string) =>\n id === 'team-lead' || id.startsWith('team-lead@')\n\n const handleSelect = useCallback(\n (item: ListItem) => {\n if (onFocusAgent) {\n // Team-lead maps to null (return to main view), others pass the id\n onFocusAgent(isTeamLeadMember(item.id) ? null : item.id)\n }\n },\n [onFocusAgent],\n )\n\n if (!isVisible || !hasActiveTeam) return null\n\n return (\n <TabbedListView\n title={`Team: ${teamName}`}\n tabs={tabs}\n activeTab={activeTab}\n onTabChange={setActiveTab}\n items={items}\n showTabs={false}\n searchEnabled={false}\n onClose={onClose}\n onSelect={handleSelect}\n isActive={isVisible}\n footerHint=\"\u2191\u2193 Navigate \u00B7 Enter Focus \u00B7 Esc Close\"\n renderItem={(item, isFocused, isSelected) => (\n <TeamMemberItem\n item={item}\n isFocused={isFocused}\n isSelected={isSelected ?? false}\n />\n )}\n />\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import figures from "figures";
|
|
4
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
|
|
5
|
+
import { getGlobalConfig, saveGlobalConfig } from "../utils/config.js";
|
|
6
|
+
import { t } from "../i18n/index.js";
|
|
7
|
+
const OPTIONS = [
|
|
8
|
+
{
|
|
9
|
+
id: "enabled",
|
|
10
|
+
label: t("thinking.enabled"),
|
|
11
|
+
description: t("thinking.enabledDesc")
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
id: "disabled",
|
|
15
|
+
label: t("thinking.disabled"),
|
|
16
|
+
description: t("thinking.disabledDesc")
|
|
17
|
+
}
|
|
18
|
+
];
|
|
19
|
+
function ThinkingSelector({ onClose }) {
|
|
20
|
+
const config = getGlobalConfig();
|
|
21
|
+
const currentEnabled = !!config.thinking;
|
|
22
|
+
const initialIndex = currentEnabled ? 0 : 1;
|
|
23
|
+
const [selectedIndex, setSelectedIndex] = useState(initialIndex);
|
|
24
|
+
useInput((input, key) => {
|
|
25
|
+
if (key.escape) {
|
|
26
|
+
onClose();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (key.downArrow) {
|
|
30
|
+
setSelectedIndex((prev) => Math.min(prev + 1, OPTIONS.length - 1));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (key.upArrow) {
|
|
34
|
+
setSelectedIndex((prev) => Math.max(prev - 1, 0));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const num = Number(input);
|
|
38
|
+
if (num >= 1 && num <= OPTIONS.length) {
|
|
39
|
+
const option = OPTIONS[num - 1];
|
|
40
|
+
const newThinking = option.id === "enabled";
|
|
41
|
+
saveGlobalConfig({ ...getGlobalConfig(), thinking: newThinking });
|
|
42
|
+
onClose();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (key.return) {
|
|
46
|
+
const selected = OPTIONS[selectedIndex];
|
|
47
|
+
const newThinking = selected.id === "enabled";
|
|
48
|
+
saveGlobalConfig({ ...getGlobalConfig(), thinking: newThinking });
|
|
49
|
+
onClose();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return /* @__PURE__ */ React.createElement(
|
|
54
|
+
Box,
|
|
55
|
+
{
|
|
56
|
+
flexDirection: "column",
|
|
57
|
+
borderStyle: "round",
|
|
58
|
+
borderColor: BRAND_GRADIENT.START,
|
|
59
|
+
paddingX: 1,
|
|
60
|
+
paddingY: 1
|
|
61
|
+
},
|
|
62
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, t("thinking.title")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("thinking.subtitle"))),
|
|
63
|
+
OPTIONS.map((option, index) => {
|
|
64
|
+
const isSelected = index === selectedIndex;
|
|
65
|
+
const isCurrent = option.id === "enabled" && currentEnabled || option.id === "disabled" && !currentEnabled;
|
|
66
|
+
return /* @__PURE__ */ React.createElement(Box, { key: option.id }, /* @__PURE__ */ React.createElement(
|
|
67
|
+
Text,
|
|
68
|
+
{
|
|
69
|
+
color: isSelected ? BRAND_GRADIENT.START : void 0,
|
|
70
|
+
bold: isSelected
|
|
71
|
+
},
|
|
72
|
+
isSelected ? `${figures.pointer} ` : " ",
|
|
73
|
+
index + 1,
|
|
74
|
+
". ",
|
|
75
|
+
option.label
|
|
76
|
+
), isCurrent && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, " \u2714"), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", option.description));
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("rewind.enterToContinue"), " \xB7 ", t("rewind.escToExit")))
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
ThinkingSelector
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=ThinkingSelector.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/ThinkingSelector.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * ThinkingSelector \u2014 Toggle thinking mode overlay\n *\n * Matches RewindPanel visual style (round border, brand colors).\n * Activated via Option+T (\u2325T).\n */\n\nimport React, { useState } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport figures from 'figures'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { getGlobalConfig, saveGlobalConfig } from '@utils/config'\nimport { t } from '@i18n'\n\ninterface Props {\n onClose: () => void\n}\n\ninterface ThinkingOption {\n id: 'enabled' | 'disabled'\n label: string\n description: string\n}\n\nconst OPTIONS: ThinkingOption[] = [\n {\n id: 'enabled',\n label: t('thinking.enabled'),\n description: t('thinking.enabledDesc'),\n },\n {\n id: 'disabled',\n label: t('thinking.disabled'),\n description: t('thinking.disabledDesc'),\n },\n]\n\nexport function ThinkingSelector({ onClose }: Props): React.ReactNode {\n const config = getGlobalConfig()\n const currentEnabled = !!config.thinking\n const initialIndex = currentEnabled ? 0 : 1\n const [selectedIndex, setSelectedIndex] = useState(initialIndex)\n\n useInput((input, key) => {\n if (key.escape) {\n onClose()\n return\n }\n\n if (key.downArrow) {\n setSelectedIndex(prev => Math.min(prev + 1, OPTIONS.length - 1))\n return\n }\n\n if (key.upArrow) {\n setSelectedIndex(prev => Math.max(prev - 1, 0))\n return\n }\n\n // Number keys 1-2\n const num = Number(input)\n if (num >= 1 && num <= OPTIONS.length) {\n const option = OPTIONS[num - 1]\n const newThinking = option.id === 'enabled'\n saveGlobalConfig({ ...getGlobalConfig(), thinking: newThinking })\n onClose()\n return\n }\n\n if (key.return) {\n const selected = OPTIONS[selectedIndex]\n const newThinking = selected.id === 'enabled'\n saveGlobalConfig({ ...getGlobalConfig(), thinking: newThinking })\n onClose()\n return\n }\n })\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={BRAND_GRADIENT.START}\n paddingX={1}\n paddingY={1}\n >\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color={BRAND_GRADIENT.START}>\n {t('thinking.title')}\n </Text>\n <Text color={SEMANTIC_COLORS.secondary}>{t('thinking.subtitle')}</Text>\n </Box>\n\n {/* Options */}\n {OPTIONS.map((option, index) => {\n const isSelected = index === selectedIndex\n const isCurrent =\n (option.id === 'enabled' && currentEnabled) ||\n (option.id === 'disabled' && !currentEnabled)\n\n return (\n <Box key={option.id}>\n <Text\n color={isSelected ? BRAND_GRADIENT.START : undefined}\n bold={isSelected}\n >\n {isSelected ? `${figures.pointer} ` : ' '}\n {index + 1}. {option.label}\n </Text>\n {isCurrent && <Text color={SEMANTIC_COLORS.success}> \u2714</Text>}\n <Text color={SEMANTIC_COLORS.dim}> {option.description}</Text>\n </Box>\n )\n })}\n\n {/* Footer */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('rewind.enterToContinue')} \u00B7 {t('rewind.escToExit')}\n </Text>\n </Box>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAOA,OAAO,SAAS,gBAAgB;AAChC,SAAS,KAAK,MAAM,gBAAgB;AACpC,OAAO,aAAa;AACpB,SAAS,gBAAgB,uBAAuB;AAChD,SAAS,iBAAiB,wBAAwB;AAClD,SAAS,SAAS;AAYlB,MAAM,UAA4B;AAAA,EAChC;AAAA,IACE,IAAI;AAAA,IACJ,OAAO,EAAE,kBAAkB;AAAA,IAC3B,aAAa,EAAE,sBAAsB;AAAA,EACvC;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,OAAO,EAAE,mBAAmB;AAAA,IAC5B,aAAa,EAAE,uBAAuB;AAAA,EACxC;AACF;AAEO,SAAS,iBAAiB,EAAE,QAAQ,GAA2B;AACpE,QAAM,SAAS,gBAAgB;AAC/B,QAAM,iBAAiB,CAAC,CAAC,OAAO;AAChC,QAAM,eAAe,iBAAiB,IAAI;AAC1C,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,YAAY;AAE/D,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ;AACd,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,IAAI,WAAW;AACjB,uBAAiB,UAAQ,KAAK,IAAI,OAAO,GAAG,QAAQ,SAAS,CAAC,CAAC;AAC/D;AAAA,IACF;AAEA,QAAI,IAAI,SAAS;AACf,uBAAiB,UAAQ,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;AAC9C;AAAA,IACF;AAGA,UAAM,MAAM,OAAO,KAAK;AACxB,QAAI,OAAO,KAAK,OAAO,QAAQ,QAAQ;AACrC,YAAM,SAAS,QAAQ,MAAM,CAAC;AAC9B,YAAM,cAAc,OAAO,OAAO;AAClC,uBAAiB,EAAE,GAAG,gBAAgB,GAAG,UAAU,YAAY,CAAC;AAChE,cAAQ;AACR;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ;AACd,YAAM,WAAW,QAAQ,aAAa;AACtC,YAAM,cAAc,SAAS,OAAO;AACpC,uBAAiB,EAAE,GAAG,gBAAgB,GAAG,UAAU,YAAY,CAAC;AAChE,cAAQ;AACR;AAAA,IACF;AAAA,EACF,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,aAAY;AAAA,MACZ,aAAa,eAAe;AAAA,MAC5B,UAAU;AAAA,MACV,UAAU;AAAA;AAAA,IAGV,oCAAC,OAAI,eAAc,UAAS,cAAc,KACxC,oCAAC,QAAK,MAAI,MAAC,OAAO,eAAe,SAC9B,EAAE,gBAAgB,CACrB,GACA,oCAAC,QAAK,OAAO,gBAAgB,aAAY,EAAE,mBAAmB,CAAE,CAClE;AAAA,IAGC,QAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9B,YAAM,aAAa,UAAU;AAC7B,YAAM,YACH,OAAO,OAAO,aAAa,kBAC3B,OAAO,OAAO,cAAc,CAAC;AAEhC,aACE,oCAAC,OAAI,KAAK,OAAO,MACf;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,aAAa,eAAe,QAAQ;AAAA,UAC3C,MAAM;AAAA;AAAA,QAEL,aAAa,GAAG,QAAQ,OAAO,MAAM;AAAA,QACrC,QAAQ;AAAA,QAAE;AAAA,QAAG,OAAO;AAAA,MACvB,GACC,aAAa,oCAAC,QAAK,OAAO,gBAAgB,WAAS,SAAE,GACtD,oCAAC,QAAK,OAAO,gBAAgB,OAAK,KAAE,OAAO,WAAY,CACzD;AAAA,IAEJ,CAAC;AAAA,IAGD,oCAAC,OAAI,WAAW,KACd,oCAAC,QAAK,OAAO,gBAAgB,OAC1B,EAAE,wBAAwB,GAAE,UAAI,EAAE,kBAAkB,CACvD,CACF;AAAA,EACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { useTerminalSize } from "../hooks/useTerminalSize.js";
|
|
4
|
+
import { SEMANTIC_COLORS } from "../constants/colors.js";
|
|
5
|
+
function TitledDivider({
|
|
6
|
+
title,
|
|
7
|
+
dividerChar = "\u2500",
|
|
8
|
+
titleColor = SEMANTIC_COLORS.secondary,
|
|
9
|
+
dividerColor = SEMANTIC_COLORS.dim,
|
|
10
|
+
width
|
|
11
|
+
}) {
|
|
12
|
+
const { columns } = useTerminalSize();
|
|
13
|
+
const effectiveWidth = width ?? columns;
|
|
14
|
+
if (!title) {
|
|
15
|
+
return /* @__PURE__ */ React.createElement(Text, { color: dividerColor }, dividerChar.repeat(Math.max(0, effectiveWidth)));
|
|
16
|
+
}
|
|
17
|
+
const titleWithPadding = ` ${title} `;
|
|
18
|
+
const remaining = effectiveWidth - titleWithPadding.length;
|
|
19
|
+
const leftLen = Math.floor(remaining / 2);
|
|
20
|
+
const rightLen = remaining - leftLen;
|
|
21
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: dividerColor }, dividerChar.repeat(Math.max(0, leftLen))), /* @__PURE__ */ React.createElement(Text, { color: titleColor }, titleWithPadding), /* @__PURE__ */ React.createElement(Text, { color: dividerColor }, dividerChar.repeat(Math.max(0, rightLen))));
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
TitledDivider
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=TitledDivider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/TitledDivider.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * TitledDivider Component\n *\n * Renders a horizontal divider line with an optional centered title.\n * Used for transcript mode indicators (Ctrl+E show/hide previous messages).\n *\n * Example output:\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 ctrl+e to show 10 previous messages \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n */\n\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\ninterface TitledDividerProps {\n title?: string\n dividerChar?: string\n titleColor?: string\n dividerColor?: string\n width?: number\n}\n\nexport function TitledDivider({\n title,\n dividerChar = '\u2500',\n titleColor = SEMANTIC_COLORS.secondary,\n dividerColor = SEMANTIC_COLORS.dim,\n width,\n}: TitledDividerProps): React.ReactNode {\n const { columns } = useTerminalSize()\n const effectiveWidth = width ?? columns\n\n if (!title) {\n return (\n <Text color={dividerColor}>\n {dividerChar.repeat(Math.max(0, effectiveWidth))}\n </Text>\n )\n }\n\n const titleWithPadding = ` ${title} `\n const remaining = effectiveWidth - titleWithPadding.length\n const leftLen = Math.floor(remaining / 2)\n const rightLen = remaining - leftLen\n\n return (\n <Box>\n <Text color={dividerColor}>\n {dividerChar.repeat(Math.max(0, leftLen))}\n </Text>\n <Text color={titleColor}>{titleWithPadding}</Text>\n <Text color={dividerColor}>\n {dividerChar.repeat(Math.max(0, rightLen))}\n </Text>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAUA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAUzB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,cAAc;AAAA,EACd,aAAa,gBAAgB;AAAA,EAC7B,eAAe,gBAAgB;AAAA,EAC/B;AACF,GAAwC;AACtC,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AACpC,QAAM,iBAAiB,SAAS;AAEhC,MAAI,CAAC,OAAO;AACV,WACE,oCAAC,QAAK,OAAO,gBACV,YAAY,OAAO,KAAK,IAAI,GAAG,cAAc,CAAC,CACjD;AAAA,EAEJ;AAEA,QAAM,mBAAmB,IAAI,KAAK;AAClC,QAAM,YAAY,iBAAiB,iBAAiB;AACpD,QAAM,UAAU,KAAK,MAAM,YAAY,CAAC;AACxC,QAAM,WAAW,YAAY;AAE7B,SACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBACV,YAAY,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,CAC1C,GACA,oCAAC,QAAK,OAAO,cAAa,gBAAiB,GAC3C,oCAAC,QAAK,OAAO,gBACV,YAAY,OAAO,KAAK,IAAI,GAAG,QAAQ,CAAC,CAC3C,CACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,9 +2,9 @@ import React, { useRef, useMemo, memo } from "react";
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { getTheme } from "../utils/theme.js";
|
|
4
4
|
import { SYMBOLS, getTodoStatusSymbol } from "../constants/symbols.js";
|
|
5
|
-
import {
|
|
5
|
+
import { getTokenDisplay } from "../utils/tokenProgress.js";
|
|
6
6
|
import { sample } from "lodash-es";
|
|
7
|
-
import { getMainStreamingState } from "../utils/streamingState.js";
|
|
7
|
+
import { getMainStreamingState, getStreamingState } from "../utils/streamingState.js";
|
|
8
8
|
import { getSessionState } from "../utils/sessionState.js";
|
|
9
9
|
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
10
10
|
import {
|
|
@@ -39,17 +39,30 @@ const SpinnerLine = memo(function SpinnerLine2({
|
|
|
39
39
|
currentTaskActiveForm,
|
|
40
40
|
todos,
|
|
41
41
|
shouldShowTodos,
|
|
42
|
-
fallbackMessage
|
|
42
|
+
fallbackMessage,
|
|
43
|
+
focusedAgentId
|
|
43
44
|
}) {
|
|
44
45
|
const theme = getTheme();
|
|
45
|
-
const
|
|
46
|
-
const
|
|
46
|
+
const fallbackStartRef = useRef(Date.now());
|
|
47
|
+
const tickRef = useRef(0);
|
|
48
|
+
const { spinnerFrame, dataTick } = useUnifiedAnimation({
|
|
47
49
|
enabled: true,
|
|
48
|
-
startTime
|
|
50
|
+
// startTime is updated below after reading streaming state
|
|
51
|
+
startTime: fallbackStartRef.current,
|
|
49
52
|
spinnerFrameCount: SHIMMER_COLORS.length,
|
|
50
53
|
componentId: "todo-panel-spinner"
|
|
51
54
|
});
|
|
52
|
-
|
|
55
|
+
tickRef.current = spinnerFrame;
|
|
56
|
+
const latestStreamState = useMemo(
|
|
57
|
+
() => focusedAgentId ? getStreamingState(focusedAgentId) : getMainStreamingState(),
|
|
58
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
|
+
[focusedAgentId, dataTick]
|
|
60
|
+
);
|
|
61
|
+
const startTime = latestStreamState.turnStartedAt ?? fallbackStartRef.current;
|
|
62
|
+
const correctedElapsed = Math.max(
|
|
63
|
+
0,
|
|
64
|
+
Math.floor((Date.now() - startTime) / 1e3)
|
|
65
|
+
);
|
|
53
66
|
const getCurrentTaskDisplay = () => {
|
|
54
67
|
if (currentTaskActiveForm) {
|
|
55
68
|
return currentTaskActiveForm;
|
|
@@ -58,9 +71,9 @@ const SpinnerLine = memo(function SpinnerLine2({
|
|
|
58
71
|
if (inProgressTodo?.activeForm) {
|
|
59
72
|
return inProgressTodo.activeForm;
|
|
60
73
|
}
|
|
61
|
-
switch (
|
|
74
|
+
switch (latestStreamState.phase) {
|
|
62
75
|
case "tool_use":
|
|
63
|
-
return
|
|
76
|
+
return latestStreamState.toolName ? `Using ${latestStreamState.toolName}` : "Executing tool";
|
|
64
77
|
case "generating":
|
|
65
78
|
return "Generating response";
|
|
66
79
|
case "waiting":
|
|
@@ -78,23 +91,9 @@ const SpinnerLine = memo(function SpinnerLine2({
|
|
|
78
91
|
};
|
|
79
92
|
const shimmerColor = getShimmerColor(spinnerFrame);
|
|
80
93
|
const spinnerIconFrame = spinnerFrame % SYMBOLS.THINKING_FRAMES.length;
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
if (streamState.receivedChars && streamState.receivedChars > 0) {
|
|
86
|
-
const approxOutputTokens = Math.round(streamState.receivedChars / 3);
|
|
87
|
-
if (streamState.sentChars && streamState.sentChars > 0) {
|
|
88
|
-
const approxInputTokens = Math.round(streamState.sentChars / 3);
|
|
89
|
-
return `\u2191 ~${formatNumber(approxInputTokens)} \xB7 \u2193 ~${formatNumber(approxOutputTokens)}`;
|
|
90
|
-
}
|
|
91
|
-
return `\u2193 ~${formatNumber(approxOutputTokens)}`;
|
|
92
|
-
}
|
|
93
|
-
return "";
|
|
94
|
-
};
|
|
95
|
-
const tokenUsage = getTokenDisplay();
|
|
96
|
-
const thinkingDuration = streamState.thinkingDurationMs ? Math.floor(streamState.thinkingDurationMs / 1e3) : null;
|
|
97
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", flexWrap: "nowrap" }, /* @__PURE__ */ React.createElement(Text, { color: shimmerColor }, SYMBOLS.THINKING_FRAMES[spinnerIconFrame], " "), /* @__PURE__ */ React.createElement(Text, { color: shimmerColor, bold: true }, getCurrentTaskDisplay()), /* @__PURE__ */ React.createElement(Text, { color: shimmerColor }, "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "(", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, "esc esc"), " to cancel \xB7", " ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, formatTime(elapsedTime)), tokenUsage && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " \xB7 ", tokenUsage), thinkingDuration !== null && thinkingDuration > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " ", "\xB7 thinking ", thinkingDuration, "s"), shouldShowTodos && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " ", "\xB7 ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, "ctrl+t"), " to hide"), ")"), getSessionState("currentError") && /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.error }, " ", "\xB7 ", getSessionState("currentError")));
|
|
94
|
+
const { formatted: tokenUsage } = getTokenDisplay(focusedAgentId);
|
|
95
|
+
const thinkingDuration = latestStreamState.thinkingDurationMs ? Math.floor(latestStreamState.thinkingDurationMs / 1e3) : null;
|
|
96
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", flexWrap: "nowrap" }, /* @__PURE__ */ React.createElement(Text, { color: shimmerColor }, SYMBOLS.THINKING_FRAMES[spinnerIconFrame], " "), /* @__PURE__ */ React.createElement(Text, { color: shimmerColor, bold: true }, getCurrentTaskDisplay()), /* @__PURE__ */ React.createElement(Text, { color: shimmerColor }, "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "(", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, "esc"), " to cancel \xB7", " ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, formatTime(correctedElapsed)), tokenUsage && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " \xB7 ", tokenUsage), latestStreamState.phase === "thinking" && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " \xB7 thinking"), thinkingDuration !== null && thinkingDuration > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " ", "\xB7 thinking ", thinkingDuration, "s"), shouldShowTodos && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, " ", "\xB7 ", /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, "ctrl+t"), " to hide"), ")"), getSessionState("currentError") && /* @__PURE__ */ React.createElement(Text, { color: SYMBOL_COLORS.error }, " ", "\xB7 ", getSessionState("currentError")));
|
|
98
97
|
});
|
|
99
98
|
const SPINNER_MESSAGES = [
|
|
100
99
|
"Thinking",
|
|
@@ -112,7 +111,8 @@ const TodoPanel = memo(function TodoPanel2({
|
|
|
112
111
|
currentTaskActiveForm,
|
|
113
112
|
elapsedTime: initialElapsedTime = 0,
|
|
114
113
|
isLoading = true,
|
|
115
|
-
showTodoList = true
|
|
114
|
+
showTodoList = true,
|
|
115
|
+
focusedAgentId
|
|
116
116
|
}) {
|
|
117
117
|
const theme = getTheme();
|
|
118
118
|
const fallbackMessage = useRef(sample(SPINNER_MESSAGES) || "Thinking");
|
|
@@ -123,7 +123,7 @@ const TodoPanel = memo(function TodoPanel2({
|
|
|
123
123
|
if (shouldShowTodos) {
|
|
124
124
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\u25CB "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, hasIncompleteTasks ? t("ui.todo.tasksRemaining", {
|
|
125
125
|
count: todos.filter((todo) => todo.status !== "completed").length
|
|
126
|
-
}) : t("ui.todo.allDone"))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, todos.map((todo, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key:
|
|
126
|
+
}) : t("ui.todo.allDone"))), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, todos.map((todo, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: todo.id }, /* @__PURE__ */ React.createElement(
|
|
127
127
|
TodoItemClaudeStyle,
|
|
128
128
|
{
|
|
129
129
|
todo,
|
|
@@ -140,12 +140,13 @@ const TodoPanel = memo(function TodoPanel2({
|
|
|
140
140
|
currentTaskActiveForm,
|
|
141
141
|
todos,
|
|
142
142
|
shouldShowTodos,
|
|
143
|
-
fallbackMessage: fallbackMessage.current
|
|
143
|
+
fallbackMessage: fallbackMessage.current,
|
|
144
|
+
focusedAgentId
|
|
144
145
|
}
|
|
145
146
|
), shouldShowTodos && /* @__PURE__ */ React.createElement(TodoList, { todos, theme }));
|
|
146
147
|
});
|
|
147
148
|
const TodoList = memo(function TodoList2({ todos, theme }) {
|
|
148
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, todos.map((todo, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key:
|
|
149
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, todos.map((todo, idx) => /* @__PURE__ */ React.createElement(React.Fragment, { key: todo.id }, /* @__PURE__ */ React.createElement(TodoItemClaudeStyle, { todo, theme, isFirst: idx === 0 }))));
|
|
149
150
|
});
|
|
150
151
|
const TodoItemClaudeStyle = memo(function TodoItemClaudeStyle2({
|
|
151
152
|
todo,
|