@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
@@ -34,6 +34,8 @@ import {
34
34
  } from '../../parser/index.js';
35
35
  import { commitIfShadow } from '../../parser/shadow.js';
36
36
  import type { PubSubManager } from '../websocket/pubsub';
37
+ import { getRelatedSessionsForTask } from './session-related.js';
38
+ import { resolveRefTitle, resolveRefEntries } from './ref-resolution.js';
37
39
 
38
40
  interface TasksRouteOptions {
39
41
  pubsub: PubSubManager;
@@ -110,6 +112,7 @@ export function createTasksRoutes(options: TasksRouteOptions) {
110
112
 
111
113
  // AC: @api-contract ac-2 - Return with status, priority, spec_ref, notes count
112
114
  // AC: @web-dashboard ac-1 - Include depends_on for blocked task computation
115
+ // AC: @ui-api-ref-resolution ac-1 - Include spec_title resolved server-side
113
116
  const items = paginated.map((task) => ({
114
117
  _ulid: task._ulid,
115
118
  slugs: task.slugs,
@@ -118,6 +121,7 @@ export function createTasksRoutes(options: TasksRouteOptions) {
118
121
  status: task.status,
119
122
  priority: task.priority,
120
123
  spec_ref: task.spec_ref,
124
+ spec_title: resolveRefTitle(index, task.spec_ref),
121
125
  meta_ref: task.meta_ref,
122
126
  tags: task.tags,
123
127
  depends_on: task.depends_on || [],
@@ -158,7 +162,8 @@ export function createTasksRoutes(options: TasksRouteOptions) {
158
162
  const ctx = await initContext(projectContext.path);
159
163
  const tasks = await loadAllTasks(ctx);
160
164
  const items = await loadAllItems(ctx);
161
- const index = new ReferenceIndex(tasks, items);
165
+ const plans = await loadPlans(ctx);
166
+ const index = new ReferenceIndex(tasks, items, [], plans);
162
167
 
163
168
  // AC: @api-contract ac-5, @trait-api-endpoint ac-2 - Resolve ref via ReferenceIndex
164
169
  const result = index.resolve(params.ref);
@@ -184,6 +189,7 @@ export function createTasksRoutes(options: TasksRouteOptions) {
184
189
 
185
190
  // AC: @api-contract ac-5 - Return full task with notes, todos, dependencies
186
191
  // AC: @ui-task-board ac-3 - Include type, description, blocked_by, vcs_refs, plan_ref, session_ref
192
+ // AC: @ui-api-ref-resolution ac-1, ac-2 - Include resolved titles for refs
187
193
  return {
188
194
  _ulid: task._ulid,
189
195
  slugs: task.slugs,
@@ -192,17 +198,21 @@ export function createTasksRoutes(options: TasksRouteOptions) {
192
198
  status: task.status,
193
199
  priority: task.priority,
194
200
  spec_ref: task.spec_ref,
201
+ spec_title: resolveRefTitle(index, task.spec_ref),
195
202
  meta_ref: task.meta_ref,
196
203
  tags: task.tags,
197
204
  description: task.description,
198
205
  derivation: task.derivation,
199
206
  depends_on: task.depends_on,
207
+ resolved_depends_on: resolveRefEntries(index, task.depends_on),
200
208
  blocked_by: task.blocked_by || [],
209
+ resolved_blocked_by: resolveRefEntries(index, task.blocked_by),
201
210
  context: task.context || [],
202
211
  vcs_refs: (task.vcs_refs || []).map((v) =>
203
212
  typeof v === 'string' ? v : v.type ? `${v.type}:${v.ref}` : v.ref
204
213
  ),
205
214
  plan_ref: task.plan_ref,
215
+ plan_title: resolveRefTitle(index, task.plan_ref),
206
216
  session_ref: task.session_id,
207
217
  notes: task.notes,
208
218
  notes_count: task.notes?.length || 0,
@@ -223,6 +233,37 @@ export function createTasksRoutes(options: TasksRouteOptions) {
223
233
  }
224
234
  )
225
235
 
236
+ .get(
237
+ '/:ref/sessions',
238
+ async ({ params, error: errorResponse, projectContext }) => {
239
+ const ctx = await initContext(projectContext.path);
240
+ const tasks = await loadAllTasks(ctx);
241
+ const items = await loadAllItems(ctx);
242
+ const result = await getRelatedSessionsForTask({
243
+ taskRef: params.ref,
244
+ tasks,
245
+ items,
246
+ sessionsDir: ctx.sessionsDir,
247
+ });
248
+
249
+ if ('error' in result) {
250
+ return errorResponse(404, result.error);
251
+ }
252
+
253
+ return {
254
+ items: result.sessions,
255
+ total: result.sessions.length,
256
+ offset: 0,
257
+ limit: result.sessions.length,
258
+ };
259
+ },
260
+ {
261
+ params: t.Object({
262
+ ref: t.String(),
263
+ }),
264
+ }
265
+ )
266
+
226
267
  // AC: @api-contract ac-6 - Start task
227
268
  .post(
228
269
  '/:ref/start',
@@ -274,12 +315,15 @@ export function createTasksRoutes(options: TasksRouteOptions) {
274
315
  await commitIfShadow(ctx.shadow, `task: start ${params.ref}`);
275
316
 
276
317
  // AC: @api-contract ac-6, @trait-api-endpoint ac-5 - WebSocket broadcast
318
+ // AC: @ui-api-aggregation ac-4 - Include title and old/new status
277
319
  // AC: @multi-directory-daemon ac-18 - Broadcast scoped to request project
278
320
  pubsub.broadcast('tasks:updates', 'task_updated', {
279
321
  ref: params.ref,
280
322
  ulid: task._ulid,
281
323
  action: 'start',
282
- status: 'in_progress',
324
+ title: task.title,
325
+ old_status: task.status,
326
+ new_status: 'in_progress',
283
327
  }, projectContext.path);
284
328
 
285
329
  // AC: @api-contract ac-6 - Return updated task
@@ -346,11 +390,15 @@ export function createTasksRoutes(options: TasksRouteOptions) {
346
390
  await commitIfShadow(ctx.shadow, `task: add note to ${params.ref}`);
347
391
 
348
392
  // AC: @api-contract ac-7 - WebSocket broadcast
393
+ // AC: @ui-api-aggregation ac-4 - Include title (no status change for notes)
349
394
  // AC: @multi-directory-daemon ac-18 - Broadcast scoped to request project
350
395
  pubsub.broadcast('tasks:updates', 'task_updated', {
351
396
  ref: params.ref,
352
397
  ulid: task._ulid,
353
398
  action: 'note_added',
399
+ title: task.title,
400
+ old_status: null,
401
+ new_status: null,
354
402
  note_ulid: note._ulid,
355
403
  }, projectContext.path);
356
404
 
@@ -409,11 +457,14 @@ export function createTasksRoutes(options: TasksRouteOptions) {
409
457
  await syncSpecImplementationStatus(ctx, updatedTask, tasks, items, index);
410
458
  await commitIfShadow(ctx.shadow, `task: submit ${params.ref}`);
411
459
 
460
+ // AC: @ui-api-aggregation ac-4 - Include title and old/new status
412
461
  pubsub.broadcast('tasks:updates', 'task_updated', {
413
462
  ref: params.ref,
414
463
  ulid: task._ulid,
415
464
  action: 'submit',
416
- status: 'pending_review',
465
+ title: task.title,
466
+ old_status: task.status,
467
+ new_status: 'pending_review',
417
468
  }, projectContext.path);
418
469
 
419
470
  return updatedTask;
@@ -456,11 +507,14 @@ export function createTasksRoutes(options: TasksRouteOptions) {
456
507
  await syncSpecImplementationStatus(ctx, updatedTask, tasks, items, index);
457
508
  await commitIfShadow(ctx.shadow, `task: complete ${params.ref}`);
458
509
 
510
+ // AC: @ui-api-aggregation ac-4 - Include title and old/new status
459
511
  pubsub.broadcast('tasks:updates', 'task_updated', {
460
512
  ref: params.ref,
461
513
  ulid: task._ulid,
462
514
  action: 'complete',
463
- status: 'completed',
515
+ title: task.title,
516
+ old_status: task.status,
517
+ new_status: 'completed',
464
518
  }, projectContext.path);
465
519
 
466
520
  return updatedTask;
@@ -508,11 +562,14 @@ export function createTasksRoutes(options: TasksRouteOptions) {
508
562
  await syncSpecImplementationStatus(ctx, updatedTask, tasks, items, index);
509
563
  await commitIfShadow(ctx.shadow, `task: block ${params.ref}`);
510
564
 
565
+ // AC: @ui-api-aggregation ac-4 - Include title and old/new status
511
566
  pubsub.broadcast('tasks:updates', 'task_updated', {
512
567
  ref: params.ref,
513
568
  ulid: task._ulid,
514
569
  action: 'block',
515
- status: 'blocked',
570
+ title: task.title,
571
+ old_status: task.status,
572
+ new_status: 'blocked',
516
573
  }, projectContext.path);
517
574
 
518
575
  return updatedTask;
@@ -25,6 +25,9 @@ import { Elysia, t } from 'elysia';
25
25
  import { ulid } from 'ulidx';
26
26
  import {
27
27
  initContext,
28
+ loadAllTasks,
29
+ loadAllItems,
30
+ ReferenceIndex,
28
31
  loadTriageRecords,
29
32
  saveTriageRecord,
30
33
  findTriageRecordByRef,
@@ -34,6 +37,7 @@ import {
34
37
  getAuthor,
35
38
  type LoadedTriageRecord,
36
39
  } from '../../parser/index.js';
40
+ import { resolveRefEntries } from './ref-resolution.js';
37
41
  import { commitIfShadow } from '../../parser/shadow.js';
38
42
  import { normalizeRefInput } from '../../schema/index.js';
39
43
  import type { TriageAction } from '../../schema/index.js';
@@ -87,8 +91,27 @@ export function createTriageRoutes(options: TriageRouteOptions) {
87
91
 
88
92
  const paginated = filtered.slice(offset, offset + limit);
89
93
 
94
+ // AC: @ui-api-ref-resolution ac-2 - Resolve evidence_refs titles
95
+ const hasEvidenceRefs = paginated.some((r) => r.evidence_refs?.length > 0);
96
+ let refIndex: ReferenceIndex | null = null;
97
+ if (hasEvidenceRefs) {
98
+ try {
99
+ const tasks = await loadAllTasks(ctx);
100
+ const items = await loadAllItems(ctx);
101
+ refIndex = new ReferenceIndex(tasks, items);
102
+ } catch {
103
+ // Non-critical
104
+ }
105
+ }
106
+ const enriched = refIndex
107
+ ? paginated.map((r) => ({
108
+ ...r,
109
+ resolved_evidence_refs: resolveRefEntries(refIndex!, r.evidence_refs),
110
+ }))
111
+ : paginated;
112
+
90
113
  return {
91
- items: paginated,
114
+ items: enriched,
92
115
  total,
93
116
  offset,
94
117
  limit,
@@ -223,6 +246,7 @@ export function createTriageRoutes(options: TriageRouteOptions) {
223
246
  )
224
247
 
225
248
  // GET single triage record
249
+ // AC: @ui-api-ref-resolution ac-2 - Resolve evidence_refs titles
226
250
  .get(
227
251
  '/:ref',
228
252
  async ({ params, error: errorResponse, projectContext }) => {
@@ -240,6 +264,21 @@ export function createTriageRoutes(options: TriageRouteOptions) {
240
264
  });
241
265
  }
242
266
 
267
+ // AC: @ui-api-ref-resolution ac-2 - Resolve evidence_refs
268
+ if (record.evidence_refs?.length > 0) {
269
+ try {
270
+ const tasks = await loadAllTasks(ctx);
271
+ const items = await loadAllItems(ctx);
272
+ const refIndex = new ReferenceIndex(tasks, items);
273
+ return {
274
+ ...record,
275
+ resolved_evidence_refs: resolveRefEntries(refIndex, record.evidence_refs),
276
+ };
277
+ } catch {
278
+ // Non-critical
279
+ }
280
+ }
281
+
243
282
  return record;
244
283
  },
245
284
  {
@@ -16,6 +16,7 @@ import { PubSubManager } from './websocket/pubsub';
16
16
  import { HeartbeatManager } from './websocket/heartbeat';
17
17
  import { WebSocketHandler } from './websocket/handler';
18
18
  import { handleWebSocketClose } from './websocket/lifecycle';
19
+ import { resolveWebSocketProject } from './websocket/project-resolution';
19
20
  import type { ConnectionData, ConnectedEvent } from './websocket/types';
20
21
  import { PidFileManager } from './pid';
21
22
  import { projectContextMiddleware } from './middleware/project-context';
@@ -29,6 +30,10 @@ import { createTriageRoutes } from './routes/triage';
29
30
  import { createAgentDispatchRoutes, getDispatchEngine, stopAllEngines } from './routes/agent-dispatch';
30
31
  import { createSessionRoutes } from './routes/sessions';
31
32
  import { createPlansRoutes } from './routes/plans';
33
+ import { createAggregationRoutes } from './routes/aggregation';
34
+ import { createRefsRoutes } from './routes/refs';
35
+ import { ShadowSyncScheduler } from './shadow-sync';
36
+ import { SessionSyncScheduler } from './session-sync';
32
37
  import { join } from 'path';
33
38
 
34
39
  export interface ServerOptions {
@@ -43,10 +48,9 @@ export interface ServerOptions {
43
48
  * Tries multiple locations in order:
44
49
  * 1. Explicit webUiDir option
45
50
  * 2. WEB_UI_DIR environment variable
46
- * 3. packages/web-ui/build in current working directory (monorepo dev)
47
- * 4. web-ui/build in current working directory
48
- * 5. Bundled dist/web-ui/ relative to this module (npm package installs)
51
+ * 3. Bundled dist/web-ui/ relative to this module (npm package installs)
49
52
  *
53
+ * AC: @daemon-web-ui-bundle ac-4, ac-5
50
54
  * Exported for testing only.
51
55
  */
52
56
  export function resolveWebUiPath(webUiDir?: string): string | null {
@@ -61,20 +65,7 @@ export function resolveWebUiPath(webUiDir?: string): string | null {
61
65
  return envPath;
62
66
  }
63
67
 
64
- // 3. Monorepo development: packages/web-ui/build from cwd
65
- // The daemon is spawned with cwd set to project root
66
- const monorepoPath = join(process.cwd(), 'packages', 'web-ui', 'build');
67
- if (existsSync(monorepoPath)) {
68
- return monorepoPath;
69
- }
70
-
71
- // 4. Alternate location: web-ui/build in cwd
72
- const altPath = join(process.cwd(), 'web-ui', 'build');
73
- if (existsSync(altPath)) {
74
- return altPath;
75
- }
76
-
77
- // 5. Bundled assets: dist/web-ui/ relative to daemon module location
68
+ // 3. Bundled assets: dist/web-ui/ relative to daemon module location
78
69
  // Covers npm package installs where no local web UI build exists.
79
70
  // import.meta.url resolves to dist/daemon/server.js → sibling is dist/web-ui/
80
71
  const selfDir = dirname(fileURLToPath(import.meta.url));
@@ -91,6 +82,66 @@ let pubsubManager: PubSubManager;
91
82
  let heartbeatManager: HeartbeatManager;
92
83
  let wsHandler: WebSocketHandler;
93
84
  let projectManager: import('./project-context').ProjectContextManager | undefined;
85
+ let shadowSyncScheduler: ShadowSyncScheduler | undefined;
86
+ const sessionSyncSchedulers: Map<string, SessionSyncScheduler> = new Map();
87
+
88
+ /**
89
+ * Start a session sync scheduler for a project if it has session branch configured.
90
+ * Safe to call multiple times — skips if scheduler already exists for that project.
91
+ */
92
+ async function startSessionSyncForProject(
93
+ projectPath: string,
94
+ pubsub: PubSubManager,
95
+ ): Promise<void> {
96
+ if (sessionSyncSchedulers.has(projectPath)) {
97
+ return;
98
+ }
99
+
100
+ const { loadProjectConfig } = await import('../parser/config.js');
101
+ const { config } = await loadProjectConfig(projectPath);
102
+ const specDir = join(projectPath, config.shadow.directory);
103
+
104
+ // AC: @multi-directory-daemon ac-31, @manifest-discovery ac-6
105
+ // Use discovery API instead of hardcoding kynetic.yaml
106
+ const { findManifestInDir, readYamlFile } = await import('../parser/yaml.js');
107
+ const manifestPath = await findManifestInDir(specDir);
108
+ if (!manifestPath) {
109
+ // No manifest found — gracefully skip session sync for this project
110
+ return;
111
+ }
112
+ const manifest = await readYamlFile<{ sessions?: { storage?: string; branch?: string } }>(manifestPath);
113
+
114
+ if (manifest?.sessions?.storage === 'branch') {
115
+ const syncInterval = config.shadow.sync_interval;
116
+
117
+ if (syncInterval > 0) {
118
+ const { resolveSessionBranchConfig } = await import('../parser/session-branch.js');
119
+ const sessionConfig = resolveSessionBranchConfig(projectPath, manifest);
120
+
121
+ if (sessionConfig) {
122
+ const scheduler = new SessionSyncScheduler({
123
+ worktreeDir: sessionConfig.worktreeDir,
124
+ intervalSeconds: syncInterval,
125
+ branchName: sessionConfig.branchName,
126
+ pubsub,
127
+ });
128
+ scheduler.start();
129
+ sessionSyncSchedulers.set(projectPath, scheduler);
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Stop session sync scheduler for a specific project.
137
+ */
138
+ function stopSessionSyncForProject(projectPath: string): void {
139
+ const scheduler = sessionSyncSchedulers.get(projectPath);
140
+ if (scheduler) {
141
+ scheduler.stop();
142
+ sessionSyncSchedulers.delete(projectPath);
143
+ }
144
+ }
94
145
 
95
146
  /**
96
147
  * Middleware to enforce localhost-only connections.
@@ -201,10 +252,16 @@ export async function createServer(options: ServerOptions) {
201
252
  // AC-3: Enforce localhost-only connections
202
253
  .onRequest(localhostOnly());
203
254
 
255
+ // Shared callback for all registration paths (middleware, projects API, WebSocket)
256
+ const onProjectRegistered = async (projectPath: string) => {
257
+ await startSessionSyncForProject(projectPath, pubsubManager);
258
+ };
259
+
204
260
  // AC: @multi-directory-daemon ac-1, ac-2, ac-3 - Project context middleware
205
261
  const { manager: projectContextManager, middleware: projectMiddleware } = projectContextMiddleware({
206
262
  startupProject: startupProjectPath,
207
- pubsub: pubsubManager
263
+ pubsub: pubsubManager,
264
+ onProjectRegistered,
208
265
  });
209
266
 
210
267
  // Store manager globally for shutdown
@@ -240,7 +297,13 @@ export async function createServer(options: ServerOptions) {
240
297
  .use(createValidationRoutes())
241
298
 
242
299
  // AC: @multi-directory-daemon ac-28, ac-29, ac-30 - Projects management endpoints
243
- .use(createProjectsRoutes({ projectManager: projectContextManager }))
300
+ .use(createProjectsRoutes({
301
+ projectManager: projectContextManager,
302
+ onProjectRegistered,
303
+ onProjectUnregistered: (projectPath) => {
304
+ stopSessionSyncForProject(projectPath);
305
+ },
306
+ }))
244
307
 
245
308
  // AC: @ui-session-stream ac-1, ac-4 - Session data endpoints
246
309
  .use(createSessionRoutes())
@@ -248,6 +311,12 @@ export async function createServer(options: ServerOptions) {
248
311
  // AC: @ui-plans-view ac-1 - Plans data endpoints
249
312
  .use(createPlansRoutes())
250
313
 
314
+ // AC: @ui-api-aggregation ac-1, ac-2, ac-3 - Aggregation endpoints
315
+ .use(createAggregationRoutes())
316
+
317
+ // AC: @ui-api-ref-resolution ac-4, ac-5 - Lightweight ref index endpoint
318
+ .use(createRefsRoutes())
319
+
251
320
  // AC: @agent-dispatch-engine ac-4 - Agent dispatch API endpoints
252
321
  // AC: @daemon-agent-dispatch ac-3, ac-4 - Pass pubsub for WebSocket broadcast on invocation events
253
322
  .use(createAgentDispatchRoutes({ pubsub: pubsubManager }))
@@ -255,14 +324,6 @@ export async function createServer(options: ServerOptions) {
255
324
  // AC-4: WebSocket endpoint for real-time updates
256
325
  .ws<ConnectionData>('/ws', {
257
326
  beforeHandle({ request, store }) {
258
- // AC: @multi-directory-daemon ac-21, ac-22, ac-23, ac-34 - Extract and validate project binding
259
- // AC: @multi-directory-daemon ac-34 - Browser WebSocket API doesn't support custom headers,
260
- // so we also accept project path as query parameter
261
- const url = new URL(request.url, `http://${request.headers.get('host')}`);
262
- const projectPath = request.headers.get('X-Kspec-Dir')
263
- || url.searchParams.get('project')
264
- || undefined;
265
-
266
327
  // IMPORTANT: Do NOT return a value from ws beforeHandle.
267
328
  // In Elysia 1.4 with derive middleware, returning a value short-circuits
268
329
  // the WebSocket upgrade and sends the value as an HTTP 200 response.
@@ -275,30 +336,15 @@ export async function createServer(options: ServerOptions) {
275
336
  return;
276
337
  }
277
338
 
278
- let projectContext;
279
- if (projectPath) {
280
- // Explicit project specified
281
- try {
282
- projectContext = manager.getProject(projectPath);
283
- } catch {
284
- // AC: @multi-directory-daemon ac-4 - auto-register
285
- projectContext = manager.registerProject(projectPath);
286
- }
287
- } else {
288
- // AC: @multi-directory-daemon ac-22, ac-23 - Use default or reject
289
- try {
290
- projectContext = manager.getProject();
291
- } catch (err: unknown) {
292
- // AC: @multi-directory-daemon ac-23 - Reject when no default
293
- if (err instanceof Error && err.message.includes('No default project configured')) {
294
- throw new Error('No project specified');
295
- }
296
- throw err;
297
- }
298
- }
339
+ const { resolvedPath } = resolveWebSocketProject({
340
+ request,
341
+ manager,
342
+ fallbackPath: startupProjectPath,
343
+ onProjectRegistered,
344
+ });
299
345
 
300
346
  // Store resolved path for open() handler via WeakMap
301
- wsProjectPaths.set(request, projectContext.path);
347
+ wsProjectPaths.set(request, resolvedPath);
302
348
  } catch (err: unknown) {
303
349
  console.error(`[daemon] WebSocket connection rejected: ${err instanceof Error ? err.message : String(err)}`);
304
350
  throw err;
@@ -364,6 +410,7 @@ export async function createServer(options: ServerOptions) {
364
410
  // SPA fallback routes for client-side routing
365
411
  // These catch paths like /tasks, /items, /inbox that don't have static files
366
412
  const spaRoutes = [
413
+ '/',
367
414
  '/tasks', '/tasks/*',
368
415
  '/items', '/items/*',
369
416
  '/inbox',
@@ -416,6 +463,44 @@ export async function createServer(options: ServerOptions) {
416
463
  }
417
464
  }
418
465
 
466
+ // AC: @config-shadow ac-12 - Start periodic shadow sync if remote tracking configured
467
+ if (startupProjectPath) {
468
+ try {
469
+ const { loadProjectConfig } = await import('../parser/config.js');
470
+ const { config } = await loadProjectConfig(startupProjectPath);
471
+ const syncInterval = config.shadow.sync_interval;
472
+ const worktreeDir = join(startupProjectPath, config.shadow.directory);
473
+
474
+ if (syncInterval > 0) {
475
+ shadowSyncScheduler = new ShadowSyncScheduler({
476
+ worktreeDir,
477
+ intervalSeconds: syncInterval,
478
+ shadowOptions: {
479
+ branchName: config.shadow.branch,
480
+ directory: config.shadow.directory,
481
+ remote: config.shadow.remote?.value,
482
+ remoteType: config.shadow.remote?.type,
483
+ },
484
+ pubsub: pubsubManager,
485
+ });
486
+ shadowSyncScheduler.start();
487
+ }
488
+ } catch (error) {
489
+ console.error('[daemon] Failed to initialize shadow sync scheduler:', error);
490
+ }
491
+ }
492
+
493
+ // AC: @session-branch-worktree ac-sync - Start periodic session branch sync if configured
494
+ // Session sync runs independently from kspec-meta sync — failures in one do not affect the other
495
+ if (startupProjectPath) {
496
+ try {
497
+ await startSessionSyncForProject(startupProjectPath, pubsubManager);
498
+ } catch (error) {
499
+ // Session sync init failure does not block daemon startup
500
+ console.error('[daemon] Failed to initialize session sync scheduler:', error);
501
+ }
502
+ }
503
+
419
504
  // AC: @daemon-server ac-13, ac-14 - Start heartbeat monitoring
420
505
  heartbeatManager.start(pubsubManager.getAllConnections());
421
506
 
@@ -427,6 +512,15 @@ export async function createServer(options: ServerOptions) {
427
512
  // Stop heartbeat monitoring
428
513
  heartbeatManager.stop();
429
514
 
515
+ // AC: @config-shadow ac-12 - Stop shadow sync scheduler
516
+ shadowSyncScheduler?.stop();
517
+
518
+ // AC: @session-branch-worktree ac-sync - Stop all session sync schedulers
519
+ for (const scheduler of sessionSyncSchedulers.values()) {
520
+ scheduler.stop();
521
+ }
522
+ sessionSyncSchedulers.clear();
523
+
430
524
  // AC: @agent-dispatch-engine ac-11 - Stop all dispatch engines before shutting down
431
525
  await stopAllEngines();
432
526
 
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Re-export SessionSyncScheduler from its canonical location in src/parser/.
3
+ * The daemon server.ts imports from this file; the actual implementation
4
+ * lives in src/parser/session-sync-scheduler.ts so that both daemon runtime
5
+ * (via dist/parser/) and vitest tests can import the same production code.
6
+ *
7
+ * AC: @session-branch-worktree ac-sync
8
+ */
9
+
10
+ export { SessionSyncScheduler } from '../parser/session-sync-scheduler.js';
11
+ export type { SessionSyncSchedulerOptions, SessionSyncPubSub } from '../parser/session-sync-scheduler.js';
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Re-export ShadowSyncScheduler from its canonical location in src/parser/.
3
+ * The daemon server.ts imports from this file; the actual implementation
4
+ * lives in src/parser/shadow-sync-scheduler.ts so that both daemon runtime
5
+ * (via dist/parser/) and vitest tests can import the same production code.
6
+ *
7
+ * AC: @config-shadow ac-12
8
+ */
9
+
10
+ export { ShadowSyncScheduler } from '../parser/shadow-sync-scheduler.js';
11
+ export type { ShadowSyncSchedulerOptions, ShadowSyncPubSub } from '../parser/shadow-sync-scheduler.js';