@askdkc/kiokuko 0.1.17 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (539) hide show
  1. package/README.ja.md +91 -112
  2. package/README.ko.md +90 -102
  3. package/README.md +103 -262
  4. package/README.zh-CN.md +88 -102
  5. package/dist/agent-file/atomic-write.d.ts +90 -3
  6. package/dist/agent-file/atomic-write.d.ts.map +1 -1
  7. package/dist/agent-file/atomic-write.js +990 -14
  8. package/dist/agent-file/atomic-write.js.map +1 -1
  9. package/dist/agent-file/managed-block.d.ts +12 -1
  10. package/dist/agent-file/managed-block.d.ts.map +1 -1
  11. package/dist/agent-file/managed-block.js +49 -4
  12. package/dist/agent-file/managed-block.js.map +1 -1
  13. package/dist/agent-file/render.d.ts +1 -1
  14. package/dist/agent-file/render.d.ts.map +1 -1
  15. package/dist/agent-file/render.js +10 -7
  16. package/dist/agent-file/render.js.map +1 -1
  17. package/dist/akinator/agent-task.d.ts +11 -22
  18. package/dist/akinator/agent-task.d.ts.map +1 -1
  19. package/dist/akinator/agent-task.js +454 -99
  20. package/dist/akinator/agent-task.js.map +1 -1
  21. package/dist/akinator/capabilities.d.ts +18 -6
  22. package/dist/akinator/capabilities.d.ts.map +1 -1
  23. package/dist/akinator/capabilities.js +72 -35
  24. package/dist/akinator/capabilities.js.map +1 -1
  25. package/dist/akinator/capability-binding.d.ts +11 -0
  26. package/dist/akinator/capability-binding.d.ts.map +1 -0
  27. package/dist/akinator/capability-binding.js +56 -0
  28. package/dist/akinator/capability-binding.js.map +1 -0
  29. package/dist/akinator/domain.js +2 -2
  30. package/dist/akinator/domain.js.map +1 -1
  31. package/dist/akinator/knowledge-path.d.ts.map +1 -1
  32. package/dist/akinator/knowledge-path.js +409 -39
  33. package/dist/akinator/knowledge-path.js.map +1 -1
  34. package/dist/akinator/orchestrator.d.ts +3 -4
  35. package/dist/akinator/orchestrator.d.ts.map +1 -1
  36. package/dist/akinator/orchestrator.js +1 -4
  37. package/dist/akinator/orchestrator.js.map +1 -1
  38. package/dist/akinator/service.d.ts +0 -4
  39. package/dist/akinator/service.d.ts.map +1 -1
  40. package/dist/akinator/service.js +19 -35
  41. package/dist/akinator/service.js.map +1 -1
  42. package/dist/akinator/skill-discovery-attempt.d.ts +20 -0
  43. package/dist/akinator/skill-discovery-attempt.d.ts.map +1 -0
  44. package/dist/akinator/skill-discovery-attempt.js +390 -0
  45. package/dist/akinator/skill-discovery-attempt.js.map +1 -0
  46. package/dist/akinator/store.d.ts.map +1 -1
  47. package/dist/akinator/store.js +107 -52
  48. package/dist/akinator/store.js.map +1 -1
  49. package/dist/akinator/types.d.ts +0 -12
  50. package/dist/akinator/types.d.ts.map +1 -1
  51. package/dist/cli.d.ts +2 -0
  52. package/dist/cli.d.ts.map +1 -1
  53. package/dist/cli.js +560 -150
  54. package/dist/cli.js.map +1 -1
  55. package/dist/client/server-client.d.ts +5 -3
  56. package/dist/client/server-client.d.ts.map +1 -1
  57. package/dist/client/server-client.js +486 -181
  58. package/dist/client/server-client.js.map +1 -1
  59. package/dist/commands/agent.d.ts +2 -0
  60. package/dist/commands/agent.d.ts.map +1 -1
  61. package/dist/commands/agent.js +861 -86
  62. package/dist/commands/agent.js.map +1 -1
  63. package/dist/commands/backup.d.ts +2 -1
  64. package/dist/commands/backup.d.ts.map +1 -1
  65. package/dist/commands/backup.js +71 -8
  66. package/dist/commands/backup.js.map +1 -1
  67. package/dist/commands/doctor.d.ts +5 -1
  68. package/dist/commands/doctor.d.ts.map +1 -1
  69. package/dist/commands/doctor.js +70 -26
  70. package/dist/commands/doctor.js.map +1 -1
  71. package/dist/commands/export.d.ts +0 -4
  72. package/dist/commands/export.d.ts.map +1 -1
  73. package/dist/commands/export.js +191 -32
  74. package/dist/commands/export.js.map +1 -1
  75. package/dist/commands/import.d.ts +10 -1
  76. package/dist/commands/import.d.ts.map +1 -1
  77. package/dist/commands/import.js +592 -113
  78. package/dist/commands/import.js.map +1 -1
  79. package/dist/commands/init.d.ts +19 -1
  80. package/dist/commands/init.d.ts.map +1 -1
  81. package/dist/commands/init.js +569 -22
  82. package/dist/commands/init.js.map +1 -1
  83. package/dist/commands/purge.d.ts.map +1 -1
  84. package/dist/commands/purge.js +3 -0
  85. package/dist/commands/purge.js.map +1 -1
  86. package/dist/commands/setup.d.ts +37 -8
  87. package/dist/commands/setup.d.ts.map +1 -1
  88. package/dist/commands/setup.js +448 -86
  89. package/dist/commands/setup.js.map +1 -1
  90. package/dist/commands/skills.d.ts +9 -0
  91. package/dist/commands/skills.d.ts.map +1 -0
  92. package/dist/commands/skills.js +317 -0
  93. package/dist/commands/skills.js.map +1 -0
  94. package/dist/commands/use.d.ts +10 -2
  95. package/dist/commands/use.d.ts.map +1 -1
  96. package/dist/commands/use.js +851 -73
  97. package/dist/commands/use.js.map +1 -1
  98. package/dist/config/paths.d.ts +11 -1
  99. package/dist/config/paths.d.ts.map +1 -1
  100. package/dist/config/paths.js +64 -29
  101. package/dist/config/paths.js.map +1 -1
  102. package/dist/config/project-config.d.ts +1 -0
  103. package/dist/config/project-config.d.ts.map +1 -1
  104. package/dist/config/project-config.js +70 -32
  105. package/dist/config/project-config.js.map +1 -1
  106. package/dist/context/broker.d.ts +28 -14
  107. package/dist/context/broker.d.ts.map +1 -1
  108. package/dist/context/broker.js +604 -145
  109. package/dist/context/broker.js.map +1 -1
  110. package/dist/context/delivery.d.ts +6 -21
  111. package/dist/context/delivery.d.ts.map +1 -1
  112. package/dist/context/delivery.js +196 -147
  113. package/dist/context/delivery.js.map +1 -1
  114. package/dist/context/feedback.d.ts +11 -12
  115. package/dist/context/feedback.d.ts.map +1 -1
  116. package/dist/context/feedback.js +229 -261
  117. package/dist/context/feedback.js.map +1 -1
  118. package/dist/context/ranking.d.ts +1 -12
  119. package/dist/context/ranking.d.ts.map +1 -1
  120. package/dist/context/ranking.js +13 -4
  121. package/dist/context/ranking.js.map +1 -1
  122. package/dist/context/recommendations.d.ts +0 -5
  123. package/dist/context/recommendations.d.ts.map +1 -1
  124. package/dist/context/recommendations.js +0 -1
  125. package/dist/context/recommendations.js.map +1 -1
  126. package/dist/context/run-state.d.ts +26 -0
  127. package/dist/context/run-state.d.ts.map +1 -0
  128. package/dist/context/run-state.js +399 -0
  129. package/dist/context/run-state.js.map +1 -0
  130. package/dist/context/scoped-broker.d.ts +17 -5
  131. package/dist/context/scoped-broker.d.ts.map +1 -1
  132. package/dist/context/scoped-broker.js +512 -106
  133. package/dist/context/scoped-broker.js.map +1 -1
  134. package/dist/context/selection-state.d.ts +19 -0
  135. package/dist/context/selection-state.d.ts.map +1 -0
  136. package/dist/context/selection-state.js +250 -0
  137. package/dist/context/selection-state.js.map +1 -0
  138. package/dist/db/adapter.d.ts +5 -3
  139. package/dist/db/adapter.d.ts.map +1 -1
  140. package/dist/db/adapter.js +7 -3
  141. package/dist/db/adapter.js.map +1 -1
  142. package/dist/db/capabilities.d.ts.map +1 -1
  143. package/dist/db/capabilities.js +34 -16
  144. package/dist/db/capabilities.js.map +1 -1
  145. package/dist/db/connection.d.ts +8 -0
  146. package/dist/db/connection.d.ts.map +1 -1
  147. package/dist/db/connection.js +55 -26
  148. package/dist/db/connection.js.map +1 -1
  149. package/dist/db/migrate.d.ts +28 -7
  150. package/dist/db/migrate.d.ts.map +1 -1
  151. package/dist/db/migrate.js +106 -78
  152. package/dist/db/migrate.js.map +1 -1
  153. package/dist/db/sqlite-retry.d.ts +11 -0
  154. package/dist/db/sqlite-retry.d.ts.map +1 -0
  155. package/dist/db/sqlite-retry.js +66 -0
  156. package/dist/db/sqlite-retry.js.map +1 -0
  157. package/dist/db/transaction.d.ts +13 -0
  158. package/dist/db/transaction.d.ts.map +1 -1
  159. package/dist/db/transaction.js +53 -24
  160. package/dist/db/transaction.js.map +1 -1
  161. package/dist/db/upgrade-backup.d.ts +58 -2
  162. package/dist/db/upgrade-backup.d.ts.map +1 -1
  163. package/dist/db/upgrade-backup.js +758 -28
  164. package/dist/db/upgrade-backup.js.map +1 -1
  165. package/dist/errors.d.ts +4 -0
  166. package/dist/errors.d.ts.map +1 -1
  167. package/dist/errors.js +29 -1
  168. package/dist/errors.js.map +1 -1
  169. package/dist/gateway/agent-service.d.ts +4 -1
  170. package/dist/gateway/agent-service.d.ts.map +1 -1
  171. package/dist/gateway/agent-service.js +71 -58
  172. package/dist/gateway/agent-service.js.map +1 -1
  173. package/dist/gateway/checkpoint-service.d.ts +1 -0
  174. package/dist/gateway/checkpoint-service.d.ts.map +1 -1
  175. package/dist/gateway/checkpoint-service.js +47 -24
  176. package/dist/gateway/checkpoint-service.js.map +1 -1
  177. package/dist/ledger/archive.d.ts +1 -4
  178. package/dist/ledger/archive.d.ts.map +1 -1
  179. package/dist/ledger/archive.js +77 -39
  180. package/dist/ledger/archive.js.map +1 -1
  181. package/dist/ledger/maintenance.d.ts +0 -11
  182. package/dist/ledger/maintenance.d.ts.map +1 -1
  183. package/dist/ledger/maintenance.js +24 -40
  184. package/dist/ledger/maintenance.js.map +1 -1
  185. package/dist/ledger/projection.d.ts +0 -1
  186. package/dist/ledger/projection.d.ts.map +1 -1
  187. package/dist/ledger/projection.js.map +1 -1
  188. package/dist/ledger/promotion.d.ts +0 -9
  189. package/dist/ledger/promotion.d.ts.map +1 -1
  190. package/dist/ledger/promotion.js.map +1 -1
  191. package/dist/ledger/query.d.ts +1 -15
  192. package/dist/ledger/query.d.ts.map +1 -1
  193. package/dist/ledger/query.js.map +1 -1
  194. package/dist/ledger/store.d.ts +0 -1
  195. package/dist/ledger/store.d.ts.map +1 -1
  196. package/dist/ledger/store.js +11 -8
  197. package/dist/ledger/store.js.map +1 -1
  198. package/dist/ledger/types.d.ts +0 -4
  199. package/dist/ledger/types.d.ts.map +1 -1
  200. package/dist/ledger/types.js.map +1 -1
  201. package/dist/ledger/validate.d.ts.map +1 -1
  202. package/dist/ledger/validate.js +0 -5
  203. package/dist/ledger/validate.js.map +1 -1
  204. package/dist/mcp/server.d.ts +4 -0
  205. package/dist/mcp/server.d.ts.map +1 -1
  206. package/dist/mcp/server.js +105 -54
  207. package/dist/mcp/server.js.map +1 -1
  208. package/dist/memory/audit.d.ts +0 -1
  209. package/dist/memory/audit.d.ts.map +1 -1
  210. package/dist/memory/audit.js +0 -1
  211. package/dist/memory/audit.js.map +1 -1
  212. package/dist/memory/curator.d.ts.map +1 -1
  213. package/dist/memory/curator.js +172 -96
  214. package/dist/memory/curator.js.map +1 -1
  215. package/dist/memory/entries.d.ts +12 -2
  216. package/dist/memory/entries.d.ts.map +1 -1
  217. package/dist/memory/entries.js +199 -115
  218. package/dist/memory/entries.js.map +1 -1
  219. package/dist/memory/federated-retrieval.d.ts +12 -1
  220. package/dist/memory/federated-retrieval.d.ts.map +1 -1
  221. package/dist/memory/federated-retrieval.js +183 -70
  222. package/dist/memory/federated-retrieval.js.map +1 -1
  223. package/dist/memory/hybrid-retrieval.d.ts +5 -11
  224. package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
  225. package/dist/memory/hybrid-retrieval.js +78 -58
  226. package/dist/memory/hybrid-retrieval.js.map +1 -1
  227. package/dist/memory/lifecycle.d.ts.map +1 -1
  228. package/dist/memory/lifecycle.js +17 -13
  229. package/dist/memory/lifecycle.js.map +1 -1
  230. package/dist/memory/rebuild-search.d.ts +5 -0
  231. package/dist/memory/rebuild-search.d.ts.map +1 -1
  232. package/dist/memory/rebuild-search.js +101 -76
  233. package/dist/memory/rebuild-search.js.map +1 -1
  234. package/dist/memory/retrieval-query.d.ts +0 -5
  235. package/dist/memory/retrieval-query.d.ts.map +1 -1
  236. package/dist/memory/retrieval-query.js +0 -5
  237. package/dist/memory/retrieval-query.js.map +1 -1
  238. package/dist/memory/retrieval.d.ts.map +1 -1
  239. package/dist/memory/retrieval.js +25 -131
  240. package/dist/memory/retrieval.js.map +1 -1
  241. package/dist/memory/revisions.d.ts +76 -1
  242. package/dist/memory/revisions.d.ts.map +1 -1
  243. package/dist/memory/revisions.js +540 -36
  244. package/dist/memory/revisions.js.map +1 -1
  245. package/dist/memory/scoped-memory.d.ts +16 -1
  246. package/dist/memory/scoped-memory.d.ts.map +1 -1
  247. package/dist/memory/scoped-memory.js +240 -107
  248. package/dist/memory/scoped-memory.js.map +1 -1
  249. package/dist/memory/secrets.d.ts +2 -0
  250. package/dist/memory/secrets.d.ts.map +1 -1
  251. package/dist/memory/secrets.js +36 -0
  252. package/dist/memory/secrets.js.map +1 -1
  253. package/dist/memory/structured-memory.d.ts +3 -2
  254. package/dist/memory/structured-memory.d.ts.map +1 -1
  255. package/dist/memory/structured-memory.js +54 -22
  256. package/dist/memory/structured-memory.js.map +1 -1
  257. package/dist/memory/workspaces.d.ts +9 -0
  258. package/dist/memory/workspaces.d.ts.map +1 -1
  259. package/dist/memory/workspaces.js +67 -0
  260. package/dist/memory/workspaces.js.map +1 -1
  261. package/dist/package-version.d.ts +2 -0
  262. package/dist/package-version.d.ts.map +1 -0
  263. package/dist/package-version.js +7 -0
  264. package/dist/package-version.js.map +1 -0
  265. package/dist/repository/binding.d.ts +5 -0
  266. package/dist/repository/binding.d.ts.map +1 -1
  267. package/dist/repository/binding.js +117 -17
  268. package/dist/repository/binding.js.map +1 -1
  269. package/dist/repository/framework-version.d.ts +8 -0
  270. package/dist/repository/framework-version.d.ts.map +1 -0
  271. package/dist/repository/framework-version.js +29 -0
  272. package/dist/repository/framework-version.js.map +1 -0
  273. package/dist/repository/identity-value.d.ts +4 -0
  274. package/dist/repository/identity-value.d.ts.map +1 -0
  275. package/dist/repository/identity-value.js +24 -0
  276. package/dist/repository/identity-value.js.map +1 -0
  277. package/dist/repository/identity.d.ts.map +1 -1
  278. package/dist/repository/identity.js +2 -0
  279. package/dist/repository/identity.js.map +1 -1
  280. package/dist/repository/project-fingerprint.d.ts +14 -2
  281. package/dist/repository/project-fingerprint.d.ts.map +1 -1
  282. package/dist/repository/project-fingerprint.js +312 -33
  283. package/dist/repository/project-fingerprint.js.map +1 -1
  284. package/dist/repository/remote-url.d.ts +0 -1
  285. package/dist/repository/remote-url.d.ts.map +1 -1
  286. package/dist/repository/remote-url.js +0 -1
  287. package/dist/repository/remote-url.js.map +1 -1
  288. package/dist/runtime-version.d.ts +2 -1
  289. package/dist/runtime-version.d.ts.map +1 -1
  290. package/dist/runtime-version.js +21 -4
  291. package/dist/runtime-version.js.map +1 -1
  292. package/dist/serialization/boundary-json.d.ts +20 -0
  293. package/dist/serialization/boundary-json.d.ts.map +1 -0
  294. package/dist/serialization/boundary-json.js +129 -0
  295. package/dist/serialization/boundary-json.js.map +1 -0
  296. package/dist/serialization/envelope.js +1 -1
  297. package/dist/serialization/envelope.js.map +1 -1
  298. package/dist/serialization/validate.d.ts +7 -0
  299. package/dist/serialization/validate.d.ts.map +1 -1
  300. package/dist/serialization/validate.js +53 -13
  301. package/dist/serialization/validate.js.map +1 -1
  302. package/dist/server/app.js +1 -1
  303. package/dist/server/app.js.map +1 -1
  304. package/dist/server/http.d.ts +4 -3
  305. package/dist/server/http.d.ts.map +1 -1
  306. package/dist/server/http.js +90 -50
  307. package/dist/server/http.js.map +1 -1
  308. package/dist/server/idempotency.d.ts +0 -6
  309. package/dist/server/idempotency.d.ts.map +1 -1
  310. package/dist/server/idempotency.js.map +1 -1
  311. package/dist/server/router.d.ts.map +1 -1
  312. package/dist/server/router.js +21 -4
  313. package/dist/server/router.js.map +1 -1
  314. package/dist/server/routes/agent-capability-gate.d.ts +40 -0
  315. package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
  316. package/dist/server/routes/agent-capability-gate.js +182 -0
  317. package/dist/server/routes/agent-capability-gate.js.map +1 -0
  318. package/dist/server/routes/agent-events.d.ts.map +1 -1
  319. package/dist/server/routes/agent-events.js +8 -1
  320. package/dist/server/routes/agent-events.js.map +1 -1
  321. package/dist/server/routes/agent-intake.d.ts.map +1 -1
  322. package/dist/server/routes/agent-intake.js +10 -2
  323. package/dist/server/routes/agent-intake.js.map +1 -1
  324. package/dist/server/routes/agent-promotions.d.ts.map +1 -1
  325. package/dist/server/routes/agent-promotions.js +5 -2
  326. package/dist/server/routes/agent-promotions.js.map +1 -1
  327. package/dist/server/routes/agent-runs.d.ts.map +1 -1
  328. package/dist/server/routes/agent-runs.js +18 -4
  329. package/dist/server/routes/agent-runs.js.map +1 -1
  330. package/dist/server/routes/request-binding.d.ts +5 -0
  331. package/dist/server/routes/request-binding.d.ts.map +1 -0
  332. package/dist/server/routes/request-binding.js +49 -0
  333. package/dist/server/routes/request-binding.js.map +1 -0
  334. package/dist/server/routes/task5-support.d.ts +1 -8
  335. package/dist/server/routes/task5-support.d.ts.map +1 -1
  336. package/dist/server/routes/task5-support.js +1 -17
  337. package/dist/server/routes/task5-support.js.map +1 -1
  338. package/dist/server/routes/task5.d.ts.map +1 -1
  339. package/dist/server/routes/task5.js +106 -36
  340. package/dist/server/routes/task5.js.map +1 -1
  341. package/dist/server/write-queue.js +2 -2
  342. package/dist/server/write-queue.js.map +1 -1
  343. package/dist/setup/claude-config.d.ts +4 -1
  344. package/dist/setup/claude-config.d.ts.map +1 -1
  345. package/dist/setup/claude-config.js +62 -4
  346. package/dist/setup/claude-config.js.map +1 -1
  347. package/dist/setup/client-detection.d.ts +7 -2
  348. package/dist/setup/client-detection.d.ts.map +1 -1
  349. package/dist/setup/client-detection.js +27 -9
  350. package/dist/setup/client-detection.js.map +1 -1
  351. package/dist/setup/hermes-config.d.ts +4 -1
  352. package/dist/setup/hermes-config.d.ts.map +1 -1
  353. package/dist/setup/hermes-config.js +71 -17
  354. package/dist/setup/hermes-config.js.map +1 -1
  355. package/dist/setup/legacy-client-cleanup.d.ts +6 -0
  356. package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
  357. package/dist/setup/legacy-client-cleanup.js +152 -0
  358. package/dist/setup/legacy-client-cleanup.js.map +1 -0
  359. package/dist/setup/managed-text.d.ts.map +1 -1
  360. package/dist/setup/managed-text.js +11 -1
  361. package/dist/setup/managed-text.js.map +1 -1
  362. package/dist/setup/mcp-conflict.d.ts +4 -0
  363. package/dist/setup/mcp-conflict.d.ts.map +1 -0
  364. package/dist/setup/mcp-conflict.js +15 -0
  365. package/dist/setup/mcp-conflict.js.map +1 -0
  366. package/dist/setup/opencode-config.d.ts +4 -1
  367. package/dist/setup/opencode-config.d.ts.map +1 -1
  368. package/dist/setup/opencode-config.js +65 -5
  369. package/dist/setup/opencode-config.js.map +1 -1
  370. package/dist/setup/render.d.ts +4 -1
  371. package/dist/setup/render.d.ts.map +1 -1
  372. package/dist/setup/render.js +168 -18
  373. package/dist/setup/render.js.map +1 -1
  374. package/dist/setup/standard-skills.d.ts +16 -2
  375. package/dist/setup/standard-skills.d.ts.map +1 -1
  376. package/dist/setup/standard-skills.js +37 -13
  377. package/dist/setup/standard-skills.js.map +1 -1
  378. package/dist/setup/strict-json.d.ts +7 -0
  379. package/dist/setup/strict-json.d.ts.map +1 -0
  380. package/dist/setup/strict-json.js +98 -0
  381. package/dist/setup/strict-json.js.map +1 -0
  382. package/dist/setup/strict-toml.d.ts +18 -0
  383. package/dist/setup/strict-toml.d.ts.map +1 -0
  384. package/dist/setup/strict-toml.js +491 -0
  385. package/dist/setup/strict-toml.js.map +1 -0
  386. package/dist/skills/cache.d.ts +15 -0
  387. package/dist/skills/cache.d.ts.map +1 -0
  388. package/dist/skills/cache.js +19 -0
  389. package/dist/skills/cache.js.map +1 -0
  390. package/dist/skills/candidate-ranking.d.ts +15 -0
  391. package/dist/skills/candidate-ranking.d.ts.map +1 -0
  392. package/dist/skills/candidate-ranking.js +52 -0
  393. package/dist/skills/candidate-ranking.js.map +1 -0
  394. package/dist/skills/chunking.d.ts +11 -0
  395. package/dist/skills/chunking.d.ts.map +1 -0
  396. package/dist/skills/chunking.js +291 -0
  397. package/dist/skills/chunking.js.map +1 -0
  398. package/dist/skills/config.d.ts +19 -0
  399. package/dist/skills/config.d.ts.map +1 -0
  400. package/dist/skills/config.js +103 -0
  401. package/dist/skills/config.js.map +1 -0
  402. package/dist/skills/discovery-service.d.ts +26 -0
  403. package/dist/skills/discovery-service.d.ts.map +1 -0
  404. package/dist/skills/discovery-service.js +921 -0
  405. package/dist/skills/discovery-service.js.map +1 -0
  406. package/dist/skills/external-transport.d.ts +2 -0
  407. package/dist/skills/external-transport.d.ts.map +1 -0
  408. package/dist/skills/external-transport.js +30 -0
  409. package/dist/skills/external-transport.js.map +1 -0
  410. package/dist/skills/find.d.ts +16 -0
  411. package/dist/skills/find.d.ts.map +1 -0
  412. package/dist/skills/find.js +58 -0
  413. package/dist/skills/find.js.map +1 -0
  414. package/dist/skills/gap-detection.d.ts +23 -0
  415. package/dist/skills/gap-detection.d.ts.map +1 -0
  416. package/dist/skills/gap-detection.js +62 -0
  417. package/dist/skills/gap-detection.js.map +1 -0
  418. package/dist/skills/import-preparation.d.ts +4 -0
  419. package/dist/skills/import-preparation.d.ts.map +1 -0
  420. package/dist/skills/import-preparation.js +20 -0
  421. package/dist/skills/import-preparation.js.map +1 -0
  422. package/dist/skills/materialization-authority.d.ts +11 -0
  423. package/dist/skills/materialization-authority.d.ts.map +1 -0
  424. package/dist/skills/materialization-authority.js +92 -0
  425. package/dist/skills/materialization-authority.js.map +1 -0
  426. package/dist/skills/materialization-service.d.ts +22 -0
  427. package/dist/skills/materialization-service.d.ts.map +1 -0
  428. package/dist/skills/materialization-service.js +101 -0
  429. package/dist/skills/materialization-service.js.map +1 -0
  430. package/dist/skills/official-catalog.d.ts +31 -0
  431. package/dist/skills/official-catalog.d.ts.map +1 -0
  432. package/dist/skills/official-catalog.js +110 -0
  433. package/dist/skills/official-catalog.js.map +1 -0
  434. package/dist/skills/providers/schema.d.ts +30 -0
  435. package/dist/skills/providers/schema.d.ts.map +1 -0
  436. package/dist/skills/providers/schema.js +354 -0
  437. package/dist/skills/providers/schema.js.map +1 -0
  438. package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
  439. package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
  440. package/dist/skills/providers/skills-sh-compat.js +71 -0
  441. package/dist/skills/providers/skills-sh-compat.js.map +1 -0
  442. package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
  443. package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
  444. package/dist/skills/providers/skills-sh-v1.js +134 -0
  445. package/dist/skills/providers/skills-sh-v1.js.map +1 -0
  446. package/dist/skills/query-builder.d.ts +18 -0
  447. package/dist/skills/query-builder.d.ts.map +1 -0
  448. package/dist/skills/query-builder.js +93 -0
  449. package/dist/skills/query-builder.js.map +1 -0
  450. package/dist/skills/source/errors.d.ts +9 -0
  451. package/dist/skills/source/errors.d.ts.map +1 -0
  452. package/dist/skills/source/errors.js +15 -0
  453. package/dist/skills/source/errors.js.map +1 -0
  454. package/dist/skills/source/frontmatter.d.ts +9 -0
  455. package/dist/skills/source/frontmatter.d.ts.map +1 -0
  456. package/dist/skills/source/frontmatter.js +77 -0
  457. package/dist/skills/source/frontmatter.js.map +1 -0
  458. package/dist/skills/source/github-fetcher.d.ts +20 -0
  459. package/dist/skills/source/github-fetcher.d.ts.map +1 -0
  460. package/dist/skills/source/github-fetcher.js +292 -0
  461. package/dist/skills/source/github-fetcher.js.map +1 -0
  462. package/dist/skills/source/snapshot-validator.d.ts +28 -0
  463. package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
  464. package/dist/skills/source/snapshot-validator.js +186 -0
  465. package/dist/skills/source/snapshot-validator.js.map +1 -0
  466. package/dist/skills/store.d.ts +181 -0
  467. package/dist/skills/store.d.ts.map +1 -0
  468. package/dist/skills/store.js +1710 -0
  469. package/dist/skills/store.js.map +1 -0
  470. package/dist/skills/types.d.ts +169 -0
  471. package/dist/skills/types.d.ts.map +1 -0
  472. package/dist/skills/types.js +2 -0
  473. package/dist/skills/types.js.map +1 -0
  474. package/dist/web/i18n.d.ts +32 -0
  475. package/dist/web/i18n.d.ts.map +1 -1
  476. package/dist/web/i18n.js +128 -0
  477. package/dist/web/i18n.js.map +1 -1
  478. package/dist/web/server.d.ts.map +1 -1
  479. package/dist/web/server.js +386 -38
  480. package/dist/web/server.js.map +1 -1
  481. package/dist/web/ui.d.ts +4 -0
  482. package/dist/web/ui.d.ts.map +1 -1
  483. package/dist/web/ui.js +382 -6
  484. package/dist/web/ui.js.map +1 -1
  485. package/migrations/009_external_skill_discovery.sql +126 -0
  486. package/package.json +6 -3
  487. package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
  488. package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
  489. package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
  490. package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
  491. package/templates/AGENTS.md +8 -7
  492. package/dist/client/runtime-discovery.d.ts +0 -15
  493. package/dist/client/runtime-discovery.d.ts.map +0 -1
  494. package/dist/client/runtime-discovery.js +0 -45
  495. package/dist/client/runtime-discovery.js.map +0 -1
  496. package/dist/commands/call.d.ts +0 -7
  497. package/dist/commands/call.d.ts.map +0 -1
  498. package/dist/commands/call.js +0 -10
  499. package/dist/commands/call.js.map +0 -1
  500. package/dist/commands/link.d.ts +0 -6
  501. package/dist/commands/link.d.ts.map +0 -1
  502. package/dist/commands/link.js +0 -6
  503. package/dist/commands/link.js.map +0 -1
  504. package/dist/commands/promote.d.ts +0 -6
  505. package/dist/commands/promote.d.ts.map +0 -1
  506. package/dist/commands/promote.js +0 -6
  507. package/dist/commands/promote.js.map +0 -1
  508. package/dist/commands/read.d.ts +0 -6
  509. package/dist/commands/read.d.ts.map +0 -1
  510. package/dist/commands/read.js +0 -4
  511. package/dist/commands/read.js.map +0 -1
  512. package/dist/commands/recall.d.ts +0 -6
  513. package/dist/commands/recall.d.ts.map +0 -1
  514. package/dist/commands/recall.js +0 -4
  515. package/dist/commands/recall.js.map +0 -1
  516. package/dist/commands/record.d.ts +0 -6
  517. package/dist/commands/record.d.ts.map +0 -1
  518. package/dist/commands/record.js +0 -4
  519. package/dist/commands/record.js.map +0 -1
  520. package/dist/commands/search.d.ts +0 -6
  521. package/dist/commands/search.d.ts.map +0 -1
  522. package/dist/commands/search.js +0 -4
  523. package/dist/commands/search.js.map +0 -1
  524. package/dist/commands/supersede.d.ts +0 -6
  525. package/dist/commands/supersede.d.ts.map +0 -1
  526. package/dist/commands/supersede.js +0 -6
  527. package/dist/commands/supersede.js.map +0 -1
  528. package/dist/knowledge/sources.d.ts +0 -72
  529. package/dist/knowledge/sources.d.ts.map +0 -1
  530. package/dist/knowledge/sources.js +0 -388
  531. package/dist/knowledge/sources.js.map +0 -1
  532. package/dist/setup/opencode-evidence.d.ts +0 -37
  533. package/dist/setup/opencode-evidence.d.ts.map +0 -1
  534. package/dist/setup/opencode-evidence.js +0 -58
  535. package/dist/setup/opencode-evidence.js.map +0 -1
  536. package/dist/setup/opencode-loop-guard.d.ts +0 -9
  537. package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
  538. package/dist/setup/opencode-loop-guard.js +0 -248
  539. package/dist/setup/opencode-loop-guard.js.map +0 -1
