@kynetic-ai/spec 0.11.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 (501) 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 +119 -10
  7. package/dist/agent-runtime/dispatch.d.ts.map +1 -1
  8. package/dist/agent-runtime/dispatch.js +1154 -219
  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 +171 -59
  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/plan-import.d.ts +3 -3
  70. package/dist/cli/commands/plan-import.d.ts.map +1 -1
  71. package/dist/cli/commands/plan-import.js +213 -528
  72. package/dist/cli/commands/plan-import.js.map +1 -1
  73. package/dist/cli/commands/plan.d.ts.map +1 -1
  74. package/dist/cli/commands/plan.js +533 -83
  75. package/dist/cli/commands/plan.js.map +1 -1
  76. package/dist/cli/commands/review.d.ts +14 -0
  77. package/dist/cli/commands/review.d.ts.map +1 -0
  78. package/dist/cli/commands/review.js +1142 -0
  79. package/dist/cli/commands/review.js.map +1 -0
  80. package/dist/cli/commands/serve.d.ts +1 -0
  81. package/dist/cli/commands/serve.d.ts.map +1 -1
  82. package/dist/cli/commands/serve.js +33 -10
  83. package/dist/cli/commands/serve.js.map +1 -1
  84. package/dist/cli/commands/session/checkpoint.d.ts +2 -4
  85. package/dist/cli/commands/session/checkpoint.d.ts.map +1 -1
  86. package/dist/cli/commands/session/checkpoint.js +6 -107
  87. package/dist/cli/commands/session/checkpoint.js.map +1 -1
  88. package/dist/cli/commands/session/commands.d.ts.map +1 -1
  89. package/dist/cli/commands/session/commands.js +33 -23
  90. package/dist/cli/commands/session/commands.js.map +1 -1
  91. package/dist/cli/commands/session/compact.js +4 -4
  92. package/dist/cli/commands/session/compact.js.map +1 -1
  93. package/dist/cli/commands/session/create.js +2 -2
  94. package/dist/cli/commands/session/create.js.map +1 -1
  95. package/dist/cli/commands/session/format.d.ts.map +1 -1
  96. package/dist/cli/commands/session/format.js +1 -6
  97. package/dist/cli/commands/session/format.js.map +1 -1
  98. package/dist/cli/commands/session/log.d.ts +32 -7
  99. package/dist/cli/commands/session/log.d.ts.map +1 -1
  100. package/dist/cli/commands/session/log.js +166 -60
  101. package/dist/cli/commands/session/log.js.map +1 -1
  102. package/dist/cli/commands/session/migrate.d.ts +9 -0
  103. package/dist/cli/commands/session/migrate.d.ts.map +1 -0
  104. package/dist/cli/commands/session/migrate.js +46 -0
  105. package/dist/cli/commands/session/migrate.js.map +1 -0
  106. package/dist/cli/commands/session/stale-close.d.ts.map +1 -1
  107. package/dist/cli/commands/session/stale-close.js +5 -8
  108. package/dist/cli/commands/session/stale-close.js.map +1 -1
  109. package/dist/cli/commands/session/types.d.ts +1 -1
  110. package/dist/cli/commands/session/types.d.ts.map +1 -1
  111. package/dist/cli/commands/setup.d.ts +2 -2
  112. package/dist/cli/commands/setup.d.ts.map +1 -1
  113. package/dist/cli/commands/setup.js +287 -257
  114. package/dist/cli/commands/setup.js.map +1 -1
  115. package/dist/cli/commands/shadow.d.ts.map +1 -1
  116. package/dist/cli/commands/shadow.js +147 -31
  117. package/dist/cli/commands/shadow.js.map +1 -1
  118. package/dist/cli/commands/skill-crud.d.ts +7 -0
  119. package/dist/cli/commands/skill-crud.d.ts.map +1 -1
  120. package/dist/cli/commands/skill-crud.js +41 -18
  121. package/dist/cli/commands/skill-crud.js.map +1 -1
  122. package/dist/cli/commands/skill-diff.d.ts.map +1 -1
  123. package/dist/cli/commands/skill-diff.js +29 -3
  124. package/dist/cli/commands/skill-diff.js.map +1 -1
  125. package/dist/cli/commands/skill-install.d.ts.map +1 -1
  126. package/dist/cli/commands/skill-install.js +5 -4
  127. package/dist/cli/commands/skill-install.js.map +1 -1
  128. package/dist/cli/commands/task.d.ts.map +1 -1
  129. package/dist/cli/commands/task.js +359 -49
  130. package/dist/cli/commands/task.js.map +1 -1
  131. package/dist/cli/commands/trait.d.ts.map +1 -1
  132. package/dist/cli/commands/trait.js +5 -27
  133. package/dist/cli/commands/trait.js.map +1 -1
  134. package/dist/cli/commands/validate.d.ts.map +1 -1
  135. package/dist/cli/commands/validate.js +113 -52
  136. package/dist/cli/commands/validate.js.map +1 -1
  137. package/dist/cli/index.d.ts.map +1 -1
  138. package/dist/cli/index.js +69 -2
  139. package/dist/cli/index.js.map +1 -1
  140. package/dist/cli/output.d.ts +26 -0
  141. package/dist/cli/output.d.ts.map +1 -1
  142. package/dist/cli/output.js +108 -1
  143. package/dist/cli/output.js.map +1 -1
  144. package/dist/cli/sync-mode.d.ts +44 -0
  145. package/dist/cli/sync-mode.d.ts.map +1 -0
  146. package/dist/cli/sync-mode.js +64 -0
  147. package/dist/cli/sync-mode.js.map +1 -0
  148. package/dist/daemon/middleware/project-context.ts +25 -7
  149. package/dist/daemon/project-context.ts +18 -0
  150. package/dist/daemon/routes/agent-dispatch.ts +99 -22
  151. package/dist/daemon/routes/aggregation.ts +184 -0
  152. package/dist/daemon/routes/inbox.ts +5 -0
  153. package/dist/daemon/routes/items.ts +145 -0
  154. package/dist/daemon/routes/meta.ts +1 -1
  155. package/dist/daemon/routes/projects.ts +28 -6
  156. package/dist/daemon/routes/ref-resolution.ts +119 -0
  157. package/dist/daemon/routes/refs.ts +42 -0
  158. package/dist/daemon/routes/session-related.ts +140 -0
  159. package/dist/daemon/routes/sessions.ts +420 -19
  160. package/dist/daemon/routes/tasks.ts +62 -5
  161. package/dist/daemon/routes/triage.ts +40 -1
  162. package/dist/daemon/server.ts +143 -49
  163. package/dist/daemon/session-sync.ts +11 -0
  164. package/dist/daemon/shadow-sync.ts +11 -0
  165. package/dist/daemon/watcher.ts +56 -5
  166. package/dist/daemon/websocket/project-resolution.ts +77 -0
  167. package/dist/export/json.d.ts.map +1 -1
  168. package/dist/export/json.js +104 -1
  169. package/dist/export/json.js.map +1 -1
  170. package/dist/export/types.d.ts +52 -1
  171. package/dist/export/types.d.ts.map +1 -1
  172. package/dist/index.d.ts +1 -0
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.js +1 -0
  175. package/dist/index.js.map +1 -1
  176. package/dist/parser/agent-detection.d.ts +1 -1
  177. package/dist/parser/agent-detection.d.ts.map +1 -1
  178. package/dist/parser/agent-detection.js +10 -0
  179. package/dist/parser/agent-detection.js.map +1 -1
  180. package/dist/parser/config.d.ts +397 -2
  181. package/dist/parser/config.d.ts.map +1 -1
  182. package/dist/parser/config.js +125 -3
  183. package/dist/parser/config.js.map +1 -1
  184. package/dist/parser/dispatch-workspaces.d.ts +18 -0
  185. package/dist/parser/dispatch-workspaces.d.ts.map +1 -0
  186. package/dist/parser/dispatch-workspaces.js +209 -0
  187. package/dist/parser/dispatch-workspaces.js.map +1 -0
  188. package/dist/parser/doctor.d.ts.map +1 -1
  189. package/dist/parser/doctor.js +27 -8
  190. package/dist/parser/doctor.js.map +1 -1
  191. package/dist/parser/file-lock.d.ts.map +1 -1
  192. package/dist/parser/file-lock.js +9 -2
  193. package/dist/parser/file-lock.js.map +1 -1
  194. package/dist/parser/index.d.ts +6 -0
  195. package/dist/parser/index.d.ts.map +1 -1
  196. package/dist/parser/index.js +6 -0
  197. package/dist/parser/index.js.map +1 -1
  198. package/dist/parser/plans.d.ts.map +1 -1
  199. package/dist/parser/plans.js +1 -0
  200. package/dist/parser/plans.js.map +1 -1
  201. package/dist/parser/refs.d.ts +8 -1
  202. package/dist/parser/refs.d.ts.map +1 -1
  203. package/dist/parser/refs.js +27 -1
  204. package/dist/parser/refs.js.map +1 -1
  205. package/dist/parser/review-operations.d.ts +72 -0
  206. package/dist/parser/review-operations.d.ts.map +1 -0
  207. package/dist/parser/review-operations.js +185 -0
  208. package/dist/parser/review-operations.js.map +1 -0
  209. package/dist/parser/review-task-integration.d.ts +78 -0
  210. package/dist/parser/review-task-integration.d.ts.map +1 -0
  211. package/dist/parser/review-task-integration.js +173 -0
  212. package/dist/parser/review-task-integration.js.map +1 -0
  213. package/dist/parser/review-threads.d.ts +101 -0
  214. package/dist/parser/review-threads.d.ts.map +1 -0
  215. package/dist/parser/review-threads.js +222 -0
  216. package/dist/parser/review-threads.js.map +1 -0
  217. package/dist/parser/review-validation.d.ts +69 -0
  218. package/dist/parser/review-validation.d.ts.map +1 -0
  219. package/dist/parser/review-validation.js +207 -0
  220. package/dist/parser/review-validation.js.map +1 -0
  221. package/dist/parser/reviews.d.ts +58 -0
  222. package/dist/parser/reviews.d.ts.map +1 -0
  223. package/dist/parser/reviews.js +230 -0
  224. package/dist/parser/reviews.js.map +1 -0
  225. package/dist/parser/session-branch.d.ts +91 -0
  226. package/dist/parser/session-branch.d.ts.map +1 -0
  227. package/dist/parser/session-branch.js +565 -0
  228. package/dist/parser/session-branch.js.map +1 -0
  229. package/dist/parser/session-sync-scheduler.d.ts +53 -0
  230. package/dist/parser/session-sync-scheduler.d.ts.map +1 -0
  231. package/dist/parser/session-sync-scheduler.js +100 -0
  232. package/dist/parser/session-sync-scheduler.js.map +1 -0
  233. package/dist/parser/setup-status.d.ts +7 -1
  234. package/dist/parser/setup-status.d.ts.map +1 -1
  235. package/dist/parser/setup-status.js +104 -39
  236. package/dist/parser/setup-status.js.map +1 -1
  237. package/dist/parser/shadow-sync-scheduler.d.ts +71 -0
  238. package/dist/parser/shadow-sync-scheduler.d.ts.map +1 -0
  239. package/dist/parser/shadow-sync-scheduler.js +139 -0
  240. package/dist/parser/shadow-sync-scheduler.js.map +1 -0
  241. package/dist/parser/shadow.d.ts +121 -14
  242. package/dist/parser/shadow.d.ts.map +1 -1
  243. package/dist/parser/shadow.js +752 -27
  244. package/dist/parser/shadow.js.map +1 -1
  245. package/dist/parser/skill-render.d.ts +24 -0
  246. package/dist/parser/skill-render.d.ts.map +1 -1
  247. package/dist/parser/skill-render.js +98 -26
  248. package/dist/parser/skill-render.js.map +1 -1
  249. package/dist/parser/validate.d.ts +43 -3
  250. package/dist/parser/validate.d.ts.map +1 -1
  251. package/dist/parser/validate.js +204 -30
  252. package/dist/parser/validate.js.map +1 -1
  253. package/dist/parser/yaml.d.ts +47 -11
  254. package/dist/parser/yaml.d.ts.map +1 -1
  255. package/dist/parser/yaml.js +329 -149
  256. package/dist/parser/yaml.js.map +1 -1
  257. package/dist/review/checks.d.ts +97 -0
  258. package/dist/review/checks.d.ts.map +1 -0
  259. package/dist/review/checks.js +175 -0
  260. package/dist/review/checks.js.map +1 -0
  261. package/dist/review/index.d.ts +3 -0
  262. package/dist/review/index.d.ts.map +1 -0
  263. package/dist/review/index.js +3 -0
  264. package/dist/review/index.js.map +1 -0
  265. package/dist/review/subject-bindings.d.ts +83 -0
  266. package/dist/review/subject-bindings.d.ts.map +1 -0
  267. package/dist/review/subject-bindings.js +175 -0
  268. package/dist/review/subject-bindings.js.map +1 -0
  269. package/dist/schema/common.d.ts +26 -0
  270. package/dist/schema/common.d.ts.map +1 -1
  271. package/dist/schema/common.js +13 -0
  272. package/dist/schema/common.js.map +1 -1
  273. package/dist/schema/dispatch-workspace.d.ts +2643 -0
  274. package/dist/schema/dispatch-workspace.d.ts.map +1 -0
  275. package/dist/schema/dispatch-workspace.js +187 -0
  276. package/dist/schema/dispatch-workspace.js.map +1 -0
  277. package/dist/schema/inbox.d.ts +8 -8
  278. package/dist/schema/index.d.ts +2 -0
  279. package/dist/schema/index.d.ts.map +1 -1
  280. package/dist/schema/index.js +2 -0
  281. package/dist/schema/index.js.map +1 -1
  282. package/dist/schema/meta.d.ts +648 -116
  283. package/dist/schema/meta.d.ts.map +1 -1
  284. package/dist/schema/meta.js +27 -0
  285. package/dist/schema/meta.js.map +1 -1
  286. package/dist/schema/plan.d.ts +30 -19
  287. package/dist/schema/plan.d.ts.map +1 -1
  288. package/dist/schema/plan.js +3 -1
  289. package/dist/schema/plan.js.map +1 -1
  290. package/dist/schema/review-records.d.ts +2676 -0
  291. package/dist/schema/review-records.d.ts.map +1 -0
  292. package/dist/schema/review-records.js +232 -0
  293. package/dist/schema/review-records.js.map +1 -0
  294. package/dist/schema/spec.d.ts +32 -14
  295. package/dist/schema/spec.d.ts.map +1 -1
  296. package/dist/schema/spec.js +5 -0
  297. package/dist/schema/spec.js.map +1 -1
  298. package/dist/schema/task.d.ts +187 -29
  299. package/dist/schema/task.d.ts.map +1 -1
  300. package/dist/schema/task.js +12 -2
  301. package/dist/schema/task.js.map +1 -1
  302. package/dist/schema/triage.d.ts +22 -22
  303. package/dist/sessions/cache.d.ts +119 -0
  304. package/dist/sessions/cache.d.ts.map +1 -0
  305. package/dist/sessions/cache.js +284 -0
  306. package/dist/sessions/cache.js.map +1 -0
  307. package/dist/sessions/index.d.ts +1 -0
  308. package/dist/sessions/index.d.ts.map +1 -1
  309. package/dist/sessions/index.js +2 -0
  310. package/dist/sessions/index.js.map +1 -1
  311. package/dist/sessions/legacy.d.ts +77 -0
  312. package/dist/sessions/legacy.d.ts.map +1 -0
  313. package/dist/sessions/legacy.js +146 -0
  314. package/dist/sessions/legacy.js.map +1 -0
  315. package/dist/sessions/store.d.ts +103 -73
  316. package/dist/sessions/store.d.ts.map +1 -1
  317. package/dist/sessions/store.js +335 -186
  318. package/dist/sessions/store.js.map +1 -1
  319. package/dist/sessions/types.d.ts +44 -16
  320. package/dist/sessions/types.d.ts.map +1 -1
  321. package/dist/sessions/types.js +11 -2
  322. package/dist/sessions/types.js.map +1 -1
  323. package/dist/strings/errors.d.ts +32 -0
  324. package/dist/strings/errors.d.ts.map +1 -1
  325. package/dist/strings/errors.js +17 -0
  326. package/dist/strings/errors.js.map +1 -1
  327. package/dist/strings/labels.d.ts +1 -0
  328. package/dist/strings/labels.d.ts.map +1 -1
  329. package/dist/strings/labels.js +1 -0
  330. package/dist/strings/labels.js.map +1 -1
  331. package/dist/utils/activity.d.ts +101 -0
  332. package/dist/utils/activity.d.ts.map +1 -0
  333. package/dist/utils/activity.js +408 -0
  334. package/dist/utils/activity.js.map +1 -0
  335. package/dist/utils/git.d.ts +31 -0
  336. package/dist/utils/git.d.ts.map +1 -1
  337. package/dist/utils/git.js +87 -0
  338. package/dist/utils/git.js.map +1 -1
  339. package/dist/utils/index.d.ts +2 -0
  340. package/dist/utils/index.d.ts.map +1 -1
  341. package/dist/utils/index.js +1 -0
  342. package/dist/utils/index.js.map +1 -1
  343. package/dist/web-ui/_app/immutable/assets/0.tmlwn-Ih.css +1 -0
  344. package/dist/web-ui/_app/immutable/assets/9.BwwJybWx.css +1 -0
  345. package/dist/web-ui/_app/immutable/chunks/2KqE8gtn.js +1 -0
  346. package/dist/web-ui/_app/immutable/chunks/70-t_QvE.js +1 -0
  347. package/dist/web-ui/_app/immutable/chunks/AiWQj974.js +1 -0
  348. package/dist/web-ui/_app/immutable/chunks/{CPPfDSei.js → B25nWFyA.js} +4 -4
  349. package/dist/web-ui/_app/immutable/chunks/{DBYE9jOd.js → B2bcA_Q_.js} +1 -1
  350. package/dist/web-ui/_app/immutable/chunks/B5e5HYyB.js +1 -0
  351. package/dist/web-ui/_app/immutable/chunks/B7-5z6eA.js +1 -0
  352. package/dist/web-ui/_app/immutable/chunks/B7bGmhK0.js +1 -0
  353. package/dist/web-ui/_app/immutable/chunks/{DzO4hlg9.js → B8tYZKAE.js} +1 -1
  354. package/dist/web-ui/_app/immutable/chunks/{B5LJFxqa.js → BFGAyJjD.js} +1 -1
  355. package/dist/web-ui/_app/immutable/chunks/BG0850zf.js +1 -0
  356. package/dist/web-ui/_app/immutable/chunks/{DAMmvwn4.js → BG8eSzAd.js} +1 -1
  357. package/dist/web-ui/_app/immutable/chunks/BIMxXS8I.js +1 -0
  358. package/dist/web-ui/_app/immutable/chunks/BSzL1fpU.js +1 -0
  359. package/dist/web-ui/_app/immutable/chunks/BYtjHfeq.js +1 -0
  360. package/dist/web-ui/_app/immutable/chunks/{DxCk-KHc.js → Bp5pFYXL.js} +1 -1
  361. package/dist/web-ui/_app/immutable/chunks/{B8a0xDxR.js → BsJFsuAT.js} +1 -1
  362. package/dist/web-ui/_app/immutable/chunks/BvpNHcD6.js +1 -0
  363. package/dist/web-ui/_app/immutable/chunks/BypqA25-.js +1 -0
  364. package/dist/web-ui/_app/immutable/chunks/{BVA9Exy-.js → C0w6WDm5.js} +1 -1
  365. package/dist/web-ui/_app/immutable/chunks/C5_PAZ0y.js +1 -0
  366. package/dist/web-ui/_app/immutable/chunks/CDRO15Iv.js +1 -0
  367. package/dist/web-ui/_app/immutable/chunks/CF1CoqD5.js +1 -0
  368. package/dist/web-ui/_app/immutable/chunks/CS2sa4_m.js +1 -0
  369. package/dist/web-ui/_app/immutable/chunks/{BJ0JX3ea.js → CWUQwB9H.js} +1 -1
  370. package/dist/web-ui/_app/immutable/chunks/CY5FDdSU.js +1 -0
  371. package/dist/web-ui/_app/immutable/chunks/C_7MTDoj.js +1 -0
  372. package/dist/web-ui/_app/immutable/chunks/{D3vxvonu.js → CaAJD3dl.js} +1 -1
  373. package/dist/web-ui/_app/immutable/chunks/{BP352uRn.js → ChB5iyEL.js} +1 -1
  374. package/dist/web-ui/_app/immutable/chunks/{pE6cYWlS.js → ChQD-6N8.js} +1 -1
  375. package/dist/web-ui/_app/immutable/chunks/{Eo4gF7ih.js → CqbsoCwA.js} +1 -1
  376. package/dist/web-ui/_app/immutable/chunks/DCeJW50p.js +1 -0
  377. package/dist/web-ui/_app/immutable/chunks/{Cncwi6fQ.js → DJtZNgcs.js} +1 -1
  378. package/dist/web-ui/_app/immutable/chunks/DKIeaprD.js +1 -0
  379. package/dist/web-ui/_app/immutable/chunks/DLd2uVIA.js +1 -0
  380. package/dist/web-ui/_app/immutable/chunks/{DjcCz-PU.js → DW_subyT.js} +2 -2
  381. package/dist/web-ui/_app/immutable/chunks/DbU6lVn0.js +1 -0
  382. package/dist/web-ui/_app/immutable/chunks/Dc7ZCC5m.js +1 -0
  383. package/dist/web-ui/_app/immutable/chunks/Dd5umPsk.js +2 -0
  384. package/dist/web-ui/_app/immutable/chunks/{BysXJlZb.js → Dg_zDpDS.js} +1 -1
  385. package/dist/web-ui/_app/immutable/chunks/Dgqu8Yuc.js +1 -0
  386. package/dist/web-ui/_app/immutable/chunks/DmxsPZTB.js +1 -0
  387. package/dist/web-ui/_app/immutable/chunks/DphTaFUB.js +1 -0
  388. package/dist/web-ui/_app/immutable/chunks/DqK4iHp0.js +1 -0
  389. package/dist/web-ui/_app/immutable/chunks/{D9QNBZM2.js → DqT6OH_u.js} +2 -2
  390. package/dist/web-ui/_app/immutable/chunks/Ds9I9wQb.js +1 -0
  391. package/dist/web-ui/_app/immutable/chunks/Du5ng3u4.js +1 -0
  392. package/dist/web-ui/_app/immutable/chunks/DxJw79Wi.js +1 -0
  393. package/dist/web-ui/_app/immutable/chunks/GFTX8GgV.js +1 -0
  394. package/dist/web-ui/_app/immutable/chunks/{C076q4JN.js → HNjs76Zz.js} +1 -1
  395. package/dist/web-ui/_app/immutable/chunks/HVMjDi4_.js +1 -0
  396. package/dist/web-ui/_app/immutable/chunks/{BkOJ8DkV.js → P0A_fJvS.js} +1 -1
  397. package/dist/web-ui/_app/immutable/chunks/T3vGWjIL.js +1 -0
  398. package/dist/web-ui/_app/immutable/chunks/VTmrX9Qu.js +1 -0
  399. package/dist/web-ui/_app/immutable/chunks/{k_Qegko0.js → Xvwhx_F1.js} +1 -1
  400. package/dist/web-ui/_app/immutable/chunks/Yyz1XMQA.js +1 -0
  401. package/dist/web-ui/_app/immutable/chunks/{62JVKtnb.js → dh5HeqUr.js} +1 -1
  402. package/dist/web-ui/_app/immutable/chunks/fZMteyca.js +62 -0
  403. package/dist/web-ui/_app/immutable/chunks/{D82RulSH.js → gPrj-hqC.js} +1 -1
  404. package/dist/web-ui/_app/immutable/chunks/htcWMiYN.js +1 -0
  405. package/dist/web-ui/_app/immutable/chunks/{CwELQvbx.js → oTsvd9y4.js} +1 -1
  406. package/dist/web-ui/_app/immutable/chunks/qJfLUwU4.js +1 -0
  407. package/dist/web-ui/_app/immutable/chunks/xCtiO_JE.js +1 -0
  408. package/dist/web-ui/_app/immutable/chunks/{DvA-KON-.js → y4GeEH6k.js} +1 -1
  409. package/dist/web-ui/_app/immutable/entry/app.C4h_eOn6.js +2 -0
  410. package/dist/web-ui/_app/immutable/entry/start.CQFTf9ep.js +1 -0
  411. package/dist/web-ui/_app/immutable/nodes/0.Dh1xO970.js +1 -0
  412. package/dist/web-ui/_app/immutable/nodes/1.l75D3Opx.js +1 -0
  413. package/dist/web-ui/_app/immutable/nodes/10.DBidBPc-.js +1 -0
  414. package/dist/web-ui/_app/immutable/nodes/11.Ab0gUKWe.js +1 -0
  415. package/dist/web-ui/_app/immutable/nodes/12.CMsnoxfs.js +1 -0
  416. package/dist/web-ui/_app/immutable/nodes/13.D8YKuknB.js +1 -0
  417. package/dist/web-ui/_app/immutable/nodes/14.DZ0aan7y.js +1 -0
  418. package/dist/web-ui/_app/immutable/nodes/15.CUIKreDL.js +2 -0
  419. package/dist/web-ui/_app/immutable/nodes/16.BWc8--BO.js +1 -0
  420. package/dist/web-ui/_app/immutable/nodes/2.CDUonbuh.js +1 -0
  421. package/dist/web-ui/_app/immutable/nodes/3.Ctg3M00i.js +1 -0
  422. package/dist/web-ui/_app/immutable/nodes/4.Ci-JDwbA.js +2 -0
  423. package/dist/web-ui/_app/immutable/nodes/5.CTyEDAq0.js +1 -0
  424. package/dist/web-ui/_app/immutable/nodes/6.BTZZqsAb.js +1 -0
  425. package/dist/web-ui/_app/immutable/nodes/7.BI52g_Jo.js +137 -0
  426. package/dist/web-ui/_app/immutable/nodes/8.3hZPaB9x.js +1 -0
  427. package/dist/web-ui/_app/immutable/nodes/9.DS49kvwl.js +29 -0
  428. package/dist/web-ui/_app/version.json +1 -1
  429. package/dist/web-ui/favicon-192.png +0 -0
  430. package/dist/web-ui/favicon-32.png +0 -0
  431. package/dist/web-ui/favicon.ico +0 -0
  432. package/dist/web-ui/index.html +14 -14
  433. package/package.json +12 -6
  434. package/plugin/.claude-plugin/marketplace.json +1 -1
  435. package/plugin/.claude-plugin/plugin.json +1 -1
  436. package/plugin/plugins/kspec/skills/merge/SKILL.md +127 -0
  437. package/plugin/plugins/kspec/skills/plan/SKILL.md +55 -26
  438. package/plugin/plugins/kspec/skills/review/SKILL.md +350 -133
  439. package/plugin/plugins/kspec/skills/task-work/SKILL.md +96 -106
  440. package/templates/agents-sections/04-pr-workflow.md +15 -12
  441. package/templates/agents-sections/06-ralph-loop.md +15 -10
  442. package/templates/skills/manifest.yaml +25 -7
  443. package/templates/skills/merge/SKILL.md +120 -0
  444. package/templates/skills/plan/SKILL.md +55 -26
  445. package/templates/skills/review/SKILL.md +346 -130
  446. package/templates/skills/task-work/SKILL.md +93 -103
  447. package/dist/web-ui/_app/immutable/assets/0.BJaYkGW2.css +0 -1
  448. package/dist/web-ui/_app/immutable/assets/9.SzGLxi4x.css +0 -1
  449. package/dist/web-ui/_app/immutable/chunks/-lc0BifF.js +0 -1
  450. package/dist/web-ui/_app/immutable/chunks/8RBjHMN1.js +0 -1
  451. package/dist/web-ui/_app/immutable/chunks/B5wTVqxm.js +0 -1
  452. package/dist/web-ui/_app/immutable/chunks/B6VSmczZ.js +0 -1
  453. package/dist/web-ui/_app/immutable/chunks/BEOQc37C.js +0 -1
  454. package/dist/web-ui/_app/immutable/chunks/BHtYorjv.js +0 -1
  455. package/dist/web-ui/_app/immutable/chunks/BMuCqDX8.js +0 -1
  456. package/dist/web-ui/_app/immutable/chunks/BUZujXJ2.js +0 -1
  457. package/dist/web-ui/_app/immutable/chunks/BWET-efb.js +0 -1
  458. package/dist/web-ui/_app/immutable/chunks/BXkNecpt.js +0 -1
  459. package/dist/web-ui/_app/immutable/chunks/BYzrIfX8.js +0 -1
  460. package/dist/web-ui/_app/immutable/chunks/BpuwufMc.js +0 -1
  461. package/dist/web-ui/_app/immutable/chunks/BwMO4RrG.js +0 -1
  462. package/dist/web-ui/_app/immutable/chunks/C33JaVbg.js +0 -1
  463. package/dist/web-ui/_app/immutable/chunks/CGtqifKp.js +0 -1
  464. package/dist/web-ui/_app/immutable/chunks/CHDZZ7OG.js +0 -1
  465. package/dist/web-ui/_app/immutable/chunks/CUir3f4J.js +0 -60
  466. package/dist/web-ui/_app/immutable/chunks/CrCIbn0C.js +0 -1
  467. package/dist/web-ui/_app/immutable/chunks/D6TVmR9T.js +0 -1
  468. package/dist/web-ui/_app/immutable/chunks/D7LTux4W.js +0 -1
  469. package/dist/web-ui/_app/immutable/chunks/DAh4Wfku.js +0 -1
  470. package/dist/web-ui/_app/immutable/chunks/DAx07bEQ.js +0 -1
  471. package/dist/web-ui/_app/immutable/chunks/DOno4cA2.js +0 -1
  472. package/dist/web-ui/_app/immutable/chunks/DQA8NZIH.js +0 -2
  473. package/dist/web-ui/_app/immutable/chunks/DRfPm2bo.js +0 -1
  474. package/dist/web-ui/_app/immutable/chunks/DhQhksaB.js +0 -1
  475. package/dist/web-ui/_app/immutable/chunks/DjG7s6hm.js +0 -1
  476. package/dist/web-ui/_app/immutable/chunks/DkltRNvh.js +0 -1
  477. package/dist/web-ui/_app/immutable/chunks/DlaTnPKL.js +0 -1
  478. package/dist/web-ui/_app/immutable/chunks/ExCq5swK.js +0 -1
  479. package/dist/web-ui/_app/immutable/chunks/T3zZGv51.js +0 -1
  480. package/dist/web-ui/_app/immutable/chunks/XZumBYeP.js +0 -1
  481. package/dist/web-ui/_app/immutable/chunks/_ySfNjkF.js +0 -1
  482. package/dist/web-ui/_app/immutable/chunks/iEtR5cV6.js +0 -1
  483. package/dist/web-ui/_app/immutable/entry/app.Cgu6uKeS.js +0 -2
  484. package/dist/web-ui/_app/immutable/entry/start.9XifnLoB.js +0 -1
  485. package/dist/web-ui/_app/immutable/nodes/0.DISwcKSK.js +0 -1
  486. package/dist/web-ui/_app/immutable/nodes/1.Cx2Ufqp1.js +0 -1
  487. package/dist/web-ui/_app/immutable/nodes/10.C3z8ijXL.js +0 -1
  488. package/dist/web-ui/_app/immutable/nodes/11.DZdIjZmM.js +0 -1
  489. package/dist/web-ui/_app/immutable/nodes/12.FsIGfAOa.js +0 -1
  490. package/dist/web-ui/_app/immutable/nodes/13.DZoFwagf.js +0 -1
  491. package/dist/web-ui/_app/immutable/nodes/14.DaIzDKbQ.js +0 -1
  492. package/dist/web-ui/_app/immutable/nodes/15.BYyt4XWF.js +0 -2
  493. package/dist/web-ui/_app/immutable/nodes/16.CQkSqpOe.js +0 -1
  494. package/dist/web-ui/_app/immutable/nodes/2.Bkf_j2UJ.js +0 -1
  495. package/dist/web-ui/_app/immutable/nodes/3.kaMCurJG.js +0 -1
  496. package/dist/web-ui/_app/immutable/nodes/4.BSsFPTHG.js +0 -2
  497. package/dist/web-ui/_app/immutable/nodes/5.CpPlcCEZ.js +0 -1
  498. package/dist/web-ui/_app/immutable/nodes/6.BN4FqQmY.js +0 -1
  499. package/dist/web-ui/_app/immutable/nodes/7.9kBYIZik.js +0 -1
  500. package/dist/web-ui/_app/immutable/nodes/8.BuijtZ6B.js +0 -1
  501. package/dist/web-ui/_app/immutable/nodes/9.C-Weba8R.js +0 -1
@@ -1,14 +1,16 @@
1
+ import { execSync } from "node:child_process";
1
2
  import chalk from "chalk";
2
3
  import { markMutating } from "../command-annotations.js";
3
- import { checkSlugUniqueness, createNote, createTask, createTodo, deleteTask, getAuthor, initContext, loadAllItems, loadAllTasks, mutateTaskAtomically, ReferenceIndex, saveTask, scanTestCoverage, syncSpecImplementationStatus, } from "../../parser/index.js";
4
+ import { checkSlugUniqueness, createNote, createTask, createTodo, deleteTask, findReviewByRef, getAuthor, initContext, loadAllItems, loadAllTasks, loadReviewRecords, mutateTaskAtomically, ReferenceIndex, saveTask, scanTestCoverage, syncSpecImplementationStatus, } from "../../parser/index.js";
4
5
  import { commitIfShadow } from "../../parser/shadow.js";
5
6
  import { normalizeRefInput } from "../../schema/index.js";
6
7
  import { alignmentCheck, errors } from "../../strings/index.js";
7
8
  import { formatCommitGuidance, printCommitGuidance, } from "../../utils/commit.js";
9
+ import { captureSubmissionLinkage, getCurrentBranch, isGitRepo } from "../../utils/git.js";
8
10
  import { executeBatchOperation, formatBatchOutput } from "../batch.js";
