fix(codex-accounts): add remove command and ignore quota artifacts in account list

This commit is contained in:
OpenClaw Assistant
2026-03-03 00:59:58 +03:00
parent 80c9967ede
commit 0e210c3d1b

View File

@@ -19,6 +19,18 @@ def ensure_dirs():
if not ACCOUNTS_DIR.exists():
ACCOUNTS_DIR.mkdir(parents=True)
def account_files():
"""Real saved account snapshots (exclude hidden/quota artifacts)."""
ensure_dirs()
out = []
for f in ACCOUNTS_DIR.glob("*.json"):
n = f.name
if n.startswith('.') or n.endswith('.quota.json'):
continue
out.append(f)
return out
def decode_jwt_payload(token):
try:
# JWT is header.payload.signature
@@ -103,7 +115,7 @@ def resolve_active_profile():
if not AUTH_FILE.exists():
return None
for f in ACCOUNTS_DIR.glob("*.json"):
for f in account_files():
if is_current(f):
info = get_account_info(f) or {}
return f.stem, info.get("email", "unknown")
@@ -201,7 +213,7 @@ def cmd_list(verbose: bool = False, json_mode: bool = False):
accounts = []
max_name = 0
for f in sorted(ACCOUNTS_DIR.glob("*.json")):
for f in sorted(account_files()):
name = f.stem
max_name = max(max_name, len(name))
active = is_current(f)
@@ -287,7 +299,7 @@ def _resolve_matching_account_by_email(email: str) -> Path | None:
return None
matches: list[Path] = []
for f in ACCOUNTS_DIR.glob("*.json"):
for f in account_files():
info = get_account_info(f) or {}
got = (info.get("email") or "").strip().lower()
if got and got == want:
@@ -620,7 +632,7 @@ def cmd_auto(json_mode=False):
import time
ensure_dirs()
accounts = [f.stem for f in ACCOUNTS_DIR.glob("*.json") if not f.name.startswith('.')]
accounts = [f.stem for f in account_files()]
if not accounts:
if json_mode:
print('{"error": "No accounts found"}')
@@ -631,7 +643,7 @@ def cmd_auto(json_mode=False):
# Save current account to restore if needed
original_account = None
if AUTH_FILE.exists():
for acct_file in ACCOUNTS_DIR.glob("*.json"):
for acct_file in account_files():
if acct_file.read_bytes() == AUTH_FILE.read_bytes():
original_account = acct_file.stem
break
@@ -750,7 +762,7 @@ def cmd_use(name):
if not source.exists():
print(f"❌ Account '{name}' not found.")
print("Available accounts:")
for f in ACCOUNTS_DIR.glob("*.json"):
for f in account_files():
print(f" - {f.stem}")
return
@@ -761,6 +773,34 @@ def cmd_use(name):
info = get_account_info(source)
print(f"✅ Switched to account: {name} ({info.get('email')})")
def cmd_remove(name: str):
ensure_dirs()
removed = []
targets = [
ACCOUNTS_DIR / f"{name}.json",
ACCOUNTS_DIR / f".{name}.quota.json",
ACCOUNTS_DIR / f"{name}.quota.json",
ACCOUNTS_DIR / f".{name}.cache.json",
ACCOUNTS_DIR / f"{name}.cache.json",
ACCOUNTS_DIR / f".{name}.meta.json",
ACCOUNTS_DIR / f"{name}.meta.json",
]
for p in targets:
if p.exists():
try:
p.unlink()
removed.append(p.name)
except Exception:
pass
if removed:
print(f"✅ Removed '{name}': {', '.join(removed)}")
else:
print(f" Nothing to remove for '{name}'")
def get_token_email(auth_path) -> str:
"""Extract email from a token file."""
info = get_account_info(auth_path) or {}
@@ -878,6 +918,9 @@ def main():
save_parser.add_argument("name", help="Name to save the account as")
save_parser.add_argument("--force", action="store_true", help="Force overwrite even if emails don't match")
rm_parser = subparsers.add_parser("remove", help="Remove account and related local artifacts")
rm_parser.add_argument("name", help="Account name to remove")
auto_parser = subparsers.add_parser("auto", help="Switch to the account with most quota available")
auto_parser.add_argument("--json", action="store_true", help="Output as JSON")
@@ -892,6 +935,8 @@ def main():
cmd_use(args.name)
elif args.command == "save":
cmd_save(args.name, force=bool(getattr(args, "force", False)))
elif args.command == "remove":
cmd_remove(args.name)
elif args.command == "auto":
cmd_auto(json_mode=bool(getattr(args, "json", False)))
else: