@shepai/cli 1.70.2 → 1.71.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 (306) hide show
  1. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts +32 -0
  2. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts +16 -2
  4. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
  5. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +46 -9
  6. package/dist/packages/core/src/infrastructure/services/deployment/log-ring-buffer.d.ts +23 -0
  7. package/dist/packages/core/src/infrastructure/services/deployment/log-ring-buffer.d.ts.map +1 -0
  8. package/dist/packages/core/src/infrastructure/services/deployment/log-ring-buffer.js +46 -0
  9. package/dist/src/presentation/web/app/actions/get-deployment-logs.d.ts +3 -0
  10. package/dist/src/presentation/web/app/actions/get-deployment-logs.d.ts.map +1 -0
  11. package/dist/src/presentation/web/app/actions/get-deployment-logs.js +9 -0
  12. package/dist/src/presentation/web/app/actions/get-feature-artifact.d.ts +2 -0
  13. package/dist/src/presentation/web/app/actions/get-feature-artifact.d.ts.map +1 -1
  14. package/dist/src/presentation/web/app/actions/get-feature-artifact.js +23 -1
  15. package/dist/src/presentation/web/app/api/deployment-logs/route.d.ts +15 -0
  16. package/dist/src/presentation/web/app/api/deployment-logs/route.d.ts.map +1 -0
  17. package/dist/src/presentation/web/app/api/deployment-logs/route.js +94 -0
  18. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.js +1 -1
  19. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js +33 -3
  21. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.d.ts +2 -1
  22. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.d.ts.map +1 -1
  23. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.js +16 -5
  24. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.d.ts +4 -0
  25. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.js +8 -0
  27. package/dist/src/presentation/web/components/common/product-decisions-summary/index.d.ts +3 -0
  28. package/dist/src/presentation/web/components/common/product-decisions-summary/index.d.ts.map +1 -0
  29. package/dist/src/presentation/web/components/common/product-decisions-summary/index.js +1 -0
  30. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.d.ts +23 -0
  31. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.d.ts.map +1 -0
  32. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.js +1 -0
  33. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.d.ts +3 -0
  34. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.d.ts.map +1 -0
  35. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.js +13 -0
  36. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.d.ts +14 -0
  37. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.d.ts.map +1 -0
  38. package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.js +74 -0
  39. package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
  40. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
  41. package/dist/src/presentation/web/components/common/server-log-viewer/index.d.ts +2 -0
  42. package/dist/src/presentation/web/components/common/server-log-viewer/index.d.ts.map +1 -0
  43. package/dist/src/presentation/web/components/common/server-log-viewer/index.js +1 -0
  44. package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.d.ts +15 -0
  45. package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.d.ts.map +1 -0
  46. package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.js +31 -0
  47. package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.d.ts +18 -0
  48. package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.d.ts.map +1 -0
  49. package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.js +113 -0
  50. package/dist/src/presentation/web/components/common/tech-decisions-review/index.d.ts +1 -1
  51. package/dist/src/presentation/web/components/common/tech-decisions-review/index.d.ts.map +1 -1
  52. package/dist/src/presentation/web/components/common/tech-decisions-review/index.js +1 -1
  53. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts +8 -1
  54. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts.map +1 -1
  55. package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js +11 -2
  56. package/dist/src/presentation/web/components/common/tech-review-tabs/index.d.ts +3 -0
  57. package/dist/src/presentation/web/components/common/tech-review-tabs/index.d.ts.map +1 -0
  58. package/dist/src/presentation/web/components/common/tech-review-tabs/index.js +1 -0
  59. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.d.ts +17 -0
  60. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.d.ts.map +1 -0
  61. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.js +1 -0
  62. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.d.ts +3 -0
  63. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.d.ts.map +1 -0
  64. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.js +12 -0
  65. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.d.ts +16 -0
  66. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.d.ts.map +1 -0
  67. package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.js +110 -0
  68. package/dist/src/presentation/web/hooks/use-deployment-logs.d.ts +7 -0
  69. package/dist/src/presentation/web/hooks/use-deployment-logs.d.ts.map +1 -0
  70. package/dist/src/presentation/web/hooks/use-deployment-logs.js +50 -0
  71. package/dist/tsconfig.build.tsbuildinfo +1 -1
  72. package/package.json +1 -1
  73. package/web/.next/BUILD_ID +1 -1
  74. package/web/.next/app-path-routes-manifest.json +1 -0
  75. package/web/.next/build-manifest.json +2 -2
  76. package/web/.next/cache/.previewinfo +1 -1
  77. package/web/.next/cache/.rscinfo +1 -1
  78. package/web/.next/cache/.tsbuildinfo +1 -1
  79. package/web/.next/cache/config.json +3 -3
  80. package/web/.next/fallback-build-manifest.json +2 -2
  81. package/web/.next/prerender-manifest.json +3 -3
  82. package/web/.next/required-server-files.js +1 -1
  83. package/web/.next/required-server-files.json +1 -1
  84. package/web/.next/routes-manifest.json +6 -0
  85. package/web/.next/server/app/_global-error.html +2 -2
  86. package/web/.next/server/app/_global-error.rsc +1 -1
  87. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  88. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  89. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  90. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  91. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  92. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  93. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  94. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  95. package/web/.next/server/app/api/deployment-logs/route/app-paths-manifest.json +3 -0
  96. package/web/.next/server/app/api/deployment-logs/route/build-manifest.json +11 -0
  97. package/web/.next/server/app/api/deployment-logs/route/server-reference-manifest.json +4 -0
  98. package/web/.next/server/app/api/deployment-logs/route.js +6 -0
  99. package/web/.next/server/app/api/deployment-logs/route.js.map +5 -0
  100. package/web/.next/server/app/api/deployment-logs/route.js.nft.json +1 -0
  101. package/web/.next/server/app/api/deployment-logs/route_client-reference-manifest.js +2 -0
  102. package/web/.next/server/app/api/tools/[id]/install/route.js +1 -1
  103. package/web/.next/server/app/api/tools/[id]/install/route.js.nft.json +1 -1
  104. package/web/.next/server/app/page/server-reference-manifest.json +51 -36
  105. package/web/.next/server/app/page.js +1 -1
  106. package/web/.next/server/app/page.js.nft.json +1 -1
  107. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  108. package/web/.next/server/app/skills/page/server-reference-manifest.json +25 -10
  109. package/web/.next/server/app/skills/page.js +1 -1
  110. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  111. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  112. package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  113. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  114. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  115. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  116. package/web/.next/server/app/version/page.js +1 -1
  117. package/web/.next/server/app/version/page.js.nft.json +1 -1
  118. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  119. package/web/.next/server/app-paths-manifest.json +1 -0
  120. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_deployment-logs_route_actions_b785cd3a.js +3 -0
  121. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_deployment-logs_route_actions_b785cd3a.js.map +1 -0
  122. package/web/.next/server/chunks/[root-of-the-server]__9a136c79._.js +9 -0
  123. package/web/.next/server/chunks/[root-of-the-server]__9a136c79._.js.map +1 -0
  124. package/web/.next/server/chunks/{[root-of-the-server]__09413611._.js → [root-of-the-server]__e926de65._.js} +2 -2
  125. package/web/.next/server/chunks/{[root-of-the-server]__09413611._.js.map → [root-of-the-server]__e926de65._.js.map} +1 -1
  126. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/[root-of-the-server]__5f968713._.js +3 -0
  129. package/web/.next/server/chunks/ssr/[root-of-the-server]__5f968713._.js.map +1 -0
  130. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  131. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/{[root-of-the-server]__249c74f6._.js → [root-of-the-server]__6e8b5181._.js} +2 -2
  133. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  134. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  135. package/web/.next/server/chunks/ssr/[root-of-the-server]__970ba1be._.js +3 -0
  136. package/web/.next/server/chunks/ssr/[root-of-the-server]__970ba1be._.js.map +1 -0
  137. package/web/.next/server/chunks/ssr/[root-of-the-server]__97a1f9c2._.js +4 -0
  138. package/web/.next/server/chunks/ssr/[root-of-the-server]__97a1f9c2._.js.map +1 -0
  139. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
  140. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
  141. package/web/.next/server/chunks/ssr/[root-of-the-server]__ad7c18fa._.js +9 -0
  142. package/web/.next/server/chunks/ssr/[root-of-the-server]__ad7c18fa._.js.map +1 -0
  143. package/web/.next/server/chunks/ssr/[root-of-the-server]__b22d8535._.js +3 -0
  144. package/web/.next/server/chunks/ssr/[root-of-the-server]__b22d8535._.js.map +1 -0
  145. package/web/.next/server/chunks/ssr/_25e0eb34._.js +3 -0
  146. package/web/.next/server/chunks/ssr/_25e0eb34._.js.map +1 -0
  147. package/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
  148. package/web/.next/server/chunks/ssr/_49bf495c._.js.map +1 -1
  149. package/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
  150. package/web/.next/server/chunks/ssr/_68b5e0de._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
  152. package/web/.next/server/chunks/ssr/_725584e5._.js.map +1 -1
  153. package/web/.next/server/chunks/ssr/_72ce07df._.js +3 -0
  154. package/web/.next/server/chunks/ssr/_72ce07df._.js.map +1 -0
  155. package/web/.next/server/chunks/ssr/{node_modules__pnpm_febcbea6._.js → node_modules__pnpm_3288606c._.js} +2 -2
  156. package/web/.next/server/chunks/ssr/{node_modules__pnpm_febcbea6._.js.map → node_modules__pnpm_3288606c._.js.map} +1 -1
  157. package/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js +3 -0
  158. package/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js.map +1 -0
  159. package/web/.next/server/chunks/ssr/src_presentation_web_components_ui_tabs_tsx_b226ea9b._.js +3 -0
  160. package/web/.next/server/chunks/ssr/src_presentation_web_components_ui_tabs_tsx_b226ea9b._.js.map +1 -0
  161. package/web/.next/server/pages/500.html +2 -2
  162. package/web/.next/server/server-reference-manifest.js +1 -1
  163. package/web/.next/server/server-reference-manifest.json +64 -42
  164. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  165. package/web/.next/standalone/src/presentation/web/.next/app-path-routes-manifest.json +1 -0
  166. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  167. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  168. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  169. package/web/.next/standalone/src/presentation/web/.next/routes-manifest.json +6 -0
  170. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  171. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  172. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  173. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  174. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  175. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  176. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  177. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  178. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  179. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  180. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route/app-paths-manifest.json +3 -0
  181. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route/build-manifest.json +11 -0
  182. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route/server-reference-manifest.json +4 -0
  183. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route.js +6 -0
  184. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route.js.map +5 -0
  185. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route.js.nft.json +1 -0
  186. package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route_client-reference-manifest.js +2 -0
  187. package/web/.next/standalone/src/presentation/web/.next/server/app/api/tools/[id]/install/route.js +1 -1
  188. package/web/.next/standalone/src/presentation/web/.next/server/app/api/tools/[id]/install/route.js.nft.json +1 -1
  189. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +51 -36
  190. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +1 -1
  191. package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
  192. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +25 -10
  194. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js +1 -1
  195. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
  196. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  197. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  198. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
  199. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  200. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  201. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js +1 -1
  202. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
  203. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  204. package/web/.next/standalone/src/presentation/web/.next/server/app-paths-manifest.json +1 -0
  205. package/web/.next/standalone/src/presentation/web/.next/server/chunks/744ca_web__next-internal_server_app_api_deployment-logs_route_actions_b785cd3a.js +3 -0
  206. package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__9a136c79._.js +9 -0
  207. package/web/.next/standalone/src/presentation/web/.next/server/chunks/{[root-of-the-server]__09413611._.js → [root-of-the-server]__e926de65._.js} +2 -2
  208. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  209. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__5f968713._.js +3 -0
  210. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  211. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{[root-of-the-server]__249c74f6._.js → [root-of-the-server]__6e8b5181._.js} +2 -2
  212. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  213. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__970ba1be._.js +3 -0
  214. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__97a1f9c2._.js +4 -0
  215. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
  216. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__ad7c18fa._.js +9 -0
  217. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__b22d8535._.js +3 -0
  218. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_25e0eb34._.js +3 -0
  219. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
  220. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
  221. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
  222. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_72ce07df._.js +3 -0
  223. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{node_modules__pnpm_febcbea6._.js → node_modules__pnpm_3288606c._.js} +2 -2
  224. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js +3 -0
  225. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_ui_tabs_tsx_b226ea9b._.js +3 -0
  226. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  227. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  228. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +64 -42
  229. package/web/.next/standalone/src/presentation/web/app/actions/get-deployment-logs.ts +16 -0
  230. package/web/.next/standalone/src/presentation/web/app/actions/get-feature-artifact.ts +26 -1
  231. package/web/.next/standalone/src/presentation/web/app/api/deployment-logs/route.ts +112 -0
  232. package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.tsx +5 -1
  233. package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx +42 -4
  234. package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.tsx +10 -0
  235. package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.tsx +76 -23
  236. package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/index.ts +6 -0
  237. package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.ts +24 -0
  238. package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.tsx +87 -0
  239. package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.tsx +52 -0
  240. package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +5 -1
  241. package/web/.next/standalone/src/presentation/web/components/common/server-log-viewer/index.ts +6 -0
  242. package/web/.next/standalone/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.tsx +168 -0
  243. package/web/.next/standalone/src/presentation/web/components/common/server-log-viewer/server-log-viewer.tsx +110 -0
  244. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/index.ts +1 -1
  245. package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx +46 -28
  246. package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/index.ts +2 -0
  247. package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.ts +17 -0
  248. package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.tsx +129 -0
  249. package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.tsx +60 -0
  250. package/web/.next/standalone/src/presentation/web/hooks/use-deployment-logs.ts +67 -0
  251. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  252. package/web/.next/static/chunks/01ae2241bd4b44b6.js +1 -0
  253. package/web/.next/static/chunks/20f7876f292cfd82.js +1 -0
  254. package/web/.next/static/chunks/224ed5f5dbd33154.css +2 -0
  255. package/web/.next/static/chunks/{87421ab1062a39b7.js → 3e1227e02ef8bcc6.js} +2 -2
  256. package/web/.next/static/chunks/{2eae41f87676d999.js → 62c8ebbd9c7bb287.js} +1 -1
  257. package/web/.next/static/chunks/673e0c1000a91948.js +1 -0
  258. package/web/.next/static/chunks/8b6df4f8e194d0ce.js +1 -0
  259. package/web/.next/static/chunks/b025563d959150a1.js +1 -0
  260. package/web/.next/static/chunks/{09e70c24eceecf48.js → c7fb052190a02a9c.js} +2 -2
  261. package/web/.next/static/chunks/d450d8db6be36b8d.js +1 -0
  262. package/web/.next/static/chunks/d9e3cf214ac2f386.js +1 -0
  263. package/web/.next/trace +1 -1
  264. package/web/.next/trace-build +1 -1
  265. package/web/.next/types/link.d.ts +1 -0
  266. package/web/.next/types/routes.d.ts +2 -1
  267. package/web/.next/types/validator.ts +9 -0
  268. package/web/.next/server/chunks/ssr/6769f_@radix-ui_react-roving-focus_dist_index_mjs_b3be3d8e._.js +0 -3
  269. package/web/.next/server/chunks/ssr/6769f_@radix-ui_react-roving-focus_dist_index_mjs_b3be3d8e._.js.map +0 -1
  270. package/web/.next/server/chunks/ssr/[root-of-the-server]__2ffb27f1._.js +0 -3
  271. package/web/.next/server/chunks/ssr/[root-of-the-server]__2ffb27f1._.js.map +0 -1
  272. package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +0 -4
  273. package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js.map +0 -1
  274. package/web/.next/server/chunks/ssr/[root-of-the-server]__7f4180a1._.js +0 -3
  275. package/web/.next/server/chunks/ssr/[root-of-the-server]__7f4180a1._.js.map +0 -1
  276. package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +0 -9
  277. package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js.map +0 -1
  278. package/web/.next/server/chunks/ssr/[root-of-the-server]__eaf6100f._.js +0 -3
  279. package/web/.next/server/chunks/ssr/[root-of-the-server]__eaf6100f._.js.map +0 -1
  280. package/web/.next/server/chunks/ssr/_28993370._.js +0 -3
  281. package/web/.next/server/chunks/ssr/_28993370._.js.map +0 -1
  282. package/web/.next/server/chunks/ssr/_690ea95f._.js +0 -3
  283. package/web/.next/server/chunks/ssr/_690ea95f._.js.map +0 -1
  284. package/web/.next/server/chunks/ssr/src_presentation_web_components_0286756b._.js +0 -3
  285. package/web/.next/server/chunks/ssr/src_presentation_web_components_0286756b._.js.map +0 -1
  286. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/6769f_@radix-ui_react-roving-focus_dist_index_mjs_b3be3d8e._.js +0 -3
  287. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2ffb27f1._.js +0 -3
  288. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +0 -4
  289. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__7f4180a1._.js +0 -3
  290. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +0 -9
  291. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__eaf6100f._.js +0 -3
  292. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_28993370._.js +0 -3
  293. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_690ea95f._.js +0 -3
  294. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_0286756b._.js +0 -3
  295. package/web/.next/static/chunks/4b357783626e0916.js +0 -1
  296. package/web/.next/static/chunks/505c6a9e4c5d0808.js +0 -1
  297. package/web/.next/static/chunks/a186bbb822ccb655.css +0 -2
  298. package/web/.next/static/chunks/a5c59952485e875e.js +0 -1
  299. package/web/.next/static/chunks/a9626385607910b3.js +0 -1
  300. package/web/.next/static/chunks/b581320ecaa97e4a.js +0 -1
  301. package/web/.next/static/chunks/d4379644a6145352.js +0 -1
  302. package/web/.next/static/chunks/fb703cf73aba2eb8.js +0 -1
  303. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__249c74f6._.js.map → [root-of-the-server]__6e8b5181._.js.map} +0 -0
  304. /package/web/.next/static/{MoPU_ZZ5QcyEys7Gfl_6r → F3mdpVVEgR5m2xHY_SnYx}/_buildManifest.js +0 -0
  305. /package/web/.next/static/{MoPU_ZZ5QcyEys7Gfl_6r → F3mdpVVEgR5m2xHY_SnYx}/_clientMiddlewareManifest.json +0 -0
  306. /package/web/.next/static/{MoPU_ZZ5QcyEys7Gfl_6r → F3mdpVVEgR5m2xHY_SnYx}/_ssgManifest.js +0 -0
