@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
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 代码节点包的执行入口。
4
+ *
5
+ * 由 `workspaceMarketplaceRuntimeCommand` 生成的命令调用:
6
+ *
7
+ * node <此文件> <entryAbs>
8
+ *
9
+ * 节点包的 `index.mjs` 是个 **模块**,不是脚本——直接 `node index.mjs` 只会定义完就退出。
10
+ * 这里负责把 Workspace 运行时的环境契约翻译成 `run()` 的三个参数:
11
+ *
12
+ * inputs 来自 AGENTFLOW_INPUTS_JSON,按槽位名取值
13
+ * outputs 来自 AGENTFLOW_OUTPUTS_ABS_JSON,槽位名 -> 该写入的绝对路径
14
+ * dirs workspaceRoot / nodeRunDir / nodeTmpDir / outputsDir
15
+ *
16
+ * 约定与 tool_nodejs 一致:退出码即成败,stdout 即节点 result,不做 JSON 包装。
17
+ */
18
+ import path from "node:path";
19
+ import { pathToFileURL } from "node:url";
20
+
21
+ function parseJsonEnv(name) {
22
+ const raw = process.env[name];
23
+ if (!raw) return {};
24
+ try {
25
+ const parsed = JSON.parse(raw);
26
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
27
+ } catch {
28
+ return {};
29
+ }
30
+ }
31
+
32
+ const entry = process.argv[2];
33
+ if (!entry) {
34
+ console.error("node-package-bootstrap: 缺少入口文件参数");
35
+ process.exit(2);
36
+ }
37
+
38
+ const entryAbs = path.resolve(entry);
39
+ let mod;
40
+ try {
41
+ mod = await import(pathToFileURL(entryAbs).href);
42
+ } catch (e) {
43
+ console.error(`节点包入口加载失败 ${entryAbs}: ${(e && e.stack) || e}`);
44
+ process.exit(1);
45
+ }
46
+
47
+ const run = typeof mod.run === "function"
48
+ ? mod.run
49
+ : typeof mod.default?.run === "function"
50
+ ? mod.default.run
51
+ : null;
52
+ if (!run) {
53
+ console.error(`节点包 ${entryAbs} 没有导出 run();请 \`export async function run(inputs, outputs, dirs)\``);
54
+ process.exit(1);
55
+ }
56
+
57
+ const inputs = parseJsonEnv("AGENTFLOW_INPUTS_JSON");
58
+ const outputs = parseJsonEnv("AGENTFLOW_OUTPUTS_ABS_JSON");
59
+ const dirs = {
60
+ workspaceRoot: process.env.AGENTFLOW_WORKSPACE_ROOT || process.cwd(),
61
+ nodeRunDir: process.env.AGENTFLOW_NODE_RUN_DIR || process.cwd(),
62
+ nodeTmpDir: process.env.AGENTFLOW_NODE_TMP_DIR || process.cwd(),
63
+ outputsDir: process.env.AGENTFLOW_OUTPUTS_DIR || process.cwd(),
64
+ };
65
+
66
+ try {
67
+ await run(inputs, outputs, dirs);
68
+ } catch (e) {
69
+ // 节点靠抛错来失败;把栈打到 stderr,退出码非零
70
+ console.error((e && e.stack) || String(e));
71
+ process.exit(1);
72
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * 代码节点包的清单提取。
3
+ *
4
+ * 一个节点包 = 一个目录,`index.mjs` 同时是「声明」和「实现」:
5
+ *
6
+ * ```js
7
+ * export default {
8
+ * id: "collect_metrics",
9
+ * version: "1.0.0",
10
+ * name: "统计流程语料",
11
+ * inputs: { date: { type: "text", description: "查询日期" } },
12
+ * outputs: { result: { type: "text" } },
13
+ * };
14
+ *
15
+ * export async function run(inputs, outputs, dirs) { ... }
16
+ * ```
17
+ *
18
+ * 声明部分由 acorn **静态解析**得到——列节点面板、校验槽位、渲染画布都不会执行包里的
19
+ * 代码。这是硬约束:目录扫描期执行第三方代码既慢又不安全。
20
+ *
21
+ * 代价是 `export default` 必须是纯字面量。任何变量引用、函数调用、展开运算都会被拒绝,
22
+ * 并给出明确报错,而不是悄悄退化成空清单。
23
+ */
24
+ import fs from "fs";
25
+ import path from "path";
26
+ import { parse as acornParse } from "acorn";
27
+
28
+ export const NODE_PACKAGE_ENTRY = "index.mjs";
29
+
30
+ /** 槽位类型;与 builtin/nodes/*.md 的 `type:` 取值一致。 */
31
+ const SLOT_TYPES = new Set(["text", "file", "bool", "node", "image", "json"]);
32
+
33
+ function staticEval(node, where) {
34
+ if (!node) throw new Error(`${where}: 空表达式`);
35
+ switch (node.type) {
36
+ case "Literal":
37
+ return node.value;
38
+ case "TemplateLiteral":
39
+ if (node.expressions.length) throw new Error(`${where}: 模板字符串不能有插值`);
40
+ return node.quasis.map((q) => q.value.cooked).join("");
41
+ case "ArrayExpression":
42
+ return node.elements.map((el, i) => staticEval(el, `${where}[${i}]`));
43
+ case "ObjectExpression": {
44
+ const out = {};
45
+ for (const prop of node.properties) {
46
+ if (prop.type !== "Property") throw new Error(`${where}: 对象里不允许展开运算符`);
47
+ if (prop.computed) throw new Error(`${where}: 对象里不允许计算属性名`);
48
+ const key = prop.key.type === "Identifier" ? prop.key.name : prop.key.value;
49
+ out[key] = staticEval(prop.value, `${where}.${key}`);
50
+ }
51
+ return out;
52
+ }
53
+ case "UnaryExpression":
54
+ if (node.operator === "-") return -staticEval(node.argument, where);
55
+ if (node.operator === "+") return +staticEval(node.argument, where);
56
+ throw new Error(`${where}: 不允许的一元运算 ${node.operator}`);
57
+ default:
58
+ throw new Error(`${where}: 只允许字面量,不允许 ${node.type}`);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * 从节点包入口静态提取 `export default` 声明。
64
+ * @returns {object|null} 解析不出声明时返回 null;语法/字面量违规时抛错。
65
+ */
66
+ export function readNodePackageDeclaration(entryPath) {
67
+ const src = fs.readFileSync(entryPath, "utf-8");
68
+ let ast;
69
+ try {
70
+ ast = acornParse(src, { ecmaVersion: 2022, sourceType: "module" });
71
+ } catch (e) {
72
+ throw new Error(`${path.basename(entryPath)} 解析失败:${(e && e.message) || e}`);
73
+ }
74
+ for (const stmt of ast.body) {
75
+ if (stmt.type !== "ExportDefaultDeclaration") continue;
76
+ return staticEval(stmt.declaration, "export default");
77
+ }
78
+ return null;
79
+ }
80
+
81
+ /** 入口是否导出了 `run`(命名导出或 `export default { run }` 之外的函数声明)。 */
82
+ export function nodePackageExportsRun(entryPath) {
83
+ const src = fs.readFileSync(entryPath, "utf-8");
84
+ let ast;
85
+ try {
86
+ ast = acornParse(src, { ecmaVersion: 2022, sourceType: "module" });
87
+ } catch {
88
+ return false;
89
+ }
90
+ for (const stmt of ast.body) {
91
+ if (stmt.type !== "ExportNamedDeclaration") continue;
92
+ const decl = stmt.declaration;
93
+ if (decl?.type === "FunctionDeclaration" && decl.id?.name === "run") return true;
94
+ if (decl?.type === "VariableDeclaration") {
95
+ for (const d of decl.declarations) if (d.id?.type === "Identifier" && d.id.name === "run") return true;
96
+ }
97
+ for (const spec of stmt.specifiers || []) {
98
+ const exported = spec.exported?.name ?? spec.exported?.value;
99
+ if (exported === "run") return true;
100
+ }
101
+ }
102
+ return false;
103
+ }
104
+
105
+ /**
106
+ * 声明里的 `inputs` / `outputs` 是对象映射(顺序即槽位顺序);平台要的是槽位数组,
107
+ * 且首位固定是控制槽 prev / next。
108
+ */
109
+ export function slotMapToList(map, kind) {
110
+ const first = kind === "input"
111
+ ? { type: "node", name: "prev", default: "" }
112
+ : { type: "node", name: "next", default: "" };
113
+ const out = [first];
114
+ if (!map || typeof map !== "object" || Array.isArray(map)) return out;
115
+ for (const [name, rawSpec] of Object.entries(map)) {
116
+ const spec = typeof rawSpec === "string" ? { type: rawSpec } : (rawSpec && typeof rawSpec === "object" ? rawSpec : {});
117
+ const type = String(spec.type || "text").trim();
118
+ if (!SLOT_TYPES.has(type)) {
119
+ throw new Error(`${kind} 槽位 ${name}: 未知类型 ${type}(可选 ${[...SLOT_TYPES].join(" / ")})`);
120
+ }
121
+ const slot = { type, name: String(name), default: spec.default == null ? "" : String(spec.default) };
122
+ if (spec.description != null) slot.description = String(spec.description);
123
+ if (spec.required != null) slot.required = Boolean(spec.required);
124
+ out.push(slot);
125
+ }
126
+ return out;
127
+ }
128
+
129
+ /**
130
+ * 把节点包声明转成 marketplace manifest 的形状(`node.yaml` 解析后的等价物)。
131
+ * @returns {object|null}
132
+ */
133
+ export function nodePackageDeclarationToManifest(decl, packageDir) {
134
+ if (!decl || typeof decl !== "object" || Array.isArray(decl)) return null;
135
+ const id = decl.id != null ? String(decl.id).trim() : path.basename(packageDir);
136
+ const version = decl.version != null ? String(decl.version).trim() : "";
137
+ if (!id || !version) return null;
138
+ return {
139
+ id,
140
+ version,
141
+ displayName: decl.name != null ? String(decl.name) : id,
142
+ description: decl.description != null ? String(decl.description) : "",
143
+ input: slotMapToList(decl.inputs, "input"),
144
+ output: slotMapToList(decl.outputs, "output"),
145
+ baseDefinitionId: "tool_nodejs",
146
+ runtime: { type: "tool_nodejs", entry: NODE_PACKAGE_ENTRY, mode: "module" },
147
+ ...(decl.ownerUserId != null ? { ownerUserId: String(decl.ownerUserId) } : {}),
148
+ ...(decl.createdBy != null ? { createdBy: String(decl.createdBy) } : {}),
149
+ };
150
+ }
151
+
152
+ /**
153
+ * 读取一个节点包目录的清单:优先 `index.mjs` 静态声明,读不出再回退调用方给的
154
+ * `node.yaml` 读取器。
155
+ * @param {string} dir
156
+ * @param {(yamlPath: string) => object|null} readYaml
157
+ * @returns {object|null}
158
+ */
159
+ export function readNodePackageManifest(dir, readYaml) {
160
+ const entry = path.join(dir, NODE_PACKAGE_ENTRY);
161
+ if (fs.existsSync(entry) && fs.statSync(entry).isFile()) {
162
+ const manifest = nodePackageDeclarationToManifest(readNodePackageDeclaration(entry), dir);
163
+ if (manifest) return manifest;
164
+ }
165
+ return typeof readYaml === "function" ? readYaml(path.join(dir, "node.yaml")) : null;
166
+ }
167
+
168
+ /** 目录是否是一个可识别的节点包。 */
169
+ export function isNodePackageDir(dir) {
170
+ if (!dir || !fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) return false;
171
+ const entry = path.join(dir, NODE_PACKAGE_ENTRY);
172
+ if (fs.existsSync(entry) && fs.statSync(entry).isFile()) return true;
173
+ return fs.existsSync(path.join(dir, "node.yaml"));
174
+ }
package/bin/lib/paths.mjs CHANGED
@@ -14,6 +14,44 @@ export const PACKAGE_ROOT = path.resolve(BIN_DIR, "..");
14
14
  /** 节点执行区域分割线(开始/结束标识用) */
15
15
  export const NODE_SEP = "════════════════════════════════════════════════════════════════";
16
16
 
17
+ /**
18
+ * 「这个目录是不是一个流程」的**唯一**判据。
19
+ *
20
+ * 历史上这条规则在十来处各写了一遍 `existsSync(dir + "/flow.yaml")`,于是 `flow.yaml`
21
+ * 从执行格式悄悄退化成了目录哨兵:内容早就是死的,存在却是承重的——没有它,目录在列表、
22
+ * 路径解析、复制改名里全都不存在。
23
+ *
24
+ * 顺序即权威顺序:代码 > 只读的遗留 JSON > 已退休的 flow.yaml。
25
+ */
26
+ export const FLOW_MARKER_FILENAMES = ["workspace.flow.js", "workspace.graph.json", "flow.yaml"];
27
+
28
+ /**
29
+ * 命中的标记文件绝对路径;都没有则空字符串。
30
+ * @param {string} dir
31
+ * @returns {string}
32
+ */
33
+ export function flowMarkerPath(dir) {
34
+ const base = dir == null ? "" : String(dir).trim();
35
+ if (!base) return "";
36
+ for (const name of FLOW_MARKER_FILENAMES) {
37
+ const p = path.join(base, name);
38
+ try {
39
+ if (fs.existsSync(p)) return p;
40
+ } catch {
41
+ /* 不可读的目录当作没有 */
42
+ }
43
+ }
44
+ return "";
45
+ }
46
+
47
+ /**
48
+ * @param {string} dir
49
+ * @returns {boolean}
50
+ */
51
+ export function isFlowDir(dir) {
52
+ return flowMarkerPath(dir) !== "";
53
+ }
54
+
17
55
  /** agentflow 包根目录(CLI 所在包的 node_modules 用于解析脚本依赖,如 js-yaml) */
18
56
  export const PACKAGE_AGENTS_DIR = path.join(PACKAGE_ROOT, "agents");
19
57
  /** 包内 agents 元数据 JSON */
@@ -142,7 +180,7 @@ export function resolveUniqueUserPipelineDir(flowName) {
142
180
  for (const userId of listAgentflowUserIds()) {
143
181
  const dir = path.join(getAgentflowDataRoot(), "users", userId, "pipelines", name);
144
182
  try {
145
- if (fs.existsSync(path.join(dir, "flow.yaml"))) matches.push(dir);
183
+ if (isFlowDir(dir)) matches.push(dir);
146
184
  } catch {
147
185
  /* ignore unreadable user dirs */
148
186
  }
@@ -178,11 +216,11 @@ export function getFlowRuntimeRoot(workspaceRoot, flowName, opts = {}) {
178
216
  : process.cwd();
179
217
  const userRoot = getUserPipelinesRoot(opts.userId);
180
218
  const userDir = path.join(userRoot, flowName);
181
- if (fs.existsSync(path.join(userDir, "flow.yaml"))) return userDir;
219
+ if (isFlowDir(userDir)) return userDir;
182
220
  const inferredUserDir = resolveUniqueUserPipelineDir(flowName);
183
221
  if (inferredUserDir) return inferredUserDir;
184
222
  const wsDir = path.join(root, PIPELINES_DIR, flowName);
185
- if (fs.existsSync(path.join(wsDir, "flow.yaml"))) return wsDir;
223
+ if (isFlowDir(wsDir)) return wsDir;
186
224
  // builtin / legacy / 尚未落盘 → 默认 user 目录,runBuild 首次写入时创建
187
225
  return userDir;
188
226
  }
@@ -260,23 +298,8 @@ export const USER_AGENTFLOW_AGENTS_LABEL = "~/agentflow/agents";
260
298
  /** agents.json 中 user 角色 filepath 展示前缀(相对数据根) */
261
299
  export const USER_AGENTS_FILEPATH_PREFIX = "agentflow/agents";
262
300
 
263
- /** apply/replay 流水线脚本目录(随包发布) */
301
+ /** 随包发布的 CLI 单步脚本目录(validate-flow / get-ready-nodes / extract-thinking) */
264
302
  export const PIPELINE_SCRIPTS_DIR = path.join(BIN_DIR, "pipeline");
265
- /** apply -ai 允许调用的单步脚本名(不含 .mjs) */
266
- export const APPLY_AI_STEPS = [
267
- "ensure-run-dir",
268
- "parse-flow",
269
- "get-ready-nodes",
270
- "pre-process-node",
271
- "post-process-node",
272
- "write-result",
273
- "run-tool-nodejs",
274
- "get-env",
275
- "validate-flow",
276
- "collect-nodes",
277
- "gc",
278
- "extract-thinking",
279
- ];
280
303
  /** 项目内流水线根目录(写入与主读取路径) */
281
304
  export const PIPELINES_DIR = ".workspace/agentflow/pipelines";
282
305
  /** 用户目录或工作区 pipelines 下存放已归档流水线的子目录名 */