@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
@@ -3,38 +3,12 @@ import { resolve } from '@/lib/server-container';
3
3
  import type { ListFeaturesUseCase } from '@shepai/core/application/use-cases/features/list-features.use-case';
4
4
  import type { ListRepositoriesUseCase } from '@shepai/core/application/use-cases/repositories/list-repositories.use-case';
5
5
  import type { IAgentRunRepository } from '@shepai/core/application/ports/output/agents/agent-run-repository.interface';
6
- import {
7
- deriveNodeState,
8
- deriveProgress,
9
- } from '@/components/common/feature-node/derive-feature-state';
10
6
  import { layoutWithDagre } from '@/lib/layout-with-dagre';
11
- import type { CanvasNodeType } from '@/components/features/features-canvas';
12
- import type { Edge } from '@xyflow/react';
13
- import type { FeatureNodeData, FeatureLifecyclePhase } from '@/components/common/feature-node';
7
+ import { buildGraphNodes } from '@/app/build-graph-nodes';
14
8
 
15
9
  /** Skip static pre-rendering since we need runtime DI container and server context. */
16
10
  export const dynamic = 'force-dynamic';
17
11
 
18
- /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
19
- const lifecycleMap: Record<string, FeatureLifecyclePhase> = {
20
- Requirements: 'requirements',
21
- Research: 'research',
22
- Implementation: 'implementation',
23
- Review: 'review',
24
- 'Deploy & QA': 'deploy',
25
- Maintain: 'maintain',
26
- };
27
-
28
- /** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
29
- const nodeToLifecyclePhase: Record<string, FeatureLifecyclePhase> = {
30
- analyze: 'requirements',
31
- requirements: 'requirements',
32
- research: 'research',
33
- plan: 'implementation',
34
- implement: 'implementation',
35
- merge: 'review',
36
- };
37
-
38
12
  export default async function HomePage() {
39
13
  const listFeatures = resolve<ListFeaturesUseCase>('ListFeaturesUseCase');
40
14
  const listRepos = resolve<ListRepositoriesUseCase>('ListRepositoriesUseCase');
@@ -49,108 +23,7 @@ export default async function HomePage() {
49
23
  })
50
24
  );
51
25
 
52
- // Group features by repository path (features may still reference paths not yet in repositories table)
53
- const featuresByRepo: Record<string, typeof featuresWithRuns> = {};
54
- featuresWithRuns.forEach((entry) => {
55
- const repoKey = entry.feature.repositoryPath;
56
- if (!featuresByRepo[repoKey]) {
57
- featuresByRepo[repoKey] = [];
58
- }
59
- featuresByRepo[repoKey].push(entry);
60
- });
61
-
62
- const nodes: CanvasNodeType[] = [];
63
- const edges: Edge[] = [];
64
-
65
- // First, add nodes for all persisted repositories (including those without features)
66
- for (const repo of repositories) {
67
- const repoNodeId = `repo-${repo.id}`;
68
- nodes.push({
69
- id: repoNodeId,
70
- type: 'repositoryNode',
71
- position: { x: 0, y: 0 },
72
- data: { name: repo.name, repositoryPath: repo.path, id: repo.id },
73
- });
74
-
75
- const repoFeatures = featuresByRepo[repo.path] ?? [];
76
- repoFeatures.forEach(({ feature, run }) => {
77
- const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
78
- const lifecycle: FeatureLifecyclePhase =
79
- run?.status === 'completed'
80
- ? 'maintain'
81
- : ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
82
- lifecycleMap[feature.lifecycle] ??
83
- 'requirements');
84
-
85
- // Resolve blockedBy display name from parent feature
86
- let blockedBy: string | undefined;
87
- if (feature.parentId && feature.lifecycle === 'Blocked') {
88
- const parentEntry = featuresWithRuns.find((e) => e.feature.id === feature.parentId);
89
- if (parentEntry) {
90
- blockedBy = parentEntry.feature.name;
91
- }
92
- }
93
-
94
- const nodeData: FeatureNodeData = {
95
- name: feature.name,
96
- description: feature.description ?? feature.slug,
97
- featureId: feature.id,
98
- lifecycle,
99
- repositoryPath: feature.repositoryPath,
100
- branch: feature.branch,
101
- specPath: feature.specPath,
102
- state: deriveNodeState(feature, run),
103
- progress: deriveProgress(feature),
104
- ...(run?.agentType && { agentType: run.agentType as FeatureNodeData['agentType'] }),
105
- ...(run?.error && { errorMessage: run.error }),
106
- ...(blockedBy && { blockedBy }),
107
- ...(feature.pr && {
108
- pr: {
109
- url: feature.pr.url,
110
- number: feature.pr.number,
111
- status: feature.pr.status,
112
- ciStatus: feature.pr.ciStatus,
113
- commitHash: feature.pr.commitHash,
114
- },
115
- }),
116
- };
117
-
118
- const featureNodeId = `feat-${feature.id}`;
119
- nodes.push({
120
- id: featureNodeId,
121
- type: 'featureNode',
122
- position: { x: 0, y: 0 },
123
- data: nodeData,
124
- });
125
-
126
- // Child features connect via parent→child dependency edge, not directly to repo
127
- if (!feature.parentId) {
128
- edges.push({
129
- id: `edge-${repoNodeId}-${featureNodeId}`,
130
- source: repoNodeId,
131
- target: featureNodeId,
132
- style: { strokeDasharray: '5 5' },
133
- });
134
- }
135
- });
136
- }
137
-
138
- // Add parent→child dependency edges
139
- for (const { feature } of featuresWithRuns) {
140
- if (feature.parentId) {
141
- const parentNodeId = `feat-${feature.parentId}`;
142
- const childNodeId = `feat-${feature.id}`;
143
- // Only add edge if both nodes exist on the canvas
144
- if (nodes.some((n) => n.id === parentNodeId) && nodes.some((n) => n.id === childNodeId)) {
145
- edges.push({
146
- id: `dep-${parentNodeId}-${childNodeId}`,
147
- source: parentNodeId,
148
- target: childNodeId,
149
- type: 'dependencyEdge',
150
- });
151
- }
152
- }
153
- }
26
+ const { nodes, edges } = buildGraphNodes(repositories, featuresWithRuns);
154
27
 
155
28
  // Use dagre LR layout for compact, automatic positioning
156
29
  const laid = layoutWithDagre(nodes, edges, {
@@ -181,6 +181,32 @@ export const WithHeaderAndFooter: Story = {
181
181
  ),
182
182
  };
183
183
 
184
+ /** Drawer with deployTarget prop showing the dev server bar below the header. */
185
+ export const WithDevServerBar: Story = {
186
+ render: () => (
187
+ <DrawerTrigger
188
+ header={
189
+ <>
190
+ <DrawerTitle>Auth Module</DrawerTitle>
191
+ <DrawerDescription>#f-001</DrawerDescription>
192
+ </>
193
+ }
194
+ deployTarget={{
195
+ targetId: '#f-001',
196
+ targetType: 'feature',
197
+ repositoryPath: '/Users/dev/my-project',
198
+ branch: 'feat/auth-module',
199
+ }}
200
+ >
201
+ <div className="p-4">
202
+ <p className="text-muted-foreground text-sm">
203
+ The deploy bar appears between the header and this content.
204
+ </p>
205
+ </div>
206
+ </DrawerTrigger>
207
+ ),
208
+ };
209
+
184
210
  /** Drawer with content that exceeds viewport to demonstrate scroll behavior. */
