@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
@@ -1,745 +0,0 @@
1
- 'use client';
2
-
3
- import { useState, useCallback, useEffect } from 'react';
4
- import { toast } from 'sonner';
5
- import {
6
- Loader2,
7
- Trash2,
8
- ExternalLink,
9
- GitCommitHorizontal,
10
- Code2,
11
- Terminal,
12
- FolderOpen,
13
- Play,
14
- Square,
15
- } from 'lucide-react';
16
- import type {
17
- PrdApprovalPayload,
18
- QuestionSelectionChange,
19
- } from '@shepai/core/domain/generated/output';
20
- import { PrStatus } from '@shepai/core/domain/generated/output';
21
- import { approveFeature } from '@/app/actions/approve-feature';
22
- import { rejectFeature } from '@/app/actions/reject-feature';
23
- import { getFeatureArtifact } from '@/app/actions/get-feature-artifact';
24
- import { getResearchArtifact } from '@/app/actions/get-research-artifact';
25
- import { getMergeReviewData } from '@/app/actions/get-merge-review-data';
26
- import { cn } from '@/lib/utils';
27
- import { featureFlags } from '@/lib/feature-flags';
28
- import { useSoundAction } from '@/hooks/use-sound-action';
29
- import { useDeployAction } from '@/hooks/use-deploy-action';
30
- import { BaseDrawer } from '@/components/common/base-drawer';
31
- import { DeploymentStatusBadge } from '@/components/common/deployment-status-badge';
32
- import { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';
33
- import { Button } from '@/components/ui/button';
34
- import { Badge } from '@/components/ui/badge';
35
- import { Separator } from '@/components/ui/separator';
36
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
37
- import { CometSpinner } from '@/components/ui/comet-spinner';
38
- import {
39
- AlertDialog,
40
- AlertDialogAction,
41
- AlertDialogCancel,
42
- AlertDialogContent,
43
- AlertDialogDescription,
44
- AlertDialogFooter,
45
- AlertDialogHeader,
46
- AlertDialogTitle,
47
- AlertDialogTrigger,
48
- } from '@/components/ui/alert-dialog';
49
- import { CiStatusBadge } from '@/components/common/ci-status-badge';
50
- import { ActionButton } from '@/components/common/action-button';
51
- import { OpenActionMenu } from '@/components/common/open-action-menu';
52
- import { FeatureCreateDrawer } from '@/components/common/feature-create-drawer';
53
- import { PrdQuestionnaire } from '@/components/common/prd-questionnaire';
54
- import { TechReviewTabs } from '@/components/common/tech-review-tabs';
55
- import type { ProductDecisionsSummaryData } from '@/components/common/product-decisions-summary';
56
- import { MergeReview } from '@/components/common/merge-review';
57
- import { featureNodeStateConfig, lifecycleDisplayLabels } from '@/components/common/feature-node';
58
- import type { FeatureNodeData } from '@/components/common/feature-node';
59
- import { useFeatureActions } from '@/components/common/feature-drawer/use-feature-actions';
60
- import { useRepositoryActions } from '@/components/common/repository-node/use-repository-actions';
61
- import type { PrdQuestionnaireData } from '@/components/common/prd-questionnaire';
62
- import type { TechDecisionsReviewData } from '@/components/common/tech-decisions-review';
63
- import type { MergeReviewData } from '@/components/common/merge-review';
64
- import type { FeatureCreatePayload } from '@/components/common/feature-create-drawer';
65
- import type { DrawerView } from './drawer-view';
66
-
67
- export interface ControlCenterDrawerProps {
68
- view: DrawerView | null;
69
- onClose: () => void;
70
- onDelete?: (featureId: string) => void;
71
- isDeleting?: boolean;
72
- onCreateSubmit: (data: FeatureCreatePayload) => void;
73
- isSubmitting?: boolean;
74
- }
75
-
76
- export function ControlCenterDrawer({
77
- view,
78
- onClose,
79
- onDelete,
80
- isDeleting,
81
- onCreateSubmit,
82
- isSubmitting,
83
- }: ControlCenterDrawerProps) {
84
- // ── PRD questionnaire state ─────────────────────────────────────────────
85
- const [prdData, setPrdData] = useState<PrdQuestionnaireData | null>(null);
86
- const [prdSelections, setPrdSelections] = useState<Record<string, string>>({});
87
- const [isLoadingPrd, setIsLoadingPrd] = useState(false);
88
-
89
- // ── Tech decisions state ────────────────────────────────────────────────
90
- const [techData, setTechData] = useState<TechDecisionsReviewData | null>(null);
91
- const [isLoadingTech, setIsLoadingTech] = useState(false);
92
-
93
- // ── Product decisions state (for tech review Product tab) ─────────────
94
- const [techProductData, setTechProductData] = useState<
95
- ProductDecisionsSummaryData | null | undefined
96
- >(undefined);
97
- const [isLoadingTechProduct, setIsLoadingTechProduct] = useState(false);
98
-
99
- // ── Merge review state ──────────────────────────────────────────────────
100
- const [mergeData, setMergeData] = useState<MergeReviewData | null>(null);
101
- const [isLoadingMerge, setIsLoadingMerge] = useState(false);
102
-
103
- // ── Shared reject state ─────────────────────────────────────────────────
104
- const [isRejecting, setIsRejecting] = useState(false);
105
- const rejectSound = useSoundAction('reject');
106
-
107
- // ── Data fetching ───────────────────────────────────────────────────────
108
-
109
- const prdFeatureId = view?.type === 'prd-review' ? view.node.featureId : null;
110
- useEffect(() => {
111
- setPrdSelections({});
112
- setPrdData(null);
113
- if (!prdFeatureId) return;
114
-
115
- let cancelled = false;
116
- setIsLoadingPrd(true);
117
- getFeatureArtifact(prdFeatureId)
118
- .then((result) => {
119
- if (cancelled) return;
120
- if (result.error) {
121
- toast.error(result.error);
122
- return;
123
- }
124
- if (result.questionnaire) {
125
- setPrdData(result.questionnaire);
126
- const defaults: Record<string, string> = {};
127
- for (const q of result.questionnaire.questions) {
128
- const recommended = q.options.find((o) => o.recommended);
129
- if (recommended) defaults[q.id] = recommended.id;
130
- }
131
- setPrdSelections(defaults);
132
- }
133
- })
134
- .catch(() => {
135
- if (!cancelled) toast.error('Failed to load questionnaire');
136
- })
137
- .finally(() => {
138
- if (!cancelled) setIsLoadingPrd(false);
139
- });
140
- return () => {
141
- cancelled = true;
142
- };
143
- }, [prdFeatureId]);
144
-
145
- const techFeatureId = view?.type === 'tech-review' ? view.node.featureId : null;
146
- useEffect(() => {
147
- setTechData(null);
148
- if (!techFeatureId) return;
149
-
150
- let cancelled = false;
151
- setIsLoadingTech(true);
152
- getResearchArtifact(techFeatureId)
153
- .then((result) => {
154
- if (cancelled) return;
155
- if (result.error) {
156
- toast.error(result.error);
157
- return;
158
- }
159
- if (result.techDecisions) setTechData(result.techDecisions);
160
- })
161
- .catch(() => {
162
- if (!cancelled) toast.error('Failed to load tech decisions');
163
- })
164
- .finally(() => {
165
- if (!cancelled) setIsLoadingTech(false);
166
- });
167
- return () => {
168
- cancelled = true;
169
- };
170
- }, [techFeatureId]);
171
-
172
- // Fetch product decisions for the Product tab in tech review
173
- useEffect(() => {
174
- setTechProductData(undefined);
175
- if (!techFeatureId) return;
176
-
177
- let cancelled = false;
178
- setIsLoadingTechProduct(true);
179
- getFeatureArtifact(techFeatureId)
180
- .then((result) => {
181
- if (cancelled) return;
182
- if (result.productDecisions) {
183
- setTechProductData(result.productDecisions);
184
- }
185
- // Silent failure — product tab shows "not available"
186
- })
187
- .catch(() => {
188
- // Silent failure — the product tab is supplementary
189
- })
190
- .finally(() => {
191
- if (!cancelled) setIsLoadingTechProduct(false);
192
- });
193
- return () => {
194
- cancelled = true;
195
- };
196
- }, [techFeatureId]);
197
-
198
- const mergeFeatureId = view?.type === 'merge-review' ? view.node.featureId : null;
199
- useEffect(() => {
200
- setMergeData(null);
201
- if (!mergeFeatureId) return;
202
-
203
- let cancelled = false;
204
- setIsLoadingMerge(true);
205
- getMergeReviewData(mergeFeatureId)
206
- .then((result) => {
207
- if (cancelled) return;
208
- if ('error' in result) {
209
- toast.error(result.error);
210
- return;
211
- }
212
- setMergeData(result);
213
- })
214
- .catch(() => {
215
- if (!cancelled) toast.error('Failed to load merge review data');
216
- })
217
- .finally(() => {
218
- if (!cancelled) setIsLoadingMerge(false);
219
- });
220
- return () => {
221
- cancelled = true;
222
- };
223
- }, [mergeFeatureId]);
224
-
225
- // ── Approve / reject handlers ───────────────────────────────────────────
226
-
227
- const reviewNode =
228
- view?.type === 'prd-review' || view?.type === 'tech-review' || view?.type === 'merge-review'
229
- ? view.node
230
- : null;
231
-
232
- const handleReject = useCallback(
233
- async (feedback: string, label: string, onDone?: () => void) => {
234
- if (!reviewNode?.featureId) return;
235
- setIsRejecting(true);
236
- try {
237
- const result = await rejectFeature(reviewNode.featureId, feedback);
238
- if (!result.rejected) {
239
- toast.error(result.error ?? `Failed to reject ${label.toLowerCase()}`);
240
- return;
241
- }
242
- rejectSound.play();
243
- toast.success(`${label} rejected — agent re-iterating (iteration ${result.iteration})`);
244
- if (result.iterationWarning) {
245
- toast.warning(
246
- `Iteration ${result.iteration} — consider approving or adjusting feedback to avoid excessive iterations`
247
- );
248
- }
249
- onClose();
250
- onDone?.();
251
- } finally {
252
- setIsRejecting(false);
253
- }
254
- },
255
- [reviewNode, onClose, rejectSound]
256
- );
257
-
258
- const handlePrdReject = useCallback(
259
- (feedback: string) => handleReject(feedback, 'Requirements', () => setPrdSelections({})),
260
- [handleReject]
261
- );
262
- const handleTechReject = useCallback(
263
- (feedback: string) => handleReject(feedback, 'Plan'),
264
- [handleReject]
265
- );
266
- const handleMergeReject = useCallback(
267
- (feedback: string) => handleReject(feedback, 'Merge'),
268
- [handleReject]
269
- );
270
-
271
- const handleSimpleApprove = useCallback(
272
- async (label: string) => {
273
- if (!reviewNode?.featureId) return;
274
- const result = await approveFeature(reviewNode.featureId);
275
- if (!result.approved) {
276
- toast.error(result.error ?? `Failed to approve ${label.toLowerCase()}`);
277
- return;
278
- }
279
- toast.success(`${label} approved — agent resuming`);
280
- onClose();
281
- },
282
- [reviewNode, onClose]
283
- );
284
-
285
- const handlePrdApprove = useCallback(
286
- async (_actionId: string) => {
287
- if (view?.type !== 'prd-review') return;
288
- let payload: PrdApprovalPayload | undefined;
289
- if (prdData) {
290
- const changedSelections: QuestionSelectionChange[] = [];
291
- for (const [questionId, optionId] of Object.entries(prdSelections)) {
292
- const question = prdData.questions.find((q) => q.id === questionId);
293
- const option = question?.options.find((o) => o.id === optionId);
294
- if (question && option) {
295
- changedSelections.push({ questionId: question.question, selectedOption: option.label });
296
- }
297
- }
298
- payload = { approved: true, changedSelections };
299
- }
300
- const result = await approveFeature(view.node.featureId, payload);
301
- if (!result.approved) {
302
- toast.error(result.error ?? 'Failed to approve requirements');
303
- return;
304
- }
305
- toast.success('Requirements approved — agent resuming');
306
- setPrdSelections({});
307
- onClose();
308
- },
309
- [view, prdData, prdSelections, onClose]
310
- );
311
-
312
- const handleTechApprove = useCallback(() => handleSimpleApprove('Plan'), [handleSimpleApprove]);
313
- const handleMergeApprove = useCallback(() => handleSimpleApprove('Merge'), [handleSimpleApprove]);
314
-
315
- // ── Derived view data ───────────────────────────────────────────────────
316
-
317
- const isCreateView = view?.type === 'feature-create';
318
- const createView = isCreateView ? view : null;
319
-
320
- const featureNode =
321
- view?.type === 'feature' ||
322
- view?.type === 'prd-review' ||
323
- view?.type === 'tech-review' ||
324
- view?.type === 'merge-review'
325
- ? view.node
326
- : null;
327
-
328
- const repoData = view?.type === 'repository' ? view.data : null;
329
-
330
- // ── Hooks (always called unconditionally per Rules of Hooks) ────────────
331
-
332
- const featureActionsInput =
333
- featureNode?.repositoryPath && featureNode?.branch
334
- ? {
335
- repositoryPath: featureNode.repositoryPath,
336
- branch: featureNode.branch,
337
- specPath: featureNode.specPath,
338
- }
339
- : null;
340
- const featureActions = useFeatureActions(featureActionsInput);
341
- const repoActions = useRepositoryActions(
342
- repoData?.repositoryPath ? { repositoryPath: repoData.repositoryPath } : null
343
- );
344
-
345
- // ── Deploy targets ──────────────────────────────────────────────────────
346
- // Feature deploy is rendered inline in the header; repo deploy uses BaseDrawer's bar.
347
-
348
- const featureDeployTarget =
349
- featureNode?.repositoryPath && featureNode.branch
350
- ? {
351
- targetId: featureNode.featureId,
352
- targetType: 'feature' as const,
353
- repositoryPath: featureNode.repositoryPath,
354
- branch: featureNode.branch,
355
- }
356
- : null;
357
-
358
- const repoDeployTarget = repoData?.repositoryPath
359
- ? {
360
- targetId: repoData.repositoryPath,
361
- targetType: 'repository' as const,
362
- repositoryPath: repoData.repositoryPath,
363
- }
364
- : undefined;
365
-
366
- const deployAction = useDeployAction(featureDeployTarget);
367
- const isFeatureDeployActive =
368
- deployAction.status === 'Booting' || deployAction.status === 'Ready';
369
-
370
- // ── Header ──────────────────────────────────────────────────────────────
371
-
372
- let header: React.ReactNode = undefined;
373
-
374
- if (featureNode) {
375
- header = (
376
- <>
377
- <div data-testid="feature-drawer-header">
378
- <DrawerTitle>{featureNode.name}</DrawerTitle>
379
- {featureNode.description ? (
380
- <DrawerDescription>{featureNode.description}</DrawerDescription>
381
- ) : featureNode.featureId ? (
382
- <DrawerDescription className="sr-only">{featureNode.featureId}</DrawerDescription>
383
- ) : null}
384
- </div>
385
-
386
- {featureActionsInput ? (
387
- <div className="flex items-center gap-2 pt-2">
388
- <OpenActionMenu
389
- actions={featureActions}
390
- repositoryPath={featureActionsInput.repositoryPath}
391
- showSpecs={!!featureActionsInput.specPath}
392
- />
393
- {featureFlags.envDeploy && featureDeployTarget ? (
394
- <>
395
- <TooltipProvider>
396
- <Tooltip>
397
- <TooltipTrigger asChild>
398
- <span>
399
- <ActionButton
400
- label={isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server'}
401
- onClick={isFeatureDeployActive ? deployAction.stop : deployAction.deploy}
402
- loading={deployAction.deployLoading || deployAction.stopLoading}
403
- error={!!deployAction.deployError}
404
- icon={isFeatureDeployActive ? Square : Play}
405
- iconOnly
406
- variant="outline"
407
- size="icon-sm"
408
- />
409
- </span>
410
- </TooltipTrigger>
411
- <TooltipContent>
412
- {isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server'}
413
- </TooltipContent>
414
- </Tooltip>
415
- </TooltipProvider>
416
- {isFeatureDeployActive ? (
417
- <DeploymentStatusBadge
418
- status={deployAction.status}
419
- url={deployAction.url}
420
- targetId={featureDeployTarget?.targetId}
421
- />
422
- ) : null}
423
- </>
424
- ) : null}
425
- {onDelete && featureNode.featureId ? (
426
- <AlertDialog>
427
- <AlertDialogTrigger asChild>
428
- <Button
429
- variant="ghost"
430
- size="icon-sm"
431
- aria-label="Delete feature"
432
- disabled={isDeleting}
433
- className="text-muted-foreground hover:text-destructive ml-auto"
434
- data-testid="feature-drawer-delete"
435
- >
436
- {isDeleting ? (
437
- <Loader2 className="size-4 animate-spin" />
438
- ) : (
439
- <Trash2 className="size-4" />
440
- )}
441
- </Button>
442
- </AlertDialogTrigger>
443
- <AlertDialogContent>
444
- <AlertDialogHeader>
445
- <AlertDialogTitle>Delete feature?</AlertDialogTitle>
446
- <AlertDialogDescription>
447
- This will permanently delete <strong>{featureNode.name}</strong> (
448
- {featureNode.featureId}). This action cannot be undone.
449
- {featureNode.state === 'running' ? (
450
- <> This feature has a running agent that will be stopped.</>
451
- ) : null}
452
- </AlertDialogDescription>
453
- </AlertDialogHeader>
454
- <AlertDialogFooter>
455
- <AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
456
- <AlertDialogAction
457
- variant="destructive"
458
- disabled={isDeleting}
459
- onClick={() => onDelete(featureNode.featureId)}
460
- >
461
- {isDeleting ? (
462
- <>
463
- <Loader2 className="mr-2 h-4 w-4 animate-spin" />
464
- Deleting…
465
- </>
466
- ) : (
467
- 'Delete'
468
- )}
469
- </AlertDialogAction>
470
- </AlertDialogFooter>
471
- </AlertDialogContent>
472
- </AlertDialog>
473
- ) : null}
474
- </div>
475
- ) : null}
476
- </>
477
- );
478
- } else if (repoData) {
479
- header = (
480
- <div data-testid="repository-drawer-header">
481
- <DrawerTitle>{repoData.name}</DrawerTitle>
482
- {repoData.repositoryPath ? (
483
- <DrawerDescription className="truncate font-mono text-xs">
484
- {repoData.repositoryPath}
485
- </DrawerDescription>
486
- ) : null}
487
- </div>
488
- );
489
- }
490
-
491
- // ── Body ────────────────────────────────────────────────────────────────
492
-
493
- let body: React.ReactNode = null;
494
-
495
- if (view?.type === 'feature' && featureNode) {
496
- body = (
497
- <div className="flex-1 overflow-y-auto">
498
- <div data-testid="feature-drawer-status" className="flex flex-col gap-3 p-4">
499
- <div className="text-muted-foreground text-xs font-semibold tracking-wider">
500
- {lifecycleDisplayLabels[featureNode.lifecycle]}
501
- </div>
502
- <FeatureStateBadge data={featureNode} />
503
- {featureNode.progress > 0 ? (
504
- <div data-testid="feature-drawer-progress" className="flex flex-col gap-1">
505
- <div className="text-muted-foreground flex items-center justify-between text-xs">
506
- <span>Progress</span>
507
- <span>{featureNode.progress}%</span>
508
- </div>
509
- <div className="bg-muted h-2 w-full overflow-hidden rounded-full">
510
- <div
511
- className={cn(
512
- 'h-full rounded-full transition-all',
513
- featureNodeStateConfig[featureNode.state].progressClass
514
- )}
515
- style={{ width: `${featureNode.progress}%` }}
516
- />
517
- </div>
518
- </div>
519
- ) : null}
520
- </div>
521
- {featureNode.pr ? (
522
- <>
523
- <Separator />
524
- <FeaturePrInfo pr={featureNode.pr} />
525
- </>
526
- ) : null}
527
- <FeatureDetails data={featureNode} />
528
- </div>
529
- );
530
- } else if (view?.type === 'prd-review') {
531
- body = prdData ? (
532
- <PrdQuestionnaire
533
- data={prdData}
534
- selections={prdSelections}
535
- onSelect={(qId, oId) => setPrdSelections((prev) => ({ ...prev, [qId]: oId }))}
536
- onApprove={handlePrdApprove}
537
- onReject={handlePrdReject}
538
- isProcessing={isLoadingPrd}
539
- isRejecting={isRejecting}
540
- />
541
- ) : (
542
- <div className="flex items-center justify-center p-8">
543
- <Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
544
- </div>
545
- );
546
- } else if (view?.type === 'tech-review') {
547
- body = techData ? (
548
- <TechReviewTabs
549
- techData={techData}
550
- productData={isLoadingTechProduct ? null : techProductData}
551
- onApprove={handleTechApprove}
552
- onReject={handleTechReject}
553
- isProcessing={isLoadingTech}
554
- isRejecting={isRejecting}
555
- />
556
- ) : (
557
- <div className="flex items-center justify-center p-8">
558
- <Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
559
- </div>
560
- );
561
- } else if (view?.type === 'merge-review') {
562
- body = mergeData ? (
563
- <MergeReview
564
- data={mergeData}
565
- onApprove={handleMergeApprove}
566
- onReject={handleMergeReject}
567
- isProcessing={isLoadingMerge}
568
- isRejecting={isRejecting}
569
- />
570
- ) : (
571
- <div className="flex items-center justify-center p-8">
572
- <Loader2 className="text-muted-foreground h-6 w-6 animate-spin" />
573
- </div>
574
- );
575
- } else if (view?.type === 'repository' && repoData?.repositoryPath) {
576
- body = (
577
- <div className="flex-1 overflow-y-auto">
578
- <Separator />
579
- <div className="flex flex-col gap-3 p-4">
580
- <div className="text-muted-foreground text-xs font-semibold tracking-wider">
581
- OPEN WITH
582
- </div>
583
- <div className="flex flex-col gap-2">
584
- <ActionButton
585
- label="Open in IDE"
586
- onClick={repoActions.openInIde}
587
- loading={repoActions.ideLoading}
588
- error={!!repoActions.ideError}
589
- icon={Code2}
590
- variant="outline"
591
- size="sm"
592
- />
593
- <ActionButton
594
- label="Open in Shell"
595
- onClick={repoActions.openInShell}
596
- loading={repoActions.shellLoading}
597
- error={!!repoActions.shellError}
598
- icon={Terminal}
599
- variant="outline"
600
- size="sm"
601
- />
602
- <ActionButton
603
- label="Open Folder"
604
- onClick={repoActions.openFolder}
605
- loading={repoActions.folderLoading}
606
- error={!!repoActions.folderError}
607
- icon={FolderOpen}
608
- variant="outline"
609
- size="sm"
610
- />
611
- </div>
612
- </div>
613
- </div>
614
- );
615
- }
616
-
617
- // ── Render ──────────────────────────────────────────────────────────────
618
-
619
- return (
620
- <>
621
- {/* Single BaseDrawer for all node-selection views */}
622
- <BaseDrawer
623
- open={view !== null && !isCreateView}
624
- onClose={onClose}
625
- size="md"
626
- modal={false}
627
- header={header}
628
- deployTarget={repoDeployTarget}
629
- data-testid={
630
- view?.type === 'feature'
631
- ? 'feature-drawer'
632
- : view?.type === 'repository'
633
- ? 'repository-drawer'
634
- : 'review-drawer'
635
- }
636
- >
637
- {body}
638
- </BaseDrawer>
639
-
640
- {/* Feature create drawer — rendered as sibling since it owns its own complex form state */}
641
- <FeatureCreateDrawer
642
- open={isCreateView}
643
- onClose={onClose}
644
- onSubmit={onCreateSubmit}
645
- repositoryPath={createView?.repositoryPath ?? ''}
646
- features={createView?.features ?? []}
647
- workflowDefaults={createView?.workflowDefaults}
648
- initialParentId={createView?.initialParentId}
649
- isSubmitting={isSubmitting}
650
- />
651
- </>
652
- );
653
- }
654
-
655
- // ── Private sub-components ────────────────────────────────────────────────────
656
-
657
- function FeatureStateBadge({ data }: { data: FeatureNodeData }) {
658
- const config = featureNodeStateConfig[data.state];
659
- const Icon = config.icon;
660
- return (
661
- <div
662
- className={cn(
663
- 'flex items-center gap-2 rounded-full px-3 py-1.5 text-sm font-medium',
664
- config.badgeBgClass,
665
- config.badgeClass
666
- )}
667
- >
668
- {data.state === 'running' ? (
669
- <CometSpinner size="sm" className="shrink-0" />
670
- ) : (
671
- <Icon className="h-4 w-4 shrink-0" />
672
- )}
673
- <span>{config.label}</span>
674
- </div>
675
- );
676
- }
677
-
678
- const prStatusStyles: Record<PrStatus, string> = {
679
- [PrStatus.Open]: 'border-transparent bg-blue-50 text-blue-700 hover:bg-blue-50',
680
- [PrStatus.Merged]: 'border-transparent bg-purple-50 text-purple-700 hover:bg-purple-50',
681
- [PrStatus.Closed]: 'border-transparent bg-red-50 text-red-700 hover:bg-red-50',
682
- };
683
-
684
- function FeaturePrInfo({ pr }: { pr: NonNullable<FeatureNodeData['pr']> }) {
685
- return (
686
- <div data-testid="feature-drawer-pr" className="border-border mx-4 rounded-lg border">
687
- <div className="space-y-3 px-4 py-3">
688
- <div className="flex items-center justify-between">
689
- <a
690
- href={pr.url}
691
- target="_blank"
692
- rel="noopener noreferrer"
693
- className="text-primary flex items-center gap-1.5 text-sm font-semibold underline underline-offset-2"
694
- >
695
- PR #{pr.number}
696
- <ExternalLink className="h-3.5 w-3.5" />
697
- </a>
698
- <Badge className={prStatusStyles[pr.status]}>{pr.status}</Badge>
699
- </div>
700
- {pr.ciStatus ? (
701
- <div className="flex items-center justify-between">
702
- <span className="text-muted-foreground text-xs font-medium">CI Status</span>
703
- <CiStatusBadge status={pr.ciStatus} />
704
- </div>
705
- ) : null}
706
- {pr.commitHash ? (
707
- <div className="flex items-center justify-between">
708
- <span className="text-muted-foreground text-xs font-medium">Commit</span>
709
- <div className="flex items-center gap-1.5">
710
- <GitCommitHorizontal className="text-muted-foreground h-3.5 w-3.5" />
711
- <code className="bg-muted text-foreground rounded-md px-1.5 py-0.5 font-mono text-[11px]">
712
- {pr.commitHash.slice(0, 7)}
713
- </code>
714
- </div>
715
- </div>
716
- ) : null}
717
- </div>
718
- </div>
719
- );
720
- }
721
-
722
- function FeatureDetails({ data }: { data: FeatureNodeData }) {
723
- const hasAnyDetail = data.agentType ?? data.runtime ?? data.blockedBy ?? data.errorMessage;
724
- if (!hasAnyDetail) return null;
725
- return (
726
- <>
727
- <Separator />
728
- <div data-testid="feature-drawer-details" className="flex flex-col gap-3 p-4">
729
- {data.agentType ? <DetailRow label="Agent" value={data.agentType} /> : null}
730
- {data.runtime ? <DetailRow label="Runtime" value={data.runtime} /> : null}
731
- {data.blockedBy ? <DetailRow label="Blocked by" value={data.blockedBy} /> : null}
732
- {data.errorMessage ? <DetailRow label="Error" value={data.errorMessage} /> : null}
733
- </div>
734
- </>
735
- );
736
- }
737
-
738
- function DetailRow({ label, value }: { label: string; value: string }) {
739
- return (
740
- <div className="flex flex-col gap-0.5">
741
- <span className="text-muted-foreground text-xs font-medium">{label}</span>
742
- <span className="text-sm">{value}</span>
743
- </div>
744
- );
745
- }