@within-7/minto 0.3.9 → 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 +461 -657
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/types.js +1 -0
- package/dist/commands/agents/types.js.map +2 -2
- package/dist/commands/agents/utils/fileOperations.js +96 -36
- package/dist/commands/agents/utils/fileOperations.js.map +3 -3
- package/dist/commands/agents/utils/index.js +3 -1
- package/dist/commands/agents/utils/index.js.map +2 -2
- package/dist/commands/context.js +54 -23
- package/dist/commands/context.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 +684 -94
- 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/language.js +19 -46
- package/dist/commands/language.js.map +2 -2
- package/dist/commands/mcp-interactive.js +425 -217
- 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 +457 -65
- 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/permissions.js +75 -49
- package/dist/commands/permissions.js.map +2 -2
- package/dist/commands/plugin/utils.js +33 -1
- package/dist/commands/plugin/utils.js.map +2 -2
- package/dist/commands/plugin.js +891 -185
- package/dist/commands/plugin.js.map +3 -3
- package/dist/commands/refreshCommands.js +2 -0
- package/dist/commands/refreshCommands.js.map +2 -2
- package/dist/commands/resume.js +1 -1
- package/dist/commands/resume.js.map +1 -1
- package/dist/commands/review.js +51 -0
- package/dist/commands/review.js.map +7 -0
- package/dist/commands/sandbox.js +168 -70
- package/dist/commands/sandbox.js.map +2 -2
- package/dist/commands/setup.js +593 -107
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/stats.js +188 -131
- package/dist/commands/stats.js.map +2 -2
- package/dist/commands/status.js +75 -13
- package/dist/commands/status.js.map +2 -2
- package/dist/commands/terminalSetup.js +6 -0
- package/dist/commands/terminalSetup.js.map +2 -2
- package/dist/commands/undo.js +146 -174
- 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/Help.js +165 -32
- package/dist/components/Help.js.map +2 -2
- package/dist/components/HighlightedCode.js +1 -0
- package/dist/components/HighlightedCode.js.map +2 -2
- package/dist/components/InfoPanel/InfoPanel.js +123 -0
- package/dist/components/InfoPanel/InfoPanel.js.map +7 -0
- package/dist/components/InfoPanel/index.js +5 -0
- package/dist/components/InfoPanel/index.js.map +7 -0
- package/dist/components/InfoPanel/types.js +1 -0
- package/dist/components/InfoPanel/types.js.map +7 -0
- package/dist/components/ModelSelector/BrandTextInput.js +43 -0
- package/dist/components/ModelSelector/BrandTextInput.js.map +7 -0
- package/dist/components/ModelSelector/ModelSelector.js +590 -565
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/ModelSelector/WizardContainer.js +45 -0
- package/dist/components/ModelSelector/WizardContainer.js.map +7 -0
- package/dist/components/ModelSelector/index.js +1 -3
- package/dist/components/ModelSelector/index.js.map +2 -2
- package/dist/components/PromptInput.js +26 -11
- 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/SimpleSelector/SimpleSelector.js +154 -0
- package/dist/components/SimpleSelector/SimpleSelector.js.map +7 -0
- package/dist/components/SimpleSelector/index.js +5 -0
- package/dist/components/SimpleSelector/index.js.map +7 -0
- package/dist/components/SimpleSelector/types.js +1 -0
- package/dist/components/SimpleSelector/types.js.map +7 -0
- 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/StatusOverlayContent.js +21 -0
- package/dist/components/StatusOverlayContent.js.map +7 -0
- package/dist/components/SubagentBlock.js +43 -6
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/TabbedListView/ScrollableList.js +31 -5
- package/dist/components/TabbedListView/ScrollableList.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 +123 -48
- 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 +29 -0
- package/dist/core/backupHook.js.map +7 -0
- package/dist/core/config/defaults.js +11 -2
- package/dist/core/config/defaults.js.map +2 -2
- package/dist/core/config/schema.js +21 -3
- package/dist/core/config/schema.js.map +2 -2
- package/dist/core/costTracker.js +18 -16
- 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/cost-tracker.js +0 -16
- package/dist/cost-tracker.js.map +2 -2
- package/dist/entrypoints/bootstrap.js +3 -1
- package/dist/entrypoints/bootstrap.js.map +2 -2
- package/dist/entrypoints/cli.js +81 -68
- 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 +299 -1
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +300 -2
- 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/customCommands.js +30 -8
- package/dist/services/customCommands.js.map +2 -2
- 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/lspServers.js +1 -1
- package/dist/services/plugins/lspServers.js.map +2 -2
- package/dist/services/plugins/pluginRuntime.js +2 -1
- package/dist/services/plugins/pluginRuntime.js.map +2 -2
- package/dist/services/plugins/pluginValidation.js +10 -3
- package/dist/services/plugins/pluginValidation.js.map +2 -2
- package/dist/services/plugins/skillMarketplace.js +20 -9
- 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 +367 -9
- 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 +8 -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 +10 -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 +7 -0
- package/dist/tools/MultiEditTool/MultiEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +2 -0
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- 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 +84 -11
- 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 +3 -5
- package/dist/types/plugin.js.map +2 -2
- package/dist/utils/agentHookExecutor.js +1 -4
- package/dist/utils/agentHookExecutor.js.map +2 -2
- package/dist/utils/agentLoader.js +91 -15
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/agentMemory.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/claudeCodeSync.js +439 -0
- package/dist/utils/claudeCodeSync.js.map +7 -0
- package/dist/utils/config.js +27 -151
- 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/execFileNoThrow.js +2 -1
- package/dist/utils/execFileNoThrow.js.map +2 -2
- 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/marketplaceManager.js +80 -43
- package/dist/utils/marketplaceManager.js.map +2 -2
- package/dist/utils/memoizeWithTTL.js +25 -0
- package/dist/utils/memoizeWithTTL.js.map +7 -0
- package/dist/utils/messages.js +2 -2
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/model.js +34 -9
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/pluginInstaller.js +68 -29
- package/dist/utils/pluginInstaller.js.map +2 -2
- package/dist/utils/pluginLoader.js +249 -57
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/repoFetcher.js +110 -0
- package/dist/utils/repoFetcher.js.map +7 -0
- package/dist/utils/safeFetch.js +45 -0
- package/dist/utils/safeFetch.js.map +7 -0
- package/dist/utils/skillLoader.js +77 -12
- 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/stringSubstitution.js +4 -5
- package/dist/utils/stringSubstitution.js.map +2 -2
- package/dist/utils/style.js +6 -3
- package/dist/utils/style.js.map +2 -2
- package/dist/utils/teamConfig.js +162 -16
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/terminal.js +1 -1
- package/dist/utils/terminal.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 +7 -6
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { useRef } from "react";
|
|
2
|
+
import { Text } from "ink";
|
|
3
|
+
import { BRAND_GRADIENT } from "../constants/colors.js";
|
|
4
|
+
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
5
|
+
const CHARACTERS = process.platform === "darwin" ? ["\xB7", "\u2722", "\u2733", "\u2217", "\u273B", "\u273D"] : ["\xB7", "\u2722", "*", "\u2217", "\u273B", "\u273D"];
|
|
6
|
+
const SPINNER_FRAMES = [...CHARACTERS, ...[...CHARACTERS].reverse()];
|
|
7
|
+
function lerpColor(a, b, t) {
|
|
8
|
+
const ha = parseInt(a.replace("#", ""), 16);
|
|
9
|
+
const hb = parseInt(b.replace("#", ""), 16);
|
|
10
|
+
const rA = ha >> 16 & 255, gA = ha >> 8 & 255, bA = ha & 255;
|
|
11
|
+
const rB = hb >> 16 & 255, gB = hb >> 8 & 255, bB = hb & 255;
|
|
12
|
+
const r = Math.round(rA + (rB - rA) * t);
|
|
13
|
+
const g = Math.round(gA + (gB - gA) * t);
|
|
14
|
+
const bl = Math.round(bA + (bB - bA) * t);
|
|
15
|
+
return `#${(1 << 24 | r << 16 | g << 8 | bl).toString(16).slice(1)}`;
|
|
16
|
+
}
|
|
17
|
+
const COLOR_STEPS = SPINNER_FRAMES.length;
|
|
18
|
+
const PULSE_TABLE = Array.from(
|
|
19
|
+
{ length: COLOR_STEPS },
|
|
20
|
+
(_, i) => Math.sin(i / (COLOR_STEPS - 1) * Math.PI)
|
|
21
|
+
);
|
|
22
|
+
const COLOR_DIM = "#555555";
|
|
23
|
+
function PulseLabel({
|
|
24
|
+
label,
|
|
25
|
+
bright = BRAND_GRADIENT.MIDDLE,
|
|
26
|
+
dim = COLOR_DIM,
|
|
27
|
+
isActive = true,
|
|
28
|
+
id = "pulse-label"
|
|
29
|
+
}) {
|
|
30
|
+
const startTimeRef = useRef(Date.now());
|
|
31
|
+
const { spinnerFrame } = useUnifiedAnimation({
|
|
32
|
+
enabled: isActive,
|
|
33
|
+
startTime: startTimeRef.current,
|
|
34
|
+
spinnerFrameCount: SPINNER_FRAMES.length,
|
|
35
|
+
componentId: id
|
|
36
|
+
});
|
|
37
|
+
const color = isActive ? lerpColor(dim, bright, PULSE_TABLE[spinnerFrame] ?? 0) : bright;
|
|
38
|
+
const char = SPINNER_FRAMES[spinnerFrame] ?? SPINNER_FRAMES[0];
|
|
39
|
+
return /* @__PURE__ */ React.createElement(Text, { color }, char, " ", label);
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
PulseLabel
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=PulseLabel.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/PulseLabel.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * PulseLabel \u2014 reusable inline loading indicator.\n *\n * Combines two visual effects:\n * 1. Cycling spinner character (\u00B7 \u2722 \u2733 \u2217 \u273B \u273D), same as the main Spinner\n * 2. Breathing text color (dim \u2194 bright), smooth sine-wave interpolation\n *\n * Both the spinner character and the label text share the same breathing color,\n * creating a unified \"alive\" loading indicator.\n *\n * Usage:\n * <PulseLabel label=\"MCP servers\" />\n * <PulseLabel label=\"Connecting\" bright=\"#22c55e\" />\n */\n\nimport React, { useRef } from 'react'\nimport { Text } from 'ink'\nimport { BRAND_GRADIENT } from '@constants/colors'\nimport { useUnifiedAnimation } from '@utils/animationManager'\n\n// \u2500\u2500 Spinner characters (same set as Spinner.tsx) \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\nconst CHARACTERS =\n process.platform === 'darwin'\n ? ['\u00B7', '\u2722', '\u2733', '\u2217', '\u273B', '\u273D']\n : ['\u00B7', '\u2722', '*', '\u2217', '\u273B', '\u273D']\n\nconst SPINNER_FRAMES = [...CHARACTERS, ...[...CHARACTERS].reverse()]\n\n// \u2500\u2500 Color breathing table \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\n/** Interpolate between two hex colors. t=0 \u2192 colorA, t=1 \u2192 colorB */\nfunction lerpColor(a: string, b: string, t: number): string {\n const ha = parseInt(a.replace('#', ''), 16)\n const hb = parseInt(b.replace('#', ''), 16)\n\n const rA = (ha >> 16) & 0xff,\n gA = (ha >> 8) & 0xff,\n bA = ha & 0xff\n const rB = (hb >> 16) & 0xff,\n gB = (hb >> 8) & 0xff,\n bB = hb & 0xff\n\n const r = Math.round(rA + (rB - rA) * t)\n const g = Math.round(gA + (gB - gA) * t)\n const bl = Math.round(bA + (bB - bA) * t)\n\n return `#${((1 << 24) | (r << 16) | (g << 8) | bl).toString(16).slice(1)}`\n}\n\n// Use same frame count as spinner so both animations stay in sync\nconst COLOR_STEPS = SPINNER_FRAMES.length\nconst PULSE_TABLE = Array.from({ length: COLOR_STEPS }, (_, i) =>\n Math.sin((i / (COLOR_STEPS - 1)) * Math.PI),\n)\n\nconst COLOR_DIM = '#555555'\n\n// \u2500\u2500 Component \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\ninterface PulseLabelProps {\n /** Text to display after the spinner character */\n label: string\n /** Bright end of the breathing range (default: BRAND_GRADIENT.MIDDLE) */\n bright?: string\n /** Dim end of the breathing range (default: #555555) */\n dim?: string\n /** Whether the animation is active (default: true) */\n isActive?: boolean\n /** Unique id when multiple PulseLabels coexist (default: 'pulse-label') */\n id?: string\n}\n\nexport function PulseLabel({\n label,\n bright = BRAND_GRADIENT.MIDDLE,\n dim = COLOR_DIM,\n isActive = true,\n id = 'pulse-label',\n}: PulseLabelProps): React.ReactNode {\n const startTimeRef = useRef(Date.now())\n\n const { spinnerFrame } = useUnifiedAnimation({\n enabled: isActive,\n startTime: startTimeRef.current,\n spinnerFrameCount: SPINNER_FRAMES.length,\n componentId: id,\n })\n\n const color = isActive\n ? lerpColor(dim, bright, PULSE_TABLE[spinnerFrame] ?? 0)\n : bright\n\n const char = SPINNER_FRAMES[spinnerFrame] ?? SPINNER_FRAMES[0]\n\n return (\n <Text color={color}>\n {char} {label}\n </Text>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAeA,OAAO,SAAS,cAAc;AAC9B,SAAS,YAAY;AACrB,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AAGpC,MAAM,aACJ,QAAQ,aAAa,WACjB,CAAC,QAAK,UAAK,UAAK,UAAK,UAAK,QAAG,IAC7B,CAAC,QAAK,UAAK,KAAK,UAAK,UAAK,QAAG;AAEnC,MAAM,iBAAiB,CAAC,GAAG,YAAY,GAAG,CAAC,GAAG,UAAU,EAAE,QAAQ,CAAC;AAKnE,SAAS,UAAU,GAAW,GAAW,GAAmB;AAC1D,QAAM,KAAK,SAAS,EAAE,QAAQ,KAAK,EAAE,GAAG,EAAE;AAC1C,QAAM,KAAK,SAAS,EAAE,QAAQ,KAAK,EAAE,GAAG,EAAE;AAE1C,QAAM,KAAM,MAAM,KAAM,KACtB,KAAM,MAAM,IAAK,KACjB,KAAK,KAAK;AACZ,QAAM,KAAM,MAAM,KAAM,KACtB,KAAM,MAAM,IAAK,KACjB,KAAK,KAAK;AAEZ,QAAM,IAAI,KAAK,MAAM,MAAM,KAAK,MAAM,CAAC;AACvC,QAAM,IAAI,KAAK,MAAM,MAAM,KAAK,MAAM,CAAC;AACvC,QAAM,KAAK,KAAK,MAAM,MAAM,KAAK,MAAM,CAAC;AAExC,SAAO,KAAM,KAAK,KAAO,KAAK,KAAO,KAAK,IAAK,IAAI,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAC1E;AAGA,MAAM,cAAc,eAAe;AACnC,MAAM,cAAc,MAAM;AAAA,EAAK,EAAE,QAAQ,YAAY;AAAA,EAAG,CAAC,GAAG,MAC1D,KAAK,IAAK,KAAK,cAAc,KAAM,KAAK,EAAE;AAC5C;AAEA,MAAM,YAAY;AAiBX,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,SAAS,eAAe;AAAA,EACxB,MAAM;AAAA,EACN,WAAW;AAAA,EACX,KAAK;AACP,GAAqC;AACnC,QAAM,eAAe,OAAO,KAAK,IAAI,CAAC;AAEtC,QAAM,EAAE,aAAa,IAAI,oBAAoB;AAAA,IAC3C,SAAS;AAAA,IACT,WAAW,aAAa;AAAA,IACxB,mBAAmB,eAAe;AAAA,IAClC,aAAa;AAAA,EACf,CAAC;AAED,QAAM,QAAQ,WACV,UAAU,KAAK,QAAQ,YAAY,YAAY,KAAK,CAAC,IACrD;AAEJ,QAAM,OAAO,eAAe,YAAY,KAAK,eAAe,CAAC;AAE7D,SACE,oCAAC,QAAK,SACH,MAAK,KAAE,KACV;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import { useRef, useMemo } from "react";
|
|
4
4
|
import { getTheme } from "../utils/theme.js";
|
|
5
5
|
import { getGlobalConfig } from "../utils/config.js";
|
|
6
|
-
import { getStreamingState } from "
|
|
6
|
+
import { getStreamingState } from "../utils/streamingState.js";
|
|
7
7
|
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
8
8
|
const PHASE_INDICATORS = {
|
|
9
9
|
thinking: "\u25D0",
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import React, { useState, useMemo, useCallback } from "react";
|
|
2
|
+
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
4
|
+
import { ScrollableList } from "../TabbedListView/index.js";
|
|
5
|
+
import { StatusOverlayContent } from "../StatusOverlayContent.js";
|
|
6
|
+
import { useTerminalSize } from "../../hooks/useTerminalSize.js";
|
|
7
|
+
import { t } from "../../i18n/index.js";
|
|
8
|
+
const PROMPT_HEIGHT = 5;
|
|
9
|
+
const CHROME_HEIGHT = 4;
|
|
10
|
+
function toListItems(items) {
|
|
11
|
+
return items.map((item) => ({
|
|
12
|
+
id: item.id,
|
|
13
|
+
label: item.label,
|
|
14
|
+
description: item.description,
|
|
15
|
+
category: item.category,
|
|
16
|
+
metadata: item.isCurrent ? `(${t("common.selected")})` : void 0,
|
|
17
|
+
status: item.isCurrent ? "enabled" : void 0,
|
|
18
|
+
data: item
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
function SelectorItemRenderer({
|
|
22
|
+
item,
|
|
23
|
+
isFocused,
|
|
24
|
+
selectorItem
|
|
25
|
+
}) {
|
|
26
|
+
const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim;
|
|
27
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, { color: isFocused ? BRAND_GRADIENT.START : void 0 }, isFocused ? "\u25C6 " : " "), selectorItem?.statusIcon && /* @__PURE__ */ React.createElement(Text, { color: selectorItem.statusColor || SEMANTIC_COLORS.dim }, selectorItem.statusIcon, " "), /* @__PURE__ */ React.createElement(Text, { color: textColor }, item.label, selectorItem?.isCurrent && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, " (", t("common.selected"), ")"), item.description && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, " ", item.description)));
|
|
28
|
+
}
|
|
29
|
+
function SimpleSelector({
|
|
30
|
+
title,
|
|
31
|
+
subtitle,
|
|
32
|
+
items,
|
|
33
|
+
onSelect,
|
|
34
|
+
onClose,
|
|
35
|
+
groupByCategory = false,
|
|
36
|
+
statusOverlay,
|
|
37
|
+
isActive = true,
|
|
38
|
+
maxVisible
|
|
39
|
+
}) {
|
|
40
|
+
const { rows } = useTerminalSize();
|
|
41
|
+
const dynamicVisible = Math.min(
|
|
42
|
+
8,
|
|
43
|
+
Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT)
|
|
44
|
+
);
|
|
45
|
+
const effectiveMaxVisible = maxVisible ?? dynamicVisible;
|
|
46
|
+
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
47
|
+
const listItems = useMemo(() => toListItems(items), [items]);
|
|
48
|
+
const selectorItemMap = useMemo(() => {
|
|
49
|
+
const map = /* @__PURE__ */ new Map();
|
|
50
|
+
items.forEach((item) => map.set(item.id, item));
|
|
51
|
+
return map;
|
|
52
|
+
}, [items]);
|
|
53
|
+
const handleSelect = useCallback(
|
|
54
|
+
(listItem) => {
|
|
55
|
+
const selectorItem = selectorItemMap.get(listItem.id);
|
|
56
|
+
if (selectorItem) {
|
|
57
|
+
onSelect(selectorItem);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
[selectorItemMap, onSelect]
|
|
61
|
+
);
|
|
62
|
+
const renderItem = useCallback(
|
|
63
|
+
(item, isFocused) => /* @__PURE__ */ React.createElement(
|
|
64
|
+
SelectorItemRenderer,
|
|
65
|
+
{
|
|
66
|
+
item,
|
|
67
|
+
isFocused,
|
|
68
|
+
selectorItem: selectorItemMap.get(item.id)
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
[selectorItemMap]
|
|
72
|
+
);
|
|
73
|
+
useInput(
|
|
74
|
+
(input, key) => {
|
|
75
|
+
if (statusOverlay && statusOverlay.type !== "loading") {
|
|
76
|
+
if (key.escape || key.return) {
|
|
77
|
+
onClose();
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (statusOverlay) return;
|
|
82
|
+
if (key.escape) {
|
|
83
|
+
onClose();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (key.downArrow && listItems.length > 0) {
|
|
87
|
+
setFocusedIndex((prev) => prev < listItems.length - 1 ? prev + 1 : prev);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (key.upArrow && listItems.length > 0) {
|
|
91
|
+
setFocusedIndex((prev) => prev > 0 ? prev - 1 : prev);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (key.return && listItems.length > 0) {
|
|
95
|
+
handleSelect(listItems[focusedIndex]);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
{ isActive }
|
|
100
|
+
);
|
|
101
|
+
const footerHint = statusOverlay ? statusOverlay.type === "loading" ? "" : t("ui.simpleSelector.dismissHint") : t("ui.simpleSelector.navigationHint");
|
|
102
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%" }, /* @__PURE__ */ React.createElement(
|
|
103
|
+
Box,
|
|
104
|
+
{
|
|
105
|
+
borderTop: true,
|
|
106
|
+
borderBottom: false,
|
|
107
|
+
borderLeft: false,
|
|
108
|
+
borderRight: false,
|
|
109
|
+
borderColor: BRAND_GRADIENT.START,
|
|
110
|
+
borderStyle: "single",
|
|
111
|
+
width: "100%",
|
|
112
|
+
paddingX: 1,
|
|
113
|
+
flexDirection: "column"
|
|
114
|
+
},
|
|
115
|
+
/* @__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), subtitle && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, " ", subtitle))
|
|
116
|
+
), /* @__PURE__ */ React.createElement(
|
|
117
|
+
Box,
|
|
118
|
+
{
|
|
119
|
+
flexDirection: "column",
|
|
120
|
+
borderTop: false,
|
|
121
|
+
borderBottom: true,
|
|
122
|
+
borderLeft: false,
|
|
123
|
+
borderRight: false,
|
|
124
|
+
borderColor: BRAND_GRADIENT.START,
|
|
125
|
+
borderStyle: "single",
|
|
126
|
+
width: "100%",
|
|
127
|
+
paddingX: 1,
|
|
128
|
+
paddingY: 1
|
|
129
|
+
},
|
|
130
|
+
statusOverlay ? /* @__PURE__ */ React.createElement(
|
|
131
|
+
StatusOverlayContent,
|
|
132
|
+
{
|
|
133
|
+
type: statusOverlay.type,
|
|
134
|
+
message: statusOverlay.message
|
|
135
|
+
}
|
|
136
|
+
) : listItems.length === 0 ? /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("ui.tabbedList.noItems"))) : /* @__PURE__ */ React.createElement(
|
|
137
|
+
ScrollableList,
|
|
138
|
+
{
|
|
139
|
+
items: listItems,
|
|
140
|
+
focusedIndex,
|
|
141
|
+
onFocusChange: setFocusedIndex,
|
|
142
|
+
onSelect: handleSelect,
|
|
143
|
+
visibleCount: effectiveMaxVisible,
|
|
144
|
+
groupByCategory,
|
|
145
|
+
renderItem
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
footerHint && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.muted }, footerHint))
|
|
149
|
+
));
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
SimpleSelector
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=SimpleSelector.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/SimpleSelector/SimpleSelector.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * SimpleSelector Component\n *\n * A lightweight single-choice selector visually matching TabbedListView\n * but without tabs or search. Reuses ScrollableList internally.\n *\n * Visual pattern:\n * \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 (BRAND_GRADIENT.START border)\n * \u25C6 Title subtitle\n *\n * Category Name\n * \u25C6 Item A (current)\n * Item B description\n * Item C description\n *\n * \u2191\u2193 Navigate \u00B7 Enter Select \u00B7 Esc Close\n * \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 (BRAND_GRADIENT.START border)\n */\n\nimport React, { useState, useMemo, useCallback } from 'react'\nimport { Box, Text, useInput } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { ScrollableList } from '@components/TabbedListView'\nimport { StatusOverlayContent } from '@components/StatusOverlayContent'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { t } from '@i18n'\nimport type { ListItem } from '@components/TabbedListView'\nimport type { SimpleSelectorProps, SelectorItem } from './types'\n\n// Heights for dynamic visible count calculation\nconst PROMPT_HEIGHT = 5 // PromptInput borders + input + hints\nconst CHROME_HEIGHT = 4 // title + footer + borders (no tabs/search)\n\n/**\n * Convert SelectorItems to ListItems for ScrollableList\n */\nfunction toListItems(items: SelectorItem[]): ListItem[] {\n return items.map(item => ({\n id: item.id,\n label: item.label,\n description: item.description,\n category: item.category,\n metadata: item.isCurrent ? `(${t('common.selected')})` : undefined,\n status: item.isCurrent ? ('enabled' as const) : undefined,\n data: item,\n }))\n}\n\n/**\n * Custom item renderer that supports statusIcon and statusColor\n */\nfunction SelectorItemRenderer({\n item,\n isFocused,\n selectorItem,\n}: {\n item: ListItem\n isFocused: boolean\n selectorItem?: SelectorItem\n}) {\n const textColor = isFocused ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim\n\n return (\n <Box flexDirection=\"row\">\n {/* Selection indicator */}\n <Text color={isFocused ? BRAND_GRADIENT.START : undefined}>\n {isFocused ? '\\u25C6 ' : ' '}\n </Text>\n\n {/* Status icon if present */}\n {selectorItem?.statusIcon && (\n <Text color={selectorItem.statusColor || SEMANTIC_COLORS.dim}>\n {selectorItem.statusIcon}{' '}\n </Text>\n )}\n\n {/* Main content */}\n <Text color={textColor}>\n {item.label}\n {selectorItem?.isCurrent && (\n <Text color={SEMANTIC_COLORS.success}> ({t('common.selected')})</Text>\n )}\n {item.description && (\n <Text color={SEMANTIC_COLORS.muted}> {item.description}</Text>\n )}\n </Text>\n </Box>\n )\n}\n\nexport function SimpleSelector({\n title,\n subtitle,\n items,\n onSelect,\n onClose,\n groupByCategory = false,\n statusOverlay,\n isActive = true,\n maxVisible,\n}: SimpleSelectorProps) {\n // Dynamic visible count based on terminal height\n const { rows } = useTerminalSize()\n const dynamicVisible = Math.min(\n 8,\n Math.max(3, rows - PROMPT_HEIGHT - CHROME_HEIGHT),\n )\n const effectiveMaxVisible = maxVisible ?? dynamicVisible\n\n const [focusedIndex, setFocusedIndex] = useState(0)\n\n const listItems = useMemo(() => toListItems(items), [items])\n\n // Map from ListItem back to SelectorItem for custom rendering\n const selectorItemMap = useMemo(() => {\n const map = new Map<string, SelectorItem>()\n items.forEach(item => map.set(item.id, item))\n return map\n }, [items])\n\n const handleSelect = useCallback(\n (listItem: ListItem) => {\n const selectorItem = selectorItemMap.get(listItem.id)\n if (selectorItem) {\n onSelect(selectorItem)\n }\n },\n [selectorItemMap, onSelect],\n )\n\n const renderItem = useCallback(\n (item: ListItem, isFocused: boolean) => (\n <SelectorItemRenderer\n item={item}\n isFocused={isFocused}\n selectorItem={selectorItemMap.get(item.id)}\n />\n ),\n [selectorItemMap],\n )\n\n // Keyboard input handling\n useInput(\n (input, key) => {\n // Status overlay: success/error -> ESC/Enter closes\n if (statusOverlay && statusOverlay.type !== 'loading') {\n if (key.escape || key.return) {\n onClose()\n }\n return\n }\n\n // Status overlay: loading -> ignore all input\n if (statusOverlay) return\n\n // Escape closes\n if (key.escape) {\n onClose()\n return\n }\n\n // Arrow navigation\n if (key.downArrow && listItems.length > 0) {\n setFocusedIndex(prev => (prev < listItems.length - 1 ? prev + 1 : prev))\n return\n }\n\n if (key.upArrow && listItems.length > 0) {\n setFocusedIndex(prev => (prev > 0 ? prev - 1 : prev))\n return\n }\n\n // Enter to select\n if (key.return && listItems.length > 0) {\n handleSelect(listItems[focusedIndex])\n return\n }\n },\n { isActive },\n )\n\n // Build footer hint\n const footerHint = statusOverlay\n ? statusOverlay.type === 'loading'\n ? ''\n : t('ui.simpleSelector.dismissHint')\n : t('ui.simpleSelector.navigationHint')\n\n return (\n <Box flexDirection=\"column\" width=\"100%\">\n {/* Header bar with top border */}\n <Box\n borderTop={true}\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n flexDirection=\"column\"\n >\n {/* Title with brand color */}\n <Box>\n <Text color={BRAND_GRADIENT.START}>{'\\u25C6'}</Text>\n <Text bold color={SEMANTIC_COLORS.secondary}>\n {' '}\n {title}\n </Text>\n {subtitle && (\n <Text color={SEMANTIC_COLORS.dim}>\n {' '}\n {subtitle}\n </Text>\n )}\n </Box>\n </Box>\n\n {/* Content container with bottom border */}\n <Box\n flexDirection=\"column\"\n borderTop={false}\n borderBottom={true}\n borderLeft={false}\n borderRight={false}\n borderColor={BRAND_GRADIENT.START}\n borderStyle=\"single\"\n width=\"100%\"\n paddingX={1}\n paddingY={1}\n >\n {statusOverlay ? (\n <StatusOverlayContent\n type={statusOverlay.type}\n message={statusOverlay.message}\n />\n ) : listItems.length === 0 ? (\n <Box>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('ui.tabbedList.noItems')}\n </Text>\n </Box>\n ) : (\n <ScrollableList\n items={listItems}\n focusedIndex={focusedIndex}\n onFocusChange={setFocusedIndex}\n onSelect={handleSelect}\n visibleCount={effectiveMaxVisible}\n groupByCategory={groupByCategory}\n renderItem={renderItem}\n />\n )}\n\n {/* Footer Hint */}\n {footerHint && (\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.muted}>{footerHint}</Text>\n </Box>\n )}\n </Box>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/components/SimpleSelector/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * SimpleSelector Component Exports\n *\n * A lightweight single-choice selector for quick selection commands.\n */\n\nexport { SimpleSelector } from './SimpleSelector'\nexport type { SimpleSelectorProps, SelectorItem, StatusOverlay } from './types'\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,sBAAsB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
|
|
4
|
+
import { SimpleSpinner } from "./Spinner.js";
|
|
5
|
+
function StatusOverlayContent({
|
|
6
|
+
type,
|
|
7
|
+
message
|
|
8
|
+
}) {
|
|
9
|
+
switch (type) {
|
|
10
|
+
case "loading":
|
|
11
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(SimpleSpinner, null), /* @__PURE__ */ React.createElement(Text, { color: BRAND_GRADIENT.MIDDLE }, " ", message));
|
|
12
|
+
case "success":
|
|
13
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.success }, "\u2713", " ", message));
|
|
14
|
+
case "error":
|
|
15
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, "\u2717", " ", message));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
StatusOverlayContent
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=StatusOverlayContent.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/StatusOverlayContent.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared StatusOverlayContent component\n *\n * Renders loading/success/error overlay content used by\n * TabbedListView, InfoPanel, and SimpleSelector.\n */\n\nimport React from 'react'\nimport { Box, Text } from 'ink'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { SimpleSpinner } from '@components/Spinner'\n\nexport type StatusOverlay = {\n type: 'loading' | 'success' | 'error'\n message: string\n}\n\nexport function StatusOverlayContent({\n type,\n message,\n}: {\n type: 'loading' | 'success' | 'error'\n message: string\n}) {\n switch (type) {\n case 'loading':\n return (\n <Box>\n <SimpleSpinner />\n <Text color={BRAND_GRADIENT.MIDDLE}> {message}</Text>\n </Box>\n )\n case 'success':\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.success}>\n {'\\u2713'} {message}\n </Text>\n </Box>\n )\n case 'error':\n return (\n <Box>\n <Text color={SEMANTIC_COLORS.error}>\n {'\\u2717'} {message}\n </Text>\n </Box>\n )\n }\n}\n"],
|
|
5
|
+
"mappings": "AAOA,OAAO,WAAW;AAClB,SAAS,KAAK,YAAY;AAC1B,SAAS,gBAAgB,uBAAuB;AAChD,SAAS,qBAAqB;AAOvB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AACF,GAGG;AACD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,mBAAc,GACf,oCAAC,QAAK,OAAO,eAAe,UAAQ,KAAE,OAAQ,CAChD;AAAA,IAEJ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,WAC1B,UAAS,KAAE,OACd,CACF;AAAA,IAEJ,KAAK;AACH,aACE,oCAAC,WACC,oCAAC,QAAK,OAAO,gBAAgB,SAC1B,UAAS,KAAE,OACd,CACF;AAAA,EAEN;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|