@shepai/cli 1.72.9 → 1.73.0-pr222.ef53005
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packages/core/src/application/ports/output/agents/agent-executor-provider.interface.d.ts +1 -1
- package/dist/packages/core/src/application/ports/output/agents/agent-executor-provider.interface.d.ts.map +1 -1
- 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/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +2 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts +4 -2
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-provider.service.js +8 -4
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-runner.service.js +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/structured-agent-caller.service.js +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +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 +83 -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 +177 -350
- 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 +19 -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 +10 -13
- 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 +45 -30
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
- 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 +51 -36
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
- 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 +41 -26
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
- 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 +45 -30
- package/web/.next/server/app/(dashboard)/create/page.js +1 -1
- 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 +51 -36
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
- 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 +41 -26
- package/web/.next/server/app/(dashboard)/page.js +1 -1
- 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 +41 -26
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
- 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_da7eef33.js +3 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +3 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.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/{standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__e5e09f72._.js → server/chunks/ssr/[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/_4f7c70c9._.js +6 -0
- package/web/.next/server/chunks/ssr/_4f7c70c9._.js.map +1 -0
- package/web/.next/server/chunks/ssr/{_1978f325._.js → _5ee4f5a7._.js} +2 -2
- package/web/.next/server/chunks/ssr/_5ee4f5a7._.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/_6e08ce21._.js +1 -1
- package/web/.next/server/chunks/ssr/_6e08ce21._.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/src_presentation_web_163038ba._.js +8 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.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_30d7eeda._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js.map → src_presentation_web_30d7eeda._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js +8 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js.map +1 -0
- package/web/.next/server/chunks/ssr/{src_presentation_web_5ea689db._.js → src_presentation_web_565a14f8._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js.map → src_presentation_web_565a14f8._.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_021a05f2.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.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/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +183 -126
- 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 +45 -30
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
- 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 +51 -36
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
- 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 +41 -26
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
- 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 +45 -30
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js +1 -1
- 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 +51 -36
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
- 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 +41 -26
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js +1 -1
- 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 +41 -26
- package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
- 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_da7eef33.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.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/{server/chunks/ssr/[root-of-the-server]__e5e09f72._.js → standalone/src/presentation/web/.next/server/chunks/ssr/[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/_4f7c70c9._.js +6 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_1978f325._.js → _5ee4f5a7._.js} +2 -2
- 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/_6e08ce21._.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/src_presentation_web_163038ba._.js +8 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{src_presentation_web_7188a290._.js → src_presentation_web_30d7eeda._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js +8 -0
- package/web/.next/{server/chunks/ssr/src_presentation_web_7188a290._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_565a14f8._.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_021a05f2.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_app_(dashboard)_get-graph-data_ts_b018483e._.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/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 +183 -126
- 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 +116 -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 +226 -438
- 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 +20 -5
- package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +13 -13
- 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/0cfed3c69c312c09.js +4 -0
- package/web/.next/static/chunks/0ffccd7be73305c8.css +2 -0
- package/web/.next/static/chunks/{c92e1360ada8ca94.js → 1f5c93a8b939416d.js} +2 -2
- package/web/.next/static/chunks/3f205fd6adbfd20a.js +7 -0
- package/web/.next/static/chunks/4c63764a2d06e45e.js +1 -0
- package/web/.next/static/chunks/{d4492cd12fdf0891.js → 89e74b1c3eb43b03.js} +1 -1
- package/web/.next/static/chunks/{c83897e9213881bf.js → 937d7d4d58942872.js} +1 -1
- package/web/.next/static/chunks/95e3f47abe8032e5.js +1 -0
- package/web/.next/static/chunks/b835e88cdc8c63d2.js +1 -0
- package/web/.next/static/chunks/cb41849bcfaa304e.js +1 -0
- package/web/.next/static/chunks/e2342af6b68c94c1.js +1 -0
- package/web/.next/static/chunks/ed69d6b172ae2bfe.js +1 -0
- package/web/.next/static/chunks/{64850cf4081a2950.js → fd46753cd16664a9.js} +1 -1
- 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/_1978f325._.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/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/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/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/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 → 0yTXyENV4ko7rpM4-3vV8}/_buildManifest.js +0 -0
- /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 0yTXyENV4ko7rpM4-3vV8}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{Atrl1oUfRQej2kgJ972uS → 0yTXyENV4ko7rpM4-3vV8}/_ssgManifest.js +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
4
4
|
import { useRouter } from 'next/navigation';
|
|
5
5
|
import { toast } from 'sonner';
|
|
6
|
-
import { applyNodeChanges } from '@xyflow/react';
|
|
7
6
|
import type { Connection, Edge, NodeChange } from '@xyflow/react';
|
|
8
7
|
import type { FeatureNodeData } from '@/components/common/feature-node';
|
|
8
|
+
import type { RepositoryNodeData } from '@/components/common/repository-node';
|
|
9
9
|
import type { CanvasNodeType } from '@/components/features/features-canvas';
|
|
10
10
|
import {
|
|
11
11
|
layoutWithDagre,
|
|
@@ -15,13 +15,21 @@ import {
|
|
|
15
15
|
import { deleteFeature } from '@/app/actions/delete-feature';
|
|
16
16
|
import { addRepository } from '@/app/actions/add-repository';
|
|
17
17
|
import { deleteRepository } from '@/app/actions/delete-repository';
|
|
18
|
+
import { getFeatureMetadata } from '@/app/actions/get-feature-metadata';
|
|
18
19
|
import { fetchGraphData } from '@/app/actions/get-graph-data';
|
|
19
20
|
import { useAgentEventsContext } from '@/hooks/agent-events-provider';
|
|
20
21
|
import { useSoundAction } from '@/hooks/use-sound-action';
|
|
22
|
+
import { createLogger } from '@/lib/logger';
|
|
23
|
+
|
|
21
24
|
import {
|
|
22
25
|
mapEventTypeToState,
|
|
23
|
-
|
|
26
|
+
resolveSseEventUpdates,
|
|
24
27
|
} from '@/components/common/feature-node/derive-feature-state';
|
|
28
|
+
import { useGraphState, type GraphCallbacks } from '@/hooks/use-graph-state';
|
|
29
|
+
import type { FeatureEntry } from '@/lib/derive-graph';
|
|
30
|
+
|
|
31
|
+
const log = createLogger('[Polling]');
|
|
32
|
+
const POLL_INTERVAL_MS = 3_000;
|
|
25
33
|
|
|
26
34
|
export interface ControlCenterState {
|
|
27
35
|
nodes: CanvasNodeType[];
|
|
@@ -37,8 +45,17 @@ export interface ControlCenterState {
|
|
|
37
45
|
dataOverride?: Partial<FeatureNodeData>,
|
|
38
46
|
edgeType?: string
|
|
39
47
|
) => string;
|
|
48
|
+
/** Stable lookup: repositoryPath for a feature node. */
|
|
49
|
+
getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;
|
|
50
|
+
/** Stable lookup: repository data by nodeId. */
|
|
51
|
+
getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;
|
|
52
|
+
/** Sync callbacks into derived node data (does not trigger re-render). */
|
|
53
|
+
setCallbacks: (callbacks: GraphCallbacks) => void;
|
|
40
54
|
}
|
|
41
55
|
|
|
56
|
+
/** Must match the message string emitted by the SSE route in agent-events/route.ts */
|
|
57
|
+
const METADATA_UPDATED_MESSAGE = 'Feature metadata updated';
|
|
58
|
+
|
|
42
59
|
let nextFeatureId = 0;
|
|
43
60
|
|
|
44
61
|
export function useControlCenterState(
|
|
@@ -46,123 +63,81 @@ export function useControlCenterState(
|
|
|
46
63
|
initialEdges: Edge[]
|
|
47
64
|
): ControlCenterState {
|
|
48
65
|
const router = useRouter();
|
|
49
|
-
const [nodes, setNodes] = useState<CanvasNodeType[]>(initialNodes);
|
|
50
|
-
// eslint-disable-next-line react/hook-use-state -- raw setter renamed; public setEdges wrapper keeps edgesRef in sync
|
|
51
|
-
const [edges, setEdgesRaw] = useState<Edge[]>(initialEdges);
|
|
52
|
-
const edgesRef = useRef<Edge[]>(initialEdges);
|
|
53
|
-
|
|
54
|
-
// Wrapper that keeps edgesRef in sync with edges state, allowing
|
|
55
|
-
// createFeatureNode to read current edges without a closure dependency.
|
|
56
|
-
const setEdges = useCallback((update: Edge[] | ((prev: Edge[]) => Edge[])) => {
|
|
57
|
-
setEdgesRaw((prev) => {
|
|
58
|
-
const next = typeof update === 'function' ? update(prev) : update;
|
|
59
|
-
edgesRef.current = next;
|
|
60
|
-
return next;
|
|
61
|
-
});
|
|
62
|
-
}, []);
|
|
63
66
|
const deleteSound = useSoundAction('delete');
|
|
64
67
|
const createSound = useSoundAction('create');
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
})
|
|
86
|
-
.sort()
|
|
87
|
-
.join(',');
|
|
88
|
-
|
|
89
|
-
// Sync server props into local state — keyed by derived strings (initialNodeKey/initialEdgeKey)
|
|
90
|
-
// to avoid infinite re-renders from unstable array references.
|
|
69
|
+
const {
|
|
70
|
+
nodes,
|
|
71
|
+
edges,
|
|
72
|
+
reconcile,
|
|
73
|
+
updateFeature,
|
|
74
|
+
addPendingFeature,
|
|
75
|
+
removeFeature,
|
|
76
|
+
restoreFeature,
|
|
77
|
+
addRepository: addRepositoryToMap,
|
|
78
|
+
removeRepository,
|
|
79
|
+
replaceRepository,
|
|
80
|
+
getFeatureRepositoryPath,
|
|
81
|
+
getRepositoryData,
|
|
82
|
+
setCallbacks,
|
|
83
|
+
} = useGraphState(initialNodes, initialEdges);
|
|
84
|
+
|
|
85
|
+
// Refs for stable access to latest nodes/edges without callback recreation
|
|
86
|
+
const nodesRef = useRef(nodes);
|
|
87
|
+
const edgesRef = useRef(edges);
|
|
91
88
|
useEffect(() => {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Truly new node with no optimistic counterpart — needs relayout
|
|
121
|
-
needsRelayout = true;
|
|
122
|
-
return serverNode;
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// Also check if non-creating nodes were removed (graph got smaller)
|
|
126
|
-
if (!needsRelayout) {
|
|
127
|
-
needsRelayout = currentNodes.some(
|
|
128
|
-
(cn) =>
|
|
129
|
-
!serverIds.has(cn.id) &&
|
|
130
|
-
!(cn.type === 'featureNode' && (cn.data as FeatureNodeData).state === 'creating')
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (needsRelayout) {
|
|
135
|
-
const layoutResult = layoutWithDagre(merged, initialEdges, CANVAS_LAYOUT_DEFAULTS);
|
|
136
|
-
setEdges(layoutResult.edges);
|
|
137
|
-
return layoutResult.nodes;
|
|
138
|
-
}
|
|
89
|
+
nodesRef.current = nodes;
|
|
90
|
+
edgesRef.current = edges;
|
|
91
|
+
}, [nodes, edges]);
|
|
92
|
+
|
|
93
|
+
// Sync server props into domain Maps when initialNodes/initialEdges change.
|
|
94
|
+
// Keyed by a stable string so we don't re-reconcile on every render.
|
|
95
|
+
const initialNodeKey = useMemo(
|
|
96
|
+
() =>
|
|
97
|
+
initialNodes
|
|
98
|
+
.map((n) => n.id)
|
|
99
|
+
.sort()
|
|
100
|
+
.join(','),
|
|
101
|
+
[initialNodes]
|
|
102
|
+
);
|
|
103
|
+
const initialDataKey = useMemo(
|
|
104
|
+
() =>
|
|
105
|
+
initialNodes
|
|
106
|
+
.filter((n) => n.type === 'featureNode')
|
|
107
|
+
.map((n) => {
|
|
108
|
+
const d = n.data as FeatureNodeData;
|
|
109
|
+
return `${n.id}:${d.state}:${d.lifecycle}`;
|
|
110
|
+
})
|
|
111
|
+
.sort()
|
|
112
|
+
.join(','),
|
|
113
|
+
[initialNodes]
|
|
114
|
+
);
|
|
139
115
|
|
|
140
|
-
|
|
141
|
-
});
|
|
142
|
-
}, [initialNodeKey, initialNodes, initialEdges, setEdges]);
|
|
116
|
+
const prevReconcileKey = useRef('');
|
|
143
117
|
|
|
144
118
|
useEffect(() => {
|
|
145
|
-
|
|
146
|
-
|
|
119
|
+
const key = `${initialNodeKey}|${initialDataKey}`;
|
|
120
|
+
if (key !== prevReconcileKey.current) {
|
|
121
|
+
prevReconcileKey.current = key;
|
|
122
|
+
reconcile(initialNodes, initialEdges);
|
|
123
|
+
}
|
|
124
|
+
}, [initialNodeKey, initialDataKey, initialNodes, initialEdges, reconcile]);
|
|
125
|
+
|
|
126
|
+
// Track previous feature states for fallback notifications
|
|
127
|
+
const prevFeatureStatesRef = useRef<Map<string, FeatureNodeData['state']>>(new Map());
|
|
147
128
|
|
|
148
|
-
// Fallback notifications from server-prop state transitions.
|
|
149
|
-
// Fires only when SSE didn't already deliver the matching event for a feature.
|
|
150
129
|
const { events } = useAgentEventsContext();
|
|
151
130
|
|
|
152
131
|
useEffect(() => {
|
|
153
132
|
const prevStates = prevFeatureStatesRef.current;
|
|
154
|
-
|
|
155
133
|
for (const node of initialNodes) {
|
|
156
134
|
if (node.type !== 'featureNode') continue;
|
|
157
135
|
const data = node.data as FeatureNodeData;
|
|
158
136
|
const prev = prevStates.get(node.id);
|
|
159
|
-
|
|
160
137
|
if (prev !== undefined && prev !== data.state) {
|
|
161
|
-
// Check if SSE already delivered a matching event for this feature
|
|
162
138
|
const sseAlreadyCovered = events.some(
|
|
163
139
|
(e) => e.featureId === data.featureId && mapEventTypeToState(e.eventType) === data.state
|
|
164
140
|
);
|
|
165
|
-
|
|
166
141
|
if (!sseAlreadyCovered) {
|
|
167
142
|
if (data.state === 'done') {
|
|
168
143
|
toast.success(data.name, { description: 'Feature completed!' });
|
|
@@ -171,9 +146,7 @@ export function useControlCenterState(
|
|
|
171
146
|
description: 'Waiting for your approval',
|
|
172
147
|
action: {
|
|
173
148
|
label: 'Review',
|
|
174
|
-
onClick: () => {
|
|
175
|
-
router.push(`/feature/${data.featureId}`);
|
|
176
|
-
},
|
|
149
|
+
onClick: () => router.push(`/feature/${data.featureId}`),
|
|
177
150
|
},
|
|
178
151
|
});
|
|
179
152
|
} else if (data.state === 'error') {
|
|
@@ -181,186 +154,102 @@ export function useControlCenterState(
|
|
|
181
154
|
}
|
|
182
155
|
}
|
|
183
156
|
}
|
|
184
|
-
|
|
185
157
|
prevStates.set(node.id, data.state);
|
|
186
158
|
}
|
|
187
159
|
}, [initialDataKey, initialNodes, events, router]);
|
|
188
160
|
|
|
189
|
-
//
|
|
190
|
-
// Uses `events` array (not `lastEvent`) so that React batching cannot silently
|
|
191
|
-
// drop events when multiple SSE messages arrive in the same tick.
|
|
161
|
+
// SSE effect: only state + lifecycle updates
|
|
192
162
|
const processedEventCountRef = useRef(0);
|
|
193
163
|
|
|
194
164
|
useEffect(() => {
|
|
165
|
+
// Clamp cursor if events were pruned
|
|
166
|
+
if (processedEventCountRef.current > events.length) {
|
|
167
|
+
processedEventCountRef.current = 0;
|
|
168
|
+
}
|
|
195
169
|
if (events.length <= processedEventCountRef.current) return;
|
|
196
|
-
|
|
197
170
|
const newEvents = events.slice(processedEventCountRef.current);
|
|
198
171
|
processedEventCountRef.current = events.length;
|
|
199
172
|
|
|
200
|
-
for (const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (node.type !== 'featureNode') return node;
|
|
208
|
-
const data = node.data as FeatureNodeData;
|
|
209
|
-
if (data.featureId !== event.featureId) return node;
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
...node,
|
|
213
|
-
data: {
|
|
214
|
-
...data,
|
|
215
|
-
state: newState,
|
|
216
|
-
...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
})
|
|
220
|
-
);
|
|
173
|
+
for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {
|
|
174
|
+
if (state !== undefined || lifecycle !== undefined) {
|
|
175
|
+
updateFeature(`feat-${featureId}`, {
|
|
176
|
+
...(state !== undefined && { state }),
|
|
177
|
+
...(lifecycle !== undefined && { lifecycle }),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
221
180
|
}
|
|
222
|
-
}, [events]);
|
|
223
|
-
|
|
224
|
-
// Lightweight server-action polling fallback: fetches fresh graph data every 5s
|
|
225
|
-
// when any feature is in an active state. This avoids full router.refresh() while
|
|
226
|
-
// ensuring the UI stays in sync even if SSE events are missed.
|
|
227
|
-
//
|
|
228
|
-
// We derive a stable boolean so the interval isn't torn down on every node change.
|
|
229
|
-
const hasActiveFeature = nodes.some((n) => {
|
|
230
|
-
if (n.type !== 'featureNode') return false;
|
|
231
|
-
const data = n.data as FeatureNodeData;
|
|
232
|
-
return (
|
|
233
|
-
data.state === 'running' || data.state === 'action-required' || data.state === 'creating'
|
|
234
|
-
);
|
|
235
|
-
});
|
|
181
|
+
}, [events, updateFeature]);
|
|
236
182
|
|
|
183
|
+
// Listen for optimistic approval events from the drawer (fires before SSE arrives)
|
|
237
184
|
useEffect(() => {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (!serverNode || node.type !== 'featureNode') return node;
|
|
250
|
-
const currentData = node.data as FeatureNodeData;
|
|
251
|
-
const serverData = serverNode.data as FeatureNodeData;
|
|
252
|
-
|
|
253
|
-
// Only update if server data has different state or lifecycle
|
|
254
|
-
if (
|
|
255
|
-
currentData.state === serverData.state &&
|
|
256
|
-
currentData.lifecycle === serverData.lifecycle
|
|
257
|
-
) {
|
|
258
|
-
return node;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
changed = true;
|
|
262
|
-
return {
|
|
263
|
-
...node,
|
|
264
|
-
data: {
|
|
265
|
-
...currentData,
|
|
266
|
-
state: serverData.state,
|
|
267
|
-
lifecycle: serverData.lifecycle,
|
|
268
|
-
progress: serverData.progress,
|
|
269
|
-
...(serverData.errorMessage && { errorMessage: serverData.errorMessage }),
|
|
270
|
-
...(serverData.runtime && { runtime: serverData.runtime }),
|
|
271
|
-
...(serverData.agentType && { agentType: serverData.agentType }),
|
|
272
|
-
...(serverData.pr && { pr: serverData.pr }),
|
|
273
|
-
...(serverData.blockedBy && { blockedBy: serverData.blockedBy }),
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
});
|
|
185
|
+
const handler = (e: Event) => {
|
|
186
|
+
const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;
|
|
187
|
+
updateFeature(`feat-${featureId}`, { state: 'running' });
|
|
188
|
+
};
|
|
189
|
+
window.addEventListener('shep:feature-approved', handler);
|
|
190
|
+
return () => window.removeEventListener('shep:feature-approved', handler);
|
|
191
|
+
}, [updateFeature]);
|
|
192
|
+
|
|
193
|
+
// Separate effect: fetch metadata (name + description) when SSE reports it changed
|
|
194
|
+
const metadataFetchedRef = useRef<Set<string>>(new Set());
|
|
195
|
+
const processedMetadataCountRef = useRef(0);
|
|
277
196
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const creatingIndices: number[] = [];
|
|
287
|
-
merged.forEach((n, i) => {
|
|
288
|
-
if (n.type === 'featureNode' && (n.data as FeatureNodeData).state === 'creating') {
|
|
289
|
-
creatingIndices.push(i);
|
|
290
|
-
}
|
|
291
|
-
});
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
// Clamp cursor if events were pruned
|
|
199
|
+
if (processedMetadataCountRef.current > events.length) {
|
|
200
|
+
processedMetadataCountRef.current = 0;
|
|
201
|
+
}
|
|
202
|
+
if (events.length <= processedMetadataCountRef.current) return;
|
|
203
|
+
const newEvents = events.slice(processedMetadataCountRef.current);
|
|
204
|
+
processedMetadataCountRef.current = events.length;
|
|
292
205
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const trueNewNodes = newServerNodes.filter((n) => !replacedIds.has(n.id));
|
|
304
|
-
if (trueNewNodes.length > 0) {
|
|
305
|
-
changed = true;
|
|
306
|
-
return [...merged, ...trueNewNodes];
|
|
307
|
-
}
|
|
206
|
+
for (const event of newEvents) {
|
|
207
|
+
if (event.message !== METADATA_UPDATED_MESSAGE) continue;
|
|
208
|
+
if (metadataFetchedRef.current.has(event.featureId)) continue;
|
|
209
|
+
metadataFetchedRef.current.add(event.featureId);
|
|
210
|
+
|
|
211
|
+
const nodeId = `feat-${event.featureId}`;
|
|
212
|
+
getFeatureMetadata(event.featureId)
|
|
213
|
+
.then((meta) => {
|
|
214
|
+
if (meta) {
|
|
215
|
+
updateFeature(nodeId, { name: meta.name, description: meta.description });
|
|
308
216
|
}
|
|
309
|
-
|
|
310
|
-
|
|
217
|
+
})
|
|
218
|
+
.catch(() => {
|
|
219
|
+
// Silent: metadata fetch failure is non-critical
|
|
311
220
|
});
|
|
312
|
-
} catch {
|
|
313
|
-
// Silently ignore polling errors — SSE is the primary mechanism
|
|
314
|
-
}
|
|
315
|
-
}, 5_000);
|
|
316
|
-
|
|
317
|
-
return () => clearInterval(interval);
|
|
318
|
-
}, [hasActiveFeature]);
|
|
319
|
-
|
|
320
|
-
const onNodesChange = useCallback((changes: NodeChange<CanvasNodeType>[]) => {
|
|
321
|
-
// Filter out 'replace' changes — in controlled mode these come from
|
|
322
|
-
// React Flow's StoreUpdater syncing the nodes prop back into state.
|
|
323
|
-
// Applying them creates a circular update loop (nodes → enrichedNodes →
|
|
324
|
-
// StoreUpdater → onNodesChange → setNodes → nodes → …) that both causes
|
|
325
|
-
// excessive re-renders and overwrites SSE-driven state changes with stale data.
|
|
326
|
-
const applicable = changes.filter((c) => c.type !== 'replace');
|
|
327
|
-
if (applicable.length > 0) {
|
|
328
|
-
setNodes((ns) => applyNodeChanges(applicable, ns));
|
|
329
221
|
}
|
|
330
|
-
}, []);
|
|
331
|
-
|
|
332
|
-
const handleConnect = useCallback(
|
|
333
|
-
(connection: Connection) => {
|
|
334
|
-
if (!connection.source || !connection.target) return;
|
|
222
|
+
}, [events, updateFeature]);
|
|
335
223
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
224
|
+
// --- Polling fallback: catch any SSE events that were missed ---
|
|
225
|
+
useEffect(() => {
|
|
226
|
+
log.debug(`polling enabled (${POLL_INTERVAL_MS}ms interval)`);
|
|
339
227
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
228
|
+
const timer = setInterval(async () => {
|
|
229
|
+
try {
|
|
230
|
+
const { nodes: freshNodes, edges: freshEdges } = await fetchGraphData();
|
|
231
|
+
reconcile(freshNodes, freshEdges);
|
|
232
|
+
} catch {
|
|
233
|
+
log.warn('poll fetch failed — will retry next interval');
|
|
234
|
+
}
|
|
235
|
+
}, POLL_INTERVAL_MS);
|
|
236
|
+
|
|
237
|
+
return () => {
|
|
238
|
+
log.debug('polling disabled');
|
|
239
|
+
clearInterval(timer);
|
|
240
|
+
};
|
|
241
|
+
}, [reconcile]);
|
|
242
|
+
|
|
243
|
+
// onNodesChange is a no-op: nodes are derived from domain Maps.
|
|
244
|
+
// Since nodesDraggable=false and elementsSelectable=false, only React Flow's
|
|
245
|
+
// internal replace/dimensions changes come through — we ignore them all.
|
|
246
|
+
const onNodesChange = useCallback((_changes: NodeChange<CanvasNodeType>[]) => {
|
|
247
|
+
// Intentional no-op: domain Maps are the source of truth.
|
|
248
|
+
}, []);
|
|
358
249
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
[setEdges]
|
|
363
|
-
);
|
|
250
|
+
const handleConnect = useCallback((_connection: Connection) => {
|
|
251
|
+
// Connections are managed via domain operations, not direct edge manipulation.
|
|
252
|
+
}, []);
|
|
364
253
|
|
|
365
254
|
const createFeatureNode = useCallback(
|
|
366
255
|
(
|
|
@@ -368,11 +257,14 @@ export function useControlCenterState(
|
|
|
368
257
|
dataOverride?: Partial<FeatureNodeData>,
|
|
369
258
|
edgeType?: string
|
|
370
259
|
): string => {
|
|
371
|
-
|
|
260
|
+
// Use real feature ID when available (from server), otherwise temp ID
|
|
261
|
+
const id = dataOverride?.featureId
|
|
262
|
+
? `feat-${dataOverride.featureId}`
|
|
263
|
+
: `feature-${Date.now()}-${nextFeatureId++}`;
|
|
372
264
|
const newFeatureData: FeatureNodeData = {
|
|
373
265
|
name: dataOverride?.name ?? 'New Feature',
|
|
374
266
|
description: dataOverride?.description ?? 'Describe what this feature does',
|
|
375
|
-
featureId: `#${id.slice(-4)}`,
|
|
267
|
+
featureId: dataOverride?.featureId ?? `#${id.slice(-4)}`,
|
|
376
268
|
lifecycle: 'requirements',
|
|
377
269
|
state: dataOverride?.state ?? 'running',
|
|
378
270
|
progress: 0,
|
|
@@ -380,171 +272,115 @@ export function useControlCenterState(
|
|
|
380
272
|
branch: dataOverride?.branch ?? '',
|
|
381
273
|
};
|
|
382
274
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
type: 'featureNode' as const,
|
|
387
|
-
position: { x: 0, y: 0 },
|
|
388
|
-
data: newFeatureData,
|
|
389
|
-
} as CanvasNodeType;
|
|
390
|
-
|
|
391
|
-
const newEdge = sourceNodeId
|
|
392
|
-
? {
|
|
393
|
-
id:
|
|
394
|
-
edgeType === 'dependencyEdge'
|
|
395
|
-
? `dep-${sourceNodeId}-${id}`
|
|
396
|
-
: `edge-${sourceNodeId}-${id}`,
|
|
397
|
-
source: sourceNodeId,
|
|
398
|
-
target: id,
|
|
399
|
-
...(edgeType ? { type: edgeType } : { style: { strokeDasharray: '5 5' } }),
|
|
400
|
-
}
|
|
401
|
-
: null;
|
|
402
|
-
|
|
403
|
-
const allEdges = newEdge
|
|
404
|
-
? [...edgesRef.current.filter((e) => e.id !== newEdge.id), newEdge]
|
|
405
|
-
: edgesRef.current;
|
|
406
|
-
|
|
407
|
-
// Insert the new node after the last sibling connected to the same source,
|
|
408
|
-
// so dagre's input-order preservation keeps repo groups together.
|
|
409
|
-
let insertIndex = currentNodes.length;
|
|
410
|
-
if (sourceNodeId) {
|
|
411
|
-
const siblingIds = new Set(
|
|
412
|
-
allEdges.filter((e) => e.source === sourceNodeId).map((e) => e.target)
|
|
413
|
-
);
|
|
414
|
-
for (let i = currentNodes.length - 1; i >= 0; i--) {
|
|
415
|
-
if (siblingIds.has(currentNodes[i].id)) {
|
|
416
|
-
insertIndex = i + 1;
|
|
417
|
-
break;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
const allNodes = [
|
|
422
|
-
...currentNodes.slice(0, insertIndex),
|
|
423
|
-
newNode,
|
|
424
|
-
...currentNodes.slice(insertIndex),
|
|
425
|
-
];
|
|
426
|
-
|
|
427
|
-
// Run dagre layout on the full graph so the new node is positioned consistently
|
|
428
|
-
const layoutResult = layoutWithDagre(allNodes, allEdges, CANVAS_LAYOUT_DEFAULTS);
|
|
429
|
-
setEdges(layoutResult.edges);
|
|
430
|
-
return layoutResult.nodes;
|
|
431
|
-
});
|
|
275
|
+
const parentNodeId = edgeType === 'dependencyEdge' && sourceNodeId ? sourceNodeId : undefined;
|
|
276
|
+
|
|
277
|
+
addPendingFeature(id, newFeatureData, parentNodeId);
|
|
432
278
|
|
|
433
279
|
return id;
|
|
434
280
|
},
|
|
435
|
-
[
|
|
281
|
+
[addPendingFeature]
|
|
436
282
|
);
|
|
437
283
|
|
|
438
284
|
const handleDeleteFeature = useCallback(
|
|
439
285
|
(featureId: string) => {
|
|
440
286
|
const nodeId = `feat-${featureId}`;
|
|
441
287
|
|
|
442
|
-
//
|
|
443
|
-
const
|
|
444
|
-
|
|
288
|
+
// Find the current entry for rollback
|
|
289
|
+
const prevEntry = nodesRef.current
|
|
290
|
+
.filter((n) => n.id === nodeId)
|
|
291
|
+
.map((n) => ({
|
|
292
|
+
nodeId: n.id,
|
|
293
|
+
data: n.data as FeatureNodeData,
|
|
294
|
+
}))[0];
|
|
445
295
|
|
|
446
|
-
// Optimistic removal
|
|
447
|
-
|
|
448
|
-
const remainingNodes = currentNodes.filter((n) => n.id !== nodeId);
|
|
449
|
-
const remainingEdges = edgesRef.current.filter(
|
|
450
|
-
(e) => e.source !== nodeId && e.target !== nodeId
|
|
451
|
-
);
|
|
452
|
-
const layoutResult = layoutWithDagre(
|
|
453
|
-
remainingNodes,
|
|
454
|
-
remainingEdges,
|
|
455
|
-
CANVAS_LAYOUT_DEFAULTS
|
|
456
|
-
);
|
|
457
|
-
setEdges(layoutResult.edges);
|
|
458
|
-
return layoutResult.nodes;
|
|
459
|
-
});
|
|
296
|
+
// Optimistic removal
|
|
297
|
+
removeFeature(nodeId);
|
|
460
298
|
deleteSound.play();
|
|
461
299
|
toast.success('Feature deleted successfully');
|
|
462
300
|
router.push('/');
|
|
463
301
|
|
|
464
|
-
// Persist in background — rollback on failure
|
|
465
302
|
deleteFeature(featureId)
|
|
466
303
|
.then((result) => {
|
|
467
304
|
if (result.error) {
|
|
468
|
-
|
|
469
|
-
setEdges(prevEdges);
|
|
305
|
+
if (prevEntry) restoreFeature(nodeId, prevEntry);
|
|
470
306
|
toast.error(result.error);
|
|
471
307
|
}
|
|
472
308
|
})
|
|
473
309
|
.catch(() => {
|
|
474
|
-
|
|
475
|
-
setEdges(prevEdges);
|
|
310
|
+
if (prevEntry) restoreFeature(nodeId, prevEntry);
|
|
476
311
|
toast.error('Failed to delete feature');
|
|
477
312
|
});
|
|
478
313
|
},
|
|
479
|
-
[
|
|
314
|
+
[router, deleteSound, removeFeature, restoreFeature]
|
|
480
315
|
);
|
|
481
316
|
|
|
482
317
|
const handleDeleteRepository = useCallback(
|
|
483
318
|
async (repositoryId: string) => {
|
|
484
319
|
const repoNodeId = `repo-${repositoryId}`;
|
|
485
320
|
|
|
321
|
+
// Find children of this repo via edges
|
|
322
|
+
const childFeatureIds = new Set(
|
|
323
|
+
edgesRef.current.filter((e) => e.source === repoNodeId).map((e) => e.target)
|
|
324
|
+
);
|
|
325
|
+
|
|
486
326
|
// Snapshot for rollback
|
|
487
|
-
const
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
remainingEdges,
|
|
509
|
-
CANVAS_LAYOUT_DEFAULTS
|
|
510
|
-
);
|
|
511
|
-
setEdges(layoutResult.edges);
|
|
512
|
-
return layoutResult.nodes;
|
|
513
|
-
});
|
|
327
|
+
const prevRepoData = getRepositoryData(repoNodeId);
|
|
328
|
+
const childSnapshots = new Map<string, FeatureEntry>();
|
|
329
|
+
for (const childId of childFeatureIds) {
|
|
330
|
+
const childNode = nodesRef.current.find((n) => n.id === childId);
|
|
331
|
+
if (childNode) {
|
|
332
|
+
childSnapshots.set(childId, { nodeId: childId, data: childNode.data as FeatureNodeData });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const rollback = () => {
|
|
337
|
+
if (prevRepoData) addRepositoryToMap(repoNodeId, prevRepoData);
|
|
338
|
+
for (const [childId, entry] of childSnapshots) {
|
|
339
|
+
restoreFeature(childId, entry);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// Optimistic: remove repo + children
|
|
344
|
+
removeRepository(repoNodeId);
|
|
345
|
+
for (const childId of childFeatureIds) {
|
|
346
|
+
removeFeature(childId);
|
|
347
|
+
}
|
|
514
348
|
|
|
515
349
|
try {
|
|
516
350
|
const result = await deleteRepository(repositoryId);
|
|
517
|
-
|
|
518
351
|
if (!result.success) {
|
|
519
352
|
toast.error(result.error ?? 'Failed to remove repository');
|
|
520
|
-
|
|
521
|
-
setEdges(prevEdges);
|
|
353
|
+
rollback();
|
|
522
354
|
return;
|
|
523
355
|
}
|
|
524
|
-
|
|
525
356
|
deleteSound.play();
|
|
526
357
|
toast.success('Repository removed');
|
|
527
358
|
} catch {
|
|
528
359
|
toast.error('Failed to remove repository');
|
|
529
|
-
|
|
530
|
-
setEdges(prevEdges);
|
|
360
|
+
rollback();
|
|
531
361
|
}
|
|
532
362
|
},
|
|
533
|
-
[
|
|
363
|
+
[
|
|
364
|
+
deleteSound,
|
|
365
|
+
removeRepository,
|
|
366
|
+
removeFeature,
|
|
367
|
+
addRepositoryToMap,
|
|
368
|
+
restoreFeature,
|
|
369
|
+
getRepositoryData,
|
|
370
|
+
]
|
|
534
371
|
);
|
|
535
372
|
|
|
536
373
|
const handleLayout = useCallback(
|
|
537
374
|
(direction: LayoutDirection) => {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
setEdges(result.edges);
|
|
544
|
-
return result.nodes;
|
|
375
|
+
// Layout is applied via reconcile on next server prop update.
|
|
376
|
+
// For immediate re-layout, we apply dagre and trigger a reconcile-like update.
|
|
377
|
+
const result = layoutWithDagre(nodesRef.current, edgesRef.current, {
|
|
378
|
+
...CANVAS_LAYOUT_DEFAULTS,
|
|
379
|
+
direction,
|
|
545
380
|
});
|
|
381
|
+
reconcile(result.nodes, result.edges);
|
|
546
382
|
},
|
|
547
|
-
[
|
|
383
|
+
[reconcile]
|
|
548
384
|
);
|
|
549
385
|
|
|
550
386
|
const handleAddRepository = useCallback(
|
|
@@ -556,81 +392,30 @@ export function useControlCenterState(
|
|
|
556
392
|
.split(/[\\/]/)
|
|
557
393
|
.pop() ?? path;
|
|
558
394
|
|
|
559
|
-
|
|
560
|
-
setNodes((currentNodes) => {
|
|
561
|
-
const newNode = {
|
|
562
|
-
id: tempId,
|
|
563
|
-
type: 'repositoryNode' as const,
|
|
564
|
-
position: { x: 0, y: 0 },
|
|
565
|
-
data: { name: repoName, repositoryPath: path, id: tempId },
|
|
566
|
-
} as CanvasNodeType;
|
|
567
|
-
|
|
568
|
-
const allNodes = [...currentNodes, newNode];
|
|
569
|
-
const layoutResult = layoutWithDagre(allNodes, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
|
|
570
|
-
setEdges(layoutResult.edges);
|
|
571
|
-
return layoutResult.nodes;
|
|
572
|
-
});
|
|
395
|
+
addRepositoryToMap(tempId, { name: repoName, repositoryPath: path, id: tempId });
|
|
573
396
|
|
|
574
|
-
// Persist via server action
|
|
575
397
|
addRepository({ path, name: repoName })
|
|
576
398
|
.then((result) => {
|
|
577
399
|
if (result.error) {
|
|
578
|
-
|
|
579
|
-
setNodes((prev) => {
|
|
580
|
-
const remaining = prev.filter((n) => n.id !== tempId);
|
|
581
|
-
const layoutResult = layoutWithDagre(
|
|
582
|
-
remaining,
|
|
583
|
-
edgesRef.current,
|
|
584
|
-
CANVAS_LAYOUT_DEFAULTS
|
|
585
|
-
);
|
|
586
|
-
setEdges(layoutResult.edges);
|
|
587
|
-
return layoutResult.nodes;
|
|
588
|
-
});
|
|
400
|
+
removeRepository(tempId);
|
|
589
401
|
toast.error(result.error);
|
|
590
402
|
return;
|
|
591
403
|
}
|
|
592
|
-
|
|
593
|
-
// Replace temp ID with real repository ID
|
|
594
404
|
const repo = result.repository!;
|
|
595
405
|
const realId = `repo-${repo.id}`;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
id: realId,
|
|
602
|
-
data: { ...n.data, id: repo.id, repositoryPath: repo.path },
|
|
603
|
-
} as CanvasNodeType)
|
|
604
|
-
: n
|
|
605
|
-
)
|
|
606
|
-
);
|
|
607
|
-
setEdges((prev) =>
|
|
608
|
-
prev.map((e) => ({
|
|
609
|
-
...e,
|
|
610
|
-
source: e.source === tempId ? realId : e.source,
|
|
611
|
-
target: e.target === tempId ? realId : e.target,
|
|
612
|
-
id: e.id.replace(tempId, realId),
|
|
613
|
-
}))
|
|
614
|
-
);
|
|
615
|
-
|
|
406
|
+
replaceRepository(tempId, realId, {
|
|
407
|
+
name: repo.name,
|
|
408
|
+
repositoryPath: repo.path,
|
|
409
|
+
id: repo.id,
|
|
410
|
+
});
|
|
616
411
|
createSound.play();
|
|
617
412
|
})
|
|
618
413
|
.catch(() => {
|
|
619
|
-
|
|
620
|
-
setNodes((prev) => {
|
|
621
|
-
const remaining = prev.filter((n) => n.id !== tempId);
|
|
622
|
-
const layoutResult = layoutWithDagre(
|
|
623
|
-
remaining,
|
|
624
|
-
edgesRef.current,
|
|
625
|
-
CANVAS_LAYOUT_DEFAULTS
|
|
626
|
-
);
|
|
627
|
-
setEdges(layoutResult.edges);
|
|
628
|
-
return layoutResult.nodes;
|
|
629
|
-
});
|
|
414
|
+
removeRepository(tempId);
|
|
630
415
|
toast.error('Failed to add repository');
|
|
631
416
|
});
|
|
632
417
|
},
|
|
633
|
-
[
|
|
418
|
+
[addRepositoryToMap, removeRepository, replaceRepository, createSound]
|
|
634
419
|
);
|
|
635
420
|
|
|
636
421
|
return {
|
|
@@ -643,5 +428,8 @@ export function useControlCenterState(
|
|
|
643
428
|
handleDeleteFeature,
|
|
644
429
|
handleDeleteRepository,
|
|
645
430
|
createFeatureNode,
|
|
431
|
+
getFeatureRepositoryPath,
|
|
432
|
+
getRepositoryData,
|
|
433
|
+
setCallbacks,
|
|
646
434
|
};
|
|
647
435
|
}
|