@within-7/minto 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Tool.js +7 -0
- package/dist/Tool.js.map +2 -2
- package/dist/commands/agents/AgentsCommand.js +1 -1
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/agents/constants.js +2 -2
- package/dist/commands/agents/constants.js.map +2 -2
- package/dist/commands/clear.js +4 -3
- package/dist/commands/clear.js.map +2 -2
- package/dist/commands/compact.js +2 -2
- package/dist/commands/compact.js.map +1 -1
- package/dist/commands/context.js +3 -1
- package/dist/commands/context.js.map +2 -2
- package/dist/commands/login.js +128 -0
- package/dist/commands/login.js.map +7 -0
- package/dist/commands/memory.js +33 -82
- package/dist/commands/memory.js.map +2 -2
- package/dist/commands/quit.js +3 -1
- package/dist/commands/quit.js.map +2 -2
- package/dist/commands/resume.js +39 -239
- package/dist/commands/resume.js.map +2 -2
- package/dist/commands/tasks.js +1 -1
- package/dist/commands/tasks.js.map +2 -2
- package/dist/commands/terminalSetup.js +6 -2
- package/dist/commands/terminalSetup.js.map +2 -2
- package/dist/commands.js +2 -0
- package/dist/commands.js.map +2 -2
- package/dist/components/AgentDetailView.js +126 -0
- package/dist/components/AgentDetailView.js.map +7 -0
- package/dist/components/AgentThinkingBlock.js +1 -1
- package/dist/components/AgentThinkingBlock.js.map +2 -2
- package/dist/components/AgentViewBanner.js +22 -0
- package/dist/components/AgentViewBanner.js.map +7 -0
- package/dist/components/HeaderBar.js +1 -1
- package/dist/components/HeaderBar.js.map +2 -2
- package/dist/components/Help.js +8 -1
- package/dist/components/Help.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +26 -8
- package/dist/components/HotkeyHelpPanel.js.map +2 -2
- package/dist/components/IdleNotificationBar.js +10 -0
- package/dist/components/IdleNotificationBar.js.map +7 -0
- package/dist/components/ModelSelector/ModelSelector.js +55 -20
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/PromptInput.js +186 -115
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/RewindPanel.js +272 -0
- package/dist/components/RewindPanel.js.map +7 -0
- package/dist/components/Spinner.js +10 -21
- package/dist/components/Spinner.js.map +2 -2
- package/dist/components/StreamingTextPreview.js +29 -0
- package/dist/components/StreamingTextPreview.js.map +7 -0
- package/dist/components/SubagentBlock.js +3 -2
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/SubagentProgress.js +4 -4
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TabbedListView/SearchInput.js +1 -1
- package/dist/components/TabbedListView/SearchInput.js.map +2 -2
- package/dist/components/TabbedListView/TabbedListView.js +87 -41
- package/dist/components/TabbedListView/TabbedListView.js.map +2 -2
- package/dist/components/TaskCard.js +4 -4
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TeamMemberPanel.js +107 -0
- package/dist/components/TeamMemberPanel.js.map +7 -0
- package/dist/components/ThinkingSelector.js +84 -0
- package/dist/components/ThinkingSelector.js.map +7 -0
- package/dist/components/TitledDivider.js +26 -0
- package/dist/components/TitledDivider.js.map +7 -0
- package/dist/components/TodoPanel.js +31 -30
- package/dist/components/TodoPanel.js.map +2 -2
- package/dist/components/TokenWarning.js +28 -7
- package/dist/components/TokenWarning.js.map +2 -2
- package/dist/components/messages/AssistantTextMessage.js +5 -2
- package/dist/components/messages/AssistantTextMessage.js.map +2 -2
- package/dist/components/messages/AssistantToolUseMessage.js +9 -1
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/DefaultToolResultFallback.js +11 -0
- package/dist/components/messages/DefaultToolResultFallback.js.map +7 -0
- package/dist/components/messages/ParallelTasksGroupView.js +14 -6
- package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
- package/dist/components/messages/TaskInModuleView.js +27 -27
- package/dist/components/messages/TaskInModuleView.js.map +2 -2
- package/dist/components/messages/UserGuidanceMessage.js +26 -0
- package/dist/components/messages/UserGuidanceMessage.js.map +7 -0
- package/dist/components/messages/UserPromptMessage.js +2 -1
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/components/messages/UserTeamNotificationMessage.js +91 -0
- package/dist/components/messages/UserTeamNotificationMessage.js.map +7 -0
- package/dist/components/messages/UserTextMessage.js +8 -0
- package/dist/components/messages/UserTextMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js +4 -2
- package/dist/components/messages/UserToolResultMessage/UserToolRejectMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js +18 -1
- package/dist/components/messages/UserToolResultMessage/UserToolResultMessage.js.map +2 -2
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js +12 -1
- package/dist/components/messages/UserToolResultMessage/UserToolSuccessMessage.js.map +2 -2
- package/dist/components/permissions/PermissionRequest.js +4 -0
- package/dist/components/permissions/PermissionRequest.js.map +2 -2
- package/dist/components/permissions/PlanApprovalRequest.js +164 -0
- package/dist/components/permissions/PlanApprovalRequest.js.map +7 -0
- package/dist/constants/agentTeams.js +17 -0
- package/dist/constants/agentTeams.js.map +7 -0
- package/dist/constants/macros.js +2 -1
- package/dist/constants/macros.js.map +2 -2
- package/dist/constants/prompts/agentPrompt.js +1 -0
- package/dist/constants/prompts/agentPrompt.js.map +2 -2
- package/dist/constants/prompts/autoMemory.js +39 -0
- package/dist/constants/prompts/autoMemory.js.map +7 -0
- package/dist/constants/prompts/codeConventions.js +1 -13
- package/dist/constants/prompts/codeConventions.js.map +2 -2
- package/dist/constants/prompts/doingTasks.js +21 -2
- package/dist/constants/prompts/doingTasks.js.map +2 -2
- package/dist/constants/prompts/envInfo.js +6 -7
- package/dist/constants/prompts/envInfo.js.map +2 -2
- package/dist/constants/prompts/index.js +27 -5
- package/dist/constants/prompts/index.js.map +2 -2
- package/dist/constants/prompts/taskManagement.js +2 -43
- package/dist/constants/prompts/taskManagement.js.map +2 -2
- package/dist/constants/prompts/teamOverlays.js +50 -0
- package/dist/constants/prompts/teamOverlays.js.map +7 -0
- package/dist/constants/prompts/toneAndStyle.js +4 -29
- package/dist/constants/prompts/toneAndStyle.js.map +2 -2
- package/dist/constants/prompts/toolUsagePolicy.js +7 -22
- package/dist/constants/prompts/toolUsagePolicy.js.map +2 -2
- package/dist/constants/toolInputExamples.js +2 -2
- package/dist/constants/toolInputExamples.js.map +2 -2
- package/dist/context.js +39 -6
- package/dist/context.js.map +2 -2
- package/dist/core/backupManager.js +1 -1
- package/dist/core/backupManager.js.map +2 -2
- package/dist/core/permissions/rules/planModeRule.js +1 -1
- package/dist/core/permissions/rules/planModeRule.js.map +1 -1
- package/dist/core/permissions/rules/safeModeRule.js +1 -1
- package/dist/core/permissions/rules/safeModeRule.js.map +1 -1
- package/dist/engine/AgentEngine.js +902 -0
- package/dist/engine/AgentEngine.js.map +7 -0
- package/dist/engine/EngineRegistry.js +89 -0
- package/dist/engine/EngineRegistry.js.map +7 -0
- package/dist/engine/foregroundAdapter.js +191 -0
- package/dist/engine/foregroundAdapter.js.map +7 -0
- package/dist/engine/index.js +15 -0
- package/dist/engine/index.js.map +7 -0
- package/dist/engine/types.js +1 -0
- package/dist/engine/types.js.map +7 -0
- package/dist/entrypoints/cli.js +410 -79
- package/dist/entrypoints/cli.js.map +3 -3
- package/dist/hooks/useAgentEngine.js +129 -0
- package/dist/hooks/useAgentEngine.js.map +7 -0
- package/dist/hooks/useAgentTokenStats.js +0 -16
- package/dist/hooks/useAgentTokenStats.js.map +2 -2
- package/dist/hooks/useCanUseTool.js +47 -2
- package/dist/hooks/useCanUseTool.js.map +2 -2
- package/dist/hooks/useDeferredLoading.js +4 -1
- package/dist/hooks/useDeferredLoading.js.map +2 -2
- package/dist/hooks/useIdleNotifications.js +66 -0
- package/dist/hooks/useIdleNotifications.js.map +7 -0
- package/dist/hooks/useSessionTracking.js +9 -7
- package/dist/hooks/useSessionTracking.js.map +2 -2
- package/dist/hooks/useTeamMembers.js +51 -0
- package/dist/hooks/useTeamMembers.js.map +7 -0
- package/dist/i18n/locales/en.js +77 -12
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +77 -12
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/messages.js.map +2 -2
- package/dist/permissions.js +113 -7
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +135 -37
- package/dist/query.js.map +2 -2
- package/dist/screens/REPL.js +504 -361
- package/dist/screens/REPL.js.map +3 -3
- package/dist/screens/ResumeConversation.js +199 -14
- package/dist/screens/ResumeConversation.js.map +2 -2
- package/dist/services/adapters/base.js.map +1 -1
- package/dist/services/agentTeams/backends/headless.js +108 -0
- package/dist/services/agentTeams/backends/headless.js.map +7 -0
- package/dist/services/agentTeams/backends/inProcess.js +102 -0
- package/dist/services/agentTeams/backends/inProcess.js.map +7 -0
- package/dist/services/agentTeams/backends/resolver.js +18 -0
- package/dist/services/agentTeams/backends/resolver.js.map +7 -0
- package/dist/services/agentTeams/backends/tmux.js +168 -0
- package/dist/services/agentTeams/backends/tmux.js.map +7 -0
- package/dist/services/agentTeams/backends/types.js +1 -0
- package/dist/services/agentTeams/backends/types.js.map +7 -0
- package/dist/services/agentTeams/heartbeat.js +88 -0
- package/dist/services/agentTeams/heartbeat.js.map +7 -0
- package/dist/services/agentTeams/index.js +42 -2
- package/dist/services/agentTeams/index.js.map +2 -2
- package/dist/services/agentTeams/injectionChannel.js +105 -0
- package/dist/services/agentTeams/injectionChannel.js.map +7 -0
- package/dist/services/agentTeams/mailbox.js +410 -30
- package/dist/services/agentTeams/mailbox.js.map +2 -2
- package/dist/services/agentTeams/messageFormatter.js +80 -0
- package/dist/services/agentTeams/messageFormatter.js.map +7 -0
- package/dist/services/agentTeams/permissionDelegation.js +71 -0
- package/dist/services/agentTeams/permissionDelegation.js.map +7 -0
- package/dist/services/agentTeams/teamEvents.js +45 -0
- package/dist/services/agentTeams/teamEvents.js.map +7 -0
- package/dist/services/agentTeams/teamManager.js +251 -34
- package/dist/services/agentTeams/teamManager.js.map +2 -2
- package/dist/services/agentTeams/teamTaskStore.js +290 -61
- package/dist/services/agentTeams/teamTaskStore.js.map +2 -2
- package/dist/services/agentTeams/teammateSpawner.js +99 -18
- package/dist/services/agentTeams/teammateSpawner.js.map +2 -2
- package/dist/services/hookExecutor.js +51 -8
- package/dist/services/hookExecutor.js.map +2 -2
- package/dist/services/llm/anthropicProvider.js +56 -59
- package/dist/services/llm/anthropicProvider.js.map +2 -2
- package/dist/services/llm/dispatch.js +24 -5
- package/dist/services/llm/dispatch.js.map +2 -2
- package/dist/services/llm/openaiProvider.js +115 -136
- package/dist/services/llm/openaiProvider.js.map +3 -3
- package/dist/services/llm/types.js +89 -15
- package/dist/services/llm/types.js.map +2 -2
- package/dist/services/mcpClient.js +80 -4
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/mintoAuth.js +299 -0
- package/dist/services/mintoAuth.js.map +7 -0
- package/dist/services/oauth.js +3 -3
- package/dist/services/oauth.js.map +2 -2
- package/dist/services/openai.js +91 -20
- package/dist/services/openai.js.map +2 -2
- package/dist/services/plugins/pluginRuntime.js +11 -5
- package/dist/services/plugins/pluginRuntime.js.map +2 -2
- package/dist/services/plugins/pluginValidation.js +4 -2
- package/dist/services/plugins/pluginValidation.js.map +2 -2
- package/dist/services/sandbox/sandboxController.js +11 -3
- package/dist/services/sandbox/sandboxController.js.map +2 -2
- package/dist/services/sessionMemoryInjector.js +77 -0
- package/dist/services/sessionMemoryInjector.js.map +7 -0
- package/dist/services/systemReminder.js +130 -8
- package/dist/services/systemReminder.js.map +2 -2
- package/dist/services/taskStore.js +199 -8
- package/dist/services/taskStore.js.map +3 -3
- package/dist/services/topicDetector.js +169 -0
- package/dist/services/topicDetector.js.map +7 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +0 -13
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +51 -28
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +95 -118
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/BashTool/utils.js +39 -1
- package/dist/tools/BashTool/utils.js.map +2 -2
- package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js +121 -0
- package/dist/tools/EnterWorktreeTool/EnterWorktreeTool.js.map +7 -0
- package/dist/tools/EnterWorktreeTool/prompt.js +22 -0
- package/dist/tools/EnterWorktreeTool/prompt.js.map +7 -0
- package/dist/tools/FileEditTool/FileEditTool.js +9 -4
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileEditTool/prompt.js +3 -7
- package/dist/tools/FileEditTool/prompt.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js +125 -3
- package/dist/tools/FileReadTool/FileReadTool.js.map +2 -2
- package/dist/tools/FileReadTool/prompt.js +1 -2
- package/dist/tools/FileReadTool/prompt.js.map +2 -2
- package/dist/tools/FileWriteTool/prompt.js +3 -5
- package/dist/tools/FileWriteTool/prompt.js.map +2 -2
- package/dist/tools/GlobTool/GlobTool.js +3 -2
- package/dist/tools/GlobTool/GlobTool.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +16 -5
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/ListMcpResourcesTool/ListMcpResourcesTool.js.map +2 -2
- package/dist/tools/MCPSearchTool/MCPSearchTool.js +172 -0
- package/dist/tools/MCPSearchTool/MCPSearchTool.js.map +7 -0
- package/dist/tools/MCPSearchTool/prompt.js +77 -0
- package/dist/tools/MCPSearchTool/prompt.js.map +7 -0
- package/dist/tools/MultiEditTool/prompt.js +4 -7
- package/dist/tools/MultiEditTool/prompt.js.map +2 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +12 -8
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +54 -1
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/prompt.js +23 -74
- package/dist/tools/PlanModeTool/prompt.js.map +2 -2
- package/dist/tools/SendMessageTool/SendMessageTool.js +341 -0
- package/dist/tools/SendMessageTool/SendMessageTool.js.map +7 -0
- package/dist/tools/SendMessageTool/prompt.js +44 -0
- package/dist/tools/SendMessageTool/prompt.js.map +7 -0
- package/dist/tools/TaskCreateTool/prompt.js +15 -4
- package/dist/tools/TaskCreateTool/prompt.js.map +2 -2
- package/dist/tools/TaskListTool/prompt.js +18 -3
- package/dist/tools/TaskListTool/prompt.js.map +2 -2
- package/dist/tools/TaskOutputTool/prompt.js +4 -3
- package/dist/tools/TaskOutputTool/prompt.js.map +2 -2
- package/dist/tools/TaskTool/TaskTool.js +762 -98
- package/dist/tools/TaskTool/TaskTool.js.map +3 -3
- package/dist/tools/TaskTool/constants.js +8 -2
- package/dist/tools/TaskTool/constants.js.map +2 -2
- package/dist/tools/TaskTool/prompt.js +74 -70
- package/dist/tools/TaskTool/prompt.js.map +2 -2
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +15 -1
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +2 -2
- package/dist/tools/TeamCreateTool/TeamCreateTool.js +129 -0
- package/dist/tools/TeamCreateTool/TeamCreateTool.js.map +7 -0
- package/dist/tools/TeamCreateTool/prompt.js +58 -0
- package/dist/tools/TeamCreateTool/prompt.js.map +7 -0
- package/dist/tools/TeamDeleteTool/TeamDeleteTool.js +151 -0
- package/dist/tools/TeamDeleteTool/TeamDeleteTool.js.map +7 -0
- package/dist/tools/TeamDeleteTool/prompt.js +16 -0
- package/dist/tools/TeamDeleteTool/prompt.js.map +7 -0
- package/dist/tools/URLFetcherTool/URLFetcherTool.js +106 -15
- package/dist/tools/URLFetcherTool/URLFetcherTool.js.map +2 -2
- package/dist/tools/URLFetcherTool/prompt.js +3 -2
- package/dist/tools/URLFetcherTool/prompt.js.map +2 -2
- package/dist/tools/WebSearchTool/WebSearchTool.js +2 -1
- package/dist/tools/WebSearchTool/WebSearchTool.js.map +2 -2
- package/dist/tools/WebSearchTool/prompt.js +5 -4
- package/dist/tools/WebSearchTool/prompt.js.map +2 -2
- package/dist/tools.js +100 -20
- package/dist/tools.js.map +2 -2
- package/dist/types/PermissionMode.js +35 -6
- package/dist/types/PermissionMode.js.map +2 -2
- package/dist/types/hooks.js +2 -0
- package/dist/types/hooks.js.map +2 -2
- package/dist/types/plugin.js +2 -0
- package/dist/types/plugin.js.map +3 -3
- package/dist/utils/CircuitBreaker.js +15 -9
- package/dist/utils/CircuitBreaker.js.map +2 -2
- package/dist/utils/agentLoader.js +249 -112
- package/dist/utils/agentLoader.js.map +2 -2
- package/dist/utils/animationManager.js +40 -3
- package/dist/utils/animationManager.js.map +2 -2
- package/dist/utils/ask.js +7 -6
- package/dist/utils/ask.js.map +2 -2
- package/dist/utils/atomicWrite.js +23 -0
- package/dist/utils/atomicWrite.js.map +7 -0
- package/dist/utils/autoCompactCore.js +73 -56
- package/dist/utils/autoCompactCore.js.map +2 -2
- package/dist/utils/autoMemoryPaths.js +89 -0
- package/dist/utils/autoMemoryPaths.js.map +7 -0
- package/dist/utils/config.js +63 -38
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/configSchema.js +13 -8
- package/dist/utils/configSchema.js.map +2 -2
- package/dist/utils/credentials/index.js +14 -0
- package/dist/utils/credentials/index.js.map +2 -2
- package/dist/utils/dualPath.js +24 -0
- package/dist/utils/dualPath.js.map +7 -0
- package/dist/utils/exit.js +66 -7
- package/dist/utils/exit.js.map +2 -2
- package/dist/utils/externalEditor.js +155 -0
- package/dist/utils/externalEditor.js.map +7 -0
- package/dist/utils/fileLock.js +67 -0
- package/dist/utils/fileLock.js.map +7 -0
- package/dist/utils/format.js +24 -14
- package/dist/utils/format.js.map +2 -2
- package/dist/utils/globalErrorHandler.js +5 -96
- package/dist/utils/globalErrorHandler.js.map +3 -3
- package/dist/utils/groupHandlers/parallelTasksHandler.js +5 -3
- package/dist/utils/groupHandlers/parallelTasksHandler.js.map +2 -2
- package/dist/utils/groupHandlers/taskHandler.js +2 -2
- package/dist/utils/groupHandlers/taskHandler.js.map +2 -2
- package/dist/utils/hookManager.js +64 -6
- package/dist/utils/hookManager.js.map +2 -2
- package/dist/utils/log.js +6 -2
- package/dist/utils/log.js.map +2 -2
- package/dist/utils/markdown.js +237 -19
- package/dist/utils/markdown.js.map +2 -2
- package/dist/utils/messageContextManager.js +18 -5
- package/dist/utils/messageContextManager.js.map +2 -2
- package/dist/utils/messageGroupManager.js +1 -1
- package/dist/utils/messageGroupManager.js.map +2 -2
- package/dist/utils/messages.js +104 -46
- package/dist/utils/messages.js.map +2 -2
- package/dist/utils/model.js +2 -2
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/pasteCache.js +8 -4
- package/dist/utils/pasteCache.js.map +2 -2
- package/dist/utils/pluginLoader.js +18 -0
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/secureKeyStorage.js +36 -7
- package/dist/utils/secureKeyStorage.js.map +2 -2
- package/dist/utils/simpleMode.js +7 -0
- package/dist/utils/simpleMode.js.map +7 -0
- package/dist/utils/streamingState.js +11 -1
- package/dist/utils/streamingState.js.map +2 -2
- package/dist/utils/taskDisplayUtils.js +2 -1
- package/dist/utils/taskDisplayUtils.js.map +2 -2
- package/dist/utils/teamConfig.js +2 -2
- package/dist/utils/teamConfig.js.map +2 -2
- package/dist/utils/thinking.js +6 -2
- package/dist/utils/thinking.js.map +3 -3
- package/dist/utils/tokenProgress.js +55 -0
- package/dist/utils/tokenProgress.js.map +7 -0
- package/dist/utils/toolRiskClassification.js +26 -17
- package/dist/utils/toolRiskClassification.js.map +2 -2
- package/dist/utils/tooling/toolError.js +12 -0
- package/dist/utils/tooling/toolError.js.map +7 -0
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +10 -8
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { Box, Text, useInput } from "ink";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { useMemo, useState } from "react";
|
|
4
|
+
import figures from "figures";
|
|
5
|
+
import { basename } from "path";
|
|
6
|
+
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
|
|
7
|
+
import { t } from "../i18n/index.js";
|
|
8
|
+
const FILE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
9
|
+
function extractFileChangesForTurn(messages, fromIndex, toIndex) {
|
|
10
|
+
const files = /* @__PURE__ */ new Set();
|
|
11
|
+
for (let i = fromIndex; i < toIndex; i++) {
|
|
12
|
+
const msg = messages[i];
|
|
13
|
+
if (!msg || msg.type !== "assistant") continue;
|
|
14
|
+
const content = msg.message.content;
|
|
15
|
+
if (!Array.isArray(content)) continue;
|
|
16
|
+
for (const block of content) {
|
|
17
|
+
if (block.type !== "tool_use") continue;
|
|
18
|
+
if (!FILE_TOOLS.has(block.name)) continue;
|
|
19
|
+
const input = block.input;
|
|
20
|
+
const filePath = input?.file_path ?? input?.notebook_path;
|
|
21
|
+
if (typeof filePath === "string") {
|
|
22
|
+
files.add(basename(filePath));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return Array.from(files);
|
|
27
|
+
}
|
|
28
|
+
function stripXmlForDisplay(raw) {
|
|
29
|
+
if (raw.includes("<command-name>") || raw.includes("<command-message>")) {
|
|
30
|
+
const cmdMatch = raw.match(/<command-message>([\s\S]*?)<\/command-message>/);
|
|
31
|
+
const argsMatch = raw.match(/<command-args>([\s\S]*?)<\/command-args>/);
|
|
32
|
+
const cmd = cmdMatch?.[1]?.trim() ?? "";
|
|
33
|
+
const args = argsMatch?.[1]?.trim() ?? "";
|
|
34
|
+
return cmd ? `/${cmd}${args ? " " + args : ""}` : "";
|
|
35
|
+
}
|
|
36
|
+
return raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>\s*/g, "").replace(/<local-command-caveat>[\s\S]*?<\/local-command-caveat>\s*/g, "").replace(/<local-command-stdout>[\s\S]*?<\/local-command-stdout>\s*/g, "").replace(/<task-notification>[\s\S]*?<\/task-notification>\s*/g, "").replace(/<user-guidance>\n?([\s\S]*?)\n?<\/user-guidance>/g, "$1").replace(/<team-message\s+[^>]*>([\s\S]*?)<\/team-message>/g, "").replace(/<bash-input>[\s\S]*?<\/bash-input>\s*/g, "").replace(/<koding-input>[\s\S]*?<\/koding-input>\s*/g, "").replace(
|
|
37
|
+
/<available-deferred-tools>[\s\S]*?<\/available-deferred-tools>\s*/g,
|
|
38
|
+
""
|
|
39
|
+
).replace(/<command-name>[\s\S]*?<\/command-name>\s*/g, "").replace(/<command-message>[\s\S]*?<\/command-message>\s*/g, "").replace(/<command-args>[\s\S]*?<\/command-args>\s*/g, "").trim();
|
|
40
|
+
}
|
|
41
|
+
function getUserText(msg) {
|
|
42
|
+
const content = msg.message.content;
|
|
43
|
+
if (typeof content === "string") return stripXmlForDisplay(content);
|
|
44
|
+
if (Array.isArray(content)) {
|
|
45
|
+
for (const block of content) {
|
|
46
|
+
if (block.type === "text") return stripXmlForDisplay(block.text);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
51
|
+
function getRewindPoints(messages) {
|
|
52
|
+
const points = [];
|
|
53
|
+
const userIndices = [];
|
|
54
|
+
for (let i = 0; i < messages.length; i++) {
|
|
55
|
+
const msg = messages[i];
|
|
56
|
+
if (msg?.type === "user" && !(Array.isArray(msg.message.content) && msg.message.content[0]?.type === "tool_result")) {
|
|
57
|
+
userIndices.push(i);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (let i = 0; i < userIndices.length; i++) {
|
|
61
|
+
const idx = userIndices[i];
|
|
62
|
+
const msg = messages[idx];
|
|
63
|
+
const nextIdx = i + 1 < userIndices.length ? userIndices[i + 1] : messages.length;
|
|
64
|
+
points.push({
|
|
65
|
+
userMessage: msg,
|
|
66
|
+
messageIndex: idx,
|
|
67
|
+
userText: getUserText(msg),
|
|
68
|
+
changedFiles: extractFileChangesForTurn(messages, idx, nextIdx)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return points;
|
|
72
|
+
}
|
|
73
|
+
const MAX_VISIBLE = 8;
|
|
74
|
+
const MAX_TEXT_LENGTH = 120;
|
|
75
|
+
function RewindPanel({
|
|
76
|
+
messages,
|
|
77
|
+
onAction,
|
|
78
|
+
onEscape
|
|
79
|
+
}) {
|
|
80
|
+
const rewindPoints = useMemo(() => getRewindPoints(messages), [messages]);
|
|
81
|
+
const [phase, setPhase] = useState(
|
|
82
|
+
"message_select"
|
|
83
|
+
);
|
|
84
|
+
const totalItems = rewindPoints.length + 1;
|
|
85
|
+
const [selectedIndex, setSelectedIndex] = useState(rewindPoints.length);
|
|
86
|
+
const [actionIndex, setActionIndex] = useState(0);
|
|
87
|
+
const [selectedPoint, setSelectedPoint] = useState(null);
|
|
88
|
+
useInput((input, key) => {
|
|
89
|
+
if (phase === "message_select") {
|
|
90
|
+
if (key.escape) {
|
|
91
|
+
onEscape();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (key.upArrow) {
|
|
95
|
+
setSelectedIndex((prev) => Math.max(0, prev - 1));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (key.downArrow) {
|
|
99
|
+
setSelectedIndex((prev) => Math.min(totalItems - 1, prev + 1));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (key.return) {
|
|
103
|
+
if (selectedIndex >= rewindPoints.length) {
|
|
104
|
+
onEscape();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const point = rewindPoints[selectedIndex];
|
|
108
|
+
if (point) {
|
|
109
|
+
setSelectedPoint(point);
|
|
110
|
+
setPhase("action_select");
|
|
111
|
+
setActionIndex(0);
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
} else if (phase === "action_select") {
|
|
116
|
+
if (key.escape) {
|
|
117
|
+
setPhase("message_select");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (key.upArrow) {
|
|
121
|
+
setActionIndex((prev) => Math.max(0, prev - 1));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (key.downArrow) {
|
|
125
|
+
setActionIndex((prev) => Math.min(4, prev + 1));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (key.return && selectedPoint) {
|
|
129
|
+
const actions = [
|
|
130
|
+
"restore_code_and_conversation",
|
|
131
|
+
"restore_conversation",
|
|
132
|
+
"restore_code",
|
|
133
|
+
"summarize_from_here",
|
|
134
|
+
"never_mind"
|
|
135
|
+
];
|
|
136
|
+
onAction(actions[actionIndex], selectedPoint);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const num = Number(input);
|
|
140
|
+
if (num >= 1 && num <= 5 && selectedPoint) {
|
|
141
|
+
const actions = [
|
|
142
|
+
"restore_code_and_conversation",
|
|
143
|
+
"restore_conversation",
|
|
144
|
+
"restore_code",
|
|
145
|
+
"summarize_from_here",
|
|
146
|
+
"never_mind"
|
|
147
|
+
];
|
|
148
|
+
onAction(actions[num - 1], selectedPoint);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
if (phase === "message_select") {
|
|
154
|
+
const firstVisible = Math.max(
|
|
155
|
+
0,
|
|
156
|
+
Math.min(
|
|
157
|
+
selectedIndex - Math.floor(MAX_VISIBLE / 2),
|
|
158
|
+
totalItems - MAX_VISIBLE
|
|
159
|
+
)
|
|
160
|
+
);
|
|
161
|
+
const lastVisible = Math.min(totalItems, firstVisible + MAX_VISIBLE);
|
|
162
|
+
return /* @__PURE__ */ React.createElement(
|
|
163
|
+
Box,
|
|
164
|
+
{
|
|
165
|
+
flexDirection: "column",
|
|
166
|
+
borderStyle: "round",
|
|
167
|
+
borderColor: BRAND_GRADIENT.START,
|
|
168
|
+
paddingX: 1,
|
|
169
|
+
paddingY: 1
|
|
170
|
+
},
|
|
171
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, t("rewind.title")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.selectMessage"))),
|
|
172
|
+
Array.from({ length: lastVisible - firstVisible }, (_, i) => {
|
|
173
|
+
const itemIndex = firstVisible + i;
|
|
174
|
+
const isSelected = itemIndex === selectedIndex;
|
|
175
|
+
const isCurrent = itemIndex >= rewindPoints.length;
|
|
176
|
+
if (isCurrent) {
|
|
177
|
+
return /* @__PURE__ */ React.createElement(Box, { key: "current", marginBottom: 0 }, /* @__PURE__ */ React.createElement(
|
|
178
|
+
Text,
|
|
179
|
+
{
|
|
180
|
+
color: isSelected ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim,
|
|
181
|
+
bold: isSelected
|
|
182
|
+
},
|
|
183
|
+
isSelected ? `${figures.pointer} ` : " "
|
|
184
|
+
), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim, italic: true }, t("dialog.current")));
|
|
185
|
+
}
|
|
186
|
+
const point = rewindPoints[itemIndex];
|
|
187
|
+
if (!point) return null;
|
|
188
|
+
const displayText = point.userText.replace(/\n/g, " ").slice(0, MAX_TEXT_LENGTH);
|
|
189
|
+
const truncated = point.userText.length > MAX_TEXT_LENGTH ? displayText + "\u2026" : displayText;
|
|
190
|
+
return /* @__PURE__ */ React.createElement(
|
|
191
|
+
Box,
|
|
192
|
+
{
|
|
193
|
+
key: point.userMessage.uuid,
|
|
194
|
+
flexDirection: "column",
|
|
195
|
+
marginBottom: 0
|
|
196
|
+
},
|
|
197
|
+
/* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
|
|
198
|
+
Text,
|
|
199
|
+
{
|
|
200
|
+
color: isSelected ? BRAND_GRADIENT.START : void 0,
|
|
201
|
+
bold: isSelected
|
|
202
|
+
},
|
|
203
|
+
isSelected ? `${figures.pointer} ` : " "
|
|
204
|
+
), /* @__PURE__ */ React.createElement(
|
|
205
|
+
Text,
|
|
206
|
+
{
|
|
207
|
+
color: isSelected ? BRAND_GRADIENT.START : void 0,
|
|
208
|
+
wrap: "truncate"
|
|
209
|
+
},
|
|
210
|
+
truncated || t("dialog.emptyMessage")
|
|
211
|
+
)),
|
|
212
|
+
/* @__PURE__ */ React.createElement(Box, { marginLeft: 3 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, point.changedFiles.length === 0 ? t("rewind.noCodeChanges") : point.changedFiles.join(", ")))
|
|
213
|
+
);
|
|
214
|
+
}),
|
|
215
|
+
firstVisible > 0 && /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, figures.arrowUp, " ", t("rewind.moreAbove"))),
|
|
216
|
+
lastVisible < totalItems && /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, figures.arrowDown, " ", t("rewind.moreBelow"))),
|
|
217
|
+
/* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("rewind.enterToContinue"), " \xB7 ", t("rewind.escToExit")))
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
if (!selectedPoint) return null;
|
|
221
|
+
const confirmText = selectedPoint.userText.replace(/\n/g, " ").slice(0, 100);
|
|
222
|
+
const confirmDisplay = selectedPoint.userText.length > 100 ? confirmText + "\u2026" : confirmText;
|
|
223
|
+
const actionLabels = [
|
|
224
|
+
t("rewind.action.restoreCodeAndConversation"),
|
|
225
|
+
t("rewind.action.restoreConversation"),
|
|
226
|
+
t("rewind.action.restoreCode"),
|
|
227
|
+
t("rewind.action.summarizeFromHere"),
|
|
228
|
+
t("rewind.action.neverMind")
|
|
229
|
+
];
|
|
230
|
+
return /* @__PURE__ */ React.createElement(
|
|
231
|
+
Box,
|
|
232
|
+
{
|
|
233
|
+
flexDirection: "column",
|
|
234
|
+
borderStyle: "round",
|
|
235
|
+
borderColor: BRAND_GRADIENT.START,
|
|
236
|
+
paddingX: 1,
|
|
237
|
+
paddingY: 1
|
|
238
|
+
},
|
|
239
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: BRAND_GRADIENT.START }, t("rewind.title")), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.confirmRestore"))),
|
|
240
|
+
/* @__PURE__ */ React.createElement(Box, { marginBottom: 1, marginLeft: 1 }, /* @__PURE__ */ React.createElement(
|
|
241
|
+
Box,
|
|
242
|
+
{
|
|
243
|
+
borderStyle: "single",
|
|
244
|
+
borderColor: SEMANTIC_COLORS.dim,
|
|
245
|
+
borderLeft: true,
|
|
246
|
+
borderRight: false,
|
|
247
|
+
borderTop: false,
|
|
248
|
+
borderBottom: false,
|
|
249
|
+
paddingLeft: 1
|
|
250
|
+
},
|
|
251
|
+
/* @__PURE__ */ React.createElement(Text, null, confirmDisplay)
|
|
252
|
+
)),
|
|
253
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1, marginLeft: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.conversationWillBeForked")), selectedPoint.changedFiles.length > 0 ? /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.secondary }, t("rewind.codeWillBeRestored"), " ", selectedPoint.changedFiles.join(", "), ".") : /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, t("rewind.noCodeChanges"))),
|
|
254
|
+
actionLabels.map((label, i) => /* @__PURE__ */ React.createElement(Box, { key: i }, /* @__PURE__ */ React.createElement(
|
|
255
|
+
Text,
|
|
256
|
+
{
|
|
257
|
+
color: i === actionIndex ? BRAND_GRADIENT.START : void 0,
|
|
258
|
+
bold: i === actionIndex
|
|
259
|
+
},
|
|
260
|
+
i === actionIndex ? `${figures.pointer} ` : " ",
|
|
261
|
+
i + 1,
|
|
262
|
+
". ",
|
|
263
|
+
label
|
|
264
|
+
))),
|
|
265
|
+
/* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.error }, t("rewind.bashWarning")))
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
export {
|
|
269
|
+
RewindPanel,
|
|
270
|
+
getRewindPoints
|
|
271
|
+
};
|
|
272
|
+
//# sourceMappingURL=RewindPanel.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/RewindPanel.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * RewindPanel \u2014 CC-compatible Rewind/Checkpoint UI\n *\n * Two-phase overlay:\n * 1. Message Select: scrollable list of user prompts with file change summaries\n * 2. Action Select: 5 options (restore code+convo, convo only, code only, summarize, cancel)\n *\n * Activation: Double-Esc or /rewind command\n * Boundaries: Only shows messages since last /clear or /compact (naturally enforced\n * because those operations truncate the messages array).\n */\n\nimport { Box, Text, useInput } from 'ink'\nimport * as React from 'react'\nimport { useMemo, useState } from 'react'\nimport figures from 'figures'\nimport { basename } from 'path'\nimport { BRAND_GRADIENT, SEMANTIC_COLORS } from '@constants/colors'\nimport { t } from '@i18n'\nimport type { Message, UserMessage } from '@query'\n\n// \u2500\u2500 Types \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\nexport interface RewindPoint {\n /** The original user message */\n userMessage: UserMessage\n /** Index in the messages array */\n messageIndex: number\n /** Plain text of the user prompt (for display) */\n userText: string\n /** File paths modified in this turn (basename only) */\n changedFiles: string[]\n}\n\nexport type RewindAction =\n | 'restore_code_and_conversation'\n | 'restore_conversation'\n | 'restore_code'\n | 'summarize_from_here'\n | 'never_mind'\n\ninterface Props {\n messages: Message[]\n onAction: (action: RewindAction, point: RewindPoint) => void\n onEscape: () => void\n}\n\n// \u2500\u2500 Utilities \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\n/** Tool names that modify files on disk */\nconst FILE_TOOLS = new Set(['Write', 'Edit', 'MultiEdit', 'NotebookEdit'])\n\n/**\n * Extract file paths changed between two message indices.\n * Scans assistant messages for file-modifying tool_use blocks.\n */\nfunction extractFileChangesForTurn(\n messages: Message[],\n fromIndex: number,\n toIndex: number,\n): string[] {\n const files = new Set<string>()\n\n for (let i = fromIndex; i < toIndex; i++) {\n const msg = messages[i]\n if (!msg || msg.type !== 'assistant') continue\n\n const content = msg.message.content\n if (!Array.isArray(content)) continue\n\n for (const block of content) {\n if (block.type !== 'tool_use') continue\n if (!FILE_TOOLS.has(block.name)) continue\n\n const input = block.input as Record<string, unknown>\n const filePath = (input?.file_path ?? input?.notebook_path) as\n | string\n | undefined\n if (typeof filePath === 'string') {\n files.add(basename(filePath))\n }\n }\n }\n\n return Array.from(files)\n}\n\n/** Strip XML tags to extract display-friendly text, mirroring REPL rendering */\nfunction stripXmlForDisplay(raw: string): string {\n // Command messages \u2192 show as \"/<command> <args>\"\n if (raw.includes('<command-name>') || raw.includes('<command-message>')) {\n const cmdMatch = raw.match(/<command-message>([\\s\\S]*?)<\\/command-message>/)\n const argsMatch = raw.match(/<command-args>([\\s\\S]*?)<\\/command-args>/)\n const cmd = cmdMatch?.[1]?.trim() ?? ''\n const args = argsMatch?.[1]?.trim() ?? ''\n return cmd ? `/${cmd}${args ? ' ' + args : ''}` : ''\n }\n\n // Strip all known system/protocol XML tags, keep remaining plain text\n return raw\n .replace(/<system-reminder>[\\s\\S]*?<\\/system-reminder>\\s*/g, '')\n .replace(/<local-command-caveat>[\\s\\S]*?<\\/local-command-caveat>\\s*/g, '')\n .replace(/<local-command-stdout>[\\s\\S]*?<\\/local-command-stdout>\\s*/g, '')\n .replace(/<task-notification>[\\s\\S]*?<\\/task-notification>\\s*/g, '')\n .replace(/<user-guidance>\\n?([\\s\\S]*?)\\n?<\\/user-guidance>/g, '$1')\n .replace(/<team-message\\s+[^>]*>([\\s\\S]*?)<\\/team-message>/g, '')\n .replace(/<bash-input>[\\s\\S]*?<\\/bash-input>\\s*/g, '')\n .replace(/<koding-input>[\\s\\S]*?<\\/koding-input>\\s*/g, '')\n .replace(\n /<available-deferred-tools>[\\s\\S]*?<\\/available-deferred-tools>\\s*/g,\n '',\n )\n .replace(/<command-name>[\\s\\S]*?<\\/command-name>\\s*/g, '')\n .replace(/<command-message>[\\s\\S]*?<\\/command-message>\\s*/g, '')\n .replace(/<command-args>[\\s\\S]*?<\\/command-args>\\s*/g, '')\n .trim()\n}\n\n/** Extract plain text from a user message */\nfunction getUserText(msg: UserMessage): string {\n const content = msg.message.content\n if (typeof content === 'string') return stripXmlForDisplay(content)\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'text') return stripXmlForDisplay(block.text)\n }\n }\n return ''\n}\n\n/**\n * Build rewind points from the messages array.\n * Each point is a user prompt (excluding tool results) with its\n * associated file changes extracted from the following assistant turn.\n */\nexport function getRewindPoints(messages: Message[]): RewindPoint[] {\n const points: RewindPoint[] = []\n\n // Collect indices of user messages (skip tool_result messages)\n const userIndices: number[] = []\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]\n if (\n msg?.type === 'user' &&\n !(\n Array.isArray(msg.message.content) &&\n msg.message.content[0]?.type === 'tool_result'\n )\n ) {\n userIndices.push(i)\n }\n }\n\n for (let i = 0; i < userIndices.length; i++) {\n const idx = userIndices[i]!\n const msg = messages[idx] as UserMessage\n const nextIdx =\n i + 1 < userIndices.length ? userIndices[i + 1]! : messages.length\n\n points.push({\n userMessage: msg,\n messageIndex: idx,\n userText: getUserText(msg),\n changedFiles: extractFileChangesForTurn(messages, idx, nextIdx),\n })\n }\n\n return points\n}\n\n// \u2500\u2500 Constants \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\nconst MAX_VISIBLE = 8\nconst MAX_TEXT_LENGTH = 120\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\n\nexport function RewindPanel({\n messages,\n onAction,\n onEscape,\n}: Props): React.ReactNode {\n const rewindPoints = useMemo(() => getRewindPoints(messages), [messages])\n\n const [phase, setPhase] = useState<'message_select' | 'action_select'>(\n 'message_select',\n )\n // Total items = rewindPoints + 1 (current). Default selection: (current)\n const totalItems = rewindPoints.length + 1\n const [selectedIndex, setSelectedIndex] = useState(rewindPoints.length)\n const [actionIndex, setActionIndex] = useState(0)\n const [selectedPoint, setSelectedPoint] = useState<RewindPoint | null>(null)\n\n useInput((input, key) => {\n if (phase === 'message_select') {\n if (key.escape) {\n onEscape()\n return\n }\n if (key.upArrow) {\n setSelectedIndex(prev => Math.max(0, prev - 1))\n return\n }\n if (key.downArrow) {\n setSelectedIndex(prev => Math.min(totalItems - 1, prev + 1))\n return\n }\n if (key.return) {\n // (current) = do nothing\n if (selectedIndex >= rewindPoints.length) {\n onEscape()\n return\n }\n const point = rewindPoints[selectedIndex]\n if (point) {\n setSelectedPoint(point)\n setPhase('action_select')\n setActionIndex(0)\n }\n return\n }\n } else if (phase === 'action_select') {\n if (key.escape) {\n setPhase('message_select')\n return\n }\n if (key.upArrow) {\n setActionIndex(prev => Math.max(0, prev - 1))\n return\n }\n if (key.downArrow) {\n setActionIndex(prev => Math.min(4, prev + 1))\n return\n }\n if (key.return && selectedPoint) {\n const actions: RewindAction[] = [\n 'restore_code_and_conversation',\n 'restore_conversation',\n 'restore_code',\n 'summarize_from_here',\n 'never_mind',\n ]\n onAction(actions[actionIndex]!, selectedPoint)\n return\n }\n // Number keys 1-5\n const num = Number(input)\n if (num >= 1 && num <= 5 && selectedPoint) {\n const actions: RewindAction[] = [\n 'restore_code_and_conversation',\n 'restore_conversation',\n 'restore_code',\n 'summarize_from_here',\n 'never_mind',\n ]\n onAction(actions[num - 1]!, selectedPoint)\n return\n }\n }\n })\n\n // \u2500\u2500 Phase 1: Message Select \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 if (phase === 'message_select') {\n const firstVisible = Math.max(\n 0,\n Math.min(\n selectedIndex - Math.floor(MAX_VISIBLE / 2),\n totalItems - MAX_VISIBLE,\n ),\n )\n const lastVisible = Math.min(totalItems, firstVisible + MAX_VISIBLE)\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={BRAND_GRADIENT.START}\n paddingX={1}\n paddingY={1}\n >\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color={BRAND_GRADIENT.START}>\n {t('rewind.title')}\n </Text>\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.selectMessage')}\n </Text>\n </Box>\n\n {/* Message list */}\n {Array.from({ length: lastVisible - firstVisible }, (_, i) => {\n const itemIndex = firstVisible + i\n const isSelected = itemIndex === selectedIndex\n const isCurrent = itemIndex >= rewindPoints.length\n\n if (isCurrent) {\n return (\n <Box key=\"current\" marginBottom={0}>\n <Text\n color={\n isSelected ? BRAND_GRADIENT.START : SEMANTIC_COLORS.dim\n }\n bold={isSelected}\n >\n {isSelected ? `${figures.pointer} ` : ' '}\n </Text>\n <Text color={SEMANTIC_COLORS.dim} italic>\n {t('dialog.current')}\n </Text>\n </Box>\n )\n }\n\n const point = rewindPoints[itemIndex]\n if (!point) return null\n\n const displayText = point.userText\n .replace(/\\n/g, ' ')\n .slice(0, MAX_TEXT_LENGTH)\n const truncated =\n point.userText.length > MAX_TEXT_LENGTH\n ? displayText + '\u2026'\n : displayText\n\n return (\n <Box\n key={point.userMessage.uuid}\n flexDirection=\"column\"\n marginBottom={0}\n >\n <Box>\n <Text\n color={isSelected ? BRAND_GRADIENT.START : undefined}\n bold={isSelected}\n >\n {isSelected ? `${figures.pointer} ` : ' '}\n </Text>\n <Text\n color={isSelected ? BRAND_GRADIENT.START : undefined}\n wrap=\"truncate\"\n >\n {truncated || t('dialog.emptyMessage')}\n </Text>\n </Box>\n <Box marginLeft={3}>\n <Text color={SEMANTIC_COLORS.dim}>\n {point.changedFiles.length === 0\n ? t('rewind.noCodeChanges')\n : point.changedFiles.join(', ')}\n </Text>\n </Box>\n </Box>\n )\n })}\n\n {/* Scroll indicators */}\n {firstVisible > 0 && (\n <Box marginLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>\n {figures.arrowUp} {t('rewind.moreAbove')}\n </Text>\n </Box>\n )}\n {lastVisible < totalItems && (\n <Box marginLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>\n {figures.arrowDown} {t('rewind.moreBelow')}\n </Text>\n </Box>\n )}\n\n {/* Footer */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n {t('rewind.enterToContinue')} \u00B7 {t('rewind.escToExit')}\n </Text>\n </Box>\n </Box>\n )\n }\n\n // \u2500\u2500 Phase 2: Action Select \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 if (!selectedPoint) return null\n\n const confirmText = selectedPoint.userText.replace(/\\n/g, ' ').slice(0, 100)\n const confirmDisplay =\n selectedPoint.userText.length > 100 ? confirmText + '\u2026' : confirmText\n\n const actionLabels = [\n t('rewind.action.restoreCodeAndConversation'),\n t('rewind.action.restoreConversation'),\n t('rewind.action.restoreCode'),\n t('rewind.action.summarizeFromHere'),\n t('rewind.action.neverMind'),\n ]\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={BRAND_GRADIENT.START}\n paddingX={1}\n paddingY={1}\n >\n {/* Header */}\n <Box flexDirection=\"column\" marginBottom={1}>\n <Text bold color={BRAND_GRADIENT.START}>\n {t('rewind.title')}\n </Text>\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.confirmRestore')}\n </Text>\n </Box>\n\n {/* Selected message preview (quoted) */}\n <Box marginBottom={1} marginLeft={1}>\n <Box\n borderStyle=\"single\"\n borderColor={SEMANTIC_COLORS.dim}\n borderLeft={true}\n borderRight={false}\n borderTop={false}\n borderBottom={false}\n paddingLeft={1}\n >\n <Text>{confirmDisplay}</Text>\n </Box>\n </Box>\n\n {/* Change summary */}\n <Box flexDirection=\"column\" marginBottom={1} marginLeft={1}>\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.conversationWillBeForked')}\n </Text>\n {selectedPoint.changedFiles.length > 0 ? (\n <Text color={SEMANTIC_COLORS.secondary}>\n {t('rewind.codeWillBeRestored')}{' '}\n {selectedPoint.changedFiles.join(', ')}.\n </Text>\n ) : (\n <Text color={SEMANTIC_COLORS.dim}>{t('rewind.noCodeChanges')}</Text>\n )}\n </Box>\n\n {/* 5 action options */}\n {actionLabels.map((label, i) => (\n <Box key={i}>\n <Text\n color={i === actionIndex ? BRAND_GRADIENT.START : undefined}\n bold={i === actionIndex}\n >\n {i === actionIndex ? `${figures.pointer} ` : ' '}\n {i + 1}. {label}\n </Text>\n </Box>\n ))}\n\n {/* Warning footer */}\n <Box marginTop={1}>\n <Text color={SEMANTIC_COLORS.error}>{t('rewind.bashWarning')}</Text>\n </Box>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -5,7 +5,8 @@ import { getTheme } from "../utils/theme.js";
|
|
|
5
5
|
import { sample } from "lodash-es";
|
|
6
6
|
import { getSessionState } from "../utils/sessionState.js";
|
|
7
7
|
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
8
|
-
import { formatNumber
|
|
8
|
+
import { formatNumber } from "../utils/format.js";
|
|
9
|
+
import { getTokenDisplay } from "../utils/tokenProgress.js";
|
|
9
10
|
import { BRAND_GRADIENT, SEMANTIC_COLORS } from "../constants/colors.js";
|
|
10
11
|
import {
|
|
11
12
|
getCurrentAgentContext,
|
|
@@ -82,13 +83,13 @@ function Spinner({ isActive = true }) {
|
|
|
82
83
|
const message = useRef(sample(MESSAGES));
|
|
83
84
|
const startTime = useRef(Date.now());
|
|
84
85
|
const theme = getTheme();
|
|
85
|
-
const { spinnerFrame, elapsedTime } = useUnifiedAnimation({
|
|
86
|
+
const { spinnerFrame, elapsedTime, dataTick } = useUnifiedAnimation({
|
|
86
87
|
enabled: isActive,
|
|
87
88
|
startTime: startTime.current,
|
|
88
89
|
spinnerFrameCount: frames.length,
|
|
89
90
|
componentId: "main-spinner"
|
|
90
91
|
});
|
|
91
|
-
const streamState = useMemo(() => getMainStreamingState2(), [
|
|
92
|
+
const streamState = useMemo(() => getMainStreamingState2(), [dataTick]);
|
|
92
93
|
const getPhaseDisplay = () => {
|
|
93
94
|
switch (streamState.phase) {
|
|
94
95
|
case "deep_thinking": {
|
|
@@ -99,8 +100,10 @@ function Spinner({ isActive = true }) {
|
|
|
99
100
|
}
|
|
100
101
|
return `Deep thinking (${elapsed}s${charInfo ? " \xB7 " + charInfo : ""})`;
|
|
101
102
|
}
|
|
102
|
-
case "retrying":
|
|
103
|
-
|
|
103
|
+
case "retrying": {
|
|
104
|
+
const delayInfo = streamState.retryDelayMs ? ` \xB7 next in ${Math.ceil(streamState.retryDelayMs / 1e3)}s` : "";
|
|
105
|
+
return streamState.retryCount && streamState.maxRetries ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \xB7 ${streamState.errorName}` : ""}${delayInfo}` : streamState.errorName ? `Retrying \xB7 ${streamState.errorName}${delayInfo}` : `Retrying...${delayInfo}`;
|
|
106
|
+
}
|
|
104
107
|
case "permission":
|
|
105
108
|
return "Waiting for permission...";
|
|
106
109
|
case "compacting":
|
|
@@ -138,23 +141,9 @@ function Spinner({ isActive = true }) {
|
|
|
138
141
|
concurrent: SEMANTIC_COLORS.success
|
|
139
142
|
// 绿色 - 并发
|
|
140
143
|
};
|
|
141
|
-
const
|
|
142
|
-
if (streamState.inputTokens || streamState.outputTokens) {
|
|
143
|
-
return formatTokenUsage(streamState.inputTokens, streamState.outputTokens);
|
|
144
|
-
}
|
|
145
|
-
if (streamState.receivedChars && streamState.receivedChars > 0) {
|
|
146
|
-
const approxOutputTokens = Math.round(streamState.receivedChars / 3);
|
|
147
|
-
if (streamState.sentChars && streamState.sentChars > 0) {
|
|
148
|
-
const approxInputTokens = Math.round(streamState.sentChars / 3);
|
|
149
|
-
return `\u2191 ~${formatNumber(approxInputTokens)} \xB7 \u2193 ~${formatNumber(approxOutputTokens)}`;
|
|
150
|
-
}
|
|
151
|
-
return `\u2193 ~${formatNumber(approxOutputTokens)}`;
|
|
152
|
-
}
|
|
153
|
-
return "";
|
|
154
|
-
};
|
|
155
|
-
const tokenUsage = getTokenDisplay();
|
|
144
|
+
const { formatted: tokenUsage } = getTokenDisplay();
|
|
156
145
|
const thinkingDuration = streamState.thinkingDurationMs ? Math.floor(streamState.thinkingDurationMs / 1e3) : null;
|
|
157
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexWrap: "nowrap", height: 1, width: 2 }, /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, frames[spinnerFrame])), /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, getPhaseDisplay(), "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(", /* @__PURE__ */ React.createElement(Text, { bold: true }, "esc
|
|
146
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginTop: 1 }, /* @__PURE__ */ React.createElement(Box, { flexWrap: "nowrap", height: 1, width: 2 }, /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, frames[spinnerFrame])), /* @__PURE__ */ React.createElement(Text, { color: phaseColors[streamState.phase] }, getPhaseDisplay(), "\u2026 "), /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "(", /* @__PURE__ */ React.createElement(Text, { bold: true }, "esc"), " to cancel \xB7 ", elapsedTime, "s", tokenUsage && /* @__PURE__ */ React.createElement(Text, null, " \xB7 ", tokenUsage), streamState.phase === "thinking" && /* @__PURE__ */ React.createElement(Text, null, " \xB7 thinking"), thinkingDuration !== null && thinkingDuration > 0 && /* @__PURE__ */ React.createElement(Text, null, " \xB7 thinking ", thinkingDuration, "s"), ")"), getSessionState("currentError") && /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.dim }, "\xB7 ", getSessionState("currentError")));
|
|
158
147
|
}
|
|
159
148
|
function SimpleSpinner({
|
|
160
149
|
isActive = true,
|
|
@@ -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 { 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
|
|
5
|
-
"mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,QAAQ,eAAe;AAChC,SAAS,gBAAgB;AACzB,SAAS,cAAc;AACvB,SAAS,uBAAuB;AAChC,SAAS,2BAA2B;AACpC,SAAS,
|
|
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 } from '@utils/format'\nimport { getTokenDisplay } from '@utils/tokenProgress'\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, dataTick } = 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 at 100ms via dataTick)\n // Use getMainStreamingState to avoid subagent interference\n const streamState = useMemo(() => getMainStreamingState(), [dataTick])\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 const delayInfo = streamState.retryDelayMs\n ? ` \u00B7 next in ${Math.ceil(streamState.retryDelayMs / 1000)}s`\n : ''\n return streamState.retryCount && streamState.maxRetries\n ? `Retrying (${streamState.retryCount}/${streamState.maxRetries})${streamState.errorName ? ` \u00B7 ${streamState.errorName}` : ''}${delayInfo}`\n : streamState.errorName\n ? `Retrying \u00B7 ${streamState.errorName}${delayInfo}`\n : `Retrying...${delayInfo}`\n }\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 const { formatted: 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</Text> to cancel \u00B7 {elapsedTime}s\n {tokenUsage && <Text> \u00B7 {tokenUsage}</Text>}\n {streamState.phase === 'thinking' && <Text> \u00B7 thinking</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
6
|
"names": ["getMainStreamingState"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { getMainStreamingState } from "../utils/streamingState.js";
|
|
5
|
+
import { applyMarkdown } from "../utils/markdown.js";
|
|
6
|
+
import { useUnifiedAnimation } from "../utils/animationManager.js";
|
|
7
|
+
import { useTerminalSize } from "../hooks/useTerminalSize.js";
|
|
8
|
+
import { SEMANTIC_COLORS } from "../constants/colors.js";
|
|
9
|
+
function StreamingTextPreview() {
|
|
10
|
+
const { columns } = useTerminalSize();
|
|
11
|
+
const { dataTick } = useUnifiedAnimation({
|
|
12
|
+
enabled: true,
|
|
13
|
+
startTime: Date.now(),
|
|
14
|
+
spinnerFrameCount: 1,
|
|
15
|
+
componentId: "streaming-text-preview"
|
|
16
|
+
});
|
|
17
|
+
const streamingText = useMemo(
|
|
18
|
+
() => getMainStreamingState().streamingText,
|
|
19
|
+
[dataTick]
|
|
20
|
+
);
|
|
21
|
+
if (!streamingText) return null;
|
|
22
|
+
const rendered = applyMarkdown(streamingText);
|
|
23
|
+
if (!rendered) return null;
|
|
24
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: columns - 6, marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: SEMANTIC_COLORS.primary }, rendered));
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
StreamingTextPreview
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=StreamingTextPreview.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/StreamingTextPreview.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * StreamingTextPreview \u2014 Typewriter-style progressive text rendering\n *\n * Reads streaming text from the global streaming state and renders it\n * in real-time as the LLM generates content. Updates at 100ms intervals\n * via the unified animation manager's dataTick.\n *\n * Displayed in the REPL's dynamic section while the model is generating.\n * Cleared when the complete message is yielded and rendered normally.\n */\n\nimport { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { useMemo } from 'react'\nimport { getMainStreamingState } from '@utils/streamingState'\nimport { applyMarkdown } from '@utils/markdown'\nimport { useUnifiedAnimation } from '@utils/animationManager'\nimport { useTerminalSize } from '@hooks/useTerminalSize'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nexport function StreamingTextPreview(): React.ReactNode {\n const { columns } = useTerminalSize()\n\n // Subscribe to animation tick for 100ms refresh\n const { dataTick } = useUnifiedAnimation({\n enabled: true,\n startTime: Date.now(),\n spinnerFrameCount: 1,\n componentId: 'streaming-text-preview',\n })\n\n const streamingText = useMemo(\n () => getMainStreamingState().streamingText,\n [dataTick],\n )\n\n if (!streamingText) return null\n\n // Apply markdown formatting to the accumulated text\n const rendered = applyMarkdown(streamingText)\n if (!rendered) return null\n\n return (\n <Box flexDirection=\"column\" width={columns - 6} marginLeft={2}>\n <Text color={SEMANTIC_COLORS.primary}>{rendered}</Text>\n </Box>\n )\n}\n"],
|
|
5
|
+
"mappings": "AAWA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,eAAe;AACxB,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAEzB,SAAS,uBAAwC;AACtD,QAAM,EAAE,QAAQ,IAAI,gBAAgB;AAGpC,QAAM,EAAE,SAAS,IAAI,oBAAoB;AAAA,IACvC,SAAS;AAAA,IACT,WAAW,KAAK,IAAI;AAAA,IACpB,mBAAmB;AAAA,IACnB,aAAa;AAAA,EACf,CAAC;AAED,QAAM,gBAAgB;AAAA,IACpB,MAAM,sBAAsB,EAAE;AAAA,IAC9B,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,CAAC,cAAe,QAAO;AAG3B,QAAM,WAAW,cAAc,aAAa;AAC5C,MAAI,CAAC,SAAU,QAAO;AAEtB,SACE,oCAAC,OAAI,eAAc,UAAS,OAAO,UAAU,GAAG,YAAY,KAC1D,oCAAC,QAAK,OAAO,gBAAgB,WAAU,QAAS,CAClD;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { getTheme } from "../utils/theme.js";
|
|
4
|
+
import { formatNumber } from "../utils/format.js";
|
|
4
5
|
import { getTodoStatusSymbol } from "../constants/symbols.js";
|
|
5
6
|
import { AgentThinkingBlock } from "./AgentThinkingBlock.js";
|
|
6
7
|
import { ToolExecutionBlock } from "./ToolExecutionBlock.js";
|
|
7
8
|
import { AgentResponseBlock } from "./AgentResponseBlock.js";
|
|
8
|
-
import { useAgentTokenStats
|
|
9
|
+
import { useAgentTokenStats } from "../hooks/useAgentTokenStats.js";
|
|
9
10
|
function SubagentBlock({
|
|
10
11
|
subagent,
|
|
11
12
|
indent = 0,
|
|
@@ -40,7 +41,7 @@ function SubagentBlock({
|
|
|
40
41
|
indent: 0,
|
|
41
42
|
isSubagent: true
|
|
42
43
|
}
|
|
43
|
-
)), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2502")), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIndicator, " ", getStatusLabel(subagent.status)), subagent.status === "completed" && /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " ", "(", duration, "s, ",
|
|
44
|
+
)), /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2502")), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 2 }, /* @__PURE__ */ React.createElement(Text, { color: theme.dimmedText }, "\u2514\u2500 "), /* @__PURE__ */ React.createElement(Text, { color: statusColor }, statusIndicator, " ", getStatusLabel(subagent.status)), subagent.status === "completed" && /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, " ", "(", duration, "s, ", formatNumber(tokenCount), " tokens)")), !expanded && /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", marginLeft: 4 }, /* @__PURE__ */ React.createElement(Text, { color: theme.mutedText }, "Press ", /* @__PURE__ */ React.createElement(Text, { bold: true }, "Ctrl+O"), " to expand details")));
|
|
44
45
|
}
|
|
45
46
|
function SubagentTodosSection({
|
|
46
47
|
todos,
|