taskmeld 0.1.2 → 0.1.41

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 (154) hide show
  1. package/README.md +176 -176
  2. package/README.zh-CN.md +176 -176
  3. package/dist/src/app/app-context-env.js +1 -1
  4. package/dist/src/app/create-app-context.js +3 -3
  5. package/dist/src/app/data-dir.js +13 -3
  6. package/dist/src/app/pipeline-config.js +4 -4
  7. package/dist/src/app/pipeline-registry.js +11 -11
  8. package/dist/src/app/pipeline-runtime.js +6 -9
  9. package/dist/src/app/runtime-store.js +3 -3
  10. package/dist/src/artifacts/artifact-cleanup.js +17 -17
  11. package/dist/src/artifacts/artifact-index.js +14 -14
  12. package/dist/src/artifacts/artifact-rebuilder.js +3 -3
  13. package/dist/src/artifacts/storage-service.js +18 -18
  14. package/dist/src/cli/bootstrap.js +7 -7
  15. package/dist/src/cli/commands/agent.js +12 -11
  16. package/dist/src/cli/commands/artifact.js +31 -30
  17. package/dist/src/cli/commands/init.js +49 -47
  18. package/dist/src/cli/commands/pipeline/result.js +9 -8
  19. package/dist/src/cli/commands/pipeline/selector.js +1 -1
  20. package/dist/src/cli/commands/pipeline/watch.js +2 -2
  21. package/dist/src/cli/commands/pipeline.js +54 -53
  22. package/dist/src/cli/commands/scheduler.js +9 -8
  23. package/dist/src/cli/commands/server.js +12 -11
  24. package/dist/src/cli/commands/system.js +4 -3
  25. package/dist/src/cli/errors.js +2 -2
  26. package/dist/src/cli/help.js +18 -17
  27. package/dist/src/cli/i18n.js +46 -0
  28. package/dist/src/cli/locales/en.json +244 -0
  29. package/dist/src/cli/locales/zh.json +244 -0
  30. package/dist/src/cli/output.js +3 -3
  31. package/dist/src/cli/renderers/engine/markdown.js +1 -1
  32. package/dist/src/cli/renderers/specs/index.js +1 -1
  33. package/dist/src/cli/router.js +1 -1
  34. package/dist/src/cli/server-runtime-client.js +54 -95
  35. package/dist/src/cli/ui-prompts.js +96 -0
  36. package/dist/src/cli/ws-runtime-client.js +51 -0
  37. package/dist/src/gateway/gateway-client.js +4 -4
  38. package/dist/src/index.js +28 -2
  39. package/dist/src/logs/run-log-reader.js +1 -1
  40. package/dist/src/pipeline/agent-activity.js +2 -2
  41. package/dist/src/pipeline/artifact-storage.js +11 -11
  42. package/dist/src/pipeline/diagnostics/dependency-diagnostic.js +11 -11
  43. package/dist/src/pipeline/dispatch/pipeline-inbound-queue.js +2 -2
  44. package/dist/src/pipeline/execution/group-item-executor.js +1 -1
  45. package/dist/src/pipeline/execution/node-item-executor.js +3 -3
  46. package/dist/src/pipeline/execution/node-runner.js +7 -7
  47. package/dist/src/pipeline/execution/readiness-state.js +1 -1
  48. package/dist/src/pipeline/execution/reject-handler.js +5 -5
  49. package/dist/src/pipeline/execution/rejected-artifact-archiver.js +1 -1
  50. package/dist/src/pipeline/execution/route-item-manager.js +4 -4
  51. package/dist/src/pipeline/execution/run-abort-controller.js +5 -5
  52. package/dist/src/pipeline/execution/run-state-helpers.js +2 -2
  53. package/dist/src/pipeline/execution/service.js +4 -4
  54. package/dist/src/pipeline/execution/structured-node-runner.js +24 -24
  55. package/dist/src/pipeline/execution-timeout.js +3 -3
  56. package/dist/src/pipeline/identity/index.js +3 -3
  57. package/dist/src/pipeline/item-batch-controller.js +6 -6
  58. package/dist/src/pipeline/scheduler/dependency-state.js +5 -5
  59. package/dist/src/pipeline/scheduler-service.js +24 -24
  60. package/dist/src/pipeline/state-machine.js +2 -2
  61. package/dist/src/pipeline/structured-output/contract.js +4 -4
  62. package/dist/src/pipeline/structured-output/index.js +2 -2
  63. package/dist/src/pipeline/structured-output/parser.js +5 -5
  64. package/dist/src/pipeline/structured-output/prompt.js +38 -38
  65. package/dist/src/pipeline/structured-output/waiter.js +6 -6
  66. package/dist/src/pipeline/template.js +5 -5
  67. package/dist/src/pipeline/timeline-log-store.js +5 -5
  68. package/dist/src/pipeline/tool-activity.js +3 -3
  69. package/dist/src/pipeline/types/pipeline-output.js +1 -1
  70. package/dist/src/pipeline/workflow/branch-rules.js +19 -19
  71. package/dist/src/pipeline/workflow/io.js +1 -1
  72. package/dist/src/pipeline/workflow/normalize.js +18 -18
  73. package/dist/src/pipeline/workflow/template-mapper.js +3 -3
  74. package/dist/src/pipeline/workflow/validate.js +39 -39
  75. package/dist/src/pipeline/workflow-graph.js +10 -10
  76. package/dist/src/server/http-handler.js +74 -0
  77. package/dist/src/services/agent-service.js +2 -2
  78. package/dist/src/services/gateway-read-helpers.js +1 -1
  79. package/dist/src/services/pipeline-service.js +19 -19
  80. package/dist/src/services/pipeline-status.js +4 -4
  81. package/dist/src/services/read-services.js +1 -1
  82. package/dist/src/services/session-service.js +6 -6
  83. package/dist/src/services/system-service.js +1 -1
  84. package/dist/src/transport/ws-broker.js +12 -1
  85. package/dist/src/transport/ws-handler.js +60 -0
  86. package/dist/src/transport/ws-methods/agents.js +144 -0
  87. package/dist/src/transport/ws-methods/artifacts.js +171 -0
  88. package/dist/src/transport/ws-methods/gateway.js +16 -0
  89. package/dist/src/transport/ws-methods/logs.js +43 -0
  90. package/dist/src/transport/ws-methods/pipeline-batch.js +68 -0
  91. package/dist/src/transport/ws-methods/pipeline-links.js +100 -0
  92. package/dist/src/transport/ws-methods/pipeline-queue.js +51 -0
  93. package/dist/src/transport/ws-methods/pipeline-runtime.js +151 -0
  94. package/dist/src/transport/ws-methods/pipeline-scheduler.js +48 -0
  95. package/dist/src/transport/ws-methods/pipeline-workflow.js +127 -0
  96. package/dist/src/transport/ws-methods/pipelines.js +56 -0
  97. package/dist/src/transport/ws-methods/register-all.js +32 -0
  98. package/dist/src/transport/ws-methods/sessions.js +154 -0
  99. package/dist/src/transport/ws-methods/timeline.js +10 -0
  100. package/dist/src/{server/routes/pipeline-identity.js → transport/ws-methods/utils.js} +14 -9
  101. package/dist/src/version.js +1 -1
  102. package/package.json +15 -7
  103. package/web/dist/assets/agent-DP6TMcLj.js +1 -0
  104. package/web/dist/assets/agent-DmJHzLyj.js +1 -0
  105. package/web/dist/assets/artifact-BqnoZy2M.js +1 -0
  106. package/web/dist/assets/artifact-DfDkgkno.js +1 -0
  107. package/web/dist/assets/common-DRMTVwE9.js +1 -0
  108. package/web/dist/assets/common-DeXccbr2.js +1 -0
  109. package/web/dist/assets/dispatch-CBskGCQI.js +1 -0
  110. package/web/dist/assets/dispatch-sk4Wp30e.js +1 -0
  111. package/web/dist/assets/index-C8wTjZvH.css +1 -0
  112. package/web/dist/assets/index-DYDQZRLk.js +58 -0
  113. package/web/dist/assets/log-DN8cjb0w.js +1 -0
  114. package/web/dist/assets/log-HSeA_dYy.js +1 -0
  115. package/web/dist/assets/modal-BdNai9jf.js +1 -0
  116. package/web/dist/assets/modal-D9_KDpFD.js +1 -0
  117. package/web/dist/assets/nav-BmF7oAKg.js +1 -0
  118. package/web/dist/assets/nav-IjC2xqXQ.js +1 -0
  119. package/web/dist/assets/node-detail-CENRXcrh.js +1 -0
  120. package/web/dist/assets/node-detail-bndPr0IM.js +1 -0
  121. package/web/dist/assets/overview-B87zWAxq.js +1 -0
  122. package/web/dist/assets/overview-gQvk-NOK.js +1 -0
  123. package/web/dist/assets/pipeline-D4dSJRDz.js +1 -0
  124. package/web/dist/assets/pipeline-DZzyOqQa.js +1 -0
  125. package/web/dist/assets/session-CUWvU14v.js +5 -0
  126. package/web/dist/assets/session-DQ6UuCaJ.js +5 -0
  127. package/web/dist/assets/timeline-8y_2_0Em.js +1 -0
  128. package/web/dist/assets/timeline-CAPsXUTC.js +1 -0
  129. package/web/dist/index.html +3 -3
  130. package/dist/src/app/pipeline-plugin-config.js +0 -2
  131. package/dist/src/server/api-handler.js +0 -163
  132. package/dist/src/server/http-utils.js +0 -34
  133. package/dist/src/server/middleware.js +0 -61
  134. package/dist/src/server/router.js +0 -105
  135. package/dist/src/server/routes/agents.js +0 -189
  136. package/dist/src/server/routes/artifacts.js +0 -163
  137. package/dist/src/server/routes/gateway.js +0 -18
  138. package/dist/src/server/routes/health.js +0 -16
  139. package/dist/src/server/routes/logs.js +0 -73
  140. package/dist/src/server/routes/pipeline-batch.js +0 -163
  141. package/dist/src/server/routes/pipeline-diagnostics.js +0 -33
  142. package/dist/src/server/routes/pipeline-links.js +0 -117
  143. package/dist/src/server/routes/pipeline-outputs.js +0 -27
  144. package/dist/src/server/routes/pipeline-queue.js +0 -62
  145. package/dist/src/server/routes/pipeline-runtime.js +0 -162
  146. package/dist/src/server/routes/pipeline-scheduler.js +0 -69
  147. package/dist/src/server/routes/pipeline-workflow.js +0 -180
  148. package/dist/src/server/routes/pipelines.js +0 -96
  149. package/dist/src/server/routes/sessions.js +0 -244
  150. package/dist/src/server/routes/timeline.js +0 -14
  151. package/dist/src/server/serve-static.js +0 -42
  152. package/web/dist/assets/index-CWnfhkn-.js +0 -65
  153. package/web/dist/assets/index-gZ0xOfSO.css +0 -1
  154. /package/dist/src/{server → transport/ws-methods}/types.js +0 -0
