Skip to content

Conversation

@dsarno
Copy link
Owner

@dsarno dsarno commented Dec 10, 2025

Note

Adds a new find_in_file regex search tool, updates workflows (stderr-only logging, Haiku primary with Sonnet fallback, repo-stats gating), and broadens NL/T fragment ID parsing; minor base64 decode guard and cleanup.

  • Server/Tools
    • New: Server/src/services/tools/find_in_file.py — regex search in files with line/position excerpts; supports unity://, file://, and plain paths.
    • Fix: manage_script.apply_text_edits only decodes contents when both contentsEncoded and encodedContents are present.
  • CI/Workflows
    • MCP runner: redirect only stderr to log to preserve stdout for MCP (.claude/run-unity-mcp.sh).
    • Models: switch primary to claude-haiku-4-5-20251001 with fallback claude-sonnet-4-5-20250929 in NL/T passes.
    • Parsing: relax report filename regex to accept dashed/non-dashed IDs (NL-?(\d+), T-?([A-J])).
    • Repo stats: gate job to main repo (github.repository == 'CoplayDev/unity-mcp').
  • Cleanup
    • Remove obsolete TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta.

Written by Cursor Bugbot for commit 03f5cc7. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Added a file-search tool that finds regex matches with configurable case sensitivity and result limits, returning line excerpts and positions.
  • Bug Fixes

    • NL/T identifier parsing now accepts dashed and non-dashed formats.
    • Improved decoding behavior to avoid spurious content decoding.
  • Chores

    • Workflows updated with model changes and fallbacks; MCP startup logging/stream behavior adjusted.
    • Removed obsolete Unity editor metadata file.
  • Chores

    • GitHub Actions job gated to run only for the main repository.

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

@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 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

Updated Claude NL/T workflow model settings and removed the MCP --status-dir argument; changed generated MCP run-script so STDERR appends to the log while STDOUT remains for MCP communication; added a Unity-integrated file search tool find_in_file; removed an obsolete Unity Editor metadata file; added a CI job guard.

Changes

