@shepai/cli 1.72.9 → 1.73.0-pr222.ef53005

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 (449) hide show
  1. package/dist/packages/core/src/application/ports/output/agents/agent-executor-provider.interface.d.ts +1 -1
  2. package/dist/packages/core/src/application/ports/output/agents/agent-executor-provider.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +20 -1
  4. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  5. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +68 -41
  6. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +10 -0
  7. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
  8. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/di/container.js +2 -1
  10. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts +4 -2
  11. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.js +8 -4
  13. package/dist/packages/core/src/infrastructure/services/agents/common/agent-runner.service.js +1 -1
  14. package/dist/packages/core/src/infrastructure/services/agents/common/structured-agent-caller.service.js +1 -1
  15. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +1 -1
  16. package/dist/packages/core/src/infrastructure/services/notifications/notification.service.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/services/notifications/notification.service.js +2 -4
  18. package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
  19. package/dist/src/presentation/web/app/actions/create-feature.js +20 -2
  20. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts +10 -0
  21. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts.map +1 -0
  22. package/dist/src/presentation/web/app/actions/get-feature-metadata.js +14 -0
  23. package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
  24. package/dist/src/presentation/web/app/api/agent-events/route.js +15 -0
  25. package/dist/src/presentation/web/app/build-feature-node-data.d.ts.map +1 -1
  26. package/dist/src/presentation/web/app/build-feature-node-data.js +2 -26
  27. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
  28. package/dist/src/presentation/web/app/build-graph-nodes.js +2 -26
  29. package/dist/src/presentation/web/app/layout.js +1 -1
  30. package/dist/src/presentation/web/components/common/add-repository-button/add-repository-button.d.ts.map +1 -0
  31. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts +2 -0
  32. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts.map +1 -0
  33. package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/index.js +0 -1
  34. package/dist/src/presentation/web/components/common/add-repository-button/pick-folder.d.ts.map +1 -0
  35. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.d.ts.map +1 -1
  36. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.js +13 -18
  37. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts +2 -0
  38. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts.map +1 -1
  39. package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.js +11 -11
  40. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  41. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +83 -144
  42. package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts +0 -1
  43. package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts.map +1 -1
  44. package/dist/src/presentation/web/components/common/control-center-drawer/index.js +0 -1
  45. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts +13 -0
  46. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts.map +1 -0
  47. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.js +46 -0
  48. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map +1 -1
  49. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.js +7 -10
  50. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts +25 -0
  51. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
  52. package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +45 -2
  53. package/dist/src/presentation/web/components/common/index.d.ts +2 -3
  54. package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
  55. package/dist/src/presentation/web/components/common/index.js +2 -3
  56. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
  57. package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.d.ts.map +1 -1
  58. package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.js +14 -39
  59. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.d.ts +1 -3
  60. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.d.ts.map +1 -1
  61. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.js +3 -7
  62. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.d.ts +0 -1
  63. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.d.ts.map +1 -1
  64. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.js +0 -11
  65. package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.js +1 -1
  66. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  67. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +31 -14
  68. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts +0 -11
  69. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
  70. package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +2 -37
  71. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +8 -0
  72. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  73. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +177 -350
  74. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts +2 -10
  75. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
  76. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +11 -54
  77. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts.map +1 -1
  78. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.js +0 -46
  79. package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +1 -1
  80. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts +1 -3
  81. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts.map +1 -1
  82. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.js +2 -2
  83. package/dist/src/presentation/web/components/ui/alert-dialog.d.ts.map +1 -1
  84. package/dist/src/presentation/web/components/ui/alert-dialog.js +2 -2
  85. package/dist/src/presentation/web/components/ui/dialog.d.ts.map +1 -1
  86. package/dist/src/presentation/web/components/ui/dialog.js +2 -2
  87. package/dist/src/presentation/web/components/ui/scroll-area.js +1 -1
  88. package/dist/src/presentation/web/hooks/agent-events-provider.d.ts.map +1 -1
  89. package/dist/src/presentation/web/hooks/agent-events-provider.js +3 -2
  90. package/dist/src/presentation/web/hooks/use-agent-events.d.ts.map +1 -1
  91. package/dist/src/presentation/web/hooks/use-agent-events.js +19 -5
  92. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  93. package/dist/src/presentation/web/hooks/use-deploy-action.js +10 -13
  94. package/dist/src/presentation/web/hooks/use-graph-state.d.ts +42 -0
  95. package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -0
  96. package/dist/src/presentation/web/hooks/use-graph-state.js +257 -0
  97. package/dist/src/presentation/web/hooks/use-notifications.d.ts +1 -5
  98. package/dist/src/presentation/web/hooks/use-notifications.d.ts.map +1 -1
  99. package/dist/src/presentation/web/hooks/use-notifications.js +1 -26
  100. package/dist/src/presentation/web/hooks/use-notifications.stories.d.ts.map +1 -1
  101. package/dist/src/presentation/web/hooks/use-notifications.stories.js +28 -38
  102. package/dist/src/presentation/web/lib/derive-graph.d.ts +52 -0
  103. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -0
  104. package/dist/src/presentation/web/lib/derive-graph.js +126 -0
  105. package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
  106. package/dist/src/presentation/web/lib/layout-with-dagre.js +1 -2
  107. package/dist/src/presentation/web/lib/logger.d.ts +7 -0
  108. package/dist/src/presentation/web/lib/logger.d.ts.map +1 -0
  109. package/dist/src/presentation/web/lib/logger.js +11 -0
  110. package/dist/tsconfig.build.tsbuildinfo +1 -1
  111. package/package.json +1 -1
  112. package/web/.next/BUILD_ID +1 -1
  113. package/web/.next/build-manifest.json +2 -2
  114. package/web/.next/cache/.previewinfo +1 -1
  115. package/web/.next/cache/.rscinfo +1 -1
  116. package/web/.next/cache/.tsbuildinfo +1 -1
  117. package/web/.next/cache/config.json +3 -3
  118. package/web/.next/fallback-build-manifest.json +2 -2
  119. package/web/.next/prerender-manifest.json +3 -3
  120. package/web/.next/required-server-files.js +1 -1
  121. package/web/.next/required-server-files.json +1 -1
  122. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +45 -30
  123. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
  124. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  125. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  126. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +51 -36
  127. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  128. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  129. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  130. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  131. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
  132. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  133. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  134. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +45 -30
  135. package/web/.next/server/app/(dashboard)/create/page.js +1 -1
  136. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  137. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  138. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +51 -36
  139. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  140. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  141. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  142. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +41 -26
  143. package/web/.next/server/app/(dashboard)/page.js +1 -1
  144. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  145. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  146. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  147. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
  148. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  149. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  150. package/web/.next/server/app/_global-error.html +2 -2
  151. package/web/.next/server/app/_global-error.rsc +1 -1
  152. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  153. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  154. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  155. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  156. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  157. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  158. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  159. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  160. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  161. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  162. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  163. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  164. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  165. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  166. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  167. package/web/.next/server/app/version/page.js.nft.json +1 -1
  168. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  169. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  170. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  171. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  172. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  173. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +3 -0
  174. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -0
  175. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +3 -0
  176. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +1 -0
  177. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  178. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  179. package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
  180. package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js.map +1 -1
  181. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  182. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  183. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  184. package/web/.next/server/chunks/ssr/{[root-of-the-server]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
  185. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -0
  186. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  187. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  188. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  189. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js.map +1 -1
  190. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  191. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  192. 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
  193. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -0
  194. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  195. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  196. package/web/.next/server/chunks/ssr/_07c2a32a._.js +1 -1
  197. package/web/.next/server/chunks/ssr/_07c2a32a._.js.map +1 -1
  198. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  199. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  200. package/web/.next/server/chunks/ssr/_4f7c70c9._.js +6 -0
  201. package/web/.next/server/chunks/ssr/_4f7c70c9._.js.map +1 -0
  202. package/web/.next/server/chunks/ssr/{_1978f325._.js → _5ee4f5a7._.js} +2 -2
  203. package/web/.next/server/chunks/ssr/_5ee4f5a7._.js.map +1 -0
  204. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  205. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  206. package/web/.next/server/chunks/ssr/_6e08ce21._.js +1 -1
  207. package/web/.next/server/chunks/ssr/_6e08ce21._.js.map +1 -1
  208. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  209. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  210. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  211. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  212. package/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js +8 -0
  213. package/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js.map +1 -0
  214. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5ea689db._.js → server/chunks/ssr/src_presentation_web_30d7eeda._.js} +2 -2
  215. package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js.map → src_presentation_web_30d7eeda._.js.map} +1 -1
  216. package/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js +8 -0
  217. package/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js.map +1 -0
  218. package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js → src_presentation_web_565a14f8._.js} +2 -2
  219. package/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js.map → src_presentation_web_565a14f8._.js.map} +1 -1
  220. package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
  221. package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js.map +1 -1
  222. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +3 -0
  223. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -0
  224. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +1 -1
  225. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js.map +1 -1
  226. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  227. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  228. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  229. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  230. package/web/.next/server/pages/500.html +2 -2
  231. package/web/.next/server/server-reference-manifest.js +1 -1
  232. package/web/.next/server/server-reference-manifest.json +183 -126
  233. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  234. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  235. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  236. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  237. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +45 -30
  238. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
  239. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  240. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  241. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +51 -36
  242. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  243. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  244. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  245. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  246. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
  247. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  248. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  249. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +45 -30
  250. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +1 -1
  251. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  252. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  253. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +51 -36
  254. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  255. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  256. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  257. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +41 -26
  258. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +1 -1
  259. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  260. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  261. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  262. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
  263. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  264. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  265. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  266. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  267. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  268. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  269. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  270. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  271. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  272. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  273. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  274. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  275. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  276. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  277. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  278. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  279. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  280. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  281. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  282. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  283. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  284. package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  285. 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
  286. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +3 -0
  287. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +3 -0
  288. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  289. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
  290. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  291. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  292. 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
  293. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  294. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  295. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  296. 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
  297. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  298. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_07c2a32a._.js +1 -1
  299. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  300. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_4f7c70c9._.js +6 -0
  301. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_1978f325._.js → _5ee4f5a7._.js} +2 -2
  302. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  303. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6e08ce21._.js +1 -1
  304. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  305. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  306. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js +8 -0
  307. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js → src_presentation_web_30d7eeda._.js} +2 -2
  308. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js +8 -0
  309. package/web/.next/{server/chunks/ssr/src_presentation_web_7188a290._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_565a14f8._.js} +2 -2
  310. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
  311. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +3 -0
  312. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +1 -1
  313. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  314. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  315. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  316. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  317. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +183 -126
  318. package/web/.next/standalone/src/presentation/web/CLAUDE.md +77 -33
  319. package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +27 -2
  320. package/web/.next/standalone/src/presentation/web/app/actions/get-feature-metadata.ts +18 -0
  321. package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +17 -0
  322. package/web/.next/standalone/src/presentation/web/app/build-feature-node-data.ts +3 -30
  323. package/web/.next/standalone/src/presentation/web/app/build-graph-nodes.ts +3 -30
  324. package/web/.next/standalone/src/presentation/web/app/layout.tsx +1 -1
  325. package/web/.next/standalone/src/presentation/web/components/common/add-repository-button/index.ts +1 -0
  326. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +15 -21
  327. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/drawer-view.ts +12 -13
  328. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +116 -141
  329. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/index.ts +0 -1
  330. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.ts +56 -0
  331. package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/use-feature-actions.ts +6 -7
  332. package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +63 -2
  333. package/web/.next/standalone/src/presentation/web/components/common/index.ts +2 -12
  334. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +2 -2
  335. package/web/.next/standalone/src/presentation/web/components/common/repository-node/use-repository-actions.ts +29 -54
  336. package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.tsx +0 -13
  337. package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.tsx +1 -45
  338. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-empty-state.tsx +1 -1
  339. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +43 -36
  340. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +2 -41
  341. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +226 -438
  342. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx +0 -48
  343. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +13 -76
  344. package/web/.next/standalone/src/presentation/web/components/layouts/app-shell/app-shell.tsx +1 -1
  345. package/web/.next/standalone/src/presentation/web/components/layouts/app-sidebar/app-sidebar.tsx +2 -14
  346. package/web/.next/standalone/src/presentation/web/components/ui/alert-dialog.tsx +2 -5
  347. package/web/.next/standalone/src/presentation/web/components/ui/dialog.tsx +2 -5
  348. package/web/.next/standalone/src/presentation/web/components/ui/scroll-area.tsx +1 -1
  349. package/web/.next/standalone/src/presentation/web/hooks/agent-events-provider.tsx +7 -2
  350. package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +20 -5
  351. package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +13 -13
  352. package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +376 -0
  353. package/web/.next/standalone/src/presentation/web/hooks/use-notifications.stories.tsx +2 -30
  354. package/web/.next/standalone/src/presentation/web/hooks/use-notifications.ts +2 -36
  355. package/web/.next/standalone/src/presentation/web/lib/derive-graph.ts +178 -0
  356. package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +1 -2
  357. package/web/.next/standalone/src/presentation/web/lib/logger.ts +12 -0
  358. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  359. package/web/.next/static/chunks/0cfed3c69c312c09.js +4 -0
  360. package/web/.next/static/chunks/0ffccd7be73305c8.css +2 -0
  361. package/web/.next/static/chunks/{c92e1360ada8ca94.js → 1f5c93a8b939416d.js} +2 -2
  362. package/web/.next/static/chunks/3f205fd6adbfd20a.js +7 -0
  363. package/web/.next/static/chunks/4c63764a2d06e45e.js +1 -0
  364. package/web/.next/static/chunks/{d4492cd12fdf0891.js → 89e74b1c3eb43b03.js} +1 -1
  365. package/web/.next/static/chunks/{c83897e9213881bf.js → 937d7d4d58942872.js} +1 -1
  366. package/web/.next/static/chunks/95e3f47abe8032e5.js +1 -0
  367. package/web/.next/static/chunks/b835e88cdc8c63d2.js +1 -0
  368. package/web/.next/static/chunks/cb41849bcfaa304e.js +1 -0
  369. package/web/.next/static/chunks/e2342af6b68c94c1.js +1 -0
  370. package/web/.next/static/chunks/ed69d6b172ae2bfe.js +1 -0
  371. package/web/.next/static/chunks/{64850cf4081a2950.js → fd46753cd16664a9.js} +1 -1
  372. package/web/.next/trace +1 -1
  373. package/web/.next/trace-build +1 -1
  374. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-button.d.ts.map +0 -1
  375. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts +0 -7
  376. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts.map +0 -1
  377. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.js +0 -1
  378. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts +0 -6
  379. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts.map +0 -1
  380. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.js +0 -23
  381. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts +0 -10
  382. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts.map +0 -1
  383. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.js +0 -33
  384. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts +0 -4
  385. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts.map +0 -1
  386. package/dist/src/presentation/web/components/common/add-repository-node/pick-folder.d.ts.map +0 -1
  387. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts +0 -12
  388. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts.map +0 -1
  389. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js +0 -337
  390. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts +0 -33
  391. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts.map +0 -1
  392. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.js +0 -214
  393. package/dist/src/presentation/web/components/common/notification-permission-banner/index.d.ts +0 -2
  394. package/dist/src/presentation/web/components/common/notification-permission-banner/index.d.ts.map +0 -1
  395. package/dist/src/presentation/web/components/common/notification-permission-banner/index.js +0 -1
  396. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.d.ts +0 -2
  397. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.d.ts.map +0 -1
  398. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.js +0 -33
  399. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.d.ts +0 -6
  400. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.d.ts.map +0 -1
  401. package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.js +0 -24
  402. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
  403. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js.map +0 -1
  404. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
  405. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js.map +0 -1
  406. package/web/.next/server/chunks/ssr/[root-of-the-server]__cbae9863._.js.map +0 -1
  407. package/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js.map +0 -1
  408. package/web/.next/server/chunks/ssr/_1978f325._.js.map +0 -1
  409. package/web/.next/server/chunks/ssr/_38d24563._.js +0 -6
  410. package/web/.next/server/chunks/ssr/_38d24563._.js.map +0 -1
  411. package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
  412. package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js.map +0 -1
  413. package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
  414. package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js.map +0 -1
  415. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js +0 -3
  416. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js.map +0 -1
  417. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
  418. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
  419. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_38d24563._.js +0 -6
  420. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
  421. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
  422. 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
  423. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node-config.ts +0 -8
  424. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.tsx +0 -70
  425. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.tsx +0 -49
  426. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/index.ts +0 -3
  427. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.tsx +0 -293
  428. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx +0 -745
  429. package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/index.ts +0 -1
  430. package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.tsx +0 -52
  431. package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.tsx +0 -55
  432. package/web/.next/static/chunks/0c54314c8c9c9739.js +0 -7
  433. package/web/.next/static/chunks/10cd08dae8c210ff.js +0 -1
  434. package/web/.next/static/chunks/15bf7ee1da91eb46.js +0 -4
  435. package/web/.next/static/chunks/3c79bca4d3f18f66.js +0 -1
  436. package/web/.next/static/chunks/67f2a7a5e8dc358a.css +0 -2
  437. package/web/.next/static/chunks/6cc840197626843b.js +0 -1
  438. package/web/.next/static/chunks/e3239b6c18cf8b96.js +0 -1
  439. package/web/.next/static/chunks/e9cc53ce8a7bdea6.js +0 -1
  440. package/web/.next/static/chunks/ef916db8c537211a.js +0 -1
  441. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.d.ts +0 -0
  442. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.js +0 -0
  443. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.d.ts +0 -0
  444. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.js +0 -0
  445. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.tsx +0 -0
  446. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.ts +0 -0
  447. /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 0yTXyENV4ko7rpM4-3vV8}/_buildManifest.js +0 -0
  448. /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 0yTXyENV4ko7rpM4-3vV8}/_clientMiddlewareManifest.json +0 -0
  449. /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 0yTXyENV4ko7rpM4-3vV8}/_ssgManifest.js +0 -0
