@shepai/cli 1.72.8 → 1.72.9-pr220.e1bfec0
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/feature-agent-process.interface.d.ts +2 -1
- package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.js +1 -0
- 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/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.js +1 -0
- package/dist/packages/core/src/domain/factories/settings-defaults.factory.js +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/dev-executor.service.js +88 -13
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +3 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +16 -3
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +5 -1
- 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/actions/get-graph-data.d.ts +10 -0
- package/dist/src/presentation/web/app/actions/get-graph-data.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/get-graph-data.js +10 -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 +18 -0
- 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 +21 -23
- 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 +35 -16
- 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 +2 -0
- package/dist/src/presentation/web/components/common/index.d.ts +1 -1
- package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/index.js +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
- 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 +23 -4
- 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 +154 -258
- 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 +12 -44
- 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/scroll-area.js +1 -1
- package/dist/src/presentation/web/hooks/use-graph-state.d.ts +41 -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 +230 -0
- 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/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 +43 -28
- 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 +49 -34
- 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 +39 -24
- 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 +43 -28
- 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 +49 -34
- 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 +39 -24
- 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 +39 -24
- 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_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]__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/_0e9d6bf7._.js +1 -1
- package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_250a63ae._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
- package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_63688261._.js +6 -0
- package/web/.next/server/chunks/ssr/_63688261._.js.map +1 -0
- 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/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_398553b0._.js → server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_5c87e8e4._.js.map → src_presentation_web_2b91e4ec._.js.map} +1 -1
- package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5c87e8e4._.js → server/chunks/ssr/src_presentation_web_5bcc1537._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_398553b0._.js.map → src_presentation_web_5bcc1537._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_5955c012.js +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 +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +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 +175 -118
- 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 +43 -28
- 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 +49 -34
- 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 +39 -24
- 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 +43 -28
- 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 +49 -34
- 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 +39 -24
- 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 +39 -24
- 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_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]__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/_0e9d6bf7._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_63688261._.js +6 -0
- 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/{server/chunks/ssr/src_presentation_web_398553b0._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_2b91e4ec._.js} +2 -2
- package/web/.next/{server/chunks/ssr/src_presentation_web_5c87e8e4._.js → standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_5bcc1537._.js} +2 -2
- 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 +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_d5b0cb86._.js +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 +175 -118
- package/web/.next/standalone/src/presentation/web/CLAUDE.md +191 -0
- 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/actions/get-graph-data.ts +12 -0
- package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +21 -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 +23 -26
- package/web/.next/standalone/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx +44 -18
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +2 -0
- package/web/.next/standalone/src/presentation/web/components/common/index.ts +1 -5
- 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/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 +24 -8
- 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 +183 -326
- 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 +34 -82
- 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/scroll-area.tsx +1 -1
- package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +343 -0
- 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/server.js +1 -1
- package/web/.next/static/chunks/{71cf72022f08a8c9.js → 0a883e2efecfd563.js} +1 -1
- package/web/.next/static/chunks/{ebf172a84c9596ed.js → 596ca28d78baae25.js} +1 -1
- package/web/.next/static/chunks/{1c07b21eb8b32f25.js → 638824249d103905.js} +1 -1
- package/web/.next/static/chunks/63a80e9d4c4b0253.js +4 -0
- package/web/.next/static/chunks/71c9ecdceac1939f.css +2 -0
- package/web/.next/static/chunks/a040b058d79f4ade.js +1 -0
- package/web/.next/static/chunks/{fcafb841e3860687.js → c575ab63c138645b.js} +1 -1
- package/web/.next/static/chunks/cdc92cdf81005c84.js +1 -0
- package/web/.next/static/chunks/{fabfa54940973cc7.js → e05eb1cc84ee254a.js} +1 -1
- package/web/.next/static/chunks/{8682dcb376de62de.js → ef8f8940eac6c542.js} +1 -1
- package/web/.next/static/chunks/f32c98a709949c5b.js +1 -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/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_2b7834f6.js +0 -3
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_2b7834f6.js.map +0 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_6923c575.js +0 -3
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_6923c575.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/_47ef589d._.js +0 -6
- package/web/.next/server/chunks/ssr/_47ef589d._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_1a32dbcb._.js +0 -8
- package/web/.next/server/chunks/ssr/src_presentation_web_1a32dbcb._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f4952172.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f4952172.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c1bc6240._.js +0 -8
- package/web/.next/server/chunks/ssr/src_presentation_web_c1bc6240._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_2b7834f6.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_6923c575.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_47ef589d._.js +0 -6
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_1a32dbcb._.js +0 -8
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f4952172.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_c1bc6240._.js +0 -8
- 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/static/chunks/3c79bca4d3f18f66.js +0 -1
- package/web/.next/static/chunks/5cd24ca47061a21d.js +0 -4
- package/web/.next/static/chunks/67f2a7a5e8dc358a.css +0 -2
- package/web/.next/static/chunks/991d4490d7a338d8.js +0 -1
- package/web/.next/static/chunks/c71589df79020ecb.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/{IKuYPxAuMvc4BtwKHlj30 → uMxPSDPwZCludF5408rWJ}/_buildManifest.js +0 -0
- /package/web/.next/static/{IKuYPxAuMvc4BtwKHlj30 → uMxPSDPwZCludF5408rWJ}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{IKuYPxAuMvc4BtwKHlj30 → uMxPSDPwZCludF5408rWJ}/_ssgManifest.js +0 -0
package/dist/src/presentation/web/components/features/control-center/control-center.stories.js
CHANGED
|
@@ -83,12 +83,6 @@ const repoNode = {
|
|
|
83
83
|
position: { x: 50, y: 115 },
|
|
84
84
|
data: { name: 'shep-ai/cli' },
|
|
85
85
|
};
|
|
86
|
-
const addRepoNode = {
|
|
87
|
-
id: 'add-repo',
|
|
88
|
-
type: 'addRepositoryNode',
|
|
89
|
-
position: { x: 50, y: 302 },
|
|
90
|
-
data: {},
|
|
91
|
-
};
|
|
92
86
|
const dashedEdge = { style: { strokeDasharray: '5 5' } };
|
|
93
87
|
export const Empty = {
|
|
94
88
|
args: {
|
|
@@ -113,7 +107,7 @@ export const WithToolbar = {
|
|
|
113
107
|
};
|
|
114
108
|
export const WithNodeActions = {
|
|
115
109
|
args: {
|
|
116
|
-
initialNodes: [repoNode,
|
|
110
|
+
initialNodes: [repoNode, ...featureNodes],
|
|
117
111
|
initialEdges: [
|
|
118
112
|
{ id: 'e-repo-f1', source: 'repo-1', target: 'feat-1', ...dashedEdge },
|
|
119
113
|
{ id: 'e-repo-f2', source: 'repo-1', target: 'feat-2', ...dashedEdge },
|
|
@@ -121,29 +115,6 @@ export const WithNodeActions = {
|
|
|
121
115
|
],
|
|
122
116
|
},
|
|
123
117
|
};
|
|
124
|
-
/**
|
|
125
|
-
* Interactive story — starts with just an "Add Repository" button.
|
|
126
|
-
*
|
|
127
|
-
* User flow:
|
|
128
|
-
* 1. Click "Add Repository" → native folder picker → select a folder → repo node appears
|
|
129
|
-
* 2. Hover the repo node → click (+) → a new feature node appears connected to the repo
|
|
130
|
-
* 3. Hover the feature node → click (+) → another feature appears connected to the first
|
|
131
|
-
*
|
|
132
|
-
* You can also use the toolbar "Add Feature" button to create unconnected features.
|
|
133
|
-
*/
|
|
134
|
-
export const Interactive = {
|
|
135
|
-
args: {
|
|
136
|
-
initialNodes: [
|
|
137
|
-
{
|
|
138
|
-
id: 'add-repo',
|
|
139
|
-
type: 'addRepositoryNode',
|
|
140
|
-
position: { x: 50, y: 50 },
|
|
141
|
-
data: {},
|
|
142
|
-
},
|
|
143
|
-
],
|
|
144
|
-
initialEdges: [],
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
118
|
// --- Dagre-layouted story: multiple repos with feature trees ---
|
|
148
119
|
const dagreRepoNodes = [
|
|
149
120
|
{
|
|
@@ -237,13 +208,7 @@ const dagreFeatureNodes = [
|
|
|
237
208
|
},
|
|
238
209
|
},
|
|
239
210
|
];
|
|
240
|
-
const
|
|
241
|
-
id: 'add-repo',
|
|
242
|
-
type: 'addRepositoryNode',
|
|
243
|
-
position: { x: 0, y: 0 },
|
|
244
|
-
data: {},
|
|
245
|
-
};
|
|
246
|
-
const dagreNodesRaw = [...dagreRepoNodes, ...dagreFeatureNodes, dagreAddRepo];
|
|
211
|
+
const dagreNodesRaw = [...dagreRepoNodes, ...dagreFeatureNodes];
|
|
247
212
|
const dagreEdges = [
|
|
248
213
|
// cli repo → Auth, SSO
|
|
249
214
|
{ id: 'e-cli-auth', source: 'repo-cli', target: 'feat-auth', style: { strokeDasharray: '5 5' } },
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Connection, Edge, NodeChange } from '@xyflow/react';
|
|
2
2
|
import type { FeatureNodeData } from '../../common/feature-node/index.js';
|
|
3
|
+
import type { RepositoryNodeData } from '../../common/repository-node/index.js';
|
|
3
4
|
import type { CanvasNodeType } from '../../features/features-canvas/index.js';
|
|
4
5
|
import { type LayoutDirection } from '../../../lib/layout-with-dagre.js';
|
|
6
|
+
import { type GraphCallbacks } from '../../../hooks/use-graph-state.js';
|
|
5
7
|
export interface ControlCenterState {
|
|
6
8
|
nodes: CanvasNodeType[];
|
|
7
9
|
edges: Edge[];
|
|
@@ -12,6 +14,12 @@ export interface ControlCenterState {
|
|
|
12
14
|
handleDeleteFeature: (featureId: string) => void;
|
|
13
15
|
handleDeleteRepository: (repositoryId: string) => Promise<void>;
|
|
14
16
|
createFeatureNode: (sourceNodeId: string | null, dataOverride?: Partial<FeatureNodeData>, edgeType?: string) => string;
|
|
17
|
+
/** Stable lookup: repositoryPath for a feature node. */
|
|
18
|
+
getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;
|
|
19
|
+
/** Stable lookup: repository data by nodeId. */
|
|
20
|
+
getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;
|
|
21
|
+
/** Sync callbacks into derived node data (does not trigger re-render). */
|
|
22
|
+
setCallbacks: (callbacks: GraphCallbacks) => void;
|
|
15
23
|
}
|
|
16
24
|
export declare function useControlCenterState(initialNodes: CanvasNodeType[], initialEdges: Edge[]): ControlCenterState;
|
|
17
25
|
//# sourceMappingURL=use-control-center-state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAYjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAE7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAID,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAuVpB"}
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js
CHANGED
|
@@ -1,45 +1,29 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
3
3
|
import { useRouter } from 'next/navigation';
|
|
4
4
|
import { toast } from 'sonner';
|
|
5
|
-
import { applyNodeChanges } from '@xyflow/react';
|
|
6
5
|
import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS, } from '../../../lib/layout-with-dagre.js';
|
|
7
6
|
import { deleteFeature } from '../../../app/actions/delete-feature.js';
|
|
8
7
|
import { addRepository } from '../../../app/actions/add-repository.js';
|
|
9
8
|
import { deleteRepository } from '../../../app/actions/delete-repository.js';
|
|
9
|
+
import { getFeatureMetadata } from '../../../app/actions/get-feature-metadata.js';
|
|
10
10
|
import { useAgentEventsContext } from '../../../hooks/agent-events-provider.js';
|
|
11
11
|
import { useSoundAction } from '../../../hooks/use-sound-action.js';
|
|
12
12
|
import { mapEventTypeToState, mapPhaseNameToLifecycle, } from '../../common/feature-node/derive-feature-state.js';
|
|
13
|
+
import { NotificationEventType } from '../../../../../../packages/core/src/domain/generated/output.js';
|
|
14
|
+
import { useGraphState } from '../../../hooks/use-graph-state.js';
|
|
13
15
|
let nextFeatureId = 0;
|
|
14
16
|
export function useControlCenterState(initialNodes, initialEdges) {
|
|
15
17
|
const router = useRouter();
|
|
16
|
-
const [nodes, setNodes] = useState(initialNodes);
|
|
17
|
-
// eslint-disable-next-line react/hook-use-state -- raw setter renamed; public setEdges wrapper keeps edgesRef in sync
|
|
18
|
-
const [edges, setEdgesRaw] = useState(initialEdges);
|
|
19
|
-
const edgesRef = useRef(initialEdges);
|
|
20
|
-
// Wrapper that keeps edgesRef in sync with edges state, allowing
|
|
21
|
-
// createFeatureNode to read current edges without a closure dependency.
|
|
22
|
-
const setEdges = useCallback((update) => {
|
|
23
|
-
setEdgesRaw((prev) => {
|
|
24
|
-
const next = typeof update === 'function' ? update(prev) : update;
|
|
25
|
-
edgesRef.current = next;
|
|
26
|
-
return next;
|
|
27
|
-
});
|
|
28
|
-
}, []);
|
|
29
18
|
const deleteSound = useSoundAction('delete');
|
|
30
19
|
const createSound = useSoundAction('create');
|
|
31
|
-
|
|
20
|
+
const { nodes, edges, reconcile, updateFeature, addPendingFeature, removeFeature, restoreFeature, addRepository: addRepositoryToMap, removeRepository, replaceRepository, getFeatureRepositoryPath, getRepositoryData, setCallbacks, } = useGraphState(initialNodes, initialEdges);
|
|
21
|
+
// Sync server props into domain Maps when initialNodes/initialEdges change.
|
|
22
|
+
// Keyed by a stable string so we don't re-reconcile on every render.
|
|
32
23
|
const initialNodeKey = initialNodes
|
|
33
24
|
.map((n) => n.id)
|
|
34
25
|
.sort()
|
|
35
26
|
.join(',');
|
|
36
|
-
const initialEdgeKey = initialEdges
|
|
37
|
-
.map((e) => e.id)
|
|
38
|
-
.sort()
|
|
39
|
-
.join(',');
|
|
40
|
-
// Track previous feature states so we can detect transitions on server refresh
|
|
41
|
-
const prevFeatureStatesRef = useRef(new Map());
|
|
42
|
-
// Stable key that changes when feature DATA changes (state/lifecycle), not just IDs.
|
|
43
27
|
const initialDataKey = initialNodes
|
|
44
28
|
.filter((n) => n.type === 'featureNode')
|
|
45
29
|
.map((n) => {
|
|
@@ -48,52 +32,24 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
48
32
|
})
|
|
49
33
|
.sort()
|
|
50
34
|
.join(',');
|
|
51
|
-
|
|
52
|
-
// to avoid infinite re-renders from unstable array references.
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
setNodes((currentNodes) => {
|
|
55
|
-
// Build a lookup of current node positions by ID
|
|
56
|
-
const currentById = new Map(currentNodes.map((n) => [n.id, n]));
|
|
57
|
-
// Identify optimistic "creating" nodes (they have temp IDs not in server data)
|
|
58
|
-
const serverIds = new Set(initialNodes.map((n) => n.id));
|
|
59
|
-
const creatingNodes = currentNodes.filter((n) => n.type === 'featureNode' &&
|
|
60
|
-
n.data.state === 'creating' &&
|
|
61
|
-
!serverIds.has(n.id));
|
|
62
|
-
// Merge server nodes with client positions, tracking if relayout is needed
|
|
63
|
-
let needsRelayout = false;
|
|
64
|
-
const merged = initialNodes.map((serverNode) => {
|
|
65
|
-
// Node already exists on canvas — keep its position, update data
|
|
66
|
-
const existing = currentById.get(serverNode.id);
|
|
67
|
-
if (existing) {
|
|
68
|
-
return { ...serverNode, position: existing.position };
|
|
69
|
-
}
|
|
70
|
-
// New server node — inherit position from an optimistic creating node if available
|
|
71
|
-
if (serverNode.type === 'featureNode' && creatingNodes.length > 0) {
|
|
72
|
-
const donor = creatingNodes.shift();
|
|
73
|
-
return { ...serverNode, position: donor.position };
|
|
74
|
-
}
|
|
75
|
-
// Truly new node with no optimistic counterpart — needs relayout
|
|
76
|
-
needsRelayout = true;
|
|
77
|
-
return serverNode;
|
|
78
|
-
});
|
|
79
|
-
// Also check if non-creating nodes were removed (graph got smaller)
|
|
80
|
-
if (!needsRelayout) {
|
|
81
|
-
needsRelayout = currentNodes.some((cn) => !serverIds.has(cn.id) &&
|
|
82
|
-
!(cn.type === 'featureNode' && cn.data.state === 'creating'));
|
|
83
|
-
}
|
|
84
|
-
if (needsRelayout) {
|
|
85
|
-
const layoutResult = layoutWithDagre(merged, initialEdges, CANVAS_LAYOUT_DEFAULTS);
|
|
86
|
-
setEdges(layoutResult.edges);
|
|
87
|
-
return layoutResult.nodes;
|
|
88
|
-
}
|
|
89
|
-
return merged;
|
|
90
|
-
});
|
|
91
|
-
}, [initialNodeKey, initialNodes, initialEdges, setEdges]);
|
|
35
|
+
const prevReconcileKey = useRef('');
|
|
92
36
|
useEffect(() => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
37
|
+
const key = `${initialNodeKey}|${initialDataKey}`;
|
|
38
|
+
if (key !== prevReconcileKey.current) {
|
|
39
|
+
prevReconcileKey.current = key;
|
|
40
|
+
reconcile(initialNodes, initialEdges);
|
|
41
|
+
}
|
|
42
|
+
}, [initialNodeKey, initialDataKey, initialNodes, initialEdges, reconcile]);
|
|
43
|
+
// Track previous feature states for fallback notifications
|
|
44
|
+
const prevFeatureStatesRef = useRef(new Map());
|
|
45
|
+
const initialFeatureDataKey = initialNodes
|
|
46
|
+
.filter((n) => n.type === 'featureNode')
|
|
47
|
+
.map((n) => {
|
|
48
|
+
const d = n.data;
|
|
49
|
+
return `${n.id}:${d.state}`;
|
|
50
|
+
})
|
|
51
|
+
.sort()
|
|
52
|
+
.join(',');
|
|
97
53
|
const { events } = useAgentEventsContext();
|
|
98
54
|
useEffect(() => {
|
|
99
55
|
const prevStates = prevFeatureStatesRef.current;
|
|
@@ -103,7 +59,6 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
103
59
|
const data = node.data;
|
|
104
60
|
const prev = prevStates.get(node.id);
|
|
105
61
|
if (prev !== undefined && prev !== data.state) {
|
|
106
|
-
// Check if SSE already delivered a matching event for this feature
|
|
107
62
|
const sseAlreadyCovered = events.some((e) => e.featureId === data.featureId && mapEventTypeToState(e.eventType) === data.state);
|
|
108
63
|
if (!sseAlreadyCovered) {
|
|
109
64
|
if (data.state === 'done') {
|
|
@@ -114,9 +69,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
114
69
|
description: 'Waiting for your approval',
|
|
115
70
|
action: {
|
|
116
71
|
label: 'Review',
|
|
117
|
-
onClick: () => {
|
|
118
|
-
router.push(`/feature/${data.featureId}`);
|
|
119
|
-
},
|
|
72
|
+
onClick: () => router.push(`/feature/${data.featureId}`),
|
|
120
73
|
},
|
|
121
74
|
});
|
|
122
75
|
}
|
|
@@ -127,179 +80,139 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
127
80
|
}
|
|
128
81
|
prevStates.set(node.id, data.state);
|
|
129
82
|
}
|
|
130
|
-
}, [
|
|
131
|
-
//
|
|
132
|
-
// Uses `events` array (not `lastEvent`) so that React batching cannot silently
|
|
133
|
-
// drop events when multiple SSE messages arrive in the same tick.
|
|
83
|
+
}, [initialFeatureDataKey, initialNodes, events, router]);
|
|
84
|
+
// SSE effect: only state + lifecycle updates
|
|
134
85
|
const processedEventCountRef = useRef(0);
|
|
135
86
|
useEffect(() => {
|
|
136
87
|
if (events.length <= processedEventCountRef.current)
|
|
137
88
|
return;
|
|
138
89
|
const newEvents = events.slice(processedEventCountRef.current);
|
|
139
90
|
processedEventCountRef.current = events.length;
|
|
91
|
+
// PhaseCompleted must NOT set state when WaitingApproval is in the same poll batch —
|
|
92
|
+
// they arrive together and PhaseCompleted → 'running' would revert 'action-required'.
|
|
93
|
+
// But when PhaseCompleted arrives WITHOUT WaitingApproval (e.g. after approval), we
|
|
94
|
+
// must allow it to update state as a fallback for any missed AgentStarted event.
|
|
95
|
+
const waitingApprovalFeatures = new Set(newEvents
|
|
96
|
+
.filter((e) => e.eventType === NotificationEventType.WaitingApproval)
|
|
97
|
+
.map((e) => e.featureId));
|
|
140
98
|
for (const event of newEvents) {
|
|
141
|
-
const newState =
|
|
99
|
+
const newState = event.eventType === NotificationEventType.PhaseCompleted &&
|
|
100
|
+
waitingApprovalFeatures.has(event.featureId)
|
|
101
|
+
? undefined
|
|
102
|
+
: mapEventTypeToState(event.eventType);
|
|
142
103
|
const newLifecycle = mapPhaseNameToLifecycle(event.phaseName);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (data.featureId !== event.featureId)
|
|
149
|
-
return node;
|
|
150
|
-
return {
|
|
151
|
-
...node,
|
|
152
|
-
data: {
|
|
153
|
-
...data,
|
|
154
|
-
state: newState,
|
|
155
|
-
...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
}));
|
|
159
|
-
}
|
|
160
|
-
}, [events]);
|
|
161
|
-
const onNodesChange = useCallback((changes) => {
|
|
162
|
-
setNodes((ns) => applyNodeChanges(changes, ns));
|
|
163
|
-
}, []);
|
|
164
|
-
const handleConnect = useCallback((connection) => {
|
|
165
|
-
if (!connection.source || !connection.target)
|
|
166
|
-
return;
|
|
167
|
-
setNodes((currentNodes) => {
|
|
168
|
-
const sourceNode = currentNodes.find((n) => n.id === connection.source);
|
|
169
|
-
if (sourceNode?.type !== 'repositoryNode')
|
|
170
|
-
return currentNodes;
|
|
171
|
-
// Block if target feature already has a repo source
|
|
172
|
-
setEdges((currentEdges) => {
|
|
173
|
-
const targetAlreadyHasRepo = currentEdges.some((e) => {
|
|
174
|
-
const edgeSource = currentNodes.find((n) => n.id === e.source);
|
|
175
|
-
return edgeSource?.type === 'repositoryNode' && e.target === connection.target;
|
|
104
|
+
const nodeId = `feat-${event.featureId}`;
|
|
105
|
+
if (newState !== undefined || newLifecycle !== undefined) {
|
|
106
|
+
updateFeature(nodeId, {
|
|
107
|
+
...(newState !== undefined && { state: newState }),
|
|
108
|
+
...(newLifecycle !== undefined && { lifecycle: newLifecycle }),
|
|
176
109
|
});
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, [events, updateFeature]);
|
|
113
|
+
// Separate effect: fetch metadata (name + description) when SSE reports it changed
|
|
114
|
+
const metadataFetchedRef = useRef(new Set());
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
for (const event of events) {
|
|
117
|
+
if (event.message !== 'Feature metadata updated')
|
|
118
|
+
continue;
|
|
119
|
+
if (metadataFetchedRef.current.has(event.featureId))
|
|
120
|
+
continue;
|
|
121
|
+
metadataFetchedRef.current.add(event.featureId);
|
|
122
|
+
const nodeId = `feat-${event.featureId}`;
|
|
123
|
+
getFeatureMetadata(event.featureId)
|
|
124
|
+
.then((meta) => {
|
|
125
|
+
if (meta) {
|
|
126
|
+
updateFeature(nodeId, { name: meta.name, description: meta.description });
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
.catch(() => {
|
|
130
|
+
// Silent: metadata fetch failure is non-critical
|
|
188
131
|
});
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
132
|
+
}
|
|
133
|
+
}, [events, updateFeature]);
|
|
134
|
+
// onNodesChange is a no-op: nodes are derived from domain Maps.
|
|
135
|
+
// Since nodesDraggable=false and elementsSelectable=false, only React Flow's
|
|
136
|
+
// internal replace/dimensions changes come through — we ignore them all.
|
|
137
|
+
const onNodesChange = useCallback((_changes) => {
|
|
138
|
+
// Intentional no-op: domain Maps are the source of truth.
|
|
139
|
+
}, []);
|
|
140
|
+
const handleConnect = useCallback((_connection) => {
|
|
141
|
+
// Connections are managed via domain operations, not direct edge manipulation.
|
|
142
|
+
}, []);
|
|
192
143
|
const createFeatureNode = useCallback((sourceNodeId, dataOverride, edgeType) => {
|
|
193
|
-
|
|
144
|
+
// Use real feature ID when available (from server), otherwise temp ID
|
|
145
|
+
const id = dataOverride?.featureId
|
|
146
|
+
? `feat-${dataOverride.featureId}`
|
|
147
|
+
: `feature-${Date.now()}-${nextFeatureId++}`;
|
|
194
148
|
const newFeatureData = {
|
|
195
149
|
name: dataOverride?.name ?? 'New Feature',
|
|
196
150
|
description: dataOverride?.description ?? 'Describe what this feature does',
|
|
197
|
-
featureId: `#${id.slice(-4)}`,
|
|
151
|
+
featureId: dataOverride?.featureId ?? `#${id.slice(-4)}`,
|
|
198
152
|
lifecycle: 'requirements',
|
|
199
153
|
state: dataOverride?.state ?? 'running',
|
|
200
154
|
progress: 0,
|
|
201
155
|
repositoryPath: dataOverride?.repositoryPath ?? '',
|
|
202
156
|
branch: dataOverride?.branch ?? '',
|
|
203
157
|
};
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
id,
|
|
207
|
-
type: 'featureNode',
|
|
208
|
-
position: { x: 0, y: 0 },
|
|
209
|
-
data: newFeatureData,
|
|
210
|
-
};
|
|
211
|
-
const newEdge = sourceNodeId
|
|
212
|
-
? {
|
|
213
|
-
id: edgeType === 'dependencyEdge'
|
|
214
|
-
? `dep-${sourceNodeId}-${id}`
|
|
215
|
-
: `edge-${sourceNodeId}-${id}`,
|
|
216
|
-
source: sourceNodeId,
|
|
217
|
-
target: id,
|
|
218
|
-
...(edgeType ? { type: edgeType } : { style: { strokeDasharray: '5 5' } }),
|
|
219
|
-
}
|
|
220
|
-
: null;
|
|
221
|
-
const allEdges = newEdge
|
|
222
|
-
? [...edgesRef.current.filter((e) => e.id !== newEdge.id), newEdge]
|
|
223
|
-
: edgesRef.current;
|
|
224
|
-
// Insert the new node after the last sibling connected to the same source,
|
|
225
|
-
// so dagre's input-order preservation keeps repo groups together.
|
|
226
|
-
let insertIndex = currentNodes.length;
|
|
227
|
-
if (sourceNodeId) {
|
|
228
|
-
const siblingIds = new Set(allEdges.filter((e) => e.source === sourceNodeId).map((e) => e.target));
|
|
229
|
-
for (let i = currentNodes.length - 1; i >= 0; i--) {
|
|
230
|
-
if (siblingIds.has(currentNodes[i].id)) {
|
|
231
|
-
insertIndex = i + 1;
|
|
232
|
-
break;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
const allNodes = [
|
|
237
|
-
...currentNodes.slice(0, insertIndex),
|
|
238
|
-
newNode,
|
|
239
|
-
...currentNodes.slice(insertIndex),
|
|
240
|
-
];
|
|
241
|
-
// Run dagre layout on the full graph so the new node is positioned consistently
|
|
242
|
-
const layoutResult = layoutWithDagre(allNodes, allEdges, CANVAS_LAYOUT_DEFAULTS);
|
|
243
|
-
setEdges(layoutResult.edges);
|
|
244
|
-
return layoutResult.nodes;
|
|
245
|
-
});
|
|
158
|
+
const parentNodeId = edgeType === 'dependencyEdge' && sourceNodeId ? sourceNodeId : undefined;
|
|
159
|
+
addPendingFeature(id, newFeatureData, parentNodeId);
|
|
246
160
|
return id;
|
|
247
|
-
}, [
|
|
161
|
+
}, [addPendingFeature]);
|
|
248
162
|
const handleDeleteFeature = useCallback((featureId) => {
|
|
249
163
|
const nodeId = `feat-${featureId}`;
|
|
250
|
-
//
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return layoutResult.nodes;
|
|
260
|
-
});
|
|
164
|
+
// Find the current entry for rollback
|
|
165
|
+
const prevEntry = nodes
|
|
166
|
+
.filter((n) => n.id === nodeId)
|
|
167
|
+
.map((n) => ({
|
|
168
|
+
nodeId: n.id,
|
|
169
|
+
data: n.data,
|
|
170
|
+
}))[0];
|
|
171
|
+
// Optimistic removal
|
|
172
|
+
removeFeature(nodeId);
|
|
261
173
|
deleteSound.play();
|
|
262
174
|
toast.success('Feature deleted successfully');
|
|
263
175
|
router.push('/');
|
|
264
|
-
// Persist in background — rollback on failure
|
|
265
176
|
deleteFeature(featureId)
|
|
266
177
|
.then((result) => {
|
|
267
178
|
if (result.error) {
|
|
268
|
-
|
|
269
|
-
|
|
179
|
+
if (prevEntry)
|
|
180
|
+
restoreFeature(nodeId, prevEntry);
|
|
270
181
|
toast.error(result.error);
|
|
271
182
|
}
|
|
272
183
|
})
|
|
273
184
|
.catch(() => {
|
|
274
|
-
|
|
275
|
-
|
|
185
|
+
if (prevEntry)
|
|
186
|
+
restoreFeature(nodeId, prevEntry);
|
|
276
187
|
toast.error('Failed to delete feature');
|
|
277
188
|
});
|
|
278
|
-
}, [nodes, router, deleteSound,
|
|
189
|
+
}, [nodes, router, deleteSound, removeFeature, restoreFeature]);
|
|
279
190
|
const handleDeleteRepository = useCallback(async (repositoryId) => {
|
|
280
191
|
const repoNodeId = `repo-${repositoryId}`;
|
|
192
|
+
// Find children of this repo via edges
|
|
193
|
+
const childFeatureIds = new Set(edges.filter((e) => e.source === repoNodeId).map((e) => e.target));
|
|
281
194
|
// Snapshot for rollback
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const remainingNodes = currentNodes.filter((n) => n.id !== repoNodeId && !childFeatureIds.has(n.id));
|
|
289
|
-
const remainingEdges = edgesRef.current.filter((e) => e.source !== repoNodeId &&
|
|
290
|
-
e.target !== repoNodeId &&
|
|
291
|
-
!childFeatureIds.has(e.source) &&
|
|
292
|
-
!childFeatureIds.has(e.target));
|
|
293
|
-
const layoutResult = layoutWithDagre(remainingNodes, remainingEdges, CANVAS_LAYOUT_DEFAULTS);
|
|
294
|
-
setEdges(layoutResult.edges);
|
|
295
|
-
return layoutResult.nodes;
|
|
296
|
-
});
|
|
195
|
+
const prevRepoData = getRepositoryData(repoNodeId);
|
|
196
|
+
// Optimistic: remove repo + children
|
|
197
|
+
removeRepository(repoNodeId);
|
|
198
|
+
for (const childId of childFeatureIds) {
|
|
199
|
+
removeFeature(childId);
|
|
200
|
+
}
|
|
297
201
|
try {
|
|
298
202
|
const result = await deleteRepository(repositoryId);
|
|
299
203
|
if (!result.success) {
|
|
300
204
|
toast.error(result.error ?? 'Failed to remove repository');
|
|
301
|
-
|
|
302
|
-
|
|
205
|
+
if (prevRepoData)
|
|
206
|
+
addRepositoryToMap(repoNodeId, prevRepoData);
|
|
207
|
+
for (const childId of childFeatureIds) {
|
|
208
|
+
const childNode = nodes.find((n) => n.id === childId);
|
|
209
|
+
if (childNode) {
|
|
210
|
+
restoreFeature(childId, {
|
|
211
|
+
nodeId: childId,
|
|
212
|
+
data: childNode.data,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
303
216
|
return;
|
|
304
217
|
}
|
|
305
218
|
deleteSound.play();
|
|
@@ -307,82 +220,62 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
307
220
|
}
|
|
308
221
|
catch {
|
|
309
222
|
toast.error('Failed to remove repository');
|
|
310
|
-
|
|
311
|
-
|
|
223
|
+
if (prevRepoData)
|
|
224
|
+
addRepositoryToMap(repoNodeId, prevRepoData);
|
|
225
|
+
for (const childId of childFeatureIds) {
|
|
226
|
+
const childNode = nodes.find((n) => n.id === childId);
|
|
227
|
+
if (childNode) {
|
|
228
|
+
restoreFeature(childId, {
|
|
229
|
+
nodeId: childId,
|
|
230
|
+
data: childNode.data,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
312
234
|
}
|
|
313
|
-
}, [
|
|
235
|
+
}, [
|
|
236
|
+
edges,
|
|
237
|
+
nodes,
|
|
238
|
+
deleteSound,
|
|
239
|
+
removeRepository,
|
|
240
|
+
removeFeature,
|
|
241
|
+
addRepositoryToMap,
|
|
242
|
+
restoreFeature,
|
|
243
|
+
getRepositoryData,
|
|
244
|
+
]);
|
|
314
245
|
const handleLayout = useCallback((direction) => {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
setEdges(result.edges);
|
|
321
|
-
return result.nodes;
|
|
322
|
-
});
|
|
323
|
-
}, [setEdges]);
|
|
246
|
+
// Layout is applied via reconcile on next server prop update.
|
|
247
|
+
// For immediate re-layout, we apply dagre and trigger a reconcile-like update.
|
|
248
|
+
const result = layoutWithDagre(nodes, edges, { ...CANVAS_LAYOUT_DEFAULTS, direction });
|
|
249
|
+
reconcile(result.nodes, result.edges);
|
|
250
|
+
}, [nodes, edges, reconcile]);
|
|
324
251
|
const handleAddRepository = useCallback((path) => {
|
|
325
252
|
const tempId = `repo-temp-${Date.now()}`;
|
|
326
253
|
const repoName = path
|
|
327
254
|
.replace(/[\\/]+$/, '')
|
|
328
255
|
.split(/[\\/]/)
|
|
329
256
|
.pop() ?? path;
|
|
330
|
-
|
|
331
|
-
setNodes((currentNodes) => {
|
|
332
|
-
const newNode = {
|
|
333
|
-
id: tempId,
|
|
334
|
-
type: 'repositoryNode',
|
|
335
|
-
position: { x: 0, y: 0 },
|
|
336
|
-
data: { name: repoName, repositoryPath: path, id: tempId },
|
|
337
|
-
};
|
|
338
|
-
const allNodes = [...currentNodes, newNode];
|
|
339
|
-
const layoutResult = layoutWithDagre(allNodes, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
|
|
340
|
-
setEdges(layoutResult.edges);
|
|
341
|
-
return layoutResult.nodes;
|
|
342
|
-
});
|
|
343
|
-
// Persist via server action
|
|
257
|
+
addRepositoryToMap(tempId, { name: repoName, repositoryPath: path, id: tempId });
|
|
344
258
|
addRepository({ path, name: repoName })
|
|
345
259
|
.then((result) => {
|
|
346
260
|
if (result.error) {
|
|
347
|
-
|
|
348
|
-
setNodes((prev) => {
|
|
349
|
-
const remaining = prev.filter((n) => n.id !== tempId);
|
|
350
|
-
const layoutResult = layoutWithDagre(remaining, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
|
|
351
|
-
setEdges(layoutResult.edges);
|
|
352
|
-
return layoutResult.nodes;
|
|
353
|
-
});
|
|
261
|
+
removeRepository(tempId);
|
|
354
262
|
toast.error(result.error);
|
|
355
263
|
return;
|
|
356
264
|
}
|
|
357
|
-
// Replace temp ID with real repository ID
|
|
358
265
|
const repo = result.repository;
|
|
359
266
|
const realId = `repo-${repo.id}`;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
: n));
|
|
367
|
-
setEdges((prev) => prev.map((e) => ({
|
|
368
|
-
...e,
|
|
369
|
-
source: e.source === tempId ? realId : e.source,
|
|
370
|
-
target: e.target === tempId ? realId : e.target,
|
|
371
|
-
id: e.id.replace(tempId, realId),
|
|
372
|
-
})));
|
|
267
|
+
replaceRepository(tempId, realId, {
|
|
268
|
+
name: repo.name,
|
|
269
|
+
repositoryPath: repo.path,
|
|
270
|
+
id: repo.id,
|
|
271
|
+
});
|
|
373
272
|
createSound.play();
|
|
374
273
|
})
|
|
375
274
|
.catch(() => {
|
|
376
|
-
|
|
377
|
-
setNodes((prev) => {
|
|
378
|
-
const remaining = prev.filter((n) => n.id !== tempId);
|
|
379
|
-
const layoutResult = layoutWithDagre(remaining, edgesRef.current, CANVAS_LAYOUT_DEFAULTS);
|
|
380
|
-
setEdges(layoutResult.edges);
|
|
381
|
-
return layoutResult.nodes;
|
|
382
|
-
});
|
|
275
|
+
removeRepository(tempId);
|
|
383
276
|
toast.error('Failed to add repository');
|
|
384
277
|
});
|
|
385
|
-
}, [
|
|
278
|
+
}, [addRepositoryToMap, removeRepository, replaceRepository, createSound]);
|
|
386
279
|
return {
|
|
387
280
|
nodes,
|
|
388
281
|
edges,
|
|
@@ -393,5 +286,8 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
393
286
|
handleDeleteFeature,
|
|
394
287
|
handleDeleteRepository,
|
|
395
288
|
createFeatureNode,
|
|
289
|
+
getFeatureRepositoryPath,
|
|
290
|
+
getRepositoryData,
|
|
291
|
+
setCallbacks,
|
|
396
292
|
};
|
|
397
293
|
}
|