hippo-memory 1.60.0 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/ablation.js +9 -27
- package/dist/agent-memories/apply.js +4 -1
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/gemini.js +1 -1
- package/dist/agent-memories/legacy.js +1 -1
- package/dist/agent-memories/source.js +1 -1
- package/dist/agent-memories/sync.js +8 -3
- package/dist/ambient-store.d.ts +14 -0
- package/dist/ambient-store.js +90 -0
- package/dist/ambient.d.ts +23 -0
- package/dist/ambient.js +72 -50
- package/dist/api/assemble.d.ts +93 -0
- package/dist/api/assemble.js +152 -0
- package/dist/api/audit.d.ts +17 -0
- package/dist/api/audit.js +23 -0
- package/dist/api/auth.d.ts +79 -0
- package/dist/api/auth.js +178 -0
- package/dist/api/context-types.d.ts +105 -0
- package/dist/api/context-types.js +3 -0
- package/dist/api/context.d.ts +31 -0
- package/dist/api/context.js +705 -0
- package/dist/api/dormant.d.ts +30 -0
- package/dist/api/dormant.js +140 -0
- package/dist/api/drill-down.d.ts +84 -0
- package/dist/api/drill-down.js +123 -0
- package/dist/api/forget.d.ts +57 -0
- package/dist/api/forget.js +87 -0
- package/dist/api/goals.d.ts +18 -0
- package/dist/api/goals.js +33 -0
- package/dist/api/learn.d.ts +31 -0
- package/dist/api/learn.js +88 -0
- package/dist/api/outcome.d.ts +61 -0
- package/dist/api/outcome.js +66 -0
- package/dist/api/promote.d.ts +54 -0
- package/dist/api/promote.js +203 -0
- package/dist/api/quarantine.d.ts +24 -0
- package/dist/api/quarantine.js +121 -0
- package/dist/api/recall-types.d.ts +390 -0
- package/dist/api/recall-types.js +3 -0
- package/dist/api/recall.d.ts +36 -0
- package/dist/api/recall.js +634 -0
- package/dist/api/remember.d.ts +35 -0
- package/dist/api/remember.js +43 -0
- package/dist/api/sleep.d.ts +136 -0
- package/dist/api/sleep.js +271 -0
- package/dist/api/tokens.d.ts +26 -0
- package/dist/api/tokens.js +60 -0
- package/dist/api/types.d.ts +56 -0
- package/dist/api/types.js +38 -0
- package/dist/api.d.ts +20 -1262
- package/dist/api.js +25 -2727
- package/dist/audit.d.ts +3 -0
- package/dist/audit.js +6 -3
- package/dist/auth.d.ts +45 -4
- package/dist/auth.js +125 -48
- package/dist/autolearn.js +2 -2
- package/dist/capture/command.d.ts +33 -0
- package/dist/capture/command.js +264 -0
- package/dist/capture/compact.d.ts +44 -0
- package/dist/capture/compact.js +354 -0
- package/dist/capture/extract.d.ts +21 -0
- package/dist/capture/extract.js +464 -0
- package/dist/capture/transcript.d.ts +40 -0
- package/dist/capture/transcript.js +193 -0
- package/dist/capture-error.js +2 -1
- package/dist/churn-git.js +4 -2
- package/dist/cli/audit.d.ts +3 -0
- package/dist/cli/audit.js +159 -0
- package/dist/cli/auth.d.ts +2 -0
- package/dist/cli/auth.js +171 -0
- package/dist/cli/briefs.d.ts +4 -0
- package/dist/cli/briefs.js +435 -0
- package/dist/cli/card.d.ts +3 -0
- package/dist/cli/card.js +333 -0
- package/dist/cli/context.d.ts +15 -0
- package/dist/cli/context.js +366 -0
- package/dist/cli/continuity.d.ts +6 -0
- package/dist/cli/continuity.js +445 -0
- package/dist/cli/curate.d.ts +19 -0
- package/dist/cli/curate.js +555 -0
- package/dist/cli/dag.d.ts +5 -0
- package/dist/cli/dag.js +177 -0
- package/dist/cli/decisions.d.ts +4 -0
- package/dist/cli/decisions.js +528 -0
- package/dist/cli/eval.d.ts +5 -0
- package/dist/cli/eval.js +213 -0
- package/dist/cli/explain.d.ts +4 -0
- package/dist/cli/explain.js +150 -0
- package/dist/cli/goals.d.ts +2 -0
- package/dist/cli/goals.js +196 -0
- package/dist/cli/hook-blocks.d.ts +18 -0
- package/dist/cli/hook-blocks.js +233 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.js +305 -0
- package/dist/cli/maintenance.d.ts +4 -0
- package/dist/cli/maintenance.js +179 -0
- package/dist/cli/playbooks.d.ts +4 -0
- package/dist/cli/playbooks.js +556 -0
- package/dist/cli/projects.js +1 -1
- package/dist/cli/recall.d.ts +7 -0
- package/dist/cli/recall.js +597 -0
- package/dist/cli/remember.d.ts +5 -0
- package/dist/cli/remember.js +442 -0
- package/dist/cli/serve.d.ts +5 -0
- package/dist/cli/serve.js +40 -0
- package/dist/cli/session-hooks.d.ts +29 -0
- package/dist/cli/session-hooks.js +637 -0
- package/dist/cli/setup.d.ts +4 -0
- package/dist/cli/setup.js +376 -0
- package/dist/cli/shared.d.ts +15 -19
- package/dist/cli/shared.js +50 -341
- package/dist/cli/slack.d.ts +2 -0
- package/dist/cli/slack.js +171 -0
- package/dist/cli/status.d.ts +18 -0
- package/dist/cli/status.js +400 -0
- package/dist/cli/transfer.d.ts +10 -0
- package/dist/cli/transfer.js +438 -0
- package/dist/cli/usage.d.ts +85 -0
- package/dist/cli/usage.js +741 -0
- package/dist/cli.d.ts +71 -120
- package/dist/cli.js +170 -8469
- package/dist/client.js +15 -8
- package/dist/compaction-record.js +6 -4
- package/dist/connectors/github/backfill.js +94 -87
- package/dist/connectors/github/cli-impl.js +4 -3
- package/dist/connectors/github/dlq.js +67 -54
- package/dist/connectors/github/ingest.js +34 -35
- package/dist/connectors/github/tenant-routing.js +3 -2
- package/dist/connectors/github/webhook.js +135 -216
- package/dist/connectors/slack/dlq.js +49 -61
- package/dist/connectors/slack/ingest.js +55 -48
- package/dist/connectors/slack/tenant-routing.js +4 -3
- package/dist/connectors/slack/webhook.js +72 -74
- package/dist/consolidate/conflicts.d.ts +10 -0
- package/dist/consolidate/conflicts.js +178 -0
- package/dist/consolidate/decay.d.ts +12 -0
- package/dist/consolidate/decay.js +145 -0
- package/dist/consolidate/llm-passes.d.ts +3 -0
- package/dist/consolidate/llm-passes.js +141 -0
- package/dist/consolidate/merge.d.ts +7 -0
- package/dist/consolidate/merge.js +251 -0
- package/dist/consolidate/physics-pass.d.ts +3 -0
- package/dist/consolidate/physics-pass.js +60 -0
- package/dist/consolidate/run.d.ts +69 -0
- package/dist/consolidate/run.js +76 -0
- package/dist/consolidate/sleep.d.ts +18 -0
- package/dist/consolidate/sleep.js +209 -0
- package/dist/consolidate/traces.d.ts +4 -0
- package/dist/consolidate/traces.js +178 -0
- package/dist/context-auto.js +7 -11
- package/dist/context-render.d.ts +1 -1
- package/dist/context-render.js +1 -1
- package/dist/customer-notes.d.ts +3 -0
- package/dist/customer-notes.js +6 -4
- package/dist/dag.js +6 -5
- package/dist/dashboard-actions.d.ts +20 -0
- package/dist/dashboard-actions.js +88 -0
- package/dist/dashboard-params.d.ts +45 -0
- package/dist/dashboard-params.js +127 -0
- package/dist/dashboard-queries.d.ts +15 -0
- package/dist/dashboard-queries.js +355 -0
- package/dist/dashboard-snapshot.d.ts +138 -0
- package/dist/dashboard-snapshot.js +308 -0
- package/dist/dashboard-types.d.ts +163 -0
- package/dist/dashboard-types.js +3 -0
- package/dist/dashboard.d.ts +6 -7
- package/dist/dashboard.js +228 -202
- package/dist/db/busy.d.ts +5 -0
- package/dist/db/busy.js +24 -0
- package/dist/db/continuity.d.ts +5 -0
- package/dist/db/continuity.js +145 -0
- package/dist/db/meta.d.ts +8 -0
- package/dist/db/meta.js +35 -0
- package/dist/db/migrate.d.ts +9 -0
- package/dist/db/migrate.js +138 -0
- package/dist/db/migrations/index.d.ts +5 -0
- package/dist/db/migrations/index.js +109 -0
- package/dist/db/migrations/types.d.ts +14 -0
- package/dist/db/migrations/types.js +2 -0
- package/dist/db/migrations/v01.d.ts +3 -0
- package/dist/db/migrations/v01.js +38 -0
- package/dist/db/migrations/v02.d.ts +3 -0
- package/dist/db/migrations/v02.js +21 -0
- package/dist/db/migrations/v03.d.ts +3 -0
- package/dist/db/migrations/v03.js +22 -0
- package/dist/db/migrations/v04.d.ts +3 -0
- package/dist/db/migrations/v04.js +28 -0
- package/dist/db/migrations/v05.d.ts +3 -0
- package/dist/db/migrations/v05.js +21 -0
- package/dist/db/migrations/v06.d.ts +3 -0
- package/dist/db/migrations/v06.js +25 -0
- package/dist/db/migrations/v07.d.ts +3 -0
- package/dist/db/migrations/v07.js +13 -0
- package/dist/db/migrations/v08.d.ts +3 -0
- package/dist/db/migrations/v08.js +8 -0
- package/dist/db/migrations/v09.d.ts +3 -0
- package/dist/db/migrations/v09.js +13 -0
- package/dist/db/migrations/v10.d.ts +3 -0
- package/dist/db/migrations/v10.js +17 -0
- package/dist/db/migrations/v11.d.ts +3 -0
- package/dist/db/migrations/v11.js +15 -0
- package/dist/db/migrations/v12.d.ts +3 -0
- package/dist/db/migrations/v12.js +11 -0
- package/dist/db/migrations/v13.d.ts +3 -0
- package/dist/db/migrations/v13.js +15 -0
- package/dist/db/migrations/v14.d.ts +3 -0
- package/dist/db/migrations/v14.js +66 -0
- package/dist/db/migrations/v15.d.ts +3 -0
- package/dist/db/migrations/v15.js +42 -0
- package/dist/db/migrations/v16.d.ts +3 -0
- package/dist/db/migrations/v16.js +61 -0
- package/dist/db/migrations/v17.d.ts +3 -0
- package/dist/db/migrations/v17.js +46 -0
- package/dist/db/migrations/v18.d.ts +3 -0
- package/dist/db/migrations/v18.js +60 -0
- package/dist/db/migrations/v19.d.ts +3 -0
- package/dist/db/migrations/v19.js +28 -0
- package/dist/db/migrations/v20.d.ts +3 -0
- package/dist/db/migrations/v20.js +42 -0
- package/dist/db/migrations/v21.d.ts +3 -0
- package/dist/db/migrations/v21.js +16 -0
- package/dist/db/migrations/v22.d.ts +3 -0
- package/dist/db/migrations/v22.js +82 -0
- package/dist/db/migrations/v23.d.ts +3 -0
- package/dist/db/migrations/v23.js +48 -0
- package/dist/db/migrations/v24.d.ts +3 -0
- package/dist/db/migrations/v24.js +72 -0
- package/dist/db/migrations/v25.d.ts +3 -0
- package/dist/db/migrations/v25.js +46 -0
- package/dist/db/migrations/v26.d.ts +3 -0
- package/dist/db/migrations/v26.js +23 -0
- package/dist/db/migrations/v27.d.ts +3 -0
- package/dist/db/migrations/v27.js +57 -0
- package/dist/db/migrations/v28.d.ts +3 -0
- package/dist/db/migrations/v28.js +38 -0
- package/dist/db/migrations/v29.d.ts +3 -0
- package/dist/db/migrations/v29.js +78 -0
- package/dist/db/migrations/v30.d.ts +3 -0
- package/dist/db/migrations/v30.js +92 -0
- package/dist/db/migrations/v31.d.ts +3 -0
- package/dist/db/migrations/v31.js +74 -0
- package/dist/db/migrations/v32.d.ts +3 -0
- package/dist/db/migrations/v32.js +102 -0
- package/dist/db/migrations/v33.d.ts +3 -0
- package/dist/db/migrations/v33.js +104 -0
- package/dist/db/migrations/v34.d.ts +3 -0
- package/dist/db/migrations/v34.js +93 -0
- package/dist/db/migrations/v35.d.ts +3 -0
- package/dist/db/migrations/v35.js +98 -0
- package/dist/db/migrations/v36.d.ts +3 -0
- package/dist/db/migrations/v36.js +98 -0
- package/dist/db/migrations/v37.d.ts +3 -0
- package/dist/db/migrations/v37.js +219 -0
- package/dist/db/migrations/v38.d.ts +3 -0
- package/dist/db/migrations/v38.js +277 -0
- package/dist/db/migrations/v39.d.ts +3 -0
- package/dist/db/migrations/v39.js +59 -0
- package/dist/db/migrations/v40.d.ts +3 -0
- package/dist/db/migrations/v40.js +74 -0
- package/dist/db/migrations/v41.d.ts +3 -0
- package/dist/db/migrations/v41.js +43 -0
- package/dist/db/migrations/v42.d.ts +3 -0
- package/dist/db/migrations/v42.js +41 -0
- package/dist/db/migrations/v43.d.ts +3 -0
- package/dist/db/migrations/v43.js +67 -0
- package/dist/db/migrations/v44.d.ts +3 -0
- package/dist/db/migrations/v44.js +28 -0
- package/dist/db/migrations/v45.d.ts +3 -0
- package/dist/db/migrations/v45.js +30 -0
- package/dist/db/migrations/v46.d.ts +3 -0
- package/dist/db/migrations/v46.js +25 -0
- package/dist/db/migrations/v47.d.ts +3 -0
- package/dist/db/migrations/v47.js +17 -0
- package/dist/db/migrations/v48.d.ts +3 -0
- package/dist/db/migrations/v48.js +10 -0
- package/dist/db/migrations/v49.d.ts +3 -0
- package/dist/db/migrations/v49.js +31 -0
- package/dist/db/migrations/v50.d.ts +3 -0
- package/dist/db/migrations/v50.js +67 -0
- package/dist/db/migrations/v51.d.ts +3 -0
- package/dist/db/migrations/v51.js +14 -0
- package/dist/db/migrations/v52.d.ts +3 -0
- package/dist/db/migrations/v52.js +7 -0
- package/dist/db/open.d.ts +23 -0
- package/dist/db/open.js +146 -0
- package/dist/db/sqlite.d.ts +21 -0
- package/dist/db/sqlite.js +8 -0
- package/dist/db/tables.d.ts +7 -0
- package/dist/db/tables.js +38 -0
- package/dist/db.d.ts +6 -46
- package/dist/db.js +5 -3049
- package/dist/decisions.d.ts +4 -1
- package/dist/decisions.js +9 -7
- package/dist/dedupe.js +3 -2
- package/dist/delivery-recorder.js +4 -1
- package/dist/doctor.js +3 -3
- package/dist/embedding-provider.d.ts +1 -1
- package/dist/embedding-provider.js +4 -3
- package/dist/embeddings.d.ts +9 -52
- package/dist/embeddings.js +43 -297
- package/dist/env.d.ts +75 -0
- package/dist/env.js +119 -0
- package/dist/eval-suite.js +1 -1
- package/dist/eval.js +2 -2
- package/dist/extract.js +1 -1
- package/dist/gated-write.js +3 -1
- package/dist/goals.d.ts +3 -1
- package/dist/goals.js +18 -0
- package/dist/graph/read.d.ts +73 -0
- package/dist/graph/read.js +325 -0
- package/dist/graph/rows.d.ts +45 -0
- package/dist/graph/rows.js +51 -0
- package/dist/graph/types.d.ts +83 -0
- package/dist/graph/types.js +11 -0
- package/dist/graph/write.d.ts +93 -0
- package/dist/{graph.js → graph/write.js} +6 -384
- package/dist/graph-extract.js +2 -1
- package/dist/graph-recall.d.ts +1 -1
- package/dist/graph-recall.js +2 -2
- package/dist/graph-stream.js +1 -1
- package/dist/graph-view.d.ts +1 -1
- package/dist/graph-view.js +1 -1
- package/dist/half-life-migration.d.ts +1 -1
- package/dist/half-life-migration.js +2 -1
- package/dist/hooks/codex-session.d.ts +8 -0
- package/dist/hooks/codex-session.js +76 -0
- package/dist/hooks/codex-wrapper.d.ts +55 -0
- package/dist/hooks/codex-wrapper.js +288 -0
- package/dist/hooks/json-hooks.d.ts +63 -0
- package/dist/hooks/json-hooks.js +356 -0
- package/dist/hooks/opencode.d.ts +50 -0
- package/dist/hooks/opencode.js +202 -0
- package/dist/hooks/shared.d.ts +54 -0
- package/dist/hooks/shared.js +77 -0
- package/dist/http-retry.d.ts +2 -0
- package/dist/http-retry.js +4 -3
- package/dist/http-util.d.ts +3 -0
- package/dist/http-util.js +10 -0
- package/dist/{importers.d.ts → importers/core.d.ts} +13 -17
- package/dist/importers/core.js +141 -0
- package/dist/importers/markdown-parse.d.ts +41 -0
- package/dist/importers/markdown-parse.js +132 -0
- package/dist/importers/markdown.d.ts +3 -0
- package/dist/importers/markdown.js +92 -0
- package/dist/importers/sources.d.ts +7 -0
- package/dist/importers/sources.js +229 -0
- package/dist/importers/vault.d.ts +11 -0
- package/dist/importers/vault.js +352 -0
- package/dist/incidents.d.ts +3 -0
- package/dist/incidents.js +7 -5
- package/dist/index.d.ts +25 -6
- package/dist/index.js +23 -6
- package/dist/invalidation.js +2 -1
- package/dist/judgment.js +2 -1
- package/dist/keyset.d.ts +13 -0
- package/dist/keyset.js +8 -0
- package/dist/local-embedding.d.ts +13 -0
- package/dist/local-embedding.js +165 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +19 -1
- package/dist/mcp/admin-tools.d.ts +8 -0
- package/dist/mcp/admin-tools.js +116 -0
- package/dist/mcp/format.d.ts +27 -0
- package/dist/mcp/format.js +135 -0
- package/dist/mcp/memory-tools.d.ts +5 -0
- package/dist/mcp/memory-tools.js +83 -0
- package/dist/mcp/protocol.d.ts +83 -0
- package/dist/mcp/protocol.js +55 -0
- package/dist/mcp/recall-tools.d.ts +6 -0
- package/dist/mcp/recall-tools.js +320 -0
- package/dist/mcp/request.d.ts +10 -0
- package/dist/mcp/request.js +163 -0
- package/dist/mcp/server.d.ts +4 -75
- package/dist/mcp/server.js +7 -1190
- package/dist/mcp/session-state.d.ts +11 -0
- package/dist/mcp/session-state.js +28 -0
- package/dist/mcp/stdio.d.ts +8 -0
- package/dist/mcp/stdio.js +79 -0
- package/dist/mcp/tools.d.ts +11 -0
- package/dist/mcp/tools.js +247 -0
- package/dist/memory.d.ts +3 -0
- package/dist/memory.js +27 -1
- package/dist/multihop.d.ts +1 -1
- package/dist/multihop.js +2 -1
- package/dist/owner-validation.js +2 -1
- package/dist/physics-state.js +10 -7
- package/dist/policies.d.ts +3 -0
- package/dist/policies.js +8 -6
- package/dist/postinstall.js +3 -2
- package/dist/predictions/planning-fallacy.d.ts +100 -0
- package/dist/predictions/planning-fallacy.js +190 -0
- package/dist/{predictions.d.ts → predictions/store.d.ts} +7 -102
- package/dist/predictions/store.js +434 -0
- package/dist/processes.d.ts +3 -0
- package/dist/processes.js +7 -5
- package/dist/project-briefs.d.ts +3 -0
- package/dist/project-briefs.js +7 -5
- package/dist/project-identity.js +3 -2
- package/dist/project-merge.js +3 -1
- package/dist/quarantine.d.ts +2 -1
- package/dist/quarantine.js +8 -5
- package/dist/raw-archive.js +1 -1
- package/dist/recall-history.js +3 -2
- package/dist/recall-pipeline.d.ts +2 -2
- package/dist/recall-pipeline.js +16 -8
- package/dist/recall-scope.js +1 -1
- package/dist/recall-trace.d.ts +1 -1
- package/dist/refine-llm.js +2 -1
- package/dist/reject-flow.js +6 -1
- package/dist/rerankers/clef.js +6 -5
- package/dist/rerankers/jev.d.ts +1 -1
- package/dist/rerankers/jev.js +4 -4
- package/dist/rerankers/llm.d.ts +4 -2
- package/dist/rerankers/llm.js +58 -38
- package/dist/rerankers/types.d.ts +1 -1
- package/dist/salience.js +1 -1
- package/dist/scheduler.d.ts +1 -0
- package/dist/scheduler.js +26 -4
- package/dist/scope.js +4 -3
- package/dist/search/as-of.d.ts +10 -0
- package/dist/search/as-of.js +22 -0
- package/dist/search/bm25-search.d.ts +14 -0
- package/dist/search/bm25-search.js +43 -0
- package/dist/search/bm25.d.ts +15 -0
- package/dist/search/bm25.js +54 -0
- package/dist/search/boosts.d.ts +54 -0
- package/dist/search/boosts.js +94 -0
- package/dist/search/breakdown.d.ts +7 -0
- package/dist/search/breakdown.js +20 -0
- package/dist/search/explain.d.ts +25 -0
- package/dist/search/explain.js +31 -0
- package/dist/search/finalize.d.ts +8 -0
- package/dist/search/finalize.js +52 -0
- package/dist/search/fusion.d.ts +27 -0
- package/dist/search/fusion.js +42 -0
- package/dist/search/hybrid-score.d.ts +20 -0
- package/dist/search/hybrid-score.js +73 -0
- package/dist/search/hybrid.d.ts +46 -0
- package/dist/search/hybrid.js +64 -0
- package/dist/search/physics-search.d.ts +29 -0
- package/dist/search/physics-search.js +162 -0
- package/dist/search/rerank.d.ts +10 -0
- package/dist/search/rerank.js +72 -0
- package/dist/search/temporal.d.ts +15 -0
- package/dist/search/temporal.js +45 -0
- package/dist/search/types.d.ts +91 -0
- package/dist/search/types.js +2 -0
- package/dist/search/vector.d.ts +30 -0
- package/dist/search/vector.js +71 -0
- package/dist/secret-detect.d.ts +2 -0
- package/dist/secret-detect.js +2 -1
- package/dist/server/auth.d.ts +52 -0
- package/dist/server/auth.js +221 -0
- package/dist/server/client-ip.d.ts +25 -0
- package/dist/server/client-ip.js +92 -0
- package/dist/server/cursor.d.ts +23 -0
- package/dist/server/cursor.js +58 -0
- package/dist/server/lifecycle.d.ts +7 -0
- package/dist/server/lifecycle.js +29 -0
- package/dist/server/mcp-http.d.ts +5 -0
- package/dist/server/mcp-http.js +199 -0
- package/dist/server/request.d.ts +33 -0
- package/dist/server/request.js +103 -0
- package/dist/server/routes/admin.d.ts +9 -0
- package/dist/server/routes/admin.js +158 -0
- package/dist/server/routes/customer-notes.d.ts +7 -0
- package/dist/server/routes/customer-notes.js +112 -0
- package/dist/server/routes/decisions.d.ts +7 -0
- package/dist/server/routes/decisions.js +133 -0
- package/dist/server/routes/incidents.d.ts +7 -0
- package/dist/server/routes/incidents.js +126 -0
- package/dist/server/routes/memories.d.ts +10 -0
- package/dist/server/routes/memories.js +179 -0
- package/dist/server/routes/policies.d.ts +8 -0
- package/dist/server/routes/policies.js +151 -0
- package/dist/server/routes/predictions.d.ts +7 -0
- package/dist/server/routes/predictions.js +164 -0
- package/dist/server/routes/processes.d.ts +7 -0
- package/dist/server/routes/processes.js +161 -0
- package/dist/server/routes/project-briefs.d.ts +8 -0
- package/dist/server/routes/project-briefs.js +136 -0
- package/dist/server/routes/recall.d.ts +8 -0
- package/dist/server/routes/recall.js +340 -0
- package/dist/server/routes/skills.d.ts +8 -0
- package/dist/server/routes/skills.js +150 -0
- package/dist/server/types.d.ts +56 -0
- package/dist/server/types.js +2 -0
- package/dist/server/validation.d.ts +14 -0
- package/dist/server/validation.js +91 -0
- package/dist/server.d.ts +7 -61
- package/dist/server.js +69 -2362
- package/dist/session-digest.d.ts +1 -1
- package/dist/session-digest.js +9 -2
- package/dist/shared.d.ts +3 -1
- package/dist/shared.js +26 -22
- package/dist/skills.d.ts +3 -0
- package/dist/skills.js +7 -5
- package/dist/stdin.js +2 -2
- package/dist/store/audit-event.d.ts +19 -0
- package/dist/store/audit-event.js +33 -0
- package/dist/store/candidates.d.ts +42 -0
- package/dist/store/candidates.js +152 -0
- package/dist/store/conflicts.d.ts +44 -0
- package/dist/store/conflicts.js +444 -0
- package/dist/store/delete-and-batch.d.ts +63 -0
- package/dist/store/delete-and-batch.js +310 -0
- package/dist/store/entry-reads.d.ts +92 -0
- package/dist/store/entry-reads.js +255 -0
- package/dist/store/entry-row.d.ts +67 -0
- package/dist/store/entry-row.js +208 -0
- package/dist/store/entry-writes.d.ts +46 -0
- package/dist/store/entry-writes.js +148 -0
- package/dist/store/handoffs.d.ts +26 -0
- package/dist/store/handoffs.js +184 -0
- package/dist/store/index-and-stats.d.ts +52 -0
- package/dist/store/index-and-stats.js +214 -0
- package/dist/store/markdown.d.ts +10 -0
- package/dist/store/markdown.js +108 -0
- package/dist/store/mirrors.d.ts +49 -0
- package/dist/store/mirrors.js +312 -0
- package/dist/store/open.d.ts +15 -0
- package/dist/store/open.js +223 -0
- package/dist/store/rows.d.ts +178 -0
- package/dist/store/rows.js +158 -0
- package/dist/store/search-rows.d.ts +86 -0
- package/dist/store/search-rows.js +254 -0
- package/dist/store/sessions.d.ts +83 -0
- package/dist/store/sessions.js +272 -0
- package/dist/store/summaries.d.ts +94 -0
- package/dist/store/summaries.js +377 -0
- package/dist/store/tenant-lookup.d.ts +12 -0
- package/dist/store/tenant-lookup.js +16 -0
- package/dist/store-cards.js +2 -1
- package/dist/summary-dirty.d.ts +4 -0
- package/dist/summary-dirty.js +32 -0
- package/dist/support-bundle.js +4 -3
- package/dist/tenant.js +2 -2
- package/dist/tokenize.d.ts +2 -0
- package/dist/tokenize.js +16 -0
- package/dist/transcript-tail.d.ts +7 -0
- package/dist/transcript-tail.js +48 -0
- package/dist/vector-store.d.ts +27 -0
- package/dist/vector-store.js +210 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/working-memory.js +1 -1
- package/dist/yaml.js +36 -11
- package/dist-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
- package/dist-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
- package/dist-ui/assets/index-DPN7cP19.js +33 -0
- package/dist-ui/assets/index-dFloKRVr.css +1 -0
- package/dist-ui/index.html +3 -25
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/capture.d.ts +0 -155
- package/dist/capture.js +0 -1295
- package/dist/consolidate.d.ts +0 -58
- package/dist/consolidate.js +0 -1124
- package/dist/graph.d.ts +0 -245
- package/dist/hooks.d.ts +0 -208
- package/dist/hooks.js +0 -1076
- package/dist/importers.js +0 -900
- package/dist/predictions.js +0 -620
- package/dist/search.d.ts +0 -320
- package/dist/search.js +0 -970
- package/dist/store.d.ts +0 -776
- package/dist/store.js +0 -3473
- package/dist-ui/assets/d3-BiWEKnn4.js +0 -1
- package/dist-ui/assets/index-BhT8RvO6.js +0 -61
- package/dist-ui/assets/index-RoXXJ5dq.css +0 -1
- package/dist-ui/assets/three-BDgTxR1l.js +0 -4112
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
/** The caller's `X-Request-Id` when it is a short plain token, else a fresh UUID. */
|
|
3
|
+
export declare function resolveRequestId(header: string | string[] | undefined): string;
|
|
4
|
+
/** One line per failed request; 4xx is the caller's mistake, so it stays below the default level and skips the stack. */
|
|
5
|
+
export declare function logRequestFailure<E>(req: IncomingMessage, err: E, requestId: string, status: number): void;
|
|
6
|
+
/** The status and client message for a failed request; a held write lock is a retryable 503, never a 500. */
|
|
7
|
+
export declare function replyFor<E>(err: E): {
|
|
8
|
+
status: number;
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function sendError(res: ServerResponse, status: number, message: string): void;
|
|
12
|
+
interface ParsedRoute {
|
|
13
|
+
method: string;
|
|
14
|
+
path: string;
|
|
15
|
+
query: URLSearchParams;
|
|
16
|
+
}
|
|
17
|
+
export declare function parseRequest(req: IncomingMessage): ParsedRoute;
|
|
18
|
+
export declare function matchPath(pattern: string, path: string): Record<string, string> | null;
|
|
19
|
+
export declare const requestIds: WeakMap<IncomingMessage, string>;
|
|
20
|
+
/**
|
|
21
|
+
* Reject URL-encoded slashes in path segments BEFORE the URL parser decodes
|
|
22
|
+
* them — otherwise `%2F` becomes `/`, path-split runs, and the route either
|
|
23
|
+
* silently 404s or matches the wrong template.
|
|
24
|
+
*
|
|
25
|
+
* codex round 3 P2: only scan the PATHNAME portion of the raw URL, not the
|
|
26
|
+
* query string. Pre-fix, `?q=https%3A%2F%2Fexample.com` would 400 because
|
|
27
|
+
* the regex matched `%2F` anywhere in `req.url`. Recall queries containing
|
|
28
|
+
* URLs would have been rejected as bypass attempts. Splitting on the first
|
|
29
|
+
* `?` confines the check to the path.
|
|
30
|
+
*/
|
|
31
|
+
export declare function rejectEncodedSlash(rawUrl: string): void;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { isSqliteBusy, STORE_BUSY_MESSAGE } from '../db.js';
|
|
3
|
+
import { errorFields, log } from '../log.js';
|
|
4
|
+
import { HttpError, mapApiError, sendJson } from '../http-util.js';
|
|
5
|
+
// The caller's id lands in a response header and in logs, so only a short plain token is echoed back.
|
|
6
|
+
const REQUEST_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
7
|
+
/** The caller's `X-Request-Id` when it is a short plain token, else a fresh UUID. */
|
|
8
|
+
export function resolveRequestId(header) {
|
|
9
|
+
const value = Array.isArray(header) ? undefined : header;
|
|
10
|
+
return value && REQUEST_ID_RE.test(value) ? value : randomUUID();
|
|
11
|
+
}
|
|
12
|
+
/** One line per failed request; 4xx is the caller's mistake, so it stays below the default level and skips the stack. */
|
|
13
|
+
export function logRequestFailure(req, err, requestId, status) {
|
|
14
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
15
|
+
const line = `${req.method ?? 'GET'} ${(req.url ?? '/').split('?')[0]} failed: ${message}`;
|
|
16
|
+
if (status >= 500)
|
|
17
|
+
log.error(line, { requestId, status, ...errorFields(err) });
|
|
18
|
+
else
|
|
19
|
+
log.info(line, { requestId, status });
|
|
20
|
+
}
|
|
21
|
+
/** The status and client message for a failed request; a held write lock is a retryable 503, never a 500. */
|
|
22
|
+
export function replyFor(err) {
|
|
23
|
+
return isSqliteBusy(err) ? { status: 503, message: STORE_BUSY_MESSAGE } : mapApiError(err);
|
|
24
|
+
}
|
|
25
|
+
export function sendError(res, status, message) {
|
|
26
|
+
sendJson(res, status, { error: message });
|
|
27
|
+
}
|
|
28
|
+
export function parseRequest(req) {
|
|
29
|
+
let url;
|
|
30
|
+
try {
|
|
31
|
+
url = new URL(req.url ?? '/', 'http://placeholder');
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
// A request target the URL parser rejects is the caller's fault, not a server failure.
|
|
35
|
+
if (e instanceof TypeError)
|
|
36
|
+
throw new HttpError(400, e.message);
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
method: req.method ?? 'GET',
|
|
41
|
+
path: url.pathname,
|
|
42
|
+
query: url.searchParams,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Lightweight pattern matcher for /v1/memories/:id/<action>. Avoids pulling
|
|
47
|
+
* in a router dependency for the half-dozen patterns we actually use.
|
|
48
|
+
*
|
|
49
|
+
* Returns null if `path` does not match `pattern`. Otherwise returns an object
|
|
50
|
+
* mapping each :param name to its value. Path segments are exact-matched
|
|
51
|
+
* except for parameter slots.
|
|
52
|
+
*/
|
|
53
|
+
function decodePathSegment(segment) {
|
|
54
|
+
try {
|
|
55
|
+
return decodeURIComponent(segment);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
if (e instanceof URIError)
|
|
59
|
+
throw new HttpError(400, e.message);
|
|
60
|
+
throw e;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function matchPath(pattern, path) {
|
|
64
|
+
const patternParts = pattern.split('/');
|
|
65
|
+
const pathParts = path.split('/');
|
|
66
|
+
if (patternParts.length !== pathParts.length)
|
|
67
|
+
return null;
|
|
68
|
+
const params = {};
|
|
69
|
+
for (let i = 0; i < patternParts.length; i++) {
|
|
70
|
+
const pp = patternParts[i];
|
|
71
|
+
const ap = pathParts[i];
|
|
72
|
+
if (pp.startsWith(':')) {
|
|
73
|
+
if (ap.length === 0)
|
|
74
|
+
return null;
|
|
75
|
+
params[pp.slice(1)] = decodePathSegment(ap);
|
|
76
|
+
}
|
|
77
|
+
else if (pp !== ap) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return params;
|
|
82
|
+
}
|
|
83
|
+
// The auth helpers only see the request, so its id rides here for their log lines.
|
|
84
|
+
export const requestIds = new WeakMap();
|
|
85
|
+
/**
|
|
86
|
+
* Reject URL-encoded slashes in path segments BEFORE the URL parser decodes
|
|
87
|
+
* them — otherwise `%2F` becomes `/`, path-split runs, and the route either
|
|
88
|
+
* silently 404s or matches the wrong template.
|
|
89
|
+
*
|
|
90
|
+
* codex round 3 P2: only scan the PATHNAME portion of the raw URL, not the
|
|
91
|
+
* query string. Pre-fix, `?q=https%3A%2F%2Fexample.com` would 400 because
|
|
92
|
+
* the regex matched `%2F` anywhere in `req.url`. Recall queries containing
|
|
93
|
+
* URLs would have been rejected as bypass attempts. Splitting on the first
|
|
94
|
+
* `?` confines the check to the path.
|
|
95
|
+
*/
|
|
96
|
+
export function rejectEncodedSlash(rawUrl) {
|
|
97
|
+
const queryIdx = rawUrl.indexOf('?');
|
|
98
|
+
const pathname = queryIdx === -1 ? rawUrl : rawUrl.slice(0, queryIdx);
|
|
99
|
+
if (/%2[Ff]/.test(pathname)) {
|
|
100
|
+
throw new HttpError(400, 'URL-encoded slash (%2F) not allowed in path segments');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { RouteRequest } from '../types.js';
|
|
2
|
+
export declare function handleCreateAuthKey({ req, res, opts }: RouteRequest): Promise<void>;
|
|
3
|
+
export declare function handleListAuthKeys({ req, res, opts, query }: RouteRequest): Promise<void>;
|
|
4
|
+
export declare function handleRevokeAuthKey({ req, res, opts }: RouteRequest, keyMatch: Record<string, string>): Promise<void>;
|
|
5
|
+
export declare function handleListQuarantine({ req, res, opts, query }: RouteRequest): Promise<void>;
|
|
6
|
+
export declare function handleApproveQuarantine({ req, res, opts }: RouteRequest, quarantineApproveMatch: Record<string, string>): Promise<void>;
|
|
7
|
+
export declare function handleRejectQuarantine({ req, res, opts }: RouteRequest, quarantineRejectMatch: Record<string, string>): Promise<void>;
|
|
8
|
+
export declare function handleListAudit({ req, res, opts, query }: RouteRequest): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=admin.d.ts.map
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Admin routes: API keys, quarantine and the audit log.
|
|
2
|
+
import { AUDIT_OPS } from '../../audit.js';
|
|
3
|
+
import { auditList, authCreate, authListRows, authRevoke, quarantineApprove, quarantineList, quarantineReject } from '../../api.js';
|
|
4
|
+
import { HttpError, sendJson } from '../../http-util.js';
|
|
5
|
+
import { assertCrossTenantAdmin, buildContextWithAuth } from '../auth.js';
|
|
6
|
+
import { pageOf, parseCursor, setNextCursorHeader } from '../cursor.js';
|
|
7
|
+
import { isJsonString, isSetMember, parseJsonBody, parseListLimit, validateIdSegment } from '../validation.js';
|
|
8
|
+
const VALID_AUDIT_OPS = new Set(AUDIT_OPS);
|
|
9
|
+
// Cap on GET /v1/audit?limit=. Matches docs/api.md (when written) and is large
|
|
10
|
+
// enough to dump a small deployment's full audit log without paginating, but
|
|
11
|
+
// small enough that a malicious client can't ask for the world.
|
|
12
|
+
const MAX_AUDIT_LIMIT = 10000;
|
|
13
|
+
// GET /v1/auth/keys had no limit, so its default page is the cap: a deployment below 1000 keys sees no change.
|
|
14
|
+
const MAX_AUTH_KEYS_PAGE = 1000;
|
|
15
|
+
// POST /v1/auth/keys — mint a new API key. Plaintext lands in the response
|
|
16
|
+
// body (Task 8): the HTTP layer hands it to the client; the user-facing
|
|
17
|
+
// "store this somewhere safe" warning belongs in the CLI client, not here.
|
|
18
|
+
export async function handleCreateAuthKey({ req, res, opts }) {
|
|
19
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
20
|
+
const body = await parseJsonBody(req, ctx);
|
|
21
|
+
const labelRaw = body['label'];
|
|
22
|
+
if (labelRaw !== undefined && !isJsonString(labelRaw)) {
|
|
23
|
+
throw new HttpError(400, 'label must be a string');
|
|
24
|
+
}
|
|
25
|
+
// v1.12.3: optional body.role mirrors the --role CLI flag. Validated
|
|
26
|
+
// strictly — anything other than 'admin'|'member' is a 400 (no silent
|
|
27
|
+
// fallback to admin). authCreate refuses a member caller with a 403.
|
|
28
|
+
const roleRaw = body['role'];
|
|
29
|
+
let role;
|
|
30
|
+
if (roleRaw !== undefined) {
|
|
31
|
+
if (roleRaw !== 'admin' && roleRaw !== 'member') {
|
|
32
|
+
throw new HttpError(400, "role must be 'admin' or 'member'");
|
|
33
|
+
}
|
|
34
|
+
role = roleRaw;
|
|
35
|
+
}
|
|
36
|
+
// Security: any `tenantId` in the body is IGNORED. The minted key is
|
|
37
|
+
// bound to the caller's authenticated tenant (ctx.tenantId, resolved
|
|
38
|
+
// from the Bearer token). Forwarding body.tenantId here would let
|
|
39
|
+
// tenant A mint a key for tenant B — see authCreate doc comment.
|
|
40
|
+
const result = authCreate(ctx, {
|
|
41
|
+
label: labelRaw,
|
|
42
|
+
role,
|
|
43
|
+
});
|
|
44
|
+
sendJson(res, 200, result);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// GET /v1/auth/keys?active=true&limit=&cursor=: list keys visible to ctx.tenantId.
|
|
48
|
+
// `active` defaults to true so the common case (show me usable keys) is
|
|
49
|
+
// a single GET; ?active=false includes revoked rows.
|
|
50
|
+
export async function handleListAuthKeys({ req, res, opts, query }) {
|
|
51
|
+
const activeRaw = query.get('active');
|
|
52
|
+
let active = true;
|
|
53
|
+
if (activeRaw !== null) {
|
|
54
|
+
if (activeRaw === 'true')
|
|
55
|
+
active = true;
|
|
56
|
+
else if (activeRaw === 'false')
|
|
57
|
+
active = false;
|
|
58
|
+
else
|
|
59
|
+
throw new HttpError(400, "active must be 'true' or 'false'");
|
|
60
|
+
}
|
|
61
|
+
const limit = parseListLimit(query.get('limit'), MAX_AUTH_KEYS_PAGE, MAX_AUTH_KEYS_PAGE);
|
|
62
|
+
const after = parseCursor(query.get('cursor'), 'integer', 'integer');
|
|
63
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
64
|
+
const page = pageOf(authListRows(ctx, { active, limit: limit + 1, after }), limit, (r) => ({ key: r.rowId, id: r.rowId }));
|
|
65
|
+
setNextCursorHeader(res, page.nextCursor);
|
|
66
|
+
sendJson(res, 200, page.items.map((r) => r.key));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// DELETE /v1/auth/keys/:keyId — revoke. Missing or cross-tenant keys are 404
|
|
70
|
+
// (no info leak); a member key targeting any key but its own is 403.
|
|
71
|
+
// 200 with the body rather than 204 so the caller sees revokedAt.
|
|
72
|
+
export async function handleRevokeAuthKey({ req, res, opts }, keyMatch) {
|
|
73
|
+
validateIdSegment(keyMatch.keyId, 'key id');
|
|
74
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
75
|
+
const result = authRevoke(ctx, keyMatch.keyId);
|
|
76
|
+
sendJson(res, 200, result);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// GET /v1/quarantine?status=&limit=&cursor=: CD5 review queue. quarantineList carries no role gate itself, so it's checked here.
|
|
80
|
+
export async function handleListQuarantine({ req, res, opts, query }) {
|
|
81
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
82
|
+
if (ctx.actor.role !== 'admin') {
|
|
83
|
+
throw new HttpError(403, '/v1/quarantine requires admin role');
|
|
84
|
+
}
|
|
85
|
+
const statusRaw = query.get('status');
|
|
86
|
+
let status = 'pending';
|
|
87
|
+
if (statusRaw !== null) {
|
|
88
|
+
if (statusRaw !== 'pending' && statusRaw !== 'approved' && statusRaw !== 'rejected' && statusRaw !== 'all') {
|
|
89
|
+
throw new HttpError(400, 'status must be one of: pending | approved | rejected | all');
|
|
90
|
+
}
|
|
91
|
+
status = statusRaw;
|
|
92
|
+
}
|
|
93
|
+
const limit = parseListLimit(query.get('limit'));
|
|
94
|
+
const after = parseCursor(query.get('cursor'), 'string', 'string');
|
|
95
|
+
const page = pageOf(quarantineList(ctx, { status, limit: limit + 1, after }), limit, (q) => ({ key: q.quarantinedAt, id: q.id }));
|
|
96
|
+
sendJson(res, 200, { quarantine: page.items, next_cursor: page.nextCursor });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// POST /v1/quarantine/:id/approve: admin only; ForbiddenError falls through to mapApiError's 403.
|
|
100
|
+
export async function handleApproveQuarantine({ req, res, opts }, quarantineApproveMatch) {
|
|
101
|
+
validateIdSegment(quarantineApproveMatch.id, 'memory id');
|
|
102
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
103
|
+
quarantineApprove(ctx, quarantineApproveMatch.id);
|
|
104
|
+
sendJson(res, 200, { approved: quarantineApproveMatch.id });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// POST /v1/quarantine/:id/reject: admin only; ForbiddenError falls through to mapApiError's 403.
|
|
108
|
+
export async function handleRejectQuarantine({ req, res, opts }, quarantineRejectMatch) {
|
|
109
|
+
validateIdSegment(quarantineRejectMatch.id, 'memory id');
|
|
110
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
111
|
+
quarantineReject(ctx, quarantineRejectMatch.id);
|
|
112
|
+
sendJson(res, 200, { rejected: quarantineRejectMatch.id });
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// GET /v1/audit?op=&since=&limit=&cursor=: read audit events. All three filters
|
|
116
|
+
// validated at the route boundary so an invalid value lands a 400 before
|
|
117
|
+
// we hit the DB.
|
|
118
|
+
export async function handleListAudit({ req, res, opts, query }) {
|
|
119
|
+
const opRaw = query.get('op');
|
|
120
|
+
let op;
|
|
121
|
+
if (opRaw !== null) {
|
|
122
|
+
if (!isSetMember(VALID_AUDIT_OPS, opRaw)) {
|
|
123
|
+
throw new HttpError(400, `invalid op: ${opRaw}`);
|
|
124
|
+
}
|
|
125
|
+
op = opRaw;
|
|
126
|
+
}
|
|
127
|
+
const sinceRaw = query.get('since');
|
|
128
|
+
let since;
|
|
129
|
+
if (sinceRaw !== null) {
|
|
130
|
+
const parsed = Date.parse(sinceRaw);
|
|
131
|
+
if (!Number.isFinite(parsed)) {
|
|
132
|
+
throw new HttpError(400, `invalid since: ${sinceRaw}`);
|
|
133
|
+
}
|
|
134
|
+
since = sinceRaw;
|
|
135
|
+
}
|
|
136
|
+
const limitRaw = query.get('limit');
|
|
137
|
+
let limit = 100;
|
|
138
|
+
if (limitRaw !== null) {
|
|
139
|
+
const parsed = Number(limitRaw);
|
|
140
|
+
if (!Number.isFinite(parsed) || !Number.isInteger(parsed) || parsed < 1 || parsed > MAX_AUDIT_LIMIT) {
|
|
141
|
+
throw new HttpError(400, `limit must be an integer between 1 and ${MAX_AUDIT_LIMIT}`);
|
|
142
|
+
}
|
|
143
|
+
limit = parsed;
|
|
144
|
+
}
|
|
145
|
+
const after = parseCursor(query.get('cursor'), 'string', 'integer');
|
|
146
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
147
|
+
// ?tenant=<t> reads another tenant (e.g. '__host__' for consolidate rows); admin only.
|
|
148
|
+
const tenantOverride = query.get('tenant');
|
|
149
|
+
const crossTenant = tenantOverride !== null && tenantOverride !== '' && tenantOverride !== ctx.tenantId;
|
|
150
|
+
if (crossTenant)
|
|
151
|
+
assertCrossTenantAdmin(ctx, '/v1/audit?tenant= for another tenant');
|
|
152
|
+
const effectiveCtx = crossTenant ? { ...ctx, tenantId: tenantOverride } : ctx;
|
|
153
|
+
const page = pageOf(auditList(effectiveCtx, { op, since, limit: limit + 1, after }), limit, (e) => ({ key: e.ts, id: e.id }));
|
|
154
|
+
setNextCursorHeader(res, page.nextCursor);
|
|
155
|
+
sendJson(res, 200, page.items);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=admin.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RouteRequest } from '../types.js';
|
|
2
|
+
export declare function handleCreateCustomerNote({ req, res, opts }: RouteRequest): Promise<void>;
|
|
3
|
+
export declare function handleListCustomerNotes({ req, res, opts, query }: RouteRequest): Promise<void>;
|
|
4
|
+
export declare function handleSupersedeCustomerNote({ req, res, opts }: RouteRequest, noteSupersedeMatch: RegExpMatchArray): Promise<void>;
|
|
5
|
+
export declare function handleCloseCustomerNote({ req, res, opts }: RouteRequest, noteCloseMatch: RegExpMatchArray): Promise<void>;
|
|
6
|
+
export declare function handleGetCustomerNote({ req, res, opts }: RouteRequest, noteByIdMatch: RegExpMatchArray): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=customer-notes.d.ts.map
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// /v1/customer-notes routes.
|
|
2
|
+
import { closeCustomerNote, loadCustomerNoteById, loadCustomerNotes, saveCustomerNote, VALID_NOTE_STATES } from '../../customer-notes.js';
|
|
3
|
+
import { HttpError, sendJson } from '../../http-util.js';
|
|
4
|
+
import { buildContextWithAuth } from '../auth.js';
|
|
5
|
+
import { byCreatedAt, pageOf, parseCursor } from '../cursor.js';
|
|
6
|
+
import { isJsonString, isSetMember, parseJsonBody, parseListLimit } from '../validation.js';
|
|
7
|
+
// ── E2 customer_note routes ──
|
|
8
|
+
//
|
|
9
|
+
// 5 routes (no assembler/refresh): POST /v1/customer-notes (new; body customer +
|
|
10
|
+
// note), GET /v1/customer-notes (list; status + customer filter; shared
|
|
11
|
+
// parseListLimit), GET /v1/customer-notes/:id, POST /v1/customer-notes/:id/supersede,
|
|
12
|
+
// POST /v1/customer-notes/:id/close. DoS caps: customer 256, note 8192,
|
|
13
|
+
// changeSummary 4096. The store validates + throws; the boundary maps validation ->
|
|
14
|
+
// 400, not-found -> 404, not-active -> 409. Mirrors /v1/project-briefs.
|
|
15
|
+
export async function handleCreateCustomerNote({ req, res, opts }) {
|
|
16
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
17
|
+
const body = await parseJsonBody(req, ctx);
|
|
18
|
+
const customer = body['customer'];
|
|
19
|
+
if (!isJsonString(customer) || customer.trim().length === 0) {
|
|
20
|
+
throw new HttpError(400, 'customer is required (non-empty string)');
|
|
21
|
+
}
|
|
22
|
+
if (customer.length > 256) {
|
|
23
|
+
throw new HttpError(400, 'customer exceeds 256-character cap');
|
|
24
|
+
}
|
|
25
|
+
const note = body['note'];
|
|
26
|
+
if (!isJsonString(note) || note.trim().length === 0) {
|
|
27
|
+
throw new HttpError(400, 'note is required (non-empty string)');
|
|
28
|
+
}
|
|
29
|
+
if (note.length > 8192) {
|
|
30
|
+
throw new HttpError(400, 'note exceeds 8192-character cap');
|
|
31
|
+
}
|
|
32
|
+
const customerNote = saveCustomerNote(opts.hippoRoot, ctx.tenantId, {
|
|
33
|
+
customer,
|
|
34
|
+
note,
|
|
35
|
+
}, ctx.actor.subject);
|
|
36
|
+
sendJson(res, 201, { note: customerNote });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
export async function handleListCustomerNotes({ req, res, opts, query }) {
|
|
40
|
+
const status = query.get('status') ?? 'all';
|
|
41
|
+
const customerFilter = query.get('customer');
|
|
42
|
+
const limit = parseListLimit(query.get('limit'));
|
|
43
|
+
const after = parseCursor(query.get('cursor'), 'string', 'integer');
|
|
44
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
45
|
+
const listOpts = { limit: limit + 1, after };
|
|
46
|
+
if (customerFilter !== null && customerFilter.trim().length > 0) {
|
|
47
|
+
listOpts.customer = customerFilter.trim();
|
|
48
|
+
}
|
|
49
|
+
if (status !== 'all') {
|
|
50
|
+
if (!isSetMember(VALID_NOTE_STATES, status)) {
|
|
51
|
+
throw new HttpError(400, `status must be one of: active | superseded | closed | all (got "${status}")`);
|
|
52
|
+
}
|
|
53
|
+
listOpts.status = status;
|
|
54
|
+
}
|
|
55
|
+
const notes = loadCustomerNotes(opts.hippoRoot, ctx.tenantId, listOpts);
|
|
56
|
+
const page = pageOf(notes, limit, byCreatedAt);
|
|
57
|
+
sendJson(res, 200, { notes: page.items, next_cursor: page.nextCursor });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
export async function handleSupersedeCustomerNote({ req, res, opts }, noteSupersedeMatch) {
|
|
61
|
+
const id = parseInt(noteSupersedeMatch[1], 10);
|
|
62
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
63
|
+
const body = await parseJsonBody(req, ctx);
|
|
64
|
+
const note = body['note'];
|
|
65
|
+
if (!isJsonString(note) || note.trim().length === 0) {
|
|
66
|
+
throw new HttpError(400, 'note is required (non-empty string)');
|
|
67
|
+
}
|
|
68
|
+
if (note.length > 8192) {
|
|
69
|
+
throw new HttpError(400, 'note exceeds 8192-character cap');
|
|
70
|
+
}
|
|
71
|
+
const changeRaw = body['changeSummary'];
|
|
72
|
+
let changeSummary;
|
|
73
|
+
if (changeRaw !== undefined && changeRaw !== null) {
|
|
74
|
+
if (!isJsonString(changeRaw)) {
|
|
75
|
+
throw new HttpError(400, 'changeSummary must be a string');
|
|
76
|
+
}
|
|
77
|
+
if (changeRaw.length > 4096) {
|
|
78
|
+
throw new HttpError(400, 'changeSummary exceeds 4096-character cap');
|
|
79
|
+
}
|
|
80
|
+
changeSummary = changeRaw;
|
|
81
|
+
}
|
|
82
|
+
const existing = loadCustomerNoteById(opts.hippoRoot, ctx.tenantId, id);
|
|
83
|
+
if (!existing) {
|
|
84
|
+
throw new HttpError(404, `customer note ${id} not found`);
|
|
85
|
+
}
|
|
86
|
+
const customerNote = saveCustomerNote(opts.hippoRoot, ctx.tenantId, {
|
|
87
|
+
customer: existing.customer,
|
|
88
|
+
note,
|
|
89
|
+
changeSummary,
|
|
90
|
+
supersedesNoteId: id,
|
|
91
|
+
}, ctx.actor.subject);
|
|
92
|
+
sendJson(res, 200, { note: customerNote });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
export async function handleCloseCustomerNote({ req, res, opts }, noteCloseMatch) {
|
|
96
|
+
const id = parseInt(noteCloseMatch[1], 10);
|
|
97
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
98
|
+
const customerNote = closeCustomerNote(opts.hippoRoot, ctx.tenantId, id, ctx.actor.subject);
|
|
99
|
+
sendJson(res, 200, { note: customerNote });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
export async function handleGetCustomerNote({ req, res, opts }, noteByIdMatch) {
|
|
103
|
+
const id = parseInt(noteByIdMatch[1], 10);
|
|
104
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
105
|
+
const customerNote = loadCustomerNoteById(opts.hippoRoot, ctx.tenantId, id);
|
|
106
|
+
if (!customerNote) {
|
|
107
|
+
throw new HttpError(404, `customer note ${id} not found`);
|
|
108
|
+
}
|
|
109
|
+
sendJson(res, 200, { note: customerNote });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=customer-notes.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RouteRequest } from '../types.js';
|
|
2
|
+
export declare function handleCreateDecision({ req, res, opts }: RouteRequest): Promise<void>;
|
|
3
|
+
export declare function handleListDecisions({ req, res, opts, query }: RouteRequest): Promise<void>;
|
|
4
|
+
export declare function handleSupersedeDecision({ req, res, opts }: RouteRequest, decisionSupersedeMatch: RegExpMatchArray): Promise<void>;
|
|
5
|
+
export declare function handleCloseDecision({ req, res, opts }: RouteRequest, decisionCloseMatch: RegExpMatchArray): Promise<void>;
|
|
6
|
+
export declare function handleGetDecision({ req, res, opts }: RouteRequest, decisionByIdMatch: RegExpMatchArray): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=decisions.d.ts.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// /v1/decisions routes.
|
|
2
|
+
import { closeDecision, loadDecisionById, loadDecisions, saveDecision, VALID_DECISION_STATES } from '../../decisions.js';
|
|
3
|
+
import { HttpError, sendJson } from '../../http-util.js';
|
|
4
|
+
import { NotFoundError } from '../../api-errors.js';
|
|
5
|
+
import { buildContextWithAuth } from '../auth.js';
|
|
6
|
+
import { byCreatedAt, pageOf, parseCursor } from '../cursor.js';
|
|
7
|
+
import { isJsonNumber, isJsonString, isSetMember, parseJsonBody, parseListLimit } from '../validation.js';
|
|
8
|
+
// ── decisions (E2 first-class object) ──
|
|
9
|
+
//
|
|
10
|
+
// 5 routes: POST /v1/decisions (create, optional supersedesDecisionId),
|
|
11
|
+
// GET /v1/decisions (list, status filter), GET /v1/decisions/:id (show),
|
|
12
|
+
// POST /v1/decisions/:id/supersede (create a successor + supersede :id),
|
|
13
|
+
// POST /v1/decisions/:id/close (retire). Bearer-authed + tenant-scoped via
|
|
14
|
+
// buildContextWithAuth. status validated against VALID_DECISION_STATES.
|
|
15
|
+
// DoS caps: text 4096, context 4096 (v1.11.4 pattern). The HTTP surface is
|
|
16
|
+
// new (no legacy --supersedes <memory-id> constraint), so it supersedes by
|
|
17
|
+
// table id and never weakens a memory mirror.
|
|
18
|
+
export async function handleCreateDecision({ req, res, opts }) {
|
|
19
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
20
|
+
const body = await parseJsonBody(req, ctx);
|
|
21
|
+
const text = body['text'];
|
|
22
|
+
if (!isJsonString(text) || text.length === 0) {
|
|
23
|
+
throw new HttpError(400, 'text is required (non-empty string)');
|
|
24
|
+
}
|
|
25
|
+
if (text.length > 4096) {
|
|
26
|
+
throw new HttpError(400, 'text exceeds 4096-character cap');
|
|
27
|
+
}
|
|
28
|
+
const contextRaw = body['context'];
|
|
29
|
+
let context;
|
|
30
|
+
if (contextRaw !== undefined && contextRaw !== null) {
|
|
31
|
+
if (!isJsonString(contextRaw)) {
|
|
32
|
+
throw new HttpError(400, 'context must be a string');
|
|
33
|
+
}
|
|
34
|
+
if (contextRaw.length > 4096) {
|
|
35
|
+
throw new HttpError(400, 'context exceeds 4096-character cap');
|
|
36
|
+
}
|
|
37
|
+
context = contextRaw;
|
|
38
|
+
}
|
|
39
|
+
const supRaw = body['supersedesDecisionId'];
|
|
40
|
+
let supersedesDecisionId;
|
|
41
|
+
if (supRaw !== undefined && supRaw !== null) {
|
|
42
|
+
if (!isJsonNumber(supRaw) || !Number.isInteger(supRaw) || supRaw <= 0) {
|
|
43
|
+
throw new HttpError(400, 'supersedesDecisionId must be a positive integer');
|
|
44
|
+
}
|
|
45
|
+
supersedesDecisionId = supRaw;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const decision = saveDecision(opts.hippoRoot, ctx.tenantId, {
|
|
49
|
+
decisionText: text,
|
|
50
|
+
context,
|
|
51
|
+
supersedesDecisionId,
|
|
52
|
+
}, ctx.actor.subject);
|
|
53
|
+
sendJson(res, 201, { decision });
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
// A missing referenced row is a conflict with the create, not a missing target.
|
|
57
|
+
if (e instanceof NotFoundError)
|
|
58
|
+
throw new HttpError(409, e.message);
|
|
59
|
+
throw e;
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
export async function handleListDecisions({ req, res, opts, query }) {
|
|
64
|
+
const status = query.get('status') ?? 'all';
|
|
65
|
+
const limit = parseListLimit(query.get('limit'));
|
|
66
|
+
const after = parseCursor(query.get('cursor'), 'string', 'integer');
|
|
67
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
68
|
+
let decisions;
|
|
69
|
+
if (status === 'all') {
|
|
70
|
+
decisions = loadDecisions(opts.hippoRoot, ctx.tenantId, { limit: limit + 1, after });
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
if (!isSetMember(VALID_DECISION_STATES, status)) {
|
|
74
|
+
throw new HttpError(400, `status must be one of: active | superseded | closed | all (got "${status}")`);
|
|
75
|
+
}
|
|
76
|
+
decisions = loadDecisions(opts.hippoRoot, ctx.tenantId, {
|
|
77
|
+
status,
|
|
78
|
+
limit: limit + 1,
|
|
79
|
+
after,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const page = pageOf(decisions, limit, byCreatedAt);
|
|
83
|
+
sendJson(res, 200, { decisions: page.items, next_cursor: page.nextCursor });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
export async function handleSupersedeDecision({ req, res, opts }, decisionSupersedeMatch) {
|
|
87
|
+
const oldId = parseInt(decisionSupersedeMatch[1], 10);
|
|
88
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
89
|
+
const body = await parseJsonBody(req, ctx);
|
|
90
|
+
const text = body['text'];
|
|
91
|
+
if (!isJsonString(text) || text.length === 0) {
|
|
92
|
+
throw new HttpError(400, 'text is required (non-empty string)');
|
|
93
|
+
}
|
|
94
|
+
if (text.length > 4096) {
|
|
95
|
+
throw new HttpError(400, 'text exceeds 4096-character cap');
|
|
96
|
+
}
|
|
97
|
+
const contextRaw = body['context'];
|
|
98
|
+
let context;
|
|
99
|
+
if (contextRaw !== undefined && contextRaw !== null) {
|
|
100
|
+
if (!isJsonString(contextRaw)) {
|
|
101
|
+
throw new HttpError(400, 'context must be a string');
|
|
102
|
+
}
|
|
103
|
+
if (contextRaw.length > 4096) {
|
|
104
|
+
throw new HttpError(400, 'context exceeds 4096-character cap');
|
|
105
|
+
}
|
|
106
|
+
context = contextRaw;
|
|
107
|
+
}
|
|
108
|
+
const decision = saveDecision(opts.hippoRoot, ctx.tenantId, {
|
|
109
|
+
decisionText: text,
|
|
110
|
+
context,
|
|
111
|
+
supersedesDecisionId: oldId,
|
|
112
|
+
}, ctx.actor.subject);
|
|
113
|
+
sendJson(res, 201, { decision });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
export async function handleCloseDecision({ req, res, opts }, decisionCloseMatch) {
|
|
117
|
+
const id = parseInt(decisionCloseMatch[1], 10);
|
|
118
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
119
|
+
const decision = closeDecision(opts.hippoRoot, ctx.tenantId, id, ctx.actor.subject);
|
|
120
|
+
sendJson(res, 200, { decision });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
export async function handleGetDecision({ req, res, opts }, decisionByIdMatch) {
|
|
124
|
+
const id = parseInt(decisionByIdMatch[1], 10);
|
|
125
|
+
const ctx = await buildContextWithAuth(req, opts);
|
|
126
|
+
const decision = loadDecisionById(opts.hippoRoot, ctx.tenantId, id);
|
|
127
|
+
if (!decision) {
|
|
128
|
+
throw new HttpError(404, `decision ${id} not found`);
|
|
129
|
+
}
|
|
130
|
+
sendJson(res, 200, { decision });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=decisions.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RouteRequest } from '../types.js';
|
|
2
|
+
export declare function handleCreateIncident({ req, res, opts }: RouteRequest): Promise<void>;
|
|
3
|
+
export declare function handleListIncidents({ req, res, opts, query }: RouteRequest): Promise<void>;
|
|
4
|
+
export declare function handleResolveIncident({ req, res, opts }: RouteRequest, incidentResolveMatch: RegExpMatchArray): Promise<void>;
|
|
5
|
+
export declare function handleCloseIncident({ req, res, opts }: RouteRequest, incidentCloseMatch: RegExpMatchArray): Promise<void>;
|
|
6
|
+
export declare function handleGetIncident({ req, res, opts }: RouteRequest, incidentByIdMatch: RegExpMatchArray): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=incidents.d.ts.map
|