@shepai/cli 1.122.2-pr390.b1ef40f → 1.122.2-pr392.a8f2b76

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 (226) hide show
  1. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts +0 -6
  2. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
  3. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +0 -60
  4. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts +2 -0
  5. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.d.ts.map +1 -1
  6. package/dist/src/presentation/web/app/actions/get-feature-phase-timings.js +2 -0
  7. package/dist/src/presentation/web/app/build-graph-nodes.d.ts +0 -7
  8. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
  9. package/dist/src/presentation/web/app/build-graph-nodes.js +0 -7
  10. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  11. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +20 -9
  12. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.d.ts.map +1 -1
  13. package/dist/src/presentation/web/components/common/feature-drawer-tabs/activity-tab.js +130 -31
  14. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.d.ts.map +1 -1
  15. package/dist/src/presentation/web/components/common/feature-drawer-tabs/feature-drawer-tabs.js +13 -0
  16. package/dist/src/presentation/web/components/common/feature-drawer-tabs/use-tab-data-fetch.d.ts.map +1 -1
  17. package/dist/src/presentation/web/components/common/feature-drawer-tabs/use-tab-data-fetch.js +18 -9
  18. package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts +0 -8
  19. package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
  21. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +6 -6
  22. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts +0 -2
  23. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts.map +1 -1
  24. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.js +17 -107
  25. package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.js +18 -18
  27. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  28. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +31 -17
  29. package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.d.ts.map +1 -1
  30. package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.js +29 -22
  31. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +1 -1
  32. package/dist/src/presentation/web/components/layouts/app-shell/app-shell.d.ts.map +1 -1
  33. package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +2 -2
  34. package/dist/src/presentation/web/hooks/sidebar-features-context.d.ts +2 -0
  35. package/dist/src/presentation/web/hooks/sidebar-features-context.d.ts.map +1 -1
  36. package/dist/src/presentation/web/hooks/sidebar-features-context.js +2 -1
  37. package/dist/src/presentation/web/lib/layout-with-dagre.js +1 -1
  38. package/dist/tsconfig.build.tsbuildinfo +1 -1
  39. package/package.json +1 -1
  40. package/web/.next/BUILD_ID +1 -1
  41. package/web/.next/build-manifest.json +2 -2
  42. package/web/.next/fallback-build-manifest.json +2 -2
  43. package/web/.next/prerender-manifest.json +3 -3
  44. package/web/.next/required-server-files.js +1 -1
  45. package/web/.next/required-server-files.json +1 -1
  46. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +22 -22
  47. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +2 -2
  48. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  49. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
  51. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +3 -3
  52. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  53. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +28 -28
  55. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  56. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  57. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
  59. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +2 -2
  60. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  61. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +22 -22
  63. package/web/.next/server/app/(dashboard)/create/page.js +2 -2
  64. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  65. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
  67. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +3 -3
  68. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  69. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +28 -28
  71. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  72. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  73. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +20 -20
  75. package/web/.next/server/app/(dashboard)/page.js +2 -2
  76. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  77. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
  79. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +2 -2
  80. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  81. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  82. package/web/.next/server/app/_global-error.html +2 -2
  83. package/web/.next/server/app/_global-error.rsc +1 -1
  84. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  85. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  86. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  87. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  88. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  89. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  90. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/api/graph-data/route.js +1 -1
  92. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  93. package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
  94. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  95. package/web/.next/server/app/settings/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_client-reference-manifest.js +1 -1
  98. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  99. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  100. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  101. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  102. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  103. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
  104. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
  105. package/web/.next/server/chunks/[root-of-the-server]__42b7ab55._.js +3 -0
  106. package/web/.next/server/chunks/{[root-of-the-server]__dcd4f847._.js.map → [root-of-the-server]__42b7ab55._.js.map} +1 -1
  107. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  108. package/web/.next/server/chunks/ssr/403f9_next_dist_31ea46d3._.js +1 -1
  109. package/web/.next/server/chunks/ssr/403f9_next_dist_c9d9b4d7._.js +1 -1
  110. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  111. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  112. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +1 -1
  113. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +1 -1
  114. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +1 -1
  115. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +1 -1
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
  117. package/web/.next/server/chunks/ssr/{[root-of-the-server]__9e8b25ad._.js → [root-of-the-server]__2698e9f4._.js} +2 -2
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js.map +1 -0
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +1 -1
  120. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +1 -1
  121. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  123. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  124. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  125. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  126. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
  128. package/web/.next/server/chunks/ssr/{[root-of-the-server]__7cbda1ea._.js → [root-of-the-server]__8e3bf5d7._.js} +2 -2
  129. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js.map +1 -0
  130. package/web/.next/server/chunks/ssr/{[root-of-the-server]__14664e9b._.js → [root-of-the-server]__a022445f._.js} +3 -3
  131. package/web/.next/server/chunks/ssr/{[root-of-the-server]__14664e9b._.js.map → [root-of-the-server]__a022445f._.js.map} +1 -1
  132. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +2 -2
  133. package/web/.next/server/chunks/ssr/[root-of-the-server]__b724df9e._.js +3 -0
  134. package/web/.next/server/chunks/ssr/{[root-of-the-server]__6677a82c._.js.map → [root-of-the-server]__b724df9e._.js.map} +1 -1
  135. package/web/.next/server/chunks/ssr/{[root-of-the-server]__aed1d6f8._.js → [root-of-the-server]__c07f9f79._.js} +2 -2
  136. package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js.map +1 -0
  137. package/web/.next/server/chunks/ssr/{[root-of-the-server]__ce6057f6._.js → [root-of-the-server]__c605a375._.js} +2 -2
  138. package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js.map +1 -0
  139. package/web/.next/server/chunks/ssr/[root-of-the-server]__f646b99a._.js +3 -0
  140. package/web/.next/server/chunks/ssr/[root-of-the-server]__f646b99a._.js.map +1 -0
  141. package/web/.next/server/chunks/ssr/{_e9703421._.js → _0dc2cfd3._.js} +2 -2
  142. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js.map +1 -0
  143. package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
  144. package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
  145. package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
  146. package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
  147. package/web/.next/server/chunks/ssr/{_15fe9326._.js → _36dccae9._.js} +2 -2
  148. package/web/.next/server/chunks/ssr/_36dccae9._.js.map +1 -0
  149. package/web/.next/server/chunks/ssr/_3a4c94e3._.js +1 -1
  150. package/web/.next/server/chunks/ssr/_75f4ccb3._.js +3 -0
  151. package/web/.next/server/chunks/ssr/_75f4ccb3._.js.map +1 -0
  152. package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
  153. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
  154. package/web/.next/server/chunks/ssr/_d99705a5._.js +3 -0
  155. package/web/.next/server/chunks/ssr/_d99705a5._.js.map +1 -0
  156. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  157. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  158. package/web/.next/server/chunks/ssr/node_modules__pnpm_b59e4b16._.js +3 -0
  159. package/web/.next/server/chunks/ssr/node_modules__pnpm_b59e4b16._.js.map +1 -0
  160. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +2 -2
  161. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js.map +1 -1
  162. package/web/.next/server/chunks/ssr/src_presentation_web_60c91521._.js +3 -0
  163. package/web/.next/server/chunks/ssr/src_presentation_web_60c91521._.js.map +1 -0
  164. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +1 -1
  165. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +1 -1
  166. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  167. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  168. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  169. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  170. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +2 -2
  171. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js.map +1 -1
  172. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  173. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  174. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  175. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  176. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  177. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  178. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  179. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  180. package/web/.next/server/pages/500.html +2 -2
  181. package/web/.next/server/server-reference-manifest.js +1 -1
  182. package/web/.next/server/server-reference-manifest.json +34 -34
  183. package/web/.next/static/chunks/{2c0cf874cda01236.js → 1c19bf1f99269544.js} +1 -1
  184. package/web/.next/static/chunks/275f0d403059b5b4.js +1 -0
  185. package/web/.next/static/chunks/3911a7175044e784.js +1 -0
  186. package/web/.next/static/chunks/61df7e9671cf4e76.css +1 -0
  187. package/web/.next/static/chunks/{fadc79bbbae100a7.js → 6272719b144b6c1a.js} +1 -1
  188. package/web/.next/static/chunks/691a93561029b01b.js +2 -0
  189. package/web/.next/static/chunks/6db4aa6aed9e6545.js +1 -0
  190. package/web/.next/static/chunks/{9fba6bb38ff0cb38.js → 816ee0f2c6b490a4.js} +2 -2
  191. package/web/.next/static/chunks/845d8e58a91014e6.js +1 -0
  192. package/web/.next/static/chunks/{24a0b215d72d8f26.js → 90e7434ef9395b62.js} +1 -1
  193. package/web/.next/static/chunks/a92706d178a3fa6c.js +1 -0
  194. package/web/.next/static/chunks/bf479173877b0a2f.js +1 -0
  195. package/web/.next/static/chunks/{96eeeb28e06de78c.js → dbbb446493f21874.js} +1 -1
  196. package/web/.next/static/chunks/f90f55b8e972bd8e.js +1 -0
  197. package/web/.next/server/chunks/[root-of-the-server]__dcd4f847._.js +0 -3
  198. package/web/.next/server/chunks/ssr/[root-of-the-server]__6677a82c._.js +0 -3
  199. package/web/.next/server/chunks/ssr/[root-of-the-server]__7cbda1ea._.js.map +0 -1
  200. package/web/.next/server/chunks/ssr/[root-of-the-server]__9e8b25ad._.js.map +0 -1
  201. package/web/.next/server/chunks/ssr/[root-of-the-server]__aed1d6f8._.js.map +0 -1
  202. package/web/.next/server/chunks/ssr/[root-of-the-server]__ce6057f6._.js.map +0 -1
  203. package/web/.next/server/chunks/ssr/[root-of-the-server]__e7258841._.js +0 -3
  204. package/web/.next/server/chunks/ssr/[root-of-the-server]__e7258841._.js.map +0 -1
  205. package/web/.next/server/chunks/ssr/_15fe9326._.js.map +0 -1
  206. package/web/.next/server/chunks/ssr/_90a34ae9._.js +0 -3
  207. package/web/.next/server/chunks/ssr/_90a34ae9._.js.map +0 -1
  208. package/web/.next/server/chunks/ssr/_b56e7571._.js +0 -3
  209. package/web/.next/server/chunks/ssr/_b56e7571._.js.map +0 -1
  210. package/web/.next/server/chunks/ssr/_e9703421._.js.map +0 -1
  211. package/web/.next/server/chunks/ssr/_f096ab6a._.js +0 -3
  212. package/web/.next/server/chunks/ssr/_f096ab6a._.js.map +0 -1
  213. package/web/.next/server/chunks/ssr/node_modules__pnpm_bc66dcc6._.js +0 -3
  214. package/web/.next/server/chunks/ssr/node_modules__pnpm_bc66dcc6._.js.map +0 -1
  215. package/web/.next/static/chunks/4232eb19944a519e.js +0 -1
  216. package/web/.next/static/chunks/4443ee9c7733399b.js +0 -1
  217. package/web/.next/static/chunks/6b8c3e3d8d4ee08e.js +0 -1
  218. package/web/.next/static/chunks/a58429fc5be52aad.js +0 -1
  219. package/web/.next/static/chunks/b200a40ffcc15eb7.css +0 -1
  220. package/web/.next/static/chunks/b67d183d3c074a4c.js +0 -2
  221. package/web/.next/static/chunks/ca946dcbfbb2df74.js +0 -1
  222. package/web/.next/static/chunks/cd2bb43fe9138791.js +0 -1
  223. package/web/.next/static/chunks/d2bfdee31e1a7d8d.js +0 -1
  224. /package/web/.next/static/{Fr059mDxLxW71ARoHnB8W → x39t_TXToqcf-uNwPMhq8}/_buildManifest.js +0 -0
  225. /package/web/.next/static/{Fr059mDxLxW71ARoHnB8W → x39t_TXToqcf-uNwPMhq8}/_clientMiddlewareManifest.json +0 -0
  226. /package/web/.next/static/{Fr059mDxLxW71ARoHnB8W → x39t_TXToqcf-uNwPMhq8}/_ssgManifest.js +0 -0
