@shepai/cli 1.65.0 → 1.66.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 (330) hide show
  1. package/dist/packages/core/src/application/ports/output/repositories/repository-repository.interface.d.ts +1 -1
  2. package/dist/packages/core/src/application/ports/output/repositories/repository-repository.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts +62 -0
  4. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts.map +1 -0
  5. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.js +12 -0
  6. package/dist/packages/core/src/application/ports/output/services/index.d.ts +1 -0
  7. package/dist/packages/core/src/application/ports/output/services/index.d.ts.map +1 -1
  8. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  9. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +4 -1
  10. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
  11. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.js +5 -2
  12. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  13. package/dist/packages/core/src/infrastructure/di/container.js +3 -0
  14. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations.js +25 -0
  16. package/dist/packages/core/src/infrastructure/repositories/sqlite-repository.repository.d.ts +1 -1
  17. package/dist/packages/core/src/infrastructure/repositories/sqlite-repository.repository.d.ts.map +1 -1
  18. package/dist/packages/core/src/infrastructure/repositories/sqlite-repository.repository.js +5 -2
  19. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  20. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +6 -2
  21. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.d.ts.map +1 -1
  22. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/merge-prompts.js +11 -7
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/plan.prompt.d.ts.map +1 -1
  24. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/plan.prompt.js +11 -7
  25. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts.map +1 -1
  26. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.js +11 -7
  27. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts +57 -0
  28. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -0
  29. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +192 -0
  30. package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.d.ts +26 -0
  31. package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.d.ts.map +1 -0
  32. package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.js +59 -0
  33. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.d.ts +15 -0
  34. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.d.ts.map +1 -0
  35. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.js +52 -0
  36. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  37. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +13 -3
  38. package/dist/src/presentation/cli/commands/_serve.command.d.ts.map +1 -1
  39. package/dist/src/presentation/cli/commands/_serve.command.js +2 -0
  40. package/dist/src/presentation/web/app/actions/deploy-feature.d.ts +7 -0
  41. package/dist/src/presentation/web/app/actions/deploy-feature.d.ts.map +1 -0
  42. package/dist/src/presentation/web/app/actions/deploy-feature.js +28 -0
  43. package/dist/src/presentation/web/app/actions/deploy-repository.d.ts +7 -0
  44. package/dist/src/presentation/web/app/actions/deploy-repository.d.ts.map +1 -0
  45. package/dist/src/presentation/web/app/actions/deploy-repository.js +21 -0
  46. package/dist/src/presentation/web/app/actions/get-deployment-status.d.ts +3 -0
  47. package/dist/src/presentation/web/app/actions/get-deployment-status.d.ts.map +1 -0
  48. package/dist/src/presentation/web/app/actions/get-deployment-status.js +9 -0
  49. package/dist/src/presentation/web/app/actions/stop-deployment.d.ts +5 -0
  50. package/dist/src/presentation/web/app/actions/stop-deployment.d.ts.map +1 -0
  51. package/dist/src/presentation/web/app/actions/stop-deployment.js +16 -0
  52. package/dist/src/presentation/web/app/build-graph-nodes.d.ts +20 -0
  53. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -0
  54. package/dist/src/presentation/web/app/build-graph-nodes.js +142 -0
  55. package/dist/src/presentation/web/app/page.d.ts.map +1 -1
  56. package/dist/src/presentation/web/app/page.js +2 -112
  57. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.d.ts +3 -1
  58. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.d.ts.map +1 -1
  59. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.js +13 -3
  60. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.d.ts +2 -0
  61. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.d.ts.map +1 -1
  62. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.js +9 -0
  63. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.d.ts +7 -0
  64. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.d.ts.map +1 -0
  65. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.js +14 -0
  66. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.d.ts +14 -0
  67. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.d.ts.map +1 -0
  68. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.js +27 -0
  69. package/dist/src/presentation/web/components/common/deployment-status-badge/index.d.ts +2 -0
  70. package/dist/src/presentation/web/components/common/deployment-status-badge/index.d.ts.map +1 -0
  71. package/dist/src/presentation/web/components/common/deployment-status-badge/index.js +1 -0
  72. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts.map +1 -1
  73. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.js +8 -1
  74. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.d.ts.map +1 -1
  75. package/dist/src/presentation/web/components/common/repository-node/repository-drawer.js +7 -1
  76. package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
  77. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +13 -2
  78. package/dist/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.d.ts.map +1 -1
  79. package/dist/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.js +12 -2
  80. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts +18 -0
  81. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -0
  82. package/dist/src/presentation/web/hooks/use-deploy-action.js +130 -0
  83. package/dist/src/presentation/web/lib/feature-flags.d.ts +1 -0
  84. package/dist/src/presentation/web/lib/feature-flags.d.ts.map +1 -1
  85. package/dist/src/presentation/web/lib/feature-flags.js +1 -0
  86. package/dist/tsconfig.build.tsbuildinfo +1 -1
  87. package/package.json +1 -1
  88. package/web/.next/BUILD_ID +1 -1
  89. package/web/.next/build-manifest.json +7 -6
  90. package/web/.next/cache/.previewinfo +1 -1
  91. package/web/.next/cache/.rscinfo +1 -1
  92. package/web/.next/cache/.tsbuildinfo +1 -1
  93. package/web/.next/cache/config.json +3 -3
  94. package/web/.next/fallback-build-manifest.json +2 -2
  95. package/web/.next/prerender-manifest.json +3 -3
  96. package/web/.next/required-server-files.js +1 -1
  97. package/web/.next/required-server-files.json +1 -1
  98. package/web/.next/server/app/_global-error/page/build-manifest.json +5 -4
  99. package/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  100. package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  101. package/web/.next/server/app/_global-error.html +2 -2
  102. package/web/.next/server/app/_global-error.rsc +1 -1
  103. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  104. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  105. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  106. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  107. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  108. package/web/.next/server/app/_not-found/page/build-manifest.json +5 -4
  109. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  110. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  111. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  112. package/web/.next/server/app/api/tools/[id]/install/route.js +1 -1
  113. package/web/.next/server/app/api/tools/[id]/install/route.js.nft.json +1 -1
  114. package/web/.next/server/app/page/build-manifest.json +5 -4
  115. package/web/.next/server/app/page/server-reference-manifest.json +88 -28
  116. package/web/.next/server/app/page.js +2 -2
  117. package/web/.next/server/app/page.js.nft.json +1 -1
  118. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  119. package/web/.next/server/app/skills/page/build-manifest.json +5 -4
  120. package/web/.next/server/app/skills/page/server-reference-manifest.json +62 -2
  121. package/web/.next/server/app/skills/page.js +2 -2
  122. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  123. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  124. package/web/.next/server/app/tools/page/build-manifest.json +5 -4
  125. package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  126. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  127. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  128. package/web/.next/server/app/version/page/build-manifest.json +5 -4
  129. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  130. package/web/.next/server/app/version/page.js +1 -1
  131. package/web/.next/server/app/version/page.js.nft.json +1 -1
  132. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  133. package/web/.next/server/chunks/{[root-of-the-server]__e926de65._.js → [root-of-the-server]__09413611._.js} +2 -2
  134. package/web/.next/server/chunks/{[root-of-the-server]__e926de65._.js.map → [root-of-the-server]__09413611._.js.map} +1 -1
  135. package/web/.next/server/chunks/ssr/403f9_next_dist_623b646a._.js +3 -0
  136. package/web/.next/server/chunks/ssr/403f9_next_dist_623b646a._.js.map +1 -0
  137. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  138. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
  139. package/web/.next/server/chunks/ssr/{[root-of-the-server]__685eaa45._.js → [root-of-the-server]__248ee887._.js} +2 -2
  140. package/web/.next/server/chunks/ssr/{[root-of-the-server]__685eaa45._.js.map → [root-of-the-server]__248ee887._.js.map} +1 -1
  141. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__fbc89707._.js → server/chunks/ssr/[root-of-the-server]__249c74f6._.js} +2 -2
  142. package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +4 -0
  143. package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js.map +1 -0
  144. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  145. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  146. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb51fac._.js +3 -0
  147. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb51fac._.js.map +1 -0
  148. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  149. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  150. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +4 -4
  151. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
  152. package/web/.next/server/chunks/ssr/[root-of-the-server]__c1f0f2a8._.js +3 -0
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__c1f0f2a8._.js.map +1 -0
  154. package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__dd5b62cb._.js → server/chunks/ssr/[root-of-the-server]__f5830fa9._.js} +2 -2
  155. package/web/.next/server/chunks/ssr/[root-of-the-server]__f5830fa9._.js.map +1 -0
  156. package/web/.next/server/chunks/ssr/[root-of-the-server]__f648005b._.js +9 -0
  157. package/web/.next/server/chunks/ssr/[root-of-the-server]__f648005b._.js.map +1 -0
  158. package/web/.next/server/chunks/ssr/_28993370._.js +3 -0
  159. package/web/.next/server/chunks/ssr/_28993370._.js.map +1 -0
  160. package/web/.next/server/chunks/ssr/_380c6567._.js +1 -1
  161. package/web/.next/server/chunks/ssr/_380c6567._.js.map +1 -1
  162. package/web/.next/server/chunks/ssr/_45715073._.js +3 -0
  163. package/web/.next/server/chunks/ssr/{_d81184e2._.js.map → _45715073._.js.map} +1 -1
  164. package/web/.next/server/chunks/ssr/_6978d868._.js +3 -0
  165. package/web/.next/server/chunks/ssr/_6978d868._.js.map +1 -0
  166. package/web/.next/server/chunks/ssr/_85965278._.js +6 -0
  167. package/web/.next/server/chunks/ssr/_85965278._.js.map +1 -0
  168. package/web/.next/server/chunks/ssr/_c52cace8._.js +3 -0
  169. package/web/.next/server/chunks/ssr/_c52cace8._.js.map +1 -0
  170. package/web/.next/server/chunks/ssr/_ed9132c9._.js +3 -0
  171. package/web/.next/server/chunks/ssr/_ed9132c9._.js.map +1 -0
  172. package/web/.next/server/chunks/ssr/{node_modules__pnpm_87f920e7._.js → node_modules__pnpm_febcbea6._.js} +2 -2
  173. package/web/.next/server/chunks/ssr/node_modules__pnpm_febcbea6._.js.map +1 -0
  174. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  175. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  176. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  177. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  178. package/web/.next/server/middleware-build-manifest.js +5 -4
  179. package/web/.next/server/pages/500.html +2 -2
  180. package/web/.next/server/server-reference-manifest.js +1 -1
  181. package/web/.next/server/server-reference-manifest.json +118 -30
  182. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  183. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +7 -6
  184. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  185. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  186. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error/page/build-manifest.json +5 -4
  187. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  188. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  189. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  190. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  191. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  192. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  193. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  194. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  195. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  196. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/build-manifest.json +5 -4
  197. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  198. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  199. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  200. package/web/.next/standalone/src/presentation/web/.next/server/app/api/tools/[id]/install/route.js +1 -1
  201. package/web/.next/standalone/src/presentation/web/.next/server/app/api/tools/[id]/install/route.js.nft.json +1 -1
  202. package/web/.next/standalone/src/presentation/web/.next/server/app/page/build-manifest.json +5 -4
  203. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +88 -28
  204. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +2 -2
  205. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
  206. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  207. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/build-manifest.json +5 -4
  208. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +62 -2
  209. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js +2 -2
  210. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  211. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  212. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/build-manifest.json +5 -4
  213. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  214. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  215. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  216. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/build-manifest.json +5 -4
  217. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  218. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js +1 -1
  219. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  220. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  221. package/web/.next/standalone/src/presentation/web/.next/server/chunks/{[root-of-the-server]__e926de65._.js → [root-of-the-server]__09413611._.js} +2 -2
  222. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/403f9_next_dist_623b646a._.js +3 -0
  223. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  224. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{[root-of-the-server]__685eaa45._.js → [root-of-the-server]__248ee887._.js} +2 -2
  225. package/web/.next/{server/chunks/ssr/[root-of-the-server]__fbc89707._.js → standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js} +2 -2
  226. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +4 -0
  227. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  228. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6bb51fac._.js +3 -0
  229. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  230. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +4 -4
  231. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__c1f0f2a8._.js +3 -0
  232. package/web/.next/{server/chunks/ssr/[root-of-the-server]__dd5b62cb._.js → standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__f5830fa9._.js} +2 -2
  233. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__f648005b._.js +9 -0
  234. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_28993370._.js +3 -0
  235. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_380c6567._.js +1 -1
  236. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_45715073._.js +3 -0
  237. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6978d868._.js +3 -0
  238. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_85965278._.js +6 -0
  239. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_c52cace8._.js +3 -0
  240. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_ed9132c9._.js +3 -0
  241. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{node_modules__pnpm_87f920e7._.js → node_modules__pnpm_febcbea6._.js} +2 -2
  242. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  243. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  244. package/web/.next/standalone/src/presentation/web/.next/server/middleware-build-manifest.js +5 -4
  245. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  246. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  247. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +118 -30
  248. package/web/.next/standalone/src/presentation/web/app/actions/deploy-feature.ts +39 -0
  249. package/web/.next/standalone/src/presentation/web/app/actions/deploy-repository.ts +28 -0
  250. package/web/.next/standalone/src/presentation/web/app/actions/get-deployment-status.ts +16 -0
  251. package/web/.next/standalone/src/presentation/web/app/actions/stop-deployment.ts +22 -0
  252. package/web/.next/standalone/src/presentation/web/app/build-graph-nodes.ts +180 -0
  253. package/web/.next/standalone/src/presentation/web/app/page.tsx +2 -129
  254. package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.stories.tsx +26 -0
  255. package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.tsx +45 -1
  256. package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.tsx +35 -0
  257. package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.tsx +42 -0
  258. package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/index.ts +1 -0
  259. package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/feature-drawer.tsx +10 -0
  260. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-drawer.tsx +9 -0
  261. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +43 -2
  262. package/web/.next/standalone/src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.tsx +79 -44
  263. package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +161 -0
  264. package/web/.next/standalone/src/presentation/web/lib/feature-flags.ts +1 -0
  265. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  266. package/web/.next/static/chunks/0b99eb9664d47ca7.js +1 -0
  267. package/web/.next/static/chunks/177f1dcbe83c136a.js +1 -0
  268. package/web/.next/static/chunks/41a2adc09edfffaf.js +1 -0
  269. package/web/.next/static/chunks/5054c72b1c8f5912.js +1 -0
  270. package/web/.next/static/chunks/71d2618e41d7da6d.js +1 -0
  271. package/web/.next/static/chunks/7ad36bef63f15bc6.js +1 -0
  272. package/web/.next/static/chunks/{3b941e59ac013e12.js → 87421ab1062a39b7.js} +2 -2
  273. package/web/.next/static/chunks/{21541b346dd4dd28.js → 8c60d1bd87239066.js} +1 -1
  274. package/web/.next/static/chunks/96f49affaceab206.css +2 -0
  275. package/web/.next/static/chunks/a6d1d774260fc927.js +2 -0
  276. package/web/.next/static/chunks/c7e793951b20a67f.js +1 -0
  277. package/web/.next/static/chunks/f54ff9c15fb7b383.js +1 -0
  278. package/web/.next/static/chunks/f5fb2f182ae9b015.js +1 -0
  279. package/web/.next/static/chunks/{fa8058049a43c698.js → f6766e799a69fb5d.js} +7 -7
  280. package/web/.next/static/chunks/turbopack-b6b5b4f015327a9a.js +4 -0
  281. package/web/.next/trace +1 -1
  282. package/web/.next/trace-build +1 -1
  283. package/web/.next/server/chunks/ssr/[root-of-the-server]__5e0f14e9._.js +0 -3
  284. package/web/.next/server/chunks/ssr/[root-of-the-server]__5e0f14e9._.js.map +0 -1
  285. package/web/.next/server/chunks/ssr/[root-of-the-server]__ae251147._.js +0 -3
  286. package/web/.next/server/chunks/ssr/[root-of-the-server]__ae251147._.js.map +0 -1
  287. package/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js +0 -9
  288. package/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js.map +0 -1
  289. package/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js +0 -4
  290. package/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js.map +0 -1
  291. package/web/.next/server/chunks/ssr/[root-of-the-server]__dd5b62cb._.js.map +0 -1
  292. package/web/.next/server/chunks/ssr/[root-of-the-server]__edca9510._.js +0 -3
  293. package/web/.next/server/chunks/ssr/[root-of-the-server]__edca9510._.js.map +0 -1
  294. package/web/.next/server/chunks/ssr/_73d14b70._.js +0 -3
  295. package/web/.next/server/chunks/ssr/_73d14b70._.js.map +0 -1
  296. package/web/.next/server/chunks/ssr/_7f386377._.js +0 -3
  297. package/web/.next/server/chunks/ssr/_7f386377._.js.map +0 -1
  298. package/web/.next/server/chunks/ssr/_d3711354._.js +0 -6
  299. package/web/.next/server/chunks/ssr/_d3711354._.js.map +0 -1
  300. package/web/.next/server/chunks/ssr/_d81184e2._.js +0 -3
  301. package/web/.next/server/chunks/ssr/node_modules__pnpm_0ce0b44d._.js +0 -3
  302. package/web/.next/server/chunks/ssr/node_modules__pnpm_0ce0b44d._.js.map +0 -1
  303. package/web/.next/server/chunks/ssr/node_modules__pnpm_87f920e7._.js.map +0 -1
  304. package/web/.next/server/chunks/ssr/src_presentation_web_components_7a0b09da._.js +0 -3
  305. package/web/.next/server/chunks/ssr/src_presentation_web_components_7a0b09da._.js.map +0 -1
  306. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__5e0f14e9._.js +0 -3
  307. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__ae251147._.js +0 -3
  308. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__b6839c3f._.js +0 -9
  309. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__da0ade1f._.js +0 -4
  310. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__edca9510._.js +0 -3
  311. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_73d14b70._.js +0 -3
  312. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_7f386377._.js +0 -3
  313. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_d3711354._.js +0 -6
  314. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_d81184e2._.js +0 -3
  315. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/node_modules__pnpm_0ce0b44d._.js +0 -3
  316. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_7a0b09da._.js +0 -3
  317. package/web/.next/static/chunks/0c6654ec27f11c7e.js +0 -1
  318. package/web/.next/static/chunks/12c70bfd5951cf9b.js +0 -1
  319. package/web/.next/static/chunks/1887af4ad3781531.js +0 -2
  320. package/web/.next/static/chunks/233fbb89beb137e8.js +0 -1
  321. package/web/.next/static/chunks/78919481e7c5ad4f.js +0 -1
  322. package/web/.next/static/chunks/a5b6a22de303e877.css +0 -2
  323. package/web/.next/static/chunks/acdb8af5a21f1ae9.js +0 -1
  324. package/web/.next/static/chunks/af7a5bcb7c49e46e.js +0 -1
  325. package/web/.next/static/chunks/be784143669bb992.js +0 -1
  326. package/web/.next/static/chunks/turbopack-eb24b869babb34b4.js +0 -4
  327. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__fbc89707._.js.map → [root-of-the-server]__249c74f6._.js.map} +0 -0
  328. /package/web/.next/static/{zuqVLdEhCDdtLqCuWgUm5 → 5RMUwLfTnzL0pvJOwfuxg}/_buildManifest.js +0 -0
  329. /package/web/.next/static/{zuqVLdEhCDdtLqCuWgUm5 → 5RMUwLfTnzL0pvJOwfuxg}/_clientMiddlewareManifest.json +0 -0
  330. /package/web/.next/static/{zuqVLdEhCDdtLqCuWgUm5 → 5RMUwLfTnzL0pvJOwfuxg}/_ssgManifest.js +0 -0
