@askdkc/kiokuko 0.1.16 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (549) hide show
  1. package/README.ja.md +91 -112
  2. package/README.ko.md +90 -102
  3. package/README.md +103 -260
  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 +14 -24
  18. package/dist/akinator/agent-task.d.ts.map +1 -1
  19. package/dist/akinator/agent-task.js +460 -103
  20. package/dist/akinator/agent-task.js.map +1 -1
  21. package/dist/akinator/capabilities.d.ts +52 -7
  22. package/dist/akinator/capabilities.d.ts.map +1 -1
  23. package/dist/akinator/capabilities.js +226 -28
  24. package/dist/akinator/capabilities.js.map +1 -1
  25. package/dist/akinator/capability-binding.d.ts +11 -0
  26. package/dist/akinator/capability-binding.d.ts.map +1 -0
  27. package/dist/akinator/capability-binding.js +56 -0
  28. package/dist/akinator/capability-binding.js.map +1 -0
  29. package/dist/akinator/domain.js +2 -2
  30. package/dist/akinator/domain.js.map +1 -1
  31. package/dist/akinator/knowledge-path.d.ts.map +1 -1
  32. package/dist/akinator/knowledge-path.js +409 -39
  33. package/dist/akinator/knowledge-path.js.map +1 -1
  34. package/dist/akinator/orchestrator.d.ts +3 -4
  35. package/dist/akinator/orchestrator.d.ts.map +1 -1
  36. package/dist/akinator/orchestrator.js +1 -4
  37. package/dist/akinator/orchestrator.js.map +1 -1
  38. package/dist/akinator/service.d.ts +0 -4
  39. package/dist/akinator/service.d.ts.map +1 -1
  40. package/dist/akinator/service.js +19 -35
  41. package/dist/akinator/service.js.map +1 -1
  42. package/dist/akinator/skill-discovery-attempt.d.ts +20 -0
  43. package/dist/akinator/skill-discovery-attempt.d.ts.map +1 -0
  44. package/dist/akinator/skill-discovery-attempt.js +390 -0
  45. package/dist/akinator/skill-discovery-attempt.js.map +1 -0
  46. package/dist/akinator/store.d.ts.map +1 -1
  47. package/dist/akinator/store.js +107 -52
  48. package/dist/akinator/store.js.map +1 -1
  49. package/dist/akinator/types.d.ts +0 -12
  50. package/dist/akinator/types.d.ts.map +1 -1
  51. package/dist/bin/kiokuko.js +0 -0
  52. package/dist/cli.d.ts +2 -0
  53. package/dist/cli.d.ts.map +1 -1
  54. package/dist/cli.js +561 -144
  55. package/dist/cli.js.map +1 -1
  56. package/dist/client/server-client.d.ts +5 -3
  57. package/dist/client/server-client.d.ts.map +1 -1
  58. package/dist/client/server-client.js +486 -181
  59. package/dist/client/server-client.js.map +1 -1
  60. package/dist/commands/agent.d.ts +2 -0
  61. package/dist/commands/agent.d.ts.map +1 -1
  62. package/dist/commands/agent.js +861 -86
  63. package/dist/commands/agent.js.map +1 -1
  64. package/dist/commands/backup.d.ts +2 -1
  65. package/dist/commands/backup.d.ts.map +1 -1
  66. package/dist/commands/backup.js +64 -8
  67. package/dist/commands/backup.js.map +1 -1
  68. package/dist/commands/doctor.d.ts +5 -1
  69. package/dist/commands/doctor.d.ts.map +1 -1
  70. package/dist/commands/doctor.js +70 -26
  71. package/dist/commands/doctor.js.map +1 -1
  72. package/dist/commands/export.d.ts +0 -4
  73. package/dist/commands/export.d.ts.map +1 -1
  74. package/dist/commands/export.js +191 -32
  75. package/dist/commands/export.js.map +1 -1
  76. package/dist/commands/import.d.ts +10 -1
  77. package/dist/commands/import.d.ts.map +1 -1
  78. package/dist/commands/import.js +592 -113
  79. package/dist/commands/import.js.map +1 -1
  80. package/dist/commands/init.d.ts +19 -1
  81. package/dist/commands/init.d.ts.map +1 -1
  82. package/dist/commands/init.js +569 -22
  83. package/dist/commands/init.js.map +1 -1
  84. package/dist/commands/purge.d.ts.map +1 -1
  85. package/dist/commands/purge.js +3 -0
  86. package/dist/commands/purge.js.map +1 -1
  87. package/dist/commands/setup.d.ts +34 -8
  88. package/dist/commands/setup.d.ts.map +1 -1
  89. package/dist/commands/setup.js +418 -86
  90. package/dist/commands/setup.js.map +1 -1
  91. package/dist/commands/skills.d.ts +9 -0
  92. package/dist/commands/skills.d.ts.map +1 -0
  93. package/dist/commands/skills.js +317 -0
  94. package/dist/commands/skills.js.map +1 -0
  95. package/dist/commands/use.d.ts +10 -2
  96. package/dist/commands/use.d.ts.map +1 -1
  97. package/dist/commands/use.js +851 -73
  98. package/dist/commands/use.js.map +1 -1
  99. package/dist/config/paths.d.ts +11 -1
  100. package/dist/config/paths.d.ts.map +1 -1
  101. package/dist/config/paths.js +64 -29
  102. package/dist/config/paths.js.map +1 -1
  103. package/dist/config/project-config.d.ts +1 -0
  104. package/dist/config/project-config.d.ts.map +1 -1
  105. package/dist/config/project-config.js +70 -32
  106. package/dist/config/project-config.js.map +1 -1
  107. package/dist/context/broker.d.ts +30 -14
  108. package/dist/context/broker.d.ts.map +1 -1
  109. package/dist/context/broker.js +628 -150
  110. package/dist/context/broker.js.map +1 -1
  111. package/dist/context/delivery.d.ts +8 -22
  112. package/dist/context/delivery.d.ts.map +1 -1
  113. package/dist/context/delivery.js +204 -152
  114. package/dist/context/delivery.js.map +1 -1
  115. package/dist/context/feedback.d.ts +11 -12
  116. package/dist/context/feedback.d.ts.map +1 -1
  117. package/dist/context/feedback.js +250 -268
  118. package/dist/context/feedback.js.map +1 -1
  119. package/dist/context/origin.d.ts +9 -0
  120. package/dist/context/origin.d.ts.map +1 -0
  121. package/dist/context/origin.js +15 -0
  122. package/dist/context/origin.js.map +1 -0
  123. package/dist/context/ranking.d.ts +4 -13
  124. package/dist/context/ranking.d.ts.map +1 -1
  125. package/dist/context/ranking.js +21 -5
  126. package/dist/context/ranking.js.map +1 -1
  127. package/dist/context/recommendations.d.ts +0 -5
  128. package/dist/context/recommendations.d.ts.map +1 -1
  129. package/dist/context/recommendations.js +0 -1
  130. package/dist/context/recommendations.js.map +1 -1
  131. package/dist/context/run-state.d.ts +26 -0
  132. package/dist/context/run-state.d.ts.map +1 -0
  133. package/dist/context/run-state.js +399 -0
  134. package/dist/context/run-state.js.map +1 -0
  135. package/dist/context/scoped-broker.d.ts +19 -6
  136. package/dist/context/scoped-broker.d.ts.map +1 -1
  137. package/dist/context/scoped-broker.js +530 -131
  138. package/dist/context/scoped-broker.js.map +1 -1
  139. package/dist/context/selection-state.d.ts +19 -0
  140. package/dist/context/selection-state.d.ts.map +1 -0
  141. package/dist/context/selection-state.js +250 -0
  142. package/dist/context/selection-state.js.map +1 -0
  143. package/dist/db/adapter.d.ts +5 -3
  144. package/dist/db/adapter.d.ts.map +1 -1
  145. package/dist/db/adapter.js +6 -3
  146. package/dist/db/adapter.js.map +1 -1
  147. package/dist/db/capabilities.d.ts.map +1 -1
  148. package/dist/db/capabilities.js +34 -16
  149. package/dist/db/capabilities.js.map +1 -1
  150. package/dist/db/connection.d.ts +8 -0
  151. package/dist/db/connection.d.ts.map +1 -1
  152. package/dist/db/connection.js +55 -26
  153. package/dist/db/connection.js.map +1 -1
  154. package/dist/db/migrate.d.ts +28 -7
  155. package/dist/db/migrate.d.ts.map +1 -1
  156. package/dist/db/migrate.js +106 -78
  157. package/dist/db/migrate.js.map +1 -1
  158. package/dist/db/sqlite-retry.d.ts +11 -0
  159. package/dist/db/sqlite-retry.d.ts.map +1 -0
  160. package/dist/db/sqlite-retry.js +66 -0
  161. package/dist/db/sqlite-retry.js.map +1 -0
  162. package/dist/db/transaction.d.ts +13 -0
  163. package/dist/db/transaction.d.ts.map +1 -1
  164. package/dist/db/transaction.js +53 -24
  165. package/dist/db/transaction.js.map +1 -1
  166. package/dist/db/upgrade-backup.d.ts +58 -2
  167. package/dist/db/upgrade-backup.d.ts.map +1 -1
  168. package/dist/db/upgrade-backup.js +757 -28
  169. package/dist/db/upgrade-backup.js.map +1 -1
  170. package/dist/errors.js +1 -1
  171. package/dist/errors.js.map +1 -1
  172. package/dist/gateway/agent-service.d.ts +4 -1
  173. package/dist/gateway/agent-service.d.ts.map +1 -1
  174. package/dist/gateway/agent-service.js +71 -58
  175. package/dist/gateway/agent-service.js.map +1 -1
  176. package/dist/gateway/checkpoint-service.d.ts +1 -0
  177. package/dist/gateway/checkpoint-service.d.ts.map +1 -1
  178. package/dist/gateway/checkpoint-service.js +47 -24
  179. package/dist/gateway/checkpoint-service.js.map +1 -1
  180. package/dist/ledger/archive.d.ts +1 -4
  181. package/dist/ledger/archive.d.ts.map +1 -1
  182. package/dist/ledger/archive.js +134 -54
  183. package/dist/ledger/archive.js.map +1 -1
  184. package/dist/ledger/maintenance.d.ts +0 -11
  185. package/dist/ledger/maintenance.d.ts.map +1 -1
  186. package/dist/ledger/maintenance.js +41 -44
  187. package/dist/ledger/maintenance.js.map +1 -1
  188. package/dist/ledger/projection.d.ts +0 -1
  189. package/dist/ledger/projection.d.ts.map +1 -1
  190. package/dist/ledger/projection.js.map +1 -1
  191. package/dist/ledger/promotion.d.ts +0 -9
  192. package/dist/ledger/promotion.d.ts.map +1 -1
  193. package/dist/ledger/promotion.js.map +1 -1
  194. package/dist/ledger/query.d.ts +1 -15
  195. package/dist/ledger/query.d.ts.map +1 -1
  196. package/dist/ledger/query.js.map +1 -1
  197. package/dist/ledger/store.d.ts +0 -1
  198. package/dist/ledger/store.d.ts.map +1 -1
  199. package/dist/ledger/store.js +11 -8
  200. package/dist/ledger/store.js.map +1 -1
  201. package/dist/ledger/types.d.ts +0 -4
  202. package/dist/ledger/types.d.ts.map +1 -1
  203. package/dist/ledger/types.js.map +1 -1
  204. package/dist/ledger/validate.d.ts.map +1 -1
  205. package/dist/ledger/validate.js +0 -5
  206. package/dist/ledger/validate.js.map +1 -1
  207. package/dist/mcp/bounded-stdio-transport.d.ts +23 -0
  208. package/dist/mcp/bounded-stdio-transport.d.ts.map +1 -0
  209. package/dist/mcp/bounded-stdio-transport.js +109 -0
  210. package/dist/mcp/bounded-stdio-transport.js.map +1 -0
  211. package/dist/mcp/server.d.ts +4 -0
  212. package/dist/mcp/server.d.ts.map +1 -1
  213. package/dist/mcp/server.js +111 -75
  214. package/dist/mcp/server.js.map +1 -1
  215. package/dist/memory/audit.d.ts +0 -1
  216. package/dist/memory/audit.d.ts.map +1 -1
  217. package/dist/memory/audit.js +0 -1
  218. package/dist/memory/audit.js.map +1 -1
  219. package/dist/memory/curator.d.ts +45 -1
  220. package/dist/memory/curator.d.ts.map +1 -1
  221. package/dist/memory/curator.js +290 -68
  222. package/dist/memory/curator.js.map +1 -1
  223. package/dist/memory/entries.d.ts +12 -2
  224. package/dist/memory/entries.d.ts.map +1 -1
  225. package/dist/memory/entries.js +198 -114
  226. package/dist/memory/entries.js.map +1 -1
  227. package/dist/memory/federated-retrieval.d.ts +78 -0
  228. package/dist/memory/federated-retrieval.d.ts.map +1 -0
  229. package/dist/memory/federated-retrieval.js +441 -0
  230. package/dist/memory/federated-retrieval.js.map +1 -0
  231. package/dist/memory/hybrid-retrieval.d.ts +5 -11
  232. package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
  233. package/dist/memory/hybrid-retrieval.js +78 -58
  234. package/dist/memory/hybrid-retrieval.js.map +1 -1
  235. package/dist/memory/lifecycle.d.ts.map +1 -1
  236. package/dist/memory/lifecycle.js +17 -13
  237. package/dist/memory/lifecycle.js.map +1 -1
  238. package/dist/memory/portability.d.ts +10 -0
  239. package/dist/memory/portability.d.ts.map +1 -0
  240. package/dist/memory/portability.js +44 -0
  241. package/dist/memory/portability.js.map +1 -0
  242. package/dist/memory/rebuild-search.d.ts +5 -0
  243. package/dist/memory/rebuild-search.d.ts.map +1 -1
  244. package/dist/memory/rebuild-search.js +101 -76
  245. package/dist/memory/rebuild-search.js.map +1 -1
  246. package/dist/memory/retrieval-query.d.ts +0 -5
  247. package/dist/memory/retrieval-query.d.ts.map +1 -1
  248. package/dist/memory/retrieval-query.js +0 -5
  249. package/dist/memory/retrieval-query.js.map +1 -1
  250. package/dist/memory/retrieval.d.ts +11 -0
  251. package/dist/memory/retrieval.d.ts.map +1 -1
  252. package/dist/memory/retrieval.js +34 -120
  253. package/dist/memory/retrieval.js.map +1 -1
  254. package/dist/memory/revisions.d.ts +76 -1
  255. package/dist/memory/revisions.d.ts.map +1 -1
  256. package/dist/memory/revisions.js +539 -35
  257. package/dist/memory/revisions.js.map +1 -1
  258. package/dist/memory/scoped-memory.d.ts +22 -13
  259. package/dist/memory/scoped-memory.d.ts.map +1 -1
  260. package/dist/memory/scoped-memory.js +248 -139
  261. package/dist/memory/scoped-memory.js.map +1 -1
  262. package/dist/memory/secrets.d.ts +2 -0
  263. package/dist/memory/secrets.d.ts.map +1 -1
  264. package/dist/memory/secrets.js +36 -0
  265. package/dist/memory/secrets.js.map +1 -1
  266. package/dist/memory/structured-memory.d.ts +8 -1
  267. package/dist/memory/structured-memory.d.ts.map +1 -1
  268. package/dist/memory/structured-memory.js +74 -20
  269. package/dist/memory/structured-memory.js.map +1 -1
  270. package/dist/memory/workspaces.d.ts +9 -0
  271. package/dist/memory/workspaces.d.ts.map +1 -1
  272. package/dist/memory/workspaces.js +67 -0
  273. package/dist/memory/workspaces.js.map +1 -1
  274. package/dist/package-version.d.ts +2 -0
  275. package/dist/package-version.d.ts.map +1 -0
  276. package/dist/package-version.js +7 -0
  277. package/dist/package-version.js.map +1 -0
  278. package/dist/repository/binding.d.ts +5 -0
  279. package/dist/repository/binding.d.ts.map +1 -1
  280. package/dist/repository/binding.js +117 -17
  281. package/dist/repository/binding.js.map +1 -1
  282. package/dist/repository/framework-version.d.ts +8 -0
  283. package/dist/repository/framework-version.d.ts.map +1 -0
  284. package/dist/repository/framework-version.js +29 -0
  285. package/dist/repository/framework-version.js.map +1 -0
  286. package/dist/repository/identity-value.d.ts +4 -0
  287. package/dist/repository/identity-value.d.ts.map +1 -0
  288. package/dist/repository/identity-value.js +24 -0
  289. package/dist/repository/identity-value.js.map +1 -0
  290. package/dist/repository/identity.d.ts.map +1 -1
  291. package/dist/repository/identity.js +2 -0
  292. package/dist/repository/identity.js.map +1 -1
  293. package/dist/repository/project-fingerprint.d.ts +33 -0
  294. package/dist/repository/project-fingerprint.d.ts.map +1 -0
  295. package/dist/repository/project-fingerprint.js +429 -0
  296. package/dist/repository/project-fingerprint.js.map +1 -0
  297. package/dist/repository/remote-url.d.ts +0 -1
  298. package/dist/repository/remote-url.d.ts.map +1 -1
  299. package/dist/repository/remote-url.js +0 -1
  300. package/dist/repository/remote-url.js.map +1 -1
  301. package/dist/runtime-version.d.ts +2 -1
  302. package/dist/runtime-version.d.ts.map +1 -1
  303. package/dist/runtime-version.js +21 -4
  304. package/dist/runtime-version.js.map +1 -1
  305. package/dist/serialization/boundary-json.d.ts +20 -0
  306. package/dist/serialization/boundary-json.d.ts.map +1 -0
  307. package/dist/serialization/boundary-json.js +129 -0
  308. package/dist/serialization/boundary-json.js.map +1 -0
  309. package/dist/serialization/envelope.js +1 -1
  310. package/dist/serialization/envelope.js.map +1 -1
  311. package/dist/serialization/validate.d.ts +7 -0
  312. package/dist/serialization/validate.d.ts.map +1 -1
  313. package/dist/serialization/validate.js +53 -13
  314. package/dist/serialization/validate.js.map +1 -1
  315. package/dist/server/app.js +1 -1
  316. package/dist/server/app.js.map +1 -1
  317. package/dist/server/http.d.ts +4 -3
  318. package/dist/server/http.d.ts.map +1 -1
  319. package/dist/server/http.js +90 -50
  320. package/dist/server/http.js.map +1 -1
  321. package/dist/server/idempotency.d.ts +0 -6
  322. package/dist/server/idempotency.d.ts.map +1 -1
  323. package/dist/server/idempotency.js.map +1 -1
  324. package/dist/server/router.d.ts.map +1 -1
  325. package/dist/server/router.js +21 -4
  326. package/dist/server/router.js.map +1 -1
  327. package/dist/server/routes/agent-capability-gate.d.ts +40 -0
  328. package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
  329. package/dist/server/routes/agent-capability-gate.js +182 -0
  330. package/dist/server/routes/agent-capability-gate.js.map +1 -0
  331. package/dist/server/routes/agent-events.d.ts.map +1 -1
  332. package/dist/server/routes/agent-events.js +8 -1
  333. package/dist/server/routes/agent-events.js.map +1 -1
  334. package/dist/server/routes/agent-intake.d.ts.map +1 -1
  335. package/dist/server/routes/agent-intake.js +10 -2
  336. package/dist/server/routes/agent-intake.js.map +1 -1
  337. package/dist/server/routes/agent-promotions.d.ts.map +1 -1
  338. package/dist/server/routes/agent-promotions.js +5 -2
  339. package/dist/server/routes/agent-promotions.js.map +1 -1
  340. package/dist/server/routes/agent-runs.d.ts.map +1 -1
  341. package/dist/server/routes/agent-runs.js +18 -4
  342. package/dist/server/routes/agent-runs.js.map +1 -1
  343. package/dist/server/routes/request-binding.d.ts +5 -0
  344. package/dist/server/routes/request-binding.d.ts.map +1 -0
  345. package/dist/server/routes/request-binding.js +49 -0
  346. package/dist/server/routes/request-binding.js.map +1 -0
  347. package/dist/server/routes/task5-support.d.ts +1 -8
  348. package/dist/server/routes/task5-support.d.ts.map +1 -1
  349. package/dist/server/routes/task5-support.js +1 -17
  350. package/dist/server/routes/task5-support.js.map +1 -1
  351. package/dist/server/routes/task5.d.ts.map +1 -1
  352. package/dist/server/routes/task5.js +106 -36
  353. package/dist/server/routes/task5.js.map +1 -1
  354. package/dist/server/write-queue.js +2 -2
  355. package/dist/server/write-queue.js.map +1 -1
  356. package/dist/setup/claude-config.d.ts +2 -1
  357. package/dist/setup/claude-config.d.ts.map +1 -1
  358. package/dist/setup/claude-config.js +54 -4
  359. package/dist/setup/claude-config.js.map +1 -1
  360. package/dist/setup/client-detection.d.ts +7 -2
  361. package/dist/setup/client-detection.d.ts.map +1 -1
  362. package/dist/setup/client-detection.js +27 -9
  363. package/dist/setup/client-detection.js.map +1 -1
  364. package/dist/setup/hermes-config.d.ts +2 -1
  365. package/dist/setup/hermes-config.d.ts.map +1 -1
  366. package/dist/setup/hermes-config.js +53 -12
  367. package/dist/setup/hermes-config.js.map +1 -1
  368. package/dist/setup/legacy-client-cleanup.d.ts +6 -0
  369. package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
  370. package/dist/setup/legacy-client-cleanup.js +152 -0
  371. package/dist/setup/legacy-client-cleanup.js.map +1 -0
  372. package/dist/setup/managed-text.d.ts.map +1 -1
  373. package/dist/setup/managed-text.js +11 -1
  374. package/dist/setup/managed-text.js.map +1 -1
  375. package/dist/setup/opencode-config.d.ts +2 -1
  376. package/dist/setup/opencode-config.d.ts.map +1 -1
  377. package/dist/setup/opencode-config.js +57 -5
  378. package/dist/setup/opencode-config.js.map +1 -1
  379. package/dist/setup/render.d.ts +2 -1
  380. package/dist/setup/render.d.ts.map +1 -1
  381. package/dist/setup/render.js +91 -17
  382. package/dist/setup/render.js.map +1 -1
  383. package/dist/setup/standard-skills.d.ts +16 -2
  384. package/dist/setup/standard-skills.d.ts.map +1 -1
  385. package/dist/setup/standard-skills.js +37 -13
  386. package/dist/setup/standard-skills.js.map +1 -1
  387. package/dist/setup/strict-json.d.ts +7 -0
  388. package/dist/setup/strict-json.d.ts.map +1 -0
  389. package/dist/setup/strict-json.js +98 -0
  390. package/dist/setup/strict-json.js.map +1 -0
  391. package/dist/setup/strict-toml.d.ts +7 -0
  392. package/dist/setup/strict-toml.d.ts.map +1 -0
  393. package/dist/setup/strict-toml.js +470 -0
  394. package/dist/setup/strict-toml.js.map +1 -0
  395. package/dist/skills/cache.d.ts +15 -0
  396. package/dist/skills/cache.d.ts.map +1 -0
  397. package/dist/skills/cache.js +19 -0
  398. package/dist/skills/cache.js.map +1 -0
  399. package/dist/skills/candidate-ranking.d.ts +15 -0
  400. package/dist/skills/candidate-ranking.d.ts.map +1 -0
  401. package/dist/skills/candidate-ranking.js +52 -0
  402. package/dist/skills/candidate-ranking.js.map +1 -0
  403. package/dist/skills/chunking.d.ts +11 -0
  404. package/dist/skills/chunking.d.ts.map +1 -0
  405. package/dist/skills/chunking.js +291 -0
  406. package/dist/skills/chunking.js.map +1 -0
  407. package/dist/skills/config.d.ts +19 -0
  408. package/dist/skills/config.d.ts.map +1 -0
  409. package/dist/skills/config.js +103 -0
  410. package/dist/skills/config.js.map +1 -0
  411. package/dist/skills/discovery-service.d.ts +26 -0
  412. package/dist/skills/discovery-service.d.ts.map +1 -0
  413. package/dist/skills/discovery-service.js +921 -0
  414. package/dist/skills/discovery-service.js.map +1 -0
  415. package/dist/skills/external-transport.d.ts +2 -0
  416. package/dist/skills/external-transport.d.ts.map +1 -0
  417. package/dist/skills/external-transport.js +30 -0
  418. package/dist/skills/external-transport.js.map +1 -0
  419. package/dist/skills/find.d.ts +16 -0
  420. package/dist/skills/find.d.ts.map +1 -0
  421. package/dist/skills/find.js +58 -0
  422. package/dist/skills/find.js.map +1 -0
  423. package/dist/skills/gap-detection.d.ts +23 -0
  424. package/dist/skills/gap-detection.d.ts.map +1 -0
  425. package/dist/skills/gap-detection.js +62 -0
  426. package/dist/skills/gap-detection.js.map +1 -0
  427. package/dist/skills/import-preparation.d.ts +4 -0
  428. package/dist/skills/import-preparation.d.ts.map +1 -0
  429. package/dist/skills/import-preparation.js +20 -0
  430. package/dist/skills/import-preparation.js.map +1 -0
  431. package/dist/skills/materialization-authority.d.ts +11 -0
  432. package/dist/skills/materialization-authority.d.ts.map +1 -0
  433. package/dist/skills/materialization-authority.js +92 -0
  434. package/dist/skills/materialization-authority.js.map +1 -0
  435. package/dist/skills/materialization-service.d.ts +22 -0
  436. package/dist/skills/materialization-service.d.ts.map +1 -0
  437. package/dist/skills/materialization-service.js +101 -0
  438. package/dist/skills/materialization-service.js.map +1 -0
  439. package/dist/skills/official-catalog.d.ts +31 -0
  440. package/dist/skills/official-catalog.d.ts.map +1 -0
  441. package/dist/skills/official-catalog.js +110 -0
  442. package/dist/skills/official-catalog.js.map +1 -0
  443. package/dist/skills/providers/schema.d.ts +30 -0
  444. package/dist/skills/providers/schema.d.ts.map +1 -0
  445. package/dist/skills/providers/schema.js +354 -0
  446. package/dist/skills/providers/schema.js.map +1 -0
  447. package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
  448. package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
  449. package/dist/skills/providers/skills-sh-compat.js +71 -0
  450. package/dist/skills/providers/skills-sh-compat.js.map +1 -0
  451. package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
  452. package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
  453. package/dist/skills/providers/skills-sh-v1.js +134 -0
  454. package/dist/skills/providers/skills-sh-v1.js.map +1 -0
  455. package/dist/skills/query-builder.d.ts +18 -0
  456. package/dist/skills/query-builder.d.ts.map +1 -0
  457. package/dist/skills/query-builder.js +93 -0
  458. package/dist/skills/query-builder.js.map +1 -0
  459. package/dist/skills/source/errors.d.ts +9 -0
  460. package/dist/skills/source/errors.d.ts.map +1 -0
  461. package/dist/skills/source/errors.js +15 -0
  462. package/dist/skills/source/errors.js.map +1 -0
  463. package/dist/skills/source/frontmatter.d.ts +9 -0
  464. package/dist/skills/source/frontmatter.d.ts.map +1 -0
  465. package/dist/skills/source/frontmatter.js +77 -0
  466. package/dist/skills/source/frontmatter.js.map +1 -0
  467. package/dist/skills/source/github-fetcher.d.ts +20 -0
  468. package/dist/skills/source/github-fetcher.d.ts.map +1 -0
  469. package/dist/skills/source/github-fetcher.js +292 -0
  470. package/dist/skills/source/github-fetcher.js.map +1 -0
  471. package/dist/skills/source/snapshot-validator.d.ts +28 -0
  472. package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
  473. package/dist/skills/source/snapshot-validator.js +186 -0
  474. package/dist/skills/source/snapshot-validator.js.map +1 -0
  475. package/dist/skills/store.d.ts +181 -0
  476. package/dist/skills/store.d.ts.map +1 -0
  477. package/dist/skills/store.js +1710 -0
  478. package/dist/skills/store.js.map +1 -0
  479. package/dist/skills/types.d.ts +169 -0
  480. package/dist/skills/types.d.ts.map +1 -0
  481. package/dist/skills/types.js +2 -0
  482. package/dist/skills/types.js.map +1 -0
  483. package/dist/web/i18n.d.ts +56 -8
  484. package/dist/web/i18n.d.ts.map +1 -1
  485. package/dist/web/i18n.js +224 -32
  486. package/dist/web/i18n.js.map +1 -1
  487. package/dist/web/server.d.ts.map +1 -1
  488. package/dist/web/server.js +458 -42
  489. package/dist/web/server.js.map +1 -1
  490. package/dist/web/ui.d.ts +4 -0
  491. package/dist/web/ui.d.ts.map +1 -1
  492. package/dist/web/ui.js +697 -61
  493. package/dist/web/ui.js.map +1 -1
  494. package/migrations/008_federated_memory.sql +46 -0
  495. package/migrations/009_external_skill_discovery.sql +126 -0
  496. package/package.json +6 -3
  497. package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
  498. package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
  499. package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
  500. package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
  501. package/templates/AGENTS.md +8 -7
  502. package/dist/client/runtime-discovery.d.ts +0 -15
  503. package/dist/client/runtime-discovery.d.ts.map +0 -1
  504. package/dist/client/runtime-discovery.js +0 -45
  505. package/dist/client/runtime-discovery.js.map +0 -1
  506. package/dist/commands/call.d.ts +0 -7
  507. package/dist/commands/call.d.ts.map +0 -1
  508. package/dist/commands/call.js +0 -10
  509. package/dist/commands/call.js.map +0 -1
  510. package/dist/commands/link.d.ts +0 -6
  511. package/dist/commands/link.d.ts.map +0 -1
  512. package/dist/commands/link.js +0 -6
  513. package/dist/commands/link.js.map +0 -1
  514. package/dist/commands/promote.d.ts +0 -6
  515. package/dist/commands/promote.d.ts.map +0 -1
  516. package/dist/commands/promote.js +0 -6
  517. package/dist/commands/promote.js.map +0 -1
  518. package/dist/commands/read.d.ts +0 -6
  519. package/dist/commands/read.d.ts.map +0 -1
  520. package/dist/commands/read.js +0 -4
  521. package/dist/commands/read.js.map +0 -1
  522. package/dist/commands/recall.d.ts +0 -6
  523. package/dist/commands/recall.d.ts.map +0 -1
  524. package/dist/commands/recall.js +0 -4
  525. package/dist/commands/recall.js.map +0 -1
  526. package/dist/commands/record.d.ts +0 -6
  527. package/dist/commands/record.d.ts.map +0 -1
  528. package/dist/commands/record.js +0 -4
  529. package/dist/commands/record.js.map +0 -1
  530. package/dist/commands/search.d.ts +0 -6
  531. package/dist/commands/search.d.ts.map +0 -1
  532. package/dist/commands/search.js +0 -4
  533. package/dist/commands/search.js.map +0 -1
  534. package/dist/commands/supersede.d.ts +0 -6
  535. package/dist/commands/supersede.d.ts.map +0 -1
  536. package/dist/commands/supersede.js +0 -6
  537. package/dist/commands/supersede.js.map +0 -1
  538. package/dist/knowledge/sources.d.ts +0 -72
  539. package/dist/knowledge/sources.d.ts.map +0 -1
  540. package/dist/knowledge/sources.js +0 -388
  541. package/dist/knowledge/sources.js.map +0 -1
  542. package/dist/setup/opencode-evidence.d.ts +0 -37
  543. package/dist/setup/opencode-evidence.d.ts.map +0 -1
  544. package/dist/setup/opencode-evidence.js +0 -58
  545. package/dist/setup/opencode-evidence.js.map +0 -1
  546. package/dist/setup/opencode-loop-guard.d.ts +0 -9
  547. package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
  548. package/dist/setup/opencode-loop-guard.js +0 -248
  549. package/dist/setup/opencode-loop-guard.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,10 +1,13 @@
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';
6
8
  import { searchEntries, recallEntries } from './memory/retrieval.js';
