@@ -1422,6 +1422,91 @@ def cmd_purge(args):
14221422 print (f"\n Purged { match_count :,} drawers. Remaining: { remaining :,} \n " )
14231423
14241424
1425+ def cmd_rename_wing (args ):
1426+ want_json = getattr (args , "json" , False )
1427+ from_wing = args .from_wing
1428+ to_wing = args .to_wing
1429+ dry_run = getattr (args , "dry_run" , False )
1430+ batch_size = getattr (args , "batch_size" , 500 )
1431+
1432+ if _daemon_strict ():
1433+ if dry_run :
1434+ try :
1435+ data = _call_daemon_tool ("mempalace_list_drawers" , {
1436+ "wing" : from_wing , "limit" : 1 ,
1437+ })
1438+ except DaemonError as e :
1439+ if want_json :
1440+ _emit_json ({"error" : str (e )})
1441+ else :
1442+ print (f"\n ERROR: { e } " , file = sys .stderr )
1443+ sys .exit (2 )
1444+ total = data .get ("total" , 0 )
1445+ if want_json :
1446+ _emit_json ({"dry_run" : True , "from_wing" : from_wing , "to_wing" : to_wing , "count" : total })
1447+ else :
1448+ print (f"\n Dry run: { total :,} drawers would be renamed from '{ from_wing } ' to '{ to_wing } '\n " )
1449+ return
1450+
1451+ try :
1452+ data = _call_daemon_tool ("mempalace_rename_wing" , {
1453+ "from_wing" : from_wing ,
1454+ "to_wing" : to_wing ,
1455+ "batch_size" : batch_size ,
1456+ })
1457+ except DaemonError as e :
1458+ if want_json :
1459+ _emit_json ({"error" : str (e )})
1460+ else :
1461+ print (f"\n ERROR: { e } " , file = sys .stderr )
1462+ sys .exit (2 )
1463+
1464+ if want_json :
1465+ _emit_json (data )
1466+ else :
1467+ renamed = data .get ("renamed" , 0 )
1468+ errors = data .get ("errors" , 0 )
1469+ print (f"\n Renamed { renamed :,} drawers: '{ from_wing } ' -> '{ to_wing } '" )
1470+ if errors :
1471+ print (f" Errors: { errors :,} " )
1472+ print ()
1473+ return
1474+
1475+ from .backends .chroma import ChromaBackend
1476+ from .backends .base import PalaceRef
1477+
1478+ palace_path = os .path .abspath (
1479+ os .path .expanduser (args .palace ) if getattr (args , "palace" , None ) else MempalaceConfig ().palace_path
1480+ )
1481+ backend = ChromaBackend ()
1482+ try :
1483+ col = backend .get_collection (
1484+ palace = PalaceRef (id = palace_path , local_path = palace_path ),
1485+ collection_name = "mempalace_drawers" ,
1486+ )
1487+ except Exception as e :
1488+ print (f"\n Error reading palace: { e } " )
1489+ sys .exit (1 )
1490+
1491+ if dry_run :
1492+ matched = col .get (where = {"wing" : from_wing }, include = [])
1493+ count = len (matched .ids ) if hasattr (matched , "ids" ) else len (matched .get ("ids" , []))
1494+ if want_json :
1495+ _emit_json ({"dry_run" : True , "from_wing" : from_wing , "to_wing" : to_wing , "count" : count })
1496+ else :
1497+ print (f"\n Dry run: { count :,} drawers would be renamed from '{ from_wing } ' to '{ to_wing } '\n " )
1498+ return
1499+
1500+ result = col .rename_wing (from_wing = from_wing , to_wing = to_wing , batch_size = batch_size )
1501+ if want_json :
1502+ _emit_json ({"success" : True , "from_wing" : from_wing , "to_wing" : to_wing , ** result })
1503+ else :
1504+ print (f"\n Renamed { result ['renamed' ]:,} drawers: '{ from_wing } ' -> '{ to_wing } '" )
1505+ if result ["errors" ]:
1506+ print (f" Errors: { result ['errors' ]:,} " )
1507+ print ()
1508+
1509+
14251510def cmd_replay (args ):
14261511 """Drain ``~/.mempalace/pending/*.jsonl`` by re-issuing each request to the daemon.
14271512
@@ -2622,6 +2707,15 @@ def main():
26222707 )
26232708 p_purge .add_argument ("--yes" , "-y" , action = "store_true" , help = "Skip confirmation prompt" )
26242709
2710+ p_rename_wing = sub .add_parser (
2711+ "rename-wing" ,
2712+ help = "Rename all drawers from one wing to another (atomic on postgres)" ,
2713+ )
2714+ p_rename_wing .add_argument ("--from" , dest = "from_wing" , required = True , help = "Source wing name" )
2715+ p_rename_wing .add_argument ("--to" , dest = "to_wing" , required = True , help = "Target wing name" )
2716+ p_rename_wing .add_argument ("--dry-run" , action = "store_true" , help = "Count matching drawers without renaming" )
2717+ p_rename_wing .add_argument ("--batch-size" , type = int , default = 500 , help = "Batch size for non-postgres backends (default: 500)" )
2718+
26252719 # ── rooms — manage the canonical room set (hybrid-search-taxonomy follow-up) ────
26262720 p_rooms = sub .add_parser (
26272721 "rooms" ,
@@ -2761,6 +2855,7 @@ def _nonneg_int(value: str) -> int:
27612855 "migrate" : cmd_migrate ,
27622856 "migrate-to-postgres" : cmd_migrate_to_postgres ,
27632857 "purge" : cmd_purge ,
2858+ "rename-wing" : cmd_rename_wing ,
27642859 "rooms" : cmd_rooms ,
27652860 "status" : cmd_status ,
27662861 "mined" : cmd_mined ,
0 commit comments