@shepai/cli 1.72.9-pr220.f17b60a → 1.73.0-pr222.ef53005

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/dist/packages/core/src/application/ports/output/agents/agent-executor-provider.interface.d.ts +1 -1
  2. package/dist/packages/core/src/application/ports/output/agents/agent-executor-provider.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  4. package/dist/packages/core/src/infrastructure/di/container.js +2 -1
  5. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts +4 -2
  6. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts.map +1 -1
  7. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.js +8 -4
  8. package/dist/packages/core/src/infrastructure/services/agents/common/agent-runner.service.js +1 -1
  9. package/dist/packages/core/src/infrastructure/services/agents/common/structured-agent-caller.service.js +1 -1
  10. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +1 -1
  11. package/dist/src/presentation/web/app/layout.js +1 -1
  12. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  13. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +54 -124
  14. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts +13 -0
  15. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts.map +1 -0
  16. package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.js +46 -0
  17. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map +1 -1
  18. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.js +7 -10
  19. package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.js +14 -39
  21. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +6 -7
  22. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  23. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +45 -8
  24. package/dist/src/presentation/web/hooks/agent-events-provider.d.ts.map +1 -1
  25. package/dist/src/presentation/web/hooks/agent-events-provider.js +3 -2
  26. package/dist/src/presentation/web/hooks/use-agent-events.d.ts.map +1 -1
  27. package/dist/src/presentation/web/hooks/use-agent-events.js +13 -2
  28. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  29. package/dist/src/presentation/web/hooks/use-deploy-action.js +10 -13
  30. package/dist/src/presentation/web/lib/logger.d.ts +7 -0
  31. package/dist/src/presentation/web/lib/logger.d.ts.map +1 -0
  32. package/dist/src/presentation/web/lib/logger.js +11 -0
  33. package/dist/tsconfig.build.tsbuildinfo +1 -1
  34. package/package.json +1 -1
  35. package/web/.next/BUILD_ID +1 -1
  36. package/web/.next/build-manifest.json +2 -2
  37. package/web/.next/cache/.previewinfo +1 -1
  38. package/web/.next/cache/.rscinfo +1 -1
  39. package/web/.next/cache/.tsbuildinfo +1 -1
  40. package/web/.next/cache/config.json +3 -3
  41. package/web/.next/fallback-build-manifest.json +2 -2
  42. package/web/.next/prerender-manifest.json +3 -3
  43. package/web/.next/required-server-files.js +1 -1
  44. package/web/.next/required-server-files.json +1 -1
  45. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +45 -30
  46. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
  47. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  48. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  49. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +51 -36
  50. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  51. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  52. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  53. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  54. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
  55. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  56. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  57. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +45 -30
  58. package/web/.next/server/app/(dashboard)/create/page.js +3 -3
  59. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  60. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  61. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +51 -36
  62. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  63. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  64. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  65. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +41 -26
  66. package/web/.next/server/app/(dashboard)/page.js +3 -3
  67. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  68. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  69. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  70. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
  71. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  72. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  73. package/web/.next/server/app/_global-error.html +2 -2
  74. package/web/.next/server/app/_global-error.rsc +1 -1
  75. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  78. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  79. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  80. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  81. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  82. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  83. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  84. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  85. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  86. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  87. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  88. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  89. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  90. package/web/.next/server/app/version/page.js.nft.json +1 -1
  91. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  92. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  93. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  94. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +3 -0
  95. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -0
  96. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +3 -0
  97. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +1 -0
  98. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  99. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  100. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  101. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  102. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  103. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
  104. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -1
  105. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  106. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js +1 -1
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  116. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/{_8e87c87b._.js → _4f7c70c9._.js} +2 -2
  118. package/web/.next/server/chunks/ssr/{_8e87c87b._.js.map → _4f7c70c9._.js.map} +1 -1
  119. package/web/.next/server/chunks/ssr/{_1978f325._.js → _5ee4f5a7._.js} +2 -2
  120. package/web/.next/server/chunks/ssr/_5ee4f5a7._.js.map +1 -0
  121. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  122. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  123. package/web/.next/server/chunks/ssr/_6e08ce21._.js +3 -0
  124. package/web/.next/server/chunks/ssr/_6e08ce21._.js.map +1 -0
  125. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  126. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  127. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  128. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  129. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js → server/chunks/ssr/src_presentation_web_163038ba._.js} +3 -3
  130. package/web/.next/server/chunks/ssr/{src_presentation_web_d5b0cb86._.js.map → src_presentation_web_163038ba._.js.map} +1 -1
  131. package/web/.next/server/chunks/ssr/{src_presentation_web_2b91e4ec._.js → src_presentation_web_30d7eeda._.js} +2 -2
  132. package/web/.next/server/chunks/ssr/{src_presentation_web_5bcc1537._.js.map → src_presentation_web_30d7eeda._.js.map} +1 -1
  133. package/web/.next/server/chunks/ssr/{src_presentation_web_d5b0cb86._.js → src_presentation_web_459cb687._.js} +3 -3
  134. package/web/.next/server/chunks/ssr/{src_presentation_web_e626b63c._.js.map → src_presentation_web_459cb687._.js.map} +1 -1
  135. package/web/.next/server/chunks/ssr/{src_presentation_web_5bcc1537._.js → src_presentation_web_565a14f8._.js} +2 -2
  136. package/web/.next/server/chunks/ssr/{src_presentation_web_2b91e4ec._.js.map → src_presentation_web_565a14f8._.js.map} +1 -1
  137. package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
  138. package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js.map +1 -1
  139. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +3 -0
  140. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -0
  141. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +3 -0
  142. package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js.map +1 -0
  143. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  144. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  145. package/web/.next/server/pages/500.html +2 -2
  146. package/web/.next/server/server-reference-manifest.js +1 -1
  147. package/web/.next/server/server-reference-manifest.json +183 -126
  148. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  149. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  150. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  151. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  152. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +45 -30
  153. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
  154. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  155. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  156. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +51 -36
  157. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  158. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  159. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  160. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  161. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
  162. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  163. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  164. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +45 -30
  165. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +3 -3
  166. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  167. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  168. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +51 -36
  169. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  170. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  171. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  172. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +41 -26
  173. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +3 -3
  174. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  175. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  176. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +41 -26
  177. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
  178. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  179. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  180. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  181. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  182. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  183. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  184. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  185. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  186. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  187. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  188. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  189. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  190. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  191. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  192. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  193. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  194. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  195. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  196. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  197. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  198. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  199. 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
  200. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +3 -0
  201. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +3 -0
  202. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  203. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  204. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  205. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
  206. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  207. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  208. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  209. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js +1 -1
  210. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  211. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  212. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_8e87c87b._.js → _4f7c70c9._.js} +2 -2
  213. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_1978f325._.js → _5ee4f5a7._.js} +2 -2
  214. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  215. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6e08ce21._.js +3 -0
  216. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  217. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  218. package/web/.next/{server/chunks/ssr/src_presentation_web_e626b63c._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js} +3 -3
  219. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_2b91e4ec._.js → src_presentation_web_30d7eeda._.js} +2 -2
  220. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_e626b63c._.js → src_presentation_web_459cb687._.js} +3 -3
  221. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_5bcc1537._.js → src_presentation_web_565a14f8._.js} +2 -2
  222. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
  223. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +3 -0
  224. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +3 -0
  225. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  226. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  227. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  228. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +183 -126
  229. package/web/.next/standalone/src/presentation/web/app/layout.tsx +1 -1
  230. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +80 -115
  231. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.ts +56 -0
  232. package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/use-feature-actions.ts +6 -7
  233. package/web/.next/standalone/src/presentation/web/components/common/repository-node/use-repository-actions.ts +29 -54
  234. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +7 -7
  235. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +50 -8
  236. package/web/.next/standalone/src/presentation/web/hooks/agent-events-provider.tsx +7 -2
  237. package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +13 -2
  238. package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +13 -13
  239. package/web/.next/standalone/src/presentation/web/lib/logger.ts +12 -0
  240. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  241. package/web/.next/static/chunks/{98ca891a5c156aa5.js → 0cfed3c69c312c09.js} +3 -3
  242. package/web/.next/static/chunks/{c92e1360ada8ca94.js → 1f5c93a8b939416d.js} +2 -2
  243. package/web/.next/static/chunks/4c63764a2d06e45e.js +1 -0
  244. package/web/.next/static/chunks/{792aac476adb5875.js → 89e74b1c3eb43b03.js} +1 -1
  245. package/web/.next/static/chunks/{9b1770f05f1d95e5.js → 937d7d4d58942872.js} +1 -1
  246. package/web/.next/static/chunks/95e3f47abe8032e5.js +1 -0
  247. package/web/.next/static/chunks/{83463b63971f5723.js → b835e88cdc8c63d2.js} +1 -1
  248. package/web/.next/static/chunks/{d5e95c4482029a39.js → e2342af6b68c94c1.js} +1 -1
  249. package/web/.next/static/chunks/{a7f52757dff0cea0.js → ed69d6b172ae2bfe.js} +1 -1
  250. package/web/.next/static/chunks/fd46753cd16664a9.js +1 -0
  251. package/web/.next/trace +1 -1
  252. package/web/.next/trace-build +1 -1
  253. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +0 -3
  254. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +0 -1
  255. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +0 -3
  256. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +0 -1
  257. package/web/.next/server/chunks/ssr/_1978f325._.js.map +0 -1
  258. package/web/.next/server/chunks/ssr/_250a63ae._.js +0 -3
  259. package/web/.next/server/chunks/ssr/_250a63ae._.js.map +0 -1
  260. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +0 -3
  261. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +0 -1
  262. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +0 -3
  263. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +0 -1
  264. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +0 -3
  265. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +0 -3
  266. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_250a63ae._.js +0 -3
  267. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +0 -3
  268. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +0 -3
  269. package/web/.next/static/chunks/76827713cb2b7333.js +0 -1
  270. package/web/.next/static/chunks/7c8adcfd920a8f74.js +0 -1
  271. package/web/.next/static/chunks/b6becf0de992842a.js +0 -1
  272. /package/web/.next/static/{eg0FTlsA4z_7CXbFfMgAr → 0yTXyENV4ko7rpM4-3vV8}/_buildManifest.js +0 -0
  273. /package/web/.next/static/{eg0FTlsA4z_7CXbFfMgAr → 0yTXyENV4ko7rpM4-3vV8}/_clientMiddlewareManifest.json +0 -0
  274. /package/web/.next/static/{eg0FTlsA4z_7CXbFfMgAr → 0yTXyENV4ko7rpM4-3vV8}/_ssgManifest.js +0 -0