7
9
  import { readEntry, recordEntry } from './memory/entries.js';
10
+ import { recallScopedMemory } from './memory/scoped-memory.js';
8
11
  import { promoteEntry, supersedeEntry, linkEntries } from './memory/lifecycle.js';
9
12
  import { purgeEntry } from './commands/purge.js';
10
13
  import { createBackup } from './commands/backup.js';
@@ -18,41 +21,153 @@ import { startWebServer } from './web/server.js';
18
21
  import { registerServerCommands } from './commands/server.js';
19
22
  import { registerAgentCommand } from './commands/agent.js';
20
23
  import { registerLedgerCommands } from './commands/ledger.js';
21
- import { answerAkinator, getAkinatorContext, startAkinator } from './akinator/orchestrator.js';
22
- import { parseSetupClients, promptSetupClients, setupGlobalClients } from './commands/setup.js';
24
+ import { answerAkinator, startAkinator } from './akinator/orchestrator.js';
25
+ import { parseSetupClients, parseSetupSkillDiscoveryMode, promptCommunitySkillDiscovery, promptSetupClients, promptSetupConfiguration, setupGlobalClients, } from './commands/setup.js';
23
26
  import { runMcpServer } from './mcp/server.js';
24
27
  import { runCuratorCommand } from './commands/curator.js';
