@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
package/dist/cli.js CHANGED
@@ -1,5 +1,7 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { createRequire } from 'node:module';
1
+ import { constants as fsConstants } from 'node:fs';
2
+ import { open } from 'node:fs/promises';
3
+ import { TextDecoder } from 'node:util';
4
+ import { isProxy } from 'node:util/types';
3
5
  import { Command, CommanderError } from 'commander';
4
6
  import { initializeDatabase } from './commands/init.js';
5
7
  import { useRepository } from './commands/use.js';
@@ -19,41 +21,154 @@ import { startWebServer } from './web/server.js';
19
21
  import { registerServerCommands } from './commands/server.js';
20
22
  import { registerAgentCommand } from './commands/agent.js';
21
23
  import { registerLedgerCommands } from './commands/ledger.js';
22
- import { answerAkinator, getAkinatorContext, startAkinator } from './akinator/orchestrator.js';
23
- import { parseSetupClients, promptSetupClients, setupGlobalClients } from './commands/setup.js';
24
+ import { answerAkinator, startAkinator } from './akinator/orchestrator.js';
25
+ import { parseSetupClients, parseSetupSkillDiscoveryMode, promptCommunitySkillDiscovery, promptReplaceConflictingMcp, promptSetupClients, promptSetupConfiguration, setupGlobalClients, } from './commands/setup.js';
26
+ import { setupMcpIdentityConflictClient } from './setup/mcp-conflict.js';
24
27
  import { runMcpServer } from './mcp/server.js';
25
28
  import { runCuratorCommand } from './commands/curator.js';
26
29
  import { globalizeCuratorCandidate } from './memory/curator.js';
27
30
  import { detectInstalledClients } from './setup/client-detection.js';