@@ -156,7 +156,11 @@ function DeployBar({ deployTarget }: { deployTarget: DeployActionInput }) {
156
156
  </Tooltip>
157
157
  </TooltipProvider>
158
158
  {isDeploymentActive ? (
159
- <DeploymentStatusBadge status={deployAction.status} url={deployAction.url} />
159
+ <DeploymentStatusBadge
160
+ status={deployAction.status}
161
+ url={deployAction.url}
162
+ targetId={deployTarget.targetId}
163
+ />
160
164
  ) : null}
161
165
  </div>
162
166
  );
@@ -51,7 +51,8 @@ import { ActionButton } from '@/components/common/action-button';
51
51
  import { OpenActionMenu } from '@/components/common/open-action-menu';
52
52
  import { FeatureCreateDrawer } from '@/components/common/feature-create-drawer';
53
53
  import { PrdQuestionnaire } from '@/components/common/prd-questionnaire';
54
- import { TechDecisionsReview } from '@/components/common/tech-decisions-review';
54
+ import { TechReviewTabs } from '@/components/common/tech-review-tabs';
55
+ import type { ProductDecisionsSummaryData } from '@/components/common/product-decisions-summary';
55
56
  import { MergeReview } from '@/components/common/merge-review';
56
57
  import { featureNodeStateConfig, lifecycleDisplayLabels } from '@/components/common/feature-node';
