data-ops-cli 0.5.0__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 (40) hide show
  1. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/PKG-INFO +1 -1
  2. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/PKG-INFO +1 -1
  3. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/SOURCES.txt +1 -0
  4. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/__init__.py +1 -1
  5. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/factory.py +2 -1
  6. data_ops_cli-0.5.1/src/dataops_cli/cli/kb.py +248 -0
  7. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/ontology.py +94 -0
  8. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/skill.py +68 -24
  9. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/README.md +0 -0
  10. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/pyproject.toml +0 -0
  11. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/setup.cfg +0 -0
  12. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/dependency_links.txt +0 -0
  13. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/entry_points.txt +0 -0
  14. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/requires.txt +0 -0
  15. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/data_ops_cli.egg-info/top_level.txt +0 -0
  16. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/_compat.py +0 -0
  17. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/__init__.py +0 -0
  18. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/alarm.py +0 -0
  19. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/api.py +0 -0
  20. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/auth.py +0 -0
  21. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/data_table.py +0 -0
  22. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/dataset.py +0 -0
  23. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/datasource.py +0 -0
  24. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/dict_.py +0 -0
  25. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/hazard.py +0 -0
  26. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/metrics.py +0 -0
  27. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/ref.py +0 -0
  28. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/report.py +0 -0
  29. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/table.py +0 -0
  30. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/tag.py +0 -0
  31. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/utils.py +0 -0
  32. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/widget.py +0 -0
  33. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/cli/workflow.py +0 -0
  34. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/exceptions.py +0 -0
  35. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/runner.py +0 -0
  36. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/schems.py +0 -0
  37. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/sdk.py +0 -0
  38. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/session.py +0 -0
  39. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/src/dataops_cli/utils.py +0 -0
  40. {data_ops_cli-0.5.0 → data_ops_cli-0.5.1}/tests/test_table_relation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-ops-cli
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Command-line wrapper around dataops_sdk for the DataOps platform.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: data-ops-cli
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Command-line wrapper around dataops_sdk for the DataOps platform.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -24,6 +24,7 @@ src/dataops_cli/cli/datasource.py
24
24
  src/dataops_cli/cli/dict_.py
25
25
  src/dataops_cli/cli/factory.py
26
26
  src/dataops_cli/cli/hazard.py
27
+ src/dataops_cli/cli/kb.py
27
28
  src/dataops_cli/cli/metrics.py
28
29
  src/dataops_cli/cli/ontology.py
29
30
  src/dataops_cli/cli/ref.py
@@ -14,4 +14,4 @@ groups command modules under :mod:`dataops_cli.cli` and re-exports the package
14
14
  removed in ``dataops_cli`` 1.0.
