@shepai/cli 1.125.0 → 1.126.0

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 (194) hide show
  1. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts +13 -2
  2. package/dist/packages/core/src/application/ports/output/services/deployment-service.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 -0
  5. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.d.ts +21 -0
  6. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.d.ts.map +1 -0
  7. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.js +32 -0
  8. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.js +9 -0
  10. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts +24 -14
  11. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +203 -31
  13. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.d.ts +0 -6
  14. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.js +6 -1
  16. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +7 -2
  18. package/dist/src/presentation/web/app/actions/deploy-feature.js +1 -1
  19. package/dist/src/presentation/web/app/actions/deploy-repository.js +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 +7 -4
  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 +12 -3
  24. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  25. package/dist/src/presentation/web/hooks/use-deploy-action.js +69 -10
  26. package/dist/src/presentation/web/lib/layout-with-dagre.js +3 -3
  27. package/dist/tsconfig.build.tsbuildinfo +1 -1
  28. package/package.json +1 -1
  29. package/web/.next/BUILD_ID +1 -1
  30. package/web/.next/build-manifest.json +2 -2
  31. package/web/.next/fallback-build-manifest.json +2 -2
  32. package/web/.next/prerender-manifest.json +3 -3
  33. package/web/.next/required-server-files.js +2 -2
  34. package/web/.next/required-server-files.json +2 -2
  35. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +57 -57
  36. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +2 -2
  37. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  38. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  39. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +69 -69
  40. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +2 -2
  41. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  42. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  43. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +69 -69
  44. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +2 -2
  45. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  46. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  47. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +53 -53
  48. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +2 -2
  49. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  50. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  51. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +57 -57
  52. package/web/.next/server/app/(dashboard)/create/page.js +2 -2
  53. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  54. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  55. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +69 -69
  56. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +2 -2
  57. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  58. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  59. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +69 -69
  60. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +2 -2
  61. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  62. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  63. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +53 -53
  64. package/web/.next/server/app/(dashboard)/page.js +2 -2
  65. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  66. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  67. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +53 -53
  68. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +2 -2
  69. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  70. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  71. package/web/.next/server/app/_global-error.html +2 -2
  72. package/web/.next/server/app/_global-error.rsc +1 -1
  73. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  74. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  75. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  76. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  77. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  78. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  79. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  80. package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
  81. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  82. package/web/.next/server/app/settings/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 +1 -2
  85. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  86. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  87. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  88. package/web/.next/server/app/tools/page.js +1 -2
  89. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  90. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  92. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  93. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
  94. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
  95. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  96. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  97. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  98. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_fdfbf5cc.js +3 -0
  99. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_fdfbf5cc.js.map +1 -0
  100. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_d8fa0b5f.js +3 -0
  101. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_d8fa0b5f.js.map +1 -0
  102. package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
  103. package/web/.next/server/chunks/ssr/{[root-of-the-server]__7cbda1ea._.js → [root-of-the-server]__248b9fc3._.js} +2 -2
  104. package/web/.next/server/chunks/ssr/{[root-of-the-server]__9e8b25ad._.js.map → [root-of-the-server]__248b9fc3._.js.map} +1 -1
  105. package/web/.next/server/chunks/ssr/[root-of-the-server]__357de47c._.js +4 -0
  106. package/web/.next/server/chunks/ssr/[root-of-the-server]__357de47c._.js.map +1 -0
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__56ecbe40._.js +1 -1
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__56ecbe40._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__67fe07fe._.js +4 -0
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__67fe07fe._.js.map +1 -0
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__a50a7e39._.js +4 -0
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__a50a7e39._.js.map +1 -0
  120. package/web/.next/server/chunks/ssr/{[root-of-the-server]__9e8b25ad._.js → [root-of-the-server]__dfc367f2._.js} +2 -2
  121. package/web/.next/server/chunks/ssr/{[root-of-the-server]__ce6057f6._.js.map → [root-of-the-server]__dfc367f2._.js.map} +1 -1
  122. package/web/.next/server/chunks/ssr/{[root-of-the-server]__ce6057f6._.js → [root-of-the-server]__e7f61cc6._.js} +2 -2
  123. package/web/.next/server/chunks/ssr/{[root-of-the-server]__7cbda1ea._.js.map → [root-of-the-server]__e7f61cc6._.js.map} +1 -1
  124. package/web/.next/server/chunks/ssr/{[root-of-the-server]__aed1d6f8._.js → [root-of-the-server]__fe48d2dc._.js} +2 -2
  125. package/web/.next/server/chunks/ssr/{[root-of-the-server]__aed1d6f8._.js.map → [root-of-the-server]__fe48d2dc._.js.map} +1 -1
  126. package/web/.next/server/chunks/ssr/{_d8b3f91f._.js → _243e3685._.js} +2 -2
  127. package/web/.next/server/chunks/ssr/{_d8b3f91f._.js.map → _243e3685._.js.map} +1 -1
  128. package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
  129. package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
  130. package/web/.next/server/chunks/ssr/_7dca1882._.js +3 -0
  131. package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -0
  132. package/web/.next/server/chunks/ssr/{_772be40b._.js → _821bbcc5._.js} +2 -2
  133. package/web/.next/server/chunks/ssr/{_772be40b._.js.map → _821bbcc5._.js.map} +1 -1
  134. package/web/.next/server/chunks/ssr/_e9703421._.js +1 -1
  135. package/web/.next/server/chunks/ssr/_e9703421._.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/_f39a1adb._.js +3 -0
  137. package/web/.next/server/chunks/ssr/{_135edb9c._.js.map → _f39a1adb._.js.map} +1 -1
  138. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  139. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web_9db47db7._.js +5 -0
  141. package/web/.next/server/chunks/ssr/{src_presentation_web_5f039db1._.js.map → src_presentation_web_9db47db7._.js.map} +1 -1
  142. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f66cd328.js +3 -0
  143. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f66cd328.js.map +1 -0
  144. package/web/.next/server/chunks/ssr/src_presentation_web_aeddd007._.js +3 -0
  145. package/web/.next/server/chunks/ssr/{src_presentation_web_d2912c21._.js.map → src_presentation_web_aeddd007._.js.map} +1 -1
  146. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  147. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  148. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  149. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  150. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  151. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  152. package/web/.next/server/chunks/ssr/src_presentation_web_ede4a227._.js +5 -0
  153. package/web/.next/server/chunks/ssr/{src_presentation_web_c4337169._.js.map → src_presentation_web_ede4a227._.js.map} +1 -1
  154. package/web/.next/server/pages/500.html +2 -2
  155. package/web/.next/server/server-reference-manifest.js +1 -1
  156. package/web/.next/server/server-reference-manifest.json +325 -325
  157. package/web/.next/static/chunks/{88639a2a92364951.js → 044f4665499a9656.js} +1 -1
  158. package/web/.next/static/chunks/{ab42606b8d9a837b.js → 112cf5891d1ca558.js} +1 -1
  159. package/web/.next/static/chunks/1be7ac7a24009333.css +1 -0
  160. package/web/.next/static/chunks/{cab346230cafc536.js → 303a1217006489b9.js} +1 -1
  161. package/web/.next/static/chunks/4ac11847f73b50d6.js +1 -0
  162. package/web/.next/static/chunks/{ee1b7156e3985766.js → 4ac4a43b7eb441e1.js} +1 -1
  163. package/web/.next/static/chunks/{609a74a7c7084d18.js → 5fb66ee5a353a6c6.js} +1 -1
  164. package/web/.next/static/chunks/{225092aaa7291166.js → 6cfc75060a243290.js} +1 -1
  165. package/web/.next/static/chunks/{0eb9cffdddfd0bb6.js → d60f93a1a25ab09d.js} +1 -1
  166. package/web/.next/static/chunks/dcfed2c9b7cd1cb4.js +1 -0
  167. package/web/.next/static/chunks/{3b6956717a7c4e16.js → de66f8d6a67c2361.js} +1 -1
  168. package/web/.next/static/chunks/{03efd55a6de64460.js → de8b0265f780e212.js} +2 -2
  169. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +0 -3
  170. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +0 -1
  171. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +0 -3
  172. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +0 -1
  173. package/web/.next/server/chunks/ssr/[root-of-the-server]__14664e9b._.js +0 -4
  174. package/web/.next/server/chunks/ssr/[root-of-the-server]__14664e9b._.js.map +0 -1
  175. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +0 -4
  176. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js.map +0 -1
  177. package/web/.next/server/chunks/ssr/_135edb9c._.js +0 -3
  178. package/web/.next/server/chunks/ssr/_cc77a143._.js +0 -3
  179. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +0 -1
  180. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +0 -5
  181. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +0 -3
  182. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +0 -1
  183. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +0 -3
  184. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +0 -1
  185. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +0 -3
  186. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +0 -1
  187. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +0 -5
  188. package/web/.next/server/chunks/ssr/src_presentation_web_d2912c21._.js +0 -3
  189. package/web/.next/static/chunks/0158bd913a9f8332.css +0 -1
  190. package/web/.next/static/chunks/93e492830319fe32.js +0 -1
  191. package/web/.next/static/chunks/9ff2ffa85c1a522d.js +0 -1
  192. /package/web/.next/static/{kV-WQWxVkAheI2w3nsEIN → 4hN7Gtw--ruMbDn0FRI2-}/_buildManifest.js +0 -0
  193. /package/web/.next/static/{kV-WQWxVkAheI2w3nsEIN → 4hN7Gtw--ruMbDn0FRI2-}/_clientMiddlewareManifest.json +0 -0
  194. /package/web/.next/static/{kV-WQWxVkAheI2w3nsEIN → 4hN7Gtw--ruMbDn0FRI2-}/_ssgManifest.js +0 -0
