hippo-memory 1.71.0 → 2.0.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 +7 -5
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +11 -26
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/copilot.d.ts +1 -3
- package/dist/agent-memories/copilot.js +1 -17
- package/dist/agent-memories/project-folds.d.ts +10 -0
- package/dist/agent-memories/project-folds.js +34 -0
- package/dist/agent-memories/sync.js +8 -6
- package/dist/api/assemble.js +3 -2
- package/dist/api/audit.d.ts +30 -2
- package/dist/api/audit.js +48 -7
- package/dist/api/auth.d.ts +11 -9
- package/dist/api/auth.js +39 -40
- package/dist/api/auto-sleep.d.ts +5 -2
- package/dist/api/auto-sleep.js +7 -3
- package/dist/api/availability.js +2 -3
- package/dist/api/cards.d.ts +42 -0
- package/dist/api/cards.js +52 -0
- package/dist/api/conflicts.d.ts +28 -0
- package/dist/api/conflicts.js +61 -0
- package/dist/api/context-auto.js +4 -2
- package/dist/api/context-render.js +4 -3
- package/dist/api/context-select.js +15 -29
- package/dist/api/context.js +29 -18
- package/dist/api/continuity.d.ts +47 -0
- package/dist/api/continuity.js +66 -0
- package/dist/api/dormant.js +4 -2
- package/dist/api/drill-down.js +3 -2
- package/dist/api/embeddings.d.ts +17 -0
- package/dist/api/embeddings.js +28 -0
- package/dist/api/error-reply.d.ts +8 -0
- package/dist/api/error-reply.js +21 -0
- package/dist/api/forget.d.ts +7 -3
- package/dist/api/forget.js +24 -14
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/graph.js +2 -1
- package/dist/api/index.d.ts +4 -2
- package/dist/api/index.js +4 -2
- package/dist/api/instruction-detect.js +5 -1
- package/dist/api/learn.d.ts +5 -1
- package/dist/api/learn.js +71 -44
- package/dist/api/ledger-db.d.ts +2 -6
- package/dist/api/ledger-db.js +4 -36
- package/dist/api/memories.d.ts +21 -1
- package/dist/api/memories.js +51 -1
- package/dist/api/objects.d.ts +1 -1
- package/dist/api/objects.js +2 -1
- package/dist/api/outcome.d.ts +5 -5
- package/dist/api/outcome.js +17 -16
- package/dist/api/pilot-arm.d.ts +1 -11
- package/dist/api/pilot-arm.js +5 -45
- package/dist/api/predictions.d.ts +3 -1
- package/dist/api/predictions.js +8 -1
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.d.ts +3 -3
- package/dist/api/promote.js +26 -28
- package/dist/api/prompt-hook.d.ts +17 -2
- package/dist/api/prompt-hook.js +45 -4
- package/dist/api/quarantine.js +2 -1
- package/dist/api/recall-cli.d.ts +3 -0
- package/dist/api/recall-cli.js +13 -4
- package/dist/api/recall-core.js +10 -5
- package/dist/api/recall-pipeline.js +23 -24
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall-types.d.ts +3 -1
- package/dist/api/recall.d.ts +0 -3
- package/dist/api/recall.js +51 -73
- package/dist/api/remember-local.d.ts +5 -2
- package/dist/api/remember-local.js +15 -7
- package/dist/api/remember.d.ts +7 -3
- package/dist/api/remember.js +19 -16
- package/dist/api/session-end.d.ts +46 -0
- package/dist/api/session-end.js +131 -0
- package/dist/api/sleep-run.d.ts +1 -1
- package/dist/api/sleep-run.js +16 -11
- package/dist/api/sleep.js +4 -3
- package/dist/api/status.d.ts +24 -0
- package/dist/api/status.js +40 -0
- package/dist/api/store-init.d.ts +4 -0
- package/dist/api/store-init.js +9 -0
- package/dist/api/tokens.js +2 -2
- package/dist/api/types.d.ts +3 -7
- package/dist/api/types.js +6 -1
- package/dist/capture/caller-session.d.ts +0 -3
- package/dist/capture/caller-session.js +1 -12
- package/dist/capture/capture-error.d.ts +2 -2
- package/dist/capture/capture-error.js +23 -18
- package/dist/capture/codex-patch.js +3 -1
- package/dist/capture/command.js +36 -95
- package/dist/capture/compact.js +10 -5
- package/dist/capture/compaction-items-caller.js +11 -20
- package/dist/capture/compaction-record.d.ts +7 -93
- package/dist/capture/compaction-record.js +29 -426
- package/dist/capture/compaction-spool.d.ts +7 -7
- package/dist/capture/compaction-spool.js +60 -51
- package/dist/capture/copilot-transcript.d.ts +2 -1
- package/dist/capture/copilot-transcript.js +2 -1
- package/dist/capture/extract.d.ts +5 -2
- package/dist/capture/extract.js +4 -3
- package/dist/capture/failure-caller.d.ts +1 -1
- package/dist/capture/failure-caller.js +21 -16
- package/dist/capture/failure-reading.d.ts +2 -1
- package/dist/capture/failure-reading.js +7 -9
- package/dist/capture/pre-compact-caller.js +5 -4
- package/dist/capture/session-digest.js +4 -3
- package/dist/capture/session-end-caller.js +3 -2
- package/dist/capture/session-worker.js +22 -10
- package/dist/capture/transcript.d.ts +2 -1
- package/dist/capture/transcript.js +6 -3
- package/dist/capture/working-state.d.ts +4 -2
- package/dist/capture/working-state.js +4 -2
- package/dist/cli/audit-prune.d.ts +0 -25
- package/dist/cli/audit-prune.js +1 -27
- package/dist/cli/audit.js +20 -20
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +16 -17
- package/dist/cli/briefs.d.ts +1 -4
- package/dist/cli/briefs.js +37 -292
- package/dist/cli/card.js +41 -33
- package/dist/cli/client.d.ts +6 -2
- package/dist/cli/client.js +37 -21
- package/dist/cli/compact-resume-payload.js +1 -1
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +13 -13
- package/dist/cli/continuity.d.ts +1 -1
- package/dist/cli/continuity.js +36 -39
- package/dist/cli/curate.d.ts +2 -2
- package/dist/cli/curate.js +32 -36
- package/dist/cli/dag.d.ts +1 -1
- package/dist/cli/dag.js +23 -8
- package/dist/cli/decisions.d.ts +0 -2
- package/dist/cli/decisions.js +7 -285
- package/dist/cli/eval.d.ts +1 -1
- package/dist/cli/eval.js +12 -13
- package/dist/cli/explain.d.ts +1 -1
- package/dist/cli/explain.js +21 -25
- package/dist/cli/flag-values.js +16 -6
- package/dist/cli/flags.d.ts +0 -289
- package/dist/cli/flags.js +3 -138
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.js +83 -0
- package/dist/cli/hook-runtime.d.ts +6 -6
- package/dist/cli/hook-runtime.js +9 -36
- package/dist/cli/incidents.d.ts +3 -0
- package/dist/cli/incidents.js +112 -0
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.js +28 -19
- package/dist/cli/install-steps.d.ts +2 -1
- package/dist/cli/install-steps.js +11 -3
- package/dist/cli/last-sleep.js +1 -1
- package/dist/cli/maintenance.d.ts +3 -3
- package/dist/cli/maintenance.js +29 -30
- package/dist/cli/notes.d.ts +2 -0
- package/dist/cli/notes.js +41 -0
- package/dist/cli/object-verbs.d.ts +2 -2
- package/dist/cli/object-verbs.js +4 -4
- package/dist/cli/open-browser.d.ts +14 -0
- package/dist/cli/open-browser.js +26 -0
- package/dist/cli/playbooks.d.ts +3 -4
- package/dist/cli/playbooks.js +126 -290
- package/dist/cli/predictions.d.ts +3 -0
- package/dist/cli/predictions.js +174 -0
- package/dist/cli/print.js +2 -1
- package/dist/cli/projects.js +30 -22
- package/dist/cli/quality-repair-once.d.ts +1 -1
- package/dist/cli/quality-repair-once.js +6 -5
- package/dist/cli/recall.js +13 -7
- package/dist/cli/refine-llm.js +18 -17
- package/dist/cli/remember.js +17 -17
- package/dist/cli/scheduler.js +2 -1
- package/dist/cli/serve.js +11 -6
- package/dist/cli/session-hooks.d.ts +1 -5
- package/dist/cli/session-hooks.js +89 -168
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +17 -10
- package/dist/cli/shared.d.ts +2 -6
- package/dist/cli/shared.js +9 -29
- package/dist/cli/sleep-render.js +6 -3
- package/dist/cli/sleep.js +6 -37
- package/dist/cli/status.d.ts +3 -3
- package/dist/cli/status.js +32 -35
- package/dist/cli/transfer.d.ts +3 -3
- package/dist/cli/transfer.js +64 -43
- package/dist/cli/usage.d.ts +1 -80
- package/dist/cli/usage.js +2 -696
- package/dist/cli/verb-row.d.ts +34 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +234 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +236 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +257 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +314 -0
- package/dist/cli/verbs.d.ts +81 -0
- package/dist/cli/verbs.js +7 -0
- package/dist/cli/versioned-verbs.d.ts +51 -0
- package/dist/cli/versioned-verbs.js +79 -0
- package/dist/cli.d.ts +1 -272
- package/dist/cli.js +24 -315
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +39 -4
- package/dist/connectors/github/backfill.js +12 -3
- package/dist/connectors/github/deletion.js +2 -1
- package/dist/connectors/github/dlq.js +31 -73
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +5 -29
- package/dist/connectors/github/tenant-routing.js +2 -1
- package/dist/connectors/github/webhook.d.ts +2 -1
- package/dist/connectors/github/webhook.js +35 -2
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +29 -0
- package/dist/connectors/slack/deletion.js +2 -1
- package/dist/connectors/slack/dlq.js +49 -71
- package/dist/connectors/slack/ingest.d.ts +2 -6
- package/dist/connectors/slack/ingest.js +4 -28
- package/dist/connectors/slack/tenant-routing.js +2 -1
- package/dist/connectors/slack/webhook.d.ts +2 -1
- package/dist/connectors/slack/webhook.js +2 -1
- package/dist/consolidate/conflicts.js +2 -2
- package/dist/consolidate/dag.js +29 -18
- package/dist/consolidate/dedupe.d.ts +7 -0
- package/dist/consolidate/dedupe.js +6 -4
- package/dist/consolidate/llm-passes.js +45 -19
- package/dist/consolidate/memory-value.js +3 -2
- package/dist/consolidate/merge.js +8 -8
- package/dist/consolidate/physics-pass.d.ts +6 -1
- package/dist/consolidate/physics-pass.js +26 -6
- package/dist/consolidate/replay.js +11 -4
- package/dist/consolidate/sleep.js +9 -6
- package/dist/consolidate/traces.js +5 -5
- package/dist/core/ablation.d.ts +10 -0
- package/dist/core/ablation.js +12 -0
- package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
- package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
- package/dist/core/ambient.d.ts +4 -0
- package/dist/core/ambient.js +39 -18
- package/dist/core/api-errors.d.ts +16 -0
- package/dist/core/api-errors.js +20 -0
- package/dist/core/card.js +3 -1
- package/dist/core/compaction-timing.d.ts +7 -0
- package/dist/core/compaction-timing.js +9 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +22 -18
- package/dist/core/cosine.d.ts +3 -0
- package/dist/core/cosine.js +19 -0
- package/dist/{store → core}/markdown.d.ts +1 -1
- package/dist/{store → core}/markdown.js +4 -4
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory.d.ts +14 -8
- package/dist/core/memory.js +35 -23
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +1 -1
- package/dist/core/physics.d.ts +3 -1
- package/dist/core/physics.js +23 -18
- package/dist/core/prediction.d.ts +3 -0
- package/dist/core/prediction.js +6 -0
- package/dist/core/project-identity.d.ts +3 -0
- package/dist/core/project-identity.js +12 -2
- package/dist/{store → core}/recall-scope.d.ts +1 -10
- package/dist/{store → core}/recall-scope.js +2 -19
- package/dist/core/search-types.d.ts +1 -1
- package/dist/dashboard/dashboard-actions.d.ts +2 -2
- package/dist/dashboard/dashboard-actions.js +5 -5
- package/dist/dashboard/dashboard-queries.js +2 -7
- package/dist/dashboard/dashboard-snapshot.js +1 -3
- package/dist/dashboard/dashboard.js +16 -5
- package/dist/db/busy.d.ts +2 -7
- package/dist/db/busy.js +21 -26
- package/dist/db/connect.d.ts +2 -2
- package/dist/db/connect.js +7 -7
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrate.js +14 -7
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/v11.js +1 -0
- package/dist/db/migrations/v14.js +1 -0
- package/dist/db/migrations/v55.d.ts +3 -0
- package/dist/db/migrations/v55.js +17 -0
- package/dist/db/open.d.ts +0 -2
- package/dist/db/open.js +6 -10
- package/dist/db/physics-state.d.ts +0 -4
- package/dist/db/physics-state.js +7 -33
- package/dist/db/request-stores.d.ts +1 -0
- package/dist/db/request-stores.js +2 -1
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.js +19 -5
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +18 -15
- package/dist/embeddings/local.d.ts +62 -0
- package/dist/embeddings/local.js +146 -0
- package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
- package/dist/{store/embeddings → embeddings}/provider.js +19 -25
- package/dist/embeddings/transformers.d.ts +26 -0
- package/dist/embeddings/transformers.js +89 -0
- package/dist/entry/session-text.d.ts +1 -1
- package/dist/entry/session-text.js +1 -1
- package/dist/entry/store-kit.d.ts +37 -0
- package/dist/entry/store-kit.js +25 -0
- package/dist/entry/testing.d.ts +6 -0
- package/dist/entry/testing.js +7 -0
- package/dist/eval/eval-suite.js +17 -11
- package/dist/eval/eval.js +1 -1
- package/dist/eval/judgment.js +12 -5
- package/dist/graph/extract.js +3 -3
- package/dist/graph/recall.js +1 -1
- package/dist/graph/view.js +13 -5
- package/dist/graph/write.d.ts +1 -1
- package/dist/graph/write.js +9 -9
- package/dist/hooks/codex-session.js +3 -2
- package/dist/hooks/codex-wrapper.js +2 -1
- package/dist/hooks/json-hooks.js +10 -4
- package/dist/hooks/opencode.js +8 -5
- package/dist/hooks/shared.d.ts +0 -6
- package/dist/hooks/shared.js +4 -15
- package/dist/importers/core.js +4 -4
- package/dist/importers/sources.js +5 -4
- package/dist/importers/vault.d.ts +1 -1
- package/dist/importers/vault.js +25 -23
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/learn/autolearn.d.ts +15 -3
- package/dist/learn/autolearn.js +38 -16
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +7 -5
- package/dist/learn/forward-claim-detector.js +4 -2
- package/dist/learn/invalidation.d.ts +2 -1
- package/dist/learn/invalidation.js +18 -9
- package/dist/mcp/admin-tools.d.ts +2 -2
- package/dist/mcp/admin-tools.js +27 -48
- package/dist/mcp/format.js +3 -2
- package/dist/mcp/framing.d.ts +1 -0
- package/dist/mcp/framing.js +1 -1
- package/dist/mcp/memory-tools.d.ts +1 -1
- package/dist/mcp/memory-tools.js +8 -9
- package/dist/mcp/protocol.d.ts +11 -7
- package/dist/mcp/protocol.js +25 -12
- package/dist/mcp/recall-tools.js +12 -9
- package/dist/mcp/request.js +22 -20
- package/dist/mcp/stdio.js +37 -16
- package/dist/mcp/tool-args.js +2 -1
- package/dist/mcp/tools.js +44 -21
- package/dist/objects/customer-notes.d.ts +2 -2
- package/dist/objects/decisions.d.ts +2 -2
- package/dist/objects/descriptor.d.ts +1 -1
- package/dist/objects/incidents.d.ts +2 -2
- package/dist/objects/lifecycle.d.ts +1 -1
- package/dist/objects/lifecycle.js +2 -1
- package/dist/objects/policies.d.ts +2 -2
- package/dist/objects/policies.js +2 -1
- package/dist/objects/processes.d.ts +2 -2
- package/dist/objects/project-briefs.d.ts +2 -2
- package/dist/objects/project-briefs.js +2 -3
- package/dist/objects/skills.d.ts +2 -2
- package/dist/postinstall.js +1 -1
- package/dist/rerankers/clef.js +3 -6
- package/dist/rerankers/cross-encoder.d.ts +31 -2
- package/dist/rerankers/cross-encoder.js +71 -98
- package/dist/rerankers/index.js +5 -4
- package/dist/rerankers/jev.js +2 -4
- package/dist/rerankers/outage-warning.d.ts +3 -1
- package/dist/rerankers/outage-warning.js +5 -3
- package/dist/search/bm25-search.js +1 -1
- package/dist/search/boosts.js +1 -1
- package/dist/search/embed-memories.d.ts +12 -0
- package/dist/search/embed-memories.js +389 -0
- package/dist/search/engine.d.ts +8 -0
- package/dist/search/engine.js +10 -0
- package/dist/search/goal-boost.d.ts +1 -1
- package/dist/search/goal-boost.js +6 -3
- package/dist/search/hybrid.d.ts +9 -2
- package/dist/search/hybrid.js +9 -4
- package/dist/search/physics-search.d.ts +6 -3
- package/dist/search/physics-search.js +22 -15
- package/dist/search/rerank.js +1 -1
- package/dist/search/vector.d.ts +8 -6
- package/dist/search/vector.js +14 -17
- package/dist/server/auth.d.ts +3 -1
- package/dist/server/auth.js +24 -15
- package/dist/server/boot.d.ts +2 -1
- package/dist/server/boot.js +34 -84
- package/dist/server/client-ip.d.ts +9 -6
- package/dist/server/client-ip.js +36 -17
- package/dist/server/deadline.d.ts +0 -2
- package/dist/server/deadline.js +1 -7
- package/dist/server/defaults.d.ts +1 -0
- package/dist/server/defaults.js +1 -0
- package/dist/server/mcp-http.js +16 -11
- package/dist/server/request.js +7 -2
- package/dist/server/route-checks.d.ts +7 -0
- package/dist/server/route-checks.js +42 -0
- package/dist/server/route-table.d.ts +9 -8
- package/dist/server/route-table.js +127 -133
- package/dist/server/routes/admin.d.ts +8 -8
- package/dist/server/routes/admin.js +13 -21
- package/dist/server/routes/customer-notes.d.ts +6 -6
- package/dist/server/routes/customer-notes.js +1 -2
- package/dist/server/routes/decisions.d.ts +6 -6
- package/dist/server/routes/decisions.js +2 -4
- package/dist/server/routes/incidents.d.ts +6 -6
- package/dist/server/routes/incidents.js +2 -5
- package/dist/server/routes/memories.d.ts +9 -9
- package/dist/server/routes/memories.js +19 -40
- package/dist/server/routes/object-routes.d.ts +6 -6
- package/dist/server/routes/object-routes.js +4 -7
- package/dist/server/routes/policies.d.ts +7 -7
- package/dist/server/routes/policies.js +2 -4
- package/dist/server/routes/predictions.d.ts +6 -6
- package/dist/server/routes/predictions.js +9 -13
- package/dist/server/routes/processes.d.ts +6 -6
- package/dist/server/routes/processes.js +1 -2
- package/dist/server/routes/project-briefs.d.ts +7 -7
- package/dist/server/routes/project-briefs.js +2 -4
- package/dist/server/routes/recall.d.ts +5 -5
- package/dist/server/routes/recall.js +6 -10
- package/dist/server/routes/skills.d.ts +7 -7
- package/dist/server/routes/skills.js +2 -4
- package/dist/server/server-detect.d.ts +7 -1
- package/dist/server/server-detect.js +36 -11
- package/dist/server/sleep-child.js +26 -7
- package/dist/server/sleep-offload.d.ts +11 -5
- package/dist/server/sleep-offload.js +17 -11
- package/dist/server/tls.d.ts +7 -2
- package/dist/server/tls.js +17 -5
- package/dist/server/types.d.ts +29 -12
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +6 -11
- package/dist/server.d.ts +4 -40
- package/dist/server.js +3 -29
- package/dist/sharing/global-store.d.ts +4 -5
- package/dist/sharing/global-store.js +8 -13
- package/dist/sharing/global-sync.js +38 -45
- package/dist/sharing/project-merge.d.ts +7 -14
- package/dist/sharing/project-merge.js +57 -121
- package/dist/sharing/search-both.js +10 -3
- package/dist/sharing/share.d.ts +2 -0
- package/dist/sharing/share.js +39 -38
- package/dist/store/ambient.js +7 -7
- package/dist/store/audit-event.d.ts +1 -1
- package/dist/store/audit.d.ts +0 -16
- package/dist/store/audit.js +4 -55
- package/dist/store/auth.d.ts +4 -2
- package/dist/store/auth.js +7 -3
- package/dist/store/candidates.d.ts +3 -2
- package/dist/store/candidates.js +59 -30
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/cards.js +6 -5
- package/dist/store/compaction-caller.d.ts +18 -0
- package/dist/store/compaction-caller.js +29 -0
- package/dist/store/compactions-record.d.ts +115 -0
- package/dist/store/compactions-record.js +418 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.d.ts +7 -1
- package/dist/store/conflicts.js +13 -9
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +33 -0
- package/dist/store/connectors/event-log.d.ts +13 -0
- package/dist/store/connectors/event-log.js +24 -0
- package/dist/store/connectors/github.d.ts +7 -9
- package/dist/store/connectors/github.js +35 -60
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +24 -57
- package/dist/store/dashboard-reads.js +8 -6
- package/dist/store/delete-and-batch.d.ts +6 -0
- package/dist/store/delete-and-batch.js +40 -6
- package/dist/store/delivery-recorder.d.ts +12 -5
- package/dist/store/delivery-recorder.js +13 -11
- package/dist/store/descendant-page.js +8 -4
- package/dist/store/dormant.d.ts +1 -1
- package/dist/store/dormant.js +10 -4
- package/dist/store/embeddings/index.d.ts +2 -12
- package/dist/store/embeddings/index.js +5 -374
- package/dist/store/entry-reads.d.ts +35 -4
- package/dist/store/entry-reads.js +86 -19
- package/dist/store/entry-row.js +9 -2
- package/dist/store/entry-writes.d.ts +15 -12
- package/dist/store/entry-writes.js +54 -22
- package/dist/store/failure-log-at.d.ts +8 -0
- package/dist/store/failure-log-at.js +16 -0
- package/dist/store/failure-log.d.ts +2 -2
- package/dist/store/failure-log.js +5 -3
- package/dist/{trust → store}/gated-write.d.ts +3 -1
- package/dist/{trust → store}/gated-write.js +7 -5
- package/dist/store/goals.js +22 -19
- package/dist/store/graph-reads.js +9 -6
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +6 -6
- package/dist/store/graph-writes.js +48 -71
- package/dist/store/half-life.js +2 -2
- package/dist/store/handoffs.d.ts +10 -4
- package/dist/store/handoffs.js +10 -9
- package/dist/store/index-and-stats.js +2 -2
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +1 -1
- package/dist/store/key-writes.js +1 -1
- package/dist/store/ledger-turn.d.ts +9 -0
- package/dist/store/ledger-turn.js +38 -0
- package/dist/store/mirrors.js +19 -10
- package/dist/store/open.d.ts +2 -5
- package/dist/store/open.js +42 -54
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/port.d.ts +68 -6
- package/dist/store/port.js +8 -0
- package/dist/store/predictions.d.ts +1 -2
- package/dist/store/predictions.js +3 -6
- package/dist/store/project-tags.d.ts +62 -0
- package/dist/store/project-tags.js +67 -0
- package/dist/store/quality-repair.js +1 -1
- package/dist/store/quarantine.js +2 -1
- package/dist/store/recall-trace.d.ts +2 -0
- package/dist/store/recall-trace.js +20 -3
- package/dist/store/rejected-values.js +16 -10
- package/dist/store/rejection-probe.d.ts +4 -0
- package/dist/store/rejection-probe.js +19 -0
- package/dist/store/rejection.d.ts +0 -17
- package/dist/store/rejection.js +1 -21
- package/dist/store/rows.js +2 -2
- package/dist/store/rule-sql.d.ts +11 -0
- package/dist/store/rule-sql.js +31 -6
- package/dist/store/search-rows.d.ts +5 -5
- package/dist/store/search-rows.js +18 -16
- package/dist/store/sessions.js +4 -2
- package/dist/store/set-aside.d.ts +14 -0
- package/dist/store/set-aside.js +23 -0
- package/dist/store/sqlite/busy.d.ts +3 -0
- package/dist/store/sqlite/busy.js +8 -0
- package/dist/store/sqlite/connector-events-group.js +4 -7
- package/dist/store/sqlite/connector-writes-group.js +6 -4
- package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
- package/dist/store/sqlite/entry-writes-group.js +3 -3
- package/dist/store/sqlite/error-codec.js +4 -3
- package/dist/store/sqlite/executor.js +10 -4
- package/dist/store/sqlite/graph-reads-group.js +1 -1
- package/dist/store/sqlite/held-connection.d.ts +11 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/last-recall-group.d.ts +13 -0
- package/dist/store/sqlite/last-recall-group.js +57 -0
- package/dist/store/sqlite/local.d.ts +0 -17
- package/dist/store/sqlite/local.js +0 -31
- package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
- package/dist/store/sqlite/maintenance-groups.js +60 -0
- package/dist/store/sqlite/object-rows.d.ts +1 -1
- package/dist/store/sqlite/objects-group.d.ts +1 -1
- package/dist/store/sqlite/objects-group.js +15 -7
- package/dist/store/sqlite/store.d.ts +1 -8
- package/dist/store/sqlite/store.js +13 -22
- package/dist/store/summaries.d.ts +10 -3
- package/dist/store/summaries.js +54 -11
- package/dist/store/token-ledger-rows.js +3 -2
- package/dist/store/token-ledger.d.ts +0 -7
- package/dist/store/token-ledger.js +0 -35
- package/dist/store/vector-index.js +8 -4
- package/dist/support-bundle.js +2 -3
- package/dist/trust/reject-flow.js +2 -2
- package/dist/util/agent-homes.d.ts +15 -0
- package/dist/util/agent-homes.js +34 -0
- package/dist/util/anthropic-messages.d.ts +6 -1
- package/dist/util/anthropic-messages.js +26 -7
- package/dist/util/atomic-write.d.ts +5 -2
- package/dist/util/atomic-write.js +12 -8
- package/dist/util/chunked.d.ts +3 -0
- package/dist/util/chunked.js +10 -0
- package/dist/util/ellipsize.d.ts +3 -0
- package/dist/util/ellipsize.js +5 -0
- package/dist/util/env.d.ts +12 -2
- package/dist/util/env.js +12 -2
- package/dist/util/format.d.ts +5 -0
- package/dist/util/format.js +10 -0
- package/dist/util/hook-payload.d.ts +8 -0
- package/dist/util/hook-payload.js +37 -0
- package/dist/util/http-retry.d.ts +6 -0
- package/dist/util/http-retry.js +43 -5
- package/dist/util/http-util.d.ts +0 -8
- package/dist/util/http-util.js +10 -21
- package/dist/util/limits.d.ts +7 -0
- package/dist/util/limits.js +14 -0
- package/dist/util/log.d.ts +4 -0
- package/dist/util/log.js +9 -0
- package/dist/util/request-scope.d.ts +9 -3
- package/dist/util/request-scope.js +18 -9
- package/dist/util/secret-detect.js +6 -1
- package/dist/util/spawn-argv.d.ts +9 -0
- package/dist/util/spawn-argv.js +57 -0
- package/dist/util/sql.d.ts +3 -0
- package/dist/util/sql.js +6 -0
- package/dist/util/sqlite-blocked.d.ts +2 -0
- package/dist/util/sqlite-blocked.js +5 -0
- package/dist/util/stream-tee.d.ts +3 -0
- package/dist/util/stream-tee.js +35 -0
- package/dist/util/time.d.ts +4 -0
- package/dist/util/time.js +4 -0
- package/dist/util/vector-codec.d.ts +4 -0
- package/dist/util/vector-codec.js +15 -0
- package/dist/util/version.d.ts +1 -1
- package/dist/util/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -2
- package/dist/api/on-store.d.ts +0 -16
- package/dist/api/on-store.js +0 -38
- package/dist/store/embeddings/local.d.ts +0 -15
- package/dist/store/embeddings/local.js +0 -175
- /package/dist/{cli → api}/correction-latency.d.ts +0 -0
- /package/dist/{cli → api}/correction-latency.js +0 -0
- /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
- /package/dist/{cli → api}/provenance-coverage.js +0 -0
- /package/dist/{store → core}/object-types.d.ts +0 -0
- /package/dist/{store → core}/object-types.js +0 -0
- /package/dist/{capture → util}/compaction-items.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.js +0 -0
- /package/dist/{store → util}/yaml.d.ts +0 -0
- /package/dist/{store → util}/yaml.js +0 -0
package/dist/core/memory.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { DEFAULT_TENANT_ID, envLossAversionRatio } from '../util/env.js';
|
|
3
3
|
import { BadRequestError } from './api-errors.js';
|
|
4
4
|
import { randomUUID } from 'crypto';
|
|
5
|
-
import {
|
|
5
|
+
import { evalNow, NO_STRENGTH_ABLATION } from './ablation.js';
|
|
6
6
|
import { AGENT_MEMORY_TOOLS, toolSourcePrefix } from './agent-memory-tools.js';
|
|
7
7
|
import { isJsonString } from '../util/json.js';
|
|
8
8
|
import { DAY_MS } from '../util/time.js';
|
|
@@ -16,6 +16,7 @@ export var Layer;
|
|
|
16
16
|
Layer["Semantic"] = "semantic";
|
|
17
17
|
Layer["Trace"] = "trace";
|
|
18
18
|
})(Layer || (Layer = {}));
|
|
19
|
+
export const MEMORY_KINDS = ['raw', 'distilled', 'superseded', 'archived'];
|
|
19
20
|
/** Tag on a memory whose named file/symbol/script changed after it was stored. */
|
|
20
21
|
export const CHURN_STALE_TAG = 'churn-stale';
|
|
21
22
|
// Losses weigh ~2x gains (Lovallo-Kahneman), so negative is 2.0; HIPPO_LOSS_AVERSION_RATIO scales it per process.
|
|
@@ -57,9 +58,9 @@ export function applyLossAversionRatio(valence, baseMultiplier) {
|
|
|
57
58
|
return baseMultiplier * getLossAversionRatio();
|
|
58
59
|
}
|
|
59
60
|
/** 1 + REWARD_SLOPE * (pos - neg) / (pos + neg + 1), in (0.5, 1.5), 1.0 with no outcomes; it scales the effective half-life. */
|
|
60
|
-
export function calculateRewardFactor(entry) {
|
|
61
|
+
export function calculateRewardFactor(entry, ablation = NO_STRENGTH_ABLATION) {
|
|
61
62
|
// EVAL-ONLY ablation (see ablation.ts): the slow outcome channel.
|
|
62
|
-
if (
|
|
63
|
+
if (ablation.outcomeSlow)
|
|
63
64
|
return 1.0;
|
|
64
65
|
const pos = entry.outcome_positive ?? 0;
|
|
65
66
|
const neg = entry.outcome_negative ?? 0;
|
|
@@ -75,8 +76,8 @@ export const DECAY_BASE = 0.5;
|
|
|
75
76
|
export const REWARD_SLOPE = 0.5;
|
|
76
77
|
export const RETRIEVAL_BOOST_SLOPE = 0.1;
|
|
77
78
|
/** Bad outcome marks past good ones, floored at zero; each halves strength and stops recall strengthening, so a correction outranks pinning. */
|
|
78
|
-
export function netWrong(entry) {
|
|
79
|
-
if (
|
|
79
|
+
export function netWrong(entry, ablation = NO_STRENGTH_ABLATION) {
|
|
80
|
+
if (ablation.outcomeSlow || ablation.decay)
|
|
80
81
|
return 0;
|
|
81
82
|
return Math.max(0, (entry.outcome_negative ?? 0) - (entry.outcome_positive ?? 0));
|
|
82
83
|
}
|
|
@@ -85,22 +86,23 @@ export function netWrong(entry) {
|
|
|
85
86
|
export function calculateStrength(entry,
|
|
86
87
|
// evalNow() is the real clock unless HIPPO_FAKE_NOW is set (eval-only); an explicit `now` wins.
|
|
87
88
|
now = evalNow(), options = {}) {
|
|
89
|
+
const ablation = options.ablation ?? NO_STRENGTH_ABLATION;
|
|
88
90
|
// Being marked wrong outranks every shield: pinning, error tags, heavy recall.
|
|
89
|
-
const wrongPenalty = Math.pow(DECAY_BASE, Math.min(netWrong(entry), MAX_WRONG_HALVINGS));
|
|
91
|
+
const wrongPenalty = Math.pow(DECAY_BASE, Math.min(netWrong(entry, ablation), MAX_WRONG_HALVINGS));
|
|
90
92
|
if (entry.pinned)
|
|
91
93
|
return wrongPenalty;
|
|
92
94
|
// EVAL-ONLY ablation (see ablation.ts): anchor decay at creation so clock resets from earlier unflagged runs cannot leak in.
|
|
93
|
-
const lastRetrieved = new Date(
|
|
95
|
+
const lastRetrieved = new Date(ablation.recallBoost ? entry.created : entry.last_retrieved);
|
|
94
96
|
const daysSince = (now.getTime() - lastRetrieved.getTime()) / DAY_MS;
|
|
95
|
-
const rewardFactor = calculateRewardFactor(entry);
|
|
97
|
+
const rewardFactor = calculateRewardFactor(entry, ablation);
|
|
96
98
|
const effectiveHalfLife = entry.half_life_days * rewardFactor;
|
|
97
99
|
// Guard: zero half-life causes 0/0 = NaN in the exponent
|
|
98
100
|
if (effectiveHalfLife <= 0)
|
|
99
101
|
return 0.0;
|
|
100
102
|
const decayExponent = decayExponentFor(options, daysSince, effectiveHalfLife);
|
|
101
103
|
// EVAL-ONLY ablation (see ablation.ts): decay := 1, so the [0,1] clamp below caps the boost at baseline.
|
|
102
|
-
const decay =
|
|
103
|
-
const retrievalBoost = retrievalBoostFor(entry);
|
|
104
|
+
const decay = ablation.decay ? 1.0 : Math.pow(DECAY_BASE, decayExponent);
|
|
105
|
+
const retrievalBoost = retrievalBoostFor(entry, ablation);
|
|
104
106
|
const baseMultiplier = EMOTIONAL_MULTIPLIERS[entry.emotional_valence] ?? 1.0;
|
|
105
107
|
const emotionalMultiplier = applyLossAversionRatio(entry.emotional_valence, baseMultiplier);
|
|
106
108
|
const raw = decay * retrievalBoost * emotionalMultiplier;
|
|
@@ -127,8 +129,8 @@ function decayExponentFor(options, daysSince, halfLifeDays) {
|
|
|
127
129
|
return daysSince / effectiveHalfLife;
|
|
128
130
|
}
|
|
129
131
|
// EVAL-ONLY ablation (see ablation.ts) neutralizes the read side too, so counts written before the flag cannot leak in.
|
|
130
|
-
function retrievalBoostFor(entry) {
|
|
131
|
-
return
|
|
132
|
+
function retrievalBoostFor(entry, ablation) {
|
|
133
|
+
return ablation.recallBoost || netWrong(entry, ablation) > 0
|
|
132
134
|
? 1.0
|
|
133
135
|
: 1 + RETRIEVAL_BOOST_SLOPE * Math.log2(entry.retrieval_count + 1);
|
|
134
136
|
}
|
|
@@ -259,7 +261,7 @@ export function createMemory(content, options = {}) {
|
|
|
259
261
|
scope: options.scope ?? null,
|
|
260
262
|
owner: options.owner ?? null,
|
|
261
263
|
artifact_ref: options.artifact_ref ?? null,
|
|
262
|
-
|
|
264
|
+
tenant_id: options.tenantId ?? DEFAULT_TENANT_ID,
|
|
263
265
|
};
|
|
264
266
|
entry.strength = calculateStrength(entry);
|
|
265
267
|
return entry;
|
|
@@ -296,16 +298,26 @@ export function createSuccessor(old, content, opts) {
|
|
|
296
298
|
/** How well new content fits existing knowledge, 0..1: above 0.7 consolidates faster, below 0.3 is novel and decays faster if unused.
|
|
297
299
|
* Tags shared with existing memories count by rarity (a rare shared tag fits more), plus content-token overlap. */
|
|
298
300
|
export function computeSchemaFit(content, tags, existingEntries) {
|
|
301
|
+
return schemaFitFrom(content, tags, schemaFitSourceOf(existingEntries));
|
|
302
|
+
}
|
|
303
|
+
/** What schema fit reads from `entries`, built once for a caller that scores many contents against the same rows. */
|
|
304
|
+
export function schemaFitSourceOf(entries) {
|
|
299
305
|
const tagCounts = new Map();
|
|
300
|
-
for (const entry of
|
|
306
|
+
for (const entry of entries) {
|
|
301
307
|
for (const tag of entry.tags) {
|
|
302
308
|
tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);
|
|
303
309
|
}
|
|
304
310
|
}
|
|
305
|
-
return
|
|
311
|
+
return { rows: entries.length, tagCounts, contents: entries.map((e) => e.content) };
|
|
306
312
|
}
|
|
313
|
+
// Tokens of this length or shorter are filler for schema fit.
|
|
314
|
+
const FILLER_TOKEN_MAX_LENGTH = 3;
|
|
315
|
+
// Matching half the tags at average weight scores about 0.5, so the raw overlap ratio is doubled.
|
|
316
|
+
const TAG_OVERLAP_SCALE = 2;
|
|
317
|
+
// Floor on the matches that saturate the content score, so a tiny store cannot saturate it on one hit.
|
|
318
|
+
const CONTENT_ENOUGH_MIN_MATCHES = 5;
|
|
307
319
|
function significantTokens(text) {
|
|
308
|
-
return new Set(text.toLowerCase().replace(/[^\w\s]/g, ' ').split(/\s+/).filter((t) => t.length >
|
|
320
|
+
return new Set(text.toLowerCase().replace(/[^\w\s]/g, ' ').split(/\s+/).filter((t) => t.length > FILLER_TOKEN_MAX_LENGTH));
|
|
309
321
|
}
|
|
310
322
|
/** computeSchemaFit against `source`, for a caller that holds counts and texts but no rows. */
|
|
311
323
|
export function schemaFitFrom(content, tags, source) {
|
|
@@ -325,13 +337,12 @@ export function schemaFitFrom(content, tags, source) {
|
|
|
325
337
|
weightedOverlap += Math.log(N / freq) + 1;
|
|
326
338
|
totalWeight += maxIdf;
|
|
327
339
|
}
|
|
328
|
-
|
|
329
|
-
const tagScore = totalWeight > 0 ? Math.min(1, (weightedOverlap / totalWeight) * 2) : 0;
|
|
340
|
+
const tagScore = totalWeight > 0 ? Math.min(1, (weightedOverlap / totalWeight) * TAG_OVERLAP_SCALE) : 0;
|
|
330
341
|
const newTokens = significantTokens(content);
|
|
331
342
|
if (newTokens.size === 0)
|
|
332
343
|
return Math.min(1, Math.max(0, tagScore));
|
|
333
344
|
// The content score is capped at 1, which this many matching memories reach.
|
|
334
|
-
const enough = Math.max(
|
|
345
|
+
const enough = Math.max(CONTENT_ENOUGH_MIN_MATCHES, N * CONTENT_ENOUGH_FRACTION);
|
|
335
346
|
let contentMatches = 0;
|
|
336
347
|
for (const text of source.contents) {
|
|
337
348
|
const entryTokens = significantTokens(text);
|
|
@@ -358,13 +369,14 @@ function inferValence(tags) {
|
|
|
358
369
|
}
|
|
359
370
|
/** Returns copies with the retrieval count, clock and half-life updated; the caller persists them.
|
|
360
371
|
* Under HIPPO_ABLATE_RECALL_BOOST (eval-only) the entries come back unchanged, not empty, since callers derive last_retrieval_ids from them. */
|
|
361
|
-
export function markRetrieved(entries, now = evalNow()) {
|
|
362
|
-
|
|
372
|
+
export function markRetrieved(entries, now = evalNow(), options = {}) {
|
|
373
|
+
const ablation = options.ablation ?? NO_STRENGTH_ABLATION;
|
|
374
|
+
if (ablation.recallBoost)
|
|
363
375
|
return entries;
|
|
364
376
|
return entries.map((e) => {
|
|
365
377
|
if (e.superseded_by)
|
|
366
378
|
return e;
|
|
367
|
-
const wrong = netWrong(e) > 0;
|
|
379
|
+
const wrong = netWrong(e, ablation) > 0;
|
|
368
380
|
// Confidence stays untouched: it is an epistemic tier, not a recency signal.
|
|
369
381
|
const updated = {
|
|
370
382
|
...e,
|
|
@@ -373,7 +385,7 @@ export function markRetrieved(entries, now = evalNow()) {
|
|
|
373
385
|
last_retrieved: wrong ? e.last_retrieved : now.toISOString(),
|
|
374
386
|
half_life_days: wrong ? e.half_life_days : e.half_life_days + RETRIEVAL_HALF_LIFE_GAIN_DAYS,
|
|
375
387
|
};
|
|
376
|
-
updated.strength = calculateStrength(updated, now);
|
|
388
|
+
updated.strength = calculateStrength(updated, now, { ablation });
|
|
377
389
|
return updated;
|
|
378
390
|
});
|
|
379
391
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MemoryEntry } from '
|
|
1
|
+
import { type MemoryEntry } from './memory.js';
|
|
2
2
|
/** The row that replaces a merged row once its retired texts leave: undefined when it holds none, null when nothing else is left. */
|
|
3
3
|
export declare function mergedSuccessor(row: MemoryEntry, retired: (text: string) => boolean, retiredIds: ReadonlySet<string>): MemoryEntry | null | undefined;
|
|
4
4
|
/** Sleep's check on a merged row: drops texts whose source was superseded since the merge, or that a rejection now covers. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// A sleep-merged row copies its sources' texts, so retiring a text (reject, or superseding its source) must reach the row too.
|
|
2
2
|
// SHORTCUT: reject rewrites merged rows at once, live and dormant; supersede and `resolve
|
|
3
3
|
// --reject-loser` wait for the next sleep's check, which sees a dormant row only once restored.
|
|
4
|
-
import { generateId } from '
|
|
4
|
+
import { generateId } from './memory.js';
|
|
5
5
|
import { duplicateKey, heldTexts, mergedText } from '../util/same-text.js';
|
|
6
6
|
/** The row that replaces a merged row once its retired texts leave: undefined when it holds none, null when nothing else is left. */
|
|
7
7
|
export function mergedSuccessor(row, retired, retiredIds) {
|
package/dist/core/physics.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Memory-as-Physics engine: pure math (forces, Velocity Verlet integration, physics-based scoring, cluster amplification), no I/O.
|
|
2
2
|
* Memories are particles on the unit hypersphere in embedding space (384-dim); query gravity, attraction, conflict repulsion and drag act on them,
|
|
3
3
|
* and nearby high-scoring memories amplify each other. */
|
|
4
|
-
import { type EmotionalValence } from './memory.js';
|
|
4
|
+
import { type EmotionalValence, type MemoryEntry } from './memory.js';
|
|
5
5
|
import type { PhysicsConfig } from './physics-config.js';
|
|
6
6
|
export interface PhysicsParticle {
|
|
7
7
|
memoryId: string;
|
|
@@ -71,4 +71,6 @@ export declare function physicsScore(particles: PhysicsParticle[], queryEmbeddin
|
|
|
71
71
|
tieKeyOf?: (memoryId: string) => string): ScoredPhysicsResult[];
|
|
72
72
|
/** Nudges a particle toward (good outcome) or away from (bad outcome) the query embedding; new memories respond more (temperature). Mutates in place. */
|
|
73
73
|
export declare function applyOutcomeFeedback(particle: PhysicsParticle, queryEmbedding: number[], good: boolean, feedbackAlpha: number): void;
|
|
74
|
+
/** Initialize physics state for a memory from its embedding vector; returns the new particle without persisting (the caller must save). */
|
|
75
|
+
export declare function initializeParticle(entry: MemoryEntry, embedding: number[], now?: Date): PhysicsParticle;
|
|
74
76
|
//# sourceMappingURL=physics.d.ts.map
|
package/dist/core/physics.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/** Memory-as-Physics engine: pure math (forces, Velocity Verlet integration, physics-based scoring, cluster amplification), no I/O.
|
|
2
2
|
* Memories are particles on the unit hypersphere in embedding space (384-dim); query gravity, attraction, conflict repulsion and drag act on them,
|
|
3
3
|
* and nearby high-scoring memories amplify each other. */
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { cosineOf } from './cosine.js';
|
|
5
|
+
import { evalNow, isRecallBoostAblated, strengthAblation } from './ablation.js';
|
|
6
|
+
import { calculateStrength, FALLBACK_HALF_LIFE_DAYS } from './memory.js';
|
|
7
|
+
import { DAY_MS } from '../util/time.js';
|
|
6
8
|
import { comparePhysicsResultsBy } from './compare.js';
|
|
7
9
|
export function vecDot(a, b) {
|
|
8
10
|
let sum = 0;
|
|
@@ -48,17 +50,6 @@ export function vecClampMagnitude(v, maxMag) {
|
|
|
48
50
|
return v;
|
|
49
51
|
return vecScale(v, maxMag / mag);
|
|
50
52
|
}
|
|
51
|
-
/** Cosine similarity between two vectors. */
|
|
52
|
-
function cosine(a, b) {
|
|
53
|
-
if (a.length === 0 || b.length === 0 || a.length !== b.length)
|
|
54
|
-
return 0;
|
|
55
|
-
const dot = vecDot(a, b);
|
|
56
|
-
const na = vecNorm(a);
|
|
57
|
-
const nb = vecNorm(b);
|
|
58
|
-
if (na < 1e-10 || nb < 1e-10)
|
|
59
|
-
return 0;
|
|
60
|
-
return Math.min(1, Math.max(-1, dot / (na * nb)));
|
|
61
|
-
}
|
|
62
53
|
const CHARGE_MAP = {
|
|
63
54
|
neutral: 0,
|
|
64
55
|
positive: 0.3,
|
|
@@ -79,7 +70,7 @@ export function computeTemperature(ageDays, temperatureDecay) {
|
|
|
79
70
|
}
|
|
80
71
|
/** Query gravity (retrieval-time, virtual: does not move the particle): scalar ranking magnitude F = G_Q * mass * max(0, cosine(pos, query))^2. */
|
|
81
72
|
export function queryGravityMagnitude(particle, queryEmbedding, G_query) {
|
|
82
|
-
const cos =
|
|
73
|
+
const cos = cosineOf(particle.position, queryEmbedding);
|
|
83
74
|
return G_query * particle.mass * Math.pow(Math.max(0, cos), 2);
|
|
84
75
|
}
|
|
85
76
|
/** Momentum bonus in [0, 1]: how aligned the particle's velocity is with the query direction. */
|
|
@@ -96,7 +87,7 @@ export function velocityAlignmentBonus(particle, queryEmbedding) {
|
|
|
96
87
|
/** Attraction force on particle i from j (consolidation-time): G_M m_i m_j max(0, cosine)^3, directed along (pos_j - pos_i) projected tangent to the unit
|
|
97
88
|
* sphere at pos_i (positions are re-normalized to the sphere after integration). Adds into `out` (a fresh zero vector by default) using `diff` as scratch. */
|
|
98
89
|
export function attractionForce(pi, pj, G_memory, out = vecZero(pi.position.length), diff = vecZero(pi.position.length)) {
|
|
99
|
-
const cos =
|
|
90
|
+
const cos = cosineOf(pi.position, pj.position);
|
|
100
91
|
if (cos <= 0)
|
|
101
92
|
return out;
|
|
102
93
|
const magnitude = G_memory * pi.mass * pj.mass * Math.pow(cos, 3);
|
|
@@ -113,7 +104,7 @@ export function attractionForce(pi, pj, G_memory, out = vecZero(pi.position.leng
|
|
|
113
104
|
}
|
|
114
105
|
/** Conflict repulsion on i away from j (consolidation-time): K_R * m_i * m_j / max(0.01, cosine_distance)^2, where cosine_distance = 1 - cosine_similarity. */
|
|
115
106
|
export function repulsionForce(pi, pj, K_repulsion) {
|
|
116
|
-
const cos =
|
|
107
|
+
const cos = cosineOf(pi.position, pj.position);
|
|
117
108
|
const dist = Math.max(0.01, 1 - cos);
|
|
118
109
|
const magnitude = K_repulsion * pi.mass * pj.mass / (dist * dist);
|
|
119
110
|
// Direction: away from j
|
|
@@ -237,7 +228,7 @@ export function computeSystemEnergy(particles, G_memory) {
|
|
|
237
228
|
}
|
|
238
229
|
for (let i = 0; i < particles.length; i++) {
|
|
239
230
|
for (let j = i + 1; j < particles.length; j++) {
|
|
240
|
-
const cos =
|
|
231
|
+
const cos = cosineOf(particles[i].position, particles[j].position);
|
|
241
232
|
potential -= G_memory * particles[i].mass * particles[j].mass * Math.max(0, cos);
|
|
242
233
|
}
|
|
243
234
|
}
|
|
@@ -292,7 +283,7 @@ function applyClusterAmplification(results, particles, config) {
|
|
|
292
283
|
const pj = particleMap.get(top[j].memoryId);
|
|
293
284
|
if (!pj)
|
|
294
285
|
continue;
|
|
295
|
-
const proximity =
|
|
286
|
+
const proximity = cosineOf(pi.position, pj.position);
|
|
296
287
|
if (proximity > config.cluster_threshold) {
|
|
297
288
|
clusterSignal += top[j].baseScore * proximity;
|
|
298
289
|
}
|
|
@@ -311,4 +302,18 @@ export function applyOutcomeFeedback(particle, queryEmbedding, good, feedbackAlp
|
|
|
311
302
|
const nudge = vecScale(direction, sign * feedbackAlpha * particle.temperature);
|
|
312
303
|
particle.position = vecNormalize(vecAdd(particle.position, nudge));
|
|
313
304
|
}
|
|
305
|
+
/** Initialize physics state for a memory from its embedding vector; returns the new particle without persisting (the caller must save). */
|
|
306
|
+
export function initializeParticle(entry, embedding, now = evalNow()) {
|
|
307
|
+
const strength = calculateStrength(entry, now, { ablation: strengthAblation() });
|
|
308
|
+
const ageDays = (now.getTime() - new Date(entry.created).getTime()) / DAY_MS;
|
|
309
|
+
return {
|
|
310
|
+
memoryId: entry.id,
|
|
311
|
+
position: [...embedding], // copy: position will diverge from original embedding
|
|
312
|
+
velocity: vecZero(embedding.length),
|
|
313
|
+
mass: computeMass(strength, entry.retrieval_count),
|
|
314
|
+
charge: computeCharge(entry.emotional_valence),
|
|
315
|
+
temperature: computeTemperature(ageDays, 1.0),
|
|
316
|
+
lastSimulation: now.toISOString(),
|
|
317
|
+
};
|
|
318
|
+
}
|
|
314
319
|
//# sourceMappingURL=physics.js.map
|
|
@@ -27,6 +27,9 @@ export declare function resolveProjectIdentity(cwd?: string, opts?: ResolveProje
|
|
|
27
27
|
/** Nearest ancestor `.hippo` below home and the temp root (never projects; on Windows the temp root sits inside home).
|
|
28
28
|
* Everything is realpath'd so a symlinked temp root or cwd still matches its bound. */
|
|
29
29
|
export declare function findHippoStoreDir(cwd?: string, opts?: ResolveProjectIdentityOpts): string | null;
|
|
30
|
+
/** Nearest ancestor store like git; the strict join is the fallback so `hippo init` still creates `<cwd>/.hippo`. */
|
|
31
|
+
export declare function getHippoRoot(cwd?: string, opts?: ResolveProjectIdentityOpts): string;
|
|
32
|
+
export declare function isInitialized(hippoRoot: string): boolean;
|
|
30
33
|
/** A reader's project: a bare name, or an identity whose own rows may also carry its legacy folder name. */
|
|
31
34
|
export type ProjectRef = string | Pick<ProjectIdentity, 'name' | 'legacyName' | 'aliases'>;
|
|
32
35
|
/** The id a reader's new rows are stamped with; '' outside a project. */
|
|
@@ -4,10 +4,11 @@ import * as os from 'os';
|
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { BadRequestError } from './api-errors.js';
|
|
6
6
|
import { isSharedStore, loadConfig } from './config.js';
|
|
7
|
-
import { MAX_ID_LEN } from '../util/
|
|
7
|
+
import { MAX_ID_LEN } from '../util/limits.js';
|
|
8
8
|
import { errorMessage, log } from '../util/log.js';
|
|
9
9
|
import { originRemoteId, projectFileId } from './project-remote.js';
|
|
10
10
|
import { realpathOrResolve } from '../util/real-path.js';
|
|
11
|
+
import { placeholders } from '../util/sql.js';
|
|
11
12
|
const MAX_WALK_DEPTH = 64;
|
|
12
13
|
const identityCache = new Map();
|
|
13
14
|
let remoteSwitch = null;
|
|
@@ -154,6 +155,15 @@ export function findHippoStoreDir(cwd, opts) {
|
|
|
154
155
|
const { hippoRoot } = walkProjectMarkers(start, home, stops);
|
|
155
156
|
return hippoRoot === null ? null : path.join(hippoRoot, '.hippo');
|
|
156
157
|
}
|
|
158
|
+
/** Nearest ancestor store like git; the strict join is the fallback so `hippo init` still creates `<cwd>/.hippo`. */
|
|
159
|
+
export function getHippoRoot(cwd = process.cwd(), opts) {
|
|
160
|
+
return findHippoStoreDir(cwd, opts) ?? path.join(realpathOrResolve(cwd), '.hippo');
|
|
161
|
+
}
|
|
162
|
+
export function isInitialized(hippoRoot) {
|
|
163
|
+
// autoInstallHooks / setupDailySchedule can create a bare .hippo with no hippo.db; counting
|
|
164
|
+
// that as initialized makes `hippo init` skip initStore, so only hippo.db counts.
|
|
165
|
+
return fs.existsSync(path.join(hippoRoot, 'hippo.db'));
|
|
166
|
+
}
|
|
157
167
|
function isBareName(project) {
|
|
158
168
|
return typeof project === 'string';
|
|
159
169
|
}
|
|
@@ -187,7 +197,7 @@ export function assertCallerProject(project) {
|
|
|
187
197
|
}
|
|
188
198
|
/** `origin_project IN (?, ...)` with one placeholder per name; an empty list matches nothing. */
|
|
189
199
|
export function originInSql(names, column = 'origin_project') {
|
|
190
|
-
return names.length === 0 ? '0' : `${column} IN (${names.
|
|
200
|
+
return names.length === 0 ? '0' : `${column} IN (${placeholders(names.length)})`;
|
|
191
201
|
}
|
|
192
202
|
/** Classifies a memory's origin_project against the active project. An empty current id (home or markerless cwd) puts everything in scope;
|
|
193
203
|
* NULL/undefined origin (legacy row, or a shared-store write naming none) counts as cross-project: deny by default for a security partition. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Recall-side scope predicates, in a leaf module so search-both.ts can apply the same default-deny rule to searchBothHybrid's candidate loads without an
|
|
2
2
|
* import cycle. src/api/index.ts imports these and re-exports them for back-compat (`api.isPrivateScope`, tests importing `passesScopeFilterForRecall`). */
|
|
3
|
-
import { ForbiddenError } from '
|
|
3
|
+
import { ForbiddenError } from './api-errors.js';
|
|
4
4
|
/** Literal scopes excluded from recall by default-deny when the caller passes no `scope`; read by the SQL clause in `loadSearchRows` and by
|
|
5
5
|
* `passesScopeFilterForRecall`. Invariant: never empty, or quarantine scopes would pass both paths silently (the module-load assertion below pins this). */
|
|
6
6
|
export declare const RECALL_DEFAULT_DENY_SCOPES: readonly ["unknown:legacy"];
|
|
@@ -31,15 +31,6 @@ export declare function ownScopeTouches(ownScope: string | null, scope: string |
|
|
|
31
31
|
/** JS half of the recall default-deny rule (SQL half: `loadSearchRows`). A non-empty `requested` needs an exact match;
|
|
32
32
|
* otherwise `<source>:private:*` and `RECALL_DEFAULT_DENY_SCOPES` buckets are denied, while null, public scopes and the caller's `ownScope` pass. */
|
|
33
33
|
export declare function passesScopeFilterForRecall(scope: string | null, requested: string | undefined, ownScope?: string | null): boolean;
|
|
34
|
-
export interface SqlFragment {
|
|
35
|
-
sql: string;
|
|
36
|
-
params: string[];
|
|
37
|
-
}
|
|
38
|
-
/** SQL twin of the no-request arm of passesScopeFilterForRecall; `ownScope` is bound and compared with `=`, so `%` or `_` in an owner match nothing extra. */
|
|
39
|
-
export declare function scopeAdmitSql(col: '' | 'm.', ownScope?: string | null): SqlFragment;
|
|
40
|
-
/** SQL twin of canTouchScope, which is also canReadScope for an admin: every row but
|
|
41
|
-
* another person's personal one. LIKE folds ASCII case as isPersonalScope's /i does. */
|
|
42
|
-
export declare function touchableScopeSql(col: '' | 'm.', ownScope?: string | null): SqlFragment;
|
|
43
34
|
/** CLI `--scope` variant: an explicit `--scope X` UNLOCKS scope X on top of the default-admitted set rather than narrowing to X (api.recall keeps 'exact').
|
|
44
35
|
* Includes private/quarantine scopes (owner access); a named personal scope never unlocks: the CLI has no caller identity. */
|
|
45
36
|
export declare function passesCliRecallScopeFilter(scope: string | null, requested: string | undefined): boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Recall-side scope predicates, in a leaf module so search-both.ts can apply the same default-deny rule to searchBothHybrid's candidate loads without an
|
|
2
2
|
* import cycle. src/api/index.ts imports these and re-exports them for back-compat (`api.isPrivateScope`, tests importing `passesScopeFilterForRecall`). */
|
|
3
|
-
import { BadRequestError, ForbiddenError } from '
|
|
4
|
-
import { MAX_ID_LEN } from '../util/
|
|
3
|
+
import { BadRequestError, ForbiddenError } from './api-errors.js';
|
|
4
|
+
import { MAX_ID_LEN } from '../util/limits.js';
|
|
5
5
|
/** Literal scopes excluded from recall by default-deny when the caller passes no `scope`; read by the SQL clause in `loadSearchRows` and by
|
|
6
6
|
* `passesScopeFilterForRecall`. Invariant: never empty, or quarantine scopes would pass both paths silently (the module-load assertion below pins this). */
|
|
7
7
|
export const RECALL_DEFAULT_DENY_SCOPES = ['unknown:legacy'];
|
|
@@ -63,23 +63,6 @@ export function passesScopeFilterForRecall(scope, requested, ownScope) {
|
|
|
63
63
|
}
|
|
64
64
|
return !isRestrictedScope(scope) || (ownScope != null && scope === ownScope);
|
|
65
65
|
}
|
|
66
|
-
/** SQL twin of the no-request arm of passesScopeFilterForRecall; `ownScope` is bound and compared with `=`, so `%` or `_` in an owner match nothing extra. */
|
|
67
|
-
export function scopeAdmitSql(col, ownScope) {
|
|
68
|
-
const placeholders = RECALL_DEFAULT_DENY_SCOPES.map(() => '?').join(', ');
|
|
69
|
-
const admitted = `${col}scope IS NULL OR (${col}scope NOT IN (${placeholders}) AND ${col}scope NOT LIKE '%:private:%')`;
|
|
70
|
-
if (ownScope == null)
|
|
71
|
-
return { sql: `(${admitted})`, params: [...RECALL_DEFAULT_DENY_SCOPES] };
|
|
72
|
-
// The own arm sits inside the outer parentheses so a caller's `AND ${sql}` cannot split it off.
|
|
73
|
-
return { sql: `(${admitted} OR ${col}scope = ?)`, params: [...RECALL_DEFAULT_DENY_SCOPES, ownScope] };
|
|
74
|
-
}
|
|
75
|
-
/** SQL twin of canTouchScope, which is also canReadScope for an admin: every row but
|
|
76
|
-
* another person's personal one. LIKE folds ASCII case as isPersonalScope's /i does. */
|
|
77
|
-
export function touchableScopeSql(col, ownScope) {
|
|
78
|
-
const notPersonal = `${col}scope IS NULL OR ${col}scope NOT LIKE '${PERSONAL_SCOPE_PREFIX}%'`;
|
|
79
|
-
if (ownScope == null)
|
|
80
|
-
return { sql: `(${notPersonal})`, params: [] };
|
|
81
|
-
return { sql: `(${notPersonal} OR ${col}scope = ?)`, params: [ownScope] };
|
|
82
|
-
}
|
|
83
66
|
/** CLI `--scope` variant: an explicit `--scope X` UNLOCKS scope X on top of the default-admitted set rather than narrowing to X (api.recall keeps 'exact').
|
|
84
67
|
* Includes private/quarantine scopes (owner access); a named personal scope never unlocks: the CLI has no caller identity. */
|
|
85
68
|
export function passesCliRecallScopeFilter(scope, requested) {
|
|
@@ -63,7 +63,7 @@ export interface ScoreBreakdown {
|
|
|
63
63
|
scopeBoost: number;
|
|
64
64
|
/** Extra multiplier applied post-hybrid (e.g. 1.2x for local hits in a local+global merge); 1.0 otherwise. */
|
|
65
65
|
sourceBump: number;
|
|
66
|
-
/** Immediate outcome nudge, 1 + 0.15*tanh(pos - neg) clipped to [0.85, 1.15]; separate from the slow strength path. */
|
|
66
|
+
/** Immediate outcome nudge, 1 + 0.15*tanh((pos - neg) / 2) clipped to [0.85, 1.15]; separate from the slow strength path. */
|
|
67
67
|
outcomeBoost: number;
|
|
68
68
|
/** CHURN_STALE_RANK_MULTIPLIER if tagged 'churn-stale', else 1.0. */
|
|
69
69
|
churnStaleMultiplier: number;
|
|
@@ -12,9 +12,9 @@ export interface ActionResult {
|
|
|
12
12
|
/** Sets `pinned`; the audit row says `remember` with actor `dashboard`, the same op the old star toggle wrote. */
|
|
13
13
|
export declare function pinMemory(hippoRoot: string, tenantId: string, rawId: string, body: ActionBody): ActionResult;
|
|
14
14
|
/** Marks a memory wrong, the same signal as `hippo outcome --bad`. */
|
|
15
|
-
export declare function markWrong(hippoRoot: string, tenantId: string, rawId: string): ActionResult
|
|
15
|
+
export declare function markWrong(hippoRoot: string, tenantId: string, rawId: string): Promise<ActionResult>;
|
|
16
16
|
/** Deletes a memory like `hippo forget`; a raw receipt is append-only and answers 409 with the archive hint. */
|
|
17
|
-
export declare function forgetMemory(hippoRoot: string, tenantId: string, rawId: string): ActionResult
|
|
17
|
+
export declare function forgetMemory(hippoRoot: string, tenantId: string, rawId: string): Promise<ActionResult>;
|
|
18
18
|
/** Keeps one side of an open conflict and weakens the other; every refusal maps to its own status. */
|
|
19
19
|
export declare function resolveOpenConflict(hippoRoot: string, tenantId: string, conflictId: number, body: ActionBody): ActionResult;
|
|
20
20
|
//# sourceMappingURL=dashboard-actions.d.ts.map
|
|
@@ -29,25 +29,25 @@ export function pinMemory(hippoRoot, tenantId, rawId, body) {
|
|
|
29
29
|
return { status: 200, body: null, changed: true, entry: next };
|
|
30
30
|
}
|
|
31
31
|
/** Marks a memory wrong, the same signal as `hippo outcome --bad`. */
|
|
32
|
-
export function markWrong(hippoRoot, tenantId, rawId) {
|
|
32
|
+
export async function markWrong(hippoRoot, tenantId, rawId) {
|
|
33
33
|
const id = parseMemoryId(rawId);
|
|
34
34
|
if (liveEntry(hippoRoot, tenantId, id) === null)
|
|
35
35
|
return notFound();
|
|
36
36
|
const ctx = { hippoRoot, tenantId, actor: api.adminActor(ACTOR) };
|
|
37
37
|
// outcome() answers `applied: 0` for a missing or other-tenant id instead of throwing.
|
|
38
|
-
if (api.outcome(ctx, [id], false).applied === 0)
|
|
38
|
+
if ((await api.outcome(ctx, [id], false)).applied === 0)
|
|
39
39
|
return notFound();
|
|
40
40
|
const entry = readEntry(hippoRoot, id, tenantId);
|
|
41
41
|
return entry === null ? notFound() : { status: 200, body: null, changed: true, entry };
|
|
42
42
|
}
|
|
43
43
|
/** Deletes a memory like `hippo forget`; a raw receipt is append-only and answers 409 with the archive hint. */
|
|
44
|
-
export function forgetMemory(hippoRoot, tenantId, rawId) {
|
|
44
|
+
export async function forgetMemory(hippoRoot, tenantId, rawId) {
|
|
45
45
|
const id = parseMemoryId(rawId);
|
|
46
46
|
if (liveEntry(hippoRoot, tenantId, id) === null)
|
|
47
47
|
return notFound();
|
|
48
48
|
const ctx = { hippoRoot, tenantId, actor: api.adminActor(ACTOR) };
|
|
49
49
|
try {
|
|
50
|
-
const done = api.forget(ctx, id);
|
|
50
|
+
const done = await api.forget(ctx, id);
|
|
51
51
|
return { status: 200, body: done, changed: true };
|
|
52
52
|
}
|
|
53
53
|
catch (err) {
|
|
@@ -79,7 +79,7 @@ export function resolveOpenConflict(hippoRoot, tenantId, conflictId, body) {
|
|
|
79
79
|
if (liveEntry(hippoRoot, tenantId, conflict.memory_a_id) === null || liveEntry(hippoRoot, tenantId, conflict.memory_b_id) === null) {
|
|
80
80
|
return notFound();
|
|
81
81
|
}
|
|
82
|
-
const resolved = resolveConflict(hippoRoot, conflictId, keep,
|
|
82
|
+
const resolved = resolveConflict(hippoRoot, { conflictId, keepId: keep, tenantId }, { rejectedBy: ACTOR });
|
|
83
83
|
// Both guards passed above, so null here is a race with another resolver.
|
|
84
84
|
if (resolved === null)
|
|
85
85
|
return already();
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { calculateStrength } from '../core/memory.js';
|
|
3
3
|
import { loadOpenConflictsOf } from '../store/conflicts.js';
|
|
4
4
|
import { BANDS, DAY_MS, LAYERS, isLiveMemory, memoryFacts, projectIdentity, } from './dashboard-snapshot.js';
|
|
5
|
+
import { pct, round1 } from '../util/format.js';
|
|
5
6
|
const SERIES_DAYS = 90;
|
|
6
7
|
/** The server words each delta for this range; the client re-slices the series for 7d and 90d. */
|
|
7
8
|
const DELTA_DAYS = 30;
|
|
@@ -9,9 +10,6 @@ const POINTS_MAX = 4_000;
|
|
|
9
10
|
const GRID_COLS = 64;
|
|
10
11
|
const GRID_ROWS = 32;
|
|
11
12
|
const NAME_MATCHES = 3;
|
|
12
|
-
function round1(value) {
|
|
13
|
-
return Math.round(value * 10) / 10;
|
|
14
|
-
}
|
|
15
13
|
function round3(value) {
|
|
16
14
|
return Math.round(value * 1000) / 1000;
|
|
17
15
|
}
|
|
@@ -32,9 +30,6 @@ function cumulativeSeries(times, nowMs) {
|
|
|
32
30
|
function addedWithin(series) {
|
|
33
31
|
return series[SERIES_DAYS] - series[SERIES_DAYS - DELTA_DAYS];
|
|
34
32
|
}
|
|
35
|
-
function pct(share) {
|
|
36
|
-
return `${(share * 100).toFixed(1)}%`;
|
|
37
|
-
}
|
|
38
33
|
function plural(n, one, many) {
|
|
39
34
|
return `${n} ${n === 1 ? one : many}`;
|
|
40
35
|
}
|
|
@@ -342,7 +337,7 @@ export function buildMemoryDetail(hippoRoot, tenantId, entry, options) {
|
|
|
342
337
|
projectKey: project.key,
|
|
343
338
|
projectName: project.name,
|
|
344
339
|
scope: entry.scope,
|
|
345
|
-
tenant: entry.
|
|
340
|
+
tenant: entry.tenant_id,
|
|
346
341
|
kind: entry.kind,
|
|
347
342
|
embedded,
|
|
348
343
|
conflicts: openConflictsOf(hippoRoot, tenantId, entry, nowMs),
|
|
@@ -5,6 +5,7 @@ import { isQuarantineScope } from '../trust/quarantine.js';
|
|
|
5
5
|
import { listMemoryConflicts } from '../store/conflicts.js';
|
|
6
6
|
import { DashboardConnection, loadDashboardRows } from '../store/dashboard-reads.js';
|
|
7
7
|
import { DAY_MS } from '../util/time.js';
|
|
8
|
+
import { round1 } from '../util/format.js';
|
|
8
9
|
export { DAY_MS };
|
|
9
10
|
export const LAYERS = ['buffer', 'episodic', 'semantic', 'trace'];
|
|
10
11
|
// Wire order of `Band`, and the order the mockup sorts bands in.
|
|
@@ -99,9 +100,6 @@ function cutHead(content) {
|
|
|
99
100
|
end -= 1;
|
|
100
101
|
return { head: content.slice(0, end), truncated: true };
|
|
101
102
|
}
|
|
102
|
-
function round1(value) {
|
|
103
|
-
return Math.round(value * 10) / 10;
|
|
104
|
-
}
|
|
105
103
|
function newDraft(identity) {
|
|
106
104
|
return {
|
|
107
105
|
summary: {
|
|
@@ -179,7 +179,7 @@ async function handlePost(ctx, segments) {
|
|
|
179
179
|
}
|
|
180
180
|
const body = await readActionBody(req);
|
|
181
181
|
const tenantId = resolveTenantId({});
|
|
182
|
-
const result = action(hippoRoot, tenantId, body);
|
|
182
|
+
const result = await action(hippoRoot, tenantId, body);
|
|
183
183
|
if (result.changed)
|
|
184
184
|
snapshots.invalidate();
|
|
185
185
|
if (result.entry) {
|
|
@@ -300,7 +300,7 @@ function answerDashboardFailure(req, res, err) {
|
|
|
300
300
|
const clientFault = err instanceof ParamError || err instanceof URIError || err instanceof BodyTimeoutError;
|
|
301
301
|
// A cut-short response is logged even for a client fault; a bare 400 is not.
|
|
302
302
|
if (res.headersSent || !clientFault) {
|
|
303
|
-
log.error('dashboard request failed', { ...errorFields(err), error: errorMessage(err), path: req.url });
|
|
303
|
+
log.error('dashboard request failed', { ...errorFields(err), error: errorMessage(err), path: (req.url ?? '/').split('?')[0] });
|
|
304
304
|
}
|
|
305
305
|
if (res.headersSent) {
|
|
306
306
|
res.end();
|
|
@@ -318,9 +318,20 @@ function answerDashboardFailure(req, res, err) {
|
|
|
318
318
|
return jsonResponse(res, { error: 'Malformed URL path' }, 400);
|
|
319
319
|
jsonResponse(res, { error: 'Internal error' }, 500);
|
|
320
320
|
}
|
|
321
|
-
|
|
321
|
+
const DASHBOARD_URL_FILE = 'dashboard.url';
|
|
322
|
+
function printDashboardBanner(hippoRoot, boundPort, token, distUiDir) {
|
|
322
323
|
// The banner is the `hippo dashboard` command's printed result, so it stays on stdout.
|
|
323
|
-
|
|
324
|
+
const url = `http://localhost:${boundPort}/?token=${token}`;
|
|
325
|
+
if (process.stdout.isTTY) {
|
|
326
|
+
console.log(`Hippo Dashboard running at ${url}`);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
// Captured stdout lands in logs, so the token goes to an owner-only file, created fresh so its mode holds.
|
|
330
|
+
const file = path.join(hippoRoot, DASHBOARD_URL_FILE);
|
|
331
|
+
fs.rmSync(file, { force: true });
|
|
332
|
+
fs.writeFileSync(file, `${url}\n`, { flag: 'wx', mode: 0o600 });
|
|
333
|
+
console.log(`Hippo Dashboard running at http://localhost:${boundPort}/ (open the URL with its token from ${file})`);
|
|
334
|
+
}
|
|
324
335
|
if (distUiDir !== null)
|
|
325
336
|
console.log(`Serving React UI from ${distUiDir}`);
|
|
326
337
|
console.log('Press Ctrl+C to stop.');
|
|
@@ -406,7 +417,7 @@ export function serveDashboard(hippoRoot, port = 3333, token = randomBytes(32).t
|
|
|
406
417
|
server.listen(port, '127.0.0.1', () => {
|
|
407
418
|
// SAFETY: listen() was given a TCP port, so address() is AddressInfo, never a pipe name.
|
|
408
419
|
const boundPort = server.address().port;
|
|
409
|
-
printDashboardBanner(boundPort, token, hasDistUi ? distUiDir : null);
|
|
420
|
+
printDashboardBanner(hippoRoot, boundPort, token, hasDistUi ? distUiDir : null);
|
|
410
421
|
});
|
|
411
422
|
return server;
|
|
412
423
|
}
|
package/dist/db/busy.d.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import type { DatabaseSyncLike } from './sqlite.js';
|
|
2
2
|
export declare function isSqliteBusy(cause: unknown): boolean;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export declare class StoreBusyError extends Error {
|
|
6
|
-
constructor(message?: string, options?: ErrorOptions);
|
|
7
|
-
}
|
|
8
|
-
/** A held lock in any store: SQLite's busy codes or a port's StoreBusyError. */
|
|
9
|
-
export declare function isStoreBusy<E>(error: E): boolean;
|
|
3
|
+
/** The lock wait of an open that names none: its busy_timeout and every explicit wait below. */
|
|
4
|
+
export declare const DEFAULT_BUSY_WAIT_MS = 5000;
|
|
10
5
|
export declare function execWithBusyRetry(db: DatabaseSyncLike, sql: string, timeoutMs?: number): void;
|
|
11
6
|
/** Waits for the lock past busy_timeout when given; ignored inside a caller's transaction, which already holds it. */
|
|
12
7
|
export interface WriteScopeOptions {
|