@@ -54,11 +54,16 @@ export function useTabDataFetch(featureId, fetchers) {
54
54
  const currentFeatureId = featureIdRef.current;
55
55
  if (!fetcher)
56
56
  return;
57
+ // Only show loading spinner when there's no existing data.
58
+ // On refresh (data already present), keep showing stale data while fetching
59
+ // to avoid flickering the entire tab on every poll cycle.
57
60
  if (mountedRef.current) {
58
- setTabStates((prev) => ({
59
- ...prev,
60
- [tab]: { ...prev[tab], loading: true, error: null },
61
- }));
61
+ setTabStates((prev) => {
62
+ const hasData = prev[tab]?.data !== null;
63
+ if (hasData)
64
+ return prev; // Keep stale data visible — no loading flash
65
+ return { ...prev, [tab]: { ...prev[tab], loading: true, error: null } };
66
+ });
62
67
  }
63
68
  try {
64
69
  const data = await fetcher(currentFeatureId);
@@ -71,11 +76,15 @@ export function useTabDataFetch(featureId, fetchers) {
71
76
  }
72
77
  catch (error) {
73
78
  if (mountedRef.current) {
74
- const message = error instanceof Error ? error.message : 'Failed to fetch tab data';
75
- setTabStates((prev) => ({
76
- ...prev,
77
- [tab]: { data: null, loading: false, error: message },
78
- }));
79
+ setTabStates((prev) => {
80
+ const message = error instanceof Error ? error.message : 'Failed to fetch tab data';
81
+ // On refresh failure, keep existing data instead of clearing it
82
+ const existingData = prev[tab]?.data ?? null;
83
+ return {
84
+ ...prev,
85
+ [tab]: { data: existingData, loading: false, error: existingData ? null : message },
86
+ };
87
+ });
79
88
  }
80
89
  }
81
90
  }, []);
