@kynetic-ai/spec 0.1.2 → 0.3.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 (510) 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 +116 -0
  32. package/dist/cli/batch-exec.d.ts.map +1 -0
  33. package/dist/cli/batch-exec.js +694 -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 +140 -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 +57 -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 +533 -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 +516 -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 +1097 -169
  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 +811 -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 +1233 -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 +53 -0
  156. package/dist/cli/commands/skill-install.d.ts.map +1 -0
  157. package/dist/cli/commands/skill-install.js +452 -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 +569 -346
  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 +227 -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 +569 -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 +235 -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 +468 -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 +351 -0
  309. package/dist/parser/config.d.ts.map +1 -0
  310. package/dist/parser/config.js +326 -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 +189 -0
  345. package/dist/parser/plan-document.d.ts.map +1 -0
  346. package/dist/parser/plan-document.js +340 -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 +277 -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 +83 -0
  401. package/dist/ralph/subagent.d.ts.map +1 -0
  402. package/dist/ralph/subagent.js +174 -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 +95 -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 +2 -2
  413. package/dist/schema/common.d.ts.map +1 -1
  414. package/dist/schema/common.js +34 -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 +233 -1
  448. package/dist/sessions/store.d.ts.map +1 -1
  449. package/dist/sessions/store.js +628 -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 +51 -0
  456. package/dist/strings/errors.d.ts.map +1 -1
  457. package/dist/strings/errors.js +136 -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/utils/commit.d.ts +1 -1
  474. package/dist/utils/commit.d.ts.map +1 -1
  475. package/dist/utils/commit.js +28 -26
  476. package/dist/utils/commit.js.map +1 -1
  477. package/dist/utils/git.d.ts +1 -1
  478. package/dist/utils/git.d.ts.map +1 -1
  479. package/dist/utils/git.js +40 -38
  480. package/dist/utils/git.js.map +1 -1
  481. package/dist/utils/grep.js +11 -11
  482. package/dist/utils/grep.js.map +1 -1
  483. package/dist/utils/index.d.ts +7 -7
  484. package/dist/utils/index.d.ts.map +1 -1
  485. package/dist/utils/index.js +4 -4
  486. package/dist/utils/index.js.map +1 -1
  487. package/dist/utils/time.d.ts.map +1 -1
  488. package/dist/utils/time.js +10 -10
  489. package/dist/utils/time.js.map +1 -1
  490. package/package.json +28 -5
  491. package/plugin/.claude-plugin/marketplace.json +17 -0
  492. package/plugin/.claude-plugin/plugin.json +5 -0
  493. package/plugin/plugins/kspec/skills/help/SKILL.md +42 -0
  494. package/plugin/plugins/kspec/skills/triage/SKILL.md +206 -0
  495. package/plugin/plugins/kspec/skills/triage/docs/automation.md +120 -0
  496. package/plugin/plugins/kspec/skills/triage/docs/inbox.md +144 -0
  497. package/plugin/plugins/kspec/skills/triage/docs/observations.md +85 -0
  498. package/templates/agents-sections/01-quick-start.md +22 -0
  499. package/templates/agents-sections/02-shadow-branch.md +34 -0
  500. package/templates/agents-sections/03-task-lifecycle.md +48 -0
  501. package/templates/agents-sections/04-pr-workflow.md +17 -0
  502. package/templates/agents-sections/05-commit-convention.md +27 -0
  503. package/templates/agents-sections/06-ralph-loop.md +45 -0
  504. package/templates/hooks/pre-commit +34 -0
  505. package/templates/skills/help/SKILL.md +37 -0
  506. package/templates/skills/manifest.yaml +15 -0
  507. package/templates/skills/triage/SKILL.md +199 -0
  508. package/templates/skills/triage/docs/automation.md +120 -0
  509. package/templates/skills/triage/docs/inbox.md +144 -0
  510. package/templates/skills/triage/docs/observations.md +85 -0