@@ -0,0 +1,142 @@
1
+ import { deriveNodeState, deriveProgress, } from '../components/common/feature-node/derive-feature-state.js';
2
+ /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
3
+ const lifecycleMap = {
4
+ Requirements: 'requirements',
5
+ Research: 'research',
6
+ Implementation: 'implementation',
7
+ Review: 'review',
8
+ 'Deploy & QA': 'deploy',
9
+ Maintain: 'maintain',
10
+ };
11
+ /** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
12
+ const nodeToLifecyclePhase = {
13
+ analyze: 'requirements',
14
+ requirements: 'requirements',
15
+ research: 'research',
16
+ plan: 'implementation',
17
+ implement: 'implementation',
18
+ merge: 'review',
19
+ };
20
+ /**
21
+ * Builds React Flow nodes and edges from persisted repositories and features.
22
+ *
23
+ * Features whose repositoryPath is not covered by any real repository row are
24
+ * grouped under a synthetic "virtual" repository node
25
+ * (id: `virtual-repo-${repositoryPath}`). This ensures the dashboard never
26
+ * renders empty when features exist but their repository rows are missing.
27
+ */
28
+ export function buildGraphNodes(repositories, featuresWithRuns) {
29
+ // Group features by repository path
30
+ const featuresByRepo = {};
31
+ featuresWithRuns.forEach((entry) => {
32
+ const repoKey = entry.feature.repositoryPath;
33
+ if (!featuresByRepo[repoKey]) {
34
+ featuresByRepo[repoKey] = [];
35
+ }
36
+ featuresByRepo[repoKey].push(entry);
37
+ });
38
+ const nodes = [];
39
+ const edges = [];
40
+ // Track which repository paths have been rendered (to avoid orphan duplicates)
41
+ const coveredPaths = new Set();
42
+ // First, add nodes for all persisted repositories (including those without features)
43
+ for (const repo of repositories) {
44
+ coveredPaths.add(repo.path);
45
+ const repoNodeId = `repo-${repo.id}`;
46
+ nodes.push({
47
+ id: repoNodeId,
48
+ type: 'repositoryNode',
49
+ position: { x: 0, y: 0 },
50
+ data: { name: repo.name, repositoryPath: repo.path, id: repo.id },
51
+ });
52
+ const repoFeatures = featuresByRepo[repo.path] ?? [];
53
+ appendFeatureNodes(repoFeatures, repoNodeId, featuresWithRuns, nodes, edges);
54
+ }
55
+ // Second pass: group orphaned features under virtual repository nodes
56
+ for (const [repoPath, orphanFeatures] of Object.entries(featuresByRepo)) {
57
+ if (coveredPaths.has(repoPath))
58
+ continue;
59
+ const virtualRepoNodeId = `virtual-repo-${repoPath}`;
60
+ const repoName = repoPath.split('/').filter(Boolean).at(-1) ?? repoPath;
61
+ nodes.push({
62
+ id: virtualRepoNodeId,
63
+ type: 'repositoryNode',
64
+ position: { x: 0, y: 0 },
65
+ data: { name: repoName, repositoryPath: repoPath },
66
+ });
67
+ appendFeatureNodes(orphanFeatures, virtualRepoNodeId, featuresWithRuns, nodes, edges);
68
+ }
69
+ // Add parent→child dependency edges
70
+ for (const { feature } of featuresWithRuns) {
71
+ if (feature.parentId) {
72
+ const parentNodeId = `feat-${feature.parentId}`;
73
+ const childNodeId = `feat-${feature.id}`;
74
+ if (nodes.some((n) => n.id === parentNodeId) && nodes.some((n) => n.id === childNodeId)) {
75
+ edges.push({
76
+ id: `dep-${parentNodeId}-${childNodeId}`,
77
+ source: parentNodeId,
78
+ target: childNodeId,
79
+ type: 'dependencyEdge',
80
+ });
81
+ }
82
+ }
83
+ }
84
+ return { nodes, edges };
85
+ }
86
+ function appendFeatureNodes(repoFeatures, repoNodeId, allFeaturesWithRuns, nodes, edges) {
87
+ repoFeatures.forEach(({ feature, run }) => {
88
+ const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
89
+ const lifecycle = run?.status === 'completed'
90
+ ? 'maintain'
91
+ : ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
92
+ lifecycleMap[feature.lifecycle] ??
93
+ 'requirements');
94
+ // Resolve blockedBy display name from parent feature
95
+ let blockedBy;
96
+ if (feature.parentId && feature.lifecycle === 'Blocked') {
97
+ const parentEntry = allFeaturesWithRuns.find((e) => e.feature.id === feature.parentId);
98
+ if (parentEntry) {
99
+ blockedBy = parentEntry.feature.name;
100
+ }
101
+ }
102
+ const nodeData = {
103
+ name: feature.name,
104
+ description: feature.description ?? feature.slug,
105
+ featureId: feature.id,
106
+ lifecycle,
107
+ repositoryPath: feature.repositoryPath,
108
+ branch: feature.branch,
109
+ specPath: feature.specPath,
110
+ state: deriveNodeState(feature, run),
111
+ progress: deriveProgress(feature),
112
+ ...(run?.agentType && { agentType: run.agentType }),
113
+ ...(run?.error && { errorMessage: run.error }),
114
+ ...(blockedBy && { blockedBy }),
115
+ ...(feature.pr && {
116
+ pr: {
117
+ url: feature.pr.url,
118
+ number: feature.pr.number,
119
+ status: feature.pr.status,
120
+ ciStatus: feature.pr.ciStatus,
121
+ commitHash: feature.pr.commitHash,
122
+ },
123
+ }),
124
+ };
125
+ const featureNodeId = `feat-${feature.id}`;
126
+ nodes.push({
127
+ id: featureNodeId,
128
+ type: 'featureNode',
129
+ position: { x: 0, y: 0 },
130
+ data: nodeData,
131
+ });
132
+ // Child features connect via parent→child dependency edge, not directly to repo
133
+ if (!feature.parentId) {
134
+ edges.push({
135
+ id: `edge-${repoNodeId}-${featureNodeId}`,
136
+ source: repoNodeId,
137
+ target: featureNodeId,
138
+ style: { strokeDasharray: '5 5' },
139
+ });
140
+ }
141
+ });
142
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAsBvC,wBAA8B,QAAQ,qDAiIrC"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAQA,uFAAuF;AACvF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,wBAA8B,QAAQ,qDA4BrC"}
@@ -1,28 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ControlCenter } from '../components/features/control-center/index.js';
3
3
  import { resolve } from '../lib/server-container.js';
