@fieldwangai/agentflow 0.1.32 → 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 +7 -2
- 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 +106 -2
- package/bin/lib/paths.mjs +5 -0
- package/bin/lib/ui-server.mjs +281 -13
- 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-D0Tkhqr6.css +0 -1
- package/builtin/web-ui/dist/assets/index-DyhW5chp.js +0 -197
|
@@ -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
|
+
});
|
|
@@ -493,26 +493,16 @@ function checkFlowCore(nodes, edges, flowDir, nodeIdToSlots, getNodeBody, instan
|
|
|
493
493
|
}
|
|
494
494
|
}
|
|
495
495
|
|
|
496
|
-
// provide_str / provide_file output 类型校验
|
|
497
|
-
if (defId === "provide_str") {
|
|
496
|
+
// provide_str / provide_file / provide_bool output 类型校验
|
|
497
|
+
if (defId === "provide_str" || defId === "provide_file" || defId === "provide_bool") {
|
|
498
498
|
const out = Array.isArray(inst.output) ? inst.output : [];
|
|
499
|
+
const expectedType = defId === "provide_file" ? "file" : defId === "provide_bool" ? "bool" : "text";
|
|
499
500
|
if (out.length !== 1) {
|
|
500
|
-
errors.push(`节点 "${n.id}"
|
|
501
|
+
errors.push(`节点 "${n.id}"(${defId})output 必须仅有 1 个槽位(value:${expectedType}),当前 ${out.length} 个`);
|
|
501
502
|
} else {
|
|
502
503
|
const t0 = normType(out[0] && out[0].type);
|
|
503
|
-
if (t0 !==
|
|
504
|
-
errors.push(`节点 "${n.id}"
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
if (defId === "provide_file") {
|
|
509
|
-
const out = Array.isArray(inst.output) ? inst.output : [];
|
|
510
|
-
if (out.length !== 1) {
|
|
511
|
-
errors.push(`节点 "${n.id}"(provide_file)output 必须仅有 1 个槽位(value:file),当前 ${out.length} 个`);
|
|
512
|
-
} else {
|
|
513
|
-
const t0 = normType(out[0] && out[0].type);
|
|
514
|
-
if (t0 !== "file") {
|
|
515
|
-
errors.push(`节点 "${n.id}"(provide_file)output[0].type 必须为 \`file\`,当前为 \`${t0 || "(空)"}\``);
|
|
504
|
+
if (t0 !== expectedType) {
|
|
505
|
+
errors.push(`节点 "${n.id}"(${defId})output[0].type 必须为 \`${expectedType}\`,当前为 \`${t0 || "(空)"}\``);
|
|
516
506
|
}
|
|
517
507
|
}
|
|
518
508
|
}
|
|
@@ -675,7 +665,7 @@ function computeValidation(loaded, workspaceRoot) {
|
|
|
675
665
|
if (!isNodeEdge) continue;
|
|
676
666
|
if (srcDef.startsWith("provide_") || tgtDef.startsWith("provide_")) {
|
|
677
667
|
validationErrors.push(
|
|
678
|
-
`provide_* 节点不得出现在控制链上(node→node 边):${e.source} ${sh} -> ${e.target} ${th};provide 仅作数据源,请改连下游 text/file 数据槽`
|
|
668
|
+
`provide_* 节点不得出现在控制链上(node→node 边):${e.source} ${sh} -> ${e.target} ${th};provide 仅作数据源,请改连下游 text/file/bool 数据槽`
|
|
679
669
|
);
|
|
680
670
|
}
|
|
681
671
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: HTML Display
|
|
3
|
+
description: Display HTML content in workspace canvas; passes HTML downstream as text
|
|
4
|
+
displayName: HTML Display
|
|
5
|
+
input:
|
|
6
|
+
- type: node
|
|
7
|
+
name: prev
|
|
8
|
+
default: ""
|
|
9
|
+
- type: text
|
|
10
|
+
name: content
|
|
11
|
+
default: ""
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
14
|
+
- type: file
|
|
15
|
+
name: filePath
|
|
16
|
+
default: ""
|
|
17
|
+
showOnNode: false
|
|
18
|
+
- type: text
|
|
19
|
+
name: workspaceContext
|
|
20
|
+
default: ""
|
|
21
|
+
showOnNode: false
|
|
22
|
+
output:
|
|
23
|
+
- type: text
|
|
24
|
+
name: content
|
|
25
|
+
default: ""
|
|
26
|
+
showOnNode: false
|
|
27
|
+
- type: node
|
|
28
|
+
name: next
|
|
29
|
+
default: ""
|
|
30
|
+
---
|
|
31
|
+
${content}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: Image Display
|
|
3
|
+
description: Display an image URL, data URL, or image path in workspace canvas; passes source downstream as text
|
|
4
|
+
displayName: Image Display
|
|
5
|
+
input:
|
|
6
|
+
- type: node
|
|
7
|
+
name: prev
|
|
8
|
+
default: ""
|
|
9
|
+
- type: text
|
|
10
|
+
name: src
|
|
11
|
+
default: ""
|
|
12
|
+
required: true
|
|
13
|
+
showOnNode: true
|
|
14
|
+
- type: file
|
|
15
|
+
name: filePath
|
|
16
|
+
default: ""
|
|
17
|
+
showOnNode: false
|
|
18
|
+
- type: text
|
|
19
|
+
name: alt
|
|
20
|
+
default: ""
|
|
21
|
+
showOnNode: false
|
|
22
|
+
- type: text
|
|
23
|
+
name: workspaceContext
|
|
24
|
+
default: ""
|
|
25
|
+
showOnNode: false
|
|
26
|
+
output:
|
|
27
|
+
- type: text
|
|
28
|
+
name: src
|
|
29
|
+
default: ""
|
|
30
|
+
showOnNode: false
|
|
31
|
+
- type: node
|
|
32
|
+
name: next
|
|
33
|
+
default: ""
|
|
34
|
+
---
|
|
35
|
+
${src}
|
|
@@ -8,6 +8,7 @@ description: |
|
|
|
8
8
|
- If `targetDir` is empty, the repository is cloned into `${pipelineWorkspace}/.workspace/agentflow/git-repos/<repo-name>`.
|
|
9
9
|
- Set `includeSubmodules` to `true` to clone/update Git submodules recursively.
|
|
10
10
|
- The `workspaceContext` output can be connected to CD Workspace, Load Skills, agent, or tool nodes.
|
|
11
|
+
- The `gitContext` output can be connected to Worktree, GitLab MR, or other Git nodes.
|
|
11
12
|
displayName: Git Checkout
|
|
12
13
|
input:
|
|
13
14
|
- type: node
|
|
@@ -31,6 +32,9 @@ input:
|
|
|
31
32
|
- type: bool
|
|
32
33
|
name: includeSubmodules
|
|
33
34
|
default: "false"
|
|
35
|
+
- type: text
|
|
36
|
+
name: remote
|
|
37
|
+
default: "origin"
|
|
34
38
|
- type: text
|
|
35
39
|
name: workspaceContext
|
|
36
40
|
default: ""
|
|
@@ -53,5 +57,8 @@ output:
|
|
|
53
57
|
- type: text
|
|
54
58
|
name: workspaceContext
|
|
55
59
|
default: ""
|
|
60
|
+
- type: text
|
|
61
|
+
name: gitContext
|
|
62
|
+
default: ""
|
|
56
63
|
---
|
|
57
|
-
Clone or update `${repoUrl}` and output
|
|
64
|
+
Clone or update `${repoUrl}` and output workspace/git contexts for the checked-out repository.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: Git Worktree Load
|
|
3
|
+
description: |
|
|
4
|
+
Create or reuse a Git worktree and expose it as the downstream workspace context.
|
|
5
|
+
|
|
6
|
+
- `repoPath` is required unless `gitContext.repoPath` is connected.
|
|
7
|
+
- `workspaceContext` is required so the node can preserve the previous execution context.
|
|
8
|
+
- `branch` is optional. When empty, AgentFlow creates a detached worktree at the current HEAD.
|
|
9
|
+
- `worktreePath` is optional. When empty, AgentFlow creates a path under `${pipelineWorkspace}/.workspace/agentflow/worktrees`.
|
|
10
|
+
- Existing worktree paths are reused only when they are registered by `git worktree list` for the given repo.
|
|
11
|
+
displayName: Load Worktree
|
|
12
|
+
input:
|
|
13
|
+
- type: node
|
|
14
|
+
name: prev
|
|
15
|
+
default: ""
|
|
16
|
+
- type: file
|
|
17
|
+
name: repoPath
|
|
18
|
+
default: ""
|
|
19
|
+
showOnNode: true
|
|
20
|
+
- type: text
|
|
21
|
+
name: branch
|
|
22
|
+
default: ""
|
|
23
|
+
showOnNode: true
|
|
24
|
+
- type: file
|
|
25
|
+
name: worktreePath
|
|
26
|
+
default: ""
|
|
27
|
+
- type: text
|
|
28
|
+
name: gitContext
|
|
29
|
+
default: ""
|
|
30
|
+
- type: text
|
|
31
|
+
name: workspaceContext
|
|
32
|
+
default: ""
|
|
33
|
+
required: true
|
|
34
|
+
output:
|
|
35
|
+
- type: node
|
|
36
|
+
name: next
|
|
37
|
+
default: ""
|
|
38
|
+
- type: file
|
|
39
|
+
name: worktreePath
|
|
40
|
+
default: ""
|
|
41
|
+
- type: text
|
|
42
|
+
name: branch
|
|
43
|
+
default: ""
|
|
44
|
+
- type: text
|
|
45
|
+
name: commit
|
|
46
|
+
default: ""
|
|
47
|
+
- type: text
|
|
48
|
+
name: workspaceContext
|
|
49
|
+
default: ""
|
|
50
|
+
- type: text
|
|
51
|
+
name: gitContext
|
|
52
|
+
default: ""
|
|
53
|
+
---
|
|
54
|
+
Load a Git worktree from `${repoPath}` and switch downstream workspace context to it.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: Git Worktree Unload
|
|
3
|
+
description: |
|
|
4
|
+
Remove a Git worktree.
|
|
5
|
+
|
|
6
|
+
- `repoPath` is required unless `gitContext.repoPath` is connected.
|
|
7
|
+
- `worktreePath` is required unless `gitContext.worktreePath` is connected.
|
|
8
|
+
- `workspaceContext` is required so the node can restore the previous execution context.
|
|
9
|
+
- By default `force` is false; dirty worktrees fail instead of being removed.
|
|
10
|
+
- By default `prune` is true.
|
|
11
|
+
displayName: Unload Worktree
|
|
12
|
+
input:
|
|
13
|
+
- type: node
|
|
14
|
+
name: prev
|
|
15
|
+
default: ""
|
|
16
|
+
- type: file
|
|
17
|
+
name: repoPath
|
|
18
|
+
default: ""
|
|
19
|
+
showOnNode: true
|
|
20
|
+
- type: file
|
|
21
|
+
name: worktreePath
|
|
22
|
+
default: ""
|
|
23
|
+
showOnNode: true
|
|
24
|
+
- type: text
|
|
25
|
+
name: gitContext
|
|
26
|
+
default: ""
|
|
27
|
+
- type: text
|
|
28
|
+
name: workspaceContext
|
|
29
|
+
default: ""
|
|
30
|
+
required: true
|
|
31
|
+
- type: bool
|
|
32
|
+
name: force
|
|
33
|
+
default: "false"
|
|
34
|
+
- type: bool
|
|
35
|
+
name: prune
|
|
36
|
+
default: "true"
|
|
37
|
+
output:
|
|
38
|
+
- type: node
|
|
39
|
+
name: next
|
|
40
|
+
default: ""
|
|
41
|
+
- type: bool
|
|
42
|
+
name: removed
|
|
43
|
+
default: ""
|
|
44
|
+
- type: text
|
|
45
|
+
name: workspaceContext
|
|
46
|
+
default: ""
|
|
47
|
+
- type: text
|
|
48
|
+
name: message
|
|
49
|
+
default: ""
|
|
50
|
+
---
|
|
51
|
+
Remove Git worktree `${worktreePath}` from repository `${repoPath}`.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Built-in node: GitLab Create MR
|
|
3
|
+
description: |
|
|
4
|
+
Create or reuse a GitLab merge request for the current branch.
|
|
5
|
+
|
|
6
|
+
- `gitContext` and `workspaceContext` can be connected from Git Checkout / Load Worktree.
|
|
7
|
+
- `repoPath` is optional. When empty, AgentFlow uses `gitContext.worktreePath`, `gitContext.repoPath`, or `workspaceContext.cwd`.
|
|
8
|
+
- `sourceBranch`, `targetBranch`, `title`, `description`, `draft`, and `labels` are optional. When empty, AgentFlow derives sensible defaults from git.
|
|
9
|
+
- `tokenEnv` is optional. Defaults to `GITLAB_TOKEN,GITLAB_PRIVATE_TOKEN`.
|
|
10
|
+
- `gitlabApiBase` is optional. When empty, AgentFlow uses `https://${gitContext.host}/api/v4`.
|
|
11
|
+
displayName: Create GitLab MR
|
|
12
|
+
input:
|
|
13
|
+
- type: node
|
|
14
|
+
name: prev
|
|
15
|
+
default: ""
|
|
16
|
+
- type: file
|
|
17
|
+
name: repoPath
|
|
18
|
+
default: ""
|
|
19
|
+
showOnNode: false
|
|
20
|
+
- type: text
|
|
21
|
+
name: gitContext
|
|
22
|
+
default: ""
|
|
23
|
+
showOnNode: true
|
|
24
|
+
- type: text
|
|
25
|
+
name: workspaceContext
|
|
26
|
+
default: ""
|
|
27
|
+
showOnNode: false
|
|
28
|
+
- type: text
|
|
29
|
+
name: sourceBranch
|
|
30
|
+
default: ""
|
|
31
|
+
showOnNode: false
|
|
32
|
+
- type: text
|
|
33
|
+
name: targetBranch
|
|
34
|
+
default: ""
|
|
35
|
+
showOnNode: false
|
|
36
|
+
- type: text
|
|
37
|
+
name: title
|
|
38
|
+
default: ""
|
|
39
|
+
showOnNode: false
|
|
40
|
+
- type: text
|
|
41
|
+
name: description
|
|
42
|
+
default: ""
|
|
43
|
+
showOnNode: false
|
|
44
|
+
- type: bool
|
|
45
|
+
name: draft
|
|
46
|
+
default: "false"
|
|
47
|
+
showOnNode: false
|
|
48
|
+
- type: text
|
|
49
|
+
name: labels
|
|
50
|
+
default: ""
|
|
51
|
+
showOnNode: false
|
|
52
|
+
- type: bool
|
|
53
|
+
name: push
|
|
54
|
+
default: "true"
|
|
55
|
+
showOnNode: false
|
|
56
|
+
- type: text
|
|
57
|
+
name: remote
|
|
58
|
+
default: "origin"
|
|
59
|
+
showOnNode: false
|
|
60
|
+
- type: text
|
|
61
|
+
name: tokenEnv
|
|
62
|
+
default: ""
|
|
63
|
+
showOnNode: false
|
|
64
|
+
- type: text
|
|
65
|
+
name: gitlabApiBase
|
|
66
|
+
default: ""
|
|
67
|
+
showOnNode: false
|
|
68
|
+
- type: bool
|
|
69
|
+
name: removeSourceBranch
|
|
70
|
+
default: "false"
|
|
71
|
+
showOnNode: false
|
|
72
|
+
- type: bool
|
|
73
|
+
name: squash
|
|
74
|
+
default: "false"
|
|
75
|
+
showOnNode: false
|
|
76
|
+
output:
|
|
77
|
+
- type: node
|
|
78
|
+
name: next
|
|
79
|
+
default: ""
|
|
80
|
+
- type: text
|
|
81
|
+
name: mrUrl
|
|
82
|
+
default: ""
|
|
83
|
+
required: true
|
|
84
|
+
- type: bool
|
|
85
|
+
name: created
|
|
86
|
+
default: ""
|
|
87
|
+
showOnNode: false
|
|
88
|
+
- type: text
|
|
89
|
+
name: mrIid
|
|
90
|
+
default: ""
|
|
91
|
+
showOnNode: false
|
|
92
|
+
- type: text
|
|
93
|
+
name: projectId
|
|
94
|
+
default: ""
|
|
95
|
+
showOnNode: false
|
|
96
|
+
- type: text
|
|
97
|
+
name: sourceBranch
|
|
98
|
+
default: ""
|
|
99
|
+
showOnNode: false
|
|
100
|
+
- type: text
|
|
101
|
+
name: targetBranch
|
|
102
|
+
default: ""
|
|
103
|
+
showOnNode: false
|
|
104
|
+
- type: text
|
|
105
|
+
name: title
|
|
106
|
+
default: ""
|
|
107
|
+
showOnNode: false
|
|
108
|
+
- type: text
|
|
109
|
+
name: message
|
|
110
|
+
default: ""
|
|
111
|
+
showOnNode: false
|
|
112
|
+
---
|
|
113
|
+
Create or reuse a GitLab merge request and output `${mrUrl}`.
|