@@ -0,0 +1,468 @@
1
+ /**
2
+ * Triage API Routes
3
+ *
4
+ * REST endpoints for triage operations:
5
+ * - GET /api/triage - list records with filters and pagination
6
+ * - GET /api/triage/export - export records for agent handoff
7
+ * - POST /api/triage - record a triage decision
8
+ * - GET /api/triage/:ref - get single record
9
+ * - POST /api/triage/:ref/override - override a decision
10
+ * - POST /api/triage/:ref/act - execute a triage action
11
+ *
12
+ * AC Coverage:
13
+ * - @triage-daemon-api ac-1: GET list sorted by created_at desc
14
+ * - @triage-daemon-api ac-2: Status filter on GET list
15
+ * - @triage-daemon-api ac-3: POST creates record with snapshot
16
+ * - @triage-daemon-api ac-4: PUT override sets override fields
17
+ * - @triage-daemon-api ac-5: PUT act executes and transitions
18
+ * - @triage-daemon-api ac-6: GET export with format parameter
19
+ * - @triage-daemon-api ac-7: POST 404 for nonexistent inbox item
20
+ * - @triage-daemon-api ac-8: PUT act 409 for already acted
21
+ * - @triage-daemon-api ac-9: PUT act 422 for pending record
22
+ */
23
+
24
+ import { Elysia, t } from 'elysia';
25
+ import { ulid } from 'ulidx';
26
+ import {
27
+ initContext,
28
+ loadTriageRecords,
29
+ saveTriageRecord,
30
+ findTriageRecordByRef,
31
+ findTriageRecordByInboxRef,
32
+ loadInboxItems,
33
+ findInboxItemByRef,
34
+ loadAllTasks,
35
+ loadAllItems,
36
+ ReferenceIndex,
37
+ getAuthor,
38
+ createObservation,
39
+ saveObservation,
40
+ createTask,
41
+ saveTask,
42
+ deleteInboxItem,
43
+ type LoadedTriageRecord,
44
+ } from '../../parser/index.js';
45
+ import { commitIfShadow } from '../../parser/shadow.js';
46
+ import type { TriageAction } from '../../schema/index.js';
47
+ import { exportTriageRecords } from '../../export/triage.js';
48
+ import type { PubSubManager } from '../websocket/pubsub';
49
+
50
+ interface TriageRouteOptions {
51
+ pubsub: PubSubManager;
52
+ }
53
+
54
+ const VALID_ACTIONS = ['promote', 'delete', 'defer', 'spec-gap', 'duplicate'];
55
+
56
+ // formatTriageContext moved to shared export/triage.ts (exportTriageRecords)
57
+
58
+ /**
59
+ * Execute a triage action (reused from CLI logic)
60
+ * AC: @triage-daemon-api ac-5
61
+ */
62
+ async function executeTriageAction(
63
+ record: LoadedTriageRecord,
64
+ ctx: Awaited<ReturnType<typeof initContext>>,
65
+ ): Promise<{ resultRef?: string }> {
66
+ const action = record.action;
67
+ if (!action) return {};
68
+
69
+ switch (action) {
70
+ case 'promote': {
71
+ const task = createTask({
72
+ title: record.item_snapshot.split('\n')[0].slice(0, 100),
73
+ type: 'task',
74
+ priority: 3,
75
+ spec_ref: null,
76
+ tags: [],
77
+ description: record.item_snapshot,
78
+ });
79
+ await saveTask(ctx, task);
80
+ const tasks = await loadAllTasks(ctx);
81
+ const items = await loadAllItems(ctx);
82
+ const index = new ReferenceIndex(tasks, items);
83
+ const taskRef = `@${index.shortUlid(task._ulid)}`;
84
+ return { resultRef: taskRef };
85
+ }
86
+
87
+ case 'delete':
88
+ case 'duplicate': {
89
+ const inboxItems = await loadInboxItems(ctx);
90
+ const inboxItem = findInboxItemByRef(inboxItems, record.inbox_ref);
91
+ if (inboxItem) {
92
+ await deleteInboxItem(ctx, inboxItem._ulid);
93
+ }
94
+ return {};
95
+ }
96
+
97
+ case 'defer': {
98
+ return {};
99
+ }
100
+
101
+ case 'spec-gap': {
102
+ const content = `[spec-gap] ${record.item_snapshot}\n\nReasoning: ${record.reasoning || ''}`;
103
+ const observation = createObservation('question', content, {
104
+ configAuthor: ctx.config?.identity?.author,
105
+ });
106
+ await saveObservation(ctx, observation);
107
+ const obsRef = `@${observation._ulid.slice(0, 8)}`;
108
+ return { resultRef: obsRef };
109
+ }
110
+
111
+ default:
112
+ return {};
113
+ }
114
+ }
115
+
116
+ export function createTriageRoutes(options: TriageRouteOptions) {
117
+ const { pubsub } = options;
118
+
119
+ return new Elysia({ prefix: '/api/triage' })
120
+ // AC: @triage-daemon-api ac-1, ac-2 - List triage records with filters and pagination
121
+ // AC: @trait-api-endpoint ac-1, ac-4 - JSON response with pagination wrapper
122
+ .get(
123
+ '/',
124
+ async ({ query, projectContext }) => {
125
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
126
+ const ctx = await initContext(projectContext.path);
127
+ const records = await loadTriageRecords(ctx);
128
+
129
+ // Apply filters
130
+ let filtered = records;
131
+
132
+ // AC: @triage-daemon-api ac-2 - Status filter
133
+ if (query.status) {
134
+ const statusFilters = Array.isArray(query.status) ? query.status : [query.status];
135
+ filtered = filtered.filter((r) => statusFilters.includes(r.status));
136
+ }
137
+
138
+ // Action filter
139
+ if (query.action) {
140
+ const actionFilters = Array.isArray(query.action) ? query.action : [query.action];
141
+ filtered = filtered.filter((r) => r.action && actionFilters.includes(r.action));
142
+ }
143
+
144
+ // AC: @triage-daemon-api ac-1 - Sort by created_at descending (newest first)
145
+ filtered.sort(
146
+ (a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
147
+ );
148
+
149
+ // AC: @trait-api-endpoint ac-4 - Pagination with limit and offset
150
+ const total = filtered.length;
151
+ const offset = Number(query.offset) || 0;
152
+ const limit = Number(query.limit) || total;
153
+
154
+ const paginated = filtered.slice(offset, offset + limit);
155
+
156
+ return {
157
+ items: paginated,
158
+ total,
159
+ offset,
160
+ limit,
161
+ };
162
+ },
163
+ {
164
+ query: t.Object({
165
+ status: t.Optional(t.Union([t.String(), t.Array(t.String())])),
166
+ action: t.Optional(t.Union([t.String(), t.Array(t.String())])),
167
+ limit: t.Optional(t.String()),
168
+ offset: t.Optional(t.String()),
169
+ }),
170
+ }
171
+ )
172
+
173
+ // AC: @triage-daemon-api ac-6 - Export triage records
174
+ // NOTE: This route MUST be defined before /:ref to avoid "export" being parsed as a ref
175
+ .get(
176
+ '/export',
177
+ async ({ query, projectContext }) => {
178
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
179
+ const ctx = await initContext(projectContext.path);
180
+ let records = await loadTriageRecords(ctx);
181
+
182
+ // Optional status filter on export
183
+ if (query.status) {
184
+ const statusFilters = Array.isArray(query.status) ? query.status : [query.status];
185
+ records = records.filter((r) => statusFilters.includes(r.status));
186
+ }
187
+
188
+ const format = (query.format || 'json') as 'json' | 'context';
189
+
190
+ // AC: @triage-daemon-api ac-6 - Export via shared formatter
191
+ // AC: @triage-agent-export ac-1, ac-2, ac-3, ac-4
192
+ return exportTriageRecords(records, format);
193
+ },
194
+ {
195
+ query: t.Object({
196
+ format: t.Optional(t.String()),
197
+ status: t.Optional(t.Union([t.String(), t.Array(t.String())])),
198
+ }),
199
+ }
200
+ )
201
+
202
+ // AC: @triage-daemon-api ac-3 - Record a triage decision
203
+ // AC: @trait-api-endpoint ac-1, ac-3, ac-5 - JSON response, validation, shadow commit
204
+ .post(
205
+ '/',
206
+ async ({ body, error: errorResponse, projectContext }) => {
207
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
208
+ const ctx = await initContext(projectContext.path);
209
+
210
+ // AC: @trait-api-endpoint ac-3 - Validate action
211
+ if (!VALID_ACTIONS.includes(body.action)) {
212
+ return errorResponse(400, {
213
+ error: 'validation_error',
214
+ details: [
215
+ {
216
+ field: 'action',
217
+ message: `Action must be one of: ${VALID_ACTIONS.join(', ')}`,
218
+ },
219
+ ],
220
+ });
221
+ }
222
+
223
+ // AC: @triage-daemon-api ac-7 - Validate inbox item exists
224
+ const inboxItems = await loadInboxItems(ctx);
225
+ const inboxItem = findInboxItemByRef(inboxItems, body.inbox_ref);
226
+ if (!inboxItem) {
227
+ // AC: @trait-api-endpoint ac-2 - 404 with error guidance
228
+ return errorResponse(404, {
229
+ error: 'not_found',
230
+ message: `Inbox item reference "${body.inbox_ref}" not found`,
231
+ suggestion: 'Use kspec inbox list or GET /api/inbox to find valid inbox item references',
232
+ });
233
+ }
234
+
235
+ const author = body.decided_by || getAuthor(ctx.config?.identity?.author);
236
+ const evidenceRefs = body.evidence_refs
237
+ ? body.evidence_refs.map((r: string) => r.startsWith('@') ? r : `@${r}`)
238
+ : [];
239
+
240
+ // Check if a record already exists for this inbox item (upsert case)
241
+ const existingRecords = await loadTriageRecords(ctx);
242
+ const existing = findTriageRecordByInboxRef(existingRecords, inboxItem._ulid);
243
+
244
+ // AC: @triage-daemon-api ac-3 - Create record with item_snapshot
245
+ const record: LoadedTriageRecord = {
246
+ _ulid: existing?._ulid || ulid(),
247
+ inbox_ref: inboxItem._ulid,
248
+ item_snapshot: inboxItem.text,
249
+ status: 'triaged',
250
+ action: body.action as TriageAction,
251
+ reasoning: body.reasoning,
252
+ decided_by: author,
253
+ evidence_refs: evidenceRefs,
254
+ created_at: existing?.created_at || new Date().toISOString(),
255
+ };
256
+
257
+ await saveTriageRecord(ctx, record);
258
+
259
+ // Reload to get the persisted record (saveTriageRecord may upsert by inbox_ref)
260
+ const savedRecords = await loadTriageRecords(ctx);
261
+ const savedRecord = findTriageRecordByInboxRef(savedRecords, inboxItem._ulid) || record;
262
+
263
+ // AC: @trait-api-endpoint ac-5 - Shadow commit
264
+ await commitIfShadow(ctx.shadow, `triage: record ${savedRecord._ulid.slice(0, 8)} as ${savedRecord.action}`);
265
+
266
+ // AC: @triage-daemon-api ac-3 - Broadcast triage:updates via WebSocket
267
+ // AC: @trait-websocket-protocol ac-3 - Broadcast event
268
+ pubsub.broadcast('triage:updates', 'triage_record_created', {
269
+ ulid: savedRecord._ulid,
270
+ inbox_ref: savedRecord.inbox_ref,
271
+ action: savedRecord.action,
272
+ }, projectContext.path);
273
+
274
+ // AC: @trait-api-endpoint ac-1 - Return 2xx with JSON body
275
+ return {
276
+ success: true,
277
+ record: savedRecord,
278
+ };
279
+ },
280
+ {
281
+ body: t.Object({
282
+ inbox_ref: t.String(),
283
+ action: t.String(),
284
+ reasoning: t.String(),
285
+ decided_by: t.Optional(t.String()),
286
+ evidence_refs: t.Optional(t.Array(t.String())),
287
+ }),
288
+ }
289
+ )
290
+
291
+ // GET single triage record
292
+ .get(
293
+ '/:ref',
294
+ async ({ params, error: errorResponse, projectContext }) => {
295
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
296
+ const ctx = await initContext(projectContext.path);
297
+ const records = await loadTriageRecords(ctx);
298
+
299
+ // AC: @trait-api-endpoint ac-2 - Resolve ref
300
+ const record = findTriageRecordByRef(records, params.ref);
301
+ if (!record) {
302
+ return errorResponse(404, {
303
+ error: 'not_found',
304
+ message: `Triage record reference "${params.ref}" not found`,
305
+ suggestion: 'Use kspec triage list or GET /api/triage to find valid triage record references',
306
+ });
307
+ }
308
+
309
+ return record;
310
+ },
311
+ {
312
+ params: t.Object({
313
+ ref: t.String(),
314
+ }),
315
+ }
316
+ )
317
+
318
+ // AC: @triage-daemon-api ac-4 - Override a triage decision
319
+ // AC: @trait-api-endpoint ac-1, ac-5 - JSON response, shadow commit
320
+ .post(
321
+ '/:ref/override',
322
+ async ({ params, body, error: errorResponse, projectContext }) => {
323
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
324
+ const ctx = await initContext(projectContext.path);
325
+ const records = await loadTriageRecords(ctx);
326
+
327
+ // AC: @trait-api-endpoint ac-2 - Resolve ref
328
+ const record = findTriageRecordByRef(records, params.ref);
329
+ if (!record) {
330
+ return errorResponse(404, {
331
+ error: 'not_found',
332
+ message: `Triage record reference "${params.ref}" not found`,
333
+ suggestion: 'Use kspec triage list or GET /api/triage to find valid triage record references',
334
+ });
335
+ }
336
+
337
+ // AC: @trait-api-endpoint ac-3 - Validate action
338
+ if (!VALID_ACTIONS.includes(body.action)) {
339
+ return errorResponse(400, {
340
+ error: 'validation_error',
341
+ details: [
342
+ {
343
+ field: 'action',
344
+ message: `Action must be one of: ${VALID_ACTIONS.join(', ')}`,
345
+ },
346
+ ],
347
+ });
348
+ }
349
+
350
+ const overrideBy = body.override_by || getAuthor(ctx.config?.identity?.author);
351
+
352
+ // AC: @triage-daemon-api ac-4 - Set override fields and update action
353
+ record.override_reasoning = body.reasoning;
354
+ record.override_by = overrideBy;
355
+ record.override_at = new Date().toISOString();
356
+ record.action = body.action as TriageAction;
357
+ record.updated_at = new Date().toISOString();
358
+
359
+ // Re-triage if already acted on (allows re-acting with new action)
360
+ // Clear stale execution metadata to avoid leaking previous action results
361
+ if (record.status === 'acted_on') {
362
+ record.status = 'triaged';
363
+ record.acted_at = undefined;
364
+ record.result_ref = undefined;
365
+ }
366
+
367
+ await saveTriageRecord(ctx, record);
368
+
369
+ // AC: @trait-api-endpoint ac-5 - Shadow commit
370
+ await commitIfShadow(ctx.shadow, `triage: override ${record._ulid.slice(0, 8)}`);
371
+
372
+ // AC: @triage-daemon-api ac-4 - Broadcast triage:updates
373
+ pubsub.broadcast('triage:updates', 'triage_record_updated', {
374
+ ulid: record._ulid,
375
+ action: 'override',
376
+ new_action: record.action,
377
+ }, projectContext.path);
378
+
379
+ return {
380
+ success: true,
381
+ record,
382
+ };
383
+ },
384
+ {
385
+ params: t.Object({
386
+ ref: t.String(),
387
+ }),
388
+ body: t.Object({
389
+ action: t.String(),
390
+ reasoning: t.String(),
391
+ override_by: t.Optional(t.String()),
392
+ }),
393
+ }
394
+ )
395
+
396
+ // AC: @triage-daemon-api ac-5, ac-8, ac-9 - Execute a triage action
397
+ // AC: @trait-api-endpoint ac-1, ac-5 - JSON response, shadow commit
398
+ .post(
399
+ '/:ref/act',
400
+ async ({ params, error: errorResponse, projectContext }) => {
401
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
402
+ const ctx = await initContext(projectContext.path);
403
+ const records = await loadTriageRecords(ctx);
404
+
405
+ // AC: @trait-api-endpoint ac-2 - Resolve ref
406
+ const record = findTriageRecordByRef(records, params.ref);
407
+ if (!record) {
408
+ return errorResponse(404, {
409
+ error: 'not_found',
410
+ message: `Triage record reference "${params.ref}" not found`,
411
+ suggestion: 'Use kspec triage list or GET /api/triage to find valid triage record references',
412
+ });
413
+ }
414
+
415
+ // AC: @triage-daemon-api ac-8 - Already acted on → 409
416
+ if (record.status === 'acted_on') {
417
+ return errorResponse(409, {
418
+ error: 'invalid_transition',
419
+ message: 'Triage record has already been acted on',
420
+ current: record.status,
421
+ suggestion: 'Use override to change the decision before acting again',
422
+ });
423
+ }
424
+
425
+ // AC: @triage-daemon-api ac-9 - Pending (no decision) → 422
426
+ if (record.status === 'pending') {
427
+ return errorResponse(422, {
428
+ error: 'incomplete_record',
429
+ message: 'No decision has been recorded for this triage record. Complete triage first.',
430
+ suggestion: 'Use POST /api/triage to record a decision, or kspec triage record <inbox-ref> --action <action> --reasoning <text>',
431
+ });
432
+ }
433
+
434
+ // AC: @triage-daemon-api ac-5 - Execute the action
435
+ const result = await executeTriageAction(record, ctx);
436
+
437
+ // Transition to acted_on
438
+ record.status = 'acted_on';
439
+ record.acted_at = new Date().toISOString();
440
+ if (result.resultRef) {
441
+ record.result_ref = result.resultRef;
442
+ }
443
+ record.updated_at = new Date().toISOString();
444
+
445
+ await saveTriageRecord(ctx, record);
446
+
447
+ // AC: @trait-api-endpoint ac-5 - Shadow commit
448
+ await commitIfShadow(ctx.shadow, `triage: act ${record._ulid.slice(0, 8)}`);
449
+
450
+ // AC: @triage-daemon-api ac-5 - Broadcast triage:updates
451
+ pubsub.broadcast('triage:updates', 'triage_record_acted', {
452
+ ulid: record._ulid,
453
+ action: record.action,
454
+ result_ref: record.result_ref,
455
+ }, projectContext.path);
456
+
457
+ return {
458
+ success: true,
459
+ record,
460
+ };
461
+ },
462
+ {
463
+ params: t.Object({
464
+ ref: t.String(),
465
+ }),
466
+ }
467
+ );
468
+ }