@shepai/cli 1.72.9-pr218.000ada0 → 1.72.9-pr220.e1bfec0

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 (326) hide show
  1. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +20 -1
  2. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +68 -41
  4. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +10 -0
  5. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
  6. package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
  7. package/dist/src/presentation/web/app/actions/create-feature.js +20 -2
  8. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts +10 -0
  9. package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts.map +1 -0
  10. package/dist/src/presentation/web/app/actions/get-feature-metadata.js +14 -0
  11. package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
  12. package/dist/src/presentation/web/app/api/agent-events/route.js +15 -0
  13. package/dist/src/presentation/web/components/common/add-repository-button/add-repository-button.d.ts.map +1 -0
  14. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts +2 -0
  15. package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts.map +1 -0
  16. package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/index.js +0 -1
  17. package/dist/src/presentation/web/components/common/add-repository-button/pick-folder.d.ts.map +1 -0
  18. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.d.ts.map +1 -1
  19. package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.js +13 -16
  20. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  21. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +35 -16
  22. package/dist/src/presentation/web/components/common/index.d.ts +1 -1
  23. package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
  24. package/dist/src/presentation/web/components/common/index.js +1 -1
  25. package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.js +1 -1
  26. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  27. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +23 -4
  28. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts +0 -11
  29. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
  30. package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +2 -37
  31. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +8 -0
  32. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  33. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +152 -350
  34. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts +2 -10
  35. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
  36. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +10 -42
  37. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts.map +1 -1
  38. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.js +0 -46
  39. package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +1 -1
  40. package/dist/src/presentation/web/hooks/use-graph-state.d.ts +41 -0
  41. package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -0
  42. package/dist/src/presentation/web/hooks/use-graph-state.js +230 -0
  43. package/dist/src/presentation/web/lib/derive-graph.d.ts +52 -0
  44. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -0
  45. package/dist/src/presentation/web/lib/derive-graph.js +126 -0
  46. package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
  47. package/dist/src/presentation/web/lib/layout-with-dagre.js +0 -1
  48. package/dist/tsconfig.build.tsbuildinfo +1 -1
  49. package/package.json +1 -1
  50. package/web/.next/BUILD_ID +1 -1
  51. package/web/.next/build-manifest.json +2 -2
  52. package/web/.next/cache/.previewinfo +1 -1
  53. package/web/.next/cache/.rscinfo +1 -1
  54. package/web/.next/cache/.tsbuildinfo +1 -1
  55. package/web/.next/cache/config.json +3 -3
  56. package/web/.next/fallback-build-manifest.json +2 -2
  57. package/web/.next/prerender-manifest.json +3 -3
  58. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +34 -34
  59. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
  60. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  61. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +40 -40
  63. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  64. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  65. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  67. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
  68. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  69. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +34 -34
  71. package/web/.next/server/app/(dashboard)/create/page.js +3 -3
  72. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  73. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +40 -40
  75. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  76. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  77. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +30 -30
  79. package/web/.next/server/app/(dashboard)/page.js +3 -3
  80. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  81. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  82. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  83. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
  84. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  85. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  86. package/web/.next/server/app/_global-error.html +2 -2
  87. package/web/.next/server/app/_global-error.rsc +1 -1
  88. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  89. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  90. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  91. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  92. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  93. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  94. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  95. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  97. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  98. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  99. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  100. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  101. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  102. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  103. package/web/.next/server/app/version/page.js.nft.json +1 -1
  104. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  105. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  106. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  107. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  108. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +3 -0
  110. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +1 -0
  111. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
  112. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +1 -0
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/{[root-of-the-server]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -0
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  120. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  121. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js.map +1 -1
  123. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  124. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  125. 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
  126. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -0
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  128. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  129. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  130. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  131. package/web/.next/server/chunks/ssr/_250a63ae._.js +3 -0
  132. package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -0
  133. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  134. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  135. package/web/.next/server/chunks/ssr/_63688261._.js +6 -0
  136. package/web/.next/server/chunks/ssr/_63688261._.js.map +1 -0
  137. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  138. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  139. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  140. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  141. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5ea689db._.js → server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
  142. package/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js.map → src_presentation_web_2b91e4ec._.js.map} +1 -1
  143. package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js → src_presentation_web_5bcc1537._.js} +2 -2
  144. package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js.map → src_presentation_web_5bcc1537._.js.map} +1 -1
  145. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +3 -0
  146. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +1 -0
  147. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +3 -0
  148. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -0
  149. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  150. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  152. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  153. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +8 -0
  154. package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js.map +1 -0
  155. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
  156. package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js.map +1 -0
  157. package/web/.next/server/pages/500.html +2 -2
  158. package/web/.next/server/server-reference-manifest.js +1 -1
  159. package/web/.next/server/server-reference-manifest.json +142 -142
  160. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  161. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  162. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  163. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +34 -34
  164. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
  165. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  166. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  167. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +40 -40
  168. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  169. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  170. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  171. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  172. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
  173. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  174. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  175. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +34 -34
  176. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +3 -3
  177. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  178. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  179. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +40 -40
  180. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  181. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  182. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  183. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +30 -30
  184. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +3 -3
  185. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  186. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  187. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +30 -30
  188. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
  189. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  190. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  191. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  192. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  193. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  194. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  195. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  196. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  197. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  198. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  199. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  200. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  201. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  202. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  203. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  204. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  205. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  206. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  207. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  208. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  209. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  210. package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  211. 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
  212. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +3 -0
  213. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
  214. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  215. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  216. 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
  217. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  218. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  219. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  220. 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
  221. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  222. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  223. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_250a63ae._.js +3 -0
  224. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  225. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_63688261._.js +6 -0
  226. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  227. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  228. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js → src_presentation_web_2b91e4ec._.js} +2 -2
  229. package/web/.next/{server/chunks/ssr/src_presentation_web_7188a290._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js} +2 -2
  230. 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
  231. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +3 -0
  232. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  233. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  234. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +8 -0
  235. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
  236. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  237. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  238. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +142 -142
  239. package/web/.next/standalone/src/presentation/web/CLAUDE.md +77 -33
  240. package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +27 -2
  241. package/web/.next/standalone/src/presentation/web/app/actions/get-feature-metadata.ts +18 -0
  242. package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +17 -0
  243. package/web/.next/standalone/src/presentation/web/components/common/add-repository-button/index.ts +1 -0
  244. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +15 -19
  245. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +44 -18
  246. package/web/.next/standalone/src/presentation/web/components/common/index.ts +1 -5
  247. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-empty-state.tsx +1 -1
  248. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +24 -8
  249. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +2 -41
  250. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +180 -429
  251. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx +0 -48
  252. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +13 -59
  253. package/web/.next/standalone/src/presentation/web/components/layouts/app-shell/app-shell.tsx +1 -1
  254. package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +343 -0
  255. package/web/.next/standalone/src/presentation/web/lib/derive-graph.ts +178 -0
  256. package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +0 -1
  257. package/web/.next/static/chunks/{0eeb65b8300fb7cd.js → 0a883e2efecfd563.js} +1 -1
  258. package/web/.next/static/chunks/{4a8df922364596f6.js → 596ca28d78baae25.js} +1 -1
  259. package/web/.next/static/chunks/{99381b9c479936d5.js → 638824249d103905.js} +1 -1
  260. package/web/.next/static/chunks/63a80e9d4c4b0253.js +4 -0
  261. package/web/.next/static/chunks/71c9ecdceac1939f.css +2 -0
  262. package/web/.next/static/chunks/a040b058d79f4ade.js +1 -0
  263. package/web/.next/static/chunks/{1249c7c8745b972e.js → c575ab63c138645b.js} +1 -1
  264. package/web/.next/static/chunks/cdc92cdf81005c84.js +1 -0
  265. package/web/.next/static/chunks/{a676f15c03fa66b9.js → e05eb1cc84ee254a.js} +1 -1
  266. package/web/.next/static/chunks/ef8f8940eac6c542.js +1 -0
  267. package/web/.next/static/chunks/{9be617fc61b893f2.js → f32c98a709949c5b.js} +1 -1
  268. package/web/.next/trace +1 -1
  269. package/web/.next/trace-build +1 -1
  270. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-button.d.ts.map +0 -1
  271. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts +0 -7
  272. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts.map +0 -1
  273. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.js +0 -1
  274. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts +0 -6
  275. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts.map +0 -1
  276. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.js +0 -23
  277. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts +0 -10
  278. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts.map +0 -1
  279. package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.js +0 -33
  280. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts +0 -4
  281. package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts.map +0 -1
  282. package/dist/src/presentation/web/components/common/add-repository-node/pick-folder.d.ts.map +0 -1
  283. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
  284. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js.map +0 -1
  285. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
  286. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js.map +0 -1
  287. package/web/.next/server/chunks/ssr/[root-of-the-server]__cbae9863._.js.map +0 -1
  288. package/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js.map +0 -1
  289. package/web/.next/server/chunks/ssr/_6e08ce21._.js +0 -3
  290. package/web/.next/server/chunks/ssr/_6e08ce21._.js.map +0 -1
  291. package/web/.next/server/chunks/ssr/_6ef06ca9._.js +0 -6
  292. package/web/.next/server/chunks/ssr/_6ef06ca9._.js.map +0 -1
  293. package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
  294. package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js.map +0 -1
  295. package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
  296. package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js.map +0 -1
  297. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js +0 -3
  298. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js.map +0 -1
  299. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +0 -3
  300. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js.map +0 -1
  301. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
  302. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
  303. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6e08ce21._.js +0 -3
  304. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6ef06ca9._.js +0 -6
  305. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
  306. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
  307. 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
  308. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +0 -3
  309. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node-config.ts +0 -8
  310. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.tsx +0 -70
  311. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.tsx +0 -49
  312. package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/index.ts +0 -3
  313. package/web/.next/static/chunks/1c15ab8668ecf473.js +0 -1
  314. package/web/.next/static/chunks/2cf89d17ee7717a6.js +0 -4
  315. package/web/.next/static/chunks/981b8df9ad045742.js +0 -1
  316. package/web/.next/static/chunks/acce8a15d6896dea.css +0 -2
  317. package/web/.next/static/chunks/b579fd590a79bf35.js +0 -1
  318. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.d.ts +0 -0
  319. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.js +0 -0
  320. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.d.ts +0 -0
  321. /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.js +0 -0
  322. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.tsx +0 -0
  323. /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.ts +0 -0
  324. /package/web/.next/static/{nnR12fAsrSagAfeV6xj6D → uMxPSDPwZCludF5408rWJ}/_buildManifest.js +0 -0
  325. /package/web/.next/static/{nnR12fAsrSagAfeV6xj6D → uMxPSDPwZCludF5408rWJ}/_clientMiddlewareManifest.json +0 -0
  326. /package/web/.next/static/{nnR12fAsrSagAfeV6xj6D → uMxPSDPwZCludF5408rWJ}/_ssgManifest.js +0 -0
