From 0a599b5facc578a4622dd249d326c97722bef539 Mon Sep 17 00:00:00 2001 From: chendelian <116870791@qq.com> Date: Sat, 4 Apr 2026 18:36:39 +0800 Subject: [PATCH] feat(account-manager): add list-json API for cross-skill orchestration --- account-manager/scripts/main.py | 158 +++++++++++++++++++++++++++++++- 1 file changed, 157 insertions(+), 1 deletion(-) diff --git a/account-manager/scripts/main.py b/account-manager/scripts/main.py index adc3760..6f2809f 100644 --- a/account-manager/scripts/main.py +++ b/account-manager/scripts/main.py @@ -586,6 +586,48 @@ def cmd_get(account_id): print(_runtime_paths_debug_text(), file=sys.stderr) +def cmd_list_json(platform_input: str, limit: int = 200) -> None: + """ + 跨技能接口:stdout 仅输出一行 JSON 数组,元素结构与 get 单条一致。 + 平台可为 all/全部 或各平台中文名/英文键;按 updated_at 倒序,最多 limit 条(上限 500)。 + """ + get_skill_logger().info("list_json filter=%r limit=%s", platform_input, limit) + init_db() + raw = (platform_input or "all").strip() + if not raw or raw.lower() == "all" or raw == "全部": + key = "all" + else: + key = resolve_platform_key(raw) + if not key: + print("ERROR:INVALID_PLATFORM_LIST_JSON 无法识别的平台名称。") + print("支持:" + _platform_list_cn_for_help()) + return + lim = max(1, min(int(limit), 500)) + conn = get_conn() + try: + cur = conn.cursor() + if key == "all": + cur.execute( + "SELECT id FROM accounts ORDER BY updated_at DESC, id DESC LIMIT ?", + (lim,), + ) + else: + cur.execute( + "SELECT id FROM accounts WHERE platform = ? " + "ORDER BY updated_at DESC, id DESC LIMIT ?", + (key, lim), + ) + ids = [r[0] for r in cur.fetchall()] + finally: + conn.close() + out = [] + for aid in ids: + acc = get_account_by_id(aid) + if acc: + out.append(acc) + print(json.dumps(out, ensure_ascii=False)) + + def cmd_pick_logged_in(platform_input: str): """ 机器可读跨技能接口:查询指定平台下「已登录」的一条账号(login_status=1,按 last_login_at 优先)。 @@ -629,6 +671,60 @@ def cmd_pick_logged_in(platform_input: str): print(json.dumps(acc, ensure_ascii=False)) +def cmd_pick_web(platform_input: str): + """ + 供 llm-manager 等:取该平台用于网页自动化的账号候选。 + 优先 login_status=1(与 pick-logged-in 一致);若无,则取该平台 updated_at 最新的一条, + 便于「已 add 未标登录」时仍打开 profile,在浏览器内登录后继续任务。 + 成功:stdout 仅一行 JSON(与 get 一致);失败:首行 ERROR:。 + """ + get_skill_logger().info("pick_web platform_input=%r", platform_input) + key = resolve_platform_key((platform_input or "").strip()) + if not key: + print("ERROR:INVALID_PLATFORM 无法识别的平台名称。") + print("支持:" + _platform_list_cn_for_help()) + return + + init_db() + conn = get_conn() + try: + cur = conn.cursor() + cur.execute( + """ + SELECT id FROM accounts + WHERE platform = ? AND login_status = 1 + ORDER BY (last_login_at IS NULL), last_login_at DESC + LIMIT 1 + """, + (key,), + ) + row = cur.fetchone() + if not row: + cur.execute( + """ + SELECT id FROM accounts + WHERE platform = ? + ORDER BY updated_at DESC, id DESC + LIMIT 1 + """, + (key,), + ) + row = cur.fetchone() + finally: + conn.close() + + if not row: + print("ERROR:NO_ACCOUNT 该平台在账号库中没有任何记录,请先执行 add。") + return + + acc = get_account_by_id(row[0]) + if not acc: + print("ERROR:ACCOUNT_NOT_FOUND") + print(_runtime_paths_debug_text(), file=sys.stderr) + return + print(json.dumps(acc, ensure_ascii=False)) + + def cmd_add(platform_input: str, phone: str): """添加账号:platform 可为中文展示名或英文键;手机号必填;同平台下同手机号不可重复。""" log = get_skill_logger() @@ -1371,13 +1467,42 @@ def _mark_login_status(account_id, success: bool): conn.close() +def cmd_set_login_status(account_id_str: str, status_str: str) -> None: + """ + 跨技能机器接口:回写 accounts.login_status。 + 成功:stdout 首行 OK:SET_LOGIN_STATUS 或 OK:CLEARED_LOGIN_STATUS,进程退出码 0。 + 失败:stdout 首行 ERROR:...,退出码 1。 + """ + aid_s = (account_id_str or "").strip() + st_s = (status_str or "").strip() + if not aid_s.isdigit(): + print("ERROR:INVALID_ACCOUNT_ID") + sys.exit(1) + if st_s not in ("0", "1"): + print("ERROR:INVALID_STATUS 须为 0 或 1") + sys.exit(1) + aid = int(aid_s) + init_db() + if get_account_by_id(aid) is None: + get_skill_logger().warning("set_login_status_not_found account_id=%r", aid) + print("ERROR:ACCOUNT_NOT_FOUND") + sys.exit(1) + ok = st_s == "1" + _mark_login_status(aid, ok) + get_skill_logger().info("set_login_status account_id=%s success=%s", aid, ok) + print("OK:SET_LOGIN_STATUS" if ok else "OK:CLEARED_LOGIN_STATUS") + + def _cli_print_full_usage() -> None: """总览(未带子命令或需要完整说明时)。""" print("用法概览(将 main.py 换为你的路径):") print(" python main.py add <平台中文名> <手机号>") print(" python main.py list [平台|all|全部]") - print(" python main.py pick-logged-in <平台> # 跨技能用:输出一行 JSON 或 ERROR") + print(" python main.py pick-logged-in <平台> # 跨技能用:仅已登录账号,一行 JSON 或 ERROR") + print(" python main.py pick-web <平台> # 跨技能用:优先已登录,否则最新一条账号") + print(" python main.py list-json <平台|all> [--limit N] # 跨技能用:一行 JSON 数组,元素同 get") print(" python main.py get ") + print(" python main.py set-login-status <0|1> # 跨技能回写登录态") print(" python main.py open ") print(" python main.py login ") print(" python main.py delete id ") @@ -1456,6 +1581,30 @@ if __name__ == "__main__": _cli_fail_need_account_id("get") sys.exit(1) cmd_get(sys.argv[2]) + elif cmd == "set-login-status": + if len(sys.argv) < 4: + print("ERROR:CLI_SET_LOGIN_STATUS_MISSING_ARGS") + print("用法:python main.py set-login-status <0|1>") + print("说明:供 llm-manager 等脚本回写登录态;成功时 stdout 首行以 OK: 开头。") + sys.exit(1) + cmd_set_login_status(sys.argv[2], sys.argv[3]) + elif cmd == "list-json": + if len(sys.argv) < 3: + print("ERROR:CLI_LIST_JSON_MISSING_PLATFORM") + print("用法:python main.py list-json <平台|all|全部> [--limit N]") + print("说明:跨技能编排;成功时 stdout 仅一行 JSON 数组(元素与 get 一致)。") + 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-logged-in": if len(sys.argv) < 3: print("ERROR:CLI_PICK_LOGGED_IN_MISSING_ARGS") @@ -1463,6 +1612,13 @@ if __name__ == "__main__": print("说明:供 llm-manager 等技能查询该平台已登录账号;成功时 stdout 仅一行 JSON。") sys.exit(1) cmd_pick_logged_in(sys.argv[2]) + elif cmd == "pick-web": + if len(sys.argv) < 3: + print("ERROR:CLI_PICK_WEB_MISSING_ARGS") + print("用法:python main.py pick-web <平台中文名或英文键>") + print("说明:供 llm-manager 等;优先已登录账号,否则返回该平台最新一条账号(未登录也可用于打开浏览器登录)。") + sys.exit(1) + cmd_pick_web(sys.argv[2]) elif cmd == "open": if len(sys.argv) < 3: _cli_fail_need_account_id("open")