15
15
  """
16
16
 
17
- __version__ = "0.5.0"
17
+ __version__ = "0.5.1"
@@ -53,6 +53,7 @@ def create_app():
53
53
  from dataops_cli.cli.datasource import datasource_typer
54
54
  from dataops_cli.cli.dict_ import dict_typer
55
55
  from dataops_cli.cli.hazard import hazard_typer
56
+ from dataops_cli.cli.kb import kb_typer
56
57
  from dataops_cli.cli.metrics import metrics_typer
57
58
  from dataops_cli.cli.ontology import ontology_typer
58
59
  from dataops_cli.cli.ref import ref_typer
@@ -84,7 +85,7 @@ def create_app():
84
85
  app.add_typer(widget_typer)
85
86
  app.add_typer(dict_typer)
86
87
  app.add_typer(hazard_typer)
87
- # app.add_typer(kb_typer) # TODO: kb CLI 尚未实现
88
+ app.add_typer(kb_typer)
88
89
  app.add_typer(tag_typer)
89
90
 
90
91
  app.registered_callback = TyperInfo(callback=main)
@@ -0,0 +1,248 @@
1
+ """Knowledge Base(知识库)管理命令组.
2
+
3
+ - 服务层函数 (service_*):纯 Python 接口,返回原始数据
4
+ - CLI 命令:基于服务层的薄包装,负责格式化输出
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+ from typing import Annotated
11
+
12
+ import typer
13
+ from dataops_cli.cli.utils import print_list
14
+ from dataops_sdk.exceptions import DataOpsError
15
+ from dataops_sdk.schemas.wiki import KbType
16
+ from dataops_sdk.services.wiki import (
17
+ service_get_knowledge_base,
18
+ service_list_knowledge_bases,
19
+ service_list_knowledge_documents,
20
+ service_search_knowledge,
21
+ service_search_wiki_pages,
22
+ service_upload_knowledge_file,
23
+ )
24
+
25
+ kb_typer = typer.Typer(
26
+ name="kb",
27
+ help="知识库管理",
28
+ no_args_is_help=True,
29
+ )
30
+ doc_typer = typer.Typer(name="doc", help="知识库文档", no_args_is_help=True)
31
+ page_typer = typer.Typer(name="page", help="Wiki 页面", no_args_is_help=True)
32
+ kb_typer.add_typer(doc_typer)
33
+ kb_typer.add_typer(page_typer)
34
+
35
+
36
+ @kb_typer.command("list")
37
+ def kb_list_cmd(
38
+ kb_type: Annotated[
39
+ KbType | None,
40
+ typer.Option("--type", "-t", help="知识库类型:document / faq / wiki"),
41
+ ] = None,
42
+ page: Annotated[int, typer.Option("--page", help="页码", min=1)] = 1,
43
+ page_size: Annotated[int, typer.Option("--page-size", help="每页条数", min=1)] = 20,
44
+ ) -> None:
45
+ """列出知识库。
46
+
47
+ Examples:
48
+ >>> data-ops-cli kb list
49
+ >>> data-ops-cli kb list --type wiki
50
+ """
51
+ try:
52
+ result = service_list_knowledge_bases(page=page, page_size=page_size, kb_type=kb_type)
53
+ except DataOpsError as e:
54
+ typer.echo(f"错误: {e.message}")
55
+ raise typer.Exit(code=1) from None
56
+
57
+ if not result.items:
58
+ print("未查询到知识库")
59
+ return
60
+
61
+ print_list(
62
+ ("id", "name", "type", "knowledge_count"),
63
+ [
64
+ [
65
+ it.id,
66
+ it.name,
67
+ it.type or "",
68
+ it.knowledge_count if it.knowledge_count is not None else "",
69
+ ]
70
+ for it in result.items
71
+ ],
72
+ )
73
+ print(f"total={result.total} page={result.page} page_size={result.page_size}")
74
+
75
+
76
+ @kb_typer.command("detail", no_args_is_help=True)
77
+ def kb_detail_cmd(
78
+ kb_id: Annotated[str, typer.Argument(help="知识库 ID")],
79
+ ) -> None:
80
+ """查看知识库详情。
81
+
82
+ Examples:
83
+ >>> data-ops-cli kb detail <kb_id>
84
+ """
85
+ try:
86
+ kb = service_get_knowledge_base(kb_id)
87
+ except DataOpsError as e:
88
+ typer.echo(f"错误: {e.message}")
89
+ raise typer.Exit(code=1) from None
90
+
91
+ print_list(
92
+ ("field", "value"),
93
+ [
94
+ ["id", kb.id],
95
+ ["name", kb.name],
96
+ ["type", kb.type or ""],
97
+ ["description", kb.description or ""],
98
+ ["knowledge_count", kb.knowledge_count if kb.knowledge_count is not None else ""],
99
+ ["chunk_count", kb.chunk_count if kb.chunk_count is not None else ""],
100
+ ],
101
+ )
102
+
103
+
104
+ @doc_typer.command("list", no_args_is_help=True)
105
+ def doc_list_cmd(
106
+ kb_id: Annotated[str, typer.Argument(help="知识库 ID")],
107
+ keyword: Annotated[
108
+ str | None,
109
+ typer.Option("--keyword", "-k", help="关键词"),
110
+ ] = None,
111
+ page: Annotated[int, typer.Option("--page", help="页码", min=1)] = 1,
112
+ page_size: Annotated[int, typer.Option("--page-size", help="每页条数", min=1)] = 20,
113
+ ) -> None:
114
+ """列出知识库文档。
115
+
116
+ Examples:
117
+ >>> data-ops-cli kb doc list <kb_id>
118
+ >>> data-ops-cli kb doc list <kb_id> --keyword "故障处理"
119
+ """
120
+ try:
121
+ result = service_list_knowledge_documents(
122
+ kb_id, page=page, page_size=page_size, keyword=keyword
123
+ )
124
+ except DataOpsError as e:
125
+ typer.echo(f"错误: {e.message}")
126
+ raise typer.Exit(code=1) from None
127
+
128
+ if not result.items:
129
+ print("未查询到文档")
130
+ return
131
+
132
+ print_list(
133
+ ("id", "title", "file_name", "parse_status"),
134
+ [
135
+ [
136
+ it.id,
137
+ it.title or "",
138
+ it.file_name or "",
139
+ it.parse_status or "",
140
+ ]
141
+ for it in result.items
142
+ ],
143
+ )
144
+ print(f"total={result.total} page={result.page} page_size={result.page_size}")
145
+
146
+
147
+ @doc_typer.command("upload", no_args_is_help=True)
148
+ def doc_upload_cmd(
149
+ kb_id: Annotated[str, typer.Argument(help="知识目录 CUID")],
150
+ file: Annotated[Path, typer.Argument(help="本地文件路径", exists=True, readable=True)],
151
+ name: Annotated[
152
+ str | None,
153
+ typer.Option("--name", help="覆盖上传文件名"),
154
+ ] = None,
155
+ security_level: Annotated[
156
+ str,
157
+ typer.Option(
158
+ "--security-level",
159
+ help="文档密级:PUBLIC / INTERNAL / CONFIDENTIAL / SECRET",
160
+ ),
161
+ ] = "INTERNAL",
162
+ ) -> None:
163
+ """上传文件到知识库。
164
+
165
+ Examples:
166
+ >>> data-ops-cli kb doc upload <kb_id> ./manual.pdf
167
+ """
168
+ try:
169
+ doc = service_upload_knowledge_file(
170
+ kb_id, file, file_name=name, security_level=security_level
171
+ )
172
+ except (DataOpsError, FileNotFoundError) as e:
173
+ msg = getattr(e, "message", None) or str(e)
174
+ typer.echo(f"错误: {msg}")
175
+ raise typer.Exit(code=1) from None
176
+
177
+ print(f"上传成功: id={doc.id} title={doc.title or ''} file_name={doc.file_name or ''}")
178
+
179
+
180
+ @kb_typer.command("search", no_args_is_help=True)
181
+ def search_cmd(
182
+ keyword: Annotated[str, typer.Argument(help="检索关键词")],
183
+ limit: Annotated[int, typer.Option("--limit", help="返回条数", min=1)] = 20,
184
+ offset: Annotated[int, typer.Option("--offset", help="偏移量", min=0)] = 0,
185
+ ) -> None:
186
+ """全局关键词检索知识内容。
187
+
188
+ Examples:
189
+ >>> data-ops-cli kb search "网络割接"
190
+ """
191
+ try:
192
+ result = service_search_knowledge(keyword, limit=limit, offset=offset)
193
+ except DataOpsError as e:
194
+ typer.echo(f"错误: {e.message}")
195
+ raise typer.Exit(code=1) from None
196
+
197
+ if not result.items:
198
+ print("未检索到内容")
199
+ return
200
+
201
+ print_list(
202
+ ("title", "kb_name", "score", "content"),
203
+ [
204
+ [
205
+ it.title or it.knowledge_title or "",
206
+ it.kb_name or "",
207
+ f"{it.score:.4f}" if it.score is not None else "",
208
+ (it.content or "")[:80],
209
+ ]
210
+ for it in result.items
211
+ ],
212
+ )
213
+ print(f"total={result.total}")
214
+
215
+
216
+ @page_typer.command("search", no_args_is_help=True)
217
+ def page_search_cmd(
218
+ kb_id: Annotated[str, typer.Argument(help="Wiki 资源 CUID(非目录 CUID)")],
219
+ query: Annotated[str, typer.Argument(help="检索词")],
220
+ limit: Annotated[int, typer.Option("--limit", help="返回条数", min=1)] = 20,
221
+ ) -> None:
222
+ """检索知识库 Wiki 页面。
223
+
224
+ Examples:
225
+ >>> data-ops-cli kb page search <kb_id> "运维手册"
226
+ """
227
+ try:
228
+ pages = service_search_wiki_pages(kb_id, query, limit=limit)
229
+ except DataOpsError as e:
230
+ typer.echo(f"错误: {e.message}")
231
+ raise typer.Exit(code=1) from None
232
+
233
+ if not pages:
234
+ print("未检索到 Wiki 页面")
235
+ return
236
+
237
+ print_list(
238
+ ("slug", "title", "page_type", "summary"),
239
+ [
240
+ [
241
+ it.slug,
242
+ it.title or "",
243
+ it.page_type or "",
244
+ (it.summary or "")[:60],
245
+ ]
246
+ for it in pages
247
+ ],
248
+ )
@@ -11,22 +11,30 @@ from typing import Annotated, Any
11
11
 
