hippo-memory 0.38.0 → 0.40.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.
Files changed (112) hide show
  1. package/README.md +9 -0
  2. package/dist/api.d.ts +29 -6
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +168 -42
  5. package/dist/api.js.map +1 -1
  6. package/dist/audit.d.ts +1 -1
  7. package/dist/audit.d.ts.map +1 -1
  8. package/dist/audit.js.map +1 -1
  9. package/dist/auth.d.ts.map +1 -1
  10. package/dist/auth.js +20 -4
  11. package/dist/auth.js.map +1 -1
  12. package/dist/cli.js +101 -6
  13. package/dist/cli.js.map +1 -1
  14. package/dist/connectors/slack/deletion.d.ts +10 -0
  15. package/dist/connectors/slack/deletion.d.ts.map +1 -1
  16. package/dist/connectors/slack/deletion.js +21 -10
  17. package/dist/connectors/slack/deletion.js.map +1 -1
  18. package/dist/connectors/slack/dlq.d.ts +59 -1
  19. package/dist/connectors/slack/dlq.d.ts.map +1 -1
  20. package/dist/connectors/slack/dlq.js +204 -6
  21. package/dist/connectors/slack/dlq.js.map +1 -1
  22. package/dist/connectors/slack/idempotency.d.ts +12 -0
  23. package/dist/connectors/slack/idempotency.d.ts.map +1 -1
  24. package/dist/connectors/slack/idempotency.js +16 -0
  25. package/dist/connectors/slack/idempotency.js.map +1 -1
  26. package/dist/connectors/slack/ingest.d.ts +7 -1
  27. package/dist/connectors/slack/ingest.d.ts.map +1 -1
  28. package/dist/connectors/slack/ingest.js +40 -6
  29. package/dist/connectors/slack/ingest.js.map +1 -1
  30. package/dist/connectors/slack/signature.d.ts +7 -0
  31. package/dist/connectors/slack/signature.d.ts.map +1 -1
  32. package/dist/connectors/slack/signature.js +16 -9
  33. package/dist/connectors/slack/signature.js.map +1 -1
  34. package/dist/connectors/slack/tenant-routing.d.ts +15 -7
  35. package/dist/connectors/slack/tenant-routing.d.ts.map +1 -1
  36. package/dist/connectors/slack/tenant-routing.js +28 -8
  37. package/dist/connectors/slack/tenant-routing.js.map +1 -1
  38. package/dist/correction-latency.d.ts +36 -0
  39. package/dist/correction-latency.d.ts.map +1 -0
  40. package/dist/correction-latency.js +74 -0
  41. package/dist/correction-latency.js.map +1 -0
  42. package/dist/db.d.ts.map +1 -1
  43. package/dist/db.js +88 -1
  44. package/dist/db.js.map +1 -1
  45. package/dist/mcp/server.d.ts +7 -0
  46. package/dist/mcp/server.d.ts.map +1 -1
  47. package/dist/mcp/server.js +73 -30
  48. package/dist/mcp/server.js.map +1 -1
  49. package/dist/provenance-coverage.d.ts +18 -0
  50. package/dist/provenance-coverage.d.ts.map +1 -0
  51. package/dist/provenance-coverage.js +23 -0
  52. package/dist/provenance-coverage.js.map +1 -0
  53. package/dist/raw-archive-mirror-cleanup.d.ts +20 -0
  54. package/dist/raw-archive-mirror-cleanup.d.ts.map +1 -0
  55. package/dist/raw-archive-mirror-cleanup.js +53 -0
  56. package/dist/raw-archive-mirror-cleanup.js.map +1 -0
  57. package/dist/raw-archive.d.ts +8 -0
  58. package/dist/raw-archive.d.ts.map +1 -1
  59. package/dist/raw-archive.js +21 -7
  60. package/dist/raw-archive.js.map +1 -1
  61. package/dist/server.d.ts.map +1 -1
  62. package/dist/server.js +142 -18
  63. package/dist/server.js.map +1 -1
  64. package/dist/shared.d.ts +1 -0
  65. package/dist/shared.d.ts.map +1 -1
  66. package/dist/shared.js +6 -1
  67. package/dist/shared.js.map +1 -1
  68. package/dist/src/api.js +168 -42
  69. package/dist/src/api.js.map +1 -1
  70. package/dist/src/audit.js.map +1 -1
  71. package/dist/src/auth.js +20 -4
  72. package/dist/src/auth.js.map +1 -1
  73. package/dist/src/cli.js +101 -6
  74. package/dist/src/cli.js.map +1 -1
  75. package/dist/src/connectors/slack/deletion.js +21 -10
  76. package/dist/src/connectors/slack/deletion.js.map +1 -1
  77. package/dist/src/connectors/slack/dlq.js +204 -6
  78. package/dist/src/connectors/slack/dlq.js.map +1 -1
  79. package/dist/src/connectors/slack/idempotency.js +16 -0
  80. package/dist/src/connectors/slack/idempotency.js.map +1 -1
  81. package/dist/src/connectors/slack/ingest.js +40 -6
  82. package/dist/src/connectors/slack/ingest.js.map +1 -1
  83. package/dist/src/connectors/slack/signature.js +16 -9
  84. package/dist/src/connectors/slack/signature.js.map +1 -1
  85. package/dist/src/connectors/slack/tenant-routing.js +28 -8
  86. package/dist/src/connectors/slack/tenant-routing.js.map +1 -1
  87. package/dist/src/correction-latency.js +74 -0
  88. package/dist/src/correction-latency.js.map +1 -0
  89. package/dist/src/db.js +88 -1
  90. package/dist/src/db.js.map +1 -1
  91. package/dist/src/mcp/server.js +73 -30
  92. package/dist/src/mcp/server.js.map +1 -1
  93. package/dist/src/provenance-coverage.js +23 -0
  94. package/dist/src/provenance-coverage.js.map +1 -0
  95. package/dist/src/raw-archive-mirror-cleanup.js +53 -0
  96. package/dist/src/raw-archive-mirror-cleanup.js.map +1 -0
  97. package/dist/src/raw-archive.js +21 -7
  98. package/dist/src/raw-archive.js.map +1 -1
  99. package/dist/src/server.js +142 -18
  100. package/dist/src/server.js.map +1 -1
  101. package/dist/src/shared.js +6 -1
  102. package/dist/src/shared.js.map +1 -1
  103. package/dist/src/store.js +50 -26
  104. package/dist/src/store.js.map +1 -1
  105. package/dist/store.d.ts +24 -0
  106. package/dist/store.d.ts.map +1 -1
  107. package/dist/store.js +50 -26
  108. package/dist/store.js.map +1 -1
  109. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  110. package/extensions/openclaw-plugin/package.json +1 -1
  111. package/openclaw.plugin.json +1 -1
  112. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -53,6 +53,8 @@ import { importChatGPT, importClaude, importCursor, importGenericFile, importMar
53
53
  import { cmdCapture } from './capture.js';
54
54
  import { auditMemories, appendAuditEvent, } from './audit.js';
55
55
  import { listApiKeys, revokeApiKey } from './auth.js';
56
+ import { buildProvenanceCoverage } from './provenance-coverage.js';
57
+ import { buildCorrectionLatency } from './correction-latency.js';
56
58
  import * as api from './api.js';
57
59
  import * as client from './client.js';
58
60
  import { detectServer, removePidfile } from './server-detect.js';
@@ -64,7 +66,7 @@ import { wmPush, wmRead, wmClear, wmFlush } from './working-memory.js';
64
66
  import { multihopSearch } from './multihop.js';
65
67
  import { computeSalience } from './salience.js';
66
68
  import { computeAmbientState, renderAmbientSummary } from './ambient.js';
67
- import { listDlq } from './connectors/slack/dlq.js';
69
+ import { listDlq, replayDlqEntry } from './connectors/slack/dlq.js';
68
70
  import { backfillChannel } from './connectors/slack/backfill.js';
69
71
  import { slackHistoryFetcher } from './connectors/slack/web-client.js';
70
72
  // ---------------------------------------------------------------------------
@@ -3992,12 +3994,17 @@ function cmdAuthCreate(hippoRoot, flags) {
3992
3994
  const tenantFlag = typeof flags['tenant'] === 'string' ? flags['tenant'] : undefined;
3993
3995
  const labelFlag = typeof flags['label'] === 'string' ? flags['label'] : undefined;
3994
3996
  const asJson = Boolean(flags['json']);
3997
+ // The CLI's --tenant flag is the only legitimate cross-tenant override
3998
+ // (admin minting a key for another tenant from the local machine). It
3999
+ // flows through ctx.tenantId, NOT through opts — authCreate's opts no
4000
+ // longer accepts a tenantId field, so the HTTP layer cannot smuggle a
4001
+ // body.tenantId across.
3995
4002
  const ctx = {
3996
4003
  hippoRoot: root,
3997
- tenantId: resolveTenantId({}),
4004
+ tenantId: tenantFlag ?? resolveTenantId({}),
3998
4005
  actor: 'cli',
3999
4006
  };
4000
- const result = api.authCreate(ctx, { tenantId: tenantFlag, label: labelFlag });
4007
+ const result = api.authCreate(ctx, { label: labelFlag });
4001
4008
  if (asJson) {
4002
4009
  console.log(JSON.stringify({
4003
4010
  keyId: result.keyId,
@@ -4464,6 +4471,28 @@ function cmdSlackDlqList(hippoRoot, _flags) {
4464
4471
  closeHippoDb(db);
4465
4472
  }
4466
4473
  }
4474
+ function cmdSlackDlqReplay(hippoRoot, args, flags) {
4475
+ const idArg = args[2];
4476
+ if (!idArg) {
4477
+ console.error('Usage: hippo slack dlq replay <id> [--force]');
4478
+ process.exit(1);
4479
+ }
4480
+ const id = Number(idArg);
4481
+ if (!Number.isFinite(id) || !Number.isInteger(id) || id < 1) {
4482
+ console.error(`replay: invalid id ${idArg}`);
4483
+ process.exit(1);
4484
+ }
4485
+ const force = flags.force === true;
4486
+ const result = replayDlqEntry({ hippoRoot }, id, {
4487
+ force,
4488
+ signingSecret: process.env.SLACK_SIGNING_SECRET,
4489
+ });
4490
+ if (!result.ok) {
4491
+ console.error(`replay failed: status=${result.status} retry_count=${result.retryCount}${result.reason ? ` reason=${result.reason}` : ''}`);
4492
+ process.exit(1);
4493
+ }
4494
+ console.log(`replay ok: status=${result.status} memory_id=${result.memoryId ?? '(none)'} retry_count=${result.retryCount}`);
4495
+ }
4467
4496
  function cmdSlack(hippoRoot, args, flags) {
4468
4497
  const sub = args[0];
4469
4498
  if (sub === 'backfill') {
@@ -4474,7 +4503,11 @@ function cmdSlack(hippoRoot, args, flags) {
4474
4503
  cmdSlackDlqList(hippoRoot, flags);
4475
4504
  return;
4476
4505
  }
4477
- console.error('Usage: hippo slack <backfill|dlq list> [...]');
4506
+ if (sub === 'dlq' && args[1] === 'replay') {
4507
+ cmdSlackDlqReplay(hippoRoot, args, flags);
4508
+ return;
4509
+ }
4510
+ console.error('Usage: hippo slack <backfill|dlq list|dlq replay <id> [--force]> [...]');
4478
4511
  process.exit(1);
4479
4512
  }
4480
4513
  function printUsage() {
@@ -4590,6 +4623,11 @@ Commands:
4590
4623
  --threshold <n> Overlap threshold 0-1 (default: 0.7)
4591
4624
  status Show memory health stats
4592
4625
  audit [--fix] Check memory quality (--fix removes junk)
4626
+ provenance Provenance coverage gate for kind='raw' rows
4627
+ --json Output as JSON
4628
+ --strict Exit non-zero when coverage < 100%
4629
+ correction-latency Wall-clock lag from receipt to supersession (p50/p95/max)
4630
+ --json Output as JSON
4593
4631
  outcome Apply feedback to last recall
4594
4632
  --good Memories were helpful
4595
4633
  --bad Memories were irrelevant
@@ -4977,6 +5015,62 @@ async function main() {
4977
5015
  }
4978
5016
  break;
4979
5017
  }
5018
+ case 'correction-latency': {
5019
+ requireInit(hippoRoot);
5020
+ const entries = loadAllEntries(hippoRoot);
5021
+ const report = buildCorrectionLatency(entries);
5022
+ if (flags['json']) {
5023
+ console.log(JSON.stringify(report, null, 2));
5024
+ }
5025
+ else if (report.count === 0) {
5026
+ console.log('No supersessions found. Correction latency is undefined.');
5027
+ }
5028
+ else {
5029
+ const fmt = (ms) => {
5030
+ if (ms === null)
5031
+ return 'n/a';
5032
+ if (ms < 1000)
5033
+ return `${ms}ms`;
5034
+ if (ms < 60_000)
5035
+ return `${(ms / 1000).toFixed(1)}s`;
5036
+ if (ms < 3_600_000)
5037
+ return `${(ms / 60_000).toFixed(1)}m`;
5038
+ return `${(ms / 3_600_000).toFixed(1)}h`;
5039
+ };
5040
+ console.log(`Corrections: ${report.count} total (${report.extractionCount} extraction-driven, ${report.manualCount} manual)`);
5041
+ console.log(`Latency p50: ${fmt(report.p50Ms)}, p95: ${fmt(report.p95Ms)}, max: ${fmt(report.maxMs)}`);
5042
+ if (report.extractionCount === 0 && report.manualCount > 0) {
5043
+ console.log(`\nAll ${report.manualCount} corrections were manual supersedes: no measurable observation lag.`);
5044
+ console.log(`To measure latency, route corrections through extraction (set new.extracted_from to the raw receipt).`);
5045
+ }
5046
+ }
5047
+ break;
5048
+ }
5049
+ case 'provenance': {
5050
+ requireInit(hippoRoot);
5051
+ const entries = loadAllEntries(hippoRoot);
5052
+ const coverage = buildProvenanceCoverage(entries);
5053
+ if (flags['json']) {
5054
+ console.log(JSON.stringify(coverage, null, 2));
5055
+ }
5056
+ else if (coverage.rawTotal === 0) {
5057
+ console.log('No kind=raw memories present. Coverage gate trivially satisfied.');
5058
+ }
5059
+ else {
5060
+ const pct = (coverage.coverage * 100).toFixed(1);
5061
+ console.log(`Provenance coverage: ${coverage.rawWithEnvelope}/${coverage.rawTotal} raw rows envelope-complete (${pct}%)`);
5062
+ if (coverage.gaps.length > 0) {
5063
+ console.log(`\nGaps:`);
5064
+ for (const g of coverage.gaps) {
5065
+ console.log(` ${g.id}: missing ${g.missing.join(', ')}`);
5066
+ }
5067
+ }
5068
+ }
5069
+ if (flags['strict'] && coverage.coverage < 1) {
5070
+ process.exit(1);
5071
+ }
5072
+ break;
5073
+ }
4980
5074
  case 'status':
4981
5075
  cmdStatus(hippoRoot);
4982
5076
  break;
@@ -5106,13 +5200,14 @@ async function main() {
5106
5200
  else if (shareId) {
5107
5201
  requireInit(hippoRoot);
5108
5202
  const force = Boolean(flags['force']);
5109
- const result = shareMemory(hippoRoot, shareId, { force });
5203
+ const tenantId = resolveTenantId({});
5204
+ const result = shareMemory(hippoRoot, shareId, { force, tenantId });
5110
5205
  if (result) {
5111
5206
  console.log(`Shared [${result.id}] to global store.`);
5112
5207
  console.log(` Source: ${result.source}`);
5113
5208
  }
5114
5209
  else {
5115
- const entry = readEntry(hippoRoot, shareId);
5210
+ const entry = readEntry(hippoRoot, shareId, tenantId);
5116
5211
  if (entry) {
5117
5212
  const score = transferScore(entry);
5118
5213
  console.log(`Transfer score too low (${fmt(score)}). This memory looks project-specific.`);