licos-platform-cli 0.8.0__tar.gz → 0.8.2__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.
Files changed (24) hide show
  1. licos_platform_cli-0.8.0/README.md → licos_platform_cli-0.8.2/PKG-INFO +24 -2
  2. licos_platform_cli-0.8.0/PKG-INFO → licos_platform_cli-0.8.2/README.md +16 -10
  3. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/pyproject.toml +2 -2
  4. licos_platform_cli-0.8.2/src/licos_platform_cli/enterprise_project_commands.py +52 -0
  5. licos_platform_cli-0.8.2/src/licos_platform_cli/enterprise_project_help.py +31 -0
  6. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/help_commands.py +3 -0
  7. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/main.py +2 -0
  8. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/tests/test_cli.py +2 -1
  9. licos_platform_cli-0.8.2/tests/test_enterprise_projects.py +57 -0
  10. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/.gitignore +0 -0
  11. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/__init__.py +0 -0
  12. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/database_commands.py +0 -0
  13. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/identity.py +0 -0
  14. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/knowledge_commands.py +0 -0
  15. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/oauth_commands.py +0 -0
  16. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/ontology_commands.py +0 -0
  17. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/ontology_package_commands.py +0 -0
  18. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/project_config_commands.py +0 -0
  19. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/storage_commands.py +0 -0
  20. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/src/licos_platform_cli/user_commands.py +0 -0
  21. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/tests/test_identity.py +0 -0
  22. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/tests/test_ontology_packages.py +0 -0
  23. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/tests/test_project_config.py +0 -0
  24. {licos_platform_cli-0.8.0 → licos_platform_cli-0.8.2}/tests/test_user.py +0 -0
@@ -1,7 +1,29 @@
1
+ Metadata-Version: 2.5
2
+ Name: licos-platform-cli
3
+ Version: 0.8.2
4
+ Summary: LICOS platform CLI
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: licos-platform-sdk>=0.9.1
7
+ Description-Content-Type: text/markdown
8
+
1
9
  # licos-platform-cli
2
10
 
3
11
  LICOS 平台命令行工具。`licos-platform help` 返回结构化 JSON 帮助。
4
12
 
13
+ ## 企业项目(0.8.1 起)
14
+
15
+ ```bash
16
+ licos-platform help enterprise-projects
17
+ licos-platform enterprise-projects list --all
18
+ licos-platform enterprise-projects search --query 发票 --type AGENT --type AICODING_AGENT --all
19
+ licos-platform enterprise-projects show RECORD_ID
20
+ licos-platform enterprise-projects capability --tenant-id TENANT --workspace-id WORKSPACE --resource-type AICODING_WORKFLOW --resource-id RESOURCE
21
+ ```
22
+
23
+ 查询包含当前用户可见的在线低代码智能体、AI 编程智能体和 AI 编程工作流;`invocation` 保留关闭调用、未就绪等原因。`--all` 完整读取匹配页;默认一页,可用 `--page`、`--page-size`。精确发布契约使用 `capability --record-id RECORD_ID`,与稳定资源选择互斥。
24
+
25
+ 命令只做发现,业务代码查项目实际安装的 SDK 文档后接入。帮助中的 `sdk` 字段提供文档入口;命令身份遵循下文“当前使用者”规则。
26
+
5
27
  ## 当前使用者(0.5.1 起)
6
28
 
7
29
  ```bash
@@ -10,7 +32,7 @@ licos-platform user me --workspace-id <执行工作空间ID>
10
32
  licos-platform help user me
11
33
  ```
12
34
 
13
- 用户接口默认使用 `LICOS_CURRENT_USER_ID` 指定的容器执行用户换取 Token。它不代表网页登录者。平台地址、服务凭证和项目工作空间沿用运行时配置。
35
+ 用户接口默认使用 `LICOS_CURRENT_USER_ID` 指定的当前命令用户换取 Token。编程助手执行命令时,由平台根据本次请求注入该标识;独立终端沿用其启动身份,不会自动跟随网页登录者变化。平台地址、服务凭证和项目工作空间沿用运行时配置。
14
36
  运行时使用 `AGENT_CURRENT_USER_ID` 注入当前用户时同样支持,不以项目负责人替代当前执行用户。企业和空间上下文沿用平台签发的认证结果。
