@fieldwangai/agentflow 0.1.25

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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/README.zh-CN.md +201 -0
  4. package/agents/agentflow-node-executor-code.md +32 -0
  5. package/agents/agentflow-node-executor-planning.md +32 -0
  6. package/agents/agentflow-node-executor-requirement.md +32 -0
  7. package/agents/agentflow-node-executor-test.md +32 -0
  8. package/agents/agentflow-node-executor-ui.md +32 -0
  9. package/agents/agentflow-node-executor.md +32 -0
  10. package/agents/agents.json +8 -0
  11. package/agents/en/agentflow-node-executor.md +32 -0
  12. package/agents/zh/agentflow-node-executor.md +32 -0
  13. package/bin/agentflow.mjs +52 -0
  14. package/bin/ensure-workspace-reference.mjs +35 -0
  15. package/bin/lib/agent-runners.mjs +1199 -0
  16. package/bin/lib/agents-path.mjs +61 -0
  17. package/bin/lib/api-runner.mjs +361 -0
  18. package/bin/lib/apply.mjs +852 -0
  19. package/bin/lib/catalog-agents.mjs +300 -0
  20. package/bin/lib/catalog-flows.mjs +532 -0
  21. package/bin/lib/composer-agent.mjs +884 -0
  22. package/bin/lib/composer-flow-instances.mjs +68 -0
  23. package/bin/lib/composer-flow-skeleton.mjs +334 -0
  24. package/bin/lib/composer-flow-validate.mjs +47 -0
  25. package/bin/lib/composer-log.mjs +197 -0
  26. package/bin/lib/composer-model-router.mjs +160 -0
  27. package/bin/lib/composer-node-schema.mjs +299 -0
  28. package/bin/lib/composer-planner.mjs +749 -0
  29. package/bin/lib/composer-script-ops.mjs +233 -0
  30. package/bin/lib/composer-skill-router.mjs +384 -0
  31. package/bin/lib/flow-import.mjs +305 -0
  32. package/bin/lib/flow-normalize.mjs +71 -0
  33. package/bin/lib/flow-write.mjs +395 -0
  34. package/bin/lib/help.mjs +139 -0
  35. package/bin/lib/hub-login.mjs +54 -0
  36. package/bin/lib/hub-publish.mjs +159 -0
  37. package/bin/lib/hub-remote.mjs +189 -0
  38. package/bin/lib/hub.mjs +299 -0
  39. package/bin/lib/i18n.mjs +233 -0
  40. package/bin/lib/locales/en.json +344 -0
  41. package/bin/lib/locales/zh.json +344 -0
  42. package/bin/lib/log.mjs +37 -0
  43. package/bin/lib/main.mjs +611 -0
  44. package/bin/lib/model-config.mjs +118 -0
  45. package/bin/lib/model-lists.mjs +188 -0
  46. package/bin/lib/node-exec-context.mjs +336 -0
  47. package/bin/lib/node-execute.mjs +513 -0
  48. package/bin/lib/normalize-node-tool-command.mjs +97 -0
  49. package/bin/lib/paths.mjs +216 -0
  50. package/bin/lib/pipeline-scripts.mjs +41 -0
  51. package/bin/lib/recent-runs.mjs +173 -0
  52. package/bin/lib/run-apply-active-lock.mjs +82 -0
  53. package/bin/lib/run-events.mjs +85 -0
  54. package/bin/lib/run-node-statuses-from-disk.mjs +85 -0
  55. package/bin/lib/schedule-config.mjs +227 -0
  56. package/bin/lib/scheduler.mjs +312 -0
  57. package/bin/lib/table.mjs +4 -0
  58. package/bin/lib/terminal.mjs +42 -0
  59. package/bin/lib/ui-print.mjs +94 -0
  60. package/bin/lib/ui-server.mjs +2113 -0
  61. package/bin/lib/workspace-tree.mjs +266 -0
  62. package/bin/lib/workspace.mjs +180 -0
  63. package/bin/pipeline/build-node-prompt.mjs +179 -0
  64. package/bin/pipeline/check-cache.mjs +191 -0
  65. package/bin/pipeline/check-flow.mjs +543 -0
  66. package/bin/pipeline/collect-nodes.mjs +212 -0
  67. package/bin/pipeline/compute-cache-md5.mjs +177 -0
  68. package/bin/pipeline/ensure-run-dir.mjs +71 -0
  69. package/bin/pipeline/extract-thinking.mjs +308 -0
  70. package/bin/pipeline/gc.mjs +129 -0
  71. package/bin/pipeline/get-env.mjs +83 -0
  72. package/bin/pipeline/get-exec-id.mjs +145 -0
  73. package/bin/pipeline/get-ready-nodes.mjs +435 -0
  74. package/bin/pipeline/get-resolved-values.mjs +337 -0
  75. package/bin/pipeline/load-key.mjs +62 -0
  76. package/bin/pipeline/parse-bool.mjs +33 -0
  77. package/bin/pipeline/parse-flow.mjs +698 -0
  78. package/bin/pipeline/post-process-control-if.mjs +23 -0
  79. package/bin/pipeline/post-process-node.mjs +490 -0
  80. package/bin/pipeline/pre-process-node.mjs +449 -0
  81. package/bin/pipeline/resolve-inputs.mjs +201 -0
  82. package/bin/pipeline/run-log.mjs +34 -0
  83. package/bin/pipeline/run-tool-nodejs.mjs +160 -0
  84. package/bin/pipeline/save-key.mjs +93 -0
  85. package/bin/pipeline/snapshot-prior-round.mjs +70 -0
  86. package/bin/pipeline/validate-flow.mjs +825 -0
  87. package/bin/pipeline/validate-for-ui.mjs +226 -0
  88. package/bin/pipeline/validate-script-output.mjs +130 -0
  89. package/bin/pipeline/write-result.mjs +182 -0
  90. package/builtin/nodes/agent_subAgent.md +14 -0
  91. package/builtin/nodes/control_agent_toBool.md +20 -0
  92. package/builtin/nodes/control_anyOne.md +17 -0
  93. package/builtin/nodes/control_end.md +11 -0
  94. package/builtin/nodes/control_if.md +20 -0
  95. package/builtin/nodes/control_start.md +11 -0
  96. package/builtin/nodes/control_toBool.md +21 -0
  97. package/builtin/nodes/provide_file.md +11 -0
  98. package/builtin/nodes/provide_str.md +11 -0
  99. package/builtin/nodes/tool_get_env.md +14 -0
  100. package/builtin/nodes/tool_load_key.md +20 -0
  101. package/builtin/nodes/tool_nodejs.md +40 -0
  102. package/builtin/nodes/tool_print.md +14 -0
  103. package/builtin/nodes/tool_save_key.md +20 -0
  104. package/builtin/nodes/tool_user_ask.md +23 -0
  105. package/builtin/nodes/tool_user_check.md +22 -0
  106. package/builtin/pipelines/module-migrate/flow.yaml +819 -0
  107. package/builtin/pipelines/module-migrate/scripts/check_imports.mjs +700 -0
  108. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Makefile +362 -0
  109. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/node_modules/node-addon-api/node_addon_api_except.stamp.d +1 -0
  110. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/tree_sitter_kotlin_binding/bindings/node/binding.o.d +17 -0
  111. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/tree_sitter_kotlin_binding/src/parser.o.d +5 -0
  112. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/obj.target/tree_sitter_kotlin_binding/src/scanner.o.d +8 -0
  113. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/.deps/Release/tree_sitter_kotlin_binding.node.d +1 -0
  114. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  115. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/tree_sitter_kotlin_binding/bindings/node/binding.o +0 -0
  116. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/tree_sitter_kotlin_binding/src/parser.o +0 -0
  117. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/obj.target/tree_sitter_kotlin_binding/src/scanner.o +0 -0
  118. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/Release/tree_sitter_kotlin_binding.node +0 -0
  119. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/binding.Makefile +6 -0
  120. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/gyp-mac-tool +768 -0
  121. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api.Makefile +6 -0
  122. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api.target.mk +122 -0
  123. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api_except.target.mk +126 -0
  124. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/node_modules/node-addon-api/node_addon_api_maybe.target.mk +122 -0
  125. package/builtin/pipelines/module-migrate/scripts/node_modules/tree-sitter-kotlin/build/tree_sitter_kotlin_binding.target.mk +203 -0
  126. package/builtin/pipelines/new/flow.yaml +545 -0
  127. package/builtin/pipelines/new/scripts/check-flow.mjs +9 -0
  128. package/builtin/pipelines/new/scripts/collect-nodes.mjs +211 -0
  129. package/builtin/pipelines/scripts/adjust-node-positions.mjs +113 -0
  130. package/builtin/web-ui/dist/agentflow-icon.svg +23 -0
  131. package/builtin/web-ui/dist/assets/index-CZkUPcXE.css +1 -0
  132. package/builtin/web-ui/dist/assets/index-DkkhNESc.js +190 -0
  133. package/builtin/web-ui/dist/index.html +24 -0
  134. package/package.json +67 -0
  135. package/reference/flow-control-capabilities.md +274 -0
  136. package/reference/flow-layout.md +84 -0
  137. package/reference/flow-prompt-handler-check.md +12 -0
  138. package/reference/flow-result-semantics.md +14 -0