@@ -1,100 +1,59 @@
1
1
  'use client';
2
- import { useState, useCallback, useEffect, useRef } from 'react';
2
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
3
3
  import { useRouter } from 'next/navigation';
4
4
  import { toast } from 'sonner';
5
- import { applyNodeChanges } from '@xyflow/react';
6
5
  import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS, } from '../../../lib/layout-with-dagre.js';
7
6
  import { deleteFeature } from '../../../app/actions/delete-feature.js';
8
7
  import { addRepository } from '../../../app/actions/add-repository.js';
9
8
  import { deleteRepository } from '../../../app/actions/delete-repository.js';
9
+ import { getFeatureMetadata } from '../../../app/actions/get-feature-metadata.js';
10
10
  import { fetchGraphData } from '../../../app/actions/get-graph-data.js';
11
11
  import { useAgentEventsContext } from '../../../hooks/agent-events-provider.js';
12
12
  import { useSoundAction } from '../../../hooks/use-sound-action.js';
13
- import { mapEventTypeToState, mapPhaseNameToLifecycle, } from '../../common/feature-node/derive-feature-state.js';
13
+ import { createLogger } from '../../../lib/logger.js';
14
+ import { mapEventTypeToState, resolveSseEventUpdates, } from '../../common/feature-node/derive-feature-state.js';
15
+ import { useGraphState } from '../../../hooks/use-graph-state.js';
16
+ const log = createLogger('[Polling]');
17
+ const POLL_INTERVAL_MS = 3_000;
18
+ /** Must match the message string emitted by the SSE route in agent-events/route.ts */
19
+ const METADATA_UPDATED_MESSAGE = 'Feature metadata updated';
14
20
  let nextFeatureId = 0;
