@askdkc/kiokuko 0.1.17 → 0.1.20

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 (539) hide show
  1. package/README.ja.md +91 -112
  2. package/README.ko.md +90 -102
  3. package/README.md +103 -262
  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 +11 -22
  18. package/dist/akinator/agent-task.d.ts.map +1 -1
  19. package/dist/akinator/agent-task.js +454 -99
  20. package/dist/akinator/agent-task.js.map +1 -1
  21. package/dist/akinator/capabilities.d.ts +18 -6
  22. package/dist/akinator/capabilities.d.ts.map +1 -1
  23. package/dist/akinator/capabilities.js +72 -35
  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/cli.d.ts +2 -0
  52. package/dist/cli.d.ts.map +1 -1
  53. package/dist/cli.js +560 -150
  54. package/dist/cli.js.map +1 -1
  55. package/dist/client/server-client.d.ts +5 -3
  56. package/dist/client/server-client.d.ts.map +1 -1
  57. package/dist/client/server-client.js +486 -181
  58. package/dist/client/server-client.js.map +1 -1
  59. package/dist/commands/agent.d.ts +2 -0
  60. package/dist/commands/agent.d.ts.map +1 -1
  61. package/dist/commands/agent.js +861 -86
  62. package/dist/commands/agent.js.map +1 -1
  63. package/dist/commands/backup.d.ts +2 -1
  64. package/dist/commands/backup.d.ts.map +1 -1
  65. package/dist/commands/backup.js +71 -8
  66. package/dist/commands/backup.js.map +1 -1
  67. package/dist/commands/doctor.d.ts +5 -1
  68. package/dist/commands/doctor.d.ts.map +1 -1
  69. package/dist/commands/doctor.js +70 -26
  70. package/dist/commands/doctor.js.map +1 -1
  71. package/dist/commands/export.d.ts +0 -4
  72. package/dist/commands/export.d.ts.map +1 -1
  73. package/dist/commands/export.js +191 -32
  74. package/dist/commands/export.js.map +1 -1
  75. package/dist/commands/import.d.ts +10 -1
  76. package/dist/commands/import.d.ts.map +1 -1
  77. package/dist/commands/import.js +592 -113
  78. package/dist/commands/import.js.map +1 -1
  79. package/dist/commands/init.d.ts +19 -1
  80. package/dist/commands/init.d.ts.map +1 -1
  81. package/dist/commands/init.js +569 -22
  82. package/dist/commands/init.js.map +1 -1
  83. package/dist/commands/purge.d.ts.map +1 -1
  84. package/dist/commands/purge.js +3 -0
  85. package/dist/commands/purge.js.map +1 -1
  86. package/dist/commands/setup.d.ts +37 -8
  87. package/dist/commands/setup.d.ts.map +1 -1
  88. package/dist/commands/setup.js +448 -86
  89. package/dist/commands/setup.js.map +1 -1
  90. package/dist/commands/skills.d.ts +9 -0
  91. package/dist/commands/skills.d.ts.map +1 -0
  92. package/dist/commands/skills.js +317 -0
  93. package/dist/commands/skills.js.map +1 -0
  94. package/dist/commands/use.d.ts +10 -2
  95. package/dist/commands/use.d.ts.map +1 -1
  96. package/dist/commands/use.js +851 -73
  97. package/dist/commands/use.js.map +1 -1
  98. package/dist/config/paths.d.ts +11 -1
  99. package/dist/config/paths.d.ts.map +1 -1
  100. package/dist/config/paths.js +64 -29
  101. package/dist/config/paths.js.map +1 -1
  102. package/dist/config/project-config.d.ts +1 -0
  103. package/dist/config/project-config.d.ts.map +1 -1
  104. package/dist/config/project-config.js +70 -32
  105. package/dist/config/project-config.js.map +1 -1
  106. package/dist/context/broker.d.ts +28 -14
  107. package/dist/context/broker.d.ts.map +1 -1
  108. package/dist/context/broker.js +604 -145
  109. package/dist/context/broker.js.map +1 -1
  110. package/dist/context/delivery.d.ts +6 -21
  111. package/dist/context/delivery.d.ts.map +1 -1
  112. package/dist/context/delivery.js +196 -147
  113. package/dist/context/delivery.js.map +1 -1
  114. package/dist/context/feedback.d.ts +11 -12
  115. package/dist/context/feedback.d.ts.map +1 -1
  116. package/dist/context/feedback.js +229 -261
  117. package/dist/context/feedback.js.map +1 -1
  118. package/dist/context/ranking.d.ts +1 -12
  119. package/dist/context/ranking.d.ts.map +1 -1
  120. package/dist/context/ranking.js +13 -4
  121. package/dist/context/ranking.js.map +1 -1
  122. package/dist/context/recommendations.d.ts +0 -5
  123. package/dist/context/recommendations.d.ts.map +1 -1
  124. package/dist/context/recommendations.js +0 -1
  125. package/dist/context/recommendations.js.map +1 -1
  126. package/dist/context/run-state.d.ts +26 -0
  127. package/dist/context/run-state.d.ts.map +1 -0
  128. package/dist/context/run-state.js +399 -0
  129. package/dist/context/run-state.js.map +1 -0
  130. package/dist/context/scoped-broker.d.ts +17 -5
  131. package/dist/context/scoped-broker.d.ts.map +1 -1
  132. package/dist/context/scoped-broker.js +512 -106
  133. package/dist/context/scoped-broker.js.map +1 -1
  134. package/dist/context/selection-state.d.ts +19 -0
  135. package/dist/context/selection-state.d.ts.map +1 -0
  136. package/dist/context/selection-state.js +250 -0
  137. package/dist/context/selection-state.js.map +1 -0
  138. package/dist/db/adapter.d.ts +5 -3
  139. package/dist/db/adapter.d.ts.map +1 -1
  140. package/dist/db/adapter.js +7 -3
  141. package/dist/db/adapter.js.map +1 -1
  142. package/dist/db/capabilities.d.ts.map +1 -1
  143. package/dist/db/capabilities.js +34 -16
  144. package/dist/db/capabilities.js.map +1 -1
  145. package/dist/db/connection.d.ts +8 -0
  146. package/dist/db/connection.d.ts.map +1 -1
  147. package/dist/db/connection.js +55 -26
  148. package/dist/db/connection.js.map +1 -1
  149. package/dist/db/migrate.d.ts +28 -7
  150. package/dist/db/migrate.d.ts.map +1 -1
  151. package/dist/db/migrate.js +106 -78
  152. package/dist/db/migrate.js.map +1 -1
  153. package/dist/db/sqlite-retry.d.ts +11 -0
  154. package/dist/db/sqlite-retry.d.ts.map +1 -0
  155. package/dist/db/sqlite-retry.js +66 -0
  156. package/dist/db/sqlite-retry.js.map +1 -0
  157. package/dist/db/transaction.d.ts +13 -0
  158. package/dist/db/transaction.d.ts.map +1 -1
  159. package/dist/db/transaction.js +53 -24
  160. package/dist/db/transaction.js.map +1 -1
  161. package/dist/db/upgrade-backup.d.ts +58 -2
  162. package/dist/db/upgrade-backup.d.ts.map +1 -1
  163. package/dist/db/upgrade-backup.js +758 -28
  164. package/dist/db/upgrade-backup.js.map +1 -1
  165. package/dist/errors.d.ts +4 -0
  166. package/dist/errors.d.ts.map +1 -1
  167. package/dist/errors.js +29 -1
  168. package/dist/errors.js.map +1 -1
  169. package/dist/gateway/agent-service.d.ts +4 -1
  170. package/dist/gateway/agent-service.d.ts.map +1 -1
  171. package/dist/gateway/agent-service.js +71 -58
  172. package/dist/gateway/agent-service.js.map +1 -1
  173. package/dist/gateway/checkpoint-service.d.ts +1 -0
  174. package/dist/gateway/checkpoint-service.d.ts.map +1 -1
  175. package/dist/gateway/checkpoint-service.js +47 -24
  176. package/dist/gateway/checkpoint-service.js.map +1 -1
  177. package/dist/ledger/archive.d.ts +1 -4
  178. package/dist/ledger/archive.d.ts.map +1 -1
  179. package/dist/ledger/archive.js +77 -39
  180. package/dist/ledger/archive.js.map +1 -1
  181. package/dist/ledger/maintenance.d.ts +0 -11
  182. package/dist/ledger/maintenance.d.ts.map +1 -1
  183. package/dist/ledger/maintenance.js +24 -40
  184. package/dist/ledger/maintenance.js.map +1 -1
  185. package/dist/ledger/projection.d.ts +0 -1
  186. package/dist/ledger/projection.d.ts.map +1 -1
  187. package/dist/ledger/projection.js.map +1 -1
  188. package/dist/ledger/promotion.d.ts +0 -9
  189. package/dist/ledger/promotion.d.ts.map +1 -1
  190. package/dist/ledger/promotion.js.map +1 -1
  191. package/dist/ledger/query.d.ts +1 -15
  192. package/dist/ledger/query.d.ts.map +1 -1
  193. package/dist/ledger/query.js.map +1 -1
  194. package/dist/ledger/store.d.ts +0 -1
  195. package/dist/ledger/store.d.ts.map +1 -1
  196. package/dist/ledger/store.js +11 -8
  197. package/dist/ledger/store.js.map +1 -1
  198. package/dist/ledger/types.d.ts +0 -4
  199. package/dist/ledger/types.d.ts.map +1 -1
  200. package/dist/ledger/types.js.map +1 -1
  201. package/dist/ledger/validate.d.ts.map +1 -1
  202. package/dist/ledger/validate.js +0 -5
  203. package/dist/ledger/validate.js.map +1 -1
  204. package/dist/mcp/server.d.ts +4 -0
  205. package/dist/mcp/server.d.ts.map +1 -1
  206. package/dist/mcp/server.js +105 -54
  207. package/dist/mcp/server.js.map +1 -1
  208. package/dist/memory/audit.d.ts +0 -1
  209. package/dist/memory/audit.d.ts.map +1 -1
  210. package/dist/memory/audit.js +0 -1
  211. package/dist/memory/audit.js.map +1 -1
  212. package/dist/memory/curator.d.ts.map +1 -1
  213. package/dist/memory/curator.js +172 -96
  214. package/dist/memory/curator.js.map +1 -1
  215. package/dist/memory/entries.d.ts +12 -2
  216. package/dist/memory/entries.d.ts.map +1 -1
  217. package/dist/memory/entries.js +199 -115
  218. package/dist/memory/entries.js.map +1 -1
  219. package/dist/memory/federated-retrieval.d.ts +12 -1
  220. package/dist/memory/federated-retrieval.d.ts.map +1 -1
  221. package/dist/memory/federated-retrieval.js +183 -70
  222. package/dist/memory/federated-retrieval.js.map +1 -1
  223. package/dist/memory/hybrid-retrieval.d.ts +5 -11
  224. package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
  225. package/dist/memory/hybrid-retrieval.js +78 -58
  226. package/dist/memory/hybrid-retrieval.js.map +1 -1
  227. package/dist/memory/lifecycle.d.ts.map +1 -1
  228. package/dist/memory/lifecycle.js +17 -13
  229. package/dist/memory/lifecycle.js.map +1 -1
  230. package/dist/memory/rebuild-search.d.ts +5 -0
  231. package/dist/memory/rebuild-search.d.ts.map +1 -1
  232. package/dist/memory/rebuild-search.js +101 -76
  233. package/dist/memory/rebuild-search.js.map +1 -1
  234. package/dist/memory/retrieval-query.d.ts +0 -5
  235. package/dist/memory/retrieval-query.d.ts.map +1 -1
  236. package/dist/memory/retrieval-query.js +0 -5
  237. package/dist/memory/retrieval-query.js.map +1 -1
  238. package/dist/memory/retrieval.d.ts.map +1 -1
  239. package/dist/memory/retrieval.js +25 -131
  240. package/dist/memory/retrieval.js.map +1 -1
  241. package/dist/memory/revisions.d.ts +76 -1
  242. package/dist/memory/revisions.d.ts.map +1 -1
  243. package/dist/memory/revisions.js +540 -36
  244. package/dist/memory/revisions.js.map +1 -1
  245. package/dist/memory/scoped-memory.d.ts +16 -1
  246. package/dist/memory/scoped-memory.d.ts.map +1 -1
  247. package/dist/memory/scoped-memory.js +240 -107
  248. package/dist/memory/scoped-memory.js.map +1 -1
  249. package/dist/memory/secrets.d.ts +2 -0
  250. package/dist/memory/secrets.d.ts.map +1 -1
  251. package/dist/memory/secrets.js +36 -0
  252. package/dist/memory/secrets.js.map +1 -1
  253. package/dist/memory/structured-memory.d.ts +3 -2
  254. package/dist/memory/structured-memory.d.ts.map +1 -1
  255. package/dist/memory/structured-memory.js +54 -22
  256. package/dist/memory/structured-memory.js.map +1 -1
  257. package/dist/memory/workspaces.d.ts +9 -0
  258. package/dist/memory/workspaces.d.ts.map +1 -1
  259. package/dist/memory/workspaces.js +67 -0
  260. package/dist/memory/workspaces.js.map +1 -1
  261. package/dist/package-version.d.ts +2 -0
  262. package/dist/package-version.d.ts.map +1 -0
  263. package/dist/package-version.js +7 -0
  264. package/dist/package-version.js.map +1 -0
  265. package/dist/repository/binding.d.ts +5 -0
  266. package/dist/repository/binding.d.ts.map +1 -1
  267. package/dist/repository/binding.js +117 -17
  268. package/dist/repository/binding.js.map +1 -1
  269. package/dist/repository/framework-version.d.ts +8 -0
  270. package/dist/repository/framework-version.d.ts.map +1 -0
  271. package/dist/repository/framework-version.js +29 -0
  272. package/dist/repository/framework-version.js.map +1 -0
  273. package/dist/repository/identity-value.d.ts +4 -0
  274. package/dist/repository/identity-value.d.ts.map +1 -0
  275. package/dist/repository/identity-value.js +24 -0
  276. package/dist/repository/identity-value.js.map +1 -0
  277. package/dist/repository/identity.d.ts.map +1 -1
  278. package/dist/repository/identity.js +2 -0
  279. package/dist/repository/identity.js.map +1 -1
  280. package/dist/repository/project-fingerprint.d.ts +14 -2
  281. package/dist/repository/project-fingerprint.d.ts.map +1 -1
  282. package/dist/repository/project-fingerprint.js +312 -33
  283. package/dist/repository/project-fingerprint.js.map +1 -1
  284. package/dist/repository/remote-url.d.ts +0 -1
  285. package/dist/repository/remote-url.d.ts.map +1 -1
  286. package/dist/repository/remote-url.js +0 -1
  287. package/dist/repository/remote-url.js.map +1 -1
  288. package/dist/runtime-version.d.ts +2 -1
  289. package/dist/runtime-version.d.ts.map +1 -1
  290. package/dist/runtime-version.js +21 -4
  291. package/dist/runtime-version.js.map +1 -1
  292. package/dist/serialization/boundary-json.d.ts +20 -0
  293. package/dist/serialization/boundary-json.d.ts.map +1 -0
  294. package/dist/serialization/boundary-json.js +129 -0
  295. package/dist/serialization/boundary-json.js.map +1 -0
  296. package/dist/serialization/envelope.js +1 -1
  297. package/dist/serialization/envelope.js.map +1 -1
  298. package/dist/serialization/validate.d.ts +7 -0
  299. package/dist/serialization/validate.d.ts.map +1 -1
  300. package/dist/serialization/validate.js +53 -13
  301. package/dist/serialization/validate.js.map +1 -1
  302. package/dist/server/app.js +1 -1
  303. package/dist/server/app.js.map +1 -1
  304. package/dist/server/http.d.ts +4 -3
  305. package/dist/server/http.d.ts.map +1 -1
  306. package/dist/server/http.js +90 -50
  307. package/dist/server/http.js.map +1 -1
  308. package/dist/server/idempotency.d.ts +0 -6
  309. package/dist/server/idempotency.d.ts.map +1 -1
  310. package/dist/server/idempotency.js.map +1 -1
  311. package/dist/server/router.d.ts.map +1 -1
  312. package/dist/server/router.js +21 -4
  313. package/dist/server/router.js.map +1 -1
  314. package/dist/server/routes/agent-capability-gate.d.ts +40 -0
  315. package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
  316. package/dist/server/routes/agent-capability-gate.js +182 -0
  317. package/dist/server/routes/agent-capability-gate.js.map +1 -0
  318. package/dist/server/routes/agent-events.d.ts.map +1 -1
  319. package/dist/server/routes/agent-events.js +8 -1
  320. package/dist/server/routes/agent-events.js.map +1 -1
  321. package/dist/server/routes/agent-intake.d.ts.map +1 -1
  322. package/dist/server/routes/agent-intake.js +10 -2
  323. package/dist/server/routes/agent-intake.js.map +1 -1
  324. package/dist/server/routes/agent-promotions.d.ts.map +1 -1
  325. package/dist/server/routes/agent-promotions.js +5 -2
  326. package/dist/server/routes/agent-promotions.js.map +1 -1
  327. package/dist/server/routes/agent-runs.d.ts.map +1 -1
  328. package/dist/server/routes/agent-runs.js +18 -4
  329. package/dist/server/routes/agent-runs.js.map +1 -1
  330. package/dist/server/routes/request-binding.d.ts +5 -0
  331. package/dist/server/routes/request-binding.d.ts.map +1 -0
  332. package/dist/server/routes/request-binding.js +49 -0
  333. package/dist/server/routes/request-binding.js.map +1 -0
  334. package/dist/server/routes/task5-support.d.ts +1 -8
  335. package/dist/server/routes/task5-support.d.ts.map +1 -1
  336. package/dist/server/routes/task5-support.js +1 -17
  337. package/dist/server/routes/task5-support.js.map +1 -1
  338. package/dist/server/routes/task5.d.ts.map +1 -1
  339. package/dist/server/routes/task5.js +106 -36
  340. package/dist/server/routes/task5.js.map +1 -1
  341. package/dist/server/write-queue.js +2 -2
  342. package/dist/server/write-queue.js.map +1 -1
  343. package/dist/setup/claude-config.d.ts +4 -1
  344. package/dist/setup/claude-config.d.ts.map +1 -1
  345. package/dist/setup/claude-config.js +62 -4
  346. package/dist/setup/claude-config.js.map +1 -1
  347. package/dist/setup/client-detection.d.ts +7 -2
  348. package/dist/setup/client-detection.d.ts.map +1 -1
  349. package/dist/setup/client-detection.js +27 -9
  350. package/dist/setup/client-detection.js.map +1 -1
  351. package/dist/setup/hermes-config.d.ts +4 -1
  352. package/dist/setup/hermes-config.d.ts.map +1 -1
  353. package/dist/setup/hermes-config.js +71 -17
  354. package/dist/setup/hermes-config.js.map +1 -1
  355. package/dist/setup/legacy-client-cleanup.d.ts +6 -0
  356. package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
  357. package/dist/setup/legacy-client-cleanup.js +152 -0
  358. package/dist/setup/legacy-client-cleanup.js.map +1 -0
  359. package/dist/setup/managed-text.d.ts.map +1 -1
  360. package/dist/setup/managed-text.js +11 -1
  361. package/dist/setup/managed-text.js.map +1 -1
  362. package/dist/setup/mcp-conflict.d.ts +4 -0
  363. package/dist/setup/mcp-conflict.d.ts.map +1 -0
  364. package/dist/setup/mcp-conflict.js +15 -0
  365. package/dist/setup/mcp-conflict.js.map +1 -0
  366. package/dist/setup/opencode-config.d.ts +4 -1
  367. package/dist/setup/opencode-config.d.ts.map +1 -1
  368. package/dist/setup/opencode-config.js +65 -5
  369. package/dist/setup/opencode-config.js.map +1 -1
  370. package/dist/setup/render.d.ts +4 -1
  371. package/dist/setup/render.d.ts.map +1 -1
  372. package/dist/setup/render.js +168 -18
  373. package/dist/setup/render.js.map +1 -1
  374. package/dist/setup/standard-skills.d.ts +16 -2
  375. package/dist/setup/standard-skills.d.ts.map +1 -1
  376. package/dist/setup/standard-skills.js +37 -13
  377. package/dist/setup/standard-skills.js.map +1 -1
  378. package/dist/setup/strict-json.d.ts +7 -0
  379. package/dist/setup/strict-json.d.ts.map +1 -0
  380. package/dist/setup/strict-json.js +98 -0
  381. package/dist/setup/strict-json.js.map +1 -0
  382. package/dist/setup/strict-toml.d.ts +18 -0
  383. package/dist/setup/strict-toml.d.ts.map +1 -0
  384. package/dist/setup/strict-toml.js +491 -0
  385. package/dist/setup/strict-toml.js.map +1 -0
  386. package/dist/skills/cache.d.ts +15 -0
  387. package/dist/skills/cache.d.ts.map +1 -0
  388. package/dist/skills/cache.js +19 -0
  389. package/dist/skills/cache.js.map +1 -0
  390. package/dist/skills/candidate-ranking.d.ts +15 -0
  391. package/dist/skills/candidate-ranking.d.ts.map +1 -0
  392. package/dist/skills/candidate-ranking.js +52 -0
  393. package/dist/skills/candidate-ranking.js.map +1 -0
  394. package/dist/skills/chunking.d.ts +11 -0
  395. package/dist/skills/chunking.d.ts.map +1 -0
  396. package/dist/skills/chunking.js +291 -0
  397. package/dist/skills/chunking.js.map +1 -0
  398. package/dist/skills/config.d.ts +19 -0
  399. package/dist/skills/config.d.ts.map +1 -0
  400. package/dist/skills/config.js +103 -0
  401. package/dist/skills/config.js.map +1 -0
  402. package/dist/skills/discovery-service.d.ts +26 -0
  403. package/dist/skills/discovery-service.d.ts.map +1 -0
  404. package/dist/skills/discovery-service.js +921 -0
  405. package/dist/skills/discovery-service.js.map +1 -0
  406. package/dist/skills/external-transport.d.ts +2 -0
  407. package/dist/skills/external-transport.d.ts.map +1 -0
  408. package/dist/skills/external-transport.js +30 -0
  409. package/dist/skills/external-transport.js.map +1 -0
  410. package/dist/skills/find.d.ts +16 -0
  411. package/dist/skills/find.d.ts.map +1 -0
  412. package/dist/skills/find.js +58 -0
  413. package/dist/skills/find.js.map +1 -0
  414. package/dist/skills/gap-detection.d.ts +23 -0
  415. package/dist/skills/gap-detection.d.ts.map +1 -0
  416. package/dist/skills/gap-detection.js +62 -0
  417. package/dist/skills/gap-detection.js.map +1 -0
  418. package/dist/skills/import-preparation.d.ts +4 -0
  419. package/dist/skills/import-preparation.d.ts.map +1 -0
  420. package/dist/skills/import-preparation.js +20 -0
  421. package/dist/skills/import-preparation.js.map +1 -0
  422. package/dist/skills/materialization-authority.d.ts +11 -0
  423. package/dist/skills/materialization-authority.d.ts.map +1 -0
  424. package/dist/skills/materialization-authority.js +92 -0
  425. package/dist/skills/materialization-authority.js.map +1 -0
  426. package/dist/skills/materialization-service.d.ts +22 -0
  427. package/dist/skills/materialization-service.d.ts.map +1 -0
  428. package/dist/skills/materialization-service.js +101 -0
  429. package/dist/skills/materialization-service.js.map +1 -0
  430. package/dist/skills/official-catalog.d.ts +31 -0
  431. package/dist/skills/official-catalog.d.ts.map +1 -0
  432. package/dist/skills/official-catalog.js +110 -0
  433. package/dist/skills/official-catalog.js.map +1 -0
  434. package/dist/skills/providers/schema.d.ts +30 -0
  435. package/dist/skills/providers/schema.d.ts.map +1 -0
  436. package/dist/skills/providers/schema.js +354 -0
  437. package/dist/skills/providers/schema.js.map +1 -0
  438. package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
  439. package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
  440. package/dist/skills/providers/skills-sh-compat.js +71 -0
  441. package/dist/skills/providers/skills-sh-compat.js.map +1 -0
  442. package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
  443. package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
  444. package/dist/skills/providers/skills-sh-v1.js +134 -0
  445. package/dist/skills/providers/skills-sh-v1.js.map +1 -0
  446. package/dist/skills/query-builder.d.ts +18 -0
  447. package/dist/skills/query-builder.d.ts.map +1 -0
  448. package/dist/skills/query-builder.js +93 -0
  449. package/dist/skills/query-builder.js.map +1 -0
  450. package/dist/skills/source/errors.d.ts +9 -0
  451. package/dist/skills/source/errors.d.ts.map +1 -0
  452. package/dist/skills/source/errors.js +15 -0
  453. package/dist/skills/source/errors.js.map +1 -0
  454. package/dist/skills/source/frontmatter.d.ts +9 -0
  455. package/dist/skills/source/frontmatter.d.ts.map +1 -0
  456. package/dist/skills/source/frontmatter.js +77 -0
  457. package/dist/skills/source/frontmatter.js.map +1 -0
  458. package/dist/skills/source/github-fetcher.d.ts +20 -0
  459. package/dist/skills/source/github-fetcher.d.ts.map +1 -0
  460. package/dist/skills/source/github-fetcher.js +292 -0
  461. package/dist/skills/source/github-fetcher.js.map +1 -0
  462. package/dist/skills/source/snapshot-validator.d.ts +28 -0
  463. package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
  464. package/dist/skills/source/snapshot-validator.js +186 -0
  465. package/dist/skills/source/snapshot-validator.js.map +1 -0
  466. package/dist/skills/store.d.ts +181 -0
  467. package/dist/skills/store.d.ts.map +1 -0
  468. package/dist/skills/store.js +1710 -0
  469. package/dist/skills/store.js.map +1 -0
  470. package/dist/skills/types.d.ts +169 -0
  471. package/dist/skills/types.d.ts.map +1 -0
  472. package/dist/skills/types.js +2 -0
  473. package/dist/skills/types.js.map +1 -0
  474. package/dist/web/i18n.d.ts +32 -0
  475. package/dist/web/i18n.d.ts.map +1 -1
  476. package/dist/web/i18n.js +128 -0
  477. package/dist/web/i18n.js.map +1 -1
  478. package/dist/web/server.d.ts.map +1 -1
  479. package/dist/web/server.js +386 -38
  480. package/dist/web/server.js.map +1 -1
  481. package/dist/web/ui.d.ts +4 -0
  482. package/dist/web/ui.d.ts.map +1 -1
  483. package/dist/web/ui.js +382 -6
  484. package/dist/web/ui.js.map +1 -1
  485. package/migrations/009_external_skill_discovery.sql +126 -0
  486. package/package.json +6 -3
  487. package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
  488. package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
  489. package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
  490. package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
  491. package/templates/AGENTS.md +8 -7
  492. package/dist/client/runtime-discovery.d.ts +0 -15
  493. package/dist/client/runtime-discovery.d.ts.map +0 -1
  494. package/dist/client/runtime-discovery.js +0 -45
  495. package/dist/client/runtime-discovery.js.map +0 -1
  496. package/dist/commands/call.d.ts +0 -7
  497. package/dist/commands/call.d.ts.map +0 -1
  498. package/dist/commands/call.js +0 -10
  499. package/dist/commands/call.js.map +0 -1
  500. package/dist/commands/link.d.ts +0 -6
  501. package/dist/commands/link.d.ts.map +0 -1
  502. package/dist/commands/link.js +0 -6
  503. package/dist/commands/link.js.map +0 -1
  504. package/dist/commands/promote.d.ts +0 -6
  505. package/dist/commands/promote.d.ts.map +0 -1
  506. package/dist/commands/promote.js +0 -6
  507. package/dist/commands/promote.js.map +0 -1
  508. package/dist/commands/read.d.ts +0 -6
  509. package/dist/commands/read.d.ts.map +0 -1
  510. package/dist/commands/read.js +0 -4
  511. package/dist/commands/read.js.map +0 -1
  512. package/dist/commands/recall.d.ts +0 -6
  513. package/dist/commands/recall.d.ts.map +0 -1
  514. package/dist/commands/recall.js +0 -4
  515. package/dist/commands/recall.js.map +0 -1
  516. package/dist/commands/record.d.ts +0 -6
  517. package/dist/commands/record.d.ts.map +0 -1
  518. package/dist/commands/record.js +0 -4
  519. package/dist/commands/record.js.map +0 -1
  520. package/dist/commands/search.d.ts +0 -6
  521. package/dist/commands/search.d.ts.map +0 -1
  522. package/dist/commands/search.js +0 -4
  523. package/dist/commands/search.js.map +0 -1
  524. package/dist/commands/supersede.d.ts +0 -6
  525. package/dist/commands/supersede.d.ts.map +0 -1
  526. package/dist/commands/supersede.js +0 -6
  527. package/dist/commands/supersede.js.map +0 -1
  528. package/dist/knowledge/sources.d.ts +0 -72
  529. package/dist/knowledge/sources.d.ts.map +0 -1
  530. package/dist/knowledge/sources.js +0 -388
  531. package/dist/knowledge/sources.js.map +0 -1
  532. package/dist/setup/opencode-evidence.d.ts +0 -37
  533. package/dist/setup/opencode-evidence.d.ts.map +0 -1
  534. package/dist/setup/opencode-evidence.js +0 -58
  535. package/dist/setup/opencode-evidence.js.map +0 -1
  536. package/dist/setup/opencode-loop-guard.d.ts +0 -9
  537. package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
  538. package/dist/setup/opencode-loop-guard.js +0 -248
  539. package/dist/setup/opencode-loop-guard.js.map +0 -1