@@ -1,21 +1,26 @@
1
- import { access, unlink } from 'node:fs/promises';
2
1
  import path from 'node:path';
2
+ import { mkdir, rmdir } from 'node:fs/promises';
3
3
  import { createInterface } from 'node:readline/promises';
4
4
  import { stdin, stdout } from 'node:process';
5
- import { atomicWriteText, readRegularFile } from '../agent-file/atomic-write.js';
6
- import { getClaudeInstructionsPath, getClaudeMcpConfigPath, getClaudeSkillsDirectory, getCodexConfigPath, getCodexInstructionsPath, getCodexSkillsDirectory, getGlobalDatabasePath, getHermesConfigPath, getHermesSkillsDirectory, getOpenCodeConfigDirectory, getOpenCodeInstructionsPath, getOpenCodeLoopGuardPath, getOpenCodeSkillsDirectory, } from '../config/paths.js';
5
+ import { atomicWriteTextIfUnchanged, assertAtomicCleanupComplete, AtomicCommittedMutationError, AtomicCommittedUnlinkError, assertFileExpectation, readDirectoryIdentity, readRegularFile, unlinkRegularFileIfUnchanged, } from '../agent-file/atomic-write.js';
6
+ import { getClaudeInstructionsPath, getClaudeMcpConfigPath, getClaudeSkillsDirectory, getCodexConfigPath, getCodexInstructionsPath, getCodexSkillsDirectory, getGlobalDatabasePath, getLegacyClaudePromptHookSettingsPath, getLegacyOpenCodeLoopGuardPath, getOpenCodeConfigDirectory, getOpenCodeInstructionsPath, getOpenCodeSkillsDirectory, resolveHermesProfilePaths, } from '../config/paths.js';
7
7
  import { initializeDatabase } from './init.js';
