Skip to content

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Dec 24, 2025

#1214

Summary by CodeRabbit

  • New Features

    • Workspace file search with glob patterns, ranked results, and workspace-aware chat mentions/auto-complete.
  • Bug Fixes

    • Normalized update channel handling (stable → beta defaults and UI option).
  • Documentation

    • Added CHANGELOG.md with recent release notes.
  • Chores

    • Version bumped to 0.5.6-beta.1.
    • Added ripgrep support for faster searches.
    • Streamlined build/release pipeline and removed legacy ACP workspace & macOS x64 build target.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 24, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Removes legacy ACP workspace presenter and types; replaces search_files with glob_search using ripgrep (with JS fallback); modularizes workspace presenter (cache, security, ripgrep search, path resolution, concurrency); updates CI/CD to tag-based releases and electron-builder packaging; renames update channel from "canary" to "beta"; bumps version to 0.5.6-beta.1.

Changes

Cohort / File(s) Summary
CI/CD & Release Workflows
​.github/workflows/build.yml, ​.github/workflows/release.yml
Switch to generic build then electron-builder packaging per platform; tag-based release trigger; resolve-tag job; per-OS build jobs and artifact uploads; CHANGELOG-based release_notes and mac YAML merging.
Builder configs & scripts
electron-builder-macx64.yml, electron-builder.yml, scripts/rebrand.js, package.json
Removed mac x64 builder file and its updater call; removed macx64 include; switched publish to GitHub provider; updated build scripts and runtime install commands; bumped version to 0.5.6-beta.1 and unified runtime (0.9.18) including ripgrep.
Workspace / ACP refactor (types & presenter)
src/shared/types/presenters/*.d.ts, src/main/presenter/acpWorkspacePresenter/*, src/main/presenter/index.ts
Removed ACP workspace types and IAcpWorkspacePresenter; deleted AcpWorkspacePresenter implementation and its Presenter registration; removed acpWorkspacePresenter from public presenter surface.
Workspace presenter modularization
src/main/presenter/workspacePresenter/* (concurrencyLimiter.ts, fileCache.ts, fileSecurity.ts, pathResolver.ts, ripgrepSearcher.ts, fileSearcher.ts, workspaceFileSearch.ts, directoryReader.ts, planStateManager.ts, index.ts)
New modular utilities: concurrency limiter, in-memory file cache, security helpers, path resolver, ripgrep searcher, paginated searcher, workspace file search; renamed Acp* types to Workspace*; added registerWorkdir/unregisterWorkdir and searchFiles methods.
File search tool & agent changes
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts, .../agentToolManager.ts
Replaced search_filesglob_search; new input schema (pattern, root, excludePatterns, maxResults, sortBy); added ripgrep execution with JS fallback; results enriched with size/mtime and formatted summaries.
Runtime helper
src/main/lib/runtimeHelper.ts
Added ripgrep runtime detection and accessor (getRipgrepRuntimePath()); extended runtime command replacement to support rg resolution/substitution.
Upgrade & config presenters
src/main/presenter/upgradePresenter/index.ts, src/main/presenter/configPresenter/index.ts
Removed remote axios/compare-versions fetch; normalized update channel to `stable
Renderer: workspace mentions & UI i18n
src/renderer/src/components/chat-input/*, src/renderer/src/editor/mention/suggestion.ts, src/renderer/src/components/workspace/WorkspaceFileNode.vue, src/renderer/src/i18n/*/about.json, AboutUsSettings.vue
Added useWorkspaceMention hook and setWorkspaceMention wiring and handler type; removed ACP presenter usage in workspace node; replaced canaryChannelbetaChannel across locales and About UI.
Stores & MCP docs
src/renderer/src/stores/workspace.ts, src/renderer/src/stores/mcp.ts, docs/mcp-store-colada-integration.md, docs/workspace-agent-refactoring-summary.md, docs/rebrand-guide.md, CHANGELOG.md
Unified stores to Workspace* types and single WorkspacePresenter; MCP store/docs updated to glob_search; changelog added; rebrand guide removed macx64 entry.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Chat Client
    participant Agent as Agent Tool Manager
    participant Handler as File System Handler
    participant Ripgrep as Ripgrep Process
    participant JS as JavaScript Search
    participant Results as Search Results

    Client->>Agent: glob_search(pattern, root, excludePatterns, maxResults)
    Agent->>Handler: globSearch(args)
    
    rect rgb(220,240,250)
    Note over Handler,Ripgrep: Ripgrep runtime detection
    Handler->>Handler: Check ripgrep runtime available
    end
    
    alt Ripgrep available
        rect rgb(200,255,200)
        Note over Handler,Ripgrep: Ripgrep-based search
        Handler->>Ripgrep: spawn rg with args
        Ripgrep-->>Handler: stream JSON matches
        Handler->>Handler: parse & enrich results
        Handler->>Results: return grep results
        end
    else Ripgrep unavailable/fails
        rect rgb(255,230,200)
        Note over Handler,JS: JS fallback search
        Handler->>JS: directory walk + minimatch filter
        JS-->>Handler: matched files
        Handler->>Results: build results
        end
    end
    
    rect rgb(240,240,200)
    Note over Results: format, sort, summary
    Handler->>Results: add size/mtime, sort by name/mtime
    end
    
    Results-->>Agent: SearchResult
    Agent-->>Client: Tool result