@@ -1,21 +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';
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';
9
10
  import { federatedEntries } from '../memory/federated-retrieval.js';
10
- import { projectLedger } from '../ledger/projection.js';
11
- import { LedgerStore } from '../ledger/store.js';
12
- import { prepareOfficialSourceSync, persistOfficialSourceSync } from '../knowledge/sources.js';
13
- import { canonicalContentHash } from '../serialization/validate.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';
14
20
  export const CONTEXT_BROKER_POLICY_VERSION = `${CONTEXT_RANKING_VERSION}+${RECOMMENDATION_POLICY_VERSION}`;
15
21
  export const CONTEXT_BROKER_DEFAULT_LIMIT = 20;
16
22
  export const CONTEXT_BROKER_MAX_LIMIT = 100;
17
23
  export const CONTEXT_BROKER_DEFAULT_CHARACTER_BUDGET = 8_000;
18
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
+ }
19
101
  function invalid() {
20
102
  throw new KiokukoError('VALIDATION_ERROR', 'Context query input is invalid');
21
103
  }
@@ -73,58 +155,50 @@ function normalizeInput(input) {
73
155
  ...(value.characterBudget === undefined ? {} : { characterBudget: value.characterBudget }),
74
156
  };
75
157
  }
76
- function parseEventRows(store, runId) {
77
- return store.readEvents(runId).map((row) => {
78
- let payload;
79
- try {
80
- payload = JSON.parse(String(row.payload_json));
81
- }
82
- catch {
83
- throw new KiokukoError('INTEGRITY_ERROR', 'Stored ledger payload is invalid');
84
- }
85
- const snapshot = {
86
- eventId: String(row.event_id),
87
- sequence: Number(row.sequence),
88
- eventType: row.event_type,
89
- ...(row.outcome === null ? {} : { outcome: row.outcome }),
90
- ...(payload === undefined ? {} : { payload: payload }),
91
- };
92
- return snapshot;
93
- });
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 };
94
178
  }
