@cleocode/core 2026.9.24 → 2026.9.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/import-tasks.d.ts.map +1 -1
- package/dist/admin/import-tasks.js +5 -2
- package/dist/admin/import-tasks.js.map +1 -1
- package/dist/admin/import.d.ts.map +1 -1
- package/dist/admin/import.js +7 -2
- package/dist/admin/import.js.map +1 -1
- package/dist/audit-prune.d.ts +32 -0
- package/dist/audit-prune.d.ts.map +1 -1
- package/dist/audit-prune.js +37 -3
- package/dist/audit-prune.js.map +1 -1
- package/dist/build-provenance.json +2 -2
- package/dist/cloud/crypto.d.ts +1 -2
- package/dist/cloud/crypto.d.ts.map +1 -1
- package/dist/cloud/crypto.js +1 -11
- package/dist/cloud/crypto.js.map +1 -1
- package/dist/cloud/index.d.ts +1 -0
- package/dist/cloud/index.d.ts.map +1 -1
- package/dist/cloud/index.js +1 -0
- package/dist/cloud/index.js.map +1 -1
- package/dist/cloud/nexus-auth.d.ts +26 -1
- package/dist/cloud/nexus-auth.d.ts.map +1 -1
- package/dist/cloud/nexus-auth.js +61 -32
- package/dist/cloud/nexus-auth.js.map +1 -1
- package/dist/cloud/nexus-credentials.js +2 -2
- package/dist/cloud/nexus-credentials.js.map +1 -1
- package/dist/cloud/nexus-device.d.ts +809 -0
- package/dist/cloud/nexus-device.d.ts.map +1 -0
- package/dist/cloud/nexus-device.js +1680 -0
- package/dist/cloud/nexus-device.js.map +1 -0
- package/dist/cloud/nexus-enrol.d.ts +210 -0
- package/dist/cloud/nexus-enrol.d.ts.map +1 -0
- package/dist/cloud/nexus-enrol.js +1023 -0
- package/dist/cloud/nexus-enrol.js.map +1 -0
- package/dist/cloud/nexus-link.d.ts +3 -0
- package/dist/cloud/nexus-link.d.ts.map +1 -1
- package/dist/cloud/nexus-link.js +38 -4
- package/dist/cloud/nexus-link.js.map +1 -1
- package/dist/cloud/signing.d.ts +20 -0
- package/dist/cloud/signing.d.ts.map +1 -1
- package/dist/cloud/signing.js +14 -0
- package/dist/cloud/signing.js.map +1 -1
- package/dist/cloud/uuidv7.d.ts +9 -0
- package/dist/cloud/uuidv7.d.ts.map +1 -0
- package/dist/cloud/uuidv7.js +19 -0
- package/dist/cloud/uuidv7.js.map +1 -0
- package/dist/crypto/credentials.d.ts +61 -0
- package/dist/crypto/credentials.d.ts.map +1 -1
- package/dist/crypto/credentials.js +154 -58
- package/dist/crypto/credentials.js.map +1 -1
- package/dist/decide/bench/index.d.ts +1 -1
- package/dist/decide/bench/index.d.ts.map +1 -1
- package/dist/decide/bench/index.js +1 -1
- package/dist/decide/bench/index.js.map +1 -1
- package/dist/decide/bench/operation.d.ts +1 -1
- package/dist/decide/bench/operation.d.ts.map +1 -1
- package/dist/decide/bench/operation.js +1 -1
- package/dist/decide/bench/operation.js.map +1 -1
- package/dist/decide/bench/profiles.d.ts +50 -22
- package/dist/decide/bench/profiles.d.ts.map +1 -1
- package/dist/decide/bench/profiles.js +103 -59
- package/dist/decide/bench/profiles.js.map +1 -1
- package/dist/decide/bench/report.d.ts.map +1 -1
- package/dist/decide/bench/report.js +6 -1
- package/dist/decide/bench/report.js.map +1 -1
- package/dist/decide/bench/runner.d.ts +6 -1
- package/dist/decide/bench/runner.d.ts.map +1 -1
- package/dist/decide/bench/runner.js +1 -0
- package/dist/decide/bench/runner.js.map +1 -1
- package/dist/decide/client.d.ts.map +1 -1
- package/dist/decide/client.js +11 -5
- package/dist/decide/client.js.map +1 -1
- package/dist/decide/jev-wire.d.ts +31 -1
- package/dist/decide/jev-wire.d.ts.map +1 -1
- package/dist/decide/jev-wire.js +61 -7
- package/dist/decide/jev-wire.js.map +1 -1
- package/dist/docs/export-document.js +12907 -10622
- package/dist/docs/export-document.js.map +3 -3
- package/dist/doctor/dependency-cycles.d.ts +41 -0
- package/dist/doctor/dependency-cycles.d.ts.map +1 -0
- package/dist/doctor/dependency-cycles.js +39 -0
- package/dist/doctor/dependency-cycles.js.map +1 -0
- package/dist/doctor/index.d.ts +2 -0
- package/dist/doctor/index.d.ts.map +1 -1
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/index.js.map +1 -1
- package/dist/doctor/orphan-ac-bindings.d.ts +64 -0
- package/dist/doctor/orphan-ac-bindings.d.ts.map +1 -0
- package/dist/doctor/orphan-ac-bindings.js +59 -0
- package/dist/doctor/orphan-ac-bindings.js.map +1 -0
- package/dist/doctor/projects.d.ts.map +1 -1
- package/dist/doctor/projects.js +43 -29
- package/dist/doctor/projects.js.map +1 -1
- package/dist/doctor/row-identity.d.ts +42 -0
- package/dist/doctor/row-identity.d.ts.map +1 -0
- package/dist/doctor/row-identity.js +151 -0
- package/dist/doctor/row-identity.js.map +1 -0
- package/dist/doctor/twin-collapse.d.ts +58 -2
- package/dist/doctor/twin-collapse.d.ts.map +1 -1
- package/dist/doctor/twin-collapse.js +212 -14
- package/dist/doctor/twin-collapse.js.map +1 -1
- package/dist/error-catalog.d.ts.map +1 -1
- package/dist/error-catalog.js +4 -0
- package/dist/error-catalog.js.map +1 -1
- package/dist/error-registry.d.ts.map +1 -1
- package/dist/error-registry.js +8 -0
- package/dist/error-registry.js.map +1 -1
- package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
- package/dist/lifecycle/verification/satisfies-validator.js +10 -0
- package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
- package/dist/llm/plugin-facade.js +17767 -15482
- package/dist/llm/plugin-facade.js.map +3 -3
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +19 -10
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/manifest-identity.d.ts +171 -0
- package/dist/memory/manifest-identity.d.ts.map +1 -0
- package/dist/memory/manifest-identity.js +345 -0
- package/dist/memory/manifest-identity.js.map +1 -0
- package/dist/memory/mental-model-queue.d.ts +14 -4
- package/dist/memory/mental-model-queue.d.ts.map +1 -1
- package/dist/memory/mental-model-queue.js +64 -35
- package/dist/memory/mental-model-queue.js.map +1 -1
- package/dist/memory/pipeline-manifest-sqlite.d.ts +47 -5
- package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
- package/dist/memory/pipeline-manifest-sqlite.js +130 -14
- package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
- package/dist/memory/retrieval/observe.d.ts.map +1 -1
- package/dist/memory/retrieval/observe.js +2 -0
- package/dist/memory/retrieval/observe.js.map +1 -1
- package/dist/memory/transcript-scanner.js +1 -1
- package/dist/nexus/deps.d.ts.map +1 -1
- package/dist/nexus/deps.js +7 -14
- package/dist/nexus/deps.js.map +1 -1
- package/dist/nexus/discover.d.ts.map +1 -1
- package/dist/nexus/discover.js +6 -9
- package/dist/nexus/discover.js.map +1 -1
- package/dist/nexus/git-state.d.ts.map +1 -1
- package/dist/nexus/git-state.js +10 -1
- package/dist/nexus/git-state.js.map +1 -1
- package/dist/nexus/projects-clean.d.ts.map +1 -1
- package/dist/nexus/projects-clean.js +22 -11
- package/dist/nexus/projects-clean.js.map +1 -1
- package/dist/nexus/projects-scan.d.ts.map +1 -1
- package/dist/nexus/projects-scan.js +8 -13
- package/dist/nexus/projects-scan.js.map +1 -1
- package/dist/nexus/query.d.ts.map +1 -1
- package/dist/nexus/query.js +4 -12
- package/dist/nexus/query.js.map +1 -1
- package/dist/nexus/registry-roots.d.ts +5 -2
- package/dist/nexus/registry-roots.d.ts.map +1 -1
- package/dist/nexus/registry-roots.js +8 -10
- package/dist/nexus/registry-roots.js.map +1 -1
- package/dist/nexus/registry.d.ts +18 -0
- package/dist/nexus/registry.d.ts.map +1 -1
- package/dist/nexus/registry.js +37 -16
- package/dist/nexus/registry.js.map +1 -1
- package/dist/nexus/workspace.d.ts.map +1 -1
- package/dist/nexus/workspace.js +54 -4
- package/dist/nexus/workspace.js.map +1 -1
- package/dist/orchestrate/lifecycle-ops.js +1 -1
- package/dist/orchestrate/lifecycle-ops.js.map +1 -1
- package/dist/orchestrate/pivot.d.ts.map +1 -1
- package/dist/orchestrate/pivot.js +4 -2
- package/dist/orchestrate/pivot.js.map +1 -1
- package/dist/orchestrate/query-ops.d.ts.map +1 -1
- package/dist/orchestrate/query-ops.js +3 -3
- package/dist/orchestrate/query-ops.js.map +1 -1
- package/dist/orchestrate/spawn-ops.js +1 -1
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/orchestrate/worktree-complete.d.ts.map +1 -1
- package/dist/orchestrate/worktree-complete.js +40 -2
- package/dist/orchestrate/worktree-complete.js.map +1 -1
- package/dist/orchestration/index.js +1 -1
- package/dist/orchestration/index.js.map +1 -1
- package/dist/orchestration/lead-rollup.d.ts.map +1 -1
- package/dist/orchestration/lead-rollup.js +3 -3
- package/dist/orchestration/lead-rollup.js.map +1 -1
- package/dist/orchestration/parallel.js +1 -1
- package/dist/orchestration/parallel.js.map +1 -1
- package/dist/orchestration/spawn-prompt.d.ts +26 -0
- package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
- package/dist/orchestration/spawn-prompt.js +62 -91
- package/dist/orchestration/spawn-prompt.js.map +1 -1
- package/dist/orchestration/wave-topic.d.ts +4 -2
- package/dist/orchestration/wave-topic.d.ts.map +1 -1
- package/dist/orchestration/wave-topic.js +6 -4
- package/dist/orchestration/wave-topic.js.map +1 -1
- package/dist/orchestration/waves.d.ts +2 -1
- package/dist/orchestration/waves.d.ts.map +1 -1
- package/dist/orchestration/waves.js +4 -3
- package/dist/orchestration/waves.js.map +1 -1
- package/dist/phases/index.d.ts.map +1 -1
- package/dist/phases/index.js +4 -2
- package/dist/phases/index.js.map +1 -1
- package/dist/release/ci-evidence.d.ts +190 -0
- package/dist/release/ci-evidence.d.ts.map +1 -1
- package/dist/release/ci-evidence.js +436 -4
- package/dist/release/ci-evidence.js.map +1 -1
- package/dist/sdk/validator-ac-pull.d.ts.map +1 -1
- package/dist/sdk/validator-ac-pull.js +2 -1
- package/dist/sdk/validator-ac-pull.js.map +1 -1
- package/dist/selfimprove/fix-gen.js +12807 -10522
- package/dist/selfimprove/fix-gen.js.map +3 -3
- package/dist/sentient/cross-project-hygiene.d.ts +5 -0
- package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
- package/dist/sentient/cross-project-hygiene.js +7 -1
- package/dist/sentient/cross-project-hygiene.js.map +1 -1
- package/dist/sentient/propose-tick.d.ts.map +1 -1
- package/dist/sentient/propose-tick.js +2 -3
- package/dist/sentient/propose-tick.js.map +1 -1
- package/dist/sentient/stage-drift-tick.d.ts.map +1 -1
- package/dist/sentient/stage-drift-tick.js +2 -3
- package/dist/sentient/stage-drift-tick.js.map +1 -1
- package/dist/session/engine-ops.d.ts.map +1 -1
- package/dist/session/engine-ops.js +77 -49
- package/dist/session/engine-ops.js.map +1 -1
- package/dist/sessions/focus-state-store.d.ts +69 -23
- package/dist/sessions/focus-state-store.d.ts.map +1 -1
- package/dist/sessions/focus-state-store.js +113 -27
- package/dist/sessions/focus-state-store.js.map +1 -1
- package/dist/sessions/handoff.js +1 -1
- package/dist/sessions/handoff.js.map +1 -1
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +24 -13
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/terminal-identity.d.ts +165 -17
- package/dist/sessions/terminal-identity.d.ts.map +1 -1
- package/dist/sessions/terminal-identity.js +341 -32
- package/dist/sessions/terminal-identity.js.map +1 -1
- package/dist/skills/manifests/research.js +2 -0
- package/dist/skills/manifests/research.js.map +1 -1
- package/dist/skills/orchestrator/startup.js +2 -2
- package/dist/skills/orchestrator/startup.js.map +1 -1
- package/dist/skills/orchestrator/validator.d.ts.map +1 -1
- package/dist/skills/orchestrator/validator.js +9 -2
- package/dist/skills/orchestrator/validator.js.map +1 -1
- package/dist/skills/validation.d.ts +4 -1
- package/dist/skills/validation.d.ts.map +1 -1
- package/dist/skills/validation.js +11 -3
- package/dist/skills/validation.js.map +1 -1
- package/dist/snapshot/index.d.ts +4 -0
- package/dist/snapshot/index.d.ts.map +1 -1
- package/dist/snapshot/index.js +50 -3
- package/dist/snapshot/index.js.map +1 -1
- package/dist/spawn/branch-lock.d.ts +111 -7
- package/dist/spawn/branch-lock.d.ts.map +1 -1
- package/dist/spawn/branch-lock.js +296 -8
- package/dist/spawn/branch-lock.js.map +1 -1
- package/dist/store/ac-binding-prune.d.ts +144 -0
- package/dist/store/ac-binding-prune.d.ts.map +1 -0
- package/dist/store/ac-binding-prune.js +293 -0
- package/dist/store/ac-binding-prune.js.map +1 -0
- package/dist/store/agent-registry-store.d.ts.map +1 -1
- package/dist/store/agent-registry-store.js +3 -2
- package/dist/store/agent-registry-store.js.map +1 -1
- package/dist/store/backup-sidecar.d.ts +85 -2
- package/dist/store/backup-sidecar.d.ts.map +1 -1
- package/dist/store/backup-sidecar.js +173 -1
- package/dist/store/backup-sidecar.js.map +1 -1
- package/dist/store/conduit-sqlite.d.ts.map +1 -1
- package/dist/store/conduit-sqlite.js +3 -2
- package/dist/store/conduit-sqlite.js.map +1 -1
- package/dist/store/credential-transfer.d.ts.map +1 -1
- package/dist/store/credential-transfer.js +3 -0
- package/dist/store/credential-transfer.js.map +1 -1
- package/dist/store/db-helpers.d.ts +32 -13
- package/dist/store/db-helpers.d.ts.map +1 -1
- package/dist/store/db-helpers.js +144 -40
- package/dist/store/db-helpers.js.map +1 -1
- package/dist/store/dependency-cycles.d.ts +164 -0
- package/dist/store/dependency-cycles.d.ts.map +1 -0
- package/dist/store/dependency-cycles.js +360 -0
- package/dist/store/dependency-cycles.js.map +1 -0
- package/dist/store/display-id-alias.d.ts +585 -0
- package/dist/store/display-id-alias.d.ts.map +1 -0
- package/dist/store/display-id-alias.js +1538 -0
- package/dist/store/display-id-alias.js.map +1 -0
- package/dist/store/dual-scope-db.d.ts.map +1 -1
- package/dist/store/dual-scope-db.js +48 -0
- package/dist/store/dual-scope-db.js.map +1 -1
- package/dist/store/exodus/migrate.d.ts.map +1 -1
- package/dist/store/exodus/migrate.js +8 -1
- package/dist/store/exodus/migrate.js.map +1 -1
- package/dist/store/exodus/reconcile.d.ts.map +1 -1
- package/dist/store/exodus/reconcile.js +7 -2
- package/dist/store/exodus/reconcile.js.map +1 -1
- package/dist/store/exodus/recovery.d.ts.map +1 -1
- package/dist/store/exodus/recovery.js +20 -1
- package/dist/store/exodus/recovery.js.map +1 -1
- package/dist/store/global-salt.d.ts +35 -0
- package/dist/store/global-salt.d.ts.map +1 -1
- package/dist/store/global-salt.js +136 -16
- package/dist/store/global-salt.js.map +1 -1
- package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
- package/dist/store/legacy-tasks-lineage.js +19 -2
- package/dist/store/legacy-tasks-lineage.js.map +1 -1
- package/dist/store/migration-sqlite.d.ts.map +1 -1
- package/dist/store/migration-sqlite.js +19 -11
- package/dist/store/migration-sqlite.js.map +1 -1
- package/dist/store/portable-bundle-scan.d.ts.map +1 -1
- package/dist/store/portable-bundle-scan.js +6 -0
- package/dist/store/portable-bundle-scan.js.map +1 -1
- package/dist/store/row-identity-flag.d.ts +26 -0
- package/dist/store/row-identity-flag.d.ts.map +1 -0
- package/dist/store/row-identity-flag.js +31 -0
- package/dist/store/row-identity-flag.js.map +1 -0
- package/dist/store/row-identity-registry.d.ts +61 -0
- package/dist/store/row-identity-registry.d.ts.map +1 -0
- package/dist/store/row-identity-registry.js +206 -0
- package/dist/store/row-identity-registry.js.map +1 -0
- package/dist/store/row-identity.d.ts +480 -0
- package/dist/store/row-identity.d.ts.map +1 -0
- package/dist/store/row-identity.js +1509 -0
- package/dist/store/row-identity.js.map +1 -0
- package/dist/store/safety-data-accessor.d.ts +5 -2
- package/dist/store/safety-data-accessor.d.ts.map +1 -1
- package/dist/store/safety-data-accessor.js +9 -2
- package/dist/store/safety-data-accessor.js.map +1 -1
- package/dist/store/schema/attachments.d.ts +1 -1
- package/dist/store/schema/audit.d.ts +4 -4
- package/dist/store/schema/background-jobs.d.ts +1 -1
- package/dist/store/schema/cleo-global/nexus.d.ts +1 -1
- package/dist/store/schema/cleo-global/skills.d.ts +2 -2
- package/dist/store/schema/cleo-project/audit.d.ts +4 -4
- package/dist/store/schema/cleo-project/docs.d.ts +1 -1
- package/dist/store/schema/cleo-project/lifecycle.d.ts +4 -4
- package/dist/store/schema/cleo-project/nexus-graph.d.ts +3 -3
- package/dist/store/schema/cleo-project/provenance-commits.d.ts +2 -2
- package/dist/store/schema/cleo-project/provenance-rest.d.ts +3 -3
- package/dist/store/schema/cleo-project/runtime.d.ts +3 -3
- package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts +87 -1
- package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts.map +1 -1
- package/dist/store/schema/cleo-project/tasks-core-batch2.js +35 -0
- package/dist/store/schema/cleo-project/tasks-core-batch2.js.map +1 -1
- package/dist/store/schema/cleo-project/tasks-core.d.ts +183 -7
- package/dist/store/schema/cleo-project/tasks-core.d.ts.map +1 -1
- package/dist/store/schema/cleo-project/tasks-core.js +52 -1
- package/dist/store/schema/cleo-project/tasks-core.js.map +1 -1
- package/dist/store/schema/cleo-shared/brain.d.ts +6 -6
- package/dist/store/schema/lifecycle.d.ts +4 -4
- package/dist/store/schema/manifest.d.ts +1 -1
- package/dist/store/schema/memory-schema.d.ts +5 -5
- package/dist/store/schema/nexus-schema.d.ts +3 -3
- package/dist/store/schema/provenance/releases.d.ts +1 -1
- package/dist/store/schema/skills-schema.d.ts +2 -2
- package/dist/store/schema/tasks.d.ts +6 -6
- package/dist/store/session-store.d.ts +63 -3
- package/dist/store/session-store.d.ts.map +1 -1
- package/dist/store/session-store.js +121 -8
- package/dist/store/session-store.js.map +1 -1
- package/dist/store/split-brain-import.d.ts +2 -14
- package/dist/store/split-brain-import.d.ts.map +1 -1
- package/dist/store/split-brain-import.js +40 -19
- package/dist/store/split-brain-import.js.map +1 -1
- package/dist/store/sqlite-data-accessor.d.ts +326 -2
- package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
- package/dist/store/sqlite-data-accessor.js +782 -49
- package/dist/store/sqlite-data-accessor.js.map +1 -1
- package/dist/store/sync/clock-store.d.ts +67 -0
- package/dist/store/sync/clock-store.d.ts.map +1 -0
- package/dist/store/sync/clock-store.js +117 -0
- package/dist/store/sync/clock-store.js.map +1 -0
- package/dist/store/sync/flags.d.ts +51 -0
- package/dist/store/sync/flags.d.ts.map +1 -0
- package/dist/store/sync/flags.js +81 -0
- package/dist/store/sync/flags.js.map +1 -0
- package/dist/store/sync/hlc.d.ts +115 -0
- package/dist/store/sync/hlc.d.ts.map +1 -0
- package/dist/store/sync/hlc.js +172 -0
- package/dist/store/sync/hlc.js.map +1 -0
- package/dist/store/sync/index.d.ts +20 -0
- package/dist/store/sync/index.d.ts.map +1 -0
- package/dist/store/sync/index.js +20 -0
- package/dist/store/sync/index.js.map +1 -0
- package/dist/store/sync/replica-registry.d.ts +85 -0
- package/dist/store/sync/replica-registry.d.ts.map +1 -0
- package/dist/store/sync/replica-registry.js +147 -0
- package/dist/store/sync/replica-registry.js.map +1 -0
- package/dist/store/sync/replica.d.ts +181 -0
- package/dist/store/sync/replica.d.ts.map +1 -0
- package/dist/store/sync/replica.js +305 -0
- package/dist/store/sync/replica.js.map +1 -0
- package/dist/store/sync/schema.d.ts +68 -0
- package/dist/store/sync/schema.d.ts.map +1 -0
- package/dist/store/sync/schema.js +130 -0
- package/dist/store/sync/schema.js.map +1 -0
- package/dist/store/sync/skew-hold.d.ts +71 -0
- package/dist/store/sync/skew-hold.d.ts.map +1 -0
- package/dist/store/sync/skew-hold.js +89 -0
- package/dist/store/sync/skew-hold.js.map +1 -0
- package/dist/store/table-classification.d.ts +10 -8
- package/dist/store/table-classification.d.ts.map +1 -1
- package/dist/store/table-classification.js +93 -25
- package/dist/store/table-classification.js.map +1 -1
- package/dist/store/tasks-sqlite.d.ts.map +1 -1
- package/dist/store/tasks-sqlite.js +23 -3
- package/dist/store/tasks-sqlite.js.map +1 -1
- package/dist/store/twin-collapse.d.ts +113 -2
- package/dist/store/twin-collapse.d.ts.map +1 -1
- package/dist/store/twin-collapse.js +247 -19
- package/dist/store/twin-collapse.js.map +1 -1
- package/dist/store/umbrella-data-accessor.d.ts +5 -2
- package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
- package/dist/store/umbrella-data-accessor.js +9 -2
- package/dist/store/umbrella-data-accessor.js.map +1 -1
- package/dist/store/validation-schemas.d.ts +241 -49
- package/dist/store/validation-schemas.d.ts.map +1 -1
- package/dist/system/health.d.ts +2 -0
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/health.js +57 -0
- package/dist/system/health.js.map +1 -1
- package/dist/system/project-health.d.ts +9 -2
- package/dist/system/project-health.d.ts.map +1 -1
- package/dist/system/project-health.js +8 -3
- package/dist/system/project-health.js.map +1 -1
- package/dist/task-work/index.d.ts.map +1 -1
- package/dist/task-work/index.js +9 -6
- package/dist/task-work/index.js.map +1 -1
- package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
- package/dist/tasks/ac-coverage-gate.js +3 -0
- package/dist/tasks/ac-coverage-gate.js.map +1 -1
- package/dist/tasks/ac-table.d.ts +35 -7
- package/dist/tasks/ac-table.d.ts.map +1 -1
- package/dist/tasks/ac-table.js +119 -14
- package/dist/tasks/ac-table.js.map +1 -1
- package/dist/tasks/add.d.ts.map +1 -1
- package/dist/tasks/add.js +48 -2
- package/dist/tasks/add.js.map +1 -1
- package/dist/tasks/analyze.d.ts.map +1 -1
- package/dist/tasks/analyze.js +3 -2
- package/dist/tasks/analyze.js.map +1 -1
- package/dist/tasks/backfill-child-projections.js +47 -6
- package/dist/tasks/backfill-child-projections.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +6 -1
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/completion-evaluation.d.ts.map +1 -1
- package/dist/tasks/completion-evaluation.js +3 -0
- package/dist/tasks/completion-evaluation.js.map +1 -1
- package/dist/tasks/evidence.d.ts +19 -1
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +93 -21
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/infer-add-params.js +1 -1
- package/dist/tasks/infer-add-params.js.map +1 -1
- package/dist/tasks/task-context.d.ts.map +1 -1
- package/dist/tasks/task-context.js +3 -1
- package/dist/tasks/task-context.js.map +1 -1
- package/dist/tasks/task-import.d.ts.map +1 -1
- package/dist/tasks/task-import.js +11 -3
- package/dist/tasks/task-import.js.map +1 -1
- package/dist/tasks/task-next.d.ts +5 -1
- package/dist/tasks/task-next.d.ts.map +1 -1
- package/dist/tasks/task-next.js +7 -2
- package/dist/tasks/task-next.js.map +1 -1
- package/dist/validation/compliance.d.ts +5 -1
- package/dist/validation/compliance.d.ts.map +1 -1
- package/dist/validation/compliance.js +24 -3
- package/dist/validation/compliance.js.map +1 -1
- package/dist/validation/engine-ops.d.ts.map +1 -1
- package/dist/validation/engine-ops.js +3 -2
- package/dist/validation/engine-ops.js.map +1 -1
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/validation/protocol-common.d.ts +47 -2
- package/dist/validation/protocol-common.d.ts.map +1 -1
- package/dist/validation/protocol-common.js +86 -21
- package/dist/validation/protocol-common.js.map +1 -1
- package/dist/workgraph/scaffold-apply.d.ts.map +1 -1
- package/dist/workgraph/scaffold-apply.js +14 -5
- package/dist/workgraph/scaffold-apply.js.map +1 -1
- package/migrations/README.md +12 -0
- package/migrations/drizzle-cleo-project/20260928120000_t12341-row-uids/migration.sql +169 -0
- package/migrations/drizzle-cleo-project/20260930160000_t12886-dependency-cycle-guard/migration.sql +76 -0
- package/migrations/drizzle-cleo-project/20260930160000_t12886-dependency-cycle-guard/revert.sql +7 -0
- package/migrations/sync-journal/20260929140000_t12342-sync-clock/migration.sql +42 -0
- package/package.json +13 -13
- package/templates/CLEO-INJECTION.md +2 -2
- package/templates/CLEO-REFERENCE.md +5 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replica-registry.js","sourceRoot":"","sources":["../../../src/store/sync/replica-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replica identity: binding a store file to its replica, and rebinding a
|
|
3
|
+
* copy (journal spec §1.5, H3, N5, N6).
|
|
4
|
+
*
|
|
5
|
+
* A replica is one physical store file, not a machine: a worktree copy or a
|
|
6
|
+
* restored file is a separate replica. The binding is
|
|
7
|
+
* `(st_ino, st_birthtime, nonce)` plus the stable device id and the device
|
|
8
|
+
* registry's high-water mark. `st_dev` is NOT used: external volumes, OS
|
|
9
|
+
* updates, overlay and network mounts renumber it.
|
|
10
|
+
*
|
|
11
|
+
* Birthtime (N5): a birthtime of 0, or one equal to the ctime at bind (the
|
|
12
|
+
* libuv fallback where the filesystem has no birthtime), is stored as NULL,
|
|
13
|
+
* and birthtimes are compared only when both are non-NULL.
|
|
14
|
+
*
|
|
15
|
+
* The open pass rebinds when:
|
|
16
|
+
* - `file-identity`: the inode differs, or both birthtimes are known and
|
|
17
|
+
* differ (a copy, `VACUUM INTO` output, a restore to a new file);
|
|
18
|
+
* - `foreign-device`: the store was bound on another device;
|
|
19
|
+
* - `nonce-mismatch`: this device registered the replica id with another
|
|
20
|
+
* nonce;
|
|
21
|
+
* - `rollback`: for some stream the store's persisted `replicaSeq` is below
|
|
22
|
+
* the registry's hwm (a restore into the same inode, e.g. `.backup()`).
|
|
23
|
+
* A store missing from the registry is re-registered, never rebound for that
|
|
24
|
+
* alone (N6). The server's "seq exists, hash differs" answer is the authority
|
|
25
|
+
* behind that; S4 reports it through {@link rebindReplica}.
|
|
26
|
+
*
|
|
27
|
+
* A rebind retires the old row, mints a new replica id and nonce, carries the
|
|
28
|
+
* clock forward, and runs the registered {@link RebindHook}s in the same
|
|
29
|
+
* transaction. Marking inherited journal rows, discarding the pull cursor,
|
|
30
|
+
* pausing push, the reconcile and the signed retire transaction arrive with
|
|
31
|
+
* those tables (S4); they plug in as hooks.
|
|
32
|
+
*
|
|
33
|
+
* Everything here is behind the store-level `sync.*` flags: with every flag
|
|
34
|
+
* off, {@link syncOpenPass} reads and writes nothing.
|
|
35
|
+
*
|
|
36
|
+
* @task T12342
|
|
37
|
+
* @module store/sync/replica
|
|
38
|
+
*/
|
|
39
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
40
|
+
import { ReplicaRegistry, type ReplicaRegistryEntry } from './replica-registry.js';
|
|
41
|
+
/** Which store a replica is. */
|
|
42
|
+
export type ReplicaScope = 'project' | 'global';
|
|
43
|
+
/**
|
|
44
|
+
* How an open treats sync (§1.5). `off` for every non-canonical open
|
|
45
|
+
* (backups, snapshots, scratch copies, bundle staging): nothing is read or
|
|
46
|
+
* written. `live` for the canonical project and global stores. `test` for a
|
|
47
|
+
* scratch-bound replica that must never touch the device registry: the
|
|
48
|
+
* caller passes its own registry.
|
|
49
|
+
*/
|
|
50
|
+
export type SyncOpenMode = 'off' | 'live' | 'test';
|
|
51
|
+
/** Why a store was rebound. */
|
|
52
|
+
export type RebindReason = 'file-identity' | 'foreign-device' | 'nonce-mismatch' | 'rollback' | 'server-seq-conflict';
|
|
53
|
+
/** What `stat` reports about a store file, in nanoseconds. */
|
|
54
|
+
export interface FileStat {
|
|
55
|
+
readonly ino: bigint;
|
|
56
|
+
readonly birthtimeNs: bigint;
|
|
57
|
+
readonly ctimeNs: bigint;
|
|
58
|
+
}
|
|
59
|
+
/** Reads a file's stat. Injectable so tests can simulate filesystems. */
|
|
60
|
+
export type StatFn = (path: string) => FileStat;
|
|
61
|
+
/** The part of a file's identity the binding compares. */
|
|
62
|
+
export interface FileIdentity {
|
|
63
|
+
readonly ino: bigint;
|
|
64
|
+
/** Birthtime in ns, or null when unknown (N5). */
|
|
65
|
+
readonly birth: bigint | null;
|
|
66
|
+
}
|
|
67
|
+
/** A `_sync_replica` row. */
|
|
68
|
+
export interface ReplicaRow {
|
|
69
|
+
readonly replicaId: string;
|
|
70
|
+
readonly scope: ReplicaScope;
|
|
71
|
+
readonly nonce: string;
|
|
72
|
+
readonly deviceId: string;
|
|
73
|
+
readonly fileIno: bigint;
|
|
74
|
+
readonly fileBirth: bigint | null;
|
|
75
|
+
readonly boundAt: string;
|
|
76
|
+
readonly boundWhy: string;
|
|
77
|
+
readonly retiredAt: string | null;
|
|
78
|
+
readonly successor: string | null;
|
|
79
|
+
}
|
|
80
|
+
/** Context handed to a {@link RebindHook}. */
|
|
81
|
+
export interface RebindContext {
|
|
82
|
+
readonly previous: ReplicaRow;
|
|
83
|
+
readonly current: ReplicaRow;
|
|
84
|
+
readonly reasons: readonly RebindReason[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Runs inside the rebind transaction, after the new replica is bound. S4
|
|
88
|
+
* registers the hooks that mark inherited rows, discard the cursor and pause
|
|
89
|
+
* push. A throw rolls the whole rebind back.
|
|
90
|
+
*/
|
|
91
|
+
export type RebindHook = (db: DatabaseSync, ctx: RebindContext) => void;
|
|
92
|
+
/**
|
|
93
|
+
* Register a hook that runs on every rebind.
|
|
94
|
+
*
|
|
95
|
+
* @returns A function that unregisters it.
|
|
96
|
+
*/
|
|
97
|
+
export declare function registerRebindHook(hook: RebindHook): () => void;
|
|
98
|
+
/** `fs.statSync` in bigint mode. */
|
|
99
|
+
export declare const defaultStat: StatFn;
|
|
100
|
+
/**
|
|
101
|
+
* The binding identity of a store file. A birthtime of 0 or equal to the
|
|
102
|
+
* ctime is the filesystem saying "unknown", so it reads as null (N5).
|
|
103
|
+
*/
|
|
104
|
+
export declare function fileIdentity(path: string, stat?: StatFn): FileIdentity;
|
|
105
|
+
/** The active (not retired) replica of a store, if bound. Read-only. */
|
|
106
|
+
export declare function activeReplica(db: DatabaseSync, scope: ReplicaScope): ReplicaRow | undefined;
|
|
107
|
+
/** Every replica row of a store, oldest first. Read-only. */
|
|
108
|
+
export declare function listReplicas(db: DatabaseSync): ReplicaRow[];
|
|
109
|
+
/**
|
|
110
|
+
* The store-side high-water mark: the last `replicaSeq` this store persisted
|
|
111
|
+
* per stream for a replica. Read-only.
|
|
112
|
+
*/
|
|
113
|
+
export declare function storeHwm(db: DatabaseSync, replicaId: string): Record<string, number>;
|
|
114
|
+
/**
|
|
115
|
+
* Record, in the caller's transaction, that a segment with `seq` was
|
|
116
|
+
* persisted for `stream`. S4 calls this in the segment-persist transaction,
|
|
117
|
+
* then {@link ReplicaRegistry.advanceHwm} after it commits. The value only
|
|
118
|
+
* moves up.
|
|
119
|
+
*/
|
|
120
|
+
export declare function persistStoreSeq(db: DatabaseSync, replicaId: string, stream: string, seq: number, now?: Date): void;
|
|
121
|
+
/**
|
|
122
|
+
* Why a bound store must rebind, if at all. Pure.
|
|
123
|
+
*
|
|
124
|
+
* @param row - The store's active replica row.
|
|
125
|
+
* @param identity - The file's identity now.
|
|
126
|
+
* @param deviceId - This device.
|
|
127
|
+
* @param entry - This device's registry entry for the replica, if any.
|
|
128
|
+
* @param hwm - The store-side hwm for the replica ({@link storeHwm}).
|
|
129
|
+
*/
|
|
130
|
+
export declare function rebindReasons(row: ReplicaRow, identity: FileIdentity, deviceId: string, entry: ReplicaRegistryEntry | undefined, hwm: Readonly<Record<string, number>>): RebindReason[];
|
|
131
|
+
/** Options for {@link syncOpenPass} and {@link rebindReplica}. */
|
|
132
|
+
export interface SyncOpenOptions {
|
|
133
|
+
/** Path of the store file the handle has open. */
|
|
134
|
+
readonly dbPath: string;
|
|
135
|
+
readonly scope: ReplicaScope;
|
|
136
|
+
readonly mode: SyncOpenMode;
|
|
137
|
+
/** This device. Defaults to `getStableDeviceId()` (live mode only). */
|
|
138
|
+
readonly deviceId?: string;
|
|
139
|
+
/** The device registry. Required in `test` mode; defaults to the device's in `live` mode. */
|
|
140
|
+
readonly registry?: ReplicaRegistry;
|
|
141
|
+
readonly stat?: StatFn;
|
|
142
|
+
readonly now?: () => Date;
|
|
143
|
+
/** Sync schema folder override (tests). */
|
|
144
|
+
readonly schemaRoot?: string;
|
|
145
|
+
}
|
|
146
|
+
/** What an open pass did. */
|
|
147
|
+
export type SyncOpenResult = {
|
|
148
|
+
readonly status: 'off' | 'disabled';
|
|
149
|
+
} | {
|
|
150
|
+
readonly status: 'bound' | 'rebound';
|
|
151
|
+
readonly replicaId: string;
|
|
152
|
+
readonly previousReplicaId?: string;
|
|
153
|
+
readonly reasons: readonly RebindReason[];
|
|
154
|
+
/** Whether the device registry file was written. */
|
|
155
|
+
readonly registryWritten: boolean;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* The sync open pass for a canonical store open.
|
|
159
|
+
*
|
|
160
|
+
* With `mode: 'off'`, or with every `sync.*` flag off on the store, it reads
|
|
161
|
+
* nothing beyond the flags and writes nothing. Otherwise, under
|
|
162
|
+
* `BEGIN IMMEDIATE`: it binds an unbound store, rebinds a copy, a rolled-back
|
|
163
|
+
* or a foreign store, and heals the clock. Then it brings the device registry
|
|
164
|
+
* up to date (re-registering a store the registry lost, recording a rename).
|
|
165
|
+
*
|
|
166
|
+
* Not yet called by `openDualScopeDb`: the capture slice (S2) wires it in.
|
|
167
|
+
*/
|
|
168
|
+
export declare function syncOpenPass(db: DatabaseSync, opts: SyncOpenOptions): SyncOpenResult;
|
|
169
|
+
/**
|
|
170
|
+
* Force a rebind of a bound store: the hook S4 uses when the server answers a
|
|
171
|
+
* push with "seq exists, hash differs" (N6: the server hwm is authoritative).
|
|
172
|
+
*
|
|
173
|
+
* @throws {Error} When the store has no active replica.
|
|
174
|
+
*/
|
|
175
|
+
export declare function rebindReplica(db: DatabaseSync, opts: SyncOpenOptions, reason?: RebindReason): {
|
|
176
|
+
replicaId: string;
|
|
177
|
+
previousReplicaId: string;
|
|
178
|
+
};
|
|
179
|
+
/** The current clock of the store's active replica, for diagnostics. Read-only. */
|
|
180
|
+
export declare function currentClock(db: DatabaseSync, scope: ReplicaScope): string | undefined;
|
|
181
|
+
//# sourceMappingURL=replica.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../../../src/store/sync/replica.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replica identity: binding a store file to its replica, and rebinding a
|
|
3
|
+
* copy (journal spec §1.5, H3, N5, N6).
|
|
4
|
+
*
|
|
5
|
+
* A replica is one physical store file, not a machine: a worktree copy or a
|
|
6
|
+
* restored file is a separate replica. The binding is
|
|
7
|
+
* `(st_ino, st_birthtime, nonce)` plus the stable device id and the device
|
|
8
|
+
* registry's high-water mark. `st_dev` is NOT used: external volumes, OS
|
|
9
|
+
* updates, overlay and network mounts renumber it.
|
|
10
|
+
*
|
|
11
|
+
* Birthtime (N5): a birthtime of 0, or one equal to the ctime at bind (the
|
|
12
|
+
* libuv fallback where the filesystem has no birthtime), is stored as NULL,
|
|
13
|
+
* and birthtimes are compared only when both are non-NULL.
|
|
14
|
+
*
|
|
15
|
+
* The open pass rebinds when:
|
|
16
|
+
* - `file-identity`: the inode differs, or both birthtimes are known and
|
|
17
|
+
* differ (a copy, `VACUUM INTO` output, a restore to a new file);
|
|
18
|
+
* - `foreign-device`: the store was bound on another device;
|
|
19
|
+
* - `nonce-mismatch`: this device registered the replica id with another
|
|
20
|
+
* nonce;
|
|
21
|
+
* - `rollback`: for some stream the store's persisted `replicaSeq` is below
|
|
22
|
+
* the registry's hwm (a restore into the same inode, e.g. `.backup()`).
|
|
23
|
+
* A store missing from the registry is re-registered, never rebound for that
|
|
24
|
+
* alone (N6). The server's "seq exists, hash differs" answer is the authority
|
|
25
|
+
* behind that; S4 reports it through {@link rebindReplica}.
|
|
26
|
+
*
|
|
27
|
+
* A rebind retires the old row, mints a new replica id and nonce, carries the
|
|
28
|
+
* clock forward, and runs the registered {@link RebindHook}s in the same
|
|
29
|
+
* transaction. Marking inherited journal rows, discarding the pull cursor,
|
|
30
|
+
* pausing push, the reconcile and the signed retire transaction arrive with
|
|
31
|
+
* those tables (S4); they plug in as hooks.
|
|
32
|
+
*
|
|
33
|
+
* Everything here is behind the store-level `sync.*` flags: with every flag
|
|
34
|
+
* off, {@link syncOpenPass} reads and writes nothing.
|
|
35
|
+
*
|
|
36
|
+
* @task T12342
|
|
37
|
+
* @module store/sync/replica
|
|
38
|
+
*/
|
|
39
|
+
import { randomBytes } from 'node:crypto';
|
|
40
|
+
import { realpathSync, statSync } from 'node:fs';
|
|
41
|
+
import { uuidv7 } from '../../cloud/crypto.js';
|
|
42
|
+
import { getStableDeviceId } from '../../llm/stable-device-id.js';
|
|
43
|
+
import { healClock, loadClock, storeClock, withImmediateTransaction } from './clock-store.js';
|
|
44
|
+
import { anySyncFlagOn } from './flags.js';
|
|
45
|
+
import { encodeHlc } from './hlc.js';
|
|
46
|
+
import { ReplicaRegistry } from './replica-registry.js';
|
|
47
|
+
import { ensureSyncSchema, hasTable } from './schema.js';
|
|
48
|
+
const rebindHooks = [];
|
|
49
|
+
/**
|
|
50
|
+
* Register a hook that runs on every rebind.
|
|
51
|
+
*
|
|
52
|
+
* @returns A function that unregisters it.
|
|
53
|
+
*/
|
|
54
|
+
export function registerRebindHook(hook) {
|
|
55
|
+
rebindHooks.push(hook);
|
|
56
|
+
return () => {
|
|
57
|
+
const i = rebindHooks.indexOf(hook);
|
|
58
|
+
if (i >= 0)
|
|
59
|
+
rebindHooks.splice(i, 1);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** `fs.statSync` in bigint mode. */
|
|
63
|
+
export const defaultStat = (path) => {
|
|
64
|
+
const s = statSync(path, { bigint: true });
|
|
65
|
+
return { ino: s.ino, birthtimeNs: s.birthtimeNs, ctimeNs: s.ctimeNs };
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* The binding identity of a store file. A birthtime of 0 or equal to the
|
|
69
|
+
* ctime is the filesystem saying "unknown", so it reads as null (N5).
|
|
70
|
+
*/
|
|
71
|
+
export function fileIdentity(path, stat = defaultStat) {
|
|
72
|
+
const s = stat(path);
|
|
73
|
+
const birth = s.birthtimeNs === 0n || s.birthtimeNs === s.ctimeNs ? null : s.birthtimeNs;
|
|
74
|
+
return { ino: s.ino, birth };
|
|
75
|
+
}
|
|
76
|
+
function rowFrom(r) {
|
|
77
|
+
return {
|
|
78
|
+
replicaId: String(r.replica_id),
|
|
79
|
+
scope: r.scope,
|
|
80
|
+
nonce: String(r.nonce),
|
|
81
|
+
deviceId: String(r.device_id),
|
|
82
|
+
fileIno: BigInt(r.file_ino),
|
|
83
|
+
fileBirth: r.file_birth === null ? null : BigInt(r.file_birth),
|
|
84
|
+
boundAt: String(r.bound_at),
|
|
85
|
+
boundWhy: String(r.bound_why),
|
|
86
|
+
retiredAt: r.retired_at === null ? null : String(r.retired_at),
|
|
87
|
+
successor: r.successor === null ? null : String(r.successor),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** The active (not retired) replica of a store, if bound. Read-only. */
|
|
91
|
+
export function activeReplica(db, scope) {
|
|
92
|
+
if (!hasTable(db, '_sync_replica'))
|
|
93
|
+
return undefined;
|
|
94
|
+
const stmt = db.prepare('SELECT * FROM _sync_replica WHERE scope = ? AND retired_at IS NULL ORDER BY bound_at DESC LIMIT 1');
|
|
95
|
+
stmt.setReadBigInts(true);
|
|
96
|
+
const r = stmt.get(scope);
|
|
97
|
+
return r ? rowFrom(r) : undefined;
|
|
98
|
+
}
|
|
99
|
+
/** Every replica row of a store, oldest first. Read-only. */
|
|
100
|
+
export function listReplicas(db) {
|
|
101
|
+
if (!hasTable(db, '_sync_replica'))
|
|
102
|
+
return [];
|
|
103
|
+
const stmt = db.prepare('SELECT * FROM _sync_replica ORDER BY bound_at, replica_id');
|
|
104
|
+
stmt.setReadBigInts(true);
|
|
105
|
+
return stmt.all().map(rowFrom);
|
|
106
|
+
}
|
|
107
|
+
const SEQ_PREFIX = 'seq:';
|
|
108
|
+
/**
|
|
109
|
+
* The store-side high-water mark: the last `replicaSeq` this store persisted
|
|
110
|
+
* per stream for a replica. Read-only.
|
|
111
|
+
*/
|
|
112
|
+
export function storeHwm(db, replicaId) {
|
|
113
|
+
if (!hasTable(db, '_sync_meta'))
|
|
114
|
+
return {};
|
|
115
|
+
const prefix = `${SEQ_PREFIX}${replicaId}:`;
|
|
116
|
+
const rows = db
|
|
117
|
+
.prepare('SELECT key, value FROM _sync_meta WHERE key >= ? AND key < ?')
|
|
118
|
+
.all(prefix, `${prefix}`);
|
|
119
|
+
return Object.fromEntries(rows.map((r) => [r.key.slice(prefix.length), Number(r.value)]));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Record, in the caller's transaction, that a segment with `seq` was
|
|
123
|
+
* persisted for `stream`. S4 calls this in the segment-persist transaction,
|
|
124
|
+
* then {@link ReplicaRegistry.advanceHwm} after it commits. The value only
|
|
125
|
+
* moves up.
|
|
126
|
+
*/
|
|
127
|
+
export function persistStoreSeq(db, replicaId, stream, seq, now = new Date()) {
|
|
128
|
+
if (!db.isTransaction)
|
|
129
|
+
throw new Error('persistStoreSeq must run inside a transaction');
|
|
130
|
+
if (!Number.isSafeInteger(seq) || seq < 0)
|
|
131
|
+
throw new Error(`invalid replicaSeq ${seq}`);
|
|
132
|
+
db.prepare('INSERT INTO _sync_meta (key, value, updated_at) VALUES (?, ?, ?) ' +
|
|
133
|
+
'ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at ' +
|
|
134
|
+
'WHERE CAST(excluded.value AS INTEGER) > CAST(_sync_meta.value AS INTEGER)').run(`${SEQ_PREFIX}${replicaId}:${stream}`, String(seq), now.toISOString());
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Why a bound store must rebind, if at all. Pure.
|
|
138
|
+
*
|
|
139
|
+
* @param row - The store's active replica row.
|
|
140
|
+
* @param identity - The file's identity now.
|
|
141
|
+
* @param deviceId - This device.
|
|
142
|
+
* @param entry - This device's registry entry for the replica, if any.
|
|
143
|
+
* @param hwm - The store-side hwm for the replica ({@link storeHwm}).
|
|
144
|
+
*/
|
|
145
|
+
export function rebindReasons(row, identity, deviceId, entry, hwm) {
|
|
146
|
+
const out = [];
|
|
147
|
+
const birthDiffers = row.fileBirth !== null && identity.birth !== null && row.fileBirth !== identity.birth;
|
|
148
|
+
if (row.fileIno !== identity.ino || birthDiffers)
|
|
149
|
+
out.push('file-identity');
|
|
150
|
+
if (row.deviceId !== deviceId)
|
|
151
|
+
out.push('foreign-device');
|
|
152
|
+
if (entry && entry.nonce !== row.nonce)
|
|
153
|
+
out.push('nonce-mismatch');
|
|
154
|
+
if (entry && Object.entries(entry.hwm).some(([stream, seq]) => (hwm[stream] ?? 0) < seq)) {
|
|
155
|
+
out.push('rollback');
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
function insertReplica(db, row) {
|
|
160
|
+
db.prepare('INSERT INTO _sync_replica (replica_id, scope, nonce, device_id, file_ino, file_birth, bound_at, bound_why) ' +
|
|
161
|
+
'VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(row.replicaId, row.scope, row.nonce, row.deviceId, row.fileIno, row.fileBirth, row.boundAt, row.boundWhy);
|
|
162
|
+
}
|
|
163
|
+
function mintRow(scope, identity, deviceId, why, now) {
|
|
164
|
+
return {
|
|
165
|
+
replicaId: uuidv7(now.getTime()),
|
|
166
|
+
scope,
|
|
167
|
+
nonce: randomBytes(16).toString('hex'),
|
|
168
|
+
deviceId,
|
|
169
|
+
fileIno: identity.ino,
|
|
170
|
+
fileBirth: identity.birth,
|
|
171
|
+
boundAt: now.toISOString(),
|
|
172
|
+
boundWhy: why,
|
|
173
|
+
retiredAt: null,
|
|
174
|
+
successor: null,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Retire `previous` and bind a new replica in its place, in the caller's
|
|
179
|
+
* transaction. The new replica's clock starts from the old one, so HLCs
|
|
180
|
+
* issued by this store keep increasing. Runs the rebind hooks.
|
|
181
|
+
*/
|
|
182
|
+
function rebindInTransaction(db, previous, identity, deviceId, reasons, now) {
|
|
183
|
+
const current = mintRow(previous.scope, identity, deviceId, `rebind:${reasons.join(',')}`, now);
|
|
184
|
+
db.prepare('UPDATE _sync_replica SET retired_at = ?, successor = ? WHERE replica_id = ?').run(now.toISOString(), current.replicaId, previous.replicaId);
|
|
185
|
+
insertReplica(db, current);
|
|
186
|
+
const old = healClock(db, previous.replicaId);
|
|
187
|
+
storeClock(db, { phys: old.phys, ctr: old.ctr, replica: current.replicaId });
|
|
188
|
+
db.prepare('INSERT INTO _sync_meta (key, value, updated_at) VALUES (?, ?, ?) ' +
|
|
189
|
+
'ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at').run('rebind:last', JSON.stringify({ from: previous.replicaId, to: current.replicaId, reasons }), now.toISOString());
|
|
190
|
+
const retired = {
|
|
191
|
+
...previous,
|
|
192
|
+
retiredAt: now.toISOString(),
|
|
193
|
+
successor: current.replicaId,
|
|
194
|
+
};
|
|
195
|
+
for (const hook of rebindHooks)
|
|
196
|
+
hook(db, { previous: retired, current, reasons });
|
|
197
|
+
return current;
|
|
198
|
+
}
|
|
199
|
+
function resolveContext(opts) {
|
|
200
|
+
if (opts.mode === 'test' && !opts.registry) {
|
|
201
|
+
throw new Error("sync open mode 'test' needs an explicit registry; it never uses the device's");
|
|
202
|
+
}
|
|
203
|
+
const deviceId = opts.deviceId ?? opts.registry?.deviceId ?? getStableDeviceId();
|
|
204
|
+
const registry = opts.registry ?? ReplicaRegistry.forDevice(deviceId);
|
|
205
|
+
if (registry.deviceId !== deviceId) {
|
|
206
|
+
throw new Error(`registry belongs to device ${registry.deviceId}, not ${deviceId}`);
|
|
207
|
+
}
|
|
208
|
+
return { deviceId, registry };
|
|
209
|
+
}
|
|
210
|
+
function register(registry, db, row, realpath, now) {
|
|
211
|
+
return registry.upsert(row.replicaId, { nonce: row.nonce, scope: row.scope, dbRealpath: realpath, hwm: storeHwm(db, row.replicaId) }, now);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The sync open pass for a canonical store open.
|
|
215
|
+
*
|
|
216
|
+
* With `mode: 'off'`, or with every `sync.*` flag off on the store, it reads
|
|
217
|
+
* nothing beyond the flags and writes nothing. Otherwise, under
|
|
218
|
+
* `BEGIN IMMEDIATE`: it binds an unbound store, rebinds a copy, a rolled-back
|
|
219
|
+
* or a foreign store, and heals the clock. Then it brings the device registry
|
|
220
|
+
* up to date (re-registering a store the registry lost, recording a rename).
|
|
221
|
+
*
|
|
222
|
+
* Not yet called by `openDualScopeDb`: the capture slice (S2) wires it in.
|
|
223
|
+
*/
|
|
224
|
+
export function syncOpenPass(db, opts) {
|
|
225
|
+
if (opts.mode === 'off')
|
|
226
|
+
return { status: 'off' };
|
|
227
|
+
if (!anySyncFlagOn(db))
|
|
228
|
+
return { status: 'disabled' };
|
|
229
|
+
const now = opts.now?.() ?? new Date();
|
|
230
|
+
const { deviceId, registry } = resolveContext(opts);
|
|
231
|
+
ensureSyncSchema(db, { root: opts.schemaRoot, now });
|
|
232
|
+
const identity = fileIdentity(opts.dbPath, opts.stat);
|
|
233
|
+
const realpath = realpathSync(opts.dbPath);
|
|
234
|
+
const known = registry.read().replicas;
|
|
235
|
+
const outcome = withImmediateTransaction(db, () => {
|
|
236
|
+
const row = activeReplica(db, opts.scope);
|
|
237
|
+
if (!row) {
|
|
238
|
+
const minted = mintRow(opts.scope, identity, deviceId, 'genesis', now);
|
|
239
|
+
insertReplica(db, minted);
|
|
240
|
+
healClock(db, minted.replicaId);
|
|
241
|
+
return { row: minted, previous: undefined, reasons: [] };
|
|
242
|
+
}
|
|
243
|
+
const entry = Object.hasOwn(known, row.replicaId) ? known[row.replicaId] : undefined;
|
|
244
|
+
const reasons = rebindReasons(row, identity, deviceId, entry, storeHwm(db, row.replicaId));
|
|
245
|
+
if (reasons.length === 0) {
|
|
246
|
+
healClock(db, row.replicaId);
|
|
247
|
+
return { row, previous: undefined, reasons };
|
|
248
|
+
}
|
|
249
|
+
const current = rebindInTransaction(db, row, identity, deviceId, reasons, now);
|
|
250
|
+
return { row: current, previous: row, reasons };
|
|
251
|
+
});
|
|
252
|
+
let registryWritten = false;
|
|
253
|
+
if (outcome.previous && Object.hasOwn(known, outcome.previous.replicaId)) {
|
|
254
|
+
const prev = known[outcome.previous.replicaId];
|
|
255
|
+
// Only the device's own registration of the retired replica is marked; a
|
|
256
|
+
// copy's original keeps its entry untouched when it lives elsewhere.
|
|
257
|
+
if (prev.dbRealpath === realpath) {
|
|
258
|
+
registryWritten =
|
|
259
|
+
registry.upsert(outcome.previous.replicaId, { ...prev, retiredAt: now.toISOString(), successor: outcome.row.replicaId }, now) || registryWritten;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
registryWritten = register(registry, db, outcome.row, realpath, now) || registryWritten;
|
|
263
|
+
return {
|
|
264
|
+
status: outcome.previous ? 'rebound' : 'bound',
|
|
265
|
+
replicaId: outcome.row.replicaId,
|
|
266
|
+
...(outcome.previous ? { previousReplicaId: outcome.previous.replicaId } : {}),
|
|
267
|
+
reasons: outcome.reasons,
|
|
268
|
+
registryWritten,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Force a rebind of a bound store: the hook S4 uses when the server answers a
|
|
273
|
+
* push with "seq exists, hash differs" (N6: the server hwm is authoritative).
|
|
274
|
+
*
|
|
275
|
+
* @throws {Error} When the store has no active replica.
|
|
276
|
+
*/
|
|
277
|
+
export function rebindReplica(db, opts, reason = 'server-seq-conflict') {
|
|
278
|
+
const now = opts.now?.() ?? new Date();
|
|
279
|
+
const { deviceId, registry } = resolveContext(opts);
|
|
280
|
+
const identity = fileIdentity(opts.dbPath, opts.stat);
|
|
281
|
+
const realpath = realpathSync(opts.dbPath);
|
|
282
|
+
const { previous, current } = withImmediateTransaction(db, () => {
|
|
283
|
+
const row = activeReplica(db, opts.scope);
|
|
284
|
+
if (!row)
|
|
285
|
+
throw new Error(`no active ${opts.scope} replica to rebind`);
|
|
286
|
+
return {
|
|
287
|
+
previous: row,
|
|
288
|
+
current: rebindInTransaction(db, row, identity, deviceId, [reason], now),
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
const prev = registry.get(previous.replicaId);
|
|
292
|
+
if (prev) {
|
|
293
|
+
registry.upsert(previous.replicaId, { ...prev, retiredAt: now.toISOString(), successor: current.replicaId }, now);
|
|
294
|
+
}
|
|
295
|
+
register(registry, db, current, realpath, now);
|
|
296
|
+
return { replicaId: current.replicaId, previousReplicaId: previous.replicaId };
|
|
297
|
+
}
|
|
298
|
+
/** The current clock of the store's active replica, for diagnostics. Read-only. */
|
|
299
|
+
export function currentClock(db, scope) {
|
|
300
|
+
const row = activeReplica(db, scope);
|
|
301
|
+
if (!row || !hasTable(db, '_sync_clock'))
|
|
302
|
+
return undefined;
|
|
303
|
+
return encodeHlc(loadClock(db, row.replicaId));
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=replica.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replica.js","sourceRoot":"","sources":["../../../src/store/sync/replica.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The change journal's own schema, applied lazily.
|
|
3
|
+
*
|
|
4
|
+
* The DDL lives in `packages/core/migrations/sync-journal/<folder>/migration.sql`,
|
|
5
|
+
* one folder per migration, like the drizzle lineages. It is NOT a drizzle
|
|
6
|
+
* lineage: it runs only when a `sync.*` flag is first enabled on a store
|
|
7
|
+
* ({@link ensureSyncSchema}), so a store with every flag off (the default)
|
|
8
|
+
* never gains a table or a journal row. Applied folders are recorded in
|
|
9
|
+
* `_sync_meta` under `schema:<folder>` with the sha256 of the folder's SQL,
|
|
10
|
+
* never in `__drizzle_migrations`. A folder whose SQL changed after it was
|
|
11
|
+
* applied is refused with {@link SyncSchemaHashDriftError}, never skipped.
|
|
12
|
+
*
|
|
13
|
+
* @task T12342
|
|
14
|
+
* @module store/sync/schema
|
|
15
|
+
*/
|
|
16
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
17
|
+
/** The migrations sub-directory that holds the sync schema. */
|
|
18
|
+
export declare const SYNC_SCHEMA_SET = "sync-journal";
|
|
19
|
+
/** One sync schema folder. */
|
|
20
|
+
export interface SyncSchemaFolder {
|
|
21
|
+
readonly name: string;
|
|
22
|
+
readonly sql: string;
|
|
23
|
+
/** sha256 of `sql`, hex. */
|
|
24
|
+
readonly hash: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* An applied sync schema folder whose SQL no longer matches what was applied
|
|
28
|
+
* (in the spirit of `E_MIGRATION_HASH_DRIFT`). Editing an applied folder is
|
|
29
|
+
* never correct: add a new folder instead.
|
|
30
|
+
*/
|
|
31
|
+
export declare class SyncSchemaHashDriftError extends Error {
|
|
32
|
+
readonly folder: string;
|
|
33
|
+
readonly applied: string;
|
|
34
|
+
readonly current: string;
|
|
35
|
+
readonly code = "E_SYNC_SCHEMA_HASH_DRIFT";
|
|
36
|
+
constructor(folder: string, applied: string, current: string);
|
|
37
|
+
}
|
|
38
|
+
/** Whether a table exists in the `main` schema. Read-only. */
|
|
39
|
+
export declare function hasTable(db: DatabaseSync, table: string): boolean;
|
|
40
|
+
/** The sync schema folders, oldest first. */
|
|
41
|
+
export declare function syncSchemaFolders(root?: string): SyncSchemaFolder[];
|
|
42
|
+
/**
|
|
43
|
+
* The schema folders already applied to this store, with the sha256 each was
|
|
44
|
+
* applied with. Read-only: a store with no `_sync_meta` has none.
|
|
45
|
+
*/
|
|
46
|
+
export declare function appliedSyncSchemaHashes(db: DatabaseSync): Map<string, string>;
|
|
47
|
+
/** The names of the schema folders already applied to this store. Read-only. */
|
|
48
|
+
export declare function appliedSyncSchema(db: DatabaseSync): string[];
|
|
49
|
+
/**
|
|
50
|
+
* Apply every sync schema folder this store has not applied yet, in one
|
|
51
|
+
* transaction (a savepoint when the caller already holds one).
|
|
52
|
+
*
|
|
53
|
+
* The applied set is read again INSIDE the transaction, under the write
|
|
54
|
+
* lock, so two processes enabling a flag at once apply each folder once.
|
|
55
|
+
*
|
|
56
|
+
* @param db - The store handle.
|
|
57
|
+
* @param options - `root` overrides the schema folder (tests); `now` stamps
|
|
58
|
+
* the journal rows; `beforeLock` runs between the unlocked pre-check and
|
|
59
|
+
* taking the lock (a test seam for the two-process race).
|
|
60
|
+
* @returns The folders applied by this call.
|
|
61
|
+
* @throws {SyncSchemaHashDriftError} When an applied folder's SQL changed.
|
|
62
|
+
*/
|
|
63
|
+
export declare function ensureSyncSchema(db: DatabaseSync, options?: {
|
|
64
|
+
root?: string;
|
|
65
|
+
now?: Date;
|
|
66
|
+
beforeLock?: () => void;
|
|
67
|
+
}): string[];
|
|
68
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/store/sync/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,+DAA+D;AAC/D,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAK9C,8BAA8B;AAC9B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IAI/C,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM;IAL1B,QAAQ,CAAC,IAAI,8BAA8B;gBAGhC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM;CAQ3B;AAID,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAKjE;AAED,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAC/B,IAAI,GAAE,MAA4D,GACjE,gBAAgB,EAAE,CAYpB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAM7E;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,MAAM,EAAE,CAE5D;AAgBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,YAAY,EAChB,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CAAO,GACnE,MAAM,EAAE,CAuBV"}
|