@jungjaehoon/mama-core 2.4.1 → 4.1.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 (378) hide show
  1. package/README.md +76 -239
  2. package/db/migrations/030-case-first-memory-substrate.sql +13 -98
  3. package/db/migrations/034-add-connector-event-scope-columns.sql +9 -13
  4. package/db/migrations/039-add-connector-event-operator-ingest-seq.sql +9 -95
  5. package/db/migrations/062-refresh-connector-event-sequences.sql +9 -113
  6. package/db/migrations/063-refresh-legacy-connector-event-updates.sql +9 -32
  7. package/db/migrations/067-add-connector-event-source-entity-id.sql +9 -13
  8. package/db/migrations/069-create-registry-nodes.sql +52 -0
  9. package/db/migrations/070-record-identity.sql +35 -0
  10. package/db/migrations/071-service-operation-origins.sql +187 -0
  11. package/db/migrations/072-observation-versions.sql +29 -0
  12. package/db/migrations/073-registry-corrections.sql +45 -0
  13. package/db/migrations/074-work-graph-ref-kinds.sql +39 -0
  14. package/db/migrations/075-agent-judgments.sql +58 -0
  15. package/db/migrations/076-scoped-checkpoint-bindings.sql +15 -0
  16. package/db/migrations/077-legacy-record-kind.sql +6 -0
  17. package/db/migrations/078-source-ingest-commands.sql +18 -0
  18. package/db/migrations/079-twin-edge-relations.sql +43 -0
  19. package/db/migrations/080-restore-duration-days.sql +7 -0
  20. package/db/migrations/081-mailbox.sql +61 -0
  21. package/db/migrations/082-commitments-row-id.sql +12 -0
  22. package/db/migrations/083-observation-is-the-evidence.sql +49 -0
  23. package/db/migrations/084-scope-kind-is-not-the-cores-to-list.sql +34 -0
  24. package/db/migrations/085-a-migration-has-a-source.sql +37 -0
  25. package/db/migrations/086-the-mailbox-is-generic.sql +110 -0
  26. package/db/migrations/087-mailbox-payload.sql +5 -0
  27. package/db/migrations/088-native-input-journal.sql +14 -0
  28. package/db/migrations/089-native-turn-receipt-lookup.sql +3 -0
  29. package/db/migrations/090-model-run-native-inputs.sql +29 -0
  30. package/db/migrations/091-native-turn-results.sql +11 -0
  31. package/db/migrations/092-restore-decision-fts.sql +34 -0
  32. package/db/migrations/093-native-turn-primary-kind.sql +14 -0
  33. package/db/migrations/094-commitment-run-provenance.sql +9 -0
  34. package/db/migrations/095-model-run-native-input-identity.sql +39 -0
  35. package/db/migrations/096-drop-connector-event-index-fts.sql +9 -0
  36. package/db/migrations/097-native-input-json-validity.sql +37 -0
  37. package/db/migrations/098-workflow-memory-kind.sql +105 -0
  38. package/db/migrations/099-commitment-revision-graph.sql +2 -0
  39. package/dist/action-contracts.d.ts +212 -0
  40. package/dist/action-contracts.js +10 -0
  41. package/dist/api/catalog.d.ts +118 -0
  42. package/dist/api/catalog.js +1756 -0
  43. package/dist/api/dispatch.d.ts +76 -0
  44. package/dist/api/dispatch.js +372 -0
  45. package/dist/canonicalize.d.ts +2 -2
  46. package/dist/canonicalize.js +3 -3
  47. package/dist/client/client.d.ts +33 -0
  48. package/dist/client/client.js +123 -0
  49. package/dist/client/ipc.d.ts +81 -0
  50. package/dist/client/ipc.js +314 -0
  51. package/dist/db-adapter/base-adapter.d.ts +6 -66
  52. package/dist/db-adapter/base-adapter.js +6 -6
  53. package/dist/db-adapter/index.d.ts +5 -5
  54. package/dist/db-adapter/index.js +2 -5
  55. package/dist/db-adapter/node-sqlite-adapter.d.ts +85 -15
  56. package/dist/db-adapter/node-sqlite-adapter.js +1985 -570
  57. package/dist/db-manager.d.ts +53 -97
  58. package/dist/db-manager.js +121 -603
  59. package/dist/embedding/embedder.d.ts +132 -0
  60. package/dist/embedding/embedder.js +299 -0
  61. package/dist/identity/principal-repository.d.ts +2 -2
  62. package/dist/index.d.ts +43 -58
  63. package/dist/index.js +97 -145
  64. package/dist/{context-compile/channel-grant.d.ts → knowledge/access.d.ts} +12 -17
  65. package/dist/knowledge/access.js +663 -0
  66. package/dist/knowledge/case-errors.d.ts +31 -0
  67. package/dist/knowledge/case-errors.js +40 -0
  68. package/dist/{cases/search-rollup.d.ts → knowledge/case-search-rollup.d.ts} +5 -4
  69. package/dist/{cases/search-rollup.js → knowledge/case-search-rollup.js} +6 -8
  70. package/dist/{cases/store.d.ts → knowledge/case-store.d.ts} +3 -6
  71. package/dist/{cases/store.js → knowledge/case-store.js} +7 -42
  72. package/dist/{cases/timeline-range.d.ts → knowledge/case-timeline-range.d.ts} +3 -3
  73. package/dist/{cases/timeline-range.js → knowledge/case-timeline-range.js} +47 -25
  74. package/dist/{cases/types.d.ts → knowledge/case-types.d.ts} +8 -2
  75. package/dist/{cases/types.js → knowledge/case-types.js} +1 -1
  76. package/dist/knowledge/commitment-revision-migration.d.ts +4 -0
  77. package/dist/knowledge/commitment-revision-migration.js +50 -0
  78. package/dist/knowledge/commitments.d.ts +192 -0
  79. package/dist/knowledge/commitments.js +386 -0
  80. package/dist/knowledge/decision-edges.d.ts +70 -0
  81. package/dist/knowledge/decision-edges.js +123 -0
  82. package/dist/{agent-graph/types.d.ts → knowledge/graph-query.d.ts} +80 -70
  83. package/dist/knowledge/graph-query.js +1585 -0
  84. package/dist/knowledge/identity.d.ts +16 -0
  85. package/dist/knowledge/identity.js +22 -0
  86. package/dist/knowledge/index.d.ts +47 -0
  87. package/dist/knowledge/index.js +90 -0
  88. package/dist/knowledge/judgment-edge.d.ts +6 -0
  89. package/dist/knowledge/judgment-edge.js +22 -0
  90. package/dist/knowledge/judgments.d.ts +118 -0
  91. package/dist/knowledge/judgments.js +802 -0
  92. package/dist/knowledge/observations.d.ts +160 -0
  93. package/dist/knowledge/observations.js +449 -0
  94. package/dist/knowledge/question-type.d.ts +34 -0
  95. package/dist/knowledge/question-type.js +70 -0
  96. package/dist/{search → knowledge}/ranker-features.js +1 -1
  97. package/dist/{search → knowledge}/search-quality.d.ts +0 -1
  98. package/dist/knowledge/search.d.ts +38 -0
  99. package/dist/knowledge/search.js +91 -0
  100. package/dist/knowledge/source-ingest.d.ts +65 -0
  101. package/dist/knowledge/source-ingest.js +174 -0
  102. package/dist/{edges/types.d.ts → knowledge/twin-edge-types.d.ts} +31 -4
  103. package/dist/{edges/types.js → knowledge/twin-edge-types.js} +13 -2
  104. package/dist/knowledge/work-dates.d.ts +49 -0
  105. package/dist/knowledge/work-dates.js +120 -0
  106. package/dist/mama-api.d.ts +114 -778
  107. package/dist/mama-api.js +313 -2461
  108. package/dist/memory/api.d.ts +264 -24
  109. package/dist/memory/api.js +1633 -843
  110. package/dist/memory/bootstrap-builder.d.ts +2 -1
  111. package/dist/memory/bootstrap-builder.js +5 -5
  112. package/dist/memory/channel-summary-state-store.d.ts +3 -2
  113. package/dist/memory/channel-summary-state-store.js +53 -51
  114. package/dist/memory/channel-summary-store.d.ts +5 -3
  115. package/dist/memory/channel-summary-store.js +3 -8
  116. package/dist/memory/dashboard-read.d.ts +46 -0
  117. package/dist/memory/dashboard-read.js +94 -0
  118. package/dist/memory/event-store.d.ts +3 -3
  119. package/dist/memory/event-store.js +3 -10
  120. package/dist/memory/finding-store.d.ts +3 -2
  121. package/dist/memory/finding-store.js +2 -7
  122. package/dist/memory/graph-read.d.ts +52 -0
  123. package/dist/memory/graph-read.js +130 -0
  124. package/dist/memory/judgment-types.d.ts +394 -0
  125. package/dist/memory/judgment-types.js +16 -0
  126. package/dist/memory/provenance-audit.d.ts +5 -2
  127. package/dist/memory/provenance-audit.js +8 -14
  128. package/dist/memory/provenance-live.d.ts +141 -0
  129. package/dist/memory/provenance-live.js +409 -0
  130. package/dist/memory/provenance-query.d.ts +5 -4
  131. package/dist/memory/provenance-query.js +21 -29
  132. package/dist/memory/provenance-resolver.d.ts +191 -0
  133. package/dist/memory/provenance-resolver.js +155 -0
  134. package/dist/memory/provenance.d.ts +1 -11
  135. package/dist/memory/provenance.js +2 -33
  136. package/dist/memory/recall-sanitize.d.ts +55 -0
  137. package/dist/memory/recall-sanitize.js +144 -0
  138. package/dist/memory/secret-filter.d.ts +32 -0
  139. package/dist/memory/secret-filter.js +126 -0
  140. package/dist/memory/truth-store.d.ts +2 -1
  141. package/dist/memory/truth-store.js +1 -4
  142. package/dist/memory/types.d.ts +74 -24
  143. package/dist/memory/types.js +75 -5
  144. package/dist/memory/write-adapters.d.ts +98 -0
  145. package/dist/memory/write-adapters.js +242 -0
  146. package/dist/operations/owner-action-effects.d.ts +53 -0
  147. package/dist/operations/owner-action-effects.js +96 -0
  148. package/dist/provenance/source-ref.d.ts +1 -1
  149. package/dist/provenance/source-ref.js +0 -2
  150. package/dist/registry/corrections.d.ts +31 -0
  151. package/dist/registry/corrections.js +332 -0
  152. package/dist/registry/record-identity.d.ts +49 -0
  153. package/dist/registry/record-identity.js +133 -0
  154. package/dist/registry/store.d.ts +101 -0
  155. package/dist/registry/store.js +395 -0
  156. package/dist/registry/types.d.ts +28 -0
  157. package/dist/registry/types.js +5 -0
  158. package/dist/relevance-scorer.js +2 -2
  159. package/dist/runtime/agent-event-bus.d.ts +50 -0
  160. package/dist/runtime/agent-event-bus.js +101 -0
  161. package/dist/runtime/drivers/claude-cli-wrapper.d.ts +152 -0
  162. package/dist/runtime/drivers/claude-cli-wrapper.js +375 -0
  163. package/dist/runtime/drivers/claude-effort.d.ts +4 -0
  164. package/dist/runtime/drivers/claude-effort.js +16 -0
  165. package/dist/runtime/drivers/cli-arg-redaction.d.ts +2 -0
  166. package/dist/runtime/drivers/cli-arg-redaction.js +18 -0
  167. package/dist/runtime/drivers/cli-secret-redaction.d.ts +17 -0
  168. package/dist/runtime/drivers/cli-secret-redaction.js +126 -0
  169. package/dist/runtime/drivers/codex-app-server-process.d.ts +277 -0
  170. package/dist/runtime/drivers/codex-app-server-process.js +2342 -0
  171. package/dist/runtime/drivers/codex-auxiliary-tools.d.ts +17 -0
  172. package/dist/runtime/drivers/codex-auxiliary-tools.js +267 -0
  173. package/dist/runtime/drivers/codex-home.d.ts +20 -0
  174. package/dist/runtime/drivers/codex-home.js +674 -0
  175. package/dist/runtime/drivers/codex-thread-registry.d.ts +63 -0
  176. package/dist/runtime/drivers/codex-thread-registry.js +433 -0
  177. package/dist/runtime/drivers/persistent-cli-adapter.d.ts +160 -0
  178. package/dist/runtime/drivers/persistent-cli-adapter.js +396 -0
  179. package/dist/runtime/drivers/persistent-cli-process.d.ts +425 -0
  180. package/dist/runtime/drivers/persistent-cli-process.js +1529 -0
  181. package/dist/runtime/drivers/types.d.ts +456 -0
  182. package/dist/runtime/drivers/types.js +110 -0
  183. package/dist/runtime/mailbox.d.ts +223 -0
  184. package/dist/runtime/mailbox.js +582 -0
  185. package/dist/runtime/model-run-store.d.ts +28 -0
  186. package/dist/{model-runs/store.js → runtime/model-run-store.js} +81 -41
  187. package/dist/{model-runs/types.d.ts → runtime/model-run-types.d.ts} +33 -4
  188. package/dist/{model-runs/types.js → runtime/model-run-types.js} +1 -1
  189. package/dist/runtime/native-effect-observer.d.ts +22 -0
  190. package/dist/runtime/native-effect-observer.js +103 -0
  191. package/dist/runtime/native-input-journal.d.ts +46 -0
  192. package/dist/runtime/native-input-journal.js +308 -0
  193. package/dist/runtime/native-prompt.d.ts +118 -0
  194. package/dist/runtime/native-prompt.js +496 -0
  195. package/dist/runtime/native-session.d.ts +10 -0
  196. package/dist/{agent-graph/index.js → runtime/native-session.js} +9 -6
  197. package/dist/runtime/native-tool-trace-observer.d.ts +5 -0
  198. package/dist/runtime/native-tool-trace-observer.js +65 -0
  199. package/dist/runtime/native-turn.d.ts +272 -0
  200. package/dist/runtime/native-turn.js +1041 -0
  201. package/dist/runtime/operations.d.ts +236 -0
  202. package/dist/runtime/operations.js +565 -0
  203. package/dist/runtime/post-tool-handler.d.ts +74 -0
  204. package/dist/runtime/post-tool-handler.js +137 -0
  205. package/dist/runtime/prompt-layers.d.ts +126 -0
  206. package/dist/runtime/prompt-layers.js +239 -0
  207. package/dist/runtime/runtime-process.d.ts +102 -0
  208. package/dist/runtime/runtime-process.js +206 -0
  209. package/dist/runtime/runtime.d.ts +278 -0
  210. package/dist/runtime/runtime.js +563 -0
  211. package/dist/runtime/session-pool.d.ts +176 -0
  212. package/dist/runtime/session-pool.js +369 -0
  213. package/dist/runtime/stimulus-payload.d.ts +5 -0
  214. package/dist/runtime/stimulus-payload.js +50 -0
  215. package/dist/runtime/subagent-bridge.d.ts +24 -0
  216. package/dist/{agent-graph/types.js → runtime/subagent-bridge.js} +1 -1
  217. package/dist/runtime/text-completion.d.ts +22 -0
  218. package/dist/{agent-situation/types.js → runtime/text-completion.js} +1 -1
  219. package/dist/runtime/token-estimator.d.ts +25 -0
  220. package/dist/runtime/token-estimator.js +75 -0
  221. package/dist/runtime/tool-trace-store.d.ts +22 -0
  222. package/dist/{model-runs → runtime}/tool-trace-store.js +46 -27
  223. package/dist/runtime/trace-summary.d.ts +5 -0
  224. package/dist/runtime/trace-summary.js +74 -0
  225. package/dist/runtime/turn-text.d.ts +23 -0
  226. package/dist/runtime/turn-text.js +41 -0
  227. package/dist/storage/database.d.ts +67 -0
  228. package/dist/storage/database.js +158 -0
  229. package/package.json +20 -34
  230. package/dist/agent-graph/alias-write.d.ts +0 -3
  231. package/dist/agent-graph/alias-write.js +0 -234
  232. package/dist/agent-graph/entity-resolve.d.ts +0 -3
  233. package/dist/agent-graph/entity-resolve.js +0 -271
  234. package/dist/agent-graph/errors.d.ts +0 -4
  235. package/dist/agent-graph/errors.js +0 -11
  236. package/dist/agent-graph/graph-query.d.ts +0 -5
  237. package/dist/agent-graph/graph-query.js +0 -360
  238. package/dist/agent-graph/index.d.ts +0 -6
  239. package/dist/agent-situation/builder.d.ts +0 -8
  240. package/dist/agent-situation/builder.js +0 -239
  241. package/dist/agent-situation/cache-key.d.ts +0 -4
  242. package/dist/agent-situation/cache-key.js +0 -64
  243. package/dist/agent-situation/index.d.ts +0 -7
  244. package/dist/agent-situation/index.js +0 -28
  245. package/dist/agent-situation/packet-store.d.ts +0 -27
  246. package/dist/agent-situation/packet-store.js +0 -228
  247. package/dist/agent-situation/ranking-policy.d.ts +0 -18
  248. package/dist/agent-situation/ranking-policy.js +0 -75
  249. package/dist/agent-situation/source-readers.d.ts +0 -52
  250. package/dist/agent-situation/source-readers.js +0 -300
  251. package/dist/agent-situation/types.d.ts +0 -195
  252. package/dist/cases/wiki-page-index.d.ts +0 -37
  253. package/dist/cases/wiki-page-index.js +0 -201
  254. package/dist/config-loader.d.ts +0 -68
  255. package/dist/config-loader.js +0 -239
  256. package/dist/connectors/event-index.d.ts +0 -24
  257. package/dist/connectors/event-index.js +0 -245
  258. package/dist/connectors/raw-query.d.ts +0 -40
  259. package/dist/connectors/raw-query.js +0 -412
  260. package/dist/connectors/types.d.ts +0 -117
  261. package/dist/connectors/types.js +0 -3
  262. package/dist/context-compile/boundary-defaults.d.ts +0 -12
  263. package/dist/context-compile/boundary-defaults.js +0 -105
  264. package/dist/context-compile/channel-grant.js +0 -66
  265. package/dist/context-compile/compiler-policy.d.ts +0 -39
  266. package/dist/context-compile/compiler-policy.js +0 -147
  267. package/dist/context-compile/compiler.d.ts +0 -18
  268. package/dist/context-compile/compiler.js +0 -404
  269. package/dist/context-compile/index.d.ts +0 -10
  270. package/dist/context-compile/index.js +0 -26
  271. package/dist/context-compile/packet-store.d.ts +0 -8
  272. package/dist/context-compile/packet-store.js +0 -239
  273. package/dist/context-compile/ref.d.ts +0 -7
  274. package/dist/context-compile/ref.js +0 -102
  275. package/dist/context-compile/source-readers.d.ts +0 -70
  276. package/dist/context-compile/source-readers.js +0 -840
  277. package/dist/context-compile/types.d.ts +0 -155
  278. package/dist/context-compile/types.js +0 -11
  279. package/dist/context-compile/visibility.d.ts +0 -21
  280. package/dist/context-compile/visibility.js +0 -224
  281. package/dist/decision-tracker.d.ts +0 -206
  282. package/dist/decision-tracker.js +0 -481
  283. package/dist/edges/ref-validation.d.ts +0 -7
  284. package/dist/edges/ref-validation.js +0 -321
  285. package/dist/edges/store.d.ts +0 -8
  286. package/dist/edges/store.js +0 -129
  287. package/dist/embedding-client.d.ts +0 -28
  288. package/dist/embedding-client.js +0 -53
  289. package/dist/embedding-server/index.d.ts +0 -67
  290. package/dist/embedding-server/index.js +0 -405
  291. package/dist/embedding-server/mobile/auth.d.ts +0 -44
  292. package/dist/embedding-server/mobile/auth.js +0 -150
  293. package/dist/embedding-server/mobile/daemon.d.ts +0 -129
  294. package/dist/embedding-server/mobile/daemon.js +0 -313
  295. package/dist/embedding-server/mobile/output-parser.d.ts +0 -115
  296. package/dist/embedding-server/mobile/output-parser.js +0 -241
  297. package/dist/embedding-server/mobile/session-api.d.ts +0 -57
  298. package/dist/embedding-server/mobile/session-api.js +0 -261
  299. package/dist/embedding-server/mobile/session-manager.d.ts +0 -138
  300. package/dist/embedding-server/mobile/session-manager.js +0 -378
  301. package/dist/embedding-server/mobile/websocket-handler.d.ts +0 -137
  302. package/dist/embedding-server/mobile/websocket-handler.js +0 -486
  303. package/dist/embeddings.d.ts +0 -68
  304. package/dist/embeddings.js +0 -244
  305. package/dist/entities/audit-metrics.d.ts +0 -68
  306. package/dist/entities/audit-metrics.js +0 -124
  307. package/dist/entities/candidate-generator.d.ts +0 -8
  308. package/dist/entities/candidate-generator.js +0 -24
  309. package/dist/entities/entity-linked-decision-counts.d.ts +0 -2
  310. package/dist/entities/entity-linked-decision-counts.js +0 -29
  311. package/dist/entities/entity-list.d.ts +0 -22
  312. package/dist/entities/entity-list.js +0 -3
  313. package/dist/entities/entity-orphan-list.d.ts +0 -17
  314. package/dist/entities/entity-orphan-list.js +0 -3
  315. package/dist/entities/entity-search.d.ts +0 -20
  316. package/dist/entities/entity-search.js +0 -3
  317. package/dist/entities/errors.d.ts +0 -55
  318. package/dist/entities/errors.js +0 -100
  319. package/dist/entities/lineage-store.d.ts +0 -28
  320. package/dist/entities/lineage-store.js +0 -204
  321. package/dist/entities/normalization.d.ts +0 -14
  322. package/dist/entities/normalization.js +0 -63
  323. package/dist/entities/policy-store.d.ts +0 -8
  324. package/dist/entities/policy-store.js +0 -75
  325. package/dist/entities/policy-types.d.ts +0 -72
  326. package/dist/entities/policy-types.js +0 -59
  327. package/dist/entities/projection.d.ts +0 -8
  328. package/dist/entities/projection.js +0 -82
  329. package/dist/entities/provenance-query.d.ts +0 -32
  330. package/dist/entities/provenance-query.js +0 -3
  331. package/dist/entities/read-identity.d.ts +0 -31
  332. package/dist/entities/read-identity.js +0 -264
  333. package/dist/entities/recall-bridge.d.ts +0 -5
  334. package/dist/entities/recall-bridge.js +0 -171
  335. package/dist/entities/resolution-engine.d.ts +0 -8
  336. package/dist/entities/resolution-engine.js +0 -3
  337. package/dist/entities/rollback-preview.d.ts +0 -35
  338. package/dist/entities/rollback-preview.js +0 -3
  339. package/dist/entities/source-locator.d.ts +0 -3
  340. package/dist/entities/source-locator.js +0 -32
  341. package/dist/entities/store.d.ts +0 -69
  342. package/dist/entities/store.js +0 -544
  343. package/dist/entities/types.d.ts +0 -166
  344. package/dist/entities/types.js +0 -30
  345. package/dist/memory/extraction-prompt.d.ts +0 -4
  346. package/dist/memory/extraction-prompt.js +0 -89
  347. package/dist/memory/scope-backfill.d.ts +0 -14
  348. package/dist/memory/scope-backfill.js +0 -3
  349. package/dist/memory/scope-store.d.ts +0 -4
  350. package/dist/memory/scope-store.js +0 -9
  351. package/dist/memory-store.d.ts +0 -87
  352. package/dist/memory-store.js +0 -78
  353. package/dist/model-runs/store.d.ts +0 -13
  354. package/dist/model-runs/tool-trace-store.d.ts +0 -8
  355. package/dist/notification-manager.d.ts +0 -7
  356. package/dist/notification-manager.js +0 -12
  357. package/dist/outcome-tracker.d.ts +0 -151
  358. package/dist/outcome-tracker.js +0 -271
  359. package/dist/query-intent.d.ts +0 -23
  360. package/dist/query-intent.js +0 -114
  361. package/dist/runtime/trusted-provenance.d.ts +0 -3
  362. package/dist/runtime/trusted-provenance.js +0 -6
  363. package/dist/search/question-type.d.ts +0 -5
  364. package/dist/search/question-type.js +0 -41
  365. package/dist/test-utils.d.ts +0 -80
  366. package/dist/test-utils.js +0 -218
  367. package/dist/tier-validator.d.ts +0 -43
  368. package/dist/tier-validator.js +0 -159
  369. package/dist/time-formatter.d.ts +0 -25
  370. package/dist/time-formatter.js +0 -93
  371. /package/dist/{search → knowledge}/feedback-store.d.ts +0 -0
  372. /package/dist/{search → knowledge}/feedback-store.js +0 -0
  373. /package/dist/{search → knowledge}/ranker-features.d.ts +0 -0
  374. /package/dist/{search → knowledge}/ranker-rescore.d.ts +0 -0
  375. /package/dist/{search → knowledge}/ranker-rescore.js +0 -0
  376. /package/dist/{search → knowledge}/ranker-trainer.d.ts +0 -0
  377. /package/dist/{search → knowledge}/ranker-trainer.js +0 -0
  378. /package/dist/{search → knowledge}/search-quality.js +0 -0