95
179
  function currentRunContext(database, runId) {
96
- const run = new LedgerStore(database).readRun(runId);
97
- if (!run)
98
- notFound();
99
- const link = readRunIntakeLink(database, { workspace: run.workspace, runId });
100
- const session = readAkinatorSession(database, { workspace: run.workspace, sessionId: link.sessionId });
101
- const status = session.status;
102
- if (status === 'active') {
103
- return {
104
- run,
105
- profile: session.profile,
106
- profileHash: link.initialProfileHash ?? canonicalContentHash(session.profile),
107
- recommendedTags: [...link.recommendedTags],
108
- intakeSessionId: link.sessionId,
109
- intakeStatus: status,
110
- projection: null,
111
- };
180
+ try {
181
+ return readContextRunRetrievalState(database, runId);
112
182
  }
113
- const projection = projectLedger({
114
- initialProfile: session.profile,
115
- intakeStatus: status,
116
- coverage: run.coverage,
117
- throughSequence: run.lastSequence,
118
- events: parseEventRows(new LedgerStore(database), runId),
119
- });
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);
120
195
  return {
121
- run,
122
- profile: projection.taskProfile,
123
- profileHash: projection.profileHash,
124
- recommendedTags: [...link.recommendedTags],
125
- intakeSessionId: link.sessionId,
126
- intakeStatus: status,
127
- 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,
128
202
  };
129
203
  }
