@fieldwangai/agentflow 0.1.29 → 0.1.31
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/agents/agentflow-node-executor-code.md +3 -2
- package/agents/agentflow-node-executor-planning.md +3 -2
- package/agents/agentflow-node-executor-requirement.md +3 -2
- package/agents/agentflow-node-executor-test.md +3 -2
- package/agents/agentflow-node-executor-ui.md +3 -2
- package/agents/agentflow-node-executor.md +3 -2
- package/agents/en/agentflow-node-executor.md +3 -2
- package/agents/zh/agentflow-node-executor.md +3 -2
- package/bin/lib/agent-runners.mjs +63 -14
- package/bin/lib/api-runner.mjs +30 -4
- package/bin/lib/apply.mjs +6 -5
- package/bin/lib/auth.mjs +240 -0
- package/bin/lib/catalog-agents.mjs +2 -2
- package/bin/lib/catalog-flows.mjs +196 -17
- package/bin/lib/composer-agent.mjs +22 -1
- package/bin/lib/composer-skill-router.mjs +10 -78
- package/bin/lib/flow-import.mjs +2 -2
- package/bin/lib/flow-write.mjs +20 -20
- package/bin/lib/help.mjs +2 -2
- package/bin/lib/locales/en.json +29 -1
- package/bin/lib/locales/zh.json +31 -3
- package/bin/lib/main.mjs +6 -1
- package/bin/lib/node-exec-context.mjs +5 -5
- package/bin/lib/node-execute.mjs +15 -10
- package/bin/lib/paths.mjs +69 -13
- package/bin/lib/recent-runs.mjs +2 -2
- package/bin/lib/run-node-statuses-from-disk.mjs +3 -3
- package/bin/lib/runtime-context.mjs +225 -0
- package/bin/lib/scheduler.mjs +42 -38
- package/bin/lib/skill-registry.mjs +145 -0
- package/bin/lib/ui-server.mjs +1517 -57
- package/bin/lib/user-env.mjs +83 -0
- package/bin/lib/workspace-tree.mjs +4 -3
- package/bin/lib/workspace.mjs +9 -11
- package/bin/pipeline/build-node-prompt.mjs +29 -4
- package/bin/pipeline/get-env.mjs +5 -29
- package/bin/pipeline/get-exec-id.mjs +2 -2
- package/bin/pipeline/get-resolved-values.mjs +1 -0
- package/bin/pipeline/pre-process-node.mjs +328 -6
- package/bin/pipeline/run-tool-nodejs.mjs +7 -0
- package/bin/pipeline/validate-flow.mjs +2 -0
- package/builtin/nodes/agent_subAgent.md +12 -3
- package/builtin/nodes/control_cd_workspace.md +45 -0
- package/builtin/nodes/control_load_skills.md +50 -0
- package/builtin/nodes/control_user_workspace.md +20 -0
- package/builtin/nodes/display_ascii.md +22 -0
- package/builtin/nodes/display_markdown.md +22 -0
- package/builtin/nodes/display_mermaid.md +22 -0
- package/builtin/nodes/tool_git_checkout.md +57 -0
- package/builtin/nodes/tool_nodejs.md +8 -1
- package/builtin/nodes/tool_print.md +4 -1
- package/builtin/web-ui/dist/assets/index-BVWwQpvg.css +1 -0
- package/builtin/web-ui/dist/assets/index-CvNy1n3f.js +197 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/skills/agentflow-flow-recipes/SKILL.md +24 -0
- package/skills/agentflow-flow-recipes/references/recipes.md +63 -0
- package/skills/agentflow-node-reference/SKILL.md +25 -0
- package/skills/agentflow-node-reference/references/builtin-nodes.md +210 -0
- package/skills/agentflow-placeholder-reference/SKILL.md +24 -0
- package/skills/agentflow-placeholder-reference/references/placeholders.md +20 -0
- package/skills/agentflow-runtime-reference/SKILL.md +25 -0
- package/skills/agentflow-runtime-reference/references/runtime.md +64 -0
- package/skills/agentflow-workspace-ascii/SKILL.md +42 -0
- package/skills/agentflow-workspace-graph/SKILL.md +67 -0
- package/skills/agentflow-workspace-markdown/SKILL.md +44 -0
- package/skills/agentflow-workspace-mermaid/SKILL.md +43 -0
- package/builtin/web-ui/dist/assets/index-0vJxkTJz.css +0 -1
- package/builtin/web-ui/dist/assets/index-h69bpxLI.js +0 -190
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
import { getAgentflowUserEnvAbs, sanitizeAgentflowUserId } from "./paths.mjs";
|
|
6
|
+
|
|
7
|
+
function normalizeEnvKey(key) {
|
|
8
|
+
return String(key || "").trim();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isValidEnvKey(key) {
|
|
12
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function readJsonObject(filePath) {
|
|
16
|
+
try {
|
|
17
|
+
if (!fs.existsSync(filePath)) return {};
|
|
18
|
+
const data = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
19
|
+
return data && typeof data === "object" && !Array.isArray(data) ? data : {};
|
|
20
|
+
} catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getFromConfig(config, keyStr) {
|
|
26
|
+
if (!config || typeof config !== "object" || !keyStr) return undefined;
|
|
27
|
+
const parts = String(keyStr).trim().split(".");
|
|
28
|
+
let cur = config;
|
|
29
|
+
for (const p of parts) {
|
|
30
|
+
if (cur == null || typeof cur !== "object") return undefined;
|
|
31
|
+
cur = cur[p];
|
|
32
|
+
}
|
|
33
|
+
return cur != null ? String(cur) : undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function normalizeUserEnvRows(rawRows) {
|
|
37
|
+
const rows = Array.isArray(rawRows) ? rawRows : [];
|
|
38
|
+
const byKey = new Map();
|
|
39
|
+
for (const item of rows) {
|
|
40
|
+
if (!item || typeof item !== "object") continue;
|
|
41
|
+
const key = normalizeEnvKey(item.key);
|
|
42
|
+
if (!key || !isValidEnvKey(key)) continue;
|
|
43
|
+
byKey.set(key, String(item.value ?? ""));
|
|
44
|
+
}
|
|
45
|
+
return Array.from(byKey.entries())
|
|
46
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
47
|
+
.map(([key, value]) => ({ key, value }));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function readUserEnvRows(userId) {
|
|
51
|
+
const data = readJsonObject(getAgentflowUserEnvAbs(userId));
|
|
52
|
+
return normalizeUserEnvRows(Array.isArray(data.env) ? data.env : []);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function readUserEnvObject(userId) {
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const row of readUserEnvRows(userId)) {
|
|
58
|
+
out[row.key] = row.value;
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function writeUserEnvRows(userId, rows) {
|
|
64
|
+
const normalized = normalizeUserEnvRows(rows);
|
|
65
|
+
const safeUserId = sanitizeAgentflowUserId(userId);
|
|
66
|
+
const filePath = getAgentflowUserEnvAbs(safeUserId);
|
|
67
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
68
|
+
fs.writeFileSync(filePath, JSON.stringify({ version: 1, env: normalized }, null, 2) + "\n", "utf-8");
|
|
69
|
+
return normalized;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function resolveUserEnvValue(key, userId) {
|
|
73
|
+
const keyStr = normalizeEnvKey(key);
|
|
74
|
+
if (!keyStr) return "";
|
|
75
|
+
const userEnv = readUserEnvObject(userId);
|
|
76
|
+
if (Object.prototype.hasOwnProperty.call(userEnv, keyStr)) return String(userEnv[keyStr] ?? "");
|
|
77
|
+
const processValue = process.env[keyStr];
|
|
78
|
+
if (processValue != null && processValue !== "") return String(processValue);
|
|
79
|
+
const configPath = path.join(os.homedir(), ".cursor", "config.json");
|
|
80
|
+
const fromConfig = getFromConfig(readJsonObject(configPath), keyStr);
|
|
81
|
+
return fromConfig !== undefined ? fromConfig : "";
|
|
82
|
+
}
|
|
83
|
+
|
|
@@ -221,13 +221,14 @@ function readFilesRecursive(dir, baseDir, maxDepth = 2, currentDepth = 0) {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
export function getPipelineFiles(workspaceRoot, flowId, flowSource, archived = false) {
|
|
224
|
+
export function getPipelineFiles(workspaceRoot, flowId, flowSource, archived = false, opts = {}) {
|
|
225
225
|
const root = path.resolve(workspaceRoot);
|
|
226
226
|
let pipelineDir = null;
|
|
227
|
+
const userPipelinesRoot = getUserPipelinesRoot(opts.userId);
|
|
227
228
|
|
|
228
229
|
if (archived) {
|
|
229
230
|
if (flowSource === "user") {
|
|
230
|
-
pipelineDir = path.join(
|
|
231
|
+
pipelineDir = path.join(userPipelinesRoot, ARCHIVED_PIPELINES_DIR_NAME, flowId);
|
|
231
232
|
} else if (flowSource === "workspace") {
|
|
232
233
|
pipelineDir = path.join(root, PIPELINES_DIR, ARCHIVED_PIPELINES_DIR_NAME, flowId);
|
|
233
234
|
if (!fs.existsSync(pipelineDir)) {
|
|
@@ -239,7 +240,7 @@ export function getPipelineFiles(workspaceRoot, flowId, flowSource, archived = f
|
|
|
239
240
|
if (flowSource === "builtin") {
|
|
240
241
|
pipelineDir = path.join(PACKAGE_BUILTIN_PIPELINES_DIR, flowId);
|
|
241
242
|
} else if (flowSource === "user") {
|
|
242
|
-
pipelineDir = path.join(
|
|
243
|
+
pipelineDir = path.join(userPipelinesRoot, flowId);
|
|
243
244
|
if (!fs.existsSync(pipelineDir)) {
|
|
244
245
|
const alt = path.join(root, PIPELINES_DIR, flowId);
|
|
245
246
|
if (fs.existsSync(alt)) pipelineDir = alt;
|
package/bin/lib/workspace.mjs
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
getReferenceRootAbs,
|
|
10
10
|
getWorkspaceRunBuildRoot,
|
|
11
11
|
getUserPipelinesRoot,
|
|
12
|
+
resolveUniqueUserPipelineDir,
|
|
12
13
|
ARCHIVED_PIPELINES_DIR_NAME,
|
|
13
14
|
} from "./paths.mjs";
|
|
14
15
|
|
|
@@ -23,7 +24,7 @@ export { getRunDir } from "./paths.mjs";
|
|
|
23
24
|
* - legacyUserRoot: ~/agentflow/runBuild/<name>/<uuid>
|
|
24
25
|
* 后两者仅作为向下兼容读取;新写入只走 user/workspace。
|
|
25
26
|
*/
|
|
26
|
-
export function listAllRunDirs(workspaceRoot) {
|
|
27
|
+
export function listAllRunDirs(workspaceRoot, opts = {}) {
|
|
27
28
|
const root = path.resolve(workspaceRoot);
|
|
28
29
|
const out = [];
|
|
29
30
|
const seen = new Set();
|
|
@@ -62,7 +63,7 @@ export function listAllRunDirs(workspaceRoot) {
|
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
// 新位置(优先)
|
|
65
|
-
scanPipelinesDir(getUserPipelinesRoot(), "user");
|
|
66
|
+
scanPipelinesDir(getUserPipelinesRoot(opts.userId), "user");
|
|
66
67
|
scanPipelinesDir(path.join(root, PIPELINES_DIR), "workspace");
|
|
67
68
|
|
|
68
69
|
// 旧位置(兼容读)
|
|
@@ -138,25 +139,22 @@ export function listRunsWithLogs(workspaceRoot) {
|
|
|
138
139
|
return list;
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
/**
|
|
142
|
-
export function getFlowDir(workspaceRoot, flowName) {
|
|
142
|
+
/** 解析活跃 flow 目录:user → workspace → legacy workspace → builtin。归档 flow 必须走显式 archived resolver。 */
|
|
143
|
+
export function getFlowDir(workspaceRoot, flowName, opts = {}) {
|
|
143
144
|
const root = path.resolve(workspaceRoot);
|
|
144
145
|
const hasFlow = (dir) => fs.existsSync(dir) && fs.existsSync(path.join(dir, "flow.yaml"));
|
|
145
146
|
|
|
146
147
|
// user pipelines
|
|
147
|
-
const userRoot = getUserPipelinesRoot();
|
|
148
|
+
const userRoot = getUserPipelinesRoot(opts.userId);
|
|
148
149
|
const userFlowDir = path.join(userRoot, flowName);
|
|
149
150
|
if (hasFlow(userFlowDir)) return userFlowDir;
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
151
|
+
|
|
152
|
+
const inferredUserFlowDir = resolveUniqueUserPipelineDir(flowName);
|
|
153
|
+
if (inferredUserFlowDir) return inferredUserFlowDir;
|
|
153
154
|
|
|
154
155
|
// workspace pipelines
|
|
155
156
|
const wsFlowDir = path.join(root, PIPELINES_DIR, flowName);
|
|
156
157
|
if (hasFlow(wsFlowDir)) return wsFlowDir;
|
|
157
|
-
// workspace archived
|
|
158
|
-
const wsArchivedDir = path.join(root, PIPELINES_DIR, ARCHIVED_PIPELINES_DIR_NAME, flowName);
|
|
159
|
-
if (hasFlow(wsArchivedDir)) return wsArchivedDir;
|
|
160
158
|
|
|
161
159
|
// legacy
|
|
162
160
|
const legacyFlowDir = path.join(root, LEGACY_PIPELINES_DIR, flowName);
|
|
@@ -16,6 +16,7 @@ import { loadFlowDefinition } from "./parse-flow.mjs";
|
|
|
16
16
|
import { getResolvedValues, getOutputPathForSlot } from "./get-resolved-values.mjs";
|
|
17
17
|
import { loadExecId } from "./get-exec-id.mjs";
|
|
18
18
|
import { intermediatePromptBasename, intermediateDirForNode } from "./get-exec-id.mjs";
|
|
19
|
+
import { normalizeSkillsContext, normalizeWorkspaceContext, renderSkillsContextForPrompt } from "../lib/runtime-context.mjs";
|
|
19
20
|
|
|
20
21
|
function shellQuote(s) {
|
|
21
22
|
if (s == null) return "''";
|
|
@@ -116,7 +117,7 @@ function marketplaceRuntimeCommand(marketplaceNode, resolvedInputs, resolvedOutp
|
|
|
116
117
|
* @param {number} [execId] - 本轮 execId,缺省则从 memory 读取
|
|
117
118
|
* @returns {{ ok: boolean, promptPath?: string, nodeContext?: string, taskBody?: string, error?: string }}
|
|
118
119
|
*/
|
|
119
|
-
export function buildNodePrompt(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
120
|
+
export function buildNodePrompt(workspaceRoot, flowName, uuid, instanceId, execId, opts = {}) {
|
|
120
121
|
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
121
122
|
const flowJsonPath = path.join(runDir, "intermediate", "flow.json");
|
|
122
123
|
let flowDir = getFlowDir(workspaceRoot, flowName) || path.join(workspaceRoot, PIPELINES_DIR, flowName);
|
|
@@ -154,7 +155,26 @@ export function buildNodePrompt(workspaceRoot, flowName, uuid, instanceId, execI
|
|
|
154
155
|
: "";
|
|
155
156
|
|
|
156
157
|
const { resolvedInputs = {}, resolvedOutputs = {}, systemPrompt = "" } = data;
|
|
157
|
-
const
|
|
158
|
+
const workspaceContext = normalizeWorkspaceContext(opts.workspaceContext || resolvedInputs.workspaceContext, workspaceRoot, flowName, { flowDir });
|
|
159
|
+
const skillsContext = normalizeSkillsContext(opts.skillsContext || resolvedInputs.skillsContext);
|
|
160
|
+
if (workspaceContext?.workspaceRoot) {
|
|
161
|
+
resolvedInputs.workspaceRoot = workspaceContext.workspaceRoot;
|
|
162
|
+
resolvedInputs.cwd = workspaceContext.cwd || workspaceContext.workspaceRoot;
|
|
163
|
+
resolvedInputs.pipelineWorkspace = workspaceContext.pipelineWorkspace || path.resolve(workspaceRoot);
|
|
164
|
+
}
|
|
165
|
+
const resolveOpts = {
|
|
166
|
+
instanceId,
|
|
167
|
+
currentExecId: e,
|
|
168
|
+
runDir,
|
|
169
|
+
workspaceRoot: workspaceContext?.workspaceRoot || workspaceRoot,
|
|
170
|
+
extra: {
|
|
171
|
+
workspaceRoot: workspaceContext?.workspaceRoot || path.resolve(workspaceRoot),
|
|
172
|
+
cwd: workspaceContext?.cwd || workspaceContext?.workspaceRoot || path.resolve(workspaceRoot),
|
|
173
|
+
pipelineWorkspace: workspaceContext?.pipelineWorkspace || path.resolve(workspaceRoot),
|
|
174
|
+
flowDir: path.resolve(flowDir),
|
|
175
|
+
runDir,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
158
178
|
const taskBody = resolvePlaceholdersInText(
|
|
159
179
|
instanceBody,
|
|
160
180
|
resolvedInputs,
|
|
@@ -168,9 +188,12 @@ export function buildNodePrompt(workspaceRoot, flowName, uuid, instanceId, execI
|
|
|
168
188
|
? marketplaceRuntimeCommand(marketplaceNode, resolvedInputs, resolvedOutputs, resolveOpts)
|
|
169
189
|
: "";
|
|
170
190
|
|
|
191
|
+
const skillsPrompt = renderSkillsContextForPrompt(skillsContext);
|
|
192
|
+
const contextBlocks = [systemPrompt || "(无)", skillsPrompt].filter((x) => x && String(x).trim());
|
|
193
|
+
|
|
171
194
|
const content = `## 节点上下文
|
|
172
195
|
|
|
173
|
-
${
|
|
196
|
+
${contextBlocks.join("\n\n")}
|
|
174
197
|
|
|
175
198
|
## 执行任务
|
|
176
199
|
|
|
@@ -191,9 +214,11 @@ ${taskBody || "(无)"}
|
|
|
191
214
|
return {
|
|
192
215
|
ok: true,
|
|
193
216
|
promptPath: relativePath.replace(/\\/g, "/"),
|
|
194
|
-
nodeContext:
|
|
217
|
+
nodeContext: contextBlocks.join("\n\n") || "",
|
|
195
218
|
taskBody: taskBody || "",
|
|
196
219
|
script: resolvedScript || "",
|
|
220
|
+
workspaceContext,
|
|
221
|
+
skillsContext,
|
|
197
222
|
};
|
|
198
223
|
}
|
|
199
224
|
|
package/bin/pipeline/get-env.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* apply -ai get-env:按 key
|
|
4
|
-
*
|
|
3
|
+
* apply -ai get-env:按 key 从用户私有 env、系统环境变量与 ~/.cursor/config.json 读取 value。
|
|
4
|
+
* 优先级:先查当前 AGENTFLOW_USER_ID 的私有 env,再查 process.env[key],最后查 ~/.cursor/config.json(支持点号路径如 openai.apiKey)。
|
|
5
5
|
*
|
|
6
6
|
* 用法(apply 步骤,由 CLI 调用):
|
|
7
7
|
* agentflow apply -ai get-env <workspaceRoot> <flowName> <uuid> <instanceId> <execId> <key>
|
|
@@ -15,39 +15,15 @@
|
|
|
15
15
|
|
|
16
16
|
import fs from "fs";
|
|
17
17
|
import path from "path";
|
|
18
|
-
import os from "os";
|
|
19
18
|
|
|
20
19
|
import { getRunDir } from "../lib/paths.mjs";
|
|
20
|
+
import { resolveUserEnvValue } from "../lib/user-env.mjs";
|
|
21
21
|
import { writeResult } from "./write-result.mjs";
|
|
22
22
|
import { outputDirForNode, outputNodeBasename } from "./get-exec-id.mjs";
|
|
23
23
|
|
|
24
|
-
function getFromConfig(config, keyStr) {
|
|
25
|
-
if (!config || typeof config !== "object" || !keyStr) return undefined;
|
|
26
|
-
const parts = String(keyStr).trim().split(".");
|
|
27
|
-
let cur = config;
|
|
28
|
-
for (const p of parts) {
|
|
29
|
-
if (cur == null || typeof cur !== "object") return undefined;
|
|
30
|
-
cur = cur[p];
|
|
31
|
-
}
|
|
32
|
-
return cur != null ? String(cur) : undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
24
|
function resolveValue(keyStr) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
value = process.env[keyStr] ?? "";
|
|
39
|
-
if (value === "") {
|
|
40
|
-
const configPath = path.join(os.homedir(), ".cursor", "config.json");
|
|
41
|
-
if (fs.existsSync(configPath)) {
|
|
42
|
-
try {
|
|
43
|
-
const raw = fs.readFileSync(configPath, "utf-8");
|
|
44
|
-
const config = JSON.parse(raw);
|
|
45
|
-
const fromConfig = getFromConfig(config, keyStr);
|
|
46
|
-
if (fromConfig !== undefined) value = fromConfig;
|
|
47
|
-
} catch (_) {}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return value;
|
|
25
|
+
if (!keyStr) return "";
|
|
26
|
+
return resolveUserEnvValue(keyStr, process.env.AGENTFLOW_USER_ID || "");
|
|
51
27
|
}
|
|
52
28
|
|
|
53
29
|
function main() {
|
|
@@ -53,8 +53,8 @@ export function loadExecId(workspaceRoot, flowName, uuid, instanceId) {
|
|
|
53
53
|
/**
|
|
54
54
|
* 从 memory 读取所有 order 中节点的 execId。
|
|
55
55
|
*/
|
|
56
|
-
export function loadAllExecIds(workspaceRoot, flowName, uuid, order) {
|
|
57
|
-
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
56
|
+
export function loadAllExecIds(workspaceRoot, flowName, uuid, order, opts = {}) {
|
|
57
|
+
const runDir = getRunDir(workspaceRoot, flowName, uuid, opts);
|
|
58
58
|
const memoryPath = path.join(runDir, MEMORY_FILENAME);
|
|
59
59
|
const map = fs.existsSync(memoryPath)
|
|
60
60
|
? parseMemory(fs.readFileSync(memoryPath, "utf-8"))
|
|
@@ -233,6 +233,7 @@ export function getResolvedValues(workspaceRoot, flowName, uuid, instanceId) {
|
|
|
233
233
|
// 运行时常量放在后面,确保不会被 input 槽位的空值覆盖
|
|
234
234
|
const runtimeConstants = {
|
|
235
235
|
workspaceRoot: path.resolve(workspaceRoot),
|
|
236
|
+
pipelineWorkspace: path.resolve(workspaceRoot),
|
|
236
237
|
flowName,
|
|
237
238
|
runDir: runDirRel,
|
|
238
239
|
flowDir: path.resolve(flowDir),
|