@@ -53,7 +53,7 @@ export default function RootLayout({
53
53
  </head>
54
54
  <body className="min-h-screen antialiased">
55
55
  <AppShell>{children}</AppShell>
56
- <Toaster />
56
+ <Toaster position="bottom-center" />
57
57
  </body>
58
58
  </html>
59
59
  );
@@ -56,6 +56,7 @@ import type { MergeReviewData } from '@/components/common/merge-review';
56
56
  import { resolveSseEventUpdates } from '@/components/common/feature-node/derive-feature-state';
57
57
  import { deriveFeatureViewType } from './drawer-view';
58
58
  import type { DrawerView } from './drawer-view';
59
+ import { useArtifactFetch } from './use-artifact-fetch';
59
60
 
60
61
  export interface FeatureDrawerClientProps {
61
62
  view: DrawerView;
@@ -87,6 +88,10 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
87
88
  const processedCountRef = useRef(0);
88
89
 
89
90
  useEffect(() => {
91
+ // Clamp cursor if events were pruned
92
+ if (processedCountRef.current > events.length) {
93
+ processedCountRef.current = 0;
94
+ }
90
95
  if (!featureNode || events.length <= processedCountRef.current) return;
91
96
 
92
97
  const newEvents = events.slice(processedCountRef.current);
@@ -96,9 +101,9 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
96
101
  if (update.featureId !== featureNode.featureId) continue;
97
102
 
98
103
  // Trigger a server refresh to get the latest drawer view,
99
- // but skip when the user has unsaved changes or a rejection is in-flight
100
- // to avoid the refresh interfering with the reject handler's navigation.
101
- if (!isDirtyRef.current && !isRejectingRef.current) router.refresh();
104
+ // but skip when the drawer is closed, the user has unsaved changes,
105
+ // or a rejection is in-flight to avoid unnecessary refreshes.
106
+ if (isOpenRef.current && !isDirtyRef.current && !isRejectingRef.current) router.refresh();
102
107
 
103
108
  if (update.state !== undefined || update.lifecycle !== undefined) {
104
109
  // Optimistically update the node data AND re-derive the view type so the
@@ -129,6 +134,19 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
129
134
  // the close animation when the path no longer matches a feature route.
130
135
  const pathname = usePathname();
131
136
  const isOpen = pathname.startsWith('/feature/');
137
+ const isOpenRef = useRef(isOpen);
138
+ const wasOpenRef = useRef(isOpen);
139
+
140
+ // When the drawer re-opens, force a server refresh so the view is always fresh.
141
+ // SSE skips router.refresh() while the drawer is closed, so data can go stale.
142
+ useEffect(() => {
143
+ if (isOpen && !wasOpenRef.current) {
144
+ router.refresh();
145
+ }
146
+ wasOpenRef.current = isOpen;
147
+ }, [isOpen, router]);
148
+
149
+ isOpenRef.current = isOpen;
132
150
 
133
151
  const onClose = useCallback(() => {
134
152
  router.push('/');
@@ -141,21 +159,17 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
141
159
  const [prdData, setPrdData] = useState<PrdQuestionnaireData | null>(null);
142
160
  const [prdSelections, setPrdSelections] = useState<Record<string, string>>({});
143
161
  const [prdDefaultSelections, setPrdDefaultSelections] = useState<Record<string, string>>({});
144
- const [isLoadingPrd, setIsLoadingPrd] = useState(false);
145
162
 
146
163
  // ── Tech state ─────────────────────────────────────────────────────────
147
164
  const [techData, setTechData] = useState<TechDecisionsReviewData | null>(null);
148
- const [isLoadingTech, setIsLoadingTech] = useState(false);
149
165
 
150
166
  // ── Product decisions state (for tech review Product tab) ─────────────
151
167
  const [techProductData, setTechProductData] = useState<
152
168
  ProductDecisionsSummaryData | null | undefined
153
169
  >(undefined);
154
- const [isLoadingTechProduct, setIsLoadingTechProduct] = useState(false);
155
170
 
156
171
  // ── Merge state ────────────────────────────────────────────────────────
157
172
  const [mergeData, setMergeData] = useState<MergeReviewData | null>(null);
158
- const [isLoadingMerge, setIsLoadingMerge] = useState(false);
159
173
 
160
174
  // ── Delete state ───────────────────────────────────────────────────────
161
175
  const [isDeleting, setIsDeleting] = useState(false);
@@ -173,120 +187,71 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
173
187
  // ── Data fetching ─────────────────────────────────────────────────────
174
188
 
175
189
  const prdFeatureId = view.type === 'prd-review' ? view.node.featureId : null;
176
- useEffect(() => {
177
- setPrdSelections({});
178
- setPrdDefaultSelections({});
179
- setPrdData(null);
180
- if (!prdFeatureId) return;
181
-
182
- let cancelled = false;
183
- setIsLoadingPrd(true);
184
- getFeatureArtifact(prdFeatureId)
185
- .then((result) => {
186
- if (cancelled) return;
187
- if (result.error) {
188
- toast.error(result.error);
189
- return;
190
- }
191
- if (result.questionnaire) {
192
- setPrdData(result.questionnaire);
193
- const defaults: Record<string, string> = {};
194
- for (const q of result.questionnaire.questions) {
195
- const recommended = q.options.find((o) => o.recommended);
196
- if (recommended) defaults[q.id] = recommended.id;
197
- }
198
- setPrdSelections(defaults);
199
- setPrdDefaultSelections(defaults);
190
+ const isLoadingPrd = useArtifactFetch(
191
+ prdFeatureId,
192
+ getFeatureArtifact,
193
+ (result) => {
194
+ if (result.error) {
195
+ toast.error(result.error);
196
+ return;
197
+ }
198
+ if (result.questionnaire) {
199
+ setPrdData(result.questionnaire);
200
+ const defaults: Record<string, string> = {};
201
+ for (const q of result.questionnaire.questions) {
202
+ const recommended = q.options.find((o) => o.recommended);
203
+ if (recommended) defaults[q.id] = recommended.id;
200
204
  }
201
- })
202
- .catch(() => {
203
- if (!cancelled) toast.error('Failed to load questionnaire');
204
- })
205
- .finally(() => {
206
- if (!cancelled) setIsLoadingPrd(false);
207
- });
208
- return () => {
209
- cancelled = true;
210
- };
211
- }, [prdFeatureId]);
205
+ setPrdSelections(defaults);
206
+ setPrdDefaultSelections(defaults);
207
+ }
208
+ },
209
+ () => {
210
+ setPrdSelections({});
211
+ setPrdDefaultSelections({});
212
+ setPrdData(null);
213
+ },
214
+ 'Failed to load questionnaire'
215
+ );
212
216
 
213
217
  const techFeatureId = view.type === 'tech-review' ? view.node.featureId : null;
214
- useEffect(() => {
215
- setTechData(null);
216
- if (!techFeatureId) return;
217
-
218
- let cancelled = false;
219
- setIsLoadingTech(true);
220
- getResearchArtifact(techFeatureId)
221
- .then((result) => {
222
- if (cancelled) return;
223
- if (result.error) {
224
- toast.error(result.error);
225
- return;
226
- }
227
- if (result.techDecisions) setTechData(result.techDecisions);
228
- })
229
- .catch(() => {
230
- if (!cancelled) toast.error('Failed to load tech decisions');
231
- })
232
- .finally(() => {
233
- if (!cancelled) setIsLoadingTech(false);
234
- });
235
- return () => {
236
- cancelled = true;
237
- };
238
- }, [techFeatureId]);
218
+ const isLoadingTech = useArtifactFetch(
219
+ techFeatureId,
220
+ getResearchArtifact,
221
+ (result) => {
222
+ if (result.error) {
223
+ toast.error(result.error);
224
+ return;
225
+ }
226
+ if (result.techDecisions) setTechData(result.techDecisions);
227
+ },
228
+ () => setTechData(null),
229
+ 'Failed to load tech decisions'
230
+ );
239
231
 
240
- useEffect(() => {
241
- setTechProductData(undefined);
242
- if (!techFeatureId) return;
243
-
244
- let cancelled = false;
245
- setIsLoadingTechProduct(true);
246
- getFeatureArtifact(techFeatureId)
247
- .then((result) => {
248
- if (cancelled) return;
249
- if (result.productDecisions) {
250
- setTechProductData(result.productDecisions);
251
- }
252
- })
253
- .catch(() => {
254
- // Silent failure — the product tab is supplementary
255
- })
256
- .finally(() => {
257
- if (!cancelled) setIsLoadingTechProduct(false);
258
- });
259
- return () => {
260
- cancelled = true;
261
- };
262
- }, [techFeatureId]);
232
+ const isLoadingTechProduct = useArtifactFetch(
233
+ techFeatureId,
234
+ getFeatureArtifact,
235
+ (result) => {
236
+ if (result.productDecisions) setTechProductData(result.productDecisions);
237
+ },
238
+ () => setTechProductData(undefined)
239
+ );
263
240
 
264
241
  const mergeFeatureId = view.type === 'merge-review' ? view.node.featureId : null;
265
- useEffect(() => {
266
- setMergeData(null);
267
- if (!mergeFeatureId) return;
268
-
269
- let cancelled = false;
270
- setIsLoadingMerge(true);
271
- getMergeReviewData(mergeFeatureId)
272
- .then((result) => {
273
- if (cancelled) return;
274
- if ('error' in result) {
275
- toast.error(result.error);
276
- return;
277
- }
278
- setMergeData(result);
279
- })
280
- .catch(() => {
281
- if (!cancelled) toast.error('Failed to load merge review data');
282
- })
283
- .finally(() => {
284
- if (!cancelled) setIsLoadingMerge(false);
285
- });
286
- return () => {
287
- cancelled = true;
288
- };
289
- }, [mergeFeatureId]);
242
+ const isLoadingMerge = useArtifactFetch(
243
+ mergeFeatureId,
244
+ getMergeReviewData,
245
+ (result) => {
246
+ if ('error' in result) {
247
+ toast.error(result.error);
248
+ return;
249
+ }
250
+ setMergeData(result);
251
+ },
252
+ () => setMergeData(null),
253
+ 'Failed to load merge review data'
254
+ );
290
255
 
291
256
  // ── Close guard ──────────────────────────────────────────────────────
292
257
  const isChatDirty = chatInput.trim().length > 0;
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useRef } from 'react';
4
+ import { toast } from 'sonner';
5
+
6
+ /**
7
+ * Generic hook for fetching drawer artifact data when a feature ID changes.
8
+ * Handles loading state, cancellation on unmount/re-fetch, and error toasting.
9
+ *
10
+ * @param featureId - The feature ID to fetch for, or null to reset.
11
+ * @param fetcher - Async function that fetches the artifact data.
12
+ * @param onSuccess - Called with the fetch result when successful and not cancelled.
13
+ * @param onReset - Called immediately when featureId changes (before fetching).
14
+ * @param errorMessage - Optional toast message shown on fetch failure.
15
+ * @returns Whether the fetch is currently in progress.
16
+ */
17
+ export function useArtifactFetch<TResult>(
18
+ featureId: string | null,
19
+ fetcher: (id: string) => Promise<TResult>,
20
+ onSuccess: (result: TResult) => void,
21
+ onReset: () => void,
22
+ errorMessage?: string
23
+ ): boolean {
24
+ const [isLoading, setIsLoading] = useState(false);
25
+
26
+ // Use refs to avoid stale callbacks in the effect without triggering re-runs.
27
+ const onSuccessRef = useRef(onSuccess);
28
+ const onResetRef = useRef(onReset);
29
+ onSuccessRef.current = onSuccess;
30
+ onResetRef.current = onReset;
31
+
32
+ useEffect(() => {
33
+ onResetRef.current();
34
+ if (!featureId) return;
35
+
36
+ let cancelled = false;
37
+ setIsLoading(true);
38
+
39
+ fetcher(featureId)
40
+ .then((result) => {
41
+ if (!cancelled) onSuccessRef.current(result);
42
+ })
43
+ .catch(() => {
44
+ if (!cancelled && errorMessage) toast.error(errorMessage);
45
+ })
46
+ .finally(() => {
47
+ if (!cancelled) setIsLoading(false);
48
+ });
49
+
50
+ return () => {
51
+ cancelled = true;
52
+ };
53
+ }, [featureId, fetcher, errorMessage]);
54
+
55
+ return isLoading;
56
+ }
@@ -37,15 +37,14 @@ export function useFeatureActions(input: FeatureActionsInput | null): FeatureAct
37
37
  const shellTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
38
38
  const specsTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
39
39
 
40
- // Clear timers on unmount
40
+ // Clear timers on unmount — read .current inside cleanup so we get the
41
+ // actual timer value at teardown time, not the always-null value at mount.
41
42
  useEffect(() => {
42
- const ideTimer = ideTimerRef.current;
43
- const shellTimer = shellTimerRef.current;
44
- const specsTimer = specsTimerRef.current;
43
+ const refs = [ideTimerRef, shellTimerRef, specsTimerRef];
45
44
  return () => {
46
- if (ideTimer) clearTimeout(ideTimer);
47
- if (shellTimer) clearTimeout(shellTimer);
48
- if (specsTimer) clearTimeout(specsTimer);
45
+ for (const ref of refs) {
46
+ if (ref.current) clearTimeout(ref.current);
47
+ }
49
48
  };
50
49
  }, []);
51
50
 
@@ -37,22 +37,19 @@ export function useRepositoryActions(input: RepositoryActionsInput | null): Repo
37
37
 
38
38
  // Clear timers on unmount
39
39
  useEffect(() => {
40
- const ideTimer = ideTimerRef.current;
41
- const shellTimer = shellTimerRef.current;
42
- const folderTimer = folderTimerRef.current;
40
+ const ideRef = ideTimerRef;
41
+ const shellRef = shellTimerRef;
42
+ const folderRef = folderTimerRef;
43
43
  return () => {
44
- if (ideTimer) clearTimeout(ideTimer);
45
- if (shellTimer) clearTimeout(shellTimer);
46
- if (folderTimer) clearTimeout(folderTimer);
44
+ if (ideRef.current) clearTimeout(ideRef.current);
45
+ if (shellRef.current) clearTimeout(shellRef.current);
46
+ if (folderRef.current) clearTimeout(folderRef.current);
47
47
  };
48
48
  }, []);
49
49
 
50
- const performToolbarAction = useCallback(
50
+ const performAction = useCallback(
51
51
  async (
52
- action: (input: { repositoryPath: string }) => Promise<{
53
- success: boolean;
54
- error?: string;
55
- }>,
52
+ action: () => Promise<{ success: boolean; error?: string }>,
56
53
  setLoading: (v: boolean) => void,
57
54
  setError: (v: string | null) => void,
58
55
  timerRef: React.RefObject<ReturnType<typeof setTimeout> | null>,
@@ -60,48 +57,13 @@ export function useRepositoryActions(input: RepositoryActionsInput | null): Repo
60
57
  ) => {
61
58
  if (!input || isLoading) return;
62
59
 
63
- // Clear any existing timer
64
60
  if (timerRef.current) clearTimeout(timerRef.current);
65
61
 
66
62
  setLoading(true);
67
63
  setError(null);
68
64
 
69
65
  try {
70
- const result = await action({ repositoryPath: input.repositoryPath });
71
-
72
- if (!result.success) {
73
- const errorMessage = result.error ?? 'An unexpected error occurred';
74
- setError(errorMessage);
75
- timerRef.current = setTimeout(() => setError(null), ERROR_CLEAR_DELAY);
76
- }
77
- } catch (err: unknown) {
78
- const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred';
79
- setError(errorMessage);
80
- timerRef.current = setTimeout(() => setError(null), ERROR_CLEAR_DELAY);
81
- } finally {
82
- setLoading(false);
83
- }
84
- },
85
- [input]
86
- );
87
-
88
- const performFolderAction = useCallback(
89
- async (
90
- action: (repositoryPath: string) => Promise<{ success: boolean; error?: string }>,
91
- setLoading: (v: boolean) => void,
92
- setError: (v: string | null) => void,
93
- timerRef: React.RefObject<ReturnType<typeof setTimeout> | null>,
94
- isLoading: boolean
95
- ) => {
96
- if (!input || isLoading) return;
97
-
98
- if (timerRef.current) clearTimeout(timerRef.current);
99
-
100
- setLoading(true);
101
- setError(null);
102
-
103
- try {
104
- const result = await action(input.repositoryPath);
66
+ const result = await action();
105
67
 
106
68
  if (!result.success) {
107
69
  const errorMessage = result.error ?? 'An unexpected error occurred';
@@ -120,26 +82,39 @@ export function useRepositoryActions(input: RepositoryActionsInput | null): Repo
120
82
  );
121
83
 
122
84
  const handleOpenIde = useCallback(
123
- () => performToolbarAction(openIde, setIdeLoading, setIdeError, ideTimerRef, ideLoading),
124
- [performToolbarAction, ideLoading]
85
+ () =>
86
+ performAction(
87
+ () => openIde({ repositoryPath: input!.repositoryPath }),
88
+ setIdeLoading,
89
+ setIdeError,
90
+ ideTimerRef,
91
+ ideLoading
92
+ ),
93
+ [performAction, ideLoading, input]
125
94
  );
126
95
 
127
96
  const handleOpenShell = useCallback(
128
97
  () =>
129
- performToolbarAction(openShell, setShellLoading, setShellError, shellTimerRef, shellLoading),
130
- [performToolbarAction, shellLoading]
98
+ performAction(
99
+ () => openShell({ repositoryPath: input!.repositoryPath }),
100
+ setShellLoading,
101
+ setShellError,
102
+ shellTimerRef,
103
+ shellLoading
104
+ ),
105
+ [performAction, shellLoading, input]
131
106
  );
132
107
 
133
108
  const handleOpenFolder = useCallback(
134
109
  () =>
135
- performFolderAction(
136
- openFolder,
110
+ performAction(
111
+ () => openFolder(input!.repositoryPath),
137
112
  setFolderLoading,
138
113
  setFolderError,
139
114
  folderTimerRef,
140
115
  folderLoading
141
116
  ),
142
- [performFolderAction, folderLoading]
117
+ [performAction, folderLoading, input]
143
118
  );
144
119
 
145
120
  return {
@@ -44,20 +44,20 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
44
44
  // Publish sidebar features to context whenever feature node data changes
45
45
  const { setFeatures: setSidebarFeatures } = useSidebarFeaturesContext();
46
46
 
47
+ const featureNodes = useMemo(() => nodes.filter((n) => n.type === 'featureNode'), [nodes]);
48
+
47
49
  const sidebarKey = useMemo(() => {
48
- return nodes
49
- .filter((n) => n.type === 'featureNode')
50
+ return featureNodes
50
51
  .map((n) => {
51
52
  const d = n.data as FeatureNodeData;
52
- return `${d.featureId}:${d.state}:${d.runtime ?? ''}:${d.startedAt ?? ''}`;
53
+ return `${d.featureId}:${d.state}:${d.name}`;
53
54
  })
54
55
  .sort()
55
56
  .join(',');
56
- }, [nodes]);
57
+ }, [featureNodes]);
57
58
 
58
59
  useEffect(() => {
59
- const sidebarItems = nodes
60
- .filter((n) => n.type === 'featureNode')
60
+ const sidebarItems = featureNodes
61
61
  .map((n) => {
62
62
  const d = n.data as FeatureNodeData;
63
63
  const status = mapNodeStateToSidebarStatus(d.state);
@@ -79,7 +79,7 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
79
79
  }[];
80
80
 
81
81
  setSidebarFeatures(sidebarItems);
82
- }, [sidebarKey, nodes, setSidebarFeatures]);
82
+ }, [sidebarKey, featureNodes, setSidebarFeatures]);
83
83
 
84
84
  // ── URL-based navigation handlers ────────────────────────────────────
85
85
 
@@ -16,8 +16,11 @@ import { deleteFeature } from '@/app/actions/delete-feature';
16
16
  import { addRepository } from '@/app/actions/add-repository';
17
17
  import { deleteRepository } from '@/app/actions/delete-repository';
18
18
  import { getFeatureMetadata } from '@/app/actions/get-feature-metadata';
19
+ import { fetchGraphData } from '@/app/actions/get-graph-data';
19
20
  import { useAgentEventsContext } from '@/hooks/agent-events-provider';
20
21
  import { useSoundAction } from '@/hooks/use-sound-action';
22
+ import { createLogger } from '@/lib/logger';
23
+
21
24
  import {
22
25
  mapEventTypeToState,
23
26
  resolveSseEventUpdates,
@@ -25,6 +28,9 @@ import {
25
28
  import { useGraphState, type GraphCallbacks } from '@/hooks/use-graph-state';
26
29
  import type { FeatureEntry } from '@/lib/derive-graph';
27
30
 
31
+ const log = createLogger('[Polling]');
32
+ const POLL_INTERVAL_MS = 3_000;
33
+
28
34
  export interface ControlCenterState {
29
35
  nodes: CanvasNodeType[];
30
36
  edges: Edge[];
@@ -76,6 +82,14 @@ export function useControlCenterState(
76
82
  setCallbacks,
77
83
  } = useGraphState(initialNodes, initialEdges);
78
84
 
85
+ // Refs for stable access to latest nodes/edges without callback recreation
86
+ const nodesRef = useRef(nodes);
87
+ const edgesRef = useRef(edges);
88
+ useEffect(() => {
89
+ nodesRef.current = nodes;
90
+ edgesRef.current = edges;
91
+ }, [nodes, edges]);
92
+
79
93
  // Sync server props into domain Maps when initialNodes/initialEdges change.
80
94
  // Keyed by a stable string so we don't re-reconcile on every render.
81
95
  const initialNodeKey = useMemo(
@@ -148,6 +162,10 @@ export function useControlCenterState(
148
162
  const processedEventCountRef = useRef(0);
149
163
 
150
164
  useEffect(() => {
165
+ // Clamp cursor if events were pruned
166
+ if (processedEventCountRef.current > events.length) {
167
+ processedEventCountRef.current = 0;
168
+ }
151
169
  if (events.length <= processedEventCountRef.current) return;
152
170
  const newEvents = events.slice(processedEventCountRef.current);
153
171
  processedEventCountRef.current = events.length;
@@ -177,6 +195,10 @@ export function useControlCenterState(
177
195
  const processedMetadataCountRef = useRef(0);
178
196
 
179
197
  useEffect(() => {
198
+ // Clamp cursor if events were pruned
199
+ if (processedMetadataCountRef.current > events.length) {
200
+ processedMetadataCountRef.current = 0;
201
+ }
180
202
  if (events.length <= processedMetadataCountRef.current) return;
181
203
  const newEvents = events.slice(processedMetadataCountRef.current);
182
204
  processedMetadataCountRef.current = events.length;
@@ -199,6 +221,25 @@ export function useControlCenterState(
199
221
  }
200
222
  }, [events, updateFeature]);
201
223
 
224
+ // --- Polling fallback: catch any SSE events that were missed ---
225
+ useEffect(() => {
226
+ log.debug(`polling enabled (${POLL_INTERVAL_MS}ms interval)`);
227
+
228
+ const timer = setInterval(async () => {
229
+ try {
230
+ const { nodes: freshNodes, edges: freshEdges } = await fetchGraphData();
231
+ reconcile(freshNodes, freshEdges);
232
+ } catch {
233
+ log.warn('poll fetch failed — will retry next interval');
234
+ }
235
+ }, POLL_INTERVAL_MS);
236
+
237
+ return () => {
238
+ log.debug('polling disabled');
239
+ clearInterval(timer);
240
+ };
241
+ }, [reconcile]);
242
+
202
243
  // onNodesChange is a no-op: nodes are derived from domain Maps.
203
244
  // Since nodesDraggable=false and elementsSelectable=false, only React Flow's
204
245
  // internal replace/dimensions changes come through — we ignore them all.
@@ -245,7 +286,7 @@ export function useControlCenterState(
245
286
  const nodeId = `feat-${featureId}`;
246
287
 
247
288
  // Find the current entry for rollback
248
- const prevEntry = nodes
289
+ const prevEntry = nodesRef.current
249
290
  .filter((n) => n.id === nodeId)
250
291
  .map((n) => ({
251
292
  nodeId: n.id,
@@ -270,7 +311,7 @@ export function useControlCenterState(
270
311
  toast.error('Failed to delete feature');
271
312
  });
272
313
  },
273
- [nodes, router, deleteSound, removeFeature, restoreFeature]
314
+ [router, deleteSound, removeFeature, restoreFeature]
274
315
  );
275
316
 
276
317
  const handleDeleteRepository = useCallback(
@@ -279,14 +320,14 @@ export function useControlCenterState(
279
320
 
280
321
  // Find children of this repo via edges
281
322
  const childFeatureIds = new Set(
282
- edges.filter((e) => e.source === repoNodeId).map((e) => e.target)
323
+ edgesRef.current.filter((e) => e.source === repoNodeId).map((e) => e.target)
283
324
  );
284
325
 
285
326
  // Snapshot for rollback
286
327
  const prevRepoData = getRepositoryData(repoNodeId);
287
328
  const childSnapshots = new Map<string, FeatureEntry>();
288
329
  for (const childId of childFeatureIds) {
289
- const childNode = nodes.find((n) => n.id === childId);
330
+ const childNode = nodesRef.current.find((n) => n.id === childId);
290
331
  if (childNode) {
291
332
  childSnapshots.set(childId, { nodeId: childId, data: childNode.data as FeatureNodeData });
292
333
  }
@@ -320,8 +361,6 @@ export function useControlCenterState(
320
361
  }
321
362
  },
322
363
  [
323
- edges,
324
- nodes,
325
364
  deleteSound,
326
365
  removeRepository,
327
366
  removeFeature,
@@ -335,10 +374,13 @@ export function useControlCenterState(
335
374
  (direction: LayoutDirection) => {
336
375
  // Layout is applied via reconcile on next server prop update.
337
376
  // For immediate re-layout, we apply dagre and trigger a reconcile-like update.
338
- const result = layoutWithDagre(nodes, edges, { ...CANVAS_LAYOUT_DEFAULTS, direction });
377
+ const result = layoutWithDagre(nodesRef.current, edgesRef.current, {
378
+ ...CANVAS_LAYOUT_DEFAULTS,
379
+ direction,
380
+ });
339
381
  reconcile(result.nodes, result.edges);
340
382
  },
341
- [nodes, edges, reconcile]
383
+ [reconcile]
342
384
  );
343
385
 
344
386
  const handleAddRepository = useCallback(
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { createContext, useContext, type ReactNode } from 'react';
3
+ import { createContext, useContext, useMemo, type ReactNode } from 'react';
4
4
  import {
5
5
  useAgentEvents,
6
6
  type UseAgentEventsOptions,
@@ -18,7 +18,12 @@ interface AgentEventsProviderProps extends UseAgentEventsOptions {
18
18
  * Wrap the app once; use `useAgentEventsContext()` to read.
19
19
  */
20
20
  export function AgentEventsProvider({ children, runId }: AgentEventsProviderProps) {
21
- const value = useAgentEvents({ runId });
21
+ const { events, lastEvent, connectionStatus } = useAgentEvents({ runId });
22
+
23
+ const value = useMemo<UseAgentEventsResult>(
24
+ () => ({ events, lastEvent, connectionStatus }),
25
+ [events, lastEvent, connectionStatus]
26
+ );
22
27
 
23
28
  return <AgentEventsContext.Provider value={value}>{children}</AgentEventsContext.Provider>;
24
29
  }