12
12
  import typer
13
13
  from dataops_sdk.exceptions import DataOpsError
14
+ from dataops_sdk.schemas.ontology import BUILTIN_SKILL_KINDS, OntologyBuiltinSkillKind
14
15
  from dataops_sdk.services.ontology import (
16
+ get_scenario_skill_code,
15
17
  service_get_ontology_by_code,
16
18
  service_get_ontology_by_name,
17
19
  service_list_ontologies,
20
+ service_list_ontology_apis,
21
+ service_list_ontology_metrics,
22
+ service_reset_ontology_builtin_skill,
18
23
  service_tree_ontology,
19
24
  service_update_ontology_basic,
20
25
  service_update_ontology_constraints,
21
26
  service_update_ontology_notes,
22
27
  service_update_ontology_relations,
28
+ service_update_ontology_scenarios,
23
29
  )
24
30
 
25
31
  from dataops_cli.cli.utils import print_group_tree, print_list
26
32
 
27
33
  ontology_typer = typer.Typer(name="ontology", help="本体管理", no_args_is_help=True)
28
34
  update_typer = typer.Typer(name="update", help="更新本体配置", no_args_is_help=True)
35
+ builtin_skill_typer = typer.Typer(name="builtin-skill", help="本体内置技能", no_args_is_help=True)
29
36
  ontology_typer.add_typer(update_typer)
