hippo-memory 1.70.0 → 1.71.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 +1 -1
- package/dist/agent-memories/claude-code.d.ts +4 -2
- package/dist/agent-memories/claude-code.js +14 -5
- package/dist/agent-memories/files.js +23 -12
- package/dist/agent-memories/markdown.d.ts +1 -3
- package/dist/agent-memories/markdown.js +1 -3
- package/dist/agent-memories/report.js +2 -1
- package/dist/agent-memories/sync.d.ts +4 -2
- package/dist/agent-memories/sync.js +10 -5
- package/dist/api/assemble.d.ts +7 -44
- package/dist/api/assemble.js +2 -22
- package/dist/api/audit.d.ts +5 -1
- package/dist/api/audit.js +9 -1
- package/dist/api/auth.d.ts +13 -22
- package/dist/api/auth.js +34 -24
- package/dist/api/auto-sleep.js +2 -2
- package/dist/api/availability.d.ts +2 -15
- package/dist/api/availability.js +2 -15
- package/dist/api/context-select.js +3 -4
- package/dist/api/context-types.d.ts +10 -35
- package/dist/api/context.d.ts +5 -22
- package/dist/api/context.js +21 -38
- package/dist/api/dormant.d.ts +5 -21
- package/dist/api/dormant.js +7 -26
- package/dist/api/drill-down.d.ts +7 -46
- package/dist/api/drill-down.js +5 -26
- package/dist/api/forget.d.ts +5 -24
- package/dist/api/forget.js +5 -28
- package/dist/api/graph.d.ts +8 -0
- package/dist/api/graph.js +7 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/instruction-detect.js +16 -5
- package/dist/api/ledger-db.d.ts +2 -1
- package/dist/api/ledger-db.js +5 -3
- package/dist/api/memories.d.ts +5 -0
- package/dist/api/memories.js +7 -0
- package/dist/api/objects.d.ts +9 -0
- package/dist/api/objects.js +11 -0
- package/dist/api/on-store.js +5 -3
- package/dist/api/predictions.d.ts +9 -0
- package/dist/api/predictions.js +18 -0
- package/dist/api/promote.d.ts +13 -17
- package/dist/api/promote.js +11 -19
- package/dist/api/prompt-hook.d.ts +4 -4
- package/dist/api/prompt-hook.js +10 -9
- package/dist/api/recall-cli.d.ts +55 -0
- package/dist/api/recall-cli.js +94 -0
- package/dist/api/recall-core.js +14 -6
- package/dist/api/recall-finish.d.ts +53 -0
- package/dist/api/recall-finish.js +30 -0
- package/dist/api/recall-history.d.ts +17 -84
- package/dist/api/recall-history.js +15 -88
- package/dist/api/recall-pipeline.d.ts +2 -3
- package/dist/api/recall-pipeline.js +16 -9
- package/dist/api/recall-types.d.ts +64 -304
- package/dist/api/recall.d.ts +5 -33
- package/dist/api/recall.js +59 -60
- package/dist/api/refine.d.ts +7 -0
- package/dist/api/refine.js +10 -0
- package/dist/api/remember-local.d.ts +57 -0
- package/dist/api/remember-local.js +90 -0
- package/dist/api/remember.d.ts +18 -1
- package/dist/api/remember.js +13 -1
- package/dist/api/sleep-run.d.ts +1 -3
- package/dist/api/sleep-run.js +17 -21
- package/dist/api/sleep.d.ts +9 -28
- package/dist/api/tokens.d.ts +3 -10
- package/dist/api/tokens.js +3 -10
- package/dist/api/types.d.ts +6 -29
- package/dist/api/types.js +4 -22
- package/dist/capture/command.d.ts +4 -12
- package/dist/capture/command.js +6 -22
- package/dist/capture/compact.d.ts +4 -15
- package/dist/capture/compact.js +16 -25
- package/dist/capture/compaction-record.js +101 -69
- package/dist/capture/compaction-spool.d.ts +1 -1
- package/dist/capture/compaction-spool.js +1 -1
- package/dist/capture/session-digest.d.ts +1 -1
- package/dist/capture/session-digest.js +13 -7
- package/dist/capture/transcript.d.ts +2 -10
- package/dist/capture/transcript.js +4 -18
- package/dist/cli/api-context.d.ts +3 -0
- package/dist/cli/api-context.js +6 -0
- package/dist/cli/audit-prune.d.ts +6 -39
- package/dist/cli/audit-prune.js +6 -39
- package/dist/cli/audit.d.ts +1 -1
- package/dist/cli/audit.js +33 -34
- package/dist/cli/auth.d.ts +2 -2
- package/dist/cli/auth.js +57 -39
- package/dist/cli/briefs.d.ts +4 -4
- package/dist/cli/briefs.js +18 -22
- package/dist/cli/card.d.ts +2 -2
- package/dist/cli/card.js +31 -32
- package/dist/cli/client.d.ts +7 -27
- package/dist/cli/client.js +24 -43
- package/dist/cli/compact-resume-payload.js +3 -2
- package/dist/cli/context.d.ts +1 -2
- package/dist/cli/context.js +12 -8
- package/dist/cli/continuity.d.ts +6 -6
- package/dist/cli/continuity.js +62 -64
- package/dist/cli/correction-latency.d.ts +2 -14
- package/dist/cli/correction-latency.js +2 -14
- package/dist/cli/curate.d.ts +13 -17
- package/dist/cli/curate.js +68 -92
- package/dist/cli/dag.d.ts +4 -4
- package/dist/cli/dag.js +33 -27
- package/dist/cli/decisions.d.ts +4 -4
- package/dist/cli/decisions.js +33 -47
- package/dist/cli/eval.js +15 -13
- package/dist/cli/exit.d.ts +6 -0
- package/dist/cli/exit.js +11 -0
- package/dist/cli/explain.d.ts +1 -2
- package/dist/cli/explain.js +6 -4
- package/dist/cli/flag-values.d.ts +6 -1
- package/dist/cli/flag-values.js +27 -10
- package/dist/cli/flags.d.ts +1 -0
- package/dist/cli/flags.js +1 -1
- package/dist/cli/github.d.ts +14 -0
- package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
- package/dist/cli/goals.d.ts +2 -2
- package/dist/cli/goals.js +46 -50
- package/dist/cli/hook-runtime.d.ts +9 -27
- package/dist/cli/hook-runtime.js +15 -31
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.js +6 -12
- package/dist/cli/install-steps.js +3 -12
- package/dist/cli/last-sleep.d.ts +2 -1
- package/dist/cli/last-sleep.js +3 -0
- package/dist/cli/maintenance.d.ts +4 -4
- package/dist/cli/maintenance.js +14 -19
- package/dist/cli/object-verbs.js +4 -3
- package/dist/cli/owner-validation.d.ts +5 -28
- package/dist/cli/owner-validation.js +5 -28
- package/dist/cli/playbooks.d.ts +4 -4
- package/dist/cli/playbooks.js +23 -28
- package/dist/cli/print.d.ts +2 -5
- package/dist/cli/print.js +1 -4
- package/dist/cli/projects.d.ts +2 -2
- package/dist/cli/projects.js +1 -3
- package/dist/cli/provenance-coverage.d.ts +2 -6
- package/dist/cli/provenance-coverage.js +2 -6
- package/dist/cli/quality-repair-once.js +2 -2
- package/dist/cli/recall.d.ts +2 -4
- package/dist/cli/recall.js +55 -131
- package/dist/cli/refine-llm.d.ts +5 -31
- package/dist/cli/refine-llm.js +9 -36
- package/dist/cli/remember.d.ts +3 -3
- package/dist/cli/remember.js +122 -180
- package/dist/cli/scheduler.d.ts +2 -17
- package/dist/cli/scheduler.js +12 -18
- package/dist/cli/serve.js +21 -12
- package/dist/cli/session-hooks.d.ts +10 -18
- package/dist/cli/session-hooks.js +112 -113
- package/dist/cli/setup.d.ts +4 -4
- package/dist/cli/setup.js +19 -21
- package/dist/cli/shared.d.ts +9 -23
- package/dist/cli/shared.js +9 -32
- package/dist/cli/slack.d.ts +2 -2
- package/dist/cli/slack.js +19 -23
- package/dist/cli/sleep.d.ts +3 -2
- package/dist/cli/sleep.js +15 -16
- package/dist/cli/status.d.ts +9 -12
- package/dist/cli/status.js +55 -98
- package/dist/cli/stdin.d.ts +4 -6
- package/dist/cli/stdin.js +2 -3
- package/dist/cli/transfer.d.ts +9 -9
- package/dist/cli/transfer.js +66 -89
- package/dist/cli/usage.js +11 -5
- package/dist/cli.d.ts +66 -448
- package/dist/cli.js +87 -263
- package/dist/connectors/github/backfill.d.ts +5 -25
- package/dist/connectors/github/backfill.js +14 -49
- package/dist/connectors/github/deletion.d.ts +4 -18
- package/dist/connectors/github/deletion.js +2 -15
- package/dist/connectors/github/dlq.d.ts +8 -33
- package/dist/connectors/github/dlq.js +12 -29
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +4 -10
- package/dist/connectors/github/octokit-client.d.ts +4 -16
- package/dist/connectors/github/octokit-client.js +27 -24
- package/dist/connectors/github/ratelimit.d.ts +3 -14
- package/dist/connectors/github/ratelimit.js +3 -14
- package/dist/connectors/github/scope.d.ts +3 -5
- package/dist/connectors/github/scope.js +3 -5
- package/dist/connectors/github/signature.d.ts +4 -26
- package/dist/connectors/github/signature.js +4 -26
- package/dist/connectors/github/tenant-routing.d.ts +2 -24
- package/dist/connectors/github/tenant-routing.js +4 -26
- package/dist/connectors/github/transform.js +2 -16
- package/dist/connectors/github/types.d.ts +3 -15
- package/dist/connectors/github/types.js +2 -9
- package/dist/connectors/github/webhook.d.ts +2 -16
- package/dist/connectors/github/webhook.js +6 -22
- package/dist/connectors/slack/backfill.d.ts +4 -17
- package/dist/connectors/slack/backfill.js +4 -13
- package/dist/connectors/slack/dlq.d.ts +2 -19
- package/dist/connectors/slack/dlq.js +2 -19
- package/dist/connectors/slack/ingest.d.ts +2 -3
- package/dist/connectors/slack/ingest.js +2 -3
- package/dist/connectors/slack/scope.d.ts +2 -8
- package/dist/connectors/slack/scope.js +2 -8
- package/dist/connectors/slack/signature.d.ts +1 -6
- package/dist/connectors/slack/tenant-routing.d.ts +2 -19
- package/dist/connectors/slack/tenant-routing.js +2 -21
- package/dist/connectors/slack/transform.d.ts +2 -18
- package/dist/connectors/slack/transform.js +2 -18
- package/dist/connectors/slack/types.d.ts +3 -9
- package/dist/connectors/slack/types.js +2 -4
- package/dist/connectors/slack/web-client.js +33 -27
- package/dist/connectors/slack/webhook.d.ts +2 -19
- package/dist/connectors/slack/webhook.js +5 -26
- package/dist/connectors/slack/workspaces.d.ts +4 -24
- package/dist/connectors/slack/workspaces.js +4 -24
- package/dist/consolidate/conflicts.js +6 -14
- package/dist/consolidate/dag-summary.d.ts +8 -0
- package/dist/consolidate/dag-summary.js +41 -0
- package/dist/consolidate/dag.d.ts +5 -28
- package/dist/consolidate/dag.js +14 -75
- package/dist/consolidate/decay.js +7 -19
- package/dist/consolidate/dedupe.d.ts +6 -52
- package/dist/consolidate/dedupe.js +13 -71
- package/dist/consolidate/flush-units.d.ts +3 -4
- package/dist/consolidate/flush-units.js +3 -3
- package/dist/consolidate/half-life-migration.d.ts +3 -26
- package/dist/consolidate/half-life-migration.js +11 -28
- package/dist/consolidate/llm-passes.js +4 -21
- package/dist/consolidate/memory-value-weights.d.ts +2 -13
- package/dist/consolidate/memory-value-weights.js +2 -13
- package/dist/consolidate/memory-value.d.ts +11 -84
- package/dist/consolidate/memory-value.js +16 -104
- package/dist/consolidate/merge.js +10 -31
- package/dist/consolidate/merged-row.js +2 -1
- package/dist/consolidate/physics-pass.js +1 -3
- package/dist/consolidate/replay.d.ts +6 -38
- package/dist/consolidate/replay.js +14 -52
- package/dist/consolidate/run.js +1 -1
- package/dist/consolidate/sleep.d.ts +1 -8
- package/dist/consolidate/sleep.js +5 -17
- package/dist/consolidate/trace.d.ts +3 -18
- package/dist/consolidate/trace.js +3 -18
- package/dist/consolidate/traces.js +6 -22
- package/dist/core/ablation.d.ts +4 -91
- package/dist/core/ablation.js +4 -91
- package/dist/core/ambient.d.ts +1 -8
- package/dist/core/ambient.js +1 -8
- package/dist/core/capture-contract.d.ts +4 -2
- package/dist/core/capture-contract.js +4 -2
- package/dist/core/card.d.ts +4 -1
- package/dist/core/card.js +8 -0
- package/dist/core/compare.d.ts +11 -67
- package/dist/core/compare.js +9 -63
- package/dist/core/config.d.ts +10 -24
- package/dist/core/config.js +13 -14
- package/dist/core/handoff.d.ts +1 -7
- package/dist/core/handoff.js +1 -7
- package/dist/core/memory-quality.js +1 -1
- package/dist/core/memory.d.ts +41 -164
- package/dist/core/memory.js +51 -221
- package/dist/core/package-root.d.ts +3 -0
- package/dist/core/package-root.js +5 -0
- package/dist/core/physics-config.d.ts +1 -4
- package/dist/core/physics-config.js +3 -8
- package/dist/core/physics.d.ts +15 -61
- package/dist/core/physics.js +59 -122
- package/dist/core/project-identity.d.ts +17 -58
- package/dist/core/project-identity.js +17 -38
- package/dist/core/project-remote.js +13 -2
- package/dist/core/raw-append-only.d.ts +5 -0
- package/dist/core/raw-append-only.js +7 -0
- package/dist/core/salience.d.ts +1 -7
- package/dist/core/salience.js +1 -7
- package/dist/dashboard/dashboard-actions.js +2 -2
- package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
- package/dist/dashboard/dashboard-snapshot.js +11 -2
- package/dist/dashboard/dashboard-types.d.ts +2 -1
- package/dist/dashboard/dashboard.d.ts +1 -0
- package/dist/dashboard/dashboard.js +50 -4
- package/dist/db/busy.d.ts +1 -1
- package/dist/db/busy.js +17 -8
- package/dist/db/connect.d.ts +1 -0
- package/dist/db/connect.js +3 -3
- package/dist/db/migrate.js +3 -3
- package/dist/db/migrations/types.d.ts +2 -5
- package/dist/db/migrations/v14.js +2 -3
- package/dist/db/migrations/v15.js +2 -8
- package/dist/db/migrations/v16.js +2 -3
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +2 -5
- package/dist/db/migrations/v20.js +2 -7
- package/dist/db/migrations/v22.js +4 -17
- package/dist/db/migrations/v23.js +3 -14
- package/dist/db/migrations/v24.js +2 -4
- package/dist/db/migrations/v25.js +3 -8
- package/dist/db/migrations/v26.js +2 -13
- package/dist/db/migrations/v27.js +3 -11
- package/dist/db/migrations/v28.js +2 -14
- package/dist/db/migrations/v29.js +4 -18
- package/dist/db/migrations/v30.js +4 -16
- package/dist/db/migrations/v31.js +2 -15
- package/dist/db/migrations/v32.js +4 -22
- package/dist/db/migrations/v33.js +2 -15
- package/dist/db/migrations/v34.js +2 -11
- package/dist/db/migrations/v35.js +2 -11
- package/dist/db/migrations/v36.js +2 -11
- package/dist/db/migrations/v37.js +8 -33
- package/dist/db/migrations/v38.js +5 -38
- package/dist/db/migrations/v39.js +9 -20
- package/dist/db/migrations/v40.js +2 -9
- package/dist/db/migrations/v41.js +2 -24
- package/dist/db/migrations/v43.js +1 -1
- package/dist/db/migrations/v44.js +2 -8
- package/dist/db/migrations/v45.js +2 -7
- package/dist/db/migrations/v47.js +2 -3
- package/dist/db/migrations/v51.js +1 -1
- package/dist/db/open.d.ts +2 -0
- package/dist/db/open.js +17 -1
- package/dist/db/physics-state.d.ts +6 -22
- package/dist/db/physics-state.js +25 -36
- package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
- package/dist/db/raw-archive-mirror-cleanup.js +2 -17
- package/dist/db/vector-store.d.ts +2 -0
- package/dist/db/vector-store.js +8 -1
- package/dist/doctor.js +74 -19
- package/dist/entry/session-text.js +2 -1
- package/dist/eval/eval-stats.d.ts +15 -53
- package/dist/eval/eval-stats.js +12 -42
- package/dist/eval/eval-suite.d.ts +2 -13
- package/dist/eval/eval-suite.js +74 -34
- package/dist/eval/eval.d.ts +6 -24
- package/dist/eval/eval.js +7 -34
- package/dist/eval/judgment.d.ts +0 -3
- package/dist/eval/judgment.js +19 -11
- package/dist/extensions/openclaw-plugin/index.js +1 -1
- package/dist/graph/extract.d.ts +5 -27
- package/dist/graph/extract.js +7 -33
- package/dist/graph/recall.d.ts +7 -20
- package/dist/graph/recall.js +14 -76
- package/dist/graph/stream.d.ts +7 -39
- package/dist/graph/stream.js +11 -34
- package/dist/graph/view.d.ts +9 -35
- package/dist/graph/view.js +11 -39
- package/dist/hooks/codex-wrapper.js +2 -2
- package/dist/hooks/copilot.js +2 -1
- package/dist/hooks/hook-blocks.d.ts +6 -2
- package/dist/hooks/hook-blocks.js +37 -124
- package/dist/hooks/json-hooks.d.ts +4 -36
- package/dist/hooks/json-hooks.js +18 -57
- package/dist/hooks/opencode.d.ts +0 -38
- package/dist/hooks/opencode.js +9 -76
- package/dist/hooks/shared.d.ts +8 -17
- package/dist/hooks/shared.js +29 -20
- package/dist/importers/core.d.ts +12 -37
- package/dist/importers/core.js +9 -27
- package/dist/importers/markdown-parse.d.ts +8 -22
- package/dist/importers/markdown-parse.js +8 -25
- package/dist/importers/markdown.js +3 -12
- package/dist/importers/sources.js +7 -35
- package/dist/importers/vault.d.ts +2 -8
- package/dist/importers/vault.js +25 -81
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/learn/autolearn.d.ts +14 -41
- package/dist/learn/autolearn.js +14 -41
- package/dist/learn/extract.js +2 -4
- package/dist/learn/forward-claim-detector.d.ts +6 -30
- package/dist/learn/forward-claim-detector.js +14 -66
- package/dist/learn/invalidation.d.ts +6 -18
- package/dist/learn/invalidation.js +9 -26
- package/dist/mcp/admin-tools.js +3 -5
- package/dist/mcp/memory-tools.js +4 -9
- package/dist/mcp/protocol.d.ts +8 -26
- package/dist/mcp/protocol.js +3 -6
- package/dist/mcp/recall-tools.js +3 -3
- package/dist/mcp/request.d.ts +3 -11
- package/dist/mcp/request.js +10 -26
- package/dist/mcp/server.d.ts +3 -9
- package/dist/mcp/server.js +5 -16
- package/dist/mcp/session-state.d.ts +1 -1
- package/dist/mcp/session-state.js +5 -11
- package/dist/mcp/stdio.d.ts +2 -6
- package/dist/mcp/stdio.js +48 -12
- package/dist/mcp/tools.js +5 -3
- package/dist/objects/customer-notes.d.ts +7 -42
- package/dist/objects/customer-notes.js +7 -48
- package/dist/objects/decisions.d.ts +12 -50
- package/dist/objects/decisions.js +15 -53
- package/dist/objects/incidents.d.ts +7 -38
- package/dist/objects/incidents.js +7 -41
- package/dist/objects/policies.d.ts +11 -89
- package/dist/objects/policies.js +11 -98
- package/dist/objects/processes.d.ts +7 -52
- package/dist/objects/processes.js +7 -61
- package/dist/objects/project-briefs.d.ts +11 -55
- package/dist/objects/project-briefs.js +14 -75
- package/dist/objects/skills.d.ts +7 -42
- package/dist/objects/skills.js +8 -54
- package/dist/postinstall.js +6 -19
- package/dist/predictions/planning-fallacy.d.ts +11 -34
- package/dist/rerankers/clef.js +3 -31
- package/dist/rerankers/cross-encoder.js +4 -6
- package/dist/rerankers/jev.js +9 -6
- package/dist/rerankers/llm.d.ts +2 -11
- package/dist/rerankers/llm.js +14 -14
- package/dist/rerankers/outage-warning.d.ts +2 -1
- package/dist/rerankers/outage-warning.js +2 -1
- package/dist/rerankers/remote.d.ts +1 -0
- package/dist/rerankers/remote.js +2 -0
- package/dist/rerankers/types.d.ts +2 -14
- package/dist/search/boosts.d.ts +0 -2
- package/dist/search/boosts.js +2 -2
- package/dist/search/goal-boost.d.ts +23 -0
- package/dist/search/goal-boost.js +90 -0
- package/dist/search/hybrid.d.ts +2 -0
- package/dist/search/multihop.js +2 -3
- package/dist/search/path-context.d.ts +5 -18
- package/dist/search/path-context.js +5 -18
- package/dist/search/physics-search.js +11 -8
- package/dist/search/rrf.d.ts +7 -35
- package/dist/search/rrf.js +5 -30
- package/dist/search/vector.d.ts +7 -0
- package/dist/search/vector.js +35 -5
- package/dist/server/auth.d.ts +9 -28
- package/dist/server/auth.js +32 -25
- package/dist/server/boot.d.ts +2 -21
- package/dist/server/boot.js +63 -96
- package/dist/server/client-ip.d.ts +3 -19
- package/dist/server/client-ip.js +5 -28
- package/dist/server/defaults.d.ts +3 -0
- package/dist/server/defaults.js +4 -0
- package/dist/server/key-check-bounds.d.ts +2 -1
- package/dist/server/lifecycle.d.ts +5 -4
- package/dist/server/lifecycle.js +19 -4
- package/dist/server/mcp-http.js +10 -44
- package/dist/server/rate-limit.d.ts +5 -18
- package/dist/server/rate-limit.js +4 -13
- package/dist/server/request.d.ts +4 -8
- package/dist/server/request.js +9 -17
- package/dist/server/route-table.js +42 -49
- package/dist/server/routes/admin.js +22 -28
- package/dist/server/routes/customer-notes.js +7 -12
- package/dist/server/routes/decisions.js +10 -17
- package/dist/server/routes/incidents.js +12 -20
- package/dist/server/routes/memories.js +12 -32
- package/dist/server/routes/object-routes.d.ts +0 -5
- package/dist/server/routes/object-routes.js +7 -15
- package/dist/server/routes/policies.js +10 -18
- package/dist/server/routes/predictions.js +13 -25
- package/dist/server/routes/processes.js +16 -26
- package/dist/server/routes/project-briefs.js +9 -16
- package/dist/server/routes/recall.js +10 -35
- package/dist/server/routes/skills.js +8 -18
- package/dist/server/server-detect.d.ts +9 -53
- package/dist/server/server-detect.js +24 -90
- package/dist/server/sleep-offload.js +4 -1
- package/dist/server/types.d.ts +12 -10
- package/dist/server/validation.d.ts +3 -1
- package/dist/server/validation.js +10 -23
- package/dist/server.d.ts +2 -2
- package/dist/server.js +3 -2
- package/dist/sharing/global-store.d.ts +19 -0
- package/dist/sharing/global-store.js +75 -0
- package/dist/sharing/global-sync.d.ts +6 -0
- package/dist/sharing/global-sync.js +80 -0
- package/dist/sharing/project-merge.d.ts +4 -5
- package/dist/sharing/project-merge.js +9 -7
- package/dist/sharing/scope.d.ts +4 -11
- package/dist/sharing/scope.js +4 -11
- package/dist/sharing/search-both.d.ts +60 -0
- package/dist/sharing/search-both.js +138 -0
- package/dist/sharing/share.d.ts +38 -0
- package/dist/sharing/share.js +226 -0
- package/dist/store/ambient.js +4 -9
- package/dist/store/audit-event.d.ts +4 -12
- package/dist/store/audit-event.js +4 -12
- package/dist/store/audit.d.ts +2 -5
- package/dist/store/audit.js +4 -12
- package/dist/store/auth.d.ts +6 -6
- package/dist/store/auth.js +10 -9
- package/dist/store/candidates.d.ts +20 -3
- package/dist/store/candidates.js +77 -48
- package/dist/store/card-detail.d.ts +2 -1
- package/dist/store/card-detail.js +2 -1
- package/dist/store/cards.d.ts +14 -9
- package/dist/store/cards.js +72 -126
- package/dist/store/conflicts.d.ts +4 -21
- package/dist/store/conflicts.js +71 -150
- package/dist/store/connectors/github.d.ts +10 -10
- package/dist/store/connectors/github.js +10 -10
- package/dist/store/dashboard-reads.js +4 -8
- package/dist/store/delete-and-batch.d.ts +11 -31
- package/dist/store/delete-and-batch.js +48 -64
- package/dist/store/delivery-recorder.d.ts +8 -4
- package/dist/store/delivery-recorder.js +25 -15
- package/dist/store/diagnostics.js +6 -13
- package/dist/store/dormant.d.ts +7 -29
- package/dist/store/dormant.js +15 -56
- package/dist/store/embeddings/index.d.ts +11 -80
- package/dist/store/embeddings/index.js +71 -207
- package/dist/store/embeddings/local.js +15 -32
- package/dist/store/embeddings/provider.d.ts +16 -53
- package/dist/store/embeddings/provider.js +41 -69
- package/dist/store/entry-reads.d.ts +21 -57
- package/dist/store/entry-reads.js +65 -126
- package/dist/store/entry-row.d.ts +6 -35
- package/dist/store/entry-row.js +9 -37
- package/dist/store/entry-writes.d.ts +10 -16
- package/dist/store/entry-writes.js +17 -35
- package/dist/store/goals.d.ts +3 -40
- package/dist/store/goals.js +21 -160
- package/dist/store/graph-queue.d.ts +6 -22
- package/dist/store/graph-queue.js +14 -45
- package/dist/store/graph-reads.d.ts +11 -35
- package/dist/store/graph-reads.js +20 -58
- package/dist/store/graph-rows.d.ts +3 -6
- package/dist/store/graph-rows.js +6 -9
- package/dist/store/graph-view-rows.d.ts +2 -1
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +6 -31
- package/dist/store/graph-writes.js +13 -37
- package/dist/store/half-life.d.ts +2 -1
- package/dist/store/half-life.js +14 -16
- package/dist/store/handoffs.d.ts +5 -11
- package/dist/store/handoffs.js +16 -34
- package/dist/store/index-and-stats.d.ts +6 -19
- package/dist/store/index-and-stats.js +34 -82
- package/dist/store/markdown.d.ts +2 -6
- package/dist/store/markdown.js +21 -20
- package/dist/store/mirrors.d.ts +2 -6
- package/dist/store/mirrors.js +14 -23
- package/dist/store/open.js +6 -13
- package/dist/store/planning-fallacy-evidence.d.ts +2 -30
- package/dist/store/planning-fallacy-evidence.js +8 -37
- package/dist/store/port.d.ts +82 -79
- package/dist/store/predictions.d.ts +11 -51
- package/dist/store/predictions.js +38 -119
- package/dist/{cli → store}/quality-repair.js +15 -31
- package/dist/store/raw-archive.d.ts +4 -16
- package/dist/store/raw-archive.js +14 -29
- package/dist/store/recall-scope.d.ts +19 -79
- package/dist/store/recall-scope.js +21 -82
- package/dist/store/recall-trace.d.ts +10 -77
- package/dist/store/recall-trace.js +19 -95
- package/dist/store/rejected-values.js +7 -19
- package/dist/store/rejection.d.ts +12 -58
- package/dist/store/rejection.js +13 -65
- package/dist/store/report-reads.d.ts +6 -0
- package/dist/store/report-reads.js +29 -0
- package/dist/store/rows.d.ts +9 -19
- package/dist/store/rows.js +36 -34
- package/dist/store/rule-sql.d.ts +5 -0
- package/dist/store/rule-sql.js +37 -0
- package/dist/store/search-rows.d.ts +7 -38
- package/dist/store/search-rows.js +14 -50
- package/dist/store/sessions.d.ts +10 -47
- package/dist/store/sessions.js +17 -73
- package/dist/store/sqlite/connector-events-group.js +2 -2
- package/dist/store/sqlite/entry-writes-group.js +2 -2
- package/dist/store/sqlite/error-codec.js +4 -2
- package/dist/store/sqlite/executor.d.ts +2 -1
- package/dist/store/sqlite/executor.js +2 -1
- package/dist/store/sqlite/local.d.ts +3 -3
- package/dist/store/sqlite/local.js +1 -0
- package/dist/store/sqlite/object-rows.js +6 -3
- package/dist/store/sqlite/objects-group.js +4 -2
- package/dist/store/sqlite/quarantine-group.js +2 -2
- package/dist/store/sqlite/store.d.ts +1 -4
- package/dist/store/sqlite/store.js +2 -3
- package/dist/store/sqlite/vector-reads-group.js +2 -2
- package/dist/store/sqlite/worker-jobs.js +1 -1
- package/dist/store/sqlite/worker-ops.d.ts +13 -2
- package/dist/store/sqlite/worker-ops.js +13 -2
- package/dist/store/sqlite/worker-store.js +5 -2
- package/dist/store/summaries.d.ts +10 -62
- package/dist/store/summaries.js +34 -146
- package/dist/store/summary-dirty.js +1 -1
- package/dist/store/tenant-lookup.d.ts +6 -1
- package/dist/store/tenant-lookup.js +7 -0
- package/dist/store/tenant.d.ts +2 -16
- package/dist/store/tenant.js +4 -19
- package/dist/store/token-ledger.d.ts +13 -43
- package/dist/store/token-ledger.js +19 -50
- package/dist/store/usage-reports.js +5 -13
- package/dist/store/vector-index.d.ts +46 -0
- package/dist/store/vector-index.js +170 -0
- package/dist/store/working-memory.d.ts +6 -25
- package/dist/store/working-memory.js +18 -52
- package/dist/store/yaml.d.ts +1 -5
- package/dist/store/yaml.js +2 -6
- package/dist/support-bundle.js +7 -5
- package/dist/trust/reject-flow.js +1 -3
- package/dist/util/anthropic-messages.js +14 -2
- package/dist/util/atomic-write.d.ts +2 -1
- package/dist/util/atomic-write.js +35 -4
- package/dist/util/capped-json.d.ts +6 -0
- package/dist/util/capped-json.js +46 -0
- package/dist/util/crash-handlers.d.ts +8 -1
- package/dist/util/crash-handlers.js +52 -10
- package/dist/util/env.d.ts +13 -6
- package/dist/util/env.js +14 -7
- package/dist/util/home-path.d.ts +2 -1
- package/dist/util/home-path.js +4 -2
- package/dist/util/http-retry.d.ts +3 -1
- package/dist/util/http-retry.js +26 -5
- package/dist/util/log.d.ts +3 -2
- package/dist/util/log.js +25 -9
- package/dist/util/request-scope.d.ts +2 -1
- package/dist/util/request-scope.js +2 -1
- package/dist/util/secret-detect.d.ts +5 -30
- package/dist/util/secret-detect.js +13 -39
- package/dist/util/stored-json.d.ts +1 -1
- package/dist/util/stored-json.js +1 -1
- package/dist/util/token-text.d.ts +1 -4
- package/dist/util/token-text.js +1 -4
- package/dist/util/transcript-tail.d.ts +2 -0
- package/dist/util/transcript-tail.js +24 -23
- package/dist/util/version.d.ts +5 -20
- package/dist/util/version.js +5 -20
- package/extensions/openclaw-plugin/index.ts +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/connectors/github/cli-impl.d.ts +0 -25
- package/dist/sharing/shared.d.ts +0 -187
- package/dist/sharing/shared.js +0 -563
- package/dist/store/vector-writes.d.ts +0 -13
- package/dist/store/vector-writes.js +0 -89
- /package/dist/{cli → store}/quality-repair.d.ts +0 -0
|
@@ -1,32 +1,22 @@
|
|
|
1
1
|
import { closeHippoDb } from '../db/index.js';
|
|
2
2
|
import { MEMORY_SELECT_COLUMNS, rowToEntry, parseJsonArray } from './rows.js';
|
|
3
|
-
import { openStore } from './open.js';
|
|
3
|
+
import { onHandle, openStore } from './open.js';
|
|
4
4
|
import { escapeLike } from '../util/escape.js';
|
|
5
5
|
import { originInSql } from '../core/project-identity.js';
|
|
6
6
|
import { scopeAdmitSql } from './recall-scope.js';
|
|
7
7
|
const MAX_IDS_PER_READ = 500;
|
|
8
8
|
// The plus keeps SQLite on the primary key for an id list: with a bare tenant_id it walks every row of the tenant instead.
|
|
9
9
|
export const TENANT_IS = '+tenant_id = ?';
|
|
10
|
-
/**
|
|
11
|
-
* Read a memory entry by ID.
|
|
12
|
-
*
|
|
13
|
-
* When `tenantId` is provided, the read is scoped to that tenant (cross-tenant
|
|
14
|
-
* lookups return null). When omitted, no tenant filter is applied — preserves
|
|
15
|
-
* legacy single-tenant callers and the writeEntry/readEntry round-trip.
|
|
16
|
-
*/
|
|
10
|
+
/** Read a memory entry by ID. With `tenantId` the read is tenant-scoped (cross-tenant returns null); omitted, no tenant filter is applied. */
|
|
17
11
|
export function readEntry(hippoRoot, id, tenantId) {
|
|
18
|
-
|
|
19
|
-
try {
|
|
12
|
+
return onHandle(hippoRoot, (db) => {
|
|
20
13
|
// SAFETY: both branches select exactly MEMORY_SELECT_COLUMNS, matching
|
|
21
14
|
// MemoryRow's field set.
|
|
22
15
|
const row = tenantId !== undefined
|
|
23
16
|
? db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id = ? AND tenant_id = ?`).get(id, tenantId)
|
|
24
17
|
: db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id = ?`).get(id);
|
|
25
18
|
return row ? rowToEntry(row) : null;
|
|
26
|
-
}
|
|
27
|
-
finally {
|
|
28
|
-
closeHippoDb(db);
|
|
29
|
-
}
|
|
19
|
+
}, openStore);
|
|
30
20
|
}
|
|
31
21
|
/** Ids per `IN (...)` list: far under SQLite's bound-parameter limit, with room for the tenant filter. */
|
|
32
22
|
export const ID_CHUNK = 500;
|
|
@@ -41,8 +31,7 @@ export function chunked(items, size = ID_CHUNK) {
|
|
|
41
31
|
export function heldIdLookup(hippoRoot, tenantId, ids) {
|
|
42
32
|
const held = new Map();
|
|
43
33
|
const lookUp = (asked) => {
|
|
44
|
-
|
|
45
|
-
try {
|
|
34
|
+
onHandle(hippoRoot, (db) => {
|
|
46
35
|
for (const chunk of chunked([...new Set(asked)])) {
|
|
47
36
|
for (const id of chunk)
|
|
48
37
|
held.set(id, false);
|
|
@@ -51,10 +40,7 @@ export function heldIdLookup(hippoRoot, tenantId, ids) {
|
|
|
51
40
|
for (const row of rows)
|
|
52
41
|
held.set(row.id, true);
|
|
53
42
|
}
|
|
54
|
-
}
|
|
55
|
-
finally {
|
|
56
|
-
closeHippoDb(db);
|
|
57
|
-
}
|
|
43
|
+
}, openStore);
|
|
58
44
|
};
|
|
59
45
|
if (ids.length > 0)
|
|
60
46
|
lookUp(ids);
|
|
@@ -99,48 +85,30 @@ export function selectChildrenByParent(db, parentIds, tenantId) {
|
|
|
99
85
|
}
|
|
100
86
|
return byParent;
|
|
101
87
|
}
|
|
102
|
-
/**
|
|
103
|
-
* Batched lookup. Caps at 500 ids per call to keep the IN(?,?,...) clause
|
|
104
|
-
* within SQLite limits. Tenant filter is enforced when `tenantId` is passed.
|
|
105
|
-
* Used by DAG-aware recall to fetch parent summaries for a set of overflowed leaves.
|
|
106
|
-
*/
|
|
88
|
+
/** Batched lookup, capped at 500 ids per call to keep IN(?,?,...) within SQLite limits; tenant filter enforced when `tenantId` is passed. */
|
|
107
89
|
export function loadEntriesByIds(hippoRoot, ids, tenantId) {
|
|
108
90
|
if (ids.length === 0)
|
|
109
91
|
return [];
|
|
110
92
|
const capped = ids.slice(0, MAX_IDS_PER_READ);
|
|
111
|
-
|
|
112
|
-
try {
|
|
93
|
+
return onHandle(hippoRoot, (db) => {
|
|
113
94
|
const placeholders = capped.map(() => '?').join(',');
|
|
114
|
-
// Without ORDER BY, rows follow SQLite's IN(...) scan order,
|
|
115
|
-
// SAFETY: both branches select exactly MEMORY_SELECT_COLUMNS, matching
|
|
116
|
-
// MemoryRow's field set.
|
|
95
|
+
// Without ORDER BY, rows follow SQLite's IN(...) scan order, undefined w.r.t. `ids`.
|
|
96
|
+
// SAFETY: both branches select exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
117
97
|
const rows = tenantId !== undefined
|
|
118
98
|
? db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${placeholders}) AND ${TENANT_IS} ORDER BY created ASC, content ASC, id ASC`).all(...capped, tenantId)
|
|
119
99
|
: db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE id IN (${placeholders}) ORDER BY created ASC, content ASC, id ASC`).all(...capped);
|
|
120
100
|
return rows.map(rowToEntry);
|
|
121
|
-
}
|
|
122
|
-
finally {
|
|
123
|
-
closeHippoDb(db);
|
|
124
|
-
}
|
|
101
|
+
}, openStore);
|
|
125
102
|
}
|
|
126
103
|
function originClause(origins) {
|
|
127
104
|
return origins === undefined ? '' : ` AND (origin_project = '' OR ${originInSql(origins)})`;
|
|
128
105
|
}
|
|
129
|
-
/**
|
|
130
|
-
*
|
|
131
|
-
* oldest-first. Used by `api.assemble` to walk a session's chronological
|
|
132
|
-
* context. Excludes superseded rows.
|
|
133
|
-
*
|
|
134
|
-
* Cap semantics: when `cap` is provided, the NEWEST `cap` rows are loaded (DESC LIMIT server-side,
|
|
135
|
-
* reversed client-side); ASC + LIMIT would drop the newest rows and break fresh-tail in assemble.
|
|
136
|
-
*
|
|
137
|
-
* Returns `[]` for an empty sessionId. Final order: `created ASC, id ASC`.
|
|
138
|
-
*/
|
|
106
|
+
/** All `kind='raw'` rows for a session, tenant-scoped, oldest-first, excluding superseded; `[]` for an empty sessionId.
|
|
107
|
+
* With `cap`, the NEWEST rows are loaded (DESC LIMIT, reversed client-side); ASC + LIMIT would drop the newest and break fresh-tail in assemble. */
|
|
139
108
|
export function loadSessionRawMemories(hippoRoot, sessionId, tenantId, cap, origins) {
|
|
140
109
|
if (!sessionId)
|
|
141
110
|
return [];
|
|
142
|
-
|
|
143
|
-
try {
|
|
111
|
+
return onHandle(hippoRoot, (db) => {
|
|
144
112
|
const params = [];
|
|
145
113
|
let sql = `SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE kind = 'raw' AND source_session_id = ? AND superseded_by IS NULL`;
|
|
146
114
|
params.push(sessionId);
|
|
@@ -161,29 +129,14 @@ export function loadSessionRawMemories(hippoRoot, sessionId, tenantId, cap, orig
|
|
|
161
129
|
// SAFETY: sql starts from MEMORY_SELECT_COLUMNS, matching MemoryRow.
|
|
162
130
|
const rows = db.prepare(sql).all(...params);
|
|
163
131
|
return rows.map(rowToEntry);
|
|
164
|
-
}
|
|
165
|
-
finally {
|
|
166
|
-
closeHippoDb(db);
|
|
167
|
-
}
|
|
132
|
+
}, openStore);
|
|
168
133
|
}
|
|
169
|
-
/**
|
|
170
|
-
*
|
|
171
|
-
* the full session size even when `rowCap` truncates the loaded window,
|
|
172
|
-
* WITHOUT leaking rows the caller wouldn't have been allowed to load.
|
|
173
|
-
*
|
|
174
|
-
* An unscoped COUNT would let a no-scope caller infer private rows by comparing `totalRaw`
|
|
175
|
-
* against `items.length`, so this SQL-encodes the default-deny rule `passesScopeFilterForRecall` applies in TS:
|
|
176
|
-
* - explicit scope passed: exact-match
|
|
177
|
-
* - no scope: `scopeAdmitSql`'s default deny, which admits `ownScope`, the caller's personal scope.
|
|
178
|
-
*
|
|
179
|
-
* `tenantId` is optional for back-compat. Pass `undefined` only when
|
|
180
|
-
* intentionally counting cross-tenant; `assemble()` passes `ctx.tenantId`.
|
|
181
|
-
*/
|
|
134
|
+
/** Pre-cap, scope-aware row count for a session, so `assemble` reports the full size without leaking rows the caller could not load. Mirrors
|
|
135
|
+
* `passesScopeFilterForRecall`'s default-deny: explicit scope matches exactly, none admits only `ownScope`. `tenantId` undefined counts cross-tenant. */
|
|
182
136
|
export function countSessionRawMemories(hippoRoot, sessionId, tenantId, scope, ownScope, origins) {
|
|
183
137
|
if (!sessionId)
|
|
184
138
|
return 0;
|
|
185
|
-
|
|
186
|
-
try {
|
|
139
|
+
return onHandle(hippoRoot, (db) => {
|
|
187
140
|
const params = [];
|
|
188
141
|
let sql = `SELECT COUNT(*) AS c FROM memories WHERE kind = 'raw' AND source_session_id = ? AND superseded_by IS NULL`;
|
|
189
142
|
params.push(sessionId);
|
|
@@ -205,31 +158,15 @@ export function countSessionRawMemories(hippoRoot, sessionId, tenantId, scope, o
|
|
|
205
158
|
// SAFETY: row's shape matches the single `COUNT(*) AS c` column above.
|
|
206
159
|
const row = db.prepare(sql).get(...params);
|
|
207
160
|
return Number(row?.c ?? 0);
|
|
208
|
-
}
|
|
209
|
-
finally {
|
|
210
|
-
closeHippoDb(db);
|
|
211
|
-
}
|
|
161
|
+
}, openStore);
|
|
212
162
|
}
|
|
213
|
-
/**
|
|
214
|
-
*
|
|
215
|
-
* `sessionId` is supplied, also constrains to a specific session — that
|
|
216
|
-
* is the correct shape for "what did I just see in THIS session."
|
|
217
|
-
*
|
|
218
|
-
* Without `sessionId`, concurrent sessions in a tenant surface each other's rows as fresh tail;
|
|
219
|
-
* pass undefined only for "anything new across the whole tenant".
|
|
220
|
-
*
|
|
221
|
-
* Bounded count cap at 200 — beyond that the caller should filter via
|
|
222
|
-
* tags/scope rather than time-windowed recall.
|
|
223
|
-
*
|
|
224
|
-
* The tenant-wide shape is the back-compat default but discouraged; `api.recall` throws
|
|
225
|
-
* `RecallContractError` for it when `HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1` is set.
|
|
226
|
-
*/
|
|
163
|
+
/** Last N kind='raw' memories by `created` desc, tenant-scoped, max 200; pass `sessionId` or concurrent sessions show up in each other's fresh tail.
|
|
164
|
+
* The tenant-wide shape is discouraged: `api.recall` throws `RecallContractError` for it when `HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1`. */
|
|
227
165
|
export function loadFreshRawMemories(hippoRoot, count, tenantId, sessionId, origins) {
|
|
228
166
|
if (count <= 0)
|
|
229
167
|
return [];
|
|
230
168
|
const capped = Math.min(count, 200);
|
|
231
|
-
|
|
232
|
-
try {
|
|
169
|
+
return onHandle(hippoRoot, (db) => {
|
|
233
170
|
const params = [];
|
|
234
171
|
let sql = `SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE kind = 'raw' AND superseded_by IS NULL`;
|
|
235
172
|
if (tenantId !== undefined) {
|
|
@@ -249,35 +186,52 @@ export function loadFreshRawMemories(hippoRoot, count, tenantId, sessionId, orig
|
|
|
249
186
|
// SAFETY: sql starts from MEMORY_SELECT_COLUMNS, matching MemoryRow.
|
|
250
187
|
const rows = db.prepare(sql).all(...params);
|
|
251
188
|
return rows.map(rowToEntry);
|
|
252
|
-
}
|
|
253
|
-
finally {
|
|
254
|
-
closeHippoDb(db);
|
|
255
|
-
}
|
|
189
|
+
}, openStore);
|
|
256
190
|
}
|
|
257
|
-
/**
|
|
258
|
-
* Load all entries from SQLite.
|
|
259
|
-
*
|
|
260
|
-
* When `tenantId` is provided, results are scoped to that tenant. Omitting it
|
|
261
|
-
* yields all rows (legacy behavior used by consolidate/autolearn etc.). Recall
|
|
262
|
-
* paths that surface results to a user MUST pass a resolved tenant.
|
|
263
|
-
*/
|
|
191
|
+
/** Load all entries from SQLite; omitting `tenantId` yields all rows (legacy). Recall paths that surface results to a user MUST pass a resolved tenant. */
|
|
264
192
|
export function loadAllEntries(hippoRoot, tenantId) {
|
|
193
|
+
return onHandle(hippoRoot, (db) => {
|
|
194
|
+
return selectAllEntries(db, tenantId);
|
|
195
|
+
}, openStore);
|
|
196
|
+
}
|
|
197
|
+
/** Every tenant's memory ids in loadAllEntries' order, for a caller that reads the rows a page at a time instead of holding them all. */
|
|
198
|
+
export function loadAllEntryIds(hippoRoot) {
|
|
199
|
+
return onHandle(hippoRoot, (db) => {
|
|
200
|
+
// SAFETY: the SELECT names exactly the one column read.
|
|
201
|
+
return db.prepare('SELECT id FROM memories ORDER BY created ASC, id ASC').all().map((row) => row.id);
|
|
202
|
+
}, openStore);
|
|
203
|
+
}
|
|
204
|
+
/** Every entry plus a by-id lookup of each as loaded, rebuilt from its row on first use, so no deep copy of the store is kept. */
|
|
205
|
+
export function loadAllEntriesWithBase(hippoRoot) {
|
|
265
206
|
const db = openStore(hippoRoot);
|
|
207
|
+
let rows;
|
|
266
208
|
try {
|
|
267
|
-
|
|
209
|
+
rows = selectAllRows(db);
|
|
268
210
|
}
|
|
269
211
|
finally {
|
|
270
212
|
closeHippoDb(db);
|
|
271
213
|
}
|
|
214
|
+
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
215
|
+
const built = new Map();
|
|
216
|
+
const get = (id) => {
|
|
217
|
+
let entry = built.get(id);
|
|
218
|
+
const row = byId.get(id);
|
|
219
|
+
if (!entry && row)
|
|
220
|
+
built.set(id, (entry = rowToEntry(row)));
|
|
221
|
+
return entry;
|
|
222
|
+
};
|
|
223
|
+
return { entries: rows.map(rowToEntry), base: { get } };
|
|
272
224
|
}
|
|
273
|
-
|
|
274
|
-
export function selectAllEntries(db, tenantId) {
|
|
225
|
+
function selectAllRows(db, tenantId) {
|
|
275
226
|
// SAFETY: both branches select exactly MEMORY_SELECT_COLUMNS, matching
|
|
276
227
|
// MemoryRow's field set.
|
|
277
|
-
|
|
228
|
+
return tenantId !== undefined
|
|
278
229
|
? db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE tenant_id = ? ORDER BY created ASC, id ASC`).all(tenantId)
|
|
279
230
|
: db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories ORDER BY created ASC, id ASC`).all();
|
|
280
|
-
|
|
231
|
+
}
|
|
232
|
+
/** Every memory row on an open connection, so a caller can read inside its own transaction. */
|
|
233
|
+
export function selectAllEntries(db, tenantId) {
|
|
234
|
+
return selectAllRows(db, tenantId).map(rowToEntry);
|
|
281
235
|
}
|
|
282
236
|
/** Live rows whose source starts with `prefix`, on the caller's handle; LIKE folds case, so the prefix is checked again exactly. */
|
|
283
237
|
export function selectLiveEntriesBySourcePrefix(db, tenantId, prefix) {
|
|
@@ -288,32 +242,24 @@ export function selectLiveEntriesBySourcePrefix(db, tenantId, prefix) {
|
|
|
288
242
|
// Content of every team-visible tenant row tagged `tag`, without reading the rest of the store; `origins` keeps one project's rows and user-global ones.
|
|
289
243
|
// No owner: a personal or connector-private row must never answer `duplicate` for, or stop, a team copy. `instr` prefilters; `includes` re-checks.
|
|
290
244
|
export function loadContentsWithTag(hippoRoot, tenantId, tag, origins) {
|
|
291
|
-
|
|
292
|
-
try {
|
|
245
|
+
return onHandle(hippoRoot, (db) => {
|
|
293
246
|
const inProject = origins === undefined ? '' : ` AND (origin_project = '' OR ${originInSql(origins)})`;
|
|
294
247
|
const admit = scopeAdmitSql('');
|
|
295
248
|
/** SAFETY: rows' shape matches the two columns named in the SELECT below. */
|
|
296
249
|
const rows = db.prepare(`SELECT content, tags_json FROM memories WHERE tenant_id = ? AND instr(tags_json, ?) > 0${inProject} AND ${admit.sql}`).all(tenantId, JSON.stringify(tag), ...(origins ?? []), ...admit.params);
|
|
297
250
|
return rows.filter((r) => parseJsonArray(r.tags_json).includes(tag)).map((r) => r.content);
|
|
298
|
-
}
|
|
299
|
-
finally {
|
|
300
|
-
closeHippoDb(db);
|
|
301
|
-
}
|
|
251
|
+
}, openStore);
|
|
302
252
|
}
|
|
303
253
|
/** Live raw rows whose artifact_ref matches a LIKE pattern, for one tenant; the store is set up first when it is new. */
|
|
304
254
|
export function loadVaultRawRows(hippoRoot, likeParam, tenantId) {
|
|
305
|
-
|
|
306
|
-
try {
|
|
255
|
+
return onHandle(hippoRoot, (db) => {
|
|
307
256
|
// SAFETY: query selects exactly the columns of VaultRawRow, in the same
|
|
308
257
|
// names, from the memories table this module owns.
|
|
309
258
|
return db
|
|
310
259
|
.prepare(`SELECT id, artifact_ref, tags_json, scope FROM memories
|
|
311
260
|
WHERE artifact_ref LIKE ? ESCAPE '\\' AND tenant_id = ? AND kind = 'raw'`)
|
|
312
261
|
.all(likeParam, tenantId);
|
|
313
|
-
}
|
|
314
|
-
finally {
|
|
315
|
-
closeHippoDb(db);
|
|
316
|
-
}
|
|
262
|
+
}, openStore);
|
|
317
263
|
}
|
|
318
264
|
/** Reads memories from a store whose schema may predate some columns; `columns` is the table's real column set. */
|
|
319
265
|
export function selectPreviewRows(db, columns, tenantId) {
|
|
@@ -352,10 +298,10 @@ export function selectRowsOutsideSourcePrefixAt(db, tenantId, sourcePrefix, orig
|
|
|
352
298
|
return db.prepare(`SELECT id, content, source FROM memories
|
|
353
299
|
WHERE tenant_id = ? AND superseded_by IS NULL AND substr(source, 1, ${sourcePrefix.length}) != ?${visible}`).all(...params);
|
|
354
300
|
}
|
|
355
|
-
/** Content of a tenant's live rows written by `source` and tagged `tag` that no extraction produced,
|
|
301
|
+
/** Content of a tenant's live rows written by `source` and tagged `tag` that no extraction produced,
|
|
302
|
+
* in loadAllEntries' order and in every scope; `exceptSessionId` drops one session's own rows. */
|
|
356
303
|
export function loadLiveContentsBySourceAndTag(hippoRoot, tenantId, source, tag, exceptSessionId) {
|
|
357
|
-
|
|
358
|
-
try {
|
|
304
|
+
return onHandle(hippoRoot, (db) => {
|
|
359
305
|
/** SAFETY: rows' shape matches the two columns named in the SELECT below. */
|
|
360
306
|
const rows = db.prepare(`SELECT content, tags_json FROM memories
|
|
361
307
|
WHERE tenant_id = ? AND source = ? AND instr(tags_json, ?) > 0
|
|
@@ -363,23 +309,16 @@ export function loadLiveContentsBySourceAndTag(hippoRoot, tenantId, source, tag,
|
|
|
363
309
|
AND (source_session_id IS NULL OR source_session_id != ?)
|
|
364
310
|
ORDER BY created ASC, id ASC`).all(tenantId, source, JSON.stringify(tag), exceptSessionId);
|
|
365
311
|
return rows.filter((r) => parseJsonArray(r.tags_json).includes(tag)).map((r) => r.content);
|
|
366
|
-
}
|
|
367
|
-
finally {
|
|
368
|
-
closeHippoDb(db);
|
|
369
|
-
}
|
|
312
|
+
}, openStore);
|
|
370
313
|
}
|
|
371
314
|
/** Every tenant's distilled rows nothing has superseded, in loadAllEntries' order: the rows that can be each other's duplicate. */
|
|
372
315
|
export function loadCurrentDistilledEntries(hippoRoot) {
|
|
373
|
-
|
|
374
|
-
try {
|
|
316
|
+
return onHandle(hippoRoot, (db) => {
|
|
375
317
|
// SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
|
|
376
318
|
const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories
|
|
377
319
|
WHERE COALESCE(kind, 'distilled') = 'distilled' AND COALESCE(superseded_by, '') = ''
|
|
378
320
|
ORDER BY created ASC, id ASC`).all();
|
|
379
321
|
return rows.map(rowToEntry);
|
|
380
|
-
}
|
|
381
|
-
finally {
|
|
382
|
-
closeHippoDb(db);
|
|
383
|
-
}
|
|
322
|
+
}, openStore);
|
|
384
323
|
}
|
|
385
324
|
//# sourceMappingURL=entry-reads.js.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { MemoryEntry } from '../core/memory.js';
|
|
2
2
|
import { openHippoDb } from '../db/index.js';
|
|
3
3
|
export declare function upsertEntryRow(db: ReturnType<typeof openHippoDb>, entry: MemoryEntry): void;
|
|
4
|
-
/** The row alone, with no rejection guard or full-text row, for `upsertEntryRow` and for
|
|
4
|
+
/** The row alone, with no rejection guard or full-text row, for `upsertEntryRow` and for
|
|
5
|
+
* `batchWriteAndDelete`, which probes tombstones and indexes per batch. Returns whether the row is new. */
|
|
5
6
|
export declare function upsertMemoryRow(db: ReturnType<typeof openHippoDb>, entry: MemoryEntry): boolean;
|
|
6
7
|
export declare function syncFtsRow(db: ReturnType<typeof openHippoDb>, entry: MemoryEntry, isNewRow?: boolean): void;
|
|
7
8
|
export declare function ftsRowExists(db: ReturnType<typeof openHippoDb>, id: string): boolean;
|
|
@@ -13,40 +14,10 @@ export declare function ftsDrift(hippoRoot: string, repair: boolean): {
|
|
|
13
14
|
memories: number;
|
|
14
15
|
fts: number;
|
|
15
16
|
} | null;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `opts.actor` defaults to 'cli' so unauthenticated direct-CLI callers still
|
|
20
|
-
* get the right audit attribution. The HTTP server and api.* layer pass
|
|
21
|
-
* the resolved actor (`api_key:<key_id>` / `localhost:cli`) so audit events
|
|
22
|
-
* land with one row per write, no double-emit.
|
|
23
|
-
*
|
|
24
|
-
* `opts.afterWrite` is invoked inside the same SAVEPOINT as the memories
|
|
25
|
-
* INSERT (mirrors archiveRawMemory's shape in raw-archive.ts). On callback
|
|
26
|
-
* throw, the SAVEPOINT rolls back — the memory row never lands, and the
|
|
27
|
-
* filesystem mirrors / audit emit never run. Used by connectors to
|
|
28
|
-
* stamp idempotency rows atomically with the memory write.
|
|
29
|
-
*/
|
|
30
|
-
/**
|
|
31
|
-
* Stamp origin_project from the store's own location when the entry has
|
|
32
|
-
* never been stamped (v39 memory scope isolation). The store dir is
|
|
33
|
-
* `<project>/.hippo`, so its parent resolves to the owning project; the
|
|
34
|
-
* home/global store resolves to '' (user-global). Callers that know a better
|
|
35
|
-
* origin (shareMemory, syncGlobalToLocal) set entry.origin_project before
|
|
36
|
-
* writing and this is a no-op. Returns a stamped copy; never mutates.
|
|
37
|
-
*
|
|
38
|
-
* NULL is PRESERVED, not re-stamped: it means no known project (a legacy row with no evidence, or a write to a
|
|
39
|
-
* shared store that named none) and ambient context denies it, so a writeback must not launder it.
|
|
40
|
-
*/
|
|
17
|
+
/** Stamp origin_project from the store's own location (parent of `<project>/.hippo`; the home store is '' = user-global) when never stamped; returns a copy.
|
|
18
|
+
* NULL is PRESERVED: it means no known project and ambient context denies it, so a writeback must not launder it. */
|
|
41
19
|
export declare function stampOriginProject(hippoRoot: string, entry: MemoryEntry): MemoryEntry;
|
|
42
|
-
/**
|
|
43
|
-
*
|
|
44
|
-
* for rows that predate the origin column - the legacy-markdown bootstrap and
|
|
45
|
-
* rebuildIndex import, which are the markdown-store equivalent of the v39 SQL
|
|
46
|
-
* backfill. Same evidence order as the migration: the provenance source
|
|
47
|
-
* (`shared:<project>:` / `promoted:<localRoot>`) wins over the destination
|
|
48
|
-
* store's location, so a shared row imported into the global store keeps its
|
|
49
|
-
* owning project instead of becoming user-global.
|
|
50
|
-
*/
|
|
20
|
+
/** Import-time variant for a mirror with no origin field (an explicit null stays null), for rows predating the origin column.
|
|
21
|
+
* Like the v39 backfill, the provenance source (`shared:<project>:` / `promoted:<localRoot>`) wins over the destination store's location. */
|
|
51
22
|
export declare function stampOriginProjectForImport(hippoRoot: string, entry: MemoryEntry): MemoryEntry;
|
|
52
23
|
//# sourceMappingURL=entry-row.d.ts.map
|
package/dist/store/entry-row.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { DEFAULT_TENANT_ID } from '../util/env.js';
|
|
1
2
|
import { closeHippoDb, ftsRowCounts, openHippoDb, isFtsAvailable, repairFtsDrift } from '../db/index.js';
|
|
2
3
|
import { fallbackOrigin, originFromSource } from '../core/project-identity.js';
|
|
3
4
|
import { checkRejectionGuard } from './rejection.js';
|
|
4
5
|
import { errorMessage, log } from '../util/log.js';
|
|
5
6
|
export function upsertEntryRow(db, entry) {
|
|
6
|
-
checkRejectionGuard(db, entry.tenantId ??
|
|
7
|
+
checkRejectionGuard(db, entry.tenantId ?? DEFAULT_TENANT_ID, entry.id, entry.content);
|
|
7
8
|
syncFtsRow(db, entry, upsertMemoryRow(db, entry));
|
|
8
9
|
}
|
|
9
|
-
/** The row alone, with no rejection guard or full-text row, for `upsertEntryRow` and for
|
|
10
|
+
/** The row alone, with no rejection guard or full-text row, for `upsertEntryRow` and for
|
|
11
|
+
* `batchWriteAndDelete`, which probes tombstones and indexes per batch. Returns whether the row is new. */
|
|
10
12
|
export function upsertMemoryRow(db, entry) {
|
|
11
13
|
const isNewRow = db.prepare(`SELECT 1 FROM memories WHERE id = ?`).get(entry.id) === undefined;
|
|
12
14
|
db.prepare(UPSERT_MEMORY_SQL).run(...memoryRowValues(entry));
|
|
@@ -102,7 +104,7 @@ function memoryRowValues(entry) {
|
|
|
102
104
|
entry.scope ?? null,
|
|
103
105
|
entry.owner ?? null,
|
|
104
106
|
entry.artifact_ref ?? null,
|
|
105
|
-
entry.tenantId ??
|
|
107
|
+
entry.tenantId ?? DEFAULT_TENANT_ID,
|
|
106
108
|
entry.origin_project ?? null,
|
|
107
109
|
entry.descendant_count ?? 0,
|
|
108
110
|
entry.earliest_at ?? null,
|
|
@@ -181,45 +183,15 @@ export function ftsDrift(hippoRoot, repair) {
|
|
|
181
183
|
closeHippoDb(db);
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
|
-
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* `opts.actor` defaults to 'cli' so unauthenticated direct-CLI callers still
|
|
188
|
-
* get the right audit attribution. The HTTP server and api.* layer pass
|
|
189
|
-
* the resolved actor (`api_key:<key_id>` / `localhost:cli`) so audit events
|
|
190
|
-
* land with one row per write, no double-emit.
|
|
191
|
-
*
|
|
192
|
-
* `opts.afterWrite` is invoked inside the same SAVEPOINT as the memories
|
|
193
|
-
* INSERT (mirrors archiveRawMemory's shape in raw-archive.ts). On callback
|
|
194
|
-
* throw, the SAVEPOINT rolls back — the memory row never lands, and the
|
|
195
|
-
* filesystem mirrors / audit emit never run. Used by connectors to
|
|
196
|
-
* stamp idempotency rows atomically with the memory write.
|
|
197
|
-
*/
|
|
198
|
-
/**
|
|
199
|
-
* Stamp origin_project from the store's own location when the entry has
|
|
200
|
-
* never been stamped (v39 memory scope isolation). The store dir is
|
|
201
|
-
* `<project>/.hippo`, so its parent resolves to the owning project; the
|
|
202
|
-
* home/global store resolves to '' (user-global). Callers that know a better
|
|
203
|
-
* origin (shareMemory, syncGlobalToLocal) set entry.origin_project before
|
|
204
|
-
* writing and this is a no-op. Returns a stamped copy; never mutates.
|
|
205
|
-
*
|
|
206
|
-
* NULL is PRESERVED, not re-stamped: it means no known project (a legacy row with no evidence, or a write to a
|
|
207
|
-
* shared store that named none) and ambient context denies it, so a writeback must not launder it.
|
|
208
|
-
*/
|
|
186
|
+
/** Stamp origin_project from the store's own location (parent of `<project>/.hippo`; the home store is '' = user-global) when never stamped; returns a copy.
|
|
187
|
+
* NULL is PRESERVED: it means no known project and ambient context denies it, so a writeback must not launder it. */
|
|
209
188
|
export function stampOriginProject(hippoRoot, entry) {
|
|
210
189
|
if (entry.origin_project !== undefined)
|
|
211
190
|
return entry;
|
|
212
191
|
return { ...entry, origin_project: fallbackOrigin(hippoRoot) };
|
|
213
192
|
}
|
|
214
|
-
/**
|
|
215
|
-
*
|
|
216
|
-
* for rows that predate the origin column - the legacy-markdown bootstrap and
|
|
217
|
-
* rebuildIndex import, which are the markdown-store equivalent of the v39 SQL
|
|
218
|
-
* backfill. Same evidence order as the migration: the provenance source
|
|
219
|
-
* (`shared:<project>:` / `promoted:<localRoot>`) wins over the destination
|
|
220
|
-
* store's location, so a shared row imported into the global store keeps its
|
|
221
|
-
* owning project instead of becoming user-global.
|
|
222
|
-
*/
|
|
193
|
+
/** Import-time variant for a mirror with no origin field (an explicit null stays null), for rows predating the origin column.
|
|
194
|
+
* Like the v39 backfill, the provenance source (`shared:<project>:` / `promoted:<localRoot>`) wins over the destination store's location. */
|
|
223
195
|
export function stampOriginProjectForImport(hippoRoot, entry) {
|
|
224
196
|
if (entry.origin_project !== undefined)
|
|
225
197
|
return entry;
|
|
@@ -6,26 +6,20 @@ export interface WriteEntryOptions {
|
|
|
6
6
|
/** Runs after the row commits and before the mirrors, on an idle connection; keep it best-effort. */
|
|
7
7
|
afterCommit?: () => void;
|
|
8
8
|
}
|
|
9
|
+
/** Write an entry to SQLite and refresh mirrors; `opts.afterWrite` runs in the same SAVEPOINT as the INSERT, so a throw rolls the row back.
|
|
10
|
+
* `opts.actor` defaults to 'cli'; the api layer passes the resolved actor so the audit log gets one row per write. */
|
|
9
11
|
export declare function writeEntry(hippoRoot: string, entry: MemoryEntry, opts?: WriteEntryOptions): void;
|
|
10
|
-
/** writeEntry for each of `entries` in one transaction, so all land or none; each
|
|
12
|
+
/** writeEntry for each of `entries` in one transaction, so all land or none; each
|
|
13
|
+
* keeps its audit row, and mirrors follow the commit. Returns how many were written. */
|
|
11
14
|
export declare function writeEntriesTogether(hippoRoot: string, entries: readonly MemoryEntry[]): number;
|
|
12
|
-
/** writeEntry for each of `entries` on one open store, so the open and its lock wait are
|
|
15
|
+
/** writeEntry for each of `entries` on one open store, so the open and its lock wait are
|
|
16
|
+
* paid once; each row commits alone, and none opens the store when the list is empty. */
|
|
13
17
|
export declare function writeEntriesSeparately(hippoRoot: string, entries: readonly MemoryEntry[]): void;
|
|
14
|
-
/** Adds `tag` to each of a tenant's rows that lacks it, in `ids` order, each read fresh
|
|
18
|
+
/** Adds `tag` to each of a tenant's rows that lacks it, in `ids` order, each read fresh
|
|
19
|
+
* on one open store and committed alone; an id the tenant does not hold is skipped. */
|
|
15
20
|
export declare function addTagToEntries(hippoRoot: string, tenantId: string, ids: readonly string[], tag: string): void;
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
18
|
-
* afterWrite hook + audit row inside one withWriteScope. Caller
|
|
19
|
-
* is responsible for opening `db`, optionally wrapping in a larger BEGIN/
|
|
20
|
-
* COMMIT (e.g. supersede's BEGIN IMMEDIATE), closing `db`, AND calling
|
|
21
|
-
* `writeEntryMirrors` after the larger tx commits — mirrors must run
|
|
22
|
-
* post-commit so a rolled-back tx never leaves orphan markdown.
|
|
23
|
-
*
|
|
24
|
-
* Audit-order note: the audit row is emitted INSIDE the write scope, so audit
|
|
25
|
-
* commits atomically with the row INSERT. A subsequent mirror failure cannot
|
|
26
|
-
* leave a recorded audit entry without its corresponding DB row. This is a
|
|
27
|
-
* documented hardening over the prior writeEntry-as-monolith ordering.
|
|
28
|
-
*/
|
|
21
|
+
/** DB-only write path: upsert, afterWrite hook and audit row inside one withWriteScope; the caller owns `db` and must call `writeEntryMirrors` after any
|
|
22
|
+
* outer tx commits, so a rolled-back tx never leaves orphan markdown. The audit row commits atomically with the INSERT. */
|
|
29
23
|
export declare function writeEntryDbOnly(db: DatabaseSyncLike, entry: MemoryEntry, opts?: {
|
|
30
24
|
actor?: string;
|
|
31
25
|
afterWrite?: (db: DatabaseSyncLike, memoryId: string) => void;
|
|
@@ -7,17 +7,16 @@ import { auditRejectionRefusal, audit } from './audit-event.js';
|
|
|
7
7
|
import { selectEntriesByIds } from './entry-reads.js';
|
|
8
8
|
import { stampOriginProject, upsertEntryRow, syncFtsRow, deleteFtsRow } from './entry-row.js';
|
|
9
9
|
import { mirrorBestEffort, writeMarkdownMirror } from './mirrors.js';
|
|
10
|
-
import { openStore } from './open.js';
|
|
10
|
+
import { onHandle, openStore } from './open.js';
|
|
11
|
+
/** Write an entry to SQLite and refresh mirrors; `opts.afterWrite` runs in the same SAVEPOINT as the INSERT, so a throw rolls the row back.
|
|
12
|
+
* `opts.actor` defaults to 'cli'; the api layer passes the resolved actor so the audit log gets one row per write. */
|
|
11
13
|
export function writeEntry(hippoRoot, entry, opts) {
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
+
onHandle(hippoRoot, (db) => {
|
|
14
15
|
writeEntryOn(db, hippoRoot, entry, opts);
|
|
15
|
-
}
|
|
16
|
-
finally {
|
|
17
|
-
closeHippoDb(db);
|
|
18
|
-
}
|
|
16
|
+
}, openStore);
|
|
19
17
|
}
|
|
20
|
-
/** writeEntry for each of `entries` in one transaction, so all land or none; each
|
|
18
|
+
/** writeEntry for each of `entries` in one transaction, so all land or none; each
|
|
19
|
+
* keeps its audit row, and mirrors follow the commit. Returns how many were written. */
|
|
21
20
|
export function writeEntriesTogether(hippoRoot, entries) {
|
|
22
21
|
const stamped = entries.map((entry) => stampOriginProject(hippoRoot, entry));
|
|
23
22
|
const db = openStore(hippoRoot);
|
|
@@ -40,23 +39,20 @@ export function writeEntriesTogether(hippoRoot, entries) {
|
|
|
40
39
|
}
|
|
41
40
|
return stamped.length;
|
|
42
41
|
}
|
|
43
|
-
/** writeEntry for each of `entries` on one open store, so the open and its lock wait are
|
|
42
|
+
/** writeEntry for each of `entries` on one open store, so the open and its lock wait are
|
|
43
|
+
* paid once; each row commits alone, and none opens the store when the list is empty. */
|
|
44
44
|
export function writeEntriesSeparately(hippoRoot, entries) {
|
|
45
45
|
if (entries.length === 0)
|
|
46
46
|
return;
|
|
47
|
-
|
|
48
|
-
try {
|
|
47
|
+
onHandle(hippoRoot, (db) => {
|
|
49
48
|
for (const entry of entries)
|
|
50
49
|
writeEntryOn(db, hippoRoot, entry);
|
|
51
|
-
}
|
|
52
|
-
finally {
|
|
53
|
-
closeHippoDb(db);
|
|
54
|
-
}
|
|
50
|
+
}, openStore);
|
|
55
51
|
}
|
|
56
|
-
/** Adds `tag` to each of a tenant's rows that lacks it, in `ids` order, each read fresh
|
|
52
|
+
/** Adds `tag` to each of a tenant's rows that lacks it, in `ids` order, each read fresh
|
|
53
|
+
* on one open store and committed alone; an id the tenant does not hold is skipped. */
|
|
57
54
|
export function addTagToEntries(hippoRoot, tenantId, ids, tag) {
|
|
58
|
-
|
|
59
|
-
try {
|
|
55
|
+
onHandle(hippoRoot, (db) => {
|
|
60
56
|
const live = selectEntriesByIds(db, ids, tenantId);
|
|
61
57
|
for (const id of new Set(ids)) {
|
|
62
58
|
const entry = live.get(id);
|
|
@@ -64,10 +60,7 @@ export function addTagToEntries(hippoRoot, tenantId, ids, tag) {
|
|
|
64
60
|
continue;
|
|
65
61
|
writeEntryOn(db, hippoRoot, { ...entry, tags: [...entry.tags, tag] });
|
|
66
62
|
}
|
|
67
|
-
}
|
|
68
|
-
finally {
|
|
69
|
-
closeHippoDb(db);
|
|
70
|
-
}
|
|
63
|
+
}, openStore);
|
|
71
64
|
}
|
|
72
65
|
/** writeEntry on the caller's open store, so a loop of writes opens the store once; each row still commits alone. */
|
|
73
66
|
function writeEntryOn(db, hippoRoot, entry, opts) {
|
|
@@ -86,19 +79,8 @@ function writeEntryOn(db, hippoRoot, entry, opts) {
|
|
|
86
79
|
throw error;
|
|
87
80
|
}
|
|
88
81
|
}
|
|
89
|
-
/**
|
|
90
|
-
*
|
|
91
|
-
* afterWrite hook + audit row inside one withWriteScope. Caller
|
|
92
|
-
* is responsible for opening `db`, optionally wrapping in a larger BEGIN/
|
|
93
|
-
* COMMIT (e.g. supersede's BEGIN IMMEDIATE), closing `db`, AND calling
|
|
94
|
-
* `writeEntryMirrors` after the larger tx commits — mirrors must run
|
|
95
|
-
* post-commit so a rolled-back tx never leaves orphan markdown.
|
|
96
|
-
*
|
|
97
|
-
* Audit-order note: the audit row is emitted INSIDE the write scope, so audit
|
|
98
|
-
* commits atomically with the row INSERT. A subsequent mirror failure cannot
|
|
99
|
-
* leave a recorded audit entry without its corresponding DB row. This is a
|
|
100
|
-
* documented hardening over the prior writeEntry-as-monolith ordering.
|
|
101
|
-
*/
|
|
82
|
+
/** DB-only write path: upsert, afterWrite hook and audit row inside one withWriteScope; the caller owns `db` and must call `writeEntryMirrors` after any
|
|
83
|
+
* outer tx commits, so a rolled-back tx never leaves orphan markdown. The audit row commits atomically with the INSERT. */
|
|
102
84
|
export function writeEntryDbOnly(db, entry, opts) {
|
|
103
85
|
// Inside a caller's transaction (e.g. supersede's BEGIN IMMEDIATE) the scope is a SAVEPOINT,
|
|
104
86
|
// so a throw here rolls back only this write and leaves the outer open.
|