@osolmaz/pi-workflows 0.15.3 → 0.16.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 +6 -6
- package/dist/client/activity.d.ts +2 -0
- package/dist/client/activity.js +6 -0
- package/dist/client/activity.js.map +1 -0
- package/dist/client/client.d.ts +101 -0
- package/dist/client/client.js +733 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/materialize.d.ts +7 -0
- package/dist/client/materialize.js +177 -0
- package/dist/client/materialize.js.map +1 -0
- package/dist/client/protocol.d.ts +60 -0
- package/dist/client/protocol.js +269 -0
- package/dist/client/protocol.js.map +1 -0
- package/dist/client/resolver.d.ts +23 -0
- package/dist/client/resolver.js +2 -0
- package/dist/client/resolver.js.map +1 -0
- package/dist/client/view.d.ts +118 -0
- package/dist/client/view.js +3 -0
- package/dist/client/view.js.map +1 -0
- package/dist/controllers/sqlite.d.ts +43 -0
- package/dist/controllers/sqlite.js +137 -2
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/extension/index.d.ts +1 -0
- package/dist/extension/index.js +278 -183
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/session-view.d.ts +7 -2
- package/dist/extension/session-view.js +60 -52
- package/dist/extension/session-view.js.map +1 -1
- package/dist/extension/widget.d.ts +2 -1
- package/dist/extension/widget.js +14 -7
- package/dist/extension/widget.js.map +1 -1
- package/dist/host/child-worker-supervisor.js +1 -1
- package/dist/host/child-worker-supervisor.js.map +1 -1
- package/dist/host/resolver-entry.d.ts +2 -23
- package/dist/host/resolver-entry.js +1 -1
- package/dist/host/resolver-entry.js.map +1 -1
- package/dist/host/runner.d.ts +11 -0
- package/dist/host/runner.js +473 -17
- package/dist/host/runner.js.map +1 -1
- package/dist/host/state.d.ts +6 -3
- package/dist/host/state.js +52 -26
- package/dist/host/state.js.map +1 -1
- package/dist/host/view.d.ts +73 -0
- package/dist/host/view.js +871 -0
- package/dist/host/view.js.map +1 -0
- package/dist/host/worker-protocol.js +1 -1
- package/dist/host/worker-protocol.js.map +1 -1
- package/dist/state/database.d.ts +1 -0
- package/dist/state/database.js +15 -0
- package/dist/state/database.js.map +1 -1
- package/dist/state/prune.d.ts +3 -1
- package/dist/state/prune.js +6 -8
- package/dist/state/prune.js.map +1 -1
- package/dist/state/schema.js +12 -1
- package/dist/state/schema.js.map +1 -1
- package/dist/viewer/backup.d.ts +2 -0
- package/dist/viewer/backup.js +28 -0
- package/dist/viewer/backup.js.map +1 -0
- package/dist/viewer/cli.d.ts +4 -0
- package/dist/viewer/cli.js +150 -170
- package/dist/viewer/cli.js.map +1 -1
- package/dist/viewer/tui.d.ts +5 -7
- package/dist/viewer/tui.js +188 -108
- package/dist/viewer/tui.js.map +1 -1
- package/dist/workflows/store.d.ts +62 -1
- package/dist/workflows/store.js +350 -44
- package/dist/workflows/store.js.map +1 -1
- package/docs/2026-09-01-unified-workflow-client-plan.md +381 -0
- package/docs/2026-09-02-installed-live-e2e-plan.md +225 -0
- package/docs/SQLITE_STATE.md +13 -11
- package/docs/WORKFLOW_HOST.md +74 -61
- package/docs/development.md +2 -1
- package/docs/live-replay-protocol.md +70 -132
- package/docs/tui-viewer.md +10 -14
- package/docs/workflows.md +44 -1
- package/herdr-plugin.toml +1 -1
- package/package.json +9 -3
- package/protocol/client.v1.schema.json +137 -0
- package/protocol/fixtures/client-v1.json +23 -0
- package/src/client/activity.ts +6 -0
- package/src/client/client.ts +935 -0
- package/src/client/index.ts +24 -0
- package/src/client/materialize.ts +228 -0
- package/src/client/protocol.ts +327 -0
- package/src/client/resolver.ts +26 -0
- package/src/client/view.ts +138 -0
- package/src/controllers/sqlite.ts +213 -2
- package/src/extension/index.ts +349 -208
- package/src/extension/session-view.ts +73 -50
- package/src/extension/widget.ts +16 -8
- package/src/host/child-worker-supervisor.ts +1 -1
- package/src/host/resolver-entry.ts +11 -26
- package/src/host/runner.ts +648 -48
- package/src/host/state.ts +71 -43
- package/src/host/view.ts +1084 -0
- package/src/host/worker-protocol.ts +1 -1
- package/src/state/database.ts +13 -0
- package/src/state/prune.ts +11 -11
- package/src/state/schema.ts +12 -1
- package/src/viewer/backup.ts +29 -0
- package/src/viewer/cli.ts +171 -185
- package/src/viewer/tui.ts +196 -124
- package/src/workflows/store.ts +500 -45
- package/dist/host/client.d.ts +0 -48
- package/dist/host/client.js +0 -216
- package/dist/host/client.js.map +0 -1
- package/dist/host/protocol.d.ts +0 -38
- package/dist/host/protocol.js +0 -156
- package/dist/host/protocol.js.map +0 -1
- package/dist/viewer/watch.d.ts +0 -6
- package/dist/viewer/watch.js +0 -46
- package/dist/viewer/watch.js.map +0 -1
- package/src/host/client.ts +0 -293
- package/src/host/protocol.ts +0 -196
- package/src/viewer/watch.ts +0 -51
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/client/resolver.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { JsonValue } from "../state/json.js";
|
|
2
|
+
export declare const RUN_VIEW_SCHEMA: "pi-workflows.run-view.v1";
|
|
3
|
+
export declare const SESSION_VIEW_SCHEMA: "pi-workflows.session-view.v1";
|
|
4
|
+
export type WorkflowDisplayStatus = "queued" | "running" | "waiting" | "paused" | "completed" | "failed" | "timed_out" | "cancelled" | "ambiguous";
|
|
5
|
+
export type WorkflowDisplay = {
|
|
6
|
+
status: WorkflowDisplayStatus;
|
|
7
|
+
activity: "supervised_worker" | "origin_turn" | null;
|
|
8
|
+
controls: Array<"pause" | "resume" | "cancel" | "answer" | "review">;
|
|
9
|
+
reason: string | null;
|
|
10
|
+
reasonContent?: JsonValue;
|
|
11
|
+
};
|
|
12
|
+
export type WorkflowRunQueueView = {
|
|
13
|
+
runId: string;
|
|
14
|
+
workflowName: string;
|
|
15
|
+
workflowSourceRef: string;
|
|
16
|
+
initialized: boolean;
|
|
17
|
+
definitionDigest: string;
|
|
18
|
+
status: "queued" | "starting" | "running" | "parked" | "done" | "failed" | "cancelled";
|
|
19
|
+
originSessionId: string | null;
|
|
20
|
+
executionMode: "interactive" | "headless";
|
|
21
|
+
parentRunId: string | null;
|
|
22
|
+
errorCode: string | null;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
updatedAt: string;
|
|
25
|
+
startedAt: string | null;
|
|
26
|
+
finishedAt: string | null;
|
|
27
|
+
};
|
|
28
|
+
export type WorkflowRunView = {
|
|
29
|
+
schema: typeof RUN_VIEW_SCHEMA;
|
|
30
|
+
runId: string;
|
|
31
|
+
revision: number;
|
|
32
|
+
display: WorkflowDisplay;
|
|
33
|
+
manifest: JsonValue;
|
|
34
|
+
state: JsonValue;
|
|
35
|
+
workflow: JsonValue;
|
|
36
|
+
queue: WorkflowRunQueueView;
|
|
37
|
+
updates: JsonValue[];
|
|
38
|
+
graphSteps: JsonValue[];
|
|
39
|
+
graphStepStart: number;
|
|
40
|
+
graphStepTotal: number;
|
|
41
|
+
takenTransitions: string[];
|
|
42
|
+
graphHistory: JsonValue;
|
|
43
|
+
takenTransitionStart: number;
|
|
44
|
+
takenTransitionTotal: number;
|
|
45
|
+
graphCursor: number;
|
|
46
|
+
stepStart: number;
|
|
47
|
+
stepTotal: number;
|
|
48
|
+
tracePage: JsonValue;
|
|
49
|
+
session: JsonValue;
|
|
50
|
+
settingsScopes: JsonValue[];
|
|
51
|
+
settingsStart: number;
|
|
52
|
+
settingsTotal: number;
|
|
53
|
+
followUpQueue: JsonValue;
|
|
54
|
+
followUpStart: number;
|
|
55
|
+
followUpTotal: number;
|
|
56
|
+
updateStart: number;
|
|
57
|
+
updateTotal: number;
|
|
58
|
+
live: boolean;
|
|
59
|
+
possiblyInterrupted: boolean;
|
|
60
|
+
};
|
|
61
|
+
export type WorkflowRunListPage = {
|
|
62
|
+
schema: "pi-workflows.run-list-page.v1";
|
|
63
|
+
revision: string;
|
|
64
|
+
start: number;
|
|
65
|
+
total: number;
|
|
66
|
+
items: WorkflowRunSummary[];
|
|
67
|
+
};
|
|
68
|
+
export type WorkflowRunSummary = {
|
|
69
|
+
runId: string;
|
|
70
|
+
workflowName: string;
|
|
71
|
+
originSessionId: string | null;
|
|
72
|
+
createdAt: string;
|
|
73
|
+
updatedAt: string;
|
|
74
|
+
display: WorkflowDisplay;
|
|
75
|
+
manifest: JsonValue;
|
|
76
|
+
live: boolean;
|
|
77
|
+
possiblyInterrupted: boolean;
|
|
78
|
+
};
|
|
79
|
+
export type ClientInteractiveRequest = {
|
|
80
|
+
requestId: string;
|
|
81
|
+
runId: string;
|
|
82
|
+
attemptId: string;
|
|
83
|
+
targetSessionId: string;
|
|
84
|
+
kind: "agent" | "assistant" | "decision";
|
|
85
|
+
contract: JsonValue;
|
|
86
|
+
revision: number;
|
|
87
|
+
status: "pending" | "presenting" | "settled" | "cancelled";
|
|
88
|
+
presenterId: string | null;
|
|
89
|
+
presentationClaimExpiresAt: string | null;
|
|
90
|
+
presentationSessionEntryId: string | null;
|
|
91
|
+
acceptedSubmissionId: string | null;
|
|
92
|
+
createdAt: string;
|
|
93
|
+
updatedAt: string;
|
|
94
|
+
settledAt: string | null;
|
|
95
|
+
consumedAt: string | null;
|
|
96
|
+
};
|
|
97
|
+
export type WorkflowDeliveryAvailability = {
|
|
98
|
+
notification: boolean;
|
|
99
|
+
turn: boolean;
|
|
100
|
+
};
|
|
101
|
+
export type WorkflowSessionView = {
|
|
102
|
+
schema: typeof SESSION_VIEW_SCHEMA;
|
|
103
|
+
sessionId: string;
|
|
104
|
+
run: WorkflowRunView | null;
|
|
105
|
+
pendingInteractions: JsonValue[];
|
|
106
|
+
pendingInteractionStart: number;
|
|
107
|
+
pendingInteractionTotal: number;
|
|
108
|
+
deliveries: WorkflowDeliveryAvailability;
|
|
109
|
+
};
|
|
110
|
+
export type OriginActivityReport = {
|
|
111
|
+
sessionId: string;
|
|
112
|
+
runId: string;
|
|
113
|
+
requestId: string;
|
|
114
|
+
deliveryId: string;
|
|
115
|
+
sessionEntryId: string;
|
|
116
|
+
sequence: number;
|
|
117
|
+
state: "started" | "refresh" | "settled";
|
|
118
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/client/view.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAG,0BAAmC,CAAC;AACnE,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAAuC,CAAC"}
|
|
@@ -22,6 +22,26 @@ export type WorkflowRunClaimOptions = WorkflowRunReservationOptions & {
|
|
|
22
22
|
claimToken: string;
|
|
23
23
|
leaseMs: number;
|
|
24
24
|
};
|
|
25
|
+
export type WorkflowRunQueueViewRecord = {
|
|
26
|
+
runId: string;
|
|
27
|
+
workflowName: string;
|
|
28
|
+
workflowSourceRef: string;
|
|
29
|
+
workflowSource: unknown;
|
|
30
|
+
initialized: boolean;
|
|
31
|
+
definitionDigest: string;
|
|
32
|
+
runStateStatus: string;
|
|
33
|
+
paused: boolean;
|
|
34
|
+
status: WorkflowRunLaunchStatus;
|
|
35
|
+
originSessionId: string | null;
|
|
36
|
+
executionMode: "interactive" | "headless";
|
|
37
|
+
parentRunId: string | null;
|
|
38
|
+
errorCode: string | null;
|
|
39
|
+
errorMessage: string | null;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
updatedAt: string;
|
|
42
|
+
startedAt: string | null;
|
|
43
|
+
finishedAt: string | null;
|
|
44
|
+
};
|
|
25
45
|
export type WorkflowRunQueueRecord = {
|
|
26
46
|
runId: string;
|
|
27
47
|
workflowName: string;
|
|
@@ -212,6 +232,19 @@ export declare class SqliteControllerStore implements ControllerStore {
|
|
|
212
232
|
prepareOrAdoptWorkflowRun(options: WorkflowRunClaimOptions): WorkflowRunPreparationResult;
|
|
213
233
|
enqueueWorkflowRun(options: WorkflowRunClaimOptions): WorkflowRunQueueRecord;
|
|
214
234
|
getWorkflowRun(runId: string): WorkflowRunQueueRecord | undefined;
|
|
235
|
+
getWorkflowRunView(runId: string): WorkflowRunQueueViewRecord | undefined;
|
|
236
|
+
workflowRunListRevision(): {
|
|
237
|
+
total: number;
|
|
238
|
+
revision: string;
|
|
239
|
+
};
|
|
240
|
+
listWorkflowRunViews(options: {
|
|
241
|
+
offset: number;
|
|
242
|
+
limit: number;
|
|
243
|
+
}): {
|
|
244
|
+
total: number;
|
|
245
|
+
revision: string;
|
|
246
|
+
runs: WorkflowRunQueueViewRecord[];
|
|
247
|
+
};
|
|
215
248
|
workflowRunProjectPath(runId: string): string | undefined;
|
|
216
249
|
listWorkflowRuns(options?: {
|
|
217
250
|
statuses?: WorkflowRunLaunchStatus[];
|
|
@@ -219,6 +252,7 @@ export declare class SqliteControllerStore implements ControllerStore {
|
|
|
219
252
|
limit?: number;
|
|
220
253
|
}): WorkflowRunQueueRecord[];
|
|
221
254
|
findSessionReservation(sessionId: string): WorkflowRunQueueRecord | undefined;
|
|
255
|
+
findSessionReservationView(sessionId: string): WorkflowRunQueueViewRecord | undefined;
|
|
222
256
|
claimWorkflowRun(options: {
|
|
223
257
|
runId: string;
|
|
224
258
|
runnerId: string;
|
|
@@ -386,6 +420,10 @@ export declare class SqliteControllerStore implements ControllerStore {
|
|
|
386
420
|
now?: string;
|
|
387
421
|
limit?: number;
|
|
388
422
|
}): WorkflowTurnIntentRecord[];
|
|
423
|
+
hasClaimableWorkflowTurnIntent(options: {
|
|
424
|
+
targetSessionId: string;
|
|
425
|
+
now?: string;
|
|
426
|
+
}): boolean;
|
|
389
427
|
makeWorkflowTurnIntentEligible(options: {
|
|
390
428
|
intentId: string;
|
|
391
429
|
fallbackFacts: WorkflowTurnIntentFacts;
|
|
@@ -421,6 +459,10 @@ export declare class SqliteControllerStore implements ControllerStore {
|
|
|
421
459
|
content: string;
|
|
422
460
|
now?: string;
|
|
423
461
|
}): WorkflowNotificationRecord;
|
|
462
|
+
hasClaimableWorkflowNotification(options: {
|
|
463
|
+
targetSessionId: string;
|
|
464
|
+
now?: string;
|
|
465
|
+
}): boolean;
|
|
424
466
|
listPendingWorkflowNotifications(options: {
|
|
425
467
|
targetSessionId: string;
|
|
426
468
|
limit?: number;
|
|
@@ -478,6 +520,7 @@ export declare class SqliteControllerStore implements ControllerStore {
|
|
|
478
520
|
private requireWorkflowRunRow;
|
|
479
521
|
private requireWorkflowRun;
|
|
480
522
|
private assertWorkflowRunPreparationCompatible;
|
|
523
|
+
private workflowRunViewRows;
|
|
481
524
|
private mapWorkflowRun;
|
|
482
525
|
private claimRun;
|
|
483
526
|
private claimRunInTransaction;
|
|
@@ -640,6 +640,32 @@ export class SqliteControllerStore {
|
|
|
640
640
|
const row = this.workflowRunRow(runId);
|
|
641
641
|
return row === undefined ? undefined : this.mapWorkflowRun(row);
|
|
642
642
|
}
|
|
643
|
+
getWorkflowRunView(runId) {
|
|
644
|
+
const row = this.workflowRunViewRows("WHERE r.run_id = ?", [runId])[0];
|
|
645
|
+
return row === undefined ? undefined : workflowRunViewRecord(row);
|
|
646
|
+
}
|
|
647
|
+
workflowRunListRevision() {
|
|
648
|
+
const row = this.state.connection
|
|
649
|
+
.prepare(`SELECT count(*) AS count, COALESCE(sum(res.revision), 0) AS revisionSum,
|
|
650
|
+
COALESCE(max(q.updated_at), 0) AS updatedAt
|
|
651
|
+
FROM runs r JOIN run_queue q ON q.run_id = r.run_id
|
|
652
|
+
JOIN resources res ON res.resource_id = r.resource_id`)
|
|
653
|
+
.get();
|
|
654
|
+
if (!isRunListRevisionRow(row))
|
|
655
|
+
throw new Error("Workflow run list revision is invalid");
|
|
656
|
+
return {
|
|
657
|
+
total: row.count,
|
|
658
|
+
revision: `${row.count}:${row.revisionSum}:${row.updatedAt}`,
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
listWorkflowRunViews(options) {
|
|
662
|
+
const current = this.workflowRunListRevision();
|
|
663
|
+
const rows = this.workflowRunViewRows("ORDER BY q.created_at DESC LIMIT ? OFFSET ?", [
|
|
664
|
+
options.limit,
|
|
665
|
+
options.offset,
|
|
666
|
+
]);
|
|
667
|
+
return { ...current, runs: rows.map(workflowRunViewRecord) };
|
|
668
|
+
}
|
|
643
669
|
workflowRunProjectPath(runId) {
|
|
644
670
|
const row = this.state.connection
|
|
645
671
|
.prepare(`SELECT p.canonical_path AS canonicalPath
|
|
@@ -662,9 +688,10 @@ export class SqliteControllerStore {
|
|
|
662
688
|
clauses.push(`r.run_id NOT IN (${options.excludeRunIds.map(() => "?").join(", ")})`);
|
|
663
689
|
params.push(...options.excludeRunIds);
|
|
664
690
|
}
|
|
665
|
-
|
|
691
|
+
if (options.limit !== undefined)
|
|
692
|
+
params.push(options.limit);
|
|
666
693
|
const rows = this.state.connection
|
|
667
|
-
.prepare(workflowRunSelect(`${clauses.length === 0 ? "" : `WHERE ${clauses.join(" AND ")}`} ORDER BY q.created_at DESC LIMIT
|
|
694
|
+
.prepare(workflowRunSelect(`${clauses.length === 0 ? "" : `WHERE ${clauses.join(" AND ")}`} ORDER BY q.created_at DESC${options.limit === undefined ? "" : " LIMIT ?"}`))
|
|
668
695
|
.all(...params);
|
|
669
696
|
return rows.filter(isRunRow).map((row) => this.mapWorkflowRun(row));
|
|
670
697
|
}
|
|
@@ -674,6 +701,10 @@ export class SqliteControllerStore {
|
|
|
674
701
|
.get(sessionId);
|
|
675
702
|
return isRunRow(row) ? this.mapWorkflowRun(row) : undefined;
|
|
676
703
|
}
|
|
704
|
+
findSessionReservationView(sessionId) {
|
|
705
|
+
const row = this.workflowRunViewRows("WHERE b.origin_session_id = ? AND q.status NOT IN ('done', 'failed', 'cancelled') ORDER BY q.created_at DESC LIMIT 1", [sessionId])[0];
|
|
706
|
+
return row === undefined ? undefined : workflowRunViewRecord(row);
|
|
707
|
+
}
|
|
677
708
|
claimWorkflowRun(options) {
|
|
678
709
|
const now = epoch(validTimestamp(options.now));
|
|
679
710
|
return this.claimRun(options.runId, options.runnerId, options.claimToken, options.leaseMs, now);
|
|
@@ -1206,6 +1237,21 @@ export class SqliteControllerStore {
|
|
|
1206
1237
|
}
|
|
1207
1238
|
return claimed;
|
|
1208
1239
|
}
|
|
1240
|
+
hasClaimableWorkflowTurnIntent(options) {
|
|
1241
|
+
const now = epoch(validTimestamp(options.now));
|
|
1242
|
+
const row = this.state.connection
|
|
1243
|
+
.prepare(`SELECT 1 AS present
|
|
1244
|
+
FROM turn_intents t
|
|
1245
|
+
JOIN effects e ON e.effect_id = t.effect_id
|
|
1246
|
+
JOIN leases l ON l.resource_id = e.resource_id
|
|
1247
|
+
WHERE t.target_session_id = ? AND t.resolved_at IS NULL
|
|
1248
|
+
AND t.eligible_at IS NOT NULL AND t.eligible_at <= ?
|
|
1249
|
+
AND e.status = 'pending'
|
|
1250
|
+
AND (l.owner_id IS NULL OR l.expires_at IS NULL OR l.expires_at <= ?)
|
|
1251
|
+
LIMIT 1`)
|
|
1252
|
+
.get(options.targetSessionId, now, now);
|
|
1253
|
+
return row !== undefined;
|
|
1254
|
+
}
|
|
1209
1255
|
makeWorkflowTurnIntentEligible(options) {
|
|
1210
1256
|
const eligibleAt = epoch(validTimestamp(options.eligibleAt ?? options.now));
|
|
1211
1257
|
const factsHash = this.state.putJson(options.fallbackFacts, eligibleAt);
|
|
@@ -1284,6 +1330,19 @@ export class SqliteControllerStore {
|
|
|
1284
1330
|
});
|
|
1285
1331
|
return this.requireNotification(options.runId, options.attemptId, options.notificationIndex);
|
|
1286
1332
|
}
|
|
1333
|
+
hasClaimableWorkflowNotification(options) {
|
|
1334
|
+
const now = epoch(validTimestamp(options.now));
|
|
1335
|
+
const row = this.state.connection
|
|
1336
|
+
.prepare(`SELECT 1 AS present
|
|
1337
|
+
FROM notifications n
|
|
1338
|
+
JOIN effects e ON e.effect_id = n.effect_id
|
|
1339
|
+
JOIN leases l ON l.resource_id = e.resource_id
|
|
1340
|
+
WHERE n.target_session_id = ? AND e.status = 'pending'
|
|
1341
|
+
AND (l.owner_id IS NULL OR l.expires_at IS NULL OR l.expires_at <= ?)
|
|
1342
|
+
LIMIT 1`)
|
|
1343
|
+
.get(options.targetSessionId, now);
|
|
1344
|
+
return row !== undefined;
|
|
1345
|
+
}
|
|
1287
1346
|
listPendingWorkflowNotifications(options) {
|
|
1288
1347
|
const now = Date.now();
|
|
1289
1348
|
return this.notificationRows(options.targetSessionId, options.limit ?? 20)
|
|
@@ -1678,6 +1737,12 @@ export class SqliteControllerStore {
|
|
|
1678
1737
|
throw new Error(`Workflow run preparation conflicts: ${options.runId}`);
|
|
1679
1738
|
}
|
|
1680
1739
|
}
|
|
1740
|
+
workflowRunViewRows(clause, params) {
|
|
1741
|
+
return this.state.connection
|
|
1742
|
+
.prepare(workflowRunViewSelect(clause))
|
|
1743
|
+
.all(...params)
|
|
1744
|
+
.filter(isWorkflowRunViewRow);
|
|
1745
|
+
}
|
|
1681
1746
|
/* istanbul ignore next -- pure projection covered by integration tests */
|
|
1682
1747
|
mapWorkflowRun(row) {
|
|
1683
1748
|
return {
|
|
@@ -2120,6 +2185,23 @@ function workflowRunSelect(clause) {
|
|
|
2120
2185
|
LEFT JOIN run_bindings b ON b.run_id = r.run_id
|
|
2121
2186
|
JOIN leases l ON l.resource_id = r.resource_id ${clause}`;
|
|
2122
2187
|
}
|
|
2188
|
+
function workflowRunViewSelect(clause) {
|
|
2189
|
+
return `SELECT r.run_id AS runId, d.workflow_name AS workflowName,
|
|
2190
|
+
r.workflow_ref AS workflowRef, r.status AS runStatus, r.paused,
|
|
2191
|
+
r.definition_digest AS definitionDigest, q.status,
|
|
2192
|
+
b.origin_session_id AS originSessionId, b.execution_mode AS executionMode,
|
|
2193
|
+
r.parent_run_id AS parentRunId, q.error_code AS errorCode,
|
|
2194
|
+
CAST(error.content AS TEXT) AS errorMessage,
|
|
2195
|
+
q.created_at AS createdAt, q.updated_at AS updatedAt,
|
|
2196
|
+
q.started_at AS startedAt, q.finished_at AS finishedAt,
|
|
2197
|
+
source.source_type AS sourceType, source.source_ref AS sourceRef,
|
|
2198
|
+
source.source_revision AS sourceRevision
|
|
2199
|
+
FROM runs r JOIN workflow_definitions d ON d.definition_digest = r.definition_digest
|
|
2200
|
+
JOIN run_queue q ON q.run_id = r.run_id
|
|
2201
|
+
LEFT JOIN run_bindings b ON b.run_id = r.run_id
|
|
2202
|
+
LEFT JOIN run_sources source ON source.run_id = r.run_id AND source.mount_path = ''
|
|
2203
|
+
LEFT JOIN blobs error ON error.blob_hash = q.error_hash ${clause}`;
|
|
2204
|
+
}
|
|
2123
2205
|
function turnIntentSelect(clause) {
|
|
2124
2206
|
return `SELECT t.turn_intent_id AS intentId, t.source_event_id AS sourceEventId,
|
|
2125
2207
|
t.run_id AS runId, t.workflow_ref AS workflowRef,
|
|
@@ -2152,6 +2234,59 @@ function isControllerRow(value) {
|
|
|
2152
2234
|
function isLeaseRow(value) {
|
|
2153
2235
|
return isRecord(value);
|
|
2154
2236
|
}
|
|
2237
|
+
function workflowRunViewRecord(row) {
|
|
2238
|
+
const root = row.sourceType === "builtin"
|
|
2239
|
+
? { kind: "builtin", id: row.sourceRef, revision: row.sourceRevision }
|
|
2240
|
+
: { kind: "file", path: row.sourceRef, hash: row.sourceRevision };
|
|
2241
|
+
return {
|
|
2242
|
+
runId: row.runId,
|
|
2243
|
+
workflowName: row.workflowName,
|
|
2244
|
+
workflowSourceRef: row.workflowRef,
|
|
2245
|
+
workflowSource: { root, mounted: [] },
|
|
2246
|
+
initialized: row.runStatus !== "queued",
|
|
2247
|
+
definitionDigest: `sha256:${row.definitionDigest.toString("hex")}`,
|
|
2248
|
+
runStateStatus: row.runStatus,
|
|
2249
|
+
paused: row.paused === 1,
|
|
2250
|
+
status: row.status,
|
|
2251
|
+
originSessionId: row.executionMode === "headless" ? null : row.originSessionId,
|
|
2252
|
+
executionMode: row.executionMode,
|
|
2253
|
+
parentRunId: row.parentRunId,
|
|
2254
|
+
errorCode: row.errorCode,
|
|
2255
|
+
errorMessage: row.errorMessage,
|
|
2256
|
+
createdAt: new Date(row.createdAt).toISOString(),
|
|
2257
|
+
updatedAt: new Date(row.updatedAt).toISOString(),
|
|
2258
|
+
startedAt: row.startedAt === null ? null : new Date(row.startedAt).toISOString(),
|
|
2259
|
+
finishedAt: row.finishedAt === null ? null : new Date(row.finishedAt).toISOString(),
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
function isWorkflowRunViewRow(value) {
|
|
2263
|
+
return (isRecord(value) &&
|
|
2264
|
+
typeof value.runId === "string" &&
|
|
2265
|
+
typeof value.workflowName === "string" &&
|
|
2266
|
+
typeof value.workflowRef === "string" &&
|
|
2267
|
+
typeof value.runStatus === "string" &&
|
|
2268
|
+
typeof value.paused === "number" &&
|
|
2269
|
+
Buffer.isBuffer(value.definitionDigest) &&
|
|
2270
|
+
typeof value.status === "string" &&
|
|
2271
|
+
(value.originSessionId === null || typeof value.originSessionId === "string") &&
|
|
2272
|
+
(value.executionMode === "interactive" || value.executionMode === "headless") &&
|
|
2273
|
+
(value.parentRunId === null || typeof value.parentRunId === "string") &&
|
|
2274
|
+
(value.errorCode === null || typeof value.errorCode === "string") &&
|
|
2275
|
+
(value.errorMessage === null || typeof value.errorMessage === "string") &&
|
|
2276
|
+
typeof value.createdAt === "number" &&
|
|
2277
|
+
typeof value.updatedAt === "number" &&
|
|
2278
|
+
(value.startedAt === null || typeof value.startedAt === "number") &&
|
|
2279
|
+
(value.finishedAt === null || typeof value.finishedAt === "number") &&
|
|
2280
|
+
(value.sourceType === "builtin" || value.sourceType === "file") &&
|
|
2281
|
+
typeof value.sourceRef === "string" &&
|
|
2282
|
+
typeof value.sourceRevision === "string");
|
|
2283
|
+
}
|
|
2284
|
+
function isRunListRevisionRow(value) {
|
|
2285
|
+
return (isRecord(value) &&
|
|
2286
|
+
typeof value.count === "number" &&
|
|
2287
|
+
typeof value.revisionSum === "number" &&
|
|
2288
|
+
typeof value.updatedAt === "number");
|
|
2289
|
+
}
|
|
2155
2290
|
function isRunRow(value) {
|
|
2156
2291
|
return isRecord(value);
|
|
2157
2292
|
}
|