@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,162 @@
1
+ /**
2
+ * Projects API Routes
3
+ *
4
+ * REST endpoints for project management operations:
5
+ * - GET /api/projects - list all registered projects
6
+ * - POST /api/projects - manually register a project
7
+ * - DELETE /api/projects/:encodedPath - unregister a project
8
+ *
9
+ * All endpoints return JSON responses.
10
+ *
11
+ * AC Coverage:
12
+ * - ac-28: GET /api/projects returns list with paths, registration time, watcher status
13
+ * - ac-29: POST /api/projects with {path: string} body for manual registration
14
+ * - ac-30: DELETE /api/projects/:encodedPath unregisters and stops watcher
15
+ */
16
+
17
+ import { Elysia, t } from 'elysia';
18
+ import { isAbsolute } from 'path';
19
+ import type { ProjectContextManager } from '../project-context';
20
+
21
+ interface ProjectsRouteOptions {
22
+ projectManager: ProjectContextManager;
23
+ }
24
+
25
+ export function createProjectsRoutes(options: ProjectsRouteOptions) {
26
+ const { projectManager } = options;
27
+
28
+ return new Elysia({ prefix: '/api/projects' })
29
+ // AC: @multi-directory-daemon ac-28 - List registered projects
30
+ .get('/', async () => {
31
+ const projects = projectManager.listProjects();
32
+
33
+ // AC: @multi-directory-daemon ac-28 - Include paths, registration time, watcher status
34
+ return {
35
+ projects: projects.map(project => ({
36
+ path: project.path,
37
+ registeredAt: project.registeredAt.toISOString(),
38
+ watcherStatus: project.watcherActive ? 'active' : 'stopped',
39
+ })),
40
+ total: projects.length,
41
+ };
42
+ })
43
+
44
+ // AC: @multi-directory-daemon ac-29 - Manual project registration
45
+ .post(
46
+ '/',
47
+ async ({ body, error: errorResponse }) => {
48
+ // AC: @multi-directory-daemon ac-29 - Accept {path: string} body
49
+ // Validate path is provided
50
+ if (!body.path || typeof body.path !== 'string' || body.path.trim().length === 0) {
51
+ return errorResponse(400, {
52
+ error: 'validation_error',
53
+ details: [
54
+ {
55
+ field: 'path',
56
+ message: 'Path is required and must be a non-empty string',
57
+ },
58
+ ],
59
+ });
60
+ }
61
+
62
+ // AC: @multi-directory-daemon ac-6 - Path must be absolute
63
+ if (!isAbsolute(body.path)) {
64
+ return errorResponse(400, {
65
+ error: 'Path must be absolute',
66
+ });
67
+ }
68
+
69
+ // AC: @multi-directory-daemon ac-7 - Reject parent traversal (..)
70
+ if (body.path.includes('..')) {
71
+ return errorResponse(400, {
72
+ error: 'Path must not contain parent traversal',
73
+ });
74
+ }
75
+
76
+ try {
77
+ // AC: @multi-directory-daemon ac-29 - Use ProjectContextManager.registerProject()
78
+ const context = projectManager.registerProject(body.path);
79
+
80
+ // Start watcher for the registered project
81
+ try {
82
+ await projectManager.startWatcher(body.path);
83
+ } catch (error: unknown) {
84
+ // AC: @multi-directory-daemon ac-19 - Handle OS limits
85
+ const message = error instanceof Error ? error.message : String(error);
86
+ if (message.includes('resource limit')) {
87
+ return errorResponse(503, {
88
+ error: 'Unable to watch project - resource limit reached',
89
+ });
90
+ }
91
+ throw error;
92
+ }
93
+
94
+ return {
95
+ success: true,
96
+ project: {
97
+ path: context.path,
98
+ registeredAt: context.registeredAt.toISOString(),
99
+ watcherStatus: context.watcherActive ? 'active' : 'stopped',
100
+ },
101
+ };
102
+ } catch (error: unknown) {
103
+ const message = error instanceof Error ? error.message : String(error);
104
+ const code = error instanceof Error && 'code' in error ? (error as NodeJS.ErrnoException).code : undefined;
105
+
106
+ // AC: @multi-directory-daemon ac-5 - Invalid project (no .kspec/)
107
+ if (message.includes('.kspec/ not found')) {
108
+ return errorResponse(400, {
109
+ error: `Invalid kspec project - .kspec/ not found at ${body.path}`,
110
+ });
111
+ }
112
+
113
+ // AC: @multi-directory-daemon ac-8b - Permission denied
114
+ if (code === 'EACCES' || code === 'EPERM') {
115
+ return errorResponse(403, {
116
+ error: `Permission denied - cannot read ${body.path}`,
117
+ });
118
+ }
119
+
120
+ // Generic error
121
+ return errorResponse(500, {
122
+ error: message || 'Failed to register project',
123
+ });
124
+ }
125
+ },
126
+ {
127
+ body: t.Object({
128
+ path: t.String(),
129
+ }),
130
+ }
131
+ )
132
+
133
+ // AC: @multi-directory-daemon ac-30 - Unregister project
134
+ .delete('/:encodedPath', async ({ params, error: errorResponse }) => {
135
+ // AC: @multi-directory-daemon ac-30 - Decode path from URL parameter
136
+ const projectPath = decodeURIComponent(params.encodedPath);
137
+
138
+ // Validate project exists
139
+ if (!projectManager.hasProject(projectPath)) {
140
+ return errorResponse(404, {
141
+ error: `Project not registered: ${projectPath}`,
142
+ });
143
+ }
144
+
145
+ try {
146
+ // AC: @multi-directory-daemon ac-30 - Stop file watcher
147
+ await projectManager.stopWatcher(projectPath);
148
+
149
+ // AC: @multi-directory-daemon ac-30 - Unregister project
150
+ projectManager.unregisterProject(projectPath);
151
+
152
+ return {
153
+ success: true,
154
+ message: `Project unregistered: ${projectPath}`,
155
+ };
156
+ } catch (error: unknown) {
157
+ return errorResponse(500, {
158
+ error: error instanceof Error ? error.message : 'Failed to unregister project',
159
+ });
160
+ }
161
+ });
162
+ }
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Task API Routes
3
+ *
4
+ * REST endpoints for task operations:
5
+ * - GET /api/tasks - list with filters and pagination
6
+ * - GET /api/tasks/:ref - get single task
7
+ * - POST /api/tasks/:ref/start - start task
8
+ * - POST /api/tasks/:ref/note - add note
9
+ *
10
+ * AC Coverage:
11
+ * - ac-2: GET /api/tasks returns array with status, priority, spec_ref, notes count
12
+ * - ac-3: Status filter with multi-value support
13
+ * - ac-4: Pagination with {items, total, offset, limit} wrapper
14
+ * - ac-5: GET /api/tasks/:ref resolves via ReferenceIndex
15
+ * - ac-6: POST /api/tasks/:ref/start transitions state
16
+ * - ac-7: POST /api/tasks/:ref/note appends note
17
+ */
18
+
19
+ import { Elysia, t } from 'elysia';
20
+ import {
21
+ initContext,
22
+ loadAllTasks,
23
+ loadAllItems,
24
+ ReferenceIndex,
25
+ createNote,
26
+ saveTask,
27
+ getAuthor,
28
+ syncSpecImplementationStatus,
29
+ type LoadedTask,
30
+ } from '../../parser/index.js';
31
+ import { commitIfShadow } from '../../parser/shadow.js';
32
+ import type { PubSubManager } from '../websocket/pubsub';
33
+
34
+ interface TasksRouteOptions {
35
+ pubsub: PubSubManager;
36
+ }
37
+
38
+ export function createTasksRoutes(options: TasksRouteOptions) {
39
+ const { pubsub } = options;
40
+
41
+ return new Elysia({ prefix: '/api/tasks' })
42
+ // AC: @api-contract ac-2, ac-3, ac-4 - List tasks with filters and pagination
43
+ .get(
44
+ '/',
45
+ async ({ query, projectContext }) => {
46
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
47
+ const ctx = await initContext(projectContext.path);
48
+ const tasks = await loadAllTasks(ctx);
49
+ const specItems = await loadAllItems(ctx);
50
+ const index = new ReferenceIndex(tasks, specItems);
51
+
52
+ // Apply filters
53
+ let filtered = tasks;
54
+
55
+ // AC: @api-contract ac-3 - Multi-value status filter
56
+ if (query.status) {
57
+ const statusFilters = Array.isArray(query.status) ? query.status : [query.status];
58
+ filtered = filtered.filter((task) => statusFilters.includes(task.status));
59
+ }
60
+
61
+ // Type filter (optional, not in ACs but useful)
62
+ if (query.type) {
63
+ const typeFilters = Array.isArray(query.type) ? query.type : [query.type];
64
+ filtered = filtered.filter((task) => task.type && typeFilters.includes(task.type));
65
+ }
66
+
67
+ // Tag filter (optional, not in ACs but useful)
68
+ if (query.tag) {
69
+ const tagFilters = Array.isArray(query.tag) ? query.tag : [query.tag];
70
+ filtered = filtered.filter((task) =>
71
+ task.tags?.some((t) => tagFilters.includes(t))
72
+ );
73
+ }
74
+
75
+ // AC: @api-contract ac-4 - Pagination
76
+ const total = filtered.length;
77
+ const offset = Number(query.offset) || 0;
78
+ const limit = Number(query.limit) || total;
79
+
80
+ const paginated = filtered.slice(offset, offset + limit);
81
+
82
+ // AC: @api-contract ac-2 - Return with status, priority, spec_ref, notes count
83
+ // AC: @web-dashboard ac-1 - Include depends_on for blocked task computation
84
+ const items = paginated.map((task) => ({
85
+ _ulid: task._ulid,
86
+ slugs: task.slugs,
87
+ title: task.title,
88
+ status: task.status,
89
+ priority: task.priority,
90
+ spec_ref: task.spec_ref,
91
+ meta_ref: task.meta_ref,
92
+ tags: task.tags,
93
+ depends_on: task.depends_on || [],
94
+ notes_count: task.notes?.length || 0,
95
+ todos_count: task.todos?.length || 0,
96
+ started_at: task.started_at,
97
+ completed_at: task.completed_at,
98
+ created_at: task.created_at,
99
+ }));
100
+
101
+ // AC: @api-contract ac-4, @trait-api-endpoint ac-4 - Return pagination wrapper
102
+ return {
103
+ items,
104
+ total,
105
+ offset,
106
+ limit,
107
+ };
108
+ },
109
+ {
110
+ query: t.Object({
111
+ status: t.Optional(t.Union([t.String(), t.Array(t.String())])),
112
+ type: t.Optional(t.Union([t.String(), t.Array(t.String())])),
113
+ tag: t.Optional(t.Union([t.String(), t.Array(t.String())])),
114
+ limit: t.Optional(t.String()),
115
+ offset: t.Optional(t.String()),
116
+ }),
117
+ }
118
+ )
119
+
120
+ // AC: @api-contract ac-5 - Get single task by ref
121
+ .get(
122
+ '/:ref',
123
+ async ({ params, error: errorResponse, projectContext }) => {
124
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
125
+ const ctx = await initContext(projectContext.path);
126
+ const tasks = await loadAllTasks(ctx);
127
+ const items = await loadAllItems(ctx);
128
+ const index = new ReferenceIndex(tasks, items);
129
+
130
+ // AC: @api-contract ac-5, @trait-api-endpoint ac-2 - Resolve ref via ReferenceIndex
131
+ const result = index.resolve(params.ref);
132
+
133
+ if (!result.ok) {
134
+ // AC: @trait-api-endpoint ac-2 - Return 404 with error details
135
+ return errorResponse(404, {
136
+ error: 'not_found',
137
+ message: `Task reference "${params.ref}" not found`,
138
+ suggestion: 'Use kspec task list or kspec search to find valid task references',
139
+ });
140
+ }
141
+
142
+ // Find the task
143
+ const task = tasks.find((t) => t._ulid === result.ulid);
144
+ if (!task) {
145
+ return errorResponse(404, {
146
+ error: 'not_found',
147
+ message: `Reference "${params.ref}" is not a task`,
148
+ suggestion: 'This reference might point to a spec item instead',
149
+ });
150
+ }
151
+
152
+ // AC: @api-contract ac-5 - Return full task with notes, todos, dependencies
153
+ return {
154
+ _ulid: task._ulid,
155
+ slugs: task.slugs,
156
+ title: task.title,
157
+ status: task.status,
158
+ priority: task.priority,
159
+ spec_ref: task.spec_ref,
160
+ meta_ref: task.meta_ref,
161
+ tags: task.tags,
162
+ description: task.description,
163
+ depends_on: task.depends_on,
164
+ notes: task.notes,
165
+ todos: task.todos,
166
+ started_at: task.started_at,
167
+ completed_at: task.completed_at,
168
+ cancelled_at: task.cancelled_at,
169
+ closed_reason: task.closed_reason,
170
+ automation: task.automation,
171
+ created_at: task.created_at,
172
+ };
173
+ },
174
+ {
175
+ params: t.Object({
176
+ ref: t.String(),
177
+ }),
178
+ }
179
+ )
180
+
181
+ // AC: @api-contract ac-6 - Start task
182
+ .post(
183
+ '/:ref/start',
184
+ async ({ params, error: errorResponse, projectContext }) => {
185
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
186
+ const ctx = await initContext(projectContext.path);
187
+ const tasks = await loadAllTasks(ctx);
188
+ const items = await loadAllItems(ctx);
189
+ const index = new ReferenceIndex(tasks, items);
190
+
191
+ // Resolve ref
192
+ const result = index.resolve(params.ref);
193
+ if (!result.ok) {
194
+ return errorResponse(404, {
195
+ error: 'not_found',
196
+ message: `Task reference "${params.ref}" not found`,
197
+ suggestion: 'Use kspec task list to find valid task references',
198
+ });
199
+ }
200
+
201
+ const task = tasks.find((t) => t._ulid === result.ulid);
202
+ if (!task) {
203
+ return errorResponse(404, {
204
+ error: 'not_found',
205
+ message: `Reference "${params.ref}" is not a task`,
206
+ });
207
+ }
208
+
209
+ // AC: @api-contract ac-6 - Transition to in_progress
210
+ if (task.status === 'in_progress') {
211
+ return errorResponse(409, {
212
+ error: 'invalid_transition',
213
+ message: 'Task is already in_progress',
214
+ current: task.status,
215
+ valid_transitions: ['blocked', 'pending_review', 'completed', 'cancelled'],
216
+ });
217
+ }
218
+
219
+ // Update task status
220
+ const updatedTask: LoadedTask = {
221
+ ...task,
222
+ status: 'in_progress',
223
+ started_at: task.started_at || new Date().toISOString(),
224
+ };
225
+
226
+ // Save and commit
227
+ await saveTask(ctx, updatedTask);
228
+ await syncSpecImplementationStatus(ctx, updatedTask, tasks, items, index);
229
+ await commitIfShadow(ctx.shadow, `task: start ${params.ref}`);
230
+
231
+ // AC: @api-contract ac-6, @trait-api-endpoint ac-5 - WebSocket broadcast
232
+ // AC: @multi-directory-daemon ac-18 - Broadcast scoped to request project
233
+ pubsub.broadcast('tasks:updates', 'task_updated', {
234
+ ref: params.ref,
235
+ ulid: task._ulid,
236
+ action: 'start',
237
+ status: 'in_progress',
238
+ }, projectContext.path);
239
+
240
+ // AC: @api-contract ac-6 - Return updated task
241
+ return updatedTask;
242
+ },
243
+ {
244
+ params: t.Object({
245
+ ref: t.String(),
246
+ }),
247
+ }
248
+ )
249
+
250
+ // AC: @api-contract ac-7 - Add note to task
251
+ .post(
252
+ '/:ref/note',
253
+ async ({ params, body, error: errorResponse, projectContext }) => {
254
+ // AC: @multi-directory-daemon ac-1, ac-24 - Use project context from middleware
255
+ const ctx = await initContext(projectContext.path);
256
+ const tasks = await loadAllTasks(ctx);
257
+ const items = await loadAllItems(ctx);
258
+ const index = new ReferenceIndex(tasks, items);
259
+
260
+ // Resolve ref
261
+ const result = index.resolve(params.ref);
262
+ if (!result.ok) {
263
+ return errorResponse(404, {
264
+ error: 'not_found',
265
+ message: `Task reference "${params.ref}" not found`,
266
+ });
267
+ }
268
+
269
+ const task = tasks.find((t) => t._ulid === result.ulid);
270
+ if (!task) {
271
+ return errorResponse(404, {
272
+ error: 'not_found',
273
+ message: `Reference "${params.ref}" is not a task`,
274
+ });
275
+ }
276
+
277
+ // AC: @trait-api-endpoint ac-3 - Validate body
278
+ if (!body.content || typeof body.content !== 'string') {
279
+ return errorResponse(400, {
280
+ error: 'validation_error',
281
+ details: [
282
+ {
283
+ field: 'content',
284
+ message: 'Content is required and must be a string',
285
+ },
286
+ ],
287
+ });
288
+ }
289
+
290
+ // AC: @api-contract ac-7 - Append note
291
+ const author = getAuthor(ctx.config?.identity?.author);
292
+ const note = createNote(body.content, author);
293
+
294
+ const updatedTask: LoadedTask = {
295
+ ...task,
296
+ notes: [...(task.notes || []), note],
297
+ };
298
+
299
+ // AC: @api-contract ac-7, @trait-api-endpoint ac-5 - Shadow commit
300
+ await saveTask(ctx, updatedTask);
301
+ await commitIfShadow(ctx.shadow, `task: add note to ${params.ref}`);
302
+
303
+ // AC: @api-contract ac-7 - WebSocket broadcast
304
+ // AC: @multi-directory-daemon ac-18 - Broadcast scoped to request project
305
+ pubsub.broadcast('tasks:updates', 'task_updated', {
306
+ ref: params.ref,
307
+ ulid: task._ulid,
308
+ action: 'note_added',
309
+ note_ulid: note._ulid,
310
+ }, projectContext.path);
311
+
312
+ return {
313
+ success: true,
314
+ note,
315
+ task: updatedTask,
316
+ };
317
+ },
318
+ {
319
+ params: t.Object({
320
+ ref: t.String(),
321
+ }),
322
+ body: t.Object({
323
+ content: t.String(),
324
+ }),
325
+ }
326
+ );
327
+ }