workplane 0.1.2 → 0.3.0
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 +1 -0
- package/dist/cli.js +466 -3
- package/dist/cli.js.map +1 -1
- package/dist/node.js +201 -24
- package/dist/node.js.map +1 -1
- package/dist/schema.sql +13 -0
- package/dist/server.js +285 -75
- package/dist/server.js.map +1 -1
- package/package.json +12 -10
package/dist/server.js
CHANGED
|
@@ -1,9 +1,126 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// ../dbos/src/index.ts
|
|
13
|
+
var src_exports = {};
|
|
14
|
+
__export(src_exports, {
|
|
15
|
+
DbosWorkflows: () => DbosWorkflows,
|
|
16
|
+
createDbosWorkflows: () => createDbosWorkflows
|
|
17
|
+
});
|
|
18
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
19
|
+
function createDbosWorkflows(store) {
|
|
20
|
+
return new DbosWorkflows(store);
|
|
21
|
+
}
|
|
22
|
+
var DbosWorkflows;
|
|
23
|
+
var init_src = __esm({
|
|
24
|
+
"../dbos/src/index.ts"() {
|
|
25
|
+
"use strict";
|
|
26
|
+
DbosWorkflows = class {
|
|
27
|
+
registered;
|
|
28
|
+
constructor(store) {
|
|
29
|
+
const createTask = DBOS.registerWorkflow(
|
|
30
|
+
async (input) => DBOS.runStep(() => store.createTask(input), { name: "store-create-task" }),
|
|
31
|
+
{ name: "createTaskWorkflow" }
|
|
32
|
+
);
|
|
33
|
+
const retryTask = DBOS.registerWorkflow(
|
|
34
|
+
async (taskId) => DBOS.runStep(() => store.retryTask(taskId), { name: "store-retry-task" }),
|
|
35
|
+
{ name: "retryTaskWorkflow" }
|
|
36
|
+
);
|
|
37
|
+
const cancelTask = DBOS.registerWorkflow(
|
|
38
|
+
async (taskId) => DBOS.runStep(() => store.cancelTask(taskId), { name: "store-cancel-task" }),
|
|
39
|
+
{ name: "cancelTaskWorkflow" }
|
|
40
|
+
);
|
|
41
|
+
const updateRunStatus = DBOS.registerWorkflow(
|
|
42
|
+
async (runId, status, error) => DBOS.runStep(() => store.updateRunStatus(runId, status, error), { name: "store-update-run-status" }),
|
|
43
|
+
{ name: "updateRunStatusWorkflow" }
|
|
44
|
+
);
|
|
45
|
+
const appendRunLogs = DBOS.registerWorkflow(
|
|
46
|
+
async (runId, logs) => DBOS.runStep(() => store.appendRunLogs(runId, logs), { name: "store-append-run-logs" }),
|
|
47
|
+
{ name: "appendRunLogsWorkflow" }
|
|
48
|
+
);
|
|
49
|
+
const createArtifact = DBOS.registerWorkflow(
|
|
50
|
+
async (runId, input) => DBOS.runStep(() => store.createArtifact(runId, input), { name: "store-create-artifact" }),
|
|
51
|
+
{ name: "createArtifactWorkflow" }
|
|
52
|
+
);
|
|
53
|
+
const appendInputEvent = DBOS.registerWorkflow(
|
|
54
|
+
async (runId, input) => DBOS.runStep(() => store.appendInputEvent(runId, input), { name: "store-append-input-event" }),
|
|
55
|
+
{ name: "appendInputEventWorkflow" }
|
|
56
|
+
);
|
|
57
|
+
const markInputDelivered = DBOS.registerWorkflow(
|
|
58
|
+
async (runId, sequence) => DBOS.runStep(() => store.markInputDelivered(runId, sequence), { name: "store-mark-input-delivered" }),
|
|
59
|
+
{ name: "markInputDeliveredWorkflow" }
|
|
60
|
+
);
|
|
61
|
+
this.registered = {
|
|
62
|
+
createTask,
|
|
63
|
+
retryTask,
|
|
64
|
+
cancelTask,
|
|
65
|
+
updateRunStatus,
|
|
66
|
+
appendRunLogs,
|
|
67
|
+
createArtifact,
|
|
68
|
+
appendInputEvent,
|
|
69
|
+
markInputDelivered
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async launch(options) {
|
|
73
|
+
DBOS.setConfig({
|
|
74
|
+
name: options.appName,
|
|
75
|
+
systemDatabaseUrl: options.systemDatabaseUrl
|
|
76
|
+
});
|
|
77
|
+
await DBOS.launch({
|
|
78
|
+
conductorKey: options.conductorKey,
|
|
79
|
+
conductorURL: options.conductorUrl
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async shutdown() {
|
|
83
|
+
await DBOS.shutdown();
|
|
84
|
+
}
|
|
85
|
+
async createTask(input) {
|
|
86
|
+
const handle = await DBOS.startWorkflow(this.registered.createTask)(input);
|
|
87
|
+
return handle.getResult();
|
|
88
|
+
}
|
|
89
|
+
async retryTask(taskId) {
|
|
90
|
+
const handle = await DBOS.startWorkflow(this.registered.retryTask)(taskId);
|
|
91
|
+
return handle.getResult();
|
|
92
|
+
}
|
|
93
|
+
async cancelTask(taskId) {
|
|
94
|
+
const handle = await DBOS.startWorkflow(this.registered.cancelTask)(taskId);
|
|
95
|
+
return handle.getResult();
|
|
96
|
+
}
|
|
97
|
+
async updateRunStatus(runId, status, error) {
|
|
98
|
+
const handle = await DBOS.startWorkflow(this.registered.updateRunStatus)(runId, status, error);
|
|
99
|
+
return handle.getResult();
|
|
100
|
+
}
|
|
101
|
+
async appendRunLogs(runId, logs) {
|
|
102
|
+
const handle = await DBOS.startWorkflow(this.registered.appendRunLogs)(runId, logs);
|
|
103
|
+
return handle.getResult();
|
|
104
|
+
}
|
|
105
|
+
async createArtifact(runId, input) {
|
|
106
|
+
const handle = await DBOS.startWorkflow(this.registered.createArtifact)(runId, input);
|
|
107
|
+
return handle.getResult();
|
|
108
|
+
}
|
|
109
|
+
async appendInputEvent(runId, input) {
|
|
110
|
+
const handle = await DBOS.startWorkflow(this.registered.appendInputEvent)(runId, input);
|
|
111
|
+
return handle.getResult();
|
|
112
|
+
}
|
|
113
|
+
async markInputDelivered(runId, sequence) {
|
|
114
|
+
const handle = await DBOS.startWorkflow(this.registered.markInputDelivered)(runId, sequence);
|
|
115
|
+
await handle.getResult();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
});
|
|
2
120
|
|
|
3
121
|
// ../server/src/index.ts
|
|
4
122
|
import { createServer } from "http";
|
|
5
123
|
import { URL } from "url";
|
|
6
|
-
import { DBOS as DBOS2 } from "@dbos-inc/dbos-sdk";
|
|
7
124
|
import { ZodError } from "zod";
|
|
8
125
|
|
|
9
126
|
// ../core/src/config.ts
|
|
@@ -97,6 +214,17 @@ function mapRun(row) {
|
|
|
97
214
|
error: row.error ? String(row.error) : null
|
|
98
215
|
};
|
|
99
216
|
}
|
|
217
|
+
function mapInputEvent(row) {
|
|
218
|
+
return {
|
|
219
|
+
id: Number(row.id),
|
|
220
|
+
runId: String(row.run_id),
|
|
221
|
+
sequence: Number(row.sequence),
|
|
222
|
+
kind: row.kind,
|
|
223
|
+
payload: row.payload ?? {},
|
|
224
|
+
createdAt: new Date(String(row.created_at)).toISOString(),
|
|
225
|
+
deliveredAt: row.delivered_at ? new Date(String(row.delivered_at)).toISOString() : null
|
|
226
|
+
};
|
|
227
|
+
}
|
|
100
228
|
function mapArtifact(row) {
|
|
101
229
|
return {
|
|
102
230
|
id: String(row.id),
|
|
@@ -414,6 +542,45 @@ var PgStore = class {
|
|
|
414
542
|
client.release();
|
|
415
543
|
}
|
|
416
544
|
}
|
|
545
|
+
async appendInputEvent(runId, input) {
|
|
546
|
+
const client = await this.pool.connect();
|
|
547
|
+
try {
|
|
548
|
+
await client.query("begin");
|
|
549
|
+
const seqResult = await client.query(
|
|
550
|
+
"select coalesce(max(sequence), 0) + 1 as next_seq from run_input_events where run_id = $1",
|
|
551
|
+
[runId]
|
|
552
|
+
);
|
|
553
|
+
const sequence = Number(seqResult.rows[0].next_seq);
|
|
554
|
+
const result = await client.query(
|
|
555
|
+
`
|
|
556
|
+
insert into run_input_events (run_id, sequence, kind, payload)
|
|
557
|
+
values ($1, $2, $3, $4::jsonb)
|
|
558
|
+
returning *
|
|
559
|
+
`,
|
|
560
|
+
[runId, sequence, input.kind, JSON.stringify(input.payload)]
|
|
561
|
+
);
|
|
562
|
+
await client.query("commit");
|
|
563
|
+
return mapInputEvent(result.rows[0]);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
await client.query("rollback");
|
|
566
|
+
throw error;
|
|
567
|
+
} finally {
|
|
568
|
+
client.release();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
async getInputEvents(runId, afterSequence) {
|
|
572
|
+
const result = await this.pool.query(
|
|
573
|
+
"select * from run_input_events where run_id = $1 and sequence > $2 order by sequence asc",
|
|
574
|
+
[runId, afterSequence]
|
|
575
|
+
);
|
|
576
|
+
return result.rows.map((row) => mapInputEvent(row));
|
|
577
|
+
}
|
|
578
|
+
async markInputDelivered(runId, sequence) {
|
|
579
|
+
await this.pool.query(
|
|
580
|
+
"update run_input_events set delivered_at = now() where run_id = $1 and sequence = $2",
|
|
581
|
+
[runId, sequence]
|
|
582
|
+
);
|
|
583
|
+
}
|
|
417
584
|
async touchNode(client, nodeId, capabilities) {
|
|
418
585
|
await client.query(
|
|
419
586
|
`
|
|
@@ -426,54 +593,37 @@ var PgStore = class {
|
|
|
426
593
|
}
|
|
427
594
|
};
|
|
428
595
|
|
|
429
|
-
// ../server/src/workflows.ts
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
{ name: "appendRunLogsWorkflow" }
|
|
461
|
-
);
|
|
462
|
-
const createArtifact = DBOS.registerWorkflow(
|
|
463
|
-
async (runId, input) => DBOS.runStep(() => store.createArtifact(runId, input), {
|
|
464
|
-
name: "store-create-artifact"
|
|
465
|
-
}),
|
|
466
|
-
{ name: "createArtifactWorkflow" }
|
|
467
|
-
);
|
|
468
|
-
return {
|
|
469
|
-
createTask,
|
|
470
|
-
retryTask,
|
|
471
|
-
cancelTask,
|
|
472
|
-
updateRunStatus,
|
|
473
|
-
appendRunLogs,
|
|
474
|
-
createArtifact
|
|
475
|
-
};
|
|
476
|
-
}
|
|
596
|
+
// ../server/src/workflows-vanilla.ts
|
|
597
|
+
var VanillaWorkflows = class {
|
|
598
|
+
constructor(store) {
|
|
599
|
+
this.store = store;
|
|
600
|
+
}
|
|
601
|
+
store;
|
|
602
|
+
createTask(input) {
|
|
603
|
+
return this.store.createTask(input);
|
|
604
|
+
}
|
|
605
|
+
retryTask(taskId) {
|
|
606
|
+
return this.store.retryTask(taskId);
|
|
607
|
+
}
|
|
608
|
+
cancelTask(taskId) {
|
|
609
|
+
return this.store.cancelTask(taskId);
|
|
610
|
+
}
|
|
611
|
+
updateRunStatus(runId, status, error) {
|
|
612
|
+
return this.store.updateRunStatus(runId, status, error);
|
|
613
|
+
}
|
|
614
|
+
appendRunLogs(runId, logs) {
|
|
615
|
+
return this.store.appendRunLogs(runId, logs);
|
|
616
|
+
}
|
|
617
|
+
createArtifact(runId, input) {
|
|
618
|
+
return this.store.createArtifact(runId, input);
|
|
619
|
+
}
|
|
620
|
+
appendInputEvent(runId, input) {
|
|
621
|
+
return this.store.appendInputEvent(runId, input);
|
|
622
|
+
}
|
|
623
|
+
markInputDelivered(runId, sequence) {
|
|
624
|
+
return this.store.markInputDelivered(runId, sequence);
|
|
625
|
+
}
|
|
626
|
+
};
|
|
477
627
|
|
|
478
628
|
// ../server/src/validation.ts
|
|
479
629
|
import { z as z2 } from "zod";
|
|
@@ -520,7 +670,8 @@ var harnessPayloadSchema = z2.object({
|
|
|
520
670
|
repo: z2.string().min(1),
|
|
521
671
|
branch: z2.string().min(1).optional(),
|
|
522
672
|
testCommand: z2.string().min(1).optional(),
|
|
523
|
-
extraArgs: z2.array(z2.string()).optional()
|
|
673
|
+
extraArgs: z2.array(z2.string()).optional(),
|
|
674
|
+
interactive: z2.boolean().optional()
|
|
524
675
|
});
|
|
525
676
|
var codexTaskSchema = z2.object({
|
|
526
677
|
kind: z2.literal("agent.run"),
|
|
@@ -544,6 +695,26 @@ var taskSchema = z2.discriminatedUnion("adapter", [
|
|
|
544
695
|
function validateCreateTaskInput(input) {
|
|
545
696
|
return taskSchema.parse(input);
|
|
546
697
|
}
|
|
698
|
+
var inputEventSchema = z2.discriminatedUnion("kind", [
|
|
699
|
+
z2.object({
|
|
700
|
+
kind: z2.literal("stdin"),
|
|
701
|
+
payload: z2.object({ data: z2.string() })
|
|
702
|
+
}),
|
|
703
|
+
z2.object({
|
|
704
|
+
kind: z2.literal("signal"),
|
|
705
|
+
payload: z2.object({ signal: z2.enum(["SIGTERM", "SIGKILL", "SIGINT"]) })
|
|
706
|
+
}),
|
|
707
|
+
z2.object({
|
|
708
|
+
kind: z2.literal("resize"),
|
|
709
|
+
payload: z2.object({
|
|
710
|
+
rows: z2.number().int().positive(),
|
|
711
|
+
cols: z2.number().int().positive()
|
|
712
|
+
})
|
|
713
|
+
})
|
|
714
|
+
]);
|
|
715
|
+
function validateInputEvent(input) {
|
|
716
|
+
return inputEventSchema.parse(input);
|
|
717
|
+
}
|
|
547
718
|
|
|
548
719
|
// ../core/src/auth.ts
|
|
549
720
|
function parseBearerToken(authorizationHeader) {
|
|
@@ -613,6 +784,15 @@ function routeAuthFor(method, pathname) {
|
|
|
613
784
|
if (method === "POST" && /^\/runs\/[^/]+\/artifacts$/.test(pathname)) {
|
|
614
785
|
return "node";
|
|
615
786
|
}
|
|
787
|
+
if (method === "GET" && /^\/runs\/[^/]+\/input$/.test(pathname)) {
|
|
788
|
+
return "node";
|
|
789
|
+
}
|
|
790
|
+
if (method === "POST" && /^\/runs\/[^/]+\/input\/\d+\/delivered$/.test(pathname)) {
|
|
791
|
+
return "node";
|
|
792
|
+
}
|
|
793
|
+
if (method === "POST" && /^\/runs\/[^/]+\/input$/.test(pathname)) {
|
|
794
|
+
return "operator";
|
|
795
|
+
}
|
|
616
796
|
if (method === "POST" && pathname === "/tasks") {
|
|
617
797
|
return "operator";
|
|
618
798
|
}
|
|
@@ -659,22 +839,26 @@ function writeJson(res, statusCode, payload) {
|
|
|
659
839
|
res.setHeader("content-type", "application/json");
|
|
660
840
|
res.end(json);
|
|
661
841
|
}
|
|
842
|
+
async function buildWorkflows(store, config) {
|
|
843
|
+
if (process.env.WORKPLANE_USE_DBOS === "true") {
|
|
844
|
+
const { createDbosWorkflows: createDbosWorkflows2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
845
|
+
const dbos = createDbosWorkflows2(store);
|
|
846
|
+
await dbos.launch({
|
|
847
|
+
appName: process.env.DBOS_APPLICATION_NAME ?? "workplane-server",
|
|
848
|
+
systemDatabaseUrl: config.databaseUrl,
|
|
849
|
+
conductorKey: process.env.DBOS_CONDUCTOR_KEY,
|
|
850
|
+
conductorUrl: process.env.DBOS_CONDUCTOR_URL
|
|
851
|
+
});
|
|
852
|
+
return { workflows: dbos, shutdown: () => dbos.shutdown() };
|
|
853
|
+
}
|
|
854
|
+
return { workflows: new VanillaWorkflows(store), shutdown: async () => {
|
|
855
|
+
} };
|
|
856
|
+
}
|
|
662
857
|
async function main() {
|
|
663
858
|
const config = loadServerConfig();
|
|
664
859
|
const pool = getPool(config.databaseUrl);
|
|
665
860
|
const store = new PgStore(pool);
|
|
666
|
-
const workflows =
|
|
667
|
-
const appName = process.env.DBOS_APPLICATION_NAME ?? "workplane-server";
|
|
668
|
-
const conductorKey = process.env.DBOS_CONDUCTOR_KEY;
|
|
669
|
-
const conductorUrl = process.env.DBOS_CONDUCTOR_URL;
|
|
670
|
-
DBOS2.setConfig({
|
|
671
|
-
name: appName,
|
|
672
|
-
systemDatabaseUrl: config.databaseUrl
|
|
673
|
-
});
|
|
674
|
-
await DBOS2.launch({
|
|
675
|
-
conductorKey,
|
|
676
|
-
conductorURL: conductorUrl
|
|
677
|
-
});
|
|
861
|
+
const { workflows, shutdown: shutdownWorkflows } = await buildWorkflows(store, config);
|
|
678
862
|
const server = createServer(async (req, res) => {
|
|
679
863
|
try {
|
|
680
864
|
if (!req.url || !req.method) {
|
|
@@ -694,13 +878,12 @@ async function main() {
|
|
|
694
878
|
if (req.method === "POST" && url.pathname === "/tasks") {
|
|
695
879
|
const body = await readJson(req);
|
|
696
880
|
const validated = validateCreateTaskInput(body);
|
|
697
|
-
const
|
|
881
|
+
const task = await workflows.createTask({
|
|
698
882
|
kind: validated.kind,
|
|
699
883
|
adapter: validated.adapter,
|
|
700
884
|
payload: validated.payload,
|
|
701
885
|
requires: validated.requires ?? []
|
|
702
886
|
});
|
|
703
|
-
const task = await handle.getResult();
|
|
704
887
|
writeJson(res, 201, task);
|
|
705
888
|
return;
|
|
706
889
|
}
|
|
@@ -722,8 +905,7 @@ async function main() {
|
|
|
722
905
|
}
|
|
723
906
|
if (req.method === "POST" && /^\/tasks\/[^/]+\/retry$/.test(url.pathname)) {
|
|
724
907
|
const taskId = url.pathname.split("/")[2];
|
|
725
|
-
const
|
|
726
|
-
const task = await handle.getResult();
|
|
908
|
+
const task = await workflows.retryTask(taskId);
|
|
727
909
|
if (!task) {
|
|
728
910
|
writeJson(res, 409, { error: "task is not retryable" });
|
|
729
911
|
return;
|
|
@@ -733,8 +915,7 @@ async function main() {
|
|
|
733
915
|
}
|
|
734
916
|
if (req.method === "POST" && /^\/tasks\/[^/]+\/cancel$/.test(url.pathname)) {
|
|
735
917
|
const taskId = url.pathname.split("/")[2];
|
|
736
|
-
const
|
|
737
|
-
const task = await handle.getResult();
|
|
918
|
+
const task = await workflows.cancelTask(taskId);
|
|
738
919
|
if (!task) {
|
|
739
920
|
writeJson(res, 409, { error: "task is not cancellable" });
|
|
740
921
|
return;
|
|
@@ -787,8 +968,7 @@ async function main() {
|
|
|
787
968
|
if (req.method === "POST" && /^\/runs\/[^/]+\/status$/.test(url.pathname)) {
|
|
788
969
|
const runId = url.pathname.split("/")[2];
|
|
789
970
|
const body = await readJson(req);
|
|
790
|
-
const
|
|
791
|
-
const run = await handle.getResult();
|
|
971
|
+
const run = await workflows.updateRunStatus(runId, body.status, body.error);
|
|
792
972
|
if (!run) {
|
|
793
973
|
writeJson(res, 404, { error: "run not found" });
|
|
794
974
|
return;
|
|
@@ -799,19 +979,49 @@ async function main() {
|
|
|
799
979
|
if (req.method === "POST" && /^\/runs\/[^/]+\/logs$/.test(url.pathname)) {
|
|
800
980
|
const runId = url.pathname.split("/")[2];
|
|
801
981
|
const body = await readJson(req);
|
|
802
|
-
const
|
|
803
|
-
const inserted = await handle.getResult();
|
|
982
|
+
const inserted = await workflows.appendRunLogs(runId, body.logs ?? []);
|
|
804
983
|
writeJson(res, 200, { inserted });
|
|
805
984
|
return;
|
|
806
985
|
}
|
|
807
986
|
if (req.method === "POST" && /^\/runs\/[^/]+\/artifacts$/.test(url.pathname)) {
|
|
808
987
|
const runId = url.pathname.split("/")[2];
|
|
809
988
|
const body = await readJson(req);
|
|
810
|
-
const
|
|
811
|
-
const artifact = await handle.getResult();
|
|
989
|
+
const artifact = await workflows.createArtifact(runId, body);
|
|
812
990
|
writeJson(res, 201, artifact);
|
|
813
991
|
return;
|
|
814
992
|
}
|
|
993
|
+
if (req.method === "POST" && /^\/runs\/[^/]+\/input$/.test(url.pathname)) {
|
|
994
|
+
const runId = url.pathname.split("/")[2];
|
|
995
|
+
const run = await store.getRun(runId);
|
|
996
|
+
if (!run) {
|
|
997
|
+
writeJson(res, 404, { error: "run not found" });
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
if (run.status !== "running") {
|
|
1001
|
+
writeJson(res, 409, { error: "run is not active" });
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const body = await readJson(req);
|
|
1005
|
+
const validated = validateInputEvent(body);
|
|
1006
|
+
const event = await workflows.appendInputEvent(runId, validated);
|
|
1007
|
+
writeJson(res, 201, event);
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
if (req.method === "GET" && /^\/runs\/[^/]+\/input$/.test(url.pathname)) {
|
|
1011
|
+
const runId = url.pathname.split("/")[2];
|
|
1012
|
+
const afterSequence = Number(url.searchParams.get("afterSequence") ?? "0");
|
|
1013
|
+
const events = await store.getInputEvents(runId, afterSequence);
|
|
1014
|
+
writeJson(res, 200, { events });
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
if (req.method === "POST" && /^\/runs\/[^/]+\/input\/\d+\/delivered$/.test(url.pathname)) {
|
|
1018
|
+
const parts = url.pathname.split("/");
|
|
1019
|
+
const runId = parts[2];
|
|
1020
|
+
const sequence = Number(parts[4]);
|
|
1021
|
+
await workflows.markInputDelivered(runId, sequence);
|
|
1022
|
+
writeJson(res, 200, { ok: true });
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
815
1025
|
writeJson(res, 404, { error: "not found" });
|
|
816
1026
|
} catch (error) {
|
|
817
1027
|
if (error instanceof ZodError) {
|
|
@@ -831,7 +1041,7 @@ async function main() {
|
|
|
831
1041
|
`);
|
|
832
1042
|
});
|
|
833
1043
|
const shutdown = async () => {
|
|
834
|
-
await
|
|
1044
|
+
await shutdownWorkflows();
|
|
835
1045
|
await pool.end();
|
|
836
1046
|
server.close();
|
|
837
1047
|
process.exit(0);
|