Cohort / File(s) Summary
Workflow & MCP config
.github/workflows/claude-nl-suite.yml, .claude/.../mcp.json
NL and T passes updated to claude-haiku-4-5-20251001 with fallback_model: claude-sonnet-4-5-20250929. Removed --status-dir from unity.args in generated MCP config.
MCP run script redirection
.claude/.../run* (generated)
Changed exec redirection so MCP command runs on STDOUT and STDERR is appended to the log (e.g., exec {uv_cmd} "$@" 2>> "$LOG").
New tool implementation
Server/src/services/tools/find_in_file.py
Added find_in_file(ctx, uri, pattern, ...) and helper _split_uri(uri); reads files via Unity manage_script (supports unity://, file://, plain paths, base64 fallback), compiles regex with optional ignore-case, returns up to max_results with 1‑based line numbers, excerpts, indices, and structured success/error responses.
Manage script decoding tweak
Server/src/services/tools/manage_script.py
Tightened condition for decoding encodedContents only when raw contents is falsy and contentsEncoded/encodedContents are present.
Metadata removal
TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta
Deleted Unity Editor import metadata file.
CI guard
.github/workflows/github-repo-stats.yml
Added if: github.repository == 'CoplayDev/unity-mcp' to gate job j1.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Caller
    participant FindTool as find_in_file
    participant URI as _split_uri
    participant Unity as Unity (manage_script)
    participant Regex as Regex Engine

    Caller->>FindTool: find_in_file(ctx, uri, pattern, ...)
    FindTool->>URI: _split_uri(uri)
    URI-->>FindTool: (name, directory)

    FindTool->>Unity: read file (name, path)
    Unity-->>FindTool: file contents (raw or base64)

    alt Read success
        FindTool->>Regex: compile(pattern, flags)
        Regex-->>FindTool: compiled_regex
        FindTool->>Regex: finditer(content)
        Regex-->>FindTool: match objects
        loop per match (<= max_results)
            FindTool->>FindTool: compute line number, excerpt, indices
        end
        FindTool-->>Caller: { success: true, data: {matches, count, total_matches} }
    else Read failure
        FindTool-->>Caller: { success: false, error }
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Review Server/src/services/tools/find_in_file.py for URI parsing edge cases (UNC, percent-decoding), base64 handling, regex flag behavior, and correct line/excerpt indexing.
  • Verify manage_script.py decoding condition change doesn't break other callers expecting content decoding.
  • Check generated .claude/.../mcp.json and run-script redirection to ensure MCP STDOUT remains unchanged and STDERR is logged.
  • Confirm workflow model/fallback updates in .github/workflows/claude-nl-suite.yml and CI guard condition in github-repo-stats.yml.

Possibly related PRs

Poem

🐇 I hopped through paths both file and scheme,
I sniffed the bytes and matched each gleam.
Haiku models hum while status flags fall,
I fetched each line and answered the call.
A rabbit's nibble — new tools for all.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Unity tests fork backup' is vague and does not accurately describe the actual changes, which include a new find_in_file tool, CI/workflow updates, model changes, and identifier parsing improvements. Use a more descriptive title that captures the main changes, such as 'Add find_in_file tool and update CI workflows with model optimization' or 'Add regex file search tool and update CI/model configuration'.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 unity-tests-fork-backup

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.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on January 7

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link

@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: 1

🧹 Nitpick comments (2)
Server/src/services/tools/find_in_file.py (2)

72-72: Remove or implement the unused project_root parameter.

The project_root parameter is declared but never used in the function body. If it's not needed for current or planned functionality, consider removing it to simplify the API.


99-104: Catch specific exceptions instead of bare except.

The bare except clause catches all exceptions including system exits. Specify the expected exception types (e.g., except (ValueError, TypeError, base64.Error)).

Apply this diff:

-    except Exception:
+    except (ValueError, TypeError, base64.Error):
         contents = contents or ""
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fbc0d2 and fc2013b.

📒 Files selected for processing (3)
  • .github/workflows/claude-nl-suite.yml (2 hunks)
  • Server/src/services/tools/find_in_file.py (1 hunks)
  • TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta (0 hunks)
💤 Files with no reviewable changes (1)
  • TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-29T21:31:02.469Z
Learnt from: dsarno
Repo: dsarno/unity-mcp PR: 56
File: .claude/prompts/nl-unity-suite-full.md:5-6
Timestamp: 2025-08-29T21:31:02.469Z
Learning: The Claude NL suite workflows (.github/workflows/claude-nl-suite.yml and .github/workflows/claude-nl-suite-mini.yml) allow "Bash" tools generally, including printf and echo operations, so prompts that reference Bash(printf:*) and Bash(echo:*) are consistent with the actual workflow permissions.

Applied to files:

  • .github/workflows/claude-nl-suite.yml
🪛 Ruff (0.14.8)
Server/src/services/tools/find_in_file.py

72-72: Unused function argument: project_root

(ARG001)


103-103: Do not catch blind exception: Exception

(BLE001)


123-123: Local variable matches is assigned to but never used

Remove assignment to unused variable matches

(F841)


124-124: Local variable lines is assigned to but never used

Remove assignment to unused variable lines

(F841)

⏰ 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). (2)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: nl-suite
🔇 Additional comments (8)
Server/src/services/tools/find_in_file.py (5)

1-13: LGTM!

The imports are well-organized and appropriate for the file search functionality.


15-64: LGTM!

