hippo-memory 1.71.0 → 1.72.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/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +6 -21
- 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 +1 -1
- package/dist/api/audit.d.ts +29 -1
- package/dist/api/audit.js +44 -5
- package/dist/api/auth.d.ts +7 -4
- package/dist/api/auth.js +12 -8
- 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-render.js +4 -3
- package/dist/api/context-select.js +9 -11
- package/dist/api/context.js +17 -8
- 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 +1 -1
- 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 +6 -2
- package/dist/api/forget.js +18 -7
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- 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 +4 -0
- package/dist/api/learn.js +53 -27
- package/dist/api/ledger-db.d.ts +2 -6
- package/dist/api/ledger-db.js +4 -36
- package/dist/api/memories.d.ts +19 -1
- package/dist/api/memories.js +39 -0
- package/dist/api/objects.d.ts +1 -1
- package/dist/api/outcome.js +1 -1
- 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 +6 -0
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.js +1 -1
- package/dist/api/prompt-hook.d.ts +15 -2
- package/dist/api/prompt-hook.js +44 -4
- package/dist/api/recall-cli.d.ts +3 -0
- package/dist/api/recall-cli.js +13 -4
- package/dist/api/recall-core.js +3 -3
- package/dist/api/recall-pipeline.js +6 -7
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall.d.ts +0 -3
- package/dist/api/recall.js +19 -44
- package/dist/api/remember-local.js +1 -1
- package/dist/api/remember.d.ts +2 -1
- package/dist/api/remember.js +3 -2
- package/dist/api/session-end.d.ts +22 -0
- package/dist/api/session-end.js +101 -0
- package/dist/api/sleep-run.d.ts +1 -1
- package/dist/api/sleep-run.js +13 -9
- 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 +1 -1
- package/dist/api/types.d.ts +2 -0
- 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 +4 -2
- package/dist/capture/compaction-spool.js +20 -6
- 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 +2 -1
- package/dist/capture/session-worker.js +3 -4
- 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 +13 -13
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +12 -13
- 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 +5 -0
- package/dist/cli/client.js +24 -8
- package/dist/cli/compact-resume-payload.js +1 -1
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +12 -12
- package/dist/cli/continuity.d.ts +1 -1
- package/dist/cli/continuity.js +36 -39
- package/dist/cli/curate.d.ts +1 -1
- package/dist/cli/curate.js +23 -27
- 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 +4 -281
- 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 +3 -5
- package/dist/cli/hook-runtime.js +7 -34
- 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/lenient-id.d.ts +2 -0
- package/dist/cli/lenient-id.js +13 -0
- 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/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 +175 -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 +17 -17
- package/dist/cli/remember.js +12 -12
- package/dist/cli/scheduler.js +2 -1
- package/dist/cli/serve.js +3 -3
- package/dist/cli/session-hooks.d.ts +1 -1
- package/dist/cli/session-hooks.js +45 -115
- 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 +1 -1
- package/dist/cli/transfer.js +33 -31
- package/dist/cli/usage.d.ts +0 -79
- package/dist/cli/usage.js +1 -695
- package/dist/cli/verb-row.d.ts +32 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +232 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +244 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +254 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +312 -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 +23 -313
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +37 -3
- package/dist/connectors/github/backfill.js +12 -3
- package/dist/connectors/github/dlq.js +31 -73
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +3 -28
- package/dist/connectors/github/webhook.d.ts +2 -1
- package/dist/connectors/github/webhook.js +33 -2
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +28 -0
- package/dist/connectors/slack/dlq.js +49 -71
- package/dist/connectors/slack/ingest.d.ts +2 -6
- package/dist/connectors/slack/ingest.js +2 -27
- package/dist/connectors/slack/webhook.d.ts +2 -1
- package/dist/connectors/slack/webhook.js +2 -1
- package/dist/consolidate/conflicts.js +1 -1
- package/dist/consolidate/dag.js +15 -9
- package/dist/consolidate/dedupe.d.ts +7 -0
- package/dist/consolidate/dedupe.js +5 -3
- package/dist/consolidate/llm-passes.js +45 -19
- package/dist/consolidate/memory-value.js +2 -1
- package/dist/consolidate/merge.js +2 -2
- 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 +8 -5
- package/dist/consolidate/traces.js +3 -3
- 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 +7 -2
- 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 +2 -2
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory.d.ts +10 -4
- package/dist/core/memory.js +25 -18
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +1 -1
- package/dist/core/physics.js +6 -16
- 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 +10 -1
- package/dist/{store → core}/recall-scope.d.ts +1 -10
- package/dist/{store → core}/recall-scope.js +2 -19
- package/dist/db/busy.d.ts +2 -7
- package/dist/db/busy.js +21 -26
- package/dist/db/connect.d.ts +0 -1
- package/dist/db/connect.js +5 -6
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- 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.js +3 -3
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.js +17 -4
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.js +11 -8
- 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 +18 -15
- 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/eval/eval-suite.js +17 -11
- package/dist/eval/eval.js +1 -1
- package/dist/eval/judgment.js +11 -4
- 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 +4 -2
- 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 +1 -1
- package/dist/importers/sources.js +5 -4
- package/dist/importers/vault.js +7 -5
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/learn/autolearn.d.ts +10 -2
- package/dist/learn/autolearn.js +32 -12
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +6 -4
- package/dist/learn/forward-claim-detector.js +4 -2
- package/dist/learn/invalidation.js +10 -6
- 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.js +3 -1
- 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 +2 -1
- package/dist/mcp/stdio.js +24 -8
- 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 +63 -97
- 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 +9 -0
- package/dist/search/embed-memories.js +377 -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 +10 -13
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +17 -7
- package/dist/server/boot.js +7 -66
- package/dist/server/client-ip.d.ts +0 -2
- package/dist/server/client-ip.js +3 -2
- 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 -132
- 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 +15 -38
- 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/types.d.ts +22 -10
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +6 -11
- package/dist/server.d.ts +5 -4
- package/dist/server.js +5 -4
- package/dist/sharing/global-store.js +2 -2
- 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 +1 -1
- package/dist/sharing/share.d.ts +2 -0
- package/dist/sharing/share.js +37 -34
- package/dist/store/ambient.js +5 -6
- 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 +42 -23
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/cards.js +1 -1
- 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 +417 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.js +7 -4
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +32 -0
- package/dist/store/connectors/github.d.ts +7 -9
- package/dist/store/connectors/github.js +30 -53
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +18 -47
- package/dist/store/dashboard-reads.js +7 -6
- package/dist/store/delete-and-batch.d.ts +6 -0
- package/dist/store/delete-and-batch.js +36 -3
- package/dist/store/delivery-recorder.d.ts +10 -3
- package/dist/store/delivery-recorder.js +12 -5
- package/dist/store/descendant-page.js +6 -3
- package/dist/store/dormant.d.ts +1 -1
- package/dist/store/dormant.js +3 -1
- package/dist/store/embeddings/index.d.ts +2 -12
- package/dist/store/embeddings/index.js +5 -374
- package/dist/store/entry-reads.d.ts +13 -4
- package/dist/store/entry-reads.js +47 -11
- package/dist/store/entry-writes.d.ts +5 -5
- package/dist/store/entry-writes.js +32 -12
- 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 +20 -18
- package/dist/store/graph-reads.js +4 -2
- package/dist/store/graph-writes.d.ts +6 -6
- package/dist/store/graph-writes.js +48 -71
- package/dist/store/handoffs.d.ts +1 -1
- package/dist/store/handoffs.js +6 -6
- package/dist/store/index-and-stats.js +2 -2
- 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 +10 -6
- package/dist/store/open.d.ts +0 -4
- package/dist/store/open.js +40 -53
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/port.d.ts +9 -3
- 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/quarantine.js +2 -1
- package/dist/store/recall-trace.d.ts +2 -0
- package/dist/store/recall-trace.js +18 -2
- package/dist/store/rejected-values.js +2 -1
- 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/rule-sql.d.ts +9 -0
- package/dist/store/rule-sql.js +21 -2
- package/dist/store/search-rows.js +9 -4
- 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 +3 -3
- package/dist/store/sqlite/entry-writes-group.js +2 -2
- 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 +9 -0
- package/dist/store/sqlite/held-connection.js +41 -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 +1 -1
- package/dist/store/sqlite/store.js +14 -12
- package/dist/store/summaries.d.ts +3 -3
- package/dist/store/summaries.js +5 -4
- package/dist/store/token-ledger.d.ts +0 -7
- package/dist/store/token-ledger.js +0 -35
- package/dist/store/vector-index.js +3 -2
- 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 +3 -0
- package/dist/util/anthropic-messages.js +22 -5
- 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 +2 -1
- package/dist/util/env.js +2 -1
- package/dist/util/format.d.ts +3 -0
- package/dist/util/format.js +6 -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 +3 -1
- package/dist/util/request-scope.js +11 -6
- package/dist/util/secret-detect.js +6 -1
- 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/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 +2 -2
- 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/search/vector.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { cosineOf
|
|
1
|
+
import { cosineOf } from '../core/cosine.js';
|
|
2
|
+
import { indexNeedsRebuild } from '../store/embeddings/index.js';
|
|
2
3
|
import { indexedModel } from '../store/vector-index.js';
|
|
3
|
-
import { resolveEmbeddingProvider } from '../
|
|
4
|
-
import { rethrowIfSqliteBlocked } from '../
|
|
4
|
+
import { resolveEmbeddingProvider } from '../embeddings/provider.js';
|
|
5
|
+
import { rethrowIfSqliteBlocked } from '../util/sqlite-blocked.js';
|
|
5
6
|
import { errorMessage, log } from '../util/log.js';
|
|
6
7
|
import { envQueryEmbedTimeoutMs } from '../util/env.js';
|
|
7
|
-
import { requireGroup
|
|
8
|
+
import { requireGroup } from '../store/index.js';
|
|
8
9
|
import { redactSecretsStrict } from '../util/secret-detect.js';
|
|
9
10
|
import { currentEntries } from './as-of.js';
|
|
10
11
|
// Jev's default budget (rerankers/jev.ts): each is one off-box call that a recall waits on.
|
|
@@ -17,11 +18,8 @@ function queryEmbedBudgetMs() {
|
|
|
17
18
|
export function startQueryEmbedDeadline() {
|
|
18
19
|
return AbortSignal.timeout(queryEmbedBudgetMs());
|
|
19
20
|
}
|
|
20
|
-
/** The query's vector, or null when
|
|
21
|
+
/** The query's vector, or null when the provider outlasts `deadline`: an API call, or a local model still downloading. Any other failure throws. */
|
|
21
22
|
export async function embedQueryBy(deadline, provider, query) {
|
|
22
|
-
// No signal stops an in-process model, so the local provider is not held to the deadline.
|
|
23
|
-
if (provider.kind === 'local')
|
|
24
|
-
return (await provider.embed([query], 'query'))[0] ?? [];
|
|
25
23
|
try {
|
|
26
24
|
return (await provider.embed([query], 'query', { signal: deadline }))[0] ?? [];
|
|
27
25
|
}
|
|
@@ -54,12 +52,12 @@ export async function vectorCandidatesOutside(reads, entries, queryVector, spec)
|
|
|
54
52
|
return (await reads.nearestEntries(queryVector, stored)).filter((e) => !inPool.has(e.id) && (admit?.(e) ?? true));
|
|
55
53
|
}
|
|
56
54
|
/** Embeds the query and loads stored vectors; any failure leaves BM25 to rank alone. */
|
|
57
|
-
export async function resolveVectorArm(query, entries, options) {
|
|
55
|
+
export async function resolveVectorArm(query, entries, source, options) {
|
|
58
56
|
const arm = { entries, addedRows: false, useEmbeddings: false, embeddingIndex: {}, queryVector: [] };
|
|
59
|
-
if (!
|
|
57
|
+
if (!source)
|
|
60
58
|
return arm;
|
|
61
59
|
try {
|
|
62
|
-
await fillVectorArm(arm, query,
|
|
60
|
+
await fillVectorArm(arm, query, source, options);
|
|
63
61
|
}
|
|
64
62
|
catch (err) {
|
|
65
63
|
rethrowIfSqliteBlocked(err);
|
|
@@ -71,11 +69,10 @@ export async function resolveVectorArm(query, entries, options) {
|
|
|
71
69
|
async function storedVectorsOf(store, reads, ids) {
|
|
72
70
|
return store.vectorViews ? store.vectorViews.storedVectorViews(ids) : reads.storedVectors(ids);
|
|
73
71
|
}
|
|
74
|
-
async function fillVectorArm(arm, query, root, options) {
|
|
72
|
+
async function fillVectorArm(arm, query, { root, store }, options) {
|
|
75
73
|
const provider = resolveEmbeddingProvider(root);
|
|
76
74
|
if (!provider.isAvailable())
|
|
77
75
|
return;
|
|
78
|
-
const store = options.store ?? sqliteStore(root);
|
|
79
76
|
const reads = requireVectorReads(store);
|
|
80
77
|
const index = await reads.embeddingIndexState();
|
|
81
78
|
if (indexNeedsRebuild(indexedModel(index), provider.id)) {
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export declare const LIMITER_MAX_KEYS = 10000;
|
|
|
24
24
|
/** Builds a per-request Context from the Authorization header and remote address; throws HttpError(401) for invalid or missing credentials.
|
|
25
25
|
* Reads the store only for an API-key-shaped Bearer (or any Bearer when no auth resolver is registered), so keyless local requests stay cheap. */
|
|
26
26
|
export declare function buildContextWithAuth(req: IncomingMessage, opts: AuthOpts): Promise<Context>;
|
|
27
|
+
/** The auth check again, uncharged, for a handler that authenticated with requireAuth before a slow body read and must re-check right before it acts. */
|
|
28
|
+
export declare function recheckContextWithAuth(req: IncomingMessage, opts: AuthOpts): Promise<Context>;
|
|
27
29
|
/** Auth check for routes that need no tenant Context (e.g. the MCP transport, which resolves its own root): throws HttpError 401 like buildContextWithAuth.
|
|
28
30
|
* A keyless local request passes only under HIPPO_ALLOW_KEYLESS_LOCAL=1. */
|
|
29
31
|
export declare function requireAuth(req: IncomingMessage, opts: AuthOpts): Promise<void>;
|
package/dist/server/auth.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// Bearer and loopback auth for the HTTP server.
|
|
2
2
|
import { envAllowKeylessLocal, envRequireAuth } from '../util/env.js';
|
|
3
3
|
import { resolveTenantId } from '../store/tenant.js';
|
|
4
|
-
import { log } from '../util/log.js';
|
|
4
|
+
import { errorFields, errorMessage, log } from '../util/log.js';
|
|
5
5
|
import { API_KEY_PREFIX, verifyApiKeyCached } from '../store/auth.js';
|
|
6
6
|
import { ownerOrSubject } from '../api/index.js';
|
|
7
|
-
import { HttpError, isCrossSite, isHeaderString, LOOPBACK_HOST_HEADER
|
|
7
|
+
import { HttpError, isCrossSite, isHeaderString, LOOPBACK_HOST_HEADER } from '../util/http-util.js';
|
|
8
|
+
import { MAX_ID_LEN } from '../util/limits.js';
|
|
8
9
|
import { clientLimitKey } from './client-ip.js';
|
|
9
10
|
import { keyCheckBounds } from './key-check-bounds.js';
|
|
10
11
|
import { isJsonString } from '../util/json.js';
|
|
@@ -243,11 +244,18 @@ function chargeCaller(tenantId, actor, opts) {
|
|
|
243
244
|
* Reads the store only for an API-key-shaped Bearer (or any Bearer when no auth resolver is registered), so keyless local requests stay cheap. */
|
|
244
245
|
export async function buildContextWithAuth(req, opts) {
|
|
245
246
|
const id = await checkAuth(req, opts);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
chargeCaller(id.tenantId, actor, opts);
|
|
249
|
-
|
|
250
|
-
|
|
247
|
+
const ctx = contextFor(id, opts);
|
|
248
|
+
if (id !== null)
|
|
249
|
+
chargeCaller(id.tenantId, ctx.actor, opts);
|
|
250
|
+
return ctx;
|
|
251
|
+
}
|
|
252
|
+
/** The auth check again, uncharged, for a handler that authenticated with requireAuth before a slow body read and must re-check right before it acts. */
|
|
253
|
+
export async function recheckContextWithAuth(req, opts) {
|
|
254
|
+
return contextFor(await checkAuth(req, opts), opts);
|
|
255
|
+
}
|
|
256
|
+
function contextFor(id, opts) {
|
|
257
|
+
if (id !== null)
|
|
258
|
+
return { hippoRoot: opts.hippoRoot, tenantId: id.tenantId, actor: bearerActor(id), store: opts.store };
|
|
251
259
|
// The keyless local fallback (HIPPO_ALLOW_KEYLESS_LOCAL=1) is this machine's own user, so it is host admin.
|
|
252
260
|
return {
|
|
253
261
|
hippoRoot: opts.hippoRoot,
|
|
@@ -270,6 +278,8 @@ export async function heartbeatVerdict(req, opts) {
|
|
|
270
278
|
return 'ok';
|
|
271
279
|
}
|
|
272
280
|
catch (err) {
|
|
281
|
+
if (!(err instanceof HttpError))
|
|
282
|
+
log.error(`heartbeat auth check failed: ${errorMessage(err)}`, errorFields(err));
|
|
273
283
|
return err instanceof HttpError && err.status < 500 && err.status !== 429 ? 'revoked' : 'unavailable';
|
|
274
284
|
}
|
|
275
285
|
}
|
package/dist/server/boot.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { envPort, envRequireAuth, envV1Rps } from '../util/env.js';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
2
|
import { detectServer, removePidfileIfOwned, writePidfile } from './server-detect.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { outsideSqliteOffLoop, runWithRequestStores, SERVER_DB_WAIT_MS, withSqliteBlocked } from '../db/index.js';
|
|
4
|
+
import { isStoreBusy } from '../store/sqlite/busy.js';
|
|
5
|
+
import { holdSqliteConnection } from '../store/sqlite/held-connection.js';
|
|
7
6
|
import { workerSqliteStore } from '../store/sqlite/worker-store.js';
|
|
8
7
|
import { markSharedStore } from '../core/config.js';
|
|
9
8
|
import { auditWriteFailureCount } from '../store/audit.js';
|
|
@@ -12,8 +11,6 @@ import { errorFields, errorMessage, log } from '../util/log.js';
|
|
|
12
11
|
import { runWithRequestId } from '../util/request-scope.js';
|
|
13
12
|
import { createRateLimiter } from './rate-limit.js';
|
|
14
13
|
import { RecallContractError } from '../api/index.js';
|
|
15
|
-
import { handleSlackEventsWebhook } from '../connectors/slack/webhook.js';
|
|
16
|
-
import { handleGitHubEventsWebhook } from '../connectors/github/webhook.js';
|
|
17
14
|
import { BodyTimeoutError, BodyTooLargeError, closeAfterReply, DeadlineExceededError, HttpError, JSON_HEADERS, sendJson } from '../util/http-util.js';
|
|
18
15
|
import { workerCounts } from '../store/sqlite/executor-counts.js';
|
|
19
16
|
import { isLocalCaller, LIMITER_MAX_KEYS } from './auth.js';
|
|
@@ -27,7 +24,8 @@ import { handleMcpPost, handleMcpStream } from './mcp-http.js';
|
|
|
27
24
|
import { MCP_PROJECT_SCOPED_HEADER } from '../core/project-identity.js';
|
|
28
25
|
import { accessRouteOf, logRequestFailure, noteAccess, openRequest, parseRequest, rejectEncodedSlash, replyFor, sendError } from './request.js';
|
|
29
26
|
import { createListener, warnIfCleartext } from './tls.js';
|
|
30
|
-
import { assertAddonRoutes, assertPublicJson
|
|
27
|
+
import { assertAddonRoutes, assertPublicJson } from './route-checks.js';
|
|
28
|
+
import { dispatchAddonRoute, dispatchPublicJson, dispatchV1Route } from './route-table.js';
|
|
31
29
|
// server.address() returns AddressInfo once a TCP socket is bound; null before
|
|
32
30
|
// listening, a string only for pipe/unix-socket listeners (never used here).
|
|
33
31
|
function isAddressInfo(a) {
|
|
@@ -70,13 +68,7 @@ async function handleRequest(req, res, opts, options) {
|
|
|
70
68
|
res.writeHead(404, JSON_HEADERS);
|
|
71
69
|
res.end(JSON.stringify({ error: 'not found' }));
|
|
72
70
|
}
|
|
73
|
-
|
|
74
|
-
/** A store missing a group a delivery writes through refuses the webhook up front, so no delivery is acknowledged and then half stored. */
|
|
75
|
-
function requireWebhookGroups(store) {
|
|
76
|
-
for (const group of WEBHOOK_GROUPS)
|
|
77
|
-
requireGroup(store, group);
|
|
78
|
-
}
|
|
79
|
-
/** Every route that runs inside a request scope, so it opens each store once: the /v1 table, public JSON, add-on routes, the webhooks and POST /mcp. */
|
|
71
|
+
/** Every route that runs inside a request scope, so it opens each store once: the /v1 table with the webhooks, public JSON, add-on routes and POST /mcp. */
|
|
80
72
|
async function dispatchScopedRoute(r, method, path) {
|
|
81
73
|
if (await dispatchV1Route(r, method, path))
|
|
82
74
|
return true;
|
|
@@ -85,26 +77,6 @@ async function dispatchScopedRoute(r, method, path) {
|
|
|
85
77
|
if (await dispatchAddonRoute(r, method, path))
|
|
86
78
|
return true;
|
|
87
79
|
const { req, res, opts } = r;
|
|
88
|
-
if (method === 'POST' && path === '/v1/connectors/slack/events') {
|
|
89
|
-
noteAccess(req, { route: path });
|
|
90
|
-
// Bearer auth deliberately skipped: this route is in PUBLIC_ROUTES and authenticates via the Slack HMAC signature.
|
|
91
|
-
if (!isPublicRoute(method, path)) {
|
|
92
|
-
// Defensive: PUBLIC_ROUTES drift would land here. Fail closed.
|
|
93
|
-
throw new HttpError(401, 'auth required');
|
|
94
|
-
}
|
|
95
|
-
requireWebhookGroups(opts.store);
|
|
96
|
-
await handleSlackEventsWebhook({ req, res, opts }, opts.store);
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
if (method === 'POST' && path === '/v1/connectors/github/events') {
|
|
100
|
-
noteAccess(req, { route: path });
|
|
101
|
-
if (!isPublicRoute(method, path)) {
|
|
102
|
-
throw new HttpError(401, 'auth required');
|
|
103
|
-
}
|
|
104
|
-
requireWebhookGroups(opts.store);
|
|
105
|
-
await handleGitHubEventsWebhook({ req, res, opts }, opts.store);
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
80
|
// Store-ready: under another store the MCP layer lists and runs only the tools ported to the port.
|
|
109
81
|
if (method === 'POST' && path === '/mcp') {
|
|
110
82
|
noteAccess(req, { route: path });
|
|
@@ -204,38 +176,7 @@ function createStoreHolder(hippoRoot, store) {
|
|
|
204
176
|
log.info(`serve: the '${store.kind}' store serves ${hippoRoot}, so no hippo.db connection is held`);
|
|
205
177
|
return { hold: () => { }, afterResponse: () => { }, release: async () => { } };
|
|
206
178
|
}
|
|
207
|
-
|
|
208
|
-
// which checkpoints and deletes the WAL. It opens only once the store exists, so serving never creates one.
|
|
209
|
-
let heldDb;
|
|
210
|
-
let checkpointer;
|
|
211
|
-
let stopHolding = false;
|
|
212
|
-
const hold = () => {
|
|
213
|
-
if (heldDb || stopHolding || !existsSync(getHippoDbPath(hippoRoot)))
|
|
214
|
-
return;
|
|
215
|
-
try {
|
|
216
|
-
// The 'finish' listener can fire inside a request scope (closing this connection with the request) and inside a `loop: 'off'` block (refusing the open).
|
|
217
|
-
// The server's lock wait: this open runs on the event loop, where SQLite's 5 s default and the 30 s journal-mode retry would stall every request.
|
|
218
|
-
heldDb = outsideSqliteOffLoop(() => outsideRequestStores(() => openHippoDb(hippoRoot, { busyWaitMs: SERVER_DB_WAIT_MS })));
|
|
219
|
-
checkpointer = startWalCheckpointer(getHippoDbPath(hippoRoot));
|
|
220
|
-
}
|
|
221
|
-
catch (err) {
|
|
222
|
-
stopHolding = true;
|
|
223
|
-
log.warn(`serve: could not hold a store connection; requests still work, only slower: ${errorMessage(err)}`);
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
const afterResponse = () => {
|
|
227
|
-
hold();
|
|
228
|
-
checkpointer?.noteResponse();
|
|
229
|
-
};
|
|
230
|
-
const release = async () => {
|
|
231
|
-
stopHolding = true;
|
|
232
|
-
// The worker's connection closes first, so the held one is SQLite's last and its close checkpoints and deletes the WAL.
|
|
233
|
-
await checkpointer?.stop();
|
|
234
|
-
if (heldDb)
|
|
235
|
-
closeHippoDb(heldDb);
|
|
236
|
-
heldDb = undefined;
|
|
237
|
-
};
|
|
238
|
-
return { hold, afterResponse, release };
|
|
179
|
+
return holdSqliteConnection(hippoRoot);
|
|
239
180
|
}
|
|
240
181
|
// A plugin's resolver may read hippo.db through this package's synchronous functions, so it runs outside the block of a `loop: 'off'` route.
|
|
241
182
|
function outsideRouteBlock(resolver) {
|
|
@@ -7,8 +7,6 @@ import type { RateLimiter } from './rate-limit.js';
|
|
|
7
7
|
export declare function clientIpForRateLimit(req: IncomingMessage): string;
|
|
8
8
|
/** Said once at boot: with no proxy list, a caller that reaches the port without the proxy picks its own bucket by sending the header. */
|
|
9
9
|
export declare function warnIfClientIpHeaderUnpinned(): void;
|
|
10
|
-
/** The key for one subscriber: an IPv6 address's /64, since one host may hold the whole /64; any other key as is. */
|
|
11
|
-
export declare function subscriberKey(ip: string): string;
|
|
12
10
|
/** The one key every per-address limit and slot count uses, so rotating inside a /64 never buys a fresh bucket. */
|
|
13
11
|
export declare function clientLimitKey(req: IncomingMessage): string;
|
|
14
12
|
export declare function enforceRateLimit(req: IncomingMessage, path: string, limiter?: RateLimiter): void;
|
package/dist/server/client-ip.js
CHANGED
|
@@ -57,11 +57,12 @@ export function warnIfClientIpHeaderUnpinned() {
|
|
|
57
57
|
const header = envClientIpHeader();
|
|
58
58
|
if (!header || trustedProxyList(envTrustedProxies()))
|
|
59
59
|
return;
|
|
60
|
-
log.warn(`serve: HIPPO_CLIENT_IP_HEADER is ${header} and HIPPO_TRUSTED_PROXIES is unset, so any caller that reaches this port
|
|
60
|
+
log.warn(`serve: HIPPO_CLIENT_IP_HEADER is ${header} and HIPPO_TRUSTED_PROXIES is unset, so any caller that reaches this port ` +
|
|
61
|
+
`without passing the proxy can send that header and pick its own rate-limit bucket. ` +
|
|
61
62
|
"Set HIPPO_TRUSTED_PROXIES to the proxy's addresses or CIDRs, so the header is read from the proxy alone.");
|
|
62
63
|
}
|
|
63
64
|
/** The key for one subscriber: an IPv6 address's /64, since one host may hold the whole /64; any other key as is. */
|
|
64
|
-
|
|
65
|
+
function subscriberKey(ip) {
|
|
65
66
|
const bare = ip.split('%')[0];
|
|
66
67
|
if (bare.toLowerCase().startsWith('::ffff:') && isIP(bare.slice(7)) === 4)
|
|
67
68
|
return bare.slice(7);
|
|
@@ -4,8 +4,6 @@ import { RequestDeadline } from '../util/request-scope.js';
|
|
|
4
4
|
export declare function handlerDeadlineCount(): number;
|
|
5
5
|
/** Whether `res` was answered at its deadline, so whatever its handler does later has no caller. */
|
|
6
6
|
export declare function isAbandoned(res: ServerResponse): boolean;
|
|
7
|
-
/** How long a request may run: 120 s, or HIPPO_REQUEST_DEADLINE_MS, where 0 turns the deadline off. */
|
|
8
|
-
export declare function requestDeadlineMs(): number;
|
|
9
7
|
/** The deadline of `req`, for every /v1 and /mcp route but the two exempt ones. */
|
|
10
8
|
export declare function requestDeadlineFor(req: IncomingMessage): RequestDeadline | undefined;
|
|
11
9
|
/** Calls `reply` when `res` has sent nothing by `deadline`. A store call still in flight answers first, since only the store knows what became of a write. */
|
package/dist/server/deadline.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { RequestDeadline } from '../util/request-scope.js';
|
|
3
|
-
const DEFAULT_REQUEST_DEADLINE_MS = 120_000;
|
|
1
|
+
import { RequestDeadline, requestDeadlineMs } from '../util/request-scope.js';
|
|
4
2
|
// Each has a deadline of its own kind: sleep stops its child process, and the stream is meant to stay open.
|
|
5
3
|
const EXEMPT = new Set(['POST /v1/sleep', 'GET /mcp/stream']);
|
|
6
4
|
const abandoned = new WeakSet();
|
|
@@ -13,10 +11,6 @@ export function handlerDeadlineCount() {
|
|
|
13
11
|
export function isAbandoned(res) {
|
|
14
12
|
return abandoned.has(res);
|
|
15
13
|
}
|
|
16
|
-
/** How long a request may run: 120 s, or HIPPO_REQUEST_DEADLINE_MS, where 0 turns the deadline off. */
|
|
17
|
-
export function requestDeadlineMs() {
|
|
18
|
-
return envRequestDeadlineMs() ?? DEFAULT_REQUEST_DEADLINE_MS;
|
|
19
|
-
}
|
|
20
14
|
/** The deadline of `req`, for every /v1 and /mcp route but the two exempt ones. */
|
|
21
15
|
export function requestDeadlineFor(req) {
|
|
22
16
|
const ms = requestDeadlineMs();
|
package/dist/server/defaults.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// `hippo serve` reads these without loading the server, so the CLI and serve() cannot disagree on a default.
|
|
2
2
|
export const DEFAULT_SERVER_PORT = 6789;
|
|
3
3
|
export const DEFAULT_SERVER_HOST = '127.0.0.1';
|
|
4
|
+
export const DEFAULT_DASHBOARD_PORT = 3333;
|
|
4
5
|
//# sourceMappingURL=defaults.js.map
|
package/dist/server/mcp-http.js
CHANGED
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
// MCP over HTTP: POST /mcp and the GET /mcp/stream SSE keepalive.
|
|
2
2
|
import { envMcpSseHeartbeatMs, envMcpSseMaxAgeSec, envMcpSseMaxStreams } from '../util/env.js';
|
|
3
|
-
import { createHash } from 'node:crypto';
|
|
4
3
|
import { isSharedStore } from '../core/config.js';
|
|
5
4
|
import { handleMcpRequest, mcpErrorResponse } from '../mcp/server.js';
|
|
6
5
|
import { HttpError, readBody, sendJson } from '../util/http-util.js';
|
|
6
|
+
import { log } from '../util/log.js';
|
|
7
7
|
import { assertCallerProject } from '../core/project-identity.js';
|
|
8
8
|
import { buildContextWithAuth, heartbeatVerdict, readAuthHeader, requireAuth } from './auth.js';
|
|
9
|
-
import { clientLimitKey
|
|
9
|
+
import { clientLimitKey } from './client-ip.js';
|
|
10
10
|
import { noteAccess } from './request.js';
|
|
11
11
|
import { isJsonString, isJsonObject } from '../util/json.js';
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import { blockHash } from '../util/token-text.js';
|
|
13
|
+
import { consolidateInChild } from './sleep-offload.js';
|
|
14
|
+
const DEFAULT_SSE_HEARTBEAT_MS = 60_000;
|
|
14
15
|
const DEFAULT_SSE_MAX_AGE_SEC = 3600;
|
|
15
16
|
/** Per-client key for MCP state isolation under HTTP-MCP (scopes `lastRecalledIds`): sha256 of the token (16 hex chars, so the raw bearer is never logged)
|
|
16
|
-
* plus
|
|
17
|
+
* plus the client address the rate limiter keys on, so clients sharing a key stay separable behind a trusted proxy too; 'noauth' covers loopback no-auth. */
|
|
17
18
|
function buildMcpClientKey(req) {
|
|
18
19
|
const auth = readAuthHeader(req);
|
|
19
20
|
const tokenHash = auth.kind === 'bearer'
|
|
20
|
-
?
|
|
21
|
+
? blockHash(auth.token)
|
|
21
22
|
: 'noauth';
|
|
22
|
-
|
|
23
|
-
return `http:${tokenHash}:${addr}`;
|
|
23
|
+
return `http:${tokenHash}:${clientLimitKey(req)}`;
|
|
24
24
|
}
|
|
25
|
-
// MCP-over-HTTP/SSE: POST /mcp answers a JSON-RPC request synchronously; GET /mcp/stream is a keepalive-only SSE stream
|
|
25
|
+
// MCP-over-HTTP/SSE: POST /mcp answers a JSON-RPC request synchronously; GET /mcp/stream is a keepalive-only SSE stream
|
|
26
|
+
// (`: ping` every DEFAULT_SSE_HEARTBEAT_MS, 60 s) in v1.
|
|
26
27
|
// Both dispatch to handleMcpRequest as stdio does. Auth matches /v1/* (Bearer via `requireAuth`, loopback fallback); SSE is checked once at stream-open.
|
|
27
28
|
// Percent-encoded by the client, so any lowercase Unicode name fits a Latin-1 header.
|
|
28
29
|
const HEADER_PIECE = /^[A-Za-z0-9\-_.!~*'()%]+$/;
|
|
@@ -70,6 +71,7 @@ function mcpContextFor(ctx, clientKey, autoSleep, project) {
|
|
|
70
71
|
clientKey,
|
|
71
72
|
store: ctx.store,
|
|
72
73
|
autoSleep,
|
|
74
|
+
autoSleepRunner: consolidateInChild,
|
|
73
75
|
};
|
|
74
76
|
if (project !== undefined)
|
|
75
77
|
mcpCtx.project = project;
|
|
@@ -100,7 +102,8 @@ export async function handleMcpPost(req, res, opts) {
|
|
|
100
102
|
mcpRes = await handleMcpRequest(rpcReq, mcpContextFor(ctx, buildMcpClientKey(req), opts.autoSleep, project));
|
|
101
103
|
}
|
|
102
104
|
catch (err) {
|
|
103
|
-
|
|
105
|
+
const tool = rpcReq.params?.name;
|
|
106
|
+
mcpRes = mcpErrorResponse(rpcReq.id, err, undefined, isJsonString(tool) ? `${rpcReq.method} ${tool.slice(0, 128)}` : rpcReq.method);
|
|
104
107
|
}
|
|
105
108
|
if (mcpRes === null) {
|
|
106
109
|
// Notification — no body, 202 Accepted.
|
|
@@ -116,7 +119,7 @@ const DEFAULT_MAX_STREAMS_PER_CLIENT = 8;
|
|
|
116
119
|
function streamSlotKey(req) {
|
|
117
120
|
const auth = readAuthHeader(req);
|
|
118
121
|
if (auth.kind === 'bearer')
|
|
119
|
-
return `key:${
|
|
122
|
+
return `key:${blockHash(auth.token)}`;
|
|
120
123
|
return `ip:${clientLimitKey(req)}`;
|
|
121
124
|
}
|
|
122
125
|
/** Takes a stream slot or throws 429; the slot is released once, when the response closes. */
|
|
@@ -180,6 +183,8 @@ function keepStreamAlive(req, res, opts) {
|
|
|
180
183
|
checking = true;
|
|
181
184
|
void heartbeatVerdict(req, opts).then((verdict) => {
|
|
182
185
|
checking = false;
|
|
186
|
+
if (!closed && verdict === 'unavailable')
|
|
187
|
+
log.warn('heartbeat tick skipped: auth check unavailable');
|
|
183
188
|
if (closed || verdict === 'unavailable')
|
|
184
189
|
return;
|
|
185
190
|
if (verdict === 'revoked') {
|
package/dist/server/request.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { STORE_BUSY_MESSAGE } from '../store/port.js';
|
|
3
|
+
import { isStoreBusy } from '../store/sqlite/busy.js';
|
|
3
4
|
import { errorFields, errorMessage, log } from '../util/log.js';
|
|
4
|
-
import {
|
|
5
|
+
import { mapApiError } from '../api/error-reply.js';
|
|
6
|
+
import { HttpError, sendJson } from '../util/http-util.js';
|
|
5
7
|
// The caller's id lands in a response header and in logs, so only a short plain token is echoed back.
|
|
6
8
|
const REQUEST_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
7
9
|
/** The caller's `X-Request-Id` when it is a short plain token, else a fresh UUID. */
|
|
@@ -18,6 +20,9 @@ export function logRequestFailure(req, err, status) {
|
|
|
18
20
|
log.warn(line, { status });
|
|
19
21
|
else if (status >= 500 && status !== 501)
|
|
20
22
|
log.error(line, { status, ...errorFields(err) });
|
|
23
|
+
// A failed login is the one 4xx an operator needs by default; the id (never the credential) is stamped from the request scope.
|
|
24
|
+
else if (status === 401 || status === 403)
|
|
25
|
+
log.warn(line, { status });
|
|
21
26
|
else
|
|
22
27
|
log.info(line, { status });
|
|
23
28
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { JsonValue } from '../util/json.js';
|
|
2
|
+
import type { AddonRoute } from './types.js';
|
|
3
|
+
/** Boot-time check: an add-on path must be plain, unique and not one core serves, so no add-on shadows a core route or hides from dispatch. */
|
|
4
|
+
export declare function assertAddonRoutes(routes: readonly AddonRoute[]): void;
|
|
5
|
+
/** Boot-time check and serialization: a public path that a core GET route serves would open that route to anyone. */
|
|
6
|
+
export declare function assertPublicJson(publicJson: Readonly<Record<string, JsonValue>>): ReadonlyMap<string, string>;
|
|
7
|
+
//# sourceMappingURL=route-checks.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { V1_ROUTES, routeMatches } from './route-table.js';
|
|
2
|
+
const PLAIN_SEGMENT_RE = /^[A-Za-z0-9._~-]+$/;
|
|
3
|
+
function isPlainV1Path(path) {
|
|
4
|
+
return path.startsWith('/v1/') && new URL(path, 'http://h').pathname === path
|
|
5
|
+
&& path.slice('/v1/'.length).split('/').every((segment) => PLAIN_SEGMENT_RE.test(segment));
|
|
6
|
+
}
|
|
7
|
+
// A plain path never holds a `%`, so matchPath cannot throw here.
|
|
8
|
+
function isCorePath(method, path) {
|
|
9
|
+
return V1_ROUTES.some((route) => routeMatches(route, method, path) !== null);
|
|
10
|
+
}
|
|
11
|
+
/** Boot-time check: an add-on path must be plain, unique and not one core serves, so no add-on shadows a core route or hides from dispatch. */
|
|
12
|
+
export function assertAddonRoutes(routes) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
for (const { path } of routes) {
|
|
15
|
+
if (!isPlainV1Path(path))
|
|
16
|
+
throw new Error(`add-on route '${path}' is not a plain /v1/ path (segments use A-Z a-z 0-9 . _ ~ -)`);
|
|
17
|
+
if (seen.has(path))
|
|
18
|
+
throw new Error(`add-on route '${path}' is registered twice`);
|
|
19
|
+
if (isCorePath('POST', path))
|
|
20
|
+
throw new Error(`add-on route '${path}' is already served by core`);
|
|
21
|
+
seen.add(path);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const PUBLIC_JSON_MAX_BYTES = 64 * 1024;
|
|
25
|
+
/** Boot-time check and serialization: a public path that a core GET route serves would open that route to anyone. */
|
|
26
|
+
export function assertPublicJson(publicJson) {
|
|
27
|
+
const bodies = new Map();
|
|
28
|
+
for (const [path, value] of Object.entries(publicJson)) {
|
|
29
|
+
if (!isPlainV1Path(path))
|
|
30
|
+
throw new Error(`public JSON path '${path}' is not a plain /v1/ path (segments use A-Z a-z 0-9 . _ ~ -)`);
|
|
31
|
+
if (isCorePath('GET', path))
|
|
32
|
+
throw new Error(`public JSON path '${path}' is already served by core`);
|
|
33
|
+
const text = JSON.stringify(value);
|
|
34
|
+
if (text === undefined)
|
|
35
|
+
throw new Error(`public JSON at '${path}' is not JSON`);
|
|
36
|
+
if (Buffer.byteLength(text) > PUBLIC_JSON_MAX_BYTES)
|
|
37
|
+
throw new Error(`public JSON at '${path}' is over 64 KiB`);
|
|
38
|
+
bodies.set(path, text);
|
|
39
|
+
}
|
|
40
|
+
return bodies;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=route-checks.js.map
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { Route, RouteRequest } from './types.js';
|
|
2
|
+
/** The /v1 routes in dispatch order; the first entry whose method and path match handles the request. Each row's `auth` is what the
|
|
3
|
+
* dispatch gate proves before its handler runs, so a handler never checks the caller itself. */
|
|
4
|
+
export declare const V1_ROUTES: readonly Route[];
|
|
5
|
+
/** The route's run for this request, gate first, or null when method or path differ. The matcher runs before the method check,
|
|
6
|
+
* as the inline route blocks did, so a malformed `%` escape still throws from matchPath on any method. */
|
|
7
|
+
export declare function routeMatches(route: Route, method: string, path: string): ((r: RouteRequest) => Promise<void>) | null;
|
|
8
|
+
/** The route as the access line names it; a regex route reads as its pattern would, so no line carries a caller's id. */
|
|
9
|
+
export declare function routeLabel(route: Route): string;
|
|
4
10
|
/** Run the first /v1 route whose method and path match. */
|
|
5
11
|
export declare function dispatchV1Route(r: RouteRequest, method: string, path: string): Promise<boolean>;
|
|
6
|
-
/** Boot-time check: an add-on path must be plain, unique and not one core serves, so no add-on shadows a core route or hides from dispatch. */
|
|
7
|
-
export declare function assertAddonRoutes(routes: readonly AddonRoute[]): void;
|
|
8
|
-
/** Boot-time check and serialization: a public path that a core GET route serves would open that route to anyone. */
|
|
9
|
-
export declare function assertPublicJson(publicJson: Readonly<Record<string, JsonValue>>): ReadonlyMap<string, string>;
|
|
10
12
|
/** Core authenticates and parses before the handler runs, so an add-on route gets the same 401, 400 and 501 as a core one. */
|
|
11
13
|
export declare function dispatchAddonRoute({ req, res, opts }: RouteRequest, method: string, path: string): Promise<boolean>;
|
|
12
14
|
/** No auth, body read or store access, so a caller with no key gets it under any store. */
|
|
13
15
|
export declare function dispatchPublicJson({ req, res, opts }: RouteRequest, method: string, path: string): boolean;
|
|
14
|
-
export declare function assertSqliteStore(opts: ResolvedServeOpts): void;
|
|
15
16
|
//# sourceMappingURL=route-table.d.ts.map
|