@@ -0,0 +1,565 @@
1
+ "use strict";
2
+ /**
3
+ * The durable record of what this system actually changed, and what caused it.
4
+ *
5
+ * One table, `evidence_effects`. A `cause_state` CHECK forbids both "attributed
6
+ * with no cause" and "unattributed with a cause", and a BEFORE INSERT trigger
7
+ * rejects unusable cause ids, so the numerator and the denominator of coverage
8
+ * cannot be separated.
9
+ *
10
+ * This lives in core, next to the commitments it describes, for one reason: a
11
+ * change and its cause have to commit or roll back together. While owner work
12
+ * was stored in the daemon's operator database and this ledger beside it, that
13
+ * held. Moving owner work into the knowledge database without moving this would
14
+ * have put a change in one database and its cause in another, and a ledger that
15
+ * can disagree with the rows it describes is worse than no ledger.
16
+ *
17
+ * Every function here takes its adapter, so the caller decides which database is
18
+ * being recorded; nothing is resolved from a global.
19
+ *
20
+ * @module runtime/operations
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.CHANGES_READ_CAUSE_STATES = exports.CHANGES_READ_TARGET_TYPES = exports.OperationError = exports.EffectWithoutCauseError = exports.EVIDENCE_EFFECTS_DDL = void 0;
24
+ exports.isUsableCause = isUsableCause;
25
+ exports.ensureEffectLedger = ensureEffectLedger;
26
+ exports.payloadHash = payloadHash;
27
+ exports.recordEffect = recordEffect;
28
+ exports.recordUnattributedChange = recordUnattributedChange;
29
+ exports.listEffects = listEffects;
30
+ exports.changeCoverage = changeCoverage;
31
+ exports.readOperation = readOperation;
32
+ exports.parseChangesSince = parseChangesSince;
33
+ exports.readChanges = readChanges;
34
+ const node_crypto_1 = require("node:crypto");
35
+ const EFFECT_KINDS = [
36
+ 'task_create',
37
+ 'task_update',
38
+ 'report_update',
39
+ 'report_publish',
40
+ 'memory_write',
41
+ 'wiki_write',
42
+ 'file_export',
43
+ 'repair_request',
44
+ 'run_budget_stop',
45
+ ];
46
+ const EFFECT_TARGETS = [
47
+ 'task',
48
+ 'report_slot',
49
+ 'memory',
50
+ 'wiki_page',
51
+ 'file',
52
+ 'issue',
53
+ 'run',
54
+ ];
55
+ /** Long enough for any upstream id, short enough that the column cannot carry content. */
56
+ const MAX_EVENT_ID_LENGTH = 200;
57
+ const PAYLOAD_HASH_LENGTH = 32;
58
+ /**
59
+ * Whether a value can serve as a cause at all.
60
+ *
61
+ * Callers ask before writing rather than discovering it as a constraint violation,
62
+ * because the answer changes what they record, not whether they may proceed: a malformed
63
+ * cause makes a change unattributed, it does not make the change illegitimate. Legacy
64
+ * rows really do carry 400-character source identifiers, and refusing to let the operator
65
+ * update a work item because its upstream id is the wrong shape would be enforcement
66
+ * bought with the owner's work.
67
+ */
68
+ function isUsableCause(value) {
69
+ if (typeof value !== 'string')
70
+ return false;
71
+ const trimmed = value.trim();
72
+ return trimmed.length > 0 && trimmed.length <= MAX_EVENT_ID_LENGTH;
73
+ }
74
+ const quoted = (values) => values.map((v) => `'${v}'`).join(', ');
75
+ exports.EVIDENCE_EFFECTS_DDL = `
76
+ CREATE TABLE IF NOT EXISTS evidence_effects (
77
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
78
+ run_id TEXT,
79
+ channel_id TEXT,
80
+ cause_state TEXT NOT NULL CHECK (cause_state IN ('attributed', 'unattributed')),
81
+ cause_kind TEXT NOT NULL
82
+ CHECK (cause_kind IN ('event', 'owner_message', 'clock', 'card_transition')),
83
+ source_event_ids_json TEXT NOT NULL
84
+ CHECK (
85
+ json_valid(source_event_ids_json)
86
+ AND (
87
+ (cause_state = 'attributed' AND json_array_length(source_event_ids_json) >= 1)
88
+ OR (cause_state = 'unattributed' AND json_array_length(source_event_ids_json) = 0)
89
+ )
90
+ ),
91
+ effect_kind TEXT NOT NULL CHECK (effect_kind IN (${quoted(EFFECT_KINDS)})),
92
+ target_type TEXT NOT NULL CHECK (target_type IN (${quoted(EFFECT_TARGETS)})),
93
+ target_id TEXT NOT NULL CHECK (length(trim(target_id)) > 0),
94
+ payload_hash TEXT NOT NULL CHECK (length(payload_hash) = ${PAYLOAD_HASH_LENGTH}),
95
+ created_at INTEGER NOT NULL CHECK (typeof(created_at) = 'integer' AND created_at >= 0)
96
+ )
97
+ `;
98
+ /**
99
+ * Per-element shape of the cause list.
100
+ *
101
+ * A trigger rather than a CHECK because SQLite forbids subqueries in CHECK, and checking
102
+ * each element needs `json_each`. Without this the column enforces only "non-empty array",
103
+ * which `[""]` and `[null]` and `[0]` all satisfy while naming nothing.
104
+ *
105
+ * The length bound is not cosmetic: an unbounded cause id turns an audit ledger into a
106
+ * content channel, which is the one thing the payload is hashed to avoid.
107
+ */
108
+ const EVIDENCE_EFFECTS_CAUSE_TRIGGER = `
109
+ CREATE TRIGGER IF NOT EXISTS evidence_effects_cause_shape
110
+ BEFORE INSERT ON evidence_effects
111
+ WHEN EXISTS (
112
+ SELECT 1 FROM json_each(NEW.source_event_ids_json)
113
+ WHERE json_each.type <> 'text'
114
+ OR trim(json_each.value) = ''
115
+ OR length(json_each.value) > ${MAX_EVENT_ID_LENGTH}
116
+ )
117
+ BEGIN
118
+ SELECT RAISE(ABORT, 'evidence_effects: a cause must be a non-empty event id');
119
+ END
120
+ `;
121
+ /**
122
+ * kind <-> ids cross-shape. A trigger (not a table CHECK) so it applies
123
+ * identically to fresh tables and ALTERed old ones: `event` must carry ids,
124
+ * the id-less kinds must not - a clock that names events or an event that
125
+ * names none is a fabricated cause either way.
126
+ */
127
+ const EVIDENCE_EFFECTS_KIND_TRIGGER = `
128
+ CREATE TRIGGER IF NOT EXISTS evidence_effects_kind_shape
129
+ BEFORE INSERT ON evidence_effects
130
+ WHEN (NEW.cause_kind = 'event' AND json_array_length(NEW.source_event_ids_json) = 0)
131
+ OR (NEW.cause_kind <> 'event' AND json_array_length(NEW.source_event_ids_json) > 0)
132
+ BEGIN
133
+ SELECT RAISE(ABORT, 'evidence_effects: cause_kind and source_event_ids disagree');
134
+ END
135
+ `;
136
+ const INDEXES = [
137
+ `CREATE INDEX IF NOT EXISTS idx_evidence_effects_run
138
+ ON evidence_effects(run_id, created_at DESC)`,
139
+ `CREATE INDEX IF NOT EXISTS idx_evidence_effects_target
140
+ ON evidence_effects(target_type, target_id, created_at DESC)`,
141
+ `CREATE INDEX IF NOT EXISTS idx_evidence_effects_channel
142
+ ON evidence_effects(channel_id, created_at DESC)`,
143
+ // Coverage is meant to be cheap enough that nobody has an excuse not to look.
144
+ `CREATE INDEX IF NOT EXISTS idx_evidence_effects_coverage
145
+ ON evidence_effects(created_at DESC, cause_state)`,
146
+ ];
147
+ function ensureEffectLedger(adapter) {
148
+ adapter.prepare(exports.EVIDENCE_EFFECTS_DDL).run();
149
+ migrateCauseKind(adapter);
150
+ widenClosedSets(adapter);
151
+ adapter.prepare(EVIDENCE_EFFECTS_CAUSE_TRIGGER).run();
152
+ adapter.prepare(EVIDENCE_EFFECTS_KIND_TRIGGER).run();
153
+ for (const sql of INDEXES) {
154
+ adapter.prepare(sql).run();
155
+ }
156
+ }
157
+ /**
158
+ * S2 migration: add cause_kind to pre-existing ledgers and backfill by
159
+ * DISCRIMINATOR, never blanket (review #3 - "104 -> clock" would stamp owner-
160
+ * and API-driven changes with a fabricated clock cause):
161
+ * attributed -> event (ids >= 1, DB-checked)
162
+ * unattributed + temporal-effect join -> clock (a temporal check fired)
163
+ * unattributed + run_id present -> clock (scheduled board:full run)
164
+ * remaining unattributed -> owner_message (console/API writes
165
+ * carry no run and no batch)
166
+ * ALTER ADD COLUMN with CHECK is legal SQLite (verified 2026-07-31; the
167
+ * prohibition covers PK/UNIQUE) - no table rebuild.
168
+ */
169
+ function migrateCauseKind(adapter) {
170
+ const columns = adapter.prepare(`PRAGMA table_info(evidence_effects)`).all();
171
+ if (columns.some((column) => column.name === 'cause_kind')) {
172
+ return;
173
+ }
174
+ adapter
175
+ .prepare(`ALTER TABLE evidence_effects ADD COLUMN cause_kind TEXT NOT NULL DEFAULT 'clock'
176
+ CHECK (cause_kind IN ('event', 'owner_message', 'clock', 'card_transition'))`)
177
+ .run();
178
+ adapter
179
+ .prepare(`UPDATE evidence_effects SET cause_kind = 'event' WHERE cause_state = 'attributed'`)
180
+ .run();
181
+ const hasTemporalTable = (adapter
182
+ .prepare(`SELECT 1 AS x FROM sqlite_master WHERE type='table' AND name='operator_temporal_effects'`)
183
+ .all().length ?? 0) > 0;
184
+ if (hasTemporalTable) {
185
+ adapter
186
+ .prepare(`UPDATE evidence_effects SET cause_kind = 'clock'
187
+ WHERE cause_state = 'unattributed'
188
+ AND EXISTS (SELECT 1 FROM operator_temporal_effects t
189
+ WHERE CAST(t.task_id AS TEXT) = evidence_effects.target_id)`)
190
+ .run();
191
+ }
192
+ // run_id-bearing unattributed rows are scheduled runs (board:full and
193
+ // friends): the ALTER's DEFAULT already left them 'clock', which is the
194
+ // intended label - no UPDATE needed (a `cause_kind <> 'clock'` predicate
195
+ // here would be dead code, review).
196
+ adapter
197
+ .prepare(hasTemporalTable
198
+ ? `UPDATE evidence_effects SET cause_kind = 'owner_message'
199
+ WHERE cause_state = 'unattributed' AND run_id IS NULL
200
+ AND NOT EXISTS (SELECT 1 FROM operator_temporal_effects t
201
+ WHERE CAST(t.task_id AS TEXT) = evidence_effects.target_id)`
202
+ : `UPDATE evidence_effects SET cause_kind = 'owner_message'
203
+ WHERE cause_state = 'unattributed' AND run_id IS NULL`)
204
+ .run();
205
+ }
206
+ /**
207
+ * Phase 3 migration: the effect_kind / target_type CHECKs are closed sets baked into the
208
+ * table, and SQLite cannot alter a CHECK in place. When an installed ledger's CHECK is
209
+ * narrower than the current constants, rebuild the table inside one transaction: copy every
210
+ * row with identical ids and created_at, keep the cause_state CHECK and both triggers
211
+ * byte-identical (they are the invariant the ledger rests on), recreate the indices.
212
+ * Detection reads the stored DDL, so a ledger that already carries the current sets is
213
+ * untouched on every later boot.
214
+ */
215
+ function widenClosedSets(adapter) {
216
+ const row = adapter
217
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='evidence_effects'`)
218
+ .all()[0];
219
+ const storedDdl = row?.sql ?? '';
220
+ const missing = [...EFFECT_KINDS, ...EFFECT_TARGETS].filter((value) => !storedDdl.includes(`'${value}'`));
221
+ if (missing.length === 0) {
222
+ return;
223
+ }
224
+ const run = (sql) => adapter.prepare(sql).run();
225
+ run('BEGIN IMMEDIATE');
226
+ try {
227
+ run(exports.EVIDENCE_EFFECTS_DDL.replace('evidence_effects (', 'evidence_effects_new ('));
228
+ run(`INSERT INTO evidence_effects_new
229
+ (id, run_id, channel_id, cause_state, cause_kind, source_event_ids_json,
230
+ effect_kind, target_type, target_id, payload_hash, created_at)
231
+ SELECT id, run_id, channel_id, cause_state, cause_kind, source_event_ids_json,
232
+ effect_kind, target_type, target_id, payload_hash, created_at
233
+ FROM evidence_effects`);
234
+ run('DROP TABLE evidence_effects');
235
+ run('ALTER TABLE evidence_effects_new RENAME TO evidence_effects');
236
+ run(EVIDENCE_EFFECTS_CAUSE_TRIGGER);
237
+ run(EVIDENCE_EFFECTS_KIND_TRIGGER);
238
+ for (const sql of INDEXES) {
239
+ run(sql);
240
+ }
241
+ run('COMMIT');
242
+ }
243
+ catch (error) {
244
+ try {
245
+ run('ROLLBACK');
246
+ }
247
+ catch {
248
+ // BEGIN itself may have failed (busy lock, nested transaction): keep the original error.
249
+ }
250
+ throw error;
251
+ }
252
+ }
253
+ class EffectWithoutCauseError extends Error {
254
+ constructor(kind, targetId) {
255
+ super(`Refusing to record ${kind} on ${targetId} with no source events: a change that cannot name its cause is not an effect.`);
256
+ this.name = 'EffectWithoutCauseError';
257
+ }
258
+ }
259
+ exports.EffectWithoutCauseError = EffectWithoutCauseError;
260
+ /** Stable hash of what was written. The ledger proves a change happened, not what it said. */
261
+ function payloadHash(payload) {
262
+ return (0, node_crypto_1.createHash)('sha256')
263
+ .update(JSON.stringify(payload ?? null))
264
+ .digest('hex')
265
+ .slice(0, PAYLOAD_HASH_LENGTH);
266
+ }
267
+ /**
268
+ * Record a durable change.
269
+ *
270
+ * Throws rather than returning a failure when the cause is missing. A caller that wrote
271
+ * something and then could not say why must not proceed as if the write were accounted
272
+ * for - silently skipping the ledger row is how 1,169 runs closed as `done` while five
273
+ * receipts existed.
274
+ */
275
+ function recordEffect(adapter, input) {
276
+ const sourceEventIds = [
277
+ ...new Set(input.sourceEventIds.filter(isUsableCause).map((id) => id.trim())),
278
+ ];
279
+ if (sourceEventIds.length === 0) {
280
+ throw new EffectWithoutCauseError(input.kind, input.targetId);
281
+ }
282
+ return insertChange(adapter, input, 'event', sourceEventIds);
283
+ }
284
+ /**
285
+ * Record a durable change that could not name what caused it.
286
+ *
287
+ * Deliberately a separate function with an uncomfortable name. Every call is an admission
288
+ * that the system changed something it cannot explain, and the point is that the count of
289
+ * these is visible next to the count of real effects rather than absent from both.
290
+ */
291
+ function recordUnattributedChange(adapter, input, causeKind) {
292
+ return insertChange(adapter, input, causeKind, []);
293
+ }
294
+ function insertChange(adapter, input, causeKind, sourceEventIds) {
295
+ const result = adapter
296
+ .prepare(`INSERT INTO evidence_effects
297
+ (run_id, channel_id, cause_state, cause_kind, source_event_ids_json,
298
+ effect_kind, target_type, target_id, payload_hash, created_at)
299
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
300
+ .run(input.runId ?? null, input.channelId ?? null, causeKind === 'event' ? 'attributed' : 'unattributed', causeKind, JSON.stringify(sourceEventIds), input.kind, input.targetType, input.targetId, payloadHash(input.payload), input.atMs);
301
+ return Number(result.lastInsertRowid ?? 0);
302
+ }
303
+ /** Read effects back, newest first - the substrate a report projects from. */
304
+ function listEffects(adapter, query = {}) {
305
+ const clauses = [];
306
+ const params = [];
307
+ if (query.id !== undefined) {
308
+ clauses.push('id = ?');
309
+ params.push(query.id);
310
+ }
311
+ if (query.runId !== undefined) {
312
+ clauses.push('run_id = ?');
313
+ params.push(query.runId);
314
+ }
315
+ if (query.targetType !== undefined) {
316
+ clauses.push('target_type = ?');
317
+ params.push(query.targetType);
318
+ }
319
+ if (query.targetId !== undefined) {
320
+ clauses.push('target_id = ?');
321
+ params.push(query.targetId);
322
+ }
323
+ if (query.causeState !== undefined) {
324
+ clauses.push('cause_state = ?');
325
+ params.push(query.causeState);
326
+ }
327
+ if (query.sinceMs !== undefined) {
328
+ clauses.push('created_at >= ?');
329
+ params.push(query.sinceMs);
330
+ }
331
+ params.push(Math.min(Math.max(query.limit ?? 200, 1), 1000));
332
+ const rows = adapter
333
+ .prepare(`SELECT * FROM evidence_effects
334
+ ${clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : ''}
335
+ ORDER BY created_at DESC, id DESC
336
+ LIMIT ?`)
337
+ .all(...params);
338
+ return rows.map((row) => ({
339
+ id: Number(row.id),
340
+ runId: typeof row.run_id === 'string' ? row.run_id : null,
341
+ channelId: typeof row.channel_id === 'string' ? row.channel_id : null,
342
+ causeState: String(row.cause_state),
343
+ causeKind: String(row.cause_kind),
344
+ sourceEventIds: JSON.parse(String(row.source_event_ids_json)),
345
+ kind: String(row.effect_kind),
346
+ targetType: String(row.target_type),
347
+ targetId: String(row.target_id),
348
+ payloadHash: String(row.payload_hash),
349
+ atMs: Number(row.created_at),
350
+ }));
351
+ }
352
+ /**
353
+ * How much of what the system changed rests on evidence.
354
+ *
355
+ * The single number this ledger exists to make answerable, and the one the previous shape
356
+ * of the system could not produce at all.
357
+ */
358
+ function changeCoverage(adapter, sinceMs, targetType) {
359
+ // Coverage must describe the same population as the rows a caller is looking at, or the
360
+ // two halves of one answer disagree and the reader cannot tell which is wrong.
361
+ const clauses = [];
362
+ const params = [];
363
+ if (sinceMs !== undefined) {
364
+ clauses.push('created_at >= ?');
365
+ params.push(sinceMs);
366
+ }
367
+ if (targetType !== undefined) {
368
+ clauses.push('target_type = ?');
369
+ params.push(targetType);
370
+ }
371
+ const rows = adapter
372
+ .prepare(`SELECT cause_state, COUNT(*) AS n FROM evidence_effects
373
+ ${clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : ''}
374
+ GROUP BY cause_state`)
375
+ .all(...params);
376
+ const coverage = { attributed: 0, unattributed: 0 };
377
+ for (const row of rows) {
378
+ if (row.cause_state === 'attributed')
379
+ coverage.attributed = Number(row.n);
380
+ if (row.cause_state === 'unattributed')
381
+ coverage.unattributed = Number(row.n);
382
+ }
383
+ return coverage;
384
+ }
385
+ class OperationError extends Error {
386
+ code;
387
+ constructor(code, message) {
388
+ super(message);
389
+ this.name = 'OperationError';
390
+ this.code = code;
391
+ }
392
+ }
393
+ exports.OperationError = OperationError;
394
+ /**
395
+ * §293: start from the command binding — principal, action, original receipt
396
+ * ref — check the caller's authority, then read the actual result. An absent
397
+ * binding and one bound to another principal answer identically: the caller
398
+ * may not learn the id exists.
399
+ */
400
+ function readOperation(adapter, operationId, access) {
401
+ const binding = adapter
402
+ .prepare(`SELECT principal_id, action, payload_hash, receipt_kind, receipt_key, created_at
403
+ FROM command_bindings WHERE command_id = ?`)
404
+ .get(operationId);
405
+ if (binding === undefined || binding.principal_id !== access.principalId) {
406
+ throw new OperationError('OPERATION_UNAVAILABLE', `operation ${operationId} is not available`);
407
+ }
408
+ let receipt = null;
409
+ if (binding.receipt_kind === 'judgment') {
410
+ const row = adapter
411
+ .prepare('SELECT receipt_json FROM judgment_commands WHERE command_id = ?')
412
+ .get(operationId);
413
+ if (row !== undefined) {
414
+ let parsed;
415
+ try {
416
+ parsed = JSON.parse(row.receipt_json);
417
+ }
418
+ catch (error) {
419
+ throw new Error('judgment_commands.receipt_json is malformed', { cause: error });
420
+ }
421
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
422
+ throw new Error('judgment_commands.receipt_json must contain an object');
423
+ }
424
+ receipt = parsed;
425
+ }
426
+ }
427
+ return {
428
+ operationId,
429
+ action: binding.action,
430
+ principalId: binding.principal_id,
431
+ payloadHash: binding.payload_hash,
432
+ boundAt: binding.created_at,
433
+ receiptKind: binding.receipt_kind,
434
+ receiptKey: binding.receipt_key,
435
+ receipt,
436
+ };
437
+ }
438
+ // ── Changes read — the reporting projection over this ledger ───────────────
439
+ // The read side of the effect ledger: what this system changed, and on what
440
+ // evidence. The failure this projection was rewritten for: rows are capped,
441
+ // coverage is not. With 40 attributed and 80 unattributed changes in a window,
442
+ // a default call returned 50 rows - all unattributed, because the newest
443
+ // changes skew that way while `task_update` has no cause field - beside a
444
+ // coverage count saying 40 were explainable, and nothing anywhere saying 120
445
+ // matched. A model reading its own output could truthfully report "nothing I
446
+ // did is explainable". So the counts and the rows must describe the same
447
+ // population, the cap must be visible, and a filter the caller misspells must
448
+ // fail loudly rather than return zero rows - "no rows" and "nothing changed"
449
+ // are the same sentence to a reader, and only one of them is ever true.
450
+ const DEFAULT_WINDOW_MS = 24 * 60 * 60 * 1000;
451
+ const DEFAULT_LIMIT = 50;
452
+ const MAX_LIMIT = 200;
453
+ /** Below this a window is not a window; it is a corrupted number reaching toISOString. */
454
+ const MIN_SINCE_MS = 0;
455
+ // Narrower than EFFECT_TARGETS on purpose: the read filter names only the
456
+ // targets this ledger has ever recorded — file/issue/run effects are writable
457
+ // but no writer produces them, so accepting them as filters would be a promise
458
+ // the ledger cannot keep.
459
+ exports.CHANGES_READ_TARGET_TYPES = [
460
+ 'task',
461
+ 'report_slot',
462
+ 'memory',
463
+ 'wiki_page',
464
+ ];
465
+ exports.CHANGES_READ_CAUSE_STATES = ['attributed', 'unattributed'];
466
+ /**
467
+ * The window a read covers.
468
+ *
469
+ * Unparseable input falls back to the default and the resolved window is returned to the
470
+ * caller, so whatever was asked for, what was actually read is stated. Non-string input is
471
+ * not a window at all - a model emitting epoch milliseconds used to crash the tool on
472
+ * `.trim()`.
473
+ */
474
+ function parseChangesSince(since, nowMs) {
475
+ const raw = typeof since === 'string' ? since.trim() : '';
476
+ if (raw === '')
477
+ return nowMs - DEFAULT_WINDOW_MS;
478
+ // Minutes are here because a caller writing "30m" is entirely ordinary, and without
479
+ // the unit it fell through to the 24-hour default - a window 48x wider than asked for.
480
+ const relative = /^(\d+)\s*([dhm])$/i.exec(raw);
481
+ if (relative) {
482
+ const unit = relative[2].toLowerCase();
483
+ const unitMs = unit === 'd' ? 24 * 60 * 60 * 1000 : unit === 'h' ? 60 * 60 * 1000 : 60 * 1000;
484
+ // Clamped: a window of 99999999999 days is not a request, and an unclamped one
485
+ // produces a timestamp that throws on the way back out.
486
+ return clampSince(nowMs - Number(relative[1]) * unitMs, nowMs);
487
+ }
488
+ const parsed = Date.parse(raw);
489
+ if (Number.isNaN(parsed))
490
+ return nowMs - DEFAULT_WINDOW_MS;
491
+ return clampSince(parsed, nowMs);
492
+ }
493
+ /** A future window returns nothing, and nothing reads as "nothing changed". */
494
+ function clampSince(sinceMs, nowMs) {
495
+ return Math.min(Math.max(sinceMs, MIN_SINCE_MS), nowMs);
496
+ }
497
+ function parseLimit(limit) {
498
+ if (limit === undefined || limit === null)
499
+ return DEFAULT_LIMIT;
500
+ const value = typeof limit === 'string' ? Number(limit.trim()) : limit;
501
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {
502
+ return invalid(`limit must be a positive whole number, got: ${String(limit)}`);
503
+ }
504
+ return Math.min(value, MAX_LIMIT);
505
+ }
506
+ function parseEnum(value, allowed, field) {
507
+ if (value === undefined || value === null || value === '')
508
+ return undefined;
509
+ if (typeof value === 'string' && allowed.includes(value))
510
+ return value;
511
+ // Silently returning zero rows for a misspelt filter is the worst answer available:
512
+ // it is indistinguishable from "nothing changed".
513
+ return invalid(`${field} must be one of ${allowed.join(', ')}, got: ${String(value)}`);
514
+ }
515
+ function invalid(error) {
516
+ return { success: false, code: 'invalid_argument', error };
517
+ }
518
+ function isChangesFailure(value) {
519
+ return (typeof value === 'object' &&
520
+ value !== null &&
521
+ value.success === false);
522
+ }
523
+ function readChanges(ledger, input, nowMs) {
524
+ const limit = parseLimit(input.limit);
525
+ if (isChangesFailure(limit))
526
+ return limit;
527
+ const targetType = parseEnum(input.target_type, exports.CHANGES_READ_TARGET_TYPES, 'target_type');
528
+ if (isChangesFailure(targetType))
529
+ return targetType;
530
+ const causeState = parseEnum(input.cause_state, exports.CHANGES_READ_CAUSE_STATES, 'cause_state');
531
+ if (isChangesFailure(causeState))
532
+ return causeState;
533
+ const sinceMs = parseChangesSince(input.since, nowMs);
534
+ // Coverage is the cause_state breakdown, so it answers within the SAME target scope the
535
+ // rows were drawn from. It deliberately ignores cause_state: filtering the breakdown by
536
+ // one of its own terms would report a zero that only means "I asked for the other one".
537
+ const coverage = ledger.changeCoverage(sinceMs, targetType);
538
+ const matching = coverage.attributed + coverage.unattributed;
539
+ const total = causeState === undefined
540
+ ? matching
541
+ : causeState === 'attributed'
542
+ ? coverage.attributed
543
+ : coverage.unattributed;
544
+ const changes = ledger.listChanges({ sinceMs, targetType, causeState, limit });
545
+ return {
546
+ success: true,
547
+ coverage,
548
+ since: new Date(sinceMs).toISOString(),
549
+ total,
550
+ returned: changes.length,
551
+ changes: changes.map((change) => ({
552
+ effect_id: change.id,
553
+ kind: change.kind,
554
+ target_type: change.targetType,
555
+ target_id: change.targetId,
556
+ cause_state: change.causeState,
557
+ cause_kind: change.causeKind,
558
+ source_event_ids: change.sourceEventIds,
559
+ channel: change.channelId,
560
+ run_id: change.runId,
561
+ at: new Date(change.atMs).toISOString(),
562
+ })),
563
+ };
564
+ }
565
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1,74 @@
1
+ /**
2
+ * After a tool runs, turn what it wrote into memory records, bounded and deduplicated,
3
+ * and fire-and-forget.
4
+ *
5
+ * What is here is the mechanism: notice that an editing tool ran, find the file it
6
+ * touched and the content it produced, ask for candidate records, keep at most a
7
+ * stated number of them, skip the ones already stored, and write the rest. What a
8
+ * candidate *is* is not here. A candidate is vocabulary, and vocabulary belongs to
9
+ * the caller: it supplies the source, and it names the two tools this handler calls.
10
+ *
11
+ * With no source, the handler is inert. That is the intended resting state once the
12
+ * caller's own extractor is gone.
13
+ */
14
+ /** A record the caller wants written when a tool's output yields one. */
15
+ export interface PostToolMemoryCandidate {
16
+ topic: string;
17
+ decision: string;
18
+ reasoning: string;
19
+ confidence: number;
20
+ }
21
+ /**
22
+ * The only thing this handler reads off the caller's execution context: somewhere to
23
+ * register the background task it starts, so the turn that produced the tool result
24
+ * can wait for the write instead of racing it.
25
+ */
26
+ export interface PostToolExecutionContext {
27
+ backgroundTasks?: {
28
+ register(task: Promise<unknown>): void;
29
+ } | null;
30
+ }
31
+ /** Where candidates come from. The caller owns every judgment this makes. */
32
+ export interface PostToolMemorySource {
33
+ /**
34
+ * Candidates this content yields. Return an empty array when the content, the
35
+ * path, or the caller's own rules say nothing should be written.
36
+ */
37
+ candidates(content: string, filePath: string): readonly PostToolMemoryCandidate[];
38
+ }
39
+ export interface PostToolHandlerConfig {
40
+ enabled: boolean;
41
+ /** Tool names whose output is read. A tool matches when its name contains one of these. */
42
+ editTools: readonly string[];
43
+ /** The tool this handler calls to look for an existing record. */
44
+ searchTool: string;
45
+ /** The tool this handler calls to write one. */
46
+ saveTool: string;
47
+ /** At most this many candidates are written per tool result. */
48
+ saveLimit?: number;
49
+ }
50
+ type ExecuteToolFn<Ctx> = (name: string, input: Record<string, unknown>, executionContext?: Ctx | null) => Promise<unknown>;
51
+ export declare class PostToolHandler<Ctx extends PostToolExecutionContext = PostToolExecutionContext> {
52
+ private readonly executeTool;
53
+ private readonly enabled;
54
+ private readonly editTools;
55
+ private readonly searchTool;
56
+ private readonly saveTool;
57
+ private readonly saveLimit;
58
+ private readonly source;
59
+ constructor(executeTool: ExecuteToolFn<Ctx>, config: PostToolHandlerConfig, source?: PostToolMemorySource | null);
60
+ /**
61
+ * Called from the tool-result path. MUST NOT be async, MUST NOT return a promise
62
+ * and MUST NOT throw: a memory write is not allowed to decide whether a turn
63
+ * continues. The task is registered so the turn can still wait for it.
64
+ */
65
+ processInBackground(toolName: string, input: unknown, result: unknown, executionContext?: Ctx | null): void;
66
+ private processAsync;
67
+ private isEditTool;
68
+ private extractFilePath;
69
+ private extractContent;
70
+ private isDuplicate;
71
+ private save;
72
+ }
73
+ export {};
74
+ //# sourceMappingURL=post-tool-handler.d.ts.map