licos-platform-cli 0.5.1__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/PKG-INFO +10 -3
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/README.md +8 -1
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/pyproject.toml +2 -2
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/help_commands.py +22 -11
- licos_platform_cli-0.6.0/src/licos_platform_cli/identity.py +26 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/knowledge_commands.py +68 -45
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/ontology_commands.py +6 -3
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/user_commands.py +19 -7
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/tests/test_cli.py +17 -6
- licos_platform_cli-0.6.0/tests/test_identity.py +31 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/tests/test_user.py +7 -3
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/.gitignore +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/__init__.py +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/database_commands.py +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/main.py +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/oauth_commands.py +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/project_config_commands.py +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/storage_commands.py +0 -0
- {licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/tests/test_project_config.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: licos-platform-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: LICOS platform CLI
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
|
-
Requires-Dist: licos-platform-sdk>=0.
|
|
6
|
+
Requires-Dist: licos-platform-sdk>=0.7.0
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
|
|
9
9
|
# licos-platform-cli
|
|
@@ -18,7 +18,7 @@ licos-platform user me --workspace-id <执行工作空间ID>
|
|
|
18
18
|
licos-platform help user me
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
用户接口默认使用 `LICOS_CURRENT_USER_ID` 指定的容器执行用户换取 Token。它不代表网页登录者。平台地址、服务凭证和项目工作空间沿用运行时配置。
|
|
22
22
|
多用户请求可将当前使用者 Token 通过标准输入传入,不将 Token 放在命令行参数中:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
@@ -31,3 +31,10 @@ licos-platform user me --token-stdin
|
|
|
31
31
|
主部门、全部所属部门、组织任职、主岗位和主职务。部门含名称路径、ID 路径;
|
|
32
32
|
无部门/任职时保持 `[]`/`null`。缺少当前使用者身份或 Token 失效时返回非零退出码,
|
|
33
33
|
不改用项目所有者。Token 和内部服务凭证不回显。
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## 身份选择(0.6.0 起)
|
|
37
|
+
|
|
38
|
+
`user me`、`knowledge enterprise …`、`ontology …` 均支持 `--token-stdin`。HTTP 服务调用这些命令时必须从标准输入传本次网页登录 Token;独立 CLI 不传此选项时按 `LICOS_CURRENT_USER_ID` 换 Token,缺少该变量则报错。
|
|
39
|
+
|
|
40
|
+
普通 `knowledge …` 命令默认使用项目身份,`--token-stdin` 可显式按调用用户授权。数据库、存储和 OAuth 应用管理仍使用项目身份。空 Token、失效 Token 不切换身份。完整接口分类见仓库 `tools/IDENTITY.md`。
|
|
@@ -10,7 +10,7 @@ licos-platform user me --workspace-id <执行工作空间ID>
|
|
|
10
10
|
licos-platform help user me
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
用户接口默认使用 `LICOS_CURRENT_USER_ID` 指定的容器执行用户换取 Token。它不代表网页登录者。平台地址、服务凭证和项目工作空间沿用运行时配置。
|
|
14
14
|
多用户请求可将当前使用者 Token 通过标准输入传入,不将 Token 放在命令行参数中:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
@@ -23,3 +23,10 @@ licos-platform user me --token-stdin
|
|
|
23
23
|
主部门、全部所属部门、组织任职、主岗位和主职务。部门含名称路径、ID 路径;
|
|
24
24
|
无部门/任职时保持 `[]`/`null`。缺少当前使用者身份或 Token 失效时返回非零退出码,
|
|
25
25
|
不改用项目所有者。Token 和内部服务凭证不回显。
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
## 身份选择(0.6.0 起)
|
|
29
|
+
|
|
30
|
+
`user me`、`knowledge enterprise …`、`ontology …` 均支持 `--token-stdin`。HTTP 服务调用这些命令时必须从标准输入传本次网页登录 Token;独立 CLI 不传此选项时按 `LICOS_CURRENT_USER_ID` 换 Token,缺少该变量则报错。
|
|
31
|
+
|
|
32
|
+
普通 `knowledge …` 命令默认使用项目身份,`--token-stdin` 可显式按调用用户授权。数据库、存储和 OAuth 应用管理仍使用项目身份。空 Token、失效 Token 不切换身份。完整接口分类见仓库 `tools/IDENTITY.md`。
|
|
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "licos-platform-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.6.0"
|
|
8
8
|
description = "LICOS platform CLI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
dependencies = [
|
|
12
|
-
"licos-platform-sdk>=0.
|
|
12
|
+
"licos-platform-sdk>=0.7.0",
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
[project.scripts]
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/help_commands.py
RENAMED
|
@@ -379,7 +379,7 @@ KNOWLEDGE_HELP = {
|
|
|
379
379
|
"Do not manage graph/ACL internals from generated application code.",
|
|
380
380
|
"Search all accessible datasets by default; pass dataset IDs or names only when the user explicitly asks for specific datasets.",
|
|
381
381
|
"For text imports, the SDK sends UTF-8 text as a text/plain base64 document through the platform API.",
|
|
382
|
-
"Enterprise commands
|
|
382
|
+
"Enterprise commands use --token-stdin or the standalone CLI user LICOS_CURRENT_USER_ID. Tenant scope and permissions come from the current user token; never pass or invent tenant IDs.",
|
|
383
383
|
"Enterprise tree supports STANDARD, GRAPH, and OBJECT_STORAGE type filters. Current enterprise APIs support retrieve and list_files only.",
|
|
384
384
|
"Validate enterprise knowledge references before retrieval or listing when an Agent receives IDs from conversation context. Manage enterprise resources through the platform knowledge IFrame.",
|
|
385
385
|
"Use document-url/document-download-link for temporary access URLs; do not construct storage URLs.",
|
|
@@ -387,8 +387,8 @@ KNOWLEDGE_HELP = {
|
|
|
387
387
|
"sdk": {
|
|
388
388
|
"python": "from licos_platform_sdk import knowledge\nknowledge.add_text('FAQ content', dataset_name='project_docs')\nresults = knowledge.search('How to reset password?')",
|
|
389
389
|
"node": "import { knowledge } from '@kmlckj/licos-platform-sdk';\nawait knowledge.addText('FAQ content', { datasetName: 'project_docs' });\nconst results = await knowledge.search('How to reset password?');",
|
|
390
|
-
"enterprise_python": "from licos_platform_sdk import enterprise_knowledge\nresources = enterprise_knowledge.tree()\nresult = enterprise_knowledge.retrieve('安全规范', 'source-id')",
|
|
391
|
-
"enterprise_node": "import { enterpriseKnowledge } from '@kmlckj/licos-platform-sdk';\nconst resources = await enterpriseKnowledge.tree();\nconst result = await enterpriseKnowledge.retrieve('安全规范', 'source-id');",
|
|
390
|
+
"enterprise_python": "from licos_platform_sdk import enterprise_knowledge\nresources = enterprise_knowledge.tree(user_token=token)\nresult = enterprise_knowledge.retrieve('安全规范', 'source-id', user_token=token)",
|
|
391
|
+
"enterprise_node": "import { enterpriseKnowledge } from '@kmlckj/licos-platform-sdk';\nconst resources = await enterpriseKnowledge.tree({ userToken: token });\nconst result = await enterpriseKnowledge.retrieve('安全规范', 'source-id', { userToken: token });",
|
|
392
392
|
},
|
|
393
393
|
"commands": {'runtime': {'description': 'Show knowledge runtime status and capabilities.',
|
|
394
394
|
'parameters': [],
|
|
@@ -798,27 +798,28 @@ ONTOLOGY_HELP = {
|
|
|
798
798
|
"Resolve elements by stable IDs before querying context, model checks, or mapped data.",
|
|
799
799
|
"READ tools query state, PREPARE tools validate a change draft, and PERSIST tools apply an explicitly confirmed draft.",
|
|
800
800
|
"PERSIST commands require --confirm. Never reuse a catalog result after its catalogVersion changes.",
|
|
801
|
-
"实时订阅由项目后端 SDK
|
|
801
|
+
"实时订阅由项目后端 SDK 完成,必须传入本次认证会话 Token;CLI 不提供常驻 WebSocket 命令。",
|
|
802
802
|
],
|
|
803
803
|
"realtimeSdk": {
|
|
804
|
-
"node": "const subscription = await ontology.subscribeRealtime({ elementIds, attributeIds });\ntry { for await (const event of subscription) { sendBusinessEvent(event); } }\nfinally { await subscription.close(); }",
|
|
805
|
-
"python": "with ontology.subscribe_realtime(element_ids, attribute_ids=attribute_ids) as subscription:\n for event in subscription:\n send_business_event(event)",
|
|
806
|
-
"minimum_versions": {"node": "0.
|
|
804
|
+
"node": "const subscription = await ontology.subscribeRealtime({ elementIds, attributeIds }, { userToken: token });\ntry { for await (const event of subscription) { sendBusinessEvent(event); } }\nfinally { await subscription.close(); }",
|
|
805
|
+
"python": "with ontology.subscribe_realtime(element_ids, attribute_ids=attribute_ids, user_token=token) as subscription:\n for event in subscription:\n send_business_event(event)",
|
|
806
|
+
"minimum_versions": {"node": "0.12.0", "python": "0.7.0"},
|
|
807
807
|
"parameters": {
|
|
808
|
+
"userToken / user_token": "必填,本次认证会话的用户 Token,不含 Bearer 前缀。",
|
|
808
809
|
"elementIds / element_ids": "必填,非空字符串 ID 数组;已解析且授权的元素,不递归子元素。",
|
|
809
810
|
"attributeIds / attribute_ids": "可选,字符串 ID 数组;省略或空数组表示所选元素的全部授权属性。",
|
|
810
811
|
},
|
|
811
812
|
"returns": "收到订阅确认后返回订阅对象;单消费者迭代 property.changed 原始业务事件,close 取消订阅。Node 使用异步迭代,Python 使用同步 with/for,异步服务放入工作线程。",
|
|
812
|
-
"errors": "创建错误直接抛出,后续错误从迭代器抛出;401
|
|
813
|
+
"errors": "创建错误直接抛出,后续错误从迭代器抛出;401/403 终止,由调用方更新 Token;网络中断默认使用原 Token 持续重连并重新检查权限。不得把获取连接计划当成订阅成功。",
|
|
813
814
|
"reference": "industrial-ontology/references/realtime-sdk.md",
|
|
814
815
|
},
|
|
815
816
|
"sdk": {
|
|
816
|
-
"python": "from licos_platform_sdk import ontology\ncatalog = ontology.search_tools('查询设备实时数据')\nselected = next((item for item in catalog['items'] if item['selection'] == 'MATCH' and item['mode'] == 'READ' and item['definition']['function']['name'] == requested_tool_name), None)\nif selected is None:\n raise RuntimeError('当前目录中没有匹配的只读本体工具')\n# 按 selected['definition']['function']['parameters'] 校验参数后调用精确函数名。",
|
|
817
|
-
"node": "import { ontology } from '@kmlckj/licos-platform-sdk';\nconst catalog = await ontology.searchTools('查询设备实时数据');\nconst selected = catalog.items.find((item) => item.selection === 'MATCH' && item.mode === 'READ' && item.definition.function.name === requestedToolName);\nif (!selected) throw new Error('当前目录中没有匹配的只读本体工具');\n// 按 selected.definition.function.parameters 校验参数后调用精确函数名。",
|
|
817
|
+
"python": "from licos_platform_sdk import ontology\ncatalog = ontology.search_tools('查询设备实时数据', user_token=token)\nselected = next((item for item in catalog['items'] if item['selection'] == 'MATCH' and item['mode'] == 'READ' and item['definition']['function']['name'] == requested_tool_name), None)\nif selected is None:\n raise RuntimeError('当前目录中没有匹配的只读本体工具')\n# 按 selected['definition']['function']['parameters'] 校验参数后调用精确函数名。",
|
|
818
|
+
"node": "import { ontology } from '@kmlckj/licos-platform-sdk';\nconst catalog = await ontology.searchTools('查询设备实时数据', { userToken: token });\nconst selected = catalog.items.find((item) => item.selection === 'MATCH' && item.mode === 'READ' && item.definition.function.name === requestedToolName);\nif (!selected) throw new Error('当前目录中没有匹配的只读本体工具');\n// 按 selected.definition.function.parameters 校验参数后调用精确函数名。",
|
|
818
819
|
},
|
|
819
820
|
"commands": {
|
|
820
821
|
"search": {
|
|
821
|
-
"description": "Search the
|
|
822
|
+
"description": "Search the user catalog; use --token-stdin for a web request or LICOS_CURRENT_USER_ID for standalone CLI.",
|
|
822
823
|
"parameters": [
|
|
823
824
|
{"name": "query", "required": True, "description": "Natural-language capability query."},
|
|
824
825
|
{"name": "--limit", "required": False, "description": "Result count from 1 to 10; default 5."},
|
|
@@ -850,6 +851,16 @@ HELP_TOPICS = {
|
|
|
850
851
|
"ontology": ONTOLOGY_HELP,
|
|
851
852
|
}
|
|
852
853
|
|
|
854
|
+
for topic in (KNOWLEDGE_HELP, ONTOLOGY_HELP):
|
|
855
|
+
for command_name, command_help in topic["commands"].items():
|
|
856
|
+
user_scoped = topic is ONTOLOGY_HELP or command_name.startswith("enterprise-")
|
|
857
|
+
command_help["parameters"].append({
|
|
858
|
+
"name": "--token-stdin", "required": False,
|
|
859
|
+
"description": "Read this request's user Token from stdin; otherwise " + (
|
|
860
|
+
"exchange LICOS_CURRENT_USER_ID for standalone CLI." if user_scoped else "use project identity."
|
|
861
|
+
),
|
|
862
|
+
})
|
|
863
|
+
|
|
853
864
|
|
|
854
865
|
def _set_handler(parser: argparse.ArgumentParser, handler: Handler) -> None:
|
|
855
866
|
parser.set_defaults(handler=handler)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Select the CLI execution identity without changing SDK or process state."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from licos_platform_sdk import ConfigurationError, runtime_user_token
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def user_token(args) -> str:
|
|
10
|
+
if args.token_stdin:
|
|
11
|
+
token = sys.stdin.read().strip()
|
|
12
|
+
if not token:
|
|
13
|
+
raise ConfigurationError("--token-stdin requires a nonempty user Token")
|
|
14
|
+
return token
|
|
15
|
+
user_id = os.environ.get("LICOS_CURRENT_USER_ID", "").strip()
|
|
16
|
+
if not user_id:
|
|
17
|
+
raise ConfigurationError("CLI user identity requires LICOS_CURRENT_USER_ID or --token-stdin")
|
|
18
|
+
return runtime_user_token(user_id)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def add_user_token_option(parser) -> None:
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--token-stdin",
|
|
24
|
+
action="store_true",
|
|
25
|
+
help="Read the caller Token from stdin; otherwise use LICOS_CURRENT_USER_ID",
|
|
26
|
+
)
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/knowledge_commands.py
RENAMED
|
@@ -4,15 +4,27 @@ import argparse
|
|
|
4
4
|
from typing import Any, Callable
|
|
5
5
|
|
|
6
6
|
from licos_platform_sdk import enterprise_knowledge, knowledge
|
|
7
|
-
|
|
7
|
+
from .identity import add_user_token_option, user_token
|
|
8
8
|
|
|
9
9
|
Handler = Callable[[argparse.Namespace], Any]
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def _set_handler(parser: argparse.ArgumentParser, handler: Handler) -> None:
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"--token-stdin", action="store_true", help="Use the request Token from stdin; omission uses project identity"
|
|
15
|
+
)
|
|
13
16
|
parser.set_defaults(handler=handler)
|
|
14
17
|
|
|
15
18
|
|
|
19
|
+
def _set_user_handler(parser, handler):
|
|
20
|
+
add_user_token_option(parser)
|
|
21
|
+
parser.set_defaults(handler=handler)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _project_identity(args):
|
|
25
|
+
return {"user_token": user_token(args)} if args.token_stdin else {}
|
|
26
|
+
|
|
27
|
+
|
|
16
28
|
def _chunk_config(args: argparse.Namespace) -> knowledge.ChunkConfig | None:
|
|
17
29
|
if not any(
|
|
18
30
|
[
|
|
@@ -35,12 +47,12 @@ def _dataset_selector(args: argparse.Namespace) -> dict[str, str | None]:
|
|
|
35
47
|
return {"dataset_id": args.dataset_id, "dataset_name": args.dataset}
|
|
36
48
|
|
|
37
49
|
|
|
38
|
-
def _cmd_runtime(
|
|
39
|
-
return knowledge.runtime()
|
|
50
|
+
def _cmd_runtime(args: argparse.Namespace) -> Any:
|
|
51
|
+
return knowledge.runtime(**_project_identity(args))
|
|
40
52
|
|
|
41
53
|
|
|
42
|
-
def _cmd_model_catalog(
|
|
43
|
-
return knowledge.model_catalog()
|
|
54
|
+
def _cmd_model_catalog(args: argparse.Namespace) -> Any:
|
|
55
|
+
return knowledge.model_catalog(**_project_identity(args))
|
|
44
56
|
|
|
45
57
|
|
|
46
58
|
def _cmd_datasets(args: argparse.Namespace) -> Any:
|
|
@@ -50,6 +62,7 @@ def _cmd_datasets(args: argparse.Namespace) -> Any:
|
|
|
50
62
|
page_size=args.page_size,
|
|
51
63
|
page_num=args.page_num,
|
|
52
64
|
format_type=args.format_type,
|
|
65
|
+
**_project_identity(args),
|
|
53
66
|
)
|
|
54
67
|
|
|
55
68
|
|
|
@@ -62,28 +75,39 @@ def _cmd_create_dataset(args: argparse.Namespace) -> Any:
|
|
|
62
75
|
source_type=args.source_type,
|
|
63
76
|
engine_type=args.engine_type,
|
|
64
77
|
access_scope=args.access_scope,
|
|
78
|
+
**_project_identity(args),
|
|
65
79
|
)
|
|
66
80
|
|
|
67
81
|
|
|
68
82
|
def _cmd_ensure_dataset(args: argparse.Namespace) -> Any:
|
|
69
|
-
return knowledge.ensure_dataset(
|
|
83
|
+
return knowledge.ensure_dataset(
|
|
84
|
+
args.name, description=args.description, space_id=args.space_id, **_project_identity(args)
|
|
85
|
+
)
|
|
70
86
|
|
|
71
87
|
|
|
72
88
|
def _cmd_get_dataset(args: argparse.Namespace) -> Any:
|
|
73
|
-
return knowledge.get_dataset(args.dataset_id)
|
|
89
|
+
return knowledge.get_dataset(args.dataset_id, **_project_identity(args))
|
|
74
90
|
|
|
75
91
|
|
|
76
92
|
def _cmd_delete_dataset(args: argparse.Namespace) -> Any:
|
|
77
|
-
return knowledge.delete_dataset(args.dataset_id)
|
|
93
|
+
return knowledge.delete_dataset(args.dataset_id, **_project_identity(args))
|
|
78
94
|
|
|
79
95
|
|
|
80
96
|
def _cmd_add(args: argparse.Namespace) -> Any:
|
|
81
97
|
selector = _dataset_selector(args)
|
|
82
98
|
chunk_config = _chunk_config(args)
|
|
83
99
|
if args.content is not None:
|
|
84
|
-
return knowledge.add_text(
|
|
100
|
+
return knowledge.add_text(
|
|
101
|
+
args.content,
|
|
102
|
+
name=args.name or "document.txt",
|
|
103
|
+
chunk_config=chunk_config,
|
|
104
|
+
**selector,
|
|
105
|
+
**_project_identity(args),
|
|
106
|
+
)
|
|
85
107
|
if args.url is not None:
|
|
86
|
-
return knowledge.add_url(
|
|
108
|
+
return knowledge.add_url(
|
|
109
|
+
args.url, name=args.name, chunk_config=chunk_config, **selector, **_project_identity(args)
|
|
110
|
+
)
|
|
87
111
|
return knowledge.add_documents(
|
|
88
112
|
[
|
|
89
113
|
knowledge.KnowledgeDocument(
|
|
@@ -95,6 +119,7 @@ def _cmd_add(args: argparse.Namespace) -> Any:
|
|
|
95
119
|
],
|
|
96
120
|
chunk_config=chunk_config,
|
|
97
121
|
**selector,
|
|
122
|
+
**_project_identity(args),
|
|
98
123
|
)
|
|
99
124
|
|
|
100
125
|
|
|
@@ -110,38 +135,36 @@ def _cmd_search(args: argparse.Namespace) -> Any:
|
|
|
110
135
|
candidate_top_k=args.candidate_top_k,
|
|
111
136
|
search_method=args.search_method,
|
|
112
137
|
enable_rerank=args.enable_rerank,
|
|
138
|
+
**_project_identity(args),
|
|
113
139
|
)
|
|
114
140
|
|
|
115
141
|
|
|
116
142
|
def _cmd_documents(args: argparse.Namespace) -> Any:
|
|
117
|
-
return knowledge.list_documents(args.dataset_id, page=args.page, size=args.size)
|
|
143
|
+
return knowledge.list_documents(args.dataset_id, page=args.page, size=args.size, **_project_identity(args))
|
|
118
144
|
|
|
119
145
|
|
|
120
146
|
def _cmd_delete_documents(args: argparse.Namespace) -> Any:
|
|
121
|
-
return knowledge.delete_documents(args.dataset_id, args.document_id)
|
|
147
|
+
return knowledge.delete_documents(args.dataset_id, args.document_id, **_project_identity(args))
|
|
122
148
|
|
|
123
149
|
|
|
124
150
|
def _cmd_enterprise_tree(args: argparse.Namespace) -> Any:
|
|
125
|
-
return enterprise_knowledge.tree(include_types=args.include_types)
|
|
151
|
+
return enterprise_knowledge.tree(include_types=args.include_types, user_token=user_token(args))
|
|
126
152
|
|
|
127
153
|
|
|
128
154
|
def _cmd_enterprise_search(args: argparse.Namespace) -> Any:
|
|
129
155
|
return enterprise_knowledge.search_knowledge_bases(
|
|
130
|
-
args.query,
|
|
131
|
-
page=args.page,
|
|
132
|
-
page_size=args.page_size,
|
|
156
|
+
args.query, page=args.page, page_size=args.page_size, user_token=user_token(args)
|
|
133
157
|
)
|
|
134
158
|
|
|
135
159
|
|
|
136
160
|
def _cmd_enterprise_validate(args: argparse.Namespace) -> Any:
|
|
137
161
|
return enterprise_knowledge.validate_references(
|
|
138
|
-
args.knowledge_base_id,
|
|
139
|
-
required_capability=args.required_capability,
|
|
162
|
+
args.knowledge_base_id, required_capability=args.required_capability, user_token=user_token(args)
|
|
140
163
|
)
|
|
141
164
|
|
|
142
165
|
|
|
143
166
|
def _cmd_enterprise_retrieve(args: argparse.Namespace) -> Any:
|
|
144
|
-
return enterprise_knowledge.retrieve(args.query, args.source_id)
|
|
167
|
+
return enterprise_knowledge.retrieve(args.query, args.source_id, user_token=user_token(args))
|
|
145
168
|
|
|
146
169
|
|
|
147
170
|
def _cmd_enterprise_folders(args: argparse.Namespace) -> Any:
|
|
@@ -150,11 +173,12 @@ def _cmd_enterprise_folders(args: argparse.Namespace) -> Any:
|
|
|
150
173
|
include_children=args.include_children,
|
|
151
174
|
page=args.page,
|
|
152
175
|
page_size=args.page_size,
|
|
176
|
+
user_token=user_token(args),
|
|
153
177
|
)
|
|
154
178
|
|
|
155
179
|
|
|
156
180
|
def _cmd_enterprise_folder(args: argparse.Namespace) -> Any:
|
|
157
|
-
return enterprise_knowledge.get_folder(args.folder_id)
|
|
181
|
+
return enterprise_knowledge.get_folder(args.folder_id, user_token=user_token(args))
|
|
158
182
|
|
|
159
183
|
|
|
160
184
|
def _cmd_enterprise_folder_knowledge_bases(args: argparse.Namespace) -> Any:
|
|
@@ -163,40 +187,40 @@ def _cmd_enterprise_folder_knowledge_bases(args: argparse.Namespace) -> Any:
|
|
|
163
187
|
include_children=args.include_children,
|
|
164
188
|
page=args.page,
|
|
165
189
|
page_size=args.page_size,
|
|
190
|
+
user_token=user_token(args),
|
|
166
191
|
)
|
|
167
192
|
|
|
168
193
|
|
|
169
194
|
def _cmd_enterprise_knowledge_base(args: argparse.Namespace) -> Any:
|
|
170
|
-
return enterprise_knowledge.get_knowledge_base(args.source_id)
|
|
195
|
+
return enterprise_knowledge.get_knowledge_base(args.source_id, user_token=user_token(args))
|
|
171
196
|
|
|
172
197
|
|
|
173
198
|
def _cmd_enterprise_documents(args: argparse.Namespace) -> Any:
|
|
174
199
|
return enterprise_knowledge.list_documents(
|
|
175
|
-
args.source_id,
|
|
176
|
-
page=args.page,
|
|
177
|
-
page_size=args.page_size,
|
|
178
|
-
query=args.query,
|
|
200
|
+
args.source_id, page=args.page, page_size=args.page_size, query=args.query, user_token=user_token(args)
|
|
179
201
|
)
|
|
180
202
|
|
|
181
203
|
|
|
182
204
|
def _cmd_enterprise_document(args: argparse.Namespace) -> Any:
|
|
183
|
-
return enterprise_knowledge.get_document(args.document_id)
|
|
205
|
+
return enterprise_knowledge.get_document(args.document_id, user_token=user_token(args))
|
|
184
206
|
|
|
185
207
|
|
|
186
208
|
def _cmd_enterprise_document_chunks(args: argparse.Namespace) -> Any:
|
|
187
209
|
return enterprise_knowledge.list_document_chunks(
|
|
188
|
-
args.document_id,
|
|
189
|
-
page=args.page,
|
|
190
|
-
page_size=args.page_size,
|
|
210
|
+
args.document_id, page=args.page, page_size=args.page_size, user_token=user_token(args)
|
|
191
211
|
)
|
|
192
212
|
|
|
193
213
|
|
|
194
214
|
def _cmd_enterprise_document_url(args: argparse.Namespace) -> Any:
|
|
195
|
-
return {
|
|
215
|
+
return {
|
|
216
|
+
"url": enterprise_knowledge.document_original_url(
|
|
217
|
+
args.document_id, download=args.download, user_token=user_token(args)
|
|
218
|
+
)
|
|
219
|
+
}
|
|
196
220
|
|
|
197
221
|
|
|
198
222
|
def _cmd_enterprise_document_download_link(args: argparse.Namespace) -> Any:
|
|
199
|
-
return enterprise_knowledge.document_download_link(args.document_id)
|
|
223
|
+
return enterprise_knowledge.document_download_link(args.document_id, user_token=user_token(args))
|
|
200
224
|
|
|
201
225
|
|
|
202
226
|
def _add_dataset_selector(parser: argparse.ArgumentParser) -> None:
|
|
@@ -244,12 +268,12 @@ def _add_enterprise_parser(
|
|
|
244
268
|
|
|
245
269
|
tree = commands.add_parser("tree", help="Get the accessible enterprise knowledge resource tree")
|
|
246
270
|
_add_enterprise_types(tree)
|
|
247
|
-
|
|
271
|
+
_set_user_handler(tree, _cmd_enterprise_tree)
|
|
248
272
|
|
|
249
273
|
search = commands.add_parser("search", help="Search enterprise knowledge bases by name")
|
|
250
274
|
search.add_argument("--query", "-q", required=True)
|
|
251
275
|
_add_page_args(search)
|
|
252
|
-
|
|
276
|
+
_set_user_handler(search, _cmd_enterprise_search)
|
|
253
277
|
|
|
254
278
|
validate = commands.add_parser("validate", help="Validate knowledge base references and capabilities")
|
|
255
279
|
validate.add_argument("knowledge_base_id", nargs="+", help="Knowledge base ID")
|
|
@@ -258,22 +282,22 @@ def _add_enterprise_parser(
|
|
|
258
282
|
choices=["retrieve", "upload", "list_files", "batch_delete_files"],
|
|
259
283
|
default="retrieve",
|
|
260
284
|
)
|
|
261
|
-
|
|
285
|
+
_set_user_handler(validate, _cmd_enterprise_validate)
|
|
262
286
|
|
|
263
287
|
retrieve = commands.add_parser("retrieve", help="Retrieve evidence from enterprise knowledge bases")
|
|
264
288
|
retrieve.add_argument("--query", "-q", required=True)
|
|
265
289
|
retrieve.add_argument("--source-id", required=True, help="Knowledge base source ID")
|
|
266
|
-
|
|
290
|
+
_set_user_handler(retrieve, _cmd_enterprise_retrieve)
|
|
267
291
|
|
|
268
292
|
folders = commands.add_parser("folders", help="List enterprise knowledge folders")
|
|
269
293
|
folders.add_argument("--parent-id", default=None)
|
|
270
294
|
folders.add_argument("--include-children", action="store_true", default=None)
|
|
271
295
|
_add_page_args(folders)
|
|
272
|
-
|
|
296
|
+
_set_user_handler(folders, _cmd_enterprise_folders)
|
|
273
297
|
|
|
274
298
|
folder = commands.add_parser("folder", help="Get one enterprise knowledge folder")
|
|
275
299
|
folder.add_argument("folder_id")
|
|
276
|
-
|
|
300
|
+
_set_user_handler(folder, _cmd_enterprise_folder)
|
|
277
301
|
|
|
278
302
|
folder_bases = commands.add_parser(
|
|
279
303
|
"folder-knowledge-bases",
|
|
@@ -282,35 +306,34 @@ def _add_enterprise_parser(
|
|
|
282
306
|
folder_bases.add_argument("folder_id")
|
|
283
307
|
folder_bases.add_argument("--include-children", action="store_true", default=None)
|
|
284
308
|
_add_page_args(folder_bases)
|
|
285
|
-
|
|
309
|
+
_set_user_handler(folder_bases, _cmd_enterprise_folder_knowledge_bases)
|
|
286
310
|
|
|
287
311
|
knowledge_base = commands.add_parser("knowledge-base", help="Get one enterprise knowledge base")
|
|
288
312
|
knowledge_base.add_argument("source_id")
|
|
289
|
-
|
|
313
|
+
_set_user_handler(knowledge_base, _cmd_enterprise_knowledge_base)
|
|
290
314
|
|
|
291
315
|
documents = commands.add_parser("documents", help="List documents in an enterprise knowledge base")
|
|
292
316
|
documents.add_argument("source_id")
|
|
293
317
|
_add_enterprise_query_args(documents)
|
|
294
|
-
|
|
318
|
+
_set_user_handler(documents, _cmd_enterprise_documents)
|
|
295
319
|
|
|
296
320
|
document = commands.add_parser("document", help="Get one enterprise knowledge document")
|
|
297
321
|
document.add_argument("document_id")
|
|
298
|
-
|
|
322
|
+
_set_user_handler(document, _cmd_enterprise_document)
|
|
299
323
|
|
|
300
324
|
chunks = commands.add_parser("document-chunks", help="List chunks for one enterprise knowledge document")
|
|
301
325
|
chunks.add_argument("document_id")
|
|
302
326
|
_add_page_args(chunks)
|
|
303
|
-
|
|
327
|
+
_set_user_handler(chunks, _cmd_enterprise_document_chunks)
|
|
304
328
|
|
|
305
329
|
document_url = commands.add_parser("document-url", help="Get a temporary original document URL")
|
|
306
330
|
document_url.add_argument("document_id")
|
|
307
331
|
document_url.add_argument("--download", action="store_true", help="Request download disposition")
|
|
308
|
-
|
|
332
|
+
_set_user_handler(document_url, _cmd_enterprise_document_url)
|
|
309
333
|
|
|
310
334
|
download_link = commands.add_parser("document-download-link", help="Get a temporary document download link")
|
|
311
335
|
download_link.add_argument("document_id")
|
|
312
|
-
|
|
313
|
-
|
|
336
|
+
_set_user_handler(download_link, _cmd_enterprise_document_download_link)
|
|
314
337
|
|
|
315
338
|
|
|
316
339
|
def add_knowledge_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/ontology_commands.py
RENAMED
|
@@ -6,12 +6,13 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any, Callable
|
|
7
7
|
|
|
8
8
|
from licos_platform_sdk import ontology
|
|
9
|
-
|
|
9
|
+
from .identity import add_user_token_option, user_token
|
|
10
10
|
|
|
11
11
|
Handler = Callable[[argparse.Namespace], Any]
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def _set_handler(parser: argparse.ArgumentParser, handler: Handler) -> None:
|
|
15
|
+
add_user_token_option(parser)
|
|
15
16
|
parser.set_defaults(handler=handler)
|
|
16
17
|
|
|
17
18
|
|
|
@@ -29,11 +30,12 @@ def _arguments(args: argparse.Namespace) -> dict[str, Any]:
|
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def _cmd_search(args: argparse.Namespace) -> Any:
|
|
32
|
-
return ontology.search_tools(args.query, limit=args.limit, offset=args.offset)
|
|
33
|
+
return ontology.search_tools(args.query, limit=args.limit, offset=args.offset, user_token=user_token(args))
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def _cmd_invoke(args: argparse.Namespace) -> Any:
|
|
36
|
-
|
|
37
|
+
token = user_token(args)
|
|
38
|
+
catalog_version, item = ontology.resolve_tool(args.name, user_token=token)
|
|
37
39
|
if args.catalog_version and args.catalog_version != catalog_version:
|
|
38
40
|
raise argparse.ArgumentTypeError(
|
|
39
41
|
"ontology tool catalog changed; search again before invoking the tool"
|
|
@@ -46,6 +48,7 @@ def _cmd_invoke(args: argparse.Namespace) -> Any:
|
|
|
46
48
|
args.name,
|
|
47
49
|
_arguments(args),
|
|
48
50
|
catalog_version=catalog_version,
|
|
51
|
+
user_token=token,
|
|
49
52
|
)
|
|
50
53
|
|
|
51
54
|
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/user_commands.py
RENAMED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
|
-
import sys
|
|
5
4
|
|
|
6
5
|
from licos_platform_sdk import get_current_user
|
|
7
|
-
|
|
6
|
+
from .identity import user_token
|
|
8
7
|
|
|
9
8
|
USER_HELP = {
|
|
10
9
|
"topic": "user",
|
|
@@ -12,8 +11,11 @@ USER_HELP = {
|
|
|
12
11
|
"runtime": [
|
|
13
12
|
{"name": "LICOS_PLATFORM_API_BASE_URL", "description": "平台 API 地址。"},
|
|
14
13
|
{"name": "LICOS_AI_AGENT_TOKEN", "description": "运行时内部服务凭证,不输出。"},
|
|
15
|
-
{"name": "LICOS_CURRENT_USER_ID", "description": "
|
|
16
|
-
{
|
|
14
|
+
{"name": "LICOS_CURRENT_USER_ID", "description": "独立 CLI 默认执行用户,即容器初始化用户;不代表网页登录者。"},
|
|
15
|
+
{
|
|
16
|
+
"name": "LICOS_WORKSPACE_ID / LICOS_OWNER_WORKSPACE_ID / AGENT_WORKSPACE_ID",
|
|
17
|
+
"description": "执行工作空间,决定企业范围。",
|
|
18
|
+
},
|
|
17
19
|
],
|
|
18
20
|
"rules": [
|
|
19
21
|
"多用户请求传当前使用者 Token;不使用项目所有者代替使用者。",
|
|
@@ -28,8 +30,18 @@ USER_HELP = {
|
|
|
28
30
|
"me": {
|
|
29
31
|
"description": "查询当前使用者信息。",
|
|
30
32
|
"parameters": [
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
+
{
|
|
34
|
+
"name": "--token-stdin",
|
|
35
|
+
"type": "boolean",
|
|
36
|
+
"required": False,
|
|
37
|
+
"description": "从标准输入读取当前用户 Token,不含 Bearer 前缀;不通过命令行参数暴露 Token。",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "--workspace-id",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"required": False,
|
|
43
|
+
"description": "执行工作空间 ID;省略时由项目运行时获取。",
|
|
44
|
+
},
|
|
33
45
|
],
|
|
34
46
|
"returns": "sys_user 对象:id、username、displayName、avatarUrl、tenantId、tenantName、primaryDepartment、departments、organizationAssignments、primaryPosition、primaryJobTitle。",
|
|
35
47
|
"example": "licos-platform user me",
|
|
@@ -40,7 +52,7 @@ USER_HELP = {
|
|
|
40
52
|
|
|
41
53
|
def _me(args: argparse.Namespace):
|
|
42
54
|
return get_current_user(
|
|
43
|
-
user_token=
|
|
55
|
+
user_token=user_token(args),
|
|
44
56
|
workspace_id=args.workspace_id,
|
|
45
57
|
)
|
|
46
58
|
|
|
@@ -36,6 +36,15 @@ def run_cli(*args: str) -> tuple[int, str, str]:
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class PlatformCliTests(unittest.TestCase):
|
|
39
|
+
|
|
40
|
+
def setUp(self):
|
|
41
|
+
identity = mock.patch("licos_platform_cli.identity.runtime_user_token", return_value="cli-token")
|
|
42
|
+
identity.start()
|
|
43
|
+
self.addCleanup(identity.stop)
|
|
44
|
+
env = mock.patch.dict(os.environ, {"LICOS_CURRENT_USER_ID": "cli-user"})
|
|
45
|
+
env.start()
|
|
46
|
+
self.addCleanup(env.stop)
|
|
47
|
+
|
|
39
48
|
def test_enterprise_help_matches_removed_management_commands(self) -> None:
|
|
40
49
|
code, output, _ = run_cli("help", "knowledge")
|
|
41
50
|
self.assertEqual(code, 0)
|
|
@@ -53,7 +62,7 @@ class PlatformCliTests(unittest.TestCase):
|
|
|
53
62
|
code, output, _ = run_cli("knowledge", "enterprise", "document-download-link", "doc-1")
|
|
54
63
|
self.assertEqual(code, 0)
|
|
55
64
|
self.assertEqual(json.loads(output), link)
|
|
56
|
-
download.assert_called_once_with("doc-1")
|
|
65
|
+
download.assert_called_once_with("doc-1", user_token="cli-token")
|
|
57
66
|
|
|
58
67
|
def test_help_exposes_storage_commands(self) -> None:
|
|
59
68
|
stdout = io.StringIO()
|
|
@@ -136,7 +145,10 @@ class PlatformCliTests(unittest.TestCase):
|
|
|
136
145
|
self.assertIn("mode", sdk_help)
|
|
137
146
|
self.assertIn("subscribeRealtime", payload["realtimeSdk"]["node"])
|
|
138
147
|
self.assertIn("subscribe_realtime", payload["realtimeSdk"]["python"])
|
|
139
|
-
self.assertEqual(payload["realtimeSdk"]["minimum_versions"], {"node": "0.
|
|
148
|
+
self.assertEqual(payload["realtimeSdk"]["minimum_versions"], {"node": "0.12.0", "python": "0.7.0"})
|
|
149
|
+
self.assertIn("userToken", payload["realtimeSdk"]["node"])
|
|
150
|
+
self.assertIn("user_token", payload["realtimeSdk"]["python"])
|
|
151
|
+
self.assertIn("--token-stdin", [item["name"] for item in payload["commands"]["search"]["parameters"]])
|
|
140
152
|
|
|
141
153
|
def test_ontology_search_forwards_catalog_pagination(self) -> None:
|
|
142
154
|
result = {"catalogVersion": "v1", "items": []}
|
|
@@ -150,7 +162,7 @@ class PlatformCliTests(unittest.TestCase):
|
|
|
150
162
|
self.assertEqual(code, 0)
|
|
151
163
|
self.assertEqual(stderr, "")
|
|
152
164
|
self.assertEqual(json.loads(stdout), result)
|
|
153
|
-
search.assert_called_once_with("查询设备数据", limit=7, offset=3)
|
|
165
|
+
search.assert_called_once_with("查询设备数据", limit=7, offset=3, user_token="cli-token")
|
|
154
166
|
|
|
155
167
|
def test_ontology_persist_requires_confirmation(self) -> None:
|
|
156
168
|
item = {"mode": "PERSIST"}
|
|
@@ -187,7 +199,7 @@ class PlatformCliTests(unittest.TestCase):
|
|
|
187
199
|
self.assertEqual(stderr, "")
|
|
188
200
|
self.assertEqual(json.loads(stdout), {"value": 7})
|
|
189
201
|
invoke.assert_called_once_with(
|
|
190
|
-
"queryElementData", {"elementId": "element-1"}, catalog_version="v4"
|
|
202
|
+
"queryElementData", {"elementId": "element-1"}, catalog_version="v4", user_token="cli-token"
|
|
191
203
|
)
|
|
192
204
|
|
|
193
205
|
def test_ontology_invoke_rejects_changed_catalog_version(self) -> None:
|
|
@@ -689,8 +701,7 @@ class PlatformCliTests(unittest.TestCase):
|
|
|
689
701
|
self.assertEqual(code, 0)
|
|
690
702
|
self.assertEqual(stderr, "")
|
|
691
703
|
self.assertEqual(json.loads(stdout), {"status": "KNOWLEDGE_TREE_READY"})
|
|
692
|
-
tree.assert_called_once_with(include_types=["STANDARD", "GRAPH"])
|
|
693
|
-
|
|
704
|
+
tree.assert_called_once_with(include_types=["STANDARD", "GRAPH"], user_token="cli-token")
|
|
694
705
|
|
|
695
706
|
def test_structured_help_describes_enterprise_knowledge_contract(self) -> None:
|
|
696
707
|
code, stdout, stderr = run_cli("help", "knowledge", "enterprise-documents")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import io
|
|
2
|
+
from argparse import Namespace
|
|
3
|
+
from unittest import TestCase, mock
|
|
4
|
+
|
|
5
|
+
from licos_platform_cli.identity import user_token
|
|
6
|
+
from licos_platform_sdk import ConfigurationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CliIdentityTests(TestCase):
|
|
10
|
+
def test_cli_defaults_to_initialization_user(self):
|
|
11
|
+
with mock.patch.dict(
|
|
12
|
+
"os.environ", {"LICOS_CURRENT_USER_ID": "initializer", "LICOS_USER_ID": "owner"}, clear=True
|
|
13
|
+
), mock.patch("licos_platform_cli.identity.runtime_user_token", return_value="cli-token") as exchange:
|
|
14
|
+
self.assertEqual(user_token(Namespace(token_stdin=False)), "cli-token")
|
|
15
|
+
exchange.assert_called_once_with("initializer")
|
|
16
|
+
|
|
17
|
+
def test_stdin_token_does_not_exchange_container_identity(self):
|
|
18
|
+
with mock.patch("sys.stdin", io.StringIO("request-token\n")), mock.patch(
|
|
19
|
+
"licos_platform_cli.identity.runtime_user_token"
|
|
20
|
+
) as exchange:
|
|
21
|
+
self.assertEqual(user_token(Namespace(token_stdin=True)), "request-token")
|
|
22
|
+
exchange.assert_not_called()
|
|
23
|
+
|
|
24
|
+
def test_missing_user_and_empty_stdin_do_not_use_owner(self):
|
|
25
|
+
with mock.patch.dict("os.environ", {"LICOS_USER_ID": "owner"}, clear=True), mock.patch(
|
|
26
|
+
"sys.stdin", io.StringIO(" ")
|
|
27
|
+
), mock.patch("licos_platform_cli.identity.runtime_user_token") as exchange:
|
|
28
|
+
for token_stdin in (True, False):
|
|
29
|
+
with self.assertRaises(ConfigurationError):
|
|
30
|
+
user_token(Namespace(token_stdin=token_stdin))
|
|
31
|
+
exchange.assert_not_called()
|
|
@@ -21,12 +21,16 @@ class UserCliTests(unittest.TestCase):
|
|
|
21
21
|
|
|
22
22
|
def test_me_outputs_sdk_json_with_chinese(self):
|
|
23
23
|
with patch.object(user_commands, "get_current_user", return_value={"id": "caller", "displayName": "张三"}) as sdk:
|
|
24
|
-
|
|
24
|
+
with patch(
|
|
25
|
+
"licos_platform_cli.identity.runtime_user_token", return_value="cli-token"
|
|
26
|
+
) as exchange, patch.dict(os.environ, {"LICOS_CURRENT_USER_ID": "cli-user"}):
|
|
27
|
+
code, out, err = self.run_cli("user", "me")
|
|
28
|
+
exchange.assert_called_once_with("cli-user")
|
|
25
29
|
self.assertEqual(code, 0)
|
|
26
30
|
self.assertEqual(err, "")
|
|
27
31
|
self.assertEqual(json.loads(out), {"id": "caller", "displayName": "张三"})
|
|
28
32
|
self.assertIn("张三", out)
|
|
29
|
-
sdk.assert_called_once_with(user_token=
|
|
33
|
+
sdk.assert_called_once_with(user_token="cli-token", workspace_id=None)
|
|
30
34
|
|
|
31
35
|
def test_stdin_token_is_forwarded_without_echo(self):
|
|
32
36
|
with patch("sys.stdin", io.StringIO("request-secret\n")), patch.object(
|
|
@@ -45,7 +49,7 @@ class UserCliTests(unittest.TestCase):
|
|
|
45
49
|
code, out, err = self.run_cli("user", "me", "--token-stdin")
|
|
46
50
|
self.assertEqual(code, 1)
|
|
47
51
|
self.assertEqual(out, "")
|
|
48
|
-
self.assertIn("
|
|
52
|
+
self.assertIn("nonempty", err)
|
|
49
53
|
|
|
50
54
|
def test_structured_help_exposes_command_and_sdk(self):
|
|
51
55
|
code, out, err = self.run_cli("help", "user")
|
|
File without changes
|
|
File without changes
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/database_commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/oauth_commands.py
RENAMED
|
File without changes
|
|
File without changes
|
{licos_platform_cli-0.5.1 → licos_platform_cli-0.6.0}/src/licos_platform_cli/storage_commands.py
RENAMED
|
File without changes
|
|
File without changes
|