15
37
  多用户请求可将当前使用者 Token 通过标准输入传入,不将 Token 放在命令行参数中:
16
38
 
@@ -28,7 +50,7 @@ licos-platform user me --token-stdin
28
50
 
29
51
  ## 身份选择(0.6.0 起)
30
52
 
31
- `LICOS_CURRENT_USER_ID` 表示容器启动时配置的执行用户,项目身份指运行时配置的项目所有者身份。不同命令的默认身份如下:
53
+ `LICOS_CURRENT_USER_ID` 表示当前命令的执行用户:编程助手按本次请求注入,独立终端沿用其启动身份。项目身份指运行时配置的项目所有者身份。不同命令的默认身份如下:
32
54
 
33
55
  | 命令 | 默认身份 | 网页登录用户执行 |
34
56
  | --- | --- | --- |
@@ -1,15 +1,21 @@
1
- Metadata-Version: 2.5
2
- Name: licos-platform-cli
3
- Version: 0.8.0
4
- Summary: LICOS platform CLI
5
- Requires-Python: >=3.10
6
- Requires-Dist: licos-platform-sdk>=0.9.0
7
- Description-Content-Type: text/markdown
8
-
9
1
  # licos-platform-cli
10
2
 
11
3
  LICOS 平台命令行工具。`licos-platform help` 返回结构化 JSON 帮助。
12
4
 
5
+ ## 企业项目(0.8.1 起)
6
+
7
+ ```bash
8
+ licos-platform help enterprise-projects
9
+ licos-platform enterprise-projects list --all
10
+ licos-platform enterprise-projects search --query 发票 --type AGENT --type AICODING_AGENT --all
11
+ licos-platform enterprise-projects show RECORD_ID
12
+ licos-platform enterprise-projects capability --tenant-id TENANT --workspace-id WORKSPACE --resource-type AICODING_WORKFLOW --resource-id RESOURCE
13
+ ```
14
+
15
+ 查询包含当前用户可见的在线低代码智能体、AI 编程智能体和 AI 编程工作流;`invocation` 保留关闭调用、未就绪等原因。`--all` 完整读取匹配页;默认一页,可用 `--page`、`--page-size`。精确发布契约使用 `capability --record-id RECORD_ID`,与稳定资源选择互斥。
16
+
17
+ 命令只做发现,业务代码查项目实际安装的 SDK 文档后接入。帮助中的 `sdk` 字段提供文档入口;命令身份遵循下文“当前使用者”规则。
18
+
13
19
  ## 当前使用者(0.5.1 起)
14
20
 
15
21
  ```bash
@@ -18,7 +24,7 @@ licos-platform user me --workspace-id <执行工作空间ID>
18
24
  licos-platform help user me
19
25
  ```
20
26
 
21
- 用户接口默认使用 `LICOS_CURRENT_USER_ID` 指定的容器执行用户换取 Token。它不代表网页登录者。平台地址、服务凭证和项目工作空间沿用运行时配置。
27
+ 用户接口默认使用 `LICOS_CURRENT_USER_ID` 指定的当前命令用户换取 Token。编程助手执行命令时,由平台根据本次请求注入该标识;独立终端沿用其启动身份,不会自动跟随网页登录者变化。平台地址、服务凭证和项目工作空间沿用运行时配置。
22
28
  运行时使用 `AGENT_CURRENT_USER_ID` 注入当前用户时同样支持,不以项目负责人替代当前执行用户。企业和空间上下文沿用平台签发的认证结果。
23
29
  多用户请求可将当前使用者 Token 通过标准输入传入,不将 Token 放在命令行参数中:
24
30
 
@@ -36,7 +42,7 @@ licos-platform user me --token-stdin
36
42
 
37
43
  ## 身份选择(0.6.0 起)
38
44
 
39
- `LICOS_CURRENT_USER_ID` 表示容器启动时配置的执行用户,项目身份指运行时配置的项目所有者身份。不同命令的默认身份如下:
45
+ `LICOS_CURRENT_USER_ID` 表示当前命令的执行用户:编程助手按本次请求注入,独立终端沿用其启动身份。项目身份指运行时配置的项目所有者身份。不同命令的默认身份如下:
40
46
 
41
47
  | 命令 | 默认身份 | 网页登录用户执行 |
