@fieldwangai/agentflow 0.1.149 → 0.1.154

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 (195) hide show
  1. package/README.md +20 -33
  2. package/README.zh-CN.md +14 -34
  3. package/agents/agentflow-node-executor-code.md +13 -3
  4. package/agents/agentflow-node-executor-planning.md +13 -3
  5. package/agents/agentflow-node-executor-requirement.md +13 -3
  6. package/agents/agentflow-node-executor-test.md +13 -3
  7. package/agents/agentflow-node-executor-ui.md +13 -3
  8. package/agents/agentflow-node-executor.md +13 -3
  9. package/agents/en/agentflow-node-executor.md +13 -3
  10. package/agents/zh/agentflow-node-executor.md +13 -3
  11. package/bin/agentflow.mjs +3 -3
  12. package/bin/lib/admin-builtin-pipelines.mjs +3 -2
  13. package/bin/lib/agent-runners.mjs +0 -929
  14. package/bin/lib/auth.mjs +2 -1
  15. package/bin/lib/catalog-agents.mjs +2 -1
  16. package/bin/lib/catalog-flows.mjs +167 -88
  17. package/bin/lib/composer-agent.mjs +3 -793
  18. package/bin/lib/composer-skill-router.mjs +3 -323
  19. package/bin/lib/exec-buffered.mjs +32 -0
  20. package/bin/lib/flow-dsl/cli.mjs +276 -0
  21. package/bin/lib/flow-dsl/codegen.mjs +358 -0
  22. package/bin/lib/flow-dsl/defs.mjs +103 -0
  23. package/bin/lib/flow-dsl/index.mjs +77 -0
  24. package/bin/lib/flow-dsl/ir.mjs +305 -0
  25. package/bin/lib/flow-dsl/layout.mjs +115 -0
  26. package/bin/lib/flow-dsl/legacy-yaml.mjs +268 -0
  27. package/bin/lib/flow-dsl/lint.mjs +241 -0
  28. package/bin/lib/flow-dsl/packages.mjs +251 -0
  29. package/bin/lib/flow-dsl/parser.mjs +444 -0
  30. package/bin/lib/flow-import.mjs +96 -26
  31. package/bin/lib/flow-write.mjs +48 -12
  32. package/bin/lib/help.mjs +10 -30
  33. package/bin/lib/html-escape.mjs +19 -0
  34. package/bin/lib/http-util.mjs +49 -0
  35. package/bin/lib/legacy-flow-execution.mjs +43 -0
  36. package/bin/lib/locales/en.json +1 -1
  37. package/bin/lib/locales/zh.json +1 -1
  38. package/bin/lib/main.mjs +153 -283
  39. package/bin/lib/marketplace.mjs +206 -61
  40. package/bin/lib/model-config.mjs +10 -0
  41. package/bin/lib/node-package-archive.mjs +240 -0
  42. package/bin/lib/node-package-bootstrap.mjs +72 -0
  43. package/bin/lib/node-package-manifest.mjs +174 -0
  44. package/bin/lib/paths.mjs +42 -19
  45. package/bin/lib/prd-workflow-routes.mjs +2949 -0
  46. package/bin/lib/prd-workflow-server.mjs +4884 -0
  47. package/bin/lib/run-events.mjs +0 -66
  48. package/bin/lib/schedule-config.mjs +4 -4
  49. package/bin/lib/skill-runtime.mjs +35 -0
  50. package/bin/lib/startup-storage-migrations.mjs +274 -0
  51. package/bin/lib/ui-server.mjs +1106 -18013
  52. package/bin/lib/user-env.mjs +16 -0
  53. package/bin/lib/workspace-auto-layout.mjs +234 -0
  54. package/bin/lib/workspace-flow-store.mjs +478 -0
  55. package/bin/lib/workspace-graph-merge.mjs +41 -34
  56. package/bin/lib/workspace-preview.mjs +74 -0
  57. package/bin/lib/workspace-routes.mjs +3088 -0
  58. package/bin/lib/workspace-server.mjs +6199 -0
  59. package/bin/lib/workspace-state.mjs +331 -0
  60. package/bin/lib/workspace.mjs +2 -1
  61. package/builtin/nodes/agent_subAgent.md +1 -0
  62. package/builtin/nodes/control_agent_toBool.md +2 -0
  63. package/builtin/nodes/control_anyOne.md +2 -0
  64. package/builtin/nodes/control_cancelled.md +2 -0
  65. package/builtin/nodes/control_cd_workspace.md +5 -11
  66. package/builtin/nodes/control_delay.md +2 -0
  67. package/builtin/nodes/control_end.md +2 -0
  68. package/builtin/nodes/control_if.md +1 -0
  69. package/builtin/nodes/control_interval_loop.md +2 -0
  70. package/builtin/nodes/control_load_mcp.md +24 -0
  71. package/builtin/nodes/control_load_skills.md +8 -23
  72. package/builtin/nodes/control_start.md +2 -0
  73. package/builtin/nodes/control_toBool.md +2 -0
  74. package/builtin/nodes/control_user_workspace.md +2 -0
  75. package/builtin/nodes/control_wait_until.md +2 -0
  76. package/builtin/nodes/display_ascii.md +1 -0
  77. package/builtin/nodes/display_chart.md +1 -0
  78. package/builtin/nodes/display_html.md +1 -0
  79. package/builtin/nodes/display_image.md +1 -0
  80. package/builtin/nodes/display_markdown.md +1 -0
  81. package/builtin/nodes/display_mermaid.md +1 -0
  82. package/builtin/nodes/display_react_app.md +1 -0
  83. package/builtin/nodes/display_table.md +1 -0
  84. package/builtin/nodes/provide_bool.md +1 -0
  85. package/builtin/nodes/provide_file.md +1 -0
  86. package/builtin/nodes/provide_password.md +1 -0
  87. package/builtin/nodes/provide_str.md +1 -0
  88. package/builtin/nodes/tool_display_share_link.md +1 -0
  89. package/builtin/nodes/tool_get_env.md +2 -0
  90. package/builtin/nodes/tool_git_checkout.md +1 -0
  91. package/builtin/nodes/tool_git_worktree_load.md +1 -0
  92. package/builtin/nodes/tool_git_worktree_unload.md +1 -0
  93. package/builtin/nodes/tool_gitlab_create_mr.md +1 -0
  94. package/builtin/nodes/tool_jenkins_build.md +2 -0
  95. package/builtin/nodes/tool_load_key.md +2 -0
  96. package/builtin/nodes/tool_nodejs.md +17 -19
  97. package/builtin/nodes/tool_print.md +2 -0
  98. package/builtin/nodes/tool_save_key.md +2 -0
  99. package/builtin/nodes/tool_set_run_env.md +1 -0
  100. package/builtin/nodes/tool_user_ask.md +2 -0
  101. package/builtin/nodes/tool_user_check.md +2 -0
  102. package/builtin/nodes/tool_wecom_send_app_markdown.md +1 -0
  103. package/builtin/nodes/tool_wecom_send_group_markdown.md +1 -0
  104. package/builtin/nodes/workspace_one_click_task.md +44 -0
  105. package/builtin/nodes/workspace_run.md +16 -0
  106. package/builtin/nodes/workspace_scheduled_run.md +16 -0
  107. package/builtin/pipelines/module-migrate/scripts/gate.mjs +37 -0
  108. package/builtin/pipelines/module-migrate/scripts/static-check.mjs +82 -0
  109. package/builtin/pipelines/module-migrate/workspace.flow.js +172 -0
  110. package/builtin/pipelines/module-migrate/workspace.layout.json +134 -0
  111. package/builtin/pipelines/new/scripts/lint-flow.mjs +38 -0
  112. package/builtin/pipelines/new/workspace.flow.js +91 -0
  113. package/builtin/pipelines/new/workspace.layout.json +70 -0
  114. package/builtin/web-ui/dist/assets/{WorkflowAssistantThread-DPbR2UaN.js → WorkflowAssistantThread-CKClwj96.js} +1 -1
  115. package/builtin/web-ui/dist/assets/index-BZ5KqLur.js +870 -0
  116. package/builtin/web-ui/dist/assets/index-CEXmmwM2.css +1 -0
  117. package/builtin/web-ui/dist/index.html +2 -2
  118. package/package.json +2 -1
  119. package/reference/flow-control-capabilities.md +77 -158
  120. package/reference/flow-layout.md +1 -1
  121. package/reference/flow-prompt-handler-check.md +2 -2
  122. package/skills/agentflow-author-flow/SKILL.md +8 -47
  123. package/skills/agentflow-cli/SKILL.md +158 -25
  124. package/skills/agentflow-cli/agents/openai.yaml +2 -2
  125. package/skills/agentflow-cli/scripts/agentflow-cli.mjs +668 -18
  126. package/skills/agentflow-cli/scripts/agentflow-runtime.mjs +97 -0
  127. package/skills/agentflow-flow-add-instances/SKILL.md +7 -248
  128. package/skills/agentflow-flow-dsl/SKILL.md +206 -0
  129. package/skills/agentflow-flow-dsl/agents/openai.yaml +4 -0
  130. package/skills/agentflow-flow-dsl/references/node-calls.md +39 -0
  131. package/skills/agentflow-flow-edit-node-fields/SKILL.md +4 -73
  132. package/skills/agentflow-flow-recipes/SKILL.md +7 -18
  133. package/skills/agentflow-flow-recipes/references/recipes.md +97 -43
  134. package/skills/agentflow-flow-sync-ui/SKILL.md +3 -54
  135. package/skills/agentflow-node-dsl/SKILL.md +212 -0
  136. package/skills/agentflow-node-dsl/agents/openai.yaml +4 -0
  137. package/skills/agentflow-node-reference/SKILL.md +5 -4
  138. package/skills/agentflow-node-reference/references/builtin-nodes.md +166 -115
  139. package/skills/agentflow-placeholder-reference/SKILL.md +2 -2
  140. package/skills/agentflow-runtime-reference/SKILL.md +2 -2
  141. package/skills/agentflow-runtime-reference/references/runtime.md +1 -1
  142. package/skills/agentflow-workspace-ascii/SKILL.md +9 -16
  143. package/skills/agentflow-workspace-graph/SKILL.md +62 -48
  144. package/skills/agentflow-workspace-html/SKILL.md +7 -2
  145. package/skills/agentflow-workspace-image/SKILL.md +6 -2
  146. package/skills/agentflow-workspace-markdown/SKILL.md +14 -21
  147. package/skills/agentflow-workspace-mermaid/SKILL.md +8 -16
  148. package/bin/lib/api-runner.mjs +0 -387
  149. package/bin/lib/apply.mjs +0 -903
  150. package/bin/lib/composer-flow-instances.mjs +0 -68
  151. package/bin/lib/composer-flow-skeleton.mjs +0 -334
  152. package/bin/lib/composer-flow-validate.mjs +0 -47
  153. package/bin/lib/composer-model-router.mjs +0 -185
  154. package/bin/lib/composer-node-schema.mjs +0 -303
  155. package/bin/lib/composer-planner.mjs +0 -751
  156. package/bin/lib/composer-script-ops.mjs +0 -233
  157. package/bin/lib/flow-static-preview.mjs +0 -104
  158. package/bin/lib/hub-login.mjs +0 -54
  159. package/bin/lib/hub-publish.mjs +0 -159
  160. package/bin/lib/hub-remote.mjs +0 -189
  161. package/bin/lib/hub.mjs +0 -299
  162. package/bin/lib/jenkins.mjs +0 -380
  163. package/bin/lib/node-execute.mjs +0 -539
  164. package/bin/lib/normalize-node-tool-command.mjs +0 -97
  165. package/bin/lib/runtime-context.mjs +0 -243
  166. package/bin/lib/scheduler.mjs +0 -601
  167. package/bin/lib/ui-print.mjs +0 -94
  168. package/bin/pipeline/build-node-prompt.mjs +0 -271
  169. package/bin/pipeline/check-cache.mjs +0 -191
  170. package/bin/pipeline/check-flow.mjs +0 -543
  171. package/bin/pipeline/collect-nodes.mjs +0 -212
  172. package/bin/pipeline/compute-cache-md5.mjs +0 -177
  173. package/bin/pipeline/ensure-run-dir.mjs +0 -71
  174. package/bin/pipeline/gc.mjs +0 -129
  175. package/bin/pipeline/get-env.mjs +0 -59
  176. package/bin/pipeline/get-resolved-values.mjs +0 -344
  177. package/bin/pipeline/load-key.mjs +0 -62
  178. package/bin/pipeline/parse-flow.mjs +0 -708
  179. package/bin/pipeline/post-process-control-if.mjs +0 -23
  180. package/bin/pipeline/post-process-node.mjs +0 -490
  181. package/bin/pipeline/pre-process-node.mjs +0 -1430
  182. package/bin/pipeline/resolve-inputs.mjs +0 -201
  183. package/bin/pipeline/run-tool-nodejs.mjs +0 -167
  184. package/bin/pipeline/save-key.mjs +0 -93
  185. package/bin/pipeline/snapshot-prior-round.mjs +0 -70
  186. package/bin/pipeline/validate-for-ui.mjs +0 -234
  187. package/bin/pipeline/validate-script-output.mjs +0 -130
  188. package/bin/pipeline/write-result.mjs +0 -182
  189. package/builtin/pipelines/module-migrate/flow.yaml +0 -819
  190. package/builtin/pipelines/new/flow.yaml +0 -545
  191. package/builtin/pipelines/new/scripts/check-flow.mjs +0 -9
  192. package/builtin/pipelines/new/scripts/collect-nodes.mjs +0 -211
  193. package/builtin/web-ui/dist/assets/index-BSCpd5la.js +0 -889
  194. package/builtin/web-ui/dist/assets/index-DZ328oSo.css +0 -1
  195. package/skills/agentflow-node-authoring/SKILL.md +0 -57
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: create share link for Display nodes
3
+ runtime: native
3
4
  description: Create a public share link for upstream Display nodes