57
58
  import type { FeatureNodeData } from '@/components/common/feature-node';
@@ -89,6 +90,12 @@ export function ControlCenterDrawer({
89
90
  const [techData, setTechData] = useState<TechDecisionsReviewData | null>(null);
90
91
  const [isLoadingTech, setIsLoadingTech] = useState(false);
91
92
 
93
+ // ── Product decisions state (for tech review Product tab) ─────────────
94
+ const [techProductData, setTechProductData] = useState<
95
+ ProductDecisionsSummaryData | null | undefined
96
+ >(undefined);
97
+ const [isLoadingTechProduct, setIsLoadingTechProduct] = useState(false);
98
+
92
99
  // ── Merge review state ──────────────────────────────────────────────────
93
100
  const [mergeData, setMergeData] = useState<MergeReviewData | null>(null);
94
101
  const [isLoadingMerge, setIsLoadingMerge] = useState(false);
@@ -162,6 +169,32 @@ export function ControlCenterDrawer({
162
169
  };
163
170
  }, [techFeatureId]);
164
171
 
172
+ // Fetch product decisions for the Product tab in tech review
173
+ useEffect(() => {
174
+ setTechProductData(undefined);
175
+ if (!techFeatureId) return;
176
+
177
+ let cancelled = false;
178
+ setIsLoadingTechProduct(true);
179
+ getFeatureArtifact(techFeatureId)
180
+ .then((result) => {
181
+ if (cancelled) return;
182
+ if (result.productDecisions) {
183
+ setTechProductData(result.productDecisions);
184
+ }
185
+ // Silent failure — product tab shows "not available"
186
+ })
187
+ .catch(() => {
188
+ // Silent failure — the product tab is supplementary
189
+ })
190
+ .finally(() => {
191
+ if (!cancelled) setIsLoadingTechProduct(false);
192
+ });
193
+ return () => {
194
+ cancelled = true;
195
+ };
196
+ }, [techFeatureId]);
197
+
165
198
  const mergeFeatureId = view?.type === 'merge-review' ? view.node.featureId : null;
166
199
  useEffect(() => {
167
200
  setMergeData(null);
@@ -381,7 +414,11 @@ export function ControlCenterDrawer({
381
414
  </Tooltip>
382
415
  </TooltipProvider>
383
416
  {isFeatureDeployActive ? (
384
- <DeploymentStatusBadge status={deployAction.status} url={deployAction.url} />
417
+ <DeploymentStatusBadge
418
+ status={deployAction.status}
419
+ url={deployAction.url}
420
+ targetId={featureDeployTarget?.targetId}
421
+ />
385
422
  ) : null}
386
423
  </>
387
424
  ) : null}
@@ -508,8 +545,9 @@ export function ControlCenterDrawer({
508
545
  );
509
546
  } else if (view?.type === 'tech-review') {
510
547
  body = techData ? (
511
- <TechDecisionsReview
512
- data={techData}
548
+ <TechReviewTabs
549
+ techData={techData}
550
+ productData={isLoadingTechProduct ? null : techProductData}
513
551
  onApprove={handleTechApprove}
514
552
  onReject={handleTechReject}
515
553
  isProcessing={isLoadingTech}
@@ -33,3 +33,13 @@ export const Stopped: Story = {
33
33
  export const NoDeployment: Story = {
34
34
  args: { status: null },
35
35
  };
36
+
37
+ /** Booting with View Logs button — shows log button next to spinner. */
38
+ export const BootingWithLogs: Story = {
39
+ args: { status: DeploymentState.Booting, targetId: 'demo-target' },
40
+ };
41
+
42
+ /** Ready with View Logs button — shows URL and log button. */
43
+ export const ReadyWithLogs: Story = {
44
+ args: { status: DeploymentState.Ready, url: 'http://localhost:3000', targetId: 'demo-target' },
45
+ };
@@ -1,40 +1,93 @@
1
- import { Loader2, ExternalLink } from 'lucide-react';
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Loader2, ExternalLink, Terminal } from 'lucide-react';
2
5
  import { DeploymentState } from '@shepai/core/domain/generated/output';
3
6
  import { Badge } from '@/components/ui/badge';
7
+ import { ServerLogViewer } from '@/components/common/server-log-viewer';
4
8
 
5
9
  export interface DeploymentStatusBadgeProps {
6
10
  status: DeploymentState | null;
7
11
  url?: string | null;
12
+ targetId?: string;
8
13
  }
9
14
 
10
- export function DeploymentStatusBadge({ status, url }: DeploymentStatusBadgeProps) {
15
+ export function DeploymentStatusBadge({ status, url, targetId }: DeploymentStatusBadgeProps) {
16
+ const [logViewerOpen, setLogViewerOpen] = useState(false);
17
+ const showLogButton =
18
+ targetId && (status === DeploymentState.Booting || status === DeploymentState.Ready);
19
+
11
20
  switch (status) {
12
21
  case DeploymentState.Booting:
13
22
  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>
23
+ <>
24
+ <Badge className="border-transparent bg-blue-50 text-blue-700 hover:bg-blue-50">
25
+ <Loader2 className="mr-1 h-3.5 w-3.5 animate-spin" />
26
+ Starting...
27
+ {showLogButton ? (
28
+ <button
29
+ type="button"
30
+ aria-label="View server logs"
31
+ className="ml-1.5 inline-flex items-center rounded-sm p-0.5 hover:bg-blue-100"
32
+ onClick={(e) => {
33
+ e.stopPropagation();
34
+ setLogViewerOpen(true);
35
+ }}
36
+ >
37
+ <Terminal className="h-3 w-3" />
38
+ </button>
39
+ ) : null}
40
+ </Badge>
41
+ {showLogButton ? (
42
+ <ServerLogViewer
43
+ open={logViewerOpen}
44
+ onOpenChange={setLogViewerOpen}
45
+ targetId={targetId}
46
+ />
47
+ ) : null}
48
+ </>
18
49
  );
19
50
  case DeploymentState.Ready:
20
51
  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>
52
+ <>
53
+ <Badge className="border-transparent bg-green-50 text-green-700 hover:bg-green-50">
54
+ <span className="mr-1 inline-block h-2 w-2 rounded-full bg-green-500" />
55
+ {url ? (
56
+ <a
57
+ href={url}
58
+ target="_blank"
59
+ rel="noopener noreferrer"
60
+ className="inline-flex items-center gap-1 hover:underline"
61
+ onClick={(e) => e.stopPropagation()}
62
+ >
63
+ {url}
64
+ <ExternalLink className="h-3 w-3" />
65
+ </a>
66
+ ) : (
67
+ 'Ready'
68
+ )}
69
+ {showLogButton ? (
70
+ <button
71
+ type="button"
72
+ aria-label="View server logs"
73
+ className="ml-1.5 inline-flex items-center rounded-sm p-0.5 hover:bg-green-100"
74
+ onClick={(e) => {
75
+ e.stopPropagation();
76
+ setLogViewerOpen(true);
77
+ }}
78
+ >
79
+ <Terminal className="h-3 w-3" />
80
+ </button>
81
+ ) : null}
82
+ </Badge>
83
+ {showLogButton ? (
84
+ <ServerLogViewer
85
+ open={logViewerOpen}
86
+ onOpenChange={setLogViewerOpen}
87
+ targetId={targetId}
88
+ />
89
+ ) : null}
90
+ </>
38
91
  );
39
92
  default:
40
93
  return null;
@@ -0,0 +1,6 @@
1
+ export { ProductDecisionsSummary } from './product-decisions-summary';
2
+ export type {
3
+ ProductDecisionsSummaryData,
4
+ ProductDecisionItem,
5
+ ProductDecisionsSummaryProps,
6
+ } from './product-decisions-summary-config';
@@ -0,0 +1,24 @@
1
+ export interface ProductDecisionItem {
2
+ /** Question text */
3
+ question: string;
4
+ /** The selected option label */
5
+ selectedOption: string;
6
+ /** Rationale for the selected option */
7
+ rationale: string;
8
+ /** Whether it was the AI-recommended option */
9
+ wasRecommended: boolean;
10
+ }
11
+
12
+ export interface ProductDecisionsSummaryData {
13
+ /** Goal/title from the PRD */
14
+ question: string;
15
+ /** Context description (one-liner) */
16
+ context: string;
17
+ /** Resolved questions with selected options */
18
+ questions: ProductDecisionItem[];
19
+ }
20
+
21
+ export interface ProductDecisionsSummaryProps {
22
+ /** Product decisions data from the feature artifact */
23
+ data: ProductDecisionsSummaryData;
24
+ }
@@ -0,0 +1,87 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { ProductDecisionsSummary } from './product-decisions-summary';
3
+ import type { ProductDecisionsSummaryData } from './product-decisions-summary-config';
4
+
5
+ const mockData: ProductDecisionsSummaryData = {
6
+ question: 'Goal',
7
+ context: 'Add user authentication to the application',
8
+ questions: [
9
+ {
10
+ question: 'Which authentication strategy should we use?',
11
+ selectedOption: 'OAuth 2.0',
12
+ rationale: 'Industry standard with broad provider support and well-maintained libraries.',
13
+ wasRecommended: true,
14
+ },
15
+ {
16
+ question: 'How should we handle session management?',
17
+ selectedOption: 'JWT tokens',
18
+ rationale: 'Stateless and scalable across services without shared session storage.',
19
+ wasRecommended: false,
20
+ },
21
+ {
22
+ question: 'What level of MFA should we support?',
23
+ selectedOption: 'Optional TOTP',
24
+ rationale: 'Balances security with user convenience. Power users can opt in.',
25
+ wasRecommended: true,
26
+ },
27
+ {
28
+ question: 'Where should we store user profiles?',
29
+ selectedOption: 'PostgreSQL',
30
+ rationale: 'Relational data model fits well for user attributes and relationships.',
31
+ wasRecommended: false,
32
+ },
33
+ ],
34
+ };
35
+
36
+ const meta: Meta<typeof ProductDecisionsSummary> = {
37
+ title: 'Drawers/Review/ProductDecisionsSummary',
38
+ component: ProductDecisionsSummary,
39
+ tags: ['autodocs'],
40
+ parameters: {
41
+ layout: 'fullscreen',
42
+ },
43
+ decorators: [
44
+ (Story) => (
45
+ <div style={{ height: '600px', width: '400px', border: '1px solid var(--color-border)' }}>
46
+ <Story />
47
+ </div>
48
+ ),
49
+ ],
50
+ };
51
+
52
+ export default meta;
53
+ type Story = StoryObj<typeof ProductDecisionsSummary>;
54
+
55
+ /** Default — multiple product decisions with a mix of recommended and non-recommended. */
56
+ export const Default: Story = {
57
+ args: {
58
+ data: mockData,
59
+ },
60
+ };
61
+
62
+ /** Single question. */
63
+ export const SingleQuestion: Story = {
64
+ args: {
65
+ data: { ...mockData, questions: [mockData.questions[0]] },
66
+ },
67
+ };
68
+
69
+ /** All recommended — every option was the AI-recommended choice. */
70
+ export const AllRecommended: Story = {
71
+ args: {
72
+ data: {
73
+ ...mockData,
74
+ questions: mockData.questions.map((q) => ({ ...q, wasRecommended: true })),
75
+ },
76
+ },
77
+ };
78
+
79
+ /** No recommended badges — none of the selected options were AI-recommended. */
80
+ export const NoneRecommended: Story = {
81
+ args: {
82
+ data: {
83
+ ...mockData,
84
+ questions: mockData.questions.map((q) => ({ ...q, wasRecommended: false })),
85
+ },
86
+ },
87
+ };
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import { ClipboardList } from 'lucide-react';
4
+ import { Badge } from '@/components/ui/badge';
5
+ import type {
6
+ ProductDecisionsSummaryProps,
7
+ ProductDecisionItem,
8
+ } from './product-decisions-summary-config';
9
+
10
+ function ProductDecisionCard({ item, index }: { item: ProductDecisionItem; index: number }) {
11
+ return (
12
+ <div className="border-border rounded-lg border">
13
+ <div className="space-y-2 px-4 py-3">
14
+ <div className="flex items-start gap-2.5">
15
+ <span className="bg-primary text-primary-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold">
16
+ {index + 1}
17
+ </span>
18
+ <div className="min-w-0 flex-1">
19
+ <h3 className="text-foreground text-sm leading-tight font-semibold">{item.question}</h3>
20
+ <div className="mt-1 flex items-center gap-2">
21
+ <p className="text-muted-foreground text-xs">{item.selectedOption}</p>
22
+ {item.wasRecommended ? (
23
+ <Badge className="px-1.5 py-0 text-[10px]">AI Recommended</Badge>
24
+ ) : null}
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ );
31
+ }
32
+
33
+ export function ProductDecisionsSummary({ data }: ProductDecisionsSummaryProps) {
34
+ const { questions } = data;
35
+
36
+ if (questions.length === 0) return null;
37
+
38
+ return (
39
+ <div className="space-y-4 p-4">
40
+ {/* Section heading */}
41
+ <div className="flex items-center gap-2">
42
+ <ClipboardList className="text-primary h-4 w-4" />
43
+ <h3 className="text-foreground text-sm font-bold">Product Decisions</h3>
44
+ </div>
45
+
46
+ {/* Decision cards */}
47
+ {questions.map((item, i) => (
48
+ <ProductDecisionCard key={item.question} item={item} index={i} />
49
+ ))}
50
+ </div>
51
+ );
52
+ }
@@ -206,7 +206,11 @@ export function RepositoryNode({ data }: { data: RepositoryNodeData; [key: strin
206
206
  </Tooltip>
207
207
  </TooltipProvider>
208
208
  {isDeploymentActive ? (
209
- <DeploymentStatusBadge status={deployAction.status} url={deployAction.url} />
209
+ <DeploymentStatusBadge
210
+ status={deployAction.status}
211
+ url={deployAction.url}
212
+ targetId={data.repositoryPath}
213
+ />
210
214
  ) : null}
211
215
  </>
212
216
  ) : null}
@@ -0,0 +1,6 @@
1
+ export {
2
+ ServerLogViewer,
3
+ ServerLogViewerContent,
4
+ type ServerLogViewerProps,
5
+ type ServerLogViewerContentProps,
6
+ } from './server-log-viewer';
@@ -0,0 +1,168 @@
1
+ import { useState } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import type { LogEntry } from '@shepai/core/application/ports/output/services/deployment-service.interface';
4
+ import { ServerLogViewerContent } from './server-log-viewer';
5
+
6
+ const meta: Meta<typeof ServerLogViewerContent> = {
7
+ title: 'Common/ServerLogViewer',
8
+ component: ServerLogViewerContent,
9
+ tags: ['autodocs'],
10
+ parameters: {
11
+ layout: 'fullscreen',
12
+ },
13
+ };
14
+
15
+ export default meta;
16
+ type Story = StoryObj<typeof ServerLogViewerContent>;
17
+
18
+ function makeLog(line: string, stream: 'stdout' | 'stderr' = 'stdout', offsetMs = 0): LogEntry {
19
+ return {
20
+ targetId: 'story-target',
21
+ stream,
22
+ line,
23
+ timestamp: Date.now() + offsetMs,
24
+ };
25
+ }
26
+
27
+ function InteractiveWrapper({ logs, isConnected }: { logs: LogEntry[]; isConnected: boolean }) {
28
+ const [open, setOpen] = useState(true);
29
+ return (
30
+ <ServerLogViewerContent
31
+ open={open}
32
+ onOpenChange={setOpen}
33
+ logs={logs}
34
+ isConnected={isConnected}
35
+ />
36
+ );
37
+ }
38
+
39
+ /** Empty state — no log output yet. */
40
+ export const Empty: Story = {
41
+ render: () => <InteractiveWrapper logs={[]} isConnected={true} />,
42
+ };
43
+
44
+ /** A few stdout-only lines. */
45
+ export const FewLines: Story = {
46
+ render: () => (
47
+ <InteractiveWrapper
48
+ logs={[
49
+ makeLog('$ npm run dev', 'stdout', 0),
50
+ makeLog('', 'stdout', 10),
51
+ makeLog('> my-app@1.0.0 dev', 'stdout', 20),
52
+ makeLog('> next dev', 'stdout', 30),
53
+ makeLog('', 'stdout', 40),
54
+ makeLog(' ▲ Next.js 14.2.3', 'stdout', 50),
55
+ makeLog(' - Local: http://localhost:3000', 'stdout', 60),
56
+ makeLog(' - Environments: .env.local', 'stdout', 70),
57
+ makeLog('', 'stdout', 80),
58
+ makeLog(' ✓ Ready in 1.2s', 'stdout', 90),
59
+ ]}
60
+ isConnected={true}
61
+ />
62
+ ),
63
+ };
64
+
65
+ /** Interleaved stdout and stderr showing color differentiation. */
66
+ export const MixedOutput: Story = {
67
+ render: () => (
68
+ <InteractiveWrapper
69
+ logs={[
70
+ makeLog('$ npm run dev', 'stdout', 0),
71
+ makeLog('> next dev', 'stdout', 10),
72
+ makeLog(' ▲ Next.js 14.2.3', 'stdout', 20),
73
+ makeLog(
74
+ '(node:12345) [DEP0040] DeprecationWarning: The punycode module is deprecated.',
75
+ 'stderr',
76
+ 30
77
+ ),
78
+ makeLog('Use `node:punycode` instead.', 'stderr', 31),
79
+ makeLog(' - Local: http://localhost:3000', 'stdout', 40),
80
+ makeLog(' ✓ Ready in 1.8s', 'stdout', 50),
81
+ makeLog(' ○ Compiling /page ...', 'stdout', 100),
82
+ makeLog(' ✓ Compiled /page in 342ms', 'stdout', 200),
83
+ makeLog('GET / 200 in 412ms', 'stdout', 300),
84
+ makeLog('Warning: Each child in a list should have a unique "key" prop.', 'stderr', 310),
85
+ makeLog('GET /api/data 200 in 23ms', 'stdout', 400),
86
+ makeLog('GET /favicon.ico 304 in 2ms', 'stdout', 410),
87
+ makeLog("Error: ENOENT: no such file or directory, open '/tmp/cache.json'", 'stderr', 500),
88
+ makeLog('GET /api/users 500 in 156ms', 'stdout', 510),
89
+ ]}
90
+ isConnected={true}
91
+ />
92
+ ),
93
+ };
94
+
95
+ /** 100+ lines demonstrating scrollable content. */
96
+ export const ManyLines: Story = {
97
+ render: () => {
98
+ const logs: LogEntry[] = [];
99
+ logs.push(makeLog('$ npm run dev', 'stdout', 0));
100
+ logs.push(makeLog('> next dev', 'stdout', 10));
101
+ logs.push(makeLog(' ✓ Ready in 1.2s', 'stdout', 20));
102
+ for (let i = 0; i < 120; i++) {
103
+ const method = ['GET', 'POST', 'PUT', 'DELETE'][i % 4];
104
+ const path = ['/api/users', '/api/features', '/api/repos', '/api/deploy'][i % 4];
105
+ const status = i % 15 === 0 ? 500 : i % 7 === 0 ? 404 : 200;
106
+ const ms = Math.floor(Math.random() * 500) + 5;
107
+ const stream: 'stdout' | 'stderr' = status >= 500 ? 'stderr' : 'stdout';
108
+ logs.push(makeLog(`${method} ${path}/${i} ${status} in ${ms}ms`, stream, 100 + i * 10));
109
+ }
110
+ return <InteractiveWrapper logs={logs} isConnected={true} />;
111
+ },
112
+ };
113
+
114
+ /** Lines exceeding viewport width showing wrap behavior. */
115
+ export const LongLines: Story = {
116
+ render: () => (
117
+ <InteractiveWrapper
118
+ logs={[
119
+ makeLog('Short line', 'stdout', 0),
120
+ makeLog(
121
+ "Error: Module not found: Can't resolve '@/components/features/really-long-component-name/that-goes-on-and-on/sub-component/deeply-nested-module/index.tsx' in '/Users/developer/projects/my-very-long-project-name/src/presentation/web/components/features'",
122
+ 'stderr',
123
+ 10
124
+ ),
125
+ makeLog(
126
+ 'at Object.resolve (webpack://my-app/node_modules/enhanced-resolve/lib/Resolver.js?:331:11) at Object.resolve (webpack://my-app/node_modules/enhanced-resolve/lib/Resolver.js?:331:11) at Object.resolve (webpack://my-app/node_modules/enhanced-resolve/lib/Resolver.js?:331:11)',
127
+ 'stderr',
128
+ 20
129
+ ),
130
+ makeLog('Normal log line here', 'stdout', 30),
131
+ makeLog(
132
+ JSON.stringify({
133
+ level: 'info',
134
+ message: 'Request processed',
135
+ metadata: {
136
+ userId: 'usr_abc123',
137
+ path: '/api/features',
138
+ method: 'POST',
139
+ duration: 234,
140
+ headers: { 'content-type': 'application/json', authorization: 'Bearer xxx...xxx' },
141
+ },
142
+ }),
143
+ 'stdout',
144
+ 40
145
+ ),
146
+ makeLog('Another normal line', 'stdout', 50),
147
+ ]}
148
+ isConnected={true}
149
+ />
150
+ ),
151
+ };
152
+
153
+ /** Disconnected state — shows server stopped message. */
154
+ export const Disconnected: Story = {
155
+ render: () => (
156
+ <InteractiveWrapper
157
+ logs={[
158
+ makeLog('$ npm run dev', 'stdout', 0),
159
+ makeLog('> next dev', 'stdout', 10),
160
+ makeLog(' ✓ Ready in 1.2s', 'stdout', 20),
161
+ makeLog('GET / 200 in 412ms', 'stdout', 100),
162
+ makeLog('GET /api/data 200 in 23ms', 'stdout', 200),
163
+ makeLog('SIGTERM received, shutting down...', 'stderr', 300),
164
+ ]}
165
+ isConnected={false}
166
+ />
167
+ ),
168
+ };