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.
Files changed (204) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +172 -0
  3. package/README.zh-CN.md +172 -0
  4. package/dist/src/app/app-context-env.js +51 -0
  5. package/dist/src/app/create-app-context.js +127 -0
  6. package/dist/src/app/data-dir.js +29 -0
  7. package/dist/src/app/pipeline-config.js +105 -0
  8. package/dist/src/app/pipeline-plugin-config.js +2 -0
  9. package/dist/src/app/pipeline-registry.js +502 -0
  10. package/dist/src/app/pipeline-runtime.js +202 -0
  11. package/dist/src/app/runtime-store.js +151 -0
  12. package/dist/src/app/user-config.js +37 -0
  13. package/dist/src/artifacts/artifact-cleanup.js +192 -0
  14. package/dist/src/artifacts/artifact-index.js +262 -0
  15. package/dist/src/artifacts/artifact-rebuilder.js +120 -0
  16. package/dist/src/artifacts/storage-service.js +371 -0
  17. package/dist/src/cli/bootstrap.js +226 -0
  18. package/dist/src/cli/commands/agent.js +126 -0
  19. package/dist/src/cli/commands/artifact.js +175 -0
  20. package/dist/src/cli/commands/init.js +150 -0
  21. package/dist/src/cli/commands/pipeline/errors.js +37 -0
  22. package/dist/src/cli/commands/pipeline/result.js +179 -0
  23. package/dist/src/cli/commands/pipeline/selector.js +51 -0
  24. package/dist/src/cli/commands/pipeline/types.js +2 -0
  25. package/dist/src/cli/commands/pipeline/watch.js +67 -0
  26. package/dist/src/cli/commands/pipeline.js +339 -0
  27. package/dist/src/cli/commands/scheduler.js +81 -0
  28. package/dist/src/cli/commands/server.js +70 -0
  29. package/dist/src/cli/commands/system.js +21 -0
  30. package/dist/src/cli/errors.js +71 -0
  31. package/dist/src/cli/help.js +184 -0
  32. package/dist/src/cli/index.js +65 -0
  33. package/dist/src/cli/output.js +19 -0
  34. package/dist/src/cli/renderers/engine/json.js +67 -0
  35. package/dist/src/cli/renderers/engine/markdown.js +95 -0
  36. package/dist/src/cli/renderers/engine/types.js +2 -0
  37. package/dist/src/cli/renderers/engine/utils.js +32 -0
  38. package/dist/src/cli/renderers/index.js +27 -0
  39. package/dist/src/cli/renderers/specs/agent.js +78 -0
  40. package/dist/src/cli/renderers/specs/artifact.js +32 -0
  41. package/dist/src/cli/renderers/specs/index.js +36 -0
  42. package/dist/src/cli/renderers/specs/init.js +25 -0
  43. package/dist/src/cli/renderers/specs/pipeline.js +561 -0
  44. package/dist/src/cli/renderers/specs/scheduler.js +46 -0
  45. package/dist/src/cli/renderers/specs/server.js +38 -0
  46. package/dist/src/cli/renderers/specs/system.js +36 -0
  47. package/dist/src/cli/router.js +199 -0
  48. package/dist/src/cli/server-runtime-client.js +780 -0
  49. package/dist/src/cli/types.js +2 -0
  50. package/dist/src/gateway/frame-sanitizer.js +78 -0
  51. package/dist/src/gateway/gateway-client.js +462 -0
  52. package/dist/src/gateway/index.js +18 -0
  53. package/dist/src/gateway/types.js +2 -0
  54. package/dist/src/index.js +123 -0
  55. package/dist/src/logs/run-log-reader.js +141 -0
  56. package/dist/src/logs/run-log-service.js +42 -0
  57. package/dist/src/logs/run-log-types.js +2 -0
  58. package/dist/src/pipeline/agent-activity.js +191 -0
  59. package/dist/src/pipeline/artifact-storage.js +208 -0
  60. package/dist/src/pipeline/diagnostics/dependency-diagnostic.js +105 -0
  61. package/dist/src/pipeline/diagnostics/index.js +6 -0
  62. package/dist/src/pipeline/dispatch/pipeline-inbound-queue.js +215 -0
  63. package/dist/src/pipeline/dispatch/pipeline-link-dispatcher.js +66 -0
  64. package/dist/src/pipeline/dispatch/pipeline-link-store.js +94 -0
  65. package/dist/src/pipeline/dispatch/pipeline-queue-drainer.js +71 -0
  66. package/dist/src/pipeline/execution/dependency-check.js +52 -0
  67. package/dist/src/pipeline/execution/execution-result.js +2 -0
  68. package/dist/src/pipeline/execution/group-item-executor.js +128 -0
  69. package/dist/src/pipeline/execution/index.js +5 -0
  70. package/dist/src/pipeline/execution/node-item-executor.js +58 -0
  71. package/dist/src/pipeline/execution/node-runner.js +159 -0
  72. package/dist/src/pipeline/execution/readiness-state.js +10 -0
  73. package/dist/src/pipeline/execution/reject-handler.js +94 -0
  74. package/dist/src/pipeline/execution/rejected-artifact-archiver.js +45 -0
  75. package/dist/src/pipeline/execution/route-item-manager.js +253 -0
  76. package/dist/src/pipeline/execution/run-abort-controller.js +66 -0
  77. package/dist/src/pipeline/execution/run-state-helpers.js +257 -0
  78. package/dist/src/pipeline/execution/service.js +165 -0
  79. package/dist/src/pipeline/execution/session-registry.js +96 -0
  80. package/dist/src/pipeline/execution/structured-node-runner.js +411 -0
  81. package/dist/src/pipeline/execution-status.js +96 -0
  82. package/dist/src/pipeline/execution-timeout.js +21 -0
  83. package/dist/src/pipeline/identity/index.js +32 -0
  84. package/dist/src/pipeline/identity/types.js +2 -0
  85. package/dist/src/pipeline/item-batch-controller.js +227 -0
  86. package/dist/src/pipeline/output/pipeline-output-resolver.js +91 -0
  87. package/dist/src/pipeline/output/pipeline-output-store.js +60 -0
  88. package/dist/src/pipeline/runtime-model.js +173 -0
  89. package/dist/src/pipeline/scheduler/dependency-state.js +144 -0
  90. package/dist/src/pipeline/scheduler-service.js +314 -0
  91. package/dist/src/pipeline/state/group-item-state.js +50 -0
  92. package/dist/src/pipeline/state/group-run-state.js +41 -0
  93. package/dist/src/pipeline/state/index.js +20 -0
  94. package/dist/src/pipeline/state/node-item-state.js +67 -0
  95. package/dist/src/pipeline/state/node-run-state.js +51 -0
  96. package/dist/src/pipeline/state/types.js +2 -0
  97. package/dist/src/pipeline/state-machine.js +101 -0
  98. package/dist/src/pipeline/structured-output/contract.js +133 -0
  99. package/dist/src/pipeline/structured-output/index.js +22 -0
  100. package/dist/src/pipeline/structured-output/parser.js +214 -0
  101. package/dist/src/pipeline/structured-output/prompt.js +290 -0
  102. package/dist/src/pipeline/structured-output/waiter.js +139 -0
  103. package/dist/src/pipeline/template.js +135 -0
  104. package/dist/src/pipeline/timeline-log-store.js +57 -0
  105. package/dist/src/pipeline/tool-activity.js +94 -0
  106. package/dist/src/pipeline/types/pipeline-link.js +7 -0
  107. package/dist/src/pipeline/types/pipeline-output.js +11 -0
  108. package/dist/src/pipeline/types/workflow.js +2 -0
  109. package/dist/src/pipeline/workflow/branch-rules.js +74 -0
  110. package/dist/src/pipeline/workflow/defaults.js +48 -0
  111. package/dist/src/pipeline/workflow/io.js +89 -0
  112. package/dist/src/pipeline/workflow/normalize.js +347 -0
  113. package/dist/src/pipeline/workflow/routes.js +16 -0
  114. package/dist/src/pipeline/workflow/template-mapper.js +113 -0
  115. package/dist/src/pipeline/workflow/validate.js +312 -0
  116. package/dist/src/pipeline/workflow-graph.js +165 -0
  117. package/dist/src/server/api-handler.js +163 -0
  118. package/dist/src/server/http-utils.js +34 -0
  119. package/dist/src/server/middleware.js +61 -0
  120. package/dist/src/server/router.js +105 -0
  121. package/dist/src/server/routes/agents.js +189 -0
  122. package/dist/src/server/routes/artifacts.js +163 -0
  123. package/dist/src/server/routes/gateway.js +18 -0
  124. package/dist/src/server/routes/health.js +16 -0
  125. package/dist/src/server/routes/logs.js +73 -0
  126. package/dist/src/server/routes/pipeline-batch.js +163 -0
  127. package/dist/src/server/routes/pipeline-diagnostics.js +33 -0
  128. package/dist/src/server/routes/pipeline-identity.js +24 -0
  129. package/dist/src/server/routes/pipeline-links.js +117 -0
  130. package/dist/src/server/routes/pipeline-outputs.js +27 -0
  131. package/dist/src/server/routes/pipeline-queue.js +62 -0
  132. package/dist/src/server/routes/pipeline-runtime.js +162 -0
  133. package/dist/src/server/routes/pipeline-scheduler.js +69 -0
  134. package/dist/src/server/routes/pipeline-workflow.js +180 -0
  135. package/dist/src/server/routes/pipelines.js +96 -0
  136. package/dist/src/server/routes/sessions.js +244 -0
  137. package/dist/src/server/routes/timeline.js +14 -0
  138. package/dist/src/server/serve-static.js +42 -0
  139. package/dist/src/server/types.js +2 -0
  140. package/dist/src/services/agent-service.js +79 -0
  141. package/dist/src/services/artifact-service.js +74 -0
  142. package/dist/src/services/gateway-read-helpers.js +10 -0
  143. package/dist/src/services/index.js +23 -0
  144. package/dist/src/services/pipeline-service.js +529 -0
  145. package/dist/src/services/pipeline-status.js +93 -0
  146. package/dist/src/services/read-services.js +60 -0
  147. package/dist/src/services/scheduler-service.js +37 -0
  148. package/dist/src/services/session-service.js +227 -0
  149. package/dist/src/services/system-service.js +26 -0
  150. package/dist/src/transport/ws-broker.js +48 -0
  151. package/dist/src/utils/array.js +17 -0
  152. package/dist/src/utils/guards.js +5 -0
  153. package/dist/src/utils/session.js +60 -0
  154. package/dist/src/version.js +5 -0
  155. package/package.json +61 -0
  156. package/web/dist/assets/index-CWnfhkn-.js +65 -0
  157. package/web/dist/assets/index-gZ0xOfSO.css +1 -0
  158. package/web/dist/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  159. package/web/dist/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  160. package/web/dist/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  161. package/web/dist/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  162. package/web/dist/assets/jetbrains-mono-cyrillic-700-normal-BWTpRfYl.woff2 +0 -0
  163. package/web/dist/assets/jetbrains-mono-cyrillic-700-normal-CEoEElIJ.woff +0 -0
  164. package/web/dist/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  165. package/web/dist/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  166. package/web/dist/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  167. package/web/dist/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  168. package/web/dist/assets/jetbrains-mono-greek-700-normal-C6CZE3T8.woff2 +0 -0
  169. package/web/dist/assets/jetbrains-mono-greek-700-normal-DEigVDxa.woff +0 -0
  170. package/web/dist/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  171. package/web/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  172. package/web/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  173. package/web/dist/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  174. package/web/dist/assets/jetbrains-mono-latin-700-normal-BYuf6tUa.woff2 +0 -0
  175. package/web/dist/assets/jetbrains-mono-latin-700-normal-D3wTyLJW.woff +0 -0
  176. package/web/dist/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  177. package/web/dist/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  178. package/web/dist/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  179. package/web/dist/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  180. package/web/dist/assets/jetbrains-mono-latin-ext-700-normal-CZipNAKV.woff2 +0 -0
  181. package/web/dist/assets/jetbrains-mono-latin-ext-700-normal-CxPITLHs.woff +0 -0
  182. package/web/dist/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  183. package/web/dist/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  184. package/web/dist/assets/jetbrains-mono-vietnamese-700-normal-BDLVIk2r.woff +0 -0
  185. package/web/dist/assets/space-grotesk-latin-400-normal-BnQMeOim.woff +0 -0
  186. package/web/dist/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
  187. package/web/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  188. package/web/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  189. package/web/dist/assets/space-grotesk-latin-700-normal-CwsQ-cCU.woff +0 -0
  190. package/web/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
  191. package/web/dist/assets/space-grotesk-latin-ext-400-normal-CfP_5XZW.woff2 +0 -0
  192. package/web/dist/assets/space-grotesk-latin-ext-400-normal-DRPE3kg4.woff +0 -0
  193. package/web/dist/assets/space-grotesk-latin-ext-500-normal-3dgZTiw9.woff +0 -0
  194. package/web/dist/assets/space-grotesk-latin-ext-500-normal-DUe3BAxM.woff2 +0 -0
  195. package/web/dist/assets/space-grotesk-latin-ext-700-normal-BQnZhY3m.woff2 +0 -0
  196. package/web/dist/assets/space-grotesk-latin-ext-700-normal-HVCqSBdx.woff +0 -0
  197. package/web/dist/assets/space-grotesk-vietnamese-400-normal-B7xT_GF5.woff2 +0 -0
  198. package/web/dist/assets/space-grotesk-vietnamese-400-normal-BIWiOVfw.woff +0 -0
  199. package/web/dist/assets/space-grotesk-vietnamese-500-normal-BTqKIpxg.woff +0 -0
  200. package/web/dist/assets/space-grotesk-vietnamese-500-normal-BmEvtly_.woff2 +0 -0
  201. package/web/dist/assets/space-grotesk-vietnamese-700-normal-DMty7AZE.woff2 +0 -0
  202. package/web/dist/assets/space-grotesk-vietnamese-700-normal-Duxec5Rn.woff +0 -0
  203. package/web/dist/favicon.svg +10 -0
  204. 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;