@shepai/cli 1.70.1 → 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.
- package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts +32 -0
- package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts +16 -2
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +46 -9
- package/dist/packages/core/src/infrastructure/services/deployment/log-ring-buffer.d.ts +23 -0
- package/dist/packages/core/src/infrastructure/services/deployment/log-ring-buffer.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/deployment/log-ring-buffer.js +46 -0
- package/dist/src/presentation/web/app/actions/get-deployment-logs.d.ts +3 -0
- package/dist/src/presentation/web/app/actions/get-deployment-logs.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/get-deployment-logs.js +9 -0
- package/dist/src/presentation/web/app/actions/get-feature-artifact.d.ts +2 -0
- package/dist/src/presentation/web/app/actions/get-feature-artifact.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/get-feature-artifact.js +23 -1
- package/dist/src/presentation/web/app/api/deployment-logs/route.d.ts +15 -0
- package/dist/src/presentation/web/app/api/deployment-logs/route.d.ts.map +1 -0
- package/dist/src/presentation/web/app/api/deployment-logs/route.js +94 -0
- package/dist/src/presentation/web/components/common/base-drawer/base-drawer.js +2 -2
- package/dist/src/presentation/web/components/common/base-drawer/base-drawer.stories.js +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js +34 -4
- package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.d.ts +2 -1
- package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.js +16 -5
- package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.d.ts +4 -0
- package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.js +8 -0
- package/dist/src/presentation/web/components/common/merge-review/merge-review.js +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.js +1 -1
- package/dist/src/presentation/web/components/common/product-decisions-summary/index.d.ts +3 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/index.js +1 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.d.ts +23 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.js +1 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.d.ts +3 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.js +13 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.d.ts +14 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.js +74 -0
- package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
- package/dist/src/presentation/web/components/common/server-log-viewer/index.d.ts +2 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/index.js +1 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.d.ts +15 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.js +31 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.d.ts +18 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.js +113 -0
- package/dist/src/presentation/web/components/common/tech-decisions-review/index.d.ts +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/index.js +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts +8 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.js +11 -2
- package/dist/src/presentation/web/components/common/tech-review-tabs/index.d.ts +3 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/index.js +1 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.d.ts +17 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.js +1 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.d.ts +3 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.js +12 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.d.ts +16 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.js +110 -0
- package/dist/src/presentation/web/hooks/use-deployment-logs.d.ts +7 -0
- package/dist/src/presentation/web/hooks/use-deployment-logs.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-deployment-logs.js +50 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -0
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/routes-manifest.json +6 -0
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/deployment-logs/route/app-paths-manifest.json +3 -0
- package/web/.next/server/app/api/deployment-logs/route/build-manifest.json +11 -0
- package/web/.next/server/app/api/deployment-logs/route/server-reference-manifest.json +4 -0
- package/web/.next/server/app/api/deployment-logs/route.js +6 -0
- package/web/.next/server/app/api/deployment-logs/route.js.map +5 -0
- package/web/.next/server/app/api/deployment-logs/route.js.nft.json +1 -0
- package/web/.next/server/app/api/deployment-logs/route_client-reference-manifest.js +2 -0
- package/web/.next/server/app/api/tools/[id]/install/route.js +1 -1
- package/web/.next/server/app/api/tools/[id]/install/route.js.nft.json +1 -1
- package/web/.next/server/app/page/server-reference-manifest.json +51 -36
- package/web/.next/server/app/page.js +1 -1
- package/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +25 -10
- package/web/.next/server/app/skills/page.js +1 -1
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page.js +1 -1
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app-paths-manifest.json +1 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_deployment-logs_route_actions_b785cd3a.js +3 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_deployment-logs_route_actions_b785cd3a.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__9a136c79._.js +9 -0
- package/web/.next/server/chunks/[root-of-the-server]__9a136c79._.js.map +1 -0
- package/web/.next/server/chunks/{[root-of-the-server]__09413611._.js → [root-of-the-server]__e926de65._.js} +2 -2
- package/web/.next/server/chunks/{[root-of-the-server]__09413611._.js.map → [root-of-the-server]__e926de65._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5f968713._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5f968713._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__249c74f6._.js → [root-of-the-server]__6e8b5181._.js} +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__970ba1be._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__970ba1be._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__97a1f9c2._.js +4 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__97a1f9c2._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ad7c18fa._.js +9 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ad7c18fa._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b22d8535._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b22d8535._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_25e0eb34._.js +3 -0
- package/web/.next/server/chunks/ssr/_25e0eb34._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
- package/web/.next/server/chunks/ssr/_49bf495c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
- package/web/.next/server/chunks/ssr/_68b5e0de._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
- package/web/.next/server/chunks/ssr/_725584e5._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_72ce07df._.js +3 -0
- package/web/.next/server/chunks/ssr/_72ce07df._.js.map +1 -0
- package/web/.next/server/chunks/ssr/{node_modules__pnpm_febcbea6._.js → node_modules__pnpm_3288606c._.js} +2 -2
- package/web/.next/server/chunks/ssr/{node_modules__pnpm_febcbea6._.js.map → node_modules__pnpm_3288606c._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_ui_tabs_tsx_b226ea9b._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_ui_tabs_tsx_b226ea9b._.js.map +1 -0
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +64 -42
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/app-path-routes-manifest.json +1 -0
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/routes-manifest.json +6 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route/build-manifest.json +11 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route.js +6 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route.js.map +5 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route.js.nft.json +1 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/deployment-logs/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/tools/[id]/install/route.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/tools/[id]/install/route.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +51 -36
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +25 -10
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app-paths-manifest.json +1 -0
- 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
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__9a136c79._.js +9 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/{[root-of-the-server]__09413611._.js → [root-of-the-server]__e926de65._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__5f968713._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- 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
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__970ba1be._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__97a1f9c2._.js +4 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__ad7c18fa._.js +9 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__b22d8535._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_25e0eb34._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_72ce07df._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{node_modules__pnpm_febcbea6._.js → node_modules__pnpm_3288606c._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_5124369c._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_ui_tabs_tsx_b226ea9b._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +64 -42
- package/web/.next/standalone/src/presentation/web/app/actions/get-deployment-logs.ts +16 -0
- package/web/.next/standalone/src/presentation/web/app/actions/get-feature-artifact.ts +26 -1
- package/web/.next/standalone/src/presentation/web/app/api/deployment-logs/route.ts +112 -0
- package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.stories.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/base-drawer/base-drawer.tsx +6 -2
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx +44 -6
- package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.stories.tsx +10 -0
- package/web/.next/standalone/src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.tsx +76 -23
- package/web/.next/standalone/src/presentation/web/components/common/merge-review/merge-review.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/index.ts +6 -0
- package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary-config.ts +24 -0
- package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.stories.tsx +87 -0
- package/web/.next/standalone/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.tsx +52 -0
- package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +5 -1
- package/web/.next/standalone/src/presentation/web/components/common/server-log-viewer/index.ts +6 -0
- package/web/.next/standalone/src/presentation/web/components/common/server-log-viewer/server-log-viewer.stories.tsx +168 -0
- package/web/.next/standalone/src/presentation/web/components/common/server-log-viewer/server-log-viewer.tsx +110 -0
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/index.ts +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/tech-decisions-review/tech-decisions-review.tsx +47 -29
- package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/index.ts +2 -0
- package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs-config.ts +17 -0
- package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.stories.tsx +129 -0
- package/web/.next/standalone/src/presentation/web/components/common/tech-review-tabs/tech-review-tabs.tsx +60 -0
- package/web/.next/standalone/src/presentation/web/hooks/use-deployment-logs.ts +67 -0
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/01ae2241bd4b44b6.js +1 -0
- package/web/.next/static/chunks/20f7876f292cfd82.js +1 -0
- package/web/.next/static/chunks/224ed5f5dbd33154.css +2 -0
- package/web/.next/static/chunks/{87421ab1062a39b7.js → 3e1227e02ef8bcc6.js} +2 -2
- package/web/.next/static/chunks/{1ed0df845a1625f6.js → 62c8ebbd9c7bb287.js} +1 -1
- package/web/.next/static/chunks/673e0c1000a91948.js +1 -0
- package/web/.next/static/chunks/8b6df4f8e194d0ce.js +1 -0
- package/web/.next/static/chunks/b025563d959150a1.js +1 -0
- package/web/.next/static/chunks/{9db5c06001f3e664.js → c7fb052190a02a9c.js} +2 -2
- package/web/.next/static/chunks/d450d8db6be36b8d.js +1 -0
- package/web/.next/static/chunks/d9e3cf214ac2f386.js +1 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/types/link.d.ts +1 -0
- package/web/.next/types/routes.d.ts +2 -1
- package/web/.next/types/validator.ts +9 -0
- package/web/.next/server/chunks/ssr/6769f_@radix-ui_react-roving-focus_dist_index_mjs_b3be3d8e._.js +0 -3
- package/web/.next/server/chunks/ssr/6769f_@radix-ui_react-roving-focus_dist_index_mjs_b3be3d8e._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2ffb27f1._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2ffb27f1._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7f4180a1._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7f4180a1._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +0 -9
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__eaf6100f._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__eaf6100f._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_28993370._.js +0 -3
- package/web/.next/server/chunks/ssr/_28993370._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_690ea95f._.js +0 -3
- package/web/.next/server/chunks/ssr/_690ea95f._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_0286756b._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_components_0286756b._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/6769f_@radix-ui_react-roving-focus_dist_index_mjs_b3be3d8e._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2ffb27f1._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +0 -4
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__7f4180a1._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +0 -9
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__eaf6100f._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_28993370._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_690ea95f._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_0286756b._.js +0 -3
- package/web/.next/static/chunks/16e380b8dd9d11bc.js +0 -1
- package/web/.next/static/chunks/24e1d97cab8bad6d.js +0 -1
- package/web/.next/static/chunks/505c6a9e4c5d0808.js +0 -1
- package/web/.next/static/chunks/a186bbb822ccb655.css +0 -2
- package/web/.next/static/chunks/a5c59952485e875e.js +0 -1
- package/web/.next/static/chunks/a9626385607910b3.js +0 -1
- package/web/.next/static/chunks/d4379644a6145352.js +0 -1
- package/web/.next/static/chunks/fb703cf73aba2eb8.js +0 -1
- /package/web/.next/server/chunks/ssr/{[root-of-the-server]__249c74f6._.js.map → [root-of-the-server]__6e8b5181._.js.map} +0 -0
- /package/web/.next/static/{8xZoRkWykApYNlvamCGUe → F3mdpVVEgR5m2xHY_SnYx}/_buildManifest.js +0 -0
- /package/web/.next/static/{8xZoRkWykApYNlvamCGUe → F3mdpVVEgR5m2xHY_SnYx}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{8xZoRkWykApYNlvamCGUe → F3mdpVVEgR5m2xHY_SnYx}/_ssgManifest.js +0 -0
package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts
CHANGED
|
@@ -10,6 +10,17 @@
|
|
|
10
10
|
* - Infrastructure layer provides concrete implementations
|
|
11
11
|
*/
|
|
12
12
|
import type { DeploymentState } from '../../../../domain/generated/output.js';
|
|
13
|
+
/** A single log line captured from a deployment's stdout or stderr. */
|
|
14
|
+
export interface LogEntry {
|
|
15
|
+
/** Which deployment produced this line. */
|
|
16
|
+
targetId: string;
|
|
17
|
+
/** Which output stream produced this line. */
|
|
18
|
+
stream: 'stdout' | 'stderr';
|
|
19
|
+
/** The line content (without trailing newline). */
|
|
20
|
+
line: string;
|
|
21
|
+
/** Timestamp (ms since epoch) when the line was captured. */
|
|
22
|
+
timestamp: number;
|
|
23
|
+
}
|
|
13
24
|
/** Status snapshot returned by getStatus(). */
|
|
14
25
|
export interface DeploymentStatus {
|
|
15
26
|
/** Current lifecycle state of the deployment. */
|
|
@@ -58,5 +69,26 @@ export interface IDeploymentService {
|
|
|
58
69
|
* Called during daemon shutdown to prevent orphaned dev server processes.
|
|
59
70
|
*/
|
|
60
71
|
stopAll(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Get the accumulated log buffer for a deployment.
|
|
74
|
+
*
|
|
75
|
+
* @param targetId - Unique identifier for the deployment target
|
|
76
|
+
* @returns Array of log entries in chronological order, or null if no deployment exists
|
|
77
|
+
*/
|
|
78
|
+
getLogs(targetId: string): LogEntry[] | null;
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to real-time log events from all deployments.
|
|
81
|
+
*
|
|
82
|
+
* @param event - Event name (only 'log' is supported)
|
|
83
|
+
* @param handler - Callback invoked with each new log entry
|
|
84
|
+
*/
|
|
85
|
+
on(event: 'log', handler: (entry: LogEntry) => void): void;
|
|
86
|
+
/**
|
|
87
|
+
* Unsubscribe from real-time log events.
|
|
88
|
+
*
|
|
89
|
+
* @param event - Event name (only 'log' is supported)
|
|
90
|
+
* @param handler - The same callback reference passed to on()
|
|
91
|
+
*/
|
|
92
|
+
off(event: 'log', handler: (entry: LogEntry) => void): void;
|
|
61
93
|
}
|
|
62
94
|
//# sourceMappingURL=deployment-service.interface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment-service.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/services/deployment-service.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,eAAe,CAAC;IACvB,qEAAqE;IACrE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;;OAMG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAErD;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"deployment-service.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/services/deployment-service.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,uEAAuE;AACvE,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,eAAe,CAAC;IACvB,qEAAqE;IACrE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;;OAMG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAErD;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;IAIhB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE7C;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7D"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* shutdown (SIGTERM → poll → SIGKILL).
|
|
8
8
|
*/
|
|
9
9
|
import { spawn } from 'node:child_process';
|
|
10
|
-
import type { IDeploymentService, DeploymentStatus } from '../../../application/ports/output/services/deployment-service.interface.js';
|
|
10
|
+
import type { IDeploymentService, DeploymentStatus, LogEntry } from '../../../application/ports/output/services/deployment-service.interface.js';
|
|
11
11
|
import { detectDevScript } from './detect-dev-script.js';
|
|
12
12
|
export interface DeploymentServiceDeps {
|
|
13
13
|
spawn: typeof spawn;
|
|
@@ -18,6 +18,7 @@ export interface DeploymentServiceDeps {
|
|
|
18
18
|
export declare class DeploymentService implements IDeploymentService {
|
|
19
19
|
private readonly deployments;
|
|
20
20
|
private readonly deps;
|
|
21
|
+
private readonly emitter;
|
|
21
22
|
constructor(deps?: Partial<DeploymentServiceDeps>);
|
|
22
23
|
/**
|
|
23
24
|
* Start a deployment for the given target.
|
|
@@ -37,12 +38,25 @@ export declare class DeploymentService implements IDeploymentService {
|
|
|
37
38
|
* Force-stop all tracked deployments immediately (for daemon shutdown).
|
|
38
39
|
*/
|
|
39
40
|
stopAll(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get the accumulated log buffer for a deployment.
|
|
43
|
+
*/
|
|
44
|
+
getLogs(targetId: string): LogEntry[] | null;
|
|
45
|
+
/**
|
|
46
|
+
* Subscribe to real-time log events.
|
|
47
|
+
*/
|
|
48
|
+
on(event: 'log', handler: (entry: LogEntry) => void): void;
|
|
49
|
+
/**
|
|
50
|
+
* Unsubscribe from real-time log events.
|
|
51
|
+
*/
|
|
52
|
+
off(event: 'log', handler: (entry: LogEntry) => void): void;
|
|
40
53
|
/**
|
|
41
54
|
* Send SIGKILL to a process group.
|
|
42
55
|
*/
|
|
43
56
|
private killProcess;
|
|
44
57
|
/**
|
|
45
|
-
* Attach a line-buffered listener on stdout or stderr that calls parsePort
|
|
58
|
+
* Attach a line-buffered listener on stdout or stderr that calls parsePort
|
|
59
|
+
* and accumulates log entries.
|
|
46
60
|
*/
|
|
47
61
|
private attachOutputListener;
|
|
48
62
|
/**
|
package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAG9D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACT,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAoBzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAgBD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;gBAElC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA+EjD;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAYpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI;IAM5C;;OAEG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAI1D;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAI3D;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA+D5B;;OAEG;YACW,aAAa;IAW3B;;OAEG;IACH,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
* shutdown (SIGTERM → poll → SIGKILL).
|
|
8
8
|
*/
|
|
9
9
|
import { spawn } from 'node:child_process';
|
|
10
|
+
import { EventEmitter } from 'node:events';
|
|
10
11
|
import { DeploymentState } from '../../../domain/generated/output.js';
|
|
11
12
|
import { detectDevScript } from './detect-dev-script.js';
|
|
12
13
|
import { createDeploymentLogger } from './deployment-logger.js';
|
|
13
14
|
import { parsePort } from './parse-port.js';
|
|
15
|
+
import { LogRingBuffer } from './log-ring-buffer.js';
|
|
14
16
|
const log = createDeploymentLogger('[DeploymentService]');
|
|
15
17
|
const POLL_INTERVAL_MS = 200;
|
|
16
18
|
const MAX_WAIT_MS = 5000;
|
|
@@ -31,6 +33,7 @@ const defaultDeps = {
|
|
|
31
33
|
export class DeploymentService {
|
|
32
34
|
deployments = new Map();
|
|
33
35
|
deps;
|
|
36
|
+
emitter = new EventEmitter();
|
|
34
37
|
constructor(deps = {}) {
|
|
35
38
|
this.deps = { ...defaultDeps, ...deps };
|
|
36
39
|
}
|
|
@@ -76,6 +79,7 @@ export class DeploymentService {
|
|
|
76
79
|
targetId,
|
|
77
80
|
stdoutBuffer: '',
|
|
78
81
|
stderrBuffer: '',
|
|
82
|
+
logs: new LogRingBuffer(),
|
|
79
83
|
};
|
|
80
84
|
this.deployments.set(targetId, entry);
|
|
81
85
|
// Attach stdout/stderr listeners for port detection
|
|
@@ -120,6 +124,7 @@ export class DeploymentService {
|
|
|
120
124
|
return;
|
|
121
125
|
}
|
|
122
126
|
log.info(`stop("${targetId}") — sending SIGTERM to process group (pid=${entry.pid})`);
|
|
127
|
+
entry.logs.clear();
|
|
123
128
|
// Send SIGTERM to process group
|
|
124
129
|
try {
|
|
125
130
|
this.deps.kill(-entry.pid, 'SIGTERM');
|
|
@@ -152,9 +157,31 @@ export class DeploymentService {
|
|
|
152
157
|
*/
|
|
153
158
|
stopAll() {
|
|
154
159
|
for (const entry of this.deployments.values()) {
|
|
160
|
+
entry.logs.clear();
|
|
155
161
|
this.killProcess(entry);
|
|
156
162
|
}
|
|
157
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Get the accumulated log buffer for a deployment.
|
|
166
|
+
*/
|
|
167
|
+
getLogs(targetId) {
|
|
168
|
+
const entry = this.deployments.get(targetId);
|
|
169
|
+
if (!entry)
|
|
170
|
+
return null;
|
|
171
|
+
return entry.logs.getAll();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Subscribe to real-time log events.
|
|
175
|
+
*/
|
|
176
|
+
on(event, handler) {
|
|
177
|
+
this.emitter.on(event, handler);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Unsubscribe from real-time log events.
|
|
181
|
+
*/
|
|
182
|
+
off(event, handler) {
|
|
183
|
+
this.emitter.off(event, handler);
|
|
184
|
+
}
|
|
158
185
|
/**
|
|
159
186
|
* Send SIGKILL to a process group.
|
|
160
187
|
*/
|
|
@@ -167,7 +194,8 @@ export class DeploymentService {
|
|
|
167
194
|
}
|
|
168
195
|
}
|
|
169
196
|
/**
|
|
170
|
-
* Attach a line-buffered listener on stdout or stderr that calls parsePort
|
|
197
|
+
* Attach a line-buffered listener on stdout or stderr that calls parsePort
|
|
198
|
+
* and accumulates log entries.
|
|
171
199
|
*/
|
|
172
200
|
attachOutputListener(entry, stream) {
|
|
173
201
|
const bufferKey = stream === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer';
|
|
@@ -188,14 +216,23 @@ export class DeploymentService {
|
|
|
188
216
|
if (!line.trim())
|
|
189
217
|
continue;
|
|
190
218
|
log.debug(`[${entry.targetId}] ${stream}: ${line}`);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
219
|
+
// Accumulate in log buffer and emit event
|
|
220
|
+
const logEntry = {
|
|
221
|
+
targetId: entry.targetId,
|
|
222
|
+
stream,
|
|
223
|
+
line,
|
|
224
|
+
timestamp: Date.now(),
|
|
225
|
+
};
|
|
226
|
+
entry.logs.push(logEntry);
|
|
227
|
+
this.emitter.emit('log', logEntry);
|
|
228
|
+
// Port detection (only while Booting)
|
|
229
|
+
if (entry.state === DeploymentState.Booting) {
|
|
230
|
+
const url = parsePort(line);
|
|
231
|
+
if (url) {
|
|
232
|
+
log.info(`[${entry.targetId}] Port detected — url="${url}" (from ${stream})`);
|
|
233
|
+
entry.state = DeploymentState.Ready;
|
|
234
|
+
entry.url = url;
|
|
235
|
+
}
|
|
199
236
|
}
|
|
200
237
|
}
|
|
201
238
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogRingBuffer — Fixed-capacity circular buffer for deployment log entries.
|
|
3
|
+
*
|
|
4
|
+
* Provides O(1) append with automatic eviction of the oldest entry when full.
|
|
5
|
+
* getAll() returns entries in chronological (insertion) order.
|
|
6
|
+
*/
|
|
7
|
+
import type { LogEntry } from '../../../application/ports/output/services/deployment-service.interface.js';
|
|
8
|
+
export declare class LogRingBuffer {
|
|
9
|
+
readonly capacity: number;
|
|
10
|
+
private buffer;
|
|
11
|
+
private writeIndex;
|
|
12
|
+
private count;
|
|
13
|
+
constructor(capacity?: number);
|
|
14
|
+
/** Append a log entry. Evicts the oldest entry when at capacity. */
|
|
15
|
+
push(entry: LogEntry): void;
|
|
16
|
+
/** Return all entries in chronological order. */
|
|
17
|
+
getAll(): LogEntry[];
|
|
18
|
+
/** Remove all entries and reset the buffer. */
|
|
19
|
+
clear(): void;
|
|
20
|
+
/** Current number of entries in the buffer. */
|
|
21
|
+
get size(): number;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=log-ring-buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-ring-buffer.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/log-ring-buffer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qEAAqE,CAAC;AAIpG,qBAAa,aAAa;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAK;gBAEN,QAAQ,GAAE,MAAyB;IAK/C,oEAAoE;IACpE,IAAI,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAU3B,iDAAiD;IACjD,MAAM,IAAI,QAAQ,EAAE;IAQpB,+CAA+C;IAC/C,KAAK,IAAI,IAAI;IAMb,+CAA+C;IAC/C,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogRingBuffer — Fixed-capacity circular buffer for deployment log entries.
|
|
3
|
+
*
|
|
4
|
+
* Provides O(1) append with automatic eviction of the oldest entry when full.
|
|
5
|
+
* getAll() returns entries in chronological (insertion) order.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_CAPACITY = 5000;
|
|
8
|
+
export class LogRingBuffer {
|
|
9
|
+
capacity;
|
|
10
|
+
buffer;
|
|
11
|
+
writeIndex = 0;
|
|
12
|
+
count = 0;
|
|
13
|
+
constructor(capacity = DEFAULT_CAPACITY) {
|
|
14
|
+
this.capacity = capacity;
|
|
15
|
+
this.buffer = [];
|
|
16
|
+
}
|
|
17
|
+
/** Append a log entry. Evicts the oldest entry when at capacity. */
|
|
18
|
+
push(entry) {
|
|
19
|
+
if (this.count < this.capacity) {
|
|
20
|
+
this.buffer.push(entry);
|
|
21
|
+
this.count++;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
this.buffer[this.writeIndex] = entry;
|
|
25
|
+
}
|
|
26
|
+
this.writeIndex = (this.writeIndex + 1) % this.capacity;
|
|
27
|
+
}
|
|
28
|
+
/** Return all entries in chronological order. */
|
|
29
|
+
getAll() {
|
|
30
|
+
if (this.count < this.capacity) {
|
|
31
|
+
return this.buffer.slice();
|
|
32
|
+
}
|
|
33
|
+
// Buffer is full and may have wrapped — writeIndex points to the oldest entry
|
|
34
|
+
return [...this.buffer.slice(this.writeIndex), ...this.buffer.slice(0, this.writeIndex)];
|
|
35
|
+
}
|
|
36
|
+
/** Remove all entries and reset the buffer. */
|
|
37
|
+
clear() {
|
|
38
|
+
this.buffer = [];
|
|
39
|
+
this.writeIndex = 0;
|
|
40
|
+
this.count = 0;
|
|
41
|
+
}
|
|
42
|
+
/** Current number of entries in the buffer. */
|
|
43
|
+
get size() {
|
|
44
|
+
return this.count;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-deployment-logs.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-deployment-logs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,QAAQ,EACT,MAAM,6EAA6E,CAAC;AAErF,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAOpF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
import { resolve } from '../../lib/server-container.js';
|
|
3
|
+
export async function getDeploymentLogs(targetId) {
|
|
4
|
+
if (!targetId?.trim()) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
const deploymentService = resolve('IDeploymentService');
|
|
8
|
+
return deploymentService.getLogs(targetId);
|
|
9
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { FeatureArtifact } from '../../../../../packages/core/src/domain/generated/output.js';
|
|
2
2
|
import type { PrdQuestionnaireData } from '../../../../../packages/core/src/domain/generated/output.js';
|
|
3
|
+
import type { ProductDecisionsSummaryData } from '../../components/common/product-decisions-summary/index.js';
|
|
3
4
|
interface GetFeatureArtifactResult {
|
|
4
5
|
questionnaire?: PrdQuestionnaireData;
|
|
6
|
+
productDecisions?: ProductDecisionsSummaryData;
|
|
5
7
|
artifact?: FeatureArtifact;
|
|
6
8
|
error?: string;
|
|
7
9
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-feature-artifact.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-artifact.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"get-feature-artifact.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/get-feature-artifact.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+CAA+C,CAAC;AAEjG,UAAU,wBAAwB;IAChC,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,gBAAgB,CAAC,EAAE,2BAA2B,CAAC;IAC/C,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmDD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAe7F"}
|
|
@@ -26,6 +26,27 @@ function toQuestionnaireData(artifact) {
|
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Map FeatureArtifact openQuestions into a read-only summary for the
|
|
31
|
+
* Product Decisions tab in the tech review drawer.
|
|
32
|
+
*/
|
|
33
|
+
function toProductDecisionsData(artifact) {
|
|
34
|
+
return {
|
|
35
|
+
question: 'Goal',
|
|
36
|
+
context: artifact.oneLiner,
|
|
37
|
+
questions: artifact.openQuestions
|
|
38
|
+
.filter((oq) => oq.resolved)
|
|
39
|
+
.map((oq) => {
|
|
40
|
+
const selected = oq.options?.find((o) => o.selected);
|
|
41
|
+
return {
|
|
42
|
+
question: oq.question,
|
|
43
|
+
selectedOption: selected?.option ?? oq.answer ?? 'N/A',
|
|
44
|
+
rationale: oq.selectionRationale ?? selected?.description ?? '',
|
|
45
|
+
wasRecommended: false,
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
29
50
|
export async function getFeatureArtifact(featureId) {
|
|
30
51
|
if (!featureId.trim()) {
|
|
31
52
|
return { error: 'Feature id is required' };
|
|
@@ -34,7 +55,8 @@ export async function getFeatureArtifact(featureId) {
|
|
|
34
55
|
const useCase = resolve('GetFeatureArtifactUseCase');
|
|
35
56
|
const artifact = await useCase.execute(featureId);
|
|
36
57
|
const questionnaire = toQuestionnaireData(artifact);
|
|
37
|
-
|
|
58
|
+
const productDecisions = toProductDecisionsData(artifact);
|
|
59
|
+
return { questionnaire, productDecisions, artifact };
|
|
38
60
|
}
|
|
39
61
|
catch (error) {
|
|
40
62
|
const message = error instanceof Error ? error.message : 'Failed to load feature artifact';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE API Route: GET /api/deployment-logs
|
|
3
|
+
*
|
|
4
|
+
* Streams deployment log events to the client via Server-Sent Events.
|
|
5
|
+
* Subscribes to the DeploymentService EventEmitter for real-time log
|
|
6
|
+
* entries, filtered by targetId.
|
|
7
|
+
*
|
|
8
|
+
* - Accepts ?targetId query parameter (required)
|
|
9
|
+
* - Sends log entries as SSE "log" events
|
|
10
|
+
* - Sends heartbeat comments every 30 seconds to keep connection alive
|
|
11
|
+
* - Cleans up EventEmitter subscription on client disconnect
|
|
12
|
+
*/
|
|
13
|
+
export declare const dynamic = "force-dynamic";
|
|
14
|
+
export declare function GET(request: Request): Response;
|
|
15
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/deployment-logs/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAIvC,wBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAuF9C"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE API Route: GET /api/deployment-logs
|
|
3
|
+
*
|
|
4
|
+
* Streams deployment log events to the client via Server-Sent Events.
|
|
5
|
+
* Subscribes to the DeploymentService EventEmitter for real-time log
|
|
6
|
+
* entries, filtered by targetId.
|
|
7
|
+
*
|
|
8
|
+
* - Accepts ?targetId query parameter (required)
|
|
9
|
+
* - Sends log entries as SSE "log" events
|
|
10
|
+
* - Sends heartbeat comments every 30 seconds to keep connection alive
|
|
11
|
+
* - Cleans up EventEmitter subscription on client disconnect
|
|
12
|
+
*/
|
|
13
|
+
import { resolve } from '../../../lib/server-container.js';
|
|
14
|
+
// Force dynamic — SSE streams must never be statically optimized or cached
|
|
15
|
+
export const dynamic = 'force-dynamic';
|
|
16
|
+
const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
17
|
+
export function GET(request) {
|
|
18
|
+
try {
|
|
19
|
+
const url = new URL(request.url);
|
|
20
|
+
const targetId = url.searchParams.get('targetId');
|
|
21
|
+
if (!targetId?.trim()) {
|
|
22
|
+
const errorStream = new ReadableStream({
|
|
23
|
+
start(controller) {
|
|
24
|
+
const encoder = new TextEncoder();
|
|
25
|
+
controller.enqueue(encoder.encode(`event: error\ndata: ${JSON.stringify({ error: 'targetId is required' })}\n\n`));
|
|
26
|
+
controller.close();
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
return new Response(errorStream, {
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'text/event-stream',
|
|
32
|
+
'Cache-Control': 'no-cache',
|
|
33
|
+
Connection: 'keep-alive',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const stream = new ReadableStream({
|
|
38
|
+
start(controller) {
|
|
39
|
+
const encoder = new TextEncoder();
|
|
40
|
+
let stopped = false;
|
|
41
|
+
function enqueue(text) {
|
|
42
|
+
if (stopped)
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
controller.enqueue(encoder.encode(text));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Stream may be closed
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const deploymentService = resolve('IDeploymentService');
|
|
52
|
+
// Subscribe to log events, filtering by targetId
|
|
53
|
+
const logHandler = (entry) => {
|
|
54
|
+
if (entry.targetId !== targetId)
|
|
55
|
+
return;
|
|
56
|
+
enqueue(`event: log\ndata: ${JSON.stringify(entry)}\n\n`);
|
|
57
|
+
};
|
|
58
|
+
deploymentService.on('log', logHandler);
|
|
59
|
+
// Heartbeat to keep connection alive
|
|
60
|
+
const heartbeatInterval = setInterval(() => {
|
|
61
|
+
enqueue(': heartbeat\n\n');
|
|
62
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
63
|
+
// Cleanup on client disconnect
|
|
64
|
+
const cleanup = () => {
|
|
65
|
+
stopped = true;
|
|
66
|
+
deploymentService.off('log', logHandler);
|
|
67
|
+
clearInterval(heartbeatInterval);
|
|
68
|
+
try {
|
|
69
|
+
controller.close();
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Stream may already be closed
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
request.signal.addEventListener('abort', cleanup, { once: true });
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
return new Response(stream, {
|
|
79
|
+
headers: {
|
|
80
|
+
'Content-Type': 'text/event-stream',
|
|
81
|
+
'Cache-Control': 'no-cache',
|
|
82
|
+
Connection: 'keep-alive',
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.error('[SSE route] GET /api/deployment-logs error:', error);
|
|
89
|
+
return new Response(JSON.stringify({ error: String(error) }), {
|
|
90
|
+
status: 500,
|
|
91
|
+
headers: { 'Content-Type': 'application/json' },
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -44,10 +44,10 @@ export function BaseDrawer({ open, onClose, modal = false, size, header, childre
|
|
|
44
44
|
return (_jsxs(Drawer, { direction: "right", modal: modal, handleOnly: true, open: open, onOpenChange: (isOpen) => {
|
|
45
45
|
if (!isOpen)
|
|
46
46
|
onClose();
|
|
47
|
-
}, children: [modal ? _jsx(DrawerOverlay, {}) : null, _jsxs(DrawerContent, { ref: contentRef, direction: "right", showCloseButton: false, className: cn(drawerVariants({ size }), className), "data-testid": testId, children: [_jsxs("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", "data-testid": testId ? `${testId}-close-button` : undefined, children: [_jsx(XIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }), header ? _jsx(DrawerHeader, { className: "shrink-0", children: header }) : null, header ? _jsx(Separator, {}) : null, featureFlags.envDeploy && deployTarget ? _jsx(DeployBar, { deployTarget: deployTarget }) : null, _jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: children }), footer ? _jsx(DrawerFooter, { className: "shrink-0", children: footer }) : null] })] }));
|
|
47
|
+
}, children: [modal ? _jsx(DrawerOverlay, {}) : null, _jsxs(DrawerContent, { ref: contentRef, direction: "right", showCloseButton: false, className: cn(drawerVariants({ size }), className), "data-testid": testId, children: [_jsxs("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", "data-testid": testId ? `${testId}-close-button` : undefined, children: [_jsx(XIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }), header ? _jsx(DrawerHeader, { className: "shrink-0", children: header }) : null, header ? _jsx(Separator, {}) : null, featureFlags.envDeploy && deployTarget ? _jsx(DeployBar, { deployTarget: deployTarget }) : null, _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: children }), footer ? _jsx(DrawerFooter, { className: "shrink-0", children: footer }) : null] })] }));
|
|
48
48
|
}
|
|
49
49
|
function DeployBar({ deployTarget }) {
|
|
50
50
|
const deployAction = useDeployAction(deployTarget);
|
|
51
51
|
const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';
|
|
52
|
-
return (_jsxs("div", { "data-testid": "base-drawer-deploy-bar", className: "flex items-center gap-2 px-4 pb-3", children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isDeploymentActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url })) : null] }));
|
|
52
|
+
return (_jsxs("div", { "data-testid": "base-drawer-deploy-bar", className: "flex items-center gap-2 px-4 pb-3", children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isDeploymentActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: deployTarget.targetId })) : null] }));
|
|
53
53
|
}
|
|
@@ -75,5 +75,5 @@ export const WithDevServerBar = {
|
|
|
75
75
|
* Try scrolling the content below to see the fixed header behavior.
|
|
76
76
|
*/
|
|
77
77
|
export const ScrollableContent = {
|
|
78
|
-
render: () => (_jsx(DrawerTrigger, { header: _jsxs(_Fragment, { children: [_jsx(DrawerTitle, { children: "Scrollable Content" }), _jsx(DrawerDescription, { children: "Content below overflows and scrolls" })] }), children: _jsx("div", { className: "flex flex-col gap-4 p-4", children: Array.from({ length: 30 }, (_, i) => (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsxs("h4", { className: "text-sm font-medium", children: ["Item ", i + 1] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "This is a scrollable content item to demonstrate overflow handling." })] }, i))) }) })),
|
|
78
|
+
render: () => (_jsx(DrawerTrigger, { header: _jsxs(_Fragment, { children: [_jsx(DrawerTitle, { children: "Scrollable Content" }), _jsx(DrawerDescription, { children: "Content below overflows and scrolls" })] }), children: _jsx("div", { className: "flex flex-col gap-4 overflow-y-auto p-4", children: Array.from({ length: 30 }, (_, i) => (_jsxs("div", { className: "border-border rounded-md border p-3", children: [_jsxs("h4", { className: "text-sm font-medium", children: ["Item ", i + 1] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "This is a scrollable content item to demonstrate overflow handling." })] }, i))) }) })),
|
|
79
79
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"control-center-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx"],"names":[],"mappings":"AA+DA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACrD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,UAAU,EACV,cAAc,EACd,YAAY,GACb,EAAE,wBAAwB,2CA0jB1B"}
|
package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js
CHANGED
|
@@ -27,7 +27,7 @@ import { ActionButton } from '../../common/action-button/index.js';
|
|
|
27
27
|
import { OpenActionMenu } from '../../common/open-action-menu/index.js';
|
|
28
28
|
import { FeatureCreateDrawer } from '../../common/feature-create-drawer/index.js';
|
|
29
29
|
import { PrdQuestionnaire } from '../../common/prd-questionnaire/index.js';
|
|
30
|
-
import {
|
|
30
|
+
import { TechReviewTabs } from '../../common/tech-review-tabs/index.js';
|
|
31
31
|
import { MergeReview } from '../../common/merge-review/index.js';
|
|
32
32
|
import { featureNodeStateConfig, lifecycleDisplayLabels } from '../../common/feature-node/index.js';
|
|
33
33
|
import { useFeatureActions } from '../../common/feature-drawer/use-feature-actions.js';
|
|
@@ -40,6 +40,9 @@ export function ControlCenterDrawer({ view, onClose, onDelete, isDeleting, onCre
|
|
|
40
40
|
// ── Tech decisions state ────────────────────────────────────────────────
|
|
41
41
|
const [techData, setTechData] = useState(null);
|
|
42
42
|
const [isLoadingTech, setIsLoadingTech] = useState(false);
|
|
43
|
+
// ── Product decisions state (for tech review Product tab) ─────────────
|
|
44
|
+
const [techProductData, setTechProductData] = useState(undefined);
|
|
45
|
+
const [isLoadingTechProduct, setIsLoadingTechProduct] = useState(false);
|
|
43
46
|
// ── Merge review state ──────────────────────────────────────────────────
|
|
44
47
|
const [mergeData, setMergeData] = useState(null);
|
|
45
48
|
const [isLoadingMerge, setIsLoadingMerge] = useState(false);
|
|
@@ -116,6 +119,33 @@ export function ControlCenterDrawer({ view, onClose, onDelete, isDeleting, onCre
|
|
|
116
119
|
cancelled = true;
|
|
117
120
|
};
|
|
118
121
|
}, [techFeatureId]);
|
|
122
|
+
// Fetch product decisions for the Product tab in tech review
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
setTechProductData(undefined);
|
|
125
|
+
if (!techFeatureId)
|
|
126
|
+
return;
|
|
127
|
+
let cancelled = false;
|
|
128
|
+
setIsLoadingTechProduct(true);
|
|
129
|
+
getFeatureArtifact(techFeatureId)
|
|
130
|
+
.then((result) => {
|
|
131
|
+
if (cancelled)
|
|
132
|
+
return;
|
|
133
|
+
if (result.productDecisions) {
|
|
134
|
+
setTechProductData(result.productDecisions);
|
|
135
|
+
}
|
|
136
|
+
// Silent failure — product tab shows "not available"
|
|
137
|
+
})
|
|
138
|
+
.catch(() => {
|
|
139
|
+
// Silent failure — the product tab is supplementary
|
|
140
|
+
})
|
|
141
|
+
.finally(() => {
|
|
142
|
+
if (!cancelled)
|
|
143
|
+
setIsLoadingTechProduct(false);
|
|
144
|
+
});
|
|
145
|
+
return () => {
|
|
146
|
+
cancelled = true;
|
|
147
|
+
};
|
|
148
|
+
}, [techFeatureId]);
|
|
119
149
|
const mergeFeatureId = view?.type === 'merge-review' ? view.node.featureId : null;
|
|
120
150
|
useEffect(() => {
|
|
121
151
|
setMergeData(null);
|
|
@@ -253,7 +283,7 @@ export function ControlCenterDrawer({ view, onClose, onDelete, isDeleting, onCre
|
|
|
253
283
|
// ── Header ──────────────────────────────────────────────────────────────
|
|
254
284
|
let header = undefined;
|
|
255
285
|
if (featureNode) {
|
|
256
|
-
header = (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: featureNode.name }), featureNode.description ? (_jsx(DrawerDescription, { children: featureNode.description })) : featureNode.featureId ? (_jsx(DrawerDescription, { className: "sr-only", children: featureNode.featureId })) : null] }), featureActionsInput ? (_jsxs("div", { className: "flex items-center gap-2 pt-2", children: [_jsx(OpenActionMenu, { actions: featureActions, repositoryPath: featureActionsInput.repositoryPath, showSpecs: !!featureActionsInput.specPath }), featureFlags.envDeploy && featureDeployTarget ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isFeatureDeployActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isFeatureDeployActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isFeatureDeployActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url })) : null] })) : null, onDelete && featureNode.featureId ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Delete feature", disabled: isDeleting, className: "text-muted-foreground hover:text-destructive ml-auto", "data-testid": "feature-drawer-delete", children: isDeleting ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Trash2, { className: "size-4" })) }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: featureNode.name }), " (", featureNode.featureId, "). This action cannot be undone.", featureNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(featureNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] })) : null] })) : null] }));
|
|
286
|
+
header = (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: featureNode.name }), featureNode.description ? (_jsx(DrawerDescription, { children: featureNode.description })) : featureNode.featureId ? (_jsx(DrawerDescription, { className: "sr-only", children: featureNode.featureId })) : null] }), featureActionsInput ? (_jsxs("div", { className: "flex items-center gap-2 pt-2", children: [_jsx(OpenActionMenu, { actions: featureActions, repositoryPath: featureActionsInput.repositoryPath, showSpecs: !!featureActionsInput.specPath }), featureFlags.envDeploy && featureDeployTarget ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isFeatureDeployActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isFeatureDeployActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isFeatureDeployActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: featureDeployTarget?.targetId })) : null] })) : null, onDelete && featureNode.featureId ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Delete feature", disabled: isDeleting, className: "text-muted-foreground hover:text-destructive ml-auto", "data-testid": "feature-drawer-delete", children: isDeleting ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Trash2, { className: "size-4" })) }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: featureNode.name }), " (", featureNode.featureId, "). This action cannot be undone.", featureNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(featureNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] })) : null] })) : null] }));
|
|
257
287
|
}
|
|
258
288
|
else if (repoData) {
|
|
259
289
|
header = (_jsxs("div", { "data-testid": "repository-drawer-header", children: [_jsx(DrawerTitle, { children: repoData.name }), repoData.repositoryPath ? (_jsx(DrawerDescription, { className: "truncate font-mono text-xs", children: repoData.repositoryPath })) : null] }));
|
|
@@ -267,13 +297,13 @@ export function ControlCenterDrawer({ view, onClose, onDelete, isDeleting, onCre
|
|
|
267
297
|
body = prdData ? (_jsx(PrdQuestionnaire, { data: prdData, selections: prdSelections, onSelect: (qId, oId) => setPrdSelections((prev) => ({ ...prev, [qId]: oId })), onApprove: handlePrdApprove, onReject: handlePrdReject, isProcessing: isLoadingPrd, isRejecting: isRejecting })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) }));
|
|
268
298
|
}
|
|
269
299
|
else if (view?.type === 'tech-review') {
|
|
270
|
-
body = techData ? (_jsx(
|
|
300
|
+
body = techData ? (_jsx(TechReviewTabs, { techData: techData, productData: isLoadingTechProduct ? null : techProductData, onApprove: handleTechApprove, onReject: handleTechReject, isProcessing: isLoadingTech, isRejecting: isRejecting })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) }));
|
|
271
301
|
}
|
|
272
302
|
else if (view?.type === 'merge-review') {
|
|
273
303
|
body = mergeData ? (_jsx(MergeReview, { data: mergeData, onApprove: handleMergeApprove, onReject: handleMergeReject, isProcessing: isLoadingMerge, isRejecting: isRejecting })) : (_jsx("div", { className: "flex items-center justify-center p-8", children: _jsx(Loader2, { className: "text-muted-foreground h-6 w-6 animate-spin" }) }));
|
|
274
304
|
}
|
|
275
305
|
else if (view?.type === 'repository' && repoData?.repositoryPath) {
|
|
276
|
-
body = (_jsxs(
|
|
306
|
+
body = (_jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsx(Separator, {}), _jsxs("div", { className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "OPEN WITH" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(ActionButton, { label: "Open in IDE", onClick: repoActions.openInIde, loading: repoActions.ideLoading, error: !!repoActions.ideError, icon: Code2, variant: "outline", size: "sm" }), _jsx(ActionButton, { label: "Open in Shell", onClick: repoActions.openInShell, loading: repoActions.shellLoading, error: !!repoActions.shellError, icon: Terminal, variant: "outline", size: "sm" }), _jsx(ActionButton, { label: "Open Folder", onClick: repoActions.openFolder, loading: repoActions.folderLoading, error: !!repoActions.folderError, icon: FolderOpen, variant: "outline", size: "sm" })] })] })] }));
|
|
277
307
|
}
|
|
278
308
|
// ── Render ──────────────────────────────────────────────────────────────
|
|
279
309
|
return (_jsxs(_Fragment, { children: [_jsx(BaseDrawer, { open: view !== null && !isCreateView, onClose: onClose, size: "md", modal: false, header: header, deployTarget: repoDeployTarget, "data-testid": view?.type === 'feature'
|
|
@@ -2,6 +2,7 @@ import { DeploymentState } from '../../../../../../packages/core/src/domain/gene
|
|
|
2
2
|
export interface DeploymentStatusBadgeProps {
|
|
3
3
|
status: DeploymentState | null;
|
|
4
4
|
url?: string | null;
|
|
5
|
+
targetId?: string;
|
|
5
6
|
}
|
|
6
|
-
export declare function DeploymentStatusBadge({ status, url }: DeploymentStatusBadgeProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export declare function DeploymentStatusBadge({ status, url, targetId }: DeploymentStatusBadgeProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
8
|
//# sourceMappingURL=deployment-status-badge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment-status-badge.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deployment-status-badge.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/deployment-status-badge/deployment-status-badge.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,0BAA0B,kDAgF1F"}
|