@within-7/minto 0.3.10 → 0.4.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/dist/Tool.js.map +2 -2
- package/dist/commands/agents/AgentsCommand.js +2 -2
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/ctx_viz.js +1 -1
- package/dist/commands/effort.js +87 -0
- package/dist/commands/effort.js.map +7 -0
- package/dist/commands/export.js +19 -9
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/ide.js +18 -0
- package/dist/commands/ide.js.map +7 -0
- package/dist/commands/mcp-interactive.js +14 -8
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/memory.js +168 -0
- package/dist/commands/memory.js.map +7 -0
- package/dist/commands/model.js +45 -2
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/outputStyle.js +64 -0
- package/dist/commands/outputStyle.js.map +7 -0
- package/dist/commands/plugin/utils.js +33 -1
- package/dist/commands/plugin/utils.js.map +2 -2
- package/dist/commands/plugin.js +10 -1
- package/dist/commands/plugin.js.map +2 -2
- package/dist/commands/refreshCommands.js +2 -0
- package/dist/commands/refreshCommands.js.map +2 -2
- package/dist/commands/review.js +51 -0
- package/dist/commands/review.js.map +7 -0
- package/dist/commands/terminalSetup.js +6 -0
- package/dist/commands/terminalSetup.js.map +2 -2
- package/dist/commands/undo.js +8 -0
- package/dist/commands/undo.js.map +2 -2
- package/dist/commands/vim.js +22 -0
- package/dist/commands/vim.js.map +7 -0
- package/dist/commands.js +12 -0
- package/dist/commands.js.map +2 -2
- package/dist/components/HighlightedCode.js +1 -0
- package/dist/components/HighlightedCode.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +250 -143
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/PromptInput.js +21 -6
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/PulseLabel.js +44 -0
- package/dist/components/PulseLabel.js.map +7 -0
- package/dist/components/RequestStatusIndicator.js +1 -1
- package/dist/components/RequestStatusIndicator.js.map +1 -1
- package/dist/components/Spinner.js +12 -42
- package/dist/components/Spinner.js.map +3 -3
- package/dist/components/StartupStatus.js +57 -0
- package/dist/components/StartupStatus.js.map +7 -0
- package/dist/components/SubagentBlock.js +43 -6
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/TabbedListView/TabBar.js +13 -8
- package/dist/components/TabbedListView/TabBar.js.map +2 -2
- package/dist/components/TabbedListView/TabbedListView.js +1 -1
- package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
- package/dist/components/TodoPanel.js +1 -1
- package/dist/components/TodoPanel.js.map +1 -1
- package/dist/components/ToolUseLoader.js +5 -0
- package/dist/components/ToolUseLoader.js.map +2 -2
- package/dist/components/TrustDialog.js +0 -2
- package/dist/components/TrustDialog.js.map +2 -2
- package/dist/components/messages/TaskInModuleView.js +1 -1
- package/dist/components/messages/TaskInModuleView.js.map +2 -2
- package/dist/components/messages/TaskToolMessage.js +1 -1
- package/dist/components/messages/TaskToolMessage.js.map +2 -2
- package/dist/components/messages/UserPromptMessage.js +6 -1
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/constants/modelCapabilities.js +103 -18
- package/dist/constants/modelCapabilities.js.map +2 -2
- package/dist/constants/product.js +2 -0
- package/dist/constants/product.js.map +2 -2
- package/dist/constants/prompts/agentPrompt.js +30 -0
- package/dist/constants/prompts/agentPrompt.js.map +7 -0
- package/dist/constants/prompts/codeConventions.js +27 -0
- package/dist/constants/prompts/codeConventions.js.map +7 -0
- package/dist/constants/prompts/doingTasks.js +15 -0
- package/dist/constants/prompts/doingTasks.js.map +7 -0
- package/dist/constants/prompts/envInfo.js +17 -0
- package/dist/constants/prompts/envInfo.js.map +7 -0
- package/dist/constants/prompts/executingWithCare.js +17 -0
- package/dist/constants/prompts/executingWithCare.js.map +7 -0
- package/dist/constants/prompts/identity.js +10 -0
- package/dist/constants/prompts/identity.js.map +7 -0
- package/dist/constants/prompts/index.js +78 -0
- package/dist/constants/prompts/index.js.map +7 -0
- package/dist/constants/prompts/taskManagement.js +60 -0
- package/dist/constants/prompts/taskManagement.js.map +7 -0
- package/dist/constants/prompts/toneAndStyle.js +62 -0
- package/dist/constants/prompts/toneAndStyle.js.map +7 -0
- package/dist/constants/prompts/toolUsagePolicy.js +38 -0
- package/dist/constants/prompts/toolUsagePolicy.js.map +7 -0
- package/dist/constants/prompts.js +5 -176
- package/dist/constants/prompts.js.map +2 -2
- package/dist/constants/providerRegistry.js +235 -0
- package/dist/constants/providerRegistry.js.map +7 -0
- package/dist/constants/providers.js +35 -0
- package/dist/constants/providers.js.map +7 -0
- package/dist/context/PermissionContext.js +0 -1
- package/dist/context/PermissionContext.js.map +2 -2
- package/dist/context.js +87 -31
- package/dist/context.js.map +2 -2
- package/dist/core/backupHook.js +2 -2
- package/dist/core/backupHook.js.map +2 -2
- package/dist/core/config/defaults.js +4 -1
- package/dist/core/config/defaults.js.map +2 -2
- package/dist/core/config/schema.js +7 -1
- package/dist/core/config/schema.js.map +2 -2
- package/dist/core/costTracker.js +18 -0
- package/dist/core/costTracker.js.map +2 -2
- package/dist/core/index.js +0 -1
- package/dist/core/index.js.map +2 -2
- package/dist/core/tokenStatsManager.js +22 -4
- package/dist/core/tokenStatsManager.js.map +2 -2
- package/dist/entrypoints/cli.js +65 -84
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/hooks/useAgentTokenStats.js +1 -1
- package/dist/hooks/useAgentTokenStats.js.map +2 -2
- package/dist/hooks/useAgentTranscripts.js +2 -1
- package/dist/hooks/useAgentTranscripts.js.map +2 -2
- package/dist/hooks/useBackgroundShells.js +29 -0
- package/dist/hooks/useBackgroundShells.js.map +7 -0
- package/dist/hooks/useCanUseTool.js +1 -1
- package/dist/hooks/useCanUseTool.js.map +2 -2
- package/dist/hooks/useDeferredLoading.js +64 -0
- package/dist/hooks/useDeferredLoading.js.map +7 -0
- package/dist/hooks/useHookStatus.js +1 -1
- package/dist/hooks/useHookStatus.js.map +2 -2
- package/dist/hooks/useSessionTracking.js +55 -0
- package/dist/hooks/useSessionTracking.js.map +7 -0
- package/dist/hooks/useTerminalSize.js +21 -0
- package/dist/hooks/useTerminalSize.js.map +2 -2
- package/dist/hooks/useTextInput.js +1 -0
- package/dist/hooks/useTextInput.js.map +2 -2
- package/dist/hooks/useUnifiedCompletion.js +3 -2
- package/dist/hooks/useUnifiedCompletion.js.map +2 -2
- package/dist/i18n/locales/en.js +8 -9
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +8 -9
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/messages.js +41 -17
- package/dist/messages.js.map +2 -2
- package/dist/permissions.js +94 -1
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +27 -19
- package/dist/query.js.map +2 -2
- package/dist/screens/REPL.js +83 -74
- package/dist/screens/REPL.js.map +2 -2
- package/dist/services/adapters/responsesAPI.js +6 -0
- package/dist/services/adapters/responsesAPI.js.map +2 -2
- package/dist/services/agentTeams/index.js +35 -0
- package/dist/services/agentTeams/index.js.map +7 -0
- package/dist/services/agentTeams/mailbox.js +114 -0
- package/dist/services/agentTeams/mailbox.js.map +7 -0
- package/dist/services/agentTeams/teamManager.js +149 -0
- package/dist/services/agentTeams/teamManager.js.map +7 -0
- package/dist/services/agentTeams/teamTaskStore.js +114 -0
- package/dist/services/agentTeams/teamTaskStore.js.map +7 -0
- package/dist/services/agentTeams/teammateSpawner.js +80 -0
- package/dist/services/agentTeams/teammateSpawner.js.map +7 -0
- package/dist/services/checkpointManager.js +16 -3
- package/dist/services/checkpointManager.js.map +2 -2
- package/dist/services/claude.js +19 -1728
- package/dist/services/claude.js.map +3 -3
- package/dist/services/gpt5ConnectionTest.js +4 -2
- package/dist/services/gpt5ConnectionTest.js.map +2 -2
- package/dist/services/hookExecutor.js +411 -127
- package/dist/services/hookExecutor.js.map +2 -2
- package/dist/services/llm/anthropicProvider.js +807 -0
- package/dist/services/llm/anthropicProvider.js.map +7 -0
- package/dist/services/llm/dispatch.js +218 -0
- package/dist/services/llm/dispatch.js.map +7 -0
- package/dist/services/llm/index.js +44 -0
- package/dist/services/llm/index.js.map +7 -0
- package/dist/services/llm/mintoContext.js +69 -0
- package/dist/services/llm/mintoContext.js.map +7 -0
- package/dist/services/llm/openaiProvider.js +622 -0
- package/dist/services/llm/openaiProvider.js.map +7 -0
- package/dist/services/llm/types.js +157 -0
- package/dist/services/llm/types.js.map +7 -0
- package/dist/services/mcpClient.js +183 -33
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/notifier.js +14 -0
- package/dist/services/notifier.js.map +2 -2
- package/dist/services/oauth.js +4 -2
- package/dist/services/oauth.js.map +2 -2
- package/dist/services/openai.js +66 -56
- package/dist/services/openai.js.map +3 -3
- package/dist/services/outputStyles.js +102 -21
- package/dist/services/outputStyles.js.map +2 -2
- package/dist/services/plugins/skillMarketplace.js +4 -1
- package/dist/services/plugins/skillMarketplace.js.map +2 -2
- package/dist/services/sentry.js +1 -1
- package/dist/services/sentry.js.map +2 -2
- package/dist/services/sessionMemory.js +16 -3
- package/dist/services/sessionMemory.js.map +2 -2
- package/dist/services/systemReminder.js +350 -3
- package/dist/services/systemReminder.js.map +2 -2
- package/dist/services/taskStore.js +19 -0
- package/dist/services/taskStore.js.map +2 -2
- package/dist/tools/ArchitectTool/ArchitectTool.js.map +1 -1
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +1 -1
- package/dist/tools/BashOutputTool/BashOutputTool.js.map +1 -1
- package/dist/tools/BashTool/BashTool.js +28 -0
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +1 -1
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js +14 -0
- package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +3 -1
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +2 -2
- package/dist/tools/GlobTool/GlobTool.js.map +1 -1
- package/dist/tools/GrepTool/GrepTool.js.map +1 -1
- package/dist/tools/KillShellTool/KillShellTool.js.map +1 -1
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
- package/dist/tools/LspTool/LspTool.js +11 -2
- package/dist/tools/LspTool/LspTool.js.map +2 -2
- package/dist/tools/MCPTool/MCPTool.js.map +1 -1
- package/dist/tools/MemoryReadTool/MemoryReadTool.js +2 -1
- package/dist/tools/MemoryReadTool/MemoryReadTool.js.map +2 -2
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js +2 -1
- package/dist/tools/MemoryWriteTool/MemoryWriteTool.js.map +2 -2
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +1 -1
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +1 -1
- package/dist/tools/NotebookReadTool/NotebookReadTool.js.map +1 -1
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +8 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +2 -0
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
- package/dist/tools/ReadMcpResourceTool/ReadMcpResourceTool.js.map +1 -1
- package/dist/tools/SlashCommandTool/SlashCommandTool.js +174 -18
- package/dist/tools/SlashCommandTool/SlashCommandTool.js.map +3 -3
- package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +1 -1
- package/dist/tools/TaskGetTool/TaskGetTool.js.map +1 -1
- package/dist/tools/TaskListTool/TaskListTool.js.map +1 -1
- package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +1 -1
- package/dist/tools/TaskStopTool/TaskStopTool.js.map +1 -1
- package/dist/tools/TaskTool/TaskTool.js +75 -5
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskTool/prompt.js +12 -6
- package/dist/tools/TaskTool/prompt.js.map +2 -2
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +1 -1
- package/dist/tools/ThinkTool/ThinkTool.js.map +1 -1
- package/dist/tools/TodoWriteTool/TodoWriteTool.js.map +1 -1
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +1 -1
- package/dist/tools/WebSearchTool/WebSearchTool.js.map +1 -1
- package/dist/tools/WebSearchTool/searchProviders.js +2 -1
- package/dist/tools/WebSearchTool/searchProviders.js.map +2 -2
- package/dist/tools/lsTool/lsTool.js.map +2 -2
- package/dist/tools/lsTool/prompt.js.map +1 -1
- package/dist/tools.js +14 -3
- package/dist/tools.js.map +2 -2
- package/dist/types/PermissionMode.js +21 -1
- package/dist/types/PermissionMode.js.map +2 -2
- package/dist/types/agentTeams.js +1 -0
- package/dist/types/agentTeams.js.map +7 -0
- package/dist/types/hooks.js +8 -2
- package/dist/types/hooks.js.map +2 -2
- package/dist/types/plugin.js +1 -1
- package/dist/types/plugin.js.map +2 -2
- package/dist/utils/agentLoader.js +25 -3
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/animationManager.js +1 -1
- package/dist/utils/animationManager.js.map +2 -2
- package/dist/utils/ask.js +1 -1
- package/dist/utils/async.js +5 -1
- package/dist/utils/async.js.map +2 -2
- package/dist/utils/autoCompactCore.js +60 -0
- package/dist/utils/autoCompactCore.js.map +2 -2
- package/dist/utils/config.js +26 -128
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/configSchema.js +227 -0
- package/dist/utils/configSchema.js.map +7 -0
- package/dist/utils/debugLogger.js.map +2 -2
- package/dist/utils/env.js +4 -3
- package/dist/utils/env.js.map +2 -2
- package/dist/utils/envConfig.js +34 -0
- package/dist/utils/envConfig.js.map +3 -3
- package/dist/utils/gpt5.js +146 -0
- package/dist/utils/gpt5.js.map +7 -0
- package/dist/utils/hookManager.js +374 -140
- package/dist/utils/hookManager.js.map +2 -2
- package/dist/utils/markdown.js +47 -0
- package/dist/utils/markdown.js.map +2 -2
- package/dist/utils/memoizeWithTTL.js +25 -0
- package/dist/utils/memoizeWithTTL.js.map +7 -0
- package/dist/utils/model.js +34 -9
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/pluginInstaller.js +34 -5
- package/dist/utils/pluginInstaller.js.map +2 -2
- package/dist/utils/pluginLoader.js +201 -32
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/safeFetch.js +45 -0
- package/dist/utils/safeFetch.js.map +7 -0
- package/dist/utils/skillLoader.js +59 -6
- package/dist/utils/skillLoader.js.map +2 -2
- package/dist/utils/streamingState.js +52 -0
- package/dist/utils/streamingState.js.map +7 -0
- package/dist/utils/style.js +6 -3
- package/dist/utils/style.js.map +2 -2
- package/dist/utils/teamConfig.js +9 -3
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/toolRiskClassification.js +0 -6
- package/dist/utils/toolRiskClassification.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/RequestStatusIndicator.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Request Status Indicator Component\n *\n * A lightweight, configurable status indicator for API requests.\n * Can be toggled via config to show minimal or detailed status.\n *\n * Uses unified animation manager to prevent screen flickering.\n */\n\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useRef, useMemo } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { getGlobalConfig } from '@utils/config'\nimport { getStreamingState, type StreamingPhase } from '
|
|
4
|
+
"sourcesContent": ["/**\n * Request Status Indicator Component\n *\n * A lightweight, configurable status indicator for API requests.\n * Can be toggled via config to show minimal or detailed status.\n *\n * Uses unified animation manager to prevent screen flickering.\n */\n\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useRef, useMemo } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { getGlobalConfig } from '@utils/config'\nimport { getStreamingState, type StreamingPhase } from '@utils/streamingState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\n\nexport type StatusDisplayMode = 'minimal' | 'compact' | 'detailed' | 'hidden'\n\ninterface Props {\n /** Override the display mode from config */\n mode?: StatusDisplayMode\n /** Whether a request is currently active */\n isActive: boolean\n /** Optional custom status text */\n statusText?: string\n}\n\n// Phase indicators for minimal mode\nconst PHASE_INDICATORS: Record<StreamingPhase, string> = {\n thinking: '\u25D0',\n deep_thinking: '\uD83E\uDDE0',\n generating: '\u25D1',\n tool_use: '\u25D2',\n waiting: '\u25D3',\n retrying: '\uD83D\uDD04',\n permission: '\uD83D\uDD10',\n compacting: '\uD83D\uDCE6',\n concurrent: '\u26A1',\n}\n\n// Animated dots for minimal mode\nconst DOTS = ['', '.', '..', '...']\n\n/**\n * Get the configured status display mode\n */\nexport function getStatusDisplayMode(): StatusDisplayMode {\n const config = getGlobalConfig()\n return (config as any).statusDisplayMode || 'compact'\n}\n\n/**\n * Minimal status indicator - just a spinning symbol\n * Uses unified animation manager instead of setInterval\n */\nfunction MinimalIndicator({\n isActive,\n}: {\n isActive: boolean\n}): React.ReactNode {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Use unified animation manager - 4 frames for dots animation\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTimeRef.current,\n spinnerFrameCount: 4, // For DOTS array\n componentId: 'minimal-indicator',\n })\n\n // Get streaming state on each render (updates when spinnerFrame changes)\n const streamState = useMemo(() => getStreamingState(), [spinnerFrame])\n\n if (!isActive) return null\n\n const indicator = PHASE_INDICATORS[streamState.phase]\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 return (\n <Text color={phaseColors[streamState.phase]}>\n {indicator}\n {DOTS[spinnerFrame]}\n </Text>\n )\n}\n\n/**\n * Compact status indicator - symbol + short phase name\n * Uses unified animation manager instead of setInterval\n */\nfunction CompactIndicator({\n isActive,\n statusText,\n}: {\n isActive: boolean\n statusText?: string\n}): React.ReactNode {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Reset start time when becoming active\n React.useEffect(() => {\n if (isActive) {\n startTimeRef.current = Date.now()\n }\n }, [isActive])\n\n // Use unified animation manager\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTimeRef.current,\n spinnerFrameCount: 4,\n componentId: 'compact-indicator',\n })\n\n // Get streaming state on each render (updates when spinnerFrame changes)\n const streamState = useMemo(() => getStreamingState(), [spinnerFrame])\n\n if (!isActive) return null\n\n const phaseLabels: Record<StreamingPhase, string> = {\n thinking: 'thinking',\n deep_thinking: 'deep thinking',\n generating: 'generating',\n tool_use: streamState.toolName ? `\u2192${streamState.toolName}` : 'tool',\n waiting: 'waiting',\n retrying: 'retrying',\n permission: 'permission',\n compacting: 'compacting',\n concurrent: 'concurrent',\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 const displayText = statusText || phaseLabels[streamState.phase]\n\n return (\n <Box>\n <Text color={phaseColors[streamState.phase]}>\n {PHASE_INDICATORS[streamState.phase]} {displayText}\n </Text>\n <Text color={theme.secondaryText}> {elapsedTime}s</Text>\n </Box>\n )\n}\n\n/**\n * Detailed status indicator - full info with tokens and chunks\n * Uses unified animation manager instead of setInterval\n */\nfunction DetailedIndicator({\n isActive,\n statusText,\n}: {\n isActive: boolean\n statusText?: string\n}): React.ReactNode {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Reset start time when becoming active\n React.useEffect(() => {\n if (isActive) {\n startTimeRef.current = Date.now()\n }\n }, [isActive])\n\n // Use unified animation manager\n const { spinnerFrame, elapsedTime } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTimeRef.current,\n spinnerFrameCount: 4,\n componentId: 'detailed-indicator',\n })\n\n // Get streaming state on each render (updates when spinnerFrame changes)\n const streamState = useMemo(() => getStreamingState(), [spinnerFrame])\n\n if (!isActive) return null\n\n const getDetailedDisplay = () => {\n switch (streamState.phase) {\n case 'tool_use':\n return streamState.toolName\n ? `Using ${streamState.toolName}`\n : 'Executing tool'\n case 'generating':\n if (streamState.chunkCount) {\n return `Generating (${streamState.chunkCount} chunks)`\n }\n return 'Generating response'\n case 'waiting':\n return 'Waiting for API response'\n case 'thinking':\n default:\n return statusText || 'Processing request'\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 return (\n <Box flexDirection=\"row\">\n <Text color={phaseColors[streamState.phase]}>\n {PHASE_INDICATORS[streamState.phase]} {getDetailedDisplay()}\n </Text>\n <Text color={theme.secondaryText}> [{elapsedTime}s]</Text>\n {streamState.tokenCount && (\n <Text color={theme.secondaryText}>\n {' '}\n ({streamState.tokenCount} tokens)\n </Text>\n )}\n </Box>\n )\n}\n\n/**\n * Main Request Status Indicator\n *\n * Renders different status displays based on config setting:\n * - hidden: Nothing shown\n * - minimal: Just a spinning indicator\n * - compact: Indicator + phase + time (default)\n * - detailed: Full info including tokens/chunks\n */\nexport function RequestStatusIndicator({\n mode,\n isActive,\n statusText,\n}: Props): React.ReactNode {\n const displayMode = mode || getStatusDisplayMode()\n\n if (displayMode === 'hidden' || !isActive) {\n return null\n }\n\n switch (displayMode) {\n case 'minimal':\n return <MinimalIndicator isActive={isActive} />\n case 'detailed':\n return <DetailedIndicator isActive={isActive} statusText={statusText} />\n case 'compact':\n default:\n return <CompactIndicator isActive={isActive} statusText={statusText} />\n }\n}\n\n/**\n * Inline status badge for use in headers/footers\n * Uses unified animation manager instead of setInterval\n */\nexport function StatusBadge({\n isActive,\n}: {\n isActive: boolean\n}): React.ReactNode {\n const theme = getTheme()\n const startTimeRef = useRef(Date.now())\n\n // Use unified animation manager\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTimeRef.current,\n spinnerFrameCount: 4,\n componentId: 'status-badge',\n })\n\n // Get streaming state on each render (updates when spinnerFrame changes)\n const streamState = useMemo(() => getStreamingState(), [spinnerFrame])\n\n if (!isActive) return null\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 return (\n <Text color={phaseColors[streamState.phase]}>\n [{PHASE_INDICATORS[streamState.phase]}]\n </Text>\n )\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -7,48 +7,18 @@ import { getSessionState } from "../utils/sessionState.js";
|
|
|
7
7
|
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
8
8
|
import { formatNumber, formatTokenUsage } from "../utils/format.js";
|
|
9
9
|
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
|
|
10
|
+
import {
|
|
11
|
+
getCurrentAgentContext,
|
|
12
|
+
pushAgentContext,
|
|
13
|
+
popAgentContext,
|
|
14
|
+
setStreamingState,
|
|
15
|
+
resetStreamingState,
|
|
16
|
+
getStreamingState,
|
|
17
|
+
getMainStreamingState,
|
|
18
|
+
cleanupAgentStreamingState
|
|
19
|
+
} from "../utils/streamingState.js";
|
|
20
|
+
import { getMainStreamingState as getMainStreamingState2 } from "../utils/streamingState.js";
|
|
10
21
|
const CHARACTERS = process.platform === "darwin" ? ["\xB7", "\u2722", "\u2733", "\u2217", "\u273B", "\u273D"] : ["\xB7", "\u2722", "*", "\u2217", "\u273B", "\u273D"];
|
|
11
|
-
function createDefaultState() {
|
|
12
|
-
return { phase: "thinking" };
|
|
13
|
-
}
|
|
14
|
-
const streamingStates = /* @__PURE__ */ new Map([
|
|
15
|
-
["__main__", createDefaultState()]
|
|
16
|
-
]);
|
|
17
|
-
const agentContextStack = ["__main__"];
|
|
18
|
-
function getCurrentAgentContext() {
|
|
19
|
-
return agentContextStack[agentContextStack.length - 1] ?? "__main__";
|
|
20
|
-
}
|
|
21
|
-
function pushAgentContext(agentId) {
|
|
22
|
-
agentContextStack.push(agentId);
|
|
23
|
-
if (!streamingStates.has(agentId)) {
|
|
24
|
-
streamingStates.set(agentId, createDefaultState());
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function popAgentContext() {
|
|
28
|
-
if (agentContextStack.length > 1) {
|
|
29
|
-
return agentContextStack.pop();
|
|
30
|
-
}
|
|
31
|
-
return void 0;
|
|
32
|
-
}
|
|
33
|
-
function setStreamingState(state, agentId) {
|
|
34
|
-
const targetId = agentId ?? getCurrentAgentContext();
|
|
35
|
-
const current = streamingStates.get(targetId) ?? createDefaultState();
|
|
36
|
-
streamingStates.set(targetId, { ...current, ...state });
|
|
37
|
-
}
|
|
38
|
-
function resetStreamingState(agentId) {
|
|
39
|
-
const targetId = agentId ?? getCurrentAgentContext();
|
|
40
|
-
streamingStates.set(targetId, createDefaultState());
|
|
41
|
-
}
|
|
42
|
-
function getStreamingState(agentId) {
|
|
43
|
-
const targetId = agentId ?? getCurrentAgentContext();
|
|
44
|
-
return streamingStates.get(targetId) ?? createDefaultState();
|
|
45
|
-
}
|
|
46
|
-
function getMainStreamingState() {
|
|
47
|
-
return streamingStates.get("__main__") ?? createDefaultState();
|
|
48
|
-
}
|
|
49
|
-
function cleanupAgentStreamingState(agentId) {
|
|
50
|
-
streamingStates.delete(agentId);
|
|
51
|
-
}
|
|
52
22
|
const MESSAGES = [
|
|
53
23
|
"Accomplishing",
|
|
54
24
|
"Actioning",
|
|
@@ -118,7 +88,7 @@ function Spinner({ isActive = true }) {
|
|
|
118
88
|
spinnerFrameCount: frames.length,
|
|
119
89
|
componentId: "main-spinner"
|
|
120
90
|
});
|
|
121
|
-
const streamState = useMemo(() =>
|
|
91
|
+
const streamState = useMemo(() => getMainStreamingState2(), [spinnerFrame]);
|
|
122
92
|
const getPhaseDisplay = () => {
|
|
123
93
|
switch (streamState.phase) {
|
|
124
94
|
case "deep_thinking": {
|
|
@@ -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, 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'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\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// Streaming state type definition\nexport interface StreamingStateData {\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}\n\n// Default state factory\nfunction createDefaultState(): StreamingStateData {\n return { phase: 'thinking' }\n}\n\n// Store streaming state per agent (agentId -> state)\n// '__main__' is used for the main/root agent\nconst streamingStates: Map<string, StreamingStateData> = new Map([\n ['__main__', createDefaultState()],\n])\n\n// Current active agent context (stack to support nesting)\nconst agentContextStack: string[] = ['__main__']\n\n/**\n * Get the current active agent ID\n */\nexport function getCurrentAgentContext(): string {\n return agentContextStack[agentContextStack.length - 1] ?? '__main__'\n}\n\n/**\n * Push a new agent context (when entering a subagent)\n */\nexport function pushAgentContext(agentId: string): void {\n agentContextStack.push(agentId)\n if (!streamingStates.has(agentId)) {\n streamingStates.set(agentId, createDefaultState())\n }\n}\n\n/**\n * Pop the current agent context (when exiting a subagent)\n */\nexport function popAgentContext(): string | undefined {\n if (agentContextStack.length > 1) {\n return agentContextStack.pop()\n }\n return undefined\n}\n\n/**\n * Set streaming state for a specific agent (or current context if not specified)\n */\nexport function setStreamingState(\n state: Partial<StreamingStateData>,\n agentId?: string,\n): void {\n const targetId = agentId ?? getCurrentAgentContext()\n const current = streamingStates.get(targetId) ?? createDefaultState()\n streamingStates.set(targetId, { ...current, ...state })\n}\n\n/**\n * Reset streaming state for a specific agent (or current context if not specified)\n */\nexport function resetStreamingState(agentId?: string): void {\n const targetId = agentId ?? getCurrentAgentContext()\n streamingStates.set(targetId, createDefaultState())\n}\n\n/**\n * Get streaming state for a specific agent (or current context if not specified)\n */\nexport function getStreamingState(agentId?: string): StreamingStateData {\n const targetId = agentId ?? getCurrentAgentContext()\n return streamingStates.get(targetId) ?? createDefaultState()\n}\n\n/**\n * Get streaming state for the main/root agent (used by main Spinner)\n */\nexport function getMainStreamingState(): StreamingStateData {\n return streamingStates.get('__main__') ?? createDefaultState()\n}\n\n/**\n * Clean up streaming state for a completed agent\n */\nexport function cleanupAgentStreamingState(agentId: string): void {\n streamingStates.delete(agentId)\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 main streaming state on each render (updates when spinnerFrame changes)\n // Use getMainStreamingState to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [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 // \u4F7F\u7528\u8BED\u4E49\u989C\u8272\u7CFB\u7EDF\uFF0C\u54C1\u724C\u8272\u7528\u4E8E\u601D\u8003\uFF0C\u72B6\u6001\u8272\u7528\u4E8E\u5404\u9636\u6BB5\n const phaseColors: Record<StreamingPhase, string> = {\n thinking: BRAND_GRADIENT.MIDDLE, // \u7C89\u7D2B - \u601D\u8003\u4E2D\n deep_thinking: BRAND_GRADIENT.START, // \u7D2B\u84DD - \u6DF1\u5EA6\u601D\u8003\n generating: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u751F\u6210\u4E2D\n tool_use: SEMANTIC_COLORS.running, // \u7C89\u7D2B - \u5DE5\u5177\u6267\u884C\n waiting: SEMANTIC_COLORS.dim, // \u7070\u8272 - \u7B49\u5F85\n retrying: SEMANTIC_COLORS.error, // \u7EA2\u8272 - \u91CD\u8BD5\n permission: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u6743\u9650\n compacting: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u538B\u7F29\n concurrent: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u5E76\u53D1\n }\n\n // Get token usage from streaming state (API values or approximate from chars)\n const getTokenDisplay = () => {\n // Prefer API-provided token counts - always show bidirectional if available\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 approxOutputTokens = Math.round(streamState.receivedChars / 3)\n // If we have sentChars, show both directions\n if (streamState.sentChars && streamState.sentChars > 0) {\n const approxInputTokens = Math.round(streamState.sentChars / 3)\n return `\u2191 ~${formatNumber(approxInputTokens)} \u00B7 \u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return `\u2193 ~${formatNumber(approxOutputTokens)}`\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={SEMANTIC_COLORS.dim}>\n (<Text bold>esc esc</Text> to cancel \u00B7 {elapsedTime}s\n {tokenUsage && <Text> \u00B7 {tokenUsage}</Text>}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text> \u00B7 thinking {thinkingDuration}s</Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SEMANTIC_COLORS.dim}>\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\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={BRAND_GRADIENT.MIDDLE}>{frames[spinnerFrame]}</Text>\n </Box>\n {label && <Text color={SEMANTIC_COLORS.dim}> {label}</Text>}\n </Box>\n )\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useRef, useMemo } from 'react'\nimport { getTheme } from '@utils/theme'\nimport { sample } from 'lodash-es'\nimport { getSessionState } from '@utils/sessionState'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { formatNumber, formatTokenUsage } from '@utils/format'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\n\n// Re-export streaming state from canonical location for backward compatibility\nexport {\n type StreamingPhase,\n type StreamingStateData,\n getCurrentAgentContext,\n pushAgentContext,\n popAgentContext,\n setStreamingState,\n resetStreamingState,\n getStreamingState,\n getMainStreamingState,\n cleanupAgentStreamingState,\n} from '@utils/streamingState'\n\nimport { getMainStreamingState } from '@utils/streamingState'\nimport type { StreamingPhase } from '@utils/streamingState'\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\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 main streaming state on each render (updates when spinnerFrame changes)\n // Use getMainStreamingState to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [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 // \u4F7F\u7528\u8BED\u4E49\u989C\u8272\u7CFB\u7EDF\uFF0C\u54C1\u724C\u8272\u7528\u4E8E\u601D\u8003\uFF0C\u72B6\u6001\u8272\u7528\u4E8E\u5404\u9636\u6BB5\n const phaseColors: Record<StreamingPhase, string> = {\n thinking: BRAND_GRADIENT.MIDDLE, // \u7C89\u7D2B - \u601D\u8003\u4E2D\n deep_thinking: BRAND_GRADIENT.START, // \u7D2B\u84DD - \u6DF1\u5EA6\u601D\u8003\n generating: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u751F\u6210\u4E2D\n tool_use: SEMANTIC_COLORS.running, // \u7C89\u7D2B - \u5DE5\u5177\u6267\u884C\n waiting: SEMANTIC_COLORS.dim, // \u7070\u8272 - \u7B49\u5F85\n retrying: SEMANTIC_COLORS.error, // \u7EA2\u8272 - \u91CD\u8BD5\n permission: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u6743\u9650\n compacting: SEMANTIC_COLORS.info, // \u84DD\u8272 - \u538B\u7F29\n concurrent: SEMANTIC_COLORS.success, // \u7EFF\u8272 - \u5E76\u53D1\n }\n\n // Get token usage from streaming state (API values or approximate from chars)\n const getTokenDisplay = () => {\n // Prefer API-provided token counts - always show bidirectional if available\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 approxOutputTokens = Math.round(streamState.receivedChars / 3)\n // If we have sentChars, show both directions\n if (streamState.sentChars && streamState.sentChars > 0) {\n const approxInputTokens = Math.round(streamState.sentChars / 3)\n return `\u2191 ~${formatNumber(approxInputTokens)} \u00B7 \u2193 ~${formatNumber(approxOutputTokens)}`\n }\n return `\u2193 ~${formatNumber(approxOutputTokens)}`\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={SEMANTIC_COLORS.dim}>\n (<Text bold>esc esc</Text> to cancel \u00B7 {elapsedTime}s\n {tokenUsage && <Text> \u00B7 {tokenUsage}</Text>}\n {thinkingDuration !== null && thinkingDuration > 0 && (\n <Text> \u00B7 thinking {thinkingDuration}s</Text>\n )}\n )\n </Text>\n {getSessionState('currentError') && (\n <Text color={SEMANTIC_COLORS.dim}>\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\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={BRAND_GRADIENT.MIDDLE}>{frames[spinnerFrame]}</Text>\n </Box>\n {label && <Text color={SEMANTIC_COLORS.dim}> {label}</Text>}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["getMainStreamingState"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
|
+
import React, { useState, useCallback, useMemo } from "react";
|
|
3
|
+
import { SEMANTIC_COLORS } from "../constants/colors.js";
|
|
4
|
+
import { PulseLabel } from "./PulseLabel.js";
|
|
5
|
+
function useStartupStatus(definitions) {
|
|
6
|
+
const [itemMap, setItemMap] = useState(
|
|
7
|
+
() => new Map(
|
|
8
|
+
definitions.map((d) => [d.id, { label: d.label, status: "loading" }])
|
|
9
|
+
)
|
|
10
|
+
);
|
|
11
|
+
const update = useCallback(
|
|
12
|
+
(id, status, detail) => {
|
|
13
|
+
setItemMap((prev) => {
|
|
14
|
+
const existing = prev.get(id);
|
|
15
|
+
if (!existing) return prev;
|
|
16
|
+
const next = new Map(prev);
|
|
17
|
+
next.set(id, { ...existing, status, detail });
|
|
18
|
+
return next;
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
[]
|
|
22
|
+
);
|
|
23
|
+
const items = useMemo(() => Array.from(itemMap.values()), [itemMap]);
|
|
24
|
+
const isLoading = useMemo(
|
|
25
|
+
() => items.some((i) => i.status === "loading"),
|
|
26
|
+
[items]
|
|
27
|
+
);
|
|
28
|
+
return { items, update, isLoading };
|
|
29
|
+
}
|
|
30
|
+
function StartupStatusBar({
|
|
31
|
+
items
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ React.createElement(Box, { gap: 2 }, items.map((item, i) => {
|
|
34
|
+
const detail = item.detail ? ` \xB7 ${item.detail}` : "";
|
|
35
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: i }, item.status === "loading" ? /* @__PURE__ */ React.createElement(
|
|
36
|
+
PulseLabel,
|
|
37
|
+
{
|
|
38
|
+
label: `${item.label}${detail}`,
|
|
39
|
+
id: `startup-${i}`
|
|
40
|
+
}
|
|
41
|
+
) : /* @__PURE__ */ React.createElement(
|
|
42
|
+
Text,
|
|
43
|
+
{
|
|
44
|
+
color: item.status === "error" ? SEMANTIC_COLORS.error : SEMANTIC_COLORS.success
|
|
45
|
+
},
|
|
46
|
+
item.status === "error" ? "\u2717" : "\u2713",
|
|
47
|
+
" ",
|
|
48
|
+
item.label,
|
|
49
|
+
detail
|
|
50
|
+
));
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
StartupStatusBar,
|
|
55
|
+
useStartupStatus
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=StartupStatus.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/StartupStatus.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport React, { useState, useCallback, useMemo } from 'react'\nimport { SEMANTIC_COLORS } from '@constants/colors'\nimport { PulseLabel } from './PulseLabel'\n\nexport type StartupItem = {\n label: string\n status: 'loading' | 'done' | 'error'\n detail?: string\n}\n\n// \u2500\u2500 Hook \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype StartupDefinition = { id: string; label: string }\n\n/**\n * Manages a set of startup status items with id-based updates.\n *\n * Usage:\n * const { items, update } = useStartupStatus([\n * { id: 'mcp', label: 'MCP servers' },\n * { id: 'version', label: 'Version check' },\n * ])\n * // later:\n * update('mcp', 'done', '3/3 connected')\n */\nexport function useStartupStatus(definitions: StartupDefinition[]): {\n items: StartupItem[]\n update: (id: string, status: 'done' | 'error', detail?: string) => void\n isLoading: boolean\n} {\n // Build initial map once from definitions (order preserved by insertion order)\n const [itemMap, setItemMap] = useState<Map<string, StartupItem>>(\n () =>\n new Map(\n definitions.map(d => [d.id, { label: d.label, status: 'loading' }]),\n ),\n )\n\n const update = useCallback(\n (id: string, status: 'done' | 'error', detail?: string) => {\n setItemMap(prev => {\n const existing = prev.get(id)\n if (!existing) return prev\n const next = new Map(prev)\n next.set(id, { ...existing, status, detail })\n return next\n })\n },\n [],\n )\n\n const items = useMemo(() => Array.from(itemMap.values()), [itemMap])\n const isLoading = useMemo(\n () => items.some(i => i.status === 'loading'),\n [items],\n )\n\n return { items, update, isLoading }\n}\n\n/**\n * Compact startup status bar for PromptInput footer.\n * Loading items show a PulseLabel with breathing color on the full text;\n * done/error items show a static icon.\n */\nexport function StartupStatusBar({\n items,\n}: {\n items: StartupItem[]\n}): React.ReactNode {\n return (\n <Box gap={2}>\n {items.map((item, i) => {\n const detail = item.detail ? ` \u00B7 ${item.detail}` : ''\n\n return (\n <React.Fragment key={i}>\n {item.status === 'loading' ? (\n <PulseLabel\n label={`${item.label}${detail}`}\n id={`startup-${i}`}\n />\n ) : (\n <Text\n color={\n item.status === 'error'\n ? SEMANTIC_COLORS.error\n : SEMANTIC_COLORS.success\n }\n >\n {item.status === 'error' ? '\u2717' : '\u2713'} {item.label}\n {detail}\n </Text>\n )}\n </React.Fragment>\n )\n })}\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,OAAO,SAAS,UAAU,aAAa,eAAe;AACtD,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAuBpB,SAAS,iBAAiB,aAI/B;AAEA,QAAM,CAAC,SAAS,UAAU,IAAI;AAAA,IAC5B,MACE,IAAI;AAAA,MACF,YAAY,IAAI,OAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,QAAQ,UAAU,CAAC,CAAC;AAAA,IACpE;AAAA,EACJ;AAEA,QAAM,SAAS;AAAA,IACb,CAAC,IAAY,QAA0B,WAAoB;AACzD,iBAAW,UAAQ;AACjB,cAAM,WAAW,KAAK,IAAI,EAAE;AAC5B,YAAI,CAAC,SAAU,QAAO;AACtB,cAAM,OAAO,IAAI,IAAI,IAAI;AACzB,aAAK,IAAI,IAAI,EAAE,GAAG,UAAU,QAAQ,OAAO,CAAC;AAC5C,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAC;AAAA,EACH;AAEA,QAAM,QAAQ,QAAQ,MAAM,MAAM,KAAK,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;AACnE,QAAM,YAAY;AAAA,IAChB,MAAM,MAAM,KAAK,OAAK,EAAE,WAAW,SAAS;AAAA,IAC5C,CAAC,KAAK;AAAA,EACR;AAEA,SAAO,EAAE,OAAO,QAAQ,UAAU;AACpC;AAOO,SAAS,iBAAiB;AAAA,EAC/B;AACF,GAEoB;AAClB,SACE,oCAAC,OAAI,KAAK,KACP,MAAM,IAAI,CAAC,MAAM,MAAM;AACtB,UAAM,SAAS,KAAK,SAAS,SAAM,KAAK,MAAM,KAAK;AAEnD,WACE,oCAAC,MAAM,UAAN,EAAe,KAAK,KAClB,KAAK,WAAW,YACf;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,GAAG,KAAK,KAAK,GAAG,MAAM;AAAA,QAC7B,IAAI,WAAW,CAAC;AAAA;AAAA,IAClB,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,OACE,KAAK,WAAW,UACZ,gBAAgB,QAChB,gBAAgB;AAAA;AAAA,MAGrB,KAAK,WAAW,UAAU,WAAM;AAAA,MAAI;AAAA,MAAE,KAAK;AAAA,MAC3C;AAAA,IACH,CAEJ;AAAA,EAEJ,CAAC,CACH;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -56,7 +56,25 @@ function SubagentTodosSection({
|
|
|
56
56
|
))));
|
|
57
57
|
}
|
|
58
58
|
function extractSubagentTodos(subagent) {
|
|
59
|
-
|
|
59
|
+
let latestTodos = null;
|
|
60
|
+
for (const msg of subagent.messages) {
|
|
61
|
+
if (msg.type === "assistant" && "message" in msg) {
|
|
62
|
+
const todoBlocks = msg.message.content.filter(
|
|
63
|
+
(block) => block.type === "tool_use" && block.name === "TodoWrite"
|
|
64
|
+
);
|
|
65
|
+
for (const block of todoBlocks) {
|
|
66
|
+
if ("input" in block && block.input?.todos) {
|
|
67
|
+
latestTodos = block.input.todos.map((t, i) => ({
|
|
68
|
+
id: t.id ?? String(i),
|
|
69
|
+
content: t.content ?? "",
|
|
70
|
+
status: t.status ?? "pending",
|
|
71
|
+
priority: t.priority ?? "medium"
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return latestTodos;
|
|
60
78
|
}
|
|
61
79
|
function extractThinkingMessage(subagent) {
|
|
62
80
|
for (const msg of subagent.messages) {
|
|
@@ -76,6 +94,20 @@ function extractThinkingMessage(subagent) {
|
|
|
76
94
|
}
|
|
77
95
|
function extractToolExecutions(subagent) {
|
|
78
96
|
const tools = [];
|
|
97
|
+
const toolResultTimes = /* @__PURE__ */ new Map();
|
|
98
|
+
let msgIndex = 0;
|
|
99
|
+
for (const msg of subagent.messages) {
|
|
100
|
+
if (msg.type === "user" && "message" in msg) {
|
|
101
|
+
const resultBlocks = (Array.isArray(msg.message.content) ? msg.message.content : []).filter((block) => block.type === "tool_result");
|
|
102
|
+
for (const rb of resultBlocks) {
|
|
103
|
+
if ("tool_use_id" in rb) {
|
|
104
|
+
toolResultTimes.set(rb.tool_use_id, msgIndex);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
msgIndex++;
|
|
109
|
+
}
|
|
110
|
+
let toolIndex = 0;
|
|
79
111
|
for (const msg of subagent.messages) {
|
|
80
112
|
if (msg.type === "assistant" && "message" in msg) {
|
|
81
113
|
const toolBlocks = msg.message.content.filter(
|
|
@@ -83,16 +115,21 @@ function extractToolExecutions(subagent) {
|
|
|
83
115
|
);
|
|
84
116
|
for (const toolBlock of toolBlocks) {
|
|
85
117
|
if ("name" in toolBlock && "id" in toolBlock) {
|
|
118
|
+
const totalDuration = (subagent.metrics.endTime || Date.now()) - subagent.metrics.startTime;
|
|
119
|
+
const toolCount = subagent.metrics.toolUseCount || tools.length + 1;
|
|
120
|
+
const estimatedDuration = Math.max(
|
|
121
|
+
1,
|
|
122
|
+
Math.round(totalDuration / toolCount)
|
|
123
|
+
);
|
|
86
124
|
tools.push({
|
|
87
125
|
id: toolBlock.id,
|
|
88
126
|
name: toolBlock.name,
|
|
89
127
|
input: toolBlock.input,
|
|
90
|
-
status: "completed",
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
durationMs: 100
|
|
94
|
-
// Placeholder
|
|
128
|
+
status: toolResultTimes.has(toolBlock.id) ? "completed" : "running",
|
|
129
|
+
startTime: subagent.metrics.startTime + toolIndex * estimatedDuration,
|
|
130
|
+
durationMs: estimatedDuration
|
|
95
131
|
});
|
|
132
|
+
toolIndex++;
|
|
96
133
|
}
|
|
97
134
|
}
|
|
98
135
|
}
|
|
@@ -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 { useAgentTokenStats, formatTokenCount } from '@hooks/useAgentTokenStats'\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 // Get real-time token stats from unified TokenStatsManager\n const tokenStats = useAgentTokenStats(subagent.id)\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 // Use token stats from TokenStatsManager (single source of truth)\n const tokenCount = tokenStats?.grandTotalTokens ?? 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, {formatTokenCount(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
|
-
"mappings": "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
|
|
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 { useAgentTokenStats, formatTokenCount } from '@hooks/useAgentTokenStats'\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 // Get real-time token stats from unified TokenStatsManager\n const tokenStats = useAgentTokenStats(subagent.id)\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 // Use token stats from TokenStatsManager (single source of truth)\n const tokenCount = tokenStats?.grandTotalTokens ?? 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, {formatTokenCount(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 // Extract todos from TodoWrite tool_use blocks in subagent messages\n let latestTodos: TodoItem[] | null = null\n\n for (const msg of subagent.messages) {\n if (msg.type === 'assistant' && 'message' in msg) {\n const todoBlocks = msg.message.content.filter(\n (block: any) => block.type === 'tool_use' && block.name === 'TodoWrite',\n )\n for (const block of todoBlocks) {\n if ('input' in block && block.input?.todos) {\n // Each TodoWrite call replaces the full list\n latestTodos = (block.input.todos as any[]).map((t, i) => ({\n id: t.id ?? String(i),\n content: t.content ?? '',\n status: t.status ?? 'pending',\n priority: t.priority ?? 'medium',\n }))\n }\n }\n }\n }\n\n return latestTodos\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, pair with tool_result for duration\n const toolResultTimes = new Map<string, number>()\n let msgIndex = 0\n\n for (const msg of subagent.messages) {\n if (msg.type === 'user' && 'message' in msg) {\n const resultBlocks = (\n Array.isArray(msg.message.content) ? msg.message.content : []\n ).filter((block: any) => block.type === 'tool_result')\n for (const rb of resultBlocks) {\n if ('tool_use_id' in rb) {\n toolResultTimes.set(rb.tool_use_id as string, msgIndex)\n }\n }\n }\n msgIndex++\n }\n\n let toolIndex = 0\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 // Estimate duration: spread evenly across total subagent time\n const totalDuration =\n (subagent.metrics.endTime || Date.now()) -\n subagent.metrics.startTime\n const toolCount = subagent.metrics.toolUseCount || tools.length + 1\n const estimatedDuration = Math.max(\n 1,\n Math.round(totalDuration / toolCount),\n )\n\n tools.push({\n id: toolBlock.id,\n name: toolBlock.name,\n input: toolBlock.input,\n status: toolResultTimes.has(toolBlock.id) ? 'completed' : 'running',\n startTime:\n subagent.metrics.startTime + toolIndex * estimatedDuration,\n durationMs: estimatedDuration,\n })\n toolIndex++\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
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,16 +2,21 @@ import React from "react";
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
4
4
|
function TabBar({ tabs, activeTab, onTabChange }) {
|
|
5
|
-
return /* @__PURE__ */ React.createElement(Box,
|
|
5
|
+
return /* @__PURE__ */ React.createElement(Box, { flexShrink: 0 }, tabs.map((tab, index) => {
|
|
6
6
|
const isActive = tab.id === activeTab;
|
|
7
7
|
const isLast = index === tabs.length - 1;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const badgeSuffix = tab.badge !== void 0 && tab.badge > 0 ? ` (${tab.badge})` : "";
|
|
9
|
+
const label = ` ${tab.label}${badgeSuffix} `;
|
|
10
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, { key: tab.id }, isActive ? /* @__PURE__ */ React.createElement(
|
|
11
|
+
Text,
|
|
12
|
+
{
|
|
13
|
+
wrap: "truncate",
|
|
14
|
+
backgroundColor: BRAND_GRADIENT.START,
|
|
15
|
+
color: "black",
|
|
16
|
+
bold: true
|
|
17
|
+
},
|
|
18
|
+
label
|
|
19
|
+
) : /* @__PURE__ */ React.createElement(Text, { wrap: "truncate", color: SEMANTIC_COLORS.dim }, label), !isLast && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, "\u2502"));
|
|
15
20
|
}), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " Tab/\u2190\u2192"));
|
|
16
21
|
}
|
|
17
22
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/TabbedListView/TabBar.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * TabBar Component\n *\n * Displays tab navigation matching the brand style.\n * Uses background color for active tab selection.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport type { TabBarProps } from './types'\n\nexport function TabBar({ tabs, activeTab, onTabChange }: TabBarProps) {\n return (\n <Box>\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab\n const isLast = index === tabs.length - 1\n\n
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * TabBar Component\n *\n * Displays tab navigation matching the brand style.\n * Uses background color for active tab selection.\n *\n * Layout notes:\n * - Each tab Box uses flexShrink={0} to prevent Yoga from compressing tabs\n * - Text uses wrap=\"truncate\" to prevent line wrapping in tight layouts\n * - Both active and inactive tabs use identical string content (no nested <Text>)\n * to ensure consistent width measurement by Ink's Yoga engine\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport type { TabBarProps } from './types'\n\nexport function TabBar({ tabs, activeTab, onTabChange }: TabBarProps) {\n return (\n <Box flexShrink={0}>\n {tabs.map((tab, index) => {\n const isActive = tab.id === activeTab\n const isLast = index === tabs.length - 1\n\n // Build label string identically for active/inactive to ensure\n // consistent width measurement by Yoga\n const badgeSuffix =\n tab.badge !== undefined && tab.badge > 0 ? ` (${tab.badge})` : ''\n const label = ` ${tab.label}${badgeSuffix} `\n\n return (\n <React.Fragment key={tab.id}>\n {isActive ? (\n <Text\n wrap=\"truncate\"\n backgroundColor={BRAND_GRADIENT.START}\n color=\"black\"\n bold\n >\n {label}\n </Text>\n ) : (\n <Text wrap=\"truncate\" color={SEMANTIC_COLORS.dim}>\n {label}\n </Text>\n )}\n {!isLast && <Text color={SEMANTIC_COLORS.muted}>\u2502</Text>}\n </React.Fragment>\n )\n })}\n <Text color={SEMANTIC_COLORS.muted}> Tab/\u2190\u2192</Text>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAaA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB,uBAAuB;AAGzC,SAAS,OAAO,EAAE,MAAM,WAAW,YAAY,GAAgB;AACpE,SACE,oCAAC,OAAI,YAAY,KACd,KAAK,IAAI,CAAC,KAAK,UAAU;AACxB,UAAM,WAAW,IAAI,OAAO;AAC5B,UAAM,SAAS,UAAU,KAAK,SAAS;AAIvC,UAAM,cACJ,IAAI,UAAU,UAAa,IAAI,QAAQ,IAAI,KAAK,IAAI,KAAK,MAAM;AACjE,UAAM,QAAQ,IAAI,IAAI,KAAK,GAAG,WAAW;AAEzC,WACE,oCAAC,MAAM,UAAN,EAAe,KAAK,IAAI,MACtB,WACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAiB,eAAe;AAAA,QAChC,OAAM;AAAA,QACN,MAAI;AAAA;AAAA,MAEH;AAAA,IACH,IAEA,oCAAC,QAAK,MAAK,YAAW,OAAO,gBAAgB,OAC1C,KACH,GAED,CAAC,UAAU,oCAAC,QAAK,OAAO,gBAAgB,SAAO,QAAC,CACnD;AAAA,EAEJ,CAAC,GACD,oCAAC,QAAK,OAAO,gBAAgB,SAAO,mBAAO,CAC7C;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -192,7 +192,7 @@ function TabbedListView({
|
|
|
192
192
|
flexDirection: "column"
|
|
193
193
|
},
|
|
194
194
|
/* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.START }, "\u25C6"), /* @__PURE__ */ React.createElement(Text, { bold: true, color: SEMANTIC_COLORS.secondary }, " ", title), showItemCount && !statusOverlay && filteredItems.length > 0 && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " (", filteredItems.length, ")")),
|
|
195
|
-
/* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(TabBar, { tabs, activeTab, onTabChange }))
|
|
195
|
+
/* @__PURE__ */ React.createElement(Box, { marginTop: 1, flexShrink: 0 }, /* @__PURE__ */ React.createElement(TabBar, { tabs, activeTab, onTabChange }))
|
|
196
196
|
), /* @__PURE__ */ React.createElement(
|
|
197
197
|
Box,
|
|
198
198
|
{
|