4
- import { deriveNodeState, deriveProgress, } from '../components/common/feature-node/derive-feature-state.js';
5
4
  import { layoutWithDagre } from '../lib/layout-with-dagre.js';
5
+ import { buildGraphNodes } from './build-graph-nodes.js';
6
6
  /** Skip static pre-rendering since we need runtime DI container and server context. */
7
7
  export const dynamic = 'force-dynamic';
8
- /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
9
- const lifecycleMap = {
10
- Requirements: 'requirements',
11
- Research: 'research',
12
- Implementation: 'implementation',
13
- Review: 'review',
14
- 'Deploy & QA': 'deploy',
15
- Maintain: 'maintain',
16
- };
17
- /** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
18
- const nodeToLifecyclePhase = {
19
- analyze: 'requirements',
20
- requirements: 'requirements',
21
- research: 'research',
22
- plan: 'implementation',
23
- implement: 'implementation',
24
- merge: 'review',
25
- };
26
8
  export default async function HomePage() {
27
9
  const listFeatures = resolve('ListFeaturesUseCase');
28
10
  const listRepos = resolve('ListRepositoriesUseCase');
@@ -32,99 +14,7 @@ export default async function HomePage() {
32
14
  const run = feature.agentRunId ? await agentRunRepo.findById(feature.agentRunId) : null;
33
15
  return { feature, run };
34
16
  }));
35
- // Group features by repository path (features may still reference paths not yet in repositories table)
36
- const featuresByRepo = {};
37
- featuresWithRuns.forEach((entry) => {
38
- const repoKey = entry.feature.repositoryPath;
39
- if (!featuresByRepo[repoKey]) {
40
- featuresByRepo[repoKey] = [];
41
- }
42
- featuresByRepo[repoKey].push(entry);
43
- });
44
- const nodes = [];
45
- const edges = [];
46
- // First, add nodes for all persisted repositories (including those without features)
47
- for (const repo of repositories) {
48
- const repoNodeId = `repo-${repo.id}`;
49
- nodes.push({
50
- id: repoNodeId,
51
- type: 'repositoryNode',
52
- position: { x: 0, y: 0 },
53
- data: { name: repo.name, repositoryPath: repo.path, id: repo.id },
54
- });
55
- const repoFeatures = featuresByRepo[repo.path] ?? [];
56
- repoFeatures.forEach(({ feature, run }) => {
57
- const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
58
- const lifecycle = run?.status === 'completed'
59
- ? 'maintain'
60
- : ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
61
- lifecycleMap[feature.lifecycle] ??
62
- 'requirements');
63
- // Resolve blockedBy display name from parent feature
64
- let blockedBy;
65
- if (feature.parentId && feature.lifecycle === 'Blocked') {
66
- const parentEntry = featuresWithRuns.find((e) => e.feature.id === feature.parentId);
67
- if (parentEntry) {
68
- blockedBy = parentEntry.feature.name;
69
- }
70
- }
71
- const nodeData = {
72
- name: feature.name,
73
- description: feature.description ?? feature.slug,
74
- featureId: feature.id,
75
- lifecycle,
76
- repositoryPath: feature.repositoryPath,
77
- branch: feature.branch,
78
- specPath: feature.specPath,
79
- state: deriveNodeState(feature, run),
80
- progress: deriveProgress(feature),
81
- ...(run?.agentType && { agentType: run.agentType }),
82
- ...(run?.error && { errorMessage: run.error }),
83
- ...(blockedBy && { blockedBy }),
84
- ...(feature.pr && {
85
- pr: {
86
- url: feature.pr.url,
87
- number: feature.pr.number,
88
- status: feature.pr.status,
89
- ciStatus: feature.pr.ciStatus,
90
- commitHash: feature.pr.commitHash,
91
- },
92
- }),
93
- };
94
- const featureNodeId = `feat-${feature.id}`;
95
- nodes.push({
96
- id: featureNodeId,
97
- type: 'featureNode',
98
- position: { x: 0, y: 0 },
99
- data: nodeData,
100
- });
101
- // Child features connect via parent→child dependency edge, not directly to repo
102
- if (!feature.parentId) {
103
- edges.push({
104
- id: `edge-${repoNodeId}-${featureNodeId}`,
105
- source: repoNodeId,
106
- target: featureNodeId,
107
- style: { strokeDasharray: '5 5' },
108
- });
109
- }
110
- });
111
- }
112
- // Add parent→child dependency edges
113
- for (const { feature } of featuresWithRuns) {
114
- if (feature.parentId) {
115
- const parentNodeId = `feat-${feature.parentId}`;
116
- const childNodeId = `feat-${feature.id}`;
117
- // Only add edge if both nodes exist on the canvas
118
- if (nodes.some((n) => n.id === parentNodeId) && nodes.some((n) => n.id === childNodeId)) {
119
- edges.push({
120
- id: `dep-${parentNodeId}-${childNodeId}`,
121
- source: parentNodeId,
122
- target: childNodeId,
123
- type: 'dependencyEdge',
124
- });
125
- }
126
- }
127
- }
17
+ const { nodes, edges } = buildGraphNodes(repositories, featuresWithRuns);
128
18
  // Use dagre LR layout for compact, automatic positioning
129
19
  const laid = layoutWithDagre(nodes, edges, {
130
20
  direction: 'LR',
@@ -1,4 +1,5 @@
1
1
  import { type VariantProps } from 'class-variance-authority';
2
+ import { type DeployActionInput } from '../../../hooks/use-deploy-action.js';
2
3
  declare const drawerVariants: (props?: ({
3
4
  size?: "md" | "sm" | null | undefined;
4
5
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -11,7 +12,8 @@ export interface BaseDrawerProps extends VariantProps<typeof drawerVariants> {
11
12
  footer?: React.ReactNode;
12
13
  className?: string;
13
14
  'data-testid'?: string;
15
+ deployTarget?: DeployActionInput;
14
16
  }
15
- export declare function BaseDrawer({ open, onClose, modal, size, header, children, footer, className, 'data-testid': testId, }: BaseDrawerProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function BaseDrawer({ open, onClose, modal, size, header, children, footer, className, 'data-testid': testId, deployTarget, }: BaseDrawerProps): import("react/jsx-runtime").JSX.Element;
16
18
  export {};
17
19
  //# sourceMappingURL=base-drawer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/base-drawer/base-drawer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAUlE,QAAA,MAAM,cAAc;;8EAUlB,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,YAAY,CAAC,OAAO,cAAc,CAAC;IAC1E,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAa,EACb,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,MAAM,EACN,SAAS,EACT,aAAa,EAAE,MAAM,GACtB,EAAE,eAAe,2CA2CjB"}
1
+ {"version":3,"file":"base-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/base-drawer/base-drawer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAYlE,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGpF,QAAA,MAAM,cAAc;;8EAUlB,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,YAAY,CAAC,OAAO,cAAc,CAAC;IAC1E,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAa,EACb,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,MAAM,EACN,SAAS,EACT,aAAa,EAAE,MAAM,EACrB,YAAY,GACb,EAAE,eAAe,2CA8CjB"}
@@ -1,9 +1,14 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { XIcon } from 'lucide-react';
3
+ import { XIcon, Play, Square } from 'lucide-react';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { cn } from '../../../lib/utils.js';
6
+ import { ActionButton } from '../../common/action-button/index.js';
7
+ import { DeploymentStatusBadge } from '../../common/deployment-status-badge/index.js';
6
8
  import { Drawer, DrawerContent, DrawerHeader, DrawerFooter, DrawerOverlay, } from '../../ui/drawer.js';
9
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
10
+ import { useDeployAction } from '../../../hooks/use-deploy-action.js';
11
+ import { featureFlags } from '../../../lib/feature-flags.js';
7
12
  const drawerVariants = cva('', {
8
13
  variants: {
9
14
  size: {
@@ -15,9 +20,14 @@ const drawerVariants = cva('', {
15
20
  size: 'sm',
16
21
  },
17
22
  });
18
- export function BaseDrawer({ open, onClose, modal = false, size, header, children, footer, className, 'data-testid': testId, }) {
23
+ export function BaseDrawer({ open, onClose, modal = false, size, header, children, footer, className, 'data-testid': testId, deployTarget, }) {
19
24
  return (_jsxs(Drawer, { direction: "right", modal: modal, handleOnly: true, open: open, onOpenChange: (isOpen) => {
20
25
  if (!isOpen)
21
26
  onClose();
22
- }, children: [modal ? _jsx(DrawerOverlay, {}) : null, _jsxs(DrawerContent, { direction: "right", showCloseButton: false, className: cn(drawerVariants({ size }), className), "data-testid": testId, children: [_jsxs("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", "data-testid": testId ? `${testId}-close-button` : undefined, children: [_jsx(XIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }), header ? _jsx(DrawerHeader, { children: header }) : null, _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx("div", { className: "flex flex-col", children: children }) }), footer ? _jsx(DrawerFooter, { children: footer }) : null] })] }));
27
+ }, children: [modal ? _jsx(DrawerOverlay, {}) : null, _jsxs(DrawerContent, { direction: "right", showCloseButton: false, className: cn(drawerVariants({ size }), className), "data-testid": testId, children: [_jsxs("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", "data-testid": testId ? `${testId}-close-button` : undefined, children: [_jsx(XIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }), header ? _jsx(DrawerHeader, { children: header }) : null, featureFlags.envDeploy && deployTarget ? _jsx(DeployBar, { deployTarget: deployTarget }) : null, _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx("div", { className: "flex flex-col", children: children }) }), footer ? _jsx(DrawerFooter, { children: footer }) : null] })] }));
28
+ }
29
+ function DeployBar({ deployTarget }) {
30
+ const deployAction = useDeployAction(deployTarget);
31
+ const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
32
+ return (_jsxs("div", { "data-testid": "base-drawer-deploy-bar", className: "flex items-center gap-2 px-4 pb-3", children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { 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: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url })) : null] }));
23
33
  }
@@ -17,6 +17,8 @@ export declare const WithHeader: Story;
17
17
  export declare const WithFooter: Story;
18
18
  /** Drawer with both header and footer slots populated. */
