@dazitech/cli 3.0.6 → 3.0.8

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 (76) hide show
  1. package/README.md +1 -1
  2. package/dist/clis/dazi-app.js +1 -1
  3. package/dist/clis/dazi-flow.js +43 -24
  4. package/dist/clis/dazi-onto.js +73 -22
  5. package/dist/clis/dazi.js +266 -171
  6. package/dist/docs/flow/ai-workflow-playbook.md +4 -2
  7. package/dist/docs/flow/flow-project-guide.md +9 -5
  8. package/dist/docs/flow/flows-guide.md +2 -2
  9. package/dist/docs/flow/node-code-guide.md +408 -401
  10. package/dist/docs/flow/run-guide.md +13 -6
  11. package/dist/docs/flow/variables-guide.md +407 -406
  12. package/dist/docs/guides/quickstart.md +18 -4
  13. package/dist/docs/guides/troubleshooting.md +1 -1
  14. package/dist/docs/guides/workspace-v3.md +43 -23
  15. package/dist/docs/index.json +9 -3
  16. package/dist/docs/onto/action-guide.md +3 -3
  17. package/dist/docs/onto/dazi_script_sdk_reference.md +178 -174
  18. package/dist/docs/onto/dazi_script_seed_data_guide.md +158 -155
  19. package/dist/docs/onto/function-guide.md +37 -10
  20. package/dist/docs/onto/space-management.md +3 -1
  21. package/dist/docs/onto//346/234/254/344/275/223/350/204/232/346/234/254/347/274/226/345/206/231/346/214/207/345/215/227.md +138 -34
  22. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +73 -31
  23. package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/344/272/247/345/223/201/351/224/200/345/224/256/346/234/254/344/275/223/350/247/204/345/210/222/346/226/271/346/241/210.md +497 -0
  24. package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/345/210/251/346/266/246/345/210/206/346/236/220/346/234/254/344/275/223/346/226/271/346/241/210.md +597 -541
  25. package/dist/examples/index.json +202 -22
  26. package/dist/examples/onto/README.md +43 -0
  27. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_account_breakdown.py +99 -0
  28. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_budget_vs_actual.py +116 -0
  29. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_cost_center_profit.py +85 -0
  30. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_get_summary.py +76 -0
  31. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_mom_analysis.py +86 -0
  32. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_top_accounts.py +103 -0
  33. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_yoy_analysis.py +86 -0
  34. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/save_test_arguments.ps1 +27 -0
  35. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.account_breakdown.json +10 -0
  36. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.budget_vs_actual.json +10 -0
  37. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.cost_center_profit.json +9 -0
  38. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.get_summary.json +9 -0
  39. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.mom_analysis.json +9 -0
  40. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.top_accounts.json +11 -0
  41. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.yoy_analysis.json +9 -0
  42. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +521 -0
  43. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_seed_data.py +213 -0
  44. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/README.md +25 -0
  45. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_channel_mix.py +86 -0
  46. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_customer_segmentation.py +123 -0
  47. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_get_summary.py +81 -0
  48. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_mom_analysis.py +90 -0
  49. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_region_breakdown.py +85 -0
  50. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_top_products.py +101 -0
  51. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_yoy_analysis.py +90 -0
  52. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +25 -0
  53. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.channel_mix.json +8 -0
  54. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.customer_segmentation.json +10 -0
  55. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.get_summary.json +8 -0
  56. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.mom_analysis.json +8 -0
  57. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.region_breakdown.json +8 -0
  58. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.top_products.json +10 -0
  59. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.yoy_analysis.json +8 -0
  60. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/README.md +5 -0
  61. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +403 -0
  62. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_seed_data.py +124 -0
  63. package/dist/prompts/flow/ai-workflow-playbook.md +4 -2
  64. package/dist/prompts/flow/flow-design.md +12 -9
  65. package/dist/prompts/flow/run-fix-loop.md +37 -22
  66. package/dist/prompts/index.json +2 -2
  67. package/dist/prompts/onto/action-design.md +4 -1
  68. package/dist/prompts/onto/function-design.md +9 -2
  69. package/dist/prompts/onto/rule-seed.md +5 -1
  70. package/dist/prompts/onto/script-publish-run.md +72 -24
  71. package/package.json +1 -1
  72. package/dist/examples/onto/function/profit_fn_customer_segmentation.py +0 -117
  73. package/dist/examples/onto/function/profit_fn_mom_analysis.py +0 -89
  74. package/dist/examples/onto/function/profit_fn_top_products.py +0 -89
  75. package/dist/examples/onto/function/profit_fn_yoy_analysis.py +0 -89
  76. package/dist/examples/onto/setup/profit_ontology_init.py +0 -388
@@ -10,14 +10,16 @@
10
10
  ## 核心原则
11
11
 