@@ -38,12 +38,17 @@ const PORT_PATTERNS = [
38
38
  * @param line - A single line of process output
39
39
  * @returns The detected URL string, or null if no URL/port was found
40
40
  */
41
+ // Strip ANSI escape codes (colors, cursor movement, etc.)
42
+ // eslint-disable-next-line no-control-regex
43
+ const ANSI_REGEX = /\x1b\[[0-9;]*[a-zA-Z]/g;
41
44
  export function parsePort(line) {
42
45
  if (!line?.trim()) {
43
46
  return null;
44
47
  }
48
+ // Strip ANSI escape codes before matching — dev servers often emit colored output
49
+ const clean = line.replace(ANSI_REGEX, '');
45
50
  for (const { regex, extract } of PORT_PATTERNS) {
46
- const match = line.match(regex);
51
+ const match = clean.match(regex);
47
52
  if (match) {
48
53
  return extract(match);
49
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git-pr.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/git-pr.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-pr.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/git-pr.service.ts"],"names":[],"mappings":"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"}
@@ -308,15 +308,19 @@ let GitPrService = class GitPrService {
308
308
  }
309
309
  }
310
310
  async watchCi(cwd, branch, timeoutMs, intervalSeconds) {
311
+ // Resolve the latest run for the branch BEFORE the try/catch so the
312
+ // runUrl is available in both success and failure return paths.
313
+ let runUrl;
311
314
  try {
312
315
  // gh run watch requires a run ID — it does not support --branch.
313
316
  // First, resolve the latest run ID for the branch via gh run list.
314
- const { stdout: listOut } = await this.execFile('gh', ['run', 'list', '--branch', branch, '--json', 'databaseId', '--limit', '1'], { cwd });
317
+ const { stdout: listOut } = await this.execFile('gh', ['run', 'list', '--branch', branch, '--json', 'databaseId,url', '--limit', '1'], { cwd });
315
318
  const runs = JSON.parse(listOut);
316
319
  if (runs.length === 0 || !runs[0].databaseId) {
317
320
  return { status: 'pending' };
318
321
  }
319
322
  const runId = String(runs[0].databaseId);
323
+ runUrl = runs[0].url;
320
324
  const interval = intervalSeconds ?? 30;
321
325
  const args = [
322
326
  'run',
@@ -335,6 +339,7 @@ let GitPrService = class GitPrService {
335
339
  // If we reach here (no exception), CI passed — no need for fragile stdout parsing.
336
340
  return {
337
341
  status: 'success',
342
+ runUrl,
338
343
  logExcerpt: stdout.trim(),
339
344
  };
340
345
  }
@@ -356,7 +361,7 @@ let GitPrService = class GitPrService {
356
361
  // Build a useful log excerpt from stdout/stderr if available
357
362
  const errObj = error;
358
363
  const parts = [errObj.stdout, errObj.stderr, message].filter(Boolean);
359
- return { status: 'failure', logExcerpt: parts.join('\n').trim() };
364
+ return { status: 'failure', runUrl, logExcerpt: parts.join('\n').trim() };
360
365
  }
361
366
  throw new GitPrError(message, GitPrErrorCode.GIT_ERROR, cause);
362
367
  }
@@ -27,7 +27,7 @@ export async function deployFeature(featureId) {
27
27
  }
28
28
  log.info('worktree path exists, calling deploymentService.start()');
29
29
  const deploymentService = resolve('IDeploymentService');
30
- deploymentService.start(featureId, worktreePath);
30
+ deploymentService.start(featureId, worktreePath, 'feature');
31
31
  log.info('start() returned successfully — state=Booting');
32
32
  return { success: true, state: DeploymentState.Booting };
33
33
  }
@@ -18,7 +18,7 @@ export async function deployRepository(repositoryPath) {
18
18
  }
19
19
  log.info('directory exists, calling deploymentService.start()');
20
20
  const deploymentService = resolve('IDeploymentService');
21
- deploymentService.start(repositoryPath, repositoryPath);
21
+ deploymentService.start(repositoryPath, repositoryPath, 'repository');
22
22
  log.info('start() returned successfully — state=Booting');
23
23
  return { success: true, state: DeploymentState.Booting };
24
24
  }
@@ -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":"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,2CAkX5F"}
@@ -3,13 +3,12 @@ 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, GitBranch, GitCommitHorizontal, ArrowDown, User, RotateCcw, } 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';
10
10
  import { Button } from '../../ui/button.js';
11
11
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
12
- import { DeploymentStatusBadge } from '../../common/deployment-status-badge/index.js';
13
12
  import { useDeployAction } from '../../../hooks/use-deploy-action.js';
14
13
  import { useFeatureFlags } from '../../../hooks/feature-flags-context.js';
15
14
  import { useRepositoryActions } from './use-repository-actions.js';
@@ -72,9 +71,13 @@ export function RepositoryNode({ data }) {
72
71
  e.stopPropagation();
73
72
  data.onClick?.();
74
73
  }
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) => {
74
+ }, 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 })] })) : 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
75
  e.stopPropagation();