19
19
  export declare const WithHeaderAndFooter: Story;
20
+ /** Drawer with deployTarget prop showing the dev server bar below the header. */
21
+ export declare const WithDevServerBar: Story;
20
22
  /** Drawer with content that exceeds viewport to demonstrate scroll behavior. */
21
23
  export declare const ScrollableContent: Story;
22
24
  //# sourceMappingURL=base-drawer.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/base-drawer/base-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAOjC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,UAAU,CAAC,CAAC;AAuBzC,6DAA6D;AAC7D,eAAO,MAAM,OAAO,EAAE,KAQrB,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,SAAS,EAAE,KAkBvB,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,UAAU,EAAE,KAiBxB,CAAC;AAEF,iCAAiC;AACjC,eAAO,MAAM,KAAK,EAAE,KAUnB,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,UAAU,EAAE,KAexB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAiBxB,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,EAAE,KAsCjC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,EAAE,KAsB/B,CAAC"}
1
+ {"version":3,"file":"base-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/base-drawer/base-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,UAAU,CAOjC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,UAAU,CAAC,CAAC;AAuBzC,6DAA6D;AAC7D,eAAO,MAAM,OAAO,EAAE,KAQrB,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,SAAS,EAAE,KAkBvB,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,UAAU,EAAE,KAiBxB,CAAC;AAEF,iCAAiC;AACjC,eAAO,MAAM,KAAK,EAAE,KAUnB,CAAC;AAEF,4EAA4E;AAC5E,eAAO,MAAM,UAAU,EAAE,KAexB,CAAC;AAEF,yDAAyD;AACzD,eAAO,MAAM,UAAU,EAAE,KAiBxB,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB,EAAE,KAsCjC,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,EAAE,KAuB9B,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,EAAE,KAsB/B,CAAC"}
@@ -50,6 +50,15 @@ export const WithFooter = {
50
50
  export const WithHeaderAndFooter = {
51
51
  render: () => (_jsx(DrawerTrigger, { header: _jsxs(_Fragment, { children: [_jsx(DrawerTitle, { children: "Create Feature" }), _jsx(DrawerDescription, { children: "Fill in the details below" })] }), footer: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "outline", className: "flex-1", children: "Cancel" }), _jsx(Button, { className: "flex-1", children: "Create" })] }), children: _jsxs("div", { className: "flex flex-col gap-4 p-4", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-sm font-medium", children: "Name" }), _jsx("input", { type: "text", className: "border-input bg-background rounded-md border px-3 py-2 text-sm", placeholder: "Feature name" })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("label", { className: "text-sm font-medium", children: "Description" }), _jsx("textarea", { className: "border-input bg-background rounded-md border px-3 py-2 text-sm", rows: 3, placeholder: "Optional description" })] })] }) })),
52
52
  };
53
+ /** Drawer with deployTarget prop showing the dev server bar below the header. */
54
+ export const WithDevServerBar = {
55
+ render: () => (_jsx(DrawerTrigger, { header: _jsxs(_Fragment, { children: [_jsx(DrawerTitle, { children: "Auth Module" }), _jsx(DrawerDescription, { children: "#f-001" })] }), deployTarget: {
56
+ targetId: '#f-001',
57
+ targetType: 'feature',
58
+ repositoryPath: '/Users/dev/my-project',
59
+ branch: 'feat/auth-module',
60
+ }, children: _jsx("div", { className: "p-4", children: _jsx("p", { className: "text-muted-foreground text-sm", children: "The deploy bar appears between the header and this content." }) }) })),
61
+ };
53
62
  /** Drawer with content that exceeds viewport to demonstrate scroll behavior. */
54
63
  export const ScrollableContent = {
55
64
  render: () => (_jsx(DrawerTrigger, { header: _jsxs(_Fragment, { children: [_jsx(DrawerTitle, { children: "Scrollable Content" }), _jsx(DrawerDescription, { children: "Content below overflows and scrolls" })] }), children: _jsx("div", { className: "flex flex-col gap-4 p-4", children: Array.from({ length: 30 }, (_, i) => (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsxs("h4", { className: "text-sm font-medium", children: ["Item ", i + 1] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "This is a scrollable content item to demonstrate overflow handling." })] }, i))) }) })),