Loading
sequenceDiagram
    participant Client as Chat Client
    participant Workspace as Workspace Presenter
    participant FileSearch as searchWorkspaceFiles
    participant Ripgrep as RipgrepSearcher
    participant Cache as FileCache
    participant Results as Results

    Client->>Workspace: searchFiles(workspacePath, query)
    
    rect rgb(220,240,250)
    Note over Workspace: Validate access
    Workspace->>Workspace: isPathAllowed(workspacePath)
    end
    
    Workspace->>FileSearch: searchWorkspaceFiles(workspacePath, query)
    
    alt Exact file match
        FileSearch->>FileSearch: resolve exact path
        FileSearch->>FileSearch: check sensitive/binary
        FileSearch-->>Workspace: return single node
    else Pattern/fuzzy
        FileSearch->>Cache: check cache for pattern
        alt Cache hit
            Cache-->>FileSearch: cached results
        else Cache miss
            FileSearch->>Ripgrep: RipgrepSearcher.files(...)
            Ripgrep-->>FileSearch: file stream
            FileSearch->>Cache: store results
        end
        FileSearch->>FileSearch: score, filter, sort
        FileSearch-->>Workspace: return nodes
    end
    
    Workspace-->>Client: searchFiles results
Loading
sequenceDiagram
    participant UI as User Interface
    participant Update as UpgradePresenter
    participant AutoUpd as electron-updater
    participant GitHub as GitHub
    participant Marker as Update Marker

    UI->>Update: checkUpdate()
    Update->>Update: normalizeUpdateChannel()
    Update->>AutoUpd: set channel & allowPrerelease
    Update->>AutoUpd: checkForUpdates()
    AutoUpd->>GitHub: query releases
    GitHub-->>AutoUpd: release metadata
    AutoUpd-->>Update: update-available
    Update->>Update: toVersionInfo() & persist _versionInfo
    Update->>UI: STATUS_CHANGED (available, lastCheckType)
    UI->>Update: startDownloadUpdate() (optional)
    AutoUpd-->>Update: update-downloaded
    Update->>Marker: writeUpdateMarker(versionInfo)
    Update->>UI: notify ready to install
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 With ripgrep paws I bound and leap,
I scour the trees so fast, not cheap.
Canary hops to Beta's crest,
ACP sleeps, the workspace rests.
New searches sing — a rabbit's cheer, code tidy, nimble, and sincere.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: filesystem with ripgrep' directly and clearly summarizes the main change: adding filesystem functionality integrated with ripgrep for file searching.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/filesystem-with-ripgrep

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

* refactor: mac build workflow

* feat: support github channels update

* fix: action error

* fix: action error

* fix: gh_token error

* fix: gh_token error

* fix: release.yml due some pack

* fix: realeas.yml workflow failed

* chore: 0.5.6-beta.1 for testing

* docs: update changelog

* docs: update changelog

* docs: update changelog

* feat(update): switch to GitHub releases auto-update
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/presenter/upgradePresenter/index.ts (2)

306-313: Fix invalid catch clause type annotation.

TypeScript only allows any or unknown as catch clause type annotations. The union type Error | unknown is invalid and will cause a parse error. This is confirmed by static analysis.

