hippo-memory 1.70.0 → 1.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agent-memories/claude-code.d.ts +4 -2
- package/dist/agent-memories/claude-code.js +14 -5
- package/dist/agent-memories/files.js +23 -12
- package/dist/agent-memories/markdown.d.ts +1 -3
- package/dist/agent-memories/markdown.js +1 -3
- package/dist/agent-memories/report.js +2 -1
- package/dist/agent-memories/sync.d.ts +4 -2
- package/dist/agent-memories/sync.js +10 -5
- package/dist/api/assemble.d.ts +7 -44
- package/dist/api/assemble.js +2 -22
- package/dist/api/audit.d.ts +5 -1
- package/dist/api/audit.js +9 -1
- package/dist/api/auth.d.ts +13 -22
- package/dist/api/auth.js +34 -24
- package/dist/api/auto-sleep.js +2 -2
- package/dist/api/availability.d.ts +2 -15
- package/dist/api/availability.js +2 -15
- package/dist/api/context-select.js +3 -4
- package/dist/api/context-types.d.ts +10 -35
- package/dist/api/context.d.ts +5 -22
- package/dist/api/context.js +21 -38
- package/dist/api/dormant.d.ts +5 -21
- package/dist/api/dormant.js +7 -26
- package/dist/api/drill-down.d.ts +7 -46
- package/dist/api/drill-down.js +5 -26
- package/dist/api/forget.d.ts +5 -24
- package/dist/api/forget.js +5 -28
- package/dist/api/graph.d.ts +8 -0
- package/dist/api/graph.js +7 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/instruction-detect.js +16 -5
- package/dist/api/ledger-db.d.ts +2 -1
- package/dist/api/ledger-db.js +5 -3
- package/dist/api/memories.d.ts +5 -0
- package/dist/api/memories.js +7 -0
- package/dist/api/objects.d.ts +9 -0
- package/dist/api/objects.js +11 -0
- package/dist/api/on-store.js +5 -3
- package/dist/api/predictions.d.ts +9 -0
- package/dist/api/predictions.js +18 -0
- package/dist/api/promote.d.ts +13 -17
- package/dist/api/promote.js +11 -19
- package/dist/api/prompt-hook.d.ts +4 -4
- package/dist/api/prompt-hook.js +10 -9
- package/dist/api/recall-cli.d.ts +55 -0
- package/dist/api/recall-cli.js +94 -0
- package/dist/api/recall-core.js +14 -6
- package/dist/api/recall-finish.d.ts +53 -0
- package/dist/api/recall-finish.js +30 -0
- package/dist/api/recall-history.d.ts +17 -84
- package/dist/api/recall-history.js +15 -88
- package/dist/api/recall-pipeline.d.ts +2 -3
- package/dist/api/recall-pipeline.js +16 -9
- package/dist/api/recall-types.d.ts +64 -304
- package/dist/api/recall.d.ts +5 -33
- package/dist/api/recall.js +59 -60
- package/dist/api/refine.d.ts +7 -0
- package/dist/api/refine.js +10 -0
- package/dist/api/remember-local.d.ts +57 -0
- package/dist/api/remember-local.js +90 -0
- package/dist/api/remember.d.ts +18 -1
- package/dist/api/remember.js +13 -1
- package/dist/api/sleep-run.d.ts +1 -3
- package/dist/api/sleep-run.js +17 -21
- package/dist/api/sleep.d.ts +9 -28
- package/dist/api/tokens.d.ts +3 -10
- package/dist/api/tokens.js +3 -10
- package/dist/api/types.d.ts +6 -29
- package/dist/api/types.js +4 -22
- package/dist/capture/command.d.ts +4 -12
- package/dist/capture/command.js +6 -22
- package/dist/capture/compact.d.ts +4 -15
- package/dist/capture/compact.js +16 -25
- package/dist/capture/compaction-record.js +101 -69
- package/dist/capture/compaction-spool.d.ts +1 -1
- package/dist/capture/compaction-spool.js +1 -1
- package/dist/capture/session-digest.d.ts +1 -1
- package/dist/capture/session-digest.js +13 -7
- package/dist/capture/transcript.d.ts +2 -10
- package/dist/capture/transcript.js +4 -18
- package/dist/cli/api-context.d.ts +3 -0
- package/dist/cli/api-context.js +6 -0
- package/dist/cli/audit-prune.d.ts +6 -39
- package/dist/cli/audit-prune.js +6 -39
- package/dist/cli/audit.d.ts +1 -1
- package/dist/cli/audit.js +33 -34
- package/dist/cli/auth.d.ts +2 -2
- package/dist/cli/auth.js +57 -39
- package/dist/cli/briefs.d.ts +4 -4
- package/dist/cli/briefs.js +18 -22
- package/dist/cli/card.d.ts +2 -2
- package/dist/cli/card.js +31 -32
- package/dist/cli/client.d.ts +7 -27
- package/dist/cli/client.js +24 -43
- package/dist/cli/compact-resume-payload.js +3 -2
- package/dist/cli/context.d.ts +1 -2
- package/dist/cli/context.js +12 -8
- package/dist/cli/continuity.d.ts +6 -6
- package/dist/cli/continuity.js +62 -64
- package/dist/cli/correction-latency.d.ts +2 -14
- package/dist/cli/correction-latency.js +2 -14
- package/dist/cli/curate.d.ts +13 -17
- package/dist/cli/curate.js +68 -92
- package/dist/cli/dag.d.ts +4 -4
- package/dist/cli/dag.js +33 -27
- package/dist/cli/decisions.d.ts +4 -4
- package/dist/cli/decisions.js +33 -47
- package/dist/cli/eval.js +15 -13
- package/dist/cli/exit.d.ts +6 -0
- package/dist/cli/exit.js +11 -0
- package/dist/cli/explain.d.ts +1 -2
- package/dist/cli/explain.js +6 -4
- package/dist/cli/flag-values.d.ts +6 -1
- package/dist/cli/flag-values.js +27 -10
- package/dist/cli/flags.d.ts +1 -0
- package/dist/cli/flags.js +1 -1
- package/dist/cli/github.d.ts +14 -0
- package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
- package/dist/cli/goals.d.ts +2 -2
- package/dist/cli/goals.js +46 -50
- package/dist/cli/hook-runtime.d.ts +9 -27
- package/dist/cli/hook-runtime.js +15 -31
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.js +6 -12
- package/dist/cli/install-steps.js +3 -12
- package/dist/cli/last-sleep.d.ts +2 -1
- package/dist/cli/last-sleep.js +3 -0
- package/dist/cli/maintenance.d.ts +4 -4
- package/dist/cli/maintenance.js +14 -19
- package/dist/cli/object-verbs.js +4 -3
- package/dist/cli/owner-validation.d.ts +5 -28
- package/dist/cli/owner-validation.js +5 -28
- package/dist/cli/playbooks.d.ts +4 -4
- package/dist/cli/playbooks.js +23 -28
- package/dist/cli/print.d.ts +2 -5
- package/dist/cli/print.js +1 -4
- package/dist/cli/projects.d.ts +2 -2
- package/dist/cli/projects.js +1 -3
- package/dist/cli/provenance-coverage.d.ts +2 -6
- package/dist/cli/provenance-coverage.js +2 -6
- package/dist/cli/quality-repair-once.js +2 -2
- package/dist/cli/recall.d.ts +2 -4
- package/dist/cli/recall.js +55 -131
- package/dist/cli/refine-llm.d.ts +5 -31
- package/dist/cli/refine-llm.js +9 -36
- package/dist/cli/remember.d.ts +3 -3
- package/dist/cli/remember.js +122 -180
- package/dist/cli/scheduler.d.ts +2 -17
- package/dist/cli/scheduler.js +12 -18
- package/dist/cli/serve.js +21 -12
- package/dist/cli/session-hooks.d.ts +10 -18
- package/dist/cli/session-hooks.js +112 -113
- package/dist/cli/setup.d.ts +4 -4
- package/dist/cli/setup.js +19 -21
- package/dist/cli/shared.d.ts +9 -23
- package/dist/cli/shared.js +9 -32
- package/dist/cli/slack.d.ts +2 -2
- package/dist/cli/slack.js +19 -23
- package/dist/cli/sleep.d.ts +3 -2
- package/dist/cli/sleep.js +15 -16
- package/dist/cli/status.d.ts +9 -12
- package/dist/cli/status.js +55 -98
- package/dist/cli/stdin.d.ts +4 -6
- package/dist/cli/stdin.js +2 -3
- package/dist/cli/transfer.d.ts +9 -9
- package/dist/cli/transfer.js +66 -89
- package/dist/cli/usage.js +11 -5
- package/dist/cli.d.ts +66 -448
- package/dist/cli.js +87 -263
- package/dist/connectors/github/backfill.d.ts +5 -25
- package/dist/connectors/github/backfill.js +14 -49
- package/dist/connectors/github/deletion.d.ts +4 -18
- package/dist/connectors/github/deletion.js +2 -15
- package/dist/connectors/github/dlq.d.ts +8 -33
- package/dist/connectors/github/dlq.js +12 -29
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +4 -10
- package/dist/connectors/github/octokit-client.d.ts +4 -16
- package/dist/connectors/github/octokit-client.js +27 -24
- package/dist/connectors/github/ratelimit.d.ts +3 -14
- package/dist/connectors/github/ratelimit.js +3 -14
- package/dist/connectors/github/scope.d.ts +3 -5
- package/dist/connectors/github/scope.js +3 -5
- package/dist/connectors/github/signature.d.ts +4 -26
- package/dist/connectors/github/signature.js +4 -26
- package/dist/connectors/github/tenant-routing.d.ts +2 -24
- package/dist/connectors/github/tenant-routing.js +4 -26
- package/dist/connectors/github/transform.js +2 -16
- package/dist/connectors/github/types.d.ts +3 -15
- package/dist/connectors/github/types.js +2 -9
- package/dist/connectors/github/webhook.d.ts +2 -16
- package/dist/connectors/github/webhook.js +6 -22
- package/dist/connectors/slack/backfill.d.ts +4 -17
- package/dist/connectors/slack/backfill.js +4 -13
- package/dist/connectors/slack/dlq.d.ts +2 -19
- package/dist/connectors/slack/dlq.js +2 -19
- package/dist/connectors/slack/ingest.d.ts +2 -3
- package/dist/connectors/slack/ingest.js +2 -3
- package/dist/connectors/slack/scope.d.ts +2 -8
- package/dist/connectors/slack/scope.js +2 -8
- package/dist/connectors/slack/signature.d.ts +1 -6
- package/dist/connectors/slack/tenant-routing.d.ts +2 -19
- package/dist/connectors/slack/tenant-routing.js +2 -21
- package/dist/connectors/slack/transform.d.ts +2 -18
- package/dist/connectors/slack/transform.js +2 -18
- package/dist/connectors/slack/types.d.ts +3 -9
- package/dist/connectors/slack/types.js +2 -4
- package/dist/connectors/slack/web-client.js +33 -27
- package/dist/connectors/slack/webhook.d.ts +2 -19
- package/dist/connectors/slack/webhook.js +5 -26
- package/dist/connectors/slack/workspaces.d.ts +4 -24
- package/dist/connectors/slack/workspaces.js +4 -24
- package/dist/consolidate/conflicts.js +6 -14
- package/dist/consolidate/dag-summary.d.ts +8 -0
- package/dist/consolidate/dag-summary.js +41 -0
- package/dist/consolidate/dag.d.ts +5 -28
- package/dist/consolidate/dag.js +14 -75
- package/dist/consolidate/decay.js +7 -19
- package/dist/consolidate/dedupe.d.ts +6 -52
- package/dist/consolidate/dedupe.js +13 -71
- package/dist/consolidate/flush-units.d.ts +3 -4
- package/dist/consolidate/flush-units.js +3 -3
- package/dist/consolidate/half-life-migration.d.ts +3 -26
- package/dist/consolidate/half-life-migration.js +11 -28
- package/dist/consolidate/llm-passes.js +4 -21
- package/dist/consolidate/memory-value-weights.d.ts +2 -13
- package/dist/consolidate/memory-value-weights.js +2 -13
- package/dist/consolidate/memory-value.d.ts +11 -84
- package/dist/consolidate/memory-value.js +16 -104
- package/dist/consolidate/merge.js +10 -31
- package/dist/consolidate/merged-row.js +2 -1
- package/dist/consolidate/physics-pass.js +1 -3
- package/dist/consolidate/replay.d.ts +6 -38
- package/dist/consolidate/replay.js +14 -52
- package/dist/consolidate/run.js +1 -1
- package/dist/consolidate/sleep.d.ts +1 -8
- package/dist/consolidate/sleep.js +5 -17
- package/dist/consolidate/trace.d.ts +3 -18
- package/dist/consolidate/trace.js +3 -18
- package/dist/consolidate/traces.js +6 -22
- package/dist/core/ablation.d.ts +4 -91
- package/dist/core/ablation.js +4 -91
- package/dist/core/ambient.d.ts +1 -8
- package/dist/core/ambient.js +1 -8
- package/dist/core/capture-contract.d.ts +4 -2
- package/dist/core/capture-contract.js +4 -2
- package/dist/core/card.d.ts +4 -1
- package/dist/core/card.js +8 -0
- package/dist/core/compare.d.ts +11 -67
- package/dist/core/compare.js +9 -63
- package/dist/core/config.d.ts +10 -24
- package/dist/core/config.js +13 -14
- package/dist/core/handoff.d.ts +1 -7
- package/dist/core/handoff.js +1 -7
- package/dist/core/memory-quality.js +1 -1
- package/dist/core/memory.d.ts +41 -164
- package/dist/core/memory.js +51 -221
- package/dist/core/package-root.d.ts +3 -0
- package/dist/core/package-root.js +5 -0
- package/dist/core/physics-config.d.ts +1 -4
- package/dist/core/physics-config.js +3 -8
- package/dist/core/physics.d.ts +15 -61
- package/dist/core/physics.js +59 -122
- package/dist/core/project-identity.d.ts +17 -58
- package/dist/core/project-identity.js +17 -38
- package/dist/core/project-remote.js +13 -2
- package/dist/core/raw-append-only.d.ts +5 -0
- package/dist/core/raw-append-only.js +7 -0
- package/dist/core/salience.d.ts +1 -7
- package/dist/core/salience.js +1 -7
- package/dist/dashboard/dashboard-actions.js +2 -2
- package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
- package/dist/dashboard/dashboard-snapshot.js +11 -2
- package/dist/dashboard/dashboard-types.d.ts +2 -1
- package/dist/dashboard/dashboard.d.ts +1 -0
- package/dist/dashboard/dashboard.js +50 -4
- package/dist/db/busy.d.ts +1 -1
- package/dist/db/busy.js +17 -8
- package/dist/db/connect.d.ts +1 -0
- package/dist/db/connect.js +3 -3
- package/dist/db/migrate.js +3 -3
- package/dist/db/migrations/types.d.ts +2 -5
- package/dist/db/migrations/v14.js +2 -3
- package/dist/db/migrations/v15.js +2 -8
- package/dist/db/migrations/v16.js +2 -3
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +2 -5
- package/dist/db/migrations/v20.js +2 -7
- package/dist/db/migrations/v22.js +4 -17
- package/dist/db/migrations/v23.js +3 -14
- package/dist/db/migrations/v24.js +2 -4
- package/dist/db/migrations/v25.js +3 -8
- package/dist/db/migrations/v26.js +2 -13
- package/dist/db/migrations/v27.js +3 -11
- package/dist/db/migrations/v28.js +2 -14
- package/dist/db/migrations/v29.js +4 -18
- package/dist/db/migrations/v30.js +4 -16
- package/dist/db/migrations/v31.js +2 -15
- package/dist/db/migrations/v32.js +4 -22
- package/dist/db/migrations/v33.js +2 -15
- package/dist/db/migrations/v34.js +2 -11
- package/dist/db/migrations/v35.js +2 -11
- package/dist/db/migrations/v36.js +2 -11
- package/dist/db/migrations/v37.js +8 -33
- package/dist/db/migrations/v38.js +5 -38
- package/dist/db/migrations/v39.js +9 -20
- package/dist/db/migrations/v40.js +2 -9
- package/dist/db/migrations/v41.js +2 -24
- package/dist/db/migrations/v43.js +1 -1
- package/dist/db/migrations/v44.js +2 -8
- package/dist/db/migrations/v45.js +2 -7
- package/dist/db/migrations/v47.js +2 -3
- package/dist/db/migrations/v51.js +1 -1
- package/dist/db/open.d.ts +2 -0
- package/dist/db/open.js +17 -1
- package/dist/db/physics-state.d.ts +6 -22
- package/dist/db/physics-state.js +25 -36
- package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
- package/dist/db/raw-archive-mirror-cleanup.js +2 -17
- package/dist/db/vector-store.d.ts +2 -0
- package/dist/db/vector-store.js +8 -1
- package/dist/doctor.js +74 -19
- package/dist/entry/session-text.js +2 -1
- package/dist/eval/eval-stats.d.ts +15 -53
- package/dist/eval/eval-stats.js +12 -42
- package/dist/eval/eval-suite.d.ts +2 -13
- package/dist/eval/eval-suite.js +74 -34
- package/dist/eval/eval.d.ts +6 -24
- package/dist/eval/eval.js +7 -34
- package/dist/eval/judgment.d.ts +0 -3
- package/dist/eval/judgment.js +19 -11
- package/dist/extensions/openclaw-plugin/index.js +1 -1
- package/dist/graph/extract.d.ts +5 -27
- package/dist/graph/extract.js +7 -33
- package/dist/graph/recall.d.ts +7 -20
- package/dist/graph/recall.js +14 -76
- package/dist/graph/stream.d.ts +7 -39
- package/dist/graph/stream.js +11 -34
- package/dist/graph/view.d.ts +9 -35
- package/dist/graph/view.js +11 -39
- package/dist/hooks/codex-wrapper.js +2 -2
- package/dist/hooks/copilot.js +2 -1
- package/dist/hooks/hook-blocks.d.ts +6 -2
- package/dist/hooks/hook-blocks.js +37 -124
- package/dist/hooks/json-hooks.d.ts +4 -36
- package/dist/hooks/json-hooks.js +18 -57
- package/dist/hooks/opencode.d.ts +0 -38
- package/dist/hooks/opencode.js +9 -76
- package/dist/hooks/shared.d.ts +8 -17
- package/dist/hooks/shared.js +29 -20
- package/dist/importers/core.d.ts +12 -37
- package/dist/importers/core.js +9 -27
- package/dist/importers/markdown-parse.d.ts +8 -22
- package/dist/importers/markdown-parse.js +8 -25
- package/dist/importers/markdown.js +3 -12
- package/dist/importers/sources.js +7 -35
- package/dist/importers/vault.d.ts +2 -8
- package/dist/importers/vault.js +25 -81
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/learn/autolearn.d.ts +14 -41
- package/dist/learn/autolearn.js +14 -41
- package/dist/learn/extract.js +2 -4
- package/dist/learn/forward-claim-detector.d.ts +6 -30
- package/dist/learn/forward-claim-detector.js +14 -66
- package/dist/learn/invalidation.d.ts +6 -18
- package/dist/learn/invalidation.js +9 -26
- package/dist/mcp/admin-tools.js +3 -5
- package/dist/mcp/memory-tools.js +4 -9
- package/dist/mcp/protocol.d.ts +8 -26
- package/dist/mcp/protocol.js +3 -6
- package/dist/mcp/recall-tools.js +3 -3
- package/dist/mcp/request.d.ts +3 -11
- package/dist/mcp/request.js +10 -26
- package/dist/mcp/server.d.ts +3 -9
- package/dist/mcp/server.js +5 -16
- package/dist/mcp/session-state.d.ts +1 -1
- package/dist/mcp/session-state.js +5 -11
- package/dist/mcp/stdio.d.ts +2 -6
- package/dist/mcp/stdio.js +48 -12
- package/dist/mcp/tools.js +5 -3
- package/dist/objects/customer-notes.d.ts +7 -42
- package/dist/objects/customer-notes.js +7 -48
- package/dist/objects/decisions.d.ts +12 -50
- package/dist/objects/decisions.js +15 -53
- package/dist/objects/incidents.d.ts +7 -38
- package/dist/objects/incidents.js +7 -41
- package/dist/objects/policies.d.ts +11 -89
- package/dist/objects/policies.js +11 -98
- package/dist/objects/processes.d.ts +7 -52
- package/dist/objects/processes.js +7 -61
- package/dist/objects/project-briefs.d.ts +11 -55
- package/dist/objects/project-briefs.js +14 -75
- package/dist/objects/skills.d.ts +7 -42
- package/dist/objects/skills.js +8 -54
- package/dist/postinstall.js +6 -19
- package/dist/predictions/planning-fallacy.d.ts +11 -34
- package/dist/rerankers/clef.js +3 -31
- package/dist/rerankers/cross-encoder.js +4 -6
- package/dist/rerankers/jev.js +9 -6
- package/dist/rerankers/llm.d.ts +2 -11
- package/dist/rerankers/llm.js +14 -14
- package/dist/rerankers/outage-warning.d.ts +2 -1
- package/dist/rerankers/outage-warning.js +2 -1
- package/dist/rerankers/remote.d.ts +1 -0
- package/dist/rerankers/remote.js +2 -0
- package/dist/rerankers/types.d.ts +2 -14
- package/dist/search/boosts.d.ts +0 -2
- package/dist/search/boosts.js +2 -2
- package/dist/search/goal-boost.d.ts +23 -0
- package/dist/search/goal-boost.js +90 -0
- package/dist/search/hybrid.d.ts +2 -0
- package/dist/search/multihop.js +2 -3
- package/dist/search/path-context.d.ts +5 -18
- package/dist/search/path-context.js +5 -18
- package/dist/search/physics-search.js +11 -8
- package/dist/search/rrf.d.ts +7 -35
- package/dist/search/rrf.js +5 -30
- package/dist/search/vector.d.ts +7 -0
- package/dist/search/vector.js +35 -5
- package/dist/server/auth.d.ts +9 -28
- package/dist/server/auth.js +32 -25
- package/dist/server/boot.d.ts +2 -21
- package/dist/server/boot.js +63 -96
- package/dist/server/client-ip.d.ts +3 -19
- package/dist/server/client-ip.js +5 -28
- package/dist/server/defaults.d.ts +3 -0
- package/dist/server/defaults.js +4 -0
- package/dist/server/key-check-bounds.d.ts +2 -1
- package/dist/server/lifecycle.d.ts +5 -4
- package/dist/server/lifecycle.js +19 -4
- package/dist/server/mcp-http.js +10 -44
- package/dist/server/rate-limit.d.ts +5 -18
- package/dist/server/rate-limit.js +4 -13
- package/dist/server/request.d.ts +4 -8
- package/dist/server/request.js +9 -17
- package/dist/server/route-table.js +42 -49
- package/dist/server/routes/admin.js +22 -28
- package/dist/server/routes/customer-notes.js +7 -12
- package/dist/server/routes/decisions.js +10 -17
- package/dist/server/routes/incidents.js +12 -20
- package/dist/server/routes/memories.js +12 -32
- package/dist/server/routes/object-routes.d.ts +0 -5
- package/dist/server/routes/object-routes.js +7 -15
- package/dist/server/routes/policies.js +10 -18
- package/dist/server/routes/predictions.js +13 -25
- package/dist/server/routes/processes.js +16 -26
- package/dist/server/routes/project-briefs.js +9 -16
- package/dist/server/routes/recall.js +10 -35
- package/dist/server/routes/skills.js +8 -18
- package/dist/server/server-detect.d.ts +9 -53
- package/dist/server/server-detect.js +24 -90
- package/dist/server/sleep-offload.js +4 -1
- package/dist/server/types.d.ts +12 -10
- package/dist/server/validation.d.ts +3 -1
- package/dist/server/validation.js +10 -23
- package/dist/server.d.ts +2 -2
- package/dist/server.js +3 -2
- package/dist/sharing/global-store.d.ts +19 -0
- package/dist/sharing/global-store.js +75 -0
- package/dist/sharing/global-sync.d.ts +6 -0
- package/dist/sharing/global-sync.js +80 -0
- package/dist/sharing/project-merge.d.ts +4 -5
- package/dist/sharing/project-merge.js +9 -7
- package/dist/sharing/scope.d.ts +4 -11
- package/dist/sharing/scope.js +4 -11
- package/dist/sharing/search-both.d.ts +60 -0
- package/dist/sharing/search-both.js +138 -0
- package/dist/sharing/share.d.ts +38 -0
- package/dist/sharing/share.js +226 -0
- package/dist/store/ambient.js +4 -9
- package/dist/store/audit-event.d.ts +4 -12
- package/dist/store/audit-event.js +4 -12
- package/dist/store/audit.d.ts +2 -5
- package/dist/store/audit.js +4 -12
- package/dist/store/auth.d.ts +6 -6
- package/dist/store/auth.js +10 -9
- package/dist/store/candidates.d.ts +20 -3
- package/dist/store/candidates.js +77 -48
- package/dist/store/card-detail.d.ts +2 -1
- package/dist/store/card-detail.js +2 -1
- package/dist/store/cards.d.ts +14 -9
- package/dist/store/cards.js +72 -126
- package/dist/store/conflicts.d.ts +4 -21
- package/dist/store/conflicts.js +71 -150
- package/dist/store/connectors/github.d.ts +10 -10
- package/dist/store/connectors/github.js +10 -10
- package/dist/store/dashboard-reads.js +4 -8
- package/dist/store/delete-and-batch.d.ts +11 -31
- package/dist/store/delete-and-batch.js +48 -64
- package/dist/store/delivery-recorder.d.ts +8 -4
- package/dist/store/delivery-recorder.js +25 -15
- package/dist/store/diagnostics.js +6 -13
- package/dist/store/dormant.d.ts +7 -29
- package/dist/store/dormant.js +15 -56
- package/dist/store/embeddings/index.d.ts +11 -80
- package/dist/store/embeddings/index.js +71 -207
- package/dist/store/embeddings/local.js +15 -32
- package/dist/store/embeddings/provider.d.ts +16 -53
- package/dist/store/embeddings/provider.js +41 -69
- package/dist/store/entry-reads.d.ts +21 -57
- package/dist/store/entry-reads.js +65 -126
- package/dist/store/entry-row.d.ts +6 -35
- package/dist/store/entry-row.js +9 -37
- package/dist/store/entry-writes.d.ts +10 -16
- package/dist/store/entry-writes.js +17 -35
- package/dist/store/goals.d.ts +3 -40
- package/dist/store/goals.js +21 -160
- package/dist/store/graph-queue.d.ts +6 -22
- package/dist/store/graph-queue.js +14 -45
- package/dist/store/graph-reads.d.ts +11 -35
- package/dist/store/graph-reads.js +20 -58
- package/dist/store/graph-rows.d.ts +3 -6
- package/dist/store/graph-rows.js +6 -9
- package/dist/store/graph-view-rows.d.ts +2 -1
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +6 -31
- package/dist/store/graph-writes.js +13 -37
- package/dist/store/half-life.d.ts +2 -1
- package/dist/store/half-life.js +14 -16
- package/dist/store/handoffs.d.ts +5 -11
- package/dist/store/handoffs.js +16 -34
- package/dist/store/index-and-stats.d.ts +6 -19
- package/dist/store/index-and-stats.js +34 -82
- package/dist/store/markdown.d.ts +2 -6
- package/dist/store/markdown.js +21 -20
- package/dist/store/mirrors.d.ts +2 -6
- package/dist/store/mirrors.js +14 -23
- package/dist/store/open.js +6 -13
- package/dist/store/planning-fallacy-evidence.d.ts +2 -30
- package/dist/store/planning-fallacy-evidence.js +8 -37
- package/dist/store/port.d.ts +82 -79
- package/dist/store/predictions.d.ts +11 -51
- package/dist/store/predictions.js +38 -119
- package/dist/{cli → store}/quality-repair.js +15 -31
- package/dist/store/raw-archive.d.ts +4 -16
- package/dist/store/raw-archive.js +14 -29
- package/dist/store/recall-scope.d.ts +19 -79
- package/dist/store/recall-scope.js +21 -82
- package/dist/store/recall-trace.d.ts +10 -77
- package/dist/store/recall-trace.js +19 -95
- package/dist/store/rejected-values.js +7 -19
- package/dist/store/rejection.d.ts +12 -58
- package/dist/store/rejection.js +13 -65
- package/dist/store/report-reads.d.ts +6 -0
- package/dist/store/report-reads.js +29 -0
- package/dist/store/rows.d.ts +9 -19
- package/dist/store/rows.js +36 -34
- package/dist/store/rule-sql.d.ts +5 -0
- package/dist/store/rule-sql.js +37 -0
- package/dist/store/search-rows.d.ts +7 -38
- package/dist/store/search-rows.js +14 -50
- package/dist/store/sessions.d.ts +10 -47
- package/dist/store/sessions.js +17 -73
- package/dist/store/sqlite/connector-events-group.js +2 -2
- package/dist/store/sqlite/entry-writes-group.js +2 -2
- package/dist/store/sqlite/error-codec.js +4 -2
- package/dist/store/sqlite/executor.d.ts +2 -1
- package/dist/store/sqlite/executor.js +2 -1
- package/dist/store/sqlite/local.d.ts +3 -3
- package/dist/store/sqlite/local.js +1 -0
- package/dist/store/sqlite/object-rows.js +6 -3
- package/dist/store/sqlite/objects-group.js +4 -2
- package/dist/store/sqlite/quarantine-group.js +2 -2
- package/dist/store/sqlite/store.d.ts +1 -4
- package/dist/store/sqlite/store.js +2 -3
- package/dist/store/sqlite/vector-reads-group.js +2 -2
- package/dist/store/sqlite/worker-jobs.js +1 -1
- package/dist/store/sqlite/worker-ops.d.ts +13 -2
- package/dist/store/sqlite/worker-ops.js +13 -2
- package/dist/store/sqlite/worker-store.js +5 -2
- package/dist/store/summaries.d.ts +10 -62
- package/dist/store/summaries.js +34 -146
- package/dist/store/summary-dirty.js +1 -1
- package/dist/store/tenant-lookup.d.ts +6 -1
- package/dist/store/tenant-lookup.js +7 -0
- package/dist/store/tenant.d.ts +2 -16
- package/dist/store/tenant.js +4 -19
- package/dist/store/token-ledger.d.ts +13 -43
- package/dist/store/token-ledger.js +19 -50
- package/dist/store/usage-reports.js +5 -13
- package/dist/store/vector-index.d.ts +46 -0
- package/dist/store/vector-index.js +170 -0
- package/dist/store/working-memory.d.ts +6 -25
- package/dist/store/working-memory.js +18 -52
- package/dist/store/yaml.d.ts +1 -5
- package/dist/store/yaml.js +2 -6
- package/dist/support-bundle.js +7 -5
- package/dist/trust/reject-flow.js +1 -3
- package/dist/util/anthropic-messages.js +14 -2
- package/dist/util/atomic-write.d.ts +2 -1
- package/dist/util/atomic-write.js +35 -4
- package/dist/util/capped-json.d.ts +6 -0
- package/dist/util/capped-json.js +46 -0
- package/dist/util/crash-handlers.d.ts +8 -1
- package/dist/util/crash-handlers.js +52 -10
- package/dist/util/env.d.ts +13 -6
- package/dist/util/env.js +14 -7
- package/dist/util/home-path.d.ts +2 -1
- package/dist/util/home-path.js +4 -2
- package/dist/util/http-retry.d.ts +3 -1
- package/dist/util/http-retry.js +26 -5
- package/dist/util/log.d.ts +3 -2
- package/dist/util/log.js +25 -9
- package/dist/util/request-scope.d.ts +2 -1
- package/dist/util/request-scope.js +2 -1
- package/dist/util/secret-detect.d.ts +5 -30
- package/dist/util/secret-detect.js +13 -39
- package/dist/util/stored-json.d.ts +1 -1
- package/dist/util/stored-json.js +1 -1
- package/dist/util/token-text.d.ts +1 -4
- package/dist/util/token-text.js +1 -4
- package/dist/util/transcript-tail.d.ts +2 -0
- package/dist/util/transcript-tail.js +24 -23
- package/dist/util/version.d.ts +5 -20
- package/dist/util/version.js +5 -20
- package/extensions/openclaw-plugin/index.ts +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/connectors/github/cli-impl.d.ts +0 -25
- package/dist/sharing/shared.d.ts +0 -187
- package/dist/sharing/shared.js +0 -563
- package/dist/store/vector-writes.d.ts +0 -13
- package/dist/store/vector-writes.js +0 -89
- /package/dist/{cli → store}/quality-repair.d.ts +0 -0
|
@@ -1,46 +1,28 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, unlinkSync, renameSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { envHealthProbeMs } from '../util/env.js';
|
|
4
|
-
// Pidfile sits directly inside hippoRoot
|
|
5
|
-
// directory itself (the same convention used by api.ts / store.ts /
|
|
6
|
-
// openHippoDb), so this resolves to `${hippoRoot}/server.pid`.
|
|
4
|
+
// Pidfile sits directly inside hippoRoot (the `.hippo` directory itself, as for openHippoDb), i.e. `${hippoRoot}/server.pid`.
|
|
7
5
|
const PIDFILE = 'server.pid';
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
* treating the pidfile as stale. Short by design: the probe only fires on
|
|
11
|
-
* the rare path where a pidfile exists and its pid is live, and the target
|
|
12
|
-
* is always loopback, so a healthy server answers well within this bound. HIPPO_HEALTH_PROBE_MS overrides it.
|
|
13
|
-
*/
|
|
6
|
+
/** How long detectServer waits for the `/health` probe before treating the pidfile as stale; short because it fires only when a pidfile exists with a live
|
|
7
|
+
* pid on loopback. HIPPO_HEALTH_PROBE_MS overrides it. */
|
|
14
8
|
const HEALTH_PROBE_TIMEOUT_MS = 300;
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
* hippo /health payload is well under 1 KB; a larger body means the process
|
|
18
|
-
* answering on the recorded port is not hippo, so the pidfile is stale.
|
|
19
|
-
*/
|
|
9
|
+
/** Hard cap on the /health body detectServer buffers: a real payload is well under 1 KB, so a larger body means the process on the recorded port is not
|
|
10
|
+
* hippo. */
|
|
20
11
|
const HEALTH_BODY_MAX_BYTES = 64 * 1024;
|
|
21
|
-
/**
|
|
22
|
-
* Loopback hosts the recorded pidfile url is allowed to point at. serve()
|
|
23
|
-
* only binds these (it mirrors LOOPBACK_HOSTS in server.ts); a pidfile url
|
|
24
|
-
* with any other host is malformed or forged and must not be probed.
|
|
25
|
-
*/
|
|
12
|
+
/** Loopback hosts a recorded pidfile url may point at (serve() only binds these); any other host is malformed or forged and is not probed. */
|
|
26
13
|
const PIDFILE_LOOPBACK_HOSTS = new Set(['127.0.0.1', '::1', 'localhost']);
|
|
27
14
|
/** False when the pidfile's pid is dead or its url could not be one serve() wrote. */
|
|
28
15
|
function isLiveLoopbackTarget(info) {
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// Node's process.kill(pid, 0) is implemented on Windows via OpenProcess +
|
|
32
|
-
// GetExitCodeProcess, so this works cross-platform for the dead-pid case.
|
|
16
|
+
// Signal 0 throws if the pid is dead or owned by another user we cannot signal; either way, treat as stale.
|
|
17
|
+
// process.kill(pid, 0) works cross-platform for the dead-pid case (OpenProcess + GetExitCodeProcess on Windows).
|
|
33
18
|
try {
|
|
34
19
|
process.kill(info.pid, 0);
|
|
35
20
|
}
|
|
36
21
|
catch {
|
|
37
22
|
return false;
|
|
38
23
|
}
|
|
39
|
-
// The pid is
|
|
40
|
-
// the recorded
|
|
41
|
-
// binds a loopback host, so a url that is not http on a loopback host and the
|
|
42
|
-
// recorded port is malformed or forged. Reject it before probing: the probe,
|
|
43
|
-
// and the routed request that may follow, can carry HIPPO_API_KEY.
|
|
24
|
+
// The pid may have been reused and the recorded url is read from a forgeable file; serve() only binds loopback, so a url that is not http on a loopback
|
|
25
|
+
// host and the recorded port is malformed or forged. Reject it before probing, since the probe and any routed request can carry HIPPO_API_KEY.
|
|
44
26
|
let probeUrl;
|
|
45
27
|
try {
|
|
46
28
|
probeUrl = new URL(info.url);
|
|
@@ -54,9 +36,8 @@ function isLiveLoopbackTarget(info) {
|
|
|
54
36
|
}
|
|
55
37
|
/** The whole body as text, or null once it passes HEALTH_BODY_MAX_BYTES (the stream is then cancelled). */
|
|
56
38
|
async function readCappedBody(body) {
|
|
57
|
-
// Read the body under a hard byte cap
|
|
58
|
-
//
|
|
59
|
-
// its response is untrusted: never hand an unbounded stream to a parser.
|
|
39
|
+
// Read the body under a hard byte cap: the process on info.url may not be hippo (pid reuse), so its response is untrusted and never goes unbounded into a
|
|
40
|
+
// parser.
|
|
60
41
|
const reader = body.getReader();
|
|
61
42
|
const decoder = new TextDecoder();
|
|
62
43
|
let raw = '';
|
|
@@ -77,12 +58,8 @@ async function readCappedBody(body) {
|
|
|
77
58
|
}
|
|
78
59
|
/** True when /health on info.url reports the pidfile's started_at; unlinks the pidfile on any definitive mismatch. */
|
|
79
60
|
async function healthMatchesPidfile(hippoRoot, info) {
|
|
80
|
-
// Confirm the
|
|
81
|
-
//
|
|
82
|
-
// non-200, or a malformed body unlink the pidfile as stale. A probe timeout
|
|
83
|
-
// is deliberately left ambiguous: a live but momentarily-busy server (e.g.
|
|
84
|
-
// blocked on a synchronous query) can miss the 300ms window, so a timeout
|
|
85
|
-
// returns null WITHOUT unlinking. The pidfile survives for the next probe.
|
|
61
|
+
// Confirm the answering process is this server by matching /health `started_at` against the pidfile; refusal, non-200 or a malformed body unlink the
|
|
62
|
+
// pidfile as stale. A probe timeout is ambiguous (a live but busy server can miss the 300ms window), so it returns null WITHOUT unlinking.
|
|
86
63
|
try {
|
|
87
64
|
const res = await fetch(`${info.url}/health`, {
|
|
88
65
|
signal: AbortSignal.timeout(envHealthProbeMs() ?? HEALTH_PROBE_TIMEOUT_MS),
|
|
@@ -104,32 +81,16 @@ async function healthMatchesPidfile(hippoRoot, info) {
|
|
|
104
81
|
return true;
|
|
105
82
|
}
|
|
106
83
|
catch (err) {
|
|
107
|
-
// A timeout is ambiguous (the server may be
|
|
108
|
-
//
|
|
109
|
-
// definitive: unlink it as stale.
|
|
110
|
-
// SAFETY: err's shape is unknown (catch clause); reading an optional
|
|
111
|
-
// .name property structurally is safe regardless of the object's actual type.
|
|
84
|
+
// A timeout is ambiguous (the server may be busy), so keep the pidfile; any other failure (refused, malformed body) is definitive: unlink as stale.
|
|
85
|
+
// SAFETY: err's shape is unknown (catch clause); reading an optional .name property structurally is safe regardless of the actual type.
|
|
112
86
|
if (err?.name !== 'TimeoutError') {
|
|
113
87
|
removePidfile(hippoRoot);
|
|
114
88
|
}
|
|
115
89
|
return false;
|
|
116
90
|
}
|
|
117
91
|
}
|
|
118
|
-
/**
|
|
119
|
-
*
|
|
120
|
-
* server is genuinely answering on the recorded url. Returns null on missing,
|
|
121
|
-
* malformed, or stale pidfiles, and best-effort unlinks the file in the
|
|
122
|
-
* stale/malformed cases.
|
|
123
|
-
*
|
|
124
|
-
* Liveness is proven in two steps. `process.kill(pid, 0)` rules out dead
|
|
125
|
-
* pids. But a pid can be reused by an unrelated process, so a GET /health
|
|
126
|
-
* then confirms the process that answers is *this* hippo server: its
|
|
127
|
-
* `started_at` must equal the pidfile's. A mismatch, non-200, malformed
|
|
128
|
-
* body, or timeout all mean the pidfile is stale.
|
|
129
|
-
*
|
|
130
|
-
* The /health probe runs only when a pidfile exists and the pid is live, so
|
|
131
|
-
* the common no-server path stays a single fast file existence check.
|
|
132
|
-
*/
|
|
92
|
+
/** Returns the pidfile's ServerInfo if a live hippo server answers on the recorded url, else null (best-effort unlinking of missing/stale/malformed pidfiles).
|
|
93
|
+
* `process.kill(pid, 0)` rules out dead pids; GET /health must then return the pidfile's `started_at` (pids get reused). Probes only if the pid is live. */
|
|
133
94
|
export async function detectServer(hippoRoot) {
|
|
134
95
|
const path = join(hippoRoot, PIDFILE);
|
|
135
96
|
if (!existsSync(path))
|
|
@@ -148,14 +109,8 @@ export async function detectServer(hippoRoot) {
|
|
|
148
109
|
}
|
|
149
110
|
return (await healthMatchesPidfile(hippoRoot, info)) ? info : null;
|
|
150
111
|
}
|
|
151
|
-
/**
|
|
152
|
-
*
|
|
153
|
-
* renames into place, which is atomic on POSIX and on NTFS via MoveFileEx.
|
|
154
|
-
*
|
|
155
|
-
* `startedAt` is supplied by the caller (`serve()`) rather than generated
|
|
156
|
-
* here, so the pidfile and the server's GET /health response carry the same
|
|
157
|
-
* timestamp — detectServer's liveness probe compares the two for equality.
|
|
158
|
-
*/
|
|
112
|
+
/** Atomically writes the pidfile (process-scoped temp file, then rename; atomic on POSIX and NTFS). `startedAt` comes from the caller (`serve()`) so the
|
|
113
|
+
* pidfile and GET /health carry the same timestamp, which detectServer's liveness probe compares. */
|
|
159
114
|
export function writePidfile(hippoRoot, opts) {
|
|
160
115
|
const path = join(hippoRoot, PIDFILE);
|
|
161
116
|
const tmp = `${path}.tmp.${process.pid}`;
|
|
@@ -169,13 +124,8 @@ export function writePidfile(hippoRoot, opts) {
|
|
|
169
124
|
writeFileSync(tmp, JSON.stringify(info));
|
|
170
125
|
renameSync(tmp, path);
|
|
171
126
|
}
|
|
172
|
-
/**
|
|
173
|
-
*
|
|
174
|
-
* caller can use this in shutdown paths without fear of throwing.
|
|
175
|
-
*
|
|
176
|
-
* Identity-blind: deletes whatever pidfile is on disk. A shutdown path that
|
|
177
|
-
* must not clobber a newer server's pidfile should use removePidfileIfOwned.
|
|
178
|
-
*/
|
|
127
|
+
/** Best-effort pidfile removal, silent on any error so shutdown paths can call it. Identity-blind: a shutdown that must not clobber a newer server's pidfile
|
|
128
|
+
* uses removePidfileIfOwned. */
|
|
179
129
|
export function removePidfile(hippoRoot) {
|
|
180
130
|
const path = join(hippoRoot, PIDFILE);
|
|
181
131
|
try {
|
|
@@ -183,24 +133,8 @@ export function removePidfile(hippoRoot) {
|
|
|
183
133
|
}
|
|
184
134
|
catch { /* already gone or undeletable; the next detectServer probe re-checks */ }
|
|
185
135
|
}
|
|
186
|
-
/**
|
|
187
|
-
*
|
|
188
|
-
* Reads and parses the pidfile and unlinks it ONLY when both `pid` and
|
|
189
|
-
* `started_at` match `owner`. A pidfile rewritten by a newer server is left
|
|
190
|
-
* intact, so a shutting-down older server cannot orphan the newer one by
|
|
191
|
-
* deleting its pidfile out from under it.
|
|
192
|
-
*
|
|
193
|
-
* Best-effort and never throws: a missing, unreadable, malformed, or
|
|
194
|
-
* non-object pidfile (including a literal JSON `null`) is "not provably mine"
|
|
195
|
-
* and left alone — detectServer unlinks a malformed pidfile on its next
|
|
196
|
-
* probe, so it does not leak. Returns true iff a matching pidfile was removed.
|
|
197
|
-
*
|
|
198
|
-
* Residual TOCTOU: the pidfile could be rewritten between the read and the
|
|
199
|
-
* unlink. The window is microseconds and the shape is the same read-check-
|
|
200
|
-
* unlink detectServer already uses; this narrows the clobber from an
|
|
201
|
-
* unbounded window (any time between writePidfile and stop) to a negligible
|
|
202
|
-
* one.
|
|
203
|
-
*/
|
|
136
|
+
/** Removes the pidfile ONLY when both `pid` and `started_at` match `owner`, so an older shutting-down server cannot orphan a newer one; never throws.
|
|
137
|
+
* Anything unreadable or malformed is "not provably mine" and left alone (detectServer unlinks it). Returns true iff removed. */
|
|
204
138
|
export function removePidfileIfOwned(hippoRoot, owner) {
|
|
205
139
|
const path = join(hippoRoot, PIDFILE);
|
|
206
140
|
try {
|
|
@@ -23,7 +23,10 @@ function runInChild(job) {
|
|
|
23
23
|
const deadlineMs = envSleepTimeoutMs() ?? DEFAULT_SLEEP_DEADLINE_MS;
|
|
24
24
|
return new Promise((resolve, reject) => {
|
|
25
25
|
// The child's stderr is the server's log, so Node's SQLite notice would repeat there on every sleep.
|
|
26
|
-
const child = spawn(process.execPath, ['--disable-warning=ExperimentalWarning', CHILD_ENTRY], {
|
|
26
|
+
const child = spawn(process.execPath, ['--disable-warning=ExperimentalWarning', CHILD_ENTRY], {
|
|
27
|
+
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
|
|
28
|
+
windowsHide: true
|
|
29
|
+
});
|
|
27
30
|
let reply;
|
|
28
31
|
let timedOut = false;
|
|
29
32
|
// SIGKILL because the child is inside synchronous SQLite work and cannot run a handler; the OS drops its write lock.
|
package/dist/server/types.d.ts
CHANGED
|
@@ -7,17 +7,16 @@ export interface ServerHandle {
|
|
|
7
7
|
port: number;
|
|
8
8
|
url: string;
|
|
9
9
|
stop: () => Promise<void>;
|
|
10
|
-
/** Introspection-only: the underlying node:http Server,
|
|
11
|
-
*
|
|
12
|
-
* into serve()'s closure. Additive field — do not depend on it for control
|
|
13
|
-
* flow outside tests. */
|
|
10
|
+
/** Introspection-only: the underlying node:http Server, so tests can assert keep-alive/headers timeout hardening without reaching into serve()'s closure.
|
|
11
|
+
* Do not use for control flow. */
|
|
14
12
|
server?: import('node:http').Server;
|
|
15
13
|
}
|
|
16
14
|
/** Identity an {@link AuthResolver} vouches for. The core sanitises it before use. */
|
|
17
15
|
export interface ResolvedBearer {
|
|
18
16
|
tenantId: string;
|
|
19
17
|
subject: string;
|
|
20
|
-
/** Not 'admin' means 'member'. Admin is tenant-only, yet can mint member API keys (POST /v1/auth/keys);
|
|
18
|
+
/** Not 'admin' means 'member'. Admin is tenant-only, yet can mint member API keys (POST /v1/auth/keys);
|
|
19
|
+
* an add-on revokes them through the exported authRevoke when the IdP deprovisions the minter. */
|
|
21
20
|
role: 'admin' | 'member';
|
|
22
21
|
scopes?: readonly string[];
|
|
23
22
|
}
|
|
@@ -28,7 +27,8 @@ export interface AddonCall {
|
|
|
28
27
|
readonly ctx: Context;
|
|
29
28
|
readonly body: Readonly<Record<string, JsonValue>>;
|
|
30
29
|
}
|
|
31
|
-
/** A POST /v1 route an add-on mounts through serve(): core authenticates and parses first, then sends the
|
|
30
|
+
/** A POST /v1 route an add-on mounts through serve(): core authenticates and parses first, then sends the
|
|
31
|
+
* returned value as 200 JSON. Under another store it runs only when that store has its `storeReady` group. */
|
|
32
32
|
export interface AddonRoute {
|
|
33
33
|
readonly path: string;
|
|
34
34
|
readonly handler: (call: AddonCall) => Promise<JsonValue>;
|
|
@@ -46,7 +46,8 @@ export interface ServeOpts {
|
|
|
46
46
|
authResolverTimeoutMs?: number;
|
|
47
47
|
port?: number;
|
|
48
48
|
host?: string;
|
|
49
|
-
/** Stop and exit on SIGINT/SIGTERM, and drain then exit 1 on an uncaught exception or unhandled rejection.
|
|
49
|
+
/** Stop and exit on SIGINT/SIGTERM, and drain then exit 1 on an uncaught exception or unhandled rejection. A stop still running
|
|
50
|
+
* 10 s past `shutdownDrainMs` ends the process with a failure exit. Only `hippo serve` owns the process, so only it sets this. */
|
|
50
51
|
handleSignals?: boolean;
|
|
51
52
|
/** How long stop() lets in-flight requests finish before closing their sockets; defaults to 5000 ms. */
|
|
52
53
|
shutdownDrainMs?: number;
|
|
@@ -59,7 +60,8 @@ export interface ServeOpts {
|
|
|
59
60
|
mintBodyDeadlineMs?: number;
|
|
60
61
|
/** Tests only: shortens the wait for a signed webhook's body, which defaults to 10 s. */
|
|
61
62
|
webhookBodyDeadlineMs?: number;
|
|
62
|
-
/** PEM certificate and key: serve() then answers HTTPS only. Unset means cleartext
|
|
63
|
+
/** PEM certificate and key: serve() then answers HTTPS only. Unset means cleartext
|
|
64
|
+
* HTTP, which needs a TLS-terminating proxy in front on any non-loopback bind. */
|
|
63
65
|
tls?: {
|
|
64
66
|
cert: string | Buffer;
|
|
65
67
|
key: string | Buffer;
|
|
@@ -94,8 +96,8 @@ type StoreStatus = {
|
|
|
94
96
|
sqliteOnly: string;
|
|
95
97
|
storeReady?: never;
|
|
96
98
|
};
|
|
97
|
-
/** One /v1 route: an exact path, a matchPath pattern, or a regex, each paired with
|
|
98
|
-
*
|
|
99
|
+
/** One /v1 route: an exact path, a matchPath pattern, or a regex, each paired with one method's handler. Under another store it runs only with its
|
|
100
|
+
* store's `storeReady` group; `loop: 'off'` runs its SQLite work on a worker thread, so the handler opens no hippo.db on the server thread. */
|
|
99
101
|
export type Route = {
|
|
100
102
|
method: string;
|
|
101
103
|
loop?: 'off';
|
|
@@ -2,9 +2,11 @@ import type { IncomingMessage } from 'node:http';
|
|
|
2
2
|
import type { Context, RememberOpts } from '../api/index.js';
|
|
3
3
|
import { type JsonValue } from '../util/json.js';
|
|
4
4
|
export declare function isSetMember<T extends string>(set: ReadonlySet<T>, value: string): value is T;
|
|
5
|
+
export declare const MAX_SHORT_FIELD_LEN = 4096;
|
|
5
6
|
export declare const MAX_LIST_LIMIT = 1000;
|
|
6
7
|
export declare function parseListLimit(limitRaw: string | null, defaultLimit?: number, maxLimit?: number): number;
|
|
7
|
-
/** `_authed` is proof the caller passed auth, so a full-size body is read only for
|
|
8
|
+
/** `_authed` is proof the caller passed auth, so a full-size body is read only for
|
|
9
|
+
* an authenticated caller; the key mint reads first under its own small cap. */
|
|
8
10
|
export declare function parseJsonBody(req: IncomingMessage, _authed: Context): Promise<Record<string, JsonValue>>;
|
|
9
11
|
export declare function parseJsonObjectText(raw: string): Record<string, JsonValue>;
|
|
10
12
|
export declare function getString(obj: Record<string, JsonValue>, key: string): string | undefined;
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import { HttpError, MAX_ID_LEN, readBody } from '../util/http-util.js';
|
|
2
2
|
import { isJsonString, isJsonObject } from '../util/json.js';
|
|
3
|
-
// Runtime membership check for a `ReadonlySet<T>` of string-literal
|
|
4
|
-
//
|
|
5
|
-
// Set<T>.has(value: T) itself gives no narrowing (its parameter type is T,
|
|
6
|
-
// not a type predicate) so callers previously needed a separate `as T` cast
|
|
7
|
-
// at both the check and the later usage; this helper is the one place that
|
|
8
|
-
// assertion lives, so downstream call sites narrow via the `value is T`
|
|
9
|
-
// return instead of re-asserting.
|
|
3
|
+
// Runtime membership check for a `ReadonlySet<T>` of string-literal members: Set<T>.has gives no narrowing, so this is the one place the `as T` assertion lives
|
|
4
|
+
// and callers narrow via the `value is T` return.
|
|
10
5
|
export function isSetMember(set, value) {
|
|
11
|
-
// SAFETY: `value as T` is discarded unless `set.has` (the real runtime
|
|
12
|
-
// check) confirms membership; the `value is T` return type is what
|
|
13
|
-
// performs the actual narrowing for callers.
|
|
6
|
+
// SAFETY: `value as T` is discarded unless `set.has` (the real runtime check) confirms membership; the `value is T` return type does the narrowing.
|
|
14
7
|
return set.has(value);
|
|
15
8
|
}
|
|
9
|
+
// Cap for short free-text HTTP fields (names, text, context, change summaries) on the object routes.
|
|
10
|
+
export const MAX_SHORT_FIELD_LEN = 4096;
|
|
16
11
|
// Number.isInteger, not isFinite: SQLite `LIMIT ?` rejects "1.5" with a 500.
|
|
17
12
|
// Shared by every first-class-object list route so the guard cannot drift.
|
|
18
13
|
export const MAX_LIST_LIMIT = 1000;
|
|
@@ -25,7 +20,8 @@ export function parseListLimit(limitRaw, defaultLimit = 100, maxLimit = MAX_LIST
|
|
|
25
20
|
}
|
|
26
21
|
return limit;
|
|
27
22
|
}
|
|
28
|
-
/** `_authed` is proof the caller passed auth, so a full-size body is read only for
|
|
23
|
+
/** `_authed` is proof the caller passed auth, so a full-size body is read only for
|
|
24
|
+
* an authenticated caller; the key mint reads first under its own small cap. */
|
|
29
25
|
export async function parseJsonBody(req, _authed) {
|
|
30
26
|
return parseJsonObjectText(await readBody(req));
|
|
31
27
|
}
|
|
@@ -72,18 +68,9 @@ export function getCallerProject(body) {
|
|
|
72
68
|
}
|
|
73
69
|
return { name: v.name, aliases: v.aliases };
|
|
74
70
|
}
|
|
75
|
-
/**
|
|
76
|
-
*
|
|
77
|
-
|
|
78
|
-
* ids with a useful 400 instead of silently falling through to "not found".
|
|
79
|
-
*
|
|
80
|
-
* Allowed charset matches all production id shapes Hippo emits: `mem_<hex>`,
|
|
81
|
-
* `sum_<hex>`, `sess-<id>`, Slack bot ids like `B01ABCD`, etc. The `:` and
|
|
82
|
-
* `.` are allowed for forward-compat. The `/` is intentionally absent —
|
|
83
|
-
* Hippo never emits ids with slashes, and `rejectEncodedSlash` already
|
|
84
|
-
* stops `%2F`-smuggled ones at the front door.
|
|
85
|
-
*/
|
|
86
|
-
const ID_SEGMENT_RE = /^[A-Za-z0-9_:.\-]+$/;
|
|
71
|
+
/** Charset + length validation for `:id` captures, called right after `matchPath` so empty/overlong/illegal ids get a 400, not "not found".
|
|
72
|
+
* Allows every production id shape (`mem_<hex>`, `sess-<id>`, Slack ids) plus `:` and `.`; no `/`, since `rejectEncodedSlash` stops `%2F` smuggling. */
|
|
73
|
+
const ID_SEGMENT_RE = /^[A-Za-z0-9_:.-]+$/;
|
|
87
74
|
export function validateIdSegment(id, fieldName) {
|
|
88
75
|
if (id.length === 0)
|
|
89
76
|
throw new HttpError(400, `${fieldName} is required`);
|
package/dist/server.d.ts
CHANGED
|
@@ -35,12 +35,12 @@ export type { AmbientLoadResult, AmbientRecallRequest, ContextCandidateFilter, R
|
|
|
35
35
|
export type { AmbientStoreFilter } from './store/ambient.js';
|
|
36
36
|
export type { AmbientTallies } from './core/ambient.js';
|
|
37
37
|
export type { TokenUse } from './store/token-ledger.js';
|
|
38
|
-
export type { EmbeddingIndexState } from './store/
|
|
38
|
+
export type { EmbeddingIndexState } from './store/vector-index.js';
|
|
39
39
|
export type { PhysicsParticle } from './core/physics.js';
|
|
40
40
|
export { StoreBusyError } from './db/index.js';
|
|
41
41
|
export { decodeVector, EMBEDDING_MODEL_META_KEY, encodeVector, rankVectorRows, type VectorMatch, type VectorRow } from './db/vector-store.js';
|
|
42
42
|
export { bufferToFloat32, float32ToBuffer } from './db/physics-state.js';
|
|
43
|
-
export { replacesIndex } from './store/
|
|
43
|
+
export { replacesIndex } from './store/vector-index.js';
|
|
44
44
|
export { passesScopeFilterForRecall, RECALL_DEFAULT_DENY_SCOPES } from './store/recall-scope.js';
|
|
45
45
|
export { SECRET_TAGS } from './util/secret-detect.js';
|
|
46
46
|
export { tallyAmbientEntries } from './core/ambient.js';
|
package/dist/server.js
CHANGED
|
@@ -9,7 +9,8 @@ export { isCrossSite, LOOPBACK_HOST_HEADER } from './util/http-util.js';
|
|
|
9
9
|
export { __resetSessionRecallHistoryHttp } from './server/routes/recall.js';
|
|
10
10
|
export { clientIpForRateLimit } from './server/client-ip.js';
|
|
11
11
|
export { isLoopback, isReservedActor } from './server/auth.js';
|
|
12
|
-
// What an add-on route handler needs: HttpError for its 4xx replies, promptHookContext
|
|
12
|
+
// What an add-on route handler needs: HttpError for its 4xx replies, promptHookContext
|
|
13
|
+
// for a caller that renders the prompt hook elsewhere, JsonValue for its body.
|
|
13
14
|
export { HttpError } from './util/http-util.js';
|
|
14
15
|
export { promptHookContext } from './api/prompt-hook.js';
|
|
15
16
|
// A session-end route stores the turns its caller read from a transcript on the caller's own machine.
|
|
@@ -26,7 +27,7 @@ export { StoreBusyError } from './db/index.js';
|
|
|
26
27
|
// so both stores keep the same bytes and return the same ids in the same order.
|
|
27
28
|
export { decodeVector, EMBEDDING_MODEL_META_KEY, encodeVector, rankVectorRows } from './db/vector-store.js';
|
|
28
29
|
export { bufferToFloat32, float32ToBuffer } from './db/physics-state.js';
|
|
29
|
-
export { replacesIndex } from './store/
|
|
30
|
+
export { replacesIndex } from './store/vector-index.js';
|
|
30
31
|
// An add-on's ContextReads applies hippo.db's scope, secret, tally and rarest-term rules with the same code.
|
|
31
32
|
export { passesScopeFilterForRecall, RECALL_DEFAULT_DENY_SCOPES } from './store/recall-scope.js';
|
|
32
33
|
export { SECRET_TAGS } from './util/secret-detect.js';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MemoryEntry } from '../core/memory.js';
|
|
2
|
+
import type { DatabaseSyncLike } from '../db/index.js';
|
|
3
|
+
/** Returns the path to the global Hippo store.
|
|
4
|
+
* Resolution order: $HIPPO_HOME > $XDG_DATA_HOME/hippo > ~/.hippo/ */
|
|
5
|
+
export declare function getGlobalRoot(): string;
|
|
6
|
+
/** Ensure the global store exists. */
|
|
7
|
+
export declare function initGlobal(): void;
|
|
8
|
+
/** Copies a local memory to the global store and returns the copy, which gets a new `g_` id so it cannot collide. */
|
|
9
|
+
export declare function promoteToGlobal(localRoot: string, id: string, opts?: {
|
|
10
|
+
actor?: string;
|
|
11
|
+
tenantId?: string;
|
|
12
|
+
afterWrite?: (db: DatabaseSyncLike, globalId: string) => void;
|
|
13
|
+
/** Also writes one `promote` audit row for the copy ({sourceId}), in the copy's own transaction. */
|
|
14
|
+
auditAs?: {
|
|
15
|
+
tenantId: string;
|
|
16
|
+
actor: string;
|
|
17
|
+
};
|
|
18
|
+
}): MemoryEntry;
|
|
19
|
+
//# sourceMappingURL=global-store.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// The global store: where it lives, creating it, and copying a local memory into it.
|
|
2
|
+
import { BadRequestError, NotFoundError } from '../core/api-errors.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { generateId } from '../core/memory.js';
|
|
5
|
+
import { initStore } from '../store/open.js';
|
|
6
|
+
import { writeEntry } from '../store/entry-writes.js';
|
|
7
|
+
import { readEntry } from '../store/entry-reads.js';
|
|
8
|
+
import { isPersonalScope } from '../store/recall-scope.js';
|
|
9
|
+
import { fallbackOrigin, resolveGlobalRootDir } from '../core/project-identity.js';
|
|
10
|
+
import { isSharedStore } from '../core/config.js';
|
|
11
|
+
import { detectSecret } from '../util/secret-detect.js';
|
|
12
|
+
import { isQuarantineScope } from '../trust/quarantine.js';
|
|
13
|
+
import { embedMemory } from '../store/embeddings/index.js';
|
|
14
|
+
import { appendAuditEvent } from '../store/audit.js';
|
|
15
|
+
/** Returns the path to the global Hippo store.
|
|
16
|
+
* Resolution order: $HIPPO_HOME > $XDG_DATA_HOME/hippo > ~/.hippo/ */
|
|
17
|
+
export function getGlobalRoot() {
|
|
18
|
+
// Single source of truth lives in project-identity.ts (leaf) so db migrations
|
|
19
|
+
// can resolve the same path without a shared.ts import cycle.
|
|
20
|
+
return resolveGlobalRootDir();
|
|
21
|
+
}
|
|
22
|
+
/** Ensure the global store exists. */
|
|
23
|
+
export function initGlobal() {
|
|
24
|
+
const globalRoot = getGlobalRoot();
|
|
25
|
+
if (!fs.existsSync(globalRoot)) {
|
|
26
|
+
initStore(globalRoot);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Ensure subdirectories exist in case partially initialized
|
|
30
|
+
initStore(globalRoot);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The copy's write hook: the `promote` row when asked for, then the caller's own hook, both in the copy's transaction. */
|
|
34
|
+
function promoteHook(sourceId, auditAs, afterWrite) {
|
|
35
|
+
if (!auditAs)
|
|
36
|
+
return afterWrite;
|
|
37
|
+
return (db, globalId) => {
|
|
38
|
+
appendAuditEvent(db, { tenantId: auditAs.tenantId, actor: auditAs.actor, op: 'promote', targetId: globalId, metadata: { sourceId } });
|
|
39
|
+
afterWrite?.(db, globalId);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Copies a local memory to the global store and returns the copy, which gets a new `g_` id so it cannot collide. */
|
|
43
|
+
export function promoteToGlobal(localRoot, id, opts) {
|
|
44
|
+
const entry = readEntry(localRoot, id, opts?.tenantId);
|
|
45
|
+
if (!entry)
|
|
46
|
+
throw new NotFoundError(`Memory not found: ${id}`);
|
|
47
|
+
// Same quarantine veto as shareMemory; a promoted copy would have no quarantine record to review.
|
|
48
|
+
if (isQuarantineScope(entry.scope)) {
|
|
49
|
+
throw new BadRequestError(`Refusing to promote ${id}: it is quarantined pending review. Approve it first via 'hippo quarantine approve ${id}'.`);
|
|
50
|
+
}
|
|
51
|
+
if (isPersonalScope(entry.scope ?? null)) {
|
|
52
|
+
throw new BadRequestError(`Refusing to promote ${id}: it is a personal memory and stays with its owner on this server.`);
|
|
53
|
+
}
|
|
54
|
+
// Secret producer veto: promote is a producer path to the global store
|
|
55
|
+
// exactly like shareMemory - same hard rule.
|
|
56
|
+
const promoteSecret = detectSecret(entry);
|
|
57
|
+
if (promoteSecret.flagged) {
|
|
58
|
+
throw new BadRequestError(`Refusing to promote ${id} to the global store: content matches secret material (${promoteSecret.reason}). ` +
|
|
59
|
+
`Secrets stay in their owning project's store.`);
|
|
60
|
+
}
|
|
61
|
+
initGlobal();
|
|
62
|
+
const globalRoot = getGlobalRoot();
|
|
63
|
+
// A project store's NULL row gets its folder back; a shared store's folder is no caller's project, so NULL stays and the label names no path.
|
|
64
|
+
const globalEntry = {
|
|
65
|
+
...entry,
|
|
66
|
+
id: generateId('g'),
|
|
67
|
+
source: isSharedStore(localRoot) ? `shared::${new Date().toISOString()}` : `promoted:${localRoot}`,
|
|
68
|
+
origin_project: entry.origin_project ?? fallbackOrigin(localRoot),
|
|
69
|
+
};
|
|
70
|
+
writeEntry(globalRoot, globalEntry, { actor: opts?.actor, afterWrite: promoteHook(id, opts?.auditAs, opts?.afterWrite) });
|
|
71
|
+
// Fire-and-forget: embedMemory gates on availability and never rejects.
|
|
72
|
+
void embedMemory(globalRoot, globalEntry);
|
|
73
|
+
return globalEntry;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=global-store.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Copy all global memories into the local store, skipping entries that already exist locally by ID or text (promote and share copy under a new ID).
|
|
2
|
+
* Returns the count of newly copied entries. */
|
|
3
|
+
export declare function syncGlobalToLocal(localRoot: string, globalRoot: string, opts?: {
|
|
4
|
+
includeCrossProject?: boolean;
|
|
5
|
+
}): number;
|
|
6
|
+
//# sourceMappingURL=global-sync.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Copying the global store's memories down into a local store.
|
|
2
|
+
import { BadRequestError } from '../core/api-errors.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { AGENT_MEMORY_SOURCE_PREFIX } from '../core/agent-memory-tools.js';
|
|
6
|
+
import { writeEntry } from '../store/entry-writes.js';
|
|
7
|
+
import { loadAllEntries } from '../store/entry-reads.js';
|
|
8
|
+
import { classifyOriginProject, resolveProjectIdentity } from '../core/project-identity.js';
|
|
9
|
+
import { isSharedStore } from '../core/config.js';
|
|
10
|
+
import { detectSecret } from '../util/secret-detect.js';
|
|
11
|
+
import { RejectedValueError } from '../store/rejection.js';
|
|
12
|
+
import { embedAll } from '../store/embeddings/index.js';
|
|
13
|
+
import { log } from '../util/log.js';
|
|
14
|
+
import { logEmbedAllFailure } from './search-both.js';
|
|
15
|
+
/** Copy all global memories into the local store, skipping entries that already exist locally by ID or text (promote and share copy under a new ID).
|
|
16
|
+
* Returns the count of newly copied entries. */
|
|
17
|
+
export function syncGlobalToLocal(localRoot, globalRoot, opts = {}) {
|
|
18
|
+
if (isSharedStore(localRoot)) {
|
|
19
|
+
throw new BadRequestError(`Refusing to sync into ${localRoot}: a shared store takes no copies of a personal global store, whose rows would reach every member.`);
|
|
20
|
+
}
|
|
21
|
+
if (!fs.existsSync(globalRoot))
|
|
22
|
+
return 0;
|
|
23
|
+
// Host-wide read: the global union is copied into a tenant-scoped local store, and writeEntry carries the tenant if the local-root context has one.
|
|
24
|
+
const globalEntries = loadAllEntries(globalRoot);
|
|
25
|
+
const textKey = (e) => `${e.tenantId}\n${e.content}`;
|
|
26
|
+
const localEntries = loadAllEntries(localRoot);
|
|
27
|
+
const localIds = new Set(localEntries.map((e) => e.id));
|
|
28
|
+
const localText = new Set(localEntries.map(textKey));
|
|
29
|
+
// Syncing down must not re-import what ambient context excludes: other-project rows are skipped by default and secret rows never copied.
|
|
30
|
+
// origin_project is preserved on the copy (writeEntry stamps it only when missing).
|
|
31
|
+
const currentProject = resolveProjectIdentity(path.dirname(path.resolve(localRoot)));
|
|
32
|
+
let count = 0;
|
|
33
|
+
// A locally rejected value must not come back through sync down: caught per item, printed as one line.
|
|
34
|
+
let rejected = 0;
|
|
35
|
+
for (const entry of globalEntries) {
|
|
36
|
+
// Skip if already present by ID
|
|
37
|
+
if (localIds.has(entry.id))
|
|
38
|
+
continue;
|
|
39
|
+
// Only the global store's user pass sets an imported note's row aside, so a copy would outlive the note.
|
|
40
|
+
if (entry.source.startsWith(AGENT_MEMORY_SOURCE_PREFIX))
|
|
41
|
+
continue;
|
|
42
|
+
if (localText.has(textKey(entry)))
|
|
43
|
+
continue;
|
|
44
|
+
if (detectSecret(entry).flagged)
|
|
45
|
+
continue;
|
|
46
|
+
if (!opts.includeCrossProject && classifyOriginProject(entry.origin_project, currentProject) === 'cross-project')
|
|
47
|
+
continue;
|
|
48
|
+
if (!writeUnlessRejected(localRoot, entry)) {
|
|
49
|
+
rejected++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
localText.add(textKey(entry));
|
|
53
|
+
count++;
|
|
54
|
+
}
|
|
55
|
+
finishSyncDown(localRoot, count, rejected);
|
|
56
|
+
return count;
|
|
57
|
+
}
|
|
58
|
+
/** False when the local store rejects the value; any other failure still throws. */
|
|
59
|
+
function writeUnlessRejected(localRoot, entry) {
|
|
60
|
+
try {
|
|
61
|
+
writeEntry(localRoot, entry);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (err instanceof RejectedValueError)
|
|
66
|
+
return false;
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function finishSyncDown(localRoot, count, rejected) {
|
|
71
|
+
if (rejected > 0) {
|
|
72
|
+
log.warn(`syncGlobalToLocal: skipped ${rejected} rejected value(s) (run \`hippo unreject\` on the local store to allow).`);
|
|
73
|
+
}
|
|
74
|
+
// Batch producer: one embedAll() on the destination rather than an
|
|
75
|
+
// embedMemory() per copied row (same batching invariant as autoShare).
|
|
76
|
+
if (count > 0) {
|
|
77
|
+
void embedAll(localRoot).catch((err) => logEmbedAllFailure('syncGlobalToLocal', err));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=global-sync.js.map
|
|
@@ -59,15 +59,14 @@ export declare function mergeProjects(db: DatabaseSyncLike, hippoRoot: string, o
|
|
|
59
59
|
export declare function namesFoldedInto(db: DatabaseSyncLike, tenantId: string, names: readonly string[]): string[];
|
|
60
60
|
/** Reads only, so doctor and a dry run take no write lock; merged rows are planned before any fold, so a few may re-tag differently once folds apply. */
|
|
61
61
|
export declare function planProjectRepair(db: DatabaseSyncLike, hippoRoot: string, tenantId: string, globalFolds?: boolean): Omit<RepairResult, 'backup'>;
|
|
62
|
-
/** Sets aside stray imports, folds the names the resolver now maps elsewhere, then
|
|
62
|
+
/** Sets aside stray imports, folds the names the resolver now maps elsewhere, then
|
|
63
|
+
* re-tags sleep's user-global merges by their parents; a dry run only plans. */
|
|
63
64
|
export declare function repairProjects(db: DatabaseSyncLike, hippoRoot: string, opts: {
|
|
64
65
|
tenantId: string;
|
|
65
66
|
dryRun: boolean;
|
|
66
67
|
globalFolds?: boolean;
|
|
67
68
|
}): RepairResult;
|
|
68
|
-
/**
|
|
69
|
-
*
|
|
70
|
-
* with `hippo projects repair`: their evidence is compaction folders, blind to a same-named repo that never compacted.
|
|
71
|
-
*/
|
|
69
|
+
/** Sleep runs repair once per store, so an upgrade needs no command. Global-store folds stay
|
|
70
|
+
* with `hippo projects repair`: their evidence is compaction folders, blind to a same-named repo that never compacted. */
|
|
72
71
|
export declare function repairOnceOnSleep(db: DatabaseSyncLike, hippoRoot: string, tenantId: string): RepairResult | null;
|
|
73
72
|
//# sourceMappingURL=project-merge.d.ts.map
|
|
@@ -115,7 +115,8 @@ function importCopies(db, tenantId) {
|
|
|
115
115
|
const userGlobal = new Set(live.filter((e) => e.origin_project === '').map((e) => duplicateKey(e.content)));
|
|
116
116
|
return live.filter((e) => e.origin_project && e.kind !== 'raw' && !e.pinned && toolTag(e.source) !== null && userGlobal.has(duplicateKey(e.content)));
|
|
117
117
|
}
|
|
118
|
-
/** Imports to set aside. The global store also checks each Claude session folder a compaction recorded: its
|
|
118
|
+
/** Imports to set aside. The global store also checks each Claude session folder a compaction recorded: its
|
|
119
|
+
* notes under any other project are misfiled, edited or not, and a text copy in the right folder is kept. */
|
|
119
120
|
function strayImports(db, hippoRoot, tenantId) {
|
|
120
121
|
const copies = importCopies(db, tenantId);
|
|
121
122
|
if (!isGlobalStoreRoot(hippoRoot))
|
|
@@ -187,7 +188,9 @@ function ownLegacyFold(db, hippoRoot, tenantId) {
|
|
|
187
188
|
const { name, legacyName } = resolveProjectIdentity(path.dirname(path.resolve(hippoRoot)));
|
|
188
189
|
if (legacyName === '' || legacyName === name)
|
|
189
190
|
return [];
|
|
190
|
-
const held = holdsOrigin(db, 'memories', tenantId, legacyName)
|
|
191
|
+
const held = holdsOrigin(db, 'memories', tenantId, legacyName)
|
|
192
|
+
|| holdsOrigin(db, 'compactions', tenantId, legacyName)
|
|
193
|
+
|| listDormantSnapshots(db, tenantId).some((s) => s.entry.origin_project === legacyName);
|
|
191
194
|
return held ? [{ from: legacyName, into: name }] : [];
|
|
192
195
|
}
|
|
193
196
|
function foldOf(value) {
|
|
@@ -253,7 +256,8 @@ function planUserGlobalRepair(db, tenantId, folds) {
|
|
|
253
256
|
}
|
|
254
257
|
return { toProject, setAside, untraced };
|
|
255
258
|
}
|
|
256
|
-
/** Sets aside stray imports, folds the names the resolver now maps elsewhere, then
|
|
259
|
+
/** Sets aside stray imports, folds the names the resolver now maps elsewhere, then
|
|
260
|
+
* re-tags sleep's user-global merges by their parents; a dry run only plans. */
|
|
257
261
|
export function repairProjects(db, hippoRoot, opts) {
|
|
258
262
|
const { tenantId, dryRun, globalFolds = true } = opts;
|
|
259
263
|
if (dryRun)
|
|
@@ -290,10 +294,8 @@ const AUTO_REPAIR_META_KEY = 'project_repair_auto';
|
|
|
290
294
|
function repairIsEmpty(r) {
|
|
291
295
|
return r.copies.length + r.folds.length + r.toProject.length + r.setAside.length === 0;
|
|
292
296
|
}
|
|
293
|
-
/**
|
|
294
|
-
*
|
|
295
|
-
* with `hippo projects repair`: their evidence is compaction folders, blind to a same-named repo that never compacted.
|
|
296
|
-
*/
|
|
297
|
+
/** Sleep runs repair once per store, so an upgrade needs no command. Global-store folds stay
|
|
298
|
+
* with `hippo projects repair`: their evidence is compaction folders, blind to a same-named repo that never compacted. */
|
|
297
299
|
export function repairOnceOnSleep(db, hippoRoot, tenantId) {
|
|
298
300
|
if (getMeta(db, AUTO_REPAIR_META_KEY) === '1')
|
|
299
301
|
return null;
|