@@ -0,0 +1,7 @@
1
+ import { DeploymentState } from '../../../../../../packages/core/src/domain/generated/output.js';
2
+ export interface DeploymentStatusBadgeProps {
3
+ status: DeploymentState | null;
4
+ url?: string | null;
5
+ }
6
+ export declare function DeploymentStatusBadge({ status, url }: DeploymentStatusBadgeProps): import("react/jsx-runtime").JSX.Element | null;
7
+ //# sourceMappingURL=deployment-status-badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-status-badge.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAGvE,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,0BAA0B,kDAgChF"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Loader2, ExternalLink } from 'lucide-react';
3
+ import { DeploymentState } from '../../../../../../packages/core/src/domain/generated/output.js';
4
+ import { Badge } from '../../ui/badge.js';
5
+ export function DeploymentStatusBadge({ status, url }) {
6
+ switch (status) {
7
+ case DeploymentState.Booting:
8
+ return (_jsxs(Badge, { className: "border-transparent bg-blue-50 text-blue-700 hover:bg-blue-50", children: [_jsx(Loader2, { className: "mr-1 h-3.5 w-3.5 animate-spin" }), "Starting..."] }));
9
+ case DeploymentState.Ready:
10
+ return (_jsxs(Badge, { className: "border-transparent bg-green-50 text-green-700 hover:bg-green-50", children: [_jsx("span", { className: "mr-1 inline-block h-2 w-2 rounded-full bg-green-500" }), url ? (_jsxs("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 hover:underline", onClick: (e) => e.stopPropagation(), children: [url, _jsx(ExternalLink, { className: "h-3 w-3" })] })) : ('Ready')] }));
11
+ default:
12
+ return null;
13
+ }
14
+ }
@@ -0,0 +1,14 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { DeploymentStatusBadge } from './deployment-status-badge.js';
3
+ declare const meta: Meta<typeof DeploymentStatusBadge>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof DeploymentStatusBadge>;
6
+ /** Booting — blue badge with animated spinner. */
7
+ export declare const Booting: Story;
8
+ /** Ready — green badge with clickable URL and external link icon. */
9
+ export declare const Ready: Story;
10
+ /** Stopped — renders nothing (badge disappears). */
11
+ export declare const Stopped: Story;
12
+ /** No deployment — renders nothing. */
13
+ export declare const NoDeployment: Story;
14
+ //# sourceMappingURL=deployment-status-badge.stories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-status-badge.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,qBAAqB,CAO5C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpD,kDAAkD;AAClD,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,uCAAuC;AACvC,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { DeploymentState } from '../../../../../../packages/core/src/domain/generated/output.js';
2
+ import { DeploymentStatusBadge } from './deployment-status-badge.js';
3
+ const meta = {
4
+ title: 'Common/DeploymentStatusBadge',
5
+ component: DeploymentStatusBadge,
6
+ tags: ['autodocs'],
7
+ parameters: {
8
+ layout: 'centered',
9
+ },
10
+ };
11
+ export default meta;
12
+ /** Booting — blue badge with animated spinner. */
13
+ export const Booting = {
14
+ args: { status: DeploymentState.Booting },
15
+ };
16
+ /** Ready — green badge with clickable URL and external link icon. */
17
+ export const Ready = {
18
+ args: { status: DeploymentState.Ready, url: 'http://localhost:3000' },
19
+ };
20
+ /** Stopped — renders nothing (badge disappears). */
21
+ export const Stopped = {
22
+ args: { status: DeploymentState.Stopped },
23
+ };
24
+ /** No deployment — renders nothing. */
25
+ export const NoDeployment = {
26
+ args: { status: null },
27
+ };
@@ -0,0 +1,2 @@
1
+ export { DeploymentStatusBadge, type DeploymentStatusBadgeProps } from './deployment-status-badge.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/deployment-status-badge/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,KAAK,0BAA0B,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1 @@
1
+ export { DeploymentStatusBadge } from './deployment-status-badge.js';
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,EAC5B,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAkB,GACnB,EAAE,kBAAkB,2CAqIpB"}
1
+ {"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,EAC5B,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAkB,GACnB,EAAE,kBAAkB,2CA+IpB"}
@@ -29,7 +29,14 @@ export function FeatureDrawer({ selectedNode, onClose, onDelete, isDeleting = fa
29
29
  drawerCloseSound.play();
30
30
  onClose();
31
31
  }, [onClose, drawerCloseSound]);
