licos-platform-cli 0.4.12__tar.gz → 0.5.1__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 (18) hide show
  1. licos_platform_cli-0.5.1/PKG-INFO +33 -0
  2. licos_platform_cli-0.5.1/README.md +25 -0
  3. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/pyproject.toml +3 -2
  4. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/help_commands.py +149 -166
  5. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/knowledge_commands.py +9 -223
  6. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/main.py +2 -0
  7. licos_platform_cli-0.5.1/src/licos_platform_cli/user_commands.py +54 -0
  8. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/tests/test_cli.py +23 -75
  9. licos_platform_cli-0.5.1/tests/test_user.py +60 -0
  10. licos_platform_cli-0.4.12/PKG-INFO +0 -6
  11. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/.gitignore +0 -0
  12. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/__init__.py +0 -0
  13. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/database_commands.py +0 -0
  14. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/oauth_commands.py +0 -0
  15. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/ontology_commands.py +0 -0
  16. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/project_config_commands.py +0 -0
  17. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/src/licos_platform_cli/storage_commands.py +0 -0
  18. {licos_platform_cli-0.4.12 → licos_platform_cli-0.5.1}/tests/test_project_config.py +0 -0
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.5
2
+ Name: licos-platform-cli
3
+ Version: 0.5.1
4
+ Summary: LICOS platform CLI
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: licos-platform-sdk>=0.6.1
7
+ Description-Content-Type: text/markdown
8
+
9
+ # licos-platform-cli
10
+
11
+ LICOS 平台命令行工具。`licos-platform help` 返回结构化 JSON 帮助。
12
+
13
+ ## 当前使用者(0.5.1 起)
14
+
15
+ ```bash
16
+ licos-platform user me
17
+ licos-platform user me --workspace-id <执行工作空间ID>
18
+ licos-platform help user me
19
+ ```
20
+
21
+ 默认由可信运行时注入 `LICOS_CURRENT_USER_ID`,平台地址、服务凭证和项目工作空间沿用运行时配置。
22
+ 多用户请求可将当前使用者 Token 通过标准输入传入,不将 Token 放在命令行参数中:
23
+
24
+ ```bash
25
+ licos-platform user me --token-stdin
26
+ ```
27
+
28
+ 输入不含 `Bearer ` 前缀的 Token 并结束标准输入。程序调用时可通过子进程的 `input` 参数传入。
29
+
30
+ 输出为与低代码 `sys_user` 相同的 JSON:用户 ID、账号、姓名、头像、执行企业、
31
+ 主部门、全部所属部门、组织任职、主岗位和主职务。部门含名称路径、ID 路径;
32
+ 无部门/任职时保持 `[]`/`null`。缺少当前使用者身份或 Token 失效时返回非零退出码,
33
+ 不改用项目所有者。Token 和内部服务凭证不回显。
@@ -0,0 +1,25 @@
1
+ # licos-platform-cli
2
+
3
+ LICOS 平台命令行工具。`licos-platform help` 返回结构化 JSON 帮助。
4
+
5
+ ## 当前使用者(0.5.1 起)
6
+
7
+ ```bash
8
+ licos-platform user me
9
+ licos-platform user me --workspace-id <执行工作空间ID>
10
+ licos-platform help user me
11
+ ```
12
+
13
+ 默认由可信运行时注入 `LICOS_CURRENT_USER_ID`,平台地址、服务凭证和项目工作空间沿用运行时配置。
14
+ 多用户请求可将当前使用者 Token 通过标准输入传入,不将 Token 放在命令行参数中:
15
+
16
+ ```bash
17
+ licos-platform user me --token-stdin
18
+ ```
19
+
20
+ 输入不含 `Bearer ` 前缀的 Token 并结束标准输入。程序调用时可通过子进程的 `input` 参数传入。
21
+
22
+ 输出为与低代码 `sys_user` 相同的 JSON:用户 ID、账号、姓名、头像、执行企业、
23
+ 主部门、全部所属部门、组织任职、主岗位和主职务。部门含名称路径、ID 路径;
24
+ 无部门/任职时保持 `[]`/`null`。缺少当前使用者身份或 Token 失效时返回非零退出码,
25
+ 不改用项目所有者。Token 和内部服务凭证不回显。
@@ -4,11 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "licos-platform-cli"
7
- version = "0.4.12"
7
+ version = "0.5.1"
8
8
  description = "LICOS platform CLI"
9
+ readme = "README.md"
9
10
  requires-python = ">=3.10"
10
11
  dependencies = [
11
- "licos-platform-sdk>=0.5.9",
12
+ "licos-platform-sdk>=0.6.1",
12
13
  ]
13
14
 
14
15
  [project.scripts]
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import argparse
4
4
  from typing import Any, Callable
5
+ from .user_commands import USER_HELP
5
6
 
6
7
 
7
8
  Handler = Callable[[argparse.Namespace], Any]
