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/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
- import { DBOS } from "@dbos-inc/dbos-sdk";
431
- function registerWorkflows(store) {
432
- const createTask = DBOS.registerWorkflow(
433
- async (input) => DBOS.runStep(() => store.createTask(input), {
434
- name: "store-create-task"
435
- }),
436
- { name: "createTaskWorkflow" }
437
- );
438
- const retryTask = DBOS.registerWorkflow(
439
- async (taskId) => DBOS.runStep(() => store.retryTask(taskId), {
440
- name: "store-retry-task"
441
- }),
442
- { name: "retryTaskWorkflow" }
443
- );
444
- const cancelTask = DBOS.registerWorkflow(
445
- async (taskId) => DBOS.runStep(() => store.cancelTask(taskId), {
446
- name: "store-cancel-task"
447
- }),
448
- { name: "cancelTaskWorkflow" }
449
- );
450
- const updateRunStatus = DBOS.registerWorkflow(
451
- async (runId, status, error) => DBOS.runStep(() => store.updateRunStatus(runId, status, error), {
452
- name: "store-update-run-status"
453
- }),
454
- { name: "updateRunStatusWorkflow" }
455
- );
456
- const appendRunLogs = DBOS.registerWorkflow(
457
- async (runId, logs) => DBOS.runStep(() => store.appendRunLogs(runId, logs), {
458
- name: "store-append-run-logs"
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 = registerWorkflows(store);
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 handle = await DBOS2.startWorkflow(workflows.createTask)({
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 handle = await DBOS2.startWorkflow(workflows.retryTask)(taskId);
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 handle = await DBOS2.startWorkflow(workflows.cancelTask)(taskId);
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 handle = await DBOS2.startWorkflow(workflows.updateRunStatus)(runId, body.status, body.error);
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 handle = await DBOS2.startWorkflow(workflows.appendRunLogs)(runId, body.logs ?? []);
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 handle = await DBOS2.startWorkflow(workflows.createArtifact)(runId, body);
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 DBOS2.shutdown();
1044
+ await shutdownWorkflows();
835
1045
  await pool.end();
836
1046
  server.close();
837
1047
  process.exit(0);