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,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPipelineRuntime = void 0;
4
+ const http_utils_1 = require("../server/http-utils");
5
+ const template_1 = require("../pipeline/template");
6
+ const execution_timeout_1 = require("../pipeline/execution-timeout");
7
+ const runtime_model_1 = require("../pipeline/runtime-model");
8
+ const array_1 = require("../utils/array");
9
+ const workflow_graph_1 = require("../pipeline/workflow-graph");
10
+ const runtime_store_1 = require("./runtime-store");
11
+ const execution_1 = require("../pipeline/execution");
12
+ const scheduler_service_1 = require("../pipeline/scheduler-service");
13
+ const createPipelineRuntime = (options) => {
14
+ const graph = (0, workflow_graph_1.createWorkflowGraph)((0, template_1.loadWorkflowDefinitionWithStorage)({ workflowFilePath: options.workflowFilePath }), (0, template_1.loadPipelineTemplateWithStorage)({ workflowFilePath: options.workflowFilePath }));
15
+ const initialRun = (0, runtime_model_1.seedRunWithItems)(graph.getTemplateNodes(), options.defaultItemKeys);
16
+ let schedulerStateAccessor = () => ({ enabled: graph.getWorkflow().scheduler.enabled, mode: graph.getWorkflow().scheduler.mode });
17
+ let batchRunStateGetter = () => null;
18
+ const runtimeStore = (0, runtime_store_1.createRuntimeStore)({
19
+ graph,
20
+ defaultItemKeys: options.defaultItemKeys,
21
+ runStateFile: options.runStateFile,
22
+ initialRun,
23
+ getSchedulerState: () => schedulerStateAccessor(),
24
+ getBatchRunState: () => batchRunStateGetter(),
25
+ });
26
+ let getBatchRunId = () => null;
27
+ const executionService = (0, execution_1.createExecutionService)({
28
+ client: options.client,
29
+ runtimeStore,
30
+ graph,
31
+ artifactDir: options.artifactDir,
32
+ pipelineId: options.pipelineId,
33
+ pipelineNodeExecutionTimeoutMs: (0, execution_timeout_1.getPipelineNodeExecutionTimeoutMs)(),
34
+ defaultItemKeys: options.defaultItemKeys,
35
+ getBatchRunId: () => getBatchRunId(),
36
+ });
37
+ const schedulerService = (0, scheduler_service_1.createSchedulerService)({
38
+ pipelineId: options.pipelineId,
39
+ runtimeStore,
40
+ graph,
41
+ defaultItemKeys: options.defaultItemKeys,
42
+ executionService,
43
+ onRunCompleted: options.onRunCompleted,
44
+ });
45
+ getBatchRunId = () => schedulerService.getBatchRunState().batchRunId;
46
+ schedulerStateAccessor = schedulerService.getSchedulerState;
47
+ batchRunStateGetter = () => schedulerService.getBatchRunState();
48
+ const sendJson = (res, code, data) => (0, http_utils_1.sendJson)(res, code, data, options.webOrigin);
49
+ const setRun = (nextRun) => {
50
+ runtimeStore.setRun(nextRun);
51
+ graph.syncRunGroupsFromWorkflow(nextRun);
52
+ if (!nextRun.itemRuns || nextRun.itemRuns.length === 0) {
53
+ runtimeStore.setRun((0, runtime_model_1.seedRunWithItems)(graph.getTemplateNodes(), options.defaultItemKeys));
54
+ graph.syncRunGroupsFromWorkflow(runtimeStore.getRun());
55
+ }
56
+ };
57
+ const setTemplateNodes = (nextNodes) => {
58
+ graph.setTemplateNodes(nextNodes);
59
+ };
60
+ const setWorkflow = (nextWorkflow) => {
61
+ graph.setWorkflow(nextWorkflow);
62
+ schedulerService.syncSchedulerStateFromWorkflow();
63
+ graph.syncRunGroupsFromWorkflow(runtimeStore.getRun());
64
+ };
65
+ const onGatewayStatus = (status) => {
66
+ runtimeStore.setLatestStatus(status);
67
+ runtimeStore.pushTimeline(`网关状态: ${status.status}`, status.status.includes("failed") ? "error" : "info");
68
+ runtimeStore.broadcast({
69
+ type: "gateway.status",
70
+ payload: status,
71
+ });
72
+ };
73
+ const onGatewayFrame = (frame) => {
74
+ const isHealthEvent = frame.type === "event" && frame.event === "health";
75
+ const isTickEvent = frame.type === "event" && frame.event === "tick";
76
+ const isSilentEvent = isHealthEvent || isTickEvent;
77
+ runtimeStore.setLastFrame(frame);
78
+ if (frame.type === "event" && !isSilentEvent) {
79
+ runtimeStore.pushTimeline(`事件: ${frame.event}`, "info", {
80
+ type: "event",
81
+ event: frame.event,
82
+ seq: frame.seq ?? null,
83
+ stateVersion: frame.stateVersion ?? null,
84
+ payload: frame.payload ?? null,
85
+ });
86
+ }
87
+ // health / tick 都是高频事件,只保留为 lastFrame,不推送到 timeline / ws,
88
+ // 避免前端与日志被刷屏,同时不影响依赖最后一帧做诊断的调试能力。
89
+ if (!isSilentEvent) {
90
+ runtimeStore.broadcast({
91
+ type: "gateway.frame",
92
+ payload: frame,
93
+ });
94
+ }
95
+ };
96
+ const onGatewayRawFrame = (rawFrame) => {
97
+ executionService.onGatewayFrame(rawFrame);
98
+ };
99
+ const onGatewayError = (error) => {
100
+ runtimeStore.pushTimeline(`网关错误: ${String(error)}`, "error");
101
+ runtimeStore.broadcast({
102
+ type: "gateway.error",
103
+ payload: { message: String(error) },
104
+ });
105
+ };
106
+ const onGatewayReady = (hello) => {
107
+ runtimeStore.setLatestHello(hello);
108
+ runtimeStore.pushTimeline("网关握手完成");
109
+ runtimeStore.emitPipeline();
110
+ runtimeStore.broadcast({
111
+ type: "gateway.ready",
112
+ payload: hello,
113
+ });
114
+ };
115
+ const getBootstrapPayload = () => {
116
+ const run = runtimeStore.getRun();
117
+ const nodesWithWorkflowMeta = graph.getNodesWithWorkflowMeta(run.nodes);
118
+ return {
119
+ status: runtimeStore.getLatestStatus() ?? options.client.getStatus(),
120
+ timeline: runtimeStore.getTimeline(),
121
+ run: { ...run, nodes: nodesWithWorkflowMeta },
122
+ pipeline: nodesWithWorkflowMeta,
123
+ runId: run.id,
124
+ hello: runtimeStore.getLatestHello(),
125
+ scheduler: schedulerService.getSchedulerState(),
126
+ batchRunState: schedulerService.getBatchRunState(),
127
+ };
128
+ };
129
+ const hasActiveSession = (sessionKey) => {
130
+ return executionService.hasActiveSession?.(sessionKey) ?? false;
131
+ };
132
+ const initialize = async () => {
133
+ await runtimeStore.restorePersistedRunState();
134
+ };
135
+ return {
136
+ initialize,
137
+ dispose: () => executionService.dispose(),
138
+ sendJson,
139
+ getBootstrapPayload,
140
+ onGatewayStatus,
141
+ onGatewayFrame,
142
+ onGatewayRawFrame,
143
+ hasActiveSession,
144
+ onGatewayError,
145
+ onGatewayReady,
146
+ runtime: {
147
+ setBroadcast: runtimeStore.setBroadcast,
148
+ pushTimeline: runtimeStore.pushTimeline,
149
+ emitPipeline: runtimeStore.emitPipeline,
150
+ getRun: runtimeStore.getRun,
151
+ setRun,
152
+ seedRun: runtimeStore.seedRun,
153
+ getTimeline: runtimeStore.getTimeline,
154
+ touchRun: runtime_model_1.touchRun,
155
+ },
156
+ gateway: {
157
+ client: options.client,
158
+ getLatestStatus: runtimeStore.getLatestStatus,
159
+ getLatestHello: runtimeStore.getLatestHello,
160
+ getLastFrame: runtimeStore.getLastFrame,
161
+ refreshSessionsFromGateway: executionService.refreshSessionsFromGateway,
162
+ getSessionCache: executionService.getSessionCache,
163
+ getExecutorSessionByAgentId: executionService.getExecutorSessionByAgentId,
164
+ pickArray: array_1.pickArray,
165
+ },
166
+ workflow: {
167
+ getTemplateNodes: graph.getTemplateNodes,
168
+ setTemplateNodes,
169
+ getWorkflow: graph.getWorkflow,
170
+ setWorkflow,
171
+ mergeTemplateNodesIntoWorkflow: template_1.mergeTemplateNodesIntoWorkflow,
172
+ getWorkflowNodeById: graph.getWorkflowNodeById,
173
+ getIncomingEdges: graph.getIncomingEdges,
174
+ isCrossBranchEdge: graph.isCrossBranchEdge,
175
+ isGroupId: graph.isGroupId,
176
+ isWorkflowNodeEnabled: graph.isWorkflowNodeEnabled,
177
+ pipelineId: options.pipelineId,
178
+ },
179
+ pipeline: {
180
+ getItemRuns: () => runtimeStore.getRun().itemRuns ?? [],
181
+ executeNode: executionService.executeNode,
182
+ retryNodeExecution: schedulerService.retryNodeExecution,
183
+ drainPipeline: schedulerService.drainPipeline,
184
+ getSchedulerState: schedulerService.getSchedulerState,
185
+ setSchedulerEnabled: schedulerService.setSchedulerEnabled,
186
+ setSchedulerMode: schedulerService.setSchedulerMode,
187
+ getBatchRunState: schedulerService.getBatchRunState,
188
+ startBatchRun: schedulerService.startBatchRun,
189
+ stopBatchRun: schedulerService.stopBatchRun,
190
+ cancelBatchRun: schedulerService.cancelBatchRun,
191
+ abortRunControllers: executionService.abortRunControllers,
192
+ getOrCreateDrainSignal: executionService.getOrCreateDrainSignal,
193
+ },
194
+ output: {
195
+ list: options.outputStore.list.bind(options.outputStore),
196
+ getByRunId: options.outputStore.getByRunId.bind(options.outputStore),
197
+ getById: options.outputStore.getById.bind(options.outputStore),
198
+ append: options.outputStore.append.bind(options.outputStore),
199
+ },
200
+ };
201
+ };
202
+ exports.createPipelineRuntime = createPipelineRuntime;
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRuntimeStore = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const frame_sanitizer_1 = require("../gateway/frame-sanitizer");
6
+ const runtime_model_1 = require("../pipeline/runtime-model");
7
+ const timeline_log_store_1 = require("../pipeline/timeline-log-store");
8
+ const data_dir_1 = require("./data-dir");
9
+ const createRuntimeStore = (options) => {
10
+ const timeline = [];
11
+ let run = options.initialRun;
12
+ let latestStatus = null;
13
+ let latestHello = null;
14
+ let lastFrame = null;
15
+ let broadcast = () => { };
16
+ let persistRunStateInFlight = null;
17
+ const timelineLogStore = (0, timeline_log_store_1.createTimelineLogStore)({
18
+ rootDir: (0, data_dir_1.resolveTaskMeldDataPath)("logs", "runs"),
19
+ });
20
+ const persistRunState = async () => {
21
+ if (persistRunStateInFlight)
22
+ return persistRunStateInFlight;
23
+ persistRunStateInFlight = (async () => {
24
+ try {
25
+ await (0, promises_1.mkdir)((0, data_dir_1.resolveTaskMeldDataPath)(), { recursive: true });
26
+ await (0, promises_1.writeFile)(options.runStateFile, JSON.stringify({
27
+ savedAt: new Date().toISOString(),
28
+ workflowVersion: options.graph.getWorkflow().version,
29
+ run,
30
+ }, null, 2), "utf8");
31
+ }
32
+ catch (error) {
33
+ // Persistence failures should not break pipeline execution.
34
+ pushTimeline(`持久化运行状态失败: ${error instanceof Error ? error.message : String(error)}`, "warn");
35
+ }
36
+ })().finally(() => {
37
+ persistRunStateInFlight = null;
38
+ });
39
+ return persistRunStateInFlight;
40
+ };
41
+ const tryLoadPersistedRunState = async () => {
42
+ try {
43
+ const raw = await (0, promises_1.readFile)(options.runStateFile, "utf8");
44
+ const parsed = JSON.parse(raw);
45
+ if (!parsed || typeof parsed !== "object")
46
+ return null;
47
+ const payload = parsed;
48
+ const savedRun = payload.run;
49
+ if (!savedRun || !Array.isArray(savedRun.nodes))
50
+ return null;
51
+ if (!Array.isArray(savedRun.itemRuns))
52
+ return null;
53
+ if (!Array.isArray(savedRun.groups))
54
+ savedRun.groups = [];
55
+ if (!Array.isArray(savedRun.groupItemRuns))
56
+ savedRun.groupItemRuns = [];
57
+ if (!savedRun.input)
58
+ savedRun.input = { trigger: "manual" };
59
+ if (savedRun.output === undefined)
60
+ savedRun.output = null;
61
+ const nodeIds = new Set(savedRun.nodes.map((node) => node.id));
62
+ const templateNodes = options.graph.getTemplateNodes();
63
+ if (nodeIds.size !== templateNodes.length)
64
+ return null;
65
+ for (const node of templateNodes) {
66
+ if (!nodeIds.has(node.id))
67
+ return null;
68
+ }
69
+ return savedRun;
70
+ }
71
+ catch (error) {
72
+ pushTimeline(`加载持久化运行状态失败: ${error instanceof Error ? error.message : String(error)}`, "warn");
73
+ return null;
74
+ }
75
+ };
76
+ const pushTimeline = (text, level = "info", detail) => {
77
+ const safeDetail = detail !== undefined ? (0, frame_sanitizer_1.sanitizeDiagnosticPayload)(detail) : undefined;
78
+ const item = (0, runtime_model_1.addTimeline)(timeline, text, level, safeDetail);
79
+ void timelineLogStore.appendTimeline(run.id, item);
80
+ broadcast({
81
+ type: "timeline.updated",
82
+ payload: { item },
83
+ });
84
+ };
85
+ const emitPipeline = () => {
86
+ options.graph.syncRunGroupsFromWorkflow(run);
87
+ (0, runtime_model_1.syncRunNodeStatusFromItemRuns)(run);
88
+ (0, runtime_model_1.touchRun)(run);
89
+ const nodesWithWorkflowMeta = options.graph.getNodesWithWorkflowMeta(run.nodes);
90
+ broadcast({
91
+ type: "pipeline.updated",
92
+ payload: {
93
+ run: { ...run, nodes: nodesWithWorkflowMeta },
94
+ runId: run.id,
95
+ nodes: nodesWithWorkflowMeta,
96
+ scheduler: { ...options.getSchedulerState() },
97
+ ...(options.getBatchRunState ? { batchRunState: options.getBatchRunState() } : {}),
98
+ },
99
+ });
100
+ void persistRunState();
101
+ };
102
+ const restorePersistedRunState = async () => {
103
+ const persisted = await tryLoadPersistedRunState();
104
+ if (!persisted)
105
+ return;
106
+ run = persisted;
107
+ options.graph.syncRunGroupsFromWorkflow(run);
108
+ (0, runtime_model_1.syncRunNodeStatusFromItemRuns)(run);
109
+ (0, runtime_model_1.touchRun)(run);
110
+ pushTimeline(`已恢复上次运行状态: ${run.id}`);
111
+ emitPipeline();
112
+ };
113
+ const bootstrapRun = () => {
114
+ if (run.itemRuns && run.itemRuns.length > 0)
115
+ return;
116
+ run = (0, runtime_model_1.seedRunWithItems)(options.graph.getTemplateNodes(), options.defaultItemKeys);
117
+ options.graph.syncRunGroupsFromWorkflow(run);
118
+ };
119
+ return {
120
+ getRun: () => run,
121
+ setRun: (nextRun) => {
122
+ run = nextRun;
123
+ },
124
+ bootstrapRun,
125
+ seedRun: (nodes = options.graph.getTemplateNodes(), itemKeys = options.defaultItemKeys) => (0, runtime_model_1.seedRunWithItems)(nodes, itemKeys),
126
+ getTimeline: () => timeline,
127
+ pushTimeline,
128
+ emitPipeline,
129
+ restorePersistedRunState,
130
+ persistRunState,
131
+ setBroadcast: (nextBroadcast) => {
132
+ broadcast = nextBroadcast;
133
+ },
134
+ broadcast: (payload) => {
135
+ broadcast(payload);
136
+ },
137
+ getLatestStatus: () => latestStatus,
138
+ setLatestStatus: (status) => {
139
+ latestStatus = status;
140
+ },
141
+ getLatestHello: () => latestHello,
142
+ setLatestHello: (hello) => {
143
+ latestHello = hello;
144
+ },
145
+ getLastFrame: () => lastFrame,
146
+ setLastFrame: (frame) => {
147
+ lastFrame = frame;
148
+ },
149
+ };
150
+ };
151
+ exports.createRuntimeStore = createRuntimeStore;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveGatewayConfig = exports.writeUserConfig = exports.readUserConfig = void 0;
4
+ const node_os_1 = require("node:os");
5
+ const node_path_1 = require("node:path");
6
+ const promises_1 = require("node:fs/promises");
7
+ const userConfigDir = (0, node_path_1.join)((0, node_os_1.homedir)(), ".taskmeld");
8
+ const userConfigPath = (0, node_path_1.join)(userConfigDir, "config.json");
9
+ const readUserConfig = async () => {
10
+ try {
11
+ const raw = await (0, promises_1.readFile)(userConfigPath, "utf8");
12
+ const parsed = JSON.parse(raw);
13
+ return {
14
+ gatewayUrl: typeof parsed.gatewayUrl === "string" ? parsed.gatewayUrl.trim() : undefined,
15
+ gatewayToken: typeof parsed.gatewayToken === "string" ? parsed.gatewayToken.trim() : undefined,
16
+ };
17
+ }
18
+ catch {
19
+ return {};
20
+ }
21
+ };
22
+ exports.readUserConfig = readUserConfig;
23
+ const writeUserConfig = async (config) => {
24
+ await (0, promises_1.mkdir)(userConfigDir, { recursive: true });
25
+ const existing = await (0, exports.readUserConfig)();
26
+ const merged = { ...existing, ...config };
27
+ await (0, promises_1.writeFile)(userConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf8");
28
+ };
29
+ exports.writeUserConfig = writeUserConfig;
30
+ const resolveGatewayConfig = async () => {
31
+ const userConfig = await (0, exports.readUserConfig)();
32
+ return {
33
+ url: process.env.OPENCLAW_GATEWAY_URL?.trim() || userConfig.gatewayUrl || null,
34
+ token: process.env.OPENCLAW_GATEWAY_TOKEN?.trim() || userConfig.gatewayToken || null,
35
+ };
36
+ };
37
+ exports.resolveGatewayConfig = resolveGatewayConfig;
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cleanupTempFiles = exports.cleanupEmptyDirs = exports.executeCleanup = exports.planCleanup = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const node_path_1 = require("node:path");
6
+ const storage_service_1 = require("./storage-service");
7
+ const artifact_index_1 = require("./artifact-index");
8
+ const DEFAULT_RETENTION_DAYS = {
9
+ success: 30,
10
+ failed: 90,
11
+ rejected: 90,
12
+ };
13
+ const ONE_DAY_MS = 24 * 60 * 60 * 1000;
14
+ /**
15
+ * 生成清理计划,不删除任何文件。
16
+ * 默认只清理 success 状态,可通过 options 指定其他状态。
17
+ */
18
+ const planCleanup = async (definition, options = {}) => {
19
+ const statuses = options.statuses?.length ? options.statuses : ["success"];
20
+ const safeStatuses = statuses.filter((s) => s !== "unknown");
21
+ const statusFilter = new Set(safeStatuses);
22
+ const kindFilter = options.kinds?.length ? new Set(options.kinds) : null;
23
+ const olderThanDays = options.olderThanDays ?? Math.max(...safeStatuses.map((s) => DEFAULT_RETENTION_DAYS[s] ?? 90));
24
+ const cutoffMs = Date.now() - olderThanDays * ONE_DAY_MS;
25
+ // 优先从索引获取文件列表,索引缺失时回退扫描
26
+ let items = await (0, artifact_index_1.readIndexRecords)(definition.artifactDir);
27
+ if (items.length === 0) {
28
+ const scanned = await (0, storage_service_1.scanStoredArtifacts)([definition]);
29
+ items = scanned.map((item) => ({
30
+ schemaVersion: 1,
31
+ artifactId: "",
32
+ pipelineId: item.pipelineId,
33
+ status: item.status,
34
+ kind: "artifact",
35
+ dateBucket: item.dateBucket,
36
+ runId: item.runId,
37
+ batchRunId: null,
38
+ nodeId: item.nodeId,
39
+ groupId: null,
40
+ itemKey: null,
41
+ requestId: null,
42
+ type: "unknown",
43
+ artifactSchemaVersion: 1,
44
+ name: "",
45
+ relativePath: item.relativePath,
46
+ sizeBytes: item.sizeBytes,
47
+ hash: "",
48
+ createdAt: item.updatedAt,
49
+ updatedAt: item.updatedAt,
50
+ }));
51
+ }
52
+ const files = [];
53
+ let totalSizeBytes = 0;
54
+ let oldestDate = null;
55
+ let newestDate = null;
56
+ for (const item of items) {
57
+ if (!statusFilter.has(item.status))
58
+ continue;
59
+ if (kindFilter && !kindFilter.has(item.kind))
60
+ continue;
61
+ const itemMs = Date.parse(item.updatedAt);
62
+ if (!Number.isFinite(itemMs) || itemMs > cutoffMs)
63
+ continue;
64
+ if (options.maxSizeBytes != null && totalSizeBytes + item.sizeBytes > options.maxSizeBytes)
65
+ break;
66
+ files.push({
67
+ relativePath: item.relativePath,
68
+ sizeBytes: item.sizeBytes,
69
+ hash: item.hash,
70
+ });
71
+ totalSizeBytes += item.sizeBytes;
72
+ const dateBucket = item.dateBucket;
73
+ if (dateBucket && (oldestDate === null || dateBucket < oldestDate))
74
+ oldestDate = dateBucket;
75
+ if (dateBucket && (newestDate === null || dateBucket > newestDate))
76
+ newestDate = dateBucket;
77
+ }
78
+ return {
79
+ pipelineId: definition.id,
80
+ files,
81
+ totalSizeBytes,
82
+ oldestDate,
83
+ newestDate,
84
+ };
85
+ };
86
+ exports.planCleanup = planCleanup;
87
+ /**
88
+ * 执行清理:删除文件 + 清理空目录 + 清理临时文件 + 重建索引。
89
+ */
90
+ const executeCleanup = async (definition, plan) => {
91
+ const warnings = [];
92
+ let deleted = 0;
93
+ let failed = 0;
94
+ for (const file of plan.files) {
95
+ const rootAbs = (0, node_path_1.resolve)(definition.artifactDir);
96
+ const absPath = (0, node_path_1.resolve)(rootAbs, file.relativePath);
97
+ // 路径穿越保护:目标必须位于当前 pipeline 的 artifactDir 内
98
+ if (absPath !== rootAbs && !absPath.startsWith(`${rootAbs}${node_path_1.sep}`)) {
99
+ failed += 1;
100
+ warnings.push(`拒绝删除越界文件 (${definition.id}:${file.relativePath})`);
101
+ continue;
102
+ }
103
+ try {
104
+ await (0, promises_1.rm)(absPath);
105
+ deleted += 1;
106
+ }
107
+ catch (error) {
108
+ failed += 1;
109
+ warnings.push(`删除失败 (${definition.id}:${file.relativePath}): ${error instanceof Error ? error.message : String(error)}`);
110
+ }
111
+ }
112
+ // 清理空目录
113
+ await (0, exports.cleanupEmptyDirs)(definition.artifactDir);
114
+ // 清理临时文件
115
+ const tmpResult = await (0, exports.cleanupTempFiles)(definition.artifactDir);
116
+ warnings.push(...tmpResult.warnings);
117
+ // 重建索引以移除已删文件
118
+ try {
119
+ const { rebuildArtifactIndex } = await import("./artifact-index.js");
120
+ await rebuildArtifactIndex(definition, (d) => (0, storage_service_1.scanStoredArtifacts)([d]));
121
+ }
122
+ catch {
123
+ warnings.push(`删除后自动重建索引失败 (${definition.id}),请手动执行 rebuild-index`);
124
+ }
125
+ return { deleted, failed, warnings };
126
+ };
127
+ exports.executeCleanup = executeCleanup;
128
+ /**
129
+ * 递归清理空目录。保留 artifactDir 根目录本身。
130
+ */
131
+ const cleanupEmptyDirs = async (artifactDir) => {
132
+ const warnings = [];
133
+ let removed = 0;
134
+ const walkAndRemove = async (dirPath) => {
135
+ try {
136
+ const entries = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
137
+ for (const entry of entries) {
138
+ if (entry.isDirectory()) {
139
+ await walkAndRemove(`${dirPath}${node_path_1.sep}${entry.name}`);
140
+ }
141
+ }
142
+ // 不删除 artifacts 根目录本身
143
+ const isRoot = dirPath === artifactDir || dirPath.endsWith(`${node_path_1.sep}artifacts`) && dirPath.replace(/\\/g, "/").endsWith("/artifacts");
144
+ if (isRoot)
145
+ return;
146
+ const after = await (0, promises_1.readdir)(dirPath);
147
+ if (after.length === 0) {
148
+ await (0, promises_1.rmdir)(dirPath);
149
+ removed += 1;
150
+ }
151
+ }
152
+ catch {
153
+ // 目录不存在或无权访问
154
+ }
155
+ };
156
+ await walkAndRemove(artifactDir);
157
+ return { removed, warnings };
158
+ };
159
+ exports.cleanupEmptyDirs = cleanupEmptyDirs;
160
+ /**
161
+ * 清理 persistArtifactFile 遗留的 .tmp-*.json 临时文件(原子写入失败残留)。
162
+ */
163
+ const cleanupTempFiles = async (artifactDir) => {
164
+ const warnings = [];
165
+ let cleaned = 0;
166
+ const walkAndClean = async (dirPath) => {
167
+ try {
168
+ const entries = await (0, promises_1.readdir)(dirPath, { withFileTypes: true });
169
+ for (const entry of entries) {
170
+ const subPath = `${dirPath}${node_path_1.sep}${entry.name}`;
171
+ if (entry.isDirectory()) {
172
+ await walkAndClean(subPath);
173
+ }
174
+ else if (entry.isFile() && entry.name.startsWith(".tmp-") && entry.name.endsWith(".json")) {
175
+ try {
176
+ await (0, promises_1.rm)(subPath);
177
+ cleaned += 1;
178
+ }
179
+ catch (error) {
180
+ warnings.push(`清理临时文件失败: ${error instanceof Error ? error.message : String(error)}`);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ catch {
186
+ // 目录不存在
187
+ }
188
+ };
189
+ await walkAndClean(artifactDir);
190
+ return { cleaned, warnings };
191
+ };
192
+ exports.cleanupTempFiles = cleanupTempFiles;