37
+ ontology_typer.add_typer(builtin_skill_typer)
30
38
 
31
39
 
32
40
  def _read_json_payload(
@@ -133,9 +141,18 @@ def detail_ontology(
133
141
 
134
142
  data = meta.data
135
143
  print(f"本体: {meta.name} ({meta.title})")
144
+ print(f"编码: {meta.code}")
136
145
  print(f"备注: {meta.remark or '-'}")
137
146
  print(f"多维表格: {data.data_table or '-'}")
147
+ if data.skills:
148
+ print("内置技能 name 映射:")
149
+ for kind in BUILTIN_SKILL_KINDS:
150
+ if kind in data.skills:
151
+ print(f" {kind}: {data.skills[kind]}")
138
152
  print(f"场景数: {len(data.scenarios)}")
153
+ for scenario in data.scenarios:
154
+ skill_code = get_scenario_skill_code(scenario)
155
+ print(f" - {scenario.id}: {scenario.name or '-'} → skill {skill_code or '-'}")
139
156
  print(f"约束数: {len(data.constraints)}")
140
157
  print(f"关系数: {len(data.relations)}")
141
158
  if data.notes:
@@ -289,3 +306,80 @@ def update_relations(
289
306
  raise typer.Exit(code=1) from None
290
307
  assert result.data is not None
291
308
  typer.echo(f"本体 {result.name} 关联关系已更新(共 {len(result.data.relations)} 条)")
309
+
310
+
311
+ @update_typer.command("scenarios", no_args_is_help=True)
312
+ def update_scenarios(
313
+ name: Annotated[str, typer.Argument(help="本体编码或业务名")],
314
+ file: Annotated[
315
+ Path | None,
316
+ typer.Option("--file", "-f", help="场景 JSON 文件路径(数组)"),
317
+ ] = None,
318
+ content: Annotated[
319
+ str | None,
320
+ typer.Option("--content", "-c", help="场景 JSON 内容(数组)"),
321
+ ] = None,
322
+ ) -> None:
323
+ """全量替换本体场景列表(内置场景 id 不可删除)。"""
324
+ payload = _read_json_payload(file, content)
325
+ if not isinstance(payload, list):
326
+ typer.echo("错误: 场景内容必须是 JSON 数组", err=True)
327
+ raise typer.Exit(code=1)
328
+ try:
329
+ result = service_update_ontology_scenarios(name, payload)
330
+ except DataOpsError as e:
331
+ typer.echo(f"错误: {e.message}", err=True)
332
+ raise typer.Exit(code=1) from None
333
+ assert result.data is not None
334
+ typer.echo(f"本体 {result.name} 场景已更新(共 {len(result.data.scenarios)} 条)")
335
+
336
+
337
+ @ontology_typer.command("metrics", no_args_is_help=True)
338
+ def list_metrics(
339
+ code: Annotated[str, typer.Argument(help="本体编码")],
340
+ ) -> None:
341
+ """查询本体关联的指标列表。"""
342
+ try:
343
+ items = service_list_ontology_metrics(code)
344
+ except DataOpsError as e:
345
+ typer.echo(f"错误: {e.message}", err=True)
346
+ raise typer.Exit(code=1) from None
347
+ print(json.dumps(items, ensure_ascii=False, indent=2))
348
+
349
+
350
+ @ontology_typer.command("apis", no_args_is_help=True)
351
+ def list_apis(
352
+ code: Annotated[str, typer.Argument(help="本体编码")],
353
+ ) -> None:
354
+ """查询本体关联的接口列表。"""
355
+ try:
356
+ items = service_list_ontology_apis(code)
357
+ except DataOpsError as e:
358
+ typer.echo(f"错误: {e.message}", err=True)
359
+ raise typer.Exit(code=1) from None
360
+ print(json.dumps(items, ensure_ascii=False, indent=2))
361
+
362
+
363
+ @builtin_skill_typer.command("reset", no_args_is_help=True)
364
+ def reset_builtin_skill(
365
+ name_or_code: Annotated[str, typer.Argument(help="本体编码或业务名")],
366
+ kind: Annotated[
367
+ OntologyBuiltinSkillKind,
368
+ typer.Argument(help="内置技能类型: query/create/delete/update"),
369
+ ],
370
+ ) -> None:
371
+ """重置本体内置技能并回填场景绑定。"""
372
+ try:
373
+ meta = service_get_ontology_by_name(name_or_code)
374
+ except DataOpsError:
375
+ try:
376
+ meta = service_get_ontology_by_code(name_or_code)
377
+ except DataOpsError as e:
378
+ typer.echo(f"错误: {e.message}", err=True)
379
+ raise typer.Exit(code=1) from None
380
+ try:
381
+ result = service_reset_ontology_builtin_skill(meta.code, kind)
382
+ except DataOpsError as e:
383
+ typer.echo(f"错误: {e.message}", err=True)
384
+ raise typer.Exit(code=1) from None
385
+ print(json.dumps(result, ensure_ascii=False, indent=2))
@@ -11,10 +11,8 @@ from pathlib import Path
11
11
  from typing import Annotated
12
12
 
13
13
  import typer
14
- from dataops_cli.cli.utils import paginate_with_line_numbers, print_list
15
14
  from dataops_sdk.exceptions import DataOpsError
16
15
  from dataops_sdk.schemas import MetaSkillFileSubType, MetaSkillSubType, MetaType
17
- from dataops_sdk.schemas.enums import GroupNodeRefType
18
16
  from dataops_sdk.services import (
19
17
  SkillPackValidationError,
20
18
  service_delete_skill,
@@ -25,6 +23,9 @@ from dataops_sdk.services import (
25
23
  service_skill_call_by_name,
26
24
  service_skill_delete_sub_file,
27
25
  service_skill_download,
26
+ service_skill_list_ontologies_by_codes,
27
+ service_skill_list_ontology_options,
28
+ service_skill_list_skill_codes_by_ontology,
28
29
  service_skill_update,
29
30
  service_skill_upload,
30
31
  service_skill_upload_sub_file,
@@ -33,6 +34,8 @@ from dataops_sdk.tiptap import TableStyle, TipTapTool
33
34
  from pydantic_core import from_json
34
35
  from rich.console import Console
35
36
 
37
+ from dataops_cli.cli.utils import paginate_with_line_numbers, print_list
38
+
36
39
  # ---------------------------------------------------------------------------
37
40
  # CLI 命令
38
41
  # ---------------------------------------------------------------------------
@@ -47,10 +50,70 @@ skill_file_typer = typer.Typer(
47
50
  help="技能文件管理",
48
51
  no_args_is_help=True,
49
52
  )
53
+ skill_ontology_typer = typer.Typer(
54
+ name="ontology",
55
+ help="技能与本体归属",
56
+ no_args_is_help=True,
57
+ )
50
58
  skill_typer.add_typer(skill_file_typer)
59
+ skill_typer.add_typer(skill_ontology_typer)
51
60
  MAKRDOWN_TABLE_STYLE = TableStyle.MARKDOWN
52
61
 
53
62
 
63
+ @skill_ontology_typer.command("options")
64
+ def ontology_options_cmd() -> None:
65
+ """列出已绑定技能的本体(用于技能中心筛选)。"""
66
+ try:
67
+ items = service_skill_list_ontology_options()
68
+ except DataOpsError as e:
69
+ typer.echo(f"错误: {e.message}")
70
+ raise typer.Exit(code=1) from None
71
+ if not items:
72
+ print("未查询到本体选项")
73
+ return
74
+ print_list(
75
+ ("code", "title"),
76
+ [[it.code, it.title] for it in items],
77
+ )
78
+
79
+
80
+ @skill_ontology_typer.command("by-codes", no_args_is_help=True)
81
+ def ontology_by_codes_cmd(
82
+ codes: Annotated[
83
+ str,
84
+ typer.Option("--codes", "-c", help="技能 code 列表,逗号分隔"),
85
+ ],
86
+ ) -> None:
87
+ """批量查询技能归属的本体。"""
88
+ code_list = [c.strip() for c in codes.split(",") if c.strip()]
89
+ if not code_list:
90
+ typer.echo("错误: --codes 不能为空")
91
+ raise typer.Exit(code=1)
92
+ try:
93
+ mapping = service_skill_list_ontologies_by_codes(code_list)
94
+ except DataOpsError as e:
95
+ typer.echo(f"错误: {e.message}")
96
+ raise typer.Exit(code=1) from None
97
+ payload = {key: [vo.model_dump() for vo in val] for key, val in mapping.items()}
98
+ print(json.dumps(payload, ensure_ascii=False, indent=2))
99
+
100
+
101
+ @skill_ontology_typer.command("skill-codes", no_args_is_help=True)
102
+ def ontology_skill_codes_cmd(
103
+ ontology_code: Annotated[
104
+ str,
105
+ typer.Option("--ontology-code", help="本体编码"),
106
+ ],
107
+ ) -> None:
108
+ """按本体查询绑定的技能 code 列表。"""
109
+ try:
110
+ codes = service_skill_list_skill_codes_by_ontology(ontology_code)
111
+ except DataOpsError as e:
112
+ typer.echo(f"错误: {e.message}")
113
+ raise typer.Exit(code=1) from None
114
+ print(json.dumps(codes, ensure_ascii=False, indent=2))
115
+
116
+
54
117
  @skill_typer.command("list")
55
118
  def list_cmd(
56
119
  sub_types: Annotated[
@@ -125,46 +188,27 @@ def detail_cmd(
125
188
 
126
189
  @skill_typer.command("upload", no_args_is_help=True)
127
190
  def upload_cmd(
128
- space_code: Annotated[str, typer.Argument(help="空间编码 (通过 ``report space list`` 查看)")],
129
191
  file: Annotated[Path, typer.Argument(help="技能 ZIP 文件路径")],
130
192
  dtype: Annotated[
131
193
  MetaSkillSubType,
132
194
  typer.Option("--type", help="技能子类型"),
133
195
  ],
134
- ref_node_id: Annotated[
135
- str | None,
136
- typer.Option(
137
- "--ref-node-id",
138
- help="文档中心分组节点 ID(可选;通过 ``report tree`` 查看,需挂到树上时填写)",
139
- ),
140
- ] = None,
141
- ref_type: Annotated[
142
- GroupNodeRefType,
143
- typer.Option("--ref-type", help="引用节点类型 (放置在引用节点前、后还是内)"),
144
- ] = GroupNodeRefType.AFTER,
145
196
  title: Annotated[str | None, typer.Option("--title", help="技能简体中文名称")] = None,
146
197
  ) -> None:
147
- """从 ZIP 包导入技能到指定文档空间(可选挂到文档中心树节点)。
198
+ """从 ZIP 包导入技能到技能中心。
148
199
 
149
200
  Examples:
150
- 仅导入到空间(不挂文档树节点)
151
- >>> data-ops-cli skill upload default my-skill.zip --type llm
152
-
153
- 挂到文档中心某分组节点内
154
- >>> data-ops-cli skill upload default my-skill.zip --type api --ref-node-id {node-id} --ref-type inner
201
+ >>> data-ops-cli skill upload my-skill.zip --type llm
155
202
  """
156
203
  if not file.exists():
157
204
  typer.echo(f"错误: 文件不存在 {file}")
158
205
  raise typer.Exit(code=2)
159
206
 
160
207
  try:
161
- result = service_skill_upload(
208
+ service_skill_upload(
162
209
  file_path=str(file),
163
210
  sub_type=dtype,
164
211
  title=title,
165
- group_name=space_code,
166
- ref_node_id=ref_node_id,
167
- ref_type=ref_type,
168
212
  )
169
213
  except DataOpsError as e:
170
214
  typer.echo(f"错误: {e.message}")
File without changes
File without changes