Add dry_run parameter to file_write tool#122
Conversation
Added optional dry_run parameter to file_write tool with two modes: - dry_run="diff": Returns unified diff without writing to file - dry_run="new-source": Returns complete file content without writing Changes: - Updated tool schema to include dry_run parameter - Modified validate-inputs to extract and pass through dry_run - Updated execute-tool to pass dry_run and skip timestamp update in dry_run mode - Modified format-results to handle new-source output - Updated core.clj write-file, write-clojure-file, and write-text-file functions - Fixed all test calls to pass nil for dry_run parameter All 365 tests pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
The dry_run parameter is for internal use only and should not be exposed in the public schema. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Rate limit exceeded@bhauman has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 6 minutes and 45 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughThe pull request introduces a unified Changes
Sequence DiagramsequenceDiagram
participant Tool as Tool Layer
participant Core as Core Logic
participant FS as File System
Tool->>Tool: validate-inputs (extract dry_run)
Tool->>Core: execute-tool (pass dry_run)
alt dry_run = "new-source"
Core->>Core: compute new_source
Core-->>Tool: return {new-source: ...}
else dry_run = true
Core->>Core: compute diff
Core-->>Tool: return {diff: ...}
else dry_run = nil
Core->>FS: write-file
Core->>FS: update timestamp
Core-->>Tool: return {type: ..., file-path: ...}
end
Tool->>Tool: format-results (check for new-source)
alt new-source present
Tool-->>Client: return new-source directly
else
Tool-->>Client: return formatted result
end
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes The changes follow a consistent pattern: adding an optional Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/clojure_mcp/tools/file_write/tool.clj (1)
66-92: Clarify dry_run access control and add validation.The PR description states that
dry_runis "for internal use and not exposed in the tool schema." However, the code extractsdry_runfrominputs(line 66), which means external callers can provide it even though it's not in the schema. This creates an undocumented API surface.Additionally, there's no validation that
dry_runcontains valid values ("diff"or"new-source").Consider one of these approaches:
Option 1: Make it truly internal
If dry_run is only for internal tool usage, extract it from a different source (e.g., tool config) rather than from user inputs:(defmethod tool-system/validate-inputs :file-write [{:keys [nrepl-client-atom]} inputs] - (let [{:keys [file_path content dry_run]} inputs + (let [{:keys [file_path content]} inputs nrepl-client (and nrepl-client-atom @nrepl-client-atom)]Option 2: Make it officially supported
If external callers should be able to use dry_run, add it to the schema and validate it:(defmethod tool-system/tool-schema :file-write [_] {:type :object :properties {:file_path {:type :string :description "The absolute path to the file to write (must be absolute, not relative)"} :content {:type :string - :description "The content to write to the file"}} + :description "The content to write to the file"} + :dry_run {:type :string + :enum ["diff" "new-source"] + :description "Preview mode: 'diff' shows changes, 'new-source' shows complete content. Does not write to disk."}} :required [:file_path :content]})And add validation:
+ (when (and dry_run (not (contains? #{"diff" "new-source"} dry_run))) + (throw (ex-info (str "Invalid dry_run value: " dry_run " - must be 'diff' or 'new-source'") + {:dry_run dry_run})))
🧹 Nitpick comments (3)
test/clojure_mcp/tools/file_write/core_test.clj (1)
69-69: Consider adding test coverage for dry_run functionality.All test calls have been updated to pass
nilfor the newdry_runparameter, which correctly maintains existing behavior. However, there's no test coverage for the new dry_run modes ("diff"and"new-source").Consider adding tests to verify:
dry_run="diff"returns diff without writing filedry_run="new-source"returns complete file content without writing- File is not modified when dry_run is set
- File timestamp is not updated when dry_run is set
Do you want me to generate test cases for the dry_run functionality?
Also applies to: 82-82, 96-97, 111-112, 125-126, 138-139, 153-154, 169-170, 185-186, 197-198
src/clojure_mcp/tools/file_write/core.clj (2)
32-75: Consider validating dry_run parameter values.The function correctly threads
dry_runthrough the pipeline and handles both"new-source"and diff modes. However, there's no validation thatdry_runis one of the expected values (nil,"diff", or"new-source"). Invalid values would fall through to the:elsebranch, potentially causing confusion.Consider adding validation at the function entry:
[nrepl-client-atom file-path content dry_run] + (when (and dry_run (not (contains? #{"diff" "new-source"} dry_run))) + (throw (ex-info (str "Invalid dry_run value: " dry_run) + {:dry_run dry_run + :expected #{"diff" "new-source"}}))) (let [file (io/file file-path)
87-112: Same validation consideration applies here.The
write-text-filefunction has the same dry_run handling pattern aswrite-clojure-fileand would benefit from the same parameter validation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/clojure_mcp/tools/file_write/core.clj(4 hunks)src/clojure_mcp/tools/file_write/tool.clj(4 hunks)test/clojure_mcp/tools/file_write/core_test.clj(10 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.{clj,cljc}
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.{clj,cljc}: Use:requirewith ns aliases for imports (e.g.,[clojure.string :as string])
Include clear tool:descriptionfor LLM guidance
Validate inputs and provide helpful error messages in MCP tools
Return structured data with both result and error status in MCP tools
Maintain atom-based state for consistent service access in MCP tools
Files:
src/clojure_mcp/tools/file_write/core.cljsrc/clojure_mcp/tools/file_write/tool.clj
**/*.{clj,cljc}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{clj,cljc}: Use kebab-case for vars/functions; end predicates with?(e.g.,is-top-level-form?)
Usetry/catchwith specific exception handling; use atom for tracking errors
Use 2-space indentation and maintain whitespace in edited forms
Align namespaces with directory structure (e.g.,clojure-mcp.repl-tools)
Files:
src/clojure_mcp/tools/file_write/core.cljtest/clojure_mcp/tools/file_write/core_test.cljsrc/clojure_mcp/tools/file_write/tool.clj
test/**/*.{clj,cljc}
📄 CodeRabbit inference engine (CLAUDE.md)
Use
deftestwith descriptive names;testingfor subsections;isfor assertions in tests
Files:
test/clojure_mcp/tools/file_write/core_test.clj
🔇 Additional comments (4)
src/clojure_mcp/tools/file_write/core.clj (2)
12-20: LGTM!The
is-clojure-file?predicate correctly follows Clojure naming conventions and provides a clean abstraction for file type detection.
129-132: LGTM!The
write-filedispatcher correctly threads thedry_runparameter to bothwrite-clojure-fileandwrite-text-filepaths.src/clojure_mcp/tools/file_write/tool.clj (2)
94-113: LGTM!The
execute-toolimplementation correctly passesdry_runthrough to the core write function and appropriately skips the timestamp update when in dry-run mode.
115-133: LGTM!The
format-resultsmethod correctly handles the new:new-sourceresult for dry-run mode while preserving the existing diff-based formatting for normal operations.
When dry_run parameter is present, return just the diff or new-source without any preamble (file type, path, or "Changes:" prefix). Changes: - Modified write-clojure-file to return only diff when dry_run="diff" - Modified write-text-file to return only diff when dry_run="diff" - Updated format-results to detect dry_run mode and return raw output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
When dry_run parameter is used, include :dry_run field in the result
containing the mode value ("diff" or "new-source") to make the API
more self-documenting.
Result formats:
- dry_run="new-source": {:error false, :dry_run "new-source", :new-source "..."}
- dry_run="diff": {:error false, :dry_run "diff", :diff "..."}
- Normal operation: {:error false, :type "update", :file-path "...", :diff "..."}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Summary
Adds optional
dry_runparameter to thefile_writetool, allowing previewing changes without writing to disk. This brings consistency with the other file editing tools (file_edit,clojure_edit,clojure_edit_replace_sexp) that already support this parameter.Changes
src/clojure_mcp/tools/file_write/tool.clj
validate-inputsto extract and pass throughdry_runexecute-toolto passdry_runand skip timestamp update in dry_run modeformat-resultsto handle new-source outputsrc/clojure_mcp/tools/file_write/core.clj
write-clojure-fileto acceptdry_runparameter and skip file save when setwrite-text-fileto acceptdry_runparameter and conditionally writewrite-filedispatcher to passdry_runthroughtest/clojure_mcp/tools/file_write/core_test.clj
nilfor dry_run parameterDry Run Modes
dry_run="diff"- Returns unified diff without writing to filedry_run="new-source"- Returns complete file content without writingTesting
✅ All 365 tests pass with 0 failures and 0 errors
✅ Verified all three modes work correctly (diff, new-source, and normal write)
Notes
The
dry_runparameter is for internal use only and is not exposed in the tool schema.🤖 Generated with Claude Code
Summary by CodeRabbit