@fieldwangai/agentflow 0.1.33 → 0.1.34
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/bin/lib/git-worktree.mjs +15 -0
- package/bin/lib/locales/en.json +3 -7
- package/bin/lib/locales/zh.json +2 -6
- package/bin/lib/paths.mjs +0 -1
- package/bin/lib/scheduler.mjs +8 -3
- package/bin/lib/ui-server.mjs +12 -9
- package/bin/pipeline/build-node-prompt.mjs +27 -1
- package/bin/pipeline/pre-process-node.mjs +70 -34
- package/builtin/nodes/agent_subAgent.md +2 -0
- package/builtin/nodes/control_agent_toBool.md +4 -0
- package/builtin/nodes/control_cancelled.md +8 -4
- package/builtin/nodes/control_cd_workspace.md +2 -0
- package/builtin/nodes/control_delay.md +9 -0
- package/builtin/nodes/control_toBool.md +6 -2
- package/builtin/nodes/control_user_workspace.md +2 -0
- package/builtin/nodes/control_wait_until.md +9 -0
- package/builtin/nodes/provide_bool.md +2 -0
- package/builtin/nodes/provide_file.md +2 -0
- package/builtin/nodes/provide_str.md +2 -0
- package/builtin/nodes/tool_get_env.md +4 -0
- package/builtin/nodes/tool_git_checkout.md +6 -1
- package/builtin/nodes/tool_git_worktree_load.md +7 -2
- package/builtin/nodes/tool_git_worktree_unload.md +5 -5
- package/builtin/nodes/tool_load_key.md +4 -0
- package/builtin/nodes/tool_nodejs.md +4 -0
- package/builtin/nodes/tool_print.md +2 -0
- package/builtin/nodes/tool_save_key.md +4 -0
- package/builtin/nodes/tool_user_ask.md +3 -1
- package/builtin/nodes/tool_user_check.md +3 -1
- package/builtin/web-ui/dist/assets/index-B1j_UaHw.js +202 -0
- package/builtin/web-ui/dist/assets/index-ChiTnW0H.css +1 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/nodes/control_deadline.md +0 -32
- package/builtin/web-ui/dist/assets/index-BWAb27N0.js +0 -198
- package/builtin/web-ui/dist/assets/index-DgfSfcjH.css +0 -1
package/bin/lib/git-worktree.mjs
CHANGED
|
@@ -112,6 +112,21 @@ export function resolveGitRepoRoot(repoPath) {
|
|
|
112
112
|
return path.resolve(gitOrThrow(["rev-parse", "--show-toplevel"], abs, "git rev-parse"));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
export function inferGitRepoRootFromWorktree(worktreePath) {
|
|
116
|
+
const raw = String(worktreePath || "").trim();
|
|
117
|
+
if (!raw) throw new Error("worktreePath is required");
|
|
118
|
+
const abs = path.resolve(raw);
|
|
119
|
+
if (!fs.existsSync(abs) || !fs.statSync(abs).isDirectory()) {
|
|
120
|
+
throw new Error(`worktreePath directory not found: ${abs}`);
|
|
121
|
+
}
|
|
122
|
+
const commonDir = gitOrThrow(["rev-parse", "--git-common-dir"], abs, "git rev-parse common dir");
|
|
123
|
+
const commonAbs = path.resolve(abs, commonDir);
|
|
124
|
+
if (path.basename(commonAbs) === ".git") {
|
|
125
|
+
return path.dirname(commonAbs);
|
|
126
|
+
}
|
|
127
|
+
return resolveGitRepoRoot(abs);
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
export function currentGitBranch(repoRoot) {
|
|
116
131
|
const branch = gitOrThrow(["rev-parse", "--abbrev-ref", "HEAD"], repoRoot, "git rev-parse branch");
|
|
117
132
|
return branch === "HEAD" ? "" : branch;
|
package/bin/lib/locales/en.json
CHANGED
|
@@ -238,7 +238,7 @@
|
|
|
238
238
|
"description": "Continues to next when any upstream input is ready"
|
|
239
239
|
},
|
|
240
240
|
"control_toBool": {
|
|
241
|
-
"displayName": "
|
|
241
|
+
"displayName": "Code ToBool",
|
|
242
242
|
"description": "Execute script to produce true/false prediction. Like tool_nodejs but enforces bool output. Extensible inputs."
|
|
243
243
|
},
|
|
244
244
|
"control_delay": {
|
|
@@ -249,13 +249,9 @@
|
|
|
249
249
|
"displayName": "Wait Until",
|
|
250
250
|
"description": "Persistently wait until an absolute time, then scheduler resumes this run."
|
|
251
251
|
},
|
|
252
|
-
"control_deadline": {
|
|
253
|
-
"displayName": "Deadline",
|
|
254
|
-
"description": "Check whether the deadline has expired and output expired as bool."
|
|
255
|
-
},
|
|
256
252
|
"control_cancelled": {
|
|
257
|
-
"displayName": "
|
|
258
|
-
"description": "Check whether the current run
|
|
253
|
+
"displayName": "Cancel Check",
|
|
254
|
+
"description": "Check whether the current wait/run has been cancelled and output cancelled as bool."
|
|
259
255
|
},
|
|
260
256
|
"control_interval_loop": {
|
|
261
257
|
"displayName": "Interval Loop",
|
package/bin/lib/locales/zh.json
CHANGED
|
@@ -238,7 +238,7 @@
|
|
|
238
238
|
"description": "当任一上游输入就绪时,沿 next 继续执行"
|
|
239
239
|
},
|
|
240
240
|
"control_toBool": {
|
|
241
|
-
"displayName": "
|
|
241
|
+
"displayName": "代码转布尔",
|
|
242
242
|
"description": "执行 script 脚本输出 true/false 到 prediction,类似 tool_nodejs 但强制 bool 输出,可扩展输入"
|
|
243
243
|
},
|
|
244
244
|
"control_delay": {
|
|
@@ -249,13 +249,9 @@
|
|
|
249
249
|
"displayName": "等待到时间",
|
|
250
250
|
"description": "持久化等待到指定时间,到点后由 scheduler 唤醒当前 run 继续执行"
|
|
251
251
|
},
|
|
252
|
-
"control_deadline": {
|
|
253
|
-
"displayName": "截止判断",
|
|
254
|
-
"description": "判断当前时间是否已超过截止时间,输出 expired 布尔值"
|
|
255
|
-
},
|
|
256
252
|
"control_cancelled": {
|
|
257
253
|
"displayName": "取消判断",
|
|
258
|
-
"description": "判断当前 run
|
|
254
|
+
"description": "判断当前 wait/run 是否已被取消,输出 cancelled 布尔值"
|
|
259
255
|
},
|
|
260
256
|
"control_interval_loop": {
|
|
261
257
|
"displayName": "间隔循环",
|
package/bin/lib/paths.mjs
CHANGED
package/bin/lib/scheduler.mjs
CHANGED
|
@@ -136,7 +136,7 @@ function readJsonObject(filePath) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
function waitStateKey(state) {
|
|
139
|
-
return String((state && (state.id || state.instanceId)) || "");
|
|
139
|
+
return String((state && (state.waitId || state.id || state.instanceId)) || "");
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
function persistedWaitState(state) {
|
|
@@ -181,17 +181,22 @@ function writeWaitState(waitState, patch = {}) {
|
|
|
181
181
|
...(patch && typeof patch === "object" ? patch : {}),
|
|
182
182
|
updatedAt: new Date().toISOString(),
|
|
183
183
|
};
|
|
184
|
+
const key = waitStateKey(next);
|
|
185
|
+
if (key) {
|
|
186
|
+
next.waitId = String(next.waitId || key);
|
|
187
|
+
next.id = String(next.id || next.waitId);
|
|
188
|
+
}
|
|
184
189
|
const runDir = next.runDir || (next.waitPath ? path.dirname(next.waitPath) : "");
|
|
185
190
|
if (!runDir) return;
|
|
186
191
|
|
|
187
192
|
const legacyPath = next.legacyPath || next.waitPath || path.join(runDir, WAIT_STATE_FILENAME);
|
|
188
193
|
const registryPath = next.registryPath || path.join(runDir, WAIT_STATES_FILENAME);
|
|
189
194
|
const persisted = persistedWaitState(next);
|
|
190
|
-
const
|
|
195
|
+
const persistedKey = waitStateKey(persisted);
|
|
191
196
|
|
|
192
197
|
const registry = readJsonObject(registryPath);
|
|
193
198
|
if (registry && Array.isArray(registry.waits)) {
|
|
194
|
-
const waits = registry.waits.filter((w) => waitStateKey(w) !==
|
|
199
|
+
const waits = registry.waits.filter((w) => waitStateKey(w) !== persistedKey);
|
|
195
200
|
waits.push(persisted);
|
|
196
201
|
fs.writeFileSync(registryPath, JSON.stringify({ ...registry, updatedAt: new Date().toISOString(), waits }, null, 2) + "\n", "utf-8");
|
|
197
202
|
}
|
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
publishFlowSnippet,
|
|
83
83
|
publishNodeFromInstance,
|
|
84
84
|
} from "./marketplace.mjs";
|
|
85
|
-
import { buildGitContext, loadGitWorktree, normalizeGitContext, runGit, unloadGitWorktree } from "./git-worktree.mjs";
|
|
85
|
+
import { buildGitContext, inferGitRepoRootFromWorktree, loadGitWorktree, normalizeGitContext, runGit, unloadGitWorktree } from "./git-worktree.mjs";
|
|
86
86
|
import { createGitLabMergeRequest } from "./gitlab-mr.mjs";
|
|
87
87
|
import {
|
|
88
88
|
authSetupRequired,
|
|
@@ -1088,20 +1088,23 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
1088
1088
|
|
|
1089
1089
|
if (defId === "tool_git_worktree_unload") {
|
|
1090
1090
|
const gitContext = normalizeGitContext(workspaceSlotValue(workspaceSlotByName(instance, "gitContext")));
|
|
1091
|
-
const
|
|
1092
|
-
|
|
1093
|
-
const worktreePath = workspaceResolvePath(
|
|
1094
|
-
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "")
|
|
1095
|
-
|
|
1096
|
-
|
|
1091
|
+
const workspaceContext = parseJsonText(workspaceSlotValue(workspaceSlotByName(instance, "workspaceContext")), null);
|
|
1092
|
+
const contextCwd = workspaceContext?.cwd ? path.resolve(String(workspaceContext.cwd)) : cwd;
|
|
1093
|
+
const worktreePath = workspaceResolvePath(contextCwd, workspaceSlotValue(workspaceSlotByName(instance, "worktreePath"))) ||
|
|
1094
|
+
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "") ||
|
|
1095
|
+
contextCwd;
|
|
1096
|
+
const repoPath = workspaceResolvePath(contextCwd, workspaceSlotValue(workspaceSlotByName(instance, "repoPath"))) ||
|
|
1097
|
+
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "") ||
|
|
1098
|
+
inferGitRepoRootFromWorktree(worktreePath);
|
|
1097
1099
|
const force = ["true", "1", "yes", "on"].includes(workspaceSlotValue(workspaceSlotByName(instance, "force")).trim().toLowerCase());
|
|
1098
1100
|
const pruneRaw = workspaceSlotValue(workspaceSlotByName(instance, "prune")).trim().toLowerCase();
|
|
1099
1101
|
const prune = pruneRaw !== "false";
|
|
1100
1102
|
const result = unloadGitWorktree({ repoPath, worktreePath, force, prune });
|
|
1101
|
-
|
|
1103
|
+
const previousContext = workspaceContext?.previous && typeof workspaceContext.previous === "object" ? workspaceContext.previous : null;
|
|
1104
|
+
cwd = previousContext?.cwd ? path.resolve(String(previousContext.cwd)) : scopedRoot;
|
|
1102
1105
|
let nextInstance = workspaceSetOutputSlot(instance, "removed", "true");
|
|
1103
1106
|
nextInstance = workspaceSetOutputSlot(nextInstance, "message", result.message);
|
|
1104
|
-
nextInstance = workspaceSetOutputSlot(nextInstance, "workspaceContext", JSON.stringify({
|
|
1107
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "workspaceContext", JSON.stringify(previousContext || {
|
|
1105
1108
|
version: 1,
|
|
1106
1109
|
label: "workspace",
|
|
1107
1110
|
cwd,
|
|
@@ -112,6 +112,31 @@ function marketplaceRuntimeCommand(marketplaceNode, resolvedInputs, resolvedOutp
|
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
function normalizePromptImages(images) {
|
|
116
|
+
if (!Array.isArray(images)) return [];
|
|
117
|
+
return images
|
|
118
|
+
.filter((item) => item && typeof item === "object")
|
|
119
|
+
.map((item, index) => ({
|
|
120
|
+
label: String(item.label || `image ${index + 1}`),
|
|
121
|
+
name: String(item.name || `image-${index + 1}`),
|
|
122
|
+
mimeType: String(item.mimeType || item.type || "image/png"),
|
|
123
|
+
dataUrl: String(item.dataUrl || item.data || ""),
|
|
124
|
+
}))
|
|
125
|
+
.filter((item) => item.dataUrl.startsWith("data:image/"));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function renderImagesForPrompt(images) {
|
|
129
|
+
const list = normalizePromptImages(images);
|
|
130
|
+
if (list.length === 0) return "";
|
|
131
|
+
const blocks = list.map((item) => [
|
|
132
|
+
`### [${item.label}]`,
|
|
133
|
+
`name: ${item.name}`,
|
|
134
|
+
`mimeType: ${item.mimeType}`,
|
|
135
|
+
`dataUrl: ${item.dataUrl}`,
|
|
136
|
+
].join("\n"));
|
|
137
|
+
return `## 图片附件\n\n${blocks.join("\n\n")}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
115
140
|
/**
|
|
116
141
|
* 执行占位符替换,组装 prompt 并写入 intermediate 文件(文件名带 _execId)。
|
|
117
142
|
* @param {number} [execId] - 本轮 execId,缺省则从 memory 读取
|
|
@@ -153,6 +178,7 @@ export function buildNodePrompt(workspaceRoot, flowName, uuid, instanceId, execI
|
|
|
153
178
|
inst?.script != null
|
|
154
179
|
? String(inst.script || "").trim()
|
|
155
180
|
: "";
|
|
181
|
+
const imagePrompt = renderImagesForPrompt(inst?.images);
|
|
156
182
|
|
|
157
183
|
const { resolvedInputs = {}, resolvedOutputs = {}, systemPrompt = "" } = data;
|
|
158
184
|
const workspaceContext = normalizeWorkspaceContext(opts.workspaceContext || resolvedInputs.workspaceContext, workspaceRoot, flowName, { flowDir });
|
|
@@ -197,7 +223,7 @@ ${contextBlocks.join("\n\n")}
|
|
|
197
223
|
|
|
198
224
|
## 执行任务
|
|
199
225
|
|
|
200
|
-
${taskBody || "(无)"}
|
|
226
|
+
${[taskBody || "(无)", imagePrompt].filter((x) => x && String(x).trim()).join("\n\n")}
|
|
201
227
|
`;
|
|
202
228
|
|
|
203
229
|
try {
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
parseSkillKeyList,
|
|
49
49
|
resolveWorkspaceTarget,
|
|
50
50
|
} from "../lib/runtime-context.mjs";
|
|
51
|
-
import { buildGitContext, loadGitWorktree, normalizeGitContext, unloadGitWorktree } from "../lib/git-worktree.mjs";
|
|
51
|
+
import { buildGitContext, inferGitRepoRootFromWorktree, loadGitWorktree, normalizeGitContext, unloadGitWorktree } from "../lib/git-worktree.mjs";
|
|
52
52
|
import { createGitLabMergeRequest } from "../lib/gitlab-mr.mjs";
|
|
53
53
|
|
|
54
54
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -403,12 +403,16 @@ function emitGitWorktreeUnloadNode(workspaceRoot, flowName, uuid, instanceId, ex
|
|
|
403
403
|
const { inputs, workspaceContext, flowJson } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
404
404
|
requireWorkspaceContextInput(inputs, "tool_git_worktree_unload");
|
|
405
405
|
const gitContext = normalizeGitContext(inputs.gitContext);
|
|
406
|
-
const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext) ||
|
|
407
|
-
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "");
|
|
408
406
|
const worktreePath = resolveMaybeWorkspacePath(inputs.worktreePath, workspaceContext) ||
|
|
409
|
-
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "")
|
|
410
|
-
|
|
411
|
-
|
|
407
|
+
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "") ||
|
|
408
|
+
(workspaceContext.cwd ? path.resolve(workspaceContext.cwd) : "") ||
|
|
409
|
+
(workspaceContext.workspaceRoot ? path.resolve(workspaceContext.workspaceRoot) : "");
|
|
410
|
+
if (!worktreePath) throw new Error("tool_git_worktree_unload: workspaceContext.cwd or worktreePath is required");
|
|
411
|
+
const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext) ||
|
|
412
|
+
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "") ||
|
|
413
|
+
inferGitRepoRootFromWorktree(worktreePath) ||
|
|
414
|
+
(workspaceContext.previous?.cwd ? path.resolve(workspaceContext.previous.cwd) : "") ||
|
|
415
|
+
(workspaceContext.previous?.workspaceRoot ? path.resolve(workspaceContext.previous.workspaceRoot) : "");
|
|
412
416
|
const force = isTruthyInput(inputs.force);
|
|
413
417
|
const prune = String(inputs.prune ?? "true").trim().toLowerCase() !== "false";
|
|
414
418
|
const result = unloadGitWorktree({ repoPath, worktreePath, force, prune });
|
|
@@ -636,8 +640,14 @@ function writeWaitState(runDir, state) {
|
|
|
636
640
|
if (parsed && typeof parsed === "object" && Array.isArray(parsed.waits)) registry = parsed;
|
|
637
641
|
} catch (_) {}
|
|
638
642
|
}
|
|
639
|
-
const
|
|
640
|
-
const
|
|
643
|
+
const waitId = String(state.waitId || state.id || `${state.instanceId}:${state.execId || 1}`).trim();
|
|
644
|
+
const waits = registry.waits.filter((w) => {
|
|
645
|
+
if (!w) return false;
|
|
646
|
+
const key = String(w.waitId || w.id || "").trim();
|
|
647
|
+
if (key && key === waitId) return false;
|
|
648
|
+
return !(w.instanceId === state.instanceId && String(w.execId || 1) === String(state.execId || 1));
|
|
649
|
+
});
|
|
650
|
+
const wait = { ...state, waitId, id: state.id || waitId };
|
|
641
651
|
waits.push(wait);
|
|
642
652
|
registry = {
|
|
643
653
|
...registry,
|
|
@@ -651,6 +661,44 @@ function writeWaitState(runDir, state) {
|
|
|
651
661
|
fs.writeFileSync(legacyPath, JSON.stringify(wait, null, 2) + "\n", "utf-8");
|
|
652
662
|
}
|
|
653
663
|
|
|
664
|
+
function buildWaitId(uuid, instanceId, execId, explicit = "") {
|
|
665
|
+
const text = String(explicit || "").trim();
|
|
666
|
+
if (text) return text;
|
|
667
|
+
return `${uuid}:${instanceId}:${execId || 1}`;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function readWaitStateById(runDir, waitId) {
|
|
671
|
+
const text = String(waitId || "").trim();
|
|
672
|
+
if (!text) return null;
|
|
673
|
+
const registryPath = path.join(runDir, "wait-states.json");
|
|
674
|
+
if (fs.existsSync(registryPath)) {
|
|
675
|
+
try {
|
|
676
|
+
const registry = JSON.parse(fs.readFileSync(registryPath, "utf-8"));
|
|
677
|
+
const waits = Array.isArray(registry?.waits) ? registry.waits : [];
|
|
678
|
+
const found = waits.find((w) => {
|
|
679
|
+
const key = String(w?.waitId || w?.id || "").trim();
|
|
680
|
+
return key === text;
|
|
681
|
+
});
|
|
682
|
+
if (found) return found;
|
|
683
|
+
} catch (_) {}
|
|
684
|
+
}
|
|
685
|
+
const legacyPath = path.join(runDir, "wait-state.json");
|
|
686
|
+
if (fs.existsSync(legacyPath)) {
|
|
687
|
+
try {
|
|
688
|
+
const state = JSON.parse(fs.readFileSync(legacyPath, "utf-8"));
|
|
689
|
+
const key = String(state?.waitId || state?.id || "").trim();
|
|
690
|
+
if (key === text) return state;
|
|
691
|
+
} catch (_) {}
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function readCancelFlagForWait(runDir, waitId) {
|
|
697
|
+
const state = readWaitStateById(runDir, waitId);
|
|
698
|
+
if (state && (state.cancelled === true || state.status === "cancelled" || state.branch === "cancelled")) return true;
|
|
699
|
+
return readCancelFlag(runDir);
|
|
700
|
+
}
|
|
701
|
+
|
|
654
702
|
function readCancelFlag(runDir) {
|
|
655
703
|
for (const name of ["cancelled", "cancelled.json", "wait-cancelled.json"]) {
|
|
656
704
|
const p = path.join(runDir, name);
|
|
@@ -966,8 +1014,11 @@ async function main() {
|
|
|
966
1014
|
process.exit(1);
|
|
967
1015
|
}
|
|
968
1016
|
|
|
1017
|
+
const waitId = buildWaitId(uuid, instanceId, execId, inputs.waitId || inputs.watchId);
|
|
1018
|
+
writeOutputSlot(runDir, instanceId, execId, "waitId", waitId);
|
|
969
1019
|
writeOutputSlot(runDir, instanceId, execId, "wakeAt", wakeAt);
|
|
970
1020
|
writeWaitState(runDir, {
|
|
1021
|
+
waitId,
|
|
971
1022
|
status: "waiting",
|
|
972
1023
|
reason: definitionId,
|
|
973
1024
|
flowName,
|
|
@@ -993,7 +1044,7 @@ async function main() {
|
|
|
993
1044
|
`此节点为 ${definitionId},已写入 wait-state.json,等待 scheduler 在 ${wakeAt} 唤醒。\n`,
|
|
994
1045
|
);
|
|
995
1046
|
writeCacheJsonForNode(workspaceRoot, flowName, uuid, instanceId, execId);
|
|
996
|
-
logToRunTag(workspaceRoot, flowName, uuid, "pre-process", { event: "waiting", instanceId, wakeAt, definitionId });
|
|
1047
|
+
logToRunTag(workspaceRoot, flowName, uuid, "pre-process", { event: "waiting", instanceId, waitId, wakeAt, definitionId });
|
|
997
1048
|
console.log(JSON.stringify({
|
|
998
1049
|
ok: true,
|
|
999
1050
|
promptPath,
|
|
@@ -1084,37 +1135,22 @@ async function main() {
|
|
|
1084
1135
|
return;
|
|
1085
1136
|
}
|
|
1086
1137
|
|
|
1087
|
-
if (definitionId === "
|
|
1138
|
+
if (definitionId === "control_cancelled") {
|
|
1088
1139
|
const data = getResolvedValues(workspaceRoot, flowName, uuid, instanceId);
|
|
1089
1140
|
if (!data.ok) {
|
|
1090
|
-
console.error(JSON.stringify({ ok: false, error:
|
|
1141
|
+
console.error(JSON.stringify({ ok: false, error: "control_cancelled: getResolvedValues failed" }));
|
|
1091
1142
|
process.exit(1);
|
|
1092
1143
|
}
|
|
1093
|
-
|
|
1094
|
-
let
|
|
1095
|
-
let message = "";
|
|
1144
|
+
let boolValue;
|
|
1145
|
+
let message;
|
|
1096
1146
|
try {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
} else {
|
|
1103
|
-
const start = inputs.startAt ? parseDateTime(inputs.startAt, timezone) : new Date();
|
|
1104
|
-
deadline = new Date(start.getTime() + parseDurationMs(inputs.duration || ""));
|
|
1105
|
-
}
|
|
1106
|
-
const deadlineAt = deadline.toISOString();
|
|
1107
|
-
boolValue = Date.now() >= deadline.getTime();
|
|
1108
|
-
writeOutputSlot(runDir, instanceId, execId, "deadlineAt", deadlineAt);
|
|
1109
|
-
writeOutputSlot(runDir, instanceId, execId, "expired", boolValue ? "true" : "false");
|
|
1110
|
-
message = boolValue ? `已超过截止时间 ${deadlineAt}` : `未超过截止时间 ${deadlineAt}`;
|
|
1111
|
-
} else {
|
|
1112
|
-
boolValue = readCancelFlag(runDir);
|
|
1113
|
-
writeOutputSlot(runDir, instanceId, execId, "cancelled", boolValue ? "true" : "false");
|
|
1114
|
-
message = boolValue ? "已取消" : "未取消";
|
|
1115
|
-
}
|
|
1147
|
+
const inputs = data.resolvedInputs || {};
|
|
1148
|
+
const waitId = String(inputs.waitId || inputs.watchId || "").trim();
|
|
1149
|
+
boolValue = waitId ? readCancelFlagForWait(runDir, waitId) : readCancelFlag(runDir);
|
|
1150
|
+
writeOutputSlot(runDir, instanceId, execId, "cancelled", boolValue ? "true" : "false");
|
|
1151
|
+
message = boolValue ? "已取消" : "未取消";
|
|
1116
1152
|
} catch (e) {
|
|
1117
|
-
console.error(JSON.stringify({ ok: false, error:
|
|
1153
|
+
console.error(JSON.stringify({ ok: false, error: `control_cancelled: ${e.message}` }));
|
|
1118
1154
|
process.exit(1);
|
|
1119
1155
|
}
|
|
1120
1156
|
writeResult(workspaceRoot, flowName, uuid, instanceId, { status: "success", message }, { execId, preserveBody: false });
|
|
@@ -9,6 +9,8 @@ input:
|
|
|
9
9
|
- type: text
|
|
10
10
|
name: value
|
|
11
11
|
default: ""
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
12
14
|
output:
|
|
13
15
|
- type: node
|
|
14
16
|
name: next
|
|
@@ -16,5 +18,7 @@ output:
|
|
|
16
18
|
- type: bool
|
|
17
19
|
name: prediction
|
|
18
20
|
default: ""
|
|
21
|
+
required: true
|
|
22
|
+
showOnNode: true
|
|
19
23
|
---
|
|
20
24
|
${USER_PROMPT}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
---
|
|
2
|
-
#
|
|
3
|
-
description: Check whether the current run
|
|
4
|
-
displayName:
|
|
2
|
+
# 内置节点:取消判断
|
|
3
|
+
description: Check whether the current wait/run has been cancelled. Use cancelled output with control_if.
|
|
4
|
+
displayName: Cancel Check
|
|
5
5
|
input:
|
|
6
6
|
- type: node
|
|
7
7
|
name: prev
|
|
8
8
|
default: ""
|
|
9
9
|
- type: text
|
|
10
|
-
name:
|
|
10
|
+
name: waitId
|
|
11
11
|
default: ""
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
12
14
|
output:
|
|
13
15
|
- type: node
|
|
14
16
|
name: next
|
|
@@ -16,5 +18,7 @@ output:
|
|
|
16
18
|
- type: bool
|
|
17
19
|
name: cancelled
|
|
18
20
|
default: ""
|
|
21
|
+
required: true
|
|
22
|
+
showOnNode: true
|
|
19
23
|
---
|
|
20
24
|
${USER_PROMPT}
|
|
@@ -9,12 +9,21 @@ input:
|
|
|
9
9
|
- type: text
|
|
10
10
|
name: duration
|
|
11
11
|
default: "10m"
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
12
14
|
output:
|
|
13
15
|
- type: node
|
|
14
16
|
name: next
|
|
15
17
|
default: ""
|
|
18
|
+
- type: text
|
|
19
|
+
name: waitId
|
|
20
|
+
default: ""
|
|
21
|
+
required: true
|
|
22
|
+
showOnNode: true
|
|
16
23
|
- type: text
|
|
17
24
|
name: wakeAt
|
|
18
25
|
default: ""
|
|
26
|
+
required: true
|
|
27
|
+
showOnNode: true
|
|
19
28
|
---
|
|
20
29
|
${USER_PROMPT}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
#
|
|
2
|
+
# 内置节点:代码转布尔(本地脚本执行,★ 可扩展输入)
|
|
3
3
|
description: "Script-based boolean conversion: executes script to produce true/false prediction. Like tool_nodejs but enforces bool output. Must have script field."
|
|
4
|
-
displayName: ToBool
|
|
4
|
+
displayName: Code ToBool
|
|
5
5
|
input:
|
|
6
6
|
- type: node
|
|
7
7
|
name: prev
|
|
@@ -9,6 +9,8 @@ input:
|
|
|
9
9
|
- type: text
|
|
10
10
|
name: value
|
|
11
11
|
default: ""
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
12
14
|
output:
|
|
13
15
|
- type: node
|
|
14
16
|
name: next
|
|
@@ -16,6 +18,8 @@ output:
|
|
|
16
18
|
- type: bool
|
|
17
19
|
name: prediction
|
|
18
20
|
default: ""
|
|
21
|
+
required: true
|
|
22
|
+
showOnNode: true
|
|
19
23
|
extensible: true
|
|
20
24
|
---
|
|
21
25
|
${USER_PROMPT}
|
|
@@ -9,6 +9,8 @@ input:
|
|
|
9
9
|
- type: text
|
|
10
10
|
name: until
|
|
11
11
|
default: ""
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
12
14
|
- type: text
|
|
13
15
|
name: timezone
|
|
14
16
|
default: "Asia/Shanghai"
|
|
@@ -16,8 +18,15 @@ output:
|
|
|
16
18
|
- type: node
|
|
17
19
|
name: next
|
|
18
20
|
default: ""
|
|
21
|
+
- type: text
|
|
22
|
+
name: waitId
|
|
23
|
+
default: ""
|
|
24
|
+
required: true
|
|
25
|
+
showOnNode: true
|
|
19
26
|
- type: text
|
|
20
27
|
name: wakeAt
|
|
21
28
|
default: ""
|
|
29
|
+
required: true
|
|
30
|
+
showOnNode: true
|
|
22
31
|
---
|
|
23
32
|
${USER_PROMPT}
|
|
@@ -22,7 +22,6 @@ input:
|
|
|
22
22
|
- type: text
|
|
23
23
|
name: branch
|
|
24
24
|
default: ""
|
|
25
|
-
showOnNode: true
|
|
26
25
|
- type: text
|
|
27
26
|
name: targetDir
|
|
28
27
|
default: ""
|
|
@@ -38,6 +37,8 @@ input:
|
|
|
38
37
|
- type: text
|
|
39
38
|
name: workspaceContext
|
|
40
39
|
default: ""
|
|
40
|
+
required: true
|
|
41
|
+
showOnNode: true
|
|
41
42
|
output:
|
|
42
43
|
- type: node
|
|
43
44
|
name: next
|
|
@@ -57,8 +58,12 @@ output:
|
|
|
57
58
|
- type: text
|
|
58
59
|
name: workspaceContext
|
|
59
60
|
default: ""
|
|
61
|
+
required: true
|
|
62
|
+
showOnNode: true
|
|
60
63
|
- type: text
|
|
61
64
|
name: gitContext
|
|
62
65
|
default: ""
|
|
66
|
+
required: true
|
|
67
|
+
showOnNode: true
|
|
63
68
|
---
|
|
64
69
|
Clone or update `${repoUrl}` and output workspace/git contexts for the checked-out repository.
|
|
@@ -16,21 +16,22 @@ input:
|
|
|
16
16
|
- type: file
|
|
17
17
|
name: repoPath
|
|
18
18
|
default: ""
|
|
19
|
-
showOnNode: true
|
|
20
19
|
- type: text
|
|
21
20
|
name: branch
|
|
22
21
|
default: ""
|
|
23
|
-
showOnNode: true
|
|
24
22
|
- type: file
|
|
25
23
|
name: worktreePath
|
|
26
24
|
default: ""
|
|
27
25
|
- type: text
|
|
28
26
|
name: gitContext
|
|
29
27
|
default: ""
|
|
28
|
+
required: true
|
|
29
|
+
showOnNode: true
|
|
30
30
|
- type: text
|
|
31
31
|
name: workspaceContext
|
|
32
32
|
default: ""
|
|
33
33
|
required: true
|
|
34
|
+
showOnNode: true
|
|
34
35
|
output:
|
|
35
36
|
- type: node
|
|
36
37
|
name: next
|
|
@@ -47,8 +48,12 @@ output:
|
|
|
47
48
|
- type: text
|
|
48
49
|
name: workspaceContext
|
|
49
50
|
default: ""
|
|
51
|
+
required: true
|
|
52
|
+
showOnNode: true
|
|
50
53
|
- type: text
|
|
51
54
|
name: gitContext
|
|
52
55
|
default: ""
|
|
56
|
+
required: true
|
|
57
|
+
showOnNode: true
|
|
53
58
|
---
|
|
54
59
|
Load a Git worktree from `${repoPath}` and switch downstream workspace context to it.
|