@fieldwangai/agentflow 0.1.31 → 0.1.33
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/catalog-flows.mjs +33 -6
- package/bin/lib/composer-node-schema.mjs +7 -7
- package/bin/lib/composer-planner.mjs +5 -5
- package/bin/lib/git-worktree.mjs +248 -0
- package/bin/lib/gitlab-mr.mjs +174 -0
- package/bin/lib/locales/en.json +24 -0
- package/bin/lib/locales/zh.json +24 -0
- package/bin/lib/marketplace.mjs +230 -4
- package/bin/lib/paths.mjs +5 -0
- package/bin/lib/ui-server.mjs +298 -14
- package/bin/pipeline/pre-process-node.mjs +152 -11
- package/bin/pipeline/validate-flow.mjs +7 -17
- package/builtin/nodes/display_html.md +31 -0
- package/builtin/nodes/display_image.md +35 -0
- package/builtin/nodes/provide_bool.md +11 -0
- package/builtin/nodes/tool_git_checkout.md +8 -1
- package/builtin/nodes/tool_git_worktree_load.md +54 -0
- package/builtin/nodes/tool_git_worktree_unload.md +51 -0
- package/builtin/nodes/tool_gitlab_create_mr.md +113 -0
- package/builtin/web-ui/dist/assets/index-BWAb27N0.js +198 -0
- package/builtin/web-ui/dist/assets/index-DgfSfcjH.css +1 -0
- package/builtin/web-ui/dist/index.html +2 -2
- package/package.json +1 -1
- package/builtin/web-ui/dist/assets/index-BVWwQpvg.css +0 -1
- package/builtin/web-ui/dist/assets/index-CvNy1n3f.js +0 -197
package/bin/lib/ui-server.mjs
CHANGED
|
@@ -74,7 +74,16 @@ import {
|
|
|
74
74
|
import { runNodeScript } from "./pipeline-scripts.mjs";
|
|
75
75
|
import { readFlowSchedule, writeFlowSchedule } from "./schedule-config.mjs";
|
|
76
76
|
import { listScheduleStatuses } from "./scheduler.mjs";
|
|
77
|
-
import {
|
|
77
|
+
import {
|
|
78
|
+
deleteMarketplaceNodePackage,
|
|
79
|
+
installFlowDependency,
|
|
80
|
+
listMarketplaceFlowSnippets,
|
|
81
|
+
listMarketplacePackages,
|
|
82
|
+
publishFlowSnippet,
|
|
83
|
+
publishNodeFromInstance,
|
|
84
|
+
} from "./marketplace.mjs";
|
|
85
|
+
import { buildGitContext, loadGitWorktree, normalizeGitContext, runGit, unloadGitWorktree } from "./git-worktree.mjs";
|
|
86
|
+
import { createGitLabMergeRequest } from "./gitlab-mr.mjs";
|
|
78
87
|
import {
|
|
79
88
|
authSetupRequired,
|
|
80
89
|
buildClearSessionCookie,
|
|
@@ -439,6 +448,7 @@ function readBody(req) {
|
|
|
439
448
|
const WORKSPACE_FILE_SKIP_DIRS = new Set([
|
|
440
449
|
".git",
|
|
441
450
|
"node_modules",
|
|
451
|
+
"runBuild",
|
|
442
452
|
".next",
|
|
443
453
|
".nuxt",
|
|
444
454
|
".turbo",
|
|
@@ -447,6 +457,11 @@ const WORKSPACE_FILE_SKIP_DIRS = new Set([
|
|
|
447
457
|
"coverage",
|
|
448
458
|
]);
|
|
449
459
|
|
|
460
|
+
const WORKSPACE_FILE_SKIP_FILES = new Set([
|
|
461
|
+
"flow.yaml",
|
|
462
|
+
"workspace.graph.json",
|
|
463
|
+
]);
|
|
464
|
+
|
|
450
465
|
const WORKSPACE_TEXT_EXTS = new Set([
|
|
451
466
|
".md",
|
|
452
467
|
".markdown",
|
|
@@ -510,6 +525,7 @@ function readWorkspaceFilesRecursive(dir, root, depth = 0, maxDepth = 3, budget
|
|
|
510
525
|
children: readWorkspaceFilesRecursive(abs, root, depth + 1, maxDepth, budget),
|
|
511
526
|
});
|
|
512
527
|
} else if (entry.isFile()) {
|
|
528
|
+
if (WORKSPACE_FILE_SKIP_FILES.has(entry.name)) continue;
|
|
513
529
|
const ext = path.extname(entry.name).toLowerCase();
|
|
514
530
|
if (!WORKSPACE_TEXT_EXTS.has(ext)) continue;
|
|
515
531
|
let size = 0;
|
|
@@ -653,6 +669,39 @@ function workspaceSlotValue(slot) {
|
|
|
653
669
|
return "";
|
|
654
670
|
}
|
|
655
671
|
|
|
672
|
+
function workspaceSlotByName(instance, name) {
|
|
673
|
+
const slots = [...(Array.isArray(instance?.input) ? instance.input : []), ...(Array.isArray(instance?.output) ? instance.output : [])];
|
|
674
|
+
return slots.find((slot) => String(slot?.name || "") === String(name || "")) || null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function workspaceSetOutputSlot(instance, name, value) {
|
|
678
|
+
const text = String(value ?? "");
|
|
679
|
+
return {
|
|
680
|
+
...(instance || {}),
|
|
681
|
+
output: (Array.isArray(instance?.output) ? instance.output : []).map((slot) => (
|
|
682
|
+
String(slot?.name || "") === String(name || "") ? { ...slot, default: text, value: text } : slot
|
|
683
|
+
)),
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function workspaceResolvePath(baseCwd, raw) {
|
|
688
|
+
const text = String(raw || "").trim();
|
|
689
|
+
if (!text) return "";
|
|
690
|
+
return path.isAbsolute(text) ? path.resolve(text) : path.resolve(baseCwd, text);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function workspaceSanitizeRepoDirName(repoUrl) {
|
|
694
|
+
const raw = String(repoUrl || "").trim().replace(/\.git$/i, "");
|
|
695
|
+
const last = raw.split(/[/:]/).filter(Boolean).pop() || "repo";
|
|
696
|
+
return last.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
function workspaceBoolSlot(instance, name, defaultValue = false) {
|
|
700
|
+
const value = workspaceSlotValue(workspaceSlotByName(instance, name));
|
|
701
|
+
if (!value.trim()) return Boolean(defaultValue);
|
|
702
|
+
return ["true", "1", "yes", "on"].includes(value.trim().toLowerCase());
|
|
703
|
+
}
|
|
704
|
+
|
|
656
705
|
function workspaceInstanceText(instance) {
|
|
657
706
|
const body = String(instance?.body || "").trim();
|
|
658
707
|
if (body) return body;
|
|
@@ -666,10 +715,12 @@ function workspaceDisplayKind(definitionId) {
|
|
|
666
715
|
if (id === "display_markdown") return "markdown";
|
|
667
716
|
if (id === "display_mermaid") return "mermaid";
|
|
668
717
|
if (id === "display_ascii") return "ascii";
|
|
718
|
+
if (id === "display_html") return "html";
|
|
719
|
+
if (id === "display_image") return "image";
|
|
669
720
|
return "";
|
|
670
721
|
}
|
|
671
722
|
|
|
672
|
-
function
|
|
723
|
+
function workspaceRunPlan(graph, runNodeId) {
|
|
673
724
|
const instances = graph?.instances && typeof graph.instances === "object" ? graph.instances : {};
|
|
674
725
|
const edges = Array.isArray(graph?.edges) ? graph.edges : [];
|
|
675
726
|
const target = String(runNodeId || "").trim();
|
|
@@ -685,15 +736,20 @@ function workspaceRunOrder(graph, runNodeId) {
|
|
|
685
736
|
if (!downstream.has(source)) downstream.set(source, []);
|
|
686
737
|
downstream.get(source).push(dest);
|
|
687
738
|
}
|
|
688
|
-
const
|
|
739
|
+
const needed = new Set();
|
|
740
|
+
const pauseNodeIds = new Set();
|
|
689
741
|
const visit = (id) => {
|
|
690
|
-
if (!id ||
|
|
691
|
-
|
|
742
|
+
if (!id || needed.has(id)) return;
|
|
743
|
+
const defId = String(instances[id]?.definitionId || "");
|
|
744
|
+
if (id !== target && defId === "workspace_run") {
|
|
745
|
+
pauseNodeIds.add(id);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
needed.add(id);
|
|
692
749
|
for (const next of downstream.get(id) || []) visit(next);
|
|
693
750
|
};
|
|
694
751
|
visit(target);
|
|
695
|
-
|
|
696
|
-
const needed = reachable;
|
|
752
|
+
needed.delete(target);
|
|
697
753
|
const indegree = new Map(Array.from(needed).map((id) => [id, 0]));
|
|
698
754
|
for (const id of needed) {
|
|
699
755
|
for (const prev of upstream.get(id) || []) {
|
|
@@ -715,7 +771,7 @@ function workspaceRunOrder(graph, runNodeId) {
|
|
|
715
771
|
if (ordered.length !== needed.size) {
|
|
716
772
|
throw new Error("Workspace run graph contains a cycle");
|
|
717
773
|
}
|
|
718
|
-
return ordered;
|
|
774
|
+
return { order: ordered, pauseNodeIds: Array.from(pauseNodeIds) };
|
|
719
775
|
}
|
|
720
776
|
|
|
721
777
|
function workspaceUpstreamText(graph, nodeId, outputs) {
|
|
@@ -762,14 +818,16 @@ function workspaceUpstreamSkillBlocks(graph, nodeId, outputs) {
|
|
|
762
818
|
function workspaceWriteDisplayContent(instance, content) {
|
|
763
819
|
const next = { ...(instance || {}) };
|
|
764
820
|
const text = String(content || "");
|
|
821
|
+
const kind = workspaceDisplayKind(next.definitionId);
|
|
822
|
+
const primaryName = kind === "image" ? "src" : "content";
|
|
765
823
|
next.body = text;
|
|
766
824
|
next.input = (Array.isArray(next.input) ? next.input : []).map((slot) => (
|
|
767
|
-
String(slot?.name || "") ===
|
|
825
|
+
String(slot?.name || "") === primaryName || String(slot?.type || "") === "text"
|
|
768
826
|
? { ...slot, default: text, value: text }
|
|
769
827
|
: slot
|
|
770
828
|
));
|
|
771
829
|
next.output = (Array.isArray(next.output) ? next.output : []).map((slot) => (
|
|
772
|
-
String(slot?.name || "") ===
|
|
830
|
+
String(slot?.name || "") === primaryName || String(slot?.type || "") === "text"
|
|
773
831
|
? { ...slot, default: text, value: text }
|
|
774
832
|
: slot
|
|
775
833
|
));
|
|
@@ -808,7 +866,7 @@ function workspaceNodePrompt(graph, nodeId, upstreamText, skillsBlock) {
|
|
|
808
866
|
async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts = {}) {
|
|
809
867
|
const graph = normalizeWorkspaceGraphPayload(payload.graph || {});
|
|
810
868
|
const runNodeId = String(payload?.runNodeId || "").trim();
|
|
811
|
-
const order =
|
|
869
|
+
const { order, pauseNodeIds } = workspaceRunPlan(graph, runNodeId);
|
|
812
870
|
const fallbackSelectedSkillKeys = Array.isArray(payload?.selectedSkills)
|
|
813
871
|
? payload.selectedSkills.map((x) => String(x || "").trim()).filter(Boolean)
|
|
814
872
|
: [];
|
|
@@ -880,6 +938,14 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
880
938
|
continue;
|
|
881
939
|
}
|
|
882
940
|
|
|
941
|
+
if (defId === "provide_bool") {
|
|
942
|
+
const raw = workspaceSlotValue(Array.isArray(instance.output) ? instance.output[0] : null) || workspaceInstanceText(instance);
|
|
943
|
+
const content = ["true", "1", "yes", "on"].includes(String(raw || "").trim().toLowerCase()) ? "true" : "false";
|
|
944
|
+
outputs.set(nodeId, content);
|
|
945
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
|
|
883
949
|
if (defId === "provide_file") {
|
|
884
950
|
const fileValue = workspaceSlotValue(Array.isArray(instance.output) ? instance.output[0] : null) || workspaceInstanceText(instance);
|
|
885
951
|
const abs = path.resolve(scopedRoot, fileValue);
|
|
@@ -912,6 +978,179 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
912
978
|
continue;
|
|
913
979
|
}
|
|
914
980
|
|
|
981
|
+
if (defId === "tool_git_checkout") {
|
|
982
|
+
const repoUrl = workspaceSlotValue(workspaceSlotByName(instance, "repoUrl")).trim();
|
|
983
|
+
if (!repoUrl) throw new Error("Git Checkout requires repoUrl");
|
|
984
|
+
const branch = workspaceSlotValue(workspaceSlotByName(instance, "branch")).trim();
|
|
985
|
+
const targetRaw = workspaceSlotValue(workspaceSlotByName(instance, "targetDir")).trim();
|
|
986
|
+
const targetDir = targetRaw
|
|
987
|
+
? workspaceResolvePath(cwd, targetRaw)
|
|
988
|
+
: path.join(scopedRoot, ".workspace", "agentflow", "git-repos", workspaceSanitizeRepoDirName(repoUrl));
|
|
989
|
+
const pullIfExists = workspaceBoolSlot(instance, "pullIfExists", true);
|
|
990
|
+
const includeSubmodules = workspaceBoolSlot(instance, "includeSubmodules", false);
|
|
991
|
+
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
992
|
+
let changed = false;
|
|
993
|
+
if (fs.existsSync(path.join(targetDir, ".git"))) {
|
|
994
|
+
if (pullIfExists) {
|
|
995
|
+
const fetch = runGit(["fetch", "--all", "--prune"], targetDir);
|
|
996
|
+
if (fetch.status !== 0) throw new Error(`git fetch failed: ${fetch.stderr || fetch.stdout}`);
|
|
997
|
+
if (branch) {
|
|
998
|
+
const checkout = runGit(["checkout", branch], targetDir);
|
|
999
|
+
if (checkout.status !== 0) throw new Error(`git checkout failed: ${checkout.stderr || checkout.stdout}`);
|
|
1000
|
+
}
|
|
1001
|
+
const before = runGit(["rev-parse", "HEAD"], targetDir).stdout.trim();
|
|
1002
|
+
const pull = runGit(["pull", "--ff-only"], targetDir);
|
|
1003
|
+
if (pull.status !== 0) throw new Error(`git pull failed: ${pull.stderr || pull.stdout}`);
|
|
1004
|
+
const after = runGit(["rev-parse", "HEAD"], targetDir).stdout.trim();
|
|
1005
|
+
changed = before !== after;
|
|
1006
|
+
}
|
|
1007
|
+
} else {
|
|
1008
|
+
const args = ["clone"];
|
|
1009
|
+
if (includeSubmodules) args.push("--recurse-submodules");
|
|
1010
|
+
if (branch) args.push("--branch", branch);
|
|
1011
|
+
args.push(repoUrl, targetDir);
|
|
1012
|
+
const clone = runGit(args, cwd);
|
|
1013
|
+
if (clone.status !== 0) throw new Error(`git clone failed: ${clone.stderr || clone.stdout}`);
|
|
1014
|
+
changed = true;
|
|
1015
|
+
}
|
|
1016
|
+
if (includeSubmodules) {
|
|
1017
|
+
const submodule = runGit(["submodule", "update", "--init", "--recursive"], targetDir);
|
|
1018
|
+
if (submodule.status !== 0) throw new Error(`git submodule update failed: ${submodule.stderr || submodule.stdout}`);
|
|
1019
|
+
}
|
|
1020
|
+
const currentBranch = runGit(["rev-parse", "--abbrev-ref", "HEAD"], targetDir).stdout.trim();
|
|
1021
|
+
const commit = runGit(["rev-parse", "HEAD"], targetDir).stdout.trim();
|
|
1022
|
+
const remote = workspaceSlotValue(workspaceSlotByName(instance, "remote")).trim() || "origin";
|
|
1023
|
+
const gitContext = buildGitContext({
|
|
1024
|
+
repoPath: targetDir,
|
|
1025
|
+
branch: currentBranch === "HEAD" ? "DETACHED" : currentBranch,
|
|
1026
|
+
commit,
|
|
1027
|
+
remote,
|
|
1028
|
+
});
|
|
1029
|
+
const previousCwd = cwd;
|
|
1030
|
+
cwd = path.resolve(targetDir);
|
|
1031
|
+
let nextInstance = workspaceSetOutputSlot(instance, "repoPath", targetDir);
|
|
1032
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "branch", gitContext.branch);
|
|
1033
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "commit", commit);
|
|
1034
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "changed", changed ? "true" : "false");
|
|
1035
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "gitContext", JSON.stringify(gitContext));
|
|
1036
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "workspaceContext", JSON.stringify({
|
|
1037
|
+
version: 1,
|
|
1038
|
+
label: workspaceSanitizeRepoDirName(repoUrl),
|
|
1039
|
+
cwd,
|
|
1040
|
+
workspaceRoot: cwd,
|
|
1041
|
+
pipelineWorkspace: scopedRoot,
|
|
1042
|
+
previous: { version: 1, label: "workspace", cwd: previousCwd, workspaceRoot: previousCwd, pipelineWorkspace: scopedRoot, previous: null },
|
|
1043
|
+
}));
|
|
1044
|
+
graph.instances[nodeId] = nextInstance;
|
|
1045
|
+
outputs.set(nodeId, targetDir);
|
|
1046
|
+
emit({ type: "graph", nodeId, graph });
|
|
1047
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
1048
|
+
continue;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
if (defId === "tool_git_worktree_load") {
|
|
1052
|
+
const gitContext = normalizeGitContext(workspaceSlotValue(workspaceSlotByName(instance, "gitContext")));
|
|
1053
|
+
const repoPath = workspaceResolvePath(cwd, workspaceSlotValue(workspaceSlotByName(instance, "repoPath"))) ||
|
|
1054
|
+
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "");
|
|
1055
|
+
if (!repoPath) throw new Error("Load Worktree requires repoPath");
|
|
1056
|
+
const branch = workspaceSlotValue(workspaceSlotByName(instance, "branch")).trim();
|
|
1057
|
+
const rawWorktreePath = workspaceSlotValue(workspaceSlotByName(instance, "worktreePath")).trim();
|
|
1058
|
+
const worktreePath = rawWorktreePath ? workspaceResolvePath(cwd, rawWorktreePath) : (gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "");
|
|
1059
|
+
const previousCwd = cwd;
|
|
1060
|
+
const result = loadGitWorktree({ repoPath, branch, worktreePath, pipelineWorkspace: scopedRoot });
|
|
1061
|
+
const outGitContext = buildGitContext({
|
|
1062
|
+
repoPath: result.repoRoot,
|
|
1063
|
+
worktreePath: result.worktreePath,
|
|
1064
|
+
branch: result.branch,
|
|
1065
|
+
commit: result.commit,
|
|
1066
|
+
remote: gitContext?.remote || "origin",
|
|
1067
|
+
remoteUrl: gitContext?.remoteUrl || "",
|
|
1068
|
+
});
|
|
1069
|
+
cwd = result.worktreePath;
|
|
1070
|
+
let nextInstance = workspaceSetOutputSlot(instance, "worktreePath", result.worktreePath);
|
|
1071
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "branch", result.branch);
|
|
1072
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "commit", result.commit);
|
|
1073
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "gitContext", JSON.stringify(outGitContext));
|
|
1074
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "workspaceContext", JSON.stringify({
|
|
1075
|
+
version: 1,
|
|
1076
|
+
label: result.branch === "DETACHED" ? `worktree:${result.commit.slice(0, 8)}` : `worktree:${result.branch}`,
|
|
1077
|
+
cwd: result.worktreePath,
|
|
1078
|
+
workspaceRoot: result.worktreePath,
|
|
1079
|
+
pipelineWorkspace: scopedRoot,
|
|
1080
|
+
previous: { version: 1, label: "workspace", cwd: previousCwd, workspaceRoot: previousCwd, pipelineWorkspace: scopedRoot, previous: null },
|
|
1081
|
+
}));
|
|
1082
|
+
graph.instances[nodeId] = nextInstance;
|
|
1083
|
+
outputs.set(nodeId, result.worktreePath);
|
|
1084
|
+
emit({ type: "graph", nodeId, graph });
|
|
1085
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
1086
|
+
continue;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
if (defId === "tool_git_worktree_unload") {
|
|
1090
|
+
const gitContext = normalizeGitContext(workspaceSlotValue(workspaceSlotByName(instance, "gitContext")));
|
|
1091
|
+
const repoPath = workspaceResolvePath(cwd, workspaceSlotValue(workspaceSlotByName(instance, "repoPath"))) ||
|
|
1092
|
+
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "");
|
|
1093
|
+
const worktreePath = workspaceResolvePath(cwd, workspaceSlotValue(workspaceSlotByName(instance, "worktreePath"))) ||
|
|
1094
|
+
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "");
|
|
1095
|
+
if (!repoPath) throw new Error("Unload Worktree requires repoPath");
|
|
1096
|
+
if (!worktreePath) throw new Error("Unload Worktree requires worktreePath");
|
|
1097
|
+
const force = ["true", "1", "yes", "on"].includes(workspaceSlotValue(workspaceSlotByName(instance, "force")).trim().toLowerCase());
|
|
1098
|
+
const pruneRaw = workspaceSlotValue(workspaceSlotByName(instance, "prune")).trim().toLowerCase();
|
|
1099
|
+
const prune = pruneRaw !== "false";
|
|
1100
|
+
const result = unloadGitWorktree({ repoPath, worktreePath, force, prune });
|
|
1101
|
+
cwd = scopedRoot;
|
|
1102
|
+
let nextInstance = workspaceSetOutputSlot(instance, "removed", "true");
|
|
1103
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "message", result.message);
|
|
1104
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "workspaceContext", JSON.stringify({
|
|
1105
|
+
version: 1,
|
|
1106
|
+
label: "workspace",
|
|
1107
|
+
cwd,
|
|
1108
|
+
workspaceRoot: cwd,
|
|
1109
|
+
pipelineWorkspace: scopedRoot,
|
|
1110
|
+
previous: null,
|
|
1111
|
+
}));
|
|
1112
|
+
graph.instances[nodeId] = nextInstance;
|
|
1113
|
+
outputs.set(nodeId, result.message);
|
|
1114
|
+
emit({ type: "graph", nodeId, graph });
|
|
1115
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
if (defId === "tool_gitlab_create_mr") {
|
|
1120
|
+
const gitContext = normalizeGitContext(workspaceSlotValue(workspaceSlotByName(instance, "gitContext")));
|
|
1121
|
+
const repoPath = workspaceResolvePath(cwd, workspaceSlotValue(workspaceSlotByName(instance, "repoPath")));
|
|
1122
|
+
const result = await createGitLabMergeRequest({
|
|
1123
|
+
gitContext,
|
|
1124
|
+
workspaceCwd: cwd,
|
|
1125
|
+
repoPath,
|
|
1126
|
+
sourceBranch: workspaceSlotValue(workspaceSlotByName(instance, "sourceBranch")),
|
|
1127
|
+
targetBranch: workspaceSlotValue(workspaceSlotByName(instance, "targetBranch")),
|
|
1128
|
+
title: workspaceSlotValue(workspaceSlotByName(instance, "title")),
|
|
1129
|
+
description: workspaceSlotValue(workspaceSlotByName(instance, "description")),
|
|
1130
|
+
draft: workspaceSlotValue(workspaceSlotByName(instance, "draft")),
|
|
1131
|
+
labels: workspaceSlotValue(workspaceSlotByName(instance, "labels")),
|
|
1132
|
+
push: workspaceSlotValue(workspaceSlotByName(instance, "push")),
|
|
1133
|
+
remote: workspaceSlotValue(workspaceSlotByName(instance, "remote")),
|
|
1134
|
+
tokenEnv: workspaceSlotValue(workspaceSlotByName(instance, "tokenEnv")),
|
|
1135
|
+
gitlabApiBase: workspaceSlotValue(workspaceSlotByName(instance, "gitlabApiBase")),
|
|
1136
|
+
removeSourceBranch: workspaceSlotValue(workspaceSlotByName(instance, "removeSourceBranch")),
|
|
1137
|
+
squash: workspaceSlotValue(workspaceSlotByName(instance, "squash")),
|
|
1138
|
+
}, runtimeEnvForUser(userCtx));
|
|
1139
|
+
let nextInstance = workspaceSetOutputSlot(instance, "mrUrl", result.mrUrl);
|
|
1140
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "created", result.created ? "true" : "false");
|
|
1141
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "mrIid", result.mrIid ?? "");
|
|
1142
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "projectId", result.projectId ?? "");
|
|
1143
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "sourceBranch", result.sourceBranch ?? "");
|
|
1144
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "targetBranch", result.targetBranch ?? "");
|
|
1145
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "title", result.title ?? "");
|
|
1146
|
+
nextInstance = workspaceSetOutputSlot(nextInstance, "message", result.message ?? "");
|
|
1147
|
+
graph.instances[nodeId] = nextInstance;
|
|
1148
|
+
outputs.set(nodeId, result.mrUrl);
|
|
1149
|
+
emit({ type: "graph", nodeId, graph });
|
|
1150
|
+
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
1151
|
+
continue;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
915
1154
|
const upstreamText = workspaceUpstreamText(graph, nodeId, outputs);
|
|
916
1155
|
const body = String(instance.body || "").trim();
|
|
917
1156
|
if (defId === "agent_subAgent" && !body && !String(upstreamText || "").trim()) {
|
|
@@ -956,8 +1195,11 @@ async function runWorkspaceGraph(root, scopedRoot, payload, userCtx = {}, opts =
|
|
|
956
1195
|
if (updatedDisplays.length) emit({ type: "graph", nodeId, displayNodeIds: updatedDisplays, graph });
|
|
957
1196
|
emit({ type: "node-done", nodeId, definitionId: defId });
|
|
958
1197
|
}
|
|
1198
|
+
if (pauseNodeIds.length > 0) {
|
|
1199
|
+
emit({ type: "paused", nodeIds: pauseNodeIds, message: `Workspace run paused at ${pauseNodeIds.join(", ")}` });
|
|
1200
|
+
}
|
|
959
1201
|
graph.updatedAt = new Date().toISOString();
|
|
960
|
-
return { graph, events, order };
|
|
1202
|
+
return { graph, events, order, pauseNodeIds };
|
|
961
1203
|
}
|
|
962
1204
|
|
|
963
1205
|
function isTransientAgentNetworkError(err) {
|
|
@@ -1609,7 +1851,7 @@ export function startUiServer({
|
|
|
1609
1851
|
try {
|
|
1610
1852
|
const result = await runWorkspaceGraph(root, scoped.root, payload, userCtx, { onEvent: writeEvent });
|
|
1611
1853
|
fs.writeFileSync(graphPath, JSON.stringify(result.graph, null, 2) + "\n", "utf-8");
|
|
1612
|
-
writeEvent({ type: "done", ok: true, path: graphPath, graph: result.graph, order: result.order });
|
|
1854
|
+
writeEvent({ type: "done", ok: true, path: graphPath, graph: result.graph, order: result.order, pauseNodeIds: result.pauseNodeIds || [] });
|
|
1613
1855
|
res.end();
|
|
1614
1856
|
} catch (e) {
|
|
1615
1857
|
writeEvent({ type: "error", error: (e && e.message) || String(e) });
|
|
@@ -2280,13 +2522,38 @@ export function startUiServer({
|
|
|
2280
2522
|
|
|
2281
2523
|
if (req.method === "GET" && url.pathname === "/api/marketplace/nodes") {
|
|
2282
2524
|
try {
|
|
2283
|
-
json(res, 200, listMarketplacePackages(root));
|
|
2525
|
+
json(res, 200, listMarketplacePackages(root, userCtx));
|
|
2284
2526
|
} catch (e) {
|
|
2285
2527
|
json(res, 500, { error: (e && e.message) || String(e) });
|
|
2286
2528
|
}
|
|
2287
2529
|
return;
|
|
2288
2530
|
}
|
|
2289
2531
|
|
|
2532
|
+
if (req.method === "GET" && url.pathname === "/api/marketplace/flow-snippets") {
|
|
2533
|
+
try {
|
|
2534
|
+
json(res, 200, listMarketplaceFlowSnippets(root));
|
|
2535
|
+
} catch (e) {
|
|
2536
|
+
json(res, 500, { error: (e && e.message) || String(e) });
|
|
2537
|
+
}
|
|
2538
|
+
return;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
if (req.method === "DELETE" && url.pathname === "/api/marketplace/node") {
|
|
2542
|
+
const id = url.searchParams.get("id") || "";
|
|
2543
|
+
const version = url.searchParams.get("version") || "";
|
|
2544
|
+
if (!id || !version) {
|
|
2545
|
+
json(res, 400, { ok: false, error: "Missing marketplace node id or version" });
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
try {
|
|
2549
|
+
const result = deleteMarketplaceNodePackage(root, id, version, userCtx);
|
|
2550
|
+
json(res, result.ok ? 200 : 400, result);
|
|
2551
|
+
} catch (e) {
|
|
2552
|
+
json(res, 500, { ok: false, error: (e && e.message) || String(e) });
|
|
2553
|
+
}
|
|
2554
|
+
return;
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2290
2557
|
if (req.method === "POST" && url.pathname === "/api/marketplace/install-node") {
|
|
2291
2558
|
let payload;
|
|
2292
2559
|
try {
|
|
@@ -2349,6 +2616,23 @@ export function startUiServer({
|
|
|
2349
2616
|
return;
|
|
2350
2617
|
}
|
|
2351
2618
|
|
|
2619
|
+
if (req.method === "POST" && url.pathname === "/api/marketplace/publish-flow-snippet") {
|
|
2620
|
+
let payload;
|
|
2621
|
+
try {
|
|
2622
|
+
payload = JSON.parse(await readBody(req));
|
|
2623
|
+
} catch {
|
|
2624
|
+
json(res, 400, { error: "Invalid JSON body" });
|
|
2625
|
+
return;
|
|
2626
|
+
}
|
|
2627
|
+
try {
|
|
2628
|
+
const result = publishFlowSnippet(root, payload || {});
|
|
2629
|
+
json(res, result.ok ? 200 : 400, result);
|
|
2630
|
+
} catch (e) {
|
|
2631
|
+
json(res, 500, { ok: false, error: (e && e.message) || String(e) });
|
|
2632
|
+
}
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2352
2636
|
if (req.method === "GET" && url.pathname === "/api/flow") {
|
|
2353
2637
|
const flowId = url.searchParams.get("flowId");
|
|
2354
2638
|
const flowSource = url.searchParams.get("flowSource") || "user";
|
|
@@ -41,12 +41,15 @@ import { getRunDir, sanitizeAgentflowUserId } from "../lib/paths.mjs";
|
|
|
41
41
|
import {
|
|
42
42
|
buildSkillsContext,
|
|
43
43
|
buildSkillsContextFromRegistry,
|
|
44
|
+
buildDefaultWorkspaceContext,
|
|
44
45
|
expandRuntimePlaceholders,
|
|
45
46
|
normalizeSkillsContext,
|
|
46
47
|
normalizeWorkspaceContext,
|
|
47
48
|
parseSkillKeyList,
|
|
48
49
|
resolveWorkspaceTarget,
|
|
49
50
|
} from "../lib/runtime-context.mjs";
|
|
51
|
+
import { buildGitContext, loadGitWorktree, normalizeGitContext, unloadGitWorktree } from "../lib/git-worktree.mjs";
|
|
52
|
+
import { createGitLabMergeRequest } from "../lib/gitlab-mr.mjs";
|
|
50
53
|
|
|
51
54
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
52
55
|
|
|
@@ -264,6 +267,12 @@ function isTruthyInput(value) {
|
|
|
264
267
|
return text === "true" || text === "1" || text === "yes" || text === "y" || text === "on";
|
|
265
268
|
}
|
|
266
269
|
|
|
270
|
+
function resolveMaybeWorkspacePath(raw, workspaceContext, extra = {}) {
|
|
271
|
+
const text = String(raw || "").trim();
|
|
272
|
+
if (!text) return "";
|
|
273
|
+
return resolveWorkspaceTarget(text, workspaceContext, extra);
|
|
274
|
+
}
|
|
275
|
+
|
|
267
276
|
function emitGitCheckoutNode(workspaceRoot, flowName, uuid, instanceId, execId, resultPathRel) {
|
|
268
277
|
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
269
278
|
const { inputs, workspaceContext } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
@@ -312,6 +321,12 @@ function emitGitCheckoutNode(workspaceRoot, flowName, uuid, instanceId, execId,
|
|
|
312
321
|
|
|
313
322
|
const currentBranch = runGit(["rev-parse", "--abbrev-ref", "HEAD"], targetDir).stdout.trim();
|
|
314
323
|
const commit = runGit(["rev-parse", "HEAD"], targetDir).stdout.trim();
|
|
324
|
+
const gitContext = buildGitContext({
|
|
325
|
+
repoPath: targetDir,
|
|
326
|
+
branch: currentBranch === "HEAD" ? "DETACHED" : currentBranch,
|
|
327
|
+
commit,
|
|
328
|
+
remote: String(inputs.remote || "origin").trim() || "origin",
|
|
329
|
+
});
|
|
315
330
|
const outWorkspaceContext = {
|
|
316
331
|
version: 1,
|
|
317
332
|
label: inputs.label || sanitizeRepoDirName(repoUrl),
|
|
@@ -326,10 +341,127 @@ function emitGitCheckoutNode(workspaceRoot, flowName, uuid, instanceId, execId,
|
|
|
326
341
|
writeOutputSlot(runDir, instanceId, execId, "commit", commit);
|
|
327
342
|
writeOutputSlot(runDir, instanceId, execId, "changed", changed ? "true" : "false");
|
|
328
343
|
writeOutputSlot(runDir, instanceId, execId, "workspaceContext", JSON.stringify(outWorkspaceContext));
|
|
344
|
+
writeOutputSlot(runDir, instanceId, execId, "gitContext", JSON.stringify(gitContext));
|
|
329
345
|
writeResult(workspaceRoot, flowName, uuid, instanceId, { status: "success", message: `git ${action}: ${currentBranch}@${commit.slice(0, 8)}` }, { execId });
|
|
330
346
|
return emitLocalNoopPrompt(workspaceRoot, runDir, instanceId, "git-checkout", `Git checkout completed: ${targetDir}\n`);
|
|
331
347
|
}
|
|
332
348
|
|
|
349
|
+
function requireWorkspaceContextInput(inputs, definitionId) {
|
|
350
|
+
if (!String(inputs?.workspaceContext || "").trim()) {
|
|
351
|
+
throw new Error(`${definitionId}: workspaceContext is required`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function emitGitWorktreeLoadNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
356
|
+
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
357
|
+
const { inputs, workspaceContext } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
358
|
+
requireWorkspaceContextInput(inputs, "tool_git_worktree_load");
|
|
359
|
+
const gitContext = normalizeGitContext(inputs.gitContext);
|
|
360
|
+
const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext) ||
|
|
361
|
+
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "");
|
|
362
|
+
if (!repoPath) throw new Error("tool_git_worktree_load: repoPath or gitContext.repoPath is required");
|
|
363
|
+
const branch = String(inputs.branch || "").trim();
|
|
364
|
+
const worktreePath = resolveMaybeWorkspacePath(inputs.worktreePath, workspaceContext, { branch }) ||
|
|
365
|
+
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "");
|
|
366
|
+
const result = loadGitWorktree({
|
|
367
|
+
repoPath,
|
|
368
|
+
branch,
|
|
369
|
+
worktreePath,
|
|
370
|
+
pipelineWorkspace: workspaceContext.pipelineWorkspace || path.resolve(workspaceRoot),
|
|
371
|
+
});
|
|
372
|
+
const outWorkspaceContext = {
|
|
373
|
+
version: 1,
|
|
374
|
+
label: result.branch === "DETACHED" ? `worktree:${result.commit.slice(0, 8)}` : `worktree:${result.branch}`,
|
|
375
|
+
cwd: result.worktreePath,
|
|
376
|
+
workspaceRoot: result.worktreePath,
|
|
377
|
+
pipelineWorkspace: workspaceContext.pipelineWorkspace || path.resolve(workspaceRoot),
|
|
378
|
+
flowDir: workspaceContext.flowDir,
|
|
379
|
+
previous: workspaceContext,
|
|
380
|
+
};
|
|
381
|
+
const outGitContext = buildGitContext({
|
|
382
|
+
repoPath: result.repoRoot,
|
|
383
|
+
worktreePath: result.worktreePath,
|
|
384
|
+
branch: result.branch,
|
|
385
|
+
commit: result.commit,
|
|
386
|
+
remote: gitContext?.remote || "origin",
|
|
387
|
+
remoteUrl: gitContext?.remoteUrl || "",
|
|
388
|
+
});
|
|
389
|
+
writeOutputSlot(runDir, instanceId, execId, "worktreePath", result.worktreePath);
|
|
390
|
+
writeOutputSlot(runDir, instanceId, execId, "branch", result.branch);
|
|
391
|
+
writeOutputSlot(runDir, instanceId, execId, "commit", result.commit);
|
|
392
|
+
writeOutputSlot(runDir, instanceId, execId, "workspaceContext", JSON.stringify(outWorkspaceContext));
|
|
393
|
+
writeOutputSlot(runDir, instanceId, execId, "gitContext", JSON.stringify(outGitContext));
|
|
394
|
+
writeResult(workspaceRoot, flowName, uuid, instanceId, {
|
|
395
|
+
status: "success",
|
|
396
|
+
message: `worktree loaded: ${result.worktreePath} (${result.branch}@${result.commit.slice(0, 8)})`,
|
|
397
|
+
}, { execId });
|
|
398
|
+
return emitLocalNoopPrompt(workspaceRoot, runDir, instanceId, "git-worktree-load", `Git worktree loaded: ${result.worktreePath}\n`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function emitGitWorktreeUnloadNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
402
|
+
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
403
|
+
const { inputs, workspaceContext, flowJson } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
404
|
+
requireWorkspaceContextInput(inputs, "tool_git_worktree_unload");
|
|
405
|
+
const gitContext = normalizeGitContext(inputs.gitContext);
|
|
406
|
+
const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext) ||
|
|
407
|
+
(gitContext?.repoPath ? path.resolve(gitContext.repoPath) : "");
|
|
408
|
+
const worktreePath = resolveMaybeWorkspacePath(inputs.worktreePath, workspaceContext) ||
|
|
409
|
+
(gitContext?.worktreePath ? path.resolve(gitContext.worktreePath) : "");
|
|
410
|
+
if (!repoPath) throw new Error("tool_git_worktree_unload: repoPath or gitContext.repoPath is required");
|
|
411
|
+
if (!worktreePath) throw new Error("tool_git_worktree_unload: worktreePath or gitContext.worktreePath is required");
|
|
412
|
+
const force = isTruthyInput(inputs.force);
|
|
413
|
+
const prune = String(inputs.prune ?? "true").trim().toLowerCase() !== "false";
|
|
414
|
+
const result = unloadGitWorktree({ repoPath, worktreePath, force, prune });
|
|
415
|
+
const nextWorkspaceContext = workspaceContext.previous
|
|
416
|
+
? normalizeWorkspaceContext(workspaceContext.previous, workspaceRoot, flowName, flowJson)
|
|
417
|
+
: buildDefaultWorkspaceContext(workspaceRoot, flowName, flowJson);
|
|
418
|
+
writeOutputSlot(runDir, instanceId, execId, "removed", "true");
|
|
419
|
+
writeOutputSlot(runDir, instanceId, execId, "message", result.message);
|
|
420
|
+
writeOutputSlot(runDir, instanceId, execId, "workspaceContext", JSON.stringify(nextWorkspaceContext));
|
|
421
|
+
writeResult(workspaceRoot, flowName, uuid, instanceId, {
|
|
422
|
+
status: "success",
|
|
423
|
+
message: result.message,
|
|
424
|
+
}, { execId });
|
|
425
|
+
return emitLocalNoopPrompt(workspaceRoot, runDir, instanceId, "git-worktree-unload", `${result.message}\n`);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async function emitGitLabCreateMrNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
429
|
+
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
430
|
+
const { inputs, workspaceContext } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
431
|
+
const repoPath = resolveMaybeWorkspacePath(inputs.repoPath, workspaceContext);
|
|
432
|
+
const result = await createGitLabMergeRequest({
|
|
433
|
+
gitContext: inputs.gitContext,
|
|
434
|
+
workspaceCwd: workspaceContext.cwd,
|
|
435
|
+
repoPath,
|
|
436
|
+
sourceBranch: inputs.sourceBranch,
|
|
437
|
+
targetBranch: inputs.targetBranch,
|
|
438
|
+
title: inputs.title,
|
|
439
|
+
description: inputs.description,
|
|
440
|
+
draft: inputs.draft,
|
|
441
|
+
labels: inputs.labels,
|
|
442
|
+
push: inputs.push,
|
|
443
|
+
remote: inputs.remote,
|
|
444
|
+
tokenEnv: inputs.tokenEnv,
|
|
445
|
+
gitlabApiBase: inputs.gitlabApiBase,
|
|
446
|
+
removeSourceBranch: inputs.removeSourceBranch,
|
|
447
|
+
squash: inputs.squash,
|
|
448
|
+
}, process.env);
|
|
449
|
+
writeOutputSlot(runDir, instanceId, execId, "mrUrl", result.mrUrl);
|
|
450
|
+
writeOutputSlot(runDir, instanceId, execId, "created", result.created ? "true" : "false");
|
|
451
|
+
writeOutputSlot(runDir, instanceId, execId, "mrIid", result.mrIid ?? "");
|
|
452
|
+
writeOutputSlot(runDir, instanceId, execId, "projectId", result.projectId ?? "");
|
|
453
|
+
writeOutputSlot(runDir, instanceId, execId, "sourceBranch", result.sourceBranch ?? "");
|
|
454
|
+
writeOutputSlot(runDir, instanceId, execId, "targetBranch", result.targetBranch ?? "");
|
|
455
|
+
writeOutputSlot(runDir, instanceId, execId, "title", result.title ?? "");
|
|
456
|
+
writeOutputSlot(runDir, instanceId, execId, "message", result.message ?? "");
|
|
457
|
+
writeResult(workspaceRoot, flowName, uuid, instanceId, {
|
|
458
|
+
status: "success",
|
|
459
|
+
message: result.message || result.mrUrl,
|
|
460
|
+
body: result.mrUrl,
|
|
461
|
+
}, { execId });
|
|
462
|
+
return emitLocalNoopPrompt(workspaceRoot, runDir, instanceId, "gitlab-create-mr", `${result.message || "GitLab MR ready"}\n${result.mrUrl}\n`);
|
|
463
|
+
}
|
|
464
|
+
|
|
333
465
|
function emitCdWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
334
466
|
const runDir = getRunDir(workspaceRoot, flowName, uuid);
|
|
335
467
|
const { inputs, workspaceContext } = resolveNodeRuntimeContexts(workspaceRoot, flowName, uuid, instanceId);
|
|
@@ -461,7 +593,7 @@ function emitToolPrintNode(workspaceRoot, flowName, uuid, instanceId, execId) {
|
|
|
461
593
|
const flowJson = readFlowJsonObject(workspaceRoot, flowName, uuid);
|
|
462
594
|
const data = getResolvedValues(workspaceRoot, flowName, uuid, instanceId);
|
|
463
595
|
const inputs = data.ok ? (data.resolvedInputs || {}) : {};
|
|
464
|
-
const skipNames = new Set(["prev", "next", "workspaceContext", "skillsContext", "workspaceRoot", "pipelineWorkspace", "flowName", "runDir", "flowDir", "cwd"]);
|
|
596
|
+
const skipNames = new Set(["prev", "next", "workspaceContext", "gitContext", "skillsContext", "workspaceRoot", "pipelineWorkspace", "flowName", "runDir", "flowDir", "cwd"]);
|
|
465
597
|
|
|
466
598
|
let content = readPrintableValue(inputs.content, runDir);
|
|
467
599
|
if (!content) {
|
|
@@ -681,7 +813,7 @@ ${directCommand}
|
|
|
681
813
|
return { optionalPromptPath: relativePath.replace(/\\/g, "/"), directCommand };
|
|
682
814
|
}
|
|
683
815
|
|
|
684
|
-
function main() {
|
|
816
|
+
async function main() {
|
|
685
817
|
const args = process.argv.slice(2);
|
|
686
818
|
if (args.length < 4) {
|
|
687
819
|
console.error(
|
|
@@ -1001,18 +1133,24 @@ function main() {
|
|
|
1001
1133
|
return;
|
|
1002
1134
|
}
|
|
1003
1135
|
|
|
1004
|
-
if (definitionId === "tool_git_checkout" || definitionId === "control_cd_workspace" || definitionId === "control_user_workspace" || definitionId === "control_load_skills" || definitionId === "tool_print") {
|
|
1136
|
+
if (definitionId === "tool_git_checkout" || definitionId === "tool_git_worktree_load" || definitionId === "tool_git_worktree_unload" || definitionId === "tool_gitlab_create_mr" || definitionId === "control_cd_workspace" || definitionId === "control_user_workspace" || definitionId === "control_load_skills" || definitionId === "tool_print") {
|
|
1005
1137
|
try {
|
|
1006
1138
|
const promptPath =
|
|
1007
1139
|
definitionId === "tool_git_checkout"
|
|
1008
1140
|
? emitGitCheckoutNode(workspaceRoot, flowName, uuid, instanceId, execId, resultPathRel)
|
|
1009
|
-
: definitionId === "
|
|
1010
|
-
?
|
|
1011
|
-
: definitionId === "
|
|
1012
|
-
?
|
|
1013
|
-
: definitionId === "
|
|
1014
|
-
?
|
|
1015
|
-
:
|
|
1141
|
+
: definitionId === "tool_git_worktree_load"
|
|
1142
|
+
? emitGitWorktreeLoadNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1143
|
+
: definitionId === "tool_git_worktree_unload"
|
|
1144
|
+
? emitGitWorktreeUnloadNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1145
|
+
: definitionId === "tool_gitlab_create_mr"
|
|
1146
|
+
? await emitGitLabCreateMrNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1147
|
+
: definitionId === "control_cd_workspace"
|
|
1148
|
+
? emitCdWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1149
|
+
: definitionId === "control_user_workspace"
|
|
1150
|
+
? emitUserWorkspaceNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1151
|
+
: definitionId === "control_load_skills"
|
|
1152
|
+
? emitLoadSkillsNode(workspaceRoot, flowName, uuid, instanceId, execId)
|
|
1153
|
+
: emitToolPrintNode(workspaceRoot, flowName, uuid, instanceId, execId);
|
|
1016
1154
|
writeCacheJsonForNode(workspaceRoot, flowName, uuid, instanceId, execId);
|
|
1017
1155
|
logToRunTag(workspaceRoot, flowName, uuid, "pre-process", { event: "runtime-context-node", instanceId, definitionId });
|
|
1018
1156
|
console.log(JSON.stringify({
|
|
@@ -1103,4 +1241,7 @@ function main() {
|
|
|
1103
1241
|
console.log(JSON.stringify(output));
|
|
1104
1242
|
}
|
|
1105
1243
|
|
|
1106
|
-
main()
|
|
1244
|
+
main().catch((e) => {
|
|
1245
|
+
console.error(JSON.stringify({ ok: false, error: e.message || String(e) }));
|
|
1246
|
+
process.exit(1);
|
|
1247
|
+
});
|