@@ -4,7 +4,6 @@ import { FeaturesCanvas } from './features-canvas';
4
4
  import type { CanvasNodeType } from './features-canvas';
5
5
  import type { FeatureNodeType } from '@/components/common/feature-node';
6
6
  import type { RepositoryNodeType } from '@/components/common/repository-node';
7
- import type { AddRepositoryNodeType } from '@/components/common/add-repository-node';
8
7
  import { layoutWithDagre } from '@/lib/layout-with-dagre';
9
8
 
10
9
  const meta: Meta<typeof FeaturesCanvas> = {
@@ -229,8 +228,6 @@ export const Interactive: Story = {
229
228
  { id: 'e3-4', source: 'node-3', target: 'node-4' },
230
229
  ],
231
230
  onAddFeature: () => undefined,
232
- onNodeAction: () => undefined,
233
- onNodeSettings: () => undefined,
234
231
  },
235
232
  };
236
233
 
@@ -243,16 +240,8 @@ const repoNode: RepositoryNodeType = {
243
240
  },
244
241
  };
245
242
 
246
- const addRepoNode: AddRepositoryNodeType = {
247
- id: 'add-repo',
248
- type: 'addRepositoryNode',
249
- position: { x: 50, y: 302 },
250
- data: {},
251
- };
252
-
253
243
  const repoFeatureNodes: CanvasNodeType[] = [
254
244
  repoNode,
255
- addRepoNode,
256
245
  {
257
246
  id: 'feat-1',
258
247
  type: 'featureNode',
@@ -296,8 +285,6 @@ export const ConnectedRepositoryMultipleFeatures: Story = {
296
285
  args: {
297
286
  nodes: repoFeatureNodes,
298
287
  edges: repoFeatureEdges,
299
- onNodeAction: () => undefined,
300
- onNodeSettings: () => undefined,
301
288
  },
302
289
  };
303
290
 
@@ -310,12 +297,6 @@ const singleRepoSingleFeatureNodes: CanvasNodeType[] = [
310
297
  position: { x: 50, y: 127 },
311
298
  data: { name: 'shep-ai/cli' },
312
299
  },
313
- {
314
- id: 'add-repo',
315
- type: 'addRepositoryNode',
316
- position: { x: 50, y: 267 },
317
- data: {},
318
- },
319
300
  {
320
301
  id: 'feat-1',
321
302
  type: 'featureNode',
@@ -339,8 +320,6 @@ export const ConnectedRepositorySingleFeature: Story = {
339
320
  edges: [
340
321
  { id: 'e-repo-f1', source: 'repo-1', target: 'feat-1', type: 'straight', ...dashedEdge },
341
322
  ],
342
- onNodeAction: () => undefined,
343
- onNodeSettings: () => undefined,
344
323
  },
345
324
  };
346
325
 
@@ -353,12 +332,6 @@ const singleRepoMultiFeatNodes: CanvasNodeType[] = [
353
332
  position: { x: 50, y: 162 },
354
333
  data: { name: 'shep-ai/cli' },
355
334
  },
356
- {
357
- id: 'add-repo',
358
- type: 'addRepositoryNode',
359
- position: { x: 50, y: 450 },
360
- data: {},
361
- },
362
335
  {
363
336
  id: 'feat-1',
364
337
  type: 'featureNode',
@@ -414,8 +387,6 @@ export const SingleRepositoryMultipleFeatures: Story = {
414
387
  { id: 'e-r1-f2', source: 'repo-1', target: 'feat-2', ...dashedEdge },
415
388
  { id: 'e-r1-f3', source: 'repo-1', target: 'feat-3', ...dashedEdge },
416
389
  ],
417
- onNodeAction: () => undefined,
418
- onNodeSettings: () => undefined,
419
390
  },
420
391
  };
421
392
 
@@ -434,12 +405,6 @@ const multiRepoNodes: CanvasNodeType[] = [
434
405
  position: { x: 50, y: 270 },
435
406
  data: { name: 'shep-ai/web' },
436
407
  },
437
- {
438
- id: 'add-repo',
439
- type: 'addRepositoryNode',
440
- position: { x: 50, y: 470 },
441
- data: {},
442
- },
443
408
  {
444
409
  id: 'feat-1',
445
410
  type: 'featureNode',
@@ -479,8 +444,6 @@ export const MultipleRepositories: Story = {
479
444
  { id: 'e-r1-f1', source: 'repo-1', target: 'feat-1', ...dashedEdge },
480
445
  { id: 'e-r2-f2', source: 'repo-2', target: 'feat-2', ...dashedEdge },
481
446
  ],
482
- onNodeAction: () => undefined,
483
- onNodeSettings: () => undefined,
484
447
  },
485
448
  };