15
21
  export function useControlCenterState(initialNodes, initialEdges) {
16
22
  const router = useRouter();
17
- const [nodes, setNodes] = useState(initialNodes);
18
- // eslint-disable-next-line react/hook-use-state -- raw setter renamed; public setEdges wrapper keeps edgesRef in sync
19
- const [edges, setEdgesRaw] = useState(initialEdges);
20
- const edgesRef = useRef(initialEdges);
21
- // Wrapper that keeps edgesRef in sync with edges state, allowing
22
- // createFeatureNode to read current edges without a closure dependency.
23
- const setEdges = useCallback((update) => {
24
- setEdgesRaw((prev) => {
25
- const next = typeof update === 'function' ? update(prev) : update;
26
- edgesRef.current = next;
27
- return next;
28
- });
29
- }, []);
30
23
  const deleteSound = useSoundAction('delete');
31
24
  const createSound = useSoundAction('create');
32
- // Sync server props into local state when parent re-renders with new data
33
- const initialNodeKey = initialNodes
25
+ const { nodes, edges, reconcile, updateFeature, addPendingFeature, removeFeature, restoreFeature, addRepository: addRepositoryToMap, removeRepository, replaceRepository, getFeatureRepositoryPath, getRepositoryData, setCallbacks, } = useGraphState(initialNodes, initialEdges);
26
+ // Refs for stable access to latest nodes/edges without callback recreation
27
+ const nodesRef = useRef(nodes);
28
+ const edgesRef = useRef(edges);
29
+ useEffect(() => {
30
+ nodesRef.current = nodes;
31
+ edgesRef.current = edges;
32
+ }, [nodes, edges]);
33
+ // Sync server props into domain Maps when initialNodes/initialEdges change.
34
+ // Keyed by a stable string so we don't re-reconcile on every render.
35
+ const initialNodeKey = useMemo(() => initialNodes
34
36
  .map((n) => n.id)
35
37
  .sort()
36
- .join(',');
37
- const initialEdgeKey = initialEdges
38
- .map((e) => e.id)
39
- .sort()
40
- .join(',');
41
- // Track previous feature states so we can detect transitions on server refresh
42
- const prevFeatureStatesRef = useRef(new Map());
43
- // Stable key that changes when feature DATA changes (state/lifecycle), not just IDs.
44
- const initialDataKey = initialNodes
38
+ .join(','), [initialNodes]);
39
+ const initialDataKey = useMemo(() => initialNodes
45
40
  .filter((n) => n.type === 'featureNode')
46
41
  .map((n) => {
47
42
  const d = n.data;
48
43
  return `${n.id}:${d.state}:${d.lifecycle}`;
49
44
  })
50
45
  .sort()
51
- .join(',');
52
- // Sync server props into local state — keyed by derived strings (initialNodeKey/initialEdgeKey)
53
- // to avoid infinite re-renders from unstable array references.
46
+ .join(','), [initialNodes]);
47
+ const prevReconcileKey = useRef('');
54
48
  useEffect(() => {
55
- setNodes((currentNodes) => {
56
- // Build a lookup of current node positions by ID
57
- const currentById = new Map(currentNodes.map((n) => [n.id, n]));
58
- // Identify optimistic "creating" nodes (they have temp IDs not in server data)
59
- const serverIds = new Set(initialNodes.map((n) => n.id));
60
- const creatingNodes = currentNodes.filter((n) => n.type === 'featureNode' &&
61
- n.data.state === 'creating' &&
62
- !serverIds.has(n.id));
63
- // Merge server nodes with client positions, tracking if relayout is needed
64
- let needsRelayout = false;
65
- const merged = initialNodes.map((serverNode) => {
66
- // Node already exists on canvas — keep its position, update data
67
- const existing = currentById.get(serverNode.id);
68
- if (existing) {
69
- return { ...serverNode, position: existing.position };
70
- }
71
- // New server node — inherit position from an optimistic creating node if available
72
- if (serverNode.type === 'featureNode' && creatingNodes.length > 0) {
73
- const donor = creatingNodes.shift();
74
- return { ...serverNode, position: donor.position };
75
- }
76
- // Truly new node with no optimistic counterpart — needs relayout
77
- needsRelayout = true;
78
- return serverNode;
79
- });
80
- // Also check if non-creating nodes were removed (graph got smaller)
81
- if (!needsRelayout) {
82
- needsRelayout = currentNodes.some((cn) => !serverIds.has(cn.id) &&
83
- !(cn.type === 'featureNode' && cn.data.state === 'creating'));
84
- }
85
- if (needsRelayout) {
86
- const layoutResult = layoutWithDagre(merged, initialEdges, CANVAS_LAYOUT_DEFAULTS);
87
- setEdges(layoutResult.edges);
88
- return layoutResult.nodes;
89
- }
90
- return merged;
91
- });
92
- }, [initialNodeKey, initialNodes, initialEdges, setEdges]);
93
- useEffect(() => {
94
- setEdges(initialEdges);
95
- }, [initialEdgeKey, initialEdges, setEdges]);
96
- // Fallback notifications from server-prop state transitions.
97
- // Fires only when SSE didn't already deliver the matching event for a feature.
49
+ const key = `${initialNodeKey}|${initialDataKey}`;
50
+ if (key !== prevReconcileKey.current) {
51
+ prevReconcileKey.current = key;
52
+ reconcile(initialNodes, initialEdges);
53
+ }
54
+ }, [initialNodeKey, initialDataKey, initialNodes, initialEdges, reconcile]);
55
+ // Track previous feature states for fallback notifications
56
+ const prevFeatureStatesRef = useRef(new Map());
98
57
  const { events } = useAgentEventsContext();
