@shepai/cli 1.72.9 → 1.73.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 (440) hide show
  1. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +20 -1
  2. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +68 -41
  4. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +10 -0
  5. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
  6. package/dist/packages/core/src/infrastructure/services/notifications/notification.service.d.ts.map +1 -1
  7. package/dist/packages/core/src/infrastructure/services/notifications/notification.service.js +2 -4
  8. package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
  9. package/dist/src/presentation/web/app/actions/create-feature.js +20 -2
  10. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts +10 -0
  11. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts.map +1 -0
  12. package/dist/src/presentation/web/app/actions/get-feature-metadata.js +14 -0
  13. package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
  14. package/dist/src/presentation/web/app/api/agent-events/route.js +15 -0
  15. package/dist/src/presentation/web/app/build-feature-node-data.d.ts.map +1 -1
  16. package/dist/src/presentation/web/app/build-feature-node-data.js +2 -26
  17. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
  18. package/dist/src/presentation/web/app/build-graph-nodes.js +2 -26
  19. package/dist/src/presentation/web/app/layout.js +1 -1
  20. package/dist/src/presentation/web/components/common/add-repository-button/add-repository-button.d.ts.map +1 -0
  21. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts +2 -0
  22. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts.map +1 -0
  23. package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/index.js +0 -1
  24. package/dist/src/presentation/web/components/common/add-repository-button/pick-folder.d.ts.map +1 -0
  25. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.js +13 -18
  27. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts +2 -0
  28. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts.map +1 -1
  29. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.js +11 -11
  30. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  31. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +74 -144
  32. package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts +0 -1
  33. package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts.map +1 -1
  34. package/dist/src/presentation/web/components/common/control-center-drawer/index.js +0 -1
  35. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts +13 -0
  36. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts.map +1 -0
  37. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.js +46 -0
  38. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map +1 -1
  39. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.js +7 -10
  40. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts +25 -0
  41. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
  42. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +45 -2
  43. package/dist/src/presentation/web/components/common/index.d.ts +2 -3
  44. package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
  45. package/dist/src/presentation/web/components/common/index.js +2 -3
  46. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
  47. package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.d.ts.map +1 -1
  48. package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.js +14 -39
  49. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.d.ts +1 -3
  50. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.d.ts.map +1 -1
  51. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.js +3 -7
  52. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.d.ts +0 -1
  53. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.d.ts.map +1 -1
  54. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.js +0 -11
  55. package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.js +1 -1
  56. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  57. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +31 -14
  58. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts +0 -11
  59. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
  60. package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +2 -37
  61. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +8 -0
  62. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  63. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +160 -354
  64. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts +2 -10
  65. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
  66. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +11 -54
  67. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts.map +1 -1
  68. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.js +0 -46
  69. package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +1 -1
  70. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts +1 -3
  71. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts.map +1 -1
  72. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.js +2 -2
  73. package/dist/src/presentation/web/components/ui/alert-dialog.d.ts.map +1 -1
  74. package/dist/src/presentation/web/components/ui/alert-dialog.js +2 -2
  75. package/dist/src/presentation/web/components/ui/dialog.d.ts.map +1 -1
  76. package/dist/src/presentation/web/components/ui/dialog.js +2 -2
  77. package/dist/src/presentation/web/components/ui/scroll-area.js +1 -1
  78. package/dist/src/presentation/web/hooks/agent-events-provider.d.ts.map +1 -1
  79. package/dist/src/presentation/web/hooks/agent-events-provider.js +3 -2
  80. package/dist/src/presentation/web/hooks/use-agent-events.d.ts.map +1 -1
  81. package/dist/src/presentation/web/hooks/use-agent-events.js +18 -5
  82. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  83. package/dist/src/presentation/web/hooks/use-deploy-action.js +8 -3
  84. package/dist/src/presentation/web/hooks/use-graph-state.d.ts +42 -0
  85. package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -0
  86. package/dist/src/presentation/web/hooks/use-graph-state.js +257 -0
  87. package/dist/src/presentation/web/hooks/use-notifications.d.ts +1 -5
  88. package/dist/src/presentation/web/hooks/use-notifications.d.ts.map +1 -1
  89. package/dist/src/presentation/web/hooks/use-notifications.js +1 -26
  90. package/dist/src/presentation/web/hooks/use-notifications.stories.d.ts.map +1 -1
  91. package/dist/src/presentation/web/hooks/use-notifications.stories.js +28 -38
  92. package/dist/src/presentation/web/lib/derive-graph.d.ts +52 -0
  93. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -0
  94. package/dist/src/presentation/web/lib/derive-graph.js +126 -0
  95. package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
  96. package/dist/src/presentation/web/lib/layout-with-dagre.js +1 -2
  97. package/dist/src/presentation/web/lib/logger.d.ts +7 -0
  98. package/dist/src/presentation/web/lib/logger.d.ts.map +1 -0
  99. package/dist/src/presentation/web/lib/logger.js +11 -0
  100. package/dist/tsconfig.build.tsbuildinfo +1 -1
  101. package/package.json +1 -1
  102. package/web/.next/BUILD_ID +1 -1
  103. package/web/.next/build-manifest.json +2 -2
  104. package/web/.next/cache/.previewinfo +1 -1
  105. package/web/.next/cache/.rscinfo +1 -1
  106. package/web/.next/cache/.tsbuildinfo +1 -1
  107. package/web/.next/cache/config.json +3 -3
  108. package/web/.next/fallback-build-manifest.json +2 -2
  109. package/web/.next/prerender-manifest.json +3 -3
  110. package/web/.next/required-server-files.js +1 -1
  111. package/web/.next/required-server-files.json +1 -1
  112. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +34 -34
  113. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
  114. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  115. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  116. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +40 -40
  117. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  118. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  119. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  120. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  121. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
  122. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  123. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  124. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +34 -34
  125. package/web/.next/server/app/(dashboard)/create/page.js +3 -3
  126. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  127. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  128. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +40 -40
  129. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  130. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  131. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  132. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +30 -30
  133. package/web/.next/server/app/(dashboard)/page.js +3 -3
  134. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  135. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  136. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  137. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
  138. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  139. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  140. package/web/.next/server/app/_global-error.html +2 -2
  141. package/web/.next/server/app/_global-error.rsc +1 -1
  142. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  143. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  144. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  145. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  146. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  147. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  148. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  149. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  150. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  151. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  152. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  153. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  154. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  155. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  156. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  157. package/web/.next/server/app/version/page.js.nft.json +1 -1
  158. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  159. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  160. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  161. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  162. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  163. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +3 -0
  164. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +1 -0
  165. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
  166. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +1 -0
  167. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  168. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  169. package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
  170. package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js.map +1 -1
  171. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  172. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  173. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  174. package/web/.next/server/chunks/ssr/{[root-of-the-server]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
  175. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -0
  176. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  177. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  178. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  179. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js.map +1 -1
  180. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  181. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  182. package/web/.next/server/chunks/ssr/{[root-of-the-server]__e5e09f72._.js → [root-of-the-server]__94a6d275._.js} +2 -2
  183. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -0
  184. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  185. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  186. package/web/.next/server/chunks/ssr/_07c2a32a._.js +1 -1
  187. package/web/.next/server/chunks/ssr/_07c2a32a._.js.map +1 -1
  188. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  189. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  190. package/web/.next/server/chunks/ssr/_250a63ae._.js +3 -0
  191. package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -0
  192. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  193. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  194. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  195. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  196. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  197. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  198. package/web/.next/server/chunks/ssr/_dee726e3._.js +6 -0
  199. package/web/.next/server/chunks/ssr/_dee726e3._.js.map +1 -0
  200. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5ea689db._.js → server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
  201. package/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js.map → src_presentation_web_2b91e4ec._.js.map} +1 -1
  202. package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js → src_presentation_web_5bcc1537._.js} +2 -2
  203. package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js.map → src_presentation_web_5bcc1537._.js.map} +1 -1
  204. package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
  205. package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js.map +1 -1
  206. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +3 -0
  207. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +1 -0
  208. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +3 -0
  209. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -0
  210. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  211. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  212. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  213. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  214. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +8 -0
  215. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js.map +1 -0
  216. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
  217. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js.map +1 -0
  218. package/web/.next/server/pages/500.html +2 -2
  219. package/web/.next/server/server-reference-manifest.js +1 -1
  220. package/web/.next/server/server-reference-manifest.json +142 -142
  221. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  222. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  223. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  224. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  225. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +34 -34
  226. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
  227. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  228. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  229. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +40 -40
  230. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  231. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  232. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  233. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  234. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
  235. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  236. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  237. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +34 -34
  238. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +3 -3
  239. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  240. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  241. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +40 -40
  242. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  243. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  244. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  245. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +30 -30
  246. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +3 -3
  247. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  248. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  249. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  250. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
  251. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  252. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  253. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  254. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  255. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  256. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  257. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  258. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  259. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  260. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  261. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  262. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  263. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  264. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  265. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  266. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  267. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  268. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  269. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  270. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  271. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  272. package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  273. 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
  274. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +3 -0
  275. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
  276. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  277. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
  278. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  279. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  280. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{[root-of-the-server]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
  281. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  282. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  283. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  284. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{[root-of-the-server]__e5e09f72._.js → [root-of-the-server]__94a6d275._.js} +2 -2
  285. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  286. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_07c2a32a._.js +1 -1
  287. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  288. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_250a63ae._.js +3 -0
  289. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  290. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  291. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  292. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_dee726e3._.js +6 -0
  293. package/web/.next/{server/chunks/ssr/src_presentation_web_7188a290._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
  294. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js → src_presentation_web_5bcc1537._.js} +2 -2
  295. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
  296. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +3 -0
  297. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +3 -0
  298. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  299. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  300. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +8 -0
  301. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
  302. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  303. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  304. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +142 -142
  305. package/web/.next/standalone/src/presentation/web/CLAUDE.md +77 -33
  306. package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +27 -2
  307. package/web/.next/standalone/src/presentation/web/app/actions/get-feature-metadata.ts +18 -0
  308. package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +17 -0
  309. package/web/.next/standalone/src/presentation/web/app/build-feature-node-data.ts +3 -30
  310. package/web/.next/standalone/src/presentation/web/app/build-graph-nodes.ts +3 -30
  311. package/web/.next/standalone/src/presentation/web/app/layout.tsx +1 -1
  312. package/web/.next/standalone/src/presentation/web/components/common/add-repository-button/index.ts +1 -0
  313. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +15 -21
  314. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/drawer-view.ts +12 -13
  315. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +105 -141
  316. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/index.ts +0 -1
  317. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.ts +56 -0
  318. package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/use-feature-actions.ts +6 -7
  319. package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +63 -2
  320. package/web/.next/standalone/src/presentation/web/components/common/index.ts +2 -12
  321. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +2 -2
  322. package/web/.next/standalone/src/presentation/web/components/common/repository-node/use-repository-actions.ts +29 -54
  323. package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.tsx +0 -13
  324. package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.tsx +1 -45
  325. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-empty-state.tsx +1 -1
  326. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +43 -36
  327. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +2 -41
  328. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +203 -440
  329. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx +0 -48
  330. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +13 -76
  331. package/web/.next/standalone/src/presentation/web/components/layouts/app-shell/app-shell.tsx +1 -1
  332. package/web/.next/standalone/src/presentation/web/components/layouts/app-sidebar/app-sidebar.tsx +2 -14
  333. package/web/.next/standalone/src/presentation/web/components/ui/alert-dialog.tsx +2 -5
  334. package/web/.next/standalone/src/presentation/web/components/ui/dialog.tsx +2 -5
  335. package/web/.next/standalone/src/presentation/web/components/ui/scroll-area.tsx +1 -1
  336. package/web/.next/standalone/src/presentation/web/hooks/agent-events-provider.tsx +7 -2
  337. package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +19 -5
  338. package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +11 -3
  339. package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +376 -0
  340. package/web/.next/standalone/src/presentation/web/hooks/use-notifications.stories.tsx +2 -30
  341. package/web/.next/standalone/src/presentation/web/hooks/use-notifications.ts +2 -36
  342. package/web/.next/standalone/src/presentation/web/lib/derive-graph.ts +178 -0
  343. package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +1 -2
  344. package/web/.next/standalone/src/presentation/web/lib/logger.ts +12 -0
  345. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  346. package/web/.next/static/chunks/0ffccd7be73305c8.css +2 -0
  347. package/web/.next/static/chunks/15ceb197ec725da2.js +1 -0
  348. package/web/.next/static/chunks/3f205fd6adbfd20a.js +7 -0
  349. package/web/.next/static/chunks/{d4492cd12fdf0891.js → 6691ad02dc1efd1f.js} +1 -1
  350. package/web/.next/static/chunks/{64850cf4081a2950.js → 7bff5fbcbf157df5.js} +1 -1
  351. package/web/.next/static/chunks/8959112899679e25.js +1 -0
  352. package/web/.next/static/chunks/{c83897e9213881bf.js → 8f508ef906cbf0fa.js} +1 -1
  353. package/web/.next/static/chunks/9cbb42a6bd516d3b.js +1 -0
  354. package/web/.next/static/chunks/c5603ed8a95d460d.js +1 -0
  355. package/web/.next/static/chunks/cb41849bcfaa304e.js +1 -0
  356. package/web/.next/static/chunks/d7e0cd32364a8d76.js +1 -0
  357. package/web/.next/static/chunks/e69d79bd3f19dec8.js +4 -0
  358. package/web/.next/trace +1 -1
  359. package/web/.next/trace-build +1 -1
  360. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-button.d.ts.map +0 -1
  361. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts +0 -7
  362. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts.map +0 -1
  363. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.js +0 -1
  364. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts +0 -6
  365. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts.map +0 -1
  366. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.js +0 -23
  367. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts +0 -10
  368. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts.map +0 -1
  369. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.js +0 -33
  370. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts +0 -4
  371. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts.map +0 -1
  372. package/dist/src/presentation/web/components/common/add-repository-node/pick-folder.d.ts.map +0 -1
  373. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts +0 -12
  374. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts.map +0 -1
  375. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js +0 -337
  376. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts +0 -33
  377. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts.map +0 -1
  378. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.js +0 -214
  379. package/dist/src/presentation/web/components/common/notification-permission-banner/index.d.ts +0 -2
  380. package/dist/src/presentation/web/components/common/notification-permission-banner/index.d.ts.map +0 -1
  381. package/dist/src/presentation/web/components/common/notification-permission-banner/index.js +0 -1
  382. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.d.ts +0 -2
  383. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.d.ts.map +0 -1
  384. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.js +0 -33
  385. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.d.ts +0 -6
  386. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.d.ts.map +0 -1
  387. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.js +0 -24
  388. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
  389. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js.map +0 -1
  390. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
  391. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js.map +0 -1
  392. package/web/.next/server/chunks/ssr/[root-of-the-server]__cbae9863._.js.map +0 -1
  393. package/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js.map +0 -1
  394. package/web/.next/server/chunks/ssr/_38d24563._.js +0 -6
  395. package/web/.next/server/chunks/ssr/_38d24563._.js.map +0 -1
  396. package/web/.next/server/chunks/ssr/_6e08ce21._.js +0 -3
  397. package/web/.next/server/chunks/ssr/_6e08ce21._.js.map +0 -1
  398. package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
  399. package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js.map +0 -1
  400. package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
  401. package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js.map +0 -1
  402. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js +0 -3
  403. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js.map +0 -1
  404. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +0 -3
  405. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js.map +0 -1
  406. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
  407. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
  408. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_38d24563._.js +0 -6
  409. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6e08ce21._.js +0 -3
  410. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
  411. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
  412. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js +0 -3
  413. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +0 -3
  414. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node-config.ts +0 -8
  415. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.tsx +0 -70
  416. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.tsx +0 -49
  417. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/index.ts +0 -3
  418. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.tsx +0 -293
  419. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx +0 -745
  420. package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/index.ts +0 -1
  421. package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.tsx +0 -52
  422. package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.tsx +0 -55
  423. package/web/.next/static/chunks/0c54314c8c9c9739.js +0 -7
  424. package/web/.next/static/chunks/10cd08dae8c210ff.js +0 -1
  425. package/web/.next/static/chunks/15bf7ee1da91eb46.js +0 -4
  426. package/web/.next/static/chunks/3c79bca4d3f18f66.js +0 -1
  427. package/web/.next/static/chunks/67f2a7a5e8dc358a.css +0 -2
  428. package/web/.next/static/chunks/6cc840197626843b.js +0 -1
  429. package/web/.next/static/chunks/e3239b6c18cf8b96.js +0 -1
  430. package/web/.next/static/chunks/e9cc53ce8a7bdea6.js +0 -1
  431. package/web/.next/static/chunks/ef916db8c537211a.js +0 -1
  432. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.d.ts +0 -0
  433. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.js +0 -0
  434. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.d.ts +0 -0
  435. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.js +0 -0
  436. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.tsx +0 -0
  437. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.ts +0 -0
  438. /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 1AvkeBASQdtzZt9cm9UYg}/_buildManifest.js +0 -0
  439. /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 1AvkeBASQdtzZt9cm9UYg}/_clientMiddlewareManifest.json +0 -0
  440. /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 1AvkeBASQdtzZt9cm9UYg}/_ssgManifest.js +0 -0
