hippo-memory 1.42.1 → 1.43.1

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 CHANGED
@@ -43,8 +43,9 @@ Numbers, not adjectives. Every claim links to the benchmark or the test that pro
43
43
 
44
44
  - **Sequential Learning Benchmark.** [benchmarks/sequential-learning/](benchmarks/sequential-learning/). 50 tasks, 10 buried traps. Measures whether agents learn from past mistakes, not just retrieve text. v0.11.0 informal magnitude RETRACTED v1.7.9; mechanism remains shipped. See [CHANGELOG.md](./CHANGELOG.md) v1.7.9 entry.
45
45
  - **R@5 = 74.0%** on [LongMemEval](benchmarks/longmemeval/). 500-question industry retrieval benchmark, BM25 only, no embeddings.
46
+ - **R@1 0.41 to 0.62 with `hippo recall "<query>" --reranker jev`** on a 300-query developer store ([full eval](docs/evals/2026-09-19-jev-reranker.md)). The opt-in [TypeSafe Jev](https://typesafe.ai) reranker, off by default, about 0.0004 USD a recall. 2000-draw paired bootstrap; the margin held in 20 of 20 seeds and a permutation null reached it in 0 of 200 runs. Ranking only: three graded tests did **not** show a better answer rate than the free local cross-encoder, and that negative result is in the same doc. What it buys today is a shorter context, 2 memories ranked by Jev answering as well as 5 without it.
46
47
  - **10 of 10 incident scenarios beat transcript replay** on a staged Slack corpus ([benchmarks/e1.3/](benchmarks/e1.3/)). Recall surfaces the cause faster than scrolling the last N messages.
47
- - **0 outbound HTTP** on the 1000-event ingestion smoke. Proven by a `globalThis.fetch` spy that throws on call, not a hardcoded zero.
48
+ - **0 outbound HTTP** on the 1000-event ingestion smoke. Proven by a `globalThis.fetch` spy that throws on call, not a hardcoded zero. The default recall path makes no network call either; the opt-in Jev reranker above is the one switch that does.
48
49
  - **926 tests, real DB, zero mocks.** Project rule. The one mocks-vs-prod divergence that bit us early is now the constraint that kept the next ten releases honest.
49
50
  - **dlPFC goal-conditioned cluster discrimination, 3/3 queries pass** — full goal stack with policy weighting and lifespan-windowed outcome propagation. Per-goal lift on a 3-cluster fixture where BM25 alone cannot discriminate; deterministic test in [`benchmarks/micro/results/b3-depth.json`](benchmarks/micro/results/b3-depth.json).
50
51
 
@@ -633,7 +634,7 @@ hippo watch "npm run build"
633
634
  | `hippo wm read --scope <s>` | Read working memory entries |
634
635
  | `hippo wm clear --scope <s>` | Clear working memory |
635
636
  | `hippo wm flush --scope <s>` | Flush working memory (session end) |
636
- | `hippo dashboard` | Open web dashboard at localhost:3333 |
637
+ | `hippo dashboard` | Open web dashboard at localhost:3333 (memory map and card board) |
637
638
  | `hippo dashboard --port <n>` | Use custom port |
638
639
  | `hippo mcp` | Start MCP server (stdio transport) |
639
640
 
@@ -0,0 +1,14 @@
1
+ import type { Card, CardComment, CardRun } from './card.js';
2
+ import type { SessionHandoff } from './handoff.js';
3
+ import { loadCardDeps } from './store.js';
4
+ /** A card plus everything `hippo card show` prints about it. */
5
+ export interface CardDetail {
6
+ card: Card;
7
+ deps: ReturnType<typeof loadCardDeps>;
8
+ runs: CardRun[];
9
+ comments: CardComment[];
10
+ handoff: SessionHandoff | null;
11
+ }
12
+ /** Loads the detail behind `hippo card show` and `GET /api/cards/:id` (null when the tenant has no such card); five separate reads, so a write landing between them can show a mixed view, as `card show` always could. */
13
+ export declare function loadCardDetail(hippoRoot: string, tenantId: string, id: string): CardDetail | null;
14
+ //# sourceMappingURL=card-detail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-detail.d.ts","sourceRoot":"","sources":["../src/card-detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAA8B,YAAY,EAA0C,MAAM,YAAY,CAAC;AAE9G,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACtC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;CAChC;AAED,2NAA2N;AAC3N,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAUjG"}
@@ -0,0 +1,15 @@
1
+ import { loadCard, loadCardComments, loadCardDeps, loadCardRuns, loadLatestHandoffForCard } from './store.js';
2
+ /** Loads the detail behind `hippo card show` and `GET /api/cards/:id` (null when the tenant has no such card); five separate reads, so a write landing between them can show a mixed view, as `card show` always could. */
3
+ export function loadCardDetail(hippoRoot, tenantId, id) {
4
+ const card = loadCard(hippoRoot, tenantId, id);
5
+ if (!card)
6
+ return null;
7
+ return {
8
+ card,
9
+ deps: loadCardDeps(hippoRoot, tenantId, id),
10
+ runs: loadCardRuns(hippoRoot, tenantId, id),
11
+ comments: loadCardComments(hippoRoot, tenantId, id),
12
+ handoff: loadLatestHandoffForCard(hippoRoot, tenantId, id),
13
+ };
14
+ }
15
+ //# sourceMappingURL=card-detail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-detail.js","sourceRoot":"","sources":["../src/card-detail.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAW9G,2NAA2N;AAC3N,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,QAAgB,EAAE,EAAU;IAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC;QAC3C,IAAI,EAAE,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC;QAC3C,QAAQ,EAAE,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC;QACnD,OAAO,EAAE,wBAAwB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AA2BH,OAAO,EAWL,WAAW,EAEZ,MAAM,aAAa,CAAC;AA6HrB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA4ChC,kFAAkF;AAClF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAuJD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;CAAE,CAwCjI;AAqxED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,MAAqB,GAAG,MAAM,CAyF3F;AAyGD;;;GAGG;AACH,oHAAoH;AACpH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAuD/D;AAsgHD,oHAAoH;AACpH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,EACtF,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAkB,GAC1B,IAAI,CA8BN"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AA2BH,OAAO,EAWL,WAAW,EAEZ,MAAM,aAAa,CAAC;AA2HrB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA4ChC,kFAAkF;AAClF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAuJD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAA;CAAE,CAwCjI;AAqxED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,MAAqB,GAAG,MAAM,CAyF3F;AAyGD;;;GAGG;AACH,oHAAoH;AACpH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAuD/D;AA6/GD,oHAAoH;AACpH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,EACtF,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAkB,GAC1B,IAAI,CA8BN"}
package/dist/cli.js CHANGED
@@ -38,11 +38,12 @@ 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, loadCardDeps, loadCardRuns, loadCardComments, claimCard, heartbeatCard, blockCard, reviewCard, completeCard, reclaimExpiredCards, addCardComment, loadLatestHandoffForCard, } from './store.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';
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
+ import { loadCardDetail } from './card-detail.js';
46
47
  import { passesScopeFilterForRecall } from './recall-scope.js';
