@travisennis/acai 0.0.9 → 0.0.11
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 +51 -760
- package/bin/acai +52 -0
- package/dist/agent/index.d.ts +12 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +380 -199
- package/dist/agent/sub-agent.d.ts +23 -0
- package/dist/agent/sub-agent.d.ts.map +1 -0
- package/dist/agent/sub-agent.js +109 -0
- package/dist/cli/index.d.ts +26 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{cli.js → cli/index.js} +84 -77
- package/dist/{stdin.d.ts → cli/stdin.d.ts} +2 -1
- package/dist/cli/stdin.d.ts.map +1 -0
- package/dist/{stdin.js → cli/stdin.js} +11 -0
- package/dist/commands/copy/index.js +2 -2
- package/dist/commands/copy/utils.d.ts.map +1 -1
- package/dist/commands/copy/utils.js +15 -13
- package/dist/commands/generate-rules/index.d.ts +1 -1
- package/dist/commands/generate-rules/index.d.ts.map +1 -1
- package/dist/commands/generate-rules/index.js +16 -101
- package/dist/commands/generate-rules/service.d.ts +22 -0
- package/dist/commands/generate-rules/service.d.ts.map +1 -0
- package/dist/commands/generate-rules/service.js +103 -0
- package/dist/commands/handoff/index.js +2 -2
- package/dist/commands/health/index.js +1 -1
- package/dist/commands/health/utils.d.ts +3 -2
- package/dist/commands/health/utils.d.ts.map +1 -1
- package/dist/commands/health/utils.js +6 -0
- package/dist/commands/history/index.d.ts +1 -1
- package/dist/commands/history/index.d.ts.map +1 -1
- package/dist/commands/history/index.js +17 -18
- package/dist/commands/history/types.d.ts +38 -0
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/history/utils.d.ts.map +1 -1
- package/dist/commands/history/utils.js +63 -58
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +3 -8
- package/dist/commands/init-project/index.d.ts.map +1 -1
- package/dist/commands/init-project/index.js +3 -3
- package/dist/commands/init-project/utils.d.ts +2 -1
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +10 -2
- package/dist/commands/list-tools/index.d.ts.map +1 -1
- package/dist/commands/list-tools/index.js +7 -31
- package/dist/commands/manager.d.ts +2 -2
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +55 -33
- package/dist/commands/model/index.d.ts.map +1 -1
- package/dist/commands/model/index.js +20 -151
- package/dist/commands/model/model-panel.d.ts +4 -0
- package/dist/commands/model/model-panel.d.ts.map +1 -0
- package/dist/commands/model/model-panel.js +144 -0
- package/dist/commands/paste/index.d.ts.map +1 -1
- package/dist/commands/paste/index.js +59 -62
- package/dist/commands/paste/utils.d.ts.map +1 -1
- package/dist/commands/paste/utils.js +88 -58
- package/dist/commands/pickup/index.d.ts.map +1 -1
- package/dist/commands/pickup/index.js +6 -3
- package/dist/commands/pickup/utils.js +3 -3
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +33 -50
- package/dist/commands/review/index.d.ts.map +1 -1
- package/dist/commands/review/index.js +3 -117
- package/dist/commands/review/review-panel.d.ts +3 -0
- package/dist/commands/review/review-panel.d.ts.map +1 -0
- package/dist/commands/review/review-panel.js +186 -0
- package/dist/commands/review/utils.d.ts +15 -1
- package/dist/commands/review/utils.d.ts.map +1 -1
- package/dist/commands/review/utils.js +127 -68
- package/dist/commands/session/index.d.ts +1 -1
- package/dist/commands/session/index.d.ts.map +1 -1
- package/dist/commands/session/index.js +124 -135
- package/dist/commands/shell/index.d.ts.map +1 -1
- package/dist/commands/shell/index.js +16 -1
- package/dist/commands/types.d.ts +2 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/{config.d.ts → config/index.d.ts} +20 -9
- package/dist/config/index.d.ts.map +1 -0
- package/dist/{config.js → config/index.js} +43 -42
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +75 -55
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -141
- package/dist/middleware/cache.d.ts.map +1 -1
- package/dist/middleware/cache.js +18 -36
- package/dist/models/ai-config.d.ts +1 -0
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +4 -3
- package/dist/models/anthropic-provider.d.ts +2 -5
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -70
- package/dist/models/deepseek-provider.d.ts +1 -0
- package/dist/models/deepseek-provider.d.ts.map +1 -1
- package/dist/models/google-provider.d.ts +2 -3
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +0 -26
- package/dist/models/groq-provider.d.ts +1 -0
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/manager.d.ts +13 -2
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +20 -8
- package/dist/models/openai-provider.d.ts +2 -5
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +0 -52
- package/dist/models/opencode-go-provider.d.ts +25 -0
- package/dist/models/opencode-go-provider.d.ts.map +1 -0
- package/dist/models/opencode-go-provider.js +78 -0
- package/dist/models/opencode-zen-provider.d.ts +7 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +49 -10
- package/dist/models/openrouter-provider.d.ts +27 -31
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +121 -180
- package/dist/models/providers.d.ts +3 -3
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +6 -0
- package/dist/models/xai-provider.d.ts +4 -3
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +18 -18
- package/dist/modes/manager.d.ts +24 -0
- package/dist/modes/manager.d.ts.map +1 -0
- package/dist/modes/manager.js +77 -0
- package/dist/modes/prompts.d.ts +2 -0
- package/dist/modes/prompts.d.ts.map +1 -0
- package/dist/modes/prompts.js +142 -0
- package/dist/prompts/mentions.d.ts +11 -0
- package/dist/prompts/mentions.d.ts.map +1 -0
- package/dist/{mentions.js → prompts/mentions.js} +55 -85
- package/dist/{prompts.d.ts → prompts/system-prompt.d.ts} +7 -2
- package/dist/prompts/system-prompt.d.ts.map +1 -0
- package/dist/{prompts.js → prompts/system-prompt.js} +31 -16
- package/dist/repl/index.d.ts +174 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/{repl-new.js → repl/index.js} +397 -76
- package/dist/repl/project-status.d.ts +1 -0
- package/dist/repl/project-status.d.ts.map +1 -1
- package/dist/repl/project-status.js +4 -1
- package/dist/sessions/manager.d.ts +92 -0
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +262 -9
- package/dist/sessions/summary.d.ts +4 -0
- package/dist/sessions/summary.d.ts.map +1 -0
- package/dist/sessions/summary.js +30 -0
- package/dist/skills/index.d.ts +29 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +294 -0
- package/dist/subagents/index.d.ts +16 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +231 -0
- package/dist/terminal/control.d.ts +1 -1
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +3 -3
- package/dist/terminal/east-asian-width.d.ts.map +1 -1
- package/dist/terminal/east-asian-width.js +404 -351
- package/dist/terminal/keys.d.ts +17 -0
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +37 -0
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +24 -12
- package/dist/terminal/string-width.d.ts.map +1 -1
- package/dist/terminal/string-width.js +25 -27
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/style.js +4 -7
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +41 -27
- package/dist/terminal/table/cell.d.ts +12 -0
- package/dist/terminal/table/cell.d.ts.map +1 -1
- package/dist/terminal/table/cell.js +40 -25
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +100 -68
- package/dist/terminal/table/utils.d.ts +1 -1
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +17 -10
- package/dist/terminal/wrap-ansi.d.ts.map +1 -1
- package/dist/terminal/wrap-ansi.js +174 -105
- package/dist/tokens/tracker.d.ts +1 -0
- package/dist/tokens/tracker.d.ts.map +1 -1
- package/dist/tokens/tracker.js +3 -0
- package/dist/tools/agent.d.ts +27 -0
- package/dist/tools/agent.d.ts.map +1 -0
- package/dist/tools/agent.js +81 -0
- package/dist/tools/apply-patch.d.ts +62 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +377 -0
- package/dist/tools/bash.d.ts +4 -3
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +349 -141
- package/dist/tools/directory-tree.d.ts +3 -3
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +8 -5
- package/dist/tools/dynamic-tool-loader.d.ts +3 -6
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +20 -4
- package/dist/tools/edit-file.d.ts +7 -7
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +292 -85
- package/dist/tools/glob.d.ts +6 -6
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +110 -63
- package/dist/tools/grep.d.ts +15 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +315 -193
- package/dist/tools/index.d.ts +114 -9
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +39 -24
- package/dist/tools/ls.d.ts +2 -2
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +7 -5
- package/dist/tools/read-file.d.ts +4 -6
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +84 -39
- package/dist/tools/save-file.d.ts +3 -3
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +36 -31
- package/dist/tools/skill.d.ts +23 -0
- package/dist/tools/skill.d.ts.map +1 -0
- package/dist/tools/skill.js +65 -0
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +2 -9
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +12 -0
- package/dist/tools/web-fetch.d.ts +50 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +446 -0
- package/dist/tools/web-search.d.ts +44 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +226 -0
- package/dist/tui/autocomplete/attachment-provider.d.ts +3 -6
- package/dist/tui/autocomplete/attachment-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/attachment-provider.js +25 -78
- package/dist/tui/autocomplete/base-provider.d.ts +1 -0
- package/dist/tui/autocomplete/base-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.d.ts +1 -4
- package/dist/tui/autocomplete/combined-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/combined-provider.js +3 -17
- package/dist/tui/autocomplete/command-provider.d.ts +1 -0
- package/dist/tui/autocomplete/command-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/command-provider.js +3 -0
- package/dist/tui/autocomplete/file-search-provider.d.ts +2 -1
- package/dist/tui/autocomplete/file-search-provider.d.ts.map +1 -1
- package/dist/tui/autocomplete/file-search-provider.js +37 -17
- package/dist/tui/autocomplete/skill-provider.d.ts +17 -0
- package/dist/tui/autocomplete/skill-provider.d.ts.map +1 -0
- package/dist/tui/autocomplete/skill-provider.js +49 -0
- package/dist/tui/autocomplete/utils.d.ts +2 -1
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +25 -23
- package/dist/tui/autocomplete.d.ts +2 -2
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +3 -5
- package/dist/tui/components/assistant-message.d.ts.map +1 -1
- package/dist/tui/components/assistant-message.js +0 -4
- package/dist/tui/components/editor.d.ts +18 -3
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +211 -237
- package/dist/tui/components/footer.d.ts +6 -4
- package/dist/tui/components/footer.d.ts.map +1 -1
- package/dist/tui/components/footer.js +49 -25
- package/dist/tui/components/markdown.d.ts +10 -7
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +57 -39
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +35 -33
- package/dist/tui/components/notification.d.ts +13 -2
- package/dist/tui/components/notification.d.ts.map +1 -1
- package/dist/tui/components/notification.js +36 -2
- package/dist/tui/components/progress-bar.js +1 -1
- package/dist/tui/components/select-list.d.ts +1 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +14 -11
- package/dist/tui/components/text.d.ts +16 -0
- package/dist/tui/components/text.d.ts.map +1 -1
- package/dist/tui/components/text.js +72 -57
- package/dist/tui/components/thinking-block.d.ts +9 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -1
- package/dist/tui/components/thinking-block.js +43 -11
- package/dist/tui/components/tool-execution.d.ts +5 -1
- package/dist/tui/components/tool-execution.d.ts.map +1 -1
- package/dist/tui/components/tool-execution.js +19 -10
- package/dist/tui/components/user-message.d.ts.map +1 -1
- package/dist/tui/components/user-message.js +0 -3
- package/dist/tui/components/welcome.d.ts +2 -1
- package/dist/tui/components/welcome.d.ts.map +1 -1
- package/dist/tui/components/welcome.js +2 -2
- package/dist/tui/editor-launcher.d.ts +3 -2
- package/dist/tui/editor-launcher.d.ts.map +1 -1
- package/dist/tui/index.d.ts +0 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/terminal.d.ts.map +1 -1
- package/dist/tui/terminal.js +10 -2
- package/dist/tui/tui.d.ts +43 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +166 -41
- package/dist/tui/utils.d.ts +1 -5
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +271 -44
- package/dist/utils/bash/parse.d.ts +19 -0
- package/dist/utils/bash/parse.d.ts.map +1 -0
- package/dist/utils/bash/parse.js +223 -0
- package/dist/utils/bash/quote.d.ts +6 -0
- package/dist/utils/bash/quote.d.ts.map +1 -0
- package/dist/utils/bash/quote.js +23 -0
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +211 -126
- package/dist/utils/command-protection.d.ts +28 -0
- package/dist/utils/command-protection.d.ts.map +1 -0
- package/dist/utils/command-protection.js +324 -0
- package/dist/utils/dedent.d.ts.map +1 -0
- package/dist/utils/env-expand.d.ts +2 -0
- package/dist/utils/env-expand.d.ts.map +1 -0
- package/dist/utils/env-expand.js +8 -0
- package/dist/utils/filesystem/path-display.d.ts +11 -0
- package/dist/utils/filesystem/path-display.d.ts.map +1 -0
- package/dist/utils/filesystem/path-display.js +32 -0
- package/dist/utils/filesystem/security.d.ts +2 -2
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +28 -30
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/{formatting.js → utils/formatting.js} +1 -1
- package/dist/utils/git.d.ts +4 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +30 -0
- package/dist/utils/glob.d.ts +1 -1
- package/dist/utils/glob.d.ts.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/{logger.js → utils/logger.js} +1 -1
- package/dist/utils/parsing.d.ts.map +1 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +90 -37
- package/dist/utils/templates.d.ts +2 -0
- package/dist/utils/templates.d.ts.map +1 -0
- package/dist/utils/templates.js +24 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/{version.js → utils/version.js} +1 -1
- package/package.json +35 -26
- package/dist/cli.d.ts +0 -23
- package/dist/cli.d.ts.map +0 -1
- package/dist/commands/add-directory/types.d.ts +0 -6
- package/dist/commands/add-directory/types.d.ts.map +0 -1
- package/dist/commands/add-directory/types.js +0 -1
- package/dist/commands/copy/types.d.ts +0 -3
- package/dist/commands/copy/types.d.ts.map +0 -1
- package/dist/commands/copy/types.js +0 -1
- package/dist/commands/exit/index.d.ts +0 -10
- package/dist/commands/exit/index.d.ts.map +0 -1
- package/dist/commands/exit/index.js +0 -21
- package/dist/commands/exit/types.d.ts +0 -8
- package/dist/commands/exit/types.d.ts.map +0 -1
- package/dist/commands/exit/types.js +0 -1
- package/dist/commands/exit/utils.d.ts +0 -2
- package/dist/commands/exit/utils.d.ts.map +0 -1
- package/dist/commands/exit/utils.js +0 -13
- package/dist/commands/prompt/index.d.ts +0 -5
- package/dist/commands/prompt/index.d.ts.map +0 -1
- package/dist/commands/prompt/index.js +0 -122
- package/dist/commands/prompt/types.d.ts +0 -15
- package/dist/commands/prompt/types.d.ts.map +0 -1
- package/dist/commands/prompt/types.js +0 -1
- package/dist/commands/prompt/utils.d.ts +0 -12
- package/dist/commands/prompt/utils.d.ts.map +0 -1
- package/dist/commands/prompt/utils.js +0 -107
- package/dist/commands/reset/index.d.ts +0 -3
- package/dist/commands/reset/index.d.ts.map +0 -1
- package/dist/commands/reset/index.js +0 -25
- package/dist/commands/reset/types.d.ts +0 -1
- package/dist/commands/reset/types.d.ts.map +0 -1
- package/dist/commands/reset/types.js +0 -3
- package/dist/commands/review/types.d.ts +0 -12
- package/dist/commands/review/types.d.ts.map +0 -1
- package/dist/commands/review/types.js +0 -1
- package/dist/commands/save/index.d.ts +0 -3
- package/dist/commands/save/index.d.ts.map +0 -1
- package/dist/commands/save/index.js +0 -19
- package/dist/config.d.ts.map +0 -1
- package/dist/dedent.d.ts.map +0 -1
- package/dist/formatting.d.ts.map +0 -1
- package/dist/logger.d.ts.map +0 -1
- package/dist/mentions.d.ts +0 -14
- package/dist/mentions.d.ts.map +0 -1
- package/dist/parsing.d.ts.map +0 -1
- package/dist/prompts.d.ts.map +0 -1
- package/dist/repl-new.d.ts +0 -65
- package/dist/repl-new.d.ts.map +0 -1
- package/dist/skills.d.ts +0 -16
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js +0 -233
- package/dist/stdin.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.d.ts +0 -21
- package/dist/tui/autocomplete/path-provider.d.ts.map +0 -1
- package/dist/tui/autocomplete/path-provider.js +0 -164
- package/dist/utils/iterables.d.ts +0 -2
- package/dist/utils/iterables.d.ts.map +0 -1
- package/dist/utils/iterables.js +0 -6
- package/dist/version.d.ts.map +0 -1
- /package/dist/{dedent.d.ts → utils/dedent.d.ts} +0 -0
- /package/dist/{dedent.js → utils/dedent.js} +0 -0
- /package/dist/{formatting.d.ts → utils/formatting.d.ts} +0 -0
- /package/dist/{logger.d.ts → utils/logger.d.ts} +0 -0
- /package/dist/{parsing.d.ts → utils/parsing.d.ts} +0 -0
- /package/dist/{parsing.js → utils/parsing.js} +0 -0
- /package/dist/{version.d.ts → utils/version.d.ts} +0 -0
|
@@ -16,7 +16,7 @@ declare const toolMetadataSchema: z.ZodObject<{
|
|
|
16
16
|
}, z.core.$strip>>;
|
|
17
17
|
needsApproval: z.ZodDefault<z.ZodBoolean>;
|
|
18
18
|
}, z.core.$strip>;
|
|
19
|
-
|
|
19
|
+
type ToolMetadata = z.infer<typeof toolMetadataSchema>;
|
|
20
20
|
export declare function parseToolMetadata(output: string): ToolMetadata;
|
|
21
21
|
interface DynamicToolObject {
|
|
22
22
|
toolDef: {
|
|
@@ -24,13 +24,10 @@ interface DynamicToolObject {
|
|
|
24
24
|
inputSchema: any;
|
|
25
25
|
};
|
|
26
26
|
execute: (input: Record<string, unknown>, options: ToolExecutionOptions) => Promise<string>;
|
|
27
|
-
ask?: (input: Record<string, unknown>, options: ToolExecutionOptions) => Promise<{
|
|
28
|
-
approve: boolean;
|
|
29
|
-
reason?: string;
|
|
30
|
-
}>;
|
|
31
27
|
}
|
|
32
|
-
export declare function loadDynamicTools({ baseDir }: {
|
|
28
|
+
export declare function loadDynamicTools({ baseDir, existingToolNames, }: {
|
|
33
29
|
baseDir: string;
|
|
30
|
+
existingToolNames?: string[];
|
|
34
31
|
}): Promise<Record<string, DynamicToolObject>>;
|
|
35
32
|
export {};
|
|
36
33
|
//# sourceMappingURL=dynamic-tool-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-tool-loader.d.ts","sourceRoot":"","sources":["../../source/tools/dynamic-tool-loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;iBAatB,CAAC;AAEH,
|
|
1
|
+
{"version":3,"file":"dynamic-tool-loader.d.ts","sourceRoot":"","sources":["../../source/tools/dynamic-tool-loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;iBAatB,CAAC;AAEH,KAAK,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEvD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAS9D;AA2LD,UAAU,iBAAiB;IACzB,OAAO,EAAE;QACP,WAAW,EAAE,MAAM,CAAC;QAEpB,WAAW,EAAE,GAAG,CAAC;KAClB,CAAC;IACF,OAAO,EAAE,CACP,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,MAAM,CAAC,CAAC;CACtB;AAwCD,wBAAsB,gBAAgB,CAAC,EACrC,OAAO,EACP,iBAAsB,GACvB,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B,8CA2FA"}
|
|
@@ -3,8 +3,8 @@ import fs from "node:fs";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { config } from "../config.js";
|
|
7
|
-
import { logger } from "../logger.js";
|
|
6
|
+
import { config } from "../config/index.js";
|
|
7
|
+
import { logger } from "../utils/logger.js";
|
|
8
8
|
// Tool Metadata Schema and Parser
|
|
9
9
|
const toolMetadataSchema = z.object({
|
|
10
10
|
name: z.string().regex(/^[a-zA-Z_][a-zA-Z0-9_-]*$/),
|
|
@@ -183,7 +183,7 @@ async function spawnChildProcess(scriptPath, params, abortSignal) {
|
|
|
183
183
|
}
|
|
184
184
|
function createDynamicTool(scriptPath, metadata) {
|
|
185
185
|
const inputSchema = generateZodSchema(metadata.parameters);
|
|
186
|
-
const toolName =
|
|
186
|
+
const toolName = metadata.name;
|
|
187
187
|
return {
|
|
188
188
|
[toolName]: {
|
|
189
189
|
toolDef: {
|
|
@@ -208,7 +208,7 @@ function createDynamicTool(scriptPath, metadata) {
|
|
|
208
208
|
},
|
|
209
209
|
};
|
|
210
210
|
}
|
|
211
|
-
export async function loadDynamicTools({ baseDir }) {
|
|
211
|
+
export async function loadDynamicTools({ baseDir, existingToolNames = [], }) {
|
|
212
212
|
const projectConfig = await config.getConfig();
|
|
213
213
|
const dynamicConfig = projectConfig.tools.dynamicTools;
|
|
214
214
|
if (!dynamicConfig.enabled) {
|
|
@@ -260,8 +260,24 @@ export async function loadDynamicTools({ baseDir }) {
|
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
const tools = {};
|
|
263
|
+
const conflictingTools = [];
|
|
263
264
|
for (const [_, { path, metadata }] of toolMap) {
|
|
265
|
+
const toolName = metadata.name;
|
|
266
|
+
// Check for conflicts with existing tools
|
|
267
|
+
if (existingToolNames.includes(toolName)) {
|
|
268
|
+
conflictingTools.push(toolName);
|
|
269
|
+
logger.warn(`Dynamic tool '${toolName}' conflicts with existing tool. Skipping.`);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
// Check for duplicate dynamic tool names
|
|
273
|
+
if (tools[toolName]) {
|
|
274
|
+
logger.warn(`Duplicate dynamic tool name '${toolName}' found. Skipping duplicate.`);
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
264
277
|
Object.assign(tools, createDynamicTool(path, metadata));
|
|
265
278
|
}
|
|
279
|
+
if (conflictingTools.length > 0) {
|
|
280
|
+
logger.warn(`Warning: ${conflictingTools.length} dynamic tool(s) skipped due to name conflicts: ${conflictingTools.join(", ")}`);
|
|
281
|
+
}
|
|
266
282
|
return tools;
|
|
267
283
|
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { WorkspaceContext } from "../index.ts";
|
|
2
3
|
import type { ToolExecutionOptions } from "./types.ts";
|
|
3
4
|
export declare const EditFileTool: {
|
|
4
5
|
name: "Edit";
|
|
5
6
|
};
|
|
6
7
|
declare const inputSchema: z.ZodObject<{
|
|
7
8
|
path: z.ZodString;
|
|
8
|
-
edits: z.ZodArray<z.ZodObject<{
|
|
9
|
+
edits: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodObject<{
|
|
9
10
|
oldText: z.ZodString;
|
|
10
11
|
newText: z.ZodString;
|
|
11
|
-
}, z.core.$strip
|
|
12
|
+
}, z.core.$strip>>>;
|
|
12
13
|
}, z.core.$strip>;
|
|
13
14
|
type EditFileInputSchema = z.infer<typeof inputSchema>;
|
|
14
|
-
export declare const createEditFileTool: (
|
|
15
|
-
|
|
16
|
-
allowedDirs?: string[];
|
|
15
|
+
export declare const createEditFileTool: (options: {
|
|
16
|
+
workspace: WorkspaceContext;
|
|
17
17
|
}) => Promise<{
|
|
18
18
|
toolDef: {
|
|
19
19
|
description: string;
|
|
20
20
|
inputSchema: z.ZodObject<{
|
|
21
21
|
path: z.ZodString;
|
|
22
|
-
edits: z.ZodArray<z.ZodObject<{
|
|
22
|
+
edits: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodArray<z.ZodObject<{
|
|
23
23
|
oldText: z.ZodString;
|
|
24
24
|
newText: z.ZodString;
|
|
25
|
-
}, z.core.$strip
|
|
25
|
+
}, z.core.$strip>>>;
|
|
26
26
|
}, z.core.$strip>;
|
|
27
27
|
};
|
|
28
28
|
display({ path, edits }: EditFileInputSchema): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edit-file.d.ts","sourceRoot":"","sources":["../../source/tools/edit-file.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"edit-file.d.ts","sourceRoot":"","sources":["../../source/tools/edit-file.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY;;CAExB,CAAC;AAIF,QAAA,MAAM,WAAW;;;;;;iBAqCf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAU,SAAS;IAChD,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;;;;6BAY4B,mBAAmB;6BAKzB,mBAAmB,mBACnB,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6BrB,CAAC;AAiDF,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAgQD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,UAAQ,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,MAAM,CAAC,CAqEjB"}
|
package/dist/tools/edit-file.js
CHANGED
|
@@ -1,46 +1,73 @@
|
|
|
1
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { access, constants, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { createTwoFilesPatch } from "diff";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { config } from "../config.js";
|
|
4
|
+
import { config } from "../config/index.js";
|
|
5
5
|
import { clearProjectStatusCache } from "../repl/project-status.js";
|
|
6
6
|
import style from "../terminal/style.js";
|
|
7
|
+
import { toDisplayPath } from "../utils/filesystem/path-display.js";
|
|
7
8
|
import { joinWorkingDir, validateFileNotReadOnly, validatePath, } from "../utils/filesystem/security.js";
|
|
8
9
|
export const EditFileTool = {
|
|
9
10
|
name: "Edit",
|
|
10
11
|
};
|
|
12
|
+
const MAX_EDITS_PER_CALL = 10;
|
|
11
13
|
const inputSchema = z.object({
|
|
12
14
|
path: z.string().describe("The path of the file to edit."),
|
|
13
|
-
edits: z
|
|
15
|
+
edits: z
|
|
16
|
+
.preprocess((val) => {
|
|
17
|
+
// Handle case where model passes a JSON string instead of an array
|
|
18
|
+
if (typeof val === "string") {
|
|
19
|
+
const trimmed = val.trim();
|
|
20
|
+
// Try parsing as JSON if it looks like an array
|
|
21
|
+
if (trimmed.startsWith("[")) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(trimmed);
|
|
24
|
+
if (Array.isArray(parsed)) {
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Not valid JSON, treat as a plain string
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return val;
|
|
34
|
+
}, z.array(z.object({
|
|
14
35
|
oldText: z
|
|
15
36
|
.string()
|
|
16
|
-
.describe("Text to search for - must match exactly
|
|
17
|
-
"Special characters require JSON escaping: backticks (
|
|
18
|
-
"For multi-line content, include exact newlines and indentation.")
|
|
37
|
+
.describe("Text to search for - must match exactly. The oldText must uniquely identify the location - include enough surrounding context (e.g., 3+ lines or function/class names) to ensure only ONE match exists in the file. " +
|
|
38
|
+
"Special characters require JSON escaping: backticks (`\\``...\\``), quotes, backslashes. " +
|
|
39
|
+
"For multi-line content, include exact newlines and indentation.")
|
|
40
|
+
.min(1, "oldText must be at least 1 character"),
|
|
19
41
|
newText: z.string().describe("Text to replace with"),
|
|
20
|
-
}))
|
|
42
|
+
})))
|
|
43
|
+
.describe("The edits to make to the file."),
|
|
21
44
|
});
|
|
22
|
-
export const createEditFileTool = async (
|
|
23
|
-
const
|
|
45
|
+
export const createEditFileTool = async (options) => {
|
|
46
|
+
const { primaryDir, allowedDirs } = options.workspace;
|
|
47
|
+
const allowedDirectory = allowedDirs ?? [primaryDir];
|
|
48
|
+
// Cache config at tool creation time instead of on every execute
|
|
49
|
+
const projectConfig = await config.getConfig();
|
|
24
50
|
return {
|
|
25
51
|
toolDef: {
|
|
26
|
-
description: "
|
|
27
|
-
"with new content. Exact literal matching is used: no whitespace, indentation, escape, or newline normalization is applied when locating matches. " +
|
|
28
|
-
"Provide enough context so the match is unique; otherwise the operation errors. Returns a git-style diff showing the changes made. " +
|
|
29
|
-
"Only works within allowed directories. " +
|
|
30
|
-
"Note: Special characters in oldText must be properly escaped for JSON (e.g., backticks as \\`...\\`). " +
|
|
31
|
-
"Multi-line strings require exact character-by-character matching including whitespace.",
|
|
52
|
+
description: "Edit text in files using literal search-and-replace.",
|
|
32
53
|
inputSchema,
|
|
33
54
|
},
|
|
34
55
|
display({ path, edits }) {
|
|
35
|
-
|
|
56
|
+
const displayPath = toDisplayPath(path);
|
|
57
|
+
return `${style.cyan(displayPath)} (${edits.length} edit${edits.length === 1 ? "" : "s"})`;
|
|
36
58
|
},
|
|
37
59
|
async execute({ path, edits }, { abortSignal }) {
|
|
38
60
|
if (abortSignal?.aborted) {
|
|
39
61
|
throw new Error("File editing aborted");
|
|
40
62
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
// Check for excessive edits and return helpful message to the model
|
|
64
|
+
if (edits.length > MAX_EDITS_PER_CALL) {
|
|
65
|
+
throw new Error(`Too many edits (${edits.length}). Maximum ${MAX_EDITS_PER_CALL} edits per call. ` +
|
|
66
|
+
"Please split your changes into multiple tool calls. " +
|
|
67
|
+
"For example, if you need to make 20 edits, make 2 calls with 10 edits each.");
|
|
68
|
+
}
|
|
69
|
+
const validPath = await validatePath(joinWorkingDir(path, primaryDir), allowedDirectory, { abortSignal });
|
|
70
|
+
validateFileNotReadOnly(validPath, projectConfig, primaryDir);
|
|
44
71
|
const result = await applyFileEdits(validPath, edits, false, abortSignal);
|
|
45
72
|
clearProjectStatusCache();
|
|
46
73
|
return result;
|
|
@@ -48,93 +75,273 @@ export const createEditFileTool = async ({ workingDir, allowedDirs, }) => {
|
|
|
48
75
|
};
|
|
49
76
|
};
|
|
50
77
|
// file editing and diffing utilities
|
|
78
|
+
/** Detect the line ending used in the content */
|
|
79
|
+
function detectLineEnding(content) {
|
|
80
|
+
const crlfIdx = content.indexOf("\r\n");
|
|
81
|
+
const lfIdx = content.indexOf("\n");
|
|
82
|
+
// If no line endings at all, default to LF
|
|
83
|
+
if (crlfIdx === -1 && lfIdx === -1)
|
|
84
|
+
return "\n";
|
|
85
|
+
// If CRLF exists (and either no LF or CRLF comes first), return CRLF
|
|
86
|
+
if (crlfIdx !== -1 && (lfIdx === -1 || crlfIdx < lfIdx)) {
|
|
87
|
+
return "\r\n";
|
|
88
|
+
}
|
|
89
|
+
return "\n";
|
|
90
|
+
}
|
|
91
|
+
/** Normalize line endings to LF for internal processing */
|
|
51
92
|
function normalizeLineEndings(text) {
|
|
52
|
-
return text.replace(/\r\n/g, "\n");
|
|
93
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
94
|
+
}
|
|
95
|
+
/** Restore original line endings after processing */
|
|
96
|
+
function restoreLineEndings(text, ending) {
|
|
97
|
+
return ending === "\r\n" ? text.replace(/\n/g, "\r\n") : text;
|
|
53
98
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
/** Strip UTF-8 BOM if present - users won't include invisible BOM in oldText */
|
|
100
|
+
function stripBom(content) {
|
|
101
|
+
return content.startsWith("\uFEFF")
|
|
102
|
+
? { bom: "\uFEFF", text: content.slice(1) }
|
|
103
|
+
: { bom: "", text: content };
|
|
104
|
+
}
|
|
105
|
+
function createUnifiedDiff(normalizedOriginal, normalizedNew, filepath = "file") {
|
|
58
106
|
return createTwoFilesPatch(filepath, filepath, normalizedOriginal, normalizedNew, "original", "modified");
|
|
59
107
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
108
|
+
async function validateFileReadable(filePath) {
|
|
109
|
+
try {
|
|
110
|
+
await access(filePath, constants.R_OK);
|
|
63
111
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (edits.
|
|
112
|
+
catch {
|
|
113
|
+
throw new Error(`File not found or not readable: ${filePath}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function validateEdits(edits) {
|
|
117
|
+
if (edits.some((edit) => edit.oldText.length === 0)) {
|
|
70
118
|
throw new Error("Invalid oldText in edit. The value of oldText must be at least one character");
|
|
71
119
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Normalize text for fuzzy matching by:
|
|
123
|
+
* - Unicode NFKC normalization (canonical compatibility decomposition)
|
|
124
|
+
* - Converting smart quotes to straight quotes
|
|
125
|
+
* - Unifying various dash characters to hyphen
|
|
126
|
+
* - Normalizing whitespace characters to regular space
|
|
127
|
+
* - Removing trailing whitespace from each line
|
|
128
|
+
*/
|
|
129
|
+
function normalizeForFuzzyMatch(text) {
|
|
130
|
+
return text
|
|
131
|
+
.normalize("NFKC")
|
|
132
|
+
.split("\n")
|
|
133
|
+
.map((line) => line.trimEnd())
|
|
134
|
+
.join("\n")
|
|
135
|
+
.replace(/[\u2018\u2019\u201A\u201B]/g, "'") // curly single quotes → '
|
|
136
|
+
.replace(/[\u201C\u201D\u201E\u201F]/g, '"') // curly double quotes → "
|
|
137
|
+
.replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212]/g, "-") // dashes → -
|
|
138
|
+
.replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g, " "); // spaces → space
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Find text in content, trying exact match first, then fuzzy match.
|
|
142
|
+
* When fuzzy match is used, positions are in the normalized content.
|
|
143
|
+
* IMPORTANT: When fuzzy matching is needed, the caller must work entirely
|
|
144
|
+
* in normalized space to avoid position mapping issues.
|
|
145
|
+
*/
|
|
146
|
+
function fuzzyFindText(content, searchText) {
|
|
147
|
+
// Try exact match first
|
|
148
|
+
const exactIndex = content.indexOf(searchText);
|
|
149
|
+
if (exactIndex !== -1) {
|
|
150
|
+
return {
|
|
151
|
+
found: true,
|
|
152
|
+
index: exactIndex,
|
|
153
|
+
matchLength: searchText.length,
|
|
154
|
+
usedFuzzyMatch: false,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// Fall back to fuzzy matching
|
|
158
|
+
const fuzzyContent = normalizeForFuzzyMatch(content);
|
|
159
|
+
const fuzzySearch = normalizeForFuzzyMatch(searchText);
|
|
160
|
+
const fuzzyIndex = fuzzyContent.indexOf(fuzzySearch);
|
|
161
|
+
if (fuzzyIndex === -1) {
|
|
162
|
+
return { found: false, index: -1, matchLength: 0, usedFuzzyMatch: false };
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
found: true,
|
|
166
|
+
index: fuzzyIndex,
|
|
167
|
+
matchLength: fuzzySearch.length,
|
|
168
|
+
usedFuzzyMatch: true,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Count how many times searchText appears in content (exact or fuzzy).
|
|
173
|
+
* Used to ensure uniqueness.
|
|
174
|
+
*/
|
|
175
|
+
function countMatches(content, searchText) {
|
|
176
|
+
// Count exact matches first
|
|
177
|
+
const exactEscaped = searchText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
178
|
+
const exactRegex = new RegExp(exactEscaped, "g");
|
|
179
|
+
const exactMatches = content.match(exactRegex);
|
|
180
|
+
const exactCount = exactMatches ? exactMatches.length : 0;
|
|
181
|
+
if (exactCount > 0) {
|
|
182
|
+
return exactCount;
|
|
183
|
+
}
|
|
184
|
+
// Count fuzzy matches
|
|
185
|
+
const fuzzyContent = normalizeForFuzzyMatch(content);
|
|
186
|
+
const fuzzySearch = normalizeForFuzzyMatch(searchText);
|
|
187
|
+
const fuzzyEscaped = fuzzySearch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
188
|
+
const fuzzyRegex = new RegExp(fuzzyEscaped, "g");
|
|
189
|
+
const fuzzyMatches = fuzzyContent.match(fuzzyRegex);
|
|
190
|
+
return fuzzyMatches ? fuzzyMatches.length : 0;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Preflight validation: Find all edit positions, validate uniqueness and no overlaps.
|
|
194
|
+
* If any edit requires fuzzy matching, normalize the entire content and work in
|
|
195
|
+
* normalized space. This avoids position mapping issues.
|
|
196
|
+
*/
|
|
197
|
+
function preflightEdits(edits, content) {
|
|
198
|
+
const normalizedEdits = edits.map((edit) => ({
|
|
199
|
+
oldText: normalizeLineEndings(edit.oldText),
|
|
200
|
+
newText: normalizeLineEndings(edit.newText),
|
|
201
|
+
}));
|
|
202
|
+
// Check if any edit requires fuzzy matching
|
|
203
|
+
const needsFuzzyMatching = normalizedEdits.some((edit) => content.indexOf(edit.oldText) === -1);
|
|
204
|
+
// Use normalized content if fuzzy matching is needed
|
|
205
|
+
const baseContent = needsFuzzyMatching
|
|
206
|
+
? normalizeForFuzzyMatch(content)
|
|
207
|
+
: content;
|
|
208
|
+
const matchedEdits = [];
|
|
209
|
+
// First pass: Find all match positions
|
|
210
|
+
for (let i = 0; i < normalizedEdits.length; i++) {
|
|
211
|
+
const edit = normalizedEdits[i];
|
|
212
|
+
// Check uniqueness
|
|
213
|
+
const matchCount = countMatches(baseContent, edit.oldText);
|
|
214
|
+
if (matchCount === 0) {
|
|
215
|
+
return {
|
|
216
|
+
success: false,
|
|
217
|
+
matchedEdits: [],
|
|
218
|
+
errorMessage: `Edit ${i + 1}: Could not find the exact text. ` +
|
|
219
|
+
"The oldText must match exactly including all whitespace and newlines.",
|
|
220
|
+
usedFuzzyMatch: needsFuzzyMatching,
|
|
221
|
+
baseContent,
|
|
222
|
+
};
|
|
77
223
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
224
|
+
if (matchCount > 1) {
|
|
225
|
+
const fuzzyContext = needsFuzzyMatching
|
|
226
|
+
? " (including fuzzy matches)"
|
|
227
|
+
: "";
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
matchedEdits: [],
|
|
231
|
+
errorMessage: `Edit ${i + 1}: oldText matches ${matchCount} locations${fuzzyContext} but should match only 1. ` +
|
|
232
|
+
"Please provide a more specific oldText that includes more surrounding context.",
|
|
233
|
+
usedFuzzyMatch: needsFuzzyMatching,
|
|
234
|
+
baseContent,
|
|
235
|
+
};
|
|
81
236
|
}
|
|
82
|
-
|
|
83
|
-
|
|
237
|
+
// Find the match position
|
|
238
|
+
const matchResult = fuzzyFindText(baseContent, edit.oldText);
|
|
239
|
+
if (!matchResult.found) {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
matchedEdits: [],
|
|
243
|
+
errorMessage: `Edit ${i + 1}: Could not find the text (unexpected error).`,
|
|
244
|
+
usedFuzzyMatch: needsFuzzyMatching,
|
|
245
|
+
baseContent,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
matchedEdits.push({
|
|
249
|
+
...edit,
|
|
250
|
+
index: matchResult.index,
|
|
251
|
+
matchLength: matchResult.matchLength,
|
|
252
|
+
editIndex: i,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
// Sort by position (ascending) for overlap detection
|
|
256
|
+
matchedEdits.sort((a, b) => a.index - b.index);
|
|
257
|
+
// Check for overlapping edits
|
|
258
|
+
for (let i = 0; i < matchedEdits.length - 1; i++) {
|
|
259
|
+
const current = matchedEdits[i];
|
|
260
|
+
const next = matchedEdits[i + 1];
|
|
261
|
+
// Check if current edit overlaps with next edit
|
|
262
|
+
if (current.index + current.matchLength > next.index) {
|
|
263
|
+
return {
|
|
264
|
+
success: false,
|
|
265
|
+
matchedEdits: [],
|
|
266
|
+
errorMessage: `Edits ${current.editIndex + 1} and ${next.editIndex + 1} overlap in the file. ` +
|
|
267
|
+
"Each edit must target a distinct region. Please combine overlapping edits into a single edit.",
|
|
268
|
+
usedFuzzyMatch: needsFuzzyMatching,
|
|
269
|
+
baseContent,
|
|
270
|
+
};
|
|
84
271
|
}
|
|
85
272
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
273
|
+
return {
|
|
274
|
+
success: true,
|
|
275
|
+
matchedEdits,
|
|
276
|
+
usedFuzzyMatch: needsFuzzyMatching,
|
|
277
|
+
baseContent,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Apply edits in reverse position order (highest index first).
|
|
282
|
+
* This prevents position shifting - earlier edits don't affect later ones.
|
|
283
|
+
* All positions are relative to baseContent (normalized if fuzzy matching).
|
|
284
|
+
*/
|
|
285
|
+
function applyEditsReverseOrder(content, matchedEdits) {
|
|
286
|
+
let result = content;
|
|
287
|
+
// Process in reverse order (highest index first)
|
|
288
|
+
for (let i = matchedEdits.length - 1; i >= 0; i--) {
|
|
289
|
+
const edit = matchedEdits[i];
|
|
290
|
+
const before = result.slice(0, edit.index);
|
|
291
|
+
const after = result.slice(edit.index + edit.matchLength);
|
|
292
|
+
result = before + edit.newText + after;
|
|
293
|
+
}
|
|
294
|
+
return result;
|
|
295
|
+
}
|
|
296
|
+
function formatDiff(diff, _filePath) {
|
|
89
297
|
let numBackticks = 3;
|
|
90
298
|
while (diff.includes("`".repeat(numBackticks))) {
|
|
91
299
|
numBackticks++;
|
|
92
300
|
}
|
|
93
|
-
|
|
301
|
+
return `${"`".repeat(numBackticks)} diff\n${diff}\n${"`".repeat(numBackticks)}`;
|
|
302
|
+
}
|
|
303
|
+
export async function applyFileEdits(filePath, edits, dryRun = false, abortSignal) {
|
|
304
|
+
if (abortSignal?.aborted) {
|
|
305
|
+
throw new Error("File edit operation aborted");
|
|
306
|
+
}
|
|
307
|
+
await validateFileReadable(filePath);
|
|
308
|
+
const rawContent = await readFile(filePath, {
|
|
309
|
+
encoding: "utf-8",
|
|
310
|
+
signal: abortSignal,
|
|
311
|
+
});
|
|
312
|
+
const { bom: originalBom, text: bomStrippedContent } = stripBom(rawContent);
|
|
313
|
+
const originalLineEnding = detectLineEnding(bomStrippedContent);
|
|
314
|
+
const content = normalizeLineEndings(bomStrippedContent);
|
|
315
|
+
validateEdits(edits);
|
|
316
|
+
// PREFLIGHT: Find all positions, validate no overlaps
|
|
317
|
+
const preflight = preflightEdits(edits, content);
|
|
318
|
+
if (!preflight.success) {
|
|
319
|
+
throw new Error(`Edit validation failed: ${preflight.errorMessage}`);
|
|
320
|
+
}
|
|
321
|
+
// All edits validated - apply in reverse order
|
|
322
|
+
// Note: baseContent is normalized if fuzzy matching was needed
|
|
323
|
+
const modifiedContent = applyEditsReverseOrder(preflight.baseContent, preflight.matchedEdits);
|
|
324
|
+
// Verify something actually changed
|
|
325
|
+
if (modifiedContent === preflight.baseContent) {
|
|
326
|
+
throw new Error("No changes were made - all edits resulted in identical content");
|
|
327
|
+
}
|
|
328
|
+
const finalContentWithLineEndings = restoreLineEndings(modifiedContent, originalLineEnding);
|
|
329
|
+
const finalContent = originalBom + finalContentWithLineEndings;
|
|
330
|
+
// Use baseContent for diff (normalized if fuzzy matching)
|
|
331
|
+
const diff = createUnifiedDiff(preflight.baseContent, modifiedContent, filePath);
|
|
332
|
+
const formattedDiff = formatDiff(diff, filePath);
|
|
333
|
+
// Add fuzzy match indicator if applicable
|
|
334
|
+
const result = preflight.usedFuzzyMatch
|
|
335
|
+
? `${formattedDiff}\n\n(Note: Used fuzzy matching - file content has been normalized)`
|
|
336
|
+
: formattedDiff;
|
|
94
337
|
if (!dryRun) {
|
|
95
338
|
if (abortSignal?.aborted) {
|
|
96
339
|
throw new Error("File edit operation aborted before writing");
|
|
97
340
|
}
|
|
98
|
-
|
|
99
|
-
await writeFile(filePath, modifiedContent, {
|
|
341
|
+
await writeFile(filePath, finalContent, {
|
|
100
342
|
encoding: "utf-8",
|
|
101
343
|
signal: abortSignal,
|
|
102
344
|
});
|
|
103
345
|
}
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Applies a single edit
|
|
108
|
-
*/
|
|
109
|
-
async function applyEditWithLlmFix(edit, content) {
|
|
110
|
-
const { oldText, newText } = edit;
|
|
111
|
-
// Try the original edit first
|
|
112
|
-
const originalResult = applyLiteralEdit(content, oldText, newText);
|
|
113
|
-
if (originalResult.matchCount > 0) {
|
|
114
|
-
return { success: true, content: originalResult.content };
|
|
115
|
-
}
|
|
116
|
-
return { success: false, content };
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Applies a literal search and replace operation
|
|
120
|
-
*/
|
|
121
|
-
function applyLiteralEdit(content, search, replace) {
|
|
122
|
-
let modifiedContent = content;
|
|
123
|
-
let matchCount = 0;
|
|
124
|
-
let currentIndex = 0;
|
|
125
|
-
while (currentIndex < modifiedContent.length) {
|
|
126
|
-
const matchIndex = modifiedContent.indexOf(search, currentIndex);
|
|
127
|
-
if (matchIndex === -1) {
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
matchCount++;
|
|
131
|
-
// Apply the replacement
|
|
132
|
-
modifiedContent =
|
|
133
|
-
modifiedContent.slice(0, matchIndex) +
|
|
134
|
-
replace +
|
|
135
|
-
modifiedContent.slice(matchIndex + search.length);
|
|
136
|
-
// Move current index past the replacement
|
|
137
|
-
currentIndex = matchIndex + replace.length;
|
|
138
|
-
}
|
|
139
|
-
return { matchCount, content: modifiedContent };
|
|
346
|
+
return result;
|
|
140
347
|
}
|
package/dist/tools/glob.d.ts
CHANGED
|
@@ -4,12 +4,12 @@ export declare const GlobTool: {
|
|
|
4
4
|
name: "Glob";
|
|
5
5
|
};
|
|
6
6
|
export declare const inputSchema: z.ZodObject<{
|
|
7
|
-
patterns: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
8
|
-
path: z.ZodString
|
|
7
|
+
patterns: z.ZodPipe<z.ZodTransform<{}, unknown>, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
8
|
+
path: z.ZodPipe<z.ZodTransform<{}, unknown>, z.ZodString>;
|
|
9
9
|
gitignore: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>;
|
|
10
10
|
recursive: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>;
|
|
11
11
|
expandDirectories: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>;
|
|
12
|
-
ignoreFiles: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
12
|
+
ignoreFiles: z.ZodPipe<z.ZodTransform<{} | null | undefined, unknown>, z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
|
|
13
13
|
cwd: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedString<unknown>>>;
|
|
14
14
|
maxResults: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
|
|
15
15
|
}, z.core.$strip>;
|
|
@@ -18,12 +18,12 @@ export declare const createGlobTool: () => {
|
|
|
18
18
|
toolDef: {
|
|
19
19
|
description: string;
|
|
20
20
|
inputSchema: z.ZodObject<{
|
|
21
|
-
patterns: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
22
|
-
path: z.ZodString
|
|
21
|
+
patterns: z.ZodPipe<z.ZodTransform<{}, unknown>, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
22
|
+
path: z.ZodPipe<z.ZodTransform<{}, unknown>, z.ZodString>;
|
|
23
23
|
gitignore: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>;
|
|
24
24
|
recursive: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>;
|
|
25
25
|
expandDirectories: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>;
|
|
26
|
-
ignoreFiles: z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]
|
|
26
|
+
ignoreFiles: z.ZodPipe<z.ZodTransform<{} | null | undefined, unknown>, z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>>;
|
|
27
27
|
cwd: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedString<unknown>>>;
|
|
28
28
|
maxResults: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
|
|
29
29
|
}, z.core.$strip>;
|
package/dist/tools/glob.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/tools/glob.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../source/tools/glob.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AA6EvD,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAEF,eAAO,MAAM,WAAW;;;;;;;;;iBA0EtB,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;gCAMK,eAAe;wGAmBtC,eAAe,mBACD,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;CAuCrB,CAAC"}
|