hippo-memory 1.44.0 → 1.46.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 +68 -24
- package/bin/hippo.js +3 -1
- package/dist/ablation.d.ts +10 -1
- package/dist/ablation.js +17 -1
- package/dist/api.d.ts +81 -22
- package/dist/api.js +258 -49
- package/dist/audit.d.ts +2 -2
- package/dist/audit.js +9 -0
- package/dist/autolearn.d.ts +1 -1
- package/dist/autolearn.js +2 -1
- package/dist/capture-error.d.ts +20 -0
- package/dist/capture-error.js +82 -0
- package/dist/capture.d.ts +25 -8
- package/dist/capture.js +100 -5
- package/dist/cli.d.ts +9 -1
- package/dist/cli.js +531 -119
- package/dist/client.d.ts +4 -21
- package/dist/client.js +3 -112
- package/dist/config.d.ts +20 -0
- package/dist/config.js +37 -1
- package/dist/consolidate.d.ts +9 -0
- package/dist/consolidate.js +133 -46
- package/dist/dag.d.ts +1 -0
- package/dist/dag.js +10 -5
- package/dist/dashboard.js +7 -3
- package/dist/db.js +69 -24
- package/dist/dedupe.d.ts +1 -0
- package/dist/dedupe.js +4 -7
- package/dist/doctor.d.ts +34 -0
- package/dist/doctor.js +174 -0
- package/dist/dormant.d.ts +91 -0
- package/dist/dormant.js +121 -0
- package/dist/embedding-provider.js +2 -1
- package/dist/embeddings.js +81 -8
- package/dist/eval-stats.d.ts +123 -0
- package/dist/eval-stats.js +187 -0
- package/dist/extract.d.ts +2 -0
- package/dist/extract.js +9 -4
- package/dist/half-life-migration.d.ts +55 -0
- package/dist/half-life-migration.js +111 -0
- package/dist/hooks.d.ts +4 -0
- package/dist/hooks.js +47 -0
- package/dist/mcp/server.d.ts +6 -0
- package/dist/mcp/server.js +90 -48
- package/dist/memory.d.ts +18 -1
- package/dist/memory.js +33 -5
- package/dist/physics-config.js +5 -1
- package/dist/recall-scope.d.ts +24 -0
- package/dist/recall-scope.js +41 -0
- package/dist/refine-llm.js +3 -2
- package/dist/reject-flow.d.ts +3 -3
- package/dist/reject-flow.js +10 -3
- package/dist/rerankers/jev.js +3 -2
- package/dist/rerankers/llm.js +3 -2
- package/dist/search.d.ts +4 -4
- package/dist/search.js +26 -21
- package/dist/server.d.ts +5 -0
- package/dist/server.js +49 -29
- package/dist/shared.js +1 -1
- package/dist/store.d.ts +29 -11
- package/dist/store.js +197 -70
- package/dist/token-ledger.d.ts +119 -0
- package/dist/token-ledger.js +181 -0
- 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 +7 -3
- 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 -109
- 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 -1346
- 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 -9387
- 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 -2731
- 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 -399
- 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 -172
- 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 -91
- 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 -186
- 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/stdin.js +0 -41
- package/dist/src/stdin.js.map +0 -1
- package/dist/src/store.js +0 -3749
- 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/stdin.d.ts.map +0 -1
- package/dist/stdin.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
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* hippo reject <id>|--value "<text>" --reason "<why>"
|
|
20
20
|
* hippo rejections
|
|
21
21
|
* hippo unreject <digest-prefix>
|
|
22
|
+
* hippo dormant [<query>] [--limit <n>] [--json] | restore <id> | forget <id>
|
|
23
|
+
* hippo tokens [--days <n>] [--json] [--global]
|
|
24
|
+
* hippo doctor [--json]
|
|
22
25
|
* hippo inspect <id>
|
|
23
26
|
* hippo embed [--status]
|
|
24
27
|
* hippo watch "<command>"
|
|
@@ -29,7 +32,7 @@
|
|
|
29
32
|
* hippo decide "<decision>" [--context "<why>"] [--supersedes <id>]
|
|
30
33
|
* hippo wm <push|read|clear|flush>
|
|
31
34
|
*/
|
|
32
|
-
import { evalNow
|
|
35
|
+
import { evalNow } from './ablation.js';
|
|
33
36
|
import * as path from 'path';
|
|
34
37
|
import * as fs from 'fs';
|
|
35
38
|
import * as os from 'os';
|
|
@@ -38,14 +41,14 @@ import { execFileSync, execSync, spawn } from 'child_process';
|
|
|
38
41
|
import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, isCodexWrapperInstalled, repairCodexWrapperIfInstalled, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
|
|
39
42
|
import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, confidenceFacets, confidenceLabel, computeSchemaFit, Layer, } from './memory.js';
|
|
40
43
|
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';
|
|
44
|
+
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
45
|
import { rejectValue, unrejectValue, listRejectionsForTenant } from './reject-flow.js';
|
|
43
46
|
import { RejectedValueError } from './rejection.js';
|
|
44
47
|
import { isHandoffOutcome, formatHandoffEvidenceLine } from './handoff.js';
|
|
45
48
|
import { isCardStatus } from './card.js';
|
|
46
49
|
import { loadCardDetail } from './card-detail.js';
|
|
47
50
|
import { passesScopeFilterForRecall } from './recall-scope.js';
|
|
48
|
-
import {
|
|
51
|
+
import { estimateTokens, hybridSearch, physicsSearch, explainMatch, textOverlap, tokenize as tokenizeQuery } from './search.js';
|
|
49
52
|
import { compareEntryIdentity } from './compare.js';
|
|
50
53
|
import { renderTraceContent, parseSteps } from './trace.js';
|
|
51
54
|
import { writeRecallTraceAtRoot } from './recall-trace.js';
|
|
@@ -56,6 +59,9 @@ import { loadPhysicsState, resetAllPhysicsState } from './physics-state.js';
|
|
|
56
59
|
import { computeSystemEnergy, vecNorm } from './physics.js';
|
|
57
60
|
import { loadConfig } from './config.js';
|
|
58
61
|
import { openHippoDb, closeHippoDb } from './db.js';
|
|
62
|
+
import { runDoctor, formatDoctor } from './doctor.js';
|
|
63
|
+
import { captureToolFailure } from './capture-error.js';
|
|
64
|
+
import { blockHash, hookPayloadSessionId, lastSentState, recordTokenUse, shouldSkipUnchanged } from './token-ledger.js';
|
|
59
65
|
import { pushGoal, getActiveGoals, completeGoal, suspendGoal, resumeGoal, applyGoalStackBoost } from './goals.js';
|
|
60
66
|
import { rowToGoal } from './goals.js';
|
|
61
67
|
import { captureError, extractLessons, partitionLessons, deduplicateLesson, runWatched, fetchGitLog, isGitRepo, } from './autolearn.js';
|
|
@@ -65,7 +71,7 @@ import { detectScope } from './scope.js';
|
|
|
65
71
|
import { getGlobalRoot, initGlobal, shareMemory, listPeers, autoShare, transferScore, searchBothHybrid, syncGlobalToLocal, } from './shared.js';
|
|
66
72
|
import { DAILY_TASK_NAME, buildDailyRunnerCommand, listRegisteredWorkspaces, registerWorkspace, runDailyMaintenance, } from './scheduler.js';
|
|
67
73
|
import { importChatGPT, importClaude, importCursor, importGenericFile, importMarkdown, importVault, } from './importers.js';
|
|
68
|
-
import { cmdCapture, cmdPreCompact, resolveLastSessionTranscript, truncateCodePointSafe, sanitizeLogMessage } from './capture.js';
|
|
74
|
+
import { cmdCapture, cmdPreCompact, postCompactMessage, resolveLastSessionTranscript, truncateCodePointSafe, sanitizeLogMessage } from './capture.js';
|
|
69
75
|
import { readStdinBounded } from './stdin.js';
|
|
70
76
|
import { auditMemories, appendAuditEvent, } from './audit.js';
|
|
71
77
|
import { listApiKeys, revokeApiKey } from './auth.js';
|
|
@@ -195,8 +201,8 @@ function requireInit(hippoRoot) {
|
|
|
195
201
|
* H2: when HIPPO_REQUIRE_SERVER is set, the CLI must not silently fall back to
|
|
196
202
|
* direct DB mode — a missing server then masks a real misconfiguration (the
|
|
197
203
|
* configured HIPPO_API_KEY is also silently discarded on fallback). Throws a
|
|
198
|
-
* clear
|
|
199
|
-
*
|
|
204
|
+
* clear error then. It guards only the routed writes (remember, forget, archive,
|
|
205
|
+
* promote); every other command opens the store directly, knob or not.
|
|
200
206
|
*/
|
|
201
207
|
function failIfServerRequired(reason) {
|
|
202
208
|
if (process.env['HIPPO_REQUIRE_SERVER']) {
|
|
@@ -263,6 +269,42 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
263
269
|
'reset-physics', 'save-baseline', 'show-cases', 'stats', 'stdin',
|
|
264
270
|
'strict', 'suite', 'value-aware', 'verified', 'version', 'why',
|
|
265
271
|
]);
|
|
272
|
+
// Every flag some command reads. Anything else is a typo that no command would act on.
|
|
273
|
+
export const KNOWN_FLAGS = new Set([
|
|
274
|
+
...BOOLEAN_FLAGS,
|
|
275
|
+
'actual', 'artifact', 'artifact-ref', 'as-of', 'author', 'baseline', 'body', 'budget', 'card-id',
|
|
276
|
+
'change', 'channel', 'chatgpt', 'class', 'claude', 'codex-home', 'compare', 'constraint', 'content',
|
|
277
|
+
'context', 'contract', 'cursor', 'customer', 'days', 'depends-on', 'depth', 'description',
|
|
278
|
+
'embedding-weight', 'entity', 'estimate', 'file', 'format', 'framing', 'fresh-tail', 'from', 'goal',
|
|
279
|
+
'graph-hops', 'graph-seeds', 'history-path', 'hops', 'host', 'id', 'importance', 'include-recent',
|
|
280
|
+
'instructions', 'keep', 'kind', 'label', 'layer', 'level', 'limit', 'link', 'local-bump', 'log-file',
|
|
281
|
+
'markdown', 'max', 'max-cases', 'max-neighbors', 'min-mrr', 'min-results', 'min-score', 'mmr-lambda',
|
|
282
|
+
'model', 'name', 'next', 'next-step', 'note', 'older-than', 'op', 'out', 'outcome', 'owner', 'parent',
|
|
283
|
+
'path', 'policy', 'port', 'reason', 'repo', 'repos', 'reranker', 'reranker-top-k', 'resolution',
|
|
284
|
+
'role', 'run', 'runtime', 'salience-threshold', 'scan', 'scope', 'session', 'session-id', 'since',
|
|
285
|
+
'source', 'start-offset', 'started-at', 'state', 'status', 'step', 'steps', 'success', 'summary',
|
|
286
|
+
'supersedes', 'tag', 'target', 'target-runtime', 'task', 'team', 'tenant', 'tenant-id', 'tests',
|
|
287
|
+
'text', 'threshold', 'title', 'to', 'transcript', 'trigger', 'type', 'unit', 'value', 'vault',
|
|
288
|
+
]);
|
|
289
|
+
// Commands that delete or hide memories: an unknown flag here stops the run instead of being ignored.
|
|
290
|
+
const DESTRUCTIVE_COMMANDS = new Set([
|
|
291
|
+
'audit', 'dedup', 'forget', 'invalidate', 'reject', 'resolve', 'sleep', 'supersede',
|
|
292
|
+
]);
|
|
293
|
+
// Commands that honour --dry-run. Any other command would ignore it and run for real.
|
|
294
|
+
const DRY_RUN_COMMANDS = new Set([
|
|
295
|
+
'audit', 'capture', 'dedup', 'forget', 'import', 'invalidate', 'refine', 'setup', 'sleep',
|
|
296
|
+
]);
|
|
297
|
+
// share and brief honour --dry-run in one form only; their other forms write for real.
|
|
298
|
+
function dryRunRefusal(command, args, flags) {
|
|
299
|
+
const isBrief = command === 'brief' || command === 'project-brief';
|
|
300
|
+
const onlyForm = command === 'share' ? 'share --auto' : isBrief ? `${command} refresh` : null;
|
|
301
|
+
const honoured = command === 'share' ? args[0] === '--auto' || Boolean(flags['auto'])
|
|
302
|
+
: isBrief ? args[0] === 'refresh' : DRY_RUN_COMMANDS.has(command);
|
|
303
|
+
if (honoured)
|
|
304
|
+
return null;
|
|
305
|
+
const where = onlyForm ? ` outside \`hippo ${onlyForm}\`` : '';
|
|
306
|
+
return `hippo ${command} has no --dry-run${where}, so it would run for real. Nothing was changed.`;
|
|
307
|
+
}
|
|
266
308
|
// Shared by both the separated and glued (`=`) forms so the list can't drift.
|
|
267
309
|
function isRepeatableFlag(key) {
|
|
268
310
|
return key === 'tag' || key === 'artifact' || key === 'link' || key === 'step' || key === 'constraint' || key === 'depends-on';
|
|
@@ -506,17 +548,17 @@ function autoInstallHooks(quiet) {
|
|
|
506
548
|
// Skip if we already installed a hook into this file
|
|
507
549
|
if (installed.has(targetPath))
|
|
508
550
|
continue;
|
|
509
|
-
//
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
551
|
+
// An instruction block already present is not rewritten, but the JSON
|
|
552
|
+
// hooks and plugins below still run: they are idempotent, and skipping
|
|
553
|
+
// them meant a store set up by an older hippo never got hooks added in
|
|
554
|
+
// later releases (PreCompact, PostToolUseFailure) on a re-run of init.
|
|
555
|
+
const blockPresent = fs.existsSync(targetPath)
|
|
556
|
+
&& fs.readFileSync(targetPath, 'utf8').includes(HOOK_MARKERS.start);
|
|
515
557
|
// Only patch the agent-instructions file if it already exists.
|
|
516
558
|
// Never create a new CLAUDE.md / AGENTS.md / etc. just because a sibling
|
|
517
559
|
// marker file (.claude/settings.json, .codex, etc.) was detected — that
|
|
518
560
|
// pollutes dirs the user didn't intend to configure.
|
|
519
|
-
if (fs.existsSync(targetPath)) {
|
|
561
|
+
if (!blockPresent && fs.existsSync(targetPath)) {
|
|
520
562
|
const block = `${HOOK_MARKERS.start}\n${hookDef.content}\n${HOOK_MARKERS.end}`;
|
|
521
563
|
const existing = fs.readFileSync(targetPath, 'utf8');
|
|
522
564
|
const sep = existing.endsWith('\n') ? '\n' : '\n\n';
|
|
@@ -527,7 +569,7 @@ function autoInstallHooks(quiet) {
|
|
|
527
569
|
// The Codex session-capture wrapper swaps the codex launcher binary, so
|
|
528
570
|
// init never installs it silently — it points at the explicit opt-in
|
|
529
571
|
// command instead (issue #133).
|
|
530
|
-
if (hook === 'codex' && !isCodexWrapperInstalled()) {
|
|
572
|
+
if (hook === 'codex' && !blockPresent && !isCodexWrapperInstalled()) {
|
|
531
573
|
console.log(' Codex detected. To capture Codex sessions: hippo hook install codex');
|
|
532
574
|
}
|
|
533
575
|
// For Claude Code, also install SessionEnd+SessionStart entries in its
|
|
@@ -550,6 +592,12 @@ function autoInstallHooks(quiet) {
|
|
|
550
592
|
if (result.installedCompactResume) {
|
|
551
593
|
console.log(` Auto-installed hippo compact-resume SessionStart(compact) hook in ${hook} settings`);
|
|
552
594
|
}
|
|
595
|
+
if (result.installedPostCompact) {
|
|
596
|
+
console.log(` Auto-installed hippo post-compact PostCompact hook in ${hook} settings`);
|
|
597
|
+
}
|
|
598
|
+
if (result.installedCaptureError) {
|
|
599
|
+
console.log(` Auto-installed hippo capture-error PostToolUseFailure hook in ${hook} settings`);
|
|
600
|
+
}
|
|
553
601
|
if (result.migratedFromStop) {
|
|
554
602
|
console.log(` Migrated legacy Stop hook → SessionEnd (no longer runs every turn)`);
|
|
555
603
|
}
|
|
@@ -658,7 +706,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
658
706
|
if (flags['verified'])
|
|
659
707
|
confidence = 'verified';
|
|
660
708
|
// Compute schema fit against existing memories
|
|
661
|
-
const existing = loadAllEntries(targetRoot);
|
|
709
|
+
const existing = loadAllEntries(targetRoot, resolveTenantId({}));
|
|
662
710
|
const schemaFit = computeSchemaFit(text, rawTags, existing);
|
|
663
711
|
// A3 envelope flags
|
|
664
712
|
const kindFlagRaw = typeof flags['kind'] === 'string' ? flags['kind'] : undefined;
|
|
@@ -688,6 +736,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
688
736
|
// A5 stub auth: stamp tenant_id from env (HIPPO_TENANT) so recall isolation
|
|
689
737
|
// can filter on this row. Default tenant 'default' for unauthenticated CLI.
|
|
690
738
|
const tenantId = resolveTenantId({});
|
|
739
|
+
const rememberConfig = loadConfig(targetRoot);
|
|
691
740
|
const entry = createMemory(text, {
|
|
692
741
|
layer: Layer.Episodic,
|
|
693
742
|
tags: rawTags,
|
|
@@ -700,6 +749,7 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
700
749
|
owner: ownerFlag,
|
|
701
750
|
artifact_ref: artifactRefFlag,
|
|
702
751
|
tenantId,
|
|
752
|
+
baseHalfLifeDays: rememberConfig.defaultHalfLifeDays,
|
|
703
753
|
});
|
|
704
754
|
// Auto-tag with path context
|
|
705
755
|
const pathTags = extractPathTags(process.cwd());
|
|
@@ -716,7 +766,6 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
716
766
|
entry.tags.push(scopeTag);
|
|
717
767
|
}
|
|
718
768
|
// Salience gate: decide if this memory is worth storing
|
|
719
|
-
const rememberConfig = loadConfig(targetRoot);
|
|
720
769
|
if (rememberConfig.salience.enabled && !Boolean(flags['pin']) && !Boolean(flags['force'])) {
|
|
721
770
|
const salienceResult = computeSalience(text, entry.tags, existing, {
|
|
722
771
|
recentWindow: rememberConfig.salience.recentWindow,
|
|
@@ -758,14 +807,16 @@ async function cmdRemember(hippoRoot, text, flags) {
|
|
|
758
807
|
const facts = await extractFacts(entry.content, {
|
|
759
808
|
apiKey,
|
|
760
809
|
model: config.extraction.model,
|
|
810
|
+
onError: (msg) => console.error(` (extraction failed: ${msg})`),
|
|
761
811
|
});
|
|
762
812
|
if (facts.length > 0) {
|
|
763
813
|
storeExtractedFacts(targetRoot, entry, facts);
|
|
764
814
|
console.error(` extracted ${facts.length} fact(s)`);
|
|
765
815
|
}
|
|
766
816
|
}
|
|
767
|
-
catch {
|
|
768
|
-
// Extraction is best-effort
|
|
817
|
+
catch (err) {
|
|
818
|
+
// Extraction is best-effort: report it, never block remember.
|
|
819
|
+
console.error(` (extraction failed: ${err instanceof Error ? err.message : String(err)})`);
|
|
769
820
|
}
|
|
770
821
|
}
|
|
771
822
|
else if (shouldExtract && !apiKey) {
|
|
@@ -797,6 +848,7 @@ function cmdSupersede(hippoRoot, oldId, newContent, flags) {
|
|
|
797
848
|
pinned,
|
|
798
849
|
source: old.source,
|
|
799
850
|
confidence: 'verified',
|
|
851
|
+
tenantId: old.tenantId,
|
|
800
852
|
});
|
|
801
853
|
// AT1: write the SUCCESSOR first. The rejection guard fires on the new
|
|
802
854
|
// content — if it refuses, nothing has been mutated yet (the old ordering
|
|
@@ -854,8 +906,9 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
854
906
|
// detected-project recalls would change shape.
|
|
855
907
|
const recallExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
856
908
|
const requestedScopeForFilter = recallExplicitScope || undefined;
|
|
857
|
-
|
|
858
|
-
let
|
|
909
|
+
const loadSuperseded = includeSuperseded || Boolean(asOf);
|
|
910
|
+
let localEntries = loadRecallSearchEntries(hippoRoot, query, undefined, tenantId, requestedScopeForFilter, 'additive', loadSuperseded);
|
|
911
|
+
let globalEntries = isInitialized(globalRoot) ? loadRecallSearchEntries(globalRoot, query, undefined, tenantId, requestedScopeForFilter, 'additive', loadSuperseded) : [];
|
|
859
912
|
// v1.12.13 / C5 — WYSIATI counters. Track filter activity per the plan v3
|
|
860
913
|
// Task 3 mapping table. dropped_pre_rank is the SUM of all non-budget
|
|
861
914
|
// filter drops (pre-rank AND post-rank); its meaning is unchanged by C5.
|
|
@@ -1616,7 +1669,7 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
1616
1669
|
sessionHandoff =
|
|
1617
1670
|
rawHandoff && passesScopeFilterForRecall(rowScope(rawHandoff), effectiveScope) ? rawHandoff : null;
|
|
1618
1671
|
recentSessionEvents = rawEvents.filter((e) => passesScopeFilterForRecall(rowScope(e), effectiveScope));
|
|
1619
|
-
const tokenize = (s) => s ?
|
|
1672
|
+
const tokenize = (s) => s ? estimateTokens(s) : 0;
|
|
1620
1673
|
continuityTokens =
|
|
1621
1674
|
tokenize(activeSnapshot?.task) +
|
|
1622
1675
|
tokenize(activeSnapshot?.summary) +
|
|
@@ -1634,6 +1687,16 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
1634
1687
|
const hasContinuity = activeSnapshot !== null
|
|
1635
1688
|
|| sessionHandoff !== null
|
|
1636
1689
|
|| recentSessionEvents.length > 0;
|
|
1690
|
+
// TE0 token ledger: the memory text this recall hands back (results plus
|
|
1691
|
+
// any continuity block), recorded once per query.
|
|
1692
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
1693
|
+
tenantId,
|
|
1694
|
+
sessionId: hostSessionId() ?? null,
|
|
1695
|
+
surface: 'recall',
|
|
1696
|
+
event: 'inject',
|
|
1697
|
+
items: results.length,
|
|
1698
|
+
tokens: results.reduce((acc, r) => acc + (r.tokens || 0), 0) + continuityTokens,
|
|
1699
|
+
}));
|
|
1637
1700
|
if (results.length === 0) {
|
|
1638
1701
|
// LC1 F1 structural fix (docs/plans/2026-08-02-lc1-recall-trace-persistence.md):
|
|
1639
1702
|
// trace the zero-result recall too (result_count 0, no result rows) so
|
|
@@ -1725,21 +1788,13 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
1725
1788
|
console.log('No memories found for:', query);
|
|
1726
1789
|
return;
|
|
1727
1790
|
}
|
|
1728
|
-
|
|
1729
|
-
const updated = markRetrieved(results.map((r) => r.entry));
|
|
1791
|
+
const retrievedIds = results.map((r) => r.entry.id);
|
|
1730
1792
|
const localIndex = loadIndex(hippoRoot);
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
// updated_at, rewrites mirrors, and marks DAG parents dirty.
|
|
1735
|
-
if (!isRecallBoostAblated()) {
|
|
1736
|
-
for (const u of updated) {
|
|
1737
|
-
const targetRoot = localIndex.entries[u.id] ? hippoRoot : (isInitialized(globalRoot) ? globalRoot : hippoRoot);
|
|
1738
|
-
writeEntry(targetRoot, u);
|
|
1739
|
-
}
|
|
1740
|
-
}
|
|
1793
|
+
const strengthenedHere = strengthenRetrieved(hippoRoot, retrievedIds);
|
|
1794
|
+
if (isInitialized(globalRoot))
|
|
1795
|
+
strengthenRetrieved(globalRoot, retrievedIds.filter((id) => !strengthenedHere.has(id)));
|
|
1741
1796
|
// Track last retrieval IDs for outcome command
|
|
1742
|
-
localIndex.last_retrieval_ids =
|
|
1797
|
+
localIndex.last_retrieval_ids = retrievedIds;
|
|
1743
1798
|
// LC1 F1 structural fix (docs/plans/2026-08-02-lc1-recall-trace-persistence.md):
|
|
1744
1799
|
// ONE trace at hippoRoot (where last_retrieval_ids and outcome
|
|
1745
1800
|
// attribution live). Write the trace FIRST, then fold its id into
|
|
@@ -1971,8 +2026,9 @@ async function cmdExplain(hippoRoot, query, flags) {
|
|
|
1971
2026
|
// command honest for an operator debugging a hidden row.
|
|
1972
2027
|
const explainExplicitScope = flags['scope'] !== undefined ? String(flags['scope']).trim() : null;
|
|
1973
2028
|
const explainRequestedScope = explainExplicitScope || undefined;
|
|
1974
|
-
|
|
1975
|
-
let
|
|
2029
|
+
const explainLoadSuperseded = explainIncludeSuperseded || Boolean(explainAsOf);
|
|
2030
|
+
let explainLocalEntries = loadRecallSearchEntries(hippoRoot, query, undefined, tenantId, explainRequestedScope, 'additive', explainLoadSuperseded);
|
|
2031
|
+
let explainGlobalEntries = isInitialized(globalRoot) ? loadRecallSearchEntries(globalRoot, query, undefined, tenantId, explainRequestedScope, 'additive', explainLoadSuperseded) : [];
|
|
1976
2032
|
const passesExplainScope = (e) => api.passesCliRecallScopeFilter(e.scope ?? null, explainRequestedScope);
|
|
1977
2033
|
explainLocalEntries = explainLocalEntries.filter(passesExplainScope);
|
|
1978
2034
|
explainGlobalEntries = explainGlobalEntries.filter(passesExplainScope);
|
|
@@ -2376,6 +2432,7 @@ function cmdTraceRecord(hippoRoot, flags) {
|
|
|
2376
2432
|
source: String(flags['source'] ?? 'cli'),
|
|
2377
2433
|
trace_outcome: outcome,
|
|
2378
2434
|
source_session_id: sessionId,
|
|
2435
|
+
tenantId: resolveTenantId({}),
|
|
2379
2436
|
});
|
|
2380
2437
|
writeEntry(hippoRoot, entry);
|
|
2381
2438
|
console.log(`Recorded trace ${entry.id} (outcome=${outcome}, ${steps.length} steps)`);
|
|
@@ -2540,7 +2597,7 @@ export function learnFromMemoryMd(hippoRoot, homeDir = os.homedir()) {
|
|
|
2540
2597
|
}
|
|
2541
2598
|
if (memoryDirs.length === 0)
|
|
2542
2599
|
return 0;
|
|
2543
|
-
const existing = loadAllEntries(hippoRoot);
|
|
2600
|
+
const existing = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
2544
2601
|
let imported = 0;
|
|
2545
2602
|
let skippedSecret = 0;
|
|
2546
2603
|
// AT1 (plan §3 containment): a rejection guard refusal is per-VALUE — one
|
|
@@ -2583,6 +2640,7 @@ export function learnFromMemoryMd(hippoRoot, homeDir = os.homedir()) {
|
|
|
2583
2640
|
tags: ['claude-code-memory'],
|
|
2584
2641
|
source: `claude-memory:${file}`,
|
|
2585
2642
|
confidence: 'observed',
|
|
2643
|
+
tenantId: resolveTenantId({}),
|
|
2586
2644
|
});
|
|
2587
2645
|
try {
|
|
2588
2646
|
writeEntry(hippoRoot, entry);
|
|
@@ -2712,6 +2770,14 @@ export function renderSleepResult(result) {
|
|
|
2712
2770
|
console.log(`\nResults:`);
|
|
2713
2771
|
console.log(` Active memories: ${result.active}`);
|
|
2714
2772
|
console.log(` Removed (decayed): ${result.removed}`);
|
|
2773
|
+
// Only when dormant.enabled moved something, so every other render stays
|
|
2774
|
+
// byte-identical (tests/cli-context-render-snapshot.test.ts).
|
|
2775
|
+
if (result.dormant !== undefined && result.dormant > 0) {
|
|
2776
|
+
console.log(` Kept dormant: ${result.dormant} (hippo dormant to list)`);
|
|
2777
|
+
}
|
|
2778
|
+
if (result.dormantExpired !== undefined && result.dormantExpired > 0) {
|
|
2779
|
+
console.log(` Expired dormant: ${result.dormantExpired} (past dormant.retentionDays)`);
|
|
2780
|
+
}
|
|
2715
2781
|
console.log(` Merged episodic: ${result.mergedEpisodic}`);
|
|
2716
2782
|
console.log(` New semantic: ${result.newSemantic}`);
|
|
2717
2783
|
if (result.details && result.details.length > 0) {
|
|
@@ -2731,11 +2797,11 @@ export function renderSleepResult(result) {
|
|
|
2731
2797
|
parts.push(`${epiDups} duplicate episodic lessons`);
|
|
2732
2798
|
if (crossDups > 0)
|
|
2733
2799
|
parts.push(`${crossDups} cross-layer duplicates`);
|
|
2734
|
-
console.log(`\
|
|
2800
|
+
console.log(`\n${result.dryRun ? 'Would dedupe' : 'Deduped'} ${removed} duplicates (${parts.join(', ')}). ${result.dryRun ? 'Would keep' : 'Kept'} stronger copies.`);
|
|
2735
2801
|
}
|
|
2736
2802
|
if (result.audit) {
|
|
2737
2803
|
if (result.audit.errorsRemoved > 0) {
|
|
2738
|
-
console.log(`\nAudit: removed ${result.audit.errorsRemoved} junk memories (too short/empty).`);
|
|
2804
|
+
console.log(`\nAudit: ${result.dryRun ? 'would remove' : 'removed'} ${result.audit.errorsRemoved} junk memories (too short/empty).`);
|
|
2739
2805
|
}
|
|
2740
2806
|
if (result.audit.warningCount > 0) {
|
|
2741
2807
|
console.log(`Audit: ${result.audit.warningCount} low-quality memories detected (run \`hippo audit\` for details).`);
|
|
@@ -2760,7 +2826,10 @@ async function cmdSleepCore(hippoRoot, flags) {
|
|
|
2760
2826
|
requireInit(hippoRoot);
|
|
2761
2827
|
// Phase 1: Auto-learn from git + MEMORY.md (CLI-only, uses process.cwd() / os.homedir()).
|
|
2762
2828
|
// Stays in cli.ts; api.sleep covers Phase 2-6 only.
|
|
2763
|
-
if (!flags['no-learn']) {
|
|
2829
|
+
if (!flags['no-learn'] && flags['dry-run']) {
|
|
2830
|
+
console.log('Dry run: skipped learning from git commits and MEMORY.md files.');
|
|
2831
|
+
}
|
|
2832
|
+
else if (!flags['no-learn']) {
|
|
2764
2833
|
const config = loadConfig(hippoRoot);
|
|
2765
2834
|
if (config.autoLearnOnSleep && isGitRepo(process.cwd())) {
|
|
2766
2835
|
const { added } = learnFromRepo(hippoRoot, process.cwd(), 1);
|
|
@@ -3227,13 +3296,13 @@ async function cmdCodexSessionEndWorker(hippoRoot, flags) {
|
|
|
3227
3296
|
// capture path logs its own failures
|
|
3228
3297
|
}
|
|
3229
3298
|
}
|
|
3230
|
-
function shouldAutoRepairCodexWrapper(currentCommand,
|
|
3299
|
+
export function shouldAutoRepairCodexWrapper(currentCommand, flags) {
|
|
3231
3300
|
if (process.env.HIPPO_SKIP_AUTO_INTEGRATIONS === '1')
|
|
3232
3301
|
return false;
|
|
3233
3302
|
if (!['context', 'remember', 'recall', 'sleep', 'capture', 'outcome', 'status', 'init'].includes(currentCommand)) {
|
|
3234
3303
|
return false;
|
|
3235
3304
|
}
|
|
3236
|
-
if (currentCommand === 'init' &&
|
|
3305
|
+
if (currentCommand === 'init' && flags['no-hooks'] === true)
|
|
3237
3306
|
return false;
|
|
3238
3307
|
return true;
|
|
3239
3308
|
}
|
|
@@ -3242,8 +3311,8 @@ function shouldAutoRepairCodexWrapper(currentCommand, currentArgs) {
|
|
|
3242
3311
|
// shim). Never first-installs — silently swapping the codex binary on routine
|
|
3243
3312
|
// commands is a consent violation and reads as binary hijacking to
|
|
3244
3313
|
// supply-chain scanners (issue #133).
|
|
3245
|
-
function maybeRepairCodexWrapper(currentCommand,
|
|
3246
|
-
if (!shouldAutoRepairCodexWrapper(currentCommand,
|
|
3314
|
+
function maybeRepairCodexWrapper(currentCommand, flags) {
|
|
3315
|
+
if (!shouldAutoRepairCodexWrapper(currentCommand, flags))
|
|
3247
3316
|
return;
|
|
3248
3317
|
try {
|
|
3249
3318
|
repairCodexWrapperIfInstalled();
|
|
@@ -3465,8 +3534,13 @@ function cmdForget(hippoRoot, id, flags) {
|
|
|
3465
3534
|
if (/append-only/i.test(msg)) {
|
|
3466
3535
|
// The delete was refused by the append-only trigger — this is a raw
|
|
3467
3536
|
// memory, not a missing one. Point the user at the archive path.
|
|
3468
|
-
console.error(
|
|
3469
|
-
|
|
3537
|
+
console.error(rawForgetRefusal(id));
|
|
3538
|
+
}
|
|
3539
|
+
else if (api.isDormant(ctx, id)) {
|
|
3540
|
+
// Sleep moved it to the dormant store: it is not in active memory, so
|
|
3541
|
+
// point at the command that owns it.
|
|
3542
|
+
console.error(`${id} is dormant, not in active memory. Delete it for good: hippo dormant forget ${id} ` +
|
|
3543
|
+
`(or bring it back: hippo dormant restore ${id})`);
|
|
3470
3544
|
}
|
|
3471
3545
|
else {
|
|
3472
3546
|
console.error(`Memory not found: ${id}`);
|
|
@@ -3474,6 +3548,28 @@ function cmdForget(hippoRoot, id, flags) {
|
|
|
3474
3548
|
process.exit(1);
|
|
3475
3549
|
}
|
|
3476
3550
|
}
|
|
3551
|
+
function rawForgetRefusal(id) {
|
|
3552
|
+
return `Cannot forget ${id}: it is a raw, append-only memory. Archive it instead: hippo forget ${id} --archive --reason "<why>"`;
|
|
3553
|
+
}
|
|
3554
|
+
// Refuses exactly where the real run would, so "Would forget" is a promise, not a guess.
|
|
3555
|
+
function previewForget(hippoRoot, id, archive) {
|
|
3556
|
+
requireInit(hippoRoot);
|
|
3557
|
+
const entry = readEntry(hippoRoot, id, resolveTenantId({}));
|
|
3558
|
+
if (!entry) {
|
|
3559
|
+
console.error(`Memory not found: ${id}`);
|
|
3560
|
+
process.exit(1);
|
|
3561
|
+
}
|
|
3562
|
+
if (!archive && entry.kind === 'raw') {
|
|
3563
|
+
console.error(rawForgetRefusal(id));
|
|
3564
|
+
process.exit(1);
|
|
3565
|
+
}
|
|
3566
|
+
if (archive && entry.kind !== 'raw') {
|
|
3567
|
+
console.error(`Could not archive ${id}: memory ${id} is not raw (kind=${entry.kind})`);
|
|
3568
|
+
process.exit(1);
|
|
3569
|
+
}
|
|
3570
|
+
const snippet = entry.content.length > 80 ? `${entry.content.slice(0, 80)}...` : entry.content;
|
|
3571
|
+
console.log(`Would ${archive ? 'archive' : 'forget'} ${id} (dry run, nothing changed): "${snippet}"`);
|
|
3572
|
+
}
|
|
3477
3573
|
function cmdInspect(hippoRoot, id) {
|
|
3478
3574
|
requireInit(hippoRoot);
|
|
3479
3575
|
const entry = readEntry(hippoRoot, id, resolveTenantId({}));
|
|
@@ -3729,6 +3825,110 @@ function cmdUnreject(hippoRoot, args, flags) {
|
|
|
3729
3825
|
}
|
|
3730
3826
|
console.log(`Unrejected [${outcome.digest.slice(0, 12)}...] (was: ${outcome.reason ?? 'none given'})`);
|
|
3731
3827
|
}
|
|
3828
|
+
/**
|
|
3829
|
+
* `hippo dormant [list] [<query>...] [--limit <n>] [--json] [--global]`,
|
|
3830
|
+
* `hippo dormant restore <id>`, `hippo dormant forget <id>`.
|
|
3831
|
+
* Dormant memories are what sleep keeps instead of deleting (on by default;
|
|
3832
|
+
* `"dormant": { "enabled": false }` in .hippo/config.json deletes instead).
|
|
3833
|
+
*/
|
|
3834
|
+
function cmdDormant(hippoRoot, args, flags) {
|
|
3835
|
+
const root = resolveAuthRoot(hippoRoot, flags);
|
|
3836
|
+
const ctx = {
|
|
3837
|
+
hippoRoot: root,
|
|
3838
|
+
tenantId: resolveTenantId({}),
|
|
3839
|
+
actor: api.adminActor('cli'),
|
|
3840
|
+
};
|
|
3841
|
+
const sub = args[0];
|
|
3842
|
+
if (sub === 'restore' || sub === 'forget') {
|
|
3843
|
+
const id = (args[1] ?? '').trim();
|
|
3844
|
+
if (!id) {
|
|
3845
|
+
console.error(`Usage: hippo dormant ${sub} <id>`);
|
|
3846
|
+
process.exit(1);
|
|
3847
|
+
}
|
|
3848
|
+
try {
|
|
3849
|
+
if (sub === 'restore') {
|
|
3850
|
+
api.restoreDormant(ctx, id);
|
|
3851
|
+
console.log(`Restored ${id} to active memory.`);
|
|
3852
|
+
}
|
|
3853
|
+
else {
|
|
3854
|
+
api.forgetDormant(ctx, id);
|
|
3855
|
+
console.log(`Forgot dormant memory ${id} permanently.`);
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
catch (err) {
|
|
3859
|
+
if (err instanceof RejectedValueError) {
|
|
3860
|
+
console.error(`Cannot restore ${id}: its value was rejected (${err.reason ?? 'no reason given'}). Run \`hippo unreject\` first to allow it.`);
|
|
3861
|
+
}
|
|
3862
|
+
else {
|
|
3863
|
+
console.error(`Could not ${sub} ${id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
3864
|
+
}
|
|
3865
|
+
process.exit(1);
|
|
3866
|
+
}
|
|
3867
|
+
return;
|
|
3868
|
+
}
|
|
3869
|
+
const queryArgs = sub === 'list' ? args.slice(1) : args;
|
|
3870
|
+
const limit = parseCountFlag(flags['limit']);
|
|
3871
|
+
const rows = api.listDormant(ctx, {
|
|
3872
|
+
query: queryArgs.join(' '),
|
|
3873
|
+
limit: limit > 0 ? limit : undefined,
|
|
3874
|
+
});
|
|
3875
|
+
if (flags['json']) {
|
|
3876
|
+
console.log(JSON.stringify({ dormant: rows }, null, 2));
|
|
3877
|
+
return;
|
|
3878
|
+
}
|
|
3879
|
+
if (rows.length === 0) {
|
|
3880
|
+
console.log(queryArgs.length > 0 ? 'No dormant memories match.' : 'No dormant memories.');
|
|
3881
|
+
if (!loadConfig(root).dormant.enabled) {
|
|
3882
|
+
console.log(`Sleep deletes faded memories. To keep them dormant instead, set "dormant": { "enabled": true } in ${path.join(root, 'config.json')}.`);
|
|
3883
|
+
}
|
|
3884
|
+
return;
|
|
3885
|
+
}
|
|
3886
|
+
console.log(`${rows.length} dormant memor${rows.length === 1 ? 'y' : 'ies'}${queryArgs.length > 0 ? ' matching' : ''} (newest first):\n`);
|
|
3887
|
+
for (const row of rows) {
|
|
3888
|
+
const preview = row.content.length > 100 ? `${row.content.slice(0, 100)}...` : row.content;
|
|
3889
|
+
console.log(`--- ${row.id}`);
|
|
3890
|
+
console.log(` ${preview}`);
|
|
3891
|
+
console.log(` Dormant since ${row.dormantAt.slice(0, 10)} (${row.reason}, strength ${row.strength.toFixed(3)})${row.tags.length > 0 ? ` tags: ${row.tags.join(', ')}` : ''}`);
|
|
3892
|
+
console.log('');
|
|
3893
|
+
}
|
|
3894
|
+
console.log('Bring one back: hippo dormant restore <id> Delete for good: hippo dormant forget <id>');
|
|
3895
|
+
}
|
|
3896
|
+
/**
|
|
3897
|
+
* `hippo tokens [--days <n>] [--json] [--global]`: the token ledger
|
|
3898
|
+
* (ROADMAP TE0). Tokens of memory text handed to agents per surface, blocks
|
|
3899
|
+
* the per-prompt hook skipped as unchanged (TE2) and the tokens that saved.
|
|
3900
|
+
* Counts are estimates (characters / 4), the same estimate every budget uses.
|
|
3901
|
+
*/
|
|
3902
|
+
function cmdTokens(hippoRoot, flags) {
|
|
3903
|
+
const root = resolveAuthRoot(hippoRoot, flags);
|
|
3904
|
+
const ctx = {
|
|
3905
|
+
hippoRoot: root,
|
|
3906
|
+
tenantId: resolveTenantId({}),
|
|
3907
|
+
actor: api.adminActor('cli'),
|
|
3908
|
+
};
|
|
3909
|
+
const days = parseCountFlag(flags['days']);
|
|
3910
|
+
const summary = api.tokenSummary(ctx, { days: days > 0 ? days : undefined });
|
|
3911
|
+
if (flags['json']) {
|
|
3912
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
3913
|
+
return;
|
|
3914
|
+
}
|
|
3915
|
+
const windowDays = days > 0 ? days : 30;
|
|
3916
|
+
if (summary.surfaces.length === 0) {
|
|
3917
|
+
console.log(`No memory text recorded in the last ${windowDays} days.`);
|
|
3918
|
+
return;
|
|
3919
|
+
}
|
|
3920
|
+
console.log(`Memory text handed to agents, last ${windowDays} days (estimated tokens)\n`);
|
|
3921
|
+
console.log(` ${'surface'.padEnd(14)}${'sent'.padStart(8)}${'tokens'.padStart(12)}${'skipped'.padStart(10)}${'saved'.padStart(12)}`);
|
|
3922
|
+
for (const row of summary.surfaces) {
|
|
3923
|
+
console.log(` ${row.surface.padEnd(14)}${String(row.injected).padStart(8)}${String(row.tokens).padStart(12)}`
|
|
3924
|
+
+ `${String(row.skipped).padStart(10)}${String(row.tokensAvoided).padStart(12)}`);
|
|
3925
|
+
}
|
|
3926
|
+
console.log('');
|
|
3927
|
+
console.log(` Total sent: ${summary.totalTokens} tokens. Saved by skipping unchanged blocks: ${summary.totalTokensAvoided}.`);
|
|
3928
|
+
if (summary.meanTokensPerSession > 0) {
|
|
3929
|
+
console.log(` Mean per session (rows with a session id): ${summary.meanTokensPerSession} tokens.`);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3732
3932
|
function cmdSnapshot(hippoRoot, args, flags) {
|
|
3733
3933
|
requireInit(hippoRoot);
|
|
3734
3934
|
const subcommand = args[0] ?? 'show';
|
|
@@ -6057,22 +6257,24 @@ async function cmdContext(hippoRoot, args, flags, stdinText) {
|
|
|
6057
6257
|
origin: r.origin ?? null,
|
|
6058
6258
|
category: r.category ?? null,
|
|
6059
6259
|
}));
|
|
6060
|
-
|
|
6260
|
+
const jsonText = JSON.stringify({
|
|
6061
6261
|
query: query || '*',
|
|
6062
6262
|
activeSnapshot: result.activeSnapshot ?? null,
|
|
6063
6263
|
sessionHandoff: result.sessionHandoff ?? null,
|
|
6064
6264
|
recentSessionEvents: result.recentEvents ?? [],
|
|
6065
6265
|
memories: output,
|
|
6066
6266
|
tokens: result.tokens,
|
|
6267
|
+
});
|
|
6268
|
+
console.log(jsonText);
|
|
6269
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
6270
|
+
tenantId: ctx.tenantId, sessionId: currentSessionId, surface: pinnedOnly ? 'hook' : 'context',
|
|
6271
|
+
event: 'inject', items: output.length, tokens: estimateTokens(jsonText),
|
|
6067
6272
|
}));
|
|
6068
6273
|
}
|
|
6069
6274
|
else if (format === 'additional-context') {
|
|
6070
6275
|
// Claude Code UserPromptSubmit hook JSON shape. Capture print* helpers'
|
|
6071
6276
|
// output into a string buffer and wrap as `additionalContext`.
|
|
6072
|
-
const
|
|
6073
|
-
const realLog = console.log;
|
|
6074
|
-
console.log = (...parts) => { lines.push(parts.map(String).join(' ')); };
|
|
6075
|
-
try {
|
|
6277
|
+
const textBlock = captureConsole(() => {
|
|
6076
6278
|
if (result.activeSnapshot)
|
|
6077
6279
|
printActiveTaskSnapshot(result.activeSnapshot);
|
|
6078
6280
|
if (result.sessionHandoff)
|
|
@@ -6081,16 +6283,37 @@ async function cmdContext(hippoRoot, args, flags, stdinText) {
|
|
|
6081
6283
|
printSessionEvents(result.recentEvents);
|
|
6082
6284
|
}
|
|
6083
6285
|
if (renderItems.length > 0) {
|
|
6084
|
-
|
|
6286
|
+
// TE1: no live strength percentage, so an unchanged set of memories
|
|
6287
|
+
// renders byte-identically turn after turn.
|
|
6288
|
+
printContextMarkdown(renderItems, result.tokens, framing, { showStrength: false });
|
|
6085
6289
|
}
|
|
6086
6290
|
printCrossProjectSection(crossEntries);
|
|
6087
|
-
}
|
|
6088
|
-
finally {
|
|
6089
|
-
console.log = realLog;
|
|
6090
|
-
}
|
|
6091
|
-
const textBlock = lines.join('\n');
|
|
6291
|
+
});
|
|
6092
6292
|
if (!textBlock.trim())
|
|
6093
6293
|
return;
|
|
6294
|
+
const surface = pinnedOnly ? 'hook' : 'context';
|
|
6295
|
+
const hash = blockHash(textBlock);
|
|
6296
|
+
const tokens = estimateTokens(textBlock);
|
|
6297
|
+
// TE2: the per-prompt hook skips a block identical to the one this
|
|
6298
|
+
// session already has, and resends it every refreshTurns skips. Only
|
|
6299
|
+
// with a session id from the hook payload itself: an inherited env id
|
|
6300
|
+
// (a manual run inside an agent's shell) must never suppress output.
|
|
6301
|
+
if (pinnedOnly && payloadSessionId !== undefined) {
|
|
6302
|
+
const injectCfg = loadConfig(hippoRoot).pinnedInject;
|
|
6303
|
+
if (injectCfg.skipUnchanged !== false) {
|
|
6304
|
+
const refreshTurns = Number.isFinite(injectCfg.refreshTurns) && injectCfg.refreshTurns >= 0
|
|
6305
|
+
? injectCfg.refreshTurns
|
|
6306
|
+
: 10;
|
|
6307
|
+
const last = withLedgerDb(hippoRoot, (db) => lastSentState(db, ctx.tenantId, payloadSessionId, surface));
|
|
6308
|
+
if (shouldSkipUnchanged(last ?? null, hash, refreshTurns)) {
|
|
6309
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
6310
|
+
tenantId: ctx.tenantId, sessionId: payloadSessionId, surface, event: 'skip',
|
|
6311
|
+
items: renderItems.length, tokens, hash,
|
|
6312
|
+
}));
|
|
6313
|
+
return;
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
}
|
|
6094
6317
|
const payload = {
|
|
6095
6318
|
hookSpecificOutput: {
|
|
6096
6319
|
hookEventName: 'UserPromptSubmit',
|
|
@@ -6098,25 +6321,113 @@ async function cmdContext(hippoRoot, args, flags, stdinText) {
|
|
|
6098
6321
|
},
|
|
6099
6322
|
};
|
|
6100
6323
|
process.stdout.write(JSON.stringify(payload));
|
|
6324
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
6325
|
+
tenantId: ctx.tenantId, sessionId: currentSessionId, surface, event: 'inject',
|
|
6326
|
+
items: renderItems.length, tokens, hash,
|
|
6327
|
+
}));
|
|
6101
6328
|
}
|
|
6102
6329
|
else {
|
|
6103
6330
|
// markdown (default)
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6331
|
+
const text = captureConsole(() => {
|
|
6332
|
+
if (result.activeSnapshot) {
|
|
6333
|
+
printActiveTaskSnapshot(result.activeSnapshot);
|
|
6334
|
+
}
|
|
6335
|
+
if (result.sessionHandoff) {
|
|
6336
|
+
printHandoff(result.sessionHandoff);
|
|
6337
|
+
}
|
|
6338
|
+
if (result.recentEvents && result.recentEvents.length > 0) {
|
|
6339
|
+
printSessionEvents(result.recentEvents);
|
|
6340
|
+
}
|
|
6341
|
+
if (renderItems.length > 0) {
|
|
6342
|
+
printContextMarkdown(renderItems, result.tokens, framing);
|
|
6343
|
+
}
|
|
6344
|
+
printCrossProjectSection(crossEntries);
|
|
6345
|
+
if (result.ambientState) {
|
|
6346
|
+
console.log(`\n${renderAmbientSummary(result.ambientState)}`);
|
|
6347
|
+
}
|
|
6348
|
+
});
|
|
6349
|
+
if (text.length > 0)
|
|
6350
|
+
console.log(text);
|
|
6351
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
6352
|
+
tenantId: ctx.tenantId, sessionId: currentSessionId, surface: pinnedOnly ? 'hook' : 'context',
|
|
6353
|
+
event: 'inject', items: renderItems.length, tokens: estimateTokens(text),
|
|
6354
|
+
}));
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
/**
|
|
6358
|
+
* TE2: compaction drops the pinned blocks the per-prompt hook injected
|
|
6359
|
+
* earlier, so record a `reset` for the payload's session and the next prompt
|
|
6360
|
+
* injects again even if nothing changed. `requiredSource` limits it to hook
|
|
6361
|
+
* payloads with that `source` (SessionStart fires for other reasons too).
|
|
6362
|
+
* Best-effort and silent: a malformed payload records nothing.
|
|
6363
|
+
*/
|
|
6364
|
+
function resetHookInjection(hippoRoot, stdinText, requiredSource) {
|
|
6365
|
+
const sessionId = hookPayloadSessionId(stdinText, requiredSource);
|
|
6366
|
+
if (sessionId === null)
|
|
6367
|
+
return;
|
|
6368
|
+
withLedgerDb(hippoRoot, (db) => recordTokenUse(db, {
|
|
6369
|
+
tenantId: resolveTenantId({}), sessionId, surface: 'hook', event: 'reset', items: 0, tokens: 0,
|
|
6370
|
+
}));
|
|
6371
|
+
}
|
|
6372
|
+
/**
|
|
6373
|
+
* Run `fn` with console.log captured; returns the captured lines joined by
|
|
6374
|
+
* newlines (what the same calls would have printed, minus the final newline).
|
|
6375
|
+
*/
|
|
6376
|
+
function captureConsole(fn) {
|
|
6377
|
+
const lines = [];
|
|
6378
|
+
const realLog = console.log;
|
|
6379
|
+
console.log = (...parts) => { lines.push(parts.map(String).join(' ')); };
|
|
6380
|
+
try {
|
|
6381
|
+
fn();
|
|
6382
|
+
}
|
|
6383
|
+
finally {
|
|
6384
|
+
console.log = realLog;
|
|
6385
|
+
}
|
|
6386
|
+
return lines.join('\n');
|
|
6387
|
+
}
|
|
6388
|
+
/**
|
|
6389
|
+
* The store a Claude Code hook writes to: the project store when there is
|
|
6390
|
+
* one, else an existing global store, else the project path (which the hook
|
|
6391
|
+
* then skips, since hooks fire in every directory and must not create one).
|
|
6392
|
+
* Pre-compact and compact-resume must agree, or a snapshot saved to one store
|
|
6393
|
+
* is looked for in the other.
|
|
6394
|
+
*/
|
|
6395
|
+
function hookStoreRoot(hippoRoot) {
|
|
6396
|
+
if (isInitialized(hippoRoot))
|
|
6397
|
+
return hippoRoot;
|
|
6398
|
+
const globalRoot = getGlobalRoot();
|
|
6399
|
+
return isInitialized(globalRoot) ? globalRoot : hippoRoot;
|
|
6400
|
+
}
|
|
6401
|
+
/**
|
|
6402
|
+
* Run `fn` against the token ledger's store: the local store when it is
|
|
6403
|
+
* initialized, else the global one (the per-prompt hook runs in directories
|
|
6404
|
+
* without a local store). Best-effort: returns undefined and never throws,
|
|
6405
|
+
* because a ledger failure must not break context or recall.
|
|
6406
|
+
*/
|
|
6407
|
+
function withLedgerDb(hippoRoot, fn) {
|
|
6408
|
+
let root = null;
|
|
6409
|
+
try {
|
|
6410
|
+
if (isInitialized(hippoRoot))
|
|
6411
|
+
root = hippoRoot;
|
|
6412
|
+
else if (isInitialized(getGlobalRoot()))
|
|
6413
|
+
root = getGlobalRoot();
|
|
6414
|
+
}
|
|
6415
|
+
catch {
|
|
6416
|
+
return undefined;
|
|
6417
|
+
}
|
|
6418
|
+
if (root === null)
|
|
6419
|
+
return undefined;
|
|
6420
|
+
let db;
|
|
6421
|
+
try {
|
|
6422
|
+
db = openHippoDb(root);
|
|
6423
|
+
return fn(db);
|
|
6424
|
+
}
|
|
6425
|
+
catch {
|
|
6426
|
+
return undefined;
|
|
6427
|
+
}
|
|
6428
|
+
finally {
|
|
6429
|
+
if (db)
|
|
6430
|
+
closeHippoDb(db);
|
|
6120
6431
|
}
|
|
6121
6432
|
}
|
|
6122
6433
|
/**
|
|
@@ -6135,13 +6446,15 @@ function printCrossProjectSection(items) {
|
|
|
6135
6446
|
}
|
|
6136
6447
|
}
|
|
6137
6448
|
/** @internal — exported for snapshot tests (tests/cli-context-render-snapshot.test.ts). NOT a stable public API. */
|
|
6138
|
-
export function printContextMarkdown(items, totalTokens, framing = 'observe') {
|
|
6449
|
+
export function printContextMarkdown(items, totalTokens, framing = 'observe', opts = {}) {
|
|
6139
6450
|
const now = evalNow();
|
|
6451
|
+
const showStrength = opts.showStrength !== false;
|
|
6140
6452
|
console.log(`## Project Memory (${items.length} entries, ${totalTokens} tokens)\n`);
|
|
6141
6453
|
for (const item of items) {
|
|
6142
6454
|
const e = item.entry;
|
|
6143
6455
|
const tagStr = e.tags.length > 0 ? ` [${e.tags.join(', ')}]` : '';
|
|
6144
6456
|
const strengthPct = Math.round(calculateStrength(e) * 100);
|
|
6457
|
+
const strengthStr = showStrength ? ` (${strengthPct}%)` : '';
|
|
6145
6458
|
const globalPrefix = item.isGlobal ? '[global] ' : '';
|
|
6146
6459
|
const effectiveConf = confidenceFacets(e, now).tier;
|
|
6147
6460
|
const label = confidenceLabel(e, now);
|
|
@@ -6151,21 +6464,21 @@ export function printContextMarkdown(items, totalTokens, framing = 'observe') {
|
|
|
6151
6464
|
const dateStr = new Date(e.created).toISOString().slice(0, 10);
|
|
6152
6465
|
if (effectiveConf === 'verified') {
|
|
6153
6466
|
// Verified: no date prefix, just the rule
|
|
6154
|
-
console.log(`- **${confTag} ${globalPrefix}${e.content}**${tagStr}
|
|
6467
|
+
console.log(`- **${confTag} ${globalPrefix}${e.content}**${tagStr}${strengthStr}`);
|
|
6155
6468
|
}
|
|
6156
6469
|
else if (effectiveConf === 'stale') {
|
|
6157
|
-
console.log(`- **${confTag} Previously observed (${dateStr}): ${globalPrefix}${e.content}**${tagStr}
|
|
6470
|
+
console.log(`- **${confTag} Previously observed (${dateStr}): ${globalPrefix}${e.content}**${tagStr}${strengthStr}`);
|
|
6158
6471
|
}
|
|
6159
6472
|
else {
|
|
6160
|
-
console.log(`- **${confTag} Previously observed (${dateStr}): ${globalPrefix}${e.content}**${tagStr}
|
|
6473
|
+
console.log(`- **${confTag} Previously observed (${dateStr}): ${globalPrefix}${e.content}**${tagStr}${strengthStr}`);
|
|
6161
6474
|
}
|
|
6162
6475
|
}
|
|
6163
6476
|
else if (framing === 'suggest') {
|
|
6164
|
-
console.log(`- **${confTag} Consider checking: ${globalPrefix}${e.content}**${tagStr}
|
|
6477
|
+
console.log(`- **${confTag} Consider checking: ${globalPrefix}${e.content}**${tagStr}${strengthStr}`);
|
|
6165
6478
|
}
|
|
6166
6479
|
else {
|
|
6167
6480
|
// framing === 'assert': no prefix (bare facts)
|
|
6168
|
-
console.log(`- **${confTag} ${globalPrefix}${e.content}**${tagStr}
|
|
6481
|
+
console.log(`- **${confTag} ${globalPrefix}${e.content}**${tagStr}${strengthStr}`);
|
|
6169
6482
|
}
|
|
6170
6483
|
}
|
|
6171
6484
|
}
|
|
@@ -6304,12 +6617,12 @@ async function cmdWatch(command, hippoRoot) {
|
|
|
6304
6617
|
console.error('Command failed but .hippo not initialized. Run `hippo init` to enable auto-learn.');
|
|
6305
6618
|
process.exit(exitCode);
|
|
6306
6619
|
}
|
|
6307
|
-
const entry = captureError(exitCode, stderr, command);
|
|
6620
|
+
const entry = captureError(exitCode, stderr, command, resolveTenantId({}));
|
|
6308
6621
|
// Compute schema fit against existing memories
|
|
6309
|
-
const existingWatch = loadAllEntries(hippoRoot);
|
|
6622
|
+
const existingWatch = loadAllEntries(hippoRoot, entry.tenantId);
|
|
6310
6623
|
const watchFit = computeSchemaFit(entry.content, entry.tags, existingWatch);
|
|
6311
6624
|
entry.schema_fit = watchFit;
|
|
6312
|
-
entry.half_life_days = deriveHalfLife(
|
|
6625
|
+
entry.half_life_days = deriveHalfLife(loadConfig(hippoRoot).defaultHalfLifeDays, entry);
|
|
6313
6626
|
entry.strength = calculateStrength(entry);
|
|
6314
6627
|
// AT1 (plan §3 containment): mechanical content from a failed command — a
|
|
6315
6628
|
// rejection-guard refusal here must not crash the watcher. Skip silently
|
|
@@ -6348,7 +6661,9 @@ function learnFromRepo(hippoRoot, repoPath, days, label) {
|
|
|
6348
6661
|
console.log(`${prefix}No fix/revert/bug commits found in the specified period.`);
|
|
6349
6662
|
return { added: 0, skipped: 0, lowInfo: 0 };
|
|
6350
6663
|
}
|
|
6351
|
-
|
|
6664
|
+
// Same patterns as MCP hippo_learn: config.gitLearnPatterns (whose default
|
|
6665
|
+
// equals extractLessons' built-in list) so a custom list applies everywhere.
|
|
6666
|
+
const parsedLessons = extractLessons(gitLog, loadConfig(hippoRoot).gitLearnPatterns);
|
|
6352
6667
|
if (parsedLessons.length === 0) {
|
|
6353
6668
|
console.log(`${prefix}No fix/revert/bug commits found in the specified period.`);
|
|
6354
6669
|
return { added: 0, skipped: 0, lowInfo: 0 };
|
|
@@ -6392,14 +6707,9 @@ function learnFromRepo(hippoRoot, repoPath, days, label) {
|
|
|
6392
6707
|
// the existing summary line.
|
|
6393
6708
|
let rejected = 0;
|
|
6394
6709
|
const gitLearnTags = ['error', 'git-learned'];
|
|
6395
|
-
const existingForSchema = loadAllEntries(hippoRoot);
|
|
6710
|
+
const existingForSchema = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
6396
6711
|
for (const lesson of lessons) {
|
|
6397
|
-
//
|
|
6398
|
-
// `loadAllEntries(hippoRoot)` call a few lines up) is host-wide and
|
|
6399
|
-
// intentionally out-of-L9-scope per plan §11 (cli.ts is
|
|
6400
|
-
// single-tenant-per-process). The tenantId arg here is a defensive no-op:
|
|
6401
|
-
// deduplicateLesson's array overload ignores it; the parameter exists
|
|
6402
|
-
// only to mirror the canonical caller pattern used elsewhere in cli.ts.
|
|
6712
|
+
// The array overload ignores the tenant arg; existingForSchema is already scoped.
|
|
6403
6713
|
if (deduplicateLesson(existingForSchema, lesson, 0.7, resolveTenantId({}))) {
|
|
6404
6714
|
skipped++;
|
|
6405
6715
|
continue;
|
|
@@ -6418,6 +6728,7 @@ function learnFromRepo(hippoRoot, repoPath, days, label) {
|
|
|
6418
6728
|
source: 'git-learn',
|
|
6419
6729
|
confidence: 'observed',
|
|
6420
6730
|
schema_fit: schemaFitVal,
|
|
6731
|
+
tenantId: resolveTenantId({}),
|
|
6421
6732
|
});
|
|
6422
6733
|
// Auto-tag with path context from the repo being learned
|
|
6423
6734
|
const learnPathTags = extractPathTags(repoPath);
|
|
@@ -6912,6 +7223,12 @@ function cmdHook(args, flags) {
|
|
|
6912
7223
|
if (result.installedCompactResume) {
|
|
6913
7224
|
console.log(`Installed hippo compact-resume SessionStart(compact) hook in ${result.target} settings`);
|
|
6914
7225
|
}
|
|
7226
|
+
if (result.installedPostCompact) {
|
|
7227
|
+
console.log(`Installed hippo post-compact PostCompact hook in ${result.target} settings`);
|
|
7228
|
+
}
|
|
7229
|
+
if (result.installedCaptureError) {
|
|
7230
|
+
console.log(`Installed hippo capture-error PostToolUseFailure hook in ${result.target} settings`);
|
|
7231
|
+
}
|
|
6915
7232
|
if (result.migratedFromStop) {
|
|
6916
7233
|
console.log(`Migrated legacy Stop hook → SessionEnd (was running every turn; now fires once on session exit)`);
|
|
6917
7234
|
}
|
|
@@ -7032,6 +7349,10 @@ function cmdSetup(flags) {
|
|
|
7032
7349
|
bits.push('PreCompact (pre-compact)');
|
|
7033
7350
|
if (result.installedCompactResume)
|
|
7034
7351
|
bits.push('SessionStart(compact) (compact-resume)');
|
|
7352
|
+
if (result.installedPostCompact)
|
|
7353
|
+
bits.push('PostCompact (post-compact)');
|
|
7354
|
+
if (result.installedCaptureError)
|
|
7355
|
+
bits.push('PostToolUseFailure (capture-error)');
|
|
7035
7356
|
if (result.migratedFromStop)
|
|
7036
7357
|
bits.push('migrated legacy Stop');
|
|
7037
7358
|
if (result.migratedSplitSessionEnd)
|
|
@@ -7573,6 +7894,8 @@ const VALID_AUDIT_OPS = new Set([
|
|
|
7573
7894
|
'reject_refusal', // AT1 — emitted when the rejection guard refuses a write; lockstep
|
|
7574
7895
|
'unreject_value', // AT1 — emitted by `hippo unreject`; lockstep
|
|
7575
7896
|
'conflict_resolve', // AT1 — emitted by resolveConflict on every resolution path; lockstep
|
|
7897
|
+
'half_life_migrate', // Decay default change — emitted by migrateDefaultHalfLife; lockstep with AuditOp union
|
|
7898
|
+
'dormant_restore', // Dormant memories — emitted by api.restoreDormant; lockstep with AuditOp union + server.ts VALID_AUDIT_OPS
|
|
7576
7899
|
]);
|
|
7577
7900
|
function formatAuditRow(ev) {
|
|
7578
7901
|
const target = ev.targetId ?? '-';
|
|
@@ -8298,6 +8621,23 @@ Commands:
|
|
|
8298
8621
|
--global Operate on the global store
|
|
8299
8622
|
unreject <digest-prefix> Delete a tombstone (the only escape hatch)
|
|
8300
8623
|
--global Operate on the global store
|
|
8624
|
+
dormant [<query>] List faded memories sleep kept instead of deleting
|
|
8625
|
+
(on by default; "dormant": {"enabled": false} deletes instead)
|
|
8626
|
+
--limit <n> Max rows, newest first (default: 20)
|
|
8627
|
+
--json Output as JSON
|
|
8628
|
+
--global Operate on the global store
|
|
8629
|
+
dormant restore <id> Bring a dormant memory back to active memory
|
|
8630
|
+
dormant forget <id> Delete a dormant memory permanently
|
|
8631
|
+
capture-error Store a failed tool call as an error memory (reads the Claude Code
|
|
8632
|
+
PostToolUseFailure hook payload on stdin; skips routine failures)
|
|
8633
|
+
doctor Check the install: Node, store, schema, sleep, agent hooks
|
|
8634
|
+
--json Machine-readable report (exit code 1 on any failure)
|
|
8635
|
+
tokens Tokens of memory text hippo handed agents, per surface
|
|
8636
|
+
(hook, context, recall, MCP, HTTP), and what skipping
|
|
8637
|
+
unchanged hook blocks saved
|
|
8638
|
+
--days <n> Window in days (default: 30)
|
|
8639
|
+
--json Output as JSON
|
|
8640
|
+
--global Operate on the global store
|
|
8301
8641
|
snapshot <sub> Persist or inspect the current active task
|
|
8302
8642
|
snapshot save Save active task state
|
|
8303
8643
|
--task <task>
|
|
@@ -8425,6 +8765,8 @@ Commands:
|
|
|
8425
8765
|
pre-compact PreCompact hook: snapshot + capture the tail before compaction
|
|
8426
8766
|
--log-file <p> Diagnostic log path (default: ~/.hippo/logs/pre-compact.log)
|
|
8427
8767
|
compact-resume SessionStart(compact) hook: re-print the snapshot + session trail
|
|
8768
|
+
post-compact PostCompact hook: tell the user what pre-compact saved
|
|
8769
|
+
--log-file <p> Same log path as pre-compact (default: ~/.hippo/logs/pre-compact.log)
|
|
8428
8770
|
codex-run [-- ...args] Launch real Codex behind Hippo's session-end wrapper
|
|
8429
8771
|
hook <sub> [target] Manage framework integrations
|
|
8430
8772
|
hook list Show available hooks
|
|
@@ -8589,6 +8931,9 @@ Examples:
|
|
|
8589
8931
|
hippo reject --value "never store my key again" --reason "secret"
|
|
8590
8932
|
hippo rejections
|
|
8591
8933
|
hippo unreject a1b2c3d4e5f6
|
|
8934
|
+
hippo dormant "staging hostname"
|
|
8935
|
+
hippo dormant restore mem_abc123
|
|
8936
|
+
hippo tokens --days 7
|
|
8592
8937
|
hippo session log --id sess_123 --task "Ship feature" --type progress --content "Build is green, next step is docs"
|
|
8593
8938
|
hippo session latest --json
|
|
8594
8939
|
hippo session resume
|
|
@@ -8632,25 +8977,16 @@ Examples:
|
|
|
8632
8977
|
// ---------------------------------------------------------------------------
|
|
8633
8978
|
// Entry point
|
|
8634
8979
|
// ---------------------------------------------------------------------------
|
|
8635
|
-
|
|
8636
|
-
const hippoRoot = getHippoRoot(process.cwd());
|
|
8637
|
-
async function main() {
|
|
8980
|
+
async function main(command, args, flags, hippoRoot) {
|
|
8638
8981
|
if (command === '--version' || command === '-v' || flags['version']) {
|
|
8639
8982
|
const __filename_local = fileURLToPath(import.meta.url);
|
|
8640
8983
|
const __dirname_local = path.dirname(__filename_local);
|
|
8641
|
-
const
|
|
8642
|
-
let pkgJson;
|
|
8643
|
-
try {
|
|
8644
|
-
pkgJson = fs.readFileSync(pkgPath, 'utf-8');
|
|
8645
|
-
}
|
|
8646
|
-
catch {
|
|
8647
|
-
pkgJson = fs.readFileSync(path.join(__dirname_local, '..', '..', 'package.json'), 'utf-8');
|
|
8648
|
-
}
|
|
8984
|
+
const pkgJson = fs.readFileSync(path.join(__dirname_local, '..', 'package.json'), 'utf-8');
|
|
8649
8985
|
const { version } = JSON.parse(pkgJson);
|
|
8650
8986
|
console.log(version);
|
|
8651
8987
|
process.exit(0);
|
|
8652
8988
|
}
|
|
8653
|
-
maybeRepairCodexWrapper(command,
|
|
8989
|
+
maybeRepairCodexWrapper(command, flags);
|
|
8654
8990
|
/** Global --scope well-formedness guard (v1.26.2). parseArgs stores a value-less
|
|
8655
8991
|
* flag as boolean true; downstream the 14 consumer sites either coerced that to
|
|
8656
8992
|
* the literal scope string 'true' (recall filter/unlock input, wm session scope,
|
|
@@ -8685,6 +9021,21 @@ async function main() {
|
|
|
8685
9021
|
process.exit(1);
|
|
8686
9022
|
}
|
|
8687
9023
|
}
|
|
9024
|
+
// card checks its flags per subcommand, with a stricter message.
|
|
9025
|
+
const unknownFlags = command === 'card' ? [] : Object.keys(flags).filter((key) => !KNOWN_FLAGS.has(key));
|
|
9026
|
+
if (unknownFlags.length > 0) {
|
|
9027
|
+
const names = unknownFlags.map((key) => `--${key}`).join(', ');
|
|
9028
|
+
if (DESTRUCTIVE_COMMANDS.has(command)) {
|
|
9029
|
+
console.error(`Unknown flag ${names} for hippo ${command}. Nothing was changed.`);
|
|
9030
|
+
process.exit(2);
|
|
9031
|
+
}
|
|
9032
|
+
console.error(`hippo: ignoring unknown flag ${names}. A later release will reject it.`);
|
|
9033
|
+
}
|
|
9034
|
+
const refusal = Object.hasOwn(flags, 'dry-run') ? dryRunRefusal(command, args, flags) : null;
|
|
9035
|
+
if (refusal) {
|
|
9036
|
+
console.error(refusal);
|
|
9037
|
+
process.exit(2);
|
|
9038
|
+
}
|
|
8688
9039
|
switch (command) {
|
|
8689
9040
|
case 'init':
|
|
8690
9041
|
cmdInit(hippoRoot, flags);
|
|
@@ -8831,16 +9182,45 @@ async function main() {
|
|
|
8831
9182
|
case 'pre-compact': {
|
|
8832
9183
|
// Bounded wait, not a TTY guard: an idle non-TTY pipe must not hang.
|
|
8833
9184
|
const { text: stdinText, timedOut: stdinTimedOut } = await readStdinBounded();
|
|
8834
|
-
|
|
9185
|
+
resetHookInjection(hippoRoot, stdinText, null);
|
|
9186
|
+
await cmdPreCompact(hookStoreRoot(hippoRoot), {
|
|
8835
9187
|
stdinText,
|
|
8836
9188
|
stdinTimedOut,
|
|
8837
9189
|
logFile: typeof flags['log-file'] === 'string' ? flags['log-file'] : undefined,
|
|
8838
9190
|
});
|
|
8839
9191
|
break;
|
|
8840
9192
|
}
|
|
9193
|
+
case 'post-compact': {
|
|
9194
|
+
// PostCompact hook: tells the user what pre-compact saved. Plain text,
|
|
9195
|
+
// because Claude Code shows this hook's stdout as-is. Always exits 0.
|
|
9196
|
+
const { text } = await readStdinBounded();
|
|
9197
|
+
const logFlag = flags['log-file'];
|
|
9198
|
+
const message = postCompactMessage(text, logFlag === true || logFlag === false || Array.isArray(logFlag) ? undefined : logFlag);
|
|
9199
|
+
if (message !== null)
|
|
9200
|
+
console.log(message);
|
|
9201
|
+
break;
|
|
9202
|
+
}
|
|
9203
|
+
case 'capture-error': {
|
|
9204
|
+
// PostToolUseFailure hook: every path exits 0, and nothing is created
|
|
9205
|
+
// when no store exists (the hook fires in every directory).
|
|
9206
|
+
const { text } = await readStdinBounded();
|
|
9207
|
+
try {
|
|
9208
|
+
const root = hookStoreRoot(hippoRoot);
|
|
9209
|
+
const payload = (text ?? '').trim();
|
|
9210
|
+
if (isInitialized(root) && payload) {
|
|
9211
|
+
// SAFETY: JSON.parse returns a JSON value by definition.
|
|
9212
|
+
captureToolFailure(root, resolveTenantId({}), JSON.parse(payload));
|
|
9213
|
+
}
|
|
9214
|
+
}
|
|
9215
|
+
catch {
|
|
9216
|
+
// A malformed payload or store error must never fail the agent's tool call.
|
|
9217
|
+
}
|
|
9218
|
+
break;
|
|
9219
|
+
}
|
|
8841
9220
|
case 'compact-resume': {
|
|
8842
9221
|
const { text: stdinText, timedOut: stdinTimedOut } = await readStdinBounded();
|
|
8843
|
-
|
|
9222
|
+
resetHookInjection(hippoRoot, stdinText, 'compact');
|
|
9223
|
+
cmdCompactResume(hookStoreRoot(hippoRoot), stdinText, stdinTimedOut);
|
|
8844
9224
|
break;
|
|
8845
9225
|
}
|
|
8846
9226
|
case 'codex-run':
|
|
@@ -8876,7 +9256,7 @@ async function main() {
|
|
|
8876
9256
|
break;
|
|
8877
9257
|
}
|
|
8878
9258
|
requireInit(hippoRoot);
|
|
8879
|
-
const entries = loadAllEntries(hippoRoot);
|
|
9259
|
+
const entries = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
8880
9260
|
const result = auditMemories(entries);
|
|
8881
9261
|
const shouldFix = Boolean(flags['fix']);
|
|
8882
9262
|
if (result.issues.length === 0) {
|
|
@@ -8890,13 +9270,15 @@ async function main() {
|
|
|
8890
9270
|
console.log(` "${issue.content.slice(0, 80)}${issue.content.length > 80 ? '...' : ''}"`);
|
|
8891
9271
|
}
|
|
8892
9272
|
if (shouldFix) {
|
|
8893
|
-
const
|
|
8894
|
-
if (
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
9273
|
+
const errors = result.issues.filter(i => i.severity === 'error');
|
|
9274
|
+
if (errors.length > 0 && flags['dry-run'] === true) {
|
|
9275
|
+
console.log(`\nWould remove ${errors.length} error-severity memories (dry run, nothing deleted).`);
|
|
9276
|
+
console.log(`${result.issues.length - errors.length} warnings would remain (review manually).`);
|
|
9277
|
+
}
|
|
9278
|
+
else if (errors.length > 0) {
|
|
9279
|
+
const removedCount = errors.filter((issue) => deleteEntry(hippoRoot, issue.memoryId, { reason: `audit --fix: ${issue.reason}`, automatic: true })).length;
|
|
9280
|
+
console.log(`\nRemoved ${removedCount} error-severity memories.`);
|
|
9281
|
+
console.log(`${result.issues.length - errors.length} warnings remain (review manually).`);
|
|
8900
9282
|
}
|
|
8901
9283
|
else {
|
|
8902
9284
|
console.log(`\nNo error-severity issues. Warnings require manual review.`);
|
|
@@ -8985,6 +9367,21 @@ async function main() {
|
|
|
8985
9367
|
case 'unreject':
|
|
8986
9368
|
cmdUnreject(hippoRoot, args, flags);
|
|
8987
9369
|
break;
|
|
9370
|
+
case 'dormant':
|
|
9371
|
+
cmdDormant(hippoRoot, args, flags);
|
|
9372
|
+
break;
|
|
9373
|
+
case 'tokens':
|
|
9374
|
+
cmdTokens(hippoRoot, flags);
|
|
9375
|
+
break;
|
|
9376
|
+
case 'doctor': {
|
|
9377
|
+
// SAFETY: package.json always carries a string "version" (checked at release by check-manifest-versions).
|
|
9378
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf-8'));
|
|
9379
|
+
const report = runDoctor({ version: pkg.version });
|
|
9380
|
+
console.log(flags['json'] ? JSON.stringify(report, null, 2) : formatDoctor(report));
|
|
9381
|
+
if (!report.ok)
|
|
9382
|
+
process.exit(1);
|
|
9383
|
+
break;
|
|
9384
|
+
}
|
|
8988
9385
|
case 'snapshot':
|
|
8989
9386
|
cmdSnapshot(hippoRoot, args, flags);
|
|
8990
9387
|
break;
|
|
@@ -9017,6 +9414,10 @@ async function main() {
|
|
|
9017
9414
|
console.error(ARCHIVE_REASON_REQUIRED);
|
|
9018
9415
|
process.exit(1);
|
|
9019
9416
|
}
|
|
9417
|
+
if (flags['dry-run'] === true) {
|
|
9418
|
+
previewForget(hippoRoot, id, archive);
|
|
9419
|
+
break;
|
|
9420
|
+
}
|
|
9020
9421
|
const routed = await runViaServerIfAvailable(hippoRoot, async (info, apiKey) => {
|
|
9021
9422
|
try {
|
|
9022
9423
|
if (archive) {
|
|
@@ -9182,7 +9583,7 @@ async function main() {
|
|
|
9182
9583
|
requireInit(hippoRoot);
|
|
9183
9584
|
const format = flags['format'] || 'json';
|
|
9184
9585
|
const outputPath = args[0] || null;
|
|
9185
|
-
const entries = loadAllEntries(hippoRoot);
|
|
9586
|
+
const entries = loadAllEntries(hippoRoot, resolveTenantId({}));
|
|
9186
9587
|
let output;
|
|
9187
9588
|
if (format === 'markdown' || format === 'md') {
|
|
9188
9589
|
output = entries.map(e => {
|
|
@@ -9282,11 +9683,11 @@ async function main() {
|
|
|
9282
9683
|
}
|
|
9283
9684
|
const host = typeof flags['host'] === 'string' ? flags['host'] : '127.0.0.1';
|
|
9284
9685
|
const { serve } = await import('./server.js');
|
|
9285
|
-
const handle = await serve({ hippoRoot, port, host });
|
|
9686
|
+
const handle = await serve({ hippoRoot, port, host, handleSignals: true });
|
|
9286
9687
|
console.log(`hippo serve listening on ${handle.url} (pid ${process.pid})`);
|
|
9287
9688
|
console.log(`pidfile: ${path.join(hippoRoot, 'server.pid')}`);
|
|
9288
9689
|
console.log('press Ctrl+C to stop');
|
|
9289
|
-
// SIGINT/SIGTERM handlers
|
|
9690
|
+
// The SIGINT/SIGTERM handlers stop the server and exit. Hang until then.
|
|
9290
9691
|
await new Promise(() => { });
|
|
9291
9692
|
break;
|
|
9292
9693
|
}
|
|
@@ -9380,8 +9781,19 @@ async function main() {
|
|
|
9380
9781
|
process.exit(1);
|
|
9381
9782
|
}
|
|
9382
9783
|
}
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9386
|
-
|
|
9784
|
+
export async function runCli(argv = process.argv) {
|
|
9785
|
+
const { command, args, flags } = parseArgs(argv);
|
|
9786
|
+
try {
|
|
9787
|
+
await main(command, args, flags, getHippoRoot(process.cwd()));
|
|
9788
|
+
}
|
|
9789
|
+
catch (err) {
|
|
9790
|
+
console.error('Error:', err instanceof Error ? err.message : err);
|
|
9791
|
+
process.exit(1);
|
|
9792
|
+
}
|
|
9793
|
+
}
|
|
9794
|
+
// bin/hippo.js calls runCli(); this keeps `node dist/cli.js` working while an import runs nothing.
|
|
9795
|
+
const entryPath = process.argv[1];
|
|
9796
|
+
if (entryPath && fs.existsSync(entryPath) && fs.realpathSync(entryPath) === fileURLToPath(import.meta.url)) {
|
|
9797
|
+
void runCli();
|
|
9798
|
+
}
|
|
9387
9799
|
//# sourceMappingURL=cli.js.map
|