32
- return (_jsx(BaseDrawer, { open: selectedNode !== null, onClose: handleClose, size: "sm", modal: false, "data-testid": "feature-drawer", header: selectedNode ? (_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] })) : undefined, children: selectedNode ? (_jsxs(_Fragment, { children: [selectedNode.repositoryPath && selectedNode.branch ? (_jsx(DrawerActions, { repositoryPath: selectedNode.repositoryPath, branch: selectedNode.branch, specPath: selectedNode.specPath })) : null, _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), selectedNode.pr ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx(PrInfoSection, { pr: selectedNode.pr })] })) : null, _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode }), onDelete ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { "data-testid": "feature-drawer-delete", className: "p-4", children: _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", className: "w-full", disabled: isDeleting, children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Delete feature"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: selectedNode.name }), " (", selectedNode.featureId, "). This action cannot be undone.", selectedNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(selectedNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] }) })] })) : null] })) : null }));
32
+ return (_jsx(BaseDrawer, { open: selectedNode !== null, onClose: handleClose, size: "sm", modal: false, "data-testid": "feature-drawer", header: selectedNode ? (_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] })) : undefined, deployTarget: selectedNode?.repositoryPath && selectedNode.branch
33
+ ? {
34
+ targetId: selectedNode.featureId,
35
+ targetType: 'feature',
36
+ repositoryPath: selectedNode.repositoryPath,
37
+ branch: selectedNode.branch,
38
+ }
39
+ : undefined, children: selectedNode ? (_jsxs(_Fragment, { children: [selectedNode.repositoryPath && selectedNode.branch ? (_jsx(DrawerActions, { repositoryPath: selectedNode.repositoryPath, branch: selectedNode.branch, specPath: selectedNode.specPath })) : null, _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), selectedNode.pr ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx(PrInfoSection, { pr: selectedNode.pr })] })) : null, _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode }), onDelete ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { "data-testid": "feature-drawer-delete", className: "p-4", children: _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", className: "w-full", disabled: isDeleting, children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Delete feature"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: selectedNode.name }), " (", selectedNode.featureId, "). This action cannot be undone.", selectedNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(selectedNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] }) })] })) : null] })) : null }));
33
40
  }
