@burdenoff/microfe-vibecontrols 2026.520.3 → 2026.521.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/dist/VibeControlsRoot.js +82 -76
- package/dist/VibeControlsRoot.js.map +1 -1
- package/dist/VibeControlsRoutes.js +50 -46
- package/dist/VibeControlsRoutes.js.map +1 -1
- package/dist/components/gitops/VibeGitOpsTab.js +33 -33
- package/dist/components/plugins/AddTabDialog.js +224 -0
- package/dist/components/plugins/AddTabDialog.js.map +1 -0
- package/dist/components/plugins/PluginIframeMount.js +134 -0
- package/dist/components/plugins/PluginIframeMount.js.map +1 -0
- package/dist/pages/AgentDetailsPage.js +830 -730
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/PluginStandalonePage.js +145 -0
- package/dist/pages/PluginStandalonePage.js.map +1 -0
- package/dist/pages/VibeDetailsPage.js +677 -579
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/services/iframeToken.js +10 -3
- package/dist/services/iframeToken.js.map +1 -1
- package/dist/store/vibeControlsStore.js +35 -2
- package/dist/store/vibeControlsStore.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeControlsRoutes.js","names":[],"sources":["../src/VibeControlsRoutes.tsx"],"sourcesContent":["import React, { Suspense, useEffect } from 'react';\nimport { Navigate, Route, Routes, useLocation } from 'react-router-dom';\nimport { FeatureGate } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useTr } from './shared/hooks/useTr';\n\n// Lazy load - All pages (required for @/ alias resolution when consumed by host app)\nconst OverviewPage = React.lazy(() =>\n import('./pages/OverviewPage').then((m) => ({ default: m.OverviewPage }))\n);\n\n// Other pages\nconst AgentsLandingPage = React.lazy(() =>\n import('./pages/AgentsLandingPage').then((m) => ({ default: m.AgentsLandingPage }))\n);\nconst AgentDetailsPage = React.lazy(() =>\n import('./pages/AgentDetailsPage').then((m) => ({ default: m.AgentDetailsPage }))\n);\nconst TargetDetailsPage = React.lazy(() =>\n import('./pages/TargetDetailsPage').then((m) => ({ default: m.TargetDetailsPage }))\n);\nconst SessionsPage = React.lazy(() =>\n import('./pages/SessionsPage').then((m) => ({ default: m.SessionsPage }))\n);\nconst SessionDetailsPage = React.lazy(() =>\n import('./pages/SessionDetailsPage').then((m) => ({ default: m.SessionDetailsPage }))\n);\nconst VibesPage = React.lazy(() =>\n import('./pages/VibesPage').then((m) => ({ default: m.VibesPage }))\n);\nconst VibeDetailsPage = React.lazy(() =>\n import('./pages/VibeDetailsPage').then((m) => ({ default: m.VibeDetailsPage }))\n);\nconst NoteDetailsPage = React.lazy(() =>\n import('./pages/NoteDetailsPage').then((m) => ({ default: m.NoteDetailsPage }))\n);\nconst TunnelsLandingPage = React.lazy(() =>\n import('./pages/TunnelsLandingPage').then((m) => ({ default: m.TunnelsLandingPage }))\n);\nconst TunnelDetailsPage = React.lazy(() =>\n import('./pages/tunnels/TunnelDetailsPage').then((m) => ({ default: m.TunnelDetailsPage }))\n);\nconst TunnelCreateWizard = React.lazy(() =>\n import('./components/tunnels/TunnelCreateWizard').then((m) => ({ default: m.TunnelCreateWizard }))\n);\nconst SettingsPage = React.lazy(() =>\n import('./pages/SettingsPage').then((m) => ({ default: m.SettingsPage }))\n);\nconst HealthPage = React.lazy(() =>\n import('./pages/HealthPage').then((m) => ({ default: m.HealthPage }))\n);\nconst GettingStartedPage = React.lazy(() =>\n import('./pages/GettingStartedPage').then((m) => ({ default: m.GettingStartedPage }))\n);\nconst SharedSessionPage = React.lazy(() =>\n import('./pages/SharedSessionPage').then((m) => ({ default: m.SharedSessionPage }))\n);\nconst VibeDeckPage = React.lazy(() =>\n import('./pages/VibeDeckPage').then((m) => ({ default: m.VibeDeckPage }))\n);\nconst SharedVibeDeckPage = React.lazy(() =>\n import('./pages/SharedVibeDeckPage').then((m) => ({ default: m.SharedVibeDeckPage }))\n);\nconst VibeCalendarPage = React.lazy(() =>\n import('./pages/VibeCalendarPage').then((m) => ({ default: m.VibeCalendarPage }))\n);\nconst VibeTaskDetailPage = React.lazy(() =>\n import('./pages/VibeTaskDetailPage').then((m) => ({ default: m.VibeTaskDetailPage }))\n);\nconst ActionsPage = React.lazy(() =>\n import('./pages/ActionsPage').then((m) => ({ default: m.ActionsPage }))\n);\nconst VibeAuditPage = React.lazy(() =>\n import('./pages/VibeAuditPage').then((m) => ({ default: m.VibeAuditPage }))\n);\nconst AnalyticsPage = React.lazy(() =>\n import('./pages/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage }))\n);\nconst VibeDocsPage = React.lazy(() =>\n import('./pages/VibeDocsPage').then((m) => ({ default: m.VibeDocsPage }))\n);\n\n// Catalog, Components, Templates pages\nconst CatalogPage = React.lazy(() =>\n import('./pages/CatalogPage').then((m) => ({ default: m.CatalogPage }))\n);\nconst CatalogDetailPage = React.lazy(() =>\n import('./pages/CatalogDetailPage').then((m) => ({ default: m.CatalogDetailPage }))\n);\nconst CatalogDocsPage = React.lazy(() =>\n import('./pages/CatalogDocsPage').then((m) => ({ default: m.CatalogDocsPage }))\n);\nconst ComponentsPage = React.lazy(() =>\n import('./pages/ComponentsPage').then((m) => ({ default: m.ComponentsPage }))\n);\nconst ComponentDetailPage = React.lazy(() =>\n import('./pages/ComponentDetailPage').then((m) => ({ default: m.ComponentDetailPage }))\n);\nconst ComponentDocsPage = React.lazy(() =>\n import('./pages/ComponentDocsPage').then((m) => ({ default: m.ComponentDocsPage }))\n);\nconst TemplatesPage = React.lazy(() =>\n import('./pages/TemplatesPage').then((m) => ({ default: m.TemplatesPage }))\n);\nconst TemplateDetailPage = React.lazy(() =>\n import('./pages/TemplateDetailPage').then((m) => ({ default: m.TemplateDetailPage }))\n);\n\n// AI pages\nconst AIPage = React.lazy(() => import('./pages/ai/AIPage').then((m) => ({ default: m.AIPage })));\nconst AISessionDetailPage = React.lazy(() =>\n import('./pages/ai/AISessionDetailPage').then((m) => ({ default: m.AISessionDetailPage }))\n);\nconst AgentManagerPage = React.lazy(() =>\n import('./pages/ai/AgentManagerPage').then((m) => ({ default: m.AgentManagerPage }))\n);\n\n// Loading fallback component\nfunction PageLoadingFallback() {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[200px]\">\n <div className=\"animate-pulse bg-muted rounded w-full h-full\" />\n </div>\n );\n}\n\n/**\n * Internal router for the VibeControls microfrontend.\n * This component handles routing within the microfrontend using React Router v7.\n *\n * Routes:\n * - / → Overview page (dashboard)\n * - /agents → Agents management page\n * - /agents/:id → Agent details page\n * - /sessions → Sessions management page\n * - /sessions/:id → Session details page\n * - /vibes → Vibes (projects) management page\n * - /vibes/:id → Vibe details page (includes Notes tab)\n * - /settings → Settings page\n * - /webhooks → Legacy redirect to Developer Portal webhooks\n * - /health → Health monitoring page\n * - /* → Catch-all redirects to overview\n */\nfunction ScrollToTop() {\n const { pathname } = useLocation();\n useEffect(() => {\n // The scrollable container is the <main> element with overflow-auto\n // inside AppShellLayout, not the window itself.\n const main = document.querySelector('main');\n if (main) main.scrollTop = 0;\n }, [pathname]);\n return null;\n}\n\n/**\n * Fallback shown when a feature flag is OFF.\n */\nfunction FeatureDisabledFallback() {\n const tr = useTr();\n return (\n <div className=\"flex items-center justify-center h-full min-h-[200px] text-text-secondary text-sm\">\n {tr(\n 'vibecontrols.pages.featureDisabled',\n 'This feature is currently disabled. You can enable it from Feature Previews.'\n )}\n </div>\n );\n}\n\n/**\n * Helper: wraps a page element in a FeatureGate.\n * defaultValue={true} means the feature shows by default (before flags are seeded).\n * Only hides when a flag is explicitly set to false.\n */\nfunction gated(flag: string, element: React.ReactNode, defaultValue = true): React.ReactElement {\n return (\n <FeatureGate flag={flag} defaultValue={defaultValue} fallback={<FeatureDisabledFallback />}>\n {element}\n </FeatureGate>\n );\n}\n\nexport function VibeControlsRoutes() {\n return (\n <Suspense fallback={<PageLoadingFallback />}>\n <ScrollToTop />\n <Routes>\n {/* Default route - overview page */}\n <Route index element={gated('vibecontrols.overview', <OverviewPage />)} />\n\n {/* Core pages */}\n <Route path=\"agents\" element={gated('vibecontrols.agents', <AgentsLandingPage />)} />\n <Route path=\"agents/:id\" element={gated('vibecontrols.agents', <AgentDetailsPage />)} />\n <Route path=\"sessions\" element={gated('vibecontrols.sessions', <SessionsPage />)} />\n <Route path=\"vibes\" element={gated('vibecontrols.vibes', <VibesPage />)} />\n <Route path=\"vibes/:id\" element={gated('vibecontrols.vibes', <VibeDetailsPage />)} />\n <Route path=\"vibes/:id/docs/*\" element={gated('vibecontrols.vibes', <VibeDocsPage />)} />\n <Route path=\"notes/:id\" element={gated('vibecontrols.vibes', <NoteDetailsPage />)} />\n <Route\n path=\"sessions/:id\"\n element={gated('vibecontrols.sessions', <SessionDetailsPage />)}\n />\n {/* Agent Manager — multi-session tabbed UI (replaces old AI page) */}\n <Route path=\"ai\" element={gated('vibecontrols.ai', <AgentManagerPage />)} />\n <Route path=\"ai/:tab\" element={gated('vibecontrols.ai', <AgentManagerPage />)} />\n <Route\n path=\"ai/sessions/:sessionId\"\n element={gated('vibecontrols.ai', <AgentManagerPage />)}\n />\n {/* AI Tools — templates, contexts, prompts, stats, playground */}\n <Route path=\"ai-tools\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route path=\"ai-tools/:tab\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route\n path=\"ai-tools/sessions/:sessionId\"\n element={gated('vibecontrols.ai', <AISessionDetailPage />)}\n />\n\n {/* Targets list lives in the Targets & Agents landing; per-target\n detail is its own page (mirrors agents/:id). */}\n <Route path=\"targets\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n <Route path=\"targets/:id\" element={gated('vibecontrols.agents', <TargetDetailsPage />)} />\n {/* Agent Graph is also a tab inside the Targets & Agents landing. */}\n <Route path=\"agent-graph\" element={<Navigate to=\"../agents?tab=graph\" replace />} />\n\n {/* Catalog */}\n <Route path=\"catalogs\" element={gated('vibecontrols.catalogs', <CatalogPage />)} />\n <Route\n path=\"catalogs/:id\"\n element={gated('vibecontrols.catalogs', <CatalogDetailPage />)}\n />\n <Route\n path=\"catalogs/:id/docs/*\"\n element={gated('vibecontrols.catalogs', <CatalogDocsPage />)}\n />\n <Route path=\"components\" element={gated('vibecontrols.components', <ComponentsPage />)} />\n <Route\n path=\"components/:id\"\n element={gated('vibecontrols.components', <ComponentDetailPage />)}\n />\n <Route\n path=\"components/:id/docs/*\"\n element={gated('vibecontrols.components', <ComponentDocsPage />)}\n />\n <Route path=\"templates\" element={gated('vibecontrols.templates', <TemplatesPage />)} />\n <Route\n path=\"templates/:id\"\n element={gated('vibecontrols.templates', <TemplateDetailPage />)}\n />\n\n {/* Automation */}\n <Route path=\"actions\" element={gated('vibecontrols.actions', <ActionsPage />)} />\n <Route path=\"vibedeck\" element={gated('vibecontrols.vibedeck', <VibeDeckPage />)} />\n <Route path=\"calendar\" element={gated('vibecontrols.calendar', <VibeCalendarPage />)} />\n <Route\n path=\"calendar/:viewType\"\n element={gated('vibecontrols.calendar', <VibeCalendarPage />)}\n />\n <Route\n path=\"calendar/task/:taskId\"\n element={gated('vibecontrols.calendar', <VibeTaskDetailPage />)}\n />\n <Route path=\"webhooks\" element={<Navigate to=\"/devportal/webhooks\" replace />} />\n <Route path=\"webhooks/new\" element={<Navigate to=\"/devportal/webhooks/new\" replace />} />\n <Route path=\"webhooks/:id\" element={<Navigate to=\"/devportal/webhooks\" replace />} />\n {/* GitOps consolidated into Vibe detail tab — old /gitops routes redirect to vibes list. */}\n <Route path=\"gitops\" element={<Navigate to=\"../vibes\" replace />} />\n <Route path=\"gitops/:tab\" element={<Navigate to=\"../vibes\" replace />} />\n\n {/* Infrastructure */}\n <Route path=\"tunnels\" element={gated('vibecontrols.tunnels', <TunnelsLandingPage />)} />\n <Route path=\"tunnels/new\" element={gated('vibecontrols.tunnels', <TunnelCreateWizard />)} />\n <Route\n path=\"tunnels/:tunnelId\"\n element={gated('vibecontrols.tunnels', <TunnelDetailsPage />)}\n />\n\n {/* Insights */}\n <Route path=\"health\" element={gated('vibecontrols.health', <HealthPage />)} />\n <Route path=\"analytics\" element={gated('vibecontrols.analytics', <AnalyticsPage />)} />\n <Route path=\"audit\" element={gated('vibecontrols.audit-log', <VibeAuditPage />, false)} />\n <Route path=\"logs\" element={<Navigate to=\"/vibecontrols/agents\" replace />} />\n\n {/* Settings */}\n <Route path=\"settings\" element={gated('vibecontrols.settings', <SettingsPage />)} />\n\n {/* Setup */}\n {/* Not gated — onboarding flow must always be reachable */}\n <Route path=\"getting-started\" element={<GettingStartedPage />} />\n\n {/* Shared public routes (no gating — accessible via public links) */}\n <Route path=\"share/:token\" element={<SharedSessionPage />} />\n <Route path=\"deck/:token\" element={<SharedVibeDeckPage />} />\n\n {/* Legacy redirects */}\n <Route path=\"access\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n <Route path=\"ssh-targets\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n <Route path=\"ssh-terminals\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n\n {/* Catch-all route - redirect to overview */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"VibeControlsRoutes.js","names":[],"sources":["../src/VibeControlsRoutes.tsx"],"sourcesContent":["import React, { Suspense, useEffect } from 'react';\nimport { Navigate, Route, Routes, useLocation } from 'react-router-dom';\nimport { FeatureGate } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useTr } from './shared/hooks/useTr';\n\n// Lazy load - All pages (required for @/ alias resolution when consumed by host app)\nconst OverviewPage = React.lazy(() =>\n import('./pages/OverviewPage').then((m) => ({ default: m.OverviewPage }))\n);\n\n// Other pages\nconst AgentsLandingPage = React.lazy(() =>\n import('./pages/AgentsLandingPage').then((m) => ({ default: m.AgentsLandingPage }))\n);\nconst AgentDetailsPage = React.lazy(() =>\n import('./pages/AgentDetailsPage').then((m) => ({ default: m.AgentDetailsPage }))\n);\nconst TargetDetailsPage = React.lazy(() =>\n import('./pages/TargetDetailsPage').then((m) => ({ default: m.TargetDetailsPage }))\n);\nconst SessionsPage = React.lazy(() =>\n import('./pages/SessionsPage').then((m) => ({ default: m.SessionsPage }))\n);\nconst SessionDetailsPage = React.lazy(() =>\n import('./pages/SessionDetailsPage').then((m) => ({ default: m.SessionDetailsPage }))\n);\nconst VibesPage = React.lazy(() =>\n import('./pages/VibesPage').then((m) => ({ default: m.VibesPage }))\n);\nconst VibeDetailsPage = React.lazy(() =>\n import('./pages/VibeDetailsPage').then((m) => ({ default: m.VibeDetailsPage }))\n);\nconst NoteDetailsPage = React.lazy(() =>\n import('./pages/NoteDetailsPage').then((m) => ({ default: m.NoteDetailsPage }))\n);\nconst TunnelsLandingPage = React.lazy(() =>\n import('./pages/TunnelsLandingPage').then((m) => ({ default: m.TunnelsLandingPage }))\n);\nconst TunnelDetailsPage = React.lazy(() =>\n import('./pages/tunnels/TunnelDetailsPage').then((m) => ({ default: m.TunnelDetailsPage }))\n);\nconst TunnelCreateWizard = React.lazy(() =>\n import('./components/tunnels/TunnelCreateWizard').then((m) => ({ default: m.TunnelCreateWizard }))\n);\nconst SettingsPage = React.lazy(() =>\n import('./pages/SettingsPage').then((m) => ({ default: m.SettingsPage }))\n);\nconst HealthPage = React.lazy(() =>\n import('./pages/HealthPage').then((m) => ({ default: m.HealthPage }))\n);\nconst GettingStartedPage = React.lazy(() =>\n import('./pages/GettingStartedPage').then((m) => ({ default: m.GettingStartedPage }))\n);\nconst SharedSessionPage = React.lazy(() =>\n import('./pages/SharedSessionPage').then((m) => ({ default: m.SharedSessionPage }))\n);\nconst VibeDeckPage = React.lazy(() =>\n import('./pages/VibeDeckPage').then((m) => ({ default: m.VibeDeckPage }))\n);\nconst SharedVibeDeckPage = React.lazy(() =>\n import('./pages/SharedVibeDeckPage').then((m) => ({ default: m.SharedVibeDeckPage }))\n);\nconst VibeCalendarPage = React.lazy(() =>\n import('./pages/VibeCalendarPage').then((m) => ({ default: m.VibeCalendarPage }))\n);\nconst VibeTaskDetailPage = React.lazy(() =>\n import('./pages/VibeTaskDetailPage').then((m) => ({ default: m.VibeTaskDetailPage }))\n);\nconst ActionsPage = React.lazy(() =>\n import('./pages/ActionsPage').then((m) => ({ default: m.ActionsPage }))\n);\nconst VibeAuditPage = React.lazy(() =>\n import('./pages/VibeAuditPage').then((m) => ({ default: m.VibeAuditPage }))\n);\nconst AnalyticsPage = React.lazy(() =>\n import('./pages/AnalyticsPage').then((m) => ({ default: m.AnalyticsPage }))\n);\nconst VibeDocsPage = React.lazy(() =>\n import('./pages/VibeDocsPage').then((m) => ({ default: m.VibeDocsPage }))\n);\n\n// Catalog, Components, Templates pages\nconst CatalogPage = React.lazy(() =>\n import('./pages/CatalogPage').then((m) => ({ default: m.CatalogPage }))\n);\nconst CatalogDetailPage = React.lazy(() =>\n import('./pages/CatalogDetailPage').then((m) => ({ default: m.CatalogDetailPage }))\n);\nconst CatalogDocsPage = React.lazy(() =>\n import('./pages/CatalogDocsPage').then((m) => ({ default: m.CatalogDocsPage }))\n);\nconst ComponentsPage = React.lazy(() =>\n import('./pages/ComponentsPage').then((m) => ({ default: m.ComponentsPage }))\n);\nconst ComponentDetailPage = React.lazy(() =>\n import('./pages/ComponentDetailPage').then((m) => ({ default: m.ComponentDetailPage }))\n);\nconst ComponentDocsPage = React.lazy(() =>\n import('./pages/ComponentDocsPage').then((m) => ({ default: m.ComponentDocsPage }))\n);\nconst TemplatesPage = React.lazy(() =>\n import('./pages/TemplatesPage').then((m) => ({ default: m.TemplatesPage }))\n);\nconst TemplateDetailPage = React.lazy(() =>\n import('./pages/TemplateDetailPage').then((m) => ({ default: m.TemplateDetailPage }))\n);\nconst PluginStandalonePage = React.lazy(() =>\n import('./pages/PluginStandalonePage').then((m) => ({ default: m.PluginStandalonePage }))\n);\n\n// AI pages\nconst AIPage = React.lazy(() => import('./pages/ai/AIPage').then((m) => ({ default: m.AIPage })));\nconst AISessionDetailPage = React.lazy(() =>\n import('./pages/ai/AISessionDetailPage').then((m) => ({ default: m.AISessionDetailPage }))\n);\nconst AgentManagerPage = React.lazy(() =>\n import('./pages/ai/AgentManagerPage').then((m) => ({ default: m.AgentManagerPage }))\n);\n\n// Loading fallback component\nfunction PageLoadingFallback() {\n return (\n <div className=\"flex items-center justify-center h-full min-h-[200px]\">\n <div className=\"animate-pulse bg-muted rounded w-full h-full\" />\n </div>\n );\n}\n\n/**\n * Internal router for the VibeControls microfrontend.\n * This component handles routing within the microfrontend using React Router v7.\n *\n * Routes:\n * - / → Overview page (dashboard)\n * - /agents → Agents management page\n * - /agents/:id → Agent details page\n * - /sessions → Sessions management page\n * - /sessions/:id → Session details page\n * - /vibes → Vibes (projects) management page\n * - /vibes/:id → Vibe details page (includes Notes tab)\n * - /settings → Settings page\n * - /webhooks → Legacy redirect to Developer Portal webhooks\n * - /health → Health monitoring page\n * - /* → Catch-all redirects to overview\n */\nfunction ScrollToTop() {\n const { pathname } = useLocation();\n useEffect(() => {\n // The scrollable container is the <main> element with overflow-auto\n // inside AppShellLayout, not the window itself.\n const main = document.querySelector('main');\n if (main) main.scrollTop = 0;\n }, [pathname]);\n return null;\n}\n\n/**\n * Fallback shown when a feature flag is OFF.\n */\nfunction FeatureDisabledFallback() {\n const tr = useTr();\n return (\n <div className=\"flex items-center justify-center h-full min-h-[200px] text-text-secondary text-sm\">\n {tr(\n 'vibecontrols.pages.featureDisabled',\n 'This feature is currently disabled. You can enable it from Feature Previews.'\n )}\n </div>\n );\n}\n\n/**\n * Helper: wraps a page element in a FeatureGate.\n * defaultValue={true} means the feature shows by default (before flags are seeded).\n * Only hides when a flag is explicitly set to false.\n */\nfunction gated(flag: string, element: React.ReactNode, defaultValue = true): React.ReactElement {\n return (\n <FeatureGate flag={flag} defaultValue={defaultValue} fallback={<FeatureDisabledFallback />}>\n {element}\n </FeatureGate>\n );\n}\n\nexport function VibeControlsRoutes() {\n return (\n <Suspense fallback={<PageLoadingFallback />}>\n <ScrollToTop />\n <Routes>\n {/* Default route - overview page */}\n <Route index element={gated('vibecontrols.overview', <OverviewPage />)} />\n\n {/* Core pages */}\n {/* PR-9 standalone plugin route — deep-link any contribution\n from any mount point as a full-page view. Wrapped in the\n same `gated()` envelope as every other authenticated route\n for consistent authz; the page-level\n `vibes.tabs.iframe-host` feature flag still gates rendering\n once the user is past the entitlement check. */}\n <Route\n path=\"plugin/:pluginKey\"\n element={gated('vibecontrols.vibes', <PluginStandalonePage />)}\n />\n\n <Route path=\"agents\" element={gated('vibecontrols.agents', <AgentsLandingPage />)} />\n <Route path=\"agents/:id\" element={gated('vibecontrols.agents', <AgentDetailsPage />)} />\n <Route path=\"sessions\" element={gated('vibecontrols.sessions', <SessionsPage />)} />\n <Route path=\"vibes\" element={gated('vibecontrols.vibes', <VibesPage />)} />\n <Route path=\"vibes/:id\" element={gated('vibecontrols.vibes', <VibeDetailsPage />)} />\n <Route path=\"vibes/:id/docs/*\" element={gated('vibecontrols.vibes', <VibeDocsPage />)} />\n <Route path=\"notes/:id\" element={gated('vibecontrols.vibes', <NoteDetailsPage />)} />\n <Route\n path=\"sessions/:id\"\n element={gated('vibecontrols.sessions', <SessionDetailsPage />)}\n />\n {/* Agent Manager — multi-session tabbed UI (replaces old AI page) */}\n <Route path=\"ai\" element={gated('vibecontrols.ai', <AgentManagerPage />)} />\n <Route path=\"ai/:tab\" element={gated('vibecontrols.ai', <AgentManagerPage />)} />\n <Route\n path=\"ai/sessions/:sessionId\"\n element={gated('vibecontrols.ai', <AgentManagerPage />)}\n />\n {/* AI Tools — templates, contexts, prompts, stats, playground */}\n <Route path=\"ai-tools\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route path=\"ai-tools/:tab\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route\n path=\"ai-tools/sessions/:sessionId\"\n element={gated('vibecontrols.ai', <AISessionDetailPage />)}\n />\n\n {/* Targets list lives in the Targets & Agents landing; per-target\n detail is its own page (mirrors agents/:id). */}\n <Route path=\"targets\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n <Route path=\"targets/:id\" element={gated('vibecontrols.agents', <TargetDetailsPage />)} />\n {/* Agent Graph is also a tab inside the Targets & Agents landing. */}\n <Route path=\"agent-graph\" element={<Navigate to=\"../agents?tab=graph\" replace />} />\n\n {/* Catalog */}\n <Route path=\"catalogs\" element={gated('vibecontrols.catalogs', <CatalogPage />)} />\n <Route\n path=\"catalogs/:id\"\n element={gated('vibecontrols.catalogs', <CatalogDetailPage />)}\n />\n <Route\n path=\"catalogs/:id/docs/*\"\n element={gated('vibecontrols.catalogs', <CatalogDocsPage />)}\n />\n <Route path=\"components\" element={gated('vibecontrols.components', <ComponentsPage />)} />\n <Route\n path=\"components/:id\"\n element={gated('vibecontrols.components', <ComponentDetailPage />)}\n />\n <Route\n path=\"components/:id/docs/*\"\n element={gated('vibecontrols.components', <ComponentDocsPage />)}\n />\n <Route path=\"templates\" element={gated('vibecontrols.templates', <TemplatesPage />)} />\n <Route\n path=\"templates/:id\"\n element={gated('vibecontrols.templates', <TemplateDetailPage />)}\n />\n\n {/* Automation */}\n <Route path=\"actions\" element={gated('vibecontrols.actions', <ActionsPage />)} />\n <Route path=\"vibedeck\" element={gated('vibecontrols.vibedeck', <VibeDeckPage />)} />\n <Route path=\"calendar\" element={gated('vibecontrols.calendar', <VibeCalendarPage />)} />\n <Route\n path=\"calendar/:viewType\"\n element={gated('vibecontrols.calendar', <VibeCalendarPage />)}\n />\n <Route\n path=\"calendar/task/:taskId\"\n element={gated('vibecontrols.calendar', <VibeTaskDetailPage />)}\n />\n <Route path=\"webhooks\" element={<Navigate to=\"/devportal/webhooks\" replace />} />\n <Route path=\"webhooks/new\" element={<Navigate to=\"/devportal/webhooks/new\" replace />} />\n <Route path=\"webhooks/:id\" element={<Navigate to=\"/devportal/webhooks\" replace />} />\n {/* GitOps consolidated into Vibe detail tab — old /gitops routes redirect to vibes list. */}\n <Route path=\"gitops\" element={<Navigate to=\"../vibes\" replace />} />\n <Route path=\"gitops/:tab\" element={<Navigate to=\"../vibes\" replace />} />\n\n {/* Infrastructure */}\n <Route path=\"tunnels\" element={gated('vibecontrols.tunnels', <TunnelsLandingPage />)} />\n <Route path=\"tunnels/new\" element={gated('vibecontrols.tunnels', <TunnelCreateWizard />)} />\n <Route\n path=\"tunnels/:tunnelId\"\n element={gated('vibecontrols.tunnels', <TunnelDetailsPage />)}\n />\n\n {/* Insights */}\n <Route path=\"health\" element={gated('vibecontrols.health', <HealthPage />)} />\n <Route path=\"analytics\" element={gated('vibecontrols.analytics', <AnalyticsPage />)} />\n <Route path=\"audit\" element={gated('vibecontrols.audit-log', <VibeAuditPage />, false)} />\n <Route path=\"logs\" element={<Navigate to=\"/vibecontrols/agents\" replace />} />\n\n {/* Settings */}\n <Route path=\"settings\" element={gated('vibecontrols.settings', <SettingsPage />)} />\n\n {/* Setup */}\n {/* Not gated — onboarding flow must always be reachable */}\n <Route path=\"getting-started\" element={<GettingStartedPage />} />\n\n {/* Shared public routes (no gating — accessible via public links) */}\n <Route path=\"share/:token\" element={<SharedSessionPage />} />\n <Route path=\"deck/:token\" element={<SharedVibeDeckPage />} />\n\n {/* Legacy redirects */}\n <Route path=\"access\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n <Route path=\"ssh-targets\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n <Route path=\"ssh-terminals\" element={<Navigate to=\"../agents?tab=targets\" replace />} />\n\n {/* Catch-all route - redirect to overview */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":";;;;;;AAMA,IAAM,IAAe,EAAM,WACzB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EAGK,IAAoB,EAAM,WAC9B,OAAO,gCAA6B,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CACpF,EACK,IAAmB,EAAM,WAC7B,OAAO,+BAA4B,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAClF,EACK,IAAoB,EAAM,WAC9B,OAAO,gCAA6B,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CACpF,EACK,IAAe,EAAM,WACzB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAqB,EAAM,WAC/B,OAAO,iCAA8B,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACtF,EACK,IAAY,EAAM,WACtB,OAAO,wBAAqB,MAAM,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CACpE,EACK,IAAkB,EAAM,WAC5B,OAAO,8BAA2B,MAAM,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAChF,EACK,IAAkB,EAAM,WAC5B,OAAO,8BAA2B,MAAM,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAChF,EACK,IAAqB,EAAM,WAC/B,OAAO,iCAA8B,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACtF,EACK,IAAoB,EAAM,WAC9B,OAAO,wCAAqC,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAC5F,EACK,IAAqB,EAAM,WAC/B,OAAO,8CAA2C,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACnG,EACK,IAAe,EAAM,WACzB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAa,EAAM,WACvB,OAAO,yBAAsB,MAAM,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,CACtE,EACK,IAAqB,EAAM,WAC/B,OAAO,iCAA8B,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACtF,EACK,IAAoB,EAAM,WAC9B,OAAO,gCAA6B,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CACpF,EACK,IAAe,EAAM,WACzB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EACK,IAAqB,EAAM,WAC/B,OAAO,iCAA8B,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACtF,EACK,IAAmB,EAAM,WAC7B,OAAO,+BAA4B,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAClF,EACK,IAAqB,EAAM,WAC/B,OAAO,iCAA8B,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACtF,EACK,IAAc,EAAM,WACxB,OAAO,0BAAuB,MAAM,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CACxE,EACK,IAAgB,EAAM,WAC1B,OAAO,4BAAyB,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAC5E,EACK,IAAgB,EAAM,WAC1B,OAAO,4BAAyB,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAC5E,EACK,IAAe,EAAM,WACzB,OAAO,2BAAwB,MAAM,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAC1E,EAGK,IAAc,EAAM,WACxB,OAAO,0BAAuB,MAAM,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CACxE,EACK,IAAoB,EAAM,WAC9B,OAAO,gCAA6B,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CACpF,EACK,IAAkB,EAAM,WAC5B,OAAO,8BAA2B,MAAM,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAChF,EACK,IAAiB,EAAM,WAC3B,OAAO,6BAA0B,MAAM,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAC9E,EACK,IAAsB,EAAM,WAChC,OAAO,kCAA+B,MAAM,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,CACxF,EACK,IAAoB,EAAM,WAC9B,OAAO,gCAA6B,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CACpF,EACK,IAAgB,EAAM,WAC1B,OAAO,4BAAyB,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAC5E,EACK,IAAqB,EAAM,WAC/B,OAAO,iCAA8B,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACtF,EACK,IAAuB,EAAM,WACjC,OAAO,mCAAgC,MAAM,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,CAC1F,EAGK,IAAS,EAAM,WAAW,OAAO,wBAAqB,MAAM,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAC3F,IAAsB,EAAM,WAChC,OAAO,qCAAkC,MAAM,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAC3F,EACK,IAAmB,EAAM,WAC7B,OAAO,kCAA+B,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CACrF;AAGD,SAAS,IAAsB;AAC7B,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD,EAAK,WAAU,gDAAiD,CAAA;EAC5D,CAAA;;AAqBV,SAAS,IAAc;CACrB,IAAM,EAAE,gBAAa,GAAa;AAOlC,QANA,QAAgB;EAGd,IAAM,IAAO,SAAS,cAAc,OAAO;AAC3C,EAAI,MAAM,EAAK,YAAY;IAC1B,CAAC,EAAS,CAAC,EACP;;AAMT,SAAS,IAA0B;AAEjC,QACE,kBAAC,OAAD;EAAK,WAAU;YAFN,GAAO,CAIZ,sCACA,+EACD;EACG,CAAA;;AASV,SAAS,EAAM,GAAc,GAA0B,IAAe,IAA0B;AAC9F,QACE,kBAAC,GAAD;EAAmB;EAAoB;EAAc,UAAU,kBAAC,GAAD,EAA2B,CAAA;YACvF;EACW,CAAA;;AAIlB,SAAgB,IAAqB;AACnC,QACE,kBAAC,GAAD;EAAU,UAAU,kBAAC,GAAD,EAAuB,CAAA;YAA3C,CACE,kBAAC,GAAD,EAAe,CAAA,EACf,kBAAC,GAAD,EAAA,UAAA;GAEE,kBAAC,GAAD;IAAO,OAAA;IAAM,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAgB,CAAA,CAAC;IAAI,CAAA;GAS1E,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,sBAAsB,kBAAC,GAAD,EAAwB,CAAA,CAAC;IAC9D,CAAA;GAEF,kBAAC,GAAD;IAAO,MAAK;IAAS,SAAS,EAAM,uBAAuB,kBAAC,GAAD,EAAqB,CAAA,CAAC;IAAI,CAAA;GACrF,kBAAC,GAAD;IAAO,MAAK;IAAa,SAAS,EAAM,uBAAuB,kBAAC,GAAD,EAAoB,CAAA,CAAC;IAAI,CAAA;GACxF,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAgB,CAAA,CAAC;IAAI,CAAA;GACpF,kBAAC,GAAD;IAAO,MAAK;IAAQ,SAAS,EAAM,sBAAsB,kBAAC,GAAD,EAAa,CAAA,CAAC;IAAI,CAAA;GAC3E,kBAAC,GAAD;IAAO,MAAK;IAAY,SAAS,EAAM,sBAAsB,kBAAC,GAAD,EAAmB,CAAA,CAAC;IAAI,CAAA;GACrF,kBAAC,GAAD;IAAO,MAAK;IAAmB,SAAS,EAAM,sBAAsB,kBAAC,GAAD,EAAgB,CAAA,CAAC;IAAI,CAAA;GACzF,kBAAC,GAAD;IAAO,MAAK;IAAY,SAAS,EAAM,sBAAsB,kBAAC,GAAD,EAAmB,CAAA,CAAC;IAAI,CAAA;GACrF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAsB,CAAA,CAAC;IAC/D,CAAA;GAEF,kBAAC,GAAD;IAAO,MAAK;IAAK,SAAS,EAAM,mBAAmB,kBAAC,GAAD,EAAoB,CAAA,CAAC;IAAI,CAAA;GAC5E,kBAAC,GAAD;IAAO,MAAK;IAAU,SAAS,EAAM,mBAAmB,kBAAC,GAAD,EAAoB,CAAA,CAAC;IAAI,CAAA;GACjF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,mBAAmB,kBAAC,GAAD,EAAoB,CAAA,CAAC;IACvD,CAAA;GAEF,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,EAAM,mBAAmB,kBAAC,GAAD,EAAU,CAAA,CAAC;IAAI,CAAA;GACxE,kBAAC,GAAD;IAAO,MAAK;IAAgB,SAAS,EAAM,mBAAmB,kBAAC,GAAD,EAAU,CAAA,CAAC;IAAI,CAAA;GAC7E,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,mBAAmB,kBAAC,GAAD,EAAuB,CAAA,CAAC;IAC1D,CAAA;GAIF,kBAAC,GAAD;IAAO,MAAK;IAAU,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAwB,SAAA;KAAU,CAAA;IAAI,CAAA;GAClF,kBAAC,GAAD;IAAO,MAAK;IAAc,SAAS,EAAM,uBAAuB,kBAAC,GAAD,EAAqB,CAAA,CAAC;IAAI,CAAA;GAE1F,kBAAC,GAAD;IAAO,MAAK;IAAc,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAsB,SAAA;KAAU,CAAA;IAAI,CAAA;GAGpF,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAe,CAAA,CAAC;IAAI,CAAA;GACnF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAqB,CAAA,CAAC;IAC9D,CAAA;GACF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAmB,CAAA,CAAC;IAC5D,CAAA;GACF,kBAAC,GAAD;IAAO,MAAK;IAAa,SAAS,EAAM,2BAA2B,kBAAC,GAAD,EAAkB,CAAA,CAAC;IAAI,CAAA;GAC1F,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,2BAA2B,kBAAC,GAAD,EAAuB,CAAA,CAAC;IAClE,CAAA;GACF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,2BAA2B,kBAAC,GAAD,EAAqB,CAAA,CAAC;IAChE,CAAA;GACF,kBAAC,GAAD;IAAO,MAAK;IAAY,SAAS,EAAM,0BAA0B,kBAAC,GAAD,EAAiB,CAAA,CAAC;IAAI,CAAA;GACvF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,0BAA0B,kBAAC,GAAD,EAAsB,CAAA,CAAC;IAChE,CAAA;GAGF,kBAAC,GAAD;IAAO,MAAK;IAAU,SAAS,EAAM,wBAAwB,kBAAC,GAAD,EAAe,CAAA,CAAC;IAAI,CAAA;GACjF,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAgB,CAAA,CAAC;IAAI,CAAA;GACpF,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAoB,CAAA,CAAC;IAAI,CAAA;GACxF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAoB,CAAA,CAAC;IAC7D,CAAA;GACF,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAsB,CAAA,CAAC;IAC/D,CAAA;GACF,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAsB,SAAA;KAAU,CAAA;IAAI,CAAA;GACjF,kBAAC,GAAD;IAAO,MAAK;IAAe,SAAS,kBAAC,GAAD;KAAU,IAAG;KAA0B,SAAA;KAAU,CAAA;IAAI,CAAA;GACzF,kBAAC,GAAD;IAAO,MAAK;IAAe,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAsB,SAAA;KAAU,CAAA;IAAI,CAAA;GAErF,kBAAC,GAAD;IAAO,MAAK;IAAS,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAW,SAAA;KAAU,CAAA;IAAI,CAAA;GACpE,kBAAC,GAAD;IAAO,MAAK;IAAc,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAW,SAAA;KAAU,CAAA;IAAI,CAAA;GAGzE,kBAAC,GAAD;IAAO,MAAK;IAAU,SAAS,EAAM,wBAAwB,kBAAC,GAAD,EAAsB,CAAA,CAAC;IAAI,CAAA;GACxF,kBAAC,GAAD;IAAO,MAAK;IAAc,SAAS,EAAM,wBAAwB,kBAAC,GAAD,EAAsB,CAAA,CAAC;IAAI,CAAA;GAC5F,kBAAC,GAAD;IACE,MAAK;IACL,SAAS,EAAM,wBAAwB,kBAAC,GAAD,EAAqB,CAAA,CAAC;IAC7D,CAAA;GAGF,kBAAC,GAAD;IAAO,MAAK;IAAS,SAAS,EAAM,uBAAuB,kBAAC,GAAD,EAAc,CAAA,CAAC;IAAI,CAAA;GAC9E,kBAAC,GAAD;IAAO,MAAK;IAAY,SAAS,EAAM,0BAA0B,kBAAC,GAAD,EAAiB,CAAA,CAAC;IAAI,CAAA;GACvF,kBAAC,GAAD;IAAO,MAAK;IAAQ,SAAS,EAAM,0BAA0B,kBAAC,GAAD,EAAiB,CAAA,EAAE,GAAM;IAAI,CAAA;GAC1F,kBAAC,GAAD;IAAO,MAAK;IAAO,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAuB,SAAA;KAAU,CAAA;IAAI,CAAA;GAG9E,kBAAC,GAAD;IAAO,MAAK;IAAW,SAAS,EAAM,yBAAyB,kBAAC,GAAD,EAAgB,CAAA,CAAC;IAAI,CAAA;GAIpF,kBAAC,GAAD;IAAO,MAAK;IAAkB,SAAS,kBAAC,GAAD,EAAsB,CAAA;IAAI,CAAA;GAGjE,kBAAC,GAAD;IAAO,MAAK;IAAe,SAAS,kBAAC,GAAD,EAAqB,CAAA;IAAI,CAAA;GAC7D,kBAAC,GAAD;IAAO,MAAK;IAAc,SAAS,kBAAC,GAAD,EAAsB,CAAA;IAAI,CAAA;GAG7D,kBAAC,GAAD;IAAO,MAAK;IAAS,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAwB,SAAA;KAAU,CAAA;IAAI,CAAA;GACjF,kBAAC,GAAD;IAAO,MAAK;IAAc,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAwB,SAAA;KAAU,CAAA;IAAI,CAAA;GACtF,kBAAC,GAAD;IAAO,MAAK;IAAgB,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAwB,SAAA;KAAU,CAAA;IAAI,CAAA;GAGxF,kBAAC,GAAD;IAAO,MAAK;IAAI,SAAS,kBAAC,GAAD;KAAU,IAAG;KAAG,SAAA;KAAU,CAAA;IAAI,CAAA;GAChD,EAAA,CAAA,CACA"}
|
|
@@ -3,44 +3,44 @@ import { useVibeControls as a } from "../../providers/VibeControlsProvider.js";
|
|
|
3
3
|
import "../../constants/pluginCatalog.js";
|
|
4
4
|
import { PluginGate as o } from "../shared/PluginGate.js";
|
|
5
5
|
import "../shared/index.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { appendIframeTokenParam as s, mintIframeToken as c, scheduleIframeTokenRefresh as l } from "../../services/iframeToken.js";
|
|
7
|
+
import { RepoStatsTab as u } from "./RepoStatsTab.js";
|
|
8
|
+
import { CITab as d } from "./CITab.js";
|
|
9
|
+
import { GitOpsSetup as f } from "./GitOpsSetup.js";
|
|
10
10
|
import { useCallback as p, useEffect as m, useState as h } from "react";
|
|
11
11
|
import { BarChart3 as g, GitBranch as _, GitMerge as v, Play as y, RefreshCw as b } from "lucide-react";
|
|
12
12
|
import { motion as x } from "framer-motion";
|
|
13
13
|
import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
14
14
|
//#region src/components/gitops/VibeGitOpsTab.tsx
|
|
15
|
-
var T = ({ vibeId:
|
|
15
|
+
var T = ({ vibeId: s, agentId: c, profile: l, tunnelUrl: p, apiKey: m, tr: T }) => {
|
|
16
16
|
let [D, O] = h("repo-stats"), [k, A] = h(!1), { workspaceId: j } = a(), { data: M, loading: N, refetch: P } = n({
|
|
17
17
|
variables: {
|
|
18
|
-
filter: { vibeId:
|
|
18
|
+
filter: { vibeId: s },
|
|
19
19
|
pagination: { limit: 50 }
|
|
20
20
|
},
|
|
21
21
|
fetchPolicy: "cache-and-network"
|
|
22
22
|
}), F = M?.listGitopsProviders?.items ?? [], I = F.find((e) => e.isActive)?.id || F[0]?.id || "", { data: L, loading: R, error: z } = t({
|
|
23
23
|
variables: {
|
|
24
24
|
providerId: I,
|
|
25
|
-
agentId:
|
|
25
|
+
agentId: c
|
|
26
26
|
},
|
|
27
|
-
skip: !I || !
|
|
27
|
+
skip: !I || !c || D !== "repo-stats",
|
|
28
28
|
fetchPolicy: "cache-and-network"
|
|
29
29
|
}), { data: B, loading: V, error: H } = e({
|
|
30
30
|
variables: {
|
|
31
31
|
providerId: I,
|
|
32
|
-
agentId:
|
|
32
|
+
agentId: c,
|
|
33
33
|
limit: 30
|
|
34
34
|
},
|
|
35
|
-
skip: !I || !
|
|
35
|
+
skip: !I || !c || D !== "ci",
|
|
36
36
|
fetchPolicy: "cache-and-network"
|
|
37
37
|
}), [U, { loading: W }] = i(), [G, { loading: K }] = r(), q = async () => {
|
|
38
|
-
!I || !
|
|
38
|
+
!I || !c || (D === "repo-stats" ? await U({ variables: {
|
|
39
39
|
providerId: I,
|
|
40
|
-
agentId:
|
|
40
|
+
agentId: c
|
|
41
41
|
} }) : D === "ci" && await G({ variables: {
|
|
42
42
|
providerId: I,
|
|
43
|
-
agentId:
|
|
43
|
+
agentId: c
|
|
44
44
|
} }));
|
|
45
45
|
}, J = W || K, Y = F.length > 0, X = [
|
|
46
46
|
{
|
|
@@ -84,7 +84,7 @@ var T = ({ vibeId: u, agentId: d, profile: f, tunnelUrl: p, apiKey: m, tr: T })
|
|
|
84
84
|
})]
|
|
85
85
|
}), /* @__PURE__ */ w("div", {
|
|
86
86
|
className: "flex items-center gap-2",
|
|
87
|
-
children: [Y &&
|
|
87
|
+
children: [Y && c && (D === "repo-stats" || D === "ci") && /* @__PURE__ */ w("button", {
|
|
88
88
|
onClick: q,
|
|
89
89
|
disabled: J,
|
|
90
90
|
className: "flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-md border border-border-default text-text-secondary hover:text-text-primary hover:border-border-strong disabled:opacity-50 transition-colors",
|
|
@@ -117,17 +117,17 @@ var T = ({ vibeId: u, agentId: d, profile: f, tunnelUrl: p, apiKey: m, tr: T })
|
|
|
117
117
|
}), /* @__PURE__ */ w("div", {
|
|
118
118
|
className: "min-w-0 flex-1 space-y-4",
|
|
119
119
|
children: [
|
|
120
|
-
k && /* @__PURE__ */ C(
|
|
120
|
+
k && /* @__PURE__ */ C(f, {
|
|
121
121
|
workspaceId: j || "",
|
|
122
|
-
agents:
|
|
123
|
-
id:
|
|
122
|
+
agents: c ? [{
|
|
123
|
+
id: c,
|
|
124
124
|
name: "Active Agent"
|
|
125
125
|
}] : [],
|
|
126
126
|
onCreated: () => {
|
|
127
127
|
A(!1), P();
|
|
128
128
|
}
|
|
129
129
|
}),
|
|
130
|
-
D === "repo-stats" && !k && /* @__PURE__ */ C(S, { children: Y ?
|
|
130
|
+
D === "repo-stats" && !k && /* @__PURE__ */ C(S, { children: Y ? c ? /* @__PURE__ */ C(u, {
|
|
131
131
|
stats: L?.getRepoStats ?? null,
|
|
132
132
|
loading: R || N,
|
|
133
133
|
error: z?.message
|
|
@@ -152,7 +152,7 @@ var T = ({ vibeId: u, agentId: d, profile: f, tunnelUrl: p, apiKey: m, tr: T })
|
|
|
152
152
|
})
|
|
153
153
|
]
|
|
154
154
|
}) }),
|
|
155
|
-
D === "ci" && !k && /* @__PURE__ */ C(S, { children: Y ?
|
|
155
|
+
D === "ci" && !k && /* @__PURE__ */ C(S, { children: Y ? c ? /* @__PURE__ */ C(d, {
|
|
156
156
|
status: B?.getCIStatus ?? null,
|
|
157
157
|
loading: V || N,
|
|
158
158
|
error: H?.message
|
|
@@ -170,15 +170,15 @@ var T = ({ vibeId: u, agentId: d, profile: f, tunnelUrl: p, apiKey: m, tr: T })
|
|
|
170
170
|
})]
|
|
171
171
|
}) }),
|
|
172
172
|
D === "git-ui" && /* @__PURE__ */ C(o, {
|
|
173
|
-
agentId:
|
|
173
|
+
agentId: c || null,
|
|
174
174
|
required: ["@vibecontrols/vibe-plugin-tool-git"],
|
|
175
175
|
mode: "all",
|
|
176
176
|
eyebrow: T("gitops.ungitEyebrow", "Ungit plugin required"),
|
|
177
177
|
title: T("gitops.ungitTitle", "Install the visual git client"),
|
|
178
178
|
description: T("gitops.ungitDescription", "The Git UI embeds the Ungit visual git client served by your agent. Install the plugin to continue."),
|
|
179
179
|
children: /* @__PURE__ */ C(E, {
|
|
180
|
-
agentId:
|
|
181
|
-
profile:
|
|
180
|
+
agentId: c,
|
|
181
|
+
profile: l,
|
|
182
182
|
tunnelUrl: p,
|
|
183
183
|
apiKey: m,
|
|
184
184
|
tr: T
|
|
@@ -190,14 +190,14 @@ var T = ({ vibeId: u, agentId: d, profile: f, tunnelUrl: p, apiKey: m, tr: T })
|
|
|
190
190
|
}, "gitops");
|
|
191
191
|
};
|
|
192
192
|
function E({ agentId: e, profile: t, tunnelUrl: n, apiKey: r, tr: i }) {
|
|
193
|
-
let [a, o] = h(!1), [
|
|
193
|
+
let [a, o] = h(!1), [u, d] = h(!1), [f, g] = h(null), [v, y] = h(null);
|
|
194
194
|
m(() => {
|
|
195
195
|
if (!e || !a) return;
|
|
196
196
|
let n = !1, r = null, i = (a) => {
|
|
197
|
-
n || (g(a), r =
|
|
197
|
+
n || (g(a), r = l(e, t, "/ungit", a, i, (e) => y(e.message)));
|
|
198
198
|
};
|
|
199
|
-
return
|
|
200
|
-
n || (g(a), r =
|
|
199
|
+
return c(e, t, "/ungit").then((a) => {
|
|
200
|
+
n || (g(a), r = l(e, t, "/ungit", a, i, (e) => y(e.message)));
|
|
201
201
|
}).catch((e) => {
|
|
202
202
|
n || y(e instanceof Error ? e.message : String(e));
|
|
203
203
|
}), () => {
|
|
@@ -230,29 +230,29 @@ function E({ agentId: e, profile: t, tunnelUrl: n, apiKey: r, tr: i }) {
|
|
|
230
230
|
className: "text-xs text-text-secondary",
|
|
231
231
|
children: i("gitops.ungitNote", "Visual git client powered by Ungit plugin on the agent.")
|
|
232
232
|
}),
|
|
233
|
-
!a && !
|
|
233
|
+
!a && !u && /* @__PURE__ */ C("button", {
|
|
234
234
|
onClick: () => {
|
|
235
235
|
if (!r) return;
|
|
236
|
-
|
|
236
|
+
d(!0);
|
|
237
237
|
let e = { "Content-Type": "application/json" };
|
|
238
238
|
e["x-agent-api-key"] = r, fetch(`${n}/api/profiles/${encodeURIComponent(t)}/ungit/start`, {
|
|
239
239
|
method: "POST",
|
|
240
240
|
headers: e,
|
|
241
241
|
body: "{}"
|
|
242
242
|
}).then((e) => e.json()).then(() => {
|
|
243
|
-
o(!0),
|
|
244
|
-
}).catch(() =>
|
|
243
|
+
o(!0), d(!1);
|
|
244
|
+
}).catch(() => d(!1));
|
|
245
245
|
},
|
|
246
246
|
className: "px-3 py-1 text-xs font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors",
|
|
247
247
|
children: i("gitops.startUngit", "Start Ungit")
|
|
248
248
|
}),
|
|
249
|
-
|
|
249
|
+
u && /* @__PURE__ */ C("span", {
|
|
250
250
|
className: "text-xs text-text-secondary animate-pulse",
|
|
251
251
|
children: i("gitops.startingUngit", "Starting...")
|
|
252
252
|
})
|
|
253
253
|
]
|
|
254
|
-
}), a ?
|
|
255
|
-
src:
|
|
254
|
+
}), a ? f ? /* @__PURE__ */ C("iframe", {
|
|
255
|
+
src: s(`${n}/ungit/`, f.token),
|
|
256
256
|
title: "Git UI (Ungit)",
|
|
257
257
|
className: "w-full",
|
|
258
258
|
style: { height: "700px" },
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { agentApiPath as e } from "../../utils/agentApiPath.js";
|
|
2
|
+
import { agentAiMutate as t } from "../../services/aiApi.js";
|
|
3
|
+
import { useCallback as n, useEffect as r, useMemo as i, useRef as a, useState as o } from "react";
|
|
4
|
+
import { AlertTriangle as s, CheckCircle2 as c, Loader2 as l, Plus as u, X as d } from "lucide-react";
|
|
5
|
+
import { AnimatePresence as f, motion as p } from "framer-motion";
|
|
6
|
+
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
7
|
+
//#region src/components/plugins/AddTabDialog.tsx
|
|
8
|
+
function _({ isOpen: _, onClose: v, mountPoint: y, agentId: b, profile: x, onInstalled: S }) {
|
|
9
|
+
let [C, w] = o(!1), [T, E] = o(null), [D, O] = o([]), [k, A] = o([]), [j, M] = o(null), [N, P] = o(null), [F, I] = o(/* @__PURE__ */ new Set()), L = a(!0);
|
|
10
|
+
r(() => (L.current = !0, () => {
|
|
11
|
+
L.current = !1;
|
|
12
|
+
}), []);
|
|
13
|
+
let R = a(null);
|
|
14
|
+
r(() => {
|
|
15
|
+
if (!_) return;
|
|
16
|
+
let e = typeof document < "u" ? document.activeElement : null, t = (e) => {
|
|
17
|
+
if (e.key === "Escape") {
|
|
18
|
+
e.preventDefault(), v();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (e.key !== "Tab" || !R.current) return;
|
|
22
|
+
let t = R.current.querySelectorAll("a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])");
|
|
23
|
+
if (t.length === 0) return;
|
|
24
|
+
let n = t[0], r = t[t.length - 1];
|
|
25
|
+
e.shiftKey && document.activeElement === n ? (e.preventDefault(), r.focus()) : !e.shiftKey && document.activeElement === r && (e.preventDefault(), n.focus());
|
|
26
|
+
};
|
|
27
|
+
return document.addEventListener("keydown", t), setTimeout(() => R.current?.focus(), 0), () => {
|
|
28
|
+
document.removeEventListener("keydown", t), e?.focus?.();
|
|
29
|
+
};
|
|
30
|
+
}, [_, v]), r(() => {
|
|
31
|
+
I(/* @__PURE__ */ new Set());
|
|
32
|
+
}, [
|
|
33
|
+
b,
|
|
34
|
+
x,
|
|
35
|
+
y,
|
|
36
|
+
_
|
|
37
|
+
]);
|
|
38
|
+
let z = n(async () => {
|
|
39
|
+
w(!0), E(null);
|
|
40
|
+
try {
|
|
41
|
+
let [n, r] = await Promise.all([t(b, e(x, "/plugins/catalog"), "GET", null), t(b, e(x, `/plugins/contributions?mountPoint=${encodeURIComponent(y)}`), "GET", null)]);
|
|
42
|
+
if (!L.current) return;
|
|
43
|
+
O(n.plugins ?? []), A(r.contributions ?? []);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
if (!L.current) return;
|
|
46
|
+
E(e instanceof Error ? e.message : String(e));
|
|
47
|
+
} finally {
|
|
48
|
+
L.current && w(!1);
|
|
49
|
+
}
|
|
50
|
+
}, [
|
|
51
|
+
b,
|
|
52
|
+
x,
|
|
53
|
+
y
|
|
54
|
+
]);
|
|
55
|
+
r(() => {
|
|
56
|
+
_ && z();
|
|
57
|
+
}, [_, z]);
|
|
58
|
+
let B = i(() => new Set(D.filter((e) => e.installed).map((e) => e.packageName)), [D]), V = i(() => D.filter((e) => !e.installed && !F.has(e.packageName)), [D, F]), H = i(() => k.filter((e) => e.contribution.mountPoint === y), [k, y]), U = n(async (n) => {
|
|
59
|
+
M(n), P(null);
|
|
60
|
+
try {
|
|
61
|
+
if (await t(b, e(x, "/plugins/install"), "POST", { packageName: n }), !L.current) return;
|
|
62
|
+
I((e) => new Set(e).add(n)), S?.(n), z();
|
|
63
|
+
} catch (e) {
|
|
64
|
+
if (!L.current) return;
|
|
65
|
+
P(e instanceof Error ? e.message : String(e));
|
|
66
|
+
} finally {
|
|
67
|
+
L.current && M(null);
|
|
68
|
+
}
|
|
69
|
+
}, [
|
|
70
|
+
b,
|
|
71
|
+
x,
|
|
72
|
+
S,
|
|
73
|
+
z
|
|
74
|
+
]);
|
|
75
|
+
return _ ? /* @__PURE__ */ h(f, { children: /* @__PURE__ */ h(p.div, {
|
|
76
|
+
initial: { opacity: 0 },
|
|
77
|
+
animate: { opacity: 1 },
|
|
78
|
+
exit: { opacity: 0 },
|
|
79
|
+
className: "fixed inset-0 z-50 bg-bg-overlay flex items-center justify-center p-4",
|
|
80
|
+
onClick: v,
|
|
81
|
+
children: /* @__PURE__ */ g(p.div, {
|
|
82
|
+
ref: R,
|
|
83
|
+
initial: {
|
|
84
|
+
opacity: 0,
|
|
85
|
+
y: 8
|
|
86
|
+
},
|
|
87
|
+
animate: {
|
|
88
|
+
opacity: 1,
|
|
89
|
+
y: 0
|
|
90
|
+
},
|
|
91
|
+
exit: {
|
|
92
|
+
opacity: 0,
|
|
93
|
+
y: -8
|
|
94
|
+
},
|
|
95
|
+
className: "bg-bg-surface rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] overflow-hidden flex flex-col focus:outline-none",
|
|
96
|
+
onClick: (e) => e.stopPropagation(),
|
|
97
|
+
role: "dialog",
|
|
98
|
+
"aria-modal": "true",
|
|
99
|
+
"aria-labelledby": "add-tab-dialog-title",
|
|
100
|
+
tabIndex: -1,
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ g("div", {
|
|
103
|
+
className: "flex items-center justify-between px-5 py-4 border-b border-border-default",
|
|
104
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h2", {
|
|
105
|
+
id: "add-tab-dialog-title",
|
|
106
|
+
className: "text-base font-semibold text-text-primary",
|
|
107
|
+
children: "Add tab"
|
|
108
|
+
}), /* @__PURE__ */ g("p", {
|
|
109
|
+
className: "text-xs text-text-secondary",
|
|
110
|
+
children: [
|
|
111
|
+
"Install a UI plugin that contributes to",
|
|
112
|
+
" ",
|
|
113
|
+
/* @__PURE__ */ h("code", {
|
|
114
|
+
className: "font-mono",
|
|
115
|
+
children: y
|
|
116
|
+
})
|
|
117
|
+
]
|
|
118
|
+
})] }), /* @__PURE__ */ h("button", {
|
|
119
|
+
type: "button",
|
|
120
|
+
onClick: v,
|
|
121
|
+
className: "text-text-secondary hover:text-text-primary",
|
|
122
|
+
"aria-label": "Close",
|
|
123
|
+
children: /* @__PURE__ */ h(d, { className: "w-5 h-5" })
|
|
124
|
+
})]
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ g("div", {
|
|
127
|
+
className: "overflow-y-auto px-5 py-4 space-y-6",
|
|
128
|
+
children: [
|
|
129
|
+
T && /* @__PURE__ */ g("div", {
|
|
130
|
+
className: "flex items-start gap-2 text-sm text-status-danger-text bg-status-danger-bg px-3 py-2 rounded-md",
|
|
131
|
+
children: [/* @__PURE__ */ h(s, { className: "w-4 h-4 mt-0.5 shrink-0" }), /* @__PURE__ */ h("span", { children: T })]
|
|
132
|
+
}),
|
|
133
|
+
N && /* @__PURE__ */ g("div", {
|
|
134
|
+
className: "flex items-start gap-2 text-sm text-status-danger-text bg-status-danger-bg px-3 py-2 rounded-md",
|
|
135
|
+
children: [/* @__PURE__ */ h(s, { className: "w-4 h-4 mt-0.5 shrink-0" }), /* @__PURE__ */ h("span", { children: N })]
|
|
136
|
+
}),
|
|
137
|
+
C && /* @__PURE__ */ g("div", {
|
|
138
|
+
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
139
|
+
children: [/* @__PURE__ */ h(l, { className: "w-4 h-4 animate-spin" }), "Loading available plugins…"]
|
|
140
|
+
}),
|
|
141
|
+
!C && H.length > 0 && /* @__PURE__ */ g("section", { children: [/* @__PURE__ */ h("h3", {
|
|
142
|
+
className: "text-xs font-medium text-text-secondary uppercase tracking-wide mb-2",
|
|
143
|
+
children: "Already on this tab strip"
|
|
144
|
+
}), /* @__PURE__ */ h("ul", {
|
|
145
|
+
className: "space-y-1",
|
|
146
|
+
children: H.map((e) => /* @__PURE__ */ g("li", {
|
|
147
|
+
className: "flex items-center gap-2 text-sm text-text-primary",
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ h(c, { className: "w-4 h-4 text-status-success-text" }),
|
|
150
|
+
/* @__PURE__ */ h("span", {
|
|
151
|
+
className: "font-medium",
|
|
152
|
+
children: e.contribution.title
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ g("span", {
|
|
155
|
+
className: "text-xs text-text-muted",
|
|
156
|
+
children: [
|
|
157
|
+
"(",
|
|
158
|
+
e.pluginKey,
|
|
159
|
+
")"
|
|
160
|
+
]
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
}, e.contribution.id))
|
|
164
|
+
})] }),
|
|
165
|
+
!C && /* @__PURE__ */ g("section", { children: [/* @__PURE__ */ h("h3", {
|
|
166
|
+
className: "text-xs font-medium text-text-secondary uppercase tracking-wide mb-2",
|
|
167
|
+
children: "Available"
|
|
168
|
+
}), V.length === 0 ? /* @__PURE__ */ h("p", {
|
|
169
|
+
className: "text-sm text-text-muted",
|
|
170
|
+
children: "No additional plugins available in the catalog."
|
|
171
|
+
}) : /* @__PURE__ */ h("ul", {
|
|
172
|
+
className: "space-y-2",
|
|
173
|
+
children: V.map((e) => {
|
|
174
|
+
let t = j === e.packageName;
|
|
175
|
+
return /* @__PURE__ */ g("li", {
|
|
176
|
+
className: "flex items-center justify-between gap-3 border border-border-default rounded-md px-3 py-2",
|
|
177
|
+
children: [/* @__PURE__ */ g("div", {
|
|
178
|
+
className: "min-w-0",
|
|
179
|
+
children: [
|
|
180
|
+
/* @__PURE__ */ g("div", {
|
|
181
|
+
className: "text-sm font-medium text-text-primary truncate",
|
|
182
|
+
children: [e.name, e.category && /* @__PURE__ */ h("span", {
|
|
183
|
+
className: "ml-2 text-xs text-text-muted font-normal",
|
|
184
|
+
children: e.category
|
|
185
|
+
})]
|
|
186
|
+
}),
|
|
187
|
+
e.description && /* @__PURE__ */ h("div", {
|
|
188
|
+
className: "text-xs text-text-secondary truncate",
|
|
189
|
+
children: e.description
|
|
190
|
+
}),
|
|
191
|
+
/* @__PURE__ */ h("div", {
|
|
192
|
+
className: "text-[10px] text-text-muted font-mono mt-0.5",
|
|
193
|
+
children: e.packageName
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
}), /* @__PURE__ */ h("button", {
|
|
197
|
+
type: "button",
|
|
198
|
+
onClick: () => void U(e.packageName),
|
|
199
|
+
disabled: t || B.has(e.packageName),
|
|
200
|
+
className: "shrink-0 inline-flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
201
|
+
children: t ? /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(l, { className: "w-3.5 h-3.5 animate-spin" }), "Installing…"] }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h(u, { className: "w-3.5 h-3.5" }), "Add"] })
|
|
202
|
+
})]
|
|
203
|
+
}, e.packageName);
|
|
204
|
+
})
|
|
205
|
+
})] })
|
|
206
|
+
]
|
|
207
|
+
}),
|
|
208
|
+
/* @__PURE__ */ h("div", {
|
|
209
|
+
className: "px-5 py-3 border-t border-border-default flex items-center justify-end",
|
|
210
|
+
children: /* @__PURE__ */ h("button", {
|
|
211
|
+
type: "button",
|
|
212
|
+
onClick: v,
|
|
213
|
+
className: "text-sm text-text-secondary hover:text-text-primary",
|
|
214
|
+
children: "Done"
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
]
|
|
218
|
+
})
|
|
219
|
+
}, "overlay") }) : null;
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
export { _ as AddTabDialog };
|
|
223
|
+
|
|
224
|
+
//# sourceMappingURL=AddTabDialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AddTabDialog.js","names":[],"sources":["../../../src/components/plugins/AddTabDialog.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { X, Plus, Loader2, CheckCircle2, AlertTriangle } from 'lucide-react';\nimport { motion, AnimatePresence } from 'framer-motion';\n\nimport { agentAiMutate } from '@/services/aiApi';\nimport { agentApiPath } from '@/utils/agentApiPath';\n\ninterface CatalogEntry {\n packageName: string;\n name: string;\n description?: string;\n cliCommand?: string;\n category?: string;\n installed: boolean;\n}\n\ninterface CatalogResponse {\n plugins: CatalogEntry[];\n}\n\ninterface ContributionEntry {\n pluginKey: string;\n contribution: {\n mountPoint: string;\n id: string;\n title: string;\n };\n}\n\ninterface ContributionsResponse {\n contributions: ContributionEntry[];\n}\n\nexport interface AddTabDialogProps {\n isOpen: boolean;\n onClose: () => void;\n /** Which mount point the picker filters for (e.g. `'vibe.detailTab'`). */\n mountPoint: string;\n /** Agent id whose tunnel the picker queries. */\n agentId: string;\n /** Active profile on that agent. */\n profile: string;\n /** Called after a successful install so the host can refetch contributions. */\n onInstalled?: (packageName: string) => void;\n}\n\n/**\n * PR-10 \"+ Add tab\" picker. Lists available plugins from the agent's\n * catalog and lets the user install them inline. Once installed,\n * `onInstalled` fires and the host re-queries contributions so the new\n * tab shows up in the strip without a page refresh.\n *\n * Catalog entries are filtered down to the org-allow-list at the agent\n * boundary (the `/plugins/install` endpoint already enforces\n * `isTrustedPackage`), so this dialog can safely surface every catalog\n * entry without per-row filtering.\n */\nexport function AddTabDialog({\n isOpen,\n onClose,\n mountPoint,\n agentId,\n profile,\n onInstalled,\n}: AddTabDialogProps) {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [catalog, setCatalog] = useState<CatalogEntry[]>([]);\n const [contributions, setContributions] = useState<ContributionEntry[]>([]);\n const [installing, setInstalling] = useState<string | null>(null);\n const [installError, setInstallError] = useState<string | null>(null);\n const [installedRecently, setInstalledRecently] = useState<Set<string>>(new Set());\n const aliveRef = useRef(true);\n\n useEffect(() => {\n aliveRef.current = true;\n return () => {\n aliveRef.current = false;\n };\n }, []);\n\n // Modal-dialog UX: bind Escape to close + trap focus inside the\n // dialog container while it's open. Without these the modal\n // violates WCAG 2.4.3 (focus order) and standard keyboard\n // expectations.\n const dialogRef = useRef<HTMLDivElement | null>(null);\n useEffect(() => {\n if (!isOpen) return undefined;\n const previouslyFocused = (\n typeof document !== 'undefined' ? document.activeElement : null\n ) as HTMLElement | null;\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n return;\n }\n if (e.key !== 'Tab' || !dialogRef.current) return;\n const focusables = dialogRef.current.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n );\n if (focusables.length === 0) return;\n const first = focusables[0]!;\n const last = focusables[focusables.length - 1]!;\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n };\n document.addEventListener('keydown', handleKey);\n // Focus the dialog container so subsequent Tab cycles stay inside.\n setTimeout(() => dialogRef.current?.focus(), 0);\n return () => {\n document.removeEventListener('keydown', handleKey);\n previouslyFocused?.focus?.();\n };\n }, [isOpen, onClose]);\n\n // Reset the recent-install filter when the dialog's context changes\n // (different agent / profile / mount) or when it closes. Otherwise\n // a multi-agent flow keeps filtering out packages installed for the\n // previous agent context.\n useEffect(() => {\n setInstalledRecently(new Set());\n }, [agentId, profile, mountPoint, isOpen]);\n\n const fetchData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const [catalogResp, contributionsResp] = await Promise.all([\n agentAiMutate<CatalogResponse>(\n agentId,\n agentApiPath(profile, '/plugins/catalog'),\n 'GET',\n null\n ),\n agentAiMutate<ContributionsResponse>(\n agentId,\n agentApiPath(\n profile,\n `/plugins/contributions?mountPoint=${encodeURIComponent(mountPoint)}`\n ),\n 'GET',\n null\n ),\n ]);\n if (!aliveRef.current) return;\n setCatalog(catalogResp.plugins ?? []);\n setContributions(contributionsResp.contributions ?? []);\n } catch (err) {\n if (!aliveRef.current) return;\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n if (aliveRef.current) setLoading(false);\n }\n }, [agentId, profile, mountPoint]);\n\n useEffect(() => {\n if (isOpen) {\n void fetchData();\n }\n }, [isOpen, fetchData]);\n\n const installedPackages = useMemo(\n () => new Set(catalog.filter((c) => c.installed).map((c) => c.packageName)),\n [catalog]\n );\n\n // Available = catalog entries that aren't yet installed. The agent\n // doesn't tell us up-front WHICH catalog entries contribute to this\n // mountPoint (manifests aren't loaded until install), so we list them\n // all; the user picks; after install the host re-queries and the new\n // tab appears in the strip if the plugin contributes here.\n const available = useMemo(\n () => catalog.filter((c) => !c.installed && !installedRecently.has(c.packageName)),\n [catalog, installedRecently]\n );\n\n // Installed plugins whose contributions ARE for this mount point. Useful\n // as a \"what's already here\" hint so the user doesn't try to install\n // duplicates.\n const installedForThisMount = useMemo(\n () => contributions.filter((c) => c.contribution.mountPoint === mountPoint),\n [contributions, mountPoint]\n );\n\n const install = useCallback(\n async (packageName: string) => {\n setInstalling(packageName);\n setInstallError(null);\n try {\n await agentAiMutate(agentId, agentApiPath(profile, '/plugins/install'), 'POST', {\n packageName,\n });\n if (!aliveRef.current) return;\n setInstalledRecently((prev) => new Set(prev).add(packageName));\n onInstalled?.(packageName);\n // Refresh both lists so the UI reflects the new state.\n void fetchData();\n } catch (err) {\n if (!aliveRef.current) return;\n setInstallError(err instanceof Error ? err.message : String(err));\n } finally {\n if (aliveRef.current) setInstalling(null);\n }\n },\n [agentId, profile, onInstalled, fetchData]\n );\n\n if (!isOpen) return null;\n\n return (\n <AnimatePresence>\n <motion.div\n key=\"overlay\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n className=\"fixed inset-0 z-50 bg-bg-overlay flex items-center justify-center p-4\"\n onClick={onClose}\n >\n <motion.div\n ref={dialogRef}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n className=\"bg-bg-surface rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] overflow-hidden flex flex-col focus:outline-none\"\n onClick={(e) => e.stopPropagation()}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"add-tab-dialog-title\"\n tabIndex={-1}\n >\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border-default\">\n <div>\n <h2 id=\"add-tab-dialog-title\" className=\"text-base font-semibold text-text-primary\">\n Add tab\n </h2>\n <p className=\"text-xs text-text-secondary\">\n Install a UI plugin that contributes to{' '}\n <code className=\"font-mono\">{mountPoint}</code>\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-text-secondary hover:text-text-primary\"\n aria-label=\"Close\"\n >\n <X className=\"w-5 h-5\" />\n </button>\n </div>\n\n <div className=\"overflow-y-auto px-5 py-4 space-y-6\">\n {error && (\n <div className=\"flex items-start gap-2 text-sm text-status-danger-text bg-status-danger-bg px-3 py-2 rounded-md\">\n <AlertTriangle className=\"w-4 h-4 mt-0.5 shrink-0\" />\n <span>{error}</span>\n </div>\n )}\n {installError && (\n <div className=\"flex items-start gap-2 text-sm text-status-danger-text bg-status-danger-bg px-3 py-2 rounded-md\">\n <AlertTriangle className=\"w-4 h-4 mt-0.5 shrink-0\" />\n <span>{installError}</span>\n </div>\n )}\n\n {loading && (\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n Loading available plugins…\n </div>\n )}\n\n {!loading && installedForThisMount.length > 0 && (\n <section>\n <h3 className=\"text-xs font-medium text-text-secondary uppercase tracking-wide mb-2\">\n Already on this tab strip\n </h3>\n <ul className=\"space-y-1\">\n {installedForThisMount.map((c) => (\n <li\n key={c.contribution.id}\n className=\"flex items-center gap-2 text-sm text-text-primary\"\n >\n <CheckCircle2 className=\"w-4 h-4 text-status-success-text\" />\n <span className=\"font-medium\">{c.contribution.title}</span>\n <span className=\"text-xs text-text-muted\">({c.pluginKey})</span>\n </li>\n ))}\n </ul>\n </section>\n )}\n\n {!loading && (\n <section>\n <h3 className=\"text-xs font-medium text-text-secondary uppercase tracking-wide mb-2\">\n Available\n </h3>\n {available.length === 0 ? (\n <p className=\"text-sm text-text-muted\">\n No additional plugins available in the catalog.\n </p>\n ) : (\n <ul className=\"space-y-2\">\n {available.map((c) => {\n const isInstallingThis = installing === c.packageName;\n return (\n <li\n key={c.packageName}\n className=\"flex items-center justify-between gap-3 border border-border-default rounded-md px-3 py-2\"\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium text-text-primary truncate\">\n {c.name}\n {c.category && (\n <span className=\"ml-2 text-xs text-text-muted font-normal\">\n {c.category}\n </span>\n )}\n </div>\n {c.description && (\n <div className=\"text-xs text-text-secondary truncate\">\n {c.description}\n </div>\n )}\n <div className=\"text-[10px] text-text-muted font-mono mt-0.5\">\n {c.packageName}\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => void install(c.packageName)}\n disabled={isInstallingThis || installedPackages.has(c.packageName)}\n className=\"shrink-0 inline-flex items-center gap-1 px-2.5 py-1.5 text-xs font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {isInstallingThis ? (\n <>\n <Loader2 className=\"w-3.5 h-3.5 animate-spin\" />\n Installing…\n </>\n ) : (\n <>\n <Plus className=\"w-3.5 h-3.5\" />\n Add\n </>\n )}\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </section>\n )}\n </div>\n\n <div className=\"px-5 py-3 border-t border-border-default flex items-center justify-end\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Done\n </button>\n </div>\n </motion.div>\n </motion.div>\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
|