@earendil-works/pi-agent-core 0.84.3 → 0.85.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 +4 -0
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +32 -25
- package/dist/agent-loop.js.map +1 -1
- 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 -251
- 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 -26
- 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 -63
- 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 +27 -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 +24 -28
- package/dist/harness/env/nodejs.d.ts.map +1 -1
- package/dist/harness/env/nodejs.js +242 -87
- 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 +240 -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 +49 -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 +406 -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 +40 -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 +170 -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 +37 -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 +311 -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 +101 -0
- package/dist/harness/runtime/lane.d.ts.map +1 -0
- package/dist/harness/runtime/lane.js +1575 -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 +61 -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 -18
- package/dist/harness/session/context.d.ts.map +1 -1
- package/dist/harness/session/context.js +31 -49
- package/dist/harness/session/context.js.map +1 -1
- package/dist/harness/session/fork-policy.d.ts +13 -0
- package/dist/harness/session/fork-policy.d.ts.map +1 -0
- package/dist/harness/session/fork-policy.js +22 -0
- package/dist/harness/session/fork-policy.js.map +1 -0
- package/dist/harness/session/fork.d.ts +18 -0
- package/dist/harness/session/fork.d.ts.map +1 -0
- package/dist/harness/session/fork.js +127 -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 +216 -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 -218
- package/dist/harness/session/jsonl/codec.js.map +1 -1
- 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/legacy-v3.d.ts +18 -0
- package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
- package/dist/harness/session/jsonl/legacy-v3.js +383 -0
- package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
- package/dist/harness/session/jsonl/repo.d.ts +26 -19
- package/dist/harness/session/jsonl/repo.d.ts.map +1 -1
- package/dist/harness/session/jsonl/repo.js +266 -156
- 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 +238 -181
- 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 +46 -40
- package/dist/harness/session/memory.d.ts.map +1 -1
- package/dist/harness/session/memory.js +346 -113
- 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 +21 -0
- package/dist/harness/session/mutation-line.js.map +1 -0
- package/dist/harness/session/session.d.ts +78 -46
- package/dist/harness/session/session.d.ts.map +1 -1
- package/dist/harness/session/session.js +343 -209
- 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 +21 -0
- package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
- package/dist/harness/session/testing/conformance/session-repo.js +590 -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 +100 -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 +16 -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 +41 -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 +424 -259
- package/dist/harness/session/types.d.ts.map +1 -1
- package/dist/harness/session/types.js +7 -8
- 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 +10 -10
- 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 +7 -7
- package/dist/harness/tools/write.js.map +1 -1
- package/dist/harness/types.d.ts +108 -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 +12 -5
- package/dist/harness/utils/shell-output.d.ts.map +1 -1
- package/dist/harness/utils/shell-output.js +64 -174
- 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/proxy.d.ts +2 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +40 -10
- package/dist/proxy.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 +5 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +25 -4
- package/dist/harness/reducer.d.ts +0 -100
- package/dist/harness/reducer.d.ts.map +0 -1
- package/dist/harness/reducer.js +0 -415
- 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 -19
- 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 -319
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fork.d.ts","sourceRoot":"","sources":["../../../src/harness/session/fork.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAoC,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAEpG,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,yFAAyF;IACzF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5B,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;CAChB;AAYD,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,WAAW,GAAG,uBAAuB,CAsC5G;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,cAAc,EAAE,CActF","sourcesContent":["import type { CommittedWrite } from \"./commit.ts\";\nimport { classifyForkAddress } from \"./fork-policy.ts\";\nimport type { Entry, ForkOptions } from \"./types.ts\";\nimport { branchTip, laneConfig, laneState, type StoredValue, type Value, value } from \"./values.ts\";\n\nexport interface ForkSourceSnapshot {\n\tentries: Entry[];\n\tscalarValues: StoredValue<unknown>[];\n\t/** False when a backend supplied only the requested branch rather than the full tree. */\n\tentriesComplete?: boolean;\n}\n\nexport interface ForkDestinationSnapshot {\n\tentries: Map<string, Entry>;\n\tscalarValues: StoredValue<unknown>[];\n\tnextSeq: number;\n}\n\nfunction storedValuesInNamespace<T>(values: readonly StoredValue<unknown>[], address: Value<T>): StoredValue<T>[] {\n\treturn values.filter((stored) => stored.address.namespace === address.namespace) as StoredValue<T>[];\n}\n\nfunction findStoredValue<T>(values: readonly StoredValue<unknown>[], address: Value<T>): StoredValue<T> | undefined {\n\treturn values.find(\n\t\t(stored) => stored.address.namespace === address.namespace && stored.address.key === address.key,\n\t) as StoredValue<T> | undefined;\n}\n\n/** Build the complete logical state for a forked destination session. */\nexport function createForkSnapshot(source: ForkSourceSnapshot, options: ForkOptions): ForkDestinationSnapshot {\n\tconst sourceEntries = new Map(source.entries.map((entry) => [entry.id, entry]));\n\tconst sourceTips = storedValuesInNamespace(source.scalarValues, branchTip(\"\"));\n\tvalidateForkSourceSnapshot(source, sourceEntries, sourceTips, options);\n\n\tconst { entryIds, destinationTips } = selectForkContents(sourceEntries, sourceTips, options);\n\tconst entries = new Map<string, Entry>();\n\tfor (const id of entryIds) entries.set(id, sourceEntries.get(id)!);\n\n\tconst scalarValues: StoredValue<unknown>[] = [];\n\tlet nextSeq = Math.max(0, ...[...entries.values()].map((entry) => entry.seq)) + 1;\n\tconst store = <T>(address: Value<T>, storedValue: T): void => {\n\t\tscalarValues.push({\n\t\t\taddress: value<unknown>(address.namespace, address.key),\n\t\t\tvalue: storedValue,\n\t\t\tseq: nextSeq++,\n\t\t});\n\t};\n\tfor (const [branch, tipId] of destinationTips) {\n\t\tconst configuration = findStoredValue(source.scalarValues, laneConfig(branch));\n\t\tstore(branchTip(branch), tipId);\n\t\tif (configuration !== undefined) {\n\t\t\tstore(laneConfig(branch), configuration.value);\n\t\t\tstore(laneState(branch), { currentOperationId: null, lastOperationId: null, inbox: [] });\n\t\t}\n\t}\n\tfor (const stored of source.scalarValues) {\n\t\tswitch (classifyForkAddress(stored.address, options.scope, (entryId) => entryIds.has(entryId))) {\n\t\t\tcase \"copy\":\n\t\t\t\tstore(stored.address, stored.value);\n\t\t\t\tbreak;\n\t\t\tcase \"exclude\":\n\t\t\tcase \"reconstruct\":\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn { entries, scalarValues, nextSeq };\n}\n\nexport function forkSnapshotWrites(snapshot: ForkDestinationSnapshot): CommittedWrite[] {\n\tconst writes: CommittedWrite[] = [];\n\tfor (const entry of snapshot.entries.values()) writes.push({ kind: \"entry\", ...entry });\n\tfor (const stored of snapshot.scalarValues) {\n\t\twrites.push({\n\t\t\tkind: \"value\",\n\t\t\top: \"set\",\n\t\t\tseq: stored.seq,\n\t\t\tnamespace: stored.address.namespace,\n\t\t\tkey: stored.address.key,\n\t\t\tvalue: stored.value,\n\t\t});\n\t}\n\treturn writes.sort((left, right) => left.seq - right.seq);\n}\n\nfunction selectForkContents(\n\tsourceEntries: Map<string, Entry>,\n\tsourceTips: StoredValue<string | null>[],\n\toptions: ForkOptions,\n): {\n\tentryIds: Set<string>;\n\tdestinationTips: Map<string, string | null>;\n} {\n\tconst entryIds = new Set<string>();\n\tconst destinationTips = new Map<string, string | null>();\n\tif (options.scope === \"tree\") {\n\t\tfor (const id of sourceEntries.keys()) entryIds.add(id);\n\t\tfor (const stored of sourceTips) destinationTips.set(stored.address.key, stored.value);\n\t} else {\n\t\tconst sourceTip = sourceTips.find((stored) => stored.address.key === options.branch);\n\t\tif (sourceTip === undefined) throw new Error(`Unknown source branch: ${options.branch}`);\n\n\t\tconst requested = options.entryId ?? sourceTip.value;\n\t\tlet found = requested === null;\n\t\tlet tipId: string | null = null;\n\t\tlet entryId = sourceTip.value;\n\t\twhile (entryId !== null) {\n\t\t\tconst entry = sourceEntries.get(entryId);\n\t\t\tif (entry === undefined) throw new Error(`Corrupt source branch: missing parent ${entryId}`);\n\t\t\tif (entry.id === requested) {\n\t\t\t\tfound = true;\n\t\t\t\ttipId = options.position === \"before\" ? entry.parentId : entry.id;\n\t\t\t\tif (options.position !== \"before\") entryIds.add(entry.id);\n\t\t\t} else if (found) {\n\t\t\t\tentryIds.add(entry.id);\n\t\t\t}\n\t\t\tentryId = entry.parentId;\n\t\t}\n\t\tif (!found) {\n\t\t\tthrow new Error(`Fork entry ${requested} is not on source branch ${JSON.stringify(options.branch)}`);\n\t\t}\n\t\tdestinationTips.set(options.branch, tipId);\n\t}\n\treturn { entryIds, destinationTips };\n}\n\nfunction validateForkSourceSnapshot(\n\tsource: ForkSourceSnapshot,\n\tsourceEntries: Map<string, Entry>,\n\tsourceTips: StoredValue<string | null>[],\n\toptions: ForkOptions,\n): void {\n\tconst sourceTipKeys = new Set(sourceTips.map((stored) => stored.address.key));\n\n\tfor (const stored of source.scalarValues) {\n\t\tif (\n\t\t\t(stored.address.namespace === laneConfig(\"\").namespace ||\n\t\t\t\tstored.address.namespace === laneState(\"\").namespace) &&\n\t\t\t!sourceTipKeys.has(stored.address.key)\n\t\t) {\n\t\t\tthrow new Error(`Source session branch ${JSON.stringify(stored.address.key)} is missing branch.tip`);\n\t\t}\n\t}\n\tfor (const tip of sourceTips) {\n\t\tconst configuration = findStoredValue(source.scalarValues, laneConfig(tip.address.key));\n\t\tconst state = findStoredValue(source.scalarValues, laneState(tip.address.key));\n\t\tif ((configuration === undefined) !== (state === undefined)) {\n\t\t\tthrow new Error(`Source session branch ${JSON.stringify(tip.address.key)} has incomplete lane state`);\n\t\t}\n\t\tif (options.scope === \"branch\" && tip.address.key === options.branch && configuration === undefined) {\n\t\t\tthrow new Error(`Source branch ${JSON.stringify(options.branch)} is not a configured AgentLane`);\n\t\t}\n\t\tif (\n\t\t\t(source.entriesComplete !== false || options.scope === \"tree\") &&\n\t\t\ttip.value !== null &&\n\t\t\t!sourceEntries.has(tip.value)\n\t\t) {\n\t\t\tthrow new Error(`Source session branch ${JSON.stringify(tip.address.key)} has an unknown tip`);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { classifyForkAddress } from "./fork-policy.js";
|
|
2
|
+
import { branchTip, laneConfig, laneState, value } from "./values.js";
|
|
3
|
+
function storedValuesInNamespace(values, address) {
|
|
4
|
+
return values.filter((stored) => stored.address.namespace === address.namespace);
|
|
5
|
+
}
|
|
6
|
+
function findStoredValue(values, address) {
|
|
7
|
+
return values.find((stored) => stored.address.namespace === address.namespace && stored.address.key === address.key);
|
|
8
|
+
}
|
|
9
|
+
/** Build the complete logical state for a forked destination session. */
|
|
10
|
+
export function createForkSnapshot(source, options) {
|
|
11
|
+
const sourceEntries = new Map(source.entries.map((entry) => [entry.id, entry]));
|
|
12
|
+
const sourceTips = storedValuesInNamespace(source.scalarValues, branchTip(""));
|
|
13
|
+
validateForkSourceSnapshot(source, sourceEntries, sourceTips, options);
|
|
14
|
+
const { entryIds, destinationTips } = selectForkContents(sourceEntries, sourceTips, options);
|
|
15
|
+
const entries = new Map();
|
|
16
|
+
for (const id of entryIds)
|
|
17
|
+
entries.set(id, sourceEntries.get(id));
|
|
18
|
+
const scalarValues = [];
|
|
19
|
+
let nextSeq = Math.max(0, ...[...entries.values()].map((entry) => entry.seq)) + 1;
|
|
20
|
+
const store = (address, storedValue) => {
|
|
21
|
+
scalarValues.push({
|
|
22
|
+
address: value(address.namespace, address.key),
|
|
23
|
+
value: storedValue,
|
|
24
|
+
seq: nextSeq++,
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
for (const [branch, tipId] of destinationTips) {
|
|
28
|
+
const configuration = findStoredValue(source.scalarValues, laneConfig(branch));
|
|
29
|
+
store(branchTip(branch), tipId);
|
|
30
|
+
if (configuration !== undefined) {
|
|
31
|
+
store(laneConfig(branch), configuration.value);
|
|
32
|
+
store(laneState(branch), { currentOperationId: null, lastOperationId: null, inbox: [] });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const stored of source.scalarValues) {
|
|
36
|
+
switch (classifyForkAddress(stored.address, options.scope, (entryId) => entryIds.has(entryId))) {
|
|
37
|
+
case "copy":
|
|
38
|
+
store(stored.address, stored.value);
|
|
39
|
+
break;
|
|
40
|
+
case "exclude":
|
|
41
|
+
case "reconstruct":
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { entries, scalarValues, nextSeq };
|
|
46
|
+
}
|
|
47
|
+
export function forkSnapshotWrites(snapshot) {
|
|
48
|
+
const writes = [];
|
|
49
|
+
for (const entry of snapshot.entries.values())
|
|
50
|
+
writes.push({ kind: "entry", ...entry });
|
|
51
|
+
for (const stored of snapshot.scalarValues) {
|
|
52
|
+
writes.push({
|
|
53
|
+
kind: "value",
|
|
54
|
+
op: "set",
|
|
55
|
+
seq: stored.seq,
|
|
56
|
+
namespace: stored.address.namespace,
|
|
57
|
+
key: stored.address.key,
|
|
58
|
+
value: stored.value,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return writes.sort((left, right) => left.seq - right.seq);
|
|
62
|
+
}
|
|
63
|
+
function selectForkContents(sourceEntries, sourceTips, options) {
|
|
64
|
+
const entryIds = new Set();
|
|
65
|
+
const destinationTips = new Map();
|
|
66
|
+
if (options.scope === "tree") {
|
|
67
|
+
for (const id of sourceEntries.keys())
|
|
68
|
+
entryIds.add(id);
|
|
69
|
+
for (const stored of sourceTips)
|
|
70
|
+
destinationTips.set(stored.address.key, stored.value);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const sourceTip = sourceTips.find((stored) => stored.address.key === options.branch);
|
|
74
|
+
if (sourceTip === undefined)
|
|
75
|
+
throw new Error(`Unknown source branch: ${options.branch}`);
|
|
76
|
+
const requested = options.entryId ?? sourceTip.value;
|
|
77
|
+
let found = requested === null;
|
|
78
|
+
let tipId = null;
|
|
79
|
+
let entryId = sourceTip.value;
|
|
80
|
+
while (entryId !== null) {
|
|
81
|
+
const entry = sourceEntries.get(entryId);
|
|
82
|
+
if (entry === undefined)
|
|
83
|
+
throw new Error(`Corrupt source branch: missing parent ${entryId}`);
|
|
84
|
+
if (entry.id === requested) {
|
|
85
|
+
found = true;
|
|
86
|
+
tipId = options.position === "before" ? entry.parentId : entry.id;
|
|
87
|
+
if (options.position !== "before")
|
|
88
|
+
entryIds.add(entry.id);
|
|
89
|
+
}
|
|
90
|
+
else if (found) {
|
|
91
|
+
entryIds.add(entry.id);
|
|
92
|
+
}
|
|
93
|
+
entryId = entry.parentId;
|
|
94
|
+
}
|
|
95
|
+
if (!found) {
|
|
96
|
+
throw new Error(`Fork entry ${requested} is not on source branch ${JSON.stringify(options.branch)}`);
|
|
97
|
+
}
|
|
98
|
+
destinationTips.set(options.branch, tipId);
|
|
99
|
+
}
|
|
100
|
+
return { entryIds, destinationTips };
|
|
101
|
+
}
|
|
102
|
+
function validateForkSourceSnapshot(source, sourceEntries, sourceTips, options) {
|
|
103
|
+
const sourceTipKeys = new Set(sourceTips.map((stored) => stored.address.key));
|
|
104
|
+
for (const stored of source.scalarValues) {
|
|
105
|
+
if ((stored.address.namespace === laneConfig("").namespace ||
|
|
106
|
+
stored.address.namespace === laneState("").namespace) &&
|
|
107
|
+
!sourceTipKeys.has(stored.address.key)) {
|
|
108
|
+
throw new Error(`Source session branch ${JSON.stringify(stored.address.key)} is missing branch.tip`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const tip of sourceTips) {
|
|
112
|
+
const configuration = findStoredValue(source.scalarValues, laneConfig(tip.address.key));
|
|
113
|
+
const state = findStoredValue(source.scalarValues, laneState(tip.address.key));
|
|
114
|
+
if ((configuration === undefined) !== (state === undefined)) {
|
|
115
|
+
throw new Error(`Source session branch ${JSON.stringify(tip.address.key)} has incomplete lane state`);
|
|
116
|
+
}
|
|
117
|
+
if (options.scope === "branch" && tip.address.key === options.branch && configuration === undefined) {
|
|
118
|
+
throw new Error(`Source branch ${JSON.stringify(options.branch)} is not a configured AgentLane`);
|
|
119
|
+
}
|
|
120
|
+
if ((source.entriesComplete !== false || options.scope === "tree") &&
|
|
121
|
+
tip.value !== null &&
|
|
122
|
+
!sourceEntries.has(tip.value)) {
|
|
123
|
+
throw new Error(`Source session branch ${JSON.stringify(tip.address.key)} has an unknown tip`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=fork.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fork.js","sourceRoot":"","sources":["../../../src/harness/session/fork.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CommittedWrite } from \"./commit.ts\";\nimport { classifyForkAddress } from \"./fork-policy.ts\";\nimport type { Entry, ForkOptions } from \"./types.ts\";\nimport { branchTip, laneConfig, laneState, type StoredValue, type Value, value } from \"./values.ts\";\n\nexport interface ForkSourceSnapshot {\n\tentries: Entry[];\n\tscalarValues: StoredValue<unknown>[];\n\t/** False when a backend supplied only the requested branch rather than the full tree. */\n\tentriesComplete?: boolean;\n}\n\nexport interface ForkDestinationSnapshot {\n\tentries: Map<string, Entry>;\n\tscalarValues: StoredValue<unknown>[];\n\tnextSeq: number;\n}\n\nfunction storedValuesInNamespace<T>(values: readonly StoredValue<unknown>[], address: Value<T>): StoredValue<T>[] {\n\treturn values.filter((stored) => stored.address.namespace === address.namespace) as StoredValue<T>[];\n}\n\nfunction findStoredValue<T>(values: readonly StoredValue<unknown>[], address: Value<T>): StoredValue<T> | undefined {\n\treturn values.find(\n\t\t(stored) => stored.address.namespace === address.namespace && stored.address.key === address.key,\n\t) as StoredValue<T> | undefined;\n}\n\n/** Build the complete logical state for a forked destination session. */\nexport function createForkSnapshot(source: ForkSourceSnapshot, options: ForkOptions): ForkDestinationSnapshot {\n\tconst sourceEntries = new Map(source.entries.map((entry) => [entry.id, entry]));\n\tconst sourceTips = storedValuesInNamespace(source.scalarValues, branchTip(\"\"));\n\tvalidateForkSourceSnapshot(source, sourceEntries, sourceTips, options);\n\n\tconst { entryIds, destinationTips } = selectForkContents(sourceEntries, sourceTips, options);\n\tconst entries = new Map<string, Entry>();\n\tfor (const id of entryIds) entries.set(id, sourceEntries.get(id)!);\n\n\tconst scalarValues: StoredValue<unknown>[] = [];\n\tlet nextSeq = Math.max(0, ...[...entries.values()].map((entry) => entry.seq)) + 1;\n\tconst store = <T>(address: Value<T>, storedValue: T): void => {\n\t\tscalarValues.push({\n\t\t\taddress: value<unknown>(address.namespace, address.key),\n\t\t\tvalue: storedValue,\n\t\t\tseq: nextSeq++,\n\t\t});\n\t};\n\tfor (const [branch, tipId] of destinationTips) {\n\t\tconst configuration = findStoredValue(source.scalarValues, laneConfig(branch));\n\t\tstore(branchTip(branch), tipId);\n\t\tif (configuration !== undefined) {\n\t\t\tstore(laneConfig(branch), configuration.value);\n\t\t\tstore(laneState(branch), { currentOperationId: null, lastOperationId: null, inbox: [] });\n\t\t}\n\t}\n\tfor (const stored of source.scalarValues) {\n\t\tswitch (classifyForkAddress(stored.address, options.scope, (entryId) => entryIds.has(entryId))) {\n\t\t\tcase \"copy\":\n\t\t\t\tstore(stored.address, stored.value);\n\t\t\t\tbreak;\n\t\t\tcase \"exclude\":\n\t\t\tcase \"reconstruct\":\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn { entries, scalarValues, nextSeq };\n}\n\nexport function forkSnapshotWrites(snapshot: ForkDestinationSnapshot): CommittedWrite[] {\n\tconst writes: CommittedWrite[] = [];\n\tfor (const entry of snapshot.entries.values()) writes.push({ kind: \"entry\", ...entry });\n\tfor (const stored of snapshot.scalarValues) {\n\t\twrites.push({\n\t\t\tkind: \"value\",\n\t\t\top: \"set\",\n\t\t\tseq: stored.seq,\n\t\t\tnamespace: stored.address.namespace,\n\t\t\tkey: stored.address.key,\n\t\t\tvalue: stored.value,\n\t\t});\n\t}\n\treturn writes.sort((left, right) => left.seq - right.seq);\n}\n\nfunction selectForkContents(\n\tsourceEntries: Map<string, Entry>,\n\tsourceTips: StoredValue<string | null>[],\n\toptions: ForkOptions,\n): {\n\tentryIds: Set<string>;\n\tdestinationTips: Map<string, string | null>;\n} {\n\tconst entryIds = new Set<string>();\n\tconst destinationTips = new Map<string, string | null>();\n\tif (options.scope === \"tree\") {\n\t\tfor (const id of sourceEntries.keys()) entryIds.add(id);\n\t\tfor (const stored of sourceTips) destinationTips.set(stored.address.key, stored.value);\n\t} else {\n\t\tconst sourceTip = sourceTips.find((stored) => stored.address.key === options.branch);\n\t\tif (sourceTip === undefined) throw new Error(`Unknown source branch: ${options.branch}`);\n\n\t\tconst requested = options.entryId ?? sourceTip.value;\n\t\tlet found = requested === null;\n\t\tlet tipId: string | null = null;\n\t\tlet entryId = sourceTip.value;\n\t\twhile (entryId !== null) {\n\t\t\tconst entry = sourceEntries.get(entryId);\n\t\t\tif (entry === undefined) throw new Error(`Corrupt source branch: missing parent ${entryId}`);\n\t\t\tif (entry.id === requested) {\n\t\t\t\tfound = true;\n\t\t\t\ttipId = options.position === \"before\" ? entry.parentId : entry.id;\n\t\t\t\tif (options.position !== \"before\") entryIds.add(entry.id);\n\t\t\t} else if (found) {\n\t\t\t\tentryIds.add(entry.id);\n\t\t\t}\n\t\t\tentryId = entry.parentId;\n\t\t}\n\t\tif (!found) {\n\t\t\tthrow new Error(`Fork entry ${requested} is not on source branch ${JSON.stringify(options.branch)}`);\n\t\t}\n\t\tdestinationTips.set(options.branch, tipId);\n\t}\n\treturn { entryIds, destinationTips };\n}\n\nfunction validateForkSourceSnapshot(\n\tsource: ForkSourceSnapshot,\n\tsourceEntries: Map<string, Entry>,\n\tsourceTips: StoredValue<string | null>[],\n\toptions: ForkOptions,\n): void {\n\tconst sourceTipKeys = new Set(sourceTips.map((stored) => stored.address.key));\n\n\tfor (const stored of source.scalarValues) {\n\t\tif (\n\t\t\t(stored.address.namespace === laneConfig(\"\").namespace ||\n\t\t\t\tstored.address.namespace === laneState(\"\").namespace) &&\n\t\t\t!sourceTipKeys.has(stored.address.key)\n\t\t) {\n\t\t\tthrow new Error(`Source session branch ${JSON.stringify(stored.address.key)} is missing branch.tip`);\n\t\t}\n\t}\n\tfor (const tip of sourceTips) {\n\t\tconst configuration = findStoredValue(source.scalarValues, laneConfig(tip.address.key));\n\t\tconst state = findStoredValue(source.scalarValues, laneState(tip.address.key));\n\t\tif ((configuration === undefined) !== (state === undefined)) {\n\t\t\tthrow new Error(`Source session branch ${JSON.stringify(tip.address.key)} has incomplete lane state`);\n\t\t}\n\t\tif (options.scope === \"branch\" && tip.address.key === options.branch && configuration === undefined) {\n\t\t\tthrow new Error(`Source branch ${JSON.stringify(options.branch)} is not a configured AgentLane`);\n\t\t}\n\t\tif (\n\t\t\t(source.entriesComplete !== false || options.scope === \"tree\") &&\n\t\t\ttip.value !== null &&\n\t\t\t!sourceEntries.has(tip.value)\n\t\t) {\n\t\t\tthrow new Error(`Source session branch ${JSON.stringify(tip.address.key)} has an unknown tip`);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type CommittedWrite, type PreparedCommit } from "./commit.ts";
|
|
2
|
+
export type { CommittedEntryWrite, CommittedListAppendWrite, CommittedListDeleteWrite, CommittedUsageWrite, CommittedValueDeleteWrite, CommittedValueSetWrite, CommittedWrite, PreparedCommit, } from "./commit.ts";
|
|
3
|
+
import type { Entry, EntryScan, EntryStructure, SessionStats, StorageBranchScan, UsageRow, UsageScan, Write } from "./types.ts";
|
|
4
|
+
import { type ListElement, type ListReadOptions, type StoredValue, type Value, type ValueList } from "./values.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Complete materialized session state for MemoryStorage and JsonlStorage.
|
|
7
|
+
*
|
|
8
|
+
* This is intentionally unsuitable for database backends and long-running sessions that may not fit in memory.
|
|
9
|
+
* Those backends should query indexed durable state and update durable aggregates within each commit transaction.
|
|
10
|
+
*/
|
|
11
|
+
export declare class InMemoryStorageState {
|
|
12
|
+
private readonly entries;
|
|
13
|
+
private readonly entriesBySeq;
|
|
14
|
+
private readonly scalarValues;
|
|
15
|
+
private readonly listValues;
|
|
16
|
+
private readonly usage;
|
|
17
|
+
private stats;
|
|
18
|
+
private nextSeq;
|
|
19
|
+
constructor();
|
|
20
|
+
prepareCommit(writes: Write[], timestamp: number): PreparedCommit;
|
|
21
|
+
validateCommitted(writes: readonly CommittedWrite[]): void;
|
|
22
|
+
/** Apply writes already accepted by validateCommitted() and return the post-apply totals. */
|
|
23
|
+
applyValidated(writes: readonly CommittedWrite[]): SessionStats;
|
|
24
|
+
advanceNextSeq(nextSeq: number): void;
|
|
25
|
+
getEntries(ids: readonly string[]): Map<string, Entry>;
|
|
26
|
+
getValue<T>(address: Value<T>): StoredValue<T> | undefined;
|
|
27
|
+
scanValues<T>(prefix: Value<T>): StoredValue<T>[];
|
|
28
|
+
readList<T>(address: ValueList<T>, options?: ListReadOptions): ListElement<T>[];
|
|
29
|
+
scanBranch(query: StorageBranchScan): Entry[];
|
|
30
|
+
scanBranchStructure(query: StorageBranchScan): EntryStructure[];
|
|
31
|
+
scanEntries(query: EntryScan): Entry[];
|
|
32
|
+
scanUsage(query: UsageScan): UsageRow[];
|
|
33
|
+
getStats(): SessionStats;
|
|
34
|
+
snapshotEntriesAndValues(): {
|
|
35
|
+
entries: Entry[];
|
|
36
|
+
scalarValues: StoredValue<unknown>[];
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=in-memory-storage-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-storage-state.d.ts","sourceRoot":"","sources":["../../../src/harness/session/in-memory-storage-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,cAAc,EAAiD,MAAM,aAAa,CAAC;AAEtH,YAAY,EACX,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,yBAAyB,EACzB,sBAAsB,EACtB,cAAc,EACd,cAAc,GACd,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EACX,KAAK,EACL,SAAS,EACT,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,SAAS,EACT,KAAK,EACL,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,WAAW,EAChB,KAAK,eAAe,EAGpB,KAAK,WAAW,EAChB,KAAK,KAAK,EACV,KAAK,SAAS,EAEd,MAAM,aAAa,CAAC;AAsBrB;;;;;GAKG;AACH,qBAAa,oBAAoB;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoC;IACjE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAS;IAExB,cAQC;IAED,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,cAAc,CAIhE;IAED,iBAAiB,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI,CAKzD;IAED,6FAA6F;IAC7F,cAAc,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,GAAG,YAAY,CAmD9D;IAED,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKpC;IAED,UAAU,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAOrD;IAED,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,SAAS,CAEzD;IAED,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAIhD;IAED,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAS9E;IAED,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,KAAK,EAAE,CA4B5C;IAED,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAS9D;IAED,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,CAkBrC;IAED,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE,CAMtC;IAED,QAAQ,IAAI,YAAY,CAEvB;IAED,wBAAwB,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAAC,YAAY,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAA;KAAE,CAKrF;CACD","sourcesContent":["import { addUsage, emptyUsage } from \"../utils/usage.ts\";\nimport { type CommittedWrite, type PreparedCommit, prepareStorageCommit, validateCommittedWrites } from \"./commit.ts\";\n\nexport type {\n\tCommittedEntryWrite,\n\tCommittedListAppendWrite,\n\tCommittedListDeleteWrite,\n\tCommittedUsageWrite,\n\tCommittedValueDeleteWrite,\n\tCommittedValueSetWrite,\n\tCommittedWrite,\n\tPreparedCommit,\n} from \"./commit.ts\";\n\nimport type {\n\tEntry,\n\tEntryScan,\n\tEntryStructure,\n\tSessionStats,\n\tStorageBranchScan,\n\tUsageRow,\n\tUsageScan,\n\tWrite,\n} from \"./types.ts\";\nimport {\n\ttype ListElement,\n\ttype ListReadOptions,\n\tlist,\n\tresolveListReadOptions,\n\ttype StoredValue,\n\ttype Value,\n\ttype ValueList,\n\tvalue,\n} from \"./values.ts\";\n\ninterface StoredListSnapshot {\n\taddress: ValueList<unknown>;\n\telements: ListElement<unknown>[];\n}\n\nfunction physicalKey(namespace: string, key: string): string {\n\treturn `${namespace}\\u0000${key}`;\n}\n\nfunction compareKeys(left: string, right: string): number {\n\tconst leftCodePoints = Array.from(left, (character) => character.codePointAt(0)!);\n\tconst rightCodePoints = Array.from(right, (character) => character.codePointAt(0)!);\n\tconst length = Math.min(leftCodePoints.length, rightCodePoints.length);\n\tfor (let index = 0; index < length; index++) {\n\t\tconst difference = leftCodePoints[index]! - rightCodePoints[index]!;\n\t\tif (difference !== 0) return difference;\n\t}\n\treturn leftCodePoints.length - rightCodePoints.length;\n}\n\n/**\n * Complete materialized session state for MemoryStorage and JsonlStorage.\n *\n * This is intentionally unsuitable for database backends and long-running sessions that may not fit in memory.\n * Those backends should query indexed durable state and update durable aggregates within each commit transaction.\n */\nexport class InMemoryStorageState {\n\tprivate readonly entries: Map<string, Entry>;\n\tprivate readonly entriesBySeq: Entry[];\n\tprivate readonly scalarValues: Map<string, StoredValue<unknown>>;\n\tprivate readonly listValues: Map<string, StoredListSnapshot>;\n\tprivate readonly usage: Map<string, UsageRow>;\n\tprivate stats: SessionStats;\n\tprivate nextSeq: number;\n\n\tconstructor() {\n\t\tthis.entries = new Map();\n\t\tthis.entriesBySeq = [];\n\t\tthis.scalarValues = new Map();\n\t\tthis.listValues = new Map();\n\t\tthis.usage = new Map();\n\t\tthis.stats = { messageCount: 0, usage: emptyUsage() };\n\t\tthis.nextSeq = 1;\n\t}\n\n\tprepareCommit(writes: Write[], timestamp: number): PreparedCommit {\n\t\tconst prepared = prepareStorageCommit(writes, this.nextSeq, timestamp);\n\t\tthis.validateCommitted(prepared.writes);\n\t\treturn prepared;\n\t}\n\n\tvalidateCommitted(writes: readonly CommittedWrite[]): void {\n\t\tvalidateCommittedWrites(writes, this.nextSeq, {\n\t\t\thasEntryOrUsageId: (id) => this.entries.has(id) || this.usage.has(id),\n\t\t\thasEntryId: (id) => this.entries.has(id),\n\t\t});\n\t}\n\n\t/** Apply writes already accepted by validateCommitted() and return the post-apply totals. */\n\tapplyValidated(writes: readonly CommittedWrite[]): SessionStats {\n\t\tfor (const write of writes) {\n\t\t\tswitch (write.kind) {\n\t\t\t\tcase \"entry\": {\n\t\t\t\t\tconst { kind: _kind, ...entry } = write;\n\t\t\t\t\tthis.entries.set(entry.id, entry);\n\t\t\t\t\tthis.entriesBySeq.push(entry);\n\t\t\t\t\tif (entry.type === \"message\") this.stats = { ...this.stats, messageCount: this.stats.messageCount + 1 };\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"usage\": {\n\t\t\t\t\tconst { kind: _kind, ...row } = write;\n\t\t\t\t\tthis.usage.set(row.id, row);\n\t\t\t\t\tthis.stats = { ...this.stats, usage: addUsage(this.stats.usage, row.usage) };\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"value\": {\n\t\t\t\t\tconst key = physicalKey(write.namespace, write.key);\n\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\tthis.scalarValues.delete(key);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.scalarValues.set(key, {\n\t\t\t\t\t\t\taddress: value<unknown>(write.namespace, write.key),\n\t\t\t\t\t\t\tvalue: write.value,\n\t\t\t\t\t\t\tseq: write.seq,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"list\": {\n\t\t\t\t\tconst key = physicalKey(write.namespace, write.key);\n\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\tthis.listValues.delete(key);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst stored = this.listValues.get(key);\n\t\t\t\t\t\tconst element = { seq: write.seq, value: write.value };\n\t\t\t\t\t\tif (stored === undefined) {\n\t\t\t\t\t\t\tthis.listValues.set(key, {\n\t\t\t\t\t\t\t\taddress: list<unknown>(write.namespace, write.key),\n\t\t\t\t\t\t\t\telements: [element],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstored.elements.push(element);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.nextSeq = write.seq + 1;\n\t\t}\n\t\treturn this.stats;\n\t}\n\n\tadvanceNextSeq(nextSeq: number): void {\n\t\tif (!Number.isSafeInteger(nextSeq) || nextSeq < 1) {\n\t\t\tthrow new Error(`Invalid storage sequence high-water mark: ${nextSeq}`);\n\t\t}\n\t\tthis.nextSeq = Math.max(this.nextSeq, nextSeq);\n\t}\n\n\tgetEntries(ids: readonly string[]): Map<string, Entry> {\n\t\tconst found = new Map<string, Entry>();\n\t\tfor (const id of ids) {\n\t\t\tconst entry = this.entries.get(id);\n\t\t\tif (entry !== undefined) found.set(id, entry);\n\t\t}\n\t\treturn found;\n\t}\n\n\tgetValue<T>(address: Value<T>): StoredValue<T> | undefined {\n\t\treturn this.scalarValues.get(physicalKey(address.namespace, address.key)) as StoredValue<T> | undefined;\n\t}\n\n\tscanValues<T>(prefix: Value<T>): StoredValue<T>[] {\n\t\treturn [...this.scalarValues.values()]\n\t\t\t.filter((stored) => stored.address.namespace === prefix.namespace && stored.address.key.startsWith(prefix.key))\n\t\t\t.sort((left, right) => compareKeys(left.address.key, right.address.key)) as StoredValue<T>[];\n\t}\n\n\treadList<T>(address: ValueList<T>, options?: ListReadOptions): ListElement<T>[] {\n\t\tconst resolved = resolveListReadOptions(options);\n\t\tconst elements = this.listValues.get(physicalKey(address.namespace, address.key))?.elements ?? [];\n\t\tconst filtered = elements.filter((element) => {\n\t\t\tif (resolved.cursor === undefined) return true;\n\t\t\treturn resolved.order === \"asc\" ? element.seq > resolved.cursor.seq : element.seq < resolved.cursor.seq;\n\t\t});\n\t\tconst ordered = resolved.order === \"asc\" ? filtered : [...filtered].reverse();\n\t\treturn ordered.slice(0, resolved.limit) as ListElement<T>[];\n\t}\n\n\tscanBranch(query: StorageBranchScan): Entry[] {\n\t\tconst start = this.entries.get(query.start);\n\t\tif (start === undefined) throw new Error(`Unknown branch start: ${query.start}`);\n\n\t\tconst path: Entry[] = [];\n\t\tlet entry: Entry | undefined = start;\n\t\twhile (entry !== undefined) {\n\t\t\tpath.push(entry);\n\t\t\tif (entry.parentId === null) break;\n\t\t\tentry = this.entries.get(entry.parentId);\n\t\t\tif (entry === undefined) throw new Error(\"Corrupt branch: missing parent\");\n\t\t}\n\t\tif (query.order === \"oldestFirst\") path.reverse();\n\n\t\tconst stopped: Entry[] = [];\n\t\tfor (const candidate of path) {\n\t\t\tstopped.push(candidate);\n\t\t\tif (candidate.id === query.stopAtId || candidate.type === query.stopAtType) break;\n\t\t}\n\t\tconst filtered = stopped\n\t\t\t.filter((candidate) => query.type === undefined || candidate.type === query.type)\n\t\t\t.filter((candidate) => query.customType === undefined || candidate.customType === query.customType)\n\t\t\t.filter(\n\t\t\t\t(candidate) =>\n\t\t\t\t\tquery.cursor === undefined ||\n\t\t\t\t\t(query.order === \"oldestFirst\" ? candidate.seq > query.cursor.seq : candidate.seq < query.cursor.seq),\n\t\t\t);\n\t\treturn query.limit === undefined ? filtered : filtered.slice(0, Math.max(0, query.limit));\n\t}\n\n\tscanBranchStructure(query: StorageBranchScan): EntryStructure[] {\n\t\treturn this.scanBranch(query).map((entry) => ({\n\t\t\tid: entry.id,\n\t\t\tparentId: entry.parentId,\n\t\t\tseq: entry.seq,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\ttype: entry.type,\n\t\t\t...(entry.customType === undefined ? {} : { customType: entry.customType }),\n\t\t}));\n\t}\n\n\tscanEntries(query: EntryScan): Entry[] {\n\t\tconst limit = query.limit === undefined ? Number.POSITIVE_INFINITY : Math.max(0, Math.trunc(query.limit));\n\t\tconst entries: Entry[] = [];\n\t\tconst descending = query.order === \"desc\";\n\t\tlet index = descending ? this.entriesBySeq.length - 1 : 0;\n\t\twhile (index >= 0 && index < this.entriesBySeq.length && entries.length < limit) {\n\t\t\tconst entry = this.entriesBySeq[index]!;\n\t\t\tif (\n\t\t\t\t(query.type === undefined || entry.type === query.type) &&\n\t\t\t\t(query.customType === undefined || entry.customType === query.customType) &&\n\t\t\t\t(query.fromSeq === undefined || entry.seq >= query.fromSeq) &&\n\t\t\t\t(query.toSeq === undefined || entry.seq <= query.toSeq)\n\t\t\t) {\n\t\t\t\tentries.push(entry);\n\t\t\t}\n\t\t\tindex += descending ? -1 : 1;\n\t\t}\n\t\treturn entries;\n\t}\n\n\tscanUsage(query: UsageScan): UsageRow[] {\n\t\tconst rows = [...this.usage.values()]\n\t\t\t.filter((row) => query.fromSeq === undefined || row.seq >= query.fromSeq)\n\t\t\t.filter((row) => query.toSeq === undefined || row.seq <= query.toSeq)\n\t\t\t.sort((left, right) => (query.order === \"desc\" ? right.seq - left.seq : left.seq - right.seq));\n\t\treturn query.limit === undefined ? rows : rows.slice(0, Math.max(0, query.limit));\n\t}\n\n\tgetStats(): SessionStats {\n\t\treturn this.stats;\n\t}\n\n\tsnapshotEntriesAndValues(): { entries: Entry[]; scalarValues: StoredValue<unknown>[] } {\n\t\treturn {\n\t\t\tentries: [...this.entries.values()].sort((left, right) => left.seq - right.seq),\n\t\t\tscalarValues: [...this.scalarValues.values()],\n\t\t};\n\t}\n}\n"]}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { addUsage, emptyUsage } from "../utils/usage.js";
|
|
2
|
+
import { prepareStorageCommit, validateCommittedWrites } from "./commit.js";
|
|
3
|
+
import { list, resolveListReadOptions, value, } from "./values.js";
|
|
4
|
+
function physicalKey(namespace, key) {
|
|
5
|
+
return `${namespace}\u0000${key}`;
|
|
6
|
+
}
|
|
7
|
+
function compareKeys(left, right) {
|
|
8
|
+
const leftCodePoints = Array.from(left, (character) => character.codePointAt(0));
|
|
9
|
+
const rightCodePoints = Array.from(right, (character) => character.codePointAt(0));
|
|
10
|
+
const length = Math.min(leftCodePoints.length, rightCodePoints.length);
|
|
11
|
+
for (let index = 0; index < length; index++) {
|
|
12
|
+
const difference = leftCodePoints[index] - rightCodePoints[index];
|
|
13
|
+
if (difference !== 0)
|
|
14
|
+
return difference;
|
|
15
|
+
}
|
|
16
|
+
return leftCodePoints.length - rightCodePoints.length;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Complete materialized session state for MemoryStorage and JsonlStorage.
|
|
20
|
+
*
|
|
21
|
+
* This is intentionally unsuitable for database backends and long-running sessions that may not fit in memory.
|
|
22
|
+
* Those backends should query indexed durable state and update durable aggregates within each commit transaction.
|
|
23
|
+
*/
|
|
24
|
+
export class InMemoryStorageState {
|
|
25
|
+
entries;
|
|
26
|
+
entriesBySeq;
|
|
27
|
+
scalarValues;
|
|
28
|
+
listValues;
|
|
29
|
+
usage;
|
|
30
|
+
stats;
|
|
31
|
+
nextSeq;
|
|
32
|
+
constructor() {
|
|
33
|
+
this.entries = new Map();
|
|
34
|
+
this.entriesBySeq = [];
|
|
35
|
+
this.scalarValues = new Map();
|
|
36
|
+
this.listValues = new Map();
|
|
37
|
+
this.usage = new Map();
|
|
38
|
+
this.stats = { messageCount: 0, usage: emptyUsage() };
|
|
39
|
+
this.nextSeq = 1;
|
|
40
|
+
}
|
|
41
|
+
prepareCommit(writes, timestamp) {
|
|
42
|
+
const prepared = prepareStorageCommit(writes, this.nextSeq, timestamp);
|
|
43
|
+
this.validateCommitted(prepared.writes);
|
|
44
|
+
return prepared;
|
|
45
|
+
}
|
|
46
|
+
validateCommitted(writes) {
|
|
47
|
+
validateCommittedWrites(writes, this.nextSeq, {
|
|
48
|
+
hasEntryOrUsageId: (id) => this.entries.has(id) || this.usage.has(id),
|
|
49
|
+
hasEntryId: (id) => this.entries.has(id),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Apply writes already accepted by validateCommitted() and return the post-apply totals. */
|
|
53
|
+
applyValidated(writes) {
|
|
54
|
+
for (const write of writes) {
|
|
55
|
+
switch (write.kind) {
|
|
56
|
+
case "entry": {
|
|
57
|
+
const { kind: _kind, ...entry } = write;
|
|
58
|
+
this.entries.set(entry.id, entry);
|
|
59
|
+
this.entriesBySeq.push(entry);
|
|
60
|
+
if (entry.type === "message")
|
|
61
|
+
this.stats = { ...this.stats, messageCount: this.stats.messageCount + 1 };
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "usage": {
|
|
65
|
+
const { kind: _kind, ...row } = write;
|
|
66
|
+
this.usage.set(row.id, row);
|
|
67
|
+
this.stats = { ...this.stats, usage: addUsage(this.stats.usage, row.usage) };
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
case "value": {
|
|
71
|
+
const key = physicalKey(write.namespace, write.key);
|
|
72
|
+
if (write.op === "delete") {
|
|
73
|
+
this.scalarValues.delete(key);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.scalarValues.set(key, {
|
|
77
|
+
address: value(write.namespace, write.key),
|
|
78
|
+
value: write.value,
|
|
79
|
+
seq: write.seq,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "list": {
|
|
85
|
+
const key = physicalKey(write.namespace, write.key);
|
|
86
|
+
if (write.op === "delete") {
|
|
87
|
+
this.listValues.delete(key);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const stored = this.listValues.get(key);
|
|
91
|
+
const element = { seq: write.seq, value: write.value };
|
|
92
|
+
if (stored === undefined) {
|
|
93
|
+
this.listValues.set(key, {
|
|
94
|
+
address: list(write.namespace, write.key),
|
|
95
|
+
elements: [element],
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
stored.elements.push(element);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
this.nextSeq = write.seq + 1;
|
|
106
|
+
}
|
|
107
|
+
return this.stats;
|
|
108
|
+
}
|
|
109
|
+
advanceNextSeq(nextSeq) {
|
|
110
|
+
if (!Number.isSafeInteger(nextSeq) || nextSeq < 1) {
|
|
111
|
+
throw new Error(`Invalid storage sequence high-water mark: ${nextSeq}`);
|
|
112
|
+
}
|
|
113
|
+
this.nextSeq = Math.max(this.nextSeq, nextSeq);
|
|
114
|
+
}
|
|
115
|
+
getEntries(ids) {
|
|
116
|
+
const found = new Map();
|
|
117
|
+
for (const id of ids) {
|
|
118
|
+
const entry = this.entries.get(id);
|
|
119
|
+
if (entry !== undefined)
|
|
120
|
+
found.set(id, entry);
|
|
121
|
+
}
|
|
122
|
+
return found;
|
|
123
|
+
}
|
|
124
|
+
getValue(address) {
|
|
125
|
+
return this.scalarValues.get(physicalKey(address.namespace, address.key));
|
|
126
|
+
}
|
|
127
|
+
scanValues(prefix) {
|
|
128
|
+
return [...this.scalarValues.values()]
|
|
129
|
+
.filter((stored) => stored.address.namespace === prefix.namespace && stored.address.key.startsWith(prefix.key))
|
|
130
|
+
.sort((left, right) => compareKeys(left.address.key, right.address.key));
|
|
131
|
+
}
|
|
132
|
+
readList(address, options) {
|
|
133
|
+
const resolved = resolveListReadOptions(options);
|
|
134
|
+
const elements = this.listValues.get(physicalKey(address.namespace, address.key))?.elements ?? [];
|
|
135
|
+
const filtered = elements.filter((element) => {
|
|
136
|
+
if (resolved.cursor === undefined)
|
|
137
|
+
return true;
|
|
138
|
+
return resolved.order === "asc" ? element.seq > resolved.cursor.seq : element.seq < resolved.cursor.seq;
|
|
139
|
+
});
|
|
140
|
+
const ordered = resolved.order === "asc" ? filtered : [...filtered].reverse();
|
|
141
|
+
return ordered.slice(0, resolved.limit);
|
|
142
|
+
}
|
|
143
|
+
scanBranch(query) {
|
|
144
|
+
const start = this.entries.get(query.start);
|
|
145
|
+
if (start === undefined)
|
|
146
|
+
throw new Error(`Unknown branch start: ${query.start}`);
|
|
147
|
+
const path = [];
|
|
148
|
+
let entry = start;
|
|
149
|
+
while (entry !== undefined) {
|
|
150
|
+
path.push(entry);
|
|
151
|
+
if (entry.parentId === null)
|
|
152
|
+
break;
|
|
153
|
+
entry = this.entries.get(entry.parentId);
|
|
154
|
+
if (entry === undefined)
|
|
155
|
+
throw new Error("Corrupt branch: missing parent");
|
|
156
|
+
}
|
|
157
|
+
if (query.order === "oldestFirst")
|
|
158
|
+
path.reverse();
|
|
159
|
+
const stopped = [];
|
|
160
|
+
for (const candidate of path) {
|
|
161
|
+
stopped.push(candidate);
|
|
162
|
+
if (candidate.id === query.stopAtId || candidate.type === query.stopAtType)
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
const filtered = stopped
|
|
166
|
+
.filter((candidate) => query.type === undefined || candidate.type === query.type)
|
|
167
|
+
.filter((candidate) => query.customType === undefined || candidate.customType === query.customType)
|
|
168
|
+
.filter((candidate) => query.cursor === undefined ||
|
|
169
|
+
(query.order === "oldestFirst" ? candidate.seq > query.cursor.seq : candidate.seq < query.cursor.seq));
|
|
170
|
+
return query.limit === undefined ? filtered : filtered.slice(0, Math.max(0, query.limit));
|
|
171
|
+
}
|
|
172
|
+
scanBranchStructure(query) {
|
|
173
|
+
return this.scanBranch(query).map((entry) => ({
|
|
174
|
+
id: entry.id,
|
|
175
|
+
parentId: entry.parentId,
|
|
176
|
+
seq: entry.seq,
|
|
177
|
+
timestamp: entry.timestamp,
|
|
178
|
+
type: entry.type,
|
|
179
|
+
...(entry.customType === undefined ? {} : { customType: entry.customType }),
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
scanEntries(query) {
|
|
183
|
+
const limit = query.limit === undefined ? Number.POSITIVE_INFINITY : Math.max(0, Math.trunc(query.limit));
|
|
184
|
+
const entries = [];
|
|
185
|
+
const descending = query.order === "desc";
|
|
186
|
+
let index = descending ? this.entriesBySeq.length - 1 : 0;
|
|
187
|
+
while (index >= 0 && index < this.entriesBySeq.length && entries.length < limit) {
|
|
188
|
+
const entry = this.entriesBySeq[index];
|
|
189
|
+
if ((query.type === undefined || entry.type === query.type) &&
|
|
190
|
+
(query.customType === undefined || entry.customType === query.customType) &&
|
|
191
|
+
(query.fromSeq === undefined || entry.seq >= query.fromSeq) &&
|
|
192
|
+
(query.toSeq === undefined || entry.seq <= query.toSeq)) {
|
|
193
|
+
entries.push(entry);
|
|
194
|
+
}
|
|
195
|
+
index += descending ? -1 : 1;
|
|
196
|
+
}
|
|
197
|
+
return entries;
|
|
198
|
+
}
|
|
199
|
+
scanUsage(query) {
|
|
200
|
+
const rows = [...this.usage.values()]
|
|
201
|
+
.filter((row) => query.fromSeq === undefined || row.seq >= query.fromSeq)
|
|
202
|
+
.filter((row) => query.toSeq === undefined || row.seq <= query.toSeq)
|
|
203
|
+
.sort((left, right) => (query.order === "desc" ? right.seq - left.seq : left.seq - right.seq));
|
|
204
|
+
return query.limit === undefined ? rows : rows.slice(0, Math.max(0, query.limit));
|
|
205
|
+
}
|
|
206
|
+
getStats() {
|
|
207
|
+
return this.stats;
|
|
208
|
+
}
|
|
209
|
+
snapshotEntriesAndValues() {
|
|
210
|
+
return {
|
|
211
|
+
entries: [...this.entries.values()].sort((left, right) => left.seq - right.seq),
|
|
212
|
+
scalarValues: [...this.scalarValues.values()],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=in-memory-storage-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"in-memory-storage-state.js","sourceRoot":"","sources":["../../../src/harness/session/in-memory-storage-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { addUsage, emptyUsage } from \"../utils/usage.ts\";\nimport { type CommittedWrite, type PreparedCommit, prepareStorageCommit, validateCommittedWrites } from \"./commit.ts\";\n\nexport type {\n\tCommittedEntryWrite,\n\tCommittedListAppendWrite,\n\tCommittedListDeleteWrite,\n\tCommittedUsageWrite,\n\tCommittedValueDeleteWrite,\n\tCommittedValueSetWrite,\n\tCommittedWrite,\n\tPreparedCommit,\n} from \"./commit.ts\";\n\nimport type {\n\tEntry,\n\tEntryScan,\n\tEntryStructure,\n\tSessionStats,\n\tStorageBranchScan,\n\tUsageRow,\n\tUsageScan,\n\tWrite,\n} from \"./types.ts\";\nimport {\n\ttype ListElement,\n\ttype ListReadOptions,\n\tlist,\n\tresolveListReadOptions,\n\ttype StoredValue,\n\ttype Value,\n\ttype ValueList,\n\tvalue,\n} from \"./values.ts\";\n\ninterface StoredListSnapshot {\n\taddress: ValueList<unknown>;\n\telements: ListElement<unknown>[];\n}\n\nfunction physicalKey(namespace: string, key: string): string {\n\treturn `${namespace}\\u0000${key}`;\n}\n\nfunction compareKeys(left: string, right: string): number {\n\tconst leftCodePoints = Array.from(left, (character) => character.codePointAt(0)!);\n\tconst rightCodePoints = Array.from(right, (character) => character.codePointAt(0)!);\n\tconst length = Math.min(leftCodePoints.length, rightCodePoints.length);\n\tfor (let index = 0; index < length; index++) {\n\t\tconst difference = leftCodePoints[index]! - rightCodePoints[index]!;\n\t\tif (difference !== 0) return difference;\n\t}\n\treturn leftCodePoints.length - rightCodePoints.length;\n}\n\n/**\n * Complete materialized session state for MemoryStorage and JsonlStorage.\n *\n * This is intentionally unsuitable for database backends and long-running sessions that may not fit in memory.\n * Those backends should query indexed durable state and update durable aggregates within each commit transaction.\n */\nexport class InMemoryStorageState {\n\tprivate readonly entries: Map<string, Entry>;\n\tprivate readonly entriesBySeq: Entry[];\n\tprivate readonly scalarValues: Map<string, StoredValue<unknown>>;\n\tprivate readonly listValues: Map<string, StoredListSnapshot>;\n\tprivate readonly usage: Map<string, UsageRow>;\n\tprivate stats: SessionStats;\n\tprivate nextSeq: number;\n\n\tconstructor() {\n\t\tthis.entries = new Map();\n\t\tthis.entriesBySeq = [];\n\t\tthis.scalarValues = new Map();\n\t\tthis.listValues = new Map();\n\t\tthis.usage = new Map();\n\t\tthis.stats = { messageCount: 0, usage: emptyUsage() };\n\t\tthis.nextSeq = 1;\n\t}\n\n\tprepareCommit(writes: Write[], timestamp: number): PreparedCommit {\n\t\tconst prepared = prepareStorageCommit(writes, this.nextSeq, timestamp);\n\t\tthis.validateCommitted(prepared.writes);\n\t\treturn prepared;\n\t}\n\n\tvalidateCommitted(writes: readonly CommittedWrite[]): void {\n\t\tvalidateCommittedWrites(writes, this.nextSeq, {\n\t\t\thasEntryOrUsageId: (id) => this.entries.has(id) || this.usage.has(id),\n\t\t\thasEntryId: (id) => this.entries.has(id),\n\t\t});\n\t}\n\n\t/** Apply writes already accepted by validateCommitted() and return the post-apply totals. */\n\tapplyValidated(writes: readonly CommittedWrite[]): SessionStats {\n\t\tfor (const write of writes) {\n\t\t\tswitch (write.kind) {\n\t\t\t\tcase \"entry\": {\n\t\t\t\t\tconst { kind: _kind, ...entry } = write;\n\t\t\t\t\tthis.entries.set(entry.id, entry);\n\t\t\t\t\tthis.entriesBySeq.push(entry);\n\t\t\t\t\tif (entry.type === \"message\") this.stats = { ...this.stats, messageCount: this.stats.messageCount + 1 };\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"usage\": {\n\t\t\t\t\tconst { kind: _kind, ...row } = write;\n\t\t\t\t\tthis.usage.set(row.id, row);\n\t\t\t\t\tthis.stats = { ...this.stats, usage: addUsage(this.stats.usage, row.usage) };\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"value\": {\n\t\t\t\t\tconst key = physicalKey(write.namespace, write.key);\n\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\tthis.scalarValues.delete(key);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.scalarValues.set(key, {\n\t\t\t\t\t\t\taddress: value<unknown>(write.namespace, write.key),\n\t\t\t\t\t\t\tvalue: write.value,\n\t\t\t\t\t\t\tseq: write.seq,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase \"list\": {\n\t\t\t\t\tconst key = physicalKey(write.namespace, write.key);\n\t\t\t\t\tif (write.op === \"delete\") {\n\t\t\t\t\t\tthis.listValues.delete(key);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst stored = this.listValues.get(key);\n\t\t\t\t\t\tconst element = { seq: write.seq, value: write.value };\n\t\t\t\t\t\tif (stored === undefined) {\n\t\t\t\t\t\t\tthis.listValues.set(key, {\n\t\t\t\t\t\t\t\taddress: list<unknown>(write.namespace, write.key),\n\t\t\t\t\t\t\t\telements: [element],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstored.elements.push(element);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.nextSeq = write.seq + 1;\n\t\t}\n\t\treturn this.stats;\n\t}\n\n\tadvanceNextSeq(nextSeq: number): void {\n\t\tif (!Number.isSafeInteger(nextSeq) || nextSeq < 1) {\n\t\t\tthrow new Error(`Invalid storage sequence high-water mark: ${nextSeq}`);\n\t\t}\n\t\tthis.nextSeq = Math.max(this.nextSeq, nextSeq);\n\t}\n\n\tgetEntries(ids: readonly string[]): Map<string, Entry> {\n\t\tconst found = new Map<string, Entry>();\n\t\tfor (const id of ids) {\n\t\t\tconst entry = this.entries.get(id);\n\t\t\tif (entry !== undefined) found.set(id, entry);\n\t\t}\n\t\treturn found;\n\t}\n\n\tgetValue<T>(address: Value<T>): StoredValue<T> | undefined {\n\t\treturn this.scalarValues.get(physicalKey(address.namespace, address.key)) as StoredValue<T> | undefined;\n\t}\n\n\tscanValues<T>(prefix: Value<T>): StoredValue<T>[] {\n\t\treturn [...this.scalarValues.values()]\n\t\t\t.filter((stored) => stored.address.namespace === prefix.namespace && stored.address.key.startsWith(prefix.key))\n\t\t\t.sort((left, right) => compareKeys(left.address.key, right.address.key)) as StoredValue<T>[];\n\t}\n\n\treadList<T>(address: ValueList<T>, options?: ListReadOptions): ListElement<T>[] {\n\t\tconst resolved = resolveListReadOptions(options);\n\t\tconst elements = this.listValues.get(physicalKey(address.namespace, address.key))?.elements ?? [];\n\t\tconst filtered = elements.filter((element) => {\n\t\t\tif (resolved.cursor === undefined) return true;\n\t\t\treturn resolved.order === \"asc\" ? element.seq > resolved.cursor.seq : element.seq < resolved.cursor.seq;\n\t\t});\n\t\tconst ordered = resolved.order === \"asc\" ? filtered : [...filtered].reverse();\n\t\treturn ordered.slice(0, resolved.limit) as ListElement<T>[];\n\t}\n\n\tscanBranch(query: StorageBranchScan): Entry[] {\n\t\tconst start = this.entries.get(query.start);\n\t\tif (start === undefined) throw new Error(`Unknown branch start: ${query.start}`);\n\n\t\tconst path: Entry[] = [];\n\t\tlet entry: Entry | undefined = start;\n\t\twhile (entry !== undefined) {\n\t\t\tpath.push(entry);\n\t\t\tif (entry.parentId === null) break;\n\t\t\tentry = this.entries.get(entry.parentId);\n\t\t\tif (entry === undefined) throw new Error(\"Corrupt branch: missing parent\");\n\t\t}\n\t\tif (query.order === \"oldestFirst\") path.reverse();\n\n\t\tconst stopped: Entry[] = [];\n\t\tfor (const candidate of path) {\n\t\t\tstopped.push(candidate);\n\t\t\tif (candidate.id === query.stopAtId || candidate.type === query.stopAtType) break;\n\t\t}\n\t\tconst filtered = stopped\n\t\t\t.filter((candidate) => query.type === undefined || candidate.type === query.type)\n\t\t\t.filter((candidate) => query.customType === undefined || candidate.customType === query.customType)\n\t\t\t.filter(\n\t\t\t\t(candidate) =>\n\t\t\t\t\tquery.cursor === undefined ||\n\t\t\t\t\t(query.order === \"oldestFirst\" ? candidate.seq > query.cursor.seq : candidate.seq < query.cursor.seq),\n\t\t\t);\n\t\treturn query.limit === undefined ? filtered : filtered.slice(0, Math.max(0, query.limit));\n\t}\n\n\tscanBranchStructure(query: StorageBranchScan): EntryStructure[] {\n\t\treturn this.scanBranch(query).map((entry) => ({\n\t\t\tid: entry.id,\n\t\t\tparentId: entry.parentId,\n\t\t\tseq: entry.seq,\n\t\t\ttimestamp: entry.timestamp,\n\t\t\ttype: entry.type,\n\t\t\t...(entry.customType === undefined ? {} : { customType: entry.customType }),\n\t\t}));\n\t}\n\n\tscanEntries(query: EntryScan): Entry[] {\n\t\tconst limit = query.limit === undefined ? Number.POSITIVE_INFINITY : Math.max(0, Math.trunc(query.limit));\n\t\tconst entries: Entry[] = [];\n\t\tconst descending = query.order === \"desc\";\n\t\tlet index = descending ? this.entriesBySeq.length - 1 : 0;\n\t\twhile (index >= 0 && index < this.entriesBySeq.length && entries.length < limit) {\n\t\t\tconst entry = this.entriesBySeq[index]!;\n\t\t\tif (\n\t\t\t\t(query.type === undefined || entry.type === query.type) &&\n\t\t\t\t(query.customType === undefined || entry.customType === query.customType) &&\n\t\t\t\t(query.fromSeq === undefined || entry.seq >= query.fromSeq) &&\n\t\t\t\t(query.toSeq === undefined || entry.seq <= query.toSeq)\n\t\t\t) {\n\t\t\t\tentries.push(entry);\n\t\t\t}\n\t\t\tindex += descending ? -1 : 1;\n\t\t}\n\t\treturn entries;\n\t}\n\n\tscanUsage(query: UsageScan): UsageRow[] {\n\t\tconst rows = [...this.usage.values()]\n\t\t\t.filter((row) => query.fromSeq === undefined || row.seq >= query.fromSeq)\n\t\t\t.filter((row) => query.toSeq === undefined || row.seq <= query.toSeq)\n\t\t\t.sort((left, right) => (query.order === \"desc\" ? right.seq - left.seq : left.seq - right.seq));\n\t\treturn query.limit === undefined ? rows : rows.slice(0, Math.max(0, query.limit));\n\t}\n\n\tgetStats(): SessionStats {\n\t\treturn this.stats;\n\t}\n\n\tsnapshotEntriesAndValues(): { entries: Entry[]; scalarValues: StoredValue<unknown>[] } {\n\t\treturn {\n\t\t\tentries: [...this.entries.values()].sort((left, right) => left.seq - right.seq),\n\t\t\tscalarValues: [...this.scalarValues.values()],\n\t\t};\n\t}\n}\n"]}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export {
|
|
4
|
-
export
|
|
5
|
-
export
|
|
1
|
+
export type { CommittedEntryWrite, CommittedListAppendWrite, CommittedListDeleteWrite, CommittedUsageWrite, CommittedValueDeleteWrite, CommittedValueSetWrite, CommittedWrite, CommitValidationState, PreparedCommit, } from "./commit.ts";
|
|
2
|
+
export { commitWrite, insertEntry, insertUsage, prepareStorageCommit, validateCommittedWrites } from "./commit.ts";
|
|
3
|
+
export { createForkSnapshot, type ForkSourceSnapshot } from "./fork.ts";
|
|
4
|
+
export { classifyForkAddress, type ForkDisposition } from "./fork-policy.ts";
|
|
5
|
+
export { JSONL_STORAGE_VERSION, type JsonlSessionCreateOptions, type JsonlSessionListOptions, type JsonlSessionMetadata, JsonlSessionRepo, type JsonlSessionRepoOptions, } from "./jsonl/index.ts";
|
|
6
|
+
export type { MemorySessionRepoOptions } from "./memory.ts";
|
|
7
|
+
export { MemorySessionRepo } from "./memory.ts";
|
|
8
|
+
export { SessionBranchExistsError, SessionInvalidBranchError, SessionInvariantError, SessionPendingAssistantMessageError, SessionUnknownTargetError, StorageBackedSession, type StorageBackedSessionOptions, } from "./session.ts";
|
|
6
9
|
export * from "./types.ts";
|
|
10
|
+
export * from "./values.ts";
|
|
7
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/harness/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/harness/session/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,mBAAmB,EACnB,yBAAyB,EACzB,sBAAsB,EACtB,cAAc,EACd,qBAAqB,EACrB,cAAc,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACN,qBAAqB,EACrB,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,KAAK,uBAAuB,GAC5B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACN,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,mCAAmC,EACnC,yBAAyB,EACzB,oBAAoB,EACpB,KAAK,2BAA2B,GAChC,MAAM,cAAc,CAAC;AACtB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC","sourcesContent":["export type {\n\tCommittedEntryWrite,\n\tCommittedListAppendWrite,\n\tCommittedListDeleteWrite,\n\tCommittedUsageWrite,\n\tCommittedValueDeleteWrite,\n\tCommittedValueSetWrite,\n\tCommittedWrite,\n\tCommitValidationState,\n\tPreparedCommit,\n} from \"./commit.ts\";\nexport { commitWrite, insertEntry, insertUsage, prepareStorageCommit, validateCommittedWrites } from \"./commit.ts\";\nexport { createForkSnapshot, type ForkSourceSnapshot } from \"./fork.ts\";\nexport { classifyForkAddress, type ForkDisposition } from \"./fork-policy.ts\";\nexport {\n\tJSONL_STORAGE_VERSION,\n\ttype JsonlSessionCreateOptions,\n\ttype JsonlSessionListOptions,\n\ttype JsonlSessionMetadata,\n\tJsonlSessionRepo,\n\ttype JsonlSessionRepoOptions,\n} from \"./jsonl/index.ts\";\nexport type { MemorySessionRepoOptions } from \"./memory.ts\";\nexport { MemorySessionRepo } from \"./memory.ts\";\nexport {\n\tSessionBranchExistsError,\n\tSessionInvalidBranchError,\n\tSessionInvariantError,\n\tSessionPendingAssistantMessageError,\n\tSessionUnknownTargetError,\n\tStorageBackedSession,\n\ttype StorageBackedSessionOptions,\n} from \"./session.ts\";\nexport * from \"./types.ts\";\nexport * from \"./values.ts\";\n"]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
export
|
|
2
|
-
export {
|
|
3
|
-
export
|
|
4
|
-
export
|
|
1
|
+
export { commitWrite, insertEntry, insertUsage, prepareStorageCommit, validateCommittedWrites } from "./commit.js";
|
|
2
|
+
export { createForkSnapshot } from "./fork.js";
|
|
3
|
+
export { classifyForkAddress } from "./fork-policy.js";
|
|
4
|
+
export { JSONL_STORAGE_VERSION, JsonlSessionRepo, } from "./jsonl/index.js";
|
|
5
|
+
export { MemorySessionRepo } from "./memory.js";
|
|
6
|
+
export { SessionBranchExistsError, SessionInvalidBranchError, SessionInvariantError, SessionPendingAssistantMessageError, SessionUnknownTargetError, StorageBackedSession, } from "./session.js";
|
|
5
7
|
export * from "./types.js";
|
|
8
|
+
export * from "./values.js";
|
|
6
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/harness/session/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/harness/session/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACnH,OAAO,EAAE,kBAAkB,EAA2B,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAwB,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EACN,qBAAqB,EAIrB,gBAAgB,GAEhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EACN,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,mCAAmC,EACnC,yBAAyB,EACzB,oBAAoB,GAEpB,MAAM,cAAc,CAAC;AACtB,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC","sourcesContent":["export type {\n\tCommittedEntryWrite,\n\tCommittedListAppendWrite,\n\tCommittedListDeleteWrite,\n\tCommittedUsageWrite,\n\tCommittedValueDeleteWrite,\n\tCommittedValueSetWrite,\n\tCommittedWrite,\n\tCommitValidationState,\n\tPreparedCommit,\n} from \"./commit.ts\";\nexport { commitWrite, insertEntry, insertUsage, prepareStorageCommit, validateCommittedWrites } from \"./commit.ts\";\nexport { createForkSnapshot, type ForkSourceSnapshot } from \"./fork.ts\";\nexport { classifyForkAddress, type ForkDisposition } from \"./fork-policy.ts\";\nexport {\n\tJSONL_STORAGE_VERSION,\n\ttype JsonlSessionCreateOptions,\n\ttype JsonlSessionListOptions,\n\ttype JsonlSessionMetadata,\n\tJsonlSessionRepo,\n\ttype JsonlSessionRepoOptions,\n} from \"./jsonl/index.ts\";\nexport type { MemorySessionRepoOptions } from \"./memory.ts\";\nexport { MemorySessionRepo } from \"./memory.ts\";\nexport {\n\tSessionBranchExistsError,\n\tSessionInvalidBranchError,\n\tSessionInvariantError,\n\tSessionPendingAssistantMessageError,\n\tSessionUnknownTargetError,\n\tStorageBackedSession,\n\ttype StorageBackedSessionOptions,\n} from \"./session.ts\";\nexport * from \"./types.ts\";\nexport * from \"./values.ts\";\n"]}
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { type Result } from "../../types.ts";
|
|
2
|
-
import type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import { type JsonlStorageHeader } from "./types.ts";
|
|
3
|
+
export interface LegacyV3SessionHeader {
|
|
4
|
+
type: "session";
|
|
5
|
+
version: 3;
|
|
6
|
+
id: string;
|
|
7
|
+
timestamp: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
parentSession?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function isLegacyV3SessionHeader(value: unknown): value is LegacyV3SessionHeader;
|
|
12
|
+
export declare function isJsonlStorageHeader(value: unknown): value is JsonlStorageHeader;
|
|
13
|
+
export type JsonlParsedSessionHeader = {
|
|
14
|
+
format: "v4";
|
|
15
|
+
header: JsonlStorageHeader;
|
|
16
|
+
} | {
|
|
17
|
+
format: "v3-legacy";
|
|
18
|
+
header: LegacyV3SessionHeader;
|
|
19
|
+
};
|
|
20
|
+
export declare function parseJsonlSessionHeader(line: string): Result<JsonlParsedSessionHeader, Error>;
|
|
10
21
|
//# sourceMappingURL=codec.d.ts.map
|