@askdkc/kiokuko 0.1.17 → 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 (534) 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/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 +534 -148
  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 +28 -14
  108. package/dist/context/broker.d.ts.map +1 -1
  109. package/dist/context/broker.js +604 -145
  110. package/dist/context/broker.js.map +1 -1
  111. package/dist/context/delivery.d.ts +6 -21
  112. package/dist/context/delivery.d.ts.map +1 -1
  113. package/dist/context/delivery.js +196 -147
  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 +229 -261
  118. package/dist/context/feedback.js.map +1 -1
  119. package/dist/context/ranking.d.ts +1 -12
  120. package/dist/context/ranking.d.ts.map +1 -1
  121. package/dist/context/ranking.js +13 -4
  122. package/dist/context/ranking.js.map +1 -1
  123. package/dist/context/recommendations.d.ts +0 -5
  124. package/dist/context/recommendations.d.ts.map +1 -1
  125. package/dist/context/recommendations.js +0 -1
  126. package/dist/context/recommendations.js.map +1 -1
  127. package/dist/context/run-state.d.ts +26 -0
  128. package/dist/context/run-state.d.ts.map +1 -0
  129. package/dist/context/run-state.js +399 -0
  130. package/dist/context/run-state.js.map +1 -0
  131. package/dist/context/scoped-broker.d.ts +17 -5
  132. package/dist/context/scoped-broker.d.ts.map +1 -1
  133. package/dist/context/scoped-broker.js +512 -106
  134. package/dist/context/scoped-broker.js.map +1 -1
  135. package/dist/context/selection-state.d.ts +19 -0
  136. package/dist/context/selection-state.d.ts.map +1 -0
  137. package/dist/context/selection-state.js +250 -0
  138. package/dist/context/selection-state.js.map +1 -0
  139. package/dist/db/adapter.d.ts +5 -3
  140. package/dist/db/adapter.d.ts.map +1 -1
  141. package/dist/db/adapter.js +6 -3
  142. package/dist/db/adapter.js.map +1 -1
  143. package/dist/db/capabilities.d.ts.map +1 -1
  144. package/dist/db/capabilities.js +34 -16
  145. package/dist/db/capabilities.js.map +1 -1
  146. package/dist/db/connection.d.ts +8 -0
  147. package/dist/db/connection.d.ts.map +1 -1
  148. package/dist/db/connection.js +55 -26
  149. package/dist/db/connection.js.map +1 -1
  150. package/dist/db/migrate.d.ts +28 -7
  151. package/dist/db/migrate.d.ts.map +1 -1
  152. package/dist/db/migrate.js +106 -78
  153. package/dist/db/migrate.js.map +1 -1
  154. package/dist/db/sqlite-retry.d.ts +11 -0
  155. package/dist/db/sqlite-retry.d.ts.map +1 -0
  156. package/dist/db/sqlite-retry.js +66 -0
  157. package/dist/db/sqlite-retry.js.map +1 -0
  158. package/dist/db/transaction.d.ts +13 -0
  159. package/dist/db/transaction.d.ts.map +1 -1
  160. package/dist/db/transaction.js +53 -24
  161. package/dist/db/transaction.js.map +1 -1
  162. package/dist/db/upgrade-backup.d.ts +58 -2
  163. package/dist/db/upgrade-backup.d.ts.map +1 -1
  164. package/dist/db/upgrade-backup.js +757 -28
  165. package/dist/db/upgrade-backup.js.map +1 -1
  166. package/dist/errors.js +1 -1
  167. package/dist/errors.js.map +1 -1
  168. package/dist/gateway/agent-service.d.ts +4 -1
  169. package/dist/gateway/agent-service.d.ts.map +1 -1
  170. package/dist/gateway/agent-service.js +71 -58
  171. package/dist/gateway/agent-service.js.map +1 -1
  172. package/dist/gateway/checkpoint-service.d.ts +1 -0
  173. package/dist/gateway/checkpoint-service.d.ts.map +1 -1
  174. package/dist/gateway/checkpoint-service.js +47 -24
  175. package/dist/gateway/checkpoint-service.js.map +1 -1
  176. package/dist/ledger/archive.d.ts +1 -4
  177. package/dist/ledger/archive.d.ts.map +1 -1
  178. package/dist/ledger/archive.js +77 -39
  179. package/dist/ledger/archive.js.map +1 -1
  180. package/dist/ledger/maintenance.d.ts +0 -11
  181. package/dist/ledger/maintenance.d.ts.map +1 -1
  182. package/dist/ledger/maintenance.js +24 -40
  183. package/dist/ledger/maintenance.js.map +1 -1
  184. package/dist/ledger/projection.d.ts +0 -1
  185. package/dist/ledger/projection.d.ts.map +1 -1
  186. package/dist/ledger/projection.js.map +1 -1
  187. package/dist/ledger/promotion.d.ts +0 -9
  188. package/dist/ledger/promotion.d.ts.map +1 -1
  189. package/dist/ledger/promotion.js.map +1 -1
  190. package/dist/ledger/query.d.ts +1 -15
  191. package/dist/ledger/query.d.ts.map +1 -1
  192. package/dist/ledger/query.js.map +1 -1
  193. package/dist/ledger/store.d.ts +0 -1
  194. package/dist/ledger/store.d.ts.map +1 -1
  195. package/dist/ledger/store.js +11 -8
  196. package/dist/ledger/store.js.map +1 -1
  197. package/dist/ledger/types.d.ts +0 -4
  198. package/dist/ledger/types.d.ts.map +1 -1
  199. package/dist/ledger/types.js.map +1 -1
  200. package/dist/ledger/validate.d.ts.map +1 -1
  201. package/dist/ledger/validate.js +0 -5
  202. package/dist/ledger/validate.js.map +1 -1
  203. package/dist/mcp/server.d.ts +4 -0
  204. package/dist/mcp/server.d.ts.map +1 -1
  205. package/dist/mcp/server.js +105 -54
  206. package/dist/mcp/server.js.map +1 -1
  207. package/dist/memory/audit.d.ts +0 -1
  208. package/dist/memory/audit.d.ts.map +1 -1
  209. package/dist/memory/audit.js +0 -1
  210. package/dist/memory/audit.js.map +1 -1
  211. package/dist/memory/curator.d.ts.map +1 -1
  212. package/dist/memory/curator.js +172 -96
  213. package/dist/memory/curator.js.map +1 -1
  214. package/dist/memory/entries.d.ts +12 -2
  215. package/dist/memory/entries.d.ts.map +1 -1
  216. package/dist/memory/entries.js +198 -114
  217. package/dist/memory/entries.js.map +1 -1
  218. package/dist/memory/federated-retrieval.d.ts +12 -1
  219. package/dist/memory/federated-retrieval.d.ts.map +1 -1
  220. package/dist/memory/federated-retrieval.js +183 -70
  221. package/dist/memory/federated-retrieval.js.map +1 -1
  222. package/dist/memory/hybrid-retrieval.d.ts +5 -11
  223. package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
  224. package/dist/memory/hybrid-retrieval.js +78 -58
  225. package/dist/memory/hybrid-retrieval.js.map +1 -1
  226. package/dist/memory/lifecycle.d.ts.map +1 -1
  227. package/dist/memory/lifecycle.js +17 -13
  228. package/dist/memory/lifecycle.js.map +1 -1
  229. package/dist/memory/rebuild-search.d.ts +5 -0
  230. package/dist/memory/rebuild-search.d.ts.map +1 -1
  231. package/dist/memory/rebuild-search.js +101 -76
  232. package/dist/memory/rebuild-search.js.map +1 -1
  233. package/dist/memory/retrieval-query.d.ts +0 -5
  234. package/dist/memory/retrieval-query.d.ts.map +1 -1
  235. package/dist/memory/retrieval-query.js +0 -5
  236. package/dist/memory/retrieval-query.js.map +1 -1
  237. package/dist/memory/retrieval.d.ts.map +1 -1
  238. package/dist/memory/retrieval.js +25 -131
  239. package/dist/memory/retrieval.js.map +1 -1
  240. package/dist/memory/revisions.d.ts +76 -1
  241. package/dist/memory/revisions.d.ts.map +1 -1
  242. package/dist/memory/revisions.js +539 -35
  243. package/dist/memory/revisions.js.map +1 -1
  244. package/dist/memory/scoped-memory.d.ts +16 -1
  245. package/dist/memory/scoped-memory.d.ts.map +1 -1
  246. package/dist/memory/scoped-memory.js +240 -107
  247. package/dist/memory/scoped-memory.js.map +1 -1
  248. package/dist/memory/secrets.d.ts +2 -0
  249. package/dist/memory/secrets.d.ts.map +1 -1
  250. package/dist/memory/secrets.js +36 -0
  251. package/dist/memory/secrets.js.map +1 -1
  252. package/dist/memory/structured-memory.d.ts +3 -2
  253. package/dist/memory/structured-memory.d.ts.map +1 -1
  254. package/dist/memory/structured-memory.js +54 -22
  255. package/dist/memory/structured-memory.js.map +1 -1
  256. package/dist/memory/workspaces.d.ts +9 -0
  257. package/dist/memory/workspaces.d.ts.map +1 -1
  258. package/dist/memory/workspaces.js +67 -0
  259. package/dist/memory/workspaces.js.map +1 -1
  260. package/dist/package-version.d.ts +2 -0
  261. package/dist/package-version.d.ts.map +1 -0
  262. package/dist/package-version.js +7 -0
  263. package/dist/package-version.js.map +1 -0
  264. package/dist/repository/binding.d.ts +5 -0
  265. package/dist/repository/binding.d.ts.map +1 -1
  266. package/dist/repository/binding.js +117 -17
  267. package/dist/repository/binding.js.map +1 -1
  268. package/dist/repository/framework-version.d.ts +8 -0
  269. package/dist/repository/framework-version.d.ts.map +1 -0
  270. package/dist/repository/framework-version.js +29 -0
  271. package/dist/repository/framework-version.js.map +1 -0
  272. package/dist/repository/identity-value.d.ts +4 -0
  273. package/dist/repository/identity-value.d.ts.map +1 -0
  274. package/dist/repository/identity-value.js +24 -0
  275. package/dist/repository/identity-value.js.map +1 -0
  276. package/dist/repository/identity.d.ts.map +1 -1
  277. package/dist/repository/identity.js +2 -0
  278. package/dist/repository/identity.js.map +1 -1
  279. package/dist/repository/project-fingerprint.d.ts +14 -2
  280. package/dist/repository/project-fingerprint.d.ts.map +1 -1
  281. package/dist/repository/project-fingerprint.js +312 -33
  282. package/dist/repository/project-fingerprint.js.map +1 -1
  283. package/dist/repository/remote-url.d.ts +0 -1
  284. package/dist/repository/remote-url.d.ts.map +1 -1
  285. package/dist/repository/remote-url.js +0 -1
  286. package/dist/repository/remote-url.js.map +1 -1
  287. package/dist/runtime-version.d.ts +2 -1
  288. package/dist/runtime-version.d.ts.map +1 -1
  289. package/dist/runtime-version.js +21 -4
  290. package/dist/runtime-version.js.map +1 -1
  291. package/dist/serialization/boundary-json.d.ts +20 -0
  292. package/dist/serialization/boundary-json.d.ts.map +1 -0
  293. package/dist/serialization/boundary-json.js +129 -0
  294. package/dist/serialization/boundary-json.js.map +1 -0
  295. package/dist/serialization/envelope.js +1 -1
  296. package/dist/serialization/envelope.js.map +1 -1
  297. package/dist/serialization/validate.d.ts +7 -0
  298. package/dist/serialization/validate.d.ts.map +1 -1
  299. package/dist/serialization/validate.js +53 -13
  300. package/dist/serialization/validate.js.map +1 -1
  301. package/dist/server/app.js +1 -1
  302. package/dist/server/app.js.map +1 -1
  303. package/dist/server/http.d.ts +4 -3
  304. package/dist/server/http.d.ts.map +1 -1
  305. package/dist/server/http.js +90 -50
  306. package/dist/server/http.js.map +1 -1
  307. package/dist/server/idempotency.d.ts +0 -6
  308. package/dist/server/idempotency.d.ts.map +1 -1
  309. package/dist/server/idempotency.js.map +1 -1
  310. package/dist/server/router.d.ts.map +1 -1
  311. package/dist/server/router.js +21 -4
  312. package/dist/server/router.js.map +1 -1
  313. package/dist/server/routes/agent-capability-gate.d.ts +40 -0
  314. package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
  315. package/dist/server/routes/agent-capability-gate.js +182 -0
  316. package/dist/server/routes/agent-capability-gate.js.map +1 -0
  317. package/dist/server/routes/agent-events.d.ts.map +1 -1
  318. package/dist/server/routes/agent-events.js +8 -1
  319. package/dist/server/routes/agent-events.js.map +1 -1
  320. package/dist/server/routes/agent-intake.d.ts.map +1 -1
  321. package/dist/server/routes/agent-intake.js +10 -2
  322. package/dist/server/routes/agent-intake.js.map +1 -1
  323. package/dist/server/routes/agent-promotions.d.ts.map +1 -1
  324. package/dist/server/routes/agent-promotions.js +5 -2
  325. package/dist/server/routes/agent-promotions.js.map +1 -1
  326. package/dist/server/routes/agent-runs.d.ts.map +1 -1
  327. package/dist/server/routes/agent-runs.js +18 -4
  328. package/dist/server/routes/agent-runs.js.map +1 -1
  329. package/dist/server/routes/request-binding.d.ts +5 -0
  330. package/dist/server/routes/request-binding.d.ts.map +1 -0
  331. package/dist/server/routes/request-binding.js +49 -0
  332. package/dist/server/routes/request-binding.js.map +1 -0
  333. package/dist/server/routes/task5-support.d.ts +1 -8
  334. package/dist/server/routes/task5-support.d.ts.map +1 -1
  335. package/dist/server/routes/task5-support.js +1 -17
  336. package/dist/server/routes/task5-support.js.map +1 -1
  337. package/dist/server/routes/task5.d.ts.map +1 -1
  338. package/dist/server/routes/task5.js +106 -36
  339. package/dist/server/routes/task5.js.map +1 -1
  340. package/dist/server/write-queue.js +2 -2
  341. package/dist/server/write-queue.js.map +1 -1
  342. package/dist/setup/claude-config.d.ts +2 -1
  343. package/dist/setup/claude-config.d.ts.map +1 -1
  344. package/dist/setup/claude-config.js +54 -4
  345. package/dist/setup/claude-config.js.map +1 -1
  346. package/dist/setup/client-detection.d.ts +7 -2
  347. package/dist/setup/client-detection.d.ts.map +1 -1
  348. package/dist/setup/client-detection.js +27 -9
  349. package/dist/setup/client-detection.js.map +1 -1
  350. package/dist/setup/hermes-config.d.ts +2 -1
  351. package/dist/setup/hermes-config.d.ts.map +1 -1
  352. package/dist/setup/hermes-config.js +53 -12
  353. package/dist/setup/hermes-config.js.map +1 -1
  354. package/dist/setup/legacy-client-cleanup.d.ts +6 -0
  355. package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
  356. package/dist/setup/legacy-client-cleanup.js +152 -0
  357. package/dist/setup/legacy-client-cleanup.js.map +1 -0
  358. package/dist/setup/managed-text.d.ts.map +1 -1
  359. package/dist/setup/managed-text.js +11 -1
  360. package/dist/setup/managed-text.js.map +1 -1
  361. package/dist/setup/opencode-config.d.ts +2 -1
  362. package/dist/setup/opencode-config.d.ts.map +1 -1
  363. package/dist/setup/opencode-config.js +57 -5
  364. package/dist/setup/opencode-config.js.map +1 -1
  365. package/dist/setup/render.d.ts +2 -1
  366. package/dist/setup/render.d.ts.map +1 -1
  367. package/dist/setup/render.js +91 -17
  368. package/dist/setup/render.js.map +1 -1
  369. package/dist/setup/standard-skills.d.ts +16 -2
  370. package/dist/setup/standard-skills.d.ts.map +1 -1
  371. package/dist/setup/standard-skills.js +37 -13
  372. package/dist/setup/standard-skills.js.map +1 -1
  373. package/dist/setup/strict-json.d.ts +7 -0
  374. package/dist/setup/strict-json.d.ts.map +1 -0
  375. package/dist/setup/strict-json.js +98 -0
  376. package/dist/setup/strict-json.js.map +1 -0
  377. package/dist/setup/strict-toml.d.ts +7 -0
  378. package/dist/setup/strict-toml.d.ts.map +1 -0
  379. package/dist/setup/strict-toml.js +470 -0
  380. package/dist/setup/strict-toml.js.map +1 -0
  381. package/dist/skills/cache.d.ts +15 -0
  382. package/dist/skills/cache.d.ts.map +1 -0
  383. package/dist/skills/cache.js +19 -0
  384. package/dist/skills/cache.js.map +1 -0
  385. package/dist/skills/candidate-ranking.d.ts +15 -0
  386. package/dist/skills/candidate-ranking.d.ts.map +1 -0
  387. package/dist/skills/candidate-ranking.js +52 -0
  388. package/dist/skills/candidate-ranking.js.map +1 -0
  389. package/dist/skills/chunking.d.ts +11 -0
  390. package/dist/skills/chunking.d.ts.map +1 -0
  391. package/dist/skills/chunking.js +291 -0
  392. package/dist/skills/chunking.js.map +1 -0
  393. package/dist/skills/config.d.ts +19 -0
  394. package/dist/skills/config.d.ts.map +1 -0
  395. package/dist/skills/config.js +103 -0
  396. package/dist/skills/config.js.map +1 -0
  397. package/dist/skills/discovery-service.d.ts +26 -0
  398. package/dist/skills/discovery-service.d.ts.map +1 -0
  399. package/dist/skills/discovery-service.js +921 -0
  400. package/dist/skills/discovery-service.js.map +1 -0
  401. package/dist/skills/external-transport.d.ts +2 -0
  402. package/dist/skills/external-transport.d.ts.map +1 -0
  403. package/dist/skills/external-transport.js +30 -0
  404. package/dist/skills/external-transport.js.map +1 -0
  405. package/dist/skills/find.d.ts +16 -0
  406. package/dist/skills/find.d.ts.map +1 -0
  407. package/dist/skills/find.js +58 -0
  408. package/dist/skills/find.js.map +1 -0
  409. package/dist/skills/gap-detection.d.ts +23 -0
  410. package/dist/skills/gap-detection.d.ts.map +1 -0
  411. package/dist/skills/gap-detection.js +62 -0
  412. package/dist/skills/gap-detection.js.map +1 -0
  413. package/dist/skills/import-preparation.d.ts +4 -0
  414. package/dist/skills/import-preparation.d.ts.map +1 -0
  415. package/dist/skills/import-preparation.js +20 -0
  416. package/dist/skills/import-preparation.js.map +1 -0
  417. package/dist/skills/materialization-authority.d.ts +11 -0
  418. package/dist/skills/materialization-authority.d.ts.map +1 -0
  419. package/dist/skills/materialization-authority.js +92 -0
  420. package/dist/skills/materialization-authority.js.map +1 -0
  421. package/dist/skills/materialization-service.d.ts +22 -0
  422. package/dist/skills/materialization-service.d.ts.map +1 -0
  423. package/dist/skills/materialization-service.js +101 -0
  424. package/dist/skills/materialization-service.js.map +1 -0
  425. package/dist/skills/official-catalog.d.ts +31 -0
  426. package/dist/skills/official-catalog.d.ts.map +1 -0
  427. package/dist/skills/official-catalog.js +110 -0
  428. package/dist/skills/official-catalog.js.map +1 -0
  429. package/dist/skills/providers/schema.d.ts +30 -0
  430. package/dist/skills/providers/schema.d.ts.map +1 -0
  431. package/dist/skills/providers/schema.js +354 -0
  432. package/dist/skills/providers/schema.js.map +1 -0
  433. package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
  434. package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
  435. package/dist/skills/providers/skills-sh-compat.js +71 -0
  436. package/dist/skills/providers/skills-sh-compat.js.map +1 -0
  437. package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
  438. package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
  439. package/dist/skills/providers/skills-sh-v1.js +134 -0
  440. package/dist/skills/providers/skills-sh-v1.js.map +1 -0
  441. package/dist/skills/query-builder.d.ts +18 -0
  442. package/dist/skills/query-builder.d.ts.map +1 -0
  443. package/dist/skills/query-builder.js +93 -0
  444. package/dist/skills/query-builder.js.map +1 -0
  445. package/dist/skills/source/errors.d.ts +9 -0
  446. package/dist/skills/source/errors.d.ts.map +1 -0
  447. package/dist/skills/source/errors.js +15 -0
  448. package/dist/skills/source/errors.js.map +1 -0
  449. package/dist/skills/source/frontmatter.d.ts +9 -0
  450. package/dist/skills/source/frontmatter.d.ts.map +1 -0
  451. package/dist/skills/source/frontmatter.js +77 -0
  452. package/dist/skills/source/frontmatter.js.map +1 -0
  453. package/dist/skills/source/github-fetcher.d.ts +20 -0
  454. package/dist/skills/source/github-fetcher.d.ts.map +1 -0
  455. package/dist/skills/source/github-fetcher.js +292 -0
  456. package/dist/skills/source/github-fetcher.js.map +1 -0
  457. package/dist/skills/source/snapshot-validator.d.ts +28 -0
  458. package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
  459. package/dist/skills/source/snapshot-validator.js +186 -0
  460. package/dist/skills/source/snapshot-validator.js.map +1 -0
  461. package/dist/skills/store.d.ts +181 -0
  462. package/dist/skills/store.d.ts.map +1 -0
  463. package/dist/skills/store.js +1710 -0
  464. package/dist/skills/store.js.map +1 -0
  465. package/dist/skills/types.d.ts +169 -0
  466. package/dist/skills/types.d.ts.map +1 -0
  467. package/dist/skills/types.js +2 -0
  468. package/dist/skills/types.js.map +1 -0
  469. package/dist/web/i18n.d.ts +32 -0
  470. package/dist/web/i18n.d.ts.map +1 -1
  471. package/dist/web/i18n.js +128 -0
  472. package/dist/web/i18n.js.map +1 -1
  473. package/dist/web/server.d.ts.map +1 -1
  474. package/dist/web/server.js +386 -38
  475. package/dist/web/server.js.map +1 -1
  476. package/dist/web/ui.d.ts +4 -0
  477. package/dist/web/ui.d.ts.map +1 -1
  478. package/dist/web/ui.js +382 -6
  479. package/dist/web/ui.js.map +1 -1
  480. package/migrations/009_external_skill_discovery.sql +126 -0
  481. package/package.json +4 -3
  482. package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
  483. package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
  484. package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
  485. package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
  486. package/templates/AGENTS.md +8 -7
  487. package/dist/client/runtime-discovery.d.ts +0 -15
  488. package/dist/client/runtime-discovery.d.ts.map +0 -1
  489. package/dist/client/runtime-discovery.js +0 -45
  490. package/dist/client/runtime-discovery.js.map +0 -1
  491. package/dist/commands/call.d.ts +0 -7
  492. package/dist/commands/call.d.ts.map +0 -1
  493. package/dist/commands/call.js +0 -10
  494. package/dist/commands/call.js.map +0 -1
  495. package/dist/commands/link.d.ts +0 -6
  496. package/dist/commands/link.d.ts.map +0 -1
  497. package/dist/commands/link.js +0 -6
  498. package/dist/commands/link.js.map +0 -1
  499. package/dist/commands/promote.d.ts +0 -6
  500. package/dist/commands/promote.d.ts.map +0 -1
  501. package/dist/commands/promote.js +0 -6
  502. package/dist/commands/promote.js.map +0 -1
  503. package/dist/commands/read.d.ts +0 -6
  504. package/dist/commands/read.d.ts.map +0 -1
  505. package/dist/commands/read.js +0 -4
  506. package/dist/commands/read.js.map +0 -1
  507. package/dist/commands/recall.d.ts +0 -6
  508. package/dist/commands/recall.d.ts.map +0 -1
  509. package/dist/commands/recall.js +0 -4
  510. package/dist/commands/recall.js.map +0 -1
  511. package/dist/commands/record.d.ts +0 -6
  512. package/dist/commands/record.d.ts.map +0 -1
  513. package/dist/commands/record.js +0 -4
  514. package/dist/commands/record.js.map +0 -1
  515. package/dist/commands/search.d.ts +0 -6
  516. package/dist/commands/search.d.ts.map +0 -1
  517. package/dist/commands/search.js +0 -4
  518. package/dist/commands/search.js.map +0 -1
  519. package/dist/commands/supersede.d.ts +0 -6
  520. package/dist/commands/supersede.d.ts.map +0 -1
  521. package/dist/commands/supersede.js +0 -6
  522. package/dist/commands/supersede.js.map +0 -1
  523. package/dist/knowledge/sources.d.ts +0 -72
  524. package/dist/knowledge/sources.d.ts.map +0 -1
  525. package/dist/knowledge/sources.js +0 -388
  526. package/dist/knowledge/sources.js.map +0 -1
  527. package/dist/setup/opencode-evidence.d.ts +0 -37
  528. package/dist/setup/opencode-evidence.d.ts.map +0 -1
  529. package/dist/setup/opencode-evidence.js +0 -58
  530. package/dist/setup/opencode-evidence.js.map +0 -1
  531. package/dist/setup/opencode-loop-guard.d.ts +0 -9
  532. package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
  533. package/dist/setup/opencode-loop-guard.js +0 -248
  534. package/dist/setup/opencode-loop-guard.js.map +0 -1