🔎 Proposed fix
-    } catch (error: Error | unknown) {
+    } catch (error: unknown) {

361-368: Fix invalid catch clause type annotation.

Same issue as line 306: Error | unknown is not valid for catch clause type annotations.

🔎 Proposed fix
-    } catch (error: Error | unknown) {
+    } catch (error: unknown) {
🧹 Nitpick comments (6)
src/main/presenter/workspacePresenter/fileCache.ts (1)

68-76: Consider tracking total cache size for memory-sensitive environments.

The current prune() only enforces maxEntries count. Since entries can vary significantly in size (up to 256KB each), total memory usage could reach ~50MB. If this cache is used in memory-constrained scenarios, consider adding total byte tracking with eviction when exceeded.

This is a minor consideration and may not be necessary for the current use case.

src/main/presenter/workspacePresenter/fileSecurity.ts (1)

3-5: Consider pattern matching precision for sensitive file detection.

The SENSITIVE_PATTERNS use substring matching, which could produce false positives. For example, a file named forgot-password-flow.md or credentials-setup.md (documentation) would be blocked.

Consider whether this is the intended behavior, or if patterns should be more specific (e.g., checking for file extensions like .pem, .key or exact filenames like credentials.json).

src/main/presenter/workspacePresenter/workspaceFileSearch.ts (1)

10-10: Incomplete glob escape pattern.

The escape pattern [\\*?\[\]] doesn't escape { and } which are also glob metacharacters used for brace expansion (e.g., {a,b,c}). This could lead to unexpected matches if user input contains braces.

🔎 Proposed fix
-const escapeGlob = (input: string) => input.replace(/[\\*?\[\]]/g, '\\$&')
+const escapeGlob = (input: string) => input.replace(/[\\*?\[\]{}]/g, '\\$&')
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts (1)

342-343: -m limits matches per file, not total matches.

The -m (max-count) flag limits matches per file, not the total number of matches across all files. If the intent is to limit total matches globally, consider post-processing the results or using --max-count-matches (if available in your ripgrep version).

The current behavior may return more matches than maxResults when searching multiple files. If strict limiting is required, truncate result.matches after aggregation.

.github/workflows/release.yml (2)

55-87: Consider reducing code duplication in tag resolution branches.

Both the dispatch and push branches contain nearly identical tag resolution logic (lines 56-73 and 75-86). This could be simplified.

🔎 Suggested refactor
-            if (isDispatch) {
-              try {
-                const { data } = await github.rest.git.getRef({
-                  owner,
-                  repo,
-                  ref: refName
-                })
-                const sha = await resolveTagSha(data)
-                core.setOutput('sha', sha)
-              } catch (error) {
-                const sha = context.sha
-                await github.rest.git.createRef({
-                  owner,
-                  repo,
-                  ref: `refs/${refName}`,
-                  sha
-                })
-                core.setOutput('sha', sha)
-              }
-            } else {
-              try {
-                const { data } = await github.rest.git.getRef({
-                  owner,
-                  repo,
-                  ref: refName
-                })
-                const sha = await resolveTagSha(data)
-                core.setOutput('sha', sha)
-              } catch (error) {
-                core.setFailed(`Tag ${tag} not found`)
-                return
-              }
-            }
+            try {
+              const { data } = await github.rest.git.getRef({
+                owner,
+                repo,
+                ref: refName
+              })
+              const sha = await resolveTagSha(data)
+              core.setOutput('sha', sha)
+            } catch (error) {
+              if (isDispatch) {
+                const sha = context.sha
+                await github.rest.git.createRef({
+                  owner,
+                  repo,
+                  ref: `refs/${refName}`,
+                  sha
+                })
+                core.setOutput('sha', sha)
+              } else {
+                core.setFailed(`Tag ${tag} not found`)
+                return
+              }
+            }

376-401: Ruby is available by default on ubuntu-latest; this is not a compatibility issue.

The merge_mac_yml function uses Ruby, which is pre-installed on GitHub's ubuntu-latest runners. No explicit setup is required for this code to work.

For improved clarity and explicit dependency documentation, consider adding a ruby/setup-ruby action step, or alternatively use yq or Python for YAML processing.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts (1)

389-399: Windows path parsing has been improved.

The previous parsing logic using regex couldn't handle Windows drive letters like C:\path\file.ts:12:content. The new implementation using lastIndexOf correctly parses such paths by finding colons from right to left, which properly handles drive letter colons in the path component.

This addresses the concern raised in the previous review about Windows colon parsing.

🧹 Nitpick comments (4)
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts (2)

369-378: Consider streaming or limiting stdout/stderr to prevent memory issues.

Accumulating all stdout and stderr in memory could cause issues with very large search results. Consider limiting buffer size or streaming results incrementally.


895-912: Log errors when file stat retrieval fails.

Lines 905-910 silently catch and skip errors when getting file stats. Per coding guidelines, errors should not be suppressed and should be logged with appropriate context for debugging.

🔎 Suggested fix with logging
       const matchesWithStats: GlobMatch[] = await Promise.all(
         filteredMatches.slice(0, maxResults).map(async (filePath) => {
           try {
             const stats = await fs.stat(filePath)
             return {
               path: filePath,
               name: path.basename(filePath),
               modified: stats.mtime,
               size: stats.size
             }
           } catch {
+            // Log warning for stat failures but continue with partial metadata
+            console.warn(`[AgentFileSystemHandler] Failed to get stats for ${filePath}`)
             return {
               path: filePath,
               name: path.basename(filePath)
             }
           }
         })
       )

As per coding guidelines, use structured logging and avoid suppressing errors.

src/main/presenter/workspacePresenter/ripgrepSearcher.ts (2)

66-76: Consider extracting pattern simplification to a helper method.

The pattern transformation logic (removing **/ and **/* prefixes) would be more testable and reusable as a separate function.

Details 🔎 Example refactoring
private static simplifyGlobPattern(pattern: string): string {
  if (pattern.startsWith('**/*')) {
    return '*' + pattern.slice(4)
  } else if (pattern.startsWith('**/')) {
    return pattern.slice(3)
  }
  return pattern
}