4
5
  displayName: Display Share Link
5
6
  input:
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # 内置节点:按 key 读取环境/配置
3
+ runtime: none
4
+ palette: hidden
3
5
  description: Get environment variable value
4
6
  displayName: GetEnv
5
7
  input:
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # 内置节点:Git Checkout
3
+ runtime: native
3
4
  description: |
4
5
  Clone or update a Git repository and expose it as a workspace context for downstream nodes.
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: Git Worktree Load
3
+ runtime: native
3
4
  description: |
4
5
  Create or reuse a Git worktree and expose it as the downstream workspace context.
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: Git Worktree Unload
3
+ runtime: native
3
4
  description: |
4
5
  Remove a Git worktree.
5
6
 
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: GitLab Create MR
3
+ runtime: native
3
4
  description: |
4
5
  Create or reuse a GitLab merge request for the current branch.
5
6
 
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # Built-in node: durable Jenkins build
3
+ runtime: none
4
+ palette: hidden
3
5
  description: |
4
6
  Trigger one Jenkins job and durably monitor it until completion.
5
7
 
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # 内置节点:按 key 读取
3
+ runtime: none
4
+ palette: hidden
3
5
  description: Load key-value from global storage
4
6
  displayName: LoadKey
5
7
  input:
@@ -1,30 +1,28 @@
1
1
  ---