12
12
  1. **扩展不会自动改代码**;你必须在终端**亲自执行** CLI 并读取 `_run/` 错误文件。
13
- 2. **改 → 读错再改再跑** 是默认工作方式,不是可选项。
14
- 3. 命令前缀统一:`dazi flow ...`(在 `dazi-work` 根;流程目录用 `--dir .`)。
13
+ 2. **改 → push →(有输出变量时)variable pull 读错再改** 是默认工作方式,不是可选项。
14
+ 3. **`node-exec` 在平台执行已 push 的代码**;改 `code.*` 后必须先 `node push`,否则测到的仍是旧版。
15
+ 4. 命令前缀统一:`dazi flow ...`(在 `dazi-work` 根;流程目录用 `--dir .`)。
15
16
 
16
17
  ## 命令约束(必须遵守)
17
18
 
18
19
  - 命令前缀统一:`dazi flow ...`(在 `dazi-work` 根)
19
20
  - 在流程目录执行时,保留 `--dir .`,避免误跑到其他流程
20
21
  - 配置变更必须 `project push --dir . --canvas`(无 `--canvas` 不会更新平台画布)
22
+ - 改 `code.*` 后测试前必须 `node push --node <node_uuid> --dir .`
21
23
  - push 前先 `project doctor`;不一致则 `repair-meta`
22
24
  - 禁止输出裸 `dazi-flow ...` 作为最终命令
23
25
  - 必读:`flow/local-files-spec`
@@ -33,48 +35,61 @@
33
35
 
34
36
  `last-error.md` 含:**错误分类**(缺上游变量/配置缺失/代码错误/连接数据源)、traceback、修复指引。
35
37
 
38
+ ## 成功判据(代码节点,缺一不可)
39
+
40
+ 1. **`node push` 已成功**(`project status` 该节点代码不再脏)
41
+ 2. **`node-exec` 返回 `success: true`**(建议带 `--json`)
42
+ 3. **若配置了 `output_variable_name`**:`variable pull --name <名>` 后,`变量/<名>.json` 为 ready 且 schema/预览符合预期
43
+
44
+ > 禁止仅凭 `node-exec` 退出码或「无 last-error 文件」就声称通过;禁止未 `node push` 就测代码。
45
+
36
46
  ## 改错循环(默认最多 3 轮)
37
47
 
38
48
  ```
39
49
  FOR round = 1..3:
40
50
  1. 读 flow.json + code.* +(若失败)last-error.md + 变量/<名>.json(如需列名)
41
51
  2. 修改 code.* 和/或 flow.json(遵守画布锚点规范)
42
- 3. 运行验证:
43
- - 优先单节点:
44
- dazi flow run node-exec --node <node_uuid> --dir .
45
- - 需要全链路时:
46
- dazi flow run flow-exec --dir . --type debug
47
- 4. IF 成功push(见下)→ 结束
52
+ 3. 若改了 flow.json 拓扑/配置 → project push --dir . --canvas
53
+ 4. 若改了 code.* → node push --node <node_uuid> --dir .(必须先于测试)
54
+ 5. 运行验证(先小后大):
55
+ - 单节点:dazi flow run node-exec --node <node_uuid> --dir .
56
+ - 整流程:dazi flow run flow-exec --dir . --type debug
57
+ 6. 若节点有 output_variable_namevariable pull --name <名> --dir .
58
+ 7. IF 满足「成功判据」→ 结束(本轮无需重复 push,步骤 4 已提交)
48
59
  ELSE → 读新生成的 last-error.md → 下一轮
49
- 5. IF round==3 仍失败 → 输出:失败节点、3 轮尝试摘要、剩余疑点、需用户提供的资料
60
+ 8. IF round==3 仍失败 → 输出:失败节点、3 轮尝试摘要、剩余疑点、需用户提供的资料
50
61
  ```
51
62
 
52
63
  ## 修复决策树
53
64
 
54
- | 错误分类 | 改哪里 | 验证命令 |
65
+ | 错误分类 | 改哪里 | 验证命令(顺序固定) |
55
66
  | ----------- | ------------------------ | ------------------------------------------------------------------------------------------------------- |
56
- | 缺上游变量 | 先跑上游或整流程 | `dazi flow run flow-exec --dir . --type debug`,再 `dazi flow run node-exec --node <node_uuid> --dir .` |
57
- | 配置缺失 | `flow.json` 节点 `data` | `dazi flow run node-exec --node <node_uuid> --dir .` → `dazi flow project push --dir . --canvas` |
58
- | 代码错误 | `节点/<名>/code.sql\|py` | `dazi flow run node-exec --node <node_uuid> --dir .` `dazi flow node push --node <node_uuid> --dir .` |
59
- | 连接/数据源 | connectionId / spaceId | 改配置后 `dazi flow project push --dir . --canvas` |
67
+ | 缺上游变量 | 先跑上游或整流程 | 上游 `node push` `node-exec` `flow-exec --type debug` `variable pull` 再测目标节点(同样先 push) |
68
+ | 配置缺失 | `flow.json` 节点 `data` | `project push --dir . --canvas` → `node push`(若也改了 code)→ `node-exec` `variable pull`(若适用) |
69
+ | 代码错误 | `节点/<名>/code.sql\|py` | **`node push`** **`node-exec`****`variable pull`**(若配置了输出变量) |
70
+ | 连接/数据源 | connectionId / spaceId | `project push --dir . --canvas` → 再按上序测试 |
60
71
 