Then use it at line 69:

-      let simplifiedPattern = pattern
-      if (pattern.startsWith('**/*')) {
-        simplifiedPattern = '*' + pattern.slice(4) // Remove "**/" prefix
-      } else if (pattern.startsWith('**/')) {
-        simplifiedPattern = pattern.slice(3) // Remove "**/" prefix
-      }
+      const simplifiedPattern = RipgrepSearcher.simplifyGlobPattern(pattern)

115-139: Consider logging malformed JSON lines for debugging.

While the empty catch block at lines 122-123 is acceptable for skipping unparseable ripgrep output, logging these occurrences would aid troubleshooting.

Details 🔎 Suggested improvement
         let parsed: { type?: string; data?: { path?: { text?: string } | string } }
         try {
           parsed = JSON.parse(line)
         } catch {
+          // Skip malformed JSON line from ripgrep output
           continue
         }

Or with structured logging if available:

         try {
           parsed = JSON.parse(line)
-        } catch {
+        } catch (error) {
+          logger.debug('Skipped malformed ripgrep JSON output', { line: line.substring(0, 100), error })
           continue
         }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9fb59d and a53b50c.

📒 Files selected for processing (2)
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for logs and comments (Chinese text exists in legacy code, but new code should use English)

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and maintain strict TypeScript type checking for all files

**/*.{ts,tsx}: Always use try-catch to handle possible errors in TypeScript code
Provide meaningful error messages when catching errors
Log detailed error logs including error details, context, and stack traces
Distinguish and handle different error types (UserError, NetworkError, SystemError, BusinessError) with appropriate handlers in TypeScript
Use structured logging with logger.error(), logger.warn(), logger.info(), logger.debug() methods from logging utilities
Do not suppress errors (avoid empty catch blocks or silently ignoring errors)
Provide user-friendly error messages for user-facing errors in TypeScript components
Implement error retry mechanisms for transient failures in TypeScript
Avoid logging sensitive information (passwords, tokens, PII) in logs

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/presenter/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Organize core business logic into dedicated Presenter classes, with one presenter per functional domain

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use EventBus from src/main/eventbus.ts for main-to-renderer communication, broadcasting events via mainWindow.webContents.send()

src/main/**/*.ts: Use EventBus pattern for inter-process communication within the main process to decouple modules
Use Electron's built-in APIs for file system and native dialogs instead of Node.js or custom implementations