2
2
  # 内置节点:执行 Node.js
3
+ runtime: native
3
4
  description: |
4
- Execute Node.js script via agentflow apply -ai run-tool-nodejs.
5
+ Execute a Node.js script. The Workspace runtime spawns the command directly — no agent involved.
5
6
 
6
- **Success/Failure:** Determined by script process **exit code**—0 = success, non-0 = failed.
7
- **Result Output:** Script stdout directly becomes result slot content (plain text, e.g., `console.log("hello")`).
8
- When stdout is empty and exit code is non-0, stderr info will be written to failure message.
7
+ **Success/Failure:** Determined by the script process **exit code** — 0 = success, non-0 = failed.
8
+ **Result Output:** Script stdout becomes the `result` slot content (plain text, e.g. `console.log("hello")`).
9
+ When stdout is empty and the exit code is non-0, stderr is written to the failure message.
10
+ Do **not** wrap stdout in a JSON envelope.
9
11
 
10
- **JSON Compatible (Optional):** If stdout is `{"err_code":0,"message":{"result":"..."}}` format, err_code will override exit code semantics, message.result writes to result slot. Only use when needing different success/failure semantics than exit code.
11
-
12
- **Direct Execution Mode (Recommended):** Set `script` field in flow.yaml instance, pipeline will skip AI and execute directly.
13
- `script` supports ${} placeholders (workspaceRoot, pipelineWorkspace, flowName, runDir, flowDir and all input/output slots), values are auto shell-quoted.
14
- When a CD Workspace node is connected, `workspaceRoot` is the current execution workspace; `pipelineWorkspace` is the original pipeline workspace.
15
- flowDir is absolute path of current pipeline flow.yaml directory, can be used to reference scripts in same directory.
12
+ **Script placeholders:** `script` (inline) or `scriptRef` (file) support `${}` placeholders
13
+ `workspaceRoot` / `pipelineWorkspace` / `flowDir` (all three resolve to the scoped workspace root),
14
+ `cwd`, `nodeRunDir`, `nodeTmpDir`, `outputsDir`, `scriptRef`, plus every input and output slot name.
15
+ Values are auto shell-quoted, so do not add your own quotes.
16
16
  Example: `script: node ${flowDir}/scripts/my-check.mjs --root ${workspaceRoot} --input ${todo}`
