Files
account-manager/scripts/cli/app.py
chendelian 3ce0cc40a1
All checks were successful
技能自动化发布 / release (push) Successful in 6s
Release v2.0.25 force-release lease row action
2026-09-12 16:18:36 +08:00

757 lines
26 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
CLI entry point: argv dispatch for account-manager v2.
Subcommand tree:
platform list/get/ensure
account add-web|copy|update|ensure-web|add-secret|get|get-credential|list|resolve|pick-web|mark-session|mark-error|mark-used|open|reveal-profile
init-master-key|export-credentials|import-credentials
credential pick|resolve
lease release|force-release|list|cleanup
(legacy) add|list|get|list-json|pick-web|open|delete
Machine commands output single-line JSON where appropriate.
"""
import sys
from typing import Optional
from service.account_crypto_commands import (
cmd_account_export_credentials,
cmd_account_import_credentials,
cmd_account_init_master_key,
)
from service.account_service import (
cmd_account_add_secret,
cmd_account_add_web,
cmd_account_copy,
cmd_account_ensure_web,
cmd_account_update,
cmd_account_get,
cmd_account_get_credential,
cmd_account_list,
cmd_account_mark_error,
cmd_account_mark_session,
cmd_account_mark_used,
cmd_account_pick_web,
cmd_account_resolve,
cmd_credential_pick,
cmd_credential_resolve,
cmd_delete_by_id,
cmd_delete_by_platform,
cmd_delete_by_platform_phone,
cmd_get,
cmd_init_db,
cmd_lease_cleanup,
cmd_lease_force_release,
cmd_lease_list,
cmd_lease_release,
cmd_list,
cmd_list_json,
cmd_pick_web,
cmd_platform_ensure,
cmd_platform_get,
cmd_platform_list,
)
from service.browser_service import cmd_open, cmd_reveal_profile
from util.constants import LOG_LOGGER_NAME, SKILL_SLUG
from util.logging_config import get_skill_logger, setup_skill_logging
from util.platforms import _platform_list_cn_for_help, resolve_platform_key
from util.runtime_paths import _maybe_print_paths_debug_cli
# =========================================================================
# Help text
# =========================================================================
_USAGE = """account-manager v2 — Credential & Browser Profile Manager
运行时 / 数据管理:
init-db # 幂等初始化本地库与数据管理中文元数据(宿主安装/升级会调用)
平台管理:
platform list [--domain logistics|llm|content]
platform get <platform>
platform ensure --key <key> --display-name <name> [--domain <d>]
[--url <url>] [--auth-strategy <s>]
账号管理:
account add-web --platform <p> [--login-id <id>] [--login-id-type <type>]
[--label <label>] [--tenant-id <t>] [--environment <env>]
[--role <role>] [--provider-code <code>] [--url <url>]
[--extra-json <json>] [--profile-dir <path>]
[--auth-strategy <s>] [--session-persistent 0|1] [--device-fingerprint <fp>]
account copy <id>
account update --id <id> [--label <label>] [--login-id <id>]
[--login-id-type <type>] [--url <url>] [--status active|disabled|needs_review]
account add-secret --platform <p> --credential-type <type>
--secret-storage env|windows_credential|none|local_encrypted
[--secret-ref <env_var>] [--secret-stdin]
[--label <label>] [--account-id <id>]
[--environment <env>] [--role <role>]
account get <id> [--with-credentials]
account get-credential <account_id> [--reveal --lease-token <token>]
account resolve [--id <id>] [--platform <p>] [--login-id <手机号/用户名>]
[--label <备注>] [--query <id或login_id或备注>]
# 用人话定位一条账号(成功输出同 account get)
account list [--platform <p>] [--environment <env>]
[--tenant-id <t>] [--role <role>]
[--login-id <id>] [--label <label>] [--limit N]
account pick-web --platform <p> [--environment <env>] [--tenant-id <t>]
[--role <role>] [--login-id <手机号/用户名>] [--label <备注>]
[--lease] [--ttl-sec 900]
[--holder <holder>] [--purpose <purpose>]
[--ensure] # 同 ensure-web:无账号时自动登记再 pick
account ensure-web --platform <p> [--login-id <手机号/用户名>] [--label <备注>]
[--environment <env>] [--tenant-id <t>] [--role <role>]
[--lease] [--ttl-sec 900] [--holder <h>] [--purpose <p>]
# 有账号则 pick;零账号则按参数 add-web 后再 pick
# 有账号但均被租约占用时不新建,返回 LEASE_CONFLICT
# 指定 --login-id/--label 时按该人读标识筛选/创建
account mark-session <id> --session-status <status>
account mark-error <id> --code <code> --message <msg>
account mark-used <id>
account open <id>
account reveal-profile <id>
account init-master-key [--print|--from-env|--rotate]
account export-credentials --plaintext
account import-credentials [--replace-all] < backup.json
凭据管理:
credential pick --platform <p> [--type <type>] [--environment <env>]
[--role <role>] [--reveal]
credential resolve --id <credential_id> [--reveal]
租约管理:
lease release <lease_token>
lease force-release --id <租约编号>
lease list [--active]
lease cleanup
浏览器 / Profile:
account open <id>
account reveal-profile <id> # 在文件管理器中打开 profile_dir
open <id> # 兼容别名
兼容入口(旧版):
get <id>
list-json <platform|all> [--limit N]
pick-web <platform>
list [platform|all]
add <platform> <phone>
delete id|platform <...>
"""
# =========================================================================
# Argument parsing helpers
# =========================================================================
def _get_opt(argv: list[str], flag: str, default=None):
"""Get value of --flag from argv, returning default if not found."""
if flag in argv:
idx = argv.index(flag)
if idx + 1 < len(argv):
return argv[idx + 1]
return default
def _has_flag(argv: list[str], flag: str) -> bool:
return flag in argv
def _get_int_opt(argv: list[str], flag: str, default: int) -> int:
v = _get_opt(argv, flag)
if v is not None:
try:
return int(v)
except ValueError:
return default
return default
def _get_all_opts(argv: list[str], flag: str) -> list[str]:
"""Collect all values for a repeatable flag (e.g. --platform-alias)."""
vals: list[str] = []
i = 0
while i < len(argv):
if argv[i] == flag and i + 1 < len(argv):
vals.append(argv[i + 1])
i += 2
else:
i += 1
return vals
def _parse_platform_aliases(argv: list[str]) -> list[str]:
aliases: list[str] = []
for raw in _get_all_opts(argv, "--platform-alias"):
for part in (raw or "").split(","):
s = part.strip()
if s and s not in aliases:
aliases.append(s)
return aliases
def _parse_platform_caller_meta(argv: list[str]):
from service.account_service import PlatformCallerMeta
display_name = _get_opt(argv, "--platform-display-name")
url = _get_opt(argv, "--platform-url")
domain = _get_opt(argv, "--platform-domain")
auth_strategy = _get_opt(argv, "--platform-auth-strategy")
aliases = _parse_platform_aliases(argv)
if not any([display_name, url, domain, auth_strategy, aliases]):
return None
return PlatformCallerMeta(
display_name=display_name,
url=url,
domain=domain,
auth_strategy=auth_strategy,
aliases=aliases,
)
# =========================================================================
# Main dispatch
# =========================================================================
def main() -> None:
setup_skill_logging(SKILL_SLUG, LOG_LOGGER_NAME)
log = get_skill_logger()
if len(sys.argv) < 2:
print(_USAGE)
sys.exit(1)
log.info("cli_start argv=%s", sys.argv)
av = sys.argv
cmd = av[1]
_maybe_print_paths_debug_cli()
# Determine if first arg is a platform key (for legacy shorthand)
plat_from_first = resolve_platform_key(cmd)
# ---- init-db(宿主 install/upgrade 标准入口)----
if cmd == "init-db":
sys.exit(cmd_init_db())
# ---- platform subcommand ----
if cmd == "platform":
if len(av) < 3:
print("ERROR:CLI_BAD_ARGS platform 需要子命令:list | get | ensure")
sys.exit(1)
sub = av[2]
if sub == "list":
domain = _get_opt(av, "--domain")
cmd_platform_list(domain)
elif sub == "get":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS platform get 需要 <platform>。")
sys.exit(1)
cmd_platform_get(av[3])
elif sub == "ensure":
import argparse as _ap
p = _ap.ArgumentParser(prog="platform ensure")
p.add_argument("--key", required=True)
p.add_argument("--display-name", default="")
p.add_argument("--domain", default="generic")
p.add_argument("--url", default="")
p.add_argument("--auth-strategy", default=None)
p.add_argument("--aliases", default=None,
help="JSON 数组字符串,如 '[\"1688\",\"阿里巴巴1688\"]'")
p.add_argument("--capabilities", default=None,
help='JSON 对象,如 \'{"web":true,"api_key":false,"rpa":true}\'')
args = p.parse_args(av[3:])
sys.exit(cmd_platform_ensure(
key=args.key,
display_name=args.display_name,
domain=args.domain,
url=args.url,
auth_strategy=args.auth_strategy,
aliases=args.aliases,
capabilities=args.capabilities,
))
else:
print("ERROR:CLI_BAD_ARGS platform 子命令必须是 list、get 或 ensure。")
sys.exit(1)
# ---- account subcommand ----
elif cmd == "account":
if len(av) < 3:
print("ERROR:CLI_BAD_ARGS account 需要子命令(add-web / ensure-web / get / …)。")
print(_USAGE)
sys.exit(1)
sub = av[2]
if sub == "add-web":
_cmd_add_web(av)
elif sub == "copy":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account copy 需要 <id>。")
sys.exit(1)
cmd_account_copy(av[3])
elif sub == "update":
_cmd_account_update(av)
elif sub == "ensure-web":
_cmd_ensure_web(av)
elif sub == "add-secret":
_cmd_add_secret(av)
elif sub == "get-credential":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account get-credential 需要 <account_id>。")
sys.exit(1)
_cmd_get_credential(av)
elif sub == "get":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account get 需要 <id>。")
sys.exit(1)
aid = av[3]
with_creds = _has_flag(av, "--with-credentials")
cmd_account_get(aid, include_credentials=with_creds)
elif sub == "list":
_cmd_account_list(av)
elif sub == "resolve":
_cmd_account_resolve(av)
elif sub == "pick-web":
_cmd_pick_web_new(av)
elif sub == "mark-session":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account mark-session 需要 <id>。")
sys.exit(1)
aid = av[3]
ss = _get_opt(av, "--session-status", "unknown")
cmd_account_mark_session(aid, ss)
elif sub == "mark-error":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account mark-error 需要 <id>。")
sys.exit(1)
aid = av[3]
ec = _get_opt(av, "--code", "")
em = _get_opt(av, "--message", "")
cmd_account_mark_error(aid, ec, em)
elif sub == "mark-used":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account mark-used 需要 <id>。")
sys.exit(1)
aid = av[3]
cmd_account_mark_used(aid)
elif sub == "open":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account open 需要 <id>。")
sys.exit(1)
cmd_open(av[3])
elif sub == "reveal-profile":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS account reveal-profile 需要 <id>。")
sys.exit(1)
cmd_reveal_profile(av[3])
elif sub == "init-master-key":
cmd_account_init_master_key(av)
elif sub == "export-credentials":
cmd_account_export_credentials(av)
elif sub == "import-credentials":
cmd_account_import_credentials(av)
else:
print("ERROR:CLI_BAD_ARGS 未知的 account 子命令。")
print(_USAGE)
sys.exit(1)
# ---- credential subcommand ----
elif cmd == "credential":
if len(av) < 3:
print("ERROR:CLI_BAD_ARGS credential 需要子命令:pick | resolve")
sys.exit(1)
sub = av[2]
if sub == "pick":
_cmd_cred_pick(av)
elif sub == "resolve":
_cmd_cred_resolve(av)
else:
print("ERROR:CLI_BAD_ARGS credential 子命令必须是 pick 或 resolve。")
sys.exit(1)
# ---- lease subcommand ----
elif cmd == "lease":
if len(av) < 3:
print("ERROR:CLI_BAD_ARGS lease 需要子命令:release | force-release | list | cleanup")
sys.exit(1)
sub = av[2]
if sub == "release":
if len(av) < 4:
print("ERROR:CLI_BAD_ARGS lease release 需要 <lease_token>。")
sys.exit(1)
cmd_lease_release(av[3])
elif sub == "force-release":
lease_id = _get_opt(av, "--id")
if lease_id is None and len(av) >= 4 and not str(av[3]).startswith("-"):
lease_id = av[3]
if lease_id is None:
print("ERROR:CLI_BAD_ARGS lease force-release 需要 --id <租约编号>。")
sys.exit(1)
try:
cmd_lease_force_release(int(lease_id))
except ValueError:
print("ERROR:CLI_BAD_ARGS 租约编号必须是数字。")
sys.exit(1)
elif sub == "list":
active = _has_flag(av, "--active")
cmd_lease_list(active)
elif sub == "cleanup":
cmd_lease_cleanup()
else:
print("ERROR:CLI_BAD_ARGS lease 子命令必须是 release、force-release、list 或 cleanup。")
sys.exit(1)
# ---- Legacy aliases ----
elif cmd == "get":
if len(sys.argv) < 3:
print("ERROR:CLI_GET_MISSING_ID")
sys.exit(1)
cmd_get(sys.argv[2])
elif cmd == "list-json":
if len(sys.argv) < 3:
print("ERROR:CLI_LIST_JSON_MISSING_PLATFORM")
sys.exit(1)
av = sys.argv[2:]
platform_arg = av[0]
lim = 200
if "--limit" in av:
i = av.index("--limit")
if i + 1 < len(av):
try:
lim = int(av[i + 1])
except ValueError:
pass
cmd_list_json(platform_arg, limit=lim)
elif cmd == "pick-web":
if len(sys.argv) < 3:
print("ERROR:CLI_PICK_WEB_MISSING_ARGS")
sys.exit(1)
cmd_pick_web(sys.argv[2])
elif cmd == "open":
if len(sys.argv) < 3:
print("ERROR:CLI_OPEN_MISSING_ID")
sys.exit(1)
cmd_open(sys.argv[2])
elif cmd == "list":
platform_arg = sys.argv[2] if len(sys.argv) >= 3 else "all"
cmd_list(platform_arg)
elif cmd == "add":
if len(sys.argv) < 4:
print("ERROR:CLI_ADD_MISSING_ARGS")
sys.exit(1)
# Legacy add maps to add-web for backward compat
cmd_account_add_web(
platform_input=sys.argv[2],
login_id=sys.argv[3],
login_id_type="phone",
label=None,
tenant_id=None,
environment="production",
role="default",
provider_code=None,
url=None,
extra_json_str=None,
profile_dir_override=None,
)
elif cmd == "delete":
if len(sys.argv) < 4:
print("ERROR:CLI_DELETE_MISSING_ARGS")
sys.exit(1)
mode = (sys.argv[2] or "").strip().lower()
if mode == "id":
cmd_delete_by_id(sys.argv[3])
elif mode == "platform":
if len(sys.argv) >= 5:
cmd_delete_by_platform_phone(sys.argv[3], sys.argv[4])
else:
cmd_delete_by_platform(sys.argv[3])
else:
print(f"ERROR:CLI_DELETE_BAD_MODE 不支持的删除方式「{sys.argv[2]}」。")
sys.exit(1)
# ---- Platform shorthand: "python main.py <platform>" ----
elif plat_from_first:
cmd_list(sys.argv[1])
# ---- Unknown ----
else:
print(f"ERROR:CLI_UNKNOWN_OR_BAD_ARGS 子命令「{cmd}」无法识别。")
print()
print(_USAGE)
sys.exit(1)
# =========================================================================
# Sub-parsers for complex commands
# =========================================================================
def _cmd_add_web(argv: list[str]) -> None:
plat = _get_opt(argv, "--platform", "")
login_id = _get_opt(argv, "--login-id")
login_id_type = _get_opt(argv, "--login-id-type")
label = _get_opt(argv, "--label")
tenant_id = _get_opt(argv, "--tenant-id")
environment = _get_opt(argv, "--environment", "production")
role = _get_opt(argv, "--role", "default")
provider_code = _get_opt(argv, "--provider-code")
url = _get_opt(argv, "--url")
extra_json_str = _get_opt(argv, "--extra-json")
profile_dir_override = _get_opt(argv, "--profile-dir")
auth_strategy = _get_opt(argv, "--auth-strategy")
session_persistent_raw = _get_opt(argv, "--session-persistent")
device_fingerprint = _get_opt(argv, "--device-fingerprint")
session_persistent: Optional[int] = None
if session_persistent_raw is not None:
try:
session_persistent = int(session_persistent_raw)
except ValueError:
print("ERROR:CLI_BAD_ARGS --session-persistent 必须是整数(0 或 1)。")
return
if not plat:
print("ERROR:CLI_BAD_ARGS account add-web 需要 --platform <platform>。")
return
platform_meta = _parse_platform_caller_meta(argv)
cmd_account_add_web(
platform_input=plat,
login_id=login_id,
login_id_type=login_id_type,
label=label,
tenant_id=tenant_id,
environment=environment,
role=role,
provider_code=provider_code,
url=url,
extra_json_str=extra_json_str,
profile_dir_override=profile_dir_override,
auth_strategy=auth_strategy,
session_persistent=session_persistent,
device_fingerprint=device_fingerprint,
platform_meta=platform_meta,
)
def _cmd_account_update(argv: list[str]) -> None:
from db.accounts_repo import _UNSET
aid = _get_opt(argv, "--id")
if not aid and len(argv) >= 4 and not str(argv[3]).startswith("-"):
aid = argv[3]
label = _get_opt(argv, "--label")
login_id_type = _get_opt(argv, "--login-id-type")
status = _get_opt(argv, "--status")
login_id = _UNSET
if "--login-id" in argv:
login_id = _get_opt(argv, "--login-id") or ""
url = _UNSET
if "--url" in argv:
url = _get_opt(argv, "--url") or ""
if not aid:
print("ERROR:CLI_BAD_ARGS account update 需要 --id <id>。")
return
cmd_account_update(
aid,
label=label,
login_id=login_id,
login_id_type=login_id_type,
url=url,
status=status,
)
def _cmd_get_credential(argv: list[str]) -> None:
aid_raw = argv[3]
try:
aid = int(aid_raw)
except ValueError:
print(f"ERROR:CLI_BAD_ARGS account_id 必须是整数:{aid_raw}")
return
reveal = _has_flag(argv, "--reveal")
lease_token = _get_opt(argv, "--lease-token")
cmd_account_get_credential(aid, reveal=reveal, lease_token=lease_token)
def _cmd_add_secret(argv: list[str]) -> None:
plat = _get_opt(argv, "--platform", "")
ctype = _get_opt(argv, "--credential-type", "api_key")
label = _get_opt(argv, "--label")
storage = _get_opt(argv, "--secret-storage", "env")
stdin_mode = _has_flag(argv, "--secret-stdin")
sref = _get_opt(argv, "--secret-ref")
aid = _get_int_opt(argv, "--account-id", 0) or None
env = _get_opt(argv, "--environment", "production")
role = _get_opt(argv, "--role", "api")
extra_json_str = _get_opt(argv, "--extra-json")
if not plat:
print("ERROR:CLI_BAD_ARGS account add-secret 需要 --platform <platform>。")
return
cmd_account_add_secret(
platform_input=plat,
credential_type=ctype,
label=label,
secret_storage=storage,
secret_stdin=stdin_mode,
secret_ref=sref,
account_id=aid,
environment=env,
role=role,
extra_json_str=extra_json_str,
)
def _cmd_account_list(argv: list[str]) -> None:
plat = _get_opt(argv, "--platform")
env = _get_opt(argv, "--environment")
tenant = _get_opt(argv, "--tenant-id")
role = _get_opt(argv, "--role")
login_id = _get_opt(argv, "--login-id")
label = _get_opt(argv, "--label")
limit = _get_int_opt(argv, "--limit", 200)
cmd_account_list(
platform_input=plat,
environment=env,
tenant_id=tenant,
role=role,
login_id=login_id,
label=label,
limit=limit,
)
def _cmd_account_resolve(argv: list[str]) -> None:
cmd_account_resolve(
account_id=_get_opt(argv, "--id"),
platform_input=_get_opt(argv, "--platform"),
login_id=_get_opt(argv, "--login-id"),
label=_get_opt(argv, "--label"),
query=_get_opt(argv, "--query"),
)
def _cmd_pick_web_new(argv: list[str]) -> None:
plat = _get_opt(argv, "--platform", "")
env = _get_opt(argv, "--environment")
tenant = _get_opt(argv, "--tenant-id")
role = _get_opt(argv, "--role")
login_id = _get_opt(argv, "--login-id")
label = _get_opt(argv, "--label")
do_lease = _has_flag(argv, "--lease")
ttl = _get_int_opt(argv, "--ttl-sec", 900)
holder = _get_opt(argv, "--holder")
purpose = _get_opt(argv, "--purpose")
do_ensure = _has_flag(argv, "--ensure")
if not plat:
print("ERROR:CLI_BAD_ARGS account pick-web 需要 --platform <platform>。")
return
platform_meta = _parse_platform_caller_meta(argv)
if do_ensure:
_cmd_ensure_web(argv)
return
cmd_account_pick_web(
platform_input=plat,
environment=env,
tenant_id=tenant,
role=role,
login_id=login_id,
label=label,
do_lease=do_lease,
ttl_sec=ttl,
holder=holder,
purpose=purpose,
platform_meta=platform_meta,
)
def _cmd_ensure_web(argv: list[str]) -> None:
plat = _get_opt(argv, "--platform", "")
login_id = _get_opt(argv, "--login-id")
login_id_type = _get_opt(argv, "--login-id-type")
label = _get_opt(argv, "--label")
tenant_id = _get_opt(argv, "--tenant-id")
environment = _get_opt(argv, "--environment")
role = _get_opt(argv, "--role")
provider_code = _get_opt(argv, "--provider-code")
url = _get_opt(argv, "--url")
extra_json_str = _get_opt(argv, "--extra-json")
profile_dir_override = _get_opt(argv, "--profile-dir")
auth_strategy = _get_opt(argv, "--auth-strategy")
session_persistent_raw = _get_opt(argv, "--session-persistent")
device_fingerprint = _get_opt(argv, "--device-fingerprint")
do_lease = _has_flag(argv, "--lease")
ttl = _get_int_opt(argv, "--ttl-sec", 900)
holder = _get_opt(argv, "--holder")
purpose = _get_opt(argv, "--purpose")
session_persistent: Optional[int] = None
if session_persistent_raw is not None:
try:
session_persistent = int(session_persistent_raw)
except ValueError:
print("ERROR:CLI_BAD_ARGS --session-persistent 必须是整数(0 或 1)。")
return
if not plat:
print("ERROR:CLI_BAD_ARGS account ensure-web 需要 --platform <platform>。")
return
platform_meta = _parse_platform_caller_meta(argv)
cmd_account_ensure_web(
platform_input=plat,
login_id=login_id,
login_id_type=login_id_type,
label=label,
tenant_id=tenant_id,
environment=environment,
role=role,
provider_code=provider_code,
url=url,
extra_json_str=extra_json_str,
profile_dir_override=profile_dir_override,
auth_strategy=auth_strategy,
session_persistent=session_persistent,
device_fingerprint=device_fingerprint,
do_lease=do_lease,
ttl_sec=ttl,
holder=holder,
purpose=purpose,
platform_meta=platform_meta,
)
def _cmd_cred_pick(argv: list[str]) -> None:
plat = _get_opt(argv, "--platform", "")
ctype = _get_opt(argv, "--type")
env = _get_opt(argv, "--environment")
role = _get_opt(argv, "--role")
reveal = _has_flag(argv, "--reveal")
if not plat:
print("ERROR:CLI_BAD_ARGS credential pick 需要 --platform <platform>。")
return
cmd_credential_pick(
platform_input=plat,
credential_type=ctype,
environment=env,
role=role,
reveal=reveal,
)
def _cmd_cred_resolve(argv: list[str]) -> None:
cid = _get_int_opt(argv, "--id", 0)
reveal = _has_flag(argv, "--reveal")
if cid <= 0:
print("ERROR:CLI_BAD_ARGS credential resolve 需要 --id <credential_id>。")
return
cmd_credential_resolve(cid, reveal=reveal)
if __name__ == "__main__":
main()