hippo-memory 0.36.0 → 0.38.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 (205) hide show
  1. package/README.md +62 -254
  2. package/dist/api.d.ts +20 -0
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +23 -3
  5. package/dist/api.js.map +1 -1
  6. package/dist/benchmarks/e1.3/incident-recall-eval.js +74 -0
  7. package/dist/benchmarks/e1.3/incident-recall-eval.js.map +1 -0
  8. package/dist/benchmarks/e1.3/scenarios.json +2587 -0
  9. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +102 -0
  10. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +1 -0
  11. package/dist/cli.js +449 -0
  12. package/dist/cli.js.map +1 -1
  13. package/dist/connectors/slack/backfill.d.ts +42 -0
  14. package/dist/connectors/slack/backfill.d.ts.map +1 -0
  15. package/dist/connectors/slack/backfill.js +76 -0
  16. package/dist/connectors/slack/backfill.js.map +1 -0
  17. package/dist/connectors/slack/deletion.d.ts +14 -0
  18. package/dist/connectors/slack/deletion.d.ts.map +1 -0
  19. package/dist/connectors/slack/deletion.js +46 -0
  20. package/dist/connectors/slack/deletion.js.map +1 -0
  21. package/dist/connectors/slack/dlq.d.ts +21 -0
  22. package/dist/connectors/slack/dlq.d.ts.map +1 -0
  23. package/dist/connectors/slack/dlq.js +23 -0
  24. package/dist/connectors/slack/dlq.js.map +1 -0
  25. package/dist/connectors/slack/idempotency.d.ts +5 -0
  26. package/dist/connectors/slack/idempotency.d.ts.map +1 -0
  27. package/dist/connectors/slack/idempotency.js +13 -0
  28. package/dist/connectors/slack/idempotency.js.map +1 -0
  29. package/dist/connectors/slack/ingest.d.ts +27 -0
  30. package/dist/connectors/slack/ingest.d.ts.map +1 -0
  31. package/dist/connectors/slack/ingest.js +48 -0
  32. package/dist/connectors/slack/ingest.js.map +1 -0
  33. package/dist/connectors/slack/ratelimit.d.ts +9 -0
  34. package/dist/connectors/slack/ratelimit.d.ts.map +1 -0
  35. package/dist/connectors/slack/ratelimit.js +18 -0
  36. package/dist/connectors/slack/ratelimit.js.map +1 -0
  37. package/dist/connectors/slack/scope.d.ts +16 -0
  38. package/dist/connectors/slack/scope.d.ts.map +1 -0
  39. package/dist/connectors/slack/scope.js +13 -0
  40. package/dist/connectors/slack/scope.js.map +1 -0
  41. package/dist/connectors/slack/signature.d.ts +12 -0
  42. package/dist/connectors/slack/signature.d.ts.map +1 -0
  43. package/dist/connectors/slack/signature.js +20 -0
  44. package/dist/connectors/slack/signature.js.map +1 -0
  45. package/dist/connectors/slack/tenant-routing.d.ts +13 -0
  46. package/dist/connectors/slack/tenant-routing.d.ts.map +1 -0
  47. package/dist/connectors/slack/tenant-routing.js +17 -0
  48. package/dist/connectors/slack/tenant-routing.js.map +1 -0
  49. package/dist/connectors/slack/transform.d.ts +20 -0
  50. package/dist/connectors/slack/transform.d.ts.map +1 -0
  51. package/dist/connectors/slack/transform.js +31 -0
  52. package/dist/connectors/slack/transform.js.map +1 -0
  53. package/dist/connectors/slack/types.d.ts +35 -0
  54. package/dist/connectors/slack/types.d.ts.map +1 -0
  55. package/dist/connectors/slack/types.js +23 -0
  56. package/dist/connectors/slack/types.js.map +1 -0
  57. package/dist/connectors/slack/web-client.d.ts +12 -0
  58. package/dist/connectors/slack/web-client.d.ts.map +1 -0
  59. package/dist/connectors/slack/web-client.js +43 -0
  60. package/dist/connectors/slack/web-client.js.map +1 -0
  61. package/dist/db.d.ts.map +1 -1
  62. package/dist/db.js +105 -1
  63. package/dist/db.js.map +1 -1
  64. package/dist/goals.d.ts +73 -0
  65. package/dist/goals.d.ts.map +1 -0
  66. package/dist/goals.js +227 -0
  67. package/dist/goals.js.map +1 -0
  68. package/dist/importers.js +3 -3
  69. package/dist/importers.js.map +1 -1
  70. package/dist/mcp/server.js +1 -1
  71. package/dist/server.d.ts.map +1 -1
  72. package/dist/server.js +174 -2
  73. package/dist/server.js.map +1 -1
  74. package/dist/src/ambient.js +147 -0
  75. package/dist/src/ambient.js.map +1 -0
  76. package/dist/src/api.js +343 -0
  77. package/dist/src/api.js.map +1 -0
  78. package/dist/src/audit.js +152 -0
  79. package/dist/src/audit.js.map +1 -0
  80. package/dist/src/auth.js +65 -0
  81. package/dist/src/auth.js.map +1 -0
  82. package/dist/src/autolearn.js +143 -0
  83. package/dist/src/autolearn.js.map +1 -0
  84. package/dist/src/capture.js +512 -0
  85. package/dist/src/capture.js.map +1 -0
  86. package/dist/src/cli.js +5338 -0
  87. package/dist/src/cli.js.map +1 -0
  88. package/dist/src/client.js +181 -0
  89. package/dist/src/client.js.map +1 -0
  90. package/dist/src/config.js +108 -0
  91. package/dist/src/config.js.map +1 -0
  92. package/dist/src/connectors/slack/backfill.js +76 -0
  93. package/dist/src/connectors/slack/backfill.js.map +1 -0
  94. package/dist/src/connectors/slack/deletion.js +46 -0
  95. package/dist/src/connectors/slack/deletion.js.map +1 -0
  96. package/dist/src/connectors/slack/dlq.js +23 -0
  97. package/dist/src/connectors/slack/dlq.js.map +1 -0
  98. package/dist/src/connectors/slack/idempotency.js +13 -0
  99. package/dist/src/connectors/slack/idempotency.js.map +1 -0
  100. package/dist/src/connectors/slack/ingest.js +48 -0
  101. package/dist/src/connectors/slack/ingest.js.map +1 -0
  102. package/dist/src/connectors/slack/ratelimit.js +18 -0
  103. package/dist/src/connectors/slack/ratelimit.js.map +1 -0
  104. package/dist/src/connectors/slack/scope.js +13 -0
  105. package/dist/src/connectors/slack/scope.js.map +1 -0
  106. package/dist/src/connectors/slack/signature.js +20 -0
  107. package/dist/src/connectors/slack/signature.js.map +1 -0
  108. package/dist/src/connectors/slack/tenant-routing.js +17 -0
  109. package/dist/src/connectors/slack/tenant-routing.js.map +1 -0
  110. package/dist/src/connectors/slack/transform.js +31 -0
  111. package/dist/src/connectors/slack/transform.js.map +1 -0
  112. package/dist/src/connectors/slack/types.js +23 -0
  113. package/dist/src/connectors/slack/types.js.map +1 -0
  114. package/dist/src/connectors/slack/web-client.js +43 -0
  115. package/dist/src/connectors/slack/web-client.js.map +1 -0
  116. package/dist/src/consolidate.js +517 -0
  117. package/dist/src/consolidate.js.map +1 -0
  118. package/dist/src/dag.js +104 -0
  119. package/dist/src/dag.js.map +1 -0
  120. package/dist/src/dashboard.js +409 -0
  121. package/dist/src/dashboard.js.map +1 -0
  122. package/dist/src/db.js +643 -0
  123. package/dist/src/db.js.map +1 -0
  124. package/dist/src/embeddings.js +344 -0
  125. package/dist/src/embeddings.js.map +1 -0
  126. package/dist/src/eval-suite.js +289 -0
  127. package/dist/src/eval-suite.js.map +1 -0
  128. package/dist/src/eval.js +187 -0
  129. package/dist/src/eval.js.map +1 -0
  130. package/dist/src/extract.js +87 -0
  131. package/dist/src/extract.js.map +1 -0
  132. package/dist/src/goals.js +227 -0
  133. package/dist/src/goals.js.map +1 -0
  134. package/dist/src/handoff.js +30 -0
  135. package/dist/src/handoff.js.map +1 -0
  136. package/dist/src/hooks.js +582 -0
  137. package/dist/src/hooks.js.map +1 -0
  138. package/dist/src/importers.js +399 -0
  139. package/dist/src/importers.js.map +1 -0
  140. package/dist/src/index.js +25 -0
  141. package/dist/src/index.js.map +1 -0
  142. package/dist/src/invalidation.js +94 -0
  143. package/dist/src/invalidation.js.map +1 -0
  144. package/dist/src/mcp/framing.js +45 -0
  145. package/dist/src/mcp/framing.js.map +1 -0
  146. package/dist/src/mcp/server.js +510 -0
  147. package/dist/src/mcp/server.js.map +1 -0
  148. package/dist/src/memory.js +280 -0
  149. package/dist/src/memory.js.map +1 -0
  150. package/dist/src/multihop.js +32 -0
  151. package/dist/src/multihop.js.map +1 -0
  152. package/dist/src/path-context.js +32 -0
  153. package/dist/src/path-context.js.map +1 -0
  154. package/dist/src/physics-config.js +26 -0
  155. package/dist/src/physics-config.js.map +1 -0
  156. package/dist/src/physics-state.js +163 -0
  157. package/dist/src/physics-state.js.map +1 -0
  158. package/dist/src/physics.js +361 -0
  159. package/dist/src/physics.js.map +1 -0
  160. package/dist/src/postinstall.js +68 -0
  161. package/dist/src/postinstall.js.map +1 -0
  162. package/dist/src/raw-archive.js +72 -0
  163. package/dist/src/raw-archive.js.map +1 -0
  164. package/dist/src/refine-llm.js +147 -0
  165. package/dist/src/refine-llm.js.map +1 -0
  166. package/dist/src/replay.js +117 -0
  167. package/dist/src/replay.js.map +1 -0
  168. package/dist/src/salience.js +74 -0
  169. package/dist/src/salience.js.map +1 -0
  170. package/dist/src/scheduler.js +67 -0
  171. package/dist/src/scheduler.js.map +1 -0
  172. package/dist/src/scope.js +35 -0
  173. package/dist/src/scope.js.map +1 -0
  174. package/dist/src/search.js +801 -0
  175. package/dist/src/search.js.map +1 -0
  176. package/dist/src/server-detect.js +70 -0
  177. package/dist/src/server-detect.js.map +1 -0
  178. package/dist/src/server.js +784 -0
  179. package/dist/src/server.js.map +1 -0
  180. package/dist/src/shared.js +309 -0
  181. package/dist/src/shared.js.map +1 -0
  182. package/dist/src/sso.js +22 -0
  183. package/dist/src/sso.js.map +1 -0
  184. package/dist/src/store.js +1390 -0
  185. package/dist/src/store.js.map +1 -0
  186. package/dist/src/tenant.js +17 -0
  187. package/dist/src/tenant.js.map +1 -0
  188. package/dist/src/trace.js +64 -0
  189. package/dist/src/trace.js.map +1 -0
  190. package/dist/src/working-memory.js +149 -0
  191. package/dist/src/working-memory.js.map +1 -0
  192. package/dist/src/yaml.js +98 -0
  193. package/dist/src/yaml.js.map +1 -0
  194. package/dist/store.d.ts +9 -1
  195. package/dist/store.d.ts.map +1 -1
  196. package/dist/store.js +30 -2
  197. package/dist/store.js.map +1 -1
  198. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  199. package/extensions/openclaw-plugin/package.json +1 -1
  200. package/openclaw.plugin.json +1 -1
  201. package/package.json +2 -2
  202. package/dist/import.d.ts +0 -31
  203. package/dist/import.d.ts.map +0 -1
  204. package/dist/import.js +0 -307
  205. package/dist/import.js.map +0 -1
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Domain API layer for Hippo.
3
+ *
4
+ * Pure functions taking a Context (hippoRoot + tenantId + actor) plus
5
+ * operation options. Both the CLI (direct mode) and the HTTP server
6
+ * (`hippo serve`, A1) call into this module so the business logic lives
7
+ * in exactly one place.
8
+ */
9
+ import { openHippoDb, closeHippoDb } from './db.js';
10
+ import { writeEntry, readEntry, deleteEntry, loadSearchEntries, removeEntryMirrors, } from './store.js';
11
+ import { createMemory, Layer, } from './memory.js';
12
+ import { appendAuditEvent, queryAuditEvents, } from './audit.js';
13
+ import { promoteToGlobal, getGlobalRoot } from './shared.js';
14
+ import { archiveRawMemory } from './raw-archive.js';
15
+ import { createApiKey, listApiKeys, revokeApiKey, } from './auth.js';
16
+ export function remember(ctx, opts) {
17
+ const entry = createMemory(opts.content, {
18
+ kind: opts.kind ?? 'distilled',
19
+ scope: opts.scope ?? null,
20
+ owner: opts.owner ?? null,
21
+ artifact_ref: opts.artifactRef ?? null,
22
+ tags: opts.tags,
23
+ tenantId: ctx.tenantId,
24
+ });
25
+ // writeEntry threads ctx.actor into its internal audit hook, so exactly
26
+ // one 'remember' event lands in the log with the supplied actor.
27
+ writeEntry(ctx.hippoRoot, entry, { actor: ctx.actor, afterWrite: opts.afterWrite });
28
+ return { id: entry.id, kind: entry.kind, tenantId: ctx.tenantId };
29
+ }
30
+ /**
31
+ * Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
32
+ * `ctx.tenantId`. The `mode` flag is accepted for forward compatibility (the
33
+ * CLI exposes hybrid/physics paths) but Task 2 wires only the BM25 candidate
34
+ * loader; later tasks can extend this to call the physics/hybrid scorer.
35
+ */
36
+ export function recall(ctx, opts) {
37
+ const limit = opts.limit ?? 10;
38
+ const all = loadSearchEntries(ctx.hippoRoot, opts.query, undefined, ctx.tenantId);
39
+ // Scope filtering runs AFTER the tenant filter inside loadSearchEntries, so
40
+ // a tenant-mismatched scope cannot surface another tenant's row even when
41
+ // both share the same scope string (e.g. 'slack:private:CSHARED').
42
+ let entries;
43
+ if (opts.scope !== undefined && opts.scope !== '') {
44
+ entries = all.filter((e) => e.scope === opts.scope);
45
+ }
46
+ else {
47
+ // Default-deny: a no-scope caller cannot see private slack channels. This
48
+ // is load-bearing because frontend callers will pass `undefined` and must
49
+ // not see `slack:private:*` rows by default.
50
+ entries = all.filter((e) => !(e.scope ?? '').startsWith('slack:private:'));
51
+ }
52
+ // BM25 ordering already comes from loadSearchEntries; cap to `limit`.
53
+ // Score is a placeholder — the physics/hybrid scorers in src/search.ts
54
+ // produce richer breakdowns and will replace this when wired up.
55
+ const ranked = entries.slice(0, limit).map((entry, idx) => ({
56
+ id: entry.id,
57
+ content: entry.content,
58
+ score: Math.max(0, 1 - idx / Math.max(1, limit)),
59
+ layer: entry.layer,
60
+ strength: entry.strength,
61
+ }));
62
+ const tokens = ranked.reduce((acc, r) => acc + Math.ceil(r.content.length / 4), 0);
63
+ // TODO(a1-task-4): emit via the shared audit hook in store.ts so we don't
64
+ // double-emit. Recall does not currently write through writeEntry, so no
65
+ // duplicate exists today, but we keep the same shape for symmetry.
66
+ const db = openHippoDb(ctx.hippoRoot);
67
+ try {
68
+ appendAuditEvent(db, {
69
+ tenantId: ctx.tenantId,
70
+ actor: ctx.actor,
71
+ op: 'recall',
72
+ metadata: { query: opts.query.slice(0, 200), results: ranked.length },
73
+ });
74
+ }
75
+ finally {
76
+ closeHippoDb(db);
77
+ }
78
+ return { results: ranked, total: entries.length, tokens };
79
+ }
80
+ // ---------------------------------------------------------------------------
81
+ // forget
82
+ // ---------------------------------------------------------------------------
83
+ /**
84
+ * Delete a memory by id. `deleteEntry` threads ctx.actor into its internal
85
+ * audit hook, so exactly one 'forget' event lands with the supplied actor.
86
+ *
87
+ * Tenant scope: deleteEntry looks up the row by id alone, so without an
88
+ * explicit tenant guard a Bearer for tenant A could delete tenant B's row
89
+ * by guessing or leaking the id. Pre-check the row's tenant_id and deny
90
+ * cross-tenant access with a not-found error (no info leak about whether
91
+ * the id exists in another tenant).
92
+ */
93
+ export function forget(ctx, id) {
94
+ const db = openHippoDb(ctx.hippoRoot);
95
+ try {
96
+ const row = db
97
+ .prepare(`SELECT tenant_id FROM memories WHERE id = ?`)
98
+ .get(id);
99
+ if (!row || row.tenant_id !== ctx.tenantId) {
100
+ throw new Error(`memory not found: ${id}`);
101
+ }
102
+ }
103
+ finally {
104
+ closeHippoDb(db);
105
+ }
106
+ const removed = deleteEntry(ctx.hippoRoot, id, { actor: ctx.actor });
107
+ if (!removed) {
108
+ throw new Error(`memory not found: ${id}`);
109
+ }
110
+ return { ok: true, id };
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // promote
114
+ // ---------------------------------------------------------------------------
115
+ /**
116
+ * Copy a local memory into the global store. Mirrors `cmdPromote` in cli.ts:
117
+ * the `writeEntry` inside `promoteToGlobal` emits a 'remember' on the global
118
+ * db; we add a 'promote' audit event on the global db so the user-facing
119
+ * intent stays distinct from the underlying upsert.
120
+ *
121
+ * Note: `promoteToGlobal` does not currently take a tenantId override — it
122
+ * reads the entry from the local root via `readEntry` (no tenant filter) and
123
+ * preserves the entry's existing tenantId on the global side. Task 4 may
124
+ * tighten this once writeEntry/readEntry thread tenant context.
125
+ */
126
+ export function promote(ctx, id) {
127
+ // promoteToGlobal threads ctx.actor into the writeEntry call on the global
128
+ // db, which emits a 'remember' audit row. We then add the user-facing
129
+ // 'promote' event on the global db so the audit trail keeps the intent
130
+ // distinct from the underlying upsert.
131
+ const globalEntry = promoteToGlobal(ctx.hippoRoot, id, { actor: ctx.actor });
132
+ const db = openHippoDb(getGlobalRoot());
133
+ try {
134
+ appendAuditEvent(db, {
135
+ tenantId: ctx.tenantId,
136
+ actor: ctx.actor,
137
+ op: 'promote',
138
+ targetId: globalEntry.id,
139
+ metadata: { sourceId: id },
140
+ });
141
+ }
142
+ finally {
143
+ closeHippoDb(db);
144
+ }
145
+ return { ok: true, sourceId: id, globalId: globalEntry.id };
146
+ }
147
+ // ---------------------------------------------------------------------------
148
+ // supersede
149
+ // ---------------------------------------------------------------------------
150
+ /**
151
+ * Replace an old memory with new content, chaining old.superseded_by = new.id.
152
+ * Mirrors `cmdSupersede` in cli.ts (without flag-driven layer/tag/pin overrides
153
+ * — A1 keeps the API minimal; the CLI handler will continue to handle those
154
+ * flags and pass the resolved values once Task 4 lands).
155
+ */
156
+ export function supersede(ctx, oldId, newContent) {
157
+ const old = readEntry(ctx.hippoRoot, oldId, ctx.tenantId);
158
+ if (!old) {
159
+ throw new Error(`Memory not found: ${oldId}`);
160
+ }
161
+ if (old.superseded_by) {
162
+ throw new Error(`Memory ${oldId} is already superseded by ${old.superseded_by}. Supersede that one instead.`);
163
+ }
164
+ const newEntry = createMemory(newContent, {
165
+ layer: old.layer ?? Layer.Episodic,
166
+ tags: [...old.tags],
167
+ pinned: old.pinned,
168
+ source: old.source,
169
+ confidence: 'verified',
170
+ tenantId: ctx.tenantId,
171
+ });
172
+ old.superseded_by = newEntry.id;
173
+ writeEntry(ctx.hippoRoot, old, { actor: ctx.actor });
174
+ writeEntry(ctx.hippoRoot, newEntry, { actor: ctx.actor });
175
+ // The two writeEntry calls above emit 'remember' audit rows; the 'supersede'
176
+ // event below carries the user-facing intent and the chained newId.
177
+ const db = openHippoDb(ctx.hippoRoot);
178
+ try {
179
+ appendAuditEvent(db, {
180
+ tenantId: ctx.tenantId,
181
+ actor: ctx.actor,
182
+ op: 'supersede',
183
+ targetId: oldId,
184
+ metadata: { newId: newEntry.id },
185
+ });
186
+ }
187
+ finally {
188
+ closeHippoDb(db);
189
+ }
190
+ return { ok: true, oldId, newId: newEntry.id };
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // archive_raw
194
+ // ---------------------------------------------------------------------------
195
+ /**
196
+ * Archive a kind='raw' memory: snapshot into raw_archive, mark archived, delete.
197
+ *
198
+ * `archiveRawMemory` audits the operation internally (op='archive_raw') using the
199
+ * row's own tenant_id. We DO NOT emit a second audit event here to avoid double-
200
+ * emitting the archive_raw op (unlike Task 1 remember/forget where the underlying
201
+ * helpers hardcode actor='cli'). Instead we pass `ctx.actor` through as `who`,
202
+ * and raw-archive.ts uses that for the audit row.
203
+ */
204
+ export function archiveRaw(ctx, id, reason) {
205
+ const db = openHippoDb(ctx.hippoRoot);
206
+ try {
207
+ // Tenant scope: archiveRawMemory looks up the row by id alone, so a
208
+ // Bearer for tenant A could archive tenant B's raw row without this
209
+ // pre-check. Deny cross-tenant access with the same not-found message
210
+ // archiveRawMemory itself would throw on a missing row, so we don't
211
+ // leak whether the id exists in another tenant.
212
+ const row = db
213
+ .prepare(`SELECT tenant_id FROM memories WHERE id = ?`)
214
+ .get(id);
215
+ if (!row || row.tenant_id !== ctx.tenantId) {
216
+ throw new Error(`memory not found: ${id}`);
217
+ }
218
+ archiveRawMemory(db, id, { reason, who: ctx.actor });
219
+ }
220
+ finally {
221
+ closeHippoDb(db);
222
+ }
223
+ // archiveRawMemory deletes the memories row but leaves any legacy markdown
224
+ // mirror in <root>/{buffer,episodic,semantic}/<id>.md untouched. If we left
225
+ // the mirror in place, a subsequent initStore() on an empty memories table
226
+ // would silently re-import the row via bootstrapLegacyStore — defeating the
227
+ // archive (and the GDPR right-to-be-forgotten promise on raw rows). Mirror
228
+ // forget() at src/store.ts:1046, which uses the same removeEntryMirrors call.
229
+ removeEntryMirrors(ctx.hippoRoot, id);
230
+ // archiveRawMemory does not return the archive_at timestamp it wrote. We
231
+ // emit a fresh ISO timestamp here for the API response. Within a millisecond
232
+ // of the actual write, fine for a server response shape.
233
+ return { ok: true, archivedAt: new Date().toISOString() };
234
+ }
235
+ /**
236
+ * Mint a new API key. Per A5 v2 follow-ups (TODOS.md), `auth_create` is currently
237
+ * unaudited — we intentionally match that behavior here for consistency. When A5
238
+ * v2 lands and adds the audit op, this function should mirror the cli handler.
239
+ */
240
+ export function authCreate(ctx, opts) {
241
+ const tenantId = opts.tenantId ?? ctx.tenantId;
242
+ const db = openHippoDb(ctx.hippoRoot);
243
+ try {
244
+ const result = createApiKey(db, { tenantId, label: opts.label });
245
+ return { keyId: result.keyId, plaintext: result.plaintext, tenantId };
246
+ }
247
+ finally {
248
+ closeHippoDb(db);
249
+ }
250
+ }
251
+ /**
252
+ * List API keys visible to the calling tenant.
253
+ *
254
+ * Divergence from `cmdAuthList` in src/cli.ts: the CLI today returns ALL keys
255
+ * regardless of tenant (single-tenant deployments). The API surface is tenant-
256
+ * scoped because future multi-tenant deployments will share a hippoRoot, and
257
+ * tenant A must not see tenant B's keys. Read-only — no audit emit (matches A5).
258
+ */
259
+ export function authList(ctx, opts) {
260
+ const db = openHippoDb(ctx.hippoRoot);
261
+ try {
262
+ const all = listApiKeys(db, opts);
263
+ return all.filter((k) => k.tenantId === ctx.tenantId);
264
+ }
265
+ finally {
266
+ closeHippoDb(db);
267
+ }
268
+ }
269
+ /**
270
+ * Revoke an API key.
271
+ *
272
+ * Security: the key must belong to `ctx.tenantId`. Cross-tenant revoke is
273
+ * rejected with the same "not found" message used for missing keys, so that a
274
+ * caller cannot probe which key_ids exist on other tenants.
275
+ *
276
+ * Audit: emits 'auth_revoke' with `tenantId` set to the KEY ROW's tenant_id
277
+ * (M1 fix from A5 review, mirrors src/cli.ts:cmdAuthRevoke). Skipped on no-op
278
+ * revoke (already revoked) so re-running doesn't pad the audit log.
279
+ */
280
+ export function authRevoke(ctx, keyId) {
281
+ const db = openHippoDb(ctx.hippoRoot);
282
+ try {
283
+ const row = db
284
+ .prepare(`SELECT key_id, tenant_id, revoked_at FROM api_keys WHERE key_id = ?`)
285
+ .get(keyId);
286
+ if (!row) {
287
+ throw new Error(`Unknown key_id: ${keyId}`);
288
+ }
289
+ // Cross-tenant access denied: same message as missing key, no info leak.
290
+ if (row.tenant_id !== ctx.tenantId) {
291
+ throw new Error(`Unknown key_id: ${keyId}`);
292
+ }
293
+ let revokedAt;
294
+ let alreadyRevoked = false;
295
+ if (row.revoked_at) {
296
+ alreadyRevoked = true;
297
+ revokedAt = row.revoked_at;
298
+ }
299
+ else {
300
+ revokeApiKey(db, keyId);
301
+ const updated = db
302
+ .prepare(`SELECT revoked_at FROM api_keys WHERE key_id = ?`)
303
+ .get(keyId);
304
+ revokedAt = updated?.revoked_at ?? new Date().toISOString();
305
+ }
306
+ if (!alreadyRevoked) {
307
+ try {
308
+ appendAuditEvent(db, {
309
+ tenantId: row.tenant_id, // M1: KEY's tenant, not ctx.tenantId.
310
+ actor: ctx.actor,
311
+ op: 'auth_revoke',
312
+ targetId: keyId,
313
+ });
314
+ }
315
+ catch {
316
+ // Audit must not crash a successful revoke.
317
+ }
318
+ }
319
+ return { ok: true, revokedAt };
320
+ }
321
+ finally {
322
+ closeHippoDb(db);
323
+ }
324
+ }
325
+ /**
326
+ * Read audit events scoped to `ctx.tenantId`. Read-only — no audit emit (matches
327
+ * A5: cmdAuditList does not record a 'recall'-style read event).
328
+ */
329
+ export function auditList(ctx, opts) {
330
+ const db = openHippoDb(ctx.hippoRoot);
331
+ try {
332
+ return queryAuditEvents(db, {
333
+ tenantId: ctx.tenantId,
334
+ op: opts.op,
335
+ since: opts.since,
336
+ limit: opts.limit,
337
+ });
338
+ }
339
+ finally {
340
+ closeHippoDb(db);
341
+ }
342
+ }
343
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ const STOP_WORDS = new Set([
2
+ 'the', 'a', 'an', 'is', 'was', 'are', 'were', 'be', 'been', 'being',
3
+ 'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'it',
4
+ 'this', 'that', 'and', 'or', 'but', 'not', 'no', 'so', 'if', 'do',
5
+ 'did', 'does', 'has', 'had', 'have', 'will', 'would', 'could', 'should',
6
+ 'may', 'might', 'can', 'shall', 'we', 'i', 'you', 'they', 'he', 'she',
7
+ 'my', 'our', 'your', 'its', 'his', 'her', 'their', 'up', 'out', 'just',
8
+ 'also', 'then', 'than', 'some', 'all', 'any', 'each', 'very', 'too',
9
+ ]);
10
+ const VAGUE_ONLY = /^[\w\s,.'"-]+$/;
11
+ function substantiveWordCount(text) {
12
+ return text
13
+ .toLowerCase()
14
+ .split(/\s+/)
15
+ .filter(w => w.length > 2 && !STOP_WORDS.has(w))
16
+ .length;
17
+ }
18
+ function isVersionBump(text) {
19
+ const t = text.trim();
20
+ // release/bump/prep/tag + version
21
+ if (/^(?:bump|release|prep|tag)\s+(?:to\s+)?v?\d+\.\d+/i.test(t))
22
+ return true;
23
+ // bare semver ("0.24.1", "v1.2.3")
24
+ if (/^v?\d+\.\d+\.\d+\s*$/i.test(t))
25
+ return true;
26
+ // chore: release 1.2.3 / chore(ci): bump v1.2.3
27
+ if (/^chore(?:\([^)]+\))?:\s*(?:release|bump|version|tag|prep)\b/i.test(t))
28
+ return true;
29
+ // Merge commits
30
+ if (/^(?:Merge branch|Merge pull request)\b/i.test(t))
31
+ return true;
32
+ // WIP sentinels
33
+ if (/^WIP\b/i.test(t))
34
+ return true;
35
+ return false;
36
+ }
37
+ function isFragment(text) {
38
+ const trimmed = text.trim();
39
+ if (trimmed.startsWith('to ') && trimmed.length < 50)
40
+ return true;
41
+ if (trimmed.startsWith('for ') && trimmed.length < 50)
42
+ return true;
43
+ if (trimmed.startsWith('and ') && trimmed.length < 50)
44
+ return true;
45
+ return false;
46
+ }
47
+ function hasNoSpecificity(text) {
48
+ const words = text.toLowerCase().split(/\s+/);
49
+ const hasNumber = /\d/.test(text);
50
+ const hasProperNoun = /[A-Z][a-z]{2,}/.test(text);
51
+ const hasPath = /[/\\.]/.test(text);
52
+ const hasCode = /[`_{}()\[\]]/.test(text);
53
+ if (hasNumber || hasProperNoun || hasPath || hasCode)
54
+ return false;
55
+ return words.length < 8 && VAGUE_ONLY.test(text);
56
+ }
57
+ export function auditMemory(entry) {
58
+ const content = entry.content.trim();
59
+ if (content.length < 3) {
60
+ return { memoryId: entry.id, content, severity: 'error', reason: 'too short (< 3 chars)' };
61
+ }
62
+ if (content.length < 10) {
63
+ return { memoryId: entry.id, content, severity: 'error', reason: 'too short (< 10 chars)' };
64
+ }
65
+ if (isVersionBump(content)) {
66
+ return { memoryId: entry.id, content, severity: 'error', reason: 'release/commit noise, not a useful memory' };
67
+ }
68
+ if (isFragment(content)) {
69
+ return { memoryId: entry.id, content, severity: 'warning', reason: 'sentence fragment — lacks context' };
70
+ }
71
+ const substantive = substantiveWordCount(content);
72
+ if (substantive < 2) {
73
+ return { memoryId: entry.id, content, severity: 'warning', reason: `only ${substantive} substantive word(s) — too vague` };
74
+ }
75
+ if (content.length < 40 && hasNoSpecificity(content)) {
76
+ return { memoryId: entry.id, content, severity: 'warning', reason: 'no specific details (names, paths, numbers, code)' };
77
+ }
78
+ return null;
79
+ }
80
+ export function auditMemories(entries) {
81
+ const issues = [];
82
+ for (const entry of entries) {
83
+ const issue = auditMemory(entry);
84
+ if (issue)
85
+ issues.push(issue);
86
+ }
87
+ return {
88
+ total: entries.length,
89
+ issues,
90
+ clean: entries.length - issues.length,
91
+ };
92
+ }
93
+ export function isContentWorthStoring(content) {
94
+ const trimmed = content.trim();
95
+ if (trimmed.length < 10)
96
+ return false;
97
+ if (isVersionBump(trimmed))
98
+ return false;
99
+ if (isFragment(trimmed))
100
+ return false;
101
+ if (substantiveWordCount(trimmed) < 2)
102
+ return false;
103
+ if (trimmed.length < 40 && hasNoSpecificity(trimmed))
104
+ return false;
105
+ return true;
106
+ }
107
+ // node:sqlite returns INTEGER columns as bigint when the value exceeds
108
+ // Number.MAX_SAFE_INTEGER. Audit metadata can carry such values (row ids,
109
+ // counts), and JSON.stringify cannot serialize bigint without a replacer.
110
+ // Mirrors the bigintSafeReplacer in src/raw-archive.ts.
111
+ function bigintSafeReplacer(_key, value) {
112
+ return typeof value === 'bigint' ? value.toString() : value;
113
+ }
114
+ export function appendAuditEvent(db, opts) {
115
+ db.prepare(`INSERT INTO audit_log (ts, tenant_id, actor, op, target_id, metadata_json) VALUES (?, ?, ?, ?, ?, ?)`).run(new Date().toISOString(), opts.tenantId, opts.actor, opts.op, opts.targetId ?? null, JSON.stringify(opts.metadata ?? {}, bigintSafeReplacer));
116
+ }
117
+ export function queryAuditEvents(db, opts) {
118
+ const where = ['tenant_id = ?'];
119
+ const params = [opts.tenantId];
120
+ if (opts.op) {
121
+ where.push('op = ?');
122
+ params.push(opts.op);
123
+ }
124
+ if (opts.since) {
125
+ where.push('ts >= ?');
126
+ params.push(opts.since);
127
+ }
128
+ const limit = Math.max(1, Math.min(opts.limit ?? 100, 10000));
129
+ const rows = db
130
+ .prepare(`SELECT id, ts, tenant_id, actor, op, target_id, metadata_json
131
+ FROM audit_log WHERE ${where.join(' AND ')} ORDER BY ts DESC, id DESC LIMIT ?`)
132
+ .all(...params, limit);
133
+ return rows.map((r) => ({
134
+ id: r.id,
135
+ ts: r.ts,
136
+ tenantId: r.tenant_id,
137
+ actor: r.actor,
138
+ op: r.op,
139
+ targetId: r.target_id,
140
+ metadata: safeJsonParse(r.metadata_json),
141
+ }));
142
+ }
143
+ function safeJsonParse(raw) {
144
+ try {
145
+ const v = JSON.parse(raw);
146
+ return typeof v === 'object' && v !== null ? v : {};
147
+ }
148
+ catch {
149
+ return {};
150
+ }
151
+ }
152
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
2
+ const KEY_PREFIX = 'hk_';
3
+ const ID_LEN = 24; // base32 chars after prefix
4
+ const SECRET_LEN = 32; // base32 chars after dot
5
+ const SCRYPT_KEYLEN = 32;
6
+ const BASE32 = 'abcdefghijklmnopqrstuvwxyz234567';
7
+ function randBase32(n) {
8
+ const bytes = randomBytes(n);
9
+ let out = '';
10
+ for (let i = 0; i < n; i++)
11
+ out += BASE32[bytes[i] % 32];
12
+ return out;
13
+ }
14
+ function hashKey(plaintext) {
15
+ // Format: scrypt$<saltHex>$<hashHex>
16
+ const salt = randomBytes(16);
17
+ const hash = scryptSync(plaintext, salt, SCRYPT_KEYLEN);
18
+ return `scrypt$${salt.toString('hex')}$${hash.toString('hex')}`;
19
+ }
20
+ function verifyKey(plaintext, stored) {
21
+ const parts = stored.split('$');
22
+ if (parts.length !== 3 || parts[0] !== 'scrypt')
23
+ return false;
24
+ const salt = Buffer.from(parts[1], 'hex');
25
+ const expected = Buffer.from(parts[2], 'hex');
26
+ const actual = scryptSync(plaintext, salt, expected.length);
27
+ return expected.length === actual.length && timingSafeEqual(expected, actual);
28
+ }
29
+ export function createApiKey(db, opts) {
30
+ const keyId = `${KEY_PREFIX}${randBase32(ID_LEN)}`;
31
+ const secret = randBase32(SECRET_LEN);
32
+ const plaintext = `${keyId}.${secret}`;
33
+ const hash = hashKey(plaintext);
34
+ db.prepare(`INSERT INTO api_keys (key_id, key_hash, tenant_id, label, created_at) VALUES (?, ?, ?, ?, ?)`).run(keyId, hash, opts.tenantId, opts.label ?? null, new Date().toISOString());
35
+ return { keyId, plaintext };
36
+ }
37
+ export function validateApiKey(db, plaintext) {
38
+ const dot = plaintext.indexOf('.');
39
+ if (dot < 0)
40
+ return { valid: false };
41
+ const keyId = plaintext.slice(0, dot);
42
+ const row = db
43
+ .prepare(`SELECT key_hash, tenant_id, revoked_at FROM api_keys WHERE key_id = ?`)
44
+ .get(keyId);
45
+ if (!row || row.revoked_at)
46
+ return { valid: false };
47
+ if (!verifyKey(plaintext, row.key_hash))
48
+ return { valid: false };
49
+ return { valid: true, tenantId: row.tenant_id, keyId };
50
+ }
51
+ export function revokeApiKey(db, keyId) {
52
+ db.prepare(`UPDATE api_keys SET revoked_at = ? WHERE key_id = ? AND revoked_at IS NULL`)
53
+ .run(new Date().toISOString(), keyId);
54
+ }
55
+ export function listApiKeys(db, opts) {
56
+ const sql = opts.active
57
+ ? `SELECT key_id, tenant_id, label, created_at, revoked_at FROM api_keys WHERE revoked_at IS NULL ORDER BY id DESC`
58
+ : `SELECT key_id, tenant_id, label, created_at, revoked_at FROM api_keys ORDER BY id DESC`;
59
+ const rows = db.prepare(sql).all();
60
+ return rows.map(r => ({
61
+ keyId: r.key_id, tenantId: r.tenant_id, label: r.label,
62
+ createdAt: r.created_at, revokedAt: r.revoked_at,
63
+ }));
64
+ }
65
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}