@kynetic-ai/spec 0.10.0 → 0.12.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 (487) hide show
  1. package/README.md +55 -455
  2. package/dist/agent-runtime/bootstrap.d.ts +31 -0
  3. package/dist/agent-runtime/bootstrap.d.ts.map +1 -0
  4. package/dist/agent-runtime/bootstrap.js +302 -0
  5. package/dist/agent-runtime/bootstrap.js.map +1 -0
  6. package/dist/agent-runtime/dispatch.d.ts +150 -10
  7. package/dist/agent-runtime/dispatch.d.ts.map +1 -1
  8. package/dist/agent-runtime/dispatch.js +1248 -244
  9. package/dist/agent-runtime/dispatch.js.map +1 -1
  10. package/dist/agent-runtime/invocation.d.ts +28 -1
  11. package/dist/agent-runtime/invocation.d.ts.map +1 -1
  12. package/dist/agent-runtime/invocation.js +172 -60
  13. package/dist/agent-runtime/invocation.js.map +1 -1
  14. package/dist/agent-runtime/prompts.d.ts +9 -0
  15. package/dist/agent-runtime/prompts.d.ts.map +1 -1
  16. package/dist/agent-runtime/prompts.js +42 -7
  17. package/dist/agent-runtime/prompts.js.map +1 -1
  18. package/dist/agent-runtime/session-event-accumulator.d.ts +83 -0
  19. package/dist/agent-runtime/session-event-accumulator.d.ts.map +1 -0
  20. package/dist/agent-runtime/session-event-accumulator.js +203 -0
  21. package/dist/agent-runtime/session-event-accumulator.js.map +1 -0
  22. package/dist/agent-runtime/session-event-types.d.ts +67 -0
  23. package/dist/agent-runtime/session-event-types.d.ts.map +1 -0
  24. package/dist/agent-runtime/session-event-types.js +13 -0
  25. package/dist/agent-runtime/session-event-types.js.map +1 -0
  26. package/dist/agent-runtime/workspace.d.ts +244 -0
  27. package/dist/agent-runtime/workspace.d.ts.map +1 -0
  28. package/dist/agent-runtime/workspace.js +2025 -0
  29. package/dist/agent-runtime/workspace.js.map +1 -0
  30. package/dist/agents/adapters.d.ts.map +1 -1
  31. package/dist/agents/adapters.js +58 -13
  32. package/dist/agents/adapters.js.map +1 -1
  33. package/dist/agents/spawner.d.ts +8 -0
  34. package/dist/agents/spawner.d.ts.map +1 -1
  35. package/dist/agents/spawner.js +25 -3
  36. package/dist/agents/spawner.js.map +1 -1
  37. package/dist/cli/batch-exec.js +1 -1
  38. package/dist/cli/batch-exec.js.map +1 -1
  39. package/dist/cli/command-annotations.d.ts +15 -3
  40. package/dist/cli/command-annotations.d.ts.map +1 -1
  41. package/dist/cli/command-annotations.js +23 -3
  42. package/dist/cli/command-annotations.js.map +1 -1
  43. package/dist/cli/commands/agent.d.ts +2 -0
  44. package/dist/cli/commands/agent.d.ts.map +1 -1
  45. package/dist/cli/commands/agent.js +144 -27
  46. package/dist/cli/commands/agent.js.map +1 -1
  47. package/dist/cli/commands/agents.d.ts.map +1 -1
  48. package/dist/cli/commands/agents.js +5 -5
  49. package/dist/cli/commands/agents.js.map +1 -1
  50. package/dist/cli/commands/derive.d.ts.map +1 -1
  51. package/dist/cli/commands/derive.js +118 -3
  52. package/dist/cli/commands/derive.js.map +1 -1
  53. package/dist/cli/commands/guard.d.ts.map +1 -1
  54. package/dist/cli/commands/guard.js +8 -6
  55. package/dist/cli/commands/guard.js.map +1 -1
  56. package/dist/cli/commands/index.d.ts +1 -0
  57. package/dist/cli/commands/index.d.ts.map +1 -1
  58. package/dist/cli/commands/index.js +1 -0
  59. package/dist/cli/commands/index.js.map +1 -1
  60. package/dist/cli/commands/init.d.ts.map +1 -1
  61. package/dist/cli/commands/init.js +20 -0
  62. package/dist/cli/commands/init.js.map +1 -1
  63. package/dist/cli/commands/item.d.ts.map +1 -1
  64. package/dist/cli/commands/item.js +205 -47
  65. package/dist/cli/commands/item.js.map +1 -1
  66. package/dist/cli/commands/log.d.ts.map +1 -1
  67. package/dist/cli/commands/log.js +24 -10
  68. package/dist/cli/commands/log.js.map +1 -1
  69. package/dist/cli/commands/meta.d.ts.map +1 -1
  70. package/dist/cli/commands/meta.js +10 -1
  71. package/dist/cli/commands/meta.js.map +1 -1
  72. package/dist/cli/commands/plan-import.d.ts +3 -3
  73. package/dist/cli/commands/plan-import.d.ts.map +1 -1
  74. package/dist/cli/commands/plan-import.js +213 -528
  75. package/dist/cli/commands/plan-import.js.map +1 -1
  76. package/dist/cli/commands/plan.d.ts.map +1 -1
  77. package/dist/cli/commands/plan.js +533 -83
  78. package/dist/cli/commands/plan.js.map +1 -1
  79. package/dist/cli/commands/review.d.ts +14 -0
  80. package/dist/cli/commands/review.d.ts.map +1 -0
  81. package/dist/cli/commands/review.js +1142 -0
  82. package/dist/cli/commands/review.js.map +1 -0
  83. package/dist/cli/commands/serve.d.ts +1 -0
  84. package/dist/cli/commands/serve.d.ts.map +1 -1
  85. package/dist/cli/commands/serve.js +33 -10
  86. package/dist/cli/commands/serve.js.map +1 -1
  87. package/dist/cli/commands/session/checkpoint.d.ts +2 -4
  88. package/dist/cli/commands/session/checkpoint.d.ts.map +1 -1
  89. package/dist/cli/commands/session/checkpoint.js +6 -107
  90. package/dist/cli/commands/session/checkpoint.js.map +1 -1
  91. package/dist/cli/commands/session/commands.d.ts.map +1 -1
  92. package/dist/cli/commands/session/commands.js +33 -23
  93. package/dist/cli/commands/session/commands.js.map +1 -1
  94. package/dist/cli/commands/session/compact.js +4 -4
  95. package/dist/cli/commands/session/compact.js.map +1 -1
  96. package/dist/cli/commands/session/create.js +2 -2
  97. package/dist/cli/commands/session/create.js.map +1 -1
  98. package/dist/cli/commands/session/format.d.ts.map +1 -1
  99. package/dist/cli/commands/session/format.js +1 -6
  100. package/dist/cli/commands/session/format.js.map +1 -1
  101. package/dist/cli/commands/session/log.d.ts +32 -7
  102. package/dist/cli/commands/session/log.d.ts.map +1 -1
  103. package/dist/cli/commands/session/log.js +166 -60
  104. package/dist/cli/commands/session/log.js.map +1 -1
  105. package/dist/cli/commands/session/migrate.d.ts +9 -0
  106. package/dist/cli/commands/session/migrate.d.ts.map +1 -0
  107. package/dist/cli/commands/session/migrate.js +46 -0
  108. package/dist/cli/commands/session/migrate.js.map +1 -0
  109. package/dist/cli/commands/session/stale-close.d.ts.map +1 -1
  110. package/dist/cli/commands/session/stale-close.js +5 -8
  111. package/dist/cli/commands/session/stale-close.js.map +1 -1
  112. package/dist/cli/commands/session/types.d.ts +1 -1
  113. package/dist/cli/commands/session/types.d.ts.map +1 -1
  114. package/dist/cli/commands/setup.d.ts +2 -2
  115. package/dist/cli/commands/setup.d.ts.map +1 -1
  116. package/dist/cli/commands/setup.js +287 -257
  117. package/dist/cli/commands/setup.js.map +1 -1
  118. package/dist/cli/commands/shadow.d.ts.map +1 -1
  119. package/dist/cli/commands/shadow.js +147 -31
  120. package/dist/cli/commands/shadow.js.map +1 -1
  121. package/dist/cli/commands/skill-crud.d.ts +7 -0
  122. package/dist/cli/commands/skill-crud.d.ts.map +1 -1
  123. package/dist/cli/commands/skill-crud.js +41 -18
  124. package/dist/cli/commands/skill-crud.js.map +1 -1
  125. package/dist/cli/commands/skill-diff.d.ts.map +1 -1
  126. package/dist/cli/commands/skill-diff.js +29 -3
  127. package/dist/cli/commands/skill-diff.js.map +1 -1
  128. package/dist/cli/commands/skill-install.d.ts.map +1 -1
  129. package/dist/cli/commands/skill-install.js +5 -4
  130. package/dist/cli/commands/skill-install.js.map +1 -1
  131. package/dist/cli/commands/task.d.ts.map +1 -1
  132. package/dist/cli/commands/task.js +359 -49
  133. package/dist/cli/commands/task.js.map +1 -1
  134. package/dist/cli/commands/trait.d.ts.map +1 -1
  135. package/dist/cli/commands/trait.js +5 -27
  136. package/dist/cli/commands/trait.js.map +1 -1
  137. package/dist/cli/commands/validate.d.ts.map +1 -1
  138. package/dist/cli/commands/validate.js +113 -52
  139. package/dist/cli/commands/validate.js.map +1 -1
  140. package/dist/cli/index.d.ts.map +1 -1
  141. package/dist/cli/index.js +69 -2
  142. package/dist/cli/index.js.map +1 -1
  143. package/dist/cli/output.d.ts +26 -0
  144. package/dist/cli/output.d.ts.map +1 -1
  145. package/dist/cli/output.js +108 -1
  146. package/dist/cli/output.js.map +1 -1
  147. package/dist/cli/sync-mode.d.ts +44 -0
  148. package/dist/cli/sync-mode.d.ts.map +1 -0
  149. package/dist/cli/sync-mode.js +64 -0
  150. package/dist/cli/sync-mode.js.map +1 -0
  151. package/dist/daemon/middleware/project-context.ts +25 -7
  152. package/dist/daemon/project-context.ts +18 -0
  153. package/dist/daemon/routes/agent-dispatch.ts +107 -23
  154. package/dist/daemon/routes/aggregation.ts +184 -0
  155. package/dist/daemon/routes/inbox.ts +5 -0
  156. package/dist/daemon/routes/items.ts +167 -0
  157. package/dist/daemon/routes/meta.ts +141 -1
  158. package/dist/daemon/routes/plans.ts +147 -0
  159. package/dist/daemon/routes/projects.ts +28 -6
  160. package/dist/daemon/routes/ref-resolution.ts +119 -0
  161. package/dist/daemon/routes/refs.ts +42 -0
  162. package/dist/daemon/routes/session-related.ts +140 -0
  163. package/dist/daemon/routes/sessions.ts +581 -0
  164. package/dist/daemon/routes/tasks.ts +257 -2
  165. package/dist/daemon/routes/triage.ts +40 -1
  166. package/dist/daemon/routes/validation.ts +1 -1
  167. package/dist/daemon/server.ts +165 -50
  168. package/dist/daemon/session-sync.ts +11 -0
  169. package/dist/daemon/shadow-sync.ts +11 -0
  170. package/dist/daemon/watcher.ts +56 -5
  171. package/dist/daemon/websocket/project-resolution.ts +77 -0
  172. package/dist/export/json.d.ts.map +1 -1
  173. package/dist/export/json.js +104 -1
  174. package/dist/export/json.js.map +1 -1
  175. package/dist/export/types.d.ts +52 -1
  176. package/dist/export/types.d.ts.map +1 -1
  177. package/dist/index.d.ts +1 -0
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +1 -0
  180. package/dist/index.js.map +1 -1
  181. package/dist/parser/agent-detection.d.ts +1 -1
  182. package/dist/parser/agent-detection.d.ts.map +1 -1
  183. package/dist/parser/agent-detection.js +10 -0
  184. package/dist/parser/agent-detection.js.map +1 -1
  185. package/dist/parser/alignment.d.ts.map +1 -1
  186. package/dist/parser/alignment.js +4 -2
  187. package/dist/parser/alignment.js.map +1 -1
  188. package/dist/parser/config.d.ts +397 -2
  189. package/dist/parser/config.d.ts.map +1 -1
  190. package/dist/parser/config.js +125 -3
  191. package/dist/parser/config.js.map +1 -1
  192. package/dist/parser/dispatch-workspaces.d.ts +18 -0
  193. package/dist/parser/dispatch-workspaces.d.ts.map +1 -0
  194. package/dist/parser/dispatch-workspaces.js +209 -0
  195. package/dist/parser/dispatch-workspaces.js.map +1 -0
  196. package/dist/parser/doctor.d.ts.map +1 -1
  197. package/dist/parser/doctor.js +27 -8
  198. package/dist/parser/doctor.js.map +1 -1
  199. package/dist/parser/file-lock.d.ts.map +1 -1
  200. package/dist/parser/file-lock.js +9 -2
  201. package/dist/parser/file-lock.js.map +1 -1
  202. package/dist/parser/index.d.ts +6 -0
  203. package/dist/parser/index.d.ts.map +1 -1
  204. package/dist/parser/index.js +6 -0
  205. package/dist/parser/index.js.map +1 -1
  206. package/dist/parser/plans.d.ts.map +1 -1
  207. package/dist/parser/plans.js +1 -0
  208. package/dist/parser/plans.js.map +1 -1
  209. package/dist/parser/refs.d.ts +8 -1
  210. package/dist/parser/refs.d.ts.map +1 -1
  211. package/dist/parser/refs.js +27 -1
  212. package/dist/parser/refs.js.map +1 -1
  213. package/dist/parser/review-operations.d.ts +72 -0
  214. package/dist/parser/review-operations.d.ts.map +1 -0
  215. package/dist/parser/review-operations.js +185 -0
  216. package/dist/parser/review-operations.js.map +1 -0
  217. package/dist/parser/review-task-integration.d.ts +78 -0
  218. package/dist/parser/review-task-integration.d.ts.map +1 -0
  219. package/dist/parser/review-task-integration.js +173 -0
  220. package/dist/parser/review-task-integration.js.map +1 -0
  221. package/dist/parser/review-threads.d.ts +101 -0
  222. package/dist/parser/review-threads.d.ts.map +1 -0
  223. package/dist/parser/review-threads.js +222 -0
  224. package/dist/parser/review-threads.js.map +1 -0
  225. package/dist/parser/review-validation.d.ts +69 -0
  226. package/dist/parser/review-validation.d.ts.map +1 -0
  227. package/dist/parser/review-validation.js +207 -0
  228. package/dist/parser/review-validation.js.map +1 -0
  229. package/dist/parser/reviews.d.ts +58 -0
  230. package/dist/parser/reviews.d.ts.map +1 -0
  231. package/dist/parser/reviews.js +230 -0
  232. package/dist/parser/reviews.js.map +1 -0
  233. package/dist/parser/session-branch.d.ts +91 -0
  234. package/dist/parser/session-branch.d.ts.map +1 -0
  235. package/dist/parser/session-branch.js +565 -0
  236. package/dist/parser/session-branch.js.map +1 -0
  237. package/dist/parser/session-sync-scheduler.d.ts +53 -0
  238. package/dist/parser/session-sync-scheduler.d.ts.map +1 -0
  239. package/dist/parser/session-sync-scheduler.js +100 -0
  240. package/dist/parser/session-sync-scheduler.js.map +1 -0
  241. package/dist/parser/setup-status.d.ts +7 -1
  242. package/dist/parser/setup-status.d.ts.map +1 -1
  243. package/dist/parser/setup-status.js +104 -39
  244. package/dist/parser/setup-status.js.map +1 -1
  245. package/dist/parser/shadow-sync-scheduler.d.ts +71 -0
  246. package/dist/parser/shadow-sync-scheduler.d.ts.map +1 -0
  247. package/dist/parser/shadow-sync-scheduler.js +139 -0
  248. package/dist/parser/shadow-sync-scheduler.js.map +1 -0
  249. package/dist/parser/shadow.d.ts +121 -14
  250. package/dist/parser/shadow.d.ts.map +1 -1
  251. package/dist/parser/shadow.js +752 -27
  252. package/dist/parser/shadow.js.map +1 -1
  253. package/dist/parser/skill-render.d.ts +24 -0
  254. package/dist/parser/skill-render.d.ts.map +1 -1
  255. package/dist/parser/skill-render.js +98 -26
  256. package/dist/parser/skill-render.js.map +1 -1
  257. package/dist/parser/validate.d.ts +43 -3
  258. package/dist/parser/validate.d.ts.map +1 -1
  259. package/dist/parser/validate.js +204 -30
  260. package/dist/parser/validate.js.map +1 -1
  261. package/dist/parser/yaml.d.ts +47 -11
  262. package/dist/parser/yaml.d.ts.map +1 -1
  263. package/dist/parser/yaml.js +329 -149
  264. package/dist/parser/yaml.js.map +1 -1
  265. package/dist/review/checks.d.ts +97 -0
  266. package/dist/review/checks.d.ts.map +1 -0
  267. package/dist/review/checks.js +175 -0
  268. package/dist/review/checks.js.map +1 -0
  269. package/dist/review/index.d.ts +3 -0
  270. package/dist/review/index.d.ts.map +1 -0
  271. package/dist/review/index.js +3 -0
  272. package/dist/review/index.js.map +1 -0
  273. package/dist/review/subject-bindings.d.ts +83 -0
  274. package/dist/review/subject-bindings.d.ts.map +1 -0
  275. package/dist/review/subject-bindings.js +175 -0
  276. package/dist/review/subject-bindings.js.map +1 -0
  277. package/dist/schema/common.d.ts +26 -0
  278. package/dist/schema/common.d.ts.map +1 -1
  279. package/dist/schema/common.js +13 -0
  280. package/dist/schema/common.js.map +1 -1
  281. package/dist/schema/dispatch-workspace.d.ts +2643 -0
  282. package/dist/schema/dispatch-workspace.d.ts.map +1 -0
  283. package/dist/schema/dispatch-workspace.js +187 -0
  284. package/dist/schema/dispatch-workspace.js.map +1 -0
  285. package/dist/schema/inbox.d.ts +8 -8
  286. package/dist/schema/index.d.ts +2 -0
  287. package/dist/schema/index.d.ts.map +1 -1
  288. package/dist/schema/index.js +2 -0
  289. package/dist/schema/index.js.map +1 -1
  290. package/dist/schema/meta.d.ts +663 -116
  291. package/dist/schema/meta.d.ts.map +1 -1
  292. package/dist/schema/meta.js +28 -0
  293. package/dist/schema/meta.js.map +1 -1
  294. package/dist/schema/plan.d.ts +30 -19
  295. package/dist/schema/plan.d.ts.map +1 -1
  296. package/dist/schema/plan.js +3 -1
  297. package/dist/schema/plan.js.map +1 -1
  298. package/dist/schema/review-records.d.ts +2676 -0
  299. package/dist/schema/review-records.d.ts.map +1 -0
  300. package/dist/schema/review-records.js +232 -0
  301. package/dist/schema/review-records.js.map +1 -0
  302. package/dist/schema/spec.d.ts +32 -14
  303. package/dist/schema/spec.d.ts.map +1 -1
  304. package/dist/schema/spec.js +5 -0
  305. package/dist/schema/spec.js.map +1 -1
  306. package/dist/schema/task.d.ts +187 -29
  307. package/dist/schema/task.d.ts.map +1 -1
  308. package/dist/schema/task.js +12 -2
  309. package/dist/schema/task.js.map +1 -1
  310. package/dist/schema/triage.d.ts +22 -22
  311. package/dist/sessions/cache.d.ts +119 -0
  312. package/dist/sessions/cache.d.ts.map +1 -0
  313. package/dist/sessions/cache.js +284 -0
  314. package/dist/sessions/cache.js.map +1 -0
  315. package/dist/sessions/index.d.ts +1 -0
  316. package/dist/sessions/index.d.ts.map +1 -1
  317. package/dist/sessions/index.js +2 -0
  318. package/dist/sessions/index.js.map +1 -1
  319. package/dist/sessions/legacy.d.ts +77 -0
  320. package/dist/sessions/legacy.d.ts.map +1 -0
  321. package/dist/sessions/legacy.js +146 -0
  322. package/dist/sessions/legacy.js.map +1 -0
  323. package/dist/sessions/store.d.ts +115 -71
  324. package/dist/sessions/store.d.ts.map +1 -1
  325. package/dist/sessions/store.js +357 -182
  326. package/dist/sessions/store.js.map +1 -1
  327. package/dist/sessions/types.d.ts +44 -16
  328. package/dist/sessions/types.d.ts.map +1 -1
  329. package/dist/sessions/types.js +11 -2
  330. package/dist/sessions/types.js.map +1 -1
  331. package/dist/strings/errors.d.ts +32 -0
  332. package/dist/strings/errors.d.ts.map +1 -1
  333. package/dist/strings/errors.js +17 -0
  334. package/dist/strings/errors.js.map +1 -1
  335. package/dist/strings/labels.d.ts +1 -0
  336. package/dist/strings/labels.d.ts.map +1 -1
  337. package/dist/strings/labels.js +1 -0
  338. package/dist/strings/labels.js.map +1 -1
  339. package/dist/utils/activity.d.ts +101 -0
  340. package/dist/utils/activity.d.ts.map +1 -0
  341. package/dist/utils/activity.js +408 -0
  342. package/dist/utils/activity.js.map +1 -0
  343. package/dist/utils/git.d.ts +31 -0
  344. package/dist/utils/git.d.ts.map +1 -1
  345. package/dist/utils/git.js +87 -0
  346. package/dist/utils/git.js.map +1 -1
  347. package/dist/utils/index.d.ts +2 -0
  348. package/dist/utils/index.d.ts.map +1 -1
  349. package/dist/utils/index.js +1 -0
  350. package/dist/utils/index.js.map +1 -1
  351. package/dist/web-ui/_app/immutable/assets/0.tmlwn-Ih.css +1 -0
  352. package/dist/web-ui/_app/immutable/assets/9.BwwJybWx.css +1 -0
  353. package/dist/web-ui/_app/immutable/chunks/2KqE8gtn.js +1 -0
  354. package/dist/web-ui/_app/immutable/chunks/70-t_QvE.js +1 -0
  355. package/dist/web-ui/_app/immutable/chunks/AiWQj974.js +1 -0
  356. package/dist/web-ui/_app/immutable/chunks/B25nWFyA.js +5 -0
  357. package/dist/web-ui/_app/immutable/chunks/B2bcA_Q_.js +1 -0
  358. package/dist/web-ui/_app/immutable/chunks/B5e5HYyB.js +1 -0
  359. package/dist/web-ui/_app/immutable/chunks/B7-5z6eA.js +1 -0
  360. package/dist/web-ui/_app/immutable/chunks/B7bGmhK0.js +1 -0
  361. package/dist/web-ui/_app/immutable/chunks/B8tYZKAE.js +1 -0
  362. package/dist/web-ui/_app/immutable/chunks/BFGAyJjD.js +1 -0
  363. package/dist/web-ui/_app/immutable/chunks/BG0850zf.js +1 -0
  364. package/dist/web-ui/_app/immutable/chunks/BG8eSzAd.js +1 -0
  365. package/dist/web-ui/_app/immutable/chunks/BIMxXS8I.js +1 -0
  366. package/dist/web-ui/_app/immutable/chunks/BSzL1fpU.js +1 -0
  367. package/dist/web-ui/_app/immutable/chunks/BYtjHfeq.js +1 -0
  368. package/dist/web-ui/_app/immutable/chunks/{D1ArdqNb.js → Bp5pFYXL.js} +1 -1
  369. package/dist/web-ui/_app/immutable/chunks/BsJFsuAT.js +1 -0
  370. package/dist/web-ui/_app/immutable/chunks/BvpNHcD6.js +1 -0
  371. package/dist/web-ui/_app/immutable/chunks/BypqA25-.js +1 -0
  372. package/dist/web-ui/_app/immutable/chunks/C0w6WDm5.js +1 -0
  373. package/dist/web-ui/_app/immutable/chunks/C5_PAZ0y.js +1 -0
  374. package/dist/web-ui/_app/immutable/chunks/CDRO15Iv.js +1 -0
  375. package/dist/web-ui/_app/immutable/chunks/CF1CoqD5.js +1 -0
  376. package/dist/web-ui/_app/immutable/chunks/CS2sa4_m.js +1 -0
  377. package/dist/web-ui/_app/immutable/chunks/CWUQwB9H.js +1 -0
  378. package/dist/web-ui/_app/immutable/chunks/CY5FDdSU.js +1 -0
  379. package/dist/web-ui/_app/immutable/chunks/C_7MTDoj.js +1 -0
  380. package/dist/web-ui/_app/immutable/chunks/CaAJD3dl.js +1 -0
  381. package/dist/web-ui/_app/immutable/chunks/{i-XnOIX0.js → ChB5iyEL.js} +1 -1
  382. package/dist/web-ui/_app/immutable/chunks/ChQD-6N8.js +1 -0
  383. package/dist/web-ui/_app/immutable/chunks/{BCkp8Hs8.js → CqbsoCwA.js} +1 -1
  384. package/dist/web-ui/_app/immutable/chunks/DCeJW50p.js +1 -0
  385. package/dist/web-ui/_app/immutable/chunks/DJtZNgcs.js +1 -0
  386. package/dist/web-ui/_app/immutable/chunks/DKIeaprD.js +1 -0
  387. package/dist/web-ui/_app/immutable/chunks/DLd2uVIA.js +1 -0
  388. package/dist/web-ui/_app/immutable/chunks/DW_subyT.js +2 -0
  389. package/dist/web-ui/_app/immutable/chunks/DbU6lVn0.js +1 -0
  390. package/dist/web-ui/_app/immutable/chunks/Dc7ZCC5m.js +1 -0
  391. package/dist/web-ui/_app/immutable/chunks/Dd5umPsk.js +2 -0
  392. package/dist/web-ui/_app/immutable/chunks/Dg_zDpDS.js +1 -0
  393. package/dist/web-ui/_app/immutable/chunks/Dgqu8Yuc.js +1 -0
  394. package/dist/web-ui/_app/immutable/chunks/DmxsPZTB.js +1 -0
  395. package/dist/web-ui/_app/immutable/chunks/DphTaFUB.js +1 -0
  396. package/dist/web-ui/_app/immutable/chunks/DqK4iHp0.js +1 -0
  397. package/dist/web-ui/_app/immutable/chunks/DqT6OH_u.js +2 -0
  398. package/dist/web-ui/_app/immutable/chunks/Ds9I9wQb.js +1 -0
  399. package/dist/web-ui/_app/immutable/chunks/Du5ng3u4.js +1 -0
  400. package/dist/web-ui/_app/immutable/chunks/DxJw79Wi.js +1 -0
  401. package/dist/web-ui/_app/immutable/chunks/GFTX8GgV.js +1 -0
  402. package/dist/web-ui/_app/immutable/chunks/HNjs76Zz.js +1 -0
  403. package/dist/web-ui/_app/immutable/chunks/HVMjDi4_.js +1 -0
  404. package/dist/web-ui/_app/immutable/chunks/P0A_fJvS.js +1 -0
  405. package/dist/web-ui/_app/immutable/chunks/T3vGWjIL.js +1 -0
  406. package/dist/web-ui/_app/immutable/chunks/VTmrX9Qu.js +1 -0
  407. package/dist/web-ui/_app/immutable/chunks/Xvwhx_F1.js +1 -0
  408. package/dist/web-ui/_app/immutable/chunks/Yyz1XMQA.js +1 -0
  409. package/dist/web-ui/_app/immutable/chunks/dh5HeqUr.js +1 -0
  410. package/dist/web-ui/_app/immutable/chunks/fZMteyca.js +62 -0
  411. package/dist/web-ui/_app/immutable/chunks/{D28BF5MJ.js → gPrj-hqC.js} +1 -1
  412. package/dist/web-ui/_app/immutable/chunks/htcWMiYN.js +1 -0
  413. package/dist/web-ui/_app/immutable/chunks/oTsvd9y4.js +1 -0
  414. package/dist/web-ui/_app/immutable/chunks/qJfLUwU4.js +1 -0
  415. package/dist/web-ui/_app/immutable/chunks/xCtiO_JE.js +1 -0
  416. package/dist/web-ui/_app/immutable/chunks/y4GeEH6k.js +1 -0
  417. package/dist/web-ui/_app/immutable/entry/app.C4h_eOn6.js +2 -0
  418. package/dist/web-ui/_app/immutable/entry/start.CQFTf9ep.js +1 -0
  419. package/dist/web-ui/_app/immutable/nodes/0.Dh1xO970.js +1 -0
  420. package/dist/web-ui/_app/immutable/nodes/1.l75D3Opx.js +1 -0
  421. package/dist/web-ui/_app/immutable/nodes/10.DBidBPc-.js +1 -0
  422. package/dist/web-ui/_app/immutable/nodes/11.Ab0gUKWe.js +1 -0
  423. package/dist/web-ui/_app/immutable/nodes/12.CMsnoxfs.js +1 -0
  424. package/dist/web-ui/_app/immutable/nodes/13.D8YKuknB.js +1 -0
  425. package/dist/web-ui/_app/immutable/nodes/14.DZ0aan7y.js +1 -0
  426. package/dist/web-ui/_app/immutable/nodes/15.CUIKreDL.js +2 -0
  427. package/dist/web-ui/_app/immutable/nodes/16.BWc8--BO.js +1 -0
  428. package/dist/web-ui/_app/immutable/nodes/2.CDUonbuh.js +1 -0
  429. package/dist/web-ui/_app/immutable/nodes/3.Ctg3M00i.js +1 -0
  430. package/dist/web-ui/_app/immutable/nodes/4.Ci-JDwbA.js +2 -0
  431. package/dist/web-ui/_app/immutable/nodes/5.CTyEDAq0.js +1 -0
  432. package/dist/web-ui/_app/immutable/nodes/6.BTZZqsAb.js +1 -0
  433. package/dist/web-ui/_app/immutable/nodes/7.BI52g_Jo.js +137 -0
  434. package/dist/web-ui/_app/immutable/nodes/8.3hZPaB9x.js +1 -0
  435. package/dist/web-ui/_app/immutable/nodes/9.DS49kvwl.js +29 -0
  436. package/dist/web-ui/_app/version.json +1 -1
  437. package/dist/web-ui/favicon-192.png +0 -0
  438. package/dist/web-ui/favicon-32.png +0 -0
  439. package/dist/web-ui/favicon.ico +0 -0
  440. package/dist/web-ui/index.html +14 -11
  441. package/package.json +14 -7
  442. package/plugin/.claude-plugin/marketplace.json +1 -1
  443. package/plugin/.claude-plugin/plugin.json +1 -1
  444. package/plugin/plugins/kspec/skills/merge/SKILL.md +127 -0
  445. package/plugin/plugins/kspec/skills/plan/SKILL.md +55 -26
  446. package/plugin/plugins/kspec/skills/review/SKILL.md +350 -133
  447. package/plugin/plugins/kspec/skills/task-work/SKILL.md +96 -106
  448. package/templates/agents-sections/04-pr-workflow.md +15 -12
  449. package/templates/agents-sections/06-ralph-loop.md +15 -10
  450. package/templates/skills/manifest.yaml +25 -7
  451. package/templates/skills/merge/SKILL.md +120 -0
  452. package/templates/skills/plan/SKILL.md +55 -26
  453. package/templates/skills/review/SKILL.md +346 -130
  454. package/templates/skills/task-work/SKILL.md +93 -103
  455. package/dist/web-ui/_app/immutable/assets/0.BxCxvrZR.css +0 -1
  456. package/dist/web-ui/_app/immutable/chunks/B-CZR0q8.js +0 -1
  457. package/dist/web-ui/_app/immutable/chunks/B1IR5Su5.js +0 -1
  458. package/dist/web-ui/_app/immutable/chunks/B_Cvvtc4.js +0 -1
  459. package/dist/web-ui/_app/immutable/chunks/BtFaGGII.js +0 -1
  460. package/dist/web-ui/_app/immutable/chunks/Bu8JVsCH.js +0 -1
  461. package/dist/web-ui/_app/immutable/chunks/C87u-CNA.js +0 -1
  462. package/dist/web-ui/_app/immutable/chunks/CrFkBTYp.js +0 -1
  463. package/dist/web-ui/_app/immutable/chunks/D6RtLpzL.js +0 -1
  464. package/dist/web-ui/_app/immutable/chunks/D7FHSgx2.js +0 -1
  465. package/dist/web-ui/_app/immutable/chunks/DBXrsxZQ.js +0 -2
  466. package/dist/web-ui/_app/immutable/chunks/Da_hHMuA.js +0 -1
  467. package/dist/web-ui/_app/immutable/chunks/Do6LchSF.js +0 -1
  468. package/dist/web-ui/_app/immutable/chunks/DoNPtcAw.js +0 -1
  469. package/dist/web-ui/_app/immutable/chunks/DtUbXRZz.js +0 -1
  470. package/dist/web-ui/_app/immutable/chunks/DyFPRlLl.js +0 -1
  471. package/dist/web-ui/_app/immutable/chunks/DzAP8lRM.js +0 -1
  472. package/dist/web-ui/_app/immutable/chunks/DzVXElzN.js +0 -2
  473. package/dist/web-ui/_app/immutable/chunks/aoPBFken.js +0 -1
  474. package/dist/web-ui/_app/immutable/chunks/laxtrUO3.js +0 -1
  475. package/dist/web-ui/_app/immutable/chunks/q1nIWgqB.js +0 -1
  476. package/dist/web-ui/_app/immutable/chunks/sTLbk5Nm.js +0 -1
  477. package/dist/web-ui/_app/immutable/chunks/vwKgQu5P.js +0 -5
  478. package/dist/web-ui/_app/immutable/entry/app.BCwMcqnT.js +0 -2
  479. package/dist/web-ui/_app/immutable/entry/start.wKCQH-tt.js +0 -1
  480. package/dist/web-ui/_app/immutable/nodes/0.CjGVMG74.js +0 -1
  481. package/dist/web-ui/_app/immutable/nodes/1.B6_AIPan.js +0 -1
  482. package/dist/web-ui/_app/immutable/nodes/2.q4oCS7Ws.js +0 -1
  483. package/dist/web-ui/_app/immutable/nodes/3.rTKZf9o2.js +0 -1
  484. package/dist/web-ui/_app/immutable/nodes/4.DVIDRu1d.js +0 -1
  485. package/dist/web-ui/_app/immutable/nodes/5.8PtPXIOd.js +0 -1
  486. package/dist/web-ui/_app/immutable/nodes/6.ZZrTemy_.js +0 -1
  487. package/dist/web-ui/_app/immutable/nodes/7.IP-gxCxi.js +0 -1
