@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,851 @@
1
+ /**
2
+ * Workflow run CLI commands
3
+ *
4
+ * Implements workflow run lifecycle management:
5
+ * - kspec workflow start @ref [--task @ref] [--json]
6
+ * - kspec workflow runs [--active] [--completed] [--workflow @ref] [--json]
7
+ * - kspec workflow show @run [--json]
8
+ * - kspec workflow abort @run [--reason text] [--json]
9
+ * - kspec workflow complete @run [--result <result>] [--json]
10
+ */
11
+ import chalk from "chalk";
12
+ import Table from "cli-table3";
13
+ import { ulid } from "ulid";
14
+ import { markMutating } from "../command-annotations.js";
15
+ import { deleteWorkflowRuns, findActiveRuns, findWorkflowRunByRef, getAuthor, initContext, loadAllTasks, loadMetaContext, loadWorkflowRuns, ReferenceIndex, saveWorkflowRun, updateWorkflowRun, } from "../../parser/index.js";
16
+ import { commitIfShadow } from "../../parser/shadow.js";
17
+ import { WorkflowRunResultSchema } from "../../schema/index.js";
18
+ import { errors } from "../../strings/errors.js";
19
+ import { EXIT_CODES } from "../exit-codes.js";
20
+ import { error, isJsonMode, output, success } from "../output.js";
21
+ /**
22
+ * Find a workflow by reference
23
+ */
24
+ function resolveWorkflowRef(ref, workflows) {
25
+ const cleanRef = ref.startsWith("@") ? ref.slice(1) : ref;
26
+ // Try by ID first
27
+ let workflow = workflows.find((w) => w.id === cleanRef);
28
+ if (workflow)
29
+ return workflow;
30
+ // Try by ULID or ULID prefix
31
+ workflow = workflows.find((w) => w._ulid === cleanRef ||
32
+ w._ulid.toLowerCase().startsWith(cleanRef.toLowerCase()));
33
+ return workflow || null;
34
+ }
35
+ /**
36
+ * Format a short ULID (first 8 chars)
37
+ */
38
+ function shortUlid(ulid) {
39
+ return ulid.slice(0, 8).toUpperCase();
40
+ }
41
+ /**
42
+ * Format run status with color
43
+ */
44
+ function formatStatus(status) {
45
+ switch (status) {
46
+ case "active":
47
+ return chalk.green(status);
48
+ case "paused":
49
+ return chalk.yellow(status);
50
+ case "completed":
51
+ return chalk.blue(status);
52
+ case "aborted":
53
+ return chalk.red(status);
54
+ default:
55
+ return status;
56
+ }
57
+ }
58
+ /**
59
+ * Command: kspec workflow start @workflow-ref [--task @task-ref] [--json]
60
+ * AC: @workflow-run-foundation ac-1, ac-6
61
+ */
62
+ async function workflowStart(workflowRef, options) {
63
+ const ctx = await initContext();
64
+ const metaCtx = await loadMetaContext(ctx);
65
+ // DEBUG: Log loaded workflows
66
+ // Resolve workflow reference
67
+ const workflow = resolveWorkflowRef(workflowRef, metaCtx.workflows);
68
+ if (!workflow) {
69
+ error(errors.workflowRun.workflowNotFound(workflowRef));
70
+ process.exit(EXIT_CODES.NOT_FOUND);
71
+ }
72
+ // Validate task reference if provided (AC: @workflow-run-foundation ac-6)
73
+ let taskRef;
74
+ if (options.task) {
75
+ const tasks = await loadAllTasks(ctx);
76
+ const index = new ReferenceIndex(tasks, []);
77
+ const result = index.resolve(options.task);
78
+ if (!result.ok) {
79
+ error(errors.reference.taskNotFound(options.task));
80
+ process.exit(EXIT_CODES.NOT_FOUND);
81
+ }
82
+ taskRef = `@${result.ulid}`;
83
+ }
84
+ // Create new workflow run
85
+ const run = {
86
+ _ulid: ulid(),
87
+ workflow_ref: `@${workflow._ulid}`,
88
+ status: "active",
89
+ current_step: 0,
90
+ total_steps: workflow.steps.length,
91
+ started_at: new Date().toISOString(),
92
+ step_results: [],
93
+ initiated_by: getAuthor(ctx.config?.identity?.author),
94
+ task_ref: taskRef,
95
+ };
96
+ // Save the run
97
+ await saveWorkflowRun(ctx, run);
98
+ // Commit to shadow
99
+ await commitIfShadow(ctx.shadow, "workflow-start");
100
+ // Output result
101
+ if (isJsonMode()) {
102
+ output({
103
+ run_id: run._ulid,
104
+ workflow_ref: run.workflow_ref,
105
+ status: run.status,
106
+ });
107
+ }
108
+ else {
109
+ success(`Started workflow run: ${shortUlid(run._ulid)}`);
110
+ console.log(` Workflow: ${workflow.id}`);
111
+ console.log(` Steps: ${run.total_steps}`);
112
+ if (taskRef) {
113
+ console.log(` Linked task: ${taskRef}`);
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Command: kspec workflow runs [--active] [--completed] [--workflow @ref] [--json]
119
+ * AC: @workflow-run-foundation ac-2
120
+ */
121
+ async function workflowRuns(options) {
122
+ const ctx = await initContext();
123
+ const metaCtx = await loadMetaContext(ctx);
124
+ let runs = await loadWorkflowRuns(ctx);
125
+ // Apply filters
126
+ if (options.active) {
127
+ runs = runs.filter((r) => r.status === "active");
128
+ }
129
+ if (options.completed) {
130
+ runs = runs.filter((r) => r.status === "completed");
131
+ }
132
+ if (options.workflow) {
133
+ const workflow = resolveWorkflowRef(options.workflow, metaCtx.workflows);
134
+ if (!workflow) {
135
+ error(errors.workflowRun.workflowNotFound(options.workflow));
136
+ process.exit(EXIT_CODES.NOT_FOUND);
137
+ }
138
+ runs = runs.filter((r) => r.workflow_ref === `@${workflow._ulid}`);
139
+ }
140
+ if (isJsonMode()) {
141
+ output({ runs });
142
+ }
143
+ else {
144
+ if (runs.length === 0) {
145
+ console.log(chalk.gray("No workflow runs found"));
146
+ return;
147
+ }
148
+ const table = new Table({
149
+ head: ["ID", "Workflow", "Status", "Step", "Started"],
150
+ colWidths: [12, 25, 12, 10, 20],
151
+ });
152
+ for (const run of runs) {
153
+ const workflow = metaCtx.workflows.find((w) => `@${w._ulid}` === run.workflow_ref);
154
+ const workflowName = workflow?.id || run.workflow_ref;
155
+ const stepProgress = `${run.current_step + 1}/${run.total_steps}`;
156
+ const started = new Date(run.started_at).toLocaleString();
157
+ table.push([
158
+ shortUlid(run._ulid),
159
+ workflowName,
160
+ formatStatus(run.status),
161
+ stepProgress,
162
+ started,
163
+ ]);
164
+ }
165
+ console.log(table.toString());
166
+ }
167
+ }
168
+ /**
169
+ * Command: kspec workflow show @run-id [--json]
170
+ * AC: @workflow-run-foundation ac-4
171
+ */
172
+ async function workflowShow(runRef, _options) {
173
+ const ctx = await initContext();
174
+ const metaCtx = await loadMetaContext(ctx);
175
+ const run = await findWorkflowRunByRef(ctx, runRef);
176
+ if (!run) {
177
+ error(errors.workflowRun.runNotFound(runRef));
178
+ process.exit(EXIT_CODES.NOT_FOUND);
179
+ }
180
+ if (isJsonMode()) {
181
+ output({ run });
182
+ }
183
+ else {
184
+ const workflow = metaCtx.workflows.find((w) => `@${w._ulid}` === run.workflow_ref);
185
+ const workflowName = workflow?.id || run.workflow_ref;
186
+ console.log(chalk.bold("Workflow Run Details"));
187
+ console.log(chalk.gray("─".repeat(50)));
188
+ console.log(`ID: ${shortUlid(run._ulid)}`);
189
+ console.log(`Workflow: ${workflowName} (${run.workflow_ref})`);
190
+ console.log(`Status: ${formatStatus(run.status)}`);
191
+ console.log(`Progress: ${run.current_step + 1}/${run.total_steps}`);
192
+ console.log(`Started: ${new Date(run.started_at).toLocaleString()}`);
193
+ if (run.initiated_by) {
194
+ console.log(`Initiated by: ${run.initiated_by}`);
195
+ }
196
+ if (run.task_ref) {
197
+ console.log(`Task: ${run.task_ref}`);
198
+ }
199
+ if (run.paused_at) {
200
+ console.log(`Paused: ${new Date(run.paused_at).toLocaleString()}`);
201
+ }
202
+ if (run.completed_at) {
203
+ console.log(`Completed: ${new Date(run.completed_at).toLocaleString()}`);
204
+ }
205
+ if (run.abort_reason) {
206
+ console.log(`Abort reason: ${run.abort_reason}`);
207
+ }
208
+ if (run.step_results.length > 0) {
209
+ console.log(chalk.gray("\nStep Results:"));
210
+ const table = new Table({
211
+ head: ["Step", "Status", "Started", "Completed"],
212
+ colWidths: [8, 12, 20, 20],
213
+ });
214
+ for (const result of run.step_results) {
215
+ table.push([
216
+ (result.step_index + 1).toString(),
217
+ formatStatus(result.status),
218
+ new Date(result.started_at).toLocaleString(),
219
+ new Date(result.completed_at).toLocaleString(),
220
+ ]);
221
+ }
222
+ console.log(table.toString());
223
+ }
224
+ }
225
+ }
226
+ /**
227
+ * Command: kspec workflow abort @run-id [--reason text] [--json]
228
+ * AC: @workflow-run-foundation ac-3, ac-5
229
+ */
230
+ async function workflowAbort(runRef, options) {
231
+ const ctx = await initContext();
232
+ const run = await findWorkflowRunByRef(ctx, runRef);
233
+ if (!run) {
234
+ error(errors.workflowRun.runNotFound(runRef));
235
+ process.exit(EXIT_CODES.NOT_FOUND);
236
+ }
237
+ // AC: @workflow-run-foundation ac-5 - Cannot abort completed or aborted runs
238
+ if (run.status === "completed") {
239
+ error(errors.workflowRun.cannotAbortCompleted);
240
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
241
+ }
242
+ if (run.status === "aborted") {
243
+ error(errors.workflowRun.cannotAbortAborted);
244
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
245
+ }
246
+ // Update run status
247
+ run.status = "aborted";
248
+ run.abort_reason = options.reason;
249
+ run.completed_at = new Date().toISOString();
250
+ await updateWorkflowRun(ctx, run);
251
+ await commitIfShadow(ctx.shadow, "workflow-abort");
252
+ if (isJsonMode()) {
253
+ output({ run_id: run._ulid, status: run.status });
254
+ }
255
+ else {
256
+ success(`Aborted workflow run: ${shortUlid(run._ulid)}`);
257
+ if (options.reason) {
258
+ console.log(` Reason: ${options.reason}`);
259
+ }
260
+ }
261
+ }
262
+ /**
263
+ * Command: kspec workflow complete @run-id [--result <result>] [--json]
264
+ * Marks a workflow run as completed with an optional result.
265
+ * Use this for graceful exits (e.g., no_work_available) instead of aborting.
266
+ */
267
+ async function workflowComplete(runRef, options) {
268
+ const ctx = await initContext();
269
+ const run = await findWorkflowRunByRef(ctx, runRef);
270
+ if (!run) {
271
+ error(errors.workflowRun.runNotFound(runRef));
272
+ process.exit(EXIT_CODES.NOT_FOUND);
273
+ }
274
+ // Cannot complete already finished runs
275
+ if (run.status === "completed") {
276
+ error(`Cannot complete run ${shortUlid(run._ulid)}: already completed`);
277
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
278
+ }
279
+ if (run.status === "aborted") {
280
+ error(`Cannot complete run ${shortUlid(run._ulid)}: already aborted`);
281
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
282
+ }
283
+ // Validate result if provided
284
+ let result;
285
+ if (options.result) {
286
+ const parseResult = WorkflowRunResultSchema.safeParse(options.result);
287
+ if (!parseResult.success) {
288
+ const validResults = WorkflowRunResultSchema.options.join(", ");
289
+ error(`Invalid result: ${options.result}. Must be one of: ${validResults}`);
290
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
291
+ }
292
+ result = parseResult.data;
293
+ }
294
+ // Update run status
295
+ run.status = "completed";
296
+ run.completed_at = new Date().toISOString();
297
+ if (result) {
298
+ run.result = result;
299
+ }
300
+ await updateWorkflowRun(ctx, run);
301
+ await commitIfShadow(ctx.shadow, "workflow-complete");
302
+ if (isJsonMode()) {
303
+ output({
304
+ run_id: run._ulid,
305
+ status: run.status,
306
+ result: run.result,
307
+ completed_at: run.completed_at,
308
+ });
309
+ }
310
+ else {
311
+ const resultInfo = run.result ? ` (${run.result})` : "";
312
+ success(`Completed workflow run: ${shortUlid(run._ulid)}${resultInfo}`);
313
+ }
314
+ }
315
+ /**
316
+ * Command: kspec workflow pause @run-id [--json]
317
+ * AC: @workflow-advanced-features ac-1
318
+ */
319
+ async function workflowPause(runRef, _options) {
320
+ const ctx = await initContext();
321
+ const run = await findWorkflowRunByRef(ctx, runRef);
322
+ if (!run) {
323
+ error(errors.workflowRun.runNotFound(runRef));
324
+ process.exit(EXIT_CODES.NOT_FOUND);
325
+ }
326
+ // Only active runs can be paused
327
+ if (run.status !== "active") {
328
+ error(`Cannot pause run ${shortUlid(run._ulid)}: current status is ${run.status}`);
329
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
330
+ }
331
+ // Update run status
332
+ run.status = "paused";
333
+ run.paused_at = new Date().toISOString();
334
+ await updateWorkflowRun(ctx, run);
335
+ await commitIfShadow(ctx.shadow, "workflow-pause");
336
+ if (isJsonMode()) {
337
+ output({ run_id: run._ulid, status: run.status, paused_at: run.paused_at });
338
+ }
339
+ else {
340
+ success(`Paused run ${shortUlid(run._ulid)} at step ${run.current_step + 1}/${run.total_steps}`);
341
+ }
342
+ }
343
+ /**
344
+ * Command: kspec workflow resume @run-id [--json]
345
+ * AC: @workflow-advanced-features ac-2, ac-4
346
+ */
347
+ async function workflowResume(runRef, _options) {
348
+ const ctx = await initContext();
349
+ const metaCtx = await loadMetaContext(ctx);
350
+ const run = await findWorkflowRunByRef(ctx, runRef);
351
+ if (!run) {
352
+ error(errors.workflowRun.runNotFound(runRef));
353
+ process.exit(EXIT_CODES.NOT_FOUND);
354
+ }
355
+ // AC: @workflow-advanced-features ac-4 - Error if not paused
356
+ if (run.status !== "paused") {
357
+ error(`Cannot resume run ${shortUlid(run._ulid)}: current status is ${run.status} (expected paused)`);
358
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
359
+ }
360
+ // Update run status
361
+ run.status = "active";
362
+ run.paused_at = undefined;
363
+ await updateWorkflowRun(ctx, run);
364
+ await commitIfShadow(ctx.shadow, "workflow-resume");
365
+ // Get workflow definition to show current step
366
+ const workflow = metaCtx.workflows.find((w) => `@${w._ulid}` === run.workflow_ref);
367
+ if (!workflow) {
368
+ error(errors.workflowRun.workflowNotFound(run.workflow_ref));
369
+ process.exit(EXIT_CODES.NOT_FOUND);
370
+ }
371
+ const currentStep = workflow.steps[run.current_step];
372
+ if (isJsonMode()) {
373
+ output({
374
+ run_id: run._ulid,
375
+ status: run.status,
376
+ current_step: run.current_step,
377
+ total_steps: run.total_steps,
378
+ next_step: {
379
+ type: currentStep.type,
380
+ content: currentStep.content,
381
+ },
382
+ });
383
+ }
384
+ else {
385
+ success(`Resumed run ${shortUlid(run._ulid)}`);
386
+ console.log(`\nStep ${run.current_step + 1}/${run.total_steps}: [${currentStep.type}] ${currentStep.content}`);
387
+ }
388
+ }
389
+ /**
390
+ * Command: kspec workflow next [run-ref] [--skip] [--notes text] [--confirm] [--force] [--input key=value] [--json]
391
+ * AC: @workflow-step-navigation ac-1 through ac-6
392
+ * AC: @workflow-enforcement-modes ac-1 through ac-4
393
+ * AC: @workflow-advanced-features ac-3
394
+ */
395
+ async function workflowNext(runRef, options) {
396
+ const ctx = await initContext();
397
+ const metaCtx = await loadMetaContext(ctx);
398
+ let run;
399
+ // AC: @workflow-step-navigation ac-3, ac-4, ac-5
400
+ if (!runRef) {
401
+ const activeRuns = await findActiveRuns(ctx);
402
+ if (activeRuns.length === 0) {
403
+ // AC: @workflow-step-navigation ac-5
404
+ error(errors.workflowRun.noActiveRuns);
405
+ process.exit(EXIT_CODES.NOT_FOUND);
406
+ }
407
+ if (activeRuns.length > 1) {
408
+ // AC: @workflow-step-navigation ac-4
409
+ const runIds = activeRuns.map((r) => shortUlid(r._ulid));
410
+ error(errors.workflowRun.multipleActiveRuns(runIds));
411
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
412
+ }
413
+ // AC: @workflow-step-navigation ac-3 - exactly one active run
414
+ run = activeRuns[0];
415
+ }
416
+ else {
417
+ run = await findWorkflowRunByRef(ctx, runRef);
418
+ if (!run) {
419
+ error(errors.workflowRun.runNotFound(runRef));
420
+ process.exit(EXIT_CODES.NOT_FOUND);
421
+ }
422
+ if (run.status !== "active") {
423
+ error(errors.workflowRun.runNotActive(runRef, run.status));
424
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
425
+ }
426
+ }
427
+ // Get workflow definition to access steps
428
+ const workflow = metaCtx.workflows.find((w) => `@${w._ulid}` === run.workflow_ref);
429
+ if (!workflow) {
430
+ error(errors.workflowRun.workflowNotFound(run.workflow_ref));
431
+ process.exit(EXIT_CODES.NOT_FOUND);
432
+ }
433
+ // Get current step and next step
434
+ const currentStepIndex = run.current_step;
435
+ const currentStep = workflow.steps[currentStepIndex];
436
+ const isStrictMode = workflow.enforcement === "strict";
437
+ const isLastStep = currentStepIndex === run.total_steps - 1;
438
+ // AC: @workflow-advanced-features ac-3 - Handle step inputs
439
+ const stepInputs = {};
440
+ if (currentStep.inputs && currentStep.inputs.length > 0) {
441
+ // Display required inputs if not in JSON mode
442
+ if (!isJsonMode()) {
443
+ console.log(`Step ${currentStepIndex + 1}/${run.total_steps}: [${currentStep.type}] ${currentStep.content}`);
444
+ console.log(chalk.cyan(" Inputs required:"));
445
+ for (const input of currentStep.inputs) {
446
+ const requiredLabel = input.required !== false ? "" : " (optional)";
447
+ const typeLabel = input.type ? ` (${input.type})` : "";
448
+ const desc = input.description ? `: ${input.description}` : "";
449
+ console.log(chalk.cyan(` - ${input.name}${typeLabel}${requiredLabel}${desc}`));
450
+ }
451
+ console.log();
452
+ }
453
+ // Parse --input flags
454
+ if (options.input) {
455
+ for (const inputStr of options.input) {
456
+ const [key, ...valueParts] = inputStr.split("=");
457
+ if (!valueParts.length) {
458
+ error(`Invalid input format: "${inputStr}". Expected format: key=value`);
459
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
460
+ }
461
+ stepInputs[key] = valueParts.join("="); // Rejoin in case value contains '='
462
+ }
463
+ }
464
+ // Validate required inputs
465
+ for (const input of currentStep.inputs) {
466
+ if (input.required !== false && !stepInputs[input.name]) {
467
+ error(`Missing required input: ${input.name}`);
468
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
469
+ }
470
+ }
471
+ }
472
+ // AC: @workflow-enforcement-modes ac-3 - Strict mode: --skip requires --force
473
+ if (options.skip && isStrictMode && !options.force) {
474
+ error(errors.workflowRun.skipRequiresForce);
475
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
476
+ }
477
+ // AC: @workflow-enforcement-modes ac-2, ac-3 - Check exit criteria for CURRENT step
478
+ if (currentStep.exit_criteria &&
479
+ currentStep.exit_criteria.length > 0 &&
480
+ !options.skip) {
481
+ // AC: @workflow-enforcement-modes ac-3 - Strict mode requires --confirm
482
+ if (isStrictMode && !options.confirm) {
483
+ if (!isJsonMode()) {
484
+ console.log(`Completing step ${currentStepIndex + 1}/${run.total_steps}: [${currentStep.type}] ${currentStep.content}`);
485
+ console.log(chalk.yellow(" Exit criteria:"));
486
+ for (const criterion of currentStep.exit_criteria) {
487
+ console.log(chalk.yellow(` - ${criterion}`));
488
+ }
489
+ console.log();
490
+ }
491
+ error(errors.workflowRun.exitCriteriaNotConfirmed);
492
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
493
+ }
494
+ // AC: @workflow-enforcement-modes ac-4 - Advisory mode shows criteria as guidance
495
+ if (!isStrictMode && !isJsonMode()) {
496
+ console.log(chalk.gray(" Exit criteria:"));
497
+ for (const criterion of currentStep.exit_criteria) {
498
+ console.log(chalk.gray(` - ${criterion}`));
499
+ }
500
+ }
501
+ }
502
+ // AC: @workflow-enforcement-modes ac-1, ac-3 - Check entry criteria for NEXT step
503
+ // (Only applies when advancing from current step normally, not when skipping or completing the workflow)
504
+ // When skipping, we don't check entry criteria because we're not actually starting the next step yet
505
+ if (!isLastStep && !options.skip) {
506
+ const nextStep = workflow.steps[currentStepIndex + 1];
507
+ if (nextStep.entry_criteria && nextStep.entry_criteria.length > 0) {
508
+ // AC: @workflow-enforcement-modes ac-3 - Strict mode requires --confirm
509
+ if (isStrictMode && !options.confirm) {
510
+ if (!isJsonMode()) {
511
+ console.log(`Step ${currentStepIndex + 2}/${run.total_steps}: [${nextStep.type}] ${nextStep.content}`);
512
+ console.log(chalk.yellow(" Entry criteria:"));
513
+ for (const criterion of nextStep.entry_criteria) {
514
+ console.log(chalk.yellow(` - ${criterion}`));
515
+ }
516
+ console.log();
517
+ }
518
+ error(errors.workflowRun.entryCriteriaNotConfirmed);
519
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
520
+ }
521
+ // AC: @workflow-enforcement-modes ac-4 - Advisory mode shows criteria as guidance
522
+ if (!isStrictMode && !isJsonMode()) {
523
+ console.log(`Step ${currentStepIndex + 2}/${run.total_steps}: [${nextStep.type}] ${nextStep.content}`);
524
+ console.log(chalk.gray(" Entry criteria:"));
525
+ for (const criterion of nextStep.entry_criteria) {
526
+ console.log(chalk.gray(` - ${criterion}`));
527
+ }
528
+ console.log();
529
+ }
530
+ }
531
+ }
532
+ // AC: @workflow-step-navigation ac-1, ac-6 - Complete current step
533
+ const previousResult = run.step_results[run.step_results.length - 1];
534
+ const startedAt = previousResult
535
+ ? previousResult.completed_at
536
+ : run.started_at;
537
+ // AC: @workflow-enforcement-modes ac-3 - Record confirmations in StepResult
538
+ // Check if a stub result already exists for this step (created when we advanced to it)
539
+ const existingResultIndex = run.step_results.findIndex((r) => r.step_index === currentStepIndex);
540
+ if (existingResultIndex >= 0) {
541
+ // Update existing stub result with completion data
542
+ const existingResult = run.step_results[existingResultIndex];
543
+ run.step_results[existingResultIndex] = {
544
+ ...existingResult,
545
+ status: options.skip ? "skipped" : "completed",
546
+ completed_at: new Date().toISOString(),
547
+ notes: options.notes,
548
+ exit_confirmed: currentStep.exit_criteria &&
549
+ currentStep.exit_criteria.length > 0 &&
550
+ options.confirm
551
+ ? true
552
+ : undefined,
553
+ inputs: Object.keys(stepInputs).length > 0 ? stepInputs : undefined,
554
+ };
555
+ }
556
+ else {
557
+ // No stub exists (first step or old data), create complete result
558
+ const stepResult = {
559
+ step_index: currentStepIndex,
560
+ status: options.skip ? "skipped" : "completed",
561
+ started_at: startedAt,
562
+ completed_at: new Date().toISOString(),
563
+ notes: options.notes,
564
+ exit_confirmed: currentStep.exit_criteria &&
565
+ currentStep.exit_criteria.length > 0 &&
566
+ options.confirm
567
+ ? true
568
+ : undefined,
569
+ entry_confirmed: undefined,
570
+ inputs: Object.keys(stepInputs).length > 0 ? stepInputs : undefined,
571
+ };
572
+ run.step_results.push(stepResult);
573
+ }
574
+ // AC: @workflow-step-navigation ac-1 - Advance to next step or complete run
575
+ if (isLastStep) {
576
+ // AC: @workflow-step-navigation ac-2 - Complete the run
577
+ run.status = "completed";
578
+ run.completed_at = new Date().toISOString();
579
+ await updateWorkflowRun(ctx, run);
580
+ await commitIfShadow(ctx.shadow, "workflow-next");
581
+ // Calculate summary stats
582
+ const totalDuration = new Date(run.completed_at).getTime() - new Date(run.started_at).getTime();
583
+ const completedSteps = run.step_results.filter((r) => r.status === "completed").length;
584
+ const skippedSteps = run.step_results.filter((r) => r.status === "skipped").length;
585
+ if (isJsonMode()) {
586
+ output({
587
+ run_id: run._ulid,
588
+ status: run.status,
589
+ completed_at: run.completed_at,
590
+ total_duration_ms: totalDuration,
591
+ steps_completed: completedSteps,
592
+ steps_skipped: skippedSteps,
593
+ });
594
+ }
595
+ else {
596
+ const currentStep = workflow.steps[currentStepIndex];
597
+ success(`Completed step ${currentStepIndex + 1}/${run.total_steps}: [${currentStep.type}] ${currentStep.content}`);
598
+ console.log();
599
+ console.log(chalk.bold("Workflow completed!"));
600
+ console.log(` Duration: ${Math.round(totalDuration / 1000)}s`);
601
+ console.log(` Steps completed: ${completedSteps}`);
602
+ console.log(` Steps skipped: ${skippedSteps}`);
603
+ }
604
+ }
605
+ else {
606
+ // Advance to next step
607
+ run.current_step += 1;
608
+ // AC: @workflow-enforcement-modes ac-3 - Record entry confirmation for the next step
609
+ // Create a stub step result for the next step to capture entry_confirmed and started_at
610
+ // This will be updated with completion data when the step is completed
611
+ const nextStep = workflow.steps[run.current_step];
612
+ const nextStepStartedAt = run.step_results[run.step_results.length - 1]?.completed_at ||
613
+ new Date().toISOString();
614
+ const nextStepStub = {
615
+ step_index: run.current_step,
616
+ status: "completed", // Placeholder, will be updated
617
+ started_at: nextStepStartedAt,
618
+ completed_at: nextStepStartedAt, // Placeholder, will be updated
619
+ entry_confirmed: nextStep.entry_criteria &&
620
+ nextStep.entry_criteria.length > 0 &&
621
+ options.confirm
622
+ ? true
623
+ : undefined,
624
+ };
625
+ run.step_results.push(nextStepStub);
626
+ await updateWorkflowRun(ctx, run);
627
+ await commitIfShadow(ctx.shadow, "workflow-next");
628
+ if (isJsonMode()) {
629
+ output({
630
+ run_id: run._ulid,
631
+ current_step: run.current_step,
632
+ total_steps: run.total_steps,
633
+ next_step: {
634
+ type: nextStep.type,
635
+ content: nextStep.content,
636
+ },
637
+ });
638
+ }
639
+ else {
640
+ const previousStep = workflow.steps[currentStepIndex];
641
+ success(`Completed step ${currentStepIndex + 1}/${run.total_steps}: [${previousStep.type}] ${previousStep.content}`);
642
+ console.log();
643
+ console.log(`Step ${run.current_step + 1}/${run.total_steps}: [${nextStep.type}] ${nextStep.content}`);
644
+ }
645
+ }
646
+ }
647
+ /**
648
+ * Command: kspec workflow prune [--older-than <duration>] [--status <status>] [--abandoned] [--dry-run]
649
+ * AC: @workflow-prune ac-1, ac-2, ac-3, ac-4
650
+ */
651
+ async function workflowPrune(options) {
652
+ const ctx = await initContext();
653
+ let runs = await loadWorkflowRuns(ctx);
654
+ // Track which runs to prune
655
+ let toPrune = [];
656
+ // AC: @workflow-prune ac-1 - Filter by age
657
+ if (options.olderThan) {
658
+ const match = options.olderThan.match(/^(\d+)([dhm])$/);
659
+ if (!match) {
660
+ error('Invalid duration format. Use format like: 30d (days), 12h (hours), 45m (minutes)');
661
+ process.exit(EXIT_CODES.USAGE_ERROR);
662
+ }
663
+ const [, amount, unit] = match;
664
+ const amountNum = parseInt(amount);
665
+ const milliseconds = {
666
+ m: amountNum * 60 * 1000,
667
+ h: amountNum * 60 * 60 * 1000,
668
+ d: amountNum * 24 * 60 * 60 * 1000,
669
+ }[unit];
670
+ if (milliseconds === undefined) {
671
+ error('Invalid duration unit. Use d (days), h (hours), or m (minutes)');
672
+ process.exit(EXIT_CODES.USAGE_ERROR);
673
+ }
674
+ const cutoffTime = Date.now() - milliseconds;
675
+ toPrune = runs.filter((r) => {
676
+ const runTime = new Date(r.started_at).getTime();
677
+ return runTime < cutoffTime;
678
+ });
679
+ }
680
+ // AC: @workflow-prune ac-2 - Filter by status
681
+ if (options.status) {
682
+ const validStatuses = ['active', 'paused', 'completed', 'aborted'];
683
+ if (!validStatuses.includes(options.status)) {
684
+ error(`Invalid status: ${options.status}. Must be one of: ${validStatuses.join(', ')}`);
685
+ process.exit(EXIT_CODES.USAGE_ERROR);
686
+ }
687
+ if (toPrune.length > 0) {
688
+ // Filter existing toPrune list
689
+ toPrune = toPrune.filter((r) => r.status === options.status);
690
+ }
691
+ else {
692
+ // No age filter, just status
693
+ toPrune = runs.filter((r) => r.status === options.status);
694
+ }
695
+ }
696
+ // AC: @workflow-prune ac-3 - Filter by abandoned (active with no activity for 7+ days)
697
+ if (options.abandoned) {
698
+ const abandonedCutoff = Date.now() - 7 * 24 * 60 * 60 * 1000; // 7 days
699
+ const abandonedRuns = runs.filter((r) => {
700
+ if (r.status !== 'active')
701
+ return false;
702
+ // Find most recent activity time
703
+ let lastActivity = new Date(r.started_at).getTime();
704
+ if (r.step_results.length > 0) {
705
+ const lastStep = r.step_results[r.step_results.length - 1];
706
+ lastActivity = new Date(lastStep.completed_at).getTime();
707
+ }
708
+ return lastActivity < abandonedCutoff;
709
+ });
710
+ if (toPrune.length > 0) {
711
+ // Intersect with existing toPrune list
712
+ const abandonedUlids = new Set(abandonedRuns.map((r) => r._ulid));
713
+ toPrune = toPrune.filter((r) => abandonedUlids.has(r._ulid));
714
+ }
715
+ else {
716
+ toPrune = abandonedRuns;
717
+ }
718
+ }
719
+ // If no filters provided, error
720
+ if (!options.olderThan && !options.status && !options.abandoned) {
721
+ error('Must specify at least one filter: --older-than, --status, or --abandoned');
722
+ process.exit(EXIT_CODES.USAGE_ERROR);
723
+ }
724
+ // AC: @workflow-prune ac-4 - Dry run mode
725
+ if (options.dryRun || isJsonMode()) {
726
+ const output_data = {
727
+ would_delete: toPrune.length,
728
+ runs: toPrune.map((r) => ({
729
+ _ulid: r._ulid,
730
+ workflow_ref: r.workflow_ref,
731
+ status: r.status,
732
+ started_at: r.started_at,
733
+ })),
734
+ };
735
+ if (isJsonMode()) {
736
+ output(output_data);
737
+ }
738
+ else {
739
+ console.log(chalk.yellow(`Would delete ${toPrune.length} workflow run${toPrune.length === 1 ? '' : 's'}:`));
740
+ if (toPrune.length > 0) {
741
+ const table = new Table({
742
+ head: ['ID', 'Workflow', 'Status', 'Started'],
743
+ colWidths: [12, 25, 12, 20],
744
+ });
745
+ const metaCtx = await loadMetaContext(ctx);
746
+ for (const run of toPrune) {
747
+ const workflow = metaCtx.workflows.find((w) => `@${w._ulid}` === run.workflow_ref);
748
+ const workflowName = workflow?.id || run.workflow_ref;
749
+ const started = new Date(run.started_at).toLocaleString();
750
+ table.push([
751
+ shortUlid(run._ulid),
752
+ workflowName,
753
+ formatStatus(run.status),
754
+ started,
755
+ ]);
756
+ }
757
+ console.log(table.toString());
758
+ console.log(chalk.gray('\nRun without --dry-run to actually delete these runs'));
759
+ }
760
+ }
761
+ return;
762
+ }
763
+ // Actually delete
764
+ if (toPrune.length === 0) {
765
+ if (!isJsonMode()) {
766
+ console.log(chalk.gray('No runs match the specified criteria'));
767
+ }
768
+ else {
769
+ output({ deleted: 0 });
770
+ }
771
+ return;
772
+ }
773
+ const ulidsToDelete = toPrune.map((r) => r._ulid);
774
+ await deleteWorkflowRuns(ctx, ulidsToDelete);
775
+ await commitIfShadow(ctx.shadow, 'workflow-prune');
776
+ if (isJsonMode()) {
777
+ output({ deleted: toPrune.length });
778
+ }
779
+ else {
780
+ success(`Deleted ${toPrune.length} workflow run${toPrune.length === 1 ? '' : 's'}`);
781
+ }
782
+ }
783
+ /**
784
+ * Register workflow commands
785
+ */
786
+ export function registerWorkflowCommand(program) {
787
+ const workflow = program
788
+ .command("workflow")
789
+ .description("Manage workflow runs");
790
+ markMutating(workflow.command("start"))
791
+ .description("Start a new workflow run")
792
+ .argument("<workflow-ref>", "Workflow reference (@id or @ulid)")
793
+ .option("--task <task-ref>", "Link run to a task")
794
+ .option("--json", "Output JSON")
795
+ .action(workflowStart);
796
+ workflow
797
+ .command("runs")
798
+ .description("List workflow runs")
799
+ .option("--active", "Show only active runs")
800
+ .option("--completed", "Show only completed runs")
801
+ .option("--workflow <ref>", "Filter by workflow")
802
+ .option("--json", "Output JSON")
803
+ .action(workflowRuns);
804
+ workflow
805
+ .command("show")
806
+ .description("Show workflow run details")
807
+ .argument("<run-ref>", "Run reference (@ulid or ulid prefix)")
808
+ .option("--json", "Output JSON")
809
+ .action(workflowShow);
810
+ markMutating(workflow.command("abort"))
811
+ .description("Abort an active workflow run")
812
+ .argument("<run-ref>", "Run reference (@ulid or ulid prefix)")
813
+ .option("--reason <text>", "Reason for aborting")
814
+ .option("--json", "Output JSON")
815
+ .action(workflowAbort);
816
+ markMutating(workflow.command("complete"))
817
+ .description("Mark workflow run as completed (graceful exit)")
818
+ .argument("<run-ref>", "Run reference (@ulid or ulid prefix)")
819
+ .option("--result <result>", "Completion result (success, no_work_available, early_exit)")
820
+ .option("--json", "Output JSON")
821
+ .action(workflowComplete);
822
+ markMutating(workflow.command("next"))
823
+ .description("Advance workflow run to next step")
824
+ .argument("[run-ref]", "Run reference (optional if only one active run)")
825
+ .option("--skip", "Mark current step as skipped")
826
+ .option("--notes <text>", "Notes for the completed step")
827
+ .option("--confirm", "Acknowledge entry/exit criteria (required in strict mode)")
828
+ .option("--force", "Allow --skip in strict mode")
829
+ .option("--input <key=value>", "Provide step input (repeatable)", (value, previous = []) => [...previous, value])
830
+ .option("--json", "Output JSON")
831
+ .action(workflowNext);
832
+ markMutating(workflow.command("pause"))
833
+ .description("Pause an active workflow run")
834
+ .argument("<run-ref>", "Run reference (@ulid or ulid prefix)")
835
+ .option("--json", "Output JSON")
836
+ .action(workflowPause);
837
+ markMutating(workflow.command("resume"))
838
+ .description("Resume a paused workflow run")
839
+ .argument("<run-ref>", "Run reference (@ulid or ulid prefix)")
840
+ .option("--json", "Output JSON")
841
+ .action(workflowResume);
842
+ markMutating(workflow.command("prune"))
843
+ .description("Remove old or stale workflow runs")
844
+ .option("--older-than <duration>", "Delete runs older than specified duration (e.g., 30d, 12h, 45m)")
845
+ .option("--status <status>", "Delete runs with specific status (active, paused, completed, aborted)")
846
+ .option("--abandoned", "Delete active runs with no activity for 7+ days")
847
+ .option("--dry-run", "Show what would be deleted without deleting")
848
+ .option("--json", "Output JSON")
849
+ .action(workflowPrune);
850
+ }
851
+ //# sourceMappingURL=workflow.js.map