@code-yeongyu/senpi-agent-core 2026.9.12 → 2026.9.13
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 +4 -0
- package/dist/harness/agent-harness.d.ts +639 -384
- package/dist/harness/agent-harness.d.ts.map +1 -1
- package/dist/harness/agent-harness.js +5 -250
- package/dist/harness/agent-harness.js.map +1 -1
- package/dist/harness/compaction/branch-summarization.d.ts +12 -6
- package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/harness/compaction/branch-summarization.js +33 -27
- package/dist/harness/compaction/branch-summarization.js.map +1 -1
- package/dist/harness/compaction/compaction.d.ts +30 -8
- package/dist/harness/compaction/compaction.d.ts.map +1 -1
- package/dist/harness/compaction/compaction.js +53 -64
- package/dist/harness/compaction/compaction.js.map +1 -1
- package/dist/harness/config.d.ts +9 -0
- package/dist/harness/config.d.ts.map +1 -0
- package/dist/harness/config.js +35 -0
- package/dist/harness/config.js.map +1 -0
- package/dist/harness/context.d.ts +9 -0
- package/dist/harness/context.d.ts.map +1 -0
- package/dist/harness/context.js +13 -0
- package/dist/harness/context.js.map +1 -0
- package/dist/harness/env/nodejs.d.ts +25 -28
- package/dist/harness/env/nodejs.d.ts.map +1 -1
- package/dist/harness/env/nodejs.js +368 -125
- package/dist/harness/env/nodejs.js.map +1 -1
- package/dist/harness/events.d.ts +20 -38
- package/dist/harness/events.d.ts.map +1 -1
- package/dist/harness/events.js +233 -55
- package/dist/harness/events.js.map +1 -1
- package/dist/harness/execution/assistant.d.ts +42 -0
- package/dist/harness/execution/assistant.d.ts.map +1 -0
- package/dist/harness/execution/assistant.js +82 -0
- package/dist/harness/execution/assistant.js.map +1 -0
- package/dist/harness/execution/effect-gate.d.ts +22 -0
- package/dist/harness/execution/effect-gate.d.ts.map +1 -0
- package/dist/harness/execution/effect-gate.js +48 -0
- package/dist/harness/execution/effect-gate.js.map +1 -0
- package/dist/harness/execution/tools.d.ts +67 -0
- package/dist/harness/execution/tools.d.ts.map +1 -0
- package/dist/harness/execution/tools.js +121 -0
- package/dist/harness/execution/tools.js.map +1 -0
- package/dist/harness/hooks.d.ts +38 -0
- package/dist/harness/hooks.d.ts.map +1 -0
- package/dist/harness/hooks.js +404 -0
- package/dist/harness/hooks.js.map +1 -0
- package/dist/harness/messages.d.ts +2 -2
- package/dist/harness/messages.d.ts.map +1 -1
- package/dist/harness/messages.js.map +1 -1
- package/dist/harness/prompt-templates.d.ts +3 -2
- package/dist/harness/prompt-templates.d.ts.map +1 -1
- package/dist/harness/prompt-templates.js +17 -17
- package/dist/harness/prompt-templates.js.map +1 -1
- package/dist/harness/result.d.ts +93 -0
- package/dist/harness/result.d.ts.map +1 -1
- package/dist/harness/result.js +39 -0
- package/dist/harness/result.js.map +1 -1
- package/dist/harness/runtime/drive/boundary.d.ts +28 -0
- package/dist/harness/runtime/drive/boundary.d.ts.map +1 -0
- package/dist/harness/runtime/drive/boundary.js +173 -0
- package/dist/harness/runtime/drive/boundary.js.map +1 -0
- package/dist/harness/runtime/drive/checkpoint.d.ts +8 -0
- package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -0
- package/dist/harness/runtime/drive/checkpoint.js +133 -0
- package/dist/harness/runtime/drive/checkpoint.js.map +1 -0
- package/dist/harness/runtime/drive/deferred.d.ts +15 -0
- package/dist/harness/runtime/drive/deferred.d.ts.map +1 -0
- package/dist/harness/runtime/drive/deferred.js +179 -0
- package/dist/harness/runtime/drive/deferred.js.map +1 -0
- package/dist/harness/runtime/drive/generation.d.ts +8 -0
- package/dist/harness/runtime/drive/generation.d.ts.map +1 -0
- package/dist/harness/runtime/drive/generation.js +205 -0
- package/dist/harness/runtime/drive/generation.js.map +1 -0
- package/dist/harness/runtime/drive/reconcile.d.ts +5 -0
- package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -0
- package/dist/harness/runtime/drive/reconcile.js +140 -0
- package/dist/harness/runtime/drive/reconcile.js.map +1 -0
- package/dist/harness/runtime/drive/recovery.d.ts +8 -0
- package/dist/harness/runtime/drive/recovery.d.ts.map +1 -0
- package/dist/harness/runtime/drive/recovery.js +85 -0
- package/dist/harness/runtime/drive/recovery.js.map +1 -0
- package/dist/harness/runtime/drive/response.d.ts +23 -0
- package/dist/harness/runtime/drive/response.d.ts.map +1 -0
- package/dist/harness/runtime/drive/response.js +394 -0
- package/dist/harness/runtime/drive/response.js.map +1 -0
- package/dist/harness/runtime/drive/retry.d.ts +4 -0
- package/dist/harness/runtime/drive/retry.d.ts.map +1 -0
- package/dist/harness/runtime/drive/retry.js +34 -0
- package/dist/harness/runtime/drive/retry.js.map +1 -0
- package/dist/harness/runtime/drive/structural.d.ts +32 -0
- package/dist/harness/runtime/drive/structural.d.ts.map +1 -0
- package/dist/harness/runtime/drive/structural.js +929 -0
- package/dist/harness/runtime/drive/structural.js.map +1 -0
- package/dist/harness/runtime/drive/terminal.d.ts +7 -0
- package/dist/harness/runtime/drive/terminal.d.ts.map +1 -0
- package/dist/harness/runtime/drive/terminal.js +49 -0
- package/dist/harness/runtime/drive/terminal.js.map +1 -0
- package/dist/harness/runtime/drive/tool-placement.d.ts +14 -0
- package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -0
- package/dist/harness/runtime/drive/tool-placement.js +244 -0
- package/dist/harness/runtime/drive/tool-placement.js.map +1 -0
- package/dist/harness/runtime/drive/tools.d.ts +6 -0
- package/dist/harness/runtime/drive/tools.d.ts.map +1 -0
- package/dist/harness/runtime/drive/tools.js +449 -0
- package/dist/harness/runtime/drive/tools.js.map +1 -0
- package/dist/harness/runtime/drive.d.ts +6 -0
- package/dist/harness/runtime/drive.d.ts.map +1 -0
- package/dist/harness/runtime/drive.js +93 -0
- package/dist/harness/runtime/drive.js.map +1 -0
- package/dist/harness/runtime/harness.d.ts +59 -0
- package/dist/harness/runtime/harness.d.ts.map +1 -0
- package/dist/harness/runtime/harness.js +302 -0
- package/dist/harness/runtime/harness.js.map +1 -0
- package/dist/harness/runtime/index.d.ts +2 -0
- package/dist/harness/runtime/index.d.ts.map +1 -0
- package/dist/harness/runtime/index.js +2 -0
- package/dist/harness/runtime/index.js.map +1 -0
- package/dist/harness/runtime/lane.d.ts +118 -0
- package/dist/harness/runtime/lane.d.ts.map +1 -0
- package/dist/harness/runtime/lane.js +1559 -0
- package/dist/harness/runtime/lane.js.map +1 -0
- package/dist/harness/runtime/progress.d.ts +15 -0
- package/dist/harness/runtime/progress.d.ts.map +1 -0
- package/dist/harness/runtime/progress.js +66 -0
- package/dist/harness/runtime/progress.js.map +1 -0
- package/dist/harness/runtime/reducer.d.ts +5 -0
- package/dist/harness/runtime/reducer.d.ts.map +1 -0
- package/dist/harness/runtime/reducer.js +240 -0
- package/dist/harness/runtime/reducer.js.map +1 -0
- package/dist/harness/runtime/restore.d.ts +24 -0
- package/dist/harness/runtime/restore.d.ts.map +1 -0
- package/dist/harness/runtime/restore.js +117 -0
- package/dist/harness/runtime/restore.js.map +1 -0
- package/dist/harness/runtime/transcript.d.ts +21 -0
- package/dist/harness/runtime/transcript.d.ts.map +1 -0
- package/dist/harness/runtime/transcript.js +72 -0
- package/dist/harness/runtime/transcript.js.map +1 -0
- package/dist/harness/runtime/types.d.ts +105 -0
- package/dist/harness/runtime/types.d.ts.map +1 -0
- package/dist/harness/runtime/types.js +50 -0
- package/dist/harness/runtime/types.js.map +1 -0
- package/dist/harness/session/commit.d.ts +53 -0
- package/dist/harness/session/commit.d.ts.map +1 -0
- package/dist/harness/session/commit.js +57 -0
- package/dist/harness/session/commit.js.map +1 -0
- package/dist/harness/session/context.d.ts +6 -19
- package/dist/harness/session/context.d.ts.map +1 -1
- package/dist/harness/session/context.js +31 -53
- package/dist/harness/session/context.js.map +1 -1
- package/dist/harness/session/fork-policy.d.ts +21 -0
- package/dist/harness/session/fork-policy.d.ts.map +1 -0
- package/dist/harness/session/fork-policy.js +55 -0
- package/dist/harness/session/fork-policy.js.map +1 -0
- package/dist/harness/session/fork.d.ts +16 -0
- package/dist/harness/session/fork.d.ts.map +1 -0
- package/dist/harness/session/fork.js +79 -0
- package/dist/harness/session/fork.js.map +1 -0
- package/dist/harness/session/in-memory-storage-state.d.ts +39 -0
- package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -0
- package/dist/harness/session/in-memory-storage-state.js +269 -0
- package/dist/harness/session/in-memory-storage-state.js.map +1 -0
- package/dist/harness/session/index.d.ts +9 -5
- package/dist/harness/session/index.d.ts.map +1 -1
- package/dist/harness/session/index.js +7 -4
- package/dist/harness/session/index.js.map +1 -1
- package/dist/harness/session/jsonl/codec.d.ts +19 -8
- package/dist/harness/session/jsonl/codec.d.ts.map +1 -1
- package/dist/harness/session/jsonl/codec.js +34 -219
- package/dist/harness/session/jsonl/codec.js.map +1 -1
- package/dist/harness/session/jsonl/fork.d.ts +38 -0
- package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
- package/dist/harness/session/jsonl/fork.js +266 -0
- package/dist/harness/session/jsonl/fork.js.map +1 -0
- package/dist/harness/session/jsonl/index.d.ts +4 -0
- package/dist/harness/session/jsonl/index.d.ts.map +1 -0
- package/dist/harness/session/jsonl/index.js +4 -0
- package/dist/harness/session/jsonl/index.js.map +1 -0
- package/dist/harness/session/jsonl/io.d.ts +14 -0
- package/dist/harness/session/jsonl/io.d.ts.map +1 -0
- package/dist/harness/session/jsonl/io.js +86 -0
- package/dist/harness/session/jsonl/io.js.map +1 -0
- package/dist/harness/session/jsonl/legacy-v3.d.ts +44 -0
- package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
- package/dist/harness/session/jsonl/legacy-v3.js +454 -0
- package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
- package/dist/harness/session/jsonl/repo.d.ts +27 -24
- package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
- package/dist/harness/session/jsonl/repo.js +276 -151
- package/dist/harness/session/jsonl/repo.js.map +1 -1
- package/dist/harness/session/jsonl/storage.d.ts +39 -41
- package/dist/harness/session/jsonl/storage.d.ts.map +1 -1
- package/dist/harness/session/jsonl/storage.js +175 -196
- package/dist/harness/session/jsonl/storage.js.map +1 -1
- package/dist/harness/session/jsonl/types.d.ts +23 -22
- package/dist/harness/session/jsonl/types.d.ts.map +1 -1
- package/dist/harness/session/jsonl/types.js +2 -1
- package/dist/harness/session/jsonl/types.js.map +1 -1
- package/dist/harness/session/memory.d.ts +44 -40
- package/dist/harness/session/memory.d.ts.map +1 -1
- package/dist/harness/session/memory.js +333 -115
- package/dist/harness/session/memory.js.map +1 -1
- package/dist/harness/session/mutation-line.d.ts +8 -0
- package/dist/harness/session/mutation-line.d.ts.map +1 -0
- package/dist/harness/session/mutation-line.js +22 -0
- package/dist/harness/session/mutation-line.js.map +1 -0
- package/dist/harness/session/session.d.ts +78 -51
- package/dist/harness/session/session.d.ts.map +1 -1
- package/dist/harness/session/session.js +327 -207
- package/dist/harness/session/session.js.map +1 -1
- package/dist/harness/session/testing/benchmark/datasets.d.ts +12 -0
- package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -0
- package/dist/harness/session/testing/benchmark/datasets.js +24 -0
- package/dist/harness/session/testing/benchmark/datasets.js.map +1 -0
- package/dist/harness/session/testing/benchmark/session-repo.d.ts +42 -0
- package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -0
- package/dist/harness/session/testing/benchmark/session-repo.js +127 -0
- package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -0
- package/dist/harness/session/testing/benchmark/storage.d.ts +25 -0
- package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -0
- package/dist/harness/session/testing/benchmark/storage.js +114 -0
- package/dist/harness/session/testing/benchmark/storage.js.map +1 -0
- package/dist/harness/session/testing/conformance/session-repo.d.ts +23 -0
- package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
- package/dist/harness/session/testing/conformance/session-repo.js +809 -0
- package/dist/harness/session/testing/conformance/session-repo.js.map +1 -0
- package/dist/harness/session/testing/conformance/storage.d.ts +4 -0
- package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -0
- package/dist/harness/session/testing/conformance/storage.js +600 -0
- package/dist/harness/session/testing/conformance/storage.js.map +1 -0
- package/dist/harness/session/testing/gating-storage.d.ts +26 -0
- package/dist/harness/session/testing/gating-storage.d.ts.map +1 -0
- package/dist/harness/session/testing/gating-storage.js +103 -0
- package/dist/harness/session/testing/gating-storage.js.map +1 -0
- package/dist/harness/session/testing/index.d.ts +9 -2
- package/dist/harness/session/testing/index.d.ts.map +1 -1
- package/dist/harness/session/testing/index.js +8 -1
- package/dist/harness/session/testing/index.js.map +1 -1
- package/dist/harness/session/testing/instrumented-storage.d.ts +11 -0
- package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -0
- package/dist/harness/session/testing/instrumented-storage.js +19 -0
- package/dist/harness/session/testing/instrumented-storage.js.map +1 -0
- package/dist/harness/session/testing/storage-decorator.d.ts +20 -0
- package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -0
- package/dist/harness/session/testing/storage-decorator.js +40 -0
- package/dist/harness/session/testing/storage-decorator.js.map +1 -0
- package/dist/harness/session/testing/types.d.ts +5 -7
- package/dist/harness/session/testing/types.d.ts.map +1 -1
- package/dist/harness/session/testing/types.js.map +1 -1
- package/dist/harness/session/types.d.ts +425 -265
- package/dist/harness/session/types.d.ts.map +1 -1
- package/dist/harness/session/types.js +7 -7
- package/dist/harness/session/types.js.map +1 -1
- package/dist/harness/session/values.d.ts +95 -0
- package/dist/harness/session/values.d.ts.map +1 -0
- package/dist/harness/session/values.js +81 -0
- package/dist/harness/session/values.js.map +1 -0
- package/dist/harness/skills.d.ts +3 -2
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +29 -26
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/telemetry.d.ts +64 -43
- package/dist/harness/telemetry.d.ts.map +1 -1
- package/dist/harness/telemetry.js +45 -26
- package/dist/harness/telemetry.js.map +1 -1
- package/dist/harness/tools/bash.d.ts +4 -4
- package/dist/harness/tools/bash.d.ts.map +1 -1
- package/dist/harness/tools/bash.js +66 -93
- package/dist/harness/tools/bash.js.map +1 -1
- package/dist/harness/tools/edit.d.ts.map +1 -1
- package/dist/harness/tools/edit.js +17 -13
- package/dist/harness/tools/edit.js.map +1 -1
- package/dist/harness/tools/file-mutation-queue.d.ts +2 -1
- package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/harness/tools/file-mutation-queue.js +5 -5
- package/dist/harness/tools/file-mutation-queue.js.map +1 -1
- package/dist/harness/tools/path-utils.d.ts +3 -2
- package/dist/harness/tools/path-utils.d.ts.map +1 -1
- package/dist/harness/tools/path-utils.js +5 -5
- package/dist/harness/tools/path-utils.js.map +1 -1
- package/dist/harness/tools/read.d.ts +2 -1
- package/dist/harness/tools/read.d.ts.map +1 -1
- package/dist/harness/tools/read.js +4 -6
- package/dist/harness/tools/read.js.map +1 -1
- package/dist/harness/tools/write.d.ts.map +1 -1
- package/dist/harness/tools/write.js +12 -8
- package/dist/harness/tools/write.js.map +1 -1
- package/dist/harness/types.d.ts +128 -45
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/utils/adaptive-publisher.d.ts +24 -0
- package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -0
- package/dist/harness/utils/adaptive-publisher.js +79 -0
- package/dist/harness/utils/adaptive-publisher.js.map +1 -0
- package/dist/harness/utils/output-capture.d.ts +31 -0
- package/dist/harness/utils/output-capture.d.ts.map +1 -0
- package/dist/harness/utils/output-capture.js +217 -0
- package/dist/harness/utils/output-capture.js.map +1 -0
- package/dist/harness/utils/shell-output.d.ts +19 -5
- package/dist/harness/utils/shell-output.d.ts.map +1 -1
- package/dist/harness/utils/shell-output.js +65 -192
- package/dist/harness/utils/shell-output.js.map +1 -1
- package/dist/harness/utils/truncate.d.ts +1 -0
- package/dist/harness/utils/truncate.d.ts.map +1 -1
- package/dist/harness/utils/truncate.js +1 -1
- package/dist/harness/utils/truncate.js.map +1 -1
- package/dist/harness/utils/usage.d.ts +4 -0
- package/dist/harness/utils/usage.d.ts.map +1 -0
- package/dist/harness/utils/usage.js +33 -0
- package/dist/harness/utils/usage.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -6
- package/dist/index.js.map +1 -1
- package/dist/search/index.d.ts +24 -16
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -1
- package/dist/search/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +27 -6
- package/dist/harness/reducer.d.ts +0 -100
- package/dist/harness/reducer.d.ts.map +0 -1
- package/dist/harness/reducer.js +0 -420
- package/dist/harness/reducer.js.map +0 -1
- package/dist/harness/session/jsonl/errors.d.ts +0 -9
- package/dist/harness/session/jsonl/errors.d.ts.map +0 -1
- package/dist/harness/session/jsonl/errors.js +0 -18
- package/dist/harness/session/jsonl/errors.js.map +0 -1
- package/dist/harness/session/jsonl.d.ts +0 -3
- package/dist/harness/session/jsonl.d.ts.map +0 -1
- package/dist/harness/session/jsonl.js +0 -2
- package/dist/harness/session/jsonl.js.map +0 -1
- package/dist/harness/session/state.d.ts +0 -65
- package/dist/harness/session/state.d.ts.map +0 -1
- package/dist/harness/session/state.js +0 -320
- package/dist/harness/session/state.js.map +0 -1
- package/dist/harness/session/testing/conformance.d.ts +0 -4
- package/dist/harness/session/testing/conformance.d.ts.map +0 -1
- package/dist/harness/session/testing/conformance.js +0 -762
- package/dist/harness/session/testing/conformance.js.map +0 -1
- package/dist/search/scanning.d.ts +0 -29
- package/dist/search/scanning.d.ts.map +0 -1
- package/dist/search/scanning.js +0 -103
- package/dist/search/scanning.js.map +0 -1
|
@@ -1,230 +1,45 @@
|
|
|
1
1
|
import { err, ok } from "../../types.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
"message",
|
|
5
|
-
"model_change",
|
|
6
|
-
"thinking_level_change",
|
|
7
|
-
"configuration_update",
|
|
8
|
-
"active_tools_change",
|
|
9
|
-
"compaction",
|
|
10
|
-
"branch_summary",
|
|
11
|
-
"custom",
|
|
12
|
-
]);
|
|
13
|
-
const RECORD_TYPES = new Set([
|
|
14
|
-
"operation_started",
|
|
15
|
-
"abort_requested",
|
|
16
|
-
"operation_finished",
|
|
17
|
-
"step_attempt",
|
|
18
|
-
"tool_started",
|
|
19
|
-
"queue_enqueued",
|
|
20
|
-
"queue_cancelled",
|
|
21
|
-
"write_deferred",
|
|
22
|
-
"usage",
|
|
23
|
-
]);
|
|
24
|
-
const OPERATION_KINDS = new Set(["run", "compaction", "navigation"]);
|
|
25
|
-
function isObject(value) {
|
|
2
|
+
import { JSONL_FORMAT_VERSION } from "./types.js";
|
|
3
|
+
function isRecord(value) {
|
|
26
4
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27
5
|
}
|
|
28
|
-
function
|
|
6
|
+
function isSafeIntegerAtLeast(value, minimum) {
|
|
7
|
+
return Number.isSafeInteger(value) && value >= minimum;
|
|
8
|
+
}
|
|
9
|
+
export function isLegacyV3SessionHeader(value) {
|
|
10
|
+
return (isRecord(value) &&
|
|
11
|
+
value.type === "session" &&
|
|
12
|
+
value.version === 3 &&
|
|
13
|
+
typeof value.id === "string" &&
|
|
14
|
+
typeof value.cwd === "string" &&
|
|
15
|
+
typeof value.timestamp === "string" &&
|
|
16
|
+
Number.isFinite(Date.parse(value.timestamp)) &&
|
|
17
|
+
(value.parentSession === undefined || typeof value.parentSession === "string"));
|
|
18
|
+
}
|
|
19
|
+
export function isJsonlStorageHeader(value) {
|
|
20
|
+
return (isRecord(value) &&
|
|
21
|
+
value.kind === "header" &&
|
|
22
|
+
value.v === JSONL_FORMAT_VERSION &&
|
|
23
|
+
typeof value.id === "string" &&
|
|
24
|
+
typeof value.cwd === "string" &&
|
|
25
|
+
isSafeIntegerAtLeast(value.storageVersion, 1) &&
|
|
26
|
+
isSafeIntegerAtLeast(value.createdAt, 0) &&
|
|
27
|
+
(value.nextSeq === undefined || isSafeIntegerAtLeast(value.nextSeq, 1)) &&
|
|
28
|
+
(value.parentSessionId === undefined || typeof value.parentSessionId === "string") &&
|
|
29
|
+
(value.legacyParentSessionPath === undefined || typeof value.legacyParentSessionPath === "string"));
|
|
30
|
+
}
|
|
31
|
+
export function parseJsonlSessionHeader(line) {
|
|
29
32
|
let value;
|
|
30
33
|
try {
|
|
31
34
|
value = JSON.parse(line);
|
|
32
35
|
}
|
|
33
36
|
catch (error) {
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
if (!isObject(value))
|
|
37
|
-
throw new JsonlDecodeError("schema", "is not a JSON object");
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
40
|
-
function requireString(value, field) {
|
|
41
|
-
if (typeof value !== "string")
|
|
42
|
-
throw new JsonlDecodeError("schema", `has invalid ${field}`);
|
|
43
|
-
return value;
|
|
44
|
-
}
|
|
45
|
-
function requireSequence(value) {
|
|
46
|
-
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
47
|
-
throw new JsonlDecodeError("schema", "has invalid seq");
|
|
48
|
-
}
|
|
49
|
-
return value;
|
|
50
|
-
}
|
|
51
|
-
function requireTimestamp(value) {
|
|
52
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
53
|
-
throw new JsonlDecodeError("schema", "has invalid timestamp");
|
|
54
|
-
}
|
|
55
|
-
return value;
|
|
56
|
-
}
|
|
57
|
-
function requireNullableId(value, field) {
|
|
58
|
-
if (value !== null && typeof value !== "string") {
|
|
59
|
-
throw new JsonlDecodeError("schema", `has invalid ${field}`);
|
|
60
|
-
}
|
|
61
|
-
return value;
|
|
62
|
-
}
|
|
63
|
-
function decodeHeader(line) {
|
|
64
|
-
const value = parseObject(line);
|
|
65
|
-
if (value.kind !== "header")
|
|
66
|
-
throw new JsonlDecodeError("schema", "is not a header");
|
|
67
|
-
if (value.version !== 4)
|
|
68
|
-
throw new JsonlDecodeError("schema", "has unsupported session version");
|
|
69
|
-
const parentSessionId = value.parentSessionId;
|
|
70
|
-
if (parentSessionId !== undefined && typeof parentSessionId !== "string") {
|
|
71
|
-
throw new JsonlDecodeError("schema", "has invalid parentSessionId");
|
|
72
|
-
}
|
|
73
|
-
const legacyParentSessionPath = value.legacyParentSessionPath;
|
|
74
|
-
if (legacyParentSessionPath !== undefined && typeof legacyParentSessionPath !== "string") {
|
|
75
|
-
throw new JsonlDecodeError("schema", "has invalid legacyParentSessionPath");
|
|
76
|
-
}
|
|
77
|
-
if (parentSessionId !== undefined && legacyParentSessionPath !== undefined) {
|
|
78
|
-
throw new JsonlDecodeError("schema", "has both parentSessionId and legacyParentSessionPath");
|
|
79
|
-
}
|
|
80
|
-
const metadataValue = value.metadata;
|
|
81
|
-
if (metadataValue !== undefined && !isObject(metadataValue)) {
|
|
82
|
-
throw new JsonlDecodeError("schema", "has invalid metadata");
|
|
83
|
-
}
|
|
84
|
-
const metadata = metadataValue;
|
|
85
|
-
return {
|
|
86
|
-
kind: "header",
|
|
87
|
-
version: 4,
|
|
88
|
-
id: requireString(value.id, "id"),
|
|
89
|
-
createdAt: requireTimestamp(value.createdAt),
|
|
90
|
-
cwd: requireString(value.cwd, "cwd"),
|
|
91
|
-
parentSessionId,
|
|
92
|
-
legacyParentSessionPath,
|
|
93
|
-
metadata,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
export function parseHeader(line) {
|
|
97
|
-
try {
|
|
98
|
-
return ok(decodeHeader(line));
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
if (error instanceof JsonlDecodeError)
|
|
102
|
-
return err(error);
|
|
103
|
-
throw error;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
export function encodeHeader(header) {
|
|
107
|
-
return `${JSON.stringify(header)}\n`;
|
|
108
|
-
}
|
|
109
|
-
export function metadataFromHeader(header, path, modifiedAt) {
|
|
110
|
-
return {
|
|
111
|
-
id: header.id,
|
|
112
|
-
createdAt: header.createdAt,
|
|
113
|
-
cwd: header.cwd,
|
|
114
|
-
path,
|
|
115
|
-
modifiedAt,
|
|
116
|
-
sourceFormat: 4,
|
|
117
|
-
...(header.parentSessionId === undefined ? {} : { parentSessionId: header.parentSessionId }),
|
|
118
|
-
...(header.legacyParentSessionPath === undefined
|
|
119
|
-
? {}
|
|
120
|
-
: { legacyParentSessionPath: header.legacyParentSessionPath }),
|
|
121
|
-
...(header.metadata === undefined ? {} : { metadata: header.metadata }),
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
function parseEntryMutation(value, seq) {
|
|
125
|
-
const lane = value.lane === undefined ? undefined : requireString(value.lane, "lane");
|
|
126
|
-
const id = requireString(value.id, "id");
|
|
127
|
-
const type = requireString(value.type, "entry type");
|
|
128
|
-
if (!ENTRY_TYPES.has(type)) {
|
|
129
|
-
throw new JsonlDecodeError("schema", `has unknown entry type ${type}`);
|
|
130
|
-
}
|
|
131
|
-
const parentId = requireNullableId(value.parentId, "parentId");
|
|
132
|
-
const timestamp = requireTimestamp(value.timestamp);
|
|
133
|
-
if (type === "custom")
|
|
134
|
-
requireString(value.customType, "customType");
|
|
135
|
-
const { kind: _kind, lane: _lane, ...entryFields } = value;
|
|
136
|
-
const entry = { ...entryFields, id, type, parentId, seq, timestamp };
|
|
137
|
-
return lane === undefined ? { kind: "entry", entry } : { kind: "entry", lane, entry };
|
|
138
|
-
}
|
|
139
|
-
function parseRecordMutation(value, seq) {
|
|
140
|
-
const id = requireString(value.id, "id");
|
|
141
|
-
const lane = requireString(value.lane, "lane");
|
|
142
|
-
const type = requireString(value.type, "record type");
|
|
143
|
-
if (!RECORD_TYPES.has(type)) {
|
|
144
|
-
throw new JsonlDecodeError("schema", `has unknown record type ${type}`);
|
|
145
|
-
}
|
|
146
|
-
const timestamp = requireTimestamp(value.timestamp);
|
|
147
|
-
if (type === "operation_started") {
|
|
148
|
-
if (!isObject(value.intent))
|
|
149
|
-
throw new JsonlDecodeError("schema", "has invalid intent");
|
|
150
|
-
const operationKind = requireString(value.intent.kind, "operation kind");
|
|
151
|
-
if (!OPERATION_KINDS.has(operationKind)) {
|
|
152
|
-
throw new JsonlDecodeError("schema", `has unknown operation kind ${operationKind}`);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (type === "operation_finished")
|
|
156
|
-
requireString(value.runId, "runId");
|
|
157
|
-
const { kind: _kind, ...recordFields } = value;
|
|
158
|
-
return {
|
|
159
|
-
kind: "record",
|
|
160
|
-
record: { ...recordFields, id, lane, type, seq, timestamp },
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
function parseLaneMutation(value, seq) {
|
|
164
|
-
return {
|
|
165
|
-
kind: "lane",
|
|
166
|
-
seq,
|
|
167
|
-
lane: requireString(value.lane, "lane"),
|
|
168
|
-
leafId: requireNullableId(value.leafId, "leafId"),
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
function parseFactMutation(value, seq) {
|
|
172
|
-
if (value.fact === "name") {
|
|
173
|
-
if (value.name !== undefined && typeof value.name !== "string") {
|
|
174
|
-
throw new JsonlDecodeError("schema", "has invalid name");
|
|
175
|
-
}
|
|
176
|
-
return { kind: "fact", seq, fact: "name", name: value.name };
|
|
177
|
-
}
|
|
178
|
-
if (value.fact === "label") {
|
|
179
|
-
if (value.label !== undefined && typeof value.label !== "string") {
|
|
180
|
-
throw new JsonlDecodeError("schema", "has invalid label");
|
|
181
|
-
}
|
|
182
|
-
return {
|
|
183
|
-
kind: "fact",
|
|
184
|
-
seq,
|
|
185
|
-
fact: "label",
|
|
186
|
-
targetId: requireString(value.targetId, "targetId"),
|
|
187
|
-
label: value.label,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
throw new JsonlDecodeError("schema", "has unknown fact type");
|
|
191
|
-
}
|
|
192
|
-
function decodeMutation(line) {
|
|
193
|
-
const value = parseObject(line);
|
|
194
|
-
const seq = requireSequence(value.seq);
|
|
195
|
-
switch (value.kind) {
|
|
196
|
-
case "entry":
|
|
197
|
-
return parseEntryMutation(value, seq);
|
|
198
|
-
case "record":
|
|
199
|
-
return parseRecordMutation(value, seq);
|
|
200
|
-
case "lane":
|
|
201
|
-
return parseLaneMutation(value, seq);
|
|
202
|
-
case "fact":
|
|
203
|
-
return parseFactMutation(value, seq);
|
|
204
|
-
default:
|
|
205
|
-
throw new JsonlDecodeError("schema", "has unknown mutation kind");
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
export function parseMutation(line) {
|
|
209
|
-
try {
|
|
210
|
-
return ok(decodeMutation(line));
|
|
211
|
-
}
|
|
212
|
-
catch (error) {
|
|
213
|
-
if (error instanceof JsonlDecodeError)
|
|
214
|
-
return err(error);
|
|
215
|
-
throw error;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
export function encodeMutation(mutation) {
|
|
219
|
-
switch (mutation.kind) {
|
|
220
|
-
case "entry":
|
|
221
|
-
return `${JSON.stringify({ kind: "entry", lane: mutation.lane, ...mutation.entry })}\n`;
|
|
222
|
-
case "record":
|
|
223
|
-
return `${JSON.stringify({ kind: "record", ...mutation.record })}\n`;
|
|
224
|
-
case "lane":
|
|
225
|
-
return `${JSON.stringify(mutation)}\n`;
|
|
226
|
-
case "fact":
|
|
227
|
-
return `${JSON.stringify(mutation)}\n`;
|
|
37
|
+
return err(new Error("Invalid JSONL session header: not valid JSON", { cause: error }));
|
|
228
38
|
}
|
|
39
|
+
if (isJsonlStorageHeader(value))
|
|
40
|
+
return ok({ format: "v4", header: value });
|
|
41
|
+
if (isLegacyV3SessionHeader(value))
|
|
42
|
+
return ok({ format: "v3-legacy", header: value });
|
|
43
|
+
return err(new Error("Unsupported JSONL session header"));
|
|
229
44
|
}
|
|
230
45
|
//# sourceMappingURL=codec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/codec.ts"],"names":[],"mappings":"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","sourcesContent":["import { err, ok, type Result } from \"../../types.ts\";\nimport type { SessionMutation } from \"../state.ts\";\nimport type { Entry, LaneRecord } from \"../types.ts\";\nimport { JsonlDecodeError } from \"./errors.ts\";\nimport type { JsonlSessionMetadata, JsonlV4Header } from \"./types.ts\";\n\nconst ENTRY_TYPES = new Set<Entry[\"type\"]>([\n\t\"message\",\n\t\"model_change\",\n\t\"thinking_level_change\",\n\t\"configuration_update\",\n\t\"active_tools_change\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t\"custom\",\n]);\nconst RECORD_TYPES = new Set<LaneRecord[\"type\"]>([\n\t\"operation_started\",\n\t\"abort_requested\",\n\t\"operation_finished\",\n\t\"step_attempt\",\n\t\"tool_started\",\n\t\"queue_enqueued\",\n\t\"queue_cancelled\",\n\t\"write_deferred\",\n\t\"usage\",\n]);\nconst OPERATION_KINDS = new Set([\"run\", \"compaction\", \"navigation\"]);\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseObject(line: string): Record<string, unknown> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(line);\n\t} catch (error) {\n\t\tthrow new JsonlDecodeError(\"syntax\", \"is not valid JSON\", error instanceof Error ? error : undefined);\n\t}\n\tif (!isObject(value)) throw new JsonlDecodeError(\"schema\", \"is not a JSON object\");\n\treturn value;\n}\n\nfunction requireString(value: unknown, field: string): string {\n\tif (typeof value !== \"string\") throw new JsonlDecodeError(\"schema\", `has invalid ${field}`);\n\treturn value;\n}\n\nfunction requireSequence(value: unknown): number {\n\tif (!Number.isSafeInteger(value) || (value as number) <= 0) {\n\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid seq\");\n\t}\n\treturn value as number;\n}\n\nfunction requireTimestamp(value: unknown): number {\n\tif (!Number.isSafeInteger(value) || (value as number) < 0) {\n\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid timestamp\");\n\t}\n\treturn value as number;\n}\n\nfunction requireNullableId(value: unknown, field: string): string | null {\n\tif (value !== null && typeof value !== \"string\") {\n\t\tthrow new JsonlDecodeError(\"schema\", `has invalid ${field}`);\n\t}\n\treturn value as string | null;\n}\n\nfunction decodeHeader(line: string): JsonlV4Header {\n\tconst value = parseObject(line);\n\tif (value.kind !== \"header\") throw new JsonlDecodeError(\"schema\", \"is not a header\");\n\tif (value.version !== 4) throw new JsonlDecodeError(\"schema\", \"has unsupported session version\");\n\tconst parentSessionId = value.parentSessionId;\n\tif (parentSessionId !== undefined && typeof parentSessionId !== \"string\") {\n\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid parentSessionId\");\n\t}\n\tconst legacyParentSessionPath = value.legacyParentSessionPath;\n\tif (legacyParentSessionPath !== undefined && typeof legacyParentSessionPath !== \"string\") {\n\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid legacyParentSessionPath\");\n\t}\n\tif (parentSessionId !== undefined && legacyParentSessionPath !== undefined) {\n\t\tthrow new JsonlDecodeError(\"schema\", \"has both parentSessionId and legacyParentSessionPath\");\n\t}\n\tconst metadataValue = value.metadata;\n\tif (metadataValue !== undefined && !isObject(metadataValue)) {\n\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid metadata\");\n\t}\n\tconst metadata = metadataValue as JsonlV4Header[\"metadata\"];\n\treturn {\n\t\tkind: \"header\",\n\t\tversion: 4,\n\t\tid: requireString(value.id, \"id\"),\n\t\tcreatedAt: requireTimestamp(value.createdAt),\n\t\tcwd: requireString(value.cwd, \"cwd\"),\n\t\tparentSessionId,\n\t\tlegacyParentSessionPath,\n\t\tmetadata,\n\t};\n}\n\nexport function parseHeader(line: string): Result<JsonlV4Header, JsonlDecodeError> {\n\ttry {\n\t\treturn ok<JsonlV4Header, JsonlDecodeError>(decodeHeader(line));\n\t} catch (error) {\n\t\tif (error instanceof JsonlDecodeError) return err<JsonlV4Header, JsonlDecodeError>(error);\n\t\tthrow error;\n\t}\n}\n\nexport function encodeHeader(header: JsonlV4Header): string {\n\treturn `${JSON.stringify(header)}\\n`;\n}\n\nexport function metadataFromHeader(header: JsonlV4Header, path: string, modifiedAt: number): JsonlSessionMetadata {\n\treturn {\n\t\tid: header.id,\n\t\tcreatedAt: header.createdAt,\n\t\tcwd: header.cwd,\n\t\tpath,\n\t\tmodifiedAt,\n\t\tsourceFormat: 4,\n\t\t...(header.parentSessionId === undefined ? {} : { parentSessionId: header.parentSessionId }),\n\t\t...(header.legacyParentSessionPath === undefined\n\t\t\t? {}\n\t\t\t: { legacyParentSessionPath: header.legacyParentSessionPath }),\n\t\t...(header.metadata === undefined ? {} : { metadata: header.metadata }),\n\t};\n}\n\nfunction parseEntryMutation(value: Record<string, unknown>, seq: number): Extract<SessionMutation, { kind: \"entry\" }> {\n\tconst lane = value.lane === undefined ? undefined : requireString(value.lane, \"lane\");\n\tconst id = requireString(value.id, \"id\");\n\tconst type = requireString(value.type, \"entry type\");\n\tif (!ENTRY_TYPES.has(type as Entry[\"type\"])) {\n\t\tthrow new JsonlDecodeError(\"schema\", `has unknown entry type ${type}`);\n\t}\n\tconst parentId = requireNullableId(value.parentId, \"parentId\");\n\tconst timestamp = requireTimestamp(value.timestamp);\n\tif (type === \"custom\") requireString(value.customType, \"customType\");\n\tconst { kind: _kind, lane: _lane, ...entryFields } = value;\n\tconst entry = { ...entryFields, id, type, parentId, seq, timestamp } as unknown as Entry;\n\treturn lane === undefined ? { kind: \"entry\", entry } : { kind: \"entry\", lane, entry };\n}\n\nfunction parseRecordMutation(\n\tvalue: Record<string, unknown>,\n\tseq: number,\n): Extract<SessionMutation, { kind: \"record\" }> {\n\tconst id = requireString(value.id, \"id\");\n\tconst lane = requireString(value.lane, \"lane\");\n\tconst type = requireString(value.type, \"record type\");\n\tif (!RECORD_TYPES.has(type as LaneRecord[\"type\"])) {\n\t\tthrow new JsonlDecodeError(\"schema\", `has unknown record type ${type}`);\n\t}\n\tconst timestamp = requireTimestamp(value.timestamp);\n\tif (type === \"operation_started\") {\n\t\tif (!isObject(value.intent)) throw new JsonlDecodeError(\"schema\", \"has invalid intent\");\n\t\tconst operationKind = requireString(value.intent.kind, \"operation kind\");\n\t\tif (!OPERATION_KINDS.has(operationKind)) {\n\t\t\tthrow new JsonlDecodeError(\"schema\", `has unknown operation kind ${operationKind}`);\n\t\t}\n\t}\n\tif (type === \"operation_finished\") requireString(value.runId, \"runId\");\n\tconst { kind: _kind, ...recordFields } = value;\n\treturn {\n\t\tkind: \"record\",\n\t\trecord: { ...recordFields, id, lane, type, seq, timestamp } as unknown as LaneRecord,\n\t};\n}\n\nfunction parseLaneMutation(value: Record<string, unknown>, seq: number): Extract<SessionMutation, { kind: \"lane\" }> {\n\treturn {\n\t\tkind: \"lane\",\n\t\tseq,\n\t\tlane: requireString(value.lane, \"lane\"),\n\t\tleafId: requireNullableId(value.leafId, \"leafId\"),\n\t};\n}\n\nfunction parseFactMutation(value: Record<string, unknown>, seq: number): Extract<SessionMutation, { kind: \"fact\" }> {\n\tif (value.fact === \"name\") {\n\t\tif (value.name !== undefined && typeof value.name !== \"string\") {\n\t\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid name\");\n\t\t}\n\t\treturn { kind: \"fact\", seq, fact: \"name\", name: value.name };\n\t}\n\tif (value.fact === \"label\") {\n\t\tif (value.label !== undefined && typeof value.label !== \"string\") {\n\t\t\tthrow new JsonlDecodeError(\"schema\", \"has invalid label\");\n\t\t}\n\t\treturn {\n\t\t\tkind: \"fact\",\n\t\t\tseq,\n\t\t\tfact: \"label\",\n\t\t\ttargetId: requireString(value.targetId, \"targetId\"),\n\t\t\tlabel: value.label,\n\t\t};\n\t}\n\tthrow new JsonlDecodeError(\"schema\", \"has unknown fact type\");\n}\n\nfunction decodeMutation(line: string): SessionMutation {\n\tconst value = parseObject(line);\n\tconst seq = requireSequence(value.seq);\n\tswitch (value.kind) {\n\t\tcase \"entry\":\n\t\t\treturn parseEntryMutation(value, seq);\n\t\tcase \"record\":\n\t\t\treturn parseRecordMutation(value, seq);\n\t\tcase \"lane\":\n\t\t\treturn parseLaneMutation(value, seq);\n\t\tcase \"fact\":\n\t\t\treturn parseFactMutation(value, seq);\n\t\tdefault:\n\t\t\tthrow new JsonlDecodeError(\"schema\", \"has unknown mutation kind\");\n\t}\n}\n\nexport function parseMutation(line: string): Result<SessionMutation, JsonlDecodeError> {\n\ttry {\n\t\treturn ok<SessionMutation, JsonlDecodeError>(decodeMutation(line));\n\t} catch (error) {\n\t\tif (error instanceof JsonlDecodeError) return err<SessionMutation, JsonlDecodeError>(error);\n\t\tthrow error;\n\t}\n}\n\nexport function encodeMutation(mutation: SessionMutation): string {\n\tswitch (mutation.kind) {\n\t\tcase \"entry\":\n\t\t\treturn `${JSON.stringify({ kind: \"entry\", lane: mutation.lane, ...mutation.entry })}\\n`;\n\t\tcase \"record\":\n\t\t\treturn `${JSON.stringify({ kind: \"record\", ...mutation.record })}\\n`;\n\t\tcase \"lane\":\n\t\t\treturn `${JSON.stringify(mutation)}\\n`;\n\t\tcase \"fact\":\n\t\t\treturn `${JSON.stringify(mutation)}\\n`;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAA2B,MAAM,YAAY,CAAC;AAW3E,SAAS,QAAQ,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc,EAAE,OAAe;IAC5D,OAAO,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAK,KAAgB,IAAI,OAAO,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACrD,OAAO,CACN,QAAQ,CAAC,KAAK,CAAC;QACf,KAAK,CAAC,IAAI,KAAK,SAAS;QACxB,KAAK,CAAC,OAAO,KAAK,CAAC;QACnB,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;QAC5B,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QAC7B,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;QACnC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC,KAAK,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,aAAa,KAAK,QAAQ,CAAC,CAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc;IAClD,OAAO,CACN,QAAQ,CAAC,KAAK,CAAC;QACf,KAAK,CAAC,IAAI,KAAK,QAAQ;QACvB,KAAK,CAAC,CAAC,KAAK,oBAAoB;QAChC,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;QAC5B,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QAC7B,oBAAoB,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;QAC7C,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;QACxC,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,oBAAoB,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvE,CAAC,KAAK,CAAC,eAAe,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,eAAe,KAAK,QAAQ,CAAC;QAClF,CAAC,KAAK,CAAC,uBAAuB,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,uBAAuB,KAAK,QAAQ,CAAC,CAClG,CAAC;AACH,CAAC;AAMD,MAAM,UAAU,uBAAuB,CAAC,IAAY;IACnD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACJ,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC,8CAA8C,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACzF,CAAC;IACD,IAAI,oBAAoB,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5E,IAAI,uBAAuB,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACtF,OAAO,GAAG,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["import { err, ok, type Result } from \"../../types.ts\";\nimport { JSONL_FORMAT_VERSION, type JsonlStorageHeader } from \"./types.ts\";\n\nexport interface LegacyV3SessionHeader {\n\ttype: \"session\";\n\tversion: 3;\n\tid: string;\n\ttimestamp: string;\n\tcwd: string;\n\tparentSession?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isSafeIntegerAtLeast(value: unknown, minimum: number): value is number {\n\treturn Number.isSafeInteger(value) && (value as number) >= minimum;\n}\n\nexport function isLegacyV3SessionHeader(value: unknown): value is LegacyV3SessionHeader {\n\treturn (\n\t\tisRecord(value) &&\n\t\tvalue.type === \"session\" &&\n\t\tvalue.version === 3 &&\n\t\ttypeof value.id === \"string\" &&\n\t\ttypeof value.cwd === \"string\" &&\n\t\ttypeof value.timestamp === \"string\" &&\n\t\tNumber.isFinite(Date.parse(value.timestamp)) &&\n\t\t(value.parentSession === undefined || typeof value.parentSession === \"string\")\n\t);\n}\n\nexport function isJsonlStorageHeader(value: unknown): value is JsonlStorageHeader {\n\treturn (\n\t\tisRecord(value) &&\n\t\tvalue.kind === \"header\" &&\n\t\tvalue.v === JSONL_FORMAT_VERSION &&\n\t\ttypeof value.id === \"string\" &&\n\t\ttypeof value.cwd === \"string\" &&\n\t\tisSafeIntegerAtLeast(value.storageVersion, 1) &&\n\t\tisSafeIntegerAtLeast(value.createdAt, 0) &&\n\t\t(value.nextSeq === undefined || isSafeIntegerAtLeast(value.nextSeq, 1)) &&\n\t\t(value.parentSessionId === undefined || typeof value.parentSessionId === \"string\") &&\n\t\t(value.legacyParentSessionPath === undefined || typeof value.legacyParentSessionPath === \"string\")\n\t);\n}\n\nexport type JsonlParsedSessionHeader =\n\t| { format: \"v4\"; header: JsonlStorageHeader }\n\t| { format: \"v3-legacy\"; header: LegacyV3SessionHeader };\n\nexport function parseJsonlSessionHeader(line: string): Result<JsonlParsedSessionHeader, Error> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(line);\n\t} catch (error) {\n\t\treturn err(new Error(\"Invalid JSONL session header: not valid JSON\", { cause: error }));\n\t}\n\tif (isJsonlStorageHeader(value)) return ok({ format: \"v4\", header: value });\n\tif (isLegacyV3SessionHeader(value)) return ok({ format: \"v3-legacy\", header: value });\n\treturn err(new Error(\"Unsupported JSONL session header\"));\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Context } from "../../context.ts";
|
|
2
|
+
import type { FileSystem } from "../../types.ts";
|
|
3
|
+
import type { ForkOptions } from "../types.ts";
|
|
4
|
+
import type { LegacyV3Source } from "./legacy-v3.ts";
|
|
5
|
+
import { type JsonlStorageHeader } from "./types.ts";
|
|
6
|
+
interface JsonlForkSourceMetadata {
|
|
7
|
+
id: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
path: string;
|
|
10
|
+
}
|
|
11
|
+
/** Prepared fork input: format-4 file metadata or an already-normalized legacy source. */
|
|
12
|
+
export type JsonlForkInput = {
|
|
13
|
+
kind: "open";
|
|
14
|
+
metadata: JsonlForkSourceMetadata;
|
|
15
|
+
nextSeq: number;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "closed";
|
|
18
|
+
metadata: JsonlForkSourceMetadata;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "legacy-v3";
|
|
21
|
+
normalized: LegacyV3Source;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Index the source, validate the requested fork, and stream selected entries and current state
|
|
25
|
+
* into an atomically published format-4 destination without modifying the source.
|
|
26
|
+
* Preserve copied sequences and the source's nextSeq while excluding usage and open-operation state.
|
|
27
|
+
* Source files must not be replaced or edited between passes; later append-only writes are excluded
|
|
28
|
+
* by the captured sequence boundary or legacy record count. Does not open the destination Session.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runJsonlFork(options: {
|
|
31
|
+
input: JsonlForkInput;
|
|
32
|
+
fileSystem: FileSystem;
|
|
33
|
+
destinationPath: string;
|
|
34
|
+
destinationHeader: Omit<JsonlStorageHeader, "nextSeq">;
|
|
35
|
+
fork: ForkOptions;
|
|
36
|
+
}, context: Context): Promise<void>;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=fork.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fork.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/fork.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,gBAAgB,CAAC;AAQjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE5E,UAAU,uBAAuB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACb;AA4LD,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,cAAc,CAAA;CAAE,CAAC;AA6ErD;;;;;;GAMG;AACH,wBAAsB,YAAY,CACjC,OAAO,EAAE;IACR,KAAK,EAAE,cAAc,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,EAAE,WAAW,CAAC;CAClB,EACD,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { projectForkCurrentStateWrite, selectBranchFork } from "../fork-policy.js";
|
|
2
|
+
import { fileValue, parseJsonlTransaction, publishJsonl, readJsonlHeader } from "./io.js";
|
|
3
|
+
import { JSONL_STORAGE_VERSION } from "./types.js";
|
|
4
|
+
function physicalKey(namespace, key) {
|
|
5
|
+
return `${namespace}\u0000${key}`;
|
|
6
|
+
}
|
|
7
|
+
async function readJsonlForkHeader(reader, source, context) {
|
|
8
|
+
const parsed = await readJsonlHeader(reader, source.path, context);
|
|
9
|
+
if (parsed.format !== "v4") {
|
|
10
|
+
throw new Error(`Invalid JSONL storage ${source.path}: expected format 4 header`);
|
|
11
|
+
}
|
|
12
|
+
const header = parsed.header;
|
|
13
|
+
if (header.id !== source.id || header.cwd !== source.cwd) {
|
|
14
|
+
throw new Error(`Session identity does not match header: ${source.id}`);
|
|
15
|
+
}
|
|
16
|
+
if (header.storageVersion !== JSONL_STORAGE_VERSION) {
|
|
17
|
+
throw new Error(`Session ${source.id} uses unsupported storage version ${header.storageVersion}`);
|
|
18
|
+
}
|
|
19
|
+
return header;
|
|
20
|
+
}
|
|
21
|
+
function reachesForkBoundary(writes, stopBeforeSeq) {
|
|
22
|
+
if (stopBeforeSeq === undefined || writes.length === 0)
|
|
23
|
+
return false;
|
|
24
|
+
const first = writes[0];
|
|
25
|
+
const last = writes.at(-1);
|
|
26
|
+
if (first.seq >= stopBeforeSeq)
|
|
27
|
+
return true;
|
|
28
|
+
if (last.seq >= stopBeforeSeq) {
|
|
29
|
+
throw new Error(`JSONL transaction crosses fork sequence boundary ${stopBeforeSeq}`);
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
/** Read complete transactions after the header, never splitting a transaction at the sequence boundary. */
|
|
34
|
+
async function* readJsonlForkTransactions(reader, path, stopBeforeSeq, context) {
|
|
35
|
+
while (true) {
|
|
36
|
+
const line = fileValue(await reader.readLine(context), `Failed to read JSONL fork source ${path}`);
|
|
37
|
+
if (line === undefined || !line.terminated)
|
|
38
|
+
break;
|
|
39
|
+
const writes = parseJsonlTransaction(line.text);
|
|
40
|
+
if (reachesForkBoundary(writes, stopBeforeSeq))
|
|
41
|
+
break;
|
|
42
|
+
yield writes;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
class JsonlForkIndex {
|
|
46
|
+
constructor() {
|
|
47
|
+
this.currentScalarSeqs = new Map();
|
|
48
|
+
this.branchTips = new Map();
|
|
49
|
+
this.firstSurvivingListSeqs = new Map();
|
|
50
|
+
this.entryParents = new Map();
|
|
51
|
+
this.copiedEntryIds = new Set();
|
|
52
|
+
this.laneConfigs = new Set();
|
|
53
|
+
this.laneStates = new Set();
|
|
54
|
+
}
|
|
55
|
+
applyEntry(id, parentId) {
|
|
56
|
+
this.entryParents.set(id, parentId);
|
|
57
|
+
}
|
|
58
|
+
applyWrites(writes) {
|
|
59
|
+
for (const write of writes) {
|
|
60
|
+
switch (write.kind) {
|
|
61
|
+
case "entry":
|
|
62
|
+
this.applyEntry(write.id, write.parentId);
|
|
63
|
+
break;
|
|
64
|
+
case "value": {
|
|
65
|
+
const key = physicalKey(write.namespace, write.key);
|
|
66
|
+
if (write.op === "delete") {
|
|
67
|
+
this.currentScalarSeqs.delete(key);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.currentScalarSeqs.set(key, write.seq);
|
|
71
|
+
}
|
|
72
|
+
this.applyLaneValue(write);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case "list": {
|
|
76
|
+
const key = physicalKey(write.namespace, write.key);
|
|
77
|
+
if (write.op === "delete")
|
|
78
|
+
this.firstSurvivingListSeqs.delete(key);
|
|
79
|
+
else if (!this.firstSurvivingListSeqs.has(key))
|
|
80
|
+
this.firstSurvivingListSeqs.set(key, write.seq);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case "usage":
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
applyLaneValue(write) {
|
|
89
|
+
const present = write.op === "set";
|
|
90
|
+
switch (write.namespace) {
|
|
91
|
+
case "pi.branch.tip":
|
|
92
|
+
if (present)
|
|
93
|
+
this.branchTips.set(write.key, write.value);
|
|
94
|
+
else
|
|
95
|
+
this.branchTips.delete(write.key);
|
|
96
|
+
break;
|
|
97
|
+
case "pi.lane.config":
|
|
98
|
+
if (present)
|
|
99
|
+
this.laneConfigs.add(write.key);
|
|
100
|
+
else
|
|
101
|
+
this.laneConfigs.delete(write.key);
|
|
102
|
+
break;
|
|
103
|
+
case "pi.lane.state":
|
|
104
|
+
if (present)
|
|
105
|
+
this.laneStates.add(write.key);
|
|
106
|
+
else
|
|
107
|
+
this.laneStates.delete(write.key);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getBranchTip(branch) {
|
|
112
|
+
return this.branchTips.get(branch);
|
|
113
|
+
}
|
|
114
|
+
hasCompleteLane(branch) {
|
|
115
|
+
return this.laneConfigs.has(branch) && this.laneStates.has(branch);
|
|
116
|
+
}
|
|
117
|
+
getCurrentScalarSeq(namespace, key) {
|
|
118
|
+
return this.currentScalarSeqs.get(physicalKey(namespace, key));
|
|
119
|
+
}
|
|
120
|
+
isSurvivingListElement(namespace, key, seq) {
|
|
121
|
+
const firstSeq = this.firstSurvivingListSeqs.get(physicalKey(namespace, key));
|
|
122
|
+
return firstSeq !== undefined && seq >= firstSeq;
|
|
123
|
+
}
|
|
124
|
+
getParent(entryId) {
|
|
125
|
+
return this.entryParents.get(entryId);
|
|
126
|
+
}
|
|
127
|
+
selectEntry(entryId) {
|
|
128
|
+
this.copiedEntryIds.add(entryId);
|
|
129
|
+
}
|
|
130
|
+
isEntrySelected(entryId) {
|
|
131
|
+
return this.copiedEntryIds.has(entryId);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Validate the source lanes and return the fork plan.
|
|
136
|
+
*
|
|
137
|
+
* Branch scope updates JsonlForkIndex's selected entries via index.selectEntry(): it selects the
|
|
138
|
+
* destination tip and its ancestors after validating entryId and applying "at"/"before". The plan
|
|
139
|
+
* records the branch name and destination tip; the copy pass uses the index to filter entries and labels.
|
|
140
|
+
*
|
|
141
|
+
* Tree scope leaves the index's selected entries unchanged because the copy pass keeps every entry.
|
|
142
|
+
* Both formats use the same indexed metadata; this function performs no file I/O.
|
|
143
|
+
*/
|
|
144
|
+
function selectJsonlFork(index, options) {
|
|
145
|
+
if (options.scope === "tree")
|
|
146
|
+
return { scope: "tree" };
|
|
147
|
+
const plan = selectBranchFork(options, {
|
|
148
|
+
tip: index.getBranchTip(options.branch),
|
|
149
|
+
getParent: (entryId) => index.getParent(entryId),
|
|
150
|
+
selectEntry: (entryId) => index.selectEntry(entryId),
|
|
151
|
+
});
|
|
152
|
+
if (!index.hasCompleteLane(options.branch)) {
|
|
153
|
+
throw new Error(`Source branch ${JSON.stringify(options.branch)} is not a configured AgentLane`);
|
|
154
|
+
}
|
|
155
|
+
return plan;
|
|
156
|
+
}
|
|
157
|
+
function projectJsonlForkWrite(write, index, plan, isEntryCopied) {
|
|
158
|
+
switch (write.kind) {
|
|
159
|
+
case "entry":
|
|
160
|
+
return isEntryCopied(write.id) ? write : undefined;
|
|
161
|
+
case "value":
|
|
162
|
+
if (write.op !== "set")
|
|
163
|
+
return undefined;
|
|
164
|
+
if (index.getCurrentScalarSeq(write.namespace, write.key) !== write.seq)
|
|
165
|
+
return undefined;
|
|
166
|
+
return projectForkCurrentStateWrite(write, plan, isEntryCopied);
|
|
167
|
+
case "list":
|
|
168
|
+
if (write.op !== "append")
|
|
169
|
+
return undefined;
|
|
170
|
+
if (!index.isSurvivingListElement(write.namespace, write.key, write.seq))
|
|
171
|
+
return undefined;
|
|
172
|
+
return projectForkCurrentStateWrite(write, plan, isEntryCopied);
|
|
173
|
+
case "usage":
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Build the index used to select branch ancestry and identify current scalar/list writes.
|
|
179
|
+
* Retains entry parent links, current-row sequences, and lane inventory, not entry payloads.
|
|
180
|
+
* Returns the index and the source's nextSeq high-water mark; no destination writes occur here.
|
|
181
|
+
*
|
|
182
|
+
* V3: LegacyV3Source already scanned the file and assigned normalized IDs/sequences. Copy its
|
|
183
|
+
* in-memory entry structures and derived values without reopening the file or calling writes(),
|
|
184
|
+
* which would unnecessarily parse payloads and reconstruct compaction tails before fork selection.
|
|
185
|
+
*
|
|
186
|
+
* V4: Open the source file and fold complete transactions into the index. For an open source,
|
|
187
|
+
* stop at the captured commit-queue sequence boundary. For a closed source, scan to EOF or a torn
|
|
188
|
+
* final line and derive nextSeq from the header and highest complete write sequence.
|
|
189
|
+
* The later copy pass reopens the source file in both formats and emits only selected writes.
|
|
190
|
+
*/
|
|
191
|
+
async function indexForkInput(input, fileSystem, context) {
|
|
192
|
+
const index = new JsonlForkIndex();
|
|
193
|
+
if (input.kind === "legacy-v3") {
|
|
194
|
+
for (const entry of input.normalized.entryStructures())
|
|
195
|
+
index.applyEntry(entry.id, entry.parentId);
|
|
196
|
+
index.applyWrites(input.normalized.values);
|
|
197
|
+
return { index, nextSeq: input.normalized.nextSeq };
|
|
198
|
+
}
|
|
199
|
+
const reader = fileValue(await fileSystem.openTextLineReader(input.metadata.path, context), `Failed to open JSONL fork source ${input.metadata.path}`);
|
|
200
|
+
try {
|
|
201
|
+
const header = await readJsonlForkHeader(reader, input.metadata, context);
|
|
202
|
+
const stopBeforeSeq = input.kind === "open" ? input.nextSeq : undefined;
|
|
203
|
+
let highestCompleteSeq = 0;
|
|
204
|
+
for await (const writes of readJsonlForkTransactions(reader, input.metadata.path, stopBeforeSeq, context)) {
|
|
205
|
+
index.applyWrites(writes);
|
|
206
|
+
if (writes.length !== 0)
|
|
207
|
+
highestCompleteSeq = writes.at(-1).seq;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
index,
|
|
211
|
+
nextSeq: input.kind === "open" ? input.nextSeq : Math.max(header.nextSeq ?? 1, highestCompleteSeq + 1),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
await reader.close(context);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/** Yield source writes; the caller owns final projection and filtering. */
|
|
219
|
+
async function* streamForkWrites(input, fileSystem, stopBeforeSeq, isEntryCopied, context) {
|
|
220
|
+
if (input.kind === "legacy-v3") {
|
|
221
|
+
// V3 filters early to avoid rereading messages and reconstructing unselected compaction tails.
|
|
222
|
+
// V4 already stores complete payloads, so it streams all captured writes below.
|
|
223
|
+
// Both formats still pass through projectJsonlForkWrite() for final filtering and transformation.
|
|
224
|
+
yield* input.normalized.writes(context, isEntryCopied);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const reader = fileValue(await fileSystem.openTextLineReader(input.metadata.path, context), `Failed to open JSONL fork source ${input.metadata.path}`);
|
|
228
|
+
try {
|
|
229
|
+
await readJsonlForkHeader(reader, input.metadata, context);
|
|
230
|
+
for await (const writes of readJsonlForkTransactions(reader, input.metadata.path, stopBeforeSeq, context)) {
|
|
231
|
+
yield* writes;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
await reader.close(context);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Index the source, validate the requested fork, and stream selected entries and current state
|
|
240
|
+
* into an atomically published format-4 destination without modifying the source.
|
|
241
|
+
* Preserve copied sequences and the source's nextSeq while excluding usage and open-operation state.
|
|
242
|
+
* Source files must not be replaced or edited between passes; later append-only writes are excluded
|
|
243
|
+
* by the captured sequence boundary or legacy record count. Does not open the destination Session.
|
|
244
|
+
*/
|
|
245
|
+
export async function runJsonlFork(options, context) {
|
|
246
|
+
const { index, nextSeq } = await indexForkInput(options.input, options.fileSystem, context);
|
|
247
|
+
let fork = options.fork;
|
|
248
|
+
if (options.input.kind === "legacy-v3" && fork.scope === "branch" && fork.entryId !== undefined) {
|
|
249
|
+
fork = { ...fork, entryId: options.input.normalized.translateForkEntryId(fork.entryId) };
|
|
250
|
+
}
|
|
251
|
+
const plan = selectJsonlFork(index, fork);
|
|
252
|
+
const isEntryCopied = (entryId) => {
|
|
253
|
+
if (plan.scope === "tree")
|
|
254
|
+
return true;
|
|
255
|
+
return index.isEntrySelected(entryId);
|
|
256
|
+
};
|
|
257
|
+
await publishJsonl(options.fileSystem, options.destinationPath, { ...options.destinationHeader, nextSeq }, context, async (append) => {
|
|
258
|
+
const sourceWrites = streamForkWrites(options.input, options.fileSystem, nextSeq, isEntryCopied, context);
|
|
259
|
+
for await (const write of sourceWrites) {
|
|
260
|
+
const projected = projectJsonlForkWrite(write, index, plan, isEntryCopied);
|
|
261
|
+
if (projected !== undefined)
|
|
262
|
+
await append([projected]);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=fork.js.map
|