@@ -53,11 +53,10 @@ import { useFeatureActions } from '@/components/common/feature-drawer/use-featur
53
53
  import type { PrdQuestionnaireData } from '@/components/common/prd-questionnaire';
54
54
  import type { TechDecisionsReviewData } from '@/components/common/tech-decisions-review';
55
55
  import type { MergeReviewData } from '@/components/common/merge-review';
56
- import {
57
- mapEventTypeToState,
58
- mapPhaseNameToLifecycle,
59
- } from '@/components/common/feature-node/derive-feature-state';
56
+ import { resolveSseEventUpdates } from '@/components/common/feature-node/derive-feature-state';
57
+ import { deriveFeatureViewType } from './drawer-view';
60
58
  import type { DrawerView } from './drawer-view';
59
+ import { useArtifactFetch } from './use-artifact-fetch';
61
60
 
62
61
  export interface FeatureDrawerClientProps {
63
62
  view: DrawerView;
@@ -89,39 +88,43 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
89
88
  const processedCountRef = useRef(0);
90
89
 
91
90
  useEffect(() => {
91
+ // Clamp cursor if events were pruned
92
+ if (processedCountRef.current > events.length) {
93
+ processedCountRef.current = 0;
94
+ }
92
95
  if (!featureNode || events.length <= processedCountRef.current) return;
93
96
 
94
97
  const newEvents = events.slice(processedCountRef.current);
95
98
  processedCountRef.current = events.length;
96
99
 
97
- for (const event of newEvents) {
98
- if (event.featureId !== featureNode.featureId) continue;
99
- const newState = mapEventTypeToState(event.eventType);
100
- const newLifecycle = mapPhaseNameToLifecycle(event.phaseName);
100
+ for (const update of resolveSseEventUpdates(newEvents)) {
101
+ if (update.featureId !== featureNode.featureId) continue;
101
102
 
102
103
  // Trigger a server refresh to get the latest drawer view,
103
- // but skip when the user has unsaved changes or a rejection is in-flight
104
- // to avoid the refresh interfering with the reject handler's navigation.
105
- if (!isDirtyRef.current && !isRejectingRef.current) router.refresh();
106
-
107
- // Optimistically update the node data for immediate UI feedback
108
- setView((prev) => {
109
- if (
110
- prev.type !== 'feature' &&
111
- prev.type !== 'prd-review' &&
112
- prev.type !== 'tech-review' &&
113
- prev.type !== 'merge-review'
114
- )
115
- return prev;
116
- return {
117
- ...prev,
118
- node: {
104
+ // but skip when the drawer is closed, the user has unsaved changes,
105
+ // or a rejection is in-flight to avoid unnecessary refreshes.
106
+ if (isOpenRef.current && !isDirtyRef.current && !isRejectingRef.current) router.refresh();
107
+
108
+ if (update.state !== undefined || update.lifecycle !== undefined) {
109
+ // Optimistically update the node data AND re-derive the view type so the
110
+ // drawer switches immediately (e.g. prd-review → feature when agent resumes)
111
+ // without waiting for the router.refresh() round-trip.
112
+ setView((prev) => {
113
+ if (
114
+ prev.type !== 'feature' &&
115
+ prev.type !== 'prd-review' &&
116
+ prev.type !== 'tech-review' &&
117
+ prev.type !== 'merge-review'
118
+ )
119
+ return prev;
120
+ const updatedNode = {
119
121
  ...prev.node,
120
- state: newState,
121
- ...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
122
- },
123
- };
124
- });
122
+ ...(update.state !== undefined && { state: update.state }),
123
+ ...(update.lifecycle !== undefined && { lifecycle: update.lifecycle }),
124
+ };
125
+ return { ...prev, type: deriveFeatureViewType(updatedNode), node: updatedNode };
126
+ });
127
+ }
125
128
  }
126
129
  }, [events, featureNode, router]);
127
130
 
@@ -131,6 +134,8 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
131
134
  // the close animation when the path no longer matches a feature route.
132
135
  const pathname = usePathname();
133
136
  const isOpen = pathname.startsWith('/feature/');
137
+ const isOpenRef = useRef(isOpen);
138
+ isOpenRef.current = isOpen;
134
139
 
135
140
  const onClose = useCallback(() => {
136
141
  router.push('/');
@@ -143,21 +148,17 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
143
148
  const [prdData, setPrdData] = useState<PrdQuestionnaireData | null>(null);
144
149
  const [prdSelections, setPrdSelections] = useState<Record<string, string>>({});
145
150
  const [prdDefaultSelections, setPrdDefaultSelections] = useState<Record<string, string>>({});
146
- const [isLoadingPrd, setIsLoadingPrd] = useState(false);
147
151
 
148
152
  // ── Tech state ─────────────────────────────────────────────────────────
149
153
  const [techData, setTechData] = useState<TechDecisionsReviewData | null>(null);
150
- const [isLoadingTech, setIsLoadingTech] = useState(false);
151
154
 
152
155
  // ── Product decisions state (for tech review Product tab) ─────────────
153
156
  const [techProductData, setTechProductData] = useState<
154
157
  ProductDecisionsSummaryData | null | undefined
155
158
  >(undefined);
156
- const [isLoadingTechProduct, setIsLoadingTechProduct] = useState(false);
157
159
 
158
160
  // ── Merge state ────────────────────────────────────────────────────────
159
161
  const [mergeData, setMergeData] = useState<MergeReviewData | null>(null);
160
- const [isLoadingMerge, setIsLoadingMerge] = useState(false);
161
162
 
162
163
  // ── Delete state ───────────────────────────────────────────────────────
163
164
  const [isDeleting, setIsDeleting] = useState(false);
@@ -175,120 +176,71 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
175
176
  // ── Data fetching ─────────────────────────────────────────────────────
176
177
 
177
178
  const prdFeatureId = view.type === 'prd-review' ? view.node.featureId : null;
178
- useEffect(() => {
179
- setPrdSelections({});
180
- setPrdDefaultSelections({});
181
- setPrdData(null);
182
- if (!prdFeatureId) return;
183
-
184
- let cancelled = false;
185
- setIsLoadingPrd(true);
186
- getFeatureArtifact(prdFeatureId)
187
- .then((result) => {
188
- if (cancelled) return;
189
- if (result.error) {
190
- toast.error(result.error);
191
- return;
192
- }
193
- if (result.questionnaire) {
194
- setPrdData(result.questionnaire);
195
- const defaults: Record<string, string> = {};
196
- for (const q of result.questionnaire.questions) {
197
- const recommended = q.options.find((o) => o.recommended);
198
- if (recommended) defaults[q.id] = recommended.id;
199
- }
200
- setPrdSelections(defaults);
201
- setPrdDefaultSelections(defaults);
179
+ const isLoadingPrd = useArtifactFetch(
180
+ prdFeatureId,
181
+ getFeatureArtifact,
182
+ (result) => {
183
+ if (result.error) {
184
+ toast.error(result.error);
185
+ return;
186
+ }
187
+ if (result.questionnaire) {
188
+ setPrdData(result.questionnaire);
189
+ const defaults: Record<string, string> = {};
190
+ for (const q of result.questionnaire.questions) {
191
+ const recommended = q.options.find((o) => o.recommended);
192
+ if (recommended) defaults[q.id] = recommended.id;
202
193
  }
203
- })
204
- .catch(() => {
205
- if (!cancelled) toast.error('Failed to load questionnaire');
206
- })
207
- .finally(() => {
208
- if (!cancelled) setIsLoadingPrd(false);
209
- });
210
- return () => {
211
- cancelled = true;
212
- };
213
- }, [prdFeatureId]);
194
+ setPrdSelections(defaults);
195
+ setPrdDefaultSelections(defaults);
196
+ }
197
+ },
198
+ () => {
199
+ setPrdSelections({});
200
+ setPrdDefaultSelections({});
201
+ setPrdData(null);
202
+ },
203
+ 'Failed to load questionnaire'
204
+ );
214
205
 
215
206
  const techFeatureId = view.type === 'tech-review' ? view.node.featureId : null;
216
- useEffect(() => {
217
- setTechData(null);
218
- if (!techFeatureId) return;
219
-
220
- let cancelled = false;
221
- setIsLoadingTech(true);
222
- getResearchArtifact(techFeatureId)
223
- .then((result) => {
224
- if (cancelled) return;
225
- if (result.error) {
226
- toast.error(result.error);
227
- return;
228
- }
229
- if (result.techDecisions) setTechData(result.techDecisions);
230
- })
231
- .catch(() => {
232
- if (!cancelled) toast.error('Failed to load tech decisions');
233
- })
234
- .finally(() => {
235
- if (!cancelled) setIsLoadingTech(false);
236
- });
237
- return () => {
238
- cancelled = true;
239
- };
240
- }, [techFeatureId]);
207
+ const isLoadingTech = useArtifactFetch(
208
+ techFeatureId,
209
+ getResearchArtifact,
210
+ (result) => {
211
+ if (result.error) {
212
+ toast.error(result.error);
213
+ return;
214
+ }
215
+ if (result.techDecisions) setTechData(result.techDecisions);
216
+ },
217
+ () => setTechData(null),
218
+ 'Failed to load tech decisions'
219
+ );
241
220
 
242
- useEffect(() => {
243
- setTechProductData(undefined);
244
- if (!techFeatureId) return;
245
-
246
- let cancelled = false;
247
- setIsLoadingTechProduct(true);
248
- getFeatureArtifact(techFeatureId)
249
- .then((result) => {
250
- if (cancelled) return;
251
- if (result.productDecisions) {
252
- setTechProductData(result.productDecisions);
253
- }
254
- })
255
- .catch(() => {
256
- // Silent failure — the product tab is supplementary
257
- })
258
- .finally(() => {
259
- if (!cancelled) setIsLoadingTechProduct(false);
260
- });
261
- return () => {
262
- cancelled = true;
263
- };
264
- }, [techFeatureId]);
221
+ const isLoadingTechProduct = useArtifactFetch(
222
+ techFeatureId,
223
+ getFeatureArtifact,
224
+ (result) => {
225
+ if (result.productDecisions) setTechProductData(result.productDecisions);
226
+ },
227
+ () => setTechProductData(undefined)
228
+ );
265
229
 
266
230
  const mergeFeatureId = view.type === 'merge-review' ? view.node.featureId : null;
267
- useEffect(() => {
268
- setMergeData(null);
269
- if (!mergeFeatureId) return;
270
-
271
- let cancelled = false;
272
- setIsLoadingMerge(true);
273
- getMergeReviewData(mergeFeatureId)
274
- .then((result) => {
275
- if (cancelled) return;
276
- if ('error' in result) {
277
- toast.error(result.error);
278
- return;
279
- }
280
- setMergeData(result);
281
- })
282
- .catch(() => {
283
- if (!cancelled) toast.error('Failed to load merge review data');
284
- })
285
- .finally(() => {
286
- if (!cancelled) setIsLoadingMerge(false);
287
- });
288
- return () => {
289
- cancelled = true;
290
- };
291
- }, [mergeFeatureId]);
231
+ const isLoadingMerge = useArtifactFetch(
232
+ mergeFeatureId,
233
+ getMergeReviewData,
234
+ (result) => {
235
+ if ('error' in result) {
236
+ toast.error(result.error);
237
+ return;
238
+ }
239
+ setMergeData(result);
240
+ },
241
+ () => setMergeData(null),
242
+ 'Failed to load merge review data'
243
+ );
292
244
 
293
245
  // ── Close guard ──────────────────────────────────────────────────────
294
246
  const isChatDirty = chatInput.trim().length > 0;
@@ -368,6 +320,12 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
368
320
  }
369
321
  setChatInput('');
370
322
  toast.success(`${label} approved — agent resuming`);
323
+ // Optimistically update canvas node before SSE arrives (~500ms delay)
324
+ window.dispatchEvent(
325
+ new CustomEvent('shep:feature-approved', {
326
+ detail: { featureId: reviewNode.featureId },
327
+ })
328
+ );
371
329
  onClose();
372
330
  },
373
331
  [reviewNode, onClose]
@@ -395,6 +353,12 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
395
353
  }
396
354
  setChatInput('');
397
355
  toast.success('Requirements approved — agent resuming');
356
+ // Optimistically update canvas node before SSE arrives (~500ms delay)
357
+ window.dispatchEvent(
358
+ new CustomEvent('shep:feature-approved', {
359
+ detail: { featureId: view.node.featureId },
360
+ })
361
+ );
398
362
  setPrdSelections({});
399
363
  onClose();
400
364
  },
@@ -1,2 +1 @@
1
- export { ControlCenterDrawer, type ControlCenterDrawerProps } from './control-center-drawer';
2
1
  export { computeDrawerView, type DrawerView } from './drawer-view';
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useRef } from 'react';
4
+ import { toast } from 'sonner';
5
+
6
+ /**
7
+ * Generic hook for fetching drawer artifact data when a feature ID changes.
8
+ * Handles loading state, cancellation on unmount/re-fetch, and error toasting.
9
+ *
10
+ * @param featureId - The feature ID to fetch for, or null to reset.
11
+ * @param fetcher - Async function that fetches the artifact data.
12
+ * @param onSuccess - Called with the fetch result when successful and not cancelled.
13
+ * @param onReset - Called immediately when featureId changes (before fetching).
14
+ * @param errorMessage - Optional toast message shown on fetch failure.
15
+ * @returns Whether the fetch is currently in progress.
16
+ */
17
+ export function useArtifactFetch<TResult>(
18
+ featureId: string | null,
19
+ fetcher: (id: string) => Promise<TResult>,
20
+ onSuccess: (result: TResult) => void,
21
+ onReset: () => void,
22
+ errorMessage?: string
23
+ ): boolean {
24
+ const [isLoading, setIsLoading] = useState(false);
25
+
26
+ // Use refs to avoid stale callbacks in the effect without triggering re-runs.
27
+ const onSuccessRef = useRef(onSuccess);
28
+ const onResetRef = useRef(onReset);
29
+ onSuccessRef.current = onSuccess;
30
+ onResetRef.current = onReset;
31
+
32
+ useEffect(() => {
33
+ onResetRef.current();
34
+ if (!featureId) return;
35
+
36
+ let cancelled = false;
37
+ setIsLoading(true);
38
+
39
+ fetcher(featureId)
40
+ .then((result) => {
41
+ if (!cancelled) onSuccessRef.current(result);
42
+ })
43
+ .catch(() => {
44
+ if (!cancelled && errorMessage) toast.error(errorMessage);
45
+ })
46
+ .finally(() => {
47
+ if (!cancelled) setIsLoading(false);
48
+ });
49
+
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }, [featureId, fetcher, errorMessage]);
54
+
55
+ return isLoading;
56
+ }
@@ -37,15 +37,14 @@ export function useFeatureActions(input: FeatureActionsInput | null): FeatureAct
37
37
  const shellTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