42
48
  | --- | --- | --- |
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "licos-platform-cli"
7
- version = "0.8.0"
7
+ version = "0.8.2"
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.9.0",
12
+ "licos-platform-sdk>=0.9.1",
13
13
  ]
14
14
 
15
15
  [project.scripts]
@@ -0,0 +1,52 @@
1
+ """Read-only discovery of published enterprise agents and coding workflows."""
2
+ from licos_platform_sdk import ConfigurationError, enterprise_projects
3
+
4
+ from .identity import add_user_token_option, user_token
5
+
6
+
7
+ def _list(args):
8
+ options = {"query": args.query, "resource_types": args.resource_types,
9
+ "page_size": args.page_size, "user_token": user_token(args)}
10
+ if args.all:
11
+ if args.page != 1:
12
+ raise ConfigurationError("--all starts at page 1; do not combine it with another --page")
13
+ return {"items": list(enterprise_projects.iter_projects(**options))}
14
+ return enterprise_projects.list_projects(page=args.page, **options)
15
+
16
+
17
+ def _capability(args):
18
+ token = user_token(args)
19
+ if args.record_id:
20
+ if any((args.tenant_id, args.workspace_id, args.resource_type)):
21
+ raise ConfigurationError("--record-id cannot be combined with resource identity fields")
22
+ return enterprise_projects.capability(args.record_id, user_token=token)
23
+ resource = {"tenant_id": args.tenant_id, "workspace_id": args.workspace_id,
24
+ "resource_type": args.resource_type, "resource_id": args.resource_id}
25
+ return enterprise_projects.current_capability(resource, user_token=token)
26
+
27
+
28
+ def add_enterprise_project_parser(subparsers):
29
+ group = subparsers.add_parser("enterprise-projects", help="Discover visible published enterprise agents and coding workflows")
30
+ commands = group.add_subparsers(dest="enterprise_project_command", required=True)
31
+ for name in ("list", "search"):
32
+ parser = commands.add_parser(name, help="List visible publications, including disabled or unready calls")
33
+ parser.add_argument("--query", required=name == "search", default="", help="Search published name and description")
34
+ parser.add_argument("--type", dest="resource_types", action="append", choices=enterprise_projects.RESOURCE_TYPES)
35
+ parser.add_argument("--page", type=int, default=1)
36
+ parser.add_argument("--page-size", type=int, default=50)
37
+ parser.add_argument("--all", action="store_true", help="Read all matching pages")
38
+ add_user_token_option(parser)
39
+ parser.set_defaults(handler=_list)
40
+ detail = commands.add_parser("show", help="Read a visible online publication and invocation availability")
41
+ detail.add_argument("record_id")
42
+ add_user_token_option(detail)
43
+ detail.set_defaults(handler=lambda args: enterprise_projects.get_project(args.record_id, user_token=user_token(args)))
44
+ capability = commands.add_parser("capability", help="Read the exact publication contract or resolve a stable resource to its current publication")
45
+ selector = capability.add_mutually_exclusive_group(required=True)
46
+ selector.add_argument("--record-id")
47
+ selector.add_argument("--resource-id")
48
+ capability.add_argument("--tenant-id")
49
+ capability.add_argument("--workspace-id")
50
+ capability.add_argument("--resource-type", choices=enterprise_projects.RESOURCE_TYPES)
51
+ add_user_token_option(capability)
52
+ capability.set_defaults(handler=_capability)
@@ -0,0 +1,31 @@
1
+ ENTERPRISE_PROJECT_HELP = {
2
+ "topic": "enterprise-projects",
3
+ "description": "查询当前用户可见的在线企业项目:低代码智能体、AI 编程智能体和 AI 编程工作流。",
4
+ "rules": [
5
+ "查询包含关闭调用及尚未就绪的可见项目;invocation 字段说明是否可调用及原因。",
6
+ "用 --all 读取全部匹配页。默认按当前用户查询全部可见范围,不限定当前开发工作空间。",
7
+ "先从列表取得完整 resource,再读取当前 capability 的输入输出 Schema,不按同名项目替换目标。",
8
+ "CLI 用于发现;业务代码查项目实际安装版本的 SDK 文档后接入 project-invocations。",
9
+ "新调用解析当前发布;已有任务恢复沿用原 invocation_id、record_id 和 contract_revision。",
10
+ ],
11
+ "sdk": {
12
+ "discovery": "Python licos-platform-sdk 的 enterprise_projects 模块;实际版本 README 的企业项目章节。",
13
+ "invocation": "Python licos-agent-runtime 包内 docs/enterprise-projects.md,包含模型工具结果边界、人工中断和接入验收;先由项目 SDK.md 确认解释器。",
14
+ "locate": "from importlib.resources import files; print(files('licos_agent_runtime').joinpath('docs/enterprise-projects.md').read_text(encoding='utf-8'))",
15
+ },
16
+ "commands": {
17
+ "list": {"description": "读取一页在线可见项目,--all 读取全部页。", "example": "licos-platform enterprise-projects list --all"},
18
+ "search": {"description": "服务端按发布名称和描述搜索。", "example": "licos-platform enterprise-projects search --query 发票 --all"},
19
+ "show": {"description": "查看精确发布记录及调用状态。", "example": "licos-platform enterprise-projects show RECORD_ID"},
20
+ "capability": {"description": "读取精确发布契约,或按完整 resource 解析当前在线发布。",
21
+ "example": "licos-platform enterprise-projects capability --tenant-id TENANT --workspace-id WORKSPACE --resource-type AGENT --resource-id RESOURCE"},
22
+ },
23
+ "parameters": {
24
+ "--type": "list/search 可重复指定 AGENT、AICODING_AGENT、AICODING_WORKFLOW。",
25
+ "--page": "从 1 开始;不能将 --all 与非 1 页组合。",
26
+ "--page-size": "1 到 100,默认 50。",
27
+ "--record-id": "capability 使用精确发布 ID;与资源选择互斥。",
28
+ "--resource-id": "capability 同时需要 --tenant-id、--workspace-id、--resource-type。",
29
+ "--token-stdin": "从 stdin 读取本次用户 Token;省略时使用当前 CLI 用户身份,不使用项目所有者替代。",
30
+ },
31
+ }
@@ -4,6 +4,7 @@ import argparse
4
4
  from typing import Any, Callable
