Adds list_backups, backup_label, backup_diff, restore_backup to bcc_core.py
Adds RestoreDialog to bcc.py: two-panel dialog with backup list (newest-first) + diff preview
Adds "Restore…" button in the MainWindow profile top bar
Key design decisions
Selective restore — only mcpServers and _disabledMcpServers are replaced. All other keys in the current config (conversation history, project state, etc.) are preserved verbatim and in their original order. This upholds the cardinal rule and is especially important for ~/.claude.json.
Pre-restore backup — restore_backup goes through write_config, so a backup of the pre-restore state is created automatically before anything is overwritten.
Accurate diff — backup_diff accepts an optional current_cfg so the dialog can diff against the already-loaded in-memory config (e.g. post-repair) instead of re-reading from disk. The diff shows before→after for servers only, matching what will actually be written.
backup_label uses regex — extracts the YYYYMMDD-HHMMSS timestamp with re.compile(r\"(\\d{8}-\\d{6})\") to handle filenames with leading dots (.claude.20260702-004124.json).
## Summary
- Adds `list_backups`, `backup_label`, `backup_diff`, `restore_backup` to `bcc_core.py`
- Adds `RestoreDialog` to `bcc.py`: two-panel dialog with backup list (newest-first) + diff preview
- Adds "Restore…" button in the MainWindow profile top bar
## Key design decisions
**Selective restore** — only `mcpServers` and `_disabledMcpServers` are replaced. All other keys in the current config (conversation history, project state, etc.) are preserved verbatim and in their original order. This upholds the cardinal rule and is especially important for `~/.claude.json`.
**Pre-restore backup** — `restore_backup` goes through `write_config`, so a backup of the pre-restore state is created automatically before anything is overwritten.
**Accurate diff** — `backup_diff` accepts an optional `current_cfg` so the dialog can diff against the already-loaded in-memory config (e.g. post-repair) instead of re-reading from disk. The diff shows before→after for servers only, matching what will actually be written.
**`backup_label` uses regex** — extracts the `YYYYMMDD-HHMMSS` timestamp with `re.compile(r\"(\\d{8}-\\d{6})\")` to handle filenames with leading dots (`.claude.20260702-004124.json`).
## Tests added (9 new, 47 total)
- `test_list_backups_returns_newest_first`
- `test_list_backups_empty_when_no_bdir`
- `test_backup_label_parses_timestamp`
- `test_backup_diff_shows_server_change`
- `test_backup_diff_no_diff_when_identical`
- `test_restore_backup_replaces_servers`
- `test_restore_preserves_non_server_keys`
- `test_restore_creates_pre_restore_backup`
- `test_restore_with_current_cfg_passed`
Closes #3
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add list_backups / backup_label / backup_diff / restore_backup to bcc_core,
RestoreDialog to bcc.py, and a "Restore…" button in the profile top bar.
Restore is selective: only mcpServers and _disabledMcpServers are replaced;
all other keys in the config (history, project state) are preserved verbatim.
Goes through write_config() so a pre-restore backup is always created first.
Closes#3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The diff preview in RestoreDialog was serializing the full config dict,
exposing secret env values and token args in cleartext on a pasteable surface.
- Add _redact_server_data / _redact_servers_block helpers that apply
redact_args to args and mask env values for is_secret_key() keys
- Rewrite backup_diff to compare only {mcpServers, _disabledMcpServers}
sections (sanitized), not the whole file — also avoids double-serializing
multi-MB ~/.claude.json for a servers-only diff
- Add clarifying comment in _restore_from_backup about why full_config
is the right base after confirm-discard
- Add test: backup_diff with secret args/env → MASK in output, raw values absent
- Add test: restore_backup restores _disabledMcpServers correctly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supervisor review — fix 1 (diff leaks secrets):backup_diff now scopes to only mcpServers/_disabledMcpServers sections and runs redact_args + is_secret_key masking on all server data before diffing. Raw secret values no longer appear in the preview. Added test_backup_diff_masks_secrets.
Supervisor follow-up 2 (_disabledMcpServers round-trip): Added test_restore_backup_restores_disabled_servers — creates a config with a disabled server, overwrites it, restores the backup, and asserts the disabled server is back under _disabledMcpServers.
Supervisor follow-up 3 (dirty-state baseline comment): Added one-line comment in _restore_from_backup explaining why full_config is the right restore base after confirm-discard.
**Supervisor review — fix 1 (diff leaks secrets):** `backup_diff` now scopes to only `mcpServers`/`_disabledMcpServers` sections and runs `redact_args` + `is_secret_key` masking on all server data before diffing. Raw secret values no longer appear in the preview. Added `test_backup_diff_masks_secrets`.
**Supervisor follow-up 2 (_disabledMcpServers round-trip):** Added `test_restore_backup_restores_disabled_servers` — creates a config with a disabled server, overwrites it, restores the backup, and asserts the disabled server is back under `_disabledMcpServers`.
**Supervisor follow-up 3 (dirty-state baseline comment):** Added one-line comment in `_restore_from_backup` explaining why `full_config` is the right restore base after confirm-discard.
the_og
merged commit be45be9eab into main2026-07-02 01:44:44 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
list_backups,backup_label,backup_diff,restore_backuptobcc_core.pyRestoreDialogtobcc.py: two-panel dialog with backup list (newest-first) + diff previewKey design decisions
Selective restore — only
mcpServersand_disabledMcpServersare replaced. All other keys in the current config (conversation history, project state, etc.) are preserved verbatim and in their original order. This upholds the cardinal rule and is especially important for~/.claude.json.Pre-restore backup —
restore_backupgoes throughwrite_config, so a backup of the pre-restore state is created automatically before anything is overwritten.Accurate diff —
backup_diffaccepts an optionalcurrent_cfgso the dialog can diff against the already-loaded in-memory config (e.g. post-repair) instead of re-reading from disk. The diff shows before→after for servers only, matching what will actually be written.backup_labeluses regex — extracts theYYYYMMDD-HHMMSStimestamp withre.compile(r\"(\\d{8}-\\d{6})\")to handle filenames with leading dots (.claude.20260702-004124.json).Tests added (9 new, 47 total)
test_list_backups_returns_newest_firsttest_list_backups_empty_when_no_bdirtest_backup_label_parses_timestamptest_backup_diff_shows_server_changetest_backup_diff_no_diff_when_identicaltest_restore_backup_replaces_serverstest_restore_preserves_non_server_keystest_restore_creates_pre_restore_backuptest_restore_with_current_cfg_passedCloses #3
🤖 Generated with Claude Code
The diff preview in RestoreDialog was serializing the full config dict, exposing secret env values and token args in cleartext on a pasteable surface. - Add _redact_server_data / _redact_servers_block helpers that apply redact_args to args and mask env values for is_secret_key() keys - Rewrite backup_diff to compare only {mcpServers, _disabledMcpServers} sections (sanitized), not the whole file — also avoids double-serializing multi-MB ~/.claude.json for a servers-only diff - Add clarifying comment in _restore_from_backup about why full_config is the right base after confirm-discard - Add test: backup_diff with secret args/env → MASK in output, raw values absent - Add test: restore_backup restores _disabledMcpServers correctly Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Supervisor review — fix 1 (diff leaks secrets):
backup_diffnow scopes to onlymcpServers/_disabledMcpServerssections and runsredact_args+is_secret_keymasking on all server data before diffing. Raw secret values no longer appear in the preview. Addedtest_backup_diff_masks_secrets.Supervisor follow-up 2 (_disabledMcpServers round-trip): Added
test_restore_backup_restores_disabled_servers— creates a config with a disabled server, overwrites it, restores the backup, and asserts the disabled server is back under_disabledMcpServers.Supervisor follow-up 3 (dirty-state baseline comment): Added one-line comment in
_restore_from_backupexplaining whyfull_configis the right restore base after confirm-discard.