feat: account ensure-web (pick-or-create for first-run UX)
All checks were successful
技能自动化发布 / release (push) Successful in 5s

This commit is contained in:
2026-07-18 14:37:16 +08:00
parent 12b1fec0b9
commit e441b0c58e
11 changed files with 470 additions and 17 deletions

View File

@@ -4,7 +4,7 @@ CLI entry point: argv dispatch for account-manager v2.
Subcommand tree:
platform list/get/ensure
account add-web|add-secret|get|get-credential|list|pick-web|mark-session|mark-error|mark-used|open
account add-web|ensure-web|add-secret|get|get-credential|list|pick-web|mark-session|mark-error|mark-used|open
init-master-key|export-credentials|import-credentials
credential pick|resolve
lease release|list|cleanup
@@ -23,6 +23,7 @@ from service.account_crypto_commands import (
from service.account_service import (
cmd_account_add_secret,
cmd_account_add_web,
cmd_account_ensure_web,
cmd_account_get,
cmd_account_get_credential,
cmd_account_list,
@@ -82,6 +83,12 @@ _USAGE = """account-manager v2 — Credential & Browser Profile Manager
account pick-web --platform <p> [--environment <env>] [--tenant-id <t>]
[--role <role>] [--lease] [--ttl-sec 900]
[--holder <holder>] [--purpose <purpose>]
[--ensure] # 同 ensure-web无账号时自动登记再 pick
account ensure-web --platform <p> [--login-id <id>] [--label <label>]
[--environment <env>] [--tenant-id <t>] [--role <role>]
[--lease] [--ttl-sec 900] [--holder <h>] [--purpose <p>]
# 有账号则 pick零账号则按参数 add-web 后再 pick
# 有账号但均被租约占用时不新建,返回 LEASE_CONFLICT
account mark-session <id> --session-status <status>
account mark-error <id> --code <code> --message <msg>
account mark-used <id>
@@ -246,12 +253,14 @@ def main() -> None:
# ---- account subcommand ----
elif cmd == "account":
if len(av) < 3:
print("ERROR:CLI_BAD_ARGS account 需要子命令add-web / get / …)。")
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 == "ensure-web":
_cmd_ensure_web(av)
elif sub == "add-secret":
_cmd_add_secret(av)
elif sub == "get-credential":
@@ -543,11 +552,15 @@ def _cmd_pick_web_new(argv: list[str]) -> None:
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,
@@ -561,6 +574,61 @@ def _cmd_pick_web_new(argv: list[str]) -> None:
)
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", "unknown")
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 or "unknown",
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")