@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from "events";
|
|
2
2
|
import { DEFAULT_ESTIMATION_CONFIG } from "./tokenStats.js";
|
|
3
|
+
import { emitReminderEvent } from "../services/systemReminder.js";
|
|
3
4
|
class TokenStatsManagerImpl extends EventEmitter {
|
|
4
5
|
static instance = null;
|
|
5
6
|
// Global aggregated stats
|
|
@@ -306,16 +307,33 @@ class TokenStatsManagerImpl extends EventEmitter {
|
|
|
306
307
|
this.globalStats = this.createEmptyStats();
|
|
307
308
|
this.agentStats.clear();
|
|
308
309
|
this.requestRecords.clear();
|
|
310
|
+
emittedTokenThresholds.clear();
|
|
309
311
|
}
|
|
310
312
|
}
|
|
311
313
|
const tokenStatsManager = TokenStatsManagerImpl.getInstance();
|
|
314
|
+
const TOKEN_THRESHOLDS = [50, 75, 90];
|
|
315
|
+
const emittedTokenThresholds = /* @__PURE__ */ new Set();
|
|
316
|
+
const DEFAULT_CONTEXT_LIMIT = 2e5;
|
|
312
317
|
function recordTokenUsage(usage, costUSD, model, context) {
|
|
313
318
|
tokenStatsManager.recordUsage(usage, costUSD, model, context);
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
319
|
+
const globalStats = tokenStatsManager.getGlobalStats();
|
|
320
|
+
const total = globalStats.grandTotalTokens;
|
|
321
|
+
const percentage = Math.round(total / DEFAULT_CONTEXT_LIMIT * 100);
|
|
322
|
+
for (const threshold of TOKEN_THRESHOLDS) {
|
|
323
|
+
if (percentage >= threshold && !emittedTokenThresholds.has(threshold)) {
|
|
324
|
+
emittedTokenThresholds.add(threshold);
|
|
325
|
+
emitReminderEvent("token:usage", {
|
|
326
|
+
used: total,
|
|
327
|
+
total: DEFAULT_CONTEXT_LIMIT,
|
|
328
|
+
percentage,
|
|
329
|
+
threshold
|
|
330
|
+
});
|
|
331
|
+
}
|
|
318
332
|
}
|
|
333
|
+
import("../utils/stats.js").then(({ recordMessage }) => {
|
|
334
|
+
recordMessage(model, usage.inputTokens, usage.outputTokens, costUSD);
|
|
335
|
+
}).catch(() => {
|
|
336
|
+
});
|
|
319
337
|
}
|
|
320
338
|
function getGlobalTokenStats() {
|
|
321
339
|
return tokenStatsManager.getGlobalStats();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/tokenStatsManager.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Token Statistics Manager\n *\n * Centralized token statistics tracking for the entire application.\n * This is the single source of truth for all token usage data.\n *\n * Architecture:\n * - Singleton pattern for global access\n * - Event-driven updates for real-time UI\n * - Hierarchical aggregation (global \u2192 agent \u2192 request)\n * - Backward compatible with existing costTracker\n *\n * Usage:\n * ```typescript\n * import { tokenStatsManager, recordTokenUsage } from '@core/tokenStatsManager'\n *\n * // Record usage from API response\n * recordTokenUsage(\n * { inputTokens: 100, outputTokens: 50 },\n * 0.0015,\n * 'gpt-4',\n * { agentId: 'agent-123' }\n * )\n *\n * // Get global stats\n * const stats = tokenStatsManager.getGlobalStats()\n *\n * // Subscribe to updates\n * const unsubscribe = tokenStatsManager.onStatsUpdate((event) => {\n * console.log('Stats updated:', event)\n * })\n * ```\n */\n\nimport { EventEmitter } from 'events'\nimport type {\n TokenUsageRecord,\n AggregatedTokenStats,\n TokenStatsScope,\n TokenStatsEvent,\n TokenTrackingContext,\n RawTokenUsage,\n ModelTokenStats,\n} from './tokenStats'\nimport { DEFAULT_ESTIMATION_CONFIG } from './tokenStats'\n\n/**\n * TokenStatsManager - Centralized token statistics tracking\n */\nclass TokenStatsManagerImpl extends EventEmitter {\n private static instance: TokenStatsManagerImpl | null = null\n\n // Global aggregated stats\n private globalStats: AggregatedTokenStats = this.createEmptyStats()\n\n // Per-agent stats (agentId \u2192 stats)\n private agentStats: Map<string, AggregatedTokenStats> = new Map()\n\n // Per-request records (requestId \u2192 record) - for debugging, with LRU eviction\n private requestRecords: Map<string, TokenUsageRecord> = new Map()\n\n // Configuration\n private static readonly MAX_REQUEST_RECORDS = 1000\n\n private constructor() {\n super()\n this.setMaxListeners(100)\n }\n\n /**\n * Get the singleton instance\n */\n static getInstance(): TokenStatsManagerImpl {\n if (!TokenStatsManagerImpl.instance) {\n TokenStatsManagerImpl.instance = new TokenStatsManagerImpl()\n }\n return TokenStatsManagerImpl.instance\n }\n\n /**\n * Record token usage from an API response\n *\n * This is the PRIMARY entry point - called from claude.ts\n * after every API response.\n *\n * @param usage - Raw token usage from API\n * @param costUSD - Calculated cost in USD\n * @param model - Model name used\n * @param context - Optional tracking context (agentId, toolUseId)\n */\n recordUsage(\n usage: RawTokenUsage,\n costUSD: number,\n model: string,\n context?: TokenTrackingContext,\n ): void {\n const record: TokenUsageRecord = {\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n cacheCreationTokens: usage.cacheCreationTokens ?? 0,\n cacheReadTokens: usage.cacheReadTokens ?? 0,\n totalTokens: usage.inputTokens + usage.outputTokens,\n estimatedCostUSD: costUSD,\n source: 'api',\n timestamp: Date.now(),\n model,\n }\n\n // Update global stats\n this.aggregateInto(this.globalStats, record)\n\n // Update agent stats if in agent context\n if (context?.agentId) {\n let stats = this.agentStats.get(context.agentId)\n if (!stats) {\n stats = this.createEmptyStats()\n this.agentStats.set(context.agentId, stats)\n }\n this.aggregateInto(stats, record)\n }\n\n // Store request record (with LRU eviction)\n const requestId =\n context?.toolUseId ??\n `req-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n this.requestRecords.set(requestId, record)\n if (this.requestRecords.size > TokenStatsManagerImpl.MAX_REQUEST_RECORDS) {\n const oldestKey = this.requestRecords.keys().next().value\n if (oldestKey) this.requestRecords.delete(oldestKey)\n }\n\n // Emit event for UI updates\n const scope: TokenStatsScope = context?.agentId\n ? { type: 'agent', agentId: context.agentId }\n : { type: 'global' }\n\n this.emitEvent({\n eventType: 'usage_recorded',\n scope,\n usage: record,\n aggregated: context?.agentId\n ? this.agentStats.get(context.agentId)!\n : this.globalStats,\n globalStats: this.globalStats,\n })\n }\n\n /**\n * Estimate token count from text\n *\n * Uses a simple character-based estimation. This is a fallback\n * when the API doesn't return token counts.\n *\n * @param text - Text to estimate tokens for\n * @returns Estimated token count\n */\n estimateTokens(text: string): number {\n return Math.ceil(text.length / DEFAULT_ESTIMATION_CONFIG.charsPerToken)\n }\n\n /**\n * Record estimated usage when API doesn't return token counts\n *\n * This is used as a fallback for APIs that don't return usage data.\n *\n * @param inputText - Input text (prompt)\n * @param outputText - Output text (completion)\n * @param model - Model name\n * @param context - Optional tracking context\n */\n recordEstimatedUsage(\n inputText: string,\n outputText: string,\n model: string,\n context?: TokenTrackingContext,\n ): void {\n const inputTokens = this.estimateTokens(inputText)\n const outputTokens = this.estimateTokens(outputText)\n\n const costUSD =\n (inputTokens / 1_000_000) *\n DEFAULT_ESTIMATION_CONFIG.defaultInputCostPerMillion +\n (outputTokens / 1_000_000) *\n DEFAULT_ESTIMATION_CONFIG.defaultOutputCostPerMillion\n\n const record: TokenUsageRecord = {\n inputTokens,\n outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n totalTokens: inputTokens + outputTokens,\n estimatedCostUSD: costUSD,\n source: 'estimated',\n timestamp: Date.now(),\n model,\n }\n\n // Update global stats\n this.aggregateInto(this.globalStats, record)\n\n // Update agent stats if in context\n if (context?.agentId) {\n let stats = this.agentStats.get(context.agentId)\n if (!stats) {\n stats = this.createEmptyStats()\n this.agentStats.set(context.agentId, stats)\n }\n this.aggregateInto(stats, record)\n }\n\n // Emit event\n this.emitEvent({\n eventType: 'usage_recorded',\n scope: { type: 'global' },\n usage: record,\n aggregated: this.globalStats,\n globalStats: this.globalStats,\n })\n }\n\n // ===== Getters =====\n\n /**\n * Get global aggregated statistics\n */\n getGlobalStats(): AggregatedTokenStats {\n return this.cloneStats(this.globalStats)\n }\n\n /**\n * Get statistics for a specific agent\n *\n * @param agentId - Agent ID to get stats for\n * @returns Agent stats or null if not found\n */\n getAgentStats(agentId: string): AggregatedTokenStats | null {\n const stats = this.agentStats.get(agentId)\n return stats ? this.cloneStats(stats) : null\n }\n\n /**\n * Get all agent statistics\n */\n getAllAgentStats(): Map<string, AggregatedTokenStats> {\n const result = new Map<string, AggregatedTokenStats>()\n for (const [agentId, stats] of this.agentStats) {\n result.set(agentId, this.cloneStats(stats))\n }\n return result\n }\n\n /**\n * Get a specific request record\n */\n getRequestRecord(requestId: string): TokenUsageRecord | null {\n return this.requestRecords.get(requestId) ?? null\n }\n\n // ===== Backward Compatibility Layer =====\n\n /**\n * Get total tokens (for costTracker.getTokenCounts compatibility)\n *\n * This method provides backward compatibility with the existing\n * costTracker.getTokenCounts() interface.\n */\n getTokenCounts(): {\n input: number\n output: number\n cacheCreation: number\n cacheRead: number\n total: number\n } {\n return {\n input: this.globalStats.totalInputTokens,\n output: this.globalStats.totalOutputTokens,\n cacheCreation: this.globalStats.totalCacheCreationTokens,\n cacheRead: this.globalStats.totalCacheReadTokens,\n total: this.globalStats.grandTotalTokens,\n }\n }\n\n // ===== Event Subscription =====\n\n /**\n * Subscribe to all stats updates\n *\n * @param callback - Called when any stats change\n * @returns Unsubscribe function\n */\n onStatsUpdate(callback: (event: TokenStatsEvent) => void): () => void {\n this.on('stats_update', callback)\n return () => this.off('stats_update', callback)\n }\n\n /**\n * Subscribe to updates for a specific agent\n *\n * @param agentId - Agent ID to subscribe to\n * @param callback - Called when agent stats change\n * @returns Unsubscribe function\n */\n onAgentStatsUpdate(\n agentId: string,\n callback: (stats: AggregatedTokenStats) => void,\n ): () => void {\n const handler = (event: TokenStatsEvent) => {\n if (event.scope.type === 'agent' && event.scope.agentId === agentId) {\n callback(event.aggregated)\n }\n }\n this.on('stats_update', handler)\n return () => this.off('stats_update', handler)\n }\n\n /**\n * Subscribe to global stats updates only\n *\n * @param callback - Called when global stats change\n * @returns Unsubscribe function\n */\n onGlobalStatsUpdate(\n callback: (stats: AggregatedTokenStats) => void,\n ): () => void {\n const handler = (event: TokenStatsEvent) => {\n callback(event.globalStats)\n }\n this.on('stats_update', handler)\n return () => this.off('stats_update', handler)\n }\n\n // ===== Agent Lifecycle =====\n\n /**\n * Mark an agent's scope as completed\n *\n * This emits a scope_completed event and optionally\n * cleans up the agent's stats from memory.\n *\n * @param agentId - Agent ID to complete\n * @param cleanup - Whether to remove from memory (default: false)\n */\n completeAgentScope(agentId: string, cleanup: boolean = false): void {\n const stats = this.agentStats.get(agentId)\n if (!stats) return\n\n this.emitEvent({\n eventType: 'scope_completed',\n scope: { type: 'agent', agentId },\n aggregated: stats,\n globalStats: this.globalStats,\n })\n\n if (cleanup) {\n this.agentStats.delete(agentId)\n }\n }\n\n // ===== Internal Methods =====\n\n private createEmptyStats(): AggregatedTokenStats {\n return {\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalCacheCreationTokens: 0,\n totalCacheReadTokens: 0,\n grandTotalTokens: 0,\n totalCostUSD: 0,\n requestCount: 0,\n byModel: new Map(),\n }\n }\n\n private aggregateInto(\n stats: AggregatedTokenStats,\n record: TokenUsageRecord,\n ): void {\n stats.totalInputTokens += record.inputTokens\n stats.totalOutputTokens += record.outputTokens\n stats.totalCacheCreationTokens += record.cacheCreationTokens\n stats.totalCacheReadTokens += record.cacheReadTokens\n stats.grandTotalTokens += record.totalTokens\n stats.totalCostUSD += record.estimatedCostUSD\n stats.requestCount += 1\n\n if (!stats.firstRequestTime) {\n stats.firstRequestTime = record.timestamp\n }\n stats.lastRequestTime = record.timestamp\n\n // Update per-model breakdown\n const modelStats = stats.byModel.get(record.model)\n if (modelStats) {\n modelStats.inputTokens += record.inputTokens\n modelStats.outputTokens += record.outputTokens\n modelStats.totalTokens += record.totalTokens\n modelStats.estimatedCostUSD += record.estimatedCostUSD\n modelStats.requestCount += 1\n } else {\n stats.byModel.set(record.model, {\n model: record.model,\n inputTokens: record.inputTokens,\n outputTokens: record.outputTokens,\n totalTokens: record.totalTokens,\n estimatedCostUSD: record.estimatedCostUSD,\n requestCount: 1,\n })\n }\n }\n\n private cloneStats(stats: AggregatedTokenStats): AggregatedTokenStats {\n return {\n ...stats,\n byModel: new Map(stats.byModel),\n }\n }\n\n private emitEvent(event: TokenStatsEvent): void {\n this.emit('stats_update', event)\n }\n\n /**\n * Reset all stats (for testing only)\n */\n resetForTests(): void {\n if (process.env.NODE_ENV !== 'test') {\n throw new Error('resetForTests can only be called in tests')\n }\n this.reset()\n }\n\n /**\n * Reset all statistics\n *\n * Called by costTracker.resetStateForTests() for backward compatibility.\n */\n reset(): void {\n this.globalStats = this.createEmptyStats()\n this.agentStats.clear()\n this.requestRecords.clear()\n }\n}\n\n// Export singleton instance\nexport const tokenStatsManager = TokenStatsManagerImpl.getInstance()\n\n// ===== Convenience Functions =====\n\n/**\n * Record token usage from an API response\n *\n * This is the main function to call from claude.ts after each API response.\n * Also updates the persistent stats manager for cross-session tracking.\n */\nexport function recordTokenUsage(\n usage: RawTokenUsage,\n costUSD: number,\n model: string,\n context?: TokenTrackingContext,\n): void {\n tokenStatsManager.recordUsage(usage, costUSD, model, context)\n\n // Also record to persistent stats manager (fire-and-forget)\n try {\n const { recordMessage } = require('@utils/stats')\n recordMessage(model, usage.inputTokens, usage.outputTokens, costUSD)\n } catch {\n // Stats manager not available, ignore\n }\n}\n\n/**\n * Get global token statistics\n */\nexport function getGlobalTokenStats(): AggregatedTokenStats {\n return tokenStatsManager.getGlobalStats()\n}\n\n/**\n * Get token statistics for a specific agent\n */\nexport function getAgentTokenStats(\n agentId: string,\n): AggregatedTokenStats | null {\n return tokenStatsManager.getAgentStats(agentId)\n}\n\n/**\n * Estimate token count from text\n */\nexport function estimateTokenCount(text: string): number {\n return tokenStatsManager.estimateTokens(text)\n}\n"],
|
|
5
|
-
"mappings": "AAkCA,SAAS,oBAAoB;AAU7B,SAAS,iCAAiC;
|
|
4
|
+
"sourcesContent": ["/**\n * Token Statistics Manager\n *\n * Centralized token statistics tracking for the entire application.\n * This is the single source of truth for all token usage data.\n *\n * Architecture:\n * - Singleton pattern for global access\n * - Event-driven updates for real-time UI\n * - Hierarchical aggregation (global \u2192 agent \u2192 request)\n * - Backward compatible with existing costTracker\n *\n * Usage:\n * ```typescript\n * import { tokenStatsManager, recordTokenUsage } from '@core/tokenStatsManager'\n *\n * // Record usage from API response\n * recordTokenUsage(\n * { inputTokens: 100, outputTokens: 50 },\n * 0.0015,\n * 'gpt-4',\n * { agentId: 'agent-123' }\n * )\n *\n * // Get global stats\n * const stats = tokenStatsManager.getGlobalStats()\n *\n * // Subscribe to updates\n * const unsubscribe = tokenStatsManager.onStatsUpdate((event) => {\n * console.log('Stats updated:', event)\n * })\n * ```\n */\n\nimport { EventEmitter } from 'events'\nimport type {\n TokenUsageRecord,\n AggregatedTokenStats,\n TokenStatsScope,\n TokenStatsEvent,\n TokenTrackingContext,\n RawTokenUsage,\n ModelTokenStats,\n} from './tokenStats'\nimport { DEFAULT_ESTIMATION_CONFIG } from './tokenStats'\nimport { emitReminderEvent } from '../services/systemReminder'\n\n/**\n * TokenStatsManager - Centralized token statistics tracking\n */\nclass TokenStatsManagerImpl extends EventEmitter {\n private static instance: TokenStatsManagerImpl | null = null\n\n // Global aggregated stats\n private globalStats: AggregatedTokenStats = this.createEmptyStats()\n\n // Per-agent stats (agentId \u2192 stats)\n private agentStats: Map<string, AggregatedTokenStats> = new Map()\n\n // Per-request records (requestId \u2192 record) - for debugging, with LRU eviction\n private requestRecords: Map<string, TokenUsageRecord> = new Map()\n\n // Configuration\n private static readonly MAX_REQUEST_RECORDS = 1000\n\n private constructor() {\n super()\n this.setMaxListeners(100)\n }\n\n /**\n * Get the singleton instance\n */\n static getInstance(): TokenStatsManagerImpl {\n if (!TokenStatsManagerImpl.instance) {\n TokenStatsManagerImpl.instance = new TokenStatsManagerImpl()\n }\n return TokenStatsManagerImpl.instance\n }\n\n /**\n * Record token usage from an API response\n *\n * This is the PRIMARY entry point - called from claude.ts\n * after every API response.\n *\n * @param usage - Raw token usage from API\n * @param costUSD - Calculated cost in USD\n * @param model - Model name used\n * @param context - Optional tracking context (agentId, toolUseId)\n */\n recordUsage(\n usage: RawTokenUsage,\n costUSD: number,\n model: string,\n context?: TokenTrackingContext,\n ): void {\n const record: TokenUsageRecord = {\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n cacheCreationTokens: usage.cacheCreationTokens ?? 0,\n cacheReadTokens: usage.cacheReadTokens ?? 0,\n totalTokens: usage.inputTokens + usage.outputTokens,\n estimatedCostUSD: costUSD,\n source: 'api',\n timestamp: Date.now(),\n model,\n }\n\n // Update global stats\n this.aggregateInto(this.globalStats, record)\n\n // Update agent stats if in agent context\n if (context?.agentId) {\n let stats = this.agentStats.get(context.agentId)\n if (!stats) {\n stats = this.createEmptyStats()\n this.agentStats.set(context.agentId, stats)\n }\n this.aggregateInto(stats, record)\n }\n\n // Store request record (with LRU eviction)\n const requestId =\n context?.toolUseId ??\n `req-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n this.requestRecords.set(requestId, record)\n if (this.requestRecords.size > TokenStatsManagerImpl.MAX_REQUEST_RECORDS) {\n const oldestKey = this.requestRecords.keys().next().value\n if (oldestKey) this.requestRecords.delete(oldestKey)\n }\n\n // Emit event for UI updates\n const scope: TokenStatsScope = context?.agentId\n ? { type: 'agent', agentId: context.agentId }\n : { type: 'global' }\n\n this.emitEvent({\n eventType: 'usage_recorded',\n scope,\n usage: record,\n aggregated: context?.agentId\n ? this.agentStats.get(context.agentId)!\n : this.globalStats,\n globalStats: this.globalStats,\n })\n }\n\n /**\n * Estimate token count from text\n *\n * Uses a simple character-based estimation. This is a fallback\n * when the API doesn't return token counts.\n *\n * @param text - Text to estimate tokens for\n * @returns Estimated token count\n */\n estimateTokens(text: string): number {\n return Math.ceil(text.length / DEFAULT_ESTIMATION_CONFIG.charsPerToken)\n }\n\n /**\n * Record estimated usage when API doesn't return token counts\n *\n * This is used as a fallback for APIs that don't return usage data.\n *\n * @param inputText - Input text (prompt)\n * @param outputText - Output text (completion)\n * @param model - Model name\n * @param context - Optional tracking context\n */\n recordEstimatedUsage(\n inputText: string,\n outputText: string,\n model: string,\n context?: TokenTrackingContext,\n ): void {\n const inputTokens = this.estimateTokens(inputText)\n const outputTokens = this.estimateTokens(outputText)\n\n const costUSD =\n (inputTokens / 1_000_000) *\n DEFAULT_ESTIMATION_CONFIG.defaultInputCostPerMillion +\n (outputTokens / 1_000_000) *\n DEFAULT_ESTIMATION_CONFIG.defaultOutputCostPerMillion\n\n const record: TokenUsageRecord = {\n inputTokens,\n outputTokens,\n cacheCreationTokens: 0,\n cacheReadTokens: 0,\n totalTokens: inputTokens + outputTokens,\n estimatedCostUSD: costUSD,\n source: 'estimated',\n timestamp: Date.now(),\n model,\n }\n\n // Update global stats\n this.aggregateInto(this.globalStats, record)\n\n // Update agent stats if in context\n if (context?.agentId) {\n let stats = this.agentStats.get(context.agentId)\n if (!stats) {\n stats = this.createEmptyStats()\n this.agentStats.set(context.agentId, stats)\n }\n this.aggregateInto(stats, record)\n }\n\n // Emit event\n this.emitEvent({\n eventType: 'usage_recorded',\n scope: { type: 'global' },\n usage: record,\n aggregated: this.globalStats,\n globalStats: this.globalStats,\n })\n }\n\n // ===== Getters =====\n\n /**\n * Get global aggregated statistics\n */\n getGlobalStats(): AggregatedTokenStats {\n return this.cloneStats(this.globalStats)\n }\n\n /**\n * Get statistics for a specific agent\n *\n * @param agentId - Agent ID to get stats for\n * @returns Agent stats or null if not found\n */\n getAgentStats(agentId: string): AggregatedTokenStats | null {\n const stats = this.agentStats.get(agentId)\n return stats ? this.cloneStats(stats) : null\n }\n\n /**\n * Get all agent statistics\n */\n getAllAgentStats(): Map<string, AggregatedTokenStats> {\n const result = new Map<string, AggregatedTokenStats>()\n for (const [agentId, stats] of this.agentStats) {\n result.set(agentId, this.cloneStats(stats))\n }\n return result\n }\n\n /**\n * Get a specific request record\n */\n getRequestRecord(requestId: string): TokenUsageRecord | null {\n return this.requestRecords.get(requestId) ?? null\n }\n\n // ===== Backward Compatibility Layer =====\n\n /**\n * Get total tokens (for costTracker.getTokenCounts compatibility)\n *\n * This method provides backward compatibility with the existing\n * costTracker.getTokenCounts() interface.\n */\n getTokenCounts(): {\n input: number\n output: number\n cacheCreation: number\n cacheRead: number\n total: number\n } {\n return {\n input: this.globalStats.totalInputTokens,\n output: this.globalStats.totalOutputTokens,\n cacheCreation: this.globalStats.totalCacheCreationTokens,\n cacheRead: this.globalStats.totalCacheReadTokens,\n total: this.globalStats.grandTotalTokens,\n }\n }\n\n // ===== Event Subscription =====\n\n /**\n * Subscribe to all stats updates\n *\n * @param callback - Called when any stats change\n * @returns Unsubscribe function\n */\n onStatsUpdate(callback: (event: TokenStatsEvent) => void): () => void {\n this.on('stats_update', callback)\n return () => this.off('stats_update', callback)\n }\n\n /**\n * Subscribe to updates for a specific agent\n *\n * @param agentId - Agent ID to subscribe to\n * @param callback - Called when agent stats change\n * @returns Unsubscribe function\n */\n onAgentStatsUpdate(\n agentId: string,\n callback: (stats: AggregatedTokenStats) => void,\n ): () => void {\n const handler = (event: TokenStatsEvent) => {\n if (event.scope.type === 'agent' && event.scope.agentId === agentId) {\n callback(event.aggregated)\n }\n }\n this.on('stats_update', handler)\n return () => this.off('stats_update', handler)\n }\n\n /**\n * Subscribe to global stats updates only\n *\n * @param callback - Called when global stats change\n * @returns Unsubscribe function\n */\n onGlobalStatsUpdate(\n callback: (stats: AggregatedTokenStats) => void,\n ): () => void {\n const handler = (event: TokenStatsEvent) => {\n callback(event.globalStats)\n }\n this.on('stats_update', handler)\n return () => this.off('stats_update', handler)\n }\n\n // ===== Agent Lifecycle =====\n\n /**\n * Mark an agent's scope as completed\n *\n * This emits a scope_completed event and optionally\n * cleans up the agent's stats from memory.\n *\n * @param agentId - Agent ID to complete\n * @param cleanup - Whether to remove from memory (default: false)\n */\n completeAgentScope(agentId: string, cleanup: boolean = false): void {\n const stats = this.agentStats.get(agentId)\n if (!stats) return\n\n this.emitEvent({\n eventType: 'scope_completed',\n scope: { type: 'agent', agentId },\n aggregated: stats,\n globalStats: this.globalStats,\n })\n\n if (cleanup) {\n this.agentStats.delete(agentId)\n }\n }\n\n // ===== Internal Methods =====\n\n private createEmptyStats(): AggregatedTokenStats {\n return {\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalCacheCreationTokens: 0,\n totalCacheReadTokens: 0,\n grandTotalTokens: 0,\n totalCostUSD: 0,\n requestCount: 0,\n byModel: new Map(),\n }\n }\n\n private aggregateInto(\n stats: AggregatedTokenStats,\n record: TokenUsageRecord,\n ): void {\n stats.totalInputTokens += record.inputTokens\n stats.totalOutputTokens += record.outputTokens\n stats.totalCacheCreationTokens += record.cacheCreationTokens\n stats.totalCacheReadTokens += record.cacheReadTokens\n stats.grandTotalTokens += record.totalTokens\n stats.totalCostUSD += record.estimatedCostUSD\n stats.requestCount += 1\n\n if (!stats.firstRequestTime) {\n stats.firstRequestTime = record.timestamp\n }\n stats.lastRequestTime = record.timestamp\n\n // Update per-model breakdown\n const modelStats = stats.byModel.get(record.model)\n if (modelStats) {\n modelStats.inputTokens += record.inputTokens\n modelStats.outputTokens += record.outputTokens\n modelStats.totalTokens += record.totalTokens\n modelStats.estimatedCostUSD += record.estimatedCostUSD\n modelStats.requestCount += 1\n } else {\n stats.byModel.set(record.model, {\n model: record.model,\n inputTokens: record.inputTokens,\n outputTokens: record.outputTokens,\n totalTokens: record.totalTokens,\n estimatedCostUSD: record.estimatedCostUSD,\n requestCount: 1,\n })\n }\n }\n\n private cloneStats(stats: AggregatedTokenStats): AggregatedTokenStats {\n return {\n ...stats,\n byModel: new Map(stats.byModel),\n }\n }\n\n private emitEvent(event: TokenStatsEvent): void {\n this.emit('stats_update', event)\n }\n\n /**\n * Reset all stats (for testing only)\n */\n resetForTests(): void {\n if (process.env.NODE_ENV !== 'test') {\n throw new Error('resetForTests can only be called in tests')\n }\n this.reset()\n }\n\n /**\n * Reset all statistics\n *\n * Called by costTracker.resetStateForTests() for backward compatibility.\n */\n reset(): void {\n this.globalStats = this.createEmptyStats()\n this.agentStats.clear()\n this.requestRecords.clear()\n emittedTokenThresholds.clear()\n }\n}\n\n// Export singleton instance\nexport const tokenStatsManager = TokenStatsManagerImpl.getInstance()\n\n// ===== Convenience Functions =====\n\n/**\n * Record token usage from an API response\n *\n * This is the main function to call from claude.ts after each API response.\n * Also updates the persistent stats manager for cross-session tracking.\n */\n// Token usage thresholds (percentage of context limit)\nconst TOKEN_THRESHOLDS = [50, 75, 90] as const\nconst emittedTokenThresholds = new Set<number>()\nconst DEFAULT_CONTEXT_LIMIT = 200_000\n\nexport function recordTokenUsage(\n usage: RawTokenUsage,\n costUSD: number,\n model: string,\n context?: TokenTrackingContext,\n): void {\n tokenStatsManager.recordUsage(usage, costUSD, model, context)\n\n // Emit token:usage at threshold crossings\n const globalStats = tokenStatsManager.getGlobalStats()\n const total = globalStats.grandTotalTokens\n const percentage = Math.round((total / DEFAULT_CONTEXT_LIMIT) * 100)\n for (const threshold of TOKEN_THRESHOLDS) {\n if (percentage >= threshold && !emittedTokenThresholds.has(threshold)) {\n emittedTokenThresholds.add(threshold)\n emitReminderEvent('token:usage', {\n used: total,\n total: DEFAULT_CONTEXT_LIMIT,\n percentage,\n threshold,\n })\n }\n }\n\n // Also record to persistent stats manager (fire-and-forget)\n import('@utils/stats')\n .then(({ recordMessage }) => {\n recordMessage(model, usage.inputTokens, usage.outputTokens, costUSD)\n })\n .catch(() => {\n // Stats manager not available, ignore\n })\n}\n\n/**\n * Get global token statistics\n */\nexport function getGlobalTokenStats(): AggregatedTokenStats {\n return tokenStatsManager.getGlobalStats()\n}\n\n/**\n * Get token statistics for a specific agent\n */\nexport function getAgentTokenStats(\n agentId: string,\n): AggregatedTokenStats | null {\n return tokenStatsManager.getAgentStats(agentId)\n}\n\n/**\n * Estimate token count from text\n */\nexport function estimateTokenCount(text: string): number {\n return tokenStatsManager.estimateTokens(text)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/cost-tracker.js
CHANGED
|
@@ -2,11 +2,6 @@ import chalk from "chalk";
|
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import signalExit from "signal-exit";
|
|
4
4
|
import { formatDuration } from "./utils/format.js";
|
|
5
|
-
import {
|
|
6
|
-
getCurrentProjectConfig,
|
|
7
|
-
saveCurrentProjectConfig
|
|
8
|
-
} from "./utils/config.js";
|
|
9
|
-
import { SESSION_ID } from "./utils/log.js";
|
|
10
5
|
const STATE = {
|
|
11
6
|
totalCost: 0,
|
|
12
7
|
totalAPIDuration: 0,
|
|
@@ -45,17 +40,6 @@ function useCostSummary() {
|
|
|
45
40
|
signalExit(
|
|
46
41
|
() => {
|
|
47
42
|
process.stdout.write("\n" + formatTotalCost() + "\n");
|
|
48
|
-
try {
|
|
49
|
-
const projectConfig = getCurrentProjectConfig();
|
|
50
|
-
saveCurrentProjectConfig({
|
|
51
|
-
...projectConfig,
|
|
52
|
-
lastCost: STATE.totalCost,
|
|
53
|
-
lastAPIDuration: STATE.totalAPIDuration,
|
|
54
|
-
lastDuration: getTotalDuration(),
|
|
55
|
-
lastSessionId: SESSION_ID
|
|
56
|
-
});
|
|
57
|
-
} catch {
|
|
58
|
-
}
|
|
59
43
|
},
|
|
60
44
|
{ alwaysLast: true }
|
|
61
45
|
);
|
package/dist/cost-tracker.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cost-tracker.ts"],
|
|
4
|
-
"sourcesContent": ["import chalk from 'chalk'\nimport { useEffect } from 'react'\nimport signalExit from 'signal-exit'\nimport { formatDuration } from './utils/format'\
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,iBAAiB;AAC1B,OAAO,gBAAgB;AACvB,SAAS,sBAAsB;
|
|
4
|
+
"sourcesContent": ["import chalk from 'chalk'\nimport { useEffect } from 'react'\nimport signalExit from 'signal-exit'\nimport { formatDuration } from './utils/format'\n\n// DO NOT ADD MORE STATE HERE OR BORIS WILL CURSE YOU\nconst STATE: {\n totalCost: number\n totalAPIDuration: number\n startTime: number\n} = {\n totalCost: 0,\n totalAPIDuration: 0,\n startTime: Date.now(),\n}\n\nexport function addToTotalCost(cost: number, duration: number): void {\n STATE.totalCost += cost\n STATE.totalAPIDuration += duration\n}\n\nexport function getTotalCost(): number {\n return STATE.totalCost\n}\n\nexport function getTotalDuration(): number {\n return Date.now() - STATE.startTime\n}\n\nexport function getTotalAPIDuration(): number {\n return STATE.totalAPIDuration\n}\n\nfunction formatCost(cost: number): string {\n return `$${cost > 0.5 ? round(cost, 100).toFixed(2) : cost.toFixed(4)}`\n}\n\nexport function formatTotalCost(): string {\n return chalk.grey(\n `Total cost: ${formatCost(STATE.totalCost)}\nTotal duration (API): ${formatDuration(STATE.totalAPIDuration)}\nTotal duration (wall): ${formatDuration(getTotalDuration())}`,\n )\n}\n\n/**\n * useCostSummary - Register exit handler to display cost summary\n *\n * CRITICAL FIX: Use signal-exit with alwaysLast: true\n *\n * The problem was that Ink also uses signal-exit (with alwaysLast: false)\n * to clean up on exit. During Ink's cleanup, it may:\n * 1. Call onRender() one last time\n * 2. Use ansiEscapes.eraseLines() to clear previous output\n * 3. Or even call clearTerminal if output height >= terminal rows\n *\n * By using signal-exit with alwaysLast: true, we ensure our handler\n * runs AFTER Ink's cleanup, so our statistics are the last thing printed.\n */\n// Flag to ensure we only register once and never unregister\nlet exitHandlerRegistered = false\n\nexport function useCostSummary(): void {\n useEffect(() => {\n // Only register ONCE, and NEVER unregister\n if (exitHandlerRegistered) {\n return\n }\n exitHandlerRegistered = true\n\n // Use signal-exit with alwaysLast: true to run AFTER Ink's cleanup\n // This ensures our statistics are printed after Ink finishes its final render\n signalExit(\n () => {\n // Write statistics to stdout\n // Using stdout.write directly to avoid any Ink interception\n process.stdout.write('\\n' + formatTotalCost() + '\\n')\n },\n { alwaysLast: true },\n )\n\n // NO cleanup function - we NEVER want to unregister this handler\n }, [])\n}\n\nfunction round(number: number, precision: number): number {\n return Math.round(number * precision) / precision\n}\n\n// Only used in tests\nexport function resetStateForTests(): void {\n if (process.env.NODE_ENV !== 'test') {\n throw new Error('resetStateForTests can only be called in tests')\n }\n STATE.startTime = Date.now()\n STATE.totalCost = 0\n STATE.totalAPIDuration = 0\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OAAO,WAAW;AAClB,SAAS,iBAAiB;AAC1B,OAAO,gBAAgB;AACvB,SAAS,sBAAsB;AAG/B,MAAM,QAIF;AAAA,EACF,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,WAAW,KAAK,IAAI;AACtB;AAEO,SAAS,eAAe,MAAc,UAAwB;AACnE,QAAM,aAAa;AACnB,QAAM,oBAAoB;AAC5B;AAEO,SAAS,eAAuB;AACrC,SAAO,MAAM;AACf;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,IAAI,IAAI,MAAM;AAC5B;AAEO,SAAS,sBAA8B;AAC5C,SAAO,MAAM;AACf;AAEA,SAAS,WAAW,MAAsB;AACxC,SAAO,IAAI,OAAO,MAAM,MAAM,MAAM,GAAG,EAAE,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;AACvE;AAEO,SAAS,kBAA0B;AACxC,SAAO,MAAM;AAAA,IACX,eAAe,WAAW,MAAM,SAAS,CAAC;AAAA,wBACtB,eAAe,MAAM,gBAAgB,CAAC;AAAA,yBACrC,eAAe,iBAAiB,CAAC,CAAC;AAAA,EACzD;AACF;AAiBA,IAAI,wBAAwB;AAErB,SAAS,iBAAuB;AACrC,YAAU,MAAM;AAEd,QAAI,uBAAuB;AACzB;AAAA,IACF;AACA,4BAAwB;AAIxB;AAAA,MACE,MAAM;AAGJ,gBAAQ,OAAO,MAAM,OAAO,gBAAgB,IAAI,IAAI;AAAA,MACtD;AAAA,MACA,EAAE,YAAY,KAAK;AAAA,IACrB;AAAA,EAGF,GAAG,CAAC,CAAC;AACP;AAEA,SAAS,MAAM,QAAgB,WAA2B;AACxD,SAAO,KAAK,MAAM,SAAS,SAAS,IAAI;AAC1C;AAGO,SAAS,qBAA2B;AACzC,MAAI,QAAQ,IAAI,aAAa,QAAQ;AACnC,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,YAAY;AAClB,QAAM,mBAAmB;AAC3B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -35,7 +35,9 @@ async function main() {
|
|
|
35
35
|
const message = err.message || "";
|
|
36
36
|
if (message.includes("react-devtools-core")) {
|
|
37
37
|
console.error("\n\u274C Failed to start: react-devtools-core not found");
|
|
38
|
-
console.error(
|
|
38
|
+
console.error(
|
|
39
|
+
" This may be caused by DEV environment variable being set."
|
|
40
|
+
);
|
|
39
41
|
console.error(" Try running: unset DEV && minto\n");
|
|
40
42
|
} else if (message.includes("yoga") || message.includes("YOGA")) {
|
|
41
43
|
console.error("\n\u274C Failed to start: yoga-layout initialization failed");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/entrypoints/bootstrap.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env -S node --no-warnings=ExperimentalWarning --enable-source-maps\n\n/**\n * Bootstrap entry point for Minto CLI\n *\n * CRITICAL: This file MUST remain minimal with NO static imports of application code.\n *\n * This bootstrap exists because ESM static imports execute BEFORE the importing\n * module's code. We need certain initializations to happen BEFORE any application\n * modules are loaded:\n *\n * 1. DEV='false' - Ink checks process.env['DEV'] at module load time and tries to\n * import 'react-devtools-core' if DEV='true'. This package isn't bundled.\n *\n * 2. EventEmitter.defaultMaxListeners - Must be set before any modules create\n * EventEmitters to prevent \"MaxListenersExceededWarning\" during startup.\n *\n * 3. YOGA_WASM_PATH - Must be set before Ink initializes yoga-layout for proper\n * terminal layout rendering.\n *\n * Solution: Use dynamic import() to load cli.tsx AFTER all initializations.\n * Dynamic import() is evaluated at runtime, not at module load time.\n *\n * DO NOT add any static imports here except for Node.js built-ins that don't\n * chain to application code (directly or transitively).\n */\n\nimport { EventEmitter } from 'events'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, join } from 'node:path'\nimport { existsSync } from 'node:fs'\n\n// ============================================================================\n// 1. Disable Ink's development mode\n// ============================================================================\n// Prevents Ink from trying to load react-devtools-core which isn't bundled.\n// Must use both syntaxes because Bun's --define only replaces dot syntax.\nprocess.env.DEV = 'false'\nprocess.env['DEV'] = 'false'\n\n// ============================================================================\n// 2. Increase EventEmitter max listeners\n// ============================================================================\n// Components like ModelConfig, ModelSelector use multiple useInput hooks which\n// add listeners. Default is 10, we increase to 20 to accommodate deep hierarchies.\n// Must be set before any modules create EventEmitters.\nEventEmitter.defaultMaxListeners = 20\n\n// ============================================================================\n// 3. Set YOGA_WASM_PATH for Ink layout engine\n// ============================================================================\n// Ink uses yoga-layout for terminal UI layout. The WASM file path must be set\n// before Ink initializes. Resolve relative to this file for both dev and dist.\ntry {\n if (!process.env.YOGA_WASM_PATH) {\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = dirname(__filename)\n // Check multiple possible locations\n const candidates = [\n join(__dirname, './yoga.wasm'),
|
|
5
|
-
"mappings": ";AA2BA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAC9B,SAAS,kBAAkB;AAO3B,QAAQ,IAAI,MAAM;AAClB,QAAQ,IAAI,KAAK,IAAI;AAQrB,aAAa,sBAAsB;AAOnC,IAAI;AACF,MAAI,CAAC,QAAQ,IAAI,gBAAgB;AAC/B,UAAM,aAAa,cAAc,YAAY,GAAG;AAChD,UAAM,YAAY,QAAQ,UAAU;AAEpC,UAAM,aAAa;AAAA,MACjB,KAAK,WAAW,aAAa;AAAA;AAAA,MAC7B,KAAK,WAAW,cAAc;AAAA;AAAA,MAC9B,KAAK,WAAW,iBAAiB;AAAA;AAAA,IACnC;AACA,eAAW,aAAa,YAAY;AAClC,UAAI,WAAW,SAAS,GAAG;AACzB,gBAAQ,IAAI,iBAAiB;AAC7B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,QAAQ;AAER;AAMA,eAAe,OAAsB;AACnC,MAAI;AACF,UAAM,OAAO,UAAU;AAAA,EACzB,SAAS,OAAO;AAEd,UAAM,MAAM;AACZ,UAAM,UAAU,IAAI,WAAW;AAE/B,QAAI,QAAQ,SAAS,qBAAqB,GAAG;AAC3C,cAAQ,MAAM,yDAAoD;AAClE,cAAQ,
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env -S node --no-warnings=ExperimentalWarning --enable-source-maps\n\n/**\n * Bootstrap entry point for Minto CLI\n *\n * CRITICAL: This file MUST remain minimal with NO static imports of application code.\n *\n * This bootstrap exists because ESM static imports execute BEFORE the importing\n * module's code. We need certain initializations to happen BEFORE any application\n * modules are loaded:\n *\n * 1. DEV='false' - Ink checks process.env['DEV'] at module load time and tries to\n * import 'react-devtools-core' if DEV='true'. This package isn't bundled.\n *\n * 2. EventEmitter.defaultMaxListeners - Must be set before any modules create\n * EventEmitters to prevent \"MaxListenersExceededWarning\" during startup.\n *\n * 3. YOGA_WASM_PATH - Must be set before Ink initializes yoga-layout for proper\n * terminal layout rendering.\n *\n * Solution: Use dynamic import() to load cli.tsx AFTER all initializations.\n * Dynamic import() is evaluated at runtime, not at module load time.\n *\n * DO NOT add any static imports here except for Node.js built-ins that don't\n * chain to application code (directly or transitively).\n */\n\nimport { EventEmitter } from 'events'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, join } from 'node:path'\nimport { existsSync } from 'node:fs'\n\n// ============================================================================\n// 1. Disable Ink's development mode\n// ============================================================================\n// Prevents Ink from trying to load react-devtools-core which isn't bundled.\n// Must use both syntaxes because Bun's --define only replaces dot syntax.\nprocess.env.DEV = 'false'\nprocess.env['DEV'] = 'false'\n\n// ============================================================================\n// 2. Increase EventEmitter max listeners\n// ============================================================================\n// Components like ModelConfig, ModelSelector use multiple useInput hooks which\n// add listeners. Default is 10, we increase to 20 to accommodate deep hierarchies.\n// Must be set before any modules create EventEmitters.\nEventEmitter.defaultMaxListeners = 20\n\n// ============================================================================\n// 3. Set YOGA_WASM_PATH for Ink layout engine\n// ============================================================================\n// Ink uses yoga-layout for terminal UI layout. The WASM file path must be set\n// before Ink initializes. Resolve relative to this file for both dev and dist.\ntry {\n if (!process.env.YOGA_WASM_PATH) {\n const __filename = fileURLToPath(import.meta.url)\n const __dirname = dirname(__filename)\n // Check multiple possible locations\n const candidates = [\n join(__dirname, './yoga.wasm'), // dist/entrypoints/yoga.wasm\n join(__dirname, '../yoga.wasm'), // dist/yoga.wasm\n join(__dirname, '../../yoga.wasm'), // project root (dev mode)\n ]\n for (const candidate of candidates) {\n if (existsSync(candidate)) {\n process.env.YOGA_WASM_PATH = candidate\n break\n }\n }\n }\n} catch {\n // Ignore errors - yoga will use fallback or error at runtime\n}\n\n// ============================================================================\n// Main: Dynamically import the CLI\n// ============================================================================\n// This ensures all static imports in cli.tsx see the initialized environment.\nasync function main(): Promise<void> {\n try {\n await import('./cli.js')\n } catch (error) {\n // Provide helpful error messages for common failures\n const err = error as Error\n const message = err.message || ''\n\n if (message.includes('react-devtools-core')) {\n console.error('\\n\u274C Failed to start: react-devtools-core not found')\n console.error(\n ' This may be caused by DEV environment variable being set.',\n )\n console.error(' Try running: unset DEV && minto\\n')\n } else if (message.includes('yoga') || message.includes('YOGA')) {\n console.error('\\n\u274C Failed to start: yoga-layout initialization failed')\n console.error(' The yoga.wasm file may be missing or corrupted.')\n console.error(' Try reinstalling: npm install -g @within-7/minto\\n')\n } else {\n console.error('\u274C Failed to start:', message || err)\n if (err.stack) {\n console.error(err.stack)\n }\n }\n process.exit(1)\n }\n}\n\nmain()\n"],
|
|
5
|
+
"mappings": ";AA2BA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,SAAS,YAAY;AAC9B,SAAS,kBAAkB;AAO3B,QAAQ,IAAI,MAAM;AAClB,QAAQ,IAAI,KAAK,IAAI;AAQrB,aAAa,sBAAsB;AAOnC,IAAI;AACF,MAAI,CAAC,QAAQ,IAAI,gBAAgB;AAC/B,UAAM,aAAa,cAAc,YAAY,GAAG;AAChD,UAAM,YAAY,QAAQ,UAAU;AAEpC,UAAM,aAAa;AAAA,MACjB,KAAK,WAAW,aAAa;AAAA;AAAA,MAC7B,KAAK,WAAW,cAAc;AAAA;AAAA,MAC9B,KAAK,WAAW,iBAAiB;AAAA;AAAA,IACnC;AACA,eAAW,aAAa,YAAY;AAClC,UAAI,WAAW,SAAS,GAAG;AACzB,gBAAQ,IAAI,iBAAiB;AAC7B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,QAAQ;AAER;AAMA,eAAe,OAAsB;AACnC,MAAI;AACF,UAAM,OAAO,UAAU;AAAA,EACzB,SAAS,OAAO;AAEd,UAAM,MAAM;AACZ,UAAM,UAAU,IAAI,WAAW;AAE/B,QAAI,QAAQ,SAAS,qBAAqB,GAAG;AAC3C,cAAQ,MAAM,yDAAoD;AAClE,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,MAAM,sCAAsC;AAAA,IACtD,WAAW,QAAQ,SAAS,MAAM,KAAK,QAAQ,SAAS,MAAM,GAAG;AAC/D,cAAQ,MAAM,6DAAwD;AACtE,cAAQ,MAAM,oDAAoD;AAClE,cAAQ,MAAM,uDAAuD;AAAA,IACvE,OAAO;AACL,cAAQ,MAAM,2BAAsB,WAAW,GAAG;AAClD,UAAI,IAAI,OAAO;AACb,gBAAQ,MAAM,IAAI,KAAK;AAAA,MACzB;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/entrypoints/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import { getContext, setContext, removeContext } from "../context.js";
|
|
|
15
15
|
import { Command } from "@commander-js/extra-typings";
|
|
16
16
|
import { ask } from "../utils/ask.js";
|
|
17
17
|
import { hasPermissionsToUseTool } from "../permissions.js";
|
|
18
|
-
import { getTools } from "../tools.js";
|
|
18
|
+
import { getBuiltInTools, getTools } from "../tools.js";
|
|
19
19
|
import {
|
|
20
20
|
getGlobalConfig,
|
|
21
21
|
getCurrentProjectConfig,
|
|
@@ -42,7 +42,7 @@ import { ResumeConversation } from "../screens/ResumeConversation.js";
|
|
|
42
42
|
import { startMCPServer } from "./mcp.js";
|
|
43
43
|
import { getCwd, setCwd, setOriginalCwd } from "../utils/state.js";
|
|
44
44
|
import { omit } from "lodash-es";
|
|
45
|
-
import { getCommands } from "../commands.js";
|
|
45
|
+
import { getBuiltInCommands, getCommands } from "../commands.js";
|
|
46
46
|
import { getNextAvailableLogForkNumber, loadLogList } from "../utils/log.js";
|
|
47
47
|
import { loadMessagesFromLog } from "../utils/conversationRecovery.js";
|
|
48
48
|
import { cleanupOldMessageFilesInBackground } from "../utils/cleanup.js";
|
|
@@ -74,8 +74,7 @@ import {
|
|
|
74
74
|
import { cursorShow } from "ansi-escapes";
|
|
75
75
|
import {
|
|
76
76
|
getLatestVersion,
|
|
77
|
-
assertMinVersion
|
|
78
|
-
getUpdateCommandSuggestions
|
|
77
|
+
assertMinVersion
|
|
79
78
|
} from "../utils/autoUpdater.js";
|
|
80
79
|
import { ensureConfigDirs } from "../utils/configPaths.js";
|
|
81
80
|
import { runStartupMigration } from "../utils/migration/index.js";
|
|
@@ -84,7 +83,6 @@ import {
|
|
|
84
83
|
setLanguage,
|
|
85
84
|
isLanguageSupported
|
|
86
85
|
} from "../i18n/index.js";
|
|
87
|
-
import { gt } from "semver";
|
|
88
86
|
import { CACHE_PATHS } from "../utils/log.js";
|
|
89
87
|
import { onShellCrash } from "../utils/PersistentShell.js";
|
|
90
88
|
import { clearTerminal, prepareTerminalForREPL } from "../utils/terminal.js";
|
|
@@ -94,6 +92,11 @@ import { ConfigParseError } from "../utils/errors.js";
|
|
|
94
92
|
import { grantReadPermissionForOriginalDir } from "../utils/permissions/filesystem.js";
|
|
95
93
|
import { MACRO } from "../constants/macros.js";
|
|
96
94
|
import { SEMANTIC_COLORS } from "../constants/colors.js";
|
|
95
|
+
import {
|
|
96
|
+
needsSync as needsCCSync,
|
|
97
|
+
syncFromClaudeCode,
|
|
98
|
+
hasClaudeCodeInstallation
|
|
99
|
+
} from "../utils/claudeCodeSync.js";
|
|
97
100
|
function completeOnboarding() {
|
|
98
101
|
const config = getGlobalConfig();
|
|
99
102
|
saveGlobalConfig({
|
|
@@ -226,6 +229,38 @@ async function setup(cwd2, safeMode) {
|
|
|
226
229
|
const projectConfig = getCurrentProjectConfig();
|
|
227
230
|
if (projectConfig.lastCost !== void 0 && projectConfig.lastDuration !== void 0) {
|
|
228
231
|
}
|
|
232
|
+
try {
|
|
233
|
+
const cfg = getGlobalConfig();
|
|
234
|
+
if (hasClaudeCodeInstallation() && needsCCSync()) {
|
|
235
|
+
const shouldSync = cfg.autoSyncClaudeCode === true || cfg.autoSyncClaudeCode === void 0;
|
|
236
|
+
if (shouldSync) {
|
|
237
|
+
syncFromClaudeCode().then((result) => {
|
|
238
|
+
const changed = result.installed.length + result.updated.length;
|
|
239
|
+
const mpRegistered = result.marketplaces.registered.length;
|
|
240
|
+
if (changed > 0 || mpRegistered > 0) {
|
|
241
|
+
const parts = [];
|
|
242
|
+
if (changed > 0) {
|
|
243
|
+
parts.push(
|
|
244
|
+
`${changed} plugin(s) (${result.installed.length} new, ${result.updated.length} updated)`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
if (mpRegistered > 0) {
|
|
248
|
+
parts.push(`${mpRegistered} marketplace(s)`);
|
|
249
|
+
}
|
|
250
|
+
console.log(`Synced from Claude Code: ${parts.join(", ")}`);
|
|
251
|
+
}
|
|
252
|
+
if (cfg.autoSyncClaudeCode === void 0) {
|
|
253
|
+
saveGlobalConfig({
|
|
254
|
+
...getGlobalConfig(),
|
|
255
|
+
autoSyncClaudeCode: true
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}).catch(() => {
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
} catch {
|
|
263
|
+
}
|
|
229
264
|
}
|
|
230
265
|
if (process.env.NODE_ENV !== "test") {
|
|
231
266
|
process.on("uncaughtException", (error) => {
|
|
@@ -350,7 +385,7 @@ async function parseArgs(stdinContent, renderContext, rawModeSupported) {
|
|
|
350
385
|
...renderContext,
|
|
351
386
|
exitOnCtrlC: true
|
|
352
387
|
};
|
|
353
|
-
const commands =
|
|
388
|
+
const commands = getBuiltInCommands();
|
|
354
389
|
const commandList = commands.filter((cmd) => !cmd.isHidden).map((cmd) => `/${cmd.name} - ${cmd.description}`).join("\n");
|
|
355
390
|
program.name(PRODUCT_COMMAND).description(
|
|
356
391
|
`${PRODUCT_NAME} - starts an interactive session by default, use -p/--print for non-interactive output
|
|
@@ -393,6 +428,10 @@ ${commandList}`
|
|
|
393
428
|
"-l, --lang <language>",
|
|
394
429
|
"Set interface language (en, zh-CN)",
|
|
395
430
|
String
|
|
431
|
+
).option(
|
|
432
|
+
"--plugin-dir <dir>",
|
|
433
|
+
"Additional plugin directory to scan (merged with defaults)",
|
|
434
|
+
String
|
|
396
435
|
).action(
|
|
397
436
|
async (prompt, {
|
|
398
437
|
cwd: cwd2,
|
|
@@ -405,23 +444,29 @@ ${commandList}`
|
|
|
405
444
|
strict,
|
|
406
445
|
new: startNew,
|
|
407
446
|
resume: selectResume,
|
|
408
|
-
lang
|
|
447
|
+
lang,
|
|
448
|
+
pluginDir
|
|
409
449
|
}) => {
|
|
410
450
|
if (lang && isLanguageSupported(lang)) {
|
|
411
451
|
setLanguage(lang);
|
|
412
452
|
}
|
|
453
|
+
if (pluginDir) {
|
|
454
|
+
const { addExtraPluginDir } = await import("../utils/pluginLoader.js");
|
|
455
|
+
addExtraPluginDir(pluginDir);
|
|
456
|
+
}
|
|
413
457
|
const envSafetyMode = process.env.MINTO_SAFETY_MODE;
|
|
414
458
|
const safetyMode = envSafetyMode ? envSafetyMode : strict ? "strict" : smart ? "smart" : free ? "free" : "yolo";
|
|
415
459
|
const safeMode = safetyMode !== "yolo";
|
|
460
|
+
const inkPromise = import("ink");
|
|
461
|
+
const replPromise = import("../screens/REPL.js");
|
|
416
462
|
await showSetupScreens(safeMode, print, rawModeSupported);
|
|
417
463
|
await setup(cwd2, safeMode);
|
|
418
464
|
assertMinVersion();
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
]);
|
|
465
|
+
const isDefaultModel = await isDefaultSlowAndCapableModel();
|
|
466
|
+
const tools = await getBuiltInTools(
|
|
467
|
+
enableArchitect ?? getCurrentProjectConfig().enableArchitectTool,
|
|
468
|
+
{ skipDescriptionCache: true }
|
|
469
|
+
);
|
|
425
470
|
const inputPrompt = [prompt, stdinContent].filter(Boolean).join("\n");
|
|
426
471
|
if (print) {
|
|
427
472
|
if (!inputPrompt) {
|
|
@@ -430,6 +475,9 @@ ${commandList}`
|
|
|
430
475
|
);
|
|
431
476
|
process.exit(1);
|
|
432
477
|
}
|
|
478
|
+
const fullTools = await getTools(
|
|
479
|
+
enableArchitect ?? getCurrentProjectConfig().enableArchitectTool
|
|
480
|
+
);
|
|
433
481
|
addToHistory(inputPrompt);
|
|
434
482
|
const { resultText: response } = await ask({
|
|
435
483
|
commands,
|
|
@@ -437,28 +485,13 @@ ${commandList}`
|
|
|
437
485
|
messageLogName: dateToFilename(/* @__PURE__ */ new Date()),
|
|
438
486
|
prompt: inputPrompt,
|
|
439
487
|
cwd: cwd2,
|
|
440
|
-
tools,
|
|
488
|
+
tools: fullTools,
|
|
441
489
|
safeMode,
|
|
442
490
|
safetyMode
|
|
443
491
|
});
|
|
444
492
|
console.log(response);
|
|
445
493
|
process.exit(0);
|
|
446
494
|
} else {
|
|
447
|
-
const isDefaultModel = await isDefaultSlowAndCapableModel();
|
|
448
|
-
const updateInfo = await (async () => {
|
|
449
|
-
try {
|
|
450
|
-
const latest = await getLatestVersion();
|
|
451
|
-
if (latest && gt(latest, MACRO.VERSION)) {
|
|
452
|
-
const cmds = await getUpdateCommandSuggestions();
|
|
453
|
-
return { version: latest, commands: cmds };
|
|
454
|
-
}
|
|
455
|
-
} catch {
|
|
456
|
-
}
|
|
457
|
-
return {
|
|
458
|
-
version: null,
|
|
459
|
-
commands: null
|
|
460
|
-
};
|
|
461
|
-
})();
|
|
462
495
|
if (renderContext?.fallbackMode) {
|
|
463
496
|
requireRawModeOrExit(process.stdin, true);
|
|
464
497
|
}
|
|
@@ -482,38 +515,11 @@ ${commandList}`
|
|
|
482
515
|
context2.unmount = unmount;
|
|
483
516
|
return;
|
|
484
517
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
let initialForkNumber;
|
|
488
|
-
if (!startNew && !inputPrompt) {
|
|
489
|
-
try {
|
|
490
|
-
const logs = await loadLogList(CACHE_PATHS.messages());
|
|
491
|
-
for (const log of logs) {
|
|
492
|
-
try {
|
|
493
|
-
const loadedMessages = await loadMessagesFromLog(
|
|
494
|
-
log.fullPath,
|
|
495
|
-
tools
|
|
496
|
-
);
|
|
497
|
-
if (loadedMessages && loadedMessages.length > 0) {
|
|
498
|
-
initialMessages = loadedMessages;
|
|
499
|
-
messageLogName = log.date;
|
|
500
|
-
initialForkNumber = getNextAvailableLogForkNumber(
|
|
501
|
-
log.date,
|
|
502
|
-
log.forkNumber ?? 1,
|
|
503
|
-
0
|
|
504
|
-
);
|
|
505
|
-
break;
|
|
506
|
-
}
|
|
507
|
-
} catch {
|
|
508
|
-
continue;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
} catch {
|
|
512
|
-
}
|
|
513
|
-
}
|
|
518
|
+
const messageLogName = dateToFilename(/* @__PURE__ */ new Date());
|
|
519
|
+
const shouldAutoResume = !startNew && !inputPrompt;
|
|
514
520
|
{
|
|
515
|
-
const { render } = await
|
|
516
|
-
const { REPL } = await
|
|
521
|
+
const { render } = await inkPromise;
|
|
522
|
+
const { REPL } = await replPromise;
|
|
517
523
|
await prepareTerminalForREPL();
|
|
518
524
|
render(
|
|
519
525
|
/* @__PURE__ */ React.createElement(
|
|
@@ -523,18 +529,18 @@ ${commandList}`
|
|
|
523
529
|
debug,
|
|
524
530
|
initialPrompt: inputPrompt,
|
|
525
531
|
messageLogName,
|
|
526
|
-
initialForkNumber,
|
|
527
|
-
initialMessages,
|
|
528
532
|
shouldShowPromptInput: true,
|
|
529
533
|
verbose,
|
|
530
534
|
tools,
|
|
531
535
|
safeMode,
|
|
532
536
|
safetyMode,
|
|
533
|
-
mcpClients,
|
|
537
|
+
mcpClients: [],
|
|
534
538
|
isDefaultModel,
|
|
535
|
-
initialUpdateVersion:
|
|
536
|
-
initialUpdateCommands:
|
|
537
|
-
|
|
539
|
+
initialUpdateVersion: null,
|
|
540
|
+
initialUpdateCommands: null,
|
|
541
|
+
enableArchitect: enableArchitect ?? getCurrentProjectConfig().enableArchitectTool,
|
|
542
|
+
fallbackMode: renderContext?.fallbackMode,
|
|
543
|
+
autoResume: shouldAutoResume
|
|
538
544
|
}
|
|
539
545
|
),
|
|
540
546
|
renderContext
|
|
@@ -860,8 +866,12 @@ Run "${PRODUCT_COMMAND}" to start using your configured setup.`
|
|
|
860
866
|
for (const [name, server] of Object.entries(servers)) {
|
|
861
867
|
if (server.type === "sse") {
|
|
862
868
|
console.log(`${name}: ${server.url} (SSE)`);
|
|
869
|
+
} else if (server.type === "http") {
|
|
870
|
+
console.log(`${name}: ${server.url} (HTTP)`);
|
|
863
871
|
} else {
|
|
864
|
-
console.log(
|
|
872
|
+
console.log(
|
|
873
|
+
`${name}: ${server.command} ${(server.args || []).join(" ")}`
|
|
874
|
+
);
|
|
865
875
|
}
|
|
866
876
|
}
|
|
867
877
|
}
|
|
@@ -920,10 +930,13 @@ Run "${PRODUCT_COMMAND}" to start using your configured setup.`
|
|
|
920
930
|
if (server.type === "sse") {
|
|
921
931
|
console.log(` Type: sse`);
|
|
922
932
|
console.log(` URL: ${server.url}`);
|
|
933
|
+
} else if (server.type === "http") {
|
|
934
|
+
console.log(` Type: http`);
|
|
935
|
+
console.log(` URL: ${server.url}`);
|
|
923
936
|
} else {
|
|
924
937
|
console.log(` Type: stdio`);
|
|
925
938
|
console.log(` Command: ${server.command}`);
|
|
926
|
-
console.log(` Args: ${server.args.join(" ")}`);
|
|
939
|
+
console.log(` Args: ${(server.args || []).join(" ")}`);
|
|
927
940
|
if (server.env) {
|
|
928
941
|
console.log(" Environment:");
|
|
929
942
|
for (const [key, value] of Object.entries(server.env)) {
|