34
41
  function StateBadge({ data }) {
35
42
  const config = featureNodeStateConfig[data.state];
@@ -1 +1 @@
1
- {"version":3,"file":"repository-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-drawer.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CAkExE"}
1
+ {"version":3,"file":"repository-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-drawer.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CA2ExE"}
@@ -8,5 +8,11 @@ import { ActionButton } from '../../common/action-button/index.js';
8
8
  import { useRepositoryActions } from './use-repository-actions.js';
9
9
  export function RepositoryDrawer({ data, onClose }) {
10
10
  const actions = useRepositoryActions(data?.repositoryPath ? { repositoryPath: data.repositoryPath } : null);
11
- return (_jsx(BaseDrawer, { open: data !== null, onClose: onClose, size: "sm", modal: false, "data-testid": "repository-drawer", header: data ? (_jsxs("div", { "data-testid": "repository-drawer-header", children: [_jsx(DrawerTitle, { children: data.name }), data.repositoryPath ? (_jsx(DrawerDescription, { className: "truncate font-mono text-xs", children: data.repositoryPath })) : null] })) : undefined, children: data?.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsxs("div", { className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "OPEN WITH" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, variant: "outline", size: "sm" }), _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, variant: "outline", size: "sm" }), _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, variant: "outline", size: "sm" })] })] })] })) : null }));
11
+ return (_jsx(BaseDrawer, { open: data !== null, onClose: onClose, size: "sm", modal: false, "data-testid": "repository-drawer", deployTarget: data?.repositoryPath
12
+ ? {
13
+ targetId: data.repositoryPath,
14
+ targetType: 'repository',
15
+ repositoryPath: data.repositoryPath,
16
+ }
17
+ : undefined, header: data ? (_jsxs("div", { "data-testid": "repository-drawer-header", children: [_jsx(DrawerTitle, { children: data.name }), data.repositoryPath ? (_jsx(DrawerDescription, { className: "truncate font-mono text-xs", children: data.repositoryPath })) : null] })) : undefined, children: data?.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsxs("div", { className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "OPEN WITH" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, variant: "outline", size: "sm" }), _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, variant: "outline", size: "sm" }), _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, variant: "outline", size: "sm" })] })] })] })) : null }));
12
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,2CA2L5F"}
1
+ {"version":3,"file":"repository-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,2CAiO5F"}
@@ -2,15 +2,26 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState } from 'react';
4
4
  import { Handle, Position } from '@xyflow/react';
