@within-7/minto 0.3.10 → 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 +2 -2
- package/dist/commands/agents/AgentsCommand.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 +19 -9
- 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/mcp-interactive.js +14 -8
- 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 +45 -2
- 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/plugin/utils.js +33 -1
- package/dist/commands/plugin/utils.js.map +2 -2
- package/dist/commands/plugin.js +10 -1
- package/dist/commands/plugin.js.map +2 -2
- package/dist/commands/refreshCommands.js +2 -0
- package/dist/commands/refreshCommands.js.map +2 -2
- package/dist/commands/review.js +51 -0
- package/dist/commands/review.js.map +7 -0
- package/dist/commands/terminalSetup.js +6 -0
- package/dist/commands/terminalSetup.js.map +2 -2
- package/dist/commands/undo.js +8 -0
- 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/HighlightedCode.js +1 -0
- package/dist/components/HighlightedCode.js.map +2 -2
- package/dist/components/ModelSelector/ModelSelector.js +250 -143
- package/dist/components/ModelSelector/ModelSelector.js.map +2 -2
- package/dist/components/PromptInput.js +21 -6
- 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/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/SubagentBlock.js +43 -6
- package/dist/components/SubagentBlock.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 +1 -1
- 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 +2 -2
- package/dist/core/backupHook.js.map +2 -2
- package/dist/core/config/defaults.js +4 -1
- package/dist/core/config/defaults.js.map +2 -2
- package/dist/core/config/schema.js +7 -1
- package/dist/core/config/schema.js.map +2 -2
- package/dist/core/costTracker.js +18 -0
- 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/entrypoints/cli.js +65 -84
- 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 +8 -9
- package/dist/i18n/locales/en.js.map +2 -2
- package/dist/i18n/locales/zh-CN.js +8 -9
- 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/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/skillMarketplace.js +4 -1
- 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 +350 -3
- 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 +1 -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 +3 -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.map +1 -1
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +1 -1
- 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 +75 -5
- 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 +1 -1
- package/dist/types/plugin.js.map +2 -2
- package/dist/utils/agentLoader.js +25 -3
- package/dist/utils/agentLoader.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/config.js +26 -128
- 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/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/memoizeWithTTL.js +25 -0
- package/dist/utils/memoizeWithTTL.js.map +7 -0
- package/dist/utils/model.js +34 -9
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/pluginInstaller.js +34 -5
- package/dist/utils/pluginInstaller.js.map +2 -2
- package/dist/utils/pluginLoader.js +201 -32
- package/dist/utils/pluginLoader.js.map +2 -2
- package/dist/utils/safeFetch.js +45 -0
- package/dist/utils/safeFetch.js.map +7 -0
- package/dist/utils/skillLoader.js +59 -6
- 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/style.js +6 -3
- package/dist/utils/style.js.map +2 -2
- package/dist/utils/teamConfig.js +9 -3
- package/dist/utils/teamConfig.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 +2 -1
|
@@ -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
|
|
@@ -275,6 +341,287 @@ ${content}
|
|
|
275
341
|
timestamp: context.timestamp
|
|
276
342
|
});
|
|
277
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
|
+
});
|
|
278
625
|
}
|
|
279
626
|
addEventListener(event, callback) {
|
|
280
627
|
if (!this.eventDispatcher.has(event)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/services/systemReminder.ts"],
|
|
4
|
-
"sourcesContent": ["import { getTodos, TodoItem } from '@utils/todoStorage'\n\nexport interface ReminderMessage {\n role: 'system'\n content: string\n isMeta: boolean\n timestamp: number\n type: string\n priority: 'low' | 'medium' | 'high'\n category: 'task' | 'security' | 'performance' | 'general'\n}\n\ninterface ReminderConfig {\n todoEmptyReminder: boolean\n securityReminder: boolean\n performanceReminder: boolean\n maxRemindersPerSession: number\n}\n\ninterface SessionReminderState {\n lastTodoUpdate: number\n lastFileAccess: number\n sessionStartTime: number\n remindersSent: Set<string>\n contextPresent: boolean\n reminderCount: number\n config: ReminderConfig\n}\n\nclass SystemReminderService {\n private sessionState: SessionReminderState = {\n lastTodoUpdate: 0,\n lastFileAccess: 0,\n sessionStartTime: Date.now(),\n remindersSent: new Set(),\n contextPresent: false,\n reminderCount: 0,\n config: {\n todoEmptyReminder: true,\n securityReminder: true,\n performanceReminder: true,\n maxRemindersPerSession: 10,\n },\n }\n\n private eventDispatcher = new Map<string, Array<(context: any) => void>>()\n private reminderCache = new Map<string, ReminderMessage>()\n\n constructor() {\n this.setupEventDispatcher()\n }\n\n /**\n * Conditional reminder injection - only when context is present\n * Enhanced with performance optimizations and priority management\n */\n public generateReminders(\n hasContext: boolean = false,\n agentId?: string,\n ): ReminderMessage[] {\n this.sessionState.contextPresent = hasContext\n\n // Only inject when context is present (matching original behavior)\n if (!hasContext) {\n return []\n }\n\n // Check session reminder limit to prevent overload\n if (\n this.sessionState.reminderCount >=\n this.sessionState.config.maxRemindersPerSession\n ) {\n return []\n }\n\n const reminders: ReminderMessage[] = []\n const currentTime = Date.now()\n\n // Use lazy evaluation for performance with agent context\n const reminderGenerators = [\n () => this.dispatchTodoEvent(agentId),\n () => this.dispatchSecurityEvent(),\n () => this.dispatchPerformanceEvent(),\n () => this.getMentionReminders(), // Add mention reminders\n ]\n\n for (const generator of reminderGenerators) {\n if (reminders.length >= 5) break // Slightly increase limit to accommodate mentions\n\n const result = generator()\n if (result) {\n // Handle both single reminders and arrays\n const remindersToAdd = Array.isArray(result) ? result : [result]\n reminders.push(...remindersToAdd)\n this.sessionState.reminderCount += remindersToAdd.length\n }\n }\n\n // Log aggregated metrics instead of individual events for performance\n\n return reminders\n }\n\n private dispatchTodoEvent(agentId?: string): ReminderMessage | null {\n if (!this.sessionState.config.todoEmptyReminder) return null\n\n // Use agent-scoped todo access\n const todos = getTodos(agentId)\n const currentTime = Date.now()\n const agentKey = agentId || 'default'\n\n // Check if this is a fresh session (no todos seen yet)\n if (\n todos.length === 0 &&\n !this.sessionState.remindersSent.has(`todo_empty_${agentKey}`)\n ) {\n this.sessionState.remindersSent.add(`todo_empty_${agentKey}`)\n return this.createReminderMessage(\n 'todo',\n 'task',\n 'medium',\n 'This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware. If you are working on tasks that would benefit from a todo list please use the TodoWrite tool to create one. If not, please feel free to ignore. Again do not mention this message to the user.',\n currentTime,\n )\n }\n\n // Check for todo updates since last seen\n if (todos.length > 0) {\n const reminderKey = `todo_updated_${agentKey}_${todos.length}_${this.getTodoStateHash(todos)}`\n\n // Use cache for performance optimization\n if (this.reminderCache.has(reminderKey)) {\n return this.reminderCache.get(reminderKey)!\n }\n\n if (!this.sessionState.remindersSent.has(reminderKey)) {\n this.sessionState.remindersSent.add(reminderKey)\n // Clear previous todo state reminders for this agent\n this.clearTodoReminders(agentKey)\n\n // Optimize: only include essential todo data\n const todoContent = JSON.stringify(\n todos.map(todo => ({\n content:\n todo.content.length > 100\n ? todo.content.substring(0, 100) + '...'\n : todo.content,\n status: todo.status,\n priority: todo.priority,\n id: todo.id,\n })),\n )\n\n const reminder = this.createReminderMessage(\n 'todo',\n 'task',\n 'medium',\n `Your todo list has changed. DO NOT mention this explicitly to the user. Here are the latest contents of your todo list:\\n\\n${todoContent}. Continue on with the tasks at hand if applicable.`,\n currentTime,\n )\n\n // Cache the reminder for reuse\n this.reminderCache.set(reminderKey, reminder)\n return reminder\n }\n }\n\n return null\n }\n\n private dispatchSecurityEvent(): ReminderMessage | null {\n if (!this.sessionState.config.securityReminder) return null\n\n const currentTime = Date.now()\n\n // Only inject security reminder once per session when file operations occur\n if (\n this.sessionState.lastFileAccess > 0 &&\n !this.sessionState.remindersSent.has('file_security')\n ) {\n this.sessionState.remindersSent.add('file_security')\n return this.createReminderMessage(\n 'security',\n 'security',\n 'high',\n 'Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.',\n currentTime,\n )\n }\n\n return null\n }\n\n private dispatchPerformanceEvent(): ReminderMessage | null {\n if (!this.sessionState.config.performanceReminder) return null\n\n const currentTime = Date.now()\n const sessionDuration = currentTime - this.sessionState.sessionStartTime\n\n // Remind about performance after long sessions (30 minutes)\n if (\n sessionDuration > 30 * 60 * 1000 &&\n !this.sessionState.remindersSent.has('performance_long_session')\n ) {\n this.sessionState.remindersSent.add('performance_long_session')\n return this.createReminderMessage(\n 'performance',\n 'performance',\n 'low',\n 'Long session detected. Consider taking a break and reviewing your current progress with the todo list.',\n currentTime,\n )\n }\n\n return null\n }\n\n /**\n * Retrieve cached mention reminders\n * Returns recent mentions (within 5 seconds) that haven't expired\n */\n private getMentionReminders(): ReminderMessage[] {\n const currentTime = Date.now()\n const MENTION_FRESHNESS_WINDOW = 5000 // 5 seconds\n const reminders: ReminderMessage[] = []\n const expiredKeys: string[] = []\n\n // Single pass through cache for both collection and cleanup identification\n for (const [key, reminder] of this.reminderCache.entries()) {\n if (this.isMentionReminder(reminder)) {\n const age = currentTime - reminder.timestamp\n if (age <= MENTION_FRESHNESS_WINDOW) {\n reminders.push(reminder)\n } else {\n expiredKeys.push(key)\n }\n }\n }\n\n // Clean up expired mention reminders in separate pass for performance\n expiredKeys.forEach(key => this.reminderCache.delete(key))\n\n return reminders\n }\n\n /**\n * Type guard for mention reminders - centralized type checking\n * Eliminates hardcoded type strings scattered throughout the code\n */\n private isMentionReminder(reminder: ReminderMessage): boolean {\n const mentionTypes = ['agent_mention', 'file_mention', 'ask_model_mention']\n return mentionTypes.includes(reminder.type)\n }\n\n /**\n * Generate reminders for external file changes\n * Called when todo files are modified externally\n */\n public generateFileChangeReminder(context: any): ReminderMessage | null {\n const { agentId, filePath, reminder } = context\n\n if (!reminder) {\n return null\n }\n\n const currentTime = Date.now()\n const reminderKey = `file_changed_${agentId}_${filePath}_${currentTime}`\n\n // Ensure this specific file change reminder is only shown once\n if (this.sessionState.remindersSent.has(reminderKey)) {\n return null\n }\n\n this.sessionState.remindersSent.add(reminderKey)\n\n return this.createReminderMessage(\n 'file_changed',\n 'general',\n 'medium',\n reminder,\n currentTime,\n )\n }\n\n private createReminderMessage(\n type: string,\n category: ReminderMessage['category'],\n priority: ReminderMessage['priority'],\n content: string,\n timestamp: number,\n ): ReminderMessage {\n return {\n role: 'system',\n content: `<system-reminder>\\n${content}\\n</system-reminder>`,\n isMeta: true,\n timestamp,\n type,\n priority,\n category,\n }\n }\n\n private getTodoStateHash(todos: TodoItem[]): string {\n return todos\n .map(t => `${t.id}:${t.status}`)\n .sort()\n .join('|')\n }\n\n private clearTodoReminders(agentId?: string): void {\n const agentKey = agentId || 'default'\n for (const key of this.sessionState.remindersSent) {\n if (key.startsWith(`todo_updated_${agentKey}_`)) {\n this.sessionState.remindersSent.delete(key)\n }\n }\n }\n\n private setupEventDispatcher(): void {\n // Session startup events\n this.addEventListener('session:startup', context => {\n // Reset session state on startup\n this.resetSession()\n\n // Initialize session tracking\n this.sessionState.sessionStartTime = Date.now()\n this.sessionState.contextPresent =\n Object.keys(context.context || {}).length > 0\n })\n\n // Todo change events\n this.addEventListener('todo:changed', context => {\n this.sessionState.lastTodoUpdate = Date.now()\n this.clearTodoReminders(context.agentId)\n })\n\n // Todo file changed externally\n this.addEventListener('todo:file_changed', context => {\n // External file change detected, cache reminder for next generateReminders() call\n const agentId = context.agentId || 'default'\n this.clearTodoReminders(agentId)\n this.sessionState.lastTodoUpdate = Date.now()\n\n // Generate and cache file change reminder directly\n const reminder = this.generateFileChangeReminder(context)\n if (reminder) {\n const cacheKey = `file_changed_${agentId}_${Date.now()}`\n this.reminderCache.set(cacheKey, reminder)\n }\n })\n\n // File conflict events (external modification between reads)\n this.addEventListener('file:conflict', context => {\n const filePath = context.filePath || context.path || 'unknown'\n const cacheKey = `file_conflict_${filePath}_${Date.now()}`\n\n if (!this.sessionState.remindersSent.has(cacheKey)) {\n this.sessionState.remindersSent.add(cacheKey)\n\n const reminder = this.createReminderMessage(\n 'file_conflict',\n 'general',\n 'high',\n `File ${filePath} was modified externally since last read. Re-read the file before editing to avoid overwriting changes.`,\n Date.now(),\n )\n this.reminderCache.set(cacheKey, reminder)\n }\n })\n\n // File access events\n this.addEventListener('file:read', context => {\n this.sessionState.lastFileAccess = Date.now()\n })\n\n // File edit events for freshness detection\n this.addEventListener('file:edited', context => {\n // File edit handling\n })\n\n // Unified mention event handlers - eliminates code duplication\n this.addEventListener('agent:mentioned', context => {\n this.createMentionReminder({\n type: 'agent_mention',\n key: `agent_mention_${context.agentType}_${context.timestamp}`,\n category: 'task',\n priority: 'high',\n content: `The user mentioned @${context.originalMention}. You MUST use the Task tool with subagent_type=\"${context.agentType}\" to delegate this task to the specified agent. Provide a detailed, self-contained task description that fully captures the user's intent for the ${context.agentType} agent to execute.`,\n timestamp: context.timestamp,\n })\n })\n\n this.addEventListener('file:mentioned', context => {\n this.createMentionReminder({\n type: 'file_mention',\n key: `file_mention_${context.filePath}_${context.timestamp}`,\n category: 'general',\n priority: 'high',\n content: `The user mentioned @${context.originalMention}. You MUST read the entire content of the file at path: ${context.filePath} using the Read tool to understand the full context before proceeding with the user's request.`,\n timestamp: context.timestamp,\n })\n })\n\n this.addEventListener('ask-model:mentioned', context => {\n this.createMentionReminder({\n type: 'ask_model_mention',\n key: `ask_model_mention_${context.modelName}_${context.timestamp}`,\n category: 'task',\n priority: 'high',\n content: `The user mentioned @${context.modelName}. You MUST use the AskExpertModelTool to consult this specific model for expert opinions and analysis. Provide the user's question or context clearly to get the most relevant response from ${context.modelName}.`,\n timestamp: context.timestamp,\n })\n })\n }\n\n public addEventListener(\n event: string,\n callback: (context: any) => void,\n ): void {\n if (!this.eventDispatcher.has(event)) {\n this.eventDispatcher.set(event, [])\n }\n this.eventDispatcher.get(event)!.push(callback)\n }\n\n public emitEvent(event: string, context: any): void {\n const listeners = this.eventDispatcher.get(event) || []\n listeners.forEach(callback => {\n try {\n callback(context)\n } catch (error) {\n console.error(`Error in event listener for ${event}:`, error)\n }\n })\n }\n\n /**\n * Unified mention reminder creation - eliminates duplicate logic\n * Centralizes reminder creation with consistent deduplication\n */\n private createMentionReminder(params: {\n type: string\n key: string\n category: ReminderMessage['category']\n priority: ReminderMessage['priority']\n content: string\n timestamp: number\n }): void {\n if (!this.sessionState.remindersSent.has(params.key)) {\n this.sessionState.remindersSent.add(params.key)\n\n const reminder = this.createReminderMessage(\n params.type,\n params.category,\n params.priority,\n params.content,\n params.timestamp,\n )\n\n this.reminderCache.set(params.key, reminder)\n }\n }\n\n public resetSession(): void {\n this.sessionState = {\n lastTodoUpdate: 0,\n lastFileAccess: 0,\n sessionStartTime: Date.now(),\n remindersSent: new Set(),\n contextPresent: false,\n reminderCount: 0,\n config: { ...this.sessionState.config }, // Preserve config across resets\n }\n this.reminderCache.clear() // Clear cache on session reset\n }\n\n public updateConfig(config: Partial<ReminderConfig>): void {\n this.sessionState.config = { ...this.sessionState.config, ...config }\n }\n\n public getSessionState(): SessionReminderState {\n return { ...this.sessionState }\n }\n}\n\nexport const systemReminderService = new SystemReminderService()\n\nexport const generateSystemReminders = (\n hasContext: boolean = false,\n agentId?: string,\n) => systemReminderService.generateReminders(hasContext, agentId)\n\nexport const generateFileChangeReminder = (context: any) =>\n systemReminderService.generateFileChangeReminder(context)\n\nexport const emitReminderEvent = (event: string, context: any) =>\n systemReminderService.emitEvent(event, context)\n\nexport const resetReminderSession = () => systemReminderService.resetSession()\nexport const getReminderSessionState = () =>\n systemReminderService.getSessionState()\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { getTodos, TodoItem } from '@utils/todoStorage'\n\nexport interface ReminderMessage {\n role: 'system'\n content: string\n isMeta: boolean\n timestamp: number\n type: string\n priority: 'low' | 'medium' | 'high'\n category: 'task' | 'security' | 'performance' | 'general'\n}\n\ninterface ReminderConfig {\n todoEmptyReminder: boolean\n securityReminder: boolean\n performanceReminder: boolean\n maxRemindersPerSession: number\n}\n\ninterface SessionReminderState {\n lastTodoUpdate: number\n lastFileAccess: number\n sessionStartTime: number\n remindersSent: Set<string>\n contextPresent: boolean\n reminderCount: number\n config: ReminderConfig\n}\n\nclass SystemReminderService {\n private sessionState: SessionReminderState = {\n lastTodoUpdate: 0,\n lastFileAccess: 0,\n sessionStartTime: Date.now(),\n remindersSent: new Set(),\n contextPresent: false,\n reminderCount: 0,\n config: {\n todoEmptyReminder: true,\n securityReminder: true,\n performanceReminder: true,\n maxRemindersPerSession: 10,\n },\n }\n\n private eventDispatcher = new Map<string, Array<(context: any) => void>>()\n private reminderCache = new Map<string, ReminderMessage>()\n\n constructor() {\n this.setupEventDispatcher()\n }\n\n /**\n * Conditional reminder injection - only when context is present\n * Enhanced with performance optimizations and priority management\n */\n public generateReminders(\n hasContext: boolean = false,\n agentId?: string,\n ): ReminderMessage[] {\n this.sessionState.contextPresent = hasContext\n\n // Only inject when context is present (matching original behavior)\n if (!hasContext) {\n return []\n }\n\n // Check session reminder limit to prevent overload\n if (\n this.sessionState.reminderCount >=\n this.sessionState.config.maxRemindersPerSession\n ) {\n return []\n }\n\n const reminders: ReminderMessage[] = []\n const currentTime = Date.now()\n\n // Use lazy evaluation for performance with agent context\n const reminderGenerators = [\n () => this.dispatchTodoEvent(agentId),\n () => this.dispatchTaskToolsReminder(),\n () => this.dispatchSecurityEvent(),\n () => this.dispatchPerformanceEvent(),\n () => this.getMentionReminders(),\n () => this.getEventReminders(),\n ]\n\n for (const generator of reminderGenerators) {\n if (reminders.length >= 8) break // Accommodate mentions + event reminders\n\n const result = generator()\n if (result) {\n // Handle both single reminders and arrays\n const remindersToAdd = Array.isArray(result) ? result : [result]\n reminders.push(...remindersToAdd)\n this.sessionState.reminderCount += remindersToAdd.length\n }\n }\n\n // Log aggregated metrics instead of individual events for performance\n\n return reminders\n }\n\n private dispatchTodoEvent(agentId?: string): ReminderMessage | null {\n if (!this.sessionState.config.todoEmptyReminder) return null\n\n // Use agent-scoped todo access\n const todos = getTodos(agentId)\n const currentTime = Date.now()\n const agentKey = agentId || 'default'\n\n // Check if this is a fresh session (no todos seen yet)\n if (\n todos.length === 0 &&\n !this.sessionState.remindersSent.has(`todo_empty_${agentKey}`)\n ) {\n this.sessionState.remindersSent.add(`todo_empty_${agentKey}`)\n return this.createReminderMessage(\n 'todo',\n 'task',\n 'medium',\n 'This is a reminder that your todo list is currently empty. DO NOT mention this to the user explicitly because they are already aware. If you are working on tasks that would benefit from a todo list please use the TodoWrite tool to create one. If not, please feel free to ignore. Again do not mention this message to the user.',\n currentTime,\n )\n }\n\n // Check for todo updates since last seen\n if (todos.length > 0) {\n const reminderKey = `todo_updated_${agentKey}_${todos.length}_${this.getTodoStateHash(todos)}`\n\n // Use cache for performance optimization\n if (this.reminderCache.has(reminderKey)) {\n return this.reminderCache.get(reminderKey)!\n }\n\n if (!this.sessionState.remindersSent.has(reminderKey)) {\n this.sessionState.remindersSent.add(reminderKey)\n // Clear previous todo state reminders for this agent\n this.clearTodoReminders(agentKey)\n\n // Optimize: only include essential todo data\n const todoContent = JSON.stringify(\n todos.map(todo => ({\n content:\n todo.content.length > 100\n ? todo.content.substring(0, 100) + '...'\n : todo.content,\n status: todo.status,\n priority: todo.priority,\n id: todo.id,\n })),\n )\n\n const reminder = this.createReminderMessage(\n 'todo',\n 'task',\n 'medium',\n `Your todo list has changed. DO NOT mention this explicitly to the user. Here are the latest contents of your todo list:\\n\\n${todoContent}. Continue on with the tasks at hand if applicable.`,\n currentTime,\n )\n\n // Cache the reminder for reuse\n this.reminderCache.set(reminderKey, reminder)\n return reminder\n }\n }\n\n return null\n }\n\n private dispatchTaskToolsReminder(): ReminderMessage | null {\n const key = 'task_tools_reminder'\n if (this.sessionState.remindersSent.has(key)) return null\n\n // Only trigger after 5 minutes of session time\n const sessionDuration =\n Date.now() - this.sessionState.sessionStartTime\n if (sessionDuration < 5 * 60 * 1000) return null\n\n // Check if tasks exist via the event cache \u2014 if task:created or task:status\n // events have fired, the user is already using task tools\n const hasTaskActivity = Array.from(\n this.sessionState.remindersSent,\n ).some(k => k.startsWith('task_'))\n if (hasTaskActivity) return null\n\n // Emit the reminder event so the listener caches the message\n this.emitEvent('task:tools_reminder', {})\n return null\n }\n\n private dispatchSecurityEvent(): ReminderMessage | null {\n if (!this.sessionState.config.securityReminder) return null\n\n const currentTime = Date.now()\n\n // Only inject security reminder once per session when file operations occur\n if (\n this.sessionState.lastFileAccess > 0 &&\n !this.sessionState.remindersSent.has('file_security')\n ) {\n this.sessionState.remindersSent.add('file_security')\n return this.createReminderMessage(\n 'security',\n 'security',\n 'high',\n 'Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.',\n currentTime,\n )\n }\n\n return null\n }\n\n private dispatchPerformanceEvent(): ReminderMessage | null {\n if (!this.sessionState.config.performanceReminder) return null\n\n const currentTime = Date.now()\n const sessionDuration = currentTime - this.sessionState.sessionStartTime\n\n // Remind about performance after long sessions (30 minutes)\n if (\n sessionDuration > 30 * 60 * 1000 &&\n !this.sessionState.remindersSent.has('performance_long_session')\n ) {\n this.sessionState.remindersSent.add('performance_long_session')\n return this.createReminderMessage(\n 'performance',\n 'performance',\n 'low',\n 'Long session detected. Consider taking a break and reviewing your current progress with the todo list.',\n currentTime,\n )\n }\n\n return null\n }\n\n /**\n * Retrieve cached mention reminders\n * Returns recent mentions (within 5 seconds) that haven't expired\n */\n private getMentionReminders(): ReminderMessage[] {\n const currentTime = Date.now()\n const MENTION_FRESHNESS_WINDOW = 5000 // 5 seconds\n const reminders: ReminderMessage[] = []\n const expiredKeys: string[] = []\n\n // Single pass through cache for both collection and cleanup identification\n for (const [key, reminder] of this.reminderCache.entries()) {\n if (this.isMentionReminder(reminder)) {\n const age = currentTime - reminder.timestamp\n if (age <= MENTION_FRESHNESS_WINDOW) {\n reminders.push(reminder)\n } else {\n expiredKeys.push(key)\n }\n }\n }\n\n // Clean up expired mention reminders in separate pass for performance\n expiredKeys.forEach(key => this.reminderCache.delete(key))\n\n return reminders\n }\n\n /**\n * Type guard for mention reminders - centralized type checking\n * Eliminates hardcoded type strings scattered throughout the code\n */\n private isMentionReminder(reminder: ReminderMessage): boolean {\n const mentionTypes = ['agent_mention', 'file_mention', 'ask_model_mention']\n return mentionTypes.includes(reminder.type)\n }\n\n /**\n * Event-based reminder types for hook results, file status, task status\n */\n private static readonly EVENT_REMINDER_TYPES = new Set([\n // Batch A\n 'hook_additional_context',\n 'hook_blocking_error',\n 'hook_stopped_continuation',\n 'file_empty',\n 'file_truncated',\n 'task_status',\n 'task_tools_reminder',\n // Batch B\n 'output_style_active',\n 'plan_file_reference',\n 'plan_mode_reentry',\n 'plan_exited',\n 'skill_invoked',\n 'mcp_resource_no_content',\n 'compact_file_reference',\n // Batch C\n 'token_usage',\n 'budget_usd',\n 'team_coordination',\n 'team_shutdown',\n 'diagnostics_new',\n 'session_continuation',\n ])\n\n private isEventReminder(reminder: ReminderMessage): boolean {\n return SystemReminderService.EVENT_REMINDER_TYPES.has(reminder.type)\n }\n\n /**\n * Retrieve cached event-based reminders (hook results, file status, task status)\n * Returns recent event reminders within freshness window\n */\n private getEventReminders(): ReminderMessage[] {\n const currentTime = Date.now()\n const EVENT_FRESHNESS_WINDOW = 10000 // 10 seconds\n const reminders: ReminderMessage[] = []\n const expiredKeys: string[] = []\n\n for (const [key, reminder] of this.reminderCache.entries()) {\n if (this.isEventReminder(reminder)) {\n const age = currentTime - reminder.timestamp\n if (age <= EVENT_FRESHNESS_WINDOW) {\n reminders.push(reminder)\n } else {\n expiredKeys.push(key)\n }\n }\n }\n\n expiredKeys.forEach(key => this.reminderCache.delete(key))\n\n return reminders\n }\n\n /**\n * Generate reminders for external file changes\n * Called when todo files are modified externally\n */\n public generateFileChangeReminder(context: any): ReminderMessage | null {\n const { agentId, filePath, reminder } = context\n\n if (!reminder) {\n return null\n }\n\n const currentTime = Date.now()\n const reminderKey = `file_changed_${agentId}_${filePath}_${currentTime}`\n\n // Ensure this specific file change reminder is only shown once\n if (this.sessionState.remindersSent.has(reminderKey)) {\n return null\n }\n\n this.sessionState.remindersSent.add(reminderKey)\n\n return this.createReminderMessage(\n 'file_changed',\n 'general',\n 'medium',\n reminder,\n currentTime,\n )\n }\n\n private createReminderMessage(\n type: string,\n category: ReminderMessage['category'],\n priority: ReminderMessage['priority'],\n content: string,\n timestamp: number,\n ): ReminderMessage {\n return {\n role: 'system',\n content: `<system-reminder>\\n${content}\\n</system-reminder>`,\n isMeta: true,\n timestamp,\n type,\n priority,\n category,\n }\n }\n\n private getTodoStateHash(todos: TodoItem[]): string {\n return todos\n .map(t => `${t.id}:${t.status}`)\n .sort()\n .join('|')\n }\n\n private clearTodoReminders(agentId?: string): void {\n const agentKey = agentId || 'default'\n for (const key of this.sessionState.remindersSent) {\n if (key.startsWith(`todo_updated_${agentKey}_`)) {\n this.sessionState.remindersSent.delete(key)\n }\n }\n }\n\n private setupEventDispatcher(): void {\n // Session startup events\n this.addEventListener('session:startup', context => {\n // Reset session state on startup\n this.resetSession()\n\n // Initialize session tracking\n this.sessionState.sessionStartTime = Date.now()\n this.sessionState.contextPresent =\n Object.keys(context.context || {}).length > 0\n })\n\n // Todo change events\n this.addEventListener('todo:changed', context => {\n this.sessionState.lastTodoUpdate = Date.now()\n this.clearTodoReminders(context.agentId)\n })\n\n // Todo file changed externally\n this.addEventListener('todo:file_changed', context => {\n // External file change detected, cache reminder for next generateReminders() call\n const agentId = context.agentId || 'default'\n this.clearTodoReminders(agentId)\n this.sessionState.lastTodoUpdate = Date.now()\n\n // Generate and cache file change reminder directly\n const reminder = this.generateFileChangeReminder(context)\n if (reminder) {\n const cacheKey = `file_changed_${agentId}_${Date.now()}`\n this.reminderCache.set(cacheKey, reminder)\n }\n })\n\n // File conflict events (external modification between reads)\n this.addEventListener('file:conflict', context => {\n const filePath = context.filePath || context.path || 'unknown'\n const cacheKey = `file_conflict_${filePath}_${Date.now()}`\n\n if (!this.sessionState.remindersSent.has(cacheKey)) {\n this.sessionState.remindersSent.add(cacheKey)\n\n const reminder = this.createReminderMessage(\n 'file_conflict',\n 'general',\n 'high',\n `File ${filePath} was modified externally since last read. Re-read the file before editing to avoid overwriting changes.`,\n Date.now(),\n )\n this.reminderCache.set(cacheKey, reminder)\n }\n })\n\n // File access events\n this.addEventListener('file:read', context => {\n this.sessionState.lastFileAccess = Date.now()\n })\n\n // File edit events for freshness detection\n this.addEventListener('file:edited', context => {\n // File edit handling\n })\n\n // Unified mention event handlers - eliminates code duplication\n this.addEventListener('agent:mentioned', context => {\n this.createMentionReminder({\n type: 'agent_mention',\n key: `agent_mention_${context.agentType}_${context.timestamp}`,\n category: 'task',\n priority: 'high',\n content: `The user mentioned @${context.originalMention}. You MUST use the Task tool with subagent_type=\"${context.agentType}\" to delegate this task to the specified agent. Provide a detailed, self-contained task description that fully captures the user's intent for the ${context.agentType} agent to execute.`,\n timestamp: context.timestamp,\n })\n })\n\n this.addEventListener('file:mentioned', context => {\n this.createMentionReminder({\n type: 'file_mention',\n key: `file_mention_${context.filePath}_${context.timestamp}`,\n category: 'general',\n priority: 'high',\n content: `The user mentioned @${context.originalMention}. You MUST read the entire content of the file at path: ${context.filePath} using the Read tool to understand the full context before proceeding with the user's request.`,\n timestamp: context.timestamp,\n })\n })\n\n this.addEventListener('ask-model:mentioned', context => {\n this.createMentionReminder({\n type: 'ask_model_mention',\n key: `ask_model_mention_${context.modelName}_${context.timestamp}`,\n category: 'task',\n priority: 'high',\n content: `The user mentioned @${context.modelName}. You MUST use the AskExpertModelTool to consult this specific model for expert opinions and analysis. Provide the user's question or context clearly to get the most relevant response from ${context.modelName}.`,\n timestamp: context.timestamp,\n })\n })\n\n // Hook result events (Batch A system reminders)\n this.addEventListener('hook:additional_context', context => {\n const key = `hook_ctx_${context.hookName}_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'hook_additional_context',\n 'general',\n 'medium',\n `Additional context from hook \"${context.hookName}\": ${context.content}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n this.addEventListener('hook:blocking_error', context => {\n const key = `hook_block_${context.hookName}_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'hook_blocking_error',\n 'general',\n 'high',\n `A hook blocked the action: ${context.reason}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n this.addEventListener('hook:stopped_continuation', context => {\n const key = `hook_stop_${context.hookName}_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'hook_stopped_continuation',\n 'general',\n 'high',\n `A hook stopped continuation: ${context.reason}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // File status events\n this.addEventListener('file:empty', context => {\n const key = `file_empty_${context.filePath}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'file_empty',\n 'general',\n 'low',\n `File exists but is empty: ${context.filePath}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n this.addEventListener('file:truncated', context => {\n const key = `file_truncated_${context.filePath}_${context.limit}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'file_truncated',\n 'general',\n 'low',\n `File content was truncated at ${context.limit} lines. Total lines: ${context.totalLines}. Use offset and limit to read more.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Task status events\n this.addEventListener('task:status', context => {\n const key = `task_status_${context.taskId}_${context.status}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'task_status',\n 'task',\n 'medium',\n `Task ${context.taskId} (${context.description || 'unnamed'}): status changed to ${context.status}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n this.addEventListener('task:tools_reminder', context => {\n const key = 'task_tools_reminder'\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'task_tools_reminder',\n 'task',\n 'low',\n \"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\",\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Batch B: Output style events\n this.addEventListener('output_style:active', context => {\n const key = `output_style_active_${context.styleName}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'output_style_active',\n 'general',\n 'low',\n `Output style \"${context.styleName}\" is active. Follow its formatting instructions for your responses.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Plan mode events\n this.addEventListener('plan:file_reference', context => {\n const key = `plan_file_ref_${context.planPath}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'plan_file_reference',\n 'general',\n 'medium',\n `A plan file exists at: ${context.planPath}. Review it before making implementation decisions.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n this.addEventListener('plan:mode_reentry', context => {\n const key = `plan_reentry_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'plan_mode_reentry',\n 'general',\n 'medium',\n 'Re-entering plan mode. Review the existing plan and update as needed before implementation.',\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n this.addEventListener('plan:exited', context => {\n const key = `plan_exited_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'plan_exited',\n 'general',\n 'medium',\n 'Exited plan mode. Proceed with implementation following the approved plan.',\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Skill invocation events\n this.addEventListener('skill:invoked', context => {\n const key = `skill_invoked_${context.skillName}_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'skill_invoked',\n 'general',\n 'low',\n `Skill \"${context.skillName}\" was invoked. Follow the skill's instructions in the expanded prompt.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // MCP resource events\n this.addEventListener('mcp:resource_no_content', context => {\n const key = `mcp_no_content_${context.resourceUri}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'mcp_resource_no_content',\n 'general',\n 'low',\n `MCP resource \"${context.resourceUri}\" returned no content. It may be unavailable or empty.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Compact file reference events\n this.addEventListener('compact:file_reference', context => {\n const key = `compact_file_ref_${context.filePath}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'compact_file_reference',\n 'general',\n 'low',\n `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.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Batch C: Token usage tracking\n this.addEventListener('token:usage', context => {\n const key = `token_usage_${context.threshold}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'token_usage',\n 'performance',\n 'low',\n `Token usage has reached ${context.percentage}% of context limit (${context.used}/${context.total} tokens).`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Budget tracking\n this.addEventListener('budget:usd', context => {\n const key = `budget_usd_${context.threshold}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'budget_usd',\n 'performance',\n 'medium',\n `USD budget usage: $${context.used.toFixed(2)} of $${context.limit.toFixed(2)} (${context.percentage}%).`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Team coordination\n this.addEventListener('team:coordination', context => {\n const key = `team_coord_${context.teamId}_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'team_coordination',\n 'task',\n 'medium',\n `Team coordination: ${context.message}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Team shutdown\n this.addEventListener('team:shutdown', context => {\n const key = `team_shutdown_${context.teamId}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'team_shutdown',\n 'task',\n 'high',\n `Team \"${context.teamId}\" is shutting down. Reason: ${context.reason || 'completed'}`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // New diagnostics\n this.addEventListener('diagnostics:new', context => {\n const key = `diagnostics_${context.source}_${Date.now()}`\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const count = context.count || 1\n const reminder = this.createReminderMessage(\n 'diagnostics_new',\n 'general',\n 'low',\n `${count} new diagnostic${count > 1 ? 's' : ''} detected from ${context.source}. Review before proceeding.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n\n // Session continuation\n this.addEventListener('session:continuation', context => {\n const key = 'session_continuation'\n if (!this.sessionState.remindersSent.has(key)) {\n this.sessionState.remindersSent.add(key)\n const reminder = this.createReminderMessage(\n 'session_continuation',\n 'general',\n 'medium',\n `This session is a continuation of a previous conversation. Key context has been preserved.`,\n Date.now(),\n )\n this.reminderCache.set(key, reminder)\n }\n })\n }\n\n public addEventListener(\n event: string,\n callback: (context: any) => void,\n ): void {\n if (!this.eventDispatcher.has(event)) {\n this.eventDispatcher.set(event, [])\n }\n this.eventDispatcher.get(event)!.push(callback)\n }\n\n public emitEvent(event: string, context: any): void {\n const listeners = this.eventDispatcher.get(event) || []\n listeners.forEach(callback => {\n try {\n callback(context)\n } catch (error) {\n console.error(`Error in event listener for ${event}:`, error)\n }\n })\n }\n\n /**\n * Unified mention reminder creation - eliminates duplicate logic\n * Centralizes reminder creation with consistent deduplication\n */\n private createMentionReminder(params: {\n type: string\n key: string\n category: ReminderMessage['category']\n priority: ReminderMessage['priority']\n content: string\n timestamp: number\n }): void {\n if (!this.sessionState.remindersSent.has(params.key)) {\n this.sessionState.remindersSent.add(params.key)\n\n const reminder = this.createReminderMessage(\n params.type,\n params.category,\n params.priority,\n params.content,\n params.timestamp,\n )\n\n this.reminderCache.set(params.key, reminder)\n }\n }\n\n public resetSession(): void {\n this.sessionState = {\n lastTodoUpdate: 0,\n lastFileAccess: 0,\n sessionStartTime: Date.now(),\n remindersSent: new Set(),\n contextPresent: false,\n reminderCount: 0,\n config: { ...this.sessionState.config }, // Preserve config across resets\n }\n this.reminderCache.clear() // Clear cache on session reset\n }\n\n public updateConfig(config: Partial<ReminderConfig>): void {\n this.sessionState.config = { ...this.sessionState.config, ...config }\n }\n\n public getSessionState(): SessionReminderState {\n return { ...this.sessionState }\n }\n}\n\nexport const systemReminderService = new SystemReminderService()\n\nexport const generateSystemReminders = (\n hasContext: boolean = false,\n agentId?: string,\n) => systemReminderService.generateReminders(hasContext, agentId)\n\nexport const generateFileChangeReminder = (context: any) =>\n systemReminderService.generateFileChangeReminder(context)\n\nexport const emitReminderEvent = (event: string, context: any) =>\n systemReminderService.emitEvent(event, context)\n\nexport const resetReminderSession = () => systemReminderService.resetSession()\nexport const getReminderSessionState = () =>\n systemReminderService.getSessionState()\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getSessionState, setSessionState } from "../utils/sessionState.js";
|
|
2
2
|
import { emitReminderEvent } from "./systemReminder.js";
|
|
3
|
+
import { getHookManager } from "../utils/hookManager.js";
|
|
3
4
|
const TASK_STORAGE_KEY = "claudeCodeTasks";
|
|
4
5
|
let taskCache = null;
|
|
5
6
|
let cacheTimestamp = 0;
|
|
@@ -155,6 +156,24 @@ function updateTask(input) {
|
|
|
155
156
|
updatedTask,
|
|
156
157
|
timestamp: now
|
|
157
158
|
});
|
|
159
|
+
if (input.status && input.status !== existingTask.status) {
|
|
160
|
+
emitReminderEvent("task:status", {
|
|
161
|
+
taskId: updatedTask.id,
|
|
162
|
+
status: updatedTask.status,
|
|
163
|
+
subject: updatedTask.subject
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (input.status === "completed") {
|
|
167
|
+
const hookMgr = getHookManager();
|
|
168
|
+
if (hookMgr) {
|
|
169
|
+
hookMgr.executeTaskCompleted(
|
|
170
|
+
updatedTask.id,
|
|
171
|
+
updatedTask.subject,
|
|
172
|
+
updatedTask.description
|
|
173
|
+
).catch(() => {
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
158
177
|
return updatedTask;
|
|
159
178
|
}
|
|
160
179
|
function getTaskById(taskId) {
|