@kynetic-ai/spec 0.1.2 → 0.4.0

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 (540) hide show
  1. package/README.md +250 -17
  2. package/dist/acp/client.d.ts +18 -4
  3. package/dist/acp/client.d.ts.map +1 -1
  4. package/dist/acp/client.js +44 -26
  5. package/dist/acp/client.js.map +1 -1
  6. package/dist/acp/framing.d.ts +2 -2
  7. package/dist/acp/framing.d.ts.map +1 -1
  8. package/dist/acp/framing.js +37 -29
  9. package/dist/acp/framing.js.map +1 -1
  10. package/dist/acp/index.d.ts +6 -7
  11. package/dist/acp/index.d.ts.map +1 -1
  12. package/dist/acp/index.js +3 -3
  13. package/dist/acp/index.js.map +1 -1
  14. package/dist/acp/types.d.ts +5 -5
  15. package/dist/acp/types.d.ts.map +1 -1
  16. package/dist/acp/types.js +18 -18
  17. package/dist/acp/types.js.map +1 -1
  18. package/dist/agents/adapters.d.ts.map +1 -1
  19. package/dist/agents/adapters.js +24 -13
  20. package/dist/agents/adapters.js.map +1 -1
  21. package/dist/agents/index.d.ts +2 -2
  22. package/dist/agents/index.js +2 -2
  23. package/dist/agents/spawner.d.ts +4 -4
  24. package/dist/agents/spawner.d.ts.map +1 -1
  25. package/dist/agents/spawner.js +6 -6
  26. package/dist/agents/spawner.js.map +1 -1
  27. package/dist/cli/batch-context.d.ts +43 -0
  28. package/dist/cli/batch-context.d.ts.map +1 -0
  29. package/dist/cli/batch-context.js +93 -0
  30. package/dist/cli/batch-context.js.map +1 -0
  31. package/dist/cli/batch-exec.d.ts +107 -0
  32. package/dist/cli/batch-exec.d.ts.map +1 -0
  33. package/dist/cli/batch-exec.js +706 -0
  34. package/dist/cli/batch-exec.js.map +1 -0
  35. package/dist/cli/batch.d.ts +4 -2
  36. package/dist/cli/batch.d.ts.map +1 -1
  37. package/dist/cli/batch.js +15 -14
  38. package/dist/cli/batch.js.map +1 -1
  39. package/dist/cli/command-annotations.d.ts +23 -0
  40. package/dist/cli/command-annotations.d.ts.map +1 -0
  41. package/dist/cli/command-annotations.js +27 -0
  42. package/dist/cli/command-annotations.js.map +1 -0
  43. package/dist/cli/commands/agents.d.ts +46 -0
  44. package/dist/cli/commands/agents.d.ts.map +1 -0
  45. package/dist/cli/commands/agents.js +377 -0
  46. package/dist/cli/commands/agents.js.map +1 -0
  47. package/dist/cli/commands/batch.d.ts +20 -0
  48. package/dist/cli/commands/batch.d.ts.map +1 -0
  49. package/dist/cli/commands/batch.js +214 -0
  50. package/dist/cli/commands/batch.js.map +1 -0
  51. package/dist/cli/commands/clone-for-testing.d.ts +1 -1
  52. package/dist/cli/commands/clone-for-testing.d.ts.map +1 -1
  53. package/dist/cli/commands/clone-for-testing.js +37 -47
  54. package/dist/cli/commands/clone-for-testing.js.map +1 -1
  55. package/dist/cli/commands/derive.d.ts +1 -1
  56. package/dist/cli/commands/derive.d.ts.map +1 -1
  57. package/dist/cli/commands/derive.js +141 -88
  58. package/dist/cli/commands/derive.js.map +1 -1
  59. package/dist/cli/commands/doctor.d.ts +11 -0
  60. package/dist/cli/commands/doctor.d.ts.map +1 -0
  61. package/dist/cli/commands/doctor.js +152 -0
  62. package/dist/cli/commands/doctor.js.map +1 -0
  63. package/dist/cli/commands/export.d.ts +12 -0
  64. package/dist/cli/commands/export.d.ts.map +1 -0
  65. package/dist/cli/commands/export.js +134 -0
  66. package/dist/cli/commands/export.js.map +1 -0
  67. package/dist/cli/commands/help.d.ts +1 -1
  68. package/dist/cli/commands/help.d.ts.map +1 -1
  69. package/dist/cli/commands/help.js +163 -37
  70. package/dist/cli/commands/help.js.map +1 -1
  71. package/dist/cli/commands/inbox.d.ts +1 -1
  72. package/dist/cli/commands/inbox.d.ts.map +1 -1
  73. package/dist/cli/commands/inbox.js +178 -56
  74. package/dist/cli/commands/inbox.js.map +1 -1
  75. package/dist/cli/commands/index.d.ts +31 -19
  76. package/dist/cli/commands/index.d.ts.map +1 -1
  77. package/dist/cli/commands/index.js +31 -19
  78. package/dist/cli/commands/index.js.map +1 -1
  79. package/dist/cli/commands/init.d.ts +5 -1
  80. package/dist/cli/commands/init.d.ts.map +1 -1
  81. package/dist/cli/commands/init.js +108 -57
  82. package/dist/cli/commands/init.js.map +1 -1
  83. package/dist/cli/commands/item.d.ts +1 -1
  84. package/dist/cli/commands/item.d.ts.map +1 -1
  85. package/dist/cli/commands/item.js +557 -274
  86. package/dist/cli/commands/item.js.map +1 -1
  87. package/dist/cli/commands/link.d.ts +1 -1
  88. package/dist/cli/commands/link.d.ts.map +1 -1
  89. package/dist/cli/commands/link.js +55 -46
  90. package/dist/cli/commands/link.js.map +1 -1
  91. package/dist/cli/commands/log.d.ts +1 -1
  92. package/dist/cli/commands/log.d.ts.map +1 -1
  93. package/dist/cli/commands/log.js +58 -51
  94. package/dist/cli/commands/log.js.map +1 -1
  95. package/dist/cli/commands/merge-driver.d.ts +19 -0
  96. package/dist/cli/commands/merge-driver.d.ts.map +1 -0
  97. package/dist/cli/commands/merge-driver.js +398 -0
  98. package/dist/cli/commands/merge-driver.js.map +1 -0
  99. package/dist/cli/commands/meta.d.ts +1 -1
  100. package/dist/cli/commands/meta.d.ts.map +1 -1
  101. package/dist/cli/commands/meta.js +534 -399
  102. package/dist/cli/commands/meta.js.map +1 -1
  103. package/dist/cli/commands/module.d.ts +1 -1
  104. package/dist/cli/commands/module.d.ts.map +1 -1
  105. package/dist/cli/commands/module.js +30 -25
  106. package/dist/cli/commands/module.js.map +1 -1
  107. package/dist/cli/commands/plan-import.d.ts +11 -0
  108. package/dist/cli/commands/plan-import.d.ts.map +1 -0
  109. package/dist/cli/commands/plan-import.js +547 -0
  110. package/dist/cli/commands/plan-import.js.map +1 -0
  111. package/dist/cli/commands/plan.d.ts +10 -0
  112. package/dist/cli/commands/plan.d.ts.map +1 -0
  113. package/dist/cli/commands/plan.js +421 -0
  114. package/dist/cli/commands/plan.js.map +1 -0
  115. package/dist/cli/commands/ralph.d.ts +1 -1
  116. package/dist/cli/commands/ralph.d.ts.map +1 -1
  117. package/dist/cli/commands/ralph.js +1109 -170
  118. package/dist/cli/commands/ralph.js.map +1 -1
  119. package/dist/cli/commands/refs.d.ts +13 -0
  120. package/dist/cli/commands/refs.d.ts.map +1 -0
  121. package/dist/cli/commands/refs.js +283 -0
  122. package/dist/cli/commands/refs.js.map +1 -0
  123. package/dist/cli/commands/search.d.ts +1 -1
  124. package/dist/cli/commands/search.d.ts.map +1 -1
  125. package/dist/cli/commands/search.js +199 -37
  126. package/dist/cli/commands/search.js.map +1 -1
  127. package/dist/cli/commands/serve.d.ts +10 -0
  128. package/dist/cli/commands/serve.d.ts.map +1 -0
  129. package/dist/cli/commands/serve.js +491 -0
  130. package/dist/cli/commands/serve.js.map +1 -0
  131. package/dist/cli/commands/session.d.ts +25 -6
  132. package/dist/cli/commands/session.d.ts.map +1 -1
  133. package/dist/cli/commands/session.js +810 -127
  134. package/dist/cli/commands/session.js.map +1 -1
  135. package/dist/cli/commands/setup-seeding.d.ts +81 -0
  136. package/dist/cli/commands/setup-seeding.d.ts.map +1 -0
  137. package/dist/cli/commands/setup-seeding.js +292 -0
  138. package/dist/cli/commands/setup-seeding.js.map +1 -0
  139. package/dist/cli/commands/setup.d.ts +77 -3
  140. package/dist/cli/commands/setup.d.ts.map +1 -1
  141. package/dist/cli/commands/setup.js +1267 -274
  142. package/dist/cli/commands/setup.js.map +1 -1
  143. package/dist/cli/commands/shadow.d.ts +1 -1
  144. package/dist/cli/commands/shadow.d.ts.map +1 -1
  145. package/dist/cli/commands/shadow.js +70 -50
  146. package/dist/cli/commands/shadow.js.map +1 -1
  147. package/dist/cli/commands/skill-crud.d.ts +58 -0
  148. package/dist/cli/commands/skill-crud.d.ts.map +1 -0
  149. package/dist/cli/commands/skill-crud.js +753 -0
  150. package/dist/cli/commands/skill-crud.js.map +1 -0
  151. package/dist/cli/commands/skill-diff.d.ts +27 -0
  152. package/dist/cli/commands/skill-diff.d.ts.map +1 -0
  153. package/dist/cli/commands/skill-diff.js +840 -0
  154. package/dist/cli/commands/skill-diff.js.map +1 -0
  155. package/dist/cli/commands/skill-install.d.ts +56 -0
  156. package/dist/cli/commands/skill-install.d.ts.map +1 -0
  157. package/dist/cli/commands/skill-install.js +509 -0
  158. package/dist/cli/commands/skill-install.js.map +1 -0
  159. package/dist/cli/commands/skill.d.ts +20 -0
  160. package/dist/cli/commands/skill.d.ts.map +1 -0
  161. package/dist/cli/commands/skill.js +36 -0
  162. package/dist/cli/commands/skill.js.map +1 -0
  163. package/dist/cli/commands/task.d.ts +1 -1
  164. package/dist/cli/commands/task.d.ts.map +1 -1
  165. package/dist/cli/commands/task.js +584 -350
  166. package/dist/cli/commands/task.js.map +1 -1
  167. package/dist/cli/commands/tasks.d.ts +26 -1
  168. package/dist/cli/commands/tasks.d.ts.map +1 -1
  169. package/dist/cli/commands/tasks.js +225 -122
  170. package/dist/cli/commands/tasks.js.map +1 -1
  171. package/dist/cli/commands/trait.d.ts +1 -1
  172. package/dist/cli/commands/trait.d.ts.map +1 -1
  173. package/dist/cli/commands/trait.js +166 -101
  174. package/dist/cli/commands/trait.js.map +1 -1
  175. package/dist/cli/commands/triage.d.ts +7 -0
  176. package/dist/cli/commands/triage.d.ts.map +1 -0
  177. package/dist/cli/commands/triage.js +483 -0
  178. package/dist/cli/commands/triage.js.map +1 -0
  179. package/dist/cli/commands/util.d.ts +7 -0
  180. package/dist/cli/commands/util.d.ts.map +1 -0
  181. package/dist/cli/commands/util.js +30 -0
  182. package/dist/cli/commands/util.js.map +1 -0
  183. package/dist/cli/commands/validate.d.ts +1 -1
  184. package/dist/cli/commands/validate.d.ts.map +1 -1
  185. package/dist/cli/commands/validate.js +264 -83
  186. package/dist/cli/commands/validate.js.map +1 -1
  187. package/dist/cli/commands/workflow.d.ts +16 -0
  188. package/dist/cli/commands/workflow.d.ts.map +1 -0
  189. package/dist/cli/commands/workflow.js +851 -0
  190. package/dist/cli/commands/workflow.js.map +1 -0
  191. package/dist/cli/exit-codes.d.ts +7 -0
  192. package/dist/cli/exit-codes.d.ts.map +1 -1
  193. package/dist/cli/exit-codes.js +26 -18
  194. package/dist/cli/exit-codes.js.map +1 -1
  195. package/dist/cli/help/content.d.ts.map +1 -1
  196. package/dist/cli/help/content.js +86 -71
  197. package/dist/cli/help/content.js.map +1 -1
  198. package/dist/cli/index.d.ts +1 -1
  199. package/dist/cli/index.d.ts.map +1 -1
  200. package/dist/cli/index.js +131 -19
  201. package/dist/cli/index.js.map +1 -1
  202. package/dist/cli/introspection.d.ts +6 -2
  203. package/dist/cli/introspection.d.ts.map +1 -1
  204. package/dist/cli/introspection.js +11 -8
  205. package/dist/cli/introspection.js.map +1 -1
  206. package/dist/cli/output.d.ts +64 -4
  207. package/dist/cli/output.d.ts.map +1 -1
  208. package/dist/cli/output.js +237 -85
  209. package/dist/cli/output.js.map +1 -1
  210. package/dist/cli/parse-utils.d.ts +21 -0
  211. package/dist/cli/parse-utils.d.ts.map +1 -0
  212. package/dist/cli/parse-utils.js +32 -0
  213. package/dist/cli/parse-utils.js.map +1 -0
  214. package/dist/cli/pid-utils.d.ts +72 -0
  215. package/dist/cli/pid-utils.d.ts.map +1 -0
  216. package/dist/cli/pid-utils.js +174 -0
  217. package/dist/cli/pid-utils.js.map +1 -0
  218. package/dist/cli/suggest.d.ts.map +1 -1
  219. package/dist/cli/suggest.js +1 -2
  220. package/dist/cli/suggest.js.map +1 -1
  221. package/dist/cli/validators.d.ts +43 -0
  222. package/dist/cli/validators.d.ts.map +1 -0
  223. package/dist/cli/validators.js +84 -0
  224. package/dist/cli/validators.js.map +1 -0
  225. package/dist/daemon/index.ts +52 -0
  226. package/dist/daemon/middleware/project-context.ts +126 -0
  227. package/dist/daemon/pid.ts +179 -0
  228. package/dist/daemon/project-context.ts +343 -0
  229. package/dist/daemon/routes/inbox.ts +164 -0
  230. package/dist/daemon/routes/items.ts +322 -0
  231. package/dist/daemon/routes/meta.ts +118 -0
  232. package/dist/daemon/routes/projects.ts +162 -0
  233. package/dist/daemon/routes/tasks.ts +327 -0
  234. package/dist/daemon/routes/triage.ts +402 -0
  235. package/dist/daemon/routes/validation.ts +248 -0
  236. package/dist/daemon/server.ts +408 -0
  237. package/dist/daemon/watcher.ts +195 -0
  238. package/dist/daemon/websocket/handler.ts +138 -0
  239. package/dist/daemon/websocket/heartbeat.ts +71 -0
  240. package/dist/daemon/websocket/pubsub.ts +125 -0
  241. package/dist/daemon/websocket/types.ts +66 -0
  242. package/dist/export/html.d.ts +19 -0
  243. package/dist/export/html.d.ts.map +1 -0
  244. package/dist/export/html.js +239 -0
  245. package/dist/export/html.js.map +1 -0
  246. package/dist/export/index.d.ts +10 -0
  247. package/dist/export/index.d.ts.map +1 -0
  248. package/dist/export/index.js +10 -0
  249. package/dist/export/index.js.map +1 -0
  250. package/dist/export/json.d.ts +24 -0
  251. package/dist/export/json.d.ts.map +1 -0
  252. package/dist/export/json.js +198 -0
  253. package/dist/export/json.js.map +1 -0
  254. package/dist/export/triage.d.ts +51 -0
  255. package/dist/export/triage.d.ts.map +1 -0
  256. package/dist/export/triage.js +83 -0
  257. package/dist/export/triage.js.map +1 -0
  258. package/dist/export/types.d.ts +122 -0
  259. package/dist/export/types.d.ts.map +1 -0
  260. package/dist/export/types.js +9 -0
  261. package/dist/export/types.js.map +1 -0
  262. package/dist/index.d.ts +2 -2
  263. package/dist/index.js +2 -2
  264. package/dist/lib/claude-plugin-registry.d.ts +66 -0
  265. package/dist/lib/claude-plugin-registry.d.ts.map +1 -0
  266. package/dist/lib/claude-plugin-registry.js +318 -0
  267. package/dist/lib/claude-plugin-registry.js.map +1 -0
  268. package/dist/merge/arrays.d.ts +87 -0
  269. package/dist/merge/arrays.d.ts.map +1 -0
  270. package/dist/merge/arrays.js +164 -0
  271. package/dist/merge/arrays.js.map +1 -0
  272. package/dist/merge/file-type.d.ts +32 -0
  273. package/dist/merge/file-type.d.ts.map +1 -0
  274. package/dist/merge/file-type.js +70 -0
  275. package/dist/merge/file-type.js.map +1 -0
  276. package/dist/merge/index.d.ts +14 -0
  277. package/dist/merge/index.d.ts.map +1 -0
  278. package/dist/merge/index.js +11 -0
  279. package/dist/merge/index.js.map +1 -0
  280. package/dist/merge/objects.d.ts +46 -0
  281. package/dist/merge/objects.d.ts.map +1 -0
  282. package/dist/merge/objects.js +193 -0
  283. package/dist/merge/objects.js.map +1 -0
  284. package/dist/merge/parse.d.ts +23 -0
  285. package/dist/merge/parse.d.ts.map +1 -0
  286. package/dist/merge/parse.js +78 -0
  287. package/dist/merge/parse.js.map +1 -0
  288. package/dist/merge/resolve.d.ts +66 -0
  289. package/dist/merge/resolve.d.ts.map +1 -0
  290. package/dist/merge/resolve.js +189 -0
  291. package/dist/merge/resolve.js.map +1 -0
  292. package/dist/merge/types.d.ts +82 -0
  293. package/dist/merge/types.d.ts.map +1 -0
  294. package/dist/merge/types.js +8 -0
  295. package/dist/merge/types.js.map +1 -0
  296. package/dist/parser/agent-data-sections.d.ts +53 -0
  297. package/dist/parser/agent-data-sections.d.ts.map +1 -0
  298. package/dist/parser/agent-data-sections.js +118 -0
  299. package/dist/parser/agent-data-sections.js.map +1 -0
  300. package/dist/parser/alignment.d.ts +4 -4
  301. package/dist/parser/alignment.d.ts.map +1 -1
  302. package/dist/parser/alignment.js +27 -22
  303. package/dist/parser/alignment.js.map +1 -1
  304. package/dist/parser/assess.d.ts +5 -5
  305. package/dist/parser/assess.d.ts.map +1 -1
  306. package/dist/parser/assess.js +36 -32
  307. package/dist/parser/assess.js.map +1 -1
  308. package/dist/parser/config.d.ts +457 -0
  309. package/dist/parser/config.d.ts.map +1 -0
  310. package/dist/parser/config.js +373 -0
  311. package/dist/parser/config.js.map +1 -0
  312. package/dist/parser/convention-validation.d.ts +1 -1
  313. package/dist/parser/convention-validation.d.ts.map +1 -1
  314. package/dist/parser/convention-validation.js +21 -16
  315. package/dist/parser/convention-validation.js.map +1 -1
  316. package/dist/parser/coverage-cache.d.ts +49 -0
  317. package/dist/parser/coverage-cache.d.ts.map +1 -0
  318. package/dist/parser/coverage-cache.js +123 -0
  319. package/dist/parser/coverage-cache.js.map +1 -0
  320. package/dist/parser/daemon-status.d.ts +37 -0
  321. package/dist/parser/daemon-status.d.ts.map +1 -0
  322. package/dist/parser/daemon-status.js +67 -0
  323. package/dist/parser/daemon-status.js.map +1 -0
  324. package/dist/parser/doctor.d.ts +107 -0
  325. package/dist/parser/doctor.d.ts.map +1 -0
  326. package/dist/parser/doctor.js +366 -0
  327. package/dist/parser/doctor.js.map +1 -0
  328. package/dist/parser/fix.d.ts +1 -1
  329. package/dist/parser/fix.d.ts.map +1 -1
  330. package/dist/parser/fix.js +31 -27
  331. package/dist/parser/fix.js.map +1 -1
  332. package/dist/parser/index.d.ts +16 -11
  333. package/dist/parser/index.d.ts.map +1 -1
  334. package/dist/parser/index.js +16 -11
  335. package/dist/parser/index.js.map +1 -1
  336. package/dist/parser/items.d.ts +8 -2
  337. package/dist/parser/items.d.ts.map +1 -1
  338. package/dist/parser/items.js +71 -35
  339. package/dist/parser/items.js.map +1 -1
  340. package/dist/parser/meta.d.ts +167 -9
  341. package/dist/parser/meta.d.ts.map +1 -1
  342. package/dist/parser/meta.js +379 -46
  343. package/dist/parser/meta.js.map +1 -1
  344. package/dist/parser/plan-document.d.ts +197 -0
  345. package/dist/parser/plan-document.d.ts.map +1 -0
  346. package/dist/parser/plan-document.js +341 -0
  347. package/dist/parser/plan-document.js.map +1 -0
  348. package/dist/parser/plans.d.ts +59 -0
  349. package/dist/parser/plans.d.ts.map +1 -0
  350. package/dist/parser/plans.js +239 -0
  351. package/dist/parser/plans.js.map +1 -0
  352. package/dist/parser/refs.d.ts +22 -9
  353. package/dist/parser/refs.d.ts.map +1 -1
  354. package/dist/parser/refs.js +102 -50
  355. package/dist/parser/refs.js.map +1 -1
  356. package/dist/parser/setup-status.d.ts +71 -0
  357. package/dist/parser/setup-status.d.ts.map +1 -0
  358. package/dist/parser/setup-status.js +269 -0
  359. package/dist/parser/setup-status.js.map +1 -0
  360. package/dist/parser/shadow.d.ts +150 -19
  361. package/dist/parser/shadow.d.ts.map +1 -1
  362. package/dist/parser/shadow.js +548 -187
  363. package/dist/parser/shadow.js.map +1 -1
  364. package/dist/parser/skill-render.d.ts +317 -0
  365. package/dist/parser/skill-render.d.ts.map +1 -0
  366. package/dist/parser/skill-render.js +943 -0
  367. package/dist/parser/skill-render.js.map +1 -0
  368. package/dist/parser/traits.d.ts +3 -3
  369. package/dist/parser/traits.d.ts.map +1 -1
  370. package/dist/parser/traits.js +2 -2
  371. package/dist/parser/traits.js.map +1 -1
  372. package/dist/parser/validate-skills.d.ts +32 -0
  373. package/dist/parser/validate-skills.d.ts.map +1 -0
  374. package/dist/parser/validate-skills.js +202 -0
  375. package/dist/parser/validate-skills.js.map +1 -0
  376. package/dist/parser/validate.d.ts +45 -3
  377. package/dist/parser/validate.d.ts.map +1 -1
  378. package/dist/parser/validate.js +622 -105
  379. package/dist/parser/validate.js.map +1 -1
  380. package/dist/parser/yaml.d.ts +83 -19
  381. package/dist/parser/yaml.d.ts.map +1 -1
  382. package/dist/parser/yaml.js +478 -173
  383. package/dist/parser/yaml.js.map +1 -1
  384. package/dist/ralph/cli-renderer.d.ts +8 -1
  385. package/dist/ralph/cli-renderer.d.ts.map +1 -1
  386. package/dist/ralph/cli-renderer.js +105 -34
  387. package/dist/ralph/cli-renderer.js.map +1 -1
  388. package/dist/ralph/events.d.ts +10 -10
  389. package/dist/ralph/events.d.ts.map +1 -1
  390. package/dist/ralph/events.js +301 -98
  391. package/dist/ralph/events.js.map +1 -1
  392. package/dist/ralph/index.d.ts +5 -2
  393. package/dist/ralph/index.d.ts.map +1 -1
  394. package/dist/ralph/index.js +9 -3
  395. package/dist/ralph/index.js.map +1 -1
  396. package/dist/ralph/loop-errors.d.ts +83 -0
  397. package/dist/ralph/loop-errors.d.ts.map +1 -0
  398. package/dist/ralph/loop-errors.js +150 -0
  399. package/dist/ralph/loop-errors.js.map +1 -0
  400. package/dist/ralph/subagent.d.ts +94 -0
  401. package/dist/ralph/subagent.d.ts.map +1 -0
  402. package/dist/ralph/subagent.js +193 -0
  403. package/dist/ralph/subagent.js.map +1 -0
  404. package/dist/ralph/wrap-up.d.ts +125 -0
  405. package/dist/ralph/wrap-up.d.ts.map +1 -0
  406. package/dist/ralph/wrap-up.js +270 -0
  407. package/dist/ralph/wrap-up.js.map +1 -0
  408. package/dist/schema/batch.d.ts +97 -0
  409. package/dist/schema/batch.d.ts.map +1 -0
  410. package/dist/schema/batch.js +24 -0
  411. package/dist/schema/batch.js.map +1 -0
  412. package/dist/schema/common.d.ts +8 -2
  413. package/dist/schema/common.d.ts.map +1 -1
  414. package/dist/schema/common.js +42 -31
  415. package/dist/schema/common.js.map +1 -1
  416. package/dist/schema/inbox.d.ts +12 -12
  417. package/dist/schema/inbox.js +4 -4
  418. package/dist/schema/inbox.js.map +1 -1
  419. package/dist/schema/index.d.ts +8 -5
  420. package/dist/schema/index.d.ts.map +1 -1
  421. package/dist/schema/index.js +8 -5
  422. package/dist/schema/index.js.map +1 -1
  423. package/dist/schema/meta.d.ts +1454 -27
  424. package/dist/schema/meta.d.ts.map +1 -1
  425. package/dist/schema/meta.js +198 -21
  426. package/dist/schema/meta.js.map +1 -1
  427. package/dist/schema/plan.d.ts +285 -0
  428. package/dist/schema/plan.d.ts.map +1 -0
  429. package/dist/schema/plan.js +81 -0
  430. package/dist/schema/plan.js.map +1 -0
  431. package/dist/schema/spec.d.ts +72 -33
  432. package/dist/schema/spec.d.ts.map +1 -1
  433. package/dist/schema/spec.js +22 -9
  434. package/dist/schema/spec.js.map +1 -1
  435. package/dist/schema/task.d.ts +172 -161
  436. package/dist/schema/task.d.ts.map +1 -1
  437. package/dist/schema/task.js +21 -12
  438. package/dist/schema/task.js.map +1 -1
  439. package/dist/schema/triage.d.ts +266 -0
  440. package/dist/schema/triage.d.ts.map +1 -0
  441. package/dist/schema/triage.js +134 -0
  442. package/dist/schema/triage.js.map +1 -0
  443. package/dist/sessions/index.d.ts +2 -2
  444. package/dist/sessions/index.d.ts.map +1 -1
  445. package/dist/sessions/index.js +3 -3
  446. package/dist/sessions/index.js.map +1 -1
  447. package/dist/sessions/store.d.ts +241 -1
  448. package/dist/sessions/store.d.ts.map +1 -1
  449. package/dist/sessions/store.js +810 -31
  450. package/dist/sessions/store.js.map +1 -1
  451. package/dist/sessions/types.d.ts +10 -10
  452. package/dist/sessions/types.d.ts.map +1 -1
  453. package/dist/sessions/types.js +10 -9
  454. package/dist/sessions/types.js.map +1 -1
  455. package/dist/strings/errors.d.ts +55 -0
  456. package/dist/strings/errors.d.ts.map +1 -1
  457. package/dist/strings/errors.js +138 -106
  458. package/dist/strings/errors.js.map +1 -1
  459. package/dist/strings/guidance.d.ts.map +1 -1
  460. package/dist/strings/guidance.js +16 -16
  461. package/dist/strings/guidance.js.map +1 -1
  462. package/dist/strings/index.d.ts +4 -4
  463. package/dist/strings/index.d.ts.map +1 -1
  464. package/dist/strings/index.js +4 -4
  465. package/dist/strings/index.js.map +1 -1
  466. package/dist/strings/labels.d.ts +4 -0
  467. package/dist/strings/labels.d.ts.map +1 -1
  468. package/dist/strings/labels.js +45 -41
  469. package/dist/strings/labels.js.map +1 -1
  470. package/dist/strings/validation.d.ts.map +1 -1
  471. package/dist/strings/validation.js +71 -71
  472. package/dist/strings/validation.js.map +1 -1
  473. package/dist/triage/actions.d.ts +27 -0
  474. package/dist/triage/actions.d.ts.map +1 -0
  475. package/dist/triage/actions.js +95 -0
  476. package/dist/triage/actions.js.map +1 -0
  477. package/dist/triage/constants.d.ts +6 -0
  478. package/dist/triage/constants.d.ts.map +1 -0
  479. package/dist/triage/constants.js +7 -0
  480. package/dist/triage/constants.js.map +1 -0
  481. package/dist/triage/index.d.ts +3 -0
  482. package/dist/triage/index.d.ts.map +1 -0
  483. package/dist/triage/index.js +3 -0
  484. package/dist/triage/index.js.map +1 -0
  485. package/dist/utils/commit.d.ts +1 -1
  486. package/dist/utils/commit.d.ts.map +1 -1
  487. package/dist/utils/commit.js +28 -26
  488. package/dist/utils/commit.js.map +1 -1
  489. package/dist/utils/git.d.ts +1 -1
  490. package/dist/utils/git.d.ts.map +1 -1
  491. package/dist/utils/git.js +40 -38
  492. package/dist/utils/git.js.map +1 -1
  493. package/dist/utils/grep.js +11 -11
  494. package/dist/utils/grep.js.map +1 -1
  495. package/dist/utils/index.d.ts +7 -7
  496. package/dist/utils/index.d.ts.map +1 -1
  497. package/dist/utils/index.js +4 -4
  498. package/dist/utils/index.js.map +1 -1
  499. package/dist/utils/time.d.ts.map +1 -1
  500. package/dist/utils/time.js +10 -10
  501. package/dist/utils/time.js.map +1 -1
  502. package/package.json +28 -5
  503. package/plugin/.claude-plugin/marketplace.json +17 -0
  504. package/plugin/.claude-plugin/plugin.json +5 -0
  505. package/plugin/plugins/kspec/skills/create-workflow/SKILL.md +235 -0
  506. package/plugin/plugins/kspec/skills/help/SKILL.md +42 -0
  507. package/plugin/plugins/kspec/skills/observations/SKILL.md +143 -0
  508. package/plugin/plugins/kspec/skills/plan/SKILL.md +343 -0
  509. package/plugin/plugins/kspec/skills/reflect/SKILL.md +161 -0
  510. package/plugin/plugins/kspec/skills/review/SKILL.md +193 -0
  511. package/plugin/plugins/kspec/skills/task-work/SKILL.md +303 -0
  512. package/plugin/plugins/kspec/skills/triage/SKILL.md +206 -0
  513. package/plugin/plugins/kspec/skills/triage/docs/automation.md +120 -0
  514. package/plugin/plugins/kspec/skills/triage/docs/inbox.md +144 -0
  515. package/plugin/plugins/kspec/skills/triage/docs/observations.md +85 -0
  516. package/plugin/plugins/kspec/skills/triage-automation/SKILL.md +140 -0
  517. package/plugin/plugins/kspec/skills/triage-inbox/SKILL.md +232 -0
  518. package/plugin/plugins/kspec/skills/writing-specs/SKILL.md +340 -0
  519. package/templates/agents-sections/01-quick-start.md +22 -0
  520. package/templates/agents-sections/02-shadow-branch.md +34 -0
  521. package/templates/agents-sections/03-task-lifecycle.md +48 -0
  522. package/templates/agents-sections/04-pr-workflow.md +17 -0
  523. package/templates/agents-sections/05-commit-convention.md +27 -0
  524. package/templates/agents-sections/06-ralph-loop.md +45 -0
  525. package/templates/hooks/pre-commit +34 -0
  526. package/templates/skills/create-workflow/SKILL.md +228 -0
  527. package/templates/skills/help/SKILL.md +37 -0
  528. package/templates/skills/manifest.yaml +60 -0
  529. package/templates/skills/observations/SKILL.md +137 -0
  530. package/templates/skills/plan/SKILL.md +336 -0
  531. package/templates/skills/reflect/SKILL.md +155 -0
  532. package/templates/skills/review/SKILL.md +186 -0
  533. package/templates/skills/task-work/SKILL.md +296 -0
  534. package/templates/skills/triage/SKILL.md +199 -0
  535. package/templates/skills/triage/docs/automation.md +120 -0
  536. package/templates/skills/triage/docs/inbox.md +144 -0
  537. package/templates/skills/triage/docs/observations.md +85 -0
  538. package/templates/skills/triage-automation/SKILL.md +134 -0
  539. package/templates/skills/triage-inbox/SKILL.md +225 -0
  540. package/templates/skills/writing-specs/SKILL.md +333 -0
