hoomanjs 1.18.0 → 1.18.1
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/README.md +22 -26
- package/dist/acp/acp-agent.d.ts +69 -0
- package/dist/acp/acp-agent.js +628 -0
- package/dist/acp/acp-agent.js.map +1 -0
- package/dist/acp/approvals.d.ts +5 -0
- package/dist/acp/approvals.js +130 -0
- package/dist/acp/approvals.js.map +1 -0
- package/dist/acp/index.d.ts +1 -0
- package/dist/acp/index.js +2 -0
- package/dist/acp/index.js.map +1 -0
- package/dist/acp/mcp-servers.d.ts +7 -0
- package/dist/acp/mcp-servers.js +57 -0
- package/dist/acp/mcp-servers.js.map +1 -0
- package/dist/acp/meta/system-prompt.d.ts +12 -0
- package/dist/acp/meta/system-prompt.js +41 -0
- package/dist/acp/meta/system-prompt.js.map +1 -0
- package/dist/acp/meta/user-id.d.ts +12 -0
- package/dist/acp/meta/user-id.js +43 -0
- package/dist/acp/meta/user-id.js.map +1 -0
- package/dist/acp/prompt-invoke.d.ts +10 -0
- package/dist/acp/prompt-invoke.js +131 -0
- package/dist/acp/prompt-invoke.js.map +1 -0
- package/dist/acp/sessions/config-options.d.ts +7 -0
- package/dist/acp/sessions/config-options.js +101 -0
- package/dist/acp/sessions/config-options.js.map +1 -0
- package/dist/acp/sessions/replay.d.ts +7 -0
- package/dist/acp/sessions/replay.js +117 -0
- package/dist/acp/sessions/replay.js.map +1 -0
- package/dist/acp/sessions/store.d.ts +24 -0
- package/dist/acp/sessions/store.js +96 -0
- package/dist/acp/sessions/store.js.map +1 -0
- package/dist/acp/sessions/title.d.ts +5 -0
- package/dist/acp/sessions/title.js +22 -0
- package/dist/acp/sessions/title.js.map +1 -0
- package/dist/acp/utils/paths.d.ts +2 -0
- package/{src/acp/utils/paths.ts → dist/acp/utils/paths.js} +2 -2
- package/dist/acp/utils/paths.js.map +1 -0
- package/dist/acp/utils/tool-kind.d.ts +6 -0
- package/dist/acp/utils/tool-kind.js +53 -0
- package/dist/acp/utils/tool-kind.js.map +1 -0
- package/dist/acp/utils/tool-locations.d.ts +3 -0
- package/dist/acp/utils/tool-locations.js +44 -0
- package/dist/acp/utils/tool-locations.js.map +1 -0
- package/dist/acp/utils/tool-result-content.d.ts +8 -0
- package/dist/acp/utils/tool-result-content.js +14 -0
- package/dist/acp/utils/tool-result-content.js.map +1 -0
- package/dist/chat/app.d.ts +15 -0
- package/dist/chat/app.js +458 -0
- package/dist/chat/app.js.map +1 -0
- package/dist/chat/approvals.d.ts +15 -0
- package/dist/chat/approvals.js +74 -0
- package/dist/chat/approvals.js.map +1 -0
- package/dist/chat/components/ApprovalPrompt.d.ts +6 -0
- package/dist/chat/components/ApprovalPrompt.js +11 -0
- package/dist/chat/components/ApprovalPrompt.js.map +1 -0
- package/dist/chat/components/ChatMessage.d.ts +7 -0
- package/dist/chat/components/ChatMessage.js +19 -0
- package/dist/chat/components/ChatMessage.js.map +1 -0
- package/dist/chat/components/Composer.d.ts +11 -0
- package/dist/chat/components/Composer.js +9 -0
- package/dist/chat/components/Composer.js.map +1 -0
- package/dist/chat/components/EmptyChatBanner.d.ts +2 -0
- package/dist/chat/components/EmptyChatBanner.js +8 -0
- package/dist/chat/components/EmptyChatBanner.js.map +1 -0
- package/dist/chat/components/PromptInput.d.ts +11 -0
- package/dist/chat/components/PromptInput.js +26 -0
- package/dist/chat/components/PromptInput.js.map +1 -0
- package/dist/chat/components/QueuedPrompts.d.ts +10 -0
- package/dist/chat/components/QueuedPrompts.js +38 -0
- package/dist/chat/components/QueuedPrompts.js.map +1 -0
- package/dist/chat/components/ReasoningStrip.d.ts +6 -0
- package/dist/chat/components/ReasoningStrip.js +13 -0
- package/dist/chat/components/ReasoningStrip.js.map +1 -0
- package/dist/chat/components/ScrollView.d.ts +101 -0
- package/dist/chat/components/ScrollView.js +74 -0
- package/dist/chat/components/ScrollView.js.map +1 -0
- package/dist/chat/components/Spinner.d.ts +8 -0
- package/dist/chat/components/Spinner.js +19 -0
- package/dist/chat/components/Spinner.js.map +1 -0
- package/dist/chat/components/StatusBar.d.ts +20 -0
- package/dist/chat/components/StatusBar.js +20 -0
- package/dist/chat/components/StatusBar.js.map +1 -0
- package/dist/chat/components/ThinkingStatus.d.ts +1 -0
- package/dist/chat/components/ThinkingStatus.js +119 -0
- package/dist/chat/components/ThinkingStatus.js.map +1 -0
- package/dist/chat/components/TodoPanel.d.ts +6 -0
- package/dist/chat/components/TodoPanel.js +27 -0
- package/dist/chat/components/TodoPanel.js.map +1 -0
- package/dist/chat/components/ToolEvent.d.ts +6 -0
- package/dist/chat/components/ToolEvent.js +18 -0
- package/dist/chat/components/ToolEvent.js.map +1 -0
- package/dist/chat/components/ToolEventFileResult.d.ts +9 -0
- package/dist/chat/components/ToolEventFileResult.js +50 -0
- package/dist/chat/components/ToolEventFileResult.js.map +1 -0
- package/dist/chat/components/Transcript.d.ts +7 -0
- package/dist/chat/components/Transcript.js +9 -0
- package/dist/chat/components/Transcript.js.map +1 -0
- package/dist/chat/components/TranscriptViewport.d.ts +9 -0
- package/dist/chat/components/TranscriptViewport.js +124 -0
- package/dist/chat/components/TranscriptViewport.js.map +1 -0
- package/dist/chat/components/ascii-logo.d.ts +1 -0
- package/{src/chat/components/ascii-logo.ts → dist/chat/components/ascii-logo.js} +3 -2
- package/dist/chat/components/ascii-logo.js.map +1 -0
- package/dist/chat/components/file-tool-diff/file-tool-result.d.ts +26 -0
- package/dist/chat/components/file-tool-diff/file-tool-result.js +73 -0
- package/dist/chat/components/file-tool-diff/file-tool-result.js.map +1 -0
- package/dist/chat/components/markdown/BlockRenderer.d.ts +8 -0
- package/dist/chat/components/markdown/BlockRenderer.js +87 -0
- package/dist/chat/components/markdown/BlockRenderer.js.map +1 -0
- package/dist/chat/components/markdown/CodeBlock.d.ts +7 -0
- package/dist/chat/components/markdown/CodeBlock.js +55 -0
- package/dist/chat/components/markdown/CodeBlock.js.map +1 -0
- package/dist/chat/components/markdown/InlineRenderer.d.ts +8 -0
- package/dist/chat/components/markdown/InlineRenderer.js +96 -0
- package/dist/chat/components/markdown/InlineRenderer.js.map +1 -0
- package/dist/chat/components/markdown/MarkdownMessage.d.ts +6 -0
- package/dist/chat/components/markdown/MarkdownMessage.js +13 -0
- package/dist/chat/components/markdown/MarkdownMessage.js.map +1 -0
- package/dist/chat/components/markdown/MarkdownTable.d.ts +6 -0
- package/dist/chat/components/markdown/MarkdownTable.js +12 -0
- package/dist/chat/components/markdown/MarkdownTable.js.map +1 -0
- package/dist/chat/components/markdown/hooks/useMarkdownTableLayout.d.ts +7 -0
- package/dist/chat/components/markdown/hooks/useMarkdownTableLayout.js +186 -0
- package/dist/chat/components/markdown/hooks/useMarkdownTableLayout.js.map +1 -0
- package/dist/chat/components/markdown/hooks/useMarkdownTokens.d.ts +9 -0
- package/dist/chat/components/markdown/hooks/useMarkdownTokens.js +25 -0
- package/dist/chat/components/markdown/hooks/useMarkdownTokens.js.map +1 -0
- package/dist/chat/components/markdown/lexer.d.ts +7 -0
- package/dist/chat/components/markdown/lexer.js +89 -0
- package/dist/chat/components/markdown/lexer.js.map +1 -0
- package/dist/chat/components/prompt-input/clipboard-image.d.ts +1 -0
- package/dist/chat/components/prompt-input/clipboard-image.js +112 -0
- package/dist/chat/components/prompt-input/clipboard-image.js.map +1 -0
- package/dist/chat/components/prompt-input/hooks/usePromptInputController.d.ts +1 -0
- package/dist/chat/components/prompt-input/hooks/usePromptInputController.js +2 -0
- package/dist/chat/components/prompt-input/hooks/usePromptInputController.js.map +1 -0
- package/dist/chat/components/prompt-input/input-model.d.ts +28 -0
- package/dist/chat/components/prompt-input/input-model.js +231 -0
- package/dist/chat/components/prompt-input/input-model.js.map +1 -0
- package/dist/chat/components/prompt-input/paste.d.ts +11 -0
- package/dist/chat/components/prompt-input/paste.js +85 -0
- package/dist/chat/components/prompt-input/paste.js.map +1 -0
- package/dist/chat/components/prompt-input/render.d.ts +13 -0
- package/dist/chat/components/prompt-input/render.js +54 -0
- package/dist/chat/components/prompt-input/render.js.map +1 -0
- package/dist/chat/components/prompt-input/usePromptInputController.d.ts +17 -0
- package/dist/chat/components/prompt-input/usePromptInputController.js +366 -0
- package/dist/chat/components/prompt-input/usePromptInputController.js.map +1 -0
- package/dist/chat/components/shared.d.ts +6 -0
- package/dist/chat/components/shared.js +66 -0
- package/dist/chat/components/shared.js.map +1 -0
- package/dist/chat/index.d.ts +13 -0
- package/dist/chat/index.js +18 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/mouse.d.ts +5 -0
- package/dist/chat/mouse.js +9 -0
- package/dist/chat/mouse.js.map +1 -0
- package/dist/chat/types.d.ts +20 -0
- package/dist/chat/types.js +2 -0
- package/dist/chat/types.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +126 -0
- package/dist/cli.js.map +1 -0
- package/dist/configure/app.d.ts +3 -0
- package/dist/configure/app.js +1036 -0
- package/dist/configure/app.js.map +1 -0
- package/dist/configure/components/BusyScreen.d.ts +6 -0
- package/dist/configure/components/BusyScreen.js +7 -0
- package/dist/configure/components/BusyScreen.js.map +1 -0
- package/dist/configure/components/HomeScreen.d.ts +12 -0
- package/dist/configure/components/HomeScreen.js +7 -0
- package/dist/configure/components/HomeScreen.js.map +1 -0
- package/dist/configure/components/MenuScreen.d.ts +10 -0
- package/dist/configure/components/MenuScreen.js +15 -0
- package/dist/configure/components/MenuScreen.js.map +1 -0
- package/dist/configure/components/PromptForm.d.ts +8 -0
- package/dist/configure/components/PromptForm.js +12 -0
- package/dist/configure/components/PromptForm.js.map +1 -0
- package/dist/configure/components/SelectMenuItem.d.ts +7 -0
- package/dist/configure/components/SelectMenuItem.js +18 -0
- package/dist/configure/components/SelectMenuItem.js.map +1 -0
- package/dist/configure/index.d.ts +1 -0
- package/dist/configure/index.js +28 -0
- package/dist/configure/index.js.map +1 -0
- package/dist/configure/open-in-editor.d.ts +8 -0
- package/dist/configure/open-in-editor.js +120 -0
- package/dist/configure/open-in-editor.js.map +1 -0
- package/dist/configure/types.d.ts +63 -0
- package/dist/configure/types.js +2 -0
- package/dist/configure/types.js.map +1 -0
- package/dist/configure/utils.d.ts +19 -0
- package/dist/configure/utils.js +108 -0
- package/dist/configure/utils.js.map +1 -0
- package/dist/core/agent/index.d.ts +13 -0
- package/dist/core/agent/index.js +70 -0
- package/dist/core/agent/index.js.map +1 -0
- package/dist/core/agents/definitions.d.ts +12 -0
- package/dist/core/agents/definitions.js +35 -0
- package/dist/core/agents/definitions.js.map +1 -0
- package/dist/core/agents/index.d.ts +4 -0
- package/dist/core/agents/index.js +5 -0
- package/dist/core/agents/index.js.map +1 -0
- package/dist/core/agents/registry.d.ts +5 -0
- package/dist/core/agents/registry.js +84 -0
- package/dist/core/agents/registry.js.map +1 -0
- package/dist/core/agents/runner.d.ts +36 -0
- package/dist/core/agents/runner.js +275 -0
- package/dist/core/agents/runner.js.map +1 -0
- package/dist/core/agents/tools.d.ts +20 -0
- package/dist/core/agents/tools.js +66 -0
- package/dist/core/agents/tools.js.map +1 -0
- package/dist/core/config.d.ts +272 -0
- package/dist/core/config.js +334 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.js +21 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/mcp/config.d.ts +44 -0
- package/dist/core/mcp/config.js +65 -0
- package/dist/core/mcp/config.js.map +1 -0
- package/dist/core/mcp/index.d.ts +8 -0
- package/dist/core/mcp/index.js +12 -0
- package/dist/core/mcp/index.js.map +1 -0
- package/dist/core/mcp/manager.d.ts +69 -0
- package/dist/core/mcp/manager.js +376 -0
- package/dist/core/mcp/manager.js.map +1 -0
- package/dist/core/mcp/prefixed-mcp-tool.d.ts +14 -0
- package/dist/core/mcp/prefixed-mcp-tool.js +38 -0
- package/dist/core/mcp/prefixed-mcp-tool.js.map +1 -0
- package/dist/core/mcp/tools.d.ts +5 -0
- package/dist/core/mcp/tools.js +82 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/mcp/types.d.ts +40 -0
- package/dist/core/mcp/types.js +28 -0
- package/dist/core/mcp/types.js.map +1 -0
- package/dist/core/memory/index.d.ts +3 -0
- package/dist/core/memory/index.js +3 -0
- package/dist/core/memory/index.js.map +1 -0
- package/dist/core/memory/ltm/embed.d.ts +16 -0
- package/dist/core/memory/ltm/embed.js +49 -0
- package/dist/core/memory/ltm/embed.js.map +1 -0
- package/dist/core/memory/ltm/index.d.ts +3 -0
- package/dist/core/memory/ltm/index.js +3 -0
- package/dist/core/memory/ltm/index.js.map +1 -0
- package/dist/core/memory/ltm/store.d.ts +20 -0
- package/dist/core/memory/ltm/store.js +271 -0
- package/dist/core/memory/ltm/store.js.map +1 -0
- package/dist/core/memory/ltm/tools.d.ts +21 -0
- package/dist/core/memory/ltm/tools.js +127 -0
- package/dist/core/memory/ltm/tools.js.map +1 -0
- package/dist/core/memory/ltm/types.d.ts +79 -0
- package/dist/core/memory/ltm/types.js +2 -0
- package/dist/core/memory/ltm/types.js.map +1 -0
- package/dist/core/memory/ltm/utils.d.ts +40 -0
- package/dist/core/memory/ltm/utils.js +145 -0
- package/dist/core/memory/ltm/utils.js.map +1 -0
- package/dist/core/memory/stm/flat-file-storage.d.ts +27 -0
- package/dist/core/memory/stm/flat-file-storage.js +63 -0
- package/dist/core/memory/stm/flat-file-storage.js.map +1 -0
- package/dist/core/memory/stm/index.d.ts +13 -0
- package/dist/core/memory/stm/index.js +24 -0
- package/dist/core/memory/stm/index.js.map +1 -0
- package/dist/core/memory/stm/lazy-session-manager.d.ts +37 -0
- package/dist/core/memory/stm/lazy-session-manager.js +163 -0
- package/dist/core/memory/stm/lazy-session-manager.js.map +1 -0
- package/dist/core/models/anthropic.d.ts +10 -0
- package/dist/core/models/anthropic.js +38 -0
- package/dist/core/models/anthropic.js.map +1 -0
- package/dist/core/models/bedrock.d.ts +21 -0
- package/dist/core/models/bedrock.js +24 -0
- package/dist/core/models/bedrock.js.map +1 -0
- package/dist/core/models/google.d.ts +10 -0
- package/dist/core/models/google.js +36 -0
- package/dist/core/models/google.js.map +1 -0
- package/dist/core/models/groq.d.ts +10 -0
- package/dist/core/models/groq.js +33 -0
- package/dist/core/models/groq.js.map +1 -0
- package/dist/core/models/index.d.ts +5 -0
- package/dist/core/models/index.js +11 -0
- package/dist/core/models/index.js.map +1 -0
- package/dist/core/models/moonshot.d.ts +11 -0
- package/dist/core/models/moonshot.js +39 -0
- package/dist/core/models/moonshot.js.map +1 -0
- package/dist/core/models/ollama/index.d.ts +3 -0
- package/dist/core/models/ollama/index.js +9 -0
- package/dist/core/models/ollama/index.js.map +1 -0
- package/dist/core/models/ollama/strands-ollama.d.ts +30 -0
- package/dist/core/models/ollama/strands-ollama.js +336 -0
- package/dist/core/models/ollama/strands-ollama.js.map +1 -0
- package/dist/core/models/openai.d.ts +4 -0
- package/dist/core/models/openai.js +9 -0
- package/dist/core/models/openai.js.map +1 -0
- package/dist/core/models/xai.d.ts +10 -0
- package/dist/core/models/xai.js +33 -0
- package/dist/core/models/xai.js.map +1 -0
- package/dist/core/prompts/environment.d.ts +11 -0
- package/dist/core/prompts/environment.js +51 -0
- package/dist/core/prompts/environment.js.map +1 -0
- package/dist/core/prompts/index.d.ts +7 -0
- package/dist/core/prompts/index.js +14 -0
- package/dist/core/prompts/index.js.map +1 -0
- package/dist/core/prompts/skills.d.ts +15 -0
- package/dist/core/prompts/skills.js +86 -0
- package/dist/core/prompts/skills.js.map +1 -0
- package/dist/core/prompts/system.d.ts +22 -0
- package/dist/core/prompts/system.js +164 -0
- package/dist/core/prompts/system.js.map +1 -0
- package/dist/core/skills/built-in/hooman-config/SKILL.md +9 -0
- package/dist/core/skills/index.d.ts +2 -0
- package/dist/core/skills/index.js +3 -0
- package/dist/core/skills/index.js.map +1 -0
- package/dist/core/skills/metadata.d.ts +8 -0
- package/dist/core/skills/metadata.js +20 -0
- package/dist/core/skills/metadata.js.map +1 -0
- package/dist/core/skills/registry.d.ts +38 -0
- package/dist/core/skills/registry.js +165 -0
- package/dist/core/skills/registry.js.map +1 -0
- package/dist/core/skills/tools.d.ts +9 -0
- package/dist/core/skills/tools.js +73 -0
- package/dist/core/skills/tools.js.map +1 -0
- package/dist/core/state/file-tool-display.d.ts +20 -0
- package/dist/core/state/file-tool-display.js +35 -0
- package/dist/core/state/file-tool-display.js.map +1 -0
- package/dist/core/state/thought-process.d.ts +18 -0
- package/dist/core/state/thought-process.js +21 -0
- package/dist/core/state/thought-process.js.map +1 -0
- package/dist/core/state/todos.d.ts +39 -0
- package/dist/core/state/todos.js +53 -0
- package/dist/core/state/todos.js.map +1 -0
- package/dist/core/state/tool-approvals.d.ts +12 -0
- package/dist/core/state/tool-approvals.js +81 -0
- package/dist/core/state/tool-approvals.js.map +1 -0
- package/dist/core/tools/fetch.d.ts +9 -0
- package/dist/core/tools/fetch.js +228 -0
- package/dist/core/tools/fetch.js.map +1 -0
- package/dist/core/tools/filesystem.d.ts +35 -0
- package/dist/core/tools/filesystem.js +791 -0
- package/dist/core/tools/filesystem.js.map +1 -0
- package/dist/core/tools/index.d.ts +9 -0
- package/dist/core/tools/index.js +10 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/shell.d.ts +18 -0
- package/dist/core/tools/shell.js +308 -0
- package/dist/core/tools/shell.js.map +1 -0
- package/dist/core/tools/sleep.d.ts +4 -0
- package/dist/core/tools/sleep.js +46 -0
- package/dist/core/tools/sleep.js.map +1 -0
- package/dist/core/tools/thinking.d.ts +12 -0
- package/dist/core/tools/thinking.js +119 -0
- package/dist/core/tools/thinking.js.map +1 -0
- package/dist/core/tools/time.d.ts +8 -0
- package/dist/core/tools/time.js +94 -0
- package/dist/core/tools/time.js.map +1 -0
- package/dist/core/tools/todo.d.ts +9 -0
- package/dist/core/tools/todo.js +33 -0
- package/dist/core/tools/todo.js.map +1 -0
- package/dist/core/tools/web-search.d.ts +11 -0
- package/dist/core/tools/web-search.js +211 -0
- package/dist/core/tools/web-search.js.map +1 -0
- package/dist/core/tools/wiki.d.ts +11 -0
- package/dist/core/tools/wiki.js +566 -0
- package/dist/core/tools/wiki.js.map +1 -0
- package/dist/core/utils/attachments.d.ts +23 -0
- package/dist/core/utils/attachments.js +125 -0
- package/dist/core/utils/attachments.js.map +1 -0
- package/dist/core/utils/cwd-context.d.ts +2 -0
- package/dist/core/utils/cwd-context.js +9 -0
- package/dist/core/utils/cwd-context.js.map +1 -0
- package/dist/core/utils/file-formats.d.ts +4 -0
- package/dist/core/utils/file-formats.js +48 -0
- package/dist/core/utils/file-formats.js.map +1 -0
- package/dist/core/utils/paths.d.ts +7 -0
- package/dist/core/utils/paths.js +25 -0
- package/dist/core/utils/paths.js.map +1 -0
- package/dist/daemon/approvals.d.ts +5 -0
- package/dist/daemon/approvals.js +95 -0
- package/dist/daemon/approvals.js.map +1 -0
- package/dist/daemon/index.d.ts +11 -0
- package/dist/daemon/index.js +106 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/queue.d.ts +5 -0
- package/dist/daemon/queue.js +38 -0
- package/dist/daemon/queue.js.map +1 -0
- package/dist/exec/approvals.d.ts +6 -0
- package/dist/exec/approvals.js +74 -0
- package/dist/exec/approvals.js.map +1 -0
- package/package.json +20 -9
- package/.github/screenshot.png +0 -0
- package/.github/workflows/build-publish.yml +0 -49
- package/docker-compose.yml +0 -13
- package/src/acp/acp-agent.ts +0 -814
- package/src/acp/approvals.ts +0 -146
- package/src/acp/index.ts +0 -1
- package/src/acp/mcp-servers.ts +0 -64
- package/src/acp/meta/system-prompt.ts +0 -44
- package/src/acp/meta/user-id.ts +0 -44
- package/src/acp/prompt-invoke.ts +0 -149
- package/src/acp/sessions/config-options.ts +0 -120
- package/src/acp/sessions/replay.ts +0 -131
- package/src/acp/sessions/store.ts +0 -161
- package/src/acp/sessions/title.ts +0 -22
- package/src/acp/utils/tool-kind.ts +0 -61
- package/src/acp/utils/tool-locations.ts +0 -48
- package/src/acp/utils/tool-result-content.ts +0 -27
- package/src/chat/app.tsx +0 -636
- package/src/chat/approvals.ts +0 -97
- package/src/chat/components/ApprovalPrompt.tsx +0 -25
- package/src/chat/components/ChatMessage.tsx +0 -50
- package/src/chat/components/Composer.tsx +0 -45
- package/src/chat/components/EmptyChatBanner.tsx +0 -26
- package/src/chat/components/PromptInput.tsx +0 -62
- package/src/chat/components/QueuedPrompts.tsx +0 -76
- package/src/chat/components/ReasoningStrip.tsx +0 -30
- package/src/chat/components/Spinner.tsx +0 -34
- package/src/chat/components/StatusBar.tsx +0 -67
- package/src/chat/components/ThinkingStatus.tsx +0 -128
- package/src/chat/components/TodoPanel.tsx +0 -49
- package/src/chat/components/ToolEvent.tsx +0 -41
- package/src/chat/components/ToolEventFileResult.tsx +0 -116
- package/src/chat/components/Transcript.tsx +0 -34
- package/src/chat/components/TranscriptViewport.tsx +0 -170
- package/src/chat/components/file-tool-diff/file-tool-result.ts +0 -155
- package/src/chat/components/markdown/BlockRenderer.tsx +0 -207
- package/src/chat/components/markdown/CodeBlock.tsx +0 -100
- package/src/chat/components/markdown/InlineRenderer.tsx +0 -122
- package/src/chat/components/markdown/MarkdownMessage.tsx +0 -35
- package/src/chat/components/markdown/MarkdownTable.tsx +0 -23
- package/src/chat/components/markdown/hooks/useMarkdownTableLayout.ts +0 -242
- package/src/chat/components/markdown/hooks/useMarkdownTokens.ts +0 -46
- package/src/chat/components/markdown/lexer.ts +0 -100
- package/src/chat/components/prompt-input/clipboard-image.ts +0 -119
- package/src/chat/components/prompt-input/hooks/usePromptInputController.ts +0 -4
- package/src/chat/components/prompt-input/input-model.ts +0 -294
- package/src/chat/components/prompt-input/paste.ts +0 -105
- package/src/chat/components/prompt-input/render.ts +0 -83
- package/src/chat/components/prompt-input/usePromptInputController.ts +0 -498
- package/src/chat/components/shared.ts +0 -70
- package/src/chat/index.tsx +0 -41
- package/src/chat/mouse.ts +0 -17
- package/src/chat/types.ts +0 -24
- package/src/cli.ts +0 -181
- package/src/configure/app.tsx +0 -1349
- package/src/configure/components/BusyScreen.tsx +0 -22
- package/src/configure/components/HomeScreen.tsx +0 -43
- package/src/configure/components/MenuScreen.tsx +0 -44
- package/src/configure/components/PromptForm.tsx +0 -40
- package/src/configure/components/SelectMenuItem.tsx +0 -30
- package/src/configure/index.tsx +0 -43
- package/src/configure/open-in-editor.ts +0 -133
- package/src/configure/types.ts +0 -51
- package/src/configure/utils.ts +0 -134
- package/src/core/agent/index.ts +0 -108
- package/src/core/agents/definitions.ts +0 -48
- package/src/core/agents/index.ts +0 -15
- package/src/core/agents/registry.ts +0 -106
- package/src/core/agents/runner.ts +0 -375
- package/src/core/agents/tools.ts +0 -100
- package/src/core/config.ts +0 -377
- package/src/core/index.ts +0 -60
- package/src/core/mcp/config.ts +0 -80
- package/src/core/mcp/index.ts +0 -33
- package/src/core/mcp/manager.ts +0 -491
- package/src/core/mcp/prefixed-mcp-tool.ts +0 -45
- package/src/core/mcp/tools.ts +0 -92
- package/src/core/mcp/types.ts +0 -37
- package/src/core/memory/index.ts +0 -17
- package/src/core/memory/ltm/embed.ts +0 -67
- package/src/core/memory/ltm/index.ts +0 -18
- package/src/core/memory/ltm/store.ts +0 -376
- package/src/core/memory/ltm/tools.ts +0 -146
- package/src/core/memory/ltm/types.ts +0 -111
- package/src/core/memory/ltm/utils.ts +0 -218
- package/src/core/memory/stm/flat-file-storage.ts +0 -89
- package/src/core/memory/stm/index.ts +0 -32
- package/src/core/memory/stm/lazy-session-manager.ts +0 -220
- package/src/core/models/anthropic.ts +0 -53
- package/src/core/models/bedrock.ts +0 -54
- package/src/core/models/google.ts +0 -51
- package/src/core/models/groq.ts +0 -48
- package/src/core/models/index.ts +0 -19
- package/src/core/models/moonshot.ts +0 -54
- package/src/core/models/ollama/index.ts +0 -13
- package/src/core/models/ollama/strands-ollama.ts +0 -439
- package/src/core/models/openai.ts +0 -12
- package/src/core/models/xai.ts +0 -47
- package/src/core/prompts/environment.ts +0 -71
- package/src/core/prompts/index.ts +0 -22
- package/src/core/prompts/skills.ts +0 -66
- package/src/core/prompts/system.ts +0 -183
- package/src/core/skills/index.ts +0 -2
- package/src/core/skills/registry.ts +0 -239
- package/src/core/skills/tools.ts +0 -80
- package/src/core/state/file-tool-display.ts +0 -70
- package/src/core/state/thought-process.ts +0 -49
- package/src/core/state/todos.ts +0 -84
- package/src/core/state/tool-approvals.ts +0 -100
- package/src/core/tools/fetch.ts +0 -288
- package/src/core/tools/filesystem.ts +0 -1105
- package/src/core/tools/index.ts +0 -9
- package/src/core/tools/shell.ts +0 -426
- package/src/core/tools/sleep.ts +0 -51
- package/src/core/tools/thinking.ts +0 -149
- package/src/core/tools/time.ts +0 -121
- package/src/core/tools/todo.ts +0 -44
- package/src/core/tools/web-search.ts +0 -278
- package/src/core/tools/wiki.ts +0 -703
- package/src/core/utils/attachments.ts +0 -201
- package/src/core/utils/cwd-context.ts +0 -11
- package/src/core/utils/file-formats.ts +0 -60
- package/src/core/utils/paths.ts +0 -37
- package/src/daemon/approvals.ts +0 -127
- package/src/daemon/index.ts +0 -153
- package/src/daemon/queue.ts +0 -48
- package/src/exec/approvals.ts +0 -90
- package/tsconfig.json +0 -30
- /package/{src → dist}/core/prompts/agents/plan.md +0 -0
- /package/{src → dist}/core/prompts/agents/research.md +0 -0
- /package/{src → dist}/core/prompts/harness/behaviour.md +0 -0
- /package/{src → dist}/core/prompts/harness/communication.md +0 -0
- /package/{src → dist}/core/prompts/harness/engineering.md +0 -0
- /package/{src → dist}/core/prompts/harness/execution.md +0 -0
- /package/{src → dist}/core/prompts/harness/guardrails.md +0 -0
- /package/{src → dist}/core/prompts/static/daemon.md +0 -0
- /package/{src → dist}/core/prompts/static/environment.md +0 -0
- /package/{src → dist}/core/prompts/static/fetch.md +0 -0
- /package/{src → dist}/core/prompts/static/filesystem.md +0 -0
- /package/{src → dist}/core/prompts/static/identity.md +0 -0
- /package/{src → dist}/core/prompts/static/ltm.md +0 -0
- /package/{src → dist}/core/prompts/static/shell.md +0 -0
- /package/{src → dist}/core/prompts/static/skills.md +0 -0
- /package/{src → dist}/core/prompts/static/sleep.md +0 -0
- /package/{src → dist}/core/prompts/static/subagents.md +0 -0
- /package/{src → dist}/core/prompts/static/thinking.md +0 -0
- /package/{src → dist}/core/prompts/static/todo.md +0 -0
- /package/{src → dist}/core/prompts/static/web-search.md +0 -0
- /package/{src → dist}/core/prompts/static/wiki.md +0 -0
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import { tool } from "@strands-agents/sdk";
|
|
6
|
+
import { getCwd } from "../utils/cwd-context.js";
|
|
7
|
+
import { setFileToolDisplay, } from "../state/file-tool-display.js";
|
|
8
|
+
import { readAttachmentAsBlocksOrBase64, } from "../utils/attachments.js";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
const DEFAULT_READ_LIMIT = 250;
|
|
11
|
+
const DEFAULT_MAX_READ_BYTES = 1024 * 1024;
|
|
12
|
+
const DEFAULT_SEARCH_MAX_RESULTS = 500;
|
|
13
|
+
const DEFAULT_TREE_DEPTH = 4;
|
|
14
|
+
const SNIPPET_RADIUS = 3;
|
|
15
|
+
const FAST_READ_MAX_BYTES = 10 * 1024 * 1024;
|
|
16
|
+
const STREAM_HIGH_WATER_MARK = 512 * 1024;
|
|
17
|
+
const EditSchema = z.object({
|
|
18
|
+
oldText: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe("Exact text to find. Must match uniquely."),
|
|
22
|
+
newText: z.string().describe("Replacement text."),
|
|
23
|
+
});
|
|
24
|
+
const textReadState = new Map();
|
|
25
|
+
function toJsonValue(value) {
|
|
26
|
+
return JSON.parse(JSON.stringify(value));
|
|
27
|
+
}
|
|
28
|
+
function expandHome(inputPath) {
|
|
29
|
+
if (inputPath === "~" || inputPath.startsWith("~/")) {
|
|
30
|
+
return path.join(os.homedir(), inputPath.slice(1));
|
|
31
|
+
}
|
|
32
|
+
return inputPath;
|
|
33
|
+
}
|
|
34
|
+
function normalizeUserPath(inputPath) {
|
|
35
|
+
let value = inputPath.trim().replace(/^["']|["']$/g, "");
|
|
36
|
+
if (process.platform === "win32" && /^\/[a-zA-Z]\//.test(value)) {
|
|
37
|
+
const drive = value[1].toUpperCase();
|
|
38
|
+
value = `${drive}:${value.slice(2).replace(/\//g, "\\")}`;
|
|
39
|
+
}
|
|
40
|
+
value = expandHome(value);
|
|
41
|
+
return path.isAbsolute(value)
|
|
42
|
+
? path.resolve(value)
|
|
43
|
+
: path.resolve(getCwd(), value);
|
|
44
|
+
}
|
|
45
|
+
function normalizeForGlob(inputPath) {
|
|
46
|
+
return inputPath.replace(/\\/g, "/");
|
|
47
|
+
}
|
|
48
|
+
function globToRegExp(pattern) {
|
|
49
|
+
const normalized = normalizeForGlob(pattern);
|
|
50
|
+
let regex = "^";
|
|
51
|
+
for (let i = 0; i < normalized.length; i += 1) {
|
|
52
|
+
const char = normalized[i];
|
|
53
|
+
const next = normalized[i + 1];
|
|
54
|
+
if (char === "*" && next === "*") {
|
|
55
|
+
regex += ".*";
|
|
56
|
+
i += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (char === "*") {
|
|
60
|
+
regex += "[^/]*";
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (char === "?") {
|
|
64
|
+
regex += "[^/]";
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
regex += /[\\^$+?.()|[\]{}]/.test(char) ? `\\${char}` : char;
|
|
68
|
+
}
|
|
69
|
+
regex += "$";
|
|
70
|
+
return new RegExp(regex, "i");
|
|
71
|
+
}
|
|
72
|
+
function splitLines(content) {
|
|
73
|
+
return content.split(/\r?\n/);
|
|
74
|
+
}
|
|
75
|
+
function normalizeLineEndings(content) {
|
|
76
|
+
return content.replaceAll("\r\n", "\n");
|
|
77
|
+
}
|
|
78
|
+
function detectLineEndings(content) {
|
|
79
|
+
return content.includes("\r\n") ? "CRLF" : "LF";
|
|
80
|
+
}
|
|
81
|
+
function restoreLineEndings(content, lineEndings) {
|
|
82
|
+
if (lineEndings === "LF") {
|
|
83
|
+
return content;
|
|
84
|
+
}
|
|
85
|
+
return normalizeLineEndings(content).split("\n").join("\r\n");
|
|
86
|
+
}
|
|
87
|
+
function countLines(content) {
|
|
88
|
+
if (content.length === 0) {
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
return splitLines(content).length;
|
|
92
|
+
}
|
|
93
|
+
function makeLineExcerpt(content, offset = 1, limit = DEFAULT_READ_LIMIT) {
|
|
94
|
+
const lines = splitLines(content);
|
|
95
|
+
const totalLines = lines.length;
|
|
96
|
+
const startIndex = Math.max(0, offset - 1);
|
|
97
|
+
const selected = lines.slice(startIndex, startIndex + limit);
|
|
98
|
+
return {
|
|
99
|
+
content: selected.join("\n"),
|
|
100
|
+
startLine: startIndex + 1,
|
|
101
|
+
endLine: startIndex + selected.length,
|
|
102
|
+
totalLines,
|
|
103
|
+
truncated: startIndex + selected.length < totalLines,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function isProbablyBinary(buffer) {
|
|
107
|
+
if (buffer.length === 0) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
let suspicious = 0;
|
|
111
|
+
const sample = Math.min(buffer.length, 8000);
|
|
112
|
+
for (let i = 0; i < sample; i += 1) {
|
|
113
|
+
const byte = buffer[i];
|
|
114
|
+
if (byte === 0) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
const isTextByte = byte === 9 || byte === 10 || byte === 13 || (byte >= 32 && byte <= 126);
|
|
118
|
+
if (!isTextByte) {
|
|
119
|
+
suspicious += 1;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return suspicious / sample > 0.3;
|
|
123
|
+
}
|
|
124
|
+
async function ensureExists(filePath) {
|
|
125
|
+
await fs.access(filePath);
|
|
126
|
+
}
|
|
127
|
+
async function ensureDirectory(filePath) {
|
|
128
|
+
const stat = await fs.stat(filePath);
|
|
129
|
+
if (!stat.isDirectory()) {
|
|
130
|
+
throw new Error(`Path is not a directory: ${filePath}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async function ensureFile(filePath) {
|
|
134
|
+
const stat = await fs.stat(filePath);
|
|
135
|
+
if (!stat.isFile()) {
|
|
136
|
+
throw new Error(`Path is not a file: ${filePath}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function statFile(filePath) {
|
|
140
|
+
const stat = await fs.stat(filePath);
|
|
141
|
+
if (!stat.isFile()) {
|
|
142
|
+
throw new Error(`Path is not a file: ${filePath}`);
|
|
143
|
+
}
|
|
144
|
+
return stat;
|
|
145
|
+
}
|
|
146
|
+
async function readTextFile(filePath, options) {
|
|
147
|
+
const stat = await statFile(filePath);
|
|
148
|
+
const maxBytes = options?.maxBytes ?? DEFAULT_MAX_READ_BYTES;
|
|
149
|
+
const offset = options?.offset ?? 1;
|
|
150
|
+
if (stat.size > maxBytes && options?.limit === undefined) {
|
|
151
|
+
throw new Error(`File too large to read safely (${stat.size} bytes). Use a narrower read or another tool.`);
|
|
152
|
+
}
|
|
153
|
+
const readResult = stat.size < FAST_READ_MAX_BYTES
|
|
154
|
+
? await readTextFileFast(filePath, options)
|
|
155
|
+
: await readTextFileStreaming(filePath, options);
|
|
156
|
+
textReadState.set(filePath, {
|
|
157
|
+
content: readResult.content,
|
|
158
|
+
mtimeMs: Number(stat.mtimeMs),
|
|
159
|
+
offset,
|
|
160
|
+
limit: options?.limit,
|
|
161
|
+
isPartial: readResult.startLine !== 1 || readResult.endLine < readResult.totalLines,
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
path: filePath,
|
|
165
|
+
content: readResult.content,
|
|
166
|
+
startLine: readResult.startLine,
|
|
167
|
+
endLine: readResult.endLine,
|
|
168
|
+
totalLines: readResult.totalLines,
|
|
169
|
+
truncated: readResult.truncated,
|
|
170
|
+
sizeBytes: Number(stat.size),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async function readTextFileFast(filePath, options) {
|
|
174
|
+
const buffer = await fs.readFile(filePath);
|
|
175
|
+
assertTextBuffer(buffer);
|
|
176
|
+
return makeLineExcerpt(buffer.toString("utf8"), options?.offset, options?.limit);
|
|
177
|
+
}
|
|
178
|
+
async function readTextFileStreaming(filePath, options) {
|
|
179
|
+
const offset = options?.offset ?? 1;
|
|
180
|
+
const limit = options?.limit ?? DEFAULT_READ_LIMIT;
|
|
181
|
+
const startIndex = Math.max(0, offset - 1);
|
|
182
|
+
const endIndex = startIndex + limit;
|
|
183
|
+
const selectedLines = [];
|
|
184
|
+
const handle = await fs.open(filePath, "r");
|
|
185
|
+
const buffer = Buffer.allocUnsafe(STREAM_HIGH_WATER_MARK);
|
|
186
|
+
let position = 0;
|
|
187
|
+
let lineIndex = 0;
|
|
188
|
+
let partial = "";
|
|
189
|
+
let sampledBytes = 0;
|
|
190
|
+
let sample = Buffer.alloc(0);
|
|
191
|
+
try {
|
|
192
|
+
for (;;) {
|
|
193
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, position);
|
|
194
|
+
if (bytesRead === 0) {
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
if (sampledBytes < 8000) {
|
|
198
|
+
const remaining = 8000 - sampledBytes;
|
|
199
|
+
const nextSample = buffer.subarray(0, Math.min(bytesRead, remaining));
|
|
200
|
+
sample = Buffer.concat([sample, nextSample]);
|
|
201
|
+
sampledBytes += nextSample.length;
|
|
202
|
+
assertTextBuffer(sample);
|
|
203
|
+
}
|
|
204
|
+
position += bytesRead;
|
|
205
|
+
const data = partial + buffer.toString("utf8", 0, bytesRead);
|
|
206
|
+
const lines = data.split("\n");
|
|
207
|
+
partial = lines.pop() ?? "";
|
|
208
|
+
for (const rawLine of lines) {
|
|
209
|
+
if (lineIndex >= startIndex && lineIndex < endIndex) {
|
|
210
|
+
selectedLines.push(rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine);
|
|
211
|
+
}
|
|
212
|
+
lineIndex += 1;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (partial.length > 0 || position > 0) {
|
|
216
|
+
if (lineIndex >= startIndex && lineIndex < endIndex) {
|
|
217
|
+
selectedLines.push(partial.endsWith("\r") ? partial.slice(0, -1) : partial);
|
|
218
|
+
}
|
|
219
|
+
lineIndex += 1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
await handle.close();
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
content: selectedLines.join("\n"),
|
|
227
|
+
startLine: selectedLines.length > 0 ? startIndex + 1 : offset,
|
|
228
|
+
endLine: selectedLines.length > 0 ? startIndex + selectedLines.length : offset - 1,
|
|
229
|
+
totalLines: lineIndex,
|
|
230
|
+
truncated: endIndex < lineIndex,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function assertTextBuffer(buffer) {
|
|
234
|
+
if (isProbablyBinary(buffer)) {
|
|
235
|
+
throw new Error("File appears to be binary. Call read_file again with `binary: true` — images (png/jpeg/gif/webp), videos (mp4/mov/mkv/webm/etc.), and documents (pdf/docx/csv/etc.) are returned as multimodal content blocks the provider can forward to the model; unknown binary types come back as base64.");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function readBinaryFile(filePath, options) {
|
|
239
|
+
return readAttachmentAsBlocksOrBase64(filePath, {
|
|
240
|
+
maxBytes: options?.maxBytes ?? DEFAULT_MAX_READ_BYTES,
|
|
241
|
+
includeMetadata: true,
|
|
242
|
+
unsupportedFormat: "base64",
|
|
243
|
+
onError: "throw",
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
function snippetAroundChange(content, index, replacementLength) {
|
|
247
|
+
const before = content.slice(0, index);
|
|
248
|
+
const startLine = Math.max(0, countLines(before) - SNIPPET_RADIUS);
|
|
249
|
+
const endLine = countLines(before) + replacementLength + SNIPPET_RADIUS;
|
|
250
|
+
const lines = splitLines(content);
|
|
251
|
+
return lines.slice(startLine, endLine).join("\n");
|
|
252
|
+
}
|
|
253
|
+
function lineNumberForIndex(content, index) {
|
|
254
|
+
let line = 1;
|
|
255
|
+
for (let i = 0; i < index; i += 1) {
|
|
256
|
+
if (content[i] === "\n") {
|
|
257
|
+
line += 1;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return line;
|
|
261
|
+
}
|
|
262
|
+
function buildPatchHunk(original, edited, oldText, newText, index) {
|
|
263
|
+
const originalLines = splitLines(original);
|
|
264
|
+
const editedLines = splitLines(edited);
|
|
265
|
+
const oldLines = splitLines(oldText);
|
|
266
|
+
const newLines = splitLines(newText);
|
|
267
|
+
const changedLine = lineNumberForIndex(original, index);
|
|
268
|
+
const contextStart = Math.max(1, changedLine - SNIPPET_RADIUS);
|
|
269
|
+
const oldStart = contextStart;
|
|
270
|
+
const newStart = contextStart;
|
|
271
|
+
const prefixContext = originalLines.slice(contextStart - 1, changedLine - 1);
|
|
272
|
+
const oldEnd = changedLine + oldLines.length - 1;
|
|
273
|
+
const suffixContext = originalLines.slice(oldEnd, Math.min(originalLines.length, oldEnd + SNIPPET_RADIUS));
|
|
274
|
+
const lines = [
|
|
275
|
+
...prefixContext.map((line) => ` ${line}`),
|
|
276
|
+
...oldLines.map((line) => `-${line}`),
|
|
277
|
+
...newLines.map((line) => `+${line}`),
|
|
278
|
+
...suffixContext.map((line) => ` ${line}`),
|
|
279
|
+
];
|
|
280
|
+
return {
|
|
281
|
+
oldStart,
|
|
282
|
+
oldLines: prefixContext.length + oldLines.length + suffixContext.length,
|
|
283
|
+
newStart,
|
|
284
|
+
newLines: prefixContext.length + newLines.length + suffixContext.length,
|
|
285
|
+
lines,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function patchLines(content) {
|
|
289
|
+
return content.length === 0 ? [] : splitLines(content);
|
|
290
|
+
}
|
|
291
|
+
function buildContentPatchHunks(original, edited) {
|
|
292
|
+
const oldLines = patchLines(original);
|
|
293
|
+
const newLines = patchLines(edited);
|
|
294
|
+
let prefix = 0;
|
|
295
|
+
while (prefix < oldLines.length &&
|
|
296
|
+
prefix < newLines.length &&
|
|
297
|
+
oldLines[prefix] === newLines[prefix]) {
|
|
298
|
+
prefix += 1;
|
|
299
|
+
}
|
|
300
|
+
let oldEnd = oldLines.length - 1;
|
|
301
|
+
let newEnd = newLines.length - 1;
|
|
302
|
+
while (oldEnd >= prefix &&
|
|
303
|
+
newEnd >= prefix &&
|
|
304
|
+
oldLines[oldEnd] === newLines[newEnd]) {
|
|
305
|
+
oldEnd -= 1;
|
|
306
|
+
newEnd -= 1;
|
|
307
|
+
}
|
|
308
|
+
if (oldEnd < prefix && newEnd < prefix) {
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
const contextStart = Math.max(0, prefix - SNIPPET_RADIUS);
|
|
312
|
+
const oldSuffixStart = oldEnd + 1;
|
|
313
|
+
const oldSuffixEnd = Math.min(oldLines.length, oldSuffixStart + SNIPPET_RADIUS);
|
|
314
|
+
const prefixContext = oldLines.slice(contextStart, prefix);
|
|
315
|
+
const removed = oldLines.slice(prefix, oldEnd + 1);
|
|
316
|
+
const added = newLines.slice(prefix, newEnd + 1);
|
|
317
|
+
const suffixContext = oldLines.slice(oldSuffixStart, oldSuffixEnd);
|
|
318
|
+
return [
|
|
319
|
+
{
|
|
320
|
+
oldStart: contextStart + 1,
|
|
321
|
+
oldLines: prefixContext.length + removed.length + suffixContext.length,
|
|
322
|
+
newStart: contextStart + 1,
|
|
323
|
+
newLines: prefixContext.length + added.length + suffixContext.length,
|
|
324
|
+
lines: [
|
|
325
|
+
...prefixContext.map((line) => ` ${line}`),
|
|
326
|
+
...removed.map((line) => `-${line}`),
|
|
327
|
+
...added.map((line) => `+${line}`),
|
|
328
|
+
...suffixContext.map((line) => ` ${line}`),
|
|
329
|
+
],
|
|
330
|
+
},
|
|
331
|
+
];
|
|
332
|
+
}
|
|
333
|
+
function applyEdits(original, edits) {
|
|
334
|
+
let current = original;
|
|
335
|
+
const replacements = [];
|
|
336
|
+
for (const edit of edits) {
|
|
337
|
+
const matches = [
|
|
338
|
+
...current.matchAll(new RegExp(escapeRegExp(edit.oldText), "g")),
|
|
339
|
+
];
|
|
340
|
+
if (matches.length === 0) {
|
|
341
|
+
throw new Error(`Could not find edit target:\n${edit.oldText}`);
|
|
342
|
+
}
|
|
343
|
+
if (matches.length > 1) {
|
|
344
|
+
throw new Error(`Edit target is ambiguous and appears ${matches.length} times:\n${edit.oldText}`);
|
|
345
|
+
}
|
|
346
|
+
const match = matches[0];
|
|
347
|
+
const index = match.index ?? -1;
|
|
348
|
+
const previous = current;
|
|
349
|
+
current =
|
|
350
|
+
current.slice(0, index) +
|
|
351
|
+
edit.newText +
|
|
352
|
+
current.slice(index + edit.oldText.length);
|
|
353
|
+
replacements.push({
|
|
354
|
+
index,
|
|
355
|
+
snippet: snippetAroundChange(current, index, countLines(edit.newText)),
|
|
356
|
+
hunk: buildPatchHunk(previous, current, edit.oldText, edit.newText, index),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return { content: current, replacements };
|
|
360
|
+
}
|
|
361
|
+
function escapeRegExp(value) {
|
|
362
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
363
|
+
}
|
|
364
|
+
async function walkDirectory(dirPath, options) {
|
|
365
|
+
const results = [];
|
|
366
|
+
const recursive = options?.recursive ?? false;
|
|
367
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_TREE_DEPTH;
|
|
368
|
+
const excludes = (options?.excludePatterns ?? []).map(globToRegExp);
|
|
369
|
+
async function visit(currentPath, depth) {
|
|
370
|
+
const entries = await fs.readdir(currentPath, { withFileTypes: true });
|
|
371
|
+
for (const entry of entries) {
|
|
372
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
373
|
+
const relative = normalizeForGlob(path.relative(dirPath, fullPath) || entry.name);
|
|
374
|
+
if (excludes.some((pattern) => pattern.test(relative))) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
if (entry.isDirectory()) {
|
|
378
|
+
results.push({ path: fullPath, type: "directory" });
|
|
379
|
+
if (recursive && depth < maxDepth) {
|
|
380
|
+
await visit(fullPath, depth + 1);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
else if (entry.isFile()) {
|
|
384
|
+
const stat = await fs.stat(fullPath);
|
|
385
|
+
results.push({ path: fullPath, type: "file", size: stat.size });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
await visit(dirPath, 1);
|
|
390
|
+
return results;
|
|
391
|
+
}
|
|
392
|
+
async function buildTree(rootPath, options) {
|
|
393
|
+
const excludes = (options?.excludePatterns ?? []).map(globToRegExp);
|
|
394
|
+
const maxDepth = options?.maxDepth ?? DEFAULT_TREE_DEPTH;
|
|
395
|
+
async function build(currentPath, depth) {
|
|
396
|
+
const stat = await fs.stat(currentPath);
|
|
397
|
+
const node = {
|
|
398
|
+
name: path.basename(currentPath) || currentPath,
|
|
399
|
+
path: currentPath,
|
|
400
|
+
type: stat.isDirectory() ? "directory" : "file",
|
|
401
|
+
};
|
|
402
|
+
if (!stat.isDirectory() || depth >= maxDepth) {
|
|
403
|
+
return node;
|
|
404
|
+
}
|
|
405
|
+
const entries = await fs.readdir(currentPath, { withFileTypes: true });
|
|
406
|
+
const children = [];
|
|
407
|
+
for (const entry of entries) {
|
|
408
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
409
|
+
const relative = normalizeForGlob(path.relative(rootPath, fullPath) || entry.name);
|
|
410
|
+
if (excludes.some((pattern) => pattern.test(relative))) {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
children.push(await build(fullPath, depth + 1));
|
|
414
|
+
}
|
|
415
|
+
node.children = children;
|
|
416
|
+
return node;
|
|
417
|
+
}
|
|
418
|
+
return build(rootPath, 1);
|
|
419
|
+
}
|
|
420
|
+
async function searchFiles(rootPath, pattern, options) {
|
|
421
|
+
const matcher = globToRegExp(pattern);
|
|
422
|
+
const excludes = (options?.excludePatterns ?? []).map(globToRegExp);
|
|
423
|
+
const maxResults = options?.maxResults ?? DEFAULT_SEARCH_MAX_RESULTS;
|
|
424
|
+
const results = [];
|
|
425
|
+
async function visit(currentPath) {
|
|
426
|
+
if (results.length >= maxResults) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const entries = await fs.readdir(currentPath, { withFileTypes: true });
|
|
430
|
+
for (const entry of entries) {
|
|
431
|
+
if (results.length >= maxResults) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
435
|
+
const relative = normalizeForGlob(path.relative(rootPath, fullPath) || entry.name);
|
|
436
|
+
if (excludes.some((exclude) => exclude.test(relative))) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (matcher.test(relative) || matcher.test(entry.name)) {
|
|
440
|
+
results.push(fullPath);
|
|
441
|
+
}
|
|
442
|
+
if (entry.isDirectory()) {
|
|
443
|
+
await visit(fullPath);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
await visit(rootPath);
|
|
448
|
+
return results;
|
|
449
|
+
}
|
|
450
|
+
function createFilesystemSchema() {
|
|
451
|
+
return {
|
|
452
|
+
readFile: z.object({
|
|
453
|
+
path: z.string().describe("File path to read."),
|
|
454
|
+
offset: z
|
|
455
|
+
.number()
|
|
456
|
+
.int()
|
|
457
|
+
.min(1)
|
|
458
|
+
.optional()
|
|
459
|
+
.describe("1-indexed starting line."),
|
|
460
|
+
limit: z
|
|
461
|
+
.number()
|
|
462
|
+
.int()
|
|
463
|
+
.min(1)
|
|
464
|
+
.optional()
|
|
465
|
+
.describe("Maximum number of lines to read."),
|
|
466
|
+
binary: z
|
|
467
|
+
.boolean()
|
|
468
|
+
.optional()
|
|
469
|
+
.describe("Read as binary. Images, videos, and documents are returned as multimodal content blocks (forwarded to the active provider's native media format where supported); other binary files come back as base64."),
|
|
470
|
+
}),
|
|
471
|
+
readMultipleFiles: z.object({
|
|
472
|
+
paths: z.array(z.string()).min(1).describe("List of file paths to read."),
|
|
473
|
+
offset: z.number().int().min(1).optional(),
|
|
474
|
+
limit: z.number().int().min(1).optional(),
|
|
475
|
+
}),
|
|
476
|
+
writeFile: z.object({
|
|
477
|
+
path: z.string().describe("File path to write."),
|
|
478
|
+
content: z.string().describe("Content to write."),
|
|
479
|
+
append: z.boolean().optional().describe("Append instead of overwrite."),
|
|
480
|
+
create_parents: z
|
|
481
|
+
.boolean()
|
|
482
|
+
.optional()
|
|
483
|
+
.describe("Create parent directories if needed."),
|
|
484
|
+
}),
|
|
485
|
+
editFile: z.object({
|
|
486
|
+
path: z.string().describe("File path to edit."),
|
|
487
|
+
edits: z
|
|
488
|
+
.array(EditSchema)
|
|
489
|
+
.min(1)
|
|
490
|
+
.describe("Exact text replacements to apply in order."),
|
|
491
|
+
dry_run: z
|
|
492
|
+
.boolean()
|
|
493
|
+
.optional()
|
|
494
|
+
.describe("Preview edits without writing the file."),
|
|
495
|
+
}),
|
|
496
|
+
createDirectory: z.object({
|
|
497
|
+
path: z.string().describe("Directory path to create."),
|
|
498
|
+
recursive: z
|
|
499
|
+
.boolean()
|
|
500
|
+
.optional()
|
|
501
|
+
.describe("Create parent directories too."),
|
|
502
|
+
}),
|
|
503
|
+
listDirectory: z.object({
|
|
504
|
+
path: z.string().describe("Directory path to list."),
|
|
505
|
+
recursive: z.boolean().optional().describe("List recursively."),
|
|
506
|
+
max_depth: z
|
|
507
|
+
.number()
|
|
508
|
+
.int()
|
|
509
|
+
.min(1)
|
|
510
|
+
.optional()
|
|
511
|
+
.describe("Maximum recursion depth."),
|
|
512
|
+
exclude_patterns: z
|
|
513
|
+
.array(z.string())
|
|
514
|
+
.optional()
|
|
515
|
+
.describe("Glob-style exclude patterns."),
|
|
516
|
+
}),
|
|
517
|
+
directoryTree: z.object({
|
|
518
|
+
path: z.string().describe("Directory path to render as a tree."),
|
|
519
|
+
max_depth: z.number().int().min(1).optional(),
|
|
520
|
+
exclude_patterns: z.array(z.string()).optional(),
|
|
521
|
+
}),
|
|
522
|
+
moveFile: z.object({
|
|
523
|
+
source: z.string().describe("Source file or directory."),
|
|
524
|
+
destination: z.string().describe("Destination path."),
|
|
525
|
+
overwrite: z
|
|
526
|
+
.boolean()
|
|
527
|
+
.optional()
|
|
528
|
+
.describe("Overwrite destination if it exists."),
|
|
529
|
+
}),
|
|
530
|
+
searchFiles: z.object({
|
|
531
|
+
path: z.string().describe("Root directory to search."),
|
|
532
|
+
pattern: z
|
|
533
|
+
.string()
|
|
534
|
+
.describe("Glob-style pattern, e.g. '**/*.ts' or '*.md'."),
|
|
535
|
+
exclude_patterns: z.array(z.string()).optional(),
|
|
536
|
+
max_results: z.number().int().min(1).optional(),
|
|
537
|
+
}),
|
|
538
|
+
getFileInfo: z.object({
|
|
539
|
+
path: z.string().describe("File or directory path."),
|
|
540
|
+
}),
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
export function createFilesystemTools() {
|
|
544
|
+
const schema = createFilesystemSchema();
|
|
545
|
+
return [
|
|
546
|
+
tool({
|
|
547
|
+
name: "read_file",
|
|
548
|
+
description: "Read a file. Defaults to UTF-8 text with optional line offset/limit. Pass `binary: true` for non-text files: images (jpeg/png/gif/webp), videos (mp4/mov/mkv/webm/etc.), and documents (pdf/docx/csv/etc.) are returned as multimodal content blocks — the active model provider forwards them natively where supported (Bedrock for all; Anthropic for images + docs; Google for images + docs; OpenAI for images; Ollama for images) and logs a warning for unsupported kinds. Any other binary file is returned as base64.",
|
|
549
|
+
inputSchema: schema.readFile,
|
|
550
|
+
callback: async (input) => {
|
|
551
|
+
const filePath = normalizeUserPath(input.path);
|
|
552
|
+
if (input.binary) {
|
|
553
|
+
// Binary reads can return SDK media blocks (ImageBlock / DocumentBlock)
|
|
554
|
+
// or a plain base64 JSON object. Both are accepted by FunctionTool's
|
|
555
|
+
// result wrapping, but the callback signature is JSONValue, so cast.
|
|
556
|
+
const result = await readBinaryFile(filePath);
|
|
557
|
+
return result;
|
|
558
|
+
}
|
|
559
|
+
const result = await readTextFile(filePath, {
|
|
560
|
+
offset: input.offset,
|
|
561
|
+
limit: input.limit,
|
|
562
|
+
});
|
|
563
|
+
return toJsonValue(result);
|
|
564
|
+
},
|
|
565
|
+
}),
|
|
566
|
+
tool({
|
|
567
|
+
name: "read_multiple_files",
|
|
568
|
+
description: "Read multiple text files in one call. Each file is returned independently with success or error details.",
|
|
569
|
+
inputSchema: schema.readMultipleFiles,
|
|
570
|
+
callback: async (input) => {
|
|
571
|
+
const results = await Promise.all(input.paths.map(async (itemPath) => {
|
|
572
|
+
const filePath = normalizeUserPath(itemPath);
|
|
573
|
+
try {
|
|
574
|
+
const readResult = await readTextFile(filePath, {
|
|
575
|
+
offset: input.offset,
|
|
576
|
+
limit: input.limit,
|
|
577
|
+
});
|
|
578
|
+
return {
|
|
579
|
+
ok: true,
|
|
580
|
+
...readResult,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
return {
|
|
585
|
+
path: filePath,
|
|
586
|
+
ok: false,
|
|
587
|
+
error: error instanceof Error ? error.message : String(error),
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
}));
|
|
591
|
+
return toJsonValue({ results });
|
|
592
|
+
},
|
|
593
|
+
}),
|
|
594
|
+
tool({
|
|
595
|
+
name: "write_file",
|
|
596
|
+
description: "Write text content to a file. Can overwrite or append, and can create parent directories when requested.",
|
|
597
|
+
inputSchema: schema.writeFile,
|
|
598
|
+
callback: async (input, context) => {
|
|
599
|
+
const filePath = normalizeUserPath(input.path);
|
|
600
|
+
if (input.create_parents ?? true) {
|
|
601
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
602
|
+
}
|
|
603
|
+
let oldContent = "";
|
|
604
|
+
try {
|
|
605
|
+
oldContent = normalizeLineEndings(await fs.readFile(filePath, "utf8"));
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
oldContent = "";
|
|
609
|
+
}
|
|
610
|
+
if (input.append) {
|
|
611
|
+
await fs.appendFile(filePath, input.content, "utf8");
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
await fs.writeFile(filePath, input.content, "utf8");
|
|
615
|
+
}
|
|
616
|
+
const newContent = input.append
|
|
617
|
+
? `${oldContent}${normalizeLineEndings(input.content)}`
|
|
618
|
+
: normalizeLineEndings(input.content);
|
|
619
|
+
const structuredPatch = buildContentPatchHunks(oldContent, newContent);
|
|
620
|
+
if (structuredPatch.length > 0) {
|
|
621
|
+
if (context) {
|
|
622
|
+
setFileToolDisplay(context.agent.appState, context.toolUse.toolUseId, {
|
|
623
|
+
structuredPatch,
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return toJsonValue({
|
|
628
|
+
path: filePath,
|
|
629
|
+
appended: input.append ?? false,
|
|
630
|
+
bytes_written: Buffer.byteLength(input.content, "utf8"),
|
|
631
|
+
});
|
|
632
|
+
},
|
|
633
|
+
}),
|
|
634
|
+
tool({
|
|
635
|
+
name: "edit_file",
|
|
636
|
+
description: "Apply exact text replacements to a file. Fails if any replacement target is missing or ambiguous.",
|
|
637
|
+
inputSchema: schema.editFile,
|
|
638
|
+
callback: async (input, context) => {
|
|
639
|
+
const filePath = normalizeUserPath(input.path);
|
|
640
|
+
const stat = await statFile(filePath);
|
|
641
|
+
const previousRead = textReadState.get(filePath);
|
|
642
|
+
const rawOriginal = await fs.readFile(filePath, "utf8");
|
|
643
|
+
const lineEndings = detectLineEndings(rawOriginal);
|
|
644
|
+
const original = normalizeLineEndings(rawOriginal);
|
|
645
|
+
if (previousRead && stat.mtimeMs > previousRead.mtimeMs) {
|
|
646
|
+
const fullReadWasUnchanged = !previousRead.isPartial && previousRead.content === original;
|
|
647
|
+
if (!fullReadWasUnchanged) {
|
|
648
|
+
throw new Error("File changed since it was last read. Read the file again before editing.");
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
const edited = applyEdits(original, input.edits);
|
|
652
|
+
const contentToWrite = restoreLineEndings(edited.content, lineEndings);
|
|
653
|
+
if (!input.dry_run) {
|
|
654
|
+
await fs.writeFile(filePath, contentToWrite, "utf8");
|
|
655
|
+
const updatedStat = await fs.stat(filePath);
|
|
656
|
+
textReadState.set(filePath, {
|
|
657
|
+
content: edited.content,
|
|
658
|
+
mtimeMs: updatedStat.mtimeMs,
|
|
659
|
+
offset: 1,
|
|
660
|
+
limit: undefined,
|
|
661
|
+
isPartial: false,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
if (context) {
|
|
665
|
+
setFileToolDisplay(context.agent.appState, context.toolUse.toolUseId, {
|
|
666
|
+
previews: edited.replacements.map((item) => item.snippet),
|
|
667
|
+
structuredPatch: edited.replacements.map((item) => item.hunk),
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return toJsonValue({
|
|
671
|
+
path: filePath,
|
|
672
|
+
dry_run: input.dry_run ?? false,
|
|
673
|
+
edits_applied: input.edits.length,
|
|
674
|
+
changed: edited.content !== original,
|
|
675
|
+
sha256_before: createHash("sha256").update(original).digest("hex"),
|
|
676
|
+
sha256_after: createHash("sha256")
|
|
677
|
+
.update(edited.content)
|
|
678
|
+
.digest("hex"),
|
|
679
|
+
});
|
|
680
|
+
},
|
|
681
|
+
}),
|
|
682
|
+
tool({
|
|
683
|
+
name: "create_directory",
|
|
684
|
+
description: "Create a directory, optionally including missing parent directories.",
|
|
685
|
+
inputSchema: schema.createDirectory,
|
|
686
|
+
callback: async (input) => {
|
|
687
|
+
const dirPath = normalizeUserPath(input.path);
|
|
688
|
+
await fs.mkdir(dirPath, { recursive: input.recursive ?? true });
|
|
689
|
+
return toJsonValue({
|
|
690
|
+
path: dirPath,
|
|
691
|
+
recursive: input.recursive ?? true,
|
|
692
|
+
});
|
|
693
|
+
},
|
|
694
|
+
}),
|
|
695
|
+
tool({
|
|
696
|
+
name: "list_directory",
|
|
697
|
+
description: "List files and directories at a path, optionally recursively with depth and exclude patterns.",
|
|
698
|
+
inputSchema: schema.listDirectory,
|
|
699
|
+
callback: async (input) => {
|
|
700
|
+
const dirPath = normalizeUserPath(input.path);
|
|
701
|
+
await ensureExists(dirPath);
|
|
702
|
+
await ensureDirectory(dirPath);
|
|
703
|
+
const entries = await walkDirectory(dirPath, {
|
|
704
|
+
recursive: input.recursive,
|
|
705
|
+
maxDepth: input.max_depth,
|
|
706
|
+
excludePatterns: input.exclude_patterns,
|
|
707
|
+
});
|
|
708
|
+
return toJsonValue({
|
|
709
|
+
path: dirPath,
|
|
710
|
+
count: entries.length,
|
|
711
|
+
entries,
|
|
712
|
+
});
|
|
713
|
+
},
|
|
714
|
+
}),
|
|
715
|
+
tool({
|
|
716
|
+
name: "directory_tree",
|
|
717
|
+
description: "Return a recursive JSON tree of a directory, with optional depth and exclude patterns.",
|
|
718
|
+
inputSchema: schema.directoryTree,
|
|
719
|
+
callback: async (input) => {
|
|
720
|
+
const dirPath = normalizeUserPath(input.path);
|
|
721
|
+
await ensureExists(dirPath);
|
|
722
|
+
await ensureDirectory(dirPath);
|
|
723
|
+
return toJsonValue(await buildTree(dirPath, {
|
|
724
|
+
maxDepth: input.max_depth,
|
|
725
|
+
excludePatterns: input.exclude_patterns,
|
|
726
|
+
}));
|
|
727
|
+
},
|
|
728
|
+
}),
|
|
729
|
+
tool({
|
|
730
|
+
name: "move_file",
|
|
731
|
+
description: "Move or rename a file or directory. Can overwrite the destination if explicitly enabled.",
|
|
732
|
+
inputSchema: schema.moveFile,
|
|
733
|
+
callback: async (input) => {
|
|
734
|
+
const source = normalizeUserPath(input.source);
|
|
735
|
+
const destination = normalizeUserPath(input.destination);
|
|
736
|
+
await ensureExists(source);
|
|
737
|
+
if (input.overwrite) {
|
|
738
|
+
await fs.rm(destination, { recursive: true, force: true });
|
|
739
|
+
}
|
|
740
|
+
await fs.mkdir(path.dirname(destination), { recursive: true });
|
|
741
|
+
await fs.rename(source, destination);
|
|
742
|
+
return toJsonValue({
|
|
743
|
+
source,
|
|
744
|
+
destination,
|
|
745
|
+
overwritten: input.overwrite ?? false,
|
|
746
|
+
});
|
|
747
|
+
},
|
|
748
|
+
}),
|
|
749
|
+
tool({
|
|
750
|
+
name: "search_files",
|
|
751
|
+
description: "Recursively search for files and directories under a root path using glob-style matching.",
|
|
752
|
+
inputSchema: schema.searchFiles,
|
|
753
|
+
callback: async (input) => {
|
|
754
|
+
const rootPath = normalizeUserPath(input.path);
|
|
755
|
+
await ensureExists(rootPath);
|
|
756
|
+
await ensureDirectory(rootPath);
|
|
757
|
+
const matches = await searchFiles(rootPath, input.pattern, {
|
|
758
|
+
excludePatterns: input.exclude_patterns,
|
|
759
|
+
maxResults: input.max_results,
|
|
760
|
+
});
|
|
761
|
+
return toJsonValue({
|
|
762
|
+
path: rootPath,
|
|
763
|
+
pattern: input.pattern,
|
|
764
|
+
count: matches.length,
|
|
765
|
+
matches,
|
|
766
|
+
});
|
|
767
|
+
},
|
|
768
|
+
}),
|
|
769
|
+
tool({
|
|
770
|
+
name: "get_file_info",
|
|
771
|
+
description: "Get metadata for a file or directory, including timestamps, size, type, and permissions.",
|
|
772
|
+
inputSchema: schema.getFileInfo,
|
|
773
|
+
callback: async (input) => {
|
|
774
|
+
const filePath = normalizeUserPath(input.path);
|
|
775
|
+
const stat = await fs.stat(filePath);
|
|
776
|
+
return toJsonValue({
|
|
777
|
+
path: filePath,
|
|
778
|
+
name: path.basename(filePath),
|
|
779
|
+
size_bytes: stat.size,
|
|
780
|
+
created_at: stat.birthtime.toISOString(),
|
|
781
|
+
modified_at: stat.mtime.toISOString(),
|
|
782
|
+
accessed_at: stat.atime.toISOString(),
|
|
783
|
+
is_file: stat.isFile(),
|
|
784
|
+
is_directory: stat.isDirectory(),
|
|
785
|
+
permissions_octal: stat.mode.toString(8).slice(-3),
|
|
786
|
+
});
|
|
787
|
+
},
|
|
788
|
+
}),
|
|
789
|
+
];
|
|
790
|
+
}
|
|
791
|
+
//# sourceMappingURL=filesystem.js.map
|