@nexus-cortex/executors 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +2 -0
- package/README.md +13 -0
- package/dist/ExecutorRegistry.d.ts +89 -0
- package/dist/ExecutorRegistry.d.ts.map +1 -0
- package/dist/ExecutorRegistry.js +219 -0
- package/dist/ExecutorRegistry.js.map +1 -0
- package/dist/base/BaseTool.d.ts +108 -0
- package/dist/base/BaseTool.d.ts.map +1 -0
- package/dist/base/BaseTool.js +111 -0
- package/dist/base/BaseTool.js.map +1 -0
- package/dist/base/ToolRegistry.d.ts +141 -0
- package/dist/base/ToolRegistry.d.ts.map +1 -0
- package/dist/base/ToolRegistry.js +241 -0
- package/dist/base/ToolRegistry.js.map +1 -0
- package/dist/base/ToolResult.d.ts +63 -0
- package/dist/base/ToolResult.d.ts.map +1 -0
- package/dist/base/ToolResult.js +8 -0
- package/dist/base/ToolResult.js.map +1 -0
- package/dist/base/index.d.ts +10 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +8 -0
- package/dist/base/index.js.map +1 -0
- package/dist/implementations/addon/CreateArtifactTool.d.ts +221 -0
- package/dist/implementations/addon/CreateArtifactTool.d.ts.map +1 -0
- package/dist/implementations/addon/CreateArtifactTool.js +1042 -0
- package/dist/implementations/addon/CreateArtifactTool.js.map +1 -0
- package/dist/implementations/addon/FrameDiffCache.d.ts +166 -0
- package/dist/implementations/addon/FrameDiffCache.d.ts.map +1 -0
- package/dist/implementations/addon/FrameDiffCache.js +395 -0
- package/dist/implementations/addon/FrameDiffCache.js.map +1 -0
- package/dist/implementations/addon/H264StreamEncoder.d.ts +84 -0
- package/dist/implementations/addon/H264StreamEncoder.d.ts.map +1 -0
- package/dist/implementations/addon/H264StreamEncoder.js +203 -0
- package/dist/implementations/addon/H264StreamEncoder.js.map +1 -0
- package/dist/implementations/addon/HybridScreenshotManager.d.ts +197 -0
- package/dist/implementations/addon/HybridScreenshotManager.d.ts.map +1 -0
- package/dist/implementations/addon/HybridScreenshotManager.js +415 -0
- package/dist/implementations/addon/HybridScreenshotManager.js.map +1 -0
- package/dist/implementations/addon/InspectSandboxTool.d.ts +54 -0
- package/dist/implementations/addon/InspectSandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/InspectSandboxTool.js +226 -0
- package/dist/implementations/addon/InspectSandboxTool.js.map +1 -0
- package/dist/implementations/addon/InteractWithSandboxTool.d.ts +90 -0
- package/dist/implementations/addon/InteractWithSandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/InteractWithSandboxTool.js +367 -0
- package/dist/implementations/addon/InteractWithSandboxTool.js.map +1 -0
- package/dist/implementations/addon/KeyframeDetector.d.ts +140 -0
- package/dist/implementations/addon/KeyframeDetector.d.ts.map +1 -0
- package/dist/implementations/addon/KeyframeDetector.js +390 -0
- package/dist/implementations/addon/KeyframeDetector.js.map +1 -0
- package/dist/implementations/addon/ModifySandboxTool.d.ts +62 -0
- package/dist/implementations/addon/ModifySandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/ModifySandboxTool.js +266 -0
- package/dist/implementations/addon/ModifySandboxTool.js.map +1 -0
- package/dist/implementations/addon/ReactArtifactBuilder.d.ts +27 -0
- package/dist/implementations/addon/ReactArtifactBuilder.d.ts.map +1 -0
- package/dist/implementations/addon/ReactArtifactBuilder.js +198 -0
- package/dist/implementations/addon/ReactArtifactBuilder.js.map +1 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.d.ts +143 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.d.ts.map +1 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.js +258 -0
- package/dist/implementations/addon/SandboxEventBroadcaster.js.map +1 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.d.ts +77 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.d.ts.map +1 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.js +292 -0
- package/dist/implementations/addon/SandboxIntrospectionTools.js.map +1 -0
- package/dist/implementations/addon/SandboxViewServer.d.ts +127 -0
- package/dist/implementations/addon/SandboxViewServer.d.ts.map +1 -0
- package/dist/implementations/addon/SandboxViewServer.js +775 -0
- package/dist/implementations/addon/SandboxViewServer.js.map +1 -0
- package/dist/implementations/addon/ScreenStream.d.ts +149 -0
- package/dist/implementations/addon/ScreenStream.d.ts.map +1 -0
- package/dist/implementations/addon/ScreenStream.js +306 -0
- package/dist/implementations/addon/ScreenStream.js.map +1 -0
- package/dist/implementations/addon/StopSandboxTool.d.ts +61 -0
- package/dist/implementations/addon/StopSandboxTool.d.ts.map +1 -0
- package/dist/implementations/addon/StopSandboxTool.js +252 -0
- package/dist/implementations/addon/StopSandboxTool.js.map +1 -0
- package/dist/implementations/addon/TerminalSandbox.d.ts +111 -0
- package/dist/implementations/addon/TerminalSandbox.d.ts.map +1 -0
- package/dist/implementations/addon/TerminalSandbox.js +345 -0
- package/dist/implementations/addon/TerminalSandbox.js.map +1 -0
- package/dist/implementations/addon/VisualFeedbackBridge.d.ts +367 -0
- package/dist/implementations/addon/VisualFeedbackBridge.d.ts.map +1 -0
- package/dist/implementations/addon/VisualFeedbackBridge.js +888 -0
- package/dist/implementations/addon/VisualFeedbackBridge.js.map +1 -0
- package/dist/implementations/addon/WindowManager.d.ts +138 -0
- package/dist/implementations/addon/WindowManager.d.ts.map +1 -0
- package/dist/implementations/addon/WindowManager.js +276 -0
- package/dist/implementations/addon/WindowManager.js.map +1 -0
- package/dist/implementations/addon/index.d.ts +29 -0
- package/dist/implementations/addon/index.d.ts.map +1 -0
- package/dist/implementations/addon/index.js +29 -0
- package/dist/implementations/addon/index.js.map +1 -0
- package/dist/implementations/addon/injectables/reactIntrospection.d.ts +57 -0
- package/dist/implementations/addon/injectables/reactIntrospection.d.ts.map +1 -0
- package/dist/implementations/addon/injectables/reactIntrospection.js +480 -0
- package/dist/implementations/addon/injectables/reactIntrospection.js.map +1 -0
- package/dist/implementations/addon/terminal-client.html +253 -0
- package/dist/implementations/agent/PRAgentTool.d.ts +37 -0
- package/dist/implementations/agent/PRAgentTool.d.ts.map +1 -0
- package/dist/implementations/agent/PRAgentTool.js +257 -0
- package/dist/implementations/agent/PRAgentTool.js.map +1 -0
- package/dist/implementations/agent/TaskTool.d.ts +76 -0
- package/dist/implementations/agent/TaskTool.d.ts.map +1 -0
- package/dist/implementations/agent/TaskTool.js +424 -0
- package/dist/implementations/agent/TaskTool.js.map +1 -0
- package/dist/implementations/agent/index.d.ts +5 -0
- package/dist/implementations/agent/index.d.ts.map +1 -0
- package/dist/implementations/agent/index.js +3 -0
- package/dist/implementations/agent/index.js.map +1 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.d.ts +68 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.d.ts.map +1 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.js +146 -0
- package/dist/implementations/execution/BackgroundProcessRegistry.js.map +1 -0
- package/dist/implementations/execution/BashOutputTool.d.ts +42 -0
- package/dist/implementations/execution/BashOutputTool.d.ts.map +1 -0
- package/dist/implementations/execution/BashOutputTool.js +168 -0
- package/dist/implementations/execution/BashOutputTool.js.map +1 -0
- package/dist/implementations/execution/CodeExecuteTool.d.ts +31 -0
- package/dist/implementations/execution/CodeExecuteTool.d.ts.map +1 -0
- package/dist/implementations/execution/CodeExecuteTool.js +127 -0
- package/dist/implementations/execution/CodeExecuteTool.js.map +1 -0
- package/dist/implementations/execution/KillShellTool.d.ts +37 -0
- package/dist/implementations/execution/KillShellTool.d.ts.map +1 -0
- package/dist/implementations/execution/KillShellTool.js +144 -0
- package/dist/implementations/execution/KillShellTool.js.map +1 -0
- package/dist/implementations/execution/SearchToolsTool.d.ts +32 -0
- package/dist/implementations/execution/SearchToolsTool.d.ts.map +1 -0
- package/dist/implementations/execution/SearchToolsTool.js +109 -0
- package/dist/implementations/execution/SearchToolsTool.js.map +1 -0
- package/dist/implementations/execution/ShellTool.d.ts +108 -0
- package/dist/implementations/execution/ShellTool.d.ts.map +1 -0
- package/dist/implementations/execution/ShellTool.js +546 -0
- package/dist/implementations/execution/ShellTool.js.map +1 -0
- package/dist/implementations/execution/WorkspaceManagerTool.d.ts +40 -0
- package/dist/implementations/execution/WorkspaceManagerTool.d.ts.map +1 -0
- package/dist/implementations/execution/WorkspaceManagerTool.js +370 -0
- package/dist/implementations/execution/WorkspaceManagerTool.js.map +1 -0
- package/dist/implementations/execution/index.d.ts +13 -0
- package/dist/implementations/execution/index.d.ts.map +1 -0
- package/dist/implementations/execution/index.js +13 -0
- package/dist/implementations/execution/index.js.map +1 -0
- package/dist/implementations/extensions/EndTurnTool.d.ts +62 -0
- package/dist/implementations/extensions/EndTurnTool.d.ts.map +1 -0
- package/dist/implementations/extensions/EndTurnTool.js +172 -0
- package/dist/implementations/extensions/EndTurnTool.js.map +1 -0
- package/dist/implementations/extensions/ResearchBacklogTool.d.ts +37 -0
- package/dist/implementations/extensions/ResearchBacklogTool.d.ts.map +1 -0
- package/dist/implementations/extensions/ResearchBacklogTool.js +102 -0
- package/dist/implementations/extensions/ResearchBacklogTool.js.map +1 -0
- package/dist/implementations/extensions/SkillTool.d.ts +108 -0
- package/dist/implementations/extensions/SkillTool.d.ts.map +1 -0
- package/dist/implementations/extensions/SkillTool.js +351 -0
- package/dist/implementations/extensions/SkillTool.js.map +1 -0
- package/dist/implementations/extensions/SlashCommandTool.d.ts +112 -0
- package/dist/implementations/extensions/SlashCommandTool.d.ts.map +1 -0
- package/dist/implementations/extensions/SlashCommandTool.js +315 -0
- package/dist/implementations/extensions/SlashCommandTool.js.map +1 -0
- package/dist/implementations/extensions/index.d.ts +14 -0
- package/dist/implementations/extensions/index.d.ts.map +1 -0
- package/dist/implementations/extensions/index.js +10 -0
- package/dist/implementations/extensions/index.js.map +1 -0
- package/dist/implementations/file/EditTool.d.ts +232 -0
- package/dist/implementations/file/EditTool.d.ts.map +1 -0
- package/dist/implementations/file/EditTool.js +707 -0
- package/dist/implementations/file/EditTool.js.map +1 -0
- package/dist/implementations/file/ReadFileTool.d.ts +49 -0
- package/dist/implementations/file/ReadFileTool.d.ts.map +1 -0
- package/dist/implementations/file/ReadFileTool.js +225 -0
- package/dist/implementations/file/ReadFileTool.js.map +1 -0
- package/dist/implementations/file/WriteBinaryTool.d.ts +21 -0
- package/dist/implementations/file/WriteBinaryTool.d.ts.map +1 -0
- package/dist/implementations/file/WriteBinaryTool.js +153 -0
- package/dist/implementations/file/WriteBinaryTool.js.map +1 -0
- package/dist/implementations/file/WriteFileTool.d.ts +41 -0
- package/dist/implementations/file/WriteFileTool.d.ts.map +1 -0
- package/dist/implementations/file/WriteFileTool.js +220 -0
- package/dist/implementations/file/WriteFileTool.js.map +1 -0
- package/dist/implementations/file/index.d.ts +8 -0
- package/dist/implementations/file/index.d.ts.map +1 -0
- package/dist/implementations/file/index.js +8 -0
- package/dist/implementations/file/index.js.map +1 -0
- package/dist/implementations/historical/GetConversationSegmentTool.d.ts +44 -0
- package/dist/implementations/historical/GetConversationSegmentTool.d.ts.map +1 -0
- package/dist/implementations/historical/GetConversationSegmentTool.js +220 -0
- package/dist/implementations/historical/GetConversationSegmentTool.js.map +1 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.d.ts +36 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.d.ts.map +1 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.js +174 -0
- package/dist/implementations/historical/ListCompactionBoundariesTool.js.map +1 -0
- package/dist/implementations/historical/ListSessionsTool.d.ts +38 -0
- package/dist/implementations/historical/ListSessionsTool.d.ts.map +1 -0
- package/dist/implementations/historical/ListSessionsTool.js +140 -0
- package/dist/implementations/historical/ListSessionsTool.js.map +1 -0
- package/dist/implementations/historical/LoadSessionTool.d.ts +39 -0
- package/dist/implementations/historical/LoadSessionTool.d.ts.map +1 -0
- package/dist/implementations/historical/LoadSessionTool.js +171 -0
- package/dist/implementations/historical/LoadSessionTool.js.map +1 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.d.ts +46 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.d.ts.map +1 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.js +224 -0
- package/dist/implementations/historical/RequestHistoricalContextTool.js.map +1 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.d.ts +51 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.d.ts.map +1 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.js +306 -0
- package/dist/implementations/historical/SearchConversationHistoryTool.js.map +1 -0
- package/dist/implementations/historical/index.d.ts +12 -0
- package/dist/implementations/historical/index.d.ts.map +1 -0
- package/dist/implementations/historical/index.js +12 -0
- package/dist/implementations/historical/index.js.map +1 -0
- package/dist/implementations/index.d.ts +16 -0
- package/dist/implementations/index.d.ts.map +1 -0
- package/dist/implementations/index.js +28 -0
- package/dist/implementations/index.js.map +1 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.d.ts +58 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.d.ts.map +1 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.js +269 -0
- package/dist/implementations/mcp/DiscoveredMcpTool.js.map +1 -0
- package/dist/implementations/mcp/index.d.ts +9 -0
- package/dist/implementations/mcp/index.d.ts.map +1 -0
- package/dist/implementations/mcp/index.js +8 -0
- package/dist/implementations/mcp/index.js.map +1 -0
- package/dist/implementations/notebook/NotebookEditTool.d.ts +96 -0
- package/dist/implementations/notebook/NotebookEditTool.d.ts.map +1 -0
- package/dist/implementations/notebook/NotebookEditTool.js +390 -0
- package/dist/implementations/notebook/NotebookEditTool.js.map +1 -0
- package/dist/implementations/notebook/index.d.ts +7 -0
- package/dist/implementations/notebook/index.d.ts.map +1 -0
- package/dist/implementations/notebook/index.js +7 -0
- package/dist/implementations/notebook/index.js.map +1 -0
- package/dist/implementations/search/GlobTool.d.ts +73 -0
- package/dist/implementations/search/GlobTool.d.ts.map +1 -0
- package/dist/implementations/search/GlobTool.js +213 -0
- package/dist/implementations/search/GlobTool.js.map +1 -0
- package/dist/implementations/search/GrepTool.d.ts +102 -0
- package/dist/implementations/search/GrepTool.d.ts.map +1 -0
- package/dist/implementations/search/GrepTool.js +754 -0
- package/dist/implementations/search/GrepTool.js.map +1 -0
- package/dist/implementations/search/index.d.ts +6 -0
- package/dist/implementations/search/index.d.ts.map +1 -0
- package/dist/implementations/search/index.js +6 -0
- package/dist/implementations/search/index.js.map +1 -0
- package/dist/implementations/tmux/TmuxSessionTool.d.ts +82 -0
- package/dist/implementations/tmux/TmuxSessionTool.d.ts.map +1 -0
- package/dist/implementations/tmux/TmuxSessionTool.js +371 -0
- package/dist/implementations/tmux/TmuxSessionTool.js.map +1 -0
- package/dist/implementations/tmux/TmuxViewServer.d.ts +86 -0
- package/dist/implementations/tmux/TmuxViewServer.d.ts.map +1 -0
- package/dist/implementations/tmux/TmuxViewServer.js +480 -0
- package/dist/implementations/tmux/TmuxViewServer.js.map +1 -0
- package/dist/implementations/tmux/index.d.ts +6 -0
- package/dist/implementations/tmux/index.d.ts.map +1 -0
- package/dist/implementations/tmux/index.js +6 -0
- package/dist/implementations/tmux/index.js.map +1 -0
- package/dist/implementations/ui/AskUserQuestionTool.d.ts +77 -0
- package/dist/implementations/ui/AskUserQuestionTool.d.ts.map +1 -0
- package/dist/implementations/ui/AskUserQuestionTool.js +241 -0
- package/dist/implementations/ui/AskUserQuestionTool.js.map +1 -0
- package/dist/implementations/ui/ExitPlanModeTool.d.ts +44 -0
- package/dist/implementations/ui/ExitPlanModeTool.d.ts.map +1 -0
- package/dist/implementations/ui/ExitPlanModeTool.js +150 -0
- package/dist/implementations/ui/ExitPlanModeTool.js.map +1 -0
- package/dist/implementations/ui/TodoWriteTool.d.ts +59 -0
- package/dist/implementations/ui/TodoWriteTool.d.ts.map +1 -0
- package/dist/implementations/ui/TodoWriteTool.js +315 -0
- package/dist/implementations/ui/TodoWriteTool.js.map +1 -0
- package/dist/implementations/ui/index.d.ts +9 -0
- package/dist/implementations/ui/index.d.ts.map +1 -0
- package/dist/implementations/ui/index.js +9 -0
- package/dist/implementations/ui/index.js.map +1 -0
- package/dist/implementations/web/BrowseTool.d.ts +43 -0
- package/dist/implementations/web/BrowseTool.d.ts.map +1 -0
- package/dist/implementations/web/BrowseTool.js +181 -0
- package/dist/implementations/web/BrowseTool.js.map +1 -0
- package/dist/implementations/web/SandboxTransferTool.d.ts +30 -0
- package/dist/implementations/web/SandboxTransferTool.d.ts.map +1 -0
- package/dist/implementations/web/SandboxTransferTool.js +261 -0
- package/dist/implementations/web/SandboxTransferTool.js.map +1 -0
- package/dist/implementations/web/WebFetchTool.d.ts +93 -0
- package/dist/implementations/web/WebFetchTool.d.ts.map +1 -0
- package/dist/implementations/web/WebFetchTool.js +484 -0
- package/dist/implementations/web/WebFetchTool.js.map +1 -0
- package/dist/implementations/web/WebSearchTool.d.ts +53 -0
- package/dist/implementations/web/WebSearchTool.d.ts.map +1 -0
- package/dist/implementations/web/WebSearchTool.js +227 -0
- package/dist/implementations/web/WebSearchTool.js.map +1 -0
- package/dist/implementations/web/escalateDirective.d.ts +11 -0
- package/dist/implementations/web/escalateDirective.d.ts.map +1 -0
- package/dist/implementations/web/escalateDirective.js +20 -0
- package/dist/implementations/web/escalateDirective.js.map +1 -0
- package/dist/implementations/web/index.d.ts +10 -0
- package/dist/implementations/web/index.d.ts.map +1 -0
- package/dist/implementations/web/index.js +10 -0
- package/dist/implementations/web/index.js.map +1 -0
- package/dist/implementations/web/webBackends.d.ts +65 -0
- package/dist/implementations/web/webBackends.d.ts.map +1 -0
- package/dist/implementations/web/webBackends.js +430 -0
- package/dist/implementations/web/webBackends.js.map +1 -0
- package/dist/implementations/web/webFetchRequestInit.d.ts +9 -0
- package/dist/implementations/web/webFetchRequestInit.d.ts.map +1 -0
- package/dist/implementations/web/webFetchRequestInit.js +21 -0
- package/dist/implementations/web/webFetchRequestInit.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/ArtifactRegistry.d.ts +138 -0
- package/dist/utils/ArtifactRegistry.d.ts.map +1 -0
- package/dist/utils/ArtifactRegistry.js +259 -0
- package/dist/utils/ArtifactRegistry.js.map +1 -0
- package/dist/utils/ChromiumBrowserManager.d.ts +56 -0
- package/dist/utils/ChromiumBrowserManager.d.ts.map +1 -0
- package/dist/utils/ChromiumBrowserManager.js +243 -0
- package/dist/utils/ChromiumBrowserManager.js.map +1 -0
- package/dist/utils/FileUtils.d.ts +81 -0
- package/dist/utils/FileUtils.d.ts.map +1 -0
- package/dist/utils/FileUtils.js +148 -0
- package/dist/utils/FileUtils.js.map +1 -0
- package/dist/utils/GitPolicy.d.ts +70 -0
- package/dist/utils/GitPolicy.d.ts.map +1 -0
- package/dist/utils/GitPolicy.js +166 -0
- package/dist/utils/GitPolicy.js.map +1 -0
- package/dist/utils/GitUtils.d.ts +18 -0
- package/dist/utils/GitUtils.d.ts.map +1 -0
- package/dist/utils/GitUtils.js +62 -0
- package/dist/utils/GitUtils.js.map +1 -0
- package/dist/utils/SandboxRegistry.d.ts +110 -0
- package/dist/utils/SandboxRegistry.d.ts.map +1 -0
- package/dist/utils/SandboxRegistry.js +220 -0
- package/dist/utils/SandboxRegistry.js.map +1 -0
- package/dist/utils/SchemaValidator.d.ts +21 -0
- package/dist/utils/SchemaValidator.d.ts.map +1 -0
- package/dist/utils/SchemaValidator.js +67 -0
- package/dist/utils/SchemaValidator.js.map +1 -0
- package/dist/utils/SessionLock.d.ts +96 -0
- package/dist/utils/SessionLock.d.ts.map +1 -0
- package/dist/utils/SessionLock.js +276 -0
- package/dist/utils/SessionLock.js.map +1 -0
- package/dist/utils/SessionPersistence.d.ts +89 -0
- package/dist/utils/SessionPersistence.d.ts.map +1 -0
- package/dist/utils/SessionPersistence.js +244 -0
- package/dist/utils/SessionPersistence.js.map +1 -0
- package/dist/utils/TextUtils.d.ts +77 -0
- package/dist/utils/TextUtils.d.ts.map +1 -0
- package/dist/utils/TextUtils.js +112 -0
- package/dist/utils/TextUtils.js.map +1 -0
- package/dist/utils/TmuxCapture.d.ts +94 -0
- package/dist/utils/TmuxCapture.d.ts.map +1 -0
- package/dist/utils/TmuxCapture.js +131 -0
- package/dist/utils/TmuxCapture.js.map +1 -0
- package/dist/utils/TmuxManager.d.ts +65 -0
- package/dist/utils/TmuxManager.d.ts.map +1 -0
- package/dist/utils/TmuxManager.js +304 -0
- package/dist/utils/TmuxManager.js.map +1 -0
- package/dist/utils/autoResearchPlanGate.d.ts +10 -0
- package/dist/utils/autoResearchPlanGate.d.ts.map +1 -0
- package/dist/utils/autoResearchPlanGate.js +57 -0
- package/dist/utils/autoResearchPlanGate.js.map +1 -0
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,754 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced Grep Tool Executor with Native Command Support
|
|
3
|
+
*
|
|
4
|
+
* Implements a 4-tier fallback strategy for optimal performance:
|
|
5
|
+
* 1. ripgrep (rg) - Fastest (0.5-1s)
|
|
6
|
+
* 2. git grep - ⚡ Fast (1-2s, git repos only)
|
|
7
|
+
* 3. system grep - Good (2-5s)
|
|
8
|
+
* 4. JavaScript fallback - Portable (5-10s)
|
|
9
|
+
*
|
|
10
|
+
* Gracefully falls back if native commands are not available.
|
|
11
|
+
*/
|
|
12
|
+
import fs from 'fs/promises';
|
|
13
|
+
import * as fsSync from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { EOL } from 'os';
|
|
16
|
+
import { spawn } from 'child_process';
|
|
17
|
+
import { globStream } from 'glob';
|
|
18
|
+
import { BaseTool } from '../../base/index.js';
|
|
19
|
+
import { SchemaValidator } from '../../utils/SchemaValidator.js';
|
|
20
|
+
import { makeRelative, shortenPath, } from '../../utils/FileUtils.js';
|
|
21
|
+
import { isGitRepository } from '../../utils/GitUtils.js';
|
|
22
|
+
/**
|
|
23
|
+
* Enhanced Grep Tool with Native Command Support
|
|
24
|
+
*/
|
|
25
|
+
export class GrepTool extends BaseTool {
|
|
26
|
+
config;
|
|
27
|
+
static DEFAULT_MAX_RESULTS = 100; // Default limit for context efficiency
|
|
28
|
+
static HARD_MAX_RESULTS = 500; // Absolute maximum to prevent context overflow
|
|
29
|
+
static MAX_CONTENT_LENGTH = 30000; // ~30KB max output
|
|
30
|
+
// JS-fallback only: skip files above this size. Reading them into a single string
|
|
31
|
+
// throws "Invalid string length" once they exceed V8's ~512MB cap (e.g. the grok
|
|
32
|
+
// CLI's .grok/upload_queue git-diff blobs), and grepping a huge minified/blob file
|
|
33
|
+
// is never useful anyway. rg/grep handle large files natively; this guards Strategy 4.
|
|
34
|
+
static MAX_SEARCHABLE_FILE_BYTES = 20 * 1024 * 1024; // 20MB
|
|
35
|
+
constructor(config) {
|
|
36
|
+
super('Grep', 'SearchText', `Searches for a regular expression pattern within the content of files. Uses ripgrep, git grep, or system grep for optimal performance, with automatic fallback to JavaScript implementation.`, {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
pattern: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
description: "The regular expression pattern to search for (e.g., 'function\\\\s+myFunction').",
|
|
42
|
+
},
|
|
43
|
+
path: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Optional: File or directory to search within. For single-file searches, provide exact file path. For directory searches, all files will be scanned. Defaults to working directory.',
|
|
46
|
+
},
|
|
47
|
+
include: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: "Optional: Glob pattern to filter files (e.g., '*.js', '**/*.{ts,tsx}').",
|
|
50
|
+
},
|
|
51
|
+
case_sensitive: {
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
description: 'Optional: Case-sensitive search. Defaults to false.',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
required: ['pattern'],
|
|
57
|
+
});
|
|
58
|
+
this.config = config;
|
|
59
|
+
}
|
|
60
|
+
validateToolParams(params) {
|
|
61
|
+
const schemaError = SchemaValidator.validate(this.parameterSchema, params);
|
|
62
|
+
if (schemaError) {
|
|
63
|
+
return schemaError;
|
|
64
|
+
}
|
|
65
|
+
// Validate regex pattern
|
|
66
|
+
try {
|
|
67
|
+
new RegExp(params.pattern);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
return `Invalid regular expression: ${params.pattern}. Error: ${error.message}`;
|
|
71
|
+
}
|
|
72
|
+
// Validate path (can be file or directory)
|
|
73
|
+
const searchPathAbsolute = path.resolve(this.config.workingDirectory, params.path || '.');
|
|
74
|
+
// Path validation: allow any absolute path (matching standard absolute-path behavior),
|
|
75
|
+
// but reject root "/" to prevent full-filesystem scans that hang tool execution.
|
|
76
|
+
if (!path.isAbsolute(searchPathAbsolute)) {
|
|
77
|
+
return `Search path must resolve to an absolute path: ${searchPathAbsolute}`;
|
|
78
|
+
}
|
|
79
|
+
if (searchPathAbsolute === '/') {
|
|
80
|
+
return `Searching from "/" would scan the entire filesystem. Use "." for the project directory or provide a specific path.`;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
if (!fsSync.existsSync(searchPathAbsolute)) {
|
|
84
|
+
return `Search path does not exist: ${searchPathAbsolute}`;
|
|
85
|
+
}
|
|
86
|
+
// Accept both files and directories
|
|
87
|
+
const stats = fsSync.statSync(searchPathAbsolute);
|
|
88
|
+
if (!stats.isFile() && !stats.isDirectory()) {
|
|
89
|
+
return `Search path must be a file or directory: ${searchPathAbsolute}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
return `Error accessing search path: ${error.message}`;
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
getDescription(params) {
|
|
98
|
+
if (!params?.pattern)
|
|
99
|
+
return 'Search file content';
|
|
100
|
+
let desc = `'${params.pattern}'`;
|
|
101
|
+
const globPattern = params.glob || params.include;
|
|
102
|
+
if (globPattern)
|
|
103
|
+
desc += ` in ${globPattern}`;
|
|
104
|
+
if (params.path) {
|
|
105
|
+
const resolved = path.resolve(this.config.workingDirectory, params.path);
|
|
106
|
+
const relative = makeRelative(resolved, this.config.workingDirectory);
|
|
107
|
+
desc += ` within ${shortenPath(relative)}`;
|
|
108
|
+
}
|
|
109
|
+
if (params.output_mode)
|
|
110
|
+
desc += ` (${params.output_mode})`;
|
|
111
|
+
return desc;
|
|
112
|
+
}
|
|
113
|
+
async execute(params, signal, updateOutput) {
|
|
114
|
+
const startTime = Date.now();
|
|
115
|
+
const validationError = this.validateToolParams(params);
|
|
116
|
+
if (validationError) {
|
|
117
|
+
return this.createErrorResult(validationError);
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const searchPathAbsolute = path.resolve(this.config.workingDirectory, params.path || '.');
|
|
121
|
+
const searchPathDisplay = params.path || '.';
|
|
122
|
+
// Normalize parameters (handle both new and legacy param names)
|
|
123
|
+
const globPattern = params.glob || params.include;
|
|
124
|
+
const caseInsensitive = params['-i'] ?? (params.case_sensitive === undefined ? false : !params.case_sensitive);
|
|
125
|
+
const outputMode = params.output_mode || 'files_with_matches'; // Default to files_with_matches for efficiency
|
|
126
|
+
// Apply default limit if not specified (prevents context overflow)
|
|
127
|
+
const headLimit = params.head_limit ?? GrepTool.DEFAULT_MAX_RESULTS;
|
|
128
|
+
const effectiveLimit = Math.min(headLimit, GrepTool.HARD_MAX_RESULTS);
|
|
129
|
+
const offset = params.offset ?? 0; // Pagination offset
|
|
130
|
+
const contextAfter = params['-A'];
|
|
131
|
+
const contextBefore = params['-B'];
|
|
132
|
+
const contextBoth = params['-C'];
|
|
133
|
+
const showLineNumbers = params['-n'] ?? true;
|
|
134
|
+
const fileType = params.type;
|
|
135
|
+
const multiline = params.multiline;
|
|
136
|
+
// Check if path is a file or directory
|
|
137
|
+
const stats = fsSync.statSync(searchPathAbsolute);
|
|
138
|
+
const isFile = stats.isFile();
|
|
139
|
+
// For single file searches, extract directory and filename
|
|
140
|
+
let searchDir;
|
|
141
|
+
let targetFile;
|
|
142
|
+
if (isFile) {
|
|
143
|
+
searchDir = path.dirname(searchPathAbsolute);
|
|
144
|
+
targetFile = path.basename(searchPathAbsolute);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
searchDir = searchPathAbsolute;
|
|
148
|
+
targetFile = undefined;
|
|
149
|
+
}
|
|
150
|
+
// Perform search with fallback strategies
|
|
151
|
+
// Pass effectiveLimit to enable early termination in native commands
|
|
152
|
+
const { matches, strategy } = await this.performGrepSearch(params.pattern, searchDir, globPattern, !caseInsensitive, // performGrepSearch expects caseSensitive, we have caseInsensitive
|
|
153
|
+
signal, targetFile, fileType, multiline, contextAfter, contextBefore, contextBoth, effectiveLimit);
|
|
154
|
+
if (matches.length === 0) {
|
|
155
|
+
const message = `No matches found for pattern "${params.pattern}" in "${searchPathDisplay}"${globPattern ? ` (filter: "${globPattern}")` : ''}.`;
|
|
156
|
+
if (updateOutput)
|
|
157
|
+
updateOutput('No matches found');
|
|
158
|
+
return this.createSuccessResult(message, {
|
|
159
|
+
executionTime: Date.now() - startTime,
|
|
160
|
+
matchCount: 0,
|
|
161
|
+
searchPath: searchPathAbsolute,
|
|
162
|
+
pattern: params.pattern,
|
|
163
|
+
strategy,
|
|
164
|
+
output_mode: outputMode,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Apply offset and limit for pagination (already limited at source for ripgrep, but ensure hard cap)
|
|
168
|
+
const totalMatches = matches.length;
|
|
169
|
+
const afterOffset = matches.slice(offset);
|
|
170
|
+
const limitedMatches = afterOffset.slice(0, effectiveLimit);
|
|
171
|
+
const hasMore = offset + limitedMatches.length < totalMatches;
|
|
172
|
+
const remainingCount = totalMatches - offset - limitedMatches.length;
|
|
173
|
+
// Format results based on output_mode
|
|
174
|
+
let llmContent;
|
|
175
|
+
let matchCount;
|
|
176
|
+
if (outputMode === 'files_with_matches') {
|
|
177
|
+
// Return only unique file paths
|
|
178
|
+
const uniqueFiles = [...new Set(limitedMatches.map(m => m.filePath))];
|
|
179
|
+
matchCount = uniqueFiles.length;
|
|
180
|
+
const displayFiles = uniqueFiles.slice(0, GrepTool.HARD_MAX_RESULTS);
|
|
181
|
+
// Build result message with pagination guidance
|
|
182
|
+
if (offset > 0 || hasMore) {
|
|
183
|
+
const rangeStart = offset + 1;
|
|
184
|
+
const rangeEnd = offset + limitedMatches.length;
|
|
185
|
+
llmContent = `Found ${totalMatches} matches in files for "${params.pattern}" (showing matches ${rangeStart}-${rangeEnd})${globPattern ? ` (filter: "${globPattern}")` : ''}:\n`;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
llmContent = `Found ${totalMatches} matches in ${uniqueFiles.length} files for "${params.pattern}"${globPattern ? ` (filter: "${globPattern}")` : ''}:\n`;
|
|
189
|
+
}
|
|
190
|
+
llmContent += displayFiles.join('\n');
|
|
191
|
+
if (hasMore) {
|
|
192
|
+
const nextOffset = offset + limitedMatches.length;
|
|
193
|
+
llmContent += `\n\n[TRUNCATED] ${remainingCount} more matches available. To see next page, call grep again with offset=${nextOffset}`;
|
|
194
|
+
}
|
|
195
|
+
if (updateOutput)
|
|
196
|
+
updateOutput(`Found ${uniqueFiles.length} files`);
|
|
197
|
+
return this.createSuccessResult(llmContent, {
|
|
198
|
+
executionTime: Date.now() - startTime,
|
|
199
|
+
matchCount: totalMatches,
|
|
200
|
+
fileCount: uniqueFiles.length,
|
|
201
|
+
searchPath: searchPathAbsolute,
|
|
202
|
+
pattern: params.pattern,
|
|
203
|
+
strategy,
|
|
204
|
+
output_mode: outputMode,
|
|
205
|
+
offset,
|
|
206
|
+
hasMore,
|
|
207
|
+
nextOffset: hasMore ? offset + limitedMatches.length : undefined,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
else if (outputMode === 'count') {
|
|
211
|
+
// Return match counts per file
|
|
212
|
+
const countsByFile = {};
|
|
213
|
+
for (const match of limitedMatches) {
|
|
214
|
+
countsByFile[match.filePath] = (countsByFile[match.filePath] || 0) + 1;
|
|
215
|
+
}
|
|
216
|
+
const fileEntries = Object.entries(countsByFile);
|
|
217
|
+
matchCount = fileEntries.length;
|
|
218
|
+
const displayEntries = fileEntries.slice(0, GrepTool.HARD_MAX_RESULTS);
|
|
219
|
+
// Build result message with pagination guidance
|
|
220
|
+
if (offset > 0 || hasMore) {
|
|
221
|
+
const rangeStart = offset + 1;
|
|
222
|
+
const rangeEnd = offset + limitedMatches.length;
|
|
223
|
+
llmContent = `Found ${totalMatches} matches for "${params.pattern}" (showing matches ${rangeStart}-${rangeEnd})${globPattern ? ` (filter: "${globPattern}")` : ''}:\n`;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
llmContent = `Found ${totalMatches} matches in ${fileEntries.length} files for "${params.pattern}"${globPattern ? ` (filter: "${globPattern}")` : ''}:\n`;
|
|
227
|
+
}
|
|
228
|
+
for (const [file, count] of displayEntries) {
|
|
229
|
+
llmContent += `${file}: ${count}\n`;
|
|
230
|
+
}
|
|
231
|
+
if (hasMore) {
|
|
232
|
+
const nextOffset = offset + limitedMatches.length;
|
|
233
|
+
llmContent += `\n[TRUNCATED] ${remainingCount} more matches available. To see next page, call grep again with offset=${nextOffset}`;
|
|
234
|
+
}
|
|
235
|
+
if (updateOutput)
|
|
236
|
+
updateOutput(`Found ${totalMatches} matches in ${fileEntries.length} files`);
|
|
237
|
+
return this.createSuccessResult(llmContent, {
|
|
238
|
+
executionTime: Date.now() - startTime,
|
|
239
|
+
matchCount: totalMatches,
|
|
240
|
+
fileCount: fileEntries.length,
|
|
241
|
+
searchPath: searchPathAbsolute,
|
|
242
|
+
pattern: params.pattern,
|
|
243
|
+
strategy,
|
|
244
|
+
output_mode: outputMode,
|
|
245
|
+
offset,
|
|
246
|
+
hasMore,
|
|
247
|
+
nextOffset: hasMore ? offset + limitedMatches.length : undefined,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
// Default: content mode - show matching lines
|
|
251
|
+
const displayMatches = limitedMatches.slice(0, GrepTool.HARD_MAX_RESULTS);
|
|
252
|
+
const matchesByFile = this.groupMatchesByFile(displayMatches, searchDir);
|
|
253
|
+
matchCount = displayMatches.length;
|
|
254
|
+
const matchTerm = matchCount === 1 ? 'match' : 'matches';
|
|
255
|
+
// Build header with pagination info
|
|
256
|
+
if (offset > 0 || hasMore) {
|
|
257
|
+
const rangeStart = offset + 1;
|
|
258
|
+
const rangeEnd = offset + limitedMatches.length;
|
|
259
|
+
llmContent = `Found ${totalMatches} matches for "${params.pattern}" (showing ${rangeStart}-${rangeEnd}) in "${searchPathDisplay}"${globPattern ? ` (filter: "${globPattern}")` : ''} [using ${strategy}]:\n---\n`;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
llmContent = `Found ${matchCount} ${matchTerm} for "${params.pattern}" in "${searchPathDisplay}"${globPattern ? ` (filter: "${globPattern}")` : ''} [using ${strategy}]:\n---\n`;
|
|
263
|
+
}
|
|
264
|
+
let contentLength = llmContent.length;
|
|
265
|
+
let contentTruncated = false;
|
|
266
|
+
for (const filePath in matchesByFile) {
|
|
267
|
+
const fileMatches = matchesByFile[filePath];
|
|
268
|
+
if (!fileMatches)
|
|
269
|
+
continue;
|
|
270
|
+
const fileHeader = `File: ${filePath}\n`;
|
|
271
|
+
if (contentLength + fileHeader.length > GrepTool.MAX_CONTENT_LENGTH) {
|
|
272
|
+
contentTruncated = true;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
llmContent += fileHeader;
|
|
276
|
+
contentLength += fileHeader.length;
|
|
277
|
+
for (const match of fileMatches) {
|
|
278
|
+
const trimmedLine = match.line.trim();
|
|
279
|
+
const lineContent = showLineNumbers ? `L${match.lineNumber}: ${trimmedLine}\n` : `${trimmedLine}\n`;
|
|
280
|
+
if (contentLength + lineContent.length > GrepTool.MAX_CONTENT_LENGTH) {
|
|
281
|
+
contentTruncated = true;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
llmContent += lineContent;
|
|
285
|
+
contentLength += lineContent.length;
|
|
286
|
+
}
|
|
287
|
+
if (contentTruncated)
|
|
288
|
+
break;
|
|
289
|
+
llmContent += '---\n';
|
|
290
|
+
contentLength += 4;
|
|
291
|
+
}
|
|
292
|
+
// Add pagination guidance
|
|
293
|
+
if (hasMore || contentTruncated) {
|
|
294
|
+
const nextOffset = offset + limitedMatches.length;
|
|
295
|
+
llmContent += `\n[TRUNCATED] ${remainingCount} more matches available. To see next page, call grep again with offset=${nextOffset}`;
|
|
296
|
+
}
|
|
297
|
+
const returnDisplay = hasMore || offset > 0
|
|
298
|
+
? `Found ${totalMatches} matches (showing ${matchCount})`
|
|
299
|
+
: `Found ${matchCount} ${matchTerm}`;
|
|
300
|
+
if (updateOutput)
|
|
301
|
+
updateOutput(returnDisplay);
|
|
302
|
+
return this.createSuccessResult(llmContent.trim(), {
|
|
303
|
+
executionTime: Date.now() - startTime,
|
|
304
|
+
matchCount: totalMatches,
|
|
305
|
+
displayedMatches: matchCount,
|
|
306
|
+
truncated: hasMore || contentTruncated,
|
|
307
|
+
searchPath: searchPathAbsolute,
|
|
308
|
+
pattern: params.pattern,
|
|
309
|
+
strategy,
|
|
310
|
+
output_mode: outputMode,
|
|
311
|
+
offset,
|
|
312
|
+
hasMore,
|
|
313
|
+
nextOffset: hasMore ? offset + limitedMatches.length : undefined,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (error.name === 'AbortError') {
|
|
318
|
+
return this.createErrorResult('Search was aborted');
|
|
319
|
+
}
|
|
320
|
+
return this.createErrorResult(`Search failed: ${error.message}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Performs grep search using best available strategy
|
|
325
|
+
*
|
|
326
|
+
* @param pattern - Regex pattern to search for
|
|
327
|
+
* @param absolutePath - Directory to search in
|
|
328
|
+
* @param include - Glob pattern for file filtering
|
|
329
|
+
* @param caseSensitive - Whether search is case-sensitive
|
|
330
|
+
* @param signal - Abort signal for cancellation
|
|
331
|
+
* @param targetFile - Optional: specific filename to search (single-file mode)
|
|
332
|
+
* @param fileType - Optional: file type filter (rg --type)
|
|
333
|
+
* @param multiline - Optional: enable multiline matching
|
|
334
|
+
* @param contextAfter - Optional: lines after match (-A)
|
|
335
|
+
* @param contextBefore - Optional: lines before match (-B)
|
|
336
|
+
* @param contextBoth - Optional: lines of context (-C)
|
|
337
|
+
* @param maxResults - Optional: maximum results (enables -m flag for ripgrep)
|
|
338
|
+
*/
|
|
339
|
+
async performGrepSearch(pattern, absolutePath, include, caseSensitive = false, signal, targetFile, fileType, multiline, contextAfter, contextBefore, contextBoth, maxResults) {
|
|
340
|
+
// Strategy 1: ripgrep (rg) - Fastest
|
|
341
|
+
if (await this.isCommandAvailable('rg')) {
|
|
342
|
+
try {
|
|
343
|
+
const matches = await this.searchWithRipgrep(pattern, absolutePath, include, caseSensitive, targetFile, fileType, multiline, contextAfter, contextBefore, contextBoth, maxResults, signal);
|
|
344
|
+
return { matches, strategy: 'ripgrep' };
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
// If aborted, propagate the error instead of falling back
|
|
348
|
+
if (error.message?.includes('aborted') || error.message?.includes('timed out')) {
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
console.debug(`ripgrep failed: ${error.message}, falling back...`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
// Strategy 2: git grep - Fast (git repos only)
|
|
355
|
+
if (isGitRepository(absolutePath) && (await this.isCommandAvailable('git'))) {
|
|
356
|
+
try {
|
|
357
|
+
const matches = await this.searchWithGitGrep(pattern, absolutePath, include, caseSensitive, targetFile, signal);
|
|
358
|
+
return { matches, strategy: 'git grep' };
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
// If aborted, propagate the error instead of falling back
|
|
362
|
+
if (error.message?.includes('aborted') || error.message?.includes('timed out')) {
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
console.debug(`git grep failed: ${error.message}, falling back...`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// Strategy 3: system grep - Good
|
|
369
|
+
if (await this.isCommandAvailable('grep')) {
|
|
370
|
+
try {
|
|
371
|
+
const matches = await this.searchWithSystemGrep(pattern, absolutePath, include, caseSensitive, targetFile, signal);
|
|
372
|
+
return { matches, strategy: 'system grep' };
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
// If aborted, propagate the error instead of falling back
|
|
376
|
+
if (error.message?.includes('aborted') || error.message?.includes('timed out')) {
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
379
|
+
console.debug(`system grep failed: ${error.message}, falling back...`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
// Strategy 4: JavaScript fallback - Portable
|
|
383
|
+
const matches = await this.searchWithJavaScript(pattern, absolutePath, include, caseSensitive, signal, targetFile, multiline);
|
|
384
|
+
return { matches, strategy: 'javascript' };
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Strategy 1: Search with ripgrep (rg)
|
|
388
|
+
*/
|
|
389
|
+
async searchWithRipgrep(pattern, cwd, include, caseSensitive = false, targetFile, fileType, multiline, contextAfter, contextBefore, contextBoth, maxResults, signal) {
|
|
390
|
+
const args = [
|
|
391
|
+
'--line-number',
|
|
392
|
+
'--no-heading',
|
|
393
|
+
'--with-filename',
|
|
394
|
+
'--color', 'never',
|
|
395
|
+
];
|
|
396
|
+
if (!caseSensitive)
|
|
397
|
+
args.push('--ignore-case');
|
|
398
|
+
if (include)
|
|
399
|
+
args.push('--glob', include);
|
|
400
|
+
if (fileType)
|
|
401
|
+
args.push('--type', fileType);
|
|
402
|
+
if (multiline)
|
|
403
|
+
args.push('-U', '--multiline-dotall');
|
|
404
|
+
if (contextAfter)
|
|
405
|
+
args.push('-A', String(contextAfter));
|
|
406
|
+
if (contextBefore)
|
|
407
|
+
args.push('-B', String(contextBefore));
|
|
408
|
+
if (contextBoth)
|
|
409
|
+
args.push('-C', String(contextBoth));
|
|
410
|
+
// Early termination: limit results at source to save context tokens
|
|
411
|
+
if (maxResults && maxResults > 0)
|
|
412
|
+
args.push('-m', String(maxResults));
|
|
413
|
+
args.push(pattern);
|
|
414
|
+
// Single file mode: search specific file instead of directory
|
|
415
|
+
args.push(targetFile || '.');
|
|
416
|
+
const output = await this.executeCommand('rg', args, cwd, signal);
|
|
417
|
+
return this.parseGrepOutput(output, cwd);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Strategy 2: Search with git grep
|
|
421
|
+
*/
|
|
422
|
+
async searchWithGitGrep(pattern, cwd, include, caseSensitive = false, targetFile, signal) {
|
|
423
|
+
const args = [
|
|
424
|
+
'grep',
|
|
425
|
+
'--untracked',
|
|
426
|
+
'-n',
|
|
427
|
+
'-E',
|
|
428
|
+
];
|
|
429
|
+
if (!caseSensitive)
|
|
430
|
+
args.push('--ignore-case');
|
|
431
|
+
args.push(pattern);
|
|
432
|
+
// Single file mode or directory mode
|
|
433
|
+
if (targetFile) {
|
|
434
|
+
args.push('--');
|
|
435
|
+
args.push(targetFile);
|
|
436
|
+
}
|
|
437
|
+
else if (include) {
|
|
438
|
+
args.push('--');
|
|
439
|
+
args.push(include);
|
|
440
|
+
}
|
|
441
|
+
const output = await this.executeCommand('git', args, cwd, signal);
|
|
442
|
+
return this.parseGrepOutput(output, cwd);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Strategy 3: Search with system grep
|
|
446
|
+
*/
|
|
447
|
+
async searchWithSystemGrep(pattern, cwd, include, caseSensitive = false, targetFile, signal) {
|
|
448
|
+
// Single file mode: use different flags (no recursion)
|
|
449
|
+
const args = targetFile ? ['-n', '-H', '-E'] : ['-r', '-n', '-H', '-E'];
|
|
450
|
+
if (!caseSensitive)
|
|
451
|
+
args.push('--ignore-case');
|
|
452
|
+
// Only exclude directories when searching recursively
|
|
453
|
+
if (!targetFile) {
|
|
454
|
+
const excludeDirs = [
|
|
455
|
+
'.git',
|
|
456
|
+
'node_modules',
|
|
457
|
+
'bower_components',
|
|
458
|
+
'dist',
|
|
459
|
+
'build',
|
|
460
|
+
'.claude', // external coding-agent data dir
|
|
461
|
+
'.cortex', // Nexus Cortex runtime data
|
|
462
|
+
'.npm', // npm cache
|
|
463
|
+
'.pythonlibs', // Python libraries
|
|
464
|
+
'.config', // Configuration data
|
|
465
|
+
'coverage', // Test coverage
|
|
466
|
+
'.next', // Next.js build
|
|
467
|
+
'.nuxt', // Nuxt.js build
|
|
468
|
+
'.cache', // General cache
|
|
469
|
+
'tmp', // Temporary files
|
|
470
|
+
'temp', // Temporary files
|
|
471
|
+
'__pycache__', // Python cache
|
|
472
|
+
'.pytest_cache', // Pytest cache
|
|
473
|
+
'.mypy_cache', // Mypy cache
|
|
474
|
+
'vendor', // Vendor dependencies
|
|
475
|
+
'.venv', // Python virtual env
|
|
476
|
+
'venv', // Python virtual env
|
|
477
|
+
'env', // Environment
|
|
478
|
+
];
|
|
479
|
+
excludeDirs.forEach(dir => args.push(`--exclude-dir=${dir}`));
|
|
480
|
+
if (include)
|
|
481
|
+
args.push(`--include=${include}`);
|
|
482
|
+
}
|
|
483
|
+
args.push(pattern);
|
|
484
|
+
// Single file mode: search specific file instead of directory
|
|
485
|
+
args.push(targetFile || '.');
|
|
486
|
+
const output = await this.executeCommand('grep', args, cwd, signal);
|
|
487
|
+
return this.parseGrepOutput(output, cwd);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Strategy 4: Pure JavaScript fallback
|
|
491
|
+
*/
|
|
492
|
+
async searchWithJavaScript(pattern, absolutePath, include, caseSensitive = false, signal, targetFile, multiline) {
|
|
493
|
+
// Build regex flags
|
|
494
|
+
let flags = caseSensitive ? '' : 'i';
|
|
495
|
+
if (multiline)
|
|
496
|
+
flags += 'ms'; // multiline + dotAll
|
|
497
|
+
const regex = new RegExp(pattern, flags);
|
|
498
|
+
const allMatches = [];
|
|
499
|
+
// Single file mode: search only the target file
|
|
500
|
+
if (targetFile) {
|
|
501
|
+
const fileAbsolutePath = path.join(absolutePath, targetFile);
|
|
502
|
+
try {
|
|
503
|
+
const stat = await fs.stat(fileAbsolutePath);
|
|
504
|
+
if (stat.size > GrepTool.MAX_SEARCHABLE_FILE_BYTES) {
|
|
505
|
+
console.debug(`Skipping ${fileAbsolutePath}: ${stat.size} bytes exceeds search limit`);
|
|
506
|
+
return allMatches;
|
|
507
|
+
}
|
|
508
|
+
const content = await fs.readFile(fileAbsolutePath, 'utf8');
|
|
509
|
+
const lines = content.split(/\r?\n/);
|
|
510
|
+
lines.forEach((line, index) => {
|
|
511
|
+
if (regex.test(line)) {
|
|
512
|
+
allMatches.push({
|
|
513
|
+
filePath: targetFile,
|
|
514
|
+
lineNumber: index + 1,
|
|
515
|
+
line,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
catch (error) {
|
|
521
|
+
console.debug(`Could not read ${fileAbsolutePath}: ${error.message}`);
|
|
522
|
+
}
|
|
523
|
+
return allMatches;
|
|
524
|
+
}
|
|
525
|
+
// Directory mode: search all matching files
|
|
526
|
+
const globPattern = include || '**/*';
|
|
527
|
+
// Minimal exclusions - let .gitignore/.rgignore handle the rest (ripgrep respects these)
|
|
528
|
+
// This matches the approach of delegating to ripgrep defaults
|
|
529
|
+
const ignorePatterns = [
|
|
530
|
+
'.git/**', // Git internals (ripgrep excludes by default)
|
|
531
|
+
'node_modules/**', // Dependencies (usually in .gitignore but critical for performance)
|
|
532
|
+
'.claude/**', // external coding-agent data dir
|
|
533
|
+
'.cortex/**', // Nexus Cortex runtime data
|
|
534
|
+
'.grok/**', // xAI Grok CLI runtime data (upload_queue holds huge blobs)
|
|
535
|
+
];
|
|
536
|
+
const filesStream = globStream(globPattern, {
|
|
537
|
+
cwd: absolutePath,
|
|
538
|
+
dot: true,
|
|
539
|
+
ignore: ignorePatterns,
|
|
540
|
+
absolute: true,
|
|
541
|
+
nodir: true,
|
|
542
|
+
signal,
|
|
543
|
+
});
|
|
544
|
+
for await (const filePath of filesStream) {
|
|
545
|
+
const fileAbsolutePath = filePath;
|
|
546
|
+
try {
|
|
547
|
+
const stat = await fs.stat(fileAbsolutePath);
|
|
548
|
+
if (stat.size > GrepTool.MAX_SEARCHABLE_FILE_BYTES) {
|
|
549
|
+
// Skip oversized files: reading them into a string can throw
|
|
550
|
+
// "Invalid string length", and they're never useful grep targets.
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
const content = await fs.readFile(fileAbsolutePath, 'utf8');
|
|
554
|
+
const lines = content.split(/\r?\n/);
|
|
555
|
+
lines.forEach((line, index) => {
|
|
556
|
+
if (regex.test(line)) {
|
|
557
|
+
allMatches.push({
|
|
558
|
+
filePath: path.relative(absolutePath, fileAbsolutePath) ||
|
|
559
|
+
path.basename(fileAbsolutePath),
|
|
560
|
+
lineNumber: index + 1,
|
|
561
|
+
line,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
if (error.code !== 'ENOENT' && error.code !== 'EISDIR') {
|
|
568
|
+
console.debug(`Could not read ${fileAbsolutePath}: ${error.message}`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return allMatches;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Executes a command and returns stdout
|
|
576
|
+
* Supports abort signal for ESC key cancellation and timeout for runaway processes
|
|
577
|
+
*/
|
|
578
|
+
executeCommand(command, args, cwd, signal, timeoutMs = 30000) {
|
|
579
|
+
return new Promise((resolve, reject) => {
|
|
580
|
+
// Check if already aborted before spawning
|
|
581
|
+
if (signal?.aborted) {
|
|
582
|
+
reject(new Error('Search was aborted'));
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
const child = spawn(command, args, {
|
|
586
|
+
cwd,
|
|
587
|
+
windowsHide: true,
|
|
588
|
+
});
|
|
589
|
+
let killed = false;
|
|
590
|
+
let timedOut = false;
|
|
591
|
+
// Setup timeout to prevent runaway grep processes
|
|
592
|
+
const timeoutId = setTimeout(() => {
|
|
593
|
+
if (!killed) {
|
|
594
|
+
timedOut = true;
|
|
595
|
+
killed = true;
|
|
596
|
+
child.kill('SIGKILL');
|
|
597
|
+
}
|
|
598
|
+
}, timeoutMs);
|
|
599
|
+
// Setup abort signal handler for ESC key cancellation
|
|
600
|
+
const abortHandler = () => {
|
|
601
|
+
if (!killed) {
|
|
602
|
+
killed = true;
|
|
603
|
+
clearTimeout(timeoutId);
|
|
604
|
+
child.kill('SIGKILL');
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
if (signal) {
|
|
608
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
609
|
+
}
|
|
610
|
+
const stdoutChunks = [];
|
|
611
|
+
const stderrChunks = [];
|
|
612
|
+
child.stdout.on('data', (chunk) => stdoutChunks.push(chunk));
|
|
613
|
+
child.stderr.on('data', (chunk) => {
|
|
614
|
+
const str = chunk.toString();
|
|
615
|
+
// Suppress common harmless messages
|
|
616
|
+
if (!str.includes('Permission denied') && !/Is a directory/i.test(str)) {
|
|
617
|
+
stderrChunks.push(chunk);
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
child.on('error', (err) => {
|
|
621
|
+
clearTimeout(timeoutId);
|
|
622
|
+
if (signal) {
|
|
623
|
+
signal.removeEventListener('abort', abortHandler);
|
|
624
|
+
}
|
|
625
|
+
reject(new Error(`Failed to start ${command}: ${err.message}`));
|
|
626
|
+
});
|
|
627
|
+
child.on('close', (code) => {
|
|
628
|
+
clearTimeout(timeoutId);
|
|
629
|
+
if (signal) {
|
|
630
|
+
signal.removeEventListener('abort', abortHandler);
|
|
631
|
+
}
|
|
632
|
+
// Handle abort/timeout cases
|
|
633
|
+
if (signal?.aborted || killed) {
|
|
634
|
+
if (timedOut) {
|
|
635
|
+
reject(new Error(`Search timed out after ${timeoutMs / 1000} seconds`));
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
reject(new Error('Search was aborted'));
|
|
639
|
+
}
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
const stdout = Buffer.concat(stdoutChunks).toString('utf8');
|
|
643
|
+
const stderr = Buffer.concat(stderrChunks).toString('utf8').trim();
|
|
644
|
+
if (code === 0) {
|
|
645
|
+
resolve(stdout);
|
|
646
|
+
}
|
|
647
|
+
else if (code === 1) {
|
|
648
|
+
resolve(''); // No matches (not an error)
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
reject(new Error(`${command} exited with code ${code}${stderr ? `: ${stderr}` : ''}`));
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Checks if a command is available
|
|
658
|
+
*/
|
|
659
|
+
isCommandAvailable(command) {
|
|
660
|
+
return new Promise((resolve) => {
|
|
661
|
+
const checkCmd = process.platform === 'win32' ? 'where' : 'command';
|
|
662
|
+
const checkArgs = process.platform === 'win32' ? [command] : ['-v', command];
|
|
663
|
+
try {
|
|
664
|
+
const child = spawn(checkCmd, checkArgs, {
|
|
665
|
+
stdio: 'ignore',
|
|
666
|
+
shell: process.platform === 'win32',
|
|
667
|
+
});
|
|
668
|
+
child.on('close', (code) => resolve(code === 0));
|
|
669
|
+
child.on('error', () => resolve(false));
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
resolve(false);
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Parses grep-style output including context lines from -A/-B/-C flags.
|
|
678
|
+
* Match lines use colons: file:line:content
|
|
679
|
+
* Context lines use dashes: file-line-content
|
|
680
|
+
* Group separators: --
|
|
681
|
+
*/
|
|
682
|
+
parseGrepOutput(output, basePath) {
|
|
683
|
+
const results = [];
|
|
684
|
+
if (!output)
|
|
685
|
+
return results;
|
|
686
|
+
const lines = output.split(EOL);
|
|
687
|
+
for (const line of lines) {
|
|
688
|
+
if (!line.trim())
|
|
689
|
+
continue;
|
|
690
|
+
// Skip group separators between match groups
|
|
691
|
+
if (line === '--')
|
|
692
|
+
continue;
|
|
693
|
+
// Try colon-separated match line: file:linenum:content
|
|
694
|
+
const firstColon = line.indexOf(':');
|
|
695
|
+
if (firstColon > 0) {
|
|
696
|
+
const secondColon = line.indexOf(':', firstColon + 1);
|
|
697
|
+
if (secondColon > 0) {
|
|
698
|
+
const filePathRaw = line.substring(0, firstColon);
|
|
699
|
+
const lineNumberStr = line.substring(firstColon + 1, secondColon);
|
|
700
|
+
const lineNumber = parseInt(lineNumberStr, 10);
|
|
701
|
+
if (!isNaN(lineNumber)) {
|
|
702
|
+
const absoluteFilePath = path.resolve(basePath, filePathRaw);
|
|
703
|
+
const relativeFilePath = path.relative(basePath, absoluteFilePath);
|
|
704
|
+
results.push({
|
|
705
|
+
filePath: relativeFilePath || path.basename(absoluteFilePath),
|
|
706
|
+
lineNumber,
|
|
707
|
+
line: line.substring(secondColon + 1),
|
|
708
|
+
});
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
// Try dash-separated context line: file-linenum-content
|
|
714
|
+
// Context lines from ripgrep -A/-B/-C use dashes instead of colons
|
|
715
|
+
const dashMatch = line.match(/^(.+?)-(\d+)-(.*)$/);
|
|
716
|
+
if (dashMatch) {
|
|
717
|
+
const [, filePathRaw, lineNumberStr, lineContent] = dashMatch;
|
|
718
|
+
const lineNumber = parseInt(lineNumberStr, 10);
|
|
719
|
+
if (!isNaN(lineNumber) && filePathRaw) {
|
|
720
|
+
const absoluteFilePath = path.resolve(basePath, filePathRaw);
|
|
721
|
+
const relativeFilePath = path.relative(basePath, absoluteFilePath);
|
|
722
|
+
results.push({
|
|
723
|
+
filePath: relativeFilePath || path.basename(absoluteFilePath),
|
|
724
|
+
lineNumber,
|
|
725
|
+
line: lineContent ?? '',
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
return results;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Groups matches by file and sorts by line number
|
|
734
|
+
*/
|
|
735
|
+
groupMatchesByFile(matches, basePath) {
|
|
736
|
+
const matchesByFile = {};
|
|
737
|
+
for (const match of matches) {
|
|
738
|
+
const absoluteFilePath = path.resolve(basePath, match.filePath);
|
|
739
|
+
const relativeFilePath = path.relative(basePath, absoluteFilePath) || path.basename(absoluteFilePath);
|
|
740
|
+
if (!matchesByFile[relativeFilePath]) {
|
|
741
|
+
matchesByFile[relativeFilePath] = [];
|
|
742
|
+
}
|
|
743
|
+
matchesByFile[relativeFilePath].push(match);
|
|
744
|
+
}
|
|
745
|
+
for (const filePath in matchesByFile) {
|
|
746
|
+
const fileMatches = matchesByFile[filePath];
|
|
747
|
+
if (fileMatches) {
|
|
748
|
+
fileMatches.sort((a, b) => a.lineNumber - b.lineNumber);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return matchesByFile;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
//# sourceMappingURL=GrepTool.js.map
|