@travisennis/acai 0.0.5 → 0.0.7
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 +190 -19
- package/bin/acai-wrapper.js +26 -0
- package/dist/agent/index.d.ts +132 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +434 -0
- package/dist/api/exa/index.js +1 -1
- package/dist/cli.d.ts +4 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +67 -40
- package/dist/commands/add-directory-command.d.ts +3 -0
- package/dist/commands/add-directory-command.d.ts.map +1 -0
- package/dist/commands/add-directory-command.js +54 -0
- package/dist/commands/application-log-command.d.ts +1 -1
- package/dist/commands/application-log-command.d.ts.map +1 -1
- package/dist/commands/application-log-command.js +18 -20
- package/dist/commands/clear-command.d.ts +1 -1
- package/dist/commands/clear-command.d.ts.map +1 -1
- package/dist/commands/clear-command.js +7 -3
- package/dist/commands/compact-command.d.ts.map +1 -1
- package/dist/commands/compact-command.js +9 -5
- package/dist/commands/context-command.d.ts +3 -0
- package/dist/commands/context-command.d.ts.map +1 -0
- package/dist/commands/context-command.js +124 -0
- package/dist/commands/copy-command.d.ts.map +1 -1
- package/dist/commands/copy-command.js +14 -5
- package/dist/commands/edit-command.d.ts +1 -1
- package/dist/commands/edit-command.d.ts.map +1 -1
- package/dist/commands/edit-command.js +21 -34
- package/dist/commands/edit-prompt-command.d.ts +1 -1
- package/dist/commands/edit-prompt-command.d.ts.map +1 -1
- package/dist/commands/edit-prompt-command.js +18 -15
- package/dist/commands/exit-command.d.ts +1 -4
- package/dist/commands/exit-command.d.ts.map +1 -1
- package/dist/commands/exit-command.js +9 -5
- package/dist/commands/files-command.d.ts +1 -1
- package/dist/commands/files-command.d.ts.map +1 -1
- package/dist/commands/files-command.js +20 -16
- package/dist/commands/generate-rules-command.d.ts +1 -1
- package/dist/commands/generate-rules-command.d.ts.map +1 -1
- package/dist/commands/generate-rules-command.js +307 -39
- package/dist/commands/handoff-command.d.ts +3 -0
- package/dist/commands/handoff-command.d.ts.map +1 -0
- package/dist/commands/handoff-command.js +191 -0
- package/dist/commands/health-command.d.ts +1 -1
- package/dist/commands/health-command.d.ts.map +1 -1
- package/dist/commands/health-command.js +49 -27
- package/dist/commands/help-command.d.ts +1 -1
- package/dist/commands/help-command.d.ts.map +1 -1
- package/dist/commands/help-command.js +25 -5
- package/dist/commands/history-command.d.ts +3 -0
- package/dist/commands/history-command.d.ts.map +1 -0
- package/dist/commands/history-command.js +458 -0
- package/dist/commands/init-command.d.ts +1 -1
- package/dist/commands/init-command.d.ts.map +1 -1
- package/dist/commands/init-command.js +40 -22
- package/dist/commands/last-log-command.d.ts +1 -1
- package/dist/commands/last-log-command.d.ts.map +1 -1
- package/dist/commands/last-log-command.js +15 -15
- package/dist/commands/list-directories-command.d.ts +3 -0
- package/dist/commands/list-directories-command.d.ts.map +1 -0
- package/dist/commands/list-directories-command.js +35 -0
- package/dist/commands/list-tools-command.d.ts.map +1 -1
- package/dist/commands/list-tools-command.js +61 -21
- package/dist/commands/manager.d.ts +9 -4
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +64 -39
- package/dist/commands/model-command.d.ts.map +1 -1
- package/dist/commands/model-command.js +201 -66
- package/dist/commands/paste-command.d.ts +1 -1
- package/dist/commands/paste-command.d.ts.map +1 -1
- package/dist/commands/paste-command.js +23 -9
- package/dist/commands/pickup-command.d.ts +3 -0
- package/dist/commands/pickup-command.d.ts.map +1 -0
- package/dist/commands/pickup-command.js +109 -0
- package/dist/commands/prompt-command.d.ts +19 -1
- package/dist/commands/prompt-command.d.ts.map +1 -1
- package/dist/commands/prompt-command.js +191 -98
- package/dist/commands/remove-directory-command.d.ts +3 -0
- package/dist/commands/remove-directory-command.d.ts.map +1 -0
- package/dist/commands/remove-directory-command.js +55 -0
- package/dist/commands/reset-command.d.ts +1 -1
- package/dist/commands/reset-command.d.ts.map +1 -1
- package/dist/commands/reset-command.js +8 -5
- package/dist/commands/rules-command.d.ts +1 -1
- package/dist/commands/rules-command.d.ts.map +1 -1
- package/dist/commands/rules-command.js +25 -22
- package/dist/commands/save-command.d.ts +1 -1
- package/dist/commands/save-command.d.ts.map +1 -1
- package/dist/commands/save-command.js +8 -3
- package/dist/commands/shell-command.d.ts.map +1 -1
- package/dist/commands/shell-command.js +45 -24
- package/dist/commands/types.d.ts +9 -7
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/usage-command.d.ts +1 -1
- package/dist/commands/usage-command.d.ts.map +1 -1
- package/dist/commands/usage-command.js +18 -7
- package/dist/config.d.ts +21 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +90 -63
- package/dist/execution/index.d.ts +17 -2
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +62 -20
- package/dist/formatting.d.ts +127 -0
- package/dist/formatting.d.ts.map +1 -1
- package/dist/formatting.js +201 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +263 -102
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +47 -18
- package/dist/mentions.d.ts +2 -1
- package/dist/mentions.d.ts.map +1 -1
- package/dist/mentions.js +16 -1
- package/dist/messages.d.ts +11 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +122 -21
- package/dist/middleware/cache.d.ts +3 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +53 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +1 -0
- package/dist/models/ai-config.d.ts +4 -2
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +12 -2
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -67
- package/dist/models/deepseek-provider.d.ts.map +1 -1
- package/dist/models/deepseek-provider.js +0 -2
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +0 -3
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/groq-provider.js +0 -1
- package/dist/models/manager.d.ts +2 -1
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +26 -2
- package/dist/models/openai-provider.d.ts.map +1 -1
- package/dist/models/openai-provider.js +0 -4
- package/dist/models/openrouter-provider.d.ts +16 -22
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +175 -236
- package/dist/models/providers.d.ts +4 -14
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +1 -57
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +0 -2
- package/dist/prompts.d.ts +10 -4
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +447 -70
- package/dist/repl/project-status-line.d.ts +3 -0
- package/dist/repl/project-status-line.d.ts.map +1 -0
- package/dist/repl/project-status-line.js +61 -0
- package/dist/repl/tool-call-repair.d.ts.map +1 -1
- package/dist/repl/tool-call-repair.js +8 -4
- package/dist/repl-new.d.ts +51 -0
- package/dist/repl-new.d.ts.map +1 -0
- package/dist/repl-new.js +354 -0
- package/dist/skills.d.ts +20 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +192 -0
- package/dist/terminal/control.d.ts +55 -0
- package/dist/terminal/control.d.ts.map +1 -0
- package/dist/terminal/control.js +109 -0
- package/dist/terminal/default-theme.d.ts +1 -1
- package/dist/terminal/default-theme.d.ts.map +1 -1
- package/dist/terminal/default-theme.js +24 -28
- package/dist/terminal/formatting.d.ts +23 -25
- package/dist/terminal/formatting.d.ts.map +1 -1
- package/dist/terminal/formatting.js +35 -52
- package/dist/terminal/highlight/index.d.ts.map +1 -1
- package/dist/terminal/highlight/index.js +3 -6
- package/dist/terminal/highlight/theme.d.ts.map +1 -1
- package/dist/terminal/highlight/theme.js +2 -6
- package/dist/terminal/index.d.ts +2 -94
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +2 -370
- package/dist/terminal/markdown.js +10 -5
- package/dist/terminal/select-prompt.d.ts +2 -2
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +47 -39
- package/dist/terminal/strip-ansi.js +4 -4
- package/dist/terminal/table/cell.d.ts +114 -0
- package/dist/terminal/table/cell.d.ts.map +1 -0
- package/dist/terminal/table/cell.js +407 -0
- package/dist/terminal/table/debug.d.ts +15 -0
- package/dist/terminal/table/debug.d.ts.map +1 -0
- package/dist/terminal/table/debug.js +32 -0
- package/dist/terminal/table/index.d.ts +3 -0
- package/dist/terminal/table/index.d.ts.map +1 -0
- package/dist/terminal/table/index.js +2 -0
- package/dist/terminal/table/layout-manager.d.ts +27 -0
- package/dist/terminal/table/layout-manager.d.ts.map +1 -0
- package/dist/terminal/table/layout-manager.js +257 -0
- package/dist/terminal/table/table.d.ts +9 -0
- package/dist/terminal/table/table.d.ts.map +1 -0
- package/dist/terminal/table/table.js +97 -0
- package/dist/terminal/table/utils.d.ts +63 -0
- package/dist/terminal/table/utils.d.ts.map +1 -0
- package/dist/terminal/table/utils.js +326 -0
- package/dist/tokens/threshold.d.ts +20 -0
- package/dist/tokens/threshold.d.ts.map +1 -0
- package/dist/tokens/threshold.js +67 -0
- package/dist/tools/advanced-edit-file.d.ts +69 -0
- package/dist/tools/advanced-edit-file.d.ts.map +1 -0
- package/dist/tools/advanced-edit-file.js +285 -0
- package/dist/tools/agent.d.ts +16 -5
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/agent.js +86 -59
- package/dist/tools/bash.d.ts +23 -12
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +243 -128
- package/dist/tools/batch.d.ts +34 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +174 -0
- package/dist/tools/code-interpreter.d.ts +21 -9
- package/dist/tools/code-interpreter.d.ts.map +1 -1
- package/dist/tools/code-interpreter.js +151 -134
- package/dist/tools/delete-file.d.ts +17 -10
- package/dist/tools/delete-file.d.ts.map +1 -1
- package/dist/tools/delete-file.js +60 -97
- package/dist/tools/directory-tree.d.ts +17 -12
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +57 -48
- package/dist/tools/dynamic-tool-loader.d.ts +16 -10
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +122 -130
- package/dist/tools/dynamic-tool-parser.d.ts +1 -0
- package/dist/tools/dynamic-tool-parser.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-parser.js +1 -0
- package/dist/tools/edit-file.d.ts +35 -15
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +127 -114
- package/dist/tools/glob.d.ts +36 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +154 -0
- package/dist/tools/grep.d.ts +73 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +425 -165
- package/dist/tools/index.d.ts +220 -126
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +284 -135
- package/dist/tools/llm-edit-fixer.d.ts +24 -0
- package/dist/tools/llm-edit-fixer.d.ts.map +1 -0
- package/dist/tools/llm-edit-fixer.js +136 -0
- package/dist/tools/move-file.d.ts +19 -7
- package/dist/tools/move-file.d.ts.map +1 -1
- package/dist/tools/move-file.js +48 -34
- package/dist/tools/read-file.d.ts +47 -9
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +84 -70
- package/dist/tools/read-multiple-files.d.ts +17 -6
- package/dist/tools/read-multiple-files.d.ts.map +1 -1
- package/dist/tools/read-multiple-files.js +132 -72
- package/dist/tools/save-file.d.ts +45 -12
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +76 -101
- package/dist/tools/think.d.ts +15 -7
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +34 -20
- package/dist/tools/types.d.ts +8 -10
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +9 -0
- package/dist/tools/utils.d.ts +14 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +16 -0
- package/dist/tools/web-fetch.d.ts +11 -4
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +39 -38
- package/dist/tools/web-search.d.ts +15 -6
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +64 -31
- package/dist/tui/autocomplete.d.ts +44 -0
- package/dist/tui/autocomplete.d.ts.map +1 -0
- package/dist/tui/autocomplete.js +466 -0
- package/dist/tui/components/assistant-message.d.ts +18 -0
- package/dist/tui/components/assistant-message.d.ts.map +1 -0
- package/dist/tui/components/assistant-message.js +29 -0
- package/dist/tui/components/box.d.ts +20 -0
- package/dist/tui/components/box.d.ts.map +1 -0
- package/dist/tui/components/box.js +81 -0
- package/dist/tui/components/editor.d.ts +106 -0
- package/dist/tui/components/editor.d.ts.map +1 -0
- package/dist/tui/components/editor.js +1220 -0
- package/dist/tui/components/footer.d.ts +12 -0
- package/dist/tui/components/footer.d.ts.map +1 -0
- package/dist/tui/components/footer.js +209 -0
- package/dist/tui/components/header.d.ts +21 -0
- package/dist/tui/components/header.d.ts.map +1 -0
- package/dist/tui/components/header.js +63 -0
- package/dist/tui/components/input.d.ts +14 -0
- package/dist/tui/components/input.d.ts.map +1 -0
- package/dist/tui/components/input.js +122 -0
- package/dist/tui/components/loader.d.ts +23 -0
- package/dist/tui/components/loader.d.ts.map +1 -0
- package/dist/tui/components/loader.js +45 -0
- package/dist/tui/components/markdown.d.ts +106 -0
- package/dist/tui/components/markdown.d.ts.map +1 -0
- package/dist/tui/components/markdown.js +586 -0
- package/dist/tui/components/modal.d.ts +29 -0
- package/dist/tui/components/modal.d.ts.map +1 -0
- package/dist/tui/components/modal.js +263 -0
- package/dist/tui/components/progress-bar.d.ts +19 -0
- package/dist/tui/components/progress-bar.d.ts.map +1 -0
- package/dist/tui/components/progress-bar.js +78 -0
- package/dist/tui/components/prompt-status.d.ts +17 -0
- package/dist/tui/components/prompt-status.d.ts.map +1 -0
- package/dist/tui/components/prompt-status.js +26 -0
- package/dist/tui/components/select-list.d.ts +48 -0
- package/dist/tui/components/select-list.d.ts.map +1 -0
- package/dist/tui/components/select-list.js +207 -0
- package/dist/tui/components/spacer.d.ts +16 -0
- package/dist/tui/components/spacer.d.ts.map +1 -0
- package/dist/tui/components/spacer.js +27 -0
- package/dist/tui/components/table.d.ts +27 -0
- package/dist/tui/components/table.d.ts.map +1 -0
- package/dist/tui/components/table.js +125 -0
- package/dist/tui/components/text.d.ts +26 -0
- package/dist/tui/components/text.d.ts.map +1 -0
- package/dist/tui/components/text.js +143 -0
- package/dist/tui/components/thinking-block.d.ts +14 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -0
- package/dist/tui/components/thinking-block.js +33 -0
- package/dist/tui/components/tool-execution.d.ts +21 -0
- package/dist/tui/components/tool-execution.d.ts.map +1 -0
- package/dist/tui/components/tool-execution.js +161 -0
- package/dist/tui/components/user-message.d.ts +9 -0
- package/dist/tui/components/user-message.d.ts.map +1 -0
- package/dist/tui/components/user-message.js +23 -0
- package/dist/tui/components/welcome.d.ts +6 -0
- package/dist/tui/components/welcome.d.ts.map +1 -0
- package/dist/tui/components/welcome.js +30 -0
- package/dist/tui/index.d.ts +18 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +22 -0
- package/dist/tui/terminal.d.ts +38 -0
- package/dist/tui/terminal.d.ts.map +1 -0
- package/dist/tui/terminal.js +94 -0
- package/dist/tui/tui.d.ts +69 -0
- package/dist/tui/tui.d.ts.map +1 -0
- package/dist/tui/tui.js +204 -0
- package/dist/tui/utils.d.ts +24 -0
- package/dist/tui/utils.d.ts.map +1 -0
- package/dist/tui/utils.js +111 -0
- package/dist/utils/bash.d.ts +7 -0
- package/dist/utils/bash.d.ts.map +1 -0
- package/dist/{tools/bash-utils.js → utils/bash.js} +31 -12
- package/dist/utils/{filesystem.d.ts → filesystem/operations.d.ts} +1 -1
- package/dist/utils/filesystem/operations.d.ts.map +1 -0
- package/dist/utils/filesystem/security.d.ts +9 -0
- package/dist/utils/filesystem/security.d.ts.map +1 -0
- package/dist/{tools/filesystem-utils.js → utils/filesystem/security.js} +93 -21
- package/dist/utils/funcs.d.ts +6 -0
- package/dist/utils/funcs.d.ts.map +1 -0
- package/dist/utils/funcs.js +6 -0
- package/dist/utils/generators.d.ts +3 -0
- package/dist/utils/generators.d.ts.map +1 -0
- package/dist/utils/generators.js +25 -0
- package/dist/{tools/git-utils.d.ts → utils/git.d.ts} +1 -1
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/{tools/git-utils.js → utils/git.js} +0 -6
- package/dist/utils/glob.js +1 -1
- package/dist/utils/iterables.d.ts +2 -0
- package/dist/utils/iterables.d.ts.map +1 -0
- package/dist/utils/iterables.js +6 -0
- package/dist/utils/{zod-utils.d.ts → zod.d.ts} +1 -1
- package/dist/utils/zod.d.ts.map +1 -0
- package/package.json +21 -21
- package/dist/conversation-analyzer.d.ts +0 -11
- package/dist/conversation-analyzer.d.ts.map +0 -1
- package/dist/conversation-analyzer.js +0 -88
- package/dist/repl/display-tool-messages.d.ts +0 -4
- package/dist/repl/display-tool-messages.d.ts.map +0 -1
- package/dist/repl/display-tool-messages.js +0 -55
- package/dist/repl/display-tool-use.d.ts +0 -14
- package/dist/repl/display-tool-use.d.ts.map +0 -1
- package/dist/repl/display-tool-use.js +0 -63
- package/dist/repl/get-prompt-header.d.ts +0 -8
- package/dist/repl/get-prompt-header.d.ts.map +0 -1
- package/dist/repl/get-prompt-header.js +0 -38
- package/dist/repl-prompt.d.ts +0 -15
- package/dist/repl-prompt.d.ts.map +0 -1
- package/dist/repl-prompt.js +0 -147
- package/dist/repl.d.ts +0 -31
- package/dist/repl.d.ts.map +0 -1
- package/dist/repl.js +0 -310
- package/dist/terminal/checkbox-prompt.d.ts +0 -36
- package/dist/terminal/checkbox-prompt.d.ts.map +0 -1
- package/dist/terminal/checkbox-prompt.js +0 -362
- package/dist/terminal/editor-prompt.d.ts +0 -10
- package/dist/terminal/editor-prompt.d.ts.map +0 -1
- package/dist/terminal/editor-prompt.js +0 -61
- package/dist/terminal/errors.d.ts +0 -19
- package/dist/terminal/errors.d.ts.map +0 -1
- package/dist/terminal/errors.js +0 -37
- package/dist/terminal/input-prompt.d.ts +0 -16
- package/dist/terminal/input-prompt.d.ts.map +0 -1
- package/dist/terminal/input-prompt.js +0 -181
- package/dist/terminal/search-prompt.d.ts +0 -20
- package/dist/terminal/search-prompt.d.ts.map +0 -1
- package/dist/terminal/search-prompt.js +0 -279
- package/dist/terminal/types.d.ts +0 -35
- package/dist/terminal/types.d.ts.map +0 -1
- package/dist/terminal/types.js +0 -1
- package/dist/tokens/manage-output.d.ts +0 -34
- package/dist/tokens/manage-output.d.ts.map +0 -1
- package/dist/tokens/manage-output.js +0 -44
- package/dist/tool-executor.d.ts +0 -28
- package/dist/tool-executor.d.ts.map +0 -1
- package/dist/tool-executor.js +0 -74
- package/dist/tools/bash-utils.d.ts +0 -7
- package/dist/tools/bash-utils.d.ts.map +0 -1
- package/dist/tools/file-editing-utils.d.ts +0 -2
- package/dist/tools/file-editing-utils.d.ts.map +0 -1
- package/dist/tools/file-editing-utils.js +0 -135
- package/dist/tools/filesystem-utils.d.ts +0 -7
- package/dist/tools/filesystem-utils.d.ts.map +0 -1
- package/dist/tools/git-utils.d.ts.map +0 -1
- package/dist/utils/filesystem.d.ts.map +0 -1
- package/dist/utils/zod-utils.d.ts.map +0 -1
- /package/dist/utils/{filesystem.js → filesystem/operations.js} +0 -0
- /package/dist/utils/{zod-utils.js → zod.js} +0 -0
package/dist/tools/grep.js
CHANGED
|
@@ -1,159 +1,187 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
|
-
import { tool } from "ai";
|
|
4
3
|
import { z } from "zod";
|
|
5
4
|
import { config } from "../config.js";
|
|
6
5
|
import style from "../terminal/style.js";
|
|
7
|
-
import {
|
|
6
|
+
import { manageTokenLimit, TokenLimitExceededError, } from "../tokens/threshold.js";
|
|
8
7
|
export const GrepTool = {
|
|
9
8
|
name: "grepFiles",
|
|
10
9
|
};
|
|
10
|
+
const inputSchema = z.object({
|
|
11
|
+
pattern: z
|
|
12
|
+
.string()
|
|
13
|
+
.describe("The search pattern (regex by default, or fixed-string if literal=true or auto-detected as unbalanced)"),
|
|
14
|
+
path: z.string().describe("The path to search in"),
|
|
15
|
+
recursive: z.coerce
|
|
16
|
+
.boolean()
|
|
17
|
+
.nullable()
|
|
18
|
+
.describe("Search recursively. (default: true))"),
|
|
19
|
+
ignoreCase: z.coerce
|
|
20
|
+
.boolean()
|
|
21
|
+
.nullable()
|
|
22
|
+
.describe("Use case-sensitive search. (default: false)"),
|
|
23
|
+
filePattern: z.coerce
|
|
24
|
+
.string()
|
|
25
|
+
.nullable()
|
|
26
|
+
.describe("Glob pattern to filter files (e.g., '*.ts', '**/*.test.js'). (Default: no filtering)"),
|
|
27
|
+
contextLines: z.coerce
|
|
28
|
+
.number()
|
|
29
|
+
.nullable()
|
|
30
|
+
.describe("The number of context lines needed in search results. (Default: 0)"),
|
|
31
|
+
searchIgnored: z.coerce
|
|
32
|
+
.boolean()
|
|
33
|
+
.nullable()
|
|
34
|
+
.describe("Search ignored files. (Default: false)"),
|
|
35
|
+
literal: z.coerce
|
|
36
|
+
.boolean()
|
|
37
|
+
.nullable()
|
|
38
|
+
.describe("Pass true for fixed-string search (-F), false for regex, (Default: auto-detects unbalanced patterns like mismatched parentheses/brackets.)"),
|
|
39
|
+
maxResults: z.coerce
|
|
40
|
+
.number()
|
|
41
|
+
.nullable()
|
|
42
|
+
.describe("Maximum number of matches to return. Set to 0 for no limit. (Default: configured value)"),
|
|
43
|
+
});
|
|
11
44
|
export const createGrepTool = (options) => {
|
|
12
|
-
const {
|
|
45
|
+
const { tokenCounter } = options;
|
|
13
46
|
return {
|
|
14
|
-
|
|
15
|
-
description: `Search files for patterns using ripgrep (rg). Uses glob patterns for file filtering (e.g., "*.ts", "**/*.test.ts"). Auto-detects unbalanced regex patterns and falls back to fixed-string search for safety.`,
|
|
16
|
-
inputSchema
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.
|
|
32
|
-
.describe("Glob pattern to filter files (e.g., '*.ts', '**/*.test.js'). (Default: no filtering)"),
|
|
33
|
-
contextLines: z.coerce
|
|
34
|
-
.number()
|
|
35
|
-
.nullable()
|
|
36
|
-
.describe("The number of context lines needed in search results. (Default: 0)"),
|
|
37
|
-
searchIgnored: z.coerce
|
|
38
|
-
.boolean()
|
|
39
|
-
.nullable()
|
|
40
|
-
.describe("Search ignored files. (Default: false)"),
|
|
41
|
-
literal: z.coerce
|
|
42
|
-
.boolean()
|
|
43
|
-
.nullable()
|
|
44
|
-
.describe("Pass true for fixed-string search (-F), false for regex, (Default: auto-detects unbalanced patterns like mismatched parentheses/brackets.)"),
|
|
45
|
-
}),
|
|
46
|
-
execute: async ({ pattern, path, recursive, ignoreCase, filePattern, contextLines, searchIgnored, literal, }, { toolCallId, abortSignal }) => {
|
|
47
|
-
// Check if execution has been aborted
|
|
48
|
-
if (abortSignal?.aborted) {
|
|
49
|
-
throw new Error("Grep search aborted");
|
|
47
|
+
toolDef: {
|
|
48
|
+
description: `Search files for patterns using ripgrep (rg). Uses glob patterns for file filtering (e.g., "*.ts", "**/*.test.ts"). Auto-detects unbalanced regex patterns and falls back to fixed-string search for safety. Results are limited to prevent overwhelming output; configure via maxResults parameter.`,
|
|
49
|
+
inputSchema,
|
|
50
|
+
},
|
|
51
|
+
async *execute({ pattern, path, recursive, ignoreCase, filePattern, contextLines, searchIgnored, literal, maxResults, }, { toolCallId, abortSignal }) {
|
|
52
|
+
// Check if execution has been aborted
|
|
53
|
+
if (abortSignal?.aborted) {
|
|
54
|
+
throw new Error("Grep search aborted");
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
// grok doesn't follow my instructions
|
|
58
|
+
const safeFilePattern = filePattern === "null" || filePattern === "undefined"
|
|
59
|
+
? null
|
|
60
|
+
: filePattern;
|
|
61
|
+
// Enhanced tool-init with detailed search parameters
|
|
62
|
+
let initMessage = `${style.cyan(inspect(pattern))} in ${style.cyan(path)}`;
|
|
63
|
+
if (safeFilePattern) {
|
|
64
|
+
initMessage += ` ${style.dim(`(filter: ${safeFilePattern})`)}`;
|
|
50
65
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
effectiveLiteral = false;
|
|
82
|
-
}
|
|
66
|
+
if (recursive === false) {
|
|
67
|
+
initMessage += ` ${style.dim("(non-recursive)")}`;
|
|
68
|
+
}
|
|
69
|
+
if (ignoreCase) {
|
|
70
|
+
initMessage += ` ${style.dim("(case-insensitive)")}`;
|
|
71
|
+
}
|
|
72
|
+
if (contextLines && contextLines > 0) {
|
|
73
|
+
initMessage += ` ${style.dim(`(with ${contextLines} context line${contextLines === 1 ? "" : "s"})`)}`;
|
|
74
|
+
}
|
|
75
|
+
yield {
|
|
76
|
+
name: GrepTool.name,
|
|
77
|
+
event: "tool-init",
|
|
78
|
+
id: toolCallId,
|
|
79
|
+
data: initMessage,
|
|
80
|
+
};
|
|
81
|
+
// Normalize literal option: if null => auto-detect using heuristic
|
|
82
|
+
let effectiveLiteral = null;
|
|
83
|
+
if (literal === true) {
|
|
84
|
+
effectiveLiteral = true;
|
|
85
|
+
}
|
|
86
|
+
else if (literal === false) {
|
|
87
|
+
effectiveLiteral = false;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// auto-detect
|
|
91
|
+
try {
|
|
92
|
+
if (likelyUnbalancedRegex(pattern)) {
|
|
93
|
+
effectiveLiteral = true;
|
|
83
94
|
}
|
|
84
|
-
|
|
95
|
+
else {
|
|
85
96
|
effectiveLiteral = false;
|
|
86
97
|
}
|
|
87
98
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
ignoreCase,
|
|
91
|
-
filePattern: safeFilePattern,
|
|
92
|
-
contextLines,
|
|
93
|
-
searchIgnored,
|
|
94
|
-
literal: effectiveLiteral,
|
|
95
|
-
});
|
|
96
|
-
const maxTokens = (await config.readProjectConfig()).tools.maxTokens;
|
|
97
|
-
const managed = manageOutput(rawResult, {
|
|
98
|
-
tokenCounter,
|
|
99
|
-
threshold: maxTokens,
|
|
100
|
-
});
|
|
101
|
-
if (managed.truncated) {
|
|
102
|
-
sendData?.({
|
|
103
|
-
event: "tool-update",
|
|
104
|
-
id: toolCallId,
|
|
105
|
-
data: { primary: managed.warning },
|
|
106
|
-
});
|
|
99
|
+
catch (_err) {
|
|
100
|
+
effectiveLiteral = false;
|
|
107
101
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (matchCount
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
102
|
+
}
|
|
103
|
+
const projectConfig = await config.getConfig();
|
|
104
|
+
const configMaxResults = projectConfig.tools.maxResults;
|
|
105
|
+
const effectiveMaxResults = maxResults ?? configMaxResults;
|
|
106
|
+
const grepResult = grepFilesStructured(pattern, path, {
|
|
107
|
+
recursive,
|
|
108
|
+
ignoreCase,
|
|
109
|
+
filePattern: safeFilePattern,
|
|
110
|
+
contextLines,
|
|
111
|
+
searchIgnored,
|
|
112
|
+
literal: effectiveLiteral,
|
|
113
|
+
maxResults: effectiveMaxResults,
|
|
114
|
+
});
|
|
115
|
+
try {
|
|
116
|
+
const result = await manageTokenLimit(grepResult.rawOutput, tokenCounter, "Grep", "Use maxResults parameter, more specific patterns, or contextLines=0 to reduce output");
|
|
117
|
+
const matchCount = grepResult.matchCount;
|
|
118
|
+
// Build completion message with preview information
|
|
119
|
+
let completionMessage = `Found ${style.cyan(matchCount)} match${matchCount === 1 ? "" : "es"}`;
|
|
120
|
+
if (matchCount === 0) {
|
|
121
|
+
completionMessage = "Search completed - no matches found";
|
|
122
|
+
}
|
|
123
|
+
// Calculate unique files with matches
|
|
124
|
+
const filesWithMatches = new Set(grepResult.parsedMatches
|
|
125
|
+
.filter((match) => match.isMatch && !match.isContext && match.file)
|
|
126
|
+
.map((match) => match.file)).size;
|
|
127
|
+
if (filesWithMatches > 0) {
|
|
128
|
+
completionMessage += ` across ${style.cyan(filesWithMatches)} file${filesWithMatches === 1 ? "" : "s"}`;
|
|
129
|
+
}
|
|
130
|
+
if (grepResult.contextCount > 0) {
|
|
131
|
+
completionMessage += ` with ${style.cyan(grepResult.contextCount)} context line${grepResult.contextCount === 1 ? "" : "s"}`;
|
|
136
132
|
}
|
|
137
|
-
|
|
133
|
+
completionMessage += ` (${result.tokenCount} tokens)`;
|
|
134
|
+
yield {
|
|
135
|
+
name: GrepTool.name,
|
|
138
136
|
event: "tool-completion",
|
|
139
137
|
id: toolCallId,
|
|
140
|
-
data:
|
|
141
|
-
}
|
|
142
|
-
|
|
138
|
+
data: completionMessage,
|
|
139
|
+
};
|
|
140
|
+
yield result.content;
|
|
143
141
|
}
|
|
144
142
|
catch (error) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
143
|
+
if (error instanceof TokenLimitExceededError) {
|
|
144
|
+
yield {
|
|
145
|
+
name: GrepTool.name,
|
|
146
|
+
event: "tool-error",
|
|
147
|
+
id: toolCallId,
|
|
148
|
+
data: error.message,
|
|
149
|
+
};
|
|
150
|
+
yield error.message;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
const errorMessage = error.message;
|
|
158
|
+
let userFriendlyError = `Error searching for "${pattern}" in ${path}: ${errorMessage}`;
|
|
159
|
+
// Provide more helpful error messages for common cases
|
|
160
|
+
if (errorMessage.includes("No such file or directory")) {
|
|
161
|
+
userFriendlyError = `Path not found: "${path}"`;
|
|
162
|
+
if (filePattern) {
|
|
163
|
+
userFriendlyError += ` with file pattern "${filePattern}"`;
|
|
164
|
+
}
|
|
165
|
+
userFriendlyError += " - check if the path exists and is accessible";
|
|
166
|
+
}
|
|
167
|
+
else if (errorMessage.includes("permission denied")) {
|
|
168
|
+
userFriendlyError = `Permission denied accessing "${path}"`;
|
|
169
|
+
}
|
|
170
|
+
else if (errorMessage.includes("Regex parse error")) {
|
|
171
|
+
userFriendlyError = `Invalid search pattern "${pattern}" - try using literal=true for fixed-string search`;
|
|
151
172
|
}
|
|
152
|
-
|
|
153
|
-
|
|
173
|
+
yield {
|
|
174
|
+
name: GrepTool.name,
|
|
175
|
+
event: "tool-error",
|
|
176
|
+
id: toolCallId,
|
|
177
|
+
data: userFriendlyError,
|
|
178
|
+
};
|
|
179
|
+
yield errorMessage;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
154
182
|
};
|
|
155
183
|
};
|
|
156
|
-
function likelyUnbalancedRegex(pattern) {
|
|
184
|
+
export function likelyUnbalancedRegex(pattern) {
|
|
157
185
|
const counts = {
|
|
158
186
|
openParen: 0,
|
|
159
187
|
closeParen: 0,
|
|
@@ -163,6 +191,7 @@ function likelyUnbalancedRegex(pattern) {
|
|
|
163
191
|
closeBrace: 0,
|
|
164
192
|
};
|
|
165
193
|
let escaped = false;
|
|
194
|
+
let inCharacterClass = false;
|
|
166
195
|
for (let i = 0; i < pattern.length; i++) {
|
|
167
196
|
const ch = pattern[i];
|
|
168
197
|
if (escaped) {
|
|
@@ -173,32 +202,105 @@ function likelyUnbalancedRegex(pattern) {
|
|
|
173
202
|
escaped = true;
|
|
174
203
|
continue;
|
|
175
204
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
// Track character class boundaries
|
|
206
|
+
if (ch === "[" && !inCharacterClass) {
|
|
207
|
+
inCharacterClass = true;
|
|
208
|
+
counts.openBracket++;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (ch === "]" && inCharacterClass) {
|
|
212
|
+
inCharacterClass = false;
|
|
213
|
+
counts.closeBracket++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
// Only count brackets/parens/braces outside of character classes
|
|
217
|
+
if (!inCharacterClass) {
|
|
218
|
+
switch (ch) {
|
|
219
|
+
case "(":
|
|
220
|
+
counts.openParen++;
|
|
221
|
+
break;
|
|
222
|
+
case ")":
|
|
223
|
+
counts.closeParen++;
|
|
224
|
+
break;
|
|
225
|
+
case "{":
|
|
226
|
+
counts.openBrace++;
|
|
227
|
+
break;
|
|
228
|
+
case "}":
|
|
229
|
+
counts.closeBrace++;
|
|
230
|
+
break;
|
|
231
|
+
default:
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Check for unbalanced brackets, parentheses, and braces
|
|
237
|
+
const hasUnbalancedBrackets = counts.openBracket !== counts.closeBracket;
|
|
238
|
+
const hasUnbalancedParens = counts.openParen !== counts.closeParen;
|
|
239
|
+
const hasUnbalancedBraces = counts.openBrace !== counts.closeBrace;
|
|
240
|
+
// Also check for invalid repetition operators (e.g., {n}, {n,}, {n,m}) outside of character classes
|
|
241
|
+
let hasInvalidRepetition = false;
|
|
242
|
+
{
|
|
243
|
+
let escaped2 = false;
|
|
244
|
+
let inClass2 = false;
|
|
245
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
246
|
+
const ch = pattern[i];
|
|
247
|
+
if (escaped2) {
|
|
248
|
+
escaped2 = false;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (ch === "\\") {
|
|
252
|
+
escaped2 = true;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (ch === "[" && !inClass2) {
|
|
256
|
+
inClass2 = true;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (ch === "]" && inClass2) {
|
|
260
|
+
inClass2 = false;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (inClass2) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (ch === "{") {
|
|
267
|
+
let j = i + 1;
|
|
268
|
+
let hasDigits = false;
|
|
269
|
+
let hasComma = false;
|
|
270
|
+
while (j < pattern.length && pattern[j] !== "}") {
|
|
271
|
+
const c = pattern[j];
|
|
272
|
+
if (c >= "0" && c <= "9") {
|
|
273
|
+
hasDigits = true;
|
|
274
|
+
}
|
|
275
|
+
else if (c === "," && !hasComma) {
|
|
276
|
+
hasComma = true;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
j++;
|
|
282
|
+
}
|
|
283
|
+
if (j >= pattern.length || pattern[j] !== "}") {
|
|
284
|
+
hasInvalidRepetition = true;
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
// At this point we have a closing brace at j
|
|
288
|
+
if (!hasDigits) {
|
|
289
|
+
// Heuristic: treat empty {} as non-quantifier when it doesn't follow a likely atom
|
|
290
|
+
const prev = i > 0 ? pattern[i - 1] : undefined;
|
|
291
|
+
if (prev !== undefined && /\S/.test(prev)) {
|
|
292
|
+
hasInvalidRepetition = true;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
// else ignore as literal braces
|
|
296
|
+
}
|
|
297
|
+
}
|
|
197
298
|
}
|
|
198
299
|
}
|
|
199
|
-
return (
|
|
200
|
-
|
|
201
|
-
|
|
300
|
+
return (hasUnbalancedBrackets ||
|
|
301
|
+
hasUnbalancedParens ||
|
|
302
|
+
hasUnbalancedBraces ||
|
|
303
|
+
hasInvalidRepetition);
|
|
202
304
|
}
|
|
203
305
|
/**
|
|
204
306
|
* Search files for patterns using ripgrep
|
|
@@ -246,21 +348,179 @@ export function buildGrepCommand(pattern, path, options = {}) {
|
|
|
246
348
|
command += " -F";
|
|
247
349
|
}
|
|
248
350
|
command += ` ${JSON.stringify(pattern)}`;
|
|
249
|
-
command += ` ${path}`;
|
|
351
|
+
command += ` ${JSON.stringify(path)}`;
|
|
250
352
|
return command;
|
|
251
353
|
}
|
|
252
|
-
|
|
354
|
+
/**
|
|
355
|
+
* Parse ripgrep output and extract structured match information
|
|
356
|
+
*/
|
|
357
|
+
export function parseRipgrepOutput(content) {
|
|
358
|
+
if (content === "No matches found.") {
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
const lines = content.trim().split("\n");
|
|
362
|
+
const parsed = [];
|
|
363
|
+
for (const line of lines) {
|
|
364
|
+
if (line === "--") {
|
|
365
|
+
// Separator between file groups - skip
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (line.trim() === "") {
|
|
369
|
+
// Empty line - skip
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
// Try multi-file format: file:line:content
|
|
373
|
+
const multiFileMatch = line.match(/^([^:]+):(\d+):(.+)$/);
|
|
374
|
+
if (multiFileMatch) {
|
|
375
|
+
parsed.push({
|
|
376
|
+
file: multiFileMatch[1],
|
|
377
|
+
line: Number.parseInt(multiFileMatch[2], 10),
|
|
378
|
+
content: multiFileMatch[3],
|
|
379
|
+
isMatch: true,
|
|
380
|
+
});
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
// Try single-file format: line:content
|
|
384
|
+
const singleFileMatch = line.match(/^(\d+):(.+)$/);
|
|
385
|
+
if (singleFileMatch) {
|
|
386
|
+
parsed.push({
|
|
387
|
+
line: Number.parseInt(singleFileMatch[1], 10),
|
|
388
|
+
content: singleFileMatch[2],
|
|
389
|
+
isMatch: true,
|
|
390
|
+
});
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
// Try context line format: file-line-context
|
|
394
|
+
const contextMatch = line.match(/^([^:]+)-(\d+)-(.+)$/);
|
|
395
|
+
if (contextMatch) {
|
|
396
|
+
parsed.push({
|
|
397
|
+
file: contextMatch[1],
|
|
398
|
+
line: Number.parseInt(contextMatch[2], 10),
|
|
399
|
+
content: contextMatch[3],
|
|
400
|
+
isMatch: false,
|
|
401
|
+
isContext: true,
|
|
402
|
+
});
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
// Try context line format without file: line-context
|
|
406
|
+
const contextNoFileMatch = line.match(/^(\d+)-(.+)$/);
|
|
407
|
+
if (contextNoFileMatch) {
|
|
408
|
+
parsed.push({
|
|
409
|
+
line: Number.parseInt(contextNoFileMatch[1], 10),
|
|
410
|
+
content: contextNoFileMatch[2],
|
|
411
|
+
isMatch: false,
|
|
412
|
+
isContext: true,
|
|
413
|
+
});
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
// If we get here, it's an unrecognized format - treat as match for backwards compatibility
|
|
417
|
+
parsed.push({
|
|
418
|
+
content: line,
|
|
419
|
+
line: 0,
|
|
420
|
+
isMatch: true,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
return parsed;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Count actual matches (excluding context lines)
|
|
427
|
+
*/
|
|
428
|
+
export function countActualMatches(parsed) {
|
|
429
|
+
return parsed.filter((match) => match.isMatch && !match.isContext).length;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Count context lines
|
|
433
|
+
*/
|
|
434
|
+
export function countContextLines(parsed) {
|
|
435
|
+
return parsed.filter((match) => match.isContext).length;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Truncate matches to a maximum number of results
|
|
439
|
+
*/
|
|
440
|
+
export function truncateMatches(matches, maxResults) {
|
|
441
|
+
if (!maxResults || maxResults <= 0) {
|
|
442
|
+
return { truncated: matches, isTruncated: false };
|
|
443
|
+
}
|
|
444
|
+
const actualMatches = matches.filter((m) => m.isMatch && !m.isContext);
|
|
445
|
+
if (actualMatches.length <= maxResults) {
|
|
446
|
+
return { truncated: matches, isTruncated: false };
|
|
447
|
+
}
|
|
448
|
+
const truncated = [];
|
|
449
|
+
let matchesKept = 0;
|
|
450
|
+
for (const match of matches) {
|
|
451
|
+
if (match.isMatch && !match.isContext) {
|
|
452
|
+
if (matchesKept < maxResults) {
|
|
453
|
+
truncated.push(match);
|
|
454
|
+
matchesKept++;
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return {
|
|
462
|
+
truncated,
|
|
463
|
+
isTruncated: true,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Extract matches from content (backwards compatibility wrapper)
|
|
468
|
+
*/
|
|
469
|
+
export function extractMatches(content) {
|
|
470
|
+
const parsed = parseRipgrepOutput(content);
|
|
471
|
+
const matches = parsed.filter((match) => match.isMatch && !match.isContext);
|
|
472
|
+
// Convert back to original string format for backwards compatibility
|
|
473
|
+
return matches.map((match) => {
|
|
474
|
+
if (match.file) {
|
|
475
|
+
return `${match.file}:${match.line}:${match.content}`;
|
|
476
|
+
}
|
|
477
|
+
return `${match.line}:${match.content}`;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
export function grepFiles(pattern, path, options = {}) {
|
|
481
|
+
const result = grepFilesStructured(pattern, path, options);
|
|
482
|
+
return result.rawOutput;
|
|
483
|
+
}
|
|
484
|
+
export function grepFilesStructured(pattern, path, options = {}) {
|
|
253
485
|
try {
|
|
254
486
|
const command = buildGrepCommand(pattern, path, options);
|
|
255
|
-
const
|
|
256
|
-
|
|
487
|
+
const rawOutput = execSync(command, {
|
|
488
|
+
encoding: "utf-8",
|
|
489
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
490
|
+
});
|
|
491
|
+
const parsedMatches = parseRipgrepOutput(rawOutput);
|
|
492
|
+
const matchCount = countActualMatches(parsedMatches);
|
|
493
|
+
const { truncated, isTruncated } = truncateMatches(parsedMatches, options.maxResults);
|
|
494
|
+
const displayedCount = countActualMatches(truncated);
|
|
495
|
+
const displayedContextCount = countContextLines(truncated);
|
|
496
|
+
return {
|
|
497
|
+
rawOutput,
|
|
498
|
+
parsedMatches: truncated,
|
|
499
|
+
matchCount,
|
|
500
|
+
displayedCount,
|
|
501
|
+
contextCount: displayedContextCount,
|
|
502
|
+
hasMatches: matchCount > 0,
|
|
503
|
+
isTruncated,
|
|
504
|
+
};
|
|
257
505
|
}
|
|
258
506
|
catch (error) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return
|
|
507
|
+
const execError = error;
|
|
508
|
+
const exitCode = execError?.status;
|
|
509
|
+
if (exitCode === 1) {
|
|
510
|
+
return {
|
|
511
|
+
rawOutput: "No matches found.",
|
|
512
|
+
parsedMatches: [],
|
|
513
|
+
matchCount: 0,
|
|
514
|
+
contextCount: 0,
|
|
515
|
+
hasMatches: false,
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
if (exitCode === 2) {
|
|
519
|
+
const stderrStr = typeof execError.stderr === "string"
|
|
520
|
+
? execError.stderr
|
|
521
|
+
: (execError.stderr?.toString("utf-8") ?? execError.message);
|
|
522
|
+
throw new Error(`Regex parse error in pattern "${pattern}": ${stderrStr}`);
|
|
263
523
|
}
|
|
264
|
-
throw new Error(`Error executing ripgrep: ${
|
|
524
|
+
throw new Error(`Error executing ripgrep: ${execError.message}`);
|
|
265
525
|
}
|
|
266
526
|
}
|