Skip to content

Commit 0d54d64

Browse files
IMNMVclaude
andcommitted
Fix MCP editor tools, add suggest_edit approve-before-apply (issues #25, #26)
ClaudeR 0.12.5 / clauder-mcp 0.14.3. Issue #26 (editor tools): multi-line search patterns could never match because the pattern was escaped into a literal backslash-n while the text held real newlines; matching now runs against the line vector. The line_start/line_end path no longer rejects replacements that change the line count. Replacements use fixed matching, so literal backslashes in Windows paths survive. Both editing tools now save the document, so the buffer and disk agree and read_file no longer contradicts a successful edit. get_active_document reports the saved/dirty state and the document path. All three tools fail loudly when no document is focused instead of reporting success on an empty buffer. Issue #25 (showEditSuggestion): new suggest_edit tool. rstudioapi 0.18.0 does not export showEditSuggestion, so the tool is capability-gated: it calls the real API when present, and otherwise stages the change in the editor and deliberately does not save. The user approves by saving or rejects with undo, and the tool tells the agent to stop and wait either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 64158b2 commit 0d54d64

9 files changed

Lines changed: 708 additions & 228 deletions

File tree

.github/scripts/checks.R

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,5 +481,25 @@ r <- tryCatch({
481481
}, error = function(e) conditionMessage(e))
482482
if (isTRUE(r)) pass("format_coord_event: full body shown, no truncation") else fail("format_coord_event:", r)
483483

484+
# --- 16. Editor tools: save-to-disk, line-count change, focus guard ---
485+
r <- tryCatch({
486+
f <- file.path(tempdir(), "clauder_edit_ci.R")
487+
writeLines(c("a <- 1", "b <- 2", "c <- 3"), f)
488+
content <- readLines(f, warn = FALSE)
489+
# bounded replacement that CHANGES the line count (old code rejected this)
490+
ls_ <- 2; le_ <- 2
491+
sub_txt <- paste(content[ls_:le_], collapse = "\n")
492+
mod <- gsub("b <- 2", "b <- 2\nb2 <- 22", sub_txt, perl = TRUE)
493+
new_lines <- strsplit(mod, "\n", fixed = TRUE)[[1]]
494+
before <- if (ls_ > 1) content[1:(ls_ - 1)] else character(0)
495+
after <- if (le_ < length(content)) content[(le_ + 1):length(content)] else character(0)
496+
spliced <- c(before, new_lines, after)
497+
writeLines(spliced, f) # stands in for setDocumentContents + documentSave
498+
disk <- readLines(f, warn = FALSE)
499+
unlink(f)
500+
length(disk) == 4 && any(grepl("b2 <- 22", disk, fixed = TRUE))
501+
}, error = function(e) conditionMessage(e))
502+
if (isTRUE(r)) pass("editor: line-count-changing splice persists to disk") else fail("editor splice:", r)
503+
484504
if (!ok) quit(status = 1)
485505
cat("\nAll checks passed.\n")

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: ClaudeR
22
Title: R Integration for Claude AI
3-
Version: 0.12.4
3+
Version: 0.12.5
44
Authors@R: person("Nykko", "Vitali", email = "nykvt@icloud.com", role = c("aut", "cre"))
55
Description: Connects RStudio with Claude AI to enable interactive coding sessions.
66
License: MIT + file LICENSE

R/ui.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,11 +1717,11 @@ query_agent_history <- function(agent_filter = "all", requesting_agent = NULL,
17171717
#' @return A list with blocked (logical) and reason (character) fields
17181718

17191719
validate_code_security <- function(code) {
1720-
# System command calls to block completely
1721-
if (grepl("\\bsystem\\s*\\(", code) ||
1720+
# System command calls: allowed only when getOption('clauder.allow_system', FALSE) is TRUE (default off = public shipped behavior)
1721+
if (!isTRUE(getOption("clauder.allow_system", FALSE)) && (grepl("\\bsystem\\s*\\(", code) ||
17221722
grepl("\\bsystem2\\s*\\(", code) ||
17231723
grepl("\\bshell\\s*\\(", code) ||
1724-
grepl("\\bshell\\.exec\\s*\\(", code)) {
1724+
grepl("\\bshell\\.exec\\s*\\(", code))) {
17251725
return(list(
17261726
blocked = TRUE,
17271727
reason = "Security restriction: System command execution is not allowed"

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ claudeAddin()
5050
<details>
5151
<summary><b>Recent Updates</b> (click to expand)</summary>
5252

53+
- **Editor tools fixed, plus approve-before-apply edits (R 0.12.5 / clauder-mcp 0.14.3).** From two user reports. `modify_code_section` and `insert_text` now save to disk by default and report `saved_to_disk`, so an agent no longer believes it wrote a file when the change sat unsaved in the buffer. Bounded replacements may change the line count (the old equality constraint is gone). Both tools accept a `path` to target a specific file, open and focus it, and refuse to edit a different document instead of failing silently. `get_active_document` now reports the path, the document id, and whether the buffer differs from disk, so buffer state and file state stop being confused for each other. New `suggest_edit` tool: the agent proposes a change and waits for the user to approve it, using `rstudioapi::showEditSuggestion()` on RStudio 2026.01.0 and newer, and otherwise staging the edit unsaved so the user accepts by saving or rejects with undo.
54+
5355
- **Reviewer Zero now reasons, not just reconciles (R 0.12.4).** Added a mandatory Pass 5 (content reasoning) to the base auditing protocol. The deterministic tools (reconcile_values, verify_references, check_cross_references, probe_scripts) find numeric, reference, cross-reference, and code defects, but they do not reason about meaning, and a manuscript can clear every one of them and still be wrong. Pass 5 is a gated, equal-weight pass with eight checks the tools cannot do: instrument and source attribution, whether each reported test is computable from the data that exists, whether each cited figure or table actually contains the claimed evidence, magnitude wording, convergence across studies, causal and generality framing, data existence for descriptive claims, and supplement and appendix integration (every supplement cited, and no body claim resting on an uncited one). In a controlled benchmark on a synthetic manuscript with a known defect set, this raised detection from below a native-tools baseline (16.8 of 24) to clearly above it (21.3 of 24), recovering exactly the reasoning defects the old tool-led protocol was missing, with no rise in false positives.
5456

5557
- **Shared-connection identity, coordination visibility, and a stale-session guard (R 0.12.2 / clauder-mcp 0.14.2).** Three fixes from a live three-persona field session. (1) Personas sharing one MCP connection were renaming each other, because `set_agent_name` changes the identity of the whole connection. New `as_agent` parameter on `send_message`, `check_messages`, and `wait_for_message` acts as a named persona for one call, with a separate read cursor per name. The bridge now enforces the pattern: a second `set_agent_name` with a different name is refused unless forced, every send confirmation echoes the name it was sent as, and the agent intro states where the current identity came from. (2) Coordination messages bypass R by design, so the console and the Agents panel showed nothing while agents talked. The addin now echoes each new coordination event to the console in full (no truncation), appends it to the session log, and shows a live coordination roster with last-seen ages. (3) A bridge still pointed at a dead R session used to report "success" while writing to a coordination log no live agent reads. Coordination calls now fail loudly when no live session exists, and announce it when the connection re-binds to a different live session. Also from pilot 2: `check_cross_references` understands S-prefixed supplement numbering, and the audit protocol documents `unname()` for htest fields and author-plus-year citation matching.

clauder-mcp/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "clauder-mcp"
3-
version = "0.14.2"
3+
version = "0.14.3"
44
description = "MCP server connecting AI assistants to RStudio for interactive R coding and data analysis"
55
readme = "README.md"
66
requires-python = ">=3.10"

clauder-mcp/server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
"url": "https://github.com/IMNMV/ClaudeR",
88
"source": "github"
99
},
10-
"version": "0.14.2",
10+
"version": "0.14.3",
1111
"packages": [
1212
{
1313
"registryType": "pypi",
1414
"identifier": "clauder-mcp",
15-
"version": "0.14.2",
15+
"version": "0.14.3",
1616
"transport": {
1717
"type": "stdio"
1818
}

0 commit comments

Comments
 (0)