130
204
  function preparedQuery(database, input) {
@@ -137,6 +211,21 @@ function preparedQuery(database, input) {
137
211
  const throughSequence = runContext?.run.lastSequence ?? 0;
138
212
  const taskProfileHash = runContext?.profileHash ?? canonicalContentHash(profile);
139
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;
140
229
  const queryShape = {
141
230
  runId: input.runId ?? null,
142
231
  workspace: input.runId === undefined ? requestedWorkspace : null,
@@ -148,10 +237,15 @@ function preparedQuery(database, input) {
148
237
  throughSequence,
149
238
  characterBudget: input.characterBudget ?? CONTEXT_BROKER_DEFAULT_CHARACTER_BUDGET,
150
239
  limit: input.limit ?? CONTEXT_BROKER_DEFAULT_LIMIT,
240
+ projectState,
241
+ retrievalStateHash,
242
+ runStateHash: runContext?.stateHash ?? null,
151
243
  };
152
244
  const queryHash = canonicalContentHash(queryShape);
153
245
  return {
154
- workspace: runContext?.run.workspace ?? requestedWorkspace,
246
+ workspace,
247
+ selectionWorkspaces,
248
+ includeEcosystem,
155
249
  run: runContext?.run ?? null,
156
250
  taskProfile: profile,
157
251
  profileHash: taskProfileHash,
@@ -165,11 +259,16 @@ function preparedQuery(database, input) {
165
259
  intakeSessionId: runContext?.intakeSessionId ?? null,
166
260
  projection: runContext?.projection ?? null,
167
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,
168
267
  queryHash,
169
- deliveryId: input.runId === undefined ? null : `context-${queryHash}`,
268
+ deliveryId: null,
170
269
  };
171
270
  }
172
- function entrySnapshot(entry, origin) {
271
+ function entrySnapshot(entry, origin, selectionReasons = []) {
173
272
  return {
174
273
  id: entry.id,
175
274
  revision: entry.revision,
@@ -183,6 +282,7 @@ function entrySnapshot(entry, origin) {
183
282
  tags: [...entry.tags],
184
283
  scope: entry.scope,
185
284
  updatedAt: entry.updatedAt,
285
+ selectionReasons: [...selectionReasons],
186
286
  ...(origin === undefined ? {} : { origin }),
187
287
  };
188
288
  }
@@ -190,13 +290,48 @@ function retrievalQuery(query) {
190
290
  const values = [query.task, query.taskProfile.target, query.taskProfile.expected, ...query.recommendedTags].filter((value) => value !== null && value.length > 0);
191
291
  return values.join(' ').slice(0, 16_384) || 'kiokuko';
192
292
  }
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
+ }
193
320
  function projectForWorkspace(database, workspace) {
194
321
  const row = database.prepare(`
195
322
  SELECT r.repository_id AS repositoryId, r.workspace, l.canonical_root AS repositoryRoot
196
323
  FROM repositories AS r JOIN repository_locations AS l ON l.repository_id = r.repository_id
197
- WHERE r.workspace = ? ORDER BY l.last_seen_at DESC LIMIT 1
324
+ WHERE r.workspace = ? ORDER BY l.last_seen_at DESC, l.canonical_root ASC LIMIT 1
198
325
  `).get(workspace);
199
- return row === undefined ? undefined : { repositoryRoot: row.repositoryRoot, repositoryId: row.repositoryId, workspace: row.workspace, source: 'location' };
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' };
200
335
  }
201
336
  async function retrieveEntries(database, query) {
202
337
  const terms = [query.task, query.taskProfile.target, query.taskProfile.expected, ...query.recommendedTags]
@@ -204,62 +339,154 @@ async function retrieveEntries(database, query) {
204
339
  .map((value) => value.slice(0, 2_000));
205
340
  const queries = [retrievalQuery(query), ...terms];
206
341
  const entries = new Map();
207
- const project = projectForWorkspace(database, query.workspace);
208
342
  for (const value of queries) {
209
- if (project !== undefined) {
210
- for (const hit of await federatedEntries(database, { project, query: value, limit: 500 }))
211
- entries.set(hit.entry.id, { entry: hit.entry, origin: hit.origin });
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
+ }
212
352
  }
213
353
  else {
214
- for (const entry of searchEntries(database, { workspace: query.workspace, query: value, limit: 500, includeSuperseded: false }).items)
215
- entries.set(entry.id, { entry, origin: 'project' });
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
+ }
216
361
  }
217
362
  }
218
363
  return [...entries.values()];
219
364
  }
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
+ }
220
386
  async function rank(database, query, prior) {
221
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 }))));
222
389
  return rankContextCandidates({
223
390
  taskProfile: query.taskProfile,
224
391
  recommendedTags: query.recommendedTags,
225
392
  changedPaths: query.changedPaths,
226
393
  errorSignatures: query.errorSignatures,
227
394
  priorDelivered: prior.delivered,
228
- feedback: prior.feedback,
229
- candidates: entries.map(({ entry, origin }) => entrySnapshot(entry, origin)),
395
+ feedback,
396
+ candidates: entries.map(({ entry, origin, selectionReasons }) => entrySnapshot(entry, origin, selectionReasons)),
230
397
  limit: query.limit,
231
398
  characterBudget: query.characterBudget,
232
399
  });