@@ -1,11 +1,15 @@
1
- import { readFile, unlink } from 'node:fs/promises';
1
+ import { randomUUID } from 'node:crypto';
2
+ import { lstat } from 'node:fs/promises';
2
3
  import path from 'node:path';
3
- import { atomicWriteText, readRegularFile } from '../agent-file/atomic-write.js';
4
+ import { setTimeout as delay } from 'node:timers/promises';
5
+ import { assertFileExpectation, assertAtomicCleanupComplete, AtomicCommittedMutationError, AtomicCommittedUnlinkError, atomicWriteTextIfUnchanged, readPendingAtomicMutation, readRegularFile, unlinkRegularFileIfUnchanged, } from '../agent-file/atomic-write.js';
6
+ import { readManagedBlockTemplateVersion, removeManagedBlock, } from '../agent-file/managed-block.js';
4
7
  import { AGENT_TEMPLATE_VERSION, renderAgentFile } from '../agent-file/render.js';
5
8
  import { getGlobalDatabasePath } from '../config/paths.js';
6
- import { readProjectConfig } from '../config/project-config.js';
9
+ import { parseProjectConfig, parseProjectConfigText, } from '../config/project-config.js';
7
10
  import { initializeDatabase } from './init.js';
8
11
  import { openConnection } from '../db/connection.js';
