@within-7/minto 0.2.0 → 0.3.3
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/commands/agents/AgentsCommand.js +22 -24
- package/dist/commands/agents/AgentsCommand.js.map +2 -2
- package/dist/commands/context.js +2 -1
- package/dist/commands/context.js.map +2 -2
- package/dist/commands/export.js +2 -1
- package/dist/commands/export.js.map +2 -2
- package/dist/commands/mcp-interactive.js +7 -6
- package/dist/commands/mcp-interactive.js.map +2 -2
- package/dist/commands/model.js +3 -2
- package/dist/commands/model.js.map +2 -2
- package/dist/commands/permissions.js +4 -3
- package/dist/commands/permissions.js.map +2 -2
- package/dist/commands/plugin/AddMarketplaceForm.js +3 -2
- package/dist/commands/plugin/AddMarketplaceForm.js.map +2 -2
- package/dist/commands/plugin/ConfirmDialog.js +2 -1
- package/dist/commands/plugin/ConfirmDialog.js.map +2 -2
- package/dist/commands/plugin/ErrorView.js +2 -1
- package/dist/commands/plugin/ErrorView.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js +5 -4
- package/dist/commands/plugin/InstalledPluginsByMarketplace.js.map +2 -2
- package/dist/commands/plugin/InstalledPluginsManager.js +5 -4
- package/dist/commands/plugin/InstalledPluginsManager.js.map +2 -2
- package/dist/commands/plugin/MainMenu.js +2 -1
- package/dist/commands/plugin/MainMenu.js.map +2 -2
- package/dist/commands/plugin/MarketplaceManager.js +5 -4
- package/dist/commands/plugin/MarketplaceManager.js.map +2 -2
- package/dist/commands/plugin/MarketplaceSelector.js +4 -3
- package/dist/commands/plugin/MarketplaceSelector.js.map +2 -2
- package/dist/commands/plugin/PlaceholderScreen.js +3 -2
- package/dist/commands/plugin/PlaceholderScreen.js.map +2 -2
- package/dist/commands/plugin/PluginBrowser.js +6 -5
- package/dist/commands/plugin/PluginBrowser.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsInstall.js +5 -4
- package/dist/commands/plugin/PluginDetailsInstall.js.map +2 -2
- package/dist/commands/plugin/PluginDetailsManage.js +4 -3
- package/dist/commands/plugin/PluginDetailsManage.js.map +2 -2
- package/dist/commands/plugin.js +16 -15
- package/dist/commands/plugin.js.map +2 -2
- package/dist/commands/sandbox.js +4 -3
- package/dist/commands/sandbox.js.map +2 -2
- package/dist/commands/setup.js +2 -1
- package/dist/commands/setup.js.map +2 -2
- package/dist/commands/status.js +2 -1
- package/dist/commands/status.js.map +2 -2
- package/dist/commands/undo.js +245 -0
- package/dist/commands/undo.js.map +7 -0
- package/dist/commands.js +2 -0
- package/dist/commands.js.map +2 -2
- package/dist/components/AgentThinkingBlock.js +1 -1
- package/dist/components/AgentThinkingBlock.js.map +2 -2
- package/dist/components/AsciiLogo.js +7 -8
- package/dist/components/AsciiLogo.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js +3 -2
- package/dist/components/AskUserQuestionDialog/AskUserQuestionDialog.js.map +2 -2
- package/dist/components/AskUserQuestionDialog/QuestionView.js +2 -1
- package/dist/components/AskUserQuestionDialog/QuestionView.js.map +2 -2
- package/dist/components/CollapsibleHint.js +2 -1
- package/dist/components/CollapsibleHint.js.map +2 -2
- package/dist/components/Config.js +3 -2
- package/dist/components/Config.js.map +2 -2
- package/dist/components/ConsoleOAuthFlow.js +2 -1
- package/dist/components/ConsoleOAuthFlow.js.map +2 -2
- package/dist/components/Cost.js +2 -1
- package/dist/components/Cost.js.map +2 -2
- package/dist/components/HeaderBar.js +13 -8
- package/dist/components/HeaderBar.js.map +2 -2
- package/dist/components/HistorySearchOverlay.js +4 -3
- package/dist/components/HistorySearchOverlay.js.map +2 -2
- package/dist/components/HotkeyHelpPanel.js +8 -11
- package/dist/components/HotkeyHelpPanel.js.map +2 -2
- package/dist/components/InvalidConfigDialog.js +2 -1
- package/dist/components/InvalidConfigDialog.js.map +2 -2
- package/dist/components/Logo.js +23 -67
- package/dist/components/Logo.js.map +2 -2
- package/dist/components/MCPServerApprovalDialog.js +2 -1
- package/dist/components/MCPServerApprovalDialog.js.map +2 -2
- package/dist/components/MCPServerDialogCopy.js +2 -1
- package/dist/components/MCPServerDialogCopy.js.map +2 -2
- package/dist/components/MCPServerMultiselectDialog.js +2 -1
- package/dist/components/MCPServerMultiselectDialog.js.map +2 -2
- package/dist/components/MessageSelector.js +4 -3
- package/dist/components/MessageSelector.js.map +2 -2
- package/dist/components/ModeIndicator.js +2 -1
- package/dist/components/ModeIndicator.js.map +2 -2
- package/dist/components/ModelConfig.js +4 -3
- package/dist/components/ModelConfig.js.map +2 -2
- package/dist/components/ModelListManager.js +4 -3
- package/dist/components/ModelListManager.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +26 -13
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/Onboarding.js +3 -2
- package/dist/components/Onboarding.js.map +2 -2
- package/dist/components/OperationSummary.js +130 -0
- package/dist/components/OperationSummary.js.map +7 -0
- package/dist/components/PromptInput.js +88 -75
- package/dist/components/PromptInput.js.map +2 -2
- package/dist/components/SensitiveFileWarning.js +31 -0
- package/dist/components/SensitiveFileWarning.js.map +7 -0
- package/dist/components/Spinner.js +71 -22
- package/dist/components/Spinner.js.map +2 -2
- package/dist/components/StructuredDiff.js +6 -8
- package/dist/components/StructuredDiff.js.map +2 -2
- package/dist/components/SubagentBlock.js +4 -2
- package/dist/components/SubagentBlock.js.map +2 -2
- package/dist/components/SubagentProgress.js +17 -6
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/components/TaskCard.js +14 -11
- package/dist/components/TaskCard.js.map +2 -2
- package/dist/components/TextInput.js +9 -1
- package/dist/components/TextInput.js.map +2 -2
- package/dist/components/TodoPanel.js +44 -26
- package/dist/components/TodoPanel.js.map +2 -2
- package/dist/components/ToolUseLoader.js +2 -2
- package/dist/components/ToolUseLoader.js.map +2 -2
- package/dist/components/TreeConnector.js +4 -3
- package/dist/components/TreeConnector.js.map +2 -2
- package/dist/components/TrustDialog.js +2 -1
- package/dist/components/TrustDialog.js.map +2 -2
- package/dist/components/binary-feedback/BinaryFeedbackView.js +2 -1
- package/dist/components/binary-feedback/BinaryFeedbackView.js.map +2 -2
- package/dist/components/messages/AssistantTextMessage.js +17 -9
- package/dist/components/messages/AssistantTextMessage.js.map +2 -2
- package/dist/components/messages/AssistantToolUseMessage.js +8 -4
- package/dist/components/messages/AssistantToolUseMessage.js.map +2 -2
- package/dist/components/messages/GroupRenderer.js +2 -1
- package/dist/components/messages/GroupRenderer.js.map +2 -2
- package/dist/components/messages/NestedTasksPreview.js +13 -1
- package/dist/components/messages/NestedTasksPreview.js.map +2 -2
- package/dist/components/messages/ParallelTasksGroupView.js +4 -3
- package/dist/components/messages/ParallelTasksGroupView.js.map +2 -2
- package/dist/components/messages/TaskInModuleView.js +35 -15
- package/dist/components/messages/TaskInModuleView.js.map +2 -2
- package/dist/components/messages/TaskOutputContent.js +9 -6
- package/dist/components/messages/TaskOutputContent.js.map +2 -2
- package/dist/components/messages/UserPromptMessage.js +2 -2
- package/dist/components/messages/UserPromptMessage.js.map +2 -2
- package/dist/constants/colors.js +90 -72
- package/dist/constants/colors.js.map +2 -2
- package/dist/constants/prompts.js +22 -1
- package/dist/constants/prompts.js.map +2 -2
- package/dist/constants/toolInputExamples.js +84 -0
- package/dist/constants/toolInputExamples.js.map +7 -0
- package/dist/core/backupManager.js +321 -0
- package/dist/core/backupManager.js.map +7 -0
- package/dist/core/costTracker.js +9 -18
- package/dist/core/costTracker.js.map +2 -2
- package/dist/core/gitAutoCommit.js +287 -0
- package/dist/core/gitAutoCommit.js.map +7 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +2 -2
- package/dist/core/operationTracker.js +212 -0
- package/dist/core/operationTracker.js.map +7 -0
- package/dist/core/permissions/rules/allowedToolsRule.js +1 -1
- package/dist/core/permissions/rules/allowedToolsRule.js.map +2 -2
- package/dist/core/permissions/rules/autoEscalationRule.js +5 -0
- package/dist/core/permissions/rules/autoEscalationRule.js.map +2 -2
- package/dist/core/permissions/rules/projectBoundaryRule.js +5 -0
- package/dist/core/permissions/rules/projectBoundaryRule.js.map +2 -2
- package/dist/core/permissions/rules/sensitivePathsRule.js +5 -0
- package/dist/core/permissions/rules/sensitivePathsRule.js.map +2 -2
- package/dist/core/tokenStats.js +9 -0
- package/dist/core/tokenStats.js.map +7 -0
- package/dist/core/tokenStatsManager.js +331 -0
- package/dist/core/tokenStatsManager.js.map +7 -0
- package/dist/entrypoints/cli.js +122 -88
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/hooks/useAgentTokenStats.js +72 -0
- package/dist/hooks/useAgentTokenStats.js.map +7 -0
- package/dist/hooks/useAgentTranscripts.js +30 -6
- package/dist/hooks/useAgentTranscripts.js.map +2 -2
- package/dist/hooks/useLogMessages.js +12 -1
- package/dist/hooks/useLogMessages.js.map +2 -2
- package/dist/i18n/locales/en.js +6 -5
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +6 -5
- package/dist/i18n/locales/zh-CN.js.map +2 -2
- package/dist/i18n/types.js.map +1 -1
- package/dist/permissions.js +147 -1
- package/dist/permissions.js.map +2 -2
- package/dist/query.js +78 -4
- package/dist/query.js.map +3 -3
- package/dist/screens/REPL.js +23 -3
- package/dist/screens/REPL.js.map +2 -2
- package/dist/screens/ResumeConversation.js +2 -0
- package/dist/screens/ResumeConversation.js.map +2 -2
- package/dist/services/claude.js +54 -3
- package/dist/services/claude.js.map +2 -2
- package/dist/services/intelligentCompactor.js +1 -1
- package/dist/services/intelligentCompactor.js.map +2 -2
- package/dist/services/mcpClient.js +81 -25
- package/dist/services/mcpClient.js.map +2 -2
- package/dist/services/sandbox/filesystemBoundary.js +58 -17
- package/dist/services/sandbox/filesystemBoundary.js.map +2 -2
- package/dist/services/taskStore.js +205 -0
- package/dist/services/taskStore.js.map +7 -0
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js +3 -2
- package/dist/tools/AskExpertModelTool/AskExpertModelTool.js.map +2 -2
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +42 -4
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +43 -7
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +184 -34
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +24 -9
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileEditTool/prompt.js +10 -4
- package/dist/tools/FileEditTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/utils.js +10 -4
- package/dist/tools/FileEditTool/utils.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js +1 -1
- package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
- package/dist/tools/FileReadTool/prompt.js +16 -1
- package/dist/tools/FileReadTool/prompt.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +1 -1
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +1 -1
- package/dist/tools/FileWriteTool/prompt.js +12 -3
- package/dist/tools/FileWriteTool/prompt.js.map +2 -2
- package/dist/tools/GlobTool/prompt.js +12 -1
- package/dist/tools/GlobTool/prompt.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +333 -65
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/GrepTool/prompt.js +15 -8
- package/dist/tools/GrepTool/prompt.js.map +2 -2
- package/dist/tools/MultiEditTool/prompt.js +5 -3
- package/dist/tools/MultiEditTool/prompt.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +59 -46
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/prompt.js +1 -1
- package/dist/tools/NotebookEditTool/prompt.js.map +1 -1
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js +3 -2
- package/dist/tools/PlanModeTool/EnterPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js +3 -2
- package/dist/tools/PlanModeTool/ExitPlanModeTool.js.map +2 -2
- package/dist/tools/PlanModeTool/prompt.js +1 -1
- package/dist/tools/PlanModeTool/prompt.js.map +1 -1
- package/dist/tools/SkillTool/SkillTool.js +4 -3
- package/dist/tools/SkillTool/SkillTool.js.map +2 -2
- package/dist/tools/SkillTool/prompt.js +1 -1
- package/dist/tools/SkillTool/prompt.js.map +1 -1
- package/dist/tools/TaskCreateTool/TaskCreateTool.js +102 -0
- package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +7 -0
- package/dist/tools/TaskCreateTool/prompt.js +47 -0
- package/dist/tools/TaskCreateTool/prompt.js.map +7 -0
- package/dist/tools/TaskGetTool/TaskGetTool.js +115 -0
- package/dist/tools/TaskGetTool/TaskGetTool.js.map +7 -0
- package/dist/tools/TaskGetTool/prompt.js +28 -0
- package/dist/tools/TaskGetTool/prompt.js.map +7 -0
- package/dist/tools/TaskListTool/TaskListTool.js +102 -0
- package/dist/tools/TaskListTool/TaskListTool.js.map +7 -0
- package/dist/tools/TaskListTool/prompt.js +27 -0
- package/dist/tools/TaskListTool/prompt.js.map +7 -0
- package/dist/tools/TaskOutputTool/TaskOutputTool.js +3 -2
- package/dist/tools/TaskOutputTool/TaskOutputTool.js.map +2 -2
- package/dist/tools/TaskStopTool/TaskStopTool.js +150 -0
- package/dist/tools/TaskStopTool/TaskStopTool.js.map +7 -0
- package/dist/tools/TaskStopTool/prompt.js +15 -0
- package/dist/tools/TaskStopTool/prompt.js.map +7 -0
- package/dist/tools/TaskTool/TaskTool.js +49 -1
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +134 -0
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +7 -0
- package/dist/tools/TaskUpdateTool/prompt.js +81 -0
- package/dist/tools/TaskUpdateTool/prompt.js.map +7 -0
- package/dist/tools/URLFetcherTool/prompt.js +1 -1
- package/dist/tools/URLFetcherTool/prompt.js.map +1 -1
- package/dist/tools.js +12 -0
- package/dist/tools.js.map +2 -2
- package/dist/utils/CircuitBreaker.js +242 -0
- package/dist/utils/CircuitBreaker.js.map +7 -0
- package/dist/utils/ask.js +2 -0
- package/dist/utils/ask.js.map +2 -2
- package/dist/utils/config.js +47 -5
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/credentials/CredentialStore.js +1 -0
- package/dist/utils/credentials/CredentialStore.js.map +7 -0
- package/dist/utils/credentials/EncryptedFileStore.js +157 -0
- package/dist/utils/credentials/EncryptedFileStore.js.map +7 -0
- package/dist/utils/credentials/index.js +37 -0
- package/dist/utils/credentials/index.js.map +7 -0
- package/dist/utils/credentials/migration.js +82 -0
- package/dist/utils/credentials/migration.js.map +7 -0
- package/dist/utils/markdown.js +13 -1
- package/dist/utils/markdown.js.map +2 -2
- package/dist/utils/model.js +15 -2
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/permissions/filesystem.js +5 -1
- package/dist/utils/permissions/filesystem.js.map +2 -2
- package/dist/utils/ripgrep.js +53 -1
- package/dist/utils/ripgrep.js.map +2 -2
- package/dist/utils/safePath.js +132 -0
- package/dist/utils/safePath.js.map +7 -0
- package/dist/utils/sensitiveFiles.js +125 -0
- package/dist/utils/sensitiveFiles.js.map +7 -0
- package/dist/utils/taskDisplayUtils.js +9 -9
- package/dist/utils/taskDisplayUtils.js.map +2 -2
- package/dist/utils/terminal.js +12 -0
- package/dist/utils/terminal.js.map +2 -2
- package/dist/utils/theme.js +6 -6
- package/dist/utils/theme.js.map +1 -1
- package/dist/utils/toolRiskClassification.js +207 -0
- package/dist/utils/toolRiskClassification.js.map +7 -0
- package/dist/utils/tooling/safeRender.js +17 -17
- package/dist/utils/tooling/safeRender.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +22 -28
- package/dist/hooks/useCancelRequest.js +0 -31
- package/dist/hooks/useCancelRequest.js.map +0 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/costTracker.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Cost Tracker\n *\n * Tracks API costs and usage metrics for the session.\n * This is the core implementation; the original cost-tracker.ts\n * re-exports from this module for backwards compatibility.\n */\n\nimport chalk from 'chalk'\nimport { useEffect } from 'react'\nimport signalExit from 'signal-exit'\nimport { formatDuration } from '../utils/format'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n} from '../utils/config'\nimport { SESSION_ID } from '../utils/log'\n\n/**\n * Cost tracking state\n */\ninterface CostState {\n /** Total cost in dollars */\n totalCost: number\n\n /** Total API call duration in milliseconds */\n totalAPIDuration: number\n\n /** Session start timestamp */\n startTime: number\n\n /**
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * Cost Tracker\n *\n * Tracks API costs and usage metrics for the session.\n * This is the core implementation; the original cost-tracker.ts\n * re-exports from this module for backwards compatibility.\n *\n * NOTE: Token statistics are now managed by TokenStatsManager.\n * This module delegates getTokenCounts() to the unified manager.\n */\n\nimport chalk from 'chalk'\nimport { useEffect } from 'react'\nimport signalExit from 'signal-exit'\nimport { formatDuration } from '../utils/format'\nimport {\n getCurrentProjectConfig,\n saveCurrentProjectConfig,\n} from '../utils/config'\nimport { SESSION_ID } from '../utils/log'\nimport { tokenStatsManager } from './tokenStatsManager'\n\n/**\n * Cost tracking state\n *\n * NOTE: Token statistics are now managed by TokenStatsManager.\n * This state only tracks cost, duration, and request count.\n */\ninterface CostState {\n /** Total cost in dollars */\n totalCost: number\n\n /** Total API call duration in milliseconds */\n totalAPIDuration: number\n\n /** Session start timestamp */\n startTime: number\n\n /** Request count */\n requestCount: number\n}\n\n// Global state (token tracking delegated to TokenStatsManager)\nconst STATE: CostState = {\n totalCost: 0,\n totalAPIDuration: 0,\n startTime: Date.now(),\n requestCount: 0,\n}\n\n/**\n * Add to total cost\n */\nexport function addToTotalCost(cost: number, duration: number): void {\n STATE.totalCost += cost\n STATE.totalAPIDuration += duration\n STATE.requestCount += 1\n}\n\n/**\n * Add token usage\n *\n * @deprecated Use tokenStatsManager.recordUsage() instead.\n * This function is kept for backward compatibility but no longer updates\n * the global token statistics. Token tracking is now handled by TokenStatsManager.\n */\nexport function addTokenUsage(\n _inputTokens: number,\n _outputTokens: number,\n _cacheCreationTokens?: number,\n _cacheReadTokens?: number,\n): void {\n // DEPRECATED: This function is a no-op.\n // Token tracking is now handled by TokenStatsManager in claude.ts via recordTokenUsage().\n}\n\n/**\n * Get total cost\n */\nexport function getTotalCost(): number {\n return STATE.totalCost\n}\n\n/**\n * Get total duration (wall clock time)\n */\nexport function getTotalDuration(): number {\n return Date.now() - STATE.startTime\n}\n\n/**\n * Get total API duration\n */\nexport function getTotalAPIDuration(): number {\n return STATE.totalAPIDuration\n}\n\n/**\n * Get token counts\n *\n * Delegates to TokenStatsManager for unified token statistics.\n */\nexport function getTokenCounts(): {\n input: number\n output: number\n cacheCreation: number\n cacheRead: number\n total: number\n} {\n // Delegate to TokenStatsManager (single source of truth)\n const globalStats = tokenStatsManager.getGlobalStats()\n return {\n input: globalStats.totalInputTokens,\n output: globalStats.totalOutputTokens,\n cacheCreation: globalStats.totalCacheCreationTokens,\n cacheRead: globalStats.totalCacheReadTokens,\n total: globalStats.grandTotalTokens,\n }\n}\n\n/**\n * Get request count\n */\nexport function getRequestCount(): number {\n return STATE.requestCount\n}\n\n/**\n * Get full cost summary\n */\nexport function getCostSummary(): {\n cost: number\n apiDuration: number\n wallDuration: number\n tokens: ReturnType<typeof getTokenCounts>\n requests: number\n} {\n return {\n cost: STATE.totalCost,\n apiDuration: STATE.totalAPIDuration,\n wallDuration: getTotalDuration(),\n tokens: getTokenCounts(),\n requests: STATE.requestCount,\n }\n}\n\n/**\n * Format cost for display\n */\nfunction formatCost(cost: number): string {\n return `$${cost > 0.5 ? round(cost, 100).toFixed(2) : cost.toFixed(4)}`\n}\n\n/**\n * Round to precision\n */\nfunction round(number: number, precision: number): number {\n return Math.round(number * precision) / precision\n}\n\n/**\n * Format total cost for display\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 * Format detailed cost summary\n */\nexport function formatDetailedCost(): string {\n const tokens = getTokenCounts()\n return chalk.grey(\n `Total cost: ${formatCost(STATE.totalCost)}\nTotal duration (API): ${formatDuration(STATE.totalAPIDuration)}\nTotal duration (wall): ${formatDuration(getTotalDuration())}\nTokens: ${tokens.input.toLocaleString()} in / ${tokens.output.toLocaleString()} out\nCache: ${tokens.cacheCreation.toLocaleString()} created / ${tokens.cacheRead.toLocaleString()} read\nRequests: ${STATE.requestCount}`,\n )\n}\n\n// Flag to ensure we only register once and never unregister\nlet exitHandlerRegistered = false\n\n/**\n * React hook for cost summary on exit\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 */\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 signalExit(\n () => {\n // Write statistics to stdout\n process.stdout.write('\\n' + formatTotalCost() + '\\n')\n\n // Save last cost and duration to project config\n try {\n const projectConfig = getCurrentProjectConfig()\n saveCurrentProjectConfig({\n ...projectConfig,\n lastCost: STATE.totalCost,\n lastAPIDuration: STATE.totalAPIDuration,\n lastDuration: getTotalDuration(),\n lastSessionId: SESSION_ID,\n })\n } catch {\n // Ignore errors during exit - config save is best-effort\n }\n },\n { alwaysLast: true },\n )\n\n // NO cleanup - never unregister the exit handler\n }, [])\n}\n\n/**\n * Reset state (for testing only)\n */\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 STATE.requestCount = 0\n // Token stats are managed by TokenStatsManager - reset there if needed\n tokenStatsManager.reset()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { minimatch } from "minimatch";
|
|
2
|
+
import { getIsGit } from "../utils/git.js";
|
|
3
|
+
import { execFileNoThrow } from "../utils/execFileNoThrow.js";
|
|
4
|
+
import { getCwd } from "../utils/state.js";
|
|
5
|
+
import { operationTracker } from "./operationTracker.js";
|
|
6
|
+
const DEFAULT_GIT_CONFIG = {
|
|
7
|
+
enabled: false,
|
|
8
|
+
// Default OFF, user must enable
|
|
9
|
+
commitAfterTask: true,
|
|
10
|
+
excludePatterns: ["*.log", "node_modules/**", "dist/**", ".minto/**"],
|
|
11
|
+
commitMessagePrefix: "chore(minto): "
|
|
12
|
+
};
|
|
13
|
+
async function shouldAutoCommit(config) {
|
|
14
|
+
if (!config.enabled) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
const isGitRepo = await getIsGit();
|
|
18
|
+
if (!isGitRepo) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
const changes = await getChangedFiles();
|
|
22
|
+
if (changes.length === 0) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const filesToCommit = filterExcludedFiles(changes, config.excludePatterns);
|
|
26
|
+
return filesToCommit.length > 0;
|
|
27
|
+
}
|
|
28
|
+
async function performAutoCommit(config, description) {
|
|
29
|
+
const isGitRepo = await getIsGit();
|
|
30
|
+
if (!isGitRepo) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
message: "Not a git repository"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const allChanges = await getChangedFiles();
|
|
37
|
+
if (allChanges.length === 0) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
message: "No changes to commit"
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const filesToCommit = filterExcludedFiles(allChanges, config.excludePatterns);
|
|
44
|
+
if (filesToCommit.length === 0) {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
message: "All changed files are excluded by patterns"
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const summary = await getChangeSummary(filesToCommit);
|
|
51
|
+
const stageResult = await stageFiles(filesToCommit.map((f) => f.path));
|
|
52
|
+
if (!stageResult.success) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
message: `Failed to stage files: ${stageResult.error}`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const commitMessage = generateCommitMessage(config, summary, description);
|
|
59
|
+
const commitResult = await createCommit(commitMessage);
|
|
60
|
+
if (!commitResult.success) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
message: `Failed to create commit: ${commitResult.error}`
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
success: true,
|
|
68
|
+
message: `Committed ${filesToCommit.length} file(s)`,
|
|
69
|
+
commitHash: commitResult.hash,
|
|
70
|
+
filesCommitted: filesToCommit.map((f) => f.path)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function generateCommitMessage(config, summary, description) {
|
|
74
|
+
const sanitizedDesc = description.trim().slice(0, 72);
|
|
75
|
+
const title = `${config.commitMessagePrefix}${sanitizedDesc}`;
|
|
76
|
+
const fileCount = summary.files.length;
|
|
77
|
+
const fileLines = summary.files.slice(0, 10).map((file) => {
|
|
78
|
+
const statusPrefix = getStatusLabel(file.status);
|
|
79
|
+
if (file.linesAdded !== void 0 || file.linesRemoved !== void 0) {
|
|
80
|
+
const added = file.linesAdded ?? 0;
|
|
81
|
+
const removed = file.linesRemoved ?? 0;
|
|
82
|
+
return `- ${file.path} (${statusPrefix}, +${added} -${removed})`;
|
|
83
|
+
}
|
|
84
|
+
return `- ${file.path} (${statusPrefix})`;
|
|
85
|
+
});
|
|
86
|
+
if (summary.files.length > 10) {
|
|
87
|
+
fileLines.push(`- ... and ${summary.files.length - 10} more file(s)`);
|
|
88
|
+
}
|
|
89
|
+
const lines = [
|
|
90
|
+
title,
|
|
91
|
+
"",
|
|
92
|
+
`Modified ${fileCount} file(s):`,
|
|
93
|
+
...fileLines,
|
|
94
|
+
"",
|
|
95
|
+
"\u{1F916} Auto-committed by Minto"
|
|
96
|
+
];
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
async function getChangedFiles() {
|
|
100
|
+
const { stdout, code } = await execFileNoThrow(
|
|
101
|
+
"git",
|
|
102
|
+
["status", "--porcelain", "-u"],
|
|
103
|
+
void 0,
|
|
104
|
+
void 0,
|
|
105
|
+
true
|
|
106
|
+
);
|
|
107
|
+
if (code !== 0) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
const files = [];
|
|
111
|
+
for (const line of stdout.split("\n")) {
|
|
112
|
+
if (!line.trim()) continue;
|
|
113
|
+
const status = line.substring(0, 2).trim();
|
|
114
|
+
const path = line.substring(3).trim();
|
|
115
|
+
if (!path) continue;
|
|
116
|
+
const normalizedStatus = normalizeStatus(status);
|
|
117
|
+
if (normalizedStatus) {
|
|
118
|
+
files.push({
|
|
119
|
+
path,
|
|
120
|
+
status: normalizedStatus
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return files;
|
|
125
|
+
}
|
|
126
|
+
async function getChangeSummary(files) {
|
|
127
|
+
let totalAdded = 0;
|
|
128
|
+
let totalRemoved = 0;
|
|
129
|
+
const trackedFiles = files.filter((f) => f.status !== "?");
|
|
130
|
+
if (trackedFiles.length > 0) {
|
|
131
|
+
const { stdout, code } = await execFileNoThrow(
|
|
132
|
+
"git",
|
|
133
|
+
["diff", "--numstat", "HEAD", "--", ...trackedFiles.map((f) => f.path)],
|
|
134
|
+
void 0,
|
|
135
|
+
void 0,
|
|
136
|
+
true
|
|
137
|
+
);
|
|
138
|
+
if (code === 0) {
|
|
139
|
+
for (const line of stdout.split("\n")) {
|
|
140
|
+
if (!line.trim()) continue;
|
|
141
|
+
const parts = line.split(" ");
|
|
142
|
+
if (parts.length >= 3) {
|
|
143
|
+
const added = parseInt(parts[0], 10) || 0;
|
|
144
|
+
const removed = parseInt(parts[1], 10) || 0;
|
|
145
|
+
const path = parts[2];
|
|
146
|
+
const file = files.find((f) => f.path === path);
|
|
147
|
+
if (file) {
|
|
148
|
+
file.linesAdded = added;
|
|
149
|
+
file.linesRemoved = removed;
|
|
150
|
+
}
|
|
151
|
+
totalAdded += added;
|
|
152
|
+
totalRemoved += removed;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const untrackedFiles = files.filter((f) => f.status === "?");
|
|
158
|
+
for (const file of untrackedFiles) {
|
|
159
|
+
const { stdout, code } = await execFileNoThrow(
|
|
160
|
+
"wc",
|
|
161
|
+
["-l", file.path],
|
|
162
|
+
void 0,
|
|
163
|
+
void 0,
|
|
164
|
+
true
|
|
165
|
+
);
|
|
166
|
+
if (code === 0) {
|
|
167
|
+
const lineCount = parseInt(stdout.trim().split(/\s+/)[0], 10) || 0;
|
|
168
|
+
file.linesAdded = lineCount;
|
|
169
|
+
file.linesRemoved = 0;
|
|
170
|
+
totalAdded += lineCount;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
files,
|
|
175
|
+
totalAdded,
|
|
176
|
+
totalRemoved
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function filterExcludedFiles(files, excludePatterns) {
|
|
180
|
+
return files.filter((file) => {
|
|
181
|
+
for (const pattern of excludePatterns) {
|
|
182
|
+
if (minimatch(file.path, pattern, { dot: true })) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async function stageFiles(paths) {
|
|
190
|
+
if (paths.length === 0) {
|
|
191
|
+
return { success: true };
|
|
192
|
+
}
|
|
193
|
+
const { code, stderr } = await execFileNoThrow(
|
|
194
|
+
"git",
|
|
195
|
+
["add", "--", ...paths],
|
|
196
|
+
void 0,
|
|
197
|
+
void 0,
|
|
198
|
+
true
|
|
199
|
+
);
|
|
200
|
+
if (code !== 0) {
|
|
201
|
+
return { success: false, error: stderr || "Unknown error" };
|
|
202
|
+
}
|
|
203
|
+
return { success: true };
|
|
204
|
+
}
|
|
205
|
+
async function createCommit(message) {
|
|
206
|
+
const { code, stdout, stderr } = await execFileNoThrow(
|
|
207
|
+
"git",
|
|
208
|
+
["commit", "-m", message],
|
|
209
|
+
void 0,
|
|
210
|
+
void 0,
|
|
211
|
+
true
|
|
212
|
+
);
|
|
213
|
+
if (code !== 0) {
|
|
214
|
+
return { success: false, error: stderr || "Unknown error" };
|
|
215
|
+
}
|
|
216
|
+
const match = stdout.match(/\[[\w/-]+ ([a-f0-9]+)\]/);
|
|
217
|
+
const hash = match ? match[1] : void 0;
|
|
218
|
+
return { success: true, hash };
|
|
219
|
+
}
|
|
220
|
+
function normalizeStatus(status) {
|
|
221
|
+
if (status.includes("?")) return "?";
|
|
222
|
+
if (status.includes("A")) return "A";
|
|
223
|
+
if (status.includes("D")) return "D";
|
|
224
|
+
if (status.includes("R")) return "R";
|
|
225
|
+
if (status.includes("C")) return "C";
|
|
226
|
+
if (status.includes("U")) return "U";
|
|
227
|
+
if (status.includes("M") || status.includes(" M")) return "M";
|
|
228
|
+
if (status.trim()) return "M";
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
function getStatusLabel(status) {
|
|
232
|
+
switch (status) {
|
|
233
|
+
case "M":
|
|
234
|
+
return "modified";
|
|
235
|
+
case "A":
|
|
236
|
+
return "new";
|
|
237
|
+
case "D":
|
|
238
|
+
return "deleted";
|
|
239
|
+
case "?":
|
|
240
|
+
return "new";
|
|
241
|
+
case "R":
|
|
242
|
+
return "renamed";
|
|
243
|
+
case "C":
|
|
244
|
+
return "copied";
|
|
245
|
+
case "U":
|
|
246
|
+
return "unmerged";
|
|
247
|
+
default:
|
|
248
|
+
return "changed";
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function getTrackedOperations() {
|
|
252
|
+
return operationTracker.getSummary();
|
|
253
|
+
}
|
|
254
|
+
function hasTrackedFileChanges() {
|
|
255
|
+
const summary = operationTracker.getSummary();
|
|
256
|
+
return summary.filesModified.length > 0 || summary.filesCreated.length > 0;
|
|
257
|
+
}
|
|
258
|
+
function enhanceWithTrackerData(files, trackerSummary) {
|
|
259
|
+
const modifiedMap = /* @__PURE__ */ new Map();
|
|
260
|
+
for (const mod of trackerSummary.filesModified) {
|
|
261
|
+
modifiedMap.set(mod.path, { added: mod.added, removed: mod.removed });
|
|
262
|
+
}
|
|
263
|
+
return files.map((file) => {
|
|
264
|
+
const tracked = modifiedMap.get(file.path);
|
|
265
|
+
if (tracked) {
|
|
266
|
+
return {
|
|
267
|
+
...file,
|
|
268
|
+
linesAdded: file.linesAdded ?? tracked.added,
|
|
269
|
+
linesRemoved: file.linesRemoved ?? tracked.removed
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
return file;
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
export {
|
|
276
|
+
DEFAULT_GIT_CONFIG,
|
|
277
|
+
enhanceWithTrackerData,
|
|
278
|
+
filterExcludedFiles,
|
|
279
|
+
generateCommitMessage,
|
|
280
|
+
getChangedFiles,
|
|
281
|
+
getCwd,
|
|
282
|
+
getTrackedOperations,
|
|
283
|
+
hasTrackedFileChanges,
|
|
284
|
+
performAutoCommit,
|
|
285
|
+
shouldAutoCommit
|
|
286
|
+
};
|
|
287
|
+
//# sourceMappingURL=gitAutoCommit.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/gitAutoCommit.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Git Auto-Commit System\n *\n * Provides automatic git commits after task completion.\n * Part of the \"\u96F6\u6210\u672C\u5F00\u7BB1\u5373\u7528\" (zero-cost out-of-box) optimization.\n *\n * Default: OFF - User must explicitly enable auto-commit.\n */\n\nimport { minimatch } from 'minimatch'\nimport { getIsGit } from '../utils/git'\nimport { execFileNoThrow } from '../utils/execFileNoThrow'\nimport { getCwd } from '../utils/state'\nimport { operationTracker, type OperationSummary } from './operationTracker'\n\n// ============================================================================\n// Types & Configuration\n// ============================================================================\n\n/**\n * Configuration for git auto-commit behavior\n */\nexport interface GitAutoCommitConfig {\n /** Whether auto-commit is enabled (default: false) */\n enabled: boolean\n\n /** Whether to commit after task completion (default: true) */\n commitAfterTask: boolean\n\n /** Glob patterns for files to exclude from auto-commit */\n excludePatterns: string[]\n\n /** Prefix for auto-generated commit messages */\n commitMessagePrefix: string\n}\n\n/**\n * Default configuration - auto-commit is OFF by default\n */\nexport const DEFAULT_GIT_CONFIG: GitAutoCommitConfig = {\n enabled: false, // Default OFF, user must enable\n commitAfterTask: true,\n excludePatterns: ['*.log', 'node_modules/**', 'dist/**', '.minto/**'],\n commitMessagePrefix: 'chore(minto): ',\n}\n\n/**\n * Result of an auto-commit operation\n */\nexport interface AutoCommitResult {\n success: boolean\n message: string\n commitHash?: string\n filesCommitted?: string[]\n}\n\n/**\n * Information about a changed file\n */\nexport interface ChangedFile {\n /** File path relative to repo root */\n path: string\n\n /** Change status: 'M' (modified), 'A' (added), 'D' (deleted), '?' (untracked) */\n status: 'M' | 'A' | 'D' | '?' | 'R' | 'C' | 'U'\n\n /** Number of lines added (for modified/added files) */\n linesAdded?: number\n\n /** Number of lines removed (for modified/deleted files) */\n linesRemoved?: number\n}\n\n/**\n * Summary of file changes for commit message generation\n */\nexport interface ChangeSummary {\n files: ChangedFile[]\n totalAdded: number\n totalRemoved: number\n}\n\n// ============================================================================\n// Core Functions\n// ============================================================================\n\n/**\n * Check if auto-commit should be performed\n *\n * @param config - Git auto-commit configuration\n * @returns true if auto-commit should proceed\n */\nexport async function shouldAutoCommit(\n config: GitAutoCommitConfig,\n): Promise<boolean> {\n // Check if auto-commit is enabled\n if (!config.enabled) {\n return false\n }\n\n // Check if we're in a git repository\n const isGitRepo = await getIsGit()\n if (!isGitRepo) {\n return false\n }\n\n // Check if there are changes to commit\n const changes = await getChangedFiles()\n if (changes.length === 0) {\n return false\n }\n\n // Filter out excluded files\n const filesToCommit = filterExcludedFiles(changes, config.excludePatterns)\n return filesToCommit.length > 0\n}\n\n/**\n * Perform an auto-commit with the given description\n *\n * @param config - Git auto-commit configuration\n * @param description - Short description of the changes\n * @returns Result of the commit operation\n */\nexport async function performAutoCommit(\n config: GitAutoCommitConfig,\n description: string,\n): Promise<AutoCommitResult> {\n // Validate we're in a git repo\n const isGitRepo = await getIsGit()\n if (!isGitRepo) {\n return {\n success: false,\n message: 'Not a git repository',\n }\n }\n\n // Get changed files\n const allChanges = await getChangedFiles()\n if (allChanges.length === 0) {\n return {\n success: false,\n message: 'No changes to commit',\n }\n }\n\n // Filter excluded files\n const filesToCommit = filterExcludedFiles(allChanges, config.excludePatterns)\n if (filesToCommit.length === 0) {\n return {\n success: false,\n message: 'All changed files are excluded by patterns',\n }\n }\n\n // Get detailed change summary for commit message\n const summary = await getChangeSummary(filesToCommit)\n\n // Stage files\n const stageResult = await stageFiles(filesToCommit.map(f => f.path))\n if (!stageResult.success) {\n return {\n success: false,\n message: `Failed to stage files: ${stageResult.error}`,\n }\n }\n\n // Generate commit message\n const commitMessage = generateCommitMessage(config, summary, description)\n\n // Create commit\n const commitResult = await createCommit(commitMessage)\n if (!commitResult.success) {\n return {\n success: false,\n message: `Failed to create commit: ${commitResult.error}`,\n }\n }\n\n return {\n success: true,\n message: `Committed ${filesToCommit.length} file(s)`,\n commitHash: commitResult.hash,\n filesCommitted: filesToCommit.map(f => f.path),\n }\n}\n\n/**\n * Generate a commit message from the change summary\n *\n * @param config - Git auto-commit configuration\n * @param summary - Summary of file changes\n * @param description - Short description of the changes\n * @returns Formatted commit message\n */\nexport function generateCommitMessage(\n config: GitAutoCommitConfig,\n summary: ChangeSummary,\n description: string,\n): string {\n // Sanitize description - remove leading/trailing whitespace, limit length\n const sanitizedDesc = description.trim().slice(0, 72)\n\n // Build title line\n const title = `${config.commitMessagePrefix}${sanitizedDesc}`\n\n // Build file list\n const fileCount = summary.files.length\n const fileLines = summary.files\n .slice(0, 10) // Limit to first 10 files\n .map(file => {\n const statusPrefix = getStatusLabel(file.status)\n if (file.linesAdded !== undefined || file.linesRemoved !== undefined) {\n const added = file.linesAdded ?? 0\n const removed = file.linesRemoved ?? 0\n return `- ${file.path} (${statusPrefix}, +${added} -${removed})`\n }\n return `- ${file.path} (${statusPrefix})`\n })\n\n // Add \"and X more\" if there are more files\n if (summary.files.length > 10) {\n fileLines.push(`- ... and ${summary.files.length - 10} more file(s)`)\n }\n\n // Build full message\n const lines = [\n title,\n '',\n `Modified ${fileCount} file(s):`,\n ...fileLines,\n '',\n '\uD83E\uDD16 Auto-committed by Minto',\n ]\n\n return lines.join('\\n')\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Get list of changed files from git status\n */\nexport async function getChangedFiles(): Promise<ChangedFile[]> {\n const { stdout, code } = await execFileNoThrow(\n 'git',\n ['status', '--porcelain', '-u'],\n undefined,\n undefined,\n true,\n )\n\n if (code !== 0) {\n return []\n }\n\n const files: ChangedFile[] = []\n\n for (const line of stdout.split('\\n')) {\n if (!line.trim()) continue\n\n // Parse git status porcelain format: XY filename\n // X = index status, Y = working tree status\n const status = line.substring(0, 2).trim()\n const path = line.substring(3).trim()\n\n if (!path) continue\n\n // Map status codes to our simplified format\n const normalizedStatus = normalizeStatus(status)\n if (normalizedStatus) {\n files.push({\n path,\n status: normalizedStatus,\n })\n }\n }\n\n return files\n}\n\n/**\n * Get detailed change summary including line counts\n */\nasync function getChangeSummary(files: ChangedFile[]): Promise<ChangeSummary> {\n let totalAdded = 0\n let totalRemoved = 0\n\n // Get numstat for tracked files\n const trackedFiles = files.filter(f => f.status !== '?')\n if (trackedFiles.length > 0) {\n const { stdout, code } = await execFileNoThrow(\n 'git',\n ['diff', '--numstat', 'HEAD', '--', ...trackedFiles.map(f => f.path)],\n undefined,\n undefined,\n true,\n )\n\n if (code === 0) {\n for (const line of stdout.split('\\n')) {\n if (!line.trim()) continue\n\n const parts = line.split('\\t')\n if (parts.length >= 3) {\n const added = parseInt(parts[0], 10) || 0\n const removed = parseInt(parts[1], 10) || 0\n const path = parts[2]\n\n // Find and update the file in our list\n const file = files.find(f => f.path === path)\n if (file) {\n file.linesAdded = added\n file.linesRemoved = removed\n }\n\n totalAdded += added\n totalRemoved += removed\n }\n }\n }\n }\n\n // For untracked files, count all lines as added\n const untrackedFiles = files.filter(f => f.status === '?')\n for (const file of untrackedFiles) {\n const { stdout, code } = await execFileNoThrow(\n 'wc',\n ['-l', file.path],\n undefined,\n undefined,\n true,\n )\n\n if (code === 0) {\n const lineCount = parseInt(stdout.trim().split(/\\s+/)[0], 10) || 0\n file.linesAdded = lineCount\n file.linesRemoved = 0\n totalAdded += lineCount\n }\n }\n\n return {\n files,\n totalAdded,\n totalRemoved,\n }\n}\n\n/**\n * Filter out files matching exclusion patterns\n */\nexport function filterExcludedFiles(\n files: ChangedFile[],\n excludePatterns: string[],\n): ChangedFile[] {\n return files.filter(file => {\n for (const pattern of excludePatterns) {\n if (minimatch(file.path, pattern, { dot: true })) {\n return false\n }\n }\n return true\n })\n}\n\n/**\n * Stage files for commit\n */\nasync function stageFiles(\n paths: string[],\n): Promise<{ success: boolean; error?: string }> {\n if (paths.length === 0) {\n return { success: true }\n }\n\n const { code, stderr } = await execFileNoThrow(\n 'git',\n ['add', '--', ...paths],\n undefined,\n undefined,\n true,\n )\n\n if (code !== 0) {\n return { success: false, error: stderr || 'Unknown error' }\n }\n\n return { success: true }\n}\n\n/**\n * Create a git commit\n */\nasync function createCommit(\n message: string,\n): Promise<{ success: boolean; hash?: string; error?: string }> {\n const { code, stdout, stderr } = await execFileNoThrow(\n 'git',\n ['commit', '-m', message],\n undefined,\n undefined,\n true,\n )\n\n if (code !== 0) {\n return { success: false, error: stderr || 'Unknown error' }\n }\n\n // Extract commit hash from output\n // Output format: \"[branch hash] message\"\n const match = stdout.match(/\\[[\\w/-]+ ([a-f0-9]+)\\]/)\n const hash = match ? match[1] : undefined\n\n return { success: true, hash }\n}\n\n/**\n * Normalize git status code to our simplified format\n */\nfunction normalizeStatus(\n status: string,\n): 'M' | 'A' | 'D' | '?' | 'R' | 'C' | 'U' | null {\n // Handle the various git status codes\n // First character is staging area, second is working tree\n\n if (status.includes('?')) return '?'\n if (status.includes('A')) return 'A'\n if (status.includes('D')) return 'D'\n if (status.includes('R')) return 'R'\n if (status.includes('C')) return 'C'\n if (status.includes('U')) return 'U'\n if (status.includes('M') || status.includes(' M')) return 'M'\n\n // For any other changes (like ' M' for unstaged modifications)\n if (status.trim()) return 'M'\n\n return null\n}\n\n/**\n * Get human-readable label for status code\n */\nfunction getStatusLabel(status: string): string {\n switch (status) {\n case 'M':\n return 'modified'\n case 'A':\n return 'new'\n case 'D':\n return 'deleted'\n case '?':\n return 'new'\n case 'R':\n return 'renamed'\n case 'C':\n return 'copied'\n case 'U':\n return 'unmerged'\n default:\n return 'changed'\n }\n}\n\n// ============================================================================\n// Operation Tracker Integration\n// ============================================================================\n\n/**\n * Get files modified during the current session from operationTracker\n *\n * This provides additional context about which files were touched by Minto,\n * which can be used to prioritize or filter files for auto-commit.\n */\nexport function getTrackedOperations(): OperationSummary {\n return operationTracker.getSummary()\n}\n\n/**\n * Check if operationTracker has any file modifications recorded\n */\nexport function hasTrackedFileChanges(): boolean {\n const summary = operationTracker.getSummary()\n return summary.filesModified.length > 0 || summary.filesCreated.length > 0\n}\n\n/**\n * Enhance changed files with line count data from operationTracker\n *\n * When operationTracker has recorded line changes, use that data\n * instead of computing it via git diff (which is more expensive).\n */\nexport function enhanceWithTrackerData(\n files: ChangedFile[],\n trackerSummary: OperationSummary,\n): ChangedFile[] {\n // Build a map of tracked modifications for fast lookup\n const modifiedMap = new Map<string, { added: number; removed: number }>()\n for (const mod of trackerSummary.filesModified) {\n modifiedMap.set(mod.path, { added: mod.added, removed: mod.removed })\n }\n\n // Enhance file data with tracker info\n return files.map(file => {\n const tracked = modifiedMap.get(file.path)\n if (tracked) {\n return {\n ...file,\n linesAdded: file.linesAdded ?? tracked.added,\n linesRemoved: file.linesRemoved ?? tracked.removed,\n }\n }\n return file\n })\n}\n\n// ============================================================================\n// Testing Utilities\n// ============================================================================\n\n/**\n * Get current working directory (for testing)\n * Re-exported from state for convenience\n */\nexport { getCwd }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/core/index.js
CHANGED
|
@@ -2,4 +2,7 @@ export * from "./config/index.js";
|
|
|
2
2
|
export * from "./permissions/index.js";
|
|
3
3
|
export * from "./tools/index.js";
|
|
4
4
|
export * from "./costTracker.js";
|
|
5
|
+
export * from "./operationTracker.js";
|
|
6
|
+
export * from "./gitAutoCommit.js";
|
|
7
|
+
export * from "./backupManager.js";
|
|
5
8
|
//# sourceMappingURL=index.js.map
|
package/dist/core/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/core/index.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Core Module\n *\n * Centralized exports for core system functionality.\n */\n\n// Configuration\nexport * from './config'\n\n// Permissions\nexport * from './permissions'\n\n// Tools\nexport * from './tools'\n\n// Cost Tracking\nexport * from './costTracker'\n"],
|
|
5
|
-
"mappings": "AAOA,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;",
|
|
4
|
+
"sourcesContent": ["/**\n * Core Module\n *\n * Centralized exports for core system functionality.\n */\n\n// Configuration\nexport * from './config'\n\n// Permissions\nexport * from './permissions'\n\n// Tools\nexport * from './tools'\n\n// Cost Tracking\nexport * from './costTracker'\n\n// Operation Tracking\nexport * from './operationTracker'\n\n// Git Auto-Commit\nexport * from './gitAutoCommit'\n\n// Backup Manager\nexport * from './backupManager'\n"],
|
|
5
|
+
"mappings": "AAOA,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;AAGd,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
class OperationTrackerImpl extends EventEmitter {
|
|
3
|
+
static instance = null;
|
|
4
|
+
/** All recorded operations in chronological order */
|
|
5
|
+
operations = [];
|
|
6
|
+
/** Counter for generating unique IDs */
|
|
7
|
+
idCounter = 0;
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.setMaxListeners(50);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the singleton instance
|
|
14
|
+
*/
|
|
15
|
+
static getInstance() {
|
|
16
|
+
if (!OperationTrackerImpl.instance) {
|
|
17
|
+
OperationTrackerImpl.instance = new OperationTrackerImpl();
|
|
18
|
+
}
|
|
19
|
+
return OperationTrackerImpl.instance;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Record a new operation
|
|
23
|
+
*
|
|
24
|
+
* @param input - Operation details to record
|
|
25
|
+
* @returns The recorded operation with generated id and timestamp
|
|
26
|
+
*/
|
|
27
|
+
record(input) {
|
|
28
|
+
const record = {
|
|
29
|
+
id: `op-${++this.idCounter}-${Date.now()}`,
|
|
30
|
+
type: input.type,
|
|
31
|
+
description: input.description,
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
duration: input.duration,
|
|
34
|
+
details: input.details
|
|
35
|
+
};
|
|
36
|
+
this.operations.push(record);
|
|
37
|
+
this.emit("operation", record);
|
|
38
|
+
return record;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get aggregated summary of all operations
|
|
42
|
+
*/
|
|
43
|
+
getSummary() {
|
|
44
|
+
const filesRead = /* @__PURE__ */ new Set();
|
|
45
|
+
const filesModified = /* @__PURE__ */ new Map();
|
|
46
|
+
const filesCreated = /* @__PURE__ */ new Set();
|
|
47
|
+
const commandsRun = [];
|
|
48
|
+
let tasksCompleted = 0;
|
|
49
|
+
let totalDuration = 0;
|
|
50
|
+
let webSearches = 0;
|
|
51
|
+
for (const op of this.operations) {
|
|
52
|
+
if (op.duration) {
|
|
53
|
+
totalDuration += op.duration;
|
|
54
|
+
}
|
|
55
|
+
switch (op.type) {
|
|
56
|
+
case "file_read":
|
|
57
|
+
if (op.details?.filePath) {
|
|
58
|
+
filesRead.add(op.details.filePath);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case "file_edit":
|
|
62
|
+
if (op.details?.filePath) {
|
|
63
|
+
const existing = filesModified.get(op.details.filePath);
|
|
64
|
+
if (existing) {
|
|
65
|
+
existing.added += op.details.linesAdded ?? 0;
|
|
66
|
+
existing.removed += op.details.linesRemoved ?? 0;
|
|
67
|
+
} else {
|
|
68
|
+
filesModified.set(op.details.filePath, {
|
|
69
|
+
path: op.details.filePath,
|
|
70
|
+
added: op.details.linesAdded ?? 0,
|
|
71
|
+
removed: op.details.linesRemoved ?? 0
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case "file_create":
|
|
77
|
+
if (op.details?.filePath) {
|
|
78
|
+
filesCreated.add(op.details.filePath);
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
case "bash_command":
|
|
82
|
+
if (op.details?.command) {
|
|
83
|
+
commandsRun.push(op.details.command);
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
case "web_search":
|
|
87
|
+
webSearches++;
|
|
88
|
+
break;
|
|
89
|
+
case "task":
|
|
90
|
+
tasksCompleted++;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
filesRead: Array.from(filesRead),
|
|
96
|
+
filesModified: Array.from(filesModified.values()),
|
|
97
|
+
filesCreated: Array.from(filesCreated),
|
|
98
|
+
commandsRun,
|
|
99
|
+
tasksCompleted,
|
|
100
|
+
totalDuration,
|
|
101
|
+
webSearches
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get all recorded operations
|
|
106
|
+
*/
|
|
107
|
+
getOperations() {
|
|
108
|
+
return [...this.operations];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get operation count by type
|
|
112
|
+
*/
|
|
113
|
+
getCountByType(type) {
|
|
114
|
+
return this.operations.filter((op) => op.type === type).length;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get total operation count
|
|
118
|
+
*/
|
|
119
|
+
getTotalCount() {
|
|
120
|
+
return this.operations.length;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Subscribe to operation events
|
|
124
|
+
*
|
|
125
|
+
* @param callback - Called when an operation is recorded
|
|
126
|
+
* @returns Unsubscribe function
|
|
127
|
+
*/
|
|
128
|
+
onOperation(callback) {
|
|
129
|
+
this.on("operation", callback);
|
|
130
|
+
return () => this.off("operation", callback);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Clear all recorded operations
|
|
134
|
+
*/
|
|
135
|
+
clear() {
|
|
136
|
+
this.operations = [];
|
|
137
|
+
this.idCounter = 0;
|
|
138
|
+
this.emit("clear");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Reset for testing (only available in test environment)
|
|
142
|
+
*/
|
|
143
|
+
resetForTests() {
|
|
144
|
+
if (process.env.NODE_ENV !== "test") {
|
|
145
|
+
throw new Error("resetForTests can only be called in tests");
|
|
146
|
+
}
|
|
147
|
+
this.clear();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const operationTracker = OperationTrackerImpl.getInstance();
|
|
151
|
+
function recordOperation(input) {
|
|
152
|
+
return operationTracker.record(input);
|
|
153
|
+
}
|
|
154
|
+
function getOperationSummary() {
|
|
155
|
+
return operationTracker.getSummary();
|
|
156
|
+
}
|
|
157
|
+
function recordFileRead(filePath, description) {
|
|
158
|
+
operationTracker.record({
|
|
159
|
+
type: "file_read",
|
|
160
|
+
description: description ?? `Read ${filePath}`,
|
|
161
|
+
details: { filePath }
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function recordFileEdit(filePath, linesAdded, linesRemoved, description) {
|
|
165
|
+
operationTracker.record({
|
|
166
|
+
type: "file_edit",
|
|
167
|
+
description: description ?? `Edit ${filePath}`,
|
|
168
|
+
details: { filePath, linesAdded, linesRemoved }
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function recordFileCreate(filePath, description) {
|
|
172
|
+
operationTracker.record({
|
|
173
|
+
type: "file_create",
|
|
174
|
+
description: description ?? `Create ${filePath}`,
|
|
175
|
+
details: { filePath }
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function recordBashCommand(command, duration, description) {
|
|
179
|
+
operationTracker.record({
|
|
180
|
+
type: "bash_command",
|
|
181
|
+
description: description ?? `Run: ${command}`,
|
|
182
|
+
duration,
|
|
183
|
+
details: { command }
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function recordWebSearch(searchQuery, description) {
|
|
187
|
+
operationTracker.record({
|
|
188
|
+
type: "web_search",
|
|
189
|
+
description: description ?? `Search: ${searchQuery}`,
|
|
190
|
+
details: { searchQuery }
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
function recordTaskComplete(description, toolCount, duration) {
|
|
194
|
+
operationTracker.record({
|
|
195
|
+
type: "task",
|
|
196
|
+
description,
|
|
197
|
+
duration,
|
|
198
|
+
details: { toolCount }
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
export {
|
|
202
|
+
getOperationSummary,
|
|
203
|
+
operationTracker,
|
|
204
|
+
recordBashCommand,
|
|
205
|
+
recordFileCreate,
|
|
206
|
+
recordFileEdit,
|
|
207
|
+
recordFileRead,
|
|
208
|
+
recordOperation,
|
|
209
|
+
recordTaskComplete,
|
|
210
|
+
recordWebSearch
|
|
211
|
+
};
|
|
212
|
+
//# sourceMappingURL=operationTracker.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/operationTracker.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Operation Tracker\n *\n * Tracks file operations, bash commands, and tasks executed during a session.\n * Provides aggregated summaries for user feedback on what changes were made.\n *\n * Architecture:\n * - Singleton pattern for global access\n * - Event-driven updates for real-time UI\n * - Categorized operation tracking (file_read, file_edit, file_create, bash_command, web_search, task)\n *\n * Usage:\n * ```typescript\n * import { operationTracker, recordOperation } from '@core/operationTracker'\n *\n * // Record a file read\n * recordOperation({\n * type: 'file_read',\n * description: 'Read configuration file',\n * details: { filePath: '/path/to/config.json' }\n * })\n *\n * // Get summary of all operations\n * const summary = operationTracker.getSummary()\n *\n * // Subscribe to updates\n * const unsubscribe = operationTracker.onOperation((record) => {\n * console.log('Operation recorded:', record)\n * })\n * ```\n */\n\nimport { EventEmitter } from 'events'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Type of operation that can be tracked\n */\nexport type OperationType =\n | 'file_read'\n | 'file_edit'\n | 'file_create'\n | 'bash_command'\n | 'web_search'\n | 'task'\n\n/**\n * Details specific to each operation type\n */\nexport interface OperationDetails {\n /** File path for file operations */\n filePath?: string\n\n /** Command string for bash operations */\n command?: string\n\n /** Lines added for file edits */\n linesAdded?: number\n\n /** Lines removed for file edits */\n linesRemoved?: number\n\n /** Number of tools used for task operations */\n toolCount?: number\n\n /** Search query for web search operations */\n searchQuery?: string\n}\n\n/**\n * A single recorded operation\n */\nexport interface OperationRecord {\n /** Unique identifier for the operation */\n id: string\n\n /** Type of operation */\n type: OperationType\n\n /** Human-readable description */\n description: string\n\n /** Unix timestamp when operation started */\n timestamp: number\n\n /** Duration in milliseconds (if completed) */\n duration?: number\n\n /** Additional details specific to operation type */\n details?: OperationDetails\n}\n\n/**\n * Aggregated summary of all operations\n */\nexport interface OperationSummary {\n /** List of files that were read */\n filesRead: string[]\n\n /** List of files that were modified with change stats */\n filesModified: { path: string; added: number; removed: number }[]\n\n /** List of files that were created */\n filesCreated: string[]\n\n /** List of bash commands that were run */\n commandsRun: string[]\n\n /** Number of tasks completed */\n tasksCompleted: number\n\n /** Total duration of all operations in milliseconds */\n totalDuration: number\n\n /** Number of web searches performed */\n webSearches: number\n}\n\n/**\n * Input for recording an operation (id and timestamp auto-generated)\n */\nexport interface OperationInput {\n type: OperationType\n description: string\n duration?: number\n details?: OperationDetails\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * OperationTrackerImpl - Centralized operation tracking\n */\nclass OperationTrackerImpl extends EventEmitter {\n private static instance: OperationTrackerImpl | null = null\n\n /** All recorded operations in chronological order */\n private operations: OperationRecord[] = []\n\n /** Counter for generating unique IDs */\n private idCounter = 0\n\n private constructor() {\n super()\n this.setMaxListeners(50)\n }\n\n /**\n * Get the singleton instance\n */\n static getInstance(): OperationTrackerImpl {\n if (!OperationTrackerImpl.instance) {\n OperationTrackerImpl.instance = new OperationTrackerImpl()\n }\n return OperationTrackerImpl.instance\n }\n\n /**\n * Record a new operation\n *\n * @param input - Operation details to record\n * @returns The recorded operation with generated id and timestamp\n */\n record(input: OperationInput): OperationRecord {\n const record: OperationRecord = {\n id: `op-${++this.idCounter}-${Date.now()}`,\n type: input.type,\n description: input.description,\n timestamp: Date.now(),\n duration: input.duration,\n details: input.details,\n }\n\n this.operations.push(record)\n this.emit('operation', record)\n\n return record\n }\n\n /**\n * Get aggregated summary of all operations\n */\n getSummary(): OperationSummary {\n const filesRead = new Set<string>()\n const filesModified = new Map<\n string,\n { path: string; added: number; removed: number }\n >()\n const filesCreated = new Set<string>()\n const commandsRun: string[] = []\n let tasksCompleted = 0\n let totalDuration = 0\n let webSearches = 0\n\n for (const op of this.operations) {\n // Accumulate duration\n if (op.duration) {\n totalDuration += op.duration\n }\n\n switch (op.type) {\n case 'file_read':\n if (op.details?.filePath) {\n filesRead.add(op.details.filePath)\n }\n break\n\n case 'file_edit':\n if (op.details?.filePath) {\n const existing = filesModified.get(op.details.filePath)\n if (existing) {\n // Accumulate changes to the same file\n existing.added += op.details.linesAdded ?? 0\n existing.removed += op.details.linesRemoved ?? 0\n } else {\n filesModified.set(op.details.filePath, {\n path: op.details.filePath,\n added: op.details.linesAdded ?? 0,\n removed: op.details.linesRemoved ?? 0,\n })\n }\n }\n break\n\n case 'file_create':\n if (op.details?.filePath) {\n filesCreated.add(op.details.filePath)\n }\n break\n\n case 'bash_command':\n if (op.details?.command) {\n commandsRun.push(op.details.command)\n }\n break\n\n case 'web_search':\n webSearches++\n break\n\n case 'task':\n tasksCompleted++\n break\n }\n }\n\n return {\n filesRead: Array.from(filesRead),\n filesModified: Array.from(filesModified.values()),\n filesCreated: Array.from(filesCreated),\n commandsRun,\n tasksCompleted,\n totalDuration,\n webSearches,\n }\n }\n\n /**\n * Get all recorded operations\n */\n getOperations(): OperationRecord[] {\n return [...this.operations]\n }\n\n /**\n * Get operation count by type\n */\n getCountByType(type: OperationType): number {\n return this.operations.filter(op => op.type === type).length\n }\n\n /**\n * Get total operation count\n */\n getTotalCount(): number {\n return this.operations.length\n }\n\n /**\n * Subscribe to operation events\n *\n * @param callback - Called when an operation is recorded\n * @returns Unsubscribe function\n */\n onOperation(callback: (record: OperationRecord) => void): () => void {\n this.on('operation', callback)\n return () => this.off('operation', callback)\n }\n\n /**\n * Clear all recorded operations\n */\n clear(): void {\n this.operations = []\n this.idCounter = 0\n this.emit('clear')\n }\n\n /**\n * Reset for testing (only available in test environment)\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.clear()\n }\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\n/** Singleton instance */\nexport const operationTracker = OperationTrackerImpl.getInstance()\n\n/**\n * Record an operation\n *\n * Convenience function for recording operations without accessing the singleton directly.\n */\nexport function recordOperation(input: OperationInput): OperationRecord {\n return operationTracker.record(input)\n}\n\n/**\n * Get operation summary\n *\n * Convenience function for getting summary without accessing the singleton directly.\n */\nexport function getOperationSummary(): OperationSummary {\n return operationTracker.getSummary()\n}\n\n/**\n * Record a file read operation\n */\nexport function recordFileRead(filePath: string, description?: string): void {\n operationTracker.record({\n type: 'file_read',\n description: description ?? `Read ${filePath}`,\n details: { filePath },\n })\n}\n\n/**\n * Record a file edit operation\n */\nexport function recordFileEdit(\n filePath: string,\n linesAdded: number,\n linesRemoved: number,\n description?: string,\n): void {\n operationTracker.record({\n type: 'file_edit',\n description: description ?? `Edit ${filePath}`,\n details: { filePath, linesAdded, linesRemoved },\n })\n}\n\n/**\n * Record a file create operation\n */\nexport function recordFileCreate(filePath: string, description?: string): void {\n operationTracker.record({\n type: 'file_create',\n description: description ?? `Create ${filePath}`,\n details: { filePath },\n })\n}\n\n/**\n * Record a bash command execution\n */\nexport function recordBashCommand(\n command: string,\n duration?: number,\n description?: string,\n): void {\n operationTracker.record({\n type: 'bash_command',\n description: description ?? `Run: ${command}`,\n duration,\n details: { command },\n })\n}\n\n/**\n * Record a web search operation\n */\nexport function recordWebSearch(\n searchQuery: string,\n description?: string,\n): void {\n operationTracker.record({\n type: 'web_search',\n description: description ?? `Search: ${searchQuery}`,\n details: { searchQuery },\n })\n}\n\n/**\n * Record a task completion\n */\nexport function recordTaskComplete(\n description: string,\n toolCount?: number,\n duration?: number,\n): void {\n operationTracker.record({\n type: 'task',\n description,\n duration,\n details: { toolCount },\n })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|