99
58
  useEffect(() => {
100
59
  const prevStates = prevFeatureStatesRef.current;
@@ -104,7 +63,6 @@ export function useControlCenterState(initialNodes, initialEdges) {
104
63
  const data = node.data;
105
64
  const prev = prevStates.get(node.id);
106
65
  if (prev !== undefined && prev !== data.state) {
107
- // Check if SSE already delivered a matching event for this feature
108
66
  const sseAlreadyCovered = events.some((e) => e.featureId === data.featureId && mapEventTypeToState(e.eventType) === data.state);
109
67
  if (!sseAlreadyCovered) {
110
68
  if (data.state === 'done') {
@@ -115,9 +73,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
115
73
  description: 'Waiting for your approval',
116
74
  action: {
117
75
  label: 'Review',
118
- onClick: () => {
119
- router.push(`/feature/${data.featureId}`);
120
- },
76
+ onClick: () => router.push(`/feature/${data.featureId}`),
121
77
  },
122
78
  });
123
79
  }
@@ -129,271 +85,168 @@ export function useControlCenterState(initialNodes, initialEdges) {
129
85
  prevStates.set(node.id, data.state);
130
86
  }
131
87
  }, [initialDataKey, initialNodes, events, router]);
132
- // Targeted optimistic updates from SSE agent events.
133
- // Uses `events` array (not `lastEvent`) so that React batching cannot silently
134
- // drop events when multiple SSE messages arrive in the same tick.
88
+ // SSE effect: only state + lifecycle updates
135
89
  const processedEventCountRef = useRef(0);
136
90
  useEffect(() => {
91
+ // Clamp cursor if events were pruned
92
+ if (processedEventCountRef.current > events.length) {
93
+ processedEventCountRef.current = 0;
94
+ }
137
95
  if (events.length <= processedEventCountRef.current)
138
96
  return;
139
97
  const newEvents = events.slice(processedEventCountRef.current);
140
98
  processedEventCountRef.current = events.length;
141
- for (const event of newEvents) {
142
- const newState = mapEventTypeToState(event.eventType);
143
- const newLifecycle = mapPhaseNameToLifecycle(event.phaseName);
144
- // Targeted node update only clone the matched node
145
- setNodes((prev) => prev.map((node) => {
146
- if (node.type !== 'featureNode')
147
- return node;
148
- const data = node.data;
149
- if (data.featureId !== event.featureId)
150
- return node;
151
- return {
152
- ...node,
153
- data: {
154
- ...data,
155
- state: newState,
156
- ...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
157
- },
158
- };
159
- }));
99
+ for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {
100
+ if (state !== undefined || lifecycle !== undefined) {
101
+ updateFeature(`feat-${featureId}`, {
102
+ ...(state !== undefined && { state }),
103
+ ...(lifecycle !== undefined && { lifecycle }),
104
+ });
105
+ }
160
106
  }
161
- }, [events]);
162
- // Lightweight server-action polling fallback: fetches fresh graph data every 5s
163
- // when any feature is in an active state. This avoids full router.refresh() while
164
- // ensuring the UI stays in sync even if SSE events are missed.
165
- //
166
- // We derive a stable boolean so the interval isn't torn down on every node change.
167
- const hasActiveFeature = nodes.some((n) => {
168
- if (n.type !== 'featureNode')
169
- return false;
170
- const data = n.data;
171
- return (data.state === 'running' || data.state === 'action-required' || data.state === 'creating');
172
- });
107
+ }, [events, updateFeature]);
108
+ // Listen for optimistic approval events from the drawer (fires before SSE arrives)
173
109
  useEffect(() => {
174
- if (!hasActiveFeature)
110
+ const handler = (e) => {
111
+ const { featureId } = e.detail;
112
+ updateFeature(`feat-${featureId}`, { state: 'running' });
113
+ };
114
+ window.addEventListener('shep:feature-approved', handler);
115
+ return () => window.removeEventListener('shep:feature-approved', handler);
116
+ }, [updateFeature]);
117
+ // Separate effect: fetch metadata (name + description) when SSE reports it changed
118
+ const metadataFetchedRef = useRef(new Set());
119
+ const processedMetadataCountRef = useRef(0);
120
+ useEffect(() => {
121
+ // Clamp cursor if events were pruned
122
+ if (processedMetadataCountRef.current > events.length) {
123
+ processedMetadataCountRef.current = 0;
124
+ }
125
+ if (events.length <= processedMetadataCountRef.current)
175
126
  return;
176
- const interval = setInterval(async () => {
127
+ const newEvents = events.slice(processedMetadataCountRef.current);
128
+ processedMetadataCountRef.current = events.length;
129
+ for (const event of newEvents) {
130
+ if (event.message !== METADATA_UPDATED_MESSAGE)
131
+ continue;
132
+ if (metadataFetchedRef.current.has(event.featureId))
133
+ continue;
134
+ metadataFetchedRef.current.add(event.featureId);
135
+ const nodeId = `feat-${event.featureId}`;
136
+ getFeatureMetadata(event.featureId)
137
+ .then((meta) => {
138
+ if (meta) {
139
+ updateFeature(nodeId, { name: meta.name, description: meta.description });
140
+ }
141
+ })
142
+ .catch(() => {
143
+ // Silent: metadata fetch failure is non-critical
144
+ });
145
+ }
146
+ }, [events, updateFeature]);
147
+ // --- Polling fallback: catch any SSE events that were missed ---
148
+ useEffect(() => {
149
+ log.debug(`polling enabled (${POLL_INTERVAL_MS}ms interval)`);
150
+ const timer = setInterval(async () => {
177
151
  try {
178
- const { nodes: serverNodes } = await fetchGraphData();
179
- setNodes((currentNodes) => {
180
- const serverById = new Map(serverNodes.map((n) => [n.id, n]));
181
- let changed = false;
182
- const merged = currentNodes.map((node) => {
183
- const serverNode = serverById.get(node.id);
184
- if (!serverNode || node.type !== 'featureNode')
185
- return node;
186
- const currentData = node.data;
187
- const serverData = serverNode.data;
188
- // Only update if server data has different state or lifecycle
189
- if (currentData.state === serverData.state &&
190
- currentData.lifecycle === serverData.lifecycle) {
191
- return node;
192
- }
193
- changed = true;
194
- return {
195
- ...node,
196
- data: {
197
- ...currentData,
198
- state: serverData.state,
199
- lifecycle: serverData.lifecycle,
200
- progress: serverData.progress,
201
- ...(serverData.errorMessage && { errorMessage: serverData.errorMessage }),
202
- ...(serverData.runtime && { runtime: serverData.runtime }),
203
- ...(serverData.agentType && { agentType: serverData.agentType }),
204
- ...(serverData.pr && { pr: serverData.pr }),
205
- ...(serverData.blockedBy && { blockedBy: serverData.blockedBy }),
206
- },
207
- };
208
- });
209
- // Find new server nodes not yet on the client
210
- const clientIds = new Set(currentNodes.map((n) => n.id));
211
- const newServerNodes = serverNodes.filter((n) => !clientIds.has(n.id));
212
- // Replace optimistic "creating" temp nodes with their real server
213
- // counterparts. Temp nodes have IDs like "feature-<ts>" while real
214
- // nodes use "feat-<uuid>". Match by repositoryPath + name.
215
- if (newServerNodes.length > 0) {
216
- const creatingIndices = [];
217
- merged.forEach((n, i) => {
218
- if (n.type === 'featureNode' && n.data.state === 'creating') {
219
- creatingIndices.push(i);
220
- }
221
- });
222
- for (const serverNode of newServerNodes) {
223
- if (serverNode.type !== 'featureNode' || creatingIndices.length === 0)
224
- continue;
225
- const idx = creatingIndices.shift();
226
- // Replace the temp node in-place, keeping its position
227
- merged[idx] = { ...serverNode, position: merged[idx].position };
228
- changed = true;
229
- }
230
- // Any remaining new server nodes that didn't replace a temp node
231
- const replacedIds = new Set(merged.map((n) => n.id));
232
- const trueNewNodes = newServerNodes.filter((n) => !replacedIds.has(n.id));
233
- if (trueNewNodes.length > 0) {
234
- changed = true;
235
- return [...merged, ...trueNewNodes];
236
- }
237
- }
238
- return changed ? merged : currentNodes;
239
- });
152
+ const { nodes: freshNodes, edges: freshEdges } = await fetchGraphData();
153
+ reconcile(freshNodes, freshEdges);
240
154
  }
241
155
  catch {
242
- // Silently ignore polling errors SSE is the primary mechanism
156
+ log.warn('poll fetch failedwill retry next interval');
243
157
  }
244
- }, 5_000);
245
- return () => clearInterval(interval);
246
- }, [hasActiveFeature]);
247
- const onNodesChange = useCallback((changes) => {
248
- // Filter out 'replace' changes — in controlled mode these come from
249
- // React Flow's StoreUpdater syncing the nodes prop back into state.
250
- // Applying them creates a circular update loop (nodes enrichedNodes
251
- // StoreUpdater onNodesChange setNodes nodes → …) that both causes
252
- // excessive re-renders and overwrites SSE-driven state changes with stale data.
253
- const applicable = changes.filter((c) => c.type !== 'replace');
254
- if (applicable.length > 0) {
255
- setNodes((ns) => applyNodeChanges(applicable, ns));
256
- }
158
+ }, POLL_INTERVAL_MS);
159
+ return () => {
160
+ log.debug('polling disabled');
161
+ clearInterval(timer);
162
+ };
163
+ }, [reconcile]);
164
+ // onNodesChange is a no-op: nodes are derived from domain Maps.
165
+ // Since nodesDraggable=false and elementsSelectable=false, only React Flow's
166
+ // internal replace/dimensions changes come through we ignore them all.
167
+ const onNodesChange = useCallback((_changes) => {
168
+ // Intentional no-op: domain Maps are the source of truth.
169
+ }, []);
170
+ const handleConnect = useCallback((_connection) => {
171
+ // Connections are managed via domain operations, not direct edge manipulation.
257
172
  }, []);
