taskmeld 0.1.1
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/LICENSE +18 -0
- package/README.md +172 -0
- package/README.zh-CN.md +172 -0
- package/dist/src/app/app-context-env.js +51 -0
- package/dist/src/app/create-app-context.js +127 -0
- package/dist/src/app/data-dir.js +29 -0
- package/dist/src/app/pipeline-config.js +105 -0
- package/dist/src/app/pipeline-plugin-config.js +2 -0
- package/dist/src/app/pipeline-registry.js +502 -0
- package/dist/src/app/pipeline-runtime.js +202 -0
- package/dist/src/app/runtime-store.js +151 -0
- package/dist/src/app/user-config.js +37 -0
- package/dist/src/artifacts/artifact-cleanup.js +192 -0
- package/dist/src/artifacts/artifact-index.js +262 -0
- package/dist/src/artifacts/artifact-rebuilder.js +120 -0
- package/dist/src/artifacts/storage-service.js +371 -0
- package/dist/src/cli/bootstrap.js +226 -0
- package/dist/src/cli/commands/agent.js +126 -0
- package/dist/src/cli/commands/artifact.js +175 -0
- package/dist/src/cli/commands/init.js +150 -0
- package/dist/src/cli/commands/pipeline/errors.js +37 -0
- package/dist/src/cli/commands/pipeline/result.js +179 -0
- package/dist/src/cli/commands/pipeline/selector.js +51 -0
- package/dist/src/cli/commands/pipeline/types.js +2 -0
- package/dist/src/cli/commands/pipeline/watch.js +67 -0
- package/dist/src/cli/commands/pipeline.js +339 -0
- package/dist/src/cli/commands/scheduler.js +81 -0
- package/dist/src/cli/commands/server.js +70 -0
- package/dist/src/cli/commands/system.js +21 -0
- package/dist/src/cli/errors.js +71 -0
- package/dist/src/cli/help.js +184 -0
- package/dist/src/cli/index.js +65 -0
- package/dist/src/cli/output.js +19 -0
- package/dist/src/cli/renderers/engine/json.js +67 -0
- package/dist/src/cli/renderers/engine/markdown.js +95 -0
- package/dist/src/cli/renderers/engine/types.js +2 -0
- package/dist/src/cli/renderers/engine/utils.js +32 -0
- package/dist/src/cli/renderers/index.js +27 -0
- package/dist/src/cli/renderers/specs/agent.js +78 -0
- package/dist/src/cli/renderers/specs/artifact.js +32 -0
- package/dist/src/cli/renderers/specs/index.js +36 -0
- package/dist/src/cli/renderers/specs/init.js +25 -0
- package/dist/src/cli/renderers/specs/pipeline.js +561 -0
- package/dist/src/cli/renderers/specs/scheduler.js +46 -0
- package/dist/src/cli/renderers/specs/server.js +38 -0
- package/dist/src/cli/renderers/specs/system.js +36 -0
- package/dist/src/cli/router.js +199 -0
- package/dist/src/cli/server-runtime-client.js +780 -0
- package/dist/src/cli/types.js +2 -0
- package/dist/src/gateway/frame-sanitizer.js +78 -0
- package/dist/src/gateway/gateway-client.js +462 -0
- package/dist/src/gateway/index.js +18 -0
- package/dist/src/gateway/types.js +2 -0
- package/dist/src/index.js +123 -0
- package/dist/src/logs/run-log-reader.js +141 -0
- package/dist/src/logs/run-log-service.js +42 -0
- package/dist/src/logs/run-log-types.js +2 -0
- package/dist/src/pipeline/agent-activity.js +191 -0
- package/dist/src/pipeline/artifact-storage.js +208 -0
- package/dist/src/pipeline/diagnostics/dependency-diagnostic.js +105 -0
- package/dist/src/pipeline/diagnostics/index.js +6 -0
- package/dist/src/pipeline/dispatch/pipeline-inbound-queue.js +215 -0
- package/dist/src/pipeline/dispatch/pipeline-link-dispatcher.js +66 -0
- package/dist/src/pipeline/dispatch/pipeline-link-store.js +94 -0
- package/dist/src/pipeline/dispatch/pipeline-queue-drainer.js +71 -0
- package/dist/src/pipeline/execution/dependency-check.js +52 -0
- package/dist/src/pipeline/execution/execution-result.js +2 -0
- package/dist/src/pipeline/execution/group-item-executor.js +128 -0
- package/dist/src/pipeline/execution/index.js +5 -0
- package/dist/src/pipeline/execution/node-item-executor.js +58 -0
- package/dist/src/pipeline/execution/node-runner.js +159 -0
- package/dist/src/pipeline/execution/readiness-state.js +10 -0
- package/dist/src/pipeline/execution/reject-handler.js +94 -0
- package/dist/src/pipeline/execution/rejected-artifact-archiver.js +45 -0
- package/dist/src/pipeline/execution/route-item-manager.js +253 -0
- package/dist/src/pipeline/execution/run-abort-controller.js +66 -0
- package/dist/src/pipeline/execution/run-state-helpers.js +257 -0
- package/dist/src/pipeline/execution/service.js +165 -0
- package/dist/src/pipeline/execution/session-registry.js +96 -0
- package/dist/src/pipeline/execution/structured-node-runner.js +411 -0
- package/dist/src/pipeline/execution-status.js +96 -0
- package/dist/src/pipeline/execution-timeout.js +21 -0
- package/dist/src/pipeline/identity/index.js +32 -0
- package/dist/src/pipeline/identity/types.js +2 -0
- package/dist/src/pipeline/item-batch-controller.js +227 -0
- package/dist/src/pipeline/output/pipeline-output-resolver.js +91 -0
- package/dist/src/pipeline/output/pipeline-output-store.js +60 -0
- package/dist/src/pipeline/runtime-model.js +173 -0
- package/dist/src/pipeline/scheduler/dependency-state.js +144 -0
- package/dist/src/pipeline/scheduler-service.js +314 -0
- package/dist/src/pipeline/state/group-item-state.js +50 -0
- package/dist/src/pipeline/state/group-run-state.js +41 -0
- package/dist/src/pipeline/state/index.js +20 -0
- package/dist/src/pipeline/state/node-item-state.js +67 -0
- package/dist/src/pipeline/state/node-run-state.js +51 -0
- package/dist/src/pipeline/state/types.js +2 -0
- package/dist/src/pipeline/state-machine.js +101 -0
- package/dist/src/pipeline/structured-output/contract.js +133 -0
- package/dist/src/pipeline/structured-output/index.js +22 -0
- package/dist/src/pipeline/structured-output/parser.js +214 -0
- package/dist/src/pipeline/structured-output/prompt.js +290 -0
- package/dist/src/pipeline/structured-output/waiter.js +139 -0
- package/dist/src/pipeline/template.js +135 -0
- package/dist/src/pipeline/timeline-log-store.js +57 -0
- package/dist/src/pipeline/tool-activity.js +94 -0
- package/dist/src/pipeline/types/pipeline-link.js +7 -0
- package/dist/src/pipeline/types/pipeline-output.js +11 -0
- package/dist/src/pipeline/types/workflow.js +2 -0
- package/dist/src/pipeline/workflow/branch-rules.js +74 -0
- package/dist/src/pipeline/workflow/defaults.js +48 -0
- package/dist/src/pipeline/workflow/io.js +89 -0
- package/dist/src/pipeline/workflow/normalize.js +347 -0
- package/dist/src/pipeline/workflow/routes.js +16 -0
- package/dist/src/pipeline/workflow/template-mapper.js +113 -0
- package/dist/src/pipeline/workflow/validate.js +312 -0
- package/dist/src/pipeline/workflow-graph.js +165 -0
- package/dist/src/server/api-handler.js +163 -0
- package/dist/src/server/http-utils.js +34 -0
- package/dist/src/server/middleware.js +61 -0
- package/dist/src/server/router.js +105 -0
- package/dist/src/server/routes/agents.js +189 -0
- package/dist/src/server/routes/artifacts.js +163 -0
- package/dist/src/server/routes/gateway.js +18 -0
- package/dist/src/server/routes/health.js +16 -0
- package/dist/src/server/routes/logs.js +73 -0
- package/dist/src/server/routes/pipeline-batch.js +163 -0
- package/dist/src/server/routes/pipeline-diagnostics.js +33 -0
- package/dist/src/server/routes/pipeline-identity.js +24 -0
- package/dist/src/server/routes/pipeline-links.js +117 -0
- package/dist/src/server/routes/pipeline-outputs.js +27 -0
- package/dist/src/server/routes/pipeline-queue.js +62 -0
- package/dist/src/server/routes/pipeline-runtime.js +162 -0
- package/dist/src/server/routes/pipeline-scheduler.js +69 -0
- package/dist/src/server/routes/pipeline-workflow.js +180 -0
- package/dist/src/server/routes/pipelines.js +96 -0
- package/dist/src/server/routes/sessions.js +244 -0
- package/dist/src/server/routes/timeline.js +14 -0
- package/dist/src/server/serve-static.js +42 -0
- package/dist/src/server/types.js +2 -0
- package/dist/src/services/agent-service.js +79 -0
- package/dist/src/services/artifact-service.js +74 -0
- package/dist/src/services/gateway-read-helpers.js +10 -0
- package/dist/src/services/index.js +23 -0
- package/dist/src/services/pipeline-service.js +529 -0
- package/dist/src/services/pipeline-status.js +93 -0
- package/dist/src/services/read-services.js +60 -0
- package/dist/src/services/scheduler-service.js +37 -0
- package/dist/src/services/session-service.js +227 -0
- package/dist/src/services/system-service.js +26 -0
- package/dist/src/transport/ws-broker.js +48 -0
- package/dist/src/utils/array.js +17 -0
- package/dist/src/utils/guards.js +5 -0
- package/dist/src/utils/session.js +60 -0
- package/dist/src/version.js +5 -0
- package/package.json +61 -0
- package/web/dist/assets/index-CWnfhkn-.js +65 -0
- package/web/dist/assets/index-gZ0xOfSO.css +1 -0
- package/web/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/web/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
- package/web/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-cyrillic-700-normal-BWTpRfYl.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-cyrillic-700-normal-CEoEElIJ.woff +0 -0
- package/web/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/web/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
- package/web/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-greek-700-normal-C6CZE3T8.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-greek-700-normal-DEigVDxa.woff +0 -0
- package/web/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/web/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
- package/web/dist/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-700-normal-CZipNAKV.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-700-normal-CxPITLHs.woff +0 -0
- package/web/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/web/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
- package/web/dist/assets/jetbrains-mono-vietnamese-700-normal-BDLVIk2r.woff +0 -0
- package/web/dist/assets/space-grotesk-latin-400-normal-BnQMeOim.woff +0 -0
- package/web/dist/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
- package/web/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-700-normal-CwsQ-cCU.woff +0 -0
- package/web/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-ext-400-normal-CfP_5XZW.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-ext-400-normal-DRPE3kg4.woff +0 -0
- package/web/dist/assets/space-grotesk-latin-ext-500-normal-3dgZTiw9.woff +0 -0
- package/web/dist/assets/space-grotesk-latin-ext-500-normal-DUe3BAxM.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-ext-700-normal-BQnZhY3m.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-ext-700-normal-HVCqSBdx.woff +0 -0
- package/web/dist/assets/space-grotesk-vietnamese-400-normal-B7xT_GF5.woff2 +0 -0
- package/web/dist/assets/space-grotesk-vietnamese-400-normal-BIWiOVfw.woff +0 -0
- package/web/dist/assets/space-grotesk-vietnamese-500-normal-BTqKIpxg.woff +0 -0
- package/web/dist/assets/space-grotesk-vietnamese-500-normal-BmEvtly_.woff2 +0 -0
- package/web/dist/assets/space-grotesk-vietnamese-700-normal-DMty7AZE.woff2 +0 -0
- package/web/dist/assets/space-grotesk-vietnamese-700-normal-Duxec5Rn.woff +0 -0
- package/web/dist/favicon.svg +10 -0
- package/web/dist/index.html +14 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createGroupItemExecutor = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const artifact_storage_1 = require("../artifact-storage");
|
|
6
|
+
const readiness_state_1 = require("./readiness-state");
|
|
7
|
+
const state_1 = require("../state");
|
|
8
|
+
const ctx = (reason, extra) => ({ reason, ...extra });
|
|
9
|
+
const createGroupItemExecutor = (deps) => {
|
|
10
|
+
const executeGroupMembers = async (item, group) => {
|
|
11
|
+
const memberItems = group.members
|
|
12
|
+
.map((memberId) => {
|
|
13
|
+
deps.ensureItemKeyInitialized(item.itemKey);
|
|
14
|
+
return deps.getItemRun(memberId, item.itemKey);
|
|
15
|
+
})
|
|
16
|
+
.filter((candidate) => !!candidate);
|
|
17
|
+
for (const memberItem of memberItems) {
|
|
18
|
+
(0, state_1.markItemReset)(memberItem, "queued", ctx("group_member_start"));
|
|
19
|
+
memberItem.route = null;
|
|
20
|
+
memberItem.artifacts = [];
|
|
21
|
+
}
|
|
22
|
+
const groupDependencyIds = [
|
|
23
|
+
...new Set(group.members.flatMap((memberId) => deps.getEffectiveDependencyIdsForNodeItem(memberId, item.itemKey))),
|
|
24
|
+
];
|
|
25
|
+
const results = await Promise.all(memberItems.map((memberItem) => deps.executeNodeItem(memberItem, {
|
|
26
|
+
suppressOutgoing: true,
|
|
27
|
+
dependencyIds: groupDependencyIds,
|
|
28
|
+
})));
|
|
29
|
+
return { results, memberItems };
|
|
30
|
+
};
|
|
31
|
+
const collectGroupResult = async (item, group, runGroup, memberItems) => {
|
|
32
|
+
const run = deps.getRun();
|
|
33
|
+
const memberArtifacts = memberItems.flatMap((memberItem) => memberItem.artifacts.map((artifact) => ({
|
|
34
|
+
nodeId: memberItem.nodeId,
|
|
35
|
+
artifact,
|
|
36
|
+
})));
|
|
37
|
+
const memberArtifactContents = await Promise.all(memberArtifacts.map(async (entry) => {
|
|
38
|
+
let content = "[artifact_read_failed]";
|
|
39
|
+
let meta;
|
|
40
|
+
try {
|
|
41
|
+
const raw = await (0, promises_1.readFile)(entry.artifact.path, "utf8");
|
|
42
|
+
const parsed = JSON.parse(raw);
|
|
43
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && "artifact" in parsed) {
|
|
44
|
+
const artifactObj = parsed.artifact;
|
|
45
|
+
content = artifactObj?.content ?? raw;
|
|
46
|
+
if (artifactObj?.meta && typeof artifactObj.meta === "object" && !Array.isArray(artifactObj.meta)) {
|
|
47
|
+
meta = artifactObj.meta;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
content = raw;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// keep fallback marker
|
|
56
|
+
}
|
|
57
|
+
const memberNode = deps.getNodeById(entry.nodeId);
|
|
58
|
+
return {
|
|
59
|
+
nodeId: entry.nodeId,
|
|
60
|
+
nodeTitle: memberNode?.title ?? entry.nodeId,
|
|
61
|
+
type: entry.artifact.type,
|
|
62
|
+
schemaVersion: entry.artifact.schemaVersion,
|
|
63
|
+
name: entry.artifact.name,
|
|
64
|
+
path: entry.artifact.path,
|
|
65
|
+
hash: entry.artifact.hash,
|
|
66
|
+
content,
|
|
67
|
+
meta,
|
|
68
|
+
};
|
|
69
|
+
}));
|
|
70
|
+
const groupContent = memberArtifactContents
|
|
71
|
+
.map((entry) => `${entry.nodeId}(${entry.nodeTitle})\n${typeof entry.content === "string" ? entry.content : JSON.stringify(entry.content, null, 2)}`)
|
|
72
|
+
.join("\n\n");
|
|
73
|
+
const groupArtifact = await (0, artifact_storage_1.persistArtifactFile)(deps.artifactDir, "success", {
|
|
74
|
+
runId: run.id,
|
|
75
|
+
pipelineId: deps.pipelineId,
|
|
76
|
+
batchRunId: deps.getBatchRunId?.(),
|
|
77
|
+
groupId: group.id,
|
|
78
|
+
itemKey: item.itemKey,
|
|
79
|
+
kind: "group",
|
|
80
|
+
}, {
|
|
81
|
+
type: "group.output.v1",
|
|
82
|
+
schemaVersion: 1,
|
|
83
|
+
name: `${group.id}-group-output`,
|
|
84
|
+
content: groupContent,
|
|
85
|
+
meta: { members: memberArtifactContents },
|
|
86
|
+
}, { fileNameSuffix: `${item.itemKey}-group-output` });
|
|
87
|
+
runGroup.artifacts = [groupArtifact];
|
|
88
|
+
item.artifacts = [groupArtifact];
|
|
89
|
+
(0, state_1.markGroupItemSuccess)(item, ctx("group_exec_done"));
|
|
90
|
+
(0, state_1.markGroupSuccess)(runGroup, ctx("group_exec_done"));
|
|
91
|
+
for (const edge of deps.graph.getOutgoingEdges(group.id)) {
|
|
92
|
+
if (edge.when)
|
|
93
|
+
continue;
|
|
94
|
+
const downstream = deps.getItemRun(edge.to, item.itemKey);
|
|
95
|
+
if (!downstream)
|
|
96
|
+
continue;
|
|
97
|
+
if ((0, readiness_state_1.canPromoteToQueuedByDependency)(downstream)) {
|
|
98
|
+
(0, state_1.markItemQueued)(downstream, ctx("group_downstream_promote"));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
deps.runtimeStore.emitPipeline();
|
|
102
|
+
};
|
|
103
|
+
const executeGroupItem = async (item) => {
|
|
104
|
+
const run = deps.getRun();
|
|
105
|
+
const group = deps.graph.getWorkflowGroupById(item.groupId);
|
|
106
|
+
const runGroup = deps.getGroupById(item.groupId);
|
|
107
|
+
if (!group || !runGroup) {
|
|
108
|
+
(0, state_1.markGroupItemFailed)(item, ctx("group_not_found", { error: "group_not_found" }));
|
|
109
|
+
return { ok: false, error: "group_not_found", finalStatus: "failed" };
|
|
110
|
+
}
|
|
111
|
+
(0, state_1.markGroupItemRunning)(item, ctx("group_start"));
|
|
112
|
+
(0, state_1.markGroupRunning)(runGroup, ctx("group_start"));
|
|
113
|
+
deps.runtimeStore.pushTimeline(`并行组执行已触发: ${group.id}#${item.itemKey}`);
|
|
114
|
+
deps.runtimeStore.emitPipeline();
|
|
115
|
+
const { results, memberItems } = await executeGroupMembers(item, group);
|
|
116
|
+
if (results.some((result) => !result.ok)) {
|
|
117
|
+
const memberError = results.find((result) => !result.ok)?.error ?? "group_member_failed";
|
|
118
|
+
(0, state_1.markGroupItemFailed)(item, ctx("member_failed", { error: memberError }));
|
|
119
|
+
(0, state_1.markGroupFailed)(runGroup, ctx("member_failed", { error: memberError }));
|
|
120
|
+
deps.runtimeStore.emitPipeline();
|
|
121
|
+
return { ok: false, error: item.lastError ?? undefined, finalStatus: "failed" };
|
|
122
|
+
}
|
|
123
|
+
await collectGroupResult(item, group, runGroup, memberItems);
|
|
124
|
+
return { ok: true, finalStatus: "success" };
|
|
125
|
+
};
|
|
126
|
+
return { executeGroupMembers, collectGroupResult, executeGroupItem };
|
|
127
|
+
};
|
|
128
|
+
exports.createGroupItemExecutor = createGroupItemExecutor;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createExecutionService = void 0;
|
|
4
|
+
var service_1 = require("./service");
|
|
5
|
+
Object.defineProperty(exports, "createExecutionService", { enumerable: true, get: function () { return service_1.createExecutionService; } });
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNodeItemExecutor = void 0;
|
|
4
|
+
const state_1 = require("../state");
|
|
5
|
+
const ctx = (reason, extra) => ({ reason, ...extra });
|
|
6
|
+
const createNodeItemExecutor = (deps) => {
|
|
7
|
+
const executeNodeItem = async (item, opts) => {
|
|
8
|
+
const run = deps.getRun();
|
|
9
|
+
const node = deps.getNodeById(item.nodeId);
|
|
10
|
+
if (!node) {
|
|
11
|
+
(0, state_1.markItemFailed)(item, ctx("node_not_found", { error: "node_not_found" }));
|
|
12
|
+
return { ok: false, error: "node_not_found", finalStatus: "failed" };
|
|
13
|
+
}
|
|
14
|
+
const workflowNode = deps.graph.getWorkflowNodeById(node.id);
|
|
15
|
+
if (workflowNode?.enabled === false) {
|
|
16
|
+
(0, state_1.markItemSkipped)(item, ctx("node_disabled"));
|
|
17
|
+
return { ok: true, envelope: null, finalStatus: "success" };
|
|
18
|
+
}
|
|
19
|
+
const maxAttempts = Math.max(1, workflowNode?.retryPolicy.maxAttempts ?? 1);
|
|
20
|
+
if (item.attempt >= maxAttempts) {
|
|
21
|
+
(0, state_1.markItemFailed)(item, ctx("max_attempts_exceeded", { error: `max_attempts_exceeded:${maxAttempts}` }));
|
|
22
|
+
deps.runtimeStore.pushTimeline(`节点项超过重试上限: ${item.nodeId}#${item.itemKey} (${maxAttempts})`, "error");
|
|
23
|
+
deps.runtimeStore.emitPipeline();
|
|
24
|
+
return { ok: false, error: item.lastError ?? undefined, finalStatus: "failed" };
|
|
25
|
+
}
|
|
26
|
+
const retryBackoffMs = workflowNode?.retryPolicy.backoffMs ?? 0;
|
|
27
|
+
if (item.attempt > 0 && retryBackoffMs > 0) {
|
|
28
|
+
await new Promise(resolve => setTimeout(resolve, retryBackoffMs));
|
|
29
|
+
}
|
|
30
|
+
(0, state_1.markItemRunning)(item, ctx("exec_start"));
|
|
31
|
+
deps.runtimeStore.pushTimeline(`节点项执行已触发: ${item.nodeId}#${item.itemKey}`);
|
|
32
|
+
deps.runtimeStore.emitPipeline();
|
|
33
|
+
const exec = await deps.nodeRunner.executeNode(node, {
|
|
34
|
+
itemKey: item.itemKey,
|
|
35
|
+
dependencyIds: opts?.dependencyIds ?? deps.getEffectiveDependencyIdsForNodeItem(item.nodeId, item.itemKey),
|
|
36
|
+
});
|
|
37
|
+
if (!exec.ok) {
|
|
38
|
+
if (exec.finalStatus === "stopped") {
|
|
39
|
+
// 用户中止时节点项已被标记为 stopped,不覆盖
|
|
40
|
+
}
|
|
41
|
+
else if (exec.finalStatus === "rejected") {
|
|
42
|
+
(0, state_1.markItemRejected)(item, ctx("node_rejected", { error: exec.error ?? null }));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
(0, state_1.markItemFailed)(item, ctx("node_item_failed", { error: exec.error ?? null }));
|
|
46
|
+
}
|
|
47
|
+
item.artifacts = node.artifacts;
|
|
48
|
+
await deps.routeItemManager.applyEnvelopeOutcomeToItem(item, exec.envelope ?? null, opts);
|
|
49
|
+
return exec;
|
|
50
|
+
}
|
|
51
|
+
(0, state_1.markItemSuccess)(item, ctx("exec_done"));
|
|
52
|
+
item.artifacts = node.artifacts;
|
|
53
|
+
await deps.routeItemManager.applyEnvelopeOutcomeToItem(item, exec.envelope ?? null, opts);
|
|
54
|
+
return exec;
|
|
55
|
+
};
|
|
56
|
+
return { executeNodeItem };
|
|
57
|
+
};
|
|
58
|
+
exports.createNodeItemExecutor = createNodeItemExecutor;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNodeRunner = void 0;
|
|
4
|
+
const state_1 = require("../state");
|
|
5
|
+
const reject_handler_1 = require("./reject-handler");
|
|
6
|
+
const ctx = (reason, extra) => ({ reason, ...extra });
|
|
7
|
+
const extractEnvelopeErrorCode = (error) => {
|
|
8
|
+
if (!error || typeof error !== "object")
|
|
9
|
+
return "";
|
|
10
|
+
const obj = error;
|
|
11
|
+
return typeof obj.code === "string" ? obj.code.trim() : "";
|
|
12
|
+
};
|
|
13
|
+
const normalizeEnvelopeErrorForDisplay = (error) => {
|
|
14
|
+
const code = extractEnvelopeErrorCode(error);
|
|
15
|
+
const message = (0, reject_handler_1.extractEnvelopeErrorMessage)(error);
|
|
16
|
+
const display = message || code || "node_failed";
|
|
17
|
+
return { code, message, display };
|
|
18
|
+
};
|
|
19
|
+
const classifyNodeFailure = (error) => {
|
|
20
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21
|
+
const lower = message.toLowerCase();
|
|
22
|
+
if (lower.includes("timeout") || lower.includes("etimedout") || lower.includes("timed out")) {
|
|
23
|
+
return { reason: "network_timeout", haltPipeline: true };
|
|
24
|
+
}
|
|
25
|
+
if (error instanceof TypeError || error instanceof ReferenceError || error instanceof SyntaxError) {
|
|
26
|
+
return { reason: "runtime_exception", haltPipeline: true };
|
|
27
|
+
}
|
|
28
|
+
return { reason: "unknown", haltPipeline: true };
|
|
29
|
+
};
|
|
30
|
+
const createNodeRunner = (deps) => {
|
|
31
|
+
const handleNodeEnvelopeResult = async (node, result, envelopeError, opts, effectiveDependencyIds, usedAgentId) => {
|
|
32
|
+
const envelopeErrorCode = envelopeError.code;
|
|
33
|
+
let succeeded = false;
|
|
34
|
+
let finalStatus = "failed";
|
|
35
|
+
let execError;
|
|
36
|
+
let haltPipeline = true;
|
|
37
|
+
if (result.envelope.status === "success") {
|
|
38
|
+
(0, state_1.markNodeSuccess)(node, ctx("exec_done", { artifacts: result.artifacts }));
|
|
39
|
+
finalStatus = "success";
|
|
40
|
+
haltPipeline = false;
|
|
41
|
+
node.rejectCount = 0;
|
|
42
|
+
node.rejectFeedbacks = [];
|
|
43
|
+
succeeded = true;
|
|
44
|
+
deps.runtimeStore.pushTimeline(`节点执行完成(结构化): ${node.id} <- ${usedAgentId}`);
|
|
45
|
+
}
|
|
46
|
+
else if (envelopeErrorCode === "upstream_reject" && node.allowReject) {
|
|
47
|
+
node.artifacts = [];
|
|
48
|
+
await deps.handleNodeReject({
|
|
49
|
+
node,
|
|
50
|
+
envelope: result.envelope,
|
|
51
|
+
itemKey: opts?.itemKey,
|
|
52
|
+
dependencyIds: effectiveDependencyIds,
|
|
53
|
+
nodes: deps.getRun().nodes,
|
|
54
|
+
runId: deps.getRun().id,
|
|
55
|
+
pushTimeline: deps.runtimeStore.pushTimeline,
|
|
56
|
+
artifactDir: deps.artifactDir,
|
|
57
|
+
pipelineId: deps.pipelineId,
|
|
58
|
+
getBatchRunId: deps.getBatchRunId,
|
|
59
|
+
resetAffectedDownstreamNodes: deps.resetAffectedDownstreamNodes,
|
|
60
|
+
});
|
|
61
|
+
finalStatus = "rejected";
|
|
62
|
+
haltPipeline = false;
|
|
63
|
+
execError = node.lastError ?? "upstream_reject";
|
|
64
|
+
}
|
|
65
|
+
else if (envelopeErrorCode === "upstream_reject" && !node.allowReject) {
|
|
66
|
+
const rejectNotAllowedError = JSON.stringify({
|
|
67
|
+
code: "upstream_reject_not_allowed",
|
|
68
|
+
message: "node_allowReject_false",
|
|
69
|
+
originalError: result.envelope.error ?? null,
|
|
70
|
+
});
|
|
71
|
+
(0, state_1.markNodeFailed)(node, ctx("upstream_reject_not_allowed", { error: rejectNotAllowedError }));
|
|
72
|
+
finalStatus = "failed";
|
|
73
|
+
node.artifacts = result.artifacts;
|
|
74
|
+
execError = "upstream_reject_not_allowed: node_allowReject_false";
|
|
75
|
+
deps.runtimeStore.pushTimeline(`节点执行失败(结构化): ${node.id} <- ${usedAgentId} upstream_reject_not_allowed: node_allowReject_false`, "error");
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const structuredFailError = JSON.stringify(result.envelope.error ?? "node_failed");
|
|
79
|
+
(0, state_1.markNodeFailed)(node, ctx("node_structured_failed", { error: structuredFailError }));
|
|
80
|
+
finalStatus = "failed";
|
|
81
|
+
haltPipeline = false;
|
|
82
|
+
node.artifacts = result.artifacts;
|
|
83
|
+
execError = envelopeError.display;
|
|
84
|
+
const detailText = envelopeError.message
|
|
85
|
+
? `${envelopeError.code ? `${envelopeError.code}: ` : ""}${envelopeError.message}`
|
|
86
|
+
: envelopeError.code || "node_failed";
|
|
87
|
+
deps.runtimeStore.pushTimeline(`节点执行失败(结构化): ${node.id} <- ${usedAgentId} ${detailText}`, "error");
|
|
88
|
+
}
|
|
89
|
+
return { succeeded, finalStatus, execError, haltPipeline };
|
|
90
|
+
};
|
|
91
|
+
const executeNode = async (node, opts) => {
|
|
92
|
+
const resolved = await deps.sessionRegistry.resolveExecutorSession(node);
|
|
93
|
+
if (!resolved) {
|
|
94
|
+
deps.runtimeStore.pushTimeline(`节点 ${node.id} 执行失败: 找不到执行者会话(${node.executor.agentId})`, "error");
|
|
95
|
+
(0, state_1.markNodeFailed)(node, ctx("executor_session_not_found", { error: "executor_session_not_found" }));
|
|
96
|
+
deps.runtimeStore.emitPipeline();
|
|
97
|
+
return {
|
|
98
|
+
ok: false,
|
|
99
|
+
error: "executor_session_not_found",
|
|
100
|
+
executorAgentId: node.executor.agentId,
|
|
101
|
+
fallbackAgentId: node.executor.fallbackAgentId,
|
|
102
|
+
envelope: null,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const sessionId = resolved.sessionId;
|
|
106
|
+
const usedAgentId = resolved.agentId;
|
|
107
|
+
(0, state_1.markNodeRunning)(node, ctx("exec_start"));
|
|
108
|
+
deps.runtimeStore.pushTimeline(`节点执行已触发: ${node.id} -> ${usedAgentId}`);
|
|
109
|
+
deps.runtimeStore.emitPipeline();
|
|
110
|
+
const effectiveDependencyIds = opts?.dependencyIds?.length
|
|
111
|
+
? Array.from(new Set(opts.dependencyIds.map((id) => id.trim()).filter(Boolean)))
|
|
112
|
+
: node.dependsOn;
|
|
113
|
+
const ac = new AbortController();
|
|
114
|
+
const runId = deps.getRun().id;
|
|
115
|
+
const entry = deps.runAbortController.registerController(runId, ac, sessionId);
|
|
116
|
+
try {
|
|
117
|
+
const result = await deps.structuredNodeRunner.runNodeViaStructuredOutput(node, sessionId, opts?.itemKey, effectiveDependencyIds, ac.signal);
|
|
118
|
+
const envelopeError = normalizeEnvelopeErrorForDisplay(result.envelope.error);
|
|
119
|
+
const outcome = await handleNodeEnvelopeResult(node, result, envelopeError, opts, effectiveDependencyIds, usedAgentId);
|
|
120
|
+
deps.runtimeStore.emitPipeline();
|
|
121
|
+
return {
|
|
122
|
+
ok: outcome.succeeded,
|
|
123
|
+
...(outcome.succeeded ? {} : { error: outcome.execError ?? "node_not_success" }),
|
|
124
|
+
haltPipeline: outcome.haltPipeline,
|
|
125
|
+
usedAgentId,
|
|
126
|
+
usedSessionId: sessionId,
|
|
127
|
+
finalStatus: outcome.finalStatus,
|
|
128
|
+
envelope: result.envelope,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
133
|
+
const isAborted = errMsg === "aborted";
|
|
134
|
+
const classification = isAborted
|
|
135
|
+
? { reason: "pipeline_aborted", haltPipeline: true }
|
|
136
|
+
: classifyNodeFailure(error);
|
|
137
|
+
// 用户中止时节点已被标记为 stopped,不应再覆盖为 failed
|
|
138
|
+
if (!isAborted) {
|
|
139
|
+
(0, state_1.markNodeFailed)(node, ctx(classification.reason, { error: String(error) }));
|
|
140
|
+
}
|
|
141
|
+
deps.runtimeStore.pushTimeline(`节点执行中断(结构化): ${node.id} <- ${usedAgentId} ${String(error)}`, "warn");
|
|
142
|
+
deps.runtimeStore.emitPipeline();
|
|
143
|
+
return {
|
|
144
|
+
ok: false,
|
|
145
|
+
error: String(error),
|
|
146
|
+
haltPipeline: classification.haltPipeline,
|
|
147
|
+
usedAgentId,
|
|
148
|
+
usedSessionId: sessionId,
|
|
149
|
+
finalStatus: isAborted ? "stopped" : "failed",
|
|
150
|
+
envelope: null,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
deps.runAbortController.unregisterController(runId, entry);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
return { executeNode, handleNodeEnvelopeResult };
|
|
158
|
+
};
|
|
159
|
+
exports.createNodeRunner = createNodeRunner;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canPromoteToQueuedByDependency = exports.isSleepWaitingState = void 0;
|
|
4
|
+
const isSleepWaitingState = (candidate) => candidate.status === "waiting" && typeof candidate.wakeAt === "string" && candidate.wakeAt.trim().length > 0;
|
|
5
|
+
exports.isSleepWaitingState = isSleepWaitingState;
|
|
6
|
+
const canPromoteToQueuedByDependency = (candidate) => candidate.status === "blocked" ||
|
|
7
|
+
candidate.status === "skipped" ||
|
|
8
|
+
// 仅允许“依赖未满足”造成的 waiting 被重新入队;sleep waiting 仍需等到 wakeAt 到期。
|
|
9
|
+
(candidate.status === "waiting" && !(0, exports.isSleepWaitingState)(candidate));
|
|
10
|
+
exports.canPromoteToQueuedByDependency = canPromoteToQueuedByDependency;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleNodeReject = exports.pickDefaultRejectTarget = exports.extractEnvelopeRejectTargets = exports.extractEnvelopeErrorMessage = void 0;
|
|
4
|
+
const state_1 = require("../state");
|
|
5
|
+
const rejected_artifact_archiver_1 = require("./rejected-artifact-archiver");
|
|
6
|
+
const ctx = (reason, extra) => ({ reason, ...extra });
|
|
7
|
+
const extractEnvelopeErrorMessage = (error) => {
|
|
8
|
+
if (!error || typeof error !== "object")
|
|
9
|
+
return "";
|
|
10
|
+
const obj = error;
|
|
11
|
+
if (typeof obj.message === "string" && obj.message.trim())
|
|
12
|
+
return obj.message.trim();
|
|
13
|
+
if (typeof obj.reason === "string" && obj.reason.trim())
|
|
14
|
+
return obj.reason.trim();
|
|
15
|
+
return "";
|
|
16
|
+
};
|
|
17
|
+
exports.extractEnvelopeErrorMessage = extractEnvelopeErrorMessage;
|
|
18
|
+
const extractEnvelopeRejectTargets = (error) => {
|
|
19
|
+
if (!error || typeof error !== "object")
|
|
20
|
+
return [];
|
|
21
|
+
const obj = error;
|
|
22
|
+
if (!Array.isArray(obj.targets))
|
|
23
|
+
return [];
|
|
24
|
+
return obj.targets
|
|
25
|
+
.filter((item) => typeof item === "string")
|
|
26
|
+
.map((item) => item.trim())
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
};
|
|
29
|
+
exports.extractEnvelopeRejectTargets = extractEnvelopeRejectTargets;
|
|
30
|
+
const pickDefaultRejectTarget = (node, nodes, dependencyIds) => {
|
|
31
|
+
const effectiveDependencyIds = dependencyIds?.length ? dependencyIds : node.dependsOn;
|
|
32
|
+
if (effectiveDependencyIds.length === 0)
|
|
33
|
+
return null;
|
|
34
|
+
const indexById = new Map(nodes.map((current, index) => [current.id, index]));
|
|
35
|
+
let best = null;
|
|
36
|
+
for (const depId of effectiveDependencyIds) {
|
|
37
|
+
const depIndex = indexById.get(depId);
|
|
38
|
+
if (typeof depIndex !== "number")
|
|
39
|
+
continue;
|
|
40
|
+
if (!best || depIndex > best.index) {
|
|
41
|
+
best = { id: depId, index: depIndex };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return best?.id ?? effectiveDependencyIds[effectiveDependencyIds.length - 1] ?? null;
|
|
45
|
+
};
|
|
46
|
+
exports.pickDefaultRejectTarget = pickDefaultRejectTarget;
|
|
47
|
+
const handleNodeReject = async (params) => {
|
|
48
|
+
const { node, envelope, itemKey, dependencyIds, nodes, runId, pushTimeline, artifactDir, pipelineId, getBatchRunId, resetAffectedDownstreamNodes } = params;
|
|
49
|
+
const limit = Number.isFinite(node.maxRejectCount) ? Math.max(0, Math.trunc(node.maxRejectCount)) : 0;
|
|
50
|
+
node.rejectCount = (node.rejectCount ?? 0) + 1;
|
|
51
|
+
if (node.rejectCount > limit) {
|
|
52
|
+
(0, state_1.markNodeFailed)(node, ctx("reject_limit_exceeded", { error: JSON.stringify(envelope.error ?? "reject_limit_exceeded") }));
|
|
53
|
+
pushTimeline(`节点 ${node.id} 打回超过 ${limit} 次,标记失败`, "error");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const effectiveDependencyIds = dependencyIds?.length ? dependencyIds : node.dependsOn;
|
|
57
|
+
const explicitTargets = (0, exports.extractEnvelopeRejectTargets)(envelope.error);
|
|
58
|
+
const defaultTarget = (0, exports.pickDefaultRejectTarget)(node, nodes, effectiveDependencyIds);
|
|
59
|
+
const rejectTargetIds = explicitTargets.length > 0
|
|
60
|
+
? explicitTargets.filter((id) => effectiveDependencyIds.includes(id))
|
|
61
|
+
: defaultTarget
|
|
62
|
+
? [defaultTarget]
|
|
63
|
+
: [];
|
|
64
|
+
const rejectMessage = (0, exports.extractEnvelopeErrorMessage)(envelope.error) || "下游校验不通过,请修正后重新提交。";
|
|
65
|
+
if (rejectTargetIds.length === 0) {
|
|
66
|
+
(0, state_1.markNodeFailed)(node, ctx("reject_target_missing", { error: JSON.stringify(envelope.error ?? "reject_target_missing") }));
|
|
67
|
+
pushTimeline(`节点 ${node.id} 请求打回但未找到可用上游节点,标记失败`, "error");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
(0, state_1.markNodeRejected)(node, ctx("upstream_reject", { error: JSON.stringify(envelope.error ?? "upstream_reject") }));
|
|
71
|
+
for (const targetId of rejectTargetIds) {
|
|
72
|
+
const targetNode = nodes.find((current) => current.id === targetId);
|
|
73
|
+
if (!targetNode)
|
|
74
|
+
continue;
|
|
75
|
+
const feedback = `${node.id}(${node.title})打回原因: ${rejectMessage}`;
|
|
76
|
+
targetNode.rejectFeedbacks = [...(targetNode.rejectFeedbacks ?? []), feedback].slice(-5);
|
|
77
|
+
const movedCount = await (0, rejected_artifact_archiver_1.archiveRejectedArtifacts)({
|
|
78
|
+
node: targetNode,
|
|
79
|
+
runId,
|
|
80
|
+
artifactDir,
|
|
81
|
+
pipelineId,
|
|
82
|
+
rejectedByNodeId: node.id,
|
|
83
|
+
getBatchRunId,
|
|
84
|
+
pushTimeline,
|
|
85
|
+
});
|
|
86
|
+
const { affectedNodeCount, affectedGroupCount } = resetAffectedDownstreamNodes({
|
|
87
|
+
targetNodeId: targetId,
|
|
88
|
+
itemKey,
|
|
89
|
+
skipNodeIds: [node.id],
|
|
90
|
+
});
|
|
91
|
+
pushTimeline(`节点 ${node.id} 打回 ${targetNode.id},原因: ${rejectMessage};重置 ${affectedNodeCount} 个节点/${affectedGroupCount} 个并行组,归档产物 ${movedCount} 条`, "warn");
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
exports.handleNodeReject = handleNodeReject;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.archiveRejectedArtifacts = void 0;
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const artifact_storage_1 = require("../artifact-storage");
|
|
7
|
+
const sanitizeArtifactFileSegment = (value) => {
|
|
8
|
+
const normalized = value
|
|
9
|
+
.trim()
|
|
10
|
+
.replace(/[<>:"/\\|?*\x00-\x1F]/g, "_")
|
|
11
|
+
.replace(/\s+/g, "_")
|
|
12
|
+
.replace(/\.+$/g, "_");
|
|
13
|
+
return normalized || "unnamed";
|
|
14
|
+
};
|
|
15
|
+
const buildArtifactFileName = (...parts) => parts.map(sanitizeArtifactFileSegment).join("-");
|
|
16
|
+
const archiveRejectedArtifacts = async (params) => {
|
|
17
|
+
const { node, runId, artifactDir, pipelineId, rejectedByNodeId, getBatchRunId, pushTimeline } = params;
|
|
18
|
+
if (!node.artifacts.length)
|
|
19
|
+
return 0;
|
|
20
|
+
const persistDirs = (0, artifact_storage_1.buildArtifactStorageDirs)(artifactDir, runId, "rejected", new Date(), getBatchRunId?.());
|
|
21
|
+
await (0, promises_1.mkdir)(persistDirs.artifactsDir, { recursive: true });
|
|
22
|
+
let moved = 0;
|
|
23
|
+
for (const artifact of node.artifacts) {
|
|
24
|
+
const sourcePath = artifact.path;
|
|
25
|
+
const fileName = sourcePath.replace(/^.*[\\/]/, "");
|
|
26
|
+
const targetPath = (0, node_path_1.join)(persistDirs.artifactsDir, buildArtifactFileName(runId, node.id, "rejected-by", rejectedByNodeId, String(Date.now()), fileName));
|
|
27
|
+
try {
|
|
28
|
+
await (0, promises_1.rename)(sourcePath, targetPath);
|
|
29
|
+
await (0, artifact_storage_1.appendMovedArtifactIndexRecord)(artifactDir, {
|
|
30
|
+
manifest: artifact,
|
|
31
|
+
pipelineId,
|
|
32
|
+
status: "rejected",
|
|
33
|
+
relativePath: (0, node_path_1.relative)(artifactDir, targetPath).replaceAll("\\", "/"),
|
|
34
|
+
movedAt: new Date(),
|
|
35
|
+
rejectedByNodeId,
|
|
36
|
+
}).catch(() => { });
|
|
37
|
+
moved += 1;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
pushTimeline(`归档被驳回产物失败 (节点 ${node.id}): ${error instanceof Error ? error.message : String(error)}`, "warn");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return moved;
|
|
44
|
+
};
|
|
45
|
+
exports.archiveRejectedArtifacts = archiveRejectedArtifacts;
|