486
449
 
@@ -505,12 +468,6 @@ const mixedRepoFeatureNodesRaw: CanvasNodeType[] = [
505
468
  position: { x: 0, y: 0 },
506
469
  data: { name: 'shep-ai/api' },
507
470
  },
508
- {
509
- id: 'add-repo',
510
- type: 'addRepositoryNode',
511
- position: { x: 0, y: 0 },
512
- data: {},
513
- },
514
471
  {
515
472
  id: 'feat-1',
516
473
  type: 'featureNode',
@@ -593,8 +550,6 @@ export const MultipleRepositoriesMixedConnections: Story = {
593
550
  args: {
594
551
  nodes: mixedLayoutedNodes,
595
552
  edges: mixedLayoutedEdges,
596
- onNodeAction: () => undefined,
597
- onNodeSettings: () => undefined,
598
553
  },
599
554
  };
600
555
 
@@ -603,8 +558,5 @@ export const InteractiveWithRepository: Story = {
603
558
  nodes: repoFeatureNodes,
604
559
  edges: repoFeatureEdges,
605
560
  onAddFeature: () => undefined,
606
- onNodeAction: () => undefined,
607
- onNodeSettings: () => undefined,
608
- onRepositoryAdd: () => undefined,
609
561
  },
610
562
  };
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useCallback, useMemo } from 'react';
3
+ import { useMemo, useCallback } from 'react';
4
4
  import { ReactFlow, Background, Controls } from '@xyflow/react';