25
28
  import { globalizeCuratorCandidate } from './memory/curator.js';
26
29
  import { detectInstalledClients } from './setup/client-detection.js';
27
- const packageMetadata = createRequire(import.meta.url)('../package.json');
28
- if (typeof packageMetadata.version !== 'string' || packageMetadata.version.length === 0) {
29
- throw new Error('Kiokuko package version is unavailable');
30
+ import { registerSkillsCommands } from './commands/skills.js';
31
+ import { normalizeSkillDiscoveryMode, SKILL_DISCOVERY_ENV } from './skills/config.js';
32
+ import { PACKAGE_VERSION } from './package-version.js';
33
+ import { parseStrictJson } from './setup/strict-json.js';
34
+ import { validateRecordInput } from './serialization/validate.js';
35
+ const MAX_CLI_JSON_INPUT_BYTES = 2 * 1024 * 1024;
36
+ const MAX_CALL_PATH_BYTES = 4 * 1024;
37
+ const CONTROL_CHARACTERS = /\p{Cc}/u;
38
+ function invalidJsonInput() {
39
+ return new KiokukoError('VALIDATION_ERROR', 'Input is not valid JSON with unique keys');
40
+ }
41
+ async function readBoundedStdin() {
42
+ if (process.stdin.readableEncoding !== null || process.stdin.readableDidRead) {
43
+ throw invalidJsonInput();
44
+ }
45
+ const chunks = [];
46
+ let size = 0;
47
+ for await (const chunk of process.stdin) {
48
+ if (!Buffer.isBuffer(chunk))
49
+ throw invalidJsonInput();
50
+ const bytes = chunk;
51
+ size += bytes.byteLength;
52
+ if (size > MAX_CLI_JSON_INPUT_BYTES)
53
+ throw invalidJsonInput();
54
+ chunks.push(bytes);
55
+ }
56
+ return Buffer.concat(chunks);
57
+ }
58
+ function filesystemErrorCode(error) {
59
+ if ((typeof error !== 'object' && typeof error !== 'function') || error === null || isProxy(error)) {
60
+ return undefined;
61
+ }
62
+ const descriptor = Object.getOwnPropertyDescriptor(error, 'code');
63
+ return descriptor !== undefined && 'value' in descriptor && typeof descriptor.value === 'string'
64
+ ? descriptor.value
65
+ : undefined;
66
+ }
67
+ async function readBoundedJsonFile(filePath) {
68
+ let handle;
69
+ try {
70
+ handle = await open(filePath, fsConstants.O_RDONLY | fsConstants.O_NONBLOCK);
71
+ }
72
+ catch (error) {
73
+ if (filesystemErrorCode(error) === 'ENOENT' || filesystemErrorCode(error) === 'ENOTDIR') {
74
+ throw new KiokukoError('NOT_FOUND', 'JSON input file does not exist');
75
+ }
76
+ throw error;
77
+ }
78
+ let result;
79
+ let operationFailed = false;
80
+ let operationError;
81
+ try {
82
+ const initial = await handle.stat({ bigint: true });
83
+ if (!initial.isFile()) {
84
+ throw invalidJsonInput();
85
+ }
86
+ if (initial.size < 0n || initial.size > BigInt(MAX_CLI_JSON_INPUT_BYTES)) {
87
+ throw invalidJsonInput();
88
+ }
89
+ const expectedSize = Number(initial.size);
90
+ const bytes = Buffer.allocUnsafe(expectedSize + 1);
91
+ let offset = 0;
92
+ while (offset < bytes.byteLength) {
93
+ const read = await handle.read(bytes, offset, bytes.byteLength - offset, offset);
94
+ if (read.bytesRead === 0)
95
+ break;
96
+ offset += read.bytesRead;
97
+ }
98
+ const final = await handle.stat({ bigint: true });
99
+ if (offset !== expectedSize
100
+ || final.size !== initial.size
101
+ || final.dev !== initial.dev
102
+ || final.ino !== initial.ino
103
+ || final.mtimeNs !== initial.mtimeNs
104
+ || final.ctimeNs !== initial.ctimeNs) {
105
+ throw new KiokukoError('CONFLICT', 'JSON input file changed while it was being read');
106
+ }
107
+ result = bytes.subarray(0, offset);
108
+ }
109
+ catch (error) {
110
+ operationFailed = true;
111
+ operationError = error;
112
+ }
113
+ try {
114
+ await handle.close();
115
+ }
116
+ catch (closeError) {
117
+ if (operationFailed) {
118
+ throw new AggregateError([operationError, closeError], 'JSON input read failed and its file descriptor could not be closed');
119
+ }
120
+ throw new AggregateError([closeError], 'JSON input was read, but its file descriptor could not be closed');
121
+ }
122
+ if (operationFailed) {
123
+ if (operationError instanceof KiokukoError && operationError.code === 'VALIDATION_ERROR') {
124
+ throw operationError;
125
+ }
126
+ throw operationError;
127
+ }
128
+ if (result === undefined)
129
+ throw invalidJsonInput();
130
+ return result;
30
131
  }
31
- const packageVersion = packageMetadata.version;
32
132
  async function readJsonInput(filePath) {
33
- const text = filePath === '-' ? await new Promise((resolve, reject) => {
34
- let value = '';
35
- process.stdin.setEncoding('utf8');
36
- process.stdin.on('data', (chunk) => { value += chunk; });
37
- process.stdin.on('end', () => resolve(value));
38
- process.stdin.on('error', reject);
39
- }) : await readFile(filePath, 'utf8');
133
+ const bytes = filePath === '-' ? await readBoundedStdin() : await readBoundedJsonFile(filePath);
134
+ let text;
40
135
  try {
41
- return JSON.parse(text);
136
+ text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes);
42
137
  }
43
138
  catch {
44
- throw new KiokukoError('VALIDATION_ERROR', 'Input is not valid JSON');
139
+ throw invalidJsonInput();
45
140
  }
141
+ return parseStrictJson(text, { allowTrailingComma: false, disallowComments: true, allowEmptyContent: false }, 'Input is not valid JSON with unique keys');
46
142
  }