@@ -0,0 +1,211 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 收集所有节点(内置 + 当前流水线)的元数据,按 tool_nodejs 约定向 stdout 输出一行 JSON。
4
+ * 用法:agentflow apply -ai collect-nodes <workspaceRoot> <flowName> [runDir]
5
+ * 输出(仅 stdout 一行):{ "err_code": 0, "message": { "result": "<节点元数据 markdown>" } };err_code 0=成功 1=失败,无 next。
6
+ * 不写任何文件,由 agentflow apply -ai run-tool-nodejs 根据 message 写入 output。
7
+ */
8
+
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import { fileURLToPath } from "url";
12
+ import yaml from "js-yaml";
13
+ import { LEGACY_NODES_DIR, PIPELINES_DIR, PROJECT_NODES_DIR } from "../../../../bin/lib/paths.mjs";
14
+ import { getFlowDir } from "../../../../bin/lib/workspace.mjs";
15
+
16
+ const __dirnameScript = path.dirname(fileURLToPath(import.meta.url));
17
+ const PACKAGE_BUILTIN_NODES_DIR = path.join(path.resolve(__dirnameScript, "..", "..", ".."), "nodes");
18
+
19
+ function extractFrontmatter(raw) {
20
+ const m = raw.match(/^---\s*\n([\s\S]*?)\n---/);
21
+ return m ? m[1] : "";
22
+ }
23
+
24
+ function parseDescription(fm) {
25
+ const match = fm.match(/\bdescription:\s*["']?([^"'\n#][^\n]*)["']?/);
26
+ return match ? match[1].trim().replace(/^["']|["']$/g, "") : "";
27
+ }
28
+
29
+ function parseDisplayName(fm) {
30
+ const match = fm.match(/\bdisplayName:\s*["']?([^"'\n#][^\n]*)["']?/);
31
+ return match ? match[1].trim().replace(/^["']|["']$/g, "") : "";
32
+ }
33
+
34
+ /** 解析 frontmatter 中的 input/output 数组,返回 [{ type, name, defaultOrValue }, ...] */
35
+ function parseSlots(fm, key) {
36
+ const slots = [];
37
+ const re = new RegExp(`\\b${key}:\\s*\\n([\\s\\S]*?)(?=\\n[a-zA-Z_][a-zA-Z0-9_]*\\s*:|---|$)`, "m");
38
+ const blockMatch = fm.match(re);
39
+ if (!blockMatch) return slots;
40
+ const block = blockMatch[1];
41
+ let current = {};
42
+ for (const line of block.split("\n")) {
43
+ const typeMatch = line.match(/^\s*-\s+type:\s*["']?([^"'\n]*)["']?/);
44
+ if (typeMatch) {
45
+ if (current.type) slots.push({ ...current });
46
+ current = { type: typeMatch[1].trim() };
47
+ continue;
48
+ }
49
+ const nameMatch = line.match(/^\s+name:\s*["']?([^"'\n]*)["']?/);
50
+ if (nameMatch) {
51
+ current.name = nameMatch[1].trim();
52
+ continue;
53
+ }
54
+ const defaultMatch = line.match(/^\s+(?:default|value):\s*(.*)$/);
55
+ if (defaultMatch) {
56
+ current.defaultOrValue = defaultMatch[1].trim().replace(/^["']|["']$/g, "");
57
+ slots.push({ ...current });
58
+ current = {};
59
+ }
60
+ }
61
+ if (current.type) slots.push({ ...current });
62
+ return slots;
63
+ }
64
+
65
+ function readNodeMeta(filePath) {
66
+ try {
67
+ if (!fs.existsSync(filePath)) return null;
68
+ const raw = fs.readFileSync(filePath, "utf-8");
69
+ const fm = extractFrontmatter(raw);
70
+ return {
71
+ description: parseDescription(fm),
72
+ displayName: parseDisplayName(fm),
73
+ input: parseSlots(fm, "input"),
74
+ output: parseSlots(fm, "output"),
75
+ };
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
80
+
81
+ /** 从 flow.yaml 的 instances 得到节点列表,每项 { id, label, definitionId, input, output },input/output 为 [{ type, name, defaultOrValue }] */
82
+ function loadFlowYamlNodes(flowDir) {
83
+ const flowPath = path.join(flowDir, "flow.yaml");
84
+ if (!fs.existsSync(flowPath)) return [];
85
+ try {
86
+ const raw = fs.readFileSync(flowPath, "utf-8");
87
+ const data = yaml.load(raw);
88
+ const instances = data?.instances && typeof data.instances === "object" ? data.instances : {};
89
+ return Object.entries(instances).map(([id, inst]) => {
90
+ const inp = Array.isArray(inst.input) ? inst.input : [];
91
+ const out = Array.isArray(inst.output) ? inst.output : [];
92
+ const input = inp.map((s) => ({
93
+ type: (s && s.type != null) ? String(s.type).trim() : "",
94
+ name: (s && s.name != null) ? String(s.name).trim() : "",
95
+ defaultOrValue: (s && (s.value != null || s.default != null)) ? String(s.value ?? s.default ?? "").trim() : "",
96
+ }));
97
+ const output = out.map((s) => ({
98
+ type: (s && s.type != null) ? String(s.type).trim() : "",
99
+ name: (s && s.name != null) ? String(s.name).trim() : "",
100
+ defaultOrValue: (s && (s.value != null || s.default != null)) ? String(s.value ?? s.default ?? "").trim() : "",
101
+ }));
102
+ return {
103
+ id,
104
+ label: (inst.label != null) ? String(inst.label) : id,
105
+ definitionId: (inst.definitionId != null) ? String(inst.definitionId) : id,
106
+ input,
107
+ output,
108
+ };
109
+ });
110
+ } catch (_) {
111
+ return [];
112
+ }
113
+ }
114
+
115
+ function main() {
116
+ const args = process.argv.slice(2);
117
+ if (args.length < 2) {
118
+ const payload = { err_code: 1, message: { result: "Usage: agentflow apply -ai collect-nodes <workspaceRoot> <flowName> [runDir]" } };
119
+ console.log(JSON.stringify(payload));
120
+ process.exit(1);
121
+ }
122
+
123
+ const [workspaceRoot, flowName] = args.map((p) => path.resolve(p));
124
+ const nodesDirLegacy = path.join(workspaceRoot, LEGACY_NODES_DIR);
125
+ const nodesDirNew = path.join(workspaceRoot, PROJECT_NODES_DIR);
126
+ const flowDir = getFlowDir(workspaceRoot, flowName) || path.join(workspaceRoot, PIPELINES_DIR, flowName);
127
+
128
+ const out = [];
129
+
130
+ // 1. 项目级节点目录:旧 .cursor 与新 .workspace 合并(同 id 新路径优先)
131
+ out.push("# 节点元数据(内置 + 当前流水线)\n");
132
+ out.push("## 1. 内置节点元数据\n\n");
133
+ const projectById = new Map();
134
+ const mergeProjectDir = (dir) => {
135
+ if (!fs.existsSync(dir)) return;
136
+ for (const file of fs.readdirSync(dir).filter((f) => f.endsWith(".md")).sort()) {
137
+ projectById.set(file.replace(/\.md$/, ""), path.join(dir, file));
138
+ }
139
+ };
140
+ mergeProjectDir(nodesDirLegacy);
141
+ mergeProjectDir(nodesDirNew);
142
+ if (projectById.size === 0) {
143
+ out.push("(无项目内节点目录)\n");
144
+ } else {
145
+ for (const definitionId of [...projectById.keys()].sort()) {
146
+ const meta = readNodeMeta(projectById.get(definitionId));
147
+ if (!meta) continue;
148
+ out.push(`### ${definitionId}\n`);
149
+ out.push(`- **displayName**: ${meta.displayName || definitionId}\n`);
150
+ out.push(`- **description**: ${meta.description || ""}\n`);
151
+ out.push(`- **input** (handle: input-0, input-1, …):\n`);
152
+ if (meta.input.length) meta.input.forEach((s, i) => out.push(` - \`${s.name || "?"}\` (${s.type || "?"}) → input-${i}\n`));
153
+ else out.push(" - 无\n");
154
+ out.push(`- **output** (handle: output-0, output-1, …):\n`);
155
+ if (meta.output.length) meta.output.forEach((s, i) => out.push(` - \`${s.name || "?"}\` (${s.type || "?"}) → output-${i}\n`));
156
+ else out.push(" - 无\n");
157
+ out.push("\n");
158
+ }
159
+ }
160
+
161
+ // 2. 当前流水线节点(来自 flow.yaml instances)
162
+ out.push("## 2. 当前流水线节点元数据\n\n");
163
+ const flowNodes = loadFlowYamlNodes(flowDir);
164
+ for (const node of flowNodes) {
165
+ const { id, label, definitionId, input: nodeInput, output: nodeOutput } = node;
166
+ let input = nodeInput || [];
167
+ let output = nodeOutput || [];
168
+ if (input.length === 0 && output.length === 0) {
169
+ const tryPaths = [
170
+ path.join(flowDir, "nodes", `${definitionId}.md`),
171
+ path.join(nodesDirNew, `${definitionId}.md`),
172
+ path.join(nodesDirLegacy, `${definitionId}.md`),
173
+ path.join(PACKAGE_BUILTIN_NODES_DIR, `${definitionId}.md`),
174
+ ];
175
+ let meta = null;
176
+ for (const defPath of tryPaths) {
177
+ meta = readNodeMeta(defPath);
178
+ if (meta) break;
179
+ }
180
+ if (meta) {
181
+ input = meta.input;
182
+ output = meta.output;
183
+ }
184
+ }
185
+ out.push(`### ${id}\n`);
186
+ out.push(`- **label**: ${label || id}\n`);
187
+ out.push(`- **definitionId**: ${definitionId || ""}\n`);
188
+ out.push(`- **input** (handle):\n`);
189
+ if (input.length) input.forEach((s, i) => out.push(` - \`${s.name || "?"}\` (${s.type || "?"}) → input-${i}\n`));
190
+ else out.push(" - 无\n");
191
+ out.push(`- **output** (handle):\n`);
192
+ if (output.length) output.forEach((s, i) => out.push(` - \`${s.name || "?"}\` (${s.type || "?"}) → output-${i}\n`));
193
+ else out.push(" - 无\n");
194
+ out.push("\n");
195
+ }
196
+
197
+ const content = out.join("");
198
+
199
+ // 优先写入 output 引脚文件(直接写文件模式)
200
+ const resultOutPath = args[2] ? String(args[2]).trim() : "";
201
+ if (resultOutPath) {
202
+ fs.mkdirSync(path.dirname(resultOutPath), { recursive: true });
203
+ fs.writeFileSync(resultOutPath, content, "utf-8");
204
+ } else {
205
+ // 兼容旧模式:通过 JSON stdout 输出
206
+ const payload = { err_code: 0, message: { result: content } };
207
+ console.log(JSON.stringify(payload));
208
+ }
209
+ }
210
+
211
+ main();
@@ -0,0 +1,113 @@
1
+ import yaml from 'js-yaml';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+
9
+ const SPACING_X = 320;
10
+ const SPACING_Y = 240;
11
+ const MIN_GAP = 280;
12
+
13
+ function calculateNodeSpacing(nodes, edges) {
14
+ const graph = {};
15
+
16
+ nodes.forEach(node => {
17
+ graph[node.id] = {
18
+ x: node.position.x,
19
+ y: node.position.y,
20
+ width: 200,
21
+ height: 100,
22
+ };
23
+ });
24
+
25
+ return graph;
26
+ }
27
+
28
+ function adjustPositions(nodePositions) {
29
+ const entries = Object.entries(nodePositions);
30
+
31
+ if (entries.length === 0) return nodePositions;
32
+
33
+ const nodes = entries.map(([id, pos]) => ({
34
+ id,
35
+ x: typeof pos.x === 'number' ? pos.x : parseFloat(pos.x) || 0,
36
+ y: typeof pos.y === 'number' ? pos.y : parseFloat(pos.y) || 0,
37
+ }));
38
+
39
+ nodes.sort((a, b) => a.x - b.x || a.y - b.y);
40
+
41
+ const adjustedNodes = nodes.map((node, index) => {
42
+ const col = index % 5;
43
+ const row = Math.floor(index / 5);
44
+
45
+ return {
46
+ id: node.id,
47
+ x: col * SPACING_X + (row % 2 === 1 ? SPACING_X / 2 : 0),
48
+ y: row * SPACING_Y,
49
+ };
50
+ });
51
+
52
+ const result = {};
53
+ adjustedNodes.forEach(node => {
54
+ result[node.id] = {
55
+ x: node.x,
56
+ y: node.y,
57
+ };
58
+ });
59
+
60
+ return result;
61
+ }
62
+
63
+ function processFlowYaml(filePath) {
64
+ const content = fs.readFileSync(filePath, 'utf-8');
65
+ const flow = yaml.load(content);
66
+
67
+ if (!flow.ui || !flow.ui.nodePositions) {
68
+ console.log(`No node positions found in ${filePath}`);
69
+ return;
70
+ }
71
+
72
+ console.log(`\nProcessing: ${filePath}`);
73
+ console.log(`Nodes count: ${Object.keys(flow.ui.nodePositions).length}`);
74
+
75
+ const oldPositions = { ...flow.ui.nodePositions };
76
+ flow.ui.nodePositions = adjustPositions(flow.ui.nodePositions);
77
+
78
+ const backupPath = filePath + '.backup';
79
+ fs.writeFileSync(backupPath, content);
80
+ console.log(`Backup saved to: ${backupPath}`);
81
+
82
+ const newContent = yaml.dump(flow, {
83
+ indent: 2,
84
+ lineWidth: -1,
85
+ noRefs: true,
86
+ quotingType: '"',
87
+ forceQuotes: false,
88
+ });
89
+
90
+ fs.writeFileSync(filePath, newContent);
91
+ console.log(`Updated: ${filePath}`);
92
+ }
93
+
94
+ function main() {
95
+ const pipelinesDir = path.join(__dirname, '..', '..', 'builtin', 'pipelines');
96
+
97
+ const flows = [
98
+ path.join(pipelinesDir, 'new', 'flow.yaml'),
99
+ path.join(pipelinesDir, 'module-migrate', 'flow.yaml'),
100
+ ];
101
+
102
+ flows.forEach(flowPath => {
103
+ if (fs.existsSync(flowPath)) {
104
+ processFlowYaml(flowPath);
105
+ } else {
106
+ console.log(`File not found: ${flowPath}`);
107
+ }
108
+ });
109
+
110
+ console.log('\n✅ Node positions adjusted successfully!');
111
+ }
112
+
113
+ main();
@@ -0,0 +1,23 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none" role="img" aria-label="AgentFlow">
2
+ <title>AgentFlow</title>
3
+ <rect width="32" height="32" rx="9" fill="#131313"/>
4
+ <!-- ���surface_container_high + primary n� -->
5
+ <rect x="4.5" y="11" width="10.5" height="10" rx="3" fill="#2a2a2a" stroke="#7c4dff" stroke-width="1.2"/>
6
+ <!-- :�޿ -->
7
+ <path
8
+ d="M15.25 14.25C17.8 12.2 19.2 9.8 22.25 9.25"
9
+ stroke="#cdbdff"
10
+ stroke-width="1.65"
11
+ stroke-linecap="round"
12
+ />
13
+ <path
14
+ d="M15.25 17.75C17.8 19.8 19.2 22.2 22.25 22.75"
15
+ stroke="#7c4dff"
16
+ stroke-width="1.65"
17
+ stroke-linecap="round"
18
+ opacity="0.92"
19
+ />
20
+ <!-- ���e�hb + {�rϹtext / file -->
21
+ <rect x="21.75" y="6" width="7.25" height="7" rx="2.25" fill="#353534" stroke="#e8deff" stroke-width="0.95" opacity="0.95"/>
22
+ <rect x="21.75" y="19" width="7.25" height="7" rx="2.25" fill="#353534" stroke="#9ecaff" stroke-width="0.95" opacity="0.9"/>
23
+ </svg>