@shepai/cli 1.72.9 → 1.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +20 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +68 -41
- package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +10 -0
- package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
- 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/actions/create-feature.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/create-feature.js +20 -2
- package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts +10 -0
- package/dist/src/presentation/web/app/actions/get-feature-metadata.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/get-feature-metadata.js +14 -0
- package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/agent-events/route.js +15 -0
- 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/app/layout.js +1 -1
- package/dist/src/presentation/web/components/common/add-repository-button/add-repository-button.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts +2 -0
- package/dist/src/presentation/web/components/common/add-repository-button/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/index.js +0 -1
- package/dist/src/presentation/web/components/common/add-repository-button/pick-folder.d.ts.map +1 -0
- 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 +13 -18
- 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 +74 -144
- 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/control-center-drawer/use-artifact-fetch.d.ts +13 -0
- package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/control-center-drawer/use-artifact-fetch.js +46 -0
- package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.js +7 -10
- 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 +2 -3
- package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/index.js +2 -3
- package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
- package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/use-repository-actions.js +14 -39
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.d.ts +1 -3
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.js +3 -7
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.d.ts +0 -1
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.js +0 -11
- package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.js +1 -1
- 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 +31 -14
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts +0 -11
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +2 -37
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +8 -0
- 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 +160 -354
- package/dist/src/presentation/web/components/features/features-canvas/features-canvas.d.ts +2 -10
- 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 +11 -54
- package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.js +0 -46
- package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +1 -1
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts +1 -3
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts.map +1 -1
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.js +2 -2
- 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/components/ui/scroll-area.js +1 -1
- package/dist/src/presentation/web/hooks/agent-events-provider.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/agent-events-provider.js +3 -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 +18 -5
- package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-deploy-action.js +8 -3
- package/dist/src/presentation/web/hooks/use-graph-state.d.ts +42 -0
- package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-graph-state.js +257 -0
- 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/src/presentation/web/lib/derive-graph.d.ts +52 -0
- package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -0
- package/dist/src/presentation/web/lib/derive-graph.js +126 -0
- package/dist/src/presentation/web/lib/layout-with-dagre.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/layout-with-dagre.js +1 -2
- package/dist/src/presentation/web/lib/logger.d.ts +7 -0
- package/dist/src/presentation/web/lib/logger.d.ts.map +1 -0
- package/dist/src/presentation/web/lib/logger.js +11 -0
- 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/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +34 -34
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
- 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 +40 -40
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
- 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 +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
- 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 +34 -34
- package/web/.next/server/app/(dashboard)/create/page.js +3 -3
- 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 +40 -40
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
- 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 +30 -30
- package/web/.next/server/app/(dashboard)/page.js +3 -3
- 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 +30 -30
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
- 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.js.nft.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.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_4d623b8e.js +2 -2
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +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 +3 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_816618e2.js.map +1 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js.map +1 -0
- 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]__249c74f6._.js +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]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js.map +1 -1
- 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]__e5e09f72._.js → [root-of-the-server]__94a6d275._.js} +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -0
- 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 +3 -0
- package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -0
- 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/_9f940437._.js +1 -1
- package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_dee726e3._.js +6 -0
- package/web/.next/server/chunks/ssr/_dee726e3._.js.map +1 -0
- package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5ea689db._.js → server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js.map → src_presentation_web_2b91e4ec._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js → src_presentation_web_5bcc1537._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js.map → src_presentation_web_5bcc1537._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -0
- 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 +8 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.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 +142 -142
- 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/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +34 -34
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +3 -3
- 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 +40 -40
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
- 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 +30 -30
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +3 -3
- 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 +34 -34
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +3 -3
- 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 +40 -40
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
- 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 +30 -30
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +3 -3
- 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 +30 -30
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +3 -3
- 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.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/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.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
- 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 +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_ba2e050f.js +3 -0
- 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]__249c74f6._.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]__cbae9863._.js → [root-of-the-server]__6258349c._.js} +2 -2
- 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]__e5e09f72._.js → [root-of-the-server]__94a6d275._.js} +2 -2
- 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 +3 -0
- 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/_9f940437._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_dee726e3._.js +6 -0
- package/web/.next/{server/chunks/ssr/src_presentation_web_7188a290._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js → src_presentation_web_5bcc1537._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.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 +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +3 -0
- 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 +8 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_e626b63c._.js +8 -0
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +142 -142
- package/web/.next/standalone/src/presentation/web/CLAUDE.md +77 -33
- package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +27 -2
- package/web/.next/standalone/src/presentation/web/app/actions/get-feature-metadata.ts +18 -0
- package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +17 -0
- 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/app/layout.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/common/add-repository-button/index.ts +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/create-drawer-client.tsx +15 -21
- 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 +105 -141
- 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/control-center-drawer/use-artifact-fetch.ts +56 -0
- package/web/.next/standalone/src/presentation/web/components/common/feature-drawer/use-feature-actions.ts +6 -7
- 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 +2 -12
- package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +2 -2
- package/web/.next/standalone/src/presentation/web/components/common/repository-node/use-repository-actions.ts +29 -54
- package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.stories.tsx +0 -13
- package/web/.next/standalone/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.tsx +1 -45
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-empty-state.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +43 -36
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center.stories.tsx +2 -41
- package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +203 -440
- package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx +0 -48
- package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +13 -76
- package/web/.next/standalone/src/presentation/web/components/layouts/app-shell/app-shell.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/components/layouts/app-sidebar/app-sidebar.tsx +2 -14
- 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/components/ui/scroll-area.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/hooks/agent-events-provider.tsx +7 -2
- package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +19 -5
- package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +11 -3
- package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +376 -0
- 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/standalone/src/presentation/web/lib/derive-graph.ts +178 -0
- package/web/.next/standalone/src/presentation/web/lib/layout-with-dagre.ts +1 -2
- package/web/.next/standalone/src/presentation/web/lib/logger.ts +12 -0
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/0ffccd7be73305c8.css +2 -0
- package/web/.next/static/chunks/15ceb197ec725da2.js +1 -0
- package/web/.next/static/chunks/3f205fd6adbfd20a.js +7 -0
- package/web/.next/static/chunks/{d4492cd12fdf0891.js → 6691ad02dc1efd1f.js} +1 -1
- package/web/.next/static/chunks/{64850cf4081a2950.js → 7bff5fbcbf157df5.js} +1 -1
- package/web/.next/static/chunks/8959112899679e25.js +1 -0
- package/web/.next/static/chunks/{c83897e9213881bf.js → 8f508ef906cbf0fa.js} +1 -1
- package/web/.next/static/chunks/9cbb42a6bd516d3b.js +1 -0
- package/web/.next/static/chunks/c5603ed8a95d460d.js +1 -0
- package/web/.next/static/chunks/cb41849bcfaa304e.js +1 -0
- package/web/.next/static/chunks/d7e0cd32364a8d76.js +1 -0
- package/web/.next/static/chunks/e69d79bd3f19dec8.js +4 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-button.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts +0 -7
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node-config.js +0 -1
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts +0 -6
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.js +0 -23
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts +0 -10
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.js +0 -33
- package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts +0 -4
- package/dist/src/presentation/web/components/common/add-repository-node/index.d.ts.map +0 -1
- package/dist/src/presentation/web/components/common/add-repository-node/pick-folder.d.ts.map +0 -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/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js.map +0 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cbae9863._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_38d24563._.js +0 -6
- package/web/.next/server/chunks/ssr/_38d24563._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_6e08ce21._.js +0 -3
- package/web/.next/server/chunks/ssr/_6e08ce21._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
- package/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
- package/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_3a02d8a5.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_a3044852.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_38d24563._.js +0 -6
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_6e08ce21._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_0a49d9ee._.js +0 -8
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_79b0305a._.js +0 -8
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_cc16bd01.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +0 -3
- package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node-config.ts +0 -8
- package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.stories.tsx +0 -70
- package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/add-repository-node.tsx +0 -49
- package/web/.next/standalone/src/presentation/web/components/common/add-repository-node/index.ts +0 -3
- 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/0c54314c8c9c9739.js +0 -7
- package/web/.next/static/chunks/10cd08dae8c210ff.js +0 -1
- package/web/.next/static/chunks/15bf7ee1da91eb46.js +0 -4
- package/web/.next/static/chunks/3c79bca4d3f18f66.js +0 -1
- package/web/.next/static/chunks/67f2a7a5e8dc358a.css +0 -2
- package/web/.next/static/chunks/6cc840197626843b.js +0 -1
- package/web/.next/static/chunks/e3239b6c18cf8b96.js +0 -1
- package/web/.next/static/chunks/e9cc53ce8a7bdea6.js +0 -1
- package/web/.next/static/chunks/ef916db8c537211a.js +0 -1
- /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.d.ts +0 -0
- /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.js +0 -0
- /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.d.ts +0 -0
- /package/dist/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.js +0 -0
- /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/add-repository-button.tsx +0 -0
- /package/web/.next/standalone/src/presentation/web/components/common/{add-repository-node → add-repository-button}/pick-folder.ts +0 -0
- /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 1AvkeBASQdtzZt9cm9UYg}/_buildManifest.js +0 -0
- /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 1AvkeBASQdtzZt9cm9UYg}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 1AvkeBASQdtzZt9cm9UYg}/_ssgManifest.js +0 -0
|
@@ -37,6 +37,66 @@ pnpm dev:cli ui
|
|
|
37
37
|
| WebSocket upgrades | Forwarded (HMR works) | NOT forwarded in `WebServerService` |
|
|
38
38
|
| Next.js mode | Always dev | dev when run from source, prod when installed |
|
|
39
39
|
|
|
40
|
+
## Graph State Architecture (Domain-Model-Driven)
|
|
41
|
+
|
|
42
|
+
All canvas node/edge state is managed through **domain Maps as the single source of truth**.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Server (layout.tsx) Client (useGraphState)
|
|
46
|
+
┌──────────────────┐ ┌─────────────────────────────┐
|
|
47
|
+
│ initialNodes[] │──parseMaps──→ │ Domain Maps (source of truth)│
|
|
48
|
+
│ initialEdges[] │ │ featureMap: Map<id, Entry> │
|
|
49
|
+
└──────────────────┘ │ repoMap: Map<id, Entry> │
|
|
50
|
+
│ pendingMap: Map<id, Entry> │
|
|
51
|
+
SSE Events │ │
|
|
52
|
+
┌──────────────────┐ └──────────┬──────────────────┘
|
|
53
|
+
│ NotificationEvent│──updateFeature──→ │
|
|
54
|
+
└──────────────────┘ │ deriveGraph() + layoutWithDagre()
|
|
55
|
+
▼
|
|
56
|
+
Optimistic UI ┌─────────────────────────────┐
|
|
57
|
+
┌──────────────────┐ │ Derived (read-only) │
|
|
58
|
+
│ shep:feature- │──addPending───→ │ nodes: CanvasNodeType[] │
|
|
59
|
+
│ created event │ │ edges: Edge[] │
|
|
60
|
+
└──────────────────┘ │ (callbacks + layout applied)│
|
|
61
|
+
└─────────────────────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Key Files
|
|
65
|
+
|
|
66
|
+
| File | Purpose |
|
|
67
|
+
| ---------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
68
|
+
| `lib/derive-graph.ts` | Pure function: domain Maps → nodes + edges (with callbacks injected) |
|
|
69
|
+
| `hooks/use-graph-state.ts` | Hook: domain Maps state + reconciliation + derivation + layout |
|
|
70
|
+
| `components/features/control-center/use-control-center-state.ts` | Wraps useGraphState, handles server actions + SSE events |
|
|
71
|
+
| `components/features/control-center/control-center-inner.tsx` | Wires callbacks via `setCallbacks()`, passes nodes/edges to canvas |
|
|
72
|
+
| `components/features/features-canvas/features-canvas.tsx` | Renders React Flow; only adds `selectedFeatureId` highlighting |
|
|
73
|
+
|
|
74
|
+
### Design Principles
|
|
75
|
+
|
|
76
|
+
1. **Domain Maps are the source of truth** — all mutations go through Maps (featureMap, repoMap, pendingMap)
|
|
77
|
+
2. **Edges are derived, never stored** — repo→feature edges from `repositoryPath` matching, dep edges from `parentNodeId`
|
|
78
|
+
3. **Callbacks via ref** — `callbacksRef` + stable `useMemo([])` wrapper prevents circular re-renders
|
|
79
|
+
4. **Layout in derivation** — `layoutWithDagre` runs inside `useMemo` after `deriveGraph()`
|
|
80
|
+
5. **`onNodesChange` is a no-op** — since `nodesDraggable=false`, we ignore all React Flow changes
|
|
81
|
+
|
|
82
|
+
### Mutation Paths
|
|
83
|
+
|
|
84
|
+
| Operation | Flow |
|
|
85
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------- |
|
|
86
|
+
| SSE event | `useAgentEventsContext` → `updateFeature(nodeId, {state, lifecycle})` |
|
|
87
|
+
| Server prop sync | `useEffect` watches `initialNodeKey` → `reconcile(newNodes, newEdges)` |
|
|
88
|
+
| Optimistic create | `shep:feature-created` event → `createFeatureNode()` → `addPendingFeature()` |
|
|
89
|
+
| Delete feature | `handleDeleteFeature()` → `removeFeature()` → server action → `restoreFeature()` on error |
|
|
90
|
+
| Add repository | `handleAddRepository()` → `addRepository(tempId)` → server action → `replaceRepository(tempId, realId)` |
|
|
91
|
+
|
|
92
|
+
### Reconciliation
|
|
93
|
+
|
|
94
|
+
`reconcile(newNodes, newEdges)` merges server data into domain Maps:
|
|
95
|
+
|
|
96
|
+
- Replaces featureMap and repoMap with fresh server data
|
|
97
|
+
- Preserves pending (creating) features in featureMap unless matched by `name + repositoryPath`
|
|
98
|
+
- Cleans pendingMap entries that now have a real counterpart in server data
|
|
99
|
+
|
|
40
100
|
## SSE / Real-Time Update Architecture
|
|
41
101
|
|
|
42
102
|
```
|
|
@@ -45,8 +105,8 @@ DB polling (500ms) -> /api/agent-events (SSE route)
|
|
|
45
105
|
-> postMessage to all browser tabs
|
|
46
106
|
-> useAgentEvents hook (hooks/use-agent-events.ts)
|
|
47
107
|
-> AgentEventsProvider context (hooks/agent-events-provider.tsx)
|
|
48
|
-
-> useControlCenterState (
|
|
49
|
-
->
|
|
108
|
+
-> useControlCenterState (SSE effect calls updateFeature)
|
|
109
|
+
-> domain Maps update -> derivation -> React Flow canvas
|
|
50
110
|
```
|
|
51
111
|
|
|
52
112
|
### SSE Key Files
|
|
@@ -58,18 +118,9 @@ DB polling (500ms) -> /api/agent-events (SSE route)
|
|
|
58
118
|
| `public/agent-events-sw.js` | Service Worker: multiplexes single SSE to all tabs |
|
|
59
119
|
| `hooks/use-agent-events.ts` | Client hook: registers with SW, receives events |
|
|
60
120
|
| `hooks/agent-events-provider.tsx` | React context wrapping `useAgentEvents` |
|
|
61
|
-
| `components/features/control-center/use-control-center-state.ts` |
|
|
121
|
+
| `components/features/control-center/use-control-center-state.ts` | SSE effect calls `updateFeature()` on domain Maps |
|
|
62
122
|
| `components/common/feature-node/derive-feature-state.ts` | Maps event types/phases to UI state/lifecycle |
|
|
63
123
|
|
|
64
|
-
### SSE Event Flow Details
|
|
65
|
-
|
|
66
|
-
1. **SSE route** seeds a per-connection cache on first poll (no events emitted for initial state)
|
|
67
|
-
2. Subsequent polls compare DB state against cache, emit only deltas
|
|
68
|
-
3. **Service Worker** connects to `/api/agent-events` via EventSource on first subscriber
|
|
69
|
-
4. SW broadcasts `{ type: 'notification', data }` to all tabs via `clients.matchAll()`
|
|
70
|
-
5. **useControlCenterState** effect processes new events, calls `setNodes()` to update node state/lifecycle
|
|
71
|
-
6. **Polling fallback** (5s interval) fetches via `fetchGraphData()` server action for active features
|
|
72
|
-
|
|
73
124
|
### SSE Lifecycle Mappings
|
|
74
125
|
|
|
75
126
|
The SSE route maps `SdlcLifecycle` enum -> agent graph node names -> client `FeatureLifecyclePhase`:
|
|
@@ -94,21 +145,17 @@ React Flow v12 (`@xyflow/react` ^12.10.0) has specific behaviors that affect rea
|
|
|
94
145
|
- **Internal Zustand store**: React Flow syncs props to an internal `nodeLookup` Map via `StoreUpdater`
|
|
95
146
|
- **Memoized NodeWrapper**: Each node is wrapped in `memo(NodeWrapper)` which subscribes to store via `useStore(selector, shallow)`
|
|
96
147
|
- **NodeWrapper gets node from store**, NOT from props directly. It does `s.nodeLookup.get(id)` with `shallow` comparison
|
|
97
|
-
- **Single ReactFlowProvider**: There must be exactly ONE `ReactFlowProvider` ancestor. Multiple nested providers create separate stores
|
|
148
|
+
- **Single ReactFlowProvider**: There must be exactly ONE `ReactFlowProvider` ancestor. Multiple nested providers create separate stores
|
|
98
149
|
|
|
99
|
-
### Circular Update Loop
|
|
150
|
+
### Circular Update Loop Prevention
|
|
100
151
|
|
|
101
|
-
|
|
102
|
-
(adding callbacks to `data`). StoreUpdater sees different references and emits `replace` changes via
|
|
103
|
-
`onNodesChange`. If `onNodesChange` applies these 'replace' changes back to state via `applyNodeChanges`,
|
|
104
|
-
it overwrites SSE-driven state updates with stale data from the previous render, AND triggers another
|
|
105
|
-
`enrichedNodes` recalculation → infinite loop (110+ renders on page load).
|
|
152
|
+
With the domain-model-driven architecture, the circular update loop is prevented by design:
|
|
106
153
|
|
|
107
|
-
**
|
|
108
|
-
|
|
109
|
-
|
|
154
|
+
1. **Callbacks are stable** — injected via `callbacksRef` + stable `useMemo([])` wrapper, so node objects don't change when callbacks change
|
|
155
|
+
2. **`onNodesChange` is a no-op** — domain Maps are the source of truth, React Flow's internal changes are ignored
|
|
156
|
+
3. **`enrichedNodes` only adds `selectedFeatureId`** — no callback injection in FeaturesCanvas
|
|
110
157
|
|
|
111
|
-
**NEVER**
|
|
158
|
+
**NEVER** make `onNodesChange` apply `replace` changes back to state.
|
|
112
159
|
|
|
113
160
|
## Testing Real-Time Updates
|
|
114
161
|
|
|
@@ -124,24 +171,21 @@ our state remains the source of truth.
|
|
|
124
171
|
|
|
125
172
|
When a user creates a feature, the UI uses optimistic updates:
|
|
126
173
|
|
|
127
|
-
1. **Create drawer** dispatches `shep:feature-created` →
|
|
174
|
+
1. **Create drawer** dispatches `shep:feature-created` → `createFeatureNode()` → `addPendingFeature()` adds temp node to pendingMap
|
|
128
175
|
2. Drawer closes immediately via `router.push('/')`
|
|
129
176
|
3. Server action `createFeature` runs in background → agent starts
|
|
130
|
-
4. SSE events arrive with real feature ID (`feat-<uuid>`) —
|
|
131
|
-
5. **
|
|
177
|
+
4. SSE events arrive with real feature ID (`feat-<uuid>`) — these update featureMap via `updateFeature()`
|
|
178
|
+
5. **Server prop sync** (rerender with new initialNodes) → `reconcile()` detects matching real feature → removes pending from both featureMap and pendingMap
|
|
132
179
|
|
|
133
180
|
### Key constraints
|
|
134
181
|
|
|
135
|
-
- **Temp node IDs don't match SSE events**: Optimistic nodes use `feature-<ts>` IDs, server uses `feat-<uuid>`.
|
|
136
|
-
|
|
137
|
-
- **
|
|
138
|
-
causes the drawer to flash open because `router.push('/')` is async and pathname hasn't changed yet.
|
|
139
|
-
- **Parallel routes preserve state**: The `CreateDrawerClient` component is NOT unmounted on navigation.
|
|
140
|
-
`isOpen` is derived from pathname, not mount/unmount lifecycle.
|
|
182
|
+
- **Temp node IDs don't match SSE events**: Optimistic nodes use `feature-<ts>` IDs, server uses `feat-<uuid>`. SSE events call `updateFeature('feat-<uuid>', ...)` which doesn't match the temp ID. The reconcile on next server prop update handles the swap.
|
|
183
|
+
- **Create drawer `isSubmitting`**: Must NOT reset until pathname leaves `/create`. Resetting in `.finally()` causes the drawer to flash open because `router.push('/')` is async and pathname hasn't changed yet.
|
|
184
|
+
- **Parallel routes preserve state**: The `CreateDrawerClient` component is NOT unmounted on navigation. `isOpen` is derived from pathname, not mount/unmount lifecycle.
|
|
141
185
|
|
|
142
186
|
## Common Pitfalls
|
|
143
187
|
|
|
144
188
|
- **No events when nothing changes**: SSE only emits deltas. If no feature state changes, no events are sent. This is correct behavior.
|
|
145
|
-
- **Polling fallback dependency**: The 5s polling `useEffect` depends on a derived `hasActiveFeature` boolean (not `nodes` directly). Using `[nodes]` as a dependency would reset the interval on every node change, potentially preventing it from ever firing.
|
|
146
189
|
- **Storybook mocks**: New server actions need mocks in `.storybook/mocks/app/actions/` or Storybook build breaks.
|
|
147
190
|
- **`output: 'standalone'`** in next.config.ts: Production builds use standalone mode. Route handlers are bundled differently.
|
|
191
|
+
- **Map insertion order affects dagre layout**: After remove+restore of a feature, the Map insertion order may change, causing slightly different dagre positions. This is expected behavior — don't write tests asserting exact position preservation across remove/restore cycles.
|
|
@@ -72,15 +72,40 @@ export async function createFeature(
|
|
|
72
72
|
|
|
73
73
|
try {
|
|
74
74
|
const createFeatureUseCase = resolve<CreateFeatureUseCase>('CreateFeatureUseCase');
|
|
75
|
-
|
|
75
|
+
|
|
76
|
+
// Phase 1 (fast): create DB record with real UUID — returns immediately
|
|
77
|
+
const { feature, shouldSpawn } = await createFeatureUseCase.createRecord({
|
|
76
78
|
userInput,
|
|
77
79
|
repositoryPath,
|
|
78
80
|
approvalGates: gates,
|
|
79
81
|
push: push ?? false,
|
|
80
82
|
openPr: openPr ?? false,
|
|
81
83
|
...(parentId ? { parentId } : {}),
|
|
84
|
+
name,
|
|
85
|
+
description,
|
|
82
86
|
});
|
|
83
|
-
|
|
87
|
+
|
|
88
|
+
// Phase 2 (background): metadata generation, worktree, spec, agent spawn
|
|
89
|
+
// Fire-and-forget — the UI gets the real feature ID immediately
|
|
90
|
+
createFeatureUseCase
|
|
91
|
+
.initializeAndSpawn(
|
|
92
|
+
feature,
|
|
93
|
+
{
|
|
94
|
+
userInput,
|
|
95
|
+
repositoryPath,
|
|
96
|
+
approvalGates: gates,
|
|
97
|
+
push: push ?? false,
|
|
98
|
+
openPr: openPr ?? false,
|
|
99
|
+
...(parentId ? { parentId } : {}),
|
|
100
|
+
},
|
|
101
|
+
shouldSpawn
|
|
102
|
+
)
|
|
103
|
+
.catch((err: unknown) => {
|
|
104
|
+
// eslint-disable-next-line no-console
|
|
105
|
+
console.error('[createFeature] initializeAndSpawn failed:', err);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return { feature };
|
|
84
109
|
} catch (error: unknown) {
|
|
85
110
|
const message = error instanceof Error ? error.message : 'Failed to create feature';
|
|
86
111
|
return { error: message };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { resolve } from '@/lib/server-container';
|
|
4
|
+
import type { IFeatureRepository } from '@shepai/core/application/ports/output/repositories/feature-repository.interface';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lightweight server action to fetch a single feature's name and description.
|
|
8
|
+
* Used by the SSE effect to update node metadata after AI metadata generation
|
|
9
|
+
* without a full graph reconcile (which can overwrite SSE-driven state).
|
|
10
|
+
*/
|
|
11
|
+
export async function getFeatureMetadata(
|
|
12
|
+
featureId: string
|
|
13
|
+
): Promise<{ name: string; description: string } | null> {
|
|
14
|
+
const featureRepo = resolve<IFeatureRepository>('IFeatureRepository');
|
|
15
|
+
const feature = await featureRepo.findById(featureId);
|
|
16
|
+
if (!feature) return null;
|
|
17
|
+
return { name: feature.name, description: feature.description };
|
|
18
|
+
}
|
|
@@ -191,6 +191,23 @@ export function GET(request: Request): Response {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
// Check for feature name change (AI metadata generation updates name)
|
|
195
|
+
if (prev.featureName !== feature.name) {
|
|
196
|
+
prev.featureName = feature.name;
|
|
197
|
+
const nodeName =
|
|
198
|
+
LIFECYCLE_TO_NODE[feature.lifecycle as SdlcLifecycle] ?? 'requirements';
|
|
199
|
+
emitEvent({
|
|
200
|
+
eventType: NotificationEventType.PhaseCompleted,
|
|
201
|
+
agentRunId: run.id,
|
|
202
|
+
featureId: feature.id,
|
|
203
|
+
featureName: feature.name,
|
|
204
|
+
phaseName: nodeName,
|
|
205
|
+
message: `Feature metadata updated`,
|
|
206
|
+
severity: NotificationSeverity.Info,
|
|
207
|
+
timestamp: new Date().toISOString(),
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
194
211
|
// Check for lifecycle change (agent stays "running" but moves through phases)
|
|
195
212
|
if (prev.lifecycle !== feature.lifecycle) {
|
|
196
213
|
prev.lifecycle = feature.lifecycle;
|
|
@@ -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,
|
package/web/.next/standalone/src/presentation/web/components/common/add-repository-button/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AddRepositoryButton } from './add-repository-button';
|
|
@@ -8,7 +8,6 @@ import { FeatureCreateDrawer } from '@/components/common/feature-create-drawer';
|
|
|
8
8
|
import type { FeatureCreatePayload } from '@/components/common/feature-create-drawer';
|
|
9
9
|
import type { ParentFeatureOption } from '@/components/common/feature-create-drawer/feature-create-drawer';
|
|
10
10
|
import type { WorkflowDefaults } from '@/app/actions/get-workflow-defaults';
|
|
11
|
-
import { useSoundAction } from '@/hooks/use-sound-action';
|
|
12
11
|
|
|
13
12
|
export interface CreateDrawerClientProps {
|
|
14
13
|
repositoryPath: string;
|
|
@@ -24,7 +23,6 @@ export function CreateDrawerClient({
|
|
|
24
23
|
workflowDefaults,
|
|
25
24
|
}: CreateDrawerClientProps) {
|
|
26
25
|
const router = useRouter();
|
|
27
|
-
const createSound = useSoundAction('create');
|
|
28
26
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
29
27
|
|
|
30
28
|
// Derive open state from the URL. Next.js parallel routes preserve slot
|
|
@@ -54,40 +52,36 @@ export function CreateDrawerClient({
|
|
|
54
52
|
(data: FeatureCreatePayload) => {
|
|
55
53
|
setIsSubmitting(true);
|
|
56
54
|
|
|
57
|
-
// Dispatch event for optimistic canvas update before navigating
|
|
58
|
-
window.dispatchEvent(
|
|
59
|
-
new CustomEvent('shep:feature-created', {
|
|
60
|
-
detail: {
|
|
61
|
-
name: data.name,
|
|
62
|
-
description: data.description,
|
|
63
|
-
repositoryPath: data.repositoryPath,
|
|
64
|
-
parentId: data.parentId,
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
);
|
|
68
|
-
|
|
69
55
|
// Close the drawer immediately for responsive UI
|
|
70
56
|
router.push('/');
|
|
71
57
|
|
|
72
|
-
//
|
|
58
|
+
// Server action Phase 1 returns fast with real feature ID (DB record created)
|
|
59
|
+
// Phase 2 (metadata, worktree, agent) runs in background on server
|
|
73
60
|
createFeature(data)
|
|
74
61
|
.then((result) => {
|
|
75
62
|
if (result.error) {
|
|
76
63
|
toast.error(result.error);
|
|
77
|
-
// Dispatch rollback event
|
|
78
|
-
window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
|
|
79
64
|
return;
|
|
80
65
|
}
|
|
81
|
-
|
|
66
|
+
// Dispatch event with real feature ID so control center adds it to featureMap
|
|
67
|
+
window.dispatchEvent(
|
|
68
|
+
new CustomEvent('shep:feature-created', {
|
|
69
|
+
detail: {
|
|
70
|
+
featureId: result.feature!.id,
|
|
71
|
+
name: result.feature!.name,
|
|
72
|
+
description: result.feature!.description,
|
|
73
|
+
repositoryPath: result.feature!.repositoryPath,
|
|
74
|
+
parentId: data.parentId,
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
);
|
|
82
78
|
})
|
|
83
79
|
.catch(() => {
|
|
84
80
|
toast.error('Failed to create feature');
|
|
85
|
-
window.dispatchEvent(new CustomEvent('shep:feature-create-failed'));
|
|
86
|
-
// Reset on error so the user can retry without navigating away
|
|
87
81
|
setIsSubmitting(false);
|
|
88
82
|
});
|
|
89
83
|
},
|
|
90
|
-
[router
|
|
84
|
+
[router]
|
|
91
85
|
);
|
|
92
86
|
|
|
93
87
|
return (
|
|
@@ -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) {
|