@shepai/cli 1.72.8 → 1.72.9-pr220.99e5e13

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 (375) hide show
  1. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -1
  2. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
  4. package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.js +1 -0
  5. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +20 -1
  6. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  7. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +68 -41
  8. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +10 -0
  9. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
  10. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
  11. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.js +1 -0
  12. package/dist/packages/core/src/domain/factories/settings-defaults.factory.js +1 -1
  13. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.d.ts.map +1 -1
  14. package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.js +88 -13
  15. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +1 -1
  16. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -1
  17. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
  18. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +3 -0
  19. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -0
  20. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  21. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +16 -3
  22. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +5 -1
  24. package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
  25. package/dist/src/presentation/web/app/actions/create-feature.js +20 -2
  26. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts +10 -0
  27. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts.map +1 -0
  28. package/dist/src/presentation/web/app/actions/get-feature-metadata.js +14 -0
  29. package/dist/src/presentation/web/app/actions/get-graph-data.d.ts +10 -0
  30. package/dist/src/presentation/web/app/actions/get-graph-data.d.ts.map +1 -0
  31. package/dist/src/presentation/web/app/actions/get-graph-data.js +10 -0
  32. package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
  33. package/dist/src/presentation/web/app/api/agent-events/route.js +18 -0
  34. package/dist/src/presentation/web/components/common/add-repository-button/add-repository-button.d.ts.map +1 -0
  35. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts +2 -0
  36. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts.map +1 -0
  37. package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/index.js +0 -1
  38. package/dist/src/presentation/web/components/common/add-repository-button/pick-folder.d.ts.map +1 -0
  39. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.d.ts.map +1 -1
  40. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.js +21 -23
  41. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  42. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +35 -16
  43. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
  44. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +2 -0
  45. package/dist/src/presentation/web/components/common/index.d.ts +1 -2
  46. package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
  47. package/dist/src/presentation/web/components/common/index.js +1 -2
  48. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
  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 +25 -7
  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 +145 -256
  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 +12 -44
  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/scroll-area.js +1 -1
  74. package/dist/src/presentation/web/hooks/use-graph-state.d.ts +42 -0
  75. package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -0
  76. package/dist/src/presentation/web/hooks/use-graph-state.js +257 -0
  77. package/dist/src/presentation/web/hooks/use-notifications.d.ts +1 -5
  78. package/dist/src/presentation/web/hooks/use-notifications.d.ts.map +1 -1
  79. package/dist/src/presentation/web/hooks/use-notifications.js +1 -26
  80. package/dist/src/presentation/web/hooks/use-notifications.stories.d.ts.map +1 -1
  81. package/dist/src/presentation/web/hooks/use-notifications.stories.js +28 -38
  82. package/dist/src/presentation/web/lib/derive-graph.d.ts +52 -0
  83. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -0
  84. package/dist/src/presentation/web/lib/derive-graph.js +126 -0
  85. package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
  86. package/dist/src/presentation/web/lib/layout-with-dagre.js +1 -2
  87. package/dist/tsconfig.build.tsbuildinfo +1 -1
  88. package/package.json +1 -1
  89. package/web/.next/BUILD_ID +1 -1
  90. package/web/.next/build-manifest.json +2 -2
  91. package/web/.next/cache/.previewinfo +1 -1
  92. package/web/.next/cache/.rscinfo +1 -1
  93. package/web/.next/cache/.tsbuildinfo +1 -1
  94. package/web/.next/cache/config.json +3 -3
  95. package/web/.next/fallback-build-manifest.json +2 -2
  96. package/web/.next/prerender-manifest.json +3 -3
  97. package/web/.next/required-server-files.js +1 -1
  98. package/web/.next/required-server-files.json +1 -1
  99. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +43 -28
  100. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
  101. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  102. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  103. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +49 -34
  104. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  105. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  106. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  107. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +39 -24
  108. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
  109. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  110. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  111. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +43 -28
  112. package/web/.next/server/app/(dashboard)/create/page.js +1 -1
  113. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  114. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  115. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +49 -34
  116. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  117. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  118. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  119. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +39 -24
  120. package/web/.next/server/app/(dashboard)/page.js +1 -1
  121. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  122. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  123. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +39 -24
  124. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
  125. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  126. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  127. package/web/.next/server/app/_global-error.html +2 -2
  128. package/web/.next/server/app/_global-error.rsc +1 -1
  129. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  130. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  131. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  132. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  133. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  134. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  135. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  136. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  137. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  138. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  139. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  140. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  141. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  142. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  143. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  144. package/web/.next/server/app/version/page.js.nft.json +1 -1
  145. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  146. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  147. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  148. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  149. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  150. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +3 -0
  151. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +1 -0
  152. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
  153. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +1 -0
  154. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  155. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  156. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  157. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  158. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  159. package/web/.next/server/chunks/ssr/{[root-of-the-server]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
  160. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -0
  161. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  162. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  163. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  164. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js.map +1 -1
  165. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  166. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  167. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js → server/chunks/ssr/[root-of-the-server]__94a6d275._.js} +2 -2
  168. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -0
  169. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  170. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  171. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  172. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  173. package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -1
  174. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  175. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  176. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  177. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  178. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  179. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  180. package/web/.next/server/chunks/ssr/_9fd79ac5._.js +6 -0
  181. package/web/.next/server/chunks/ssr/_9fd79ac5._.js.map +1 -0
  182. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_398553b0._.js → server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
  183. package/web/.next/server/chunks/ssr/{src_presentation_web_5c87e8e4._.js.map → src_presentation_web_2b91e4ec._.js.map} +1 -1
  184. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5c87e8e4._.js → server/chunks/ssr/src_presentation_web_5bcc1537._.js} +2 -2
  185. package/web/.next/server/chunks/ssr/{src_presentation_web_398553b0._.js.map → src_presentation_web_5bcc1537._.js.map} +1 -1
  186. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +3 -0
  187. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +1 -0
  188. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  189. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  190. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  191. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  192. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  193. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  194. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +8 -0
  195. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js.map +1 -0
  196. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
  197. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js.map +1 -0
  198. package/web/.next/server/pages/500.html +2 -2
  199. package/web/.next/server/server-reference-manifest.js +1 -1
  200. package/web/.next/server/server-reference-manifest.json +175 -118
  201. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  202. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  203. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  204. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  205. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +43 -28
  206. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
  207. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  208. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  209. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +49 -34
  210. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  211. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  212. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  213. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +39 -24
  214. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
  215. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  216. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  217. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +43 -28
  218. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +1 -1
  219. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  220. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  221. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +49 -34
  222. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  223. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  224. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  225. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +39 -24
  226. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +1 -1
  227. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  228. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  229. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +39 -24
  230. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
  231. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  232. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  233. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  234. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  235. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  236. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  237. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  238. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  239. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  240. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  241. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  242. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  243. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  244. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  245. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  246. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  247. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  248. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  249. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  250. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  251. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  252. package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  253. 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
  254. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +3 -0
  255. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
  256. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  257. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  258. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  259. 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
  260. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  261. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  262. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  263. package/web/.next/{server/chunks/ssr/[root-of-the-server]__e5e09f72._.js → standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js} +2 -2
  264. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  265. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  266. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  267. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  268. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  269. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9fd79ac5._.js +6 -0
  270. package/web/.next/{server/chunks/ssr/src_presentation_web_398553b0._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
  271. package/web/.next/{server/chunks/ssr/src_presentation_web_5c87e8e4._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js} +2 -2
  272. 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
  273. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  274. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  275. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  276. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +8 -0
  277. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
  278. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  279. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  280. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +175 -118
  281. package/web/.next/standalone/src/presentation/web/CLAUDE.md +191 -0
  282. package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +27 -2
  283. package/web/.next/standalone/src/presentation/web/app/actions/get-feature-metadata.ts +18 -0
  284. package/web/.next/standalone/src/presentation/web/app/actions/get-graph-data.ts +12 -0
  285. package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +21 -1
  286. package/web/.next/standalone/src/presentation/web/components/common/add-repository-button/index.ts +1 -0
  287. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +23 -26
  288. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +44 -18
  289. package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +2 -0
  290. package/web/.next/standalone/src/presentation/web/components/common/index.ts +1 -6
  291. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +2 -2
  292. package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.tsx +0 -13
  293. package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.tsx +1 -45
  294. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-empty-state.tsx +1 -1
  295. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +36 -29
  296. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +2 -41
  297. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +178 -325
  298. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx +0 -48
  299. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +34 -82
  300. package/web/.next/standalone/src/presentation/web/components/layouts/app-shell/app-shell.tsx +1 -1
  301. package/web/.next/standalone/src/presentation/web/components/layouts/app-sidebar/app-sidebar.tsx +2 -14
  302. package/web/.next/standalone/src/presentation/web/components/ui/scroll-area.tsx +1 -1
  303. package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +376 -0
  304. package/web/.next/standalone/src/presentation/web/hooks/use-notifications.stories.tsx +2 -30
  305. package/web/.next/standalone/src/presentation/web/hooks/use-notifications.ts +2 -36
  306. package/web/.next/standalone/src/presentation/web/lib/derive-graph.ts +178 -0
  307. package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +1 -2
  308. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  309. package/web/.next/static/chunks/{1c07b21eb8b32f25.js → 0b409f42a82665ec.js} +1 -1
  310. package/web/.next/static/chunks/0e035a073754dde7.js +1 -0
  311. package/web/.next/static/chunks/109d6898972d7b78.js +1 -0
  312. package/web/.next/static/chunks/{fcafb841e3860687.js → 5238c7e71fc81e4d.js} +1 -1
  313. package/web/.next/static/chunks/6b4899963367ea96.js +4 -0
  314. package/web/.next/static/chunks/71c9ecdceac1939f.css +2 -0
  315. package/web/.next/static/chunks/752846e217931a38.js +1 -0
  316. package/web/.next/static/chunks/9f9e6f5083600784.js +1 -0
  317. package/web/.next/static/chunks/{8682dcb376de62de.js → ae00da647a8354b9.js} +1 -1
  318. package/web/.next/static/chunks/cb41849bcfaa304e.js +1 -0
  319. package/web/.next/static/chunks/dc23a5773f5cd610.js +1 -0
  320. package/web/.next/trace +1 -1
  321. package/web/.next/trace-build +1 -1
  322. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-button.d.ts.map +0 -1
  323. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts +0 -7
  324. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts.map +0 -1
  325. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.js +0 -1
  326. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts +0 -6
  327. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts.map +0 -1
  328. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.js +0 -23
  329. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts +0 -10
  330. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts.map +0 -1
  331. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.js +0 -33
  332. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts +0 -4
  333. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts.map +0 -1
  334. package/dist/src/presentation/web/components/common/add-repository-node/pick-folder.d.ts.map +0 -1
  335. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_2b7834f6.js +0 -3
  336. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_2b7834f6.js.map +0 -1
  337. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_6923c575.js +0 -3
  338. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_6923c575.js.map +0 -1
  339. package/web/.next/server/chunks/ssr/[root-of-the-server]__cbae9863._.js.map +0 -1
  340. package/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js.map +0 -1
  341. package/web/.next/server/chunks/ssr/_47ef589d._.js +0 -6
  342. package/web/.next/server/chunks/ssr/_47ef589d._.js.map +0 -1
  343. package/web/.next/server/chunks/ssr/src_presentation_web_1a32dbcb._.js +0 -8
  344. package/web/.next/server/chunks/ssr/src_presentation_web_1a32dbcb._.js.map +0 -1
  345. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f4952172.js +0 -3
  346. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f4952172.js.map +0 -1
  347. package/web/.next/server/chunks/ssr/src_presentation_web_c1bc6240._.js +0 -8
  348. package/web/.next/server/chunks/ssr/src_presentation_web_c1bc6240._.js.map +0 -1
  349. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_2b7834f6.js +0 -3
  350. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_6923c575.js +0 -3
  351. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_47ef589d._.js +0 -6
  352. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_1a32dbcb._.js +0 -8
  353. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f4952172.js +0 -3
  354. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_c1bc6240._.js +0 -8
  355. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node-config.ts +0 -8
  356. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.tsx +0 -70
  357. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.tsx +0 -49
  358. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/index.ts +0 -3
  359. package/web/.next/static/chunks/3c79bca4d3f18f66.js +0 -1
  360. package/web/.next/static/chunks/5cd24ca47061a21d.js +0 -4
  361. package/web/.next/static/chunks/67f2a7a5e8dc358a.css +0 -2
  362. package/web/.next/static/chunks/71cf72022f08a8c9.js +0 -1
  363. package/web/.next/static/chunks/991d4490d7a338d8.js +0 -1
  364. package/web/.next/static/chunks/c71589df79020ecb.js +0 -1
  365. package/web/.next/static/chunks/ebf172a84c9596ed.js +0 -1
  366. package/web/.next/static/chunks/fabfa54940973cc7.js +0 -1
  367. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.d.ts +0 -0
  368. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.js +0 -0
  369. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.d.ts +0 -0
  370. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.js +0 -0
  371. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.tsx +0 -0
  372. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.ts +0 -0
  373. /package/web/.next/static/{IKuYPxAuMvc4BtwKHlj30 → JYBKfZ0ROsNn817Id2TJ7}/_buildManifest.js +0 -0
  374. /package/web/.next/static/{IKuYPxAuMvc4BtwKHlj30 → JYBKfZ0ROsNn817Id2TJ7}/_clientMiddlewareManifest.json +0 -0
  375. /package/web/.next/static/{IKuYPxAuMvc4BtwKHlj30 → JYBKfZ0ROsNn817Id2TJ7}/_ssgManifest.js +0 -0
@@ -0,0 +1,191 @@
1
+ # Web UI Development Notes
2
+
3
+ ## Running the UI
4
+
5
+ There are two distinct ways to run the web UI. **Always test in BOTH modes.**
6
+
7
+ ### 1. Dev Mode (local development)
8
+
9
+ ```bash
10
+ pnpm dev:web
11
+ ```
12
+
13
+ - Uses `dev-server.ts` which initializes the DI container and starts Next.js in dev mode
14
+ - Turbopack HMR enabled
15
+ - Runs on port 3000 by default
16
+
17
+ ### 2. Production Mode (how users run it)
18
+
19
+ ```bash
20
+ shep ui
21
+ # or
22
+ pnpm dev:cli ui
23
+ ```
24
+
25
+ - The CLI bootstraps the DI container (`src/presentation/cli/index.ts`), then starts Next.js via `WebServerService`
26
+ - Runs on port 4050 by default
27
+ - This is how real users experience the UI
28
+ - **IMPORTANT**: Always test real-time features in this mode, not just dev mode
29
+
30
+ ### Key Differences Between Modes
31
+
32
+ | Aspect | Dev Mode (`pnpm dev:web`) | Production Mode (`shep ui`) |
33
+ | ------------------ | ------------------------------------------------------- | ------------------------------------------------------- |
34
+ | Entry point | `dev-server.ts` | `cli/index.ts` -> `ui.command.ts` -> `WebServerService` |
35
+ | Port | 3000 | 4050 |
36
+ | DI container | Set on `globalThis.__shepContainer` in dev-server.ts:73 | Set in cli/index.ts:76 |
37
+ | WebSocket upgrades | Forwarded (HMR works) | NOT forwarded in `WebServerService` |
38
+ | Next.js mode | Always dev | dev when run from source, prod when installed |
39
+
40
+ ## Graph State Architecture (Domain-Model-Driven)
41
+
42
+ All canvas node/edge state is managed through **domain Maps as the single source of truth**.
43
+
44
+ ```
45
+ Server (layout.tsx) Client (useGraphState)
46
+ ┌──────────────────┐ ┌─────────────────────────────┐
47
+ │ initialNodes[] │──parseMaps──→ │ Domain Maps (source of truth)│
48
+ │ initialEdges[] │ │ featureMap: Map<id, Entry> │
49
+ └──────────────────┘ │ repoMap: Map<id, Entry> │
50
+ │ pendingMap: Map<id, Entry> │
51
+ SSE Events │ │
52
+ ┌──────────────────┐ └──────────┬──────────────────┘
53
+ │ NotificationEvent│──updateFeature──→ │
54
+ └──────────────────┘ │ deriveGraph() + layoutWithDagre()
55
+
56
+ Optimistic UI ┌─────────────────────────────┐
57
+ ┌──────────────────┐ │ Derived (read-only) │
58
+ │ shep:feature- │──addPending───→ │ nodes: CanvasNodeType[] │
59
+ │ created event │ │ edges: Edge[] │
60
+ └──────────────────┘ │ (callbacks + layout applied)│
61
+ └─────────────────────────────┘
62
+ ```
63
+
64
+ ### Key Files
65
+
66
+ | File | Purpose |
67
+ | ---------------------------------------------------------------- | -------------------------------------------------------------------- |
68
+ | `lib/derive-graph.ts` | Pure function: domain Maps → nodes + edges (with callbacks injected) |
69
+ | `hooks/use-graph-state.ts` | Hook: domain Maps state + reconciliation + derivation + layout |
70
+ | `components/features/control-center/use-control-center-state.ts` | Wraps useGraphState, handles server actions + SSE events |
71
+ | `components/features/control-center/control-center-inner.tsx` | Wires callbacks via `setCallbacks()`, passes nodes/edges to canvas |
72
+ | `components/features/features-canvas/features-canvas.tsx` | Renders React Flow; only adds `selectedFeatureId` highlighting |
73
+
74
+ ### Design Principles
75
+
76
+ 1. **Domain Maps are the source of truth** — all mutations go through Maps (featureMap, repoMap, pendingMap)
77
+ 2. **Edges are derived, never stored** — repo→feature edges from `repositoryPath` matching, dep edges from `parentNodeId`
78
+ 3. **Callbacks via ref** — `callbacksRef` + stable `useMemo([])` wrapper prevents circular re-renders
79
+ 4. **Layout in derivation** — `layoutWithDagre` runs inside `useMemo` after `deriveGraph()`
80
+ 5. **`onNodesChange` is a no-op** — since `nodesDraggable=false`, we ignore all React Flow changes
81
+
82
+ ### Mutation Paths
83
+
84
+ | Operation | Flow |
85
+ | ----------------- | ------------------------------------------------------------------------------------------------------- |
86
+ | SSE event | `useAgentEventsContext` → `updateFeature(nodeId, {state, lifecycle})` |
87
+ | Server prop sync | `useEffect` watches `initialNodeKey` → `reconcile(newNodes, newEdges)` |
88
+ | Optimistic create | `shep:feature-created` event → `createFeatureNode()` → `addPendingFeature()` |
89
+ | Delete feature | `handleDeleteFeature()` → `removeFeature()` → server action → `restoreFeature()` on error |
90
+ | Add repository | `handleAddRepository()` → `addRepository(tempId)` → server action → `replaceRepository(tempId, realId)` |
91
+
92
+ ### Reconciliation
93
+
94
+ `reconcile(newNodes, newEdges)` merges server data into domain Maps:
95
+
96
+ - Replaces featureMap and repoMap with fresh server data
97
+ - Preserves pending (creating) features in featureMap unless matched by `name + repositoryPath`
98
+ - Cleans pendingMap entries that now have a real counterpart in server data
99
+
100
+ ## SSE / Real-Time Update Architecture
101
+
102
+ ```
103
+ DB polling (500ms) -> /api/agent-events (SSE route)
104
+ -> Service Worker (public/agent-events-sw.js, single connection)
105
+ -> postMessage to all browser tabs
106
+ -> useAgentEvents hook (hooks/use-agent-events.ts)
107
+ -> AgentEventsProvider context (hooks/agent-events-provider.tsx)
108
+ -> useControlCenterState (SSE effect calls updateFeature)
109
+ -> domain Maps update -> derivation -> React Flow canvas
110
+ ```
111
+
112
+ ### SSE Key Files
113
+
114
+ | File | Purpose |
115
+ | ---------------------------------------------------------------- | ------------------------------------------------------ |
116
+ | `app/api/agent-events/route.ts` | SSE endpoint, polls DB every 500ms, emits delta events |
117
+ | `app/api/agent-events/health/route.ts` | Health check: `/api/agent-events/health` |
118
+ | `public/agent-events-sw.js` | Service Worker: multiplexes single SSE to all tabs |
119
+ | `hooks/use-agent-events.ts` | Client hook: registers with SW, receives events |
120
+ | `hooks/agent-events-provider.tsx` | React context wrapping `useAgentEvents` |
121
+ | `components/features/control-center/use-control-center-state.ts` | SSE effect calls `updateFeature()` on domain Maps |
122
+ | `components/common/feature-node/derive-feature-state.ts` | Maps event types/phases to UI state/lifecycle |
123
+
124
+ ### SSE Lifecycle Mappings
125
+
126
+ The SSE route maps `SdlcLifecycle` enum -> agent graph node names -> client `FeatureLifecyclePhase`:
127
+
128
+ ```
129
+ SdlcLifecycle.Started -> 'requirements' -> 'requirements'
130
+ SdlcLifecycle.Analyze -> 'analyze' -> 'requirements'
131
+ SdlcLifecycle.Requirements-> 'requirements' -> 'requirements'
132
+ SdlcLifecycle.Research -> 'research' -> 'research'
133
+ SdlcLifecycle.Planning -> 'plan' -> 'implementation'
134
+ SdlcLifecycle.Implementation -> 'implement' -> 'implementation'
135
+ SdlcLifecycle.Review -> 'merge' -> 'review'
136
+ SdlcLifecycle.Maintain -> 'maintain' -> 'maintain'
137
+ SdlcLifecycle.Blocked -> 'blocked' -> 'requirements'
138
+ ```
139
+
140
+ ## React Flow Rendering (CRITICAL)
141
+
142
+ React Flow v12 (`@xyflow/react` ^12.10.0) has specific behaviors that affect real-time updates:
143
+
144
+ - **Controlled mode**: `<ReactFlow nodes={nodes}>` passes nodes as props
145
+ - **Internal Zustand store**: React Flow syncs props to an internal `nodeLookup` Map via `StoreUpdater`
146
+ - **Memoized NodeWrapper**: Each node is wrapped in `memo(NodeWrapper)` which subscribes to store via `useStore(selector, shallow)`
147
+ - **NodeWrapper gets node from store**, NOT from props directly. It does `s.nodeLookup.get(id)` with `shallow` comparison
148
+ - **Single ReactFlowProvider**: There must be exactly ONE `ReactFlowProvider` ancestor. Multiple nested providers create separate stores
149
+
150
+ ### Circular Update Loop Prevention
151
+
152
+ With the domain-model-driven architecture, the circular update loop is prevented by design:
153
+
154
+ 1. **Callbacks are stable** — injected via `callbacksRef` + stable `useMemo([])` wrapper, so node objects don't change when callbacks change
155
+ 2. **`onNodesChange` is a no-op** — domain Maps are the source of truth, React Flow's internal changes are ignored
156
+ 3. **`enrichedNodes` only adds `selectedFeatureId`** — no callback injection in FeaturesCanvas
157
+
158
+ **NEVER** make `onNodesChange` apply `replace` changes back to state.
159
+
160
+ ## Testing Real-Time Updates
161
+
162
+ 1. Start the UI in the mode you want to test
163
+ 2. Check SSE health: `curl http://localhost:<port>/api/agent-events/health`
164
+ 3. Check SW status in browser: `navigator.serviceWorker.controller?.state` should be "activated"
165
+ 4. Trigger state changes: `pnpm dev:cli feat approve <id>` or start a new feature run
166
+ 5. Watch both **sidebar** and **canvas nodes** - they should both update
167
+ 6. Check browser console for errors
168
+ 7. Check server logs for `[SSE] emit:` messages confirming events are sent
169
+
170
+ ## Optimistic Feature Creation Flow
171
+
172
+ When a user creates a feature, the UI uses optimistic updates:
173
+
174
+ 1. **Create drawer** dispatches `shep:feature-created` → `createFeatureNode()` → `addPendingFeature()` adds temp node to pendingMap
175
+ 2. Drawer closes immediately via `router.push('/')`
176
+ 3. Server action `createFeature` runs in background → agent starts
177
+ 4. SSE events arrive with real feature ID (`feat-<uuid>`) — these update featureMap via `updateFeature()`
178
+ 5. **Server prop sync** (rerender with new initialNodes) → `reconcile()` detects matching real feature → removes pending from both featureMap and pendingMap
179
+
180
+ ### Key constraints
181
+
182
+ - **Temp node IDs don't match SSE events**: Optimistic nodes use `feature-<ts>` IDs, server uses `feat-<uuid>`. SSE events call `updateFeature('feat-<uuid>', ...)` which doesn't match the temp ID. The reconcile on next server prop update handles the swap.
183
+ - **Create drawer `isSubmitting`**: Must NOT reset until pathname leaves `/create`. Resetting in `.finally()` causes the drawer to flash open because `router.push('/')` is async and pathname hasn't changed yet.
184
+ - **Parallel routes preserve state**: The `CreateDrawerClient` component is NOT unmounted on navigation. `isOpen` is derived from pathname, not mount/unmount lifecycle.
185
+
186
+ ## Common Pitfalls
187
+
188
+ - **No events when nothing changes**: SSE only emits deltas. If no feature state changes, no events are sent. This is correct behavior.
189
+ - **Storybook mocks**: New server actions need mocks in `.storybook/mocks/app/actions/` or Storybook build breaks.
190
+ - **`output: 'standalone'`** in next.config.ts: Production builds use standalone mode. Route handlers are bundled differently.
191
+ - **Map insertion order affects dagre layout**: After remove+restore of a feature, the Map insertion order may change, causing slightly different dagre positions. This is expected behavior — don't write tests asserting exact position preservation across remove/restore cycles.
@@ -72,15 +72,40 @@ export async function createFeature(
72
72
 
73
73
  try {
74
74
  const createFeatureUseCase = resolve<CreateFeatureUseCase>('CreateFeatureUseCase');
75
- const result = await createFeatureUseCase.execute({
75
+
76
+ // Phase 1 (fast): create DB record with real UUID — returns immediately
77
+ const { feature, shouldSpawn } = await createFeatureUseCase.createRecord({
76
78
  userInput,
77
79
  repositoryPath,
78
80
  approvalGates: gates,
79
81
  push: push ?? false,
80
82
  openPr: openPr ?? false,
81
83
  ...(parentId ? { parentId } : {}),
84
+ name,
85
+ description,
82
86
  });
83
- return { feature: result.feature };
87
+
88
+ // Phase 2 (background): metadata generation, worktree, spec, agent spawn
89
+ // Fire-and-forget — the UI gets the real feature ID immediately
90
+ createFeatureUseCase
91
+ .initializeAndSpawn(
92
+ feature,
93
+ {
94
+ userInput,
95
+ repositoryPath,
96
+ approvalGates: gates,
97
+ push: push ?? false,
98
+ openPr: openPr ?? false,
99
+ ...(parentId ? { parentId } : {}),
100
+ },
101
+ shouldSpawn
102
+ )
103
+ .catch((err: unknown) => {
104
+ // eslint-disable-next-line no-console
105
+ console.error('[createFeature] initializeAndSpawn failed:', err);
106
+ });
107
+
108
+ return { feature };
84
109
  } catch (error: unknown) {
85
110
  const message = error instanceof Error ? error.message : 'Failed to create feature';
86
111
  return { error: message };
@@ -0,0 +1,18 @@
1
+ 'use server';
2
+
3
+ import { resolve } from '@/lib/server-container';
4
+ import type { IFeatureRepository } from '@shepai/core/application/ports/output/repositories/feature-repository.interface';
5
+
6
+ /**
7
+ * Lightweight server action to fetch a single feature's name and description.
8
+ * Used by the SSE effect to update node metadata after AI metadata generation
9
+ * without a full graph reconcile (which can overwrite SSE-driven state).
10
+ */
11
+ export async function getFeatureMetadata(
12
+ featureId: string
13
+ ): Promise<{ name: string; description: string } | null> {
14
+ const featureRepo = resolve<IFeatureRepository>('IFeatureRepository');
15
+ const feature = await featureRepo.findById(featureId);
16
+ if (!feature) return null;
17
+ return { name: feature.name, description: feature.description };
18
+ }
@@ -0,0 +1,12 @@
1
+ 'use server';
2
+
3
+ import { getGraphData } from '@/app/(dashboard)/get-graph-data';
4
+
5
+ /**
6
+ * Server action that fetches fresh graph nodes and edges.
7
+ * Used as a lightweight polling fallback for active features,
8
+ * avoiding full router.refresh() page re-renders.
9
+ */
10
+ export async function fetchGraphData() {
11
+ return getGraphData();
12
+ }
@@ -44,13 +44,16 @@ interface CachedFeatureState {
44
44
  * Maps SdlcLifecycle values to agent graph node names so the client
45
45
  * can derive the correct FeatureLifecyclePhase via mapPhaseNameToLifecycle().
46
46
  */
47
- const LIFECYCLE_TO_NODE: Partial<Record<SdlcLifecycle, string>> = {
47
+ const LIFECYCLE_TO_NODE: Record<SdlcLifecycle, string> = {
48
+ [SdlcLifecycle.Started]: 'requirements',
48
49
  [SdlcLifecycle.Analyze]: 'analyze',
49
50
  [SdlcLifecycle.Requirements]: 'requirements',
50
51
  [SdlcLifecycle.Research]: 'research',
51
52
  [SdlcLifecycle.Planning]: 'plan',
52
53
  [SdlcLifecycle.Implementation]: 'implement',
53
54
  [SdlcLifecycle.Review]: 'merge',
55
+ [SdlcLifecycle.Maintain]: 'maintain',
56
+ [SdlcLifecycle.Blocked]: 'blocked',
54
57
  };
55
58
 
56
59
  const STATUS_TO_EVENT: Partial<
@@ -188,6 +191,23 @@ export function GET(request: Request): Response {
188
191
  }
189
192
  }
190
193
 
194
+ // Check for feature name change (AI metadata generation updates name)
195
+ if (prev.featureName !== feature.name) {
196
+ prev.featureName = feature.name;
197
+ const nodeName =
198
+ LIFECYCLE_TO_NODE[feature.lifecycle as SdlcLifecycle] ?? 'requirements';
199
+ emitEvent({
200
+ eventType: NotificationEventType.PhaseCompleted,
201
+ agentRunId: run.id,
202
+ featureId: feature.id,
203
+ featureName: feature.name,
204
+ phaseName: nodeName,
205
+ message: `Feature metadata updated`,
206
+ severity: NotificationSeverity.Info,
207
+ timestamp: new Date().toISOString(),
208
+ });
209
+ }
210
+
191
211
  // Check for lifecycle change (agent stays "running" but moves through phases)
192
212
  if (prev.lifecycle !== feature.lifecycle) {
193
213
  prev.lifecycle = feature.lifecycle;
@@ -0,0 +1 @@
1
+ export { AddRepositoryButton } from './add-repository-button';
@@ -8,7 +8,6 @@ import { FeatureCreateDrawer } from '@/components/common/feature-create-drawer';
8
8
  import type { FeatureCreatePayload } from '@/components/common/feature-create-drawer';
9
9
  import type { ParentFeatureOption } from '@/components/common/feature-create-drawer/feature-create-drawer';
10
10
  import type { WorkflowDefaults } from '@/app/actions/get-workflow-defaults';
11
- import { useSoundAction } from '@/hooks/use-sound-action';
12
11
 
13
12
  export interface CreateDrawerClientProps {
14
13
  repositoryPath: string;
@@ -24,7 +23,6 @@ export function CreateDrawerClient({
24
23
  workflowDefaults,
25
24
  }: CreateDrawerClientProps) {
26
25
  const router = useRouter();
27
- const createSound = useSoundAction('create');
28
26
  const [isSubmitting, setIsSubmitting] = useState(false);
29
27
 
30
28
  // Derive open state from the URL. Next.js parallel routes preserve slot
@@ -34,15 +32,17 @@ export function CreateDrawerClient({
34
32
  // When submitting, force the drawer closed immediately — router.push('/')
35
33
  // is async and the pathname may not update before the next render.
36
34
  const pathname = usePathname();
37
- const isOpen = !isSubmitting && pathname.startsWith('/create');
35
+ const isOnCreateRoute = pathname.startsWith('/create');
36
+ const isOpen = !isSubmitting && isOnCreateRoute;
38
37
 
39
- // Safety net: if the drawer is closed (e.g. via form submit + isSubmitting)
40
- // but router.push('/') hasn't taken effect yet, force-clear the route.
38
+ // Reset isSubmitting once the route has actually changed away from /create,
39
+ // so the drawer can reopen on future visits. Without this, isSubmitting
40
+ // would stay true forever since parallel routes preserve component state.
41
41
  useEffect(() => {
42
- if (!isOpen && pathname.startsWith('/create')) {
43
- router.replace('/');
42
+ if (!isOnCreateRoute && isSubmitting) {
43
+ setIsSubmitting(false);
44
44
  }
45
- }, [isOpen, pathname, router]);
45
+ }, [isOnCreateRoute, isSubmitting]);
46
46
 
47
47
  const onClose = useCallback(() => {
48
48
  router.push('/');
@@ -52,41 +52,38 @@ export function CreateDrawerClient({
52
52
  (data: FeatureCreatePayload) => {
53
53
  setIsSubmitting(true);
54
54
 
55
- // Dispatch event for optimistic canvas update before navigating
56
- window.dispatchEvent(
57
- new CustomEvent('shep:feature-created', {
58
- detail: {
59
- name: data.name,
60
- description: data.description,
61
- repositoryPath: data.repositoryPath,
62
- parentId: data.parentId,
63
- },
64
- })
65
- );
66
-
67
55
  // Close the drawer immediately for responsive UI
68
56
  router.push('/');
69
57
 
70
- // Fire server action in the background
58
+ // Server action Phase 1 returns fast with real feature ID (DB record created)
59
+ // Phase 2 (metadata, worktree, agent) runs in background on server
71
60
  createFeature(data)
72
61
  .then((result) => {
73
62
  if (result.error) {
74
63
  toast.error(result.error);
75
- // Dispatch rollback event
76
64
  window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
77
65
  return;
78
66
  }
79
- createSound.play();
67
+ // Dispatch event with real feature ID so control center adds it to featureMap
68
+ window.dispatchEvent(
69
+ new CustomEvent('shep:feature-created', {
70
+ detail: {
71
+ featureId: result.feature!.id,
72
+ name: result.feature!.name,
73
+ description: result.feature!.description,
74
+ repositoryPath: result.feature!.repositoryPath,
75
+ parentId: data.parentId,
76
+ },
77
+ })
78
+ );
80
79
  })
81
80
  .catch(() => {
82
81
  toast.error('Failed to create feature');
83
82
  window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
84
- })
85
- .finally(() => {
86
83
  setIsSubmitting(false);
87
84
  });
88
85
  },
89
- [router, createSound]
86
+ [router]
90
87
  );
91
88
 
92
89
  return (
@@ -8,7 +8,7 @@ import type {
8
8
  PrdApprovalPayload,
9
9
  QuestionSelectionChange,
10
10
  } from '@shepai/core/domain/generated/output';
11
- import { PrStatus } from '@shepai/core/domain/generated/output';
11
+ import { PrStatus, NotificationEventType } from '@shepai/core/domain/generated/output';
12
12
  import { approveFeature } from '@/app/actions/approve-feature';
13
13
  import { rejectFeature } from '@/app/actions/reject-feature';
14
14
  import { getFeatureArtifact } from '@/app/actions/get-feature-artifact';
@@ -94,9 +94,22 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
94
94
  const newEvents = events.slice(processedCountRef.current);
95
95
  processedCountRef.current = events.length;
96
96
 
97
+ // PhaseCompleted must NOT set state when WaitingApproval is in the same poll batch.
98
+ // But when it arrives without WaitingApproval (e.g. post-approval), allow it as
99
+ // a fallback for missed AgentStarted events.
100
+ const waitingApprovalInBatch = newEvents.some(
101
+ (e) =>
102
+ e.featureId === featureNode.featureId &&
103
+ e.eventType === NotificationEventType.WaitingApproval
104
+ );
105
+
97
106
  for (const event of newEvents) {
98
107
  if (event.featureId !== featureNode.featureId) continue;
99
- const newState = mapEventTypeToState(event.eventType);
108
+
109
+ const newState =
110
+ event.eventType === NotificationEventType.PhaseCompleted && waitingApprovalInBatch
111
+ ? undefined
112
+ : mapEventTypeToState(event.eventType);
100
113
  const newLifecycle = mapPhaseNameToLifecycle(event.phaseName);
101
114
 
102
115
  // Trigger a server refresh to get the latest drawer view,
@@ -104,24 +117,26 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
104
117
  // to avoid the refresh interfering with the reject handler's navigation.
105
118
  if (!isDirtyRef.current && !isRejectingRef.current) router.refresh();
106
119
 
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: {
120
+ if (newState !== undefined || newLifecycle !== undefined) {
121
+ // Optimistically update the node data AND re-derive the view type so the
122
+ // drawer switches immediately (e.g. prd-review → feature when agent resumes)
123
+ // without waiting for the router.refresh() round-trip.
124
+ setView((prev) => {
125
+ if (
126
+ prev.type !== 'feature' &&
127
+ prev.type !== 'prd-review' &&
128
+ prev.type !== 'tech-review' &&
129
+ prev.type !== 'merge-review'
130
+ )
131
+ return prev;
132
+ const updatedNode = {
119
133
  ...prev.node,
120
- state: newState,
134
+ ...(newState !== undefined && { state: newState }),
121
135
  ...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
122
- },
123
- };
124
- });
136
+ };
137
+ return { ...prev, type: deriveViewType(updatedNode), node: updatedNode };
138
+ });
139
+ }
125
140
  }
126
141
  }, [events, featureNode, router]);
127
142
 
@@ -765,3 +780,14 @@ function DetailRow({ label, value }: { label: string; value: string }) {
765
780
  </div>
766
781
  );
767
782
  }
783
+
784
+ /** Mirrors computeDrawerView logic — derives view type from live node data. */
785
+ function deriveViewType(
786
+ node: FeatureNodeData
787
+ ): 'feature' | 'prd-review' | 'tech-review' | 'merge-review' {
788
+ if (node.lifecycle === 'requirements' && node.state === 'action-required') return 'prd-review';
789
+ if (node.lifecycle === 'implementation' && node.state === 'action-required') return 'tech-review';
790
+ if (node.lifecycle === 'review' && (node.state === 'action-required' || node.state === 'error'))
791
+ return 'merge-review';
792
+ return 'feature';
793
+ }
@@ -120,6 +120,8 @@ const phaseNameToLifecycle: Record<string, FeatureLifecyclePhase> = {
120
120
  plan: 'implementation',
121
121
  implement: 'implementation',
122
122
  merge: 'review',
123
+ maintain: 'maintain',
124
+ blocked: 'requirements',
123
125
  };
124
126
 
125
127
  export function mapPhaseNameToLifecycle(
@@ -4,11 +4,7 @@ export {
4
4
  computeDrawerView,
5
5
  type DrawerView,
6
6
  } from './control-center-drawer';
7
- export {
8
- AddRepositoryNode,
9
- type AddRepositoryNodeData,
10
- type AddRepositoryNodeType,
11
- } from './add-repository-node';
7
+ export { AddRepositoryButton } from './add-repository-button';
12
8
  export { ElapsedTime, formatElapsed } from './elapsed-time';
13
9
  export { EmptyState, type EmptyStateProps } from './empty-state';
14
10
  export {
@@ -35,7 +31,6 @@ export {
35
31
  export { FeatureStatusBadges, type FeatureStatusBadgesProps } from './feature-status-badges';
36
32
  export { FeatureStatusGroup, type FeatureStatusGroupProps } from './feature-status-group';
37
33
  export { LoadingSkeleton } from './loading-skeleton';
38
- export { NotificationPermissionBanner } from './notification-permission-banner';
39
34
  export {
40
35
  RepositoryNode,
41
36
  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>
@@ -28,16 +28,3 @@ export const Default: Story = {
28
28
  label: 'Features',
29
29
  },
30
30
  };
31
-
32
- function noop() {
33
- // Intentional no-op for Storybook interaction demos
34
- return;
35
- }
36
-
37
- export const WithActions: Story = {
38
- args: {
39
- label: 'Features',
40
- onFolderClick: noop,
41
- onMenuClick: noop,
42
- },
43
- };
@@ -1,62 +1,18 @@
1
1
  'use client';
2
2
 
3
- import { Folder, GripHorizontal } from 'lucide-react';
4
3
  import { SidebarGroup } from '@/components/ui/sidebar';
5
- import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
6
- import { useSidebar } from '@/components/ui/sidebar';
7
4
  import { cn } from '@/lib/utils';
8
5
 
9
6
  export interface SidebarSectionHeaderProps {
10
7
  label: string;
11
- onFolderClick?: () => void;
12
- onMenuClick?: () => void;
13
8
  className?: string;
14
9
  }
15
10
 
16
- export function SidebarSectionHeader({
17
- label,
18
- onFolderClick,
19
- onMenuClick,
20
- className,
21
- }: SidebarSectionHeaderProps) {
22
- const { state, isMobile } = useSidebar();
23
-
11
+ export function SidebarSectionHeader({ label, className }: SidebarSectionHeaderProps) {
24
12
  return (
25
13
  <SidebarGroup data-testid="sidebar-section-header" className={cn('px-2 py-1', className)}>
26
14
  <div className="text-sidebar-foreground flex h-7 w-full shrink-0 items-center px-2 text-sm font-medium">
27
15
  <span className="min-w-0 flex-1 truncate">{label}</span>
28
- <span className="text-sidebar-foreground/70 flex shrink-0 items-center gap-0.5">
29
- <Tooltip>
30
- <TooltipTrigger asChild>
31
- <button
32
- type="button"
33
- onClick={onFolderClick}
34
- className="ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex size-7 items-center justify-center rounded-md p-0 outline-hidden transition-colors focus-visible:ring-2 [&>svg]:size-4"
35
- aria-label="Open features folder"
36
- >
37
- <Folder className="size-4" />
38
- </button>
39
- </TooltipTrigger>
40
- <TooltipContent side="right" align="center" hidden={state !== 'collapsed' || isMobile}>
41
- Open features folder
42
- </TooltipContent>
43
- </Tooltip>
44
- <Tooltip>
45
- <TooltipTrigger asChild>
46
- <button
47
- type="button"
48
- onClick={onMenuClick}
49
- className="ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex size-7 items-center justify-center rounded-md p-0 outline-hidden transition-colors focus-visible:ring-2 [&>svg]:size-4"
50
- aria-label="Features options"
51
- >
52
- <GripHorizontal className="size-4" />
53
- </button>
54
- </TooltipTrigger>
55
- <TooltipContent side="right" align="center" hidden={state !== 'collapsed' || isMobile}>
56
- Features options
57
- </TooltipContent>
58
- </Tooltip>
59
- </span>
60
16
  </div>
61
17
  </SidebarGroup>
62
18
  );
@@ -3,7 +3,7 @@
3
3
  import { useState, useCallback } from 'react';
4
4
  import { Github, Plus, TerminalSquare, Copy, Check, Loader2 } from 'lucide-react';
5
5
  import { cn } from '@/lib/utils';
6
- import { pickFolder } from '@/components/common/add-repository-node/pick-folder';
6
+ import { pickFolder } from '@/components/common/add-repository-button/pick-folder';
7
7
 
8
8
  export interface ControlCenterEmptyStateProps {
9
9
  onRepositorySelect?: (path: string) => void;