@shepai/cli 1.72.9-pr220.e1bfec0 → 1.72.9-pr220.f17b60a
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/infrastructure/services/notifications/notification.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/notifications/notification.service.js +2 -4
- package/dist/src/presentation/web/app/build-feature-node-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/build-feature-node-data.js +2 -26
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
- package/dist/src/presentation/web/app/build-graph-nodes.js +2 -26
- package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/create-drawer-client.js +0 -2
- package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts +2 -0
- package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/drawer-view.js +11 -11
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +17 -27
- package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts +0 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/index.js +0 -1
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts +25 -0
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +45 -2
- package/dist/src/presentation/web/components/common/index.d.ts +1 -2
- package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/index.js +1 -2
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +3 -4
- 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 +46 -58
- package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +2 -13
- package/dist/src/presentation/web/components/ui/alert-dialog.d.ts.map +1 -1
- package/dist/src/presentation/web/components/ui/alert-dialog.js +2 -2
- package/dist/src/presentation/web/components/ui/dialog.d.ts.map +1 -1
- package/dist/src/presentation/web/components/ui/dialog.js +2 -2
- package/dist/src/presentation/web/hooks/use-agent-events.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-agent-events.js +6 -3
- package/dist/src/presentation/web/hooks/use-graph-state.d.ts +2 -1
- package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-graph-state.js +50 -23
- package/dist/src/presentation/web/hooks/use-notifications.d.ts +1 -5
- package/dist/src/presentation/web/hooks/use-notifications.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-notifications.js +1 -26
- package/dist/src/presentation/web/hooks/use-notifications.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-notifications.stories.js +28 -38
- 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/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/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +15 -15
- 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]/page/server-reference-manifest.json +18 -18
- 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]/page/server-reference-manifest.json +13 -13
- 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)/create/page/server-reference-manifest.json +15 -15
- 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]/page/server-reference-manifest.json +18 -18
- 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 +13 -13
- 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]/page/server-reference-manifest.json +13 -13
- 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 +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
- 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 +6 -6
- 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_client-reference-manifest.js +1 -1
- 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/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -1
- 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]__6cbc1149._.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]__94a6d275._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_07c2a32a._.js +1 -1
- package/web/.next/server/chunks/ssr/_07c2a32a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
- package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_250a63ae._.js +1 -1
- package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
- package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
- package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_63688261._.js → _8e87c87b._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_63688261._.js.map → _8e87c87b._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
- package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js.map +1 -1
- 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 +21 -21
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- 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/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +15 -15
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +18 -18
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +13 -13
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +15 -15
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +18 -18
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +13 -13
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +13 -13
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- 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_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
- 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 +6 -6
- 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_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2018e25f._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
- 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]__6cbc1149._.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]__94a6d275._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_07c2a32a._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_250a63ae._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_63688261._.js → _8e87c87b._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +2 -2
- 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 +21 -21
- package/web/.next/standalone/src/presentation/web/app/build-feature-node-data.ts +3 -30
- package/web/.next/standalone/src/presentation/web/app/build-graph-nodes.ts +3 -30
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +0 -2
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/drawer-view.ts +12 -13
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +21 -37
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/index.ts +0 -1
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +63 -2
- package/web/.next/standalone/src/presentation/web/components/common/index.ts +1 -7
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +12 -21
- package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +65 -70
- package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +1 -18
- package/web/.next/standalone/src/presentation/web/components/ui/alert-dialog.tsx +2 -5
- package/web/.next/standalone/src/presentation/web/components/ui/dialog.tsx +2 -5
- package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +7 -3
- package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +104 -71
- package/web/.next/standalone/src/presentation/web/hooks/use-notifications.stories.tsx +2 -30
- package/web/.next/standalone/src/presentation/web/hooks/use-notifications.ts +2 -36
- package/web/.next/static/chunks/0ffccd7be73305c8.css +2 -0
- package/web/.next/static/chunks/3f205fd6adbfd20a.js +7 -0
- package/web/.next/static/chunks/76827713cb2b7333.js +1 -0
- package/web/.next/static/chunks/{c575ab63c138645b.js → 792aac476adb5875.js} +1 -1
- package/web/.next/static/chunks/7c8adcfd920a8f74.js +1 -0
- package/web/.next/static/chunks/{cdc92cdf81005c84.js → 83463b63971f5723.js} +1 -1
- package/web/.next/static/chunks/{63a80e9d4c4b0253.js → 98ca891a5c156aa5.js} +3 -3
- package/web/.next/static/chunks/{638824249d103905.js → 9b1770f05f1d95e5.js} +1 -1
- package/web/.next/static/chunks/a7f52757dff0cea0.js +1 -0
- package/web/.next/static/chunks/b6becf0de992842a.js +1 -0
- package/web/.next/static/chunks/{f32c98a709949c5b.js → cb41849bcfaa304e.js} +1 -1
- package/web/.next/static/chunks/d5e95c4482029a39.js +1 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts +0 -12
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.js +0 -337
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts +0 -33
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.js +0 -214
- package/dist/src/presentation/web/components/common/notification-permission-banner/index.d.ts +0 -2
- package/dist/src/presentation/web/components/common/notification-permission-banner/index.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/notification-permission-banner/index.js +0 -1
- package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.d.ts +0 -2
- package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.js +0 -33
- package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.d.ts +0 -6
- package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.js +0 -24
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.stories.tsx +0 -293
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/control-center-drawer.tsx +0 -745
- package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/index.ts +0 -1
- package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.stories.tsx +0 -52
- package/web/.next/standalone/src/presentation/web/components/common/notification-permission-banner/notification-permission-banner.tsx +0 -55
- package/web/.next/static/chunks/0a883e2efecfd563.js +0 -1
- package/web/.next/static/chunks/0c54314c8c9c9739.js +0 -7
- package/web/.next/static/chunks/596ca28d78baae25.js +0 -1
- package/web/.next/static/chunks/71c9ecdceac1939f.css +0 -2
- package/web/.next/static/chunks/a040b058d79f4ade.js +0 -1
- package/web/.next/static/chunks/e05eb1cc84ee254a.js +0 -1
- package/web/.next/static/chunks/ef8f8940eac6c542.js +0 -1
- /package/web/.next/static/{uMxPSDPwZCludF5408rWJ → eg0FTlsA4z_7CXbFfMgAr}/_buildManifest.js +0 -0
- /package/web/.next/static/{uMxPSDPwZCludF5408rWJ → eg0FTlsA4z_7CXbFfMgAr}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{uMxPSDPwZCludF5408rWJ → eg0FTlsA4z_7CXbFfMgAr}/_ssgManifest.js +0 -0
|
@@ -2,47 +2,20 @@ import type { Feature, AgentRun } from '@shepai/core/domain/generated/output';
|
|
|
2
2
|
import {
|
|
3
3
|
deriveNodeState,
|
|
4
4
|
deriveProgress,
|
|
5
|
+
deriveLifecycle,
|
|
5
6
|
} from '@/components/common/feature-node/derive-feature-state';
|
|
6
|
-
import type { FeatureNodeData
|
|
7
|
-
|
|
8
|
-
/** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
|
|
9
|
-
const lifecycleMap: Record<string, FeatureLifecyclePhase> = {
|
|
10
|
-
Requirements: 'requirements',
|
|
11
|
-
Research: 'research',
|
|
12
|
-
Implementation: 'implementation',
|
|
13
|
-
Review: 'review',
|
|
14
|
-
'Deploy & QA': 'deploy',
|
|
15
|
-
Maintain: 'maintain',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
|
|
19
|
-
const nodeToLifecyclePhase: Record<string, FeatureLifecyclePhase> = {
|
|
20
|
-
analyze: 'requirements',
|
|
21
|
-
requirements: 'requirements',
|
|
22
|
-
research: 'research',
|
|
23
|
-
plan: 'implementation',
|
|
24
|
-
implement: 'implementation',
|
|
25
|
-
merge: 'review',
|
|
26
|
-
};
|
|
7
|
+
import type { FeatureNodeData } from '@/components/common/feature-node';
|
|
27
8
|
|
|
28
9
|
/**
|
|
29
10
|
* Builds a FeatureNodeData object from a Feature entity and optional AgentRun.
|
|
30
11
|
* This is the single-feature version of the logic in `buildGraphNodes`.
|
|
31
12
|
*/
|
|
32
13
|
export function buildFeatureNodeData(feature: Feature, run: AgentRun | null): FeatureNodeData {
|
|
33
|
-
const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
|
|
34
|
-
const lifecycle: FeatureLifecyclePhase =
|
|
35
|
-
run?.status === 'completed'
|
|
36
|
-
? 'maintain'
|
|
37
|
-
: ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
|
|
38
|
-
lifecycleMap[feature.lifecycle] ??
|
|
39
|
-
'requirements');
|
|
40
|
-
|
|
41
14
|
return {
|
|
42
15
|
name: feature.name,
|
|
43
16
|
description: feature.description ?? feature.slug,
|
|
44
17
|
featureId: feature.id,
|
|
45
|
-
lifecycle,
|
|
18
|
+
lifecycle: deriveLifecycle(feature, run),
|
|
46
19
|
repositoryPath: feature.repositoryPath,
|
|
47
20
|
branch: feature.branch,
|
|
48
21
|
specPath: feature.specPath,
|
|
@@ -2,30 +2,11 @@ import type { Feature, Repository, AgentRun } from '@shepai/core/domain/generate
|
|
|
2
2
|
import {
|
|
3
3
|
deriveNodeState,
|
|
4
4
|
deriveProgress,
|
|
5
|
+
deriveLifecycle,
|
|
5
6
|
} from '@/components/common/feature-node/derive-feature-state';
|
|
6
7
|
import type { CanvasNodeType } from '@/components/features/features-canvas';
|
|
7
8
|
import type { Edge } from '@xyflow/react';
|
|
8
|
-
import type { FeatureNodeData
|
|
9
|
-
|
|
10
|
-
/** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
|
|
11
|
-
const lifecycleMap: Record<string, FeatureLifecyclePhase> = {
|
|
12
|
-
Requirements: 'requirements',
|
|
13
|
-
Research: 'research',
|
|
14
|
-
Implementation: 'implementation',
|
|
15
|
-
Review: 'review',
|
|
16
|
-
'Deploy & QA': 'deploy',
|
|
17
|
-
Maintain: 'maintain',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/** Map agent graph node names (from agent_run.result) to UI lifecycle phases. */
|
|
21
|
-
const nodeToLifecyclePhase: Record<string, FeatureLifecyclePhase> = {
|
|
22
|
-
analyze: 'requirements',
|
|
23
|
-
requirements: 'requirements',
|
|
24
|
-
research: 'research',
|
|
25
|
-
plan: 'implementation',
|
|
26
|
-
implement: 'implementation',
|
|
27
|
-
merge: 'review',
|
|
28
|
-
};
|
|
9
|
+
import type { FeatureNodeData } from '@/components/common/feature-node';
|
|
29
10
|
|
|
30
11
|
export interface FeatureWithRun {
|
|
31
12
|
feature: Feature;
|
|
@@ -131,14 +112,6 @@ function appendFeatureNodes(
|
|
|
131
112
|
});
|
|
132
113
|
|
|
133
114
|
sorted.forEach(({ feature, run }) => {
|
|
134
|
-
const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
|
|
135
|
-
const lifecycle: FeatureLifecyclePhase =
|
|
136
|
-
run?.status === 'completed'
|
|
137
|
-
? 'maintain'
|
|
138
|
-
: ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
|
|
139
|
-
lifecycleMap[feature.lifecycle] ??
|
|
140
|
-
'requirements');
|
|
141
|
-
|
|
142
115
|
// Resolve blockedBy display name from parent feature
|
|
143
116
|
let blockedBy: string | undefined;
|
|
144
117
|
if (feature.parentId && feature.lifecycle === 'Blocked') {
|
|
@@ -152,7 +125,7 @@ function appendFeatureNodes(
|
|
|
152
125
|
name: feature.name,
|
|
153
126
|
description: feature.description ?? feature.slug,
|
|
154
127
|
featureId: feature.id,
|
|
155
|
-
lifecycle,
|
|
128
|
+
lifecycle: deriveLifecycle(feature, run),
|
|
156
129
|
repositoryPath: feature.repositoryPath,
|
|
157
130
|
branch: feature.branch,
|
|
158
131
|
specPath: feature.specPath,
|
|
@@ -61,7 +61,6 @@ export function CreateDrawerClient({
|
|
|
61
61
|
.then((result) => {
|
|
62
62
|
if (result.error) {
|
|
63
63
|
toast.error(result.error);
|
|
64
|
-
window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
|
|
65
64
|
return;
|
|
66
65
|
}
|
|
67
66
|
// Dispatch event with real feature ID so control center adds it to featureMap
|
|
@@ -79,7 +78,6 @@ export function CreateDrawerClient({
|
|
|
79
78
|
})
|
|
80
79
|
.catch(() => {
|
|
81
80
|
toast.error('Failed to create feature');
|
|
82
|
-
window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
|
|
83
81
|
setIsSubmitting(false);
|
|
84
82
|
});
|
|
85
83
|
},
|
|
@@ -27,6 +27,17 @@ export type DrawerView =
|
|
|
27
27
|
/** Repository node actions */
|
|
28
28
|
| { type: 'repository'; data: RepositoryNodeData };
|
|
29
29
|
|
|
30
|
+
/** Derives the feature-specific view type from node lifecycle + state. */
|
|
31
|
+
export function deriveFeatureViewType(
|
|
32
|
+
node: FeatureNodeData
|
|
33
|
+
): 'feature' | 'prd-review' | 'tech-review' | 'merge-review' {
|
|
34
|
+
if (node.lifecycle === 'requirements' && node.state === 'action-required') return 'prd-review';
|
|
35
|
+
if (node.lifecycle === 'implementation' && node.state === 'action-required') return 'tech-review';
|
|
36
|
+
if (node.lifecycle === 'review' && (node.state === 'action-required' || node.state === 'error'))
|
|
37
|
+
return 'merge-review';
|
|
38
|
+
return 'feature';
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
/**
|
|
31
42
|
* Derives the active DrawerView from control-center state.
|
|
32
43
|
* Priority: feature-create > selected-node (prd/tech/merge/feature) > repository
|
|
@@ -59,19 +70,7 @@ export function computeDrawerView({
|
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
if (selectedNode) {
|
|
62
|
-
|
|
63
|
-
return { type: 'prd-review', node: selectedNode };
|
|
64
|
-
}
|
|
65
|
-
if (selectedNode.lifecycle === 'implementation' && selectedNode.state === 'action-required') {
|
|
66
|
-
return { type: 'tech-review', node: selectedNode };
|
|
67
|
-
}
|
|
68
|
-
if (
|
|
69
|
-
selectedNode.lifecycle === 'review' &&
|
|
70
|
-
(selectedNode.state === 'action-required' || selectedNode.state === 'error')
|
|
71
|
-
) {
|
|
72
|
-
return { type: 'merge-review', node: selectedNode };
|
|
73
|
-
}
|
|
74
|
-
return { type: 'feature', node: selectedNode };
|
|
73
|
+
return { type: deriveFeatureViewType(selectedNode), node: selectedNode };
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
if (selectedRepoNode) {
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
PrdApprovalPayload,
|
|
9
9
|
QuestionSelectionChange,
|
|
10
10
|
} from '@shepai/core/domain/generated/output';
|
|
11
|
-
import { PrStatus
|
|
11
|
+
import { PrStatus } from '@shepai/core/domain/generated/output';
|
|
12
12
|
import { approveFeature } from '@/app/actions/approve-feature';
|
|
13
13
|
import { rejectFeature } from '@/app/actions/reject-feature';
|
|
14
14
|
import { getFeatureArtifact } from '@/app/actions/get-feature-artifact';
|
|
@@ -53,10 +53,8 @@ import { useFeatureActions } from '@/components/common/feature-drawer/use-featur
|
|
|
53
53
|
import type { PrdQuestionnaireData } from '@/components/common/prd-questionnaire';
|
|
54
54
|
import type { TechDecisionsReviewData } from '@/components/common/tech-decisions-review';
|
|
55
55
|
import type { MergeReviewData } from '@/components/common/merge-review';
|
|
56
|
-
import {
|
|
57
|
-
|
|
58
|
-
mapPhaseNameToLifecycle,
|
|
59
|
-
} from '@/components/common/feature-node/derive-feature-state';
|
|
56
|
+
import { resolveSseEventUpdates } from '@/components/common/feature-node/derive-feature-state';
|
|
57
|
+
import { deriveFeatureViewType } from './drawer-view';
|
|
60
58
|
import type { DrawerView } from './drawer-view';
|
|
61
59
|
|
|
62
60
|
export interface FeatureDrawerClientProps {
|
|
@@ -94,30 +92,15 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
|
|
|
94
92
|
const newEvents = events.slice(processedCountRef.current);
|
|
95
93
|
processedCountRef.current = events.length;
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// a fallback for missed AgentStarted events.
|
|
100
|
-
const waitingApprovalInBatch = newEvents.some(
|
|
101
|
-
(e) =>
|
|
102
|
-
e.featureId === featureNode.featureId &&
|
|
103
|
-
e.eventType === NotificationEventType.WaitingApproval
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
for (const event of newEvents) {
|
|
107
|
-
if (event.featureId !== featureNode.featureId) continue;
|
|
108
|
-
|
|
109
|
-
const newState =
|
|
110
|
-
event.eventType === NotificationEventType.PhaseCompleted && waitingApprovalInBatch
|
|
111
|
-
? undefined
|
|
112
|
-
: mapEventTypeToState(event.eventType);
|
|
113
|
-
const newLifecycle = mapPhaseNameToLifecycle(event.phaseName);
|
|
95
|
+
for (const update of resolveSseEventUpdates(newEvents)) {
|
|
96
|
+
if (update.featureId !== featureNode.featureId) continue;
|
|
114
97
|
|
|
115
98
|
// Trigger a server refresh to get the latest drawer view,
|
|
116
99
|
// but skip when the user has unsaved changes or a rejection is in-flight
|
|
117
100
|
// to avoid the refresh interfering with the reject handler's navigation.
|
|
118
101
|
if (!isDirtyRef.current && !isRejectingRef.current) router.refresh();
|
|
119
102
|
|
|
120
|
-
if (
|
|
103
|
+
if (update.state !== undefined || update.lifecycle !== undefined) {
|
|
121
104
|
// Optimistically update the node data AND re-derive the view type so the
|
|
122
105
|
// drawer switches immediately (e.g. prd-review → feature when agent resumes)
|
|
123
106
|
// without waiting for the router.refresh() round-trip.
|
|
@@ -131,10 +114,10 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
|
|
|
131
114
|
return prev;
|
|
132
115
|
const updatedNode = {
|
|
133
116
|
...prev.node,
|
|
134
|
-
...(
|
|
135
|
-
...(
|
|
117
|
+
...(update.state !== undefined && { state: update.state }),
|
|
118
|
+
...(update.lifecycle !== undefined && { lifecycle: update.lifecycle }),
|
|
136
119
|
};
|
|
137
|
-
return { ...prev, type:
|
|
120
|
+
return { ...prev, type: deriveFeatureViewType(updatedNode), node: updatedNode };
|
|
138
121
|
});
|
|
139
122
|
}
|
|
140
123
|
}
|
|
@@ -383,6 +366,12 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
|
|
|
383
366
|
}
|
|
384
367
|
setChatInput('');
|
|
385
368
|
toast.success(`${label} approved — agent resuming`);
|
|
369
|
+
// Optimistically update canvas node before SSE arrives (~500ms delay)
|
|
370
|
+
window.dispatchEvent(
|
|
371
|
+
new CustomEvent('shep:feature-approved', {
|
|
372
|
+
detail: { featureId: reviewNode.featureId },
|
|
373
|
+
})
|
|
374
|
+
);
|
|
386
375
|
onClose();
|
|
387
376
|
},
|
|
388
377
|
[reviewNode, onClose]
|
|
@@ -410,6 +399,12 @@ export function FeatureDrawerClient({ view: initialView }: FeatureDrawerClientPr
|
|
|
410
399
|
}
|
|
411
400
|
setChatInput('');
|
|
412
401
|
toast.success('Requirements approved — agent resuming');
|
|
402
|
+
// Optimistically update canvas node before SSE arrives (~500ms delay)
|
|
403
|
+
window.dispatchEvent(
|
|
404
|
+
new CustomEvent('shep:feature-approved', {
|
|
405
|
+
detail: { featureId: view.node.featureId },
|
|
406
|
+
})
|
|
407
|
+
);
|
|
413
408
|
setPrdSelections({});
|
|
414
409
|
onClose();
|
|
415
410
|
},
|
|
@@ -780,14 +775,3 @@ function DetailRow({ label, value }: { label: string; value: string }) {
|
|
|
780
775
|
</div>
|
|
781
776
|
);
|
|
782
777
|
}
|
|
783
|
-
|
|
784
|
-
/** Mirrors computeDrawerView logic — derives view type from live node data. */
|
|
785
|
-
function deriveViewType(
|
|
786
|
-
node: FeatureNodeData
|
|
787
|
-
): 'feature' | 'prd-review' | 'tech-review' | 'merge-review' {
|
|
788
|
-
if (node.lifecycle === 'requirements' && node.state === 'action-required') return 'prd-review';
|
|
789
|
-
if (node.lifecycle === 'implementation' && node.state === 'action-required') return 'tech-review';
|
|
790
|
-
if (node.lifecycle === 'review' && (node.state === 'action-required' || node.state === 'error'))
|
|
791
|
-
return 'merge-review';
|
|
792
|
-
return 'feature';
|
|
793
|
-
}
|
|
@@ -41,7 +41,7 @@ export function deriveNodeState(feature: Feature, agentRun?: AgentRun | null): F
|
|
|
41
41
|
case AgentRunStatus.cancelled:
|
|
42
42
|
return 'blocked';
|
|
43
43
|
case AgentRunStatus.completed:
|
|
44
|
-
return
|
|
44
|
+
return 'done';
|
|
45
45
|
case AgentRunStatus.running:
|
|
46
46
|
case AgentRunStatus.pending:
|
|
47
47
|
return 'running';
|
|
@@ -112,7 +112,17 @@ export function mapEventTypeToState(eventType: NotificationEventType): FeatureNo
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
/**
|
|
115
|
+
/** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase. */
|
|
116
|
+
export const sdlcLifecycleMap: Record<string, FeatureLifecyclePhase> = {
|
|
117
|
+
Requirements: 'requirements',
|
|
118
|
+
Research: 'research',
|
|
119
|
+
Implementation: 'implementation',
|
|
120
|
+
Review: 'review',
|
|
121
|
+
'Deploy & QA': 'deploy',
|
|
122
|
+
Maintain: 'maintain',
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/** Map agent graph node names (from agent_run.result or SSE phaseName) to UI lifecycle phases. */
|
|
116
126
|
const phaseNameToLifecycle: Record<string, FeatureLifecyclePhase> = {
|
|
117
127
|
analyze: 'requirements',
|
|
118
128
|
requirements: 'requirements',
|
|
@@ -124,6 +134,57 @@ const phaseNameToLifecycle: Record<string, FeatureLifecyclePhase> = {
|
|
|
124
134
|
blocked: 'requirements',
|
|
125
135
|
};
|
|
126
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Derives the UI lifecycle phase from a Feature + AgentRun.
|
|
139
|
+
* Shared by build-feature-node-data.ts and build-graph-nodes.ts.
|
|
140
|
+
*/
|
|
141
|
+
export function deriveLifecycle(feature: Feature, run: AgentRun | null): FeatureLifecyclePhase {
|
|
142
|
+
if (run?.status === 'completed') return 'maintain';
|
|
143
|
+
const agentNode = run?.result?.startsWith('node:') ? run.result.slice(5) : undefined;
|
|
144
|
+
return (
|
|
145
|
+
(agentNode ? phaseNameToLifecycle[agentNode] : undefined) ??
|
|
146
|
+
sdlcLifecycleMap[feature.lifecycle] ??
|
|
147
|
+
'requirements'
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface SseEventUpdate {
|
|
152
|
+
featureId: string;
|
|
153
|
+
state: FeatureNodeState | undefined;
|
|
154
|
+
lifecycle: FeatureLifecyclePhase | undefined;
|
|
155
|
+
eventType: NotificationEventType;
|
|
156
|
+
phaseName?: string;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Resolves state/lifecycle updates from a batch of SSE events, applying
|
|
161
|
+
* the WaitingApproval batch-suppression rule: when WaitingApproval and
|
|
162
|
+
* PhaseCompleted arrive in the same batch for a feature, PhaseCompleted
|
|
163
|
+
* is fully suppressed to prevent lifecycle regression.
|
|
164
|
+
*/
|
|
165
|
+
export function resolveSseEventUpdates(
|
|
166
|
+
events: readonly { featureId: string; eventType: NotificationEventType; phaseName?: string }[]
|
|
167
|
+
): SseEventUpdate[] {
|
|
168
|
+
const waitingApprovalFeatures = new Set(
|
|
169
|
+
events
|
|
170
|
+
.filter((e) => e.eventType === NotificationEventType.WaitingApproval)
|
|
171
|
+
.map((e) => e.featureId)
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
return events.map((event) => {
|
|
175
|
+
const isSuppressed =
|
|
176
|
+
event.eventType === NotificationEventType.PhaseCompleted &&
|
|
177
|
+
waitingApprovalFeatures.has(event.featureId);
|
|
178
|
+
return {
|
|
179
|
+
featureId: event.featureId,
|
|
180
|
+
state: isSuppressed ? undefined : mapEventTypeToState(event.eventType),
|
|
181
|
+
lifecycle: isSuppressed ? undefined : mapPhaseNameToLifecycle(event.phaseName),
|
|
182
|
+
eventType: event.eventType,
|
|
183
|
+
phaseName: event.phaseName,
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
127
188
|
export function mapPhaseNameToLifecycle(
|
|
128
189
|
phaseName: string | undefined
|
|
129
190
|
): FeatureLifecyclePhase | undefined {
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
ControlCenterDrawer,
|
|
3
|
-
type ControlCenterDrawerProps,
|
|
4
|
-
computeDrawerView,
|
|
5
|
-
type DrawerView,
|
|
6
|
-
} from './control-center-drawer';
|
|
1
|
+
export { computeDrawerView, type DrawerView } from './control-center-drawer';
|
|
7
2
|
export { AddRepositoryButton } from './add-repository-button';
|
|
8
3
|
export { ElapsedTime, formatElapsed } from './elapsed-time';
|
|
9
4
|
export { EmptyState, type EmptyStateProps } from './empty-state';
|
|
@@ -31,7 +26,6 @@ export {
|
|
|
31
26
|
export { FeatureStatusBadges, type FeatureStatusBadgesProps } from './feature-status-badges';
|
|
32
27
|
export { FeatureStatusGroup, type FeatureStatusGroupProps } from './feature-status-group';
|
|
33
28
|
export { LoadingSkeleton } from './loading-skeleton';
|
|
34
|
-
export { NotificationPermissionBanner } from './notification-permission-banner';
|
|
35
29
|
export {
|
|
36
30
|
RepositoryNode,
|
|
37
31
|
type RepositoryNodeData,
|
|
@@ -7,7 +7,6 @@ import { FeaturesCanvas } from '@/components/features/features-canvas';
|
|
|
7
7
|
import type { CanvasNodeType } from '@/components/features/features-canvas';
|
|
8
8
|
import type { FeatureNodeData } from '@/components/common/feature-node';
|
|
9
9
|
import type { RepositoryNodeData } from '@/components/common/repository-node';
|
|
10
|
-
import { NotificationPermissionBanner } from '@/components/common/notification-permission-banner';
|
|
11
10
|
import {
|
|
12
11
|
useSidebarFeaturesContext,
|
|
13
12
|
mapNodeStateToSidebarStatus,
|
|
@@ -235,28 +234,20 @@ export function ControlCenterInner({ initialNodes, initialEdges }: ControlCenter
|
|
|
235
234
|
const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');
|
|
236
235
|
|
|
237
236
|
if (!hasRepositories) {
|
|
238
|
-
return
|
|
239
|
-
<>
|
|
240
|
-
<NotificationPermissionBanner />
|
|
241
|
-
<ControlCenterEmptyState onRepositorySelect={handleAddRepository} />
|
|
242
|
-
</>
|
|
243
|
-
);
|
|
237
|
+
return <ControlCenterEmptyState onRepositorySelect={handleAddRepository} />;
|
|
244
238
|
}
|
|
245
239
|
|
|
246
240
|
return (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
emptyState={<ControlCenterEmptyState onRepositorySelect={handleAddRepository} />}
|
|
259
|
-
/>
|
|
260
|
-
</>
|
|
241
|
+
<FeaturesCanvas
|
|
242
|
+
nodes={nodes}
|
|
243
|
+
edges={edges}
|
|
244
|
+
selectedFeatureId={selectedFeatureId}
|
|
245
|
+
onNodesChange={onNodesChange}
|
|
246
|
+
onConnect={handleConnect}
|
|
247
|
+
onAddFeature={handleAddFeature}
|
|
248
|
+
onNodeClick={handleNodeClick}
|
|
249
|
+
onPaneClick={handleClearDrawers}
|
|
250
|
+
emptyState={<ControlCenterEmptyState onRepositorySelect={handleAddRepository} />}
|
|
251
|
+
/>
|
|
261
252
|
);
|
|
262
253
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { useRouter } from 'next/navigation';
|
|
5
5
|
import { toast } from 'sonner';
|
|
6
6
|
import type { Connection, Edge, NodeChange } from '@xyflow/react';
|
|
@@ -20,10 +20,10 @@ import { useAgentEventsContext } from '@/hooks/agent-events-provider';
|
|
|
20
20
|
import { useSoundAction } from '@/hooks/use-sound-action';
|
|
21
21
|
import {
|
|
22
22
|
mapEventTypeToState,
|
|
23
|
-
|
|
23
|
+
resolveSseEventUpdates,
|
|
24
24
|
} from '@/components/common/feature-node/derive-feature-state';
|
|
25
|
-
import { NotificationEventType } from '@shepai/core/domain/generated/output';
|
|
26
25
|
import { useGraphState, type GraphCallbacks } from '@/hooks/use-graph-state';
|
|
26
|
+
import type { FeatureEntry } from '@/lib/derive-graph';
|
|
27
27
|
|
|
28
28
|
export interface ControlCenterState {
|
|
29
29
|
nodes: CanvasNodeType[];
|
|
@@ -47,6 +47,9 @@ export interface ControlCenterState {
|
|
|
47
47
|
setCallbacks: (callbacks: GraphCallbacks) => void;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/** Must match the message string emitted by the SSE route in agent-events/route.ts */
|
|
51
|
+
const METADATA_UPDATED_MESSAGE = 'Feature metadata updated';
|
|
52
|
+
|
|
50
53
|
let nextFeatureId = 0;
|
|
51
54
|
|
|
52
55
|
export function useControlCenterState(
|
|
@@ -75,18 +78,26 @@ export function useControlCenterState(
|
|
|
75
78
|
|
|
76
79
|
// Sync server props into domain Maps when initialNodes/initialEdges change.
|
|
77
80
|
// Keyed by a stable string so we don't re-reconcile on every render.
|
|
78
|
-
const initialNodeKey =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
const initialNodeKey = useMemo(
|
|
82
|
+
() =>
|
|
83
|
+
initialNodes
|
|
84
|
+
.map((n) => n.id)
|
|
85
|
+
.sort()
|
|
86
|
+
.join(','),
|
|
87
|
+
[initialNodes]
|
|
88
|
+
);
|
|
89
|
+
const initialDataKey = useMemo(
|
|
90
|
+
() =>
|
|
91
|
+
initialNodes
|
|
92
|
+
.filter((n) => n.type === 'featureNode')
|
|
93
|
+
.map((n) => {
|
|
94
|
+
const d = n.data as FeatureNodeData;
|
|
95
|
+
return `${n.id}:${d.state}:${d.lifecycle}`;
|
|
96
|
+
})
|
|
97
|
+
.sort()
|
|
98
|
+
.join(','),
|
|
99
|
+
[initialNodes]
|
|
100
|
+
);
|
|
90
101
|
|
|
91
102
|
const prevReconcileKey = useRef('');
|
|
92
103
|
|
|
@@ -101,15 +112,6 @@ export function useControlCenterState(
|
|
|
101
112
|
// Track previous feature states for fallback notifications
|
|
102
113
|
const prevFeatureStatesRef = useRef<Map<string, FeatureNodeData['state']>>(new Map());
|
|
103
114
|
|
|
104
|
-
const initialFeatureDataKey = initialNodes
|
|
105
|
-
.filter((n) => n.type === 'featureNode')
|
|
106
|
-
.map((n) => {
|
|
107
|
-
const d = n.data as FeatureNodeData;
|
|
108
|
-
return `${n.id}:${d.state}`;
|
|
109
|
-
})
|
|
110
|
-
.sort()
|
|
111
|
-
.join(',');
|
|
112
|
-
|
|
113
115
|
const { events } = useAgentEventsContext();
|
|
114
116
|
|
|
115
117
|
useEffect(() => {
|
|
@@ -140,7 +142,7 @@ export function useControlCenterState(
|
|
|
140
142
|
}
|
|
141
143
|
prevStates.set(node.id, data.state);
|
|
142
144
|
}
|
|
143
|
-
}, [
|
|
145
|
+
}, [initialDataKey, initialNodes, events, router]);
|
|
144
146
|
|
|
145
147
|
// SSE effect: only state + lifecycle updates
|
|
146
148
|
const processedEventCountRef = useRef(0);
|
|
@@ -150,40 +152,37 @@ export function useControlCenterState(
|
|
|
150
152
|
const newEvents = events.slice(processedEventCountRef.current);
|
|
151
153
|
processedEventCountRef.current = events.length;
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
newEvents
|
|
159
|
-
.filter((e) => e.eventType === NotificationEventType.WaitingApproval)
|
|
160
|
-
.map((e) => e.featureId)
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
for (const event of newEvents) {
|
|
164
|
-
const newState =
|
|
165
|
-
event.eventType === NotificationEventType.PhaseCompleted &&
|
|
166
|
-
waitingApprovalFeatures.has(event.featureId)
|
|
167
|
-
? undefined
|
|
168
|
-
: mapEventTypeToState(event.eventType);
|
|
169
|
-
const newLifecycle = mapPhaseNameToLifecycle(event.phaseName);
|
|
170
|
-
|
|
171
|
-
const nodeId = `feat-${event.featureId}`;
|
|
172
|
-
if (newState !== undefined || newLifecycle !== undefined) {
|
|
173
|
-
updateFeature(nodeId, {
|
|
174
|
-
...(newState !== undefined && { state: newState }),
|
|
175
|
-
...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
|
|
155
|
+
for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {
|
|
156
|
+
if (state !== undefined || lifecycle !== undefined) {
|
|
157
|
+
updateFeature(`feat-${featureId}`, {
|
|
158
|
+
...(state !== undefined && { state }),
|
|
159
|
+
...(lifecycle !== undefined && { lifecycle }),
|
|
176
160
|
});
|
|
177
161
|
}
|
|
178
162
|
}
|
|
179
163
|
}, [events, updateFeature]);
|
|
180
164
|
|
|
165
|
+
// Listen for optimistic approval events from the drawer (fires before SSE arrives)
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
const handler = (e: Event) => {
|
|
168
|
+
const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;
|
|
169
|
+
updateFeature(`feat-${featureId}`, { state: 'running' });
|
|
170
|
+
};
|
|
171
|
+
window.addEventListener('shep:feature-approved', handler);
|
|
172
|
+
return () => window.removeEventListener('shep:feature-approved', handler);
|
|
173
|
+
}, [updateFeature]);
|
|
174
|
+
|
|
181
175
|
// Separate effect: fetch metadata (name + description) when SSE reports it changed
|
|
182
176
|
const metadataFetchedRef = useRef<Set<string>>(new Set());
|
|
177
|
+
const processedMetadataCountRef = useRef(0);
|
|
183
178
|
|
|
184
179
|
useEffect(() => {
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
if (events.length <= processedMetadataCountRef.current) return;
|
|
181
|
+
const newEvents = events.slice(processedMetadataCountRef.current);
|
|
182
|
+
processedMetadataCountRef.current = events.length;
|
|
183
|
+
|
|
184
|
+
for (const event of newEvents) {
|
|
185
|
+
if (event.message !== METADATA_UPDATED_MESSAGE) continue;
|
|
187
186
|
if (metadataFetchedRef.current.has(event.featureId)) continue;
|
|
188
187
|
metadataFetchedRef.current.add(event.featureId);
|
|
189
188
|
|
|
@@ -285,6 +284,20 @@ export function useControlCenterState(
|
|
|
285
284
|
|
|
286
285
|
// Snapshot for rollback
|
|
287
286
|
const prevRepoData = getRepositoryData(repoNodeId);
|
|
287
|
+
const childSnapshots = new Map<string, FeatureEntry>();
|
|
288
|
+
for (const childId of childFeatureIds) {
|
|
289
|
+
const childNode = nodes.find((n) => n.id === childId);
|
|
290
|
+
if (childNode) {
|
|
291
|
+
childSnapshots.set(childId, { nodeId: childId, data: childNode.data as FeatureNodeData });
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const rollback = () => {
|
|
296
|
+
if (prevRepoData) addRepositoryToMap(repoNodeId, prevRepoData);
|
|
297
|
+
for (const [childId, entry] of childSnapshots) {
|
|
298
|
+
restoreFeature(childId, entry);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
288
301
|
|
|
289
302
|
// Optimistic: remove repo + children
|
|
290
303
|
removeRepository(repoNodeId);
|
|
@@ -296,32 +309,14 @@ export function useControlCenterState(
|
|
|
296
309
|
const result = await deleteRepository(repositoryId);
|
|
297
310
|
if (!result.success) {
|
|
298
311
|
toast.error(result.error ?? 'Failed to remove repository');
|
|
299
|
-
|
|
300
|
-
for (const childId of childFeatureIds) {
|
|
301
|
-
const childNode = nodes.find((n) => n.id === childId);
|
|
302
|
-
if (childNode) {
|
|
303
|
-
restoreFeature(childId, {
|
|
304
|
-
nodeId: childId,
|
|
305
|
-
data: childNode.data as FeatureNodeData,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
}
|
|
312
|
+
rollback();
|
|
309
313
|
return;
|
|
310
314
|
}
|
|
311
315
|
deleteSound.play();
|
|
312
316
|
toast.success('Repository removed');
|
|
313
317
|
} catch {
|
|
314
318
|
toast.error('Failed to remove repository');
|
|
315
|
-
|
|
316
|
-
for (const childId of childFeatureIds) {
|
|
317
|
-
const childNode = nodes.find((n) => n.id === childId);
|
|
318
|
-
if (childNode) {
|
|
319
|
-
restoreFeature(childId, {
|
|
320
|
-
nodeId: childId,
|
|
321
|
-
data: childNode.data as FeatureNodeData,
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
}
|
|
319
|
+
rollback();
|
|
325
320
|
}
|
|
326
321
|
},
|
|
327
322
|
[
|