@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
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { join, resolve } from "path";
|
|
11
11
|
import { homedir } from "os";
|
|
12
12
|
import crypto from "crypto";
|
|
13
|
+
import { debug as debugLogger } from "../utils/debugLogger.js";
|
|
13
14
|
class SessionMemoryManager {
|
|
14
15
|
baseDir;
|
|
15
16
|
projectHash;
|
|
@@ -150,12 +151,20 @@ class SessionMemoryManager {
|
|
|
150
151
|
try {
|
|
151
152
|
const content = readFileSync(metadataPath, "utf-8");
|
|
152
153
|
sessions.push(JSON.parse(content));
|
|
153
|
-
} catch {
|
|
154
|
+
} catch (e) {
|
|
155
|
+
debugLogger.warn(
|
|
156
|
+
"SESSION_MEMORY",
|
|
157
|
+
`Skip invalid session metadata: ${e instanceof Error ? e.message : String(e)}`
|
|
158
|
+
);
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
}
|
|
157
162
|
}
|
|
158
|
-
} catch {
|
|
163
|
+
} catch (e) {
|
|
164
|
+
debugLogger.warn(
|
|
165
|
+
"SESSION_MEMORY",
|
|
166
|
+
`Cannot read session directory: ${e instanceof Error ? e.message : String(e)}`
|
|
167
|
+
);
|
|
159
168
|
}
|
|
160
169
|
return sessions.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
161
170
|
}
|
|
@@ -200,7 +209,11 @@ class SessionMemoryManager {
|
|
|
200
209
|
this.deleteDirectory(sessionDir);
|
|
201
210
|
cleaned++;
|
|
202
211
|
}
|
|
203
|
-
} catch {
|
|
212
|
+
} catch (e) {
|
|
213
|
+
debugLogger.warn(
|
|
214
|
+
"SESSION_MEMORY",
|
|
215
|
+
`Failed to clean session: ${e instanceof Error ? e.message : String(e)}`
|
|
216
|
+
);
|
|
204
217
|
}
|
|
205
218
|
}
|
|
206
219
|
return cleaned;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/services/sessionMemory.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Session Memory Service\n *\n * Provides persistent session memory for context compression.\n * Stores compressed contexts, decisions, and session metadata.\n *\n * Storage structure:\n * ~/.minto/projects/\n * <project-hash>/\n * session-<uuid>/\n * session_memory.json # Compressed context\n * conversation.json # Full conversation (optional)\n * decisions.json # Key decisions\n * metadata.json # Session metadata\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n readdirSync,\n unlinkSync,\n rmdirSync,\n} from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\nimport crypto from 'crypto'\nimport type { Message } from '@query'\nimport type {\n ExtractedDecision,\n ExtractedCodeChange,\n} from './intelligentCompactor'\n\n/**\n * Session metadata\n */\nexport interface SessionMetadata {\n sessionId: string\n projectPath: string\n projectHash: string\n createdAt: number\n updatedAt: number\n messageCount: number\n compressedAt?: number\n compressionRatio?: number\n focusArea?: string\n}\n\n/**\n * Session memory data\n */\nexport interface SessionMemoryData {\n summary: string\n decisions: ExtractedDecision[]\n codeChanges: ExtractedCodeChange[]\n toolUsageSummary: Record<string, number>\n focusAreas: string[]\n preservedContext: string[]\n}\n\n/**\n * Full session record\n */\nexport interface SessionRecord {\n metadata: SessionMetadata\n memory: SessionMemoryData\n messages?: Message[]\n}\n\n/**\n * Session Memory Manager\n */\nexport class SessionMemoryManager {\n private baseDir: string\n private projectHash: string\n private sessionId: string\n\n constructor(projectPath: string, sessionId?: string) {\n this.baseDir = join(homedir(), '.minto', 'projects')\n this.projectHash = this.hashPath(projectPath)\n this.sessionId = sessionId || crypto.randomUUID()\n this.ensureDirectories()\n }\n\n /**\n * Get the session ID\n */\n getSessionId(): string {\n return this.sessionId\n }\n\n /**\n * Get the project hash\n */\n getProjectHash(): string {\n return this.projectHash\n }\n\n /**\n * Save session memory\n */\n saveMemory(\n memory: SessionMemoryData,\n metadata?: Partial<SessionMetadata>,\n ): void {\n const sessionDir = this.getSessionDir()\n\n const fullMetadata: SessionMetadata = {\n sessionId: this.sessionId,\n projectPath: '', // Will be set by caller\n projectHash: this.projectHash,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n messageCount: 0,\n ...this.loadMetadata(),\n ...metadata,\n }\n\n // Save memory\n writeFileSync(\n join(sessionDir, 'session_memory.json'),\n JSON.stringify(memory, null, 2),\n )\n\n // Save metadata\n writeFileSync(\n join(sessionDir, 'metadata.json'),\n JSON.stringify(fullMetadata, null, 2),\n )\n\n // Save decisions separately for quick access\n if (memory.decisions.length > 0) {\n writeFileSync(\n join(sessionDir, 'decisions.json'),\n JSON.stringify(memory.decisions, null, 2),\n )\n }\n }\n\n /**\n * Save full conversation (optional, for debugging/recovery)\n */\n saveConversation(messages: Message[]): void {\n const sessionDir = this.getSessionDir()\n writeFileSync(\n join(sessionDir, 'conversation.json'),\n JSON.stringify(messages, null, 2),\n )\n\n // Update metadata\n const metadata = this.loadMetadata()\n if (metadata) {\n metadata.messageCount = messages.length\n metadata.updatedAt = Date.now()\n writeFileSync(\n join(sessionDir, 'metadata.json'),\n JSON.stringify(metadata, null, 2),\n )\n }\n }\n\n /**\n * Load session memory\n */\n loadMemory(): SessionMemoryData | null {\n const memoryPath = join(this.getSessionDir(), 'session_memory.json')\n if (!existsSync(memoryPath)) return null\n\n try {\n const content = readFileSync(memoryPath, 'utf-8')\n return JSON.parse(content) as SessionMemoryData\n } catch {\n return null\n }\n }\n\n /**\n * Load session metadata\n */\n loadMetadata(): SessionMetadata | null {\n const metadataPath = join(this.getSessionDir(), 'metadata.json')\n if (!existsSync(metadataPath)) return null\n\n try {\n const content = readFileSync(metadataPath, 'utf-8')\n return JSON.parse(content) as SessionMetadata\n } catch {\n return null\n }\n }\n\n /**\n * Load conversation history\n */\n loadConversation(): Message[] | null {\n const convoPath = join(this.getSessionDir(), 'conversation.json')\n if (!existsSync(convoPath)) return null\n\n try {\n const content = readFileSync(convoPath, 'utf-8')\n return JSON.parse(content) as Message[]\n } catch {\n return null\n }\n }\n\n /**\n * Load decisions from current or previous session\n */\n loadDecisions(): ExtractedDecision[] {\n const decisionsPath = join(this.getSessionDir(), 'decisions.json')\n if (!existsSync(decisionsPath)) return []\n\n try {\n const content = readFileSync(decisionsPath, 'utf-8')\n return JSON.parse(content) as ExtractedDecision[]\n } catch {\n return []\n }\n }\n\n /**\n * List all sessions for current project\n */\n listSessions(): SessionMetadata[] {\n const projectDir = this.getProjectDir()\n if (!existsSync(projectDir)) return []\n\n const sessions: SessionMetadata[] = []\n\n try {\n const entries = readdirSync(projectDir, { withFileTypes: true })\n for (const entry of entries) {\n if (entry.isDirectory() && entry.name.startsWith('session-')) {\n const metadataPath = join(projectDir, entry.name, 'metadata.json')\n if (existsSync(metadataPath)) {\n try {\n const content = readFileSync(metadataPath, 'utf-8')\n sessions.push(JSON.parse(content) as SessionMetadata)\n } catch {\n
|
|
5
|
-
"mappings": "AAgBA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,MAAM,eAAe;AAC9B,SAAS,eAAe;AACxB,OAAO,YAAY;
|
|
4
|
+
"sourcesContent": ["/**\n * Session Memory Service\n *\n * Provides persistent session memory for context compression.\n * Stores compressed contexts, decisions, and session metadata.\n *\n * Storage structure:\n * ~/.minto/projects/\n * <project-hash>/\n * session-<uuid>/\n * session_memory.json # Compressed context\n * conversation.json # Full conversation (optional)\n * decisions.json # Key decisions\n * metadata.json # Session metadata\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n readdirSync,\n unlinkSync,\n rmdirSync,\n} from 'fs'\nimport { join, resolve } from 'path'\nimport { homedir } from 'os'\nimport crypto from 'crypto'\nimport { debug as debugLogger } from '@utils/debugLogger'\nimport type { Message } from '@query'\nimport type {\n ExtractedDecision,\n ExtractedCodeChange,\n} from './intelligentCompactor'\n\n/**\n * Session metadata\n */\nexport interface SessionMetadata {\n sessionId: string\n projectPath: string\n projectHash: string\n createdAt: number\n updatedAt: number\n messageCount: number\n compressedAt?: number\n compressionRatio?: number\n focusArea?: string\n}\n\n/**\n * Session memory data\n */\nexport interface SessionMemoryData {\n summary: string\n decisions: ExtractedDecision[]\n codeChanges: ExtractedCodeChange[]\n toolUsageSummary: Record<string, number>\n focusAreas: string[]\n preservedContext: string[]\n}\n\n/**\n * Full session record\n */\nexport interface SessionRecord {\n metadata: SessionMetadata\n memory: SessionMemoryData\n messages?: Message[]\n}\n\n/**\n * Session Memory Manager\n */\nexport class SessionMemoryManager {\n private baseDir: string\n private projectHash: string\n private sessionId: string\n\n constructor(projectPath: string, sessionId?: string) {\n this.baseDir = join(homedir(), '.minto', 'projects')\n this.projectHash = this.hashPath(projectPath)\n this.sessionId = sessionId || crypto.randomUUID()\n this.ensureDirectories()\n }\n\n /**\n * Get the session ID\n */\n getSessionId(): string {\n return this.sessionId\n }\n\n /**\n * Get the project hash\n */\n getProjectHash(): string {\n return this.projectHash\n }\n\n /**\n * Save session memory\n */\n saveMemory(\n memory: SessionMemoryData,\n metadata?: Partial<SessionMetadata>,\n ): void {\n const sessionDir = this.getSessionDir()\n\n const fullMetadata: SessionMetadata = {\n sessionId: this.sessionId,\n projectPath: '', // Will be set by caller\n projectHash: this.projectHash,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n messageCount: 0,\n ...this.loadMetadata(),\n ...metadata,\n }\n\n // Save memory\n writeFileSync(\n join(sessionDir, 'session_memory.json'),\n JSON.stringify(memory, null, 2),\n )\n\n // Save metadata\n writeFileSync(\n join(sessionDir, 'metadata.json'),\n JSON.stringify(fullMetadata, null, 2),\n )\n\n // Save decisions separately for quick access\n if (memory.decisions.length > 0) {\n writeFileSync(\n join(sessionDir, 'decisions.json'),\n JSON.stringify(memory.decisions, null, 2),\n )\n }\n }\n\n /**\n * Save full conversation (optional, for debugging/recovery)\n */\n saveConversation(messages: Message[]): void {\n const sessionDir = this.getSessionDir()\n writeFileSync(\n join(sessionDir, 'conversation.json'),\n JSON.stringify(messages, null, 2),\n )\n\n // Update metadata\n const metadata = this.loadMetadata()\n if (metadata) {\n metadata.messageCount = messages.length\n metadata.updatedAt = Date.now()\n writeFileSync(\n join(sessionDir, 'metadata.json'),\n JSON.stringify(metadata, null, 2),\n )\n }\n }\n\n /**\n * Load session memory\n */\n loadMemory(): SessionMemoryData | null {\n const memoryPath = join(this.getSessionDir(), 'session_memory.json')\n if (!existsSync(memoryPath)) return null\n\n try {\n const content = readFileSync(memoryPath, 'utf-8')\n return JSON.parse(content) as SessionMemoryData\n } catch {\n return null\n }\n }\n\n /**\n * Load session metadata\n */\n loadMetadata(): SessionMetadata | null {\n const metadataPath = join(this.getSessionDir(), 'metadata.json')\n if (!existsSync(metadataPath)) return null\n\n try {\n const content = readFileSync(metadataPath, 'utf-8')\n return JSON.parse(content) as SessionMetadata\n } catch {\n return null\n }\n }\n\n /**\n * Load conversation history\n */\n loadConversation(): Message[] | null {\n const convoPath = join(this.getSessionDir(), 'conversation.json')\n if (!existsSync(convoPath)) return null\n\n try {\n const content = readFileSync(convoPath, 'utf-8')\n return JSON.parse(content) as Message[]\n } catch {\n return null\n }\n }\n\n /**\n * Load decisions from current or previous session\n */\n loadDecisions(): ExtractedDecision[] {\n const decisionsPath = join(this.getSessionDir(), 'decisions.json')\n if (!existsSync(decisionsPath)) return []\n\n try {\n const content = readFileSync(decisionsPath, 'utf-8')\n return JSON.parse(content) as ExtractedDecision[]\n } catch {\n return []\n }\n }\n\n /**\n * List all sessions for current project\n */\n listSessions(): SessionMetadata[] {\n const projectDir = this.getProjectDir()\n if (!existsSync(projectDir)) return []\n\n const sessions: SessionMetadata[] = []\n\n try {\n const entries = readdirSync(projectDir, { withFileTypes: true })\n for (const entry of entries) {\n if (entry.isDirectory() && entry.name.startsWith('session-')) {\n const metadataPath = join(projectDir, entry.name, 'metadata.json')\n if (existsSync(metadataPath)) {\n try {\n const content = readFileSync(metadataPath, 'utf-8')\n sessions.push(JSON.parse(content) as SessionMetadata)\n } catch (e) {\n debugLogger.warn(\n 'SESSION_MEMORY',\n `Skip invalid session metadata: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }\n }\n }\n } catch (e) {\n debugLogger.warn(\n 'SESSION_MEMORY',\n `Cannot read session directory: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n\n return sessions.sort((a, b) => b.updatedAt - a.updatedAt)\n }\n\n /**\n * Get the most recent session for current project\n */\n getMostRecentSession(): SessionRecord | null {\n const sessions = this.listSessions()\n if (sessions.length === 0) return null\n\n const mostRecent = sessions[0]\n if (!mostRecent) return null\n\n const tempManager = new SessionMemoryManager('', mostRecent.sessionId)\n // Hack to use the same project dir\n Object.assign(tempManager, { projectHash: this.projectHash })\n\n return {\n metadata: mostRecent,\n memory: tempManager.loadMemory() || {\n summary: '',\n decisions: [],\n codeChanges: [],\n toolUsageSummary: {},\n focusAreas: [],\n preservedContext: [],\n },\n messages: tempManager.loadConversation() || undefined,\n }\n }\n\n /**\n * Clean up old sessions (keep only N most recent)\n */\n cleanupOldSessions(keepCount: number = 5): number {\n const sessions = this.listSessions()\n let cleaned = 0\n\n if (sessions.length <= keepCount) return 0\n\n const toDelete = sessions.slice(keepCount)\n for (const session of toDelete) {\n try {\n const sessionDir = join(\n this.getProjectDir(),\n 'session-' + session.sessionId,\n )\n if (existsSync(sessionDir)) {\n // Simple recursive delete using fs\n this.deleteDirectory(sessionDir)\n cleaned++\n }\n } catch (e) {\n debugLogger.warn(\n 'SESSION_MEMORY',\n `Failed to clean session: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }\n\n return cleaned\n }\n\n /**\n * Check if a session exists\n */\n sessionExists(): boolean {\n return existsSync(this.getSessionDir())\n }\n\n /**\n * Get session directory path\n */\n private getSessionDir(): string {\n return join(this.getProjectDir(), 'session-' + this.sessionId)\n }\n\n /**\n * Get project directory path\n */\n private getProjectDir(): string {\n return join(this.baseDir, this.projectHash)\n }\n\n /**\n * Ensure required directories exist\n */\n private ensureDirectories(): void {\n const sessionDir = this.getSessionDir()\n if (!existsSync(sessionDir)) {\n mkdirSync(sessionDir, { recursive: true })\n }\n }\n\n /**\n * Hash a path to create a safe directory name\n */\n private hashPath(path: string): string {\n const normalized = resolve(path).toLowerCase()\n return crypto\n .createHash('sha256')\n .update(normalized)\n .digest('hex')\n .slice(0, 16)\n }\n\n /**\n * Recursively delete a directory\n */\n private deleteDirectory(dirPath: string): void {\n if (!existsSync(dirPath)) return\n\n const entries = readdirSync(dirPath, { withFileTypes: true })\n for (const entry of entries) {\n const fullPath = join(dirPath, entry.name)\n if (entry.isDirectory()) {\n this.deleteDirectory(fullPath)\n } else {\n unlinkSync(fullPath)\n }\n }\n rmdirSync(dirPath)\n }\n}\n\n/**\n * Create a session memory manager for the current project\n */\nexport function createSessionMemory(\n projectPath: string,\n sessionId?: string,\n): SessionMemoryManager {\n return new SessionMemoryManager(projectPath, sessionId)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -35,13 +35,14 @@ class SystemReminderService {
|
|
|
35
35
|
const currentTime = Date.now();
|
|
36
36
|
const reminderGenerators = [
|
|
37
37
|
() => this.dispatchTodoEvent(agentId),
|
|
38
|
+
() => this.dispatchTaskToolsReminder(),
|
|
38
39
|
() => this.dispatchSecurityEvent(),
|
|
39
40
|
() => this.dispatchPerformanceEvent(),
|
|
40
|
-
() => this.getMentionReminders()
|
|
41
|
-
|
|
41
|
+
() => this.getMentionReminders(),
|
|
42
|
+
() => this.getEventReminders()
|
|
42
43
|
];
|
|
43
44
|
for (const generator of reminderGenerators) {
|
|
44
|
-
if (reminders.length >=
|
|
45
|
+
if (reminders.length >= 8) break;
|
|
45
46
|
const result = generator();
|
|
46
47
|
if (result) {
|
|
47
48
|
const remindersToAdd = Array.isArray(result) ? result : [result];
|
|
@@ -97,6 +98,18 @@ ${todoContent}. Continue on with the tasks at hand if applicable.`,
|
|
|
97
98
|
}
|
|
98
99
|
return null;
|
|
99
100
|
}
|
|
101
|
+
dispatchTaskToolsReminder() {
|
|
102
|
+
const key = "task_tools_reminder";
|
|
103
|
+
if (this.sessionState.remindersSent.has(key)) return null;
|
|
104
|
+
const sessionDuration = Date.now() - this.sessionState.sessionStartTime;
|
|
105
|
+
if (sessionDuration < 5 * 60 * 1e3) return null;
|
|
106
|
+
const hasTaskActivity = Array.from(
|
|
107
|
+
this.sessionState.remindersSent
|
|
108
|
+
).some((k) => k.startsWith("task_"));
|
|
109
|
+
if (hasTaskActivity) return null;
|
|
110
|
+
this.emitEvent("task:tools_reminder", {});
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
100
113
|
dispatchSecurityEvent() {
|
|
101
114
|
if (!this.sessionState.config.securityReminder) return null;
|
|
102
115
|
const currentTime = Date.now();
|
|
@@ -158,6 +171,59 @@ ${todoContent}. Continue on with the tasks at hand if applicable.`,
|
|
|
158
171
|
const mentionTypes = ["agent_mention", "file_mention", "ask_model_mention"];
|
|
159
172
|
return mentionTypes.includes(reminder.type);
|
|
160
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Event-based reminder types for hook results, file status, task status
|
|
176
|
+
*/
|
|
177
|
+
static EVENT_REMINDER_TYPES = /* @__PURE__ */ new Set([
|
|
178
|
+
// Batch A
|
|
179
|
+
"hook_additional_context",
|
|
180
|
+
"hook_blocking_error",
|
|
181
|
+
"hook_stopped_continuation",
|
|
182
|
+
"file_empty",
|
|
183
|
+
"file_truncated",
|
|
184
|
+
"task_status",
|
|
185
|
+
"task_tools_reminder",
|
|
186
|
+
// Batch B
|
|
187
|
+
"output_style_active",
|
|
188
|
+
"plan_file_reference",
|
|
189
|
+
"plan_mode_reentry",
|
|
190
|
+
"plan_exited",
|
|
191
|
+
"skill_invoked",
|
|
192
|
+
"mcp_resource_no_content",
|
|
193
|
+
"compact_file_reference",
|
|
194
|
+
// Batch C
|
|
195
|
+
"token_usage",
|
|
196
|
+
"budget_usd",
|
|
197
|
+
"team_coordination",
|
|
198
|
+
"team_shutdown",
|
|
199
|
+
"diagnostics_new",
|
|
200
|
+
"session_continuation"
|
|
201
|
+
]);
|
|
202
|
+
isEventReminder(reminder) {
|
|
203
|
+
return SystemReminderService.EVENT_REMINDER_TYPES.has(reminder.type);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Retrieve cached event-based reminders (hook results, file status, task status)
|
|
207
|
+
* Returns recent event reminders within freshness window
|
|
208
|
+
*/
|
|
209
|
+
getEventReminders() {
|
|
210
|
+
const currentTime = Date.now();
|
|
211
|
+
const EVENT_FRESHNESS_WINDOW = 1e4;
|
|
212
|
+
const reminders = [];
|
|
213
|
+
const expiredKeys = [];
|
|
214
|
+
for (const [key, reminder] of this.reminderCache.entries()) {
|
|
215
|
+
if (this.isEventReminder(reminder)) {
|
|
216
|
+
const age = currentTime - reminder.timestamp;
|
|
217
|
+
if (age <= EVENT_FRESHNESS_WINDOW) {
|
|
218
|
+
reminders.push(reminder);
|
|
219
|
+
} else {
|
|
220
|
+
expiredKeys.push(key);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
expiredKeys.forEach((key) => this.reminderCache.delete(key));
|
|
225
|
+
return reminders;
|
|
226
|
+
}
|
|
161
227
|
/**
|
|
162
228
|
* Generate reminders for external file changes
|
|
163
229
|
* Called when todo files are modified externally
|
|
@@ -221,12 +287,23 @@ ${content}
|
|
|
221
287
|
this.sessionState.lastTodoUpdate = Date.now();
|
|
222
288
|
const reminder = this.generateFileChangeReminder(context);
|
|
223
289
|
if (reminder) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
290
|
+
const cacheKey = `file_changed_${agentId}_${Date.now()}`;
|
|
291
|
+
this.reminderCache.set(cacheKey, reminder);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
this.addEventListener("file:conflict", (context) => {
|
|
295
|
+
const filePath = context.filePath || context.path || "unknown";
|
|
296
|
+
const cacheKey = `file_conflict_${filePath}_${Date.now()}`;
|
|
297
|
+
if (!this.sessionState.remindersSent.has(cacheKey)) {
|
|
298
|
+
this.sessionState.remindersSent.add(cacheKey);
|
|
299
|
+
const reminder = this.createReminderMessage(
|
|
300
|
+
"file_conflict",
|
|
301
|
+
"general",
|
|
302
|
+
"high",
|
|
303
|
+
`File ${filePath} was modified externally since last read. Re-read the file before editing to avoid overwriting changes.`,
|
|
304
|
+
Date.now()
|
|
305
|
+
);
|
|
306
|
+
this.reminderCache.set(cacheKey, reminder);
|
|
230
307
|
}
|
|
231
308
|
});
|
|
232
309
|
this.addEventListener("file:read", (context) => {
|
|
@@ -264,6 +341,287 @@ ${content}
|
|
|
264
341
|
timestamp: context.timestamp
|
|
265
342
|
});
|
|
266
343
|
});
|
|
344
|
+
this.addEventListener("hook:additional_context", (context) => {
|
|
345
|
+
const key = `hook_ctx_${context.hookName}_${Date.now()}`;
|
|
346
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
347
|
+
this.sessionState.remindersSent.add(key);
|
|
348
|
+
const reminder = this.createReminderMessage(
|
|
349
|
+
"hook_additional_context",
|
|
350
|
+
"general",
|
|
351
|
+
"medium",
|
|
352
|
+
`Additional context from hook "${context.hookName}": ${context.content}`,
|
|
353
|
+
Date.now()
|
|
354
|
+
);
|
|
355
|
+
this.reminderCache.set(key, reminder);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
this.addEventListener("hook:blocking_error", (context) => {
|
|
359
|
+
const key = `hook_block_${context.hookName}_${Date.now()}`;
|
|
360
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
361
|
+
this.sessionState.remindersSent.add(key);
|
|
362
|
+
const reminder = this.createReminderMessage(
|
|
363
|
+
"hook_blocking_error",
|
|
364
|
+
"general",
|
|
365
|
+
"high",
|
|
366
|
+
`A hook blocked the action: ${context.reason}`,
|
|
367
|
+
Date.now()
|
|
368
|
+
);
|
|
369
|
+
this.reminderCache.set(key, reminder);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
this.addEventListener("hook:stopped_continuation", (context) => {
|
|
373
|
+
const key = `hook_stop_${context.hookName}_${Date.now()}`;
|
|
374
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
375
|
+
this.sessionState.remindersSent.add(key);
|
|
376
|
+
const reminder = this.createReminderMessage(
|
|
377
|
+
"hook_stopped_continuation",
|
|
378
|
+
"general",
|
|
379
|
+
"high",
|
|
380
|
+
`A hook stopped continuation: ${context.reason}`,
|
|
381
|
+
Date.now()
|
|
382
|
+
);
|
|
383
|
+
this.reminderCache.set(key, reminder);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
this.addEventListener("file:empty", (context) => {
|
|
387
|
+
const key = `file_empty_${context.filePath}`;
|
|
388
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
389
|
+
this.sessionState.remindersSent.add(key);
|
|
390
|
+
const reminder = this.createReminderMessage(
|
|
391
|
+
"file_empty",
|
|
392
|
+
"general",
|
|
393
|
+
"low",
|
|
394
|
+
`File exists but is empty: ${context.filePath}`,
|
|
395
|
+
Date.now()
|
|
396
|
+
);
|
|
397
|
+
this.reminderCache.set(key, reminder);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
this.addEventListener("file:truncated", (context) => {
|
|
401
|
+
const key = `file_truncated_${context.filePath}_${context.limit}`;
|
|
402
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
403
|
+
this.sessionState.remindersSent.add(key);
|
|
404
|
+
const reminder = this.createReminderMessage(
|
|
405
|
+
"file_truncated",
|
|
406
|
+
"general",
|
|
407
|
+
"low",
|
|
408
|
+
`File content was truncated at ${context.limit} lines. Total lines: ${context.totalLines}. Use offset and limit to read more.`,
|
|
409
|
+
Date.now()
|
|
410
|
+
);
|
|
411
|
+
this.reminderCache.set(key, reminder);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
this.addEventListener("task:status", (context) => {
|
|
415
|
+
const key = `task_status_${context.taskId}_${context.status}`;
|
|
416
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
417
|
+
this.sessionState.remindersSent.add(key);
|
|
418
|
+
const reminder = this.createReminderMessage(
|
|
419
|
+
"task_status",
|
|
420
|
+
"task",
|
|
421
|
+
"medium",
|
|
422
|
+
`Task ${context.taskId} (${context.description || "unnamed"}): status changed to ${context.status}`,
|
|
423
|
+
Date.now()
|
|
424
|
+
);
|
|
425
|
+
this.reminderCache.set(key, reminder);
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
this.addEventListener("task:tools_reminder", (context) => {
|
|
429
|
+
const key = "task_tools_reminder";
|
|
430
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
431
|
+
this.sessionState.remindersSent.add(key);
|
|
432
|
+
const reminder = this.createReminderMessage(
|
|
433
|
+
"task_tools_reminder",
|
|
434
|
+
"task",
|
|
435
|
+
"low",
|
|
436
|
+
"The task tools haven't been used recently. If you're working on tasks that would benefit from tracking progress, consider using TaskCreate to add new tasks and TaskUpdate to update task status (set to in_progress when starting, completed when done). Also consider cleaning up the task list if it has become stale. Only use these if relevant to the current work. This is just a gentle reminder - ignore if not applicable. Make sure that you NEVER mention this reminder to the user",
|
|
437
|
+
Date.now()
|
|
438
|
+
);
|
|
439
|
+
this.reminderCache.set(key, reminder);
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
this.addEventListener("output_style:active", (context) => {
|
|
443
|
+
const key = `output_style_active_${context.styleName}`;
|
|
444
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
445
|
+
this.sessionState.remindersSent.add(key);
|
|
446
|
+
const reminder = this.createReminderMessage(
|
|
447
|
+
"output_style_active",
|
|
448
|
+
"general",
|
|
449
|
+
"low",
|
|
450
|
+
`Output style "${context.styleName}" is active. Follow its formatting instructions for your responses.`,
|
|
451
|
+
Date.now()
|
|
452
|
+
);
|
|
453
|
+
this.reminderCache.set(key, reminder);
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
this.addEventListener("plan:file_reference", (context) => {
|
|
457
|
+
const key = `plan_file_ref_${context.planPath}`;
|
|
458
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
459
|
+
this.sessionState.remindersSent.add(key);
|
|
460
|
+
const reminder = this.createReminderMessage(
|
|
461
|
+
"plan_file_reference",
|
|
462
|
+
"general",
|
|
463
|
+
"medium",
|
|
464
|
+
`A plan file exists at: ${context.planPath}. Review it before making implementation decisions.`,
|
|
465
|
+
Date.now()
|
|
466
|
+
);
|
|
467
|
+
this.reminderCache.set(key, reminder);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
this.addEventListener("plan:mode_reentry", (context) => {
|
|
471
|
+
const key = `plan_reentry_${Date.now()}`;
|
|
472
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
473
|
+
this.sessionState.remindersSent.add(key);
|
|
474
|
+
const reminder = this.createReminderMessage(
|
|
475
|
+
"plan_mode_reentry",
|
|
476
|
+
"general",
|
|
477
|
+
"medium",
|
|
478
|
+
"Re-entering plan mode. Review the existing plan and update as needed before implementation.",
|
|
479
|
+
Date.now()
|
|
480
|
+
);
|
|
481
|
+
this.reminderCache.set(key, reminder);
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
this.addEventListener("plan:exited", (context) => {
|
|
485
|
+
const key = `plan_exited_${Date.now()}`;
|
|
486
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
487
|
+
this.sessionState.remindersSent.add(key);
|
|
488
|
+
const reminder = this.createReminderMessage(
|
|
489
|
+
"plan_exited",
|
|
490
|
+
"general",
|
|
491
|
+
"medium",
|
|
492
|
+
"Exited plan mode. Proceed with implementation following the approved plan.",
|
|
493
|
+
Date.now()
|
|
494
|
+
);
|
|
495
|
+
this.reminderCache.set(key, reminder);
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
this.addEventListener("skill:invoked", (context) => {
|
|
499
|
+
const key = `skill_invoked_${context.skillName}_${Date.now()}`;
|
|
500
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
501
|
+
this.sessionState.remindersSent.add(key);
|
|
502
|
+
const reminder = this.createReminderMessage(
|
|
503
|
+
"skill_invoked",
|
|
504
|
+
"general",
|
|
505
|
+
"low",
|
|
506
|
+
`Skill "${context.skillName}" was invoked. Follow the skill's instructions in the expanded prompt.`,
|
|
507
|
+
Date.now()
|
|
508
|
+
);
|
|
509
|
+
this.reminderCache.set(key, reminder);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
this.addEventListener("mcp:resource_no_content", (context) => {
|
|
513
|
+
const key = `mcp_no_content_${context.resourceUri}`;
|
|
514
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
515
|
+
this.sessionState.remindersSent.add(key);
|
|
516
|
+
const reminder = this.createReminderMessage(
|
|
517
|
+
"mcp_resource_no_content",
|
|
518
|
+
"general",
|
|
519
|
+
"low",
|
|
520
|
+
`MCP resource "${context.resourceUri}" returned no content. It may be unavailable or empty.`,
|
|
521
|
+
Date.now()
|
|
522
|
+
);
|
|
523
|
+
this.reminderCache.set(key, reminder);
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
this.addEventListener("compact:file_reference", (context) => {
|
|
527
|
+
const key = `compact_file_ref_${context.filePath}`;
|
|
528
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
529
|
+
this.sessionState.remindersSent.add(key);
|
|
530
|
+
const reminder = this.createReminderMessage(
|
|
531
|
+
"compact_file_reference",
|
|
532
|
+
"general",
|
|
533
|
+
"low",
|
|
534
|
+
`Note: ${context.filePath} was read before the last conversation was summarized, but the contents are too large to include. Use Read tool if you need to access it.`,
|
|
535
|
+
Date.now()
|
|
536
|
+
);
|
|
537
|
+
this.reminderCache.set(key, reminder);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
this.addEventListener("token:usage", (context) => {
|
|
541
|
+
const key = `token_usage_${context.threshold}`;
|
|
542
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
543
|
+
this.sessionState.remindersSent.add(key);
|
|
544
|
+
const reminder = this.createReminderMessage(
|
|
545
|
+
"token_usage",
|
|
546
|
+
"performance",
|
|
547
|
+
"low",
|
|
548
|
+
`Token usage has reached ${context.percentage}% of context limit (${context.used}/${context.total} tokens).`,
|
|
549
|
+
Date.now()
|
|
550
|
+
);
|
|
551
|
+
this.reminderCache.set(key, reminder);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
this.addEventListener("budget:usd", (context) => {
|
|
555
|
+
const key = `budget_usd_${context.threshold}`;
|
|
556
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
557
|
+
this.sessionState.remindersSent.add(key);
|
|
558
|
+
const reminder = this.createReminderMessage(
|
|
559
|
+
"budget_usd",
|
|
560
|
+
"performance",
|
|
561
|
+
"medium",
|
|
562
|
+
`USD budget usage: $${context.used.toFixed(2)} of $${context.limit.toFixed(2)} (${context.percentage}%).`,
|
|
563
|
+
Date.now()
|
|
564
|
+
);
|
|
565
|
+
this.reminderCache.set(key, reminder);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
this.addEventListener("team:coordination", (context) => {
|
|
569
|
+
const key = `team_coord_${context.teamId}_${Date.now()}`;
|
|
570
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
571
|
+
this.sessionState.remindersSent.add(key);
|
|
572
|
+
const reminder = this.createReminderMessage(
|
|
573
|
+
"team_coordination",
|
|
574
|
+
"task",
|
|
575
|
+
"medium",
|
|
576
|
+
`Team coordination: ${context.message}`,
|
|
577
|
+
Date.now()
|
|
578
|
+
);
|
|
579
|
+
this.reminderCache.set(key, reminder);
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
this.addEventListener("team:shutdown", (context) => {
|
|
583
|
+
const key = `team_shutdown_${context.teamId}`;
|
|
584
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
585
|
+
this.sessionState.remindersSent.add(key);
|
|
586
|
+
const reminder = this.createReminderMessage(
|
|
587
|
+
"team_shutdown",
|
|
588
|
+
"task",
|
|
589
|
+
"high",
|
|
590
|
+
`Team "${context.teamId}" is shutting down. Reason: ${context.reason || "completed"}`,
|
|
591
|
+
Date.now()
|
|
592
|
+
);
|
|
593
|
+
this.reminderCache.set(key, reminder);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
this.addEventListener("diagnostics:new", (context) => {
|
|
597
|
+
const key = `diagnostics_${context.source}_${Date.now()}`;
|
|
598
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
599
|
+
this.sessionState.remindersSent.add(key);
|
|
600
|
+
const count = context.count || 1;
|
|
601
|
+
const reminder = this.createReminderMessage(
|
|
602
|
+
"diagnostics_new",
|
|
603
|
+
"general",
|
|
604
|
+
"low",
|
|
605
|
+
`${count} new diagnostic${count > 1 ? "s" : ""} detected from ${context.source}. Review before proceeding.`,
|
|
606
|
+
Date.now()
|
|
607
|
+
);
|
|
608
|
+
this.reminderCache.set(key, reminder);
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
this.addEventListener("session:continuation", (context) => {
|
|
612
|
+
const key = "session_continuation";
|
|
613
|
+
if (!this.sessionState.remindersSent.has(key)) {
|
|
614
|
+
this.sessionState.remindersSent.add(key);
|
|
615
|
+
const reminder = this.createReminderMessage(
|
|
616
|
+
"session_continuation",
|
|
617
|
+
"general",
|
|
618
|
+
"medium",
|
|
619
|
+
`This session is a continuation of a previous conversation. Key context has been preserved.`,
|
|
620
|
+
Date.now()
|
|
621
|
+
);
|
|
622
|
+
this.reminderCache.set(key, reminder);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
267
625
|
}
|
|
268
626
|
addEventListener(event, callback) {
|
|
269
627
|
if (!this.eventDispatcher.has(event)) {
|