The URI parsing logic correctly handles multiple URI formats (unity://, file://, plain paths) with proper normalization for Windows drive letters, UNC paths, and Assets-relative path derivation.


109-121: LGTM!

The regex compilation with error handling and flexible ignore_case parameter handling (supporting both boolean and string inputs) is well-implemented.


139-175: LGTM!

The regex matching logic correctly:

  • Searches the entire file content
  • Calculates line numbers by counting newlines
  • Extracts line excerpts using efficient string operations
  • Respects the max_results limit
  • Returns structured match information with line, content, match text, and indices

177-184: LGTM!

The return structure clearly distinguishes between count (number of results returned, capped by max_results) and total_matches (total matches found), allowing callers to detect truncation.

.github/workflows/claude-nl-suite.yml (3)

446-447: LGTM!

The updated redirect strategy correctly separates MCP communication (stdout) from logging (stderr), which is essential for stdio-based MCP transport.


647-648: LGTM!

The model configuration now uses Claude Haiku as primary with Sonnet fallback, optimizing for speed while maintaining reliability. This is a sensible cost/performance trade-off for the NL pass.


681-682: LGTM!

Consistent with the NL pass, the T pass now uses Claude Haiku with Sonnet fallback, maintaining a uniform model strategy across both test stages.

@greptile-apps
Copy link

greptile-apps bot commented Dec 10, 2025

Greptile Overview

Greptile Summary

Adds regex-based find_in_file MCP tool and optimizes CI workflow configuration.

Major changes:

  • New find_in_file tool enables regex pattern search within Unity project files with configurable options (case sensitivity, result limits)
  • Workflow optimizations: removed redundant --status-dir CLI arg (now uses env var), redirected only stderr to logs (keeps stdout clean for MCP stdio), switched to Haiku model with Sonnet fallback for improved performance
  • Cleaned up obsolete Unity metadata file

Issues found:

  • find_in_file.py contains unused matches variable (line 123) and dead get_line_number helper function (lines 127-133)
  • Unused project_root parameter in find_in_file function signature (line 72)

Confidence Score: 4/5

  • Safe to merge with minor cleanup recommended
  • The PR implements functional improvements (new search tool, workflow optimizations) with sound logic that follows established codebase patterns. The only issues are cosmetic: unused code/parameters that don't affect functionality. No bugs, security issues, or breaking changes detected.
  • Server/src/services/tools/find_in_file.py could benefit from cleanup of unused code, but no critical issues

Important Files Changed

File Analysis

Filename Score Overview
Server/src/services/tools/find_in_file.py 3/5 New regex-based file search tool with URI normalization; has unused code and parameter but logic is functional
.github/workflows/claude-nl-suite.yml 5/5 Optimized MCP config (removed redundant --status-dir arg), improved logging (stderr only), switched to Haiku with Sonnet fallback
TestProjects/UnityMCPTests/Assets/Scripts/Editor.meta 5/5 Removed obsolete Unity metadata file

Sequence Diagram

sequenceDiagram
    participant Client as MCP Client
    participant Tool as find_in_file Tool
    participant URI as _split_uri Helper
    participant Unity as Unity Instance
    participant Regex as Regex Engine

    Client->>Tool: find_in_file(uri, pattern, options)
    Tool->>URI: _split_uri(uri)
    
    alt unity://path/Assets/...
        URI->>URI: Extract Assets-relative path
    else file://...
        URI->>URI: URL decode & normalize
        URI->>URI: Find Assets segment
    else plain path
        URI->>URI: Normalize separators
        URI->>URI: Find Assets segment
    end
    
    URI-->>Tool: (name, directory)
    
    Tool->>Unity: manage_script(action=read, name, path)
    Unity-->>Tool: {success, data: {contents or contentsEncoded}}
    
    alt contentsEncoded=true
        Tool->>Tool: Base64 decode encodedContents
    end
    
    Tool->>Regex: compile(pattern, flags)
    
    alt Invalid regex
        Regex-->>Tool: re.error
        Tool-->>Client: {success: false, message}
    end
    
    Regex->>Regex: finditer(contents)
    
    loop For each match (up to max_results)
        Regex->>Tool: Match object
        Tool->>Tool: Calculate line number
        Tool->>Tool: Extract line content
        Tool->>Tool: Append to results
    end
    
    Tool-->>Client: {success: true, data: {matches, count, total_matches}}
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 123 to 133
matches = []
lines = contents.splitlines()

# Helper to map index to line number
def get_line_number(index, content_lines):
# This is a bit slow for large files if we do it for every match,
# but robust.
# Better: iterate matches and count newlines?
# Or just search line by line?
# Searching line by line is safer for line-based results, but regex might span lines.
pass
Copy link

Choose a reason for hiding this comment

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

style: Unused matches list and dead code in get_line_number function - should be removed

Suggested change
matches = []
lines = contents.splitlines()
# Helper to map index to line number
def get_line_number(index, content_lines):
# This is a bit slow for large files if we do it for every match,
# but robust.
# Better: iterate matches and count newlines?
# Or just search line by line?
# Searching line by line is safer for line-based results, but regex might span lines.
pass
# Search the whole content and map back to lines
Prompt To Fix With AI
This is a comment left during a code review.
Path: Server/src/services/tools/find_in_file.py
Line: 123:133

Comment:
**style:** Unused `matches` list and dead code in `get_line_number` function - should be removed

```suggestion
    # Search the whole content and map back to lines
```

How can I resolve this? If you propose a fix, please make it concise.

ctx: Context,
uri: Annotated[str, "The resource URI to search under Assets/ or file path form supported by read_resource"],
pattern: Annotated[str, "The regex pattern to search for"],
project_root: Annotated[str | None, "Optional project root path"] = None,
Copy link

Choose a reason for hiding this comment

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

style: project_root parameter is defined but never used in the function

Prompt To Fix With AI
This is a comment left during a code review.
Path: Server/src/services/tools/find_in_file.py
Line: 72:72

Comment:
**style:** `project_root` parameter is defined but never used in the function

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 99 to 104
if not contents and data.get("contentsEncoded"):
try:
contents = base64.b64decode(data.get("encodedContents", "").encode(
"utf-8")).decode("utf-8", "replace")
except Exception:
contents = contents or ""
Copy link

Choose a reason for hiding this comment

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

logic: Logic checks contentsEncoded but decodes from encodedContents - field name mismatch will cause decoding to fail

Suggested change
if not contents and data.get("contentsEncoded"):
try:
contents = base64.b64decode(data.get("encodedContents", "").encode(
"utf-8")).decode("utf-8", "replace")
except Exception:
contents = contents or ""
if not contents and data.get("contentsEncoded"):
try:
contents = base64.b64decode(data.get("contentsEncoded", "").encode(
"utf-8")).decode("utf-8", "replace")
except Exception:
contents = contents or ""
Prompt To Fix With AI
This is a comment left during a code review.
Path: Server/src/services/tools/find_in_file.py
Line: 99:104

Comment:
**logic:** Logic checks `contentsEncoded` but decodes from `encodedContents` - field name mismatch will cause decoding to fail

```suggestion
    if not contents and data.get("contentsEncoded"):
        try:
            contents = base64.b64decode(data.get("contentsEncoded", "").encode(
                "utf-8")).decode("utf-8", "replace")
        except Exception:
            contents = contents or ""
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@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

♻️ Duplicate comments (1)
Server/src/services/tools/find_in_file.py (1)

98-105: Fix fallback decoding for base64-encoded contents (contentsEncoded vs encodedContents).

The guard checks data.get("contentsEncoded") but the decode uses encodedContents, so valid encoded content will be ignored and you’ll end up searching an empty string or erroring despite a successful read.

Align the keys and support either spelling:

-    contents = data.get("contents")
-    if not contents and data.get("contentsEncoded"):
-        try:
-            contents = base64.b64decode(data.get("encodedContents", "").encode(
-                "utf-8")).decode("utf-8", "replace")
-        except (ValueError, TypeError, base64.binascii.Error):
-            contents = contents or ""
+    contents = data.get("contents")
+    if not contents:
+        encoded = data.get("contentsEncoded") or data.get("encodedContents")
+        if encoded:
+            try:
+                contents = base64.b64decode(encoded.encode("utf-8")).decode(
+                    "utf-8", "replace"
+                )
+            except (ValueError, TypeError, base64.binascii.Error):
+                contents = contents or ""

This way you correctly use the encoded payload regardless of which field name Unity returns.

🧹 Nitpick comments (3)
Server/src/services/tools/find_in_file.py (1)

72-77: Unused project_root parameter (stylistic only).

project_root is unused and Ruff flags it (ARG001). Since you’re keeping it for interface consistency, consider renaming to _project_root (or using it in _split_uri logic later) to quiet linters without changing the public API.

.github/workflows/claude-nl-suite.yml (2)

439-448: Stderr-only redirect is correct; consider quoting uv_cmd for safety.

Redirecting only stderr to the debug log while leaving stdout for MCP framing is exactly what you want here. To be robust against paths with spaces, you might quote the command:

-              exec {uv_cmd} "$@" 2>> "$LOG"
+              exec "{uv_cmd}" "$@" 2>> "$LOG"

817-825: Unify NL/T filename regexes across helpers (allowing optional dash everywhere).

id_from_filename in the canonicalization and backfill steps now accept both NL0_results.xml/T A and NL-0_results.xml/T-A_results.xml, but the JUnit assembly id_from_filename still only matches the non-dashed form. That means dashed filenames rely on the system-out fallback instead of the filename, which is a bit fragile.

Recommend making the JUnit helper match the same forms:

-          def id_from_filename(p: Path):
-              n = p.name
-              m = re.match(r'NL(\d+)_results\.xml$', n, re.I)
-              if m:
-                  return f"NL-{int(m.group(1))}"
-              m = re.match(r'T([A-J])_results\.xml$', n, re.I)
-              if m:
-                  return f"T-{m.group(1).upper()}"
-              return None
+          def id_from_filename(p: Path):
+              n = p.name
+              m = re.match(r'NL-?(\d+)_results\.xml$', n, re.I)
+              if m:
+                  return f"NL-{int(m.group(1))}"
+              m = re.match(r'T-?([A-J])_results\.xml$', n, re.I)
+              if m:
+                  return f"T-{m.group(1).upper()}"
+              return None

or, longer term, factor a single shared helper so these patterns can’t diverge.

Also applies to: 866-872, 941-949

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc2013b and 0e20067.

📒 Files selected for processing (2)
  • .github/workflows/claude-nl-suite.yml (4 hunks)
  • Server/src/services/tools/find_in_file.py (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-29T21:31:02.469Z
Learnt from: dsarno
Repo: dsarno/unity-mcp PR: 56
File: .claude/prompts/nl-unity-suite-full.md:5-6
Timestamp: 2025-08-29T21:31:02.469Z
Learning: The Claude NL suite workflows (.github/workflows/claude-nl-suite.yml and .github/workflows/claude-nl-suite-mini.yml) allow "Bash" tools generally, including printf and echo operations, so prompts that reference Bash(printf:*) and Bash(echo:*) are consistent with the actual workflow permissions.

Applied to files:

  • .github/workflows/claude-nl-suite.yml
🪛 Ruff (0.14.8)
Server/src/services/tools/find_in_file.py

72-72: Unused function argument: project_root

(ARG001)

⏰ 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: Cursor Bugbot
🔇 Additional comments (2)
Server/src/services/tools/find_in_file.py (1)

110-173: Regex search and line/excerpt mapping look correct.

Flags handling (including stringy ignore_case), finditer usage, newline-based line calculation, and max_results capping all look sound and should produce stable line numbers and excerpts even for multiline patterns.

.github/workflows/claude-nl-suite.yml (1)

647-648: Model IDs are valid; no action needed.

The model IDs are legitimate Anthropic Claude 4.5 snapshots:

  • claude-haiku-4-5-20251001 (Haiku 4.5, Oct 1, 2025 snapshot)
  • claude-sonnet-4-5-20250929 (Sonnet 4.5, Sep 29, 2025 snapshot)

Both are supported by anthropics/claude-code-base-action@beta, which accepts any valid Anthropic model ID. The setup using Haiku with Sonnet fallback is sound.

contents = contents or ""

if contents is None:
return {"success": False, "message": "Could not read file content."}
Copy link

Choose a reason for hiding this comment

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

Bug: Base64 decode failure silently returns empty results

When base64 decoding fails, the exception handler sets contents = contents or "", resulting in an empty string. The subsequent check if contents is None: doesn't catch this case since "" is not None. This causes the function to silently return success with zero matches instead of reporting a decode error. If contents was originally None and contentsEncoded is true but decoding fails, users get a false positive "no matches found" response rather than an error message.

Fix in Cursor Fix in Web

Copy link

@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

♻️ Duplicate comments (1)
Server/src/services/tools/find_in_file.py (1)

100-108: Base64 decode failure silently returns empty results instead of error.

If contents is None initially and decoding fails, line 105 sets contents = "". The check at line 107 (if contents is None) won't catch this, causing the function to proceed with empty content and return zero matches—a false positive instead of an error.

     if not contents and data.get("contentsEncoded") and data.get("encodedContents"):
         try:
             contents = base64.b64decode(data.get("encodedContents", "").encode(
                 "utf-8")).decode("utf-8", "replace")
-        except (ValueError, TypeError, base64.binascii.Error):
-            contents = contents or ""
-    
-    if contents is None:
-        return {"success": False, "message": "Could not read file content."}
+        except (ValueError, TypeError, base64.binascii.Error) as e:
+            return {"success": False, "message": f"Failed to decode file content: {e}"}
+
+    if not contents and contents != "":
+        return {"success": False, "message": "Could not read file content."}

Alternatively, if empty files are valid and should return zero matches, keep the original flow but ensure the decode error is explicitly reported.

🧹 Nitpick comments (2)
Server/src/services/tools/find_in_file.py (2)

15-64: Extract _split_uri to a shared module to avoid duplication.

This function is duplicated verbatim from manage_script.py. Extract it to a shared utility module (e.g., services/tools/uri_utils.py) and import it in both files.

# services/tools/uri_utils.py
from urllib.parse import unquote, urlparse
import os

def split_uri(uri: str) -> tuple[str, str]:
    """Split an incoming URI or path into (name, directory) suitable for Unity."""
    # ... existing implementation ...

Then in both files:

from services.tools.uri_utils import split_uri

72-76: Prefix unused parameter with underscore to silence linter.

The parameter is intentionally kept for interface consistency (as documented at line 76), but should be prefixed to signal it's unused.

-    project_root: Annotated[str | None, "Optional project root path"] = None,
+    _project_root: Annotated[str | None, "Optional project root path (unused, kept for interface consistency)"] = None,

Then remove the comment at line 76.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ec42fb and 03f5cc7.

📒 Files selected for processing (2)
  • Server/src/services/tools/find_in_file.py (1 hunks)
  • Server/src/services/tools/manage_script.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.8)
Server/src/services/tools/find_in_file.py

72-72: Unused function argument: project_root

(ARG001)

⏰ 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: Cursor Bugbot
🔇 Additional comments (3)
Server/src/services/tools/manage_script.py (1)

124-129: Stricter decoding gate looks correct.

The condition now properly requires all three conditions: no existing contents, contentsEncoded flag is truthy, AND encodedContents data is present. This prevents decode attempts when there's no actual encoded data.

Server/src/services/tools/find_in_file.py (2)

128-164: Regex search implementation looks correct.

The line number calculation, excerpt extraction, and result capping are implemented correctly.

One minor consideration: line_content.strip() at line 159 removes leading/trailing whitespace, which may make it harder to see exact indentation context. Consider keeping the original or offering a configurable option.


166-173: Return structure is well-designed.

Including both count (returned matches) and total_matches (all found) allows callers to detect truncation. This is a good UX pattern.

@dsarno dsarno closed this Dec 10, 2025
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.

2 participants