hippo-memory 1.38.2 → 1.38.7

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.
Files changed (50) hide show
  1. package/README.md +18 -1
  2. package/dist/api.d.ts +4 -14
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +18 -2
  5. package/dist/api.js.map +1 -1
  6. package/dist/benchmarks/e1.3/scenarios.json +2587 -0
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +57 -59
  9. package/dist/cli.js.map +1 -1
  10. package/dist/client.d.ts +7 -0
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +15 -1
  13. package/dist/client.js.map +1 -1
  14. package/dist/connectors/slack/backfill.js +1 -1
  15. package/dist/consolidate.d.ts.map +1 -1
  16. package/dist/consolidate.js +11 -22
  17. package/dist/consolidate.js.map +1 -1
  18. package/dist/db.d.ts.map +1 -1
  19. package/dist/db.js +18 -3
  20. package/dist/db.js.map +1 -1
  21. package/dist/replay.d.ts +1 -1
  22. package/dist/replay.d.ts.map +1 -1
  23. package/dist/replay.js +5 -3
  24. package/dist/replay.js.map +1 -1
  25. package/dist/search.d.ts.map +1 -1
  26. package/dist/search.js +3 -1
  27. package/dist/search.js.map +1 -1
  28. package/dist/src/api.js +18 -2
  29. package/dist/src/api.js.map +1 -1
  30. package/dist/src/cli.js +57 -59
  31. package/dist/src/cli.js.map +1 -1
  32. package/dist/src/client.js +15 -1
  33. package/dist/src/client.js.map +1 -1
  34. package/dist/src/connectors/slack/backfill.js +1 -1
  35. package/dist/src/consolidate.js +11 -22
  36. package/dist/src/consolidate.js.map +1 -1
  37. package/dist/src/db.js +18 -3
  38. package/dist/src/db.js.map +1 -1
  39. package/dist/src/replay.js +5 -3
  40. package/dist/src/replay.js.map +1 -1
  41. package/dist/src/search.js +3 -1
  42. package/dist/src/search.js.map +1 -1
  43. package/dist/src/version.js +1 -1
  44. package/dist/version.d.ts +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist-ui/index.html +12 -12
  47. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  48. package/extensions/openclaw-plugin/package.json +1 -1
  49. package/openclaw.plugin.json +1 -1
  50. package/package.json +1 -1
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AA2BH,OAAO,EASL,WAAW,EAEZ,MAAM,aAAa,CAAC;AA6GrB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA4ChC,kFAAkF;AAClF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AA4ID,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;AA6xED;;;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;AA2jGD,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,CA6BN"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AA2BH,OAAO,EASL,WAAW,EAEZ,MAAM,aAAa,CAAC;AA4GrB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA4ChC,kFAAkF;AAClF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AA4ID,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;AA6xED;;;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;AA4iGD,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,CA6BN"}
package/dist/cli.js CHANGED
@@ -36,7 +36,6 @@ import { fileURLToPath } from 'node:url';
36
36
  import { execFileSync, execSync, spawn } from 'child_process';
37
37
  import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, isCodexWrapperInstalled, repairCodexWrapperIfInstalled, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
38
38
  import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, computeSchemaFit, Layer, } from './memory.js';
39
- import { resolveProjectIdentity } from './project-identity.js';
40
39
  import { detectSecret } from './secret-detect.js';
41
40
  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, RECALL_DEFAULT_DENY_SCOPES, } from './store.js';
42
41
  import { rejectValue, unrejectValue, listRejectionsForTenant } from './reject-flow.js';
@@ -115,7 +114,7 @@ import { graphExpandRecall, MAX_HOPS, DEFAULT_MAX_NEIGHBORS } from './graph-reca
115
114
  import { DEFAULT_GRAPH_STREAM_WEIGHT } from './graph-stream.js';
116
115
  import { getReranker } from './rerankers/index.js';
117
116
  import { computeSalience } from './salience.js';
