@askdkc/kiokuko 0.1.16 → 0.1.19

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 (549) hide show
  1. package/README.ja.md +91 -112
  2. package/README.ko.md +90 -102
  3. package/README.md +103 -260
  4. package/README.zh-CN.md +88 -102
  5. package/dist/agent-file/atomic-write.d.ts +90 -3
  6. package/dist/agent-file/atomic-write.d.ts.map +1 -1
  7. package/dist/agent-file/atomic-write.js +990 -14
  8. package/dist/agent-file/atomic-write.js.map +1 -1
  9. package/dist/agent-file/managed-block.d.ts +12 -1
  10. package/dist/agent-file/managed-block.d.ts.map +1 -1
  11. package/dist/agent-file/managed-block.js +49 -4
  12. package/dist/agent-file/managed-block.js.map +1 -1
  13. package/dist/agent-file/render.d.ts +1 -1
  14. package/dist/agent-file/render.d.ts.map +1 -1
  15. package/dist/agent-file/render.js +10 -7
  16. package/dist/agent-file/render.js.map +1 -1
  17. package/dist/akinator/agent-task.d.ts +14 -24
  18. package/dist/akinator/agent-task.d.ts.map +1 -1
  19. package/dist/akinator/agent-task.js +460 -103
  20. package/dist/akinator/agent-task.js.map +1 -1
  21. package/dist/akinator/capabilities.d.ts +52 -7
  22. package/dist/akinator/capabilities.d.ts.map +1 -1
  23. package/dist/akinator/capabilities.js +226 -28
  24. package/dist/akinator/capabilities.js.map +1 -1
  25. package/dist/akinator/capability-binding.d.ts +11 -0
  26. package/dist/akinator/capability-binding.d.ts.map +1 -0
  27. package/dist/akinator/capability-binding.js +56 -0
  28. package/dist/akinator/capability-binding.js.map +1 -0
  29. package/dist/akinator/domain.js +2 -2
  30. package/dist/akinator/domain.js.map +1 -1
  31. package/dist/akinator/knowledge-path.d.ts.map +1 -1
  32. package/dist/akinator/knowledge-path.js +409 -39
  33. package/dist/akinator/knowledge-path.js.map +1 -1
  34. package/dist/akinator/orchestrator.d.ts +3 -4
  35. package/dist/akinator/orchestrator.d.ts.map +1 -1
  36. package/dist/akinator/orchestrator.js +1 -4
  37. package/dist/akinator/orchestrator.js.map +1 -1
  38. package/dist/akinator/service.d.ts +0 -4
  39. package/dist/akinator/service.d.ts.map +1 -1
  40. package/dist/akinator/service.js +19 -35
  41. package/dist/akinator/service.js.map +1 -1
  42. package/dist/akinator/skill-discovery-attempt.d.ts +20 -0
  43. package/dist/akinator/skill-discovery-attempt.d.ts.map +1 -0
  44. package/dist/akinator/skill-discovery-attempt.js +390 -0
  45. package/dist/akinator/skill-discovery-attempt.js.map +1 -0
  46. package/dist/akinator/store.d.ts.map +1 -1
  47. package/dist/akinator/store.js +107 -52
  48. package/dist/akinator/store.js.map +1 -1
  49. package/dist/akinator/types.d.ts +0 -12
  50. package/dist/akinator/types.d.ts.map +1 -1
  51. package/dist/bin/kiokuko.js +0 -0
  52. package/dist/cli.d.ts +2 -0
  53. package/dist/cli.d.ts.map +1 -1
  54. package/dist/cli.js +561 -144
  55. package/dist/cli.js.map +1 -1
  56. package/dist/client/server-client.d.ts +5 -3
  57. package/dist/client/server-client.d.ts.map +1 -1
  58. package/dist/client/server-client.js +486 -181
  59. package/dist/client/server-client.js.map +1 -1
  60. package/dist/commands/agent.d.ts +2 -0
  61. package/dist/commands/agent.d.ts.map +1 -1
  62. package/dist/commands/agent.js +861 -86
  63. package/dist/commands/agent.js.map +1 -1
  64. package/dist/commands/backup.d.ts +2 -1
  65. package/dist/commands/backup.d.ts.map +1 -1
  66. package/dist/commands/backup.js +64 -8
  67. package/dist/commands/backup.js.map +1 -1
  68. package/dist/commands/doctor.d.ts +5 -1
  69. package/dist/commands/doctor.d.ts.map +1 -1
  70. package/dist/commands/doctor.js +70 -26
  71. package/dist/commands/doctor.js.map +1 -1
  72. package/dist/commands/export.d.ts +0 -4
  73. package/dist/commands/export.d.ts.map +1 -1
  74. package/dist/commands/export.js +191 -32
  75. package/dist/commands/export.js.map +1 -1
  76. package/dist/commands/import.d.ts +10 -1
  77. package/dist/commands/import.d.ts.map +1 -1
  78. package/dist/commands/import.js +592 -113
  79. package/dist/commands/import.js.map +1 -1
  80. package/dist/commands/init.d.ts +19 -1
  81. package/dist/commands/init.d.ts.map +1 -1
  82. package/dist/commands/init.js +569 -22
  83. package/dist/commands/init.js.map +1 -1
  84. package/dist/commands/purge.d.ts.map +1 -1
  85. package/dist/commands/purge.js +3 -0
  86. package/dist/commands/purge.js.map +1 -1
  87. package/dist/commands/setup.d.ts +34 -8
  88. package/dist/commands/setup.d.ts.map +1 -1
  89. package/dist/commands/setup.js +418 -86
  90. package/dist/commands/setup.js.map +1 -1
  91. package/dist/commands/skills.d.ts +9 -0
  92. package/dist/commands/skills.d.ts.map +1 -0
  93. package/dist/commands/skills.js +317 -0
  94. package/dist/commands/skills.js.map +1 -0
  95. package/dist/commands/use.d.ts +10 -2
  96. package/dist/commands/use.d.ts.map +1 -1
  97. package/dist/commands/use.js +851 -73
  98. package/dist/commands/use.js.map +1 -1
  99. package/dist/config/paths.d.ts +11 -1
  100. package/dist/config/paths.d.ts.map +1 -1
  101. package/dist/config/paths.js +64 -29
  102. package/dist/config/paths.js.map +1 -1
  103. package/dist/config/project-config.d.ts +1 -0
  104. package/dist/config/project-config.d.ts.map +1 -1
  105. package/dist/config/project-config.js +70 -32
  106. package/dist/config/project-config.js.map +1 -1
  107. package/dist/context/broker.d.ts +30 -14
  108. package/dist/context/broker.d.ts.map +1 -1
  109. package/dist/context/broker.js +628 -150
  110. package/dist/context/broker.js.map +1 -1
  111. package/dist/context/delivery.d.ts +8 -22
  112. package/dist/context/delivery.d.ts.map +1 -1
  113. package/dist/context/delivery.js +204 -152
  114. package/dist/context/delivery.js.map +1 -1
  115. package/dist/context/feedback.d.ts +11 -12
  116. package/dist/context/feedback.d.ts.map +1 -1
  117. package/dist/context/feedback.js +250 -268
  118. package/dist/context/feedback.js.map +1 -1
  119. package/dist/context/origin.d.ts +9 -0
  120. package/dist/context/origin.d.ts.map +1 -0
  121. package/dist/context/origin.js +15 -0
  122. package/dist/context/origin.js.map +1 -0
  123. package/dist/context/ranking.d.ts +4 -13
  124. package/dist/context/ranking.d.ts.map +1 -1
  125. package/dist/context/ranking.js +21 -5
  126. package/dist/context/ranking.js.map +1 -1
  127. package/dist/context/recommendations.d.ts +0 -5
  128. package/dist/context/recommendations.d.ts.map +1 -1
  129. package/dist/context/recommendations.js +0 -1
  130. package/dist/context/recommendations.js.map +1 -1
  131. package/dist/context/run-state.d.ts +26 -0
  132. package/dist/context/run-state.d.ts.map +1 -0
  133. package/dist/context/run-state.js +399 -0
  134. package/dist/context/run-state.js.map +1 -0
  135. package/dist/context/scoped-broker.d.ts +19 -6
  136. package/dist/context/scoped-broker.d.ts.map +1 -1
  137. package/dist/context/scoped-broker.js +530 -131
  138. package/dist/context/scoped-broker.js.map +1 -1
  139. package/dist/context/selection-state.d.ts +19 -0
  140. package/dist/context/selection-state.d.ts.map +1 -0
  141. package/dist/context/selection-state.js +250 -0
  142. package/dist/context/selection-state.js.map +1 -0
  143. package/dist/db/adapter.d.ts +5 -3
  144. package/dist/db/adapter.d.ts.map +1 -1
  145. package/dist/db/adapter.js +6 -3
  146. package/dist/db/adapter.js.map +1 -1
  147. package/dist/db/capabilities.d.ts.map +1 -1
  148. package/dist/db/capabilities.js +34 -16
  149. package/dist/db/capabilities.js.map +1 -1
  150. package/dist/db/connection.d.ts +8 -0
  151. package/dist/db/connection.d.ts.map +1 -1
  152. package/dist/db/connection.js +55 -26
  153. package/dist/db/connection.js.map +1 -1
  154. package/dist/db/migrate.d.ts +28 -7
  155. package/dist/db/migrate.d.ts.map +1 -1
  156. package/dist/db/migrate.js +106 -78
  157. package/dist/db/migrate.js.map +1 -1
  158. package/dist/db/sqlite-retry.d.ts +11 -0
  159. package/dist/db/sqlite-retry.d.ts.map +1 -0
  160. package/dist/db/sqlite-retry.js +66 -0
  161. package/dist/db/sqlite-retry.js.map +1 -0
  162. package/dist/db/transaction.d.ts +13 -0
  163. package/dist/db/transaction.d.ts.map +1 -1
  164. package/dist/db/transaction.js +53 -24
  165. package/dist/db/transaction.js.map +1 -1
  166. package/dist/db/upgrade-backup.d.ts +58 -2
  167. package/dist/db/upgrade-backup.d.ts.map +1 -1
  168. package/dist/db/upgrade-backup.js +757 -28
  169. package/dist/db/upgrade-backup.js.map +1 -1
  170. package/dist/errors.js +1 -1
  171. package/dist/errors.js.map +1 -1
  172. package/dist/gateway/agent-service.d.ts +4 -1
  173. package/dist/gateway/agent-service.d.ts.map +1 -1
  174. package/dist/gateway/agent-service.js +71 -58
  175. package/dist/gateway/agent-service.js.map +1 -1
  176. package/dist/gateway/checkpoint-service.d.ts +1 -0
  177. package/dist/gateway/checkpoint-service.d.ts.map +1 -1
  178. package/dist/gateway/checkpoint-service.js +47 -24
  179. package/dist/gateway/checkpoint-service.js.map +1 -1
  180. package/dist/ledger/archive.d.ts +1 -4
  181. package/dist/ledger/archive.d.ts.map +1 -1
  182. package/dist/ledger/archive.js +134 -54
  183. package/dist/ledger/archive.js.map +1 -1
  184. package/dist/ledger/maintenance.d.ts +0 -11
  185. package/dist/ledger/maintenance.d.ts.map +1 -1
  186. package/dist/ledger/maintenance.js +41 -44
  187. package/dist/ledger/maintenance.js.map +1 -1
  188. package/dist/ledger/projection.d.ts +0 -1
  189. package/dist/ledger/projection.d.ts.map +1 -1
  190. package/dist/ledger/projection.js.map +1 -1
  191. package/dist/ledger/promotion.d.ts +0 -9
  192. package/dist/ledger/promotion.d.ts.map +1 -1
  193. package/dist/ledger/promotion.js.map +1 -1
  194. package/dist/ledger/query.d.ts +1 -15
  195. package/dist/ledger/query.d.ts.map +1 -1
  196. package/dist/ledger/query.js.map +1 -1
  197. package/dist/ledger/store.d.ts +0 -1
  198. package/dist/ledger/store.d.ts.map +1 -1
  199. package/dist/ledger/store.js +11 -8
  200. package/dist/ledger/store.js.map +1 -1
  201. package/dist/ledger/types.d.ts +0 -4
  202. package/dist/ledger/types.d.ts.map +1 -1
  203. package/dist/ledger/types.js.map +1 -1
  204. package/dist/ledger/validate.d.ts.map +1 -1
  205. package/dist/ledger/validate.js +0 -5
  206. package/dist/ledger/validate.js.map +1 -1
  207. package/dist/mcp/bounded-stdio-transport.d.ts +23 -0
  208. package/dist/mcp/bounded-stdio-transport.d.ts.map +1 -0
  209. package/dist/mcp/bounded-stdio-transport.js +109 -0
  210. package/dist/mcp/bounded-stdio-transport.js.map +1 -0
  211. package/dist/mcp/server.d.ts +4 -0
  212. package/dist/mcp/server.d.ts.map +1 -1
  213. package/dist/mcp/server.js +111 -75
  214. package/dist/mcp/server.js.map +1 -1
  215. package/dist/memory/audit.d.ts +0 -1
  216. package/dist/memory/audit.d.ts.map +1 -1
  217. package/dist/memory/audit.js +0 -1
  218. package/dist/memory/audit.js.map +1 -1
  219. package/dist/memory/curator.d.ts +45 -1
  220. package/dist/memory/curator.d.ts.map +1 -1
  221. package/dist/memory/curator.js +290 -68
  222. package/dist/memory/curator.js.map +1 -1
  223. package/dist/memory/entries.d.ts +12 -2
  224. package/dist/memory/entries.d.ts.map +1 -1
  225. package/dist/memory/entries.js +198 -114
  226. package/dist/memory/entries.js.map +1 -1
  227. package/dist/memory/federated-retrieval.d.ts +78 -0
  228. package/dist/memory/federated-retrieval.d.ts.map +1 -0
  229. package/dist/memory/federated-retrieval.js +441 -0
  230. package/dist/memory/federated-retrieval.js.map +1 -0
  231. package/dist/memory/hybrid-retrieval.d.ts +5 -11
  232. package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
  233. package/dist/memory/hybrid-retrieval.js +78 -58
  234. package/dist/memory/hybrid-retrieval.js.map +1 -1
  235. package/dist/memory/lifecycle.d.ts.map +1 -1
  236. package/dist/memory/lifecycle.js +17 -13
  237. package/dist/memory/lifecycle.js.map +1 -1
  238. package/dist/memory/portability.d.ts +10 -0
  239. package/dist/memory/portability.d.ts.map +1 -0
  240. package/dist/memory/portability.js +44 -0
  241. package/dist/memory/portability.js.map +1 -0
  242. package/dist/memory/rebuild-search.d.ts +5 -0
  243. package/dist/memory/rebuild-search.d.ts.map +1 -1
  244. package/dist/memory/rebuild-search.js +101 -76
  245. package/dist/memory/rebuild-search.js.map +1 -1
  246. package/dist/memory/retrieval-query.d.ts +0 -5
  247. package/dist/memory/retrieval-query.d.ts.map +1 -1
  248. package/dist/memory/retrieval-query.js +0 -5
  249. package/dist/memory/retrieval-query.js.map +1 -1
  250. package/dist/memory/retrieval.d.ts +11 -0
  251. package/dist/memory/retrieval.d.ts.map +1 -1
  252. package/dist/memory/retrieval.js +34 -120
  253. package/dist/memory/retrieval.js.map +1 -1
  254. package/dist/memory/revisions.d.ts +76 -1
  255. package/dist/memory/revisions.d.ts.map +1 -1
  256. package/dist/memory/revisions.js +539 -35
  257. package/dist/memory/revisions.js.map +1 -1
  258. package/dist/memory/scoped-memory.d.ts +22 -13
  259. package/dist/memory/scoped-memory.d.ts.map +1 -1
  260. package/dist/memory/scoped-memory.js +248 -139
  261. package/dist/memory/scoped-memory.js.map +1 -1
  262. package/dist/memory/secrets.d.ts +2 -0
  263. package/dist/memory/secrets.d.ts.map +1 -1
  264. package/dist/memory/secrets.js +36 -0
  265. package/dist/memory/secrets.js.map +1 -1
  266. package/dist/memory/structured-memory.d.ts +8 -1
  267. package/dist/memory/structured-memory.d.ts.map +1 -1
  268. package/dist/memory/structured-memory.js +74 -20
  269. package/dist/memory/structured-memory.js.map +1 -1
  270. package/dist/memory/workspaces.d.ts +9 -0
  271. package/dist/memory/workspaces.d.ts.map +1 -1
  272. package/dist/memory/workspaces.js +67 -0
  273. package/dist/memory/workspaces.js.map +1 -1
  274. package/dist/package-version.d.ts +2 -0
  275. package/dist/package-version.d.ts.map +1 -0
  276. package/dist/package-version.js +7 -0
  277. package/dist/package-version.js.map +1 -0
  278. package/dist/repository/binding.d.ts +5 -0
  279. package/dist/repository/binding.d.ts.map +1 -1
  280. package/dist/repository/binding.js +117 -17
  281. package/dist/repository/binding.js.map +1 -1
  282. package/dist/repository/framework-version.d.ts +8 -0
  283. package/dist/repository/framework-version.d.ts.map +1 -0
  284. package/dist/repository/framework-version.js +29 -0
  285. package/dist/repository/framework-version.js.map +1 -0
  286. package/dist/repository/identity-value.d.ts +4 -0
  287. package/dist/repository/identity-value.d.ts.map +1 -0
  288. package/dist/repository/identity-value.js +24 -0
  289. package/dist/repository/identity-value.js.map +1 -0
  290. package/dist/repository/identity.d.ts.map +1 -1
  291. package/dist/repository/identity.js +2 -0
  292. package/dist/repository/identity.js.map +1 -1
  293. package/dist/repository/project-fingerprint.d.ts +33 -0
  294. package/dist/repository/project-fingerprint.d.ts.map +1 -0
  295. package/dist/repository/project-fingerprint.js +429 -0
  296. package/dist/repository/project-fingerprint.js.map +1 -0
  297. package/dist/repository/remote-url.d.ts +0 -1
  298. package/dist/repository/remote-url.d.ts.map +1 -1
  299. package/dist/repository/remote-url.js +0 -1
  300. package/dist/repository/remote-url.js.map +1 -1
  301. package/dist/runtime-version.d.ts +2 -1
  302. package/dist/runtime-version.d.ts.map +1 -1
  303. package/dist/runtime-version.js +21 -4
  304. package/dist/runtime-version.js.map +1 -1
  305. package/dist/serialization/boundary-json.d.ts +20 -0
  306. package/dist/serialization/boundary-json.d.ts.map +1 -0
  307. package/dist/serialization/boundary-json.js +129 -0
  308. package/dist/serialization/boundary-json.js.map +1 -0
  309. package/dist/serialization/envelope.js +1 -1
  310. package/dist/serialization/envelope.js.map +1 -1
  311. package/dist/serialization/validate.d.ts +7 -0
  312. package/dist/serialization/validate.d.ts.map +1 -1
  313. package/dist/serialization/validate.js +53 -13
  314. package/dist/serialization/validate.js.map +1 -1
  315. package/dist/server/app.js +1 -1
  316. package/dist/server/app.js.map +1 -1
  317. package/dist/server/http.d.ts +4 -3
  318. package/dist/server/http.d.ts.map +1 -1
  319. package/dist/server/http.js +90 -50
  320. package/dist/server/http.js.map +1 -1
  321. package/dist/server/idempotency.d.ts +0 -6
  322. package/dist/server/idempotency.d.ts.map +1 -1
  323. package/dist/server/idempotency.js.map +1 -1
  324. package/dist/server/router.d.ts.map +1 -1
  325. package/dist/server/router.js +21 -4
  326. package/dist/server/router.js.map +1 -1
  327. package/dist/server/routes/agent-capability-gate.d.ts +40 -0
  328. package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
  329. package/dist/server/routes/agent-capability-gate.js +182 -0
  330. package/dist/server/routes/agent-capability-gate.js.map +1 -0
  331. package/dist/server/routes/agent-events.d.ts.map +1 -1
  332. package/dist/server/routes/agent-events.js +8 -1
  333. package/dist/server/routes/agent-events.js.map +1 -1
  334. package/dist/server/routes/agent-intake.d.ts.map +1 -1
  335. package/dist/server/routes/agent-intake.js +10 -2
  336. package/dist/server/routes/agent-intake.js.map +1 -1
  337. package/dist/server/routes/agent-promotions.d.ts.map +1 -1
  338. package/dist/server/routes/agent-promotions.js +5 -2
  339. package/dist/server/routes/agent-promotions.js.map +1 -1
  340. package/dist/server/routes/agent-runs.d.ts.map +1 -1
  341. package/dist/server/routes/agent-runs.js +18 -4
  342. package/dist/server/routes/agent-runs.js.map +1 -1
  343. package/dist/server/routes/request-binding.d.ts +5 -0
  344. package/dist/server/routes/request-binding.d.ts.map +1 -0
  345. package/dist/server/routes/request-binding.js +49 -0
  346. package/dist/server/routes/request-binding.js.map +1 -0
  347. package/dist/server/routes/task5-support.d.ts +1 -8
  348. package/dist/server/routes/task5-support.d.ts.map +1 -1
  349. package/dist/server/routes/task5-support.js +1 -17
  350. package/dist/server/routes/task5-support.js.map +1 -1
  351. package/dist/server/routes/task5.d.ts.map +1 -1
  352. package/dist/server/routes/task5.js +106 -36
  353. package/dist/server/routes/task5.js.map +1 -1
  354. package/dist/server/write-queue.js +2 -2
  355. package/dist/server/write-queue.js.map +1 -1
  356. package/dist/setup/claude-config.d.ts +2 -1
  357. package/dist/setup/claude-config.d.ts.map +1 -1
  358. package/dist/setup/claude-config.js +54 -4
  359. package/dist/setup/claude-config.js.map +1 -1
  360. package/dist/setup/client-detection.d.ts +7 -2
  361. package/dist/setup/client-detection.d.ts.map +1 -1
  362. package/dist/setup/client-detection.js +27 -9
  363. package/dist/setup/client-detection.js.map +1 -1
  364. package/dist/setup/hermes-config.d.ts +2 -1
  365. package/dist/setup/hermes-config.d.ts.map +1 -1
  366. package/dist/setup/hermes-config.js +53 -12
  367. package/dist/setup/hermes-config.js.map +1 -1
  368. package/dist/setup/legacy-client-cleanup.d.ts +6 -0
  369. package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
  370. package/dist/setup/legacy-client-cleanup.js +152 -0
  371. package/dist/setup/legacy-client-cleanup.js.map +1 -0
  372. package/dist/setup/managed-text.d.ts.map +1 -1
  373. package/dist/setup/managed-text.js +11 -1
  374. package/dist/setup/managed-text.js.map +1 -1
  375. package/dist/setup/opencode-config.d.ts +2 -1
  376. package/dist/setup/opencode-config.d.ts.map +1 -1
  377. package/dist/setup/opencode-config.js +57 -5
  378. package/dist/setup/opencode-config.js.map +1 -1
  379. package/dist/setup/render.d.ts +2 -1
  380. package/dist/setup/render.d.ts.map +1 -1
  381. package/dist/setup/render.js +91 -17
  382. package/dist/setup/render.js.map +1 -1
  383. package/dist/setup/standard-skills.d.ts +16 -2
  384. package/dist/setup/standard-skills.d.ts.map +1 -1
  385. package/dist/setup/standard-skills.js +37 -13
  386. package/dist/setup/standard-skills.js.map +1 -1
  387. package/dist/setup/strict-json.d.ts +7 -0
  388. package/dist/setup/strict-json.d.ts.map +1 -0
  389. package/dist/setup/strict-json.js +98 -0
  390. package/dist/setup/strict-json.js.map +1 -0
  391. package/dist/setup/strict-toml.d.ts +7 -0
  392. package/dist/setup/strict-toml.d.ts.map +1 -0
  393. package/dist/setup/strict-toml.js +470 -0
  394. package/dist/setup/strict-toml.js.map +1 -0
  395. package/dist/skills/cache.d.ts +15 -0
  396. package/dist/skills/cache.d.ts.map +1 -0
  397. package/dist/skills/cache.js +19 -0
  398. package/dist/skills/cache.js.map +1 -0
  399. package/dist/skills/candidate-ranking.d.ts +15 -0
  400. package/dist/skills/candidate-ranking.d.ts.map +1 -0
  401. package/dist/skills/candidate-ranking.js +52 -0
  402. package/dist/skills/candidate-ranking.js.map +1 -0
  403. package/dist/skills/chunking.d.ts +11 -0
  404. package/dist/skills/chunking.d.ts.map +1 -0
  405. package/dist/skills/chunking.js +291 -0
  406. package/dist/skills/chunking.js.map +1 -0
  407. package/dist/skills/config.d.ts +19 -0
  408. package/dist/skills/config.d.ts.map +1 -0
  409. package/dist/skills/config.js +103 -0
  410. package/dist/skills/config.js.map +1 -0
  411. package/dist/skills/discovery-service.d.ts +26 -0
  412. package/dist/skills/discovery-service.d.ts.map +1 -0
  413. package/dist/skills/discovery-service.js +921 -0
  414. package/dist/skills/discovery-service.js.map +1 -0
  415. package/dist/skills/external-transport.d.ts +2 -0
  416. package/dist/skills/external-transport.d.ts.map +1 -0
  417. package/dist/skills/external-transport.js +30 -0
  418. package/dist/skills/external-transport.js.map +1 -0
  419. package/dist/skills/find.d.ts +16 -0
  420. package/dist/skills/find.d.ts.map +1 -0
  421. package/dist/skills/find.js +58 -0
  422. package/dist/skills/find.js.map +1 -0
  423. package/dist/skills/gap-detection.d.ts +23 -0
  424. package/dist/skills/gap-detection.d.ts.map +1 -0
  425. package/dist/skills/gap-detection.js +62 -0
  426. package/dist/skills/gap-detection.js.map +1 -0
  427. package/dist/skills/import-preparation.d.ts +4 -0
  428. package/dist/skills/import-preparation.d.ts.map +1 -0
  429. package/dist/skills/import-preparation.js +20 -0
  430. package/dist/skills/import-preparation.js.map +1 -0
  431. package/dist/skills/materialization-authority.d.ts +11 -0
  432. package/dist/skills/materialization-authority.d.ts.map +1 -0
  433. package/dist/skills/materialization-authority.js +92 -0
  434. package/dist/skills/materialization-authority.js.map +1 -0
  435. package/dist/skills/materialization-service.d.ts +22 -0
  436. package/dist/skills/materialization-service.d.ts.map +1 -0
  437. package/dist/skills/materialization-service.js +101 -0
  438. package/dist/skills/materialization-service.js.map +1 -0
  439. package/dist/skills/official-catalog.d.ts +31 -0
  440. package/dist/skills/official-catalog.d.ts.map +1 -0
  441. package/dist/skills/official-catalog.js +110 -0
  442. package/dist/skills/official-catalog.js.map +1 -0
  443. package/dist/skills/providers/schema.d.ts +30 -0
  444. package/dist/skills/providers/schema.d.ts.map +1 -0
  445. package/dist/skills/providers/schema.js +354 -0
  446. package/dist/skills/providers/schema.js.map +1 -0
  447. package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
  448. package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
  449. package/dist/skills/providers/skills-sh-compat.js +71 -0
  450. package/dist/skills/providers/skills-sh-compat.js.map +1 -0
  451. package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
  452. package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
  453. package/dist/skills/providers/skills-sh-v1.js +134 -0
  454. package/dist/skills/providers/skills-sh-v1.js.map +1 -0
  455. package/dist/skills/query-builder.d.ts +18 -0
  456. package/dist/skills/query-builder.d.ts.map +1 -0
  457. package/dist/skills/query-builder.js +93 -0
  458. package/dist/skills/query-builder.js.map +1 -0
  459. package/dist/skills/source/errors.d.ts +9 -0
  460. package/dist/skills/source/errors.d.ts.map +1 -0
  461. package/dist/skills/source/errors.js +15 -0
  462. package/dist/skills/source/errors.js.map +1 -0
  463. package/dist/skills/source/frontmatter.d.ts +9 -0
  464. package/dist/skills/source/frontmatter.d.ts.map +1 -0
  465. package/dist/skills/source/frontmatter.js +77 -0
  466. package/dist/skills/source/frontmatter.js.map +1 -0
  467. package/dist/skills/source/github-fetcher.d.ts +20 -0
  468. package/dist/skills/source/github-fetcher.d.ts.map +1 -0
  469. package/dist/skills/source/github-fetcher.js +292 -0
  470. package/dist/skills/source/github-fetcher.js.map +1 -0
  471. package/dist/skills/source/snapshot-validator.d.ts +28 -0
  472. package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
  473. package/dist/skills/source/snapshot-validator.js +186 -0
  474. package/dist/skills/source/snapshot-validator.js.map +1 -0
  475. package/dist/skills/store.d.ts +181 -0
  476. package/dist/skills/store.d.ts.map +1 -0
  477. package/dist/skills/store.js +1710 -0
  478. package/dist/skills/store.js.map +1 -0
  479. package/dist/skills/types.d.ts +169 -0
  480. package/dist/skills/types.d.ts.map +1 -0
  481. package/dist/skills/types.js +2 -0
  482. package/dist/skills/types.js.map +1 -0
  483. package/dist/web/i18n.d.ts +56 -8
  484. package/dist/web/i18n.d.ts.map +1 -1
  485. package/dist/web/i18n.js +224 -32
  486. package/dist/web/i18n.js.map +1 -1
  487. package/dist/web/server.d.ts.map +1 -1
  488. package/dist/web/server.js +458 -42
  489. package/dist/web/server.js.map +1 -1
  490. package/dist/web/ui.d.ts +4 -0
  491. package/dist/web/ui.d.ts.map +1 -1
  492. package/dist/web/ui.js +697 -61
  493. package/dist/web/ui.js.map +1 -1
  494. package/migrations/008_federated_memory.sql +46 -0
  495. package/migrations/009_external_skill_discovery.sql +126 -0
  496. package/package.json +6 -3
  497. package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
  498. package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
  499. package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
  500. package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
  501. package/templates/AGENTS.md +8 -7
  502. package/dist/client/runtime-discovery.d.ts +0 -15
  503. package/dist/client/runtime-discovery.d.ts.map +0 -1
  504. package/dist/client/runtime-discovery.js +0 -45
  505. package/dist/client/runtime-discovery.js.map +0 -1
  506. package/dist/commands/call.d.ts +0 -7
  507. package/dist/commands/call.d.ts.map +0 -1
  508. package/dist/commands/call.js +0 -10
  509. package/dist/commands/call.js.map +0 -1
  510. package/dist/commands/link.d.ts +0 -6
  511. package/dist/commands/link.d.ts.map +0 -1
  512. package/dist/commands/link.js +0 -6
  513. package/dist/commands/link.js.map +0 -1
  514. package/dist/commands/promote.d.ts +0 -6
  515. package/dist/commands/promote.d.ts.map +0 -1
  516. package/dist/commands/promote.js +0 -6
  517. package/dist/commands/promote.js.map +0 -1
  518. package/dist/commands/read.d.ts +0 -6
  519. package/dist/commands/read.d.ts.map +0 -1
  520. package/dist/commands/read.js +0 -4
  521. package/dist/commands/read.js.map +0 -1
  522. package/dist/commands/recall.d.ts +0 -6
  523. package/dist/commands/recall.d.ts.map +0 -1
  524. package/dist/commands/recall.js +0 -4
  525. package/dist/commands/recall.js.map +0 -1
  526. package/dist/commands/record.d.ts +0 -6
  527. package/dist/commands/record.d.ts.map +0 -1
  528. package/dist/commands/record.js +0 -4
  529. package/dist/commands/record.js.map +0 -1
  530. package/dist/commands/search.d.ts +0 -6
  531. package/dist/commands/search.d.ts.map +0 -1
  532. package/dist/commands/search.js +0 -4
  533. package/dist/commands/search.js.map +0 -1
  534. package/dist/commands/supersede.d.ts +0 -6
  535. package/dist/commands/supersede.d.ts.map +0 -1
  536. package/dist/commands/supersede.js +0 -6
  537. package/dist/commands/supersede.js.map +0 -1
  538. package/dist/knowledge/sources.d.ts +0 -72
  539. package/dist/knowledge/sources.d.ts.map +0 -1
  540. package/dist/knowledge/sources.js +0 -388
  541. package/dist/knowledge/sources.js.map +0 -1
  542. package/dist/setup/opencode-evidence.d.ts +0 -37
  543. package/dist/setup/opencode-evidence.d.ts.map +0 -1
  544. package/dist/setup/opencode-evidence.js +0 -58
  545. package/dist/setup/opencode-evidence.js.map +0 -1
  546. package/dist/setup/opencode-loop-guard.d.ts +0 -9
  547. package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
  548. package/dist/setup/opencode-loop-guard.js +0 -248
  549. package/dist/setup/opencode-loop-guard.js.map +0 -1