17
17
 
18
- **Pin Path Constraint (Important):** File paths read/written by script **must be passed via pins**, forbidden to construct output paths inside script.
19
- - All input slots with type 'file' (e.g., `figma_tree`, `semantic_outline`) are parsed from upstream connections by pipeline, script receives via CLI args.
20
- - All output slots with type 'file' (e.g., `restore_todolist`, `screenshot_map`) are generated by pipeline as absolute paths following `output/<instanceId>/node_<instanceId>_<slot>.md` convention, script receives via CLI args and writes directly.
21
- - Use `${slotName}` in `script` field to get correct path, e.g., `--figma-tree ${figma_tree} --output ${restore_todolist}`.
22
- - **Forbidden** to use `outDirForNode`, manually write `node_<instance>_xxx.json` etc. in script—this causes script output path mismatch with pipeline parser convention, downstream nodes cannot find files.
23
-
24
- **AI Execution Mode (Legacy):** Without `script` field, AI agent reads body and manually executes commands.
18
+ **Pin Path Constraint (Important):** File paths read/written by the script **must be passed via pins**;
19
+ never construct output paths inside the script.
20
+ - Input slots of type `file` are resolved from upstream connections; the script receives them as CLI args.
21
+ - Output slots of type `file` are resolved to absolute paths by the runtime; the script writes to them directly.
22
+ - Reference them with `${slotName}` in `script`, e.g. `--figma-tree ${figma_tree} --output ${restore_todolist}`.
23
+ - **Forbidden** to invent output paths inside the script — downstream nodes will not find the files.
25
24
 
26
- **Underlying Usage:**
27
- agentflow apply -ai run-tool-nodejs <workspaceRoot> <flowName> <uuid> <instanceId> [execId] -- <scriptCmd> [args...]
25
+ **Scripts under `scripts/` must be referenced as `${flowDir}/scripts/xxx.mjs`.**
28
26
  displayName: NodeJs
29
27
  input:
30
28
  - type: node
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # 内置节点:醒目输出
3
+ runtime: none
4
+ palette: hidden
3
5
  description: Output content to user with special font style
4
6
  displayName: Print
5
7
  input:
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # 内置节点:按 key 写入
3
+ runtime: none
4
+ palette: hidden
3
5
  description: Save key-value pair to global storage
4
6
  displayName: SaveKey
