hippo-memory 1.60.0 → 1.61.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/ablation.js +9 -27
- package/dist/agent-memories/apply.js +4 -1
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/gemini.js +1 -1
- package/dist/agent-memories/legacy.js +1 -1
- package/dist/agent-memories/source.js +1 -1
- package/dist/agent-memories/sync.js +8 -3
- package/dist/ambient-store.d.ts +14 -0
- package/dist/ambient-store.js +90 -0
- package/dist/ambient.d.ts +23 -0
- package/dist/ambient.js +72 -50
- package/dist/api/assemble.d.ts +93 -0
- package/dist/api/assemble.js +152 -0
- package/dist/api/audit.d.ts +17 -0
- package/dist/api/audit.js +23 -0
- package/dist/api/auth.d.ts +79 -0
- package/dist/api/auth.js +178 -0
- package/dist/api/context-types.d.ts +105 -0
- package/dist/api/context-types.js +3 -0
- package/dist/api/context.d.ts +31 -0
- package/dist/api/context.js +705 -0
- package/dist/api/dormant.d.ts +30 -0
- package/dist/api/dormant.js +140 -0
- package/dist/api/drill-down.d.ts +84 -0
- package/dist/api/drill-down.js +123 -0
- package/dist/api/forget.d.ts +57 -0
- package/dist/api/forget.js +87 -0
- package/dist/api/goals.d.ts +18 -0
- package/dist/api/goals.js +33 -0
- package/dist/api/learn.d.ts +31 -0
- package/dist/api/learn.js +88 -0
- package/dist/api/outcome.d.ts +61 -0
- package/dist/api/outcome.js +66 -0
- package/dist/api/promote.d.ts +54 -0
- package/dist/api/promote.js +203 -0
- package/dist/api/quarantine.d.ts +24 -0
- package/dist/api/quarantine.js +121 -0
- package/dist/api/recall-types.d.ts +390 -0
- package/dist/api/recall-types.js +3 -0
- package/dist/api/recall.d.ts +36 -0
- package/dist/api/recall.js +634 -0
- package/dist/api/remember.d.ts +35 -0
- package/dist/api/remember.js +43 -0
- package/dist/api/sleep.d.ts +136 -0
- package/dist/api/sleep.js +271 -0
- package/dist/api/tokens.d.ts +26 -0
- package/dist/api/tokens.js +60 -0
- package/dist/api/types.d.ts +56 -0
- package/dist/api/types.js +38 -0
- package/dist/api.d.ts +20 -1262
- package/dist/api.js +25 -2727
- package/dist/audit.d.ts +3 -0
- package/dist/audit.js +6 -3
- package/dist/auth.d.ts +45 -4
- package/dist/auth.js +125 -48
- package/dist/autolearn.js +2 -2
- package/dist/capture/command.d.ts +33 -0
- package/dist/capture/command.js +264 -0
- package/dist/capture/compact.d.ts +44 -0
- package/dist/capture/compact.js +354 -0
- package/dist/capture/extract.d.ts +21 -0
- package/dist/capture/extract.js +464 -0
- package/dist/capture/transcript.d.ts +40 -0
- package/dist/capture/transcript.js +193 -0
- package/dist/capture-error.js +2 -1
- package/dist/churn-git.js +4 -2
- package/dist/cli/audit.d.ts +3 -0
- package/dist/cli/audit.js +159 -0
- package/dist/cli/auth.d.ts +2 -0
- package/dist/cli/auth.js +171 -0
- package/dist/cli/briefs.d.ts +4 -0
- package/dist/cli/briefs.js +435 -0
- package/dist/cli/card.d.ts +3 -0
- package/dist/cli/card.js +333 -0
- package/dist/cli/context.d.ts +15 -0
- package/dist/cli/context.js +366 -0
- package/dist/cli/continuity.d.ts +6 -0
- package/dist/cli/continuity.js +445 -0
- package/dist/cli/curate.d.ts +19 -0
- package/dist/cli/curate.js +555 -0
- package/dist/cli/dag.d.ts +5 -0
- package/dist/cli/dag.js +177 -0
- package/dist/cli/decisions.d.ts +4 -0
- package/dist/cli/decisions.js +528 -0
- package/dist/cli/eval.d.ts +5 -0
- package/dist/cli/eval.js +213 -0
- package/dist/cli/explain.d.ts +4 -0
- package/dist/cli/explain.js +150 -0
- package/dist/cli/goals.d.ts +2 -0
- package/dist/cli/goals.js +196 -0
- package/dist/cli/hook-blocks.d.ts +18 -0
- package/dist/cli/hook-blocks.js +233 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.js +305 -0
- package/dist/cli/maintenance.d.ts +4 -0
- package/dist/cli/maintenance.js +179 -0
- package/dist/cli/playbooks.d.ts +4 -0
- package/dist/cli/playbooks.js +556 -0
- package/dist/cli/projects.js +1 -1
- package/dist/cli/recall.d.ts +7 -0
- package/dist/cli/recall.js +597 -0
- package/dist/cli/remember.d.ts +5 -0
- package/dist/cli/remember.js +442 -0
- package/dist/cli/serve.d.ts +5 -0
- package/dist/cli/serve.js +40 -0
- package/dist/cli/session-hooks.d.ts +29 -0
- package/dist/cli/session-hooks.js +637 -0
- package/dist/cli/setup.d.ts +4 -0
- package/dist/cli/setup.js +376 -0
- package/dist/cli/shared.d.ts +15 -19
- package/dist/cli/shared.js +50 -341
- package/dist/cli/slack.d.ts +2 -0
- package/dist/cli/slack.js +171 -0
- package/dist/cli/status.d.ts +18 -0
- package/dist/cli/status.js +400 -0
- package/dist/cli/transfer.d.ts +10 -0
- package/dist/cli/transfer.js +438 -0
- package/dist/cli/usage.d.ts +85 -0
- package/dist/cli/usage.js +741 -0
- package/dist/cli.d.ts +71 -120
- package/dist/cli.js +170 -8469
- package/dist/client.js +15 -8
- package/dist/compaction-record.js +6 -4
- package/dist/connectors/github/backfill.js +94 -87
- package/dist/connectors/github/cli-impl.js +4 -3
- package/dist/connectors/github/dlq.js +67 -54
- package/dist/connectors/github/ingest.js +34 -35
- package/dist/connectors/github/tenant-routing.js +3 -2
- package/dist/connectors/github/webhook.js +135 -216
- package/dist/connectors/slack/dlq.js +49 -61
- package/dist/connectors/slack/ingest.js +55 -48
- package/dist/connectors/slack/tenant-routing.js +4 -3
- package/dist/connectors/slack/webhook.js +72 -74
- package/dist/consolidate/conflicts.d.ts +10 -0
- package/dist/consolidate/conflicts.js +178 -0
- package/dist/consolidate/decay.d.ts +12 -0
- package/dist/consolidate/decay.js +145 -0
- package/dist/consolidate/llm-passes.d.ts +3 -0
- package/dist/consolidate/llm-passes.js +141 -0
- package/dist/consolidate/merge.d.ts +7 -0
- package/dist/consolidate/merge.js +251 -0
- package/dist/consolidate/physics-pass.d.ts +3 -0
- package/dist/consolidate/physics-pass.js +60 -0
- package/dist/consolidate/run.d.ts +69 -0
- package/dist/consolidate/run.js +76 -0
- package/dist/consolidate/sleep.d.ts +18 -0
- package/dist/consolidate/sleep.js +209 -0
- package/dist/consolidate/traces.d.ts +4 -0
- package/dist/consolidate/traces.js +178 -0
- package/dist/context-auto.js +7 -11
- package/dist/context-render.d.ts +1 -1
- package/dist/context-render.js +1 -1
- package/dist/customer-notes.d.ts +3 -0
- package/dist/customer-notes.js +6 -4
- package/dist/dag.js +6 -5
- package/dist/dashboard-actions.d.ts +20 -0
- package/dist/dashboard-actions.js +88 -0
- package/dist/dashboard-params.d.ts +45 -0
- package/dist/dashboard-params.js +127 -0
- package/dist/dashboard-queries.d.ts +15 -0
- package/dist/dashboard-queries.js +355 -0
- package/dist/dashboard-snapshot.d.ts +138 -0
- package/dist/dashboard-snapshot.js +308 -0
- package/dist/dashboard-types.d.ts +163 -0
- package/dist/dashboard-types.js +3 -0
- package/dist/dashboard.d.ts +6 -7
- package/dist/dashboard.js +228 -202
- package/dist/db/busy.d.ts +5 -0
- package/dist/db/busy.js +24 -0
- package/dist/db/continuity.d.ts +5 -0
- package/dist/db/continuity.js +145 -0
- package/dist/db/meta.d.ts +8 -0
- package/dist/db/meta.js +35 -0
- package/dist/db/migrate.d.ts +9 -0
- package/dist/db/migrate.js +138 -0
- package/dist/db/migrations/index.d.ts +5 -0
- package/dist/db/migrations/index.js +109 -0
- package/dist/db/migrations/types.d.ts +14 -0
- package/dist/db/migrations/types.js +2 -0
- package/dist/db/migrations/v01.d.ts +3 -0
- package/dist/db/migrations/v01.js +38 -0
- package/dist/db/migrations/v02.d.ts +3 -0
- package/dist/db/migrations/v02.js +21 -0
- package/dist/db/migrations/v03.d.ts +3 -0
- package/dist/db/migrations/v03.js +22 -0
- package/dist/db/migrations/v04.d.ts +3 -0
- package/dist/db/migrations/v04.js +28 -0
- package/dist/db/migrations/v05.d.ts +3 -0
- package/dist/db/migrations/v05.js +21 -0
- package/dist/db/migrations/v06.d.ts +3 -0
- package/dist/db/migrations/v06.js +25 -0
- package/dist/db/migrations/v07.d.ts +3 -0
- package/dist/db/migrations/v07.js +13 -0
- package/dist/db/migrations/v08.d.ts +3 -0
- package/dist/db/migrations/v08.js +8 -0
- package/dist/db/migrations/v09.d.ts +3 -0
- package/dist/db/migrations/v09.js +13 -0
- package/dist/db/migrations/v10.d.ts +3 -0
- package/dist/db/migrations/v10.js +17 -0
- package/dist/db/migrations/v11.d.ts +3 -0
- package/dist/db/migrations/v11.js +15 -0
- package/dist/db/migrations/v12.d.ts +3 -0
- package/dist/db/migrations/v12.js +11 -0
- package/dist/db/migrations/v13.d.ts +3 -0
- package/dist/db/migrations/v13.js +15 -0
- package/dist/db/migrations/v14.d.ts +3 -0
- package/dist/db/migrations/v14.js +66 -0
- package/dist/db/migrations/v15.d.ts +3 -0
- package/dist/db/migrations/v15.js +42 -0
- package/dist/db/migrations/v16.d.ts +3 -0
- package/dist/db/migrations/v16.js +61 -0
- package/dist/db/migrations/v17.d.ts +3 -0
- package/dist/db/migrations/v17.js +46 -0
- package/dist/db/migrations/v18.d.ts +3 -0
- package/dist/db/migrations/v18.js +60 -0
- package/dist/db/migrations/v19.d.ts +3 -0
- package/dist/db/migrations/v19.js +28 -0
- package/dist/db/migrations/v20.d.ts +3 -0
- package/dist/db/migrations/v20.js +42 -0
- package/dist/db/migrations/v21.d.ts +3 -0
- package/dist/db/migrations/v21.js +16 -0
- package/dist/db/migrations/v22.d.ts +3 -0
- package/dist/db/migrations/v22.js +82 -0
- package/dist/db/migrations/v23.d.ts +3 -0
- package/dist/db/migrations/v23.js +48 -0
- package/dist/db/migrations/v24.d.ts +3 -0
- package/dist/db/migrations/v24.js +72 -0
- package/dist/db/migrations/v25.d.ts +3 -0
- package/dist/db/migrations/v25.js +46 -0
- package/dist/db/migrations/v26.d.ts +3 -0
- package/dist/db/migrations/v26.js +23 -0
- package/dist/db/migrations/v27.d.ts +3 -0
- package/dist/db/migrations/v27.js +57 -0
- package/dist/db/migrations/v28.d.ts +3 -0
- package/dist/db/migrations/v28.js +38 -0
- package/dist/db/migrations/v29.d.ts +3 -0
- package/dist/db/migrations/v29.js +78 -0
- package/dist/db/migrations/v30.d.ts +3 -0
- package/dist/db/migrations/v30.js +92 -0
- package/dist/db/migrations/v31.d.ts +3 -0
- package/dist/db/migrations/v31.js +74 -0
- package/dist/db/migrations/v32.d.ts +3 -0
- package/dist/db/migrations/v32.js +102 -0
- package/dist/db/migrations/v33.d.ts +3 -0
- package/dist/db/migrations/v33.js +104 -0
- package/dist/db/migrations/v34.d.ts +3 -0
- package/dist/db/migrations/v34.js +93 -0
- package/dist/db/migrations/v35.d.ts +3 -0
- package/dist/db/migrations/v35.js +98 -0
- package/dist/db/migrations/v36.d.ts +3 -0
- package/dist/db/migrations/v36.js +98 -0
- package/dist/db/migrations/v37.d.ts +3 -0
- package/dist/db/migrations/v37.js +219 -0
- package/dist/db/migrations/v38.d.ts +3 -0
- package/dist/db/migrations/v38.js +277 -0
- package/dist/db/migrations/v39.d.ts +3 -0
- package/dist/db/migrations/v39.js +59 -0
- package/dist/db/migrations/v40.d.ts +3 -0
- package/dist/db/migrations/v40.js +74 -0
- package/dist/db/migrations/v41.d.ts +3 -0
- package/dist/db/migrations/v41.js +43 -0
- package/dist/db/migrations/v42.d.ts +3 -0
- package/dist/db/migrations/v42.js +41 -0
- package/dist/db/migrations/v43.d.ts +3 -0
- package/dist/db/migrations/v43.js +67 -0
- package/dist/db/migrations/v44.d.ts +3 -0
- package/dist/db/migrations/v44.js +28 -0
- package/dist/db/migrations/v45.d.ts +3 -0
- package/dist/db/migrations/v45.js +30 -0
- package/dist/db/migrations/v46.d.ts +3 -0
- package/dist/db/migrations/v46.js +25 -0
- package/dist/db/migrations/v47.d.ts +3 -0
- package/dist/db/migrations/v47.js +17 -0
- package/dist/db/migrations/v48.d.ts +3 -0
- package/dist/db/migrations/v48.js +10 -0
- package/dist/db/migrations/v49.d.ts +3 -0
- package/dist/db/migrations/v49.js +31 -0
- package/dist/db/migrations/v50.d.ts +3 -0
- package/dist/db/migrations/v50.js +67 -0
- package/dist/db/migrations/v51.d.ts +3 -0
- package/dist/db/migrations/v51.js +14 -0
- package/dist/db/migrations/v52.d.ts +3 -0
- package/dist/db/migrations/v52.js +7 -0
- package/dist/db/open.d.ts +23 -0
- package/dist/db/open.js +146 -0
- package/dist/db/sqlite.d.ts +21 -0
- package/dist/db/sqlite.js +8 -0
- package/dist/db/tables.d.ts +7 -0
- package/dist/db/tables.js +38 -0
- package/dist/db.d.ts +6 -46
- package/dist/db.js +5 -3049
- package/dist/decisions.d.ts +4 -1
- package/dist/decisions.js +9 -7
- package/dist/dedupe.js +3 -2
- package/dist/delivery-recorder.js +4 -1
- package/dist/doctor.js +3 -3
- package/dist/embedding-provider.d.ts +1 -1
- package/dist/embedding-provider.js +4 -3
- package/dist/embeddings.d.ts +9 -52
- package/dist/embeddings.js +43 -297
- package/dist/env.d.ts +75 -0
- package/dist/env.js +119 -0
- package/dist/eval-suite.js +1 -1
- package/dist/eval.js +2 -2
- package/dist/extract.js +1 -1
- package/dist/gated-write.js +3 -1
- package/dist/goals.d.ts +3 -1
- package/dist/goals.js +18 -0
- package/dist/graph/read.d.ts +73 -0
- package/dist/graph/read.js +325 -0
- package/dist/graph/rows.d.ts +45 -0
- package/dist/graph/rows.js +51 -0
- package/dist/graph/types.d.ts +83 -0
- package/dist/graph/types.js +11 -0
- package/dist/graph/write.d.ts +93 -0
- package/dist/{graph.js → graph/write.js} +6 -384
- package/dist/graph-extract.js +2 -1
- package/dist/graph-recall.d.ts +1 -1
- package/dist/graph-recall.js +2 -2
- package/dist/graph-stream.js +1 -1
- package/dist/graph-view.d.ts +1 -1
- package/dist/graph-view.js +1 -1
- package/dist/half-life-migration.d.ts +1 -1
- package/dist/half-life-migration.js +2 -1
- package/dist/hooks/codex-session.d.ts +8 -0
- package/dist/hooks/codex-session.js +76 -0
- package/dist/hooks/codex-wrapper.d.ts +55 -0
- package/dist/hooks/codex-wrapper.js +288 -0
- package/dist/hooks/json-hooks.d.ts +63 -0
- package/dist/hooks/json-hooks.js +356 -0
- package/dist/hooks/opencode.d.ts +50 -0
- package/dist/hooks/opencode.js +202 -0
- package/dist/hooks/shared.d.ts +54 -0
- package/dist/hooks/shared.js +77 -0
- package/dist/http-retry.d.ts +2 -0
- package/dist/http-retry.js +4 -3
- package/dist/http-util.d.ts +3 -0
- package/dist/http-util.js +10 -0
- package/dist/{importers.d.ts → importers/core.d.ts} +13 -17
- package/dist/importers/core.js +141 -0
- package/dist/importers/markdown-parse.d.ts +41 -0
- package/dist/importers/markdown-parse.js +132 -0
- package/dist/importers/markdown.d.ts +3 -0
- package/dist/importers/markdown.js +92 -0
- package/dist/importers/sources.d.ts +7 -0
- package/dist/importers/sources.js +229 -0
- package/dist/importers/vault.d.ts +11 -0
- package/dist/importers/vault.js +352 -0
- package/dist/incidents.d.ts +3 -0
- package/dist/incidents.js +7 -5
- package/dist/index.d.ts +25 -6
- package/dist/index.js +23 -6
- package/dist/invalidation.js +2 -1
- package/dist/judgment.js +2 -1
- package/dist/keyset.d.ts +13 -0
- package/dist/keyset.js +8 -0
- package/dist/local-embedding.d.ts +13 -0
- package/dist/local-embedding.js +165 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +19 -1
- package/dist/mcp/admin-tools.d.ts +8 -0
- package/dist/mcp/admin-tools.js +116 -0
- package/dist/mcp/format.d.ts +27 -0
- package/dist/mcp/format.js +135 -0
- package/dist/mcp/memory-tools.d.ts +5 -0
- package/dist/mcp/memory-tools.js +83 -0
- package/dist/mcp/protocol.d.ts +83 -0
- package/dist/mcp/protocol.js +55 -0
- package/dist/mcp/recall-tools.d.ts +6 -0
- package/dist/mcp/recall-tools.js +320 -0
- package/dist/mcp/request.d.ts +10 -0
- package/dist/mcp/request.js +163 -0
- package/dist/mcp/server.d.ts +4 -75
- package/dist/mcp/server.js +7 -1190
- package/dist/mcp/session-state.d.ts +11 -0
- package/dist/mcp/session-state.js +28 -0
- package/dist/mcp/stdio.d.ts +8 -0
- package/dist/mcp/stdio.js +79 -0
- package/dist/mcp/tools.d.ts +11 -0
- package/dist/mcp/tools.js +247 -0
- package/dist/memory.d.ts +3 -0
- package/dist/memory.js +27 -1
- package/dist/multihop.d.ts +1 -1
- package/dist/multihop.js +2 -1
- package/dist/owner-validation.js +2 -1
- package/dist/physics-state.js +10 -7
- package/dist/policies.d.ts +3 -0
- package/dist/policies.js +8 -6
- package/dist/postinstall.js +3 -2
- package/dist/predictions/planning-fallacy.d.ts +100 -0
- package/dist/predictions/planning-fallacy.js +190 -0
- package/dist/{predictions.d.ts → predictions/store.d.ts} +7 -102
- package/dist/predictions/store.js +434 -0
- package/dist/processes.d.ts +3 -0
- package/dist/processes.js +7 -5
- package/dist/project-briefs.d.ts +3 -0
- package/dist/project-briefs.js +7 -5
- package/dist/project-identity.js +3 -2
- package/dist/project-merge.js +3 -1
- package/dist/quarantine.d.ts +2 -1
- package/dist/quarantine.js +8 -5
- package/dist/raw-archive.js +1 -1
- package/dist/recall-history.js +3 -2
- package/dist/recall-pipeline.d.ts +2 -2
- package/dist/recall-pipeline.js +16 -8
- package/dist/recall-scope.js +1 -1
- package/dist/recall-trace.d.ts +1 -1
- package/dist/refine-llm.js +2 -1
- package/dist/reject-flow.js +6 -1
- package/dist/rerankers/clef.js +6 -5
- package/dist/rerankers/jev.d.ts +1 -1
- package/dist/rerankers/jev.js +4 -4
- package/dist/rerankers/llm.d.ts +4 -2
- package/dist/rerankers/llm.js +58 -38
- package/dist/rerankers/types.d.ts +1 -1
- package/dist/salience.js +1 -1
- package/dist/scheduler.d.ts +1 -0
- package/dist/scheduler.js +26 -4
- package/dist/scope.js +4 -3
- package/dist/search/as-of.d.ts +10 -0
- package/dist/search/as-of.js +22 -0
- package/dist/search/bm25-search.d.ts +14 -0
- package/dist/search/bm25-search.js +43 -0
- package/dist/search/bm25.d.ts +15 -0
- package/dist/search/bm25.js +54 -0
- package/dist/search/boosts.d.ts +54 -0
- package/dist/search/boosts.js +94 -0
- package/dist/search/breakdown.d.ts +7 -0
- package/dist/search/breakdown.js +20 -0
- package/dist/search/explain.d.ts +25 -0
- package/dist/search/explain.js +31 -0
- package/dist/search/finalize.d.ts +8 -0
- package/dist/search/finalize.js +52 -0
- package/dist/search/fusion.d.ts +27 -0
- package/dist/search/fusion.js +42 -0
- package/dist/search/hybrid-score.d.ts +20 -0
- package/dist/search/hybrid-score.js +73 -0
- package/dist/search/hybrid.d.ts +46 -0
- package/dist/search/hybrid.js +64 -0
- package/dist/search/physics-search.d.ts +29 -0
- package/dist/search/physics-search.js +162 -0
- package/dist/search/rerank.d.ts +10 -0
- package/dist/search/rerank.js +72 -0
- package/dist/search/temporal.d.ts +15 -0
- package/dist/search/temporal.js +45 -0
- package/dist/search/types.d.ts +91 -0
- package/dist/search/types.js +2 -0
- package/dist/search/vector.d.ts +30 -0
- package/dist/search/vector.js +71 -0
- package/dist/secret-detect.d.ts +2 -0
- package/dist/secret-detect.js +2 -1
- package/dist/server/auth.d.ts +52 -0
- package/dist/server/auth.js +221 -0
- package/dist/server/client-ip.d.ts +25 -0
- package/dist/server/client-ip.js +92 -0
- package/dist/server/cursor.d.ts +23 -0
- package/dist/server/cursor.js +58 -0
- package/dist/server/lifecycle.d.ts +7 -0
- package/dist/server/lifecycle.js +29 -0
- package/dist/server/mcp-http.d.ts +5 -0
- package/dist/server/mcp-http.js +199 -0
- package/dist/server/request.d.ts +33 -0
- package/dist/server/request.js +103 -0
- package/dist/server/routes/admin.d.ts +9 -0
- package/dist/server/routes/admin.js +158 -0
- package/dist/server/routes/customer-notes.d.ts +7 -0
- package/dist/server/routes/customer-notes.js +112 -0
- package/dist/server/routes/decisions.d.ts +7 -0
- package/dist/server/routes/decisions.js +133 -0
- package/dist/server/routes/incidents.d.ts +7 -0
- package/dist/server/routes/incidents.js +126 -0
- package/dist/server/routes/memories.d.ts +10 -0
- package/dist/server/routes/memories.js +179 -0
- package/dist/server/routes/policies.d.ts +8 -0
- package/dist/server/routes/policies.js +151 -0
- package/dist/server/routes/predictions.d.ts +7 -0
- package/dist/server/routes/predictions.js +164 -0
- package/dist/server/routes/processes.d.ts +7 -0
- package/dist/server/routes/processes.js +161 -0
- package/dist/server/routes/project-briefs.d.ts +8 -0
- package/dist/server/routes/project-briefs.js +136 -0
- package/dist/server/routes/recall.d.ts +8 -0
- package/dist/server/routes/recall.js +340 -0
- package/dist/server/routes/skills.d.ts +8 -0
- package/dist/server/routes/skills.js +150 -0
- package/dist/server/types.d.ts +56 -0
- package/dist/server/types.js +2 -0
- package/dist/server/validation.d.ts +14 -0
- package/dist/server/validation.js +91 -0
- package/dist/server.d.ts +7 -61
- package/dist/server.js +69 -2362
- package/dist/session-digest.d.ts +1 -1
- package/dist/session-digest.js +9 -2
- package/dist/shared.d.ts +3 -1
- package/dist/shared.js +26 -22
- package/dist/skills.d.ts +3 -0
- package/dist/skills.js +7 -5
- package/dist/stdin.js +2 -2
- package/dist/store/audit-event.d.ts +19 -0
- package/dist/store/audit-event.js +33 -0
- package/dist/store/candidates.d.ts +42 -0
- package/dist/store/candidates.js +152 -0
- package/dist/store/conflicts.d.ts +44 -0
- package/dist/store/conflicts.js +444 -0
- package/dist/store/delete-and-batch.d.ts +63 -0
- package/dist/store/delete-and-batch.js +310 -0
- package/dist/store/entry-reads.d.ts +92 -0
- package/dist/store/entry-reads.js +255 -0
- package/dist/store/entry-row.d.ts +67 -0
- package/dist/store/entry-row.js +208 -0
- package/dist/store/entry-writes.d.ts +46 -0
- package/dist/store/entry-writes.js +148 -0
- package/dist/store/handoffs.d.ts +26 -0
- package/dist/store/handoffs.js +184 -0
- package/dist/store/index-and-stats.d.ts +52 -0
- package/dist/store/index-and-stats.js +214 -0
- package/dist/store/markdown.d.ts +10 -0
- package/dist/store/markdown.js +108 -0
- package/dist/store/mirrors.d.ts +49 -0
- package/dist/store/mirrors.js +312 -0
- package/dist/store/open.d.ts +15 -0
- package/dist/store/open.js +223 -0
- package/dist/store/rows.d.ts +178 -0
- package/dist/store/rows.js +158 -0
- package/dist/store/search-rows.d.ts +86 -0
- package/dist/store/search-rows.js +254 -0
- package/dist/store/sessions.d.ts +83 -0
- package/dist/store/sessions.js +272 -0
- package/dist/store/summaries.d.ts +94 -0
- package/dist/store/summaries.js +377 -0
- package/dist/store/tenant-lookup.d.ts +12 -0
- package/dist/store/tenant-lookup.js +16 -0
- package/dist/store-cards.js +2 -1
- package/dist/summary-dirty.d.ts +4 -0
- package/dist/summary-dirty.js +32 -0
- package/dist/support-bundle.js +4 -3
- package/dist/tenant.js +2 -2
- package/dist/tokenize.d.ts +2 -0
- package/dist/tokenize.js +16 -0
- package/dist/transcript-tail.d.ts +7 -0
- package/dist/transcript-tail.js +48 -0
- package/dist/vector-store.d.ts +27 -0
- package/dist/vector-store.js +210 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/working-memory.js +1 -1
- package/dist/yaml.js +36 -11
- package/dist-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/dist-ui/assets/index-DPN7cP19.js +33 -0
- package/dist-ui/assets/index-dFloKRVr.css +1 -0
- package/dist-ui/index.html +3 -25
- 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/capture.d.ts +0 -155
- package/dist/capture.js +0 -1295
- package/dist/consolidate.d.ts +0 -58
- package/dist/consolidate.js +0 -1124
- package/dist/graph.d.ts +0 -245
- package/dist/hooks.d.ts +0 -208
- package/dist/hooks.js +0 -1076
- package/dist/importers.js +0 -900
- package/dist/predictions.js +0 -620
- package/dist/search.d.ts +0 -320
- package/dist/search.js +0 -970
- package/dist/store.d.ts +0 -776
- package/dist/store.js +0 -3473
- package/dist-ui/assets/d3-BiWEKnn4.js +0 -1
- package/dist-ui/assets/index-BhT8RvO6.js +0 -61
- package/dist-ui/assets/index-RoXXJ5dq.css +0 -1
- package/dist-ui/assets/three-BDgTxR1l.js +0 -4112
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import { closeHippoDb } from '../db.js';
|
|
2
|
+
import { rejectionDigest, insertRejectedValue, normalizeValueForRejection } from '../rejection.js';
|
|
3
|
+
import { archiveRawMemory } from '../raw-archive.js';
|
|
4
|
+
import { rowToMemoryConflict } from './rows.js';
|
|
5
|
+
import { audit } from './audit-event.js';
|
|
6
|
+
import { syncMirrorFiles, purgeMirrorBestEffort } from './mirrors.js';
|
|
7
|
+
import { openStore } from './open.js';
|
|
8
|
+
import { deleteEntryCore } from './delete-and-batch.js';
|
|
9
|
+
function canonicalConflictPair(aId, bId) {
|
|
10
|
+
return aId < bId
|
|
11
|
+
? { memory_a_id: aId, memory_b_id: bId }
|
|
12
|
+
: { memory_a_id: bId, memory_b_id: aId };
|
|
13
|
+
}
|
|
14
|
+
export function listMemoryConflicts(hippoRoot, status = 'open', tenantId) {
|
|
15
|
+
const db = openStore(hippoRoot);
|
|
16
|
+
try {
|
|
17
|
+
// v0.28 — '*' is a sentinel meaning "no status filter, return all rows".
|
|
18
|
+
// Pre-v0.28 callers (cli/mcp/dashboard) always passed 'open' or default,
|
|
19
|
+
// so this sentinel is purely additive. The 4 SQL branches below cover
|
|
20
|
+
// {tenanted | unscoped} × {all-statuses | specific-status}.
|
|
21
|
+
const allStatuses = status === '*';
|
|
22
|
+
let rows;
|
|
23
|
+
if (tenantId !== undefined) {
|
|
24
|
+
// Tenanted query — JOIN to memories on both conflict members and require
|
|
25
|
+
// each in-tenant, so neither a normal cross-tenant pair nor a stale
|
|
26
|
+
// pre-fix row surfaces (consistent with resolveConflict).
|
|
27
|
+
// SAFETY: both branches select the same eight mc.* columns (aliased
|
|
28
|
+
// to MemoryConflictRow's field names) from memory_conflicts.
|
|
29
|
+
rows = allStatuses
|
|
30
|
+
? db.prepare(`
|
|
31
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
32
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
33
|
+
FROM memory_conflicts mc
|
|
34
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
35
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
36
|
+
WHERE ma.tenant_id = ? AND mb.tenant_id = ?
|
|
37
|
+
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
38
|
+
`).all(tenantId, tenantId)
|
|
39
|
+
: db.prepare(`
|
|
40
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
41
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
42
|
+
FROM memory_conflicts mc
|
|
43
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
44
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
45
|
+
WHERE mc.status = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
46
|
+
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
47
|
+
`).all(status, tenantId, tenantId);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Unscoped query — legacy direct-mode (CLI, tests, consolidate).
|
|
51
|
+
// SAFETY: both branches select the same eight columns matching
|
|
52
|
+
// MemoryConflictRow's field set.
|
|
53
|
+
rows = allStatuses
|
|
54
|
+
? db.prepare(`
|
|
55
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
56
|
+
FROM memory_conflicts
|
|
57
|
+
ORDER BY updated_at DESC, id DESC
|
|
58
|
+
`).all()
|
|
59
|
+
: db.prepare(`
|
|
60
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
61
|
+
FROM memory_conflicts
|
|
62
|
+
WHERE status = ?
|
|
63
|
+
ORDER BY updated_at DESC, id DESC
|
|
64
|
+
`).all(status);
|
|
65
|
+
}
|
|
66
|
+
return rows.map(rowToMemoryConflict);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
closeHippoDb(db);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function replaceDetectedConflicts(hippoRoot, detected, detectedAt = new Date().toISOString()) {
|
|
73
|
+
const db = openStore(hippoRoot);
|
|
74
|
+
try {
|
|
75
|
+
db.exec('BEGIN');
|
|
76
|
+
const sameTenant = loadSameTenantCheck(db);
|
|
77
|
+
const canonicalDetected = detected.map((conflict) => ({
|
|
78
|
+
...canonicalConflictPair(conflict.memory_a_id, conflict.memory_b_id),
|
|
79
|
+
reason: conflict.reason,
|
|
80
|
+
score: conflict.score,
|
|
81
|
+
}));
|
|
82
|
+
resolveStaleOpenConflicts(db, canonicalDetected, sameTenant, detectedAt);
|
|
83
|
+
upsertDetectedConflicts(db, canonicalDetected, sameTenant, detectedAt);
|
|
84
|
+
rebuildConflictsWithJson(db, sameTenant);
|
|
85
|
+
db.exec('COMMIT');
|
|
86
|
+
syncMirrorFiles(hippoRoot, db);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
try {
|
|
90
|
+
db.exec('ROLLBACK');
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Ignore nested rollback failures.
|
|
94
|
+
}
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
closeHippoDb(db);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function loadSameTenantCheck(db) {
|
|
102
|
+
// Tenant guard (E2): a conflict is meaningful only within one tenant.
|
|
103
|
+
// Build id -> tenant_id once and skip cross-tenant pairs both when
|
|
104
|
+
// inserting rows and when rebuilding conflicts_with_json, so a stale
|
|
105
|
+
// cross-tenant row can neither persist nor leak a foreign id.
|
|
106
|
+
const tenantById = new Map();
|
|
107
|
+
// SAFETY: rows' shape matches the two columns named in the SELECT below.
|
|
108
|
+
for (const r of db.prepare(`SELECT id, tenant_id FROM memories`).all()) {
|
|
109
|
+
tenantById.set(r.id, r.tenant_id);
|
|
110
|
+
}
|
|
111
|
+
return (a, b) => {
|
|
112
|
+
const ta = tenantById.get(a);
|
|
113
|
+
const tb = tenantById.get(b);
|
|
114
|
+
return ta !== undefined && tb !== undefined && ta === tb;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function resolveStaleOpenConflicts(db, canonicalDetected, sameTenant, detectedAt) {
|
|
118
|
+
const detectedKeys = new Set(canonicalDetected.map((conflict) => `${conflict.memory_a_id}::${conflict.memory_b_id}`));
|
|
119
|
+
// SAFETY: openRows' shape matches the eight columns named in the SELECT
|
|
120
|
+
// above.
|
|
121
|
+
const openRows = db.prepare(`
|
|
122
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
123
|
+
FROM memory_conflicts
|
|
124
|
+
WHERE status = 'open'
|
|
125
|
+
`).all();
|
|
126
|
+
for (const row of openRows) {
|
|
127
|
+
const key = `${row.memory_a_id}::${row.memory_b_id}`;
|
|
128
|
+
const stale = !detectedKeys.has(key);
|
|
129
|
+
// v1.11.0 residue: auto-resolve any open cross-tenant row. The insert
|
|
130
|
+
// loop below (line 2089) and the refMap rebuild (line 2117) skip
|
|
131
|
+
// cross-tenant pairs, but the resolve-stale loop previously left
|
|
132
|
+
// re-detected cross-tenant rows lingering status='open'. The
|
|
133
|
+
// sameTenant() helper is already built one block up; no extra query.
|
|
134
|
+
const crossTenant = !sameTenant(row.memory_a_id, row.memory_b_id);
|
|
135
|
+
if (stale || crossTenant) {
|
|
136
|
+
db.prepare(`UPDATE memory_conflicts SET status = 'resolved', updated_at = ? WHERE id = ?`).run(detectedAt, row.id);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function upsertDetectedConflicts(db, canonicalDetected, sameTenant, detectedAt) {
|
|
141
|
+
for (const conflict of canonicalDetected) {
|
|
142
|
+
// Skip cross-tenant pairs — never persist a conflict spanning tenants.
|
|
143
|
+
if (!sameTenant(conflict.memory_a_id, conflict.memory_b_id))
|
|
144
|
+
continue;
|
|
145
|
+
db.prepare(`
|
|
146
|
+
INSERT INTO memory_conflicts(memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at)
|
|
147
|
+
VALUES (?, ?, ?, ?, 'open', ?, ?)
|
|
148
|
+
ON CONFLICT(memory_a_id, memory_b_id) DO UPDATE SET
|
|
149
|
+
reason = excluded.reason,
|
|
150
|
+
score = excluded.score,
|
|
151
|
+
status = 'open',
|
|
152
|
+
updated_at = excluded.updated_at
|
|
153
|
+
`).run(conflict.memory_a_id, conflict.memory_b_id, conflict.reason, conflict.score, detectedAt, detectedAt);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function rebuildConflictsWithJson(db, sameTenant) {
|
|
157
|
+
// SAFETY: openConflicts' shape matches the two columns named above.
|
|
158
|
+
const openConflicts = db.prepare(`
|
|
159
|
+
SELECT memory_a_id, memory_b_id
|
|
160
|
+
FROM memory_conflicts
|
|
161
|
+
WHERE status = 'open'
|
|
162
|
+
`).all();
|
|
163
|
+
const refMap = new Map();
|
|
164
|
+
for (const row of openConflicts) {
|
|
165
|
+
// Skip cross-tenant pairs so a stale row never seeds a foreign id
|
|
166
|
+
// into conflicts_with_json.
|
|
167
|
+
if (!sameTenant(row.memory_a_id, row.memory_b_id))
|
|
168
|
+
continue;
|
|
169
|
+
if (!refMap.has(row.memory_a_id))
|
|
170
|
+
refMap.set(row.memory_a_id, new Set());
|
|
171
|
+
if (!refMap.has(row.memory_b_id))
|
|
172
|
+
refMap.set(row.memory_b_id, new Set());
|
|
173
|
+
refMap.get(row.memory_a_id).add(row.memory_b_id);
|
|
174
|
+
refMap.get(row.memory_b_id).add(row.memory_a_id);
|
|
175
|
+
}
|
|
176
|
+
// SAFETY: memoryRows' shape matches the single `id` column selected
|
|
177
|
+
// above.
|
|
178
|
+
const memoryRows = db.prepare(`SELECT id FROM memories`).all();
|
|
179
|
+
for (const memory of memoryRows) {
|
|
180
|
+
const refs = Array.from(refMap.get(memory.id) ?? []).sort();
|
|
181
|
+
db.prepare(`UPDATE memories SET conflicts_with_json = ?, updated_at = datetime('now') WHERE id = ?`).run(JSON.stringify(refs), memory.id);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve a conflict by keeping one memory and weakening the other.
|
|
186
|
+
* Sets conflict status to 'resolved' and halves the loser's half-life.
|
|
187
|
+
* If --forget is used, the loser is removed entirely (kind-aware: raw rows
|
|
188
|
+
* are archived via archiveRawMemory, others deleted via deleteEntryCore —
|
|
189
|
+
* AT1 fix for the pre-existing crash where a raw loser aborted the whole
|
|
190
|
+
* resolve transaction against the append-only trigger). `opts.rejectLoserValue`
|
|
191
|
+
* additionally tombstones the loser's normalized digest so it cannot be
|
|
192
|
+
* re-asserted later.
|
|
193
|
+
*
|
|
194
|
+
* Every resolution path (weaken / forget / reject) emits a `conflict_resolve`
|
|
195
|
+
* audit row (AT1 — previously resolveConflict wrote zero audit rows on any path).
|
|
196
|
+
*
|
|
197
|
+
* Returns the resolved conflict, or null if not found.
|
|
198
|
+
*/
|
|
199
|
+
export function resolveConflict(hippoRoot, conflictId, keepId, forgetLoser = false, tenantId, opts) {
|
|
200
|
+
const db = openStore(hippoRoot);
|
|
201
|
+
// When tenantId is set, the conflict lookup requires BOTH members in-tenant
|
|
202
|
+
// and every memories mutation carries AND tenant_id = ?. A cross-tenant probe
|
|
203
|
+
// then returns null, indistinguishable from a bad id. Omitted tenantId =
|
|
204
|
+
// legacy unscoped behaviour (CLI direct mode, tests, consolidate.ts).
|
|
205
|
+
const scope = {
|
|
206
|
+
memScope: tenantId !== undefined ? ' AND tenant_id = ?' : '',
|
|
207
|
+
memArgs: tenantId !== undefined ? [tenantId] : [],
|
|
208
|
+
};
|
|
209
|
+
try {
|
|
210
|
+
const row = selectConflictRow(db, conflictId, tenantId);
|
|
211
|
+
if (!row)
|
|
212
|
+
return null;
|
|
213
|
+
const conflict = rowToMemoryConflict(row);
|
|
214
|
+
if (conflict.status !== 'open')
|
|
215
|
+
return null;
|
|
216
|
+
const loserId = keepId === conflict.memory_a_id
|
|
217
|
+
? conflict.memory_b_id
|
|
218
|
+
: keepId === conflict.memory_b_id
|
|
219
|
+
? conflict.memory_a_id
|
|
220
|
+
: null;
|
|
221
|
+
if (!loserId)
|
|
222
|
+
return null;
|
|
223
|
+
db.exec('BEGIN');
|
|
224
|
+
// Mark conflict as resolved
|
|
225
|
+
db.prepare(`UPDATE memory_conflicts SET status = 'resolved', updated_at = datetime('now') WHERE id = ?`)
|
|
226
|
+
.run(conflictId);
|
|
227
|
+
const target = { conflictId, keepId, loserId, scope, opts };
|
|
228
|
+
const removeLoser = forgetLoser || opts?.rejectLoserValue === true;
|
|
229
|
+
const removal = removeLoser ? removeConflictLoser(db, target) : weakenConflictLoser(db, target);
|
|
230
|
+
stripConflictRefs(db, target, removal.loserRemoved);
|
|
231
|
+
auditConflictResolve(db, target, removal, tenantId);
|
|
232
|
+
db.exec('COMMIT');
|
|
233
|
+
syncMirrorFiles(hippoRoot, db);
|
|
234
|
+
if (removal.loserRemoved)
|
|
235
|
+
purgeRemovedLoserMirrors(hippoRoot, db, loserId, removal);
|
|
236
|
+
return { conflict: { ...conflict, status: 'resolved' }, loserId };
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
try {
|
|
240
|
+
db.exec('ROLLBACK');
|
|
241
|
+
}
|
|
242
|
+
catch { /* ignore */ }
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
closeHippoDb(db);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function selectConflictRow(db, conflictId, tenantId) {
|
|
250
|
+
// SAFETY: both branches select the same eight columns (aliased in the
|
|
251
|
+
// tenanted branch) matching MemoryConflictRow's field set.
|
|
252
|
+
return (tenantId !== undefined
|
|
253
|
+
? db.prepare(`
|
|
254
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
255
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
256
|
+
FROM memory_conflicts mc
|
|
257
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
258
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
259
|
+
WHERE mc.id = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
260
|
+
`).get(conflictId, tenantId, tenantId)
|
|
261
|
+
: db.prepare(`
|
|
262
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
263
|
+
FROM memory_conflicts WHERE id = ?
|
|
264
|
+
`).get(conflictId));
|
|
265
|
+
}
|
|
266
|
+
function weakenConflictLoser(db, t) {
|
|
267
|
+
// Halve the loser's half-life (weakens it over time)
|
|
268
|
+
db.prepare(`UPDATE memories SET half_life_days = MAX(1, half_life_days / 2), updated_at = datetime('now') WHERE id = ?${t.scope.memScope}`)
|
|
269
|
+
.run(t.loserId, ...t.scope.memArgs);
|
|
270
|
+
return { loserRemoved: false, loserWasRaw: false, rejectedDigest: undefined, extraRemovedIds: [], extraRemovedRawIds: [] };
|
|
271
|
+
}
|
|
272
|
+
function removeConflictLoser(db, t) {
|
|
273
|
+
// AT1 (plan §5): removal (forgetLoser OR rejectLoserValue — a tombstoned
|
|
274
|
+
// value cannot be left live) is now kind-aware. The old bare
|
|
275
|
+
// `DELETE FROM memories WHERE id = ?` aborted the whole transaction when
|
|
276
|
+
// the loser was kind='raw' (append-only trigger fires); route through
|
|
277
|
+
// the same helpers the reject verb uses (both db-scoped, both compose
|
|
278
|
+
// inside this BEGIN/COMMIT). loserRemoved / loserWasRaw drive both the
|
|
279
|
+
// conflicts_with_json skip below and the post-commit mirror purge.
|
|
280
|
+
const removal = {
|
|
281
|
+
loserRemoved: false,
|
|
282
|
+
loserWasRaw: false,
|
|
283
|
+
rejectedDigest: undefined,
|
|
284
|
+
// AT1 P1 fix (codex): same-tenant duplicates of the loser's content that
|
|
285
|
+
// rejectLoserValue also removes (see below) — separate from loserId so
|
|
286
|
+
// the audit + post-commit mirror purge can cover ALL of them, not just
|
|
287
|
+
// loserId.
|
|
288
|
+
extraRemovedIds: [],
|
|
289
|
+
extraRemovedRawIds: [],
|
|
290
|
+
};
|
|
291
|
+
const { loserId, opts } = t;
|
|
292
|
+
// SAFETY: loserRow's shape matches the three columns named in the
|
|
293
|
+
// SELECT above.
|
|
294
|
+
const loserRow = db
|
|
295
|
+
.prepare(`SELECT kind, content, tenant_id FROM memories WHERE id = ?${t.scope.memScope}`)
|
|
296
|
+
.get(loserId, ...t.scope.memArgs);
|
|
297
|
+
if (loserRow) {
|
|
298
|
+
const actor = opts?.rejectedBy ?? 'cli';
|
|
299
|
+
const reason = opts?.reason ?? `resolveConflict ${t.conflictId}: kept ${t.keepId}`;
|
|
300
|
+
if (opts?.rejectLoserValue) {
|
|
301
|
+
removal.rejectedDigest = tombstoneLoserValue(db, t, loserRow, { actor, reason }, removal);
|
|
302
|
+
}
|
|
303
|
+
if (loserRow.kind === 'raw') {
|
|
304
|
+
archiveRawMemory(db, loserId, { reason, who: actor });
|
|
305
|
+
removal.loserWasRaw = true;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
deleteEntryCore(db, loserId, { actor, suppressForgetAudit: true });
|
|
309
|
+
}
|
|
310
|
+
removal.loserRemoved = true;
|
|
311
|
+
}
|
|
312
|
+
// loserRow undefined = tenant-scope mismatch (or already gone); matches
|
|
313
|
+
// the old tenant-scoped DELETE's silent 0-rows-affected behavior.
|
|
314
|
+
return removal;
|
|
315
|
+
}
|
|
316
|
+
/** Tombstones the loser's digest and removes its same-tenant duplicates into `removal`; returns the digest. */
|
|
317
|
+
function tombstoneLoserValue(db, t, loserRow, who, removal) {
|
|
318
|
+
const { actor, reason } = who;
|
|
319
|
+
const rejectedDigest = rejectionDigest(loserRow.content);
|
|
320
|
+
insertRejectedValue(db, {
|
|
321
|
+
tenantId: loserRow.tenant_id ?? 'default',
|
|
322
|
+
digest: rejectedDigest,
|
|
323
|
+
reason,
|
|
324
|
+
rejectedBy: actor,
|
|
325
|
+
rejectedAt: new Date().toISOString(),
|
|
326
|
+
sourceMemoryId: t.loserId,
|
|
327
|
+
normalizedChars: normalizeValueForRejection(loserRow.content).length,
|
|
328
|
+
});
|
|
329
|
+
// AT1 P1 fix (codex): reject-flow.ts's `rejectValue` removes ALL
|
|
330
|
+
// live same-tenant rows whose normalized digest matches, not just
|
|
331
|
+
// the one id passed — but this branch only ever removed loserId,
|
|
332
|
+
// leaving same-TENANT duplicates live while their shared content
|
|
333
|
+
// was tombstoned. Same O(N) scan pattern as reject-flow.ts (human-
|
|
334
|
+
// triggered command, tenant's row count is human-scale). CRITICAL
|
|
335
|
+
// BOUNDARY: tenant-scoped ONLY — tombstones are tenant-scoped by
|
|
336
|
+
// design, so a same-content row in ANOTHER tenant is legitimately
|
|
337
|
+
// live and must NOT be touched here. `keepId` is excluded even if
|
|
338
|
+
// its content coincidentally matches: the human explicitly chose
|
|
339
|
+
// to keep it in this same resolution, and this branch must not
|
|
340
|
+
// undo that choice in the same transaction.
|
|
341
|
+
const loserTenantId = loserRow.tenant_id ?? 'default';
|
|
342
|
+
// SAFETY: dupRows' shape matches the three columns named in the
|
|
343
|
+
// SELECT above.
|
|
344
|
+
const dupRows = db
|
|
345
|
+
.prepare(`SELECT id, kind, content FROM memories WHERE tenant_id = ? AND id != ? AND id != ?`)
|
|
346
|
+
.all(loserTenantId, t.loserId, t.keepId);
|
|
347
|
+
for (const dup of dupRows) {
|
|
348
|
+
if (rejectionDigest(dup.content) !== rejectedDigest)
|
|
349
|
+
continue;
|
|
350
|
+
if (dup.kind === 'raw') {
|
|
351
|
+
archiveRawMemory(db, dup.id, { reason, who: actor });
|
|
352
|
+
removal.extraRemovedRawIds.push(dup.id);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
deleteEntryCore(db, dup.id, { actor, suppressForgetAudit: true });
|
|
356
|
+
}
|
|
357
|
+
removal.extraRemovedIds.push(dup.id);
|
|
358
|
+
}
|
|
359
|
+
return rejectedDigest;
|
|
360
|
+
}
|
|
361
|
+
function stripConflictRefs(db, t, loserRemoved) {
|
|
362
|
+
const { memScope, memArgs } = t.scope;
|
|
363
|
+
const { keepId, loserId } = t;
|
|
364
|
+
// Clean up conflicts_with references
|
|
365
|
+
// SAFETY: keepRow's shape matches the single `conflicts_with_json`
|
|
366
|
+
// column selected above.
|
|
367
|
+
const keepRow = db.prepare(`SELECT conflicts_with_json FROM memories WHERE id = ?${memScope}`).get(keepId, ...memArgs);
|
|
368
|
+
if (keepRow) {
|
|
369
|
+
const refs = JSON.parse(keepRow.conflicts_with_json || '[]');
|
|
370
|
+
const cleaned = refs.filter((r) => r !== loserId);
|
|
371
|
+
db.prepare(`UPDATE memories SET conflicts_with_json = ?, updated_at = datetime('now') WHERE id = ?${memScope}`)
|
|
372
|
+
.run(JSON.stringify(cleaned), keepId, ...memArgs);
|
|
373
|
+
}
|
|
374
|
+
if (!loserRemoved) {
|
|
375
|
+
// SAFETY: loserRow's shape matches the single `conflicts_with_json`
|
|
376
|
+
// column named in the SELECT below.
|
|
377
|
+
const loserRow = db.prepare(`SELECT conflicts_with_json FROM memories WHERE id = ?${memScope}`).get(loserId, ...memArgs);
|
|
378
|
+
if (loserRow) {
|
|
379
|
+
const refs = JSON.parse(loserRow.conflicts_with_json || '[]');
|
|
380
|
+
const cleaned = refs.filter((r) => r !== keepId);
|
|
381
|
+
db.prepare(`UPDATE memories SET conflicts_with_json = ?, updated_at = datetime('now') WHERE id = ?${memScope}`)
|
|
382
|
+
.run(JSON.stringify(cleaned), loserId, ...memArgs);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
function auditConflictResolve(db, t, removal, tenantId) {
|
|
387
|
+
const { loserRemoved, loserWasRaw, rejectedDigest, extraRemovedIds } = removal;
|
|
388
|
+
// AT1: the missing audit (plan §5 — resolveConflict wrote ZERO audit_log
|
|
389
|
+
// rows on any path before this). Every path — weaken, forget, reject —
|
|
390
|
+
// lands exactly one conflict_resolve row.
|
|
391
|
+
const conflictResolveMeta = {
|
|
392
|
+
conflictId: t.conflictId,
|
|
393
|
+
keepId: t.keepId,
|
|
394
|
+
loserId: t.loserId,
|
|
395
|
+
disposition: loserRemoved ? (loserWasRaw ? 'archived_raw' : 'deleted') : 'weakened',
|
|
396
|
+
rejected: Boolean(t.opts?.rejectLoserValue),
|
|
397
|
+
// AT1 P1 fix: every row this call removed, not just loserId — the
|
|
398
|
+
// same-tenant duplicate sweep above (extraRemovedIds) needs an
|
|
399
|
+
// audit trail too.
|
|
400
|
+
removedIds: loserRemoved ? [t.loserId, ...extraRemovedIds] : [],
|
|
401
|
+
};
|
|
402
|
+
// Assigned only when present so the serialized audit payload keeps
|
|
403
|
+
// omitting the key, exactly as the pre-migration object literal did.
|
|
404
|
+
if (rejectedDigest !== undefined)
|
|
405
|
+
conflictResolveMeta.rejectedDigest = rejectedDigest;
|
|
406
|
+
// Fresh spread literal: ConflictResolveMeta is a closed interface (no
|
|
407
|
+
// index signature) and isn't directly assignable to audit()'s
|
|
408
|
+
// Record<string, JsonValue> metadata param; a spread into a fresh
|
|
409
|
+
// object literal satisfies it without widening the declared type above.
|
|
410
|
+
audit(db, 'conflict_resolve', t.keepId, { ...conflictResolveMeta }, t.opts?.rejectedBy ?? 'cli', tenantId);
|
|
411
|
+
}
|
|
412
|
+
function purgeRemovedLoserMirrors(hippoRoot, db, loserId, removal) {
|
|
413
|
+
// AT1 P1b fix: mirror purge + reaper stamp for EVERY removed loser, not
|
|
414
|
+
// just the rejectLoserValue path. Pre-AT1, the plain forgetLoser path on
|
|
415
|
+
// a raw loser crashed outright (bare DELETE FROM memories hit the
|
|
416
|
+
// append-only trigger) — there is no legacy "successful forget, no
|
|
417
|
+
// purge" behavior to preserve for that case. Post-AT1's kind-aware
|
|
418
|
+
// removal (archiveRawMemory / deleteEntryCore above) makes plain
|
|
419
|
+
// --forget succeed on every kind, but until this fix the mirror was
|
|
420
|
+
// only purged when rejectLoserValue was ALSO set: a plain raw --forget
|
|
421
|
+
// left its markdown mirror orphaned (the reaper still catches it
|
|
422
|
+
// eventually, since archiveRawMemory's own raw_archive insert leaves
|
|
423
|
+
// mirror_cleaned_at NULL) and a plain non-raw --forget left its mirror
|
|
424
|
+
// orphaned FOREVER (no reaper exists for non-raw rows). Same post-commit
|
|
425
|
+
// purge+reaper pattern as the reject verb (src/reject-flow.ts) and
|
|
426
|
+
// api.archiveRaw — reusing removeEntryMirrors + raw_archive bookkeeping.
|
|
427
|
+
// AT1 P1 fix: loop over loserId AND every same-tenant duplicate the
|
|
428
|
+
// rejectLoserValue sweep above removed (extraRemovedIds) — previously
|
|
429
|
+
// only loserId's mirror was purged, leaving duplicate mirrors orphaned
|
|
430
|
+
// despite their rows being gone.
|
|
431
|
+
for (const removedId of [loserId, ...removal.extraRemovedIds]) {
|
|
432
|
+
const isRaw = removedId === loserId ? removal.loserWasRaw : removal.extraRemovedRawIds.includes(removedId);
|
|
433
|
+
// AT1 fix: purgeMirrorBestEffort retries once, then — for non-raw ids,
|
|
434
|
+
// which cleanupArchivedMirrors' reaper never scans — reports the
|
|
435
|
+
// EXPLICIT leftover path(s) instead of the false "will retry via
|
|
436
|
+
// reaper" claim. See its own doc comment (store.ts, near
|
|
437
|
+
// removeEntryMirrors) for the full rationale.
|
|
438
|
+
const mirrorOk = purgeMirrorBestEffort(hippoRoot, removedId, isRaw, 'resolveConflict');
|
|
439
|
+
if (mirrorOk && isRaw) {
|
|
440
|
+
db.prepare(`UPDATE raw_archive SET mirror_cleaned_at = ? WHERE memory_id = ?`).run(new Date().toISOString(), removedId);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
//# sourceMappingURL=conflicts.js.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type MemoryEntry } from '../memory.js';
|
|
2
|
+
import { openHippoDb } from '../db.js';
|
|
3
|
+
import { type DormantMove } from '../dormant.js';
|
|
4
|
+
/** Tables whose rows keep a first-class object's backing memory in `memory_id` (ON DELETE SET NULL); tests/dormant-memories.test.ts pins it to the schema. */
|
|
5
|
+
export declare const MEMORY_BACKED_TABLES: readonly ["predictions", "decisions", "incidents", "processes", "policies", "skills", "project_briefs", "customer_notes"];
|
|
6
|
+
/** Ids of memories that back a first-class object, for passes that plan deletes before making them. A table missing from an older schema is skipped. */
|
|
7
|
+
export declare function memoriesBackingObjects(hippoRoot: string): Set<string>;
|
|
8
|
+
/**
|
|
9
|
+
* AT1 (plan §4, round-2 fix, designed from source): db-scoped delete core.
|
|
10
|
+
* `deleteEntry` used to open+close its OWN connection, which meant it could
|
|
11
|
+
* never compose inside a caller's transaction (unlike writeEntry/
|
|
12
|
+
* writeEntryDbOnly, which already split this way). Split identically: row-
|
|
13
|
+
* meta SELECT, `DELETE FROM memories`, FTS delete, `forget` audit, DAG
|
|
14
|
+
* dirty-mark. NO filesystem I/O — the caller's own transaction may still be
|
|
15
|
+
* rolled back, and mirror writes must only happen post-commit.
|
|
16
|
+
*
|
|
17
|
+
* `opts.suppressForgetAudit` (default false, off): two AT1 callers set this
|
|
18
|
+
* so a removed non-raw row does NOT ALSO emit a `forget` row, because each
|
|
19
|
+
* already writes its own aggregate audit trail — `src/reject-flow.ts`'s
|
|
20
|
+
* `rejectValue` (single `reject_value` row covering every same-digest row
|
|
21
|
+
* removed) and `resolveConflict` (`conflict_resolve` row per resolution).
|
|
22
|
+
* Default keeps `deleteEntry` byte-identical to its pre-split behavior.
|
|
23
|
+
*
|
|
24
|
+
* Returns `{tenantId, dagParentId}` for the removed row, or `null` if no row with `id`
|
|
25
|
+
* existed or `automatic` refused it (pinned, raw, kept for good or backing an object at DELETE time, so a late pin wins).
|
|
26
|
+
*/
|
|
27
|
+
export declare function deleteEntryCore(db: ReturnType<typeof openHippoDb>, id: string, opts?: {
|
|
28
|
+
actor?: string;
|
|
29
|
+
suppressForgetAudit?: boolean;
|
|
30
|
+
reason?: string;
|
|
31
|
+
automatic?: boolean;
|
|
32
|
+
}): {
|
|
33
|
+
tenantId: string;
|
|
34
|
+
dagParentId: string | null;
|
|
35
|
+
} | null;
|
|
36
|
+
/**
|
|
37
|
+
* Delete an entry from SQLite and mirrors.
|
|
38
|
+
*
|
|
39
|
+
* `opts.actor` defaults to 'cli'. The api.* layer threads `ctx.actor` so HTTP
|
|
40
|
+
* callers land with `api_key:<key_id>` in the audit log without a duplicate
|
|
41
|
+
* emit from the api wrapper.
|
|
42
|
+
*
|
|
43
|
+
* Thin wrapper over `deleteEntryCore` (open → core → mirrors → close);
|
|
44
|
+
* behavior is byte-identical to the pre-split implementation for every
|
|
45
|
+
* existing caller.
|
|
46
|
+
*/
|
|
47
|
+
export declare function deleteEntry(hippoRoot: string, id: string, opts?: {
|
|
48
|
+
actor?: string;
|
|
49
|
+
reason?: string;
|
|
50
|
+
automatic?: boolean;
|
|
51
|
+
}): boolean;
|
|
52
|
+
/** Consolidation's flush, one transaction. With `snapshot` (rows as the caller loaded them), a write keeps only
|
|
53
|
+
* the fields the caller changed, takes the rest from the live row, and never resurrects a row that is gone.
|
|
54
|
+
*
|
|
55
|
+
* `dormant` (src/dormant.ts): each move's snapshot is inserted into `dormant_memories` and its `memories` row
|
|
56
|
+
* leaves exactly like a delete (FTS row, DAG parent dirty-mark, mirrors), in the same transaction, so a memory
|
|
57
|
+
* is never in both places or in neither. Deletes and moves both skip rows that are no longer auto-deletable
|
|
58
|
+
* (pinned, raw, kept for good or backing an object since the caller decided). Returns the ids that left `memories`, deleted or moved. */
|
|
59
|
+
export declare function batchWriteAndDelete(hippoRoot: string, toWrite: MemoryEntry[], toDeleteIds: string[], opts?: {
|
|
60
|
+
snapshot?: ReadonlyMap<string, MemoryEntry>;
|
|
61
|
+
dormant?: DormantMove[];
|
|
62
|
+
}): string[];
|
|
63
|
+
//# sourceMappingURL=delete-and-batch.d.ts.map
|