61
72
  ## 提交规则
62
73
 
63
- - 只改代码:`dazi flow node push --node <node_uuid> --dir .`
64
- - 改连线/配置/增删节点:`dazi flow project push --dir . --canvas`
65
- - 确认变量 schema:`dazi flow variable pull --name <output_variable_name> --dir .`
66
- - **禁止**未验证通过就 push
74
+ - `code.*`:**测试前** `node push`(见改错循环步骤 4);不要等测试通过才第一次 push
75
+ - 改连线/配置/增删节点:`project push --dir . --canvas`(先于依赖该配置的测试)
76
+ - `output_variable_name`:**成功判据**须包含 `variable pull` 核对
77
+ - **禁止**未满足成功判据就声称完成
78
+ - **禁止**未 `node push` 就 `node-exec` 并声称已验证新代码
67
79
 
68
80
  ## 回答格式(每轮结束后)
69
81
 
70
- 1. **本轮运行**:命令 + 成功/失败
71
- 2. **若失败**:节点、错误分类、根因(引用 last-error 原文)
72
- 3. **本轮修改**:改了哪些文件、改了什么
73
- 4. **下一步**:重跑命令或已 push
82
+ 1. **本轮 push**:`node push` / `push --canvas` 是否成功
83
+ 2. **本轮运行**:命令 + 成功/失败 +(若适用)variable pull 结果
84
+ 3. **若失败**:节点、错误分类、根因(引用 last-error 原文)
85
+ 4. **本轮修改**:改了哪些文件、改了什么
86
+ 5. **下一步**:重跑命令或已满足成功判据
74
87
 
75
88
  ## 禁止项
76
89
 
77
90
  - 未运行就声称修复完成
91
+ - 未 `node push` 就 `node-exec` 验证代码改动
78
92
  - 不读 `_run/*.last-error.md` 就猜原因
93
+ - 仅凭 exit code 通过就 push 或声称完成(跳过 variable pull)
79
94
  - 使用裸 `dazi-flow` 作为最终命令