38
38
  const specsTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
39
39
 
40
- // Clear timers on unmount
40
+ // Clear timers on unmount — read .current inside cleanup so we get the
41
+ // actual timer value at teardown time, not the always-null value at mount.
41
42
  useEffect(() => {
42
- const ideTimer = ideTimerRef.current;
43
- const shellTimer = shellTimerRef.current;
44
- const specsTimer = specsTimerRef.current;
43
+ const refs = [ideTimerRef, shellTimerRef, specsTimerRef];
45
44
  return () => {
46
- if (ideTimer) clearTimeout(ideTimer);
47
- if (shellTimer) clearTimeout(shellTimer);
48
- if (specsTimer) clearTimeout(specsTimer);
45
+ for (const ref of refs) {
46
+ if (ref.current) clearTimeout(ref.current);
47
+ }
49
48
  };
50
49
  }, []);
51
50
 
@@ -41,7 +41,7 @@ export function deriveNodeState(feature: Feature, agentRun?: AgentRun | null): F
41
41
  case AgentRunStatus.cancelled:
42
42
  return 'blocked';
43
43
  case AgentRunStatus.completed:
44
- return feature.lifecycle === SdlcLifecycle.Maintain ? 'done' : 'done';
44
+ return 'done';
45
45
  case AgentRunStatus.running:
46
46
  case AgentRunStatus.pending:
47
47
  return 'running';
@@ -112,7 +112,17 @@ export function mapEventTypeToState(eventType: NotificationEventType): FeatureNo
112
112
  }
113
113
  }
114
114
 
115
- /** Maps an SSE event phaseName to a FeatureLifecyclePhase. Mirrors page.tsx nodeToLifecyclePhase. */
115
+ /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase. */
116
+ export const sdlcLifecycleMap: Record<string, FeatureLifecyclePhase> = {
117
+ Requirements: 'requirements',
118
+ Research: 'research',
119
+ Implementation: 'implementation',
120
+ Review: 'review',
121
+ 'Deploy & QA': 'deploy',
122
+ Maintain: 'maintain',
123
+ };
124
+
125
+ /** Map agent graph node names (from agent_run.result or SSE phaseName) to UI lifecycle phases. */
116
126
  const phaseNameToLifecycle: Record<string, FeatureLifecyclePhase> = {
117
127
  analyze: 'requirements',
118
128
  requirements: 'requirements',
@@ -124,6 +134,57 @@ const phaseNameToLifecycle: Record<string, FeatureLifecyclePhase> = {
124
134
  blocked: 'requirements',
125
135
  };
126
136
 
137
+ /**
138
+ * Derives the UI lifecycle phase from a Feature + AgentRun.
139
+ * Shared by build-feature-node-data.ts and build-graph-nodes.ts.
140
+ */
141
+ export function deriveLifecycle(feature: Feature, run: AgentRun | null): FeatureLifecyclePhase {
142
+ if (run?.status === 'completed') return 'maintain';
143
+ const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
144
+ return (
145
+ (agentNode ? phaseNameToLifecycle[agentNode] : undefined) ??
146
+ sdlcLifecycleMap[feature.lifecycle] ??
147
+ 'requirements'
148
+ );
149
+ }
150
+
151
+ export interface SseEventUpdate {
152
+ featureId: string;
153
+ state: FeatureNodeState | undefined;
154
+ lifecycle: FeatureLifecyclePhase | undefined;
155
+ eventType: NotificationEventType;
156
+ phaseName?: string;
157
+ }
158
+
159
+ /**
160
+ * Resolves state/lifecycle updates from a batch of SSE events, applying
161
+ * the WaitingApproval batch-suppression rule: when WaitingApproval and
162
+ * PhaseCompleted arrive in the same batch for a feature, PhaseCompleted
163
+ * is fully suppressed to prevent lifecycle regression.
164
+ */
165
+ export function resolveSseEventUpdates(
166
+ events: readonly { featureId: string; eventType: NotificationEventType; phaseName?: string }[]
167
+ ): SseEventUpdate[] {
168
+ const waitingApprovalFeatures = new Set(
169
+ events
170
+ .filter((e) => e.eventType === NotificationEventType.WaitingApproval)
171
+ .map((e) => e.featureId)
172
+ );
173
+
174
+ return events.map((event) => {
175
+ const isSuppressed =
176
+ event.eventType === NotificationEventType.PhaseCompleted &&
177
+ waitingApprovalFeatures.has(event.featureId);
178
+ return {
179
+ featureId: event.featureId,
180
+ state: isSuppressed ? undefined : mapEventTypeToState(event.eventType),
181
+ lifecycle: isSuppressed ? undefined : mapPhaseNameToLifecycle(event.phaseName),
182
+ eventType: event.eventType,
183
+ phaseName: event.phaseName,
184
+ };
185
+ });
186
+ }
187
+
127
188
  export function mapPhaseNameToLifecycle(
128
189
  phaseName: string | undefined
129
190
  ): FeatureLifecyclePhase | undefined {
@@ -1,14 +1,5 @@
1
- export {
2
- ControlCenterDrawer,
3
- type ControlCenterDrawerProps,
4
- computeDrawerView,
5
- type DrawerView,
6
- } from './control-center-drawer';
7
- export {
8
- AddRepositoryNode,
9
- type AddRepositoryNodeData,
10
- type AddRepositoryNodeType,
11
- } from './add-repository-node';
1
+ export { computeDrawerView, type DrawerView } from './control-center-drawer';
2
+ export { AddRepositoryButton } from './add-repository-button';
12
3
  export { ElapsedTime, formatElapsed } from './elapsed-time';
13
4
  export { EmptyState, type EmptyStateProps } from './empty-state';
14
5
  export {
@@ -35,7 +26,6 @@ export {
35
26
  export { FeatureStatusBadges, type FeatureStatusBadgesProps } from './feature-status-badges';
36
27
  export { FeatureStatusGroup, type FeatureStatusGroupProps } from './feature-status-group';
37
28
  export { LoadingSkeleton } from './loading-skeleton';
38
- export { NotificationPermissionBanner } from './notification-permission-banner';
39
29
  export {
40
30
  RepositoryNode,
41
31
  type RepositoryNodeData,
@@ -39,7 +39,7 @@ export function RepositoryNode({ data }: { data: RepositoryNodeData; [key: strin
39
39
  const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
40
40
 
41
41
  return (
42
- <div className="group relative">
42
+ <div className={cn('group relative', data.onDelete && data.id && 'pl-10')}>
43
43
  {data.showHandles ? (
44
44
  <Handle
45
45
  type="target"
@@ -52,7 +52,7 @@ export function RepositoryNode({ data }: { data: RepositoryNodeData; [key: strin
52
52
  {/* Delete button — visible on hover, positioned to the left */}
53
53
  {data.onDelete && data.id ? (
54
54
  <>
55
- <div className="absolute top-1/2 -left-10 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100">
55
+ <div className="absolute top-1/2 left-0 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100">
56
56
  <TooltipProvider>
57
57
  <Tooltip>
58
58
  <TooltipTrigger asChild>
@@ -37,22 +37,19 @@ export function useRepositoryActions(input: RepositoryActionsInput | null): Repo
37
37
 
38
38
  // Clear timers on unmount
39
39
  useEffect(() => {
40
- const ideTimer = ideTimerRef.current;
41
- const shellTimer = shellTimerRef.current;
42
- const folderTimer = folderTimerRef.current;
40
+ const ideRef = ideTimerRef;
41
+ const shellRef = shellTimerRef;
42
+ const folderRef = folderTimerRef;
43
43
  return () => {
44
- if (ideTimer) clearTimeout(ideTimer);
45
- if (shellTimer) clearTimeout(shellTimer);
46
- if (folderTimer) clearTimeout(folderTimer);
44
+ if (ideRef.current) clearTimeout(ideRef.current);
45
+ if (shellRef.current) clearTimeout(shellRef.current);
46
+ if (folderRef.current) clearTimeout(folderRef.current);
47
47
  };
48
48
  }, []);
49
49
 
50
- const performToolbarAction = useCallback(
50
+ const performAction = useCallback(
51
51
  async (
52
- action: (input: { repositoryPath: string }) => Promise<{
53
- success: boolean;
54
- error?: string;
55
- }>,
52
+ action: () => Promise<{ success: boolean; error?: string }>,
56
53
  setLoading: (v: boolean) => void,
57
54
  setError: (v: string | null) => void,
58
55
  timerRef: React.RefObject<ReturnType<typeof setTimeout> | null>,
@@ -60,48 +57,13 @@ export function useRepositoryActions(input: RepositoryActionsInput | null): Repo
60
57
  ) => {
61
58
  if (!input || isLoading) return;
62
59
 
63
- // Clear any existing timer
64
60
  if (timerRef.current) clearTimeout(timerRef.current);
65
61
 
66
62
  setLoading(true);
67
63
  setError(null);
68
64
 
69
65
  try {
70
- const result = await action({ repositoryPath: input.repositoryPath });
71
-
72
- if (!result.success) {
73
- const errorMessage = result.error ?? 'An unexpected error occurred';
74
- setError(errorMessage);
75
- timerRef.current = setTimeout(() => setError(null), ERROR_CLEAR_DELAY);
76
- }
77
- } catch (err: unknown) {
78
- const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred';
79
- setError(errorMessage);
80
- timerRef.current = setTimeout(() => setError(null), ERROR_CLEAR_DELAY);
81
- } finally {
82
- setLoading(false);
83
- }
84
- },
85
- [input]
86
- );
87
-
88
- const performFolderAction = useCallback(
89
- async (
90
- action: (repositoryPath: string) => Promise<{ success: boolean; error?: string }>,
91
- setLoading: (v: boolean) => void,
92
- setError: (v: string | null) => void,
93
- timerRef: React.RefObject<ReturnType<typeof setTimeout> | null>,
94
- isLoading: boolean
95
- ) => {
96
- if (!input || isLoading) return;
97
-
98
- if (timerRef.current) clearTimeout(timerRef.current);
99
-
100
- setLoading(true);
101
- setError(null);
102
-
103
- try {
104
- const result = await action(input.repositoryPath);
66
+ const result = await action();
105
67
 
106
68
  if (!result.success) {
107
69
  const errorMessage = result.error ?? 'An unexpected error occurred';
@@ -120,26 +82,39 @@ export function useRepositoryActions(input: RepositoryActionsInput | null): Repo
120
82
  );
121
83
 
122
84
  const handleOpenIde = useCallback(
123
- () => performToolbarAction(openIde, setIdeLoading, setIdeError, ideTimerRef, ideLoading),
124
- [performToolbarAction, ideLoading]
85
+ () =>
86
+ performAction(
87
+ () => openIde({ repositoryPath: input!.repositoryPath }),
88
+ setIdeLoading,
89
+ setIdeError,
90
+ ideTimerRef,
91
+ ideLoading
92
+ ),
93
+ [performAction, ideLoading, input]
125
94
  );
126
95
 
127
96
  const handleOpenShell = useCallback(
128
97
  () =>
129
- performToolbarAction(openShell, setShellLoading, setShellError, shellTimerRef, shellLoading),
130
- [performToolbarAction, shellLoading]
98
+ performAction(
99
+ () => openShell({ repositoryPath: input!.repositoryPath }),
100
+ setShellLoading,
101
+ setShellError,
102
+ shellTimerRef,
103
+ shellLoading
104
+ ),
105
+ [performAction, shellLoading, input]
131
106
  );
132
107
 
133
108
  const handleOpenFolder = useCallback(
134
109
  () =>
135
- performFolderAction(
136
- openFolder,
110
+ performAction(
111
+ () => openFolder(input!.repositoryPath),
137
112
  setFolderLoading,
138
113
  setFolderError,
139
114
  folderTimerRef,
140
115
  folderLoading
141
116
  ),
142
- [performFolderAction, folderLoading]
117
+ [performAction, folderLoading, input]
143
118
  );
144
119
 
145
120
  return {