8
8
  import { openConnection } from '../db/connection.js';
9
9
  import { ensureGlobalWorkspace } from '../memory/workspaces.js';
10
10
  import { KiokukoError } from '../errors.js';
11
+ import { isSkillDiscoveryMode, normalizeSkillDiscoveryMode, SKILL_DISCOVERY_ENV } from '../skills/config.js';
11
12
  import { renderOpenCodeConfig } from '../setup/opencode-config.js';
12
- import { renderOpenCodeLoopGuard } from '../setup/opencode-loop-guard.js';
13
13
  import { renderCodexMcpConfig, renderGlobalInstructions } from '../setup/render.js';
14
14
  import { renderClaudeConfig } from '../setup/claude-config.js';
15
15
  import { renderHermesConfig } from '../setup/hermes-config.js';
16
16
  import { detectInstalledClients } from '../setup/client-detection.js';
17
- import { loadBundledStandardSkillFiles, renderStandardSkillFile, STANDARD_UI_SKILL_NAME, } from '../setup/standard-skills.js';
17
+ import { assertExactLegacyOpenCodeLoopGuard, cleanupLegacyClaudePromptHook, } from '../setup/legacy-client-cleanup.js';
18
+ import { loadBundledStandardSkillFiles, renderStandardSkillFile, } from '../setup/standard-skills.js';
18
19
  export const SETUP_CLIENTS = ['codex', 'opencode', 'claude', 'hermes'];
