hippo-memory 1.72.0 → 2.0.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 (259) hide show
  1. package/README.md +6 -4
  2. package/dist/agent-memories/apply.js +5 -5
  3. package/dist/api/assemble.js +2 -1
  4. package/dist/api/audit.d.ts +7 -7
  5. package/dist/api/audit.js +19 -17
  6. package/dist/api/auth.d.ts +5 -6
  7. package/dist/api/auth.js +28 -33
  8. package/dist/api/conflicts.js +1 -1
  9. package/dist/api/context-auto.js +4 -2
  10. package/dist/api/context-select.js +8 -20
  11. package/dist/api/context.js +12 -10
  12. package/dist/api/drill-down.js +2 -1
  13. package/dist/api/forget.d.ts +2 -2
  14. package/dist/api/forget.js +6 -7
  15. package/dist/api/graph.js +2 -1
  16. package/dist/api/learn.d.ts +1 -1
  17. package/dist/api/learn.js +45 -44
  18. package/dist/api/memories.d.ts +4 -2
  19. package/dist/api/memories.js +16 -5
  20. package/dist/api/objects.js +2 -1
  21. package/dist/api/outcome.d.ts +5 -5
  22. package/dist/api/outcome.js +16 -15
  23. package/dist/api/predictions.js +2 -1
  24. package/dist/api/promote.d.ts +3 -3
  25. package/dist/api/promote.js +25 -27
  26. package/dist/api/prompt-hook.d.ts +3 -1
  27. package/dist/api/prompt-hook.js +1 -0
  28. package/dist/api/quarantine.js +2 -1
  29. package/dist/api/recall-core.js +8 -3
  30. package/dist/api/recall-pipeline.js +17 -17
  31. package/dist/api/recall-types.d.ts +3 -1
  32. package/dist/api/recall.js +32 -29
  33. package/dist/api/remember-local.d.ts +5 -2
  34. package/dist/api/remember-local.js +14 -6
  35. package/dist/api/remember.d.ts +5 -2
  36. package/dist/api/remember.js +16 -14
  37. package/dist/api/session-end.d.ts +24 -0
  38. package/dist/api/session-end.js +31 -1
  39. package/dist/api/sleep-run.js +5 -4
  40. package/dist/api/sleep.js +4 -3
  41. package/dist/api/tokens.js +1 -1
  42. package/dist/api/types.d.ts +1 -7
  43. package/dist/capture/command.js +1 -1
  44. package/dist/capture/compaction-spool.d.ts +3 -5
  45. package/dist/capture/compaction-spool.js +41 -46
  46. package/dist/capture/session-end-caller.js +1 -1
  47. package/dist/capture/session-worker.js +19 -6
  48. package/dist/cli/audit.js +10 -10
  49. package/dist/cli/auth.js +4 -4
  50. package/dist/cli/client.d.ts +1 -2
  51. package/dist/cli/client.js +13 -13
  52. package/dist/cli/context.js +1 -1
  53. package/dist/cli/curate.d.ts +1 -1
  54. package/dist/cli/curate.js +9 -9
  55. package/dist/cli/decisions.js +4 -5
  56. package/dist/cli/hook-runtime.d.ts +3 -1
  57. package/dist/cli/hook-runtime.js +2 -2
  58. package/dist/cli/init.d.ts +1 -1
  59. package/dist/cli/init.js +9 -9
  60. package/dist/cli/object-verbs.d.ts +2 -2
  61. package/dist/cli/object-verbs.js +4 -4
  62. package/dist/cli/predictions.js +2 -3
  63. package/dist/cli/quality-repair-once.d.ts +1 -1
  64. package/dist/cli/quality-repair-once.js +2 -2
  65. package/dist/cli/refine-llm.js +2 -1
  66. package/dist/cli/remember.js +5 -5
  67. package/dist/cli/serve.js +9 -4
  68. package/dist/cli/session-hooks.d.ts +0 -4
  69. package/dist/cli/session-hooks.js +57 -66
  70. package/dist/cli/setup.d.ts +1 -1
  71. package/dist/cli/setup.js +2 -2
  72. package/dist/cli/shared.d.ts +1 -1
  73. package/dist/cli/shared.js +2 -2
  74. package/dist/cli/sleep.js +2 -2
  75. package/dist/cli/transfer.d.ts +3 -3
  76. package/dist/cli/transfer.js +34 -15
  77. package/dist/cli/usage.d.ts +1 -1
  78. package/dist/cli/usage.js +1 -1
  79. package/dist/cli/verb-row.d.ts +2 -0
  80. package/dist/cli/verbs/health.js +2 -0
  81. package/dist/cli/verbs/memory.js +43 -51
  82. package/dist/cli/verbs/objects.js +6 -3
  83. package/dist/cli/verbs/sessions.js +4 -2
  84. package/dist/cli.js +1 -2
  85. package/dist/connectors/dlq.js +2 -1
  86. package/dist/connectors/github/deletion.js +2 -1
  87. package/dist/connectors/github/ingest.js +2 -1
  88. package/dist/connectors/github/tenant-routing.js +2 -1
  89. package/dist/connectors/github/webhook.js +4 -2
  90. package/dist/connectors/ingest.js +2 -1
  91. package/dist/connectors/slack/deletion.js +2 -1
  92. package/dist/connectors/slack/ingest.js +2 -1
  93. package/dist/connectors/slack/tenant-routing.js +2 -1
  94. package/dist/consolidate/conflicts.js +1 -1
  95. package/dist/consolidate/dag.js +14 -9
  96. package/dist/consolidate/dedupe.js +1 -1
  97. package/dist/consolidate/memory-value.js +1 -1
  98. package/dist/consolidate/merge.js +6 -6
  99. package/dist/consolidate/sleep.js +1 -1
  100. package/dist/consolidate/traces.js +2 -2
  101. package/dist/core/config.js +15 -16
  102. package/dist/core/markdown.js +2 -2
  103. package/dist/core/memory.d.ts +4 -4
  104. package/dist/core/memory.js +10 -5
  105. package/dist/core/physics.d.ts +3 -1
  106. package/dist/core/physics.js +17 -2
  107. package/dist/core/project-identity.js +2 -1
  108. package/dist/core/search-types.d.ts +1 -1
  109. package/dist/dashboard/dashboard-actions.d.ts +2 -2
  110. package/dist/dashboard/dashboard-actions.js +5 -5
  111. package/dist/dashboard/dashboard-queries.js +2 -7
  112. package/dist/dashboard/dashboard-snapshot.js +1 -3
  113. package/dist/dashboard/dashboard.js +16 -5
  114. package/dist/db/connect.d.ts +2 -1
  115. package/dist/db/connect.js +2 -1
  116. package/dist/db/migrate.js +14 -7
  117. package/dist/db/migrations/v11.js +1 -0
  118. package/dist/db/migrations/v14.js +1 -0
  119. package/dist/db/physics-state.d.ts +0 -4
  120. package/dist/db/physics-state.js +5 -31
  121. package/dist/db/request-stores.d.ts +1 -0
  122. package/dist/db/request-stores.js +2 -1
  123. package/dist/db/vector-store.js +2 -1
  124. package/dist/doctor.d.ts +3 -0
  125. package/dist/doctor.js +7 -7
  126. package/dist/embeddings/local.js +2 -2
  127. package/dist/embeddings/provider.js +1 -10
  128. package/dist/entry/store-kit.d.ts +37 -0
  129. package/dist/entry/store-kit.js +25 -0
  130. package/dist/entry/testing.d.ts +6 -0
  131. package/dist/entry/testing.js +7 -0
  132. package/dist/eval/judgment.js +1 -1
  133. package/dist/hooks/json-hooks.js +6 -2
  134. package/dist/importers/core.js +3 -3
  135. package/dist/importers/vault.d.ts +1 -1
  136. package/dist/importers/vault.js +18 -18
  137. package/dist/index.d.ts +2 -2
  138. package/dist/index.js +1 -1
  139. package/dist/learn/autolearn.d.ts +6 -2
  140. package/dist/learn/autolearn.js +8 -6
  141. package/dist/learn/extract.js +1 -1
  142. package/dist/learn/invalidation.d.ts +2 -1
  143. package/dist/learn/invalidation.js +10 -5
  144. package/dist/mcp/memory-tools.d.ts +1 -1
  145. package/dist/mcp/memory-tools.js +6 -9
  146. package/dist/mcp/request.js +20 -19
  147. package/dist/mcp/stdio.js +13 -8
  148. package/dist/rerankers/cross-encoder.js +10 -3
  149. package/dist/search/embed-memories.d.ts +5 -2
  150. package/dist/search/embed-memories.js +40 -28
  151. package/dist/search/engine.d.ts +8 -0
  152. package/dist/search/engine.js +10 -0
  153. package/dist/search/vector.js +5 -5
  154. package/dist/server/auth.d.ts +1 -1
  155. package/dist/server/auth.js +7 -8
  156. package/dist/server/boot.d.ts +2 -1
  157. package/dist/server/boot.js +28 -19
  158. package/dist/server/client-ip.d.ts +9 -4
  159. package/dist/server/client-ip.js +35 -17
  160. package/dist/server/route-table.js +5 -6
  161. package/dist/server/routes/memories.js +4 -2
  162. package/dist/server/sleep-offload.js +3 -3
  163. package/dist/server/tls.d.ts +7 -2
  164. package/dist/server/tls.js +17 -5
  165. package/dist/server/types.d.ts +7 -2
  166. package/dist/server.d.ts +4 -41
  167. package/dist/server.js +3 -30
  168. package/dist/sharing/global-store.d.ts +4 -5
  169. package/dist/sharing/global-store.js +6 -11
  170. package/dist/sharing/global-sync.js +1 -1
  171. package/dist/sharing/search-both.js +9 -2
  172. package/dist/sharing/share.js +2 -4
  173. package/dist/store/ambient.js +2 -1
  174. package/dist/store/candidates.js +18 -8
  175. package/dist/store/cards.js +5 -4
  176. package/dist/store/compactions-record.js +8 -7
  177. package/dist/store/conflicts.d.ts +7 -1
  178. package/dist/store/conflicts.js +6 -5
  179. package/dist/store/connectors/dlq.js +2 -1
  180. package/dist/store/connectors/event-log.d.ts +13 -0
  181. package/dist/store/connectors/event-log.js +24 -0
  182. package/dist/store/connectors/github.js +6 -8
  183. package/dist/store/connectors/slack.js +6 -10
  184. package/dist/store/dashboard-reads.js +1 -0
  185. package/dist/store/delete-and-batch.js +5 -4
  186. package/dist/store/delivery-recorder.d.ts +2 -2
  187. package/dist/store/delivery-recorder.js +1 -6
  188. package/dist/store/descendant-page.js +2 -1
  189. package/dist/store/dormant.js +7 -3
  190. package/dist/store/entry-reads.d.ts +25 -3
  191. package/dist/store/entry-reads.js +43 -12
  192. package/dist/store/entry-row.js +9 -2
  193. package/dist/store/entry-writes.d.ts +10 -7
  194. package/dist/store/entry-writes.js +23 -11
  195. package/dist/store/goals.js +3 -2
  196. package/dist/store/graph-reads.js +5 -4
  197. package/dist/store/graph-view-rows.js +2 -1
  198. package/dist/store/half-life.js +2 -2
  199. package/dist/store/handoffs.d.ts +9 -3
  200. package/dist/store/handoffs.js +4 -3
  201. package/dist/store/index.d.ts +2 -2
  202. package/dist/store/index.js +1 -1
  203. package/dist/store/mirrors.js +9 -4
  204. package/dist/store/open.d.ts +2 -1
  205. package/dist/store/open.js +2 -1
  206. package/dist/store/port.d.ts +59 -3
  207. package/dist/store/quality-repair.js +1 -1
  208. package/dist/store/recall-trace.js +2 -1
  209. package/dist/store/rejected-values.js +14 -9
  210. package/dist/store/rows.js +2 -2
  211. package/dist/store/rule-sql.d.ts +2 -0
  212. package/dist/store/rule-sql.js +12 -6
  213. package/dist/store/search-rows.d.ts +5 -5
  214. package/dist/store/search-rows.js +9 -12
  215. package/dist/store/set-aside.js +1 -1
  216. package/dist/store/sqlite/connector-writes-group.js +3 -1
  217. package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
  218. package/dist/store/sqlite/entry-writes-group.js +1 -1
  219. package/dist/store/sqlite/held-connection.d.ts +2 -0
  220. package/dist/store/sqlite/held-connection.js +1 -1
  221. package/dist/store/sqlite/last-recall-group.d.ts +13 -0
  222. package/dist/store/sqlite/last-recall-group.js +57 -0
  223. package/dist/store/sqlite/local.d.ts +0 -17
  224. package/dist/store/sqlite/local.js +0 -31
  225. package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
  226. package/dist/store/sqlite/maintenance-groups.js +60 -0
  227. package/dist/store/sqlite/objects-group.js +14 -6
  228. package/dist/store/sqlite/store.d.ts +1 -8
  229. package/dist/store/sqlite/store.js +13 -24
  230. package/dist/store/summaries.d.ts +7 -0
  231. package/dist/store/summaries.js +49 -7
  232. package/dist/store/token-ledger-rows.js +3 -2
  233. package/dist/store/vector-index.js +5 -2
  234. package/dist/util/anthropic-messages.d.ts +3 -1
  235. package/dist/util/anthropic-messages.js +4 -2
  236. package/dist/util/atomic-write.d.ts +5 -2
  237. package/dist/util/atomic-write.js +12 -8
  238. package/dist/util/env.d.ts +10 -1
  239. package/dist/util/env.js +10 -1
  240. package/dist/util/format.d.ts +2 -0
  241. package/dist/util/format.js +4 -0
  242. package/dist/util/request-scope.d.ts +6 -2
  243. package/dist/util/request-scope.js +7 -3
  244. package/dist/util/spawn-argv.d.ts +9 -0
  245. package/dist/util/spawn-argv.js +57 -0
  246. package/dist/util/sql.d.ts +3 -0
  247. package/dist/util/sql.js +6 -0
  248. package/dist/util/vector-codec.d.ts +4 -0
  249. package/dist/util/vector-codec.js +15 -0
  250. package/dist/util/version.d.ts +1 -1
  251. package/dist/util/version.js +1 -1
  252. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  253. package/extensions/openclaw-plugin/package.json +1 -1
  254. package/openclaw.plugin.json +1 -1
  255. package/package.json +3 -1
  256. package/dist/api/on-store.d.ts +0 -16
  257. package/dist/api/on-store.js +0 -38
  258. package/dist/cli/lenient-id.d.ts +0 -2
  259. package/dist/cli/lenient-id.js +0 -13
