@travisennis/acai 0.0.5 → 0.0.6
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 +4 -2
- package/dist/agent/index.d.ts +119 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +406 -0
- package/dist/agent/manual-loop.d.ts +41 -0
- package/dist/agent/manual-loop.d.ts.map +1 -0
- package/dist/agent/manual-loop.js +278 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +27 -33
- 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 +85 -0
- package/dist/commands/application-log-command.d.ts.map +1 -1
- package/dist/commands/application-log-command.js +34 -0
- package/dist/commands/clear-command.d.ts.map +1 -1
- package/dist/commands/clear-command.js +8 -0
- package/dist/commands/compact-command.d.ts.map +1 -1
- package/dist/commands/compact-command.js +15 -2
- 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 +183 -0
- package/dist/commands/copy-command.d.ts.map +1 -1
- package/dist/commands/copy-command.js +28 -0
- package/dist/commands/edit-command.d.ts.map +1 -1
- package/dist/commands/edit-command.js +33 -0
- package/dist/commands/edit-prompt-command.d.ts.map +1 -1
- package/dist/commands/edit-prompt-command.js +28 -0
- package/dist/commands/exit-command.d.ts.map +1 -1
- package/dist/commands/exit-command.js +20 -0
- package/dist/commands/files-command.d.ts.map +1 -1
- package/dist/commands/files-command.js +57 -0
- package/dist/commands/generate-rules-command.d.ts.map +1 -1
- package/dist/commands/generate-rules-command.js +311 -1
- 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 +202 -0
- package/dist/commands/health-command.d.ts.map +1 -1
- package/dist/commands/health-command.js +119 -2
- package/dist/commands/help-command.d.ts.map +1 -1
- package/dist/commands/help-command.js +28 -0
- 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 +534 -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 +55 -18
- package/dist/commands/last-log-command.d.ts.map +1 -1
- package/dist/commands/last-log-command.js +27 -0
- 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 +48 -0
- package/dist/commands/list-tools-command.d.ts.map +1 -1
- package/dist/commands/list-tools-command.js +66 -3
- package/dist/commands/manager.d.ts +15 -3
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +86 -26
- package/dist/commands/model-command.d.ts +22 -0
- package/dist/commands/model-command.d.ts.map +1 -1
- package/dist/commands/model-command.js +256 -0
- package/dist/commands/paste-command.d.ts.map +1 -1
- package/dist/commands/paste-command.js +92 -0
- 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 +161 -0
- package/dist/commands/prompt-command.d.ts +1 -1
- package/dist/commands/prompt-command.d.ts.map +1 -1
- package/dist/commands/prompt-command.js +117 -2
- 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 +87 -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 +13 -2
- package/dist/commands/rules-command.d.ts.map +1 -1
- package/dist/commands/rules-command.js +65 -0
- package/dist/commands/save-command.d.ts.map +1 -1
- package/dist/commands/save-command.js +12 -0
- package/dist/commands/shell-command.d.ts.map +1 -1
- package/dist/commands/shell-command.js +68 -0
- package/dist/commands/types.d.ts +9 -4
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/usage-command.d.ts.map +1 -1
- package/dist/commands/usage-command.js +22 -0
- package/dist/config.d.ts +6 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -29
- package/dist/formatting.d.ts +108 -0
- package/dist/formatting.d.ts.map +1 -1
- package/dist/formatting.js +147 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +140 -38
- 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 +8 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +56 -19
- 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 -60
- 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/openrouter-provider.d.ts +7 -14
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +114 -169
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/prompts.d.ts +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +53 -4
- package/dist/repl/display-tool-messages.d.ts +1 -1
- package/dist/repl/display-tool-messages.d.ts.map +1 -1
- package/dist/repl/display-tool-messages.js +47 -44
- package/dist/repl/get-prompt-header.d.ts.map +1 -1
- package/dist/repl/get-prompt-header.js +1 -30
- package/dist/repl/project-status-line.d.ts +2 -0
- package/dist/repl/project-status-line.d.ts.map +1 -0
- package/dist/repl/project-status-line.js +31 -0
- package/dist/repl/prompt.d.ts +21 -0
- package/dist/repl/prompt.d.ts.map +1 -0
- package/dist/{repl-prompt.js → repl/prompt.js} +119 -22
- 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 +53 -0
- package/dist/repl-new.d.ts.map +1 -0
- package/dist/repl-new.js +374 -0
- package/dist/repl.d.ts +3 -5
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +74 -166
- package/dist/terminal/checkbox-prompt.d.ts.map +1 -1
- package/dist/terminal/checkbox-prompt.js +10 -4
- package/dist/terminal/index.d.ts +7 -0
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +94 -0
- package/dist/terminal/input-prompt.d.ts +2 -1
- package/dist/terminal/input-prompt.d.ts.map +1 -1
- package/dist/terminal/markdown.js +3 -0
- package/dist/terminal/search-prompt.d.ts.map +1 -1
- package/dist/terminal/search-prompt.js +11 -10
- 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/tokens/threshold.d.ts +35 -0
- package/dist/tokens/threshold.d.ts.map +1 -0
- package/dist/tokens/threshold.js +85 -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 +281 -0
- package/dist/tools/agent.d.ts +16 -5
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/agent.js +71 -58
- package/dist/tools/bash-utils.d.ts +1 -1
- package/dist/tools/bash-utils.d.ts.map +1 -1
- package/dist/tools/bash-utils.js +14 -6
- package/dist/tools/bash.d.ts +21 -12
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +88 -135
- 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 +138 -137
- 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 +51 -95
- package/dist/tools/directory-tree.d.ts +17 -6
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +47 -49
- package/dist/tools/dynamic-tool-loader.d.ts +18 -8
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +121 -129
- 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 +112 -112
- package/dist/tools/filesystem-utils.d.ts +2 -1
- package/dist/tools/filesystem-utils.d.ts.map +1 -1
- package/dist/tools/filesystem-utils.js +31 -17
- package/dist/tools/glob.d.ts +36 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +143 -0
- package/dist/tools/grep.d.ts +73 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +413 -168
- package/dist/tools/index.d.ts +204 -124
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +242 -135
- package/dist/tools/llm-edit-fixer.d.ts +25 -0
- package/dist/tools/llm-edit-fixer.d.ts.map +1 -0
- package/dist/tools/llm-edit-fixer.js +150 -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 +40 -33
- 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 +74 -69
- 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 +76 -73
- 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 +58 -101
- package/dist/tools/think.d.ts +15 -7
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +30 -22
- package/dist/tools/types.d.ts +4 -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 +50 -32
- 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/editor.d.ts +51 -0
- package/dist/tui/components/editor.d.ts.map +1 -0
- package/dist/tui/components/editor.js +758 -0
- package/dist/tui/components/footer.d.ts +24 -0
- package/dist/tui/components/footer.d.ts.map +1 -0
- package/dist/tui/components/footer.js +197 -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 +19 -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 +103 -0
- package/dist/tui/components/markdown.d.ts.map +1 -0
- package/dist/tui/components/markdown.js +533 -0
- package/dist/tui/components/modal.d.ts +40 -0
- package/dist/tui/components/modal.d.ts.map +1 -0
- package/dist/tui/components/modal.js +292 -0
- package/dist/tui/components/prompt-status.d.ts +16 -0
- package/dist/tui/components/prompt-status.d.ts.map +1 -0
- package/dist/tui/components/prompt-status.js +21 -0
- package/dist/tui/components/select-list.d.ts +22 -0
- package/dist/tui/components/select-list.d.ts.map +1 -0
- package/dist/tui/components/select-list.js +143 -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/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 +30 -0
- package/dist/tui/components/tool-execution.d.ts +17 -0
- package/dist/tui/components/tool-execution.d.ts.map +1 -0
- package/dist/tui/components/tool-execution.js +153 -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 +21 -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 +14 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +18 -0
- package/dist/tui/terminal.d.ts +37 -0
- package/dist/tui/terminal.d.ts.map +1 -0
- package/dist/tui/terminal.js +104 -0
- package/dist/tui/tui.d.ts +67 -0
- package/dist/tui/tui.d.ts.map +1 -0
- package/dist/tui/tui.js +184 -0
- package/dist/tui/utils.d.ts +19 -0
- package/dist/tui/utils.d.ts.map +1 -0
- package/dist/tui/utils.js +31 -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/utils/iterables.d.ts +2 -0
- package/dist/utils/iterables.d.ts.map +1 -0
- package/dist/utils/iterables.js +6 -0
- package/package.json +16 -16
- 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-prompt.d.ts +0 -15
- package/dist/repl-prompt.d.ts.map +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/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/grep.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../source/tools/grep.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../source/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,QAAQ;;CAEpB,CAAC;AAEF,QAAA,MAAM,WAAW;;;;;;;;;;iBA2Cf,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEnD,eAAO,MAAM,cAAc,GAAI,SAAS;IAAE,YAAY,EAAE,YAAY,CAAA;CAAE;;;;;;;;;;;;;;;sHAmB7D,eAAe,+BACW,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;CAuIhC,CAAC;AAEF,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAQD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiI9D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,MAAM,CAmDR;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,UAAU;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CA4EjE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAE/D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,WAAW,EAAE,EACtB,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC;IAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CA6BpD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAWxD;AAED,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,MAAM,CAGR;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,UAAU,CAqDZ"}
|
package/dist/tools/grep.js
CHANGED
|
@@ -1,159 +1,172 @@
|
|
|
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 } 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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
102
|
+
}
|
|
103
|
+
const projectConfig = await config.readProjectConfig();
|
|
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
|
+
const result = await manageTokenLimit(grepResult.rawOutput, tokenCounter, "Grep", "Use maxResults parameter, more specific patterns, or contextLines=0 to reduce output");
|
|
116
|
+
const matchCount = grepResult.matchCount;
|
|
117
|
+
// Build completion message with preview information
|
|
118
|
+
let completionMessage = `Found ${style.cyan(matchCount)} match${matchCount === 1 ? "" : "es"}`;
|
|
119
|
+
if (matchCount === 0) {
|
|
120
|
+
completionMessage = "Search completed - no matches found";
|
|
121
|
+
}
|
|
122
|
+
// Calculate unique files with matches
|
|
123
|
+
const filesWithMatches = new Set(grepResult.parsedMatches
|
|
124
|
+
.filter((match) => match.isMatch && !match.isContext && match.file)
|
|
125
|
+
.map((match) => match.file)).size;
|
|
126
|
+
if (filesWithMatches > 0) {
|
|
127
|
+
completionMessage += ` across ${style.cyan(filesWithMatches)} file${filesWithMatches === 1 ? "" : "s"}`;
|
|
128
|
+
}
|
|
129
|
+
if (grepResult.contextCount > 0) {
|
|
130
|
+
completionMessage += ` with ${style.cyan(grepResult.contextCount)} context line${grepResult.contextCount === 1 ? "" : "s"}`;
|
|
131
|
+
}
|
|
132
|
+
completionMessage += ` (${result.tokenCount} tokens)`;
|
|
133
|
+
yield {
|
|
134
|
+
name: GrepTool.name,
|
|
135
|
+
event: "tool-completion",
|
|
136
|
+
id: toolCallId,
|
|
137
|
+
data: completionMessage,
|
|
138
|
+
};
|
|
139
|
+
yield result.content;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const errorMessage = error.message;
|
|
143
|
+
let userFriendlyError = `Error searching for "${pattern}" in ${path}: ${errorMessage}`;
|
|
144
|
+
// Provide more helpful error messages for common cases
|
|
145
|
+
if (errorMessage.includes("No such file or directory")) {
|
|
146
|
+
userFriendlyError = `Path not found: "${path}"`;
|
|
147
|
+
if (filePattern) {
|
|
148
|
+
userFriendlyError += ` with file pattern "${filePattern}"`;
|
|
136
149
|
}
|
|
137
|
-
|
|
138
|
-
event: "tool-completion",
|
|
139
|
-
id: toolCallId,
|
|
140
|
-
data: `Found ${style.cyan(matchCount)} matches. (${managed.tokenCount} tokens)`,
|
|
141
|
-
});
|
|
142
|
-
return Promise.resolve(managed.content);
|
|
150
|
+
userFriendlyError += " - check if the path exists and is accessible";
|
|
143
151
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
event: "tool-error",
|
|
147
|
-
id: toolCallId,
|
|
148
|
-
data: `Error searching for "${pattern}" in ${path}`,
|
|
149
|
-
});
|
|
150
|
-
return Promise.resolve(error.message);
|
|
152
|
+
else if (errorMessage.includes("permission denied")) {
|
|
153
|
+
userFriendlyError = `Permission denied accessing "${path}"`;
|
|
151
154
|
}
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
else if (errorMessage.includes("Regex parse error")) {
|
|
156
|
+
userFriendlyError = `Invalid search pattern "${pattern}" - try using literal=true for fixed-string search`;
|
|
157
|
+
}
|
|
158
|
+
yield {
|
|
159
|
+
name: GrepTool.name,
|
|
160
|
+
event: "tool-error",
|
|
161
|
+
id: toolCallId,
|
|
162
|
+
data: userFriendlyError,
|
|
163
|
+
};
|
|
164
|
+
yield errorMessage;
|
|
165
|
+
}
|
|
166
|
+
},
|
|
154
167
|
};
|
|
155
168
|
};
|
|
156
|
-
function likelyUnbalancedRegex(pattern) {
|
|
169
|
+
export function likelyUnbalancedRegex(pattern) {
|
|
157
170
|
const counts = {
|
|
158
171
|
openParen: 0,
|
|
159
172
|
closeParen: 0,
|
|
@@ -163,6 +176,7 @@ function likelyUnbalancedRegex(pattern) {
|
|
|
163
176
|
closeBrace: 0,
|
|
164
177
|
};
|
|
165
178
|
let escaped = false;
|
|
179
|
+
let inCharacterClass = false;
|
|
166
180
|
for (let i = 0; i < pattern.length; i++) {
|
|
167
181
|
const ch = pattern[i];
|
|
168
182
|
if (escaped) {
|
|
@@ -173,32 +187,105 @@ function likelyUnbalancedRegex(pattern) {
|
|
|
173
187
|
escaped = true;
|
|
174
188
|
continue;
|
|
175
189
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
// Track character class boundaries
|
|
191
|
+
if (ch === "[" && !inCharacterClass) {
|
|
192
|
+
inCharacterClass = true;
|
|
193
|
+
counts.openBracket++;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (ch === "]" && inCharacterClass) {
|
|
197
|
+
inCharacterClass = false;
|
|
198
|
+
counts.closeBracket++;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
// Only count brackets/parens/braces outside of character classes
|
|
202
|
+
if (!inCharacterClass) {
|
|
203
|
+
switch (ch) {
|
|
204
|
+
case "(":
|
|
205
|
+
counts.openParen++;
|
|
206
|
+
break;
|
|
207
|
+
case ")":
|
|
208
|
+
counts.closeParen++;
|
|
209
|
+
break;
|
|
210
|
+
case "{":
|
|
211
|
+
counts.openBrace++;
|
|
212
|
+
break;
|
|
213
|
+
case "}":
|
|
214
|
+
counts.closeBrace++;
|
|
215
|
+
break;
|
|
216
|
+
default:
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
197
219
|
}
|
|
198
220
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
221
|
+
// Check for unbalanced brackets, parentheses, and braces
|
|
222
|
+
const hasUnbalancedBrackets = counts.openBracket !== counts.closeBracket;
|
|
223
|
+
const hasUnbalancedParens = counts.openParen !== counts.closeParen;
|
|
224
|
+
const hasUnbalancedBraces = counts.openBrace !== counts.closeBrace;
|
|
225
|
+
// Also check for invalid repetition operators (e.g., {n}, {n,}, {n,m}) outside of character classes
|
|
226
|
+
let hasInvalidRepetition = false;
|
|
227
|
+
{
|
|
228
|
+
let escaped2 = false;
|
|
229
|
+
let inClass2 = false;
|
|
230
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
231
|
+
const ch = pattern[i];
|
|
232
|
+
if (escaped2) {
|
|
233
|
+
escaped2 = false;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
if (ch === "\\") {
|
|
237
|
+
escaped2 = true;
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (ch === "[" && !inClass2) {
|
|
241
|
+
inClass2 = true;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (ch === "]" && inClass2) {
|
|
245
|
+
inClass2 = false;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
if (inClass2) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (ch === "{") {
|
|
252
|
+
let j = i + 1;
|
|
253
|
+
let hasDigits = false;
|
|
254
|
+
let hasComma = false;
|
|
255
|
+
while (j < pattern.length && pattern[j] !== "}") {
|
|
256
|
+
const c = pattern[j];
|
|
257
|
+
if (c >= "0" && c <= "9") {
|
|
258
|
+
hasDigits = true;
|
|
259
|
+
}
|
|
260
|
+
else if (c === "," && !hasComma) {
|
|
261
|
+
hasComma = true;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
j++;
|
|
267
|
+
}
|
|
268
|
+
if (j >= pattern.length || pattern[j] !== "}") {
|
|
269
|
+
hasInvalidRepetition = true;
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
// At this point we have a closing brace at j
|
|
273
|
+
if (!hasDigits) {
|
|
274
|
+
// Heuristic: treat empty {} as non-quantifier when it doesn't follow a likely atom
|
|
275
|
+
const prev = i > 0 ? pattern[i - 1] : undefined;
|
|
276
|
+
if (prev !== undefined && /\S/.test(prev)) {
|
|
277
|
+
hasInvalidRepetition = true;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
// else ignore as literal braces
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return (hasUnbalancedBrackets ||
|
|
286
|
+
hasUnbalancedParens ||
|
|
287
|
+
hasUnbalancedBraces ||
|
|
288
|
+
hasInvalidRepetition);
|
|
202
289
|
}
|
|
203
290
|
/**
|
|
204
291
|
* Search files for patterns using ripgrep
|
|
@@ -246,21 +333,179 @@ export function buildGrepCommand(pattern, path, options = {}) {
|
|
|
246
333
|
command += " -F";
|
|
247
334
|
}
|
|
248
335
|
command += ` ${JSON.stringify(pattern)}`;
|
|
249
|
-
command += ` ${path}`;
|
|
336
|
+
command += ` ${JSON.stringify(path)}`;
|
|
250
337
|
return command;
|
|
251
338
|
}
|
|
252
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Parse ripgrep output and extract structured match information
|
|
341
|
+
*/
|
|
342
|
+
export function parseRipgrepOutput(content) {
|
|
343
|
+
if (content === "No matches found.") {
|
|
344
|
+
return [];
|
|
345
|
+
}
|
|
346
|
+
const lines = content.trim().split("\n");
|
|
347
|
+
const parsed = [];
|
|
348
|
+
for (const line of lines) {
|
|
349
|
+
if (line === "--") {
|
|
350
|
+
// Separator between file groups - skip
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (line.trim() === "") {
|
|
354
|
+
// Empty line - skip
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
// Try multi-file format: file:line:content
|
|
358
|
+
const multiFileMatch = line.match(/^([^:]+):(\d+):(.+)$/);
|
|
359
|
+
if (multiFileMatch) {
|
|
360
|
+
parsed.push({
|
|
361
|
+
file: multiFileMatch[1],
|
|
362
|
+
line: Number.parseInt(multiFileMatch[2], 10),
|
|
363
|
+
content: multiFileMatch[3],
|
|
364
|
+
isMatch: true,
|
|
365
|
+
});
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
// Try single-file format: line:content
|
|
369
|
+
const singleFileMatch = line.match(/^(\d+):(.+)$/);
|
|
370
|
+
if (singleFileMatch) {
|
|
371
|
+
parsed.push({
|
|
372
|
+
line: Number.parseInt(singleFileMatch[1], 10),
|
|
373
|
+
content: singleFileMatch[2],
|
|
374
|
+
isMatch: true,
|
|
375
|
+
});
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
// Try context line format: file-line-context
|
|
379
|
+
const contextMatch = line.match(/^([^:]+)-(\d+)-(.+)$/);
|
|
380
|
+
if (contextMatch) {
|
|
381
|
+
parsed.push({
|
|
382
|
+
file: contextMatch[1],
|
|
383
|
+
line: Number.parseInt(contextMatch[2], 10),
|
|
384
|
+
content: contextMatch[3],
|
|
385
|
+
isMatch: false,
|
|
386
|
+
isContext: true,
|
|
387
|
+
});
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
// Try context line format without file: line-context
|
|
391
|
+
const contextNoFileMatch = line.match(/^(\d+)-(.+)$/);
|
|
392
|
+
if (contextNoFileMatch) {
|
|
393
|
+
parsed.push({
|
|
394
|
+
line: Number.parseInt(contextNoFileMatch[1], 10),
|
|
395
|
+
content: contextNoFileMatch[2],
|
|
396
|
+
isMatch: false,
|
|
397
|
+
isContext: true,
|
|
398
|
+
});
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
// If we get here, it's an unrecognized format - treat as match for backwards compatibility
|
|
402
|
+
parsed.push({
|
|
403
|
+
content: line,
|
|
404
|
+
line: 0,
|
|
405
|
+
isMatch: true,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return parsed;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Count actual matches (excluding context lines)
|
|
412
|
+
*/
|
|
413
|
+
export function countActualMatches(parsed) {
|
|
414
|
+
return parsed.filter((match) => match.isMatch && !match.isContext).length;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Count context lines
|
|
418
|
+
*/
|
|
419
|
+
export function countContextLines(parsed) {
|
|
420
|
+
return parsed.filter((match) => match.isContext).length;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Truncate matches to a maximum number of results
|
|
424
|
+
*/
|
|
425
|
+
export function truncateMatches(matches, maxResults) {
|
|
426
|
+
if (!maxResults || maxResults <= 0) {
|
|
427
|
+
return { truncated: matches, isTruncated: false };
|
|
428
|
+
}
|
|
429
|
+
const actualMatches = matches.filter((m) => m.isMatch && !m.isContext);
|
|
430
|
+
if (actualMatches.length <= maxResults) {
|
|
431
|
+
return { truncated: matches, isTruncated: false };
|
|
432
|
+
}
|
|
433
|
+
const truncated = [];
|
|
434
|
+
let matchesKept = 0;
|
|
435
|
+
for (const match of matches) {
|
|
436
|
+
if (match.isMatch && !match.isContext) {
|
|
437
|
+
if (matchesKept < maxResults) {
|
|
438
|
+
truncated.push(match);
|
|
439
|
+
matchesKept++;
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
truncated,
|
|
448
|
+
isTruncated: true,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Extract matches from content (backwards compatibility wrapper)
|
|
453
|
+
*/
|
|
454
|
+
export function extractMatches(content) {
|
|
455
|
+
const parsed = parseRipgrepOutput(content);
|
|
456
|
+
const matches = parsed.filter((match) => match.isMatch && !match.isContext);
|
|
457
|
+
// Convert back to original string format for backwards compatibility
|
|
458
|
+
return matches.map((match) => {
|
|
459
|
+
if (match.file) {
|
|
460
|
+
return `${match.file}:${match.line}:${match.content}`;
|
|
461
|
+
}
|
|
462
|
+
return `${match.line}:${match.content}`;
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
export function grepFiles(pattern, path, options = {}) {
|
|
466
|
+
const result = grepFilesStructured(pattern, path, options);
|
|
467
|
+
return result.rawOutput;
|
|
468
|
+
}
|
|
469
|
+
export function grepFilesStructured(pattern, path, options = {}) {
|
|
253
470
|
try {
|
|
254
471
|
const command = buildGrepCommand(pattern, path, options);
|
|
255
|
-
const
|
|
256
|
-
|
|
472
|
+
const rawOutput = execSync(command, {
|
|
473
|
+
encoding: "utf-8",
|
|
474
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
475
|
+
});
|
|
476
|
+
const parsedMatches = parseRipgrepOutput(rawOutput);
|
|
477
|
+
const matchCount = countActualMatches(parsedMatches);
|
|
478
|
+
const { truncated, isTruncated } = truncateMatches(parsedMatches, options.maxResults);
|
|
479
|
+
const displayedCount = countActualMatches(truncated);
|
|
480
|
+
const displayedContextCount = countContextLines(truncated);
|
|
481
|
+
return {
|
|
482
|
+
rawOutput,
|
|
483
|
+
parsedMatches: truncated,
|
|
484
|
+
matchCount,
|
|
485
|
+
displayedCount,
|
|
486
|
+
contextCount: displayedContextCount,
|
|
487
|
+
hasMatches: matchCount > 0,
|
|
488
|
+
isTruncated,
|
|
489
|
+
};
|
|
257
490
|
}
|
|
258
491
|
catch (error) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
return
|
|
492
|
+
const execError = error;
|
|
493
|
+
const exitCode = execError?.status;
|
|
494
|
+
if (exitCode === 1) {
|
|
495
|
+
return {
|
|
496
|
+
rawOutput: "No matches found.",
|
|
497
|
+
parsedMatches: [],
|
|
498
|
+
matchCount: 0,
|
|
499
|
+
contextCount: 0,
|
|
500
|
+
hasMatches: false,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
if (exitCode === 2) {
|
|
504
|
+
const stderrStr = typeof execError.stderr === "string"
|
|
505
|
+
? execError.stderr
|
|
506
|
+
: (execError.stderr?.toString("utf-8") ?? execError.message);
|
|
507
|
+
throw new Error(`Regex parse error in pattern "${pattern}": ${stderrStr}`);
|
|
263
508
|
}
|
|
264
|
-
throw new Error(`Error executing ripgrep: ${
|
|
509
|
+
throw new Error(`Error executing ripgrep: ${execError.message}`);
|
|
265
510
|
}
|
|
266
511
|
}
|