@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/MCPTool/MCPTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { type Tool } from '@tool'\nimport { getTheme } from '@utils/theme'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { OutputLine } from '@tools/BashTool/OutputLine'\n\n// Allow any input object since MCP tools define their own schemas\nconst inputSchema = z.object({}).passthrough()\n\nexport const MCPTool = {\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MCPTool can modify state through MCP calls, not safe for concurrent execution\n },\n // Overridden in mcpClient.ts\n name: 'mcp',\n // Overridden in mcpClient.ts\n async description() {\n return DESCRIPTION\n },\n // Overridden in mcpClient.ts\n async prompt() {\n return PROMPT\n },\n inputSchema,\n // Overridden in mcpClient.ts\n async *call() {\n yield {\n type: 'result',\n data: '',\n resultForAssistant: '',\n }\n },\n needsPermissions() {\n return true\n },\n renderToolUseMessage(input) {\n return Object.entries(input)\n .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)\n .join(', ')\n },\n // Overridden in mcpClient.ts\n userFacingName: () => 'mcp',\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n const verbose = false // Set default value for verbose\n\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().secondaryText}>(No content)</Text>\n </Box>\n </Box>\n )\n }\n\n if (Array.isArray(output)) {\n return (\n <Box flexDirection=\"column\">\n {output.map((item, i) => {\n // Guard against null/undefined items in array\n if (!item) {\n return null\n }\n if (item.type === 'image') {\n return (\n <Box\n key={i}\n justifyContent=\"space-between\"\n overflowX=\"hidden\"\n width=\"100%\"\n >\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text>[Image]</Text>\n </Box>\n </Box>\n )\n }\n // Guard against missing text property\n const text = item.text || ''\n const lines = text.split('\\n').length\n return (\n <OutputLine\n key={i}\n content={text}\n lines={lines}\n verbose={verbose}\n />\n )\n })}\n </Box>\n )\n }\n\n // Guard against non-string output\n if (typeof output !== 'string') {\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().secondaryText}>\n MCP operation completed\n </Text>\n </Box>\n </Box>\n )\n }\n\n const lines = output.split('\\n').length\n return <OutputLine content={output} lines={lines} verbose={verbose} />\n },\n renderResultForAssistant(content) {\n return content\n },\n} satisfies Tool
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { type Tool } from '@tool'\nimport { getTheme } from '@utils/theme'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { OutputLine } from '@tools/BashTool/OutputLine'\n\n// Allow any input object since MCP tools define their own schemas\nconst inputSchema = z.object({}).passthrough()\n\nexport const MCPTool = {\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MCPTool can modify state through MCP calls, not safe for concurrent execution\n },\n // Overridden in mcpClient.ts\n name: 'mcp',\n // Overridden in mcpClient.ts\n async description() {\n return DESCRIPTION\n },\n // Overridden in mcpClient.ts\n async prompt() {\n return PROMPT\n },\n inputSchema,\n // Overridden in mcpClient.ts\n async *call() {\n yield {\n type: 'result',\n data: '',\n resultForAssistant: '',\n }\n },\n needsPermissions() {\n return true\n },\n renderToolUseMessage(input) {\n return Object.entries(input)\n .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)\n .join(', ')\n },\n // Overridden in mcpClient.ts\n userFacingName: () => 'mcp',\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n const verbose = false // Set default value for verbose\n\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().secondaryText}>(No content)</Text>\n </Box>\n </Box>\n )\n }\n\n if (Array.isArray(output)) {\n return (\n <Box flexDirection=\"column\">\n {output.map((item, i) => {\n // Guard against null/undefined items in array\n if (!item) {\n return null\n }\n if (item.type === 'image') {\n return (\n <Box\n key={i}\n justifyContent=\"space-between\"\n overflowX=\"hidden\"\n width=\"100%\"\n >\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text>[Image]</Text>\n </Box>\n </Box>\n )\n }\n // Guard against missing text property\n const text = item.text || ''\n const lines = text.split('\\n').length\n return (\n <OutputLine\n key={i}\n content={text}\n lines={lines}\n verbose={verbose}\n />\n )\n })}\n </Box>\n )\n }\n\n // Guard against non-string output\n if (typeof output !== 'string') {\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().secondaryText}>\n MCP operation completed\n </Text>\n </Box>\n </Box>\n )\n }\n\n const lines = output.split('\\n').length\n return <OutputLine content={output} lines={lines} verbose={verbose} />\n },\n renderResultForAssistant(content) {\n return content\n },\n} satisfies Tool\n"],
|
|
5
5
|
"mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAE/C,SAAS,gBAAgB;AACzB,SAAS,aAAa,cAAc;AACpC,SAAS,kBAAkB;AAG3B,MAAM,cAAc,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAEtC,MAAM,UAAU;AAAA,EACrB,MAAM,YAAY;AAChB,WAAO;AAAA,EACT;AAAA,EACA,aAAa;AACX,WAAO;AAAA,EACT;AAAA,EACA,oBAAoB;AAClB,WAAO;AAAA,EACT;AAAA;AAAA,EAEA,MAAM;AAAA;AAAA,EAEN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA;AAAA,EAEA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA;AAAA;AAAA,EAEA,OAAO,OAAO;AACZ,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA,MACN,oBAAoB;AAAA,IACtB;AAAA,EACF;AAAA,EACA,mBAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EACA,qBAAqB,OAAO;AAC1B,WAAO,OAAO,QAAQ,KAAK,EACxB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,KAAK,KAAK,UAAU,KAAK,CAAC,EAAE,EACxD,KAAK,IAAI;AAAA,EACd;AAAA;AAAA,EAEA,gBAAgB,MAAM;AAAA,EACtB,+BAA+B;AAC7B,WAAO,oCAAC,oCAA+B;AAAA,EACzC;AAAA,EACA,wBAAwB,QAAQ;AAC9B,UAAM,UAAU;AAGhB,QAAI,CAAC,QAAQ;AACX,aACE,oCAAC,OAAI,gBAAe,iBAAgB,WAAU,UAAS,OAAM,UAC3D,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,iBAAe,cAAY,CACrD,CACF;AAAA,IAEJ;AAEA,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,aACE,oCAAC,OAAI,eAAc,YAChB,OAAO,IAAI,CAAC,MAAM,MAAM;AAEvB,YAAI,CAAC,MAAM;AACT,iBAAO;AAAA,QACT;AACA,YAAI,KAAK,SAAS,SAAS;AACzB,iBACE;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,gBAAe;AAAA,cACf,WAAU;AAAA,cACV,OAAM;AAAA;AAAA,YAEN,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,YAAK,SAAO,CACf;AAAA,UACF;AAAA,QAEJ;AAEA,cAAM,OAAO,KAAK,QAAQ;AAC1B,cAAMA,SAAQ,KAAK,MAAM,IAAI,EAAE;AAC/B,eACE;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,SAAS;AAAA,YACT,OAAOA;AAAA,YACP;AAAA;AAAA,QACF;AAAA,MAEJ,CAAC,CACH;AAAA,IAEJ;AAGA,QAAI,OAAO,WAAW,UAAU;AAC9B,aACE,oCAAC,OAAI,gBAAe,iBAAgB,WAAU,UAAS,OAAM,UAC3D,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,iBAAe,yBAEvC,CACF,CACF;AAAA,IAEJ;AAEA,UAAM,QAAQ,OAAO,MAAM,IAAI,EAAE;AACjC,WAAO,oCAAC,cAAW,SAAS,QAAQ,OAAc,SAAkB;AAAA,EACtE;AAAA,EACA,yBAAyB,SAAS;AAChC,WAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": ["lines"]
|
|
7
7
|
}
|
|
@@ -23,7 +23,8 @@ const MemoryReadTool = {
|
|
|
23
23
|
return "Read Memory";
|
|
24
24
|
},
|
|
25
25
|
async isEnabled() {
|
|
26
|
-
|
|
26
|
+
const { getGlobalConfig } = await import("../../utils/config.js");
|
|
27
|
+
return getGlobalConfig().enableMemoryTools === true;
|
|
27
28
|
},
|
|
28
29
|
isReadOnly() {
|
|
29
30
|
return true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/MemoryReadTool/MemoryReadTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { join, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { MEMORY_DIR } from '@utils/env'\nimport { resolveAgentId } from '@utils/agentStorage'\nimport { DESCRIPTION, PROMPT } from './prompt'\n\nconst inputSchema = z.strictObject({\n file_path: z\n .string()\n .optional()\n .describe('Optional path to a specific memory file to read'),\n})\n\nexport const MemoryReadTool = {\n name: 'MemoryRead',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Read Memory'\n },\n async isEnabled() {\n // Memory tools are
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,WAAW,WAAW,aAAa,oBAAoB;AAC5E,SAAS,KAAK,YAAY;AAC1B,SAAS,MAAM,eAAe;AAC9B,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAE/C,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,aAAa,cAAc;AAEpC,MAAM,cAAc,EAAE,aAAa;AAAA,EACjC,WAAW,EACR,OAAO,EACP,SAAS,EACT,SAAS,iDAAiD;AAC/D,CAAC;AAEM,MAAM,iBAAiB;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY;
|
|
4
|
+
"sourcesContent": ["import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { join, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { MEMORY_DIR } from '@utils/env'\nimport { resolveAgentId } from '@utils/agentStorage'\nimport { DESCRIPTION, PROMPT } from './prompt'\n\nconst inputSchema = z.strictObject({\n file_path: z\n .string()\n .optional()\n .describe('Optional path to a specific memory file to read'),\n})\n\nexport const MemoryReadTool = {\n name: 'MemoryRead',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Read Memory'\n },\n async isEnabled() {\n // Memory tools are opt-in via config: enableMemoryTools\n const { getGlobalConfig } = await import('@utils/config')\n return getGlobalConfig().enableMemoryTools === true\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true // MemoryRead is read-only, safe for concurrent execution\n },\n needsPermissions() {\n return false\n },\n renderResultForAssistant({ content }) {\n return content\n },\n renderToolUseMessage(input) {\n return Object.entries(input)\n .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)\n .join(', ')\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text>(No memory content)</Text>\n </Box>\n </Box>\n )\n }\n\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text>{output.content}</Text>\n </Box>\n </Box>\n )\n },\n async validateInput({ file_path }, context) {\n const agentId = resolveAgentId(context?.agentId)\n const agentMemoryDir = resolve(MEMORY_DIR, 'agents', agentId)\n\n if (file_path) {\n // Use resolve() to normalize paths and prevent path traversal attacks\n // join() alone doesn't protect against \"../\" sequences\n const fullPath = resolve(agentMemoryDir, file_path)\n if (\n !fullPath.startsWith(agentMemoryDir + '/') &&\n fullPath !== agentMemoryDir\n ) {\n return { result: false, message: 'Invalid memory file path' }\n }\n if (!existsSync(fullPath)) {\n return { result: false, message: 'Memory file does not exist' }\n }\n // Check for symlinks that could escape the directory\n try {\n const stat = lstatSync(fullPath)\n if (stat.isSymbolicLink()) {\n return {\n result: false,\n message: 'Symbolic links are not allowed in memory paths',\n }\n }\n } catch {\n // File doesn't exist or can't be accessed, will be caught above\n }\n }\n return { result: true }\n },\n async *call({ file_path }, context) {\n const agentId = resolveAgentId(context?.agentId)\n const agentMemoryDir = resolve(MEMORY_DIR, 'agents', agentId)\n mkdirSync(agentMemoryDir, { recursive: true })\n\n // If a specific file is requested, return its contents\n if (file_path) {\n const fullPath = resolve(agentMemoryDir, file_path)\n if (!existsSync(fullPath)) {\n throw new Error('Memory file does not exist')\n }\n const content = readFileSync(fullPath, 'utf-8')\n yield {\n type: 'result',\n data: {\n content,\n },\n resultForAssistant: this.renderResultForAssistant({ content }),\n }\n return\n }\n\n // Otherwise return the index and file list for this agent\n const files = readdirSync(agentMemoryDir, { recursive: true })\n .map(f => join(agentMemoryDir, f.toString()))\n .filter(f => !lstatSync(f).isDirectory())\n .map(f => `- ${f}`)\n .join('\\n')\n\n const indexPath = join(agentMemoryDir, 'index.md')\n const index = existsSync(indexPath) ? readFileSync(indexPath, 'utf-8') : ''\n\n const quotes = \"'''\"\n const content = `Here are the contents of the agent memory file, \\`${indexPath}\\`:\n${quotes}\n${index}\n${quotes}\n\nFiles in the agent memory directory:\n${files}`\n yield {\n type: 'result',\n data: { content },\n resultForAssistant: this.renderResultForAssistant({ content }),\n }\n },\n} satisfies Tool\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["content"]
|
|
7
7
|
}
|
|
@@ -25,7 +25,8 @@ const MemoryWriteTool = {
|
|
|
25
25
|
return "Write Memory";
|
|
26
26
|
},
|
|
27
27
|
async isEnabled() {
|
|
28
|
-
|
|
28
|
+
const { getGlobalConfig } = await import("../../utils/config.js");
|
|
29
|
+
return getGlobalConfig().enableMemoryTools === true;
|
|
29
30
|
},
|
|
30
31
|
isReadOnly() {
|
|
31
32
|
return false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/MemoryWriteTool/MemoryWriteTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { mkdirSync, writeFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { dirname, join, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { MEMORY_DIR } from '@utils/env'\nimport { resolveAgentId } from '@utils/agentStorage'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { DESCRIPTION, PROMPT } from './prompt'\n\nconst inputSchema = z.strictObject({\n file_path: z.string().describe('Path to the memory file to write'),\n content: z.string().describe('Content to write to the file'),\n})\n\nexport const MemoryWriteTool = {\n name: 'MemoryWrite',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Write Memory'\n },\n async isEnabled() {\n // Memory tools are
|
|
5
|
-
"mappings": "AAAA,SAAS,WAAW,qBAAqB;AACzC,SAAS,KAAK,YAAY;AAC1B,SAAS,SAAe,eAAe;AACvC,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAE/C,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,aAAa,cAAc;AAEpC,MAAM,cAAc,EAAE,aAAa;AAAA,EACjC,WAAW,EAAE,OAAO,EAAE,SAAS,kCAAkC;AAAA,EACjE,SAAS,EAAE,OAAO,EAAE,SAAS,8BAA8B;AAC7D,CAAC;AAEM,MAAM,kBAAkB;AAAA,EAC7B,MAAM;AAAA,EACN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY;
|
|
4
|
+
"sourcesContent": ["import { mkdirSync, writeFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { dirname, join, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { MEMORY_DIR } from '@utils/env'\nimport { resolveAgentId } from '@utils/agentStorage'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { DESCRIPTION, PROMPT } from './prompt'\n\nconst inputSchema = z.strictObject({\n file_path: z.string().describe('Path to the memory file to write'),\n content: z.string().describe('Content to write to the file'),\n})\n\nexport const MemoryWriteTool = {\n name: 'MemoryWrite',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Write Memory'\n },\n async isEnabled() {\n // Memory tools are opt-in via config: enableMemoryTools\n const { getGlobalConfig } = await import('@utils/config')\n return getGlobalConfig().enableMemoryTools === true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MemoryWrite modifies state, not safe for concurrent execution\n },\n needsPermissions() {\n return false\n },\n renderResultForAssistant(content) {\n return content\n },\n renderToolUseMessage(input) {\n return Object.entries(input)\n .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)\n .join(', ')\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage() {\n return (\n <Box justifyContent=\"space-between\" overflowX=\"hidden\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text>{' '}\u23BF Updated memory</Text>\n </Box>\n </Box>\n )\n },\n async validateInput({ file_path }, context) {\n const agentId = resolveAgentId(context?.agentId)\n const agentMemoryDir = resolve(MEMORY_DIR, 'agents', agentId)\n // Use resolve() to normalize paths and prevent path traversal attacks\n // join() alone doesn't protect against \"../\" sequences\n const fullPath = resolve(agentMemoryDir, file_path)\n if (\n !fullPath.startsWith(agentMemoryDir + '/') &&\n fullPath !== agentMemoryDir\n ) {\n return { result: false, message: 'Invalid memory file path' }\n }\n return { result: true }\n },\n async *call({ file_path, content }, context) {\n const agentId = resolveAgentId(context?.agentId)\n const agentMemoryDir = resolve(MEMORY_DIR, 'agents', agentId)\n const fullPath = resolve(agentMemoryDir, file_path)\n mkdirSync(dirname(fullPath), { recursive: true })\n writeFileSync(fullPath, content, 'utf-8')\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, content)\n\n yield {\n type: 'result',\n data: 'Saved',\n resultForAssistant: 'Saved',\n }\n },\n} satisfies Tool\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,WAAW,qBAAqB;AACzC,SAAS,KAAK,YAAY;AAC1B,SAAS,SAAe,eAAe;AACvC,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAE/C,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B,SAAS,aAAa,cAAc;AAEpC,MAAM,cAAc,EAAE,aAAa;AAAA,EACjC,WAAW,EAAE,OAAO,EAAE,SAAS,kCAAkC;AAAA,EACjE,SAAS,EAAE,OAAO,EAAE,SAAS,8BAA8B;AAC7D,CAAC;AAEM,MAAM,kBAAkB;AAAA,EAC7B,MAAM;AAAA,EACN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY;AAEhB,UAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,eAAe;AACxD,WAAO,gBAAgB,EAAE,sBAAsB;AAAA,EACjD;AAAA,EACA,aAAa;AACX,WAAO;AAAA,EACT;AAAA,EACA,oBAAoB;AAClB,WAAO;AAAA,EACT;AAAA,EACA,mBAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EACA,yBAAyB,SAAS;AAChC,WAAO;AAAA,EACT;AAAA,EACA,qBAAqB,OAAO;AAC1B,WAAO,OAAO,QAAQ,KAAK,EACxB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,KAAK,KAAK,UAAU,KAAK,CAAC,EAAE,EACxD,KAAK,IAAI;AAAA,EACd;AAAA,EACA,+BAA+B;AAC7B,WAAO,oCAAC,oCAA+B;AAAA,EACzC;AAAA,EACA,0BAA0B;AACxB,WACE,oCAAC,OAAI,gBAAe,iBAAgB,WAAU,UAAS,OAAM,UAC3D,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAM,MAAK,uBAAgB,CAC9B,CACF;AAAA,EAEJ;AAAA,EACA,MAAM,cAAc,EAAE,UAAU,GAAG,SAAS;AAC1C,UAAM,UAAU,eAAe,SAAS,OAAO;AAC/C,UAAM,iBAAiB,QAAQ,YAAY,UAAU,OAAO;AAG5D,UAAM,WAAW,QAAQ,gBAAgB,SAAS;AAClD,QACE,CAAC,SAAS,WAAW,iBAAiB,GAAG,KACzC,aAAa,gBACb;AACA,aAAO,EAAE,QAAQ,OAAO,SAAS,2BAA2B;AAAA,IAC9D;AACA,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAAA,EACA,OAAO,KAAK,EAAE,WAAW,QAAQ,GAAG,SAAS;AAC3C,UAAM,UAAU,eAAe,SAAS,OAAO;AAC/C,UAAM,iBAAiB,QAAQ,YAAY,UAAU,OAAO;AAC5D,UAAM,WAAW,QAAQ,gBAAgB,SAAS;AAClD,cAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAChD,kBAAc,UAAU,SAAS,OAAO;AAGxC,mBAAe,UAAU,OAAO;AAEhC,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA,MACN,oBAAoB;AAAA,IACtB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/MultiEditTool/MultiEditTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, mkdirSync, readFileSync, statSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { dirname, isAbsolute, relative, resolve, sep } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FileEditToolUpdatedMessage } from '@components/FileEditToolUpdatedMessage'\nimport { StructuredDiff } from '@components/StructuredDiff'\nimport { Tool, ValidationResult } from '@tool'\nimport { intersperse } from '@utils/array'\nimport {\n addLineNumbers,\n detectFileEncoding,\n detectLineEndings,\n findSimilarFile,\n writeTextContent,\n} from '@utils/file'\nimport { logError } from '@utils/log'\nimport { getCwd } from '@utils/state'\nimport { getTheme } from '@utils/theme'\nimport { NotebookEditTool } from '@tools/NotebookEditTool/NotebookEditTool'\n// Local content-based edit function for MultiEditTool\nfunction applyContentEdit(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false,\n): { newContent: string; occurrences: number } {\n if (replaceAll) {\n const regex = new RegExp(\n oldString.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n 'g',\n )\n const matches = content.match(regex)\n const occurrences = matches ? matches.length : 0\n const newContent = content.replace(regex, newString)\n return { newContent, occurrences }\n } else {\n if (content.includes(oldString)) {\n const newContent = content.replace(oldString, newString)\n return { newContent, occurrences: 1 }\n } else {\n throw new Error(`String not found: ${oldString.substring(0, 50)}...`)\n }\n }\n}\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { PROJECT_FILE } from '@constants/product'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { getPatch } from '@utils/diff'\nimport { triggerBackup } from '@core/backupHook'\n\nconst EditSchema = z.object({\n old_string: z.string().describe('The text to replace'),\n new_string: z.string().describe('The text to replace it with'),\n replace_all: z\n .boolean()\n .optional()\n .default(false)\n .describe('Replace all occurences of old_string (default false)'),\n})\n\nconst inputSchema = z.strictObject({\n file_path: z.string().describe('The absolute path to the file to modify'),\n edits: z\n .array(EditSchema)\n .min(1)\n .describe('Array of edit operations to perform sequentially on the file'),\n})\n\nexport type In = typeof inputSchema\n\n// Number of lines of context to include before/after the change in our result message\nconst N_LINES_SNIPPET = 4\n\nexport const MultiEditTool = {\n name: 'MultiEdit',\n async description() {\n return 'A tool for making multiple edits to a single file atomically'\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Multi-Edit'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MultiEdit modifies files, not safe for concurrent execution\n },\n needsPermissions(input?: z.infer<typeof inputSchema>) {\n if (!input) return true\n return !hasWritePermission(input.file_path)\n },\n renderResultForAssistant(content) {\n return content\n },\n renderToolUseMessage(input, { verbose }) {\n const { file_path, edits } = input\n const workingDir = getCwd()\n const relativePath = isAbsolute(file_path)\n ? relative(workingDir, file_path)\n : file_path\n\n if (verbose) {\n const editSummary = edits\n .map(\n (edit, index) =>\n `${index + 1}. Replace \"${edit.old_string.substring(0, 50)}${edit.old_string.length > 50 ? '...' : ''}\" with \"${edit.new_string.substring(0, 50)}${edit.new_string.length > 50 ? '...' : ''}\"`,\n )\n .join('\\n')\n return `Multiple edits to ${relativePath}:\\n${editSummary}`\n }\n\n return `Making ${edits.length} edits to ${relativePath}`\n },\n renderToolUseRejectedMessage() {\n return (\n <Box>\n <Text color={getTheme().error}>\u26A0 Edit request rejected</Text>\n </Box>\n )\n },\n renderToolResultMessage(output, options?: { verbose?: boolean }) {\n const verbose = options?.verbose ?? false\n\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text color={getTheme().secondaryText}>Multi-edit completed</Text>\n </Box>\n )\n }\n\n if (typeof output === 'string') {\n const isError = output.includes('Error:')\n return (\n <Box flexDirection=\"column\">\n <Text color={isError ? getTheme().error : getTheme().success}>\n {output}\n </Text>\n </Box>\n )\n }\n\n return (\n <FileEditToolUpdatedMessage\n filePath={output.filePath}\n structuredPatch={output.structuredPatch}\n verbose={verbose}\n />\n )\n },\n async validateInput(\n { file_path, edits }: z.infer<typeof inputSchema>,\n context?: { readFileTimestamps?: Record<string, number> },\n ): Promise<ValidationResult> {\n const workingDir = getCwd()\n const normalizedPath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n // Check if it's a notebook file\n if (normalizedPath.endsWith('.ipynb')) {\n return {\n result: false,\n errorCode: 1,\n message: `For Jupyter notebooks (.ipynb files), use the ${NotebookEditTool.name} tool instead.`,\n }\n }\n\n // For new files, check parent directory exists\n if (!existsSync(normalizedPath)) {\n const parentDir = dirname(normalizedPath)\n if (!existsSync(parentDir)) {\n return {\n result: false,\n errorCode: 2,\n message: `Parent directory does not exist: ${parentDir}`,\n }\n }\n\n // For new files, ensure first edit creates the file (empty old_string)\n if (edits.length === 0 || edits[0].old_string !== '') {\n return {\n result: false,\n errorCode: 6,\n message:\n 'For new files, the first edit must have an empty old_string to create the file content.',\n }\n }\n } else {\n // For existing files, apply file protection mechanisms\n const readFileTimestamps = context?.readFileTimestamps || {}\n const readTimestamp = readFileTimestamps[normalizedPath]\n\n if (!readTimestamp) {\n return {\n result: false,\n errorCode: 7,\n message:\n 'File has not been read yet. Read it first before editing it.',\n meta: {\n filePath: normalizedPath,\n isFilePathAbsolute: String(isAbsolute(file_path)),\n },\n }\n }\n\n // Check if file has been modified since last read\n const stats = statSync(normalizedPath)\n const lastWriteTime = stats.mtimeMs\n if (lastWriteTime > readTimestamp) {\n return {\n result: false,\n errorCode: 8,\n message:\n 'File has been modified since read, either by the user or by a linter. Read it again before attempting to edit it.',\n meta: {\n filePath: normalizedPath,\n lastWriteTime,\n readTimestamp,\n },\n }\n }\n\n // Pre-validate that all old_strings exist in the file\n const encoding = detectFileEncoding(normalizedPath)\n if (encoding === 'binary') {\n return {\n result: false,\n errorCode: 9,\n message: 'Cannot edit binary files.',\n }\n }\n\n const currentContent = readFileSync(normalizedPath, 'utf-8')\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (\n edit.old_string !== '' &&\n !currentContent.includes(edit.old_string)\n ) {\n return {\n result: false,\n errorCode: 10,\n message: `Edit ${i + 1}: String to replace not found in file: \"${edit.old_string.substring(0, 100)}${edit.old_string.length > 100 ? '...' : ''}\"`,\n meta: {\n editIndex: i + 1,\n oldString: edit.old_string.substring(0, 200),\n },\n }\n }\n }\n }\n\n // Validate each edit\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (edit.old_string === edit.new_string) {\n return {\n result: false,\n errorCode: 3,\n message: `Edit ${i + 1}: old_string and new_string cannot be the same`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ file_path, edits }, { readFileTimestamps }) {\n const startTime = Date.now()\n const workingDir = getCwd()\n const filePath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n try {\n // Read current file content (or empty for new files)\n let currentContent = ''\n let fileExists = existsSync(filePath)\n\n if (fileExists) {\n const encoding = detectFileEncoding(filePath)\n if (encoding === 'binary') {\n yield {\n type: 'result',\n data: 'Error: Cannot edit binary files',\n resultForAssistant: 'Error: Cannot edit binary files',\n }\n return\n }\n currentContent = readFileSync(filePath, 'utf-8')\n } else {\n // For new files, ensure parent directory exists\n const parentDir = dirname(filePath)\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true })\n }\n }\n\n // Apply all edits sequentially with progress updates\n let modifiedContent = currentContent\n const appliedEdits = []\n const totalEdits = edits.length\n\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n const { old_string, new_string, replace_all } = edit\n\n // Yield progress update for multi-edit operations\n if (totalEdits > 1) {\n yield {\n type: 'progress',\n content: {\n type: 'streaming',\n toolName: 'Multi-Edit',\n stdout: `Applying edit ${i + 1}/${totalEdits}...`,\n stderr: '',\n isStreaming: true,\n },\n }\n }\n\n try {\n const result = applyContentEdit(\n modifiedContent,\n old_string,\n new_string,\n replace_all,\n )\n modifiedContent = result.newContent\n appliedEdits.push({\n editIndex: i + 1,\n success: true,\n old_string: old_string.substring(0, 100),\n new_string: new_string.substring(0, 100),\n occurrences: result.occurrences,\n })\n } catch (error) {\n // If any edit fails, abort the entire operation\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error'\n yield {\n type: 'result',\n data: `Error in edit ${i + 1}: ${errorMessage}`,\n resultForAssistant: `Error in edit ${i + 1}: ${errorMessage}`,\n }\n return\n }\n }\n\n // Write the modified content\n const lineEndings = fileExists ? detectLineEndings(currentContent) : 'LF'\n const encoding = fileExists ? detectFileEncoding(filePath) : 'utf8'\n writeTextContent(filePath, modifiedContent, encoding, lineEndings)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(filePath, modifiedContent)\n triggerBackup(\n filePath,\n currentContent || null,\n modifiedContent,\n fileExists ? 'update' : 'create',\n )\n\n // Update readFileTimestamps to prevent stale file warnings\n readFileTimestamps[filePath] = Date.now()\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath,\n edits: edits.map(e => ({\n oldString: e.old_string,\n newString: e.new_string,\n })),\n originalContent: currentContent,\n newContent: modifiedContent,\n timestamp: Date.now(),\n operation: fileExists ? 'update' : 'create',\n })\n\n // Generate result data\n const relativePath = relative(workingDir, filePath)\n const summary = `Successfully applied ${edits.length} edits to ${relativePath}`\n\n const structuredPatch = getPatch({\n filePath: file_path,\n fileContents: currentContent,\n oldStr: currentContent,\n newStr: modifiedContent,\n })\n\n const resultData = {\n filePath: file_path,\n wasNewFile: !fileExists,\n editsApplied: appliedEdits,\n totalEdits: edits.length,\n summary,\n structuredPatch,\n }\n\n // Log the operation\n\n yield {\n type: 'result',\n data: resultData,\n resultForAssistant: summary,\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n const errorResult = `Error applying multi-edit: ${errorMessage}`\n\n logError(error)\n\n yield {\n type: 'result',\n data: errorResult,\n resultForAssistant: errorResult,\n }\n }\n },\n} satisfies Tool<typeof inputSchema, any>\n"],
|
|
4
|
+
"sourcesContent": ["import { existsSync, mkdirSync, readFileSync, statSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { dirname, isAbsolute, relative, resolve, sep } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FileEditToolUpdatedMessage } from '@components/FileEditToolUpdatedMessage'\nimport { StructuredDiff } from '@components/StructuredDiff'\nimport { Tool, ValidationResult } from '@tool'\nimport { intersperse } from '@utils/array'\nimport {\n addLineNumbers,\n detectFileEncoding,\n detectLineEndings,\n findSimilarFile,\n writeTextContent,\n} from '@utils/file'\nimport { logError } from '@utils/log'\nimport { getCwd } from '@utils/state'\nimport { getTheme } from '@utils/theme'\nimport { NotebookEditTool } from '@tools/NotebookEditTool/NotebookEditTool'\n// Local content-based edit function for MultiEditTool\nfunction applyContentEdit(\n content: string,\n oldString: string,\n newString: string,\n replaceAll: boolean = false,\n): { newContent: string; occurrences: number } {\n if (replaceAll) {\n const regex = new RegExp(\n oldString.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n 'g',\n )\n const matches = content.match(regex)\n const occurrences = matches ? matches.length : 0\n const newContent = content.replace(regex, newString)\n return { newContent, occurrences }\n } else {\n if (content.includes(oldString)) {\n const newContent = content.replace(oldString, newString)\n return { newContent, occurrences: 1 }\n } else {\n throw new Error(`String not found: ${oldString.substring(0, 50)}...`)\n }\n }\n}\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { PROJECT_FILE } from '@constants/product'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { getPatch } from '@utils/diff'\nimport { triggerBackup } from '@core/backupHook'\n\nconst EditSchema = z.object({\n old_string: z.string().describe('The text to replace'),\n new_string: z.string().describe('The text to replace it with'),\n replace_all: z\n .boolean()\n .optional()\n .default(false)\n .describe('Replace all occurences of old_string (default false)'),\n})\n\nconst inputSchema = z.strictObject({\n file_path: z.string().describe('The absolute path to the file to modify'),\n edits: z\n .array(EditSchema)\n .min(1)\n .describe('Array of edit operations to perform sequentially on the file'),\n})\n\nexport type In = typeof inputSchema\n\n// Number of lines of context to include before/after the change in our result message\nconst N_LINES_SNIPPET = 4\n\nexport const MultiEditTool = {\n name: 'MultiEdit',\n async description() {\n return 'A tool for making multiple edits to a single file atomically'\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Multi-Edit'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // MultiEdit modifies files, not safe for concurrent execution\n },\n needsPermissions(input?: z.infer<typeof inputSchema>) {\n if (!input) return true\n return !hasWritePermission(input.file_path)\n },\n renderResultForAssistant(content) {\n return content\n },\n renderToolUseMessage(input, { verbose }) {\n const { file_path, edits } = input\n const workingDir = getCwd()\n const relativePath = isAbsolute(file_path)\n ? relative(workingDir, file_path)\n : file_path\n\n if (verbose) {\n const editSummary = edits\n .map(\n (edit, index) =>\n `${index + 1}. Replace \"${edit.old_string.substring(0, 50)}${edit.old_string.length > 50 ? '...' : ''}\" with \"${edit.new_string.substring(0, 50)}${edit.new_string.length > 50 ? '...' : ''}\"`,\n )\n .join('\\n')\n return `Multiple edits to ${relativePath}:\\n${editSummary}`\n }\n\n return `Making ${edits.length} edits to ${relativePath}`\n },\n renderToolUseRejectedMessage() {\n return (\n <Box>\n <Text color={getTheme().error}>\u26A0 Edit request rejected</Text>\n </Box>\n )\n },\n renderToolResultMessage(output, options?: { verbose?: boolean }) {\n const verbose = options?.verbose ?? false\n\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text color={getTheme().secondaryText}>Multi-edit completed</Text>\n </Box>\n )\n }\n\n if (typeof output === 'string') {\n const isError = output.includes('Error:')\n return (\n <Box flexDirection=\"column\">\n <Text color={isError ? getTheme().error : getTheme().success}>\n {output}\n </Text>\n </Box>\n )\n }\n\n return (\n <FileEditToolUpdatedMessage\n filePath={output.filePath}\n structuredPatch={output.structuredPatch}\n verbose={verbose}\n />\n )\n },\n async validateInput(\n { file_path, edits }: z.infer<typeof inputSchema>,\n context?: { readFileTimestamps?: Record<string, number> },\n ): Promise<ValidationResult> {\n const workingDir = getCwd()\n const normalizedPath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n // Check if it's a notebook file\n if (normalizedPath.endsWith('.ipynb')) {\n return {\n result: false,\n errorCode: 1,\n message: `For Jupyter notebooks (.ipynb files), use the ${NotebookEditTool.name} tool instead.`,\n }\n }\n\n // For new files, check parent directory exists\n if (!existsSync(normalizedPath)) {\n const parentDir = dirname(normalizedPath)\n if (!existsSync(parentDir)) {\n return {\n result: false,\n errorCode: 2,\n message: `Parent directory does not exist: ${parentDir}`,\n }\n }\n\n // For new files, ensure first edit creates the file (empty old_string)\n if (edits.length === 0 || edits[0].old_string !== '') {\n return {\n result: false,\n errorCode: 6,\n message:\n 'For new files, the first edit must have an empty old_string to create the file content.',\n }\n }\n } else {\n // For existing files, apply file protection mechanisms\n const readFileTimestamps = context?.readFileTimestamps || {}\n const readTimestamp = readFileTimestamps[normalizedPath]\n\n if (!readTimestamp) {\n return {\n result: false,\n errorCode: 7,\n message:\n 'File has not been read yet. Read it first before editing it.',\n meta: {\n filePath: normalizedPath,\n isFilePathAbsolute: String(isAbsolute(file_path)),\n },\n }\n }\n\n // Check if file has been modified since last read\n const stats = statSync(normalizedPath)\n const lastWriteTime = stats.mtimeMs\n if (lastWriteTime > readTimestamp) {\n return {\n result: false,\n errorCode: 8,\n message:\n 'File has been modified since read, either by the user or by a linter. Read it again before attempting to edit it.',\n meta: {\n filePath: normalizedPath,\n lastWriteTime,\n readTimestamp,\n },\n }\n }\n\n // Pre-validate that all old_strings exist in the file\n const encoding = detectFileEncoding(normalizedPath)\n if (encoding === 'binary') {\n return {\n result: false,\n errorCode: 9,\n message: 'Cannot edit binary files.',\n }\n }\n\n const currentContent = readFileSync(normalizedPath, 'utf-8')\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (\n edit.old_string !== '' &&\n !currentContent.includes(edit.old_string)\n ) {\n return {\n result: false,\n errorCode: 10,\n message: `Edit ${i + 1}: String to replace not found in file: \"${edit.old_string.substring(0, 100)}${edit.old_string.length > 100 ? '...' : ''}\"`,\n meta: {\n editIndex: i + 1,\n oldString: edit.old_string.substring(0, 200),\n },\n }\n }\n }\n }\n\n // Validate each edit\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n if (edit.old_string === edit.new_string) {\n return {\n result: false,\n errorCode: 3,\n message: `Edit ${i + 1}: old_string and new_string cannot be the same`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ file_path, edits }, { readFileTimestamps }) {\n const startTime = Date.now()\n const workingDir = getCwd()\n const filePath = isAbsolute(file_path)\n ? resolve(file_path)\n : resolve(workingDir, file_path)\n\n try {\n // Read current file content (or empty for new files)\n let currentContent = ''\n let fileExists = existsSync(filePath)\n\n if (fileExists) {\n const encoding = detectFileEncoding(filePath)\n if (encoding === 'binary') {\n yield {\n type: 'result',\n data: 'Error: Cannot edit binary files',\n resultForAssistant: 'Error: Cannot edit binary files',\n }\n return\n }\n currentContent = readFileSync(filePath, 'utf-8')\n } else {\n // For new files, ensure parent directory exists\n const parentDir = dirname(filePath)\n if (!existsSync(parentDir)) {\n mkdirSync(parentDir, { recursive: true })\n }\n }\n\n // Apply all edits sequentially with progress updates\n let modifiedContent = currentContent\n const appliedEdits = []\n const totalEdits = edits.length\n\n for (let i = 0; i < edits.length; i++) {\n const edit = edits[i]\n const { old_string, new_string, replace_all } = edit\n\n // Yield progress update for multi-edit operations\n if (totalEdits > 1) {\n yield {\n type: 'progress',\n content: {\n type: 'streaming',\n toolName: 'Multi-Edit',\n stdout: `Applying edit ${i + 1}/${totalEdits}...`,\n stderr: '',\n isStreaming: true,\n },\n }\n }\n\n try {\n const result = applyContentEdit(\n modifiedContent,\n old_string,\n new_string,\n replace_all,\n )\n modifiedContent = result.newContent\n appliedEdits.push({\n editIndex: i + 1,\n success: true,\n old_string: old_string.substring(0, 100),\n new_string: new_string.substring(0, 100),\n occurrences: result.occurrences,\n })\n } catch (error) {\n // If any edit fails, abort the entire operation\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error'\n yield {\n type: 'result',\n data: `Error in edit ${i + 1}: ${errorMessage}`,\n resultForAssistant: `Error in edit ${i + 1}: ${errorMessage}`,\n }\n return\n }\n }\n\n // Write the modified content\n const lineEndings = fileExists ? detectLineEndings(currentContent) : 'LF'\n const encoding = fileExists ? detectFileEncoding(filePath) : 'utf8'\n writeTextContent(filePath, modifiedContent, encoding, lineEndings)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(filePath, modifiedContent)\n triggerBackup(\n filePath,\n currentContent || null,\n modifiedContent,\n fileExists ? 'update' : 'create',\n )\n\n // Update readFileTimestamps to prevent stale file warnings\n readFileTimestamps[filePath] = Date.now()\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath,\n edits: edits.map(e => ({\n oldString: e.old_string,\n newString: e.new_string,\n })),\n originalContent: currentContent,\n newContent: modifiedContent,\n timestamp: Date.now(),\n operation: fileExists ? 'update' : 'create',\n })\n\n // Generate result data\n const relativePath = relative(workingDir, filePath)\n const summary = `Successfully applied ${edits.length} edits to ${relativePath}`\n\n const structuredPatch = getPatch({\n filePath: file_path,\n fileContents: currentContent,\n oldStr: currentContent,\n newStr: modifiedContent,\n })\n\n const resultData = {\n filePath: file_path,\n wasNewFile: !fileExists,\n editsApplied: appliedEdits,\n totalEdits: edits.length,\n summary,\n structuredPatch,\n }\n\n // Log the operation\n\n yield {\n type: 'result',\n data: resultData,\n resultForAssistant: summary,\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n const errorResult = `Error applying multi-edit: ${errorMessage}`\n\n logError(error)\n\n yield {\n type: 'result',\n data: errorResult,\n resultForAssistant: errorResult,\n }\n }\n },\n} satisfies Tool\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["encoding"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/NotebookEditTool/NotebookEditTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { HighlightedCode } from '@components/HighlightedCode'\nimport type { Tool } from '@tool'\nimport { NotebookCellType, NotebookContent } from '@minto-types/notebook'\nimport {\n detectFileEncoding,\n detectLineEndings,\n writeTextContent,\n} from '@utils/file'\nimport { safeParseJSON } from '@utils/json'\nimport { getCwd } from '@utils/state'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { triggerBackup } from '@core/backupHook'\nimport { FileEditTool } from '@tools/FileEditTool/FileEditTool'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)',\n ),\n cell_id: z\n .string()\n .optional()\n .describe(\n 'The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified.',\n ),\n new_source: z.string().describe('The new source for the cell'),\n cell_type: z\n .enum(['code', 'markdown'])\n .optional()\n .describe(\n 'The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.',\n ),\n edit_mode: z\n .enum(['replace', 'insert', 'delete'])\n .optional()\n .describe(\n 'The type of edit to make (replace, insert, delete). Defaults to replace.',\n ),\n})\n\nexport const NotebookEditTool = {\n name: 'NotebookEdit',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Edit Notebook'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // NotebookEditTool modifies state/files, not safe for concurrent execution\n },\n needsPermissions({ notebook_path }) {\n return !hasWritePermission(notebook_path)\n },\n renderResultForAssistant({ cell_id, edit_mode, new_source, error }) {\n if (error) {\n return error\n }\n switch (edit_mode) {\n case 'replace':\n return `Updated cell ${cell_id} with ${new_source}`\n case 'insert':\n return `Inserted cell after ${cell_id || 'beginning'} with ${new_source}`\n case 'delete':\n return `Deleted cell ${cell_id}`\n }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell_id: ${input.cell_id || '(beginning)'}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? 'replace'}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text>Notebook cell updated</Text>\n </Box>\n )\n }\n\n const { cell_id, new_source, language, error } = output\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text>Updated cell {cell_id}:</Text>\n <Box marginLeft={2}>\n <HighlightedCode code={new_source} language={language} />\n </Box>\n </Box>\n )\n },\n async validateInput({\n notebook_path,\n cell_id,\n cell_type,\n edit_mode = 'replace',\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullPath)) {\n return {\n result: false,\n message: 'Notebook file does not exist.',\n }\n }\n\n if (extname(fullPath) !== '.ipynb') {\n return {\n result: false,\n message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`,\n }\n }\n\n if (edit_mode === 'insert' && !cell_type) {\n return {\n result: false,\n message: 'Cell type is required when using edit_mode=insert.',\n }\n }\n\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = safeParseJSON(content) as NotebookContent | null\n if (!notebook) {\n return {\n result: false,\n message: 'Notebook is not valid JSON.',\n }\n }\n\n // For replace and delete, cell_id is required and must exist\n if ((edit_mode === 'replace' || edit_mode === 'delete') && !cell_id) {\n return {\n result: false,\n message: 'cell_id is required for replace and delete operations.',\n }\n }\n\n // Validate cell_id exists in notebook (if provided)\n if (cell_id) {\n const cellIndex = notebook.cells.findIndex(\n (cell: { id?: string }, index: number) =>\n cell.id === cell_id || String(index) === cell_id,\n )\n if (cellIndex === -1 && edit_mode !== 'insert') {\n return {\n result: false,\n message: `Cell with ID '${cell_id}' not found in notebook. Available cells: ${notebook.cells.length}`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ notebook_path, cell_id, new_source, cell_type, edit_mode }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n try {\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n\n // Find cell index by ID (or treat cell_id as index string for backward compatibility)\n const findCellIndex = (id: string | undefined): number => {\n if (!id) return 0 // Insert at beginning if no cell_id\n const byId = notebook.cells.findIndex(\n (cell: { id?: string }) => cell.id === id,\n )\n if (byId !== -1) return byId\n // Fallback: treat as numeric index for backward compatibility\n const numIndex = parseInt(id, 10)\n if (\n !isNaN(numIndex) &&\n numIndex >= 0 &&\n numIndex < notebook.cells.length\n ) {\n return numIndex\n }\n return -1\n }\n\n const cellIndex = findCellIndex(cell_id)\n\n if (edit_mode === 'delete') {\n // Delete the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n notebook.cells.splice(cellIndex, 1)\n } else if (edit_mode === 'insert') {\n // Insert the new cell after the specified cell (or at beginning if no cell_id)\n const insertIndex = cell_id ? cellIndex + 1 : 0\n const newCellId = `cell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n const new_cell = {\n id: newCellId,\n cell_type: cell_type!, // validateInput ensures cell_type is not undefined\n source: new_source,\n metadata: {},\n }\n notebook.cells.splice(\n insertIndex,\n 0,\n cell_type === 'markdown' ? new_cell : { ...new_cell, outputs: [] },\n )\n } else {\n // Replace: Find the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n const targetCell = notebook.cells[cellIndex]!\n targetCell.source = new_source\n // Reset execution count and clear outputs since cell was modified\n targetCell.execution_count = undefined\n targetCell.outputs = []\n if (cell_type && cell_type !== targetCell.cell_type) {\n targetCell.cell_type = cell_type\n }\n }\n // Write back to file\n const endings = detectLineEndings(fullPath)\n const updatedNotebook = JSON.stringify(notebook, null, 1)\n writeTextContent(fullPath, updatedNotebook, enc, endings!)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, updatedNotebook)\n triggerBackup(fullPath, content, updatedNotebook, 'update')\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath: fullPath,\n cellId: cell_id,\n newSource: new_source,\n cellType: cell_type,\n editMode: edit_mode || 'replace',\n timestamp: Date.now(),\n operation: 'notebook_edit',\n })\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language,\n edit_mode: edit_mode ?? 'replace',\n error: '',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n } catch (error) {\n if (error instanceof Error) {\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: error.message,\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n return\n }\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: 'Unknown error occurred while editing notebook',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n {\n cell_id: string\n new_source: string\n cell_type: NotebookCellType\n language: string\n edit_mode: string\n error?: string\n }\n>\n"],
|
|
4
|
+
"sourcesContent": ["import { existsSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { HighlightedCode } from '@components/HighlightedCode'\nimport type { Tool } from '@tool'\nimport { NotebookCellType, NotebookContent } from '@minto-types/notebook'\nimport {\n detectFileEncoding,\n detectLineEndings,\n writeTextContent,\n} from '@utils/file'\nimport { safeParseJSON } from '@utils/json'\nimport { getCwd } from '@utils/state'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { triggerBackup } from '@core/backupHook'\nimport { FileEditTool } from '@tools/FileEditTool/FileEditTool'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)',\n ),\n cell_id: z\n .string()\n .optional()\n .describe(\n 'The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified.',\n ),\n new_source: z.string().describe('The new source for the cell'),\n cell_type: z\n .enum(['code', 'markdown'])\n .optional()\n .describe(\n 'The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.',\n ),\n edit_mode: z\n .enum(['replace', 'insert', 'delete'])\n .optional()\n .describe(\n 'The type of edit to make (replace, insert, delete). Defaults to replace.',\n ),\n})\n\nexport const NotebookEditTool = {\n name: 'NotebookEdit',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Edit Notebook'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // NotebookEditTool modifies state/files, not safe for concurrent execution\n },\n needsPermissions({ notebook_path }) {\n return !hasWritePermission(notebook_path)\n },\n renderResultForAssistant({ cell_id, edit_mode, new_source, error }) {\n if (error) {\n return error\n }\n switch (edit_mode) {\n case 'replace':\n return `Updated cell ${cell_id} with ${new_source}`\n case 'insert':\n return `Inserted cell after ${cell_id || 'beginning'} with ${new_source}`\n case 'delete':\n return `Deleted cell ${cell_id}`\n }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell_id: ${input.cell_id || '(beginning)'}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? 'replace'}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text>Notebook cell updated</Text>\n </Box>\n )\n }\n\n const { cell_id, new_source, language, error } = output\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text>Updated cell {cell_id}:</Text>\n <Box marginLeft={2}>\n <HighlightedCode code={new_source} language={language} />\n </Box>\n </Box>\n )\n },\n async validateInput({\n notebook_path,\n cell_id,\n cell_type,\n edit_mode = 'replace',\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullPath)) {\n return {\n result: false,\n message: 'Notebook file does not exist.',\n }\n }\n\n if (extname(fullPath) !== '.ipynb') {\n return {\n result: false,\n message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`,\n }\n }\n\n if (edit_mode === 'insert' && !cell_type) {\n return {\n result: false,\n message: 'Cell type is required when using edit_mode=insert.',\n }\n }\n\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = safeParseJSON(content) as NotebookContent | null\n if (!notebook) {\n return {\n result: false,\n message: 'Notebook is not valid JSON.',\n }\n }\n\n // For replace and delete, cell_id is required and must exist\n if ((edit_mode === 'replace' || edit_mode === 'delete') && !cell_id) {\n return {\n result: false,\n message: 'cell_id is required for replace and delete operations.',\n }\n }\n\n // Validate cell_id exists in notebook (if provided)\n if (cell_id) {\n const cellIndex = notebook.cells.findIndex(\n (cell: { id?: string }, index: number) =>\n cell.id === cell_id || String(index) === cell_id,\n )\n if (cellIndex === -1 && edit_mode !== 'insert') {\n return {\n result: false,\n message: `Cell with ID '${cell_id}' not found in notebook. Available cells: ${notebook.cells.length}`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ notebook_path, cell_id, new_source, cell_type, edit_mode }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n try {\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n\n // Find cell index by ID (or treat cell_id as index string for backward compatibility)\n const findCellIndex = (id: string | undefined): number => {\n if (!id) return 0 // Insert at beginning if no cell_id\n const byId = notebook.cells.findIndex(\n (cell: { id?: string }) => cell.id === id,\n )\n if (byId !== -1) return byId\n // Fallback: treat as numeric index for backward compatibility\n const numIndex = parseInt(id, 10)\n if (\n !isNaN(numIndex) &&\n numIndex >= 0 &&\n numIndex < notebook.cells.length\n ) {\n return numIndex\n }\n return -1\n }\n\n const cellIndex = findCellIndex(cell_id)\n\n if (edit_mode === 'delete') {\n // Delete the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n notebook.cells.splice(cellIndex, 1)\n } else if (edit_mode === 'insert') {\n // Insert the new cell after the specified cell (or at beginning if no cell_id)\n const insertIndex = cell_id ? cellIndex + 1 : 0\n const newCellId = `cell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n const new_cell = {\n id: newCellId,\n cell_type: cell_type!, // validateInput ensures cell_type is not undefined\n source: new_source,\n metadata: {},\n }\n notebook.cells.splice(\n insertIndex,\n 0,\n cell_type === 'markdown' ? new_cell : { ...new_cell, outputs: [] },\n )\n } else {\n // Replace: Find the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n const targetCell = notebook.cells[cellIndex]!\n targetCell.source = new_source\n // Reset execution count and clear outputs since cell was modified\n targetCell.execution_count = undefined\n targetCell.outputs = []\n if (cell_type && cell_type !== targetCell.cell_type) {\n targetCell.cell_type = cell_type\n }\n }\n // Write back to file\n const endings = detectLineEndings(fullPath)\n const updatedNotebook = JSON.stringify(notebook, null, 1)\n writeTextContent(fullPath, updatedNotebook, enc, endings!)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, updatedNotebook)\n triggerBackup(fullPath, content, updatedNotebook, 'update')\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath: fullPath,\n cellId: cell_id,\n newSource: new_source,\n cellType: cell_type,\n editMode: edit_mode || 'replace',\n timestamp: Date.now(),\n operation: 'notebook_edit',\n })\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language,\n edit_mode: edit_mode ?? 'replace',\n error: '',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n } catch (error) {\n if (error instanceof Error) {\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: error.message,\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n return\n }\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: 'Unknown error occurred while editing notebook',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n }\n },\n} satisfies Tool\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["data"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/NotebookReadTool/NotebookReadTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import type {\n ImageBlockParam,\n TextBlockParam,\n} from '@anthropic-ai/sdk/resources/index.mjs'\n\nimport { existsSync, readFileSync } from 'fs'\nimport { Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport {\n NotebookCellSource,\n NotebookContent,\n NotebookCell,\n NotebookOutputImage,\n NotebookCellSourceOutput,\n NotebookCellOutput,\n NotebookCellType,\n} from '@minto-types/notebook'\nimport { formatOutput } from '@tools/BashTool/utils'\nimport { getCwd } from '@utils/state'\nimport { findSimilarFile } from '@utils/file'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasReadPermission } from '@utils/permissions/filesystem'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to read (must be absolute, not relative)',\n ),\n})\n\ntype In = typeof inputSchema\ntype Out = NotebookCellSource[]\n\nexport const NotebookReadTool = {\n name: 'ReadNotebook',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true // NotebookReadTool is read-only, safe for concurrent execution\n },\n inputSchema,\n userFacingName() {\n return 'Read Notebook'\n },\n async isEnabled() {\n return true\n },\n needsPermissions({ notebook_path }) {\n return !hasReadPermission(notebook_path)\n },\n async validateInput({ notebook_path }) {\n const fullFilePath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullFilePath)) {\n // Try to find a similar file with a different extension\n const similarFilename = findSimilarFile(fullFilePath)\n let message = 'File does not exist.'\n\n // If we found a similar file, suggest it to the assistant\n if (similarFilename) {\n message += ` Did you mean ${similarFilename}?`\n }\n\n return {\n result: false,\n message,\n }\n }\n\n if (extname(fullFilePath) !== '.ipynb') {\n return {\n result: false,\n message: 'File must be a Jupyter notebook (.ipynb file).',\n }\n }\n\n return { result: true }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n\n renderToolResultMessage(content) {\n if (!content) {\n return <Text>No cells found in notebook</Text>\n }\n if (content.length < 1 || !content[0]) {\n return <Text>No cells found in notebook</Text>\n }\n return <Text>Read {content.length} cells</Text>\n },\n async *call({ notebook_path }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n const content = readFileSync(fullPath, 'utf-8')\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n const cells = notebook.cells.map((cell, index) =>\n processCell(cell, index, language),\n )\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(cells),\n data: cells,\n }\n },\n renderResultForAssistant(data: NotebookCellSource[]) {\n // Guard against undefined or null data\n if (!data || !Array.isArray(data)) {\n return 'No cells found in notebook'\n }\n\n // Convert the complex structure to a string representation for the assistant\n return data\n .map((cell, index) => {\n if (!cell) return `Cell ${index + 1}: (empty)`\n let content = `Cell ${index + 1} (${cell.cellType || 'unknown'}):\\n${cell.source || ''}`\n if (\n cell.outputs &&\n Array.isArray(cell.outputs) &&\n cell.outputs.length > 0\n ) {\n const outputText = cell.outputs\n .filter(output => output != null)\n .map(output => output.text || '')\n .filter(Boolean)\n .join('\\n')\n if (outputText) {\n content += `\\nOutput:\\n${outputText}`\n }\n }\n return content\n })\n .join('\\n\\n')\n },\n} satisfies Tool
|
|
4
|
+
"sourcesContent": ["import type {\n ImageBlockParam,\n TextBlockParam,\n} from '@anthropic-ai/sdk/resources/index.mjs'\n\nimport { existsSync, readFileSync } from 'fs'\nimport { Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport {\n NotebookCellSource,\n NotebookContent,\n NotebookCell,\n NotebookOutputImage,\n NotebookCellSourceOutput,\n NotebookCellOutput,\n NotebookCellType,\n} from '@minto-types/notebook'\nimport { formatOutput } from '@tools/BashTool/utils'\nimport { getCwd } from '@utils/state'\nimport { findSimilarFile } from '@utils/file'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasReadPermission } from '@utils/permissions/filesystem'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to read (must be absolute, not relative)',\n ),\n})\n\ntype In = typeof inputSchema\ntype Out = NotebookCellSource[]\n\nexport const NotebookReadTool = {\n name: 'ReadNotebook',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true // NotebookReadTool is read-only, safe for concurrent execution\n },\n inputSchema,\n userFacingName() {\n return 'Read Notebook'\n },\n async isEnabled() {\n return true\n },\n needsPermissions({ notebook_path }) {\n return !hasReadPermission(notebook_path)\n },\n async validateInput({ notebook_path }) {\n const fullFilePath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullFilePath)) {\n // Try to find a similar file with a different extension\n const similarFilename = findSimilarFile(fullFilePath)\n let message = 'File does not exist.'\n\n // If we found a similar file, suggest it to the assistant\n if (similarFilename) {\n message += ` Did you mean ${similarFilename}?`\n }\n\n return {\n result: false,\n message,\n }\n }\n\n if (extname(fullFilePath) !== '.ipynb') {\n return {\n result: false,\n message: 'File must be a Jupyter notebook (.ipynb file).',\n }\n }\n\n return { result: true }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n\n renderToolResultMessage(content) {\n if (!content) {\n return <Text>No cells found in notebook</Text>\n }\n if (content.length < 1 || !content[0]) {\n return <Text>No cells found in notebook</Text>\n }\n return <Text>Read {content.length} cells</Text>\n },\n async *call({ notebook_path }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n const content = readFileSync(fullPath, 'utf-8')\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n const cells = notebook.cells.map((cell, index) =>\n processCell(cell, index, language),\n )\n\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(cells),\n data: cells,\n }\n },\n renderResultForAssistant(data: NotebookCellSource[]) {\n // Guard against undefined or null data\n if (!data || !Array.isArray(data)) {\n return 'No cells found in notebook'\n }\n\n // Convert the complex structure to a string representation for the assistant\n return data\n .map((cell, index) => {\n if (!cell) return `Cell ${index + 1}: (empty)`\n let content = `Cell ${index + 1} (${cell.cellType || 'unknown'}):\\n${cell.source || ''}`\n if (\n cell.outputs &&\n Array.isArray(cell.outputs) &&\n cell.outputs.length > 0\n ) {\n const outputText = cell.outputs\n .filter(output => output != null)\n .map(output => output.text || '')\n .filter(Boolean)\n .join('\\n')\n if (outputText) {\n content += `\\nOutput:\\n${outputText}`\n }\n }\n return content\n })\n .join('\\n\\n')\n },\n} satisfies Tool\n\nfunction processOutputText(text: string | string[] | undefined): string {\n if (!text) return ''\n const rawText = Array.isArray(text) ? text.join('') : text\n const { truncatedContent } = formatOutput(rawText)\n return truncatedContent\n}\n\nfunction extractImage(\n data: Record<string, unknown>,\n): NotebookOutputImage | undefined {\n if (typeof data['image/png'] === 'string') {\n return {\n image_data: data['image/png'] as string,\n media_type: 'image/png',\n }\n }\n if (typeof data['image/jpeg'] === 'string') {\n return {\n image_data: data['image/jpeg'] as string,\n media_type: 'image/jpeg',\n }\n }\n return undefined\n}\n\nfunction processOutput(output: NotebookCellOutput) {\n switch (output.output_type) {\n case 'stream':\n return {\n output_type: output.output_type,\n text: processOutputText(output.text),\n }\n case 'execute_result':\n case 'display_data':\n return {\n output_type: output.output_type,\n text: processOutputText(\n output.data?.['text/plain'] as string | string[] | undefined,\n ),\n image: output.data && extractImage(output.data),\n }\n case 'error':\n return {\n output_type: output.output_type,\n text: processOutputText(\n `${output.ename}: ${output.evalue}\\n${output.traceback.join('\\n')}`,\n ),\n }\n }\n}\n\nfunction processCell(\n cell: NotebookCell,\n index: number,\n language: string,\n): NotebookCellSource {\n const cellData: NotebookCellSource = {\n cell: index,\n cellType: cell.cell_type,\n source: Array.isArray(cell.source) ? cell.source.join('') : cell.source,\n language,\n execution_count: cell.execution_count,\n }\n\n if (cell.outputs?.length) {\n cellData.outputs = cell.outputs.map(processOutput)\n }\n\n return cellData\n}\n\nfunction cellContentToToolResult(cell: NotebookCellSource): TextBlockParam {\n const metadata = []\n if (cell.cellType !== 'code') {\n metadata.push(`<cell_type>${cell.cellType}</cell_type>`)\n }\n if (cell.language !== 'python' && cell.cellType === 'code') {\n metadata.push(`<language>${cell.language}</language>`)\n }\n const cellContent = `<cell ${cell.cell}>${metadata.join('')}${cell.source}</cell ${cell.cell}>`\n return {\n text: cellContent,\n type: 'text',\n }\n}\n\nfunction cellOutputToToolResult(output: NotebookCellSourceOutput) {\n const outputs: (TextBlockParam | ImageBlockParam)[] = []\n if (output.text) {\n outputs.push({\n text: `\\n${output.text}`,\n type: 'text',\n })\n }\n if (output.image) {\n outputs.push({\n type: 'image',\n source: {\n data: output.image.image_data,\n media_type: output.image.media_type,\n type: 'base64',\n },\n })\n }\n return outputs\n}\n\nfunction getToolResultFromCell(cell: NotebookCellSource) {\n const contentResult = cellContentToToolResult(cell)\n const outputResults = cell.outputs?.flatMap(cellOutputToToolResult)\n return [contentResult, ...(outputResults ?? [])]\n}\n\nexport function isNotebookCellType(\n value: string | null,\n): value is NotebookCellType {\n return value === 'code' || value === 'markdown'\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Box, Text } from "ink";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { enterPlanMode } from "../../utils/plan/planMode.js";
|
|
4
|
+
import { enterPlanMode, isPlanModeEnabled } from "../../utils/plan/planMode.js";
|
|
5
|
+
import { emitReminderEvent } from "../../services/systemReminder.js";
|
|
5
6
|
import { ENTER_DESCRIPTION, ENTER_PROMPT, ENTER_TOOL_NAME } from "./prompt.js";
|
|
6
7
|
import { SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
7
8
|
const inputSchema = z.strictObject({});
|
|
@@ -58,7 +59,12 @@ Remember: DO NOT write or edit any files yet. This is a read-only exploration an
|
|
|
58
59
|
if (context?.agentId) {
|
|
59
60
|
throw new Error("EnterPlanMode tool cannot be used in agent contexts");
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
+
const wasAlreadyInPlanMode = isPlanModeEnabled(context);
|
|
63
|
+
const { planFilePath } = enterPlanMode(context);
|
|
64
|
+
if (wasAlreadyInPlanMode) {
|
|
65
|
+
emitReminderEvent("plan:mode_reentry", { planPath: planFilePath });
|
|
66
|
+
}
|
|
67
|
+
emitReminderEvent("plan:file_reference", { planPath: planFilePath });
|
|
62
68
|
const output = {
|
|
63
69
|
message: "Entered plan mode. You should now focus on exploring the codebase and designing an implementation approach."
|
|
64
70
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/PlanModeTool/EnterPlanModeTool.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Enter Plan Mode Tool\n *\n * Requests permission to enter plan mode for complex tasks.\n */\n\nimport { Box, Text } from 'ink'\nimport React from 'react'\nimport { z } from 'zod'\nimport { Tool } from '@tool'\nimport { enterPlanMode } from '@utils/plan/planMode'\nimport { ENTER_DESCRIPTION, ENTER_PROMPT, ENTER_TOOL_NAME } from './prompt'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nconst inputSchema = z.strictObject({})\n\ntype Output = {\n message: string\n}\n\nexport const EnterPlanModeTool = {\n name: ENTER_TOOL_NAME,\n async description() {\n return ENTER_DESCRIPTION\n },\n userFacingName() {\n return ''\n },\n inputSchema,\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true\n },\n async isEnabled() {\n return true\n },\n needsPermissions() {\n return true\n },\n requiresUserInteraction() {\n return true\n },\n async prompt() {\n return ENTER_PROMPT\n },\n renderToolUseMessage() {\n return ''\n },\n renderToolUseRejectedMessage() {\n return (\n <Box flexDirection=\"row\" marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n User declined to enter plan mode\n </Text>\n </Box>\n )\n },\n renderToolResultMessage(_output: Output) {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text color=\"cyan\">\u25CF</Text>\n <Text> Entered plan mode</Text>\n </Box>\n <Box paddingLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>\n Minto is now exploring and designing an implementation approach.\n </Text>\n </Box>\n </Box>\n )\n },\n renderResultForAssistant(output: Output) {\n return `${output.message}\n\nIn plan mode, you should:\n1. Thoroughly explore the codebase to understand existing patterns\n2. Identify similar features and architectural approaches\n3. Consider multiple approaches and their trade-offs\n4. Use AskUserQuestion if you need to clarify the approach\n5. Design a concrete implementation strategy\n6. When ready, use ExitPlanMode to present your plan for approval\n\nRemember: DO NOT write or edit any files yet. This is a read-only exploration and planning phase.`\n },\n async *call(_input: z.infer<typeof inputSchema>, context: any) {\n if (context?.agentId) {\n throw new Error('EnterPlanMode tool cannot be used in agent contexts')\n }\n\n enterPlanMode(context)\n\n const output: Output = {\n message:\n 'Entered plan mode. You should now focus on exploring the codebase and designing an implementation approach.',\n }\n yield {\n type: 'result',\n data: output,\n resultForAssistant: this.renderResultForAssistant(output),\n }\n },\n} satisfies Tool
|
|
5
|
-
"mappings": "AAMA,SAAS,KAAK,YAAY;AAC1B,OAAO,WAAW;AAClB,SAAS,SAAS;AAElB,SAAS,
|
|
4
|
+
"sourcesContent": ["/**\n * Enter Plan Mode Tool\n *\n * Requests permission to enter plan mode for complex tasks.\n */\n\nimport { Box, Text } from 'ink'\nimport React from 'react'\nimport { z } from 'zod'\nimport { Tool } from '@tool'\nimport { enterPlanMode, isPlanModeEnabled } from '@utils/plan/planMode'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { ENTER_DESCRIPTION, ENTER_PROMPT, ENTER_TOOL_NAME } from './prompt'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nconst inputSchema = z.strictObject({})\n\ntype Output = {\n message: string\n}\n\nexport const EnterPlanModeTool = {\n name: ENTER_TOOL_NAME,\n async description() {\n return ENTER_DESCRIPTION\n },\n userFacingName() {\n return ''\n },\n inputSchema,\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true\n },\n async isEnabled() {\n return true\n },\n needsPermissions() {\n return true\n },\n requiresUserInteraction() {\n return true\n },\n async prompt() {\n return ENTER_PROMPT\n },\n renderToolUseMessage() {\n return ''\n },\n renderToolUseRejectedMessage() {\n return (\n <Box flexDirection=\"row\" marginTop={1}>\n <Text color={SEMANTIC_COLORS.dim}>\n User declined to enter plan mode\n </Text>\n </Box>\n )\n },\n renderToolResultMessage(_output: Output) {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box flexDirection=\"row\">\n <Text color=\"cyan\">\u25CF</Text>\n <Text> Entered plan mode</Text>\n </Box>\n <Box paddingLeft={2}>\n <Text color={SEMANTIC_COLORS.dim}>\n Minto is now exploring and designing an implementation approach.\n </Text>\n </Box>\n </Box>\n )\n },\n renderResultForAssistant(output: Output) {\n return `${output.message}\n\nIn plan mode, you should:\n1. Thoroughly explore the codebase to understand existing patterns\n2. Identify similar features and architectural approaches\n3. Consider multiple approaches and their trade-offs\n4. Use AskUserQuestion if you need to clarify the approach\n5. Design a concrete implementation strategy\n6. When ready, use ExitPlanMode to present your plan for approval\n\nRemember: DO NOT write or edit any files yet. This is a read-only exploration and planning phase.`\n },\n async *call(_input: z.infer<typeof inputSchema>, context: any) {\n if (context?.agentId) {\n throw new Error('EnterPlanMode tool cannot be used in agent contexts')\n }\n\n const wasAlreadyInPlanMode = isPlanModeEnabled(context)\n const { planFilePath } = enterPlanMode(context)\n\n if (wasAlreadyInPlanMode) {\n emitReminderEvent('plan:mode_reentry', { planPath: planFilePath })\n }\n emitReminderEvent('plan:file_reference', { planPath: planFilePath })\n\n const output: Output = {\n message:\n 'Entered plan mode. You should now focus on exploring the codebase and designing an implementation approach.',\n }\n yield {\n type: 'result',\n data: output,\n resultForAssistant: this.renderResultForAssistant(output),\n }\n },\n} satisfies Tool\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,KAAK,YAAY;AAC1B,OAAO,WAAW;AAClB,SAAS,SAAS;AAElB,SAAS,eAAe,yBAAyB;AACjD,SAAS,yBAAyB;AAClC,SAAS,mBAAmB,cAAc,uBAAuB;AACjE,SAAS,uBAAuB;AAEhC,MAAM,cAAc,EAAE,aAAa,CAAC,CAAC;AAM9B,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA;AAAA,EACA,aAAa;AACX,WAAO;AAAA,EACT;AAAA,EACA,oBAAoB;AAClB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY;AAChB,WAAO;AAAA,EACT;AAAA,EACA,mBAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EACA,0BAA0B;AACxB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA,uBAAuB;AACrB,WAAO;AAAA,EACT;AAAA,EACA,+BAA+B;AAC7B,WACE,oCAAC,OAAI,eAAc,OAAM,WAAW,KAClC,oCAAC,QAAK,OAAO,gBAAgB,OAAK,kCAElC,CACF;AAAA,EAEJ;AAAA,EACA,wBAAwB,SAAiB;AACvC,WACE,oCAAC,OAAI,eAAc,UAAS,WAAW,KACrC,oCAAC,OAAI,eAAc,SACjB,oCAAC,QAAK,OAAM,UAAO,QAAC,GACpB,oCAAC,YAAK,oBAAkB,CAC1B,GACA,oCAAC,OAAI,aAAa,KAChB,oCAAC,QAAK,OAAO,gBAAgB,OAAK,kEAElC,CACF,CACF;AAAA,EAEJ;AAAA,EACA,yBAAyB,QAAgB;AACvC,WAAO,GAAG,OAAO,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAW1B;AAAA,EACA,OAAO,KAAK,QAAqC,SAAc;AAC7D,QAAI,SAAS,SAAS;AACpB,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACvE;AAEA,UAAM,uBAAuB,kBAAkB,OAAO;AACtD,UAAM,EAAE,aAAa,IAAI,cAAc,OAAO;AAE9C,QAAI,sBAAsB;AACxB,wBAAkB,qBAAqB,EAAE,UAAU,aAAa,CAAC;AAAA,IACnE;AACA,sBAAkB,uBAAuB,EAAE,UAAU,aAAa,CAAC;AAEnE,UAAM,SAAiB;AAAA,MACrB,SACE;AAAA,IACJ;AACA,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,MAAM;AAAA,MACN,oBAAoB,KAAK,yBAAyB,MAAM;AAAA,IAC1D;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getPlanFilePath,
|
|
7
7
|
readPlanFile
|
|
8
8
|
} from "../../utils/plan/planMode.js";
|
|
9
|
+
import { emitReminderEvent } from "../../services/systemReminder.js";
|
|
9
10
|
import { EXIT_DESCRIPTION, EXIT_PROMPT, EXIT_TOOL_NAME } from "./prompt.js";
|
|
10
11
|
import { SEMANTIC_COLORS } from "../../constants/colors.js";
|
|
11
12
|
function getExitPlanModePlanText(conversationKey) {
|
|
@@ -90,6 +91,7 @@ ${output.plan}`;
|
|
|
90
91
|
`No plan file found at ${planFilePath}. Please write your plan to this file before calling ExitPlanMode.`
|
|
91
92
|
);
|
|
92
93
|
}
|
|
94
|
+
emitReminderEvent("plan:exited", { planPath: planFilePath });
|
|
93
95
|
const isAgent = !!context?.agentId;
|
|
94
96
|
const output = {
|
|
95
97
|
plan: content,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/PlanModeTool/ExitPlanModeTool.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Exit Plan Mode Tool\n *\n * Prompts the user to exit plan mode and start coding.\n */\n\nimport { Box, Text } from 'ink'\nimport React from 'react'\nimport { z } from 'zod'\nimport { Tool } from '@tool'\nimport {\n getPlanConversationKey,\n getPlanFilePath,\n readPlanFile,\n} from '@utils/plan/planMode'\nimport { EXIT_DESCRIPTION, EXIT_PROMPT, EXIT_TOOL_NAME } from './prompt'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nfunction getExitPlanModePlanText(conversationKey?: string): string {\n const { content } = readPlanFile(undefined, conversationKey)\n return (\n content || 'No plan found. Please write your plan to the plan file first.'\n )\n}\n\nconst inputSchema = z.strictObject({}).passthrough()\n\ntype Output = {\n plan: string\n isAgent: boolean\n filePath?: string\n}\n\nexport const ExitPlanModeTool = {\n name: EXIT_TOOL_NAME,\n async description() {\n return EXIT_DESCRIPTION\n },\n userFacingName() {\n return ''\n },\n inputSchema,\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return true\n },\n async isEnabled() {\n return true\n },\n needsPermissions() {\n return true\n },\n requiresUserInteraction() {\n return true\n },\n async prompt() {\n return EXIT_PROMPT\n },\n renderToolUseMessage() {\n return ''\n },\n renderToolUseRejectedMessage(\n _input: z.infer<typeof inputSchema>,\n options: { conversationKey?: string } = {},\n ) {\n const conversationKey =\n typeof options.conversationKey === 'string' &&\n options.conversationKey.trim()\n ? options.conversationKey.trim()\n : undefined\n\n const plan = getExitPlanModePlanText(conversationKey)\n\n return (\n <Box flexDirection=\"column\" marginTop={1} width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Box flexDirection=\"column\" width=\"100%\">\n <Text color=\"red\">User rejected the plan:</Text>\n <Box\n borderStyle=\"round\"\n borderColor=\"cyan\"\n borderDimColor\n paddingX={1}\n overflow=\"hidden\"\n >\n <Text color={SEMANTIC_COLORS.dim}>{plan}</Text>\n </Box>\n </Box>\n </Box>\n </Box>\n )\n },\n renderToolResultMessage(output: Output) {\n if (!output) {\n return (\n <Box paddingLeft={2}>\n <Text>Plan mode completed</Text>\n </Box>\n )\n }\n\n const planPath =\n typeof output.filePath === 'string' ? output.filePath : null\n const plan = output.plan || 'No plan found'\n\n return (\n <Box flexDirection=\"column\" marginTop={1} width=\"100%\">\n <Box flexDirection=\"row\">\n <Text color=\"cyan\">\u25CF</Text>\n <Text> User approved the plan</Text>\n </Box>\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Box flexDirection=\"column\">\n {planPath ? (\n <Text color={SEMANTIC_COLORS.dim}>Plan saved to: {planPath}</Text>\n ) : null}\n <Text color={SEMANTIC_COLORS.dim}>{plan.substring(0, 200)}...</Text>\n </Box>\n </Box>\n </Box>\n )\n },\n renderResultForAssistant(output: Output) {\n if (!output) {\n return 'Plan mode completed'\n }\n\n if (output.isAgent) {\n return 'User has approved the plan. There is nothing else needed from you now. Please respond with \"ok\"'\n }\n\n return `User has approved your plan. You can now start coding. Start with updating your todo list if applicable\n\nYour plan has been saved to: ${output.filePath}\nYou can refer back to it if needed during implementation.\n\n## Approved Plan:\n${output.plan}`\n },\n async *call(input: z.infer<typeof inputSchema>, context: any) {\n const conversationKey = getPlanConversationKey(context)\n const planFilePath = getPlanFilePath(context?.agentId, conversationKey)\n const { content, exists } = readPlanFile(context?.agentId, conversationKey)\n\n if (!exists) {\n throw new Error(\n `No plan file found at ${planFilePath}. Please write your plan to this file before calling ExitPlanMode.`,\n )\n }\n\n const isAgent = !!context?.agentId\n const output: Output = {\n plan: content,\n isAgent,\n filePath: planFilePath,\n }\n yield {\n type: 'result',\n data: output,\n resultForAssistant: this.renderResultForAssistant(output),\n }\n },\n} satisfies Tool
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Exit Plan Mode Tool\n *\n * Prompts the user to exit plan mode and start coding.\n */\n\nimport { Box, Text } from 'ink'\nimport React from 'react'\nimport { z } from 'zod'\nimport { Tool } from '@tool'\nimport {\n getPlanConversationKey,\n getPlanFilePath,\n readPlanFile,\n} from '@utils/plan/planMode'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { EXIT_DESCRIPTION, EXIT_PROMPT, EXIT_TOOL_NAME } from './prompt'\nimport { SEMANTIC_COLORS } from '@constants/colors'\n\nfunction getExitPlanModePlanText(conversationKey?: string): string {\n const { content } = readPlanFile(undefined, conversationKey)\n return (\n content || 'No plan found. Please write your plan to the plan file first.'\n )\n}\n\nconst inputSchema = z.strictObject({}).passthrough()\n\ntype Output = {\n plan: string\n isAgent: boolean\n filePath?: string\n}\n\nexport const ExitPlanModeTool = {\n name: EXIT_TOOL_NAME,\n async description() {\n return EXIT_DESCRIPTION\n },\n userFacingName() {\n return ''\n },\n inputSchema,\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return true\n },\n async isEnabled() {\n return true\n },\n needsPermissions() {\n return true\n },\n requiresUserInteraction() {\n return true\n },\n async prompt() {\n return EXIT_PROMPT\n },\n renderToolUseMessage() {\n return ''\n },\n renderToolUseRejectedMessage(\n _input: z.infer<typeof inputSchema>,\n options: { conversationKey?: string } = {},\n ) {\n const conversationKey =\n typeof options.conversationKey === 'string' &&\n options.conversationKey.trim()\n ? options.conversationKey.trim()\n : undefined\n\n const plan = getExitPlanModePlanText(conversationKey)\n\n return (\n <Box flexDirection=\"column\" marginTop={1} width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Box flexDirection=\"column\" width=\"100%\">\n <Text color=\"red\">User rejected the plan:</Text>\n <Box\n borderStyle=\"round\"\n borderColor=\"cyan\"\n borderDimColor\n paddingX={1}\n overflow=\"hidden\"\n >\n <Text color={SEMANTIC_COLORS.dim}>{plan}</Text>\n </Box>\n </Box>\n </Box>\n </Box>\n )\n },\n renderToolResultMessage(output: Output) {\n if (!output) {\n return (\n <Box paddingLeft={2}>\n <Text>Plan mode completed</Text>\n </Box>\n )\n }\n\n const planPath =\n typeof output.filePath === 'string' ? output.filePath : null\n const plan = output.plan || 'No plan found'\n\n return (\n <Box flexDirection=\"column\" marginTop={1} width=\"100%\">\n <Box flexDirection=\"row\">\n <Text color=\"cyan\">\u25CF</Text>\n <Text> User approved the plan</Text>\n </Box>\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Box flexDirection=\"column\">\n {planPath ? (\n <Text color={SEMANTIC_COLORS.dim}>Plan saved to: {planPath}</Text>\n ) : null}\n <Text color={SEMANTIC_COLORS.dim}>{plan.substring(0, 200)}...</Text>\n </Box>\n </Box>\n </Box>\n )\n },\n renderResultForAssistant(output: Output) {\n if (!output) {\n return 'Plan mode completed'\n }\n\n if (output.isAgent) {\n return 'User has approved the plan. There is nothing else needed from you now. Please respond with \"ok\"'\n }\n\n return `User has approved your plan. You can now start coding. Start with updating your todo list if applicable\n\nYour plan has been saved to: ${output.filePath}\nYou can refer back to it if needed during implementation.\n\n## Approved Plan:\n${output.plan}`\n },\n async *call(input: z.infer<typeof inputSchema>, context: any) {\n const conversationKey = getPlanConversationKey(context)\n const planFilePath = getPlanFilePath(context?.agentId, conversationKey)\n const { content, exists } = readPlanFile(context?.agentId, conversationKey)\n\n if (!exists) {\n throw new Error(\n `No plan file found at ${planFilePath}. Please write your plan to this file before calling ExitPlanMode.`,\n )\n }\n\n emitReminderEvent('plan:exited', { planPath: planFilePath })\n\n const isAgent = !!context?.agentId\n const output: Output = {\n plan: content,\n isAgent,\n filePath: planFilePath,\n }\n yield {\n type: 'result',\n data: output,\n resultForAssistant: this.renderResultForAssistant(output),\n }\n },\n} satisfies Tool\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/ReadMcpResourceTool/ReadMcpResourceTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { Box, Text } from 'ink'\nimport React from 'react'\nimport { z } from 'zod'\nimport { Cost } from '@components/Cost'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { readMCPResource, McpResourceContent } from '@services/mcpClient'\nimport { DESCRIPTION, TOOL_NAME_FOR_PROMPT } from './prompt'\nimport { getTheme } from '@utils/theme'\n\nconst inputSchema = z.strictObject({\n uri: z.string().describe('The URI of the resource to read'),\n server: z\n .string()\n .optional()\n .describe('Optional server name to target a specific MCP server'),\n})\n\ntype Output = {\n durationMs: number\n content: McpResourceContent | null\n error?: string\n}\n\nexport const ReadMcpResourceTool = {\n name: TOOL_NAME_FOR_PROMPT,\n async description() {\n return DESCRIPTION\n },\n userFacingName() {\n return 'Read MCP Resource'\n },\n inputSchema,\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true // Read-only operation, safe for concurrent execution\n },\n needsPermissions() {\n return false // No file system access needed\n },\n async prompt() {\n return DESCRIPTION\n },\n renderToolUseMessage({ uri, server }, { verbose }) {\n let msg = `uri: \"${uri}\"`\n if (server) {\n msg += `, server: \"${server}\"`\n }\n return msg\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n if (!output) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().error}>Failed to read resource</Text>\n </Box>\n </Box>\n )\n }\n\n // Handle string content for backward compatibility\n if (typeof output === 'string') {\n try {\n output = JSON.parse(output) as Output\n } catch {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF Read MCP resource</Text>\n </Box>\n </Box>\n )\n }\n }\n\n const durationMs = output?.durationMs ?? 0\n\n if (output?.error) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().error}>{output.error}</Text>\n </Box>\n <Cost costUSD={0} durationMs={durationMs} debug={false} />\n </Box>\n )\n }\n\n if (!output?.content) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().warning}>Resource not found</Text>\n </Box>\n <Cost costUSD={0} durationMs={durationMs} debug={false} />\n </Box>\n )\n }\n\n const contentType = output.content.mimeType || 'unknown'\n const hasText = !!output.content.text\n const hasBlob = !!output.content.blob\n\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF Read resource </Text>\n <Text color={getTheme().secondaryText}>\n ({contentType}, {hasText ? 'text' : hasBlob ? 'binary' : 'empty'})\n </Text>\n </Box>\n <Cost costUSD={0} durationMs={durationMs} debug={false} />\n </Box>\n )\n },\n async *call({ uri, server }) {\n const start = Date.now()\n\n try {\n const content = await readMCPResource(uri, server)\n const output: Output = {\n content,\n durationMs: Date.now() - start,\n }\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(output),\n data: output,\n }\n } catch (error) {\n const output: Output = {\n content: null,\n durationMs: Date.now() - start,\n error: error instanceof Error ? error.message : String(error),\n }\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(output),\n data: output,\n }\n }\n },\n renderResultForAssistant(output) {\n if (output.error) {\n return `Error reading resource: ${output.error}`\n }\n\n if (!output.content) {\n return 'Resource not found or not accessible'\n }\n\n const lines: string[] = []\n lines.push(`Resource: ${output.content.uri}`)\n\n if (output.content.mimeType) {\n lines.push(`MIME Type: ${output.content.mimeType}`)\n }\n\n lines.push('')\n\n if (output.content.text) {\n lines.push('Content:')\n lines.push(output.content.text)\n } else if (output.content.blob) {\n lines.push(\n `Binary content (base64, ${output.content.blob.length} characters)`,\n )\n // Only show first 200 chars of base64 for preview\n if (output.content.blob.length > 200) {\n lines.push(output.content.blob.substring(0, 200) + '...')\n } else {\n lines.push(output.content.blob)\n }\n } else {\n lines.push('(Empty content)')\n }\n\n return lines.join('\\n')\n },\n} satisfies Tool
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport React from 'react'\nimport { z } from 'zod'\nimport { Cost } from '@components/Cost'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { readMCPResource, McpResourceContent } from '@services/mcpClient'\nimport { DESCRIPTION, TOOL_NAME_FOR_PROMPT } from './prompt'\nimport { getTheme } from '@utils/theme'\n\nconst inputSchema = z.strictObject({\n uri: z.string().describe('The URI of the resource to read'),\n server: z\n .string()\n .optional()\n .describe('Optional server name to target a specific MCP server'),\n})\n\ntype Output = {\n durationMs: number\n content: McpResourceContent | null\n error?: string\n}\n\nexport const ReadMcpResourceTool = {\n name: TOOL_NAME_FOR_PROMPT,\n async description() {\n return DESCRIPTION\n },\n userFacingName() {\n return 'Read MCP Resource'\n },\n inputSchema,\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true // Read-only operation, safe for concurrent execution\n },\n needsPermissions() {\n return false // No file system access needed\n },\n async prompt() {\n return DESCRIPTION\n },\n renderToolUseMessage({ uri, server }, { verbose }) {\n let msg = `uri: \"${uri}\"`\n if (server) {\n msg += `, server: \"${server}\"`\n }\n return msg\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n if (!output) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().error}>Failed to read resource</Text>\n </Box>\n </Box>\n )\n }\n\n // Handle string content for backward compatibility\n if (typeof output === 'string') {\n try {\n output = JSON.parse(output) as Output\n } catch {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF Read MCP resource</Text>\n </Box>\n </Box>\n )\n }\n }\n\n const durationMs = output?.durationMs ?? 0\n\n if (output?.error) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().error}>{output.error}</Text>\n </Box>\n <Cost costUSD={0} durationMs={durationMs} debug={false} />\n </Box>\n )\n }\n\n if (!output?.content) {\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().warning}>Resource not found</Text>\n </Box>\n <Cost costUSD={0} durationMs={durationMs} debug={false} />\n </Box>\n )\n }\n\n const contentType = output.content.mimeType || 'unknown'\n const hasText = !!output.content.text\n const hasBlob = !!output.content.blob\n\n return (\n <Box justifyContent=\"space-between\" width=\"100%\">\n <Box flexDirection=\"row\">\n <Text> \u23BF Read resource </Text>\n <Text color={getTheme().secondaryText}>\n ({contentType}, {hasText ? 'text' : hasBlob ? 'binary' : 'empty'})\n </Text>\n </Box>\n <Cost costUSD={0} durationMs={durationMs} debug={false} />\n </Box>\n )\n },\n async *call({ uri, server }) {\n const start = Date.now()\n\n try {\n const content = await readMCPResource(uri, server)\n const output: Output = {\n content,\n durationMs: Date.now() - start,\n }\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(output),\n data: output,\n }\n } catch (error) {\n const output: Output = {\n content: null,\n durationMs: Date.now() - start,\n error: error instanceof Error ? error.message : String(error),\n }\n yield {\n type: 'result',\n resultForAssistant: this.renderResultForAssistant(output),\n data: output,\n }\n }\n },\n renderResultForAssistant(output) {\n if (output.error) {\n return `Error reading resource: ${output.error}`\n }\n\n if (!output.content) {\n return 'Resource not found or not accessible'\n }\n\n const lines: string[] = []\n lines.push(`Resource: ${output.content.uri}`)\n\n if (output.content.mimeType) {\n lines.push(`MIME Type: ${output.content.mimeType}`)\n }\n\n lines.push('')\n\n if (output.content.text) {\n lines.push('Content:')\n lines.push(output.content.text)\n } else if (output.content.blob) {\n lines.push(\n `Binary content (base64, ${output.content.blob.length} characters)`,\n )\n // Only show first 200 chars of base64 for preview\n if (output.content.blob.length > 200) {\n lines.push(output.content.blob.substring(0, 200) + '...')\n } else {\n lines.push(output.content.blob)\n }\n } else {\n lines.push('(Empty content)')\n }\n\n return lines.join('\\n')\n },\n} satisfies Tool\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|