47
143
  async function withDatabase(operation) {
48
144
  const result = await initializeDatabase();
49
145
  const database = openConnection(result.databasePath);
146
+ let operationResult;
147
+ let operationFailed = false;
148
+ let operationError;
50
149
  try {
51
- return await operation(database);
150
+ operationResult = { value: await operation(database) };
151
+ }
152
+ catch (error) {
153
+ operationFailed = true;
154
+ operationError = error;
52
155
  }
53
- finally {
156
+ try {
54
157
  database.close();
55
158
  }
159
+ catch (closeError) {
160
+ if (operationFailed) {
161
+ throw new AggregateError([operationError, closeError], 'Database operation failed and closing its connection also failed');
162
+ }
163
+ throw new AggregateError([closeError], 'Database operation completed, but closing its connection failed');
164
+ }
165
+ if (operationFailed)
166
+ throw operationError;
167
+ if (operationResult === undefined) {
168
+ throw new KiokukoError('INTEGRITY_ERROR', 'Database operation produced no result');
169
+ }
170
+ return operationResult.value;
56
171
  }
57
172
  function emit(value) {
58
173
  process.stdout.write(`${JSON.stringify(value)}\n`);
@@ -74,102 +189,401 @@ function parseExpectedRevision(value) {
74
189
  function addWorkspaceOptions(command) {
75
190
  return command.option('--workspace <name>', 'Workspace name').option('--json', 'Emit a JSON response');
76
191
  }
77
- async function dispatchRequest(request) {
78
- if (typeof request !== 'object' || request === null || Array.isArray(request))
79
- throw new KiokukoError('VALIDATION_ERROR', 'Request must be a JSON object');
80
- const value = request;
81
- if (value.apiVersion !== '1')
192
+ function configureRecallCommand(command) {
193
+ const recall = addWorkspaceOptions(command.description('Human/operator management: recall relevant memory entries').argument('<query>'))
194
+ .option('--limit <number>', 'Maximum entries', '5').option('--max-chars <number>', 'Context character budget', '8000')
195
+ .option('--scope <scope>', 'auto, project, ecosystem, or global', 'auto').option('--cwd <path>', 'Repository path used for scoped recall');
196
+ recall.action(async (query, options) => {
197
+ let data;
198
+ if (options.workspace !== undefined) {
199
+ data = await withDatabase((database) => recallEntries(database, { workspace: String(options.workspace), query, limit: Number(options.limit), maxChars: Number(options.maxChars) }));
200
+ }
201
+ else {
202
+ data = await withDatabase((database) => recallScopedMemory(database, {
203
+ query,
204
+ scope: String(options.scope ?? 'auto'),
205
+ limit: Number(options.limit),
206
+ maxChars: Number(options.maxChars),
207
+ ...(typeof options.cwd === 'string' ? { cwd: options.cwd } : {}),
208
+ }));
209
+ }
210
+ const items = 'items' in data ? data.items : data.combined?.items ?? data.ecosystem?.items ?? data.global?.items ?? data.project?.memory.items ?? [];
211
+ const count = 'count' in data ? data.count : items.length;
212
+ const truncated = 'truncated' in data ? data.truncated : data.combined?.truncated ?? data.ecosystem?.truncated ?? false;
213
+ humanOrJson(options.json === true, 'recall', data, `${items.length} memory entries recalled`, { count, truncated });
214
+ });
215
+ return recall;
216
+ }
217
+ const CALL_OPERATIONS = [
218
+ 'init',
219
+ 'use',
220
+ 'record',
221
+ 'curator',
222
+ 'curator_globalize',
223
+ 'guide_start',
224
+ 'guide_answer',
225
+ 'promote',
226
+ 'supersede',
227
+ 'link',
228
+ 'purge',
229
+ 'export',
230
+ 'import',
231
+ 'backup',
232
+ 'doctor',
233
+ ];
234
+ const SUPPORTED_CALL_OPERATIONS = new Set(CALL_OPERATIONS);
235
+ function snapshotPlainJsonObject(value, message) {
236
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
237
+ throw new KiokukoError('VALIDATION_ERROR', message);
238
+ }
239
+ const prototype = Object.getPrototypeOf(value);
240
+ if (prototype !== Object.prototype && prototype !== null) {
241
+ throw new KiokukoError('VALIDATION_ERROR', message);
242
+ }
243
+ const result = Object.create(null);
244
+ for (const key of Reflect.ownKeys(value)) {
245
+ if (typeof key !== 'string')
246
+ throw new KiokukoError('VALIDATION_ERROR', message);
247
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
248
+ if (descriptor === undefined || !('value' in descriptor) || descriptor.enumerable !== true) {
249
+ throw new KiokukoError('VALIDATION_ERROR', message);
250
+ }
251
+ Object.defineProperty(result, key, {
252
+ value: descriptor.value,
253
+ enumerable: true,
254
+ writable: true,
255
+ configurable: true,
256
+ });
257
+ }
258
+ return result;
259
+ }
260
+ function assertExactCallArguments(args, operation, allowed, required = []) {
261
+ const allowedFields = new Set(allowed);
262
+ for (const field of Object.keys(args)) {
263
+ if (!allowedFields.has(field)) {
264
+ throw new KiokukoError('VALIDATION_ERROR', `Unknown ${operation} argument: ${field}`);
265
+ }
266
+ }
267
+ for (const field of required) {
268
+ if (!Object.hasOwn(args, field)) {
269
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} is required`);
270
+ }
271
+ }
272
+ }
273
+ function requiredStringArgument(args, operation, field) {
274
+ const value = args[field];
275
+ if (typeof value !== 'string' || value.trim().length === 0) {
276
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a non-empty string`);
277
+ }
278
+ return value;
279
+ }
280
+ function optionalStringArgument(args, operation, field) {
281
+ return Object.hasOwn(args, field) ? requiredStringArgument(args, operation, field) : undefined;
282
+ }
283
+ function requiredPathArgument(args, operation, field) {
284
+ const value = requiredStringArgument(args, operation, field);
285
+ if (CONTROL_CHARACTERS.test(value) || Buffer.byteLength(value, 'utf8') > MAX_CALL_PATH_BYTES) {
286
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a bounded path without control characters`);
287
+ }
288
+ return value;
289
+ }
290
+ function optionalPathArgument(args, operation, field) {
291
+ return Object.hasOwn(args, field) ? requiredPathArgument(args, operation, field) : undefined;
292
+ }
293
+ function requiredBooleanArgument(args, operation, field) {
294
+ const value = args[field];
295
+ if (typeof value !== 'boolean') {
296
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a boolean`);
297
+ }
298
+ return value;
299
+ }
300
+ function optionalBooleanArgument(args, operation, field) {
301
+ return Object.hasOwn(args, field) ? requiredBooleanArgument(args, operation, field) : undefined;
302
+ }
303
+ function requiredPositiveIntegerArgument(args, operation, field) {
304
+ const value = args[field];
305
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) {
306
+ throw new KiokukoError('VALIDATION_ERROR', `${operation}.${field} must be a positive integer`);
307
+ }
308
+ return value;
309
+ }
310
+ function validateUseCallArguments(args) {
311
+ const operation = 'use';
312
+ assertExactCallArguments(args, operation, [
313
+ 'cwd',
314
+ 'root',
315
+ 'workspace',
316
+ 'agentFile',
317
+ 'dryRun',
318
+ 'noAgentFile',
319
+ 'forceRebind',
320
+ 'allowDirectory',
321
+ 'databasePath',
322
+ 'migrationsDirectory',
323
+ 'repositoryId',
324
+ ]);
325
+ const result = {};
326
+ const cwd = optionalPathArgument(args, operation, 'cwd');
327
+ const root = optionalPathArgument(args, operation, 'root');
328
+ const workspace = optionalStringArgument(args, operation, 'workspace');
329
+ const agentFile = optionalPathArgument(args, operation, 'agentFile');
330
+ const databasePath = optionalPathArgument(args, operation, 'databasePath');
331
+ const migrationsDirectory = optionalPathArgument(args, operation, 'migrationsDirectory');
332
+ const repositoryId = optionalStringArgument(args, operation, 'repositoryId');
333
+ const dryRun = optionalBooleanArgument(args, operation, 'dryRun');
334
+ const noAgentFile = optionalBooleanArgument(args, operation, 'noAgentFile');
335
+ const forceRebind = optionalBooleanArgument(args, operation, 'forceRebind');
336
+ const allowDirectory = optionalBooleanArgument(args, operation, 'allowDirectory');
337
+ if (cwd !== undefined)
338
+ result.cwd = cwd;
339
+ if (root !== undefined)
340
+ result.root = root;
341
+ if (workspace !== undefined)
342
+ result.workspace = workspace;
343
+ if (agentFile !== undefined)
344
+ result.agentFile = agentFile;
345
+ if (databasePath !== undefined)
346
+ result.databasePath = databasePath;
347
+ if (migrationsDirectory !== undefined)
348
+ result.migrationsDirectory = migrationsDirectory;
349
+ if (repositoryId !== undefined)
350
+ result.repositoryId = repositoryId;
351
+ if (dryRun !== undefined)
352
+ result.dryRun = dryRun;
353
+ if (noAgentFile !== undefined)
354
+ result.noAgentFile = noAgentFile;
355
+ if (forceRebind !== undefined)
356
+ result.forceRebind = forceRebind;
357
+ if (allowDirectory !== undefined)
358
+ result.allowDirectory = allowDirectory;
359
+ return result;
360
+ }
361
+ function validateRecordCallArguments(args) {
362
+ return validateRecordInput(args);
363
+ }
364
+ function validateCuratorCallArguments(args) {
365
+ const operation = 'curator';
366
+ assertExactCallArguments(args, operation, ['workspace', 'cwd', 'limit', 'entryId', 'yes']);
367
+ const workspace = optionalStringArgument(args, operation, 'workspace');
368
+ const cwd = optionalPathArgument(args, operation, 'cwd');
369
+ const entryId = optionalStringArgument(args, operation, 'entryId');
370
+ const yes = optionalBooleanArgument(args, operation, 'yes');
371
+ const limit = Object.hasOwn(args, 'limit')
372
+ ? requiredPositiveIntegerArgument(args, operation, 'limit')
373
+ : undefined;
374
+ if (limit !== undefined && limit > 50) {
375
+ throw new KiokukoError('VALIDATION_ERROR', 'curator.limit must be an integer between 1 and 50');
376
+ }
377
+ return {
378
+ ...(workspace === undefined ? {} : { workspace }),
379
+ ...(cwd === undefined ? {} : { cwd }),
380
+ ...(limit === undefined ? {} : { limit }),
381
+ ...(entryId === undefined ? {} : { entryId }),
382
+ ...(yes === undefined ? {} : { yes }),
383
+ };
384
+ }
385
+ function validateCuratorGlobalizeCallArguments(args) {
386
+ const operation = 'curator_globalize';
387
+ assertExactCallArguments(args, operation, ['workspace', 'entryId', 'expectedRevision', 'actor'], ['workspace', 'entryId', 'expectedRevision']);
388
+ const actor = optionalStringArgument(args, operation, 'actor');
389
+ return {
390
+ workspace: requiredStringArgument(args, operation, 'workspace'),
391
+ entryId: requiredStringArgument(args, operation, 'entryId'),
392
+ expectedRevision: requiredPositiveIntegerArgument(args, operation, 'expectedRevision'),
393
+ ...(actor === undefined ? {} : { actor }),
394
+ };
395
+ }
396
+ function validateGuideStartCallArguments(args) {
397
+ const operation = 'guide_start';
398
+ assertExactCallArguments(args, operation, ['workspace', 'task'], ['workspace', 'task']);
399
+ return {
400
+ workspace: requiredStringArgument(args, operation, 'workspace'),
401
+ task: requiredStringArgument(args, operation, 'task'),
402
+ };
403
+ }
404
+ function validateGuideAnswerCallArguments(args) {
405
+ const operation = 'guide_answer';
406
+ assertExactCallArguments(args, operation, ['workspace', 'sessionId', 'questionId', 'value'], ['workspace', 'sessionId', 'questionId', 'value']);
407
+ const questionId = requiredStringArgument(args, operation, 'questionId');
408
+ if (!['taskType', 'target', 'expected', 'constraints'].includes(questionId)) {
409
+ throw new KiokukoError('VALIDATION_ERROR', 'guide_answer.questionId is unsupported');
410
+ }
411
+ return {
412
+ workspace: requiredStringArgument(args, operation, 'workspace'),
413
+ sessionId: requiredStringArgument(args, operation, 'sessionId'),
414
+ questionId: questionId,
415
+ value: requiredStringArgument(args, operation, 'value'),
416
+ };
417
+ }
418
+ function validatePromoteCallArguments(args) {
419
+ const operation = 'promote';
420
+ assertExactCallArguments(args, operation, ['workspace', 'entryId', 'expectedRevision'], ['workspace', 'entryId', 'expectedRevision']);
421
+ return {
422
+ workspace: requiredStringArgument(args, operation, 'workspace'),
423
+ entryId: requiredStringArgument(args, operation, 'entryId'),
424
+ expectedRevision: requiredPositiveIntegerArgument(args, operation, 'expectedRevision'),
425
+ };
426
+ }
427
+ function validateSupersedeCallArguments(args) {
428
+ const operation = 'supersede';
429
+ assertExactCallArguments(args, operation, ['workspace', 'oldEntryId', 'replacementEntryId', 'expectedRevision'], ['workspace', 'oldEntryId', 'replacementEntryId', 'expectedRevision']);
430
+ return {
431
+ workspace: requiredStringArgument(args, operation, 'workspace'),
432
+ oldEntryId: requiredStringArgument(args, operation, 'oldEntryId'),
433
+ replacementEntryId: requiredStringArgument(args, operation, 'replacementEntryId'),
434
+ expectedRevision: requiredPositiveIntegerArgument(args, operation, 'expectedRevision'),
435
+ };
436
+ }
437
+ function validateLinkCallArguments(args) {
438
+ const operation = 'link';
439
+ assertExactCallArguments(args, operation, ['workspace', 'fromEntryId', 'toEntryId', 'relation', 'actor', 'now'], ['workspace', 'fromEntryId', 'toEntryId', 'relation']);
440
+ const relation = requiredStringArgument(args, operation, 'relation');
441
+ if (!['supports', 'contradicts', 'derived_from', 'related_to'].includes(relation)) {
442
+ throw new KiokukoError('VALIDATION_ERROR', 'link.relation is unsupported');
443
+ }
444
+ const actor = optionalStringArgument(args, operation, 'actor');
445
+ const now = optionalStringArgument(args, operation, 'now');
446
+ return {
447
+ workspace: requiredStringArgument(args, operation, 'workspace'),
448
+ fromEntryId: requiredStringArgument(args, operation, 'fromEntryId'),
449
+ toEntryId: requiredStringArgument(args, operation, 'toEntryId'),
450
+ relation: relation,
451
+ ...(actor === undefined ? {} : { actor }),
452
+ ...(now === undefined ? {} : { now }),
453
+ };
454
+ }
455
+ function validatePurgeCallArguments(args) {
456
+ const operation = 'purge';
457
+ assertExactCallArguments(args, operation, ['workspace', 'entryId', 'confirm'], ['workspace', 'entryId', 'confirm']);
458
+ return {
459
+ workspace: requiredStringArgument(args, operation, 'workspace'),
460
+ entryId: requiredStringArgument(args, operation, 'entryId'),
461
+ confirm: requiredBooleanArgument(args, operation, 'confirm'),
462
+ };
463
+ }
464
+ function parseCallRequest(request) {
465
+ const value = snapshotPlainJsonObject(request, 'Request must be a JSON object');
466
+ const fields = Object.keys(value).sort();
467
+ if (fields.length !== 3
468
+ || fields[0] !== 'apiVersion'
469
+ || fields[1] !== 'arguments'
470
+ || fields[2] !== 'operation') {
471
+ throw new KiokukoError('VALIDATION_ERROR', 'Request must contain exactly apiVersion, operation, and arguments');
472
+ }
473
+ if (value.apiVersion !== '1') {
82
474
  throw new KiokukoError('VALIDATION_ERROR', 'apiVersion must be "1"');
83
- if (typeof value.operation !== 'string' || value.operation.length === 0)
475
+ }
476
+ if (typeof value.operation !== 'string' || value.operation.length === 0) {
84
477
  throw new KiokukoError('VALIDATION_ERROR', 'operation must be a non-empty string');
85
- const args = typeof value.arguments === 'object' && value.arguments !== null && !Array.isArray(value.arguments) ? value.arguments : {};
86
- const operation = value.operation;
87
- if (operation === 'init')
478
+ }
479
+ const args = snapshotPlainJsonObject(value.arguments, 'arguments must be a JSON object');
480
+ if (!SUPPORTED_CALL_OPERATIONS.has(value.operation)) {
481
+ throw new KiokukoError('VALIDATION_ERROR', `Unknown operation: ${value.operation}`);
482
+ }
483
+ return {
484
+ apiVersion: '1',
485
+ operation: value.operation,
486
+ arguments: args,
487
+ };
488
+ }
489
+ async function dispatchRequest(request) {
490
+ const args = request.arguments;
491
+ const operation = request.operation;
492
+ if (operation === 'init') {
493
+ assertExactCallArguments(args, operation, []);
88
494
  return initializeDatabase();
495
+ }
89
496
  if (operation === 'use')
90
- return useRepository(args);
91
- if (operation === 'record')
92
- return withDatabase((database) => recordEntry(database, args));
93
- if (operation === 'read')
94
- return withDatabase((database) => readEntry(database, { workspace: String(args.workspace ?? ''), entryId: String(args.entryId ?? '') }));
95
- if (operation === 'search')
96
- return withDatabase((database) => searchEntries(database, args));
97
- if (operation === 'recall')
98
- return withDatabase((database) => recallEntries(database, args));
99
- if (operation === 'curator')
100
- return withDatabase((database) => runCuratorCommand(database, {
101
- ...(typeof args.workspace === 'string' ? { workspace: args.workspace } : {}),
102
- ...(typeof args.cwd === 'string' ? { cwd: args.cwd } : {}),
103
- ...(typeof args.limit === 'number' ? { limit: args.limit } : {}),
104
- ...(typeof args.entryId === 'string' ? { entryId: args.entryId } : {}),
105
- yes: args.yes === true,
106
- json: true,
107
- }));
108
- if (operation === 'curator_globalize')
109
- return withDatabase((database) => globalizeCuratorCandidate(database, {
110
- workspace: String(args.workspace ?? ''),
111
- entryId: String(args.entryId ?? ''),
112
- expectedRevision: Number(args.expectedRevision),
113
- ...(typeof args.actor === 'string' ? { actor: args.actor } : {}),
114
- }));
115
- if (operation === 'guide_start')
116
- return withDatabase((database) => startAkinator(database, {
117
- workspace: String(args.workspace ?? ''),
118
- task: String(args.task ?? ''),
119
- }));
120
- if (operation === 'guide_answer')
121
- return withDatabase((database) => answerAkinator(database, {
122
- workspace: String(args.workspace ?? ''),
123
- sessionId: String(args.sessionId ?? ''),
124
- questionId: String(args.questionId ?? ''),
125
- value: String(args.value ?? ''),
126
- }));
127
- if (operation === 'guide_context')
128
- return withDatabase((database) => getAkinatorContext(database, {
129
- workspace: String(args.workspace ?? ''),
130
- sessionId: String(args.sessionId ?? ''),
131
- }));
132
- if (operation === 'promote')
133
- return withDatabase((database) => promoteEntry(database, { workspace: String(args.workspace ?? ''), entryId: String(args.entryId ?? ''), expectedRevision: Number(args.expectedRevision) }));
134
- if (operation === 'supersede')
135
- return withDatabase((database) => supersedeEntry(database, { workspace: String(args.workspace ?? ''), oldEntryId: String(args.oldEntryId ?? ''), replacementEntryId: String(args.replacementEntryId ?? ''), expectedRevision: Number(args.expectedRevision) }));
136
- if (operation === 'link')
137
- return withDatabase((database) => { linkEntries(database, args); return { linked: true }; });
138
- if (operation === 'purge')
139
- return withDatabase((database) => { purgeEntry(database, { workspace: String(args.workspace ?? ''), entryId: String(args.entryId ?? ''), confirm: args.confirm === true }); return { purged: true }; });
497
+ return useRepository(validateUseCallArguments(args));
498
+ if (operation === 'record') {
499
+ const input = validateRecordCallArguments(args);
500
+ return withDatabase((database) => recordEntry(database, input));
501
+ }
502
+ if (operation === 'curator') {
503
+ const input = validateCuratorCallArguments(args);
504
+ return withDatabase((database) => runCuratorCommand(database, { ...input, json: true }));
505
+ }
506
+ if (operation === 'curator_globalize') {
507
+ const input = validateCuratorGlobalizeCallArguments(args);
508
+ return withDatabase((database) => globalizeCuratorCandidate(database, input));
509
+ }
510
+ if (operation === 'guide_start') {
511
+ const input = validateGuideStartCallArguments(args);
512
+ return withDatabase((database) => startAkinator(database, input));
513
+ }
514
+ if (operation === 'guide_answer') {
515
+ const input = validateGuideAnswerCallArguments(args);
516
+ return withDatabase((database) => answerAkinator(database, input));
517
+ }
518
+ if (operation === 'promote') {
519
+ const input = validatePromoteCallArguments(args);
520
+ return withDatabase((database) => promoteEntry(database, input));
521
+ }
522
+ if (operation === 'supersede') {
523
+ const input = validateSupersedeCallArguments(args);
524
+ return withDatabase((database) => supersedeEntry(database, input));
525
+ }
526
+ if (operation === 'link') {
527
+ const input = validateLinkCallArguments(args);
528
+ return withDatabase((database) => {
529
+ linkEntries(database, input);
530
+ return { linked: true };
531
+ });
532
+ }
533
+ if (operation === 'purge') {
534
+ const input = validatePurgeCallArguments(args);
535
+ return withDatabase((database) => {
536
+ purgeEntry(database, input);
537
+ return { purged: true };
538
+ });
539
+ }
140
540
  if (operation === 'export') {
141
- const workspace = String(args.workspace ?? '');
142
- const output = String(args.output ?? '');
143
- if (output.length === 0)
541
+ assertExactCallArguments(args, operation, ['workspace', 'output']);
542
+ if (!Object.hasOwn(args, 'output')) {
144
543
  throw new KiokukoError('VALIDATION_ERROR', 'export output is required');
544
+ }
545
+ const workspace = requiredStringArgument(args, operation, 'workspace');
546
+ const output = requiredPathArgument(args, operation, 'output');
145
547
  return withDatabase((database) => writeExport(database, { workspace, output }));
146
548
  }
147
549
  if (operation === 'import') {
148
- const input = String(args.input ?? '');
149
- if (input.length === 0)
550
+ assertExactCallArguments(args, operation, ['input', 'workspace', 'dryRun']);
551
+ if (!Object.hasOwn(args, 'input')) {
150
552
  throw new KiokukoError('VALIDATION_ERROR', 'import input is required');
151
- const importOptions = { input, dryRun: args.dryRun === true };
152
- if (typeof args.workspace === 'string')
153
- importOptions.workspace = args.workspace;
154
- return args.dryRun === true ? importWorkspace(undefined, importOptions) : withDatabase((database) => importWorkspace(database, importOptions));
553
+ }
554
+ const input = requiredPathArgument(args, operation, 'input');
555
+ const workspace = optionalStringArgument(args, operation, 'workspace');
556
+ const dryRun = optionalBooleanArgument(args, operation, 'dryRun');
557
+ const importOptions = {
558
+ input,
559
+ ...(workspace === undefined ? {} : { workspace }),
560
+ ...(dryRun === undefined ? {} : { dryRun }),
561
+ };
562
+ return dryRun === true
563
+ ? importWorkspace(undefined, importOptions)
564
+ : withDatabase((database) => importWorkspace(database, importOptions));
155
565
  }
156
566
  if (operation === 'backup') {
157
- const output = String(args.output ?? '');
158
- if (output.length === 0)
567
+ assertExactCallArguments(args, operation, ['output']);
568
+ if (!Object.hasOwn(args, 'output')) {
159
569
  throw new KiokukoError('VALIDATION_ERROR', 'backup output is required');
570
+ }
571
+ const output = requiredPathArgument(args, operation, 'output');
160
572
  return createBackup(output);
161
573
  }
162
- if (operation === 'doctor')
574
+ if (operation === 'doctor') {
575
+ assertExactCallArguments(args, operation, []);
163
576
  return runDoctor();
164
- throw new KiokukoError('VALIDATION_ERROR', `Unknown operation: ${operation}`);
577
+ }
578
+ throw new KiokukoError('INTEGRITY_ERROR', 'Supported call operation has no dispatcher');
165
579
  }
