@shepai/cli 1.72.9-pr220.ce0911d → 1.72.9-pr220.f17b60a

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 (232) hide show
  1. package/dist/src/presentation/web/app/build-feature-node-data.d.ts.map +1 -1
  2. package/dist/src/presentation/web/app/build-feature-node-data.js +2 -26
  3. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
  4. package/dist/src/presentation/web/app/build-graph-nodes.js +2 -26
  5. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.d.ts.map +1 -1
  6. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.js +0 -2
  7. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts +2 -0
  8. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts.map +1 -1
  9. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.js +11 -11
  10. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  11. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +17 -31
  12. package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts +0 -1
  13. package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts.map +1 -1
  14. package/dist/src/presentation/web/components/common/control-center-drawer/index.js +0 -1
  15. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts +25 -0
  16. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
  17. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +45 -2
  18. package/dist/src/presentation/web/components/common/index.d.ts +1 -1
  19. package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/index.js +1 -1
  21. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  22. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +20 -30
  23. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
  24. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +2 -13
  25. package/dist/src/presentation/web/hooks/use-agent-events.d.ts.map +1 -1
  26. package/dist/src/presentation/web/hooks/use-agent-events.js +6 -3
  27. package/dist/tsconfig.build.tsbuildinfo +1 -1
  28. package/package.json +1 -1
  29. package/web/.next/BUILD_ID +1 -1
  30. package/web/.next/build-manifest.json +2 -2
  31. package/web/.next/cache/.previewinfo +1 -1
  32. package/web/.next/cache/.rscinfo +1 -1
  33. package/web/.next/cache/.tsbuildinfo +1 -1
  34. package/web/.next/cache/config.json +3 -3
  35. package/web/.next/fallback-build-manifest.json +2 -2
  36. package/web/.next/prerender-manifest.json +3 -3
  37. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +15 -15
  38. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  39. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  40. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +18 -18
  41. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  42. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  43. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +13 -13
  44. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  45. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  46. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +15 -15
  47. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  48. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  49. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +18 -18
  50. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  51. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  52. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +13 -13
  53. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  54. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  55. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +13 -13
  56. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  57. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/_global-error.html +2 -2
  59. package/web/.next/server/app/_global-error.rsc +1 -1
  60. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  62. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  66. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  67. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  68. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  69. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  71. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  72. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  73. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  74. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  75. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  76. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  77. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +1 -1
  78. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +1 -1
  79. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +1 -1
  80. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +1 -1
  81. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  82. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  83. package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
  84. package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js.map +1 -1
  85. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  86. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  87. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
  88. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -1
  89. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  90. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js +1 -1
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -1
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  98. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  99. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  100. package/web/.next/server/chunks/ssr/_250a63ae._.js +1 -1
  101. package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -1
  102. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  103. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  104. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  105. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  106. package/web/.next/server/chunks/ssr/{_1fae710b._.js → _8e87c87b._.js} +2 -2
  107. package/web/.next/server/chunks/ssr/{_1fae710b._.js.map → _8e87c87b._.js.map} +1 -1
  108. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  109. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  110. package/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js +1 -1
  111. package/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js.map +1 -1
  112. package/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js +1 -1
  113. package/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js.map +1 -1
  114. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +1 -1
  115. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +1 -1
  116. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  117. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  118. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  119. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  120. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +2 -2
  121. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js.map +1 -1
  122. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +2 -2
  123. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js.map +1 -1
  124. package/web/.next/server/pages/500.html +2 -2
  125. package/web/.next/server/server-reference-manifest.js +1 -1
  126. package/web/.next/server/server-reference-manifest.json +21 -21
  127. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  128. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  129. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  130. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +15 -15
  131. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  132. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  133. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +18 -18
  134. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  135. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  136. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +13 -13
  137. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  138. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  139. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +15 -15
  140. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  141. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  142. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +18 -18
  143. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  144. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  145. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +13 -13
  146. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  147. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  148. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +13 -13
  149. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  150. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  151. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  152. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  153. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  154. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  155. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  156. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  157. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  158. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  159. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  160. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  161. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  162. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  163. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  164. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  165. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  166. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  167. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  168. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  169. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +1 -1
  170. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +1 -1
  171. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  172. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
  173. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  174. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
  175. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  176. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  177. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  178. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js +1 -1
  179. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  180. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  181. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_250a63ae._.js +1 -1
  182. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  183. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  184. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_1fae710b._.js → _8e87c87b._.js} +2 -2
  185. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  186. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js +1 -1
  187. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js +1 -1
  188. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +1 -1
  189. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  190. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  191. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +2 -2
  192. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +2 -2
  193. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  194. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  195. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +21 -21
  196. package/web/.next/standalone/src/presentation/web/app/build-feature-node-data.ts +3 -30
  197. package/web/.next/standalone/src/presentation/web/app/build-graph-nodes.ts +3 -30
  198. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +0 -2
  199. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/drawer-view.ts +12 -13
  200. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +21 -41
  201. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/index.ts +0 -1
  202. package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +63 -2
  203. package/web/.next/standalone/src/presentation/web/components/common/index.ts +1 -6
  204. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +37 -43
  205. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +1 -18
  206. package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +7 -3
  207. package/web/.next/static/chunks/0ffccd7be73305c8.css +2 -0
  208. package/web/.next/static/chunks/76827713cb2b7333.js +1 -0
  209. package/web/.next/static/chunks/{ce35cf93d71d1c1e.js → 792aac476adb5875.js} +1 -1
  210. package/web/.next/static/chunks/{f3d1b4bf5f83a7bb.js → 7c8adcfd920a8f74.js} +1 -1
  211. package/web/.next/static/chunks/{28ab1bfc2f001573.js → 83463b63971f5723.js} +1 -1
  212. package/web/.next/static/chunks/{145335ccbec019cd.js → 98ca891a5c156aa5.js} +3 -3
  213. package/web/.next/static/chunks/{cd256f1719637fae.js → 9b1770f05f1d95e5.js} +1 -1
  214. package/web/.next/static/chunks/{d8b549dcd668b553.js → a7f52757dff0cea0.js} +1 -1
  215. package/web/.next/static/chunks/b6becf0de992842a.js +1 -0
  216. package/web/.next/static/chunks/{5c1f5a37231b6108.js → d5e95c4482029a39.js} +1 -1
  217. package/web/.next/trace +1 -1
  218. package/web/.next/trace-build +1 -1
  219. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts +0 -12
  220. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts.map +0 -1
  221. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js +0 -337
  222. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts +0 -33
  223. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts.map +0 -1
  224. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.js +0 -214
  225. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.tsx +0 -293
  226. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx +0 -745
  227. package/web/.next/static/chunks/02f29f2542ce0260.js +0 -1
  228. package/web/.next/static/chunks/87bd8e61a05cb052.css +0 -2
  229. package/web/.next/static/chunks/da76b4d6b8a4cdb0.js +0 -1
  230. /package/web/.next/static/{DSNQz6BAG_GWooVc5rWTS → eg0FTlsA4z_7CXbFfMgAr}/_buildManifest.js +0 -0
  231. /package/web/.next/static/{DSNQz6BAG_GWooVc5rWTS → eg0FTlsA4z_7CXbFfMgAr}/_clientMiddlewareManifest.json +0 -0
  232. /package/web/.next/static/{DSNQz6BAG_GWooVc5rWTS → eg0FTlsA4z_7CXbFfMgAr}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"build-feature-node-data.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-feature-node-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAK9E,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,kCAAkC,CAAC;AAsB/F;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,GAAG,eAAe,CA+B5F"}