@@ -0,0 +1,753 @@
1
+ /**
2
+ * Skill CRUD commands: list, add, get, set, delete, import
3
+ *
4
+ * AC: @skill-cli ac-1 - kspec skill list outputs table with ID, Name, Origin, Version, Platforms
5
+ * AC: @skill-cli ac-2 - kspec skill list --json outputs JSON array with full skill metadata
6
+ * AC: @skill-cli ac-3 - kspec skill add creates meta entry with origin custom
7
+ * AC: @skill-cli ac-4 - kspec skill add creates .kspec/skills/<id>/SKILL.md
8
+ * AC: @skill-cli ac-5 - kspec skill get outputs metadata including id, name, origin, platforms
9
+ * AC: @skill-cli ac-6 - kspec skill get outputs SKILL.md content
10
+ * AC: @skill-cli ac-7 - kspec skill delete --confirm removes meta entry
11
+ * AC: @skill-cli ac-8 - kspec skill delete removes .kspec/skills/<id>/ directory
12
+ */
13
+ import * as fs from "node:fs/promises";
14
+ import * as path from "node:path";
15
+ import chalk from "chalk";
16
+ import Table from "cli-table3";
17
+ import { ulid } from "ulid";
18
+ import yaml from "yaml";
19
+ import { markMutating } from "../command-annotations.js";
20
+ import { deleteMetaItem, findMetaItemByRef, getSkillContentPath, initContext, isSkill, loadMetaContext, loadSkillContent, loadSkillDocs, saveMetaItem, } from "../../parser/index.js";
21
+ import { commitIfShadow } from "../../parser/shadow.js";
22
+ import { copyDirectory } from "../../parser/skill-render.js";
23
+ import { SkillSchema, ClaudeCodeConfigSchema, CodexConfigSchema, } from "../../schema/index.js";
24
+ import { errors } from "../../strings/errors.js";
25
+ import { EXIT_CODES } from "../exit-codes.js";
26
+ import { error, output, success } from "../output.js";
27
+ import { parseTagsArray } from "../parse-utils.js";
28
+ /**
29
+ * Parse YAML frontmatter from markdown content.
30
+ * Returns null if no valid frontmatter found.
31
+ *
32
+ * AC: @import-frontmatter-strip ac-1 - Parse all Agent Skills frontmatter fields
33
+ * AC: @import-frontmatter-strip ac-3 - Parse Claude Code platform frontmatter
34
+ */
35
+ export function parseFrontmatter(content) {
36
+ const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
37
+ const match = content.match(frontmatterRegex);
38
+ if (!match) {
39
+ return null;
40
+ }
41
+ try {
42
+ const parsed = yaml.parse(match[1]);
43
+ if (typeof parsed === "object" && parsed !== null) {
44
+ const result = {};
45
+ // Core metadata
46
+ if (typeof parsed.name === "string")
47
+ result.name = parsed.name;
48
+ if (typeof parsed.description === "string")
49
+ result.description = parsed.description;
50
+ // Portable Agent Skills fields (AC: ac-1)
51
+ if (typeof parsed.license === "string")
52
+ result.license = parsed.license;
53
+ if (typeof parsed.compatibility === "string")
54
+ result.compatibility = parsed.compatibility;
55
+ if (Array.isArray(parsed.allowed_tools)) {
56
+ result.allowed_tools = parsed.allowed_tools.filter((t) => typeof t === "string");
57
+ }
58
+ // Claude Code platform fields (AC: ac-3)
59
+ // Support both underscore and hyphen naming for user-invocable
60
+ if (typeof parsed.user_invocable === "boolean")
61
+ result.user_invocable = parsed.user_invocable;
62
+ if (typeof parsed["user-invocable"] === "boolean")
63
+ result.user_invocable = parsed["user-invocable"];
64
+ if (typeof parsed.disable_model_invocation === "boolean")
65
+ result.disable_model_invocation = parsed.disable_model_invocation;
66
+ if (typeof parsed["disable-model-invocation"] === "boolean")
67
+ result.disable_model_invocation = parsed["disable-model-invocation"];
68
+ if (typeof parsed.context === "string")
69
+ result.context = parsed.context;
70
+ if (typeof parsed.agent === "string")
71
+ result.agent = parsed.agent;
72
+ if (typeof parsed.model === "string")
73
+ result.model = parsed.model;
74
+ if (typeof parsed.argument_hint === "string")
75
+ result.argument_hint = parsed.argument_hint;
76
+ if (typeof parsed["argument-hint"] === "string")
77
+ result.argument_hint = parsed["argument-hint"];
78
+ return result;
79
+ }
80
+ }
81
+ catch {
82
+ // Invalid YAML in frontmatter
83
+ }
84
+ return null;
85
+ }
86
+ /**
87
+ * Strip YAML frontmatter from markdown content.
88
+ * AC: @import-frontmatter-strip ac-2 - Remove frontmatter for body-only storage
89
+ */
90
+ export function stripFrontmatter(content) {
91
+ return content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
92
+ }
93
+ /**
94
+ * Normalize base-directory paths in skill content.
95
+ * AC: @skill-import ac-7 - Strip or convert absolute paths to relative.
96
+ *
97
+ * Matches patterns like:
98
+ * - "Base directory for this skill: /absolute/path/to/skill"
99
+ * - Lines starting with hardcoded paths
100
+ */
101
+ export function normalizeBaseDirectory(content) {
102
+ // Remove or normalize "Base directory for/of [this] skill:" lines with absolute paths
103
+ // Common pattern in Claude-generated skill files
104
+ // AC: @cross-platform-and-version-robustness ac-5 - case-insensitive with wording variations
105
+ const baseDirLineRegex = /^base\s+directory\s+(?:for|of)\s+(?:this\s+)?skill:.*$/gim;
106
+ return content.replace(baseDirLineRegex, "");
107
+ }
108
+ // ============================================================================
109
+ // Formatting Helpers
110
+ // ============================================================================
111
+ /**
112
+ * Format skills as a table
113
+ * AC: @skill-cli ac-1 - table displays ID, Name, Origin, Version, Platforms
114
+ */
115
+ function formatSkillsTable(skills) {
116
+ if (skills.length === 0) {
117
+ console.log(chalk.yellow("No skills defined"));
118
+ return;
119
+ }
120
+ const table = new Table({
121
+ head: [
122
+ chalk.bold("ID"),
123
+ chalk.bold("Name"),
124
+ chalk.bold("Origin"),
125
+ chalk.bold("Version"),
126
+ chalk.bold("Platforms"),
127
+ ],
128
+ style: {
129
+ head: [],
130
+ border: [],
131
+ },
132
+ });
133
+ for (const skill of skills) {
134
+ table.push([
135
+ skill.id,
136
+ skill.name,
137
+ skill.origin,
138
+ skill.version || "-",
139
+ skill.platforms.join(", "),
140
+ ]);
141
+ }
142
+ console.log(table.toString());
143
+ console.log(chalk.gray(`\n${skills.length} skill(s)`));
144
+ }
145
+ /**
146
+ * Format skill details
147
+ * AC: @skill-cli ac-5 - outputs metadata including id, name, origin, platforms
148
+ */
149
+ function formatSkillDetails(skill, content) {
150
+ console.log(chalk.bold(skill.name));
151
+ console.log(chalk.gray("─".repeat(40)));
152
+ console.log(`ID: ${skill.id}`);
153
+ console.log(`ULID: ${skill._ulid}`);
154
+ console.log(`Origin: ${skill.origin}`);
155
+ console.log(`Platforms: ${skill.platforms.join(", ")}`);
156
+ if (skill.version) {
157
+ console.log(`Version: ${skill.version}`);
158
+ }
159
+ if (skill.description) {
160
+ console.log(`\n─── Description ───`);
161
+ console.log(skill.description);
162
+ }
163
+ if (skill.depends_on && skill.depends_on.length > 0) {
164
+ console.log(`\n─── Dependencies ───`);
165
+ for (const dep of skill.depends_on) {
166
+ console.log(` • ${dep}`);
167
+ }
168
+ }
169
+ if (skill.tags && skill.tags.length > 0) {
170
+ console.log(`\nTags: ${skill.tags.join(", ")}`);
171
+ }
172
+ // AC: @skill-cli ac-6 - display SKILL.md content
173
+ if (content) {
174
+ console.log(`\n─── SKILL.md Content ───`);
175
+ console.log(content);
176
+ }
177
+ else {
178
+ console.log(chalk.gray("\n(No SKILL.md content found)"));
179
+ }
180
+ }
181
+ // ============================================================================
182
+ // Command Registration
183
+ // ============================================================================
184
+ /**
185
+ * Register CRUD skill commands (list, add, get, set, delete, import)
186
+ */
187
+ export function registerSkillCrudCommands(skill) {
188
+ // AC: @skill-cli ac-1, ac-2 - kspec skill list
189
+ skill
190
+ .command("list")
191
+ .description("List all skills")
192
+ .option("--origin <origin>", "Filter by origin (core, project, local)")
193
+ .option("--tag <tag>", "Filter by tag")
194
+ .action(async (options) => {
195
+ try {
196
+ const ctx = await initContext();
197
+ if (!ctx.manifestPath) {
198
+ error(errors.project.noKspecProject);
199
+ process.exit(EXIT_CODES.ERROR);
200
+ }
201
+ const metaCtx = await loadMetaContext(ctx);
202
+ let skills = metaCtx.skills || [];
203
+ // Apply filters
204
+ if (options.origin) {
205
+ skills = skills.filter((s) => s.origin === options.origin);
206
+ }
207
+ if (options.tag) {
208
+ skills = skills.filter((s) => s.tags?.includes(options.tag));
209
+ }
210
+ // AC: @skill-cli ac-2 - JSON output includes full skill metadata
211
+ output(skills.map((s) => ({
212
+ _ulid: s._ulid,
213
+ id: s.id,
214
+ name: s.name,
215
+ description: s.description,
216
+ origin: s.origin,
217
+ version: s.version,
218
+ platforms: s.platforms,
219
+ depends_on: s.depends_on,
220
+ tags: s.tags,
221
+ })),
222
+ // AC: @skill-cli ac-1 - Table output
223
+ () => formatSkillsTable(skills));
224
+ }
225
+ catch (err) {
226
+ error("Failed to list skills", err);
227
+ process.exit(EXIT_CODES.ERROR);
228
+ }
229
+ });
230
+ // AC: @skill-cli ac-3, ac-4 - kspec skill add
231
+ // AC: @skill-add ac-3 - --content-file copies existing file to SKILL.md
232
+ markMutating(skill.command("add"))
233
+ .description("Create a new skill")
234
+ .requiredOption("--id <id>", "Skill ID (kebab-case)")
235
+ .requiredOption("--name <name>", "Skill name")
236
+ .option("--description <desc>", "Skill description")
237
+ .option("--origin <origin>", "Skill origin (core, project, local)", "project")
238
+ .option("--skill-version <version>", "Skill version")
239
+ .option("--platform <platform...>", "Target platforms")
240
+ .option("--tag <tag...>", "Tags for the skill")
241
+ .option("--depends-on <ref...>", "Skill dependencies")
242
+ .option("--content-file <path>", "Path to existing file to use as SKILL.md content")
243
+ .action(async (options) => {
244
+ try {
245
+ const ctx = await initContext();
246
+ if (!ctx.manifestPath) {
247
+ error(errors.project.noKspecProject);
248
+ process.exit(EXIT_CODES.ERROR);
249
+ }
250
+ // Validate origin
251
+ const validOrigins = ["core", "project", "local"];
252
+ if (!validOrigins.includes(options.origin)) {
253
+ error(`Invalid origin: ${options.origin}. Valid origins: ${validOrigins.join(", ")}`);
254
+ process.exit(EXIT_CODES.ERROR);
255
+ }
256
+ // Check if skill with this ID already exists
257
+ const metaCtx = await loadMetaContext(ctx);
258
+ const existingSkill = metaCtx.skills.find((s) => s.id === options.id);
259
+ if (existingSkill) {
260
+ error(`Skill with ID '${options.id}' already exists`);
261
+ process.exit(EXIT_CODES.CONFLICT);
262
+ }
263
+ // Build skill object (schema provides defaults for platforms, depends_on, tags)
264
+ const skillData = {
265
+ _ulid: ulid(),
266
+ id: options.id,
267
+ name: options.name,
268
+ description: options.description,
269
+ origin: options.origin,
270
+ version: options.skillVersion,
271
+ ...(options.platform && options.platform.length > 0 && { platforms: options.platform }),
272
+ ...(options.dependsOn && options.dependsOn.length > 0 && { depends_on: options.dependsOn }),
273
+ allowed_tools: [],
274
+ ...(options.tag && options.tag.length > 0 && { tags: parseTagsArray(options.tag) }),
275
+ };
276
+ // Validate with schema
277
+ const parsed = SkillSchema.safeParse(skillData);
278
+ if (!parsed.success) {
279
+ const issues = parsed.error.issues
280
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
281
+ .join("; ");
282
+ error(`Invalid skill data: ${issues}`);
283
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
284
+ }
285
+ const skill = { ...parsed.data };
286
+ // AC: @skill-cli ac-3 - save meta entry (also creates directory per ac-4)
287
+ await saveMetaItem(ctx, skill, "skill");
288
+ // AC: @skill-cli ac-4 - create SKILL.md with placeholder content
289
+ // AC: @skill-add ac-3 - if --content-file provided, copy its contents
290
+ const skillMdPath = getSkillContentPath(ctx, skill.id);
291
+ let initialContent;
292
+ if (options.contentFile) {
293
+ // Read content from the specified file
294
+ const contentFilePath = path.isAbsolute(options.contentFile)
295
+ ? options.contentFile
296
+ : path.resolve(process.cwd(), options.contentFile);
297
+ try {
298
+ initialContent = await fs.readFile(contentFilePath, "utf-8");
299
+ }
300
+ catch (err) {
301
+ // Clean up: remove the skill we just created
302
+ await deleteMetaItem(ctx, skill._ulid, "skill");
303
+ error(`Failed to read content file: ${contentFilePath}`);
304
+ process.exit(EXIT_CODES.ERROR);
305
+ }
306
+ }
307
+ else {
308
+ initialContent = `# ${skill.name}\n\n${skill.description || "Add skill content here."}\n`;
309
+ }
310
+ await fs.writeFile(skillMdPath, initialContent, "utf-8");
311
+ // Commit changes
312
+ await commitIfShadow(ctx.shadow, "skill-add", skill.id, skill.name);
313
+ output(skill, () => success(`Created skill: ${skill.id}`, { skill }));
314
+ }
315
+ catch (err) {
316
+ error("Failed to create skill", err);
317
+ process.exit(EXIT_CODES.ERROR);
318
+ }
319
+ });
320
+ // AC: @skill-cli ac-5, ac-6 - kspec skill get
321
+ skill
322
+ .command("get <ref>")
323
+ .description("Show skill details")
324
+ .action(async (ref) => {
325
+ try {
326
+ const ctx = await initContext();
327
+ if (!ctx.manifestPath) {
328
+ error(errors.project.noKspecProject);
329
+ process.exit(EXIT_CODES.ERROR);
330
+ }
331
+ const metaCtx = await loadMetaContext(ctx);
332
+ const item = findMetaItemByRef(metaCtx, ref);
333
+ if (!item) {
334
+ error(`Skill not found: ${ref}`);
335
+ console.log(chalk.gray("Try: kspec skill list"));
336
+ process.exit(EXIT_CODES.NOT_FOUND);
337
+ }
338
+ // Check it's a skill (uses _type discriminant)
339
+ if (!isSkill(item)) {
340
+ error(`Item ${ref} is not a skill`);
341
+ process.exit(EXIT_CODES.ERROR);
342
+ }
343
+ const skill = item;
344
+ // AC: @skill-cli ac-6 - load SKILL.md content
345
+ const content = await loadSkillContent(ctx, skill);
346
+ const docs = await loadSkillDocs(ctx, skill);
347
+ // AC: @skill-cli ac-5, ac-6 - output metadata and content
348
+ // Include extended skill schema fields (license, compatibility, allowed_tools, metadata, platform_config)
349
+ output({
350
+ _ulid: skill._ulid,
351
+ id: skill.id,
352
+ name: skill.name,
353
+ description: skill.description,
354
+ origin: skill.origin,
355
+ version: skill.version,
356
+ platforms: skill.platforms,
357
+ depends_on: skill.depends_on,
358
+ tags: skill.tags,
359
+ // Extended fields from @extended-skill-schema
360
+ license: skill.license,
361
+ compatibility: skill.compatibility,
362
+ allowed_tools: skill.allowed_tools,
363
+ metadata: skill.metadata,
364
+ platform_config: skill.platform_config,
365
+ content,
366
+ docs: docs.map((d) => ({ name: d.name, path: d.path })),
367
+ }, () => formatSkillDetails(skill, content));
368
+ }
369
+ catch (err) {
370
+ error("Failed to get skill", err);
371
+ process.exit(EXIT_CODES.ERROR);
372
+ }
373
+ });
374
+ // AC: @skill-set ac-1, ac-2, ac-3 - kspec skill set
375
+ markMutating(skill.command("set <ref>"))
376
+ .description("Update skill metadata fields")
377
+ .option("--name <name>", "Update skill name")
378
+ .option("--description <desc>", "Update skill description")
379
+ .option("--origin <origin>", "Update skill origin (core, project, local)")
380
+ .option("--skill-version <version>", "Update skill version")
381
+ .option("--add-platform <platform>", "Add a platform to the platforms array")
382
+ .option("--remove-platform <platform>", "Remove a platform from the platforms array")
383
+ .option("--add-tag <tag>", "Add a tag to the tags array")
384
+ .option("--remove-tag <tag>", "Remove a tag from the tags array")
385
+ .option("--add-depends-on <ref>", "Add a dependency reference")
386
+ .option("--remove-depends-on <ref>", "Remove a dependency reference")
387
+ .option("--platform-config <config>", "Set platform config (format: platform.key=value, e.g., claude_code.user_invocable=false)", (value, previous) => {
388
+ // Collect multiple --platform-config options
389
+ return previous.concat([value]);
390
+ }, [])
391
+ .action(async (ref, options) => {
392
+ try {
393
+ const ctx = await initContext();
394
+ if (!ctx.manifestPath) {
395
+ error(errors.project.noKspecProject);
396
+ process.exit(EXIT_CODES.ERROR);
397
+ }
398
+ const metaCtx = await loadMetaContext(ctx);
399
+ const item = findMetaItemByRef(metaCtx, ref);
400
+ if (!item) {
401
+ error(`Skill not found: ${ref}`);
402
+ console.log(chalk.gray("Try: kspec skill list"));
403
+ process.exit(EXIT_CODES.NOT_FOUND);
404
+ }
405
+ // Check it's a skill (uses _type discriminant)
406
+ if (!isSkill(item)) {
407
+ error(`Item ${ref} is not a skill`);
408
+ process.exit(EXIT_CODES.ERROR);
409
+ }
410
+ // Clone before mutating to protect against partial save failure
411
+ const skill = structuredClone(item);
412
+ // AC: @skill-set ac-1 - update description field
413
+ if (options.name !== undefined) {
414
+ skill.name = options.name;
415
+ }
416
+ if (options.description !== undefined) {
417
+ skill.description = options.description;
418
+ }
419
+ // Update origin
420
+ if (options.origin !== undefined) {
421
+ const validOrigins = ["core", "project", "local"];
422
+ if (!validOrigins.includes(options.origin)) {
423
+ error(`Invalid origin: ${options.origin}. Valid origins: ${validOrigins.join(", ")}`);
424
+ process.exit(EXIT_CODES.ERROR);
425
+ }
426
+ skill.origin = options.origin;
427
+ }
428
+ // Update version
429
+ if (options.skillVersion !== undefined) {
430
+ skill.version = options.skillVersion;
431
+ }
432
+ // AC: @skill-set ac-2 - add platform to array
433
+ if (options.addPlatform) {
434
+ if (!skill.platforms.includes(options.addPlatform)) {
435
+ skill.platforms.push(options.addPlatform);
436
+ }
437
+ }
438
+ // Remove platform
439
+ if (options.removePlatform) {
440
+ const idx = skill.platforms.indexOf(options.removePlatform);
441
+ if (idx >= 0) {
442
+ skill.platforms.splice(idx, 1);
443
+ }
444
+ }
445
+ // AC: @skill-set ac-3 - add tag to array
446
+ if (options.addTag) {
447
+ if (!skill.tags) {
448
+ skill.tags = [];
449
+ }
450
+ if (!skill.tags.includes(options.addTag)) {
451
+ skill.tags.push(options.addTag);
452
+ }
453
+ }
454
+ // Remove tag
455
+ if (options.removeTag && skill.tags) {
456
+ const idx = skill.tags.indexOf(options.removeTag);
457
+ if (idx >= 0) {
458
+ skill.tags.splice(idx, 1);
459
+ }
460
+ }
461
+ // Add dependency
462
+ if (options.addDependsOn) {
463
+ if (!skill.depends_on) {
464
+ skill.depends_on = [];
465
+ }
466
+ if (!skill.depends_on.includes(options.addDependsOn)) {
467
+ skill.depends_on.push(options.addDependsOn);
468
+ }
469
+ }
470
+ // Remove dependency
471
+ if (options.removeDependsOn && skill.depends_on) {
472
+ const idx = skill.depends_on.indexOf(options.removeDependsOn);
473
+ if (idx >= 0) {
474
+ skill.depends_on.splice(idx, 1);
475
+ }
476
+ }
477
+ // AC: @skill-platform-config-cli ac-1, ac-2 - Handle platform config updates
478
+ if (options.platformConfig && options.platformConfig.length > 0) {
479
+ // Initialize platform_config if not present
480
+ if (!skill.platform_config) {
481
+ skill.platform_config = {};
482
+ }
483
+ for (const configStr of options.platformConfig) {
484
+ // Parse "platform.key=value" format
485
+ const match = configStr.match(/^([^.]+)\.([^=]+)=(.*)$/);
486
+ if (!match) {
487
+ error(`Invalid platform config format: ${configStr}\n` +
488
+ `Expected format: platform.key=value (e.g., claude_code.user_invocable=false)`);
489
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
490
+ }
491
+ const [, platform, key, rawValue] = match;
492
+ // Parse value type: "true"/"false" → boolean, otherwise string
493
+ let value;
494
+ if (rawValue === "true") {
495
+ value = true;
496
+ }
497
+ else if (rawValue === "false") {
498
+ value = false;
499
+ }
500
+ else {
501
+ // Remove surrounding quotes if present
502
+ value = rawValue.replace(/^["']|["']$/g, "");
503
+ }
504
+ // Deep merge: initialize platform object if needed
505
+ if (!(platform in skill.platform_config)) {
506
+ skill.platform_config[platform] = {};
507
+ }
508
+ // Set the value
509
+ skill.platform_config[platform][key] = value;
510
+ }
511
+ }
512
+ // Validate updated skill
513
+ // AC: @skill-platform-config-cli ac-4 - validation error with guidance on valid keys
514
+ const parsed = SkillSchema.safeParse(skill);
515
+ if (!parsed.success) {
516
+ const issues = parsed.error.issues
517
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
518
+ .join("; ");
519
+ // Check if any errors are related to platform_config and provide guidance
520
+ const hasPlatformConfigError = parsed.error.issues.some((i) => i.path[0] === "platform_config");
521
+ let errorMsg = `Invalid skill data: ${issues}`;
522
+ if (hasPlatformConfigError) {
523
+ // Get valid keys from schemas
524
+ const claudeCodeKeys = Object.keys(ClaudeCodeConfigSchema.shape).join(", ");
525
+ const codexKeys = Object.keys(CodexConfigSchema.shape).join(", ");
526
+ errorMsg +=
527
+ `\n\nValid platform config keys:` +
528
+ `\n claude_code: ${claudeCodeKeys}` +
529
+ `\n codex: ${codexKeys}`;
530
+ }
531
+ error(errorMsg);
532
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
533
+ }
534
+ // Save the updated skill
535
+ await saveMetaItem(ctx, skill, "skill");
536
+ // Commit changes
537
+ await commitIfShadow(ctx.shadow, "skill-set", skill.id, skill.name);
538
+ output(skill, () => success(`Updated skill: ${skill.id}`));
539
+ }
540
+ catch (err) {
541
+ error("Failed to update skill", err);
542
+ process.exit(EXIT_CODES.ERROR);
543
+ }
544
+ });
545
+ // AC: @skill-cli ac-7, ac-8 - kspec skill delete
546
+ markMutating(skill.command("delete <ref>"))
547
+ .description("Delete a skill")
548
+ .option("--confirm", "Skip confirmation prompt")
549
+ .action(async (ref, options) => {
550
+ try {
551
+ const ctx = await initContext();
552
+ if (!ctx.manifestPath) {
553
+ error(errors.project.noKspecProject);
554
+ process.exit(EXIT_CODES.ERROR);
555
+ }
556
+ const metaCtx = await loadMetaContext(ctx);
557
+ const item = findMetaItemByRef(metaCtx, ref);
558
+ if (!item) {
559
+ error(`Skill not found: ${ref}`);
560
+ console.log(chalk.gray("Try: kspec skill list"));
561
+ process.exit(EXIT_CODES.NOT_FOUND);
562
+ }
563
+ // Check it's a skill (uses _type discriminant)
564
+ if (!isSkill(item)) {
565
+ error(`Item ${ref} is not a skill`);
566
+ process.exit(EXIT_CODES.ERROR);
567
+ }
568
+ const skill = item;
569
+ // Check for confirmation
570
+ if (!options.confirm) {
571
+ error(`Confirm deletion of skill '${skill.id}' with --confirm flag`);
572
+ process.exit(EXIT_CODES.ERROR);
573
+ }
574
+ // Check for dependencies from other skills
575
+ const dependentSkills = metaCtx.skills.filter((s) => s._ulid !== skill._ulid &&
576
+ s.depends_on?.some((dep) => dep === `@${skill.id}` ||
577
+ dep === skill.id ||
578
+ dep.startsWith(`@${skill._ulid.substring(0, 8)}`)));
579
+ if (dependentSkills.length > 0) {
580
+ const depRefs = dependentSkills.map((s) => `@${s.id}`).join(", ");
581
+ error(`Cannot delete skill '${skill.id}': referenced by ${dependentSkills.length} skill(s): ${depRefs}`);
582
+ process.exit(EXIT_CODES.ERROR);
583
+ }
584
+ // AC: @skill-cli ac-7, ac-8 - delete meta entry and directory
585
+ const deleted = await deleteMetaItem(ctx, skill._ulid, "skill");
586
+ if (!deleted) {
587
+ error(`Failed to delete skill: ${skill.id}`);
588
+ process.exit(EXIT_CODES.ERROR);
589
+ }
590
+ // Commit changes
591
+ await commitIfShadow(ctx.shadow, "skill-delete", skill.id);
592
+ success(`Deleted skill: ${skill.id}`);
593
+ }
594
+ catch (err) {
595
+ error("Failed to delete skill", err);
596
+ process.exit(EXIT_CODES.ERROR);
597
+ }
598
+ });
599
+ // AC: @skill-import ac-1 through ac-7 - kspec skill import
600
+ // AC: @import-frontmatter-strip ac-1 through ac-6 - Extended frontmatter parsing
601
+ markMutating(skill.command("import <file>"))
602
+ .description("Import an existing SKILL.md file into kspec")
603
+ .option("--id <id>", "Custom skill ID (defaults to directory name)")
604
+ .option("--name <name>", "Skill name (required if no frontmatter)")
605
+ .option("--description <desc>", "Skill description (required if no frontmatter)")
606
+ .option("--origin <origin>", "Skill origin (core, project, local)", "project")
607
+ .option("--skill-version <version>", "Skill version")
608
+ .action(async (file, options) => {
609
+ try {
610
+ const ctx = await initContext();
611
+ if (!ctx.manifestPath) {
612
+ error(errors.project.noKspecProject);
613
+ process.exit(EXIT_CODES.ERROR);
614
+ }
615
+ // Resolve file path
616
+ const filePath = path.isAbsolute(file)
617
+ ? file
618
+ : path.resolve(process.cwd(), file);
619
+ // Check file exists
620
+ try {
621
+ await fs.access(filePath);
622
+ }
623
+ catch {
624
+ error(`File not found: ${filePath}`);
625
+ process.exit(EXIT_CODES.NOT_FOUND);
626
+ }
627
+ // Read file content
628
+ const content = await fs.readFile(filePath, "utf-8");
629
+ // AC: @skill-import ac-1, ac-6 - Parse YAML frontmatter
630
+ // AC: @import-frontmatter-strip ac-1, ac-3 - Parse all Agent Skills fields
631
+ const frontmatter = parseFrontmatter(content);
632
+ // Determine name and description from frontmatter or options
633
+ // AC: @import-frontmatter-strip ac-6 - CLI flags work when no frontmatter
634
+ const skillName = options.name || frontmatter?.name;
635
+ const skillDescription = options.description || frontmatter?.description;
636
+ // AC: @skill-import ac-6, @import-frontmatter-strip ac-6 - Error if no name/description and no frontmatter
637
+ if (!skillName) {
638
+ error("Name is required. Either add YAML frontmatter with 'name' field or use --name option.");
639
+ console.log(chalk.gray("Example frontmatter:\n---\nname: my-skill\ndescription: My skill description\n---"));
640
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
641
+ }
642
+ if (!skillDescription) {
643
+ error("Description is required. Either add YAML frontmatter with 'description' field or use --description option.");
644
+ console.log(chalk.gray("Example frontmatter:\n---\nname: my-skill\ndescription: My skill description\n---"));
645
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
646
+ }
647
+ // AC: @skill-import ac-5 - Derive ID from directory name or use custom
648
+ const sourceDir = path.dirname(filePath);
649
+ const derivedId = path.basename(sourceDir);
650
+ const skillId = options.id || derivedId;
651
+ // Validate origin
652
+ const validOrigins = ["core", "project", "local"];
653
+ if (!validOrigins.includes(options.origin)) {
654
+ error(`Invalid origin: ${options.origin}. Valid origins: ${validOrigins.join(", ")}`);
655
+ process.exit(EXIT_CODES.ERROR);
656
+ }
657
+ // Check if skill with this ID already exists
658
+ const metaCtx = await loadMetaContext(ctx);
659
+ const existingSkill = metaCtx.skills.find((s) => s.id === skillId);
660
+ if (existingSkill) {
661
+ error(`Skill with ID '${skillId}' already exists. Use --id to specify a different ID.`);
662
+ process.exit(EXIT_CODES.CONFLICT);
663
+ }
664
+ // AC: @import-frontmatter-strip ac-3 - Build platform_config.claude_code from frontmatter
665
+ let platformConfig;
666
+ if (frontmatter) {
667
+ const claudeCodeConfig = {};
668
+ if (frontmatter.user_invocable !== undefined) {
669
+ claudeCodeConfig.user_invocable = frontmatter.user_invocable;
670
+ }
671
+ if (frontmatter.disable_model_invocation !== undefined) {
672
+ claudeCodeConfig.disable_model_invocation = frontmatter.disable_model_invocation;
673
+ }
674
+ if (frontmatter.context !== undefined) {
675
+ claudeCodeConfig.context = frontmatter.context;
676
+ }
677
+ if (frontmatter.agent !== undefined) {
678
+ claudeCodeConfig.agent = frontmatter.agent;
679
+ }
680
+ if (frontmatter.model !== undefined) {
681
+ claudeCodeConfig.model = frontmatter.model;
682
+ }
683
+ if (frontmatter.argument_hint !== undefined) {
684
+ claudeCodeConfig.argument_hint = frontmatter.argument_hint;
685
+ }
686
+ // Only set platform_config if we have Claude Code config fields
687
+ if (Object.keys(claudeCodeConfig).length > 0) {
688
+ platformConfig = { claude_code: claudeCodeConfig };
689
+ }
690
+ }
691
+ // Build skill object
692
+ // AC: @import-frontmatter-strip ac-1 - All recognized fields populate meta.yaml
693
+ // Schema provides defaults for platforms, depends_on, tags
694
+ const skillData = {
695
+ _ulid: ulid(),
696
+ id: skillId,
697
+ name: skillName,
698
+ description: skillDescription,
699
+ origin: options.origin,
700
+ version: options.skillVersion,
701
+ // AC: @import-frontmatter-strip ac-1 - license, compatibility, allowed_tools from frontmatter
702
+ license: frontmatter?.license,
703
+ compatibility: frontmatter?.compatibility,
704
+ allowed_tools: frontmatter?.allowed_tools || [],
705
+ // AC: @import-frontmatter-strip ac-3 - platform_config.claude_code from frontmatter
706
+ platform_config: platformConfig,
707
+ };
708
+ // Validate with schema
709
+ const parsed = SkillSchema.safeParse(skillData);
710
+ if (!parsed.success) {
711
+ const issues = parsed.error.issues
712
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
713
+ .join("; ");
714
+ error(`Invalid skill data: ${issues}`);
715
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
716
+ }
717
+ const skill = { ...parsed.data };
718
+ // Save meta entry (also creates directory)
719
+ await saveMetaItem(ctx, skill, "skill");
720
+ // AC: @skill-import ac-7 - Strip/normalize base-directory paths
721
+ // AC: @import-frontmatter-strip ac-2 - Store body-only content (strip frontmatter)
722
+ const normalizedContent = normalizeBaseDirectory(content);
723
+ const bodyOnlyContent = stripFrontmatter(normalizedContent);
724
+ // AC: @skill-import ac-2 - Copy content to .kspec/skills/<id>/SKILL.md
725
+ const skillMdPath = getSkillContentPath(ctx, skill.id);
726
+ await fs.writeFile(skillMdPath, bodyOnlyContent, "utf-8");
727
+ // AC: @import-frontmatter-strip ac-4, ac-5 - Copy all supporting directories
728
+ const supportingDirs = ["references", "scripts", "assets", "docs"];
729
+ for (const dirName of supportingDirs) {
730
+ const sourceSubDir = path.join(sourceDir, dirName);
731
+ try {
732
+ const stats = await fs.stat(sourceSubDir);
733
+ if (stats.isDirectory()) {
734
+ const targetSubDir = path.join(ctx.specDir, "skills", skill.id, dirName);
735
+ await fs.mkdir(targetSubDir, { recursive: true });
736
+ await copyDirectory(sourceSubDir, targetSubDir);
737
+ }
738
+ }
739
+ catch {
740
+ // Directory doesn't exist, that's fine
741
+ }
742
+ }
743
+ // Commit changes
744
+ await commitIfShadow(ctx.shadow, "skill-import", skill.id, skill.name);
745
+ output(skill, () => success(`Imported skill: ${skill.id}`, { skill }));
746
+ }
747
+ catch (err) {
748
+ error("Failed to import skill", err);
749
+ process.exit(EXIT_CODES.ERROR);
750
+ }
751
+ });
752
+ }
753
+ //# sourceMappingURL=skill-crud.js.map