@osolmaz/pi-workflows 0.13.4 → 0.15.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 +146 -160
- package/dist/builtins/autoimplement.workflow.js +3 -1
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/change-verification.workflow.js +7 -2
- package/dist/builtins/change-verification.workflow.js.map +1 -1
- package/dist/builtins/metadata.d.ts +22 -0
- package/dist/builtins/metadata.js +10 -0
- package/dist/builtins/metadata.js.map +1 -0
- package/dist/builtins/monitor.workflow.js +4 -1
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/sanity-check.workflow.js +4 -1
- package/dist/builtins/sanity-check.workflow.js.map +1 -1
- package/dist/builtins/workspace-preparation.workflow.js +3 -1
- package/dist/builtins/workspace-preparation.workflow.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -2
- package/dist/controllers/index.js +0 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/sqlite.d.ts +85 -31
- package/dist/controllers/sqlite.js +541 -126
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/controllers/store.d.ts +1 -0
- package/dist/extension/controller-command.d.ts +22 -0
- package/dist/extension/controller-command.js +32 -0
- package/dist/extension/controller-command.js.map +1 -0
- package/dist/extension/index.d.ts +2 -9
- package/dist/extension/index.js +876 -2928
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/message-card.d.ts +13 -0
- package/dist/extension/message-card.js +46 -0
- package/dist/extension/message-card.js.map +1 -0
- package/dist/extension/step-message.d.ts +5 -6
- package/dist/extension/step-message.js +41 -52
- package/dist/extension/step-message.js.map +1 -1
- package/dist/host/child-worker-supervisor.d.ts +50 -0
- package/dist/host/child-worker-supervisor.js +159 -0
- package/dist/host/child-worker-supervisor.js.map +1 -0
- package/dist/host/client.d.ts +48 -0
- package/dist/host/client.js +216 -0
- package/dist/host/client.js.map +1 -0
- package/dist/host/controller-worker-entry.d.ts +2 -0
- package/dist/host/controller-worker-entry.js +244 -0
- package/dist/host/controller-worker-entry.js.map +1 -0
- package/dist/host/controller-worker-protocol.d.ts +36 -0
- package/dist/host/controller-worker-protocol.js +49 -0
- package/dist/host/controller-worker-protocol.js.map +1 -0
- package/dist/host/controller-worker-supervisor.d.ts +21 -0
- package/dist/host/controller-worker-supervisor.js +54 -0
- package/dist/host/controller-worker-supervisor.js.map +1 -0
- package/dist/host/host-entry.d.ts +2 -0
- package/dist/host/host-entry.js +23 -0
- package/dist/host/host-entry.js.map +1 -0
- package/dist/host/processes.d.ts +17 -12
- package/dist/host/processes.js +154 -50
- package/dist/host/processes.js.map +1 -1
- package/dist/host/protocol.d.ts +38 -0
- package/dist/host/protocol.js +156 -0
- package/dist/host/protocol.js.map +1 -0
- package/dist/host/resolver-entry.d.ts +49 -0
- package/dist/host/resolver-entry.js +149 -0
- package/dist/host/resolver-entry.js.map +1 -0
- package/dist/host/rpc-executor.d.ts +14 -3
- package/dist/host/rpc-executor.js +63 -30
- package/dist/host/rpc-executor.js.map +1 -1
- package/dist/host/runner.d.ts +95 -29
- package/dist/host/runner.js +2311 -348
- package/dist/host/runner.js.map +1 -1
- package/dist/host/state.d.ts +174 -0
- package/dist/host/state.js +689 -0
- package/dist/host/state.js.map +1 -0
- package/dist/host/worker-entry.d.ts +10 -0
- package/dist/host/worker-entry.js +446 -0
- package/dist/host/worker-entry.js.map +1 -0
- package/dist/host/worker-protocol.d.ts +31 -0
- package/dist/host/worker-protocol.js +122 -0
- package/dist/host/worker-protocol.js.map +1 -0
- package/dist/host/worker-store.d.ts +80 -0
- package/dist/host/worker-store.js +91 -0
- package/dist/host/worker-store.js.map +1 -0
- package/dist/host/worker-supervisor.d.ts +22 -0
- package/dist/host/worker-supervisor.js +54 -0
- package/dist/host/worker-supervisor.js.map +1 -0
- package/dist/render/canvas.d.ts +2 -1
- package/dist/render/canvas.js +40 -15
- package/dist/render/canvas.js.map +1 -1
- package/dist/render/graph-render.d.ts +7 -3
- package/dist/render/graph-render.js +125 -74
- package/dist/render/graph-render.js.map +1 -1
- package/dist/state/database.js +3 -1
- package/dist/state/database.js.map +1 -1
- package/dist/state/index.d.ts +1 -0
- package/dist/state/index.js +1 -0
- package/dist/state/index.js.map +1 -1
- package/dist/state/prune.js +36 -10
- package/dist/state/prune.js.map +1 -1
- package/dist/state/schema.d.ts +1 -1
- package/dist/state/schema.js +171 -3
- package/dist/state/schema.js.map +1 -1
- package/dist/state/viewer.d.ts +46 -0
- package/dist/state/viewer.js +249 -0
- package/dist/state/viewer.js.map +1 -0
- package/dist/viewer/cli.d.ts +1 -1
- package/dist/viewer/cli.js +47 -18
- package/dist/viewer/cli.js.map +1 -1
- package/dist/workflows/composition.js +25 -2
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/definition.d.ts +3 -1
- package/dist/workflows/definition.js +25 -0
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +1 -0
- package/dist/workflows/engine.js +157 -42
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/errors.d.ts +3 -1
- package/dist/workflows/errors.js +4 -7
- package/dist/workflows/errors.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +3 -0
- package/dist/workflows/human-decision.js +31 -0
- package/dist/workflows/human-decision.js.map +1 -1
- package/dist/workflows/index.d.ts +1 -1
- package/dist/workflows/index.js +1 -1
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/schema.js +17 -6
- package/dist/workflows/schema.js.map +1 -1
- package/dist/{viewer → workflows}/session-reducer.d.ts +3 -1
- package/dist/{viewer → workflows}/session-reducer.js +4 -0
- package/dist/workflows/session-reducer.js.map +1 -0
- package/dist/workflows/store.d.ts +87 -1
- package/dist/workflows/store.js +892 -93
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/tool-input.d.ts +0 -22
- package/dist/workflows/tool-input.js +1 -44
- package/dist/workflows/tool-input.js.map +1 -1
- package/dist/workflows/types.d.ts +36 -4
- package/docs/2026-08-25-workflow-follow-ups.md +8 -6
- package/docs/2026-08-30-out-of-process-workflow-host-plan.md +353 -0
- package/docs/CONTROLLERS.md +11 -11
- package/docs/DEFERRED_TURNS.md +61 -27
- package/docs/HUMAN_DECISIONS.md +12 -4
- package/docs/SQLITE_STATE.md +42 -8
- package/docs/WORKFLOW_HOST.md +452 -0
- package/docs/development.md +46 -30
- package/docs/live-replay-protocol.md +129 -100
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +34 -8
- package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +399 -0
- package/docs/plans/2026-08-28-piw-incremental-viewer-plan.md +293 -0
- package/docs/plans/piw-viewer-experience-implementation-plan.md +11 -1
- package/docs/plans/tui-viewer-implementation-plan.md +5 -0
- package/docs/tui-viewer.md +18 -3
- package/docs/workflows.md +164 -156
- package/examples/workflows/command-batch.workflow.ts +2 -0
- package/examples/workflows/shell.workflow.ts +2 -1
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/skills/autodoc/SKILL.md +1 -1
- package/skills/autoimplement/SKILL.md +1 -1
- package/skills/autoplan/SKILL.md +1 -1
- package/skills/pi-workflows/SKILL.md +2 -0
- package/src/builtins/autoimplement.workflow.ts +3 -0
- package/src/builtins/change-verification.workflow.ts +7 -2
- package/src/builtins/metadata.ts +9 -0
- package/src/builtins/monitor.workflow.ts +4 -0
- package/src/builtins/sanity-check.workflow.ts +4 -0
- package/src/builtins/workspace-preparation.workflow.ts +3 -1
- package/src/controllers/index.ts +3 -5
- package/src/controllers/sqlite.ts +929 -225
- package/src/controllers/store.ts +1 -0
- package/src/extension/controller-command.ts +45 -0
- package/src/extension/index.ts +948 -3506
- package/src/extension/message-card.ts +61 -0
- package/src/extension/step-message.ts +58 -63
- package/src/host/child-worker-supervisor.ts +183 -0
- package/src/host/client.ts +293 -0
- package/src/host/controller-worker-entry.ts +311 -0
- package/src/host/controller-worker-protocol.ts +104 -0
- package/src/host/controller-worker-supervisor.ts +79 -0
- package/src/host/host-entry.ts +23 -0
- package/src/host/processes.ts +171 -54
- package/src/host/protocol.ts +196 -0
- package/src/host/resolver-entry.ts +241 -0
- package/src/host/rpc-executor.ts +76 -34
- package/src/host/runner.ts +2813 -422
- package/src/host/state.ts +1160 -0
- package/src/host/worker-entry.ts +533 -0
- package/src/host/worker-protocol.ts +165 -0
- package/src/host/worker-store.ts +229 -0
- package/src/host/worker-supervisor.ts +74 -0
- package/src/render/canvas.ts +44 -10
- package/src/render/graph-render.ts +145 -90
- package/src/state/database.ts +2 -1
- package/src/state/index.ts +14 -0
- package/src/state/prune.ts +35 -9
- package/src/state/schema.ts +171 -3
- package/src/state/viewer.ts +356 -0
- package/src/viewer/cli.ts +49 -17
- package/src/workflows/composition.ts +36 -2
- package/src/workflows/definition.ts +32 -0
- package/src/workflows/engine.ts +157 -54
- package/src/workflows/errors.ts +11 -2
- package/src/workflows/human-decision.ts +49 -0
- package/src/workflows/index.ts +2 -0
- package/src/workflows/schema.ts +19 -6
- package/src/{viewer → workflows}/session-reducer.ts +11 -1
- package/src/workflows/store.ts +1316 -108
- package/src/workflows/tool-input.ts +2 -60
- package/src/workflows/types.ts +32 -4
- package/dist/controllers/workflow-engine-scheduler.d.ts +0 -29
- package/dist/controllers/workflow-engine-scheduler.js +0 -175
- package/dist/controllers/workflow-engine-scheduler.js.map +0 -1
- package/dist/extension/controller-host.d.ts +0 -48
- package/dist/extension/controller-host.js +0 -110
- package/dist/extension/controller-host.js.map +0 -1
- package/dist/extension/deferred-turn-coordinator.d.ts +0 -32
- package/dist/extension/deferred-turn-coordinator.js +0 -143
- package/dist/extension/deferred-turn-coordinator.js.map +0 -1
- package/dist/extension/deferred-turn.d.ts +0 -44
- package/dist/extension/deferred-turn.js +0 -110
- package/dist/extension/deferred-turn.js.map +0 -1
- package/dist/extension/executor.d.ts +0 -86
- package/dist/extension/executor.js +0 -311
- package/dist/extension/executor.js.map +0 -1
- package/dist/extension/follow-up-coordinator.d.ts +0 -27
- package/dist/extension/follow-up-coordinator.js +0 -131
- package/dist/extension/follow-up-coordinator.js.map +0 -1
- package/dist/extension/recorder.d.ts +0 -84
- package/dist/extension/recorder.js +0 -528
- package/dist/extension/recorder.js.map +0 -1
- package/dist/extension/session-events.d.ts +0 -133
- package/dist/extension/session-events.js +0 -61
- package/dist/extension/session-events.js.map +0 -1
- package/dist/viewer/session-reducer.js.map +0 -1
- package/src/controllers/workflow-engine-scheduler.ts +0 -246
- package/src/extension/controller-host.ts +0 -167
- package/src/extension/deferred-turn-coordinator.ts +0 -171
- package/src/extension/deferred-turn.ts +0 -166
- package/src/extension/executor.ts +0 -411
- package/src/extension/follow-up-coordinator.ts +0 -151
- package/src/extension/recorder.ts +0 -655
- package/src/extension/session-events.ts +0 -121
package/src/workflows/errors.ts
CHANGED
|
@@ -20,13 +20,22 @@ export class CancelledError extends Error {
|
|
|
20
20
|
* The current claim holder owns the run from that point on, so the fenced
|
|
21
21
|
* writer must stop changing the run immediately.
|
|
22
22
|
*/
|
|
23
|
+
export type ClaimLostReason =
|
|
24
|
+
| "missingAuthority"
|
|
25
|
+
| "expired"
|
|
26
|
+
| "ownerChanged"
|
|
27
|
+
| "tokenChanged"
|
|
28
|
+
| "generationChanged";
|
|
29
|
+
|
|
23
30
|
export class ClaimLostError extends Error {
|
|
24
31
|
readonly runId: string;
|
|
32
|
+
readonly reason: ClaimLostReason;
|
|
25
33
|
|
|
26
|
-
constructor(runId: string) {
|
|
27
|
-
super(`Workflow run claim lost: ${runId}`);
|
|
34
|
+
constructor(runId: string, reason: ClaimLostReason = "missingAuthority") {
|
|
35
|
+
super(`Workflow run claim lost (${reason}): ${runId}`);
|
|
28
36
|
this.name = "ClaimLostError";
|
|
29
37
|
this.runId = runId;
|
|
38
|
+
this.reason = reason;
|
|
30
39
|
}
|
|
31
40
|
}
|
|
32
41
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { StateDatabase, workflowStatePath } from "../state/database.js";
|
|
3
3
|
import { resourceIdFor, tokenHash } from "../state/mutation.js";
|
|
4
|
+
import { recordViewerDeltas } from "../state/viewer.js";
|
|
4
5
|
import {
|
|
5
6
|
digestCanonical,
|
|
6
7
|
normalizeDecisionPresentation,
|
|
@@ -451,6 +452,7 @@ export class HumanDecisionStore {
|
|
|
451
452
|
requestHash,
|
|
452
453
|
now,
|
|
453
454
|
);
|
|
455
|
+
recordDecisionViewerChange(this.state, request.runId, request.decisionId, now);
|
|
454
456
|
return "created";
|
|
455
457
|
});
|
|
456
458
|
}
|
|
@@ -473,6 +475,13 @@ export class HumanDecisionStore {
|
|
|
473
475
|
request: HumanDecisionRequest,
|
|
474
476
|
submission: HumanDecisionSubmission,
|
|
475
477
|
): Promise<HumanDecisionAcceptance> {
|
|
478
|
+
return this.acceptSync(request, submission);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
acceptSync(
|
|
482
|
+
request: HumanDecisionRequest,
|
|
483
|
+
submission: HumanDecisionSubmission,
|
|
484
|
+
): HumanDecisionAcceptance {
|
|
476
485
|
validateHumanDecisionRequestIntegrity(request);
|
|
477
486
|
const normalized = validateHumanDecisionSubmission(request, submission);
|
|
478
487
|
const attemptedAt = new Date().toISOString();
|
|
@@ -511,6 +520,10 @@ export class HumanDecisionStore {
|
|
|
511
520
|
request: HumanDecisionRequest,
|
|
512
521
|
now = new Date(),
|
|
513
522
|
): Promise<HumanDecisionAcceptance> {
|
|
523
|
+
return this.resolveTimeoutSync(request, now);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
resolveTimeoutSync(request: HumanDecisionRequest, now = new Date()): HumanDecisionAcceptance {
|
|
514
527
|
validateHumanDecisionRequestIntegrity(request);
|
|
515
528
|
if (request.expiresAt === undefined || request.defaultResponse === undefined) {
|
|
516
529
|
throw new Error("Human decision request has no timeout default");
|
|
@@ -630,6 +643,7 @@ export class HumanDecisionStore {
|
|
|
630
643
|
now,
|
|
631
644
|
);
|
|
632
645
|
this.enqueueResolutionEffects(row.resourceId, row.revision + 1, request, "cancelled", now);
|
|
646
|
+
recordDecisionViewerChange(this.state, request.runId, request.decisionId, now);
|
|
633
647
|
return "created";
|
|
634
648
|
});
|
|
635
649
|
}
|
|
@@ -732,6 +746,22 @@ export class HumanDecisionStore {
|
|
|
732
746
|
return rows.filter(isRequestHashRow).map((row) => this.readRequestFromHash(row.requestHash));
|
|
733
747
|
}
|
|
734
748
|
|
|
749
|
+
async listExpiredDefaultRequests(now = new Date()): Promise<HumanDecisionRequest[]> {
|
|
750
|
+
const timestamp = now.getTime();
|
|
751
|
+
if (!Number.isFinite(timestamp)) throw new Error("Human decision timeout date is invalid");
|
|
752
|
+
const rows = this.state.connection
|
|
753
|
+
.prepare(
|
|
754
|
+
`SELECT h.request_hash AS requestHash
|
|
755
|
+
FROM human_decisions h
|
|
756
|
+
LEFT JOIN human_decision_resolutions r ON r.decision_id = h.decision_id
|
|
757
|
+
WHERE h.deadline_at IS NOT NULL AND h.deadline_at <= ?
|
|
758
|
+
AND h.default_response_hash IS NOT NULL AND r.decision_id IS NULL
|
|
759
|
+
ORDER BY h.deadline_at, h.decision_id`,
|
|
760
|
+
)
|
|
761
|
+
.all(timestamp);
|
|
762
|
+
return rows.filter(isRequestHashRow).map((row) => this.readRequestFromHash(row.requestHash));
|
|
763
|
+
}
|
|
764
|
+
|
|
735
765
|
private attemptAcceptance(
|
|
736
766
|
request: HumanDecisionRequest,
|
|
737
767
|
decision: ResolvedHumanDecision,
|
|
@@ -837,6 +867,7 @@ export class HumanDecisionStore {
|
|
|
837
867
|
);
|
|
838
868
|
this.enqueueResolutionEffects(row.resourceId, row.revision + 1, request, "accepted", now);
|
|
839
869
|
this.markSubmission(request.decisionId, attempt.attemptId, "won", responseHash);
|
|
870
|
+
recordDecisionViewerChange(this.state, request.runId, request.decisionId, now);
|
|
840
871
|
return { status: "accepted", decision };
|
|
841
872
|
});
|
|
842
873
|
}
|
|
@@ -1175,6 +1206,24 @@ export class HumanDecisionStore {
|
|
|
1175
1206
|
}
|
|
1176
1207
|
}
|
|
1177
1208
|
|
|
1209
|
+
function recordDecisionViewerChange(
|
|
1210
|
+
state: StateDatabase,
|
|
1211
|
+
runId: string,
|
|
1212
|
+
decisionId: string,
|
|
1213
|
+
now: number,
|
|
1214
|
+
): void {
|
|
1215
|
+
recordViewerDeltas(
|
|
1216
|
+
state,
|
|
1217
|
+
runId,
|
|
1218
|
+
[
|
|
1219
|
+
{ targetType: "graph" },
|
|
1220
|
+
{ targetType: "replay" },
|
|
1221
|
+
{ targetType: "inspector", targetKey: `decision:${decisionId}` },
|
|
1222
|
+
],
|
|
1223
|
+
now,
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1178
1227
|
function digestBuffer(value: string): Buffer {
|
|
1179
1228
|
const hex = value.startsWith("sha256:") ? value.slice(7) : value;
|
|
1180
1229
|
if (!/^[a-f0-9]{64}$/i.test(hex)) throw new Error("Expected a SHA-256 digest");
|
package/src/workflows/index.ts
CHANGED
package/src/workflows/schema.ts
CHANGED
|
@@ -104,6 +104,24 @@ export function assertValidActionNode(node: ActionNodeDefinition, nodeId = "acti
|
|
|
104
104
|
if (hasExec === hasRun) {
|
|
105
105
|
fail(`node ${nodeId} requires exactly one of run or exec`);
|
|
106
106
|
}
|
|
107
|
+
if (node.effect === undefined || node.effect === null || typeof node.effect !== "object") {
|
|
108
|
+
fail(`node ${nodeId} requires a managed effect`);
|
|
109
|
+
}
|
|
110
|
+
if (typeof node.effect.type !== "string" || node.effect.type.trim().length === 0) {
|
|
111
|
+
fail(`node ${nodeId} effect type must be nonempty text`);
|
|
112
|
+
}
|
|
113
|
+
if (node.effect.recovery !== "idempotent" && node.effect.recovery !== "manual") {
|
|
114
|
+
fail(`node ${nodeId} effect recovery must be idempotent or manual`);
|
|
115
|
+
}
|
|
116
|
+
if (
|
|
117
|
+
typeof node.effect.idempotencyKey !== "string" &&
|
|
118
|
+
typeof node.effect.idempotencyKey !== "function"
|
|
119
|
+
) {
|
|
120
|
+
fail(`node ${nodeId} effect idempotencyKey must be text or a function`);
|
|
121
|
+
}
|
|
122
|
+
if (!("request" in node.effect)) {
|
|
123
|
+
fail(`node ${nodeId} effect requires request data or a request function`);
|
|
124
|
+
}
|
|
107
125
|
if (hasExec) {
|
|
108
126
|
if (typeof node.exec !== "function") {
|
|
109
127
|
fail(`node ${nodeId} exec must be a function`);
|
|
@@ -121,12 +139,7 @@ export function assertValidShellActionNode(
|
|
|
121
139
|
node: ShellActionNodeDefinition,
|
|
122
140
|
nodeId = "shell",
|
|
123
141
|
): void {
|
|
124
|
-
|
|
125
|
-
fail(`node ${nodeId} requires an exec function`);
|
|
126
|
-
}
|
|
127
|
-
assertOptionalFunction(node.parse, `node ${nodeId} parse`);
|
|
128
|
-
assertShellUpdates(node, nodeId);
|
|
129
|
-
assertCommonNodeFields(node, nodeId);
|
|
142
|
+
assertValidActionNode(node, nodeId);
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
function assertShellUpdates(node: ShellActionNodeDefinition, nodeId: string): void {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WorkflowSessionEntryRecord, WorkflowSessionEventRecord } from "
|
|
1
|
+
import type { WorkflowSessionEntryRecord, WorkflowSessionEventRecord } from "./types.js";
|
|
2
2
|
|
|
3
3
|
export type TemporalContentBlock = {
|
|
4
4
|
contentIndex: number;
|
|
@@ -267,6 +267,16 @@ export function reduceSessionEvents(
|
|
|
267
267
|
return foldSessionEvents(entries, events, throughSeq);
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
/** Continue a bounded page fold from a durable replay checkpoint. */
|
|
271
|
+
export function reduceSessionEventsFromCheckpoint(
|
|
272
|
+
entries: WorkflowSessionEntryRecord[],
|
|
273
|
+
events: WorkflowSessionEventRecord[],
|
|
274
|
+
throughSeq: number,
|
|
275
|
+
checkpoint: TemporalSessionState,
|
|
276
|
+
): TemporalSessionState {
|
|
277
|
+
return foldSessionEvents(entries, events, throughSeq, checkpoint);
|
|
278
|
+
}
|
|
279
|
+
|
|
270
280
|
/**
|
|
271
281
|
* In-memory seek index. Checkpoints are viewer-only cache state and are never
|
|
272
282
|
* persisted into a SQLite run state.
|