80
95
  - 把代码正文塞进 `flow.json`
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "3.0.6",
3
- "updatedAt": "2026-05-26T00:00:00.000Z",
2
+ "version": "3.0.8",
3
+ "updatedAt": "2026-06-05T00:00:00.000Z",
4
4
  "prompts": [
5
5
  {
6
6
  "id": "onto/script-publish-run",
@@ -40,10 +40,13 @@ def main(params: dict, context: dict, s=None) -> dict:
40
40
  return {"status": "ok"}
41
41
  ```
42
42
 
43
+ 脚本落盘路径:`项目/<业务名>/本体/ontos/<实现名>/setup/` 或 `functions/`(按脚本类型选择)。
44
+ `space_id` 取自 `ontos/<实现名>/README.md`。
45
+
43
46
  发布命令(v3;**勿用** `dazi-onto`):
44
47
 
45
48
  ```powershell
46
- dazi onto script publish 项目/onto_<名>/脚本/<file>.py --space <space-id> --register-action-id <action_code> --register-action-permission-tag "finance.write"
49
+ dazi onto script publish 项目/<业务名>/本体/ontos/<实现名>/setup/<file>.py --space <space-id> --register-action-id <action_code> --register-action-permission-tag "finance.write"
47
50
  ```
48
51
 
49
52
  详见提示词 `onto/script-publish-run`。
@@ -19,6 +19,7 @@
19
19
  4. 包含完整的 docstring(中文),说明:函数目的、参数说明、返回值说明
20
20
  5. 包含基本的错误处理(try/except)
21
21
  6. 引用的搭子数据空间对象通过 `s` 上下文访问
22
+ 7. 在脚本顶部定义 `TEST_ARGUMENTS` 常量(与 `functions/test_arguments/<function_id>.json` 同步),供发布后 `save-test-arguments` 入库
22
23
 
23
24
  ## 输出格式
24
25
 
@@ -36,11 +37,17 @@ def main(params: dict, s=None) -> dict:
36
37
  # 实现
37
38
  ```
38
39
 
40
+ 脚本落盘路径:`项目/<业务名>/本体/ontos/<实现名>/functions/<file>.py`
41
+ `space_id` 取自同目录上级的 `README.md`(`ontos/<实现名>/README.md`)。
42
+
39
43
  发布与运行(v3,工作区根目录;**勿用** `dazi-onto`):
40
44
 
41
45
  ```powershell
42
- dazi onto script publish 项目/onto_<名>/脚本/functions/<file>.py --space <space-id> --register-function-id <id>
46
+ dazi onto script publish 项目/<业务名>/本体/ontos/<实现名>/functions/<file>.py --space <space-id> --register-function-id <id>
43
47
  dazi onto function run <id> --space <space-id>
48
+ # run 验证通过后,保存 test_arguments(侧栏「运行函数」预填;须用 ofn_xxx 内部 id,见 script-publish-run §7)
49
+ dazi onto function save-test-arguments <ofn_internal_id> --space <space-id> `
50
+ --arguments-json-file 项目/<业务名>/本体/ontos/<实现名>/functions/test_arguments/<id>.json
44
51
  ```
45
52
 
46
- 详见提示词 `onto/script-publish-run`(侧栏 帮助 → 提示词)。
53
+ 详见提示词 `onto/script-publish-run`(侧栏 帮助 → 提示词),含 `test_arguments` JSON 格式与批量 `save_test_arguments.ps1`。
@@ -13,6 +13,9 @@
13
13
 
14
14
  ## 种子脚本模板
15
15
 
16
+ 建议将种子脚本保存到 `项目/<业务名>/本体/ontos/<实现名>/setup/<stem>_seed_rules.py`(与同实现的 init/seed 脚本并列)。
17
+ `space_id` 取自 `ontos/<实现名>/README.md`。
18
+
16
19
  ```python
17
20
  def main(params: dict, s=None) -> dict:
18
21
  """
@@ -34,9 +37,10 @@ def main(params: dict, s=None) -> dict:
34
37
  return {"upserted": len(rules), "result": result}
35
38
  ```
36
39
 
37
- 执行命令(v3;**勿用** `dazi-onto`):
40
+ 发布与执行(v3;**勿用** `dazi-onto`):
38
41
 
39
42
  ```powershell
43
+ dazi onto script publish 项目/<业务名>/本体/ontos/<实现名>/setup/<stem>_seed_rules.py --space <space-id> --type data
40
44
  dazi onto rule run-seed --space <space-id> --stem <seed_file_stem>
41
45
  ```
42
46
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  ---
8
8
 
9
- 你是搭子平台 **dazi-vscode v3** 本体实施助手。用户已完成或正在完成 `项目/onto_<名称>/规划/` 中的方案,你的任务是编写 `脚本/` 下 Python,并**用正确命令**发布与运行。
9
+ 你是搭子平台 **dazi-vscode v3** 本体实施助手。用户已完成或正在完成 `项目/<业务名>/本体/ontos/<实现名>/plans/` 中的方案,你的任务是编写 `setup/`、`functions/` 下 Python,并**用正确命令**发布与运行。
10
10
 
11
11
  ## 强制规则(违反会导致 CommandNotFound 或 404)
12
12
 
@@ -17,20 +17,35 @@
17
17
  - **仅开发仓库**:`node bundled/clis/dazi.js onto ...`(维护方打包用;客户环境用 `dazi.ps1`)
18
18
  - **完整路径**:`node <搭子仓库>/dazi/dazi-vscode/bundled/clis/dazi.js onto <子命令> ...`,并设置环境变量 `DAZI_BUNDLED_DIR=<同目录 bundled/clis>`
19
19
  4. **工作目录**必须是搭子工作区根(含 `项目/` 目录),例如 `dazi-work`。
20
- 5. **`space_id`** 只从 `项目/onto_<名称>/README.md` 的「数据空间 ID」读取,禁止猜测。
20
+ 5. **`space_id`** 只从 `项目/<业务名>/本体/ontos/<实现名>/README.md` 的「数据空间 ID」读取,禁止猜测。
21
21
 
22
22
  ## 工作区目录(v3)
23
23
 
24
24
  ```text
25
25
  <工作区根>/
26
- 项目/onto_<名称>/
27
- README.md space_id(权威)
28
- 规划/ ← 规划 Markdown(本阶段不 publish)
29
- 脚本/
30
- setup/ 初始化、灌数(先 init 后 seed)
31
- functions/ 本体函数
32
- 资源/docs/ ← dazi docs sync 后的指南
33
- scripts/ dazi.ps1 / dazi.cmd 包装(客户工作区模板应包含)
26
+ 项目/<业务名>/
27
+ README.md 业务项目元信息
28
+ 本体/
29
+ README.md ← 容器说明(onto-assets + ontos 索引)
30
+ onto-assets/ 平台元数据缓存(业务项目级,侧栏懒拉取)
31
+ objects/ functions/ actions/ rules/
32
+ ontos/
33
+ <实现名>/ 本体实现工作单元
34
+ README.md ← space_id(权威)
35
+ 快速启动_<实现名>.md ← 动态生成,含本实现命令模板
36
+ plans/ ← 规划 Markdown(本阶段不 publish)
37
+ setup/ ← 初始化、灌数(先 init 后 seed)
38
+ functions/ ← 本体函数
39
+ test_arguments/ ← 各 function_id 的默认测试入参 JSON
40
+ save_test_arguments.ps1 ← 可选:批量 save-test-arguments
41
+ 流程/
42
+ plans/
43
+ flows/<流程名>/...
44
+ 应用/
45
+ plans/
46
+ apps/<组件名>/...
47
+ 资源/docs/ ← dazi docs sync 后的指南
48
+ scripts/ ← dazi.ps1 / dazi.cmd 包装(客户工作区模板应包含)
34
49
  ```
35
50
 
36
51
  本地开发路径 **不是** `onto/<space_id>/editorial/`;发布时 CLI 自动映射为平台路径
@@ -49,24 +64,25 @@ dazi auth login
49
64
 
50
65
  ## 标准发布与运行顺序
51
66
 
52
- `<空间>`、`<项目路径>` 替换为实际值,例如 `space__0519`、`项目/onto_本体项目01`。
67
+ `<业务名>`、`<实现名>`、`<空间>` 替换为实际值,例如 `潘达石化`、`本体01`、`space__0519`。
68
+ 脚本路径前缀记为 `<项目路径>` = `项目/<业务名>/本体/ontos/<实现名>`。
53
69
 
54
70
  ### 1. 预检(可选)
55
71
 
56
72
  ```powershell
57
- dazi onto script publish-preview <项目路径>/脚本/setup/xxx_ontology_init.py --space <空间> --type setup
73
+ dazi onto script publish-preview <项目路径>/setup/xxx_ontology_init.py --space <空间> --type setup
58
74
  ```
59
75
 
60
76
  ### 2. 发布初始化脚本(setup)
61
77
 
62
78
  ```powershell
63
- dazi onto script publish <项目路径>/脚本/setup/xxx_ontology_init.py --space <空间> --type setup
79
+ dazi onto script publish <项目路径>/setup/xxx_ontology_init.py --space <空间> --type setup
64
80
  ```
65
81
 
66
82
  ### 3. 发布灌数脚本(data)
67
83
 
68
84
  ```powershell
69
- dazi onto script publish <项目路径>/脚本/setup/xxx_seed_data.py --space <空间> --type data
85
+ dazi onto script publish <项目路径>/setup/xxx_seed_data.py --space <空间> --type data
70
86
  ```
71
87
 
72
88
  ### 4. 发布本体函数(**必须** `--register-function-id`,否则函数列表看不到)
@@ -76,7 +92,7 @@ dazi onto script publish <项目路径>/脚本/setup/xxx_seed_data.py --space <
76
92
  发布后必须确认输出含 `functionId` / `function_registration.ok`,并执行 `function list` 能看到该 id。
77
93
 
78
94
  ```powershell
79
- dazi onto script publish <项目路径>/脚本/functions/xxx_fn_yyy.py --space <空间> --register-function-id <domain>.fn.<name>
95
+ dazi onto script publish <项目路径>/functions/xxx_fn_yyy.py --space <空间> --register-function-id <domain>.fn.<name>
80
96
  dazi onto function list --space <空间>
81
97
  ```
82
98
 
@@ -84,8 +100,8 @@ dazi onto function list --space <空间>
84
100
 
85
101
  ```powershell
86
102
  # 按 publish 返回的 scriptId,或:
87
- dazi onto script run --file <项目路径>/脚本/setup/xxx_ontology_init.py --space <空间>
88
- dazi onto script run --file <项目路径>/脚本/setup/xxx_seed_data.py --space <空间>
103
+ dazi onto script run --file <项目路径>/setup/xxx_ontology_init.py --space <空间>
104
+ dazi onto script run --file <项目路径>/setup/xxx_seed_data.py --space <空间>
89
105
  ```
90
106
 
91
107
  **顺序**:先 run init,再 run seed,再发布/运行函数。
@@ -103,13 +119,44 @@ $env:DAZI_PARAMS='{"start_date":"2025-01-01","end_date":"2026-12-31"}'
103
119
  dazi onto function run <function_id> --space <空间> --params $env:DAZI_PARAMS
104
120
  ```
105
121
 
122
+ ### 7. 保存测试参数(test_arguments,**发布后必做**)
123
+
124
+ `publish` + `function run` **不会**自动写入测试参数。侧栏 **Onto → 运行函数** 依赖函数定义上的 **`test_arguments`** 预填表单;未保存时侧栏参数为空。
125
+
126
+ **本地约定**(与 `plans/` 规划文档一致):
127
+
128
+ 1. 每个函数一份 JSON:`<项目路径>/functions/test_arguments/<function_id>.json`
129
+ 2. 脚本内常量 `TEST_ARGUMENTS` 与 JSON **保持同步**
130
+ 3. JSON 格式:`{"v":1,"arguments":{...},"object_type_code":"<ObjectTypeCode>"}`
131
+
132
+ **保存到平台**(`function run` 验证通过后):
133
+
134
+ ```powershell
135
+ # 推荐:批量脚本(解析 function list,用内部 id ofn_xxx 调用 PATCH)
136
+ .\<项目路径>\functions\save_test_arguments.ps1
137
+ ```
138
+
139
+ 单条保存(**须用平台内部 id `ofn_xxx`**,先 `dazi onto function list --space <空间>` 查看;直接传 `sales.fn.xxx` 等 function_id 字符串可能 **404**):
140
+
141
+ ```powershell
142
+ dazi onto function save-test-arguments <ofn_internal_id> --space <空间> `
143
+ --arguments-json-file <项目路径>/functions/test_arguments/<function_id>.json
144
+ ```
145
+
146
+ 验收:
147
+
148
+ ```powershell
149
+ dazi onto function get <function_id> --space <空间>
150
+ # 确认 test_arguments 非 null,且 arguments 与 JSON 一致
151
+ ```
152
+
106
153
  ## 脚本类型与路径推断
107
154
 
108
- | 本地路径特征 | `--type` | 平台目录 |
109
- | ---------------------- | -------------------------- | --------------------- |
110
- | `脚本/setup/*init*.py` | `setup` | `setup/` |
111
- | `脚本/setup/*seed*.py` | `data` | `data/` |
112
- | `脚本/functions/*.py` | (默认 ontology_function) | `ontology_functions/` |
155
+ | 本地路径特征 | `--type` | 平台目录 |
156
+ | ------------------------- | -------------------------- | --------------------- |
157
+ | `.../setup/*init*.py` | `setup` | `setup/` |
158
+ | `.../setup/*seed*.py` | `data` | `data/` |
159
+ | `.../functions/*.py` | (默认 ontology_function) | `ontology_functions/` |
113
160
 
114
161
  ## 编写脚本时注意
115
162
 
@@ -122,7 +169,7 @@ dazi onto function run <function_id> --space <空间> --params $env:DAZI_PARAMS
122
169
  ```powershell
123
170
  $env:DAZI_BUNDLED_DIR = "<绝对路径>/dazi/dazi-vscode/bundled/clis"
124
171
  cd <工作区根>
125
- node "<绝对路径>/dazi/dazi-vscode/bundled/clis/dazi.js" onto script publish <相对路径> --space <空间> --type setup
172
+ node "<绝对路径>/dazi/dazi-vscode/bundled/clis/dazi.js" onto script publish 项目/<业务名>/本体/ontos/<实现名>/setup/xxx_ontology_init.py --space <空间> --type setup
126
173
  ```
127
174
 
128
175
  VS Code 用户也可在侧栏 **搭子 → Onto 本体** 使用「发布脚本」「运行函数」,无需终端。
@@ -141,6 +188,7 @@ VS Code 用户也可在侧栏 **搭子 → Onto 本体** 使用「发布脚本
141
188
 
142
189
  **用户补充上下文(可选)**:
143
190
 
144
- - 项目名称:{{project_name}}
191
+ - 业务项目:{{business_name}}
192
+ - 本体实现:{{item_name}}
145
193
  - 数据空间 ID:{{space_id}}
146
194
  - 当前任务:{{task}}(如:发布 training_ontology_init 并执行)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dazitech/cli",
3
- "version": "3.0.6",
3
+ "version": "3.0.8",
4
4
  "description": "搭子 v3 命令行工具(Onto / Flow / App),与 dazi-vscode 同版本",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -1,117 +0,0 @@
1
- """Customer Segmentation Function
2
-
3
- 功能:基于利润贡献对客户进行分层
4
- 参数:metric, method, start_date, end_date
5
- 返回:客户分层数据(VIP/High/Medium/Low)
6
-
7
- 放置位置:spaces/space__profit0520/editorial/scripts/ontology_functions/profit_fn_customer_segmentation.py
8
- 检索关键字:profit customer_segmentation
9
- """
10
-
11
-
12
- def _ontology_fn_body(p):
13
- params = dict(p.get_params() or {})
14
-
15
- metric = params.get("metric", "profit")
16
- method = params.get("method", "quartile")
17
- start_date = params.get("start_date", "")
18
- end_date = params.get("end_date", "")
19
-
20
- where_clause = ""
21
- if start_date and end_date:
22
- where_clause = f"WHERE order_date >= '{start_date}' AND order_date <= '{end_date}'"
23
-
24
- sql = f"""
25
- SELECT
26
- customer_id,
27
- customer_region,
28
- sum(revenue) as revenue,
29
- sum(cost) as cost,
30
- sum(revenue) - sum(cost) as profit
31
- FROM profit_analysis_fact
32
- {where_clause}
33
- GROUP BY customer_id, customer_region
34
- ORDER BY profit DESC
35
- """
36
-
37
- result = p.sql.query(sql)
38
-
39
- if not result:
40
- return p.function_result(
41
- columns=["customer_id", "customer_region", "revenue", "cost", "profit", "segment"],
42
- data=[],
43
- row_count=0
44
- )
45
-
46
- profits = [float(row.get("profit", 0) or 0) for row in result]
47
- total = len(profits)
48
-
49
- if total == 0:
50
- return p.function_result(
51
- columns=["customer_id", "customer_region", "revenue", "cost", "profit", "segment"],
52
- data=[],
53
- row_count=0
54
- )
55
-
56
- if method == "percentile":
57
- sorted_profits = sorted(profits, reverse=True)
58
- p80_idx = min(int(total * 0.8), total - 1)
59
- p50_idx = min(int(total * 0.5), total - 1)
60
- p20_idx = min(int(total * 0.2), total - 1)
61
- p80 = sorted_profits[p80_idx]
62
- p50 = sorted_profits[p50_idx]
63
- p20 = sorted_profits[p20_idx]
64
- else:
65
- sorted_profits = sorted(profits, reverse=True)
66
- q1_idx = min(int(total * 0.25), total - 1)
67
- q2_idx = min(int(total * 0.5), total - 1)
68
- q3_idx = min(int(total * 0.75), total - 1)
69
- p80 = sorted_profits[q1_idx]
70
- p50 = sorted_profits[q2_idx]
71
- p20 = sorted_profits[q3_idx]
72
-
73
- def get_segment(profit_val):
74
- if profit_val >= p80:
75
- return "VIP"
76
- elif profit_val >= p50:
77
- return "High"
78
- elif profit_val >= p20:
79
- return "Medium"
80
- else:
81
- return "Low"
82
-
83
- data = []
84
- for row in result:
85
- profit = float(row.get("profit", 0) or 0)
86
- data.append({
87
- "customer_id": str(row.get("customer_id", "")),
88
- "customer_region": str(row.get("customer_region", "")),
89
- "revenue": round(float(row.get("revenue", 0) or 0), 2),
90
- "cost": round(float(row.get("cost", 0) or 0), 2),
91
- "profit": round(profit, 2),
92
- "segment": get_segment(profit),
93
- })
94
-
95
- return p.function_result(
96
- columns=["customer_id", "customer_region", "revenue", "cost", "profit", "segment"],
97
- data=data,
98
- row_count=len(data)
99
- )
100
-
101
-
102
- def main():
103
- s = space.get(ctx.space_id or "")
104
-
105
- _Ports = type(
106
- "_Ports",
107
- (),
108
- {
109
- "get_params": lambda self: dict(ctx.params or {}),
110
- "function_result": lambda self, **kw: onto.function_result(**kw),
111
- },
112
- )
113
- p = _Ports()
114
- p.space_id = str(ctx.space_id or "")
115
- p.sql = s.sql
116
-
117
- return _ontology_fn_body(p)
@@ -1,89 +0,0 @@
1
- """MoM (Month-over-Month) Analysis Function
2
-
3
- 功能:计算指定时间范围内的月度环比分析
4
- 参数:start_date, end_date
5
- 返回:月度利润数据及环比增长率
6
-
7
- 放置位置:spaces/space__profit0520/editorial/scripts/ontology_functions/profit_fn_mom_analysis.py
8
- 检索关键字:profit mom month-over-month
9
- """
10
-
11
-
12
- def _ontology_fn_body(p):
13
- params = dict(p.get_params() or {})
14
-
15
- start_date = params.get("start_date", "")
16
- end_date = params.get("end_date", "")
17
-
18
- where_clause = ""
19
- if start_date and end_date:
20
- where_clause = f"WHERE order_date >= '{start_date}' AND order_date <= '{end_date}'"
21
-
22
- sql = f"""
23
- SELECT
24
- formatDateTime(order_date, '%Y-%m') as year_month,
25
- sum(revenue) as revenue,
26
- sum(cost) as cost,
27
- sum(revenue) - sum(cost) as profit,
28
- if(sum(revenue) > 0, (sum(revenue) - sum(cost)) / sum(revenue), 0) as profit_margin
29
- FROM profit_analysis_fact
30
- {where_clause}
31
- GROUP BY formatDateTime(order_date, '%Y-%m')
32
- ORDER BY year_month
33
- """
34
-
35
- result = p.sql.query(sql)
36
-
37
- if not result:
38
- return p.function_result(
39
- columns=["year_month", "revenue", "cost", "profit", "profit_margin", "mom_growth"],
40
- data=[],
41
- row_count=0
42
- )
43
-
44
- data = []
45
- prev_profit = None
46
-
47
- for row in result:
48
- year_month = str(row.get("year_month", ""))
49
- profit = float(row.get("profit", 0) or 0)
50
-
51
- if prev_profit is not None and prev_profit != 0:
52
- mom_growth = (profit - prev_profit) / prev_profit
53
- else:
54
- mom_growth = 0.0
55
-
56
- data.append({
57
- "year_month": year_month,
58
- "revenue": round(float(row.get("revenue", 0) or 0), 2),
59
- "cost": round(float(row.get("cost", 0) or 0), 2),
60
- "profit": round(profit, 2),
61
- "profit_margin": round(float(row.get("profit_margin", 0) or 0), 4),
62
- "mom_growth": round(mom_growth, 4),
63
- })
64
-
65
- prev_profit = profit
66
-
67
- return p.function_result(
68
- columns=["year_month", "revenue", "cost", "profit", "profit_margin", "mom_growth"],
69
- data=data,
70
- row_count=len(data)
71
- )
72
-
73
-
74
- def main():
75
- s = space.get(ctx.space_id or "")
76
-
77
- _Ports = type(
78
- "_Ports",
79
- (),
80
- {
81
- "get_params": lambda self: dict(ctx.params or {}),
82
- "function_result": lambda self, **kw: onto.function_result(**kw),
83
- },
84
- )
85
- p = _Ports()
86
- p.space_id = str(ctx.space_id or "")
87
- p.sql = s.sql
88
-
89
- return _ontology_fn_body(p)
@@ -1,89 +0,0 @@
1
- """Top Products Profit Ranking Function
2
-
3
- 功能:按利润或利润率排序,获取Top N产品
4
- 参数:limit, metric, start_date, end_date
5
- 返回:产品利润排行数据
6
-
7
- 放置位置:spaces/space__profit0520/editorial/scripts/ontology_functions/profit_fn_top_products.py
8
- 检索关键字:profit top_products ranking
9
- """
10
-
11
-
12
- def _ontology_fn_body(p):
13
- params = dict(p.get_params() or {})
14
-
15
- limit = int(params.get("limit", 10) or 10)
16
- metric = params.get("metric", "profit")
17
- start_date = params.get("start_date", "")
18
- end_date = params.get("end_date", "")
19
-
20
- where_clause = ""
21
- if start_date and end_date:
22
- where_clause = f"WHERE order_date >= '{start_date}' AND order_date <= '{end_date}'"
23
-
24
- if metric == "margin":
25
- order_by = "profit_margin DESC"
26
- else:
27
- order_by = "profit DESC"
28
-
29
- sql = f"""
30
- SELECT
31
- product_id,
32
- product_category,
33
- sum(revenue) as revenue,
34
- sum(cost) as cost,
35
- sum(revenue) - sum(cost) as profit,
36
- if(sum(revenue) > 0, (sum(revenue) - sum(cost)) / sum(revenue), 0) as profit_margin
37
- FROM profit_analysis_fact
38
- {where_clause}
39
- GROUP BY product_id, product_category
40
- ORDER BY {order_by}
41
- LIMIT {limit}
42
- """
43
-
44
- result = p.sql.query(sql)
45
-
46
- if not result:
47
- return p.function_result(
48
- columns=["rank", "product_id", "product_category", "revenue", "cost", "profit", "profit_margin"],
49
- data=[],
50
- row_count=0
51
- )
52
-
53
- data = []
54
- rank = 1
55
- for row in result:
56
- data.append({
57
- "rank": rank,
58
- "product_id": str(row.get("product_id", "")),
59
- "product_category": str(row.get("product_category", "")),
60
- "revenue": round(float(row.get("revenue", 0) or 0), 2),
61
- "cost": round(float(row.get("cost", 0) or 0), 2),
62
- "profit": round(float(row.get("profit", 0) or 0), 2),
63
- "profit_margin": round(float(row.get("profit_margin", 0) or 0), 4),
64
- })
65
- rank += 1
66
-
67
- return p.function_result(
68
- columns=["rank", "product_id", "product_category", "revenue", "cost", "profit", "profit_margin"],
69
- data=data,
70
- row_count=len(data)
71
- )
72
-
73
-
74
- def main():
75
- s = space.get(ctx.space_id or "")
76
-
77
- _Ports = type(
78
- "_Ports",
79
- (),
80
- {
81
- "get_params": lambda self: dict(ctx.params or {}),
82
- "function_result": lambda self, **kw: onto.function_result(**kw),
83
- },
84
- )
85
- p = _Ports()
86
- p.space_id = str(ctx.space_id or "")
87
- p.sql = s.sql
88
-
89
- return _ontology_fn_body(p)