@@ -9,14 +9,6 @@ export interface RepositoryNodeData {
9
9
  repositoryPath?: string;
10
10
  /** Creation timestamp (epoch ms) — used for stable vertical ordering. */
11
11
  createdAt?: number;
12
- /** Current git branch name (e.g. "main", "feat/my-feature") */
13
- branch?: string;
14
- /** Commit message of the branch HEAD (first line only) */
15
- commitMessage?: string;
16
- /** Name of the person who made the latest commit */
17
- committer?: string;
18
- /** Number of commits the current branch is behind the default branch. null if on default branch or unknown. */
19
- behindCount?: number | null;
20
12
  onClick?: () => void;
21
13
  onAdd?: () => void;
22
14
  onDelete?: (repositoryId: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+GAA+G;IAC/G,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"repository-node-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,2CA+U5F"}
1
+ {"version":3,"file":"repository-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,2CAyR5F"}
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useState, useCallback } from 'react';
4
4
  import { Handle, Position } from '@xyflow/react';
5
5
  import { useRouter } from 'next/navigation';
6
- import { Github, Plus, Code2, Terminal, FolderOpen, Trash2, Play, Square, GitBranch, GitCommitHorizontal, ArrowDown, User, } from 'lucide-react';
6
+ import { Github, Plus, Code2, Terminal, FolderOpen, Trash2, Play, Square } from 'lucide-react';
7
7
  import { cn } from '../../../lib/utils.js';
8
8
  import { ActionButton } from '../../common/action-button/index.js';
9
9
  import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../../ui/dialog.js';
@@ -72,9 +72,9 @@ export function RepositoryNode({ data }) {
72
72
  e.stopPropagation();
73
73
  data.onClick?.();
74
74
  }