77
76
  data.onAdd?.();
78
77
  }, 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] }));
78
+ '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, featureFlags.envDeploy && data.repositoryPath ? (_jsx("div", { "data-testid": "repository-node-dev-preview", className: "border-t px-4 py-2", onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "flex items-center gap-2 text-xs", children: [deployAction.deployError ? (_jsx("span", { className: "truncate text-xs text-red-500", children: deployAction.deployError })) : isDeploymentActive ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "mr-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500" }), deployAction.url ? (_jsx("a", { href: deployAction.url, target: "_blank", rel: "noopener noreferrer", className: "truncate text-green-700 hover:underline dark:text-green-400", children: deployAction.url })) : (_jsx("span", { className: "text-muted-foreground", children: "Starting..." }))] })) : (_jsxs("span", { className: "text-muted-foreground", children: ["Run", _jsx("span", { className: "text-muted-foreground/50 ml-2 text-[10px]", children: "start local environment" })] })), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "ml-auto flex items-center", children: _jsx(ActionButton, { label: deployAction.deployError
79
+ ? 'Retry'
80
+ : isDeploymentActive
81
+ ? 'Stop Dev Server'
82
+ : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: false, icon: deployAction.deployError ? RotateCcw : isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) })] }) })) : null] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
80
83
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAgBjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7F,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAQD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CA6gBpB"}
1
+ {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAgBjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7F,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAQD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAuhBpB"}
@@ -102,11 +102,20 @@ export function useControlCenterState(initialNodes, initialEdges) {
102
102
  for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {
103
103
  if (state !== undefined || lifecycle !== undefined) {
104
104
  const nodeId = `feat-${featureId}`;
105
+ const existingNode = nodesRef.current.find((n) => n.id === nodeId);
106
+ const existingState = existingNode
107
+ ? existingNode.data.state
108
+ : undefined;
105
109
  // Skip SSE updates for features in 'deleting' state — the optimistic
106
110
  // delete state must not be overwritten by stale SSE events (e.g. agent
107
111
  // cancellation emitting AgentFailed during the soft-delete window).
108
- const existingNode = nodesRef.current.find((n) => n.id === nodeId);
109
- if (existingNode && existingNode.data.state === 'deleting')
112
+ if (existingState === 'deleting')
113
+ continue;
114
+ // Skip SSE error events during mutation cooldown — after approve/reject
115
+ // the agent may still report AgentFailed from the previous run before
116
+ // the resume kicks in. The optimistic 'running' state must not be
117
+ // overwritten by stale error events during this transition window.
118
+ if (state === 'error' && isMutating() && existingState === 'running')
110
119
  continue;
111
120
  updateFeature(nodeId, {
112
121
  ...(state !== undefined && { state }),
@@ -114,7 +123,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
114
123
  });
115
124
  }
116
125
  }
117
- }, [events, updateFeature]);
126
+ }, [events, updateFeature, isMutating]);
118
127
  // Listen for optimistic approval/rejection events from the drawer (fires before SSE arrives).