5
7
  input:
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: set environment variables for the current run only
3
+ runtime: native
3
4
  description: Set environment variables for downstream nodes in the current workspace run
4
5
  displayName: Set Run Env
5
6
  input:
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # 内置节点:用户选择(Switch 分支)
3
+ runtime: none
4
+ palette: hidden
3
5
  description: 等待用户从多个选项中选择一个,流程暂停;按用户选择沿对应出边分支继续。每个 output 槽位对应一条分支,槽位的 description 作为选项文案。
4
6
  displayName: UserAsk
5
7
  input:
@@ -1,5 +1,7 @@
1
1
  ---
2
2
  # 内置节点:用户确认
3
+ runtime: none
4
+ palette: hidden
3
5
  description: 等待用户确认,流程暂停。展示确认内容给用户,用户可编辑/AI修改后保存,回复 "继续" 后重启流程。
4
6
  displayName: UserCheck
5
7
  input:
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: WeCom direct markdown message
3
+ runtime: native
3
4
  description: Send Markdown message to WeCom users through an enterprise application
4
5
  displayName: WeCom Direct Markdown
5
6
  input:
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  # Built-in node: WeCom group robot markdown message
3
+ runtime: native
3
4
  description: Send Markdown message to a WeCom group robot webhook
4
5
  displayName: WeCom Group Chat Markdown
5
6
  input:
@@ -0,0 +1,44 @@
1
+ ---
2
+ # 内置节点:一键任务
3
+ runtime: native
4
+ type: agent
5
+ description: 输入任务描述,选择 Skills、workspace 上下文和输出类型后直接运行;等价于「Load Skills + 子 Agent + Display」的合并节点。
6
+ displayName: 一键任务
7
+ input:
8
+ - type: node
9
+ name: prev
10
+ default: ""
11
+ - type: text
12
+ name: skillKeys
13
+ default: ""
14
+ showOnNode: false
15
+ - type: bool
16
+ name: includeWorkspaceContext
17
+ default: "true"
18
+ showOnNode: false
19
+ - type: text
20
+ name: displayType
21
+ default: "markdown"
22
+ showOnNode: false
23
+ - type: text
24
+ name: knowledgeContext
25
+ default: ""
26
+ showOnNode: false
27
+ - type: text
28
+ name: workspaceContext
29
+ default: ""
30
+ showOnNode: false
31
+ output:
32
+ - type: node
33
+ name: next
34
+ default: ""
35
+ - type: text
36
+ name: content
37
+ default: ""
38
+ showOnNode: true
39
+ - type: text
40
+ name: displayType
41
+ default: "markdown"
42
+ showOnNode: false
43
+ ---
44
+ 输入任务,选择 Skills、workspace 上下文和输出类型后直接运行。
@@ -0,0 +1,16 @@
1
+ ---
2
+ # 内置节点:Run
3
+ runtime: native
4
+ type: control
5
+ description: Workspace 图的运行入口。点击运行时,从本节点出发沿控制边选出子图并执行;本节点自身不产生输出。
6
+ displayName: Run
7
+ input:
8
+ - type: node
9
+ name: prev
10
+ default: ""
11
+ output:
12
+ - type: node
13
+ name: next
14
+ default: ""
15
+ ---
16
+ Run the downstream workspace subgraph connected from this node.
@@ -0,0 +1,16 @@
1
+ ---
2
+ # 内置节点:Scheduled Run
3
+ runtime: native
4
+ type: control
5
+ description: 定时运行入口。与 Run 相同的执行语义,区别是由调度器按节点 body 中的 JSON 排程配置触发。
6
+ displayName: Scheduled Run
7
+ input:
8
+ - type: node
9
+ name: prev
10
+ default: ""
11
+ output:
12
+ - type: node
13
+ name: next
14
+ default: ""
15
+ ---
16
+ Run the downstream workspace subgraph on a schedule.
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 把「脚本判定」和「AI 判定」合成一个 bool,喂给 `control.if` 的 prediction。
4
+ *
5
+ * 用法(由 tool_nodejs 的 script 调用):
6
+ * node gate.mjs <scriptOk> <aiVerdict> <okPath> <reportPath>
7
+ *
8
+ * - `<scriptOk>`:上游脚本节点写的 `true` / `false`
9
+ * - `<aiVerdict>`:上游 agent 的回复正文,**第一行**必须是 true / false
10
+ *
11
+ * 为什么不用 `control.agentToBool`:那个节点没有任何东西约束模型输出,`parse-bool` 只认
12
+ * `true` / `1` / `yes` / `on`,模型回「是」或「true(因为…)」都会静默变成 false。判定能
13
+ * 用脚本做的时候就别交给模型。
14
+ */
15
+ import fs from "node:fs";
16
+
17
+ const [scriptOk, aiVerdict, okPath, reportPath] = process.argv.slice(2);
18
+
19
+ if (!okPath || !reportPath) {
20
+ console.error("用法: node gate.mjs <scriptOk> <aiVerdict> <okPath> <reportPath>");
21
+ process.exit(1);
22
+ }
23
+
24
+ const scriptPassed = String(scriptOk || "").trim().toLowerCase() === "true";
25
+ const firstLine = String(aiVerdict || "").trim().split("\n")[0].trim().toLowerCase();
26
+ const aiPassed = firstLine === "true";
27
+ const ok = scriptPassed && aiPassed;
28
+
29
+ fs.writeFileSync(reportPath, [
30
+ `脚本检查:${scriptPassed ? "通过" : "未通过"}`,
31
+ `AI 检查:${aiPassed ? "通过" : `未通过(首行是 ${JSON.stringify(firstLine)},期望 true)`}`,
32
+ "",
33
+ ok ? "两边都干净,进入编译。" : "有一边没过,进入修复。",
34
+ ].join("\n"), "utf-8");
35
+ fs.writeFileSync(okPath, ok ? "true" : "false", "utf-8");
36
+
37
+ console.log(`脚本=${scriptPassed} AI=${aiPassed} -> ${ok}`);
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 把 `check_imports.mjs` 接到 Workspace 运行时上。
4
+ *
5
+ * 用法(由 tool_nodejs 的 script 调用):
6
+ * node static-check.mjs <repoRoot> <beforeList> <afterList> <okPath> <reportPath>
7
+ *
8
+ * `<beforeList>` / `<afterList>` 是**清单正文**(每行一个仓库相对路径),不是文件路径——
9
+ * 上游 agent 的回复正文直接作为引脚值传进来。这里落成临时文件再喂给 check_imports。
10
+ *
11
+ * `check_imports.mjs` 是旧执行栈的产物,stdout 吐一行
12
+ * `{"err_code":0|1,"message":{"result":"…"}}`。Workspace 运行时不认这个信封,所以在这里
13
+ * 拆开:结果写 `<reportPath>`,通过与否写 `<okPath>`(`true` / `false`)。
14
+ *
15
+ * **总是 exit 0**:查出问题不是这一步失败,是下一步要修的事。真失败只有「脚本跑不起来」。
16
+ * 缺 tree-sitter 依赖时也走 `false` + 明确的报告,绝不静默跳过。
17
+ */
18
+ import { spawnSync } from "node:child_process";
19
+ import fs from "node:fs";
20
+ import path from "node:path";
21
+ import { fileURLToPath } from "node:url";
22
+
23
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
24
+ const [repoRoot, beforeText, afterText, okPath, reportPath] = process.argv.slice(2);
25
+
26
+ if (!repoRoot || !okPath || !reportPath) {
27
+ console.error("用法: node static-check.mjs <repoRoot> <beforeList> <afterList> <okPath> <reportPath>");
28
+ process.exit(1);
29
+ }
30
+
31
+ const finish = (ok, report) => {
32
+ fs.writeFileSync(reportPath, report, "utf-8");
33
+ fs.writeFileSync(okPath, ok ? "true" : "false", "utf-8");
34
+ console.log(ok ? "静态检查通过" : "静态检查有问题,交给下游修");
35
+ process.exit(0);
36
+ };
37
+
38
+ if (!fs.existsSync(path.join(HERE, "node_modules", "tree-sitter"))) {
39
+ finish(false, [
40
+ "# 静态检查未运行",
41
+ "",
42
+ "`check_imports.mjs` 依赖 tree-sitter,当前 `scripts/node_modules` 里没有。先执行:",
43
+ "",
44
+ "```bash",
45
+ `cd ${HERE} && npm install`,
46
+ "```",
47
+ "",
48
+ "装完重跑本节点。**这一轮的 false 不代表代码有问题,只代表没查。**",
49
+ ].join("\n"));
50
+ }
51
+
52
+ const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || "/tmp", "static-check-"));
53
+ const beforeFile = path.join(tmpDir, "before.txt");
54
+ const afterFile = path.join(tmpDir, "after.txt");
55
+ fs.writeFileSync(beforeFile, String(beforeText || ""), "utf-8");
56
+ fs.writeFileSync(afterFile, String(afterText || ""), "utf-8");
57
+
58
+ const r = spawnSync("node", [
59
+ path.join(HERE, "check_imports.mjs"),
60
+ "--root", repoRoot,
61
+ "--before-list", beforeFile,
62
+ "--after-list", afterFile,
63
+ ], { encoding: "utf-8" });
64
+
65
+ if (r.error) {
66
+ console.error(`执行 check_imports.mjs 失败:${r.error.message}`);
67
+ process.exit(1);
68
+ }
69
+
70
+ let payload = null;
71
+ try {
72
+ payload = JSON.parse(String(r.stdout || "").trim().split("\n").pop() || "");
73
+ } catch {
74
+ payload = null;
75
+ }
76
+
77
+ if (!payload) {
78
+ finish(false, `# 静态检查输出无法解析\n\n\`\`\`\n${(r.stdout || "") + (r.stderr || "")}\n\`\`\`\n`);
79
+ }
80
+
81
+ const detail = String(payload?.message?.result || "").trim();
82
+ finish(payload.err_code === 0 && !detail, `# 静态引用检查\n\n${detail || "未发现主模块直接引用被迁类。"}\n`);
@@ -0,0 +1,172 @@
1
+ import { agent, control, display, flow, provide, tool } from "agentflow/flow";
2
+
3
+ // ── 输入:原来这些值硬编码在节点正文里,现在提到引脚上 ──────────────
4
+ const repoRoot = provide.str("仓库根目录", {
5
+ value: ".",
6
+ });
7
+ const sourcePath = provide.str("待迁移的源码路径", {
8
+ value: "app/src/main/java/com/example/push/",
9
+ });
10
+ const moduleName = provide.str("新模块名", {
11
+ value: "module-push",
12
+ });
13
+ const rules = provide.str("模块规范文档", {
14
+ value: ".cursor/rules/android-module-structure.mdc、.cursor/rules/module-main-sub-dependency.mdc",
15
+ });
16
+
17
+ // ══ ① 定范围 ════════════════════════════════════════════════════════
18
+ const scope = agent.subAgent("确定迁移范围", {}, `参照 ${rules.value},确定 ${sourcePath.value} 的迁移范围。仓库根目录 ${repoRoot.value}。
19
+
20
+ **只定范围,不动任何文件。**
21
+
22
+ 回复正文就是要迁的文件清单,每行一个仓库相对路径,不要标题、不要编号、不要别的话——下游脚本按行解析。`);
23
+
24
+ const showScope = display.markdown("迁移范围(确认后点②)", { content: scope.result });
25
+
26
+ export const scopeRun = flow("① 定范围", scope, showScope);
27
+
28
+ // ══ ② 建模块并迁移 ══════════════════════════════════════════════════
29
+ const newModule = agent.subAgent("新建模块", {}, `参照 ${rules.value},在 ${repoRoot.value} 下新建模块 ${moduleName.value},同时建出配套的 ${moduleName.value}_api。
30
+
31
+ 按规范补齐 build.gradle、settings.gradle 注册、包结构。`);
32
+
33
+ const migrate = agent.subAgent("执行迁移", {}, `按清单迁移到 ${moduleName.value}:
34
+
35
+ ${scope.result}
36
+
37
+ **只搬代码和资源,不改业务逻辑。** 可以并行分派多个 agent,但只做搬运,不做检查。
38
+
39
+ 回复正文是迁移后的文件清单,每行一个仓库相对路径,格式同上。`);
40
+
41
+ // ── 静态检查:脚本查一遍,AI 再查一遍,两个判定用脚本合成一个 bool ──
42
+ const staticCheck = tool.nodejs("静态引用检查", {
43
+ repoRoot: repoRoot.value,
44
+ before: scope.result,
45
+ after: migrate.result,
46
+ }, `node ${flowDir}/scripts/static-check.mjs ${repoRoot} ${before} ${after} ${ok} ${report}`);
47
+ const { ok: staticOk, report: staticReport } = staticCheck;
48
+
49
+ const aiCheck = agent.subAgent("AI 交叉检查", {}, `迁移前清单:
50
+
51
+ ${scope.result}
52
+
53
+ 迁移后清单:
54
+
55
+ ${migrate.result}
56
+
57
+ 脚本侧的静态检查结果:
58
+
59
+ ${staticReport}
60
+
61
+ 参照 ${rules.value},检查主模块是否还直接依赖被迁走的类。逐条列出需要改成 API 中转的位置(\`文件:行号 -> 全限定类名\`)。
62
+
63
+ **回复正文第一行必须只有 \`true\` 或 \`false\`**:脚本和你自己都没查出问题写 true,任一有问题写 false。第二行起写明细。`);
64
+
65
+ const verdict = tool.nodejs("合成静态检查结论", {
66
+ scriptOk: staticOk,
67
+ aiVerdict: aiCheck.result,
68
+ }, `node ${flowDir}/scripts/gate.mjs ${scriptOk} ${aiVerdict} ${ok} ${report}`);
69
+ const { ok: verdictOk, report: verdictReport } = verdict;
70
+
71
+ // ── 静态一次过:直接编译 ────────────────────────────────────────────
72
+ // 「逐个编译、失败就修、修完重编」是节点内部的迭代,不是图上的环——图不支持环,
73
+ // 而 agent 本来就能在一个节点里循环。原来那圈 anyOne + toBool + if 就是在图上
74
+ // 表达本该在节点里表达的东西。
75
+ const buildA = agent.subAgent("编译并修到通过", {}, `在 ${repoRoot.value} 用 gradle 列出 Java / Kotlin 的 debug 编译任务,**串行**逐个执行,一次一个,不要一把梭。
76
+
77
+ 失败就当场修(参照 ${rules.value},缺的依赖走 _api 模块中转,不要把实现类重新暴露给主模块),修完重编该任务,直到全过或确实卡住。
78
+
79
+ 回复正文第一行只写 \`true\`(全部通过)或 \`false\`(有卡住的),第二行起写任务清单和失败详情。`);
80
+
81
+ const buildOkA = control.agentToBool("编译全过了吗", { value: buildA.result }, `上游正文第一行是 true 或 false。**只回 true 或 false 这一个词**,多一个字都会被判成 false。`);
82
+
83
+ const docA = agent.subAgent("输出迁移文档", {}, `把这次迁移写成文档:范围、改了什么、主模块改成 API 中转的位置、遗留问题。
84
+
85
+ 范围:${scope.result}
86
+
87
+ 编译结果:${buildA.result}`);
88
+ const showDocA = display.markdown("迁移文档", { content: docA.result });
89
+ const buildStuckA = display.markdown("编译卡住,需要人工介入", { content: buildA.result });
90
+
91
+ const gateBuildA = control.if("编译过了吗", { prediction: buildOkA.prediction },
92
+ flow(docA, showDocA),
93
+ flow(buildStuckA),
94
+ );
95
+
96
+ // ── 静态没过:修一轮,再查一轮。没有循环原语,就展开成固定两轮 ──────
97
+ const fix1 = agent.subAgent("修引用", {}, `静态检查没过。
98
+
99
+ ${verdictReport}
100
+
101
+ 脚本报告:
102
+ ${staticReport}
103
+
104
+ AI 检查:
105
+ ${aiCheck.result}
106
+
107
+ 参照 ${rules.value},把主模块里直接用到被迁类的地方改成走 SPI(对应的 _api 模块)中转。一次批量处理多条,改完自检一遍。`);
108
+
109
+ const staticCheck2 = tool.nodejs("静态引用复查", {
110
+ repoRoot: repoRoot.value,
111
+ before: scope.result,
112
+ after: migrate.result,
113
+ }, `node ${flowDir}/scripts/static-check.mjs ${repoRoot} ${before} ${after} ${ok} ${report}`);
114
+ const { ok: staticOk2, report: staticReport2 } = staticCheck2;
115
+
116
+ const aiCheck2 = agent.subAgent("AI 复查", {}, `修完一轮了。脚本侧复查结果:
117
+
118
+ ${staticReport2}
119
+
120
+ 参照 ${rules.value} 再查一遍主模块对被迁类的直接依赖。
121
+
122
+ **回复正文第一行必须只有 \`true\` 或 \`false\`。**`);
123
+
124
+ const verdict2 = tool.nodejs("合成复查结论", {
125
+ scriptOk: staticOk2,
126
+ aiVerdict: aiCheck2.result,
127
+ }, `node ${flowDir}/scripts/gate.mjs ${scriptOk} ${aiVerdict} ${ok} ${report}`);
128
+ const { ok: verdictOk2, report: verdictReport2 } = verdict2;
129
+
130
+ // 修过一轮之后的编译链。和上面那条是两条独立的链——分支不能汇合,fan-in 是禁止的
131
+ const buildB = agent.subAgent("编译并修到通过(修过一轮)", {}, `在 ${repoRoot.value} 用 gradle 列出 Java / Kotlin 的 debug 编译任务,**串行**逐个执行。
132
+
133
+ 失败就当场修(参照 ${rules.value},走 _api 模块中转),修完重编,直到全过或确实卡住。
134
+
135
+ 回复正文第一行只写 \`true\` 或 \`false\`,第二行起写清单和详情。`);
136
+
137
+ const buildOkB = control.agentToBool("编译全过了吗(修过一轮)", { value: buildB.result }, `上游正文第一行是 true 或 false。**只回 true 或 false 这一个词**,多一个字都会被判成 false。`);
138
+
139
+ const docB = agent.subAgent("输出迁移文档(修过一轮)", {}, `把这次迁移写成文档:范围、改了什么、主模块改成 API 中转的位置、遗留问题。
140
+
141
+ 范围:${scope.result}
142
+
143
+ 修复记录:${fix1.result}
144
+
145
+ 编译结果:${buildB.result}`);
146
+ const showDocB = display.markdown("迁移文档", { content: docB.result });
147
+ const buildStuckB = display.markdown("编译卡住,需要人工介入", { content: buildB.result });
148
+
149
+ const gateBuildB = control.if("编译过了吗(修过一轮)", { prediction: buildOkB.prediction },
150
+ flow(docB, showDocB),
151
+ flow(buildStuckB),
152
+ );
153
+
154
+ const staticStuck = display.markdown("两轮静态检查仍未通过,需要人工介入", { content: verdictReport2 });
155
+
156
+ const gate2 = control.if("第二轮静态检查", { prediction: verdictOk2 },
157
+ flow(buildB, buildOkB, gateBuildB),
158
+ flow(staticStuck),
159
+ );
160
+
161
+ const gate1 = control.if("第一轮静态检查", { prediction: verdictOk },
162
+ flow(buildA, buildOkA, gateBuildA),
163
+ flow(fix1, staticCheck2, aiCheck2, verdict2, gate2),
164
+ );
165
+
166
+ export const migrateRun = flow(
167
+ "② 建模块并迁移",
168
+ newModule, migrate, staticCheck, aiCheck, verdict, gate1,
169
+ );
170
+
171
+ // 人工闸门:范围确认过了再点②
172
+ flow.resume(showScope, migrateRun);