258
- const handleConnect = useCallback((connection) => {
259
- if (!connection.source || !connection.target)
260
- return;
261
- setNodes((currentNodes) => {
262
- const sourceNode = currentNodes.find((n) => n.id === connection.source);
263
- if (sourceNode?.type !== 'repositoryNode')
264
- return currentNodes;
265
- // Block if target feature already has a repo source
266
- setEdges((currentEdges) => {
267
- const targetAlreadyHasRepo = currentEdges.some((e) => {
268
- const edgeSource = currentNodes.find((n) => n.id === e.source);
269
- return edgeSource?.type === 'repositoryNode' && e.target === connection.target;
270
- });
271
- if (targetAlreadyHasRepo)
272
- return currentEdges;
273
- return [
274
- ...currentEdges,
275
- {
276
- id: `edge-${connection.source}-${connection.target}`,
277
- source: connection.source,
278
- target: connection.target,
279
- style: { strokeDasharray: '5 5' },
280
- },
281
- ];
282
- });
283
- return currentNodes;
284
- });
285
- }, [setEdges]);
286
173
  const createFeatureNode = useCallback((sourceNodeId, dataOverride, edgeType) => {
287
- const id = `feature-${Date.now()}-${nextFeatureId++}`;
174
+ // Use real feature ID when available (from server), otherwise temp ID
175
+ const id = dataOverride?.featureId
176
+ ? `feat-${dataOverride.featureId}`
177
+ : `feature-${Date.now()}-${nextFeatureId++}`;
288
178
  const newFeatureData = {
289
179
  name: dataOverride?.name ?? 'New Feature',
290
180
  description: dataOverride?.description ?? 'Describe what this feature does',
291
- featureId: `#${id.slice(-4)}`,
181
+ featureId: dataOverride?.featureId ?? `#${id.slice(-4)}`,
292
182
  lifecycle: 'requirements',
293
183
  state: dataOverride?.state ?? 'running',
294
184
  progress: 0,
295
185
  repositoryPath: dataOverride?.repositoryPath ?? '',
296
186
  branch: dataOverride?.branch ?? '',
297
187
  };
298
- setNodes((currentNodes) => {
299
- const newNode = {
300
- id,
301
- type: 'featureNode',
302
- position: { x: 0, y: 0 },
303
- data: newFeatureData,
304
- };
305
- const newEdge = sourceNodeId
306
- ? {
307
- id: edgeType === 'dependencyEdge'
308
- ? `dep-${sourceNodeId}-${id}`
309
- : `edge-${sourceNodeId}-${id}`,
310
- source: sourceNodeId,
311
- target: id,
312
- ...(edgeType ? { type: edgeType } : { style: { strokeDasharray: '5 5' } }),
313
- }
314
- : null;
315
- const allEdges = newEdge
316
- ? [...edgesRef.current.filter((e) => e.id !== newEdge.id), newEdge]
317
- : edgesRef.current;
318
- // Insert the new node after the last sibling connected to the same source,
319
- // so dagre's input-order preservation keeps repo groups together.
320
- let insertIndex = currentNodes.length;
321
- if (sourceNodeId) {
322
- const siblingIds = new Set(allEdges.filter((e) => e.source === sourceNodeId).map((e) => e.target));
323
- for (let i = currentNodes.length - 1; i >= 0; i--) {
324
- if (siblingIds.has(currentNodes[i].id)) {
325
- insertIndex = i + 1;
326
- break;
327
- }
328
- }
329
- }
330
- const allNodes = [
331
- ...currentNodes.slice(0, insertIndex),
332
- newNode,
333
- ...currentNodes.slice(insertIndex),
334
- ];
335
- // Run dagre layout on the full graph so the new node is positioned consistently
336
- const layoutResult = layoutWithDagre(allNodes, allEdges, CANVAS_LAYOUT_DEFAULTS);
337
- setEdges(layoutResult.edges);
338
- return layoutResult.nodes;
339
- });
188
+ const parentNodeId = edgeType === 'dependencyEdge' && sourceNodeId ? sourceNodeId : undefined;
189
+ addPendingFeature(id, newFeatureData, parentNodeId);
340
190
  return id;
341
- }, [setEdges]);
191
+ }, [addPendingFeature]);
342
192
  const handleDeleteFeature = useCallback((featureId) => {
343
193
  const nodeId = `feat-${featureId}`;
344
- // Snapshot current state for rollback
345
- const prevNodes = nodes;
346
- const prevEdges = edgesRef.current;
347
- // Optimistic removal — update UI immediately
348
- setNodes((currentNodes) => {
349
- const remainingNodes = currentNodes.filter((n) => n.id !== nodeId);
350
- const remainingEdges = edgesRef.current.filter((e) => e.source !== nodeId && e.target !== nodeId);
351
- const layoutResult = layoutWithDagre(remainingNodes, remainingEdges, CANVAS_LAYOUT_DEFAULTS);
352
- setEdges(layoutResult.edges);
353
- return layoutResult.nodes;
354
- });
194
+ // Find the current entry for rollback
195
+ const prevEntry = nodesRef.current
196
+ .filter((n) => n.id === nodeId)
197
+ .map((n) => ({
198
+ nodeId: n.id,
199
+ data: n.data,
200
+ }))[0];
201
+ // Optimistic removal
202
+ removeFeature(nodeId);
355
203
  deleteSound.play();
356
204
  toast.success('Feature deleted successfully');
357
205
  router.push('/');
358
- // Persist in background — rollback on failure
359
206
  deleteFeature(featureId)
360
207
  .then((result) => {
361
208
  if (result.error) {
362
- setNodes(prevNodes);
363
- setEdges(prevEdges);
209
+ if (prevEntry)
210
+ restoreFeature(nodeId, prevEntry);
364
211
  toast.error(result.error);
365
212
  }
366
213
  })
367
214
  .catch(() => {
368
- setNodes(prevNodes);
369
- setEdges(prevEdges);
215
+ if (prevEntry)
216
+ restoreFeature(nodeId, prevEntry);
370
217
  toast.error('Failed to delete feature');
371
218
  });
372
- }, [nodes, router, deleteSound, setEdges]);
219
+ }, [router, deleteSound, removeFeature, restoreFeature]);
373
220
  const handleDeleteRepository = useCallback(async (repositoryId) => {
374
221
  const repoNodeId = `repo-${repositoryId}`;
222
+ // Find children of this repo via edges
223
+ const childFeatureIds = new Set(edgesRef.current.filter((e) => e.source === repoNodeId).map((e) => e.target));
375
224
  // Snapshot for rollback
376
- const prevNodes = nodes;
377
- const prevEdges = edgesRef.current;
378
- // Optimistic: remove repo node, its child feature nodes, and all related edges
379
- setNodes((currentNodes) => {
380
- // Find feature node IDs connected to this repo via edges
381
- const childFeatureIds = new Set(edgesRef.current.filter((e) => e.source === repoNodeId).map((e) => e.target));
382
- const remainingNodes = currentNodes.filter((n) => n.id !== repoNodeId && !childFeatureIds.has(n.id));
383
- const remainingEdges = edgesRef.current.filter((e) => e.source !== repoNodeId &&
384
- e.target !== repoNodeId &&
385
- !childFeatureIds.has(e.source) &&
386
- !childFeatureIds.has(e.target));
387
- const layoutResult = layoutWithDagre(remainingNodes, remainingEdges, CANVAS_LAYOUT_DEFAULTS);
388
- setEdges(layoutResult.edges);
389
- return layoutResult.nodes;
390
- });
225
+ const prevRepoData = getRepositoryData(repoNodeId);
226
+ const childSnapshots = new Map();
227
+ for (const childId of childFeatureIds) {
228
+ const childNode = nodesRef.current.find((n) => n.id === childId);
229
+ if (childNode) {
230
+ childSnapshots.set(childId, { nodeId: childId, data: childNode.data });
231
+ }
232
+ }
233
+ const rollback = () => {
234
+ if (prevRepoData)
235
+ addRepositoryToMap(repoNodeId, prevRepoData);
236
+ for (const [childId, entry] of childSnapshots) {
237
+ restoreFeature(childId, entry);
238
+ }
239
+ };
240
+ // Optimistic: remove repo + children
241
+ removeRepository(repoNodeId);
242
+ for (const childId of childFeatureIds) {
243
+ removeFeature(childId);
244
+ }
391
245
  try {
392
246
  const result = await deleteRepository(repositoryId);
393
247
  if (!result.success) {
394
248
  toast.error(result.error ?? 'Failed to remove repository');
395
- setNodes(prevNodes);
396
- setEdges(prevEdges);
249
+ rollback();
397
250
  return;
398
251
  }
399
252
  deleteSound.play();
@@ -401,82 +254,53 @@ export function useControlCenterState(initialNodes, initialEdges) {
401
254
  }
402
255
  catch {
403
256
  toast.error('Failed to remove repository');
404
- setNodes(prevNodes);
405
- setEdges(prevEdges);
257
+ rollback();
406
258
  }
407
- }, [nodes, deleteSound, setEdges]);
259
+ }, [
260
+ deleteSound,
261
+ removeRepository,
262
+ removeFeature,
263
+ addRepositoryToMap,
264
+ restoreFeature,
265
+ getRepositoryData,
266
+ ]);
408
267
  const handleLayout = useCallback((direction) => {
409
- setNodes((currentNodes) => {
410
- const result = layoutWithDagre(currentNodes, edgesRef.current, {
411
- ...CANVAS_LAYOUT_DEFAULTS,
412
- direction,
413
- });
414
- setEdges(result.edges);
415
- return result.nodes;
268
+ // Layout is applied via reconcile on next server prop update.
269
+ // For immediate re-layout, we apply dagre and trigger a reconcile-like update.
270
+ const result = layoutWithDagre(nodesRef.current, edgesRef.current, {
271
+ ...CANVAS_LAYOUT_DEFAULTS,
272
+ direction,
416
273
  });
417
- }, [setEdges]);
274
+ reconcile(result.nodes, result.edges);
275
+ }, [reconcile]);
418
276
  const handleAddRepository = useCallback((path) => {
419
277
  const tempId = `repo-temp-${Date.now()}`;
420
278
  const repoName = path
421
279
  .replace(/[\\/]+$/, '')
422
280
  .split(/[\\/]/)
423
281
  .pop() ?? path;
424
- // Optimistic UI: add node and re-layout immediately
425
- setNodes((currentNodes) => {
426
- const newNode = {
427
- id: tempId,
428
- type: 'repositoryNode',
429
- position: { x: 0, y: 0 },
430
- data: { name: repoName, repositoryPath: path, id: tempId },
431
- };
432
- const allNodes = [...currentNodes, newNode];
433
- const layoutResult = layoutWithDagre(allNodes, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
434
- setEdges(layoutResult.edges);
435
- return layoutResult.nodes;
436
- });
437
- // Persist via server action
282
+ addRepositoryToMap(tempId, { name: repoName, repositoryPath: path, id: tempId });
438
283
  addRepository({ path, name: repoName })
439
284
  .then((result) => {
440
285
  if (result.error) {
441
- // Rollback optimistic node and re-layout
442
- setNodes((prev) => {
443
- const remaining = prev.filter((n) => n.id !== tempId);
444
- const layoutResult = layoutWithDagre(remaining, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
445
- setEdges(layoutResult.edges);
446
- return layoutResult.nodes;
447
- });
286
+ removeRepository(tempId);
448
287
  toast.error(result.error);
449
288
  return;
450
289
  }
451
- // Replace temp ID with real repository ID
452
290
  const repo = result.repository;
453
291
  const realId = `repo-${repo.id}`;
454
- setNodes((prev) => prev.map((n) => n.id === tempId
455
- ? {
456
- ...n,
457
- id: realId,
458
- data: { ...n.data, id: repo.id, repositoryPath: repo.path },
459
- }
460
- : n));
461
- setEdges((prev) => prev.map((e) => ({
462
- ...e,
463
- source: e.source === tempId ? realId : e.source,
464
- target: e.target === tempId ? realId : e.target,
465
- id: e.id.replace(tempId, realId),
466
- })));
292
+ replaceRepository(tempId, realId, {
293
+ name: repo.name,
294
+ repositoryPath: repo.path,
295
+ id: repo.id,
296
+ });
467
297
  createSound.play();
468
298
  })
469
299
  .catch(() => {
470
- // Rollback optimistic node and re-layout
471
- setNodes((prev) => {
472
- const remaining = prev.filter((n) => n.id !== tempId);
473
- const layoutResult = layoutWithDagre(remaining, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
474
- setEdges(layoutResult.edges);
475
- return layoutResult.nodes;
476
- });
300
+ removeRepository(tempId);
477
301
  toast.error('Failed to add repository');
478
302
  });
479
- }, [createSound, setEdges]);
303
+ }, [addRepositoryToMap, removeRepository, replaceRepository, createSound]);
480
304
  return {
481
305
  nodes,
482
306
  edges,
@@ -487,5 +311,8 @@ export function useControlCenterState(initialNodes, initialEdges) {
487
311
  handleDeleteFeature,
488
312
  handleDeleteRepository,
489
313
  createFeatureNode,
314
+ getFeatureRepositoryPath,
315
+ getRepositoryData,
316
+ setCallbacks,
490
317
  };
491
318
  }