@@ -1,20 +1,103 @@
1
- import { createHash, randomUUID } from 'node:crypto';
2
1
  import { KiokukoError } from '../errors.js';
3
- import { readAkinatorSession, readRunIntakeLink } from '../akinator/store.js';
4
- import { listContextDeliveries, readContextDelivery, recordContextDelivery } from './delivery.js';
5
- import { listContextFeedback } from './feedback.js';
2
+ import { withImmediateTransaction } from '../db/transaction.js';
3
+ import { listContextDeliveries, readContextDelivery, recordContextDeliveryInTransaction, } from './delivery.js';
4
+ import { contextFeedbackSignals } from './feedback.js';
6
5
  import { buildRecommendations, RECOMMENDATION_POLICY_VERSION } from './recommendations.js';
7
- import { CONTEXT_RANKING_VERSION, rankContextCandidates } from './ranking.js';
8
- import { searchEntries } from '../memory/retrieval.js';
9
- import { projectLedger } from '../ledger/projection.js';
10
- import { LedgerStore } from '../ledger/store.js';
11
- import { prepareOfficialSourceSync, persistOfficialSourceSync } from '../knowledge/sources.js';
12
- import { canonicalContentHash } from '../serialization/validate.js';
6
+ import { CONTEXT_RANKING_VERSION, CONTEXT_SELECTION_REASON_ORDER, rankContextCandidates } from './ranking.js';
7
+ import { rankedEntryHits } from '../memory/retrieval.js';
8
+ import { readEntry } from '../memory/entries.js';
9
+ import { decodeStoredStructuredScope, readEntryRevision } from '../memory/revisions.js';
10
+ import { federatedEntries } from '../memory/federated-retrieval.js';
11
+ import { isRetrievableEntry } from '../memory/hybrid-retrieval.js';
12
+ import { GLOBAL_WORKSPACE } from '../memory/workspaces.js';
13
+ import { effectiveRetrievalScope, hasExplicitApplicability } from '../memory/structured-memory.js';
14
+ import { canonicalContentHash, compareCanonicalStrings } from '../serialization/validate.js';
15
+ import { entryOriginMatchesWorkspace } from './origin.js';
16
+ import { isExternalSkillReference } from '../skills/store.js';
17
+ import { contextRetrievalStateHash } from './selection-state.js';
18
+ import { readContextRunRetrievalState } from './run-state.js';
19
+ import { captureProjectManifestSnapshot, resolveProjectFingerprint, } from '../repository/project-fingerprint.js';
13
20
  export const CONTEXT_BROKER_POLICY_VERSION = `${CONTEXT_RANKING_VERSION}+${RECOMMENDATION_POLICY_VERSION}`;