@@ -370,7 +371,7 @@ DATABASE_HELP = {
370
371
 
371
372
  KNOWLEDGE_HELP = {
372
373
  "topic": "knowledge",
373
- "description": "Personal/project knowledge datasets plus enterprise knowledge folders, knowledge bases, documents, retrieval, and object storage.",
374
+ "description": "Personal/project knowledge datasets plus read-only enterprise knowledge discovery, documents, retrieval, and download links.",
374
375
  "runtime": RUNTIME_ENV,
375
376
  "rules": [
376
377
  "Use SDK from server/runtime code; do not call from browser bundles.",
@@ -379,9 +380,9 @@ KNOWLEDGE_HELP = {
379
380
  "Search all accessible datasets by default; pass dataset IDs or names only when the user explicitly asks for specific datasets.",
380
381
  "For text imports, the SDK sends UTF-8 text as a text/plain base64 document through the platform API.",
381
382
  "Enterprise commands require an enterprise user. Tenant scope and permissions come from the current user token; never pass or invent tenant IDs.",
382
- "Enterprise knowledge types are STANDARD, GRAPH, and OBJECT_STORAGE. Capabilities are retrieve, upload, list_files, and batch_delete_files.",
383
- "Validate enterprise knowledge references before retrieval, upload, listing, or deletion when an Agent receives IDs from conversation context.",
384
- "Use document-url/object-url for temporary access URLs; do not construct storage URLs.",
383
+ "Enterprise tree supports STANDARD, GRAPH, and OBJECT_STORAGE type filters. Current enterprise APIs support retrieve and list_files only.",
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
+ "Use document-url/document-download-link for temporary access URLs; do not construct storage URLs.",
385
386
  ],
386
387
  "sdk": {
387
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,168 +390,148 @@ KNOWLEDGE_HELP = {
389
390
  "enterprise_python": "from licos_platform_sdk import enterprise_knowledge\nresources = enterprise_knowledge.tree()\nresult = enterprise_knowledge.retrieve('安全规范', 'source-id')",
390
391
  "enterprise_node": "import { enterpriseKnowledge } from '@kmlckj/licos-platform-sdk';\nconst resources = await enterpriseKnowledge.tree();\nconst result = await enterpriseKnowledge.retrieve('安全规范', 'source-id');",
391
392
  },
392
- "commands": {
393
- "runtime": {
394
- "description": "Show knowledge runtime status and capabilities.",
395
- "parameters": [],
396
- "example": "licos-platform knowledge runtime",
397
- },
398
- "model-catalog": {
399
- "description": "Show knowledge-related model catalog metadata.",
400
- "parameters": [],
401
- "example": "licos-platform knowledge model-catalog",
402
- },
403
- "datasets": {
404
- "description": "List knowledge datasets visible to the current project owner.",
405
- "parameters": [
406
- {"name": "--name", "required": False, "description": "Filter by dataset name."},
407
- {"name": "--space-id", "required": False, "description": "Workspace/space ID. Defaults to runtime workspace when available."},
408
- {"name": "--page-size", "required": False, "description": "Page size."},
409
- {"name": "--page-num", "required": False, "description": "Page number."},
410
- ],
411
- "example": "licos-platform knowledge datasets --name project_docs",
412
- },
413
- "create-dataset": {
414
- "description": "Create a knowledge dataset.",
415
- "parameters": [
416
- {"name": "name", "required": True, "description": "Dataset name."},
417
- {"name": "--description", "required": False, "description": "Dataset description."},
418
- {"name": "--space-id", "required": False, "description": "Workspace/space ID."},
419
- ],
420
- "example": "licos-platform knowledge create-dataset project_docs --description 'Project documentation'",
421
- },
422
- "ensure-dataset": {
423
- "description": "Find a dataset by name or create it if missing.",
424
- "parameters": [
425
- {"name": "name", "required": True, "description": "Dataset name."},
426
- {"name": "--description", "required": False, "description": "Description used only when creating."},
427
- ],
428
- "example": "licos-platform knowledge ensure-dataset project_docs",
429
- },
430
- "add": {
431
- "description": "Import raw text, a web URL, or a platform object-storage file reference into a dataset.",
432
- "parameters": [
433
- {"name": "--dataset-id / --dataset", "required": True, "description": "Target dataset ID or dataset name. Names are created when missing."},
434
- {"name": "--content / --url / --source-file-id", "required": True, "description": "Exactly one import source."},
435
- {"name": "--name", "required": False, "description": "Document display name."},
436
- {"name": "--max-tokens", "required": False, "description": "Max tokens per chunk."},
437
- {"name": "--separator", "required": False, "description": "Chunk separator."},
438
- ],
439
- "example": "licos-platform knowledge add --dataset project_docs --content 'FAQ content' --name faq.txt",
440
- },
441
- "search": {
442
- "description": "Run semantic retrieval. Omit dataset filters to search all accessible datasets.",
443
- "parameters": [
444
- {"name": "--query", "required": True, "description": "Search query."},
445
- {"name": "--dataset-id", "required": False, "description": "Dataset ID. Can repeat."},
446
- {"name": "--dataset", "required": False, "description": "Dataset name. Can repeat."},
447
- {"name": "--top-k", "required": False, "description": "Result count, default 5."},
448
- {"name": "--min-score", "required": False, "description": "Minimum score threshold."},
449
- ],
450
- "example": "licos-platform knowledge search --query 'How to reset password?' --top-k 5",
451
- },
452
- "documents": {
453
- "description": "List documents in a dataset.",
454
- "parameters": [
455
- {"name": "dataset_id", "required": True, "description": "Dataset ID."},
456
- {"name": "--page", "required": False, "description": "Page number."},
457
- {"name": "--size", "required": False, "description": "Page size."},
458
- ],
459
- "example": "licos-platform knowledge documents dataset-id --page 1 --size 20",
460
- },
461
- "delete-documents": {
462
- "description": "Delete one or more documents from a dataset.",
463
- "parameters": [
464
- {"name": "dataset_id", "required": True, "description": "Dataset ID."},
465
- {"name": "document_id", "required": True, "description": "Document ID. Can repeat."},
466
- ],
467
- "example": "licos-platform knowledge delete-documents dataset-id doc-1 doc-2",
468
- },
469
- "enterprise-tree": {
470
- "description": "Return the enterprise knowledge resource tree visible to the current enterprise user.",
471
- "parameters": [{"name": "--include-type", "type": "enum, repeatable", "required": False, "values": ["STANDARD", "GRAPH", "OBJECT_STORAGE"], "description": "Limit returned knowledge types."}],
472
- "returns": "Tree response with status, tenant_id, permission_scope, nodes, capabilities, and children.",
473
- "example": "licos-platform knowledge enterprise tree --include-type STANDARD --include-type GRAPH",
474
- },
475
- "enterprise-search": {
476
- "description": "Search visible enterprise knowledge bases by name.",
477
- "parameters": [{"name": "--query", "type": "string", "required": True, "description": "Knowledge base name search text."}, {"name": "--include-type", "type": "enum, repeatable", "required": False, "description": "STANDARD, GRAPH, or OBJECT_STORAGE."}, {"name": "--page / --page-size", "type": "integer", "required": False, "description": "One-based pagination; page size maximum is 100."}],
478
- "returns": "Platform paged search response containing visible enterprise knowledge resources.",
479
- "example": "licos-platform knowledge enterprise search --query 设备手册 --include-type STANDARD",
480
- },
481
- "enterprise-validate": {
482
- "description": "Validate one or more enterprise knowledge IDs against the current user's access and required capability.",
483
- "parameters": [{"name": "knowledge_base_id", "type": "string, repeatable", "required": True, "description": "Knowledge base/source ID."}, {"name": "--required-capability", "type": "enum", "required": False, "values": ["retrieve", "upload", "list_files", "batch_delete_files"], "description": "Required operation capability; default retrieve."}],
484
- "returns": "Object with valid boolean, required_capability string, and per-ID validation items.",
485
- "example": "licos-platform knowledge enterprise validate source-1 --required-capability retrieve",
486
- },
487
- "enterprise-retrieve": {
488
- "description": "Retrieve evidence from explicitly selected enterprise knowledge bases.",
489
- "parameters": [{"name": "--query", "type": "string", "required": True, "description": "Natural-language retrieval query."}, {"name": "--source-id", "type": "string", "required": True, "description": "Knowledge base source ID."}],
490
- "returns": "Enterprise retrieval response from the platform, including matching evidence and source metadata when available.",
491
- "example": "licos-platform knowledge enterprise retrieve --query 安全规范 --source-id source-1",
492
- },
493
- "enterprise-folders": {
494
- "description": "List enterprise knowledge folders.",
495
- "parameters": [{"name": "--parent-id", "type": "string", "required": False, "description": "Parent folder ID; omit for root."}, {"name": "--include-children", "type": "flag", "required": False, "description": "Include descendants."}, {"name": "--query", "type": "string", "required": False, "description": "Folder name filter."}],
496
- "returns": "Paged folder response.",
497
- "example": "licos-platform knowledge enterprise folders --include-children",
498
- },
499
- "enterprise-create-folder": {
500
- "description": "Create an enterprise knowledge folder.",
501
- "parameters": [{"name": "name", "type": "string", "required": True, "description": "Folder name."}, {"name": "--parent-id", "type": "string", "required": False, "description": "Parent folder ID."}, {"name": "--description", "type": "string", "required": False, "description": "Folder description."}],
502
- "returns": "Created folder resource.",
503
- "example": "licos-platform knowledge enterprise create-folder 设备文档 --description 设备说明书",
504
- },
505
- "enterprise-delete-folder": {
506
- "description": "Delete an enterprise knowledge folder after explicit confirmation.",
507
- "parameters": [{"name": "folder_id", "type": "string", "required": True, "description": "Folder ID."}, {"name": "--reason", "type": "string", "required": False, "description": "Audit reason."}, {"name": "--hard-delete", "type": "flag", "required": False, "description": "Permanently delete."}, {"name": "--confirm-name", "type": "string", "required": False, "description": "Name required by platform confirmation policy."}, {"name": "--confirm", "type": "flag", "required": True, "description": "Confirm destructive operation."}],
508
- "returns": "Platform deletion result.",
509
- "example": "licos-platform knowledge enterprise delete-folder folder-id --reason 重建目录 --confirm",
510
- },
511
- "enterprise-create-knowledge-base": {
512
- "description": "Create a STANDARD, GRAPH, or OBJECT_STORAGE enterprise knowledge base.",
513
- "parameters": [{"name": "name", "type": "string", "required": True, "description": "Knowledge base name."}, {"name": "--folder-id", "type": "string", "required": False, "description": "Parent folder ID."}, {"name": "--knowledge-type", "type": "enum", "required": False, "values": ["STANDARD", "GRAPH", "OBJECT_STORAGE"], "description": "Knowledge type; default STANDARD."}, {"name": "--description", "type": "string", "required": False, "description": "Knowledge base description."}],
514
- "returns": "Created knowledge base with durable source/resource ID.",
515
- "example": "licos-platform knowledge enterprise create-knowledge-base 设备手册 --folder-id folder-id --knowledge-type STANDARD",
516
- },
517
- "enterprise-documents": {
518
- "description": "List documents belonging to one enterprise knowledge base.",
519
- "parameters": [{"name": "source_id", "type": "string", "required": True, "description": "Knowledge base source ID."}, {"name": "--query", "type": "string", "required": False, "description": "Document search text."}, {"name": "--status", "type": "string", "required": False, "description": "Platform document processing status."}, {"name": "--document-id", "type": "string", "required": False, "description": "Exact document ID filter."}],
520
- "returns": "Paged document response with document processing metadata.",
521
- "example": "licos-platform knowledge enterprise documents source-id --page 1 --page-size 20",
522
- },
523
- "enterprise-upload-document": {
524
- "description": "Upload a local document to an enterprise knowledge base. Use --chunked for resumable uploads.",
525
- "parameters": [{"name": "source_id", "type": "string", "required": True, "description": "Target knowledge base source ID."}, {"name": "file", "type": "path", "required": True, "description": "Readable local file."}, {"name": "--file-name", "type": "string", "required": False, "description": "Override display name."}, {"name": "--content-type", "type": "MIME string", "required": False, "description": "Override inferred MIME type."}, {"name": "--chunked", "type": "flag", "required": False, "description": "Use resumable upload."}, {"name": "--chunk-size", "type": "integer bytes", "required": False, "description": "5 MiB to 100 MiB; default 8 MiB."}],
526
- "returns": "Asynchronous processing task/result object. Poll task ID when returned.",
527
- "example": "licos-platform knowledge enterprise upload-document source-id ./manual.pdf --chunked",
528
- },
529
- "enterprise-delete-documents": {
530
- "description": "Batch delete up to 100 enterprise knowledge documents after explicit confirmation.",
531
- "parameters": [{"name": "source_id", "type": "string", "required": True, "description": "Knowledge base source ID."}, {"name": "document_id", "type": "string, repeatable", "required": True, "description": "Document ID."}, {"name": "--operator / --reason", "type": "string", "required": False, "description": "Audit metadata."}, {"name": "--confirm", "type": "flag", "required": True, "description": "Confirm destructive operation."}],
532
- "returns": "Batch deletion result, which may report partial failures.",
533
- "example": "licos-platform knowledge enterprise delete-documents source-id doc-1 doc-2 --reason 重复文档 --confirm",
534
- },
535
- "enterprise-objects": {
536
- "description": "Query objects in an OBJECT_STORAGE enterprise knowledge base.",
537
- "parameters": [{"name": "source_id", "type": "string", "required": True, "description": "Object-storage knowledge base source ID."}, {"name": "--prefix", "type": "string", "required": False, "description": "Object-key prefix."}, {"name": "--query", "type": "string", "required": False, "description": "Object name search text."}],
538
- "returns": "Paged object metadata response.",
539
- "example": "licos-platform knowledge enterprise objects source-id --prefix reports/",
540
- },
541
- "enterprise-upload-objects": {
542
- "description": "Upload one or more files to an OBJECT_STORAGE enterprise knowledge base.",
543
- "parameters": [{"name": "source_id", "type": "string", "required": True, "description": "Object-storage knowledge base source ID."}, {"name": "file", "type": "path, repeatable", "required": True, "description": "Local files."}, {"name": "--object-key", "type": "string, repeatable", "required": False, "description": "Explicit object key for each file; count must match files."}, {"name": "--prefix", "type": "string", "required": False, "description": "Target object prefix."}, {"name": "--metadata", "type": "JSON object", "required": False, "description": "Upload metadata."}],
544
- "returns": "Asynchronous object upload task/result.",
545
- "example": "licos-platform knowledge enterprise upload-objects source-id ./a.pdf ./b.pdf --prefix reports/",
546
- },
547
- "enterprise-object-url": {
548
- "description": "Get a temporary URL for one enterprise knowledge object.",
549
- "parameters": [{"name": "source_id", "type": "string", "required": True, "description": "Object-storage knowledge base source ID."}, {"name": "object_key", "type": "string", "required": True, "description": "Exact object key."}, {"name": "--inline", "type": "flag", "required": False, "description": "Request inline display instead of download."}],
550
- "returns": "Object with temporary url string.",
551
- "example": "licos-platform knowledge enterprise object-url source-id reports/manual.pdf --inline",
552
- },
553
- },
393
+ "commands": {'runtime': {'description': 'Show knowledge runtime status and capabilities.',
394
+ 'parameters': [],
395
+ 'example': 'licos-platform knowledge runtime'},
396
+ 'model-catalog': {'description': 'Show knowledge-related model catalog metadata.',
397
+ 'parameters': [],
398
+ 'example': 'licos-platform knowledge model-catalog'},
399
+ 'datasets': {'description': 'List knowledge datasets visible to the current project owner.',
400
+ 'parameters': [{'name': '--name', 'required': False, 'description': 'Filter by dataset name.'},
401
+ {'name': '--space-id',
402
+ 'required': False,
403
+ 'description': 'Workspace/space ID. Defaults to runtime workspace when available.'},
404
+ {'name': '--page-size', 'required': False, 'description': 'Page size.'},
405
+ {'name': '--page-num', 'required': False, 'description': 'Page number.'}],
406
+ 'example': 'licos-platform knowledge datasets --name project_docs'},
407
+ 'create-dataset': {'description': 'Create a knowledge dataset.',
408
+ 'parameters': [{'name': 'name', 'required': True, 'description': 'Dataset name.'},
409
+ {'name': '--description', 'required': False, 'description': 'Dataset description.'},
410
+ {'name': '--space-id', 'required': False, 'description': 'Workspace/space ID.'}],
411
+ 'example': "licos-platform knowledge create-dataset project_docs --description 'Project documentation'"},
412
+ 'ensure-dataset': {'description': 'Find a dataset by name or create it if missing.',
413
+ 'parameters': [{'name': 'name', 'required': True, 'description': 'Dataset name.'},
414
+ {'name': '--description',
415
+ 'required': False,
416
+ 'description': 'Description used only when creating.'}],
417
+ 'example': 'licos-platform knowledge ensure-dataset project_docs'},
418
+ 'add': {'description': 'Import raw text, a web URL, or a platform object-storage file reference into a dataset.',
419
+ 'parameters': [{'name': '--dataset-id / --dataset',
420
+ 'required': True,
421
+ 'description': 'Target dataset ID or dataset name. Names are created when missing.'},
422
+ {'name': '--content / --url / --source-file-id',
423
+ 'required': True,
424
+ 'description': 'Exactly one import source.'},
425
+ {'name': '--name', 'required': False, 'description': 'Document display name.'},
426
+ {'name': '--max-tokens', 'required': False, 'description': 'Max tokens per chunk.'},
427
+ {'name': '--separator', 'required': False, 'description': 'Chunk separator.'}],
428
+ 'example': "licos-platform knowledge add --dataset project_docs --content 'FAQ content' --name faq.txt"},
429
+ 'search': {'description': 'Run semantic retrieval. Omit dataset filters to search all accessible datasets.',
430
+ 'parameters': [{'name': '--query', 'required': True, 'description': 'Search query.'},
431
+ {'name': '--dataset-id', 'required': False, 'description': 'Dataset ID. Can repeat.'},
432
+ {'name': '--dataset', 'required': False, 'description': 'Dataset name. Can repeat.'},
433
+ {'name': '--top-k', 'required': False, 'description': 'Result count, default 5.'},
434
+ {'name': '--min-score', 'required': False, 'description': 'Minimum score threshold.'}],
435
+ 'example': "licos-platform knowledge search --query 'How to reset password?' --top-k 5"},
436
+ 'documents': {'description': 'List documents in a dataset.',
437
+ 'parameters': [{'name': 'dataset_id', 'required': True, 'description': 'Dataset ID.'},
438
+ {'name': '--page', 'required': False, 'description': 'Page number.'},
439
+ {'name': '--size', 'required': False, 'description': 'Page size.'}],
440
+ 'example': 'licos-platform knowledge documents dataset-id --page 1 --size 20'},
441
+ 'delete-documents': {'description': 'Delete one or more documents from a dataset.',
442
+ 'parameters': [{'name': 'dataset_id', 'required': True, 'description': 'Dataset ID.'},
443
+ {'name': 'document_id', 'required': True, 'description': 'Document ID. Can repeat.'}],
444
+ 'example': 'licos-platform knowledge delete-documents dataset-id doc-1 doc-2'},
445
+ 'enterprise-tree': {'description': 'Return the enterprise knowledge resource tree visible to the current enterprise user.',
446
+ 'parameters': [{'name': '--include-type',
447
+ 'type': 'enum, repeatable',
448
+ 'required': False,
449
+ 'values': ['STANDARD', 'GRAPH', 'OBJECT_STORAGE'],
450
+ 'description': 'Limit returned knowledge types.'}],
451
+ 'returns': 'Tree response with status, tenant_id, permission_scope, nodes, capabilities, and children.',
452
+ 'example': 'licos-platform knowledge enterprise tree --include-type STANDARD --include-type GRAPH'},
453
+ 'enterprise-search': {'description': 'Search visible enterprise knowledge bases by name.',
454
+ 'parameters': [{'name': '--query',
455
+ 'type': 'string',
456
+ 'required': True,
457
+ 'description': 'Knowledge base name search text.'},
458
+ {'name': '--page / --page-size',
459
+ 'type': 'integer',
460
+ 'required': False,
461
+ 'description': 'One-based pagination; page size maximum is 100.'}],
462
+ 'returns': 'Platform paged search response containing visible enterprise knowledge resources.',
463
+ 'example': 'licos-platform knowledge enterprise search --query 设备手册 --include-type STANDARD'},
464
+ 'enterprise-validate': {'description': "Validate one or more enterprise knowledge IDs against the current user's access "
465
+ 'and required capability.',
466
+ 'parameters': [{'name': 'knowledge_base_id',
467
+ 'type': 'string, repeatable',
468
+ 'required': True,
469
+ 'description': 'Knowledge base/source ID.'},
470
+ {'name': '--required-capability',
471
+ 'type': 'enum',
472
+ 'required': False,
473
+ 'values': ['retrieve', 'upload', 'list_files', 'batch_delete_files'],
474
+ 'description': 'Required operation capability; default retrieve.'}],
475
+ 'returns': 'Object with valid boolean, required_capability string, and per-ID validation items.',
476
+ 'example': 'licos-platform knowledge enterprise validate source-1 --required-capability retrieve'},
477
+ 'enterprise-retrieve': {'description': 'Retrieve evidence from explicitly selected enterprise knowledge bases.',
478
+ 'parameters': [{'name': '--query',
479
+ 'type': 'string',
480
+ 'required': True,
481
+ 'description': 'Natural-language retrieval query.'},
482
+ {'name': '--source-id',
483
+ 'type': 'string',
484
+ 'required': True,
485
+ 'description': 'Knowledge base source ID.'}],
486
+ 'returns': 'Enterprise retrieval response from the platform, including matching evidence and '
487
+ 'source metadata when available.',
488
+ 'example': 'licos-platform knowledge enterprise retrieve --query 安全规范 --source-id source-1'},
489
+ 'enterprise-folders': {'description': 'List enterprise knowledge folders.',
490
+ 'parameters': [{'name': '--parent-id',
491
+ 'type': 'string',
492
+ 'required': False,
493
+ 'description': 'Parent folder ID; omit for root.'},
494
+ {'name': '--include-children',
495
+ 'type': 'flag',
496
+ 'required': False,
497
+ 'description': 'Include descendants.'}],
498
+ 'returns': 'Paged folder response.',
499
+ 'example': 'licos-platform knowledge enterprise folders --include-children'},
500
+ 'enterprise-documents': {'description': 'List documents belonging to one enterprise knowledge base.',
501
+ 'parameters': [{'name': 'source_id',
502
+ 'type': 'string',
503
+ 'required': True,
504
+ 'description': 'Knowledge base source ID.'},
505
+ {'name': '--query',
506
+ 'type': 'string',
507
+ 'required': False,
508
+ 'description': 'Document search text.'}],
509
+ 'returns': 'Paged document response with document processing metadata.',
510
+ 'example': 'licos-platform knowledge enterprise documents source-id --page 1 --page-size 20'},
511
+ 'enterprise-folder': {'description': '读取企业目录详情。',
512
+ 'parameters': [{'name': 'folder-id', 'required': True}],
513
+ 'example': 'licos-platform knowledge enterprise folder folder-id'},
514
+ 'enterprise-knowledge-base': {'description': '读取企业知识库详情。',
515
+ 'parameters': [{'name': 'source-id', 'required': True}],
516
+ 'example': 'licos-platform knowledge enterprise knowledge-base source-id'},
517
+ 'enterprise-document': {'description': '读取文件详情,包含原始状态及元数据。',
518
+ 'parameters': [{'name': 'document-id', 'required': True}],
519
+ 'example': 'licos-platform knowledge enterprise document document-id'},
520
+ 'enterprise-document-url': {'description': '获取临时原文 URL,不得持久化。',
521
+ 'parameters': [{'name': 'document-id', 'required': True}],
522
+ 'example': 'licos-platform knowledge enterprise document-url document-id'},
523
+ 'enterprise-document-download-link': {'description': '获取临时下载短链及文件 ID。',
524
+ 'parameters': [{'name': 'document-id', 'required': True}],
525
+ 'example': 'licos-platform knowledge enterprise document-download-link document-id'},
526
+ 'enterprise-folder-knowledge-bases': {'description': '列出目录下的知识库。',
527
+ 'parameters': [{'name': 'folder-id', 'required': True},
528
+ {'name': '--include-children', 'required': False},
529
+ {'name': '--page / --page-size', 'required': False}],
530
+ 'example': 'licos-platform knowledge enterprise folder-knowledge-bases folder-id'},
531
+ 'enterprise-document-chunks': {'description': '分页读取文件分片,不支持关键词过滤。',
532
+ 'parameters': [{'name': 'document-id', 'required': True},
533
+ {'name': '--page / --page-size', 'required': False}],
534
+ 'example': 'licos-platform knowledge enterprise document-chunks document-id'}},
554
535
  }
555
536
 
556
537
 
@@ -860,6 +841,7 @@ ONTOLOGY_HELP = {
860
841
 
861
842
 
862
843
  HELP_TOPICS = {
844
+ "user": USER_HELP,
863
845
  "storage": STORAGE_HELP,
864
846
  "database": DATABASE_HELP,
865
847
  "knowledge": KNOWLEDGE_HELP,
@@ -891,6 +873,7 @@ def _cmd_help(args: argparse.Namespace) -> dict[str, Any]:
891
873
  "licos-platform help project-config set-database",
892
874
  "licos-platform help ontology",
893
875
  "licos-platform help ontology search",
876
+ "licos-platform help user me",
894
877
  ],
895
878
  "topics": sorted(HELP_TOPICS),
896
879
  }
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import argparse
4
- import json
5
4
  from typing import Any, Callable
6
5
 
7
6
  from licos_platform_sdk import enterprise_knowledge, knowledge
@@ -129,7 +128,6 @@ def _cmd_enterprise_tree(args: argparse.Namespace) -> Any:
129
128
  def _cmd_enterprise_search(args: argparse.Namespace) -> Any:
130
129
  return enterprise_knowledge.search_knowledge_bases(
131
130
  args.query,
132
- include_types=args.include_types,
133
131
  page=args.page,
134
132
  page_size=args.page_size,
135
133
  )
@@ -150,7 +148,6 @@ def _cmd_enterprise_folders(args: argparse.Namespace) -> Any:
150
148
  return enterprise_knowledge.list_folders(
151
149
  parent_id=args.parent_id,
152
150
  include_children=args.include_children,
153
- query=args.query,
154
151
  page=args.page,
155
152
  page_size=args.page_size,
156
153
  )
@@ -160,64 +157,25 @@ def _cmd_enterprise_folder(args: argparse.Namespace) -> Any:
160
157
  return enterprise_knowledge.get_folder(args.folder_id)
161
158
 
162
159
 
163
- def _cmd_enterprise_create_folder(args: argparse.Namespace) -> Any:
164
- return enterprise_knowledge.create_folder(
165
- args.name,
166
- parent_id=args.parent_id,
167
- description=args.description,
168
- )
169
-
170
-
171
- def _cmd_enterprise_delete_folder(args: argparse.Namespace) -> Any:
172
- return enterprise_knowledge.delete_folder(
173
- args.folder_id,
174
- reason=args.reason,
175
- hard_delete=args.hard_delete,
176
- confirm_name=args.confirm_name,
177
- )
178
-
179
-
180
160
  def _cmd_enterprise_folder_knowledge_bases(args: argparse.Namespace) -> Any:
181
161
  return enterprise_knowledge.list_folder_knowledge_bases(
182
162
  args.folder_id,
183
163
  include_children=args.include_children,
184
- include_types=args.include_types,
185
- query=args.query,
186
164
  page=args.page,
187
165
  page_size=args.page_size,
188
166
  )
189
167
 
190
168
 
191
- def _cmd_enterprise_create_knowledge_base(args: argparse.Namespace) -> Any:
192
- return enterprise_knowledge.create_knowledge_base(
193
- args.name,
194
- folder_id=args.folder_id,
195
- description=args.description,
196
- knowledge_type=args.knowledge_type,
197
- )
198
-
199
-
200
169
  def _cmd_enterprise_knowledge_base(args: argparse.Namespace) -> Any:
201
170
  return enterprise_knowledge.get_knowledge_base(args.source_id)
202
171
 
203
172
 
204
- def _cmd_enterprise_delete_knowledge_base(args: argparse.Namespace) -> Any:
205
- return enterprise_knowledge.delete_knowledge_base(
206
- args.source_id,
207
- reason=args.reason,
208
- hard_delete=args.hard_delete,
209
- confirm_name=args.confirm_name,
210
- )
211
-
212
-
213
173
  def _cmd_enterprise_documents(args: argparse.Namespace) -> Any:
214
174
  return enterprise_knowledge.list_documents(
215
175
  args.source_id,
216
176
  page=args.page,
217
177
  page_size=args.page_size,
218
178
  query=args.query,
219
- status=args.status,
220
- document_id=args.document_id,
221
179
  )
222
180
 
223
181
 
@@ -230,7 +188,6 @@ def _cmd_enterprise_document_chunks(args: argparse.Namespace) -> Any:
230
188
  args.document_id,
231
189
  page=args.page,
232
190
  page_size=args.page_size,
233
- query=args.query,
234
191
  )
235
192
 
236
193
 
@@ -238,86 +195,8 @@ def _cmd_enterprise_document_url(args: argparse.Namespace) -> Any:
238
195
  return {"url": enterprise_knowledge.document_original_url(args.document_id, download=args.download)}
239
196
 
240
197
 
241
- def _cmd_enterprise_delete_documents(args: argparse.Namespace) -> Any:
242
- return enterprise_knowledge.batch_delete_documents(
243
- args.source_id,
244
- args.document_id,
245
- operator=args.operator,
246
- reason=args.reason,
247
- )
248
-
249
-
250
- def _cmd_enterprise_upload_document(args: argparse.Namespace) -> Any:
251
- options = {
252
- "file_name": args.file_name,
253
- "content_type": args.content_type,
254
- }
255
- if args.chunked:
256
- return enterprise_knowledge.upload_document_chunked(
257
- args.source_id,
258
- args.file,
259
- chunk_size=args.chunk_size,
260
- **options,
261
- )
262
- return enterprise_knowledge.upload_document(args.source_id, args.file, **options)
263
-
264
-
265
- def _cmd_enterprise_object_contract(_args: argparse.Namespace) -> Any:
266
- return enterprise_knowledge.object_storage_contract()
267
-
268
-
269
- def _cmd_enterprise_objects(args: argparse.Namespace) -> Any:
270
- return enterprise_knowledge.query_objects(
271
- args.source_id,
272
- prefix=args.prefix,
273
- query=args.query,
274
- page=args.page,
275
- page_size=args.page_size,
276
- )
277
-
278
-
279
- def _parse_json_object(value: str | None, argument: str) -> dict[str, Any] | None:
280
- if value is None:
281
- return None
282
- try:
283
- parsed = json.loads(value)
284
- except json.JSONDecodeError as exc:
285
- raise argparse.ArgumentTypeError(f"{argument} must be valid JSON: {exc.msg}") from exc
286
- if not isinstance(parsed, dict):
287
- raise argparse.ArgumentTypeError(f"{argument} must be a JSON object")
288
- return parsed
289
-
290
-
291
- def _cmd_enterprise_upload_objects(args: argparse.Namespace) -> Any:
292
- return enterprise_knowledge.upload_objects(
293
- args.source_id,
294
- args.file,
295
- object_keys=args.object_key,
296
- prefix=args.prefix,
297
- metadata=_parse_json_object(args.metadata, "--metadata"),
298
- )
299
-
300
-
301
- def _cmd_enterprise_object(args: argparse.Namespace) -> Any:
302
- return enterprise_knowledge.get_object(args.source_id, args.object_key)
303
-
304
-
305
- def _cmd_enterprise_object_url(args: argparse.Namespace) -> Any:
306
- return {
307
- "url": enterprise_knowledge.object_download_url(
308
- args.source_id,
309
- args.object_key,
310
- inline=args.inline,
311
- )
312
- }
313
-
314
-
315
- def _cmd_enterprise_delete_object(args: argparse.Namespace) -> Any:
316
- return enterprise_knowledge.delete_object(args.source_id, args.object_key)
317
-
318
-
319
- def _cmd_enterprise_object_task(args: argparse.Namespace) -> Any:
320
- return enterprise_knowledge.get_object_upload_task(args.task_id)
198
+ def _cmd_enterprise_document_download_link(args: argparse.Namespace) -> Any:
199
+ return enterprise_knowledge.document_download_link(args.document_id)
321
200
 
322
201
 
323
202
  def _add_dataset_selector(parser: argparse.ArgumentParser) -> None:
@@ -354,13 +233,6 @@ def _add_enterprise_types(parser: argparse.ArgumentParser) -> None:
354
233
  )
355
234
 
356
235
 
357
- def _add_enterprise_delete_args(parser: argparse.ArgumentParser) -> None:
358
- parser.add_argument("--reason", default=None, help="Audit reason for deleting the resource")
359
- parser.add_argument("--hard-delete", action="store_true", default=None, help="Permanently delete the resource")
360
- parser.add_argument("--confirm-name", default=None, help="Resource name confirmation required by platform policy")
361
- parser.add_argument("--confirm", action="store_true", required=True, help="Confirm this destructive operation")
362
-
363
-
364
236
  def _add_enterprise_parser(
365
237
  knowledge_subparsers: argparse._SubParsersAction[argparse.ArgumentParser],
366
238
  ) -> None:
@@ -376,7 +248,6 @@ def _add_enterprise_parser(
376
248
 
377
249
  search = commands.add_parser("search", help="Search enterprise knowledge bases by name")
378
250
  search.add_argument("--query", "-q", required=True)
379
- _add_enterprise_types(search)
380
251
  _add_page_args(search)
381
252
  _set_handler(search, _cmd_enterprise_search)
382
253
 
@@ -397,58 +268,28 @@ def _add_enterprise_parser(
397
268
  folders = commands.add_parser("folders", help="List enterprise knowledge folders")
398
269
  folders.add_argument("--parent-id", default=None)
399
270
  folders.add_argument("--include-children", action="store_true", default=None)
400
- _add_enterprise_query_args(folders)
271
+ _add_page_args(folders)
401
272
  _set_handler(folders, _cmd_enterprise_folders)
402
273
 
403
274
  folder = commands.add_parser("folder", help="Get one enterprise knowledge folder")
404
275
  folder.add_argument("folder_id")
405
276
  _set_handler(folder, _cmd_enterprise_folder)
406
277
 
407
- create_folder = commands.add_parser("create-folder", help="Create an enterprise knowledge folder")
408
- create_folder.add_argument("name")
409
- create_folder.add_argument("--parent-id", default=None)
410
- create_folder.add_argument("--description", default=None)
411
- _set_handler(create_folder, _cmd_enterprise_create_folder)
412
-
413
- delete_folder = commands.add_parser("delete-folder", help="Delete an enterprise knowledge folder")
414
- delete_folder.add_argument("folder_id")
415
- _add_enterprise_delete_args(delete_folder)
416
- _set_handler(delete_folder, _cmd_enterprise_delete_folder)
417
-
418
278
  folder_bases = commands.add_parser(
419
279
  "folder-knowledge-bases",
420
280
  help="List knowledge bases in an enterprise folder",
421
281
  )
422
282
  folder_bases.add_argument("folder_id")
423
283
  folder_bases.add_argument("--include-children", action="store_true", default=None)
424
- _add_enterprise_types(folder_bases)
425
- _add_enterprise_query_args(folder_bases)
284
+ _add_page_args(folder_bases)
426
285
  _set_handler(folder_bases, _cmd_enterprise_folder_knowledge_bases)
427
286
 
428
- create_base = commands.add_parser("create-knowledge-base", help="Create an enterprise knowledge base")
429
- create_base.add_argument("name")
430
- create_base.add_argument("--folder-id", default=None)
431
- create_base.add_argument("--description", default=None)
432
- create_base.add_argument(
433
- "--knowledge-type",
434
- choices=["STANDARD", "GRAPH", "OBJECT_STORAGE"],
435
- default="STANDARD",
436
- )
437
- _set_handler(create_base, _cmd_enterprise_create_knowledge_base)
438
-
439
287
  knowledge_base = commands.add_parser("knowledge-base", help="Get one enterprise knowledge base")
440
288
  knowledge_base.add_argument("source_id")
441
289
  _set_handler(knowledge_base, _cmd_enterprise_knowledge_base)
442
290
 
443
- delete_base = commands.add_parser("delete-knowledge-base", help="Delete an enterprise knowledge base")
444
- delete_base.add_argument("source_id")
445
- _add_enterprise_delete_args(delete_base)
446
- _set_handler(delete_base, _cmd_enterprise_delete_knowledge_base)
447
-
448
291
  documents = commands.add_parser("documents", help="List documents in an enterprise knowledge base")
449
292
  documents.add_argument("source_id")
450
- documents.add_argument("--status", default=None)
451
- documents.add_argument("--document-id", default=None)
452
293
  _add_enterprise_query_args(documents)
453
294
  _set_handler(documents, _cmd_enterprise_documents)
454
295
 
@@ -458,7 +299,7 @@ def _add_enterprise_parser(
458
299
 
459
300
  chunks = commands.add_parser("document-chunks", help="List chunks for one enterprise knowledge document")
460
301
  chunks.add_argument("document_id")
461
- _add_enterprise_query_args(chunks)
302
+ _add_page_args(chunks)
462
303
  _set_handler(chunks, _cmd_enterprise_document_chunks)
463
304
 
464
305
  document_url = commands.add_parser("document-url", help="Get a temporary original document URL")
@@ -466,65 +307,10 @@ def _add_enterprise_parser(
466
307
  document_url.add_argument("--download", action="store_true", help="Request download disposition")
467
308
  _set_handler(document_url, _cmd_enterprise_document_url)
468
309
 
469
- delete_documents = commands.add_parser("delete-documents", help="Delete enterprise knowledge documents")
470
- delete_documents.add_argument("source_id")
471
- delete_documents.add_argument("document_id", nargs="+")
472
- delete_documents.add_argument("--operator", default=None)
473
- delete_documents.add_argument("--reason", default=None)
474
- delete_documents.add_argument("--confirm", action="store_true", required=True)
475
- _set_handler(delete_documents, _cmd_enterprise_delete_documents)
476
-
477
- upload_document = commands.add_parser("upload-document", help="Upload a document asynchronously")
478
- upload_document.add_argument("source_id")
479
- upload_document.add_argument("file")
480
- upload_document.add_argument("--file-name", default=None)
481
- upload_document.add_argument("--content-type", default=None)
482
- upload_document.add_argument("--chunked", action="store_true", help="Use resumable chunked upload")
483
- upload_document.add_argument(
484
- "--chunk-size",
485
- type=int,
486
- default=enterprise_knowledge.DEFAULT_CHUNK_SIZE,
487
- help="Chunk size in bytes; valid range is 5 MiB to 100 MiB",
488
- )
489
- _set_handler(upload_document, _cmd_enterprise_upload_document)
490
-
491
- object_contract = commands.add_parser("object-contract", help="Get object-storage capability contract")
492
- _set_handler(object_contract, _cmd_enterprise_object_contract)
493
-
494
- objects = commands.add_parser("objects", help="Query objects in an object-storage knowledge base")
495
- objects.add_argument("source_id")
496
- objects.add_argument("--prefix", default=None)
497
- _add_enterprise_query_args(objects)
498
- _set_handler(objects, _cmd_enterprise_objects)
499
-
500
- upload_objects = commands.add_parser("upload-objects", help="Upload files to an object-storage knowledge base")
501
- upload_objects.add_argument("source_id")
502
- upload_objects.add_argument("file", nargs="+")
503
- upload_objects.add_argument("--object-key", action="append", default=None)
504
- upload_objects.add_argument("--prefix", default=None)
505
- upload_objects.add_argument("--metadata", default=None, help="JSON object applied to this upload")
506
- _set_handler(upload_objects, _cmd_enterprise_upload_objects)
507
-
508
- object_detail = commands.add_parser("object", help="Get object metadata")
509
- object_detail.add_argument("source_id")
510
- object_detail.add_argument("object_key")
511
- _set_handler(object_detail, _cmd_enterprise_object)
512
-
513
- object_url = commands.add_parser("object-url", help="Get a temporary object URL")
514
- object_url.add_argument("source_id")
515
- object_url.add_argument("object_key")
516
- object_url.add_argument("--inline", action="store_true", help="Request inline display disposition")
517
- _set_handler(object_url, _cmd_enterprise_object_url)
518
-
519
- delete_object = commands.add_parser("delete-object", help="Delete one object")
520
- delete_object.add_argument("source_id")
521
- delete_object.add_argument("object_key")
522
- delete_object.add_argument("--confirm", action="store_true", required=True)
523
- _set_handler(delete_object, _cmd_enterprise_delete_object)
524
-
525
- object_task = commands.add_parser("object-task", help="Get one object upload task")
526
- object_task.add_argument("task_id")
527
- _set_handler(object_task, _cmd_enterprise_object_task)
310
+ download_link = commands.add_parser("document-download-link", help="Get a temporary document download link")
311
+ download_link.add_argument("document_id")
312
+ _set_handler(download_link, _cmd_enterprise_document_download_link)
313
+
528
314
 
529
315
 
530
316
  def add_knowledge_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
@@ -14,6 +14,7 @@ from .oauth_commands import add_oauth_parser
14
14
  from .ontology_commands import add_ontology_parser
15
15
  from .project_config_commands import add_project_config_parser
16
16
  from .storage_commands import add_storage_parser
17
+ from .user_commands import add_user_parser
17
18
 
18
19
 
19
20
  def _print_json(value: Any) -> None:
@@ -38,6 +39,7 @@ def _build_parser() -> argparse.ArgumentParser:
38
39
  add_oauth_parser(subparsers)
39
40
  add_project_config_parser(subparsers)
40
41
  add_ontology_parser(subparsers)
42
+ add_user_parser(subparsers)
41
43
  return parser
42
44
 
43
45
 
@@ -0,0 +1,54 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import sys
5
+
6
+ from licos_platform_sdk import get_current_user
7
+
8
+
9
+ USER_HELP = {
10
+ "topic": "user",
11
+ "description": "查询当前执行使用者,返回与低代码 sys_user 相同的用户、企业和组织任职信息。",
12
+ "runtime": [
13
+ {"name": "LICOS_PLATFORM_API_BASE_URL", "description": "平台 API 地址。"},
14
+ {"name": "LICOS_AI_AGENT_TOKEN", "description": "运行时内部服务凭证,不输出。"},
15
+ {"name": "LICOS_CURRENT_USER_ID", "description": "未通过标准输入传 Token 时,必须由可信运行时注入的当前用户 ID。"},
16
+ {"name": "LICOS_WORKSPACE_ID / LICOS_OWNER_WORKSPACE_ID / AGENT_WORKSPACE_ID", "description": "执行工作空间,决定企业范围。"},
17
+ ],
18
+ "rules": [
19
+ "多用户请求传当前使用者 Token;不使用项目所有者代替使用者。",
20
+ "企业范围按执行工作空间确定,个人或企业外使用者的空组织信息原样返回。",
21
+ "不缓存结果,不回显 Token;Token 失效直接报错。",
22
+ ],
23
+ "sdk": {
24
+ "python": "from licos_platform_sdk import get_current_user\nsys_user = get_current_user(user_token=token)",
25
+ "node": "import { getCurrentUser } from '@kmlckj/licos-platform-sdk';\nconst sysUser = await getCurrentUser({ userToken: token });",
26
+ },
27
+ "commands": {
28
+ "me": {
29
+ "description": "查询当前使用者信息。",
30
+ "parameters": [
31
+ {"name": "--token-stdin", "type": "boolean", "required": False, "description": "从标准输入读取当前用户 Token,不含 Bearer 前缀;不通过命令行参数暴露 Token。"},
32
+ {"name": "--workspace-id", "type": "string", "required": False, "description": "执行工作空间 ID;省略时由项目运行时获取。"},
33
+ ],
34
+ "returns": "sys_user 对象:id、username、displayName、avatarUrl、tenantId、tenantName、primaryDepartment、departments、organizationAssignments、primaryPosition、primaryJobTitle。",
35
+ "example": "licos-platform user me",
36
+ },
37
+ },
38
+ }
39
+
40
+
41
+ def _me(args: argparse.Namespace):
42
+ return get_current_user(
43
+ user_token=sys.stdin.read().strip() if args.token_stdin else None,
44
+ workspace_id=args.workspace_id,
45
+ )
46
+
47
+
48
+ def add_user_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
49
+ parser = subparsers.add_parser("user", help="当前使用者及企业组织信息")
50
+ commands = parser.add_subparsers(dest="user_command", required=True)
51
+ me = commands.add_parser("me", help="返回与低代码 sys_user 相同的当前用户信息")
52
+ me.add_argument("--token-stdin", action="store_true", help="从标准输入读取当前使用者 Token")
53
+ me.add_argument("--workspace-id", help="执行工作空间 ID;默认读取运行时环境")
54
+ me.set_defaults(handler=_me)
@@ -36,6 +36,25 @@ def run_cli(*args: str) -> tuple[int, str, str]:
36
36
 
37
37
 
38
38
  class PlatformCliTests(unittest.TestCase):
39
+ def test_enterprise_help_matches_removed_management_commands(self) -> None:
40
+ code, output, _ = run_cli("help", "knowledge")
41
+ self.assertEqual(code, 0)
42
+ commands = json.loads(output)["commands"]
43
+ self.assertIn("enterprise-document-download-link", commands)
44
+ for name in ("create-folder", "upload-document", "delete-documents", "objects"):
45
+ self.assertNotIn("enterprise-" + name, commands)
46
+ code, _, error = run_cli("knowledge", "enterprise", name)
47
+ self.assertEqual(code, 2)
48
+ self.assertIn("invalid choice", error)
49
+
50
+ def test_enterprise_download_link_uses_current_sdk(self) -> None:
51
+ link = {"documentId": "doc-1", "downloadUrl": "https://files.example/manual.pdf"}
52
+ with mock.patch.object(knowledge_commands.enterprise_knowledge, "document_download_link", return_value=link) as download:
53
+ code, output, _ = run_cli("knowledge", "enterprise", "document-download-link", "doc-1")
54
+ self.assertEqual(code, 0)
55
+ self.assertEqual(json.loads(output), link)
56
+ download.assert_called_once_with("doc-1")
57
+
39
58
  def test_help_exposes_storage_commands(self) -> None:
40
59
  stdout = io.StringIO()
41
60
  with self.assertRaises(SystemExit) as caught, redirect_stdout(stdout):
@@ -61,6 +80,7 @@ class PlatformCliTests(unittest.TestCase):
61
80
  "ontology",
62
81
  "project-config",
63
82
  "storage",
83
+ "user",
64
84
  ],
65
85
  )
66
86
  self.assertIn("licos-platform help storage", payload["usage"])
@@ -671,88 +691,16 @@ class PlatformCliTests(unittest.TestCase):
671
691
  self.assertEqual(json.loads(stdout), {"status": "KNOWLEDGE_TREE_READY"})
672
692
  tree.assert_called_once_with(include_types=["STANDARD", "GRAPH"])
673
693
 
674
- def test_enterprise_knowledge_create_base_forwards_typed_contract(self) -> None:
675
- with mock.patch.object(
676
- knowledge_commands.enterprise_knowledge,
677
- "create_knowledge_base",
678
- return_value={"source_id": "source-1"},
679
- ) as create:
680
- code, stdout, stderr = run_cli(
681
- "knowledge",
682
- "enterprise",
683
- "create-knowledge-base",
684
- "设备手册",
685
- "--folder-id",
686
- "folder-1",
687
- "--description",
688
- "设备维护说明",
689
- "--knowledge-type",
690
- "STANDARD",
691
- )
692
-
693
- self.assertEqual(code, 0)
694
- self.assertEqual(stderr, "")
695
- self.assertEqual(json.loads(stdout), {"source_id": "source-1"})
696
- create.assert_called_once_with(
697
- "设备手册",
698
- folder_id="folder-1",
699
- description="设备维护说明",
700
- knowledge_type="STANDARD",
701
- )
702
-
703
- def test_enterprise_knowledge_chunked_upload_forwards_file_options(self) -> None:
704
- with mock.patch.object(
705
- knowledge_commands.enterprise_knowledge,
706
- "upload_document_chunked",
707
- return_value={"task_id": "task-1"},
708
- ) as upload:
709
- code, stdout, stderr = run_cli(
710
- "knowledge",
711
- "enterprise",
712
- "upload-document",
713
- "source-1",
714
- "manual.pdf",
715
- "--file-name",
716
- "设备手册.pdf",
717
- "--content-type",
718
- "application/pdf",
719
- "--chunked",
720
- "--chunk-size",
721
- str(8 * 1024 * 1024),
722
- )
723
-
724
- self.assertEqual(code, 0)
725
- self.assertEqual(stderr, "")
726
- self.assertEqual(json.loads(stdout), {"task_id": "task-1"})
727
- upload.assert_called_once_with(
728
- "source-1",
729
- "manual.pdf",
730
- file_name="设备手册.pdf",
731
- content_type="application/pdf",
732
- chunk_size=8 * 1024 * 1024,
733
- )
734
-
735
- def test_enterprise_knowledge_delete_requires_explicit_confirmation(self) -> None:
736
- code, stdout, stderr = run_cli(
737
- "knowledge",
738
- "enterprise",
739
- "delete-knowledge-base",
740
- "source-1",
741
- )
742
-
743
- self.assertEqual(code, 2)
744
- self.assertEqual(stdout, "")
745
- self.assertIn("--confirm", stderr)
746
694
 
747
695
  def test_structured_help_describes_enterprise_knowledge_contract(self) -> None:
748
- code, stdout, stderr = run_cli("help", "knowledge", "enterprise-upload-document")
696
+ code, stdout, stderr = run_cli("help", "knowledge", "enterprise-documents")
749
697
 
750
698
  self.assertEqual(code, 0)
751
699
  self.assertEqual(stderr, "")
752
700
  payload = json.loads(stdout)
753
701
  self.assertEqual(payload["topic"], "knowledge")
754
- self.assertEqual(payload["command"], "enterprise-upload-document")
755
- self.assertIn("--chunk-size", [item["name"] for item in payload["parameters"]])
702
+ self.assertEqual(payload["command"], "enterprise-documents")
703
+ self.assertIn("--query", [item["name"] for item in payload["parameters"]])
756
704
 
757
705
 
758
706
  if __name__ == "__main__":
@@ -0,0 +1,60 @@
1
+ import io
2
+ import json
3
+ import os
4
+ import sys
5
+ import unittest
6
+ from contextlib import redirect_stdout, redirect_stderr
7
+ from pathlib import Path
8
+ from unittest.mock import patch
9
+
10
+ sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "licos-platform-sdk/src"))
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
12
+ from licos_platform_cli import main, user_commands
13
+
14
+
15
+ class UserCliTests(unittest.TestCase):
16
+ def run_cli(self, *args):
17
+ out, err = io.StringIO(), io.StringIO()
18
+ with redirect_stdout(out), redirect_stderr(err):
19
+ code = main.main(args)
20
+ return code, out.getvalue(), err.getvalue()
21
+
22
+ def test_me_outputs_sdk_json_with_chinese(self):
23
+ with patch.object(user_commands, "get_current_user", return_value={"id": "caller", "displayName": "张三"}) as sdk:
24
+ code, out, err = self.run_cli("user", "me")
25
+ self.assertEqual(code, 0)
26
+ self.assertEqual(err, "")
27
+ self.assertEqual(json.loads(out), {"id": "caller", "displayName": "张三"})
28
+ self.assertIn("张三", out)
29
+ sdk.assert_called_once_with(user_token=None, workspace_id=None)
30
+
31
+ def test_stdin_token_is_forwarded_without_echo(self):
32
+ with patch("sys.stdin", io.StringIO("request-secret\n")), patch.object(
33
+ user_commands, "get_current_user", return_value={"id": "caller"},
34
+ ) as sdk:
35
+ code, out, err = self.run_cli("user", "me", "--token-stdin", "--workspace-id", "space")
36
+ self.assertEqual(code, 0)
37
+ self.assertNotIn("request-secret", out + err)
38
+ sdk.assert_called_once_with(user_token="request-secret", workspace_id="space")
39
+
40
+ def test_empty_stdin_fails_in_sdk_without_identity_fallback(self):
41
+ with patch("sys.stdin", io.StringIO(" \n")), patch.dict(os.environ, {
42
+ "LICOS_PLATFORM_API_BASE_URL": "https://platform.example", "LICOS_AI_AGENT_TOKEN": "secret",
43
+ "LICOS_CURRENT_USER_ID": "injected-user", "LICOS_OWNER_USER_ID": "owner",
44
+ }, clear=True):
45
+ code, out, err = self.run_cli("user", "me", "--token-stdin")
46
+ self.assertEqual(code, 1)
47
+ self.assertEqual(out, "")
48
+ self.assertIn("不能为空", err)
49
+
50
+ def test_structured_help_exposes_command_and_sdk(self):
51
+ code, out, err = self.run_cli("help", "user")
52
+ self.assertEqual(code, 0)
53
+ self.assertEqual(err, "")
54
+ help_data = json.loads(out)
55
+ self.assertIn("me", help_data["commands"])
56
+ self.assertIn("get_current_user", help_data["sdk"]["python"])
57
+ self.assertIn("getCurrentUser", help_data["sdk"]["node"])
58
+
59
+
60
+ if __name__ == "__main__": unittest.main()
@@ -1,6 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: licos-platform-cli
3
- Version: 0.4.12
4
- Summary: LICOS platform CLI
5
- Requires-Python: >=3.10
6
- Requires-Dist: licos-platform-sdk>=0.5.9