233
400
  }
234
- function priorData(database, query) {
401
+ function priorData(database, query, options = {}) {
235
402
  if (query.run === null)
236
- return { delivered: [], feedback: [], stale: [] };
403
+ return { delivered: [], stale: [], stateHash: null };
237
404
  const deliveries = [];
238
405
  let cursor;
406
+ let complete = false;
239
407
  for (let page = 0; page < 10; page += 1) {
240
408
  const result = listContextDeliveries(database, { workspace: query.workspace, runId: query.run.runId, limit: 100, ...(cursor === undefined ? {} : { cursor }) });
241
409
  deliveries.push(...result.items);
242
- if (result.nextCursor === null)
410
+ if (result.nextCursor === null) {
411
+ complete = true;
243
412
  break;
413
+ }
244
414
  cursor = result.nextCursor;
245
415
  }
246
- const delivered = deliveries.flatMap((delivery) => delivery.items.map((item) => ({ entryId: item.entryId, revision: item.entryRevision })));
247
- const feedbackPage = listContextFeedback(database, { workspace: query.workspace, runId: query.run.runId, limit: 100 });
248
- const feedback = feedbackPage.records.map((record) => ({ entryId: record.entryId, verdict: record.verdict }));
249
- 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) => {
250
432
  const current = database.prepare('SELECT current_revision FROM entries WHERE id = ?').get(item.entryId);
251
433
  return current && Number(current.current_revision) > item.entryRevision ? [{ entryId: item.entryId, deliveredRevision: item.entryRevision, currentRevision: Number(current.current_revision), stale: true }] : [];
252
434
  }));