14
21
  export const CONTEXT_BROKER_DEFAULT_LIMIT = 20;
15
22
  export const CONTEXT_BROKER_MAX_LIMIT = 100;
16
23
  export const CONTEXT_BROKER_DEFAULT_CHARACTER_BUDGET = 8_000;
17
24
  export const CONTEXT_BROKER_MAX_CHARACTER_BUDGET = 100_000;
25
+ function normalizedGateDecision(value) {
26
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
27
+ throw new TypeError('Context broker gate returned an invalid decision');
28
+ }
29
+ const prototype = Object.getPrototypeOf(value);
30
+ const keys = Reflect.ownKeys(value);
31
+ if ((prototype !== Object.prototype && prototype !== null)
32
+ || keys.some((key) => typeof key !== 'string'
33
+ || key !== 'persist' && key !== 'value' && key !== 'assertBeforePersist')
34
+ || !keys.includes('persist')
35
+ || !keys.includes('value')) {
36
+ throw new TypeError('Context broker gate returned an invalid decision');
37
+ }
38
+ const persistDescriptor = Object.getOwnPropertyDescriptor(value, 'persist');
39
+ const resultDescriptor = Object.getOwnPropertyDescriptor(value, 'value');
40
+ const assertionDescriptor = Object.getOwnPropertyDescriptor(value, 'assertBeforePersist');
41
+ if (persistDescriptor === undefined
42
+ || !Object.hasOwn(persistDescriptor, 'value')
43
+ || typeof persistDescriptor.value !== 'boolean'
44
+ || resultDescriptor === undefined
45
+ || !Object.hasOwn(resultDescriptor, 'value')
46
+ || assertionDescriptor !== undefined
47
+ && (!Object.hasOwn(assertionDescriptor, 'value') || typeof assertionDescriptor.value !== 'function')) {
48
+ throw new TypeError('Context broker gate returned an invalid decision');
49
+ }
50
+ return {
51
+ persist: persistDescriptor.value,
52
+ value: resultDescriptor.value,
53
+ ...(assertionDescriptor === undefined
54
+ ? {}
55
+ : { assertBeforePersist: assertionDescriptor.value }),
56
+ };
57
+ }
58
+ function contextDeliverySnapshotHash(delivery) {
59
+ return canonicalContentHash({
60
+ workspace: delivery.workspace,
61
+ deliveryId: delivery.deliveryId,
62
+ runId: delivery.runId,
63
+ throughSequence: delivery.throughSequence,
64
+ intakeSessionId: delivery.intakeSessionId,
65
+ taskProfileHash: delivery.taskProfileHash,
66
+ queryHash: delivery.queryHash,
67
+ policyVersion: delivery.policyVersion,
68
+ charBudget: delivery.charBudget,
69
+ charCount: delivery.charCount,
70
+ truncated: delivery.truncated,
71
+ createdAt: delivery.createdAt,
72
+ scoreSchemaVersion: delivery.scoreSchemaVersion ?? 1,
73
+ items: delivery.items.map((item) => ({
74
+ entryId: item.entryId,
75
+ entryRevision: item.entryRevision,
76
+ rank: item.rank,
77
+ scoreComponents: item.scoreComponents,
78
+ selectionReasons: item.selectionReasons,
79
+ ...(item.origin === undefined ? {} : { origin: item.origin }),
80
+ })),
81
+ });
82
+ }
83
+ function assertReplayDeliveryUnchanged(database, expected) {
84
+ let current;
85
+ try {
86
+ current = readContextDelivery(database, {
87
+ workspace: expected.workspace,
88
+ deliveryId: expected.deliveryId,
89
+ });
90
+ }
91
+ catch (error) {
92
+ if (error instanceof KiokukoError && error.code === 'NOT_FOUND') {
93
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context delivery disappeared during replay');
94
+ }
95
+ throw error;
96
+ }
97
+ if (contextDeliverySnapshotHash(current) !== contextDeliverySnapshotHash(expected)) {
98
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context delivery changed during replay');
99
+ }
100
+ }
18
101
  function invalid() {
19
102
  throw new KiokukoError('VALIDATION_ERROR', 'Context query input is invalid');
20
103
  }