src/main/**/*.ts: Electron main process code belongs in src/main/ with presenters in presenter/ (Window/Tab/Thread/Mcp/Config/LLMProvider) and eventbus.ts for app events
Use the Presenter pattern in the main process for UI coordination

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Do not include AI co-authoring information (e.g., 'Co-Authored-By: Claude') in git commits

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
**/*.{js,ts,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)

Write logs and comments in English

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
{src/main/presenter/**/*.ts,src/renderer/**/*.ts}

📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)

Implement proper inter-process communication (IPC) patterns using Electron's ipcRenderer and ipcMain APIs

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

New features should be developed in the src directory

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Main process code for Electron should be placed in src/main

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.{ts,tsx,vue,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier with single quotes, no semicolons, and 100 character width

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use OxLint for linting JavaScript and TypeScript files

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Use camelCase for variable and function names in TypeScript files
Use PascalCase for type and class names in TypeScript
Use SCREAMING_SNAKE_CASE for constant names

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use EventBus for inter-process communication events

Files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/presenter/llmProviderPresenter/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm-agent-loop.mdc)

Define the standardized LLMCoreStreamEvent interface with fields: type (text | reasoning | tool_call_start | tool_call_chunk | tool_call_end | error | usage | stop | image_data), content (for text), reasoning_content (for reasoning), tool_call_id, tool_call_name, tool_call_arguments_chunk (for streaming), tool_call_arguments_complete (for complete arguments), error_message, usage object with token counts, stop_reason (tool_use | max_tokens | stop_sequence | error | complete), and image_data object with Base64-encoded data and mimeType

Files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
🧠 Learnings (4)
📚 Learning: 2025-11-25T05:26:35.317Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-11-25T05:26:35.317Z
Learning: Applies to **/*.{ts,tsx} : Do not suppress errors (avoid empty catch blocks or silently ignoring errors)

Applied to files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
📚 Learning: 2025-11-25T05:26:35.317Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-11-25T05:26:35.317Z
Learning: Applies to **/*.{ts,tsx} : Always use try-catch to handle possible errors in TypeScript code