9
11
  import { EXIT_CODES } from "../exit-codes.js";
10
12
  import { parseTagsArray } from "../parse-utils.js";
11
- import { annotateNotesWithSuperseded, error, formatTaskDetails, info, isJsonMode, output, success, warn, } from "../output.js";
13
+ import { annotateNotesWithSuperseded, error, formatTaskDetails, info, isJsonMode, output, showChangeDiff, success, warn, } from "../output.js";
12
14
  import { parsePriority, validateEnumOption, validateSpecRef, } from "../validators.js";
13
15
  import { addListOptions, listTasksAction } from "./tasks.js";
14
16
  import { findClosestCommand } from "../suggest.js";
@@ -129,6 +131,120 @@ function resolveTaskRefForBatch(ref, tasks, index) {
129
131
  }
130
132
  return { task };
131
133
  }
134
+ /**
135
+ * Compute the deterministic dispatch-compatible branch name for a task.
136
+ * Uses the exact `dispatch/task/<normalized-task-slug>/<short-task-ref>` naming contract.
137
+ * AC: @deterministic-task-branch-helper ac-1
138
+ */
139
+ function computeDispatchBranchName(taskRef, task) {
140
+ const preferred = task?.slugs?.[0] ?? task?.title ?? taskRef.replace(/^@/, "task");
141
+ const slug = preferred
142
+ .toLowerCase()
143
+ .replace(/[^a-z0-9]+/g, "-")
144
+ .replace(/^-+|-+$/g, "")
145
+ .replace(/--+/g, "-") || "task";
146
+ const shortId = taskRef.replace(/^@/, "").slice(0, 8).toLowerCase();
147
+ return `dispatch/task/${slug}/${shortId}`;
148
+ }
149
+ /**
150
+ * Check if a git ref exists locally.
151
+ */
152
+ function gitRefExists(ref) {
153
+ try {
154
+ execSync(`git show-ref --verify --quiet ${ref}`, { stdio: "pipe" });
155
+ return true;
156
+ }
157
+ catch {
158
+ return false;
159
+ }
160
+ }
161
+ /**
162
+ * List git remotes, with "origin" sorted first.
163
+ */
164
+ function listRemotes() {
165
+ try {
166
+ const output = execSync("git remote", { encoding: "utf-8", stdio: "pipe" }).trim();
167
+ if (!output)
168
+ return [];
169
+ const remotes = output.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
170
+ return [
171
+ ...remotes.filter((r) => r === "origin"),
172
+ ...remotes.filter((r) => r !== "origin"),
173
+ ];
174
+ }
175
+ catch {
176
+ return [];
177
+ }
178
+ }
179
+ /**
180
+ * Find a branch on any configured remote. Returns the remote ref (e.g. "origin/branch")
181
+ * if found, null otherwise. Fetches from the remote to ensure refs are up to date.
182
+ */
183
+ function findBranchOnRemote(branch) {
184
+ for (const remote of listRemotes()) {
185
+ // Fetch the branch from the remote (it may exist remotely but not be tracked locally)
186
+ try {
187
+ execSync(`git fetch ${remote} ${branch}`, { stdio: "pipe" });
188
+ }
189
+ catch {
190
+ // Fetch failed — branch may not exist on this remote
191
+ }
192
+ if (gitRefExists(`refs/remotes/${remote}/${branch}`)) {
193
+ return `${remote}/${branch}`;
194
+ }
195
+ }
196
+ return null;
197
+ }
198
+ /**
199
+ * Create a local branch from a remote tracking ref.
200
+ */
201
+ function gitCreateBranchFrom(branch, startPoint) {
202
+ execSync(`git branch ${branch} ${startPoint}`, { stdio: "pipe" });
203
+ }
204
+ /**
205
+ * Switch to an existing branch.
206
+ */
207
+ function gitCheckout(branch) {
208
+ execSync(`git checkout ${branch}`, { stdio: "pipe" });
209
+ }
210
+ /**
211
+ * Create and switch to a new branch.
212
+ */
213
+ function gitCheckoutNew(branch) {
214
+ execSync(`git checkout -b ${branch}`, { stdio: "pipe" });
215
+ }
216
+ /**
217
+ * Report the result of the branch helper operation.
218
+ * AC: @deterministic-task-branch-helper ac-3
219
+ * AC: @trait-json-output ac-1, ac-2, ac-4
220
+ */
221
+ function reportBranchResult(result) {
222
+ const actionLabels = {
223
+ created: "Created new branch",
224
+ switched: "Switched to existing branch",
225
+ rehydrated: "Rehydrated branch from remote",
226
+ already_on_branch: "Already on branch",
227
+ };
228
+ const label = actionLabels[result.action];
229
+ const guidance = "Using this dispatch-compatible branch preserves reviewer and fix-cycle continuity for manual work.";
230
+ if (isJsonMode()) {
231
+ output({
232
+ branch: result.branch,
233
+ action: result.action,
234
+ task_ref: result.taskRef,
235
+ source: result.source ?? null,
236
+ guidance,
237
+ });
238
+ }
239
+ else {
240
+ success(`${label}: ${result.branch}`);
241
+ info(`Task: ${result.taskRef}`);
242
+ if (result.source) {
243
+ info(`Source: ${result.source}`);
244
+ }
245
+ info(guidance);
246
+ }
247
+ }
132
248
  /**
133
249
  * Helper function to update task fields.
134
250
  * Used by both single-ref and batch modes of task set.
@@ -281,78 +397,101 @@ async function setTaskFields(foundTask, ctx, tasks, items, _allMetaItems, index,
281
397
  updatedTask = await mutateTaskAtomically(ctx, foundTask, (latestTask) => {
282
398
  const nextTask = { ...latestTask };
283
399
  const mutationChanges = [];
284
- if (options.title) {
400
+ if (options.title && options.title !== latestTask.title) {
285
401
  nextTask.title = options.title;
286
- mutationChanges.push("title");
402
+ mutationChanges.push({ field: "title", before: latestTask.title, after: options.title });
287
403
  }
288
404
  if (options.description !== undefined) {
289
405
  if (options.description === "null" || options.description.trim() === "") {
290
- delete nextTask.description;
291
- mutationChanges.push("description: cleared");
406
+ if (latestTask.description !== undefined) {
407
+ const before = latestTask.description;
408
+ delete nextTask.description;
409
+ mutationChanges.push({ field: "description", before, after: null });
410
+ }
292
411
  }
293
- else {
412
+ else if (options.description !== latestTask.description) {
413
+ mutationChanges.push({ field: "description", before: latestTask.description, after: options.description });
294
414
  nextTask.description = options.description;
295
- mutationChanges.push("description");
296
415
  }
297
416
  }
298
417
  if (options.specRef !== undefined) {
299
418
  if (options.specRef === "null") {
300
- nextTask.spec_ref = null;
301
- mutationChanges.push("spec_ref: cleared");
419
+ if (latestTask.spec_ref != null) {
420
+ mutationChanges.push({ field: "spec_ref", before: latestTask.spec_ref, after: null });
421
+ nextTask.spec_ref = null;
422
+ }
302
423
  }
303
424
  else {
304
- nextTask.spec_ref = normalizeRefInput(options.specRef);
305
- mutationChanges.push("spec_ref");
425
+ const newVal = normalizeRefInput(options.specRef);
426
+ if (newVal !== latestTask.spec_ref) {
427
+ mutationChanges.push({ field: "spec_ref", before: latestTask.spec_ref, after: newVal });
428
+ nextTask.spec_ref = newVal;
429
+ }
306
430
  }
307
431
  }
308
432
  if (options.metaRef !== undefined) {
309
433
  if (options.metaRef === "null") {
310
- nextTask.meta_ref = null;
311
- mutationChanges.push("meta_ref: cleared");
434
+ if (latestTask.meta_ref != null) {
435
+ mutationChanges.push({ field: "meta_ref", before: latestTask.meta_ref, after: null });
436
+ nextTask.meta_ref = null;
437
+ }
312
438
  }
313
439
  else {
314
- nextTask.meta_ref = normalizeRefInput(options.metaRef);
315
- mutationChanges.push("meta_ref");
440
+ const newVal = normalizeRefInput(options.metaRef);
441
+ if (newVal !== latestTask.meta_ref) {
442
+ mutationChanges.push({ field: "meta_ref", before: latestTask.meta_ref, after: newVal });
443
+ nextTask.meta_ref = newVal;
444
+ }
316
445
  }
317
446
  }
318
447
  if (options.planRef !== undefined) {
319
448
  if (options.planRef === "null") {
320
- nextTask.plan_ref = null;
321
- mutationChanges.push("plan_ref: cleared");
449
+ if (latestTask.plan_ref != null) {
450
+ mutationChanges.push({ field: "plan_ref", before: latestTask.plan_ref, after: null });
451
+ nextTask.plan_ref = null;
452
+ }
322
453
  }
323
454
  else {
324
- nextTask.plan_ref = normalizeRefInput(options.planRef);
325
- mutationChanges.push("plan_ref");
455
+ const newVal = normalizeRefInput(options.planRef);
456
+ if (newVal !== latestTask.plan_ref) {
457
+ mutationChanges.push({ field: "plan_ref", before: latestTask.plan_ref, after: newVal });
458
+ nextTask.plan_ref = newVal;
459
+ }
326
460
  }
327
461
  }
328
462
  if (options.reviewUrl !== undefined) {
329
463
  if (options.reviewUrl === "null") {
330
- delete nextTask.review_url;
331
- mutationChanges.push("review_url: cleared");
464
+ if (latestTask.review_url != null) {
465
+ mutationChanges.push({ field: "review_url", before: latestTask.review_url, after: null });
466
+ delete nextTask.review_url;
467
+ }
332
468
  }
333
- else {
469
+ else if (options.reviewUrl !== latestTask.review_url) {
470
+ mutationChanges.push({ field: "review_url", before: latestTask.review_url, after: options.reviewUrl });
334
471
  nextTask.review_url = options.reviewUrl;
335
- mutationChanges.push("review_url");
336
472
  }
337
473
  }
338
- if (parsedPriority !== undefined) {
474
+ if (parsedPriority !== undefined && parsedPriority !== latestTask.priority) {
475
+ mutationChanges.push({ field: "priority", before: latestTask.priority, after: parsedPriority });
339
476
  nextTask.priority = parsedPriority;
340
- mutationChanges.push("priority");
341
477
  }
342
478
  if (options.slug && !nextTask.slugs.includes(options.slug)) {
479
+ const before = [...latestTask.slugs];
343
480
  nextTask.slugs = [...nextTask.slugs, options.slug];
344
- mutationChanges.push("slug");
481
+ mutationChanges.push({ field: "slugs", before, after: nextTask.slugs });
345
482
  }
346
483
  if (parsedTags.length > 0) {
347
484
  const newTags = parsedTags.filter((tag) => !nextTask.tags.includes(tag));
348
485
  if (newTags.length > 0) {
486
+ const before = [...latestTask.tags];
349
487
  nextTask.tags = [...nextTask.tags, ...newTags];
350
- mutationChanges.push("tags");
488
+ mutationChanges.push({ field: "tags", before, after: nextTask.tags });
351
489
  }
352
490
  }
353
491
  if (options.dependsOn) {
492
+ const before = [...latestTask.depends_on];
354
493
  nextTask.depends_on = options.dependsOn.map(normalizeRefInput);
355
- mutationChanges.push("depends_on");
494
+ mutationChanges.push({ field: "depends_on", before, after: nextTask.depends_on });
356
495
  }
357
496
  if (options.clearDeps) {
358
497
  if (latestTask.depends_on.length === 0) {
@@ -360,23 +499,41 @@ async function setTaskFields(foundTask, ctx, tasks, items, _allMetaItems, index,
360
499
  noChangesMessage = "No changes: task has no dependencies to clear";
361
500
  return latestTask;
362
501
  }
502
+ const before = [...latestTask.depends_on];
363
503
  nextTask.depends_on = [];
364
- mutationChanges.push("depends_on");
504
+ mutationChanges.push({ field: "depends_on", before, after: [] });
365
505
  // AC: @task-set ac-author
366
506
  const note = createNote(`Dependencies cleared (was: ${latestTask.depends_on.join(", ")})`, getAuthor(ctx.config?.identity?.author));
367
507
  nextTask.notes = [...nextTask.notes, note];
368
508
  }
369
509
  if (options.automation === false) {
370
- delete nextTask.automation;
371
- mutationChanges.push("automation");
510
+ if (latestTask.automation != null) {
511
+ mutationChanges.push({ field: "automation", before: latestTask.automation, after: null });
512
+ delete nextTask.automation;
513
+ }
372
514
  }
373
- else if (validatedAutomation) {
515
+ else if (validatedAutomation && validatedAutomation !== latestTask.automation) {
516
+ mutationChanges.push({ field: "automation", before: latestTask.automation, after: validatedAutomation });
374
517
  nextTask.automation = validatedAutomation;
375
- mutationChanges.push("automation");
376
518
  if (options.reason) {
377
519
  const note = createNote(`Automation status set to ${validatedAutomation}: ${options.reason}`, getAuthor(ctx.config?.identity?.author));
378
520
  nextTask.notes = [...nextTask.notes, note];
379
- mutationChanges.push("note");
521
+ }
522
+ }
523
+ // AC: @portable-task-submission-linkage ac-4 — repair/backfill or clear submission linkage
524
+ if (options.clearSubmissionLinkage) {
525
+ if (latestTask.submission_linkage != null) {
526
+ mutationChanges.push({ field: "submission_linkage", before: latestTask.submission_linkage, after: null });
527
+ nextTask.submission_linkage = null;
528
+ }
529
+ }
530
+ else if (options.submissionLinkage) {
531
+ const linkage = isGitRepo(ctx.projectRoot)
532
+ ? captureSubmissionLinkage(ctx.projectRoot, latestTask.review_url, ctx.config?.dispatch?.base_branch)
533
+ : null;
534
+ if (linkage) {
535
+ mutationChanges.push({ field: "submission_linkage", before: latestTask.submission_linkage, after: linkage });
536
+ nextTask.submission_linkage = linkage;
380
537
  }
381
538
  }
382
539
  changes.splice(0, changes.length, ...mutationChanges);
@@ -397,11 +554,12 @@ async function setTaskFields(foundTask, ctx, tasks, items, _allMetaItems, index,
397
554
  data: { task: updatedTask },
398
555
  };
399
556
  }
400
- await commitIfShadow(ctx.shadow, "task-set", foundTask.slugs[0] || index.shortUlid(foundTask._ulid), changes.join(", "));
557
+ const changedFields = changes.map((c) => c.field).join(", ");
558
+ await commitIfShadow(ctx.shadow, "task-set", foundTask.slugs[0] || index.shortUlid(foundTask._ulid), changedFields);
401
559
  return {
402
560
  success: true,
403
- message: `Updated task: ${index.shortUlid(updatedTask._ulid)} (${changes.join(", ")})`,
404
- data: { task: updatedTask },
561
+ message: `Updated task: ${index.shortUlid(updatedTask._ulid)} (${changedFields})`,
562
+ data: { task: updatedTask, changes },
405
563
  };
406
564
  }
407
565
  catch (err) {
@@ -470,6 +628,7 @@ export function registerTaskCommands(program) {
470
628
  .command("get <ref>")
471
629
  .description("Get task details")
472
630
  .option("--all", "Show all notes including superseded ones")
631
+ .option("--activity", "Show full activity timeline")
473
632
  .action(async (ref, options) => {
474
633
  try {
475
634
  const ctx = await initContext();
@@ -499,11 +658,66 @@ export function registerTaskCommands(program) {
499
658
  inheritedTraits = Array.from(traitsByTrait.values());
500
659
  }
501
660
  }
661
+ // Load review records once — used for both active review display and activity timeline
662
+ const allReviews = await loadReviewRecords(ctx);
663
+ // AC: @review-cli-task-linkage ac-1 — resolve active review for task
664
+ let activeReview = null;
665
+ if (foundTask.review_ref) {
666
+ const { computeDisposition } = await import("../../parser/index.js");
667
+ const found = findReviewByRef(allReviews, foundTask.review_ref);
668
+ if (found) {
669
+ activeReview = {
670
+ ref: `@${found.slugs[0] || found._ulid}`,
671
+ title: found.title,
672
+ lifecycle_state: found.lifecycle_state,
673
+ disposition: computeDisposition(found),
674
+ };
675
+ }
676
+ }
677
+ // AC: @task-activity-timeline ac-1, ac-2, ac-3 — load activity timeline
678
+ let activity = [];
679
+ try {
680
+ const { getRawTaskCommits, normalizeTaskActivity } = await import("../../utils/activity.js");
681
+ const rawCommits = getRawTaskCommits(ctx.specDir, foundTask._ulid);
682
+ activity = normalizeTaskActivity(rawCommits);
683
+ // AC: @task-activity-timeline ac-3 — merge review events into timeline
684
+ const taskRef = `@${foundTask.slugs[0] || foundTask._ulid}`;
685
+ const linkedReviews = allReviews.filter((r) => r.related_refs.includes(taskRef) ||
686
+ (r.subject.type === "task" && r.subject.ref === taskRef) ||
687
+ r._ulid === (foundTask.review_ref?.startsWith("@")
688
+ ? foundTask.review_ref.slice(1)
689
+ : foundTask.review_ref));
690
+ for (const review of linkedReviews) {
691
+ const reviewRef = `@${review.slugs[0] || review._ulid}`;
692
+ for (const event of review.events) {
693
+ activity.push({
694
+ type: event.event_type === "verdict_submitted"
695
+ ? "submitted"
696
+ : event.event_type === "lifecycle_change"
697
+ ? "state_change"
698
+ : "review_linked",
699
+ timestamp: event.timestamp,
700
+ author: event.actor,
701
+ summary: `Review ${reviewRef}: ${event.event_type.replace(/_/g, " ")}`,
702
+ commitHash: "",
703
+ });
704
+ }
705
+ }
706
+ // Re-sort chronologically (oldest first) after merging
707
+ activity.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
708
+ }
709
+ catch {
710
+ // Activity is best-effort — don't fail task get if git query fails
711
+ }
502
712
  // Build JSON output with inherited traits (AC: @trait-display ac-2)
503
713
  // Always include all notes in JSON output with superseded computed field
714
+ // AC: @review-cli-task-linkage ac-1 — include resolved review summary in JSON
715
+ // AC: @task-activity-timeline ac-4 — include activity in JSON output
504
716
  const jsonOutput = {
505
717
  ...foundTask,
506
718
  notes: annotateNotesWithSuperseded(foundTask.notes),
719
+ ...(activeReview && { active_review: activeReview }),
720
+ ...(activity.length > 0 && { activity }),
507
721
  ...(inheritedTraits.length > 0 && {
508
722
  inherited_traits: inheritedTraits.map(({ trait, acs }) => ({
509
723
  ref: `@${trait.slug}`,
@@ -513,7 +727,12 @@ export function registerTaskCommands(program) {
513
727
  }),
514
728
  };
515
729
  output(jsonOutput, () => {
516
- formatTaskDetails(foundTask, index, { showAllNotes: options.all });
730
+ formatTaskDetails(foundTask, index, {
731
+ showAllNotes: options.all,
732
+ activeReview,
733
+ activity,
734
+ showFullActivity: options.activity,
735
+ });
517
736
  // AC: @trait-display ac-3, ac-4, ac-5 - Show inherited AC per trait in labeled sections
518
737
  if (inheritedTraits.length > 0) {
519
738
  for (const { trait, acs } of inheritedTraits) {
@@ -613,7 +832,7 @@ Examples:
613
832
  }
614
833
  automationValue = automationResult.value;
615
834
  }
616
- // Validate plan_ref if provided (AC: @plan-derive ac-5, ac-6)
835
+ // Validate plan_ref if provided (AC: @plan-derive-enhanced ac-task-refs, ac-bidirectional-links)
617
836
  if (options.planRef) {
618
837
  // First check if it's a task or spec item (wrong type)
619
838
  const cleanRef = options.planRef.startsWith("@")
@@ -709,12 +928,15 @@ Examples:
709
928
  .option("--no-automation", "Clear automation status (return to unassessed)")
710
929
  .option("--reason <reason>", "Reason for status change (required when setting needs_review)")
711
930
  .option("--status <status>", "Reject with error - use state transition commands instead")
931
+ .option("--submission-linkage", "Repair/backfill submission linkage from current git context (AC: @portable-task-submission-linkage ac-4)")
932
+ .option("--clear-submission-linkage", "Clear submission linkage (AC: @portable-task-submission-linkage ac-4)")
712
933
  .addHelpText("after", `
713
934
  Examples:
714
935
  $ kspec task set @task-slug --priority 2
715
936
  $ kspec task set @task-slug --description "Updated context"
716
937
  $ kspec task set @task-slug --depends-on @dep1 @dep2
717
938
  $ kspec task set @task-slug --tag cli urgent
939
+ $ kspec task set @task-slug --submission-linkage # capture current git context
718
940
  $ kspec task set --refs @task1 @task2 --priority 3`)
719
941
  .action(async (ref, options) => {
720
942
  try {
@@ -789,6 +1011,11 @@ Examples:
789
1011
  }
790
1012
  else {
791
1013
  success(result.message, result.data);
1014
+ // Show before→after diff in text mode
1015
+ const data = result.data;
1016
+ if (data?.changes) {
1017
+ showChangeDiff(data.changes);
1018
+ }
792
1019
  }
793
1020
  }
794
1021
  }
@@ -930,7 +1157,7 @@ Examples:
930
1157
  }
931
1158
  // AC: @session-end-loop-signal ac-block-task - Block if end-loop requested
932
1159
  if (sessionId) {
933
- const endLoopState = await isEndLoopRequested(ctx.specDir, sessionId);
1160
+ const endLoopState = await isEndLoopRequested(ctx.sessionsDir, sessionId);
934
1161
  if (endLoopState?.requested) {
935
1162
  error(`Cannot start task: loop is ending for session ${sessionId.slice(0, 8)}...` +
936
1163
  (endLoopState.reason ? ` Reason: ${endLoopState.reason}` : ""));
@@ -944,7 +1171,7 @@ Examples:
944
1171
  // already consumed a budget slot when originally started; blocking it
945
1172
  // would prevent completing already-assigned work.
946
1173
  if (foundTask.status !== "needs_work") {
947
- const budgetCheck = await checkBudget(ctx.specDir, sessionId || undefined);
1174
+ const budgetCheck = await checkBudget(ctx.sessionsDir, sessionId || undefined);
948
1175
  if (!budgetCheck.allowed) {
949
1176
  error(budgetCheck.reason);
950
1177
  process.exit(EXIT_CODES.VALIDATION_FAILED);
@@ -969,7 +1196,7 @@ Examples:
969
1196
  // above. needs_work→in_progress is a fix cycle (task already consumed
970
1197
  // a budget slot when originally started) — don't double-count it.
971
1198
  if (sessionId && transitionFromStatus === "pending") {
972
- await incrementBudget(ctx.specDir, sessionId);
1199
+ await incrementBudget(ctx.sessionsDir, sessionId);
973
1200
  }
974
1201
  // AC: @daemon-agent-dispatch ac-2, ac-7 - Notify daemon of state change (fire-and-forget)
975
1202
  postDispatchEvent({
@@ -977,7 +1204,7 @@ Examples:
977
1204
  taskRef: `@${updatedTask.slugs[0] || updatedTask._ulid}`,
978
1205
  fromStatus: transitionFromStatus,
979
1206
  toStatus: updatedTask.status,
980
- projectPath: ctx.rootDir,
1207
+ projectPath: ctx.projectRoot,
981
1208
  });
982
1209
  success(`Started task: ${index.shortUlid(updatedTask._ulid)}`, {
983
1210
  task: updatedTask,
@@ -1139,7 +1366,7 @@ Examples:
1139
1366
  taskRef: `@${updatedTask.slugs[0] || updatedTask._ulid}`,
1140
1367
  fromStatus: transitionFromStatus,
1141
1368
  toStatus: updatedTask.status,
1142
- projectPath: ctx.rootDir,
1369
+ projectPath: ctx.projectRoot,
1143
1370
  });
1144
1371
  // Sync spec implementation status (unless --no-sync)
1145
1372
  if (options.sync !== false && foundTask.spec_ref) {
@@ -1228,6 +1455,10 @@ Examples:
1228
1455
  const items = await loadAllItems(ctx);
1229
1456
  const index = new ReferenceIndex(tasks, items);
1230
1457
  const foundTask = resolveTaskRef(ref, tasks, index);
1458
+ // AC: @portable-task-submission-linkage ac-1, ac-3, ac-5 — capture git context
1459
+ const linkage = isGitRepo(ctx.projectRoot)
1460
+ ? captureSubmissionLinkage(ctx.projectRoot, options.reviewUrl, ctx.config?.dispatch?.base_branch)
1461
+ : null;
1231
1462
  let transitionFromStatus = foundTask.status;
1232
1463
  const updatedTask = await mutateTaskAtomically(ctx, foundTask, (latestTask) => {
1233
1464
  transitionFromStatus = latestTask.status;
@@ -1240,6 +1471,8 @@ Examples:
1240
1471
  submitted_at: new Date().toISOString(),
1241
1472
  // AC: @task-submit ac-submit-2
1242
1473
  ...(options.reviewUrl !== undefined && { review_url: options.reviewUrl }),
1474
+ // AC: @portable-task-submission-linkage ac-1
1475
+ ...(linkage && { submission_linkage: linkage }),
1243
1476
  };
1244
1477
  });
1245
1478
  if (transitionFromStatus !== "in_progress") {
@@ -1253,9 +1486,15 @@ Examples:
1253
1486
  taskRef: `@${updatedTask.slugs[0] || updatedTask._ulid}`,
1254
1487
  fromStatus: transitionFromStatus,
1255
1488
  toStatus: updatedTask.status,
1256
- projectPath: ctx.rootDir,
1489
+ projectPath: ctx.projectRoot,
1257
1490
  });
1258
1491
  success(`Submitted task for review: ${index.shortUlid(updatedTask._ulid)}`, { task: updatedTask });
1492
+ // AC: @portable-task-submission-linkage ac-3 — warn on detached HEAD
1493
+ if (linkage && !linkage.branch) {
1494
+ warn("Submitted from detached HEAD — submission linkage has no branch name. " +
1495
+ "Dispatch review continuity may require an explicit branch. " +
1496
+ "Use `kspec task set @ref --submission-linkage` to repair.");
1497
+ }
1259
1498
  }
1260
1499
  catch (err) {
1261
1500
  error(errors.failures.updateTask, err);
@@ -1304,7 +1543,7 @@ Examples:
1304
1543
  taskRef: `@${updatedTask.slugs[0] || updatedTask._ulid}`,
1305
1544
  fromStatus: transitionFromStatus,
1306
1545
  toStatus: updatedTask.status,
1307
- projectPath: ctx.rootDir,
1546
+ projectPath: ctx.projectRoot,
1308
1547
  });
1309
1548
  success(`Kicked back task: ${index.shortUlid(updatedTask._ulid)} (fix cycle ${cycleNumber})`, { task: updatedTask });
1310
1549
  }
@@ -1349,7 +1588,7 @@ Examples:
1349
1588
  taskRef: `@${updatedTask.slugs[0] || updatedTask._ulid}`,
1350
1589
  fromStatus: transitionFromStatus,
1351
1590
  toStatus: updatedTask.status,
1352
- projectPath: ctx.rootDir,
1591
+ projectPath: ctx.projectRoot,
1353
1592
  });
1354
1593
  success(`Blocked task: ${index.shortUlid(updatedTask._ulid)}`, {
1355
1594
  task: updatedTask,
@@ -1395,7 +1634,7 @@ Examples:
1395
1634
  taskRef: `@${updatedTask.slugs[0] || updatedTask._ulid}`,
1396
1635
  fromStatus: transitionFromStatus,
1397
1636
  toStatus: updatedTask.status,
1398
- projectPath: ctx.rootDir,
1637
+ projectPath: ctx.projectRoot,
1399
1638
  });
1400
1639
  success(`Unblocked task: ${index.shortUlid(updatedTask._ulid)}`, {
1401
1640
  task: updatedTask,
@@ -2035,5 +2274,76 @@ Examples:
2035
2274
  process.exit(EXIT_CODES.ERROR);
2036
2275
  }
2037
2276
  });
2277
+ // kspec task branch <ref>
2278
+ // AC: @deterministic-task-branch-helper ac-1, ac-2, ac-3
2279
+ task
2280
+ .command("branch <ref>")
2281
+ .description("Create or resume the deterministic dispatch-compatible branch for a task")
2282
+ .action(async (ref) => {
2283
+ try {
2284
+ const ctx = await initContext();
2285
+ const tasks = await loadAllTasks(ctx);
2286
+ const items = await loadAllItems(ctx);
2287
+ const index = new ReferenceIndex(tasks, items);
2288
+ const foundTask = resolveTaskRef(ref, tasks, index);
2289
+ // AC: @trait-error-guidance ac-1, ac-2
2290
+ if (!isGitRepo()) {
2291
+ error("Not a git repository. Run this command from inside a git repo.");
2292
+ process.exit(EXIT_CODES.VALIDATION_FAILED);
2293
+ }
2294
+ // AC: @deterministic-task-branch-helper ac-1
2295
+ // Compute the deterministic branch name using the dispatch naming contract
2296
+ const branchName = computeDispatchBranchName(foundTask._ulid, foundTask);
2297
+ // AC: @deterministic-task-branch-helper ac-2
2298
+ // Check if the branch already exists locally
2299
+ const localExists = gitRefExists(`refs/heads/${branchName}`);
2300
+ if (localExists) {
2301
+ // Branch exists locally — switch to it
2302
+ const currentBranch = getCurrentBranch();
2303
+ if (currentBranch === branchName) {
2304
+ // Already on the branch
2305
+ reportBranchResult({
2306
+ branch: branchName,
2307
+ action: "already_on_branch",
2308
+ taskRef: `@${foundTask.slugs[0] || foundTask._ulid}`,
2309
+ });
2310
+ }
2311
+ else {
2312
+ gitCheckout(branchName);
2313
+ reportBranchResult({
2314
+ branch: branchName,
2315
+ action: "switched",
2316
+ taskRef: `@${foundTask.slugs[0] || foundTask._ulid}`,
2317
+ });
2318
+ }
2319
+ return;
2320
+ }
2321
+ // AC: @deterministic-task-branch-helper ac-2
2322
+ // Check remotes for the branch and rehydrate if found
2323
+ const remoteSource = findBranchOnRemote(branchName);
2324
+ if (remoteSource) {
2325
+ gitCreateBranchFrom(branchName, remoteSource);
2326
+ gitCheckout(branchName);
2327
+ reportBranchResult({
2328
+ branch: branchName,
2329
+ action: "rehydrated",
2330
+ source: remoteSource,
2331
+ taskRef: `@${foundTask.slugs[0] || foundTask._ulid}`,
2332
+ });
2333
+ return;
2334
+ }
2335
+ // Branch does not exist anywhere — create it
2336
+ gitCheckoutNew(branchName);
2337
+ reportBranchResult({
2338
+ branch: branchName,
2339
+ action: "created",
2340
+ taskRef: `@${foundTask.slugs[0] || foundTask._ulid}`,
2341
+ });
2342
+ }
2343
+ catch (err) {
2344
+ error(errors.failures.taskBranch, err);
2345
+ process.exit(EXIT_CODES.ERROR);
2346
+ }
2347
+ });
2038
2348
  }
2039
2349
  //# sourceMappingURL=task.js.map