5
5
  from .user_commands import USER_HELP
6
6
  from .ontology_package_commands import PACKAGE_HELP
7
+ from .enterprise_project_help import ENTERPRISE_PROJECT_HELP
7
8
 
8
9
 
9
10
  Handler = Callable[[argparse.Namespace], Any]
@@ -849,6 +850,7 @@ ONTOLOGY_HELP = {
849
850
  ONTOLOGY_HELP["commands"].update(PACKAGE_HELP)
850
851
 
851
852
  HELP_TOPICS = {
853
+ "enterprise-projects": ENTERPRISE_PROJECT_HELP,
852
854
  "user": USER_HELP,
853
855
  "storage": STORAGE_HELP,
854
856
  "database": DATABASE_HELP,
@@ -892,6 +894,7 @@ def _cmd_help(args: argparse.Namespace) -> dict[str, Any]:
892
894
  "licos-platform help ontology",
893
895
  "licos-platform help ontology search",
894
896
  "licos-platform help user me",
897
+ "licos-platform help enterprise-projects",
895
898
  ],
896
899
  "topics": sorted(HELP_TOPICS),
897
900
  }
@@ -8,6 +8,7 @@ from typing import Any, Sequence
8
8
  from licos_platform_sdk import PlatformSdkError
9
9
 
10
10
  from .database_commands import add_database_parser
11
+ from .enterprise_project_commands import add_enterprise_project_parser
11
12
  from .help_commands import add_help_parser
12
13
  from .knowledge_commands import add_knowledge_parser
13
14
  from .oauth_commands import add_oauth_parser
@@ -40,6 +41,7 @@ def _build_parser() -> argparse.ArgumentParser:
40
41
  add_project_config_parser(subparsers)
41
42
  add_ontology_parser(subparsers)
42
43
  add_user_parser(subparsers)
44
+ add_enterprise_project_parser(subparsers)
43
45
  return parser
44
46
 
45
47
 
@@ -84,6 +84,7 @@ class PlatformCliTests(unittest.TestCase):
84
84
  payload["topics"],
