@shepai/cli 1.202.1-pr606.60460ac → 1.202.2
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/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +2 -2
- package/web/.next/required-server-files.json +2 -2
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +37 -37
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +35 -35
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +38 -38
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +47 -47
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +47 -47
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +35 -35
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/control-center/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/control-center/page/server-reference-manifest.json +35 -35
- package/web/.next/server/app/(dashboard)/control-center/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/control-center/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +38 -38
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +47 -47
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +47 -47
- 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)/repository/[repositoryId]/[tab]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +36 -36
- 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/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/agent-questions/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/agent-questions/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/agent-questions/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/agents/[agentType]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/agents/[agentType]/page/server-reference-manifest.json +13 -13
- package/web/.next/server/app/agents/[agentType]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/agents/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/agents/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/application/[id]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/application/[id]/page/server-reference-manifest.json +18 -18
- package/web/.next/server/app/application/[id]/page.js.nft.json +1 -1
- package/web/.next/server/app/application/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/application/[id]/supervisor/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/application/[id]/supervisor/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/application/[id]/supervisor/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/applications/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/applications/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/applications/page.js.nft.json +1 -1
- package/web/.next/server/app/applications/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/features/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/features/page/server-reference-manifest.json +31 -31
- package/web/.next/server/app/features/page.js.nft.json +1 -1
- package/web/.next/server/app/features/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/onboarding/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/onboarding/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/projects/[slug]/items/[itemId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/projects/[slug]/items/[itemId]/page/server-reference-manifest.json +16 -16
- package/web/.next/server/app/projects/[slug]/items/[itemId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/projects/[slug]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/projects/[slug]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/projects/[slug]/pages/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/projects/[slug]/pages/page/server-reference-manifest.json +12 -12
- package/web/.next/server/app/projects/[slug]/pages/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/projects/[slug]/settings/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/projects/[slug]/settings/page/server-reference-manifest.json +18 -18
- package/web/.next/server/app/projects/[slug]/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/projects/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/projects/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/settings/page/server-reference-manifest.json +15 -15
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/skills/page/server-reference-manifest.json +17 -17
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/supervisor/feature/[featureId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/supervisor/feature/[featureId]/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/supervisor/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/supervisor/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/supervisor/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/supervisor/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/supervisor/repo/[repositoryId]/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/supervisor/repo/[repositoryId]/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/supervisor/repo/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/tools/page/server-reference-manifest.json +15 -15
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/react-loadable-manifest.json +4 -4
- package/web/.next/server/app/version/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__10e976f3._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_agent-questions_page_actions_4b694f8d.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_agent-questions_page_actions_4b694f8d.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_agents_[agentType]_page_actions_103679a6.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_agents_[agentType]_page_actions_103679a6.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_projects_[slug]_pages_page_actions_19d50f6c.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_projects_[slug]_pages_page_actions_19d50f6c.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_app_projects_[slug]_items_[itemId]_work-item-detail-client_tsx_d2e02407._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_app_projects_[slug]_items_[itemId]_work-item-detail-client_tsx_d2e02407._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_app_projects_[slug]_settings_project-settings-client_tsx_e8b85ddc._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_app_projects_[slug]_settings_project-settings-client_tsx_e8b85ddc._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js +2 -2
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_features_applications_applications-page-client_tsx_d0db9938._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_features_applications_applications-page-client_tsx_d0db9938._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0af8610a._.js +3 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0af8610a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0b652a2f._.js +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__8b73253b._.js → [root-of-the-server]__2e388ba3._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__8b73253b._.js.map → [root-of-the-server]__2e388ba3._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__56cf47e7._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__56cf47e7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__648730d4._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__68df6415._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__68df6415._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bc6bf96._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bc6bf96._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9852cb08._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9852cb08._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a1167cec._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a1167cec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a12d0ad7._.js +3 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__52ca7f88._.js.map → [root-of-the-server]__a12d0ad7._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ba699bec._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ba699bec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e0741ee1._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e0fa59e6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e0fa59e6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ea26ff90._.js +3 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ff0095e3._.js +1 -1
- package/web/.next/server/chunks/ssr/_07036593._.js +1 -1
- package/web/.next/server/chunks/ssr/_07036593._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0d2a7595._.js +1 -1
- package/web/.next/server/chunks/ssr/_0d2a7595._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_101de7c3._.js +1 -1
- package/web/.next/server/chunks/ssr/_101de7c3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_db111d21._.js → _10f54ace._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_db111d21._.js.map → _10f54ace._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_24fca3cf._.js +1 -1
- package/web/.next/server/chunks/ssr/_24fca3cf._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_6ff832ad._.js → _2759af76._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_6ff832ad._.js.map → _2759af76._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_2bc48f3d._.js +1 -1
- package/web/.next/server/chunks/ssr/_2bc48f3d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_fb539286._.js → _2bef1982._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_fb539286._.js.map → _2bef1982._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_32f66845._.js +1 -1
- package/web/.next/server/chunks/ssr/_408848e6._.js +1 -1
- package/web/.next/server/chunks/ssr/_408848e6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_40e02782._.js +1 -1
- package/web/.next/server/chunks/ssr/_40e02782._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_486d45d6._.js +1 -1
- package/web/.next/server/chunks/ssr/_486d45d6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_824d5772._.js → _498cba11._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_824d5772._.js.map → _498cba11._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_5cbb0e22._.js +1 -1
- package/web/.next/server/chunks/ssr/_5cbb0e22._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_5a3edc88._.js → _673be4f1._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_5a3edc88._.js.map → _673be4f1._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_7ba67729._.js +1 -1
- package/web/.next/server/chunks/ssr/_7ba67729._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_805ae1aa._.js +1 -1
- package/web/.next/server/chunks/ssr/_805ae1aa._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_87cf18c3._.js +1 -1
- package/web/.next/server/chunks/ssr/_87cf18c3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_8a700ff4._.js +1 -1
- package/web/.next/server/chunks/ssr/_8a700ff4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_95b97274._.js +1 -1
- package/web/.next/server/chunks/ssr/_95b97274._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_fbcfaf3a._.js → _9d18d1b1._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_fbcfaf3a._.js.map → _9d18d1b1._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_70ff64a1._.js → _a93687e6._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_70ff64a1._.js.map → _a93687e6._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_c2e196ee._.js +1 -1
- package/web/.next/server/chunks/ssr/_c2e196ee._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_ca3b7bf7._.js +1 -1
- package/web/.next/server/chunks/ssr/_ca3b7bf7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d53224a9._.js +1 -1
- package/web/.next/server/chunks/ssr/_d53224a9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d573dcc2._.js +1 -1
- package/web/.next/server/chunks/ssr/_e2671e14._.js +1 -1
- package/web/.next/server/chunks/ssr/_e2671e14._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_ecd45b17._.js +1 -1
- package/web/.next/server/chunks/ssr/_ecd45b17._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_f0d45e47._.js → _f46d2018._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_f0d45e47._.js.map → _f46d2018._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_f602cc9f._.js +1 -1
- package/web/.next/server/chunks/ssr/_f602cc9f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_20a56008._.js → _f71954a5._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_20a56008._.js.map → _f71954a5._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_0e291f0b._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_0e291f0b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{src_presentation_web_40673f0c._.js → src_presentation_web_16c83ab4._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_40673f0c._.js.map → src_presentation_web_16c83ab4._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_1d8d177f._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_1d8d177f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_450b58fc._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_450b58fc._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_47727150._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_47727150._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_64fcfc84._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_64fcfc84._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_74b7bdb2._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_74b7bdb2._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_82aeca34._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_82aeca34._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_8a564d47._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_8a564d47._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_9a543843._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_9a543843._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app__not-found_page_actions_f4f3fad9.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app__not-found_page_actions_f4f3fad9.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_agents_page_actions_d4bd4711.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_agents_page_actions_d4bd4711.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_onboarding_page_actions_bb695e8d.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_onboarding_page_actions_bb695e8d.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_page_actions_ac47e420.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_page_actions_ac47e420.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_projects_page_actions_c91a23a8.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_projects_page_actions_c91a23a8.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_version_page_actions_63c2d912.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_version_page_actions_63c2d912.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_a53a3da6._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_a53a3da6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_246617fe._.js +3 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_adopt-local-directory_ts_75f1f28c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_adopt-local-directory_ts_75f1f28c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_approve-feature_ts_9453ce8b._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-directory_ts_1209d917._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-directory_ts_1209d917._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_features_feature-tree-page-client_tsx_34c5cbbf._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_b1b3c26c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_b1b3c26c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_b98a4353._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_b98a4353._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c96ca051._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c96ca051._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{src_presentation_web_e812a69b._.js → src_presentation_web_cb0d2c28._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_e812a69b._.js.map → src_presentation_web_cb0d2c28._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_66643378._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_66643378._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_agent-editor_agent-editor-tabs_tsx_d5a954b4._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_agent-editor_agent-editor-tabs_tsx_d5a954b4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_skills_8a174cac._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_skills_8a174cac._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d3858f16._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d3858f16._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d7f8130c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_d7f8130c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_dddd8ccd._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_dddd8ccd._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e13d58b0._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e13d58b0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ee94a9aa._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ee94a9aa._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_f0fcfdff._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_f0fcfdff._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_f17e8516._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_f17e8516._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_f7180fec._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_f7180fec._.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 +111 -111
- package/web/.next/static/chunks/{5faa828877b1e669.js → 03dda23205877d8b.js} +1 -1
- package/web/.next/static/chunks/{4bf4f333302e24a4.js → 054e3a5f5ff4db71.js} +1 -1
- package/web/.next/static/chunks/{a868014dbe1b4e42.js → 06e58041911c290b.js} +1 -1
- package/web/.next/static/chunks/{b5ff852fee23795d.js → 089ef5b749d79ebd.js} +1 -1
- package/web/.next/static/chunks/{1a093b13a9d6952e.js → 0d106010c498c198.js} +2 -2
- package/web/.next/static/chunks/193e5a0540757f5e.js +1 -0
- package/web/.next/static/chunks/{9abc3e68af98e636.js → 25111a2f2597f500.js} +1 -1
- package/web/.next/static/chunks/285e724d07901ef6.js +1 -0
- package/web/.next/static/chunks/{3c396f63ebefe875.js → 2b2bfc0465b18a7d.js} +1 -1
- package/web/.next/static/chunks/{6af99a08ccacdbce.js → 2b436562e69d2827.js} +1 -1
- package/web/.next/static/chunks/{8c96a835b3b0dc44.js → 2e3844d0ac487ac7.js} +1 -1
- package/web/.next/static/chunks/325859b8a9482427.js +1 -0
- package/web/.next/static/chunks/{2773e7b2587bc9cc.js → 44ab458ceb89d85d.js} +1 -1
- package/web/.next/static/chunks/4fdf36904f5421a6.js +1 -0
- package/web/.next/static/chunks/59004c65d552581c.js +1 -0
- package/web/.next/static/chunks/{0edcdc8a2dd06b7a.js → 5c4837e88a3431b8.js} +1 -1
- package/web/.next/static/chunks/{a131f868af7f1f7c.js → 74cdd562eb663f72.js} +1 -1
- package/web/.next/static/chunks/{0315591c972888a6.js → 7670d76d4ee743e6.js} +1 -1
- package/web/.next/static/chunks/{02d88da9fd656fcd.js → 83fc784ce05a701e.js} +1 -1
- package/web/.next/static/chunks/{460cedaa85c821e7.js → 8dd4fdd20b103a66.js} +1 -1
- package/web/.next/static/chunks/9336bdc7fc319282.js +1 -0
- package/web/.next/static/chunks/9d285565922b2de7.js +1 -0
- package/web/.next/static/chunks/{45eeca36eabbed23.js → 9f7f2a11937d87eb.js} +1 -1
- package/web/.next/static/chunks/{c3931fdbae836be6.js → a7c7bcfb6f7696a3.js} +1 -1
- package/web/.next/static/chunks/{9f7985e2a73929a2.js → a8f57d2a12849f32.js} +1 -1
- package/web/.next/static/chunks/{0e1c933065a1100a.js → abe98954ccdf29db.js} +1 -1
- package/web/.next/static/chunks/{4378715fa2b5e7de.js → b05808da85e8b34c.js} +1 -1
- package/web/.next/static/chunks/{b5dc7979d66caa38.js → b5f83e5e1dad23d5.js} +1 -1
- package/web/.next/static/chunks/{6d2074fa3453d333.js → b8293a56f257e5a2.js} +1 -1
- package/web/.next/static/chunks/{bc5b87e4068ba11d.js → c61c5e97c76dc733.js} +1 -1
- package/web/.next/static/chunks/c6b411bf31744ca7.js +1 -0
- package/web/.next/static/chunks/{bdaa907bf3d1d932.js → c732d6cc4c5e4343.js} +1 -1
- package/web/.next/static/chunks/{25a200f055ae5cba.js → d214d6a670f48d79.js} +1 -1
- package/web/.next/static/chunks/{6901861cb53ab483.js → d7b17a93a26e97c8.js} +1 -1
- package/web/.next/static/chunks/{a0325f77bbccc63d.js → d8f14fac959a6bd0.js} +1 -1
- package/web/.next/static/chunks/{24ea54516dc249c0.js → d98912f5b6cf4938.js} +1 -1
- package/web/.next/static/chunks/{21500b3fe3754296.js → df79667c16344317.js} +1 -1
- package/web/.next/static/chunks/{05e8df10619fb980.js → ec8f19328ad1ecd4.js} +1 -1
- package/web/.next/static/chunks/{e6e6ba783b2e4d14.js → f0157331838ac962.js} +1 -1
- package/web/.next/static/chunks/{c687ed21b9518d73.js → f757d865fae71faf.js} +1 -1
- package/web/.next/static/chunks/fb3cbb7f575a7128.js +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__52ca7f88._.js +0 -3
- package/web/.next/static/chunks/03d7b81c2554d52f.js +0 -1
- package/web/.next/static/chunks/15acdaaea57bb459.js +0 -1
- package/web/.next/static/chunks/39fe1c1397d5483b.js +0 -1
- package/web/.next/static/chunks/495883829026f13f.js +0 -1
- package/web/.next/static/chunks/4b3a4f416a6eb1ac.js +0 -1
- package/web/.next/static/chunks/4b4160f36cf2a3d6.js +0 -1
- package/web/.next/static/chunks/7269537b2188650d.js +0 -1
- package/web/.next/static/chunks/b1534b2f3d814fef.js +0 -1
- package/web/.next/static/chunks/f6dc1ba364203bb2.js +0 -1
- /package/web/.next/static/{My4IQDygZ4BFTXkkKanja → 9zd-B2rWybTaAgE74IKiK}/_buildManifest.js +0 -0
- /package/web/.next/static/{My4IQDygZ4BFTXkkKanja → 9zd-B2rWybTaAgE74IKiK}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{My4IQDygZ4BFTXkkKanja → 9zd-B2rWybTaAgE74IKiK}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts","../../../../../../../src/presentation/web/app/actions/data%3A659644%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/app/actions/data%3A60257f%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/hooks/use-graph-state.ts","../../../../../../../src/presentation/web/lib/derive-graph.ts","../../../../../../../src/presentation/web/components/common/repository-node/repository-drawer.tsx","../../../../../../../src/presentation/web/components/common/application-node/application-node.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/dependency-edge.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/features-canvas.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/canvas-toolbar.tsx","../../../../../../../src/presentation/web/hooks/use-workspaces.ts","../../../../../../../src/presentation/web/components/features/features-canvas/workspace-selector.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/manage-workspace-dialog.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/workspace-name-dialog.tsx","../../../../../../../src/presentation/web/hooks/use-selected-feature-id.ts","../../../../../../../src/presentation/web/hooks/use-selected-repository.ts","../../../../../../../src/presentation/web/hooks/use-viewport-persistence.ts","../../../../../../../src/presentation/web/app/actions/data%3A867418%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/app/actions/data%3A2701ad%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/components/features/control-center/control-center.tsx","../../../../../../../src/presentation/web/app/actions/data%3A8e4c13%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx","../../../../../../../src/presentation/web/components/features/control-center/welcome-agent-setup.tsx","../../../../../../../src/presentation/web/components/features/control-center/control-center-onboarding.tsx","../../../../../../../src/presentation/web/components/features/control-center/collaboration-onboarding.tsx","../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx","../../../../../../../src/presentation/web/components/features/control-center/use-fab-actions.tsx","../../../../../../../node_modules/.pnpm/lucide-react%400.563.0_react%4019.2.4/node_modules/lucide-react/src/icons/maximize.ts","../../../../../../../node_modules/.pnpm/lucide-react%400.563.0_react%4019.2.4/node_modules/lucide-react/src/icons/zoom-in.ts","../../../../../../../node_modules/.pnpm/lucide-react%400.563.0_react%4019.2.4/node_modules/lucide-react/src/icons/zoom-out.ts","../../../../../../../src/presentation/web/components/features/control-center/use-workspace-fit-view.ts","../../../../../../../src/presentation/web/components/features/control-center/use-canvas-event-listeners.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { toast } from 'sonner';\nimport type { Connection, Edge, NodeChange } from '@xyflow/react';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport {\n layoutWithDagre,\n getCanvasLayoutDefaults,\n type LayoutDirection,\n} from '@/lib/layout-with-dagre';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\nimport { archiveFeature } from '@/app/actions/archive-feature';\nimport { deleteFeature } from '@/app/actions/delete-feature';\nimport { resumeFeature } from '@/app/actions/resume-feature';\nimport { startFeature } from '@/app/actions/start-feature';\nimport { stopFeature } from '@/app/actions/stop-feature';\nimport { unarchiveFeature } from '@/app/actions/unarchive-feature';\nimport { addRepository } from '@/app/actions/add-repository';\nimport { deleteRepository } from '@/app/actions/delete-repository';\nimport { deleteApplication } from '@/app/actions/delete-application';\nimport { getFeatureMetadata } from '@/app/actions/get-feature-metadata';\nimport { useAgentEventsContext } from '@/hooks/agent-events-provider';\nimport { useDeploymentStatusContext } from '@/hooks/deployment-status-provider';\nimport { useSoundAction } from '@/hooks/use-sound-action';\nimport { createLogger } from '@/lib/logger';\nimport { featureIdForApplication } from '@shepai/core/domain/shared/feature-id';\n\nimport {\n mapEventTypeToState,\n resolveSseEventUpdates,\n} from '@/components/common/feature-node/derive-feature-state';\nimport { useGraphState, type GraphCallbacks } from '@/hooks/use-graph-state';\nimport type { FeatureEntry } from '@/lib/derive-graph';\n\nconst log = createLogger('[Polling]');\nconst POLL_INTERVAL_MS = 15_000;\n\nexport interface ControlCenterState {\n nodes: CanvasNodeType[];\n edges: Edge[];\n onNodesChange: (changes: NodeChange<CanvasNodeType>[]) => void;\n handleConnect: (connection: Connection) => void;\n handleAddRepository: (path: string) => {\n wasEmpty: boolean;\n repoPath: string;\n tempNodeId: string;\n };\n handleLayout: (direction: LayoutDirection) => void;\n handleArchiveFeature: (featureId: string) => void;\n handleDeleteFeature: (\n featureId: string,\n cleanup?: boolean,\n cascadeDelete?: boolean,\n closePr?: boolean\n ) => void;\n handleRetryFeature: (featureId: string) => void;\n handleStartFeature: (featureId: string) => void;\n handleStopFeature: (featureId: string) => void;\n handleUnarchiveFeature: (featureId: string) => void;\n handleDeleteRepository: (\n repositoryId: string,\n options?: { deleteFromDisk?: boolean }\n ) => Promise<void>;\n handleDeleteApplication: (applicationId: string) => Promise<void>;\n createFeatureNode: (\n sourceNodeId: string | null,\n dataOverride?: Partial<FeatureNodeData>,\n edgeType?: string\n ) => string;\n /** Add an application node to the canvas optimistically. */\n addApplication: (nodeId: string, data: ApplicationNodeData) => void;\n /** Whether archived features are shown on the canvas. */\n showArchived: boolean;\n /** Toggle archived feature visibility. */\n setShowArchived: (show: boolean) => void;\n /** Stable lookup: repositoryPath for a feature node. */\n getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;\n /** Stable lookup: repository data by nodeId. */\n getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;\n /** Sync callbacks into derived node data (does not trigger re-render). */\n setCallbacks: (callbacks: GraphCallbacks) => void;\n}\n\n/** Must match the message string emitted by the SSE route in agent-events/route.ts */\nconst METADATA_UPDATED_MESSAGE = 'Feature metadata updated';\n\nlet nextFeatureId = 0;\nlet nextRepoTempId = 0;\n\nexport function useControlCenterState(\n initialNodes: CanvasNodeType[],\n initialEdges: Edge[]\n): ControlCenterState {\n const router = useRouter();\n const deleteSound = useSoundAction('delete');\n const createSound = useSoundAction('create');\n\n // Archive toggle: persists during session, resets on page reload (FR-10)\n const [showArchived, setShowArchived] = useState(false);\n\n const {\n nodes,\n edges,\n reconcile,\n updateFeature,\n addPendingFeature,\n removeFeature,\n restoreFeature,\n addRepository: addRepositoryToMap,\n removeRepository,\n replaceRepository,\n getFeatureRepositoryPath,\n getRepositoryData,\n getRepoMapSize,\n addApplication: addApplicationToMap,\n removeApplication,\n setCallbacks,\n beginMutation,\n endMutation,\n isMutating,\n } = useGraphState(initialNodes, initialEdges, showArchived);\n\n // Refs for stable access to latest nodes/edges without callback recreation\n const nodesRef = useRef(nodes);\n const edgesRef = useRef(edges);\n useEffect(() => {\n nodesRef.current = nodes;\n edgesRef.current = edges;\n }, [nodes, edges]);\n\n // Sync server props into domain Maps when initialNodes/initialEdges change.\n // Keyed by a stable string so we don't re-reconcile on every render.\n const initialNodeKey = useMemo(\n () =>\n initialNodes\n .map((n) => n.id)\n .sort()\n .join(','),\n [initialNodes]\n );\n const initialDataKey = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'featureNode')\n .map((n) => {\n const d = n.data as FeatureNodeData;\n return `${n.id}:${d.state}:${d.lifecycle}`;\n })\n .sort()\n .join(','),\n [initialNodes]\n );\n\n const prevReconcileKey = useRef('');\n\n useEffect(() => {\n const key = `${initialNodeKey}|${initialDataKey}`;\n if (key !== prevReconcileKey.current) {\n prevReconcileKey.current = key;\n reconcile(initialNodes, initialEdges);\n }\n }, [initialNodeKey, initialDataKey, initialNodes, initialEdges, reconcile]);\n\n // Track previous feature states for fallback notifications\n const prevFeatureStatesRef = useRef<Map<string, FeatureNodeData['state']>>(new Map());\n\n const { events, connectionStatus } = useAgentEventsContext();\n const { store: deploymentStore } = useDeploymentStatusContext();\n\n useEffect(() => {\n const prevStates = prevFeatureStatesRef.current;\n for (const node of initialNodes) {\n if (node.type !== 'featureNode') continue;\n const data = node.data as FeatureNodeData;\n const prev = prevStates.get(node.id);\n if (prev !== undefined && prev !== data.state) {\n const sseAlreadyCovered = events.some(\n (e) => e.featureId === data.featureId && mapEventTypeToState(e.eventType) === data.state\n );\n if (!sseAlreadyCovered) {\n if (data.state === 'done') {\n toast.success(data.name, { description: 'Feature completed!' });\n } else if (data.state === 'action-required') {\n toast.warning(data.name, {\n description: 'Waiting for your approval',\n action: {\n label: 'Review',\n onClick: () => router.push(`/feature/${data.featureId}`),\n },\n });\n } else if (data.state === 'error') {\n toast.error(data.name, { description: data.errorMessage ?? 'Agent failed' });\n }\n }\n }\n prevStates.set(node.id, data.state);\n }\n }, [initialDataKey, initialNodes, events, router]);\n\n // SSE effect: only state + lifecycle updates\n const processedEventCountRef = useRef(0);\n\n useEffect(() => {\n // Clamp cursor if events were pruned\n if (processedEventCountRef.current > events.length) {\n processedEventCountRef.current = 0;\n }\n if (events.length <= processedEventCountRef.current) return;\n const newEvents = events.slice(processedEventCountRef.current);\n processedEventCountRef.current = events.length;\n\n for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {\n if (state !== undefined || lifecycle !== undefined) {\n const nodeId = `feat-${featureId}`;\n const existingNode = nodesRef.current.find((n) => n.id === nodeId);\n const existingState = existingNode\n ? (existingNode.data as FeatureNodeData).state\n : undefined;\n\n // Skip SSE updates for features in 'deleting' state — the optimistic\n // delete state must not be overwritten by stale SSE events (e.g. agent\n // cancellation emitting AgentFailed during the soft-delete window).\n if (existingState === 'deleting') continue;\n\n // Skip SSE error events during mutation cooldown — after approve/reject\n // the agent may still report AgentFailed from the previous run before\n // the resume kicks in. The optimistic 'running' state must not be\n // overwritten by stale error events during this transition window.\n if (state === 'error' && isMutating() && existingState === 'running') continue;\n\n updateFeature(nodeId, {\n ...(state !== undefined && { state }),\n ...(lifecycle !== undefined && { lifecycle }),\n });\n }\n }\n }, [events, updateFeature, isMutating]);\n\n // Listen for optimistic approval/rejection events from the drawer (fires before SSE arrives).\n // Uses beginMutation + endMutation to prevent stale poll/reconcile data from overwriting\n // the optimistic 'running' state during the transition window (avoids brief \"Something went wrong\" flash).\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;\n beginMutation();\n updateFeature(`feat-${featureId}`, { state: 'running' });\n endMutation();\n };\n window.addEventListener('shep:feature-approved', handler);\n return () => window.removeEventListener('shep:feature-approved', handler);\n }, [updateFeature, beginMutation, endMutation]);\n\n // Separate effect: fetch metadata (name + description) when SSE reports it changed\n const metadataFetchedRef = useRef<Set<string>>(new Set());\n const processedMetadataCountRef = useRef(0);\n\n useEffect(() => {\n // Clamp cursor if events were pruned\n if (processedMetadataCountRef.current > events.length) {\n processedMetadataCountRef.current = 0;\n }\n if (events.length <= processedMetadataCountRef.current) return;\n const newEvents = events.slice(processedMetadataCountRef.current);\n processedMetadataCountRef.current = events.length;\n\n for (const event of newEvents) {\n if (event.message !== METADATA_UPDATED_MESSAGE) continue;\n if (metadataFetchedRef.current.has(event.featureId)) continue;\n metadataFetchedRef.current.add(event.featureId);\n\n const nodeId = `feat-${event.featureId}`;\n getFeatureMetadata(event.featureId)\n .then((meta) => {\n if (meta) {\n updateFeature(nodeId, { name: meta.name, description: meta.description });\n }\n })\n .catch(() => {\n // Silent: metadata fetch failure is non-critical\n });\n }\n }, [events, updateFeature]);\n\n // --- Polling fallback: only run as recovery when SSE is unhealthy ---\n // While SSE is connected, every state change is delivered via the stream\n // and reconciliation happens on the next render — there's no need to\n // re-fetch the whole graph. Polling only kicks in when SSE has been\n // disconnected or stuck connecting (e.g. server restarted, network\n // glitch, service worker not yet activated).\n const sseHealthyRef = useRef(connectionStatus === 'connected');\n sseHealthyRef.current = connectionStatus === 'connected';\n\n useEffect(() => {\n log.debug(`polling enabled (${POLL_INTERVAL_MS}ms recovery interval)`);\n\n const timer = setInterval(async () => {\n // Skip when tab is hidden — no point polling for a user who isn't looking.\n if (document.hidden) return;\n // Skip while SSE is healthy — the stream is the source of truth.\n if (sseHealthyRef.current) return;\n // Skip fetch entirely while a mutation is in-flight — the response\n // would contain pre-mutation data that reconcile would discard anyway.\n if (isMutating()) return;\n\n try {\n // Use a plain fetch instead of a server action so the poll\n // doesn't trigger the Next.js \"Rendering…\" indicator.\n const res = await fetch('/api/graph-data');\n if (!res.ok) throw new Error(`status ${res.status}`);\n const {\n nodes: freshNodes,\n edges: freshEdges,\n deployments: freshDeployments,\n } = await res.json();\n reconcile(freshNodes, freshEdges);\n if (Array.isArray(freshDeployments)) {\n deploymentStore.hydrate(freshDeployments);\n }\n } catch {\n log.warn('recovery poll failed — will retry next interval');\n }\n }, POLL_INTERVAL_MS);\n\n return () => {\n log.debug('polling disabled');\n clearInterval(timer);\n };\n }, [reconcile, isMutating, deploymentStore]);\n\n // onNodesChange is a no-op: nodes are derived from domain Maps.\n // Since nodesDraggable=false and elementsSelectable=false, only React Flow's\n // internal replace/dimensions changes come through — we ignore them all.\n const onNodesChange = useCallback((_changes: NodeChange<CanvasNodeType>[]) => {\n // Intentional no-op: domain Maps are the source of truth.\n }, []);\n\n const handleConnect = useCallback((_connection: Connection) => {\n // Connections are managed via domain operations, not direct edge manipulation.\n }, []);\n\n const createFeatureNode = useCallback(\n (\n sourceNodeId: string | null,\n dataOverride?: Partial<FeatureNodeData>,\n edgeType?: string\n ): string => {\n // Use real feature ID when available (from server), otherwise temp ID\n const id = dataOverride?.featureId\n ? `feat-${dataOverride.featureId}`\n : `feature-${Date.now()}-${nextFeatureId++}`;\n const newFeatureData: FeatureNodeData = {\n name: dataOverride?.name ?? 'New Feature',\n description: dataOverride?.description ?? 'Describe what this feature does',\n featureId: dataOverride?.featureId ?? `#${id.slice(-4)}`,\n lifecycle: 'requirements',\n state: dataOverride?.state ?? 'running',\n progress: 0,\n repositoryPath: dataOverride?.repositoryPath ?? '',\n branch: dataOverride?.branch ?? '',\n ...(dataOverride?.applicationId && { applicationId: dataOverride.applicationId }),\n };\n\n const parentNodeId = edgeType === 'dependencyEdge' && sourceNodeId ? sourceNodeId : undefined;\n\n addPendingFeature(id, newFeatureData, parentNodeId);\n\n return id;\n },\n [addPendingFeature]\n );\n\n const handleRetryFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n // Optimistic: switch to running state\n beginMutation();\n updateFeature(nodeId, { state: 'running' });\n\n resumeFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'error' });\n toast.error(result.error);\n } else {\n toast.success('Feature resumed');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'error' });\n toast.error('Failed to resume feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleStartFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n // Optimistic: switch to running state\n beginMutation();\n updateFeature(nodeId, { state: 'running' });\n\n startFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'pending' });\n toast.error(result.error);\n } else {\n toast.success('Feature started');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'pending' });\n toast.error('Failed to start feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleStopFeature = useCallback(\n (featureId: string) => {\n beginMutation();\n\n stopFeature(featureId)\n .then((result) => {\n if (result.error) {\n toast.error(result.error);\n } else {\n toast.success('Agent stopped');\n }\n })\n .catch(() => {\n toast.error('Failed to stop agent');\n })\n .finally(() => endMutation());\n },\n [beginMutation, endMutation]\n );\n\n const handleArchiveFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n beginMutation();\n updateFeature(nodeId, { state: 'archived' });\n\n archiveFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'done' });\n toast.error(result.error);\n } else {\n toast.success('Feature archived');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'done' });\n toast.error('Failed to archive feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleUnarchiveFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n beginMutation();\n updateFeature(nodeId, { state: 'done' });\n\n unarchiveFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'archived' });\n toast.error(result.error);\n } else {\n toast.success('Feature unarchived');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'archived' });\n toast.error('Failed to unarchive feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleDeleteFeature = useCallback(\n (featureId: string, cleanup?: boolean, cascadeDelete?: boolean, closePr?: boolean) => {\n const nodeId = `feat-${featureId}`;\n const shouldCascade = cascadeDelete === true;\n\n // Collect all descendant feature node IDs (children, grandchildren, etc.)\n const descendants: string[] = [];\n if (shouldCascade) {\n const queue = [nodeId];\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const edge of edgesRef.current) {\n if (edge.type === 'dependencyEdge' && edge.source === current) {\n descendants.push(edge.target);\n queue.push(edge.target);\n }\n }\n }\n }\n\n // Snapshot current states for rollback (parent + descendants)\n const prevStates = new Map<string, FeatureNodeData['state']>();\n for (const nid of [nodeId, ...descendants]) {\n const node = nodesRef.current.find((n) => n.id === nid);\n if (node) {\n prevStates.set(nid, (node.data as FeatureNodeData).state);\n }\n }\n\n // Optimistic: show \"deleting\" state on parent (and descendants if cascading)\n beginMutation();\n updateFeature(nodeId, { state: 'deleting' });\n for (const childId of descendants) {\n updateFeature(childId, { state: 'deleting' });\n }\n deleteSound.play();\n router.push('/control-center');\n\n deleteFeature(featureId, cleanup, cascadeDelete, closePr)\n .then((result) => {\n if (result.error) {\n // Rollback all to previous states\n for (const [nid, prevState] of prevStates) {\n if (prevState) updateFeature(nid, { state: prevState });\n }\n toast.error(result.error);\n } else {\n // Delete succeeded — remove features from the canvas. The polling\n // reconcile would eventually clean them up, but we remove them\n // explicitly so the user sees them disappear promptly.\n removeFeature(nodeId);\n for (const childId of descendants) {\n removeFeature(childId);\n }\n }\n })\n .catch(() => {\n for (const [nid, prevState] of prevStates) {\n if (prevState) updateFeature(nid, { state: prevState });\n }\n toast.error('Failed to delete feature');\n })\n .finally(() => endMutation());\n },\n [router, deleteSound, updateFeature, removeFeature, beginMutation, endMutation]\n );\n\n const handleDeleteRepository = useCallback(\n async (repositoryId: string, options?: { deleteFromDisk?: boolean }) => {\n const repoNodeId = `repo-${repositoryId}`;\n\n // Find children of this repo via edges\n const childFeatureIds = new Set(\n edgesRef.current.filter((e) => e.source === repoNodeId).map((e) => e.target)\n );\n\n // Snapshot for rollback\n const prevRepoData = getRepositoryData(repoNodeId);\n const childSnapshots = new Map<string, FeatureEntry>();\n for (const childId of childFeatureIds) {\n const childNode = nodesRef.current.find((n) => n.id === childId);\n if (childNode) {\n childSnapshots.set(childId, { nodeId: childId, data: childNode.data as FeatureNodeData });\n }\n }\n\n const rollback = () => {\n if (prevRepoData) addRepositoryToMap(repoNodeId, prevRepoData);\n for (const [childId, entry] of childSnapshots) {\n restoreFeature(childId, entry);\n }\n };\n\n // Optimistic: remove repo + children\n beginMutation();\n removeRepository(repoNodeId);\n for (const childId of childFeatureIds) {\n removeFeature(childId);\n }\n\n try {\n const result = await deleteRepository(repositoryId, {\n deleteFromDisk: options?.deleteFromDisk === true,\n });\n if (!result.success) {\n toast.error(result.error ?? 'Failed to remove repository');\n rollback();\n return;\n }\n deleteSound.play();\n } catch {\n toast.error('Failed to remove repository');\n rollback();\n } finally {\n endMutation();\n }\n },\n [\n deleteSound,\n removeRepository,\n removeFeature,\n addRepositoryToMap,\n restoreFeature,\n getRepositoryData,\n beginMutation,\n endMutation,\n ]\n );\n\n const handleDeleteApplication = useCallback(\n async (applicationId: string) => {\n const appNodeId = featureIdForApplication(applicationId);\n\n // Optimistic: remove application node\n beginMutation();\n removeApplication(appNodeId);\n deleteSound.play();\n\n try {\n const result = await deleteApplication(applicationId);\n if (result.error) {\n toast.error(result.error);\n // Rollback would require storing the previous data; for now we let\n // the next polling reconcile restore it if the delete actually failed.\n }\n } catch {\n toast.error('Failed to delete application');\n } finally {\n endMutation();\n }\n },\n [deleteSound, removeApplication, beginMutation, endMutation]\n );\n\n const handleLayout = useCallback(\n (direction: LayoutDirection) => {\n // Layout is applied via reconcile on next server prop update.\n // For immediate re-layout, we apply dagre and trigger a reconcile-like update.\n const result = layoutWithDagre(nodesRef.current, edgesRef.current, {\n ...getCanvasLayoutDefaults(),\n direction,\n });\n reconcile(result.nodes, result.edges);\n },\n [reconcile]\n );\n\n const handleAddRepository = useCallback(\n (path: string): { wasEmpty: boolean; repoPath: string; tempNodeId: string } => {\n const wasEmpty = getRepoMapSize() === 0;\n const tempId = `repo-temp-${++nextRepoTempId}`;\n const repoName =\n path\n .replace(/[\\\\/]+$/, '')\n .split(/[\\\\/]/)\n .pop() ?? path;\n\n beginMutation();\n addRepositoryToMap(tempId, {\n name: repoName,\n repositoryPath: path,\n id: tempId,\n createdAt: Date.now(),\n gitInfoStatus: 'loading',\n });\n\n addRepository({ path, name: repoName })\n .then((result) => {\n if (result.error) {\n removeRepository(tempId);\n toast.error(result.error);\n return;\n }\n const repo = result.repository!;\n const realId = `repo-${repo.id}`;\n replaceRepository(tempId, realId, {\n name: repo.name,\n repositoryPath: repo.path,\n id: repo.id,\n createdAt:\n repo.createdAt instanceof Date ? repo.createdAt.getTime() : Number(repo.createdAt),\n });\n createSound.play();\n })\n .catch(() => {\n removeRepository(tempId);\n toast.error('Failed to add repository');\n })\n .finally(() => endMutation());\n\n return { wasEmpty, repoPath: path, tempNodeId: tempId };\n },\n [\n addRepositoryToMap,\n removeRepository,\n replaceRepository,\n createSound,\n getRepoMapSize,\n beginMutation,\n endMutation,\n ]\n );\n\n return {\n nodes,\n edges,\n onNodesChange,\n handleConnect,\n handleAddRepository,\n handleArchiveFeature,\n handleLayout,\n handleDeleteFeature,\n handleRetryFeature,\n handleStartFeature,\n handleStopFeature,\n handleUnarchiveFeature,\n handleDeleteRepository,\n handleDeleteApplication,\n createFeatureNode,\n addApplication: addApplicationToMap,\n showArchived,\n setShowArchived,\n getFeatureRepositoryPath,\n getRepositoryData,\n setCallbacks,\n };\n}\n","/* __next_internal_action_entry_do_not_use__ [{\"60495f1a3ee94d5d2693e35665a5b94c6c425339ab\":\"deleteRepository\"},\"src/presentation/web/app/actions/delete-repository.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"60495f1a3ee94d5d2693e35665a5b94c6c425339ab\",callServer,void 0,findSourceMapURL,\"deleteRepository\");export{$$RSC_SERVER_ACTION_0 as deleteRepository};","/* __next_internal_action_entry_do_not_use__ [{\"4094d93eeeace2053edf550148c9336dfa0384d465\":\"getFeatureMetadata\"},\"src/presentation/web/app/actions/get-feature-metadata.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"4094d93eeeace2053edf550148c9336dfa0384d465\",callServer,void 0,findSourceMapURL,\"getFeatureMetadata\");export{$$RSC_SERVER_ACTION_0 as getFeatureMetadata};","'use client';\n\nimport { useState, useMemo, useCallback, useRef, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { Edge, Position } from '@xyflow/react';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\nimport {\n deriveGraph,\n type FeatureEntry,\n type RepoEntry,\n type ApplicationEntry,\n type GraphCallbacks,\n} from '@/lib/derive-graph';\nimport { layoutWithDagre, getCanvasLayoutDefaults } from '@/lib/layout-with-dagre';\n\nexport type { GraphCallbacks } from '@/lib/derive-graph';\n\nexport interface UseGraphStateReturn {\n /** Derived React Flow nodes (from domain Maps). */\n nodes: CanvasNodeType[];\n /** Derived React Flow edges (from domain Maps). */\n edges: Edge[];\n /**\n * Reconcile domain Maps with fresh server data (new initialNodes/initialEdges).\n * Preserves pending (creating) nodes unless a matching real feature appears.\n * No-ops when a mutation is in-flight (see beginMutation/endMutation).\n */\n reconcile: (newNodes: CanvasNodeType[], newEdges: Edge[]) => void;\n /** Update a feature's state/lifecycle/name (e.g., from SSE events). */\n updateFeature: (featureNodeId: string, updates: FeatureDataUpdates) => void;\n /** Add a pending (optimistic) feature node (state='creating'). */\n addPendingFeature: (nodeId: string, data: FeatureNodeData, parentNodeId?: string) => void;\n /** Remove a pending feature node (e.g., on rollback). */\n removePendingFeature: (nodeId: string) => void;\n /** Remove a real feature node from the domain Map. */\n removeFeature: (nodeId: string) => void;\n /** Restore a previously removed feature (rollback). */\n restoreFeature: (nodeId: string, entry: FeatureEntry) => void;\n /** Add a repository node (may use a temp ID initially). */\n addRepository: (nodeId: string, data: RepositoryNodeData) => void;\n /** Remove a repository node. */\n removeRepository: (nodeId: string) => void;\n /** Replace a temp repo ID with the real one (atomic). */\n replaceRepository: (tempId: string, realId: string, data: RepositoryNodeData) => void;\n /** Stable lookup: get the repositoryPath for a feature node. */\n getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;\n /** Stable lookup: get repository node data by nodeId. */\n getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;\n /** Stable lookup: get the current number of repositories in the domain Map. */\n getRepoMapSize: () => number;\n /** Add an application node. */\n addApplication: (nodeId: string, data: ApplicationNodeData) => void;\n /** Remove an application node. */\n removeApplication: (nodeId: string) => void;\n /** Update callbacks injected into node data (does NOT trigger re-render). */\n setCallbacks: (callbacks: GraphCallbacks) => void;\n /**\n * Signal that an optimistic mutation has started. While any mutation is\n * in-flight, `reconcile` becomes a no-op so stale poll data cannot\n * overwrite optimistic state. Calls are ref-counted — nest freely.\n */\n beginMutation: () => void;\n /**\n * Signal that an optimistic mutation has resolved. Adds a one-poll-interval\n * cooldown (default 3 s) so the next poll fetches post-mutation data.\n */\n endMutation: (cooldownMs?: number) => void;\n /** Whether a mutation is currently in-flight (for polling skip logic). */\n isMutating: () => boolean;\n}\n\n/** Parse initialNodes + initialEdges into domain Maps. */\nfunction parseMaps(\n initialNodes: CanvasNodeType[],\n initialEdges: Edge[]\n): {\n featureMap: Map<string, FeatureEntry>;\n repoMap: Map<string, RepoEntry>;\n applicationMap: Map<string, ApplicationEntry>;\n} {\n // Build parentNodeId map from dependency edges\n const parentByChild = new Map<string, string>();\n for (const edge of initialEdges) {\n if (edge.type === 'dependencyEdge') {\n parentByChild.set(edge.target, edge.source);\n }\n }\n\n const featureMap = new Map<string, FeatureEntry>();\n const repoMap = new Map<string, RepoEntry>();\n const applicationMap = new Map<string, ApplicationEntry>();\n\n for (const node of initialNodes) {\n if (node.type === 'featureNode') {\n const data = node.data as FeatureNodeData;\n featureMap.set(node.id, {\n nodeId: node.id,\n data,\n parentNodeId: parentByChild.get(node.id),\n ...(data.applicationId && { applicationId: data.applicationId }),\n });\n } else if (node.type === 'repositoryNode') {\n repoMap.set(node.id, {\n nodeId: node.id,\n data: node.data as RepositoryNodeData,\n });\n } else if (node.type === 'applicationNode') {\n applicationMap.set(node.id, {\n nodeId: node.id,\n data: node.data as ApplicationNodeData,\n });\n }\n }\n\n return { featureMap, repoMap, applicationMap };\n}\n\ntype FeatureDataUpdates = Partial<\n Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>\n>;\n\nfunction isFeatureDataUnchanged(data: FeatureNodeData, updates: FeatureDataUpdates): boolean {\n return (\n (updates.state === undefined || updates.state === data.state) &&\n (updates.lifecycle === undefined || updates.lifecycle === data.lifecycle) &&\n (updates.name === undefined || updates.name === data.name) &&\n (updates.description === undefined || updates.description === data.description)\n );\n}\n\n/**\n * Shallow-compare two Maps by key set and entry data (JSON equality).\n * Returns true if they are structurally identical, avoiding unnecessary re-renders.\n */\nfunction mapsEqual<T extends { data: unknown; parentNodeId?: string }>(\n a: Map<string, T>,\n b: Map<string, T>\n): boolean {\n if (a.size !== b.size) return false;\n for (const [key, aEntry] of a) {\n const bEntry = b.get(key);\n if (!bEntry) return false;\n if (aEntry.parentNodeId !== bEntry.parentNodeId) return false;\n if (aEntry.data === bEntry.data) continue;\n if (JSON.stringify(aEntry.data) !== JSON.stringify(bEntry.data)) return false;\n }\n return true;\n}\n\nexport function useGraphState(\n initialNodes: CanvasNodeType[],\n initialEdges: Edge[],\n showArchived = false\n): UseGraphStateReturn {\n const { i18n } = useTranslation();\n const layoutDefaults = useMemo(() => getCanvasLayoutDefaults(i18n.dir()), [i18n]);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional: parse only on mount (like useState initializer)\n const init = useMemo(() => parseMaps(initialNodes, initialEdges), []);\n\n const [featureMap, setFeatureMap] = useState<Map<string, FeatureEntry>>(init.featureMap);\n const [repoMap, setRepoMap] = useState<Map<string, RepoEntry>>(init.repoMap);\n const [applicationMap, setApplicationMap] = useState<Map<string, ApplicationEntry>>(\n init.applicationMap\n );\n const [pendingMap, setPendingMap] = useState<Map<string, FeatureEntry>>(\n new Map<string, FeatureEntry>()\n );\n\n // Buffer for SSE updates that arrive before their feature is in featureMap.\n // When reconcile adds new features, buffered updates are applied automatically.\n const pendingUpdatesRef = useRef<\n Map<string, Partial<Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>>>\n >(new Map());\n\n // Protect recently-added/replaced repos from stale-poll reconcile.\n // After addRepository or replaceRepository, the repo ID is marked as protected.\n // Once reconcile sees the repo in server data, the protection is cleared.\n // This prevents a stale poll (that fetched data before the server action completed)\n // from wiping a repo that the client has already added.\n const protectedRepoIdsRef = useRef<Set<string>>(new Set());\n\n // Mutation guard: ref-counted counter. While > 0, reconcile is a no-op\n // so stale poll data cannot overwrite optimistic state.\n const mutationCountRef = useRef(0);\n const mutationTimersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n\n // Track 'deleting' features that the server no longer returns.\n // Retained for one extra reconcile cycle so the user sees the deleting state\n // before the node disappears from the canvas.\n const deletingRetainedRef = useRef<Set<string>>(new Set());\n\n // Track deleted repo IDs so reconcile doesn't resurrect them from stale server data.\n // Cleared once reconcile sees the repo is gone from server data.\n const deletedRepoIdsRef = useRef<Set<string>>(new Set());\n\n // Callbacks stored in a ref so changing them doesn't trigger re-render.\n // The stable wrapper object reads from the ref so node closures always use latest callbacks.\n const callbacksRef = useRef<GraphCallbacks>({});\n const stableCallbacks = useMemo<GraphCallbacks>(\n () => ({\n onNodeAction: (nodeId) => callbacksRef.current.onNodeAction?.(nodeId),\n onNodeSettings: (nodeId) => callbacksRef.current.onNodeSettings?.(nodeId),\n onFeatureDelete: (featureId, cleanup, cascadeDelete, closePr) =>\n callbacksRef.current.onFeatureDelete?.(featureId, cleanup, cascadeDelete, closePr),\n onRepositoryAdd: (nodeId) => callbacksRef.current.onRepositoryAdd?.(nodeId),\n onRepositoryClick: (nodeId) => callbacksRef.current.onRepositoryClick?.(nodeId),\n onRepositoryDelete: (repositoryId) => callbacksRef.current.onRepositoryDelete?.(repositoryId),\n onRetryFeature: (featureId) => callbacksRef.current.onRetryFeature?.(featureId),\n onStartFeature: (featureId) => callbacksRef.current.onStartFeature?.(featureId),\n onArchiveFeature: (featureId) => callbacksRef.current.onArchiveFeature?.(featureId),\n onUnarchiveFeature: (featureId) => callbacksRef.current.onUnarchiveFeature?.(featureId),\n onApplicationClick: (applicationId) =>\n callbacksRef.current.onApplicationClick?.(applicationId),\n onApplicationDelete: (applicationId) =>\n callbacksRef.current.onApplicationDelete?.(applicationId),\n onApplicationCreateSddFeature: (applicationId) =>\n callbacksRef.current.onApplicationCreateSddFeature?.(applicationId),\n }),\n []\n );\n\n // Stable refs for domain Maps (for use in callbacks without depending on state)\n const featureMapRef = useRef(featureMap);\n featureMapRef.current = featureMap;\n const repoMapRef = useRef(repoMap);\n repoMapRef.current = repoMap;\n\n // Filter archived features from the Map when the toggle is off.\n // This gives instant toggle response (no server round-trip) per NFR-3.\n const visibleFeatureMap = useMemo(() => {\n if (showArchived) return featureMap;\n const filtered = new Map<string, FeatureEntry>();\n for (const [id, entry] of featureMap) {\n if ((entry.data.state as string) !== 'archived') {\n filtered.set(id, entry);\n }\n }\n return filtered.size === featureMap.size ? featureMap : filtered;\n }, [featureMap, showArchived]);\n\n // Derive graph from domain Maps (runs on every Map change, but dagre only on topology change)\n const derived = useMemo(\n () => deriveGraph(visibleFeatureMap, repoMap, pendingMap, stableCallbacks, applicationMap),\n [visibleFeatureMap, repoMap, pendingMap, stableCallbacks, applicationMap]\n );\n\n // Cache dagre layout positions — only re-run when node set or edge connections change\n const layoutCacheRef = useRef<{\n key: string;\n positions: Map<\n string,\n { position: { x: number; y: number }; targetPosition: Position; sourcePosition: Position }\n >;\n }>({ key: '', positions: new Map() });\n\n const { nodes, edges } = useMemo(() => {\n const nodeIds = derived.nodes\n .map((n) => n.id)\n .sort()\n .join(',');\n const edgeKeys = derived.edges\n .map((e) => `${e.source}-${e.target}`)\n .sort()\n .join(',');\n const topologyKey = `${nodeIds}|${edgeKeys}|${layoutDefaults.direction}`;\n\n if (topologyKey !== layoutCacheRef.current.key) {\n // Topology changed — re-run dagre\n const result = layoutWithDagre(derived.nodes, derived.edges, layoutDefaults);\n const positions = new Map<\n string,\n { position: { x: number; y: number }; targetPosition: Position; sourcePosition: Position }\n >();\n for (const node of result.nodes) {\n positions.set(node.id, {\n position: node.position,\n targetPosition: (node as Record<string, unknown>).targetPosition as Position,\n sourcePosition: (node as Record<string, unknown>).sourcePosition as Position,\n });\n }\n\n // Anchor new layout to previous positions so the graph doesn't drift.\n // Find the first surviving node (exists in both old and new layouts) and\n // shift the entire new layout by the delta between its old and new position.\n const prevPositions = layoutCacheRef.current.positions;\n if (prevPositions.size > 0) {\n let dx = 0;\n let dy = 0;\n for (const [id, newPos] of positions) {\n const oldPos = prevPositions.get(id);\n if (oldPos) {\n dx = oldPos.position.x - newPos.position.x;\n dy = oldPos.position.y - newPos.position.y;\n break;\n }\n }\n if (dx !== 0 || dy !== 0) {\n for (const pos of positions.values()) {\n pos.position = { x: pos.position.x + dx, y: pos.position.y + dy };\n }\n for (const node of result.nodes) {\n node.position = { x: node.position.x + dx, y: node.position.y + dy };\n }\n }\n }\n\n layoutCacheRef.current = { key: topologyKey, positions };\n return result;\n }\n\n // Data-only change — apply cached positions without re-running dagre\n const { positions } = layoutCacheRef.current;\n const nodes = derived.nodes.map((node) => {\n const cached = positions.get(node.id);\n return cached ? { ...node, ...cached } : node;\n });\n return { nodes, edges: derived.edges };\n }, [derived, layoutDefaults]);\n\n // --- Mutations ---\n\n const reconcile = useCallback((newNodes: CanvasNodeType[], newEdges: Edge[]) => {\n // Skip reconciliation while an optimistic mutation is in-flight.\n // Stale poll data fetched before the mutation completed would overwrite\n // the optimistic state, causing flicker (nodes disappearing/reappearing).\n if (mutationCountRef.current > 0) return;\n\n const { featureMap: newFeatureMap, repoMap: newRepoMap } = parseMaps(newNodes, newEdges);\n\n // Precompute match keys so we don't scan newFeatureMap.values() per pending entry\n const realFeatureKeys = new Set(\n [...newFeatureMap.values()].map((e) => `${e.data.name}\\0${e.data.repositoryPath}`)\n );\n\n setFeatureMap((currentFeatureMap) => {\n // Preserve pending (creating) nodes unless matched by name+repositoryPath from newFeatureMap\n const pendingEntries = [...currentFeatureMap.entries()].filter(\n ([, e]) => e.data.state === 'creating'\n );\n\n const merged = new Map(newFeatureMap);\n\n // Keep pending nodes that don't have a real counterpart in new data\n for (const [tempId, pendingEntry] of pendingEntries) {\n const key = `${pendingEntry.data.name}\\0${pendingEntry.data.repositoryPath}`;\n if (!realFeatureKeys.has(key)) {\n merged.set(tempId, pendingEntry);\n }\n }\n\n // Preserve 'deleting' state for features being deleted.\n // If the server still returns the feature, override its state to 'deleting'.\n // If the server no longer returns it (soft-deleted), retain it for one\n // extra reconcile cycle so the user sees the deleting animation.\n const nextRetained = new Set<string>();\n for (const [id, entry] of currentFeatureMap) {\n if (entry.data.state === 'deleting') {\n if (merged.has(id)) {\n // Server still has it — override state to keep showing 'deleting'\n merged.set(id, {\n ...merged.get(id)!,\n data: { ...merged.get(id)!.data, state: 'deleting' },\n });\n } else if (!deletingRetainedRef.current.has(id)) {\n // First reconcile after server removal — retain with deleting state\n merged.set(id, entry);\n nextRetained.add(id);\n }\n // else: already retained once — let it disappear\n }\n }\n deletingRetainedRef.current = nextRetained;\n\n // Apply any buffered SSE updates to features that now exist in the map\n for (const [nodeId, updates] of pendingUpdatesRef.current) {\n const entry = merged.get(nodeId);\n if (entry) {\n merged.set(nodeId, { ...entry, data: { ...entry.data, ...updates } });\n pendingUpdatesRef.current.delete(nodeId);\n }\n }\n\n // Avoid re-render when polling returns identical data\n if (mapsEqual(currentFeatureMap, merged)) return currentFeatureMap;\n return merged;\n });\n\n // Clean pendingMap entries that now have a real counterpart in server data\n setPendingMap((currentPendingMap) => {\n if (currentPendingMap.size === 0) return currentPendingMap;\n let changed = false;\n const next = new Map(currentPendingMap);\n for (const [tempId, pendingEntry] of currentPendingMap) {\n const key = `${pendingEntry.data.name}\\0${pendingEntry.data.repositoryPath}`;\n if (realFeatureKeys.has(key)) {\n next.delete(tempId);\n changed = true;\n }\n }\n return changed ? next : currentPendingMap;\n });\n\n // Merge repoMap: preserve optimistic (temp) repos AND recently-added/replaced\n // repos that the server doesn't know about yet. Without this, a polling\n // reconcile that fires before the server action returns (or uses stale data\n // from an in-flight fetch) would wipe the repo, causing a canvas→empty flicker.\n setRepoMap((currentRepoMap) => {\n // Start with everything the server returned\n const merged = new Map(newRepoMap);\n\n // Remove repos that were deleted client-side but the server still returns\n // (stale data). Once the server stops returning the repo, clear the tombstone.\n for (const deletedId of deletedRepoIdsRef.current) {\n if (merged.has(deletedId)) {\n merged.delete(deletedId);\n } else {\n // Server confirmed deletion — no longer need the tombstone\n deletedRepoIdsRef.current.delete(deletedId);\n }\n }\n\n // Build a set of repositoryPaths present in server data for dedup\n const serverPaths = new Set([...newRepoMap.values()].map((e) => e.data.repositoryPath));\n\n for (const [id, entry] of currentRepoMap) {\n if (merged.has(id)) {\n // Server confirmed this repo — no longer needs protection\n protectedRepoIdsRef.current.delete(id);\n continue;\n }\n if (serverPaths.has(entry.data.repositoryPath)) {\n // Server has a repo with same path — clear protection\n protectedRepoIdsRef.current.delete(id);\n continue;\n }\n // Keep temp repos or protected (recently added/replaced) repos\n if (id.startsWith('repo-temp-') || protectedRepoIdsRef.current.has(id)) {\n merged.set(id, entry);\n }\n }\n\n // Avoid re-render when polling returns identical data\n if (mapsEqual(currentRepoMap, merged)) return currentRepoMap;\n return merged;\n });\n\n // Reconcile applicationMap\n const { applicationMap: newApplicationMap } = parseMaps(newNodes, newEdges);\n setApplicationMap((currentAppMap) => {\n if (mapsEqual(currentAppMap, newApplicationMap)) return currentAppMap;\n return newApplicationMap;\n });\n }, []);\n\n const updateFeature = useCallback((featureNodeId: string, updates: FeatureDataUpdates) => {\n setFeatureMap((prev) => {\n const entry = prev.get(featureNodeId);\n if (!entry) {\n // Feature not yet in map — buffer update for when reconcile adds it\n pendingUpdatesRef.current.set(featureNodeId, {\n ...pendingUpdatesRef.current.get(featureNodeId),\n ...updates,\n });\n return prev;\n }\n // Clear any buffered update for this feature since it's now in the map\n pendingUpdatesRef.current.delete(featureNodeId);\n if (isFeatureDataUnchanged(entry.data, updates)) return prev;\n const next = new Map(prev);\n next.set(featureNodeId, { ...entry, data: { ...entry.data, ...updates } });\n return next;\n });\n\n // Also check pendingMap\n setPendingMap((prev) => {\n const entry = prev.get(featureNodeId);\n if (!entry) return prev;\n if (isFeatureDataUnchanged(entry.data, updates)) return prev;\n const next = new Map(prev);\n next.set(featureNodeId, { ...entry, data: { ...entry.data, ...updates } });\n return next;\n });\n }, []);\n\n const addPendingFeature = useCallback(\n (nodeId: string, data: FeatureNodeData, parentNodeId?: string) => {\n setPendingMap((prev) => {\n const next = new Map(prev);\n // Mirror parseMaps: lift data.applicationId into the FeatureEntry so\n // derive-graph emits an app→feature edge for the optimistic node.\n next.set(nodeId, {\n nodeId,\n data,\n parentNodeId,\n ...(data.applicationId && { applicationId: data.applicationId }),\n });\n return next;\n });\n },\n []\n );\n\n const removePendingFeature = useCallback((nodeId: string) => {\n setPendingMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const removeFeature = useCallback((nodeId: string) => {\n setFeatureMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const restoreFeature = useCallback((nodeId: string, entry: FeatureEntry) => {\n setFeatureMap((prev) => {\n const next = new Map(prev);\n next.set(nodeId, entry);\n return next;\n });\n }, []);\n\n const addRepository = useCallback((nodeId: string, data: RepositoryNodeData) => {\n protectedRepoIdsRef.current.add(nodeId);\n deletedRepoIdsRef.current.delete(nodeId);\n setRepoMap((prev) => {\n const next = new Map(prev);\n next.set(nodeId, { nodeId, data });\n return next;\n });\n }, []);\n\n const removeRepository = useCallback((nodeId: string) => {\n protectedRepoIdsRef.current.delete(nodeId);\n deletedRepoIdsRef.current.add(nodeId);\n setRepoMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const replaceRepository = useCallback(\n (tempId: string, realId: string, data: RepositoryNodeData) => {\n protectedRepoIdsRef.current.delete(tempId);\n protectedRepoIdsRef.current.add(realId);\n setRepoMap((prev) => {\n if (!prev.has(tempId)) return prev;\n const next = new Map(prev);\n next.delete(tempId);\n next.set(realId, { nodeId: realId, data });\n return next;\n });\n },\n []\n );\n\n const addApplication = useCallback((nodeId: string, data: ApplicationNodeData) => {\n setApplicationMap((prev) => {\n const next = new Map(prev);\n next.set(nodeId, { nodeId, data });\n return next;\n });\n }, []);\n\n const removeApplication = useCallback((nodeId: string) => {\n setApplicationMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const getFeatureRepositoryPath = useCallback((featureNodeId: string): string | undefined => {\n return featureMapRef.current.get(featureNodeId)?.data.repositoryPath;\n }, []);\n\n const getRepositoryData = useCallback((nodeId: string): RepositoryNodeData | undefined => {\n return repoMapRef.current.get(nodeId)?.data;\n }, []);\n\n const getRepoMapSize = useCallback((): number => {\n return repoMapRef.current.size;\n }, []);\n\n const setCallbacks = useCallback((callbacks: GraphCallbacks) => {\n callbacksRef.current = callbacks;\n }, []);\n\n const beginMutation = useCallback(() => {\n mutationCountRef.current++;\n }, []);\n\n const endMutation = useCallback((cooldownMs = 3_000) => {\n // Delay decrement by one poll interval so the next fetch after the\n // mutation returns post-mutation data, not a stale in-flight response.\n const timer = setTimeout(() => {\n mutationCountRef.current = Math.max(0, mutationCountRef.current - 1);\n mutationTimersRef.current.delete(timer);\n }, cooldownMs);\n mutationTimersRef.current.add(timer);\n }, []);\n\n const isMutating = useCallback(() => mutationCountRef.current > 0, []);\n\n // Cleanup cooldown timers on unmount\n useEffect(() => {\n const timers = mutationTimersRef.current;\n return () => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n };\n }, []);\n\n return {\n nodes,\n edges,\n reconcile,\n updateFeature,\n addPendingFeature,\n removePendingFeature,\n removeFeature,\n restoreFeature,\n addRepository,\n removeRepository,\n replaceRepository,\n getFeatureRepositoryPath,\n getRepositoryData,\n getRepoMapSize,\n addApplication,\n removeApplication,\n setCallbacks,\n beginMutation,\n endMutation,\n isMutating,\n };\n}\n","/**\n * derive-graph.ts\n *\n * Pure client-side derivation: domain Maps → React Flow nodes + edges.\n * All edges are derived from domain relationships (repositoryPath matching,\n * parentNodeId) — never stored independently.\n */\n\nimport type { Edge } from '@xyflow/react';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\n/** A feature node entry stored in the domain Map. */\nexport interface FeatureEntry {\n nodeId: string;\n data: FeatureNodeData;\n /** If set, this feature connects to a parent feature via a dependency edge (no repo→feature edge). */\n parentNodeId?: string;\n /**\n * If set, this feature was launched scoped to an Application. Matched against\n * ApplicationEntry.data.id to derive an app→feature dependency edge instead of\n * the default repo→feature edge.\n */\n applicationId?: string;\n}\n\n/** A repository node entry stored in the domain Map. */\nexport interface RepoEntry {\n nodeId: string;\n data: RepositoryNodeData;\n}\n\n/** An application node entry stored in the domain Map. */\nexport interface ApplicationEntry {\n nodeId: string;\n data: ApplicationNodeData;\n}\n\n/** Stable callbacks passed by the consumer, injected into derived node data. */\nexport interface GraphCallbacks {\n /** Called when the user triggers an action on a feature node (e.g., adds a sub-feature). */\n onNodeAction?: (nodeId: string) => void;\n /** Called when the user opens settings/details on a feature node. */\n onNodeSettings?: (nodeId: string) => void;\n /** Called when the user deletes a feature. */\n onFeatureDelete?: (\n featureId: string,\n cleanup?: boolean,\n cascadeDelete?: boolean,\n closePr?: boolean\n ) => void;\n /** Called when the user clicks the \"+\" add-feature button on a repo node. */\n onRepositoryAdd?: (repoNodeId: string) => void;\n /** Called when the user clicks a repo node to navigate to its detail page. */\n onRepositoryClick?: (repoNodeId: string) => void;\n /** Called when the user deletes a repository. */\n onRepositoryDelete?: (repositoryId: string, options?: { deleteFromDisk?: boolean }) => void;\n /** Called when the user retries a failed feature. */\n onRetryFeature?: (featureId: string) => void;\n /** Called when the user starts a pending feature. */\n onStartFeature?: (featureId: string) => void;\n /** Called when the user stops a running feature. */\n onStopFeature?: (featureId: string) => void;\n /** Called when the user archives a feature. */\n onArchiveFeature?: (featureId: string) => void;\n /** Called when the user unarchives a feature. */\n onUnarchiveFeature?: (featureId: string) => void;\n /** Called when the user clicks an application node to navigate to its detail page. */\n onApplicationClick?: (applicationId: string) => void;\n /** Called when the user deletes an application. */\n onApplicationDelete?: (applicationId: string) => void;\n /** Called when the user triggers \"New SDD feature\" on an application node —\n * the consumer is expected to navigate to the create drawer pre-scoped to\n * this application in spec mode. */\n onApplicationCreateSddFeature?: (applicationId: string) => void;\n}\n\n/**\n * Derives React Flow nodes and edges from domain Maps.\n *\n * - Feature nodes without a parentNodeId → repo→feature edge (matched by repositoryPath)\n * - Feature nodes without a parentNodeId but with no matching repo → virtual repo node\n * - Feature nodes with a parentNodeId → dependency edge (parentNodeId→nodeId)\n * - Pending feature nodes (creating state) from pendingMap → same rules, no action callbacks\n * - Callbacks are injected into node data via closures\n */\nexport function deriveGraph(\n featureMap: Map<string, FeatureEntry>,\n repoMap: Map<string, RepoEntry>,\n pendingMap: Map<string, FeatureEntry>,\n callbacks?: GraphCallbacks,\n applicationMap?: Map<string, ApplicationEntry>\n): { nodes: CanvasNodeType[]; edges: Edge[] } {\n const nodes: CanvasNodeType[] = [];\n const edges: Edge[] = [];\n\n // Normalize path separators so Windows backslash paths match forward-slash paths\n const normalizePath = (p: string) => p.replace(/\\\\/g, '/');\n\n // Build a lookup: repositoryPath → repoNodeId\n const repoByPath = new Map<string, string>();\n for (const [nodeId, entry] of repoMap) {\n if (entry.data.repositoryPath) {\n repoByPath.set(normalizePath(entry.data.repositoryPath), nodeId);\n }\n }\n\n // Build a lookup: application domain UUID → applicationNodeId. Used to\n // resolve a feature's `applicationId` (a domain UUID, not a node id)\n // to its rendered ApplicationNode on the canvas.\n const appByDomainId = new Map<string, string>();\n if (applicationMap) {\n for (const [nodeId, entry] of applicationMap) {\n if (entry.data.id) {\n appByDomainId.set(entry.data.id, nodeId);\n }\n }\n }\n\n // Virtual repo nodes created for orphaned features (not in repoMap)\n const virtualRepos = new Map<string, string>(); // path → virtualNodeId\n\n function getOrCreateVirtualRepo(repositoryPath: string): string {\n if (virtualRepos.has(repositoryPath)) {\n return virtualRepos.get(repositoryPath)!;\n }\n const virtualId = `virtual-repo-${repositoryPath}`;\n const repoName = repositoryPath.split('/').filter(Boolean).at(-1) ?? repositoryPath;\n nodes.push({\n id: virtualId,\n type: 'repositoryNode',\n position: { x: 0, y: 0 },\n data: { name: repoName, repositoryPath } satisfies RepositoryNodeData,\n } as CanvasNodeType);\n virtualRepos.set(repositoryPath, virtualId);\n return virtualId;\n }\n\n // Add repo nodes (real ones) — sorted by createdAt for stable vertical order.\n // The server-side layoutWithDagre may reorder the node array (connected vs\n // disconnected split), so we cannot rely on Map insertion order alone.\n // Use Infinity fallback so repos without createdAt sort last (appear at bottom).\n const sortedRepoEntries = [...repoMap.entries()].sort((a, b) => {\n const aRaw = a[1].data.createdAt;\n const bRaw = b[1].data.createdAt;\n const aTime = typeof aRaw === 'number' && !Number.isNaN(aRaw) ? aRaw : Infinity;\n const bTime = typeof bRaw === 'number' && !Number.isNaN(bRaw) ? bRaw : Infinity;\n return aTime - bTime;\n });\n for (const [nodeId, entry] of sortedRepoEntries) {\n const data: RepositoryNodeData = {\n ...entry.data,\n ...(callbacks?.onRepositoryAdd && {\n onAdd: () => callbacks.onRepositoryAdd!(nodeId),\n }),\n ...(callbacks?.onRepositoryClick && {\n onClick: () => callbacks.onRepositoryClick!(nodeId),\n }),\n ...(callbacks?.onRepositoryDelete && {\n onDelete: callbacks.onRepositoryDelete,\n }),\n };\n nodes.push({\n id: nodeId,\n type: 'repositoryNode',\n position: { x: 0, y: 0 },\n data,\n } as CanvasNodeType);\n }\n\n // Process feature entries (both real and pending).\n // Skip pendingMap entries that already exist in featureMap (reconcile may not\n // have cleaned them up yet if the AI-generated name differs from the original).\n const allFeatureEntries: [string, FeatureEntry, boolean][] = [\n ...[...featureMap.entries()].map(\n ([id, e]) => [id, e, false] as [string, FeatureEntry, boolean]\n ),\n ...[...pendingMap.entries()]\n .filter(([id]) => !featureMap.has(id))\n .map(([id, e]) => [id, e, true] as [string, FeatureEntry, boolean]),\n ];\n\n for (const [nodeId, entry, isPending] of allFeatureEntries) {\n const isCreating = entry.data.state === 'creating' || isPending;\n\n const data: FeatureNodeData = {\n ...entry.data,\n // Callbacks only for non-creating nodes\n ...(!isCreating &&\n callbacks?.onNodeAction && {\n onAction: () => callbacks.onNodeAction!(nodeId),\n }),\n ...(!isCreating &&\n callbacks?.onNodeSettings && {\n onSettings: () => callbacks.onNodeSettings!(nodeId),\n }),\n ...(!isCreating &&\n callbacks?.onFeatureDelete && {\n onDelete: callbacks.onFeatureDelete,\n }),\n ...(!isCreating &&\n entry.data.state === 'error' &&\n callbacks?.onRetryFeature && {\n onRetry: callbacks.onRetryFeature,\n }),\n ...(!isCreating &&\n entry.data.state === 'pending' &&\n callbacks?.onStartFeature && {\n onStart: callbacks.onStartFeature,\n }),\n ...(!isCreating &&\n (entry.data.state === 'running' || entry.data.state === 'action-required') &&\n callbacks?.onStopFeature && {\n onStop: callbacks.onStopFeature,\n }),\n ...(!isCreating &&\n entry.data.state !== 'archived' &&\n entry.data.state !== 'deleting' &&\n callbacks?.onArchiveFeature && {\n onArchive: callbacks.onArchiveFeature,\n }),\n ...(!isCreating &&\n entry.data.state === 'archived' &&\n callbacks?.onUnarchiveFeature && {\n onUnarchive: callbacks.onUnarchiveFeature,\n }),\n };\n\n nodes.push({\n id: nodeId,\n type: 'featureNode',\n position: { x: 0, y: 0 },\n data,\n } as CanvasNodeType);\n\n // Edge derivation\n // Priority order:\n // 1) parentNodeId → feature→feature dep edge (existing behavior)\n // 2) applicationId matching a known ApplicationNode → app→feature dep edge\n // 3) repositoryPath → repo→feature edge (existing fallback)\n // If parentNodeId references a feature that's not visible (e.g. archived/filtered),\n // fall through so the child reconnects to its application or repository.\n const appNodeId = entry.applicationId ? appByDomainId.get(entry.applicationId) : undefined;\n if (\n entry.parentNodeId &&\n (featureMap.has(entry.parentNodeId) || pendingMap.has(entry.parentNodeId))\n ) {\n // Dependency edge (parent→child feature)\n edges.push({\n id: `dep-${entry.parentNodeId}-${nodeId}`,\n source: entry.parentNodeId,\n target: nodeId,\n type: 'dependencyEdge',\n });\n } else if (appNodeId) {\n // Application→feature dep edge (SDD-mode features launched from an app)\n edges.push({\n id: `dep-${appNodeId}-${nodeId}`,\n source: appNodeId,\n target: nodeId,\n type: 'dependencyEdge',\n });\n } else {\n // Repo→feature edge (matched by repositoryPath)\n const repositoryPath = normalizePath(entry.data.repositoryPath);\n const repoNodeId = repoByPath.get(repositoryPath) ?? getOrCreateVirtualRepo(repositoryPath);\n edges.push({\n id: `edge-${repoNodeId}-${nodeId}`,\n source: repoNodeId,\n target: nodeId,\n style: { strokeDasharray: '5 5' },\n });\n }\n }\n\n // Emit ApplicationNodes for every workspace application. Features whose\n // `applicationId` matches an entry above already have an app→feature edge;\n // applications without any child SDD feature simply render as standalone\n // nodes (mirrors how repository nodes appear with no children).\n if (applicationMap) {\n for (const [nodeId, entry] of applicationMap) {\n const data: ApplicationNodeData = {\n ...entry.data,\n ...(callbacks?.onApplicationClick && {\n onClick: () => callbacks.onApplicationClick!(entry.data.id),\n }),\n ...(callbacks?.onApplicationDelete && {\n onDelete: callbacks.onApplicationDelete,\n }),\n ...(callbacks?.onApplicationCreateSddFeature && {\n onCreateSddFeature: callbacks.onApplicationCreateSddFeature,\n }),\n };\n nodes.push({\n id: nodeId,\n type: 'applicationNode',\n position: { x: 0, y: 0 },\n data,\n } as CanvasNodeType);\n }\n }\n\n // Build set of feature node IDs that have children (are dependency edge sources)\n const parentNodeIds = new Set<string>();\n for (const edge of edges) {\n if (edge.type === 'dependencyEdge') {\n parentNodeIds.add(edge.source);\n }\n }\n\n // Inject showHandles and hasChildren based on edges\n const hasEdges = edges.length > 0;\n for (const node of nodes) {\n const data = node.data as Record<string, unknown>;\n data.showHandles = hasEdges;\n if (node.type === 'featureNode') {\n data.hasChildren = parentNodeIds.has(node.id);\n }\n }\n\n return { nodes, edges };\n}\n","'use client';\n\nimport { useCallback } from 'react';\nimport { Code2, Terminal, FolderOpen, RefreshCw } from 'lucide-react';\nimport { BaseDrawer } from '@/components/common/base-drawer';\nimport { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';\nimport { Separator } from '@/components/ui/separator';\nimport { ActionButton } from '@/components/common/action-button';\nimport type { RepositoryNodeData } from './repository-node-config';\nimport { useRepositoryActions } from './use-repository-actions';\n\nexport interface RepositoryDrawerProps {\n data: RepositoryNodeData | null;\n onClose: () => void;\n}\n\nexport function RepositoryDrawer({ data, onClose }: RepositoryDrawerProps) {\n const handleClose = useCallback(() => {\n onClose();\n }, [onClose]);\n\n const actions = useRepositoryActions(\n data?.repositoryPath ? { repositoryId: data.id, repositoryPath: data.repositoryPath } : null\n );\n\n return (\n <BaseDrawer\n open={data !== null}\n onClose={handleClose}\n size=\"md\"\n modal={false}\n data-testid=\"repository-drawer\"\n deployTarget={\n data?.repositoryPath\n ? {\n targetId: data.repositoryPath,\n targetType: 'repository',\n repositoryPath: data.repositoryPath,\n }\n : undefined\n }\n header={\n data ? (\n <div data-testid=\"repository-drawer-header\">\n <DrawerTitle>{data.name}</DrawerTitle>\n {data.repositoryPath ? (\n <DrawerDescription className=\"truncate font-mono text-xs\">\n {data.repositoryPath}\n </DrawerDescription>\n ) : null}\n </div>\n ) : undefined\n }\n >\n {data?.repositoryPath ? (\n <>\n <Separator />\n <div className=\"flex flex-col gap-3 p-4\">\n <div className=\"text-muted-foreground text-xs font-semibold tracking-wider\">\n OPEN WITH\n </div>\n <div className=\"flex flex-col gap-2\">\n <ActionButton\n label=\"Open in IDE\"\n onClick={actions.openInIde}\n loading={actions.ideLoading}\n error={!!actions.ideError}\n icon={Code2}\n variant=\"outline\"\n size=\"sm\"\n />\n <ActionButton\n label=\"Open in Shell\"\n onClick={actions.openInShell}\n loading={actions.shellLoading}\n error={!!actions.shellError}\n icon={Terminal}\n variant=\"outline\"\n size=\"sm\"\n />\n <ActionButton\n label=\"Open Folder\"\n onClick={actions.openFolder}\n loading={actions.folderLoading}\n error={!!actions.folderError}\n icon={FolderOpen}\n variant=\"outline\"\n size=\"sm\"\n />\n </div>\n </div>\n {data.id ? (\n <>\n <Separator />\n <div className=\"flex flex-col gap-3 p-4\">\n <div className=\"text-muted-foreground text-xs font-semibold tracking-wider\">\n GIT OPERATIONS\n </div>\n <div className=\"flex flex-col gap-2\">\n <ActionButton\n label=\"Sync Main\"\n onClick={actions.syncMain}\n loading={actions.syncLoading}\n error={!!actions.syncError}\n icon={RefreshCw}\n variant=\"outline\"\n size=\"sm\"\n />\n {actions.syncError ? (\n <p className=\"text-destructive text-xs\">{actions.syncError}</p>\n ) : null}\n </div>\n </div>\n </>\n ) : null}\n </>\n ) : null}\n </BaseDrawer>\n );\n}\n","'use client';\n\nimport { useCallback, useState } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport {\n ExternalLink,\n LayoutGrid,\n Loader2,\n Play,\n Plus,\n RotateCcw,\n Square,\n Trash2,\n} from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Button } from '@/components/ui/button';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\nimport { useTurnStatus } from '@/hooks/turn-statuses-provider';\nimport { useDeployAction } from '@/hooks/use-deploy-action';\nimport { DeploymentState } from '@shepai/core/domain/generated/output';\nimport { featureIdForApplication } from '@shepai/core/domain/shared/feature-id';\nimport { deriveAppLiveStatus } from '@/lib/derive-app-status';\nimport type { ApplicationNodeData } from './application-node-config';\n\n/** Preview slot height. Used only when a deployment is actually Live —\n * when the app is idle, we collapse to a single Run row so the card\n * matches the repository node's vertical rhythm on the canvas. */\nconst PREVIEW_HEIGHT_PX = 180;\n\nexport function ApplicationNode({\n data,\n selected,\n}: {\n data: ApplicationNodeData;\n selected?: boolean;\n [key: string]: unknown;\n}) {\n const { i18n, t } = useTranslation('web');\n const isRtl = i18n.dir() === 'rtl';\n const targetHandlePos = isRtl ? Position.Right : Position.Left;\n const sourceHandlePos = isRtl ? Position.Left : Position.Right;\n const [confirmOpen, setConfirmOpen] = useState(false);\n\n const totalRepoCount = 1 + data.additionalPathCount;\n const repoCountLabel = totalRepoCount === 1 ? '1 repository' : `${totalRepoCount} repositories`;\n\n // Live session turn status from the global SSE subscription. The\n // scope key is `app-<id>` — same key used everywhere else the\n // application's chat is referenced.\n const turnStatus = useTurnStatus(featureIdForApplication(data.id));\n\n // Shared dev-server deploy state — one per card. Subscribes to the\n // `DeploymentStatusProvider` which is SSR-seeded in the dashboard\n // layout from `ListDeploymentsUseCase`, so running apps render as\n // \"Live\" on the first paint without a client round-trip.\n //\n // The card's Preview button drives this hook and the `live.label`\n // below is derived from the SAME state (via `deploy.url`), so the\n // status pill, the preview slot, and the button are always in\n // sync — hitting the button on one card can never leave the card\n // itself showing a stale \"Ready\" state.\n const deploy = useDeployAction({\n targetId: data.id,\n targetType: 'application',\n repositoryPath: data.repositoryPath,\n });\n\n // The hook is the single source of truth for the running URL.\n //\n // The shared `DeploymentStatusProvider` is seeded from SSR\n // (`get-graph-data` → `ListDeploymentsUseCase`) so the entry for\n // this application is already populated on the first client render,\n // and `ensureHydrated` catches anything the SSR seed missed. On\n // Stop the hook clears `deploy.url` to null which immediately\n // collapses the pill from \"Live\" back to \"Ready\" — there is\n // intentionally no secondary snapshot URL that could stay stale.\n const effectiveDeploymentUrl = deploy.url;\n\n const live = deriveAppLiveStatus(data.status, turnStatus, !!effectiveDeploymentUrl);\n\n // Clicking anything in the \"card controls\" zone (Preview button,\n // open-in-new-tab) must not trigger the card's navigation-to-app\n // click handler. A single stopPropagation wrapper keeps every\n // control inside the card safe without individually guarding each\n // one.\n const stopCardClick = useCallback((e: React.MouseEvent | React.PointerEvent) => {\n e.stopPropagation();\n }, []);\n\n const openPreviewInNewTab = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (effectiveDeploymentUrl) {\n window.open(effectiveDeploymentUrl, '_blank', 'noopener,noreferrer');\n }\n },\n [effectiveDeploymentUrl]\n );\n\n return (\n <div\n className={cn('group relative', data.onDelete && data.id && 'ps-10')}\n style={{ direction: isRtl ? 'rtl' : 'ltr' }}\n >\n {/* Target handle (left in LTR) — always rendered for edge connections */}\n <Handle\n type=\"target\"\n position={targetHandlePos}\n isConnectable={false}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n\n {/* Delete button — visible on hover, positioned just outside the card\n on the left. Uses the same inset offset as the repository node so\n the two card types align horizontally on the canvas. */}\n {data.onDelete && data.id ? (\n <>\n <div\n className=\"absolute -start-3 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n aria-label=\"Remove application\"\n data-testid=\"application-node-delete-button\"\n onClick={(e) => {\n e.stopPropagation();\n setConfirmOpen(true);\n }}\n className=\"bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Remove application</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n\n <Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>\n <DialogContent className=\"max-w-xs\">\n <DialogHeader>\n <DialogTitle>Remove application?</DialogTitle>\n <DialogDescription>\n This will remove <strong>{data.name}</strong> from your workspace.\n </DialogDescription>\n </DialogHeader>\n <DialogFooter className=\"grid grid-cols-2 gap-2 sm:flex-none\">\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button\n variant=\"destructive\"\n onClick={() => {\n setConfirmOpen(false);\n data.onDelete?.(data.id);\n }}\n >\n Remove\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n ) : null}\n\n <div\n role=\"button\"\n tabIndex={0}\n data-testid=\"application-node-card\"\n data-app-name={data.name}\n onClick={(e) => {\n e.stopPropagation();\n data.onClick?.();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n data.onClick?.();\n }\n }}\n className={cn(\n 'nodrag bg-card flex w-[26rem] cursor-pointer flex-col overflow-hidden rounded-xl border shadow-sm transition-[border-color,box-shadow] duration-200 dark:bg-neutral-800/80',\n selected && 'border-blue-400 dark:border-amber-500/60',\n !selected && live.borderClass\n )}\n >\n {/* Row 1: Header — icon, name, status, \"+ New\" action.\n Layout mirrors the repository node so apps and repos read\n as visual peers on the canvas. The \"+ New\" button is the\n primary entry point for creating a feature scoped to this\n application; it opens the same drawer the repo node opens\n (mode editable, repo locked to the app's repo). */}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-violet-500\">\n <LayoutGrid className=\"h-4 w-4 text-white\" />\n </div>\n <span\n data-testid=\"application-node-name\"\n className=\"min-w-0 truncate text-sm font-medium\"\n >\n {data.name}\n </span>\n <span className=\"ms-auto flex shrink-0 items-center gap-2\">\n <span className=\"flex items-center gap-1.5\">\n <span\n data-testid=\"application-node-status-dot\"\n className={cn(\n 'relative flex h-2 w-2 items-center justify-center rounded-full',\n live.dotClass\n )}\n >\n {live.pulse ? (\n <span\n className={cn(\n 'absolute inline-flex h-full w-full animate-ping rounded-full opacity-60',\n live.dotClass\n )}\n />\n ) : null}\n </span>\n <span\n data-testid=\"application-node-status-text\"\n className=\"text-muted-foreground text-xs\"\n >\n {live.label}\n </span>\n </span>\n {data.onCreateSddFeature && data.id ? (\n <span onClick={(e) => e.stopPropagation()}>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={t('applicationNode.newFeature')}\n data-testid=\"application-node-new-sdd-feature-button\"\n onClick={(e) => {\n e.stopPropagation();\n data.onCreateSddFeature?.(data.id);\n }}\n onPointerDown={(e) => e.stopPropagation()}\n className=\"nodrag flex h-6 shrink-0 cursor-pointer items-center gap-0.5 rounded bg-blue-500 px-1.5 text-[11px] font-bold text-white transition-colors hover:bg-blue-600 dark:bg-amber-500 dark:hover:bg-amber-400\"\n >\n <Plus className=\"h-3 w-3\" />\n <span className=\"translate-y-px\">{t('repositoryNode.new')}</span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">{t('applicationNode.newFeature')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </span>\n ) : null}\n </span>\n </div>\n\n {/* Row 2: Live preview iframe — only mounted when a deployment\n is actually Ready. When the app is idle / booting / errored\n we collapse this slot so the card matches the repository\n node's vertical rhythm; the dev-server status is surfaced\n on the Run row below instead of an oversized placeholder. */}\n {effectiveDeploymentUrl && deploy.status === DeploymentState.Ready ? (\n <div className=\"px-4 pb-2\" onClick={stopCardClick}>\n <div\n className=\"bg-muted group/preview relative overflow-hidden rounded-lg\"\n style={{ height: PREVIEW_HEIGHT_PX }}\n >\n <iframe\n src={effectiveDeploymentUrl}\n title={`${data.name} live preview`}\n className=\"pointer-events-none absolute top-0 left-0 origin-top-left border-0 bg-white\"\n style={{\n width: '250%',\n height: '250%',\n transform: 'scale(0.4)',\n }}\n sandbox=\"allow-same-origin allow-scripts\"\n loading=\"lazy\"\n />\n\n {/* Hover overlay — Stop + Open-in-new-tab cluster */}\n <div\n className=\"pointer-events-none absolute inset-0 flex items-center justify-center gap-2 bg-neutral-900/75 opacity-0 transition-opacity duration-150 group-hover/preview:pointer-events-auto group-hover/preview:opacity-100 dark:bg-neutral-950/80\"\n onPointerDown={stopCardClick}\n onClick={stopCardClick}\n >\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n void deploy.stop();\n }}\n disabled={deploy.stopLoading}\n aria-label=\"Stop dev server\"\n title=\"Stop dev server\"\n className=\"inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-md border border-neutral-300 bg-white px-3 text-xs font-semibold text-neutral-900 shadow-md transition-colors hover:border-red-500 hover:bg-red-50 hover:text-red-600 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-100 dark:hover:border-red-500 dark:hover:bg-red-950 dark:hover:text-red-400\"\n >\n {deploy.stopLoading ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <Square className=\"h-3.5 w-3.5 fill-current\" />\n )}\n <span>Stop</span>\n </button>\n <button\n type=\"button\"\n onClick={openPreviewInNewTab}\n aria-label={`Open ${data.name} in a new tab`}\n title={effectiveDeploymentUrl}\n className=\"inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-md border border-neutral-300 bg-white px-3 text-xs font-semibold text-neutral-900 shadow-md transition-colors hover:bg-neutral-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-100 dark:hover:bg-neutral-800\"\n >\n <ExternalLink className=\"h-3.5 w-3.5\" />\n <span>Open</span>\n </button>\n </div>\n </div>\n </div>\n ) : null}\n\n {/* Row 3: Run / dev-server status — mirrors the repository\n node's \"Run | start local environment | ▶\" line so apps\n and repos read as visual peers. Carries every transient\n state (Booting / Stopping / Error) inline instead of\n inflating the card with a placeholder slot. */}\n <div\n data-testid=\"application-node-dev-preview\"\n className=\"border-border/50 flex items-center gap-2 border-t px-4 py-2 text-xs\"\n onClick={stopCardClick}\n >\n {deploy.deployError ? (\n <span className=\"truncate text-xs text-red-500\">{deploy.deployError}</span>\n ) : deploy.status === DeploymentState.Booting || deploy.deployLoading ? (\n <span className=\"text-muted-foreground inline-flex items-center gap-1.5\">\n <Loader2 className=\"h-3 w-3 shrink-0 animate-spin text-amber-500\" />\n <span>Starting…</span>\n </span>\n ) : deploy.stopLoading ? (\n <span className=\"text-muted-foreground inline-flex items-center gap-1.5\">\n <Loader2 className=\"h-3 w-3 shrink-0 animate-spin\" />\n <span>Stopping…</span>\n </span>\n ) : effectiveDeploymentUrl ? (\n <>\n <span className=\"me-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500\" />\n <a\n href={effectiveDeploymentUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"truncate text-green-700 hover:underline dark:text-green-400\"\n onClick={openPreviewInNewTab}\n >\n {effectiveDeploymentUrl}\n </a>\n </>\n ) : (\n <span className=\"text-muted-foreground inline-flex items-baseline gap-2\">\n <span>Run</span>\n <span className=\"text-muted-foreground/50 text-[10px]\">start local environment</span>\n </span>\n )}\n <span className=\"ms-auto flex items-center gap-1\">\n <span data-testid=\"application-node-repo-count\" className=\"text-muted-foreground/70\">\n {repoCountLabel}\n </span>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n if (deploy.deployError) {\n void deploy.deploy();\n return;\n }\n if (effectiveDeploymentUrl) {\n void deploy.stop();\n return;\n }\n void deploy.deploy();\n }}\n onPointerDown={stopCardClick}\n disabled={deploy.deployLoading || deploy.stopLoading}\n aria-label={\n deploy.deployError\n ? 'Retry'\n : effectiveDeploymentUrl\n ? 'Stop dev server'\n : 'Start dev server'\n }\n className={cn(\n 'text-muted-foreground hover:bg-muted flex h-6 w-6 items-center justify-center rounded transition-colors disabled:cursor-not-allowed disabled:opacity-50',\n !effectiveDeploymentUrl &&\n !deploy.deployError &&\n 'text-green-600 hover:text-green-700 dark:text-green-400 dark:hover:text-green-300'\n )}\n >\n {deploy.deployLoading || deploy.stopLoading ? (\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n ) : deploy.deployError ? (\n <RotateCcw className=\"h-3 w-3\" />\n ) : effectiveDeploymentUrl ? (\n <Square className=\"h-3 w-3 fill-current\" />\n ) : (\n <Play className=\"h-3 w-3 fill-current\" />\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {deploy.deployError\n ? 'Failed — click to retry'\n : effectiveDeploymentUrl\n ? 'Stop dev server'\n : 'Start dev server'}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </span>\n </div>\n </div>\n\n {/* Source handle (right in LTR) — hosts the \"New SDD feature\" action\n button when a callback is wired, mirroring the feature-node pattern.\n Falls back to a hidden handle when no callback is provided so edge\n connections still attach to the same coordinate. */}\n {/* Source handle — invisible edge anchor for child feature edges.\n The user-facing \"+ New\" affordance is in the header (matching\n the repository node), not on this handle. */}\n <Handle\n type=\"source\"\n position={sourceHandlePos}\n isConnectable={false}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n </div>\n );\n}\n","'use client';\n\nimport { BaseEdge, getBezierPath } from '@xyflow/react';\nimport type { EdgeProps } from '@xyflow/react';\n\n/**\n * Custom React Flow edge for parent→child feature dependencies.\n * Uses bezier curves and dashed style matching repo→feature edges.\n */\nexport function DependencyEdge(props: EdgeProps) {\n const [edgePath] = getBezierPath({\n sourceX: props.sourceX,\n sourceY: props.sourceY,\n targetX: props.targetX,\n targetY: props.targetY,\n sourcePosition: props.sourcePosition,\n targetPosition: props.targetPosition,\n });\n\n return (\n <BaseEdge\n id={props.id}\n path={edgePath}\n style={{\n strokeDasharray: '5 5',\n }}\n />\n );\n}\n","'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { ReactFlow, Background, BackgroundVariant, Panel } from '@xyflow/react';\nimport type { Connection, Edge, NodeChange, OnMoveEnd, Viewport } from '@xyflow/react';\nimport { Plus } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/button';\nimport { EmptyState } from '@/components/common/empty-state';\nimport { FeatureNode } from '@/components/common/feature-node';\nimport type { FeatureNodeType, FeatureNodeData } from '@/components/common/feature-node';\nimport { RepositoryNode } from '@/components/common/repository-node';\nimport type { RepositoryNodeType, RepositoryNodeData } from '@/components/common/repository-node';\nimport { ApplicationNode } from '@/components/common/application-node/application-node';\nimport type { ApplicationNodeType } from '@/components/common/application-node/application-node-config';\nimport { DependencyEdge } from './dependency-edge';\n\nexport type CanvasNodeType = FeatureNodeType | RepositoryNodeType | ApplicationNodeType;\n\nexport interface FeaturesCanvasProps {\n nodes: CanvasNodeType[];\n edges: Edge[];\n selectedFeatureId?: string | null;\n selectedRepository?: { id: string | null; path: string | null };\n defaultViewport?: Viewport;\n onNodesChange?: (changes: NodeChange<CanvasNodeType>[]) => void;\n onAddFeature?: () => void;\n onNodeClick?: (event: React.MouseEvent, node: CanvasNodeType) => void;\n onPaneClick?: (event: React.MouseEvent) => void;\n onConnect?: (connection: Connection) => void;\n onCanvasDrag?: () => void;\n onMoveEnd?: OnMoveEnd;\n toolbar?: React.ReactNode;\n /** Show the toolbar even when the canvas is empty (e.g. empty workspace). Defaults to true. */\n showToolbarOnEmpty?: boolean;\n emptyState?: React.ReactNode;\n}\n\nconst FALLBACK_VIEWPORT: Viewport = { x: 30, y: 30, zoom: 0.85 };\n\nexport function FeaturesCanvas({\n nodes,\n edges,\n selectedFeatureId,\n selectedRepository,\n defaultViewport,\n onNodesChange,\n onAddFeature,\n onConnect,\n onNodeClick,\n onPaneClick,\n onCanvasDrag,\n onMoveEnd,\n toolbar,\n showToolbarOnEmpty = true,\n emptyState,\n}: FeaturesCanvasProps) {\n const { t } = useTranslation('web');\n const nodeTypes = useMemo(\n () => ({\n featureNode: FeatureNode,\n repositoryNode: RepositoryNode,\n applicationNode: ApplicationNode,\n }),\n []\n );\n\n const edgeTypes = useMemo(\n () => ({\n dependencyEdge: DependencyEdge,\n }),\n []\n );\n\n // Callbacks and showHandles are already injected into node.data by deriveGraph.\n // Apply selectedFeatureId and selectedRepository highlighting here.\n const enrichedNodes = useMemo(() => {\n const hasFeatureSel = selectedFeatureId != null;\n const hasRepoSel =\n selectedRepository != null &&\n (selectedRepository.id != null || selectedRepository.path != null);\n if (!hasFeatureSel && !hasRepoSel) return nodes;\n return nodes.map((node) => {\n if (\n hasFeatureSel &&\n node.type === 'featureNode' &&\n (node.data as FeatureNodeData).featureId === selectedFeatureId\n ) {\n return { ...node, selected: true };\n }\n if (hasRepoSel && node.type === 'repositoryNode') {\n const rd = node.data as RepositoryNodeData;\n const matchById =\n selectedRepository!.id != null &&\n (node.id === selectedRepository!.id || rd.id === selectedRepository!.id);\n const matchByPath =\n selectedRepository!.path != null && rd.repositoryPath === selectedRepository!.path;\n if (matchById || matchByPath) return { ...node, selected: true };\n }\n return node;\n }) as CanvasNodeType[];\n }, [nodes, selectedFeatureId, selectedRepository]);\n\n const isEmpty = nodes.length === 0;\n\n // Track empty→populated transition for exit animation.\n // When isEmpty flips from true to false, keep the overlay mounted\n // and fade it out before removing it from the DOM.\n const [showOverlay, setShowOverlay] = useState(isEmpty);\n const [overlayExiting, setOverlayExiting] = useState(false);\n const prevEmptyRef = useRef(isEmpty);\n\n useEffect(() => {\n if (prevEmptyRef.current && !isEmpty) {\n // Was empty, now populated — start exit animation\n setOverlayExiting(true);\n const timer = setTimeout(() => {\n setShowOverlay(false);\n setOverlayExiting(false);\n }, 300);\n prevEmptyRef.current = isEmpty;\n return () => clearTimeout(timer);\n }\n if (!prevEmptyRef.current && isEmpty) {\n // Was populated, now empty — show overlay immediately\n setShowOverlay(true);\n }\n prevEmptyRef.current = isEmpty;\n }, [isEmpty]);\n\n const fallbackEmptyState =\n isEmpty && !emptyState ? (\n <EmptyState\n title={t('canvas.noFeatures')}\n description={t('canvas.noFeaturesDescription')}\n action={\n <Button onClick={onAddFeature}>\n <Plus className=\"me-2 h-4 w-4\" />\n {t('canvas.newFeature')}\n </Button>\n }\n />\n ) : null;\n\n const overlayContent = emptyState ?? fallbackEmptyState;\n\n return (\n <div\n data-testid={isEmpty ? 'features-canvas-empty' : 'features-canvas'}\n data-no-drawer-close\n className=\"dark:bg-background pointer-events-auto relative h-full w-full bg-[#f6f7f8]\"\n >\n <ReactFlow\n nodes={enrichedNodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n onConnect={onConnect}\n onNodesChange={onNodesChange}\n onNodeClick={onNodeClick}\n onPaneClick={onPaneClick}\n onMoveStart={onCanvasDrag}\n onMoveEnd={onMoveEnd}\n defaultViewport={defaultViewport ?? FALLBACK_VIEWPORT}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={false}\n proOptions={{ hideAttribution: true }}\n className=\"[&_.react-flow__pane]:!cursor-default\"\n >\n <Background\n variant={BackgroundVariant.Dots}\n gap={24}\n size={1}\n color=\"#b8bcc4\"\n className=\"dark:[&_circle]:!fill-white/[0.1]\"\n />\n {toolbar && !isEmpty ? (\n <Panel position=\"top-right\" className=\"!me-3 !mt-3\">\n {toolbar}\n </Panel>\n ) : null}\n </ReactFlow>\n {showOverlay && overlayContent ? (\n <div\n className={cn(\n 'pointer-events-none absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300',\n overlayExiting ? 'opacity-0' : 'animate-in fade-in opacity-100 duration-200'\n )}\n >\n <div className=\"pointer-events-auto h-full w-full\">{overlayContent}</div>\n </div>\n ) : null}\n {/* Toolbar rendered above the empty-state overlay so the workspace\n selector remains usable while an empty workspace is shown.\n Hidden when showToolbarOnEmpty is false (welcome prompt screen). */}\n {toolbar && isEmpty && showToolbarOnEmpty ? (\n <div className=\"pointer-events-auto absolute end-3 top-3 z-20\">{toolbar}</div>\n ) : null}\n </div>\n );\n}\n","'use client';\n\nimport { useCallback } from 'react';\nimport { useReactFlow } from '@xyflow/react';\nimport type { Viewport } from '@xyflow/react';\nimport { Eye, EyeOff, ZoomIn, ZoomOut, Maximize, RotateCcw } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\n\nexport interface CanvasToolbarProps {\n showArchived: boolean;\n onToggleArchived: () => void;\n onResetViewport?: () => Viewport;\n /** Optional slot rendered at the start of the toolbar (e.g. workspace selector). */\n startSlot?: React.ReactNode;\n}\n\nexport function CanvasToolbar({\n showArchived,\n onToggleArchived,\n onResetViewport,\n startSlot,\n}: CanvasToolbarProps) {\n const { t } = useTranslation('web');\n const { zoomIn, zoomOut, fitView, setViewport } = useReactFlow();\n\n const handleZoomIn = useCallback(() => {\n zoomIn({ duration: 200 });\n }, [zoomIn]);\n\n const handleZoomOut = useCallback(() => {\n zoomOut({ duration: 200 });\n }, [zoomOut]);\n\n const handleFitView = useCallback(() => {\n fitView({ duration: 400, padding: 0.3 });\n }, [fitView]);\n\n const handleReset = useCallback(() => {\n if (onResetViewport) {\n const viewport = onResetViewport();\n setViewport(viewport, { duration: 400 });\n }\n }, [onResetViewport, setViewport]);\n\n return (\n <div className=\"bg-background flex items-center gap-1 rounded-xl border px-2 py-1.5 shadow-md dark:bg-neutral-900\">\n {startSlot ? (\n <>\n {startSlot}\n <div className=\"bg-border mx-1 h-5 w-px\" />\n </>\n ) : null}\n {/* View controls */}\n <ToolbarButton\n onClick={onToggleArchived}\n title={showArchived ? t('canvas.hideArchived') : t('canvas.showArchived')}\n active={showArchived}\n label={showArchived ? t('canvas.hideArchivedLabel') : t('canvas.showArchivedLabel')}\n >\n {showArchived ? <Eye className=\"h-4 w-4\" /> : <EyeOff className=\"h-4 w-4\" />}\n </ToolbarButton>\n\n <div className=\"bg-border mx-1 h-5 w-px\" />\n\n {/* Zoom controls */}\n <ToolbarButton onClick={handleZoomOut} title={t('canvas.zoomOut')}>\n <ZoomOut className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton onClick={handleZoomIn} title={t('canvas.zoomIn')}>\n <ZoomIn className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton onClick={handleFitView} title={t('canvas.fitView')}>\n <Maximize className=\"h-4 w-4\" />\n </ToolbarButton>\n {onResetViewport ? (\n <ToolbarButton onClick={handleReset} title={t('canvas.resetView')}>\n <RotateCcw className=\"h-4 w-4\" />\n </ToolbarButton>\n ) : null}\n </div>\n );\n}\n\n// ── Internal button ──────────────────────────────────────────────────────\n\nfunction ToolbarButton({\n children,\n onClick,\n title,\n label,\n active,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n title: string;\n label?: string;\n active?: boolean;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={title}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n active ? 'text-primary bg-primary/10' : 'text-muted-foreground'\n )}\n >\n {children}\n {label ? <span>{label}</span> : null}\n </button>\n );\n}\n","'use client';\n\n/**\n * Playground prototype: client-side workspaces.\n *\n * ⚠️ PROTOTYPE BOUNDARY — DO NOT IMPORT FROM OUTSIDE THIS PROTOTYPE ⚠️\n *\n * A workspace is a named, explicit allowlist of repositories and features\n * that should appear on the canvas. The \"default\" workspace is special: it\n * always shows everything (its allowlists are ignored).\n *\n * Persistence: localStorage only. There is no backend, no domain model, no\n * use cases, and no infrastructure adapter. Mutation rules (\"default is\n * read-only\", \"default always exists\", rename validation) are enforced\n * inline rather than as domain invariants.\n *\n * This file deliberately violates Clean Architecture by holding domain\n * shape (`Workspace`), application logic (mutations + invariants), and\n * infrastructure concerns (localStorage persistence) inside a React hook.\n * It exists ONLY to validate the workspace UX on the playground branch.\n *\n * Before promoting workspaces to a real feature, replace this file with:\n * - tsp/Workspace.tsp — domain entity\n * - application/ports/output/repositories/\n * workspace.repository.interface.ts — output port\n * - application/use-cases/workspaces/\n * create-workspace.use-case.ts\n * rename-workspace.use-case.ts\n * delete-workspace.use-case.ts\n * set-workspace-members.use-case.ts\n * list-workspaces.use-case.ts\n * set-active-workspace.use-case.ts\n * - infrastructure/repositories/sqlite-workspace.repository.ts\n *\n * Then this hook becomes a thin client wrapper that calls server actions\n * backed by those use cases. Until that refactor lands, the `Workspace`\n * type defined here MUST NOT be imported from any non-prototype code.\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nconst STORAGE_KEY = 'shep:workspaces:v1';\nexport const DEFAULT_WORKSPACE_ID = 'default';\nexport const DEFAULT_WORKSPACE_NAME = 'Default';\n\nexport interface Workspace {\n id: string;\n name: string;\n /** Repository node IDs (React Flow node ids, e.g. \"repo-...\"). */\n repoIds: string[];\n /** Feature node IDs (React Flow node ids, e.g. \"feat-...\"). */\n featureIds: string[];\n}\n\ninterface WorkspacesState {\n workspaces: Workspace[];\n activeWorkspaceId: string;\n}\n\nconst INITIAL_STATE: WorkspacesState = {\n workspaces: [\n {\n id: DEFAULT_WORKSPACE_ID,\n name: DEFAULT_WORKSPACE_NAME,\n repoIds: [],\n featureIds: [],\n },\n ],\n activeWorkspaceId: DEFAULT_WORKSPACE_ID,\n};\n\nfunction loadState(): WorkspacesState {\n if (typeof window === 'undefined') return INITIAL_STATE;\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY);\n if (!raw) return INITIAL_STATE;\n const parsed = JSON.parse(raw) as Partial<WorkspacesState>;\n if (!parsed.workspaces || !Array.isArray(parsed.workspaces)) return INITIAL_STATE;\n // Make sure default workspace always exists\n const hasDefault = parsed.workspaces.some((w) => w.id === DEFAULT_WORKSPACE_ID);\n const workspaces = hasDefault\n ? parsed.workspaces\n : [INITIAL_STATE.workspaces[0]!, ...parsed.workspaces];\n return {\n workspaces,\n activeWorkspaceId: parsed.activeWorkspaceId ?? DEFAULT_WORKSPACE_ID,\n };\n } catch {\n return INITIAL_STATE;\n }\n}\n\nfunction saveState(state: WorkspacesState) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n } catch {\n // localStorage may be unavailable (private mode); ignore.\n }\n}\n\nfunction generateId(): string {\n return `ws-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nexport interface UseWorkspacesResult {\n workspaces: Workspace[];\n activeWorkspace: Workspace;\n activeWorkspaceId: string;\n isDefaultActive: boolean;\n setActiveWorkspace: (id: string) => void;\n createWorkspace: (name: string) => Workspace;\n renameWorkspace: (id: string, name: string) => void;\n deleteWorkspace: (id: string) => void;\n setWorkspaceMembers: (id: string, members: { repoIds: string[]; featureIds: string[] }) => void;\n toggleRepoInActive: (repoId: string) => void;\n toggleFeatureInActive: (featureId: string) => void;\n /**\n * Append node IDs to the active workspace's allowlists. No-op when the\n * default workspace is active (it shows everything anyway). Idempotent —\n * IDs already present are skipped.\n */\n addToActiveWorkspace: (members: { repoIds?: string[]; featureIds?: string[] }) => void;\n}\n\nexport function useWorkspaces(): UseWorkspacesResult {\n const [state, setState] = useState<WorkspacesState>(INITIAL_STATE);\n\n // Hydrate from localStorage on mount (client-only).\n useEffect(() => {\n setState(loadState());\n }, []);\n\n // Persist whenever state changes (after hydration).\n useEffect(() => {\n saveState(state);\n }, [state]);\n\n const setActiveWorkspace = useCallback((id: string) => {\n setState((prev) => {\n if (!prev.workspaces.some((w) => w.id === id)) return prev;\n return { ...prev, activeWorkspaceId: id };\n });\n }, []);\n\n const createWorkspace = useCallback((name: string): Workspace => {\n const trimmed = name.trim() || 'Untitled workspace';\n const next: Workspace = {\n id: generateId(),\n name: trimmed,\n repoIds: [],\n featureIds: [],\n };\n setState((prev) => ({\n workspaces: [...prev.workspaces, next],\n activeWorkspaceId: next.id,\n }));\n return next;\n }, []);\n\n const renameWorkspace = useCallback((id: string, name: string) => {\n if (id === DEFAULT_WORKSPACE_ID) return;\n const trimmed = name.trim();\n if (!trimmed) return;\n setState((prev) => ({\n ...prev,\n workspaces: prev.workspaces.map((w) => (w.id === id ? { ...w, name: trimmed } : w)),\n }));\n }, []);\n\n const deleteWorkspace = useCallback((id: string) => {\n if (id === DEFAULT_WORKSPACE_ID) return;\n setState((prev) => {\n const workspaces = prev.workspaces.filter((w) => w.id !== id);\n const activeWorkspaceId =\n prev.activeWorkspaceId === id ? DEFAULT_WORKSPACE_ID : prev.activeWorkspaceId;\n return { workspaces, activeWorkspaceId };\n });\n }, []);\n\n const setWorkspaceMembers = useCallback(\n (id: string, members: { repoIds: string[]; featureIds: string[] }) => {\n if (id === DEFAULT_WORKSPACE_ID) return;\n setState((prev) => ({\n ...prev,\n workspaces: prev.workspaces.map((w) =>\n w.id === id\n ? { ...w, repoIds: [...members.repoIds], featureIds: [...members.featureIds] }\n : w\n ),\n }));\n },\n []\n );\n\n const toggleMember = useCallback((kind: 'repo' | 'feature', nodeId: string) => {\n setState((prev) => {\n if (prev.activeWorkspaceId === DEFAULT_WORKSPACE_ID) return prev;\n return {\n ...prev,\n workspaces: prev.workspaces.map((w) => {\n if (w.id !== prev.activeWorkspaceId) return w;\n const list = kind === 'repo' ? w.repoIds : w.featureIds;\n const nextList = list.includes(nodeId)\n ? list.filter((x) => x !== nodeId)\n : [...list, nodeId];\n return kind === 'repo' ? { ...w, repoIds: nextList } : { ...w, featureIds: nextList };\n }),\n };\n });\n }, []);\n\n const toggleRepoInActive = useCallback(\n (repoId: string) => toggleMember('repo', repoId),\n [toggleMember]\n );\n const toggleFeatureInActive = useCallback(\n (featureId: string) => toggleMember('feature', featureId),\n [toggleMember]\n );\n\n const addToActiveWorkspace = useCallback(\n (members: { repoIds?: string[]; featureIds?: string[] }) => {\n const incomingRepos = members.repoIds ?? [];\n const incomingFeatures = members.featureIds ?? [];\n if (incomingRepos.length === 0 && incomingFeatures.length === 0) return;\n\n setState((prev) => {\n if (prev.activeWorkspaceId === DEFAULT_WORKSPACE_ID) return prev;\n return {\n ...prev,\n workspaces: prev.workspaces.map((w) => {\n if (w.id !== prev.activeWorkspaceId) return w;\n const repoSet = new Set(w.repoIds);\n for (const id of incomingRepos) repoSet.add(id);\n const featureSet = new Set(w.featureIds);\n for (const id of incomingFeatures) featureSet.add(id);\n // Bail out if nothing actually changed — keeps referential equality\n // so downstream effects don't re-fire.\n if (repoSet.size === w.repoIds.length && featureSet.size === w.featureIds.length) {\n return w;\n }\n return {\n ...w,\n repoIds: Array.from(repoSet),\n featureIds: Array.from(featureSet),\n };\n }),\n };\n });\n },\n []\n );\n\n const activeWorkspace =\n state.workspaces.find((w) => w.id === state.activeWorkspaceId) ?? state.workspaces[0]!;\n\n return {\n workspaces: state.workspaces,\n activeWorkspace,\n activeWorkspaceId: state.activeWorkspaceId,\n isDefaultActive: state.activeWorkspaceId === DEFAULT_WORKSPACE_ID,\n setActiveWorkspace,\n createWorkspace,\n renameWorkspace,\n deleteWorkspace,\n setWorkspaceMembers,\n toggleRepoInActive,\n toggleFeatureInActive,\n addToActiveWorkspace,\n };\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { Layers, Check, Plus, Pencil, Trash2, SlidersHorizontal } from 'lucide-react';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport { cn } from '@/lib/utils';\nimport {\n DEFAULT_WORKSPACE_ID,\n type UseWorkspacesResult,\n type Workspace,\n} from '@/hooks/use-workspaces';\n\nexport interface WorkspaceSelectorProps {\n workspaces: UseWorkspacesResult['workspaces'];\n activeWorkspace: Workspace;\n onSelect: (id: string) => void;\n onRequestCreate: () => void;\n onRequestRename: () => void;\n /** Request deletion of a specific workspace by id. */\n onRequestDelete: (id: string) => void;\n onManage: () => void;\n}\n\nexport function WorkspaceSelector({\n workspaces,\n activeWorkspace,\n onSelect,\n onRequestCreate,\n onRequestRename,\n onRequestDelete,\n onManage,\n}: WorkspaceSelectorProps) {\n const [open, setOpen] = useState(false);\n const isDefault = activeWorkspace.id === DEFAULT_WORKSPACE_ID;\n\n return (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-testid=\"workspace-selector-trigger\"\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n isDefault ? 'text-muted-foreground' : 'text-primary bg-primary/10'\n )}\n title=\"Workspace\"\n >\n <Layers className=\"h-4 w-4\" />\n <span className=\"max-w-[120px] truncate\">{activeWorkspace.name}</span>\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"min-w-[220px]\">\n <DropdownMenuLabel>Workspaces</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {workspaces.map((w) => {\n const active = w.id === activeWorkspace.id;\n const canDelete = w.id !== DEFAULT_WORKSPACE_ID;\n return (\n <DropdownMenuItem\n key={w.id}\n onSelect={() => onSelect(w.id)}\n className=\"group/ws-row flex items-center justify-between gap-2\"\n >\n <span className=\"truncate\">{w.name}</span>\n <span className=\"flex shrink-0 items-center gap-1\">\n {active ? <Check className=\"h-3.5 w-3.5\" /> : null}\n {canDelete ? (\n <button\n type=\"button\"\n aria-label={`Delete workspace ${w.name}`}\n title={`Delete workspace ${w.name}`}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n setOpen(false);\n onRequestDelete(w.id);\n }}\n className=\"text-muted-foreground hover:bg-destructive/10 hover:text-destructive rounded p-0.5 opacity-0 transition-opacity group-hover/ws-row:opacity-100 focus-visible:opacity-100\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n ) : null}\n </span>\n </DropdownMenuItem>\n );\n })}\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={onRequestCreate}>\n <Plus className=\"mr-2 h-3.5 w-3.5\" />\n New workspace…\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onManage} disabled={isDefault}>\n <SlidersHorizontal className=\"mr-2 h-3.5 w-3.5\" />\n Manage items…\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onRequestRename} disabled={isDefault}>\n <Pencil className=\"mr-2 h-3.5 w-3.5\" />\n Rename\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { GitBranch, Sparkles } from 'lucide-react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Button } from '@/components/ui/button';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { Workspace } from '@/hooks/use-workspaces';\n\nexport interface ManageWorkspaceDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n workspace: Workspace;\n /** All nodes currently on the canvas (unfiltered). */\n allNodes: CanvasNodeType[];\n onSave: (members: { repoIds: string[]; featureIds: string[] }) => void;\n}\n\ninterface RepoEntry {\n nodeId: string;\n name: string;\n features: { nodeId: string; name: string }[];\n}\n\nexport function ManageWorkspaceDialog({\n open,\n onOpenChange,\n workspace,\n allNodes,\n onSave,\n}: ManageWorkspaceDialogProps) {\n const [selectedRepoIds, setSelectedRepoIds] = useState<Set<string>>(new Set());\n const [selectedFeatureIds, setSelectedFeatureIds] = useState<Set<string>>(new Set());\n\n // Reset selection state whenever the dialog opens for a (possibly different) workspace.\n useEffect(() => {\n if (open) {\n setSelectedRepoIds(new Set(workspace.repoIds));\n setSelectedFeatureIds(new Set(workspace.featureIds));\n }\n }, [open, workspace]);\n\n // Group features under their parent repo by repositoryPath.\n const repoEntries = useMemo<RepoEntry[]>(() => {\n const repos: RepoEntry[] = [];\n const byPath = new Map<string, RepoEntry>();\n\n for (const node of allNodes) {\n if (node.type !== 'repositoryNode') continue;\n const data = node.data as RepositoryNodeData;\n const path = data.repositoryPath ?? '';\n const entry: RepoEntry = {\n nodeId: node.id,\n name: data.name ?? path.split('/').filter(Boolean).pop() ?? path,\n features: [],\n };\n repos.push(entry);\n byPath.set(path, entry);\n }\n\n for (const node of allNodes) {\n if (node.type !== 'featureNode') continue;\n const data = node.data as FeatureNodeData;\n const repo = byPath.get(data.repositoryPath ?? '');\n if (repo) {\n repo.features.push({ nodeId: node.id, name: data.name });\n }\n }\n\n return repos;\n }, [allNodes]);\n\n const toggleRepo = (id: string) => {\n setSelectedRepoIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const toggleFeature = (id: string) => {\n setSelectedFeatureIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const handleSave = () => {\n onSave({\n repoIds: Array.from(selectedRepoIds),\n featureIds: Array.from(selectedFeatureIds),\n });\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[80vh] max-w-lg overflow-hidden\">\n <DialogHeader>\n <DialogTitle>Manage workspace: {workspace.name}</DialogTitle>\n <DialogDescription>\n Select the repositories and features that should appear on this workspace's canvas.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"-mx-6 max-h-[50vh] overflow-y-auto px-6\">\n {repoEntries.length === 0 ? (\n <p className=\"text-muted-foreground py-8 text-center text-sm\">\n No repositories on the canvas yet.\n </p>\n ) : (\n <ul className=\"space-y-3 py-2\">\n {repoEntries.map((repo) => (\n <li key={repo.nodeId}>\n <label className=\"hover:bg-accent/30 flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5\">\n <Checkbox\n checked={selectedRepoIds.has(repo.nodeId)}\n onCheckedChange={() => toggleRepo(repo.nodeId)}\n />\n <GitBranch className=\"text-muted-foreground h-4 w-4\" />\n <span className=\"text-sm font-medium\">{repo.name}</span>\n </label>\n {repo.features.length > 0 ? (\n <ul className=\"mt-1 ml-7 space-y-0.5\">\n {repo.features.map((feat) => (\n <li key={feat.nodeId}>\n <label className=\"hover:bg-accent/30 flex cursor-pointer items-center gap-2 rounded-md px-2 py-1\">\n <Checkbox\n checked={selectedFeatureIds.has(feat.nodeId)}\n onCheckedChange={() => toggleFeature(feat.nodeId)}\n />\n <Sparkles className=\"text-muted-foreground h-3.5 w-3.5\" />\n <span className=\"text-muted-foreground text-xs\">{feat.name}</span>\n </label>\n </li>\n ))}\n </ul>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={handleSave}>Save</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Input } from '@/components/ui/input';\nimport { Button } from '@/components/ui/button';\n\nexport interface WorkspaceNameDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description?: string;\n initialValue?: string;\n confirmLabel: string;\n onConfirm: (name: string) => void;\n}\n\nexport function WorkspaceNameDialog({\n open,\n onOpenChange,\n title,\n description,\n initialValue = '',\n confirmLabel,\n onConfirm,\n}: WorkspaceNameDialogProps) {\n const [value, setValue] = useState(initialValue);\n\n useEffect(() => {\n if (open) setValue(initialValue);\n }, [open, initialValue]);\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const trimmed = value.trim();\n if (!trimmed) return;\n onConfirm(trimmed);\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-sm\">\n <form onSubmit={handleSubmit}>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n <div className=\"py-4\">\n <Input\n autoFocus\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Workspace name\"\n data-testid=\"workspace-name-input\"\n />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={!value.trim()}>\n {confirmLabel}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n","'use client';\n\nimport { usePathname } from 'next/navigation';\n\n/**\n * Extracts the selected feature ID from the current URL path.\n * Returns `null` when no feature drawer route is active.\n */\nexport function useSelectedFeatureId(): string | null {\n const pathname = usePathname();\n const match = pathname.match(/^\\/feature\\/([^/]+)/);\n return match?.[1] ?? null;\n}\n","'use client';\n\nimport { usePathname, useSearchParams } from 'next/navigation';\nimport { URL_PARAMS } from '@/lib/url-params';\n\n/**\n * Extracts the selected repository context from the current URL.\n * Returns `{ id, path }` — either or both may be set depending on the route.\n *\n * Matches:\n * - `/repository/<id>` → id is set\n * - `/create?repo=<path>` → path is set\n */\nexport function useSelectedRepository(): { id: string | null; path: string | null } {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const repoIdMatch = pathname.match(/^\\/repository\\/([^/]+)/);\n const id = repoIdMatch?.[1] ?? null;\n\n const isCreate = pathname.startsWith('/create');\n const path = isCreate ? searchParams.get(URL_PARAMS.repo) : null;\n\n return { id, path };\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport type { Viewport } from '@xyflow/react';\n\nexport type { Viewport } from '@xyflow/react';\n\nexport const STORAGE_KEY = 'shep-canvas-viewport';\nexport const DEBOUNCE_MS = 500;\n\nexport const DEFAULT_VIEWPORT: Viewport = { x: 30, y: 30, zoom: 0.85 };\n\nexport interface UseViewportPersistenceResult {\n defaultViewport: Viewport;\n onMoveEnd: (viewport: Viewport) => void;\n resetViewport: () => Viewport;\n}\n\nfunction isValidViewport(value: unknown): value is Viewport {\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n const v = value as Record<string, unknown>;\n return (\n typeof v.x === 'number' &&\n typeof v.y === 'number' &&\n typeof v.zoom === 'number' &&\n Number.isFinite(v.x) &&\n Number.isFinite(v.y) &&\n Number.isFinite(v.zoom) &&\n v.zoom > 0\n );\n}\n\nfunction readViewport(): Viewport {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (raw == null) return DEFAULT_VIEWPORT;\n const parsed: unknown = JSON.parse(raw);\n return isValidViewport(parsed) ? parsed : DEFAULT_VIEWPORT;\n } catch {\n return DEFAULT_VIEWPORT;\n }\n}\n\nexport function useViewportPersistence(): UseViewportPersistenceResult {\n const defaultViewport = useRef<Viewport>(readViewport()).current;\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current != null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const onMoveEnd = useCallback((viewport: Viewport) => {\n if (timerRef.current != null) {\n clearTimeout(timerRef.current);\n }\n timerRef.current = setTimeout(() => {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(viewport));\n } catch {\n // Silently ignore localStorage errors (quota exceeded, private browsing, etc.)\n }\n }, DEBOUNCE_MS);\n }, []);\n\n const resetViewport = useCallback((): Viewport => {\n try {\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // Silently ignore localStorage errors\n }\n return DEFAULT_VIEWPORT;\n }, []);\n\n return { defaultViewport, onMoveEnd, resetViewport };\n}\n","/* __next_internal_action_entry_do_not_use__ [{\"002230a65a9a52766f2fac7b9bafe2f0a0ab4ff5f5\":\"isAgentSetupComplete\"},\"src/presentation/web/app/actions/agent-setup-flag.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"002230a65a9a52766f2fac7b9bafe2f0a0ab4ff5f5\",callServer,void 0,findSourceMapURL,\"isAgentSetupComplete\");export{$$RSC_SERVER_ACTION_0 as isAgentSetupComplete};","/* __next_internal_action_entry_do_not_use__ [{\"003eb1909cd10ed1e04526145e4a21282e819a745e\":\"checkAgentAuth\"},\"src/presentation/web/app/actions/check-agent-auth.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"003eb1909cd10ed1e04526145e4a21282e819a745e\",callServer,void 0,findSourceMapURL,\"checkAgentAuth\");export{$$RSC_SERVER_ACTION_0 as checkAgentAuth};","'use client';\n\nimport type { ReactNode } from 'react';\nimport { ReactFlowProvider } from '@xyflow/react';\nimport type { Edge } from '@xyflow/react';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport { SessionsProvider } from '@/hooks/sessions-provider';\nimport { ControlCenterInner } from './control-center-inner';\n\nexport interface ControlCenterProps {\n initialNodes: CanvasNodeType[];\n initialEdges: Edge[];\n /** Drawer content rendered by the @drawer parallel route slot. */\n drawer?: ReactNode;\n}\n\nexport function ControlCenter({ initialNodes, initialEdges, drawer }: ControlCenterProps) {\n return (\n <div data-testid=\"control-center\" className=\"h-full w-full\">\n <SessionsProvider>\n <ReactFlowProvider>\n <ControlCenterInner initialNodes={initialNodes} initialEdges={initialEdges} />\n </ReactFlowProvider>\n </SessionsProvider>\n <div key=\"drawer\">{drawer}</div>\n </div>\n );\n}\n","/* __next_internal_action_entry_do_not_use__ [{\"00f312436a846d36665ad6519b2a873685e7baa13f\":\"checkToolStatus\"},\"src/presentation/web/app/actions/check-tool-status.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"00f312436a846d36665ad6519b2a873685e7baa13f\",callServer,void 0,findSourceMapURL,\"checkToolStatus\");export{$$RSC_SERVER_ACTION_0 as checkToolStatus};","'use client';\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport { useRouter } from 'next/navigation';\nimport {\n Github,\n Plus,\n Code2,\n Terminal,\n FolderOpen,\n Trash2,\n Play,\n Square,\n GitBranch,\n GitCommitHorizontal,\n ArrowDown,\n User,\n RotateCcw,\n MessageSquare,\n} from 'lucide-react';\nimport { Trans, useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport { buildCreateUrl } from '@/lib/url-params';\nimport { ActionButton } from '@/components/common/action-button';\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Label } from '@/components/ui/label';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\nimport { useDeployAction } from '@/hooks/use-deploy-action';\nimport { useFeatureFlags } from '@/hooks/feature-flags-context';\nimport type { RepositoryNodeData } from './repository-node-config';\nimport { useRepositoryActions } from './use-repository-actions';\nimport { ChatDotIndicator } from '@/components/features/chat/ChatDotIndicator';\nimport { useTurnStatus } from '@/hooks/turn-statuses-provider';\nimport {\n FeatureSessionsDropdown,\n type SessionSummary,\n} from '@/components/common/feature-node/feature-sessions-dropdown';\n\nexport function RepositoryNode({\n data,\n selected,\n}: {\n data: RepositoryNodeData;\n selected?: boolean;\n [key: string]: unknown;\n}) {\n const { t, i18n } = useTranslation('web');\n const router = useRouter();\n const isRtl = i18n.dir() === 'rtl';\n const targetHandlePos = isRtl ? Position.Right : Position.Left;\n const sourceHandlePos = isRtl ? Position.Left : Position.Right;\n const featureFlags = useFeatureFlags();\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [deleteFromDisk, setDeleteFromDisk] = useState(false);\n useEffect(() => {\n if (confirmOpen) setDeleteFromDisk(false);\n }, [confirmOpen]);\n const repoScopeId = data.id ? `repo-${data.id}` : `repo-${data.name}`;\n const chatTurnStatus = useTurnStatus(repoScopeId);\n const actions = useRepositoryActions(\n data.repositoryPath ? { repositoryId: data.id, repositoryPath: data.repositoryPath } : null\n );\n const deployAction = useDeployAction(\n data.repositoryPath\n ? {\n targetId: data.repositoryPath,\n targetType: 'repository',\n repositoryPath: data.repositoryPath,\n }\n : null\n );\n const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';\n\n const handleCreateFromSession = useCallback(\n (session: SessionSummary, sessionFilePath: string) => {\n if (!data.repositoryPath) return;\n const preview = session.preview ? session.preview.slice(0, 200) : 'Unknown conversation';\n const prompt = [\n `Continue work from a previous agent session.`,\n ``,\n `## Session Context`,\n `- Session ID: ${session.id}`,\n `- Messages: ${session.messageCount}`,\n session.lastMessageAt ? `- Last active: ${session.lastMessageAt}` : '',\n `- Conversation file: ${sessionFilePath}`,\n ``,\n `## Session Preview`,\n `> ${preview}`,\n ``,\n `## Instructions`,\n `1. Read the full conversation history from the file above`,\n `2. Analyze the current state of the repository — what was done, what remains`,\n `3. Create or update spec files to accurately reflect the current state and remaining work`,\n `4. Continue implementing any unfinished work from the conversation`,\n ]\n .filter(Boolean)\n .join('\\n');\n\n router.push(buildCreateUrl({ repo: data.repositoryPath, prompt }));\n },\n [data.repositoryPath, router]\n );\n\n return (\n <div\n className={cn('group relative', data.onDelete && data.id && 'ps-10')}\n style={{ direction: isRtl ? 'rtl' : 'ltr' }}\n >\n {data.showHandles ? (\n <Handle\n type=\"target\"\n position={targetHandlePos}\n isConnectable={false}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n ) : null}\n\n {/* Delete button — visible on hover, positioned to the left */}\n {data.onDelete && data.id ? (\n <>\n <div className=\"absolute -start-3 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100\">\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n aria-label={t('repositoryNode.removeRepository')}\n data-testid=\"repository-node-delete-button\"\n onClick={(e) => {\n e.stopPropagation();\n setConfirmOpen(true);\n }}\n className=\"bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.removeRepository')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n\n <Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>\n <DialogContent className=\"max-w-sm\">\n <DialogHeader>\n <DialogTitle>{t('repositoryNode.removeConfirmTitle')}</DialogTitle>\n <DialogDescription>\n <Trans\n t={t}\n i18nKey=\"repositoryNode.removeConfirmDescription\"\n values={{ name: data.name }}\n components={{ strong: <strong /> }}\n />{' '}\n {deleteFromDisk\n ? t('repositoryNode.removeConfirmDescriptionDeleteFiles')\n : t('repositoryNode.removeConfirmDescriptionKeepFiles')}\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"repository-delete-from-disk\"\n checked={deleteFromDisk}\n onCheckedChange={(checked) => setDeleteFromDisk(checked === true)}\n data-testid=\"repository-node-delete-from-disk-checkbox\"\n aria-label={t('repositoryNode.deleteFromDiskLabel')}\n />\n <Label\n htmlFor=\"repository-delete-from-disk\"\n className=\"cursor-pointer text-sm font-normal\"\n >\n {t('repositoryNode.deleteFromDiskLabel')}\n </Label>\n </div>\n <DialogFooter className=\"grid grid-cols-2 gap-2 sm:flex-none\">\n <DialogClose asChild>\n <Button variant=\"outline\">{t('repositoryNode.cancel')}</Button>\n </DialogClose>\n <Button\n variant=\"destructive\"\n data-testid=\"repository-node-delete-confirm-button\"\n onClick={() => {\n setConfirmOpen(false);\n data.onDelete?.(data.id!, { deleteFromDisk });\n }}\n >\n {t('repositoryNode.remove')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n ) : null}\n\n <div\n role=\"button\"\n tabIndex={0}\n data-testid=\"repository-node-card\"\n data-repo-name={data.name}\n onClick={(e) => {\n e.stopPropagation();\n data.onClick?.();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n data.onClick?.();\n }\n }}\n className={cn(\n 'nodrag bg-card flex w-[26rem] cursor-pointer flex-col overflow-hidden rounded-xl border shadow-sm transition-[border-color,box-shadow] duration-200 dark:bg-neutral-800/80',\n selected && 'border-blue-400 dark:border-amber-500/60'\n )}\n >\n {/* Row 1: Repository name + action buttons */}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Github className=\"text-muted-foreground h-5 w-5 shrink-0\" />\n <span data-testid=\"repository-node-name\" className=\"min-w-0 truncate text-sm font-medium\">\n {data.name}\n </span>\n\n <div\n className={cn(\n 'flex shrink-0 items-center gap-2',\n (data.repositoryPath ?? data.onAdd) && 'ms-auto'\n )}\n onClick={(e) => e.stopPropagation()}\n >\n {data.repositoryPath ? (\n <>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex items-center\">\n <ActionButton\n label={t('repositoryNode.openInIde')}\n onClick={actions.openInIde}\n loading={actions.ideLoading}\n error={!!actions.ideError}\n icon={Code2}\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.openInIde')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex items-center\">\n <ActionButton\n label={t('repositoryNode.openInShell')}\n onClick={actions.openInShell}\n loading={actions.shellLoading}\n error={!!actions.shellError}\n icon={Terminal}\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.openInShell')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex items-center\">\n <ActionButton\n label={t('repositoryNode.openFolder')}\n onClick={actions.openFolder}\n loading={actions.folderLoading}\n error={!!actions.folderError}\n icon={FolderOpen}\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.openFolder')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={t('repositoryNode.chatWithAgent')}\n onClick={(e) => {\n e.stopPropagation();\n if (data.id)\n router.push(\n `/repository/${data.id}/chat` as Parameters<typeof router.push>[0]\n );\n }}\n className=\"nodrag relative cursor-pointer text-violet-500 hover:text-violet-600 dark:text-violet-400 dark:hover:text-violet-300\"\n >\n <MessageSquare className=\"h-3 w-3\" />\n <ChatDotIndicator status={chatTurnStatus} />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.chatWithAgent')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <FeatureSessionsDropdown\n repositoryPath={data.repositoryPath}\n includeWorktrees\n onCreateFromSession={handleCreateFromSession}\n />\n </>\n ) : null}\n\n {data.onAdd ? <div className=\"ms-1.5\" /> : null}\n {data.onAdd ? (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n aria-label={t('repositoryNode.newFeature')}\n data-testid=\"repository-node-add-button\"\n onClick={(e) => {\n e.stopPropagation();\n data.onAdd?.();\n }}\n className={cn(\n 'flex h-6 shrink-0 cursor-pointer items-center gap-0.5 rounded bg-blue-500 px-1.5 text-[11px] font-bold text-white transition-colors hover:bg-blue-600 dark:bg-amber-500 dark:hover:bg-amber-400',\n data.pulseAdd && 'animate-pulse-cta'\n )}\n >\n <Plus className=\"h-3 w-3\" />\n <span className=\"translate-y-px\">{t('repositoryNode.new')}</span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">{t('repositoryNode.newFeature')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n ) : null}\n </div>\n </div>\n\n {/* Row 2 & 3: Git info or placeholder */}\n {data.branch ? (\n <>\n {/* Row 2: Branch + behind status */}\n <div\n data-testid=\"repository-node-git-info\"\n className=\"text-muted-foreground border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex items-center gap-3 text-xs\">\n <span\n className=\"flex items-center gap-1 truncate\"\n data-testid=\"repository-node-branch\"\n >\n <GitBranch className=\"h-3 w-3 shrink-0\" />\n <span className=\"truncate\">{data.branch}</span>\n </span>\n {data.behindCount != null && data.behindCount > 0 ? (\n <span\n className=\"flex shrink-0 items-center gap-1 whitespace-nowrap text-amber-500\"\n data-testid=\"repository-node-behind\"\n >\n <ArrowDown className=\"h-3 w-3 shrink-0\" />\n {t('repositoryNode.behind', { count: data.behindCount })}\n </span>\n ) : null}\n </div>\n </div>\n {/* Row 3: Latest commit */}\n {data.commitMessage ? (\n <div\n data-testid=\"repository-node-commit-info\"\n className=\"text-muted-foreground border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex items-center gap-2 text-xs\">\n <GitCommitHorizontal className=\"h-3 w-3 shrink-0\" />\n <span className=\"min-w-0 truncate\" data-testid=\"repository-node-commit-message\">\n {data.commitMessage}\n </span>\n {data.committer ? (\n <span\n className=\"text-muted-foreground/70 ms-auto flex shrink-0 items-center gap-1\"\n data-testid=\"repository-node-committer\"\n >\n <User className=\"h-3 w-3 shrink-0\" />\n <span>{data.committer}</span>\n </span>\n ) : null}\n </div>\n </div>\n ) : null}\n </>\n ) : data.gitInfoStatus === 'not-a-repo' ? (\n /* Not a git repo — two rows for consistency with loading/ready states */\n <>\n <div\n data-testid=\"repository-node-not-repo\"\n className=\"text-muted-foreground border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex items-center gap-2 text-xs\">\n <FolderOpen className=\"h-3 w-3 shrink-0\" />\n <span className=\"min-w-0 truncate opacity-60\">\n {data.repositoryPath ?? 'Unknown path'}\n </span>\n </div>\n </div>\n <div className=\"text-muted-foreground border-border/50 border-t px-4 py-2\">\n <div className=\"flex items-center gap-2 text-xs opacity-40\">\n <GitBranch className=\"h-3 w-3 shrink-0\" />\n <span>{t('repositoryNode.notAGitRepository')}</span>\n </div>\n </div>\n </>\n ) : data.gitInfoStatus !== 'ready' ? (\n /* Loading — show skeleton placeholders for both rows */\n <>\n <div\n data-testid=\"repository-node-git-loading\"\n className=\"border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex h-4 items-center gap-2 text-xs\">\n <GitBranch className=\"text-muted-foreground h-3 w-3 shrink-0\" />\n <span className=\"bg-muted h-3 w-20 animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"border-border/50 border-t px-4 py-2\">\n <div className=\"flex h-4 items-center gap-2 text-xs\">\n <GitCommitHorizontal className=\"text-muted-foreground h-3 w-3 shrink-0\" />\n <span className=\"bg-muted h-3 w-36 animate-pulse rounded\" />\n </div>\n </div>\n </>\n ) : null}\n\n {/* Row 4: Local dev server — always visible when envDeploy flag is on */}\n {featureFlags.envDeploy && data.repositoryPath ? (\n <div\n data-testid=\"repository-node-dev-preview\"\n className=\"border-border/50 border-t px-4 py-2\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center gap-2 text-xs\">\n {deployAction.deployError ? (\n <span className=\"truncate text-xs text-red-500\">{deployAction.deployError}</span>\n ) : isDeploymentActive ? (\n <>\n <span className=\"me-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500\" />\n {deployAction.url ? (\n <a\n href={deployAction.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"truncate text-green-700 hover:underline dark:text-green-400\"\n >\n {deployAction.url}\n </a>\n ) : (\n <span className=\"text-muted-foreground\">{t('repositoryNode.starting')}</span>\n )}\n </>\n ) : (\n <span className=\"text-muted-foreground inline-flex items-baseline gap-2\">\n <span>{t('repositoryNode.run')}</span>\n <span className=\"text-muted-foreground/50 text-[10px]\">\n {t('repositoryNode.startLocalEnvironment')}\n </span>\n </span>\n )}\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n className={cn(\n 'ms-auto flex items-center',\n !isDeploymentActive &&\n !deployAction.deployError &&\n '[&_button]:text-green-600 [&_button]:hover:text-green-700 dark:[&_button]:text-green-400 dark:[&_button]:hover:text-green-300'\n )}\n >\n <ActionButton\n label={\n deployAction.deployError\n ? t('repositoryNode.retry')\n : isDeploymentActive\n ? t('repositoryNode.stopDevServer')\n : t('repositoryNode.startDevServer')\n }\n onClick={isDeploymentActive ? deployAction.stop : deployAction.deploy}\n loading={deployAction.deployLoading || deployAction.stopLoading}\n error={false}\n icon={\n deployAction.deployError ? RotateCcw : isDeploymentActive ? Square : Play\n }\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isDeploymentActive\n ? t('repositoryNode.stopDevServer')\n : t('repositoryNode.startDevServer')}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n </div>\n ) : null}\n </div>\n\n {/* Source handle — invisible, for edge connections */}\n {data.onAdd || data.showHandles ? (\n <Handle\n type=\"source\"\n position={sourceHandlePos}\n isConnectable={!data.showHandles}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n ) : null}\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { ChevronLeft, Loader2 } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { getAllAgentModels } from '@/app/actions/get-all-agent-models';\nimport type { AgentModelGroup } from '@/app/actions/get-all-agent-models';\nimport { updateAgentAndModel } from '@/app/actions/update-agent-and-model';\nimport { getAgentTypeIcon } from '@/components/common/feature-node/agent-type-icons';\nimport { getModelMeta } from '@/lib/model-metadata';\nimport { cn } from '@/lib/utils';\n\nexport interface WelcomeAgentSetupProps {\n onComplete: () => void;\n className?: string;\n}\n\ntype SetupStep = 'select-agent' | 'select-model';\n\nconst STEPS: SetupStep[] = ['select-agent', 'select-model'];\n\nexport function WelcomeAgentSetup({ onComplete, className }: WelcomeAgentSetupProps) {\n const { t } = useTranslation('web');\n const [groups, setGroups] = useState<AgentModelGroup[]>([]);\n const [loading, setLoading] = useState(true);\n const [step, setStep] = useState<SetupStep>('select-agent');\n const [selectedAgent, setSelectedAgent] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n const [transitioning, setTransitioning] = useState(false);\n const [visible, setVisible] = useState(true);\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n useEffect(() => {\n getAllAgentModels()\n .then(setGroups)\n .finally(() => setLoading(false));\n }, []);\n\n const activeGroup = selectedAgent ? groups.find((g) => g.agentType === selectedAgent) : null;\n\n const transitionTo = useCallback((nextStep: SetupStep, setup?: () => void) => {\n setTransitioning(true);\n setVisible(false);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => {\n setup?.();\n setStep(nextStep);\n requestAnimationFrame(() => {\n setVisible(true);\n setTransitioning(false);\n });\n }, 150);\n }, []);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n const saveAndComplete = useCallback(\n async (agentType: string, model: string | null) => {\n setSaving(true);\n try {\n await updateAgentAndModel(agentType, model);\n // Fade out the entire wizard before handing off to the next view\n setVisible(false);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => {\n onComplete();\n }, 200);\n } catch {\n setSaving(false);\n }\n },\n [onComplete]\n );\n\n const handleAgentSelect = useCallback(\n (agentType: string) => {\n const group = groups.find((g) => g.agentType === agentType);\n if (group && group.models.length > 0) {\n transitionTo('select-model', () => {\n setSelectedAgent(agentType);\n });\n } else {\n saveAndComplete(agentType, null);\n }\n },\n [groups, transitionTo, saveAndComplete]\n );\n\n const handleModelSelect = useCallback(\n (model: string) => {\n if (!selectedAgent) return;\n saveAndComplete(selectedAgent, model);\n },\n [selectedAgent, saveAndComplete]\n );\n\n const handleBack = useCallback(() => {\n if (step === 'select-model') {\n transitionTo('select-agent', () => {\n setSelectedAgent(null);\n });\n }\n }, [step, transitionTo]);\n\n if (loading) {\n return (\n <div\n data-testid=\"welcome-agent-setup\"\n className={cn('flex flex-col items-center justify-center gap-4', className)}\n >\n <Loader2 className=\"text-muted-foreground h-5 w-5 animate-spin\" />\n <p className=\"text-muted-foreground text-sm\">{t('welcome.loadingAgents')}</p>\n </div>\n );\n }\n\n const stepIndex = STEPS.indexOf(step);\n\n // Dynamic hero text per step\n const heroTitle = step === 'select-agent' ? t('welcome.chooseAgent') : t('welcome.pickModel');\n\n const heroSubtitle =\n step === 'select-agent'\n ? t('welcome.selectAgentSubtitle')\n : activeGroup\n ? t('welcome.chooseModelSubtitle', { label: activeGroup.label })\n : '';\n\n return (\n <div\n data-testid=\"welcome-agent-setup\"\n className={cn('flex w-full flex-col items-center', className)}\n >\n {/* Step indicator — stays visible across transitions */}\n <div className=\"mb-8 flex w-full max-w-xs items-center gap-1.5\">\n {STEPS.map((s, i) => (\n <div\n key={s}\n className={cn(\n 'h-[3px] flex-1 rounded-full transition-colors duration-300',\n i <= stepIndex ? 'bg-foreground/60' : 'bg-muted'\n )}\n />\n ))}\n </div>\n\n {/* Hero + content — all fade together on step transitions */}\n <div\n className={cn(\n 'flex w-full flex-col items-center transition-opacity duration-200',\n visible && !transitioning ? 'opacity-100' : 'opacity-0'\n )}\n >\n <h1 className=\"text-foreground/90 text-center text-5xl font-extralight tracking-tight\">\n {heroTitle}\n </h1>\n <p className=\"text-muted-foreground mt-3 text-center text-lg leading-relaxed font-light\">\n {heroSubtitle}\n </p>\n\n <div className=\"mt-8 flex w-full flex-col items-center\">\n {/* Step 1: Agent selection — horizontal grid */}\n {step === 'select-agent' && (\n <div\n data-testid=\"agent-list\"\n className=\"grid w-full max-w-lg gap-3\"\n style={{\n gridTemplateColumns: `repeat(${Math.min(groups.length, 4)}, minmax(0, 1fr))`,\n }}\n >\n {groups.map((group) => {\n const GroupIcon = getAgentTypeIcon(group.agentType);\n return (\n <button\n key={group.agentType}\n type=\"button\"\n disabled={saving}\n data-testid={`agent-option-${group.agentType}`}\n className=\"border-border hover:bg-accent hover:border-foreground/20 flex cursor-pointer flex-col items-center gap-3 rounded-2xl border px-4 py-5 transition-all duration-150 active:scale-[0.97] disabled:opacity-50\"\n onClick={() => handleAgentSelect(group.agentType)}\n >\n <GroupIcon className=\"text-foreground/70 h-7 w-7\" />\n <span className=\"text-sm font-medium\">{group.label}</span>\n </button>\n );\n })}\n </div>\n )}\n\n {/* Step 2: Model selection — horizontal grid */}\n {step === 'select-model' && activeGroup ? (\n <div\n data-testid=\"model-list\"\n className=\"flex w-full max-w-lg flex-col items-center gap-4\"\n >\n <button\n type=\"button\"\n disabled={saving}\n className=\"text-muted-foreground hover:text-foreground flex cursor-pointer items-center gap-1.5 self-start text-sm transition-colors\"\n onClick={handleBack}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('welcome.back')}\n </button>\n <div\n className=\"grid w-full gap-3\"\n style={{\n gridTemplateColumns: `repeat(${Math.min(activeGroup.models.length, 3)}, minmax(0, 1fr))`,\n }}\n >\n {activeGroup.models.map((m) => {\n const meta = getModelMeta(m.id);\n return (\n <button\n key={m.id}\n type=\"button\"\n disabled={saving}\n data-testid={`model-option-${m.id}`}\n className=\"border-border hover:bg-accent hover:border-foreground/20 flex cursor-pointer flex-col items-center gap-2 rounded-2xl border px-4 py-5 text-center transition-all duration-150 active:scale-[0.97] disabled:opacity-50\"\n onClick={() => handleModelSelect(m.id)}\n >\n <span className=\"text-sm font-medium\">\n {meta.displayName || m.displayName}\n </span>\n <span className=\"text-muted-foreground text-xs leading-tight\">\n {meta.description || m.description}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useCallback, useEffect } from 'react';\nimport {\n FolderOpen,\n FolderPlus,\n Copy,\n Check,\n Loader2,\n CheckCircle2,\n AlertCircle,\n Terminal,\n ChevronDown,\n ExternalLink,\n Github,\n} from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport { pickFolder } from '@/components/common/add-repository-button/pick-folder';\nimport { ReactFileManagerDialog } from '@/components/common/react-file-manager-dialog';\nimport { useFeatureFlags } from '@/hooks/feature-flags-context';\nimport { isAgentSetupComplete } from '@/app/actions/agent-setup-flag';\nimport { checkAgentAuth } from '@/app/actions/check-agent-auth';\nimport type { AgentAuthStatus } from '@/app/actions/check-agent-auth';\nimport { checkToolStatus } from '@/app/actions/check-tool-status';\nimport type { ToolStatusResult, ToolStatusEntry } from '@/app/actions/check-tool-status';\nimport { WelcomeAgentSetup } from './welcome-agent-setup';\nimport { NewProjectDialog } from './new-project-dialog';\n\nexport interface ControlCenterOnboardingProps {\n onRepositorySelect?: (path: string) => void;\n className?: string;\n}\n\nconst commands = ['cd ~/my-repo', 'shep feat new \"sleek dashboard\"'];\n\nexport function ControlCenterOnboarding({\n onRepositorySelect,\n className,\n}: ControlCenterOnboardingProps) {\n const { t } = useTranslation('web');\n const [copied, setCopied] = useState(false);\n const [loading, setLoading] = useState(false);\n const [showReactPicker, setShowReactPicker] = useState(false);\n const [agentReady, setAgentReady] = useState<boolean | null>(null);\n const [authStatus, setAuthStatus] = useState<AgentAuthStatus | null>(null);\n const [cliExpanded, setCliExpanded] = useState(false);\n const [toolStatus, setToolStatus] = useState<ToolStatusResult | null>(null);\n const [newProjectOpen, setNewProjectOpen] = useState(false);\n const { reactFileManager: useReactFileManager } = useFeatureFlags();\n\n useEffect(() => {\n isAgentSetupComplete()\n .then((done) => setAgentReady(done))\n .catch(() => setAgentReady(false));\n }, []);\n\n useEffect(() => {\n if (!agentReady) return;\n checkAgentAuth()\n .then(setAuthStatus)\n .catch(() =>\n setAuthStatus({\n agentType: 'unknown',\n installed: false,\n authenticated: false,\n label: 'Agent',\n binaryName: null,\n installCommand: null,\n authCommand: null,\n })\n );\n checkToolStatus()\n .then(setToolStatus)\n .catch(() =>\n setToolStatus({\n git: { installed: false, version: null, installCommand: null, installUrl: null },\n gh: { installed: false, version: null, installCommand: null, installUrl: null },\n })\n );\n }, [agentReady]);\n\n async function handlePickerClick() {\n if (loading) return;\n\n if (useReactFileManager) {\n setShowReactPicker(true);\n return;\n }\n\n setLoading(true);\n try {\n const path = await pickFolder();\n if (path) {\n onRepositorySelect?.(path);\n }\n } catch {\n setShowReactPicker(true);\n } finally {\n setLoading(false);\n }\n }\n\n function handleReactPickerSelect(path: string | null) {\n if (path) {\n onRepositorySelect?.(path);\n }\n setShowReactPicker(false);\n }\n\n const handleCopy = useCallback(async () => {\n await navigator.clipboard.writeText(commands.join('\\n'));\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, []);\n\n const handleAgentSetupComplete = useCallback(() => {\n setAgentReady(true);\n }, []);\n\n const handleRetryAuth = useCallback(() => {\n setAuthStatus(null);\n checkAgentAuth().then(setAuthStatus);\n }, []);\n\n if (agentReady === null) return null;\n\n return (\n <div\n data-testid=\"control-center-onboarding\"\n className={cn(\n 'relative flex h-full w-full flex-col items-center justify-center px-8',\n className\n )}\n >\n {!agentReady ? (\n <WelcomeAgentSetup onComplete={handleAgentSetupComplete} />\n ) : (\n <div className=\"animate-in fade-in flex w-full max-w-md flex-col items-center duration-300\">\n <h1 className=\"text-foreground/90 text-center text-5xl font-extralight tracking-tight\">\n {t('emptyState.addProject')}\n </h1>\n <p className=\"text-muted-foreground mt-3 text-center text-lg leading-relaxed font-light\">\n {t('emptyState.addProjectDescription')}\n <br />\n {t('emptyState.addProjectDescriptionLine2')}\n </p>\n\n <div className=\"mt-8 flex w-full flex-col gap-3\">\n <AgentAuthBanner status={authStatus} onRetry={handleRetryAuth} />\n <ToolStatusRow\n label={t('emptyState.git')}\n status={toolStatus?.git ?? null}\n missingHint={t('emptyState.gitRequired')}\n />\n <ToolStatusRow\n label={t('emptyState.githubCli')}\n status={toolStatus?.gh ?? null}\n missingHint={t('emptyState.githubCliRequired')}\n />\n </div>\n\n <button\n type=\"button\"\n data-testid=\"empty-state-add-repository\"\n onClick={handlePickerClick}\n disabled={loading}\n className=\"bg-foreground text-background hover:bg-foreground/90 mt-10 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl px-6 py-4 text-base font-medium shadow-lg transition-all duration-200 hover:shadow-xl active:scale-[0.98] disabled:cursor-wait disabled:opacity-50\"\n >\n {loading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <FolderOpen className=\"h-5 w-5\" />\n )}\n {loading ? t('emptyState.opening') : t('emptyState.chooseFolder')}\n </button>\n\n <button\n type=\"button\"\n data-testid=\"empty-state-new-project\"\n onClick={() => setNewProjectOpen(true)}\n disabled={loading}\n className=\"border-foreground/15 text-foreground/80 hover:bg-foreground/5 hover:border-foreground/25 mt-3 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl border px-6 py-3.5 text-sm font-medium transition-all duration-200 active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <FolderPlus className=\"h-4 w-4\" />\n New Project\n </button>\n\n <button\n type=\"button\"\n data-testid=\"empty-state-import-github\"\n onClick={() => window.dispatchEvent(new CustomEvent('shep:open-github-import'))}\n disabled={loading}\n className=\"border-foreground/15 text-foreground/80 hover:bg-foreground/5 hover:border-foreground/25 mt-3 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl border px-6 py-3.5 text-sm font-medium transition-all duration-200 active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Github className=\"h-4 w-4\" />\n Import from GitHub\n </button>\n\n <p className=\"text-muted-foreground/60 mt-3 text-center text-sm\">\n {t('emptyState.folderHint')}\n </p>\n </div>\n )}\n\n {agentReady ? (\n <div\n className=\"absolute bottom-8 flex flex-col items-center\"\n style={{\n animationDelay: '400ms',\n animationDuration: '600ms',\n animationFillMode: 'both',\n }}\n >\n <button\n type=\"button\"\n onClick={() => setCliExpanded(!cliExpanded)}\n className=\"text-muted-foreground hover:text-foreground flex cursor-pointer items-center gap-1.5 transition-colors duration-200\"\n >\n <Terminal className=\"h-3.5 w-3.5\" />\n <span className=\"text-sm\">{t('emptyState.orUseCli')}</span>\n <ChevronDown\n className={cn(\n 'h-3.5 w-3.5 transition-transform duration-200',\n cliExpanded ? '' : 'rotate-180'\n )}\n />\n </button>\n\n {cliExpanded ? (\n <div className=\"animate-in fade-in slide-in-from-top-1 mt-3 w-80 duration-200\">\n <div\n data-testid=\"cli-code-block\"\n className=\"relative rounded-xl bg-zinc-900 px-5 py-4 font-mono text-[13px] leading-relaxed text-zinc-400\"\n >\n <button\n type=\"button\"\n data-testid=\"cli-code-block-copy\"\n onClick={handleCopy}\n className=\"absolute top-3 right-3 cursor-pointer rounded-md p-1.5 text-zinc-600 transition-colors hover:bg-zinc-800 hover:text-zinc-300\"\n aria-label={t('emptyState.copyCommands')}\n >\n {copied ? (\n <Check className=\"h-3.5 w-3.5 text-emerald-400\" />\n ) : (\n <Copy className=\"h-3.5 w-3.5\" />\n )}\n </button>\n <div className=\"space-y-1\">\n {commands.map((cmd) => (\n <div key={cmd} className=\"whitespace-nowrap\">\n <span className=\"text-zinc-600 select-none\">$ </span>\n <span className=\"text-zinc-300\">{cmd}</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n ) : null}\n\n <ReactFileManagerDialog\n open={showReactPicker}\n onOpenChange={(open) => {\n if (!open) setShowReactPicker(false);\n }}\n onSelect={handleReactPickerSelect}\n />\n <NewProjectDialog\n open={newProjectOpen}\n onOpenChange={setNewProjectOpen}\n onCreated={(path) => onRepositorySelect?.(path)}\n />\n </div>\n );\n}\n\nfunction AgentAuthBanner({\n status,\n onRetry,\n}: {\n status: AgentAuthStatus | null;\n onRetry: () => void;\n}) {\n const { t } = useTranslation('web');\n\n if (!status) {\n return (\n <ChecklistRow icon={<Loader2 className=\"text-muted-foreground/50 h-4 w-4 animate-spin\" />}>\n <span className=\"text-muted-foreground/50 text-sm\">{t('emptyState.checkingSetup')}</span>\n </ChecklistRow>\n );\n }\n\n if (status.installed && status.authenticated) {\n return (\n <ChecklistRow icon={<CheckCircle2 className=\"h-4 w-4 text-emerald-500\" />}>\n <span className=\"text-sm text-emerald-600 dark:text-emerald-400\">\n {t('emptyState.ready', { label: status.label })}\n </span>\n </ChecklistRow>\n );\n }\n\n if (!status.installed) {\n return (\n <ChecklistRow icon={<AlertCircle className=\"h-4 w-4 text-amber-500\" />}>\n <span className=\"text-sm font-medium text-amber-600 dark:text-amber-400\">\n {t('emptyState.notInstalled', { label: status.label })}\n </span>\n {status.installCommand ? <CopyableCommand command={status.installCommand} /> : null}\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n {t('emptyState.reCheck')}\n </button>\n </ChecklistRow>\n );\n }\n\n return (\n <ChecklistRow icon={<AlertCircle className=\"h-4 w-4 text-amber-500\" />}>\n <span className=\"text-sm font-medium text-amber-600 dark:text-amber-400\">\n {t('emptyState.needsAuth', { label: status.label })}\n </span>\n {status.authCommand ? <CopyableCommand command={status.authCommand} /> : null}\n <div className=\"flex items-center gap-3\">\n {status.binaryName ? (\n <button\n type=\"button\"\n data-testid=\"auth-banner-open-terminal\"\n onClick={async () => {\n try {\n const toolId =\n status.agentType === 'claude-code' ? 'claude-code' : status.agentType;\n await fetch(`/api/tools/${toolId}/launch`, { method: 'POST' });\n } catch {\n /* best effort */\n }\n }}\n className=\"flex items-center gap-1 text-xs font-medium text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n <Terminal className=\"h-3 w-3\" />\n {t('emptyState.open', { label: status.label })}\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n {t('emptyState.reCheck')}\n </button>\n </div>\n </ChecklistRow>\n );\n}\n\nfunction ToolStatusRow({\n label,\n status,\n missingHint,\n}: {\n label: string;\n status: ToolStatusEntry | null;\n missingHint: string;\n}) {\n const { t } = useTranslation('web');\n\n if (!status) {\n return (\n <ChecklistRow icon={<Loader2 className=\"text-muted-foreground/50 h-4 w-4 animate-spin\" />}>\n <span className=\"text-muted-foreground/50 text-sm\">\n {t('emptyState.checking', { label })}\n </span>\n </ChecklistRow>\n );\n }\n\n if (status.installed) {\n return (\n <ChecklistRow icon={<CheckCircle2 className=\"h-4 w-4 text-emerald-500\" />}>\n <span className=\"flex items-baseline gap-2\">\n <span className=\"text-sm text-emerald-600 dark:text-emerald-400\">\n {t('emptyState.ready', { label })}\n </span>\n {status.version ? (\n <span className=\"text-muted-foreground/40 text-xs\">v{status.version}</span>\n ) : null}\n </span>\n </ChecklistRow>\n );\n }\n\n return (\n <ChecklistRow icon={<AlertCircle className=\"h-4 w-4 text-amber-500\" />}>\n <span className=\"text-sm font-medium text-amber-600 dark:text-amber-400\">\n {t('emptyState.notFound', { label })}\n </span>\n <span className=\"text-muted-foreground/50 text-xs\">{missingHint}</span>\n {status.installCommand ? <CopyableCommand command={status.installCommand} /> : null}\n {status.installUrl ? (\n <a\n href={status.installUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n {t('emptyState.docs')} <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : null}\n </ChecklistRow>\n );\n}\n\nfunction ChecklistRow({ icon, children }: { icon: React.ReactNode; children: React.ReactNode }) {\n return (\n <div className=\"animate-in fade-in flex items-start gap-2.5\">\n <div className=\"mt-0.5 shrink-0\">{icon}</div>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">{children}</div>\n </div>\n );\n}\n\nfunction CopyableCommand({ command }: { command: string }) {\n const [copied, setCopied] = useState(false);\n\n return (\n <button\n type=\"button\"\n onClick={async () => {\n await navigator.clipboard.writeText(command);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }}\n className=\"group/cmd flex cursor-pointer items-center justify-between gap-2 rounded-md bg-zinc-100 py-1 ps-2.5 pe-2 text-start transition-colors hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700\"\n >\n <code className=\"min-w-0 truncate text-[11px] leading-relaxed text-zinc-600 dark:text-zinc-300\">\n {command}\n </code>\n {copied ? (\n <Check className=\"h-3 w-3 shrink-0 text-emerald-500\" />\n ) : (\n <Copy className=\"h-3 w-3 shrink-0 text-zinc-400 opacity-0 transition-opacity group-hover/cmd:opacity-100\" />\n )}\n </button>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport {\n X,\n MessageCircleQuestion,\n ShieldCheck,\n ArrowRight,\n Plus,\n Layers,\n GitBranch,\n Sparkles,\n} from 'lucide-react';\nimport Link from 'next/link';\nimport type { Route } from 'next';\nimport { cn } from '@/lib/utils';\n\nconst DISMISSED_KEY = 'shep:collaboration-onboarding-dismissed';\n\n/** Human-friendly cap for the inline pill list before collapsing into a picker. */\nconst PILL_LIMIT = 3;\n\nexport type SupervisorScopeKind = 'app' | 'repo' | 'feature';\n\nexport interface SupervisorScopeEntry {\n id: string;\n name: string;\n kind: SupervisorScopeKind;\n}\n\nexport interface CollaborationOnboardingProps {\n /** Applications on the canvas. */\n apps?: SupervisorScopeEntry[];\n /** Repositories on the canvas. */\n repos?: SupervisorScopeEntry[];\n /** Features on the canvas. */\n features?: SupervisorScopeEntry[];\n className?: string;\n}\n\n/**\n * Dismissable first-run callout shown in the control center when the\n * collaboration feature flag is on. Surfaces every entity the user can\n * attach a supervisor to — applications, repositories, and features —\n * mirroring the cascading scope model (`global → app → repo → feature`).\n *\n * no scopes → tells the user to add a repo or app to get started\n * 1 scope → links directly to the right /supervisor/... page\n * N scopes → shows up to PILL_LIMIT inline pills with an overflow picker\n */\nexport function CollaborationOnboarding({\n apps = [],\n repos = [],\n features = [],\n className,\n}: CollaborationOnboardingProps) {\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n try {\n if (!localStorage.getItem(DISMISSED_KEY)) {\n setVisible(true);\n }\n } catch {\n // localStorage blocked (private mode, SSR, etc.)\n }\n }, []);\n\n function dismiss() {\n try {\n localStorage.setItem(DISMISSED_KEY, '1');\n } catch {\n // ignore\n }\n setVisible(false);\n }\n\n if (!visible) return null;\n\n return (\n <div\n className={cn(\n 'border-border/60 bg-card relative flex flex-col gap-4 rounded-xl border p-5 shadow-sm',\n className\n )}\n role=\"region\"\n aria-label=\"Agent collaboration onboarding\"\n data-testid=\"collaboration-onboarding\"\n >\n {/* Dismiss */}\n <button\n type=\"button\"\n aria-label=\"Dismiss\"\n onClick={dismiss}\n className=\"text-muted-foreground hover:text-foreground absolute top-3 right-3 rounded-md p-1 transition-colors\"\n >\n <X className=\"size-4\" />\n </button>\n\n {/* Header */}\n <div>\n <p className=\"text-[10px] font-semibold tracking-widest text-indigo-500 uppercase\">New</p>\n <h2 className=\"mt-0.5 text-base font-semibold\">Agent Collaboration & Supervision</h2>\n <p className=\"text-muted-foreground mt-1 text-sm\">\n Your agents can now ask questions, talk to each other, and be guided by a supervisor you\n configure.\n </p>\n </div>\n\n {/* Feature cards */}\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <SupervisorCard apps={apps} repos={repos} features={features} />\n <FeatureCard\n icon={MessageCircleQuestion}\n title=\"Agent questions inbox\"\n description=\"A single place for all questions raised by agents during interactive and background runs.\"\n href=\"/agent-questions\"\n cta=\"View inbox\"\n />\n </div>\n </div>\n );\n}\n\n// ── Supervisor card — adapts to whatever scopes exist on the canvas ──────────\n\ninterface SupervisorCardProps {\n apps: SupervisorScopeEntry[];\n repos: SupervisorScopeEntry[];\n features: SupervisorScopeEntry[];\n}\n\nfunction SupervisorCard({ apps, repos, features }: SupervisorCardProps) {\n const [pickerOpen, setPickerOpen] = useState(false);\n\n const allScopes = useMemo(\n () => [\n ...apps.map((a) => ({ ...a, kind: 'app' as const })),\n ...repos.map((r) => ({ ...r, kind: 'repo' as const })),\n ...features.map((f) => ({ ...f, kind: 'feature' as const })),\n ],\n [apps, repos, features]\n );\n\n // Empty: no apps, repos, or features yet.\n if (allScopes.length === 0) {\n return (\n <div className=\"bg-muted/40 border-border/40 flex flex-col gap-2 rounded-lg border p-4\">\n <SupervisorHeader />\n <p className=\"text-muted-foreground text-xs leading-relaxed\">\n Supervisors attach to an application, repository, or feature. Add a repository or create\n an application to configure your first one.\n </p>\n <button\n type=\"button\"\n onClick={() => window.dispatchEvent(new CustomEvent('shep:open-create-application'))}\n className=\"text-primary mt-auto inline-flex cursor-pointer items-center gap-1 text-xs font-medium hover:underline\"\n >\n <Plus className=\"size-3\" />\n Create an application\n </button>\n </div>\n );\n }\n\n // Single scope on the canvas — link straight to its page.\n if (allScopes.length === 1) {\n const only = allScopes[0]!;\n return (\n <FeatureCard\n icon={ShieldCheck}\n title=\"Supervisor agent\"\n description={`Delegate approvals and policy decisions for ${describeKind(only.kind)} \"${only.name}\".`}\n href={routeFor(only)}\n cta=\"Configure supervisor\"\n />\n );\n }\n\n // Multiple — show a few pills + (open picker for the rest).\n const pills = allScopes.slice(0, PILL_LIMIT);\n const overflow = allScopes.length - pills.length;\n\n return (\n <div className=\"bg-muted/40 border-border/40 flex flex-col gap-2 rounded-lg border p-4\">\n <SupervisorHeader />\n <p className=\"text-muted-foreground text-xs leading-relaxed\">\n Pick an application, repository, or feature to configure its supervisor.\n </p>\n\n {pickerOpen ? (\n <div className=\"mt-1 flex max-h-72 flex-col gap-1 overflow-y-auto\">\n {allScopes.map((scope) => (\n <Link\n key={`${scope.kind}-${scope.id}`}\n href={routeFor(scope)}\n className=\"border-border/50 hover:bg-background flex items-center justify-between rounded-md border px-3 py-2 text-xs transition-colors\"\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n <KindIcon kind={scope.kind} className=\"text-muted-foreground size-3 shrink-0\" />\n <span className=\"truncate font-medium\">{scope.name}</span>\n </span>\n <ArrowRight className=\"text-muted-foreground ml-2 size-3 shrink-0\" />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"mt-1 flex flex-wrap gap-1.5\">\n {pills.map((scope) => (\n <Link\n key={`${scope.kind}-${scope.id}`}\n href={routeFor(scope)}\n className=\"border-border/50 bg-background hover:border-primary/40 hover:text-primary flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs transition-colors\"\n >\n <KindIcon kind={scope.kind} className=\"size-3 shrink-0\" />\n <span className=\"max-w-[10rem] truncate\">{scope.name}</span>\n <ArrowRight className=\"size-2.5\" />\n </Link>\n ))}\n {overflow > 0 ? (\n <button\n type=\"button\"\n onClick={() => setPickerOpen(true)}\n className=\"text-muted-foreground hover:text-foreground border-border/50 rounded-md border px-2.5 py-1 text-xs transition-colors\"\n >\n +{overflow} more\n </button>\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nfunction SupervisorHeader() {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"bg-primary/10 text-primary flex h-7 w-7 shrink-0 items-center justify-center rounded-md\">\n <ShieldCheck className=\"size-3.5\" />\n </div>\n <span className=\"text-sm font-medium\">Supervisor agent</span>\n </div>\n );\n}\n\nfunction KindIcon({ kind, className }: { kind: SupervisorScopeKind; className?: string }) {\n const Icon = kind === 'app' ? Layers : kind === 'repo' ? GitBranch : Sparkles;\n return <Icon className={className} aria-hidden />;\n}\n\nfunction describeKind(kind: SupervisorScopeKind): string {\n return kind === 'app' ? 'application' : kind === 'repo' ? 'repository' : 'feature';\n}\n\nfunction routeFor(scope: SupervisorScopeEntry): Route {\n switch (scope.kind) {\n case 'app':\n return `/application/${scope.id}/supervisor` as Route;\n case 'repo':\n return `/supervisor/repo/${scope.id}` as Route;\n case 'feature':\n return `/supervisor/feature/${scope.id}` as Route;\n }\n}\n\n// ── Generic card ─────────────────────────────────────────────────────────────\n\ninterface FeatureCardProps {\n icon: React.ComponentType<{ className?: string }>;\n title: string;\n description: string;\n href: Route;\n cta: string;\n}\n\nfunction FeatureCard({ icon: Icon, title, description, href, cta }: FeatureCardProps) {\n return (\n <div className=\"bg-muted/40 border-border/40 flex flex-col gap-2 rounded-lg border p-4\">\n <div className=\"flex items-center gap-2\">\n <div className=\"bg-primary/10 text-primary flex h-7 w-7 shrink-0 items-center justify-center rounded-md\">\n <Icon className=\"size-3.5\" />\n </div>\n <span className=\"text-sm font-medium\">{title}</span>\n </div>\n <p className=\"text-muted-foreground text-xs leading-relaxed\">{description}</p>\n <Link\n href={href}\n className=\"text-primary mt-auto inline-flex items-center gap-1 text-xs font-medium hover:underline\"\n >\n {cta}\n <ArrowRight className=\"size-3\" />\n </Link>\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useRouter, usePathname } from 'next/navigation';\nimport { FolderPlus } from 'lucide-react';\nimport type { Edge, Viewport } from '@xyflow/react';\nimport { useReactFlow } from '@xyflow/react';\nimport { FeaturesCanvas } from '@/components/features/features-canvas';\nimport { CanvasToolbar } from '@/components/features/features-canvas/canvas-toolbar';\nimport { WorkspaceSelector } from '@/components/features/features-canvas/workspace-selector';\nimport { ManageWorkspaceDialog } from '@/components/features/features-canvas/manage-workspace-dialog';\nimport { WorkspaceNameDialog } from '@/components/features/features-canvas/workspace-name-dialog';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '@/components/ui/alert-dialog';\nimport { useWorkspaces, DEFAULT_WORKSPACE_ID } from '@/hooks/use-workspaces';\nimport { Layers, Plus } from 'lucide-react';\nimport { Button } from '@/components/ui/button';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\nimport {\n FloatingActionButton,\n type FloatingActionButtonAction,\n} from '@/components/common/floating-action-button';\nimport {\n useSidebarFeaturesContext,\n mapNodeStateToSidebarStatus,\n} from '@/hooks/sidebar-features-context';\nimport { useTranslation } from 'react-i18next';\n\nimport { useSelectedFeatureId } from '@/hooks/use-selected-feature-id';\nimport { useSelectedRepository } from '@/hooks/use-selected-repository';\nimport { useSoundAction } from '@/hooks/use-sound-action';\nimport { useDrawerCloseGuard } from '@/hooks/drawer-close-guard';\nimport { useViewportPersistence } from '@/hooks/use-viewport-persistence';\nimport { useSidebar } from '@/components/ui/sidebar';\nimport { useFabLayout } from '@/hooks/fab-layout-context';\nimport { useFeatureFlags } from '@/hooks/feature-flags-context';\nimport { ControlCenterEmptyState } from './control-center-empty-state';\nimport { ControlCenterOnboarding } from './control-center-onboarding';\nimport { CollaborationOnboarding } from './collaboration-onboarding';\nimport { NewProjectDialog } from './new-project-dialog';\nimport { useControlCenterState } from './use-control-center-state';\nimport { useCanvasEventListeners } from './use-canvas-event-listeners';\nimport { useWorkspaceFitView } from './use-workspace-fit-view';\nimport { useFabActions } from './use-fab-actions';\nimport { buildCreateUrl } from '@/lib/url-params';\nimport { BuildMode } from '@shepai/core/domain/generated/output';\n\nconst AUTO_FOCUS_OPTIONS = {\n maxZoom: 1.0,\n padding: 0.5,\n duration: 500,\n} as const;\n\nconst AUTO_FOCUS_DRAWER_DELAY_MS = 600;\n\ninterface ControlCenterInnerProps {\n initialNodes: CanvasNodeType[];\n initialEdges: Edge[];\n}\n\nexport function ControlCenterInner({ initialNodes, initialEdges }: ControlCenterInnerProps) {\n const router = useRouter();\n const pathname = usePathname();\n const selectedFeatureId = useSelectedFeatureId();\n const selectedRepository = useSelectedRepository();\n const clickSound = useSoundAction('click');\n const { guardedNavigate } = useDrawerCloseGuard();\n const { fitView } = useReactFlow();\n const drawerTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const {\n defaultViewport,\n onMoveEnd: handleViewportChange,\n resetViewport,\n } = useViewportPersistence();\n\n const {\n nodes,\n edges,\n onNodesChange,\n handleConnect,\n handleAddRepository,\n handleArchiveFeature,\n handleDeleteFeature,\n handleRetryFeature,\n handleStartFeature,\n handleStopFeature,\n handleUnarchiveFeature,\n handleDeleteRepository,\n handleDeleteApplication,\n createFeatureNode,\n showArchived,\n setShowArchived,\n setCallbacks,\n } = useControlCenterState(initialNodes, initialEdges);\n\n // ── Workspaces (client-only prototype) ────────────────────────────────\n const {\n workspaces,\n activeWorkspace,\n isDefaultActive,\n setActiveWorkspace,\n createWorkspace,\n renameWorkspace,\n deleteWorkspace,\n setWorkspaceMembers,\n addToActiveWorkspace,\n } = useWorkspaces();\n // Tracks the set of node ids we've already seen, so we can detect new\n // repo/feature nodes appearing on the canvas and auto-include them in the\n // active workspace (when it isn't the default).\n const knownNodeIdsRef = useRef<Set<string>>(new Set());\n const [manageWorkspaceOpen, setManageWorkspaceOpen] = useState(false);\n const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false);\n const [renameWorkspaceOpen, setRenameWorkspaceOpen] = useState(false);\n const [deleteWorkspaceOpen, setDeleteWorkspaceOpen] = useState(false);\n // Target of the delete confirmation dialog. Allows deleting any workspace\n // (not just the active one) directly from the workspace dropdown.\n const [pendingDeleteWorkspaceId, setPendingDeleteWorkspaceId] = useState<string | null>(null);\n // Inline \"New Project\" dialog launched from the empty-workspace state.\n const [workspaceNewProjectOpen, setWorkspaceNewProjectOpen] = useState(false);\n\n // Publish sidebar features + repo state to context\n const { setFeatures: setSidebarFeatures, setHasRepositories: setSidebarHasRepos } =\n useSidebarFeaturesContext();\n\n const featureNodes = useMemo(() => nodes.filter((n) => n.type === 'featureNode'), [nodes]);\n\n const sidebarKey = useMemo(() => {\n return featureNodes\n .map((n) => {\n const d = n.data as FeatureNodeData;\n return `${d.featureId}:${d.state}:${d.name}:${d.repositoryPath}`;\n })\n .sort()\n .join(',');\n }, [featureNodes]);\n\n useEffect(() => {\n const sidebarItems = featureNodes\n .map((n) => {\n const d = n.data as FeatureNodeData;\n const status = mapNodeStateToSidebarStatus(d.state);\n if (!status) return null;\n const repoPath = d.repositoryPath ?? '';\n return {\n featureId: d.featureId,\n name: d.name,\n status,\n repositoryPath: repoPath,\n repositoryName: d.repositoryName ?? repoPath.split('/').filter(Boolean).pop() ?? repoPath,\n ...(d.startedAt != null && { startedAt: d.startedAt }),\n ...(d.runtime != null && { duration: d.runtime }),\n ...(d.agentType && { agentType: d.agentType }),\n ...(d.modelId && { modelId: d.modelId }),\n };\n })\n .filter(Boolean) as {\n featureId: string;\n name: string;\n status: 'action-needed' | 'in-progress' | 'done';\n repositoryPath: string;\n repositoryName: string;\n startedAt?: number;\n duration?: string;\n agentType?: string;\n modelId?: string;\n }[];\n\n setSidebarFeatures(sidebarItems);\n }, [sidebarKey, featureNodes, setSidebarFeatures]);\n\n // ── URL-based navigation handlers ────────────────────────────────────\n\n const handleApplicationClick = useCallback(\n (applicationId: string) => {\n guardedNavigate(() => router.push(`/application/${applicationId}`));\n },\n [router, guardedNavigate]\n );\n\n const handleApplicationCreateSddFeature = useCallback(\n (applicationId: string) => {\n clickSound.play();\n guardedNavigate(() => router.push(buildCreateUrl({ applicationId, mode: BuildMode.Spec })));\n },\n [router, clickSound, guardedNavigate]\n );\n\n const handleNodeClick = useCallback(\n (event: React.MouseEvent, node: CanvasNodeType) => {\n if (node.type === 'featureNode') {\n const data = node.data as FeatureNodeData;\n if (data.state === 'creating' || data.state === 'deleting') return;\n // Only navigate when the click lands on the card itself, not on\n // overlay buttons (delete, add) or pointer events leaking from dialogs.\n const target = event.target as HTMLElement;\n if (!target.closest('[data-testid=\"feature-node-card\"]')) return;\n guardedNavigate(() => {\n clickSound.play();\n router.push(`/feature/${data.featureId}`);\n });\n }\n },\n [router, clickSound, guardedNavigate]\n );\n\n const handleAddFeature = useCallback(() => {\n clickSound.play();\n router.push('/create');\n }, [router, clickSound]);\n\n const handleAddFeatureToRepo = useCallback(\n (repoNodeId: string) => {\n clickSound.play();\n const node = nodes.find((n) => n.id === repoNodeId);\n const repoPath = (node?.data as { repositoryPath?: string } | undefined)?.repositoryPath;\n router.push(buildCreateUrl(repoPath ? { repo: repoPath } : {}));\n },\n [nodes, router, clickSound]\n );\n\n const handleAddFeatureToFeature = useCallback(\n (featureNodeId: string) => {\n const featureId = featureNodeId.startsWith('feat-') ? featureNodeId.slice(5) : featureNodeId;\n // Find the repo node that owns this feature\n const repoEdge = edges.find((e) => e.target === featureNodeId);\n const repoNode = repoEdge ? nodes.find((n) => n.id === repoEdge.source) : null;\n const repoPath = (repoNode?.data as { repositoryPath?: string } | undefined)?.repositoryPath;\n\n clickSound.play();\n router.push(buildCreateUrl({ repo: repoPath, parent: featureId }));\n },\n [nodes, edges, router, clickSound]\n );\n\n const handleRepositoryClick = useCallback(\n (nodeId: string) => {\n const node = nodes.find((n) => n.id === nodeId);\n if (node?.type === 'repositoryNode') {\n const data = node.data as RepositoryNodeData;\n if (data.id) {\n guardedNavigate(() => router.push(`/repository/${data.id}`));\n }\n }\n },\n [nodes, router, guardedNavigate]\n );\n\n // Close all drawers — navigate back to the control-center canvas\n const handleClearDrawers = useCallback(() => {\n if (pathname !== '/control-center') {\n guardedNavigate(() => router.push('/control-center'));\n }\n }, [router, pathname, guardedNavigate]);\n\n // Shared: after adding first repo, center canvas and open create drawer\n const focusAndOpenDrawer = useCallback(\n (repoPath: string) => {\n // Wait for next render so the repo node exists in the DOM\n setTimeout(() => {\n fitView(AUTO_FOCUS_OPTIONS);\n\n // Open the create-feature drawer after the fitView animation completes\n drawerTimerRef.current = setTimeout(() => {\n guardedNavigate(() => router.push(buildCreateUrl({ repo: repoPath })));\n }, AUTO_FOCUS_DRAWER_DELAY_MS);\n }, 0);\n },\n [fitView, guardedNavigate, router]\n );\n\n // Smoothly pan/zoom to a specific node after it appears on canvas\n const focusOnNode = useCallback(\n (nodeId: string) => {\n // Wait for next render so the node exists in the DOM\n setTimeout(() => {\n fitView({\n nodes: [{ id: nodeId }],\n maxZoom: 1.0,\n padding: 0.4,\n duration: 600,\n });\n }, 0);\n },\n [fitView]\n );\n\n // Wrapper: add repo + auto-focus on the new node\n const addRepoAndFocus = useCallback(\n (path: string) => {\n const { wasEmpty, repoPath, tempNodeId } = handleAddRepository(path);\n if (wasEmpty) {\n focusAndOpenDrawer(repoPath);\n } else {\n focusOnNode(tempNodeId);\n }\n },\n [handleAddRepository, focusAndOpenDrawer, focusOnNode]\n );\n\n // All five window-level CustomEvent listeners (add-repository, feature-\n // created, delete/archive/unarchive requests) live in this hook so the\n // parent component stays focused on graph state + rendering.\n useCanvasEventListeners({\n addRepoAndFocus,\n createFeatureNode,\n nodes,\n handleDeleteFeature,\n handleArchiveFeature,\n handleUnarchiveFeature,\n });\n\n // Cleanup the drawer timer on unmount. Used to live inside the inlined\n // shep:add-repository listener; now standalone since the listener moved.\n useEffect(() => {\n return () => {\n if (drawerTimerRef.current != null) {\n clearTimeout(drawerTimerRef.current);\n }\n };\n }, []);\n\n // Wire callbacks into derived node data (via ref — no re-render).\n useEffect(() => {\n setCallbacks({\n onNodeAction: handleAddFeatureToFeature,\n onFeatureDelete: handleDeleteFeature,\n onRetryFeature: handleRetryFeature,\n onStartFeature: handleStartFeature,\n onStopFeature: handleStopFeature,\n onArchiveFeature: handleArchiveFeature,\n onUnarchiveFeature: handleUnarchiveFeature,\n onRepositoryAdd: handleAddFeatureToRepo,\n onRepositoryClick: handleRepositoryClick,\n onRepositoryDelete: handleDeleteRepository,\n onApplicationClick: handleApplicationClick,\n onApplicationDelete: handleDeleteApplication,\n onApplicationCreateSddFeature: handleApplicationCreateSddFeature,\n });\n }, [\n setCallbacks,\n handleAddFeatureToFeature,\n handleArchiveFeature,\n handleDeleteFeature,\n handleRetryFeature,\n handleStartFeature,\n handleStopFeature,\n handleUnarchiveFeature,\n handleAddFeatureToRepo,\n handleRepositoryClick,\n handleDeleteRepository,\n handleApplicationClick,\n handleDeleteApplication,\n handleApplicationCreateSddFeature,\n ]);\n\n const handleMoveEnd = useCallback(\n (_event: unknown, viewport: Viewport) => {\n handleViewportChange(viewport);\n },\n [handleViewportChange]\n );\n\n const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');\n // The canvas is \"non-empty\" as soon as ANY repo OR application node is\n // present — applications are first-class top-level nodes, so creating\n // an application alone must be enough to keep the prompt empty state\n // from re-appearing on next visit.\n const hasCanvasContent = hasRepositories || nodes.some((n) => n.type === 'applicationNode');\n\n // Publish repo state to sidebar context so AppShell can hide FAB during onboarding\n useEffect(() => {\n setSidebarHasRepos(hasRepositories);\n }, [hasRepositories, setSidebarHasRepos]);\n\n // Debounced latch: prevent empty-state flicker during brief reconcile gaps\n // (e.g. stale poll momentarily drops nodes), but allow the empty state to\n // return after a real delete once content stays gone past the debounce window.\n const [showCanvas, setShowCanvas] = useState(hasCanvasContent);\n const latchTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (hasCanvasContent) {\n // Repos / apps exist — show canvas immediately, cancel any pending unlatch\n if (latchTimerRef.current) {\n clearTimeout(latchTimerRef.current);\n latchTimerRef.current = null;\n }\n setShowCanvas(true);\n } else if (showCanvas) {\n // All canvas content gone — clear saved viewport so next add starts\n // centered, then wait before showing empty state (debounce stale polls)\n resetViewport();\n latchTimerRef.current = setTimeout(() => {\n setShowCanvas(false);\n latchTimerRef.current = null;\n }, 500);\n }\n return () => {\n if (latchTimerRef.current) clearTimeout(latchTimerRef.current);\n };\n }, [hasCanvasContent, showCanvas, resetViewport]);\n\n // Auto-include any newly-appearing repo/feature nodes in the active\n // workspace (skipped when default is active — that workspace shows\n // everything anyway). We diff the current node id list against the set\n // we've already seen so we only add the deltas.\n useEffect(() => {\n const seen = knownNodeIdsRef.current;\n const newRepoIds: string[] = [];\n const newFeatureIds: string[] = [];\n for (const n of nodes) {\n if (seen.has(n.id)) continue;\n seen.add(n.id);\n if (n.type === 'repositoryNode') newRepoIds.push(n.id);\n else if (n.type === 'featureNode') newFeatureIds.push(n.id);\n }\n if (isDefaultActive) return;\n if (newRepoIds.length === 0 && newFeatureIds.length === 0) return;\n addToActiveWorkspace({ repoIds: newRepoIds, featureIds: newFeatureIds });\n }, [nodes, isDefaultActive, addToActiveWorkspace]);\n\n // Filter nodes by the active workspace (default workspace = no filter).\n // We always filter from the full `nodes` list so `displayNodes` already\n // reflects workspace membership before pulse-add decoration runs.\n const workspaceFilteredNodes = useMemo(() => {\n if (isDefaultActive) return nodes;\n const allowedRepos = new Set(activeWorkspace.repoIds);\n const allowedFeatures = new Set(activeWorkspace.featureIds);\n return nodes.filter((n) => {\n if (n.type === 'repositoryNode') return allowedRepos.has(n.id);\n if (n.type === 'featureNode') return allowedFeatures.has(n.id);\n return true;\n });\n }, [nodes, isDefaultActive, activeWorkspace]);\n\n // Drop edges whose endpoints were filtered out.\n const workspaceFilteredEdges = useMemo(() => {\n if (isDefaultActive) return edges;\n const visibleIds = new Set(workspaceFilteredNodes.map((n) => n.id));\n return edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target));\n }, [edges, isDefaultActive, workspaceFilteredNodes]);\n\n // Pulse the \"+\" button when there's a single repo with no features and the\n // create-feature drawer is not open — draws attention to the next action.\n const isCreateDrawerOpen = pathname.startsWith('/create');\n const displayNodes = useMemo(() => {\n const source = workspaceFilteredNodes;\n const repoNodes = source.filter((n) => n.type === 'repositoryNode');\n const hasFeatures = source.some((n) => n.type === 'featureNode');\n const shouldPulse = repoNodes.length === 1 && !hasFeatures && !isCreateDrawerOpen;\n\n if (!shouldPulse) return source;\n\n return source.map((n) =>\n n.type === 'repositoryNode' ? { ...n, data: { ...n.data, pulseAdd: true } } : n\n );\n }, [workspaceFilteredNodes, isCreateDrawerOpen]);\n\n const handlePickFolder = useCallback(() => {\n window.dispatchEvent(new CustomEvent('shep:pick-folder'));\n }, []);\n\n // Re-fit the viewport when the active workspace's visible node set changes.\n // See use-workspace-fit-view.ts for the scoping rules.\n useWorkspaceFitView({\n activeWorkspace,\n isDefaultActive,\n workspaceFilteredNodes,\n fitView,\n });\n\n // When the active (non-default) workspace has no members but real canvas\n // content (repos or applications) exists, show a workspace-aware empty\n // state instead of the welcome wizard. The wizard would imply \"no nodes\n // at all\", which is wrong here — and crucially, leaves the workspace\n // selector visible via the toolbar so users can switch back to default.\n const workspaceFilteredEmpty =\n hasCanvasContent && !isDefaultActive && workspaceFilteredNodes.length === 0;\n\n const emptyStateNode = workspaceFilteredEmpty ? (\n <div className=\"pointer-events-auto flex h-full w-full flex-col items-center justify-center px-8\">\n <div className=\"bg-primary/10 text-primary mb-5 flex h-12 w-12 items-center justify-center rounded-2xl\">\n <Layers className=\"h-6 w-6\" />\n </div>\n <h2 className=\"text-foreground/90 text-center text-2xl font-light tracking-tight\">\n This workspace is empty\n </h2>\n <p className=\"text-muted-foreground mt-2 max-w-sm text-center text-sm leading-relaxed\">\n Add repositories or features from the canvas, or switch back to the default workspace to see\n everything.\n </p>\n <div className=\"mt-6 flex items-center gap-2\">\n <Button\n size=\"sm\"\n onClick={() => setWorkspaceNewProjectOpen(true)}\n className=\"bg-blue-500 text-white hover:bg-blue-600\"\n >\n <FolderPlus className=\"me-1.5 h-3.5 w-3.5\" />\n New project\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setManageWorkspaceOpen(true)}>\n <Plus className=\"me-1.5 h-3.5 w-3.5\" />\n Manage items\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setActiveWorkspace(DEFAULT_WORKSPACE_ID)}>\n Switch to Default\n </Button>\n </div>\n </div>\n ) : (\n <ControlCenterOnboarding onRepositorySelect={addRepoAndFocus} />\n );\n\n // ── Full-screen create prompt overlay ────────────────────────────────\n const [showCreatePrompt, setShowCreatePrompt] = useState(false);\n\n const featureFlags = useFeatureFlags();\n\n const collaborationApps = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'applicationNode')\n .map((n) => ({\n id: n.data.id as string,\n name: n.data.name as string,\n kind: 'app' as const,\n })),\n [initialNodes]\n );\n\n const collaborationRepos = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'repositoryNode')\n .map((n) => ({\n id: (n.data.id ?? n.id) as string,\n name: n.data.name as string,\n kind: 'repo' as const,\n })),\n [initialNodes]\n );\n\n const collaborationFeatures = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'featureNode')\n .map((n) => ({\n id: (n.data.featureId ?? n.id) as string,\n name: n.data.name as string,\n kind: 'feature' as const,\n })),\n [initialNodes]\n );\n\n // Derive the FAB's app context from the canvas. When exactly one\n // ApplicationNode is on the visible canvas we treat it as the scoped\n // application — surfacing the contextual \"New SDD feature for <app>\"\n // FAB action without forcing the user to make an explicit selection\n // gesture (the canvas runs with `elementsSelectable={false}` so React\n // Flow's native multi-select isn't available here).\n const applicationNodes = useMemo(\n () => displayNodes.filter((n) => n.type === 'applicationNode'),\n [displayNodes]\n );\n const selectedApplicationId =\n applicationNodes.length === 1\n ? (applicationNodes[0].data as ApplicationNodeData).id\n : undefined;\n const selectedApplicationName =\n applicationNodes.length === 1\n ? (applicationNodes[0].data as ApplicationNodeData).name\n : undefined;\n\n // (+) FAB actions — only visible on control center. Action list lives in\n // its own hook so this component stays focused on graph state + rendering.\n const fabActions = useFabActions({\n router,\n clickSound,\n guardedNavigate,\n handlePickFolder,\n onNewProject: () => setWorkspaceNewProjectOpen(true),\n onNewApplication: () => setShowCreatePrompt(true),\n ...(selectedApplicationId !== undefined && { selectedApplicationId }),\n ...(selectedApplicationName !== undefined && { selectedApplicationName }),\n });\n\n const canvasToolbar = (\n <CanvasToolbar\n showArchived={showArchived}\n onToggleArchived={() => setShowArchived(!showArchived)}\n onResetViewport={resetViewport}\n startSlot={\n <WorkspaceSelector\n workspaces={workspaces}\n activeWorkspace={activeWorkspace}\n onSelect={setActiveWorkspace}\n onRequestCreate={() => setCreateWorkspaceOpen(true)}\n onRequestRename={() => setRenameWorkspaceOpen(true)}\n onRequestDelete={(id) => {\n setPendingDeleteWorkspaceId(id);\n setDeleteWorkspaceOpen(true);\n }}\n onManage={() => setManageWorkspaceOpen(true)}\n />\n }\n />\n );\n\n return (\n <>\n <FeaturesCanvas\n nodes={showCanvas ? displayNodes : []}\n edges={showCanvas ? workspaceFilteredEdges : []}\n selectedFeatureId={selectedFeatureId}\n selectedRepository={selectedRepository}\n defaultViewport={defaultViewport}\n onNodesChange={onNodesChange}\n onConnect={handleConnect}\n onAddFeature={handleAddFeature}\n onNodeClick={handleNodeClick}\n onPaneClick={handleClearDrawers}\n onMoveEnd={handleMoveEnd}\n toolbar={canvasToolbar}\n showToolbarOnEmpty={workspaceFilteredEmpty}\n emptyState={emptyStateNode}\n />\n {/* Collaboration onboarding — top-right overlay, shown once per browser profile */}\n {featureFlags.collaboration ? (\n <div className=\"pointer-events-none absolute inset-x-0 top-14 z-10 flex justify-end px-4\">\n <CollaborationOnboarding\n apps={collaborationApps}\n repos={collaborationRepos}\n features={collaborationFeatures}\n className=\"pointer-events-auto w-full max-w-md\"\n />\n </div>\n ) : null}\n {/* (+) FAB — bottom-left, moves with sidebar */}\n {showCanvas ? <CreateFab actions={fabActions} /> : null}\n <NewProjectDialog\n open={workspaceNewProjectOpen}\n onOpenChange={setWorkspaceNewProjectOpen}\n onCreated={(path) => addRepoAndFocus(path)}\n />\n <ManageWorkspaceDialog\n open={manageWorkspaceOpen}\n onOpenChange={setManageWorkspaceOpen}\n workspace={activeWorkspace}\n allNodes={nodes}\n onSave={(members) => setWorkspaceMembers(activeWorkspace.id, members)}\n />\n <WorkspaceNameDialog\n open={createWorkspaceOpen}\n onOpenChange={setCreateWorkspaceOpen}\n title=\"New workspace\"\n description=\"Create a workspace to filter the canvas to a specific set of repositories and features.\"\n confirmLabel=\"Create\"\n onConfirm={(name) => {\n createWorkspace(name);\n setManageWorkspaceOpen(true);\n }}\n />\n <WorkspaceNameDialog\n open={renameWorkspaceOpen}\n onOpenChange={setRenameWorkspaceOpen}\n title=\"Rename workspace\"\n initialValue={activeWorkspace.name}\n confirmLabel=\"Rename\"\n onConfirm={(name) => renameWorkspace(activeWorkspace.id, name)}\n />\n <AlertDialog\n open={deleteWorkspaceOpen}\n onOpenChange={(open) => {\n setDeleteWorkspaceOpen(open);\n if (!open) setPendingDeleteWorkspaceId(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete workspace?</AlertDialogTitle>\n <AlertDialogDescription>\n This will permanently remove the workspace “\n {workspaces.find((w) => w.id === pendingDeleteWorkspaceId)?.name ??\n activeWorkspace.name}\n ”. The repositories and features themselves are not affected.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n if (pendingDeleteWorkspaceId) {\n deleteWorkspace(pendingDeleteWorkspaceId);\n setPendingDeleteWorkspaceId(null);\n }\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* Full-screen create prompt overlay (replaces the old dialog) */}\n {showCreatePrompt ? (\n <div className=\"absolute inset-0 z-50\">\n <ControlCenterEmptyState\n onRepositorySelect={(path) => {\n setShowCreatePrompt(false);\n addRepoAndFocus(path);\n }}\n onApplicationCreated={(appId) => {\n // Navigate first — keep overlay mounted to avoid canvas flash.\n // The overlay unmounts when the route changes.\n router.push(`/application/${appId}`);\n }}\n onClose={() => setShowCreatePrompt(false)}\n className=\"bg-background\"\n />\n </div>\n ) : null}\n </>\n );\n}\n\n/** (+) FAB that tracks sidebar width via CSS var + transition.\n * When fabLayout.swapPosition is true, moves to the end side (right in LTR). */\nfunction CreateFab({ actions }: { actions: FloatingActionButtonAction[] }) {\n const { state } = useSidebar();\n const { i18n } = useTranslation('web');\n const { swapPosition } = useFabLayout();\n const isRtl = i18n.dir() === 'rtl';\n\n // Default: start side (left in LTR), tracking sidebar width\n // Swapped: end side (right in LTR), fixed 32px from edge\n if (swapPosition) {\n const positionStyle: React.CSSProperties = isRtl\n ? {\n left: 'calc(var(--sidebar-width-icon) + 32px)',\n transition: 'left 200ms ease-in-out',\n }\n : { right: '32px', transition: 'right 200ms ease-in-out' };\n\n return (\n <FloatingActionButton actions={actions} className=\"!fixed bottom-6\" style={positionStyle} />\n );\n }\n\n // Sidebar expanded = var(--sidebar-width) = 16rem, collapsed = var(--sidebar-width-icon) = 3rem\n // Position just outside the sidebar edge with 16px gap\n const offset =\n state === 'expanded'\n ? 'calc(var(--sidebar-width) + 32px)'\n : 'calc(var(--sidebar-width-icon) + 32px)';\n\n const positionStyle: React.CSSProperties = isRtl\n ? { right: offset, transition: 'right 200ms ease-in-out' }\n : { left: offset, transition: 'left 200ms ease-in-out' };\n\n return (\n <FloatingActionButton actions={actions} className=\"!fixed bottom-6\" style={positionStyle} />\n );\n}\n","/**\n * Build the action list for the (+) FloatingActionButton on the control\n * center. Extracted from control-center-inner.tsx so the parent component\n * stays focused on graph state + rendering.\n */\n\nimport { useMemo } from 'react';\nimport {\n ClipboardList,\n FolderOpen,\n FolderPlus,\n GitBranch,\n Github,\n LayoutGrid,\n Sparkles,\n} from 'lucide-react';\nimport type { useRouter } from 'next/navigation';\nimport { useTranslation } from 'react-i18next';\n\nimport { BuildMode } from '@shepai/core/domain/generated/output';\nimport type { FloatingActionButtonAction } from '@/components/common/floating-action-button';\nimport { buildCreateUrl } from '@/lib/url-params';\n\ninterface UseFabActionsParams {\n router: ReturnType<typeof useRouter>;\n clickSound: { play: () => void };\n guardedNavigate: (fn: () => void) => void;\n handlePickFolder: () => void;\n onNewProject: () => void;\n onNewApplication: () => void;\n /** Domain UUID of the application currently scoped on the canvas — when\n * exactly one ApplicationNode is selected/visible, the FAB exposes an\n * extra \"New SDD feature for <app>\" item that opens the create drawer\n * pre-scoped to this application in spec mode. Undefined disables the\n * action; the rest of the FAB items are unconditional. */\n selectedApplicationId?: string;\n /** Display name of the selected application — used purely for the\n * i18n interpolation of the FAB item label. */\n selectedApplicationName?: string;\n}\n\nexport function useFabActions({\n router,\n clickSound,\n guardedNavigate,\n handlePickFolder,\n onNewProject,\n onNewApplication,\n selectedApplicationId,\n selectedApplicationName,\n}: UseFabActionsParams): FloatingActionButtonAction[] {\n const { t } = useTranslation('web');\n\n return useMemo<FloatingActionButtonAction[]>(() => {\n const actions: FloatingActionButtonAction[] = [\n {\n id: 'new-project',\n label: 'New project',\n icon: <FolderPlus className=\"h-4 w-4\" />,\n onClick: () => {\n clickSound.play();\n onNewProject();\n },\n },\n {\n id: 'new-feature',\n label: t('fab.newFeature'),\n icon: <Sparkles className=\"h-4 w-4\" />,\n onClick: () => {\n clickSound.play();\n guardedNavigate(() => router.push('/create'));\n },\n },\n {\n id: 'add-local-repo',\n label: t('fab.localFolder'),\n icon: <FolderOpen className=\"h-4 w-4\" />,\n onClick: handlePickFolder,\n },\n {\n id: 'new-application',\n label: t('fab.newApplication'),\n icon: <LayoutGrid className=\"h-4 w-4\" />,\n onClick: onNewApplication,\n },\n ];\n if (selectedApplicationId) {\n actions.push({\n id: 'new-sdd-feature-for-app',\n label: t('fab.newSddForApp', { appName: selectedApplicationName ?? '' }),\n icon: <ClipboardList className=\"h-4 w-4\" />,\n onClick: () => {\n clickSound.play();\n guardedNavigate(() =>\n router.push(\n buildCreateUrl({\n applicationId: selectedApplicationId,\n mode: BuildMode.Spec,\n })\n )\n );\n },\n });\n }\n actions.push({\n id: 'adopt-branch',\n label: t('fab.adoptBranch'),\n icon: <GitBranch className=\"h-4 w-4\" />,\n onClick: () => {\n guardedNavigate(() => router.push('/adopt'));\n },\n });\n actions.push({\n id: 'add-github-repo',\n label: t('fab.fromGithub'),\n icon: <Github className=\"h-4 w-4\" />,\n onClick: () => {\n window.dispatchEvent(new CustomEvent('shep:open-github-import'));\n },\n });\n return actions;\n }, [\n t,\n clickSound,\n guardedNavigate,\n router,\n handlePickFolder,\n onNewProject,\n onNewApplication,\n selectedApplicationId,\n selectedApplicationName,\n ]);\n}\n","import createLucideIcon from '../createLucideIcon';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [\n ['path', { d: 'M8 3H5a2 2 0 0 0-2 2v3', key: '1dcmit' }],\n ['path', { d: 'M21 8V5a2 2 0 0 0-2-2h-3', key: '1e4gt3' }],\n ['path', { d: 'M3 16v3a2 2 0 0 0 2 2h3', key: 'wsl5sc' }],\n ['path', { d: 'M16 21h3a2 2 0 0 0 2-2v-3', key: '18trek' }],\n];\n\n/**\n * @component @name Maximize\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview  - https://lucide.dev/icons/maximize\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Maximize = createLucideIcon('maximize', __iconNode);\n\nexport default Maximize;\n","import createLucideIcon from '../createLucideIcon';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [\n ['circle', { cx: '11', cy: '11', r: '8', key: '4ej97u' }],\n ['line', { x1: '21', x2: '16.65', y1: '21', y2: '16.65', key: '13gj7c' }],\n ['line', { x1: '11', x2: '11', y1: '8', y2: '14', key: '1vmskp' }],\n ['line', { x1: '8', x2: '14', y1: '11', y2: '11', key: 'durymu' }],\n];\n\n/**\n * @component @name ZoomIn\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview  - https://lucide.dev/icons/zoom-in\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ZoomIn = createLucideIcon('zoom-in', __iconNode);\n\nexport default ZoomIn;\n","import createLucideIcon from '../createLucideIcon';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [\n ['circle', { cx: '11', cy: '11', r: '8', key: '4ej97u' }],\n ['line', { x1: '21', x2: '16.65', y1: '21', y2: '16.65', key: '13gj7c' }],\n ['line', { x1: '8', x2: '14', y1: '11', y2: '11', key: 'durymu' }],\n];\n\n/**\n * @component @name ZoomOut\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview  - https://lucide.dev/icons/zoom-out\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ZoomOut = createLucideIcon('zoom-out', __iconNode);\n\nexport default ZoomOut;\n","/**\n * Re-fit the React Flow viewport when the active workspace's visible node\n * set changes (switching workspaces, or changing the active workspace's\n * membership via the Manage dialog).\n *\n * Intentionally scoped:\n * - Skips the first run so we don't override the persisted viewport on mount.\n * - Skips the default workspace, which shows everything and owns the\n * persisted viewport via useViewportPersistence.\n * - Skips empty workspaces — there's nothing to fit.\n * - Defers fitView to the next tick so React Flow has committed the new\n * node set before measuring.\n */\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport type { useReactFlow } from '@xyflow/react';\n\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\n\ntype FitViewFn = ReturnType<typeof useReactFlow>['fitView'];\n\ninterface ActiveWorkspaceLike {\n id: string;\n}\n\nconst AUTO_FOCUS_OPTIONS = {\n maxZoom: 1.0,\n padding: 0.5,\n duration: 500,\n} as const;\n\nexport function useWorkspaceFitView(params: {\n activeWorkspace: ActiveWorkspaceLike;\n isDefaultActive: boolean;\n workspaceFilteredNodes: CanvasNodeType[];\n fitView: FitViewFn;\n}): void {\n const { activeWorkspace, isDefaultActive, workspaceFilteredNodes, fitView } = params;\n\n const fingerprint = useMemo(() => {\n if (isDefaultActive) return 'default';\n const ids = workspaceFilteredNodes\n .map((n) => n.id)\n .sort()\n .join(',');\n return `${activeWorkspace.id}:${ids}`;\n }, [isDefaultActive, activeWorkspace.id, workspaceFilteredNodes]);\n\n const prevFingerprintRef = useRef<string | null>(null);\n\n useEffect(() => {\n const prev = prevFingerprintRef.current;\n prevFingerprintRef.current = fingerprint;\n if (prev === null) return;\n if (prev === fingerprint) return;\n if (isDefaultActive) return;\n if (workspaceFilteredNodes.length === 0) return;\n\n const t = setTimeout(() => {\n fitView(AUTO_FOCUS_OPTIONS);\n }, 0);\n return () => clearTimeout(t);\n }, [fingerprint, isDefaultActive, workspaceFilteredNodes.length, fitView]);\n}\n","/**\n * Wire global window events used by the control center canvas to the\n * appropriate handlers. The canvas listens for cross-component requests\n * dispatched as CustomEvents:\n *\n * - shep:add-repository → addRepoAndFocus(path)\n * - shep:feature-created → createFeatureNode(...)\n * - shep:feature-delete-requested → handleDeleteFeature(...)\n * - shep:feature-archive-requested → handleArchiveFeature(...)\n * - shep:feature-unarchive-requested → handleUnarchiveFeature(...)\n *\n * Extracted from control-center-inner.tsx so the parent component stays\n * focused on graph state + rendering, not event-bus plumbing.\n */\n\nimport { useEffect } from 'react';\n\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\n\nexport type CreateFeatureNodeFn = (\n sourceNodeId: string | null,\n dataOverride?: Partial<FeatureNodeData>,\n edgeType?: string\n) => string;\n\nexport interface CanvasEventListenerHandlers {\n addRepoAndFocus: (path: string) => void;\n createFeatureNode: CreateFeatureNodeFn;\n nodes: CanvasNodeType[];\n handleDeleteFeature: (\n featureId: string,\n cleanup?: boolean,\n cascadeDelete?: boolean,\n closePr?: boolean\n ) => void;\n handleArchiveFeature: (featureId: string) => void;\n handleUnarchiveFeature: (featureId: string) => void;\n}\n\nexport function useCanvasEventListeners(handlers: CanvasEventListenerHandlers): void {\n const {\n addRepoAndFocus,\n createFeatureNode,\n nodes,\n handleDeleteFeature,\n handleArchiveFeature,\n handleUnarchiveFeature,\n } = handlers;\n\n // shep:add-repository — top-bar \"add folder\" button\n useEffect(() => {\n const handler = (e: Event) => {\n const path = (e as CustomEvent<{ path: string }>).detail.path;\n addRepoAndFocus(path);\n };\n window.addEventListener('shep:add-repository', handler);\n return () => window.removeEventListener('shep:add-repository', handler);\n }, [addRepoAndFocus]);\n\n // shep:feature-created — fired by the create drawer with the real server feature ID\n useEffect(() => {\n const handler = (e: Event) => {\n const detail = (\n e as CustomEvent<{\n featureId: string;\n name: string;\n description?: string;\n repositoryPath: string;\n parentId?: string;\n applicationId?: string;\n }>\n ).detail;\n\n // When parentId is provided, attach to the parent feature node via a\n // dependency edge instead of the repo node.\n if (detail.parentId) {\n const parentNodeId = `feat-${detail.parentId}`;\n createFeatureNode(\n parentNodeId,\n {\n state: 'creating',\n featureId: detail.featureId,\n name: detail.name,\n description: detail.description,\n repositoryPath: detail.repositoryPath,\n },\n 'dependencyEdge'\n );\n return;\n }\n\n // When applicationId is provided, attach to the matching application\n // node via a dependency edge so the optimistic feature renders as a\n // child of its application — never as a sibling of a virtual repo.\n // The `applicationId` data field also lets `derive-graph` keep the\n // app→feature edge stable across reconciliation.\n if (detail.applicationId) {\n const appNodeId = `app-${detail.applicationId}`;\n const appNode = nodes.find((n) => n.id === appNodeId && n.type === 'applicationNode');\n if (appNode) {\n createFeatureNode(\n appNodeId,\n {\n state: 'running',\n featureId: detail.featureId,\n name: detail.name,\n description: detail.description,\n repositoryPath: detail.repositoryPath,\n applicationId: detail.applicationId,\n },\n 'dependencyEdge'\n );\n return;\n }\n }\n\n const repoNode = nodes.find(\n (n) =>\n n.type === 'repositoryNode' &&\n (n.data as { repositoryPath?: string }).repositoryPath === detail.repositoryPath\n );\n\n createFeatureNode(repoNode?.id ?? null, {\n state: 'running',\n featureId: detail.featureId,\n name: detail.name,\n description: detail.description,\n repositoryPath: detail.repositoryPath,\n });\n };\n window.addEventListener('shep:feature-created', handler);\n return () => window.removeEventListener('shep:feature-created', handler);\n }, [nodes, createFeatureNode]);\n\n // shep:feature-delete-requested — fired from the feature drawer\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId, cleanup, cascadeDelete, closePr } = (\n e as CustomEvent<{\n featureId: string;\n cleanup?: boolean;\n cascadeDelete?: boolean;\n closePr?: boolean;\n }>\n ).detail;\n handleDeleteFeature(featureId, cleanup, cascadeDelete, closePr);\n };\n window.addEventListener('shep:feature-delete-requested', handler);\n return () => window.removeEventListener('shep:feature-delete-requested', handler);\n }, [handleDeleteFeature]);\n\n // shep:feature-archive-requested — fired from the feature drawer\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;\n handleArchiveFeature(featureId);\n };\n window.addEventListener('shep:feature-archive-requested', handler);\n return () => window.removeEventListener('shep:feature-archive-requested', handler);\n }, [handleArchiveFeature]);\n\n // shep:feature-unarchive-requested — fired from the feature drawer\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;\n handleUnarchiveFeature(featureId);\n };\n window.addEventListener('shep:feature-unarchive-requested', handler);\n return () => window.removeEventListener('shep:feature-unarchive-requested', handler);\n }, [handleUnarchiveFeature]);\n}\n"],"names":[],"mappings":"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","ignoreList":[27,28,29]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts","../../../../../../../src/presentation/web/app/actions/data%3A2d0c6c%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/app/actions/data%3A060abd%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/hooks/use-graph-state.ts","../../../../../../../src/presentation/web/lib/derive-graph.ts","../../../../../../../src/presentation/web/components/common/repository-node/repository-drawer.tsx","../../../../../../../src/presentation/web/components/common/application-node/application-node.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/dependency-edge.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/features-canvas.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/canvas-toolbar.tsx","../../../../../../../src/presentation/web/hooks/use-workspaces.ts","../../../../../../../src/presentation/web/components/features/features-canvas/workspace-selector.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/manage-workspace-dialog.tsx","../../../../../../../src/presentation/web/components/features/features-canvas/workspace-name-dialog.tsx","../../../../../../../src/presentation/web/hooks/use-selected-feature-id.ts","../../../../../../../src/presentation/web/hooks/use-selected-repository.ts","../../../../../../../src/presentation/web/hooks/use-viewport-persistence.ts","../../../../../../../src/presentation/web/app/actions/data%3A32721d%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/app/actions/data%3A6da3ef%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/components/features/control-center/control-center.tsx","../../../../../../../src/presentation/web/app/actions/data%3A83b7bc%20%3Ctext/javascript%3E","../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx","../../../../../../../src/presentation/web/components/features/control-center/welcome-agent-setup.tsx","../../../../../../../src/presentation/web/components/features/control-center/control-center-onboarding.tsx","../../../../../../../src/presentation/web/components/features/control-center/collaboration-onboarding.tsx","../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx","../../../../../../../src/presentation/web/components/features/control-center/use-fab-actions.tsx","../../../../../../../node_modules/.pnpm/lucide-react%400.563.0_react%4019.2.4/node_modules/lucide-react/src/icons/maximize.ts","../../../../../../../node_modules/.pnpm/lucide-react%400.563.0_react%4019.2.4/node_modules/lucide-react/src/icons/zoom-in.ts","../../../../../../../node_modules/.pnpm/lucide-react%400.563.0_react%4019.2.4/node_modules/lucide-react/src/icons/zoom-out.ts","../../../../../../../src/presentation/web/components/features/control-center/use-workspace-fit-view.ts","../../../../../../../src/presentation/web/components/features/control-center/use-canvas-event-listeners.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useRouter } from 'next/navigation';\nimport { toast } from 'sonner';\nimport type { Connection, Edge, NodeChange } from '@xyflow/react';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport {\n layoutWithDagre,\n getCanvasLayoutDefaults,\n type LayoutDirection,\n} from '@/lib/layout-with-dagre';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\nimport { archiveFeature } from '@/app/actions/archive-feature';\nimport { deleteFeature } from '@/app/actions/delete-feature';\nimport { resumeFeature } from '@/app/actions/resume-feature';\nimport { startFeature } from '@/app/actions/start-feature';\nimport { stopFeature } from '@/app/actions/stop-feature';\nimport { unarchiveFeature } from '@/app/actions/unarchive-feature';\nimport { addRepository } from '@/app/actions/add-repository';\nimport { deleteRepository } from '@/app/actions/delete-repository';\nimport { deleteApplication } from '@/app/actions/delete-application';\nimport { getFeatureMetadata } from '@/app/actions/get-feature-metadata';\nimport { useAgentEventsContext } from '@/hooks/agent-events-provider';\nimport { useDeploymentStatusContext } from '@/hooks/deployment-status-provider';\nimport { useSoundAction } from '@/hooks/use-sound-action';\nimport { createLogger } from '@/lib/logger';\nimport { featureIdForApplication } from '@shepai/core/domain/shared/feature-id';\n\nimport {\n mapEventTypeToState,\n resolveSseEventUpdates,\n} from '@/components/common/feature-node/derive-feature-state';\nimport { useGraphState, type GraphCallbacks } from '@/hooks/use-graph-state';\nimport type { FeatureEntry } from '@/lib/derive-graph';\n\nconst log = createLogger('[Polling]');\nconst POLL_INTERVAL_MS = 15_000;\n\nexport interface ControlCenterState {\n nodes: CanvasNodeType[];\n edges: Edge[];\n onNodesChange: (changes: NodeChange<CanvasNodeType>[]) => void;\n handleConnect: (connection: Connection) => void;\n handleAddRepository: (path: string) => {\n wasEmpty: boolean;\n repoPath: string;\n tempNodeId: string;\n };\n handleLayout: (direction: LayoutDirection) => void;\n handleArchiveFeature: (featureId: string) => void;\n handleDeleteFeature: (\n featureId: string,\n cleanup?: boolean,\n cascadeDelete?: boolean,\n closePr?: boolean\n ) => void;\n handleRetryFeature: (featureId: string) => void;\n handleStartFeature: (featureId: string) => void;\n handleStopFeature: (featureId: string) => void;\n handleUnarchiveFeature: (featureId: string) => void;\n handleDeleteRepository: (\n repositoryId: string,\n options?: { deleteFromDisk?: boolean }\n ) => Promise<void>;\n handleDeleteApplication: (applicationId: string) => Promise<void>;\n createFeatureNode: (\n sourceNodeId: string | null,\n dataOverride?: Partial<FeatureNodeData>,\n edgeType?: string\n ) => string;\n /** Add an application node to the canvas optimistically. */\n addApplication: (nodeId: string, data: ApplicationNodeData) => void;\n /** Whether archived features are shown on the canvas. */\n showArchived: boolean;\n /** Toggle archived feature visibility. */\n setShowArchived: (show: boolean) => void;\n /** Stable lookup: repositoryPath for a feature node. */\n getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;\n /** Stable lookup: repository data by nodeId. */\n getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;\n /** Sync callbacks into derived node data (does not trigger re-render). */\n setCallbacks: (callbacks: GraphCallbacks) => void;\n}\n\n/** Must match the message string emitted by the SSE route in agent-events/route.ts */\nconst METADATA_UPDATED_MESSAGE = 'Feature metadata updated';\n\nlet nextFeatureId = 0;\nlet nextRepoTempId = 0;\n\nexport function useControlCenterState(\n initialNodes: CanvasNodeType[],\n initialEdges: Edge[]\n): ControlCenterState {\n const router = useRouter();\n const deleteSound = useSoundAction('delete');\n const createSound = useSoundAction('create');\n\n // Archive toggle: persists during session, resets on page reload (FR-10)\n const [showArchived, setShowArchived] = useState(false);\n\n const {\n nodes,\n edges,\n reconcile,\n updateFeature,\n addPendingFeature,\n removeFeature,\n restoreFeature,\n addRepository: addRepositoryToMap,\n removeRepository,\n replaceRepository,\n getFeatureRepositoryPath,\n getRepositoryData,\n getRepoMapSize,\n addApplication: addApplicationToMap,\n removeApplication,\n setCallbacks,\n beginMutation,\n endMutation,\n isMutating,\n } = useGraphState(initialNodes, initialEdges, showArchived);\n\n // Refs for stable access to latest nodes/edges without callback recreation\n const nodesRef = useRef(nodes);\n const edgesRef = useRef(edges);\n useEffect(() => {\n nodesRef.current = nodes;\n edgesRef.current = edges;\n }, [nodes, edges]);\n\n // Sync server props into domain Maps when initialNodes/initialEdges change.\n // Keyed by a stable string so we don't re-reconcile on every render.\n const initialNodeKey = useMemo(\n () =>\n initialNodes\n .map((n) => n.id)\n .sort()\n .join(','),\n [initialNodes]\n );\n const initialDataKey = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'featureNode')\n .map((n) => {\n const d = n.data as FeatureNodeData;\n return `${n.id}:${d.state}:${d.lifecycle}`;\n })\n .sort()\n .join(','),\n [initialNodes]\n );\n\n const prevReconcileKey = useRef('');\n\n useEffect(() => {\n const key = `${initialNodeKey}|${initialDataKey}`;\n if (key !== prevReconcileKey.current) {\n prevReconcileKey.current = key;\n reconcile(initialNodes, initialEdges);\n }\n }, [initialNodeKey, initialDataKey, initialNodes, initialEdges, reconcile]);\n\n // Track previous feature states for fallback notifications\n const prevFeatureStatesRef = useRef<Map<string, FeatureNodeData['state']>>(new Map());\n\n const { events, connectionStatus } = useAgentEventsContext();\n const { store: deploymentStore } = useDeploymentStatusContext();\n\n useEffect(() => {\n const prevStates = prevFeatureStatesRef.current;\n for (const node of initialNodes) {\n if (node.type !== 'featureNode') continue;\n const data = node.data as FeatureNodeData;\n const prev = prevStates.get(node.id);\n if (prev !== undefined && prev !== data.state) {\n const sseAlreadyCovered = events.some(\n (e) => e.featureId === data.featureId && mapEventTypeToState(e.eventType) === data.state\n );\n if (!sseAlreadyCovered) {\n if (data.state === 'done') {\n toast.success(data.name, { description: 'Feature completed!' });\n } else if (data.state === 'action-required') {\n toast.warning(data.name, {\n description: 'Waiting for your approval',\n action: {\n label: 'Review',\n onClick: () => router.push(`/feature/${data.featureId}`),\n },\n });\n } else if (data.state === 'error') {\n toast.error(data.name, { description: data.errorMessage ?? 'Agent failed' });\n }\n }\n }\n prevStates.set(node.id, data.state);\n }\n }, [initialDataKey, initialNodes, events, router]);\n\n // SSE effect: only state + lifecycle updates\n const processedEventCountRef = useRef(0);\n\n useEffect(() => {\n // Clamp cursor if events were pruned\n if (processedEventCountRef.current > events.length) {\n processedEventCountRef.current = 0;\n }\n if (events.length <= processedEventCountRef.current) return;\n const newEvents = events.slice(processedEventCountRef.current);\n processedEventCountRef.current = events.length;\n\n for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {\n if (state !== undefined || lifecycle !== undefined) {\n const nodeId = `feat-${featureId}`;\n const existingNode = nodesRef.current.find((n) => n.id === nodeId);\n const existingState = existingNode\n ? (existingNode.data as FeatureNodeData).state\n : undefined;\n\n // Skip SSE updates for features in 'deleting' state — the optimistic\n // delete state must not be overwritten by stale SSE events (e.g. agent\n // cancellation emitting AgentFailed during the soft-delete window).\n if (existingState === 'deleting') continue;\n\n // Skip SSE error events during mutation cooldown — after approve/reject\n // the agent may still report AgentFailed from the previous run before\n // the resume kicks in. The optimistic 'running' state must not be\n // overwritten by stale error events during this transition window.\n if (state === 'error' && isMutating() && existingState === 'running') continue;\n\n updateFeature(nodeId, {\n ...(state !== undefined && { state }),\n ...(lifecycle !== undefined && { lifecycle }),\n });\n }\n }\n }, [events, updateFeature, isMutating]);\n\n // Listen for optimistic approval/rejection events from the drawer (fires before SSE arrives).\n // Uses beginMutation + endMutation to prevent stale poll/reconcile data from overwriting\n // the optimistic 'running' state during the transition window (avoids brief \"Something went wrong\" flash).\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;\n beginMutation();\n updateFeature(`feat-${featureId}`, { state: 'running' });\n endMutation();\n };\n window.addEventListener('shep:feature-approved', handler);\n return () => window.removeEventListener('shep:feature-approved', handler);\n }, [updateFeature, beginMutation, endMutation]);\n\n // Separate effect: fetch metadata (name + description) when SSE reports it changed\n const metadataFetchedRef = useRef<Set<string>>(new Set());\n const processedMetadataCountRef = useRef(0);\n\n useEffect(() => {\n // Clamp cursor if events were pruned\n if (processedMetadataCountRef.current > events.length) {\n processedMetadataCountRef.current = 0;\n }\n if (events.length <= processedMetadataCountRef.current) return;\n const newEvents = events.slice(processedMetadataCountRef.current);\n processedMetadataCountRef.current = events.length;\n\n for (const event of newEvents) {\n if (event.message !== METADATA_UPDATED_MESSAGE) continue;\n if (metadataFetchedRef.current.has(event.featureId)) continue;\n metadataFetchedRef.current.add(event.featureId);\n\n const nodeId = `feat-${event.featureId}`;\n getFeatureMetadata(event.featureId)\n .then((meta) => {\n if (meta) {\n updateFeature(nodeId, { name: meta.name, description: meta.description });\n }\n })\n .catch(() => {\n // Silent: metadata fetch failure is non-critical\n });\n }\n }, [events, updateFeature]);\n\n // --- Polling fallback: only run as recovery when SSE is unhealthy ---\n // While SSE is connected, every state change is delivered via the stream\n // and reconciliation happens on the next render — there's no need to\n // re-fetch the whole graph. Polling only kicks in when SSE has been\n // disconnected or stuck connecting (e.g. server restarted, network\n // glitch, service worker not yet activated).\n const sseHealthyRef = useRef(connectionStatus === 'connected');\n sseHealthyRef.current = connectionStatus === 'connected';\n\n useEffect(() => {\n log.debug(`polling enabled (${POLL_INTERVAL_MS}ms recovery interval)`);\n\n const timer = setInterval(async () => {\n // Skip when tab is hidden — no point polling for a user who isn't looking.\n if (document.hidden) return;\n // Skip while SSE is healthy — the stream is the source of truth.\n if (sseHealthyRef.current) return;\n // Skip fetch entirely while a mutation is in-flight — the response\n // would contain pre-mutation data that reconcile would discard anyway.\n if (isMutating()) return;\n\n try {\n // Use a plain fetch instead of a server action so the poll\n // doesn't trigger the Next.js \"Rendering…\" indicator.\n const res = await fetch('/api/graph-data');\n if (!res.ok) throw new Error(`status ${res.status}`);\n const {\n nodes: freshNodes,\n edges: freshEdges,\n deployments: freshDeployments,\n } = await res.json();\n reconcile(freshNodes, freshEdges);\n if (Array.isArray(freshDeployments)) {\n deploymentStore.hydrate(freshDeployments);\n }\n } catch {\n log.warn('recovery poll failed — will retry next interval');\n }\n }, POLL_INTERVAL_MS);\n\n return () => {\n log.debug('polling disabled');\n clearInterval(timer);\n };\n }, [reconcile, isMutating, deploymentStore]);\n\n // onNodesChange is a no-op: nodes are derived from domain Maps.\n // Since nodesDraggable=false and elementsSelectable=false, only React Flow's\n // internal replace/dimensions changes come through — we ignore them all.\n const onNodesChange = useCallback((_changes: NodeChange<CanvasNodeType>[]) => {\n // Intentional no-op: domain Maps are the source of truth.\n }, []);\n\n const handleConnect = useCallback((_connection: Connection) => {\n // Connections are managed via domain operations, not direct edge manipulation.\n }, []);\n\n const createFeatureNode = useCallback(\n (\n sourceNodeId: string | null,\n dataOverride?: Partial<FeatureNodeData>,\n edgeType?: string\n ): string => {\n // Use real feature ID when available (from server), otherwise temp ID\n const id = dataOverride?.featureId\n ? `feat-${dataOverride.featureId}`\n : `feature-${Date.now()}-${nextFeatureId++}`;\n const newFeatureData: FeatureNodeData = {\n name: dataOverride?.name ?? 'New Feature',\n description: dataOverride?.description ?? 'Describe what this feature does',\n featureId: dataOverride?.featureId ?? `#${id.slice(-4)}`,\n lifecycle: 'requirements',\n state: dataOverride?.state ?? 'running',\n progress: 0,\n repositoryPath: dataOverride?.repositoryPath ?? '',\n branch: dataOverride?.branch ?? '',\n ...(dataOverride?.applicationId && { applicationId: dataOverride.applicationId }),\n };\n\n const parentNodeId = edgeType === 'dependencyEdge' && sourceNodeId ? sourceNodeId : undefined;\n\n addPendingFeature(id, newFeatureData, parentNodeId);\n\n return id;\n },\n [addPendingFeature]\n );\n\n const handleRetryFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n // Optimistic: switch to running state\n beginMutation();\n updateFeature(nodeId, { state: 'running' });\n\n resumeFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'error' });\n toast.error(result.error);\n } else {\n toast.success('Feature resumed');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'error' });\n toast.error('Failed to resume feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleStartFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n // Optimistic: switch to running state\n beginMutation();\n updateFeature(nodeId, { state: 'running' });\n\n startFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'pending' });\n toast.error(result.error);\n } else {\n toast.success('Feature started');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'pending' });\n toast.error('Failed to start feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleStopFeature = useCallback(\n (featureId: string) => {\n beginMutation();\n\n stopFeature(featureId)\n .then((result) => {\n if (result.error) {\n toast.error(result.error);\n } else {\n toast.success('Agent stopped');\n }\n })\n .catch(() => {\n toast.error('Failed to stop agent');\n })\n .finally(() => endMutation());\n },\n [beginMutation, endMutation]\n );\n\n const handleArchiveFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n beginMutation();\n updateFeature(nodeId, { state: 'archived' });\n\n archiveFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'done' });\n toast.error(result.error);\n } else {\n toast.success('Feature archived');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'done' });\n toast.error('Failed to archive feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleUnarchiveFeature = useCallback(\n (featureId: string) => {\n const nodeId = `feat-${featureId}`;\n beginMutation();\n updateFeature(nodeId, { state: 'done' });\n\n unarchiveFeature(featureId)\n .then((result) => {\n if (result.error) {\n updateFeature(nodeId, { state: 'archived' });\n toast.error(result.error);\n } else {\n toast.success('Feature unarchived');\n }\n })\n .catch(() => {\n updateFeature(nodeId, { state: 'archived' });\n toast.error('Failed to unarchive feature');\n })\n .finally(() => endMutation());\n },\n [updateFeature, beginMutation, endMutation]\n );\n\n const handleDeleteFeature = useCallback(\n (featureId: string, cleanup?: boolean, cascadeDelete?: boolean, closePr?: boolean) => {\n const nodeId = `feat-${featureId}`;\n const shouldCascade = cascadeDelete === true;\n\n // Collect all descendant feature node IDs (children, grandchildren, etc.)\n const descendants: string[] = [];\n if (shouldCascade) {\n const queue = [nodeId];\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const edge of edgesRef.current) {\n if (edge.type === 'dependencyEdge' && edge.source === current) {\n descendants.push(edge.target);\n queue.push(edge.target);\n }\n }\n }\n }\n\n // Snapshot current states for rollback (parent + descendants)\n const prevStates = new Map<string, FeatureNodeData['state']>();\n for (const nid of [nodeId, ...descendants]) {\n const node = nodesRef.current.find((n) => n.id === nid);\n if (node) {\n prevStates.set(nid, (node.data as FeatureNodeData).state);\n }\n }\n\n // Optimistic: show \"deleting\" state on parent (and descendants if cascading)\n beginMutation();\n updateFeature(nodeId, { state: 'deleting' });\n for (const childId of descendants) {\n updateFeature(childId, { state: 'deleting' });\n }\n deleteSound.play();\n router.push('/control-center');\n\n deleteFeature(featureId, cleanup, cascadeDelete, closePr)\n .then((result) => {\n if (result.error) {\n // Rollback all to previous states\n for (const [nid, prevState] of prevStates) {\n if (prevState) updateFeature(nid, { state: prevState });\n }\n toast.error(result.error);\n } else {\n // Delete succeeded — remove features from the canvas. The polling\n // reconcile would eventually clean them up, but we remove them\n // explicitly so the user sees them disappear promptly.\n removeFeature(nodeId);\n for (const childId of descendants) {\n removeFeature(childId);\n }\n }\n })\n .catch(() => {\n for (const [nid, prevState] of prevStates) {\n if (prevState) updateFeature(nid, { state: prevState });\n }\n toast.error('Failed to delete feature');\n })\n .finally(() => endMutation());\n },\n [router, deleteSound, updateFeature, removeFeature, beginMutation, endMutation]\n );\n\n const handleDeleteRepository = useCallback(\n async (repositoryId: string, options?: { deleteFromDisk?: boolean }) => {\n const repoNodeId = `repo-${repositoryId}`;\n\n // Find children of this repo via edges\n const childFeatureIds = new Set(\n edgesRef.current.filter((e) => e.source === repoNodeId).map((e) => e.target)\n );\n\n // Snapshot for rollback\n const prevRepoData = getRepositoryData(repoNodeId);\n const childSnapshots = new Map<string, FeatureEntry>();\n for (const childId of childFeatureIds) {\n const childNode = nodesRef.current.find((n) => n.id === childId);\n if (childNode) {\n childSnapshots.set(childId, { nodeId: childId, data: childNode.data as FeatureNodeData });\n }\n }\n\n const rollback = () => {\n if (prevRepoData) addRepositoryToMap(repoNodeId, prevRepoData);\n for (const [childId, entry] of childSnapshots) {\n restoreFeature(childId, entry);\n }\n };\n\n // Optimistic: remove repo + children\n beginMutation();\n removeRepository(repoNodeId);\n for (const childId of childFeatureIds) {\n removeFeature(childId);\n }\n\n try {\n const result = await deleteRepository(repositoryId, {\n deleteFromDisk: options?.deleteFromDisk === true,\n });\n if (!result.success) {\n toast.error(result.error ?? 'Failed to remove repository');\n rollback();\n return;\n }\n deleteSound.play();\n } catch {\n toast.error('Failed to remove repository');\n rollback();\n } finally {\n endMutation();\n }\n },\n [\n deleteSound,\n removeRepository,\n removeFeature,\n addRepositoryToMap,\n restoreFeature,\n getRepositoryData,\n beginMutation,\n endMutation,\n ]\n );\n\n const handleDeleteApplication = useCallback(\n async (applicationId: string) => {\n const appNodeId = featureIdForApplication(applicationId);\n\n // Optimistic: remove application node\n beginMutation();\n removeApplication(appNodeId);\n deleteSound.play();\n\n try {\n const result = await deleteApplication(applicationId);\n if (result.error) {\n toast.error(result.error);\n // Rollback would require storing the previous data; for now we let\n // the next polling reconcile restore it if the delete actually failed.\n }\n } catch {\n toast.error('Failed to delete application');\n } finally {\n endMutation();\n }\n },\n [deleteSound, removeApplication, beginMutation, endMutation]\n );\n\n const handleLayout = useCallback(\n (direction: LayoutDirection) => {\n // Layout is applied via reconcile on next server prop update.\n // For immediate re-layout, we apply dagre and trigger a reconcile-like update.\n const result = layoutWithDagre(nodesRef.current, edgesRef.current, {\n ...getCanvasLayoutDefaults(),\n direction,\n });\n reconcile(result.nodes, result.edges);\n },\n [reconcile]\n );\n\n const handleAddRepository = useCallback(\n (path: string): { wasEmpty: boolean; repoPath: string; tempNodeId: string } => {\n const wasEmpty = getRepoMapSize() === 0;\n const tempId = `repo-temp-${++nextRepoTempId}`;\n const repoName =\n path\n .replace(/[\\\\/]+$/, '')\n .split(/[\\\\/]/)\n .pop() ?? path;\n\n beginMutation();\n addRepositoryToMap(tempId, {\n name: repoName,\n repositoryPath: path,\n id: tempId,\n createdAt: Date.now(),\n gitInfoStatus: 'loading',\n });\n\n addRepository({ path, name: repoName })\n .then((result) => {\n if (result.error) {\n removeRepository(tempId);\n toast.error(result.error);\n return;\n }\n const repo = result.repository!;\n const realId = `repo-${repo.id}`;\n replaceRepository(tempId, realId, {\n name: repo.name,\n repositoryPath: repo.path,\n id: repo.id,\n createdAt:\n repo.createdAt instanceof Date ? repo.createdAt.getTime() : Number(repo.createdAt),\n });\n createSound.play();\n })\n .catch(() => {\n removeRepository(tempId);\n toast.error('Failed to add repository');\n })\n .finally(() => endMutation());\n\n return { wasEmpty, repoPath: path, tempNodeId: tempId };\n },\n [\n addRepositoryToMap,\n removeRepository,\n replaceRepository,\n createSound,\n getRepoMapSize,\n beginMutation,\n endMutation,\n ]\n );\n\n return {\n nodes,\n edges,\n onNodesChange,\n handleConnect,\n handleAddRepository,\n handleArchiveFeature,\n handleLayout,\n handleDeleteFeature,\n handleRetryFeature,\n handleStartFeature,\n handleStopFeature,\n handleUnarchiveFeature,\n handleDeleteRepository,\n handleDeleteApplication,\n createFeatureNode,\n addApplication: addApplicationToMap,\n showArchived,\n setShowArchived,\n getFeatureRepositoryPath,\n getRepositoryData,\n setCallbacks,\n };\n}\n","/* __next_internal_action_entry_do_not_use__ [{\"608cb7bed4e740de6ec1034873b198d85e0771cdfb\":\"deleteRepository\"},\"src/presentation/web/app/actions/delete-repository.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"608cb7bed4e740de6ec1034873b198d85e0771cdfb\",callServer,void 0,findSourceMapURL,\"deleteRepository\");export{$$RSC_SERVER_ACTION_0 as deleteRepository};","/* __next_internal_action_entry_do_not_use__ [{\"40127b07baac3bb5494e3d8ad7b721b35a467f4a93\":\"getFeatureMetadata\"},\"src/presentation/web/app/actions/get-feature-metadata.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"40127b07baac3bb5494e3d8ad7b721b35a467f4a93\",callServer,void 0,findSourceMapURL,\"getFeatureMetadata\");export{$$RSC_SERVER_ACTION_0 as getFeatureMetadata};","'use client';\n\nimport { useState, useMemo, useCallback, useRef, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { Edge, Position } from '@xyflow/react';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\nimport {\n deriveGraph,\n type FeatureEntry,\n type RepoEntry,\n type ApplicationEntry,\n type GraphCallbacks,\n} from '@/lib/derive-graph';\nimport { layoutWithDagre, getCanvasLayoutDefaults } from '@/lib/layout-with-dagre';\n\nexport type { GraphCallbacks } from '@/lib/derive-graph';\n\nexport interface UseGraphStateReturn {\n /** Derived React Flow nodes (from domain Maps). */\n nodes: CanvasNodeType[];\n /** Derived React Flow edges (from domain Maps). */\n edges: Edge[];\n /**\n * Reconcile domain Maps with fresh server data (new initialNodes/initialEdges).\n * Preserves pending (creating) nodes unless a matching real feature appears.\n * No-ops when a mutation is in-flight (see beginMutation/endMutation).\n */\n reconcile: (newNodes: CanvasNodeType[], newEdges: Edge[]) => void;\n /** Update a feature's state/lifecycle/name (e.g., from SSE events). */\n updateFeature: (featureNodeId: string, updates: FeatureDataUpdates) => void;\n /** Add a pending (optimistic) feature node (state='creating'). */\n addPendingFeature: (nodeId: string, data: FeatureNodeData, parentNodeId?: string) => void;\n /** Remove a pending feature node (e.g., on rollback). */\n removePendingFeature: (nodeId: string) => void;\n /** Remove a real feature node from the domain Map. */\n removeFeature: (nodeId: string) => void;\n /** Restore a previously removed feature (rollback). */\n restoreFeature: (nodeId: string, entry: FeatureEntry) => void;\n /** Add a repository node (may use a temp ID initially). */\n addRepository: (nodeId: string, data: RepositoryNodeData) => void;\n /** Remove a repository node. */\n removeRepository: (nodeId: string) => void;\n /** Replace a temp repo ID with the real one (atomic). */\n replaceRepository: (tempId: string, realId: string, data: RepositoryNodeData) => void;\n /** Stable lookup: get the repositoryPath for a feature node. */\n getFeatureRepositoryPath: (featureNodeId: string) => string | undefined;\n /** Stable lookup: get repository node data by nodeId. */\n getRepositoryData: (nodeId: string) => RepositoryNodeData | undefined;\n /** Stable lookup: get the current number of repositories in the domain Map. */\n getRepoMapSize: () => number;\n /** Add an application node. */\n addApplication: (nodeId: string, data: ApplicationNodeData) => void;\n /** Remove an application node. */\n removeApplication: (nodeId: string) => void;\n /** Update callbacks injected into node data (does NOT trigger re-render). */\n setCallbacks: (callbacks: GraphCallbacks) => void;\n /**\n * Signal that an optimistic mutation has started. While any mutation is\n * in-flight, `reconcile` becomes a no-op so stale poll data cannot\n * overwrite optimistic state. Calls are ref-counted — nest freely.\n */\n beginMutation: () => void;\n /**\n * Signal that an optimistic mutation has resolved. Adds a one-poll-interval\n * cooldown (default 3 s) so the next poll fetches post-mutation data.\n */\n endMutation: (cooldownMs?: number) => void;\n /** Whether a mutation is currently in-flight (for polling skip logic). */\n isMutating: () => boolean;\n}\n\n/** Parse initialNodes + initialEdges into domain Maps. */\nfunction parseMaps(\n initialNodes: CanvasNodeType[],\n initialEdges: Edge[]\n): {\n featureMap: Map<string, FeatureEntry>;\n repoMap: Map<string, RepoEntry>;\n applicationMap: Map<string, ApplicationEntry>;\n} {\n // Build parentNodeId map from dependency edges\n const parentByChild = new Map<string, string>();\n for (const edge of initialEdges) {\n if (edge.type === 'dependencyEdge') {\n parentByChild.set(edge.target, edge.source);\n }\n }\n\n const featureMap = new Map<string, FeatureEntry>();\n const repoMap = new Map<string, RepoEntry>();\n const applicationMap = new Map<string, ApplicationEntry>();\n\n for (const node of initialNodes) {\n if (node.type === 'featureNode') {\n const data = node.data as FeatureNodeData;\n featureMap.set(node.id, {\n nodeId: node.id,\n data,\n parentNodeId: parentByChild.get(node.id),\n ...(data.applicationId && { applicationId: data.applicationId }),\n });\n } else if (node.type === 'repositoryNode') {\n repoMap.set(node.id, {\n nodeId: node.id,\n data: node.data as RepositoryNodeData,\n });\n } else if (node.type === 'applicationNode') {\n applicationMap.set(node.id, {\n nodeId: node.id,\n data: node.data as ApplicationNodeData,\n });\n }\n }\n\n return { featureMap, repoMap, applicationMap };\n}\n\ntype FeatureDataUpdates = Partial<\n Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>\n>;\n\nfunction isFeatureDataUnchanged(data: FeatureNodeData, updates: FeatureDataUpdates): boolean {\n return (\n (updates.state === undefined || updates.state === data.state) &&\n (updates.lifecycle === undefined || updates.lifecycle === data.lifecycle) &&\n (updates.name === undefined || updates.name === data.name) &&\n (updates.description === undefined || updates.description === data.description)\n );\n}\n\n/**\n * Shallow-compare two Maps by key set and entry data (JSON equality).\n * Returns true if they are structurally identical, avoiding unnecessary re-renders.\n */\nfunction mapsEqual<T extends { data: unknown; parentNodeId?: string }>(\n a: Map<string, T>,\n b: Map<string, T>\n): boolean {\n if (a.size !== b.size) return false;\n for (const [key, aEntry] of a) {\n const bEntry = b.get(key);\n if (!bEntry) return false;\n if (aEntry.parentNodeId !== bEntry.parentNodeId) return false;\n if (aEntry.data === bEntry.data) continue;\n if (JSON.stringify(aEntry.data) !== JSON.stringify(bEntry.data)) return false;\n }\n return true;\n}\n\nexport function useGraphState(\n initialNodes: CanvasNodeType[],\n initialEdges: Edge[],\n showArchived = false\n): UseGraphStateReturn {\n const { i18n } = useTranslation();\n const layoutDefaults = useMemo(() => getCanvasLayoutDefaults(i18n.dir()), [i18n]);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional: parse only on mount (like useState initializer)\n const init = useMemo(() => parseMaps(initialNodes, initialEdges), []);\n\n const [featureMap, setFeatureMap] = useState<Map<string, FeatureEntry>>(init.featureMap);\n const [repoMap, setRepoMap] = useState<Map<string, RepoEntry>>(init.repoMap);\n const [applicationMap, setApplicationMap] = useState<Map<string, ApplicationEntry>>(\n init.applicationMap\n );\n const [pendingMap, setPendingMap] = useState<Map<string, FeatureEntry>>(\n new Map<string, FeatureEntry>()\n );\n\n // Buffer for SSE updates that arrive before their feature is in featureMap.\n // When reconcile adds new features, buffered updates are applied automatically.\n const pendingUpdatesRef = useRef<\n Map<string, Partial<Pick<FeatureNodeData, 'state' | 'lifecycle' | 'name' | 'description'>>>\n >(new Map());\n\n // Protect recently-added/replaced repos from stale-poll reconcile.\n // After addRepository or replaceRepository, the repo ID is marked as protected.\n // Once reconcile sees the repo in server data, the protection is cleared.\n // This prevents a stale poll (that fetched data before the server action completed)\n // from wiping a repo that the client has already added.\n const protectedRepoIdsRef = useRef<Set<string>>(new Set());\n\n // Mutation guard: ref-counted counter. While > 0, reconcile is a no-op\n // so stale poll data cannot overwrite optimistic state.\n const mutationCountRef = useRef(0);\n const mutationTimersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n\n // Track 'deleting' features that the server no longer returns.\n // Retained for one extra reconcile cycle so the user sees the deleting state\n // before the node disappears from the canvas.\n const deletingRetainedRef = useRef<Set<string>>(new Set());\n\n // Track deleted repo IDs so reconcile doesn't resurrect them from stale server data.\n // Cleared once reconcile sees the repo is gone from server data.\n const deletedRepoIdsRef = useRef<Set<string>>(new Set());\n\n // Callbacks stored in a ref so changing them doesn't trigger re-render.\n // The stable wrapper object reads from the ref so node closures always use latest callbacks.\n const callbacksRef = useRef<GraphCallbacks>({});\n const stableCallbacks = useMemo<GraphCallbacks>(\n () => ({\n onNodeAction: (nodeId) => callbacksRef.current.onNodeAction?.(nodeId),\n onNodeSettings: (nodeId) => callbacksRef.current.onNodeSettings?.(nodeId),\n onFeatureDelete: (featureId, cleanup, cascadeDelete, closePr) =>\n callbacksRef.current.onFeatureDelete?.(featureId, cleanup, cascadeDelete, closePr),\n onRepositoryAdd: (nodeId) => callbacksRef.current.onRepositoryAdd?.(nodeId),\n onRepositoryClick: (nodeId) => callbacksRef.current.onRepositoryClick?.(nodeId),\n onRepositoryDelete: (repositoryId) => callbacksRef.current.onRepositoryDelete?.(repositoryId),\n onRetryFeature: (featureId) => callbacksRef.current.onRetryFeature?.(featureId),\n onStartFeature: (featureId) => callbacksRef.current.onStartFeature?.(featureId),\n onArchiveFeature: (featureId) => callbacksRef.current.onArchiveFeature?.(featureId),\n onUnarchiveFeature: (featureId) => callbacksRef.current.onUnarchiveFeature?.(featureId),\n onApplicationClick: (applicationId) =>\n callbacksRef.current.onApplicationClick?.(applicationId),\n onApplicationDelete: (applicationId) =>\n callbacksRef.current.onApplicationDelete?.(applicationId),\n onApplicationCreateSddFeature: (applicationId) =>\n callbacksRef.current.onApplicationCreateSddFeature?.(applicationId),\n }),\n []\n );\n\n // Stable refs for domain Maps (for use in callbacks without depending on state)\n const featureMapRef = useRef(featureMap);\n featureMapRef.current = featureMap;\n const repoMapRef = useRef(repoMap);\n repoMapRef.current = repoMap;\n\n // Filter archived features from the Map when the toggle is off.\n // This gives instant toggle response (no server round-trip) per NFR-3.\n const visibleFeatureMap = useMemo(() => {\n if (showArchived) return featureMap;\n const filtered = new Map<string, FeatureEntry>();\n for (const [id, entry] of featureMap) {\n if ((entry.data.state as string) !== 'archived') {\n filtered.set(id, entry);\n }\n }\n return filtered.size === featureMap.size ? featureMap : filtered;\n }, [featureMap, showArchived]);\n\n // Derive graph from domain Maps (runs on every Map change, but dagre only on topology change)\n const derived = useMemo(\n () => deriveGraph(visibleFeatureMap, repoMap, pendingMap, stableCallbacks, applicationMap),\n [visibleFeatureMap, repoMap, pendingMap, stableCallbacks, applicationMap]\n );\n\n // Cache dagre layout positions — only re-run when node set or edge connections change\n const layoutCacheRef = useRef<{\n key: string;\n positions: Map<\n string,\n { position: { x: number; y: number }; targetPosition: Position; sourcePosition: Position }\n >;\n }>({ key: '', positions: new Map() });\n\n const { nodes, edges } = useMemo(() => {\n const nodeIds = derived.nodes\n .map((n) => n.id)\n .sort()\n .join(',');\n const edgeKeys = derived.edges\n .map((e) => `${e.source}-${e.target}`)\n .sort()\n .join(',');\n const topologyKey = `${nodeIds}|${edgeKeys}|${layoutDefaults.direction}`;\n\n if (topologyKey !== layoutCacheRef.current.key) {\n // Topology changed — re-run dagre\n const result = layoutWithDagre(derived.nodes, derived.edges, layoutDefaults);\n const positions = new Map<\n string,\n { position: { x: number; y: number }; targetPosition: Position; sourcePosition: Position }\n >();\n for (const node of result.nodes) {\n positions.set(node.id, {\n position: node.position,\n targetPosition: (node as Record<string, unknown>).targetPosition as Position,\n sourcePosition: (node as Record<string, unknown>).sourcePosition as Position,\n });\n }\n\n // Anchor new layout to previous positions so the graph doesn't drift.\n // Find the first surviving node (exists in both old and new layouts) and\n // shift the entire new layout by the delta between its old and new position.\n const prevPositions = layoutCacheRef.current.positions;\n if (prevPositions.size > 0) {\n let dx = 0;\n let dy = 0;\n for (const [id, newPos] of positions) {\n const oldPos = prevPositions.get(id);\n if (oldPos) {\n dx = oldPos.position.x - newPos.position.x;\n dy = oldPos.position.y - newPos.position.y;\n break;\n }\n }\n if (dx !== 0 || dy !== 0) {\n for (const pos of positions.values()) {\n pos.position = { x: pos.position.x + dx, y: pos.position.y + dy };\n }\n for (const node of result.nodes) {\n node.position = { x: node.position.x + dx, y: node.position.y + dy };\n }\n }\n }\n\n layoutCacheRef.current = { key: topologyKey, positions };\n return result;\n }\n\n // Data-only change — apply cached positions without re-running dagre\n const { positions } = layoutCacheRef.current;\n const nodes = derived.nodes.map((node) => {\n const cached = positions.get(node.id);\n return cached ? { ...node, ...cached } : node;\n });\n return { nodes, edges: derived.edges };\n }, [derived, layoutDefaults]);\n\n // --- Mutations ---\n\n const reconcile = useCallback((newNodes: CanvasNodeType[], newEdges: Edge[]) => {\n // Skip reconciliation while an optimistic mutation is in-flight.\n // Stale poll data fetched before the mutation completed would overwrite\n // the optimistic state, causing flicker (nodes disappearing/reappearing).\n if (mutationCountRef.current > 0) return;\n\n const { featureMap: newFeatureMap, repoMap: newRepoMap } = parseMaps(newNodes, newEdges);\n\n // Precompute match keys so we don't scan newFeatureMap.values() per pending entry\n const realFeatureKeys = new Set(\n [...newFeatureMap.values()].map((e) => `${e.data.name}\\0${e.data.repositoryPath}`)\n );\n\n setFeatureMap((currentFeatureMap) => {\n // Preserve pending (creating) nodes unless matched by name+repositoryPath from newFeatureMap\n const pendingEntries = [...currentFeatureMap.entries()].filter(\n ([, e]) => e.data.state === 'creating'\n );\n\n const merged = new Map(newFeatureMap);\n\n // Keep pending nodes that don't have a real counterpart in new data\n for (const [tempId, pendingEntry] of pendingEntries) {\n const key = `${pendingEntry.data.name}\\0${pendingEntry.data.repositoryPath}`;\n if (!realFeatureKeys.has(key)) {\n merged.set(tempId, pendingEntry);\n }\n }\n\n // Preserve 'deleting' state for features being deleted.\n // If the server still returns the feature, override its state to 'deleting'.\n // If the server no longer returns it (soft-deleted), retain it for one\n // extra reconcile cycle so the user sees the deleting animation.\n const nextRetained = new Set<string>();\n for (const [id, entry] of currentFeatureMap) {\n if (entry.data.state === 'deleting') {\n if (merged.has(id)) {\n // Server still has it — override state to keep showing 'deleting'\n merged.set(id, {\n ...merged.get(id)!,\n data: { ...merged.get(id)!.data, state: 'deleting' },\n });\n } else if (!deletingRetainedRef.current.has(id)) {\n // First reconcile after server removal — retain with deleting state\n merged.set(id, entry);\n nextRetained.add(id);\n }\n // else: already retained once — let it disappear\n }\n }\n deletingRetainedRef.current = nextRetained;\n\n // Apply any buffered SSE updates to features that now exist in the map\n for (const [nodeId, updates] of pendingUpdatesRef.current) {\n const entry = merged.get(nodeId);\n if (entry) {\n merged.set(nodeId, { ...entry, data: { ...entry.data, ...updates } });\n pendingUpdatesRef.current.delete(nodeId);\n }\n }\n\n // Avoid re-render when polling returns identical data\n if (mapsEqual(currentFeatureMap, merged)) return currentFeatureMap;\n return merged;\n });\n\n // Clean pendingMap entries that now have a real counterpart in server data\n setPendingMap((currentPendingMap) => {\n if (currentPendingMap.size === 0) return currentPendingMap;\n let changed = false;\n const next = new Map(currentPendingMap);\n for (const [tempId, pendingEntry] of currentPendingMap) {\n const key = `${pendingEntry.data.name}\\0${pendingEntry.data.repositoryPath}`;\n if (realFeatureKeys.has(key)) {\n next.delete(tempId);\n changed = true;\n }\n }\n return changed ? next : currentPendingMap;\n });\n\n // Merge repoMap: preserve optimistic (temp) repos AND recently-added/replaced\n // repos that the server doesn't know about yet. Without this, a polling\n // reconcile that fires before the server action returns (or uses stale data\n // from an in-flight fetch) would wipe the repo, causing a canvas→empty flicker.\n setRepoMap((currentRepoMap) => {\n // Start with everything the server returned\n const merged = new Map(newRepoMap);\n\n // Remove repos that were deleted client-side but the server still returns\n // (stale data). Once the server stops returning the repo, clear the tombstone.\n for (const deletedId of deletedRepoIdsRef.current) {\n if (merged.has(deletedId)) {\n merged.delete(deletedId);\n } else {\n // Server confirmed deletion — no longer need the tombstone\n deletedRepoIdsRef.current.delete(deletedId);\n }\n }\n\n // Build a set of repositoryPaths present in server data for dedup\n const serverPaths = new Set([...newRepoMap.values()].map((e) => e.data.repositoryPath));\n\n for (const [id, entry] of currentRepoMap) {\n if (merged.has(id)) {\n // Server confirmed this repo — no longer needs protection\n protectedRepoIdsRef.current.delete(id);\n continue;\n }\n if (serverPaths.has(entry.data.repositoryPath)) {\n // Server has a repo with same path — clear protection\n protectedRepoIdsRef.current.delete(id);\n continue;\n }\n // Keep temp repos or protected (recently added/replaced) repos\n if (id.startsWith('repo-temp-') || protectedRepoIdsRef.current.has(id)) {\n merged.set(id, entry);\n }\n }\n\n // Avoid re-render when polling returns identical data\n if (mapsEqual(currentRepoMap, merged)) return currentRepoMap;\n return merged;\n });\n\n // Reconcile applicationMap\n const { applicationMap: newApplicationMap } = parseMaps(newNodes, newEdges);\n setApplicationMap((currentAppMap) => {\n if (mapsEqual(currentAppMap, newApplicationMap)) return currentAppMap;\n return newApplicationMap;\n });\n }, []);\n\n const updateFeature = useCallback((featureNodeId: string, updates: FeatureDataUpdates) => {\n setFeatureMap((prev) => {\n const entry = prev.get(featureNodeId);\n if (!entry) {\n // Feature not yet in map — buffer update for when reconcile adds it\n pendingUpdatesRef.current.set(featureNodeId, {\n ...pendingUpdatesRef.current.get(featureNodeId),\n ...updates,\n });\n return prev;\n }\n // Clear any buffered update for this feature since it's now in the map\n pendingUpdatesRef.current.delete(featureNodeId);\n if (isFeatureDataUnchanged(entry.data, updates)) return prev;\n const next = new Map(prev);\n next.set(featureNodeId, { ...entry, data: { ...entry.data, ...updates } });\n return next;\n });\n\n // Also check pendingMap\n setPendingMap((prev) => {\n const entry = prev.get(featureNodeId);\n if (!entry) return prev;\n if (isFeatureDataUnchanged(entry.data, updates)) return prev;\n const next = new Map(prev);\n next.set(featureNodeId, { ...entry, data: { ...entry.data, ...updates } });\n return next;\n });\n }, []);\n\n const addPendingFeature = useCallback(\n (nodeId: string, data: FeatureNodeData, parentNodeId?: string) => {\n setPendingMap((prev) => {\n const next = new Map(prev);\n // Mirror parseMaps: lift data.applicationId into the FeatureEntry so\n // derive-graph emits an app→feature edge for the optimistic node.\n next.set(nodeId, {\n nodeId,\n data,\n parentNodeId,\n ...(data.applicationId && { applicationId: data.applicationId }),\n });\n return next;\n });\n },\n []\n );\n\n const removePendingFeature = useCallback((nodeId: string) => {\n setPendingMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const removeFeature = useCallback((nodeId: string) => {\n setFeatureMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const restoreFeature = useCallback((nodeId: string, entry: FeatureEntry) => {\n setFeatureMap((prev) => {\n const next = new Map(prev);\n next.set(nodeId, entry);\n return next;\n });\n }, []);\n\n const addRepository = useCallback((nodeId: string, data: RepositoryNodeData) => {\n protectedRepoIdsRef.current.add(nodeId);\n deletedRepoIdsRef.current.delete(nodeId);\n setRepoMap((prev) => {\n const next = new Map(prev);\n next.set(nodeId, { nodeId, data });\n return next;\n });\n }, []);\n\n const removeRepository = useCallback((nodeId: string) => {\n protectedRepoIdsRef.current.delete(nodeId);\n deletedRepoIdsRef.current.add(nodeId);\n setRepoMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const replaceRepository = useCallback(\n (tempId: string, realId: string, data: RepositoryNodeData) => {\n protectedRepoIdsRef.current.delete(tempId);\n protectedRepoIdsRef.current.add(realId);\n setRepoMap((prev) => {\n if (!prev.has(tempId)) return prev;\n const next = new Map(prev);\n next.delete(tempId);\n next.set(realId, { nodeId: realId, data });\n return next;\n });\n },\n []\n );\n\n const addApplication = useCallback((nodeId: string, data: ApplicationNodeData) => {\n setApplicationMap((prev) => {\n const next = new Map(prev);\n next.set(nodeId, { nodeId, data });\n return next;\n });\n }, []);\n\n const removeApplication = useCallback((nodeId: string) => {\n setApplicationMap((prev) => {\n if (!prev.has(nodeId)) return prev;\n const next = new Map(prev);\n next.delete(nodeId);\n return next;\n });\n }, []);\n\n const getFeatureRepositoryPath = useCallback((featureNodeId: string): string | undefined => {\n return featureMapRef.current.get(featureNodeId)?.data.repositoryPath;\n }, []);\n\n const getRepositoryData = useCallback((nodeId: string): RepositoryNodeData | undefined => {\n return repoMapRef.current.get(nodeId)?.data;\n }, []);\n\n const getRepoMapSize = useCallback((): number => {\n return repoMapRef.current.size;\n }, []);\n\n const setCallbacks = useCallback((callbacks: GraphCallbacks) => {\n callbacksRef.current = callbacks;\n }, []);\n\n const beginMutation = useCallback(() => {\n mutationCountRef.current++;\n }, []);\n\n const endMutation = useCallback((cooldownMs = 3_000) => {\n // Delay decrement by one poll interval so the next fetch after the\n // mutation returns post-mutation data, not a stale in-flight response.\n const timer = setTimeout(() => {\n mutationCountRef.current = Math.max(0, mutationCountRef.current - 1);\n mutationTimersRef.current.delete(timer);\n }, cooldownMs);\n mutationTimersRef.current.add(timer);\n }, []);\n\n const isMutating = useCallback(() => mutationCountRef.current > 0, []);\n\n // Cleanup cooldown timers on unmount\n useEffect(() => {\n const timers = mutationTimersRef.current;\n return () => {\n for (const timer of timers) clearTimeout(timer);\n timers.clear();\n };\n }, []);\n\n return {\n nodes,\n edges,\n reconcile,\n updateFeature,\n addPendingFeature,\n removePendingFeature,\n removeFeature,\n restoreFeature,\n addRepository,\n removeRepository,\n replaceRepository,\n getFeatureRepositoryPath,\n getRepositoryData,\n getRepoMapSize,\n addApplication,\n removeApplication,\n setCallbacks,\n beginMutation,\n endMutation,\n isMutating,\n };\n}\n","/**\n * derive-graph.ts\n *\n * Pure client-side derivation: domain Maps → React Flow nodes + edges.\n * All edges are derived from domain relationships (repositoryPath matching,\n * parentNodeId) — never stored independently.\n */\n\nimport type { Edge } from '@xyflow/react';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\n/** A feature node entry stored in the domain Map. */\nexport interface FeatureEntry {\n nodeId: string;\n data: FeatureNodeData;\n /** If set, this feature connects to a parent feature via a dependency edge (no repo→feature edge). */\n parentNodeId?: string;\n /**\n * If set, this feature was launched scoped to an Application. Matched against\n * ApplicationEntry.data.id to derive an app→feature dependency edge instead of\n * the default repo→feature edge.\n */\n applicationId?: string;\n}\n\n/** A repository node entry stored in the domain Map. */\nexport interface RepoEntry {\n nodeId: string;\n data: RepositoryNodeData;\n}\n\n/** An application node entry stored in the domain Map. */\nexport interface ApplicationEntry {\n nodeId: string;\n data: ApplicationNodeData;\n}\n\n/** Stable callbacks passed by the consumer, injected into derived node data. */\nexport interface GraphCallbacks {\n /** Called when the user triggers an action on a feature node (e.g., adds a sub-feature). */\n onNodeAction?: (nodeId: string) => void;\n /** Called when the user opens settings/details on a feature node. */\n onNodeSettings?: (nodeId: string) => void;\n /** Called when the user deletes a feature. */\n onFeatureDelete?: (\n featureId: string,\n cleanup?: boolean,\n cascadeDelete?: boolean,\n closePr?: boolean\n ) => void;\n /** Called when the user clicks the \"+\" add-feature button on a repo node. */\n onRepositoryAdd?: (repoNodeId: string) => void;\n /** Called when the user clicks a repo node to navigate to its detail page. */\n onRepositoryClick?: (repoNodeId: string) => void;\n /** Called when the user deletes a repository. */\n onRepositoryDelete?: (repositoryId: string, options?: { deleteFromDisk?: boolean }) => void;\n /** Called when the user retries a failed feature. */\n onRetryFeature?: (featureId: string) => void;\n /** Called when the user starts a pending feature. */\n onStartFeature?: (featureId: string) => void;\n /** Called when the user stops a running feature. */\n onStopFeature?: (featureId: string) => void;\n /** Called when the user archives a feature. */\n onArchiveFeature?: (featureId: string) => void;\n /** Called when the user unarchives a feature. */\n onUnarchiveFeature?: (featureId: string) => void;\n /** Called when the user clicks an application node to navigate to its detail page. */\n onApplicationClick?: (applicationId: string) => void;\n /** Called when the user deletes an application. */\n onApplicationDelete?: (applicationId: string) => void;\n /** Called when the user triggers \"New SDD feature\" on an application node —\n * the consumer is expected to navigate to the create drawer pre-scoped to\n * this application in spec mode. */\n onApplicationCreateSddFeature?: (applicationId: string) => void;\n}\n\n/**\n * Derives React Flow nodes and edges from domain Maps.\n *\n * - Feature nodes without a parentNodeId → repo→feature edge (matched by repositoryPath)\n * - Feature nodes without a parentNodeId but with no matching repo → virtual repo node\n * - Feature nodes with a parentNodeId → dependency edge (parentNodeId→nodeId)\n * - Pending feature nodes (creating state) from pendingMap → same rules, no action callbacks\n * - Callbacks are injected into node data via closures\n */\nexport function deriveGraph(\n featureMap: Map<string, FeatureEntry>,\n repoMap: Map<string, RepoEntry>,\n pendingMap: Map<string, FeatureEntry>,\n callbacks?: GraphCallbacks,\n applicationMap?: Map<string, ApplicationEntry>\n): { nodes: CanvasNodeType[]; edges: Edge[] } {\n const nodes: CanvasNodeType[] = [];\n const edges: Edge[] = [];\n\n // Normalize path separators so Windows backslash paths match forward-slash paths\n const normalizePath = (p: string) => p.replace(/\\\\/g, '/');\n\n // Build a lookup: repositoryPath → repoNodeId\n const repoByPath = new Map<string, string>();\n for (const [nodeId, entry] of repoMap) {\n if (entry.data.repositoryPath) {\n repoByPath.set(normalizePath(entry.data.repositoryPath), nodeId);\n }\n }\n\n // Build a lookup: application domain UUID → applicationNodeId. Used to\n // resolve a feature's `applicationId` (a domain UUID, not a node id)\n // to its rendered ApplicationNode on the canvas.\n const appByDomainId = new Map<string, string>();\n if (applicationMap) {\n for (const [nodeId, entry] of applicationMap) {\n if (entry.data.id) {\n appByDomainId.set(entry.data.id, nodeId);\n }\n }\n }\n\n // Virtual repo nodes created for orphaned features (not in repoMap)\n const virtualRepos = new Map<string, string>(); // path → virtualNodeId\n\n function getOrCreateVirtualRepo(repositoryPath: string): string {\n if (virtualRepos.has(repositoryPath)) {\n return virtualRepos.get(repositoryPath)!;\n }\n const virtualId = `virtual-repo-${repositoryPath}`;\n const repoName = repositoryPath.split('/').filter(Boolean).at(-1) ?? repositoryPath;\n nodes.push({\n id: virtualId,\n type: 'repositoryNode',\n position: { x: 0, y: 0 },\n data: { name: repoName, repositoryPath } satisfies RepositoryNodeData,\n } as CanvasNodeType);\n virtualRepos.set(repositoryPath, virtualId);\n return virtualId;\n }\n\n // Add repo nodes (real ones) — sorted by createdAt for stable vertical order.\n // The server-side layoutWithDagre may reorder the node array (connected vs\n // disconnected split), so we cannot rely on Map insertion order alone.\n // Use Infinity fallback so repos without createdAt sort last (appear at bottom).\n const sortedRepoEntries = [...repoMap.entries()].sort((a, b) => {\n const aRaw = a[1].data.createdAt;\n const bRaw = b[1].data.createdAt;\n const aTime = typeof aRaw === 'number' && !Number.isNaN(aRaw) ? aRaw : Infinity;\n const bTime = typeof bRaw === 'number' && !Number.isNaN(bRaw) ? bRaw : Infinity;\n return aTime - bTime;\n });\n for (const [nodeId, entry] of sortedRepoEntries) {\n const data: RepositoryNodeData = {\n ...entry.data,\n ...(callbacks?.onRepositoryAdd && {\n onAdd: () => callbacks.onRepositoryAdd!(nodeId),\n }),\n ...(callbacks?.onRepositoryClick && {\n onClick: () => callbacks.onRepositoryClick!(nodeId),\n }),\n ...(callbacks?.onRepositoryDelete && {\n onDelete: callbacks.onRepositoryDelete,\n }),\n };\n nodes.push({\n id: nodeId,\n type: 'repositoryNode',\n position: { x: 0, y: 0 },\n data,\n } as CanvasNodeType);\n }\n\n // Process feature entries (both real and pending).\n // Skip pendingMap entries that already exist in featureMap (reconcile may not\n // have cleaned them up yet if the AI-generated name differs from the original).\n const allFeatureEntries: [string, FeatureEntry, boolean][] = [\n ...[...featureMap.entries()].map(\n ([id, e]) => [id, e, false] as [string, FeatureEntry, boolean]\n ),\n ...[...pendingMap.entries()]\n .filter(([id]) => !featureMap.has(id))\n .map(([id, e]) => [id, e, true] as [string, FeatureEntry, boolean]),\n ];\n\n for (const [nodeId, entry, isPending] of allFeatureEntries) {\n const isCreating = entry.data.state === 'creating' || isPending;\n\n const data: FeatureNodeData = {\n ...entry.data,\n // Callbacks only for non-creating nodes\n ...(!isCreating &&\n callbacks?.onNodeAction && {\n onAction: () => callbacks.onNodeAction!(nodeId),\n }),\n ...(!isCreating &&\n callbacks?.onNodeSettings && {\n onSettings: () => callbacks.onNodeSettings!(nodeId),\n }),\n ...(!isCreating &&\n callbacks?.onFeatureDelete && {\n onDelete: callbacks.onFeatureDelete,\n }),\n ...(!isCreating &&\n entry.data.state === 'error' &&\n callbacks?.onRetryFeature && {\n onRetry: callbacks.onRetryFeature,\n }),\n ...(!isCreating &&\n entry.data.state === 'pending' &&\n callbacks?.onStartFeature && {\n onStart: callbacks.onStartFeature,\n }),\n ...(!isCreating &&\n (entry.data.state === 'running' || entry.data.state === 'action-required') &&\n callbacks?.onStopFeature && {\n onStop: callbacks.onStopFeature,\n }),\n ...(!isCreating &&\n entry.data.state !== 'archived' &&\n entry.data.state !== 'deleting' &&\n callbacks?.onArchiveFeature && {\n onArchive: callbacks.onArchiveFeature,\n }),\n ...(!isCreating &&\n entry.data.state === 'archived' &&\n callbacks?.onUnarchiveFeature && {\n onUnarchive: callbacks.onUnarchiveFeature,\n }),\n };\n\n nodes.push({\n id: nodeId,\n type: 'featureNode',\n position: { x: 0, y: 0 },\n data,\n } as CanvasNodeType);\n\n // Edge derivation\n // Priority order:\n // 1) parentNodeId → feature→feature dep edge (existing behavior)\n // 2) applicationId matching a known ApplicationNode → app→feature dep edge\n // 3) repositoryPath → repo→feature edge (existing fallback)\n // If parentNodeId references a feature that's not visible (e.g. archived/filtered),\n // fall through so the child reconnects to its application or repository.\n const appNodeId = entry.applicationId ? appByDomainId.get(entry.applicationId) : undefined;\n if (\n entry.parentNodeId &&\n (featureMap.has(entry.parentNodeId) || pendingMap.has(entry.parentNodeId))\n ) {\n // Dependency edge (parent→child feature)\n edges.push({\n id: `dep-${entry.parentNodeId}-${nodeId}`,\n source: entry.parentNodeId,\n target: nodeId,\n type: 'dependencyEdge',\n });\n } else if (appNodeId) {\n // Application→feature dep edge (SDD-mode features launched from an app)\n edges.push({\n id: `dep-${appNodeId}-${nodeId}`,\n source: appNodeId,\n target: nodeId,\n type: 'dependencyEdge',\n });\n } else {\n // Repo→feature edge (matched by repositoryPath)\n const repositoryPath = normalizePath(entry.data.repositoryPath);\n const repoNodeId = repoByPath.get(repositoryPath) ?? getOrCreateVirtualRepo(repositoryPath);\n edges.push({\n id: `edge-${repoNodeId}-${nodeId}`,\n source: repoNodeId,\n target: nodeId,\n style: { strokeDasharray: '5 5' },\n });\n }\n }\n\n // Emit ApplicationNodes for every workspace application. Features whose\n // `applicationId` matches an entry above already have an app→feature edge;\n // applications without any child SDD feature simply render as standalone\n // nodes (mirrors how repository nodes appear with no children).\n if (applicationMap) {\n for (const [nodeId, entry] of applicationMap) {\n const data: ApplicationNodeData = {\n ...entry.data,\n ...(callbacks?.onApplicationClick && {\n onClick: () => callbacks.onApplicationClick!(entry.data.id),\n }),\n ...(callbacks?.onApplicationDelete && {\n onDelete: callbacks.onApplicationDelete,\n }),\n ...(callbacks?.onApplicationCreateSddFeature && {\n onCreateSddFeature: callbacks.onApplicationCreateSddFeature,\n }),\n };\n nodes.push({\n id: nodeId,\n type: 'applicationNode',\n position: { x: 0, y: 0 },\n data,\n } as CanvasNodeType);\n }\n }\n\n // Build set of feature node IDs that have children (are dependency edge sources)\n const parentNodeIds = new Set<string>();\n for (const edge of edges) {\n if (edge.type === 'dependencyEdge') {\n parentNodeIds.add(edge.source);\n }\n }\n\n // Inject showHandles and hasChildren based on edges\n const hasEdges = edges.length > 0;\n for (const node of nodes) {\n const data = node.data as Record<string, unknown>;\n data.showHandles = hasEdges;\n if (node.type === 'featureNode') {\n data.hasChildren = parentNodeIds.has(node.id);\n }\n }\n\n return { nodes, edges };\n}\n","'use client';\n\nimport { useCallback } from 'react';\nimport { Code2, Terminal, FolderOpen, RefreshCw } from 'lucide-react';\nimport { BaseDrawer } from '@/components/common/base-drawer';\nimport { DrawerTitle, DrawerDescription } from '@/components/ui/drawer';\nimport { Separator } from '@/components/ui/separator';\nimport { ActionButton } from '@/components/common/action-button';\nimport type { RepositoryNodeData } from './repository-node-config';\nimport { useRepositoryActions } from './use-repository-actions';\n\nexport interface RepositoryDrawerProps {\n data: RepositoryNodeData | null;\n onClose: () => void;\n}\n\nexport function RepositoryDrawer({ data, onClose }: RepositoryDrawerProps) {\n const handleClose = useCallback(() => {\n onClose();\n }, [onClose]);\n\n const actions = useRepositoryActions(\n data?.repositoryPath ? { repositoryId: data.id, repositoryPath: data.repositoryPath } : null\n );\n\n return (\n <BaseDrawer\n open={data !== null}\n onClose={handleClose}\n size=\"md\"\n modal={false}\n data-testid=\"repository-drawer\"\n deployTarget={\n data?.repositoryPath\n ? {\n targetId: data.repositoryPath,\n targetType: 'repository',\n repositoryPath: data.repositoryPath,\n }\n : undefined\n }\n header={\n data ? (\n <div data-testid=\"repository-drawer-header\">\n <DrawerTitle>{data.name}</DrawerTitle>\n {data.repositoryPath ? (\n <DrawerDescription className=\"truncate font-mono text-xs\">\n {data.repositoryPath}\n </DrawerDescription>\n ) : null}\n </div>\n ) : undefined\n }\n >\n {data?.repositoryPath ? (\n <>\n <Separator />\n <div className=\"flex flex-col gap-3 p-4\">\n <div className=\"text-muted-foreground text-xs font-semibold tracking-wider\">\n OPEN WITH\n </div>\n <div className=\"flex flex-col gap-2\">\n <ActionButton\n label=\"Open in IDE\"\n onClick={actions.openInIde}\n loading={actions.ideLoading}\n error={!!actions.ideError}\n icon={Code2}\n variant=\"outline\"\n size=\"sm\"\n />\n <ActionButton\n label=\"Open in Shell\"\n onClick={actions.openInShell}\n loading={actions.shellLoading}\n error={!!actions.shellError}\n icon={Terminal}\n variant=\"outline\"\n size=\"sm\"\n />\n <ActionButton\n label=\"Open Folder\"\n onClick={actions.openFolder}\n loading={actions.folderLoading}\n error={!!actions.folderError}\n icon={FolderOpen}\n variant=\"outline\"\n size=\"sm\"\n />\n </div>\n </div>\n {data.id ? (\n <>\n <Separator />\n <div className=\"flex flex-col gap-3 p-4\">\n <div className=\"text-muted-foreground text-xs font-semibold tracking-wider\">\n GIT OPERATIONS\n </div>\n <div className=\"flex flex-col gap-2\">\n <ActionButton\n label=\"Sync Main\"\n onClick={actions.syncMain}\n loading={actions.syncLoading}\n error={!!actions.syncError}\n icon={RefreshCw}\n variant=\"outline\"\n size=\"sm\"\n />\n {actions.syncError ? (\n <p className=\"text-destructive text-xs\">{actions.syncError}</p>\n ) : null}\n </div>\n </div>\n </>\n ) : null}\n </>\n ) : null}\n </BaseDrawer>\n );\n}\n","'use client';\n\nimport { useCallback, useState } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport {\n ExternalLink,\n LayoutGrid,\n Loader2,\n Play,\n Plus,\n RotateCcw,\n Square,\n Trash2,\n} from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Button } from '@/components/ui/button';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\nimport { useTurnStatus } from '@/hooks/turn-statuses-provider';\nimport { useDeployAction } from '@/hooks/use-deploy-action';\nimport { DeploymentState } from '@shepai/core/domain/generated/output';\nimport { featureIdForApplication } from '@shepai/core/domain/shared/feature-id';\nimport { deriveAppLiveStatus } from '@/lib/derive-app-status';\nimport type { ApplicationNodeData } from './application-node-config';\n\n/** Preview slot height. Used only when a deployment is actually Live —\n * when the app is idle, we collapse to a single Run row so the card\n * matches the repository node's vertical rhythm on the canvas. */\nconst PREVIEW_HEIGHT_PX = 180;\n\nexport function ApplicationNode({\n data,\n selected,\n}: {\n data: ApplicationNodeData;\n selected?: boolean;\n [key: string]: unknown;\n}) {\n const { i18n, t } = useTranslation('web');\n const isRtl = i18n.dir() === 'rtl';\n const targetHandlePos = isRtl ? Position.Right : Position.Left;\n const sourceHandlePos = isRtl ? Position.Left : Position.Right;\n const [confirmOpen, setConfirmOpen] = useState(false);\n\n const totalRepoCount = 1 + data.additionalPathCount;\n const repoCountLabel = totalRepoCount === 1 ? '1 repository' : `${totalRepoCount} repositories`;\n\n // Live session turn status from the global SSE subscription. The\n // scope key is `app-<id>` — same key used everywhere else the\n // application's chat is referenced.\n const turnStatus = useTurnStatus(featureIdForApplication(data.id));\n\n // Shared dev-server deploy state — one per card. Subscribes to the\n // `DeploymentStatusProvider` which is SSR-seeded in the dashboard\n // layout from `ListDeploymentsUseCase`, so running apps render as\n // \"Live\" on the first paint without a client round-trip.\n //\n // The card's Preview button drives this hook and the `live.label`\n // below is derived from the SAME state (via `deploy.url`), so the\n // status pill, the preview slot, and the button are always in\n // sync — hitting the button on one card can never leave the card\n // itself showing a stale \"Ready\" state.\n const deploy = useDeployAction({\n targetId: data.id,\n targetType: 'application',\n repositoryPath: data.repositoryPath,\n });\n\n // The hook is the single source of truth for the running URL.\n //\n // The shared `DeploymentStatusProvider` is seeded from SSR\n // (`get-graph-data` → `ListDeploymentsUseCase`) so the entry for\n // this application is already populated on the first client render,\n // and `ensureHydrated` catches anything the SSR seed missed. On\n // Stop the hook clears `deploy.url` to null which immediately\n // collapses the pill from \"Live\" back to \"Ready\" — there is\n // intentionally no secondary snapshot URL that could stay stale.\n const effectiveDeploymentUrl = deploy.url;\n\n const live = deriveAppLiveStatus(data.status, turnStatus, !!effectiveDeploymentUrl);\n\n // Clicking anything in the \"card controls\" zone (Preview button,\n // open-in-new-tab) must not trigger the card's navigation-to-app\n // click handler. A single stopPropagation wrapper keeps every\n // control inside the card safe without individually guarding each\n // one.\n const stopCardClick = useCallback((e: React.MouseEvent | React.PointerEvent) => {\n e.stopPropagation();\n }, []);\n\n const openPreviewInNewTab = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n if (effectiveDeploymentUrl) {\n window.open(effectiveDeploymentUrl, '_blank', 'noopener,noreferrer');\n }\n },\n [effectiveDeploymentUrl]\n );\n\n return (\n <div\n className={cn('group relative', data.onDelete && data.id && 'ps-10')}\n style={{ direction: isRtl ? 'rtl' : 'ltr' }}\n >\n {/* Target handle (left in LTR) — always rendered for edge connections */}\n <Handle\n type=\"target\"\n position={targetHandlePos}\n isConnectable={false}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n\n {/* Delete button — visible on hover, positioned just outside the card\n on the left. Uses the same inset offset as the repository node so\n the two card types align horizontally on the canvas. */}\n {data.onDelete && data.id ? (\n <>\n <div\n className=\"absolute -start-3 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100\"\n onPointerDown={(e) => e.stopPropagation()}\n >\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n aria-label=\"Remove application\"\n data-testid=\"application-node-delete-button\"\n onClick={(e) => {\n e.stopPropagation();\n setConfirmOpen(true);\n }}\n className=\"bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Remove application</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n\n <Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>\n <DialogContent className=\"max-w-xs\">\n <DialogHeader>\n <DialogTitle>Remove application?</DialogTitle>\n <DialogDescription>\n This will remove <strong>{data.name}</strong> from your workspace.\n </DialogDescription>\n </DialogHeader>\n <DialogFooter className=\"grid grid-cols-2 gap-2 sm:flex-none\">\n <DialogClose asChild>\n <Button variant=\"outline\">Cancel</Button>\n </DialogClose>\n <Button\n variant=\"destructive\"\n onClick={() => {\n setConfirmOpen(false);\n data.onDelete?.(data.id);\n }}\n >\n Remove\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n ) : null}\n\n <div\n role=\"button\"\n tabIndex={0}\n data-testid=\"application-node-card\"\n data-app-name={data.name}\n onClick={(e) => {\n e.stopPropagation();\n data.onClick?.();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n data.onClick?.();\n }\n }}\n className={cn(\n 'nodrag bg-card flex w-[26rem] cursor-pointer flex-col overflow-hidden rounded-xl border shadow-sm transition-[border-color,box-shadow] duration-200 dark:bg-neutral-800/80',\n selected && 'border-blue-400 dark:border-amber-500/60',\n !selected && live.borderClass\n )}\n >\n {/* Row 1: Header — icon, name, status, \"+ New\" action.\n Layout mirrors the repository node so apps and repos read\n as visual peers on the canvas. The \"+ New\" button is the\n primary entry point for creating a feature scoped to this\n application; it opens the same drawer the repo node opens\n (mode editable, repo locked to the app's repo). */}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-violet-500\">\n <LayoutGrid className=\"h-4 w-4 text-white\" />\n </div>\n <span\n data-testid=\"application-node-name\"\n className=\"min-w-0 truncate text-sm font-medium\"\n >\n {data.name}\n </span>\n <span className=\"ms-auto flex shrink-0 items-center gap-2\">\n <span className=\"flex items-center gap-1.5\">\n <span\n data-testid=\"application-node-status-dot\"\n className={cn(\n 'relative flex h-2 w-2 items-center justify-center rounded-full',\n live.dotClass\n )}\n >\n {live.pulse ? (\n <span\n className={cn(\n 'absolute inline-flex h-full w-full animate-ping rounded-full opacity-60',\n live.dotClass\n )}\n />\n ) : null}\n </span>\n <span\n data-testid=\"application-node-status-text\"\n className=\"text-muted-foreground text-xs\"\n >\n {live.label}\n </span>\n </span>\n {data.onCreateSddFeature && data.id ? (\n <span onClick={(e) => e.stopPropagation()}>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={t('applicationNode.newFeature')}\n data-testid=\"application-node-new-sdd-feature-button\"\n onClick={(e) => {\n e.stopPropagation();\n data.onCreateSddFeature?.(data.id);\n }}\n onPointerDown={(e) => e.stopPropagation()}\n className=\"nodrag flex h-6 shrink-0 cursor-pointer items-center gap-0.5 rounded bg-blue-500 px-1.5 text-[11px] font-bold text-white transition-colors hover:bg-blue-600 dark:bg-amber-500 dark:hover:bg-amber-400\"\n >\n <Plus className=\"h-3 w-3\" />\n <span className=\"translate-y-px\">{t('repositoryNode.new')}</span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">{t('applicationNode.newFeature')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </span>\n ) : null}\n </span>\n </div>\n\n {/* Row 2: Live preview iframe — only mounted when a deployment\n is actually Ready. When the app is idle / booting / errored\n we collapse this slot so the card matches the repository\n node's vertical rhythm; the dev-server status is surfaced\n on the Run row below instead of an oversized placeholder. */}\n {effectiveDeploymentUrl && deploy.status === DeploymentState.Ready ? (\n <div className=\"px-4 pb-2\" onClick={stopCardClick}>\n <div\n className=\"bg-muted group/preview relative overflow-hidden rounded-lg\"\n style={{ height: PREVIEW_HEIGHT_PX }}\n >\n <iframe\n src={effectiveDeploymentUrl}\n title={`${data.name} live preview`}\n className=\"pointer-events-none absolute top-0 left-0 origin-top-left border-0 bg-white\"\n style={{\n width: '250%',\n height: '250%',\n transform: 'scale(0.4)',\n }}\n sandbox=\"allow-same-origin allow-scripts\"\n loading=\"lazy\"\n />\n\n {/* Hover overlay — Stop + Open-in-new-tab cluster */}\n <div\n className=\"pointer-events-none absolute inset-0 flex items-center justify-center gap-2 bg-neutral-900/75 opacity-0 transition-opacity duration-150 group-hover/preview:pointer-events-auto group-hover/preview:opacity-100 dark:bg-neutral-950/80\"\n onPointerDown={stopCardClick}\n onClick={stopCardClick}\n >\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n void deploy.stop();\n }}\n disabled={deploy.stopLoading}\n aria-label=\"Stop dev server\"\n title=\"Stop dev server\"\n className=\"inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-md border border-neutral-300 bg-white px-3 text-xs font-semibold text-neutral-900 shadow-md transition-colors hover:border-red-500 hover:bg-red-50 hover:text-red-600 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-100 dark:hover:border-red-500 dark:hover:bg-red-950 dark:hover:text-red-400\"\n >\n {deploy.stopLoading ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <Square className=\"h-3.5 w-3.5 fill-current\" />\n )}\n <span>Stop</span>\n </button>\n <button\n type=\"button\"\n onClick={openPreviewInNewTab}\n aria-label={`Open ${data.name} in a new tab`}\n title={effectiveDeploymentUrl}\n className=\"inline-flex h-9 cursor-pointer items-center gap-1.5 rounded-md border border-neutral-300 bg-white px-3 text-xs font-semibold text-neutral-900 shadow-md transition-colors hover:bg-neutral-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-100 dark:hover:bg-neutral-800\"\n >\n <ExternalLink className=\"h-3.5 w-3.5\" />\n <span>Open</span>\n </button>\n </div>\n </div>\n </div>\n ) : null}\n\n {/* Row 3: Run / dev-server status — mirrors the repository\n node's \"Run | start local environment | ▶\" line so apps\n and repos read as visual peers. Carries every transient\n state (Booting / Stopping / Error) inline instead of\n inflating the card with a placeholder slot. */}\n <div\n data-testid=\"application-node-dev-preview\"\n className=\"border-border/50 flex items-center gap-2 border-t px-4 py-2 text-xs\"\n onClick={stopCardClick}\n >\n {deploy.deployError ? (\n <span className=\"truncate text-xs text-red-500\">{deploy.deployError}</span>\n ) : deploy.status === DeploymentState.Booting || deploy.deployLoading ? (\n <span className=\"text-muted-foreground inline-flex items-center gap-1.5\">\n <Loader2 className=\"h-3 w-3 shrink-0 animate-spin text-amber-500\" />\n <span>Starting…</span>\n </span>\n ) : deploy.stopLoading ? (\n <span className=\"text-muted-foreground inline-flex items-center gap-1.5\">\n <Loader2 className=\"h-3 w-3 shrink-0 animate-spin\" />\n <span>Stopping…</span>\n </span>\n ) : effectiveDeploymentUrl ? (\n <>\n <span className=\"me-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500\" />\n <a\n href={effectiveDeploymentUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"truncate text-green-700 hover:underline dark:text-green-400\"\n onClick={openPreviewInNewTab}\n >\n {effectiveDeploymentUrl}\n </a>\n </>\n ) : (\n <span className=\"text-muted-foreground inline-flex items-baseline gap-2\">\n <span>Run</span>\n <span className=\"text-muted-foreground/50 text-[10px]\">start local environment</span>\n </span>\n )}\n <span className=\"ms-auto flex items-center gap-1\">\n <span data-testid=\"application-node-repo-count\" className=\"text-muted-foreground/70\">\n {repoCountLabel}\n </span>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n if (deploy.deployError) {\n void deploy.deploy();\n return;\n }\n if (effectiveDeploymentUrl) {\n void deploy.stop();\n return;\n }\n void deploy.deploy();\n }}\n onPointerDown={stopCardClick}\n disabled={deploy.deployLoading || deploy.stopLoading}\n aria-label={\n deploy.deployError\n ? 'Retry'\n : effectiveDeploymentUrl\n ? 'Stop dev server'\n : 'Start dev server'\n }\n className={cn(\n 'text-muted-foreground hover:bg-muted flex h-6 w-6 items-center justify-center rounded transition-colors disabled:cursor-not-allowed disabled:opacity-50',\n !effectiveDeploymentUrl &&\n !deploy.deployError &&\n 'text-green-600 hover:text-green-700 dark:text-green-400 dark:hover:text-green-300'\n )}\n >\n {deploy.deployLoading || deploy.stopLoading ? (\n <Loader2 className=\"h-3 w-3 animate-spin\" />\n ) : deploy.deployError ? (\n <RotateCcw className=\"h-3 w-3\" />\n ) : effectiveDeploymentUrl ? (\n <Square className=\"h-3 w-3 fill-current\" />\n ) : (\n <Play className=\"h-3 w-3 fill-current\" />\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {deploy.deployError\n ? 'Failed — click to retry'\n : effectiveDeploymentUrl\n ? 'Stop dev server'\n : 'Start dev server'}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </span>\n </div>\n </div>\n\n {/* Source handle (right in LTR) — hosts the \"New SDD feature\" action\n button when a callback is wired, mirroring the feature-node pattern.\n Falls back to a hidden handle when no callback is provided so edge\n connections still attach to the same coordinate. */}\n {/* Source handle — invisible edge anchor for child feature edges.\n The user-facing \"+ New\" affordance is in the header (matching\n the repository node), not on this handle. */}\n <Handle\n type=\"source\"\n position={sourceHandlePos}\n isConnectable={false}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n </div>\n );\n}\n","'use client';\n\nimport { BaseEdge, getBezierPath } from '@xyflow/react';\nimport type { EdgeProps } from '@xyflow/react';\n\n/**\n * Custom React Flow edge for parent→child feature dependencies.\n * Uses bezier curves and dashed style matching repo→feature edges.\n */\nexport function DependencyEdge(props: EdgeProps) {\n const [edgePath] = getBezierPath({\n sourceX: props.sourceX,\n sourceY: props.sourceY,\n targetX: props.targetX,\n targetY: props.targetY,\n sourcePosition: props.sourcePosition,\n targetPosition: props.targetPosition,\n });\n\n return (\n <BaseEdge\n id={props.id}\n path={edgePath}\n style={{\n strokeDasharray: '5 5',\n }}\n />\n );\n}\n","'use client';\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { ReactFlow, Background, BackgroundVariant, Panel } from '@xyflow/react';\nimport type { Connection, Edge, NodeChange, OnMoveEnd, Viewport } from '@xyflow/react';\nimport { Plus } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/button';\nimport { EmptyState } from '@/components/common/empty-state';\nimport { FeatureNode } from '@/components/common/feature-node';\nimport type { FeatureNodeType, FeatureNodeData } from '@/components/common/feature-node';\nimport { RepositoryNode } from '@/components/common/repository-node';\nimport type { RepositoryNodeType, RepositoryNodeData } from '@/components/common/repository-node';\nimport { ApplicationNode } from '@/components/common/application-node/application-node';\nimport type { ApplicationNodeType } from '@/components/common/application-node/application-node-config';\nimport { DependencyEdge } from './dependency-edge';\n\nexport type CanvasNodeType = FeatureNodeType | RepositoryNodeType | ApplicationNodeType;\n\nexport interface FeaturesCanvasProps {\n nodes: CanvasNodeType[];\n edges: Edge[];\n selectedFeatureId?: string | null;\n selectedRepository?: { id: string | null; path: string | null };\n defaultViewport?: Viewport;\n onNodesChange?: (changes: NodeChange<CanvasNodeType>[]) => void;\n onAddFeature?: () => void;\n onNodeClick?: (event: React.MouseEvent, node: CanvasNodeType) => void;\n onPaneClick?: (event: React.MouseEvent) => void;\n onConnect?: (connection: Connection) => void;\n onCanvasDrag?: () => void;\n onMoveEnd?: OnMoveEnd;\n toolbar?: React.ReactNode;\n /** Show the toolbar even when the canvas is empty (e.g. empty workspace). Defaults to true. */\n showToolbarOnEmpty?: boolean;\n emptyState?: React.ReactNode;\n}\n\nconst FALLBACK_VIEWPORT: Viewport = { x: 30, y: 30, zoom: 0.85 };\n\nexport function FeaturesCanvas({\n nodes,\n edges,\n selectedFeatureId,\n selectedRepository,\n defaultViewport,\n onNodesChange,\n onAddFeature,\n onConnect,\n onNodeClick,\n onPaneClick,\n onCanvasDrag,\n onMoveEnd,\n toolbar,\n showToolbarOnEmpty = true,\n emptyState,\n}: FeaturesCanvasProps) {\n const { t } = useTranslation('web');\n const nodeTypes = useMemo(\n () => ({\n featureNode: FeatureNode,\n repositoryNode: RepositoryNode,\n applicationNode: ApplicationNode,\n }),\n []\n );\n\n const edgeTypes = useMemo(\n () => ({\n dependencyEdge: DependencyEdge,\n }),\n []\n );\n\n // Callbacks and showHandles are already injected into node.data by deriveGraph.\n // Apply selectedFeatureId and selectedRepository highlighting here.\n const enrichedNodes = useMemo(() => {\n const hasFeatureSel = selectedFeatureId != null;\n const hasRepoSel =\n selectedRepository != null &&\n (selectedRepository.id != null || selectedRepository.path != null);\n if (!hasFeatureSel && !hasRepoSel) return nodes;\n return nodes.map((node) => {\n if (\n hasFeatureSel &&\n node.type === 'featureNode' &&\n (node.data as FeatureNodeData).featureId === selectedFeatureId\n ) {\n return { ...node, selected: true };\n }\n if (hasRepoSel && node.type === 'repositoryNode') {\n const rd = node.data as RepositoryNodeData;\n const matchById =\n selectedRepository!.id != null &&\n (node.id === selectedRepository!.id || rd.id === selectedRepository!.id);\n const matchByPath =\n selectedRepository!.path != null && rd.repositoryPath === selectedRepository!.path;\n if (matchById || matchByPath) return { ...node, selected: true };\n }\n return node;\n }) as CanvasNodeType[];\n }, [nodes, selectedFeatureId, selectedRepository]);\n\n const isEmpty = nodes.length === 0;\n\n // Track empty→populated transition for exit animation.\n // When isEmpty flips from true to false, keep the overlay mounted\n // and fade it out before removing it from the DOM.\n const [showOverlay, setShowOverlay] = useState(isEmpty);\n const [overlayExiting, setOverlayExiting] = useState(false);\n const prevEmptyRef = useRef(isEmpty);\n\n useEffect(() => {\n if (prevEmptyRef.current && !isEmpty) {\n // Was empty, now populated — start exit animation\n setOverlayExiting(true);\n const timer = setTimeout(() => {\n setShowOverlay(false);\n setOverlayExiting(false);\n }, 300);\n prevEmptyRef.current = isEmpty;\n return () => clearTimeout(timer);\n }\n if (!prevEmptyRef.current && isEmpty) {\n // Was populated, now empty — show overlay immediately\n setShowOverlay(true);\n }\n prevEmptyRef.current = isEmpty;\n }, [isEmpty]);\n\n const fallbackEmptyState =\n isEmpty && !emptyState ? (\n <EmptyState\n title={t('canvas.noFeatures')}\n description={t('canvas.noFeaturesDescription')}\n action={\n <Button onClick={onAddFeature}>\n <Plus className=\"me-2 h-4 w-4\" />\n {t('canvas.newFeature')}\n </Button>\n }\n />\n ) : null;\n\n const overlayContent = emptyState ?? fallbackEmptyState;\n\n return (\n <div\n data-testid={isEmpty ? 'features-canvas-empty' : 'features-canvas'}\n data-no-drawer-close\n className=\"dark:bg-background pointer-events-auto relative h-full w-full bg-[#f6f7f8]\"\n >\n <ReactFlow\n nodes={enrichedNodes}\n edges={edges}\n nodeTypes={nodeTypes}\n edgeTypes={edgeTypes}\n onConnect={onConnect}\n onNodesChange={onNodesChange}\n onNodeClick={onNodeClick}\n onPaneClick={onPaneClick}\n onMoveStart={onCanvasDrag}\n onMoveEnd={onMoveEnd}\n defaultViewport={defaultViewport ?? FALLBACK_VIEWPORT}\n nodesDraggable={false}\n nodesConnectable={false}\n elementsSelectable={false}\n proOptions={{ hideAttribution: true }}\n className=\"[&_.react-flow__pane]:!cursor-default\"\n >\n <Background\n variant={BackgroundVariant.Dots}\n gap={24}\n size={1}\n color=\"#b8bcc4\"\n className=\"dark:[&_circle]:!fill-white/[0.1]\"\n />\n {toolbar && !isEmpty ? (\n <Panel position=\"top-right\" className=\"!me-3 !mt-3\">\n {toolbar}\n </Panel>\n ) : null}\n </ReactFlow>\n {showOverlay && overlayContent ? (\n <div\n className={cn(\n 'pointer-events-none absolute inset-0 z-10 flex items-center justify-center transition-opacity duration-300',\n overlayExiting ? 'opacity-0' : 'animate-in fade-in opacity-100 duration-200'\n )}\n >\n <div className=\"pointer-events-auto h-full w-full\">{overlayContent}</div>\n </div>\n ) : null}\n {/* Toolbar rendered above the empty-state overlay so the workspace\n selector remains usable while an empty workspace is shown.\n Hidden when showToolbarOnEmpty is false (welcome prompt screen). */}\n {toolbar && isEmpty && showToolbarOnEmpty ? (\n <div className=\"pointer-events-auto absolute end-3 top-3 z-20\">{toolbar}</div>\n ) : null}\n </div>\n );\n}\n","'use client';\n\nimport { useCallback } from 'react';\nimport { useReactFlow } from '@xyflow/react';\nimport type { Viewport } from '@xyflow/react';\nimport { Eye, EyeOff, ZoomIn, ZoomOut, Maximize, RotateCcw } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\n\nexport interface CanvasToolbarProps {\n showArchived: boolean;\n onToggleArchived: () => void;\n onResetViewport?: () => Viewport;\n /** Optional slot rendered at the start of the toolbar (e.g. workspace selector). */\n startSlot?: React.ReactNode;\n}\n\nexport function CanvasToolbar({\n showArchived,\n onToggleArchived,\n onResetViewport,\n startSlot,\n}: CanvasToolbarProps) {\n const { t } = useTranslation('web');\n const { zoomIn, zoomOut, fitView, setViewport } = useReactFlow();\n\n const handleZoomIn = useCallback(() => {\n zoomIn({ duration: 200 });\n }, [zoomIn]);\n\n const handleZoomOut = useCallback(() => {\n zoomOut({ duration: 200 });\n }, [zoomOut]);\n\n const handleFitView = useCallback(() => {\n fitView({ duration: 400, padding: 0.3 });\n }, [fitView]);\n\n const handleReset = useCallback(() => {\n if (onResetViewport) {\n const viewport = onResetViewport();\n setViewport(viewport, { duration: 400 });\n }\n }, [onResetViewport, setViewport]);\n\n return (\n <div className=\"bg-background flex items-center gap-1 rounded-xl border px-2 py-1.5 shadow-md dark:bg-neutral-900\">\n {startSlot ? (\n <>\n {startSlot}\n <div className=\"bg-border mx-1 h-5 w-px\" />\n </>\n ) : null}\n {/* View controls */}\n <ToolbarButton\n onClick={onToggleArchived}\n title={showArchived ? t('canvas.hideArchived') : t('canvas.showArchived')}\n active={showArchived}\n label={showArchived ? t('canvas.hideArchivedLabel') : t('canvas.showArchivedLabel')}\n >\n {showArchived ? <Eye className=\"h-4 w-4\" /> : <EyeOff className=\"h-4 w-4\" />}\n </ToolbarButton>\n\n <div className=\"bg-border mx-1 h-5 w-px\" />\n\n {/* Zoom controls */}\n <ToolbarButton onClick={handleZoomOut} title={t('canvas.zoomOut')}>\n <ZoomOut className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton onClick={handleZoomIn} title={t('canvas.zoomIn')}>\n <ZoomIn className=\"h-4 w-4\" />\n </ToolbarButton>\n <ToolbarButton onClick={handleFitView} title={t('canvas.fitView')}>\n <Maximize className=\"h-4 w-4\" />\n </ToolbarButton>\n {onResetViewport ? (\n <ToolbarButton onClick={handleReset} title={t('canvas.resetView')}>\n <RotateCcw className=\"h-4 w-4\" />\n </ToolbarButton>\n ) : null}\n </div>\n );\n}\n\n// ── Internal button ──────────────────────────────────────────────────────\n\nfunction ToolbarButton({\n children,\n onClick,\n title,\n label,\n active,\n}: {\n children: React.ReactNode;\n onClick: () => void;\n title: string;\n label?: string;\n active?: boolean;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n title={title}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n active ? 'text-primary bg-primary/10' : 'text-muted-foreground'\n )}\n >\n {children}\n {label ? <span>{label}</span> : null}\n </button>\n );\n}\n","'use client';\n\n/**\n * Playground prototype: client-side workspaces.\n *\n * ⚠️ PROTOTYPE BOUNDARY — DO NOT IMPORT FROM OUTSIDE THIS PROTOTYPE ⚠️\n *\n * A workspace is a named, explicit allowlist of repositories and features\n * that should appear on the canvas. The \"default\" workspace is special: it\n * always shows everything (its allowlists are ignored).\n *\n * Persistence: localStorage only. There is no backend, no domain model, no\n * use cases, and no infrastructure adapter. Mutation rules (\"default is\n * read-only\", \"default always exists\", rename validation) are enforced\n * inline rather than as domain invariants.\n *\n * This file deliberately violates Clean Architecture by holding domain\n * shape (`Workspace`), application logic (mutations + invariants), and\n * infrastructure concerns (localStorage persistence) inside a React hook.\n * It exists ONLY to validate the workspace UX on the playground branch.\n *\n * Before promoting workspaces to a real feature, replace this file with:\n * - tsp/Workspace.tsp — domain entity\n * - application/ports/output/repositories/\n * workspace.repository.interface.ts — output port\n * - application/use-cases/workspaces/\n * create-workspace.use-case.ts\n * rename-workspace.use-case.ts\n * delete-workspace.use-case.ts\n * set-workspace-members.use-case.ts\n * list-workspaces.use-case.ts\n * set-active-workspace.use-case.ts\n * - infrastructure/repositories/sqlite-workspace.repository.ts\n *\n * Then this hook becomes a thin client wrapper that calls server actions\n * backed by those use cases. Until that refactor lands, the `Workspace`\n * type defined here MUST NOT be imported from any non-prototype code.\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nconst STORAGE_KEY = 'shep:workspaces:v1';\nexport const DEFAULT_WORKSPACE_ID = 'default';\nexport const DEFAULT_WORKSPACE_NAME = 'Default';\n\nexport interface Workspace {\n id: string;\n name: string;\n /** Repository node IDs (React Flow node ids, e.g. \"repo-...\"). */\n repoIds: string[];\n /** Feature node IDs (React Flow node ids, e.g. \"feat-...\"). */\n featureIds: string[];\n}\n\ninterface WorkspacesState {\n workspaces: Workspace[];\n activeWorkspaceId: string;\n}\n\nconst INITIAL_STATE: WorkspacesState = {\n workspaces: [\n {\n id: DEFAULT_WORKSPACE_ID,\n name: DEFAULT_WORKSPACE_NAME,\n repoIds: [],\n featureIds: [],\n },\n ],\n activeWorkspaceId: DEFAULT_WORKSPACE_ID,\n};\n\nfunction loadState(): WorkspacesState {\n if (typeof window === 'undefined') return INITIAL_STATE;\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY);\n if (!raw) return INITIAL_STATE;\n const parsed = JSON.parse(raw) as Partial<WorkspacesState>;\n if (!parsed.workspaces || !Array.isArray(parsed.workspaces)) return INITIAL_STATE;\n // Make sure default workspace always exists\n const hasDefault = parsed.workspaces.some((w) => w.id === DEFAULT_WORKSPACE_ID);\n const workspaces = hasDefault\n ? parsed.workspaces\n : [INITIAL_STATE.workspaces[0]!, ...parsed.workspaces];\n return {\n workspaces,\n activeWorkspaceId: parsed.activeWorkspaceId ?? DEFAULT_WORKSPACE_ID,\n };\n } catch {\n return INITIAL_STATE;\n }\n}\n\nfunction saveState(state: WorkspacesState) {\n if (typeof window === 'undefined') return;\n try {\n window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n } catch {\n // localStorage may be unavailable (private mode); ignore.\n }\n}\n\nfunction generateId(): string {\n return `ws-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nexport interface UseWorkspacesResult {\n workspaces: Workspace[];\n activeWorkspace: Workspace;\n activeWorkspaceId: string;\n isDefaultActive: boolean;\n setActiveWorkspace: (id: string) => void;\n createWorkspace: (name: string) => Workspace;\n renameWorkspace: (id: string, name: string) => void;\n deleteWorkspace: (id: string) => void;\n setWorkspaceMembers: (id: string, members: { repoIds: string[]; featureIds: string[] }) => void;\n toggleRepoInActive: (repoId: string) => void;\n toggleFeatureInActive: (featureId: string) => void;\n /**\n * Append node IDs to the active workspace's allowlists. No-op when the\n * default workspace is active (it shows everything anyway). Idempotent —\n * IDs already present are skipped.\n */\n addToActiveWorkspace: (members: { repoIds?: string[]; featureIds?: string[] }) => void;\n}\n\nexport function useWorkspaces(): UseWorkspacesResult {\n const [state, setState] = useState<WorkspacesState>(INITIAL_STATE);\n\n // Hydrate from localStorage on mount (client-only).\n useEffect(() => {\n setState(loadState());\n }, []);\n\n // Persist whenever state changes (after hydration).\n useEffect(() => {\n saveState(state);\n }, [state]);\n\n const setActiveWorkspace = useCallback((id: string) => {\n setState((prev) => {\n if (!prev.workspaces.some((w) => w.id === id)) return prev;\n return { ...prev, activeWorkspaceId: id };\n });\n }, []);\n\n const createWorkspace = useCallback((name: string): Workspace => {\n const trimmed = name.trim() || 'Untitled workspace';\n const next: Workspace = {\n id: generateId(),\n name: trimmed,\n repoIds: [],\n featureIds: [],\n };\n setState((prev) => ({\n workspaces: [...prev.workspaces, next],\n activeWorkspaceId: next.id,\n }));\n return next;\n }, []);\n\n const renameWorkspace = useCallback((id: string, name: string) => {\n if (id === DEFAULT_WORKSPACE_ID) return;\n const trimmed = name.trim();\n if (!trimmed) return;\n setState((prev) => ({\n ...prev,\n workspaces: prev.workspaces.map((w) => (w.id === id ? { ...w, name: trimmed } : w)),\n }));\n }, []);\n\n const deleteWorkspace = useCallback((id: string) => {\n if (id === DEFAULT_WORKSPACE_ID) return;\n setState((prev) => {\n const workspaces = prev.workspaces.filter((w) => w.id !== id);\n const activeWorkspaceId =\n prev.activeWorkspaceId === id ? DEFAULT_WORKSPACE_ID : prev.activeWorkspaceId;\n return { workspaces, activeWorkspaceId };\n });\n }, []);\n\n const setWorkspaceMembers = useCallback(\n (id: string, members: { repoIds: string[]; featureIds: string[] }) => {\n if (id === DEFAULT_WORKSPACE_ID) return;\n setState((prev) => ({\n ...prev,\n workspaces: prev.workspaces.map((w) =>\n w.id === id\n ? { ...w, repoIds: [...members.repoIds], featureIds: [...members.featureIds] }\n : w\n ),\n }));\n },\n []\n );\n\n const toggleMember = useCallback((kind: 'repo' | 'feature', nodeId: string) => {\n setState((prev) => {\n if (prev.activeWorkspaceId === DEFAULT_WORKSPACE_ID) return prev;\n return {\n ...prev,\n workspaces: prev.workspaces.map((w) => {\n if (w.id !== prev.activeWorkspaceId) return w;\n const list = kind === 'repo' ? w.repoIds : w.featureIds;\n const nextList = list.includes(nodeId)\n ? list.filter((x) => x !== nodeId)\n : [...list, nodeId];\n return kind === 'repo' ? { ...w, repoIds: nextList } : { ...w, featureIds: nextList };\n }),\n };\n });\n }, []);\n\n const toggleRepoInActive = useCallback(\n (repoId: string) => toggleMember('repo', repoId),\n [toggleMember]\n );\n const toggleFeatureInActive = useCallback(\n (featureId: string) => toggleMember('feature', featureId),\n [toggleMember]\n );\n\n const addToActiveWorkspace = useCallback(\n (members: { repoIds?: string[]; featureIds?: string[] }) => {\n const incomingRepos = members.repoIds ?? [];\n const incomingFeatures = members.featureIds ?? [];\n if (incomingRepos.length === 0 && incomingFeatures.length === 0) return;\n\n setState((prev) => {\n if (prev.activeWorkspaceId === DEFAULT_WORKSPACE_ID) return prev;\n return {\n ...prev,\n workspaces: prev.workspaces.map((w) => {\n if (w.id !== prev.activeWorkspaceId) return w;\n const repoSet = new Set(w.repoIds);\n for (const id of incomingRepos) repoSet.add(id);\n const featureSet = new Set(w.featureIds);\n for (const id of incomingFeatures) featureSet.add(id);\n // Bail out if nothing actually changed — keeps referential equality\n // so downstream effects don't re-fire.\n if (repoSet.size === w.repoIds.length && featureSet.size === w.featureIds.length) {\n return w;\n }\n return {\n ...w,\n repoIds: Array.from(repoSet),\n featureIds: Array.from(featureSet),\n };\n }),\n };\n });\n },\n []\n );\n\n const activeWorkspace =\n state.workspaces.find((w) => w.id === state.activeWorkspaceId) ?? state.workspaces[0]!;\n\n return {\n workspaces: state.workspaces,\n activeWorkspace,\n activeWorkspaceId: state.activeWorkspaceId,\n isDefaultActive: state.activeWorkspaceId === DEFAULT_WORKSPACE_ID,\n setActiveWorkspace,\n createWorkspace,\n renameWorkspace,\n deleteWorkspace,\n setWorkspaceMembers,\n toggleRepoInActive,\n toggleFeatureInActive,\n addToActiveWorkspace,\n };\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { Layers, Check, Plus, Pencil, Trash2, SlidersHorizontal } from 'lucide-react';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu';\nimport { cn } from '@/lib/utils';\nimport {\n DEFAULT_WORKSPACE_ID,\n type UseWorkspacesResult,\n type Workspace,\n} from '@/hooks/use-workspaces';\n\nexport interface WorkspaceSelectorProps {\n workspaces: UseWorkspacesResult['workspaces'];\n activeWorkspace: Workspace;\n onSelect: (id: string) => void;\n onRequestCreate: () => void;\n onRequestRename: () => void;\n /** Request deletion of a specific workspace by id. */\n onRequestDelete: (id: string) => void;\n onManage: () => void;\n}\n\nexport function WorkspaceSelector({\n workspaces,\n activeWorkspace,\n onSelect,\n onRequestCreate,\n onRequestRename,\n onRequestDelete,\n onManage,\n}: WorkspaceSelectorProps) {\n const [open, setOpen] = useState(false);\n const isDefault = activeWorkspace.id === DEFAULT_WORKSPACE_ID;\n\n return (\n <DropdownMenu open={open} onOpenChange={setOpen}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-testid=\"workspace-selector-trigger\"\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-xs font-medium transition-colors',\n 'hover:bg-accent hover:text-accent-foreground',\n isDefault ? 'text-muted-foreground' : 'text-primary bg-primary/10'\n )}\n title=\"Workspace\"\n >\n <Layers className=\"h-4 w-4\" />\n <span className=\"max-w-[120px] truncate\">{activeWorkspace.name}</span>\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"min-w-[220px]\">\n <DropdownMenuLabel>Workspaces</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {workspaces.map((w) => {\n const active = w.id === activeWorkspace.id;\n const canDelete = w.id !== DEFAULT_WORKSPACE_ID;\n return (\n <DropdownMenuItem\n key={w.id}\n onSelect={() => onSelect(w.id)}\n className=\"group/ws-row flex items-center justify-between gap-2\"\n >\n <span className=\"truncate\">{w.name}</span>\n <span className=\"flex shrink-0 items-center gap-1\">\n {active ? <Check className=\"h-3.5 w-3.5\" /> : null}\n {canDelete ? (\n <button\n type=\"button\"\n aria-label={`Delete workspace ${w.name}`}\n title={`Delete workspace ${w.name}`}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n setOpen(false);\n onRequestDelete(w.id);\n }}\n className=\"text-muted-foreground hover:bg-destructive/10 hover:text-destructive rounded p-0.5 opacity-0 transition-opacity group-hover/ws-row:opacity-100 focus-visible:opacity-100\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n ) : null}\n </span>\n </DropdownMenuItem>\n );\n })}\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={onRequestCreate}>\n <Plus className=\"mr-2 h-3.5 w-3.5\" />\n New workspace…\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onManage} disabled={isDefault}>\n <SlidersHorizontal className=\"mr-2 h-3.5 w-3.5\" />\n Manage items…\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onRequestRename} disabled={isDefault}>\n <Pencil className=\"mr-2 h-3.5 w-3.5\" />\n Rename\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { GitBranch, Sparkles } from 'lucide-react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Button } from '@/components/ui/button';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { Workspace } from '@/hooks/use-workspaces';\n\nexport interface ManageWorkspaceDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n workspace: Workspace;\n /** All nodes currently on the canvas (unfiltered). */\n allNodes: CanvasNodeType[];\n onSave: (members: { repoIds: string[]; featureIds: string[] }) => void;\n}\n\ninterface RepoEntry {\n nodeId: string;\n name: string;\n features: { nodeId: string; name: string }[];\n}\n\nexport function ManageWorkspaceDialog({\n open,\n onOpenChange,\n workspace,\n allNodes,\n onSave,\n}: ManageWorkspaceDialogProps) {\n const [selectedRepoIds, setSelectedRepoIds] = useState<Set<string>>(new Set());\n const [selectedFeatureIds, setSelectedFeatureIds] = useState<Set<string>>(new Set());\n\n // Reset selection state whenever the dialog opens for a (possibly different) workspace.\n useEffect(() => {\n if (open) {\n setSelectedRepoIds(new Set(workspace.repoIds));\n setSelectedFeatureIds(new Set(workspace.featureIds));\n }\n }, [open, workspace]);\n\n // Group features under their parent repo by repositoryPath.\n const repoEntries = useMemo<RepoEntry[]>(() => {\n const repos: RepoEntry[] = [];\n const byPath = new Map<string, RepoEntry>();\n\n for (const node of allNodes) {\n if (node.type !== 'repositoryNode') continue;\n const data = node.data as RepositoryNodeData;\n const path = data.repositoryPath ?? '';\n const entry: RepoEntry = {\n nodeId: node.id,\n name: data.name ?? path.split('/').filter(Boolean).pop() ?? path,\n features: [],\n };\n repos.push(entry);\n byPath.set(path, entry);\n }\n\n for (const node of allNodes) {\n if (node.type !== 'featureNode') continue;\n const data = node.data as FeatureNodeData;\n const repo = byPath.get(data.repositoryPath ?? '');\n if (repo) {\n repo.features.push({ nodeId: node.id, name: data.name });\n }\n }\n\n return repos;\n }, [allNodes]);\n\n const toggleRepo = (id: string) => {\n setSelectedRepoIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const toggleFeature = (id: string) => {\n setSelectedFeatureIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n };\n\n const handleSave = () => {\n onSave({\n repoIds: Array.from(selectedRepoIds),\n featureIds: Array.from(selectedFeatureIds),\n });\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[80vh] max-w-lg overflow-hidden\">\n <DialogHeader>\n <DialogTitle>Manage workspace: {workspace.name}</DialogTitle>\n <DialogDescription>\n Select the repositories and features that should appear on this workspace's canvas.\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"-mx-6 max-h-[50vh] overflow-y-auto px-6\">\n {repoEntries.length === 0 ? (\n <p className=\"text-muted-foreground py-8 text-center text-sm\">\n No repositories on the canvas yet.\n </p>\n ) : (\n <ul className=\"space-y-3 py-2\">\n {repoEntries.map((repo) => (\n <li key={repo.nodeId}>\n <label className=\"hover:bg-accent/30 flex cursor-pointer items-center gap-2 rounded-md px-2 py-1.5\">\n <Checkbox\n checked={selectedRepoIds.has(repo.nodeId)}\n onCheckedChange={() => toggleRepo(repo.nodeId)}\n />\n <GitBranch className=\"text-muted-foreground h-4 w-4\" />\n <span className=\"text-sm font-medium\">{repo.name}</span>\n </label>\n {repo.features.length > 0 ? (\n <ul className=\"mt-1 ml-7 space-y-0.5\">\n {repo.features.map((feat) => (\n <li key={feat.nodeId}>\n <label className=\"hover:bg-accent/30 flex cursor-pointer items-center gap-2 rounded-md px-2 py-1\">\n <Checkbox\n checked={selectedFeatureIds.has(feat.nodeId)}\n onCheckedChange={() => toggleFeature(feat.nodeId)}\n />\n <Sparkles className=\"text-muted-foreground h-3.5 w-3.5\" />\n <span className=\"text-muted-foreground text-xs\">{feat.name}</span>\n </label>\n </li>\n ))}\n </ul>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </div>\n\n <DialogFooter>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button onClick={handleSave}>Save</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n","'use client';\n\nimport { useEffect, useState } from 'react';\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Input } from '@/components/ui/input';\nimport { Button } from '@/components/ui/button';\n\nexport interface WorkspaceNameDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description?: string;\n initialValue?: string;\n confirmLabel: string;\n onConfirm: (name: string) => void;\n}\n\nexport function WorkspaceNameDialog({\n open,\n onOpenChange,\n title,\n description,\n initialValue = '',\n confirmLabel,\n onConfirm,\n}: WorkspaceNameDialogProps) {\n const [value, setValue] = useState(initialValue);\n\n useEffect(() => {\n if (open) setValue(initialValue);\n }, [open, initialValue]);\n\n const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const trimmed = value.trim();\n if (!trimmed) return;\n onConfirm(trimmed);\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-sm\">\n <form onSubmit={handleSubmit}>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n <div className=\"py-4\">\n <Input\n autoFocus\n value={value}\n onChange={(e) => setValue(e.target.value)}\n placeholder=\"Workspace name\"\n data-testid=\"workspace-name-input\"\n />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"ghost\" onClick={() => onOpenChange(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={!value.trim()}>\n {confirmLabel}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n}\n","'use client';\n\nimport { usePathname } from 'next/navigation';\n\n/**\n * Extracts the selected feature ID from the current URL path.\n * Returns `null` when no feature drawer route is active.\n */\nexport function useSelectedFeatureId(): string | null {\n const pathname = usePathname();\n const match = pathname.match(/^\\/feature\\/([^/]+)/);\n return match?.[1] ?? null;\n}\n","'use client';\n\nimport { usePathname, useSearchParams } from 'next/navigation';\nimport { URL_PARAMS } from '@/lib/url-params';\n\n/**\n * Extracts the selected repository context from the current URL.\n * Returns `{ id, path }` — either or both may be set depending on the route.\n *\n * Matches:\n * - `/repository/<id>` → id is set\n * - `/create?repo=<path>` → path is set\n */\nexport function useSelectedRepository(): { id: string | null; path: string | null } {\n const pathname = usePathname();\n const searchParams = useSearchParams();\n\n const repoIdMatch = pathname.match(/^\\/repository\\/([^/]+)/);\n const id = repoIdMatch?.[1] ?? null;\n\n const isCreate = pathname.startsWith('/create');\n const path = isCreate ? searchParams.get(URL_PARAMS.repo) : null;\n\n return { id, path };\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport type { Viewport } from '@xyflow/react';\n\nexport type { Viewport } from '@xyflow/react';\n\nexport const STORAGE_KEY = 'shep-canvas-viewport';\nexport const DEBOUNCE_MS = 500;\n\nexport const DEFAULT_VIEWPORT: Viewport = { x: 30, y: 30, zoom: 0.85 };\n\nexport interface UseViewportPersistenceResult {\n defaultViewport: Viewport;\n onMoveEnd: (viewport: Viewport) => void;\n resetViewport: () => Viewport;\n}\n\nfunction isValidViewport(value: unknown): value is Viewport {\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n const v = value as Record<string, unknown>;\n return (\n typeof v.x === 'number' &&\n typeof v.y === 'number' &&\n typeof v.zoom === 'number' &&\n Number.isFinite(v.x) &&\n Number.isFinite(v.y) &&\n Number.isFinite(v.zoom) &&\n v.zoom > 0\n );\n}\n\nfunction readViewport(): Viewport {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (raw == null) return DEFAULT_VIEWPORT;\n const parsed: unknown = JSON.parse(raw);\n return isValidViewport(parsed) ? parsed : DEFAULT_VIEWPORT;\n } catch {\n return DEFAULT_VIEWPORT;\n }\n}\n\nexport function useViewportPersistence(): UseViewportPersistenceResult {\n const defaultViewport = useRef<Viewport>(readViewport()).current;\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current != null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const onMoveEnd = useCallback((viewport: Viewport) => {\n if (timerRef.current != null) {\n clearTimeout(timerRef.current);\n }\n timerRef.current = setTimeout(() => {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(viewport));\n } catch {\n // Silently ignore localStorage errors (quota exceeded, private browsing, etc.)\n }\n }, DEBOUNCE_MS);\n }, []);\n\n const resetViewport = useCallback((): Viewport => {\n try {\n localStorage.removeItem(STORAGE_KEY);\n } catch {\n // Silently ignore localStorage errors\n }\n return DEFAULT_VIEWPORT;\n }, []);\n\n return { defaultViewport, onMoveEnd, resetViewport };\n}\n","/* __next_internal_action_entry_do_not_use__ [{\"000dc696afafd019691d30ebc74c3bb2bf6be80fc9\":\"isAgentSetupComplete\"},\"src/presentation/web/app/actions/agent-setup-flag.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"000dc696afafd019691d30ebc74c3bb2bf6be80fc9\",callServer,void 0,findSourceMapURL,\"isAgentSetupComplete\");export{$$RSC_SERVER_ACTION_0 as isAgentSetupComplete};","/* __next_internal_action_entry_do_not_use__ [{\"00043b20dfa79e7ce6d504a372669a2b7396e4f421\":\"checkAgentAuth\"},\"src/presentation/web/app/actions/check-agent-auth.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"00043b20dfa79e7ce6d504a372669a2b7396e4f421\",callServer,void 0,findSourceMapURL,\"checkAgentAuth\");export{$$RSC_SERVER_ACTION_0 as checkAgentAuth};","'use client';\n\nimport type { ReactNode } from 'react';\nimport { ReactFlowProvider } from '@xyflow/react';\nimport type { Edge } from '@xyflow/react';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport { SessionsProvider } from '@/hooks/sessions-provider';\nimport { ControlCenterInner } from './control-center-inner';\n\nexport interface ControlCenterProps {\n initialNodes: CanvasNodeType[];\n initialEdges: Edge[];\n /** Drawer content rendered by the @drawer parallel route slot. */\n drawer?: ReactNode;\n}\n\nexport function ControlCenter({ initialNodes, initialEdges, drawer }: ControlCenterProps) {\n return (\n <div data-testid=\"control-center\" className=\"h-full w-full\">\n <SessionsProvider>\n <ReactFlowProvider>\n <ControlCenterInner initialNodes={initialNodes} initialEdges={initialEdges} />\n </ReactFlowProvider>\n </SessionsProvider>\n <div key=\"drawer\">{drawer}</div>\n </div>\n );\n}\n","/* __next_internal_action_entry_do_not_use__ [{\"00fd3bb249b5c2f4771f7eac594bf5656eaf959cdb\":\"checkToolStatus\"},\"src/presentation/web/app/actions/check-tool-status.ts\",\"\"] */\"use turbopack no side effects\";import{createServerReference,callServer,findSourceMapURL}from\"private-next-rsc-action-client-wrapper\";const $$RSC_SERVER_ACTION_0=/*#__PURE__*/createServerReference(\"00fd3bb249b5c2f4771f7eac594bf5656eaf959cdb\",callServer,void 0,findSourceMapURL,\"checkToolStatus\");export{$$RSC_SERVER_ACTION_0 as checkToolStatus};","'use client';\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport { useRouter } from 'next/navigation';\nimport {\n Github,\n Plus,\n Code2,\n Terminal,\n FolderOpen,\n Trash2,\n Play,\n Square,\n GitBranch,\n GitCommitHorizontal,\n ArrowDown,\n User,\n RotateCcw,\n MessageSquare,\n} from 'lucide-react';\nimport { Trans, useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport { buildCreateUrl } from '@/lib/url-params';\nimport { ActionButton } from '@/components/common/action-button';\nimport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@/components/ui/dialog';\nimport { Button } from '@/components/ui/button';\nimport { Checkbox } from '@/components/ui/checkbox';\nimport { Label } from '@/components/ui/label';\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';\nimport { useDeployAction } from '@/hooks/use-deploy-action';\nimport { useFeatureFlags } from '@/hooks/feature-flags-context';\nimport type { RepositoryNodeData } from './repository-node-config';\nimport { useRepositoryActions } from './use-repository-actions';\nimport { ChatDotIndicator } from '@/components/features/chat/ChatDotIndicator';\nimport { useTurnStatus } from '@/hooks/turn-statuses-provider';\nimport {\n FeatureSessionsDropdown,\n type SessionSummary,\n} from '@/components/common/feature-node/feature-sessions-dropdown';\n\nexport function RepositoryNode({\n data,\n selected,\n}: {\n data: RepositoryNodeData;\n selected?: boolean;\n [key: string]: unknown;\n}) {\n const { t, i18n } = useTranslation('web');\n const router = useRouter();\n const isRtl = i18n.dir() === 'rtl';\n const targetHandlePos = isRtl ? Position.Right : Position.Left;\n const sourceHandlePos = isRtl ? Position.Left : Position.Right;\n const featureFlags = useFeatureFlags();\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [deleteFromDisk, setDeleteFromDisk] = useState(false);\n useEffect(() => {\n if (confirmOpen) setDeleteFromDisk(false);\n }, [confirmOpen]);\n const repoScopeId = data.id ? `repo-${data.id}` : `repo-${data.name}`;\n const chatTurnStatus = useTurnStatus(repoScopeId);\n const actions = useRepositoryActions(\n data.repositoryPath ? { repositoryId: data.id, repositoryPath: data.repositoryPath } : null\n );\n const deployAction = useDeployAction(\n data.repositoryPath\n ? {\n targetId: data.repositoryPath,\n targetType: 'repository',\n repositoryPath: data.repositoryPath,\n }\n : null\n );\n const isDeploymentActive = deployAction.status === 'Booting' || deployAction.status === 'Ready';\n\n const handleCreateFromSession = useCallback(\n (session: SessionSummary, sessionFilePath: string) => {\n if (!data.repositoryPath) return;\n const preview = session.preview ? session.preview.slice(0, 200) : 'Unknown conversation';\n const prompt = [\n `Continue work from a previous agent session.`,\n ``,\n `## Session Context`,\n `- Session ID: ${session.id}`,\n `- Messages: ${session.messageCount}`,\n session.lastMessageAt ? `- Last active: ${session.lastMessageAt}` : '',\n `- Conversation file: ${sessionFilePath}`,\n ``,\n `## Session Preview`,\n `> ${preview}`,\n ``,\n `## Instructions`,\n `1. Read the full conversation history from the file above`,\n `2. Analyze the current state of the repository — what was done, what remains`,\n `3. Create or update spec files to accurately reflect the current state and remaining work`,\n `4. Continue implementing any unfinished work from the conversation`,\n ]\n .filter(Boolean)\n .join('\\n');\n\n router.push(buildCreateUrl({ repo: data.repositoryPath, prompt }));\n },\n [data.repositoryPath, router]\n );\n\n return (\n <div\n className={cn('group relative', data.onDelete && data.id && 'ps-10')}\n style={{ direction: isRtl ? 'rtl' : 'ltr' }}\n >\n {data.showHandles ? (\n <Handle\n type=\"target\"\n position={targetHandlePos}\n isConnectable={false}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n ) : null}\n\n {/* Delete button — visible on hover, positioned to the left */}\n {data.onDelete && data.id ? (\n <>\n <div className=\"absolute -start-3 top-1/2 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100\">\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n aria-label={t('repositoryNode.removeRepository')}\n data-testid=\"repository-node-delete-button\"\n onClick={(e) => {\n e.stopPropagation();\n setConfirmOpen(true);\n }}\n className=\"bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors\"\n >\n <Trash2 className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.removeRepository')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n\n <Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>\n <DialogContent className=\"max-w-sm\">\n <DialogHeader>\n <DialogTitle>{t('repositoryNode.removeConfirmTitle')}</DialogTitle>\n <DialogDescription>\n <Trans\n t={t}\n i18nKey=\"repositoryNode.removeConfirmDescription\"\n values={{ name: data.name }}\n components={{ strong: <strong /> }}\n />{' '}\n {deleteFromDisk\n ? t('repositoryNode.removeConfirmDescriptionDeleteFiles')\n : t('repositoryNode.removeConfirmDescriptionKeepFiles')}\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id=\"repository-delete-from-disk\"\n checked={deleteFromDisk}\n onCheckedChange={(checked) => setDeleteFromDisk(checked === true)}\n data-testid=\"repository-node-delete-from-disk-checkbox\"\n aria-label={t('repositoryNode.deleteFromDiskLabel')}\n />\n <Label\n htmlFor=\"repository-delete-from-disk\"\n className=\"cursor-pointer text-sm font-normal\"\n >\n {t('repositoryNode.deleteFromDiskLabel')}\n </Label>\n </div>\n <DialogFooter className=\"grid grid-cols-2 gap-2 sm:flex-none\">\n <DialogClose asChild>\n <Button variant=\"outline\">{t('repositoryNode.cancel')}</Button>\n </DialogClose>\n <Button\n variant=\"destructive\"\n data-testid=\"repository-node-delete-confirm-button\"\n onClick={() => {\n setConfirmOpen(false);\n data.onDelete?.(data.id!, { deleteFromDisk });\n }}\n >\n {t('repositoryNode.remove')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n ) : null}\n\n <div\n role=\"button\"\n tabIndex={0}\n data-testid=\"repository-node-card\"\n data-repo-name={data.name}\n onClick={(e) => {\n e.stopPropagation();\n data.onClick?.();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n e.stopPropagation();\n data.onClick?.();\n }\n }}\n className={cn(\n 'nodrag bg-card flex w-[26rem] cursor-pointer flex-col overflow-hidden rounded-xl border shadow-sm transition-[border-color,box-shadow] duration-200 dark:bg-neutral-800/80',\n selected && 'border-blue-400 dark:border-amber-500/60'\n )}\n >\n {/* Row 1: Repository name + action buttons */}\n <div className=\"flex items-center gap-3 px-4 py-3\">\n <Github className=\"text-muted-foreground h-5 w-5 shrink-0\" />\n <span data-testid=\"repository-node-name\" className=\"min-w-0 truncate text-sm font-medium\">\n {data.name}\n </span>\n\n <div\n className={cn(\n 'flex shrink-0 items-center gap-2',\n (data.repositoryPath ?? data.onAdd) && 'ms-auto'\n )}\n onClick={(e) => e.stopPropagation()}\n >\n {data.repositoryPath ? (\n <>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex items-center\">\n <ActionButton\n label={t('repositoryNode.openInIde')}\n onClick={actions.openInIde}\n loading={actions.ideLoading}\n error={!!actions.ideError}\n icon={Code2}\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.openInIde')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex items-center\">\n <ActionButton\n label={t('repositoryNode.openInShell')}\n onClick={actions.openInShell}\n loading={actions.shellLoading}\n error={!!actions.shellError}\n icon={Terminal}\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.openInShell')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex items-center\">\n <ActionButton\n label={t('repositoryNode.openFolder')}\n onClick={actions.openFolder}\n loading={actions.folderLoading}\n error={!!actions.folderError}\n icon={FolderOpen}\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.openFolder')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={t('repositoryNode.chatWithAgent')}\n onClick={(e) => {\n e.stopPropagation();\n if (data.id)\n router.push(\n `/repository/${data.id}/chat` as Parameters<typeof router.push>[0]\n );\n }}\n className=\"nodrag relative cursor-pointer text-violet-500 hover:text-violet-600 dark:text-violet-400 dark:hover:text-violet-300\"\n >\n <MessageSquare className=\"h-3 w-3\" />\n <ChatDotIndicator status={chatTurnStatus} />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{t('repositoryNode.chatWithAgent')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <FeatureSessionsDropdown\n repositoryPath={data.repositoryPath}\n includeWorktrees\n onCreateFromSession={handleCreateFromSession}\n />\n </>\n ) : null}\n\n {data.onAdd ? <div className=\"ms-1.5\" /> : null}\n {data.onAdd ? (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n aria-label={t('repositoryNode.newFeature')}\n data-testid=\"repository-node-add-button\"\n onClick={(e) => {\n e.stopPropagation();\n data.onAdd?.();\n }}\n className={cn(\n 'flex h-6 shrink-0 cursor-pointer items-center gap-0.5 rounded bg-blue-500 px-1.5 text-[11px] font-bold text-white transition-colors hover:bg-blue-600 dark:bg-amber-500 dark:hover:bg-amber-400',\n data.pulseAdd && 'animate-pulse-cta'\n )}\n >\n <Plus className=\"h-3 w-3\" />\n <span className=\"translate-y-px\">{t('repositoryNode.new')}</span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">{t('repositoryNode.newFeature')}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n ) : null}\n </div>\n </div>\n\n {/* Row 2 & 3: Git info or placeholder */}\n {data.branch ? (\n <>\n {/* Row 2: Branch + behind status */}\n <div\n data-testid=\"repository-node-git-info\"\n className=\"text-muted-foreground border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex items-center gap-3 text-xs\">\n <span\n className=\"flex items-center gap-1 truncate\"\n data-testid=\"repository-node-branch\"\n >\n <GitBranch className=\"h-3 w-3 shrink-0\" />\n <span className=\"truncate\">{data.branch}</span>\n </span>\n {data.behindCount != null && data.behindCount > 0 ? (\n <span\n className=\"flex shrink-0 items-center gap-1 whitespace-nowrap text-amber-500\"\n data-testid=\"repository-node-behind\"\n >\n <ArrowDown className=\"h-3 w-3 shrink-0\" />\n {t('repositoryNode.behind', { count: data.behindCount })}\n </span>\n ) : null}\n </div>\n </div>\n {/* Row 3: Latest commit */}\n {data.commitMessage ? (\n <div\n data-testid=\"repository-node-commit-info\"\n className=\"text-muted-foreground border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex items-center gap-2 text-xs\">\n <GitCommitHorizontal className=\"h-3 w-3 shrink-0\" />\n <span className=\"min-w-0 truncate\" data-testid=\"repository-node-commit-message\">\n {data.commitMessage}\n </span>\n {data.committer ? (\n <span\n className=\"text-muted-foreground/70 ms-auto flex shrink-0 items-center gap-1\"\n data-testid=\"repository-node-committer\"\n >\n <User className=\"h-3 w-3 shrink-0\" />\n <span>{data.committer}</span>\n </span>\n ) : null}\n </div>\n </div>\n ) : null}\n </>\n ) : data.gitInfoStatus === 'not-a-repo' ? (\n /* Not a git repo — two rows for consistency with loading/ready states */\n <>\n <div\n data-testid=\"repository-node-not-repo\"\n className=\"text-muted-foreground border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex items-center gap-2 text-xs\">\n <FolderOpen className=\"h-3 w-3 shrink-0\" />\n <span className=\"min-w-0 truncate opacity-60\">\n {data.repositoryPath ?? 'Unknown path'}\n </span>\n </div>\n </div>\n <div className=\"text-muted-foreground border-border/50 border-t px-4 py-2\">\n <div className=\"flex items-center gap-2 text-xs opacity-40\">\n <GitBranch className=\"h-3 w-3 shrink-0\" />\n <span>{t('repositoryNode.notAGitRepository')}</span>\n </div>\n </div>\n </>\n ) : data.gitInfoStatus !== 'ready' ? (\n /* Loading — show skeleton placeholders for both rows */\n <>\n <div\n data-testid=\"repository-node-git-loading\"\n className=\"border-border/50 border-t px-4 py-2\"\n >\n <div className=\"flex h-4 items-center gap-2 text-xs\">\n <GitBranch className=\"text-muted-foreground h-3 w-3 shrink-0\" />\n <span className=\"bg-muted h-3 w-20 animate-pulse rounded\" />\n </div>\n </div>\n <div className=\"border-border/50 border-t px-4 py-2\">\n <div className=\"flex h-4 items-center gap-2 text-xs\">\n <GitCommitHorizontal className=\"text-muted-foreground h-3 w-3 shrink-0\" />\n <span className=\"bg-muted h-3 w-36 animate-pulse rounded\" />\n </div>\n </div>\n </>\n ) : null}\n\n {/* Row 4: Local dev server — always visible when envDeploy flag is on */}\n {featureFlags.envDeploy && data.repositoryPath ? (\n <div\n data-testid=\"repository-node-dev-preview\"\n className=\"border-border/50 border-t px-4 py-2\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center gap-2 text-xs\">\n {deployAction.deployError ? (\n <span className=\"truncate text-xs text-red-500\">{deployAction.deployError}</span>\n ) : isDeploymentActive ? (\n <>\n <span className=\"me-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500\" />\n {deployAction.url ? (\n <a\n href={deployAction.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"truncate text-green-700 hover:underline dark:text-green-400\"\n >\n {deployAction.url}\n </a>\n ) : (\n <span className=\"text-muted-foreground\">{t('repositoryNode.starting')}</span>\n )}\n </>\n ) : (\n <span className=\"text-muted-foreground inline-flex items-baseline gap-2\">\n <span>{t('repositoryNode.run')}</span>\n <span className=\"text-muted-foreground/50 text-[10px]\">\n {t('repositoryNode.startLocalEnvironment')}\n </span>\n </span>\n )}\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n className={cn(\n 'ms-auto flex items-center',\n !isDeploymentActive &&\n !deployAction.deployError &&\n '[&_button]:text-green-600 [&_button]:hover:text-green-700 dark:[&_button]:text-green-400 dark:[&_button]:hover:text-green-300'\n )}\n >\n <ActionButton\n label={\n deployAction.deployError\n ? t('repositoryNode.retry')\n : isDeploymentActive\n ? t('repositoryNode.stopDevServer')\n : t('repositoryNode.startDevServer')\n }\n onClick={isDeploymentActive ? deployAction.stop : deployAction.deploy}\n loading={deployAction.deployLoading || deployAction.stopLoading}\n error={false}\n icon={\n deployAction.deployError ? RotateCcw : isDeploymentActive ? Square : Play\n }\n iconOnly\n variant=\"ghost\"\n size=\"icon-xs\"\n />\n </span>\n </TooltipTrigger>\n <TooltipContent>\n {isDeploymentActive\n ? t('repositoryNode.stopDevServer')\n : t('repositoryNode.startDevServer')}\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n </div>\n ) : null}\n </div>\n\n {/* Source handle — invisible, for edge connections */}\n {data.onAdd || data.showHandles ? (\n <Handle\n type=\"source\"\n position={sourceHandlePos}\n isConnectable={!data.showHandles}\n className=\"opacity-0!\"\n style={{ top: 70 }}\n />\n ) : null}\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { ChevronLeft, Loader2 } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { getAllAgentModels } from '@/app/actions/get-all-agent-models';\nimport type { AgentModelGroup } from '@/app/actions/get-all-agent-models';\nimport { updateAgentAndModel } from '@/app/actions/update-agent-and-model';\nimport { getAgentTypeIcon } from '@/components/common/feature-node/agent-type-icons';\nimport { getModelMeta } from '@/lib/model-metadata';\nimport { cn } from '@/lib/utils';\n\nexport interface WelcomeAgentSetupProps {\n onComplete: () => void;\n className?: string;\n}\n\ntype SetupStep = 'select-agent' | 'select-model';\n\nconst STEPS: SetupStep[] = ['select-agent', 'select-model'];\n\nexport function WelcomeAgentSetup({ onComplete, className }: WelcomeAgentSetupProps) {\n const { t } = useTranslation('web');\n const [groups, setGroups] = useState<AgentModelGroup[]>([]);\n const [loading, setLoading] = useState(true);\n const [step, setStep] = useState<SetupStep>('select-agent');\n const [selectedAgent, setSelectedAgent] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n const [transitioning, setTransitioning] = useState(false);\n const [visible, setVisible] = useState(true);\n const timeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n useEffect(() => {\n getAllAgentModels()\n .then(setGroups)\n .finally(() => setLoading(false));\n }, []);\n\n const activeGroup = selectedAgent ? groups.find((g) => g.agentType === selectedAgent) : null;\n\n const transitionTo = useCallback((nextStep: SetupStep, setup?: () => void) => {\n setTransitioning(true);\n setVisible(false);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => {\n setup?.();\n setStep(nextStep);\n requestAnimationFrame(() => {\n setVisible(true);\n setTransitioning(false);\n });\n }, 150);\n }, []);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n };\n }, []);\n\n const saveAndComplete = useCallback(\n async (agentType: string, model: string | null) => {\n setSaving(true);\n try {\n await updateAgentAndModel(agentType, model);\n // Fade out the entire wizard before handing off to the next view\n setVisible(false);\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => {\n onComplete();\n }, 200);\n } catch {\n setSaving(false);\n }\n },\n [onComplete]\n );\n\n const handleAgentSelect = useCallback(\n (agentType: string) => {\n const group = groups.find((g) => g.agentType === agentType);\n if (group && group.models.length > 0) {\n transitionTo('select-model', () => {\n setSelectedAgent(agentType);\n });\n } else {\n saveAndComplete(agentType, null);\n }\n },\n [groups, transitionTo, saveAndComplete]\n );\n\n const handleModelSelect = useCallback(\n (model: string) => {\n if (!selectedAgent) return;\n saveAndComplete(selectedAgent, model);\n },\n [selectedAgent, saveAndComplete]\n );\n\n const handleBack = useCallback(() => {\n if (step === 'select-model') {\n transitionTo('select-agent', () => {\n setSelectedAgent(null);\n });\n }\n }, [step, transitionTo]);\n\n if (loading) {\n return (\n <div\n data-testid=\"welcome-agent-setup\"\n className={cn('flex flex-col items-center justify-center gap-4', className)}\n >\n <Loader2 className=\"text-muted-foreground h-5 w-5 animate-spin\" />\n <p className=\"text-muted-foreground text-sm\">{t('welcome.loadingAgents')}</p>\n </div>\n );\n }\n\n const stepIndex = STEPS.indexOf(step);\n\n // Dynamic hero text per step\n const heroTitle = step === 'select-agent' ? t('welcome.chooseAgent') : t('welcome.pickModel');\n\n const heroSubtitle =\n step === 'select-agent'\n ? t('welcome.selectAgentSubtitle')\n : activeGroup\n ? t('welcome.chooseModelSubtitle', { label: activeGroup.label })\n : '';\n\n return (\n <div\n data-testid=\"welcome-agent-setup\"\n className={cn('flex w-full flex-col items-center', className)}\n >\n {/* Step indicator — stays visible across transitions */}\n <div className=\"mb-8 flex w-full max-w-xs items-center gap-1.5\">\n {STEPS.map((s, i) => (\n <div\n key={s}\n className={cn(\n 'h-[3px] flex-1 rounded-full transition-colors duration-300',\n i <= stepIndex ? 'bg-foreground/60' : 'bg-muted'\n )}\n />\n ))}\n </div>\n\n {/* Hero + content — all fade together on step transitions */}\n <div\n className={cn(\n 'flex w-full flex-col items-center transition-opacity duration-200',\n visible && !transitioning ? 'opacity-100' : 'opacity-0'\n )}\n >\n <h1 className=\"text-foreground/90 text-center text-5xl font-extralight tracking-tight\">\n {heroTitle}\n </h1>\n <p className=\"text-muted-foreground mt-3 text-center text-lg leading-relaxed font-light\">\n {heroSubtitle}\n </p>\n\n <div className=\"mt-8 flex w-full flex-col items-center\">\n {/* Step 1: Agent selection — horizontal grid */}\n {step === 'select-agent' && (\n <div\n data-testid=\"agent-list\"\n className=\"grid w-full max-w-lg gap-3\"\n style={{\n gridTemplateColumns: `repeat(${Math.min(groups.length, 4)}, minmax(0, 1fr))`,\n }}\n >\n {groups.map((group) => {\n const GroupIcon = getAgentTypeIcon(group.agentType);\n return (\n <button\n key={group.agentType}\n type=\"button\"\n disabled={saving}\n data-testid={`agent-option-${group.agentType}`}\n className=\"border-border hover:bg-accent hover:border-foreground/20 flex cursor-pointer flex-col items-center gap-3 rounded-2xl border px-4 py-5 transition-all duration-150 active:scale-[0.97] disabled:opacity-50\"\n onClick={() => handleAgentSelect(group.agentType)}\n >\n <GroupIcon className=\"text-foreground/70 h-7 w-7\" />\n <span className=\"text-sm font-medium\">{group.label}</span>\n </button>\n );\n })}\n </div>\n )}\n\n {/* Step 2: Model selection — horizontal grid */}\n {step === 'select-model' && activeGroup ? (\n <div\n data-testid=\"model-list\"\n className=\"flex w-full max-w-lg flex-col items-center gap-4\"\n >\n <button\n type=\"button\"\n disabled={saving}\n className=\"text-muted-foreground hover:text-foreground flex cursor-pointer items-center gap-1.5 self-start text-sm transition-colors\"\n onClick={handleBack}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('welcome.back')}\n </button>\n <div\n className=\"grid w-full gap-3\"\n style={{\n gridTemplateColumns: `repeat(${Math.min(activeGroup.models.length, 3)}, minmax(0, 1fr))`,\n }}\n >\n {activeGroup.models.map((m) => {\n const meta = getModelMeta(m.id);\n return (\n <button\n key={m.id}\n type=\"button\"\n disabled={saving}\n data-testid={`model-option-${m.id}`}\n className=\"border-border hover:bg-accent hover:border-foreground/20 flex cursor-pointer flex-col items-center gap-2 rounded-2xl border px-4 py-5 text-center transition-all duration-150 active:scale-[0.97] disabled:opacity-50\"\n onClick={() => handleModelSelect(m.id)}\n >\n <span className=\"text-sm font-medium\">\n {meta.displayName || m.displayName}\n </span>\n <span className=\"text-muted-foreground text-xs leading-tight\">\n {meta.description || m.description}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useCallback, useEffect } from 'react';\nimport {\n FolderOpen,\n FolderPlus,\n Copy,\n Check,\n Loader2,\n CheckCircle2,\n AlertCircle,\n Terminal,\n ChevronDown,\n ExternalLink,\n Github,\n} from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '@/lib/utils';\nimport { pickFolder } from '@/components/common/add-repository-button/pick-folder';\nimport { ReactFileManagerDialog } from '@/components/common/react-file-manager-dialog';\nimport { useFeatureFlags } from '@/hooks/feature-flags-context';\nimport { isAgentSetupComplete } from '@/app/actions/agent-setup-flag';\nimport { checkAgentAuth } from '@/app/actions/check-agent-auth';\nimport type { AgentAuthStatus } from '@/app/actions/check-agent-auth';\nimport { checkToolStatus } from '@/app/actions/check-tool-status';\nimport type { ToolStatusResult, ToolStatusEntry } from '@/app/actions/check-tool-status';\nimport { WelcomeAgentSetup } from './welcome-agent-setup';\nimport { NewProjectDialog } from './new-project-dialog';\n\nexport interface ControlCenterOnboardingProps {\n onRepositorySelect?: (path: string) => void;\n className?: string;\n}\n\nconst commands = ['cd ~/my-repo', 'shep feat new \"sleek dashboard\"'];\n\nexport function ControlCenterOnboarding({\n onRepositorySelect,\n className,\n}: ControlCenterOnboardingProps) {\n const { t } = useTranslation('web');\n const [copied, setCopied] = useState(false);\n const [loading, setLoading] = useState(false);\n const [showReactPicker, setShowReactPicker] = useState(false);\n const [agentReady, setAgentReady] = useState<boolean | null>(null);\n const [authStatus, setAuthStatus] = useState<AgentAuthStatus | null>(null);\n const [cliExpanded, setCliExpanded] = useState(false);\n const [toolStatus, setToolStatus] = useState<ToolStatusResult | null>(null);\n const [newProjectOpen, setNewProjectOpen] = useState(false);\n const { reactFileManager: useReactFileManager } = useFeatureFlags();\n\n useEffect(() => {\n isAgentSetupComplete()\n .then((done) => setAgentReady(done))\n .catch(() => setAgentReady(false));\n }, []);\n\n useEffect(() => {\n if (!agentReady) return;\n checkAgentAuth()\n .then(setAuthStatus)\n .catch(() =>\n setAuthStatus({\n agentType: 'unknown',\n installed: false,\n authenticated: false,\n label: 'Agent',\n binaryName: null,\n installCommand: null,\n authCommand: null,\n })\n );\n checkToolStatus()\n .then(setToolStatus)\n .catch(() =>\n setToolStatus({\n git: { installed: false, version: null, installCommand: null, installUrl: null },\n gh: { installed: false, version: null, installCommand: null, installUrl: null },\n })\n );\n }, [agentReady]);\n\n async function handlePickerClick() {\n if (loading) return;\n\n if (useReactFileManager) {\n setShowReactPicker(true);\n return;\n }\n\n setLoading(true);\n try {\n const path = await pickFolder();\n if (path) {\n onRepositorySelect?.(path);\n }\n } catch {\n setShowReactPicker(true);\n } finally {\n setLoading(false);\n }\n }\n\n function handleReactPickerSelect(path: string | null) {\n if (path) {\n onRepositorySelect?.(path);\n }\n setShowReactPicker(false);\n }\n\n const handleCopy = useCallback(async () => {\n await navigator.clipboard.writeText(commands.join('\\n'));\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, []);\n\n const handleAgentSetupComplete = useCallback(() => {\n setAgentReady(true);\n }, []);\n\n const handleRetryAuth = useCallback(() => {\n setAuthStatus(null);\n checkAgentAuth().then(setAuthStatus);\n }, []);\n\n if (agentReady === null) return null;\n\n return (\n <div\n data-testid=\"control-center-onboarding\"\n className={cn(\n 'relative flex h-full w-full flex-col items-center justify-center px-8',\n className\n )}\n >\n {!agentReady ? (\n <WelcomeAgentSetup onComplete={handleAgentSetupComplete} />\n ) : (\n <div className=\"animate-in fade-in flex w-full max-w-md flex-col items-center duration-300\">\n <h1 className=\"text-foreground/90 text-center text-5xl font-extralight tracking-tight\">\n {t('emptyState.addProject')}\n </h1>\n <p className=\"text-muted-foreground mt-3 text-center text-lg leading-relaxed font-light\">\n {t('emptyState.addProjectDescription')}\n <br />\n {t('emptyState.addProjectDescriptionLine2')}\n </p>\n\n <div className=\"mt-8 flex w-full flex-col gap-3\">\n <AgentAuthBanner status={authStatus} onRetry={handleRetryAuth} />\n <ToolStatusRow\n label={t('emptyState.git')}\n status={toolStatus?.git ?? null}\n missingHint={t('emptyState.gitRequired')}\n />\n <ToolStatusRow\n label={t('emptyState.githubCli')}\n status={toolStatus?.gh ?? null}\n missingHint={t('emptyState.githubCliRequired')}\n />\n </div>\n\n <button\n type=\"button\"\n data-testid=\"empty-state-add-repository\"\n onClick={handlePickerClick}\n disabled={loading}\n className=\"bg-foreground text-background hover:bg-foreground/90 mt-10 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl px-6 py-4 text-base font-medium shadow-lg transition-all duration-200 hover:shadow-xl active:scale-[0.98] disabled:cursor-wait disabled:opacity-50\"\n >\n {loading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <FolderOpen className=\"h-5 w-5\" />\n )}\n {loading ? t('emptyState.opening') : t('emptyState.chooseFolder')}\n </button>\n\n <button\n type=\"button\"\n data-testid=\"empty-state-new-project\"\n onClick={() => setNewProjectOpen(true)}\n disabled={loading}\n className=\"border-foreground/15 text-foreground/80 hover:bg-foreground/5 hover:border-foreground/25 mt-3 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl border px-6 py-3.5 text-sm font-medium transition-all duration-200 active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <FolderPlus className=\"h-4 w-4\" />\n New Project\n </button>\n\n <button\n type=\"button\"\n data-testid=\"empty-state-import-github\"\n onClick={() => window.dispatchEvent(new CustomEvent('shep:open-github-import'))}\n disabled={loading}\n className=\"border-foreground/15 text-foreground/80 hover:bg-foreground/5 hover:border-foreground/25 mt-3 flex w-full cursor-pointer items-center justify-center gap-2.5 rounded-xl border px-6 py-3.5 text-sm font-medium transition-all duration-200 active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <Github className=\"h-4 w-4\" />\n Import from GitHub\n </button>\n\n <p className=\"text-muted-foreground/60 mt-3 text-center text-sm\">\n {t('emptyState.folderHint')}\n </p>\n </div>\n )}\n\n {agentReady ? (\n <div\n className=\"absolute bottom-8 flex flex-col items-center\"\n style={{\n animationDelay: '400ms',\n animationDuration: '600ms',\n animationFillMode: 'both',\n }}\n >\n <button\n type=\"button\"\n onClick={() => setCliExpanded(!cliExpanded)}\n className=\"text-muted-foreground hover:text-foreground flex cursor-pointer items-center gap-1.5 transition-colors duration-200\"\n >\n <Terminal className=\"h-3.5 w-3.5\" />\n <span className=\"text-sm\">{t('emptyState.orUseCli')}</span>\n <ChevronDown\n className={cn(\n 'h-3.5 w-3.5 transition-transform duration-200',\n cliExpanded ? '' : 'rotate-180'\n )}\n />\n </button>\n\n {cliExpanded ? (\n <div className=\"animate-in fade-in slide-in-from-top-1 mt-3 w-80 duration-200\">\n <div\n data-testid=\"cli-code-block\"\n className=\"relative rounded-xl bg-zinc-900 px-5 py-4 font-mono text-[13px] leading-relaxed text-zinc-400\"\n >\n <button\n type=\"button\"\n data-testid=\"cli-code-block-copy\"\n onClick={handleCopy}\n className=\"absolute top-3 right-3 cursor-pointer rounded-md p-1.5 text-zinc-600 transition-colors hover:bg-zinc-800 hover:text-zinc-300\"\n aria-label={t('emptyState.copyCommands')}\n >\n {copied ? (\n <Check className=\"h-3.5 w-3.5 text-emerald-400\" />\n ) : (\n <Copy className=\"h-3.5 w-3.5\" />\n )}\n </button>\n <div className=\"space-y-1\">\n {commands.map((cmd) => (\n <div key={cmd} className=\"whitespace-nowrap\">\n <span className=\"text-zinc-600 select-none\">$ </span>\n <span className=\"text-zinc-300\">{cmd}</span>\n </div>\n ))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n ) : null}\n\n <ReactFileManagerDialog\n open={showReactPicker}\n onOpenChange={(open) => {\n if (!open) setShowReactPicker(false);\n }}\n onSelect={handleReactPickerSelect}\n />\n <NewProjectDialog\n open={newProjectOpen}\n onOpenChange={setNewProjectOpen}\n onCreated={(path) => onRepositorySelect?.(path)}\n />\n </div>\n );\n}\n\nfunction AgentAuthBanner({\n status,\n onRetry,\n}: {\n status: AgentAuthStatus | null;\n onRetry: () => void;\n}) {\n const { t } = useTranslation('web');\n\n if (!status) {\n return (\n <ChecklistRow icon={<Loader2 className=\"text-muted-foreground/50 h-4 w-4 animate-spin\" />}>\n <span className=\"text-muted-foreground/50 text-sm\">{t('emptyState.checkingSetup')}</span>\n </ChecklistRow>\n );\n }\n\n if (status.installed && status.authenticated) {\n return (\n <ChecklistRow icon={<CheckCircle2 className=\"h-4 w-4 text-emerald-500\" />}>\n <span className=\"text-sm text-emerald-600 dark:text-emerald-400\">\n {t('emptyState.ready', { label: status.label })}\n </span>\n </ChecklistRow>\n );\n }\n\n if (!status.installed) {\n return (\n <ChecklistRow icon={<AlertCircle className=\"h-4 w-4 text-amber-500\" />}>\n <span className=\"text-sm font-medium text-amber-600 dark:text-amber-400\">\n {t('emptyState.notInstalled', { label: status.label })}\n </span>\n {status.installCommand ? <CopyableCommand command={status.installCommand} /> : null}\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n {t('emptyState.reCheck')}\n </button>\n </ChecklistRow>\n );\n }\n\n return (\n <ChecklistRow icon={<AlertCircle className=\"h-4 w-4 text-amber-500\" />}>\n <span className=\"text-sm font-medium text-amber-600 dark:text-amber-400\">\n {t('emptyState.needsAuth', { label: status.label })}\n </span>\n {status.authCommand ? <CopyableCommand command={status.authCommand} /> : null}\n <div className=\"flex items-center gap-3\">\n {status.binaryName ? (\n <button\n type=\"button\"\n data-testid=\"auth-banner-open-terminal\"\n onClick={async () => {\n try {\n const toolId =\n status.agentType === 'claude-code' ? 'claude-code' : status.agentType;\n await fetch(`/api/tools/${toolId}/launch`, { method: 'POST' });\n } catch {\n /* best effort */\n }\n }}\n className=\"flex items-center gap-1 text-xs font-medium text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n <Terminal className=\"h-3 w-3\" />\n {t('emptyState.open', { label: status.label })}\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n {t('emptyState.reCheck')}\n </button>\n </div>\n </ChecklistRow>\n );\n}\n\nfunction ToolStatusRow({\n label,\n status,\n missingHint,\n}: {\n label: string;\n status: ToolStatusEntry | null;\n missingHint: string;\n}) {\n const { t } = useTranslation('web');\n\n if (!status) {\n return (\n <ChecklistRow icon={<Loader2 className=\"text-muted-foreground/50 h-4 w-4 animate-spin\" />}>\n <span className=\"text-muted-foreground/50 text-sm\">\n {t('emptyState.checking', { label })}\n </span>\n </ChecklistRow>\n );\n }\n\n if (status.installed) {\n return (\n <ChecklistRow icon={<CheckCircle2 className=\"h-4 w-4 text-emerald-500\" />}>\n <span className=\"flex items-baseline gap-2\">\n <span className=\"text-sm text-emerald-600 dark:text-emerald-400\">\n {t('emptyState.ready', { label })}\n </span>\n {status.version ? (\n <span className=\"text-muted-foreground/40 text-xs\">v{status.version}</span>\n ) : null}\n </span>\n </ChecklistRow>\n );\n }\n\n return (\n <ChecklistRow icon={<AlertCircle className=\"h-4 w-4 text-amber-500\" />}>\n <span className=\"text-sm font-medium text-amber-600 dark:text-amber-400\">\n {t('emptyState.notFound', { label })}\n </span>\n <span className=\"text-muted-foreground/50 text-xs\">{missingHint}</span>\n {status.installCommand ? <CopyableCommand command={status.installCommand} /> : null}\n {status.installUrl ? (\n <a\n href={status.installUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 text-xs text-amber-600 underline underline-offset-2 hover:text-amber-800 dark:text-amber-400\"\n >\n {t('emptyState.docs')} <ExternalLink className=\"h-3 w-3\" />\n </a>\n ) : null}\n </ChecklistRow>\n );\n}\n\nfunction ChecklistRow({ icon, children }: { icon: React.ReactNode; children: React.ReactNode }) {\n return (\n <div className=\"animate-in fade-in flex items-start gap-2.5\">\n <div className=\"mt-0.5 shrink-0\">{icon}</div>\n <div className=\"flex min-w-0 flex-1 flex-col gap-1\">{children}</div>\n </div>\n );\n}\n\nfunction CopyableCommand({ command }: { command: string }) {\n const [copied, setCopied] = useState(false);\n\n return (\n <button\n type=\"button\"\n onClick={async () => {\n await navigator.clipboard.writeText(command);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }}\n className=\"group/cmd flex cursor-pointer items-center justify-between gap-2 rounded-md bg-zinc-100 py-1 ps-2.5 pe-2 text-start transition-colors hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700\"\n >\n <code className=\"min-w-0 truncate text-[11px] leading-relaxed text-zinc-600 dark:text-zinc-300\">\n {command}\n </code>\n {copied ? (\n <Check className=\"h-3 w-3 shrink-0 text-emerald-500\" />\n ) : (\n <Copy className=\"h-3 w-3 shrink-0 text-zinc-400 opacity-0 transition-opacity group-hover/cmd:opacity-100\" />\n )}\n </button>\n );\n}\n","'use client';\n\nimport { useState, useEffect, useMemo } from 'react';\nimport {\n X,\n MessageCircleQuestion,\n ShieldCheck,\n ArrowRight,\n Plus,\n Layers,\n GitBranch,\n Sparkles,\n} from 'lucide-react';\nimport Link from 'next/link';\nimport type { Route } from 'next';\nimport { cn } from '@/lib/utils';\n\nconst DISMISSED_KEY = 'shep:collaboration-onboarding-dismissed';\n\n/** Human-friendly cap for the inline pill list before collapsing into a picker. */\nconst PILL_LIMIT = 3;\n\nexport type SupervisorScopeKind = 'app' | 'repo' | 'feature';\n\nexport interface SupervisorScopeEntry {\n id: string;\n name: string;\n kind: SupervisorScopeKind;\n}\n\nexport interface CollaborationOnboardingProps {\n /** Applications on the canvas. */\n apps?: SupervisorScopeEntry[];\n /** Repositories on the canvas. */\n repos?: SupervisorScopeEntry[];\n /** Features on the canvas. */\n features?: SupervisorScopeEntry[];\n className?: string;\n}\n\n/**\n * Dismissable first-run callout shown in the control center when the\n * collaboration feature flag is on. Surfaces every entity the user can\n * attach a supervisor to — applications, repositories, and features —\n * mirroring the cascading scope model (`global → app → repo → feature`).\n *\n * no scopes → tells the user to add a repo or app to get started\n * 1 scope → links directly to the right /supervisor/... page\n * N scopes → shows up to PILL_LIMIT inline pills with an overflow picker\n */\nexport function CollaborationOnboarding({\n apps = [],\n repos = [],\n features = [],\n className,\n}: CollaborationOnboardingProps) {\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n try {\n if (!localStorage.getItem(DISMISSED_KEY)) {\n setVisible(true);\n }\n } catch {\n // localStorage blocked (private mode, SSR, etc.)\n }\n }, []);\n\n function dismiss() {\n try {\n localStorage.setItem(DISMISSED_KEY, '1');\n } catch {\n // ignore\n }\n setVisible(false);\n }\n\n if (!visible) return null;\n\n return (\n <div\n className={cn(\n 'border-border/60 bg-card relative flex flex-col gap-4 rounded-xl border p-5 shadow-sm',\n className\n )}\n role=\"region\"\n aria-label=\"Agent collaboration onboarding\"\n data-testid=\"collaboration-onboarding\"\n >\n {/* Dismiss */}\n <button\n type=\"button\"\n aria-label=\"Dismiss\"\n onClick={dismiss}\n className=\"text-muted-foreground hover:text-foreground absolute top-3 right-3 rounded-md p-1 transition-colors\"\n >\n <X className=\"size-4\" />\n </button>\n\n {/* Header */}\n <div>\n <p className=\"text-[10px] font-semibold tracking-widest text-indigo-500 uppercase\">New</p>\n <h2 className=\"mt-0.5 text-base font-semibold\">Agent Collaboration & Supervision</h2>\n <p className=\"text-muted-foreground mt-1 text-sm\">\n Your agents can now ask questions, talk to each other, and be guided by a supervisor you\n configure.\n </p>\n </div>\n\n {/* Feature cards */}\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <SupervisorCard apps={apps} repos={repos} features={features} />\n <FeatureCard\n icon={MessageCircleQuestion}\n title=\"Agent questions inbox\"\n description=\"A single place for all questions raised by agents during interactive and background runs.\"\n href=\"/agent-questions\"\n cta=\"View inbox\"\n />\n </div>\n </div>\n );\n}\n\n// ── Supervisor card — adapts to whatever scopes exist on the canvas ──────────\n\ninterface SupervisorCardProps {\n apps: SupervisorScopeEntry[];\n repos: SupervisorScopeEntry[];\n features: SupervisorScopeEntry[];\n}\n\nfunction SupervisorCard({ apps, repos, features }: SupervisorCardProps) {\n const [pickerOpen, setPickerOpen] = useState(false);\n\n const allScopes = useMemo(\n () => [\n ...apps.map((a) => ({ ...a, kind: 'app' as const })),\n ...repos.map((r) => ({ ...r, kind: 'repo' as const })),\n ...features.map((f) => ({ ...f, kind: 'feature' as const })),\n ],\n [apps, repos, features]\n );\n\n // Empty: no apps, repos, or features yet.\n if (allScopes.length === 0) {\n return (\n <div className=\"bg-muted/40 border-border/40 flex flex-col gap-2 rounded-lg border p-4\">\n <SupervisorHeader />\n <p className=\"text-muted-foreground text-xs leading-relaxed\">\n Supervisors attach to an application, repository, or feature. Add a repository or create\n an application to configure your first one.\n </p>\n <button\n type=\"button\"\n onClick={() => window.dispatchEvent(new CustomEvent('shep:open-create-application'))}\n className=\"text-primary mt-auto inline-flex cursor-pointer items-center gap-1 text-xs font-medium hover:underline\"\n >\n <Plus className=\"size-3\" />\n Create an application\n </button>\n </div>\n );\n }\n\n // Single scope on the canvas — link straight to its page.\n if (allScopes.length === 1) {\n const only = allScopes[0]!;\n return (\n <FeatureCard\n icon={ShieldCheck}\n title=\"Supervisor agent\"\n description={`Delegate approvals and policy decisions for ${describeKind(only.kind)} \"${only.name}\".`}\n href={routeFor(only)}\n cta=\"Configure supervisor\"\n />\n );\n }\n\n // Multiple — show a few pills + (open picker for the rest).\n const pills = allScopes.slice(0, PILL_LIMIT);\n const overflow = allScopes.length - pills.length;\n\n return (\n <div className=\"bg-muted/40 border-border/40 flex flex-col gap-2 rounded-lg border p-4\">\n <SupervisorHeader />\n <p className=\"text-muted-foreground text-xs leading-relaxed\">\n Pick an application, repository, or feature to configure its supervisor.\n </p>\n\n {pickerOpen ? (\n <div className=\"mt-1 flex max-h-72 flex-col gap-1 overflow-y-auto\">\n {allScopes.map((scope) => (\n <Link\n key={`${scope.kind}-${scope.id}`}\n href={routeFor(scope)}\n className=\"border-border/50 hover:bg-background flex items-center justify-between rounded-md border px-3 py-2 text-xs transition-colors\"\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n <KindIcon kind={scope.kind} className=\"text-muted-foreground size-3 shrink-0\" />\n <span className=\"truncate font-medium\">{scope.name}</span>\n </span>\n <ArrowRight className=\"text-muted-foreground ml-2 size-3 shrink-0\" />\n </Link>\n ))}\n </div>\n ) : (\n <div className=\"mt-1 flex flex-wrap gap-1.5\">\n {pills.map((scope) => (\n <Link\n key={`${scope.kind}-${scope.id}`}\n href={routeFor(scope)}\n className=\"border-border/50 bg-background hover:border-primary/40 hover:text-primary flex items-center gap-1.5 rounded-md border px-2.5 py-1 text-xs transition-colors\"\n >\n <KindIcon kind={scope.kind} className=\"size-3 shrink-0\" />\n <span className=\"max-w-[10rem] truncate\">{scope.name}</span>\n <ArrowRight className=\"size-2.5\" />\n </Link>\n ))}\n {overflow > 0 ? (\n <button\n type=\"button\"\n onClick={() => setPickerOpen(true)}\n className=\"text-muted-foreground hover:text-foreground border-border/50 rounded-md border px-2.5 py-1 text-xs transition-colors\"\n >\n +{overflow} more\n </button>\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nfunction SupervisorHeader() {\n return (\n <div className=\"flex items-center gap-2\">\n <div className=\"bg-primary/10 text-primary flex h-7 w-7 shrink-0 items-center justify-center rounded-md\">\n <ShieldCheck className=\"size-3.5\" />\n </div>\n <span className=\"text-sm font-medium\">Supervisor agent</span>\n </div>\n );\n}\n\nfunction KindIcon({ kind, className }: { kind: SupervisorScopeKind; className?: string }) {\n const Icon = kind === 'app' ? Layers : kind === 'repo' ? GitBranch : Sparkles;\n return <Icon className={className} aria-hidden />;\n}\n\nfunction describeKind(kind: SupervisorScopeKind): string {\n return kind === 'app' ? 'application' : kind === 'repo' ? 'repository' : 'feature';\n}\n\nfunction routeFor(scope: SupervisorScopeEntry): Route {\n switch (scope.kind) {\n case 'app':\n return `/application/${scope.id}/supervisor` as Route;\n case 'repo':\n return `/supervisor/repo/${scope.id}` as Route;\n case 'feature':\n return `/supervisor/feature/${scope.id}` as Route;\n }\n}\n\n// ── Generic card ─────────────────────────────────────────────────────────────\n\ninterface FeatureCardProps {\n icon: React.ComponentType<{ className?: string }>;\n title: string;\n description: string;\n href: Route;\n cta: string;\n}\n\nfunction FeatureCard({ icon: Icon, title, description, href, cta }: FeatureCardProps) {\n return (\n <div className=\"bg-muted/40 border-border/40 flex flex-col gap-2 rounded-lg border p-4\">\n <div className=\"flex items-center gap-2\">\n <div className=\"bg-primary/10 text-primary flex h-7 w-7 shrink-0 items-center justify-center rounded-md\">\n <Icon className=\"size-3.5\" />\n </div>\n <span className=\"text-sm font-medium\">{title}</span>\n </div>\n <p className=\"text-muted-foreground text-xs leading-relaxed\">{description}</p>\n <Link\n href={href}\n className=\"text-primary mt-auto inline-flex items-center gap-1 text-xs font-medium hover:underline\"\n >\n {cta}\n <ArrowRight className=\"size-3\" />\n </Link>\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useRouter, usePathname } from 'next/navigation';\nimport { FolderPlus } from 'lucide-react';\nimport type { Edge, Viewport } from '@xyflow/react';\nimport { useReactFlow } from '@xyflow/react';\nimport { FeaturesCanvas } from '@/components/features/features-canvas';\nimport { CanvasToolbar } from '@/components/features/features-canvas/canvas-toolbar';\nimport { WorkspaceSelector } from '@/components/features/features-canvas/workspace-selector';\nimport { ManageWorkspaceDialog } from '@/components/features/features-canvas/manage-workspace-dialog';\nimport { WorkspaceNameDialog } from '@/components/features/features-canvas/workspace-name-dialog';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '@/components/ui/alert-dialog';\nimport { useWorkspaces, DEFAULT_WORKSPACE_ID } from '@/hooks/use-workspaces';\nimport { Layers, Plus } from 'lucide-react';\nimport { Button } from '@/components/ui/button';\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\nimport type { RepositoryNodeData } from '@/components/common/repository-node';\nimport type { ApplicationNodeData } from '@/components/common/application-node/application-node-config';\nimport {\n FloatingActionButton,\n type FloatingActionButtonAction,\n} from '@/components/common/floating-action-button';\nimport {\n useSidebarFeaturesContext,\n mapNodeStateToSidebarStatus,\n} from '@/hooks/sidebar-features-context';\nimport { useTranslation } from 'react-i18next';\n\nimport { useSelectedFeatureId } from '@/hooks/use-selected-feature-id';\nimport { useSelectedRepository } from '@/hooks/use-selected-repository';\nimport { useSoundAction } from '@/hooks/use-sound-action';\nimport { useDrawerCloseGuard } from '@/hooks/drawer-close-guard';\nimport { useViewportPersistence } from '@/hooks/use-viewport-persistence';\nimport { useSidebar } from '@/components/ui/sidebar';\nimport { useFabLayout } from '@/hooks/fab-layout-context';\nimport { useFeatureFlags } from '@/hooks/feature-flags-context';\nimport { ControlCenterEmptyState } from './control-center-empty-state';\nimport { ControlCenterOnboarding } from './control-center-onboarding';\nimport { CollaborationOnboarding } from './collaboration-onboarding';\nimport { NewProjectDialog } from './new-project-dialog';\nimport { useControlCenterState } from './use-control-center-state';\nimport { useCanvasEventListeners } from './use-canvas-event-listeners';\nimport { useWorkspaceFitView } from './use-workspace-fit-view';\nimport { useFabActions } from './use-fab-actions';\nimport { buildCreateUrl } from '@/lib/url-params';\nimport { BuildMode } from '@shepai/core/domain/generated/output';\n\nconst AUTO_FOCUS_OPTIONS = {\n maxZoom: 1.0,\n padding: 0.5,\n duration: 500,\n} as const;\n\nconst AUTO_FOCUS_DRAWER_DELAY_MS = 600;\n\ninterface ControlCenterInnerProps {\n initialNodes: CanvasNodeType[];\n initialEdges: Edge[];\n}\n\nexport function ControlCenterInner({ initialNodes, initialEdges }: ControlCenterInnerProps) {\n const router = useRouter();\n const pathname = usePathname();\n const selectedFeatureId = useSelectedFeatureId();\n const selectedRepository = useSelectedRepository();\n const clickSound = useSoundAction('click');\n const { guardedNavigate } = useDrawerCloseGuard();\n const { fitView } = useReactFlow();\n const drawerTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const {\n defaultViewport,\n onMoveEnd: handleViewportChange,\n resetViewport,\n } = useViewportPersistence();\n\n const {\n nodes,\n edges,\n onNodesChange,\n handleConnect,\n handleAddRepository,\n handleArchiveFeature,\n handleDeleteFeature,\n handleRetryFeature,\n handleStartFeature,\n handleStopFeature,\n handleUnarchiveFeature,\n handleDeleteRepository,\n handleDeleteApplication,\n createFeatureNode,\n showArchived,\n setShowArchived,\n setCallbacks,\n } = useControlCenterState(initialNodes, initialEdges);\n\n // ── Workspaces (client-only prototype) ────────────────────────────────\n const {\n workspaces,\n activeWorkspace,\n isDefaultActive,\n setActiveWorkspace,\n createWorkspace,\n renameWorkspace,\n deleteWorkspace,\n setWorkspaceMembers,\n addToActiveWorkspace,\n } = useWorkspaces();\n // Tracks the set of node ids we've already seen, so we can detect new\n // repo/feature nodes appearing on the canvas and auto-include them in the\n // active workspace (when it isn't the default).\n const knownNodeIdsRef = useRef<Set<string>>(new Set());\n const [manageWorkspaceOpen, setManageWorkspaceOpen] = useState(false);\n const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false);\n const [renameWorkspaceOpen, setRenameWorkspaceOpen] = useState(false);\n const [deleteWorkspaceOpen, setDeleteWorkspaceOpen] = useState(false);\n // Target of the delete confirmation dialog. Allows deleting any workspace\n // (not just the active one) directly from the workspace dropdown.\n const [pendingDeleteWorkspaceId, setPendingDeleteWorkspaceId] = useState<string | null>(null);\n // Inline \"New Project\" dialog launched from the empty-workspace state.\n const [workspaceNewProjectOpen, setWorkspaceNewProjectOpen] = useState(false);\n\n // Publish sidebar features + repo state to context\n const { setFeatures: setSidebarFeatures, setHasRepositories: setSidebarHasRepos } =\n useSidebarFeaturesContext();\n\n const featureNodes = useMemo(() => nodes.filter((n) => n.type === 'featureNode'), [nodes]);\n\n const sidebarKey = useMemo(() => {\n return featureNodes\n .map((n) => {\n const d = n.data as FeatureNodeData;\n return `${d.featureId}:${d.state}:${d.name}:${d.repositoryPath}`;\n })\n .sort()\n .join(',');\n }, [featureNodes]);\n\n useEffect(() => {\n const sidebarItems = featureNodes\n .map((n) => {\n const d = n.data as FeatureNodeData;\n const status = mapNodeStateToSidebarStatus(d.state);\n if (!status) return null;\n const repoPath = d.repositoryPath ?? '';\n return {\n featureId: d.featureId,\n name: d.name,\n status,\n repositoryPath: repoPath,\n repositoryName: d.repositoryName ?? repoPath.split('/').filter(Boolean).pop() ?? repoPath,\n ...(d.startedAt != null && { startedAt: d.startedAt }),\n ...(d.runtime != null && { duration: d.runtime }),\n ...(d.agentType && { agentType: d.agentType }),\n ...(d.modelId && { modelId: d.modelId }),\n };\n })\n .filter(Boolean) as {\n featureId: string;\n name: string;\n status: 'action-needed' | 'in-progress' | 'done';\n repositoryPath: string;\n repositoryName: string;\n startedAt?: number;\n duration?: string;\n agentType?: string;\n modelId?: string;\n }[];\n\n setSidebarFeatures(sidebarItems);\n }, [sidebarKey, featureNodes, setSidebarFeatures]);\n\n // ── URL-based navigation handlers ────────────────────────────────────\n\n const handleApplicationClick = useCallback(\n (applicationId: string) => {\n guardedNavigate(() => router.push(`/application/${applicationId}`));\n },\n [router, guardedNavigate]\n );\n\n const handleApplicationCreateSddFeature = useCallback(\n (applicationId: string) => {\n clickSound.play();\n guardedNavigate(() => router.push(buildCreateUrl({ applicationId, mode: BuildMode.Spec })));\n },\n [router, clickSound, guardedNavigate]\n );\n\n const handleNodeClick = useCallback(\n (event: React.MouseEvent, node: CanvasNodeType) => {\n if (node.type === 'featureNode') {\n const data = node.data as FeatureNodeData;\n if (data.state === 'creating' || data.state === 'deleting') return;\n // Only navigate when the click lands on the card itself, not on\n // overlay buttons (delete, add) or pointer events leaking from dialogs.\n const target = event.target as HTMLElement;\n if (!target.closest('[data-testid=\"feature-node-card\"]')) return;\n guardedNavigate(() => {\n clickSound.play();\n router.push(`/feature/${data.featureId}`);\n });\n }\n },\n [router, clickSound, guardedNavigate]\n );\n\n const handleAddFeature = useCallback(() => {\n clickSound.play();\n router.push('/create');\n }, [router, clickSound]);\n\n const handleAddFeatureToRepo = useCallback(\n (repoNodeId: string) => {\n clickSound.play();\n const node = nodes.find((n) => n.id === repoNodeId);\n const repoPath = (node?.data as { repositoryPath?: string } | undefined)?.repositoryPath;\n router.push(buildCreateUrl(repoPath ? { repo: repoPath } : {}));\n },\n [nodes, router, clickSound]\n );\n\n const handleAddFeatureToFeature = useCallback(\n (featureNodeId: string) => {\n const featureId = featureNodeId.startsWith('feat-') ? featureNodeId.slice(5) : featureNodeId;\n // Find the repo node that owns this feature\n const repoEdge = edges.find((e) => e.target === featureNodeId);\n const repoNode = repoEdge ? nodes.find((n) => n.id === repoEdge.source) : null;\n const repoPath = (repoNode?.data as { repositoryPath?: string } | undefined)?.repositoryPath;\n\n clickSound.play();\n router.push(buildCreateUrl({ repo: repoPath, parent: featureId }));\n },\n [nodes, edges, router, clickSound]\n );\n\n const handleRepositoryClick = useCallback(\n (nodeId: string) => {\n const node = nodes.find((n) => n.id === nodeId);\n if (node?.type === 'repositoryNode') {\n const data = node.data as RepositoryNodeData;\n if (data.id) {\n guardedNavigate(() => router.push(`/repository/${data.id}`));\n }\n }\n },\n [nodes, router, guardedNavigate]\n );\n\n // Close all drawers — navigate back to the control-center canvas\n const handleClearDrawers = useCallback(() => {\n if (pathname !== '/control-center') {\n guardedNavigate(() => router.push('/control-center'));\n }\n }, [router, pathname, guardedNavigate]);\n\n // Shared: after adding first repo, center canvas and open create drawer\n const focusAndOpenDrawer = useCallback(\n (repoPath: string) => {\n // Wait for next render so the repo node exists in the DOM\n setTimeout(() => {\n fitView(AUTO_FOCUS_OPTIONS);\n\n // Open the create-feature drawer after the fitView animation completes\n drawerTimerRef.current = setTimeout(() => {\n guardedNavigate(() => router.push(buildCreateUrl({ repo: repoPath })));\n }, AUTO_FOCUS_DRAWER_DELAY_MS);\n }, 0);\n },\n [fitView, guardedNavigate, router]\n );\n\n // Smoothly pan/zoom to a specific node after it appears on canvas\n const focusOnNode = useCallback(\n (nodeId: string) => {\n // Wait for next render so the node exists in the DOM\n setTimeout(() => {\n fitView({\n nodes: [{ id: nodeId }],\n maxZoom: 1.0,\n padding: 0.4,\n duration: 600,\n });\n }, 0);\n },\n [fitView]\n );\n\n // Wrapper: add repo + auto-focus on the new node\n const addRepoAndFocus = useCallback(\n (path: string) => {\n const { wasEmpty, repoPath, tempNodeId } = handleAddRepository(path);\n if (wasEmpty) {\n focusAndOpenDrawer(repoPath);\n } else {\n focusOnNode(tempNodeId);\n }\n },\n [handleAddRepository, focusAndOpenDrawer, focusOnNode]\n );\n\n // All five window-level CustomEvent listeners (add-repository, feature-\n // created, delete/archive/unarchive requests) live in this hook so the\n // parent component stays focused on graph state + rendering.\n useCanvasEventListeners({\n addRepoAndFocus,\n createFeatureNode,\n nodes,\n handleDeleteFeature,\n handleArchiveFeature,\n handleUnarchiveFeature,\n });\n\n // Cleanup the drawer timer on unmount. Used to live inside the inlined\n // shep:add-repository listener; now standalone since the listener moved.\n useEffect(() => {\n return () => {\n if (drawerTimerRef.current != null) {\n clearTimeout(drawerTimerRef.current);\n }\n };\n }, []);\n\n // Wire callbacks into derived node data (via ref — no re-render).\n useEffect(() => {\n setCallbacks({\n onNodeAction: handleAddFeatureToFeature,\n onFeatureDelete: handleDeleteFeature,\n onRetryFeature: handleRetryFeature,\n onStartFeature: handleStartFeature,\n onStopFeature: handleStopFeature,\n onArchiveFeature: handleArchiveFeature,\n onUnarchiveFeature: handleUnarchiveFeature,\n onRepositoryAdd: handleAddFeatureToRepo,\n onRepositoryClick: handleRepositoryClick,\n onRepositoryDelete: handleDeleteRepository,\n onApplicationClick: handleApplicationClick,\n onApplicationDelete: handleDeleteApplication,\n onApplicationCreateSddFeature: handleApplicationCreateSddFeature,\n });\n }, [\n setCallbacks,\n handleAddFeatureToFeature,\n handleArchiveFeature,\n handleDeleteFeature,\n handleRetryFeature,\n handleStartFeature,\n handleStopFeature,\n handleUnarchiveFeature,\n handleAddFeatureToRepo,\n handleRepositoryClick,\n handleDeleteRepository,\n handleApplicationClick,\n handleDeleteApplication,\n handleApplicationCreateSddFeature,\n ]);\n\n const handleMoveEnd = useCallback(\n (_event: unknown, viewport: Viewport) => {\n handleViewportChange(viewport);\n },\n [handleViewportChange]\n );\n\n const hasRepositories = nodes.some((n) => n.type === 'repositoryNode');\n // The canvas is \"non-empty\" as soon as ANY repo OR application node is\n // present — applications are first-class top-level nodes, so creating\n // an application alone must be enough to keep the prompt empty state\n // from re-appearing on next visit.\n const hasCanvasContent = hasRepositories || nodes.some((n) => n.type === 'applicationNode');\n\n // Publish repo state to sidebar context so AppShell can hide FAB during onboarding\n useEffect(() => {\n setSidebarHasRepos(hasRepositories);\n }, [hasRepositories, setSidebarHasRepos]);\n\n // Debounced latch: prevent empty-state flicker during brief reconcile gaps\n // (e.g. stale poll momentarily drops nodes), but allow the empty state to\n // return after a real delete once content stays gone past the debounce window.\n const [showCanvas, setShowCanvas] = useState(hasCanvasContent);\n const latchTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (hasCanvasContent) {\n // Repos / apps exist — show canvas immediately, cancel any pending unlatch\n if (latchTimerRef.current) {\n clearTimeout(latchTimerRef.current);\n latchTimerRef.current = null;\n }\n setShowCanvas(true);\n } else if (showCanvas) {\n // All canvas content gone — clear saved viewport so next add starts\n // centered, then wait before showing empty state (debounce stale polls)\n resetViewport();\n latchTimerRef.current = setTimeout(() => {\n setShowCanvas(false);\n latchTimerRef.current = null;\n }, 500);\n }\n return () => {\n if (latchTimerRef.current) clearTimeout(latchTimerRef.current);\n };\n }, [hasCanvasContent, showCanvas, resetViewport]);\n\n // Auto-include any newly-appearing repo/feature nodes in the active\n // workspace (skipped when default is active — that workspace shows\n // everything anyway). We diff the current node id list against the set\n // we've already seen so we only add the deltas.\n useEffect(() => {\n const seen = knownNodeIdsRef.current;\n const newRepoIds: string[] = [];\n const newFeatureIds: string[] = [];\n for (const n of nodes) {\n if (seen.has(n.id)) continue;\n seen.add(n.id);\n if (n.type === 'repositoryNode') newRepoIds.push(n.id);\n else if (n.type === 'featureNode') newFeatureIds.push(n.id);\n }\n if (isDefaultActive) return;\n if (newRepoIds.length === 0 && newFeatureIds.length === 0) return;\n addToActiveWorkspace({ repoIds: newRepoIds, featureIds: newFeatureIds });\n }, [nodes, isDefaultActive, addToActiveWorkspace]);\n\n // Filter nodes by the active workspace (default workspace = no filter).\n // We always filter from the full `nodes` list so `displayNodes` already\n // reflects workspace membership before pulse-add decoration runs.\n const workspaceFilteredNodes = useMemo(() => {\n if (isDefaultActive) return nodes;\n const allowedRepos = new Set(activeWorkspace.repoIds);\n const allowedFeatures = new Set(activeWorkspace.featureIds);\n return nodes.filter((n) => {\n if (n.type === 'repositoryNode') return allowedRepos.has(n.id);\n if (n.type === 'featureNode') return allowedFeatures.has(n.id);\n return true;\n });\n }, [nodes, isDefaultActive, activeWorkspace]);\n\n // Drop edges whose endpoints were filtered out.\n const workspaceFilteredEdges = useMemo(() => {\n if (isDefaultActive) return edges;\n const visibleIds = new Set(workspaceFilteredNodes.map((n) => n.id));\n return edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target));\n }, [edges, isDefaultActive, workspaceFilteredNodes]);\n\n // Pulse the \"+\" button when there's a single repo with no features and the\n // create-feature drawer is not open — draws attention to the next action.\n const isCreateDrawerOpen = pathname.startsWith('/create');\n const displayNodes = useMemo(() => {\n const source = workspaceFilteredNodes;\n const repoNodes = source.filter((n) => n.type === 'repositoryNode');\n const hasFeatures = source.some((n) => n.type === 'featureNode');\n const shouldPulse = repoNodes.length === 1 && !hasFeatures && !isCreateDrawerOpen;\n\n if (!shouldPulse) return source;\n\n return source.map((n) =>\n n.type === 'repositoryNode' ? { ...n, data: { ...n.data, pulseAdd: true } } : n\n );\n }, [workspaceFilteredNodes, isCreateDrawerOpen]);\n\n const handlePickFolder = useCallback(() => {\n window.dispatchEvent(new CustomEvent('shep:pick-folder'));\n }, []);\n\n // Re-fit the viewport when the active workspace's visible node set changes.\n // See use-workspace-fit-view.ts for the scoping rules.\n useWorkspaceFitView({\n activeWorkspace,\n isDefaultActive,\n workspaceFilteredNodes,\n fitView,\n });\n\n // When the active (non-default) workspace has no members but real canvas\n // content (repos or applications) exists, show a workspace-aware empty\n // state instead of the welcome wizard. The wizard would imply \"no nodes\n // at all\", which is wrong here — and crucially, leaves the workspace\n // selector visible via the toolbar so users can switch back to default.\n const workspaceFilteredEmpty =\n hasCanvasContent && !isDefaultActive && workspaceFilteredNodes.length === 0;\n\n const emptyStateNode = workspaceFilteredEmpty ? (\n <div className=\"pointer-events-auto flex h-full w-full flex-col items-center justify-center px-8\">\n <div className=\"bg-primary/10 text-primary mb-5 flex h-12 w-12 items-center justify-center rounded-2xl\">\n <Layers className=\"h-6 w-6\" />\n </div>\n <h2 className=\"text-foreground/90 text-center text-2xl font-light tracking-tight\">\n This workspace is empty\n </h2>\n <p className=\"text-muted-foreground mt-2 max-w-sm text-center text-sm leading-relaxed\">\n Add repositories or features from the canvas, or switch back to the default workspace to see\n everything.\n </p>\n <div className=\"mt-6 flex items-center gap-2\">\n <Button\n size=\"sm\"\n onClick={() => setWorkspaceNewProjectOpen(true)}\n className=\"bg-blue-500 text-white hover:bg-blue-600\"\n >\n <FolderPlus className=\"me-1.5 h-3.5 w-3.5\" />\n New project\n </Button>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setManageWorkspaceOpen(true)}>\n <Plus className=\"me-1.5 h-3.5 w-3.5\" />\n Manage items\n </Button>\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setActiveWorkspace(DEFAULT_WORKSPACE_ID)}>\n Switch to Default\n </Button>\n </div>\n </div>\n ) : (\n <ControlCenterOnboarding onRepositorySelect={addRepoAndFocus} />\n );\n\n // ── Full-screen create prompt overlay ────────────────────────────────\n const [showCreatePrompt, setShowCreatePrompt] = useState(false);\n\n const featureFlags = useFeatureFlags();\n\n const collaborationApps = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'applicationNode')\n .map((n) => ({\n id: n.data.id as string,\n name: n.data.name as string,\n kind: 'app' as const,\n })),\n [initialNodes]\n );\n\n const collaborationRepos = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'repositoryNode')\n .map((n) => ({\n id: (n.data.id ?? n.id) as string,\n name: n.data.name as string,\n kind: 'repo' as const,\n })),\n [initialNodes]\n );\n\n const collaborationFeatures = useMemo(\n () =>\n initialNodes\n .filter((n) => n.type === 'featureNode')\n .map((n) => ({\n id: (n.data.featureId ?? n.id) as string,\n name: n.data.name as string,\n kind: 'feature' as const,\n })),\n [initialNodes]\n );\n\n // Derive the FAB's app context from the canvas. When exactly one\n // ApplicationNode is on the visible canvas we treat it as the scoped\n // application — surfacing the contextual \"New SDD feature for <app>\"\n // FAB action without forcing the user to make an explicit selection\n // gesture (the canvas runs with `elementsSelectable={false}` so React\n // Flow's native multi-select isn't available here).\n const applicationNodes = useMemo(\n () => displayNodes.filter((n) => n.type === 'applicationNode'),\n [displayNodes]\n );\n const selectedApplicationId =\n applicationNodes.length === 1\n ? (applicationNodes[0].data as ApplicationNodeData).id\n : undefined;\n const selectedApplicationName =\n applicationNodes.length === 1\n ? (applicationNodes[0].data as ApplicationNodeData).name\n : undefined;\n\n // (+) FAB actions — only visible on control center. Action list lives in\n // its own hook so this component stays focused on graph state + rendering.\n const fabActions = useFabActions({\n router,\n clickSound,\n guardedNavigate,\n handlePickFolder,\n onNewProject: () => setWorkspaceNewProjectOpen(true),\n onNewApplication: () => setShowCreatePrompt(true),\n ...(selectedApplicationId !== undefined && { selectedApplicationId }),\n ...(selectedApplicationName !== undefined && { selectedApplicationName }),\n });\n\n const canvasToolbar = (\n <CanvasToolbar\n showArchived={showArchived}\n onToggleArchived={() => setShowArchived(!showArchived)}\n onResetViewport={resetViewport}\n startSlot={\n <WorkspaceSelector\n workspaces={workspaces}\n activeWorkspace={activeWorkspace}\n onSelect={setActiveWorkspace}\n onRequestCreate={() => setCreateWorkspaceOpen(true)}\n onRequestRename={() => setRenameWorkspaceOpen(true)}\n onRequestDelete={(id) => {\n setPendingDeleteWorkspaceId(id);\n setDeleteWorkspaceOpen(true);\n }}\n onManage={() => setManageWorkspaceOpen(true)}\n />\n }\n />\n );\n\n return (\n <>\n <FeaturesCanvas\n nodes={showCanvas ? displayNodes : []}\n edges={showCanvas ? workspaceFilteredEdges : []}\n selectedFeatureId={selectedFeatureId}\n selectedRepository={selectedRepository}\n defaultViewport={defaultViewport}\n onNodesChange={onNodesChange}\n onConnect={handleConnect}\n onAddFeature={handleAddFeature}\n onNodeClick={handleNodeClick}\n onPaneClick={handleClearDrawers}\n onMoveEnd={handleMoveEnd}\n toolbar={canvasToolbar}\n showToolbarOnEmpty={workspaceFilteredEmpty}\n emptyState={emptyStateNode}\n />\n {/* Collaboration onboarding — top-right overlay, shown once per browser profile */}\n {featureFlags.collaboration ? (\n <div className=\"pointer-events-none absolute inset-x-0 top-14 z-10 flex justify-end px-4\">\n <CollaborationOnboarding\n apps={collaborationApps}\n repos={collaborationRepos}\n features={collaborationFeatures}\n className=\"pointer-events-auto w-full max-w-md\"\n />\n </div>\n ) : null}\n {/* (+) FAB — bottom-left, moves with sidebar */}\n {showCanvas ? <CreateFab actions={fabActions} /> : null}\n <NewProjectDialog\n open={workspaceNewProjectOpen}\n onOpenChange={setWorkspaceNewProjectOpen}\n onCreated={(path) => addRepoAndFocus(path)}\n />\n <ManageWorkspaceDialog\n open={manageWorkspaceOpen}\n onOpenChange={setManageWorkspaceOpen}\n workspace={activeWorkspace}\n allNodes={nodes}\n onSave={(members) => setWorkspaceMembers(activeWorkspace.id, members)}\n />\n <WorkspaceNameDialog\n open={createWorkspaceOpen}\n onOpenChange={setCreateWorkspaceOpen}\n title=\"New workspace\"\n description=\"Create a workspace to filter the canvas to a specific set of repositories and features.\"\n confirmLabel=\"Create\"\n onConfirm={(name) => {\n createWorkspace(name);\n setManageWorkspaceOpen(true);\n }}\n />\n <WorkspaceNameDialog\n open={renameWorkspaceOpen}\n onOpenChange={setRenameWorkspaceOpen}\n title=\"Rename workspace\"\n initialValue={activeWorkspace.name}\n confirmLabel=\"Rename\"\n onConfirm={(name) => renameWorkspace(activeWorkspace.id, name)}\n />\n <AlertDialog\n open={deleteWorkspaceOpen}\n onOpenChange={(open) => {\n setDeleteWorkspaceOpen(open);\n if (!open) setPendingDeleteWorkspaceId(null);\n }}\n >\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete workspace?</AlertDialogTitle>\n <AlertDialogDescription>\n This will permanently remove the workspace “\n {workspaces.find((w) => w.id === pendingDeleteWorkspaceId)?.name ??\n activeWorkspace.name}\n ”. The repositories and features themselves are not affected.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n variant=\"destructive\"\n onClick={() => {\n if (pendingDeleteWorkspaceId) {\n deleteWorkspace(pendingDeleteWorkspaceId);\n setPendingDeleteWorkspaceId(null);\n }\n }}\n >\n Delete\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n\n {/* Full-screen create prompt overlay (replaces the old dialog) */}\n {showCreatePrompt ? (\n <div className=\"absolute inset-0 z-50\">\n <ControlCenterEmptyState\n onRepositorySelect={(path) => {\n setShowCreatePrompt(false);\n addRepoAndFocus(path);\n }}\n onApplicationCreated={(appId) => {\n // Navigate first — keep overlay mounted to avoid canvas flash.\n // The overlay unmounts when the route changes.\n router.push(`/application/${appId}`);\n }}\n onClose={() => setShowCreatePrompt(false)}\n className=\"bg-background\"\n />\n </div>\n ) : null}\n </>\n );\n}\n\n/** (+) FAB that tracks sidebar width via CSS var + transition.\n * When fabLayout.swapPosition is true, moves to the end side (right in LTR). */\nfunction CreateFab({ actions }: { actions: FloatingActionButtonAction[] }) {\n const { state } = useSidebar();\n const { i18n } = useTranslation('web');\n const { swapPosition } = useFabLayout();\n const isRtl = i18n.dir() === 'rtl';\n\n // Default: start side (left in LTR), tracking sidebar width\n // Swapped: end side (right in LTR), fixed 32px from edge\n if (swapPosition) {\n const positionStyle: React.CSSProperties = isRtl\n ? {\n left: 'calc(var(--sidebar-width-icon) + 32px)',\n transition: 'left 200ms ease-in-out',\n }\n : { right: '32px', transition: 'right 200ms ease-in-out' };\n\n return (\n <FloatingActionButton actions={actions} className=\"!fixed bottom-6\" style={positionStyle} />\n );\n }\n\n // Sidebar expanded = var(--sidebar-width) = 16rem, collapsed = var(--sidebar-width-icon) = 3rem\n // Position just outside the sidebar edge with 16px gap\n const offset =\n state === 'expanded'\n ? 'calc(var(--sidebar-width) + 32px)'\n : 'calc(var(--sidebar-width-icon) + 32px)';\n\n const positionStyle: React.CSSProperties = isRtl\n ? { right: offset, transition: 'right 200ms ease-in-out' }\n : { left: offset, transition: 'left 200ms ease-in-out' };\n\n return (\n <FloatingActionButton actions={actions} className=\"!fixed bottom-6\" style={positionStyle} />\n );\n}\n","/**\n * Build the action list for the (+) FloatingActionButton on the control\n * center. Extracted from control-center-inner.tsx so the parent component\n * stays focused on graph state + rendering.\n */\n\nimport { useMemo } from 'react';\nimport {\n ClipboardList,\n FolderOpen,\n FolderPlus,\n GitBranch,\n Github,\n LayoutGrid,\n Sparkles,\n} from 'lucide-react';\nimport type { useRouter } from 'next/navigation';\nimport { useTranslation } from 'react-i18next';\n\nimport { BuildMode } from '@shepai/core/domain/generated/output';\nimport type { FloatingActionButtonAction } from '@/components/common/floating-action-button';\nimport { buildCreateUrl } from '@/lib/url-params';\n\ninterface UseFabActionsParams {\n router: ReturnType<typeof useRouter>;\n clickSound: { play: () => void };\n guardedNavigate: (fn: () => void) => void;\n handlePickFolder: () => void;\n onNewProject: () => void;\n onNewApplication: () => void;\n /** Domain UUID of the application currently scoped on the canvas — when\n * exactly one ApplicationNode is selected/visible, the FAB exposes an\n * extra \"New SDD feature for <app>\" item that opens the create drawer\n * pre-scoped to this application in spec mode. Undefined disables the\n * action; the rest of the FAB items are unconditional. */\n selectedApplicationId?: string;\n /** Display name of the selected application — used purely for the\n * i18n interpolation of the FAB item label. */\n selectedApplicationName?: string;\n}\n\nexport function useFabActions({\n router,\n clickSound,\n guardedNavigate,\n handlePickFolder,\n onNewProject,\n onNewApplication,\n selectedApplicationId,\n selectedApplicationName,\n}: UseFabActionsParams): FloatingActionButtonAction[] {\n const { t } = useTranslation('web');\n\n return useMemo<FloatingActionButtonAction[]>(() => {\n const actions: FloatingActionButtonAction[] = [\n {\n id: 'new-project',\n label: 'New project',\n icon: <FolderPlus className=\"h-4 w-4\" />,\n onClick: () => {\n clickSound.play();\n onNewProject();\n },\n },\n {\n id: 'new-feature',\n label: t('fab.newFeature'),\n icon: <Sparkles className=\"h-4 w-4\" />,\n onClick: () => {\n clickSound.play();\n guardedNavigate(() => router.push('/create'));\n },\n },\n {\n id: 'add-local-repo',\n label: t('fab.localFolder'),\n icon: <FolderOpen className=\"h-4 w-4\" />,\n onClick: handlePickFolder,\n },\n {\n id: 'new-application',\n label: t('fab.newApplication'),\n icon: <LayoutGrid className=\"h-4 w-4\" />,\n onClick: onNewApplication,\n },\n ];\n if (selectedApplicationId) {\n actions.push({\n id: 'new-sdd-feature-for-app',\n label: t('fab.newSddForApp', { appName: selectedApplicationName ?? '' }),\n icon: <ClipboardList className=\"h-4 w-4\" />,\n onClick: () => {\n clickSound.play();\n guardedNavigate(() =>\n router.push(\n buildCreateUrl({\n applicationId: selectedApplicationId,\n mode: BuildMode.Spec,\n })\n )\n );\n },\n });\n }\n actions.push({\n id: 'adopt-branch',\n label: t('fab.adoptBranch'),\n icon: <GitBranch className=\"h-4 w-4\" />,\n onClick: () => {\n guardedNavigate(() => router.push('/adopt'));\n },\n });\n actions.push({\n id: 'add-github-repo',\n label: t('fab.fromGithub'),\n icon: <Github className=\"h-4 w-4\" />,\n onClick: () => {\n window.dispatchEvent(new CustomEvent('shep:open-github-import'));\n },\n });\n return actions;\n }, [\n t,\n clickSound,\n guardedNavigate,\n router,\n handlePickFolder,\n onNewProject,\n onNewApplication,\n selectedApplicationId,\n selectedApplicationName,\n ]);\n}\n","import createLucideIcon from '../createLucideIcon';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [\n ['path', { d: 'M8 3H5a2 2 0 0 0-2 2v3', key: '1dcmit' }],\n ['path', { d: 'M21 8V5a2 2 0 0 0-2-2h-3', key: '1e4gt3' }],\n ['path', { d: 'M3 16v3a2 2 0 0 0 2 2h3', key: 'wsl5sc' }],\n ['path', { d: 'M16 21h3a2 2 0 0 0 2-2v-3', key: '18trek' }],\n];\n\n/**\n * @component @name Maximize\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview  - https://lucide.dev/icons/maximize\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst Maximize = createLucideIcon('maximize', __iconNode);\n\nexport default Maximize;\n","import createLucideIcon from '../createLucideIcon';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [\n ['circle', { cx: '11', cy: '11', r: '8', key: '4ej97u' }],\n ['line', { x1: '21', x2: '16.65', y1: '21', y2: '16.65', key: '13gj7c' }],\n ['line', { x1: '11', x2: '11', y1: '8', y2: '14', key: '1vmskp' }],\n ['line', { x1: '8', x2: '14', y1: '11', y2: '11', key: 'durymu' }],\n];\n\n/**\n * @component @name ZoomIn\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview  - https://lucide.dev/icons/zoom-in\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ZoomIn = createLucideIcon('zoom-in', __iconNode);\n\nexport default ZoomIn;\n","import createLucideIcon from '../createLucideIcon';\nimport { IconNode } from '../types';\n\nexport const __iconNode: IconNode = [\n ['circle', { cx: '11', cy: '11', r: '8', key: '4ej97u' }],\n ['line', { x1: '21', x2: '16.65', y1: '21', y2: '16.65', key: '13gj7c' }],\n ['line', { x1: '8', x2: '14', y1: '11', y2: '11', key: 'durymu' }],\n];\n\n/**\n * @component @name ZoomOut\n * @description Lucide SVG icon component, renders SVG Element with children.\n *\n * @preview  - https://lucide.dev/icons/zoom-out\n * @see https://lucide.dev/guide/packages/lucide-react - Documentation\n *\n * @param {Object} props - Lucide icons props and any valid SVG attribute\n * @returns {JSX.Element} JSX Element\n *\n */\nconst ZoomOut = createLucideIcon('zoom-out', __iconNode);\n\nexport default ZoomOut;\n","/**\n * Re-fit the React Flow viewport when the active workspace's visible node\n * set changes (switching workspaces, or changing the active workspace's\n * membership via the Manage dialog).\n *\n * Intentionally scoped:\n * - Skips the first run so we don't override the persisted viewport on mount.\n * - Skips the default workspace, which shows everything and owns the\n * persisted viewport via useViewportPersistence.\n * - Skips empty workspaces — there's nothing to fit.\n * - Defers fitView to the next tick so React Flow has committed the new\n * node set before measuring.\n */\n\nimport { useEffect, useMemo, useRef } from 'react';\nimport type { useReactFlow } from '@xyflow/react';\n\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\n\ntype FitViewFn = ReturnType<typeof useReactFlow>['fitView'];\n\ninterface ActiveWorkspaceLike {\n id: string;\n}\n\nconst AUTO_FOCUS_OPTIONS = {\n maxZoom: 1.0,\n padding: 0.5,\n duration: 500,\n} as const;\n\nexport function useWorkspaceFitView(params: {\n activeWorkspace: ActiveWorkspaceLike;\n isDefaultActive: boolean;\n workspaceFilteredNodes: CanvasNodeType[];\n fitView: FitViewFn;\n}): void {\n const { activeWorkspace, isDefaultActive, workspaceFilteredNodes, fitView } = params;\n\n const fingerprint = useMemo(() => {\n if (isDefaultActive) return 'default';\n const ids = workspaceFilteredNodes\n .map((n) => n.id)\n .sort()\n .join(',');\n return `${activeWorkspace.id}:${ids}`;\n }, [isDefaultActive, activeWorkspace.id, workspaceFilteredNodes]);\n\n const prevFingerprintRef = useRef<string | null>(null);\n\n useEffect(() => {\n const prev = prevFingerprintRef.current;\n prevFingerprintRef.current = fingerprint;\n if (prev === null) return;\n if (prev === fingerprint) return;\n if (isDefaultActive) return;\n if (workspaceFilteredNodes.length === 0) return;\n\n const t = setTimeout(() => {\n fitView(AUTO_FOCUS_OPTIONS);\n }, 0);\n return () => clearTimeout(t);\n }, [fingerprint, isDefaultActive, workspaceFilteredNodes.length, fitView]);\n}\n","/**\n * Wire global window events used by the control center canvas to the\n * appropriate handlers. The canvas listens for cross-component requests\n * dispatched as CustomEvents:\n *\n * - shep:add-repository → addRepoAndFocus(path)\n * - shep:feature-created → createFeatureNode(...)\n * - shep:feature-delete-requested → handleDeleteFeature(...)\n * - shep:feature-archive-requested → handleArchiveFeature(...)\n * - shep:feature-unarchive-requested → handleUnarchiveFeature(...)\n *\n * Extracted from control-center-inner.tsx so the parent component stays\n * focused on graph state + rendering, not event-bus plumbing.\n */\n\nimport { useEffect } from 'react';\n\nimport type { CanvasNodeType } from '@/components/features/features-canvas';\nimport type { FeatureNodeData } from '@/components/common/feature-node';\n\nexport type CreateFeatureNodeFn = (\n sourceNodeId: string | null,\n dataOverride?: Partial<FeatureNodeData>,\n edgeType?: string\n) => string;\n\nexport interface CanvasEventListenerHandlers {\n addRepoAndFocus: (path: string) => void;\n createFeatureNode: CreateFeatureNodeFn;\n nodes: CanvasNodeType[];\n handleDeleteFeature: (\n featureId: string,\n cleanup?: boolean,\n cascadeDelete?: boolean,\n closePr?: boolean\n ) => void;\n handleArchiveFeature: (featureId: string) => void;\n handleUnarchiveFeature: (featureId: string) => void;\n}\n\nexport function useCanvasEventListeners(handlers: CanvasEventListenerHandlers): void {\n const {\n addRepoAndFocus,\n createFeatureNode,\n nodes,\n handleDeleteFeature,\n handleArchiveFeature,\n handleUnarchiveFeature,\n } = handlers;\n\n // shep:add-repository — top-bar \"add folder\" button\n useEffect(() => {\n const handler = (e: Event) => {\n const path = (e as CustomEvent<{ path: string }>).detail.path;\n addRepoAndFocus(path);\n };\n window.addEventListener('shep:add-repository', handler);\n return () => window.removeEventListener('shep:add-repository', handler);\n }, [addRepoAndFocus]);\n\n // shep:feature-created — fired by the create drawer with the real server feature ID\n useEffect(() => {\n const handler = (e: Event) => {\n const detail = (\n e as CustomEvent<{\n featureId: string;\n name: string;\n description?: string;\n repositoryPath: string;\n parentId?: string;\n applicationId?: string;\n }>\n ).detail;\n\n // When parentId is provided, attach to the parent feature node via a\n // dependency edge instead of the repo node.\n if (detail.parentId) {\n const parentNodeId = `feat-${detail.parentId}`;\n createFeatureNode(\n parentNodeId,\n {\n state: 'creating',\n featureId: detail.featureId,\n name: detail.name,\n description: detail.description,\n repositoryPath: detail.repositoryPath,\n },\n 'dependencyEdge'\n );\n return;\n }\n\n // When applicationId is provided, attach to the matching application\n // node via a dependency edge so the optimistic feature renders as a\n // child of its application — never as a sibling of a virtual repo.\n // The `applicationId` data field also lets `derive-graph` keep the\n // app→feature edge stable across reconciliation.\n if (detail.applicationId) {\n const appNodeId = `app-${detail.applicationId}`;\n const appNode = nodes.find((n) => n.id === appNodeId && n.type === 'applicationNode');\n if (appNode) {\n createFeatureNode(\n appNodeId,\n {\n state: 'running',\n featureId: detail.featureId,\n name: detail.name,\n description: detail.description,\n repositoryPath: detail.repositoryPath,\n applicationId: detail.applicationId,\n },\n 'dependencyEdge'\n );\n return;\n }\n }\n\n const repoNode = nodes.find(\n (n) =>\n n.type === 'repositoryNode' &&\n (n.data as { repositoryPath?: string }).repositoryPath === detail.repositoryPath\n );\n\n createFeatureNode(repoNode?.id ?? null, {\n state: 'running',\n featureId: detail.featureId,\n name: detail.name,\n description: detail.description,\n repositoryPath: detail.repositoryPath,\n });\n };\n window.addEventListener('shep:feature-created', handler);\n return () => window.removeEventListener('shep:feature-created', handler);\n }, [nodes, createFeatureNode]);\n\n // shep:feature-delete-requested — fired from the feature drawer\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId, cleanup, cascadeDelete, closePr } = (\n e as CustomEvent<{\n featureId: string;\n cleanup?: boolean;\n cascadeDelete?: boolean;\n closePr?: boolean;\n }>\n ).detail;\n handleDeleteFeature(featureId, cleanup, cascadeDelete, closePr);\n };\n window.addEventListener('shep:feature-delete-requested', handler);\n return () => window.removeEventListener('shep:feature-delete-requested', handler);\n }, [handleDeleteFeature]);\n\n // shep:feature-archive-requested — fired from the feature drawer\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;\n handleArchiveFeature(featureId);\n };\n window.addEventListener('shep:feature-archive-requested', handler);\n return () => window.removeEventListener('shep:feature-archive-requested', handler);\n }, [handleArchiveFeature]);\n\n // shep:feature-unarchive-requested — fired from the feature drawer\n useEffect(() => {\n const handler = (e: Event) => {\n const { featureId } = (e as CustomEvent<{ featureId: string }>).detail;\n handleUnarchiveFeature(featureId);\n };\n window.addEventListener('shep:feature-unarchive-requested', handler);\n return () => window.removeEventListener('shep:feature-unarchive-requested', handler);\n }, [handleUnarchiveFeature]);\n}\n"],"names":[],"mappings":"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","ignoreList":[27,28,29]}
|