28
- const packageMetadata = createRequire(import.meta.url)('../package.json');
29
- if (typeof packageMetadata.version !== 'string' || packageMetadata.version.length === 0) {
30
- throw new Error('Kiokuko package version is unavailable');
31
+ import { registerSkillsCommands } from './commands/skills.js';
32
+ import { normalizeSkillDiscoveryMode, SKILL_DISCOVERY_ENV } from './skills/config.js';
33
+ import { PACKAGE_VERSION } from './package-version.js';
34
+ import { parseStrictJson } from './setup/strict-json.js';
35
+ import { validateRecordInput } from './serialization/validate.js';
36
+ const MAX_CLI_JSON_INPUT_BYTES = 2 * 1024 * 1024;
37
+ const MAX_CALL_PATH_BYTES = 4 * 1024;
38
+ const CONTROL_CHARACTERS = /\p{Cc}/u;
39
+ function invalidJsonInput() {
40
+ return new KiokukoError('VALIDATION_ERROR', 'Input is not valid JSON with unique keys');
41
+ }
42
+ async function readBoundedStdin() {
43
+ if (process.stdin.readableEncoding !== null || process.stdin.readableDidRead) {
44
+ throw invalidJsonInput();
45
+ }
46
+ const chunks = [];
47
+ let size = 0;
48
+ for await (const chunk of process.stdin) {
49
+ if (!Buffer.isBuffer(chunk))
50
+ throw invalidJsonInput();
51
+ const bytes = chunk;
52
+ size += bytes.byteLength;
53
+ if (size > MAX_CLI_JSON_INPUT_BYTES)
54
+ throw invalidJsonInput();
55
+ chunks.push(bytes);
56
+ }
57
+ return Buffer.concat(chunks);
58
+ }
59
+ function filesystemErrorCode(error) {
60
+ if ((typeof error !== 'object' && typeof error !== 'function') || error === null || isProxy(error)) {
61
+ return undefined;
62
+ }
63
+ const descriptor = Object.getOwnPropertyDescriptor(error, 'code');
64
+ return descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string'
65
+ ? descriptor.value
66
+ : undefined;
67
+ }
68
+ async function readBoundedJsonFile(filePath) {
69
+ let handle;
70
+ try {
71
+ handle = await open(filePath, fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
72
+ }
73
+ catch (error) {
74
+ if (filesystemErrorCode(error) === 'ENOENT' || filesystemErrorCode(error) === 'ENOTDIR') {
75
+ throw new KiokukoError('NOT_FOUND', 'JSON input file does not exist');
76
+ }
77
+ throw error;
78
+ }
79
+ let result;
80
+ let operationFailed = false;
81
+ let operationError;
82
+ try {
83
+ const initial = await handle.stat({ bigint: true });
84
+ if (!initial.isFile()) {
85
+ throw invalidJsonInput();
86
+ }
87
+ if (initial.size < 0n || initial.size > BigInt(MAX_CLI_JSON_INPUT_BYTES)) {
88
+ throw invalidJsonInput();
89
+ }
90
+ const expectedSize = Number(initial.size);
91
+ const bytes = Buffer.allocUnsafe(expectedSize + 1);
92
+ let offset = 0;
93
+ while (offset < bytes.byteLength) {
94
+ const read = await handle.read(bytes, offset, bytes.byteLength - offset, offset);
95
+ if (read.bytesRead === 0)
96
+ break;
97
+ offset += read.bytesRead;
98
+ }
99
+ const final = await handle.stat({ bigint: true });
100
+ if (offset !== expectedSize
101
+ || final.size !== initial.size
102
+ || final.dev !== initial.dev
103
+ || final.ino !== initial.ino
104
+ || final.mtimeNs !== initial.mtimeNs
105
+ || final.ctimeNs !== initial.ctimeNs) {
106
+ throw new KiokukoError('CONFLICT', 'JSON input file changed while it was being read');
107
+ }
108
+ result = bytes.subarray(0, offset);
109
+ }
110
+ catch (error) {
111
+ operationFailed = true;
112
+ operationError = error;
113
+ }
114
+ try {
115
+ await handle.close();
116
+ }
117
+ catch (closeError) {
118
+ if (operationFailed) {
119
+ throw new AggregateError([operationError, closeError], 'JSON input read failed and its file descriptor could not be closed');
120
+ }
121
+ throw new AggregateError([closeError], 'JSON input was read, but its file descriptor could not be closed');
122
+ }
123
+ if (operationFailed) {
124
+ if (operationError instanceof KiokukoError && operationError.code === 'VALIDATION_ERROR') {
125
+ throw operationError;
126
+ }
127
+ throw operationError;
128
+ }
129
+ if (result === undefined)
130
+ throw invalidJsonInput();
131
+ return result;
31
132
  }
32
- const packageVersion = packageMetadata.version;
33
133
  async function readJsonInput(filePath) {
34
- const text = filePath === '-' ? await new Promise((resolve, reject) => {
35
- let value = '';
36
- process.stdin.setEncoding('utf8');
37
- process.stdin.on('data', (chunk) => { value += chunk; });
38
- process.stdin.on('end', () => resolve(value));
39
- process.stdin.on('error', reject);
40
- }) : await readFile(filePath, 'utf8');
134
+ const bytes = filePath === '-' ? await readBoundedStdin() : await readBoundedJsonFile(filePath);
135
+ let text;
41
136
  try {
42
- return JSON.parse(text);
137
+ text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
43
138
  }
44
139
  catch {
45
- throw new KiokukoError('VALIDATION_ERROR', 'Input is not valid JSON');
140
+ throw invalidJsonInput();
46
141
  }
142
+ return parseStrictJson(text, { allowTrailingComma: false, disallowComments: true, allowEmptyContent: false }, 'Input is not valid JSON with unique keys');
47
143
  }
48
144
  async function withDatabase(operation) {
49
145
  const result = await initializeDatabase();
50
146
  const database = openConnection(result.databasePath);
147
+ let operationResult;
148
+ let operationFailed = false;
149
+ let operationError;
51
150
  try {
52
- return await operation(database);
151
+ operationResult = { value: await operation(database) };
53
152
  }
54
- finally {
153
+ catch (error) {
154
+ operationFailed = true;
155
+ operationError = error;
156
+ }
157
+ try {
55
158
  database.close();
56
159
  }
160
+ catch (closeError) {
161
+ if (operationFailed) {
162
+ throw new AggregateError([operationError, closeError], 'Database operation failed and closing its connection also failed');
163
+ }
164
+ throw new AggregateError([closeError], 'Database operation completed, but closing its connection failed');
165
+ }
166
+ if (operationFailed)
167
+ throw operationError;
168
+ if (operationResult === undefined) {
169
+ throw new KiokukoError('INTEGRITY_ERROR', 'Database operation produced no result');
170
+ }
171
+ return operationResult.value;
57
172
  }
58
173
  function emit(value) {
59
174
  process.stdout.write(`${JSON.stringify(value)}\n`);
@@ -76,7 +191,7 @@ function addWorkspaceOptions(command) {
76
191
  return command.option('--workspace <name>', 'Workspace name').option('--json', 'Emit a JSON response');
77
192
  }
78
193
  function configureRecallCommand(command) {
79
- const recall = addWorkspaceOptions(command.description('Recall relevant memory entries').argument('<query>'))
194
+ const recall = addWorkspaceOptions(command.description('Human/operator management: recall relevant memory entries').argument('<query>'))
80
195
  .option('--limit <number>', 'Maximum entries', '5').option('--max-chars <number>', 'Context character budget', '8000')
81
196
  .option('--scope <scope>', 'auto, project, ecosystem, or global', 'auto').option('--cwd <path>', 'Repository path used for scoped recall');
82
197
  recall.action(async (query, options) => {
@@ -100,112 +215,376 @@ function configureRecallCommand(command) {
100
215
  });
101
216
  return recall;
102
217
  }
103
- async function dispatchRequest(request) {
104
- if (typeof request !== 'object' || request === null || Array.isArray(request))
105
- throw new KiokukoError('VALIDATION_ERROR', 'Request must be a JSON object');
106
- const value = request;
107
- if (value.apiVersion !== '1')
218
+ const CALL_OPERATIONS = [
219
+ 'init',
220
+ 'use',
221
+ 'record',
222
+ 'curator',
223
+ 'curator_globalize',
224
+ 'guide_start',
225
+ 'guide_answer',
226
+ 'promote',
227
+ 'supersede',
228
+ 'link',
229
+ 'purge',
230
+ 'export',
231
+ 'import',
232
+ 'backup',
233
+ 'doctor',
234
+ ];
235
+ const SUPPORTED_CALL_OPERATIONS = new Set(CALL_OPERATIONS);
236
+ function snapshotPlainJsonObject(value, message) {
237
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
238
+ throw new KiokukoError('VALIDATION_ERROR', message);
239
+ }
240
+ const prototype = Object.getPrototypeOf(value);
241
+ if (prototype !== Object.prototype && prototype !== null) {
242
+ throw new KiokukoError('VALIDATION_ERROR', message);
243
+ }
244
+ const result = Object.create(null);
245
+ for (const key of Reflect.ownKeys(value)) {
246
+ if (typeof key !== 'string')
247
+ throw new KiokukoError('VALIDATION_ERROR', message);
248
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
249
+ if (descriptor === undefined || !('value' in descriptor) || descriptor.enumerable !== true) {
250
+ throw new KiokukoError('VALIDATION_ERROR', message);
251
+ }
252
+ Object.defineProperty(result, key, {
253
+ value: descriptor.value,
254
+ enumerable: true,
255
+ writable: true,
256
+ configurable: true,
257
+ });
258
+ }
259
+ return result;
260
+ }
261
+ function assertExactCallArguments(args, operation, allowed, required = []) {
262
+ const allowedFields = new Set(allowed);
263
+ for (const field of Object.keys(args)) {
264
+ if (!allowedFields.has(field)) {
265
+ throw new KiokukoError('VALIDATION_ERROR', `Unknown ${operation} argument: ${field}`);
266
+ }
267
+ }
268
+ for (const field of required) {
269
+ if (!Object.hasOwn(args, field)) {
270
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} is required`);
271
+ }
272
+ }
273
+ }
274
+ function requiredStringArgument(args, operation, field) {
275
+ const value = args[field];
276
+ if (typeof value !== 'string' || value.trim().length === 0) {
277
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a non-empty string`);
278
+ }
279
+ return value;
280
+ }
281
+ function optionalStringArgument(args, operation, field) {
282
+ return Object.hasOwn(args, field) ? requiredStringArgument(args, operation, field) : undefined;
283
+ }
284
+ function requiredPathArgument(args, operation, field) {
285
+ const value = requiredStringArgument(args, operation, field);
286
+ if (CONTROL_CHARACTERS.test(value) || Buffer.byteLength(value, 'utf8') > MAX_CALL_PATH_BYTES) {
287
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a bounded path without control characters`);
288
+ }
289
+ return value;
290
+ }
291
+ function optionalPathArgument(args, operation, field) {
292
+ return Object.hasOwn(args, field) ? requiredPathArgument(args, operation, field) : undefined;
293
+ }
294
+ function requiredBooleanArgument(args, operation, field) {
295
+ const value = args[field];
296
+ if (typeof value !== 'boolean') {
297
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a boolean`);
298
+ }
299
+ return value;
300
+ }
301
+ function optionalBooleanArgument(args, operation, field) {
302
+ return Object.hasOwn(args, field) ? requiredBooleanArgument(args, operation, field) : undefined;
303
+ }
304
+ function requiredPositiveIntegerArgument(args, operation, field) {
305
+ const value = args[field];
306
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) {
307
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a positive integer`);
308
+ }
309
+ return value;
310
+ }
311
+ function validateUseCallArguments(args) {
312
+ const operation = 'use';
313
+ assertExactCallArguments(args, operation, [
314
+ 'cwd',
315
+ 'root',
316
+ 'workspace',
317
+ 'agentFile',
318
+ 'dryRun',
319
+ 'noAgentFile',
320
+ 'forceRebind',
321
+ 'allowDirectory',
322
+ 'databasePath',
323
+ 'migrationsDirectory',
324
+ 'repositoryId',
325
+ ]);
326
+ const result = {};
327
+ const cwd = optionalPathArgument(args, operation, 'cwd');
328
+ const root = optionalPathArgument(args, operation, 'root');
329
+ const workspace = optionalStringArgument(args, operation, 'workspace');
330
+ const agentFile = optionalPathArgument(args, operation, 'agentFile');
331
+ const databasePath = optionalPathArgument(args, operation, 'databasePath');
332
+ const migrationsDirectory = optionalPathArgument(args, operation, 'migrationsDirectory');
333
+ const repositoryId = optionalStringArgument(args, operation, 'repositoryId');
334
+ const dryRun = optionalBooleanArgument(args, operation, 'dryRun');
335
+ const noAgentFile = optionalBooleanArgument(args, operation, 'noAgentFile');
336
+ const forceRebind = optionalBooleanArgument(args, operation, 'forceRebind');
337
+ const allowDirectory = optionalBooleanArgument(args, operation, 'allowDirectory');
338
+ if (cwd !== undefined)
339
+ result.cwd = cwd;
340
+ if (root !== undefined)
341
+ result.root = root;
342
+ if (workspace !== undefined)
343
+ result.workspace = workspace;
344
+ if (agentFile !== undefined)
345
+ result.agentFile = agentFile;
346
+ if (databasePath !== undefined)
347
+ result.databasePath = databasePath;
348
+ if (migrationsDirectory !== undefined)
349
+ result.migrationsDirectory = migrationsDirectory;
350
+ if (repositoryId !== undefined)
351
+ result.repositoryId = repositoryId;
352
+ if (dryRun !== undefined)
353
+ result.dryRun = dryRun;
354
+ if (noAgentFile !== undefined)
355
+ result.noAgentFile = noAgentFile;
356
+ if (forceRebind !== undefined)
357
+ result.forceRebind = forceRebind;
358
+ if (allowDirectory !== undefined)
359
+ result.allowDirectory = allowDirectory;
360
+ return result;
361
+ }
362
+ function validateRecordCallArguments(args) {
363
+ return validateRecordInput(args);
364
+ }
365
+ function validateCuratorCallArguments(args) {
366
+ const operation = 'curator';
367
+ assertExactCallArguments(args, operation, ['workspace', 'cwd', 'limit', 'entryId', 'yes']);
368
+ const workspace = optionalStringArgument(args, operation, 'workspace');
369
+ const cwd = optionalPathArgument(args, operation, 'cwd');
370
+ const entryId = optionalStringArgument(args, operation, 'entryId');
371
+ const yes = optionalBooleanArgument(args, operation, 'yes');
372
+ const limit = Object.hasOwn(args, 'limit')
373
+ ? requiredPositiveIntegerArgument(args, operation, 'limit')
374
+ : undefined;
375
+ if (limit !== undefined && limit > 50) {
376
+ throw new KiokukoError('VALIDATION_ERROR', 'curator.limit must be an integer between 1 and 50');
377
+ }
378
+ return {
379
+ ...(workspace === undefined ? {} : { workspace }),
380
+ ...(cwd === undefined ? {} : { cwd }),
381
+ ...(limit === undefined ? {} : { limit }),
382
+ ...(entryId === undefined ? {} : { entryId }),
383
+ ...(yes === undefined ? {} : { yes }),
384
+ };
385
+ }
386
+ function validateCuratorGlobalizeCallArguments(args) {
387
+ const operation = 'curator_globalize';
388
+ assertExactCallArguments(args, operation, ['workspace', 'entryId', 'expectedRevision', 'actor'], ['workspace', 'entryId', 'expectedRevision']);
389
+ const actor = optionalStringArgument(args, operation, 'actor');
390
+ return {
391
+ workspace: requiredStringArgument(args, operation, 'workspace'),
392
+ entryId: requiredStringArgument(args, operation, 'entryId'),
393
+ expectedRevision: requiredPositiveIntegerArgument(args, operation, 'expectedRevision'),
394
+ ...(actor === undefined ? {} : { actor }),
395
+ };
396
+ }
397
+ function validateGuideStartCallArguments(args) {
398
+ const operation = 'guide_start';
399
+ assertExactCallArguments(args, operation, ['workspace', 'task'], ['workspace', 'task']);
400
+ return {
401
+ workspace: requiredStringArgument(args, operation, 'workspace'),
402
+ task: requiredStringArgument(args, operation, 'task'),
403
+ };
404
+ }
405
+ function validateGuideAnswerCallArguments(args) {
406
+ const operation = 'guide_answer';
407
+ assertExactCallArguments(args, operation, ['workspace', 'sessionId', 'questionId', 'value'], ['workspace', 'sessionId', 'questionId', 'value']);
408
+ const questionId = requiredStringArgument(args, operation, 'questionId');
409
+ if (!['taskType', 'target', 'expected', 'constraints'].includes(questionId)) {
410
+ throw new KiokukoError('VALIDATION_ERROR', 'guide_answer.questionId is unsupported');
411
+ }
412
+ return {
413
+ workspace: requiredStringArgument(args, operation, 'workspace'),
414
+ sessionId: requiredStringArgument(args, operation, 'sessionId'),
415
+ questionId: questionId,
416
+ value: requiredStringArgument(args, operation, 'value'),
417
+ };
418
+ }
419
+ function validatePromoteCallArguments(args) {
420
+ const operation = 'promote';
421
+ assertExactCallArguments(args, operation, ['workspace', 'entryId', 'expectedRevision'], ['workspace', 'entryId', 'expectedRevision']);
422
+ return {
423
+ workspace: requiredStringArgument(args, operation, 'workspace'),
424
+ entryId: requiredStringArgument(args, operation, 'entryId'),
425
+ expectedRevision: requiredPositiveIntegerArgument(args, operation, 'expectedRevision'),
426
+ };
427
+ }
428
+ function validateSupersedeCallArguments(args) {
429
+ const operation = 'supersede';
430
+ assertExactCallArguments(args, operation, ['workspace', 'oldEntryId', 'replacementEntryId', 'expectedRevision'], ['workspace', 'oldEntryId', 'replacementEntryId', 'expectedRevision']);
431
+ return {
432
+ workspace: requiredStringArgument(args, operation, 'workspace'),
433
+ oldEntryId: requiredStringArgument(args, operation, 'oldEntryId'),
434
+ replacementEntryId: requiredStringArgument(args, operation, 'replacementEntryId'),
435
+ expectedRevision: requiredPositiveIntegerArgument(args, operation, 'expectedRevision'),
436
+ };
437
+ }
438
+ function validateLinkCallArguments(args) {
439
+ const operation = 'link';
440
+ assertExactCallArguments(args, operation, ['workspace', 'fromEntryId', 'toEntryId', 'relation', 'actor', 'now'], ['workspace', 'fromEntryId', 'toEntryId', 'relation']);
441
+ const relation = requiredStringArgument(args, operation, 'relation');
442
+ if (!['supports', 'contradicts', 'derived_from', 'related_to'].includes(relation)) {
443
+ throw new KiokukoError('VALIDATION_ERROR', 'link.relation is unsupported');
444
+ }
445
+ const actor = optionalStringArgument(args, operation, 'actor');
446
+ const now = optionalStringArgument(args, operation, 'now');
447
+ return {
448
+ workspace: requiredStringArgument(args, operation, 'workspace'),
449
+ fromEntryId: requiredStringArgument(args, operation, 'fromEntryId'),
450
+ toEntryId: requiredStringArgument(args, operation, 'toEntryId'),
451
+ relation: relation,
452
+ ...(actor === undefined ? {} : { actor }),
453
+ ...(now === undefined ? {} : { now }),
454
+ };
455
+ }
456
+ function validatePurgeCallArguments(args) {
457
+ const operation = 'purge';
458
+ assertExactCallArguments(args, operation, ['workspace', 'entryId', 'confirm'], ['workspace', 'entryId', 'confirm']);
459
+ return {
460
+ workspace: requiredStringArgument(args, operation, 'workspace'),
461
+ entryId: requiredStringArgument(args, operation, 'entryId'),
462
+ confirm: requiredBooleanArgument(args, operation, 'confirm'),
463
+ };
464
+ }
465
+ function parseCallRequest(request) {
466
+ const value = snapshotPlainJsonObject(request, 'Request must be a JSON object');
467
+ const fields = Object.keys(value).sort();
468
+ if (fields.length !== 3
469
+ || fields[0] !== 'apiVersion'
470
+ || fields[1] !== 'arguments'
471
+ || fields[2] !== 'operation') {
472
+ throw new KiokukoError('VALIDATION_ERROR', 'Request must contain exactly apiVersion, operation, and arguments');
473
+ }
474
+ if (value.apiVersion !== '1') {
108
475
  throw new KiokukoError('VALIDATION_ERROR', 'apiVersion must be "1"');
109
- if (typeof value.operation !== 'string' || value.operation.length === 0)
476
+ }
477
+ if (typeof value.operation !== 'string' || value.operation.length === 0) {
110
478
  throw new KiokukoError('VALIDATION_ERROR', 'operation must be a non-empty string');
111
- const args = typeof value.arguments === 'object' && value.arguments !== null && !Array.isArray(value.arguments) ? value.arguments : {};
112
- const operation = value.operation;
113
- if (operation === 'init')
479
+ }
480
+ const args = snapshotPlainJsonObject(value.arguments, 'arguments must be a JSON object');
481
+ if (!SUPPORTED_CALL_OPERATIONS.has(value.operation)) {
482
+ throw new KiokukoError('VALIDATION_ERROR', `Unknown operation: ${value.operation}`);
483
+ }
484
+ return {
485
+ apiVersion: '1',
486
+ operation: value.operation,
487
+ arguments: args,
488
+ };
489
+ }
490
+ async function dispatchRequest(request) {
491
+ const args = request.arguments;
492
+ const operation = request.operation;
493
+ if (operation === 'init') {
494
+ assertExactCallArguments(args, operation, []);
114
495
  return initializeDatabase();
496
+ }
115
497
  if (operation === 'use')
116
- return useRepository(args);
117
- if (operation === 'record')
118
- return withDatabase((database) => recordEntry(database, args));
119
- if (operation === 'read')
120
- return withDatabase((database) => readEntry(database, { workspace: String(args.workspace ?? ''), entryId: String(args.entryId ?? '') }));
121
- if (operation === 'search')
122
- return withDatabase((database) => searchEntries(database, args));
123
- if (operation === 'recall') {
124
- if (typeof args.scope === 'string' || typeof args.cwd === 'string' || args.workspace === undefined) {
125
- return withDatabase((database) => recallScopedMemory(database, {
126
- query: String(args.query ?? ''),
127
- scope: String(args.scope ?? 'auto'),
128
- ...(typeof args.limit === 'number' ? { limit: args.limit } : {}),
129
- ...(typeof args.maxChars === 'number' ? { maxChars: args.maxChars } : {}),
130
- ...(typeof args.cwd === 'string' ? { cwd: args.cwd } : {}),
131
- }));
132
- }
133
- return withDatabase((database) => recallEntries(database, args));
134
- }
135
- if (operation === 'curator')
136
- return withDatabase((database) => runCuratorCommand(database, {
137
- ...(typeof args.workspace === 'string' ? { workspace: args.workspace } : {}),
138
- ...(typeof args.cwd === 'string' ? { cwd: args.cwd } : {}),
139
- ...(typeof args.limit === 'number' ? { limit: args.limit } : {}),
140
- ...(typeof args.entryId === 'string' ? { entryId: args.entryId } : {}),
141
- yes: args.yes === true,
142
- json: true,
143
- }));
144
- if (operation === 'curator_globalize')
145
- return withDatabase((database) => globalizeCuratorCandidate(database, {
146
- workspace: String(args.workspace ?? ''),
147
- entryId: String(args.entryId ?? ''),
148
- expectedRevision: Number(args.expectedRevision),
149
- ...(typeof args.actor === 'string' ? { actor: args.actor } : {}),
150
- }));
151
- if (operation === 'guide_start')
152
- return withDatabase((database) => startAkinator(database, {
153
- workspace: String(args.workspace ?? ''),
154
- task: String(args.task ?? ''),
155
- }));
156
- if (operation === 'guide_answer')
157
- return withDatabase((database) => answerAkinator(database, {
158
- workspace: String(args.workspace ?? ''),
159
- sessionId: String(args.sessionId ?? ''),
160
- questionId: String(args.questionId ?? ''),
161
- value: String(args.value ?? ''),
162
- }));
163
- if (operation === 'guide_context')
164
- return withDatabase((database) => getAkinatorContext(database, {
165
- workspace: String(args.workspace ?? ''),
166
- sessionId: String(args.sessionId ?? ''),
167
- }));
168
- if (operation === 'promote')
169
- return withDatabase((database) => promoteEntry(database, { workspace: String(args.workspace ?? ''), entryId: String(args.entryId ?? ''), expectedRevision: Number(args.expectedRevision) }));
170
- if (operation === 'supersede')
171
- return withDatabase((database) => supersedeEntry(database, { workspace: String(args.workspace ?? ''), oldEntryId: String(args.oldEntryId ?? ''), replacementEntryId: String(args.replacementEntryId ?? ''), expectedRevision: Number(args.expectedRevision) }));
172
- if (operation === 'link')
173
- return withDatabase((database) => { linkEntries(database, args); return { linked: true }; });
174
- if (operation === 'purge')
175
- return withDatabase((database) => { purgeEntry(database, { workspace: String(args.workspace ?? ''), entryId: String(args.entryId ?? ''), confirm: args.confirm === true }); return { purged: true }; });
498
+ return useRepository(validateUseCallArguments(args));
499
+ if (operation === 'record') {
500
+ const input = validateRecordCallArguments(args);
501
+ return withDatabase((database) => recordEntry(database, input));
502
+ }
503
+ if (operation === 'curator') {
504
+ const input = validateCuratorCallArguments(args);
505
+ return withDatabase((database) => runCuratorCommand(database, { ...input, json: true }));
506
+ }
507
+ if (operation === 'curator_globalize') {
508
+ const input = validateCuratorGlobalizeCallArguments(args);
509
+ return withDatabase((database) => globalizeCuratorCandidate(database, input));
510
+ }
511
+ if (operation === 'guide_start') {
512
+ const input = validateGuideStartCallArguments(args);
513
+ return withDatabase((database) => startAkinator(database, input));
514
+ }
515
+ if (operation === 'guide_answer') {
516
+ const input = validateGuideAnswerCallArguments(args);
517
+ return withDatabase((database) => answerAkinator(database, input));
518
+ }
519
+ if (operation === 'promote') {
520
+ const input = validatePromoteCallArguments(args);
521
+ return withDatabase((database) => promoteEntry(database, input));
522
+ }
523
+ if (operation === 'supersede') {
524
+ const input = validateSupersedeCallArguments(args);
525
+ return withDatabase((database) => supersedeEntry(database, input));
526
+ }
527
+ if (operation === 'link') {
528
+ const input = validateLinkCallArguments(args);
529
+ return withDatabase((database) => {
530
+ linkEntries(database, input);
531
+ return { linked: true };
532
+ });
533
+ }
534
+ if (operation === 'purge') {
535
+ const input = validatePurgeCallArguments(args);
536
+ return withDatabase((database) => {
537
+ purgeEntry(database, input);
538
+ return { purged: true };
539
+ });
540
+ }
176
541
  if (operation === 'export') {
177
- const workspace = String(args.workspace ?? '');
178
- const output = String(args.output ?? '');
179
- if (output.length === 0)
542
+ assertExactCallArguments(args, operation, ['workspace', 'output']);
543
+ if (!Object.hasOwn(args, 'output')) {
180
544
  throw new KiokukoError('VALIDATION_ERROR', 'export output is required');
545
+ }
546
+ const workspace = requiredStringArgument(args, operation, 'workspace');
547
+ const output = requiredPathArgument(args, operation, 'output');
181
548
  return withDatabase((database) => writeExport(database, { workspace, output }));
182
549
  }
183
550
  if (operation === 'import') {
184
- const input = String(args.input ?? '');
185
- if (input.length === 0)
551
+ assertExactCallArguments(args, operation, ['input', 'workspace', 'dryRun']);
552
+ if (!Object.hasOwn(args, 'input')) {
186
553
  throw new KiokukoError('VALIDATION_ERROR', 'import input is required');
187
- const importOptions = { input, dryRun: args.dryRun === true };
188
- if (typeof args.workspace === 'string')
189
- importOptions.workspace = args.workspace;
190
- return args.dryRun === true ? importWorkspace(undefined, importOptions) : withDatabase((database) => importWorkspace(database, importOptions));
554
+ }
555
+ const input = requiredPathArgument(args, operation, 'input');
556
+ const workspace = optionalStringArgument(args, operation, 'workspace');
557
+ const dryRun = optionalBooleanArgument(args, operation, 'dryRun');
558
+ const importOptions = {
559
+ input,
560
+ ...(workspace === undefined ? {} : { workspace }),
561
+ ...(dryRun === undefined ? {} : { dryRun }),
562
+ };
563
+ return dryRun === true
564
+ ? importWorkspace(undefined, importOptions)
565
+ : withDatabase((database) => importWorkspace(database, importOptions));
191
566
  }
192
567
  if (operation === 'backup') {
193
- const output = String(args.output ?? '');
194
- if (output.length === 0)
568
+ assertExactCallArguments(args, operation, ['output']);
569
+ if (!Object.hasOwn(args, 'output')) {
195
570
  throw new KiokukoError('VALIDATION_ERROR', 'backup output is required');
571
+ }
572
+ const output = requiredPathArgument(args, operation, 'output');
196
573
  return createBackup(output);
197
574
  }
198
- if (operation === 'doctor')
575
+ if (operation === 'doctor') {
576
+ assertExactCallArguments(args, operation, []);
199
577
  return runDoctor();
200
- throw new KiokukoError('VALIDATION_ERROR', `Unknown operation: ${operation}`);
578
+ }
579
+ throw new KiokukoError('INTEGRITY_ERROR', 'Supported call operation has no dispatcher');
201
580
  }
202
581
  export function buildCli(dependencies = {}) {
203
582
  const cli = new Command();
204
- cli.name('kiokuko').description('Model-agnostic external memory for AI coding agents').version(packageVersion);
583
+ cli.name('kiokuko').description('Model-agnostic external memory for AI coding agents').version(PACKAGE_VERSION);
205
584
  cli.exitOverride();
206
585
  cli.configureOutput({ outputError: () => undefined });
207
586
  cli.command('version').description('Show the Kiokuko package version').action(() => {
208
- process.stdout.write(`${packageVersion}\n`);
587
+ process.stdout.write(`${PACKAGE_VERSION}\n`);
209
588
  });
210
589
  cli.command('init').description('Initialize the global Kiokuko database').option('--json').action(async (options) => {
211
590
  const result = await initializeDatabase();
@@ -217,36 +596,73 @@ export function buildCli(dependencies = {}) {
217
596
  .option('--command <path>', 'Kiokuko executable name or absolute path', 'kiokuko')
218
597
  .option('--dry-run', 'Validate and show planned changes without writing')
219
598
  .option('--no-standard-skills', 'Skip installing bundled Kiokuko standard skills')
220
- .option('--opencode-capture <profile>', 'OpenCode evidence capture: off,minimal,standard', 'off')
221
- .option('--opencode-mode <mode>', 'OpenCode prepare enforcement: advisory,strict', 'advisory')
599
+ .option('--skill-discovery <mode>', 'External Skill discovery: off,official,community')
222
600
  .option('--json', 'Emit a JSON response')
223
601
  .action(async (options) => {
224
- if (!['off', 'minimal', 'standard'].includes(options.opencodeCapture))
225
- throw new KiokukoError('VALIDATION_ERROR', 'opencode capture must be off, minimal, or standard');
226
- if (!['advisory', 'strict'].includes(options.opencodeMode))
227
- throw new KiokukoError('VALIDATION_ERROR', 'opencode mode must be advisory or strict');
602
+ const optionSkillDiscoveryMode = options.skillDiscovery === undefined
603
+ ? undefined
604
+ : parseSetupSkillDiscoveryMode(options.skillDiscovery);
228
605
  const setupEnvironment = dependencies.setupEnvironment ?? {};
606
+ const setupProcessEnvironment = setupEnvironment.env ?? process.env;
607
+ const environmentSkillDiscoveryMode = optionSkillDiscoveryMode === undefined
608
+ && Object.prototype.hasOwnProperty.call(setupProcessEnvironment, SKILL_DISCOVERY_ENV)
609
+ ? normalizeSkillDiscoveryMode(setupProcessEnvironment[SKILL_DISCOVERY_ENV])
610
+ : undefined;
611
+ const requestedSkillDiscoveryMode = optionSkillDiscoveryMode ?? environmentSkillDiscoveryMode;
229
612
  const detectedClients = options.clients === undefined ? await detectInstalledClients(setupEnvironment) : [];
230
613
  const setupInput = dependencies.setupInput ?? process.stdin;
231
614
  const setupOutput = dependencies.setupOutput ?? process.stdout;
232
- const interactive = options.clients === undefined
233
- && options.json !== true
615
+ const interactive = options.json !== true
234
616
  && setupInput.isTTY === true
235
617
  && setupOutput.isTTY === true;
236
- const clients = options.clients !== undefined
237
- ? parseSetupClients(options.clients)
238
- : interactive
239
- ? await promptSetupClients(detectedClients, { input: setupInput, output: setupOutput })
240
- : detectedClients;
241
- const data = await setupGlobalClients({
618
+ let clients;
619
+ let skillDiscoveryMode = requestedSkillDiscoveryMode;
620
+ if (interactive && options.clients === undefined && requestedSkillDiscoveryMode === undefined) {
621
+ const prompted = await promptSetupConfiguration(detectedClients, { input: setupInput, output: setupOutput });
622
+ clients = prompted.clients;
623
+ skillDiscoveryMode = prompted.skillDiscoveryMode;
624
+ }
625
+ else {
626
+ clients = options.clients !== undefined
627
+ ? parseSetupClients(options.clients)
628
+ : interactive
629
+ ? await promptSetupClients(detectedClients, { input: setupInput, output: setupOutput })
630
+ : detectedClients;
631
+ if (interactive && clients.length > 0 && skillDiscoveryMode === undefined) {
632
+ skillDiscoveryMode = await promptCommunitySkillDiscovery({ input: setupInput, output: setupOutput });
633
+ }
634
+ }
635
+ const setupOptions = {
242
636
  ...setupEnvironment,
243
637
  clients,
244
638
  command: options.command,
245
639
  dryRun: options.dryRun === true,
246
640
  standardSkills: options.standardSkills,
247
- opencodeCapture: options.opencodeCapture,
248
- opencodeMode: options.opencodeMode,
249
- });
641
+ ...(skillDiscoveryMode === undefined ? {} : { skillDiscoveryMode }),
642
+ };
643
+ let data;
644
+ const replacementClients = new Set();
645
+ for (;;) {
646
+ try {
647
+ data = await setupGlobalClients({
648
+ ...setupOptions,
649
+ replaceConflictingMcpServers: [...replacementClients],
650
+ });
651
+ break;
652
+ }
653
+ catch (error) {
654
+ const conflictClient = setupMcpIdentityConflictClient(error);
655
+ if (!interactive
656
+ || conflictClient === undefined
657
+ || !clients.includes(conflictClient)
658
+ || replacementClients.has(conflictClient))
659
+ throw error;
660
+ const replace = await promptReplaceConflictingMcp(conflictClient, { input: setupInput, output: setupOutput });
661
+ if (!replace)
662
+ throw error;
663
+ replacementClients.add(conflictClient);
664
+ }
665
+ }
250
666
  const changed = data.files.filter((file) => file.action !== 'unchanged').length;
251
667
  const clientLabel = data.clients.length === 0 ? 'no detected clients' : data.clients.join(', ');
252
668
  const message = options.dryRun
@@ -260,7 +676,7 @@ export function buildCli(dependencies = {}) {
260
676
  await runMcpServer();
261
677
  });
262
678
  cli.command('use').description('Bind this repository to Kiokuko external memory')
263
- .option('--root <path>').option('--workspace <name>').option('--agent-file <path>', 'Agent instruction file', 'AGENTS.md')
679
+ .option('--root <path>').option('--workspace <name>').option('--agent-file <path>', 'Agent instruction file')
264
680
  .option('--dry-run').option('--no-agent-file').option('--force-rebind').option('--allow-directory').option('--json')
265
681
  .action(async (options) => {
266
682
  const useOptions = {};
@@ -282,7 +698,7 @@ export function buildCli(dependencies = {}) {
282
698
  humanOrJson(options.json === true, 'use', result, `Kiokuko enabled for ${result.repositoryRoot}`);
283
699
  });
284
700
  configureRecallCommand(cli.command('recall'));
285
- const memory = cli.command('memory').description('Memory operations');
701
+ const memory = cli.command('memory').description('Human/operator memory management');
286
702
  configureRecallCommand(memory.command('recall'));
287
703
  const guide = cli.command('guide').description('Run the Akinator-style knowledge and skill intake');
288
704
  guide.command('start').description('Start an intake session').argument('<task>').requiredOption('--workspace <name>').option('--json').action(async (task, options) => {
@@ -298,17 +714,7 @@ export function buildCli(dependencies = {}) {
298
714
  }));
299
715
  humanOrJson(options.json, 'guide.answer', data, data.question?.prompt ?? 'Akinator context is ready');
300
716
  });
301
- guide.command('context').description('Build the knowledge and skill context for an intake session').argument('<session-id>').requiredOption('--workspace <name>')
302
- .option('--no-client-skills', 'Allow the mattpocock/skills fallback because the client has no available skills')
303
- .option('--json').action(async (sessionId, options) => {
304
- const data = await withDatabase((database) => getAkinatorContext(database, {
305
- workspace: options.workspace,
306
- sessionId,
307
- ...(options.clientSkills === false ? { allowExternalSkillFallback: true } : {}),
308
- }));
309
- humanOrJson(options.json, 'guide.context', data, `${data.entries.length} knowledge entries selected`);
310
- });
311
- const search = addWorkspaceOptions(cli.command('search').description('Search memory entries').argument('<query>'))
717
+ const search = addWorkspaceOptions(cli.command('search').description('Human/operator management: search memory entries').argument('<query>'))
312
718
  .option('--limit <number>', 'Maximum entries', '20').option('--kind <kind>').option('--status <status>').option('--tag <tag>');
313
719
  search.action(async (query, options) => {
314
720
  const searchOptions = { workspace: String(options.workspace ?? ''), query, limit: Number(options.limit) };
@@ -321,17 +727,16 @@ export function buildCli(dependencies = {}) {
321
727
  const data = await withDatabase((database) => searchEntries(database, searchOptions));
322
728
  humanOrJson(options.json === true, 'search', data, `${data.items.length} memory entries found`, { count: data.count });
323
729
  });
324
- const read = addWorkspaceOptions(cli.command('read').description('Read one memory entry').argument('<entry-id>'));
730
+ const read = addWorkspaceOptions(cli.command('read').description('Human/operator management: read one memory entry').argument('<entry-id>'));
325
731
  read.action(async (entryId, options) => {
326
732
  const data = await withDatabase((database) => readEntry(database, { workspace: String(options.workspace ?? ''), entryId }));
327
733
  humanOrJson(options.json === true, 'read', data, `${data.title}\n${data.body}`);
328
734
  });
329
735
  const record = cli.command('record').description('Record a memory entry').requiredOption('--workspace <name>').requiredOption('--input-json <file>').option('--json');
330
736
  record.action(async (options) => {
331
- const input = await readJsonInput(options.inputJson);
332
- if (typeof input !== 'object' || input === null || Array.isArray(input))
333
- throw new KiokukoError('VALIDATION_ERROR', 'record input must be a JSON object');
334
- const data = await withDatabase((database) => recordEntry(database, { ...input, workspace: options.workspace }));
737
+ const parsed = snapshotPlainJsonObject(await readJsonInput(options.inputJson), 'record input must be a JSON object');
738
+ const input = validateRecordInput({ ...parsed, workspace: options.workspace });
739
+ const data = await withDatabase((database) => recordEntry(database, input));
335
740
  humanOrJson(options.json, 'record', data, `Recorded ${data.id}`);
336
741
  });
337
742
  const promote = cli.command('promote').description('Promote a candidate entry').argument('<entry-id>').requiredOption('--workspace <name>').requiredOption('--expected-revision <number>').option('--json');
@@ -387,6 +792,7 @@ export function buildCli(dependencies = {}) {
387
792
  registerServerCommands(cli, dependencies.server);
388
793
  registerAgentCommand(cli, dependencies.agent);
389
794
  registerLedgerCommands(cli, { withDatabase });
795
+ registerSkillsCommands(cli, dependencies.skills ?? { withDatabase });
390
796
  cli.command('web').description('Start the local Kiokuko web UI')
391
797
  .option('--host <host>', 'Loopback host', '127.0.0.1')
392
798
  .option('--port <number>', 'HTTP port', '4173')
@@ -421,20 +827,17 @@ export function buildCli(dependencies = {}) {
421
827
  : await withDatabase((database) => importWorkspace(database, importOptions));
422
828
  humanOrJson(options.json, 'import', data, `${data.count} records inspected`);
423
829
  });
424
- cli.command('call').description('Process one JSON request').requiredOption('--input-json <file>').option('--json').action(async (options) => {
425
- const request = await readJsonInput(options.inputJson);
426
- const operation = typeof request === 'object' && request !== null && !Array.isArray(request) && typeof request.operation === 'string' ? request.operation : 'unknown';
830
+ cli.command('call').description('Process one management JSON request; memory reads are not supported').requiredOption('--input-json <file>').option('--json').action(async (options) => {
831
+ const request = parseCallRequest(await readJsonInput(options.inputJson));
427
832
  const data = await dispatchRequest(request);
428
- emit(successEnvelope(operation, data));
833
+ emit(successEnvelope(request.operation, data));
429
834
  });
430
835
  return cli;
431
836
  }
432
837
  function operationFor(argv) {
433
838
  const command = argv[2] ?? 'unknown';
434
- if (command === 'server' && argv[3] !== undefined && !argv[3].startsWith('-'))
435
- return `server.${argv[3]}`;
436
- if (command === 'agent' && argv[3] !== undefined && !argv[3].startsWith('-'))
437
- return `agent.${argv[3]}`;
839
+ if (['server', 'agent', 'skills'].includes(command) && argv[3] !== undefined && !argv[3].startsWith('-'))
840
+ return `${command}.${argv[3]}`;
438
841
  return command;
439
842
  }
440
843
  function commanderDiagnostic(error) {
@@ -460,15 +863,22 @@ export async function runCli(argv = process.argv, dependencies = {}) {
460
863
  }
461
864
  catch (error) {
462
865
  if (error instanceof CommanderError) {
866
+ if (error.exitCode === 0)
867
+ return 0;
868
+ if (jsonRequested) {
869
+ emit(errorEnvelope(operation, new KiokukoError('USAGE_ERROR', 'Invalid command-line usage', { commanderCode: error.code })));
870
+ return 2;
871
+ }
463
872
  const diagnostic = commanderDiagnostic(error);
464
873
  if (diagnostic.length > 0)
465
874
  process.stderr.write(diagnostic);
466
- return error.exitCode === 0 ? 0 : 2;
875
+ return 2;
467
876
  }
877
+ const envelope = errorEnvelope(operation, error);
468
878
  if (jsonRequested && !(serveStarted && operation === 'serve'))
469
- emit(errorEnvelope(operation, error));
879
+ emit(envelope);
470
880
  else
471
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
881
+ process.stderr.write(`${envelope.error.message}\n`);
472
882
  return exitCodeFor(error);
473
883
  }
474
884
  }