5
- import { Github, Plus, Code2, Terminal, FolderOpen, Trash2 } from 'lucide-react';
5
+ import { Github, Plus, Code2, Terminal, FolderOpen, Trash2, Play, Square } from 'lucide-react';
6
6
  import { cn } from '../../../lib/utils.js';
7
7
  import { ActionButton } from '../../common/action-button/index.js';
8
8
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '../../ui/alert-dialog.js';
9
9
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
10
+ import { DeploymentStatusBadge } from '../../common/deployment-status-badge/index.js';
11
+ import { useDeployAction } from '../../../hooks/use-deploy-action.js';
12
+ import { featureFlags } from '../../../lib/feature-flags.js';
10
13
  import { useRepositoryActions } from './use-repository-actions.js';
11
14
  export function RepositoryNode({ data }) {
12
15
  const [confirmOpen, setConfirmOpen] = useState(false);
13
16
  const actions = useRepositoryActions(data.repositoryPath ? { repositoryPath: data.repositoryPath } : null);
17
+ const deployAction = useDeployAction(data.repositoryPath
18
+ ? {
19
+ targetId: data.repositoryPath,
20
+ targetType: 'repository',
21
+ repositoryPath: data.repositoryPath,
22
+ }
23
+ : null);
24
+ const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
14
25
  return (_jsxs("div", { className: "group relative", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!" })) : null, data.onDelete && data.id ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 -left-10 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Remove repository", "data-testid": "repository-node-delete-button", onClick: (e) => {
15
26
  e.stopPropagation();
16
27
  setConfirmOpen(true);
@@ -23,7 +34,7 @@ export function RepositoryNode({ data }) {
23
34
  e.stopPropagation();
24
35
  data.onClick?.();
25
36
  }
26
- }, className: "nodrag bg-card flex w-72 cursor-default items-center gap-3 rounded-full border px-4 py-3 shadow-sm", children: [_jsx(Github, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { "data-testid": "repository-node-name", className: "min-w-0 truncate text-sm font-medium", children: data.name }), _jsxs("div", { className: cn('flex shrink-0 items-center gap-2', (data.repositoryPath ?? data.onAdd) && 'ml-auto'), onClick: (e) => e.stopPropagation(), children: [data.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in IDE" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in Shell" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open Folder" })] }) })] })) : 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) => {
37
+ }, className: "nodrag bg-card flex min-w-[18rem] cursor-default items-center gap-3 rounded-full border px-4 py-3 shadow-sm", children: [_jsx(Github, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { "data-testid": "repository-node-name", className: "min-w-0 truncate text-sm font-medium", children: data.name }), _jsxs("div", { className: cn('flex shrink-0 items-center gap-2', (data.repositoryPath ?? data.onAdd) && 'ml-auto'), onClick: (e) => e.stopPropagation(), children: [data.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in IDE" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in Shell" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open Folder" })] }) }), 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 })) : 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) => {
27
38
  e.stopPropagation();
28
39
  data.onAdd?.();
29
40
  }, className: "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", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Add feature" })] }) })) : null] })] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
@@ -1 +1 @@
1
- {"version":3,"file":"review-drawer-shell.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAE3E,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,GACT,EAAE,sBAAsB,2CA0FxB"}
1
+ {"version":3,"file":"review-drawer-shell.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/review-drawer-shell/review-drawer-shell.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAE3E,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,GACT,EAAE,sBAAsB,2CAwHxB"}