hippo-memory 1.59.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 -1260
- package/dist/api.js +25 -2711
- package/dist/audit.d.ts +3 -0
- package/dist/audit.js +7 -3
- package/dist/auth.d.ts +45 -4
- package/dist/auth.js +125 -48
- package/dist/autolearn.js +7 -4
- 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 +319 -13
- package/dist/cli.js +436 -8580
- package/dist/client.js +15 -8
- package/dist/compaction-record.js +12 -9
- package/dist/config.js +12 -11
- package/dist/connectors/github/backfill.js +94 -87
- package/dist/connectors/github/cli-impl.js +5 -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 +13 -12
- 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 +231 -203
- 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 -3036
- package/dist/decisions.d.ts +4 -1
- package/dist/decisions.js +9 -7
- package/dist/dedupe.js +3 -2
- package/dist/delivery-recorder.js +5 -1
- package/dist/doctor.js +4 -3
- package/dist/dormant.js +1 -0
- package/dist/embedding-provider.d.ts +1 -1
- package/dist/embedding-provider.js +7 -5
- package/dist/embeddings.d.ts +9 -52
- package/dist/embeddings.js +47 -298
- 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 +5 -4
- 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} +8 -391
- 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/handoff.js +3 -0
- 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 +8 -5
- package/dist/index.d.ts +25 -6
- package/dist/index.js +23 -6
- package/dist/invalidation.js +2 -1
- package/dist/judgment.js +7 -3
- 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 -70
- package/dist/mcp/server.js +8 -1172
- 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 +8 -3
- 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 +8 -5
- package/dist/project-briefs.d.ts +3 -0
- package/dist/project-briefs.js +7 -5
- package/dist/project-identity.d.ts +1 -1
- package/dist/project-identity.js +12 -6
- package/dist/project-merge.js +3 -1
- package/dist/quarantine.d.ts +2 -1
- package/dist/quarantine.js +8 -5
- package/dist/raw-archive-mirror-cleanup.js +2 -1
- 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 +3 -3
- package/dist/recall-trace.js +10 -14
- package/dist/refine-llm.js +20 -11
- package/dist/reject-flow.js +6 -1
- package/dist/rerankers/clef.d.ts +2 -2
- package/dist/rerankers/clef.js +72 -30
- package/dist/rerankers/cross-encoder.js +6 -4
- package/dist/rerankers/jev.d.ts +4 -2
- package/dist/rerankers/jev.js +24 -19
- package/dist/rerankers/llm.d.ts +4 -2
- package/dist/rerankers/llm.js +61 -41
- package/dist/rerankers/types.d.ts +1 -1
- package/dist/salience.js +1 -1
- package/dist/same-text.d.ts +2 -0
- package/dist/same-text.js +4 -0
- package/dist/scheduler.d.ts +1 -0
- package/dist/scheduler.js +26 -3
- 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 +3 -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 +92 -2368
- 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 +46 -40
- package/dist/skills.d.ts +3 -0
- package/dist/skills.js +7 -5
- package/dist/stdin.js +3 -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/token-ledger.js +1 -0
- 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 +2 -1
- package/dist/capture.d.ts +0 -155
- package/dist/capture.js +0 -1293
- package/dist/consolidate.d.ts +0 -58
- package/dist/consolidate.js +0 -1123
- package/dist/graph.d.ts +0 -245
- package/dist/hooks.d.ts +0 -208
- package/dist/hooks.js +0 -1073
- package/dist/importers.js +0 -897
- package/dist/predictions.js +0 -620
- package/dist/search.d.ts +0 -320
- package/dist/search.js +0 -968
- package/dist/store.d.ts +0 -744
- package/dist/store.js +0 -3372
- 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,312 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { Layer } from '../memory.js';
|
|
4
|
+
import { dumpFrontmatter } from '../yaml.js';
|
|
5
|
+
import { getMeta } from '../db.js';
|
|
6
|
+
import { log } from '../log.js';
|
|
7
|
+
import { parseJsonArray, INDEX_VERSION, parseLastTraceId, MEMORY_SELECT_COLUMNS, rowToEntry, rowToMemoryConflict, } from './rows.js';
|
|
8
|
+
import { serializeEntry } from './markdown.js';
|
|
9
|
+
export function layerDir(root, layer) {
|
|
10
|
+
return path.join(root, layer);
|
|
11
|
+
}
|
|
12
|
+
export function ensureMirrorDirectories(hippoRoot) {
|
|
13
|
+
const dirs = [
|
|
14
|
+
hippoRoot,
|
|
15
|
+
path.join(hippoRoot, 'buffer'),
|
|
16
|
+
path.join(hippoRoot, 'episodic'),
|
|
17
|
+
path.join(hippoRoot, 'semantic'),
|
|
18
|
+
path.join(hippoRoot, 'conflicts'),
|
|
19
|
+
];
|
|
20
|
+
for (const dir of dirs) {
|
|
21
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Tenant-scoped mirror file paths. The single-tenant 'default' deployment
|
|
25
|
+
// keeps the original `active-task.md` / `recent-session.md` filenames for
|
|
26
|
+
// on-disk back-compat; multi-tenant deployments get a `.<tenantId>` suffix
|
|
27
|
+
// so tenant B saving cannot overwrite tenant A's mirror file.
|
|
28
|
+
function activeTaskMirrorPath(hippoRoot, tenantId) {
|
|
29
|
+
const file = tenantId === 'default' ? 'active-task.md' : `active-task.${tenantId}.md`;
|
|
30
|
+
return path.join(hippoRoot, 'buffer', file);
|
|
31
|
+
}
|
|
32
|
+
function recentSessionMirrorPath(hippoRoot, tenantId) {
|
|
33
|
+
const file = tenantId === 'default' ? 'recent-session.md' : `recent-session.${tenantId}.md`;
|
|
34
|
+
return path.join(hippoRoot, 'buffer', file);
|
|
35
|
+
}
|
|
36
|
+
export function writeActiveTaskMirror(hippoRoot, tenantId, snapshot) {
|
|
37
|
+
const filePath = activeTaskMirrorPath(hippoRoot, tenantId);
|
|
38
|
+
const fm = dumpFrontmatter({
|
|
39
|
+
id: snapshot.id,
|
|
40
|
+
task: snapshot.task,
|
|
41
|
+
status: snapshot.status,
|
|
42
|
+
source: snapshot.source,
|
|
43
|
+
session_id: snapshot.session_id,
|
|
44
|
+
created_at: snapshot.created_at,
|
|
45
|
+
updated_at: snapshot.updated_at,
|
|
46
|
+
next_step: snapshot.next_step,
|
|
47
|
+
});
|
|
48
|
+
const body = [
|
|
49
|
+
`# Active Task Snapshot`,
|
|
50
|
+
'',
|
|
51
|
+
`## Summary`,
|
|
52
|
+
snapshot.summary,
|
|
53
|
+
'',
|
|
54
|
+
`## Next step`,
|
|
55
|
+
snapshot.next_step,
|
|
56
|
+
'',
|
|
57
|
+
`## Task`,
|
|
58
|
+
snapshot.task,
|
|
59
|
+
'',
|
|
60
|
+
];
|
|
61
|
+
if (snapshot.session_id) {
|
|
62
|
+
body.push(`## Session`, snapshot.session_id, '');
|
|
63
|
+
}
|
|
64
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
65
|
+
fs.writeFileSync(filePath, `${fm}\n\n${body.join('\n')}`, 'utf8');
|
|
66
|
+
}
|
|
67
|
+
export function removeActiveTaskMirror(hippoRoot, tenantId) {
|
|
68
|
+
const filePath = activeTaskMirrorPath(hippoRoot, tenantId);
|
|
69
|
+
if (fs.existsSync(filePath)) {
|
|
70
|
+
fs.unlinkSync(filePath);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function writeRecentSessionMirror(hippoRoot, tenantId, events) {
|
|
74
|
+
const filePath = recentSessionMirrorPath(hippoRoot, tenantId);
|
|
75
|
+
if (events.length === 0) {
|
|
76
|
+
if (fs.existsSync(filePath)) {
|
|
77
|
+
fs.unlinkSync(filePath);
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const latest = events[events.length - 1];
|
|
82
|
+
const fm = dumpFrontmatter({
|
|
83
|
+
session_id: latest.session_id,
|
|
84
|
+
task: latest.task,
|
|
85
|
+
event_count: events.length,
|
|
86
|
+
updated_at: latest.created_at,
|
|
87
|
+
});
|
|
88
|
+
const lines = [
|
|
89
|
+
'# Recent Session Trail',
|
|
90
|
+
'',
|
|
91
|
+
`- Session: ${latest.session_id}`,
|
|
92
|
+
`- Task: ${latest.task ?? 'n/a'}`,
|
|
93
|
+
`- Updated: ${latest.created_at}`,
|
|
94
|
+
'',
|
|
95
|
+
'## Events',
|
|
96
|
+
'',
|
|
97
|
+
];
|
|
98
|
+
for (const event of events) {
|
|
99
|
+
lines.push(`- [${event.created_at}] (${event.event_type}) ${event.content}`);
|
|
100
|
+
}
|
|
101
|
+
lines.push('');
|
|
102
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
103
|
+
fs.writeFileSync(filePath, `${fm}\n\n${lines.join('\n')}`, 'utf8');
|
|
104
|
+
}
|
|
105
|
+
function writeConflictMirrors(hippoRoot, conflicts) {
|
|
106
|
+
const conflictDir = path.join(hippoRoot, 'conflicts');
|
|
107
|
+
fs.mkdirSync(conflictDir, { recursive: true });
|
|
108
|
+
const keep = new Set();
|
|
109
|
+
for (const conflict of conflicts) {
|
|
110
|
+
const filename = `conflict_${conflict.id}.md`;
|
|
111
|
+
keep.add(filename);
|
|
112
|
+
const fm = dumpFrontmatter({
|
|
113
|
+
id: conflict.id,
|
|
114
|
+
memory_a_id: conflict.memory_a_id,
|
|
115
|
+
memory_b_id: conflict.memory_b_id,
|
|
116
|
+
reason: conflict.reason,
|
|
117
|
+
score: Math.round(conflict.score * 10000) / 10000,
|
|
118
|
+
status: conflict.status,
|
|
119
|
+
detected_at: conflict.detected_at,
|
|
120
|
+
updated_at: conflict.updated_at,
|
|
121
|
+
});
|
|
122
|
+
const body = [
|
|
123
|
+
'# Memory Conflict',
|
|
124
|
+
'',
|
|
125
|
+
`- Memory A: ${conflict.memory_a_id}`,
|
|
126
|
+
`- Memory B: ${conflict.memory_b_id}`,
|
|
127
|
+
`- Reason: ${conflict.reason}`,
|
|
128
|
+
`- Score: ${conflict.score.toFixed(3)}`,
|
|
129
|
+
`- Status: ${conflict.status}`,
|
|
130
|
+
'',
|
|
131
|
+
].join('\n');
|
|
132
|
+
fs.writeFileSync(path.join(conflictDir, filename), `${fm}\n\n${body}`, 'utf8');
|
|
133
|
+
}
|
|
134
|
+
for (const existing of fs.readdirSync(conflictDir)) {
|
|
135
|
+
if (existing === '.gitkeep')
|
|
136
|
+
continue;
|
|
137
|
+
if (!keep.has(existing)) {
|
|
138
|
+
fs.unlinkSync(path.join(conflictDir, existing));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export function writeMarkdownMirror(hippoRoot, entry) {
|
|
143
|
+
removeEntryMirrors(hippoRoot, entry.id);
|
|
144
|
+
const dir = layerDir(hippoRoot, entry.layer);
|
|
145
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
146
|
+
fs.writeFileSync(path.join(dir, `${entry.id}.md`), serializeEntry(entry), 'utf8');
|
|
147
|
+
}
|
|
148
|
+
// AT1 P1 fix (codex): `writeMarkdownMirror` writes ANY layer's mirror,
|
|
149
|
+
// including `trace/<id>.md` for Layer.Trace rows (auto-promoted traces,
|
|
150
|
+
// consolidate.ts) — but this enumeration only walked
|
|
151
|
+
// Buffer/Episodic/Semantic. A rejected/forgotten trace row's markdown
|
|
152
|
+
// content survived on disk while the purge (and `hippo reject`/plain
|
|
153
|
+
// `forget`) reported success, and a stale trace mirror is exactly the
|
|
154
|
+
// resurrection channel bootstrapLegacyStore/rebuildIndex guard against.
|
|
155
|
+
// Fixes BOTH the AT1 reject-flow purge and the pre-existing plain-`forget`
|
|
156
|
+
// gap for trace rows (deleteEntry has always called this same function).
|
|
157
|
+
export function removeEntryMirrors(hippoRoot, id) {
|
|
158
|
+
for (const layer of [Layer.Buffer, Layer.Episodic, Layer.Semantic, Layer.Trace]) {
|
|
159
|
+
const file = path.join(layerDir(hippoRoot, layer), `${id}.md`);
|
|
160
|
+
if (fs.existsSync(file)) {
|
|
161
|
+
fs.unlinkSync(file);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* AT1 mirror-purge honesty fix (docs/plans/2026-08-15-at1-rejected-value-tombstone.md):
|
|
167
|
+
* the candidate markdown mirror paths still on disk for `id`, computed the
|
|
168
|
+
* same way `removeEntryMirrors` walks them (one per layer: buffer/episodic/
|
|
169
|
+
* semantic), filtered to the ones that still `fs.existsSync`. Used to report
|
|
170
|
+
* an EXPLICIT path when a best-effort purge fails and no reaper exists to
|
|
171
|
+
* retry it — plain `removeEntryMirrors` returns void, giving no way to name
|
|
172
|
+
* which file is stuck.
|
|
173
|
+
*/
|
|
174
|
+
export function getExistingEntryMirrorPaths(hippoRoot, id) {
|
|
175
|
+
// AT1 P1 fix (codex): same missing Layer.Trace as removeEntryMirrors above
|
|
176
|
+
// — kept in lockstep with it since this function's whole purpose is
|
|
177
|
+
// walking the mirror paths "the same way removeEntryMirrors walks them"
|
|
178
|
+
// (see its own doc comment).
|
|
179
|
+
return [Layer.Buffer, Layer.Episodic, Layer.Semantic, Layer.Trace]
|
|
180
|
+
.map((layer) => path.join(layerDir(hippoRoot, layer), `${id}.md`))
|
|
181
|
+
.filter((file) => fs.existsSync(file));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* AT1 fix: best-effort markdown-mirror purge shared by `reject-flow.ts`'s
|
|
185
|
+
* `rejectValue` and `resolveConflict`'s post-commit purge. Both used to log
|
|
186
|
+
* "will retry via reaper on next open" for EVERY failure, but the reaper
|
|
187
|
+
* (`cleanupArchivedMirrors`, raw-archive-mirror-cleanup.ts) only scans
|
|
188
|
+
* `raw_archive` — that message was false for a non-raw id, which has no
|
|
189
|
+
* reaper at all.
|
|
190
|
+
*
|
|
191
|
+
* Retries the unlink once synchronously (the common real-world failure is a
|
|
192
|
+
* transient lock/AV-scanner false positive, not a permanent one). On a
|
|
193
|
+
* second failure: raw ids still get the honest reaper message (true); non-raw
|
|
194
|
+
* ids get the EXPLICIT leftover file path(s) and a manual-delete instruction,
|
|
195
|
+
* since nothing will ever retry them automatically.
|
|
196
|
+
*
|
|
197
|
+
* Returns true if the mirror ended up purged (first or second attempt).
|
|
198
|
+
*/
|
|
199
|
+
export function purgeMirrorBestEffort(hippoRoot, id, isRaw, logPrefix) {
|
|
200
|
+
try {
|
|
201
|
+
removeEntryMirrors(hippoRoot, id);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
try {
|
|
206
|
+
removeEntryMirrors(hippoRoot, id);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
catch (secondErr) {
|
|
210
|
+
const msg = secondErr instanceof Error ? secondErr.message : String(secondErr);
|
|
211
|
+
if (isRaw) {
|
|
212
|
+
log.error(`${logPrefix}: mirror cleanup failed for ${id} (will retry via reaper on next open): ${msg}`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const leftover = getExistingEntryMirrorPaths(hippoRoot, id);
|
|
216
|
+
const pathsNote = leftover.length > 0 ? leftover.join(', ') : `${id}.md (path unresolved)`;
|
|
217
|
+
log.error(`${logPrefix}: mirror cleanup failed for ${id} - no automatic retry exists for this file, ` +
|
|
218
|
+
`delete it manually: ${pathsNote} (${msg})`);
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/** Derive the current `HippoIndex` from SQLite. Exported for `rebuildIndex`
|
|
225
|
+
* (the only index.json writer) and the longmemeval benchmark. */
|
|
226
|
+
export function buildIndexFromDb(db) {
|
|
227
|
+
// SAFETY: rows' shape matches the seven columns named in the SELECT below.
|
|
228
|
+
const rows = db.prepare(`SELECT id, created, last_retrieved, strength, layer, tags_json, pinned FROM memories ORDER BY created ASC, id ASC`).all();
|
|
229
|
+
const entries = {};
|
|
230
|
+
for (const row of rows) {
|
|
231
|
+
// SAFETY: layer is only ever written from the Layer enum by this
|
|
232
|
+
// module's own INSERT/UPDATE paths.
|
|
233
|
+
const layer = row.layer;
|
|
234
|
+
entries[row.id] = {
|
|
235
|
+
id: row.id,
|
|
236
|
+
file: path.join(layer, `${row.id}.md`),
|
|
237
|
+
layer,
|
|
238
|
+
strength: Number(row.strength ?? 0),
|
|
239
|
+
tags: parseJsonArray(row.tags_json),
|
|
240
|
+
created: row.created,
|
|
241
|
+
last_retrieved: row.last_retrieved,
|
|
242
|
+
pinned: Boolean(row.pinned),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// LC1 codex round-2 med: the two lockstep keys must be read in ONE
|
|
246
|
+
// statement. Two autocommit SELECTs leave a window where a concurrent
|
|
247
|
+
// saveIndex (which commits both keys in one transaction) lands between
|
|
248
|
+
// them, handing the reader mismatched last_retrieval_ids / last_trace_id
|
|
249
|
+
// and re-opening the mislinkage hole saveIndex's BEGIN/COMMIT closed on
|
|
250
|
+
// the write side. One SELECT = one SQLite read snapshot.
|
|
251
|
+
// SAFETY: lockstepRows' shape matches the key/value columns named above.
|
|
252
|
+
const lockstepRows = db.prepare(`SELECT key, value FROM meta WHERE key IN ('last_retrieval_ids', 'last_trace_id')`).all();
|
|
253
|
+
const lockstep = new Map(lockstepRows.map((r) => [r.key, r.value]));
|
|
254
|
+
return {
|
|
255
|
+
version: INDEX_VERSION,
|
|
256
|
+
entries,
|
|
257
|
+
last_retrieval_ids: parseJsonArray(lockstep.get('last_retrieval_ids') ?? '[]'),
|
|
258
|
+
last_trace_id: parseLastTraceId(lockstep.get('last_trace_id') ?? ''),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
export function buildStatsFromDb(db) {
|
|
262
|
+
// SAFETY: runs' shape matches the four columns named in the SELECT above.
|
|
263
|
+
const runs = db.prepare(`SELECT timestamp, decayed, merged, removed FROM consolidation_runs ORDER BY timestamp ASC, id ASC`).all();
|
|
264
|
+
return {
|
|
265
|
+
total_remembered: Number(getMeta(db, 'total_remembered', '0')),
|
|
266
|
+
total_recalled: Number(getMeta(db, 'total_recalled', '0')),
|
|
267
|
+
total_forgotten: Number(getMeta(db, 'total_forgotten', '0')),
|
|
268
|
+
consolidation_runs: runs.map((run) => ({
|
|
269
|
+
timestamp: run.timestamp,
|
|
270
|
+
decayed: run.decayed,
|
|
271
|
+
merged: run.merged,
|
|
272
|
+
removed: run.removed,
|
|
273
|
+
})),
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/** Write the `index.json` mirror file for an already-derived index. Exported for
|
|
277
|
+
* `rebuildIndex` (the only index.json writer) and the longmemeval benchmark. */
|
|
278
|
+
export function writeIndexMirror(hippoRoot, index) {
|
|
279
|
+
mirrorBestEffort('index.json', () => fs.writeFileSync(path.join(hippoRoot, 'index.json'), JSON.stringify(index, null, 2), 'utf8'));
|
|
280
|
+
}
|
|
281
|
+
export function writeStatsMirror(hippoRoot, stats) {
|
|
282
|
+
mirrorBestEffort('stats.json', () => fs.writeFileSync(path.join(hippoRoot, 'stats.json'), JSON.stringify(stats, null, 2), 'utf8'));
|
|
283
|
+
}
|
|
284
|
+
/** Mirrors are derived from SQLite and written after COMMIT, so a failed write warns instead of failing a committed change. */
|
|
285
|
+
export function mirrorBestEffort(what, write) {
|
|
286
|
+
try {
|
|
287
|
+
write();
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
log.warn(`${what} not refreshed (${err instanceof Error ? err.message : String(err)}); the database write succeeded`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function syncMirrorFiles(hippoRoot, db) {
|
|
294
|
+
// SAFETY: this query selects exactly MEMORY_SELECT_COLUMNS, matching
|
|
295
|
+
// MemoryRow's field set.
|
|
296
|
+
const entries = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories ORDER BY created ASC, id ASC`).all();
|
|
297
|
+
mirrorBestEffort('markdown mirrors', () => {
|
|
298
|
+
for (const entry of entries.map(rowToEntry))
|
|
299
|
+
writeMarkdownMirror(hippoRoot, entry);
|
|
300
|
+
});
|
|
301
|
+
// SAFETY: conflicts' shape matches the eight columns named in the SELECT
|
|
302
|
+
// above.
|
|
303
|
+
const conflicts = db.prepare(`
|
|
304
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
305
|
+
FROM memory_conflicts
|
|
306
|
+
WHERE status = 'open'
|
|
307
|
+
ORDER BY updated_at DESC, id DESC
|
|
308
|
+
`).all();
|
|
309
|
+
mirrorBestEffort('conflict mirrors', () => writeConflictMirrors(hippoRoot, conflicts.map(rowToMemoryConflict)));
|
|
310
|
+
writeStatsMirror(hippoRoot, buildStatsFromDb(db));
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=mirrors.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type MemoryEntry } from '../memory.js';
|
|
2
|
+
import { type DatabaseSyncLike } from '../db.js';
|
|
3
|
+
import { type ResolveProjectIdentityOpts } from '../project-identity.js';
|
|
4
|
+
/** Nearest ancestor store like git; the strict join is the fallback so `hippo init` still creates `<cwd>/.hippo`. */
|
|
5
|
+
export declare function getHippoRoot(cwd?: string, opts?: ResolveProjectIdentityOpts): string;
|
|
6
|
+
export declare function isInitialized(hippoRoot: string): boolean;
|
|
7
|
+
export declare function initStore(hippoRoot: string): void;
|
|
8
|
+
/** One open connection with init done on it, for callers who used to pay for `initStore` + a second `openHippoDb`. */
|
|
9
|
+
export declare function openStore(hippoRoot: string): DatabaseSyncLike;
|
|
10
|
+
/** `meta` key holding the default half-life base a store's memories are on (src/half-life-migration.ts). */
|
|
11
|
+
export declare const HALF_LIFE_BASE_META_KEY = "default_half_life_base";
|
|
12
|
+
/** `meta` key set once no memory of a decision, incident or other object sits on the old flat 90 days. */
|
|
13
|
+
export declare const TYPED_HALF_LIFE_META_KEY = "typed_half_life_on_default";
|
|
14
|
+
export declare function loadLegacyEntriesFromMarkdown(hippoRoot: string): MemoryEntry[];
|
|
15
|
+
//# sourceMappingURL=open.d.ts.map
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// Opens the SQLite store, the source of truth; Markdown and JSON files are human-readable mirrors of it.
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { DEFAULT_HALF_LIFE_DAYS, Layer } from '../memory.js';
|
|
5
|
+
import { closeHippoDb, openHippoDb, getMeta, setMeta } from '../db.js';
|
|
6
|
+
import { findHippoStoreDir, realpathOrResolve } from '../project-identity.js';
|
|
7
|
+
import { RejectedValueError } from '../rejection.js';
|
|
8
|
+
import { log } from '../log.js';
|
|
9
|
+
import { isPlainJsonObject } from './rows.js';
|
|
10
|
+
import { audit } from './audit-event.js';
|
|
11
|
+
import { deserializeEntry } from './markdown.js';
|
|
12
|
+
import { stampOriginProjectForImport, upsertEntryRow } from './entry-row.js';
|
|
13
|
+
import { ensureMirrorDirectories, syncMirrorFiles, layerDir } from './mirrors.js';
|
|
14
|
+
/** Nearest ancestor store like git; the strict join is the fallback so `hippo init` still creates `<cwd>/.hippo`. */
|
|
15
|
+
export function getHippoRoot(cwd = process.cwd(), opts) {
|
|
16
|
+
return findHippoStoreDir(cwd, opts) ?? path.join(realpathOrResolve(cwd), '.hippo');
|
|
17
|
+
}
|
|
18
|
+
export function isInitialized(hippoRoot) {
|
|
19
|
+
// A bare .hippo directory is not enough — autoInstallHooks /
|
|
20
|
+
// setupDailySchedule can create it without ever calling initStore,
|
|
21
|
+
// leaving a partial directory (integrations/, logs/, runs/) with no
|
|
22
|
+
// hippo.db. Returning true in that state caused `hippo init` to skip
|
|
23
|
+
// initStore and `hippo recall` to silently fall back to an empty store
|
|
24
|
+
// (incident 2026-04-26: ingest_direct.py against a bare .hippo).
|
|
25
|
+
// Treat the store as initialized only if hippo.db actually exists.
|
|
26
|
+
return fs.existsSync(path.join(hippoRoot, 'hippo.db'));
|
|
27
|
+
}
|
|
28
|
+
export function initStore(hippoRoot) {
|
|
29
|
+
closeHippoDb(openStore(hippoRoot));
|
|
30
|
+
}
|
|
31
|
+
/** One open connection with init done on it, for callers who used to pay for `initStore` + a second `openHippoDb`. */
|
|
32
|
+
export function openStore(hippoRoot) {
|
|
33
|
+
ensureMirrorDirectories(hippoRoot);
|
|
34
|
+
const db = openHippoDb(hippoRoot);
|
|
35
|
+
try {
|
|
36
|
+
const bootstrapped = bootstrapLegacyStore(db, hippoRoot);
|
|
37
|
+
if (bootstrapped) {
|
|
38
|
+
syncMirrorFiles(hippoRoot, db);
|
|
39
|
+
}
|
|
40
|
+
recordHalfLifeBaseForNewStore(db);
|
|
41
|
+
return db;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
try {
|
|
45
|
+
closeHippoDb(db);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Best effort only; surface the original init error.
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** `meta` key holding the default half-life base a store's memories are on (src/half-life-migration.ts). */
|
|
54
|
+
export const HALF_LIFE_BASE_META_KEY = 'default_half_life_base';
|
|
55
|
+
/** `meta` key set once no memory of a decision, incident or other object sits on the old flat 90 days. */
|
|
56
|
+
export const TYPED_HALF_LIFE_META_KEY = 'typed_half_life_on_default';
|
|
57
|
+
/**
|
|
58
|
+
* A store with no memories starts on the current default half-life base, so
|
|
59
|
+
* `hippo sleep` never migrates it. A store that already holds memories and
|
|
60
|
+
* no recorded base predates the record, and keeps reading as the legacy
|
|
61
|
+
* 7-day base until sleep migrates it.
|
|
62
|
+
*/
|
|
63
|
+
function recordHalfLifeBaseForNewStore(db) {
|
|
64
|
+
if (getMeta(db, HALF_LIFE_BASE_META_KEY, '') !== '')
|
|
65
|
+
return;
|
|
66
|
+
if (db.prepare(`SELECT 1 AS x FROM memories LIMIT 1`).get() !== undefined)
|
|
67
|
+
return;
|
|
68
|
+
setMeta(db, HALF_LIFE_BASE_META_KEY, String(DEFAULT_HALF_LIFE_DAYS));
|
|
69
|
+
setMeta(db, TYPED_HALF_LIFE_META_KEY, '1');
|
|
70
|
+
}
|
|
71
|
+
function bootstrapLegacyStore(db, hippoRoot) {
|
|
72
|
+
// SAFETY: countRow's shape matches the single `COUNT(*) AS count` column
|
|
73
|
+
// selected above; `.get()` returns undefined only when no row exists.
|
|
74
|
+
const countRow = db.prepare(`SELECT COUNT(*) AS count FROM memories`).get();
|
|
75
|
+
const memoryCount = Number(countRow?.count ?? 0);
|
|
76
|
+
if (memoryCount > 0)
|
|
77
|
+
return false;
|
|
78
|
+
// AT1 P2 fix: memoryCount alone is not a reliable "already bootstrapped"
|
|
79
|
+
// signal once the rejection guard exists. If EVERY legacy mirror row is
|
|
80
|
+
// rejected, memories stays at 0 rows even after a successful bootstrap
|
|
81
|
+
// pass, so the memoryCount>0 gate above never trips — every subsequent
|
|
82
|
+
// initStore() call would re-run this whole function: re-scan the legacy
|
|
83
|
+
// mirrors, re-attempt (and re-refuse, re-auditing) every row, and
|
|
84
|
+
// re-INSERT the legacy consolidation_runs rows with no dedup, duplicating
|
|
85
|
+
// them on each open. A dedicated meta flag marks bootstrap as
|
|
86
|
+
// attempted-and-settled regardless of how many rows actually landed.
|
|
87
|
+
if (getMeta(db, 'legacy_bootstrap_completed', '0') === '1')
|
|
88
|
+
return false;
|
|
89
|
+
const legacyEntries = loadLegacyEntriesFromMarkdown(hippoRoot);
|
|
90
|
+
if (legacyEntries.length === 0)
|
|
91
|
+
return false;
|
|
92
|
+
db.exec('BEGIN');
|
|
93
|
+
try {
|
|
94
|
+
importLegacyEntries(db, hippoRoot, legacyEntries);
|
|
95
|
+
importLegacyIndexAndStats(db, hippoRoot);
|
|
96
|
+
// AT1 P2 fix: stamp completion regardless of how many rows actually
|
|
97
|
+
// landed (all-rejected included) — see the gate comment above.
|
|
98
|
+
setMeta(db, 'legacy_bootstrap_completed', '1');
|
|
99
|
+
db.exec('COMMIT');
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
try {
|
|
103
|
+
db.exec('ROLLBACK');
|
|
104
|
+
}
|
|
105
|
+
catch { /* already rolled back; keep the original error */ }
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
function importLegacyEntries(db, hippoRoot, legacyEntries) {
|
|
111
|
+
// AT1 (plan §3, round-3 redesign): run the guard LIVE per row rather
|
|
112
|
+
// than bypassing it. bootstrapLegacyStore is exactly the channel through
|
|
113
|
+
// which a stale/never-purged markdown mirror could resurrect a rejected
|
|
114
|
+
// value; a skip-and-count here closes that structurally, independent of
|
|
115
|
+
// mirror state. The refusal audit is written INLINE inside this
|
|
116
|
+
// still-open loop transaction (plain audit() — nothing is rolled back
|
|
117
|
+
// on a per-row skip, so the post-rollback auditRejectionRefusal helper
|
|
118
|
+
// is the wrong tool here).
|
|
119
|
+
let rejectedCount = 0;
|
|
120
|
+
for (const entry of legacyEntries) {
|
|
121
|
+
// v39: legacy markdown carries no origin_project; stamp from the store
|
|
122
|
+
// location so bootstrapped rows stay visible to ambient context.
|
|
123
|
+
const stamped = stampOriginProjectForImport(hippoRoot, entry);
|
|
124
|
+
try {
|
|
125
|
+
upsertEntryRow(db, stamped);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (err instanceof RejectedValueError) {
|
|
129
|
+
rejectedCount++;
|
|
130
|
+
audit(db, 'reject_refusal', err.entryId, { digest: err.digest, reason: err.reason }, 'cli', err.tenantId);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
throw err;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (rejectedCount > 0) {
|
|
137
|
+
log.warn(`bootstrapLegacyStore: skipped ${rejectedCount} rejected value(s) found in legacy mirrors`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function importLegacyIndexAndStats(db, hippoRoot) {
|
|
141
|
+
const legacyIndex = loadLegacyIndexFile(hippoRoot);
|
|
142
|
+
setMeta(db, 'last_retrieval_ids', JSON.stringify(legacyIndex.last_retrieval_ids ?? []));
|
|
143
|
+
// LC1: legacy index.json predates last_trace_id, so this is '' for every
|
|
144
|
+
// pre-v40 store — harmless, matches the ensureMetaDefaults default.
|
|
145
|
+
// Coerce like its neighbors below coerce theirs (independent-review-critic
|
|
146
|
+
// LOW finding): accept only a clean digit string, else fall back to ''
|
|
147
|
+
// rather than trusting whatever a hand-edited/corrupt index.json carries.
|
|
148
|
+
const legacyTraceId = String(legacyIndex.last_trace_id ?? '');
|
|
149
|
+
setMeta(db, 'last_trace_id', /^\d+$/.test(legacyTraceId) ? legacyTraceId : '');
|
|
150
|
+
const legacyStats = loadLegacyStatsFile(hippoRoot);
|
|
151
|
+
setMeta(db, 'total_remembered', String(Number(legacyStats.total_remembered ?? 0)));
|
|
152
|
+
setMeta(db, 'total_recalled', String(Number(legacyStats.total_recalled ?? 0)));
|
|
153
|
+
setMeta(db, 'total_forgotten', String(Number(legacyStats.total_forgotten ?? 0)));
|
|
154
|
+
const runs = Array.isArray(legacyStats.consolidation_runs) ? legacyStats.consolidation_runs : [];
|
|
155
|
+
const insertRun = db.prepare(`INSERT INTO consolidation_runs(timestamp, decayed, merged, removed) VALUES (?, ?, ?, ?)`);
|
|
156
|
+
for (const run of runs) {
|
|
157
|
+
if (!isPlainJsonObject(run))
|
|
158
|
+
continue;
|
|
159
|
+
const row = run;
|
|
160
|
+
insertRun.run(String(row.timestamp ?? new Date().toISOString()), Number(row.decayed ?? 0), Number(row.merged ?? 0), Number(row.removed ?? 0));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export function loadLegacyEntriesFromMarkdown(hippoRoot) {
|
|
164
|
+
const entries = [];
|
|
165
|
+
for (const layer of [Layer.Buffer, Layer.Episodic, Layer.Semantic]) {
|
|
166
|
+
const dir = layerDir(hippoRoot, layer);
|
|
167
|
+
if (!fs.existsSync(dir))
|
|
168
|
+
continue;
|
|
169
|
+
for (const file of fs.readdirSync(dir)) {
|
|
170
|
+
if (!file.endsWith('.md'))
|
|
171
|
+
continue;
|
|
172
|
+
const raw = fs.readFileSync(path.join(dir, file), 'utf8');
|
|
173
|
+
const entry = deserializeEntry(raw);
|
|
174
|
+
if (entry)
|
|
175
|
+
entries.push(entry);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return entries;
|
|
179
|
+
}
|
|
180
|
+
function loadLegacyIndexFile(hippoRoot) {
|
|
181
|
+
const indexPath = path.join(hippoRoot, 'index.json');
|
|
182
|
+
if (!fs.existsSync(indexPath)) {
|
|
183
|
+
return { version: 1, entries: {}, last_retrieval_ids: [], last_trace_id: null };
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
// SAFETY: index.json is only ever written by writeIndexMirror below,
|
|
187
|
+
// which always serializes a HippoIndex; a hand-edited or corrupted file
|
|
188
|
+
// that violates the shape falls through to the catch block's fallback.
|
|
189
|
+
return JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
log.debug(`store: unreadable index.json read as empty: ${err instanceof Error ? err.message : String(err)}`);
|
|
193
|
+
return { version: 1, entries: {}, last_retrieval_ids: [], last_trace_id: null };
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function loadLegacyStatsFile(hippoRoot) {
|
|
197
|
+
const statsPath = path.join(hippoRoot, 'stats.json');
|
|
198
|
+
if (!fs.existsSync(statsPath)) {
|
|
199
|
+
return {
|
|
200
|
+
total_remembered: 0,
|
|
201
|
+
total_recalled: 0,
|
|
202
|
+
total_forgotten: 0,
|
|
203
|
+
consolidation_runs: [],
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
// SAFETY: stats.json is only ever written by writeStatsMirror below,
|
|
208
|
+
// which always emits exactly these four fields; callers additionally
|
|
209
|
+
// guard every read with `?? 0` / `Array.isArray`, tolerating a
|
|
210
|
+
// hand-edited or corrupted file even if this optimistic cast is wrong.
|
|
211
|
+
return JSON.parse(fs.readFileSync(statsPath, 'utf8'));
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
log.debug(`store: unreadable stats.json read as zero: ${err instanceof Error ? err.message : String(err)}`);
|
|
215
|
+
return {
|
|
216
|
+
total_remembered: 0,
|
|
217
|
+
total_recalled: 0,
|
|
218
|
+
total_forgotten: 0,
|
|
219
|
+
consolidation_runs: [],
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=open.js.map
|