feat: backup restore UI (#3) #14
Reference in New Issue
Block a user
Delete Branch "feat/3-backup-restore-ui"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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.