12
+ import { TransactionCommitUncertainError } from '../db/transaction.js';
9
13
  import { registerRepositoryAndLocation } from '../repository/binding.js';
10
14
  import { detectRepositoryRoot } from '../repository/detect-root.js';
11
15
  import { createRepositoryIdentity } from '../repository/identity.js';
@@ -14,20 +18,15 @@ import { readGitOrigin } from '../repository/git-origin.js';
14
18
  function ensureChildPath(root, filePath) {
15
19
  const resolvedRoot = path.resolve(root);
16
20
  const resolvedPath = path.resolve(root, filePath);
17
- if (resolvedPath !== resolvedRoot && !resolvedPath.startsWith(`${resolvedRoot}${path.sep}`)) {
21
+ if (resolvedPath === resolvedRoot || !resolvedPath.startsWith(`${resolvedRoot}${path.sep}`)) {
18
22
  throw new KiokukoError('VALIDATION_ERROR', 'agentFile must remain inside the repository root');
19
23
  }
20
24
  return resolvedPath;
21
25
  }
22
- async function readOptionalText(filePath) {
23
- try {
24
- return await readFile(filePath, 'utf8');
25
- }
26
- catch (error) {
27
- if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
28
- return undefined;
29
- throw error;
30
- }
26
+ function parseBindingSnapshot(snapshot) {
27
+ if (snapshot === undefined)
28
+ return undefined;
29
+ return parseProjectConfigText(snapshot.content);
31
30
  }
32
31
  function bindingText(value) {
33
32
  return `${JSON.stringify(value, null, 2)}\n`;
@@ -42,7 +41,497 @@ function preferredCliCommand() {
42
41
  ? 'npm exec -- kiokuko'
43
42
  : 'kiokuko';
44
43
  }
45
- export async function useRepository(options = {}) {
44
+ class ConcurrentUseBinding extends Error {
45
+ binding;
46
+ constructor(binding) {
47
+ super('A concurrent use operation created the repository binding');
48
+ this.binding = binding;
49
+ this.name = 'ConcurrentUseBinding';
50
+ }
51
+ }
52
+ const CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS = 50;
53
+ const CONCURRENT_IDENTICAL_OBSERVATION_DELAY_MS = 10;
54
+ class CommittedRegistrationCloseError extends AggregateError {
55
+ constructor(closeError) {
56
+ super([closeError], 'Repository registration committed, but closing the database connection failed');
57
+ this.name = 'CommittedRegistrationCloseError';
58
+ }
59
+ }
60
+ class UncertainRegistrationCloseError extends AggregateError {
61
+ registrationError;
62
+ closeError;
63
+ constructor(registrationError, closeError) {
64
+ super([registrationError, closeError], 'Repository registration may have committed, and closing the database connection also failed');
65
+ this.name = 'UncertainRegistrationCloseError';
66
+ this.registrationError = registrationError;
67
+ this.closeError = closeError;
68
+ }
69
+ }
70
+ function expectation(expected, containmentRoot, parentIdentity) {
71
+ return {
72
+ expected,
73
+ containmentRoot,
74
+ ...(parentIdentity === undefined ? {} : { expectedParentDirectory: parentIdentity }),
75
+ };
76
+ }
77
+ async function existingParentIdentity(filePath) {
78
+ let info;
79
+ try {
80
+ info = await lstat(path.dirname(filePath), { bigint: true });
81
+ }
82
+ catch (error) {
83
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
84
+ throw new KiokukoError('VALIDATION_ERROR', 'Managed file parent directory must already exist');
85
+ }
86
+ throw error;
87
+ }
88
+ if (info.isSymbolicLink()) {
89
+ throw new KiokukoError('SECURITY_REJECTION', 'Refusing to traverse a symbolic link');
90
+ }
91
+ if (!info.isDirectory()) {
92
+ throw new KiokukoError('VALIDATION_ERROR', 'Managed file parent must be a directory');
93
+ }
94
+ const identity = { device: BigInt(info.dev), inode: BigInt(info.ino) };
95
+ if (identity.inode === 0n) {
96
+ throw new KiokukoError('SECURITY_REJECTION', 'The filesystem does not expose a stable parent-directory identity required for safe mutation');
97
+ }
98
+ return identity;
99
+ }
100
+ async function restoreInstalledWrites(files, dependencies) {
101
+ const failures = [];
102
+ for (const file of [...files].reverse()) {
103
+ try {
104
+ if (file.original === undefined) {
105
+ if (file.installed === undefined) {
106
+ throw new KiokukoError('INTEGRITY_ERROR', 'Invalid file-restoration state');
107
+ }
108
+ const outcome = await dependencies.unlinkRegularFileIfUnchanged(file.path, expectation(file.installed, file.containmentRoot, file.parentIdentity));
109
+ assertAtomicCleanupComplete(outcome);
110
+ }
111
+ else {
112
+ const outcome = await dependencies.atomicWriteTextIfUnchanged(file.path, file.original.content, expectation(file.installed, file.containmentRoot, file.parentIdentity), file.original.mode);
113
+ assertAtomicCleanupComplete(outcome);
114
+ }
115
+ }
116
+ catch (error) {
117
+ failures.push(error);
118
+ }
119
+ }
120
+ return failures;
121
+ }
122
+ function isConflict(error) {
123
+ return error instanceof KiokukoError && error.code === 'CONFLICT';
124
+ }
125
+ function isTargetConflict(error, filePath) {
126
+ return isConflict(error) && error.details.target === filePath;
127
+ }
128
+ function sameFileIdentity(left, right) {
129
+ return left.device === right.device && left.inode === right.inode;
130
+ }
131
+ function assertSupportedManagedTemplate(snapshot, label) {
132
+ if (snapshot === undefined)
133
+ return;
134
+ const version = readManagedBlockTemplateVersion(snapshot.content);
135
+ if (version !== undefined && version > AGENT_TEMPLATE_VERSION) {
136
+ throw new KiokukoError('VALIDATION_ERROR', `${label} uses managed template version ${version}, newer than supported version ${AGENT_TEMPLATE_VERSION}`);
137
+ }
138
+ }
139
+ function sameRegularFileSnapshot(left, right) {
140
+ return left.content === right.content
141
+ && left.mode === right.mode
142
+ && sameFileIdentity(left.identity, right.identity);
143
+ }
144
+ async function readObservedTarget(filePath, containmentRoot, parentIdentity) {
145
+ const current = await readRegularFile(filePath, { containmentRoot });
146
+ await assertFileExpectation(filePath, expectation(current, containmentRoot, parentIdentity));
147
+ if (current === undefined)
148
+ return undefined;
149
+ let info;
150
+ try {
151
+ info = await lstat(filePath, { bigint: true });
152
+ }
153
+ catch (error) {
154
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
155
+ throw new KiokukoError('CONFLICT', 'Concurrent target changed during convergence', {
156
+ target: filePath,
157
+ });
158
+ }
159
+ throw error;
160
+ }
161
+ if (!info.isFile()
162
+ || info.dev !== current.identity.device
163
+ || info.ino !== current.identity.inode
164
+ || Number(info.mode & 511n) !== current.mode) {
165
+ throw new KiokukoError('CONFLICT', 'Concurrent target changed during convergence', {
166
+ target: filePath,
167
+ });
168
+ }
169
+ await assertFileExpectation(filePath, expectation(current, containmentRoot, parentIdentity));
170
+ return { snapshot: current, linkCount: info.nlink };
171
+ }
172
+ async function readStrictSettledTarget(filePath, containmentRoot, parentIdentity, label) {
173
+ const first = await readObservedTarget(filePath, containmentRoot, parentIdentity);
174
+ const firstPending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
175
+ if (firstPending !== undefined) {
176
+ throw new KiokukoError('CONFLICT', `${label} has a concurrent atomic mutation`, {
177
+ target: filePath,
178
+ });
179
+ }
180
+ const second = await readObservedTarget(filePath, containmentRoot, parentIdentity);
181
+ const secondPending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
182
+ if (secondPending !== undefined
183
+ || (first === undefined) !== (second === undefined)
184
+ || (first !== undefined
185
+ && second !== undefined
186
+ && !sameRegularFileSnapshot(first.snapshot, second.snapshot))) {
187
+ throw new KiokukoError('CONFLICT', `${label} changed while settling`, {
188
+ target: filePath,
189
+ });
190
+ }
191
+ const linked = first?.linkCount !== undefined && first.linkCount !== 1n
192
+ ? first
193
+ : second?.linkCount !== undefined && second.linkCount !== 1n
194
+ ? second
195
+ : undefined;
196
+ if (linked !== undefined) {
197
+ throw new KiokukoError('SECURITY_REJECTION', `${label} must have exactly one link`, {
198
+ target: filePath,
199
+ });
200
+ }
201
+ return second?.snapshot;
202
+ }
203
+ async function observeConcurrentTarget(filePath, content, mode, containmentRoot, parentIdentity) {
204
+ const observed = await readObservedTarget(filePath, containmentRoot, parentIdentity);
205
+ if (observed === undefined)
206
+ return { kind: 'absent' };
207
+ if (observed.snapshot.content !== content || observed.snapshot.mode !== mode) {
208
+ return { kind: 'different' };
209
+ }
210
+ if (observed.linkCount !== 1n)
211
+ return { kind: 'linked', snapshot: observed.snapshot };
212
+ return { kind: 'identical', snapshot: observed.snapshot };
213
+ }
214
+ async function readIdenticalTargetAfterConflict(filePath, content, mode, containmentRoot, parentIdentity, planned) {
215
+ let settlingCandidate;
216
+ let lastObservation;
217
+ let lastHadPendingArtifact = false;
218
+ for (let attempt = 0; attempt < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS; attempt += 1) {
219
+ const observation = await observeConcurrentTarget(filePath, content, mode, containmentRoot, parentIdentity);
220
+ if (settlingCandidate !== undefined) {
221
+ if (observation.kind === 'absent')
222
+ return undefined;
223
+ if (observation.kind === 'different'
224
+ || !sameRegularFileSnapshot(settlingCandidate, observation.snapshot)) {
225
+ throw new KiokukoError('CONFLICT', 'Concurrent target changed while settling', {
226
+ target: filePath,
227
+ });
228
+ }
229
+ }
230
+ lastObservation = observation;
231
+ if (observation.kind === 'different')
232
+ return undefined;
233
+ if (observation.kind === 'absent') {
234
+ if (planned === undefined)
235
+ return undefined;
236
+ const pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
237
+ if (pending === undefined
238
+ || pending.kind !== 'previous'
239
+ || !sameRegularFileSnapshot(pending.snapshot, planned)) {
240
+ return undefined;
241
+ }
242
+ lastHadPendingArtifact = true;
243
+ }
244
+ else if (observation.kind === 'linked') {
245
+ settlingCandidate = observation.snapshot;
246
+ lastHadPendingArtifact = false;
247
+ }
248
+ else {
249
+ if (planned !== undefined
250
+ && sameFileIdentity(observation.snapshot.identity, planned.identity)) {
251
+ throw new KiokukoError('CONFLICT', 'Concurrent target was modified in place instead of atomically replaced', { target: filePath });
252
+ }
253
+ const pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
254
+ if (pending === undefined)
255
+ return observation.snapshot;
256
+ if (planned === undefined
257
+ || pending.kind !== 'previous'
258
+ || !sameRegularFileSnapshot(pending.snapshot, planned)) {
259
+ throw new KiokukoError('CONFLICT', 'Concurrent target retained an incompatible atomic artifact', { target: filePath });
260
+ }
261
+ settlingCandidate = observation.snapshot;
262
+ lastHadPendingArtifact = true;
263
+ }
264
+ if (attempt + 1 < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS) {
265
+ await delay(CONCURRENT_IDENTICAL_OBSERVATION_DELAY_MS);
266
+ }
267
+ }
268
+ if (lastObservation?.kind === 'linked') {
269
+ throw new KiokukoError('SECURITY_REJECTION', 'Refusing to adopt a hard-linked concurrent target', { target: filePath });
270
+ }
271
+ if (lastHadPendingArtifact) {
272
+ throw new KiokukoError('CONFLICT', 'Concurrent target mutation did not settle', {
273
+ target: filePath,
274
+ });
275
+ }
276
+ return undefined;
277
+ }
278
+ async function writeOrConvergeIdentical(dependencies, filePath, content, planned, mode, containmentRoot, parentIdentity) {
279
+ try {
280
+ const outcome = await dependencies.atomicWriteTextIfUnchanged(filePath, content, expectation(planned, containmentRoot, parentIdentity), mode);
281
+ return {
282
+ snapshot: outcome.installed,
283
+ owned: true,
284
+ cleanupFailures: outcome.cleanupFailures,
285
+ };
286
+ }
287
+ catch (error) {
288
+ if (!isTargetConflict(error, filePath))
289
+ throw error;
290
+ const current = await readIdenticalTargetAfterConflict(filePath, content, mode, containmentRoot, parentIdentity, planned);
291
+ if (current === undefined)
292
+ throw error;
293
+ return { snapshot: current, owned: false, cleanupFailures: [] };
294
+ }
295
+ }
296
+ async function writeStrict(dependencies, filePath, content, planned, mode, containmentRoot, parentIdentity) {
297
+ const outcome = await dependencies.atomicWriteTextIfUnchanged(filePath, content, expectation(planned, containmentRoot, parentIdentity), mode);
298
+ return {
299
+ snapshot: outcome.installed,
300
+ owned: true,
301
+ cleanupFailures: outcome.cleanupFailures,
302
+ };
303
+ }
304
+ async function readSettledBindingSnapshot(bindingFile, repositoryRoot, bindingParentIdentity) {
305
+ let candidate;
306
+ let pendingOriginal;
307
+ let sawPending = false;
308
+ let lastState;
309
+ for (let attempt = 0; attempt < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS; attempt += 1) {
310
+ let observed = await readObservedTarget(bindingFile, repositoryRoot, bindingParentIdentity);
311
+ let pending = await readPendingAtomicMutation(bindingFile, bindingParentIdentity, repositoryRoot);
312
+ if (observed === undefined && candidate !== undefined) {
313
+ throw new KiokukoError('CONFLICT', 'Repository binding disappeared while settling', {
314
+ target: bindingFile,
315
+ });
316
+ }
317
+ if (observed === undefined && pending === undefined) {
318
+ observed = await readObservedTarget(bindingFile, repositoryRoot, bindingParentIdentity);
319
+ if (observed === undefined) {
320
+ pending = await readPendingAtomicMutation(bindingFile, bindingParentIdentity, repositoryRoot);
321
+ if (pending === undefined) {
322
+ if (sawPending) {
323
+ throw new KiokukoError('CONFLICT', 'Concurrent repository binding mutation ended without a target', { target: bindingFile });
324
+ }
325
+ return undefined;
326
+ }
327
+ }
328
+ }
329
+ if (pending !== undefined) {
330
+ sawPending = true;
331
+ if (pending.kind !== 'previous'
332
+ || (pendingOriginal !== undefined
333
+ && !sameRegularFileSnapshot(pendingOriginal, pending.snapshot))) {
334
+ throw new KiokukoError('CONFLICT', 'Repository binding has an incompatible atomic artifact', { target: bindingFile });
335
+ }
336
+ pendingOriginal = pending.snapshot;
337
+ }
338
+ if (observed !== undefined) {
339
+ if (candidate !== undefined && !sameRegularFileSnapshot(candidate, observed.snapshot)) {
340
+ throw new KiokukoError('CONFLICT', 'Repository binding changed while settling', {
341
+ target: bindingFile,
342
+ });
343
+ }
344
+ candidate = observed.snapshot;
345
+ if (pending === undefined && observed.linkCount === 1n)
346
+ return observed.snapshot;
347
+ lastState = pending === undefined ? 'linked' : 'pending';
348
+ }
349
+ else {
350
+ lastState = 'pending';
351
+ }
352
+ if (attempt + 1 < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS) {
353
+ await delay(CONCURRENT_IDENTICAL_OBSERVATION_DELAY_MS);
354
+ }
355
+ }
356
+ if (lastState === 'linked') {
357
+ throw new KiokukoError('SECURITY_REJECTION', 'Refusing to plan from a hard-linked repository binding file', { target: bindingFile });
358
+ }
359
+ throw new KiokukoError('CONFLICT', 'Concurrent repository binding mutation did not settle', {
360
+ target: bindingFile,
361
+ });
362
+ }
363
+ async function readConcurrentBinding(bindingFile, repositoryRoot, requestedAgentFile, bindingParentIdentity) {
364
+ const snapshot = await readSettledBindingSnapshot(bindingFile, repositoryRoot, bindingParentIdentity);
365
+ const binding = parseBindingSnapshot(snapshot);
366
+ if (snapshot === undefined || binding === undefined) {
367
+ throw new KiokukoError('CONFLICT', 'Concurrent repository binding disappeared during convergence', { target: bindingFile });
368
+ }
369
+ if (snapshot.content !== bindingText(binding)
370
+ || (process.platform !== 'win32' && snapshot.mode !== 0o644)
371
+ || binding.agentFile !== requestedAgentFile
372
+ || binding.templateVersion !== AGENT_TEMPLATE_VERSION) {
373
+ throw new KiokukoError('CONFLICT', 'Concurrent use operation created an incompatible repository binding', { target: bindingFile });
374
+ }
375
+ return binding;
376
+ }
377
+ async function readSettledAgentPlan(filePath, containmentRoot, parentIdentity, forbiddenBindingIdentity, intendedFromOriginal) {
378
+ const continuePendingMutation = async (pending, observedFinalCandidate) => {
379
+ const intended = pending.kind === 'previous'
380
+ ? intendedFromOriginal?.(pending.snapshot)
381
+ : undefined;
382
+ if (intended === undefined) {
383
+ throw new KiokukoError('CONFLICT', 'Agent target is absent during an incompatible atomic mutation', { target: filePath });
384
+ }
385
+ if (observedFinalCandidate !== undefined
386
+ && (observedFinalCandidate.content !== intended.content
387
+ || observedFinalCandidate.mode !== intended.mode
388
+ || sameFileIdentity(observedFinalCandidate.identity, pending.snapshot.identity))) {
389
+ throw new KiokukoError('CONFLICT', 'Observed agent target is not the intended atomic result', { target: filePath });
390
+ }
391
+ const settled = await readRetriedAgentPlan(filePath, pending.snapshot, intended.content, intended.mode, containmentRoot, parentIdentity, forbiddenBindingIdentity, observedFinalCandidate);
392
+ if (settled === undefined) {
393
+ throw new KiokukoError('CONFLICT', 'Concurrent agent mutation did not settle', {
394
+ target: filePath,
395
+ });
396
+ }
397
+ return settled;
398
+ };
399
+ let linkedCandidate;
400
+ for (let attempt = 0; attempt < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS; attempt += 1) {
401
+ let observed = await readObservedTarget(filePath, containmentRoot, parentIdentity);
402
+ if (observed === undefined && linkedCandidate !== undefined) {
403
+ throw new KiokukoError('CONFLICT', 'Agent target disappeared while settling', {
404
+ target: filePath,
405
+ });
406
+ }
407
+ if (observed === undefined) {
408
+ let pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
409
+ if (pending === undefined) {
410
+ observed = await readObservedTarget(filePath, containmentRoot, parentIdentity);
411
+ if (observed === undefined) {
412
+ pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
413
+ if (pending === undefined)
414
+ return undefined;
415
+ }
416
+ }
417
+ if (observed === undefined) {
418
+ if (pending === undefined) {
419
+ throw new KiokukoError('INTEGRITY_ERROR', 'Atomic quarantine observation was lost');
420
+ }
421
+ return continuePendingMutation(pending);
422
+ }
423
+ }
424
+ if (forbiddenBindingIdentity !== undefined
425
+ && sameFileIdentity(observed.snapshot.identity, forbiddenBindingIdentity)) {
426
+ throw new KiokukoError('CONFLICT', 'agentFile resolves to the repository binding file');
427
+ }
428
+ if (linkedCandidate !== undefined
429
+ && !sameRegularFileSnapshot(linkedCandidate, observed.snapshot)) {
430
+ throw new KiokukoError('CONFLICT', 'Agent target changed while settling', {
431
+ target: filePath,
432
+ });
433
+ }
434
+ linkedCandidate = observed.snapshot;
435
+ if (observed.linkCount === 1n) {
436
+ const pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
437
+ if (pending === undefined)
438
+ return observed.snapshot;
439
+ return continuePendingMutation(pending, observed.snapshot);
440
+ }
441
+ if (attempt + 1 < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS) {
442
+ await delay(CONCURRENT_IDENTICAL_OBSERVATION_DELAY_MS);
443
+ }
444
+ }
445
+ throw new KiokukoError('SECURITY_REJECTION', 'Refusing to plan from a hard-linked agent target', { target: filePath });
446
+ }
447
+ async function readRetriedAgentPlan(filePath, initial, intendedContent, intendedMode, containmentRoot, parentIdentity, forbiddenBindingIdentity, initialFinalCandidate) {
448
+ let finalCandidate = initialFinalCandidate;
449
+ let linkedCandidate;
450
+ let lastWasLinked = false;
451
+ for (let attempt = 0; attempt < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS; attempt += 1) {
452
+ const observed = await readObservedTarget(filePath, containmentRoot, parentIdentity);
453
+ if (observed === undefined) {
454
+ lastWasLinked = false;
455
+ if (linkedCandidate !== undefined || finalCandidate !== undefined) {
456
+ throw new KiokukoError('CONFLICT', 'Concurrent agent target disappeared while settling', {
457
+ target: filePath,
458
+ });
459
+ }
460
+ const pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
461
+ if (initial === undefined) {
462
+ if (pending !== undefined) {
463
+ throw new KiokukoError('CONFLICT', 'An unexpected atomic quarantine appeared for an initially absent agent target', { target: filePath });
464
+ }
465
+ return undefined;
466
+ }
467
+ if (pending === undefined
468
+ || pending.kind !== 'previous'
469
+ || !sameRegularFileSnapshot(pending.snapshot, initial)) {
470
+ throw new KiokukoError('CONFLICT', 'Agent target disappeared outside its exact atomic quarantine', { target: filePath });
471
+ }
472
+ }
473
+ else {
474
+ if (forbiddenBindingIdentity !== undefined
475
+ && sameFileIdentity(observed.snapshot.identity, forbiddenBindingIdentity)) {
476
+ throw new KiokukoError('CONFLICT', 'agentFile resolves to the repository binding file');
477
+ }
478
+ if (linkedCandidate !== undefined
479
+ && !sameRegularFileSnapshot(linkedCandidate, observed.snapshot)) {
480
+ throw new KiokukoError('CONFLICT', 'Concurrent agent target changed while settling', {
481
+ target: filePath,
482
+ });
483
+ }
484
+ const isInitial = initial !== undefined
485
+ && sameRegularFileSnapshot(observed.snapshot, initial);
486
+ const isIntendedFinal = intendedContent !== undefined
487
+ && observed.snapshot.content === intendedContent
488
+ && observed.snapshot.mode === intendedMode
489
+ && (initial === undefined
490
+ || !sameFileIdentity(observed.snapshot.identity, initial.identity));
491
+ if (finalCandidate !== undefined
492
+ && !sameRegularFileSnapshot(finalCandidate, observed.snapshot)) {
493
+ throw new KiokukoError('CONFLICT', 'Concurrent agent result changed while settling', {
494
+ target: filePath,
495
+ });
496
+ }
497
+ if (!isInitial && !isIntendedFinal) {
498
+ throw new KiokukoError('CONFLICT', 'Concurrent agent target is neither the planned original nor the intended final state', { target: filePath });
499
+ }
500
+ if (isIntendedFinal)
501
+ finalCandidate = observed.snapshot;
502
+ lastWasLinked = observed.linkCount !== 1n;
503
+ if (lastWasLinked) {
504
+ linkedCandidate = observed.snapshot;
505
+ }
506
+ else {
507
+ const pending = await readPendingAtomicMutation(filePath, parentIdentity, containmentRoot);
508
+ if (pending === undefined)
509
+ return observed.snapshot;
510
+ if (initial === undefined
511
+ || pending.kind !== 'previous'
512
+ || !sameRegularFileSnapshot(pending.snapshot, initial)) {
513
+ throw new KiokukoError('CONFLICT', 'Concurrent agent target retained an incompatible atomic artifact', { target: filePath });
514
+ }
515
+ }
516
+ }
517
+ if (attempt + 1 < CONCURRENT_IDENTICAL_OBSERVATION_ATTEMPTS) {
518
+ await delay(CONCURRENT_IDENTICAL_OBSERVATION_DELAY_MS);
519
+ }
520
+ }
521
+ if (lastWasLinked) {
522
+ throw new KiokukoError('SECURITY_REJECTION', 'Refusing to plan from a hard-linked concurrent agent target', { target: filePath });
523
+ }
524
+ throw new KiokukoError('CONFLICT', 'Concurrent agent mutation did not settle', {
525
+ target: filePath,
526
+ });
527
+ }
528
+ async function useRepositoryAttempt(options = {}, dependencyOverrides = {}, allowConcurrentConvergence, allowConcurrentAgentConvergence, retryParents) {
529
+ const dependencies = {
530
+ atomicWriteTextIfUnchanged: dependencyOverrides.atomicWriteTextIfUnchanged ?? atomicWriteTextIfUnchanged,
531
+ unlinkRegularFileIfUnchanged: dependencyOverrides.unlinkRegularFileIfUnchanged ?? unlinkRegularFileIfUnchanged,
532
+ registerRepositoryAndLocation: dependencyOverrides.registerRepositoryAndLocation ?? registerRepositoryAndLocation,
533
+ openConnection: dependencyOverrides.openConnection ?? openConnection,
534
+ };
46
535
  const rootOptions = {};
47
536
  if (options.cwd !== undefined)
48
537
  rootOptions.cwd = options.cwd;
@@ -52,49 +541,139 @@ export async function useRepository(options = {}) {
52
541
  rootOptions.allowDirectory = options.allowDirectory;
53
542
  const detected = detectRepositoryRoot(rootOptions);
54
543
  const repositoryRoot = detected.root;
544
+ if (retryParents !== undefined && repositoryRoot !== retryParents.repositoryRoot) {
545
+ throw new KiokukoError('CONFLICT', 'Repository root changed during concurrent binding convergence');
546
+ }
55
547
  const bindingFile = path.join(repositoryRoot, '.kiokuko.json');
56
- const existingBindingText = await readOptionalText(bindingFile);
57
- const existingBinding = existingBindingText === undefined ? undefined : await readProjectConfig(bindingFile);
58
- if (existingBinding && options.workspace && existingBinding.workspace !== options.workspace && !options.forceRebind) {
59
- throw new KiokukoError('CONFLICT', 'Existing binding uses another workspace; pass --force-rebind to change it');
548
+ const bindingParentIdentity = await existingParentIdentity(bindingFile);
549
+ if (retryParents !== undefined
550
+ && !sameFileIdentity(bindingParentIdentity, retryParents.bindingParentIdentity)) {
551
+ throw new KiokukoError('CONFLICT', 'Repository root changed during concurrent binding convergence');
552
+ }
553
+ const bindingSnapshot = await readSettledBindingSnapshot(bindingFile, repositoryRoot, bindingParentIdentity);
554
+ const existingBinding = parseBindingSnapshot(bindingSnapshot);
555
+ if (existingBinding !== undefined && existingBinding.templateVersion > AGENT_TEMPLATE_VERSION) {
556
+ throw new KiokukoError('VALIDATION_ERROR', `Project binding templateVersion ${existingBinding.templateVersion} is newer than supported version ${AGENT_TEMPLATE_VERSION}`);
557
+ }
558
+ if (options.forceRebind && existingBinding === undefined) {
559
+ throw new KiokukoError('CONFLICT', 'Cannot rebind a repository without an existing project binding');
560
+ }
561
+ if (existingBinding && !options.forceRebind) {
562
+ if (options.repositoryId !== undefined && existingBinding.repositoryId !== options.repositoryId) {
563
+ throw new KiokukoError('CONFLICT', 'Existing binding uses another repository ID; pass --force-rebind to change it');
564
+ }
565
+ if (options.workspace !== undefined && existingBinding.workspace !== options.workspace) {
566
+ throw new KiokukoError('CONFLICT', 'Existing binding uses another workspace; pass --force-rebind to change it');
567
+ }
60
568
  }
61
569
  const requestedAgentFile = options.agentFile ?? existingBinding?.agentFile ?? 'AGENTS.md';
62
- const agentFile = ensureChildPath(repositoryRoot, requestedAgentFile);
63
- const existingAgent = options.noAgentFile ? undefined : await readRegularFile(agentFile);
64
570
  const identityOptions = { repositoryRoot };
65
571
  const remote = readGitOrigin(repositoryRoot);
66
572
  if (remote !== undefined)
67
573
  identityOptions.remoteUrl = remote;
68
- if (options.repositoryId !== undefined)
69
- identityOptions.repositoryId = options.repositoryId;
70
- if (existingBinding) {
574
+ if (existingBinding && options.forceRebind) {
575
+ if (options.repositoryId === undefined && options.workspace === undefined) {
576
+ throw new KiokukoError('CONFLICT', 'Forced rebind requires a different target identity');
577
+ }
578
+ identityOptions.repositoryId = options.repositoryId ?? `repo_${randomUUID()}`;
579
+ if (options.workspace !== undefined)
580
+ identityOptions.workspace = options.workspace;
581
+ }
582
+ else if (existingBinding) {
71
583
  identityOptions.existingBinding = {
72
584
  repositoryId: existingBinding.repositoryId,
73
585
  workspace: existingBinding.workspace,
74
586
  };
75
587
  }
76
- if (options.workspace !== undefined)
77
- identityOptions.workspace = options.workspace;
588
+ else {
589
+ if (options.repositoryId !== undefined)
590
+ identityOptions.repositoryId = options.repositoryId;
591
+ if (options.workspace !== undefined)
592
+ identityOptions.workspace = options.workspace;
593
+ }
78
594
  const identity = createRepositoryIdentity(identityOptions);
79
- if (existingBinding && options.workspace && existingBinding.workspace !== identity.workspace && !options.forceRebind) {
80
- throw new KiokukoError('CONFLICT', 'Existing binding uses another workspace; pass --force-rebind to change it');
595
+ if (existingBinding && options.forceRebind
596
+ && (identity.repositoryId === existingBinding.repositoryId
597
+ || identity.workspace === existingBinding.workspace)) {
598
+ throw new KiokukoError('CONFLICT', 'Forced rebind requires both a different repository ID and a different workspace');
81
599
  }
82
- const nextBinding = {
600
+ // Validate the exact serialized binding before resolving, reading, initializing,
601
+ // or writing anything. Absolute and non-canonical lexical paths cannot persist.
602
+ const nextBinding = parseProjectConfig({
83
603
  schemaVersion: 1,
84
604
  repositoryId: identity.repositoryId,
85
605
  workspace: identity.workspace,
86
606
  agentFile: requestedAgentFile,
87
607
  templateVersion: AGENT_TEMPLATE_VERSION,
608
+ });
609
+ const agentFile = ensureChildPath(repositoryRoot, nextBinding.agentFile);
610
+ const agentParentIdentity = await existingParentIdentity(agentFile);
611
+ if (retryParents !== undefined
612
+ && !sameFileIdentity(agentParentIdentity, retryParents.agentParentIdentity)) {
613
+ throw new KiokukoError('CONFLICT', 'agentFile parent changed during concurrent binding convergence');
614
+ }
615
+ const agentTemplateValues = {
616
+ repositoryId: identity.repositoryId,
617
+ workspace: identity.workspace,
618
+ cliCommand: preferredCliCommand(),
619
+ templateVersion: AGENT_TEMPLATE_VERSION,
88
620
  };
621
+ const retryRendered = retryParents === undefined || options.noAgentFile
622
+ ? undefined
623
+ : renderAgentFile(retryParents.agentSnapshot?.content, agentTemplateValues);
624
+ const plannedAgent = retryParents === undefined
625
+ ? await readSettledAgentPlan(agentFile, repositoryRoot, agentParentIdentity, bindingSnapshot?.identity, options.noAgentFile
626
+ ? undefined
627
+ : (original) => ({
628
+ content: renderAgentFile(original.content, agentTemplateValues).content,
629
+ mode: original.mode,
630
+ }))
631
+ : await readRetriedAgentPlan(agentFile, retryParents.agentSnapshot, retryRendered?.action === 'unchanged' ? undefined : retryRendered?.content, retryParents.agentSnapshot?.mode ?? 0o644, repositoryRoot, agentParentIdentity, bindingSnapshot?.identity);
632
+ assertSupportedManagedTemplate(plannedAgent, 'Prospective agentFile');
633
+ const existingAgent = options.noAgentFile ? undefined : plannedAgent;
634
+ if (options.noAgentFile && plannedAgent !== undefined) {
635
+ const plannedManagedBlock = removeManagedBlock(plannedAgent.content);
636
+ if (plannedManagedBlock.action !== 'absent'
637
+ && renderAgentFile(plannedAgent.content, agentTemplateValues).action !== 'unchanged') {
638
+ throw new KiokukoError('CONFLICT', 'Cannot use --no-agent-file while the prospective agentFile contains a stale managed block');
639
+ }
640
+ }
641
+ if (bindingSnapshot !== undefined
642
+ && plannedAgent !== undefined
643
+ && bindingSnapshot.identity.device === plannedAgent.identity.device
644
+ && bindingSnapshot.identity.inode === plannedAgent.identity.inode) {
645
+ throw new KiokukoError('CONFLICT', 'agentFile resolves to the repository binding file');
646
+ }
647
+ const previousAgentFile = existingBinding !== undefined
648
+ && existingBinding.agentFile !== nextBinding.agentFile
649
+ ? ensureChildPath(repositoryRoot, existingBinding.agentFile)
650
+ : undefined;
651
+ const previousAgentParentIdentity = previousAgentFile === undefined
652
+ ? bindingParentIdentity
653
+ : await existingParentIdentity(previousAgentFile);
654
+ const previousAgent = previousAgentFile === undefined
655
+ ? undefined
656
+ : await readStrictSettledTarget(previousAgentFile, repositoryRoot, previousAgentParentIdentity, 'Previous agentFile');
657
+ assertSupportedManagedTemplate(previousAgent, 'Previous agentFile');
658
+ if (bindingSnapshot !== undefined
659
+ && previousAgent !== undefined
660
+ && bindingSnapshot.identity.device === previousAgent.identity.device
661
+ && bindingSnapshot.identity.inode === previousAgent.identity.inode) {
662
+ throw new KiokukoError('CONFLICT', 'Previous agentFile resolves to the repository binding file');
663
+ }
664
+ if (previousAgent !== undefined
665
+ && plannedAgent !== undefined
666
+ && previousAgent.identity.device === plannedAgent.identity.device
667
+ && previousAgent.identity.inode === plannedAgent.identity.inode) {
668
+ throw new KiokukoError('CONFLICT', 'Old and new agentFile paths resolve to the same regular file');
669
+ }
670
+ const previousAgentRemoval = previousAgent === undefined
671
+ ? undefined
672
+ : removeManagedBlock(previousAgent.content);
89
673
  const nextBindingText = bindingText(nextBinding);
90
674
  const rendered = options.noAgentFile
91
675
  ? undefined
92
- : renderAgentFile(existingAgent?.content, {
93
- repositoryId: identity.repositoryId,
94
- workspace: identity.workspace,
95
- cliCommand: preferredCliCommand(),
96
- templateVersion: AGENT_TEMPLATE_VERSION,
97
- });
676
+ : renderAgentFile(existingAgent?.content, agentTemplateValues);
98
677
  const databasePath = options.databasePath ?? getGlobalDatabasePath();
99
678
  const result = {
100
679
  repositoryRoot,
@@ -104,7 +683,7 @@ export async function useRepository(options = {}) {
104
683
  bindingFile,
105
684
  agentFile: options.noAgentFile ? null : agentFile,
106
685
  agentFileAction: options.noAgentFile ? 'skipped' : rendered?.action ?? 'unchanged',
107
- bindingAction: options.dryRun ? 'planned' : bindingAction(existingBindingText, nextBindingText),
686
+ bindingAction: options.dryRun ? 'planned' : bindingAction(bindingSnapshot?.content, nextBindingText),
108
687
  dryRun: options.dryRun ?? false,
109
688
  templateVersion: AGENT_TEMPLATE_VERSION,
110
689
  };
@@ -114,11 +693,199 @@ export async function useRepository(options = {}) {
114
693
  if (options.migrationsDirectory !== undefined)
115
694
  initOptions.migrationsDirectory = options.migrationsDirectory;
116
695
  await initializeDatabase(initOptions);
117
- const database = openConnection(databasePath);
118
- let retryBinding;
696
+ const installed = [];
119
697
  try {
698
+ let resolvedBinding = bindingSnapshot;
699
+ if (result.bindingAction !== 'unchanged') {
700
+ try {
701
+ const resolution = bindingSnapshot === undefined
702
+ ? await writeOrConvergeIdentical(dependencies, bindingFile, nextBindingText, bindingSnapshot, 0o644, repositoryRoot, bindingParentIdentity)
703
+ : await writeStrict(dependencies, bindingFile, nextBindingText, bindingSnapshot, bindingSnapshot.mode, repositoryRoot, bindingParentIdentity);
704
+ resolvedBinding = resolution.snapshot;
705
+ if (resolution.owned) {
706
+ installed.push({
707
+ path: bindingFile,
708
+ original: bindingSnapshot,
709
+ installed: resolution.snapshot,
710
+ containmentRoot: repositoryRoot,
711
+ parentIdentity: bindingParentIdentity,
712
+ });
713
+ }
714
+ assertAtomicCleanupComplete(resolution);
715
+ }
716
+ catch (error) {
717
+ if (error instanceof AtomicCommittedMutationError) {
718
+ installed.push({
719
+ path: bindingFile,
720
+ original: bindingSnapshot,
721
+ installed: error.outcome.installed,
722
+ containmentRoot: repositoryRoot,
723
+ parentIdentity: bindingParentIdentity,
724
+ });
725
+ }
726
+ else if (error instanceof AtomicCommittedUnlinkError && bindingSnapshot !== undefined) {
727
+ installed.push({
728
+ path: bindingFile,
729
+ original: bindingSnapshot,
730
+ installed: undefined,
731
+ containmentRoot: repositoryRoot,
732
+ parentIdentity: bindingParentIdentity,
733
+ });
734
+ }
735
+ if (allowConcurrentConvergence
736
+ && isTargetConflict(error, bindingFile)
737
+ && bindingSnapshot === undefined
738
+ && existingBinding === undefined
739
+ && options.repositoryId === undefined
740
+ && options.workspace === undefined) {
741
+ throw new ConcurrentUseBinding(await readConcurrentBinding(bindingFile, repositoryRoot, requestedAgentFile, bindingParentIdentity));
742
+ }
743
+ throw error;
744
+ }
745
+ }
746
+ else if (bindingSnapshot !== undefined) {
747
+ await assertFileExpectation(bindingFile, expectation(bindingSnapshot, repositoryRoot, bindingParentIdentity));
748
+ resolvedBinding = bindingSnapshot;
749
+ }
750
+ let resolvedAgent = existingAgent;
751
+ if (rendered && rendered.action !== 'unchanged') {
752
+ try {
753
+ const resolution = existingBinding === undefined || allowConcurrentAgentConvergence
754
+ ? await writeOrConvergeIdentical(dependencies, agentFile, rendered.content, existingAgent, existingAgent?.mode ?? 0o644, repositoryRoot, agentParentIdentity)
755
+ : await writeStrict(dependencies, agentFile, rendered.content, existingAgent, existingAgent?.mode ?? 0o644, repositoryRoot, agentParentIdentity);
756
+ resolvedAgent = resolution.snapshot;
757
+ if (resolution.owned) {
758
+ installed.push({
759
+ path: agentFile,
760
+ original: existingAgent,
761
+ installed: resolution.snapshot,
762
+ containmentRoot: repositoryRoot,
763
+ parentIdentity: agentParentIdentity,
764
+ });
765
+ }
766
+ assertAtomicCleanupComplete(resolution);
767
+ }
768
+ catch (error) {
769
+ if (error instanceof AtomicCommittedMutationError) {
770
+ installed.push({
771
+ path: agentFile,
772
+ original: existingAgent,
773
+ installed: error.outcome.installed,
774
+ containmentRoot: repositoryRoot,
775
+ parentIdentity: agentParentIdentity,
776
+ });
777
+ }
778
+ else if (error instanceof AtomicCommittedUnlinkError && existingAgent !== undefined) {
779
+ installed.push({
780
+ path: agentFile,
781
+ original: existingAgent,
782
+ installed: undefined,
783
+ containmentRoot: repositoryRoot,
784
+ parentIdentity: agentParentIdentity,
785
+ });
786
+ }
787
+ throw error;
788
+ }
789
+ }
790
+ else if (rendered && existingAgent !== undefined) {
791
+ await assertFileExpectation(agentFile, expectation(existingAgent, repositoryRoot, agentParentIdentity));
792
+ resolvedAgent = existingAgent;
793
+ }
794
+ let resolvedPreviousAgent = previousAgent;
795
+ if (previousAgentFile !== undefined
796
+ && previousAgent !== undefined
797
+ && previousAgentRemoval?.action === 'updated'
798
+ && previousAgentRemoval.content !== undefined) {
799
+ try {
800
+ const outcome = await dependencies.atomicWriteTextIfUnchanged(previousAgentFile, previousAgentRemoval.content, expectation(previousAgent, repositoryRoot, previousAgentParentIdentity), previousAgent.mode);
801
+ resolvedPreviousAgent = outcome.installed;
802
+ installed.push({
803
+ path: previousAgentFile,
804
+ original: previousAgent,
805
+ installed: outcome.installed,
806
+ containmentRoot: repositoryRoot,
807
+ parentIdentity: previousAgentParentIdentity,
808
+ });
809
+ assertAtomicCleanupComplete(outcome);
810
+ }
811
+ catch (error) {
812
+ if (error instanceof AtomicCommittedMutationError) {
813
+ installed.push({
814
+ path: previousAgentFile,
815
+ original: previousAgent,
816
+ installed: error.outcome.installed,
817
+ containmentRoot: repositoryRoot,
818
+ parentIdentity: previousAgentParentIdentity,
819
+ });
820
+ }
821
+ else if (error instanceof AtomicCommittedUnlinkError) {
822
+ installed.push({
823
+ path: previousAgentFile,
824
+ original: previousAgent,
825
+ installed: undefined,
826
+ containmentRoot: repositoryRoot,
827
+ parentIdentity: previousAgentParentIdentity,
828
+ });
829
+ }
830
+ throw error;
831
+ }
832
+ }
833
+ else if (previousAgentFile !== undefined
834
+ && previousAgent !== undefined
835
+ && previousAgentRemoval?.action === 'deleted') {
836
+ try {
837
+ const outcome = await dependencies.unlinkRegularFileIfUnchanged(previousAgentFile, expectation(previousAgent, repositoryRoot, previousAgentParentIdentity));
838
+ resolvedPreviousAgent = undefined;
839
+ installed.push({
840
+ path: previousAgentFile,
841
+ original: previousAgent,
842
+ installed: undefined,
843
+ containmentRoot: repositoryRoot,
844
+ parentIdentity: previousAgentParentIdentity,
845
+ });
846
+ assertAtomicCleanupComplete(outcome);
847
+ }
848
+ catch (error) {
849
+ if (error instanceof AtomicCommittedUnlinkError) {
850
+ installed.push({
851
+ path: previousAgentFile,
852
+ original: previousAgent,
853
+ installed: undefined,
854
+ containmentRoot: repositoryRoot,
855
+ parentIdentity: previousAgentParentIdentity,
856
+ });
857
+ }
858
+ throw error;
859
+ }
860
+ }
861
+ const finalBinding = await readSettledBindingSnapshot(bindingFile, repositoryRoot, bindingParentIdentity);
862
+ if (resolvedBinding === undefined
863
+ || finalBinding === undefined
864
+ || !sameRegularFileSnapshot(finalBinding, resolvedBinding)) {
865
+ throw new KiokukoError('CONFLICT', 'Repository binding changed before registration', {
866
+ target: bindingFile,
867
+ });
868
+ }
869
+ if (!options.noAgentFile) {
870
+ await assertFileExpectation(agentFile, expectation(resolvedAgent, repositoryRoot, agentParentIdentity));
871
+ }
872
+ else {
873
+ await assertFileExpectation(agentFile, expectation(plannedAgent, repositoryRoot, agentParentIdentity));
874
+ }
875
+ if (previousAgentFile !== undefined) {
876
+ const finalPreviousAgent = await readStrictSettledTarget(previousAgentFile, repositoryRoot, previousAgentParentIdentity, 'Previous agentFile');
877
+ if ((resolvedPreviousAgent === undefined) !== (finalPreviousAgent === undefined)
878
+ || (resolvedPreviousAgent !== undefined
879
+ && finalPreviousAgent !== undefined
880
+ && !sameRegularFileSnapshot(resolvedPreviousAgent, finalPreviousAgent))) {
881
+ throw new KiokukoError('CONFLICT', 'Previous agentFile changed before registration', {
882
+ target: previousAgentFile,
883
+ });
884
+ }
885
+ }
886
+ const database = dependencies.openConnection(databasePath);
120
887
  try {
121
- registerRepositoryAndLocation(database, {
888
+ dependencies.registerRepositoryAndLocation(database, {
122
889
  repositoryId: identity.repositoryId,
123
890
  workspace: identity.workspace,
124
891
  displayName: identity.displayName,
@@ -126,51 +893,62 @@ export async function useRepository(options = {}) {
126
893
  remoteFingerprint: identity.remoteFingerprint,
127
894
  bindingSchemaVersion: 1,
128
895
  agentTemplateVersion: AGENT_TEMPLATE_VERSION,
896
+ ...(options.forceRebind && existingBinding !== undefined
897
+ ? {
898
+ rebindFrom: {
899
+ repositoryId: existingBinding.repositoryId,
900
+ workspace: existingBinding.workspace,
901
+ },
902
+ }
903
+ : {}),
129
904
  });
130
905
  }
131
- catch (error) {
132
- if (error instanceof KiokukoError && error.code === 'CONFLICT' && options.repositoryId === undefined && options.workspace === undefined && existingBinding === undefined) {
133
- retryBinding = database.prepare(`
134
- SELECT r.repository_id AS repositoryId, r.workspace AS workspace
135
- FROM repositories r JOIN repository_locations l ON l.repository_id = r.repository_id
136
- WHERE l.canonical_root = ?
137
- `).get(repositoryRoot);
138
- }
139
- if (!retryBinding)
140
- throw error;
906
+ catch (registrationError) {
907
+ try {
908
+ database.close();
909
+ }
910
+ catch (closeError) {
911
+ if (registrationError instanceof TransactionCommitUncertainError) {
912
+ throw new UncertainRegistrationCloseError(registrationError, closeError);
913
+ }
914
+ throw new AggregateError([registrationError, closeError], 'Repository registration failed and closing the database connection also failed');
915
+ }
916
+ throw registrationError;
917
+ }
918
+ try {
919
+ database.close();
920
+ }
921
+ catch (closeError) {
922
+ throw new CommittedRegistrationCloseError(closeError);
141
923
  }
142
- }
143
- finally {
144
- database.close();
145
- }
146
- if (retryBinding) {
147
- return useRepository({ ...options, repositoryId: retryBinding.repositoryId, workspace: retryBinding.workspace });
148
- }
149
- const originalBinding = existingBindingText;
150
- const originalAgent = existingAgent?.content;
151
- try {
152
- if (result.bindingAction !== 'unchanged')
153
- await atomicWriteText(bindingFile, nextBindingText, 0o644);
154
- if (rendered && rendered.action !== 'unchanged')
155
- await atomicWriteText(agentFile, rendered.content, existingAgent?.mode ?? 0o644);
156
924
  }
157
925
  catch (error) {
158
- if (originalBinding === undefined)
159
- await unlink(bindingFile).catch(() => undefined);
160
- else
161
- await atomicWriteText(bindingFile, originalBinding, 0o644).catch(() => undefined);
162
- if (options.noAgentFile) {
163
- // No agent file was requested, so there is nothing to restore.
926
+ if (error instanceof CommittedRegistrationCloseError
927
+ || error instanceof TransactionCommitUncertainError
928
+ || error instanceof UncertainRegistrationCloseError) {
929
+ throw error;
164
930
  }
165
- else if (originalAgent === undefined) {
166
- await unlink(agentFile).catch(() => undefined);
931
+ const restorationFailures = await restoreInstalledWrites(installed, dependencies);
932
+ if (restorationFailures.length > 0) {
933
+ throw new AggregateError([error, ...restorationFailures], 'Repository setup failed and file restoration also failed');
167
934
  }
168
- else {
169
- await atomicWriteText(agentFile, originalAgent, existingAgent?.mode ?? 0o644).catch(() => undefined);
935
+ if (error instanceof ConcurrentUseBinding) {
936
+ return useRepositoryAttempt({
937
+ ...options,
938
+ repositoryId: error.binding.repositoryId,
939
+ workspace: error.binding.workspace,
940
+ }, dependencyOverrides, false, true, {
941
+ repositoryRoot,
942
+ bindingParentIdentity,
943
+ agentParentIdentity,
944
+ agentSnapshot: plannedAgent,
945
+ });
170
946
  }
171
947
  throw error;
172
948
  }
173
949
  return result;
174
950
  }
175
- export const use = useRepository;
951
+ export async function useRepository(options = {}, dependencyOverrides = {}) {
952
+ return useRepositoryAttempt(options, dependencyOverrides, true, false);
953
+ }
176
954
  //# sourceMappingURL=use.js.map