@@ -72,58 +155,50 @@ function normalizeInput(input) {
72
155
  ...(value.characterBudget === undefined ? {} : { characterBudget: value.characterBudget }),
73
156
  };
74
157
  }
75
- function parseEventRows(store, runId) {
76
- return store.readEvents(runId).map((row) => {
77
- let payload;
78
- try {
79
- payload = JSON.parse(String(row.payload_json));
80
- }
81
- catch {
82
- throw new KiokukoError('INTEGRITY_ERROR', 'Stored ledger payload is invalid');
83
- }
84
- const snapshot = {
85
- eventId: String(row.event_id),
86
- sequence: Number(row.sequence),
87
- eventType: row.event_type,
88
- ...(row.outcome === null ? {} : { outcome: row.outcome }),
89
- ...(payload === undefined ? {} : { payload: payload }),
90
- };
91
- return snapshot;
92
- });
158
+ function normalizePersistence(value) {
159
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
160
+ throw new TypeError('Context broker persistence adapter is invalid');
161
+ }
162
+ const object = value;
163
+ const prototype = Object.getPrototypeOf(object);
164
+ const keys = Reflect.ownKeys(object);
165
+ const descriptor = Object.getOwnPropertyDescriptor(object, 'enqueueWrite');
166
+ if ((prototype !== Object.prototype && prototype !== null)
167
+ || keys.some((key) => key !== 'enqueueWrite')
168
+ || descriptor !== undefined && !Object.hasOwn(descriptor, 'value')) {
169
+ throw new TypeError('Context broker persistence adapter is invalid');
170
+ }
171
+ const enqueueWrite = descriptor?.value;
172
+ if (enqueueWrite !== undefined && typeof enqueueWrite !== 'function') {
173
+ throw new TypeError('Context broker persistence adapter is invalid');
174
+ }
175
+ return enqueueWrite === undefined
176
+ ? {}
177
+ : { enqueueWrite: enqueueWrite };
93
178
  }