118
- import { computeAmbientState, renderAmbientSummary } from './ambient.js';
117
+ import { renderAmbientSummary } from './ambient.js';
119
118
  import { validateOwner, isStrictOwnerEnv } from './owner-validation.js';
120
119
  import { pruneAuditLog, parseOlderThanFlag } from './audit-prune.js';
121
120
  import { listDlq, replayDlqEntry } from './connectors/slack/dlq.js';
@@ -2868,7 +2867,7 @@ function cmdCompactResume(hippoRoot, stdinText) {
2868
2867
  * immediately. The child writes to the log file and survives TUI teardown;
2869
2868
  * the next SessionStart reads the log via `hippo last-sleep`.
2870
2869
  */
2871
- function cmdSessionEnd(hippoRoot, flags) {
2870
+ async function cmdSessionEnd(hippoRoot, flags) {
2872
2871
  const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : null;
2873
2872
  // Read stdin synchronously. The SessionEnd hook payload carries
2874
2873
  // `transcript_path` as JSON; we extract it here and pass it to the worker
@@ -2915,7 +2914,7 @@ function cmdSessionEnd(hippoRoot, flags) {
2915
2914
  // --session-id (both are stdin-derived, argv-only for the child), so in
2916
2915
  // this fallback capture auto-discovers the transcript and the DF1
2917
2916
  // snapshot close no-ops — the ambient freshness bound is the backstop.
2918
- cmdSessionEndWorker(hippoRoot, flags);
2917
+ await cmdSessionEndWorker(hippoRoot, flags);
2919
2918
  return;
2920
2919
  }
2921
2920
  }
@@ -2924,9 +2923,9 @@ function cmdSessionEnd(hippoRoot, flags) {
2924
2923
  * `__session-end-worker` subcommand (not user-facing). Failures in one stage
2925
2924
  * do not block the other.
2926
2925
  */
2927
- function cmdSessionEndWorker(hippoRoot, flags) {
2926
+ async function cmdSessionEndWorker(hippoRoot, flags) {
2928
2927
  try {
2929
- cmdSleep(hippoRoot, flags);
2928
+ await cmdSleep(hippoRoot, flags);
2930
2929
  }
2931
2930
  catch {
2932
2931
  // sleep errors are already tee'd to the log file via cmdSleep's
@@ -3035,7 +3034,7 @@ function cmdCodexRun(hippoRoot, args) {
3035
3034
  console.error(`Failed to launch Codex: ${err.message}`);
3036
3035
  process.exit(1);
3037
3036
  });
3038
- child.on('exit', (code, signal) => {
3037
+ child.on('exit', async (code, signal) => {
3039
3038
  const workerArgs = [
3040
3039
  process.argv[1],
3041
3040
  '__codex-session-end-worker',
@@ -3060,13 +3059,19 @@ function cmdCodexRun(hippoRoot, args) {
3060
3059
  }
3061
3060
  catch {
3062
3061
  // Fall back to the inline path if the detached worker cannot be created.
3063
- cmdCodexSessionEndWorker(hippoRoot, {
3064
- 'codex-home': path.dirname(historyPath),
3065
- 'history-path': historyPath,
3066
- 'start-offset': String(startOffsetBytes),
3067
- 'started-at': String(startedAtMs),
3068
- 'log-file': metadata.logFile,
3069
- });
3062
+ // Awaited so the sleep write can't be killed by the exit calls below.
3063
+ try {
3064
+ await cmdCodexSessionEndWorker(hippoRoot, {
3065
+ 'codex-home': path.dirname(historyPath),
3066
+ 'history-path': historyPath,
3067
+ 'start-offset': String(startOffsetBytes),
3068
+ 'started-at': String(startedAtMs),
3069
+ 'log-file': metadata.logFile,
3070
+ });
3071
+ }
3072
+ catch {
3073
+ // cmdCodexSessionEndWorker already fail-softs internally; this is belt-and-braces.
3074
+ }
3070
3075
  }
3071
3076
  if (signal) {
3072
3077
  try {
@@ -3080,10 +3085,10 @@ function cmdCodexRun(hippoRoot, args) {
3080
3085
  process.exit(code ?? 0);
3081
3086
  });
3082
3087
  }
3083
- function cmdCodexSessionEndWorker(hippoRoot, flags) {
3088
+ async function cmdCodexSessionEndWorker(hippoRoot, flags) {
3084
3089
  const logFile = typeof flags['log-file'] === 'string' ? flags['log-file'] : undefined;
3085
3090
  try {
3086
- cmdSleep(hippoRoot, logFile ? { 'log-file': logFile } : {});
3091
+ await cmdSleep(hippoRoot, logFile ? { 'log-file': logFile } : {});
3087
3092
  }
3088
3093
  catch {
3089
3094
  // sleep errors are already written via cmdSleep
@@ -3314,6 +3319,8 @@ function cmdOutcome(hippoRoot, flags) {
3314
3319
  }
3315
3320
  console.log(`Applied ${good ? 'positive' : 'negative'} outcome to ${updated} memor${updated === 1 ? 'y' : 'ies'}`);
3316
3321
  }
3322
+ // Shared between the forget dispatch and cmdForget so the message can't drift.
3323
+ const ARCHIVE_REASON_REQUIRED = 'hippo forget --archive requires --reason "<why>" (recorded on the archive).';
3317
3324
  function cmdForget(hippoRoot, id, flags) {
3318
3325
  requireInit(hippoRoot);
3319
3326
  const ctx = {
@@ -3327,12 +3334,11 @@ function cmdForget(hippoRoot, id, flags) {
3327
3334
  if (flags['archive'] === true) {
3328
3335
  const reason = typeof flags['reason'] === 'string' ? flags['reason'] : null;
3329
3336
  if (!reason) {
3330
- console.error('hippo forget --archive requires --reason "<why>" (recorded on the archive).');
3337
+ console.error(ARCHIVE_REASON_REQUIRED);
3331
3338
  process.exit(1);
3332
3339
  }
3333
3340
  try {
3334
3341
  api.archiveRaw(ctx, id, reason);
3335
- updateStats(hippoRoot, { forgotten: 1 });
3336
3342
  console.log(`Archived ${id}`);
3337
3343
  }
3338
3344
  catch (err) {
@@ -5590,30 +5596,8 @@ async function cmdContext(hippoRoot, args, flags, stdinText) {
5590
5596
  printContextMarkdown(renderItems, result.tokens, framing);
5591
5597
  }
5592
5598
  printCrossProjectSection(crossEntries);
5593
- // Ambient state summary (CLI-side: api.getContext doesn't load all entries
5594
- // post-selection, so we re-load here for the landscape summary).
5595
- const ambientConfig = loadConfig(hippoRoot);
5596
- if (ambientConfig.ambient.enabled && !pinnedOnly) {
5597
- const tenantId = ctx.tenantId;
5598
- const globalRoot = getGlobalRoot();
5599
- const hasGlobalForAmbient = isInitialized(globalRoot);
5600
- // v39: the landscape summary must reflect the same admission policy as
5601
- // the injected entries - otherwise excluded rows leak back in as
5602
- // aggregate signal (codex P2-13).
5603
- const isolationOff = ambientConfig.contextProjectIsolation === false;
5604
- const ambientCurrentName = resolveProjectIdentity(process.cwd()).name;
5605
- const ambientAdmit = (e) => api.ambientAdmitEntry(e, ambientCurrentName, crossProject || isolationOff);
5606
- const localForAmbient = isInitialized(hippoRoot)
5607
- ? loadAllEntries(hippoRoot, tenantId).filter(e => !e.superseded_by).filter(ambientAdmit)
5608
- : [];
5609
- const globalForAmbient = hasGlobalForAmbient
5610
- ? loadAllEntries(globalRoot, tenantId).filter(e => !e.superseded_by).filter(ambientAdmit)
5611
- : [];
5612
- const allForAmbient = [...localForAmbient, ...globalForAmbient];
5613
- if (allForAmbient.length > 0) {
5614
- const ambientState = computeAmbientState(allForAmbient);
5615
- console.log(`\n${renderAmbientSummary(ambientState)}`);
5616
- }
5599
+ if (result.ambientState) {
5600
+ console.log(`\n${renderAmbientSummary(result.ambientState)}`);
5617
5601
  }
5618
5602
  }
5619
5603
  }
@@ -8247,10 +8231,10 @@ async function main() {
8247
8231
  cmdLastSleep(flags);
8248
8232
  break;
8249
8233
  case 'session-end':
8250
- cmdSessionEnd(hippoRoot, flags);
8234
+ await cmdSessionEnd(hippoRoot, flags);
8251
8235
  break;
8252
8236
  case '__session-end-worker':
8253
- cmdSessionEndWorker(hippoRoot, flags);
8237
+ await cmdSessionEndWorker(hippoRoot, flags);
8254
8238
  break;
8255
8239
  case 'pre-compact': {
8256
8240
  // Same TTY guard as `capture --last-session`: skip reading stdin when
@@ -8287,7 +8271,7 @@ async function main() {
8287
8271
  cmdCodexRun(hippoRoot, args);
8288
8272
  break;
8289
8273
  case '__codex-session-end-worker':
8290
- cmdCodexSessionEndWorker(hippoRoot, flags);
8274
+ await cmdCodexSessionEndWorker(hippoRoot, flags);
8291
8275
  break;
8292
8276
  case 'dedup':
8293
8277
  cmdDedup(hippoRoot, flags);
@@ -8446,23 +8430,37 @@ async function main() {
8446
8430
  console.error('Please provide a memory ID.');
8447
8431
  process.exit(1);
8448
8432
  }
8449
- // A3: --archive is a direct-DB operation (raw archival via archiveRaw);
8450
- // the HTTP forget route does not carry it, so archive requests always
8451
- // take the direct path rather than silently no-op'ing over a server.
8452
- if (flags['archive'] !== true) {
8453
- const routed = await runViaServerIfAvailable(hippoRoot, async (info, apiKey) => {
8454
- try {
8433
+ // Archive has its own HTTP route (POST /v1/memories/:id/archive); route
8434
+ // both branches the same way the direct path does.
8435
+ const archive = flags['archive'] === true;
8436
+ const reason = typeof flags['reason'] === 'string' ? flags['reason'] : null;
8437
+ if (archive && !reason) {
8438
+ console.error(ARCHIVE_REASON_REQUIRED);
8439
+ process.exit(1);
8440
+ }
8441
+ const routed = await runViaServerIfAvailable(hippoRoot, async (info, apiKey) => {
8442
+ try {
8443
+ if (archive) {
8444
+ await client.archiveRaw(info.url, apiKey, id, reason);
8445
+ console.log(`Archived ${id}`);
8446
+ }
8447
+ else {
8455
8448
  await client.forget(info.url, apiKey, id);
8456
8449
  console.log(`Forgot ${id}`);
8457
8450
  }
8458
- catch (err) {
8459
- console.error(err.message);
8460
- process.exit(1);
8461
- }
8462
- });
8463
- if (routed)
8464
- break;
8465
- }
8451
+ }
8452
+ catch (err) {
8453
+ // A server that died after the health probe is the caller's stale
8454
+ // pidfile fallback to handle, not an error to report to the user.
8455
+ if (client.isConnectionRefused(err))
8456
+ throw err;
8457
+ const msg = err instanceof Error ? err.message : String(err);
8458
+ console.error(archive ? `Could not archive ${id}: ${msg}` : msg);
8459
+ process.exit(1);
8460
+ }
8461
+ });
8462
+ if (routed)
8463
+ break;
8466
8464
  cmdForget(hippoRoot, id, flags);
8467
8465
  break;
8468
8466
  }