Applied to files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
📚 Learning: 2025-11-25T05:26:35.317Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-11-25T05:26:35.317Z
Learning: Applies to **/*.{ts,tsx} : Implement error retry mechanisms for transient failures in TypeScript

Applied to files:

  • src/main/presenter/workspacePresenter/ripgrepSearcher.ts
📚 Learning: 2025-11-25T05:27:12.209Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-11-25T05:27:12.209Z
Learning: Implement separation of concerns where `src/main/presenter/llmProviderPresenter/index.ts` manages the Agent loop and conversation history, while Provider files handle LLM API interactions, Provider-specific request/response formatting, tool definition conversion, and native vs non-native tool call mechanisms

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
🧬 Code graph analysis (1)
src/main/presenter/workspacePresenter/ripgrepSearcher.ts (1)
src/main/lib/runtimeHelper.ts (1)
  • RuntimeHelper (9-416)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (6)
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts (2)

430-549: LGTM on the JavaScript grep fallback implementation.

The refactored JS implementation correctly handles file traversal, pattern matching with minimatch, and context lines. Silent error handling at lines 505-507 and 531-533 is appropriate for search operations where you want to skip inaccessible files rather than fail the entire search.


254-256: This code is safe and does not have a race condition. RuntimeHelper.initializeRuntimes() is a synchronous method (returns void) that uses only fs.existsSync() calls for filesystem checks. It completes before getRipgrepRuntimePath() is called on the next line, so ripgrep availability is correctly determined.

Likely an incorrect or invalid review comment.

src/main/presenter/workspacePresenter/ripgrepSearcher.ts (4)

37-43: LGTM! Runtime initialization follows singleton pattern correctly.

The ripgrep executable resolution properly handles both bundled runtime and system fallback, with correct platform-specific path handling for Windows vs. Unix systems.


45-48: LGTM! Excellent use of Set for deduplication and sensible thread limiting.

The options processing correctly merges user-provided exclusions with defaults and caps worker threads at a reasonable maximum.


50-85: LGTM! Ripgrep arguments are correctly configured for file listing mode.

The args array has been corrected since the previous review—the ineffective --binary flag has been removed. The current configuration with --files, --json, thread limits, and glob-based filtering is appropriate.


140-156: LGTM! Error handling correctly refactored to avoid unsafe throws in finally block.

The finally block has been properly restructured to capture errors in variables (runError, exitError, exitCode) and defer throwing until after cleanup completes. This resolves the static analysis warning from the previous review.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/shared/regexValidator.ts (1)

48-52: Format error message consistently.

When the error object is interpolated directly in the string template at line 51, it may produce output like [object Object] rather than a meaningful message.

🔎 Proposed fix
   } catch (error) {
-    throw new Error(`Invalid glob pattern: ${pattern}. Error: ${error}`)
+    throw new Error(`Invalid glob pattern: ${pattern}. Error: ${error instanceof Error ? error.message : String(error)}`)
   }
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts (3)

398-408: Ripgrep output parsing has improved but may still have edge cases.

The parsing logic has been updated from the regex-based approach mentioned in past reviews to use lastIndexOf working backwards, which should handle Windows drive letters correctly. For C:\path\file.ts:12:content, this correctly extracts the file path by finding the last two colons.

However, line 406 validates that lineNum matches /^\d+$/, which is good, but there's no validation that the extraction succeeded properly. If a line doesn't match the expected format, the continue on line 407 skips it silently.

Consider adding debug logging for skipped lines to aid troubleshooting:

🔎 Suggested improvement
               const lineNum = line.slice(lineNumberSeparator + 1, lastColonIndex)
               const content = line.slice(lastColonIndex + 1)
               if (!/^\d+$/.test(lineNum)) {
+                logger.debug('[AgentFileSystemHandler] Skipping malformed ripgrep line', { line })
                 continue
               }

Based on learnings, use structured logging for better observability.


372-377: Use SIGTERM instead of SIGKILL for more graceful shutdown.

The timeout uses SIGKILL which forcefully terminates the process without allowing cleanup. SIGTERM allows the process to shut down gracefully.

🔎 Proposed fix
       const timeout = setTimeout(() => {
         if (settled) return
         settled = true
-        ripgrep.kill('SIGKILL')
+        ripgrep.kill('SIGTERM')
         reject(new Error('Ripgrep search timed out after 30000ms'))
       }, 30_000)

888-888: Consider documenting the maxResults buffer rationale.

The code adds 100 extra results (maxResults + 100) to account for filtering, but the magic number 100 isn't explained. This could be insufficient for cases with many excluded paths or beneficial to document.

🔎 Suggested improvement
       maxResults: maxResults + 100 // Get extra results for filtering
+      // Buffer accounts for files that may be filtered out by validatePath
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a53b50c and c671204.

📒 Files selected for processing (2)
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
  • src/shared/regexValidator.ts
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for logs and comments (Chinese text exists in legacy code, but new code should use English)

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and maintain strict TypeScript type checking for all files

**/*.{ts,tsx}: Always use try-catch to handle possible errors in TypeScript code
Provide meaningful error messages when catching errors
Log detailed error logs including error details, context, and stack traces
Distinguish and handle different error types (UserError, NetworkError, SystemError, BusinessError) with appropriate handlers in TypeScript
Use structured logging with logger.error(), logger.warn(), logger.info(), logger.debug() methods from logging utilities
Do not suppress errors (avoid empty catch blocks or silently ignoring errors)
Provide user-friendly error messages for user-facing errors in TypeScript components
Implement error retry mechanisms for transient failures in TypeScript
Avoid logging sensitive information (passwords, tokens, PII) in logs

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Do not include AI co-authoring information (e.g., 'Co-Authored-By: Claude') in git commits

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
**/*.{js,ts,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)

Write logs and comments in English

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

New features should be developed in the src directory

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/shared/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Shared type definitions and utilities between main and renderer processes should be placed in src/shared

Files:

  • src/shared/regexValidator.ts
src/shared/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Shared types and utilities should be placed in src/shared/

Files:

  • src/shared/regexValidator.ts
src/**/*.{ts,tsx,vue,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Prettier with single quotes, no semicolons, and 100 character width

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use OxLint for linting JavaScript and TypeScript files

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Use camelCase for variable and function names in TypeScript files
Use PascalCase for type and class names in TypeScript
Use SCREAMING_SNAKE_CASE for constant names

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use EventBus for inter-process communication events

Files:

  • src/shared/regexValidator.ts
  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/presenter/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Organize core business logic into dedicated Presenter classes, with one presenter per functional domain

Files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use EventBus from src/main/eventbus.ts for main-to-renderer communication, broadcasting events via mainWindow.webContents.send()

src/main/**/*.ts: Use EventBus pattern for inter-process communication within the main process to decouple modules
Use Electron's built-in APIs for file system and native dialogs instead of Node.js or custom implementations

src/main/**/*.ts: Electron main process code belongs in src/main/ with presenters in presenter/ (Window/Tab/Thread/Mcp/Config/LLMProvider) and eventbus.ts for app events
Use the Presenter pattern in the main process for UI coordination

Files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
{src/main/presenter/**/*.ts,src/renderer/**/*.ts}

📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)