5
5
  import type { Connection, Edge, NodeChange } from '@xyflow/react';
6
6
  import { Plus } from 'lucide-react';
@@ -10,11 +10,9 @@ import { FeatureNode } from '@/components/common/feature-node';
10
10
  import type { FeatureNodeType, FeatureNodeData } from '@/components/common/feature-node';
11
11
  import { RepositoryNode } from '@/components/common/repository-node';
12
12
  import type { RepositoryNodeType } from '@/components/common/repository-node';
13
- import { AddRepositoryNode } from '@/components/common/add-repository-node';
14
- import type { AddRepositoryNodeType } from '@/components/common/add-repository-node';
15
13
  import { DependencyEdge } from './dependency-edge';
16
14
 
17
- export type CanvasNodeType = FeatureNodeType | RepositoryNodeType | AddRepositoryNodeType;
15
+ export type CanvasNodeType = FeatureNodeType | RepositoryNodeType;
18
16
 
19
17
  export interface FeaturesCanvasProps {
20
18
  nodes: CanvasNodeType[];
@@ -22,16 +20,9 @@ export interface FeaturesCanvasProps {
22
20
  selectedFeatureId?: string | null;
23
21
  onNodesChange?: (changes: NodeChange<CanvasNodeType>[]) => void;
24
22
  onAddFeature?: () => void;
25
- onNodeAction?: (nodeId: string) => void;
26
- onNodeSettings?: (nodeId: string) => void;
27
23
  onNodeClick?: (event: React.MouseEvent, node: CanvasNodeType) => void;
28
24
  onPaneClick?: (event: React.MouseEvent) => void;
29
- onRepositoryAdd?: (repoNodeId: string) => void;
30
- onRepositoryClick?: (nodeId: string) => void;
31
- onRepositoryDelete?: (repositoryId: string) => void;
32
- onFeatureDelete?: (featureId: string) => void;
33
25
  onConnect?: (connection: Connection) => void;
34
- onRepositorySelect?: (path: string) => void;
35
26
  onCanvasDrag?: () => void;
36
27
  toolbar?: React.ReactNode;
37
28
  emptyState?: React.ReactNode;
@@ -43,16 +34,9 @@ export function FeaturesCanvas({
43
34
  selectedFeatureId,
44
35
  onNodesChange,
45
36
  onAddFeature,
46
- onNodeAction,
47
- onNodeSettings,
48
37
  onConnect,
49
38
  onNodeClick,
50
39
  onPaneClick,
51
- onRepositoryAdd,
52
- onRepositoryClick,
53
- onRepositoryDelete,
54
- onFeatureDelete,
55
- onRepositorySelect,
56
40
  onCanvasDrag,
57
41
  toolbar,
58
42
  emptyState,
@@ -61,7 +45,6 @@ export function FeaturesCanvas({
61
45
  () => ({
62
46
  featureNode: FeatureNode,
63
47
  repositoryNode: RepositoryNode,
64
- addRepositoryNode: AddRepositoryNode,
65
48
  }),
66
49
  []
67
50
  );
@@ -89,48 +72,19 @@ export function FeaturesCanvas({
89
72
  [nodes, edges]
90
73
  );
91
74
 
75
+ // Callbacks and showHandles are already injected into node.data by deriveGraph.
76
+ // Only selectedFeatureId highlighting needs to be applied here.
92
77
  const enrichedNodes = useMemo(
93
78
  () =>
94
- nodes.map((node) => ({
95
- ...node,
96
- // React Flow passes `selected` as a prop to the node component
97
- ...(node.type === 'featureNode' && {
98
- selected:
99
- selectedFeatureId != null &&
100
- (node.data as FeatureNodeData).featureId === selectedFeatureId,
101
- }),
102
- data: {
103
- ...node.data,
104
- showHandles: edges.length > 0,
105
- ...(node.type === 'featureNode' && (node.data as FeatureNodeData).state !== 'creating'
106
- ? {
107
- onAction: onNodeAction ? () => onNodeAction(node.id) : undefined,
108
- onSettings: onNodeSettings ? () => onNodeSettings(node.id) : undefined,
109
- onDelete: onFeatureDelete,
110
- }
111
- : {}),
112
- ...(node.type === 'repositoryNode' && {
113
- onAdd: onRepositoryAdd ? () => onRepositoryAdd(node.id) : undefined,
114
- onClick: onRepositoryClick ? () => onRepositoryClick(node.id) : undefined,
115
- onDelete: onRepositoryDelete,
116
- }),
117
- ...(node.type === 'addRepositoryNode' && {
118
- onSelect: onRepositorySelect ? (path: string) => onRepositorySelect(path) : undefined,
119
- }),
120
- },
121
- })) as CanvasNodeType[],
122
- [
123
- nodes,
124
- edges.length,
125
- selectedFeatureId,
126
- onNodeAction,
127
- onNodeSettings,
128
- onFeatureDelete,
129
- onRepositoryAdd,
130
- onRepositoryClick,
131
- onRepositoryDelete,
132
- onRepositorySelect,
133
- ]
79
+ selectedFeatureId == null
80
+ ? nodes
81
+ : (nodes.map((node) =>
82
+ node.type === 'featureNode' &&
83
+ (node.data as FeatureNodeData).featureId === selectedFeatureId
84
+ ? { ...node, selected: true }
85
+ : node
86
+ ) as CanvasNodeType[]),
87
+ [nodes, selectedFeatureId]
134
88
  );
135
89
 
136
90
  if (nodes.length === 0) {
@@ -4,7 +4,7 @@ import { useCallback, type ReactNode } from 'react';
4
4
  import { useRouter } from 'next/navigation';
5
5
  import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar';
6
6
  import { AppSidebar } from '@/components/layouts/app-sidebar';
7
- import { AddRepositoryButton } from '@/components/common/add-repository-node';
7
+ import { AddRepositoryButton } from '@/components/common/add-repository-button';
8
8
  import { ThemeToggle } from '@/components/common/theme-toggle';
9
9
  import { SoundToggle } from '@/components/common/sound-toggle';
10
10
  import { AgentEventsProvider } from '@/hooks/agent-events-provider';
@@ -0,0 +1,343 @@
1
+ 'use client';
2
+
3
+ import { useState, useMemo, useCallback, useRef } from 'react';
4
+ import type { Edge } from '@xyflow/react';
5
+ import type { CanvasNodeType } from '@/components/features/features-canvas';
6
+ import type { FeatureNodeData } from '@/components/common/feature-node';
7
+ import type { RepositoryNodeData } from '@/components/common/repository-node';
8
+ import {
9
+ deriveGraph,
10
+ type FeatureEntry,
11
+ type RepoEntry,
12
+ type GraphCallbacks,
13
+ } from '@/lib/derive-graph';
14
+ import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS } from '@/lib/layout-with-dagre';
15
+
16
+ export type { GraphCallbacks } from '@/lib/derive-graph';
17
+
18
+ export interface UseGraphStateReturn {
19
+ /** Derived React Flow nodes (from domain Maps). */
20
+ nodes: CanvasNodeType[];
21
+ /** Derived React Flow edges (from domain Maps). */
22
+ edges: Edge[];
23
+ /**
24
+ * Reconcile domain Maps with fresh server data (new initialNodes/initialEdges).
25
+ * Preserves pending (creating) nodes unless a matching real feature appears.
26
+ */
27
+ reconcile: (newNodes: CanvasNodeType[], newEdges: Edge[]) => void;
28
+ /** Update a feature's state/lifecycle/name (e.g., from SSE events). */
29
+ updateFeature: (
30
+ featureNodeId: string,
31
+ updates: Partial<Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>>
32
+ ) => void;
33
+ /** Add a pending (optimistic) feature node (state='creating'). */
34
+ addPendingFeature: (nodeId: string, data: FeatureNodeData, parentNodeId?: string) => void;
35
+ /** Remove a pending feature node (e.g., on rollback). */
36
+ removePendingFeature: (nodeId: string) => void;
37
+ /** Remove a real feature node from the domain Map. */
38
+ removeFeature: (nodeId: string) => void;
39
+ /** Restore a previously removed feature (rollback). */
40
+ restoreFeature: (nodeId: string, entry: FeatureEntry) => void;
41
+ /** Add a repository node (may use a temp ID initially). */
42
+ addRepository: (nodeId: string, data: RepositoryNodeData) => void;
43
+ /** Remove a repository node. */
44
+ removeRepository: (nodeId: string) => void;
45
+ /** Replace a temp repo ID with the real one (atomic). */
46
+ replaceRepository: (tempId: string, realId: string, data: RepositoryNodeData) => void;
47
+ /** Stable lookup: get the repositoryPath for a feature node. */
48
+ getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;
49
+ /** Stable lookup: get repository node data by nodeId. */
50
+ getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;
51
+ /** Update callbacks injected into node data (does NOT trigger re-render). */
52
+ setCallbacks: (callbacks: GraphCallbacks) => void;
53
+ }
54
+
55
+ /** Parse initialNodes + initialEdges into domain Maps. */
56
+ function parseMaps(
57
+ initialNodes: CanvasNodeType[],
58
+ initialEdges: Edge[]
59
+ ): {
60
+ featureMap: Map<string, FeatureEntry>;
61
+ repoMap: Map<string, RepoEntry>;
62
+ } {
63
+ // Build parentNodeId map from dependency edges
64
+ const parentByChild = new Map<string, string>();
65
+ for (const edge of initialEdges) {
66
+ if (edge.type === 'dependencyEdge' || edge.id.startsWith('dep-')) {
67
+ parentByChild.set(edge.target, edge.source);
68
+ }
69
+ }
70
+
71
+ const featureMap = new Map<string, FeatureEntry>();
72
+ const repoMap = new Map<string, RepoEntry>();
73
+
74
+ for (const node of initialNodes) {
75
+ if (node.type === 'featureNode') {
76
+ featureMap.set(node.id, {
77
+ nodeId: node.id,
78
+ data: node.data as FeatureNodeData,
79
+ parentNodeId: parentByChild.get(node.id),
80
+ });
81
+ } else if (node.type === 'repositoryNode') {
82
+ repoMap.set(node.id, {
83
+ nodeId: node.id,
84
+ data: node.data as RepositoryNodeData,
85
+ });
86
+ }
87
+ }
88
+
89
+ return { featureMap, repoMap };
90
+ }
91
+
92
+ export function useGraphState(
93
+ initialNodes: CanvasNodeType[],
94
+ initialEdges: Edge[]
95
+ ): UseGraphStateReturn {
96
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional: parse only on mount (like useState initializer)
97
+ const init = useMemo(() => parseMaps(initialNodes, initialEdges), []);
98
+
99
+ const [featureMap, setFeatureMap] = useState<Map<string, FeatureEntry>>(init.featureMap);
100
+ const [repoMap, setRepoMap] = useState<Map<string, RepoEntry>>(init.repoMap);
101
+ const [pendingMap, setPendingMap] = useState<Map<string, FeatureEntry>>(
102
+ new Map<string, FeatureEntry>()
103
+ );
104
+
105
+ // Buffer for SSE updates that arrive before their feature is in featureMap.
106
+ // When reconcile adds new features, buffered updates are applied automatically.
107
+ const pendingUpdatesRef = useRef<
108
+ Map<string, Partial<Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>>>
109
+ >(new Map());
110
+
111
+ // Callbacks stored in a ref so changing them doesn't trigger re-render.
112
+ // The stable wrapper object reads from the ref so node closures always use latest callbacks.
113
+ const callbacksRef = useRef<GraphCallbacks>({});
114
+ const stableCallbacks = useMemo<GraphCallbacks>(
115
+ () => ({
116
+ onNodeAction: (nodeId) => callbacksRef.current.onNodeAction?.(nodeId),
117
+ onNodeSettings: (nodeId) => callbacksRef.current.onNodeSettings?.(nodeId),
118
+ onFeatureDelete: (featureId) => callbacksRef.current.onFeatureDelete?.(featureId),
119
+ onRepositoryAdd: (nodeId) => callbacksRef.current.onRepositoryAdd?.(nodeId),
120
+ onRepositoryClick: (nodeId) => callbacksRef.current.onRepositoryClick?.(nodeId),
121
+ onRepositoryDelete: (repositoryId) => callbacksRef.current.onRepositoryDelete?.(repositoryId),
122
+ }),
123
+ []
124
+ );
125
+
126
+ // Stable refs for domain Maps (for use in callbacks without depending on state)
127
+ const featureMapRef = useRef(featureMap);
128
+ featureMapRef.current = featureMap;
129
+ const repoMapRef = useRef(repoMap);
130
+ repoMapRef.current = repoMap;
131
+
132
+ // Derived nodes/edges — only re-runs when domain Maps change (not callbacks)
133
+ const { nodes, edges } = useMemo(() => {
134
+ const derived = deriveGraph(featureMap, repoMap, pendingMap, stableCallbacks);
135
+ return layoutWithDagre(derived.nodes, derived.edges, CANVAS_LAYOUT_DEFAULTS);
136
+ }, [featureMap, repoMap, pendingMap, stableCallbacks]);
137
+
138
+ // --- Mutations ---
139
+
140
+ const reconcile = useCallback((newNodes: CanvasNodeType[], newEdges: Edge[]) => {
141
+ const { featureMap: newFeatureMap, repoMap: newRepoMap } = parseMaps(newNodes, newEdges);
142
+
143
+ setFeatureMap((currentFeatureMap) => {
144
+ // Preserve pending (creating) nodes unless matched by name+repositoryPath from newFeatureMap
145
+ const pendingEntries = [...currentFeatureMap.entries()].filter(
146
+ ([, e]) => e.data.state === 'creating'
147
+ );
148
+
149
+ const merged = new Map(newFeatureMap);
150
+
151
+ // Keep pending nodes that don't have a real counterpart in new data
152
+ for (const [tempId, pendingEntry] of pendingEntries) {
153
+ const matched = [...newFeatureMap.values()].some(
154
+ (e) =>
155
+ e.data.name === pendingEntry.data.name &&
156
+ e.data.repositoryPath === pendingEntry.data.repositoryPath
157
+ );
158
+ if (!matched) {
159
+ merged.set(tempId, pendingEntry);
160
+ }
161
+ }
162
+
163
+ // Apply any buffered SSE updates to features that now exist in the map
164
+ for (const [nodeId, updates] of pendingUpdatesRef.current) {
165
+ const entry = merged.get(nodeId);
166
+ if (entry) {
167
+ merged.set(nodeId, { ...entry, data: { ...entry.data, ...updates } });
168
+ pendingUpdatesRef.current.delete(nodeId);
169
+ }
170
+ }
171
+
172
+ return merged;
173
+ });
174
+
175
+ // Clean pendingMap entries that now have a real counterpart in server data
176
+ setPendingMap((currentPendingMap) => {
177
+ if (currentPendingMap.size === 0) return currentPendingMap;
178
+ let changed = false;
179
+ const next = new Map(currentPendingMap);
180
+ for (const [tempId, pendingEntry] of currentPendingMap) {
181
+ const matched = [...newFeatureMap.values()].some(
182
+ (e) =>
183
+ e.data.name === pendingEntry.data.name &&
184
+ e.data.repositoryPath === pendingEntry.data.repositoryPath
185
+ );
186
+ if (matched) {
187
+ next.delete(tempId);
188
+ changed = true;
189
+ }
190
+ }
191
+ return changed ? next : currentPendingMap;
192
+ });
193
+
194
+ setRepoMap(newRepoMap);
195
+ }, []);
196
+
197
+ const updateFeature = useCallback(
198
+ (
199
+ featureNodeId: string,
200
+ updates: Partial<Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>>
201
+ ) => {
202
+ setFeatureMap((prev) => {
203
+ const entry = prev.get(featureNodeId);
204
+ if (!entry) {
205
+ // Feature not yet in map — buffer update for when reconcile adds it
206
+ pendingUpdatesRef.current.set(featureNodeId, {
207
+ ...pendingUpdatesRef.current.get(featureNodeId),
208
+ ...updates,
209
+ });
210
+ return prev;
211
+ }
212
+ // Clear any buffered update for this feature since it's now in the map
213
+ pendingUpdatesRef.current.delete(featureNodeId);
214
+ // Skip if no actual change (prevents unnecessary re-renders on event replay)
215
+ const stateUnchanged = updates.state === undefined || updates.state === entry.data.state;
216
+ const lifecycleUnchanged =
217
+ updates.lifecycle === undefined || updates.lifecycle === entry.data.lifecycle;
218
+ const nameUnchanged = updates.name === undefined || updates.name === entry.data.name;
219
+ const descUnchanged =
220
+ updates.description === undefined || updates.description === entry.data.description;
221
+ if (stateUnchanged && lifecycleUnchanged && nameUnchanged && descUnchanged) {
222
+ return prev;
223
+ }
224
+ const next = new Map(prev);
225
+ next.set(featureNodeId, { ...entry, data: { ...entry.data, ...updates } });
226
+ return next;
227
+ });
228
+
229
+ // Also check pendingMap
230
+ setPendingMap((prev) => {
231
+ const entry = prev.get(featureNodeId);
232
+ if (!entry) return prev;
233
+ const stateUnchanged = updates.state === undefined || updates.state === entry.data.state;
234
+ const lifecycleUnchanged =
235
+ updates.lifecycle === undefined || updates.lifecycle === entry.data.lifecycle;
236
+ const nameUnchanged = updates.name === undefined || updates.name === entry.data.name;
237
+ const descUnchanged =
238
+ updates.description === undefined || updates.description === entry.data.description;
239
+ if (stateUnchanged && lifecycleUnchanged && nameUnchanged && descUnchanged) return prev;
240
+ const next = new Map(prev);
241
+ next.set(featureNodeId, { ...entry, data: { ...entry.data, ...updates } });
242
+ return next;
243
+ });
244
+ },
245
+ []
246
+ );
247
+
248
+ const addPendingFeature = useCallback(
249
+ (nodeId: string, data: FeatureNodeData, parentNodeId?: string) => {
250
+ setPendingMap((prev) => {
251
+ const next = new Map(prev);
252
+ next.set(nodeId, { nodeId, data, parentNodeId });
253
+ return next;
254
+ });
255
+ },
256
+ []
257
+ );
258
+
259
+ const removePendingFeature = useCallback((nodeId: string) => {
260
+ setPendingMap((prev) => {
261
+ if (!prev.has(nodeId)) return prev;
262
+ const next = new Map(prev);
263
+ next.delete(nodeId);
264
+ return next;
265
+ });
266
+ }, []);
267
+
268
+ const removeFeature = useCallback((nodeId: string) => {
269
+ setFeatureMap((prev) => {
270
+ if (!prev.has(nodeId)) return prev;
271
+ const next = new Map(prev);
272
+ next.delete(nodeId);
273
+ return next;
274
+ });
275
+ }, []);
276
+
277
+ const restoreFeature = useCallback((nodeId: string, entry: FeatureEntry) => {
278
+ setFeatureMap((prev) => {
279
+ const next = new Map(prev);
280
+ next.set(nodeId, entry);
281
+ return next;
282
+ });
283
+ }, []);
284
+
285
+ const addRepository = useCallback((nodeId: string, data: RepositoryNodeData) => {
286
+ setRepoMap((prev) => {
287
+ const next = new Map(prev);
288
+ next.set(nodeId, { nodeId, data });
289
+ return next;
290
+ });
291
+ }, []);
292
+
293
+ const removeRepository = useCallback((nodeId: string) => {
294
+ setRepoMap((prev) => {
295
+ if (!prev.has(nodeId)) return prev;
296
+ const next = new Map(prev);
297
+ next.delete(nodeId);
298
+ return next;
299
+ });
300
+ }, []);
301
+
302
+ const replaceRepository = useCallback(
303
+ (tempId: string, realId: string, data: RepositoryNodeData) => {
304
+ setRepoMap((prev) => {
305
+ if (!prev.has(tempId)) return prev;
306
+ const next = new Map(prev);
307
+ next.delete(tempId);
308
+ next.set(realId, { nodeId: realId, data });
309
+ return next;
310
+ });
311
+ },
312
+ []
313
+ );
314
+
315
+ const getFeatureRepositoryPath = useCallback((featureNodeId: string): string | undefined => {
316
+ return featureMapRef.current.get(featureNodeId)?.data.repositoryPath;
317
+ }, []);
318
+
319
+ const getRepositoryData = useCallback((nodeId: string): RepositoryNodeData | undefined => {
320
+ return repoMapRef.current.get(nodeId)?.data;
321
+ }, []);
322
+
323
+ const setCallbacks = useCallback((callbacks: GraphCallbacks) => {
324
+ callbacksRef.current = callbacks;
325
+ }, []);
326
+
327
+ return {
328
+ nodes,
329
+ edges,
330
+ reconcile,
331
+ updateFeature,
332
+ addPendingFeature,
333
+ removePendingFeature,
334
+ removeFeature,
335
+ restoreFeature,
336
+ addRepository,
337
+ removeRepository,
338
+ replaceRepository,
339
+ getFeatureRepositoryPath,
340
+ getRepositoryData,
341
+ setCallbacks,
342
+ };
343
+ }