hippo-memory 1.43.3 → 1.45.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 +14 -12
- package/bin/hippo.js +3 -1
- package/dist/api.d.ts +21 -21
- package/dist/api.js +69 -42
- package/dist/audit-prune.js +4 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +9 -0
- package/dist/autolearn.d.ts +1 -1
- package/dist/autolearn.js +2 -1
- package/dist/capture.d.ts +11 -10
- package/dist/capture.js +22 -30
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +309 -171
- package/dist/client.d.ts +4 -21
- package/dist/client.js +3 -112
- package/dist/config.js +2 -1
- package/dist/consolidate.d.ts +3 -0
- package/dist/consolidate.js +44 -42
- package/dist/dag.d.ts +1 -0
- package/dist/dag.js +10 -5
- package/dist/dashboard.js +7 -3
- package/dist/db.js +16 -24
- package/dist/dedupe.d.ts +1 -0
- package/dist/dedupe.js +4 -7
- package/dist/embedding-provider.d.ts +1 -1
- package/dist/embedding-provider.js +3 -2
- package/dist/embeddings.js +81 -8
- package/dist/extract.d.ts +2 -0
- package/dist/extract.js +9 -4
- package/dist/goals.js +12 -3
- package/dist/mcp/server.js +21 -36
- package/dist/memory.d.ts +3 -0
- package/dist/memory.js +7 -1
- package/dist/physics-state.js +4 -1
- package/dist/raw-archive.js +5 -2
- package/dist/recall-trace.js +4 -1
- package/dist/refine-llm.js +3 -2
- package/dist/rerankers/jev.js +3 -2
- package/dist/rerankers/llm.js +3 -2
- package/dist/search.js +3 -3
- package/dist/server.d.ts +5 -0
- package/dist/server.js +39 -29
- package/dist/shared.js +1 -1
- package/dist/stdin.d.ts +12 -0
- package/dist/stdin.js +41 -0
- package/dist/store.d.ts +18 -11
- package/dist/store.js +152 -65
- package/dist/version.d.ts +4 -6
- package/dist/version.js +4 -7
- 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 +8 -5
- package/dist/ablation.d.ts.map +0 -1
- package/dist/ablation.js.map +0 -1
- package/dist/ambient.d.ts.map +0 -1
- package/dist/ambient.js.map +0 -1
- package/dist/api.d.ts.map +0 -1
- package/dist/api.js.map +0 -1
- package/dist/audit-prune.d.ts.map +0 -1
- package/dist/audit-prune.js.map +0 -1
- package/dist/audit.d.ts.map +0 -1
- package/dist/audit.js.map +0 -1
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/autolearn.d.ts.map +0 -1
- package/dist/autolearn.js.map +0 -1
- package/dist/availability.d.ts.map +0 -1
- package/dist/availability.js.map +0 -1
- package/dist/benchmarks/e1.3/incident-recall-eval.js +0 -78
- package/dist/benchmarks/e1.3/incident-recall-eval.js.map +0 -1
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +0 -103
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +0 -1
- package/dist/capture.d.ts.map +0 -1
- package/dist/capture.js.map +0 -1
- package/dist/card-detail.d.ts.map +0 -1
- package/dist/card-detail.js.map +0 -1
- package/dist/card.d.ts.map +0 -1
- package/dist/card.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/compare.d.ts.map +0 -1
- package/dist/compare.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/connectors/github/backfill.d.ts.map +0 -1
- package/dist/connectors/github/backfill.js.map +0 -1
- package/dist/connectors/github/cli-impl.d.ts.map +0 -1
- package/dist/connectors/github/cli-impl.js.map +0 -1
- package/dist/connectors/github/deletion.d.ts.map +0 -1
- package/dist/connectors/github/deletion.js.map +0 -1
- package/dist/connectors/github/dlq.d.ts.map +0 -1
- package/dist/connectors/github/dlq.js.map +0 -1
- package/dist/connectors/github/idempotency.d.ts.map +0 -1
- package/dist/connectors/github/idempotency.js.map +0 -1
- package/dist/connectors/github/ingest.d.ts.map +0 -1
- package/dist/connectors/github/ingest.js.map +0 -1
- package/dist/connectors/github/octokit-client.d.ts.map +0 -1
- package/dist/connectors/github/octokit-client.js.map +0 -1
- package/dist/connectors/github/ratelimit.d.ts.map +0 -1
- package/dist/connectors/github/ratelimit.js.map +0 -1
- package/dist/connectors/github/scope.d.ts.map +0 -1
- package/dist/connectors/github/scope.js.map +0 -1
- package/dist/connectors/github/signature.d.ts.map +0 -1
- package/dist/connectors/github/signature.js.map +0 -1
- package/dist/connectors/github/tenant-routing.d.ts.map +0 -1
- package/dist/connectors/github/tenant-routing.js.map +0 -1
- package/dist/connectors/github/transform.d.ts.map +0 -1
- package/dist/connectors/github/transform.js.map +0 -1
- package/dist/connectors/github/types.d.ts.map +0 -1
- package/dist/connectors/github/types.js.map +0 -1
- package/dist/connectors/slack/backfill.d.ts.map +0 -1
- package/dist/connectors/slack/backfill.js.map +0 -1
- package/dist/connectors/slack/deletion.d.ts.map +0 -1
- package/dist/connectors/slack/deletion.js.map +0 -1
- package/dist/connectors/slack/dlq.d.ts.map +0 -1
- package/dist/connectors/slack/dlq.js.map +0 -1
- package/dist/connectors/slack/idempotency.d.ts.map +0 -1
- package/dist/connectors/slack/idempotency.js.map +0 -1
- package/dist/connectors/slack/ingest.d.ts.map +0 -1
- package/dist/connectors/slack/ingest.js.map +0 -1
- package/dist/connectors/slack/ratelimit.d.ts.map +0 -1
- package/dist/connectors/slack/ratelimit.js.map +0 -1
- package/dist/connectors/slack/scope.d.ts.map +0 -1
- package/dist/connectors/slack/scope.js.map +0 -1
- package/dist/connectors/slack/signature.d.ts.map +0 -1
- package/dist/connectors/slack/signature.js.map +0 -1
- package/dist/connectors/slack/tenant-routing.d.ts.map +0 -1
- package/dist/connectors/slack/tenant-routing.js.map +0 -1
- package/dist/connectors/slack/transform.d.ts.map +0 -1
- package/dist/connectors/slack/transform.js.map +0 -1
- package/dist/connectors/slack/types.d.ts.map +0 -1
- package/dist/connectors/slack/types.js.map +0 -1
- package/dist/connectors/slack/web-client.d.ts.map +0 -1
- package/dist/connectors/slack/web-client.js.map +0 -1
- package/dist/connectors/slack/workspaces.d.ts.map +0 -1
- package/dist/connectors/slack/workspaces.js.map +0 -1
- package/dist/consolidate.d.ts.map +0 -1
- package/dist/consolidate.js.map +0 -1
- package/dist/correction-latency.d.ts.map +0 -1
- package/dist/correction-latency.js.map +0 -1
- package/dist/customer-notes.d.ts.map +0 -1
- package/dist/customer-notes.js.map +0 -1
- package/dist/dag.d.ts.map +0 -1
- package/dist/dag.js.map +0 -1
- package/dist/dashboard.d.ts.map +0 -1
- package/dist/dashboard.js.map +0 -1
- package/dist/db.d.ts.map +0 -1
- package/dist/db.js.map +0 -1
- package/dist/decisions.d.ts.map +0 -1
- package/dist/decisions.js.map +0 -1
- package/dist/dedupe.d.ts.map +0 -1
- package/dist/dedupe.js.map +0 -1
- package/dist/embedding-provider.d.ts.map +0 -1
- package/dist/embedding-provider.js.map +0 -1
- package/dist/embeddings.d.ts.map +0 -1
- package/dist/embeddings.js.map +0 -1
- package/dist/eval-suite.d.ts.map +0 -1
- package/dist/eval-suite.js.map +0 -1
- package/dist/eval.d.ts.map +0 -1
- package/dist/eval.js.map +0 -1
- package/dist/extensions/openclaw-plugin/index.js.map +0 -1
- package/dist/extract.d.ts.map +0 -1
- package/dist/extract.js.map +0 -1
- package/dist/forward-claim-detector.d.ts.map +0 -1
- package/dist/forward-claim-detector.js.map +0 -1
- package/dist/goals.d.ts.map +0 -1
- package/dist/goals.js.map +0 -1
- package/dist/graph-extract.d.ts.map +0 -1
- package/dist/graph-extract.js.map +0 -1
- package/dist/graph-recall.d.ts.map +0 -1
- package/dist/graph-recall.js.map +0 -1
- package/dist/graph-stream.d.ts.map +0 -1
- package/dist/graph-stream.js.map +0 -1
- package/dist/graph-view.d.ts.map +0 -1
- package/dist/graph-view.js.map +0 -1
- package/dist/graph.d.ts.map +0 -1
- package/dist/graph.js.map +0 -1
- package/dist/handoff.d.ts.map +0 -1
- package/dist/handoff.js.map +0 -1
- package/dist/hooks.d.ts.map +0 -1
- package/dist/hooks.js.map +0 -1
- package/dist/importers.d.ts.map +0 -1
- package/dist/importers.js.map +0 -1
- package/dist/incidents.d.ts.map +0 -1
- package/dist/incidents.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/invalidation.d.ts.map +0 -1
- package/dist/invalidation.js.map +0 -1
- package/dist/mcp/framing.d.ts.map +0 -1
- package/dist/mcp/framing.js.map +0 -1
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js.map +0 -1
- package/dist/memory-value-weights.d.ts.map +0 -1
- package/dist/memory-value-weights.js.map +0 -1
- package/dist/memory-value.d.ts.map +0 -1
- package/dist/memory-value.js.map +0 -1
- package/dist/memory.d.ts.map +0 -1
- package/dist/memory.js.map +0 -1
- package/dist/multihop.d.ts.map +0 -1
- package/dist/multihop.js.map +0 -1
- package/dist/owner-validation.d.ts.map +0 -1
- package/dist/owner-validation.js.map +0 -1
- package/dist/path-context.d.ts.map +0 -1
- package/dist/path-context.js.map +0 -1
- package/dist/physics-config.d.ts.map +0 -1
- package/dist/physics-config.js.map +0 -1
- package/dist/physics-state.d.ts.map +0 -1
- package/dist/physics-state.js.map +0 -1
- package/dist/physics.d.ts.map +0 -1
- package/dist/physics.js.map +0 -1
- package/dist/policies.d.ts.map +0 -1
- package/dist/policies.js.map +0 -1
- package/dist/postinstall.d.ts.map +0 -1
- package/dist/postinstall.js.map +0 -1
- package/dist/predictions.d.ts.map +0 -1
- package/dist/predictions.js.map +0 -1
- package/dist/processes.d.ts.map +0 -1
- package/dist/processes.js.map +0 -1
- package/dist/project-briefs.d.ts.map +0 -1
- package/dist/project-briefs.js.map +0 -1
- package/dist/project-identity.d.ts.map +0 -1
- package/dist/project-identity.js.map +0 -1
- package/dist/provenance-coverage.d.ts.map +0 -1
- package/dist/provenance-coverage.js.map +0 -1
- package/dist/rate-limit.d.ts.map +0 -1
- package/dist/rate-limit.js.map +0 -1
- package/dist/raw-archive-mirror-cleanup.d.ts.map +0 -1
- package/dist/raw-archive-mirror-cleanup.js.map +0 -1
- package/dist/raw-archive.d.ts.map +0 -1
- package/dist/raw-archive.js.map +0 -1
- package/dist/recall-history.d.ts.map +0 -1
- package/dist/recall-history.js.map +0 -1
- package/dist/recall-scope.d.ts.map +0 -1
- package/dist/recall-scope.js.map +0 -1
- package/dist/recall-trace.d.ts.map +0 -1
- package/dist/recall-trace.js.map +0 -1
- package/dist/refine-llm.d.ts.map +0 -1
- package/dist/refine-llm.js.map +0 -1
- package/dist/reject-flow.d.ts.map +0 -1
- package/dist/reject-flow.js.map +0 -1
- package/dist/rejection.d.ts.map +0 -1
- package/dist/rejection.js.map +0 -1
- package/dist/replay.d.ts.map +0 -1
- package/dist/replay.js.map +0 -1
- package/dist/rerankers/cross-encoder.d.ts.map +0 -1
- package/dist/rerankers/cross-encoder.js.map +0 -1
- package/dist/rerankers/index.d.ts.map +0 -1
- package/dist/rerankers/index.js.map +0 -1
- package/dist/rerankers/jev.d.ts.map +0 -1
- package/dist/rerankers/jev.js.map +0 -1
- package/dist/rerankers/llm.d.ts.map +0 -1
- package/dist/rerankers/llm.js.map +0 -1
- package/dist/rerankers/types.d.ts.map +0 -1
- package/dist/rerankers/types.js.map +0 -1
- package/dist/rrf.d.ts.map +0 -1
- package/dist/rrf.js.map +0 -1
- package/dist/salience.d.ts.map +0 -1
- package/dist/salience.js.map +0 -1
- package/dist/scheduler.d.ts.map +0 -1
- package/dist/scheduler.js.map +0 -1
- package/dist/scope.d.ts.map +0 -1
- package/dist/scope.js.map +0 -1
- package/dist/search.d.ts.map +0 -1
- package/dist/search.js.map +0 -1
- package/dist/secret-detect.d.ts.map +0 -1
- package/dist/secret-detect.js.map +0 -1
- package/dist/server-detect.d.ts.map +0 -1
- package/dist/server-detect.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/shared.d.ts.map +0 -1
- package/dist/shared.js.map +0 -1
- package/dist/skills.d.ts.map +0 -1
- package/dist/skills.js.map +0 -1
- package/dist/sleep-redact.d.ts +0 -58
- package/dist/sleep-redact.d.ts.map +0 -1
- package/dist/sleep-redact.js +0 -80
- package/dist/sleep-redact.js.map +0 -1
- package/dist/src/ablation.js +0 -138
- package/dist/src/ablation.js.map +0 -1
- package/dist/src/ambient.js +0 -148
- package/dist/src/ambient.js.map +0 -1
- package/dist/src/api.js +0 -2109
- package/dist/src/api.js.map +0 -1
- package/dist/src/audit-prune.js +0 -106
- package/dist/src/audit-prune.js.map +0 -1
- package/dist/src/audit.js +0 -213
- package/dist/src/audit.js.map +0 -1
- package/dist/src/auth.js +0 -97
- package/dist/src/auth.js.map +0 -1
- package/dist/src/autolearn.js +0 -174
- package/dist/src/autolearn.js.map +0 -1
- package/dist/src/availability.js +0 -94
- package/dist/src/availability.js.map +0 -1
- package/dist/src/capture.js +0 -1354
- package/dist/src/capture.js.map +0 -1
- package/dist/src/card-detail.js +0 -15
- package/dist/src/card-detail.js.map +0 -1
- package/dist/src/card.js +0 -19
- package/dist/src/card.js.map +0 -1
- package/dist/src/cli.js +0 -9328
- package/dist/src/cli.js.map +0 -1
- package/dist/src/client.js +0 -237
- package/dist/src/client.js.map +0 -1
- package/dist/src/compare.js +0 -122
- package/dist/src/compare.js.map +0 -1
- package/dist/src/config.js +0 -135
- package/dist/src/config.js.map +0 -1
- package/dist/src/connectors/github/backfill.js +0 -281
- package/dist/src/connectors/github/backfill.js.map +0 -1
- package/dist/src/connectors/github/cli-impl.js +0 -234
- package/dist/src/connectors/github/cli-impl.js.map +0 -1
- package/dist/src/connectors/github/deletion.js +0 -85
- package/dist/src/connectors/github/deletion.js.map +0 -1
- package/dist/src/connectors/github/dlq.js +0 -190
- package/dist/src/connectors/github/dlq.js.map +0 -1
- package/dist/src/connectors/github/idempotency.js +0 -27
- package/dist/src/connectors/github/idempotency.js.map +0 -1
- package/dist/src/connectors/github/ingest.js +0 -156
- package/dist/src/connectors/github/ingest.js.map +0 -1
- package/dist/src/connectors/github/octokit-client.js +0 -70
- package/dist/src/connectors/github/octokit-client.js.map +0 -1
- package/dist/src/connectors/github/ratelimit.js +0 -31
- package/dist/src/connectors/github/ratelimit.js.map +0 -1
- package/dist/src/connectors/github/scope.js +0 -13
- package/dist/src/connectors/github/scope.js.map +0 -1
- package/dist/src/connectors/github/signature.js +0 -81
- package/dist/src/connectors/github/signature.js.map +0 -1
- package/dist/src/connectors/github/tenant-routing.js +0 -69
- package/dist/src/connectors/github/tenant-routing.js.map +0 -1
- package/dist/src/connectors/github/transform.js +0 -103
- package/dist/src/connectors/github/transform.js.map +0 -1
- package/dist/src/connectors/github/types.js +0 -100
- package/dist/src/connectors/github/types.js.map +0 -1
- package/dist/src/connectors/slack/backfill.js +0 -78
- package/dist/src/connectors/slack/backfill.js.map +0 -1
- package/dist/src/connectors/slack/deletion.js +0 -59
- package/dist/src/connectors/slack/deletion.js.map +0 -1
- package/dist/src/connectors/slack/dlq.js +0 -224
- package/dist/src/connectors/slack/dlq.js.map +0 -1
- package/dist/src/connectors/slack/idempotency.js +0 -31
- package/dist/src/connectors/slack/idempotency.js.map +0 -1
- package/dist/src/connectors/slack/ingest.js +0 -109
- package/dist/src/connectors/slack/ingest.js.map +0 -1
- package/dist/src/connectors/slack/ratelimit.js +0 -18
- package/dist/src/connectors/slack/ratelimit.js.map +0 -1
- package/dist/src/connectors/slack/scope.js +0 -13
- package/dist/src/connectors/slack/scope.js.map +0 -1
- package/dist/src/connectors/slack/signature.js +0 -27
- package/dist/src/connectors/slack/signature.js.map +0 -1
- package/dist/src/connectors/slack/tenant-routing.js +0 -41
- package/dist/src/connectors/slack/tenant-routing.js.map +0 -1
- package/dist/src/connectors/slack/transform.js +0 -47
- package/dist/src/connectors/slack/transform.js.map +0 -1
- package/dist/src/connectors/slack/types.js +0 -35
- package/dist/src/connectors/slack/types.js.map +0 -1
- package/dist/src/connectors/slack/web-client.js +0 -43
- package/dist/src/connectors/slack/web-client.js.map +0 -1
- package/dist/src/connectors/slack/workspaces.js +0 -62
- package/dist/src/connectors/slack/workspaces.js.map +0 -1
- package/dist/src/consolidate.js +0 -978
- package/dist/src/consolidate.js.map +0 -1
- package/dist/src/correction-latency.js +0 -74
- package/dist/src/correction-latency.js.map +0 -1
- package/dist/src/customer-notes.js +0 -325
- package/dist/src/customer-notes.js.map +0 -1
- package/dist/src/dag.js +0 -352
- package/dist/src/dag.js.map +0 -1
- package/dist/src/dashboard.js +0 -258
- package/dist/src/dashboard.js.map +0 -1
- package/dist/src/db.js +0 -2728
- package/dist/src/db.js.map +0 -1
- package/dist/src/decisions.js +0 -304
- package/dist/src/decisions.js.map +0 -1
- package/dist/src/dedupe.js +0 -141
- package/dist/src/dedupe.js.map +0 -1
- package/dist/src/embedding-provider.js +0 -314
- package/dist/src/embedding-provider.js.map +0 -1
- package/dist/src/embeddings.js +0 -543
- package/dist/src/embeddings.js.map +0 -1
- package/dist/src/eval-suite.js +0 -294
- package/dist/src/eval-suite.js.map +0 -1
- package/dist/src/eval.js +0 -187
- package/dist/src/eval.js.map +0 -1
- package/dist/src/extract.js +0 -117
- package/dist/src/extract.js.map +0 -1
- package/dist/src/forward-claim-detector.js +0 -117
- package/dist/src/forward-claim-detector.js.map +0 -1
- package/dist/src/goals.js +0 -390
- package/dist/src/goals.js.map +0 -1
- package/dist/src/graph-extract.js +0 -314
- package/dist/src/graph-extract.js.map +0 -1
- package/dist/src/graph-recall.js +0 -277
- package/dist/src/graph-recall.js.map +0 -1
- package/dist/src/graph-stream.js +0 -176
- package/dist/src/graph-stream.js.map +0 -1
- package/dist/src/graph-view.js +0 -310
- package/dist/src/graph-view.js.map +0 -1
- package/dist/src/graph.js +0 -762
- package/dist/src/graph.js.map +0 -1
- package/dist/src/handoff.js +0 -65
- package/dist/src/handoff.js.map +0 -1
- package/dist/src/hooks.js +0 -926
- package/dist/src/hooks.js.map +0 -1
- package/dist/src/importers.js +0 -881
- package/dist/src/importers.js.map +0 -1
- package/dist/src/incidents.js +0 -336
- package/dist/src/incidents.js.map +0 -1
- package/dist/src/index.js +0 -32
- package/dist/src/index.js.map +0 -1
- package/dist/src/invalidation.js +0 -129
- package/dist/src/invalidation.js.map +0 -1
- package/dist/src/mcp/framing.js +0 -45
- package/dist/src/mcp/framing.js.map +0 -1
- package/dist/src/mcp/server.js +0 -1298
- package/dist/src/mcp/server.js.map +0 -1
- package/dist/src/memory-value-weights.js +0 -31
- package/dist/src/memory-value-weights.js.map +0 -1
- package/dist/src/memory-value.js +0 -261
- package/dist/src/memory-value.js.map +0 -1
- package/dist/src/memory.js +0 -425
- package/dist/src/memory.js.map +0 -1
- package/dist/src/multihop.js +0 -35
- package/dist/src/multihop.js.map +0 -1
- package/dist/src/owner-validation.js +0 -56
- package/dist/src/owner-validation.js.map +0 -1
- package/dist/src/path-context.js +0 -48
- package/dist/src/path-context.js.map +0 -1
- package/dist/src/physics-config.js +0 -26
- package/dist/src/physics-config.js.map +0 -1
- package/dist/src/physics-state.js +0 -169
- package/dist/src/physics-state.js.map +0 -1
- package/dist/src/physics.js +0 -378
- package/dist/src/physics.js.map +0 -1
- package/dist/src/policies.js +0 -414
- package/dist/src/policies.js.map +0 -1
- package/dist/src/postinstall.js +0 -101
- package/dist/src/postinstall.js.map +0 -1
- package/dist/src/predictions.js +0 -629
- package/dist/src/predictions.js.map +0 -1
- package/dist/src/processes.js +0 -349
- package/dist/src/processes.js.map +0 -1
- package/dist/src/project-briefs.js +0 -492
- package/dist/src/project-briefs.js.map +0 -1
- package/dist/src/project-identity.js +0 -200
- package/dist/src/project-identity.js.map +0 -1
- package/dist/src/provenance-coverage.js +0 -23
- package/dist/src/provenance-coverage.js.map +0 -1
- package/dist/src/rate-limit.js +0 -60
- package/dist/src/rate-limit.js.map +0 -1
- package/dist/src/raw-archive-mirror-cleanup.js +0 -55
- package/dist/src/raw-archive-mirror-cleanup.js.map +0 -1
- package/dist/src/raw-archive.js +0 -88
- package/dist/src/raw-archive.js.map +0 -1
- package/dist/src/recall-history.js +0 -235
- package/dist/src/recall-history.js.map +0 -1
- package/dist/src/recall-scope.js +0 -89
- package/dist/src/recall-scope.js.map +0 -1
- package/dist/src/recall-trace.js +0 -183
- package/dist/src/recall-trace.js.map +0 -1
- package/dist/src/refine-llm.js +0 -156
- package/dist/src/refine-llm.js.map +0 -1
- package/dist/src/reject-flow.js +0 -209
- package/dist/src/reject-flow.js.map +0 -1
- package/dist/src/rejection.js +0 -160
- package/dist/src/rejection.js.map +0 -1
- package/dist/src/replay.js +0 -122
- package/dist/src/replay.js.map +0 -1
- package/dist/src/rerankers/cross-encoder.js +0 -137
- package/dist/src/rerankers/cross-encoder.js.map +0 -1
- package/dist/src/rerankers/index.js +0 -20
- package/dist/src/rerankers/index.js.map +0 -1
- package/dist/src/rerankers/jev.js +0 -119
- package/dist/src/rerankers/jev.js.map +0 -1
- package/dist/src/rerankers/llm.js +0 -80
- package/dist/src/rerankers/llm.js.map +0 -1
- package/dist/src/rerankers/types.js +0 -2
- package/dist/src/rerankers/types.js.map +0 -1
- package/dist/src/rrf.js +0 -61
- package/dist/src/rrf.js.map +0 -1
- package/dist/src/salience.js +0 -74
- package/dist/src/salience.js.map +0 -1
- package/dist/src/scheduler.js +0 -77
- package/dist/src/scheduler.js.map +0 -1
- package/dist/src/scope.js +0 -35
- package/dist/src/scope.js.map +0 -1
- package/dist/src/search.js +0 -1003
- package/dist/src/search.js.map +0 -1
- package/dist/src/secret-detect.js +0 -95
- package/dist/src/secret-detect.js.map +0 -1
- package/dist/src/server-detect.js +0 -231
- package/dist/src/server-detect.js.map +0 -1
- package/dist/src/server.js +0 -3255
- package/dist/src/server.js.map +0 -1
- package/dist/src/shared.js +0 -502
- package/dist/src/shared.js.map +0 -1
- package/dist/src/skills.js +0 -346
- package/dist/src/skills.js.map +0 -1
- package/dist/src/sleep-redact.js +0 -80
- package/dist/src/sleep-redact.js.map +0 -1
- package/dist/src/sso.js +0 -22
- package/dist/src/sso.js.map +0 -1
- package/dist/src/store.js +0 -3743
- package/dist/src/store.js.map +0 -1
- package/dist/src/tenant.js +0 -17
- package/dist/src/tenant.js.map +0 -1
- package/dist/src/trace.js +0 -72
- package/dist/src/trace.js.map +0 -1
- package/dist/src/version.js +0 -40
- package/dist/src/version.js.map +0 -1
- package/dist/src/working-memory.js +0 -157
- package/dist/src/working-memory.js.map +0 -1
- package/dist/src/yaml.js +0 -107
- package/dist/src/yaml.js.map +0 -1
- package/dist/sso.d.ts +0 -13
- package/dist/sso.d.ts.map +0 -1
- package/dist/sso.js +0 -22
- package/dist/sso.js.map +0 -1
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js.map +0 -1
- package/dist/tenant.d.ts.map +0 -1
- package/dist/tenant.js.map +0 -1
- package/dist/trace.d.ts.map +0 -1
- package/dist/trace.js.map +0 -1
- package/dist/version.d.ts.map +0 -1
- package/dist/version.js.map +0 -1
- package/dist/working-memory.d.ts.map +0 -1
- package/dist/working-memory.js.map +0 -1
- package/dist/yaml.d.ts.map +0 -1
- package/dist/yaml.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* hippo decide "<decision>" [--context "<why>"] [--supersedes <id>]
|
|
30
30
|
* hippo wm <push|read|clear|flush>
|
|
31
31
|
*/
|
|
32
|
-
import { evalNow
|
|
32
|
+
import { evalNow } from './ablation.js';
|
|
33
33
|
import * as path from 'path';
|
|
34
34
|
import * as fs from 'fs';
|
|
35
35
|
import * as os from 'os';
|
|
@@ -38,14 +38,14 @@ import { execFileSync, execSync, spawn } from 'child_process';
|
|
|
38
38
|
import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, isCodexWrapperInstalled, repairCodexWrapperIfInstalled, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
|
|
39
39
|
import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, confidenceFacets, confidenceLabel, computeSchemaFit, Layer, } from './memory.js';
|
|
40
40
|
import { detectSecret } from './secret-detect.js';
|
|
41
|
-
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadRecallSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, closeTaskSnapshotsForSession, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, stampHandoffOutcome, writeSessionEndHandoff, createCard, loadCard, listCards, loadCardRuns, claimCard, heartbeatCard, blockCard, reviewCard, completeCard, reclaimExpiredCards, addCardComment, } from './store.js';
|
|
41
|
+
import { getHippoRoot, isInitialized, initStore, writeEntry, strengthenRetrieved, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadRecallSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, closeTaskSnapshotsForSession, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, stampHandoffOutcome, writeSessionEndHandoff, createCard, loadCard, listCards, loadCardRuns, claimCard, heartbeatCard, blockCard, reviewCard, completeCard, reclaimExpiredCards, addCardComment, } from './store.js';
|
|
42
42
|
import { rejectValue, unrejectValue, listRejectionsForTenant } from './reject-flow.js';
|
|
43
43
|
import { RejectedValueError } from './rejection.js';
|
|
44
44
|
import { isHandoffOutcome, formatHandoffEvidenceLine } from './handoff.js';
|
|
45
45
|
import { isCardStatus } from './card.js';
|
|
46
46
|
import { loadCardDetail } from './card-detail.js';
|
|
47
47
|
import { passesScopeFilterForRecall } from './recall-scope.js';
|
|
48
|
-
import {
|
|
48
|
+
import { hybridSearch, physicsSearch, explainMatch, textOverlap, tokenize as tokenizeQuery } from './search.js';
|
|
49
49
|
import { compareEntryIdentity } from './compare.js';
|
|
50
50
|
import { renderTraceContent, parseSteps } from './trace.js';
|
|
51
51
|
import { writeRecallTraceAtRoot } from './recall-trace.js';
|
|
@@ -65,7 +65,8 @@ import { detectScope } from './scope.js';
|
|
|
65
65
|
import { getGlobalRoot, initGlobal, shareMemory, listPeers, autoShare, transferScore, searchBothHybrid, syncGlobalToLocal, } from './shared.js';
|
|
66
66
|
import { DAILY_TASK_NAME, buildDailyRunnerCommand, listRegisteredWorkspaces, registerWorkspace, runDailyMaintenance, } from './scheduler.js';
|
|
67
67
|
import { importChatGPT, importClaude, importCursor, importGenericFile, importMarkdown, importVault, } from './importers.js';
|
|
68
|
-
import { cmdCapture, cmdPreCompact, truncateCodePointSafe, sanitizeLogMessage } from './capture.js';
|
|
68
|
+
import { cmdCapture, cmdPreCompact, resolveLastSessionTranscript, truncateCodePointSafe, sanitizeLogMessage } from './capture.js';
|
|
69
|
+
import { readStdinBounded } from './stdin.js';
|
|
69
70
|
import { auditMemories, appendAuditEvent, } from './audit.js';
|
|
70
71
|
import { listApiKeys, revokeApiKey } from './auth.js';
|
|
71
72
|
import { buildProvenanceCoverage } from './provenance-coverage.js';
|
|
@@ -143,6 +144,22 @@ function parseCountFlag(value) {
|
|
|
143
144
|
const parsed = parseInt(String(value), 10);
|
|
144
145
|
return Number.isFinite(parsed) && parsed >= 1 ? parsed : 0;
|
|
145
146
|
}
|
|
147
|
+
function parseBudgetFlag(value, fallback) {
|
|
148
|
+
if (value === undefined)
|
|
149
|
+
return fallback;
|
|
150
|
+
// A value-less flag and a junk value are different typos; the --hops guard already splits them.
|
|
151
|
+
if (typeof value !== 'string') {
|
|
152
|
+
console.error('--budget requires an integer value (e.g. --budget 1500).');
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
// Number(), like the --hops guard: parseInt('12abc') is 12, silently accepting what this message rejects.
|
|
156
|
+
const parsed = Number(value);
|
|
157
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
158
|
+
console.error(`Invalid --budget: "${value}". Must be a non-negative integer.`);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
return parsed;
|
|
162
|
+
}
|
|
146
163
|
/**
|
|
147
164
|
* Emit an audit event against `hippoRoot`'s db. Opens its own short-lived
|
|
148
165
|
* connection so callers don't have to thread a db handle. Swallows all errors
|
|
@@ -178,8 +195,8 @@ function requireInit(hippoRoot) {
|
|
|
178
195
|
* H2: when HIPPO_REQUIRE_SERVER is set, the CLI must not silently fall back to
|
|
179
196
|
* direct DB mode — a missing server then masks a real misconfiguration (the
|
|
180
197
|
* configured HIPPO_API_KEY is also silently discarded on fallback). Throws a
|
|
181
|
-
* clear
|
|
182
|
-
*
|
|
198
|
+
* clear error then. It guards only the routed writes (remember, forget, archive,
|
|
199
|
+
* promote); every other command opens the store directly, knob or not.
|
|
183
200
|
*/
|
|
184
201
|
function failIfServerRequired(reason) {
|
|
185
202
|
if (process.env['HIPPO_REQUIRE_SERVER']) {
|
|
@@ -233,10 +250,68 @@ async function runViaServerIfAvailable(hippoRoot, httpFn) {
|
|
|
233
250
|
throw err;
|
|
234
251
|
}
|
|
235
252
|
}
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
const BOOLEAN_FLAGS = new Set([
|
|
253
|
+
// Every switch the CLI reads. A value on one reads as on under Boolean() (`--fix=false` would fix)
|
|
254
|
+
// and as off under === true (`--pin=true` would not pin), so parseArgs and main() refuse one.
|
|
255
|
+
// tests/cli-parse-flag-equals.test.ts fails when a switch read is missing from this set.
|
|
256
|
+
export const BOOLEAN_FLAGS = new Set([
|
|
257
|
+
'all', 'all-tenants', 'archive', 'auto', 'bad', 'bootstrap', 'classic', 'continuity',
|
|
258
|
+
'cross-project', 'dry-run', 'equal-sources', 'error', 'evc-adaptive', 'extract',
|
|
259
|
+
'filter-conflicts', 'fix', 'force', 'forget', 'git', 'global', 'good', 'graph-stream',
|
|
260
|
+
'help', 'include-superseded', 'inferred', 'json', 'last-session', 'multihop', 'no-hooks',
|
|
261
|
+
'no-learn', 'no-mmr', 'no-propagate', 'no-schedule', 'no-share', 'no-summarize-older',
|
|
262
|
+
'observed', 'open', 'physics', 'pin', 'pinned-only', 'reject-loser', 'rerank-utility',
|
|
263
|
+
'reset-physics', 'save-baseline', 'show-cases', 'stats', 'stdin',
|
|
264
|
+
'strict', 'suite', 'value-aware', 'verified', 'version', 'why',
|
|
265
|
+
]);
|
|
266
|
+
// Every flag some command reads. Anything else is a typo that no command would act on.
|
|
267
|
+
export const KNOWN_FLAGS = new Set([
|
|
268
|
+
...BOOLEAN_FLAGS,
|
|
269
|
+
'actual', 'artifact', 'artifact-ref', 'as-of', 'author', 'baseline', 'body', 'budget', 'card-id',
|
|
270
|
+
'change', 'channel', 'chatgpt', 'class', 'claude', 'codex-home', 'compare', 'constraint', 'content',
|
|
271
|
+
'context', 'contract', 'cursor', 'customer', 'days', 'depends-on', 'depth', 'description',
|
|
272
|
+
'embedding-weight', 'entity', 'estimate', 'file', 'format', 'framing', 'fresh-tail', 'from', 'goal',
|
|
273
|
+
'graph-hops', 'graph-seeds', 'history-path', 'hops', 'host', 'id', 'importance', 'include-recent',
|
|
274
|
+
'instructions', 'keep', 'kind', 'label', 'layer', 'level', 'limit', 'link', 'local-bump', 'log-file',
|
|
275
|
+
'markdown', 'max', 'max-cases', 'max-neighbors', 'min-mrr', 'min-results', 'min-score', 'mmr-lambda',
|
|
276
|
+
'model', 'name', 'next', 'next-step', 'note', 'older-than', 'op', 'out', 'outcome', 'owner', 'parent',
|
|
277
|
+
'path', 'policy', 'port', 'reason', 'repo', 'repos', 'reranker', 'reranker-top-k', 'resolution',
|
|
278
|
+
'role', 'run', 'runtime', 'salience-threshold', 'scan', 'scope', 'session', 'session-id', 'since',
|
|
279
|
+
'source', 'start-offset', 'started-at', 'state', 'status', 'step', 'steps', 'success', 'summary',
|
|
280
|
+
'supersedes', 'tag', 'target', 'target-runtime', 'task', 'team', 'tenant', 'tenant-id', 'tests',
|
|
281
|
+
'text', 'threshold', 'title', 'to', 'transcript', 'trigger', 'type', 'unit', 'value', 'vault',
|
|
282
|
+
]);
|
|
283
|
+
// Commands that delete or hide memories: an unknown flag here stops the run instead of being ignored.
|
|
284
|
+
const DESTRUCTIVE_COMMANDS = new Set([
|
|
285
|
+
'audit', 'dedup', 'forget', 'invalidate', 'reject', 'resolve', 'sleep', 'supersede',
|
|
286
|
+
]);
|
|
287
|
+
// Commands that honour --dry-run. Any other command would ignore it and run for real.
|
|
288
|
+
const DRY_RUN_COMMANDS = new Set([
|
|
289
|
+
'audit', 'capture', 'dedup', 'forget', 'import', 'invalidate', 'refine', 'setup', 'sleep',
|
|
290
|
+
]);
|
|
291
|
+
// share and brief honour --dry-run in one form only; their other forms write for real.
|
|
292
|
+
function dryRunRefusal(command, args, flags) {
|
|
293
|
+
const isBrief = command === 'brief' || command === 'project-brief';
|
|
294
|
+
const onlyForm = command === 'share' ? 'share --auto' : isBrief ? `${command} refresh` : null;
|
|
295
|
+
const honoured = command === 'share' ? args[0] === '--auto' || Boolean(flags['auto'])
|
|
296
|
+
: isBrief ? args[0] === 'refresh' : DRY_RUN_COMMANDS.has(command);
|
|
297
|
+
if (honoured)
|
|
298
|
+
return null;
|
|
299
|
+
const where = onlyForm ? ` outside \`hippo ${onlyForm}\`` : '';
|
|
300
|
+
return `hippo ${command} has no --dry-run${where}, so it would run for real. Nothing was changed.`;
|
|
301
|
+
}
|
|
302
|
+
// Shared by both the separated and glued (`=`) forms so the list can't drift.
|
|
303
|
+
function isRepeatableFlag(key) {
|
|
304
|
+
return key === 'tag' || key === 'artifact' || key === 'link' || key === 'step' || key === 'constraint' || key === 'depends-on';
|
|
305
|
+
}
|
|
306
|
+
function pushRepeatableFlag(flags, key, value) {
|
|
307
|
+
if (Array.isArray(flags[key])) {
|
|
308
|
+
// SAFETY: Array.isArray just confirmed flags[key] is an array; the union has no other array member.
|
|
309
|
+
flags[key].push(value);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
flags[key] = [value];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
240
315
|
export function parseArgs(argv) {
|
|
241
316
|
const [, , command = '', ...rest] = argv;
|
|
242
317
|
const args = [];
|
|
@@ -249,26 +324,43 @@ export function parseArgs(argv) {
|
|
|
249
324
|
break;
|
|
250
325
|
}
|
|
251
326
|
if (part.startsWith('--')) {
|
|
327
|
+
const eqIdx = part.indexOf('=');
|
|
328
|
+
if (eqIdx > 2) {
|
|
329
|
+
// Glued form has no following token to swallow, so BOOLEAN_FLAGS gets its
|
|
330
|
+
// own branch here instead of the swallow-avoidance short-circuit below.
|
|
331
|
+
const key = part.slice(2, eqIdx);
|
|
332
|
+
const value = part.slice(eqIdx + 1);
|
|
333
|
+
if (BOOLEAN_FLAGS.has(key)) {
|
|
334
|
+
flags[key] = value;
|
|
335
|
+
}
|
|
336
|
+
else if (isRepeatableFlag(key)) {
|
|
337
|
+
if (value !== '')
|
|
338
|
+
pushRepeatableFlag(flags, key, value);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
flags[key] = value === '' ? true : value;
|
|
342
|
+
}
|
|
343
|
+
i++;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
252
346
|
const key = part.slice(2);
|
|
253
347
|
const next = rest[i + 1];
|
|
254
|
-
if (
|
|
348
|
+
if (BOOLEAN_FLAGS.has(key) && (next === 'true' || next === 'false')) {
|
|
349
|
+
// Kept as a value so main() rejects it, instead of `--pin true` pinning the text "... true".
|
|
350
|
+
flags[key] = next;
|
|
351
|
+
i += 2;
|
|
352
|
+
}
|
|
353
|
+
else if (!next || next.startsWith('--') || BOOLEAN_FLAGS.has(key)) {
|
|
255
354
|
// Boolean flag
|
|
256
355
|
flags[key] = true;
|
|
257
356
|
i++;
|
|
258
357
|
}
|
|
358
|
+
else if (isRepeatableFlag(key)) {
|
|
359
|
+
pushRepeatableFlag(flags, key, next);
|
|
360
|
+
i += 2;
|
|
361
|
+
}
|
|
259
362
|
else {
|
|
260
|
-
|
|
261
|
-
if (key === 'tag' || key === 'artifact' || key === 'link' || key === 'step' || key === 'constraint' || key === 'depends-on') {
|
|
262
|
-
if (Array.isArray(flags[key])) {
|
|
263
|
-
flags[key].push(next);
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
flags[key] = [next];
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
flags[key] = next;
|
|
271
|
-
}
|
|
363
|
+
flags[key] = next;
|
|
272
364
|
i += 2;
|
|
273
365
|
}
|
|
274
366
|
}
|
|
@@ -602,7 +694,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
602
694
|
if (flags['verified'])
|
|
603
695
|
confidence = 'verified';
|
|
604
696
|
// Compute schema fit against existing memories
|
|
605
|
-
const existing = loadAllEntries(targetRoot);
|
|
697
|
+
const existing = loadAllEntries(targetRoot, resolveTenantId({}));
|
|
606
698
|
const schemaFit = computeSchemaFit(text, rawTags, existing);
|
|
607
699
|
// A3 envelope flags
|
|
608
700
|
const kindFlagRaw = typeof flags['kind'] === 'string' ? flags['kind'] : undefined;
|
|
@@ -632,6 +724,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
632
724
|
// A5 stub auth: stamp tenant_id from env (HIPPO_TENANT) so recall isolation
|
|
633
725
|
// can filter on this row. Default tenant 'default' for unauthenticated CLI.
|
|
634
726
|
const tenantId = resolveTenantId({});
|
|
727
|
+
const rememberConfig = loadConfig(targetRoot);
|
|
635
728
|
const entry = createMemory(text, {
|
|
636
729
|
layer: Layer.Episodic,
|
|
637
730
|
tags: rawTags,
|
|
@@ -644,6 +737,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
644
737
|
owner: ownerFlag,
|
|
645
738
|
artifact_ref: artifactRefFlag,
|
|
646
739
|
tenantId,
|
|
740
|
+
baseHalfLifeDays: rememberConfig.defaultHalfLifeDays,
|
|
647
741
|
});
|
|
648
742
|
// Auto-tag with path context
|
|
649
743
|
const pathTags = extractPathTags(process.cwd());
|
|
@@ -660,7 +754,6 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
660
754
|
entry.tags.push(scopeTag);
|
|
661
755
|
}
|
|
662
756
|
// Salience gate: decide if this memory is worth storing
|
|
663
|
-
const rememberConfig = loadConfig(targetRoot);
|
|
664
757
|
if (rememberConfig.salience.enabled && !Boolean(flags['pin']) && !Boolean(flags['force'])) {
|
|
665
758
|
const salienceResult = computeSalience(text, entry.tags, existing, {
|
|
666
759
|
recentWindow: rememberConfig.salience.recentWindow,
|
|
@@ -702,14 +795,16 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
702
795
|
const facts = await extractFacts(entry.content, {
|
|
703
796
|
apiKey,
|
|
704
797
|
model: config.extraction.model,
|
|
798
|
+
onError: (msg) => console.error(` (extraction failed: ${msg})`),
|
|
705
799
|
});
|
|
706
800
|
if (facts.length > 0) {
|
|
707
801
|
storeExtractedFacts(targetRoot, entry, facts);
|
|
708
802
|
console.error(` extracted ${facts.length} fact(s)`);
|
|
709
803
|
}
|
|
710
804
|
}
|
|
711
|
-
catch {
|
|
712
|
-
// Extraction is best-effort
|
|
805
|
+
catch (err) {
|
|
806
|
+
// Extraction is best-effort: report it, never block remember.
|
|
807
|
+
console.error(` (extraction failed: ${err instanceof Error ? err.message : String(err)})`);
|
|
713
808
|
}
|
|
714
809
|
}
|
|
715
810
|
else if (shouldExtract && !apiKey) {
|
|
@@ -741,6 +836,7 @@ function cmdSupersede(hippoRoot, oldId, newContent, flags) {
|
|
|
741
836
|
pinned,
|
|
742
837
|
source: old.source,
|
|
743
838
|
confidence: 'verified',
|
|
839
|
+
tenantId: old.tenantId,
|
|
744
840
|
});
|
|
745
841
|
// AT1: write the SUCCESSOR first. The rejection guard fires on the new
|
|
746
842
|
// content — if it refuses, nothing has been mutated yet (the old ordering
|
|
@@ -768,7 +864,7 @@ function cmdSupersede(hippoRoot, oldId, newContent, flags) {
|
|
|
768
864
|
}
|
|
769
865
|
async function cmdRecall(hippoRoot, query, flags) {
|
|
770
866
|
requireInit(hippoRoot);
|
|
771
|
-
const budget =
|
|
867
|
+
const budget = parseBudgetFlag(flags['budget'], 4000);
|
|
772
868
|
const limit = parseLimitFlag(flags['limit']);
|
|
773
869
|
const asJson = Boolean(flags['json']);
|
|
774
870
|
const showWhy = Boolean(flags['why']);
|
|
@@ -798,8 +894,9 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
798
894
|
// detected-project recalls would change shape.
|
|
799
895
|
const recallExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
800
896
|
const requestedScopeForFilter = recallExplicitScope || undefined;
|
|
801
|
-
|
|
802
|
-
let
|
|
897
|
+
const loadSuperseded = includeSuperseded || Boolean(asOf);
|
|
898
|
+
let localEntries = loadRecallSearchEntries(hippoRoot, query, undefined, tenantId, requestedScopeForFilter, 'additive', loadSuperseded);
|
|
899
|
+
let globalEntries = isInitialized(globalRoot) ? loadRecallSearchEntries(globalRoot, query, undefined, tenantId, requestedScopeForFilter, 'additive', loadSuperseded) : [];
|
|
803
900
|
// v1.12.13 / C5 — WYSIATI counters. Track filter activity per the plan v3
|
|
804
901
|
// Task 3 mapping table. dropped_pre_rank is the SUM of all non-budget
|
|
805
902
|
// filter drops (pre-rank AND post-rank); its meaning is unchanged by C5.
|
|
@@ -1669,21 +1766,13 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
1669
1766
|
console.log('No memories found for:', query);
|
|
1670
1767
|
return;
|
|
1671
1768
|
}
|
|
1672
|
-
|
|
1673
|
-
const updated = markRetrieved(results.map((r) => r.entry));
|
|
1769
|
+
const retrievedIds = results.map((r) => r.entry.id);
|
|
1674
1770
|
const localIndex = loadIndex(hippoRoot);
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
// updated_at, rewrites mirrors, and marks DAG parents dirty.
|
|
1679
|
-
if (!isRecallBoostAblated()) {
|
|
1680
|
-
for (const u of updated) {
|
|
1681
|
-
const targetRoot = localIndex.entries[u.id] ? hippoRoot : (isInitialized(globalRoot) ? globalRoot : hippoRoot);
|
|
1682
|
-
writeEntry(targetRoot, u);
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1771
|
+
const strengthenedHere = strengthenRetrieved(hippoRoot, retrievedIds);
|
|
1772
|
+
if (isInitialized(globalRoot))
|
|
1773
|
+
strengthenRetrieved(globalRoot, retrievedIds.filter((id) => !strengthenedHere.has(id)));
|
|
1685
1774
|
// Track last retrieval IDs for outcome command
|
|
1686
|
-
localIndex.last_retrieval_ids =
|
|
1775
|
+
localIndex.last_retrieval_ids = retrievedIds;
|
|
1687
1776
|
// LC1 F1 structural fix (docs/plans/2026-08-02-lc1-recall-trace-persistence.md):
|
|
1688
1777
|
// ONE trace at hippoRoot (where last_retrieval_ids and outcome
|
|
1689
1778
|
// attribution live). Write the trace FIRST, then fold its id into
|
|
@@ -1895,7 +1984,7 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
1895
1984
|
}
|
|
1896
1985
|
async function cmdExplain(hippoRoot, query, flags) {
|
|
1897
1986
|
requireInit(hippoRoot);
|
|
1898
|
-
const budget =
|
|
1987
|
+
const budget = parseBudgetFlag(flags['budget'], 4000);
|
|
1899
1988
|
const limit = parseLimitFlag(flags['limit']);
|
|
1900
1989
|
const asJson = Boolean(flags['json']);
|
|
1901
1990
|
const forcePhysics = Boolean(flags['physics']);
|
|
@@ -1915,8 +2004,9 @@ async function cmdExplain(hippoRoot, query, flags) {
|
|
|
1915
2004
|
// command honest for an operator debugging a hidden row.
|
|
1916
2005
|
const explainExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
1917
2006
|
const explainRequestedScope = explainExplicitScope || undefined;
|
|
1918
|
-
|
|
1919
|
-
let
|
|
2007
|
+
const explainLoadSuperseded = explainIncludeSuperseded || Boolean(explainAsOf);
|
|
2008
|
+
let explainLocalEntries = loadRecallSearchEntries(hippoRoot, query, undefined, tenantId, explainRequestedScope, 'additive', explainLoadSuperseded);
|
|
2009
|
+
let explainGlobalEntries = isInitialized(globalRoot) ? loadRecallSearchEntries(globalRoot, query, undefined, tenantId, explainRequestedScope, 'additive', explainLoadSuperseded) : [];
|
|
1920
2010
|
const passesExplainScope = (e) => api.passesCliRecallScopeFilter(e.scope ?? null, explainRequestedScope);
|
|
1921
2011
|
explainLocalEntries = explainLocalEntries.filter(passesExplainScope);
|
|
1922
2012
|
explainGlobalEntries = explainGlobalEntries.filter(passesExplainScope);
|
|
@@ -2320,6 +2410,7 @@ function cmdTraceRecord(hippoRoot, flags) {
|
|
|
2320
2410
|
source: String(flags['source'] ?? 'cli'),
|
|
2321
2411
|
trace_outcome: outcome,
|
|
2322
2412
|
source_session_id: sessionId,
|
|
2413
|
+
tenantId: resolveTenantId({}),
|
|
2323
2414
|
});
|
|
2324
2415
|
writeEntry(hippoRoot, entry);
|
|
2325
2416
|
console.log(`Recorded trace ${entry.id} (outcome=${outcome}, ${steps.length} steps)`);
|
|
@@ -2484,7 +2575,7 @@ export function learnFromMemoryMd(hippoRoot, homeDir = os.homedir()) {
|
|
|
2484
2575
|
}
|
|
2485
2576
|
if (memoryDirs.length === 0)
|
|
2486
2577
|
return 0;
|
|
2487
|
-
const existing = loadAllEntries(hippoRoot);
|
|
2578
|
+
const existing = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
2488
2579
|
let imported = 0;
|
|
2489
2580
|
let skippedSecret = 0;
|
|
2490
2581
|
// AT1 (plan §3 containment): a rejection guard refusal is per-VALUE — one
|
|
@@ -2527,6 +2618,7 @@ export function learnFromMemoryMd(hippoRoot, homeDir = os.homedir()) {
|
|
|
2527
2618
|
tags: ['claude-code-memory'],
|
|
2528
2619
|
source: `claude-memory:${file}`,
|
|
2529
2620
|
confidence: 'observed',
|
|
2621
|
+
tenantId: resolveTenantId({}),
|
|
2530
2622
|
});
|
|
2531
2623
|
try {
|
|
2532
2624
|
writeEntry(hippoRoot, entry);
|
|
@@ -2675,11 +2767,11 @@ export function renderSleepResult(result) {
|
|
|
2675
2767
|
parts.push(`${epiDups} duplicate episodic lessons`);
|
|
2676
2768
|
if (crossDups > 0)
|
|
2677
2769
|
parts.push(`${crossDups} cross-layer duplicates`);
|
|
2678
|
-
console.log(`\
|
|
2770
|
+
console.log(`\n${result.dryRun ? 'Would dedupe' : 'Deduped'} ${removed} duplicates (${parts.join(', ')}). ${result.dryRun ? 'Would keep' : 'Kept'} stronger copies.`);
|
|
2679
2771
|
}
|
|
2680
2772
|
if (result.audit) {
|
|
2681
2773
|
if (result.audit.errorsRemoved > 0) {
|
|
2682
|
-
console.log(`\nAudit: removed ${result.audit.errorsRemoved} junk memories (too short/empty).`);
|
|
2774
|
+
console.log(`\nAudit: ${result.dryRun ? 'would remove' : 'removed'} ${result.audit.errorsRemoved} junk memories (too short/empty).`);
|
|
2683
2775
|
}
|
|
2684
2776
|
if (result.audit.warningCount > 0) {
|
|
2685
2777
|
console.log(`Audit: ${result.audit.warningCount} low-quality memories detected (run \`hippo audit\` for details).`);
|
|
@@ -2704,7 +2796,10 @@ async function cmdSleepCore(hippoRoot, flags) {
|
|
|
2704
2796
|
requireInit(hippoRoot);
|
|
2705
2797
|
// Phase 1: Auto-learn from git + MEMORY.md (CLI-only, uses process.cwd() / os.homedir()).
|
|
2706
2798
|
// Stays in cli.ts; api.sleep covers Phase 2-6 only.
|
|
2707
|
-
if (!flags['no-learn']) {
|
|
2799
|
+
if (!flags['no-learn'] && flags['dry-run']) {
|
|
2800
|
+
console.log('Dry run: skipped learning from git commits and MEMORY.md files.');
|
|
2801
|
+
}
|
|
2802
|
+
else if (!flags['no-learn']) {
|
|
2708
2803
|
const config = loadConfig(hippoRoot);
|
|
2709
2804
|
if (config.autoLearnOnSleep && isGitRepo(process.cwd())) {
|
|
2710
2805
|
const { added } = learnFromRepo(hippoRoot, process.cwd(), 1);
|
|
@@ -2776,7 +2871,7 @@ function cmdLastSleep(flags) {
|
|
|
2776
2871
|
// X8: session-event content is capped at print time only — the shared
|
|
2777
2872
|
// printSessionEvents stays untouched for every other caller.
|
|
2778
2873
|
const COMPACT_RESUME_EVENT_CONTENT_CAP = 400;
|
|
2779
|
-
function cmdCompactResume(hippoRoot, stdinText) {
|
|
2874
|
+
function cmdCompactResume(hippoRoot, stdinText, stdinTimedOut) {
|
|
2780
2875
|
try {
|
|
2781
2876
|
// X3: gate on the non-exiting isInitialized check before any
|
|
2782
2877
|
// store-opening call (loadActiveTaskSnapshot/listSessionEvents both
|
|
@@ -2791,7 +2886,9 @@ function cmdCompactResume(hippoRoot, stdinText) {
|
|
|
2791
2886
|
// carries a different source (e.g. 'startup') means the matcher-based
|
|
2792
2887
|
// gate failed to apply — stay silent rather than print stale state.
|
|
2793
2888
|
const nonEmptyStdin = !!stdinText && stdinText.trim() !== '';
|
|
2794
|
-
|
|
2889
|
+
// Without a payload session_id the X5 cross-restore guard below can
|
|
2890
|
+
// never fire, so a timed-out empty read must not reach the print path.
|
|
2891
|
+
let suppressOutput = stdinTimedOut && !nonEmptyStdin;
|
|
2795
2892
|
let payloadSessionId = null;
|
|
2796
2893
|
if (nonEmptyStdin) {
|
|
2797
2894
|
let payload = null;
|
|
@@ -2872,30 +2969,23 @@ function cmdCompactResume(hippoRoot, stdinText) {
|
|
|
2872
2969
|
*/
|
|
2873
2970
|
async function cmdSessionEnd(hippoRoot, flags) {
|
|
2874
2971
|
const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : null;
|
|
2875
|
-
//
|
|
2876
|
-
//
|
|
2877
|
-
// via argv so the detached child doesn't need to inherit stdin.
|
|
2878
|
-
// DF1 T3 (docs/plans/2026-08-23-df1-snapshot-lifecycle.md): `session_id`
|
|
2879
|
-
// is extracted the same way, so the worker can close the ending session's
|
|
2880
|
-
// own active task snapshot after sleep+capture finish.
|
|
2881
|
-
let transcriptPath = null;
|
|
2972
|
+
// Bounded read (DF1 T3, docs/plans/2026-08-23-df1-snapshot-lifecycle.md):
|
|
2973
|
+
// extracts transcript_path + session_id for the detached worker's argv.
|
|
2882
2974
|
let sessionId = null;
|
|
2975
|
+
const { text: stdinText, timedOut: stdinTimedOut } = await readStdinBounded();
|
|
2883
2976
|
try {
|
|
2884
|
-
const stdinText = fs.readFileSync(0, 'utf8');
|
|
2885
2977
|
if (stdinText && stdinText.trim().startsWith('{')) {
|
|
2886
2978
|
const payload = JSON.parse(stdinText);
|
|
2887
|
-
if (typeof payload.transcript_path === 'string') {
|
|
2888
|
-
transcriptPath = payload.transcript_path;
|
|
2889
|
-
}
|
|
2890
2979
|
if (typeof payload.session_id === 'string') {
|
|
2891
2980
|
sessionId = payload.session_id;
|
|
2892
2981
|
}
|
|
2893
2982
|
}
|
|
2894
2983
|
}
|
|
2895
2984
|
catch {
|
|
2896
|
-
// No stdin, not JSON, or read failure
|
|
2897
|
-
// transcript auto-discovery; the snapshot close below will no-op.
|
|
2985
|
+
// No stdin, not JSON, or read failure: the snapshot close below will no-op.
|
|
2898
2986
|
}
|
|
2987
|
+
// Resolved here because only this process saw the payload; the worker captures just the path it is handed.
|
|
2988
|
+
const transcriptPath = resolveLastSessionTranscript(undefined, stdinText, stdinTimedOut);
|
|
2899
2989
|
const workerArgs = [process.argv[1], '__session-end-worker'];
|
|
2900
2990
|
if (logFile)
|
|
2901
2991
|
workerArgs.push('--log-file', logFile);
|
|
@@ -2912,11 +3002,11 @@ async function cmdSessionEnd(hippoRoot, flags) {
|
|
|
2912
3002
|
child.unref();
|
|
2913
3003
|
}
|
|
2914
3004
|
catch (err) {
|
|
2915
|
-
// If spawn fails, run inline as a last resort
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
3005
|
+
// If spawn fails, run inline as a last resort, handed what the child's argv would have carried.
|
|
3006
|
+
if (transcriptPath)
|
|
3007
|
+
flags['transcript'] = transcriptPath;
|
|
3008
|
+
if (sessionId)
|
|
3009
|
+
flags['session-id'] = sessionId;
|
|
2920
3010
|
await cmdSessionEndWorker(hippoRoot, flags);
|
|
2921
3011
|
return;
|
|
2922
3012
|
}
|
|
@@ -2959,19 +3049,22 @@ async function cmdSessionEndWorker(hippoRoot, flags) {
|
|
|
2959
3049
|
// `[hippo] sleep failed: ...` line. Continue to capture regardless.
|
|
2960
3050
|
}
|
|
2961
3051
|
try {
|
|
2962
|
-
const
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
3052
|
+
const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : undefined;
|
|
3053
|
+
const transcriptPath = typeof flags['transcript'] === 'string' ? flags['transcript'] : undefined;
|
|
3054
|
+
// With no stdin of its own, capture would read this as a manual run and scan every project.
|
|
3055
|
+
if (!transcriptPath) {
|
|
3056
|
+
appendSessionEndCloseLog(logFile ?? null, 'skip capture: no transcript for this session');
|
|
3057
|
+
}
|
|
3058
|
+
else {
|
|
3059
|
+
cmdCapture(hippoRoot, {
|
|
3060
|
+
source: 'last-session',
|
|
3061
|
+
transcriptPath,
|
|
3062
|
+
logFile,
|
|
3063
|
+
dryRun: false,
|
|
3064
|
+
global: false,
|
|
3065
|
+
tenantId: resolveTenantId({}),
|
|
3066
|
+
});
|
|
3067
|
+
}
|
|
2975
3068
|
}
|
|
2976
3069
|
catch {
|
|
2977
3070
|
// Same treatment — the failure line is already in the log.
|
|
@@ -3154,6 +3247,11 @@ async function cmdCodexSessionEndWorker(hippoRoot, flags) {
|
|
|
3154
3247
|
startOffsetBytes,
|
|
3155
3248
|
startedAtMs,
|
|
3156
3249
|
}) ?? undefined;
|
|
3250
|
+
// No Codex transcript must not fall through to the scan of Claude Code projects.
|
|
3251
|
+
if (!transcriptPath) {
|
|
3252
|
+
appendSessionEndCloseLog(logFile ?? null, 'skip capture: no Codex transcript for this session');
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3157
3255
|
const captureOpts = {
|
|
3158
3256
|
source: 'last-session',
|
|
3159
3257
|
transcriptPath,
|
|
@@ -3168,13 +3266,13 @@ async function cmdCodexSessionEndWorker(hippoRoot, flags) {
|
|
|
3168
3266
|
// capture path logs its own failures
|
|
3169
3267
|
}
|
|
3170
3268
|
}
|
|
3171
|
-
function shouldAutoRepairCodexWrapper(currentCommand,
|
|
3269
|
+
export function shouldAutoRepairCodexWrapper(currentCommand, flags) {
|
|
3172
3270
|
if (process.env.HIPPO_SKIP_AUTO_INTEGRATIONS === '1')
|
|
3173
3271
|
return false;
|
|
3174
3272
|
if (!['context', 'remember', 'recall', 'sleep', 'capture', 'outcome', 'status', 'init'].includes(currentCommand)) {
|
|
3175
3273
|
return false;
|
|
3176
3274
|
}
|
|
3177
|
-
if (currentCommand === 'init' &&
|
|
3275
|
+
if (currentCommand === 'init' && flags['no-hooks'] === true)
|
|
3178
3276
|
return false;
|
|
3179
3277
|
return true;
|
|
3180
3278
|
}
|
|
@@ -3183,8 +3281,8 @@ function shouldAutoRepairCodexWrapper(currentCommand, currentArgs) {
|
|
|
3183
3281
|
// shim). Never first-installs — silently swapping the codex binary on routine
|
|
3184
3282
|
// commands is a consent violation and reads as binary hijacking to
|
|
3185
3283
|
// supply-chain scanners (issue #133).
|
|
3186
|
-
function maybeRepairCodexWrapper(currentCommand,
|
|
3187
|
-
if (!shouldAutoRepairCodexWrapper(currentCommand,
|
|
3284
|
+
function maybeRepairCodexWrapper(currentCommand, flags) {
|
|
3285
|
+
if (!shouldAutoRepairCodexWrapper(currentCommand, flags))
|
|
3188
3286
|
return;
|
|
3189
3287
|
try {
|
|
3190
3288
|
repairCodexWrapperIfInstalled();
|
|
@@ -3406,8 +3504,7 @@ function cmdForget(hippoRoot, id, flags) {
|
|
|
3406
3504
|
if (/append-only/i.test(msg)) {
|
|
3407
3505
|
// The delete was refused by the append-only trigger — this is a raw
|
|
3408
3506
|
// memory, not a missing one. Point the user at the archive path.
|
|
3409
|
-
console.error(
|
|
3410
|
-
`Archive it instead: hippo forget ${id} --archive --reason "<why>"`);
|
|
3507
|
+
console.error(rawForgetRefusal(id));
|
|
3411
3508
|
}
|
|
3412
3509
|
else {
|
|
3413
3510
|
console.error(`Memory not found: ${id}`);
|
|
@@ -3415,6 +3512,28 @@ function cmdForget(hippoRoot, id, flags) {
|
|
|
3415
3512
|
process.exit(1);
|
|
3416
3513
|
}
|
|
3417
3514
|
}
|
|
3515
|
+
function rawForgetRefusal(id) {
|
|
3516
|
+
return `Cannot forget ${id}: it is a raw, append-only memory. Archive it instead: hippo forget ${id} --archive --reason "<why>"`;
|
|
3517
|
+
}
|
|
3518
|
+
// Refuses exactly where the real run would, so "Would forget" is a promise, not a guess.
|
|
3519
|
+
function previewForget(hippoRoot, id, archive) {
|
|
3520
|
+
requireInit(hippoRoot);
|
|
3521
|
+
const entry = readEntry(hippoRoot, id, resolveTenantId({}));
|
|
3522
|
+
if (!entry) {
|
|
3523
|
+
console.error(`Memory not found: ${id}`);
|
|
3524
|
+
process.exit(1);
|
|
3525
|
+
}
|
|
3526
|
+
if (!archive && entry.kind === 'raw') {
|
|
3527
|
+
console.error(rawForgetRefusal(id));
|
|
3528
|
+
process.exit(1);
|
|
3529
|
+
}
|
|
3530
|
+
if (archive && entry.kind !== 'raw') {
|
|
3531
|
+
console.error(`Could not archive ${id}: memory ${id} is not raw (kind=${entry.kind})`);
|
|
3532
|
+
process.exit(1);
|
|
3533
|
+
}
|
|
3534
|
+
const snippet = entry.content.length > 80 ? `${entry.content.slice(0, 80)}...` : entry.content;
|
|
3535
|
+
console.log(`Would ${archive ? 'archive' : 'forget'} ${id} (dry run, nothing changed): "${snippet}"`);
|
|
3536
|
+
}
|
|
3418
3537
|
function cmdInspect(hippoRoot, id) {
|
|
3419
3538
|
requireInit(hippoRoot);
|
|
3420
3539
|
const entry = readEntry(hippoRoot, id, resolveTenantId({}));
|
|
@@ -4122,10 +4241,8 @@ function cmdCard(hippoRoot, args, flags) {
|
|
|
4122
4241
|
const allowedFlags = CARD_SUBCOMMAND_FLAGS[subcommand];
|
|
4123
4242
|
for (const key of Object.keys(flags)) {
|
|
4124
4243
|
if (!allowedFlags.includes(key)) {
|
|
4125
|
-
// --flag=value never splits on '=' (see parseArgs), so it lands here as one long key.
|
|
4126
|
-
const hint = key.includes('=') ? ` Use --${key.slice(0, key.indexOf('='))} <value>, not --${key}.` : '';
|
|
4127
4244
|
const valid = allowedFlags.length > 0 ? allowedFlags.map((f) => `--${f}`).join(', ') : '(none)';
|
|
4128
|
-
console.error(`Unknown flag --${key} for hippo card ${subcommand}
|
|
4245
|
+
console.error(`Unknown flag --${key} for hippo card ${subcommand}. Valid flags: ${valid}`);
|
|
4129
4246
|
process.exit(1);
|
|
4130
4247
|
}
|
|
4131
4248
|
}
|
|
@@ -5915,7 +6032,7 @@ async function cmdContext(hippoRoot, args, flags, stdinText) {
|
|
|
5915
6032
|
if (!pinnedOnly) {
|
|
5916
6033
|
requireInit(hippoRoot);
|
|
5917
6034
|
}
|
|
5918
|
-
const budget =
|
|
6035
|
+
const budget = parseBudgetFlag(flags['budget'], 1500);
|
|
5919
6036
|
if (budget <= 0)
|
|
5920
6037
|
return;
|
|
5921
6038
|
// Resolve query: explicit args, --auto (git diff via CLI-side helper), or
|
|
@@ -6247,9 +6364,9 @@ async function cmdWatch(command, hippoRoot) {
|
|
|
6247
6364
|
console.error('Command failed but .hippo not initialized. Run `hippo init` to enable auto-learn.');
|
|
6248
6365
|
process.exit(exitCode);
|
|
6249
6366
|
}
|
|
6250
|
-
const entry = captureError(exitCode, stderr, command);
|
|
6367
|
+
const entry = captureError(exitCode, stderr, command, resolveTenantId({}));
|
|
6251
6368
|
// Compute schema fit against existing memories
|
|
6252
|
-
const existingWatch = loadAllEntries(hippoRoot);
|
|
6369
|
+
const existingWatch = loadAllEntries(hippoRoot, entry.tenantId);
|
|
6253
6370
|
const watchFit = computeSchemaFit(entry.content, entry.tags, existingWatch);
|
|
6254
6371
|
entry.schema_fit = watchFit;
|
|
6255
6372
|
entry.half_life_days = deriveHalfLife(7, entry);
|
|
@@ -6335,14 +6452,9 @@ function learnFromRepo(hippoRoot, repoPath, days, label) {
|
|
|
6335
6452
|
// the existing summary line.
|
|
6336
6453
|
let rejected = 0;
|
|
6337
6454
|
const gitLearnTags = ['error', 'git-learned'];
|
|
6338
|
-
const existingForSchema = loadAllEntries(hippoRoot);
|
|
6455
|
+
const existingForSchema = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
6339
6456
|
for (const lesson of lessons) {
|
|
6340
|
-
//
|
|
6341
|
-
// `loadAllEntries(hippoRoot)` call a few lines up) is host-wide and
|
|
6342
|
-
// intentionally out-of-L9-scope per plan §11 (cli.ts is
|
|
6343
|
-
// single-tenant-per-process). The tenantId arg here is a defensive no-op:
|
|
6344
|
-
// deduplicateLesson's array overload ignores it; the parameter exists
|
|
6345
|
-
// only to mirror the canonical caller pattern used elsewhere in cli.ts.
|
|
6457
|
+
// The array overload ignores the tenant arg; existingForSchema is already scoped.
|
|
6346
6458
|
if (deduplicateLesson(existingForSchema, lesson, 0.7, resolveTenantId({}))) {
|
|
6347
6459
|
skipped++;
|
|
6348
6460
|
continue;
|
|
@@ -6361,6 +6473,7 @@ function learnFromRepo(hippoRoot, repoPath, days, label) {
|
|
|
6361
6473
|
source: 'git-learn',
|
|
6362
6474
|
confidence: 'observed',
|
|
6363
6475
|
schema_fit: schemaFitVal,
|
|
6476
|
+
tenantId: resolveTenantId({}),
|
|
6364
6477
|
});
|
|
6365
6478
|
// Auto-tag with path context from the repo being learned
|
|
6366
6479
|
const learnPathTags = extractPathTags(repoPath);
|
|
@@ -7242,7 +7355,8 @@ function cmdDag(hippoRoot, flags) {
|
|
|
7242
7355
|
}
|
|
7243
7356
|
function cmdAssemble(hippoRoot, sessionId, flags) {
|
|
7244
7357
|
requireInit(hippoRoot);
|
|
7245
|
-
|
|
7358
|
+
// Absent stays undefined so the api default applies; the 0 fallback is unreachable.
|
|
7359
|
+
const budget = flags['budget'] === undefined ? undefined : parseBudgetFlag(flags['budget'], 0);
|
|
7246
7360
|
const freshTailCount = typeof flags['fresh-tail'] === 'string' ? Number(flags['fresh-tail']) : undefined;
|
|
7247
7361
|
const summarizeOlder = flags['no-summarize-older'] !== true;
|
|
7248
7362
|
const scope = typeof flags['scope'] === 'string' && flags['scope'].length > 0
|
|
@@ -7273,7 +7387,8 @@ function cmdAssemble(hippoRoot, sessionId, flags) {
|
|
|
7273
7387
|
function cmdDrillDown(hippoRoot, summaryId, flags) {
|
|
7274
7388
|
requireInit(hippoRoot);
|
|
7275
7389
|
const limit = typeof flags['limit'] === 'string' ? Number(flags['limit']) : undefined;
|
|
7276
|
-
|
|
7390
|
+
// Absent stays undefined so the api default applies; the 0 fallback is unreachable.
|
|
7391
|
+
const budget = flags['budget'] === undefined ? undefined : parseBudgetFlag(flags['budget'], 0);
|
|
7277
7392
|
// v0.30 / E5: --depth N walks N levels down (default 1, hard cap 10).
|
|
7278
7393
|
// L4 fold: reject out-of-range explicitly (no silent clamp).
|
|
7279
7394
|
const rawDepth = typeof flags['depth'] === 'string' ? Number(flags['depth']) : undefined;
|
|
@@ -8573,25 +8688,16 @@ Examples:
|
|
|
8573
8688
|
// ---------------------------------------------------------------------------
|
|
8574
8689
|
// Entry point
|
|
8575
8690
|
// ---------------------------------------------------------------------------
|
|
8576
|
-
|
|
8577
|
-
const hippoRoot = getHippoRoot(process.cwd());
|
|
8578
|
-
async function main() {
|
|
8691
|
+
async function main(command, args, flags, hippoRoot) {
|
|
8579
8692
|
if (command === '--version' || command === '-v' || flags['version']) {
|
|
8580
8693
|
const __filename_local = fileURLToPath(import.meta.url);
|
|
8581
8694
|
const __dirname_local = path.dirname(__filename_local);
|
|
8582
|
-
const
|
|
8583
|
-
let pkgJson;
|
|
8584
|
-
try {
|
|
8585
|
-
pkgJson = fs.readFileSync(pkgPath, 'utf-8');
|
|
8586
|
-
}
|
|
8587
|
-
catch {
|
|
8588
|
-
pkgJson = fs.readFileSync(path.join(__dirname_local, '..', '..', 'package.json'), 'utf-8');
|
|
8589
|
-
}
|
|
8695
|
+
const pkgJson = fs.readFileSync(path.join(__dirname_local, '..', 'package.json'), 'utf-8');
|
|
8590
8696
|
const { version } = JSON.parse(pkgJson);
|
|
8591
8697
|
console.log(version);
|
|
8592
8698
|
process.exit(0);
|
|
8593
8699
|
}
|
|
8594
|
-
maybeRepairCodexWrapper(command,
|
|
8700
|
+
maybeRepairCodexWrapper(command, flags);
|
|
8595
8701
|
/** Global --scope well-formedness guard (v1.26.2). parseArgs stores a value-less
|
|
8596
8702
|
* flag as boolean true; downstream the 14 consumer sites either coerced that to
|
|
8597
8703
|
* the literal scope string 'true' (recall filter/unlock input, wm session scope,
|
|
@@ -8603,6 +8709,44 @@ async function main() {
|
|
|
8603
8709
|
console.error('--scope requires a non-empty value (e.g. --scope slack:private:C1).');
|
|
8604
8710
|
process.exit(1);
|
|
8605
8711
|
}
|
|
8712
|
+
// parseArgs stores a value-less flag as boolean true, and NaN then survives every
|
|
8713
|
+
// downstream guard because each comparison against it is false.
|
|
8714
|
+
const NUMERIC_FLAGS = [
|
|
8715
|
+
'days', 'threshold', 'min-score', 'port', 'limit', 'mmr-lambda', 'local-bump',
|
|
8716
|
+
'min-results', 'reranker-top-k', 'min-mrr', 'embedding-weight', 'max-cases',
|
|
8717
|
+
];
|
|
8718
|
+
for (const key of NUMERIC_FLAGS) {
|
|
8719
|
+
const raw = flags[key];
|
|
8720
|
+
if (raw === undefined)
|
|
8721
|
+
continue;
|
|
8722
|
+
if (typeof raw !== 'string' || !raw.trim() || !Number.isFinite(Number(raw))) {
|
|
8723
|
+
console.error(`--${key} requires a numeric value.`);
|
|
8724
|
+
process.exit(1);
|
|
8725
|
+
}
|
|
8726
|
+
}
|
|
8727
|
+
// Reject rather than coerce: consumers read --dry-run both as Boolean() and === true,
|
|
8728
|
+
// so no single coercion of an inline value would be correct for every one of them.
|
|
8729
|
+
for (const key of BOOLEAN_FLAGS) {
|
|
8730
|
+
if (Object.hasOwn(flags, key) && typeof flags[key] !== 'boolean') {
|
|
8731
|
+
console.error(`--${key} takes no value`);
|
|
8732
|
+
process.exit(1);
|
|
8733
|
+
}
|
|
8734
|
+
}
|
|
8735
|
+
// card checks its flags per subcommand, with a stricter message.
|
|
8736
|
+
const unknownFlags = command === 'card' ? [] : Object.keys(flags).filter((key) => !KNOWN_FLAGS.has(key));
|
|
8737
|
+
if (unknownFlags.length > 0) {
|
|
8738
|
+
const names = unknownFlags.map((key) => `--${key}`).join(', ');
|
|
8739
|
+
if (DESTRUCTIVE_COMMANDS.has(command)) {
|
|
8740
|
+
console.error(`Unknown flag ${names} for hippo ${command}. Nothing was changed.`);
|
|
8741
|
+
process.exit(2);
|
|
8742
|
+
}
|
|
8743
|
+
console.error(`hippo: ignoring unknown flag ${names}. A later release will reject it.`);
|
|
8744
|
+
}
|
|
8745
|
+
const refusal = Object.hasOwn(flags, 'dry-run') ? dryRunRefusal(command, args, flags) : null;
|
|
8746
|
+
if (refusal) {
|
|
8747
|
+
console.error(refusal);
|
|
8748
|
+
process.exit(2);
|
|
8749
|
+
}
|
|
8606
8750
|
switch (command) {
|
|
8607
8751
|
case 'init':
|
|
8608
8752
|
cmdInit(hippoRoot, flags);
|
|
@@ -8747,34 +8891,18 @@ async function main() {
|
|
|
8747
8891
|
await cmdSessionEndWorker(hippoRoot, flags);
|
|
8748
8892
|
break;
|
|
8749
8893
|
case 'pre-compact': {
|
|
8750
|
-
//
|
|
8751
|
-
|
|
8752
|
-
let stdinText;
|
|
8753
|
-
if (!process.stdin.isTTY) {
|
|
8754
|
-
try {
|
|
8755
|
-
stdinText = fs.readFileSync(0, 'utf8');
|
|
8756
|
-
}
|
|
8757
|
-
catch {
|
|
8758
|
-
stdinText = undefined;
|
|
8759
|
-
}
|
|
8760
|
-
}
|
|
8894
|
+
// Bounded wait, not a TTY guard: an idle non-TTY pipe must not hang.
|
|
8895
|
+
const { text: stdinText, timedOut: stdinTimedOut } = await readStdinBounded();
|
|
8761
8896
|
await cmdPreCompact(hippoRoot, {
|
|
8762
8897
|
stdinText,
|
|
8898
|
+
stdinTimedOut,
|
|
8763
8899
|
logFile: typeof flags['log-file'] === 'string' ? flags['log-file'] : undefined,
|
|
8764
8900
|
});
|
|
8765
8901
|
break;
|
|
8766
8902
|
}
|
|
8767
8903
|
case 'compact-resume': {
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
try {
|
|
8771
|
-
stdinText = fs.readFileSync(0, 'utf8');
|
|
8772
|
-
}
|
|
8773
|
-
catch {
|
|
8774
|
-
stdinText = undefined;
|
|
8775
|
-
}
|
|
8776
|
-
}
|
|
8777
|
-
cmdCompactResume(hippoRoot, stdinText);
|
|
8904
|
+
const { text: stdinText, timedOut: stdinTimedOut } = await readStdinBounded();
|
|
8905
|
+
cmdCompactResume(hippoRoot, stdinText, stdinTimedOut);
|
|
8778
8906
|
break;
|
|
8779
8907
|
}
|
|
8780
8908
|
case 'codex-run':
|
|
@@ -8810,7 +8938,7 @@ async function main() {
|
|
|
8810
8938
|
break;
|
|
8811
8939
|
}
|
|
8812
8940
|
requireInit(hippoRoot);
|
|
8813
|
-
const entries = loadAllEntries(hippoRoot);
|
|
8941
|
+
const entries = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
8814
8942
|
const result = auditMemories(entries);
|
|
8815
8943
|
const shouldFix = Boolean(flags['fix']);
|
|
8816
8944
|
if (result.issues.length === 0) {
|
|
@@ -8824,13 +8952,15 @@ async function main() {
|
|
|
8824
8952
|
console.log(` "${issue.content.slice(0, 80)}${issue.content.length > 80 ? '...' : ''}"`);
|
|
8825
8953
|
}
|
|
8826
8954
|
if (shouldFix) {
|
|
8827
|
-
const
|
|
8828
|
-
if (
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8955
|
+
const errors = result.issues.filter(i => i.severity === 'error');
|
|
8956
|
+
if (errors.length > 0 && flags['dry-run'] === true) {
|
|
8957
|
+
console.log(`\nWould remove ${errors.length} error-severity memories (dry run, nothing deleted).`);
|
|
8958
|
+
console.log(`${result.issues.length - errors.length} warnings would remain (review manually).`);
|
|
8959
|
+
}
|
|
8960
|
+
else if (errors.length > 0) {
|
|
8961
|
+
const removedCount = errors.filter((issue) => deleteEntry(hippoRoot, issue.memoryId, { reason: `audit --fix: ${issue.reason}`, automatic: true })).length;
|
|
8962
|
+
console.log(`\nRemoved ${removedCount} error-severity memories.`);
|
|
8963
|
+
console.log(`${result.issues.length - errors.length} warnings remain (review manually).`);
|
|
8834
8964
|
}
|
|
8835
8965
|
else {
|
|
8836
8966
|
console.log(`\nNo error-severity issues. Warnings require manual review.`);
|
|
@@ -8951,6 +9081,10 @@ async function main() {
|
|
|
8951
9081
|
console.error(ARCHIVE_REASON_REQUIRED);
|
|
8952
9082
|
process.exit(1);
|
|
8953
9083
|
}
|
|
9084
|
+
if (flags['dry-run'] === true) {
|
|
9085
|
+
previewForget(hippoRoot, id, archive);
|
|
9086
|
+
break;
|
|
9087
|
+
}
|
|
8954
9088
|
const routed = await runViaServerIfAvailable(hippoRoot, async (info, apiKey) => {
|
|
8955
9089
|
try {
|
|
8956
9090
|
if (archive) {
|
|
@@ -8987,23 +9121,9 @@ async function main() {
|
|
|
8987
9121
|
break;
|
|
8988
9122
|
}
|
|
8989
9123
|
case 'context': {
|
|
8990
|
-
// DF1 T2
|
|
8991
|
-
//
|
|
8992
|
-
|
|
8993
|
-
// hangs. `hippo context` is both the hot UserPromptSubmit path
|
|
8994
|
-
// (non-TTY, stdin carries the hook JSON with `session_id`) and a
|
|
8995
|
-
// manually-invocable command (TTY, no payload) — the guardless read in
|
|
8996
|
-
// cmdSessionEnd is the wrong sibling to copy here; it only runs under
|
|
8997
|
-
// a hook that always supplies stdin.
|
|
8998
|
-
let stdinText;
|
|
8999
|
-
if (!process.stdin.isTTY) {
|
|
9000
|
-
try {
|
|
9001
|
-
stdinText = fs.readFileSync(0, 'utf8');
|
|
9002
|
-
}
|
|
9003
|
-
catch {
|
|
9004
|
-
stdinText = undefined;
|
|
9005
|
-
}
|
|
9006
|
-
}
|
|
9124
|
+
// Bounded, not a TTY guard (DF1 T2, docs/plans/2026-08-23-df1-snapshot-lifecycle.md):
|
|
9125
|
+
// the hot stdin path and a manual run share this one command.
|
|
9126
|
+
const { text: stdinText } = await readStdinBounded();
|
|
9007
9127
|
await cmdContext(hippoRoot, args, flags, stdinText);
|
|
9008
9128
|
break;
|
|
9009
9129
|
}
|
|
@@ -9130,7 +9250,7 @@ async function main() {
|
|
|
9130
9250
|
requireInit(hippoRoot);
|
|
9131
9251
|
const format = flags['format'] || 'json';
|
|
9132
9252
|
const outputPath = args[0] || null;
|
|
9133
|
-
const entries = loadAllEntries(hippoRoot);
|
|
9253
|
+
const entries = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
9134
9254
|
let output;
|
|
9135
9255
|
if (format === 'markdown' || format === 'md') {
|
|
9136
9256
|
output = entries.map(e => {
|
|
@@ -9180,10 +9300,17 @@ async function main() {
|
|
|
9180
9300
|
console.error('Usage: hippo capture --stdin|--file <path>|--last-session [--transcript <path>] [--log-file <path>] [--dry-run] [--global]');
|
|
9181
9301
|
process.exit(1);
|
|
9182
9302
|
}
|
|
9303
|
+
// Bounded, and only when last-session has no explicit path: the
|
|
9304
|
+
// --stdin source keeps its own blocking read in capture.ts by design.
|
|
9305
|
+
const bounded = captureSource === 'last-session' && !transcriptPath
|
|
9306
|
+
? await readStdinBounded()
|
|
9307
|
+
: { text: undefined, timedOut: false };
|
|
9183
9308
|
cmdCapture(hippoRoot, {
|
|
9184
9309
|
source: captureSource,
|
|
9185
9310
|
filePath: captureFile,
|
|
9186
9311
|
transcriptPath,
|
|
9312
|
+
stdinText: bounded.text,
|
|
9313
|
+
stdinTimedOut: bounded.timedOut,
|
|
9187
9314
|
logFile: typeof flags['log-file'] === 'string' ? flags['log-file'] : undefined,
|
|
9188
9315
|
dryRun: Boolean(flags['dry-run']),
|
|
9189
9316
|
global: Boolean(flags['global']),
|
|
@@ -9223,11 +9350,11 @@ async function main() {
|
|
|
9223
9350
|
}
|
|
9224
9351
|
const host = typeof flags['host'] === 'string' ? flags['host'] : '127.0.0.1';
|
|
9225
9352
|
const { serve } = await import('./server.js');
|
|
9226
|
-
const handle = await serve({ hippoRoot, port, host });
|
|
9353
|
+
const handle = await serve({ hippoRoot, port, host, handleSignals: true });
|
|
9227
9354
|
console.log(`hippo serve listening on ${handle.url} (pid ${process.pid})`);
|
|
9228
9355
|
console.log(`pidfile: ${path.join(hippoRoot, 'server.pid')}`);
|
|
9229
9356
|
console.log('press Ctrl+C to stop');
|
|
9230
|
-
// SIGINT/SIGTERM handlers
|
|
9357
|
+
// The SIGINT/SIGTERM handlers stop the server and exit. Hang until then.
|
|
9231
9358
|
await new Promise(() => { });
|
|
9232
9359
|
break;
|
|
9233
9360
|
}
|
|
@@ -9242,8 +9369,8 @@ async function main() {
|
|
|
9242
9369
|
}
|
|
9243
9370
|
const onlyId = typeof flags['id'] === 'string' ? flags['id'] : undefined;
|
|
9244
9371
|
if (typeof flags['dry-run'] === 'string') {
|
|
9245
|
-
//
|
|
9246
|
-
//
|
|
9372
|
+
// Dead: the earlier global BOOLEAN_FLAGS guard now exits first on any --dry-run=<v>.
|
|
9373
|
+
// Kept as defence in depth on a destructive command.
|
|
9247
9374
|
console.error('--dry-run takes no value');
|
|
9248
9375
|
process.exit(1);
|
|
9249
9376
|
}
|
|
@@ -9321,8 +9448,19 @@ async function main() {
|
|
|
9321
9448
|
process.exit(1);
|
|
9322
9449
|
}
|
|
9323
9450
|
}
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9451
|
+
export async function runCli(argv = process.argv) {
|
|
9452
|
+
const { command, args, flags } = parseArgs(argv);
|
|
9453
|
+
try {
|
|
9454
|
+
await main(command, args, flags, getHippoRoot(process.cwd()));
|
|
9455
|
+
}
|
|
9456
|
+
catch (err) {
|
|
9457
|
+
console.error('Error:', err instanceof Error ? err.message : err);
|
|
9458
|
+
process.exit(1);
|
|
9459
|
+
}
|
|
9460
|
+
}
|
|
9461
|
+
// bin/hippo.js calls runCli(); this keeps `node dist/cli.js` working while an import runs nothing.
|
|
9462
|
+
const entryPath = process.argv[1];
|
|
9463
|
+
if (entryPath && fs.existsSync(entryPath) && fs.realpathSync(entryPath) === fileURLToPath(import.meta.url)) {
|
|
9464
|
+
void runCli();
|
|
9465
|
+
}
|
|
9328
9466
|
//# sourceMappingURL=cli.js.map
|