119
128
  // Uses beginMutation + endMutation to prevent stale poll/reconcile data from overwriting
120
129
  // the optimistic 'running' state during the transition window (avoids brief "Something went wrong" flash).
@@ -1 +1 @@
1
- {"version":3,"file":"use-deploy-action.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-deploy-action.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAM5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,GAAG,YAAY,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAOD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,iBAAiB,CAwKlF"}
1
+ {"version":3,"file":"use-deploy-action.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-deploy-action.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAM5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,GAAG,YAAY,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAMD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,iBAAiB,CAmOlF"}
@@ -6,7 +6,6 @@ import { deployRepository } from '../app/actions/deploy-repository.js';
6
6
  import { stopDeployment } from '../app/actions/stop-deployment.js';
7
7
  import { getDeploymentStatus } from '../app/actions/get-deployment-status.js';
8
8
  const log = createLogger('[useDeployAction]');
9
- const ERROR_CLEAR_DELAY = 5000;
10
9
  const POLL_INTERVAL = 3000;
11
10
  export function useDeployAction(input) {
12
11
  const [deployLoading, setDeployLoading] = useState(false);
@@ -14,7 +13,6 @@ export function useDeployAction(input) {
14
13
  const [deployError, setDeployError] = useState(null);
15
14
  const [status, setStatus] = useState(null);
16
15
  const [url, setUrl] = useState(null);
17
- const errorTimerRef = useRef(null);
18
16
  const pollIntervalRef = useRef(null);
19
17
  const mountedRef = useRef(true);
20
18
  const statusRef = useRef(status);
@@ -29,11 +27,37 @@ export function useDeployAction(input) {
29
27
  mountedRef.current = false;
30
28
  };
31
29
  }, []);