75
- }, className: "nodrag bg-card flex w-[26rem] cursor-pointer flex-col overflow-hidden rounded-xl border shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-3", children: [_jsx(Github, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { "data-testid": "repository-node-name", className: "min-w-0 truncate text-sm font-medium", children: data.name }), _jsxs("div", { className: cn('flex shrink-0 items-center gap-2', (data.repositoryPath ?? data.onAdd) && 'ml-auto'), onClick: (e) => e.stopPropagation(), children: [data.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in IDE" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in Shell" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open Folder" })] }) }), _jsx(FeatureSessionsDropdown, { repositoryPath: data.repositoryPath, onCreateFromSession: handleCreateFromSession }), featureFlags.envDeploy ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: data.repositoryPath })) : null] })) : null] })) : null, data.onAdd ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Add feature", "data-testid": "repository-node-add-button", onClick: (e) => {
76
- e.stopPropagation();
77
- data.onAdd?.();
78
- }, className: cn('text-muted-foreground hover:bg-accent dark:hover:bg-accent/50 flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-full transition-colors hover:text-blue-500', data.pulseAdd &&
79
- 'animate-pulse-cta bg-blue-100 text-blue-500 dark:bg-blue-900/40'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Add feature" })] }) })) : null] })] }), data.branch ? (_jsx("div", { "data-testid": "repository-node-git-info", className: "text-muted-foreground border-t px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-3 text-xs", children: [_jsxs("span", { className: "flex items-center gap-1 truncate", "data-testid": "repository-node-branch", children: [_jsx(GitBranch, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "truncate", children: data.branch })] }), data.behindCount != null && data.behindCount > 0 ? (_jsxs("span", { className: "flex shrink-0 items-center gap-1 whitespace-nowrap text-amber-500", "data-testid": "repository-node-behind", children: [_jsx(ArrowDown, { className: "h-3 w-3 shrink-0" }), data.behindCount, " behind"] })) : null] }) })) : null, data.commitMessage ? (_jsx("div", { "data-testid": "repository-node-commit-info", className: "text-muted-foreground border-t px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-2 text-xs", children: [_jsx(GitCommitHorizontal, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "min-w-0 truncate", "data-testid": "repository-node-commit-message", children: data.commitMessage }), data.committer ? (_jsxs("span", { className: "text-muted-foreground/70 ml-auto flex shrink-0 items-center gap-1", "data-testid": "repository-node-committer", children: [_jsx(User, { className: "h-3 w-3 shrink-0" }), _jsx("span", { children: data.committer })] })) : null] }) })) : null] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
75
+ }, className: "nodrag bg-card flex min-w-[18rem] cursor-pointer items-center gap-3 rounded-full border px-4 py-3 shadow-sm", children: [_jsx(Github, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { "data-testid": "repository-node-name", className: "min-w-0 truncate text-sm font-medium", children: data.name }), _jsxs("div", { className: cn('flex shrink-0 items-center gap-2', (data.repositoryPath ?? data.onAdd) && 'ml-auto'), onClick: (e) => e.stopPropagation(), children: [data.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in IDE" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in Shell" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open Folder" })] }) }), _jsx(FeatureSessionsDropdown, { repositoryPath: data.repositoryPath, onCreateFromSession: handleCreateFromSession }), featureFlags.envDeploy ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: data.repositoryPath })) : null] })) : null] })) : null, data.onAdd ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Add feature", "data-testid": "repository-node-add-button", onClick: (e) => {
76
+ e.stopPropagation();
77
+ data.onAdd?.();
78
+ }, className: cn('text-muted-foreground hover:bg-accent dark:hover:bg-accent/50 flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-full transition-colors hover:text-blue-500', data.pulseAdd &&
79
+ 'animate-pulse-cta bg-blue-100 text-blue-500 dark:bg-blue-900/40'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Add feature" })] }) })) : null] })] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
80
80
  }
@@ -14,6 +14,4 @@ export declare const WithActions: Story;
14
14
  export declare const WithActionsAndAddButton: Story;
15
15
  export declare const WithDeleteButton: Story;
16
16
  export declare const MultipleWithActions: Story;
17
- export declare const WithGitInfo: Story;
18
- export declare const WithGitInfoBehind: Story;
19
17
  //# sourceMappingURL=repository-node.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,0BAA0B,CAAC;AAgCvF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,kBAAkB,CAYlC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAE1C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAK3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAiCF,eAAO,MAAM,QAAQ,EAAE,KAwBtB,CAAC;AAkCF,eAAO,MAAM,kBAAkB,EAAE,KAwBhC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAS1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,KAQrC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,KAS9B,CAAC;AA+CF,eAAO,MAAM,mBAAmB,EAAE,KAwBjC,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KASzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAS/B,CAAC"}
1
+ {"version":3,"file":"repository-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,0BAA0B,CAAC;AAgCvF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,kBAAkB,CASlC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAE1C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAK3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAWF,eAAO,MAAM,QAAQ,EAAE,KAwBtB,CAAC;AASF,eAAO,MAAM,kBAAkB,EAAE,KAwBhC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAS1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,KAQrC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,KAS9B,CAAC;AA2BF,eAAO,MAAM,mBAAmB,EAAE,KAwBjC,CAAC"}
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
3
3
  import { ReactFlowProvider, ReactFlow } from '@xyflow/react';
4
4
  import { RepositoryNode } from './repository-node.js';
5
5
  const nodeTypes = { repositoryNode: RepositoryNode };
6
- function RepositoryNodeCanvas({ data, style = { width: 550, height: 300 }, }) {
6
+ function RepositoryNodeCanvas({ data, style = { width: 500, height: 250 }, }) {
7
7
  const nodes = useMemo(() => [{ id: 'node-1', type: 'repositoryNode', position: { x: 0, y: 0 }, data }], [data]);
8
8
  return (_jsx("div", { style: style, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
9
9
  }
@@ -15,9 +15,6 @@ const meta = {
15
15
  },
16
16
  args: {
17
17
  name: 'shep-ai/cli',
18
- branch: 'main',
19
- commitMessage: 'feat: add dark mode toggle',
20
- committer: 'Jane Doe',
21
18
  },
22
19
  };
23
20
  export default meta;
@@ -44,84 +41,37 @@ export const LongName = {
44
41
  };
45
42
  const onAdd = () => undefined;
46
43
  const multipleRepos = [
47
- {
48
- name: 'shep-ai/cli',
49
- branch: 'main',
50
- commitMessage: 'feat: add dark mode toggle',
51
- committer: 'Jane Doe',
52
- },
53
- {
54
- name: 'vercel/edge-runtime',
55
- branch: 'feat/streaming',
56
- commitMessage: 'fix: handle edge cases in streaming',
57
- committer: 'John Smith',
58
- behindCount: 3,
59
- },
60
- {
61
- name: 'acme-corp/web-dashboard-v2',
62
- branch: 'develop',
63
- commitMessage: 'chore: update dependencies',
64
- committer: 'Bot',
65
- behindCount: 12,
66
- },
67
- {
68
- name: 'openai/tiktoken',
69
- branch: 'main',
70
- commitMessage: 'perf: optimize token encoding',
71
- committer: 'Alice Chen',
72
- },
44
+ { name: 'shep-ai/cli' },
45
+ { name: 'vercel/edge-runtime' },
46
+ { name: 'acme-corp/web-dashboard-v2' },
47
+ { name: 'openai/tiktoken' },
73
48
  ];
74
49
  export const Multiple = {
75
50
  render: () => {
76
51
  const nodes = multipleRepos.map((data, i) => ({
77
52
  id: `repo-${i}`,
78
53
  type: 'repositoryNode',
79
- position: { x: 0, y: i * 140 },
54
+ position: { x: 0, y: i * 80 },
80
55
  data,
81
56
  }));
82
- return (_jsx("div", { style: { width: 600, height: 750 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
57
+ return (_jsx("div", { style: { width: 500, height: 500 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
83
58
  },
84
59
  };
85
60
  const multipleReposWithButton = [
86
- {
87
- name: 'shep-ai/cli',
88
- onAdd,
89
- branch: 'main',
90
- commitMessage: 'feat: add dark mode toggle',
91
- committer: 'Jane Doe',
92
- },
93
- {
94
- name: 'vercel/edge-runtime',
95
- onAdd,
96
- branch: 'feat/streaming',
97
- commitMessage: 'fix: handle edge cases in streaming',
98
- committer: 'John Smith',
99
- behindCount: 3,
100
- },
101
- {
102
- name: 'acme-corp/web-dashboard-v2',
103
- onAdd,
104
- branch: 'develop',
105
- commitMessage: 'chore: update dependencies',
106
- committer: 'Bot',
107
- },
108
- {
109
- name: 'openai/tiktoken',
110
- onAdd,
111
- branch: 'main',
112
- commitMessage: 'perf: optimize token encoding',
113
- committer: 'Alice Chen',
114
- },
61
+ { name: 'shep-ai/cli', onAdd },
62
+ { name: 'vercel/edge-runtime', onAdd },
63
+ { name: 'acme-corp/web-dashboard-v2', onAdd },
64
+ { name: 'openai/tiktoken', onAdd },
115
65
  ];
116
66
  export const MultipleWithButton = {
117
67
  render: () => {
118
68
  const nodes = multipleReposWithButton.map((data, i) => ({
119
69
  id: `repo-${i}`,
120
70
  type: 'repositoryNode',
121
- position: { x: 0, y: i * 140 },
71
+ position: { x: 0, y: i * 80 },
122
72
  data,
123
73
  }));
124
- return (_jsx("div", { style: { width: 600, height: 750 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
74
+ return (_jsx("div", { style: { width: 500, height: 500 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
125
75
  },
126
76
  };
127
77
  export const WithPulseAdd = {
@@ -158,29 +108,16 @@ export const WithDeleteButton = {
158
108
  argTypes: {
159
109
  onDelete: { action: 'onDelete' },
160
110
  },
161
- render: (args) => _jsx(RepositoryNodeCanvas, { data: args, style: { width: 600, height: 300 } }),
111
+ render: (args) => _jsx(RepositoryNodeCanvas, { data: args, style: { width: 550, height: 250 } }),
162
112
  };
163
113
  const multipleReposWithActions = [
164
- {
165
- id: 'r1',
166
- name: 'shep-ai/cli',
167
- repositoryPath: '/home/user/shep-ai/cli',
168
- onAdd,
169
- onDelete,
170
- branch: 'main',
171
- commitMessage: 'feat(web): enrich repository node with branch and commit info',
172
- committer: 'Ariel Shadkhan',
173
- },
114
+ { id: 'r1', name: 'shep-ai/cli', repositoryPath: '/home/user/shep-ai/cli', onAdd, onDelete },
174
115
  {
175
116
  id: 'r2',
176
117
  name: 'vercel/edge-runtime',
177
118
  repositoryPath: '/home/user/vercel/edge-runtime',
178
119
  onAdd,
179
120
  onDelete,
180
- branch: 'feat/streaming-v2',
181
- commitMessage: 'fix: handle edge cases in streaming response',
182
- committer: 'John Smith',
183
- behindCount: 5,
184
121
  },
185
122
  {
186
123
  id: 'r3',
@@ -188,10 +125,6 @@ const multipleReposWithActions = [
188
125
  repositoryPath: '/home/user/acme-corp/web-dashboard-v2',
189
126
  onAdd,
190
127
  onDelete,
191
- branch: 'develop',
192
- commitMessage: 'chore(deps): update all dependencies to latest',
193
- committer: 'Renovate Bot',
194
- behindCount: 23,
195
128
  },
196
129
  {
197
130
  id: 'r4',
@@ -199,9 +132,6 @@ const multipleReposWithActions = [
199
132
  repositoryPath: '/home/user/openai/tiktoken',
200
133
  onAdd,
201
134
  onDelete,
202
- branch: 'main',
203
- commitMessage: 'perf: optimize token encoding for large inputs',
204
- committer: 'Alice Chen',
205
135
  },
206
136
  ];
207
137
  export const MultipleWithActions = {
@@ -209,29 +139,9 @@ export const MultipleWithActions = {
209
139
  const nodes = multipleReposWithActions.map((data, i) => ({
210
140
  id: `repo-${i}`,
211
141
  type: 'repositoryNode',
212
- position: { x: 0, y: i * 140 },
142
+ position: { x: 0, y: i * 80 },
213
143
  data,
214
144
  }));
215
- return (_jsx("div", { style: { width: 600, height: 800 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
216
- },
217
- };
218
- export const WithGitInfo = {
219
- args: {
220
- repositoryPath: '/home/user/shep-ai/cli',
221
- branch: 'feat/repo-node-enrichment',
222
- commitMessage: 'feat(web): enrich repository node with branch and commit info',
223
- committer: 'Ariel Shadkhan',
224
- behindCount: 0,
145
+ return (_jsx("div", { style: { width: 500, height: 500 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
225
146
  },
226
- render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
227
- };
228
- export const WithGitInfoBehind = {
229
- args: {
230
- repositoryPath: '/home/user/shep-ai/cli',
231
- branch: 'feat/old-feature-branch',
232
- commitMessage: 'fix: resolve merge conflict in auth module',
233
- committer: 'Jane Doe',
234
- behindCount: 7,
235
- },
236
- render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
237
147
  };
@@ -1 +1 @@
1
- {"version":3,"file":"control-center-empty-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-empty-state.tsx"],"names":[],"mappings":"AAqBA,MAAM,WAAW,4BAA4B;IAC3C,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,uBAAuB,CAAC,EACtC,kBAAkB,EAClB,SAAS,GACV,EAAE,4BAA4B,kDA+I9B"}
1
+ {"version":3,"file":"control-center-empty-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-empty-state.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,4BAA4B;IAC3C,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,uBAAuB,CAAC,EACtC,kBAAkB,EAClB,SAAS,GACV,EAAE,4BAA4B,kDA8J9B"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useCallback, useEffect } from 'react';
4
- import { Github, Plus, TerminalSquare, Copy, Check, Loader2, CheckCircle2, AlertCircle, Terminal, } from 'lucide-react';
4
+ import { FolderOpen, Copy, Check, Loader2, CheckCircle2, AlertCircle, Terminal, ChevronDown, } from 'lucide-react';
5
5
  import { cn } from '../../../lib/utils.js';
6
6
  import { pickFolder } from '../../common/add-repository-button/pick-folder.js';
7
7
  import { isAgentSetupComplete } from '../../../app/actions/agent-setup-flag.js';
@@ -13,12 +13,12 @@ export function ControlCenterEmptyState({ onRepositorySelect, className, }) {
13
13
  const [loading, setLoading] = useState(false);
14
14
  const [agentReady, setAgentReady] = useState(null);
15
15
  const [authStatus, setAuthStatus] = useState(null);
16
+ const [cliExpanded, setCliExpanded] = useState(false);
16
17
  useEffect(() => {
17
18
  isAgentSetupComplete().then((done) => {
18
19
  setAgentReady(done);
19
20
  });
20
21
  }, []);
21
- // Background auth check — runs after agent setup is complete
22
22
  useEffect(() => {
23
23
  if (!agentReady)
24
24
  return;
@@ -52,28 +52,28 @@ export function ControlCenterEmptyState({ onRepositorySelect, className, }) {
52
52
  }, []);
53
53
  if (agentReady === null)
54
54
  return null;
55
- return (_jsx("div", { "data-testid": "control-center-empty-state", className: cn('flex flex-col items-center justify-center', className), children: _jsx("div", { className: "animate-in fade-in slide-in-from-bottom-2 w-96 rounded-2xl border border-white/30 bg-white/50 px-8 py-8 shadow-lg backdrop-blur-xl duration-300 dark:border-white/10 dark:bg-white/5", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [_jsxs("div", { className: "mb-2 text-center", children: [_jsx("h1", { className: "text-xl font-bold tracking-tight", children: "Features" }), _jsx("p", { className: "text-muted-foreground text-sm font-light", children: "Control Center" })] }), !agentReady ? (
56
- /* Step 1: Agent setup */
57
- _jsx(WelcomeAgentSetup, { onComplete: handleAgentSetupComplete, className: "w-full" })) : (
58
- /* Step 2: Add repository (shown immediately after agent is configured) */
59
- _jsxs(_Fragment, { children: [_jsx(AgentAuthBanner, { status: authStatus, onRetry: handleRetryAuth }), _jsxs("div", { className: "text-muted-foreground flex items-center gap-2", children: [_jsx(Github, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-[10px] font-semibold tracking-widest uppercase", children: "Repositories" })] }), _jsxs("button", { type: "button", "data-testid": "empty-state-add-repository", onClick: handlePickerClick, disabled: loading, className: "border-border hover:border-foreground/40 flex w-full cursor-pointer items-center gap-2.5 rounded-md border border-dashed px-4 py-2.5 transition-colors disabled:cursor-wait disabled:opacity-50", children: [loading ? (_jsx(Loader2, { className: "text-muted-foreground h-4 w-4 animate-spin" })) : (_jsx(Plus, { className: "text-muted-foreground h-4 w-4" })), _jsx("span", { className: "text-xs font-medium", children: loading ? 'Opening…' : 'Add Repository' })] }), _jsxs("div", { className: "text-muted-foreground flex items-center gap-2", children: [_jsx("div", { className: "bg-border h-px w-10" }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(TerminalSquare, { className: "h-3 w-3" }), _jsx("span", { className: "text-[10px] font-semibold tracking-widest uppercase", children: "Or via CLI" })] }), _jsx("div", { className: "bg-border h-px w-10" })] }), _jsxs("div", { "data-testid": "cli-code-block", className: "relative w-full rounded-md bg-zinc-900 px-3 py-2 font-mono text-[11px] text-zinc-300", children: [_jsx("button", { type: "button", "data-testid": "cli-code-block-copy", onClick: handleCopy, className: "absolute top-2 right-2 cursor-pointer rounded p-1 text-zinc-500 transition-colors hover:bg-zinc-800 hover:text-zinc-300", "aria-label": "Copy commands", children: copied ? _jsx(Check, { className: "h-3 w-3" }) : _jsx(Copy, { className: "h-3 w-3" }) }), _jsx("div", { className: "space-y-0.5", children: commands.map((cmd) => (_jsxs("div", { className: "whitespace-nowrap", children: [_jsx("span", { className: "text-zinc-500 select-none", children: "$ " }), _jsx("span", { children: cmd })] }, cmd))) })] }), _jsx("p", { className: "text-muted-foreground text-[10px]", children: "Feature will appear on canvas once created" })] }))] }) }) }));
55
+ return (_jsxs("div", { "data-testid": "control-center-empty-state", className: cn('relative flex h-full w-full flex-col items-center justify-center px-8', className), children: [!agentReady ? (
56
+ /* Agent setup wizard — owns its own hero */
57
+ _jsx(WelcomeAgentSetup, { onComplete: handleAgentSetupComplete })) : (
58
+ /* Repository step — fade in to match wizard transitions */
59
+ _jsxs("div", { className: "animate-in fade-in flex w-full max-w-md flex-col items-center duration-300", children: [_jsx("h1", { className: "text-foreground/90 text-center text-5xl font-extralight tracking-tight", children: "Add a project" }), _jsxs("p", { className: "text-muted-foreground mt-3 text-center text-lg leading-relaxed font-light", children: ["Add your project folder to unlock feature creation.", _jsx("br", {}), "Describe what you need \u2014 Shep handles the rest."] }), _jsx("div", { className: "mt-8", children: _jsx(AgentAuthBanner, { status: authStatus, onRetry: handleRetryAuth }) }), _jsxs("button", { type: "button", "data-testid": "empty-state-add-repository", onClick: handlePickerClick, disabled: loading, className: "bg-foreground text-background hover:bg-foreground/90 mt-10 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl px-6 py-4 text-base font-medium shadow-lg transition-all duration-200 hover:shadow-xl active:scale-[0.98] disabled:cursor-wait disabled:opacity-50", children: [loading ? (_jsx(Loader2, { className: "h-5 w-5 animate-spin" })) : (_jsx(FolderOpen, { className: "h-5 w-5" })), loading ? 'Opening…' : 'Choose a Folder'] }), _jsx("p", { className: "text-muted-foreground/60 mt-3 text-center text-sm", children: "Any folder works \u2014 git will be initialized automatically if needed." })] })), agentReady ? (_jsxs("div", { className: "absolute bottom-8 flex flex-col items-center", style: {
60
+ animationDelay: '400ms',
61
+ animationDuration: '600ms',
62
+ animationFillMode: 'both',
63
+ }, children: [_jsxs("button", { type: "button", onClick: () => setCliExpanded(!cliExpanded), className: "text-muted-foreground hover:text-foreground flex cursor-pointer items-center gap-1.5 transition-colors duration-200", children: [_jsx(Terminal, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-sm", children: "or use the CLI" }), _jsx(ChevronDown, { className: cn('h-3.5 w-3.5 transition-transform duration-200', cliExpanded ? '' : 'rotate-180') })] }), cliExpanded ? (_jsx("div", { className: "animate-in fade-in slide-in-from-top-1 mt-3 w-80 duration-200", children: _jsxs("div", { "data-testid": "cli-code-block", className: "relative rounded-xl bg-zinc-900 px-5 py-4 font-mono text-[13px] leading-relaxed text-zinc-400", children: [_jsx("button", { type: "button", "data-testid": "cli-code-block-copy", onClick: handleCopy, className: "absolute top-3 right-3 cursor-pointer rounded-md p-1.5 text-zinc-600 transition-colors hover:bg-zinc-800 hover:text-zinc-300", "aria-label": "Copy commands", children: copied ? (_jsx(Check, { className: "h-3.5 w-3.5 text-emerald-400" })) : (_jsx(Copy, { className: "h-3.5 w-3.5" })) }), _jsx("div", { className: "space-y-1", children: commands.map((cmd) => (_jsxs("div", { className: "whitespace-nowrap", children: [_jsx("span", { className: "text-zinc-600 select-none", children: "$ " }), _jsx("span", { className: "text-zinc-300", children: cmd })] }, cmd))) })] }) })) : null] })) : null] }));
60
64
  }
61
- /** Compact auth status banner — shows checking/success/error states */
65
+ /** Inline status pill — minimal, no background box */
62
66
  function AgentAuthBanner({ status, onRetry, }) {
63
- // Still checking — show subtle spinner
64
67
  if (!status) {
65
- return (_jsxs("div", { className: "bg-muted/50 flex w-full items-center gap-2 rounded-md px-3 py-1.5", children: [_jsx(Loader2, { className: "text-muted-foreground h-3 w-3 animate-spin" }), _jsx("span", { className: "text-muted-foreground text-[10px]", children: "Checking agent setup\u2026" })] }));
68
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Loader2, { className: "text-muted-foreground/50 h-3.5 w-3.5 animate-spin" }), _jsx("span", { className: "text-muted-foreground/50 text-sm", children: "Checking setup\u2026" })] }));
66
69
  }
67
- // All good — compact success, auto-fades
68
70
  if (status.installed && status.authenticated) {
69
- return (_jsxs("div", { className: "animate-in fade-in flex w-full items-center gap-2 rounded-md bg-emerald-500/10 px-3 py-1.5", children: [_jsx(CheckCircle2, { className: "h-3 w-3 text-emerald-600 dark:text-emerald-400" }), _jsxs("span", { className: "text-[10px] text-emerald-700 dark:text-emerald-300", children: [status.label, " ready"] })] }));
71
+ return (_jsxs("div", { className: "animate-in fade-in flex items-center gap-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-500" }), _jsxs("span", { className: "text-sm text-emerald-600 dark:text-emerald-400", children: [status.label, " ready"] })] }));
70
72
  }
71
- // Not installed
72
73
  if (!status.installed) {
73
- return (_jsxs("div", { className: "flex w-full flex-col gap-2 rounded-md bg-amber-500/10 px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-3 w-3 text-amber-600 dark:text-amber-400" }), _jsxs("span", { className: "text-[10px] font-medium text-amber-700 dark:text-amber-300", children: [status.label, " not installed"] })] }), status.binaryName ? (_jsxs("div", { className: "rounded bg-zinc-900 px-2 py-1 font-mono text-[10px] text-zinc-300", children: [_jsx("span", { className: "text-zinc-500 select-none", children: "$ " }), "npm install -g ", status.binaryName] })) : null, _jsx("button", { type: "button", onClick: onRetry, className: "self-start text-[10px] font-medium text-amber-700 underline underline-offset-2 hover:text-amber-900 dark:text-amber-300 dark:hover:text-amber-100", children: "Re-check" })] }));
74
+ return (_jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-amber-500" }), _jsxs("span", { className: "text-sm font-medium text-amber-600 dark:text-amber-400", children: [status.label, " not installed"] })] }), status.binaryName ? (_jsxs("code", { className: "rounded-lg bg-zinc-100 px-3 py-1.5 text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400", children: ["npm install -g ", status.binaryName] })) : null, _jsx("button", { type: "button", onClick: onRetry, className: "text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400", children: "Re-check" })] }));
74
75
  }
75
- // Installed but not authenticated
76
- return (_jsxs("div", { className: "flex w-full flex-col gap-2 rounded-md bg-amber-500/10 px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-3 w-3 text-amber-600 dark:text-amber-400" }), _jsxs("span", { className: "text-[10px] font-medium text-amber-700 dark:text-amber-300", children: [status.label, " needs authentication"] })] }), status.authCommand ? (_jsxs("div", { className: "rounded bg-zinc-900 px-2 py-1 font-mono text-[10px] text-zinc-300", children: [_jsx("span", { className: "text-zinc-500 select-none", children: "$ " }), status.authCommand] })) : null, _jsxs("div", { className: "flex items-center gap-2", children: [status.binaryName ? (_jsxs("button", { type: "button", "data-testid": "auth-banner-open-terminal", onClick: async () => {
76
+ return (_jsxs("div", { className: "flex flex-col items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-amber-500" }), _jsxs("span", { className: "text-sm font-medium text-amber-600 dark:text-amber-400", children: [status.label, " needs authentication"] })] }), status.authCommand ? (_jsx("code", { className: "rounded-lg bg-zinc-100 px-3 py-1.5 text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400", children: status.authCommand })) : null, _jsxs("div", { className: "flex items-center gap-3", children: [status.binaryName ? (_jsxs("button", { type: "button", "data-testid": "auth-banner-open-terminal", onClick: async () => {
77
77
  try {
78
78
  const toolId = status.agentType === 'claude-code' ? 'claude-code' : status.agentType;
79
79
  await fetch(`/api/tools/${toolId}/launch`, { method: 'POST' });
@@ -81,5 +81,5 @@ function AgentAuthBanner({ status, onRetry, }) {
81
81
  catch {
82
82
  // best effort
83
83
  }
84
- }, className: "flex items-center gap-1 rounded border border-amber-600/30 px-2 py-0.5 text-[10px] font-medium text-amber-700 transition-colors hover:bg-amber-500/10 dark:text-amber-300", children: [_jsx(Terminal, { className: "h-2.5 w-2.5" }), "Open ", status.label] })) : null, _jsx("button", { type: "button", onClick: onRetry, className: "text-[10px] font-medium text-amber-700 underline underline-offset-2 hover:text-amber-900 dark:text-amber-300 dark:hover:text-amber-100", children: "Re-check" })] })] }));
84
+ }, className: "flex items-center gap-1.5 text-xs font-medium text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400", children: [_jsx(Terminal, { className: "h-3 w-3" }), "Open ", status.label] })) : null, _jsx("button", { type: "button", onClick: onRetry, className: "text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400", children: "Re-check" })] })] }));
85
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAuB5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CA2UzF"}
1
+ {"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAuB5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAkWzF"}
@@ -27,8 +27,8 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
27
27
  const drawerTimerRef = useRef(null);
28
28
  const { defaultViewport, onMoveEnd: handleViewportChange, resetViewport, } = useViewportPersistence();
29
29
  const { nodes, edges, onNodesChange, handleConnect, handleAddRepository, handleDeleteFeature, handleRetryFeature, handleStartFeature, handleStopFeature, handleDeleteRepository, createFeatureNode, setCallbacks, } = useControlCenterState(initialNodes, initialEdges);
30
- // Publish sidebar features to context whenever feature node data changes
31
- const { setFeatures: setSidebarFeatures } = useSidebarFeaturesContext();
30
+ // Publish sidebar features + repo state to context
31
+ const { setFeatures: setSidebarFeatures, setHasRepositories: setSidebarHasRepos } = useSidebarFeaturesContext();
32
32
  const featureNodes = useMemo(() => nodes.filter((n) => n.type === 'featureNode'), [nodes]);
33
33
  const sidebarKey = useMemo(() => {
34
34
  return featureNodes
@@ -119,21 +119,29 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
119
119
  guardedNavigate(() => router.push('/'));
120
120
  }
121
121
  }, [router, pathname, guardedNavigate]);
122
+ // Shared: after adding first repo, center canvas and open create drawer
123
+ const focusAndOpenDrawer = useCallback((repoPath) => {
124
+ // Wait for next render so the repo node exists in the DOM
125
+ setTimeout(() => {
126
+ fitView(AUTO_FOCUS_OPTIONS);
127
+ // Open the create-feature drawer after the fitView animation completes
128
+ drawerTimerRef.current = setTimeout(() => {
129
+ guardedNavigate(() => router.push(`/create?repo=${encodeURIComponent(repoPath)}`));
130
+ }, AUTO_FOCUS_DRAWER_DELAY_MS);
131
+ }, 0);
132
+ }, [fitView, guardedNavigate, router]);
133
+ // Wrapper: add repo + auto-focus if canvas was empty
134
+ const addRepoAndFocus = useCallback((path) => {
135
+ const { wasEmpty, repoPath } = handleAddRepository(path);
136
+ if (wasEmpty) {
137
+ focusAndOpenDrawer(repoPath);
138
+ }
139
+ }, [handleAddRepository, focusAndOpenDrawer]);
122
140
  // Listen for global "add repository" events from the top bar button
123
141
  useEffect(() => {
124
142
  const handler = (e) => {
125
143
  const path = e.detail.path;
126
- const { wasEmpty, repoPath } = handleAddRepository(path);
127
- if (wasEmpty) {
128
- // Wait for next render so the repo node exists in the DOM, then auto-focus
129
- setTimeout(() => {
130
- fitView(AUTO_FOCUS_OPTIONS);
131
- // Open the create-feature drawer after the fitView animation completes
132
- drawerTimerRef.current = setTimeout(() => {
133
- guardedNavigate(() => router.push(`/create?repo=${encodeURIComponent(repoPath)}`));
134
- }, AUTO_FOCUS_DRAWER_DELAY_MS);
135
- }, 0);
136
- }
144
+ addRepoAndFocus(path);
137
145
  };
138
146
  window.addEventListener('shep:add-repository', handler);
139
147
  return () => {
@@ -142,7 +150,7 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
142
150
  clearTimeout(drawerTimerRef.current);
143
151
  }
144
152
  };
145
- }, [handleAddRepository, fitView, guardedNavigate, router]);
153
+ }, [addRepoAndFocus]);
146
154
  // Listen for create events from the create drawer (with real feature ID from server)
147
155
  useEffect(() => {
148
156
  const handler = (e) => {
@@ -212,6 +220,10 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
212
220
  handleViewportChange(viewport);
213
221
  }, [handleViewportChange]);
214
222
  const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
223
+ // Publish repo state to sidebar context so AppShell can hide FAB during onboarding
224
+ useEffect(() => {
225
+ setSidebarHasRepos(hasRepositories);
226
+ }, [hasRepositories, setSidebarHasRepos]);
215
227
  // Debounced latch: prevent empty-state flicker during brief reconcile gaps
216
228
  // (e.g. stale poll momentarily drops repos), but allow the empty state to
217
229
  // return after a real delete once repos stay gone past the debounce window.
@@ -227,7 +239,9 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
227
239
  setShowCanvas(true);
228
240
  }
229
241
  else if (showCanvas) {
230
- // Repos gone — wait before showing empty state (debounce stale polls)
242
+ // Repos gone — clear saved viewport so next add starts centered,
243
+ // then wait before showing empty state (debounce stale polls)
244
+ resetViewport();
231
245
  latchTimerRef.current = setTimeout(() => {
232
246
  setShowCanvas(false);
233
247
  latchTimerRef.current = null;
@@ -237,7 +251,7 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
237
251
  if (latchTimerRef.current)
238
252
  clearTimeout(latchTimerRef.current);
239
253
  };
240
- }, [hasRepositories, showCanvas]);
254
+ }, [hasRepositories, showCanvas, resetViewport]);
241
255
  // Pulse the "+" button when there's a single repo with no features and the
242
256
  // create-feature drawer is not open — draws attention to the next action.
243
257
  const isCreateDrawerOpen = pathname.startsWith('/create');
@@ -249,5 +263,5 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
249
263
  return nodes;
250
264
  return nodes.map((n) => n.type === 'repositoryNode' ? { ...n, data: { ...n.data, pulseAdd: true } } : n);
251
265
  }, [nodes, isCreateDrawerOpen]);
252
- return (_jsx(FeaturesCanvas, { nodes: showCanvas ? displayNodes : [], edges: showCanvas ? edges : [], selectedFeatureId: selectedFeatureId, defaultViewport: defaultViewport, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeClick: handleNodeClick, onPaneClick: handleClearDrawers, onMoveEnd: handleMoveEnd, onResetViewport: resetViewport, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }));
266
+ return (_jsx(FeaturesCanvas, { nodes: showCanvas ? displayNodes : [], edges: showCanvas ? edges : [], selectedFeatureId: selectedFeatureId, defaultViewport: defaultViewport, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeClick: handleNodeClick, onPaneClick: handleClearDrawers, onMoveEnd: handleMoveEnd, onResetViewport: resetViewport, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: addRepoAndFocus }) }));
253
267
  }
@@ -1 +1 @@
1
- {"version":3,"file":"welcome-agent-setup.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/welcome-agent-setup.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,sBAAsB,2CAuNlF"}
1
+ {"version":3,"file":"welcome-agent-setup.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/welcome-agent-setup.tsx"],"names":[],"mappings":"AAWA,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,sBAAsB,2CA4NlF"}