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
+27
View File
@@ -132,6 +132,33 @@ def load_config(path: str | os.PathLike) -> dict:
return obj
def repair_config_file(path: str | os.PathLike) -> tuple[dict, list[str], str]:
"""
Attempt to repair a config file that failed strict parsing, WITHOUT writing
anything to disk. The caller decides what to do with the result (BCC shows
the user the issues and asks before saving).
Returns (cfg, notes, repaired_text):
cfg - the parsed dict from the repaired JSON
notes - human-readable list of fixes that were applied
repaired_text - pretty-printed JSON the config would become
Raises ValueError if the file can't be salvaged automatically.
"""
text = Path(path).read_text(encoding="utf-8")
candidate, notes = repair_json_text(text)
try:
obj = json.loads(candidate)
except json.JSONDecodeError as e:
raise ValueError(
f"Couldn't repair the file automatically (line {e.lineno}, column {e.colno}: {e.msg})."
) from e
if not isinstance(obj, dict):
raise ValueError("Even after repair, the top level isn't a JSON object.")
pretty = json.dumps(obj, indent=2, ensure_ascii=False) + "\n"
return obj, notes, pretty
def extract_servers(cfg: dict) -> list[ServerEntry]:
"""Pull enabled (`mcpServers`) and disabled (`_disabledMcpServers`) servers."""
out: list[ServerEntry] = []