@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,43 +1,772 @@
1
- import { randomBytes } from 'node:crypto';
2
- import { chmod, mkdir, unlink } from 'node:fs/promises';
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { constants } from 'node:fs';
4
+ import { lstat, mkdir, open, realpath } from 'node:fs/promises';
3
5
  import { DatabaseSync } from 'node:sqlite';
4
6
  import path from 'node:path';
5
7
  import { KiokukoError } from '../errors.js';
8
+ import { isWellFormedUnicode } from '../serialization/boundary-json.js';
9
+ function portableDatabaseLabel(databasePath) {
10
+ const basename = path.basename(databasePath);
11
+ const sanitized = basename
12
+ .toLowerCase()
13
+ .replace(/[^a-z0-9_-]+/gu, '-')
14
+ .replace(/^-+|-+$/gu, '')
15
+ .slice(0, 32) || 'file';
16
+ const hash = createHash('sha256').update(basename, 'utf8').digest('hex').slice(0, 16);
17
+ // The fixed `db-` prefix prevents Windows device-name collisions even when
18
+ // the source basename is a valid POSIX name such as CON or NUL.
19
+ return `db-${sanitized}-${hash}`;
20
+ }
6
21
  function backupName(databasePath, fromVersion, toVersion) {
7
22
  const timestamp = new Date().toISOString().replace(/[^0-9]/g, '').slice(0, 17);
8
23
  const nonce = randomBytes(8).toString('hex');
9
- return `${path.basename(databasePath)}.pre-upgrade-v${fromVersion}-to-v${toVersion}-${timestamp}-${nonce}.sqlite3`;
10
- }
11
- export async function createPreMigrationBackup(database, databasePath, fromVersion, toVersion) {
12
- const backupDirectory = path.join(path.dirname(databasePath), 'backups');
13
- const output = path.join(backupDirectory, backupName(databasePath, fromVersion, toVersion));
14
- try {
15
- await mkdir(backupDirectory, { recursive: true, mode: 0o700 });
16
- await chmod(backupDirectory, 0o700);
17
- await database.backup(output);
18
- await chmod(output, 0o600);
19
- // The backup API copies the source journal mode. Normalize only the backup
20
- // to DELETE mode so it remains a self-contained file without WAL sidecars.
21
- const verification = new DatabaseSync(output, { timeout: 5000, enableForeignKeyConstraints: true });
24
+ return `${portableDatabaseLabel(databasePath)}.pre-upgrade-v${fromVersion}-to-v${toVersion}-${timestamp}-${nonce}.sqlite3`;
25
+ }
26
+ /**
27
+ * Resolve the pathname-safety flags as one mandatory POSIX capability. A
28
+ * supported non-Windows runtime must provide every flag; dropping one to zero
29
+ * would silently remove the directory, no-follow, or nonblocking guarantee.
30
+ */
31
+ export function requirePosixBackupOpenFlags(platform = process.platform, openFlags = constants) {
32
+ if (platform === 'win32')
33
+ return undefined;
34
+ function required(name) {
35
+ const value = openFlags[name];
36
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {
37
+ throw new KiokukoError('INTEGRITY_ERROR', 'Required POSIX backup open flags are unavailable', { flag: name });
38
+ }
39
+ return value;
40
+ }
41
+ return Object.freeze({
42
+ directory: required('O_DIRECTORY'),
43
+ noFollow: required('O_NOFOLLOW'),
44
+ nonBlock: required('O_NONBLOCK'),
45
+ });
46
+ }
47
+ function isAlreadyExists(error) {
48
+ return error instanceof Error
49
+ && 'code' in error
50
+ && error.code === 'EEXIST';
51
+ }
52
+ async function requireCanonicalDirectoryChain(directory) {
53
+ const parsed = path.parse(directory);
54
+ const relative = path.relative(parsed.root, directory);
55
+ let current = parsed.root;
56
+ for (const component of relative.split(path.sep).filter((value) => value.length > 0)) {
57
+ current = path.join(current, component);
58
+ const status = await lstat(current);
59
+ if (!status.isDirectory() || status.isSymbolicLink()) {
60
+ throw new KiokukoError('INTEGRITY_ERROR', 'Backup directory path contains a non-directory or symbolic link');
61
+ }
62
+ }
63
+ }
64
+ async function bindBackupDirectory(databasePath, posixFlags) {
65
+ const databaseDirectory = await realpath(path.dirname(databasePath));
66
+ await requireCanonicalDirectoryChain(databaseDirectory);
67
+ const directory = path.join(databaseDirectory, 'backups');
68
+ try {
69
+ await mkdir(directory, { mode: 0o700 });
70
+ }
71
+ catch (error) {
72
+ if (!isAlreadyExists(error))
73
+ throw error;
74
+ }
75
+ const before = await lstat(directory, { bigint: true });
76
+ if (!before.isDirectory() || before.isSymbolicLink()) {
77
+ throw new KiokukoError('INTEGRITY_ERROR', 'Backup directory must be a non-symbolic-link directory');
78
+ }
79
+ let handle;
80
+ try {
81
+ if (posixFlags !== undefined) {
82
+ handle = await open(directory, constants.O_RDONLY | posixFlags.directory | posixFlags.noFollow);
83
+ const opened = await handle.stat({ bigint: true });
84
+ if (!opened.isDirectory() || opened.dev !== before.dev || opened.ino !== before.ino) {
85
+ throw new KiokukoError('CONFLICT', 'Backup directory changed while it was being opened');
86
+ }
87
+ await handle.chmod(0o700);
88
+ }
89
+ const secured = handle === undefined
90
+ ? await lstat(directory, { bigint: true })
91
+ : await handle.stat({ bigint: true });
92
+ if (!secured.isDirectory() || secured.dev !== before.dev || secured.ino !== before.ino) {
93
+ throw new KiokukoError('CONFLICT', 'Backup directory changed while it was being secured');
94
+ }
95
+ const binding = {
96
+ directory,
97
+ device: secured.dev,
98
+ inode: secured.ino,
99
+ owner: secured.uid,
100
+ group: secured.gid,
101
+ mode: secured.mode,
102
+ privateDirectory: true,
103
+ ...(handle === undefined ? {} : { handle }),
104
+ };
105
+ await requireBackupDirectory(binding);
106
+ return binding;
107
+ }
108
+ catch (error) {
109
+ if (handle === undefined)
110
+ throw error;
111
+ const pendingHandle = handle;
112
+ handle = undefined;
113
+ try {
114
+ await pendingHandle.close();
115
+ }
116
+ catch (closeError) {
117
+ throw new AggregateError([error, closeError], 'Backup directory binding failed and closing it also failed');
118
+ }
119
+ throw error;
120
+ }
121
+ }
122
+ async function bindExistingOutputDirectory(destination, posixFlags) {
123
+ const directory = path.dirname(destination);
124
+ await requireCanonicalDirectoryChain(directory);
125
+ const before = await lstat(directory, { bigint: true });
126
+ if (!before.isDirectory() || before.isSymbolicLink()) {
127
+ throw new KiokukoError('INTEGRITY_ERROR', 'Backup output directory must be a non-symbolic-link directory');
128
+ }
129
+ let handle;
130
+ try {
131
+ if (posixFlags !== undefined) {
132
+ handle = await open(directory, constants.O_RDONLY | posixFlags.directory | posixFlags.noFollow);
133
+ const opened = await handle.stat({ bigint: true });
134
+ if (!opened.isDirectory() || opened.dev !== before.dev || opened.ino !== before.ino) {
135
+ throw new KiokukoError('CONFLICT', 'Backup output directory changed while it was being opened');
136
+ }
137
+ }
138
+ const secured = handle === undefined
139
+ ? await lstat(directory, { bigint: true })
140
+ : await handle.stat({ bigint: true });
141
+ if (!secured.isDirectory() || secured.dev !== before.dev || secured.ino !== before.ino) {
142
+ throw new KiokukoError('CONFLICT', 'Backup output directory changed while it was being bound');
143
+ }
144
+ const binding = {
145
+ directory,
146
+ device: secured.dev,
147
+ inode: secured.ino,
148
+ owner: secured.uid,
149
+ group: secured.gid,
150
+ mode: secured.mode,
151
+ privateDirectory: false,
152
+ ...(handle === undefined ? {} : { handle }),
153
+ };
154
+ await requireBackupDirectory(binding);
155
+ return binding;
156
+ }
157
+ catch (error) {
158
+ if (handle === undefined)
159
+ throw error;
160
+ const pendingHandle = handle;
161
+ handle = undefined;
22
162
  try {
23
- verification.exec('PRAGMA journal_mode = DELETE;');
24
- const row = verification.prepare('PRAGMA integrity_check').get();
25
- const integrity = row?.integrity_check;
26
- if (integrity !== 'ok')
27
- throw new Error('backup integrity check failed');
163
+ await pendingHandle.close();
164
+ }
165
+ catch (closeError) {
166
+ throw new AggregateError([error, closeError], 'Backup output directory binding failed and closing it also failed');
167
+ }
168
+ throw error;
169
+ }
170
+ }
171
+ async function requireBackupDirectory(binding) {
172
+ await requireCanonicalDirectoryChain(path.dirname(binding.directory));
173
+ const status = await lstat(binding.directory, { bigint: true });
174
+ if (!status.isDirectory()
175
+ || status.isSymbolicLink()
176
+ || status.dev !== binding.device
177
+ || status.ino !== binding.inode
178
+ || status.uid !== binding.owner
179
+ || status.gid !== binding.group
180
+ || status.mode !== binding.mode
181
+ || (binding.privateDirectory && process.platform !== 'win32' && (status.mode & 511n) !== 448n)) {
182
+ throw new KiokukoError('CONFLICT', 'Backup output directory changed during backup creation');
183
+ }
184
+ if (binding.handle !== undefined) {
185
+ const opened = await binding.handle.stat({ bigint: true });
186
+ if (!opened.isDirectory()
187
+ || opened.dev !== binding.device
188
+ || opened.ino !== binding.inode
189
+ || opened.uid !== binding.owner
190
+ || opened.gid !== binding.group
191
+ || opened.mode !== binding.mode
192
+ || (binding.privateDirectory && process.platform !== 'win32' && (opened.mode & 511n) !== 448n)) {
193
+ throw new KiokukoError('CONFLICT', 'Backup output directory changed during backup creation');
194
+ }
195
+ }
196
+ }
197
+ const WRITER_DEADLINE_MS = 30_000;
198
+ const WRITER_PROTOCOL_LIMIT_BYTES = 64 * 1024;
199
+ const BOUND_WRITER_SCRIPT = String.raw `
200
+ const { createHash } = require('node:crypto');
201
+ const {
202
+ closeSync,
203
+ constants,
204
+ fchmodSync,
205
+ fstatSync,
206
+ fsyncSync,
207
+ lstatSync,
208
+ openSync,
209
+ readFileSync,
210
+ readSync,
211
+ statSync,
212
+ writeFileSync,
213
+ } = require('node:fs');
214
+ const path = require('node:path');
215
+
216
+ function plain(value) {
217
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;
218
+ const prototype = Object.getPrototypeOf(value);
219
+ return prototype === Object.prototype || prototype === null;
220
+ }
221
+
222
+ function exact(value, keys) {
223
+ const actual = Object.keys(value).sort();
224
+ const expected = [...keys].sort();
225
+ return actual.length === expected.length
226
+ && actual.every((key, index) => key === expected[index]);
227
+ }
228
+
229
+ function unsigned(value) {
230
+ if (typeof value !== 'string' || !/^(?:0|[1-9][0-9]*)$/.test(value)) {
231
+ throw new Error('Bound backup request contains an invalid integer');
232
+ }
233
+ return BigInt(value);
234
+ }
235
+
236
+ function parseDirectory(value) {
237
+ if (!plain(value) || !exact(value, ['device', 'inode', 'owner', 'group', 'mode'])) {
238
+ throw new Error('Bound backup directory identity is invalid');
239
+ }
240
+ return {
241
+ device: unsigned(value.device),
242
+ inode: unsigned(value.inode),
243
+ owner: unsigned(value.owner),
244
+ group: unsigned(value.group),
245
+ mode: unsigned(value.mode),
246
+ };
247
+ }
248
+
249
+ function portableDestination(value) {
250
+ const stem = value.split('.', 1)[0].replace(/[ .]+$/u, '').toUpperCase();
251
+ return !/[<>:"\/\\|?*\u0000-\u001F]/u.test(value)
252
+ && !/[\uD800-\uDFFF]/u.test(value)
253
+ && !/[ .]$/u.test(value)
254
+ && !/^(?:CON|PRN|AUX|NUL|COM[1-9¹²³]|LPT[1-9¹²³]|CONIN\$|CONOUT\$)$/u.test(stem);
255
+ }
256
+
257
+ function parseRequest() {
258
+ const value = JSON.parse(process.argv[1]);
259
+ if (!plain(value)
260
+ || !exact(value, [
261
+ 'destination', 'directory', 'enforcePosixFileMode', 'requirePrivateDirectory', 'sha256', 'size',
262
+ ])
263
+ || typeof value.destination !== 'string'
264
+ || value.destination.length === 0
265
+ || value.destination.includes('\0')
266
+ || value.destination.includes('/')
267
+ || value.destination.includes('\\')
268
+ || value.destination === '.'
269
+ || value.destination === '..'
270
+ || path.basename(value.destination) !== value.destination
271
+ || !portableDestination(value.destination)
272
+ || typeof value.enforcePosixFileMode !== 'boolean'
273
+ || typeof value.requirePrivateDirectory !== 'boolean'
274
+ || typeof value.sha256 !== 'string'
275
+ || !/^[0-9a-f]{64}$/.test(value.sha256)) {
276
+ throw new Error('Bound backup request is invalid');
277
+ }
278
+ return {
279
+ destination: value.destination,
280
+ directory: parseDirectory(value.directory),
281
+ enforcePosixFileMode: value.enforcePosixFileMode,
282
+ requirePrivateDirectory: value.requirePrivateDirectory,
283
+ sha256: value.sha256,
284
+ size: unsigned(value.size),
285
+ };
286
+ }
287
+
288
+ function requireDirectory(request) {
289
+ const status = statSync('.', { bigint: true });
290
+ if (!status.isDirectory()
291
+ || status.dev !== request.directory.device
292
+ || status.ino !== request.directory.inode
293
+ || status.uid !== request.directory.owner
294
+ || status.gid !== request.directory.group
295
+ || status.mode !== request.directory.mode
296
+ || (request.requirePrivateDirectory && (status.mode & 0o777n) !== 0o700n)) {
297
+ throw new Error('Bound backup directory identity changed');
298
+ }
299
+ }
300
+
301
+ function requiredOpenFlag(name) {
302
+ const value = constants[name];
303
+ if (!Number.isSafeInteger(value) || value <= 0) {
304
+ throw new Error('Required POSIX backup open flag is unavailable: ' + name);
305
+ }
306
+ return value;
307
+ }
308
+
309
+ function descriptorHash(descriptor, size) {
310
+ const hash = createHash('sha256');
311
+ const buffer = Buffer.allocUnsafe(64 * 1024);
312
+ let offset = 0n;
313
+ while (offset < size) {
314
+ const length = Number(size - offset > BigInt(buffer.length) ? BigInt(buffer.length) : size - offset);
315
+ const bytesRead = readSync(descriptor, buffer, 0, length, Number(offset));
316
+ if (bytesRead === 0) throw new Error('Bound backup output was truncated');
317
+ hash.update(buffer.subarray(0, bytesRead));
318
+ offset += BigInt(bytesRead);
319
+ }
320
+ return hash.digest('hex');
321
+ }
322
+
323
+ function serializedError(error) {
324
+ return {
325
+ name: error instanceof Error ? error.name : 'Error',
326
+ message: error instanceof Error ? error.message : 'Bound backup writer failed',
327
+ ...(typeof error?.code === 'string' ? { code: error.code } : {}),
328
+ };
329
+ }
330
+
331
+ let descriptor;
332
+ let result;
333
+ let failure;
334
+ try {
335
+ const request = parseRequest();
336
+ const bytes = readFileSync(0);
337
+ if (BigInt(bytes.length) !== request.size
338
+ || createHash('sha256').update(bytes).digest('hex') !== request.sha256) {
339
+ throw new Error('Bound backup input bytes do not match their attestation');
340
+ }
341
+ requireDirectory(request);
342
+ const noFollow = request.enforcePosixFileMode ? requiredOpenFlag('O_NOFOLLOW') : 0;
343
+ descriptor = openSync(
344
+ request.destination,
345
+ constants.O_CREAT | constants.O_EXCL | constants.O_RDWR
346
+ | noFollow,
347
+ 0o600,
348
+ );
349
+ if (request.enforcePosixFileMode) fchmodSync(descriptor, 0o600);
350
+ writeFileSync(descriptor, bytes);
351
+ fsyncSync(descriptor);
352
+ const opened = fstatSync(descriptor, { bigint: true });
353
+ if (!opened.isFile()
354
+ || opened.size !== request.size
355
+ || opened.nlink !== 1n
356
+ || (request.enforcePosixFileMode && (opened.mode & 0o777n) !== 0o600n)
357
+ || descriptorHash(descriptor, opened.size) !== request.sha256) {
358
+ throw new Error('Bound backup output failed descriptor attestation');
359
+ }
360
+ closeSync(descriptor);
361
+ descriptor = undefined;
362
+ const named = lstatSync(request.destination, { bigint: true });
363
+ if (!named.isFile()
364
+ || named.isSymbolicLink()
365
+ || named.dev !== opened.dev
366
+ || named.ino !== opened.ino
367
+ || named.uid !== opened.uid
368
+ || named.gid !== opened.gid
369
+ || named.mode !== opened.mode
370
+ || named.size !== opened.size
371
+ || named.nlink !== opened.nlink) {
372
+ throw new Error('Bound backup output changed before handoff');
373
+ }
374
+ requireDirectory(request);
375
+ result = {
376
+ ok: true,
377
+ artifact: {
378
+ device: opened.dev.toString(),
379
+ inode: opened.ino.toString(),
380
+ owner: opened.uid.toString(),
381
+ group: opened.gid.toString(),
382
+ mode: opened.mode.toString(),
383
+ size: opened.size.toString(),
384
+ linkCount: opened.nlink.toString(),
385
+ sha256: request.sha256,
386
+ },
387
+ };
388
+ } catch (error) {
389
+ failure = error;
390
+ }
391
+ if (descriptor !== undefined) {
392
+ try {
393
+ closeSync(descriptor);
394
+ } catch (closeError) {
395
+ failure = failure === undefined
396
+ ? closeError
397
+ : new AggregateError([failure, closeError], 'Bound backup write and descriptor close both failed');
398
+ }
399
+ }
400
+ if (failure !== undefined) result = { ok: false, error: serializedError(failure) };
401
+ process.stdout.write(JSON.stringify(result));
402
+ `;
403
+ function sha256(bytes) {
404
+ return createHash('sha256').update(bytes).digest('hex');
405
+ }
406
+ function normalizedSerializedSnapshot(database) {
407
+ const serialized = Buffer.from(database.serializeDatabase());
408
+ if (serialized.length < 100
409
+ || !serialized.subarray(0, 16).equals(Buffer.from('SQLite format 3\0', 'binary'))
410
+ || !((serialized[18] === 1 && serialized[19] === 1)
411
+ || (serialized[18] === 2 && serialized[19] === 2))) {
412
+ throw new KiokukoError('INTEGRITY_ERROR', 'Serialized SQLite backup has an invalid file header');
413
+ }
414
+ // sqlite3_serialize preserves the WAL read/write header bytes. The serialized
415
+ // image already contains the connection's complete logical snapshot, so set
416
+ // the standalone image to rollback-journal format before deserializing it.
417
+ serialized[18] = 1;
418
+ serialized[19] = 1;
419
+ const verification = new DatabaseSync(':memory:', { enableForeignKeyConstraints: true });
420
+ let failed = false;
421
+ let operationError;
422
+ try {
423
+ const methods = verification;
424
+ if (typeof methods.deserialize !== 'function' || typeof methods.serialize !== 'function') {
425
+ throw new Error('SQLite serialization requires Node.js 24.16.0 or newer');
426
+ }
427
+ methods.deserialize(serialized);
428
+ const integrity = verification.prepare('PRAGMA integrity_check').get();
429
+ if (integrity?.integrity_check !== 'ok')
430
+ throw new Error('backup integrity check failed');
431
+ if (verification.prepare('PRAGMA foreign_key_check').all().length > 0) {
432
+ throw new Error('backup foreign-key integrity check failed');
433
+ }
434
+ const normalized = Buffer.from(methods.serialize());
435
+ if (normalized.length < 100 || normalized[18] !== 1 || normalized[19] !== 1) {
436
+ throw new Error('Serialized SQLite backup did not normalize to a standalone image');
28
437
  }
29
- finally {
438
+ return normalized;
439
+ }
440
+ catch (error) {
441
+ failed = true;
442
+ operationError = error;
443
+ throw error;
444
+ }
445
+ finally {
446
+ try {
30
447
  verification.close();
31
448
  }
32
- return output;
449
+ catch (closeError) {
450
+ if (failed) {
451
+ throw new AggregateError([operationError, closeError], 'Serialized backup verification failed and closing it also failed');
452
+ }
453
+ throw closeError;
454
+ }
455
+ }
456
+ }
457
+ function isPlainObject(value) {
458
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
459
+ return false;
460
+ const prototype = Object.getPrototypeOf(value);
461
+ return prototype === Object.prototype || prototype === null;
462
+ }
463
+ function exactKeys(value, keys) {
464
+ const actual = Object.keys(value).sort();
465
+ const expected = [...keys].sort();
466
+ return actual.length === expected.length
467
+ && actual.every((key, index) => key === expected[index]);
468
+ }
469
+ function parseUnsigned(value) {
470
+ if (typeof value !== 'string' || !/^(?:0|[1-9][0-9]*)$/u.test(value)) {
471
+ throw new Error('Bound backup writer returned an invalid integer');
472
+ }
473
+ return BigInt(value);
474
+ }
475
+ function writeBoundArtifact(binding, fileName, bytes, posixFlags) {
476
+ const request = {
477
+ destination: fileName,
478
+ directory: {
479
+ device: binding.device.toString(),
480
+ inode: binding.inode.toString(),
481
+ owner: binding.owner.toString(),
482
+ group: binding.group.toString(),
483
+ mode: binding.mode.toString(),
484
+ },
485
+ enforcePosixFileMode: posixFlags !== undefined,
486
+ requirePrivateDirectory: binding.privateDirectory && posixFlags !== undefined,
487
+ sha256: sha256(bytes),
488
+ size: bytes.length.toString(),
489
+ };
490
+ const child = spawnSync(process.execPath, ['--input-type=commonjs', '--eval', BOUND_WRITER_SCRIPT, JSON.stringify(request)], {
491
+ cwd: binding.directory,
492
+ // The worker uses only built-in modules and an absolute executable path.
493
+ // Do not inherit preload, loader, search-path, or application environment.
494
+ env: {},
495
+ shell: false,
496
+ input: bytes,
497
+ timeout: WRITER_DEADLINE_MS,
498
+ maxBuffer: WRITER_PROTOCOL_LIMIT_BYTES,
499
+ });
500
+ if (child.error !== undefined)
501
+ throw child.error;
502
+ if (child.status !== 0 || child.signal !== null) {
503
+ throw new Error('Bound backup writer subprocess failed');
504
+ }
505
+ let parsed;
506
+ try {
507
+ parsed = JSON.parse(child.stdout.toString('utf8'));
33
508
  }
34
509
  catch (error) {
35
- await Promise.all([
36
- unlink(output).catch(() => undefined),
37
- unlink(`${output}-wal`).catch(() => undefined),
38
- unlink(`${output}-shm`).catch(() => undefined),
39
- ]);
40
- throw new KiokukoError('DATABASE_ERROR', 'Could not create and verify the pre-migration backup; the database was not migrated', { cause: error instanceof Error ? error.message : 'unknown backup error' });
510
+ if (error instanceof SyntaxError)
511
+ throw new Error('Bound backup writer returned invalid JSON');
512
+ throw error;
513
+ }
514
+ if (!isPlainObject(parsed) || typeof parsed.ok !== 'boolean') {
515
+ throw new Error('Bound backup writer returned an invalid result');
516
+ }
517
+ if (!parsed.ok) {
518
+ if (!exactKeys(parsed, ['error', 'ok']) || !isPlainObject(parsed.error)
519
+ || !Object.hasOwn(parsed.error, 'name')
520
+ || !Object.hasOwn(parsed.error, 'message')
521
+ || Object.keys(parsed.error).some((key) => !['code', 'message', 'name'].includes(key))
522
+ || typeof parsed.error.name !== 'string'
523
+ || typeof parsed.error.message !== 'string'
524
+ || (Object.hasOwn(parsed.error, 'code') && typeof parsed.error.code !== 'string')) {
525
+ throw new Error('Bound backup writer returned an invalid result');
526
+ }
527
+ if (parsed.error.code === 'EEXIST') {
528
+ throw new KiokukoError('CONFLICT', 'Backup destination already exists');
529
+ }
530
+ throw Object.assign(new Error(parsed.error.message), {
531
+ name: parsed.error.name,
532
+ ...(typeof parsed.error.code === 'string' ? { code: parsed.error.code } : {}),
533
+ });
534
+ }
535
+ if (!exactKeys(parsed, ['artifact', 'ok']) || !isPlainObject(parsed.artifact)
536
+ || !exactKeys(parsed.artifact, [
537
+ 'device', 'group', 'inode', 'linkCount', 'mode', 'owner', 'sha256', 'size',
538
+ ])
539
+ || typeof parsed.artifact.sha256 !== 'string'
540
+ || parsed.artifact.sha256 !== request.sha256) {
541
+ throw new Error('Bound backup writer returned an invalid artifact attestation');
542
+ }
543
+ const attestation = Object.freeze({
544
+ device: parseUnsigned(parsed.artifact.device),
545
+ inode: parseUnsigned(parsed.artifact.inode),
546
+ owner: parseUnsigned(parsed.artifact.owner),
547
+ group: parseUnsigned(parsed.artifact.group),
548
+ mode: parseUnsigned(parsed.artifact.mode),
549
+ size: parseUnsigned(parsed.artifact.size),
550
+ linkCount: parseUnsigned(parsed.artifact.linkCount),
551
+ sha256: parsed.artifact.sha256,
552
+ });
553
+ if (attestation.size !== BigInt(bytes.length)
554
+ || attestation.linkCount !== 1n
555
+ || (process.platform !== 'win32' && (attestation.mode & 511n) !== 384n)) {
556
+ throw new Error('Bound backup writer returned an invalid artifact attestation');
557
+ }
558
+ return attestation;
559
+ }
560
+ async function descriptorSha256(handle, size) {
561
+ if (size < 0n || size > BigInt(Number.MAX_SAFE_INTEGER)) {
562
+ throw new KiokukoError('INTEGRITY_ERROR', 'Serialized backup artifact size is unsupported');
563
+ }
564
+ const expectedLength = Number(size);
565
+ const hash = createHash('sha256');
566
+ const buffer = Buffer.allocUnsafe(64 * 1024);
567
+ let offset = 0;
568
+ while (offset < expectedLength) {
569
+ const length = Math.min(buffer.length, expectedLength - offset);
570
+ const { bytesRead } = await handle.read(buffer, 0, length, offset);
571
+ if (bytesRead === 0) {
572
+ throw new KiokukoError('CONFLICT', 'Serialized backup artifact changed during verification');
573
+ }
574
+ hash.update(buffer.subarray(0, bytesRead));
575
+ offset += bytesRead;
576
+ }
577
+ return hash.digest('hex');
578
+ }
579
+ function sameArtifactStatus(status, attestation) {
580
+ return status.isFile()
581
+ && status.dev === attestation.device
582
+ && status.ino === attestation.inode
583
+ && status.uid === attestation.owner
584
+ && status.gid === attestation.group
585
+ && status.mode === attestation.mode
586
+ && status.size === attestation.size
587
+ && status.nlink === attestation.linkCount
588
+ && status.size > 0n
589
+ && status.nlink === 1n
590
+ && (process.platform === 'win32' || (status.mode & 511n) === 384n);
591
+ }
592
+ async function requireBoundArtifact(output, attestation, posixFlags) {
593
+ let handle;
594
+ let operationFailed = false;
595
+ let operationError;
596
+ try {
597
+ handle = await open(output, posixFlags === undefined
598
+ ? constants.O_RDONLY
599
+ : constants.O_RDONLY | posixFlags.noFollow | posixFlags.nonBlock);
600
+ const opened = await handle.stat({ bigint: true });
601
+ const named = await lstat(output, { bigint: true });
602
+ if (!sameArtifactStatus(opened, attestation)
603
+ || !named.isFile()
604
+ || named.isSymbolicLink()
605
+ || named.dev !== opened.dev
606
+ || named.ino !== opened.ino
607
+ || named.uid !== opened.uid
608
+ || named.gid !== opened.gid
609
+ || named.mode !== opened.mode
610
+ || named.size !== opened.size
611
+ || named.nlink !== opened.nlink
612
+ || await descriptorSha256(handle, opened.size) !== attestation.sha256) {
613
+ throw new KiokukoError('CONFLICT', 'Serialized backup artifact changed before parent verification');
614
+ }
615
+ const after = await handle.stat({ bigint: true });
616
+ if (!sameArtifactStatus(after, attestation)) {
617
+ throw new KiokukoError('CONFLICT', 'Serialized backup artifact changed during parent verification');
618
+ }
619
+ }
620
+ catch (error) {
621
+ operationFailed = true;
622
+ operationError = error;
623
+ throw error;
624
+ }
625
+ finally {
626
+ if (handle !== undefined) {
627
+ try {
628
+ await handle.close();
629
+ }
630
+ catch (closeError) {
631
+ if (operationFailed) {
632
+ throw new AggregateError([operationError, closeError], 'Serialized backup verification failed and closing its descriptor also failed');
633
+ }
634
+ throw closeError;
635
+ }
636
+ }
637
+ }
638
+ }
639
+ function directoryAttestation(binding) {
640
+ return Object.freeze({
641
+ path: binding.directory,
642
+ device: binding.device,
643
+ inode: binding.inode,
644
+ owner: binding.owner,
645
+ group: binding.group,
646
+ mode: binding.mode,
647
+ });
648
+ }
649
+ async function normalizedDestination(destination) {
650
+ if (typeof destination !== 'string'
651
+ || destination.length === 0
652
+ || destination.includes('\0')
653
+ || !isWellFormedUnicode(destination)
654
+ || /[\\/]$/u.test(destination)) {
655
+ throw new KiokukoError('VALIDATION_ERROR', 'Backup destination must be a non-empty pathname');
656
+ }
657
+ const requestedOutput = path.resolve(destination);
658
+ const fileName = path.basename(requestedOutput);
659
+ const portableStem = fileName.split('.', 1)[0]?.replace(/[ .]+$/u, '').toUpperCase();
660
+ if (fileName.length === 0
661
+ || fileName === '.'
662
+ || fileName === '..'
663
+ || /[<>:"\/\\|?*\u0000-\u001F]/u.test(fileName)
664
+ || /[ .]$/u.test(fileName)
665
+ || portableStem === undefined
666
+ || /^(?:CON|PRN|AUX|NUL|COM[1-9¹²³]|LPT[1-9¹²³]|CONIN\$|CONOUT\$)$/u.test(portableStem)) {
667
+ throw new KiokukoError('VALIDATION_ERROR', 'Backup destination must name one portable standalone file');
668
+ }
669
+ const directory = await realpath(path.dirname(requestedOutput));
670
+ await requireCanonicalDirectoryChain(directory);
671
+ return { output: path.join(directory, fileName), fileName };
672
+ }
673
+ async function syncBackupDirectory(binding) {
674
+ if (process.platform !== 'win32' && binding.handle !== undefined) {
675
+ await binding.handle.sync();
676
+ }
677
+ }
678
+ /**
679
+ * Serialize the exact already-open source and install one create-only backup.
680
+ * The output directory must already exist and is never chmodded by this path.
681
+ */
682
+ export async function createSerializedBackupArtifact(database, destination, hooks = {}) {
683
+ const posixFlags = requirePosixBackupOpenFlags();
684
+ const { output, fileName } = await normalizedDestination(destination);
685
+ await hooks.validateDestination?.(output);
686
+ let directoryBinding;
687
+ let operationFailed = false;
688
+ let operationError;
689
+ try {
690
+ await hooks.beforeSerialization?.();
691
+ const bytes = normalizedSerializedSnapshot(database);
692
+ directoryBinding = await bindExistingOutputDirectory(output, posixFlags);
693
+ await hooks.afterDirectoryBound?.();
694
+ await hooks.beforeArtifactWrite?.(output);
695
+ const artifact = writeBoundArtifact(directoryBinding, fileName, bytes, posixFlags);
696
+ await requireBoundArtifact(output, artifact, posixFlags);
697
+ await hooks.afterArtifactWritten?.(output);
698
+ await requireBoundArtifact(output, artifact, posixFlags);
699
+ await requireBackupDirectory(directoryBinding);
700
+ await syncBackupDirectory(directoryBinding);
701
+ return Object.freeze({
702
+ path: output,
703
+ directory: directoryAttestation(directoryBinding),
704
+ artifact,
705
+ });
706
+ }
707
+ catch (error) {
708
+ operationFailed = true;
709
+ operationError = error;
710
+ throw error;
711
+ }
712
+ finally {
713
+ if (directoryBinding?.handle !== undefined) {
714
+ try {
715
+ await directoryBinding.handle.close();
716
+ }
717
+ catch (closeError) {
718
+ if (operationFailed) {
719
+ throw new AggregateError([operationError, closeError], 'Serialized backup creation failed and closing its directory also failed');
720
+ }
721
+ throw closeError;
722
+ }
723
+ }
724
+ }
725
+ }
726
+ export async function createPreMigrationBackup(database, databasePath, fromVersion, toVersion, hooks = {}) {
727
+ const posixFlags = requirePosixBackupOpenFlags();
728
+ let directoryBinding;
729
+ let operationFailed = false;
730
+ let operationError;
731
+ try {
732
+ await hooks.beforeSerialization?.();
733
+ const bytes = normalizedSerializedSnapshot(database);
734
+ directoryBinding = await bindBackupDirectory(databasePath, posixFlags);
735
+ const fileName = backupName(databasePath, fromVersion, toVersion);
736
+ const output = path.join(directoryBinding.directory, fileName);
737
+ await hooks.afterDirectoryBound?.();
738
+ await hooks.beforeArtifactWrite?.(output);
739
+ const artifact = writeBoundArtifact(directoryBinding, fileName, bytes, posixFlags);
740
+ await requireBoundArtifact(output, artifact, posixFlags);
741
+ await hooks.afterArtifactWritten?.(output);
742
+ await requireBoundArtifact(output, artifact, posixFlags);
743
+ await requireBackupDirectory(directoryBinding);
744
+ await syncBackupDirectory(directoryBinding);
745
+ return Object.freeze({
746
+ path: output,
747
+ directory: directoryAttestation(directoryBinding),
748
+ artifact,
749
+ });
750
+ }
751
+ catch (error) {
752
+ const failure = new KiokukoError('DATABASE_ERROR', 'Could not create and verify the pre-migration backup; the database was not migrated');
753
+ Object.defineProperty(failure, 'cause', { value: error });
754
+ operationFailed = true;
755
+ operationError = failure;
756
+ throw failure;
757
+ }
758
+ finally {
759
+ if (directoryBinding?.handle !== undefined) {
760
+ try {
761
+ await directoryBinding.handle.close();
762
+ }
763
+ catch (closeError) {
764
+ if (operationFailed) {
765
+ throw new AggregateError([operationError, closeError], 'Pre-migration backup failed and closing its directory also failed');
766
+ }
767
+ throw closeError;
768
+ }
769
+ }
41
770
  }
42
771
  }
43
772
  //# sourceMappingURL=upgrade-backup.js.map