1
+ {"version":3,"file":"build-feature-node-data.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-feature-node-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAM9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,GAAG,eAAe,CAuB5F"}
@@ -1,38 +1,14 @@
1
- import { deriveNodeState, deriveProgress, } from '../components/common/feature-node/derive-feature-state.js';
2
- /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
3
- const lifecycleMap = {
4
- Requirements: 'requirements',
5
- Research: 'research',
6
- Implementation: 'implementation',
7
- Review: 'review',
8
- 'Deploy & QA': 'deploy',
9
- Maintain: 'maintain',
10
- };
11
- /** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
12
- const nodeToLifecyclePhase = {
13
- analyze: 'requirements',
14
- requirements: 'requirements',
15
- research: 'research',
16
- plan: 'implementation',
17
- implement: 'implementation',
18
- merge: 'review',
19
- };
1
+ import { deriveNodeState, deriveProgress, deriveLifecycle, } from '../components/common/feature-node/derive-feature-state.js';
20
2
  /**
21
3
  * Builds a FeatureNodeData object from a Feature entity and optional AgentRun.
22
4
  * This is the single-feature version of the logic in `buildGraphNodes`.
23
5
  */
24
6
  export function buildFeatureNodeData(feature, run) {
25
- const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
26
- const lifecycle = run?.status === 'completed'
27
- ? 'maintain'
28
- : ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
29
- lifecycleMap[feature.lifecycle] ??
30
- 'requirements');
31
7
  return {
32
8
  name: feature.name,
33
9
  description: feature.description ?? feature.slug,
34
10
  featureId: feature.id,
35
- lifecycle,
11
+ lifecycle: deriveLifecycle(feature, run),
36
12
  repositoryPath: feature.repositoryPath,
37
13
  branch: feature.branch,
38
14
  specPath: feature.specPath,
@@ -1 +1 @@
1
- {"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAK1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAuB1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,GACjC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAiE5C"}
1
+ {"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAM1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAG1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,GACjC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAiE5C"}
@@ -1,22 +1,4 @@
1
- import { deriveNodeState, deriveProgress, } from '../components/common/feature-node/derive-feature-state.js';
2
- /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
3
- const lifecycleMap = {
4
- Requirements: 'requirements',
5
- Research: 'research',
6
- Implementation: 'implementation',
7
- Review: 'review',
8
- 'Deploy & QA': 'deploy',
9
- Maintain: 'maintain',
10
- };
11
- /** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
12
- const nodeToLifecyclePhase = {
13
- analyze: 'requirements',
14
- requirements: 'requirements',
15
- research: 'research',
16
- plan: 'implementation',
17
- implement: 'implementation',
18
- merge: 'review',
19
- };
1
+ import { deriveNodeState, deriveProgress, deriveLifecycle, } from '../components/common/feature-node/derive-feature-state.js';
20
2
  /**
21
3
  * Builds React Flow nodes and edges from persisted repositories and features.
22
4
  *
@@ -95,12 +77,6 @@ function appendFeatureNodes(repoFeatures, repoNodeId, allFeaturesWithRuns, nodes
95
77
  return aTime - bTime;
96
78
  });
97
79
  sorted.forEach(({ feature, run }) => {
98
- const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
99
- const lifecycle = run?.status === 'completed'
100
- ? 'maintain'
101
- : ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
102
- lifecycleMap[feature.lifecycle] ??
103
- 'requirements');
104
80
  // Resolve blockedBy display name from parent feature
105
81
  let blockedBy;
106
82
  if (feature.parentId && feature.lifecycle === 'Blocked') {
@@ -113,7 +89,7 @@ function appendFeatureNodes(repoFeatures, repoNodeId, allFeaturesWithRuns, nodes
113
89
  name: feature.name,
114
90
  description: feature.description ?? feature.slug,
115
91
  featureId: feature.id,
116
- lifecycle,
92
+ lifecycle: deriveLifecycle(feature, run),
117
93
  repositoryPath: feature.repositoryPath,
118
94
  branch: feature.branch,
119
95
  specPath: feature.specPath,
@@ -1 +1 @@
1
- {"version":3,"file":"create-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAAc,EACd,eAAe,EACf,QAAQ,EACR,gBAAgB,GACjB,EAAE,uBAAuB,2CA6EzB"}
1
+ {"version":3,"file":"create-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAAc,EACd,eAAe,EACf,QAAQ,EACR,gBAAgB,GACjB,EAAE,uBAAuB,2CA2EzB"}
@@ -38,7 +38,6 @@ export function CreateDrawerClient({ repositoryPath, initialParentId, features,
38
38
  .then((result) => {
39
39
  if (result.error) {
40
40
  toast.error(result.error);
41
- window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
42
41
  return;
43
42
  }
44
43
  // Dispatch event with real feature ID so control center adds it to featureMap
@@ -54,7 +53,6 @@ export function CreateDrawerClient({ repositoryPath, initialParentId, features,
54
53
  })
55
54
  .catch(() => {
56
55
  toast.error('Failed to create feature');
57
- window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
58
56
  setIsSubmitting(false);
59
57
  });
60
58
  }, [router]);
@@ -40,6 +40,8 @@ export type DrawerView =
40
40
  type: 'repository';
41
41
  data: RepositoryNodeData;
42
42
  };
43
+ /** Derives the feature-specific view type from node lifecycle + state. */
44
+ export declare function deriveFeatureViewType(node: FeatureNodeData): 'feature' | 'prd-review' | 'tech-review' | 'merge-review';
43
45
  /**
44
46
  * Derives the active DrawerView from control-center state.
45
47
  * Priority: feature-create > selected-node (prd/tech/merge/feature) > repository
@@ -1 +1 @@
1
- {"version":3,"file":"drawer-view.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/drawer-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE5E;;;GAGG;AACH,MAAM,MAAM,UAAU;AACpB,gGAAgG;AAC9F;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AAC5C,mEAAmE;GACjE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AAC/C,yEAAyE;GACvE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AAChD,8DAA8D;GAC5D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AACjD,4BAA4B;GAC1B;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AACH,8BAA8B;GAC5B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAErD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAChD,GAAG,UAAU,GAAG,IAAI,CAgCpB"}
1
+ {"version":3,"file":"drawer-view.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/drawer-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAE5E;;;GAGG;AACH,MAAM,MAAM,UAAU;AACpB,gGAAgG;AAC9F;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AAC5C,mEAAmE;GACjE;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AAC/C,yEAAyE;GACvE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AAChD,8DAA8D;GAC5D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE;AACjD,4BAA4B;GAC1B;IACE,IAAI,EAAE,gBAAgB,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AACH,8BAA8B;GAC5B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAErD,0EAA0E;AAC1E,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,eAAe,GACpB,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,cAAc,CAM3D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAChD,GAAG,UAAU,GAAG,IAAI,CAoBpB"}
@@ -1,3 +1,13 @@
1
+ /** Derives the feature-specific view type from node lifecycle + state. */
2
+ export function deriveFeatureViewType(node) {
3
+ if (node.lifecycle === 'requirements' && node.state === 'action-required')
4
+ return 'prd-review';
5
+ if (node.lifecycle === 'implementation' && node.state === 'action-required')
6
+ return 'tech-review';
7
+ if (node.lifecycle === 'review' && (node.state === 'action-required' || node.state === 'error'))
8
+ return 'merge-review';
9
+ return 'feature';
10
+ }
1
11
  /**
2
12
  * Derives the active DrawerView from control-center state.
3
13
  * Priority: feature-create > selected-node (prd/tech/merge/feature) > repository
@@ -13,17 +23,7 @@ export function computeDrawerView({ selectedNode, isCreateDrawerOpen, pendingRep
13
23
  };
14
24
  }
15
25
  if (selectedNode) {
16
- if (selectedNode.lifecycle === 'requirements' && selectedNode.state === 'action-required') {
17
- return { type: 'prd-review', node: selectedNode };
18
- }
19
- if (selectedNode.lifecycle === 'implementation' && selectedNode.state === 'action-required') {
20
- return { type: 'tech-review', node: selectedNode };
21
- }
22
- if (selectedNode.lifecycle === 'review' &&
23
- (selectedNode.state === 'action-required' || selectedNode.state === 'error')) {
24
- return { type: 'merge-review', node: selectedNode };
25
- }
26
- return { type: 'feature', node: selectedNode };
26
+ return { type: deriveFeatureViewType(selectedNode), node: selectedNode };
27
27
  }
28
28
  if (selectedRepoNode) {
29
29
  return { type: 'repository', data: selectedRepoNode };
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AA2DA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,wBAAwB,2CAonBlF"}
1
+ {"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAyDA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,wBAAwB,2CA6mBlF"}
@@ -4,7 +4,7 @@ import { useState, useCallback, useEffect, useRef } from 'react';
4
4
  import { useRouter, usePathname } from 'next/navigation';
5
5
  import { toast } from 'sonner';
6
6
  import { Loader2, Trash2, ExternalLink, GitCommitHorizontal, Play, Square } from 'lucide-react';
7
- import { PrStatus, NotificationEventType } from '../../../../../../packages/core/src/domain/generated/output.js';
7
+ import { PrStatus } from '../../../../../../packages/core/src/domain/generated/output.js';
8
8
  import { approveFeature } from '../../../app/actions/approve-feature.js';
9
9
  import { rejectFeature } from '../../../app/actions/reject-feature.js';
10
10
  import { getFeatureArtifact } from '../../../app/actions/get-feature-artifact.js';
@@ -34,7 +34,8 @@ import { TechReviewTabs } from '../../common/tech-review-tabs/index.js';
34
34
  import { MergeReview } from '../../common/merge-review/index.js';
35
35
  import { featureNodeStateConfig, lifecycleDisplayLabels } from '../../common/feature-node/index.js';
36
36
  import { useFeatureActions } from '../../common/feature-drawer/use-feature-actions.js';
37
- import { mapEventTypeToState, mapPhaseNameToLifecycle, } from '../../common/feature-node/derive-feature-state.js';
37
+ import { resolveSseEventUpdates } from '../../common/feature-node/derive-feature-state.js';
38
+ import { deriveFeatureViewType } from './drawer-view.js';
38
39
  export function FeatureDrawerClient({ view: initialView }) {
39
40
  const router = useRouter();
40
41
  const deleteSound = useSoundAction('delete');
@@ -59,28 +60,15 @@ export function FeatureDrawerClient({ view: initialView }) {
59
60
  return;
60
61
  const newEvents = events.slice(processedCountRef.current);
61
62
  processedCountRef.current = events.length;
62
- // When WaitingApproval and PhaseCompleted arrive in the same poll batch,
63
- // PhaseCompleted must be fully suppressed (both state AND lifecycle). Without this,
64
- // a phase-timing PhaseCompleted (e.g. phaseName='research') can regress the lifecycle
65
- // that WaitingApproval already set correctly (e.g. to 'implementation' for plan gate).
66
- const waitingApprovalInBatch = newEvents.some((e) => e.featureId === featureNode.featureId &&
67
- e.eventType === NotificationEventType.WaitingApproval);
68
- for (const event of newEvents) {
69
- if (event.featureId !== featureNode.featureId)
63
+ for (const update of resolveSseEventUpdates(newEvents)) {
64
+ if (update.featureId !== featureNode.featureId)
70
65
  continue;
71
- const isSuppressedPhaseCompleted = event.eventType === NotificationEventType.PhaseCompleted && waitingApprovalInBatch;
72
- const newState = isSuppressedPhaseCompleted
73
- ? undefined
74
- : mapEventTypeToState(event.eventType);
75
- const newLifecycle = isSuppressedPhaseCompleted
76
- ? undefined
77
- : mapPhaseNameToLifecycle(event.phaseName);
78
66
  // Trigger a server refresh to get the latest drawer view,
79
67
  // but skip when the user has unsaved changes or a rejection is in-flight
80
68
  // to avoid the refresh interfering with the reject handler's navigation.
81
69
  if (!isDirtyRef.current && !isRejectingRef.current)
82
70
  router.refresh();
83
- if (newState !== undefined || newLifecycle !== undefined) {
71
+ if (update.state !== undefined || update.lifecycle !== undefined) {
84
72
  // Optimistically update the node data AND re-derive the view type so the
85
73
  // drawer switches immediately (e.g. prd-review → feature when agent resumes)
86
74
  // without waiting for the router.refresh() round-trip.
@@ -92,10 +80,10 @@ export function FeatureDrawerClient({ view: initialView }) {
92
80
  return prev;
93
81
  const updatedNode = {
94
82
  ...prev.node,
95
- ...(newState !== undefined && { state: newState }),
96
- ...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
83
+ ...(update.state !== undefined && { state: update.state }),
84
+ ...(update.lifecycle !== undefined && { lifecycle: update.lifecycle }),
97
85
  };
98
- return { ...prev, type: deriveViewType(updatedNode), node: updatedNode };
86
+ return { ...prev, type: deriveFeatureViewType(updatedNode), node: updatedNode };
99
87
  });
100
88
  }
101
89
  }
@@ -317,6 +305,10 @@ export function FeatureDrawerClient({ view: initialView }) {
317
305
  }
318
306
  setChatInput('');
319
307
  toast.success(`${label} approved — agent resuming`);
308
+ // Optimistically update canvas node before SSE arrives (~500ms delay)
309
+ window.dispatchEvent(new CustomEvent('shep:feature-approved', {
310
+ detail: { featureId: reviewNode.featureId },
311
+ }));
320
312
  onClose();
321
313
  }, [reviewNode, onClose]);
322
314
  const handlePrdApprove = useCallback(async (_actionId) => {
@@ -341,6 +333,10 @@ export function FeatureDrawerClient({ view: initialView }) {
341
333
  }
342
334
  setChatInput('');
343
335
  toast.success('Requirements approved — agent resuming');
336
+ // Optimistically update canvas node before SSE arrives (~500ms delay)
337
+ window.dispatchEvent(new CustomEvent('shep:feature-approved', {
338
+ detail: { featureId: view.node.featureId },
339
+ }));
344
340
  setPrdSelections({});
345
341
  onClose();
346
342
  }, [view, prdData, prdSelections, onClose]);
@@ -433,13 +429,3 @@ function FeatureDetails({ data }) {
433
429
  function DetailRow({ label, value }) {
434
430
  return (_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: label }), _jsx("span", { className: "text-sm", children: value })] }));
435
431
  }
436
- /** Mirrors computeDrawerView logic — derives view type from live node data. */
437
- function deriveViewType(node) {
438
- if (node.lifecycle === 'requirements' && node.state === 'action-required')
439
- return 'prd-review';
440
- if (node.lifecycle === 'implementation' && node.state === 'action-required')
441
- return 'tech-review';
442
- if (node.lifecycle === 'review' && (node.state === 'action-required' || node.state === 'error'))
443
- return 'merge-review';
444
- return 'feature';
445
- }
@@ -1,3 +1,2 @@
1
- export { ControlCenterDrawer, type ControlCenterDrawerProps } from './control-center-drawer.js';
2
1
  export { computeDrawerView, type DrawerView } from './drawer-view.js';
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -1,2 +1 @@
1
- export { ControlCenterDrawer } from './control-center-drawer.js';
2
1
  export { computeDrawerView } from './drawer-view.js';
@@ -28,5 +28,30 @@ export declare function deriveNodeState(feature: Feature, agentRun?: AgentRun |
28
28
  export declare function deriveProgress(feature: Feature): number;
29
29
  /** Maps a NotificationEventType to the corresponding FeatureNodeState for optimistic UI updates. */
30
30
  export declare function mapEventTypeToState(eventType: NotificationEventType): FeatureNodeState;
31
+ /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase. */
32
+ export declare const sdlcLifecycleMap: Record<string, FeatureLifecyclePhase>;
33
+ /**
34
+ * Derives the UI lifecycle phase from a Feature + AgentRun.
35
+ * Shared by build-feature-node-data.ts and build-graph-nodes.ts.
36
+ */
37
+ export declare function deriveLifecycle(feature: Feature, run: AgentRun | null): FeatureLifecyclePhase;
38
+ export interface SseEventUpdate {
39
+ featureId: string;
40
+ state: FeatureNodeState | undefined;
41
+ lifecycle: FeatureLifecyclePhase | undefined;
42
+ eventType: NotificationEventType;
43
+ phaseName?: string;
44
+ }
45
+ /**
46
+ * Resolves state/lifecycle updates from a batch of SSE events, applying
47
+ * the WaitingApproval batch-suppression rule: when WaitingApproval and
48
+ * PhaseCompleted arrive in the same batch for a feature, PhaseCompleted
49
+ * is fully suppressed to prevent lifecycle regression.
50
+ */
51
+ export declare function resolveSseEventUpdates(events: readonly {
52
+ featureId: string;
53
+ eventType: NotificationEventType;
54
+ phaseName?: string;
55
+ }[]): SseEventUpdate[];
31
56
  export declare function mapPhaseNameToLifecycle(phaseName: string | undefined): FeatureLifecyclePhase | undefined;
32
57
  //# sourceMappingURL=derive-feature-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"derive-feature-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/derive-feature-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAE3F;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,gBAAgB,CA4C9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAYvD;AAED,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,qBAAqB,GAAG,gBAAgB,CAkBtF;AAcD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,qBAAqB,GAAG,SAAS,CAGnC"}
1
+ {"version":3,"file":"derive-feature-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/derive-feature-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAE3F;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,gBAAgB,CA4C9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAYvD;AAED,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,qBAAqB,GAAG,gBAAgB,CAkBtF;AAED,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAOlE,CAAC;AAcF;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,GAAG,qBAAqB,CAQ7F;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACpC,SAAS,EAAE,qBAAqB,GAAG,SAAS,CAAC;IAC7C,SAAS,EAAE,qBAAqB,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,qBAAqB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAC7F,cAAc,EAAE,CAmBlB;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,qBAAqB,GAAG,SAAS,CAGnC"}
@@ -31,7 +31,7 @@ export function deriveNodeState(feature, agentRun) {
31
31
  case AgentRunStatus.cancelled:
32
32
  return 'blocked';
33
33
  case AgentRunStatus.completed:
34
- return feature.lifecycle === SdlcLifecycle.Maintain ? 'done' : 'done';
34
+ return 'done';
35
35
  case AgentRunStatus.running:
36
36
  case AgentRunStatus.pending:
37
37
  return 'running';
@@ -93,7 +93,16 @@ export function mapEventTypeToState(eventType) {
93
93
  return 'action-required';
94
94
  }
95
95
  }
96
- /** Maps an SSE event phaseName to a FeatureLifecyclePhase. Mirrors page.tsx nodeToLifecyclePhase. */
96
+ /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase. */
97
+ export const sdlcLifecycleMap = {
98
+ Requirements: 'requirements',
99
+ Research: 'research',
100
+ Implementation: 'implementation',
101
+ Review: 'review',
102
+ 'Deploy & QA': 'deploy',
103
+ Maintain: 'maintain',
104
+ };
105
+ /** Map agent graph node names (from agent_run.result or SSE phaseName) to UI lifecycle phases. */
97
106
  const phaseNameToLifecycle = {
98
107
  analyze: 'requirements',
99
108
  requirements: 'requirements',
@@ -104,6 +113,40 @@ const phaseNameToLifecycle = {
104
113
  maintain: 'maintain',
105
114
  blocked: 'requirements',
106
115
  };
116
+ /**
117
+ * Derives the UI lifecycle phase from a Feature + AgentRun.
118
+ * Shared by build-feature-node-data.ts and build-graph-nodes.ts.
119
+ */
120
+ export function deriveLifecycle(feature, run) {
121
+ if (run?.status === 'completed')
122
+ return 'maintain';
123
+ const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
124
+ return ((agentNode ? phaseNameToLifecycle[agentNode] : undefined) ??
125
+ sdlcLifecycleMap[feature.lifecycle] ??
126
+ 'requirements');
127
+ }
128
+ /**
129
+ * Resolves state/lifecycle updates from a batch of SSE events, applying
130
+ * the WaitingApproval batch-suppression rule: when WaitingApproval and
131
+ * PhaseCompleted arrive in the same batch for a feature, PhaseCompleted
132
+ * is fully suppressed to prevent lifecycle regression.
133
+ */
134
+ export function resolveSseEventUpdates(events) {
135
+ const waitingApprovalFeatures = new Set(events
136
+ .filter((e) => e.eventType === NotificationEventType.WaitingApproval)
137
+ .map((e) => e.featureId));
138
+ return events.map((event) => {
139
+ const isSuppressed = event.eventType === NotificationEventType.PhaseCompleted &&
140
+ waitingApprovalFeatures.has(event.featureId);
141
+ return {
142
+ featureId: event.featureId,
143
+ state: isSuppressed ? undefined : mapEventTypeToState(event.eventType),
144
+ lifecycle: isSuppressed ? undefined : mapPhaseNameToLifecycle(event.phaseName),
145
+ eventType: event.eventType,
146
+ phaseName: event.phaseName,
147
+ };
148
+ });
149
+ }
107
150
  export function mapPhaseNameToLifecycle(phaseName) {
108
151
  if (!phaseName)
109
152
  return undefined;
@@ -1,4 +1,4 @@
1
- export { ControlCenterDrawer, type ControlCenterDrawerProps, computeDrawerView, type DrawerView, } from './control-center-drawer/index.js';
1
+ export { computeDrawerView, type DrawerView } from './control-center-drawer/index.js';
2
2
  export { AddRepositoryButton } from './add-repository-button/index.js';
3
3
  export { ElapsedTime, formatElapsed } from './elapsed-time/index.js';
4
4
  export { EmptyState, type EmptyStateProps } from './empty-state/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,UAAU,GAChB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/components/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,KAAK,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
@@ -1,4 +1,4 @@
1
- export { ControlCenterDrawer, computeDrawerView, } from './control-center-drawer/index.js';
1
+ export { computeDrawerView } from './control-center-drawer/index.js';
2
2
  export { AddRepositoryButton } from './add-repository-button/index.js';
3
3
  export { ElapsedTime, formatElapsed } from './elapsed-time/index.js';
4
4
  export { EmptyState } from './empty-state/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAYjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAG7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAOD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAoVpB"}
1
+ {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAWjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAG7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAOD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CA+UpB"}
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useCallback, useEffect, useRef } from 'react';
2
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
3
3
  import { useRouter } from 'next/navigation';
4
4
  import { toast } from 'sonner';
5
5
  import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS, } from '../../../lib/layout-with-dagre.js';
@@ -9,8 +9,7 @@ import { deleteRepository } from '../../../app/actions/delete-repository.js';
9
9
  import { getFeatureMetadata } from '../../../app/actions/get-feature-metadata.js';
10
10
  import { useAgentEventsContext } from '../../../hooks/agent-events-provider.js';
11
11
  import { useSoundAction } from '../../../hooks/use-sound-action.js';
12
- import { mapEventTypeToState, mapPhaseNameToLifecycle, } from '../../common/feature-node/derive-feature-state.js';
13
- import { NotificationEventType } from '../../../../../../packages/core/src/domain/generated/output.js';
12
+ import { mapEventTypeToState, resolveSseEventUpdates, } from '../../common/feature-node/derive-feature-state.js';
14
13
  import { useGraphState } from '../../../hooks/use-graph-state.js';
15
14
  /** Must match the message string emitted by the SSE route in agent-events/route.ts */
16
15
  const METADATA_UPDATED_MESSAGE = 'Feature metadata updated';
@@ -22,18 +21,18 @@ export function useControlCenterState(initialNodes, initialEdges) {
22
21
  const { nodes, edges, reconcile, updateFeature, addPendingFeature, removeFeature, restoreFeature, addRepository: addRepositoryToMap, removeRepository, replaceRepository, getFeatureRepositoryPath, getRepositoryData, setCallbacks, } = useGraphState(initialNodes, initialEdges);
23
22
  // Sync server props into domain Maps when initialNodes/initialEdges change.
24
23
  // Keyed by a stable string so we don't re-reconcile on every render.
25
- const initialNodeKey = initialNodes
24
+ const initialNodeKey = useMemo(() => initialNodes
26
25
  .map((n) => n.id)
27
26
  .sort()
28
- .join(',');
29
- const initialDataKey = initialNodes
27
+ .join(','), [initialNodes]);
28
+ const initialDataKey = useMemo(() => initialNodes
30
29
  .filter((n) => n.type === 'featureNode')
31
30
  .map((n) => {
32
31
  const d = n.data;
33
32
  return `${n.id}:${d.state}:${d.lifecycle}`;
34
33
  })
35
34
  .sort()
36
- .join(',');
35
+ .join(','), [initialNodes]);
37
36
  const prevReconcileKey = useRef('');
38
37
  useEffect(() => {
39
38
  const key = `${initialNodeKey}|${initialDataKey}`;
@@ -82,33 +81,24 @@ export function useControlCenterState(initialNodes, initialEdges) {
82
81
  return;
83
82
  const newEvents = events.slice(processedEventCountRef.current);
84
83
  processedEventCountRef.current = events.length;
85
- // When WaitingApproval and PhaseCompleted arrive in the same poll batch for a feature,
86
- // PhaseCompleted must be fully suppressed (both state AND lifecycle). Without this,
87
- // a phase-timing PhaseCompleted (e.g. phaseName='research') can regress the lifecycle
88
- // that WaitingApproval already set correctly (e.g. to 'implementation' for plan gate).
89
- // When PhaseCompleted arrives WITHOUT WaitingApproval (e.g. after approval), we allow
90
- // it to update both state and lifecycle as a fallback for any missed AgentStarted event.
91
- const waitingApprovalFeatures = new Set(newEvents
92
- .filter((e) => e.eventType === NotificationEventType.WaitingApproval)
93
- .map((e) => e.featureId));
94
- for (const event of newEvents) {
95
- const isSuppressedPhaseCompleted = event.eventType === NotificationEventType.PhaseCompleted &&
96
- waitingApprovalFeatures.has(event.featureId);
97
- const newState = isSuppressedPhaseCompleted
98
- ? undefined
99
- : mapEventTypeToState(event.eventType);
100
- const newLifecycle = isSuppressedPhaseCompleted
101
- ? undefined
102
- : mapPhaseNameToLifecycle(event.phaseName);
103
- const nodeId = `feat-${event.featureId}`;
104
- if (newState !== undefined || newLifecycle !== undefined) {
105
- updateFeature(nodeId, {
106
- ...(newState !== undefined && { state: newState }),
107
- ...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
84
+ for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {
85
+ if (state !== undefined || lifecycle !== undefined) {
86
+ updateFeature(`feat-${featureId}`, {
87
+ ...(state !== undefined && { state }),
88
+ ...(lifecycle !== undefined && { lifecycle }),
108
89
  });
109
90
  }
110
91
  }
111
92
  }, [events, updateFeature]);
93
+ // Listen for optimistic approval events from the drawer (fires before SSE arrives)
94
+ useEffect(() => {
95
+ const handler = (e) => {
96
+ const { featureId } = e.detail;
97
+ updateFeature(`feat-${featureId}`, { state: 'running' });
98
+ };
99
+ window.addEventListener('shep:feature-approved', handler);
100
+ return () => window.removeEventListener('shep:feature-approved', handler);
101
+ }, [updateFeature]);
112
102
  // Separate effect: fetch metadata (name + description) when SSE reports it changed
113
103
  const metadataFetchedRef = useRef(new Set());
114
104
  const processedMetadataCountRef = useRef(0);
@@ -1 +1 @@
1
- {"version":3,"file":"features-canvas.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/features-canvas/features-canvas.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKlE,OAAO,KAAK,EAAE,eAAe,EAAmB,MAAM,kCAAkC,CAAC;AAEzF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAG9E,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAElE,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAChE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACtE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAChD,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,KAAK,EACL,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE,mBAAmB,2CAmGrB"}
1
+ {"version":3,"file":"features-canvas.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/features-canvas/features-canvas.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKlE,OAAO,KAAK,EAAE,eAAe,EAAmB,MAAM,kCAAkC,CAAC;AAEzF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAG9E,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAElE,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAChE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IACtE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAChD,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC9B;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,KAAK,EACL,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,EACX,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE,mBAAmB,2CAkFrB"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useMemo, useCallback } from 'react';
3
+ import { useMemo } from 'react';
4
4
  import { ReactFlow, Background, Controls } from '@xyflow/react';
5
5
  import { Plus } from 'lucide-react';
6
6
  import { Button } from '../../ui/button.js';
@@ -16,17 +16,6 @@ export function FeaturesCanvas({ nodes, edges, selectedFeatureId, onNodesChange,
16
16
  const edgeTypes = useMemo(() => ({
17
17
  dependencyEdge: DependencyEdge,
18
18
  }), []);
19
- // Prevent a feature from having more than one source repository
20
- const isValidConnection = useCallback((connection) => {
21
- const sourceNode = nodes.find((n) => n.id === connection.source);
22
- if (sourceNode?.type !== 'repositoryNode')
23
- return true;
24
- const targetAlreadyHasRepo = edges.some((e) => {
25
- const edgeSourceNode = nodes.find((n) => n.id === e.source);
26
- return edgeSourceNode?.type === 'repositoryNode' && e.target === connection.target;
27
- });
28
- return !targetAlreadyHasRepo;
29
- }, [nodes, edges]);
30
19
  // Callbacks and showHandles are already injected into node.data by deriveGraph.
31
20
  // Only selectedFeatureId highlighting needs to be applied here.
32
21
  const enrichedNodes = useMemo(() => selectedFeatureId == null
@@ -41,5 +30,5 @@ export function FeaturesCanvas({ nodes, edges, selectedFeatureId, onNodesChange,
41
30
  }
42
31
  return (_jsx("div", { "data-testid": "features-canvas-empty", children: _jsx(EmptyState, { title: "No features yet", description: "Get started by creating your first feature.", action: _jsxs(Button, { onClick: onAddFeature, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), "New Feature"] }) }) }));
43
32
  }
44
- return (_jsx("div", { "data-testid": "features-canvas", "data-no-drawer-close": true, className: "pointer-events-auto h-full w-full", children: _jsxs(ReactFlow, { nodes: enrichedNodes, edges: edges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, isValidConnection: isValidConnection, onConnect: onConnect, onNodesChange: onNodesChange, onNodeClick: onNodeClick, onPaneClick: onPaneClick, onMoveStart: onCanvasDrag, defaultViewport: { x: 30, y: 30, zoom: 0.85 }, nodesDraggable: false, nodesConnectable: false, elementsSelectable: false, children: [_jsx(Background, {}), _jsx(Controls, {}), toolbar] }) }));
33
+ return (_jsx("div", { "data-testid": "features-canvas", "data-no-drawer-close": true, className: "pointer-events-auto h-full w-full", children: _jsxs(ReactFlow, { nodes: enrichedNodes, edges: edges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, onConnect: onConnect, onNodesChange: onNodesChange, onNodeClick: onNodeClick, onPaneClick: onPaneClick, onMoveStart: onCanvasDrag, defaultViewport: { x: 30, y: 30, zoom: 0.85 }, nodesDraggable: false, nodesConnectable: false, elementsSelectable: false, children: [_jsx(Background, {}), _jsx(Controls, {}), toolbar] }) }));
45
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-agent-events.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-agent-events.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAID;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,oBAAoB,CA2GpF"}
1
+ {"version":3,"file":"use-agent-events.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-agent-events.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,YAAY,GAAG,cAAc,CAAC;AAE3E,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,SAAS,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAID;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,oBAAoB,CA+GpF"}
@@ -75,10 +75,13 @@ export function useAgentEvents(options) {
75
75
  subscribeToWorker(sw);
76
76
  }
77
77
  else {
78
- sw.addEventListener('statechange', () => {
79
- if (sw.state === 'activated')
78
+ const onStateChange = () => {
79
+ if (sw.state === 'activated') {
80
+ sw.removeEventListener('statechange', onStateChange);
80
81
  subscribeToWorker(sw);
81
- });
82
+ }
83
+ };
84
+ sw.addEventListener('statechange', onStateChange);
82
85
  }
83
86
  })
84
87
  .catch(() => {