Implement proper inter-process communication (IPC) patterns using Electron's ipcRenderer and ipcMain APIs

Files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/presenter/llmProviderPresenter/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm-agent-loop.mdc)

Define the standardized LLMCoreStreamEvent interface with fields: type (text | reasoning | tool_call_start | tool_call_chunk | tool_call_end | error | usage | stop | image_data), content (for text), reasoning_content (for reasoning), tool_call_id, tool_call_name, tool_call_arguments_chunk (for streaming), tool_call_arguments_complete (for complete arguments), error_message, usage object with token counts, stop_reason (tool_use | max_tokens | stop_sequence | error | complete), and image_data object with Base64-encoded data and mimeType

Files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
src/main/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Main process code for Electron should be placed in src/main

Files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
🧠 Learnings (6)
📚 Learning: 2025-11-25T05:27:12.209Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-11-25T05:27:12.209Z
Learning: Implement separation of concerns where `src/main/presenter/llmProviderPresenter/index.ts` manages the Agent loop and conversation history, while Provider files handle LLM API interactions, Provider-specific request/response formatting, tool definition conversion, and native vs non-native tool call mechanisms

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
📚 Learning: 2025-11-25T05:26:35.317Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-11-25T05:26:35.317Z
Learning: Applies to **/*.{ts,tsx} : Use structured logging with logger.error(), logger.warn(), logger.info(), logger.debug() methods from logging utilities

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
📚 Learning: 2025-11-25T05:26:35.317Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-11-25T05:26:35.317Z
Learning: Applies to **/*.{ts,tsx} : Avoid logging sensitive information (passwords, tokens, PII) in logs

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
📚 Learning: 2025-11-25T05:27:39.200Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/provider-guidelines.mdc:0-0
Timestamp: 2025-11-25T05:27:39.200Z
Learning: Applies to **/*Provider**/index.ts : Error handling: use `error` event uniformly to carry error messages, avoid mixing errors into other event fields

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
📚 Learning: 2025-11-25T05:26:11.312Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T05:26:11.312Z
Learning: Applies to **/*.{ts,tsx,js,jsx,vue} : Use English for logs and comments (Chinese text exists in legacy code, but new code should use English)

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
📚 Learning: 2025-11-25T05:26:35.317Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-11-25T05:26:35.317Z
Learning: Applies to **/*.{ts,tsx} : Implement error retry mechanisms for transient failures in TypeScript

Applied to files:

  • src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (4)
src/main/presenter/llmProviderPresenter/agent/agentFileSystemHandler.ts (4)

867-867: Glob pattern validation successfully implemented.

The validateGlobPattern call addresses the security concern raised in past reviews about ReDoS attacks on unchecked glob patterns. This validation occurs before any file system operations.


271-273: Structured logging correctly implemented.

The code now uses logger.warn() with structured error context instead of console.warn(), which aligns with the coding guidelines for better observability and consistent log levels.

As per coding guidelines, structured logging improves observability.


254-285: Well-designed fallback architecture for ripgrep integration.

The implementation correctly attempts ripgrep first and gracefully falls back to the JavaScript implementation if ripgrep is unavailable or fails. This provides robustness across different deployment environments while maintaining the performance benefit of native tooling when available.


255-257: No changes needed. initializeRuntimes() is synchronous and idempotent by design, returning immediately on subsequent calls. The filesystem checks are lightweight operations performed only once at runtime startup. The current pattern is appropriate and requires no modification.

@zerob13 zerob13 merged commit 8152762 into dev Dec 24, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants