feat: offer guided repair when loading a broken config file

If a config file on disk fails strict JSON parsing, BCC now runs it
through the same repair pipeline as pasted snippets and shows a dialog
listing the parse error, each fix it would apply, and a preview of the
resulting file. The user chooses: Repair & load (marks the profile
dirty; the file is only rewritten on Save, after the broken original
is backed up) or Cancel. Unsalvageable files keep the old error path.

repair_config_file() in bcc_core never writes to disk itself.
This commit is contained in:
AJ
2026-07-02 00:10:27 -04:00
parent d6ce4a0fb0
commit 77f469c1dd
3 changed files with 132 additions and 6 deletions
+31
View File
@@ -2,6 +2,8 @@
parse_pasted_json_verbose). Every case here is a shape people actually paste
from MCP docs, blog posts, and chat windows."""
import json
import pytest
import bcc_core as c
@@ -170,6 +172,35 @@ def test_kitchen_sink():
assert len(notes) >= 4
# --------------------------------------------------------------------------- #
# Config-file repair (load-time)
# --------------------------------------------------------------------------- #
def test_repair_config_file_fixes_and_reports(tmp_path):
p = tmp_path / "claude_desktop_config.json"
p.write_text(
'{\n "globalShortcut": "Cmd+Space",\n'
" // my servers\n"
' "mcpServers": {\n'
' "brave": {"command": "npx", "args": ["-y"],},\n'
" },\n}"
)
cfg, notes, preview = c.repair_config_file(p)
assert cfg["mcpServers"]["brave"]["command"] == "npx"
assert cfg["globalShortcut"] == "Cmd+Space" # unrelated keys survive
assert any("comment" in n for n in notes)
assert any("trailing" in n for n in notes)
assert json.loads(preview) == cfg
# nothing was written to disk
assert "//" in p.read_text()
def test_repair_config_file_hopeless_raises(tmp_path):
p = tmp_path / "claude_desktop_config.json"
p.write_text("total nonsense, no braces at all")
with pytest.raises(ValueError):
c.repair_config_file(p)
# --------------------------------------------------------------------------- #
# Still fails cleanly on hopeless input
# --------------------------------------------------------------------------- #