@@ -1,6 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import { markMutating } from "../command-annotations.js";
3
- import { AlignmentIndex, addChildItem, buildIndexes, checkSlugUniqueness, createNote, createSpecItem, deleteSpecItem, findChildItems, findDescendantItems, findTraitImplementors, initContext, loadAllItems, loadMetaContext, loadAllTasks, patchSpecItems, ReferenceIndex, resolveMetaRef, shortestUniqueUlid, updateSpecItem, } from "../../parser/index.js";
3
+ import { AlignmentIndex, addProjectLevelTraitItem, addChildItem, buildIndexes, checkSlugUniqueness, createNote, createSpecItem, deleteSpecItem, findChildItems, findDescendantItems, findTraitImplementors, initContext, loadAllItems, loadMetaContext, loadAllTasks, patchSpecItems, ReferenceIndex, resolveMetaRef, shortestUniqueUlid, updateSpecItem, } from "../../parser/index.js";
4
4
  import { commitIfShadow } from "../../parser/shadow.js";
5
5
  import { SpecItemPatchSchema } from "../../schema/index.js";
6
6
  import { ImplementationStatusSchema, MaturitySchema, } from "../../schema/common.js";
@@ -8,8 +8,22 @@ import { errors } from "../../strings/errors.js";
8
8
  import { fieldLabels, sectionHeaders } from "../../strings/labels.js";
