fix(profiles): ship a retry path for the rename identity migration
A rename under a live multiplexer that could not reach the control verb warned and stopped there, leaving the operator with no way to finish: the rename cannot be repeated (profiles/<old> is gone) and the CLI deliberately never rewrites the routing DB a live gateway holds in memory. - `hermes profile migrate-identity <old> <new>`: retries the migration — delegates to the gateway control verb while a multiplexer is live, performs the durable rewrite of both state DBs when none is. Idempotent, and exits non-zero naming the offending database on a collision, a lock, or a partial failure. Only the name format and the existence of the new profile are checked; the old profile directory is expected to be gone. - An older gateway that does not implement the verb is reported as such (`identify` answers while the migrate verb does not), not as "no gateway". - `_migrate_profile_identity` returns an explicit success/failure result so the command can set its exit code; the rename warning now names the exact invocation. - A failed control answer keeps the raw payload when it carries no reason field. - The offline failure branch called `click.echo` in a module that never imports `click`: a failed second database raised NameError instead of printing its warning.
This commit is contained in:
@@ -9,10 +9,10 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
from typing import NoReturn, Optional
|
||||
|
||||
|
||||
def _die(msg: str, code: int = 1, *, err: bool = False) -> None:
|
||||
def _die(msg: str, code: int = 1, *, err: bool = False) -> NoReturn:
|
||||
print(msg, file=sys.stderr if err else sys.stdout)
|
||||
sys.exit(code)
|
||||
|
||||
@@ -436,6 +436,21 @@ def _profile_rename(args):
|
||||
_die(f"Error: {e}")
|
||||
|
||||
|
||||
def _profile_migrate_identity(args):
|
||||
"""Retry the identity migration of a rename that already completed. Exits non-zero when a
|
||||
live gateway would not migrate (it still owns the routing index in memory), or when a
|
||||
database rejected the rewrite (collision, lock, partial failure)."""
|
||||
from hermes_cli.profiles import migrate_profile_identity
|
||||
try:
|
||||
migrated = migrate_profile_identity(args.old_name, args.new_name)
|
||||
except (ValueError, FileNotFoundError) as e:
|
||||
_die(f"Error: {e}")
|
||||
if not migrated:
|
||||
_die(f"Error: session identity was not migrated. Restart or stop the gateway, then run:\n"
|
||||
f" hermes profile migrate-identity {args.old_name} {args.new_name}", err=True)
|
||||
print(f"✓ Session/routing identity migrated: {args.old_name} → {args.new_name}")
|
||||
|
||||
|
||||
def _profile_export(args):
|
||||
from hermes_cli.profiles import export_profile, get_profile_export_path
|
||||
name = args.profile_name
|
||||
@@ -575,6 +590,7 @@ PROFILE_ACTIONS = {
|
||||
'show': _profile_show,
|
||||
'alias': _profile_alias,
|
||||
'rename': _profile_rename,
|
||||
'migrate-identity': _profile_migrate_identity,
|
||||
'export': _profile_export,
|
||||
'import': _profile_import,
|
||||
'install': _profile_install,
|
||||
|
||||
Reference in New Issue
Block a user