@fieldwangai/agentflow 0.1.153 → 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 (192) hide show
  1. package/README.md +16 -34
  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 +165 -90
  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 +8 -28
  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 +37 -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 +152 -286
  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 +1087 -18122
  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-routes.mjs +3088 -0
  57. package/bin/lib/workspace-server.mjs +6199 -0
  58. package/bin/lib/workspace-state.mjs +331 -0
  59. package/bin/lib/workspace.mjs +2 -1
  60. package/builtin/nodes/agent_subAgent.md +1 -0
  61. package/builtin/nodes/control_agent_toBool.md +2 -0
  62. package/builtin/nodes/control_anyOne.md +2 -0
  63. package/builtin/nodes/control_cancelled.md +2 -0
  64. package/builtin/nodes/control_cd_workspace.md +5 -11
  65. package/builtin/nodes/control_delay.md +2 -0
  66. package/builtin/nodes/control_end.md +2 -0
  67. package/builtin/nodes/control_if.md +1 -0
  68. package/builtin/nodes/control_interval_loop.md +2 -0
  69. package/builtin/nodes/control_load_mcp.md +24 -0
  70. package/builtin/nodes/control_load_skills.md +8 -23
  71. package/builtin/nodes/control_start.md +2 -0
  72. package/builtin/nodes/control_toBool.md +2 -0
  73. package/builtin/nodes/control_user_workspace.md +2 -0
  74. package/builtin/nodes/control_wait_until.md +2 -0
  75. package/builtin/nodes/display_ascii.md +1 -0
  76. package/builtin/nodes/display_chart.md +1 -0
  77. package/builtin/nodes/display_html.md +1 -0
  78. package/builtin/nodes/display_image.md +1 -0
  79. package/builtin/nodes/display_markdown.md +1 -0
  80. package/builtin/nodes/display_mermaid.md +1 -0
  81. package/builtin/nodes/display_react_app.md +1 -0
  82. package/builtin/nodes/display_table.md +1 -0
  83. package/builtin/nodes/provide_bool.md +1 -0
  84. package/builtin/nodes/provide_file.md +1 -0
  85. package/builtin/nodes/provide_password.md +1 -0
  86. package/builtin/nodes/provide_str.md +1 -0
  87. package/builtin/nodes/tool_display_share_link.md +1 -0
  88. package/builtin/nodes/tool_get_env.md +2 -0
  89. package/builtin/nodes/tool_git_checkout.md +1 -0
  90. package/builtin/nodes/tool_git_worktree_load.md +1 -0
  91. package/builtin/nodes/tool_git_worktree_unload.md +1 -0
  92. package/builtin/nodes/tool_gitlab_create_mr.md +1 -0
  93. package/builtin/nodes/tool_jenkins_build.md +2 -0
  94. package/builtin/nodes/tool_load_key.md +2 -0
  95. package/builtin/nodes/tool_nodejs.md +17 -19
  96. package/builtin/nodes/tool_print.md +2 -0
  97. package/builtin/nodes/tool_save_key.md +2 -0
  98. package/builtin/nodes/tool_set_run_env.md +1 -0
  99. package/builtin/nodes/tool_user_ask.md +2 -0
  100. package/builtin/nodes/tool_user_check.md +2 -0
  101. package/builtin/nodes/tool_wecom_send_app_markdown.md +1 -0
  102. package/builtin/nodes/tool_wecom_send_group_markdown.md +1 -0
  103. package/builtin/nodes/workspace_one_click_task.md +44 -0
  104. package/builtin/nodes/workspace_run.md +16 -0
  105. package/builtin/nodes/workspace_scheduled_run.md +16 -0
  106. package/builtin/pipelines/module-migrate/scripts/gate.mjs +37 -0
  107. package/builtin/pipelines/module-migrate/scripts/static-check.mjs +82 -0
  108. package/builtin/pipelines/module-migrate/workspace.flow.js +172 -0
  109. package/builtin/pipelines/module-migrate/workspace.layout.json +134 -0
  110. package/builtin/pipelines/new/scripts/lint-flow.mjs +38 -0
  111. package/builtin/pipelines/new/workspace.flow.js +91 -0
  112. package/builtin/pipelines/new/workspace.layout.json +70 -0
  113. package/builtin/web-ui/dist/assets/{WorkflowAssistantThread-B9xslwI0.js → WorkflowAssistantThread-CKClwj96.js} +1 -1
  114. package/builtin/web-ui/dist/assets/index-BZ5KqLur.js +870 -0
  115. package/builtin/web-ui/dist/assets/index-CEXmmwM2.css +1 -0
  116. package/builtin/web-ui/dist/index.html +2 -2
  117. package/package.json +2 -1
  118. package/reference/flow-control-capabilities.md +77 -158
  119. package/reference/flow-layout.md +1 -1
  120. package/reference/flow-prompt-handler-check.md +2 -2
  121. package/skills/agentflow-author-flow/SKILL.md +1 -1
  122. package/skills/agentflow-cli/SKILL.md +139 -24
  123. package/skills/agentflow-cli/agents/openai.yaml +2 -2
  124. package/skills/agentflow-cli/scripts/agentflow-cli.mjs +654 -20
  125. package/skills/agentflow-cli/scripts/agentflow-runtime.mjs +97 -0
  126. package/skills/agentflow-flow-add-instances/SKILL.md +1 -1
  127. package/skills/agentflow-flow-dsl/SKILL.md +206 -0
  128. package/skills/agentflow-flow-dsl/agents/openai.yaml +4 -0
  129. package/skills/agentflow-flow-dsl/references/node-calls.md +39 -0
  130. package/skills/agentflow-flow-edit-node-fields/SKILL.md +1 -1
  131. package/skills/agentflow-flow-recipes/SKILL.md +7 -4
  132. package/skills/agentflow-flow-recipes/references/recipes.md +97 -43
  133. package/skills/agentflow-flow-sync-ui/SKILL.md +1 -1
  134. package/skills/agentflow-node-dsl/SKILL.md +212 -0
  135. package/skills/agentflow-node-dsl/agents/openai.yaml +4 -0
  136. package/skills/agentflow-node-reference/SKILL.md +2 -2
  137. package/skills/agentflow-node-reference/references/builtin-nodes.md +166 -115
  138. package/skills/agentflow-runtime-reference/references/runtime.md +1 -1
  139. package/skills/agentflow-workspace-ascii/SKILL.md +9 -16
  140. package/skills/agentflow-workspace-graph/SKILL.md +62 -48
  141. package/skills/agentflow-workspace-html/SKILL.md +7 -2
  142. package/skills/agentflow-workspace-image/SKILL.md +6 -2
  143. package/skills/agentflow-workspace-markdown/SKILL.md +14 -21
  144. package/skills/agentflow-workspace-mermaid/SKILL.md +8 -16
  145. package/bin/lib/api-runner.mjs +0 -387
  146. package/bin/lib/apply.mjs +0 -903
  147. package/bin/lib/composer-flow-instances.mjs +0 -68
  148. package/bin/lib/composer-flow-skeleton.mjs +0 -334
  149. package/bin/lib/composer-flow-validate.mjs +0 -47
  150. package/bin/lib/composer-model-router.mjs +0 -185
  151. package/bin/lib/composer-node-schema.mjs +0 -303
  152. package/bin/lib/composer-planner.mjs +0 -751
  153. package/bin/lib/composer-script-ops.mjs +0 -233
  154. package/bin/lib/flow-static-preview.mjs +0 -104
  155. package/bin/lib/hub-login.mjs +0 -54
  156. package/bin/lib/hub-publish.mjs +0 -159
  157. package/bin/lib/hub-remote.mjs +0 -189
  158. package/bin/lib/hub.mjs +0 -299
  159. package/bin/lib/jenkins.mjs +0 -380
  160. package/bin/lib/node-execute.mjs +0 -539
  161. package/bin/lib/normalize-node-tool-command.mjs +0 -97
  162. package/bin/lib/runtime-context.mjs +0 -243
  163. package/bin/lib/scheduler.mjs +0 -601
  164. package/bin/lib/ui-print.mjs +0 -94
  165. package/bin/pipeline/build-node-prompt.mjs +0 -271
  166. package/bin/pipeline/check-cache.mjs +0 -191
  167. package/bin/pipeline/check-flow.mjs +0 -543
  168. package/bin/pipeline/collect-nodes.mjs +0 -212
  169. package/bin/pipeline/compute-cache-md5.mjs +0 -177
  170. package/bin/pipeline/ensure-run-dir.mjs +0 -71
  171. package/bin/pipeline/gc.mjs +0 -129
  172. package/bin/pipeline/get-env.mjs +0 -59
  173. package/bin/pipeline/get-resolved-values.mjs +0 -344
  174. package/bin/pipeline/load-key.mjs +0 -62
  175. package/bin/pipeline/parse-flow.mjs +0 -708
  176. package/bin/pipeline/post-process-control-if.mjs +0 -23
  177. package/bin/pipeline/post-process-node.mjs +0 -490
  178. package/bin/pipeline/pre-process-node.mjs +0 -1430
  179. package/bin/pipeline/resolve-inputs.mjs +0 -201
  180. package/bin/pipeline/run-tool-nodejs.mjs +0 -167
  181. package/bin/pipeline/save-key.mjs +0 -93
  182. package/bin/pipeline/snapshot-prior-round.mjs +0 -70
  183. package/bin/pipeline/validate-for-ui.mjs +0 -234
  184. package/bin/pipeline/validate-script-output.mjs +0 -130
  185. package/bin/pipeline/write-result.mjs +0 -182
  186. package/builtin/pipelines/module-migrate/flow.yaml +0 -819
  187. package/builtin/pipelines/new/flow.yaml +0 -545
  188. package/builtin/pipelines/new/scripts/check-flow.mjs +0 -9
  189. package/builtin/pipelines/new/scripts/collect-nodes.mjs +0 -211
  190. package/builtin/web-ui/dist/assets/index-DZ328oSo.css +0 -1
  191. package/builtin/web-ui/dist/assets/index-DmUV7ZCL.js +0 -888
  192. package/skills/agentflow-node-authoring/SKILL.md +0 -57
