@shepai/cli 1.95.0 → 1.96.0-pr281.fcbc0cd
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/README.md +132 -348
- package/apis/json-schema/Feature.yaml +1 -1
- package/apis/json-schema/SdlcLifecycle.yaml +1 -0
- package/dist/packages/core/src/application/ports/output/repositories/feature-repository.interface.d.ts +16 -4
- package/dist/packages/core/src/application/ports/output/repositories/feature-repository.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.d.ts +17 -12
- package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.js +64 -31
- package/dist/packages/core/src/application/use-cases/settings/complete-web-onboarding.use-case.d.ts +19 -0
- package/dist/packages/core/src/application/use-cases/settings/complete-web-onboarding.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/settings/complete-web-onboarding.use-case.js +52 -0
- package/dist/packages/core/src/application/use-cases/settings/index.d.ts +2 -0
- package/dist/packages/core/src/application/use-cases/settings/index.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/settings/index.js +1 -0
- package/dist/packages/core/src/domain/generated/output.d.ts +3 -2
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/domain/generated/output.js +1 -0
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +5 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/feature.mapper.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/feature.mapper.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/feature.mapper.js +4 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations.js +12 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-feature.repository.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-feature.repository.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-feature.repository.js +13 -3
- package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/ls.command.js +9 -2
- package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/new.command.js +9 -0
- package/dist/src/presentation/cli/index.js +0 -12
- package/dist/src/presentation/web/app/actions/agent-setup-flag.d.ts +6 -0
- package/dist/src/presentation/web/app/actions/agent-setup-flag.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/agent-setup-flag.js +14 -0
- package/dist/src/presentation/web/app/actions/check-agent-tool.d.ts +11 -0
- package/dist/src/presentation/web/app/actions/check-agent-tool.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/check-agent-tool.js +35 -0
- package/dist/src/presentation/web/app/actions/update-agent-and-model.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/update-agent-and-model.js +6 -12
- package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/agent-events/route.js +1 -0
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +5 -0
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +4 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.js +11 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.js +4 -4
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +21 -0
- package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-empty-state.js +20 -4
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +53 -16
- package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.d.ts +6 -0
- package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.d.ts.map +1 -0
- package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.js +222 -0
- package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.stories.d.ts +7 -0
- package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.stories.js +20 -0
- package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +1 -1
- package/dist/src/presentation/web/hooks/sidebar-features-context.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/sidebar-features-context.js +1 -0
- package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-graph-state.js +27 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +92 -62
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js +2 -2
- 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/server-reference-manifest.json +102 -42
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +2 -2
- 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/server-reference-manifest.json +102 -42
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +2 -2
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +88 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +2 -2
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +92 -62
- package/web/.next/server/app/(dashboard)/create/page.js +2 -2
- 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/server-reference-manifest.json +102 -42
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +2 -2
- 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/server-reference-manifest.json +102 -42
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +2 -2
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +88 -28
- package/web/.next/server/app/(dashboard)/page.js +2 -2
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +88 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +2 -2
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_2b65878f._.js +3 -0
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_2b65878f._.js.map +1 -0
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_6ba7eb21._.js +3 -0
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_6ba7eb21._.js.map +1 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_c757eb00.js +3 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_c757eb00.js.map +1 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_7eb49631.js +3 -0
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_7eb49631.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__17143953._.js → [root-of-the-server]__19fb0bfe._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__5cc4752a._.js.map → [root-of-the-server]__19fb0bfe._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__24dd0927._.js +4 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__24dd0927._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__45aad79d._.js → [root-of-the-server]__3d6f6b0e._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__17143953._.js.map → [root-of-the-server]__3d6f6b0e._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__5cc4752a._.js → [root-of-the-server]__42020c54._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__9de266fa._.js.map → [root-of-the-server]__42020c54._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7b49fcb3._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7b49fcb3._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__845a9d2a._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__845a9d2a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__9de266fa._.js → [root-of-the-server]__9cb60e1e._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__45aad79d._.js.map → [root-of-the-server]__9cb60e1e._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_1bb131c4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_501b06da._.js +3 -0
- package/web/.next/server/chunks/ssr/_501b06da._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_5e112f82._.js +3 -0
- package/web/.next/server/chunks/ssr/_5e112f82._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_6e08ce21._.js +1 -1
- package/web/.next/server/chunks/ssr/_6e08ce21._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_3533fed7._.js → _7f1598ce._.js} +2 -2
- package/web/.next/server/chunks/ssr/_7f1598ce._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
- package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_c2399eb5._.js → _c1e8bc5a._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_c2399eb5._.js.map → _c1e8bc5a._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.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/src_presentation_web_3c53a23d._.js +5 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_3c53a23d._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_befd865a.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_befd865a.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_tools_tools-page-client_tsx_3d0aa70c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_tools_tools-page-client_tsx_3d0aa70c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ec8c7a4f._.js +5 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_ec8c7a4f._.js.map +1 -0
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +482 -242
- package/web/.next/static/chunks/0043b0813128e1ff.js +1 -0
- package/web/.next/static/chunks/158f9d833716f8e0.js +1 -0
- package/web/.next/static/chunks/{465f63a101981da8.js → 1e45f54397cd5d7f.js} +1 -1
- package/web/.next/static/chunks/{c4bbbfcfc008cba4.js → 275e1e0c565cc109.js} +1 -1
- package/web/.next/static/chunks/71d785d1de4b86f6.css +1 -0
- package/web/.next/static/chunks/7268e1087af4eaa0.js +1 -0
- package/web/.next/static/chunks/86a559935e43c119.js +1 -0
- package/web/.next/static/chunks/8bd300e88a189928.js +1 -0
- package/web/.next/static/chunks/{98767389c1aad0b2.js → 8d943a1a82db483d.js} +1 -1
- package/web/.next/static/chunks/a262fb8cb5f35ce3.js +1 -0
- package/web/.next/static/chunks/ae4e669485fb8d72.js +1 -0
- package/web/.next/static/chunks/b272ac93b52dceeb.js +1 -0
- package/web/.next/static/chunks/{f0bbc2f086d7d996.js → b42e2cd6fe3896c3.js} +2 -2
- package/web/.next/static/chunks/{59b988d41943386c.js → c4e8e94e8c2800b0.js} +1 -1
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_81a06555._.js +0 -3
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_81a06555._.js.map +0 -1
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_rocket_1575cd4d.js +0 -3
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_rocket_1575cd4d.js.map +0 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +0 -3
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +0 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +0 -3
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__4be9a9bb._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__4be9a9bb._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9dc40036._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9dc40036._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_3533fed7._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_364346ad._.js +0 -3
- package/web/.next/server/chunks/ssr/_364346ad._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_df15bd24._.js +0 -3
- package/web/.next/server/chunks/ssr/_df15bd24._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_f50485a5._.js +0 -3
- package/web/.next/server/chunks/ssr/_f50485a5._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js +0 -5
- package/web/.next/server/chunks/ssr/src_presentation_web_c4348b8a._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js +0 -5
- package/web/.next/server/chunks/ssr/src_presentation_web_e4510d10._.js.map +0 -1
- package/web/.next/static/chunks/2536dce61f55daad.js +0 -1
- package/web/.next/static/chunks/35b142afe3405da9.js +0 -1
- package/web/.next/static/chunks/3c68b85c9dd7f200.js +0 -1
- package/web/.next/static/chunks/42040482bd2ec9aa.js +0 -1
- package/web/.next/static/chunks/490407527f8234cb.js +0 -1
- package/web/.next/static/chunks/6d61b6eaca9f925a.js +0 -1
- package/web/.next/static/chunks/8ec10587d1c608a2.css +0 -1
- package/web/.next/static/chunks/d9247a52ae260218.js +0 -1
- package/web/.next/static/chunks/eb981f9e02a74f15.js +0 -1
- /package/web/.next/static/{AT8BmALAnMpq68TlqG9FY → mF-tWwVmRA3ztS3klC9lR}/_buildManifest.js +0 -0
- /package/web/.next/static/{AT8BmALAnMpq68TlqG9FY → mF-tWwVmRA3ztS3klC9lR}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{AT8BmALAnMpq68TlqG9FY → mF-tWwVmRA3ztS3klC9lR}/_ssgManifest.js +0 -0
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js
CHANGED
|
@@ -99,7 +99,14 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
99
99
|
processedEventCountRef.current = events.length;
|
|
100
100
|
for (const { featureId, state, lifecycle } of resolveSseEventUpdates(newEvents)) {
|
|
101
101
|
if (state !== undefined || lifecycle !== undefined) {
|
|
102
|
-
|
|
102
|
+
const nodeId = `feat-${featureId}`;
|
|
103
|
+
// Skip SSE updates for features in 'deleting' state — the optimistic
|
|
104
|
+
// delete state must not be overwritten by stale SSE events (e.g. agent
|
|
105
|
+
// cancellation emitting AgentFailed during the soft-delete window).
|
|
106
|
+
const existingNode = nodesRef.current.find((n) => n.id === nodeId);
|
|
107
|
+
if (existingNode && existingNode.data.state === 'deleting')
|
|
108
|
+
continue;
|
|
109
|
+
updateFeature(nodeId, {
|
|
103
110
|
...(state !== undefined && { state }),
|
|
104
111
|
...(lifecycle !== undefined && { lifecycle }),
|
|
105
112
|
});
|
|
@@ -192,32 +199,62 @@ export function useControlCenterState(initialNodes, initialEdges) {
|
|
|
192
199
|
}, [addPendingFeature]);
|
|
193
200
|
const handleDeleteFeature = useCallback((featureId, cleanup) => {
|
|
194
201
|
const nodeId = `feat-${featureId}`;
|
|
195
|
-
//
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
202
|
+
// Collect all descendant feature node IDs (children, grandchildren, etc.)
|
|
203
|
+
const descendants = [];
|
|
204
|
+
const queue = [nodeId];
|
|
205
|
+
while (queue.length > 0) {
|
|
206
|
+
const current = queue.shift();
|
|
207
|
+
for (const edge of edgesRef.current) {
|
|
208
|
+
if (edge.type === 'dependencyEdge' && edge.source === current) {
|
|
209
|
+
descendants.push(edge.target);
|
|
210
|
+
queue.push(edge.target);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Snapshot current states for rollback (parent + descendants)
|
|
215
|
+
const prevStates = new Map();
|
|
216
|
+
for (const nid of [nodeId, ...descendants]) {
|
|
217
|
+
const node = nodesRef.current.find((n) => n.id === nid);
|
|
218
|
+
if (node) {
|
|
219
|
+
prevStates.set(nid, node.data.state);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Optimistic: show "deleting" state on parent AND all descendants
|
|
223
|
+
updateFeature(nodeId, { state: 'deleting' });
|
|
224
|
+
for (const childId of descendants) {
|
|
225
|
+
updateFeature(childId, { state: 'deleting' });
|
|
226
|
+
}
|
|
204
227
|
deleteSound.play();
|
|
205
|
-
toast.success('
|
|
228
|
+
toast.success('Deleting feature…');
|
|
206
229
|
router.push('/');
|
|
207
230
|
deleteFeature(featureId, cleanup)
|
|
208
231
|
.then((result) => {
|
|
209
232
|
if (result.error) {
|
|
210
|
-
|
|
211
|
-
|
|
233
|
+
// Rollback all to previous states
|
|
234
|
+
for (const [nid, prevState] of prevStates) {
|
|
235
|
+
if (prevState)
|
|
236
|
+
updateFeature(nid, { state: prevState });
|
|
237
|
+
}
|
|
212
238
|
toast.error(result.error);
|
|
213
239
|
}
|
|
240
|
+
else {
|
|
241
|
+
// Delete succeeded — remove features from the canvas. The polling
|
|
242
|
+
// reconcile would eventually clean them up, but we remove them
|
|
243
|
+
// explicitly so the user sees them disappear promptly.
|
|
244
|
+
removeFeature(nodeId);
|
|
245
|
+
for (const childId of descendants) {
|
|
246
|
+
removeFeature(childId);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
214
249
|
})
|
|
215
250
|
.catch(() => {
|
|
216
|
-
|
|
217
|
-
|
|
251
|
+
for (const [nid, prevState] of prevStates) {
|
|
252
|
+
if (prevState)
|
|
253
|
+
updateFeature(nid, { state: prevState });
|
|
254
|
+
}
|
|
218
255
|
toast.error('Failed to delete feature');
|
|
219
256
|
});
|
|
220
|
-
}, [router, deleteSound,
|
|
257
|
+
}, [router, deleteSound, updateFeature, removeFeature]);
|
|
221
258
|
const handleDeleteRepository = useCallback(async (repositoryId) => {
|
|
222
259
|
const repoNodeId = `repo-${repositoryId}`;
|
|
223
260
|
// Find children of this repo via edges
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface WelcomeAgentSetupProps {
|
|
2
|
+
onComplete: () => void;
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function WelcomeAgentSetup({ onComplete, className }: WelcomeAgentSetupProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
//# sourceMappingURL=welcome-agent-setup.d.ts.map
|
package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"welcome-agent-setup.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/welcome-agent-setup.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,iBAAiB,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,sBAAsB,2CAoTlF"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
4
|
+
import { Check, ChevronRight, ChevronLeft, Download, Loader2, CheckCircle2, Circle, AlertCircle, Bot, Terminal, ExternalLink, } from 'lucide-react';
|
|
5
|
+
import { getAllAgentModels } from '../../../app/actions/get-all-agent-models.js';
|
|
6
|
+
import { checkAgentTool } from '../../../app/actions/check-agent-tool.js';
|
|
7
|
+
import { updateAgentAndModel } from '../../../app/actions/update-agent-and-model.js';
|
|
8
|
+
import { getAgentTypeIcon } from '../../common/feature-node/agent-type-icons.js';
|
|
9
|
+
import { getModelMeta } from '../../../lib/model-metadata.js';
|
|
10
|
+
import { useToolInstallStream } from '../../../hooks/use-tool-install-stream.js';
|
|
11
|
+
import { cn } from '../../../lib/utils.js';
|
|
12
|
+
const STEPS = ['select-agent', 'select-model', 'check-tool', 'authenticate'];
|
|
13
|
+
/** Fixed width for the wizard content area to prevent layout jumps */
|
|
14
|
+
const WIZARD_WIDTH = 'w-72';
|
|
15
|
+
export function WelcomeAgentSetup({ onComplete, className }) {
|
|
16
|
+
const [groups, setGroups] = useState([]);
|
|
17
|
+
const [loading, setLoading] = useState(true);
|
|
18
|
+
const [step, setStep] = useState('select-agent');
|
|
19
|
+
const [selectedAgent, setSelectedAgent] = useState(null);
|
|
20
|
+
const [selectedModel, setSelectedModel] = useState(null);
|
|
21
|
+
const [toolStatus, setToolStatus] = useState(null);
|
|
22
|
+
const [checkingTool, setCheckingTool] = useState(false);
|
|
23
|
+
const [saving, setSaving] = useState(false);
|
|
24
|
+
const [transitioning, setTransitioning] = useState(false);
|
|
25
|
+
const [visible, setVisible] = useState(true);
|
|
26
|
+
const timeoutRef = useRef(undefined);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
getAllAgentModels()
|
|
29
|
+
.then(setGroups)
|
|
30
|
+
.finally(() => setLoading(false));
|
|
31
|
+
}, []);
|
|
32
|
+
const activeGroup = selectedAgent ? groups.find((g) => g.agentType === selectedAgent) : null;
|
|
33
|
+
/** Animate step transition: fade out → change step → fade in */
|
|
34
|
+
const transitionTo = useCallback((nextStep, setup) => {
|
|
35
|
+
setTransitioning(true);
|
|
36
|
+
setVisible(false);
|
|
37
|
+
if (timeoutRef.current)
|
|
38
|
+
clearTimeout(timeoutRef.current);
|
|
39
|
+
timeoutRef.current = setTimeout(() => {
|
|
40
|
+
setup?.();
|
|
41
|
+
setStep(nextStep);
|
|
42
|
+
// Small delay to let React render the new content before fading in
|
|
43
|
+
requestAnimationFrame(() => {
|
|
44
|
+
setVisible(true);
|
|
45
|
+
setTransitioning(false);
|
|
46
|
+
});
|
|
47
|
+
}, 150);
|
|
48
|
+
}, []);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
return () => {
|
|
51
|
+
if (timeoutRef.current)
|
|
52
|
+
clearTimeout(timeoutRef.current);
|
|
53
|
+
};
|
|
54
|
+
}, []);
|
|
55
|
+
const handleAgentSelect = useCallback((agentType) => {
|
|
56
|
+
const group = groups.find((g) => g.agentType === agentType);
|
|
57
|
+
if (group && group.models.length > 0) {
|
|
58
|
+
transitionTo('select-model', () => {
|
|
59
|
+
setSelectedAgent(agentType);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
transitionTo('check-tool', () => {
|
|
64
|
+
setSelectedAgent(agentType);
|
|
65
|
+
setSelectedModel('');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}, [groups, transitionTo]);
|
|
69
|
+
const handleModelSelect = useCallback((model) => {
|
|
70
|
+
transitionTo('check-tool', () => {
|
|
71
|
+
setSelectedModel(model);
|
|
72
|
+
});
|
|
73
|
+
}, [transitionTo]);
|
|
74
|
+
const handleProceedToAuth = useCallback(() => {
|
|
75
|
+
transitionTo('authenticate');
|
|
76
|
+
}, [transitionTo]);
|
|
77
|
+
const handleBack = useCallback(() => {
|
|
78
|
+
if (step === 'select-model') {
|
|
79
|
+
transitionTo('select-agent', () => {
|
|
80
|
+
setSelectedAgent(null);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
else if (step === 'check-tool') {
|
|
84
|
+
if (activeGroup && activeGroup.models.length > 0) {
|
|
85
|
+
transitionTo('select-model', () => {
|
|
86
|
+
setSelectedModel(null);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
transitionTo('select-agent', () => {
|
|
91
|
+
setSelectedAgent(null);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (step === 'authenticate') {
|
|
96
|
+
// If tool needed install, go back to check-tool; otherwise skip to model/agent
|
|
97
|
+
if (toolStatus && !toolStatus.installed && toolStatus.toolId) {
|
|
98
|
+
transitionTo('check-tool');
|
|
99
|
+
}
|
|
100
|
+
else if (activeGroup && activeGroup.models.length > 0) {
|
|
101
|
+
transitionTo('select-model', () => {
|
|
102
|
+
setSelectedModel(null);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
transitionTo('select-agent', () => {
|
|
107
|
+
setSelectedAgent(null);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, [step, activeGroup, toolStatus, transitionTo]);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (step !== 'check-tool' || !selectedAgent)
|
|
114
|
+
return;
|
|
115
|
+
setCheckingTool(true);
|
|
116
|
+
checkAgentTool(selectedAgent)
|
|
117
|
+
.then((status) => {
|
|
118
|
+
setToolStatus(status);
|
|
119
|
+
// Auto-skip to authenticate when tool is already available or not required
|
|
120
|
+
if (status.installed || !status.toolId) {
|
|
121
|
+
transitionTo('authenticate');
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
.finally(() => setCheckingTool(false));
|
|
125
|
+
}, [step, selectedAgent, transitionTo]);
|
|
126
|
+
const handleConfirm = useCallback(async () => {
|
|
127
|
+
if (!selectedAgent)
|
|
128
|
+
return;
|
|
129
|
+
setSaving(true);
|
|
130
|
+
try {
|
|
131
|
+
await updateAgentAndModel(selectedAgent, selectedModel ?? null);
|
|
132
|
+
onComplete();
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
setSaving(false);
|
|
136
|
+
}
|
|
137
|
+
}, [selectedAgent, selectedModel, onComplete]);
|
|
138
|
+
if (loading) {
|
|
139
|
+
return (_jsxs("div", { "data-testid": "welcome-agent-setup", className: cn('flex flex-col items-center justify-center gap-3', className), children: [_jsx(Loader2, { className: "text-muted-foreground h-4 w-4 animate-spin" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Loading agents\u2026" })] }));
|
|
140
|
+
}
|
|
141
|
+
const stepIndex = STEPS.indexOf(step);
|
|
142
|
+
return (_jsxs("div", { "data-testid": "welcome-agent-setup", className: cn('flex flex-col items-center gap-4', WIZARD_WIDTH, className), children: [_jsx("div", { className: "flex flex-col items-center gap-1", children: _jsxs("div", { className: "text-muted-foreground flex items-center gap-2", children: [step === 'select-agent' && (_jsxs(_Fragment, { children: [_jsx(Bot, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-[10px] font-semibold tracking-widest uppercase", children: "Choose your agent" })] })), step === 'select-model' && activeGroup
|
|
143
|
+
? (() => {
|
|
144
|
+
const AgentIcon = getAgentTypeIcon(activeGroup.agentType);
|
|
145
|
+
return (_jsxs(_Fragment, { children: [_jsx(AgentIcon, { className: "h-3.5 w-3.5" }), _jsxs("span", { className: "text-[10px] font-semibold tracking-widest uppercase", children: [activeGroup.label, " \u2014 Pick a model"] })] }));
|
|
146
|
+
})()
|
|
147
|
+
: null, step === 'check-tool' && (_jsxs(_Fragment, { children: [_jsx(Bot, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-[10px] font-semibold tracking-widest uppercase", children: "Verifying setup" })] })), step === 'authenticate' && activeGroup
|
|
148
|
+
? (() => {
|
|
149
|
+
const AgentIcon = getAgentTypeIcon(activeGroup.agentType);
|
|
150
|
+
return (_jsxs(_Fragment, { children: [_jsx(AgentIcon, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-[10px] font-semibold tracking-widest uppercase", children: "Authenticate" })] }));
|
|
151
|
+
})()
|
|
152
|
+
: null] }) }), _jsx("div", { className: "flex w-32 items-center gap-1", children: STEPS.map((s, i) => (_jsx("div", { className: cn('h-0.5 flex-1 rounded-full transition-colors duration-300', i <= stepIndex ? 'bg-foreground/60' : 'bg-muted') }, s))) }), _jsxs("div", { className: cn('flex w-full flex-col items-center transition-opacity duration-150', visible && !transitioning ? 'opacity-100' : 'opacity-0'), children: [step === 'select-agent' && (_jsx("div", { "data-testid": "agent-list", className: "flex w-full flex-col gap-1.5", children: groups.map((group) => {
|
|
153
|
+
const GroupIcon = getAgentTypeIcon(group.agentType);
|
|
154
|
+
return (_jsxs("button", { type: "button", "data-testid": `agent-option-${group.agentType}`, className: "border-border hover:border-foreground/40 flex w-full cursor-pointer items-center gap-2.5 rounded-md border border-dashed px-4 py-2.5 transition-colors", onClick: () => handleAgentSelect(group.agentType), children: [_jsx(GroupIcon, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx("span", { className: "flex-1 text-left text-xs font-medium", children: group.label }), _jsx(ChevronRight, { className: "text-muted-foreground h-3 w-3" })] }, group.agentType));
|
|
155
|
+
}) })), step === 'select-model' && activeGroup ? (_jsxs("div", { "data-testid": "model-list", className: "flex w-full flex-col gap-1.5", children: [_jsxs("button", { type: "button", className: "text-muted-foreground hover:text-foreground mb-0.5 flex cursor-pointer items-center gap-1 self-start text-[10px] font-medium transition-colors", onClick: handleBack, children: [_jsx(ChevronLeft, { className: "h-3 w-3" }), "Back"] }), _jsx("div", { className: "flex max-h-48 w-full flex-col gap-1.5 overflow-y-auto", children: activeGroup.models.map((m) => {
|
|
156
|
+
const meta = getModelMeta(m.id);
|
|
157
|
+
return (_jsxs("button", { type: "button", "data-testid": `model-option-${m.id}`, className: "border-border hover:border-foreground/40 flex w-full cursor-pointer items-center gap-2.5 rounded-md border border-dashed px-4 py-2.5 text-left transition-colors", onClick: () => handleModelSelect(m.id), children: [_jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("span", { className: "text-xs font-medium", children: meta.displayName || m.displayName }), _jsx("span", { className: "text-muted-foreground text-[10px] leading-tight", children: meta.description || m.description })] }), _jsx(ChevronRight, { className: "text-muted-foreground h-3 w-3 shrink-0" })] }, m.id));
|
|
158
|
+
}) })] })) : null, step === 'check-tool' && (_jsx(ToolCheckStep, { toolStatus: toolStatus, checking: checkingTool, saving: false, onConfirm: handleProceedToAuth, onBack: handleBack, onToolInstalled: () => {
|
|
159
|
+
if (selectedAgent) {
|
|
160
|
+
setCheckingTool(true);
|
|
161
|
+
checkAgentTool(selectedAgent)
|
|
162
|
+
.then(setToolStatus)
|
|
163
|
+
.finally(() => setCheckingTool(false));
|
|
164
|
+
}
|
|
165
|
+
} })), step === 'authenticate' && toolStatus ? (_jsx(AuthenticateStep, { toolStatus: toolStatus, agentLabel: activeGroup?.label ?? selectedAgent ?? 'Agent', saving: saving, onConfirm: handleConfirm, onBack: handleBack })) : null] })] }));
|
|
166
|
+
}
|
|
167
|
+
/** Sub-component for the tool verification step */
|
|
168
|
+
function ToolCheckStep({ toolStatus, checking, saving, onConfirm, onBack, onToolInstalled, }) {
|
|
169
|
+
if (checking || !toolStatus) {
|
|
170
|
+
return (_jsxs("div", { className: "flex flex-col items-center gap-2 py-4", children: [_jsx(Loader2, { className: "text-muted-foreground h-4 w-4 animate-spin" }), _jsx("p", { className: "text-muted-foreground text-[10px]", children: "Checking tool availability\u2026" })] }));
|
|
171
|
+
}
|
|
172
|
+
// Agent doesn't require a tool (e.g., dev/demo)
|
|
173
|
+
if (!toolStatus.toolId) {
|
|
174
|
+
return (_jsxs("div", { className: "flex w-full flex-col items-center gap-3", children: [_jsxs("div", { className: "text-muted-foreground flex items-center gap-1.5", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-xs", children: "No additional tools required" })] }), _jsx(ConfirmRow, { saving: saving, onConfirm: onConfirm, onBack: onBack })] }));
|
|
175
|
+
}
|
|
176
|
+
if (toolStatus.installed) {
|
|
177
|
+
return (_jsxs("div", { className: "flex w-full flex-col items-center gap-3", children: [_jsxs("div", { className: "text-muted-foreground flex items-center gap-1.5", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5" }), _jsxs("span", { className: "text-xs", children: [toolStatus.tool?.name ?? toolStatus.toolId, " is installed"] })] }), _jsx(ConfirmRow, { saving: saving, onConfirm: onConfirm, onBack: onBack })] }));
|
|
178
|
+
}
|
|
179
|
+
return (_jsx(ToolInstallInline, { toolStatus: toolStatus, saving: saving, onConfirm: onConfirm, onBack: onBack, onInstalled: onToolInstalled }));
|
|
180
|
+
}
|
|
181
|
+
/** Shared back + continue row */
|
|
182
|
+
function ConfirmRow({ saving, onConfirm, onBack, label = 'Continue', }) {
|
|
183
|
+
return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("button", { type: "button", className: "text-muted-foreground hover:text-foreground cursor-pointer text-[10px] transition-colors", onClick: onBack, children: [_jsx(ChevronLeft, { className: "mr-0.5 inline h-3 w-3" }), "Back"] }), _jsxs("button", { type: "button", "data-testid": "agent-setup-confirm", disabled: saving, className: "border-border hover:border-foreground/40 flex cursor-pointer items-center gap-1.5 rounded-md border border-dashed px-4 py-2 text-xs font-medium transition-colors disabled:opacity-50", onClick: onConfirm, children: [saving ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : _jsx(Check, { className: "h-3 w-3" }), label] })] }));
|
|
184
|
+
}
|
|
185
|
+
/** Authenticate step — optional agent launch for auth */
|
|
186
|
+
function AuthenticateStep({ toolStatus, agentLabel, saving, onConfirm, onBack, }) {
|
|
187
|
+
const [launching, setLaunching] = useState(false);
|
|
188
|
+
const [launched, setLaunched] = useState(false);
|
|
189
|
+
const handleLaunch = useCallback(async () => {
|
|
190
|
+
if (!toolStatus.toolId)
|
|
191
|
+
return;
|
|
192
|
+
setLaunching(true);
|
|
193
|
+
try {
|
|
194
|
+
const res = await fetch(`/api/tools/${toolStatus.toolId}/launch`, { method: 'POST' });
|
|
195
|
+
if (res.ok)
|
|
196
|
+
setLaunched(true);
|
|
197
|
+
}
|
|
198
|
+
finally {
|
|
199
|
+
setLaunching(false);
|
|
200
|
+
}
|
|
201
|
+
}, [toolStatus.toolId]);
|
|
202
|
+
// No tool = no auth needed, skip straight to confirm
|
|
203
|
+
if (!toolStatus.toolId) {
|
|
204
|
+
return (_jsxs("div", { className: "flex w-full flex-col items-center gap-3", children: [_jsx("p", { className: "text-muted-foreground text-[10px]", children: "No authentication required" }), _jsx(ConfirmRow, { saving: saving, onConfirm: onConfirm, onBack: onBack, label: "Done" })] }));
|
|
205
|
+
}
|
|
206
|
+
return (_jsxs("div", { className: "flex w-full flex-col items-center gap-3", children: [_jsxs("p", { className: "text-muted-foreground text-center text-[10px] leading-relaxed", children: ["Open ", agentLabel, " in a terminal to sign in.", _jsx("br", {}), "Follow the prompts, then come back here."] }), _jsxs("button", { type: "button", "data-testid": "agent-setup-launch", disabled: launching, onClick: handleLaunch, className: "border-border hover:border-foreground/40 flex w-full cursor-pointer items-center gap-2.5 rounded-md border border-dashed px-4 py-2.5 transition-colors disabled:opacity-50", children: [launching ? (_jsx(Loader2, { className: "text-muted-foreground h-4 w-4 animate-spin" })) : (_jsx(Terminal, { className: "text-muted-foreground h-4 w-4" })), _jsx("span", { className: "flex-1 text-left text-xs font-medium", children: launched ? 'Open again' : `Open ${agentLabel}` }), _jsx(ExternalLink, { className: "text-muted-foreground h-3 w-3" })] }), launched ? (_jsx("p", { className: "text-muted-foreground text-[10px]", children: "Terminal opened \u2014 complete sign-in there" })) : null, toolStatus.binaryName ? (_jsxs("div", { className: "flex w-full flex-col gap-1", children: [_jsx("p", { className: "text-muted-foreground text-[10px]", children: "Or run manually in any terminal:" }), _jsxs("div", { className: "w-full rounded-md bg-zinc-900 px-3 py-1.5 font-mono text-[11px] text-zinc-300", children: [_jsx("span", { className: "text-zinc-500 select-none", children: "$ " }), toolStatus.binaryName] })] })) : null, _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("button", { type: "button", className: "text-muted-foreground hover:text-foreground cursor-pointer text-[10px] transition-colors", onClick: onBack, children: [_jsx(ChevronLeft, { className: "mr-0.5 inline h-3 w-3" }), "Back"] }), _jsxs("button", { type: "button", "data-testid": "agent-setup-confirm", disabled: saving, className: "border-border hover:border-foreground/40 flex cursor-pointer items-center gap-1.5 rounded-md border border-dashed px-4 py-2 text-xs font-medium transition-colors disabled:opacity-50", onClick: onConfirm, children: [saving ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : _jsx(Check, { className: "h-3 w-3" }), launched ? 'Done' : 'Skip'] })] })] }));
|
|
207
|
+
}
|
|
208
|
+
/** Inline tool installer for the welcome wizard */
|
|
209
|
+
function ToolInstallInline({ toolStatus, saving, onConfirm, onBack, onInstalled, }) {
|
|
210
|
+
const toolId = toolStatus.toolId ?? '';
|
|
211
|
+
const { logs, status, startInstall } = useToolInstallStream(toolId);
|
|
212
|
+
const isInstallDone = status === 'done';
|
|
213
|
+
const isInstallError = status === 'error';
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
if (isInstallDone) {
|
|
216
|
+
onInstalled();
|
|
217
|
+
}
|
|
218
|
+
}, [isInstallDone, onInstalled]);
|
|
219
|
+
return (_jsxs("div", { className: "flex w-full flex-col items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [isInstallDone ? (_jsx(CheckCircle2, { className: "text-muted-foreground h-3.5 w-3.5" })) : isInstallError ? (_jsx(AlertCircle, { className: "text-destructive h-3.5 w-3.5" })) : (_jsx(Circle, { className: "text-muted-foreground h-3.5 w-3.5" })), _jsxs("span", { className: "text-xs", children: [toolStatus.tool?.name ?? toolId, ' ', isInstallDone ? 'installed' : isInstallError ? 'install failed' : 'is not installed'] })] }), toolStatus.tool?.installCommand && status === 'idle' ? (_jsxs("div", { className: "w-full rounded-md bg-zinc-900 px-3 py-2 font-mono text-[11px] text-zinc-300", children: [_jsx("span", { className: "text-zinc-500 select-none", children: "$ " }), toolStatus.tool.installCommand] })) : null, (status === 'streaming' || isInstallDone || isInstallError) && logs.length > 0 ? (_jsxs("div", { className: "max-h-28 w-full overflow-auto rounded-md bg-zinc-900 px-3 py-2 font-mono text-[10px] leading-relaxed text-zinc-400", children: [logs.map((line, idx) => (
|
|
220
|
+
// eslint-disable-next-line react/no-array-index-key -- logs are append-only, never reorder
|
|
221
|
+
_jsx("div", { className: "break-all whitespace-pre-wrap", children: line }, idx))), isInstallDone ? (_jsx("div", { className: "text-muted-foreground mt-1", children: "Installation complete" })) : null, isInstallError ? (_jsx("div", { className: "text-destructive mt-1", children: "Installation failed \u2014 try manually" })) : null] })) : null, _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("button", { type: "button", className: "text-muted-foreground hover:text-foreground cursor-pointer text-[10px] transition-colors", onClick: onBack, children: [_jsx(ChevronLeft, { className: "mr-0.5 inline h-3 w-3" }), "Back"] }), !isInstallDone && toolStatus.tool?.autoInstall ? (_jsxs("button", { type: "button", "data-testid": "agent-setup-install", disabled: status === 'streaming', className: "border-border hover:border-foreground/40 flex cursor-pointer items-center gap-1.5 rounded-md border border-dashed px-4 py-2 text-xs font-medium transition-colors disabled:opacity-50", onClick: startInstall, children: [status === 'streaming' ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin" })) : (_jsx(Download, { className: "h-3 w-3" })), status === 'streaming' ? 'Installing…' : 'Install'] })) : null, isInstallDone ? (_jsxs("button", { type: "button", "data-testid": "agent-setup-confirm", disabled: saving, className: "border-border hover:border-foreground/40 flex cursor-pointer items-center gap-1.5 rounded-md border border-dashed px-4 py-2 text-xs font-medium transition-colors disabled:opacity-50", onClick: onConfirm, children: [saving ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : _jsx(Check, { className: "h-3 w-3" }), "Continue"] })) : null] })] }));
|
|
222
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { WelcomeAgentSetup } from './welcome-agent-setup.js';
|
|
3
|
+
declare const meta: Meta<typeof WelcomeAgentSetup>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof meta>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
//# sourceMappingURL=welcome-agent-setup.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"welcome-agent-setup.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/welcome-agent-setup.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,iBAAiB,CAcxC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAIrB,CAAC"}
|
package/dist/src/presentation/web/components/features/control-center/welcome-agent-setup.stories.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
import { WelcomeAgentSetup } from './welcome-agent-setup.js';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Features/WelcomeAgentSetup',
|
|
6
|
+
component: WelcomeAgentSetup,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
},
|
|
11
|
+
decorators: [
|
|
12
|
+
(Story) => (_jsx("div", { style: { width: 480, padding: 48, display: 'flex', justifyContent: 'center' }, children: _jsx(Story, {}) })),
|
|
13
|
+
],
|
|
14
|
+
};
|
|
15
|
+
export default meta;
|
|
16
|
+
export const Default = {
|
|
17
|
+
args: {
|
|
18
|
+
onComplete: fn(),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -29,7 +29,7 @@ function AppShellInner({ children }) {
|
|
|
29
29
|
const handleRepositorySelect = useCallback((path) => {
|
|
30
30
|
window.dispatchEvent(new CustomEvent('shep:add-repository', { detail: { path } }));
|
|
31
31
|
}, []);
|
|
32
|
-
return (_jsxs(SidebarProvider, { children: [_jsx(AppSidebar, { features: features, featureFlags: featureFlags, onNewFeature: handleNewFeature, onFeatureClick: handleFeatureClick }), _jsx(SidebarInset, { children: _jsxs("div", { className: "relative h-full", children: [_jsxs("div", { className: "absolute top-3 right-3 z-50 flex gap-1", children: [_jsx(AddRepositoryButton, { onSelect: handleRepositorySelect }), _jsx(SoundToggle, {}), _jsx(ThemeToggle, {})] }), _jsx("main", { className: "h-full", children: children })] }) })] }));
|
|
32
|
+
return (_jsxs(SidebarProvider, { defaultOpen: false, children: [_jsx(AppSidebar, { features: features, featureFlags: featureFlags, onNewFeature: handleNewFeature, onFeatureClick: handleFeatureClick }), _jsx(SidebarInset, { children: _jsxs("div", { className: "relative h-full", children: [_jsxs("div", { className: "absolute top-3 right-3 z-50 flex gap-1", children: [_jsx(AddRepositoryButton, { onSelect: handleRepositorySelect }), _jsx(SoundToggle, {}), _jsx(ThemeToggle, {})] }), _jsx("main", { className: "h-full", children: children })] }) })] }));
|
|
33
33
|
}
|
|
34
34
|
export function AppShell({ children }) {
|
|
35
35
|
return (_jsx(AgentEventsProvider, { children: _jsx(DrawerCloseGuardProvider, { children: _jsx(SidebarFeaturesProvider, { children: _jsx(AppShellInner, { children: children }) }) }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar-features-context.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/sidebar-features-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4DAA4D,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAI/E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"sidebar-features-context.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/sidebar-features-context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4DAA4D,CAAC;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAI/E,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAgBD;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,gBAAgB,GAAG,aAAa,GAAG,IAAI,CAEzF;AAMD,UAAU,2BAA2B;IACnC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,WAAW,EAAE,CAAC,QAAQ,EAAE,kBAAkB,EAAE,KAAK,IAAI,CAAC;CACvD;AAID,UAAU,4BAA4B;IACpC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,EAAE,4BAA4B,2CAQjF;AAED,wBAAgB,yBAAyB,IAAI,2BAA2B,CAMvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-graph-state.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-graph-state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,mDAAmD;IACnD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd;;;OAGG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAClE,uEAAuE;IACvE,aAAa,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC5E,kEAAkE;IAClE,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1F,yDAAyD;IACzD,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sDAAsD;IACtD,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,uDAAuD;IACvD,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC9D,2DAA2D;IAC3D,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAClE,gCAAgC;IAChC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,yDAAyD;IACzD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACtF,gEAAgE;IAChE,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,yDAAyD;IACzD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,+EAA+E;IAC/E,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,6EAA6E;IAC7E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAuCD,KAAK,kBAAkB,GAAG,OAAO,CAC/B,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,aAAa,CAAC,CACtE,CAAC;AAWF,wBAAgB,aAAa,CAC3B,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"use-graph-state.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-graph-state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,mDAAmD;IACnD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd;;;OAGG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAClE,uEAAuE;IACvE,aAAa,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC5E,kEAAkE;IAClE,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1F,yDAAyD;IACzD,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sDAAsD;IACtD,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,uDAAuD;IACvD,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC9D,2DAA2D;IAC3D,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAClE,gCAAgC;IAChC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,yDAAyD;IACzD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACtF,gEAAgE;IAChE,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,yDAAyD;IACzD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,+EAA+E;IAC/E,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,6EAA6E;IAC7E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAuCD,KAAK,kBAAkB,GAAG,OAAO,CAC/B,IAAI,CAAC,eAAe,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,aAAa,CAAC,CACtE,CAAC;AAWF,wBAAgB,aAAa,CAC3B,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,mBAAmB,CAgTrB"}
|
|
@@ -45,6 +45,10 @@ export function useGraphState(initialNodes, initialEdges) {
|
|
|
45
45
|
// Buffer for SSE updates that arrive before their feature is in featureMap.
|
|
46
46
|
// When reconcile adds new features, buffered updates are applied automatically.
|
|
47
47
|
const pendingUpdatesRef = useRef(new Map());
|
|
48
|
+
// Track 'deleting' features that the server no longer returns.
|
|
49
|
+
// Retained for one extra reconcile cycle so the user sees the deleting state
|
|
50
|
+
// before the node disappears from the canvas.
|
|
51
|
+
const deletingRetainedRef = useRef(new Set());
|
|
48
52
|
// Callbacks stored in a ref so changing them doesn't trigger re-render.
|
|
49
53
|
// The stable wrapper object reads from the ref so node closures always use latest callbacks.
|
|
50
54
|
const callbacksRef = useRef({});
|
|
@@ -113,6 +117,29 @@ export function useGraphState(initialNodes, initialEdges) {
|
|
|
113
117
|
merged.set(tempId, pendingEntry);
|
|
114
118
|
}
|
|
115
119
|
}
|
|
120
|
+
// Preserve 'deleting' state for features being deleted.
|
|
121
|
+
// If the server still returns the feature, override its state to 'deleting'.
|
|
122
|
+
// If the server no longer returns it (soft-deleted), retain it for one
|
|
123
|
+
// extra reconcile cycle so the user sees the deleting animation.
|
|
124
|
+
const nextRetained = new Set();
|
|
125
|
+
for (const [id, entry] of currentFeatureMap) {
|
|
126
|
+
if (entry.data.state === 'deleting') {
|
|
127
|
+
if (merged.has(id)) {
|
|
128
|
+
// Server still has it — override state to keep showing 'deleting'
|
|
129
|
+
merged.set(id, {
|
|
130
|
+
...merged.get(id),
|
|
131
|
+
data: { ...merged.get(id).data, state: 'deleting' },
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
else if (!deletingRetainedRef.current.has(id)) {
|
|
135
|
+
// First reconcile after server removal — retain with deleting state
|
|
136
|
+
merged.set(id, entry);
|
|
137
|
+
nextRetained.add(id);
|
|
138
|
+
}
|
|
139
|
+
// else: already retained once — let it disappear
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
deletingRetainedRef.current = nextRetained;
|
|
116
143
|
// Apply any buffered SSE updates to features that now exist in the map
|
|
117
144
|
for (const [nodeId, updates] of pendingUpdatesRef.current) {
|
|
118
145
|
const entry = merged.get(nodeId);
|