@@ -1,117 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPipelineLinksRoutes = void 0;
4
- const node_crypto_1 = require("node:crypto");
5
- const pipeline_link_js_1 = require("../../pipeline/types/pipeline-link.js");
6
- const registerPipelineLinksRoutes = (router) => {
7
- // GET /api/pipeline-links
8
- router.register("GET", "/api/pipeline-links", async (ctx) => {
9
- const { app } = ctx.options;
10
- const links = await app.dispatch.listLinks();
11
- ctx.sendJson(200, { ok: true, items: links });
12
- });
13
- // POST /api/pipeline-links
14
- router.register("POST", "/api/pipeline-links", async (ctx) => {
15
- const { app } = ctx.options;
16
- const body = await ctx.readBody();
17
- const id = typeof body.id === "string" ? body.id.trim() : `link:${(0, node_crypto_1.randomUUID)()}`;
18
- if (!(0, pipeline_link_js_1.isValidLinkId)(id)) {
19
- ctx.sendJson(400, { ok: false, error: "pipeline_link_invalid_id" });
20
- return;
21
- }
22
- const fromPipelineId = typeof body.fromPipelineId === "string" ? body.fromPipelineId.trim() : "";
23
- const toPipelineId = typeof body.toPipelineId === "string" ? body.toPipelineId.trim() : "";
24
- if (!fromPipelineId || !toPipelineId) {
25
- ctx.sendJson(400, { ok: false, error: "pipeline_link_missing_pipelines" });
26
- return;
27
- }
28
- if (!app.getPipelineDefinition(fromPipelineId)) {
29
- ctx.sendJson(400, { ok: false, error: "pipeline_not_found", detail: `上游流水线 ${fromPipelineId} 不存在` });
30
- return;
31
- }
32
- if (!app.getPipelineDefinition(toPipelineId)) {
33
- ctx.sendJson(400, { ok: false, error: "pipeline_not_found", detail: `下游流水线 ${toPipelineId} 不存在` });
34
- return;
35
- }
36
- const contract = body.inputContract && typeof body.inputContract === "object"
37
- ? {
38
- requireType: typeof body.inputContract.requireType === "string"
39
- ? body.inputContract.requireType
40
- : undefined,
41
- requireSchemaVersion: typeof body.inputContract.requireSchemaVersion === "number"
42
- ? body.inputContract.requireSchemaVersion
43
- : undefined,
44
- }
45
- : null;
46
- const maxPendingJobs = typeof body.maxPendingJobs === "number" && Number.isFinite(body.maxPendingJobs)
47
- ? Math.min(10000, Math.max(1, Math.trunc(body.maxPendingJobs)))
48
- : 100;
49
- const onJobFailed = body.onJobFailed === "pause" ? "pause" : "continue";
50
- const now = new Date().toISOString();
51
- const link = {
52
- schemaVersion: 1,
53
- id,
54
- enabled: body.enabled !== false,
55
- fromPipelineId,
56
- toPipelineId,
57
- trigger: "on_success",
58
- dispatchPolicy: "fifo",
59
- inputContract: contract,
60
- onJobFailed,
61
- maxPendingJobs,
62
- createdAt: now,
63
- updatedAt: now,
64
- };
65
- const result = await app.dispatch.createLink(link);
66
- if (!result.ok) {
67
- const statusCode = result.error === "pipeline_link_duplicate" ? 409 : 400;
68
- ctx.sendJson(statusCode, { ok: false, error: result.error });
69
- return;
70
- }
71
- ctx.sendJson(201, { ok: true, link: result.link });
72
- });
73
- // PATCH /api/pipeline-links/:linkId
74
- router.register("PATCH", "/api/pipeline-links/:linkId", async (ctx) => {
75
- const { app } = ctx.options;
76
- const { linkId } = ctx.params;
77
- const body = await ctx.readBody();
78
- const patch = {};
79
- if (typeof body.enabled === "boolean")
80
- patch.enabled = body.enabled;
81
- if (body.inputContract !== undefined) {
82
- patch.inputContract = body.inputContract && typeof body.inputContract === "object"
83
- ? {
84
- requireType: typeof body.inputContract.requireType === "string"
85
- ? body.inputContract.requireType
86
- : undefined,
87
- requireSchemaVersion: typeof body.inputContract.requireSchemaVersion === "number"
88
- ? body.inputContract.requireSchemaVersion
89
- : undefined,
90
- }
91
- : null;
92
- }
93
- if (body.onJobFailed === "continue" || body.onJobFailed === "pause")
94
- patch.onJobFailed = body.onJobFailed;
95
- if (typeof body.maxPendingJobs === "number" && Number.isFinite(body.maxPendingJobs)) {
96
- patch.maxPendingJobs = Math.min(10000, Math.max(1, Math.trunc(body.maxPendingJobs)));
97
- }
98
- const result = await app.dispatch.updateLink(linkId, patch);
99
- if (!result.ok) {
100
- ctx.sendJson(404, { ok: false, error: result.error });
101
- return;
102
- }
103
- ctx.sendJson(200, { ok: true, link: result.link });
104
- });
105
- // DELETE /api/pipeline-links/:linkId
106
- router.register("DELETE", "/api/pipeline-links/:linkId", async (ctx) => {
107
- const { app } = ctx.options;
108
- const { linkId } = ctx.params;
109
- const result = await app.dispatch.deleteLink(linkId);
110
- if (!result.ok) {
111
- ctx.sendJson(404, { ok: false, error: result.error });
112
- return;
113
- }
114
- ctx.sendJson(200, { ok: true });
115
- });
116
- };
117
- exports.registerPipelineLinksRoutes = registerPipelineLinksRoutes;
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPipelineOutputsRoutes = void 0;
4
- const registerPipelineOutputsRoutes = (router) => {
5
- // GET /api/pipelines/:pipelineId/outputs
6
- router.register("GET", "/api/pipelines/:pipelineId/outputs", async (ctx) => {
7
- const { app } = ctx.options;
8
- const { pipelineId } = ctx.params;
9
- const runtime = app.getPipelineRuntime(pipelineId);
10
- if (!runtime) {
11
- ctx.sendJson(404, { ok: false, error: "pipeline_not_found", pipelineId });
12
- return;
13
- }
14
- const runId = ctx.url.searchParams.get("runId")?.trim() || undefined;
15
- const batchRunId = ctx.url.searchParams.get("batchRunId")?.trim() || undefined;
16
- const outputs = await runtime.output.list();
17
- let filtered = outputs;
18
- if (runId)
19
- filtered = filtered.filter((o) => o.runId === runId);
20
- if (batchRunId)
21
- filtered = filtered.filter((o) => o.batchRunId === batchRunId);
22
- // Sort newest first
23
- filtered.sort((a, b) => b.producedAt.localeCompare(a.producedAt));
24
- ctx.sendJson(200, { ok: true, pipelineId, items: filtered });
25
- });
26
- };
27
- exports.registerPipelineOutputsRoutes = registerPipelineOutputsRoutes;
@@ -1,62 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPipelineQueueRoutes = void 0;
4
- const registerPipelineQueueRoutes = (router) => {
5
- // GET /api/pipelines/:pipelineId/queue
6
- router.register("GET", "/api/pipelines/:pipelineId/queue", async (ctx) => {
7
- const { app } = ctx.options;
8
- const { pipelineId } = ctx.params;
9
- if (!app.getPipelineDefinition(pipelineId)) {
10
- ctx.sendJson(404, { ok: false, error: "pipeline_not_found", pipelineId });
11
- return;
12
- }
13
- const items = app.dispatch.getQueue(pipelineId);
14
- ctx.sendJson(200, { ok: true, pipelineId, items });
15
- });
16
- // POST /api/pipelines/:pipelineId/queue/:jobId/retry
17
- router.register("POST", "/api/pipelines/:pipelineId/queue/:jobId/retry", async (ctx) => {
18
- const { app } = ctx.options;
19
- const { pipelineId, jobId } = ctx.params;
20
- if (!app.getPipelineDefinition(pipelineId)) {
21
- ctx.sendJson(404, { ok: false, error: "pipeline_not_found", pipelineId });
22
- return;
23
- }
24
- const result = await app.dispatch.retryJob(jobId);
25
- if (!result.ok) {
26
- const statusCode = result.error === "pipeline_queue_job_not_found" ? 404 : 400;
27
- ctx.sendJson(statusCode, { ok: false, error: result.error });
28
- return;
29
- }
30
- ctx.sendJson(200, { ok: true, job: result.job });
31
- });
32
- // POST /api/pipelines/:pipelineId/queue/:jobId/cancel
33
- router.register("POST", "/api/pipelines/:pipelineId/queue/:jobId/cancel", async (ctx) => {
34
- const { app } = ctx.options;
35
- const { pipelineId, jobId } = ctx.params;
36
- if (!app.getPipelineDefinition(pipelineId)) {
37
- ctx.sendJson(404, { ok: false, error: "pipeline_not_found", pipelineId });
38
- return;
39
- }
40
- const body = await ctx.readBody();
41
- const reason = typeof body.reason === "string" ? body.reason.trim() : "canceled_by_user";
42
- const result = await app.dispatch.cancelJob(jobId, reason);
43
- if (!result.ok) {
44
- const statusCode = result.error === "pipeline_queue_job_not_found" ? 404 : 400;
45
- ctx.sendJson(statusCode, { ok: false, error: result.error });
46
- return;
47
- }
48
- ctx.sendJson(200, { ok: true });
49
- });
50
- // POST /api/pipelines/:pipelineId/queue/drain
51
- router.register("POST", "/api/pipelines/:pipelineId/queue/drain", async (ctx) => {
52
- const { app } = ctx.options;
53
- const { pipelineId } = ctx.params;
54
- if (!app.getPipelineDefinition(pipelineId)) {
55
- ctx.sendJson(404, { ok: false, error: "pipeline_not_found", pipelineId });
56
- return;
57
- }
58
- app.dispatch.drainQueue(pipelineId);
59
- ctx.sendJson(200, { ok: true, pipelineId });
60
- });
61
- };
62
- exports.registerPipelineQueueRoutes = registerPipelineQueueRoutes;
@@ -1,162 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPipelineRuntimeRoutes = void 0;
4
- const pipeline_identity_js_1 = require("./pipeline-identity.js");
5
- /**
6
- * 注册 Pipeline 运行态路由:
7
- * GET /api/pipelines/:pipelineId/current — 当前运行信息
8
- * GET /api/pipelines/:pipelineId/status — Pipeline 状态
9
- * POST /api/pipelines/:pipelineId/run — 启动运行
10
- * POST /api/pipelines/:pipelineId/stop — 停止运行(同时作为 /batch-run/stop 的别名入口)
11
- * GET /api/pipelines/:pipelineId/executor-bindings — Executor 会话绑定
12
- * POST /api/pipelines/:pipelineId/nodes/:nodeId/retry — 节点重试
13
- */
14
- const registerPipelineRuntimeRoutes = (router) => {
15
- // GET /api/pipelines/:pipelineId/current
16
- router.register("GET", "/api/pipelines/:pipelineId/current", (ctx) => {
17
- const scope = ctx.getPipelineScope();
18
- if (!scope) {
19
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
20
- return;
21
- }
22
- const run = scope.getRun();
23
- scope.touchRun(run);
24
- const workflow = scope.getWorkflow?.();
25
- const nodes = workflow?.nodes && workflow.nodes.length > 0
26
- ? run.nodes.map((node) => {
27
- const matched = workflow.nodes.find((wNode) => wNode.id === node.id);
28
- return {
29
- ...node,
30
- isMainline: matched?.isMainline ?? true,
31
- lane: matched?.lane ?? "main",
32
- parallelGroupId: matched?.parallelGroupId ?? null,
33
- };
34
- })
35
- : run.nodes;
36
- ctx.sendJson(200, {
37
- run: { ...run, nodes },
38
- runId: run.id,
39
- nodes,
40
- scheduler: scope.getSchedulerState ? scope.getSchedulerState() : null,
41
- pipelineId: scope.pipelineId,
42
- });
43
- });
44
- // GET /api/pipelines/:pipelineId/status
45
- router.register("GET", "/api/pipelines/:pipelineId/status", (ctx) => {
46
- const scope = ctx.getPipelineScope();
47
- if (!scope) {
48
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
49
- return;
50
- }
51
- const { pipelineService } = ctx.services;
52
- const result = pipelineService.getPipelineExecutionStatus(scope.pipelineId, (0, pipeline_identity_js_1.readIdentityTargetFromUrl)(ctx.url));
53
- const statusCode = result.ok === false && result.error === "run_not_found" ? 404 : 200;
54
- ctx.sendJson(statusCode, result);
55
- });
56
- // POST /api/pipelines/:pipelineId/run
57
- router.register("POST", "/api/pipelines/:pipelineId/run", async (ctx) => {
58
- const scope = ctx.getPipelineScope();
59
- if (!scope) {
60
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
61
- return;
62
- }
63
- const { pipelineService } = ctx.services;
64
- const started = await pipelineService.startPipeline(scope.pipelineId);
65
- if (started.ok === false && started.error === "batch_run_in_progress") {
66
- ctx.sendJson(409, { ok: false, error: started.error, state: started.state, pipelineId: scope.pipelineId });
67
- return;
68
- }
69
- if (started.ok === false) {
70
- const statusCode = started.error === "remote_pool_url_empty" || started.error === "remote_batch_items_empty"
71
- ? 400
72
- : started.error === "remote_pool_fetch_failed" || started.error === "remote_pool_fetch_error"
73
- ? 502
74
- : 409;
75
- ctx.sendJson(statusCode, {
76
- ok: false,
77
- error: started.error,
78
- state: started.state,
79
- remoteUrl: started.remoteUrl,
80
- status: started.status,
81
- detail: started.detail,
82
- pipelineId: scope.pipelineId,
83
- });
84
- return;
85
- }
86
- if (started.mode === "remote_batch") {
87
- ctx.sendJson(200, {
88
- ...started,
89
- state: started.batchRun,
90
- });
91
- return;
92
- }
93
- ctx.sendJson(200, started);
94
- });
95
- // POST /api/pipelines/:pipelineId/stop
96
- // 旧代码中 /stop 与 /batch-run/stop 共享同一处理逻辑;此处注册 /stop,/batch-run/stop 在 pipeline-batch.ts 中注册
97
- router.register("POST", "/api/pipelines/:pipelineId/stop", async (ctx) => {
98
- const scope = ctx.getPipelineScope();
99
- if (!scope) {
100
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
101
- return;
102
- }
103
- const { pipelineService } = ctx.services;
104
- const body = await ctx.readBody();
105
- const target = (0, pipeline_identity_js_1.mergeIdentityTargets)((0, pipeline_identity_js_1.readIdentityTargetFromBody)(body), (0, pipeline_identity_js_1.readIdentityTargetFromUrl)(ctx.url));
106
- const stopped = pipelineService.stopPipeline(scope.pipelineId, target);
107
- if (stopped.ok === false && stopped.error === "run_not_found") {
108
- ctx.sendJson(404, stopped);
109
- return;
110
- }
111
- if (stopped.ok === false) {
112
- ctx.sendJson(409, stopped);
113
- return;
114
- }
115
- ctx.sendJson(200, {
116
- ...stopped,
117
- });
118
- });
119
- // GET /api/pipelines/:pipelineId/executor-bindings
120
- router.register("GET", "/api/pipelines/:pipelineId/executor-bindings", (ctx) => {
121
- const scope = ctx.getPipelineScope();
122
- if (!scope) {
123
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
124
- return;
125
- }
126
- ctx.sendJson(200, {
127
- bindings: Object.fromEntries(scope.executorSessionByAgentId.entries()),
128
- sessions: scope.getSessionCache().map((s) => ({ id: s.id, title: s.title })),
129
- pipelineId: scope.pipelineId,
130
- });
131
- });
132
- // POST /api/pipelines/:pipelineId/nodes/:nodeId/retry
133
- router.register("POST", "/api/pipelines/:pipelineId/nodes/:nodeId/retry", async (ctx) => {
134
- const scope = ctx.getPipelineScope();
135
- if (!scope) {
136
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
137
- return;
138
- }
139
- const { pipelineService } = ctx.services;
140
- const body = await ctx.readBody();
141
- const itemKey = typeof body.itemKey === "string" && body.itemKey.trim() ? body.itemKey.trim() : undefined;
142
- const result = await pipelineService.retryNode({
143
- pipelineId: scope.pipelineId,
144
- nodeId: ctx.params.nodeId,
145
- itemKey,
146
- });
147
- if (!result.ok) {
148
- ctx.sendJson(404, result);
149
- return;
150
- }
151
- if (!result.retry.ok && result.retry.error === "node_not_found") {
152
- ctx.sendJson(404, { run: result.run, ...result.retry });
153
- return;
154
- }
155
- if (!result.retry.ok && result.retry.error === "executor_session_not_found") {
156
- ctx.sendJson(400, { run: result.run, ...result.retry });
157
- return;
158
- }
159
- ctx.sendJson(200, { run: result.run, ...result.retry });
160
- });
161
- };
162
- exports.registerPipelineRuntimeRoutes = registerPipelineRuntimeRoutes;
@@ -1,69 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPipelineSchedulerRoutes = void 0;
4
- /**
5
- * 注册 Pipeline Scheduler 路由:
6
- * POST /api/pipelines/:pipelineId/scheduler/toggle — 切换调度器开关
7
- * POST /api/pipelines/:pipelineId/scheduler/mode — 设置调度模式
8
- * POST /api/pipelines/:pipelineId/tick — 手动触发调度 tick
9
- */
10
- const registerPipelineSchedulerRoutes = (router) => {
11
- // POST /api/pipelines/:pipelineId/scheduler/toggle
12
- router.register("POST", "/api/pipelines/:pipelineId/scheduler/toggle", async (ctx) => {
13
- const scope = ctx.getPipelineScope();
14
- if (!scope) {
15
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
16
- return;
17
- }
18
- const { schedulerService } = ctx.services;
19
- const body = await ctx.readBody();
20
- const enabled = body.enabled !== false;
21
- const toggled = schedulerService.toggleScheduler(scope.pipelineId, enabled);
22
- if (!toggled.ok) {
23
- // pipeline_plugin_disabled 时返回 403,pipeline_not_found 时返回 404
24
- const statusCode = toggled.error === "pipeline_not_found" ? 404 : 403;
25
- ctx.sendJson(statusCode, toggled);
26
- return;
27
- }
28
- scope.pushTimeline(`[${scope.pipelineId}] 调度器已${toggled.scheduler.enabled ? "启用" : "停用"}`);
29
- ctx.sendJson(200, toggled);
30
- });
31
- // POST /api/pipelines/:pipelineId/scheduler/mode
32
- router.register("POST", "/api/pipelines/:pipelineId/scheduler/mode", async (ctx) => {
33
- const scope = ctx.getPipelineScope();
34
- if (!scope) {
35
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
36
- return;
37
- }
38
- const { schedulerService } = ctx.services;
39
- const body = await ctx.readBody();
40
- const mode = body.mode === "manual" ? "manual" : "auto";
41
- const updated = schedulerService.setSchedulerMode(scope.pipelineId, mode);
42
- if (!updated.ok) {
43
- const statusCode = updated.error === "pipeline_not_found" ? 404 : 403;
44
- ctx.sendJson(statusCode, updated);
45
- return;
46
- }
47
- scope.pushTimeline(`[${scope.pipelineId}] 调度器模式切换为: ${updated.scheduler.mode}`);
48
- ctx.sendJson(200, updated);
49
- });
50
- // POST /api/pipelines/:pipelineId/tick
51
- router.register("POST", "/api/pipelines/:pipelineId/tick", async (ctx) => {
52
- const scope = ctx.getPipelineScope();
53
- if (!scope) {
54
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
55
- return;
56
- }
57
- const workflow = scope.getWorkflow?.();
58
- // 保持 scheduler plugin disabled 时的 403 语义
59
- if (!workflow || !workflow.plugins.scheduler.enabled) {
60
- ctx.sendJson(403, { error: "pipeline_plugin_disabled", plugin: "scheduler", pipelineId: scope.pipelineId });
61
- return;
62
- }
63
- const drained = await scope.drainPipeline("manual_tick");
64
- const run = scope.getRun();
65
- scope.touchRun(run);
66
- ctx.sendJson(200, { ok: true, run, drained, pipelineId: scope.pipelineId });
67
- });
68
- };
69
- exports.registerPipelineSchedulerRoutes = registerPipelineSchedulerRoutes;
@@ -1,180 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPipelineWorkflowRoutes = void 0;
4
- const template_js_1 = require("../../pipeline/template.js");
5
- const pipeline_config_js_1 = require("../../app/pipeline-config.js");
6
- // 将未知值安全转换为 Record<string, unknown>,非对象返回 null
7
- const asRecord = (value) => value && typeof value === "object" ? value : null;
8
- /**
9
- * 注册 Pipeline Workflow / Template / Plugins 路由:
10
- * GET /api/pipelines/:pipelineId/template — 读取模板节点
11
- * GET /api/pipelines/:pipelineId/workflow — 读取工作流定义
12
- * POST /api/pipelines/:pipelineId/workflow — 保存工作流定义
13
- * GET /api/pipelines/:pipelineId/plugins — 读取插件配置
14
- * POST /api/pipelines/:pipelineId/plugins — 写入插件配置
15
- */
16
- const registerPipelineWorkflowRoutes = (router) => {
17
- // GET /api/pipelines/:pipelineId/plugins
18
- router.register("GET", "/api/pipelines/:pipelineId/plugins", (ctx) => {
19
- const scope = ctx.getPipelineScope();
20
- if (!scope) {
21
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
22
- return;
23
- }
24
- const workflow = scope.getWorkflow();
25
- if (!workflow) {
26
- ctx.sendJson(501, { error: "workflow_api_not_enabled" });
27
- return;
28
- }
29
- ctx.sendJson(200, { ok: true, state: workflow.plugins, pipelineId: scope.pipelineId });
30
- });
31
- // POST /api/pipelines/:pipelineId/plugins
32
- router.register("POST", "/api/pipelines/:pipelineId/plugins", async (ctx) => {
33
- const scope = ctx.getPipelineScope();
34
- if (!scope) {
35
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
36
- return;
37
- }
38
- if (!scope.getWorkflow || !scope.setWorkflow) {
39
- ctx.sendJson(501, { error: "workflow_api_not_enabled" });
40
- return;
41
- }
42
- const body = await ctx.readBody();
43
- const currentWorkflow = scope.getWorkflow();
44
- const currentPlugin = currentWorkflow.plugins;
45
- const remoteBatchBody = asRecord(body.remoteBatch) ?? body;
46
- const schedulerBody = asRecord(body.scheduler);
47
- const nextPlugin = {
48
- remoteBatch: {
49
- enabled: remoteBatchBody.enabled === true,
50
- url: typeof remoteBatchBody.url === "string" && remoteBatchBody.url.trim()
51
- ? remoteBatchBody.url.trim()
52
- : currentPlugin.remoteBatch.url || pipeline_config_js_1.DEFAULT_REMOTE_BATCH_URL,
53
- startBatch: typeof remoteBatchBody.startBatch === "number" && Number.isFinite(remoteBatchBody.startBatch)
54
- ? Math.max(1, Math.trunc(remoteBatchBody.startBatch))
55
- : currentPlugin.remoteBatch.startBatch,
56
- batchSize: typeof remoteBatchBody.batchSize === "number" && Number.isFinite(remoteBatchBody.batchSize)
57
- ? Math.max(1, Math.trunc(remoteBatchBody.batchSize))
58
- : currentPlugin.remoteBatch.batchSize,
59
- sourceField: typeof remoteBatchBody.sourceField === "string" && remoteBatchBody.sourceField.trim()
60
- ? remoteBatchBody.sourceField.trim()
61
- : currentPlugin.remoteBatch.sourceField,
62
- },
63
- scheduler: {
64
- enabled: schedulerBody?.enabled === undefined ? currentPlugin.scheduler.enabled : schedulerBody.enabled === true,
65
- },
66
- };
67
- const nextWorkflow = {
68
- ...currentWorkflow,
69
- plugins: {
70
- ...currentWorkflow.plugins,
71
- ...nextPlugin,
72
- },
73
- // 调度器插件关闭时同步落盘为 disabled,避免刷新后后台仍按旧 scheduler.enabled 自动运行
74
- scheduler: nextPlugin.scheduler.enabled
75
- ? currentWorkflow.scheduler
76
- : {
77
- ...currentWorkflow.scheduler,
78
- enabled: false,
79
- },
80
- };
81
- if (!nextPlugin.remoteBatch.enabled && scope.cancelBatchRun && scope.getBatchRunState?.().status === "running") {
82
- scope.cancelBatchRun();
83
- }
84
- scope.setWorkflow(nextWorkflow);
85
- (0, template_js_1.saveWorkflowDefinitionWithStorage)(nextWorkflow, { workflowFilePath: scope.workflowFilePath });
86
- ctx.sendJson(200, { ok: true, state: nextPlugin, pipelineId: scope.pipelineId });
87
- });
88
- // GET /api/pipelines/:pipelineId/template
89
- router.register("GET", "/api/pipelines/:pipelineId/template", (ctx) => {
90
- const scope = ctx.getPipelineScope();
91
- if (!scope) {
92
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
93
- return;
94
- }
95
- const workflow = scope.getWorkflow();
96
- if (!workflow) {
97
- ctx.sendJson(501, { error: "workflow_api_not_enabled" });
98
- return;
99
- }
100
- ctx.sendJson(200, { nodes: (0, template_js_1.workflowToTemplateNodes)(workflow) });
101
- });
102
- // GET /api/pipelines/:pipelineId/workflow
103
- router.register("GET", "/api/pipelines/:pipelineId/workflow", (ctx) => {
104
- const scope = ctx.getPipelineScope();
105
- if (!scope) {
106
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
107
- return;
108
- }
109
- if (!scope.getWorkflow) {
110
- ctx.sendJson(501, { error: "workflow_api_not_enabled" });
111
- return;
112
- }
113
- ctx.sendJson(200, { workflow: scope.getWorkflow(), pipelineId: scope.pipelineId });
114
- });
115
- // POST /api/pipelines/:pipelineId/workflow
116
- router.register("POST", "/api/pipelines/:pipelineId/workflow", async (ctx) => {
117
- const scope = ctx.getPipelineScope();
118
- if (!scope) {
119
- ctx.sendJson(404, { error: "pipeline_not_found", pipelineId: ctx.params.pipelineId });
120
- return;
121
- }
122
- if (!scope.setWorkflow || !scope.getWorkflow) {
123
- ctx.sendJson(501, { error: "workflow_api_not_enabled" });
124
- return;
125
- }
126
- const body = await ctx.readBody();
127
- const parseResult = (0, template_js_1.readWorkflowDefinitionFromRawDetailed)(body.workflow ?? body);
128
- if (!parseResult.ok) {
129
- ctx.sendJson(400, {
130
- error: parseResult.error,
131
- detail: parseResult.detail,
132
- pipelineId: scope.pipelineId,
133
- });
134
- return;
135
- }
136
- const next = parseResult.workflow;
137
- let normalized;
138
- try {
139
- normalized = (0, template_js_1.normalizeWorkflowFallbacksWithStorage)(next, { workflowFilePath: scope.workflowFilePath });
140
- }
141
- catch (error) {
142
- // 透传读盘异常,保证「坏盘后修复提交」场景能得到结构化错误响应
143
- const errorObj = error;
144
- ctx.sendJson(400, {
145
- error: errorObj.message || "invalid_persisted_workflow_definition",
146
- detail: errorObj.detail ?? errorObj.message,
147
- pipelineId: scope.pipelineId,
148
- });
149
- return;
150
- }
151
- const validation = (0, template_js_1.validateWorkflowDefinition)(normalized);
152
- if (!validation.ok) {
153
- ctx.sendJson(400, {
154
- error: validation.error,
155
- detail: validation.detail,
156
- pipelineId: scope.pipelineId,
157
- });
158
- return;
159
- }
160
- scope.setWorkflow(normalized);
161
- try {
162
- (0, template_js_1.saveWorkflowDefinitionWithStorage)(normalized, { workflowFilePath: scope.workflowFilePath });
163
- }
164
- catch (error) {
165
- const errorObj = error;
166
- ctx.sendJson(400, {
167
- error: errorObj.message || "invalid_workflow_definition",
168
- detail: errorObj.detail ?? errorObj.message,
169
- pipelineId: scope.pipelineId,
170
- });
171
- return;
172
- }
173
- const run = scope.seedRun(scope.getTemplateNodes());
174
- scope.setRun(run);
175
- scope.pushTimeline(`[${scope.pipelineId}] 工作流定义已更新,节点数: ${normalized.nodes.length}`);
176
- scope.emitPipeline();
177
- ctx.sendJson(200, { ok: true, workflow: normalized, run, pipelineId: scope.pipelineId });
178
- });
179
- };
180
- exports.registerPipelineWorkflowRoutes = registerPipelineWorkflowRoutes;