package/README.md CHANGED
@@ -675,11 +675,13 @@ hippo sleep
675
675
  Wrap any command with `hippo watch` to auto-learn from failures:
676
676
 
677
677
  ```bash
678
- hippo watch "npm run build"
678
+ hippo watch -- npm run build
679
679
  # if it fails, Hippo captures the error automatically
680
680
  # next time an agent asks about build issues, the memory is there
681
681
  ```
682
682
 
683
+ The command runs with no shell, so each argument reaches the program as written. To run a shell line with pipes or `&&`, pass it as one string after `--shell`: `hippo watch --shell "npm test && npm run build"`.
684
+
683
685
  ---
684
686
 
685
687
  ## CLI Reference
@@ -736,7 +738,7 @@ hippo watch "npm run build"
736
738
  | `hippo failures [--days n]` | Failed tool calls the capture-error hook saw, by outcome, and how many errors first happened in another session |
737
739
  | `hippo embed` | Embed all memories for semantic search |
738
740
  | `hippo embed --status` | Show embedding coverage |
739
- | `hippo watch "<command>"` | Run command, auto-learn from failures |
741
+ | `hippo watch -- <command> [args...]` | Run command with no shell, auto-learn from failures (`--shell "<line>"` runs one line through the shell) |
740
742
  | `hippo learn --git` | Scan recent git commits for lessons |