20
+ function setupPathJoin(options, ...segments) {
21
+ const platform = options.platform ?? process.platform;
22
+ return platform === 'win32' ? path.win32.join(...segments) : path.posix.join(...segments);
23
+ }
19
24
  export function parseSetupClients(value) {
20
25
  const clients = [...new Set(value.split(',').map((client) => client.trim()).filter(Boolean))];
21
26
  if (clients.length === 0 || clients.some((client) => !SETUP_CLIENTS.includes(client))) {
@@ -23,6 +28,12 @@ export function parseSetupClients(value) {
23
28
  }
24
29
  return clients;
25
30
  }
31
+ export function parseSetupSkillDiscoveryMode(value) {
32
+ if (!isSkillDiscoveryMode(value)) {
33
+ throw new KiokukoError('VALIDATION_ERROR', 'skill discovery must be off, official, or community');
34
+ }
35
+ return value;
36
+ }
26
37
  function setupClientLabel(client) {
27
38
  if (client === 'codex')
28
39
  return 'Codex';
@@ -32,92 +43,316 @@ function setupClientLabel(client) {
32
43
  return 'Claude Code';
33
44
  return 'Hermes Agent';
34
45
  }
46
+ async function askSetupClients(prompt, output, detected) {
47
+ const defaultSelection = detected.length === 0 ? 'none' : detected.join(',');
48
+ output.write('Select clients to configure (detected clients are preselected):\n');
49
+ for (const [index, client] of SETUP_CLIENTS.entries()) {
50
+ const checked = detected.includes(client) ? 'x' : ' ';
51
+ const status = detected.includes(client) ? 'detected' : 'not detected';
52
+ output.write(` ${index + 1}. [${checked}] ${setupClientLabel(client)} (${status})\n`);
53
+ }
54
+ output.write('Enter client names or numbers separated by commas. Press Enter to accept the checked clients; type none to skip all.\n');
55
+ while (true) {
56
+ const answer = (await prompt.question(`Clients [${defaultSelection}]: `)).trim();
57
+ if (answer.length === 0)
58
+ return detected;
59
+ if (/^(?:none|なし)$/iu.test(answer))
60
+ return [];
61
+ const selected = [];
62
+ let invalid = false;
63
+ for (const token of answer.split(',').map((value) => value.trim()).filter(Boolean)) {
64
+ const index = Number(token);
65
+ const indexedClient = Number.isInteger(index) && index >= 1 && index <= SETUP_CLIENTS.length
66
+ ? SETUP_CLIENTS[index - 1]
67
+ : undefined;
68
+ const client = indexedClient ?? token.toLowerCase();
69
+ if (!SETUP_CLIENTS.includes(client)) {
70
+ invalid = true;
71
+ break;
72
+ }
73
+ selected.push(client);
74
+ }
75
+ if (!invalid)
76
+ return [...new Set(selected)];
77
+ output.write(`Invalid selection. Choose names or numbers for: ${SETUP_CLIENTS.join(', ')}.\n`);
78
+ }
79
+ }
80
+ async function askCommunitySkillDiscovery(prompt, output) {
81
+ output.write('Official external Skill discovery is enabled by default and uses validated content only as untrusted references. It never installs or executes Skills.\n');
82
+ output.write('Community discovery can also use audited community Skills as untrusted references when relevant.\n');
83
+ const answer = (await prompt.question('Enable community Skill discovery? [y/N] ')).trim();
84
+ return /^(?:y|yes|はい)$/iu.test(answer) ? 'community' : 'official';
85
+ }
86
+ async function askReplaceConflictingMcp(prompt, output, client) {
87
+ const label = setupClientLabel(client);
88
+ output.write(`${label} already has a non-canonical or unmanaged Kiokuko MCP identity.\n`);
89
+ output.write('Kiokuko can remove that identity, install the managed configuration, and continue setup.\n');
90
+ const answer = (await prompt.question(`Replace the existing ${label} Kiokuko MCP identity and continue? [y/N] `)).trim();
91
+ return /^(?:y|yes|はい)$/iu.test(answer);
92
+ }
35
93
  /** Ask which supported clients should receive configuration in an interactive terminal. */
36
94
  export async function promptSetupClients(detected, options = {}) {
37
95
  const input = options.input ?? stdin;
38
96
  const output = options.output ?? stdout;
39
97
  const prompt = createInterface({ input, output });
40
- const defaultSelection = detected.length === 0 ? 'none' : detected.join(',');
41
98
  try {
42
- output.write('Select clients to configure (detected clients are preselected):\n');
43
- for (const [index, client] of SETUP_CLIENTS.entries()) {
44
- const checked = detected.includes(client) ? 'x' : ' ';
45
- const status = detected.includes(client) ? 'detected' : 'not detected';
46
- output.write(` ${index + 1}. [${checked}] ${setupClientLabel(client)} (${status})\n`);
47
- }
48
- output.write('Enter client names or numbers separated by commas. Press Enter to accept the checked clients; type none to skip all.\n');
49
- while (true) {
50
- const answer = (await prompt.question(`Clients [${defaultSelection}]: `)).trim();
51
- if (answer.length === 0)
52
- return detected;
53
- if (/^(?:none|なし)$/iu.test(answer))
54
- return [];
55
- const selected = [];
56
- let invalid = false;
57
- for (const token of answer.split(',').map((value) => value.trim()).filter(Boolean)) {
58
- const index = Number(token);
59
- const indexedClient = Number.isInteger(index) && index >= 1 && index <= SETUP_CLIENTS.length
60
- ? SETUP_CLIENTS[index - 1]
61
- : undefined;
62
- const client = indexedClient ?? token.toLowerCase();
63
- if (!SETUP_CLIENTS.includes(client)) {
64
- invalid = true;
65
- break;
66
- }
67
- selected.push(client);
68
- }
69
- if (!invalid)
70
- return [...new Set(selected)];
71
- output.write(`Invalid selection. Choose names or numbers for: ${SETUP_CLIENTS.join(', ')}.\n`);
72
- }
99
+ return await askSetupClients(prompt, output, detected);
73
100
  }
74
101
  finally {
75
102
  prompt.close();
76
103
  }
77
104
  }
78
- async function exists(filePath) {
105
+ /** Ask whether audited community Skill discovery should be enabled. */
106
+ export async function promptCommunitySkillDiscovery(options = {}) {
107
+ const input = options.input ?? stdin;
108
+ const output = options.output ?? stdout;
109
+ const prompt = createInterface({ input, output });
79
110
  try {
80
- await access(filePath);
81
- return true;
111
+ return await askCommunitySkillDiscovery(prompt, output);
82
112
  }
83
- catch (error) {
84
- if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
85
- return false;
86
- throw error;
113
+ finally {
114
+ prompt.close();
115
+ }
116
+ }
117
+ /** Ask before replacing a client Kiokuko MCP identity that setup does not own. */
118
+ export async function promptReplaceConflictingMcp(client, options = {}) {
119
+ const input = options.input ?? stdin;
120
+ const output = options.output ?? stdout;
121
+ const prompt = createInterface({ input, output });
122
+ try {
123
+ return await askReplaceConflictingMcp(prompt, output, client);
124
+ }
125
+ finally {
126
+ prompt.close();
127
+ }
128
+ }
129
+ function replacementClientSet(value) {
130
+ if (value === undefined)
131
+ return new Set();
132
+ if (!Array.isArray(value)
133
+ || value.some((client) => !SETUP_CLIENTS.includes(client))
134
+ || new Set(value).size !== value.length) {
135
+ throw new KiokukoError('VALIDATION_ERROR', `replaceConflictingMcpServers must be a unique subset of: ${SETUP_CLIENTS.join(', ')}`);
136
+ }
137
+ return new Set(value);
138
+ }
139
+ /** Ask both setup questions through one readline session so buffered input remains intact. */
140
+ export async function promptSetupConfiguration(detected, options = {}) {
141
+ const input = options.input ?? stdin;
142
+ const output = options.output ?? stdout;
143
+ const prompt = createInterface({ input, output });
144
+ try {
145
+ const clients = await askSetupClients(prompt, output, detected);
146
+ const skillDiscoveryMode = clients.length === 0
147
+ ? 'official'
148
+ : await askCommunitySkillDiscovery(prompt, output);
149
+ return { clients, skillDiscoveryMode };
150
+ }
151
+ finally {
152
+ prompt.close();
153
+ }
154
+ }
155
+ function sameFileIdentity(left, right) {
156
+ return left.device === right.device && left.inode === right.inode;
157
+ }
158
+ function setupDirectoryChanged(directoryPath) {
159
+ return new KiokukoError('CONFLICT', 'Setup directory changed after planning', { target: directoryPath });
160
+ }
161
+ function plannedDirectoryIdentity(directory) {
162
+ return directory.original ?? directory.created;
163
+ }
164
+ function directoryLineage(directory) {
165
+ const lineage = [];
166
+ let current = directory;
167
+ while (current !== undefined) {
168
+ lineage.push(current);
169
+ current = current.parent;
170
+ }
171
+ return lineage.reverse();
172
+ }
173
+ async function assertPlannedDirectory(directory) {
174
+ for (const planned of directoryLineage(directory)) {
175
+ const current = await readDirectoryIdentity(planned.path);
176
+ const expected = plannedDirectoryIdentity(planned);
177
+ if ((current === undefined) !== (expected === undefined)
178
+ || (current !== undefined && expected !== undefined && !sameFileIdentity(current, expected))) {
179
+ throw setupDirectoryChanged(planned.path);
180
+ }
181
+ }
182
+ }
183
+ async function planDirectory(planning, directoryPath) {
184
+ const resolved = path.resolve(directoryPath);
185
+ const existing = planning.directories.get(resolved);
186
+ if (existing !== undefined)
187
+ return existing;
188
+ const original = await readDirectoryIdentity(resolved);
189
+ const parentPath = path.dirname(resolved);
190
+ const parent = original !== undefined || parentPath === resolved
191
+ ? undefined
192
+ : await planDirectory(planning, parentPath);
193
+ const planned = {
194
+ path: resolved,
195
+ parent,
196
+ original,
197
+ created: undefined,
198
+ };
199
+ planning.directories.set(resolved, planned);
200
+ return planned;
201
+ }
202
+ async function readPlannedRegularFile(planning, filePath) {
203
+ const parentDirectory = await planDirectory(planning, path.dirname(filePath));
204
+ await assertPlannedDirectory(parentDirectory);
205
+ const snapshot = await readRegularFile(filePath);
206
+ await assertPlannedDirectory(parentDirectory);
207
+ return { parentDirectory, snapshot };
208
+ }
209
+ function errno(error) {
210
+ return error instanceof Error && 'code' in error
211
+ ? String(error.code)
212
+ : undefined;
213
+ }
214
+ async function preparePlannedDirectories(files, createdDirectories) {
215
+ const required = new Set();
216
+ for (const file of files) {
217
+ if (file.action === 'unchanged')
218
+ continue;
219
+ for (const directory of directoryLineage(file.parentDirectory))
220
+ required.add(directory);
221
+ }
222
+ const ordered = [...required].sort((left, right) => directoryLineage(left).length - directoryLineage(right).length);
223
+ for (const directory of ordered) {
224
+ const expected = plannedDirectoryIdentity(directory);
225
+ if (expected !== undefined) {
226
+ await assertPlannedDirectory(directory);
227
+ continue;
228
+ }
229
+ if (directory.parent === undefined) {
230
+ throw new KiokukoError('INTEGRITY_ERROR', 'Setup cannot create a missing filesystem root');
231
+ }
232
+ await assertPlannedDirectory(directory.parent);
233
+ if (await readDirectoryIdentity(directory.path) !== undefined) {
234
+ throw setupDirectoryChanged(directory.path);
235
+ }
236
+ try {
237
+ await mkdir(directory.path, { mode: 0o700 });
238
+ }
239
+ catch (error) {
240
+ if (errno(error) === 'EEXIST')
241
+ throw setupDirectoryChanged(directory.path);
242
+ throw error;
243
+ }
244
+ const created = await readDirectoryIdentity(directory.path);
245
+ if (created === undefined) {
246
+ throw new KiokukoError('INTEGRITY_ERROR', 'Setup directory disappeared immediately after creation', {
247
+ target: directory.path,
248
+ });
249
+ }
250
+ directory.created = created;
251
+ createdDirectories.push(directory);
252
+ await assertPlannedDirectory(directory);
87
253
  }
88
254
  }
89
- async function planFile(filePath, client, purpose, render) {
90
- const original = await readRegularFile(filePath);
255
+ async function removeCreatedDirectories(createdDirectories) {
256
+ const failures = [];
257
+ for (const directory of [...createdDirectories].reverse()) {
258
+ try {
259
+ await assertPlannedDirectory(directory);
260
+ await rmdir(directory.path);
261
+ if (await readDirectoryIdentity(directory.path) !== undefined) {
262
+ throw setupDirectoryChanged(directory.path);
263
+ }
264
+ directory.created = undefined;
265
+ if (directory.parent !== undefined)
266
+ await assertPlannedDirectory(directory.parent);
267
+ }
268
+ catch (error) {
269
+ failures.push(error);
270
+ }
271
+ }
272
+ return failures;
273
+ }
274
+ async function planFile(planning, filePath, client, purpose, render, mustRemainAbsent = []) {
275
+ const { parentDirectory, snapshot: original } = await readPlannedRegularFile(planning, filePath);
91
276
  const rendered = render(original?.content);
92
277
  const action = original === undefined
93
278
  ? 'created'
94
279
  : rendered.content === original.content ? 'unchanged' : 'updated';
95
280
  return {
96
281
  path: filePath,
282
+ parentDirectory,
97
283
  content: rendered.content,
98
284
  mode: original?.mode ?? 0o600,
99
- original: original?.content,
285
+ original,
286
+ ...(mustRemainAbsent.length === 0 ? {} : { mustRemainAbsent }),
100
287
  action,
101
288
  purpose,
102
289
  client,
290
+ report: true,
103
291
  };
104
292
  }
105
- async function openCodeConfigPath(options) {
293
+ async function planLegacyClaudeHookCleanup(planning, options) {
294
+ const filePath = getLegacyClaudePromptHookSettingsPath(options);
295
+ const { parentDirectory, snapshot: original } = await readPlannedRegularFile(planning, filePath);
296
+ const content = original === undefined ? undefined : cleanupLegacyClaudePromptHook(original.content);
297
+ const changed = original !== undefined && content !== original.content;
298
+ return {
299
+ path: filePath,
300
+ parentDirectory,
301
+ content,
302
+ mode: original?.mode ?? 0o600,
303
+ original,
304
+ action: changed ? 'updated' : 'unchanged',
305
+ purpose: 'legacy-cleanup',
306
+ client: 'claude',
307
+ report: changed,
308
+ };
309
+ }
310
+ async function planLegacyOpenCodeGuardCleanup(planning, options) {
311
+ const filePath = getLegacyOpenCodeLoopGuardPath(options);
312
+ const { parentDirectory, snapshot: original } = await readPlannedRegularFile(planning, filePath);
313
+ if (original !== undefined)
314
+ assertExactLegacyOpenCodeLoopGuard(original.content);
315
+ return {
316
+ path: filePath,
317
+ parentDirectory,
318
+ content: undefined,
319
+ mode: original?.mode ?? 0o600,
320
+ original,
321
+ action: original === undefined ? 'unchanged' : 'deleted',
322
+ purpose: 'legacy-cleanup',
323
+ client: 'opencode',
324
+ report: original !== undefined,
325
+ };
326
+ }
327
+ async function openCodeConfigPath(planning, options) {
106
328
  const directory = getOpenCodeConfigDirectory(options);
107
- const jsonc = path.join(directory, 'opencode.jsonc');
108
- if (await exists(jsonc))
109
- return jsonc;
110
- return path.join(directory, 'opencode.json');
329
+ const jsonc = setupPathJoin(options, directory, 'opencode.jsonc');
330
+ if ((await readPlannedRegularFile(planning, jsonc)).snapshot !== undefined) {
331
+ return { path: jsonc, mustRemainAbsent: [] };
332
+ }
333
+ return { path: setupPathJoin(options, directory, 'opencode.json'), mustRemainAbsent: [jsonc] };
111
334
  }
112
- async function restoreFiles(files) {
113
- for (const file of [...files].reverse()) {
114
- if (file.action === 'unchanged')
115
- continue;
116
- if (file.original === undefined)
117
- await unlink(file.path).catch(() => undefined);
118
- else
119
- await atomicWriteText(file.path, file.original, file.mode).catch(() => undefined);
335
+ async function restoreFiles(mutations, dependencies) {
336
+ const failures = [];
337
+ for (const mutation of [...mutations].reverse()) {
338
+ const { file, installed } = mutation;
339
+ try {
340
+ if (file.original === undefined) {
341
+ if (installed === undefined)
342
+ throw new KiokukoError('INTEGRITY_ERROR', 'Setup rollback record is invalid');
343
+ const outcome = await dependencies.unlinkRegularFileIfUnchanged(file.path, fileExpectation(file, installed, false));
344
+ assertAtomicCleanupComplete(outcome);
345
+ }
346
+ else {
347
+ const outcome = await dependencies.atomicWriteTextIfUnchanged(file.path, file.original.content, fileExpectation(file, installed, false), file.original.mode);
348
+ assertAtomicCleanupComplete(outcome);
349
+ }
350
+ }
351
+ catch (error) {
352
+ failures.push(error);
353
+ }
120
354
  }
355
+ return failures;
121
356
  }
122
357
  function setupNextStep(clients, standardSkills) {
123
358
  return clients.map((client) => {
@@ -130,55 +365,119 @@ function setupNextStep(clients, standardSkills) {
130
365
  return `Restart ${label} so it reloads global MCP and instruction configuration${standardSkills ? ' and standard skills' : ''}.`;
131
366
  }).join(' ');
132
367
  }
133
- async function standardSkillDirectory(client, options) {
368
+ async function standardSkillDirectory(client, options, hermesProfile) {
134
369
  if (client === 'codex')
135
370
  return getCodexSkillsDirectory(options);
136
371
  if (client === 'opencode')
137
372
  return getOpenCodeSkillsDirectory(options);
138
373
  if (client === 'claude')
139
374
  return getClaudeSkillsDirectory(options);
140
- return getHermesSkillsDirectory(options);
375
+ if (hermesProfile === undefined)
376
+ throw new KiokukoError('INTEGRITY_ERROR', 'Hermes profile was not bound during setup planning');
377
+ return hermesProfile.skillsDirectory;
378
+ }
379
+ function fileExpectation(file, expected, includeAlternatePaths = true) {
380
+ const expectedParentDirectory = plannedDirectoryIdentity(file.parentDirectory);
381
+ if (expectedParentDirectory === undefined) {
382
+ throw new KiokukoError('INTEGRITY_ERROR', 'Setup file parent was not created or bound before mutation', {
383
+ target: file.parentDirectory.path,
384
+ });
385
+ }
386
+ return {
387
+ expected,
388
+ expectedParentDirectory,
389
+ ...(includeAlternatePaths && file.mustRemainAbsent !== undefined
390
+ ? { mustRemainAbsent: file.mustRemainAbsent }
391
+ : {}),
392
+ };
141
393
  }
142
- export async function setupGlobalClients(options = {}) {
394
+ async function assertPlannedFile(file, expected) {
395
+ await assertPlannedDirectory(file.parentDirectory);
396
+ if (plannedDirectoryIdentity(file.parentDirectory) === undefined) {
397
+ if (expected !== undefined || await readRegularFile(file.path) !== undefined) {
398
+ throw setupDirectoryChanged(file.parentDirectory.path);
399
+ }
400
+ for (const absentPath of file.mustRemainAbsent ?? []) {
401
+ if (await readRegularFile(absentPath) !== undefined) {
402
+ throw new KiokukoError('CONFLICT', 'Setup target changed after planning', { target: absentPath });
403
+ }
404
+ }
405
+ }
406
+ else {
407
+ await assertFileExpectation(file.path, fileExpectation(file, expected));
408
+ }
409
+ await assertPlannedDirectory(file.parentDirectory);
410
+ }
411
+ async function assertPlannedFiles(files, applied = []) {
412
+ const installedByPath = new Map(applied.map((mutation) => [mutation.file.path, mutation.installed]));
413
+ for (const file of files) {
414
+ const expected = installedByPath.has(file.path) ? installedByPath.get(file.path) : file.original;
415
+ await assertPlannedFile(file, expected);
416
+ }
417
+ }
418
+ export async function setupGlobalClients(options = {}, dependencyOverrides = {}) {
419
+ const dependencies = {
420
+ atomicWriteTextIfUnchanged: dependencyOverrides.atomicWriteTextIfUnchanged ?? atomicWriteTextIfUnchanged,
421
+ unlinkRegularFileIfUnchanged: dependencyOverrides.unlinkRegularFileIfUnchanged ?? unlinkRegularFileIfUnchanged,
422
+ beforeCommit: dependencyOverrides.beforeCommit ?? (() => undefined),
423
+ openConnection: dependencyOverrides.openConnection ?? openConnection,
424
+ ensureGlobalWorkspace: dependencyOverrides.ensureGlobalWorkspace ?? ensureGlobalWorkspace,
425
+ };
143
426
  const pathEnvironment = {
144
427
  ...(options.platform === undefined ? {} : { platform: options.platform }),
145
428
  ...(options.env === undefined ? {} : { env: options.env }),
146
429
  };
430
+ if (options.skillDiscoveryMode !== undefined && !isSkillDiscoveryMode(options.skillDiscoveryMode)) {
431
+ throw new KiokukoError('VALIDATION_ERROR', 'skill discovery must be off, official, or community');
432
+ }
433
+ const replaceConflictingMcpServers = replacementClientSet(options.replaceConflictingMcpServers);
147
434
  const clients = options.clients ?? await detectInstalledClients(pathEnvironment);
148
- if (clients.some((client) => !SETUP_CLIENTS.includes(client))) {
435
+ if (!Array.isArray(clients) || clients.some((client) => !SETUP_CLIENTS.includes(client))) {
149
436
  throw new KiokukoError('VALIDATION_ERROR', `clients must be a subset of: ${SETUP_CLIENTS.join(', ')}`);
150
437
  }
151
438
  const command = options.command ?? 'kiokuko';
152
- if (command.trim().length === 0 || command.includes('\0'))
439
+ if (typeof command !== 'string' || command.trim().length === 0 || command.includes('\0')) {
153
440
  throw new KiokukoError('VALIDATION_ERROR', 'command must be a non-empty executable path or name');
441
+ }
154
442
  const databasePath = options.databasePath ?? getGlobalDatabasePath(pathEnvironment);
155
443
  const standardSkills = options.standardSkills ?? true;
444
+ const environment = options.env ?? process.env;
445
+ const environmentSkillDiscoveryMode = options.skillDiscoveryMode === undefined
446
+ && Object.prototype.hasOwnProperty.call(environment, SKILL_DISCOVERY_ENV)
447
+ ? normalizeSkillDiscoveryMode(environment[SKILL_DISCOVERY_ENV])
448
+ : undefined;
449
+ const skillDiscoveryMode = options.skillDiscoveryMode ?? environmentSkillDiscoveryMode;
156
450
  const files = [];
451
+ const planning = { directories: new Map() };
452
+ const hermesProfile = clients.includes('hermes')
453
+ ? await resolveHermesProfilePaths(pathEnvironment)
454
+ : undefined;
157
455
  if (clients.includes('codex')) {
158
- files.push(await planFile(getCodexConfigPath(pathEnvironment), 'codex', 'mcp-config', (existing) => renderCodexMcpConfig(existing ?? '', command)));
159
- files.push(await planFile(getCodexInstructionsPath(pathEnvironment), 'codex', 'instructions', (existing) => renderGlobalInstructions(existing ?? '')));
456
+ files.push(await planFile(planning, getCodexConfigPath(pathEnvironment), 'codex', 'mcp-config', (existing) => renderCodexMcpConfig(existing ?? '', command, skillDiscoveryMode, { replaceConflictingIdentity: replaceConflictingMcpServers.has('codex') })));
457
+ files.push(await planFile(planning, getCodexInstructionsPath(pathEnvironment), 'codex', 'instructions', (existing) => renderGlobalInstructions(existing ?? '')));
160
458
  }
161
459
  if (clients.includes('opencode')) {
162
- files.push(await planFile(await openCodeConfigPath(pathEnvironment), 'opencode', 'mcp-config', (existing) => renderOpenCodeConfig(existing, command)));
163
- files.push(await planFile(getOpenCodeInstructionsPath(pathEnvironment), 'opencode', 'instructions', (existing) => renderGlobalInstructions(existing ?? '')));
164
- files.push(await planFile(getOpenCodeLoopGuardPath(pathEnvironment), 'opencode', 'runtime-guard', (existing) => renderOpenCodeLoopGuard(existing, {
165
- ...(options.opencodeCapture === undefined ? {} : { captureProfile: options.opencodeCapture }),
166
- ...(options.opencodeMode === undefined ? {} : { mode: options.opencodeMode }),
167
- })));
460
+ const selectedConfig = await openCodeConfigPath(planning, pathEnvironment);
461
+ files.push(await planFile(planning, selectedConfig.path, 'opencode', 'mcp-config', (existing) => renderOpenCodeConfig(existing, command, skillDiscoveryMode, { replaceConflictingIdentity: replaceConflictingMcpServers.has('opencode') }), selectedConfig.mustRemainAbsent));
462
+ files.push(await planFile(planning, getOpenCodeInstructionsPath(pathEnvironment), 'opencode', 'instructions', (existing) => renderGlobalInstructions(existing ?? '')));
463
+ files.push(await planLegacyOpenCodeGuardCleanup(planning, pathEnvironment));
168
464
  }
169
465
  if (clients.includes('claude')) {
170
- files.push(await planFile(getClaudeMcpConfigPath(pathEnvironment), 'claude', 'mcp-config', (existing) => renderClaudeConfig(existing, command)));
171
- files.push(await planFile(getClaudeInstructionsPath(pathEnvironment), 'claude', 'instructions', (existing) => renderGlobalInstructions(existing ?? '')));
466
+ files.push(await planFile(planning, getClaudeMcpConfigPath(pathEnvironment), 'claude', 'mcp-config', (existing) => renderClaudeConfig(existing, command, skillDiscoveryMode, { replaceConflictingIdentity: replaceConflictingMcpServers.has('claude') })));
467
+ files.push(await planFile(planning, getClaudeInstructionsPath(pathEnvironment), 'claude', 'instructions', (existing) => renderGlobalInstructions(existing ?? '')));
468
+ files.push(await planLegacyClaudeHookCleanup(planning, pathEnvironment));
172
469
  }
173
470
  if (clients.includes('hermes')) {
174
- files.push(await planFile(await getHermesConfigPath(pathEnvironment), 'hermes', 'mcp-config', (existing) => renderHermesConfig(existing, command)));
471
+ if (hermesProfile === undefined)
472
+ throw new KiokukoError('INTEGRITY_ERROR', 'Hermes profile was not bound during setup planning');
473
+ files.push(await planFile(planning, hermesProfile.configPath, 'hermes', 'mcp-config', (existing) => renderHermesConfig(existing, command, skillDiscoveryMode, { replaceConflictingIdentity: replaceConflictingMcpServers.has('hermes') })));
175
474
  }
176
475
  if (standardSkills) {
177
476
  const bundledFiles = await loadBundledStandardSkillFiles();
178
477
  for (const client of clients) {
179
- const destination = path.join(await standardSkillDirectory(client, pathEnvironment), STANDARD_UI_SKILL_NAME);
478
+ const skillsDirectory = await standardSkillDirectory(client, pathEnvironment, hermesProfile);
180
479
  for (const bundled of bundledFiles) {
181
- files.push(await planFile(path.join(destination, bundled.relativePath), client, 'standard-skill', (existing) => renderStandardSkillFile(existing, bundled)));
480
+ files.push(await planFile(planning, setupPathJoin(pathEnvironment, skillsDirectory, bundled.skillName, bundled.relativePath), client, 'standard-skill', (existing) => renderStandardSkillFile(existing, bundled)));
182
481
  }
183
482
  }
184
483
  }
@@ -188,7 +487,9 @@ export async function setupGlobalClients(options = {}) {
188
487
  databaseAction: options.dryRun ? 'planned' : 'initialized',
189
488
  databaseBackupPath: null,
190
489
  appliedMigrations: [],
191
- files: files.map(({ path: filePath, action, purpose, client }) => ({ path: filePath, action, purpose, client })),
490
+ files: files
491
+ .filter((file) => file.report)
492
+ .map(({ path: filePath, action, purpose, client }) => ({ path: filePath, action, purpose, client })),
192
493
  standardSkills,
193
494
  dryRun: options.dryRun ?? false,
194
495
  nextStep: setupNextStep(clients, standardSkills),
@@ -201,24 +502,85 @@ export async function setupGlobalClients(options = {}) {
201
502
  });
202
503
  result.databaseBackupPath = initialized.backupPath;
203
504
  result.appliedMigrations = initialized.applied;
204
- const database = openConnection(databasePath);
505
+ const database = dependencies.openConnection(databasePath);
506
+ let workspaceInitializationFailed = false;
507
+ let workspaceInitializationError;
205
508
  try {
206
- ensureGlobalWorkspace(database);
509
+ dependencies.ensureGlobalWorkspace(database);
207
510
  }
208
- finally {
511
+ catch (error) {
512
+ workspaceInitializationFailed = true;
513
+ workspaceInitializationError = error;
514
+ }
515
+ try {
209
516
  database.close();
210
517
  }
211
- const written = [];
518
+ catch (closeError) {
519
+ if (workspaceInitializationFailed) {
520
+ throw new AggregateError([workspaceInitializationError, closeError], 'Global workspace initialization failed and closing the database connection also failed');
521
+ }
522
+ throw closeError;
523
+ }
524
+ if (workspaceInitializationFailed)
525
+ throw workspaceInitializationError;
526
+ const applied = [];
527
+ const createdDirectories = [];
212
528
  try {
529
+ await dependencies.beforeCommit();
530
+ await preparePlannedDirectories(files, createdDirectories);
531
+ await assertPlannedFiles(files);
213
532
  for (const file of files) {
214
533
  if (file.action === 'unchanged')
215
534
  continue;
216
- await atomicWriteText(file.path, file.content, file.mode);
217
- written.push(file);
535
+ // Record a committed mutation before inspecting its cleanup outcome so
536
+ // rollback never loses ownership of a target that already changed.
537
+ let installed;
538
+ if (file.action === 'deleted') {
539
+ if (file.original === undefined)
540
+ throw new KiokukoError('INTEGRITY_ERROR', 'Setup deletion plan is missing original content');
541
+ let outcome;
542
+ try {
543
+ outcome = await dependencies.unlinkRegularFileIfUnchanged(file.path, fileExpectation(file, file.original));
544
+ }
545
+ catch (error) {
546
+ if (error instanceof AtomicCommittedUnlinkError) {
547
+ applied.push({ file, installed: undefined });
548
+ }
549
+ throw error;
550
+ }
551
+ applied.push({ file, installed: undefined });
552
+ assertAtomicCleanupComplete(outcome);
553
+ }
554
+ else {
555
+ if (file.content === undefined)
556
+ throw new KiokukoError('INTEGRITY_ERROR', 'Setup file plan is missing rendered content');
557
+ let outcome;
558
+ try {
559
+ outcome = await dependencies.atomicWriteTextIfUnchanged(file.path, file.content, fileExpectation(file, file.original), file.mode);
560
+ }
561
+ catch (error) {
562
+ if (error instanceof AtomicCommittedMutationError) {
563
+ applied.push({ file, installed: error.outcome.installed });
564
+ }
565
+ else if (error instanceof AtomicCommittedUnlinkError) {
566
+ applied.push({ file, installed: undefined });
567
+ }
568
+ throw error;
569
+ }
570
+ installed = outcome.installed;
571
+ applied.push({ file, installed });
572
+ assertAtomicCleanupComplete(outcome);
573
+ }
218
574
  }
575
+ await assertPlannedFiles(files, applied);
219
576
  }
220
577
  catch (error) {
221
- await restoreFiles(written);
578
+ const restorationFailures = await restoreFiles(applied, dependencies);
579
+ const directoryRestorationFailures = await removeCreatedDirectories(createdDirectories);
580
+ const failures = [...restorationFailures, ...directoryRestorationFailures];
581
+ if (failures.length > 0) {
582
+ throw new AggregateError([error, ...failures], 'Setup failed and filesystem restoration also failed');
583
+ }
222
584
  throw error;
223
585
  }
224
586
  return result;