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.
- package/README.md +176 -176
- package/README.zh-CN.md +176 -176
- package/dist/src/app/app-context-env.js +1 -1
- package/dist/src/app/create-app-context.js +3 -3
- package/dist/src/app/data-dir.js +13 -3
- package/dist/src/app/pipeline-config.js +4 -4
- package/dist/src/app/pipeline-registry.js +11 -11
- package/dist/src/app/pipeline-runtime.js +6 -9
- package/dist/src/app/runtime-store.js +3 -3
- package/dist/src/artifacts/artifact-cleanup.js +17 -17
- package/dist/src/artifacts/artifact-index.js +14 -14
- package/dist/src/artifacts/artifact-rebuilder.js +3 -3
- package/dist/src/artifacts/storage-service.js +18 -18
- package/dist/src/cli/bootstrap.js +7 -7
- package/dist/src/cli/commands/agent.js +12 -11
- package/dist/src/cli/commands/artifact.js +31 -30
- package/dist/src/cli/commands/init.js +49 -47
- package/dist/src/cli/commands/pipeline/result.js +9 -8
- package/dist/src/cli/commands/pipeline/selector.js +1 -1
- package/dist/src/cli/commands/pipeline/watch.js +2 -2
- package/dist/src/cli/commands/pipeline.js +54 -53
- package/dist/src/cli/commands/scheduler.js +9 -8
- package/dist/src/cli/commands/server.js +12 -11
- package/dist/src/cli/commands/system.js +4 -3
- package/dist/src/cli/errors.js +2 -2
- package/dist/src/cli/help.js +18 -17
- package/dist/src/cli/i18n.js +46 -0
- package/dist/src/cli/locales/en.json +244 -0
- package/dist/src/cli/locales/zh.json +244 -0
- package/dist/src/cli/output.js +3 -3
- package/dist/src/cli/renderers/engine/markdown.js +1 -1
- package/dist/src/cli/renderers/specs/index.js +1 -1
- package/dist/src/cli/router.js +1 -1
- package/dist/src/cli/server-runtime-client.js +54 -95
- package/dist/src/cli/ui-prompts.js +96 -0
- package/dist/src/cli/ws-runtime-client.js +51 -0
- package/dist/src/gateway/gateway-client.js +4 -4
- package/dist/src/index.js +28 -2
- package/dist/src/logs/run-log-reader.js +1 -1
- package/dist/src/pipeline/agent-activity.js +2 -2
- package/dist/src/pipeline/artifact-storage.js +11 -11
- package/dist/src/pipeline/diagnostics/dependency-diagnostic.js +11 -11
- package/dist/src/pipeline/dispatch/pipeline-inbound-queue.js +2 -2
- package/dist/src/pipeline/execution/group-item-executor.js +1 -1
- package/dist/src/pipeline/execution/node-item-executor.js +3 -3
- package/dist/src/pipeline/execution/node-runner.js +7 -7
- package/dist/src/pipeline/execution/readiness-state.js +1 -1
- package/dist/src/pipeline/execution/reject-handler.js +5 -5
- package/dist/src/pipeline/execution/rejected-artifact-archiver.js +1 -1
- package/dist/src/pipeline/execution/route-item-manager.js +4 -4
- package/dist/src/pipeline/execution/run-abort-controller.js +5 -5
- package/dist/src/pipeline/execution/run-state-helpers.js +2 -2
- package/dist/src/pipeline/execution/service.js +4 -4
- package/dist/src/pipeline/execution/structured-node-runner.js +24 -24
- package/dist/src/pipeline/execution-timeout.js +3 -3
- package/dist/src/pipeline/identity/index.js +3 -3
- package/dist/src/pipeline/item-batch-controller.js +6 -6
- package/dist/src/pipeline/scheduler/dependency-state.js +5 -5
- package/dist/src/pipeline/scheduler-service.js +24 -24
- package/dist/src/pipeline/state-machine.js +2 -2
- package/dist/src/pipeline/structured-output/contract.js +4 -4
- package/dist/src/pipeline/structured-output/index.js +2 -2
- package/dist/src/pipeline/structured-output/parser.js +5 -5
- package/dist/src/pipeline/structured-output/prompt.js +38 -38
- package/dist/src/pipeline/structured-output/waiter.js +6 -6
- package/dist/src/pipeline/template.js +5 -5
- package/dist/src/pipeline/timeline-log-store.js +5 -5
- package/dist/src/pipeline/tool-activity.js +3 -3
- package/dist/src/pipeline/types/pipeline-output.js +1 -1
- package/dist/src/pipeline/workflow/branch-rules.js +19 -19
- package/dist/src/pipeline/workflow/io.js +1 -1
- package/dist/src/pipeline/workflow/normalize.js +18 -18
- package/dist/src/pipeline/workflow/template-mapper.js +3 -3
- package/dist/src/pipeline/workflow/validate.js +39 -39
- package/dist/src/pipeline/workflow-graph.js +10 -10
- package/dist/src/server/http-handler.js +74 -0
- package/dist/src/services/agent-service.js +2 -2
- package/dist/src/services/gateway-read-helpers.js +1 -1
- package/dist/src/services/pipeline-service.js +19 -19
- package/dist/src/services/pipeline-status.js +4 -4
- package/dist/src/services/read-services.js +1 -1
- package/dist/src/services/session-service.js +6 -6
- package/dist/src/services/system-service.js +1 -1
- package/dist/src/transport/ws-broker.js +12 -1
- package/dist/src/transport/ws-handler.js +60 -0
- package/dist/src/transport/ws-methods/agents.js +144 -0
- package/dist/src/transport/ws-methods/artifacts.js +171 -0
- package/dist/src/transport/ws-methods/gateway.js +16 -0
- package/dist/src/transport/ws-methods/logs.js +43 -0
- package/dist/src/transport/ws-methods/pipeline-batch.js +68 -0
- package/dist/src/transport/ws-methods/pipeline-links.js +100 -0
- package/dist/src/transport/ws-methods/pipeline-queue.js +51 -0
- package/dist/src/transport/ws-methods/pipeline-runtime.js +151 -0
- package/dist/src/transport/ws-methods/pipeline-scheduler.js +48 -0
- package/dist/src/transport/ws-methods/pipeline-workflow.js +127 -0
- package/dist/src/transport/ws-methods/pipelines.js +56 -0
- package/dist/src/transport/ws-methods/register-all.js +32 -0
- package/dist/src/transport/ws-methods/sessions.js +154 -0
- package/dist/src/transport/ws-methods/timeline.js +10 -0
- package/dist/src/{server/routes/pipeline-identity.js → transport/ws-methods/utils.js} +14 -9
- package/dist/src/version.js +1 -1
- package/package.json +15 -7
- package/web/dist/assets/agent-DP6TMcLj.js +1 -0
- package/web/dist/assets/agent-DmJHzLyj.js +1 -0
- package/web/dist/assets/artifact-BqnoZy2M.js +1 -0
- package/web/dist/assets/artifact-DfDkgkno.js +1 -0
- package/web/dist/assets/common-DRMTVwE9.js +1 -0
- package/web/dist/assets/common-DeXccbr2.js +1 -0
- package/web/dist/assets/dispatch-CBskGCQI.js +1 -0
- package/web/dist/assets/dispatch-sk4Wp30e.js +1 -0
- package/web/dist/assets/index-C8wTjZvH.css +1 -0
- package/web/dist/assets/index-DYDQZRLk.js +58 -0
- package/web/dist/assets/log-DN8cjb0w.js +1 -0
- package/web/dist/assets/log-HSeA_dYy.js +1 -0
- package/web/dist/assets/modal-BdNai9jf.js +1 -0
- package/web/dist/assets/modal-D9_KDpFD.js +1 -0
- package/web/dist/assets/nav-BmF7oAKg.js +1 -0
- package/web/dist/assets/nav-IjC2xqXQ.js +1 -0
- package/web/dist/assets/node-detail-CENRXcrh.js +1 -0
- package/web/dist/assets/node-detail-bndPr0IM.js +1 -0
- package/web/dist/assets/overview-B87zWAxq.js +1 -0
- package/web/dist/assets/overview-gQvk-NOK.js +1 -0
- package/web/dist/assets/pipeline-D4dSJRDz.js +1 -0
- package/web/dist/assets/pipeline-DZzyOqQa.js +1 -0
- package/web/dist/assets/session-CUWvU14v.js +5 -0
- package/web/dist/assets/session-DQ6UuCaJ.js +5 -0
- package/web/dist/assets/timeline-8y_2_0Em.js +1 -0
- package/web/dist/assets/timeline-CAPsXUTC.js +1 -0
- package/web/dist/index.html +3 -3
- package/dist/src/app/pipeline-plugin-config.js +0 -2
- package/dist/src/server/api-handler.js +0 -163
- package/dist/src/server/http-utils.js +0 -34
- package/dist/src/server/middleware.js +0 -61
- package/dist/src/server/router.js +0 -105
- package/dist/src/server/routes/agents.js +0 -189
- package/dist/src/server/routes/artifacts.js +0 -163
- package/dist/src/server/routes/gateway.js +0 -18
- package/dist/src/server/routes/health.js +0 -16
- package/dist/src/server/routes/logs.js +0 -73
- package/dist/src/server/routes/pipeline-batch.js +0 -163
- package/dist/src/server/routes/pipeline-diagnostics.js +0 -33
- package/dist/src/server/routes/pipeline-links.js +0 -117
- package/dist/src/server/routes/pipeline-outputs.js +0 -27
- package/dist/src/server/routes/pipeline-queue.js +0 -62
- package/dist/src/server/routes/pipeline-runtime.js +0 -162
- package/dist/src/server/routes/pipeline-scheduler.js +0 -69
- package/dist/src/server/routes/pipeline-workflow.js +0 -180
- package/dist/src/server/routes/pipelines.js +0 -96
- package/dist/src/server/routes/sessions.js +0 -244
- package/dist/src/server/routes/timeline.js +0 -14
- package/dist/src/server/serve-static.js +0 -42
- package/web/dist/assets/index-CWnfhkn-.js +0 -65
- package/web/dist/assets/index-gZ0xOfSO.css +0 -1
- /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;
|