166
580
  export function buildCli(dependencies = {}) {
167
581
  const cli = new Command();
168
- cli.name('kiokuko').description('Model-agnostic external memory for AI coding agents').version(packageVersion);
582
+ cli.name('kiokuko').description('Model-agnostic external memory for AI coding agents').version(PACKAGE_VERSION);
169
583
  cli.exitOverride();
170
584
  cli.configureOutput({ outputError: () => undefined });
171
585
  cli.command('version').description('Show the Kiokuko package version').action(() => {
172
- process.stdout.write(`${packageVersion}\n`);
586
+ process.stdout.write(`${PACKAGE_VERSION}\n`);
173
587
  });
174
588
  cli.command('init').description('Initialize the global Kiokuko database').option('--json').action(async (options) => {
175
589
  const result = await initializeDatabase();
@@ -181,35 +595,49 @@ export function buildCli(dependencies = {}) {
181
595
  .option('--command <path>', 'Kiokuko executable name or absolute path', 'kiokuko')
182
596
  .option('--dry-run', 'Validate and show planned changes without writing')
183
597
  .option('--no-standard-skills', 'Skip installing bundled Kiokuko standard skills')
184
- .option('--opencode-capture <profile>', 'OpenCode evidence capture: off,minimal,standard', 'off')
185
- .option('--opencode-mode <mode>', 'OpenCode prepare enforcement: advisory,strict', 'advisory')
598
+ .option('--skill-discovery <mode>', 'External Skill discovery: off,official,community')
186
599
  .option('--json', 'Emit a JSON response')
187
600
  .action(async (options) => {
188
- if (!['off', 'minimal', 'standard'].includes(options.opencodeCapture))
189
- throw new KiokukoError('VALIDATION_ERROR', 'opencode capture must be off, minimal, or standard');
190
- if (!['advisory', 'strict'].includes(options.opencodeMode))
191
- throw new KiokukoError('VALIDATION_ERROR', 'opencode mode must be advisory or strict');
601
+ const optionSkillDiscoveryMode = options.skillDiscovery === undefined
602
+ ? undefined
603
+ : parseSetupSkillDiscoveryMode(options.skillDiscovery);
192
604
  const setupEnvironment = dependencies.setupEnvironment ?? {};
605
+ const setupProcessEnvironment = setupEnvironment.env ?? process.env;
606
+ const environmentSkillDiscoveryMode = optionSkillDiscoveryMode === undefined
607
+ && Object.prototype.hasOwnProperty.call(setupProcessEnvironment, SKILL_DISCOVERY_ENV)
608
+ ? normalizeSkillDiscoveryMode(setupProcessEnvironment[SKILL_DISCOVERY_ENV])
609
+ : undefined;
610
+ const requestedSkillDiscoveryMode = optionSkillDiscoveryMode ?? environmentSkillDiscoveryMode;
193
611
  const detectedClients = options.clients === undefined ? await detectInstalledClients(setupEnvironment) : [];
194
612
  const setupInput = dependencies.setupInput ?? process.stdin;
195
613
  const setupOutput = dependencies.setupOutput ?? process.stdout;
196
- const interactive = options.clients === undefined
197
- && options.json !== true
614
+ const interactive = options.json !== true
198
615
  && setupInput.isTTY === true
199
616
  && setupOutput.isTTY === true;
200
- const clients = options.clients !== undefined
201
- ? parseSetupClients(options.clients)
202
- : interactive
203
- ? await promptSetupClients(detectedClients, { input: setupInput, output: setupOutput })
204
- : detectedClients;
617
+ let clients;
618
+ let skillDiscoveryMode = requestedSkillDiscoveryMode;
619
+ if (interactive && options.clients === undefined && requestedSkillDiscoveryMode === undefined) {
620
+ const prompted = await promptSetupConfiguration(detectedClients, { input: setupInput, output: setupOutput });
621
+ clients = prompted.clients;
622
+ skillDiscoveryMode = prompted.skillDiscoveryMode;
623
+ }
624
+ else {
625
+ clients = options.clients !== undefined
626
+ ? parseSetupClients(options.clients)
627
+ : interactive
628
+ ? await promptSetupClients(detectedClients, { input: setupInput, output: setupOutput })
629
+ : detectedClients;
630
+ if (interactive && clients.length > 0 && skillDiscoveryMode === undefined) {
631
+ skillDiscoveryMode = await promptCommunitySkillDiscovery({ input: setupInput, output: setupOutput });
632
+ }
633
+ }
205
634
  const data = await setupGlobalClients({
206
635
  ...setupEnvironment,
207
636
  clients,
208
637
  command: options.command,
209
638
  dryRun: options.dryRun === true,
210
639
  standardSkills: options.standardSkills,
211
- opencodeCapture: options.opencodeCapture,
212
- opencodeMode: options.opencodeMode,
640
+ ...(skillDiscoveryMode === undefined ? {} : { skillDiscoveryMode }),
213
641
  });
214
642
  const changed = data.files.filter((file) => file.action !== 'unchanged').length;
215
643
  const clientLabel = data.clients.length === 0 ? 'no detected clients' : data.clients.join(', ');
@@ -224,7 +652,7 @@ export function buildCli(dependencies = {}) {
224
652
  await runMcpServer();
225
653
  });
226
654
  cli.command('use').description('Bind this repository to Kiokuko external memory')
227
- .option('--root <path>').option('--workspace <name>').option('--agent-file <path>', 'Agent instruction file', 'AGENTS.md')
655
+ .option('--root <path>').option('--workspace <name>').option('--agent-file <path>', 'Agent instruction file')
228
656
  .option('--dry-run').option('--no-agent-file').option('--force-rebind').option('--allow-directory').option('--json')
229
657
  .action(async (options) => {
230
658
  const useOptions = {};
@@ -245,14 +673,9 @@ export function buildCli(dependencies = {}) {
245
673
  const result = await useRepository(useOptions);
246
674
  humanOrJson(options.json === true, 'use', result, `Kiokuko enabled for ${result.repositoryRoot}`);
247
675
  });
248
- const recall = addWorkspaceOptions(cli.command('recall').description('Recall relevant memory entries').argument('<query>'))
249
- .option('--limit <number>', 'Maximum entries', '5').option('--max-chars <number>', 'Context character budget', '8000');
250
- recall.action(async (query, options) => {
251
- const data = await withDatabase((database) => recallEntries(database, {
252
- workspace: String(options.workspace ?? ''), query, limit: Number(options.limit), maxChars: Number(options.maxChars),
253
- }));
254
- humanOrJson(options.json === true, 'recall', data, `${data.items.length} memory entries recalled`, { count: data.count, truncated: data.truncated });
255
- });
676
+ configureRecallCommand(cli.command('recall'));
677
+ const memory = cli.command('memory').description('Human/operator memory management');
678
+ configureRecallCommand(memory.command('recall'));
256
679
  const guide = cli.command('guide').description('Run the Akinator-style knowledge and skill intake');
257
680
  guide.command('start').description('Start an intake session').argument('<task>').requiredOption('--workspace <name>').option('--json').action(async (task, options) => {
258
681
  const data = await withDatabase((database) => startAkinator(database, { workspace: options.workspace, task }));
@@ -267,17 +690,7 @@ export function buildCli(dependencies = {}) {
267
690
  }));
268
691
  humanOrJson(options.json, 'guide.answer', data, data.question?.prompt ?? 'Akinator context is ready');
269
692
  });
270
- guide.command('context').description('Build the knowledge and skill context for an intake session').argument('<session-id>').requiredOption('--workspace <name>')
271
- .option('--no-client-skills', 'Allow the mattpocock/skills fallback because the client has no available skills')
272
- .option('--json').action(async (sessionId, options) => {
273
- const data = await withDatabase((database) => getAkinatorContext(database, {
274
- workspace: options.workspace,
275
- sessionId,
276
- ...(options.clientSkills === false ? { allowExternalSkillFallback: true } : {}),
277
- }));
278
- humanOrJson(options.json, 'guide.context', data, `${data.entries.length} knowledge entries selected`);
279
- });
280
- const search = addWorkspaceOptions(cli.command('search').description('Search memory entries').argument('<query>'))
693
+ const search = addWorkspaceOptions(cli.command('search').description('Human/operator management: search memory entries').argument('<query>'))
281
694
  .option('--limit <number>', 'Maximum entries', '20').option('--kind <kind>').option('--status <status>').option('--tag <tag>');
282
695
  search.action(async (query, options) => {
283
696
  const searchOptions = { workspace: String(options.workspace ?? ''), query, limit: Number(options.limit) };
@@ -290,17 +703,16 @@ export function buildCli(dependencies = {}) {
290
703
  const data = await withDatabase((database) => searchEntries(database, searchOptions));
291
704
  humanOrJson(options.json === true, 'search', data, `${data.items.length} memory entries found`, { count: data.count });
292
705
  });
293
- const read = addWorkspaceOptions(cli.command('read').description('Read one memory entry').argument('<entry-id>'));
706
+ const read = addWorkspaceOptions(cli.command('read').description('Human/operator management: read one memory entry').argument('<entry-id>'));
294
707
  read.action(async (entryId, options) => {
295
708
  const data = await withDatabase((database) => readEntry(database, { workspace: String(options.workspace ?? ''), entryId }));
296
709
  humanOrJson(options.json === true, 'read', data, `${data.title}\n${data.body}`);
297
710
  });
298
711
  const record = cli.command('record').description('Record a memory entry').requiredOption('--workspace <name>').requiredOption('--input-json <file>').option('--json');
299
712
  record.action(async (options) => {
300
- const input = await readJsonInput(options.inputJson);
301
- if (typeof input !== 'object' || input === null || Array.isArray(input))
302
- throw new KiokukoError('VALIDATION_ERROR', 'record input must be a JSON object');
303
- const data = await withDatabase((database) => recordEntry(database, { ...input, workspace: options.workspace }));
713
+ const parsed = snapshotPlainJsonObject(await readJsonInput(options.inputJson), 'record input must be a JSON object');
714
+ const input = validateRecordInput({ ...parsed, workspace: options.workspace });
715
+ const data = await withDatabase((database) => recordEntry(database, input));
304
716
  humanOrJson(options.json, 'record', data, `Recorded ${data.id}`);
305
717
  });
306
718
  const promote = cli.command('promote').description('Promote a candidate entry').argument('<entry-id>').requiredOption('--workspace <name>').requiredOption('--expected-revision <number>').option('--json');
@@ -356,6 +768,7 @@ export function buildCli(dependencies = {}) {
356
768
  registerServerCommands(cli, dependencies.server);
357
769
  registerAgentCommand(cli, dependencies.agent);
358
770
  registerLedgerCommands(cli, { withDatabase });
771
+ registerSkillsCommands(cli, dependencies.skills ?? { withDatabase });
359
772
  cli.command('web').description('Start the local Kiokuko web UI')
360
773
  .option('--host <host>', 'Loopback host', '127.0.0.1')
361
774
  .option('--port <number>', 'HTTP port', '4173')
@@ -390,20 +803,17 @@ export function buildCli(dependencies = {}) {
390
803
  : await withDatabase((database) => importWorkspace(database, importOptions));
391
804
  humanOrJson(options.json, 'import', data, `${data.count} records inspected`);
392
805
  });
393
- cli.command('call').description('Process one JSON request').requiredOption('--input-json <file>').option('--json').action(async (options) => {
394
- const request = await readJsonInput(options.inputJson);
395
- const operation = typeof request === 'object' && request !== null && !Array.isArray(request) && typeof request.operation === 'string' ? request.operation : 'unknown';
806
+ cli.command('call').description('Process one management JSON request; memory reads are not supported').requiredOption('--input-json <file>').option('--json').action(async (options) => {
807
+ const request = parseCallRequest(await readJsonInput(options.inputJson));
396
808
  const data = await dispatchRequest(request);
397
- emit(successEnvelope(operation, data));
809
+ emit(successEnvelope(request.operation, data));
398
810
  });
399
811
  return cli;
400
812
  }
401
813
  function operationFor(argv) {
402
814
  const command = argv[2] ?? 'unknown';
403
- if (command === 'server' && argv[3] !== undefined && !argv[3].startsWith('-'))
404
- return `server.${argv[3]}`;
405
- if (command === 'agent' && argv[3] !== undefined && !argv[3].startsWith('-'))
406
- return `agent.${argv[3]}`;
815
+ if (['server', 'agent', 'skills'].includes(command) && argv[3] !== undefined && !argv[3].startsWith('-'))
816
+ return `${command}.${argv[3]}`;
407
817
  return command;
408
818
  }
409
819
  function commanderDiagnostic(error) {
@@ -429,15 +839,22 @@ export async function runCli(argv = process.argv, dependencies = {}) {
429
839
  }
430
840
  catch (error) {
431
841
  if (error instanceof CommanderError) {
842
+ if (error.exitCode === 0)
843
+ return 0;
844
+ if (jsonRequested) {
845
+ emit(errorEnvelope(operation, new KiokukoError('USAGE_ERROR', 'Invalid command-line usage', { commanderCode: error.code })));
846
+ return 2;
847
+ }
432
848
  const diagnostic = commanderDiagnostic(error);
433
849
  if (diagnostic.length > 0)
434
850
  process.stderr.write(diagnostic);
435
- return error.exitCode === 0 ? 0 : 2;
851
+ return 2;
436
852
  }
853
+ const envelope = errorEnvelope(operation, error);
437
854
  if (jsonRequested && !(serveStarted && operation === 'serve'))
438
- emit(errorEnvelope(operation, error));
855
+ emit(envelope);
439
856
  else
440
- process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
857
+ process.stderr.write(`${envelope.error.message}\n`);
441
858
  return exitCodeFor(error);
442
859
  }
443
860
  }