741
743
  | `hippo learn --git --days <n>` | Scan N days back (default: 7) |
742
744
  | `hippo learn --git --repos <paths>` | Scan multiple repos (comma-separated) |
@@ -784,8 +786,8 @@ hippo watch "npm run build"
784
786
  | `hippo dashboard` | Open web dashboard at localhost:3333 (memory health by project, and the card board); open the printed URL, which carries a per-start access token |
785
787
  | `hippo dashboard --port <n>` | Use custom port |
786
788
  | `hippo mcp` | Start MCP server (stdio transport) |
787
- | `hippo serve` | Start the HTTP API server for this store on `127.0.0.1:6789` (`--port <n>` or `HIPPO_PORT`; `--host <host>`, which off loopback needs `HIPPO_REQUIRE_AUTH=1`). Every request needs an API key (`hippo auth create`, then `Authorization: Bearer <key>`; the hippo CLI reads `HIPPO_API_KEY`). `HIPPO_ALLOW_KEYLESS_LOCAL=1` lets requests from this machine in without one, as host admin; `HIPPO_REQUIRE_AUTH=1` wins over it |
788
- | `hippo serve --tls-cert <file> --tls-key <file>` | Serve HTTPS with that PEM certificate and key (or set `HIPPO_TLS_CERT` and `HIPPO_TLS_KEY`). Without them a network bind still starts, and warns once that API keys and memory text travel in cleartext unless a TLS-terminating proxy sits in front |
789
+ | `hippo serve` | Start the HTTP API server for this store on `127.0.0.1:6789` (`--port <n>` or `HIPPO_PORT`; `--host <host>`, which off loopback needs `HIPPO_REQUIRE_AUTH=1`). Every request needs an API key (`hippo auth create`, then `Authorization: Bearer <key>`; the hippo CLI reads `HIPPO_API_KEY`). `HIPPO_ALLOW_KEYLESS_LOCAL=1` lets requests from this machine in without one, as a member (`HIPPO_KEYLESS_LOCAL_ROLE=admin` makes them host admin, for sleep and the quarantine routes); `HIPPO_REQUIRE_AUTH=1` wins over it. Each caller gets 20 requests a second, burst 40 (`HIPPO_CALLER_RPS`; `0` turns it off). See [Security defaults](docs/UPGRADING-2.0.md#security-defaults) |
790
+ | `hippo serve --tls-cert <file> --tls-key <file>` | Serve HTTPS with that PEM certificate and key (or set `HIPPO_TLS_CERT` and `HIPPO_TLS_KEY`). Without them a network bind refuses to start, since API keys and memory text would travel in cleartext; behind a TLS-terminating proxy, pass `--allow-cleartext` (or set `HIPPO_ALLOW_CLEARTEXT=1`) |
789
791
 
790
792
  On `heartbeat`, `block`, `review` and `complete`, a given `--run` is checked against the card's live run and the command is refused, unchanged, if the two do not match.
791
793
 
@@ -84,7 +84,7 @@ class ContainerRun {
84
84
  continue;
85
85
  const source = itemSource(this.w.prefix, key, item.text);
86
86
  for (const row of rows) {
87
- if (renameEntrySourceAt(this.s.db, row.tenantId, row.id, row.source, source) === 0)
87
+ if (renameEntrySourceAt(this.s.db, row.tenant_id, row.id, row.source, source) === 0)
88
88
  continue;
89
89
  this.tally.adopted++;
90
90
  this.mirror.push({ ...row, source });
@@ -97,7 +97,7 @@ class ContainerRun {
97
97
  let moved = 0;
98
98
  for (const row of selectLiveEntriesBySourcePrefix(this.s.db, this.s.tenantId, old)) {
99
99
  const source = this.w.prefix + row.source.slice(old.length);
100
- if (renameEntrySourceAndOriginAt(this.s.db, row.tenantId, row.id, { from: row.source, to: source, origin }) === 0)
100
+ if (renameEntrySourceAndOriginAt(this.s.db, row.tenant_id, row.id, { from: row.source, to: source, origin }) === 0)
101
101
  continue;
102
102
  moved++;
103
103
  this.mirror.push({ ...row, source, origin_project: origin ?? row.origin_project });
@@ -150,11 +150,11 @@ class ContainerRun {
150
150
  }
151
151
  /** api.supersede's steps on this transaction; false when another writer superseded the row first. */
152
152
  supersede(old, newId) {
153
- if (!supersedeEntryAt(this.s.db, old.tenantId, old.id, newId))
153
+ if (!supersedeEntryAt(this.s.db, old.tenant_id, old.id, newId))
154
154
  return false;
155
155
  if (old.dag_parent_id)
156
- markSummaryDirtyInTx(this.s.db, old.dag_parent_id, old.tenantId, SYNC_ACTOR);
157
- appendAuditEvent(this.s.db, { tenantId: old.tenantId, actor: SYNC_ACTOR, op: 'supersede', targetId: old.id, metadata: { newId } });
156
+ markSummaryDirtyInTx(this.s.db, old.dag_parent_id, old.tenant_id, SYNC_ACTOR);
157
+ appendAuditEvent(this.s.db, { tenantId: old.tenant_id, actor: SYNC_ACTOR, op: 'supersede', targetId: old.id, metadata: { newId } });
158
158
  this.mirror.push({ ...old, superseded_by: newId });
159
159
  return true;
160
160
  }
@@ -1,5 +1,6 @@
1
1
  // Session context assembly under a token budget.
2
- import { requireGroup, storeFor } from '../store/index.js';
2
+ import { requireGroup } from '../store/index.js';
3
+ import { storeFor } from '../store/sqlite/store.js';
3
4
  import { estimateTokens } from '../util/token-text.js';
4
5
  import { passesScopeFilterForRecall, assertScopeRequestAllowed, personalScopeOf } from '../core/recall-scope.js';
5
6
  import { classifyOriginProject, projectNames } from '../core/project-identity.js';
@@ -1,6 +1,6 @@
1
- import { type AuditEvent, type AuditOp } from '../store/audit.js';
1
+ import type { AuditEvent, AuditOp } from '../store/audit.js';
2
2
  import { type AuditIssue, type AuditResult } from '../core/memory-audit.js';
3
- import { type QualityRepairResult } from '../store/quality-repair.js';
3
+ import type { QualityRepairResult } from '../store/quality-repair.js';
4
4
  import type { KeysetPosition } from '../util/keyset.js';
5
5
  import type { Context } from './types.js';
6
6
  export interface AuditListOpts {
@@ -16,13 +16,13 @@ export declare function auditList(ctx: Context, opts: AuditListOpts): Promise<Au
16
16
  /** The pass that removes audit errors; it leads the reason on each forget row. */
17
17
  export type AuditPass = 'audit --fix' | 'sleep-audit';
18
18
  /** Delete the memories an audit marked as errors, each with its own forget row, and answer the ids that went: a pinned or raw row stays. */
19
- export declare function removeAuditErrors(ctx: Context, pass: AuditPass, issues: readonly AuditIssue[]): string[];
19
+ export declare function removeAuditErrors(ctx: Context, pass: AuditPass, issues: readonly AuditIssue[]): Promise<string[]>;
20
20
  /** The caller's memories run through the quality audit; a memory that backs an object is never marked for removal. */
21
- export declare function auditMemoryQuality(ctx: Context): AuditResult;
21
+ export declare function auditMemoryQuality(ctx: Context): Promise<AuditResult>;
22
22
  /** Audit repair for the caller's tenant: a preview, or with `apply` the moves of certain defects to dormant storage behind a backup. */
23
- export declare function repairMemoryQuality(ctx: Context, apply: boolean): QualityRepairResult;
23
+ export declare function repairMemoryQuality(ctx: Context, apply: boolean): Promise<QualityRepairResult>;
24
24
  /** The repair sleep and the daily runner apply once per store after an upgrade; null when it already ran there. */
25
- export declare function repairMemoryQualityOnce(ctx: Context): QualityRepairResult | null;
25
+ export declare function repairMemoryQualityOnce(ctx: Context): Promise<QualityRepairResult | null>;
26
26
  export interface PruneAuditOpts {
27
27
  /** Cutoff in days. Rows with `ts < (now - N days)` are deleted. */
28
28
  olderThanDays: number;
@@ -42,5 +42,5 @@ export declare function computeCutoff(days: number, now?: Date): string;
42
42
  /** Delete the caller's tenant's audit_log rows older than `olderThanDays`, then record an `audit_prune` row as `ctx.actor`; opt-in, since
43
43
  * retention floors (HIPAA, SOX, GDPR) apply. The row is written after the DELETE, so a call never prunes its own record.
44
44
  * Throws on non-positive days or an empty tenant. */
45
- export declare function pruneAuditLog(ctx: Context, opts: PruneAuditOpts): PruneAuditResult;
45
+ export declare function pruneAuditLog(ctx: Context, opts: PruneAuditOpts): Promise<PruneAuditResult>;
46
46
  //# sourceMappingURL=audit.d.ts.map
package/dist/api/audit.js CHANGED
@@ -1,37 +1,38 @@
1
1
  // Audit log queries and retention, and the memory-quality audit with its repair passes.
2
- import { pruneAuditRows } from '../store/audit.js';
3
2
  import { auditMemories } from '../core/memory-audit.js';
4
- import { deleteEntriesAutomatically, memoriesBackingObjects } from '../store/delete-and-batch.js';
5
- import { loadAllEntries } from '../store/entry-reads.js';
6
- import { repairAutomaticMemories, repairQualityOnce } from '../store/quality-repair.js';
7
3
  import { DAY_MS } from '../util/time.js';
8
- import { requireGroup, storeFor } from '../store/index.js';
4
+ import { requireGroup } from '../store/index.js';
5
+ import { storeFor } from '../store/sqlite/store.js';
9
6
  /** Read audit events scoped to `ctx.tenantId` on the store the request runs on. Read-only, no audit emit. */
10
7
  export async function auditList(ctx, opts) {
11
8
  return requireGroup(storeFor(ctx), 'auditLog').listAuditEvents({
12
9
  tenantId: ctx.tenantId, op: opts.op, since: opts.since, limit: opts.limit, after: opts.after,
13
10
  });
14
11
  }
12
+ function maintenanceOf(ctx) {
13
+ return requireGroup(storeFor(ctx), 'auditMaintenance');
14
+ }
15
15
  /** Delete the memories an audit marked as errors, each with its own forget row, and answer the ids that went: a pinned or raw row stays. */
16
- export function removeAuditErrors(ctx, pass, issues) {
16
+ export async function removeAuditErrors(ctx, pass, issues) {
17
17
  const removals = issues
18
18
  .filter((issue) => issue.severity === 'error')
19
19
  .map((issue) => ({ id: issue.memoryId, reason: `${pass}: ${issue.reason}` }));
20
- return deleteEntriesAutomatically(ctx.hippoRoot, removals, ctx.actor.subject);
20
+ if (removals.length === 0)
21
+ return [];
22
+ return maintenanceOf(ctx).deleteAutomatically(removals, ctx.actor.subject);
21
23
  }
22
- // SHORTCUT: hippo.db only, as the port has no whole-tenant read, backing-object read or automatic delete with a reason; another store kind
23
- // answers 501 at the open. Port groups for them once a served store must audit.
24
24
  /** The caller's memories run through the quality audit; a memory that backs an object is never marked for removal. */
25
- export function auditMemoryQuality(ctx) {
26
- return auditMemories(loadAllEntries(ctx.hippoRoot, ctx.tenantId), memoriesBackingObjects(ctx.hippoRoot));
25
+ export async function auditMemoryQuality(ctx) {
26
+ const maintenance = maintenanceOf(ctx);
27
+ return auditMemories(await maintenance.tenantEntries(ctx.tenantId), await maintenance.objectBackedIds());
27
28
  }
28
29
  /** Audit repair for the caller's tenant: a preview, or with `apply` the moves of certain defects to dormant storage behind a backup. */
29
- export function repairMemoryQuality(ctx, apply) {
30
- return repairAutomaticMemories(ctx.hippoRoot, { tenantId: ctx.tenantId, apply });
30
+ export async function repairMemoryQuality(ctx, apply) {
31
+ return maintenanceOf(ctx).repairQuality(ctx.tenantId, apply);
31
32
  }
32
33
  /** The repair sleep and the daily runner apply once per store after an upgrade; null when it already ran there. */
33
- export function repairMemoryQualityOnce(ctx) {
34
- return repairQualityOnce(ctx.hippoRoot, ctx.tenantId);
34
+ export async function repairMemoryQualityOnce(ctx) {
35
+ return maintenanceOf(ctx).repairQualityOnce(ctx.tenantId);
35
36
  }
36
37
  /** Cutoff ISO timestamp for N days ago; exported so tests can pin "now" without mocking Date. */
37
38
  export function computeCutoff(days, now = new Date()) {
@@ -41,7 +42,7 @@ export function computeCutoff(days, now = new Date()) {
41
42
  /** Delete the caller's tenant's audit_log rows older than `olderThanDays`, then record an `audit_prune` row as `ctx.actor`; opt-in, since
42
43
  * retention floors (HIPAA, SOX, GDPR) apply. The row is written after the DELETE, so a call never prunes its own record.
43
44
  * Throws on non-positive days or an empty tenant. */
44
- export function pruneAuditLog(ctx, opts) {
45
+ export async function pruneAuditLog(ctx, opts) {
45
46
  if (!Number.isFinite(opts.olderThanDays) || opts.olderThanDays <= 0) {
46
47
  throw new Error(`pruneAuditLog: olderThanDays must be a positive number, got ${opts.olderThanDays}`);
47
48
  }
@@ -50,7 +51,8 @@ export function pruneAuditLog(ctx, opts) {
50
51
  }
51
52
  const dryRun = opts.dryRun === true;
52
53
  const cutoff = computeCutoff(opts.olderThanDays);
53
- const count = pruneAuditRows(ctx.hippoRoot, { tenantId: ctx.tenantId, cutoff, actor: ctx.actor.subject, olderThanDays: opts.olderThanDays, dryRun });
54
+ const prune = { tenantId: ctx.tenantId, cutoff, actor: ctx.actor.subject, olderThanDays: opts.olderThanDays, dryRun };
55
+ const count = await maintenanceOf(ctx).pruneAuditRows(prune);
54
56
  return { cutoff, count, dryRun };
55
57
  }
56
58
  //# sourceMappingURL=audit.js.map
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_KEY_TTL_DAYS, type ApiKeyListItem, type ApiKeyListRow } from '../store/auth.js';
2
2
  import type { KeysetPosition } from '../util/keyset.js';
3
- import { type Context, type StoreReply } from './types.js';
3
+ import { type Context } from './types.js';
4
4
  export interface AuthCreateOpts {
5
5
  label?: string;
6
6
  /** Defaults to `'member'`, which admin-gated routes such as `POST /v1/sleep` refuse; an admin key has to be asked for by name. */
@@ -21,7 +21,7 @@ export interface AuthCreateResult {
21
21
  }
22
22
  /** Mints a key always bound to `ctx.tenantId`; opts cannot override the tenant, or tenant A could mint a key for tenant B.
23
23
  * Admin only (ForbiddenError otherwise), and a key never outranks its minter: a resolver admin is tenant-only, so it mints members. */
24
- export declare function authCreate<C extends Context>(ctx: C, opts: AuthCreateOpts): StoreReply<C, AuthCreateResult>;
24
+ export declare function authCreate(ctx: Context, opts: AuthCreateOpts): Promise<AuthCreateResult>;
25
25
  export { DEFAULT_KEY_TTL_DAYS };
26
26
  export declare const MAX_TTL_DAYS = 3650;
27
27
  export interface AuthCreateSelfOpts {
@@ -37,24 +37,23 @@ export interface AuthCreateSelfResult extends AuthCreateResult {
37
37
  }
38
38
  /** Mint a member key for the caller an auth resolver vouched for, whatever its role; the
39
39
  * binary floor, the cap's revokes, the mint and its audit rows commit or fail together. */
40
- export declare function authCreateSelf<C extends Context>(ctx: C, opts: AuthCreateSelfOpts): StoreReply<C, AuthCreateSelfResult>;
40
+ export declare function authCreateSelf(ctx: Context, opts: AuthCreateSelfOpts): Promise<AuthCreateSelfResult>;
41
41
  type KeyListOpts = {
42
42
  active: boolean;
43
43
  limit?: number;
44
44
  after?: KeysetPosition;
45
45
  };
46
46
  /** One page of the caller's tenant's keys, newest first, with the row ids a next-page cursor is built from. */
47
- export declare function authListRows<C extends Context>(ctx: C, opts: KeyListOpts): StoreReply<C, ApiKeyListRow[]>;
47
+ export declare function authListRows(ctx: Context, opts: KeyListOpts): Promise<ApiKeyListRow[]>;
48
48
  /** Every tenant's keys in the store, live ones only unless `active` is false; the host's own view, so the host admin only. */
49
49
  export declare function authListAllTenants(ctx: Context, active: boolean): ApiKeyListItem[];
50
50
  export interface AuthRevokeResult {
51
51
  ok: true;
52
52
  revokedAt: string;
53
53
  }
54
- export type AuthRevokeReply<C extends Context> = StoreReply<C, AuthRevokeResult>;
55
54
  /** Revoke a key in the caller's tenant: a member API key may revoke only itself, a resolver member only the keys it minted.
56
55
  * The revoke and its auth_revoke row commit together on either store, so a failed audit write leaves the key live. */
57
- export declare function authRevoke<C extends Context>(ctx: C, keyId: string): AuthRevokeReply<C>;
56
+ export declare function authRevoke(ctx: Context, keyId: string): Promise<AuthRevokeResult>;
58
57
  /** The tenant that owns `keyId`, or undefined for an unknown key. Host admin only: it reads across tenants,
59
58
  * so the local CLI can run revoke and grant in the key's own tenant. */
60
59
  export declare function authKeyTenant(ctx: Context, keyId: string): Promise<string | undefined>;
package/dist/api/auth.js CHANGED
@@ -1,10 +1,10 @@
1
1
  // API key management: create, list, revoke, and grant or ungrant restricted scopes.
2
2
  import { BadRequestError, ForbiddenError, NotFoundError } from '../core/api-errors.js';
3
3
  import { DEFAULT_KEY_TTL_DAYS, listApiKeys, mintApiKey, } from '../store/auth.js';
4
- import { storeFor } from '../store/index.js';
4
+ import { requireGroup } from '../store/index.js';
5
+ import { storeFor } from '../store/sqlite/store.js';
5
6
  import { changeScopeGrant } from '../store/sqlite/local.js';
6
7
  import { DAY_MS } from '../util/time.js';
7
- import { andThen, notPorted, onStore } from './on-store.js';
8
8
  import { requireHostAdmin } from './types.js';
9
9
  const API_KEY_SUBJECT = 'api_key:';
10
10
  /** The key id an API-key actor's subject names, or null for any other actor. */
@@ -13,13 +13,12 @@ function keyIdOfSubject(subject) {
13
13
  }
14
14
  /** Mints a key always bound to `ctx.tenantId`; opts cannot override the tenant, or tenant A could mint a key for tenant B.
15
15
  * Admin only (ForbiddenError otherwise), and a key never outranks its minter: a resolver admin is tenant-only, so it mints members. */
16
- export function authCreate(ctx, opts) {
17
- // The key and its auth_create row commit together on either store, so a failed audit write leaves no key.
18
- return onStore(ctx, (port) => {
19
- const keyWrites = port.keyWrites ?? notPorted(port, 'keyWrites');
20
- const { plaintext, mint } = adminKeyMint(ctx, opts);
21
- return andThen(keyWrites.createApiKey(mint), () => createResult(mint, plaintext));
22
- });
16
+ export async function authCreate(ctx, opts) {
17
+ // The key and its auth_create row commit together on every store, so a failed audit write leaves no key.
18
+ const keyWrites = requireGroup(storeFor(ctx), 'keyWrites');
19
+ const { plaintext, mint } = adminKeyMint(ctx, opts);
20
+ await keyWrites.createApiKey(mint);
21
+ return createResult(mint, plaintext);
23
22
  }
24
23
  /** A key row in the caller's tenant, made here so only its hash ever reaches a store. */
25
24
  function newKey(ctx, fields) {
@@ -70,12 +69,11 @@ function assertSelfMintOpts({ ttlDays, perSubject }) {
70
69
  }
71
70
  /** Mint a member key for the caller an auth resolver vouched for, whatever its role; the
72
71
  * binary floor, the cap's revokes, the mint and its audit rows commit or fail together. */
73
- export function authCreateSelf(ctx, opts) {
74
- return onStore(ctx, (port) => {
75
- const keyWrites = port.keyWrites ?? notPorted(port, 'keyWrites');
76
- const { plaintext, mint } = selfKeyMint(ctx, opts);
77
- return andThen(keyWrites.createSelfApiKey(mint), () => selfResult(mint, plaintext));
78
- });
72
+ export async function authCreateSelf(ctx, opts) {
73
+ const keyWrites = requireGroup(storeFor(ctx), 'keyWrites');
74
+ const { plaintext, mint } = selfKeyMint(ctx, opts);
75
+ await keyWrites.createSelfApiKey(mint);
76
+ return selfResult(mint, plaintext);
79
77
  }
80
78
  function selfKeyMint(ctx, opts) {
81
79
  if (!ctx.actor.viaAuthResolver) {
@@ -97,21 +95,20 @@ function selfResult({ key }, plaintext) {
97
95
  return { keyId: key.keyId, plaintext, tenantId: key.tenantId, role: 'member', expiresAt: key.expiresAt };
98
96
  }
99
97
  /** One page of the caller's tenant's keys, newest first, with the row ids a next-page cursor is built from. */
100
- export function authListRows(ctx, opts) {
101
- return onStore(ctx, (port) => listRows(ctx, port, opts));
98
+ export async function authListRows(ctx, opts) {
99
+ return listRows(ctx, storeFor(ctx), opts);
102
100
  }
103
101
  /** Every tenant's keys in the store, live ones only unless `active` is false; the host's own view, so the host admin only. */
104
102
  export function authListAllTenants(ctx, active) {
105
103
  requireHostAdmin(ctx, "Listing every tenant's keys");
106
104
  return listApiKeys(ctx.hippoRoot, { active });
107
105
  }
108
- function listRows(ctx, port, opts) {
109
- const keyWrites = port.keyWrites ?? notPorted(port, 'keyWrites');
106
+ async function listRows(ctx, store, opts) {
107
+ const keyWrites = requireGroup(store, 'keyWrites');
110
108
  const keyId = memberKeyIdOf(ctx.actor);
111
- return andThen(keyId === null ? undefined : port.findApiKey(keyId), (record) => {
112
- const filter = memberListFilter(ctx.actor, record?.ownerSubject);
113
- return filter === null ? [] : keyWrites.listApiKeys({ ...opts, tenantId: ctx.tenantId, ...filter });
114
- });
109
+ const record = keyId === null ? undefined : await store.findApiKey(keyId);
110
+ const filter = memberListFilter(ctx.actor, record?.ownerSubject);
111
+ return filter === null ? [] : keyWrites.listApiKeys({ ...opts, tenantId: ctx.tenantId, ...filter });
115
112
  }
116
113
  /** The key id of a member API key caller, whose owner decides what it lists; null for any other caller. */
117
114
  function memberKeyIdOf(actor) {
@@ -144,16 +141,14 @@ function assertMayRevoke(ctx, keyId, row) {
144
141
  }
145
142
  /** Revoke a key in the caller's tenant: a member API key may revoke only itself, a resolver member only the keys it minted.
146
143
  * The revoke and its auth_revoke row commit together on either store, so a failed audit write leaves the key live. */
147
- export function authRevoke(ctx, keyId) {
148
- return onStore(ctx, (port) => {
149
- const keyAudit = port.keyAudit ?? notPorted(port, 'keyAudit');
150
- assertMemberKeyRevokesSelf(ctx, keyId);
151
- return andThen(port.findApiKey(keyId), (record) => {
152
- assertMayRevoke(ctx, keyId, keyOwnerOf(record));
153
- const revoke = { tenantId: ctx.tenantId, keyId, actor: ctx.actor.subject, at: new Date().toISOString() };
154
- return andThen(keyAudit.revokeApiKey(revoke), (revokedAt) => ({ ok: true, revokedAt }));
155
- });
156
- });
144
+ export async function authRevoke(ctx, keyId) {
145
+ const store = storeFor(ctx);
146
+ const keyAudit = requireGroup(store, 'keyAudit');
147
+ assertMemberKeyRevokesSelf(ctx, keyId);
148
+ const record = await store.findApiKey(keyId);
149
+ assertMayRevoke(ctx, keyId, keyOwnerOf(record));
150
+ const revoke = { tenantId: ctx.tenantId, keyId, actor: ctx.actor.subject, at: new Date().toISOString() };
151
+ return { ok: true, revokedAt: await keyAudit.revokeApiKey(revoke) };
157
152
  }
158
153
  function assertMemberKeyRevokesSelf(ctx, keyId) {
159
154
  if (ctx.actor.role !== 'admin' && !ctx.actor.viaAuthResolver && keyIdOfSubject(ctx.actor.subject) !== keyId) {
@@ -26,7 +26,7 @@ export function resolveMemoryConflict(ctx, conflictId, opts) {
26
26
  if (loadEntriesByIds(ctx.hippoRoot, pair, ctx.tenantId).filter(isLive).length < pair.length) {
27
27
  throw new NotFoundError(`conflict ${conflictId} names a memory that is superseded, archived or quarantined`);
28
28
  }
29
- const resolved = resolveConflict(ctx.hippoRoot, conflictId, opts.keepId, opts.forget === true, ctx.tenantId, {
29
+ const resolved = resolveConflict(ctx.hippoRoot, { conflictId, keepId: opts.keepId, forgetLoser: opts.forget === true, tenantId: ctx.tenantId }, {
30
30
  rejectLoserValue: opts.rejectLoser === true,
31
31
  reason: opts.reason,
32
32
  rejectedBy: ctx.actor.subject,
@@ -1,4 +1,5 @@
1
1
  import { execFileSync } from 'child_process';
2
+ import { errorFields, log } from '../util/log.js';
2
3
  const MAX_DIFF_TERMS = 10;
3
4
  const SKIPPED_PATH_TERMS = ['src', 'dist', 'test', 'tests', 'node_modules', 'index'];
4
5
  // stderr is dropped because git's warnings (line-ending notices, for one) would otherwise become query terms.
@@ -23,8 +24,9 @@ export function autoDetectContext() {
23
24
  return branch.replace(/[-_/]/g, ' ');
24
25
  }
25
26
  }
26
- catch {
27
- // Not a git repo or git missing: no query, so the caller lists by strength.
27
+ catch (err) {
28
+ // Not a git repo, git missing or a timeout: no query, so the caller lists by strength.
29
+ log.debug('auto context: no git-derived query', errorFields(err));
28
30
  }
29
31
  return '';
30
32
  }
@@ -6,8 +6,7 @@ import { auditQueryFields, recordAuditEvent } from '../store/audit.js';
6
6
  import { isWorthSurfacing } from '../core/memory-quality.js';
7
7
  import { rankBothStores } from '../sharing/search-both.js';
8
8
  import { evalNow, strengthAblation } from '../core/ablation.js';
9
- import { hybridSearch } from '../search/hybrid.js';
10
- import { physicsSearchIn } from '../search/physics-search.js';
9
+ import { searchByEngine } from '../search/engine.js';
11
10
  import { DEFAULT_LOCAL_BUMP } from '../core/search-types.js';
12
11
  import { compareScoredResults } from '../core/compare.js';
13
12
  import { scopeMatch } from '../core/active-scope.js';
@@ -279,24 +278,13 @@ async function searchLocalRows(ctx, plan, options) {
279
278
  const localCost = cost && ((r) => price(r.entry, primaryIsGlobal));
280
279
  const vectorCandidates = contextVectorSpec(ctx, plan, admit);
281
280
  const store = plan.local.store;
282
- const ctxResults = usePhysicsCtx
283
- ? await physicsSearchIn({ root: ctx.hippoRoot, store }, query, localEntries, {
284
- budget: left,
285
- minResults,
286
- cost: localCost,
287
- physicsConfig: ctxConfig.physics,
288
- scope: plan.activeScope,
289
- vectorCandidates,
290
- })
291
- : await hybridSearch(query, localEntries, {
292
- budget: left,
293
- minResults,
294
- cost: localCost,
295
- hippoRoot: ctx.hippoRoot,
296
- scope: plan.activeScope,
297
- vectorCandidates,
298
- store,
299
- });
281
+ const ctxResults = await searchByEngine({ root: ctx.hippoRoot, store }, query, localEntries, usePhysicsCtx ? ctxConfig.physics : null, {
282
+ budget: left,
283
+ minResults,
284
+ cost: localCost,
285
+ scope: plan.activeScope,
286
+ vectorCandidates,
287
+ });
300
288
  return ctxResults.map((r) => ({
301
289
  entry: r.entry,
302
290
  score: r.score,
@@ -16,10 +16,10 @@ import { promptTokens } from '../core/prompt-recall.js';
16
16
  import { detectSecret } from '../util/secret-detect.js';
17
17
  import { isSessionDigestRow } from '../core/session-digest-row.js';
18
18
  import { addAmbientTallies, ambientStateFromTallies } from '../core/ambient.js';
19
- import { requireGroup, sqliteStore, storeFor } from '../store/index.js';
19
+ import { hasGroup, requireGroup, sqliteStore } from '../store/index.js';
20
+ import { storeFor } from '../store/sqlite/store.js';
20
21
  import { passesScopeFilterForRecall, assertScopeRequestAllowed, personalScopeOf } from '../core/recall-scope.js';
21
22
  import { finiteOr, selectBySearch, selectPinned, selectStrongest, } from './context-select.js';
22
- import { andThen, onStore } from './on-store.js';
23
23
  import { strengthenOf } from './recall-record.js';
24
24
  import { ownerOrSubject } from './types.js';
25
25
  export { oneCopyPerMemory } from './context-select.js';
@@ -54,7 +54,7 @@ function sourceOf(store) {
54
54
  // The pinned-only branch needs pins and recent-N candidates, not the corpus.
55
55
  async function loadAmbientEntries(source, tenantId, options) {
56
56
  const { pinnedOnly, recent, admit, recheck, window, recall, onQualityDrop } = options;
57
- const ownTenant = (e) => e.tenantId === tenantId;
57
+ const ownTenant = (e) => e.tenant_id === tenantId;
58
58
  if (!pinnedOnly) {
59
59
  const rows = 'query' in window
60
60
  ? await source.store.searchRecallEntries(window.query, {
@@ -139,7 +139,7 @@ function warnIsolationIgnored(hippoRoot) {
139
139
  }
140
140
  /** Which stores this read can draw on, and what kind the primary one is. */
141
141
  function storesInReach(ctx, opts, local) {
142
- const other = local.store.kind !== 'sqlite' ? local.store : undefined;
142
+ const other = hasGroup(local.store, 'localFiles') ? undefined : local.store;
143
143
  // Global memories do not establish a project boundary for task state.
144
144
  const hasLocal = other !== undefined || isInitialized(ctx.hippoRoot);
145
145
  const globalRoot = getGlobalRoot();
@@ -363,7 +363,7 @@ async function traceEmptyContext(ctx, opts, plan) {
363
363
  };
364
364
  // The empty reply is already decided, so a lost trace is logged and the call still answers.
365
365
  try {
366
- await onStore(ctx, (port) => port.finishRecall({ goalLog: [], audit: [], trace }));
366
+ await storeFor(ctx).finishRecall({ goalLog: [], audit: [], trace });
367
367
  }
368
368
  catch (error) {
369
369
  rethrowIfSqliteBlocked(error);
@@ -387,11 +387,13 @@ async function recordRetrieval(ctx, opts, plan, selected, activeSnapshot) {
387
387
  })),
388
388
  };
389
389
  const writes = { goalLog: [], audit: [], trace, strengthen: strengthenOf(ctx, retrievedIds) };
390
- // hippo.db keeps the ids as its last recall, which feeds only outcomeForLastRecall, and it alone reads a second root.
391
- await onStore(ctx, (port, local) => andThen(local.finishLastRecall(writes, plan.hasGlobal ? plan.globalRoot : undefined), (traceId) => {
392
- plan.obs?.traced(traceId);
393
- return port.bumpRecallStats(selected.length);
394
- }));
390
+ // The last recall feeds only outcomeForLastRecall, so a store that keeps none still finishes the recall without one.
391
+ const store = storeFor(ctx);
392
+ const traceId = store.lastRecall
393
+ ? await store.lastRecall.finishRecall(writes, plan.hasGlobal ? plan.globalRoot : undefined)
394
+ : await store.finishRecall(writes).then(() => null);
395
+ plan.obs?.traced(traceId);
396
+ await store.bumpRecallStats(selected.length);
395
397
  // Replace selectedItems entries with markRetrieved-updated copies so
396
398
  // the returned ContextResult reflects post-recall state.
397
399
  const items = selected.map((s) => ({
@@ -1,5 +1,6 @@
1
1
  // DAG drill-down from a summary to its children.
2
- import { requireGroup, storeFor } from '../store/index.js';
2
+ import { requireGroup } from '../store/index.js';
3
+ import { storeFor } from '../store/sqlite/store.js';
3
4
  import { estimateTokens } from '../util/token-text.js';
4
5
  import { passesScopeFilterForRecall, personalScopeOf } from '../core/recall-scope.js';
5
6
  import { classifyOriginProject } from '../core/project-identity.js';
@@ -1,12 +1,12 @@
1
1
  import { type RejectFlowResult } from '../trust/reject-flow.js';
2
- import { type Context, type StoreReply } from './types.js';
2
+ import { type Context } from './types.js';
3
3
  /** Delete a memory by id. Reach is checked inside the delete's write scope, and a
4
4
  * row out of reach answers as not found, so a caller learns nothing about it. */
5
5
  export interface ForgetResult {
6
6
  ok: true;
7
7
  id: string;
8
8
  }
9
- export declare function forget<C extends Context>(ctx: C, id: string): StoreReply<C, ForgetResult>;
9
+ export declare function forget(ctx: Context, id: string): Promise<ForgetResult>;
10
10
  export interface RejectOpts {
11
11
  /** By-id form: reject the CURRENT content of an existing memory. */
12
12
  memoryId?: string;
@@ -1,16 +1,15 @@
1
1
  // Forget a memory, and reject or unreject a value so it cannot be stored again.
2
2
  import { BadRequestError, NotFoundError } from '../core/api-errors.js';
3
3
  import { rejectValue, unrejectValue } from '../trust/reject-flow.js';
4
- import { andThen, notPorted, onStore } from './on-store.js';
4
+ import { requireGroup } from '../store/index.js';
5
+ import { storeFor } from '../store/sqlite/store.js';
5
6
  import { requireHostAdmin } from './types.js';
6
7
  import { getMemory } from './memories.js';
7
8
  import { canTouchScope, personalScopeOf } from '../core/recall-scope.js';
8
- export function forget(ctx, id) {
9
- return onStore(ctx, (port) => {
10
- const entryWrites = port.entryWrites ?? notPorted(port, 'entryWrites');
11
- const removal = { tenantId: ctx.tenantId, actor: ctx.actor.subject, ownScope: personalScopeOf(ctx.actor), id };
12
- return andThen(entryWrites.forget(removal), () => ({ ok: true, id }));
13
- });
9
+ export async function forget(ctx, id) {
10
+ const entryWrites = requireGroup(storeFor(ctx), 'entryWrites');
11
+ await entryWrites.forget({ tenantId: ctx.tenantId, actor: ctx.actor.subject, ownScope: personalScopeOf(ctx.actor), id });
12
+ return { ok: true, id };
14
13
  }
15
14
  /** Tombstones a value's normalized digest so a matching write is refused everywhere until `unreject`; pass exactly one of `memoryId` or `value`.
16
15
  * `memoryId` also removes every live tenant row with that digest (not others' personal rows); `reason` is required. Throws on an unknown id or both/neither. */
package/dist/api/graph.js CHANGED
@@ -1,4 +1,5 @@
1
- import { requireGroup, storeFor } from '../store/index.js';
1
+ import { requireGroup } from '../store/index.js';
2
+ import { storeFor } from '../store/sqlite/store.js';
2
3
  /** The entity/relation rows behind GET /v1/graph, as the caller's role, scopes and owner may see them. */
3
4
  export async function graphRows(ctx, query) {
4
5
  const { role, scopes, owner } = ctx.actor;
@@ -28,7 +28,7 @@ export interface LearnResult {
28
28
  }>;
29
29
  }
30
30
  /** Learn from `repoPath`'s last `days` of commits into the caller's tenant. Host admin only. */
31
- export declare function learn(ctx: Context, opts: LearnOpts): LearnResult;
31
+ export declare function learn(ctx: Context, opts: LearnOpts): Promise<LearnResult>;
32
32
  export type { InvalidationOptions, InvalidationResult, InvalidationTarget };
33
33
  /** `hippo invalidate`: weakens the caller's tenant's memories that reference `target.from`, or only the one `options.onlyId` names. */
34
34
  export declare function invalidateMemories(ctx: Context, target: InvalidationTarget, options: InvalidationOptions): InvalidationResult;