@@ -1,201 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * 按 flow 结构 + 中间文件为单个 instance 计算 resolvedInputs(不注入常量;上游 output 路径已带对应 input handler 的 execId)。
4
- * 供 get-resolved-values 等用时现算,不依赖 flow.json 中的 resolvedInputs。
5
- * 约定:上游节点的 output 槽路径使用该前驱的 latestResultExecId,即 output/<predId>/node_<predId>_<execId>_<slot>.md。
6
- * 用法(模块):import { computeResolvedInputsForInstance } from "./resolve-inputs.mjs";
7
- * @returns {{ ok: true, resolvedInputs: object }} 或 {{ ok: false, error: string }}
8
- */
9
-
10
- import fs from "fs";
11
- import path from "path";
12
-
13
- import { getRunDir, PIPELINES_DIR } from "../lib/paths.mjs";
14
- import { getFlowDir } from "../lib/workspace.mjs";
15
- import {
16
- loadAllExecIds,
17
- latestResultExecId,
18
- intermediateResultBasename,
19
- outputDirForNode,
20
- outputNodeBasename,
21
- } from "./get-exec-id.mjs";
22
- import {
23
- loadFlowDefinition,
24
- parseResultOutputPath,
25
- instanceEntryToSlots,
26
- parseInstanceSlots,
27
- readInstanceContent,
28
- extractPlaceholders,
29
- } from "./parse-flow.mjs";
30
-
31
- /**
32
- * 为指定 instanceId 计算 resolvedInputs(与 parse-flow resolvePlaceholders 单实例逻辑一致)。
33
- */
34
- export function computeResolvedInputsForInstance(workspaceRoot, flowName, uuid, instanceId) {
35
- const root = path.resolve(workspaceRoot);
36
- const runDir = getRunDir(workspaceRoot, flowName, uuid);
37
- const flowJsonPath = path.join(runDir, "intermediate", "flow.json");
38
- const intermediateDir = path.join(runDir, "intermediate");
39
-
40
- if (!fs.existsSync(flowJsonPath)) {
41
- return { ok: false, error: `flow.json not found: ${flowJsonPath}. Run parse-flow.mjs first.` };
42
- }
43
-
44
- let flow;
45
- try {
46
- flow = JSON.parse(fs.readFileSync(flowJsonPath, "utf-8"));
47
- } catch (e) {
48
- return { ok: false, error: e.message || "Invalid flow.json" };
49
- }
50
- if (!flow.ok) {
51
- return { ok: false, error: flow.error || "flow.json indicates error" };
52
- }
53
-
54
- let flowDir = getFlowDir(root, flowName) || path.join(root, PIPELINES_DIR, flowName);
55
- if (flow.flowDir && typeof flow.flowDir === "string" && flow.flowDir.trim()) {
56
- flowDir = path.isAbsolute(flow.flowDir) ? flow.flowDir : path.join(root, flow.flowDir);
57
- }
58
- const instanceDir = path.join(flowDir, "instance");
59
-
60
- const order = flow.order || [];
61
- const edges = flow.edges || [];
62
- if (!order.length) {
63
- return { ok: false, error: "flow.json missing order" };
64
- }
65
-
66
- if (!order.includes(instanceId)) {
67
- return { ok: false, error: `instanceId ${instanceId} not in flow order` };
68
- }
69
-
70
- const flowData = loadFlowDefinition(flowDir);
71
- const instances = flowData?.instances && typeof flowData.instances === "object" ? flowData.instances : {};
72
- const useYaml = Object.keys(instances).length > 0;
73
-
74
- let execIds = {};
75
- if (fs.existsSync(intermediateDir)) {
76
- try {
77
- execIds = loadAllExecIds(workspaceRoot, flowName, uuid, order);
78
- } catch (_) {}
79
- }
80
-
81
- /** 入边:target -> [{ source, sourceHandle, targetHandle }] */
82
- const predecessors = new Map();
83
- for (const e of edges) {
84
- if (!e.target) continue;
85
- if (!predecessors.has(e.target)) predecessors.set(e.target, []);
86
- predecessors.get(e.target).push({
87
- source: e.source,
88
- sourceHandle: e.sourceHandle || "output-0",
89
- targetHandle: e.targetHandle,
90
- });
91
- }
92
-
93
- const getSlotsFor = (id) => {
94
- if (useYaml && instances[id]) return instanceEntryToSlots(instances[id]);
95
- const instPath = path.join(instanceDir, `${id}.md`);
96
- return fs.existsSync(instPath) ? parseInstanceSlots(instPath) : instanceEntryToSlots(null);
97
- };
98
-
99
- const getContentFor = (id) => {
100
- if (useYaml && instances[id] && instances[id].body != null) return String(instances[id].body || "").trim();
101
- return readInstanceContent(path.join(instanceDir, `${id}.md`));
102
- };
103
-
104
- const getNodeOutput = (id, sourceHandle) => {
105
- const slots = getSlotsFor(id);
106
- const outValues = Object.values(slots.output || {});
107
- if (sourceHandle && /^output-(\d+)$/.test(sourceHandle)) {
108
- const idx = parseInt(sourceHandle.replace("output-", ""), 10);
109
- if (idx >= 0 && idx < outValues.length) return outValues[idx] ?? null;
110
- }
111
- return outValues[0] ?? null;
112
- };
113
-
114
- const getNodeOutputFromResult = (id) => {
115
- const latestE = latestResultExecId(execIds[id] ?? 1);
116
- if (!latestE) return null;
117
- const resultPath = path.join(intermediateDir, id, intermediateResultBasename(id, latestE));
118
- return parseResultOutputPath(resultPath);
119
- };
120
-
121
- const resolvedInputs = {};
122
- const slots = getSlotsFor(instanceId);
123
- const { inputs: inputRefs } = extractPlaceholders(getContentFor(instanceId));
124
- const preds = predecessors.get(instanceId) || [];
125
- const inputSlotNames = Object.keys(slots.input || {});
126
-
127
- for (let i = 0; i < inputSlotNames.length; i++) {
128
- const slotName = inputSlotNames[i];
129
- const targetHandle = `input-${i}`;
130
- const pred = preds.find((p) => p.targetHandle === targetHandle);
131
- if (!pred) continue;
132
-
133
- const fromResult = getNodeOutputFromResult(pred.source);
134
- const fromInstance = getNodeOutput(pred.source, pred.sourceHandle);
135
- let value = fromResult ?? fromInstance;
136
-
137
- if (pred.sourceHandle && /^output-(\d+)$/.test(pred.sourceHandle)) {
138
- const sourceSlots = getSlotsFor(pred.source);
139
- const outSlotNames = Object.keys(sourceSlots.output || {});
140
- if (outSlotNames.length > 0) {
141
- const idx = parseInt(pred.sourceHandle.replace("output-", ""), 10);
142
- if (idx >= 0 && idx < outSlotNames.length) {
143
- const predExecId = latestResultExecId(execIds[pred.source] ?? 1);
144
- const slotPath = `${outputDirForNode(pred.source)}/${outputNodeBasename(pred.source, predExecId, outSlotNames[idx])}`;
145
- if (!value || value === "" || outSlotNames.length > 1) {
146
- value = slotPath;
147
- }
148
- }
149
- }
150
- }
151
-
152
- if (value != null) {
153
- const slotType = (slots.inputTypes && slots.inputTypes[slotName]) || null;
154
- if (slotType === "节点" || slotType === "node") {
155
- value = pred.source;
156
- }
157
- resolvedInputs[slotName] = value;
158
- }
159
- }
160
-
161
- for (const slotName of inputSlotNames) {
162
- if (resolvedInputs[slotName] != null) continue;
163
- const defaultVal = slots.input && slots.input[slotName];
164
- if (defaultVal !== undefined && defaultVal !== "") {
165
- resolvedInputs[slotName] = defaultVal;
166
- }
167
- }
168
-
169
- // --input 覆盖:仅当对应上游是 provide_ 节点,且用户传了该 slotName 的值时生效。
170
- // parse-flow 初始阶段也会写入 flow.json 的 cliInputsApplied,但此处在运行时重算 resolvedInputs,
171
- // 必须在同一处再打一次 patch,否则 override 会丢失(provide 节点原 default 值会覆盖用户输入)。
172
- if (flow.cliInputsApplied && typeof flow.cliInputsApplied === "object") {
173
- for (let i = 0; i < inputSlotNames.length; i++) {
174
- const slotName = inputSlotNames[i];
175
- const cliVal = flow.cliInputsApplied[slotName];
176
- if (!cliVal || typeof cliVal !== "object") continue;
177
- const pred = preds.find((p) => p.targetHandle === `input-${i}`);
178
- if (!pred?.source) continue;
179
- const sourceInst = instances[pred.source];
180
- if (!sourceInst?.definitionId?.startsWith?.("provide_")) continue;
181
- const overrideValue = cliVal.type === "file" ? cliVal.path : cliVal.value;
182
- if (overrideValue == null) continue;
183
- resolvedInputs[slotName] = overrideValue;
184
- }
185
- }
186
-
187
- if (inputRefs.length > 0 && preds.length > 0 && !Object.keys(resolvedInputs).length) {
188
- const pred = preds[0];
189
- const fromResult = getNodeOutputFromResult(pred.source);
190
- const fromInstance = getNodeOutput(pred.source, pred.sourceHandle);
191
- let v = fromResult ?? fromInstance;
192
- if (v != null) {
193
- const firstSlotName = inputSlotNames[0];
194
- const firstType = (slots.inputTypes && slots.inputTypes[firstSlotName]) || null;
195
- if (firstType === "节点" || firstType === "node") v = pred.source;
196
- return { ok: true, resolvedInputs: { _: v } };
197
- }
198
- }
199
-
200
- return { ok: true, resolvedInputs };
201
- }
@@ -1,167 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * 运行 tool_nodejs 脚本并将结果写入流水线。
4
- *
5
- * 成败判定(Unix 哲学):
6
- * - 进程 exit code 0 → success,非 0 → failed
7
- * - 若 stdout 为合法 JSON 且含 err_code,err_code 优先(向后兼容旧脚本)
8
- *
9
- * stdout 内容 → result 槽位:
10
- * - JSON 模式:提取 message.result
11
- * - 纯文本模式:整段 stdout 作为 result
12
- *
13
- * 用法:node run-tool-nodejs.mjs <workspaceRoot> <flowName> <uuid> <instanceId> [execId] -- <scriptCmd> [args...]
14
- */
15
-
16
- import { spawnSync } from "child_process";
17
- import fs from "fs";
18
- import path from "path";
19
- import { fileURLToPath } from "url";
20
-
21
- import { getRunDir } from "../lib/paths.mjs";
22
- import { readMergedEnvObject } from "../lib/user-env.mjs";
23
- import { validateAndParse } from "./validate-script-output.mjs";
24
- import { writeResult } from "./write-result.mjs";
25
- import { loadExecId, outputNodeBasename, outputDirForNode } from "./get-exec-id.mjs";
26
- import { nodeToolCommandToArgv } from "../lib/normalize-node-tool-command.mjs";
27
- import { buildPipelineScriptPathHint } from "../lib/flow-normalize.mjs";
28
-
29
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
30
- const MAX_RETRIES = 3;
31
- const RETRY_DELAY_MS = 1000;
32
-
33
- function runtimeEnv() {
34
- return { ...process.env, ...readMergedEnvObject(process.env.AGENTFLOW_USER_ID || "") };
35
- }
36
-
37
- function runOnce(workspaceRoot, flowName, uuid, instanceId, execId, scriptArgs) {
38
- const runDir = getRunDir(workspaceRoot, flowName, uuid);
39
- const outputDir = path.join(runDir, outputDirForNode(instanceId));
40
-
41
- const rawLine = scriptArgs.join(" ");
42
- const { argv, commandLine: normalizedCmd } = nodeToolCommandToArgv(rawLine);
43
- const child =
44
- /^node\s/i.test(String(normalizedCmd).trim()) && argv.length >= 1
45
- ? spawnSync(process.execPath, argv, {
46
- cwd: workspaceRoot,
47
- shell: false,
48
- stdio: ["inherit", "pipe", "pipe"],
49
- env: runtimeEnv(),
50
- })
51
- : spawnSync(normalizedCmd, [], {
52
- cwd: workspaceRoot,
53
- shell: true,
54
- stdio: ["inherit", "pipe", "pipe"],
55
- env: runtimeEnv(),
56
- });
57
-
58
- const stdout = child.stdout?.toString("utf-8") ?? "";
59
- const stderr = child.stderr?.toString("utf-8") ?? "";
60
- const exitCode = child.status ?? 1;
61
-
62
- if (child.signal) {
63
- persistStderr(outputDir, instanceId, execId, stderr);
64
- return { success: false, fatal: true, detail: `Script killed: ${child.signal}` };
65
- }
66
-
67
- const { ok, errors, payload } = validateAndParse(stdout);
68
-
69
- if (!ok) {
70
- const baseDetail = exitCode !== 0
71
- ? `脚本退出码 ${exitCode}` + (stderr.trim() ? `:${stderr.trim().slice(0, 200)}` : "")
72
- : (errors.length ? errors.join("; ") : "脚本无输出");
73
- const detail = baseDetail + buildPipelineScriptPathHint(stderr);
74
- writeResult(workspaceRoot, flowName, uuid, instanceId, {
75
- status: "failed",
76
- message: detail,
77
- }, { preserveBody: true, execId });
78
- persistStderr(outputDir, instanceId, execId, stderr);
79
- return { success: false, fatal: false, detail };
80
- }
81
-
82
- const isSynthetic = Boolean(payload._synthetic);
83
- const success = isSynthetic ? exitCode === 0 : (payload.err_code === 0);
84
- const message = payload.message;
85
-
86
- try {
87
- fs.mkdirSync(outputDir, { recursive: true });
88
- // 备份由 snapshotPriorRoundIfNeeded 在 pre-process 入口统一处理。
89
- for (const slot of Object.keys(message)) {
90
- if (slot === "_synthetic") continue;
91
- const content = message[slot];
92
- if (content == null) continue;
93
- fs.writeFileSync(
94
- path.join(outputDir, outputNodeBasename(instanceId, execId, slot)),
95
- String(content),
96
- "utf-8",
97
- );
98
- }
99
- writeResult(workspaceRoot, flowName, uuid, instanceId, {
100
- status: success ? "success" : "failed",
101
- message: success ? "执行完成" : "执行未通过",
102
- }, { preserveBody: true, execId });
103
- } catch (e) {
104
- writeResult(workspaceRoot, flowName, uuid, instanceId, {
105
- status: "failed",
106
- message: e.message || "写入 output/result 异常",
107
- }, { preserveBody: true, execId });
108
- persistStderr(outputDir, instanceId, execId, stderr);
109
- return { success: false, fatal: false, detail: e.message };
110
- }
111
-
112
- persistStderr(outputDir, instanceId, execId, stderr);
113
- return { success, fatal: false, detail: success ? "" : `脚本退出码 ${exitCode}` };
114
- }
115
-
116
- function persistStderr(outputDir, instanceId, execId, stderr) {
117
- if (!stderr) return;
118
- try {
119
- fs.mkdirSync(outputDir, { recursive: true });
120
- fs.writeFileSync(
121
- path.join(outputDir, outputNodeBasename(instanceId, execId, "stderr")),
122
- stderr,
123
- "utf-8",
124
- );
125
- } catch (_) {}
126
- }
127
-
128
- function main() {
129
- const args = process.argv.slice(2);
130
- const sep = args.indexOf("--");
131
- if (sep < 0 || args.length < sep + 2) {
132
- console.error(
133
- "Usage: node run-tool-nodejs.mjs <workspaceRoot> <flowName> <uuid> <instanceId> [execId] -- <scriptCmd> [args...]",
134
- );
135
- process.exit(2);
136
- }
137
-
138
- const workspaceRoot = path.resolve(args[0]);
139
- const flowName = args[1];
140
- const uuid = args[2];
141
- const instanceId = args[3];
142
- const execId =
143
- sep >= 5 && args[4] !== "--"
144
- ? (parseInt(String(args[4]), 10) || 1)
145
- : loadExecId(workspaceRoot, flowName, uuid, instanceId);
146
- const scriptArgs = args.slice(sep + 1);
147
-
148
- for (let attempt = 1; attempt <= MAX_RETRIES + 1; attempt++) {
149
- const result = runOnce(workspaceRoot, flowName, uuid, instanceId, execId, scriptArgs);
150
- if (result.success) {
151
- process.exit(0);
152
- }
153
- if (result.fatal) {
154
- console.error(result.detail);
155
- process.exit(1);
156
- }
157
- if (attempt <= MAX_RETRIES) {
158
- console.error(`[tool_nodejs 自愈] ${instanceId} 第 ${attempt}/${MAX_RETRIES} 次重试:${result.detail?.slice(0, 200) || "unknown"}`);
159
- spawnSync("sleep", [String(RETRY_DELAY_MS / 1000)], { stdio: "ignore" });
160
- } else {
161
- console.error(result.detail);
162
- process.exit(1);
163
- }
164
- }
165
- }
166
-
167
- main();
@@ -1,93 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * tool_save_key 执行脚本:按 key 将 value 写入 run 目录下 memory 存储,stdout 输出 tool_nodejs 约定 JSON。
4
- * 存储路径与格式由本脚本内部实现,节点不感知。key/value 由命令行参数传入,不读 flow。
5
- * value 若为 run 目录内相对路径则读取文件内容后写入。
6
- * 用法:node save-key.mjs <workspaceRoot> <flowName> <uuid> <key> [value]
7
- * 输出(stdout 一行 JSON):成功时 result 为写入的 value;err_code 0=成功 1=失败,无 next。
8
- */
9
-
10
- import fs from "fs";
11
- import path from "path";
12
-
13
- import { getRunDir } from "../lib/paths.mjs";
14
-
15
- const MEMORY_FILENAME = "memory.md";
16
-
17
- function parseMemory(content) {
18
- const map = new Map();
19
- for (const line of (content || "").split(/\r?\n/)) {
20
- const idx = line.indexOf(": ");
21
- if (idx <= 0) continue;
22
- const k = line.slice(0, idx).trim();
23
- const v = line.slice(idx + 2).trim();
24
- if (k) map.set(k, v);
25
- }
26
- return map;
27
- }
28
-
29
- function serializeMemory(map) {
30
- return (
31
- Array.from(map.entries())
32
- .map(([k, v]) => `${k}: ${String(v).replace(/\r?\n/g, " ")}`)
33
- .join("\n") + (map.size ? "\n" : "")
34
- );
35
- }
36
-
37
- function main() {
38
- const [root, flowName, uuid, keyArg, valueArg] = process.argv.slice(2);
39
- if (!root || !flowName || !uuid) {
40
- console.log(
41
- JSON.stringify({
42
- err_code: 1,
43
- message: { result: "" },
44
- }),
45
- );
46
- process.exit(0);
47
- }
48
-
49
- const key = keyArg != null ? String(keyArg).trim() : "";
50
- let value = valueArg != null ? String(valueArg).trim() : "";
51
-
52
- const workspaceRoot = path.resolve(root);
53
- const runDir = getRunDir(workspaceRoot, flowName, uuid);
54
- const memoryPath = path.join(runDir, MEMORY_FILENAME);
55
-
56
- if (!key) {
57
- console.log(
58
- JSON.stringify({
59
- err_code: 0,
60
- message: { result: "" },
61
- }),
62
- );
63
- process.exit(0);
64
- }
65
-
66
- if (
67
- value &&
68
- (value.includes("/") || value.startsWith("output") || value.startsWith("intermediate"))
69
- ) {
70
- const valuePath = path.join(runDir, value);
71
- if (fs.existsSync(valuePath)) {
72
- try {
73
- value = fs.readFileSync(valuePath, "utf-8").trim();
74
- } catch (_) {}
75
- }
76
- }
77
-
78
- const existing = fs.existsSync(memoryPath)
79
- ? parseMemory(fs.readFileSync(memoryPath, "utf-8"))
80
- : new Map();
81
- existing.set(key, value);
82
- fs.mkdirSync(path.dirname(memoryPath), { recursive: true });
83
- fs.writeFileSync(memoryPath, serializeMemory(existing), "utf-8");
84
-
85
- console.log(
86
- JSON.stringify({
87
- err_code: 0,
88
- message: { result: value },
89
- }),
90
- );
91
- }
92
-
93
- main();
@@ -1,70 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * 节点每轮执行进入 pre-process 时,统一把「上一轮遗留的当前文件」快照到
4
- * <name>_<priorExecId>.<ext>
5
- * 形式。这是唯一的备份入口,替代分散在 write-result / build-node-prompt /
6
- * pre-process 内多种辅助 prompt / get-env / run-tool-nodejs 中的 rename 调用。
7
- *
8
- * 不变量:
9
- * 1. 文件后缀 `_K` 严格对应「第 K 轮结束时的文件内容」,无错位。
10
- * 2. unsuffixed(无 `_N` 后缀)= 当前最新版本,永远存在;snapshot 用 copy
11
- * 生成 `_K` 历史快照,不破坏 unsuffixed。下游运行时只 resolve unsuffixed,
12
- * 不应也不需要 fallback 到 `_K`。
13
- * 3. 幂等:目标 `_K.ext` 已存在或源文件已经是 `_K.ext` 形态,直接跳过。
14
- *
15
- * 调用方:bin/pipeline/pre-process-node.mjs 在计算 execId 后、任何 write 前。
16
- */
17
- import fs from "fs";
18
- import path from "path";
19
-
20
- import { intermediateDirForNode, outputDirForNode } from "./get-exec-id.mjs";
21
-
22
- const BACKUP_SUFFIX_RE = /_\d+$/;
23
-
24
- /**
25
- * @param {string} runDir - .workspace/agentflow/runBuild/<flowName>/<uuid>
26
- * @param {string} instanceId
27
- * @param {number} priorExecId - memory 里记录的「上一轮已完成 execId」,首轮传 0/undefined 直接返回
28
- */
29
- export function snapshotPriorRoundIfNeeded(runDir, instanceId, priorExecId) {
30
- const prior = Number(priorExecId);
31
- if (!Number.isFinite(prior) || prior < 1) return;
32
- const suffix = `_${prior}`;
33
-
34
- const interDir = path.join(runDir, intermediateDirForNode(instanceId));
35
- snapshotDir(interDir, (f) => f.startsWith(instanceId + "."), suffix);
36
-
37
- const outDir = path.join(runDir, outputDirForNode(instanceId));
38
- snapshotDir(outDir, (f) => f.startsWith(`node_${instanceId}_`), suffix);
39
- }
40
-
41
- /**
42
- * @param {string} dir
43
- * @param {(filename: string) => boolean} predicate
44
- * @param {string} suffix - `_<N>`
45
- */
46
- function snapshotDir(dir, predicate, suffix) {
47
- if (!fs.existsSync(dir)) return;
48
- let files;
49
- try {
50
- files = fs.readdirSync(dir);
51
- } catch {
52
- return;
53
- }
54
- for (const f of files) {
55
- if (!predicate(f)) continue;
56
- const ext = path.extname(f);
57
- const base = path.basename(f, ext);
58
- // 已是备份文件(以 _\d+ 结尾),跳过
59
- if (BACKUP_SUFFIX_RE.test(base)) continue;
60
- const to = base + suffix + ext;
61
- if (to === f) continue;
62
- const toPath = path.join(dir, to);
63
- if (fs.existsSync(toPath)) continue; // 幂等
64
- try {
65
- fs.copyFileSync(path.join(dir, f), toPath);
66
- } catch {
67
- // 并发或权限错误:放弃该文件,其它继续。unsuffixed 保留不动。
68
- }
69
- }
70
- }