30
+ // Fetch status on mount — recover running dev servers after page reload
31
+ useEffect(() => {
32
+ if (!input)
33
+ return;
34
+ let cancelled = false;
35
+ (async () => {
36
+ try {
37
+ const result = await getDeploymentStatus(input.targetId);
38
+ if (cancelled || !mountedRef.current)
39
+ return;
40
+ if (result && result.state !== 'Stopped') {
41
+ log.info(`mount recovery: "${input.targetId}" state=${result.state}, url=${result.url}`);
42
+ setStatus(result.state);
43
+ setUrl(result.url);
44
+ startPolling(input.targetId);
45
+ }
46
+ }
47
+ catch {
48
+ // Server container may not be available (e.g., in tests)
49
+ log.debug(`mount recovery failed for "${input.targetId}" — ignoring`);
50
+ }
51
+ })();
52
+ return () => {
53
+ cancelled = true;
54
+ };
55
+ // Only run on mount (input identity is stable from the caller)
56
+ // eslint-disable-next-line react-hooks/exhaustive-deps
57
+ }, [input?.targetId]);
32
58
  // Cleanup on unmount
33
59
  useEffect(() => {
34
60
  return () => {
35
- if (errorTimerRef.current)
36
- clearTimeout(errorTimerRef.current);
37
61
  if (pollIntervalRef.current)
38
62
  clearInterval(pollIntervalRef.current);
39
63
  };
@@ -53,7 +77,20 @@ export function useDeployAction(input) {
53
77
  stopPolling();
54
78
  return;
55
79
  }
56
- const result = await getDeploymentStatus(targetId);
80
+ let result;
81
+ try {
82
+ result = await getDeploymentStatus(targetId);
83
+ }
84
+ catch (err) {
85
+ log.warn(`poll fetch failed for "${targetId}":`, err);
86
+ // Treat fetch failure as deployment gone — clear UI
87
+ if (mountedRef.current) {
88
+ setStatus(null);
89
+ setUrl(null);
90
+ stopPolling();
91
+ }
92
+ return;
93
+ }
57
94
  if (!mountedRef.current)
58
95
  return;
59
96
  if (!result || result.state === 'Stopped') {
@@ -71,6 +108,32 @@ export function useDeployAction(input) {
71
108
  }
72
109
  }, POLL_INTERVAL);
73
110
  }, [stopPolling]);