253
- 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
+ };
446
+ }
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,
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);
254
481
  }
255
482
  function outputContext(query, items, delivery) {
256
483
  const sourceItems = items.map((item, index) => ({
257
484
  entryId: item.entryId,
258
485
  entryRevision: item.revision,
259
486
  rank: index + 1,
260
- scoreComponents: item.scoreComponents,
487
+ scoreComponents: { ...item.scoreComponents },
261
488
  selectionReasons: [...item.selectionReasons],
262
- content: item.content,
489
+ content: { ...item.content },
263
490
  untrusted: true,
264
491
  ...(item.origin === undefined ? {} : { origin: item.origin }),
265
492
  }));
@@ -274,12 +501,12 @@ function outputContext(query, items, delivery) {
274
501
  untrusted: true,
275
502
  };
276
503
  }
277
- function deliveryInput(query, ranked, summary) {
504
+ function deliveryInput(query, ranked) {
278
505
  const items = ranked.map((item, index) => ({
279
506
  entryId: item.entryId,
280
507
  entryRevision: item.revision,
281
508
  rank: index + 1,
282
- scoreComponents: item.scoreComponents,
509
+ scoreComponents: { ...item.scoreComponents },
283
510
  selectionReasons: [...item.selectionReasons],
284
511
  ...(item.origin === undefined ? {} : { origin: item.origin }),
285
512
  }));
@@ -294,7 +521,6 @@ function deliveryInput(query, ranked, summary) {
294
521
  taskProfileHash: query.profileHash,
295
522
  queryHash: query.queryHash,
296
523
  policyVersion: CONTEXT_BROKER_POLICY_VERSION,
297
- externalSyncSummary: summary,
298
524
  charBudget: query.characterBudget,
299
525
  charCount,
300
526
  truncated,
@@ -302,19 +528,74 @@ function deliveryInput(query, ranked, summary) {
302
528
  items,
303
529
  };
304
530
  }
305
- function emptyExternalSummary() {
306
- 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;
307
585
  }
308
586
  function storedContext(database, query, delivery) {
309
587
  let remaining = query.characterBudget;
588
+ let totalCharacterCount = 0;
589
+ let anyTruncated = false;
310
590
  const items = delivery.items.map((item) => {
311
- const entry = database.prepare(`
312
- SELECT r.entry_id AS id, r.revision, r.title, r.summary, r.body
313
- FROM entry_revisions AS r
314
- WHERE r.entry_id = ? AND r.revision = ?
315
- `).get(item.entryId, item.entryRevision);
316
- if (!entry)
317
- 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
+ });
318
599
  const take = (value, budget) => Array.from(value).slice(0, Math.max(0, budget)).join('');
319
600
  const count = (value) => Array.from(value).length;
320
601
  const title = take(entry.title, remaining);
@@ -323,6 +604,12 @@ function storedContext(database, query, delivery) {
323
604
  remaining -= count(summary ?? '');
324
605
  const bodyPreview = take(entry.body, remaining);
325
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;
326
613
  return {
327
614
  entryId: item.entryId,
328
615
  entryRevision: item.entryRevision,
@@ -333,13 +620,16 @@ function storedContext(database, query, delivery) {
333
620
  title,
334
621
  summary,
335
622
  bodyPreview,
336
- characterCount: title.length + (summary?.length ?? 0) + bodyPreview.length,
337
- truncated: title.length < entry.title.length || (entry.summary !== null && summary?.length !== entry.summary.length) || bodyPreview.length < entry.body.length,
623
+ characterCount,
624
+ truncated,
338
625
  },
339
626
  untrusted: true,
340
627
  ...(item.origin === undefined ? {} : { origin: item.origin }),
341
628
  };
342
629
  });
630
+ if (totalCharacterCount !== delivery.charCount || anyTruncated !== delivery.truncated) {
631
+ throw new KiokukoError('INTEGRITY_ERROR', 'Stored context character accounting is invalid');
632
+ }
343
633
  return {
344
634
  deliveryId: delivery.deliveryId,
345
635
  runId: delivery.runId,
@@ -351,13 +641,87 @@ function storedContext(database, query, delivery) {
351
641
  untrusted: true,
352
642
  };
353
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
+ }
354
720
  export class ContextBroker {
355
721
  database;
356
- options;
357
722
  inFlight = new Map();
358
- constructor(database, options = {}) {
723
+ constructor(database) {
359
724
  this.database = database;
360
- this.options = options;
361
725
  }
362
726
  listDeliveries(input) {
363
727
  const context = currentRunContext(this.database, input.runId);
@@ -372,6 +736,20 @@ export class ContextBroker {
372
736
  };
373
737
  }
374
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) {
375
753
  const input = normalizeInput(rawInput);
376
754
  const query = preparedQuery(this.database, input);
377
755
  const previous = this.inFlight.get(query.queryHash);
@@ -388,6 +766,10 @@ export class ContextBroker {
388
766
  }
389
767
  }
390
768
  async queryPrepared(query, persistence) {
769
+ const prepared = await this.prepareResult(query);
770
+ return this.persistPrepared(prepared, persistence, query);
771
+ }
772
+ async prepareResult(query) {
391
773
  const base = {
392
774
  status: query.runStatus,
393
775
  taskProfile: { ...query.taskProfile },
@@ -398,63 +780,140 @@ export class ContextBroker {
398
780
  projection: query.projection,
399
781
  context: null,
400
782
  recommendations: query.projection === null ? [] : buildRecommendations({ projection: query.projection, broker: {} }),
401
- externalSyncSummary: emptyExternalSummary(),
402
783
  };
403
784
  if (query.runStatus === 'needs_answer')
404
- return base;
405
- const prior = priorData(this.database, query);
406
- const existing = query.deliveryId === null ? null : (() => {
407
- try {
408
- return readContextDelivery(this.database, { workspace: query.workspace, deliveryId: query.deliveryId });
409
- }
410
- catch (error) {
411
- if (error instanceof KiokukoError && error.code === 'NOT_FOUND')
412
- return null;
413
- throw error;
414
- }
415
- })();
416
- 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) {
417
794
  return {
418
- ...base,
419
- context: storedContext(this.database, query, existing),
420
- externalSyncSummary: existing.externalSyncSummary,
421
- 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,
422
802
  };
423
803
  }
424
- let ranked = await rank(this.database, query, prior);
425
- let externalSyncSummary = emptyExternalSummary();
426
- if (ranked.length < query.limit && query.taskProfile !== undefined && this.options.allowExternalSkillFallback === true) {
427
- const prepared = await prepareOfficialSourceSync({
428
- workspace: query.workspace,
429
- task: query.task,
430
- profile: query.taskProfile,
431
- recommendedTags: query.recommendedTags,
432
- ...(this.options.fetchImpl === undefined ? {} : { fetchImpl: this.options.fetchImpl }),
433
- });
434
- const result = persistence.persistSources === undefined
435
- ? persistOfficialSourceSync(this.database, { workspace: query.workspace, prepared })
436
- : await persistence.persistSources(query.workspace, prepared);
437
- externalSyncSummary = { attempted: result.attempted, imported: result.imported, sources: result.sources };
438
- ranked = await 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');
439
807
  }
808
+ const deliveryQuery = query.run === null
809
+ ? query
810
+ : {
811
+ ...query,
812
+ deliveryId: historyAttestedDeliveryId(query, prior.stateHash, query.deliveryHistoryExcludeQueryHash),
813
+ };
440
814
  const recommendations = query.projection === null
441
815
  ? []
442
816
  : buildRecommendations({ projection: query.projection, broker: { staleDeliveredEntries: prior.stale } });
443
- const context = outputContext(query, ranked, null);
444
- if (query.deliveryId === null || query.run === null) {
445
- 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 };
446
820
  }
447
- const deliveryRequest = deliveryInput(query, ranked, externalSyncSummary);
448
- const delivery = persistence.persistDelivery === undefined
449
- ? recordContextDelivery(this.database, deliveryRequest)
450
- : await persistence.persistDelivery(deliveryRequest);
451
- 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
+ });
452
917
  }
453
- }
454
- export function contextBrokerQueryHash(input) {
455
- return createHash('sha256').update(JSON.stringify(input), 'utf8').digest('hex');
456
- }
457
- export function newContextDeliveryId() {
458
- return `context-${randomUUID()}`;
459
918
  }
460
919
  //# sourceMappingURL=broker.js.map