feat: Git-based backup system replacing JSON bundle backup/restore

DB is source of truth with git as downstream replica. SSH key generated
on first start, all resource mutations committed as apply-compatible YAML.
Supports manual commit import, conflict resolution (DB wins), disaster
recovery (empty DB restores from git), and timeline branches on restore.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michal
2026-03-08 01:14:28 +00:00
parent 9fc31e5945
commit 7818cb2194
22 changed files with 2011 additions and 127 deletions

View File

@@ -233,10 +233,43 @@ _mcpctl() {
fi
return ;;
backup)
COMPREPLY=($(compgen -W "-o --output -p --password -r --resources -h --help" -- "$cur"))
local backup_sub=$(_mcpctl_get_subcmd $subcmd_pos)
if [[ -z "$backup_sub" ]]; then
COMPREPLY=($(compgen -W "log key help" -- "$cur"))
else
case "$backup_sub" in
log)
COMPREPLY=($(compgen -W "-n --limit -h --help" -- "$cur"))
;;
key)
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
;;
*)
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
;;
esac
fi
return ;;
restore)
COMPREPLY=($(compgen -W "-i --input -p --password -c --conflict -h --help" -- "$cur"))
local restore_sub=$(_mcpctl_get_subcmd $subcmd_pos)
if [[ -z "$restore_sub" ]]; then
COMPREPLY=($(compgen -W "list diff to help" -- "$cur"))
else
case "$restore_sub" in
list)
COMPREPLY=($(compgen -W "-n --limit -h --help" -- "$cur"))
;;
diff)
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
;;
to)
COMPREPLY=($(compgen -W "--force -h --help" -- "$cur"))
;;
*)
COMPREPLY=($(compgen -W "-h --help" -- "$cur"))
;;
esac
fi
return ;;
attach-server)
if [[ $((cword - subcmd_pos)) -ne 1 ]]; then return; fi

View File

@@ -227,8 +227,8 @@ complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a edit -d 'Edit a resource in your default editor (server, project)'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a apply -d 'Apply declarative configuration from a YAML or JSON file'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a patch -d 'Patch a resource field (e.g. mcpctl patch project myproj llmProvider=none)'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a backup -d 'Backup mcpctl configuration to a JSON file'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a restore -d 'Restore mcpctl configuration from a backup file'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a backup -d 'Git-based backup status and management'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a restore -d 'Restore mcpctl state from backup history'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a approve -d 'Approve a pending prompt request (atomic: delete request, create prompt)'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a console -d 'Interactive MCP console — unified timeline with tools, provenance, and lab replay'
complete -c mcpctl -n "not __mcpctl_has_project; and not __fish_seen_subcommand_from $commands" -a cache -d 'Manage ProxyModel pipeline cache'
@@ -353,6 +353,26 @@ complete -c mcpctl -n "__mcpctl_subcmd_active create promptrequest" -l content -
complete -c mcpctl -n "__mcpctl_subcmd_active create promptrequest" -l content-file -d 'Read prompt content from file' -rF
complete -c mcpctl -n "__mcpctl_subcmd_active create promptrequest" -l priority -d 'Priority 1-10 (default: 5, higher = more important)' -x
# backup subcommands
set -l backup_cmds log key
complete -c mcpctl -n "__fish_seen_subcommand_from backup; and not __fish_seen_subcommand_from $backup_cmds" -a log -d 'Show backup commit history'
complete -c mcpctl -n "__fish_seen_subcommand_from backup; and not __fish_seen_subcommand_from $backup_cmds" -a key -d 'Show SSH public key for deploy key setup'
# backup log options
complete -c mcpctl -n "__mcpctl_subcmd_active backup log" -s n -l limit -d 'number of commits to show' -x
# restore subcommands
set -l restore_cmds list diff to
complete -c mcpctl -n "__fish_seen_subcommand_from restore; and not __fish_seen_subcommand_from $restore_cmds" -a list -d 'List available restore points'
complete -c mcpctl -n "__fish_seen_subcommand_from restore; and not __fish_seen_subcommand_from $restore_cmds" -a diff -d 'Preview what restoring to a commit would change'
complete -c mcpctl -n "__fish_seen_subcommand_from restore; and not __fish_seen_subcommand_from $restore_cmds" -a to -d 'Restore to a specific commit'
# restore list options
complete -c mcpctl -n "__mcpctl_subcmd_active restore list" -s n -l limit -d 'number of entries' -x
# restore to options
complete -c mcpctl -n "__mcpctl_subcmd_active restore to" -l force -d 'skip confirmation'
# cache subcommands
set -l cache_cmds stats clear
complete -c mcpctl -n "__fish_seen_subcommand_from cache; and not __fish_seen_subcommand_from $cache_cmds" -a stats -d 'Show cache statistics'
@@ -388,16 +408,6 @@ complete -c mcpctl -n "__fish_seen_subcommand_from logs" -s i -l instance -d 'In
complete -c mcpctl -n "__fish_seen_subcommand_from apply" -s f -l file -d 'Path to config file (alternative to positional arg)' -rF
complete -c mcpctl -n "__fish_seen_subcommand_from apply" -l dry-run -d 'Validate and show changes without applying'
# backup options
complete -c mcpctl -n "__fish_seen_subcommand_from backup" -s o -l output -d 'output file path' -rF
complete -c mcpctl -n "__fish_seen_subcommand_from backup" -s p -l password -d 'encrypt sensitive values with password' -x
complete -c mcpctl -n "__fish_seen_subcommand_from backup" -s r -l resources -d 'resource types to backup (comma-separated: servers,profiles,projects)' -x
# restore options
complete -c mcpctl -n "__fish_seen_subcommand_from restore" -s i -l input -d 'backup file path' -rF
complete -c mcpctl -n "__fish_seen_subcommand_from restore" -s p -l password -d 'decryption password for encrypted backups' -x
complete -c mcpctl -n "__fish_seen_subcommand_from restore" -s c -l conflict -d 'conflict resolution: skip, overwrite, fail' -x
# console options
complete -c mcpctl -n "__fish_seen_subcommand_from console" -l stdin-mcp -d 'Run inspector as MCP server over stdin/stdout (for Claude)'
complete -c mcpctl -n "__fish_seen_subcommand_from console" -l audit -d 'Browse audit events from mcpd'