111
+ // Idle poll — when no deployment is known, periodically check if one was
112
+ // started externally (e.g., from the drawer while the repo node is mounted).
113
+ const IDLE_POLL_INTERVAL = 5000;
114
+ useEffect(() => {
115
+ if (!input || status !== null)
116
+ return;
117
+ const timer = setInterval(async () => {
118
+ if (!mountedRef.current)
119
+ return;
120
+ try {
121
+ const result = await getDeploymentStatus(input.targetId);
122
+ if (!mountedRef.current)
123
+ return;
124
+ if (result && result.state !== 'Stopped') {
125
+ log.info(`idle poll: "${input.targetId}" state=${result.state}, url=${result.url}`);
126
+ setStatus(result.state);
127
+ setUrl(result.url);
128
+ startPolling(input.targetId);
129
+ }
130
+ }
131
+ catch {
132
+ // ignore
133
+ }
134
+ }, IDLE_POLL_INTERVAL);
135
+ return () => clearInterval(timer);
136
+ }, [input, status, startPolling]);
74
137
  const handleDeploy = useCallback(async () => {
75
138
  if (!input) {
76
139
  log.warn('deploy() called but input is null — no-op');
@@ -81,8 +144,6 @@ export function useDeployAction(input) {
81
144
  return;
82
145
  }
83
146
  log.info(`deploy() — targetType="${input.targetType}", targetId="${input.targetId}", repositoryPath="${input.repositoryPath}"`);
84
- if (errorTimerRef.current)
85
- clearTimeout(errorTimerRef.current);
86
147
  setDeployLoading(true);
87
148
  setDeployError(null);
88
149
  try {
@@ -96,9 +157,8 @@ export function useDeployAction(input) {
96
157
  }
97
158
  if (!result.success) {
98
159
  const errorMessage = result.error ?? 'An unexpected error occurred';
99
- log.error(`deploy failed: ${errorMessage}`);
160
+ log.warn(`deploy failed: ${errorMessage}`);
100
161
  setDeployError(errorMessage);
101
- errorTimerRef.current = setTimeout(() => setDeployError(null), ERROR_CLEAR_DELAY);
102
162
  }
103
163
  else {
104
164
  log.info(`deploy succeeded — initial state=${result.state}, starting polling`);
@@ -113,7 +173,6 @@ export function useDeployAction(input) {
113
173
  const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred';
114
174
  log.error(`deploy threw exception: ${errorMessage}`, err);
115
175
  setDeployError(errorMessage);
116
- errorTimerRef.current = setTimeout(() => setDeployError(null), ERROR_CLEAR_DELAY);
117
176
  }
118
177
  finally {
119
178
  if (mountedRef.current) {
@@ -3,12 +3,12 @@ import dagre from '@dagrejs/dagre';
3
3
  export const CANVAS_LAYOUT_DEFAULTS = {
4
4
  direction: 'LR',
5
5
  ranksep: 200,
6
- nodesep: 15,
6
+ nodesep: 30,
7
7
  };
8
8
  /** Known node-type dimensions for the canvas node types */
9
9
  const NODE_DIMENSIONS = {
10
- featureNode: { width: 288, height: 140 },
11
- repositoryNode: { width: 400, height: 110 },
10
+ featureNode: { width: 288, height: 160 },
11
+ repositoryNode: { width: 400, height: 160 },
12
12
  };
13
13
  function getNodeSize(node, defaultSize) {
14
14
  // Prefer per-node size from data, then type-based lookup, then default