Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba991a2462 | |||
| e9455cbb86 |
4
SKILL.md
4
SKILL.md
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: 账号与凭据管理
|
||||
description: "通用账号 & 凭据 & 登录流程管理器。管理网页/RPA 账号、API Key/Token;支持 9 种登录策略(账密自动、扫码、2FA、SSO 等);提供加密本地存储(Fernet);提供 rpa_helpers 库供业务 skill 同进程调用 ensure_logged_in 完成多平台自动登录。涵盖物流、LLM、内容、开发、API 五类平台。"
|
||||
version: 2.0.17
|
||||
version: 2.0.19
|
||||
author: 深圳匠厂科技有限公司
|
||||
metadata:
|
||||
openclaw:
|
||||
@@ -28,7 +28,7 @@ allowed-tools:
|
||||
## 何时使用本技能
|
||||
|
||||
1. **安装/升级后初始化库与数据管理元数据**:`init-db`(宿主会自动调用;也可手工执行)
|
||||
2. **登记网页/RPA 账号**:`account add-web` — 平台 + 登录标识 + 自动生成 profile_dir;可选 `--auth-strategy` / `--session-persistent` / `--device-fingerprint`。
|
||||
2. **登记网页/RPA 账号**:`account add-web` — 平台 + 登录标识 + 自动生成 profile_dir;可选 `--auth-strategy` / `--session-persistent` / `--device-fingerprint`。数据管理「新增」已绑定该能力(`replaces: create`),勿用宿主直写库新建账号。
|
||||
3. **登记凭据(API Key / Token / 加密密码)**:`account add-secret` — `none` / `env` / `windows_credential` / `local_encrypted`。
|
||||
4. **查看/列出账号**:`account get/list` — JSON 输出;list 可按 `--login-id` / `--label` 筛选。
|
||||
5. **用人话定位账号**:`account resolve --login-id <手机号/用户名>` 或 `--label` / `--query`(不必先查数字 id)。
|
||||
|
||||
@@ -2,6 +2,80 @@
|
||||
"schemaVersion": 1,
|
||||
"skill": "account-manager",
|
||||
"actions": [
|
||||
{
|
||||
"id": "account-add-web",
|
||||
"label": "新增账号",
|
||||
"description": "登记网页/RPA 账号并自动创建浏览器 Profile 目录(走 account add-web,非宿主直写库)。",
|
||||
"replaces": "create",
|
||||
"placements": [],
|
||||
"executionProfile": "sync",
|
||||
"interaction": "form",
|
||||
"bind": {
|
||||
"tables": ["accounts"]
|
||||
},
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"required": ["platform", "accountLabel"],
|
||||
"properties": {
|
||||
"platform": {
|
||||
"type": "string",
|
||||
"title": "平台",
|
||||
"description": "平台键或显示名,如 cosco / 抖音"
|
||||
},
|
||||
"accountLabel": {
|
||||
"type": "string",
|
||||
"title": "账号名称"
|
||||
},
|
||||
"loginId": {
|
||||
"type": "string",
|
||||
"title": "登录账号"
|
||||
},
|
||||
"loginIdType": {
|
||||
"type": "string",
|
||||
"title": "登录标识类型",
|
||||
"default": "unknown"
|
||||
},
|
||||
"tenantId": {
|
||||
"type": "string",
|
||||
"title": "租户编号"
|
||||
},
|
||||
"environment": {
|
||||
"type": "string",
|
||||
"title": "环境",
|
||||
"default": "production"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"title": "角色",
|
||||
"default": "default"
|
||||
},
|
||||
"providerCode": {
|
||||
"type": "string",
|
||||
"title": "供应商代码"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"title": "入口链接"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entrypoint": {
|
||||
"type": "cli",
|
||||
"command": "account",
|
||||
"args": [
|
||||
"add-web",
|
||||
"--platform", "{{platform}}",
|
||||
"--label", "{{accountLabel}}",
|
||||
"--login-id", "{{loginId}}",
|
||||
"--login-id-type", "{{loginIdType}}",
|
||||
"--tenant-id", "{{tenantId}}",
|
||||
"--environment", "{{environment}}",
|
||||
"--role", "{{role}}",
|
||||
"--provider-code", "{{providerCode}}",
|
||||
"--url", "{{url}}"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "reveal-profile",
|
||||
"label": "打开文件位置",
|
||||
|
||||
@@ -6,6 +6,7 @@ SQLite 无原生表/字段 COMMENT;中文展示名称通过这两张元数据
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Iterable
|
||||
|
||||
INTERNAL_METADATA_TABLES = frozenset({"_jiangchang_tables", "_jiangchang_columns"})
|
||||
@@ -20,6 +21,26 @@ ACCOUNT_LEASES_TABLE = "account_leases"
|
||||
DATETIME_UNIX_SECONDS = "datetime_unix_seconds"
|
||||
STANDARD_TIMESTAMP_COLUMNS = frozenset({"created_at", "updated_at"})
|
||||
|
||||
# Data-management lookup: host resolves options_json object into select options.
|
||||
PLATFORM_KEY_LOOKUP_JSON = json.dumps(
|
||||
{
|
||||
"ref_table": "platforms",
|
||||
"value_column": "platform_key",
|
||||
"label_column": "display_name",
|
||||
"filter_column": "enabled",
|
||||
"filter_value": 1,
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
ACCOUNT_ID_LOOKUP_JSON = json.dumps(
|
||||
{
|
||||
"ref_table": "accounts",
|
||||
"value_column": "id",
|
||||
"label_column": "account_label",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
USER_BUSINESS_TABLES = (
|
||||
PLATFORMS_TABLE,
|
||||
ACCOUNTS_TABLE,
|
||||
@@ -123,7 +144,13 @@ ACCOUNTS_TABLE_METADATA = {
|
||||
|
||||
ACCOUNTS_COLUMN_METADATA: tuple[dict[str, object], ...] = (
|
||||
_col("id", "编号", description="账号唯一编号", editable=0),
|
||||
_col("platform_key", "平台", description="所属平台键"),
|
||||
_col(
|
||||
"platform_key",
|
||||
"平台",
|
||||
description="所属平台键(来自平台信息表)",
|
||||
display_type="lookup",
|
||||
options_json=PLATFORM_KEY_LOOKUP_JSON,
|
||||
),
|
||||
_col("account_label", "账号名称", description="人可读的账号名称"),
|
||||
_col("login_id", "登录账号", description="手机号、邮箱、用户名等登录标识"),
|
||||
_col("login_id_type", "登录标识类型", description="phone / email / username / unknown 等"),
|
||||
@@ -158,8 +185,20 @@ CREDENTIALS_TABLE_METADATA = {
|
||||
|
||||
CREDENTIALS_COLUMN_METADATA: tuple[dict[str, object], ...] = (
|
||||
_col("id", "编号", description="凭据唯一编号", editable=0),
|
||||
_col("account_id", "账号编号", description="关联的 accounts.id,可空"),
|
||||
_col("platform_key", "平台", description="所属平台键"),
|
||||
_col(
|
||||
"account_id",
|
||||
"账号编号",
|
||||
description="关联的 accounts.id,可空",
|
||||
display_type="lookup",
|
||||
options_json=ACCOUNT_ID_LOOKUP_JSON,
|
||||
),
|
||||
_col(
|
||||
"platform_key",
|
||||
"平台",
|
||||
description="所属平台键(来自平台信息表)",
|
||||
display_type="lookup",
|
||||
options_json=PLATFORM_KEY_LOOKUP_JSON,
|
||||
),
|
||||
_col("credential_label", "凭据名称", description="人可读的凭据名称"),
|
||||
_col("credential_type", "凭据类型", description="api_key / password / bearer_token 等"),
|
||||
_col("secret_storage", "密钥存储方式", description="none / env / windows_credential / local_encrypted", editable=0),
|
||||
|
||||
@@ -102,6 +102,44 @@ def test_sensitive_credential_fields_not_editable(metadata_db):
|
||||
assert int(searchable) == 0, column_name
|
||||
|
||||
|
||||
def test_account_and_credential_platform_lookups(metadata_db):
|
||||
import json
|
||||
|
||||
cur = metadata_db.cursor()
|
||||
for table_name, column_name in (
|
||||
(ACCOUNTS_TABLE, "platform_key"),
|
||||
(CREDENTIALS_TABLE, "platform_key"),
|
||||
):
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT display_type, options_json
|
||||
FROM _jiangchang_columns
|
||||
WHERE table_name = ? AND column_name = ?
|
||||
""",
|
||||
(table_name, column_name),
|
||||
)
|
||||
display_type, options_json = cur.fetchone()
|
||||
assert display_type == "lookup", table_name
|
||||
payload = json.loads(options_json)
|
||||
assert payload["ref_table"] == "platforms"
|
||||
assert payload["value_column"] == "platform_key"
|
||||
assert payload["label_column"] == "display_name"
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT display_type, options_json
|
||||
FROM _jiangchang_columns
|
||||
WHERE table_name = ? AND column_name = 'account_id'
|
||||
""",
|
||||
(CREDENTIALS_TABLE,),
|
||||
)
|
||||
display_type, options_json = cur.fetchone()
|
||||
assert display_type == "lookup"
|
||||
payload = json.loads(options_json)
|
||||
assert payload["ref_table"] == "accounts"
|
||||
assert payload["value_column"] == "id"
|
||||
|
||||
|
||||
def test_lease_token_not_editable(metadata_db):
|
||||
cur = metadata_db.cursor()
|
||||
cur.execute(
|
||||
|
||||
Reference in New Issue
Block a user