Skip to content

fix(setup): wrap all claude CLI calls with .claude.json guard (BUG-011)#69

Merged
mlorentedev merged 1 commit into
mainfrom
fix/BUG-011-mcp-loop-claude-json-guard
May 21, 2026
Merged

fix(setup): wrap all claude CLI calls with .claude.json guard (BUG-011)#69
mlorentedev merged 1 commit into
mainfrom
fix/BUG-011-mcp-loop-claude-json-guard

Conversation

@mlorentedev
Copy link
Copy Markdown
Owner

@mlorentedev mlorentedev commented May 21, 2026

Summary

  • BUG-004 (PR fix(setup): wrap claude plugin install with .claude.json snapshot/restore guard (BUG-004) #57) wrapped only claude plugin install with the snapshot/restore guard against upstream truncation bug anthropics/claude-code#59870. Every other CLI call site (claude mcp get, claude mcp add, claude plugin list) still hits the deserialize-modify-serialize path that truncates ~/.claude/.claude.json and forces re-authentication in every project.
  • This PR extends the guard to every Claude CLI invocation in setup-linux.sh and setup-windows.ps1 (per-call wrap, not per-loop, so a legitimate mcp add size increase never trips the >50% shrink restore).
  • Adds bats parity assertions so future call sites added without the guard fail CI.

Why per-call (not per-loop)

The restore condition is "new size < 50% of snapshot size". Per-loop wrapping would snapshot before iteration 1, then a successful mcp add in iteration 5 could legitimately grow the file and a malformed write in iteration 8 could still leave it >50% of the original snapshot — masking the truncation. Per-call wrapping snapshots immediately before each CLI invocation and restores against that single call's baseline.

Windows scriptblock semantics

Each claude <cmd> is wrapped in its own narrowly-scoped Backup-AndRestoreClaudeJson -Action { ... } rather than one wrap around the whole foreach body. Reason: continue inside a scriptblock invoked via & $Action does NOT continue the OUTER foreach. Per-call wraps preserve control flow.

Empirical smoke test (in specs/BUG-011-mcp-loop-claude-json-guard/verification.md) confirms $LASTEXITCODE, captured stdout, and foreach closure variables all survive & $Action.

Test plan

  • CI bats job (Docker) green — including 5 new asserts in tests/setup-linux.bats + 3 new asserts in tests/setup-windows.bats.
  • shellcheck --severity=error setup-linux.sh clean.
  • pwsh -Command "Invoke-ScriptAnalyzer -Path setup-windows.ps1 -Severity Error" clean.
  • Manual end-to-end confirmation: next clean-machine setup-windows.ps1 run with a healthy ~75 KB ~/.claude/.claude.json — file is unchanged (or restored from snapshot if upstream fires).

Spec

specs/BUG-011-mcp-loop-claude-json-guard/{proposal,tasks,verification}.md

BUG-004 added Backup-AndRestoreClaudeJson / snapshot_claude_json around
`claude plugin install` only. Upstream truncation bug #59870 fires on every
CLI invocation that goes through deserialize-modify-serialize, including
`claude mcp get`, `claude mcp add`, and `claude plugin list`. Result:
~/.claude/.claude.json keeps getting truncated on each setup-windows.ps1
run, forcing re-authentication everywhere.

Changes:
- setup-linux.sh: relocate snapshot_claude_json / restore_claude_json_if_truncated
  ABOVE the MCP registration block; wrap each MCP loop iteration around
  `claude mcp get` + `claude mcp add`; wrap the pre-loop `claude plugin list`.
- setup-windows.ps1: wrap each MCP foreach iteration body around `claude mcp get`
  + `claude mcp add` with Backup-AndRestoreClaudeJson scriptblock; wrap the
  pre-loop `claude plugin list` invocation.
- Per-call wrap (not per-loop): legitimate `mcp add` size growth never trips
  the >50% shrink restore — each call is checked against its own snapshot.
- Windows: separate scriptblocks per CLI call so `continue` keeps unwinding
  the outer foreach correctly.
- BUG-004 comment blocks updated to reflect the broader scope.
- bats parity assertions in tests/setup-linux.bats + setup-windows.bats
  fail CI if a future call site is added without the guard.
- specs/BUG-011-mcp-loop-claude-json-guard/{proposal,tasks,verification}.md.

Empirical end-to-end confirmation pending until the next clean-machine
setup run; verification.md documents the wrapper-semantics smoke test
($LASTEXITCODE / stdout / closure preserved across `& $Action`).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@mlorentedev mlorentedev merged commit 4b6641c into main May 21, 2026
7 checks passed
@mlorentedev mlorentedev deleted the fix/BUG-011-mcp-loop-claude-json-guard branch May 21, 2026 01:24
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.

1 participant