94
179
  function currentRunContext(database, runId) {
95
- const run = new LedgerStore(database).readRun(runId);
96
- if (!run)
97
- notFound();
98
- const link = readRunIntakeLink(database, { workspace: run.workspace, runId });
99
- const session = readAkinatorSession(database, { workspace: run.workspace, sessionId: link.sessionId });
100
- const status = session.status;
101
- if (status === 'active') {
102
- return {
103
- run,
104
- profile: session.profile,
105
- profileHash: link.initialProfileHash ?? canonicalContentHash(session.profile),
106
- recommendedTags: [...link.recommendedTags],
107
- intakeSessionId: link.sessionId,
108
- intakeStatus: status,
109
- projection: null,
110
- };
180
+ try {
181
+ return readContextRunRetrievalState(database, runId);
111
182
  }
112
- const projection = projectLedger({
113
- initialProfile: session.profile,
114
- intakeStatus: status,
115
- coverage: run.coverage,
116
- throughSequence: run.lastSequence,
117
- events: parseEventRows(new LedgerStore(database), runId),
118
- });
183
+ catch (error) {
184
+ if (error instanceof KiokukoError
185
+ && error.code === 'NOT_FOUND'
186
+ && error.message === 'Context run was not found') {
187
+ notFound();
188
+ }
189
+ throw error;
190
+ }
191
+ }
192
+ /** Read the same authoritative run/intake/profile snapshot used to rank broker context. */
193
+ export function readContextBrokerRunState(database, runId) {
194
+ const current = currentRunContext(database, runId);
119
195
  return {
120
- run,
121
- profile: projection.taskProfile,
122
- profileHash: projection.profileHash,
123
- recommendedTags: [...link.recommendedTags],
124
- intakeSessionId: link.sessionId,
125
- intakeStatus: status,
126
- projection,
196
+ run: current.run,
197
+ taskProfile: { ...current.profile },
198
+ profileHash: current.profileHash,
199
+ recommendedTags: [...current.recommendedTags],
200
+ intakeSessionId: current.intakeSessionId,
201
+ status: current.intakeStatus === 'active' ? 'needs_answer' : current.intakeStatus,
127
202
  };
128
203
  }
129
204
  function preparedQuery(database, input) {
@@ -136,6 +211,21 @@ function preparedQuery(database, input) {
136
211
  const throughSequence = runContext?.run.lastSequence ?? 0;
137
212
  const taskProfileHash = runContext?.profileHash ?? canonicalContentHash(profile);
138
213
  const recommendedTags = runContext?.recommendedTags ?? input.recommendedTags ?? [];
214
+ const workspace = runContext?.run.workspace ?? requestedWorkspace;
215
+ const project = projectForWorkspace(database, workspace);
216
+ const projectState = project === undefined
217
+ ? null
218
+ : {
219
+ project,
220
+ fingerprint: resolveProjectFingerprint(database, project, captureProjectManifestSnapshot(project)),
221
+ };
222
+ const includeEcosystem = projectState !== null;
223
+ const selectionWorkspaces = !includeEcosystem
224
+ ? [workspace]
225
+ : [workspace, GLOBAL_WORKSPACE];
226
+ const retrievalStateHash = runContext === null || runContext.intakeStatus !== 'active'
227
+ ? contextRetrievalStateHash(database, selectionWorkspaces, { includeEcosystem })
228
+ : null;
139
229
  const queryShape = {
140
230
  runId: input.runId ?? null,
141
231
  workspace: input.runId === undefined ? requestedWorkspace : null,
@@ -147,10 +237,15 @@ function preparedQuery(database, input) {
147
237
  throughSequence,
148
238
  characterBudget: input.characterBudget ?? CONTEXT_BROKER_DEFAULT_CHARACTER_BUDGET,
149
239
  limit: input.limit ?? CONTEXT_BROKER_DEFAULT_LIMIT,
240
+ projectState,
241
+ retrievalStateHash,
242
+ runStateHash: runContext?.stateHash ?? null,
150
243
  };
151
244
  const queryHash = canonicalContentHash(queryShape);
152
245
  return {
153
- workspace: runContext?.run.workspace ?? requestedWorkspace,
246
+ workspace,
247
+ selectionWorkspaces,
248
+ includeEcosystem,
154
249
  run: runContext?.run ?? null,
155
250
  taskProfile: profile,
156
251
  profileHash: taskProfileHash,
@@ -164,11 +259,16 @@ function preparedQuery(database, input) {
164
259
  intakeSessionId: runContext?.intakeSessionId ?? null,
165
260
  projection: runContext?.projection ?? null,
166
261
  runStatus: runContext === null ? 'unbound' : runContext.intakeStatus === 'active' ? 'needs_answer' : runContext.intakeStatus,
262
+ projectState,
263
+ retrievalStateHash,
264
+ runStateHash: runContext?.stateHash ?? null,
265
+ deliveryHistoryStateHash: null,
266
+ deliveryHistoryExcludeQueryHash: null,
167
267
  queryHash,
168
- deliveryId: input.runId === undefined ? null : `context-${queryHash}`,
268
+ deliveryId: null,
169
269
  };
170
270
  }
171
- function entrySnapshot(entry) {
271
+ function entrySnapshot(entry, origin, selectionReasons = []) {
172
272
  return {
173
273
  id: entry.id,
174
274
  revision: entry.revision,
@@ -182,69 +282,213 @@ function entrySnapshot(entry) {
182
282
  tags: [...entry.tags],
183
283
  scope: entry.scope,
184
284
  updatedAt: entry.updatedAt,
285
+ selectionReasons: [...selectionReasons],
286
+ ...(origin === undefined ? {} : { origin }),
185
287
  };
186
288
  }
187
289
  function retrievalQuery(query) {
188
290
  const values = [query.task, query.taskProfile.target, query.taskProfile.expected, ...query.recommendedTags].filter((value) => value !== null && value.length > 0);
189
291
  return values.join(' ').slice(0, 16_384) || 'kiokuko';
190
292
  }
191
- function retrieveEntries(database, query) {
293
+ const APPLICABILITY_DETAIL_REASONS = new Set([
294
+ 'language_match',
295
+ 'database_match',
296
+ 'runtime_match',
297
+ 'tool_match',
298
+ 'platform_match',
299
+ 'framework_exact_match',
300
+ 'framework_match',
301
+ ]);
302
+ function canonicalRetrievedReasons(reasons) {
303
+ const normalized = reasons.map((reason) => {
304
+ if (APPLICABILITY_DETAIL_REASONS.has(reason))
305
+ return 'applicability_match';
306
+ if (CONTEXT_SELECTION_REASON_ORDER.includes(reason))
307
+ return reason;
308
+ throw new KiokukoError('INTEGRITY_ERROR', 'Retrieval returned an unknown selection reason');
309
+ });
310
+ const rank = (reason) => CONTEXT_SELECTION_REASON_ORDER.indexOf(reason);
311
+ return [...new Set(normalized)].sort((left, right) => rank(left) - rank(right) || compareCanonicalStrings(left, right));
312
+ }
313
+ function addRetrievedEntry(entries, value) {
314
+ const existing = entries.get(value.entry.id);
315
+ entries.set(value.entry.id, {
316
+ ...value,
317
+ selectionReasons: canonicalRetrievedReasons([...(existing?.selectionReasons ?? []), ...value.selectionReasons]),
318
+ });
319
+ }
320
+ function projectForWorkspace(database, workspace) {
321
+ const row = database.prepare(`
322
+ SELECT r.repository_id AS repositoryId, r.workspace, l.canonical_root AS repositoryRoot
323
+ FROM repositories AS r JOIN repository_locations AS l ON l.repository_id = r.repository_id
324
+ WHERE r.workspace = ? ORDER BY l.last_seen_at DESC, l.canonical_root ASC LIMIT 1
325
+ `).get(workspace);
326
+ if (row === undefined)
327
+ return undefined;
328
+ const { repositoryId, repositoryRoot, workspace: storedWorkspace } = row;
329
+ if (typeof repositoryId !== 'string' || repositoryId.length === 0
330
+ || typeof storedWorkspace !== 'string' || storedWorkspace !== workspace
331
+ || typeof repositoryRoot !== 'string' || repositoryRoot.length === 0) {
332
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context project binding is invalid');
333
+ }
334
+ return { repositoryRoot, repositoryId, workspace: storedWorkspace, source: 'location' };
335
+ }
336
+ async function retrieveEntries(database, query) {
192
337
  const terms = [query.task, query.taskProfile.target, query.taskProfile.expected, ...query.recommendedTags]
193
338
  .filter((value) => value !== null && value.length > 0)
194
339
  .map((value) => value.slice(0, 2_000));
195
340
  const queries = [retrievalQuery(query), ...terms];
196
341
  const entries = new Map();
197
342
  for (const value of queries) {
198
- for (const entry of searchEntries(database, { workspace: query.workspace, query: value, limit: 500, includeSuperseded: false }).items) {
199
- entries.set(entry.id, entry);
343
+ if (query.projectState !== null) {
344
+ for (const hit of await federatedEntries(database, {
345
+ project: query.projectState.project,
346
+ fingerprint: query.projectState.fingerprint,
347
+ query: value,
348
+ limit: 500,
349
+ })) {
350
+ addRetrievedEntry(entries, { entry: hit.entry, origin: hit.origin, selectionReasons: hit.selectionReasons });
351
+ }
352
+ }
353
+ else {
354
+ for (const hit of rankedEntryHits(database, { workspace: query.workspace, query: value, limit: 500, includeSuperseded: false }).hits) {
355
+ addRetrievedEntry(entries, {
356
+ entry: readEntry(database, { workspace: query.workspace, entryId: hit.entryId }),
357
+ origin: 'project',
358
+ selectionReasons: ['project_origin', ...hit.reasons],
359
+ });
360
+ }
200
361
  }
201
362
  }
202
363
  return [...entries.values()];
203
364
  }
204
- function priorData(database, query) {
365
+ function assertPreparedProjectState(database, query) {
366
+ const currentProject = projectForWorkspace(database, query.workspace);
367
+ if (query.projectState === null) {
368
+ if (currentProject !== undefined) {
369
+ throw new KiokukoError('CONFLICT', 'Context project state changed after ranking');
370
+ }
371
+ return;
372
+ }
373
+ if (currentProject === undefined
374
+ || canonicalContentHash(currentProject) !== canonicalContentHash(query.projectState.project)) {
375
+ throw new KiokukoError('CONFLICT', 'Context project state changed after ranking');
376
+ }
377
+ const manifestSnapshot = captureProjectManifestSnapshot(currentProject);
378
+ if (manifestSnapshot.manifestDigest !== query.projectState.fingerprint.manifestDigest) {
379
+ throw new KiokukoError('CONFLICT', 'Context project state changed after ranking');
380
+ }
381
+ const currentFingerprint = resolveProjectFingerprint(database, currentProject, manifestSnapshot, { readOnly: true });
382
+ if (canonicalContentHash(currentFingerprint) !== canonicalContentHash(query.projectState.fingerprint)) {
383
+ throw new KiokukoError('CONFLICT', 'Context project state changed after ranking');
384
+ }
385
+ }
386
+ async function rank(database, query, prior) {
387
+ const entries = await retrieveEntries(database, query);
388
+ const feedback = entries.flatMap(({ entry }) => contextFeedbackSignals(database, entry.id).flatMap((signal) => Array.from({ length: signal.boundedInfluence }, () => ({ entryId: entry.id, verdict: signal.verdict }))));
389
+ return rankContextCandidates({
390
+ taskProfile: query.taskProfile,
391
+ recommendedTags: query.recommendedTags,
392
+ changedPaths: query.changedPaths,
393
+ errorSignatures: query.errorSignatures,
394
+ priorDelivered: prior.delivered,
395
+ feedback,
396
+ candidates: entries.map(({ entry, origin, selectionReasons }) => entrySnapshot(entry, origin, selectionReasons)),
397
+ limit: query.limit,
398
+ characterBudget: query.characterBudget,
399
+ });
400
+ }
401
+ function priorData(database, query, options = {}) {
205
402
  if (query.run === null)
206
- return { delivered: [], feedback: [], stale: [] };
403
+ return { delivered: [], stale: [], stateHash: null };
207
404
  const deliveries = [];
208
405
  let cursor;
406
+ let complete = false;
209
407
  for (let page = 0; page < 10; page += 1) {
210
408
  const result = listContextDeliveries(database, { workspace: query.workspace, runId: query.run.runId, limit: 100, ...(cursor === undefined ? {} : { cursor }) });
211
409
  deliveries.push(...result.items);
212
- if (result.nextCursor === null)
410
+ if (result.nextCursor === null) {
411
+ complete = true;
213
412
  break;
413
+ }
214
414
  cursor = result.nextCursor;
215
415
  }
216
- const delivered = deliveries.flatMap((delivery) => delivery.items.map((item) => ({ entryId: item.entryId, revision: item.entryRevision })));
217
- const feedbackPage = listContextFeedback(database, { workspace: query.workspace, runId: query.run.runId, limit: 100 });
218
- const feedback = feedbackPage.records.map((record) => ({ entryId: record.entryId, verdict: record.verdict }));
219
- const stale = deliveries.flatMap((delivery) => delivery.items.flatMap((item) => {
416
+ if (!complete) {
417
+ throw new KiokukoError('INTEGRITY_ERROR', 'Context delivery history exceeds the broker policy bound');
418
+ }
419
+ for (const delivery of deliveries) {
420
+ for (const item of delivery.items) {
421
+ currentRetrievableDeliveryEntry(database, query.workspace, item);
422
+ }
423
+ }
424
+ const stateDeliveries = deliveries.filter((delivery) => delivery.deliveryId !== options.excludeDeliveryId);
425
+ const delivered = stateDeliveries
426
+ .filter((delivery) => delivery.queryHash !== options.excludeDeliveredQueryHash)
427
+ .flatMap((delivery) => delivery.items.flatMap((item) => contextFeedbackSignals(database, item.entryId)
428
+ .some((signal) => signal.verdict === 'helpful')
429
+ ? []
430
+ : [{ entryId: item.entryId, revision: item.entryRevision }]));
431
+ const stale = stateDeliveries.flatMap((delivery) => delivery.items.flatMap((item) => {
220
432
  const current = database.prepare('SELECT current_revision FROM entries WHERE id = ?').get(item.entryId);
221
433
  return current && Number(current.current_revision) > item.entryRevision ? [{ entryId: item.entryId, deliveredRevision: item.entryRevision, currentRevision: Number(current.current_revision), stale: true }] : [];
222
434
  }));
223
- return { delivered, feedback, stale };
435
+ return {
436
+ delivered,
437
+ stale,
438
+ stateHash: canonicalContentHash({
439
+ runId: query.run.runId,
440
+ excludeDeliveredQueryHash: options.excludeDeliveredQueryHash ?? null,
441
+ deliveries: stateDeliveries.map(contextDeliverySnapshotHash),
442
+ delivered,
443
+ stale,
444
+ }),
445
+ };
224
446
  }
225
- function rank(database, query, prior) {
226
- const entries = retrieveEntries(database, query);
227
- return rankContextCandidates({
228
- taskProfile: query.taskProfile,
229
- recommendedTags: query.recommendedTags,
230
- changedPaths: query.changedPaths,
231
- errorSignatures: query.errorSignatures,
232
- priorDelivered: prior.delivered,
233
- feedback: prior.feedback,
234
- candidates: entries.map(entrySnapshot),
235
- limit: query.limit,
236
- characterBudget: query.characterBudget,
447
+ function historyAttestedDeliveryId(query, historyStateHash, excludeDeliveredQueryHash) {
448
+ return `context-${canonicalContentHash({
449
+ kind: 'context-delivery-history-attestation-v1',
450
+ queryHash: query.queryHash,
451
+ historyStateHash,
452
+ excludeDeliveredQueryHash,
453
+ })}`;
454
+ }
455
+ function deliveryHistoryExclusionForReplay(database, query, deliveryId) {
456
+ if (query.run === null)
457
+ return null;
458
+ const priorSameQuery = database.prepare(`
459
+ SELECT 1 AS present
460
+ FROM context_deliveries
461
+ WHERE run_id = ? AND query_hash = ? AND delivery_id <> ?
462
+ LIMIT 1
463
+ `).get(query.run.runId, query.queryHash, deliveryId);
464
+ if (priorSameQuery === undefined)
465
+ return null;
466
+ if (priorSameQuery.present !== 1) {
467
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context delivery history is invalid');
468
+ }
469
+ return query.queryHash;
470
+ }
471
+ function deliveryHistoryIsAttested(database, query, delivery) {
472
+ const excludeDeliveredQueryHash = deliveryHistoryExclusionForReplay(database, query, delivery.deliveryId);
473
+ const history = priorData(database, query, {
474
+ ...(excludeDeliveredQueryHash === null ? {} : { excludeDeliveredQueryHash }),
475
+ excludeDeliveryId: delivery.deliveryId,
237
476
  });
477
+ if (history.stateHash === null) {
478
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context delivery history is invalid');
479
+ }
480
+ return delivery.deliveryId === historyAttestedDeliveryId(query, history.stateHash, excludeDeliveredQueryHash);
238
481
  }
239
482
  function outputContext(query, items, delivery) {
240
483
  const sourceItems = items.map((item, index) => ({
241
484
  entryId: item.entryId,
242
485
  entryRevision: item.revision,
243
486
  rank: index + 1,
244
- scoreComponents: item.scoreComponents,
487
+ scoreComponents: { ...item.scoreComponents },
245
488
  selectionReasons: [...item.selectionReasons],
246
- content: item.content,
489
+ content: { ...item.content },
247
490
  untrusted: true,
491
+ ...(item.origin === undefined ? {} : { origin: item.origin }),
248
492
  }));
249
493
  return {
250
494
  deliveryId: delivery?.deliveryId ?? query.deliveryId,
@@ -257,13 +501,14 @@ function outputContext(query, items, delivery) {
257
501
  untrusted: true,
258
502
  };
259
503
  }
260
- function deliveryInput(query, ranked, summary) {
504
+ function deliveryInput(query, ranked) {
261
505
  const items = ranked.map((item, index) => ({
262
506
  entryId: item.entryId,
263
507
  entryRevision: item.revision,
264
508
  rank: index + 1,
265
- scoreComponents: item.scoreComponents,
509
+ scoreComponents: { ...item.scoreComponents },
266
510
  selectionReasons: [...item.selectionReasons],
511
+ ...(item.origin === undefined ? {} : { origin: item.origin }),
267
512
  }));
268
513
  const charCount = ranked.reduce((sum, item) => sum + item.content.characterCount, 0);
269
514
  const truncated = ranked.some((item) => item.content.truncated);
@@ -276,7 +521,6 @@ function deliveryInput(query, ranked, summary) {
276
521
  taskProfileHash: query.profileHash,
277
522
  queryHash: query.queryHash,
278
523
  policyVersion: CONTEXT_BROKER_POLICY_VERSION,
279
- externalSyncSummary: summary,
280
524
  charBudget: query.characterBudget,
281
525
  charCount,
282
526
  truncated,
@@ -284,19 +528,74 @@ function deliveryInput(query, ranked, summary) {
284
528
  items,
285
529
  };
286
530
  }
287
- function emptyExternalSummary() {
288
- return { attempted: false, imported: 0, sources: [] };
531
+ function currentRetrievableDeliveryEntry(database, runWorkspace, item) {
532
+ const candidate = database.prepare('SELECT workspace FROM entries WHERE id = ?')
533
+ .get(item.entryId);
534
+ if (candidate === undefined) {
535
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry is missing');
536
+ }
537
+ if (typeof candidate.workspace !== 'string' || candidate.workspace.length === 0) {
538
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry is invalid');
539
+ }
540
+ const origin = item.origin ?? 'project';
541
+ let deliveredRevision;
542
+ try {
543
+ deliveredRevision = readEntryRevision(database, {
544
+ workspace: candidate.workspace,
545
+ entryId: item.entryId,
546
+ revision: item.entryRevision,
547
+ });
548
+ }
549
+ catch (error) {
550
+ if (error instanceof KiokukoError && error.code === 'NOT_FOUND') {
551
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry revision is missing');
552
+ }
553
+ throw error;
554
+ }
555
+ const deliveredScope = decodeStoredStructuredScope(deliveredRevision.scope, origin !== 'project').canonicalScope;
556
+ if (!entryOriginMatchesWorkspace({ origin, runWorkspace, entryWorkspace: deliveredRevision.workspace })) {
557
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry origin is invalid');
558
+ }
559
+ if (origin === 'global'
560
+ && (deliveredScope.visibility !== 'global' || effectiveRetrievalScope(deliveredScope) !== 'global')) {
561
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry scope is invalid');
562
+ }
563
+ if (origin === 'ecosystem'
564
+ && (!Object.hasOwn(deliveredScope, 'retrievalScope')
565
+ || effectiveRetrievalScope(deliveredScope) !== 'ecosystem'
566
+ || !hasExplicitApplicability(deliveredScope))) {
567
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry scope is invalid');
568
+ }
569
+ if (isExternalSkillReference(deliveredRevision)) {
570
+ const mappings = database.prepare('SELECT COUNT(*) AS count FROM external_skill_entries WHERE entry_id = ?')
571
+ .get(item.entryId)?.count;
572
+ if (typeof mappings !== 'number' || !Number.isSafeInteger(mappings) || mappings < 1) {
573
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context external entry mapping is missing');
574
+ }
575
+ }
576
+ const entry = readEntry(database, { workspace: candidate.workspace, entryId: item.entryId }, { requireStructuredScope: origin !== 'project' });
577
+ const retrievable = isRetrievableEntry(database, entry);
578
+ if (entry.revision !== item.entryRevision)
579
+ return null;
580
+ if (!retrievable)
581
+ return null;
582
+ if (entry.status === 'superseded')
583
+ return null;
584
+ return entry;
289
585
  }
290
586
  function storedContext(database, query, delivery) {
291
587
  let remaining = query.characterBudget;
588
+ let totalCharacterCount = 0;
589
+ let anyTruncated = false;
292
590
  const items = delivery.items.map((item) => {
293
- const entry = database.prepare(`
294
- SELECT r.entry_id AS id, r.revision, r.title, r.summary, r.body
295
- FROM entry_revisions AS r
296
- WHERE r.entry_id = ? AND r.revision = ?
297
- `).get(item.entryId, item.entryRevision);
298
- if (!entry)
299
- throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry is missing');
591
+ const current = currentRetrievableDeliveryEntry(database, query.workspace, item);
592
+ if (current === null)
593
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context entry is no longer retrievable');
594
+ const entry = readEntryRevision(database, {
595
+ entryId: item.entryId,
596
+ workspace: current.workspace,
597
+ revision: item.entryRevision,
598
+ });
300
599
  const take = (value, budget) => Array.from(value).slice(0, Math.max(0, budget)).join('');
301
600
  const count = (value) => Array.from(value).length;
302
601
  const title = take(entry.title, remaining);
@@ -305,6 +604,12 @@ function storedContext(database, query, delivery) {
305
604
  remaining -= count(summary ?? '');
306
605
  const bodyPreview = take(entry.body, remaining);
307
606
  remaining -= count(bodyPreview);
607
+ const characterCount = count(title) + count(summary ?? '') + count(bodyPreview);
608
+ const truncated = count(title) < count(entry.title)
609
+ || (entry.summary !== null && count(summary ?? '') < count(entry.summary))
610
+ || count(bodyPreview) < count(entry.body);
611
+ totalCharacterCount += characterCount;
612
+ anyTruncated ||= truncated;
308
613
  return {
309
614
  entryId: item.entryId,
310
615
  entryRevision: item.entryRevision,
@@ -315,12 +620,16 @@ function storedContext(database, query, delivery) {
315
620
  title,
316
621
  summary,
317
622
  bodyPreview,
318
- characterCount: title.length + (summary?.length ?? 0) + bodyPreview.length,
319
- truncated: title.length < entry.title.length || (entry.summary !== null && summary?.length !== entry.summary.length) || bodyPreview.length < entry.body.length,
623
+ characterCount,
624
+ truncated,
320
625
  },
321
626
  untrusted: true,
627
+ ...(item.origin === undefined ? {} : { origin: item.origin }),
322
628
  };
323
629
  });
630
+ if (totalCharacterCount !== delivery.charCount || anyTruncated !== delivery.truncated) {
631
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context character accounting is invalid');
632
+ }
324
633
  return {
325
634
  deliveryId: delivery.deliveryId,
326
635
  runId: delivery.runId,
@@ -332,13 +641,87 @@ function storedContext(database, query, delivery) {
332
641
  untrusted: true,
333
642
  };
334
643
  }
644
+ function storedDeliveryIsRetrievable(database, query, delivery) {
645
+ if (delivery.throughSequence !== query.throughSequence) {
646
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context delivery sequence is invalid');
647
+ }
648
+ if (!delivery.items.every((item) => currentRetrievableDeliveryEntry(database, query.workspace, item) !== null))
649
+ return false;
650
+ return !(delivery.taskProfileHash !== query.profileHash
651
+ || delivery.queryHash !== query.queryHash
652
+ || delivery.policyVersion !== CONTEXT_BROKER_POLICY_VERSION
653
+ || (delivery.scoreSchemaVersion ?? 1) !== 1
654
+ || delivery.charBudget !== query.characterBudget
655
+ || delivery.items.length > query.limit);
656
+ }
657
+ function assertPreparedSelectedEntries(database, query, result) {
658
+ if (result.context !== null
659
+ && result.context.items.some((item) => currentRetrievableDeliveryEntry(database, query.workspace, item) === null)) {
660
+ throw new KiokukoError('CONFLICT', 'Context delivery selection changed before return');
661
+ }
662
+ }
663
+ function assertPreparedBrokerState(database, query, result, expectedHistoryStateHash = query.deliveryHistoryStateHash) {
664
+ assertPreparedProjectState(database, query);
665
+ if (query.run === null) {
666
+ if (query.retrievalStateHash !== null
667
+ && contextRetrievalStateHash(database, query.selectionWorkspaces, { includeEcosystem: query.includeEcosystem }) !== query.retrievalStateHash) {
668
+ throw new KiokukoError('CONFLICT', 'Context selection state changed after ranking');
669
+ }
670
+ return;
671
+ }
672
+ const current = currentRunContext(database, query.run.runId);
673
+ const currentStatus = current.intakeStatus === 'active' ? 'needs_answer' : current.intakeStatus;
674
+ if (query.runStateHash === null
675
+ || current.stateHash !== query.runStateHash
676
+ || current.run.workspace !== query.workspace
677
+ || current.run.status !== query.run.status
678
+ || current.run.lastSequence !== query.throughSequence
679
+ || current.intakeSessionId !== query.intakeSessionId
680
+ || currentStatus !== query.runStatus
681
+ || current.profileHash !== query.profileHash
682
+ || canonicalContentHash([...current.recommendedTags].sort()) !== canonicalContentHash([...query.recommendedTags].sort())) {
683
+ throw new KiokukoError('CONFLICT', 'Context delivery conflicts with current run state');
684
+ }
685
+ if (result.context !== null && query.run.status !== 'active') {
686
+ throw new KiokukoError('CONFLICT', 'Context delivery conflicts with current run state');
687
+ }
688
+ assertPreparedSelectedEntries(database, query, result);
689
+ if (query.retrievalStateHash !== null
690
+ && contextRetrievalStateHash(database, query.selectionWorkspaces, { includeEcosystem: query.includeEcosystem }) !== query.retrievalStateHash) {
691
+ throw new KiokukoError('CONFLICT', 'Context selection state changed after ranking');
692
+ }
693
+ if (expectedHistoryStateHash !== null) {
694
+ const currentHistory = priorData(database, query, query.deliveryHistoryExcludeQueryHash === null
695
+ ? {}
696
+ : { excludeDeliveredQueryHash: query.deliveryHistoryExcludeQueryHash });
697
+ if (currentHistory.stateHash !== expectedHistoryStateHash) {
698
+ throw new KiokukoError('CONFLICT', 'Context delivery history changed after ranking');
699
+ }
700
+ }
701
+ }
702
+ function replayableDelivery(database, query) {
703
+ if (query.run === null)
704
+ return { delivery: null, found: false };
705
+ const rows = database.prepare(`
706
+ SELECT delivery_id AS deliveryId
707
+ FROM context_deliveries
708
+ WHERE run_id = ? AND query_hash = ?
709
+ ORDER BY delivery_id ASC
710
+ `).all(query.run.runId, query.queryHash);
711
+ for (const row of rows) {
712
+ const delivery = readContextDelivery(database, { workspace: query.workspace, deliveryId: row.deliveryId });
713
+ if (storedDeliveryIsRetrievable(database, query, delivery)
714
+ && deliveryHistoryIsAttested(database, query, delivery)) {
715
+ return { delivery, found: true };
716
+ }
717
+ }
718
+ return { delivery: null, found: rows.length > 0 };
719
+ }
335
720
  export class ContextBroker {
336
721
  database;
337
- options;
338
722
  inFlight = new Map();
339
- constructor(database, options = {}) {
723
+ constructor(database) {
340
724
  this.database = database;
341
- this.options = options;
342
725
  }
343
726
  listDeliveries(input) {
344
727
  const context = currentRunContext(this.database, input.runId);
@@ -353,6 +736,20 @@ export class ContextBroker {
353
736
  };
354
737
  }
355
738
  async query(rawInput, persistence = {}) {
739
+ return this.execute(rawInput, normalizePersistence(persistence));
740
+ }
741
+ async queryGated(rawInput, decide, persistence = {}) {
742
+ const normalizedPersistence = normalizePersistence(persistence);
743
+ const input = normalizeInput(rawInput);
744
+ const query = preparedQuery(this.database, input);
745
+ const prepared = await this.prepareResult(query);
746
+ const decision = normalizedGateDecision(decide(prepared.result));
747
+ const broker = decision.persist
748
+ ? await this.persistPrepared(prepared, normalizedPersistence, query, decision.assertBeforePersist)
749
+ : this.validatePrepared(prepared, query, decision.assertBeforePersist);
750
+ return { broker, value: decision.value };
751
+ }
752
+ async execute(rawInput, persistence) {
356
753
  const input = normalizeInput(rawInput);
357
754
  const query = preparedQuery(this.database, input);
358
755
  const previous = this.inFlight.get(query.queryHash);
@@ -369,6 +766,10 @@ export class ContextBroker {
369
766
  }
370
767
  }
371
768
  async queryPrepared(query, persistence) {
769
+ const prepared = await this.prepareResult(query);
770
+ return this.persistPrepared(prepared, persistence, query);
771
+ }
772
+ async prepareResult(query) {
372
773
  const base = {
373
774
  status: query.runStatus,
374
775
  taskProfile: { ...query.taskProfile },
@@ -379,63 +780,140 @@ export class ContextBroker {
379
780
  projection: query.projection,
380
781
  context: null,
381
782
  recommendations: query.projection === null ? [] : buildRecommendations({ projection: query.projection, broker: {} }),
382
- externalSyncSummary: emptyExternalSummary(),
383
783
  };
384
784
  if (query.runStatus === 'needs_answer')
385
- return base;
386
- const prior = priorData(this.database, query);
387
- const existing = query.deliveryId === null ? null : (() => {
388
- try {
389
- return readContextDelivery(this.database, { workspace: query.workspace, deliveryId: query.deliveryId });
390
- }
391
- catch (error) {
392
- if (error instanceof KiokukoError && error.code === 'NOT_FOUND')
393
- return null;
394
- throw error;
395
- }
396
- })();
397
- if (existing) {
785
+ return { result: base, replayDelivery: null, pendingDelivery: null };
786
+ const replay = replayableDelivery(this.database, query);
787
+ const excludeDeliveredQueryHash = replay.delivery === null && replay.found ? query.queryHash : undefined;
788
+ const prior = priorData(this.database, query, excludeDeliveredQueryHash === undefined
789
+ ? {}
790
+ : { excludeDeliveredQueryHash });
791
+ query.deliveryHistoryStateHash = prior.stateHash;
792
+ query.deliveryHistoryExcludeQueryHash = excludeDeliveredQueryHash ?? null;
793
+ if (replay.delivery !== null) {
398
794
  return {
399
- ...base,
400
- context: storedContext(this.database, query, existing),
401
- externalSyncSummary: existing.externalSyncSummary,
402
- recommendations: query.projection === null ? [] : buildRecommendations({ projection: query.projection, broker: { staleDeliveredEntries: prior.stale } }),
795
+ result: {
796
+ ...base,
797
+ context: storedContext(this.database, query, replay.delivery),
798
+ recommendations: query.projection === null ? [] : buildRecommendations({ projection: query.projection, broker: { staleDeliveredEntries: prior.stale } }),
799
+ },
800
+ replayDelivery: replay.delivery,
801
+ pendingDelivery: null,
403
802
  };
404
803
  }
405
- let ranked = rank(this.database, query, prior);
406
- let externalSyncSummary = emptyExternalSummary();
407
- if (ranked.length < query.limit && query.taskProfile !== undefined && this.options.allowExternalSkillFallback === true) {
408
- const prepared = await prepareOfficialSourceSync({
409
- workspace: query.workspace,
410
- task: query.task,
411
- profile: query.taskProfile,
412
- recommendedTags: query.recommendedTags,
413
- ...(this.options.fetchImpl === undefined ? {} : { fetchImpl: this.options.fetchImpl }),
414
- });
415
- const result = persistence.persistSources === undefined
416
- ? persistOfficialSourceSync(this.database, { workspace: query.workspace, prepared })
417
- : await persistence.persistSources(query.workspace, prepared);
418
- externalSyncSummary = { attempted: result.attempted, imported: result.imported, sources: result.sources };
419
- ranked = rank(this.database, query, priorData(this.database, query));
804
+ const ranked = await rank(this.database, query, prior);
805
+ if (query.run !== null && prior.stateHash === null) {
806
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context delivery history is invalid');
420
807
  }
808
+ const deliveryQuery = query.run === null
809
+ ? query
810
+ : {
811
+ ...query,
812
+ deliveryId: historyAttestedDeliveryId(query, prior.stateHash, query.deliveryHistoryExcludeQueryHash),
813
+ };
421
814
  const recommendations = query.projection === null
422
815
  ? []
423
816
  : buildRecommendations({ projection: query.projection, broker: { staleDeliveredEntries: prior.stale } });
424
- const context = outputContext(query, ranked, null);
425
- if (query.deliveryId === null || query.run === null) {
426
- return { ...base, context, recommendations, externalSyncSummary };
817
+ const context = outputContext(deliveryQuery, ranked, null);
818
+ if (deliveryQuery.deliveryId === null || deliveryQuery.run === null) {
819
+ return { result: { ...base, context, recommendations }, replayDelivery: null, pendingDelivery: null };
427
820
  }
428
- const deliveryRequest = deliveryInput(query, ranked, externalSyncSummary);
429
- const delivery = persistence.persistDelivery === undefined
430
- ? recordContextDelivery(this.database, deliveryRequest)
431
- : await persistence.persistDelivery(deliveryRequest);
432
- return { ...base, context: outputContext(query, ranked, delivery), recommendations, externalSyncSummary };
821
+ const deliveryRequest = deliveryInput(deliveryQuery, ranked);
822
+ return {
823
+ result: { ...base, context, recommendations },
824
+ replayDelivery: null,
825
+ pendingDelivery: { query: deliveryQuery, ranked, input: deliveryRequest },
826
+ };
827
+ }
828
+ async persistPrepared(prepared, persistence, query, assertBeforePersist) {
829
+ if (prepared.pendingDelivery === null) {
830
+ return withImmediateTransaction(this.database, () => {
831
+ if (prepared.replayDelivery !== null) {
832
+ assertPreparedSelectedEntries(this.database, query, prepared.result);
833
+ assertReplayDeliveryUnchanged(this.database, prepared.replayDelivery);
834
+ }
835
+ assertPreparedBrokerState(this.database, query, prepared.result);
836
+ if (assertBeforePersist !== undefined) {
837
+ assertBeforePersist();
838
+ if (prepared.replayDelivery !== null) {
839
+ assertPreparedSelectedEntries(this.database, query, prepared.result);
840
+ assertReplayDeliveryUnchanged(this.database, prepared.replayDelivery);
841
+ }
842
+ assertPreparedBrokerState(this.database, query, prepared.result);
843
+ }
844
+ return prepared.result;
845
+ });
846
+ }
847
+ const pendingDelivery = prepared.pendingDelivery;
848
+ let committedDelivery = null;
849
+ let committedHistoryStateHash = null;
850
+ let invocationCount = 0;
851
+ let acceptingInvocation = true;
852
+ const persist = () => {
853
+ if (!acceptingInvocation) {
854
+ throw new KiokukoError('INTEGRITY_ERROR', 'Context broker write adapter invoked persistence outside its queue operation');
855
+ }
856
+ invocationCount += 1;
857
+ if (invocationCount !== 1) {
858
+ throw new KiokukoError('INTEGRITY_ERROR', 'Context broker write adapter invoked persistence more than once');
859
+ }
860
+ committedDelivery = withImmediateTransaction(this.database, () => {
861
+ assertPreparedBrokerState(this.database, query, prepared.result);
862
+ if (assertBeforePersist !== undefined) {
863
+ assertBeforePersist();
864
+ assertPreparedBrokerState(this.database, query, prepared.result);
865
+ }
866
+ const delivery = recordContextDeliveryInTransaction(this.database, pendingDelivery.input);
867
+ committedHistoryStateHash = priorData(this.database, query, query.deliveryHistoryExcludeQueryHash === null
868
+ ? {}
869
+ : { excludeDeliveredQueryHash: query.deliveryHistoryExcludeQueryHash }).stateHash;
870
+ return delivery;
871
+ });
872
+ return committedDelivery;
873
+ };
874
+ let returned;
875
+ try {
876
+ returned = persistence.enqueueWrite === undefined
877
+ ? persist()
878
+ : await persistence.enqueueWrite(persist);
879
+ }
880
+ finally {
881
+ acceptingInvocation = false;
882
+ }
883
+ const committed = committedDelivery;
884
+ const committedHistory = committedHistoryStateHash;
885
+ if (invocationCount !== 1 || committed === null || committedHistory === null || returned !== committed) {
886
+ throw new KiokukoError('INTEGRITY_ERROR', 'Context broker write adapter returned an invalid result');
887
+ }
888
+ withImmediateTransaction(this.database, () => {
889
+ assertReplayDeliveryUnchanged(this.database, committed);
890
+ if (!deliveryHistoryIsAttested(this.database, query, committed)) {
891
+ throw new KiokukoError('CONFLICT', 'Context delivery history changed after ranking');
892
+ }
893
+ assertPreparedBrokerState(this.database, query, prepared.result, committedHistory);
894
+ });
895
+ return {
896
+ ...prepared.result,
897
+ context: outputContext(pendingDelivery.query, pendingDelivery.ranked, committed),
898
+ };
899
+ }
900
+ validatePrepared(prepared, query, assertBeforeReturn) {
901
+ return withImmediateTransaction(this.database, () => {
902
+ if (prepared.replayDelivery !== null) {
903
+ assertPreparedSelectedEntries(this.database, query, prepared.result);
904
+ assertReplayDeliveryUnchanged(this.database, prepared.replayDelivery);
905
+ }
906
+ assertPreparedBrokerState(this.database, query, prepared.result);
907
+ if (assertBeforeReturn !== undefined) {
908
+ assertBeforeReturn();
909
+ if (prepared.replayDelivery !== null) {
910
+ assertPreparedSelectedEntries(this.database, query, prepared.result);
911
+ assertReplayDeliveryUnchanged(this.database, prepared.replayDelivery);
912
+ }
913
+ assertPreparedBrokerState(this.database, query, prepared.result);
914
+ }
915
+ return prepared.result;
916
+ });
433
917
  }
434
- }
435
- export function contextBrokerQueryHash(input) {
436
- return createHash('sha256').update(JSON.stringify(input), 'utf8').digest('hex');
437
- }
438
- export function newContextDeliveryId() {
439
- return `context-${randomUUID()}`;
440
918
  }
441
919
  //# sourceMappingURL=broker.js.map