@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.
- package/README.md +20 -33
- package/README.zh-CN.md +14 -34
- package/agents/agentflow-node-executor-code.md +13 -3
- package/agents/agentflow-node-executor-planning.md +13 -3
- package/agents/agentflow-node-executor-requirement.md +13 -3
- package/agents/agentflow-node-executor-test.md +13 -3
- package/agents/agentflow-node-executor-ui.md +13 -3
- package/agents/agentflow-node-executor.md +13 -3
- package/agents/en/agentflow-node-executor.md +13 -3
- package/agents/zh/agentflow-node-executor.md +13 -3
- package/bin/agentflow.mjs +3 -3
- package/bin/lib/admin-builtin-pipelines.mjs +3 -2
- package/bin/lib/agent-runners.mjs +0 -929
- package/bin/lib/auth.mjs +2 -1
- package/bin/lib/catalog-agents.mjs +2 -1
- package/bin/lib/catalog-flows.mjs +167 -88
- package/bin/lib/composer-agent.mjs +3 -793
- package/bin/lib/composer-skill-router.mjs +3 -323
- package/bin/lib/exec-buffered.mjs +32 -0
- package/bin/lib/flow-dsl/cli.mjs +276 -0
- package/bin/lib/flow-dsl/codegen.mjs +358 -0
- package/bin/lib/flow-dsl/defs.mjs +103 -0
- package/bin/lib/flow-dsl/index.mjs +77 -0
- package/bin/lib/flow-dsl/ir.mjs +305 -0
- package/bin/lib/flow-dsl/layout.mjs +115 -0
- package/bin/lib/flow-dsl/legacy-yaml.mjs +268 -0
- package/bin/lib/flow-dsl/lint.mjs +241 -0
- package/bin/lib/flow-dsl/packages.mjs +251 -0
- package/bin/lib/flow-dsl/parser.mjs +444 -0
- package/bin/lib/flow-import.mjs +96 -26
- package/bin/lib/flow-write.mjs +48 -12
- package/bin/lib/help.mjs +10 -30
- package/bin/lib/html-escape.mjs +19 -0
- package/bin/lib/http-util.mjs +49 -0
- package/bin/lib/legacy-flow-execution.mjs +43 -0
- package/bin/lib/locales/en.json +1 -1
- package/bin/lib/locales/zh.json +1 -1
- package/bin/lib/main.mjs +153 -283
- package/bin/lib/marketplace.mjs +206 -61
- package/bin/lib/model-config.mjs +10 -0
- package/bin/lib/node-package-archive.mjs +240 -0
- package/bin/lib/node-package-bootstrap.mjs +72 -0
- package/bin/lib/node-package-manifest.mjs +174 -0
- package/bin/lib/paths.mjs +42 -19
- package/bin/lib/prd-workflow-routes.mjs +2949 -0
- package/bin/lib/prd-workflow-server.mjs +4884 -0
- package/bin/lib/run-events.mjs +0 -66
- package/bin/lib/schedule-config.mjs +4 -4
- package/bin/lib/skill-runtime.mjs +35 -0
- package/bin/lib/startup-storage-migrations.mjs +274 -0
- package/bin/lib/ui-server.mjs +1106 -18013
- package/bin/lib/user-env.mjs +16 -0
- package/bin/lib/workspace-auto-layout.mjs +234 -0
- package/bin/lib/workspace-flow-store.mjs +478 -0
- package/bin/lib/workspace-graph-merge.mjs +41 -34
- package/bin/lib/workspace-preview.mjs +74 -0
- package/bin/lib/workspace-routes.mjs +3088 -0
- package/bin/lib/workspace-server.mjs +6199 -0
- package/bin/lib/workspace-state.mjs +331 -0
- package/bin/lib/workspace.mjs +2 -1
- package/builtin/nodes/agent_subAgent.md +1 -0
- package/builtin/nodes/control_agent_toBool.md +2 -0
- package/builtin/nodes/control_anyOne.md +2 -0
- package/builtin/nodes/control_cancelled.md +2 -0
- package/builtin/nodes/control_cd_workspace.md +5 -11
- package/builtin/nodes/control_delay.md +2 -0
- package/builtin/nodes/control_end.md +2 -0
- package/builtin/nodes/control_if.md +1 -0
- package/builtin/nodes/control_interval_loop.md +2 -0
- package/builtin/nodes/control_load_mcp.md +24 -0
- package/builtin/nodes/control_load_skills.md +8 -23
- package/builtin/nodes/control_start.md +2 -0
- package/builtin/nodes/control_toBool.md +2 -0
- package/builtin/nodes/control_user_workspace.md +2 -0
- package/builtin/nodes/control_wait_until.md +2 -0
- package/builtin/nodes/display_ascii.md +1 -0
- package/builtin/nodes/display_chart.md +1 -0
- package/builtin/nodes/display_html.md +1 -0
- package/builtin/nodes/display_image.md +1 -0
- package/builtin/nodes/display_markdown.md +1 -0
- package/builtin/nodes/display_mermaid.md +1 -0
- package/builtin/nodes/display_react_app.md +1 -0
- package/builtin/nodes/display_table.md +1 -0
- package/builtin/nodes/provide_bool.md +1 -0
- package/builtin/nodes/provide_file.md +1 -0
- package/builtin/nodes/provide_password.md +1 -0
- package/builtin/nodes/provide_str.md +1 -0
- package/builtin/nodes/tool_display_share_link.md +1 -0
- package/builtin/nodes/tool_get_env.md +2 -0
- package/builtin/nodes/tool_git_checkout.md +1 -0
- package/builtin/nodes/tool_git_worktree_load.md +1 -0
- package/builtin/nodes/tool_git_worktree_unload.md +1 -0
- package/builtin/nodes/tool_gitlab_create_mr.md +1 -0
- package/builtin/nodes/tool_jenkins_build.md +2 -0
- package/builtin/nodes/tool_load_key.md +2 -0
- package/builtin/nodes/tool_nodejs.md +17 -19
- package/builtin/nodes/tool_print.md +2 -0
- package/builtin/nodes/tool_save_key.md +2 -0
- package/builtin/nodes/tool_set_run_env.md +1 -0
- package/builtin/nodes/tool_user_ask.md +2 -0
- package/builtin/nodes/tool_user_check.md +2 -0
- package/builtin/nodes/tool_wecom_send_app_markdown.md +1 -0
- package/builtin/nodes/tool_wecom_send_group_markdown.md +1 -0
- package/builtin/nodes/workspace_one_click_task.md +44 -0
- package/builtin/nodes/workspace_run.md +16 -0
- package/builtin/nodes/workspace_scheduled_run.md +16 -0
- package/builtin/pipelines/module-migrate/scripts/gate.mjs +37 -0
- package/builtin/pipelines/module-migrate/scripts/static-check.mjs +82 -0
- package/builtin/pipelines/module-migrate/workspace.flow.js +172 -0
- package/builtin/pipelines/module-migrate/workspace.layout.json +134 -0
- package/builtin/pipelines/new/scripts/lint-flow.mjs +38 -0
- package/builtin/pipelines/new/workspace.flow.js +91 -0
- package/builtin/pipelines/new/workspace.layout.json +70 -0
- package/builtin/web-ui/dist/assets/{WorkflowAssistantThread-DPbR2UaN.js → WorkflowAssistantThread-CKClwj96.js} +1 -1
- package/builtin/web-ui/dist/assets/index-BZ5KqLur.js +870 -0
- package/builtin/web-ui/dist/assets/index-CEXmmwM2.css +1 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +2 -1
- package/reference/flow-control-capabilities.md +77 -158
- package/reference/flow-layout.md +1 -1
- package/reference/flow-prompt-handler-check.md +2 -2
- package/skills/agentflow-author-flow/SKILL.md +8 -47
- package/skills/agentflow-cli/SKILL.md +158 -25
- package/skills/agentflow-cli/agents/openai.yaml +2 -2
- package/skills/agentflow-cli/scripts/agentflow-cli.mjs +668 -18
- package/skills/agentflow-cli/scripts/agentflow-runtime.mjs +97 -0
- package/skills/agentflow-flow-add-instances/SKILL.md +7 -248
- package/skills/agentflow-flow-dsl/SKILL.md +206 -0
- package/skills/agentflow-flow-dsl/agents/openai.yaml +4 -0
- package/skills/agentflow-flow-dsl/references/node-calls.md +39 -0
- package/skills/agentflow-flow-edit-node-fields/SKILL.md +4 -73
- package/skills/agentflow-flow-recipes/SKILL.md +7 -18
- package/skills/agentflow-flow-recipes/references/recipes.md +97 -43
- package/skills/agentflow-flow-sync-ui/SKILL.md +3 -54
- package/skills/agentflow-node-dsl/SKILL.md +212 -0
- package/skills/agentflow-node-dsl/agents/openai.yaml +4 -0
- package/skills/agentflow-node-reference/SKILL.md +5 -4
- package/skills/agentflow-node-reference/references/builtin-nodes.md +166 -115
- package/skills/agentflow-placeholder-reference/SKILL.md +2 -2
- package/skills/agentflow-runtime-reference/SKILL.md +2 -2
- package/skills/agentflow-runtime-reference/references/runtime.md +1 -1
- package/skills/agentflow-workspace-ascii/SKILL.md +9 -16
- package/skills/agentflow-workspace-graph/SKILL.md +62 -48
- package/skills/agentflow-workspace-html/SKILL.md +7 -2
- package/skills/agentflow-workspace-image/SKILL.md +6 -2
- package/skills/agentflow-workspace-markdown/SKILL.md +14 -21
- package/skills/agentflow-workspace-mermaid/SKILL.md +8 -16
- package/bin/lib/api-runner.mjs +0 -387
- package/bin/lib/apply.mjs +0 -903
- package/bin/lib/composer-flow-instances.mjs +0 -68
- package/bin/lib/composer-flow-skeleton.mjs +0 -334
- package/bin/lib/composer-flow-validate.mjs +0 -47
- package/bin/lib/composer-model-router.mjs +0 -185
- package/bin/lib/composer-node-schema.mjs +0 -303
- package/bin/lib/composer-planner.mjs +0 -751
- package/bin/lib/composer-script-ops.mjs +0 -233
- package/bin/lib/flow-static-preview.mjs +0 -104
- package/bin/lib/hub-login.mjs +0 -54
- package/bin/lib/hub-publish.mjs +0 -159
- package/bin/lib/hub-remote.mjs +0 -189
- package/bin/lib/hub.mjs +0 -299
- package/bin/lib/jenkins.mjs +0 -380
- package/bin/lib/node-execute.mjs +0 -539
- package/bin/lib/normalize-node-tool-command.mjs +0 -97
- package/bin/lib/runtime-context.mjs +0 -243
- package/bin/lib/scheduler.mjs +0 -601
- package/bin/lib/ui-print.mjs +0 -94
- package/bin/pipeline/build-node-prompt.mjs +0 -271
- package/bin/pipeline/check-cache.mjs +0 -191
- package/bin/pipeline/check-flow.mjs +0 -543
- package/bin/pipeline/collect-nodes.mjs +0 -212
- package/bin/pipeline/compute-cache-md5.mjs +0 -177
- package/bin/pipeline/ensure-run-dir.mjs +0 -71
- package/bin/pipeline/gc.mjs +0 -129
- package/bin/pipeline/get-env.mjs +0 -59
- package/bin/pipeline/get-resolved-values.mjs +0 -344
- package/bin/pipeline/load-key.mjs +0 -62
- package/bin/pipeline/parse-flow.mjs +0 -708
- package/bin/pipeline/post-process-control-if.mjs +0 -23
- package/bin/pipeline/post-process-node.mjs +0 -490
- package/bin/pipeline/pre-process-node.mjs +0 -1430
- package/bin/pipeline/resolve-inputs.mjs +0 -201
- package/bin/pipeline/run-tool-nodejs.mjs +0 -167
- package/bin/pipeline/save-key.mjs +0 -93
- package/bin/pipeline/snapshot-prior-round.mjs +0 -70
- package/bin/pipeline/validate-for-ui.mjs +0 -234
- package/bin/pipeline/validate-script-output.mjs +0 -130
- package/bin/pipeline/write-result.mjs +0 -182
- package/builtin/pipelines/module-migrate/flow.yaml +0 -819
- package/builtin/pipelines/new/flow.yaml +0 -545
- package/builtin/pipelines/new/scripts/check-flow.mjs +0 -9
- package/builtin/pipelines/new/scripts/collect-nodes.mjs +0 -211
- package/builtin/web-ui/dist/assets/index-BSCpd5la.js +0 -889
- package/builtin/web-ui/dist/assets/index-DZ328oSo.css +0 -1
- package/skills/agentflow-node-authoring/SKILL.md +0 -57
package/bin/lib/auth.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getAgentflowDataRoot,
|
|
7
7
|
getUserPipelinesRoot,
|
|
8
8
|
sanitizeAgentflowUserId,
|
|
9
|
+
isFlowDir,
|
|
9
10
|
} from "./paths.mjs";
|
|
10
11
|
|
|
11
12
|
const SESSION_COOKIE = "af_session";
|
|
@@ -229,7 +230,7 @@ function listFlowDirs(root) {
|
|
|
229
230
|
return fs.readdirSync(root, { withFileTypes: true })
|
|
230
231
|
.filter((entry) => entry.isDirectory())
|
|
231
232
|
.filter((entry) => entry.name !== ARCHIVED_PIPELINES_DIR_NAME)
|
|
232
|
-
.filter((entry) =>
|
|
233
|
+
.filter((entry) => isFlowDir(path.join(root, entry.name)))
|
|
233
234
|
.map((entry) => entry.name)
|
|
234
235
|
.sort((a, b) => a.localeCompare(b));
|
|
235
236
|
} catch {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
getUserAgentsDirAbs,
|
|
14
14
|
getUserAgentsJsonAbs,
|
|
15
15
|
getUserPipelinesRoot,
|
|
16
|
+
isFlowDir,
|
|
16
17
|
} from "./paths.mjs";
|
|
17
18
|
import { Table } from "./table.mjs";
|
|
18
19
|
|
|
@@ -283,7 +284,7 @@ export function copyBuiltinJson(workspaceRoot, flowId, targetFlowId, opts = {})
|
|
|
283
284
|
const srcDir = path.join(PACKAGE_BUILTIN_PIPELINES_DIR, flowId);
|
|
284
285
|
const pipelinesRoot = getUserPipelinesRoot(opts.userId);
|
|
285
286
|
const destDir = path.join(pipelinesRoot, destId);
|
|
286
|
-
if (!fs.existsSync(srcDir) || !
|
|
287
|
+
if (!fs.existsSync(srcDir) || !isFlowDir(srcDir)) {
|
|
287
288
|
return { success: false, error: t("catalog.builtin_flow_not_found") };
|
|
288
289
|
}
|
|
289
290
|
const existing = collectPipelineNamesFromDir(pipelinesRoot);
|
|
@@ -14,13 +14,21 @@ import {
|
|
|
14
14
|
PROJECT_NODES_DIR,
|
|
15
15
|
USER_AGENTFLOW_PIPELINES_LABEL,
|
|
16
16
|
getUserPipelinesRoot,
|
|
17
|
+
isFlowDir,
|
|
17
18
|
} from "./paths.mjs";
|
|
18
19
|
import {
|
|
19
20
|
readAdminBuiltinPipelineConfig,
|
|
20
21
|
resolveAdminBuiltinPipelineDir,
|
|
21
22
|
} from "./admin-builtin-pipelines.mjs";
|
|
22
23
|
import { Table } from "./table.mjs";
|
|
23
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
listMarketplaceNodes,
|
|
26
|
+
listNodePackagesInDir,
|
|
27
|
+
parseMarketplaceDefinitionId,
|
|
28
|
+
resolveMarketplaceNodePackage,
|
|
29
|
+
} from "./marketplace.mjs";
|
|
30
|
+
import { isWorkspacePreviewDir } from "./workspace-preview.mjs";
|
|
31
|
+
import { RETIRED_NODE_IDS } from "./legacy-flow-execution.mjs";
|
|
24
32
|
|
|
25
33
|
/** 从指定目录收集含 flow.yaml 的子目录名。 */
|
|
26
34
|
export function collectPipelineNamesFromDir(dirPath) {
|
|
@@ -28,27 +36,45 @@ export function collectPipelineNamesFromDir(dirPath) {
|
|
|
28
36
|
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
29
37
|
return entries
|
|
30
38
|
.filter((e) => e.isDirectory())
|
|
31
|
-
.filter((e) =>
|
|
39
|
+
.filter((e) => isFlowDir(path.join(dirPath, e.name)))
|
|
40
|
+
.filter((e) => !isWorkspacePreviewDir(path.join(dirPath, e.name)))
|
|
32
41
|
.map((e) => e.name);
|
|
33
42
|
}
|
|
34
43
|
|
|
44
|
+
const trimmedOrUndefined = (value) => {
|
|
45
|
+
if (typeof value !== "string") return undefined;
|
|
46
|
+
const t = value.trim();
|
|
47
|
+
return t === "" ? undefined : t;
|
|
48
|
+
};
|
|
49
|
+
|
|
35
50
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
51
|
+
* 流水线级说明(列表里那一行)。
|
|
52
|
+
*
|
|
53
|
+
* 两个来源,代码化的图优先:`ui.description` 在往返时由 `extractLayout` 透传进
|
|
54
|
+
* `workspace.layout.json` 的顶层,所以代码化的流程说明在 layout.json 里;只有 flow.yaml
|
|
55
|
+
* 的老流程还从 yaml 的 `ui.description` 读。
|
|
56
|
+
*
|
|
57
|
+
* @param {string} flowDir
|
|
38
58
|
* @returns {string | undefined}
|
|
39
59
|
*/
|
|
40
60
|
export function readPipelineListDescription(flowDir) {
|
|
61
|
+
const layoutPath = path.join(flowDir, "workspace.layout.json");
|
|
62
|
+
if (fs.existsSync(layoutPath)) {
|
|
63
|
+
try {
|
|
64
|
+
const layout = JSON.parse(fs.readFileSync(layoutPath, "utf-8"));
|
|
65
|
+
const fromLayout = trimmedOrUndefined(layout?.description);
|
|
66
|
+
if (fromLayout) return fromLayout;
|
|
67
|
+
} catch {
|
|
68
|
+
/* layout 读不动就退回 yaml */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
41
71
|
const yamlPath = path.join(flowDir, "flow.yaml");
|
|
42
72
|
if (!fs.existsSync(yamlPath)) return undefined;
|
|
43
73
|
try {
|
|
44
|
-
const
|
|
45
|
-
const data = yaml.load(raw);
|
|
74
|
+
const data = yaml.load(fs.readFileSync(yamlPath, "utf-8"));
|
|
46
75
|
if (!data || typeof data !== "object") return undefined;
|
|
47
76
|
const ui = data.ui && typeof data.ui === "object" ? data.ui : {};
|
|
48
|
-
|
|
49
|
-
if (typeof d !== "string") return undefined;
|
|
50
|
-
const t = d.trim();
|
|
51
|
-
return t === "" ? undefined : t;
|
|
77
|
+
return trimmedOrUndefined(ui.description);
|
|
52
78
|
} catch {
|
|
53
79
|
return undefined;
|
|
54
80
|
}
|
|
@@ -164,6 +190,22 @@ function normalizeFrontmatterSlots(arr) {
|
|
|
164
190
|
});
|
|
165
191
|
}
|
|
166
192
|
|
|
193
|
+
/** Workspace 运行时对该节点类型的支持程度;未声明按 native 处理(兼容旧的自定义节点 .md)。 */
|
|
194
|
+
const NODE_RUNTIME_TIERS = new Set(["native", "degraded", "none"]);
|
|
195
|
+
|
|
196
|
+
function normalizeNodeRuntimeTier(value) {
|
|
197
|
+
const tier = String(value ?? "").trim().toLowerCase();
|
|
198
|
+
return NODE_RUNTIME_TIERS.has(tier) ? tier : "native";
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** 节点分类;未声明时由 id 前缀推断。 */
|
|
202
|
+
const NODE_CATEGORY_TYPES = new Set(["control", "provide", "agent"]);
|
|
203
|
+
|
|
204
|
+
function normalizeNodeCategory(value) {
|
|
205
|
+
const type = String(value ?? "").trim().toLowerCase();
|
|
206
|
+
return NODE_CATEGORY_TYPES.has(type) ? type : "";
|
|
207
|
+
}
|
|
208
|
+
|
|
167
209
|
/**
|
|
168
210
|
* 解析 .md 节点文件的 frontmatter。
|
|
169
211
|
* 优先用 js-yaml 解析整块 frontmatter,以支持 description: | / >- 等多行字段;
|
|
@@ -171,7 +213,16 @@ function normalizeFrontmatterSlots(arr) {
|
|
|
171
213
|
*/
|
|
172
214
|
export function parseNodeFrontmatter(raw) {
|
|
173
215
|
const m = raw.match(/^---\s*\r?\n([\s\S]*?)\r?\n---/);
|
|
174
|
-
const data = {
|
|
216
|
+
const data = {
|
|
217
|
+
input: [],
|
|
218
|
+
output: [],
|
|
219
|
+
displayName: undefined,
|
|
220
|
+
description: undefined,
|
|
221
|
+
guide: undefined,
|
|
222
|
+
runtime: "native",
|
|
223
|
+
type: "",
|
|
224
|
+
paletteHidden: false,
|
|
225
|
+
};
|
|
175
226
|
if (!m) return data;
|
|
176
227
|
const fm = m[1];
|
|
177
228
|
try {
|
|
@@ -186,6 +237,9 @@ export function parseNodeFrontmatter(raw) {
|
|
|
186
237
|
if (parsed.guide && typeof parsed.guide === "object" && !Array.isArray(parsed.guide)) {
|
|
187
238
|
data.guide = parsed.guide;
|
|
188
239
|
}
|
|
240
|
+
data.runtime = normalizeNodeRuntimeTier(parsed.runtime);
|
|
241
|
+
data.type = normalizeNodeCategory(parsed.type);
|
|
242
|
+
data.paletteHidden = String(parsed.palette ?? "").trim().toLowerCase() === "hidden";
|
|
189
243
|
data.input = normalizeFrontmatterSlots(parsed.input);
|
|
190
244
|
data.output = normalizeFrontmatterSlots(parsed.output);
|
|
191
245
|
return data;
|
|
@@ -222,6 +276,9 @@ export function parseNodeFrontmatter(raw) {
|
|
|
222
276
|
const displayM = fm.match(/\bdisplayName:\s*["']?([^"'\n#][^\n]*)["']?/);
|
|
223
277
|
if (descM) data.description = descM[1].trim().replace(/^["']|["']$/g, "");
|
|
224
278
|
if (displayM) data.displayName = displayM[1].trim().replace(/^["']|["']$/g, "");
|
|
279
|
+
data.runtime = normalizeNodeRuntimeTier((fm.match(/^\s*runtime:\s*(\S+)/m) || [])[1]);
|
|
280
|
+
data.type = normalizeNodeCategory((fm.match(/^\s*type:\s*(\S+)/m) || [])[1]);
|
|
281
|
+
data.paletteHidden = /^\s*palette:\s*hidden\s*$/m.test(fm);
|
|
225
282
|
return data;
|
|
226
283
|
}
|
|
227
284
|
|
|
@@ -229,7 +286,7 @@ export function parseNodeFrontmatter(raw) {
|
|
|
229
286
|
* @param {string} workspaceRoot
|
|
230
287
|
* @param {string} flowId
|
|
231
288
|
* @param {string} flowSource
|
|
232
|
-
* @param {{ archived?: boolean
|
|
289
|
+
* @param {{ archived?: boolean }} [opts]
|
|
233
290
|
*/
|
|
234
291
|
export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
235
292
|
const root = path.resolve(workspaceRoot);
|
|
@@ -238,14 +295,7 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
|
238
295
|
const byId = new Map();
|
|
239
296
|
const pipelineTranslations = {};
|
|
240
297
|
let marketplaceFlowData = null;
|
|
241
|
-
|
|
242
|
-
const staticFlowDir = staticFlowPath ? path.dirname(staticFlowPath) : "";
|
|
243
|
-
if (staticFlowPath && fs.existsSync(staticFlowPath) && fs.statSync(staticFlowPath).isFile()) {
|
|
244
|
-
try {
|
|
245
|
-
const parsed = yaml.load(fs.readFileSync(staticFlowPath, "utf-8"));
|
|
246
|
-
if (parsed && typeof parsed === "object") marketplaceFlowData = parsed;
|
|
247
|
-
} catch (_) {}
|
|
248
|
-
} else if (flowId && flowSource) {
|
|
298
|
+
if (flowId && flowSource) {
|
|
249
299
|
const flowPath = getFlowYamlAbs(workspaceRoot, flowId, flowSource, opts);
|
|
250
300
|
if (flowPath.path && fs.existsSync(flowPath.path)) {
|
|
251
301
|
try {
|
|
@@ -259,6 +309,7 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
|
259
309
|
const files = fs.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".md"));
|
|
260
310
|
for (const e of files) {
|
|
261
311
|
const id = e.name.replace(/\.mdx?$/i, "").replace(/\.markdown$/i, "");
|
|
312
|
+
if (RETIRED_NODE_IDS.has(id)) continue;
|
|
262
313
|
let type = "agent";
|
|
263
314
|
if (/^control/i.test(id)) type = "control";
|
|
264
315
|
else if (/^provide/i.test(id)) type = "provide";
|
|
@@ -266,6 +317,10 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
|
266
317
|
try {
|
|
267
318
|
const raw = fs.readFileSync(path.join(dir, e.name), "utf-8");
|
|
268
319
|
const data = parseNodeFrontmatter(raw);
|
|
320
|
+
// frontmatter 的 type: 优先于按 id 前缀的推断(workspace_run 等不带前缀的节点靠它归类)
|
|
321
|
+
if (data.type) type = data.type;
|
|
322
|
+
// frontmatter 的 palette: hidden 与 RETIRED_NODE_IDS 等价,让节点自带可见性
|
|
323
|
+
if (data.paletteHidden) continue;
|
|
269
324
|
const strippedId =
|
|
270
325
|
id.replace(/^agent_?/i, "").replace(/^control_?/i, "").replace(/^provide_?/i, "").replace(/^tool_?/i, "") || id;
|
|
271
326
|
const label = data.displayName ?? strippedId;
|
|
@@ -283,6 +338,7 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
|
283
338
|
byId.set(id, {
|
|
284
339
|
id,
|
|
285
340
|
type,
|
|
341
|
+
runtimeTier: data.runtime,
|
|
286
342
|
label: translatedDisplayName || label,
|
|
287
343
|
displayName: translatedDisplayName || data.displayName,
|
|
288
344
|
description: translatedDescription || data.description,
|
|
@@ -294,6 +350,29 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
|
294
350
|
});
|
|
295
351
|
} catch (_) {}
|
|
296
352
|
}
|
|
353
|
+
// 同一个 nodes/ 目录里,子目录形式的代码节点包(index.mjs 声明 + 实现)也进目录。
|
|
354
|
+
// 这样 AI 可以把节点实现直接写在流程目录里,不必先发布到 marketplace。
|
|
355
|
+
for (const manifest of listNodePackagesInDir(dir)) {
|
|
356
|
+
byId.set(manifest.definitionId, {
|
|
357
|
+
id: manifest.definitionId,
|
|
358
|
+
baseDefinitionId: manifest.baseDefinitionId || manifest.runtime?.type || "",
|
|
359
|
+
marketplaceDefinitionId: manifest.definitionId,
|
|
360
|
+
packageId: manifest.id,
|
|
361
|
+
version: manifest.version,
|
|
362
|
+
type: "agent",
|
|
363
|
+
runtimeTier: "native",
|
|
364
|
+
label: manifest.displayName,
|
|
365
|
+
displayName: manifest.displayName,
|
|
366
|
+
description: manifest.description,
|
|
367
|
+
inputs: manifest.input,
|
|
368
|
+
outputs: manifest.output,
|
|
369
|
+
source: flowIdOpt ? "flow" : "project",
|
|
370
|
+
flowId: flowIdOpt,
|
|
371
|
+
packageDir: manifest.packageDir,
|
|
372
|
+
// 与 marketplace 分支同名:前端 scriptFromMarketplaceRuntime 读的就是这个对象
|
|
373
|
+
runtime: manifest.runtime,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
297
376
|
};
|
|
298
377
|
addFromDir(PACKAGE_BUILTIN_NODES_DIR, "project");
|
|
299
378
|
addFromDir(path.join(root, LEGACY_NODES_DIR), "project");
|
|
@@ -322,24 +401,6 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
|
|
|
322
401
|
runtime: manifest.runtime,
|
|
323
402
|
});
|
|
324
403
|
}
|
|
325
|
-
if (staticFlowDir) {
|
|
326
|
-
addFromDir(path.join(staticFlowDir, "nodes"), "flow", flowId);
|
|
327
|
-
const flowData = marketplaceFlowData;
|
|
328
|
-
if (flowData?.instances) {
|
|
329
|
-
pipelineTranslations[flowId] = pipelineTranslations[flowId] || {};
|
|
330
|
-
for (const [nodeId, inst] of Object.entries(flowData.instances)) {
|
|
331
|
-
pipelineTranslations[flowId][nodeId] = {
|
|
332
|
-
label: inst?.label,
|
|
333
|
-
body: inst?.body,
|
|
334
|
-
description: inst?.description || inst?.userDescription,
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
if (flowData?.ui?.description) {
|
|
339
|
-
pipelineTranslations[flowId] = pipelineTranslations[flowId] || {};
|
|
340
|
-
pipelineTranslations[flowId].__flowDescription = flowData.ui.description;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
404
|
if (flowId && flowSource) {
|
|
344
405
|
if (flowSource === "builtin") {
|
|
345
406
|
addFromDir(path.join(PACKAGE_BUILTIN_PIPELINES_DIR, flowId, "nodes"), "flow", flowId);
|
|
@@ -491,63 +552,79 @@ export function readFlowJson(workspaceRoot, flowId, flowSource, options = {}) {
|
|
|
491
552
|
}
|
|
492
553
|
|
|
493
554
|
/**
|
|
494
|
-
*
|
|
495
|
-
* @
|
|
496
|
-
* @returns {{ path: string } | { error: string }}
|
|
555
|
+
* 按 flowSource 列出候选目录(含 user→workspace→legacy 的历史回退顺序)。
|
|
556
|
+
* @returns {{ dirs: string[] } | { error: string }}
|
|
497
557
|
*/
|
|
498
|
-
|
|
558
|
+
function flowDirCandidates(workspaceRoot, flowId, flowSource, options = {}) {
|
|
499
559
|
const root = path.resolve(workspaceRoot);
|
|
500
|
-
const archived = Boolean(options.archived);
|
|
501
560
|
const userPipelinesRoot = getUserPipelinesRoot(options.userId);
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if (flowSource === "builtin") {
|
|
505
|
-
return { error: t("catalog.builtin_flow_archive_path_not_supported") };
|
|
506
|
-
}
|
|
561
|
+
if (Boolean(options.archived)) {
|
|
562
|
+
if (flowSource === "builtin") return { error: t("catalog.builtin_flow_archive_path_not_supported") };
|
|
507
563
|
if (flowSource === "user") {
|
|
508
|
-
|
|
509
|
-
} else if (flowSource === "workspace") {
|
|
510
|
-
yamlPath = path.join(root, PIPELINES_DIR, ARCHIVED_PIPELINES_DIR_NAME, flowId, "flow.yaml");
|
|
511
|
-
if (!fs.existsSync(yamlPath)) {
|
|
512
|
-
const altLeg = path.join(root, LEGACY_PIPELINES_DIR, ARCHIVED_PIPELINES_DIR_NAME, flowId, "flow.yaml");
|
|
513
|
-
if (fs.existsSync(altLeg)) yamlPath = altLeg;
|
|
514
|
-
}
|
|
515
|
-
} else {
|
|
516
|
-
return { error: "Invalid flowSource" };
|
|
517
|
-
}
|
|
518
|
-
if (!fs.existsSync(yamlPath)) {
|
|
519
|
-
return { error: "Flow not found: " + flowId };
|
|
520
|
-
}
|
|
521
|
-
return { path: yamlPath };
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
if (flowSource === "builtin") {
|
|
525
|
-
yamlPath = path.join(PACKAGE_BUILTIN_PIPELINES_DIR, flowId, "flow.yaml");
|
|
526
|
-
} else if (flowSource === "admin") {
|
|
527
|
-
const flowDir = resolveAdminBuiltinPipelineDir(flowId);
|
|
528
|
-
yamlPath = flowDir ? path.join(flowDir, "flow.yaml") : "";
|
|
529
|
-
} else if (flowSource === "user") {
|
|
530
|
-
yamlPath = path.join(userPipelinesRoot, flowId, "flow.yaml");
|
|
531
|
-
if (!fs.existsSync(yamlPath)) {
|
|
532
|
-
const alt = path.join(root, PIPELINES_DIR, flowId, "flow.yaml");
|
|
533
|
-
if (fs.existsSync(alt)) yamlPath = alt;
|
|
534
|
-
}
|
|
535
|
-
if (!fs.existsSync(yamlPath)) {
|
|
536
|
-
const altLeg = path.join(root, LEGACY_PIPELINES_DIR, flowId, "flow.yaml");
|
|
537
|
-
if (fs.existsSync(altLeg)) yamlPath = altLeg;
|
|
564
|
+
return { dirs: [path.join(userPipelinesRoot, ARCHIVED_PIPELINES_DIR_NAME, flowId)] };
|
|
538
565
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
566
|
+
if (flowSource === "workspace") {
|
|
567
|
+
return {
|
|
568
|
+
dirs: [
|
|
569
|
+
path.join(root, PIPELINES_DIR, ARCHIVED_PIPELINES_DIR_NAME, flowId),
|
|
570
|
+
path.join(root, LEGACY_PIPELINES_DIR, ARCHIVED_PIPELINES_DIR_NAME, flowId),
|
|
571
|
+
],
|
|
572
|
+
};
|
|
544
573
|
}
|
|
545
|
-
} else {
|
|
546
574
|
return { error: "Invalid flowSource" };
|
|
547
575
|
}
|
|
548
|
-
if (
|
|
549
|
-
|
|
576
|
+
if (flowSource === "builtin") return { dirs: [path.join(PACKAGE_BUILTIN_PIPELINES_DIR, flowId)] };
|
|
577
|
+
if (flowSource === "admin") {
|
|
578
|
+
const dir = resolveAdminBuiltinPipelineDir(flowId);
|
|
579
|
+
return { dirs: dir ? [dir] : [] };
|
|
550
580
|
}
|
|
581
|
+
if (flowSource === "user") {
|
|
582
|
+
return {
|
|
583
|
+
dirs: [
|
|
584
|
+
path.join(userPipelinesRoot, flowId),
|
|
585
|
+
path.join(root, PIPELINES_DIR, flowId),
|
|
586
|
+
path.join(root, LEGACY_PIPELINES_DIR, flowId),
|
|
587
|
+
],
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
if (flowSource === "workspace") {
|
|
591
|
+
return {
|
|
592
|
+
dirs: [path.join(root, PIPELINES_DIR, flowId), path.join(root, LEGACY_PIPELINES_DIR, flowId)],
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
return { error: "Invalid flowSource" };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* 解析流程目录绝对路径。
|
|
600
|
+
*
|
|
601
|
+
* 大多数调用方要的其实是**目录**,以前却只能 `path.dirname(getFlowYamlAbs().path)` —— 于是
|
|
602
|
+
* 「改个名」这种和 yaml 毫无关系的操作,也被 `flow.yaml` 是否存在卡住。目录存不存在现在由
|
|
603
|
+
* `isFlowDir` 说了算(见 paths.mjs),三种标记文件任一即可。
|
|
604
|
+
*
|
|
605
|
+
* @param {{ archived?: boolean, userId?: string }} [options]
|
|
606
|
+
* @returns {{ dir: string } | { error: string }}
|
|
607
|
+
*/
|
|
608
|
+
export function resolveFlowDirAbs(workspaceRoot, flowId, flowSource, options = {}) {
|
|
609
|
+
const candidates = flowDirCandidates(workspaceRoot, flowId, flowSource, options);
|
|
610
|
+
if (candidates.error) return { error: candidates.error };
|
|
611
|
+
for (const dir of candidates.dirs) {
|
|
612
|
+
if (isFlowDir(dir)) return { dir };
|
|
613
|
+
}
|
|
614
|
+
return { error: "Flow not found: " + flowId };
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* 解析 flow.yaml 绝对路径。**只给真的要读 yaml 内容的调用方用**;要目录请用
|
|
619
|
+
* `resolveFlowDirAbs`。
|
|
620
|
+
* @param {{ archived?: boolean }} [options]
|
|
621
|
+
* @returns {{ path: string } | { error: string }}
|
|
622
|
+
*/
|
|
623
|
+
export function getFlowYamlAbs(workspaceRoot, flowId, flowSource, options = {}) {
|
|
624
|
+
const resolved = resolveFlowDirAbs(workspaceRoot, flowId, flowSource, options);
|
|
625
|
+
if (resolved.error) return { error: resolved.error };
|
|
626
|
+
const yamlPath = path.join(resolved.dir, "flow.yaml");
|
|
627
|
+
if (!fs.existsSync(yamlPath)) return { error: "Flow not found: " + flowId };
|
|
551
628
|
return { path: yamlPath };
|
|
552
629
|
}
|
|
553
630
|
|
|
@@ -628,6 +705,7 @@ export function readNodeJson(workspaceRoot, nodeId, flowId, flowSource, opts = {
|
|
|
628
705
|
if (/^control/i.test(nodeId)) type = "control";
|
|
629
706
|
else if (/^provide/i.test(nodeId)) type = "provide";
|
|
630
707
|
else if (/^tool/i.test(nodeId)) type = "agent";
|
|
708
|
+
if (data.type) type = data.type;
|
|
631
709
|
const strippedId =
|
|
632
710
|
nodeId
|
|
633
711
|
.replace(/\.md$/, "")
|
|
@@ -638,6 +716,7 @@ export function readNodeJson(workspaceRoot, nodeId, flowId, flowSource, opts = {
|
|
|
638
716
|
const label = data.displayName ?? strippedId;
|
|
639
717
|
return {
|
|
640
718
|
type,
|
|
719
|
+
runtimeTier: data.runtime,
|
|
641
720
|
label,
|
|
642
721
|
displayName: data.displayName,
|
|
643
722
|
inputs: data.input,
|
|
@@ -870,13 +949,13 @@ export function listPipelines(workspaceRoot) {
|
|
|
870
949
|
return;
|
|
871
950
|
}
|
|
872
951
|
const table = new Table({
|
|
873
|
-
head: [chalk.cyan(t("catalog.pipeline_header")), chalk.cyan(t("catalog.source_header")), chalk.cyan(t("catalog.
|
|
952
|
+
head: [chalk.cyan(t("catalog.pipeline_header")), chalk.cyan(t("catalog.source_header")), chalk.cyan(t("catalog.open_example_header"))],
|
|
874
953
|
colWidths: [24, 10, 48],
|
|
875
954
|
style: { head: [], border: ["grey"] },
|
|
876
955
|
});
|
|
877
956
|
for (const row of rows) {
|
|
878
957
|
const sourceLabel = row.source === "builtin" || row.source === "admin" ? "builtin" : row.source === "workspace" ? "workspace" : "user";
|
|
879
|
-
table.push([row.id, sourceLabel, `agentflow
|
|
958
|
+
table.push([row.id, sourceLabel, `agentflow validate ${row.id}`]);
|
|
880
959
|
}
|
|
881
960
|
log.info("\n" + chalk.bold("Pipelines"));
|
|
882
961
|
log.info(table.toString());
|