@shepai/cli 1.179.0 → 1.179.1
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 +17 -0
- package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/file-system-service.interface.d.ts +7 -0
- package/dist/packages/core/src/application/ports/output/services/file-system-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/shep-instance-service.interface.d.ts +22 -0
- package/dist/packages/core/src/application/ports/output/services/shep-instance-service.interface.d.ts.map +1 -0
- package/dist/packages/core/src/application/ports/output/services/shep-instance-service.interface.js +11 -0
- package/dist/packages/core/src/application/use-cases/deployments/get-deployment-status.use-case.d.ts +13 -0
- package/dist/packages/core/src/application/use-cases/deployments/get-deployment-status.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/deployments/get-deployment-status.use-case.js +37 -0
- package/dist/packages/core/src/application/use-cases/deployments/list-deployments.use-case.d.ts +14 -0
- package/dist/packages/core/src/application/use-cases/deployments/list-deployments.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/deployments/list-deployments.use-case.js +35 -0
- package/dist/packages/core/src/application/use-cases/deployments/start-feature-deployment.use-case.d.ts +27 -0
- package/dist/packages/core/src/application/use-cases/deployments/start-feature-deployment.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/deployments/start-feature-deployment.use-case.js +68 -0
- package/dist/packages/core/src/application/use-cases/deployments/start-repository-deployment.use-case.d.ts +23 -0
- package/dist/packages/core/src/application/use-cases/deployments/start-repository-deployment.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/deployments/start-repository-deployment.use-case.js +58 -0
- package/dist/packages/core/src/application/use-cases/deployments/stop-deployment.use-case.d.ts +13 -0
- package/dist/packages/core/src/application/use-cases/deployments/stop-deployment.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/deployments/stop-deployment.use-case.js +37 -0
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +29 -0
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts +9 -1
- 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 +66 -0
- package/dist/packages/core/src/infrastructure/services/file-system.service.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/file-system.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/file-system.service.js +4 -0
- package/dist/packages/core/src/infrastructure/services/shep-instance.service.d.ts +16 -0
- package/dist/packages/core/src/infrastructure/services/shep-instance.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/shep-instance.service.js +39 -0
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts +2 -0
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +9 -19
- package/dist/src/presentation/web/app/(dashboard)/layout.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/layout.js +3 -2
- package/dist/src/presentation/web/app/actions/deploy-feature.d.ts +1 -1
- package/dist/src/presentation/web/app/actions/deploy-feature.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/deploy-feature.js +4 -33
- package/dist/src/presentation/web/app/actions/deploy-repository.d.ts +1 -1
- package/dist/src/presentation/web/app/actions/deploy-repository.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/deploy-repository.js +4 -24
- package/dist/src/presentation/web/app/actions/get-deployment-status.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/get-deployment-status.js +2 -5
- package/dist/src/presentation/web/app/actions/list-deployments.d.ts +3 -0
- package/dist/src/presentation/web/app/actions/list-deployments.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/list-deployments.js +6 -0
- package/dist/src/presentation/web/app/actions/stop-deployment.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/stop-deployment.js +2 -5
- package/dist/src/presentation/web/app/api/graph-data/route.d.ts +1 -0
- package/dist/src/presentation/web/app/api/graph-data/route.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +7 -2
- package/dist/src/presentation/web/hooks/deployment-status-provider.d.ts +41 -0
- package/dist/src/presentation/web/hooks/deployment-status-provider.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/deployment-status-provider.js +205 -0
- package/dist/src/presentation/web/hooks/deployment-status-store.d.ts +42 -0
- package/dist/src/presentation/web/hooks/deployment-status-store.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/deployment-status-store.js +99 -0
- package/dist/src/presentation/web/hooks/use-deploy-action.d.ts +2 -6
- package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-deploy-action.js +42 -159
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +2 -2
- package/web/.next/required-server-files.json +2 -2
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +31 -31
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +39 -39
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +39 -39
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/chat/page.js +4 -4
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +31 -31
- package/web/.next/server/app/(dashboard)/create/page.js +4 -4
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +39 -39
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +39 -39
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/page.js +4 -4
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +4 -4
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- 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 +6 -6
- 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/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/api/interactive/chat/[featureId]/messages/route.js.nft.json +1 -1
- package/web/.next/server/app/features/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/features/page.js.nft.json +1 -1
- package/web/.next/server/app/features/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/settings/page.js +1 -1
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +13 -13
- package/web/.next/server/app/skills/page.js +2 -3
- 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 +11 -11
- package/web/.next/server/app/tools/page.js +1 -2
- 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 +6 -6
- 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/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_bdff55d6.js +3 -0
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_bdff55d6.js.map +1 -0
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_chat_page_actions_6aa77d75.js +3 -0
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_chat_page_actions_6aa77d75.js.map +1 -0
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_chat_page_actions_24adb073.js +3 -0
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_chat_page_actions_24adb073.js.map +1 -0
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js +2 -2
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__69dd3217._.js → [root-of-the-server]__16c1388b._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__69dd3217._.js.map → [root-of-the-server]__16c1388b._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6c7d3936._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6c7d3936._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__75070d2e._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__75070d2e._.js.map +1 -0
- package/web/.next/server/chunks/ssr/{_f8c55130._.js → [root-of-the-server]__7c634c0f._.js} +3 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7c634c0f._.js.map +1 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__1cd4327c._.js → [root-of-the-server]__8f02b364._.js} +3 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8f02b364._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9dde817e._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9dde817e._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a00db173._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a00db173._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cf751517._.js +4 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cf751517._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e0592c69._.js +3 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__4ed9b909._.js.map → [root-of-the-server]__e0592c69._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e5f31e9a._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e5f31e9a._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_15f6bbd4._.js +3 -0
- package/web/.next/server/chunks/ssr/{_7bfbaebc._.js.map → _15f6bbd4._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_16eb4fec._.js → _396a6887._.js} +2 -2
- package/web/.next/server/chunks/ssr/_396a6887._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_45496654._.js +1 -1
- package/web/.next/server/chunks/ssr/_45496654._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_496c9117._.js +1 -1
- package/web/.next/server/chunks/ssr/_496c9117._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_b384cf4d._.js → _5889596f._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_b384cf4d._.js.map → _5889596f._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_6abfa39e._.js +1 -1
- package/web/.next/server/chunks/ssr/_6abfa39e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_d9c0a97a._.js → _74a1a173._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_d9c0a97a._.js.map → _74a1a173._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_2b1e0171._.js → _7d50fed0._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_2b1e0171._.js.map → _7d50fed0._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_9bbdd461._.js +4 -0
- package/web/.next/server/chunks/ssr/_9bbdd461._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_bcd239dd._.js +3 -0
- package/web/.next/server/chunks/ssr/_bcd239dd._.js.map +1 -0
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_0338c789._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_0338c789._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_071f1e80._.js +5 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_071f1e80._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_55c1ff7d._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_55c1ff7d._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_9a543843._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_9a543843._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ad14a90f.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ad14a90f.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_bade80bd._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_bade80bd._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_skills_8a174cac._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_skills_8a174cac._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d5838156._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_d5838156._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_dc28bc60._.js +5 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_dc28bc60._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_dcb020e3._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_dcb020e3._.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 +51 -51
- package/web/.next/static/chunks/{c49b1801fada7fa4.js → 200e07d995bd9a42.js} +1 -1
- package/web/.next/static/chunks/22e3a3738308da2e.js +1 -0
- package/web/.next/static/chunks/{2e616ccf4645a26b.js → 25d3c4d18b8aecff.js} +1 -1
- package/web/.next/static/chunks/34444901ca3a1c3b.js +1 -0
- package/web/.next/static/chunks/{2265497d1f25f0b2.js → 3cf86457869c47bc.js} +1 -1
- package/web/.next/static/chunks/{0c5306088ba2ca1c.js → 55060446f5490f20.js} +3 -3
- package/web/.next/static/chunks/{697dff0baf6241e5.js → 59bff7b33ebe5f68.js} +1 -1
- package/web/.next/static/chunks/{8aa96e7709416478.js → 5a2bdbc57ed1368e.js} +1 -1
- package/web/.next/static/chunks/{d3d8e87d41b1d063.js → 981c6f3f1db99b4e.js} +1 -1
- package/web/.next/static/chunks/{46e2693dbc9262fd.js → c94a6a3d54dd4997.js} +2 -2
- package/web/.next/static/chunks/{6c660b0c1d5cf116.js → d04d868f0971941d.js} +1 -1
- package/web/.next/static/chunks/{9109f74856342d59.js → d26d0a7bc1a9b5a4.js} +1 -1
- package/web/.next/static/chunks/e7502fb670f32235.js +1 -0
- package/web/.next/static/chunks/{c1b52ddd382c063b.js → f5c61237675acc89.js} +1 -1
- package/web/.next/static/chunks/{53c9a26266f46989.js → fb7211d94190d010.js} +3 -3
- package/dist/src/presentation/web/lib/is-same-shep-instance.d.ts +0 -7
- package/dist/src/presentation/web/lib/is-same-shep-instance.d.ts.map +0 -1
- package/dist/src/presentation/web/lib/is-same-shep-instance.js +0 -18
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1cd4327c._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__46b10380._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__46b10380._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__4ed9b909._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__540c615f._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__540c615f._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8b512877._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8b512877._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__990dba2d._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__990dba2d._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cc9c7bbb._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cc9c7bbb._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js +0 -3
- package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_7bfbaebc._.js +0 -3
- package/web/.next/server/chunks/ssr/_f8c55130._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_06109d28._.js +0 -5
- package/web/.next/server/chunks/ssr/src_presentation_web_06109d28._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_0bca70f8._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_0bca70f8._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_367cdbe0._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_367cdbe0._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_57fed7fd._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_57fed7fd._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_7f567f6d._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_7f567f6d._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_972f58d5._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_972f58d5._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_4ce30db7.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_4ce30db7.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_e4032193.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_e4032193.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_a71b18a2._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_a71b18a2._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_bebe675e._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_bebe675e._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c93e8bc6._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_c93e8bc6._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e729f44a._.js +0 -5
- package/web/.next/server/chunks/ssr/src_presentation_web_e729f44a._.js.map +0 -1
- package/web/.next/static/chunks/2df108b69e81ba41.js +0 -1
- package/web/.next/static/chunks/477b12987135b175.js +0 -1
- package/web/.next/static/chunks/e3255a05122f168f.js +0 -1
- /package/web/.next/static/{4TvL4L8RNpkHhM-ORqvgP → mLJ1Qa4FUFmmZm0crRH2U}/_buildManifest.js +0 -0
- /package/web/.next/static/{4TvL4L8RNpkHhM-ORqvgP → mLJ1Qa4FUFmmZm0crRH2U}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{4TvL4L8RNpkHhM-ORqvgP → mLJ1Qa4FUFmmZm0crRH2U}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* DeploymentStatusProvider
|
|
5
|
+
*
|
|
6
|
+
* Wraps the dashboard with a shared deployment-status store seeded from
|
|
7
|
+
* SSR data (ListDeploymentsUseCase via get-graph-data). All components
|
|
8
|
+
* that call `useDeployAction(targetId)` subscribe to the same store, so
|
|
9
|
+
* the "click Run on node → tab shows URL instantly" bug and the
|
|
10
|
+
* "URL lost after refresh" bug are both resolved by construction.
|
|
11
|
+
*
|
|
12
|
+
* All business logic lives in use cases on the backend. This provider
|
|
13
|
+
* owns only UI state transitions: which entries are hydrated, which are
|
|
14
|
+
* loading, which have errors, and which need polling.
|
|
15
|
+
*/
|
|
16
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, } from 'react';
|
|
17
|
+
import { deployFeature } from '../app/actions/deploy-feature.js';
|
|
18
|
+
import { deployRepository } from '../app/actions/deploy-repository.js';
|
|
19
|
+
import { stopDeployment } from '../app/actions/stop-deployment.js';
|
|
20
|
+
import { getDeploymentStatus } from '../app/actions/get-deployment-status.js';
|
|
21
|
+
import { createLogger } from '../lib/logger.js';
|
|
22
|
+
import { DeploymentStatusStore, EMPTY_ENTRY, } from './deployment-status-store.js';
|
|
23
|
+
const log = createLogger('[DeploymentStatusProvider]');
|
|
24
|
+
const POLL_INTERVAL_MS = 3000;
|
|
25
|
+
const ACTIVE_STATES = new Set([
|
|
26
|
+
'Booting',
|
|
27
|
+
'Ready',
|
|
28
|
+
]);
|
|
29
|
+
const DeploymentStatusContext = createContext(null);
|
|
30
|
+
export function DeploymentStatusProvider({ initialDeployments, children, }) {
|
|
31
|
+
// One store per provider instance. Stable across renders.
|
|
32
|
+
const storeRef = useRef(null);
|
|
33
|
+
if (!storeRef.current) {
|
|
34
|
+
storeRef.current = new DeploymentStatusStore();
|
|
35
|
+
storeRef.current.hydrate(initialDeployments);
|
|
36
|
+
}
|
|
37
|
+
const store = storeRef.current;
|
|
38
|
+
// Re-hydrate when SSR data changes (e.g. after graph-data poll).
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
store.hydrate(initialDeployments);
|
|
41
|
+
}, [initialDeployments, store]);
|
|
42
|
+
// ── Polling ──────────────────────────────────────────────────────────
|
|
43
|
+
// One interval per targetId. Started when an entry becomes active
|
|
44
|
+
// (Booting/Ready) and stopped when it is no longer active.
|
|
45
|
+
const pollIntervalsRef = useRef(new Map());
|
|
46
|
+
const stopPolling = useCallback((targetId) => {
|
|
47
|
+
const existing = pollIntervalsRef.current.get(targetId);
|
|
48
|
+
if (existing) {
|
|
49
|
+
clearInterval(existing);
|
|
50
|
+
pollIntervalsRef.current.delete(targetId);
|
|
51
|
+
}
|
|
52
|
+
}, []);
|
|
53
|
+
const startPolling = useCallback((targetId) => {
|
|
54
|
+
if (pollIntervalsRef.current.has(targetId))
|
|
55
|
+
return;
|
|
56
|
+
const interval = setInterval(async () => {
|
|
57
|
+
let result;
|
|
58
|
+
try {
|
|
59
|
+
result = await getDeploymentStatus(targetId);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
log.warn(`poll failed for "${targetId}"`, err);
|
|
63
|
+
store.setStatus(targetId, null);
|
|
64
|
+
stopPolling(targetId);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!result || result.state === 'Stopped') {
|
|
68
|
+
store.setStatus(targetId, null);
|
|
69
|
+
stopPolling(targetId);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
store.setStatus(targetId, result);
|
|
73
|
+
}, POLL_INTERVAL_MS);
|
|
74
|
+
pollIntervalsRef.current.set(targetId, interval);
|
|
75
|
+
}, [store, stopPolling]);
|
|
76
|
+
// Reconcile polling with store state on every change.
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const intervals = pollIntervalsRef.current;
|
|
79
|
+
const reconcile = () => {
|
|
80
|
+
// Stop polls for entries that are no longer active.
|
|
81
|
+
for (const [targetId] of intervals) {
|
|
82
|
+
const entry = store.getEntry(targetId);
|
|
83
|
+
if (!entry.status || !ACTIVE_STATES.has(entry.status)) {
|
|
84
|
+
stopPolling(targetId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const unsubscribe = store.subscribeAll(reconcile);
|
|
89
|
+
return () => {
|
|
90
|
+
unsubscribe();
|
|
91
|
+
for (const [, interval] of intervals)
|
|
92
|
+
clearInterval(interval);
|
|
93
|
+
intervals.clear();
|
|
94
|
+
};
|
|
95
|
+
}, [store, stopPolling]);
|
|
96
|
+
// ── Mount hydration per targetId ─────────────────────────────────────
|
|
97
|
+
// When a hook subscribes to a targetId that was not in the SSR hydration
|
|
98
|
+
// (e.g. a stale page with deployments started in another tab), fetch its
|
|
99
|
+
// status once from the backend via getDeploymentStatus → use case.
|
|
100
|
+
const ensureHydrated = useCallback((targetId) => {
|
|
101
|
+
if (!targetId)
|
|
102
|
+
return;
|
|
103
|
+
const entry = store.getEntry(targetId);
|
|
104
|
+
if (entry.hydrated)
|
|
105
|
+
return;
|
|
106
|
+
// Mark hydrated immediately to dedupe concurrent callers.
|
|
107
|
+
store.update(targetId, { hydrated: true });
|
|
108
|
+
void (async () => {
|
|
109
|
+
try {
|
|
110
|
+
const result = await getDeploymentStatus(targetId);
|
|
111
|
+
store.setStatus(targetId, result);
|
|
112
|
+
if (result && ACTIVE_STATES.has(result.state))
|
|
113
|
+
startPolling(targetId);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
log.warn(`ensureHydrated failed for "${targetId}"`, err);
|
|
117
|
+
}
|
|
118
|
+
})();
|
|
119
|
+
}, [store, startPolling]);
|
|
120
|
+
// ── Actions ──────────────────────────────────────────────────────────
|
|
121
|
+
const deploy = useCallback(async (input) => {
|
|
122
|
+
store.update(input.targetId, { deployLoading: true, deployError: null });
|
|
123
|
+
try {
|
|
124
|
+
const result = input.targetType === 'feature'
|
|
125
|
+
? await deployFeature(input.targetId)
|
|
126
|
+
: await deployRepository(input.repositoryPath);
|
|
127
|
+
if (!result.success) {
|
|
128
|
+
store.update(input.targetId, {
|
|
129
|
+
deployLoading: false,
|
|
130
|
+
deployError: result.error ?? 'An unexpected error occurred',
|
|
131
|
+
});
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
store.update(input.targetId, {
|
|
135
|
+
deployLoading: false,
|
|
136
|
+
status: result.state ?? null,
|
|
137
|
+
url: null,
|
|
138
|
+
hydrated: true,
|
|
139
|
+
targetType: input.targetType,
|
|
140
|
+
});
|
|
141
|
+
startPolling(input.targetId);
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
const message = err instanceof Error ? err.message : 'An unexpected error occurred';
|
|
145
|
+
store.update(input.targetId, { deployLoading: false, deployError: message });
|
|
146
|
+
}
|
|
147
|
+
}, [store, startPolling]);
|
|
148
|
+
const stop = useCallback(async (targetId) => {
|
|
149
|
+
if (!targetId)
|
|
150
|
+
return;
|
|
151
|
+
store.update(targetId, { stopLoading: true });
|
|
152
|
+
try {
|
|
153
|
+
const result = await stopDeployment(targetId);
|
|
154
|
+
if (result.success) {
|
|
155
|
+
stopPolling(targetId);
|
|
156
|
+
store.update(targetId, {
|
|
157
|
+
stopLoading: false,
|
|
158
|
+
status: null,
|
|
159
|
+
url: null,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
store.update(targetId, { stopLoading: false });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
log.warn('stop error (non-critical)', err);
|
|
168
|
+
store.update(targetId, { stopLoading: false });
|
|
169
|
+
}
|
|
170
|
+
}, [store, stopPolling]);
|
|
171
|
+
const value = useMemo(() => ({ store, deploy, stop, ensureHydrated }), [store, deploy, stop, ensureHydrated]);
|
|
172
|
+
return (_jsx(DeploymentStatusContext.Provider, { value: value, children: children }));
|
|
173
|
+
}
|
|
174
|
+
export function useDeploymentStatusContext() {
|
|
175
|
+
const ctx = useContext(DeploymentStatusContext);
|
|
176
|
+
if (!ctx) {
|
|
177
|
+
throw new Error('useDeploymentStatusContext must be used within a <DeploymentStatusProvider>');
|
|
178
|
+
}
|
|
179
|
+
return ctx;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Non-throwing variant used by presentational hooks (e.g. useDeployAction)
|
|
183
|
+
* that may render inside Storybook or other isolated contexts without
|
|
184
|
+
* a provider. Returns a stub store/actions that do nothing.
|
|
185
|
+
*/
|
|
186
|
+
export function useDeploymentStatusContextOptional() {
|
|
187
|
+
const ctx = useContext(DeploymentStatusContext);
|
|
188
|
+
if (ctx)
|
|
189
|
+
return ctx;
|
|
190
|
+
return FALLBACK_CONTEXT;
|
|
191
|
+
}
|
|
192
|
+
const FALLBACK_STORE = new DeploymentStatusStore();
|
|
193
|
+
const FALLBACK_CONTEXT = {
|
|
194
|
+
store: FALLBACK_STORE,
|
|
195
|
+
deploy: async () => {
|
|
196
|
+
/* no-op */
|
|
197
|
+
},
|
|
198
|
+
stop: async () => {
|
|
199
|
+
/* no-op */
|
|
200
|
+
},
|
|
201
|
+
ensureHydrated: () => {
|
|
202
|
+
/* no-op */
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
export { EMPTY_ENTRY };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Status Store
|
|
3
|
+
*
|
|
4
|
+
* External store (useSyncExternalStore-compatible) that holds the shared
|
|
5
|
+
* deployment state keyed by targetId. Multiple components subscribed to
|
|
6
|
+
* the same targetId see the same state — fixes the node/drawer-out-of-sync
|
|
7
|
+
* bug and makes page-refresh hydration trivial.
|
|
8
|
+
*
|
|
9
|
+
* Mutation paths (deploy/stop/poll) go through server actions that wrap
|
|
10
|
+
* use cases — this module stores state only and never contains business
|
|
11
|
+
* logic.
|
|
12
|
+
*/
|
|
13
|
+
import type { DeploymentState } from '../../../../packages/core/src/domain/generated/output.js';
|
|
14
|
+
import type { DeploymentStatus, DeploymentStatusEntry } from '../../../../packages/core/src/application/ports/output/services/deployment-service.interface.js';
|
|
15
|
+
export interface DeploymentEntryState {
|
|
16
|
+
status: DeploymentState | null;
|
|
17
|
+
url: string | null;
|
|
18
|
+
targetType: string | null;
|
|
19
|
+
/** Whether mount-hydration (listDeployments / getDeploymentStatus) has completed for this targetId. */
|
|
20
|
+
hydrated: boolean;
|
|
21
|
+
deployLoading: boolean;
|
|
22
|
+
stopLoading: boolean;
|
|
23
|
+
deployError: string | null;
|
|
24
|
+
}
|
|
25
|
+
export declare const EMPTY_ENTRY: DeploymentEntryState;
|
|
26
|
+
type Listener = () => void;
|
|
27
|
+
export declare class DeploymentStatusStore {
|
|
28
|
+
private entries;
|
|
29
|
+
private listeners;
|
|
30
|
+
private globalListeners;
|
|
31
|
+
/** Seed the store from SSR data (ListDeploymentsUseCase output). */
|
|
32
|
+
hydrate(entries: DeploymentStatusEntry[]): void;
|
|
33
|
+
getEntry(targetId: string): DeploymentEntryState;
|
|
34
|
+
update(targetId: string, patch: Partial<DeploymentEntryState>): void;
|
|
35
|
+
/** Apply a status snapshot (from a server action result) to a targetId. */
|
|
36
|
+
setStatus(targetId: string, status: DeploymentStatus | null): void;
|
|
37
|
+
subscribe(targetId: string, listener: Listener): () => void;
|
|
38
|
+
subscribeAll(listener: Listener): () => void;
|
|
39
|
+
private notify;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=deployment-status-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-status-store.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/deployment-status-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,KAAK,EACV,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,6EAA6E,CAAC;AAErF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uGAAuG;IACvG,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,eAAO,MAAM,WAAW,EAAE,oBAQzB,CAAC;AAEF,KAAK,QAAQ,GAAG,MAAM,IAAI,CAAC;AAE3B,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,eAAe,CAAuB;IAE9C,oEAAoE;IACpE,OAAO,CAAC,OAAO,EAAE,qBAAqB,EAAE,GAAG,IAAI;IAwB/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB;IAIhD,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,IAAI;IAOpE,2EAA2E;IAC3E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAYlE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI;IAa3D,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI;IAO5C,OAAO,CAAC,MAAM;CAKf"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Status Store
|
|
3
|
+
*
|
|
4
|
+
* External store (useSyncExternalStore-compatible) that holds the shared
|
|
5
|
+
* deployment state keyed by targetId. Multiple components subscribed to
|
|
6
|
+
* the same targetId see the same state — fixes the node/drawer-out-of-sync
|
|
7
|
+
* bug and makes page-refresh hydration trivial.
|
|
8
|
+
*
|
|
9
|
+
* Mutation paths (deploy/stop/poll) go through server actions that wrap
|
|
10
|
+
* use cases — this module stores state only and never contains business
|
|
11
|
+
* logic.
|
|
12
|
+
*/
|
|
13
|
+
export const EMPTY_ENTRY = {
|
|
14
|
+
status: null,
|
|
15
|
+
url: null,
|
|
16
|
+
targetType: null,
|
|
17
|
+
hydrated: false,
|
|
18
|
+
deployLoading: false,
|
|
19
|
+
stopLoading: false,
|
|
20
|
+
deployError: null,
|
|
21
|
+
};
|
|
22
|
+
export class DeploymentStatusStore {
|
|
23
|
+
entries = new Map();
|
|
24
|
+
listeners = new Map();
|
|
25
|
+
globalListeners = new Set();
|
|
26
|
+
/** Seed the store from SSR data (ListDeploymentsUseCase output). */
|
|
27
|
+
hydrate(entries) {
|
|
28
|
+
// Mark every SSR entry as hydrated and merge into the map.
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
seen.add(entry.targetId);
|
|
32
|
+
this.update(entry.targetId, {
|
|
33
|
+
status: entry.state,
|
|
34
|
+
url: entry.url,
|
|
35
|
+
targetType: entry.targetType,
|
|
36
|
+
hydrated: true,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Any previously tracked entries missing from the SSR list are stale —
|
|
40
|
+
// mark them hydrated with null state so subscribers learn their
|
|
41
|
+
// deployment is gone.
|
|
42
|
+
for (const [targetId, existing] of this.entries) {
|
|
43
|
+
if (!seen.has(targetId) && existing.hydrated && existing.status !== null) {
|
|
44
|
+
this.update(targetId, { status: null, url: null });
|
|
45
|
+
}
|
|
46
|
+
else if (!seen.has(targetId) && !existing.hydrated) {
|
|
47
|
+
this.update(targetId, { hydrated: true });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
getEntry(targetId) {
|
|
52
|
+
return this.entries.get(targetId) ?? EMPTY_ENTRY;
|
|
53
|
+
}
|
|
54
|
+
update(targetId, patch) {
|
|
55
|
+
const current = this.entries.get(targetId) ?? EMPTY_ENTRY;
|
|
56
|
+
const next = { ...current, ...patch };
|
|
57
|
+
this.entries.set(targetId, next);
|
|
58
|
+
this.notify(targetId);
|
|
59
|
+
}
|
|
60
|
+
/** Apply a status snapshot (from a server action result) to a targetId. */
|
|
61
|
+
setStatus(targetId, status) {
|
|
62
|
+
if (status === null) {
|
|
63
|
+
this.update(targetId, { status: null, url: null, hydrated: true });
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
this.update(targetId, {
|
|
67
|
+
status: status.state,
|
|
68
|
+
url: status.url,
|
|
69
|
+
hydrated: true,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
subscribe(targetId, listener) {
|
|
73
|
+
let set = this.listeners.get(targetId);
|
|
74
|
+
if (!set) {
|
|
75
|
+
set = new Set();
|
|
76
|
+
this.listeners.set(targetId, set);
|
|
77
|
+
}
|
|
78
|
+
set.add(listener);
|
|
79
|
+
return () => {
|
|
80
|
+
set?.delete(listener);
|
|
81
|
+
if (set?.size === 0)
|
|
82
|
+
this.listeners.delete(targetId);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
subscribeAll(listener) {
|
|
86
|
+
this.globalListeners.add(listener);
|
|
87
|
+
return () => {
|
|
88
|
+
this.globalListeners.delete(listener);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
notify(targetId) {
|
|
92
|
+
const set = this.listeners.get(targetId);
|
|
93
|
+
if (set)
|
|
94
|
+
for (const l of set)
|
|
95
|
+
l();
|
|
96
|
+
for (const l of this.globalListeners)
|
|
97
|
+
l();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type { DeploymentState } from '../../../../packages/core/src/domain/generated/output.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
targetType: 'feature' | 'repository';
|
|
5
|
-
repositoryPath: string;
|
|
6
|
-
branch?: string;
|
|
7
|
-
}
|
|
2
|
+
import { type DeployActionInput } from './deployment-status-provider.js';
|
|
3
|
+
export type { DeployActionInput };
|
|
8
4
|
export interface DeployActionState {
|
|
9
5
|
deploy: () => Promise<void>;
|
|
10
6
|
stop: () => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-deploy-action.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-deploy-action.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-deploy-action.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-deploy-action.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAOlC,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,iBAAiB,CA0ClF"}
|
|
@@ -1,171 +1,54 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
/**
|
|
3
|
+
* useDeployAction
|
|
4
|
+
*
|
|
5
|
+
* Thin subscriber to the shared DeploymentStatusProvider, scoped to one
|
|
6
|
+
* targetId. All components that call this hook with the same targetId
|
|
7
|
+
* see the same state — a click on a node updates the drawer instantly,
|
|
8
|
+
* and state survives page refresh via SSR hydration.
|
|
9
|
+
*
|
|
10
|
+
* Business logic (start/stop/status) lives in backend use cases — this
|
|
11
|
+
* hook contains zero decision-making code.
|
|
12
|
+
*/
|
|
13
|
+
import { useEffect, useSyncExternalStore, useCallback } from 'react';
|
|
14
|
+
import { useDeploymentStatusContextOptional, } from './deployment-status-provider.js';
|
|
15
|
+
/** Stable no-op unsubscribe for hooks called with a null input. */
|
|
16
|
+
function noop() {
|
|
17
|
+
/* no-op */
|
|
18
|
+
}
|
|
10
19
|
export function useDeployAction(input) {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}, [status]);
|
|
23
|
-
// Track mounted state
|
|
20
|
+
const { store, deploy, stop, ensureHydrated } = useDeploymentStatusContextOptional();
|
|
21
|
+
const targetId = input?.targetId ?? '';
|
|
22
|
+
// Subscribe to the store entry for this targetId.
|
|
23
|
+
const subscribe = useCallback((listener) => {
|
|
24
|
+
if (!targetId)
|
|
25
|
+
return noop;
|
|
26
|
+
return store.subscribe(targetId, listener);
|
|
27
|
+
}, [store, targetId]);
|
|
28
|
+
const getSnapshot = useCallback(() => (targetId ? store.getEntry(targetId) : store.getEntry('')), [store, targetId]);
|
|
29
|
+
const entry = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
30
|
+
// On mount (or when targetId changes), ensure the entry is hydrated.
|
|
24
31
|
useEffect(() => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
}, []);
|
|
30
|
-
// Mount recovery removed — getGraphData() already enriches nodes with
|
|
31
|
-
// deployment status (get-graph-data.ts lines 180-200). No need to call
|
|
32
|
-
// a server action per node on every mount.
|
|
33
|
-
// Cleanup on unmount
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
return () => {
|
|
36
|
-
if (pollIntervalRef.current)
|
|
37
|
-
clearInterval(pollIntervalRef.current);
|
|
38
|
-
};
|
|
39
|
-
}, []);
|
|
40
|
-
const stopPolling = useCallback(() => {
|
|
41
|
-
if (pollIntervalRef.current) {
|
|
42
|
-
log.debug('stopping polling');
|
|
43
|
-
clearInterval(pollIntervalRef.current);
|
|
44
|
-
pollIntervalRef.current = null;
|
|
45
|
-
}
|
|
46
|
-
}, []);
|
|
47
|
-
const startPolling = useCallback((targetId) => {
|
|
48
|
-
stopPolling();
|
|
49
|
-
log.debug(`starting polling for "${targetId}" every ${POLL_INTERVAL}ms`);
|
|
50
|
-
pollIntervalRef.current = setInterval(async () => {
|
|
51
|
-
if (!mountedRef.current) {
|
|
52
|
-
stopPolling();
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
let result;
|
|
56
|
-
try {
|
|
57
|
-
result = await getDeploymentStatus(targetId);
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
log.warn(`poll fetch failed for "${targetId}":`, err);
|
|
61
|
-
// Treat fetch failure as deployment gone — clear UI
|
|
62
|
-
if (mountedRef.current) {
|
|
63
|
-
setStatus(null);
|
|
64
|
-
setUrl(null);
|
|
65
|
-
stopPolling();
|
|
66
|
-
}
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
if (!mountedRef.current)
|
|
70
|
-
return;
|
|
71
|
-
if (!result || result.state === 'Stopped') {
|
|
72
|
-
log.info(`poll result: ${result ? `state=${result.state}` : 'null (deployment gone)'} — stopping poll`);
|
|
73
|
-
setStatus(null);
|
|
74
|
-
setUrl(null);
|
|
75
|
-
stopPolling();
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
if (result.state !== statusRef.current) {
|
|
79
|
-
log.info(`poll state changed: ${statusRef.current} → ${result.state}, url=${result.url}`);
|
|
80
|
-
}
|
|
81
|
-
setStatus(result.state);
|
|
82
|
-
setUrl(result.url);
|
|
83
|
-
}
|
|
84
|
-
}, POLL_INTERVAL);
|
|
85
|
-
}, [stopPolling]);
|
|
86
|
-
// Idle poll removed — it was calling getDeploymentStatus every 5s for EVERY
|
|
87
|
-
// node on the canvas (~25 nodes = ~5 server action calls/sec). The mount
|
|
88
|
-
// recovery effect above (line 57) already checks on mount. Deployments
|
|
89
|
-
// started externally (e.g., from the drawer) should update the node via
|
|
90
|
-
// reconcile from the graph-data poll instead.
|
|
32
|
+
if (targetId)
|
|
33
|
+
ensureHydrated(targetId);
|
|
34
|
+
}, [targetId, ensureHydrated]);
|
|
91
35
|
const handleDeploy = useCallback(async () => {
|
|
92
|
-
if (!input)
|
|
93
|
-
log.warn('deploy() called but input is null — no-op');
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (deployLoading) {
|
|
97
|
-
log.warn('deploy() called but already loading — no-op');
|
|
36
|
+
if (!input)
|
|
98
37
|
return;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
setDeployLoading(true);
|
|
102
|
-
setDeployError(null);
|
|
103
|
-
try {
|
|
104
|
-
const result = input.targetType === 'feature'
|
|
105
|
-
? await deployFeature(input.targetId)
|
|
106
|
-
: await deployRepository(input.repositoryPath);
|
|
107
|
-
log.info('server action result:', result);
|
|
108
|
-
if (!mountedRef.current) {
|
|
109
|
-
log.warn('component unmounted after deploy — discarding result');
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (!result.success) {
|
|
113
|
-
const errorMessage = result.error ?? 'An unexpected error occurred';
|
|
114
|
-
log.warn(`deploy failed: ${errorMessage}`);
|
|
115
|
-
setDeployError(errorMessage);
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
log.info(`deploy succeeded — initial state=${result.state}, starting polling`);
|
|
119
|
-
setStatus(result.state ?? null);
|
|
120
|
-
setUrl(null);
|
|
121
|
-
startPolling(input.targetId);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
if (!mountedRef.current)
|
|
126
|
-
return;
|
|
127
|
-
const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred';
|
|
128
|
-
log.error(`deploy threw exception: ${errorMessage}`, err);
|
|
129
|
-
setDeployError(errorMessage);
|
|
130
|
-
}
|
|
131
|
-
finally {
|
|
132
|
-
if (mountedRef.current) {
|
|
133
|
-
setDeployLoading(false);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}, [input, deployLoading, startPolling]);
|
|
38
|
+
await deploy(input);
|
|
39
|
+
}, [deploy, input]);
|
|
137
40
|
const handleStop = useCallback(async () => {
|
|
138
|
-
if (!
|
|
41
|
+
if (!targetId)
|
|
139
42
|
return;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
const result = await stopDeployment(input.targetId);
|
|
144
|
-
log.info('stop result:', result);
|
|
145
|
-
if (!mountedRef.current)
|
|
146
|
-
return;
|
|
147
|
-
if (result.success) {
|
|
148
|
-
stopPolling();
|
|
149
|
-
setStatus(null);
|
|
150
|
-
setUrl(null);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
catch (err) {
|
|
154
|
-
log.warn('stop error (non-critical):', err);
|
|
155
|
-
}
|
|
156
|
-
finally {
|
|
157
|
-
if (mountedRef.current) {
|
|
158
|
-
setStopLoading(false);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}, [input, stopLoading, stopPolling]);
|
|
43
|
+
await stop(targetId);
|
|
44
|
+
}, [stop, targetId]);
|
|
162
45
|
return {
|
|
163
46
|
deploy: handleDeploy,
|
|
164
47
|
stop: handleStop,
|
|
165
|
-
deployLoading,
|
|
166
|
-
stopLoading,
|
|
167
|
-
deployError,
|
|
168
|
-
status,
|
|
169
|
-
url,
|
|
48
|
+
deployLoading: entry.deployLoading,
|
|
49
|
+
stopLoading: entry.stopLoading,
|
|
50
|
+
deployError: entry.deployError,
|
|
51
|
+
status: entry.status,
|
|
52
|
+
url: entry.url,
|
|
170
53
|
};
|
|
171
54
|
}
|