185
211
  export const ScrollableContent: Story = {
186
212
  render: () => (
@@ -1,8 +1,10 @@
1
1
  'use client';
2
2
 
3
- import { XIcon } from 'lucide-react';
3
+ import { XIcon, Play, Square } from 'lucide-react';
4
4
  import { cva, type VariantProps } from 'class-variance-authority';
5
5
  import { cn } from '@/lib/utils';
6
+ import { ActionButton } from '@/components/common/action-button';
7
+ import { DeploymentStatusBadge } from '@/components/common/deployment-status-badge';
6
8
  import {
7
9
  Drawer,
8
10
  DrawerContent,
@@ -10,6 +12,9 @@ import {
10
12
  DrawerFooter,
11
13
  DrawerOverlay,
12
14
  } from '@/components/ui/drawer';
15
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
16
+ import { useDeployAction, type DeployActionInput } from '@/hooks/use-deploy-action';
17
+ import { featureFlags } from '@/lib/feature-flags';
13
18
 
14
19
  const drawerVariants = cva('', {
15
20
  variants: {
@@ -32,6 +37,7 @@ export interface BaseDrawerProps extends VariantProps<typeof drawerVariants> {
32
37
  footer?: React.ReactNode;
33
38
  className?: string;
34
39
  'data-testid'?: string;
40
+ deployTarget?: DeployActionInput;
35
41
  }
36
42
 
37
43
  export function BaseDrawer({
@@ -44,6 +50,7 @@ export function BaseDrawer({
44
50
  footer,
45
51
  className,
46
52
  'data-testid': testId,
53
+ deployTarget,
47
54
  }: BaseDrawerProps) {
48
55
  return (
49
56
  <Drawer
@@ -77,6 +84,9 @@ export function BaseDrawer({
77
84
  {/* Header slot */}
78
85
  {header ? <DrawerHeader>{header}</DrawerHeader> : null}
79
86
 
87
+ {/* Dev server bar — rendered when deployTarget is provided and env deploy is enabled */}
88
+ {featureFlags.envDeploy && deployTarget ? <DeployBar deployTarget={deployTarget} /> : null}
89
+
80
90
  {/* Scrollable content area */}
81
91
  <div className="flex-1 overflow-y-auto">
82
92
  <div className="flex flex-col">{children}</div>
@@ -88,3 +98,37 @@ export function BaseDrawer({
88
98
  </Drawer>
89
99
  );
90
100
  }
101
+
102
+ function DeployBar({ deployTarget }: { deployTarget: DeployActionInput }) {
103
+ const deployAction = useDeployAction(deployTarget);
104
+ const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
105
+
106
+ return (
107
+ <div data-testid="base-drawer-deploy-bar" className="flex items-center gap-2 px-4 pb-3">
108
+ <TooltipProvider>
109
+ <Tooltip>
110
+ <TooltipTrigger asChild>
111
+ <span>
112
+ <ActionButton
113
+ label={isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server'}
114
+ onClick={isDeploymentActive ? deployAction.stop : deployAction.deploy}
115
+ loading={deployAction.deployLoading || deployAction.stopLoading}
116
+ error={!!deployAction.deployError}
117
+ icon={isDeploymentActive ? Square : Play}
118
+ iconOnly
119
+ variant="outline"
120
+ size="icon-sm"
121
+ />
122
+ </span>
123
+ </TooltipTrigger>
124
+ <TooltipContent>
125
+ {isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server'}
126
+ </TooltipContent>
127
+ </Tooltip>
128
+ </TooltipProvider>
129
+ {isDeploymentActive ? (
130
+ <DeploymentStatusBadge status={deployAction.status} url={deployAction.url} />
131
+ ) : null}
132
+ </div>
133
+ );
134
+ }
@@ -0,0 +1,35 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { DeploymentState } from '@shepai/core/domain/generated/output';
3
+ import { DeploymentStatusBadge } from './deployment-status-badge';
4
+
5
+ const meta: Meta<typeof DeploymentStatusBadge> = {
6
+ title: 'Common/DeploymentStatusBadge',
7
+ component: DeploymentStatusBadge,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ layout: 'centered',
11
+ },
12
+ };
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof DeploymentStatusBadge>;
16
+
17
+ /** Booting — blue badge with animated spinner. */
18
+ export const Booting: Story = {
19
+ args: { status: DeploymentState.Booting },
20
+ };
21
+
22
+ /** Ready — green badge with clickable URL and external link icon. */
23
+ export const Ready: Story = {
24
+ args: { status: DeploymentState.Ready, url: 'http://localhost:3000' },
25
+ };
26
+
27
+ /** Stopped — renders nothing (badge disappears). */
28
+ export const Stopped: Story = {
29
+ args: { status: DeploymentState.Stopped },
30
+ };
31
+
32
+ /** No deployment — renders nothing. */
33
+ export const NoDeployment: Story = {
34
+ args: { status: null },
35
+ };
@@ -0,0 +1,42 @@
1
+ import { Loader2, ExternalLink } from 'lucide-react';
2
+ import { DeploymentState } from '@shepai/core/domain/generated/output';
3
+ import { Badge } from '@/components/ui/badge';
4
+
5
+ export interface DeploymentStatusBadgeProps {
6
+ status: DeploymentState | null;
7
+ url?: string | null;
8
+ }
9
+
10
+ export function DeploymentStatusBadge({ status, url }: DeploymentStatusBadgeProps) {
11
+ switch (status) {
12
+ case DeploymentState.Booting:
13
+ return (
14
+ <Badge className="border-transparent bg-blue-50 text-blue-700 hover:bg-blue-50">
15
+ <Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
16
+ Starting...
17
+ </Badge>
18
+ );
19
+ case DeploymentState.Ready:
20
+ return (
21
+ <Badge className="border-transparent bg-green-50 text-green-700 hover:bg-green-50">
22
+ <span className="mr-1 inline-block h-2 w-2 rounded-full bg-green-500" />
23
+ {url ? (
24
+ <a
25
+ href={url}
26
+ target="_blank"
27
+ rel="noopener noreferrer"
28
+ className="inline-flex items-center gap-1 hover:underline"
29
+ onClick={(e) => e.stopPropagation()}
30
+ >
31
+ {url}
32
+ <ExternalLink className="h-3 w-3" />
33
+ </a>
34
+ ) : (
35
+ 'Ready'
36
+ )}
37
+ </Badge>
38
+ );
39
+ default:
40
+ return null;
41
+ }
42
+ }
@@ -0,0 +1 @@
1
+ export { DeploymentStatusBadge, type DeploymentStatusBadgeProps } from './deployment-status-badge';
@@ -70,6 +70,16 @@ export function FeatureDrawer({
70
70
  </div>
71
71
  ) : undefined
72
72
  }
73
+ deployTarget={
74
+ selectedNode?.repositoryPath && selectedNode.branch
75
+ ? {
76
+ targetId: selectedNode.featureId,
77
+ targetType: 'feature',
78
+ repositoryPath: selectedNode.repositoryPath,
79
+ branch: selectedNode.branch,
80
+ }
81
+ : undefined
82
+ }
73
83
  >
74
84
  {selectedNode ? (
75
85
  <>
@@ -25,6 +25,15 @@ export function RepositoryDrawer({ data, onClose }: RepositoryDrawerProps) {
25
25
  size="sm"
26
26
  modal={false}
27
27
  data-testid="repository-drawer"
28
+ deployTarget={
29
+ data?.repositoryPath
30
+ ? {
31
+ targetId: data.repositoryPath,
32
+ targetType: 'repository',
33
+ repositoryPath: data.repositoryPath,
34
+ }
35
+ : undefined
36
+ }
28
37
  header={
29
38
  data ? (
30
39
  <div data-testid="repository-drawer-header">
@@ -2,7 +2,7 @@
2
2
 
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';
7
7
  import { ActionButton } from '@/components/common/action-button';
8
8
  import {
@@ -16,6 +16,9 @@ import {
16
16
  AlertDialogTitle,
17
17
  } from '@/components/ui/alert-dialog';
18
18
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
19
+ import { DeploymentStatusBadge } from '@/components/common/deployment-status-badge';
20
+ import { useDeployAction } from '@/hooks/use-deploy-action';
21
+ import { featureFlags } from '@/lib/feature-flags';
19
22
  import type { RepositoryNodeData } from './repository-node-config';
20
23
  import { useRepositoryActions } from './use-repository-actions';
21
24
 
@@ -24,6 +27,16 @@ export function RepositoryNode({ data }: { data: RepositoryNodeData; [key: strin
24
27
  const actions = useRepositoryActions(
25
28
  data.repositoryPath ? { repositoryPath: data.repositoryPath } : null
26
29
  );
30
+ const deployAction = useDeployAction(
31
+ data.repositoryPath
32
+ ? {
33
+ targetId: data.repositoryPath,
34
+ targetType: 'repository',
35
+ repositoryPath: data.repositoryPath,
36
+ }
37
+ : null
38
+ );
39
+ const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
27
40
 
28
41
  return (
29
42
  <div className="group relative">
@@ -96,7 +109,7 @@ export function RepositoryNode({ data }: { data: RepositoryNodeData; [key: strin
96
109
  data.onClick?.();
97
110
  }
98
111
  }}
99
- className="nodrag bg-card flex w-72 cursor-default items-center gap-3 rounded-full border px-4 py-3 shadow-sm"
112
+ className="nodrag bg-card flex min-w-[18rem] cursor-default items-center gap-3 rounded-full border px-4 py-3 shadow-sm"
100
113
  >
101
114
  <Github className="text-muted-foreground h-5 w-5 shrink-0" />
102
115
  <span data-testid="repository-node-name" className="min-w-0 truncate text-sm font-medium">
@@ -169,6 +182,34 @@ export function RepositoryNode({ data }: { data: RepositoryNodeData; [key: strin
169
182
  <TooltipContent>Open Folder</TooltipContent>
170
183
  </Tooltip>
171
184
  </TooltipProvider>
185
+ {featureFlags.envDeploy ? (
186
+ <>
187
+ <TooltipProvider>
188
+ <Tooltip>
189
+ <TooltipTrigger asChild>
190
+ <span className="flex items-center">
191
+ <ActionButton
192
+ label={isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server'}
193
+ onClick={isDeploymentActive ? deployAction.stop : deployAction.deploy}
194
+ loading={deployAction.deployLoading || deployAction.stopLoading}
195
+ error={!!deployAction.deployError}
196
+ icon={isDeploymentActive ? Square : Play}
197
+ iconOnly
198
+ variant="ghost"
199
+ size="icon-xs"
200
+ />
201
+ </span>
202
+ </TooltipTrigger>
203
+ <TooltipContent>
204
+ {isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server'}
205
+ </TooltipContent>
206
+ </Tooltip>
207
+ </TooltipProvider>
208
+ {isDeploymentActive ? (
209
+ <DeploymentStatusBadge status={deployAction.status} url={deployAction.url} />
210
+ ) : null}
211
+ </>
212
+ ) : null}
172
213
  </>
173
214
  ) : null}
174
215
 
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { Loader2, Trash2 } from 'lucide-react';
3
+ import { Loader2, Trash2, Play, Square } from 'lucide-react';
4
4
  import { BaseDrawer } from '@/components/common/base-drawer';
5
5
  import { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';
6
6
  import { Button } from '@/components/ui/button';
@@ -16,8 +16,13 @@ import {
16
16
  AlertDialogTitle,
17
17
  AlertDialogTrigger,
18
18
  } from '@/components/ui/alert-dialog';
19
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
19
20
  import { OpenActionMenu } from '@/components/common/open-action-menu';
21
+ import { ActionButton } from '@/components/common/action-button';
20
22
  import { useFeatureActions } from '@/components/common/feature-drawer/use-feature-actions';
23
+ import { DeploymentStatusBadge } from '@/components/common/deployment-status-badge';
24
+ import { useDeployAction } from '@/hooks/use-deploy-action';
25
+ import { featureFlags } from '@/lib/feature-flags';
21
26
  import type { ReviewDrawerShellProps } from './review-drawer-shell-config';
22
27
 
23
28
  export function ReviewDrawerShell({
@@ -36,6 +41,13 @@ export function ReviewDrawerShell({
36
41
  const actionsInput = repositoryPath && branch ? { repositoryPath, branch, specPath } : null;
37
42
  const actions = useFeatureActions(actionsInput);
38
43
 
44
+ const deployTargetInput =
45
+ featureId && repositoryPath && branch
46
+ ? { targetId: featureId, targetType: 'feature' as const, repositoryPath, branch }
47
+ : null;
48
+ const deployAction = useDeployAction(deployTargetInput);
49
+ const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
50
+
39
51
  return (
40
52
  <BaseDrawer
41
53
  open={open}
@@ -54,7 +66,7 @@ export function ReviewDrawerShell({
54
66
  ) : null}
55
67
  </div>
56
68
 
57
- {/* Action menu + inline delete */}
69
+ {/* Action row: Open | Deploy → Delete (right-aligned) */}
58
70
  {actionsInput ? (
59
71
  <div className="flex items-center gap-2 pt-2">
60
72
  <OpenActionMenu
@@ -62,54 +74,77 @@ export function ReviewDrawerShell({
62
74
  repositoryPath={actionsInput.repositoryPath}
63
75
  showSpecs={!!specPath}
64
76
  />
77
+ {featureFlags.envDeploy && deployTargetInput ? (
78
+ <TooltipProvider>
79
+ <Tooltip>
80
+ <TooltipTrigger asChild>
81
+ <span>
82
+ <ActionButton
83
+ label={isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server'}
84
+ onClick={isDeploymentActive ? deployAction.stop : deployAction.deploy}
85
+ loading={deployAction.deployLoading || deployAction.stopLoading}
86
+ error={!!deployAction.deployError}
87
+ icon={isDeploymentActive ? Square : Play}
88
+ iconOnly
89
+ variant="outline"
90
+ size="icon-sm"
91
+ />
92
+ </span>
93
+ </TooltipTrigger>
94
+ <TooltipContent>
95
+ {isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server'}
96
+ </TooltipContent>
97
+ </Tooltip>
98
+ </TooltipProvider>
99
+ ) : null}
100
+ {featureFlags.envDeploy && isDeploymentActive ? (
101
+ <DeploymentStatusBadge status={deployAction.status} url={deployAction.url} />
102
+ ) : null}
65
103
  {onDelete && featureId ? (
66
- <>
67
- <div className="bg-border mx-1 h-4 w-px" />
68
- <AlertDialog>
69
- <AlertDialogTrigger asChild>
70
- <Button
71
- variant="ghost"
72
- size="icon-sm"
73
- aria-label="Delete feature"
104
+ <AlertDialog>
105
+ <AlertDialogTrigger asChild>
106
+ <Button
107
+ variant="ghost"
108
+ size="icon-sm"
109
+ aria-label="Delete feature"
110
+ disabled={isDeleting}
111
+ className="text-muted-foreground hover:text-destructive ml-auto"
112
+ data-testid="review-drawer-delete"
113
+ >
114
+ {isDeleting ? (
115
+ <Loader2 className="size-4 animate-spin" />
116
+ ) : (
117
+ <Trash2 className="size-4" />
118
+ )}
119
+ </Button>
120
+ </AlertDialogTrigger>
121
+ <AlertDialogContent>
122
+ <AlertDialogHeader>
123
+ <AlertDialogTitle>Delete feature?</AlertDialogTitle>
124
+ <AlertDialogDescription>
125
+ This will permanently delete <strong>{featureName}</strong> ({featureId}).
126
+ This action cannot be undone.
127
+ </AlertDialogDescription>
128
+ </AlertDialogHeader>
129
+ <AlertDialogFooter>
130
+ <AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
131
+ <AlertDialogAction
132
+ variant="destructive"
74
133
  disabled={isDeleting}
75
- className="text-muted-foreground hover:text-destructive"
76
- data-testid="review-drawer-delete"
134
+ onClick={() => onDelete(featureId)}
77
135
  >
78
136
  {isDeleting ? (
79
- <Loader2 className="size-4 animate-spin" />
137
+ <>
138
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
139
+ Deleting…
140
+ </>
80
141
  ) : (
81
- <Trash2 className="size-4" />
142
+ 'Delete'
82
143
  )}
83
- </Button>
84
- </AlertDialogTrigger>
85
- <AlertDialogContent>
86
- <AlertDialogHeader>
87
- <AlertDialogTitle>Delete feature?</AlertDialogTitle>
88
- <AlertDialogDescription>
89
- This will permanently delete <strong>{featureName}</strong> ({featureId}).
90
- This action cannot be undone.
91
- </AlertDialogDescription>
92
- </AlertDialogHeader>
93
- <AlertDialogFooter>
94
- <AlertDialogCancel disabled={isDeleting}>Cancel</AlertDialogCancel>
95
- <AlertDialogAction
96
- variant="destructive"
97
- disabled={isDeleting}
98
- onClick={() => onDelete(featureId)}
99
- >
100
- {isDeleting ? (
101
- <>
102
- <Loader2 className="mr-2 h-4 w-4 animate-spin" />
103
- Deleting…
104
- </>
105
- ) : (
106
- 'Delete'
107
- )}
108
- </AlertDialogAction>
109
- </AlertDialogFooter>
110
- </AlertDialogContent>
111
- </AlertDialog>
112
- </>
144
+ </AlertDialogAction>
145
+ </AlertDialogFooter>
146
+ </AlertDialogContent>
147
+ </AlertDialog>
113
148
  ) : null}
114
149
  </div>
115
150
  ) : null}