85
85
  [
86
86
  "database",
87
+ "enterprise-projects",
87
88
  "knowledge",
88
89
  "oauth",
89
90
  "ontology",
@@ -136,7 +137,7 @@ class PlatformCliTests(unittest.TestCase):
136
137
  self.assertEqual(stderr, "")
137
138
  payload = json.loads(stdout)
138
139
  self.assertEqual(payload["topic"], "ontology")
139
- self.assertEqual(set(payload["commands"]), {"search", "invoke", "releases", "package", "bind", "validate", "query", "function", "diff"})
140
+ self.assertEqual(set(payload["commands"]), {"search", "invoke", "releases", "package", "bind", "resolve", "validate", "query", "function", "diff"})
140
141
  self.assertTrue(any("catalogVersion" in rule for rule in payload["rules"]))
141
142
  sdk_help = "\n".join(payload["sdk"].values())
142
143
  self.assertNotIn("items[0]", sdk_help)
@@ -0,0 +1,57 @@
1
+ import io
2
+ import json
3
+ import os
4
+ import unittest
5
+ from contextlib import redirect_stderr, redirect_stdout
6
+ from unittest.mock import patch
7
+
8
+ import httpx
9
+
10
+ from licos_platform_cli.main import main
11
+
12
+
13
+ def run(*args):
14
+ out, err = io.StringIO(), io.StringIO()
15
+ with redirect_stdout(out), redirect_stderr(err):
16
+ try:
17
+ status = main(list(args))
18
+ except SystemExit as error:
19
+ status = error.code
20
+ return status, out.getvalue(), err.getvalue()
21
+
22
+
23
+ class EnterpriseProjectCommandTests(unittest.TestCase):
24
+ def test_cli_current_user_reaches_real_sdk_with_search_and_type(self):
25
+ response = httpx.Response(200, request=httpx.Request("GET", "https://platform.test/catalog"),
26
+ json={"code": 0, "data": {"records": [], "total": 0, "current": 1, "size": 50, "pages": 0}})
27
+ with patch.dict(os.environ, {"LICOS_CURRENT_USER_ID": "caller", "LICOS_USER_ID": "owner",
28
+ "LICOS_PLATFORM_API_BASE_URL": "https://platform.test"}, clear=True), \
29
+ patch("licos_platform_cli.identity.runtime_user_token", return_value="caller-token") as exchange, \
30
+ patch.object(httpx, "get", return_value=response) as get:
31
+ status, output, _ = run("enterprise-projects", "search", "--query", "发票", "--type", "AICODING_WORKFLOW", "--all")
32
+ self.assertEqual(status, 0)
33
+ self.assertEqual(json.loads(output), {"items": []})
34
+ exchange.assert_called_once_with("caller")
35
+ self.assertEqual(get.call_args.kwargs["params"]["resourceTypes"], "AICODING_WORKFLOW")
36
+ self.assertEqual(get.call_args.kwargs["headers"]["Authorization"], "Bearer caller-token")
37
+
38
+ def test_explicit_request_token_does_not_exchange_owner_identity(self):
39
+ with patch("sys.stdin", io.StringIO("request-token")), \
40
+ patch("licos_platform_cli.identity.runtime_user_token") as exchange, \
41
+ patch("licos_platform_cli.enterprise_project_commands.enterprise_projects.capability", return_value={"record_id": "record"}) as call:
42
+ status, _, _ = run("enterprise-projects", "capability", "--record-id", "record", "--token-stdin")
43
+ self.assertEqual(status, 0)
44
+ exchange.assert_not_called()
45
+ call.assert_called_once_with("record", user_token="request-token")
46
+
47
+ def test_help_explains_discovery_and_sdk_document_entry(self):
48
+ status, output, _ = run("help", "enterprise-projects")
49
+ self.assertEqual(status, 0)
50
+ value = json.loads(output)
51
+ self.assertIn("enterprise-projects.md", value["sdk"]["invocation"])
52
+ self.assertEqual(set(value["commands"]), {"list", "search", "show", "capability"})
53
+
54
+ def test_lowcode_workflow_and_incomplete_identity_fail(self):
55
+ self.assertEqual(run("enterprise-projects", "list", "--type", "WORKFLOW")[0], 2)
56
+ with patch("sys.stdin", io.StringIO("caller")):
57
+ self.assertEqual(run("enterprise-projects", "capability", "--resource-id", "id", "--token-stdin")[0], 1)