47
48
  import { markRetrieved, hybridSearch, physicsSearch, explainMatch, textOverlap, tokenize as tokenizeQuery } from './search.js';
48
49
  import { compareEntryIdentity } from './compare.js';
@@ -4029,7 +4030,8 @@ function cmdHandoff(hippoRoot, args, flags) {
4029
4030
  }
4030
4031
  // Mirrors ARCHIVE_REASON_REQUIRED so the block message can't drift from its usage line.
4031
4032
  const CARD_BLOCK_REASON_REQUIRED = 'hippo card block <id> requires --reason "<why>" (recorded as a comment).';
4032
- function printCard(hippoRoot, tenantId, card) {
4033
+ function printCard(detail) {
4034
+ const { card, deps, runs, comments, handoff } = detail;
4033
4035
  console.log(`## Card ${card.id}\n`);
4034
4036
  console.log(`- Title: ${card.title}`);
4035
4037
  console.log(`- Status: ${card.status}`);
@@ -4046,26 +4048,22 @@ function printCard(hippoRoot, tenantId, card) {
4046
4048
  if (card.budget !== null)
4047
4049
  console.log(`- Budget: ${card.budget}`);
4048
4050
  console.log(`- Updated: ${card.updatedAt}`);
4049
- const deps = loadCardDeps(hippoRoot, tenantId, card.id);
4050
4051
  if (deps.parents.length > 0)
4051
4052
  console.log(`- Parents: ${deps.parents.join(', ')}`);
4052
4053
  if (deps.children.length > 0)
4053
4054
  console.log(`- Children: ${deps.children.join(', ')}`);
4054
- const runs = loadCardRuns(hippoRoot, tenantId, card.id);
4055
4055
  if (runs.length > 0) {
4056
4056
  console.log('\n### Runs');
4057
4057
  for (const run of runs) {
4058
4058
  console.log(`- run ${run.id}: ${run.runtime} started ${run.started}${run.ended ? ` ended ${run.ended} (${run.outcome})` : ' (open)'}`);
4059
4059
  }
4060
4060
  }
4061
- const comments = loadCardComments(hippoRoot, tenantId, card.id);
4062
4061
  if (comments.length > 0) {
4063
4062
  console.log('\n### Comments');
4064
4063
  for (const comment of comments) {
4065
4064
  console.log(`- [${comment.createdAt}] ${comment.author}: ${comment.body}`);
4066
4065
  }
4067
4066
  }
4068
- const handoff = loadLatestHandoffForCard(hippoRoot, tenantId, card.id);
4069
4067
  if (handoff) {
4070
4068
  console.log('\n### Latest handoff');
4071
4069
  console.log(`- Session: ${handoff.sessionId}, updated ${handoff.updatedAt}`);
@@ -4172,22 +4170,16 @@ function cmdCard(hippoRoot, args, flags) {
4172
4170
  console.error('Usage: hippo card show <id> [--json]');
4173
4171
  process.exit(1);
4174
4172
  }
4175
- const card = loadCard(hippoRoot, tenantId, id);
4176
- if (!card) {
4173
+ const detail = loadCardDetail(hippoRoot, tenantId, id);
4174
+ if (!detail) {
4177
4175
  console.error(`No card found with id ${id}.`);
4178
4176
  process.exit(1);
4179
4177
  }
4180
4178
  if (flags['json']) {
4181
- console.log(JSON.stringify({
4182
- card,
4183
- deps: loadCardDeps(hippoRoot, tenantId, id),
4184
- runs: loadCardRuns(hippoRoot, tenantId, id),
4185
- comments: loadCardComments(hippoRoot, tenantId, id),
4186
- handoff: loadLatestHandoffForCard(hippoRoot, tenantId, id),
4187
- }, null, 2));
4179
+ console.log(JSON.stringify(detail, null, 2));
4188
4180
  return;
4189
4181
  }
4190
- printCard(hippoRoot, tenantId, card);
4182
+ printCard(detail);
4191
4183
  return;
4192
4184
  }
4193
4185
  if (subcommand === 'list') {