9
9
  import { formatMatchedFields, grepItem } from "../../utils/grep.js";
10
10
  import { EXIT_CODES } from "../exit-codes.js";
11
- import { error, isJsonMode, output, success, warn } from "../output.js";
11
+ import { error, isJsonMode, output, showChangeDiff, success, warn } from "../output.js";
12
12
  import { parseTagsArray } from "../parse-utils.js";
13
+ /**
14
+ * Serialize a LoadedSpecItem for JSON output.
15
+ * Strips internal fields (_sourceFile, _path), renames _ulid → ulid,
16
+ * and adds a ref field with @ prefix for the primary slug.
17
+ * AC: @trait-json-output ac-4
18
+ */
19
+ function serializeSpecItemForJson(item) {
20
+ const { _sourceFile, _path, _ulid, ...rest } = item;
21
+ return {
22
+ ulid: _ulid,
23
+ ref: item.slugs.length > 0 ? `@${item.slugs[0]}` : `@${_ulid}`,
24
+ ...rest,
25
+ };
26
+ }
13
27
  /**
14
28
  * Format a spec item for display
15
29
  */
@@ -290,12 +304,9 @@ export function registerItemCommands(program) {
290
304
  return;
291
305
  }
292
306
  output({
293
- items: specItems,
307
+ items: specItems.map(serializeSpecItemForJson),
294
308
  total: effectiveTotal,
295
309
  showing: specItems.length,
296
- grepPattern: options.grep,
297
- tree: options.tree,
298
- under: options.under,
299
310
  }, () => {
300
311
  if (options.tree) {
301
312
  // AC: @module-scoped-item-listing ac-under-with-tree
@@ -347,7 +358,7 @@ export function registerItemCommands(program) {
347
358
  }
348
359
  // Build JSON output with inherited traits
349
360
  const jsonOutput = {
350
- ...item,
361
+ ...serializeSpecItemForJson(item),
351
362
  inherited_traits: Array.from(traitsByTrait.values()).map(({ trait, acs }) => ({
352
363
  ref: `@${trait.slug}`,
353
364
  title: trait.title,
@@ -493,8 +504,9 @@ export function registerItemCommands(program) {
493
504
  });
494
505
  // kspec item add - create a new spec item under a parent
495
506
  markMutating(item.command("add"))
496
- .description("Create a new spec item under a parent")
497
- .requiredOption("--under <ref>", "Parent item reference (e.g., @core-primitives)")
507
+ .description("Create a new spec item under a parent or in project root")
508
+ .option("--under <ref>", "Parent item reference (e.g., @core-primitives)")
509
+ .option("--root", "Create at project root (trait items only)")
498
510
  .requiredOption("--title <title>", "Item title")
499
511
  .option("--type <type>", "Item type (feature, requirement, constraint, decision)", "feature")
500
512
  .option("--slug <slug>", "Human-friendly slug")
@@ -507,22 +519,47 @@ export function registerItemCommands(program) {
507
519
  Examples:
508
520
  $ kspec item add --under @parent --title "Feature name" --type feature
509
521
  $ kspec item add --under @parent --title "Multi-tag" --tag api public
510
- $ kspec item add --under @parent --title "API endpoint" --trait @trait-api-endpoint`)
522
+ $ kspec item add --under @parent --title "API endpoint" --trait @trait-api-endpoint
523
+ $ kspec item add --root --type trait --title "JSON Output" --slug trait-json-output`)
511
524
  .action(async (options) => {
512
525
  try {
513
526
  const ctx = await initContext();
514
527
  const { refIndex, items } = await buildIndexes(ctx);
515
- // Find the parent item
516
- const parentResult = refIndex.resolve(options.under);
517
- if (!parentResult.ok) {
518
- error(errors.reference.itemNotFound(options.under));
519
- process.exit(EXIT_CODES.ERROR);
528
+ const isRootAdd = Boolean(options.root);
529
+ const itemType = options.type;
530
+ const exitWithUsageGuidance = (message, suggestion, details) => {
531
+ error(message, { suggestion, ...details });
532
+ process.exit(EXIT_CODES.USAGE_ERROR);
533
+ };
534
+ if (options.under && isRootAdd) {
535
+ exitWithUsageGuidance(`Cannot use --under (${options.under}) and --root together`, "Use --root only for project-level traits in kynetic.yaml, or remove --root and keep --under for nested items.", {
536
+ field: "under",
537
+ value: options.under,
538
+ conflicting_field: "root",
539
+ });
520
540
  }
521
- const parent = parentResult.item;
522
- // Check it's not a task
523
- if ("status" in parent && typeof parent.status === "string") {
524
- error(errors.reference.parentIsTask(options.under));
525
- process.exit(EXIT_CODES.ERROR);
541
+ if (!options.under && !isRootAdd) {
542
+ exitWithUsageGuidance("item add requires either --under <ref> or --root", "Use --under @parent to create a nested item, or use --root --type trait to create a project-level trait in kynetic.yaml.");
543
+ }
544
+ if (isRootAdd && itemType !== "trait") {
545
+ exitWithUsageGuidance(`--root is only supported for --type trait (received: ${itemType || "undefined"})`, "Change --type to trait for project-level creation, or remove --root and create the item under a parent with --under.", {
546
+ field: "type",
547
+ value: itemType || null,
548
+ });
549
+ }
550
+ let parent = null;
551
+ if (options.under) {
552
+ const parentResult = refIndex.resolve(options.under);
553
+ if (!parentResult.ok) {
554
+ error(errors.reference.itemNotFound(options.under));
555
+ process.exit(EXIT_CODES.ERROR);
556
+ }
557
+ parent = parentResult.item;
558
+ // Check it's not a task
559
+ if ("status" in parent && typeof parent.status === "string") {
560
+ error(errors.reference.parentIsTask(options.under));
561
+ process.exit(EXIT_CODES.ERROR);
562
+ }
526
563
  }
527
564
  // Check slug uniqueness if provided
528
565
  if (options.slug) {
@@ -565,7 +602,7 @@ Examples:
565
602
  }
566
603
  const input = {
567
604
  title: options.title,
568
- type: options.type,
605
+ type: itemType,
569
606
  slugs: options.slug ? [options.slug] : [],
570
607
  priority: options.priority,
571
608
  tags: parseTagsArray(options.tag),
@@ -578,20 +615,32 @@ Examples:
578
615
  notes: [],
579
616
  };
580
617
  const newItem = createSpecItem(input);
581
- const result = await addChildItem(ctx, parent, newItem, options.as);
618
+ const addResult = isRootAdd
619
+ ? await addProjectLevelTraitItem(ctx, newItem)
620
+ : await addChildItem(ctx, parent, newItem, options.as);
621
+ const resultItem = {
622
+ ...addResult.item,
623
+ ...(isRootAdd
624
+ ? {
625
+ _sourceFile: ctx.manifestPath,
626
+ _path: addResult.path,
627
+ }
628
+ : {}),
629
+ };
582
630
  // Build index including the new item for accurate short ULID
583
- const index = new ReferenceIndex([], [...items, result.item]);
584
- const itemSlug = result.item.slugs?.[0] ||
585
- index.shortUlid(result.item._ulid);
631
+ const index = new ReferenceIndex([], [...items, resultItem]);
632
+ const itemSlug = resultItem.slugs?.[0] || index.shortUlid(resultItem._ulid);
633
+ const itemRef = `@${itemSlug}`;
586
634
  await commitIfShadow(ctx.shadow, "item-add", itemSlug);
587
- success(`Created item: ${index.shortUlid(result.item._ulid)} under @${parent.slugs[0] || index.shortUlid(parent._ulid)}`, {
588
- item: result.item,
589
- path: result.path,
635
+ success(isRootAdd
636
+ ? `Created item: ${itemRef} in project root traits`
637
+ : `Created item: ${index.shortUlid(resultItem._ulid)} under @${parent.slugs[0] || index.shortUlid(parent._ulid)}`, {
638
+ item: resultItem,
639
+ path: addResult.path,
590
640
  });
591
641
  // Derive hint
592
642
  if (!isJsonMode()) {
593
- const refSlug = result.item.slugs?.[0] ||
594
- index.shortUlid(result.item._ulid);
643
+ const refSlug = resultItem.slugs?.[0] || index.shortUlid(resultItem._ulid);
595
644
  console.log(chalk.gray(`\nDerive implementation task? kspec derive @${refSlug}`));
596
645
  }
597
646
  }
@@ -615,20 +664,27 @@ Examples:
615
664
  .option("--verified-by <agent-ref>", "Set verified_by (for retrospective specs)")
616
665
  .option("--verified-at <iso-timestamp>", "Set verified_at (defaults to now if --verified-by provided)")
617
666
  .option("--trait <trait...>", "Set traits (replaces existing)")
667
+ .option("--add-trait <trait...>", "Add traits (appends to existing)")
668
+ .option("--remove-trait <trait...>", "Remove specific traits")
669
+ .option("--clear-traits", "Clear all traits")
618
670
  .option("--relates-to <ref>", "Add a relates_to reference")
619
671
  .option("--implements <ref>", "Add an implements reference")
620
672
  .option("--depends-on <ref>", "Add a depends_on reference")
621
673
  .option("--clear-relates-to", "Clear all relates_to references")
622
674
  .option("--clear-implements", "Clear all implements references")
623
675
  .option("--clear-depends-on", "Clear all depends_on references")
676
+ .option("--no-cascade", "Skip child status cascade prompt (apply change only to target item)")
624
677
  .addHelpText("after", `
625
678
  Examples:
626
679
  $ kspec item set @item-ref --title "New title"
627
680
  $ kspec item set @item-ref --tag api internal security
628
- $ kspec item set @item-ref --trait reusable testable
681
+ $ kspec item set @item-ref --trait @reusable @testable # replaces all traits
682
+ $ kspec item set @item-ref --add-trait @json-output # appends trait
683
+ $ kspec item set @item-ref --remove-trait @old-trait # removes trait
629
684
  $ kspec item set @item-ref --relates-to @other-item
630
685
  $ kspec item set @item-ref --implements @feature-spec
631
- $ kspec item set @item-ref --depends-on @prereq-spec`)
686
+ $ kspec item set @item-ref --depends-on @prereq-spec
687
+ $ kspec item set @item-ref --status implemented --no-cascade`)
632
688
  .action(async (ref, options) => {
633
689
  try {
634
690
  const ctx = await initContext();
@@ -678,6 +734,41 @@ Examples:
678
734
  error("Cannot use --depends-on and --clear-depends-on together");
679
735
  process.exit(EXIT_CODES.USAGE_ERROR);
680
736
  }
737
+ // Mutual exclusivity for trait flags
738
+ const traitFlagCount = [options.trait, options.addTrait, options.removeTrait, options.clearTraits].filter(Boolean).length;
739
+ if (traitFlagCount > 1) {
740
+ error("Cannot combine --trait, --add-trait, --remove-trait, and --clear-traits. Use only one at a time.");
741
+ process.exit(EXIT_CODES.USAGE_ERROR);
742
+ }
743
+ // Helper to validate and canonicalize a list of trait refs
744
+ const validateTraitRefs = (traitRefs) => {
745
+ const validated = [];
746
+ const seenUlids = new Set();
747
+ let hasErrors = false;
748
+ for (const traitRef of traitRefs) {
749
+ const traitResult = refIndex.resolve(traitRef);
750
+ if (!traitResult.ok) {
751
+ error(`Trait not found: ${traitRef}`);
752
+ hasErrors = true;
753
+ continue;
754
+ }
755
+ const traitItem = traitResult.item;
756
+ if (traitItem.type !== "trait") {
757
+ error(`${traitRef} is not a trait (type: ${traitItem.type})`);
758
+ hasErrors = true;
759
+ continue;
760
+ }
761
+ if (seenUlids.has(traitItem._ulid))
762
+ continue;
763
+ seenUlids.add(traitItem._ulid);
764
+ const canonicalRef = `@${traitItem.slugs[0] || traitItem._ulid}`;
765
+ validated.push(canonicalRef);
766
+ }
767
+ if (hasErrors) {
768
+ process.exit(EXIT_CODES.NOT_FOUND);
769
+ }
770
+ return validated;
771
+ };
681
772
  // Helper to validate relationship refs (must exist and be a spec item, not a task)
682
773
  // Returns { ulid, canonicalRef } for deduplication and user-friendly storage
683
774
  const validateRelationshipRef = (refStr, flagName) => {
@@ -744,8 +835,46 @@ Examples:
744
835
  updates.priority = options.priority;
745
836
  if (options.tag)
746
837
  updates.tags = parseTagsArray(options.tag);
747
- if (options.trait)
748
- updates.traits = options.trait;
838
+ // Handle trait mutations (--trait replaces, --add-trait appends, --remove-trait removes, --clear-traits clears)
839
+ if (options.trait) {
840
+ updates.traits = validateTraitRefs(options.trait);
841
+ }
842
+ else if (options.addTrait) {
843
+ const validated = validateTraitRefs(options.addTrait);
844
+ const current = foundItem.traits || [];
845
+ // Resolve existing traits to ULIDs for deduplication
846
+ const existingUlids = new Set();
847
+ for (const ref of current) {
848
+ const result = refIndex.resolve(ref);
849
+ if (result.ok)
850
+ existingUlids.add(result.ulid);
851
+ }
852
+ const newTraits = validated.filter((ref) => {
853
+ const result = refIndex.resolve(ref);
854
+ return result.ok && !existingUlids.has(result.ulid);
855
+ });
856
+ if (newTraits.length > 0) {
857
+ updates.traits = [...current, ...newTraits];
858
+ }
859
+ }
860
+ else if (options.removeTrait) {
861
+ const validated = validateTraitRefs(options.removeTrait);
862
+ const current = foundItem.traits || [];
863
+ // Resolve removal targets to ULIDs
864
+ const removeUlids = new Set();
865
+ for (const ref of validated) {
866
+ const result = refIndex.resolve(ref);
867
+ if (result.ok)
868
+ removeUlids.add(result.ulid);
869
+ }
870
+ updates.traits = current.filter((ref) => {
871
+ const result = refIndex.resolve(ref);
872
+ return !result.ok || !removeUlids.has(result.ulid);
873
+ });
874
+ }
875
+ else if (options.clearTraits) {
876
+ updates.traits = [];
877
+ }
749
878
  if (options.description)
750
879
  updates.description = options.description;
751
880
  // AC: @implementation-states ac-reject-invalid
@@ -825,18 +954,35 @@ Examples:
825
954
  warn("No updates specified");
826
955
  return;
827
956
  }
957
+ // Build before→after changes for display
958
+ const changes = [];
959
+ for (const [key, value] of Object.entries(updates)) {
960
+ const before = foundItem[key];
961
+ // Only record if value actually changed
962
+ if (JSON.stringify(before) !== JSON.stringify(value)) {
963
+ changes.push({ field: key, before, after: value });
964
+ }
965
+ }
966
+ if (changes.length === 0) {
967
+ warn("No changes: values are already set to the specified values");
968
+ return;
969
+ }
828
970
  const updated = await updateSpecItem(ctx, foundItem, updates);
829
971
  const itemSlug = foundItem.slugs[0] || refIndex.shortUlid(foundItem._ulid);
830
972
  // Handle cascade for implementation status updates
831
973
  const updatedItems = [updated];
832
- if (options.status) {
974
+ if (options.status && options.cascade !== false) {
833
975
  const cascadeResult = await handleStatusCascade(ctx, updated, options.status, items, refIndex);
834
976
  updatedItems.push(...cascadeResult);
835
977
  }
836
978
  await commitIfShadow(ctx.shadow, "item-set", itemSlug);
837
- success(`Updated item: ${refIndex.shortUlid(updated._ulid)}`, {
979
+ const changedFields = changes.map((c) => c.field).join(", ");
980
+ success(`Updated item: ${refIndex.shortUlid(updated._ulid)} (${changedFields})`, {
838
981
  item: updated,
982
+ changes,
839
983
  });
984
+ // Show before→after diff in text mode
985
+ showChangeDiff(changes);
840
986
  // Derive hint
841
987
  if (!isJsonMode()) {
842
988
  const refSlug = updated.slugs?.[0] || refIndex.shortUlid(updated._ulid);
@@ -1403,9 +1549,10 @@ Examples:
1403
1549
  error(errors.conflict.acIdAlreadyExists(options.id));
1404
1550
  process.exit(EXIT_CODES.CONFLICT);
1405
1551
  }
1406
- // Build updated AC
1552
+ // Build updated AC and track before→after changes
1407
1553
  const updatedAc = [...existingAc];
1408
- const updatedFields = [];
1554
+ const originalAc = { ...updatedAc[acIndex] };
1555
+ const changes = [];
1409
1556
  updatedAc[acIndex] = {
1410
1557
  ...updatedAc[acIndex],
1411
1558
  ...(options.id && { id: options.id }),
@@ -1413,19 +1560,30 @@ Examples:
1413
1560
  ...(options.when && { when: options.when }),
1414
1561
  ...(options.then && { then: options.then }),
1415
1562
  };
1416
- if (options.id)
1417
- updatedFields.push("id");
1418
- if (options.given)
1419
- updatedFields.push("given");
1420
- if (options.when)
1421
- updatedFields.push("when");
1422
- if (options.then)
1423
- updatedFields.push("then");
1563
+ if (options.id && options.id !== originalAc.id) {
1564
+ changes.push({ field: "id", before: originalAc.id, after: options.id });
1565
+ }
1566
+ if (options.given && options.given !== originalAc.given) {
1567
+ changes.push({ field: "given", before: originalAc.given, after: options.given });
1568
+ }
1569
+ if (options.when && options.when !== originalAc.when) {
1570
+ changes.push({ field: "when", before: originalAc.when, after: options.when });
1571
+ }
1572
+ if (options.then && options.then !== originalAc.then) {
1573
+ changes.push({ field: "then", before: originalAc.then, after: options.then });
1574
+ }
1575
+ if (changes.length === 0) {
1576
+ warn("No changes: values are already set to the specified values");
1577
+ return;
1578
+ }
1424
1579
  // Update item
1425
1580
  await updateSpecItem(ctx, item, { acceptance_criteria: updatedAc });
1426
1581
  const itemSlug = item.slugs[0] || refIndex.shortUlid(item._ulid);
1427
1582
  await commitIfShadow(ctx.shadow, "item-ac-set", itemSlug);
1428
- success(`Updated acceptance criterion: ${acId} on @${itemSlug} (${updatedFields.join(", ")})`, { ac: updatedAc[acIndex] });
1583
+ const changedFields = changes.map((c) => c.field).join(", ");
1584
+ success(`Updated acceptance criterion: ${acId} on @${itemSlug} (${changedFields})`, { ac: updatedAc[acIndex], changes });
1585
+ // Show before→after diff in text mode
1586
+ showChangeDiff(changes);
1429
1587
  }
1430
1588
  catch (err) {
1431
1589
  error(errors.failures.updateAc, err);