@burdenoff/microfe-vibecontrols 2026.601.13 → 2026.601.15
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/VibeControlsRoutes.js +6 -6
- package/dist/VibeControlsRoutes.js.map +1 -1
- package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
- package/dist/components/assistant/AssistantChatArea.js +1 -1
- package/dist/components/assistant/AssistantChatArea.js.map +1 -1
- package/package.json +1 -1
|
@@ -70,7 +70,7 @@ function re() {
|
|
|
70
70
|
}),
|
|
71
71
|
/* @__PURE__ */ c(a, {
|
|
72
72
|
path: "agents",
|
|
73
|
-
element:
|
|
73
|
+
element: /* @__PURE__ */ c(f, {})
|
|
74
74
|
}),
|
|
75
75
|
/* @__PURE__ */ c(a, {
|
|
76
76
|
path: "agents/new",
|
|
@@ -81,11 +81,11 @@ function re() {
|
|
|
81
81
|
}),
|
|
82
82
|
/* @__PURE__ */ c(a, {
|
|
83
83
|
path: "agents/:id",
|
|
84
|
-
element:
|
|
84
|
+
element: /* @__PURE__ */ c(p, {})
|
|
85
85
|
}),
|
|
86
86
|
/* @__PURE__ */ c(a, {
|
|
87
87
|
path: "sessions",
|
|
88
|
-
element:
|
|
88
|
+
element: /* @__PURE__ */ c(h, {})
|
|
89
89
|
}),
|
|
90
90
|
/* @__PURE__ */ c(a, {
|
|
91
91
|
path: "vibes",
|
|
@@ -112,7 +112,7 @@ function re() {
|
|
|
112
112
|
}),
|
|
113
113
|
/* @__PURE__ */ c(a, {
|
|
114
114
|
path: "sessions/:id",
|
|
115
|
-
element:
|
|
115
|
+
element: /* @__PURE__ */ c(g, {})
|
|
116
116
|
}),
|
|
117
117
|
/* @__PURE__ */ c(a, {
|
|
118
118
|
path: "ai",
|
|
@@ -169,7 +169,7 @@ function re() {
|
|
|
169
169
|
}),
|
|
170
170
|
/* @__PURE__ */ c(a, {
|
|
171
171
|
path: "targets/:id",
|
|
172
|
-
element:
|
|
172
|
+
element: /* @__PURE__ */ c(m, {})
|
|
173
173
|
}),
|
|
174
174
|
/* @__PURE__ */ c(a, {
|
|
175
175
|
path: "agent-graph",
|
|
@@ -295,7 +295,7 @@ function re() {
|
|
|
295
295
|
}),
|
|
296
296
|
/* @__PURE__ */ c(a, {
|
|
297
297
|
path: "logs",
|
|
298
|
-
element:
|
|
298
|
+
element: /* @__PURE__ */ c(F, {})
|
|
299
299
|
}),
|
|
300
300
|
/* @__PURE__ */ c(a, {
|
|
301
301
|
path: "settings",
|
|
@@ -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, useParams } 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 ScheduledJobDetailPage = React.lazy(() =>\n import('./pages/ScheduledJobDetailPage').then((m) => ({ default: m.ScheduledJobDetailPage }))\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);\nconst LogsPage = React.lazy(() =>\n import('./pages/LogsPage').then((m) => ({ default: m.LogsPage }))\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 PluginsCatalogPage = React.lazy(() =>\n import('./pages/PluginsCatalogPage').then((m) => ({ default: m.PluginsCatalogPage }))\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);\nconst AIBookmarksPage = React.lazy(() =>\n import('./pages/ai/AIBookmarksPage').then((m) => ({ default: m.AIBookmarksPage }))\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 * Legacy redirect: /ai-tools/<tab> → /ai-tools/ai/<tab>.\n *\n * Before the Plan / AI mode toggle the page was reachable directly at\n * /ai-tools/<tab>. New shape is /ai-tools/<mode>/<tab>. We keep the\n * legacy links working by mapping the captured `:tab` param: if it\n * resolves to a known AI sub-tab, redirect there; if it's literally\n * \"plan\", route to the Plan page; otherwise fall back to AI overview.\n */\nconst VALID_AI_TABS = new Set<string>([\n 'overview',\n 'templates',\n 'contexts',\n 'prompts',\n 'sessions',\n 'tasks',\n 'stats',\n 'playground',\n 'config',\n]);\n\nfunction LegacyAIToolsRedirect() {\n const { tab } = useParams<{ tab?: string }>();\n if (tab === 'plan') {\n return <Navigate to=\"/vibecontrols/ai-tools/plan\" replace />;\n }\n if (tab && VALID_AI_TABS.has(tab)) {\n return <Navigate to={`/vibecontrols/ai-tools/ai/${tab}`} replace />;\n }\n return <Navigate to=\"/vibecontrols/ai-tools/ai/overview\" replace />;\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 {/* Plugins catalog — searchable grid of every published plugin. */}\n <Route path=\"plugins\" element={gated('vibecontrols.vibes', <PluginsCatalogPage />)} />\n\n <Route path=\"agents\" element={gated('vibecontrols.agents', <AgentsLandingPage />)} />\n <Route path=\"agents/new\" element={<Navigate to=\"../agents?create=true\" replace />} />\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/new\" element={<Navigate to=\"../vibes?create=true\" replace />} />\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 {/* Saved messages — listed BEFORE ai/:tab so \"bookmarks\" is not consumed as a tab. */}\n <Route path=\"ai/bookmarks\" element={gated('vibecontrols.ai', <AIBookmarksPage />)} />\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 — Plan / AI modes:\n /ai-tools → /ai-tools/ai/overview (redirect)\n /ai-tools/plan → Plan mode (plannotator iframe)\n /ai-tools/ai → /ai-tools/ai/overview (redirect)\n /ai-tools/ai/:tab → AI mode with active sub-tab\n Legacy /ai-tools/<tab> URLs from before the Plan mode rollout\n redirect into the new shape via LegacyAIToolsRedirect. */}\n <Route path=\"ai-tools\" element={<Navigate to=\"ai/overview\" replace />} />\n <Route path=\"ai-tools/plan\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route path=\"ai-tools/ai\" element={<Navigate to=\"overview\" replace />} />\n <Route path=\"ai-tools/ai/:tab\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route path=\"ai-tools/:tab\" element={<LegacyAIToolsRedirect />} />\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 {/* ScheduledJob (wspace-scheduler-svc) — separate id space\n from VibeCalendarTask above, so it needs its own route. */}\n <Route\n path=\"calendar/scheduled-job/:jobId\"\n element={gated('vibecontrols.calendar', <ScheduledJobDetailPage />)}\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={gated('vibecontrols.agents', <LogsPage />)} />\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, useParams } 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 ScheduledJobDetailPage = React.lazy(() =>\n import('./pages/ScheduledJobDetailPage').then((m) => ({ default: m.ScheduledJobDetailPage }))\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);\nconst LogsPage = React.lazy(() =>\n import('./pages/LogsPage').then((m) => ({ default: m.LogsPage }))\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 PluginsCatalogPage = React.lazy(() =>\n import('./pages/PluginsCatalogPage').then((m) => ({ default: m.PluginsCatalogPage }))\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);\nconst AIBookmarksPage = React.lazy(() =>\n import('./pages/ai/AIBookmarksPage').then((m) => ({ default: m.AIBookmarksPage }))\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 * Legacy redirect: /ai-tools/<tab> → /ai-tools/ai/<tab>.\n *\n * Before the Plan / AI mode toggle the page was reachable directly at\n * /ai-tools/<tab>. New shape is /ai-tools/<mode>/<tab>. We keep the\n * legacy links working by mapping the captured `:tab` param: if it\n * resolves to a known AI sub-tab, redirect there; if it's literally\n * \"plan\", route to the Plan page; otherwise fall back to AI overview.\n */\nconst VALID_AI_TABS = new Set<string>([\n 'overview',\n 'templates',\n 'contexts',\n 'prompts',\n 'sessions',\n 'tasks',\n 'stats',\n 'playground',\n 'config',\n]);\n\nfunction LegacyAIToolsRedirect() {\n const { tab } = useParams<{ tab?: string }>();\n if (tab === 'plan') {\n return <Navigate to=\"/vibecontrols/ai-tools/plan\" replace />;\n }\n if (tab && VALID_AI_TABS.has(tab)) {\n return <Navigate to={`/vibecontrols/ai-tools/ai/${tab}`} replace />;\n }\n return <Navigate to=\"/vibecontrols/ai-tools/ai/overview\" replace />;\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 {/* Plugins catalog — searchable grid of every published plugin. */}\n <Route path=\"plugins\" element={gated('vibecontrols.vibes', <PluginsCatalogPage />)} />\n\n <Route path=\"agents\" element={<AgentsLandingPage />} />\n <Route path=\"agents/new\" element={<Navigate to=\"../agents?create=true\" replace />} />\n <Route path=\"agents/:id\" element={<AgentDetailsPage />} />\n <Route path=\"sessions\" element={<SessionsPage />} />\n <Route path=\"vibes\" element={gated('vibecontrols.vibes', <VibesPage />)} />\n <Route path=\"vibes/new\" element={<Navigate to=\"../vibes?create=true\" replace />} />\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 path=\"sessions/:id\" element={<SessionDetailsPage />} />\n {/* Agent Manager — multi-session tabbed UI (replaces old AI page) */}\n <Route path=\"ai\" element={gated('vibecontrols.ai', <AgentManagerPage />)} />\n {/* Saved messages — listed BEFORE ai/:tab so \"bookmarks\" is not consumed as a tab. */}\n <Route path=\"ai/bookmarks\" element={gated('vibecontrols.ai', <AIBookmarksPage />)} />\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 — Plan / AI modes:\n /ai-tools → /ai-tools/ai/overview (redirect)\n /ai-tools/plan → Plan mode (plannotator iframe)\n /ai-tools/ai → /ai-tools/ai/overview (redirect)\n /ai-tools/ai/:tab → AI mode with active sub-tab\n Legacy /ai-tools/<tab> URLs from before the Plan mode rollout\n redirect into the new shape via LegacyAIToolsRedirect. */}\n <Route path=\"ai-tools\" element={<Navigate to=\"ai/overview\" replace />} />\n <Route path=\"ai-tools/plan\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route path=\"ai-tools/ai\" element={<Navigate to=\"overview\" replace />} />\n <Route path=\"ai-tools/ai/:tab\" element={gated('vibecontrols.ai', <AIPage />)} />\n <Route path=\"ai-tools/:tab\" element={<LegacyAIToolsRedirect />} />\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={<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 {/* ScheduledJob (wspace-scheduler-svc) — separate id space\n from VibeCalendarTask above, so it needs its own route. */}\n <Route\n path=\"calendar/scheduled-job/:jobId\"\n element={gated('vibecontrols.calendar', <ScheduledJobDetailPage />)}\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={<LogsPage />} />\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentConnectionRecovery.js","names":[],"sources":["../../../src/components/agents/AgentConnectionRecovery.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { KeyRound, Link2, Loader2, ShieldCheck, AlertTriangle } from 'lucide-react';\n\nimport {\n useSetAgentApiKeyMutation,\n useUpdateAgentTunnelUrlMutation,\n} from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentConnectionRecoveryProps {\n agentId: string;\n currentTunnelUrl?: string | null;\n /** Refetch the agent after a successful in-place update. */\n onUpdated?: () => void;\n}\n\nconst CARD = 'rounded-lg border border-border-default bg-bg-surface p-4 sm:p-5';\nconst BTN =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50';\nconst INPUT =\n 'w-full px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 font-mono';\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Emergency connection recovery for an existing agent — used when gateway\n * auto-report is broken (so the agent can't refresh its own key/tunnel) and\n * the operator must fix it in place WITHOUT delete + re-add (which loses\n * sessions / notes / bookmarks).\n * - \"Update API key\": paste the value from `vibe key`; the backend probes the\n * agent with it and only saves if the agent accepts it.\n * - \"Update tunnel URL\": paste the new quick-tunnel URL; the backend verifies\n * it's the same machine (hostname) before saving.\n */\nexport function AgentConnectionRecovery({\n agentId,\n currentTunnelUrl,\n onUpdated,\n}: AgentConnectionRecoveryProps) {\n const tr = useTr();\n\n // ── API key ─────────────────────────────────────────────────────────────\n const [keyInput, setKeyInput] = useState('');\n const [setKey, { loading: settingKey }] = useSetAgentApiKeyMutation();\n const [keyResult, setKeyResult] = useState<{ ok: boolean; msg: string } | null>(null);\n\n const handleSetKey = async () => {\n setKeyResult(null);\n const key = keyInput.trim();\n if (!key) return;\n try {\n await setKey({ variables: { agentId, apiKey: key } });\n setKeyResult({\n ok: true,\n msg: tr('agentDetails.recovery.keySaved'
|
|
1
|
+
{"version":3,"file":"AgentConnectionRecovery.js","names":[],"sources":["../../../src/components/agents/AgentConnectionRecovery.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { KeyRound, Link2, Loader2, ShieldCheck, AlertTriangle } from 'lucide-react';\n\nimport {\n useSetAgentApiKeyMutation,\n useUpdateAgentTunnelUrlMutation,\n} from '@/generated/wspace-operations';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentConnectionRecoveryProps {\n agentId: string;\n currentTunnelUrl?: string | null;\n /** Refetch the agent after a successful in-place update. */\n onUpdated?: () => void;\n}\n\nconst CARD = 'rounded-lg border border-border-default bg-bg-surface p-4 sm:p-5';\nconst BTN =\n 'inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50';\nconst INPUT =\n 'w-full px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 font-mono';\n\nfunction errMsg(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Emergency connection recovery for an existing agent — used when gateway\n * auto-report is broken (so the agent can't refresh its own key/tunnel) and\n * the operator must fix it in place WITHOUT delete + re-add (which loses\n * sessions / notes / bookmarks).\n * - \"Update API key\": paste the value from `vibe key`; the backend probes the\n * agent with it and only saves if the agent accepts it.\n * - \"Update tunnel URL\": paste the new quick-tunnel URL; the backend verifies\n * it's the same machine (hostname) before saving.\n */\nexport function AgentConnectionRecovery({\n agentId,\n currentTunnelUrl,\n onUpdated,\n}: AgentConnectionRecoveryProps) {\n const tr = useTr();\n\n // ── API key ─────────────────────────────────────────────────────────────\n const [keyInput, setKeyInput] = useState('');\n const [setKey, { loading: settingKey }] = useSetAgentApiKeyMutation();\n const [keyResult, setKeyResult] = useState<{ ok: boolean; msg: string } | null>(null);\n\n const handleSetKey = async () => {\n setKeyResult(null);\n const key = keyInput.trim();\n if (!key) return;\n try {\n await setKey({ variables: { agentId, apiKey: key } });\n setKeyResult({\n ok: true,\n msg: tr(\n 'agentDetails.recovery.keySaved',\n 'API key validated and saved. The agent is reachable again.'\n ),\n });\n setKeyInput('');\n onUpdated?.();\n } catch (e) {\n setKeyResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n // ── Tunnel URL ──────────────────────────────────────────────────────────\n const [urlInput, setUrlInput] = useState(currentTunnelUrl ?? '');\n const [updateUrl, { loading: updatingUrl }] = useUpdateAgentTunnelUrlMutation();\n const [urlResult, setUrlResult] = useState<{ ok: boolean; msg: string } | null>(null);\n\n const handleUpdateUrl = async () => {\n setUrlResult(null);\n const url = urlInput.trim();\n if (!url) return;\n try {\n await updateUrl({ variables: { agentId, tunnelUrl: url } });\n setUrlResult({\n ok: true,\n msg: tr(\n 'agentDetails.recovery.urlSaved',\n 'Tunnel URL verified and updated. The agent is back online.'\n ),\n });\n onUpdated?.();\n } catch (e) {\n setUrlResult({ ok: false, msg: errMsg(e) });\n }\n };\n\n const result = (r: { ok: boolean; msg: string } | null) =>\n r ? (\n <p\n className={`mt-2 flex items-start gap-2 text-xs ${\n r.ok ? 'text-status-success-text' : 'text-status-error-text'\n }`}\n >\n {r.ok ? (\n <ShieldCheck className=\"size-4 flex-shrink-0 mt-0.5\" />\n ) : (\n <AlertTriangle className=\"size-4 flex-shrink-0 mt-0.5\" />\n )}\n <span>{r.msg}</span>\n </p>\n ) : null;\n\n return (\n <div className=\"space-y-4\">\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <KeyRound className=\"size-5 text-text-secondary\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.recovery.keyTitle', 'Update API key (no re-add)')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.recovery.keyHint',\n 'If the agent’s API key changed and it can’t auto-report (gateway auth down), paste the value from `vibe key` on the host. It’s validated against the agent before saving — your sessions and data stay intact.'\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row gap-2\">\n <input\n type=\"password\"\n autoComplete=\"off\"\n value={keyInput}\n onChange={(e) => setKeyInput(e.target.value)}\n placeholder=\"vcak_…\"\n className={INPUT}\n />\n <button\n type=\"button\"\n onClick={handleSetKey}\n disabled={settingKey || keyInput.trim().length === 0}\n className={BTN}\n >\n {settingKey ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <ShieldCheck className=\"size-4\" />\n )}\n {tr('agentDetails.recovery.validateSave', 'Validate & save')}\n </button>\n </div>\n {result(keyResult)}\n </section>\n\n <section className={CARD}>\n <div className=\"flex items-center gap-2 mb-1\">\n <Link2 className=\"size-5 text-text-secondary\" />\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('agentDetails.recovery.urlTitle', 'Update tunnel URL (re-pair)')}\n </h3>\n </div>\n <p className=\"text-xs text-text-muted mb-3\">\n {tr(\n 'agentDetails.recovery.urlHint',\n 'After a quick-tunnel rotation, paste the new URL here. The backend verifies it points at the same machine before saving — no re-registration, no data loss.'\n )}\n </p>\n <div className=\"flex flex-col sm:flex-row gap-2\">\n <input\n type=\"url\"\n value={urlInput}\n onChange={(e) => setUrlInput(e.target.value)}\n placeholder=\"https://….trycloudflare.com\"\n className={INPUT}\n />\n <button\n type=\"button\"\n onClick={handleUpdateUrl}\n disabled={updatingUrl || urlInput.trim().length === 0}\n className={BTN}\n >\n {updatingUrl ? (\n <Loader2 className=\"size-4 animate-spin\" />\n ) : (\n <Link2 className=\"size-4\" />\n )}\n {tr('agentDetails.recovery.verifyUpdate', 'Verify & update')}\n </button>\n </div>\n {result(urlResult)}\n </section>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -166,7 +166,7 @@ var j = () => {
|
|
|
166
166
|
v("ai-credits"), h("You've run out of AI credits for this billing cycle. Upgrade your plan to keep chatting."), U(a, "error", m, null);
|
|
167
167
|
return;
|
|
168
168
|
}
|
|
169
|
-
|
|
169
|
+
console.warn("[assistant] AI-credit pre-flight check failed with a non-quota error; proceeding — gateway @usage(checkQuota) still enforces the real budget downstream", e);
|
|
170
170
|
}
|
|
171
171
|
try {
|
|
172
172
|
let { sandboxId: t, sessionId: n } = await Z(a, m, i, u, f);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantChatArea.js","names":[],"sources":["../../../src/components/assistant/AssistantChatArea.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, type FC } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { AssistantChatInput } from './AssistantChatInput';\nimport { AssistantMessageList } from './AssistantMessageList';\nimport { AssistantModeSelector } from './AssistantModeSelector';\nimport { AssistantWelcome } from './AssistantWelcome';\nimport { useAssistantStore } from '@/store/assistantStore';\nimport {\n checkAssistantAiCredits,\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantArtifacts,\n getAssistantMessages,\n getAssistantSession,\n reportAssistantAiTokenUsage,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n type AssistantRawMessage,\n type AssistantSandboxAuthContext,\n} from '@/services/assistantApi';\nimport { gatherPageContext } from '@/utils/pageContext';\nimport { dispatchAssistantQuotaExhausted, notifyAiCreditsUpdated } from '@/utils/aiCredits';\nimport { isQuotaExhaustedError } from '@/utils/quotaUtils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type {\n AssistantArtifact,\n AssistantConversationStatus,\n AssistantMode,\n Message,\n} from '@/types/assistant';\n\n// How long the client streams progress before giving up on a turn. Chat replies\n// (general / api-calls) finish in seconds; a vibe-plugins build is a multi-step\n// pipeline (read docs → scaffold → bun install → bun build → checklist) that runs\n// for minutes, so it gets a much larger budget. The sandbox TTL is auto-extended\n// every 30s during the poll loop, so a longer budget never outlives the sandbox.\nconst STREAM_BUDGET_MS: Record<AssistantMode, number> = {\n general: 180_000,\n 'api-calls': 180_000,\n 'vibe-plugins': 600_000,\n};\nconst DEFAULT_STREAM_BUDGET_MS = 180_000;\n\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId'\n ? 'burdenoff-active-context-workspace'\n : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as {\n workspaceId?: string;\n organizationId?: string;\n };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId');\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\nfunction isRecoverableAssistantError(error: unknown): boolean {\n const message =\n error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n 'session mode mismatch',\n ].some((fragment) => message.includes(fragment));\n}\n\nfunction sanitizeAssistantResponse(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n return message.info?.time?.created ?? 0;\n}\n\nfunction getAssistantText(parts: AssistantRawMessage['parts']): string {\n return (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getToolProgress(parts: AssistantRawMessage['parts']): string[] {\n return (parts ?? [])\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildAssistantProgress(\n messages: AssistantRawMessage[],\n sinceMs: number\n): {\n content: string;\n done: boolean;\n tokens?: { input: number; output: number };\n} {\n const relevant = messages\n .filter(\n (message) => message.info?.role === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs\n )\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n if (relevant.length === 0) {\n return { content: 'Thinking...', done: false };\n }\n\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest.parts);\n const toolProgress = getToolProgress(latest.parts);\n const content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking...';\n\n return {\n content,\n done: Boolean(latest.info?.time?.completed) && (Boolean(text) || toolProgress.length > 0),\n tokens: latest.info?.tokens,\n };\n}\n\nfunction getConversationStatusMessage(status: AssistantConversationStatus): string {\n switch (status) {\n case 'provisioning':\n return 'Starting assistant environment...';\n case 'connecting':\n return 'Connecting to assistant...';\n case 'streaming':\n return 'Thinking...';\n default:\n return '';\n }\n}\n\nexport const AssistantChatArea: FC = () => {\n const tr = useTr();\n const apollo = useGatewayClient('workspace');\n const { getAccessToken, getWorkspaceToken, userId } = useAuthToken();\n\n const {\n conversations,\n activeConversationId,\n mode,\n processingByConversationId,\n setMode,\n setConversationMode,\n setActiveConversation,\n createConversation,\n addMessage,\n updateMessage,\n patchMessage,\n setConversationProcessing,\n clearConversationProcessing,\n setBackendSessionId,\n clearBackendSessionId,\n setSandbox,\n clearSandbox,\n } = useAssistantStore();\n\n const activeConversation = conversations.find(\n (conversation) => conversation.id === activeConversationId\n );\n const messages = activeConversation?.messages ?? [];\n const activeProcessing = activeConversationId\n ? processingByConversationId[activeConversationId]\n : undefined;\n const activeStreamingMessageId = activeProcessing?.messageId ?? null;\n const activeIsProcessing =\n activeProcessing?.status === 'provisioning' ||\n activeProcessing?.status === 'connecting' ||\n activeProcessing?.status === 'streaming';\n\n const updateConversationStage = useCallback(\n (\n conversationId: string,\n assistantMessageId: string,\n status: AssistantConversationStatus,\n content?: string\n ) => {\n setConversationProcessing(conversationId, status, assistantMessageId, null);\n if (content) {\n updateMessage(conversationId, assistantMessageId, content);\n } else {\n updateMessage(conversationId, assistantMessageId, getConversationStatusMessage(status));\n }\n },\n [setConversationProcessing, updateMessage]\n );\n\n const ensureAssistantRuntime = useCallback(\n async (\n conversationId: string,\n assistantMessageId: string,\n currentMode: AssistantMode,\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let currentSandboxId =\n useAssistantStore.getState().sandboxesByMode[currentMode]?.sandboxId ?? null;\n\n if (!currentSandboxId) {\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'provisioning',\n 'Looking for existing environment...'\n );\n const existingId = await findExistingSandbox(apollo, workspaceId, currentMode, authContext);\n\n if (existingId) {\n currentSandboxId = existingId;\n setSandbox(currentMode, currentSandboxId, 'provisioning');\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'provisioning',\n 'Reusing assistant environment...'\n );\n await waitForSandboxReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 300_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'provisioning', message)\n );\n await waitForAssistantServiceReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 90_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'connecting', message)\n );\n setSandbox(currentMode, currentSandboxId, 'running');\n } else {\n if (currentMode === 'api-calls' && !getAccessToken()) {\n throw new Error(\n 'API Calls mode requires an authenticated session. Please sign in again.'\n );\n }\n\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'provisioning',\n 'Starting assistant environment...'\n );\n setSandbox(currentMode, null, 'provisioning');\n currentSandboxId = await createAssistantSandbox(\n apollo,\n currentMode,\n workspaceId,\n authContext\n );\n\n setSandbox(currentMode, currentSandboxId, 'provisioning');\n await waitForSandboxReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 300_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'provisioning', message)\n );\n await waitForAssistantServiceReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 90_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'connecting', message)\n );\n setSandbox(currentMode, currentSandboxId, 'running');\n }\n }\n\n let sessionId =\n useAssistantStore\n .getState()\n .conversations.find((conversation) => conversation.id === conversationId)\n ?.backendSessionId ?? null;\n\n if (sessionId) {\n try {\n const session = await getAssistantSession(\n apollo,\n currentSandboxId,\n workspaceId,\n sessionId,\n authContext\n );\n if (session.mode !== currentMode) {\n throw new Error(\n `Session mode mismatch: expected ${currentMode}, received ${session.mode}`\n );\n }\n } catch {\n clearBackendSessionId(conversationId);\n sessionId = null;\n }\n }\n\n if (!sessionId) {\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'connecting',\n 'Preparing session...'\n );\n const result = await createAssistantSession(\n apollo,\n currentSandboxId,\n workspaceId,\n currentMode,\n authContext\n );\n sessionId = result.sessionId;\n setBackendSessionId(conversationId, sessionId);\n }\n\n return {\n sandboxId: currentSandboxId,\n sessionId,\n };\n },\n [\n apollo,\n clearBackendSessionId,\n getAccessToken,\n setBackendSessionId,\n setSandbox,\n updateConversationStage,\n ]\n );\n\n const handleSend = useCallback(\n async (content: string) => {\n // Only block re-entry while a turn is genuinely in-flight. Earlier code\n // checked for *any* entry in the map, which stuck around as `complete`\n // / `error` after the first turn — making every subsequent message\n // silently disappear (the input cleared but handleSend bailed before\n // adding the user message to the conversation).\n if (activeConversationId) {\n const inflightStatus = processingByConversationId[activeConversationId]?.status;\n if (\n inflightStatus === 'provisioning' ||\n inflightStatus === 'connecting' ||\n inflightStatus === 'streaming'\n ) {\n return;\n }\n }\n\n const selectedMode = useAssistantStore.getState().mode;\n let conversationId = activeConversationId;\n const currentConversation = conversationId\n ? useAssistantStore\n .getState()\n .conversations.find((conversation) => conversation.id === conversationId)\n : undefined;\n\n if (!conversationId) {\n conversationId = createConversation(undefined, selectedMode);\n } else if (\n currentConversation &&\n currentConversation.mode !== selectedMode &&\n (currentConversation.messages.length > 0 || currentConversation.backendSessionId)\n ) {\n conversationId = createConversation(undefined, selectedMode);\n } else if (currentConversation && currentConversation.mode !== selectedMode) {\n setConversationMode(conversationId, selectedMode);\n }\n\n if (!conversationId) return;\n\n const workspaceId = getWorkspaceId();\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n\n const userMessage: Message = {\n id: generateId(),\n role: 'user',\n content,\n timestamp: new Date().toISOString(),\n };\n addMessage(conversationId, userMessage);\n\n const assistantMessageId = generateId();\n addMessage(conversationId, {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n timestamp: new Date().toISOString(),\n });\n\n const applyAssistantResponse = (\n response: string,\n artifacts?: AssistantArtifact[],\n sessionId?: string,\n sandboxId?: string\n ) => {\n patchMessage(conversationId, assistantMessageId, {\n content: sanitizeAssistantResponse(response),\n metadata:\n artifacts?.length || sessionId || sandboxId\n ? {\n artifacts,\n mode: selectedMode,\n sessionId,\n sandboxId,\n }\n : undefined,\n });\n };\n\n const sendWithRealBackend = async (attempt: 1 | 2 = 1): Promise<void> => {\n // Pre-flight AI-credit gate. The wspace gateway's @usage(checkQuota)\n // rejects with 429 QUOTA_EXHAUSTED when the monthly token budget is\n // depleted — block the send (don't provision a sandbox or dispatch the\n // prompt) and surface the upgrade dialog instead of a generic error.\n try {\n await checkAssistantAiCredits(apollo, workspaceId, authContext);\n } catch (creditError) {\n if (isQuotaExhaustedError(creditError)) {\n dispatchAssistantQuotaExhausted('ai-credits');\n applyAssistantResponse(\n \"You've run out of AI credits for this billing cycle. Upgrade your plan to keep chatting.\"\n );\n setConversationProcessing(conversationId, 'error', assistantMessageId, null);\n return;\n }\n throw creditError;\n }\n\n try {\n const { sandboxId, sessionId } = await ensureAssistantRuntime(\n conversationId,\n assistantMessageId,\n selectedMode,\n workspaceId,\n authContext\n );\n\n updateConversationStage(conversationId, assistantMessageId, 'streaming', 'Thinking...');\n const promptStartedAt = Date.now();\n await sendAssistantPromptAsync(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n content,\n selectedMode,\n gatherPageContext(),\n authContext\n );\n\n let result = buildAssistantProgress([], promptStartedAt);\n const timeoutAt =\n Date.now() + (STREAM_BUDGET_MS[selectedMode] ?? DEFAULT_STREAM_BUDGET_MS);\n let lastTtlExtensionAt = Date.now();\n\n while (Date.now() < timeoutAt) {\n const sessionMessages = await getAssistantMessages(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n authContext,\n 50\n );\n\n result = buildAssistantProgress(sessionMessages, promptStartedAt);\n patchMessage(conversationId, assistantMessageId, {\n content: sanitizeAssistantResponse(result.content),\n });\n\n if (result.done) break;\n\n if (Date.now() - lastTtlExtensionAt > 30_000) {\n await extendAssistantSandboxTTL(\n apollo,\n sandboxId,\n workspaceId,\n 600,\n authContext\n ).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, 1500));\n }\n\n // For non-build modes a timeout is a hard failure. For vibe-plugins the\n // prompt runs async server-side (/sessions/:id/prompt-async) and keeps\n // writing artifacts after the poll budget elapses, so we surface whatever\n // it has produced instead of discarding the turn.\n if (!result.done && selectedMode !== 'vibe-plugins') {\n throw new Error('Assistant response timed out while streaming progress');\n }\n\n const artifacts =\n selectedMode === 'vibe-plugins'\n ? await getAssistantArtifacts(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n authContext\n ).catch(() => [])\n : undefined;\n\n if (!result.done) {\n // vibe-plugins build still running in the background. Append a note so\n // the user knows the answer is partial and the artifacts will finish.\n result = {\n ...result,\n content: `${result.content}\\n\\n_Still building in the background — any artifacts below will finish shortly. Re-open this conversation to pick up the completed plugin._`,\n };\n }\n\n applyAssistantResponse(result.content, artifacts, sessionId, sandboxId);\n\n if (result.tokens) {\n patchMessage(conversationId, assistantMessageId, { tokens: result.tokens });\n // Charge the real token usage against the AI-credits quota (the\n // gateway records it via @usage(trackUsage)). We AWAIT it before\n // marking the turn complete / re-enabling input: otherwise a rapid\n // follow-up send would run its pre-flight checkAiCredits against a\n // stale balance (this turn's charge still in flight) and could\n // dispatch a prompt that should have been blocked, letting fast\n // sends bypass the credit cap. Still best-effort — a charge failure\n // never blocks the displayed answer.\n try {\n await reportAssistantAiTokenUsage(\n apollo,\n workspaceId,\n sessionId,\n result.tokens,\n authContext\n );\n notifyAiCreditsUpdated();\n } catch {\n // ignore — server-side @usage tracking is the source of truth\n }\n }\n setConversationProcessing(conversationId, 'complete', assistantMessageId, null);\n } catch (error) {\n if (attempt === 1 && isRecoverableAssistantError(error)) {\n clearBackendSessionId(conversationId);\n clearSandbox(selectedMode);\n return sendWithRealBackend(2);\n }\n\n throw error;\n }\n };\n\n try {\n if (!workspaceId) {\n throw new Error('Assistant backend is unavailable without an active workspace context.');\n }\n await sendWithRealBackend();\n } catch (error) {\n // A quota error reaching here is the sandbox-environment wall hit\n // during runtime provisioning (createSandbox @usage). Surface the\n // upgrade dialog instead of a generic failure (the AI-credit wall is\n // already handled by the pre-flight gate above).\n if (isQuotaExhaustedError(error)) {\n dispatchAssistantQuotaExhausted('sandbox');\n applyAssistantResponse(\n \"You've reached your sandbox limit on the current plan. Upgrade to start the AI assistant.\"\n );\n setConversationProcessing(conversationId, 'error', assistantMessageId, null);\n return;\n }\n const errorMessage = error instanceof Error ? error.message : 'Something went wrong';\n setConversationProcessing(conversationId, 'error', assistantMessageId, errorMessage);\n updateMessage(\n conversationId,\n assistantMessageId,\n `Sorry, an error occurred: ${errorMessage}. Please try again.`\n );\n }\n },\n [\n activeConversationId,\n addMessage,\n apollo,\n clearBackendSessionId,\n clearSandbox,\n conversations,\n createConversation,\n ensureAssistantRuntime,\n getAccessToken,\n getWorkspaceToken,\n patchMessage,\n processingByConversationId,\n setBackendSessionId,\n setConversationMode,\n setConversationProcessing,\n updateConversationStage,\n updateMessage,\n userId,\n ]\n );\n\n const handleSuggestionClick = useCallback(\n (suggestion: string) => {\n void handleSend(suggestion);\n },\n [handleSend]\n );\n\n // Auto-send any prompt that was queued by `useOpenAssistantHelp` (from\n // the shared GetHelpButton). We keep the latest handleSend in a ref so\n // the subscription effect below doesn't need to tear down on every\n // render — the store subscription lives for the component lifetime and\n // always calls the freshest handler.\n const handleSendRef = useRef(handleSend);\n useEffect(() => {\n handleSendRef.current = handleSend;\n }, [handleSend]);\n\n useEffect(() => {\n // Flush any prompt that was queued before this component mounted.\n const initial = useAssistantStore.getState().consumePendingPrompt();\n if (initial) {\n void handleSendRef.current(initial);\n }\n\n // Watch for new prompts queued while we're already mounted.\n const unsubscribe = useAssistantStore.subscribe((state, prev) => {\n if (state.pendingPrompt && state.pendingPrompt !== prev.pendingPrompt) {\n const queued = useAssistantStore.getState().consumePendingPrompt();\n if (queued) {\n void handleSendRef.current(queued);\n }\n }\n });\n return unsubscribe;\n }, []);\n\n const handleModeChange = useCallback(\n (newMode: AssistantMode) => {\n const currentConversation = activeConversationId\n ? useAssistantStore\n .getState()\n .conversations.find((conversation) => conversation.id === activeConversationId)\n : undefined;\n\n if (\n currentConversation &&\n (currentConversation.messages.length > 0 || currentConversation.backendSessionId)\n ) {\n if (currentConversation.mode !== newMode) {\n const reusableDraft = useAssistantStore\n .getState()\n .conversations.find(\n (conversation) =>\n conversation.mode === newMode &&\n conversation.messages.length === 0 &&\n !conversation.backendSessionId &&\n !useAssistantStore.getState().processingByConversationId[conversation.id]\n );\n\n if (reusableDraft) {\n setActiveConversation(reusableDraft.id);\n } else {\n createConversation(undefined, newMode);\n }\n }\n } else if (activeConversationId) {\n setConversationMode(activeConversationId, newMode);\n }\n\n setMode(newMode);\n },\n [activeConversationId, createConversation, setActiveConversation, setConversationMode, setMode]\n );\n\n return (\n <div className=\"flex flex-col flex-1 overflow-hidden pt-3\">\n {messages.length === 0 ? (\n <AssistantWelcome mode={mode} onSuggestionClick={handleSuggestionClick} />\n ) : (\n <AssistantMessageList messages={messages} streamingMessageId={activeStreamingMessageId} />\n )}\n\n <div>\n <div className=\"px-3 pb-1\">\n <AssistantModeSelector mode={mode} onModeChange={handleModeChange} />\n </div>\n <AssistantChatInput\n onSend={(value) => void handleSend(value)}\n disabled={activeIsProcessing}\n placeholder={tr(\n 'vibecontrols.assistant.chatArea.placeholder',\n `Ask about ${mode.replace(/-/g, ' ')}...`\n )}\n />\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssistantChatArea.js","names":[],"sources":["../../../src/components/assistant/AssistantChatArea.tsx"],"sourcesContent":["import { useCallback, useEffect, useRef, type FC } from 'react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { AssistantChatInput } from './AssistantChatInput';\nimport { AssistantMessageList } from './AssistantMessageList';\nimport { AssistantModeSelector } from './AssistantModeSelector';\nimport { AssistantWelcome } from './AssistantWelcome';\nimport { useAssistantStore } from '@/store/assistantStore';\nimport {\n checkAssistantAiCredits,\n createAssistantSandbox,\n createAssistantSession,\n extendAssistantSandboxTTL,\n findExistingSandbox,\n getAssistantArtifacts,\n getAssistantMessages,\n getAssistantSession,\n reportAssistantAiTokenUsage,\n sendAssistantPromptAsync,\n waitForAssistantServiceReady,\n waitForSandboxReady,\n type AssistantRawMessage,\n type AssistantSandboxAuthContext,\n} from '@/services/assistantApi';\nimport { gatherPageContext } from '@/utils/pageContext';\nimport { dispatchAssistantQuotaExhausted, notifyAiCreditsUpdated } from '@/utils/aiCredits';\nimport { isQuotaExhaustedError } from '@/utils/quotaUtils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type {\n AssistantArtifact,\n AssistantConversationStatus,\n AssistantMode,\n Message,\n} from '@/types/assistant';\n\n// How long the client streams progress before giving up on a turn. Chat replies\n// (general / api-calls) finish in seconds; a vibe-plugins build is a multi-step\n// pipeline (read docs → scaffold → bun install → bun build → checklist) that runs\n// for minutes, so it gets a much larger budget. The sandbox TTL is auto-extended\n// every 30s during the poll loop, so a longer budget never outlives the sandbox.\nconst STREAM_BUDGET_MS: Record<AssistantMode, number> = {\n general: 180_000,\n 'api-calls': 180_000,\n 'vibe-plugins': 600_000,\n};\nconst DEFAULT_STREAM_BUDGET_MS = 180_000;\n\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction getProfileContextValue(key: 'workspaceId' | 'organizationId'): string {\n try {\n const activeContextKey =\n key === 'workspaceId'\n ? 'burdenoff-active-context-workspace'\n : 'burdenoff-active-context-organization';\n const activeContextValue = localStorage.getItem(activeContextKey);\n if (activeContextValue) return activeContextValue;\n\n const activeProfileId = sessionStorage.getItem('bf-active-profile');\n if (!activeProfileId) return '';\n const raw = localStorage.getItem(`bf-p-${activeProfileId}-context`);\n if (!raw) return '';\n const context = JSON.parse(raw) as {\n workspaceId?: string;\n organizationId?: string;\n };\n return context[key] ?? '';\n } catch {\n return '';\n }\n}\n\nfunction getWorkspaceId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('workspace') ?? getProfileContextValue('workspaceId');\n}\n\nfunction getOrganizationId(): string {\n const params = new URLSearchParams(window.location.search);\n return params.get('org') ?? getProfileContextValue('organizationId');\n}\n\nfunction isRecoverableAssistantError(error: unknown): boolean {\n const message =\n error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();\n\n if (\n message.includes('rate limit exceeded') ||\n message.includes('unauthorized') ||\n message.includes('k8s api error 401')\n ) {\n return false;\n }\n\n return [\n 'sandbox not found',\n 'sandbox is not running',\n 'sandbox service not available yet',\n 'sandbox failed',\n 'sandbox startup timed out',\n 'assistant service did not become healthy',\n 'proxy error: 404',\n 'proxy error: 502',\n 'proxy error: 503',\n 'session mode mismatch',\n ].some((fragment) => message.includes(fragment));\n}\n\nfunction sanitizeAssistantResponse(response: string): string {\n return response\n .replace(/(Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/(X-Workspace-Authorization\\s*:\\s*Bearer\\s+)[^\\s\\n]+/gi, '$1[REDACTED]')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9._-]+\\.[A-Za-z0-9._-]+\\b/g, '[REDACTED_JWT]')\n .replace(/\\bsk-ant-[A-Za-z0-9-]+\\b/g, '[REDACTED_API_KEY]');\n}\n\nfunction getRawMessageCreatedAt(message: AssistantRawMessage): number {\n return message.info?.time?.created ?? 0;\n}\n\nfunction getAssistantText(parts: AssistantRawMessage['parts']): string {\n return (parts ?? [])\n .filter((part) => part.type === 'text' && typeof part.text === 'string')\n .map((part) => part.text?.trim() ?? '')\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getToolProgress(parts: AssistantRawMessage['parts']): string[] {\n return (parts ?? [])\n .filter((part) => part.type === 'tool' && part.tool)\n .map((part) => {\n const status = part.state?.status ?? 'running';\n const tool = part.tool ?? 'tool';\n if (status === 'completed') return `Completed: ${tool}`;\n if (status === 'failed') return `Failed: ${tool}`;\n return `Running: ${tool}`;\n });\n}\n\nfunction buildAssistantProgress(\n messages: AssistantRawMessage[],\n sinceMs: number\n): {\n content: string;\n done: boolean;\n tokens?: { input: number; output: number };\n} {\n const relevant = messages\n .filter(\n (message) => message.info?.role === 'assistant' && getRawMessageCreatedAt(message) >= sinceMs\n )\n .sort((left, right) => getRawMessageCreatedAt(left) - getRawMessageCreatedAt(right));\n\n if (relevant.length === 0) {\n return { content: 'Thinking...', done: false };\n }\n\n const latest = relevant[relevant.length - 1]!;\n const text = getAssistantText(latest.parts);\n const toolProgress = getToolProgress(latest.parts);\n const content = [text, ...toolProgress].filter(Boolean).join('\\n\\n') || 'Thinking...';\n\n return {\n content,\n done: Boolean(latest.info?.time?.completed) && (Boolean(text) || toolProgress.length > 0),\n tokens: latest.info?.tokens,\n };\n}\n\nfunction getConversationStatusMessage(status: AssistantConversationStatus): string {\n switch (status) {\n case 'provisioning':\n return 'Starting assistant environment...';\n case 'connecting':\n return 'Connecting to assistant...';\n case 'streaming':\n return 'Thinking...';\n default:\n return '';\n }\n}\n\nexport const AssistantChatArea: FC = () => {\n const tr = useTr();\n const apollo = useGatewayClient('workspace');\n const { getAccessToken, getWorkspaceToken, userId } = useAuthToken();\n\n const {\n conversations,\n activeConversationId,\n mode,\n processingByConversationId,\n setMode,\n setConversationMode,\n setActiveConversation,\n createConversation,\n addMessage,\n updateMessage,\n patchMessage,\n setConversationProcessing,\n clearConversationProcessing,\n setBackendSessionId,\n clearBackendSessionId,\n setSandbox,\n clearSandbox,\n } = useAssistantStore();\n\n const activeConversation = conversations.find(\n (conversation) => conversation.id === activeConversationId\n );\n const messages = activeConversation?.messages ?? [];\n const activeProcessing = activeConversationId\n ? processingByConversationId[activeConversationId]\n : undefined;\n const activeStreamingMessageId = activeProcessing?.messageId ?? null;\n const activeIsProcessing =\n activeProcessing?.status === 'provisioning' ||\n activeProcessing?.status === 'connecting' ||\n activeProcessing?.status === 'streaming';\n\n const updateConversationStage = useCallback(\n (\n conversationId: string,\n assistantMessageId: string,\n status: AssistantConversationStatus,\n content?: string\n ) => {\n setConversationProcessing(conversationId, status, assistantMessageId, null);\n if (content) {\n updateMessage(conversationId, assistantMessageId, content);\n } else {\n updateMessage(conversationId, assistantMessageId, getConversationStatusMessage(status));\n }\n },\n [setConversationProcessing, updateMessage]\n );\n\n const ensureAssistantRuntime = useCallback(\n async (\n conversationId: string,\n assistantMessageId: string,\n currentMode: AssistantMode,\n workspaceId: string,\n authContext: AssistantSandboxAuthContext\n ): Promise<{ sandboxId: string; sessionId: string }> => {\n let currentSandboxId =\n useAssistantStore.getState().sandboxesByMode[currentMode]?.sandboxId ?? null;\n\n if (!currentSandboxId) {\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'provisioning',\n 'Looking for existing environment...'\n );\n const existingId = await findExistingSandbox(apollo, workspaceId, currentMode, authContext);\n\n if (existingId) {\n currentSandboxId = existingId;\n setSandbox(currentMode, currentSandboxId, 'provisioning');\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'provisioning',\n 'Reusing assistant environment...'\n );\n await waitForSandboxReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 300_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'provisioning', message)\n );\n await waitForAssistantServiceReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 90_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'connecting', message)\n );\n setSandbox(currentMode, currentSandboxId, 'running');\n } else {\n if (currentMode === 'api-calls' && !getAccessToken()) {\n throw new Error(\n 'API Calls mode requires an authenticated session. Please sign in again.'\n );\n }\n\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'provisioning',\n 'Starting assistant environment...'\n );\n setSandbox(currentMode, null, 'provisioning');\n currentSandboxId = await createAssistantSandbox(\n apollo,\n currentMode,\n workspaceId,\n authContext\n );\n\n setSandbox(currentMode, currentSandboxId, 'provisioning');\n await waitForSandboxReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 300_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'provisioning', message)\n );\n await waitForAssistantServiceReady(\n apollo,\n currentSandboxId,\n workspaceId,\n authContext,\n 90_000,\n (message) =>\n updateConversationStage(conversationId, assistantMessageId, 'connecting', message)\n );\n setSandbox(currentMode, currentSandboxId, 'running');\n }\n }\n\n let sessionId =\n useAssistantStore\n .getState()\n .conversations.find((conversation) => conversation.id === conversationId)\n ?.backendSessionId ?? null;\n\n if (sessionId) {\n try {\n const session = await getAssistantSession(\n apollo,\n currentSandboxId,\n workspaceId,\n sessionId,\n authContext\n );\n if (session.mode !== currentMode) {\n throw new Error(\n `Session mode mismatch: expected ${currentMode}, received ${session.mode}`\n );\n }\n } catch {\n clearBackendSessionId(conversationId);\n sessionId = null;\n }\n }\n\n if (!sessionId) {\n updateConversationStage(\n conversationId,\n assistantMessageId,\n 'connecting',\n 'Preparing session...'\n );\n const result = await createAssistantSession(\n apollo,\n currentSandboxId,\n workspaceId,\n currentMode,\n authContext\n );\n sessionId = result.sessionId;\n setBackendSessionId(conversationId, sessionId);\n }\n\n return {\n sandboxId: currentSandboxId,\n sessionId,\n };\n },\n [\n apollo,\n clearBackendSessionId,\n getAccessToken,\n setBackendSessionId,\n setSandbox,\n updateConversationStage,\n ]\n );\n\n const handleSend = useCallback(\n async (content: string) => {\n // Only block re-entry while a turn is genuinely in-flight. Earlier code\n // checked for *any* entry in the map, which stuck around as `complete`\n // / `error` after the first turn — making every subsequent message\n // silently disappear (the input cleared but handleSend bailed before\n // adding the user message to the conversation).\n if (activeConversationId) {\n const inflightStatus = processingByConversationId[activeConversationId]?.status;\n if (\n inflightStatus === 'provisioning' ||\n inflightStatus === 'connecting' ||\n inflightStatus === 'streaming'\n ) {\n return;\n }\n }\n\n const selectedMode = useAssistantStore.getState().mode;\n let conversationId = activeConversationId;\n const currentConversation = conversationId\n ? useAssistantStore\n .getState()\n .conversations.find((conversation) => conversation.id === conversationId)\n : undefined;\n\n if (!conversationId) {\n conversationId = createConversation(undefined, selectedMode);\n } else if (\n currentConversation &&\n currentConversation.mode !== selectedMode &&\n (currentConversation.messages.length > 0 || currentConversation.backendSessionId)\n ) {\n conversationId = createConversation(undefined, selectedMode);\n } else if (currentConversation && currentConversation.mode !== selectedMode) {\n setConversationMode(conversationId, selectedMode);\n }\n\n if (!conversationId) return;\n\n const workspaceId = getWorkspaceId();\n const authContext: AssistantSandboxAuthContext = {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n userId,\n organizationId: getOrganizationId(),\n };\n\n const userMessage: Message = {\n id: generateId(),\n role: 'user',\n content,\n timestamp: new Date().toISOString(),\n };\n addMessage(conversationId, userMessage);\n\n const assistantMessageId = generateId();\n addMessage(conversationId, {\n id: assistantMessageId,\n role: 'assistant',\n content: '',\n timestamp: new Date().toISOString(),\n });\n\n const applyAssistantResponse = (\n response: string,\n artifacts?: AssistantArtifact[],\n sessionId?: string,\n sandboxId?: string\n ) => {\n patchMessage(conversationId, assistantMessageId, {\n content: sanitizeAssistantResponse(response),\n metadata:\n artifacts?.length || sessionId || sandboxId\n ? {\n artifacts,\n mode: selectedMode,\n sessionId,\n sandboxId,\n }\n : undefined,\n });\n };\n\n const sendWithRealBackend = async (attempt: 1 | 2 = 1): Promise<void> => {\n // Pre-flight AI-credit gate. The wspace gateway's @usage(checkQuota)\n // rejects with 429 QUOTA_EXHAUSTED when the monthly token budget is\n // depleted — block the send (don't provision a sandbox or dispatch the\n // prompt) and surface the upgrade dialog instead of a generic error.\n try {\n await checkAssistantAiCredits(apollo, workspaceId, authContext);\n } catch (creditError) {\n if (isQuotaExhaustedError(creditError)) {\n dispatchAssistantQuotaExhausted('ai-credits');\n applyAssistantResponse(\n \"You've run out of AI credits for this billing cycle. Upgrade your plan to keep chatting.\"\n );\n setConversationProcessing(conversationId, 'error', assistantMessageId, null);\n return;\n }\n // The pre-flight gate exists ONLY to catch a genuine QUOTA_EXHAUSTED\n // rejection. Any other failure here is a transient fault in the\n // credit check itself — e.g. the usage subgraph's getUsageSummary /\n // checkAiCredits intermittently 500s (Postgres/Prisma blip) and the\n // gateway masks it as the opaque \"Unexpected error.\". That is NOT\n // proof the user is out of budget, so it must not abort an otherwise\n // valid send. Fail open and proceed: the wspace gateway's\n // @usage(checkQuota) on createSandbox still enforces the real budget\n // downstream (a truly over-quota caller is stopped there with a 429\n // that surfaces the upgrade dialog via the outer catch).\n console.warn(\n '[assistant] AI-credit pre-flight check failed with a non-quota error; proceeding — gateway @usage(checkQuota) still enforces the real budget downstream',\n creditError\n );\n }\n\n try {\n const { sandboxId, sessionId } = await ensureAssistantRuntime(\n conversationId,\n assistantMessageId,\n selectedMode,\n workspaceId,\n authContext\n );\n\n updateConversationStage(conversationId, assistantMessageId, 'streaming', 'Thinking...');\n const promptStartedAt = Date.now();\n await sendAssistantPromptAsync(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n content,\n selectedMode,\n gatherPageContext(),\n authContext\n );\n\n let result = buildAssistantProgress([], promptStartedAt);\n const timeoutAt =\n Date.now() + (STREAM_BUDGET_MS[selectedMode] ?? DEFAULT_STREAM_BUDGET_MS);\n let lastTtlExtensionAt = Date.now();\n\n while (Date.now() < timeoutAt) {\n const sessionMessages = await getAssistantMessages(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n authContext,\n 50\n );\n\n result = buildAssistantProgress(sessionMessages, promptStartedAt);\n patchMessage(conversationId, assistantMessageId, {\n content: sanitizeAssistantResponse(result.content),\n });\n\n if (result.done) break;\n\n if (Date.now() - lastTtlExtensionAt > 30_000) {\n await extendAssistantSandboxTTL(\n apollo,\n sandboxId,\n workspaceId,\n 600,\n authContext\n ).catch(() => undefined);\n lastTtlExtensionAt = Date.now();\n }\n\n await new Promise((resolve) => setTimeout(resolve, 1500));\n }\n\n // For non-build modes a timeout is a hard failure. For vibe-plugins the\n // prompt runs async server-side (/sessions/:id/prompt-async) and keeps\n // writing artifacts after the poll budget elapses, so we surface whatever\n // it has produced instead of discarding the turn.\n if (!result.done && selectedMode !== 'vibe-plugins') {\n throw new Error('Assistant response timed out while streaming progress');\n }\n\n const artifacts =\n selectedMode === 'vibe-plugins'\n ? await getAssistantArtifacts(\n apollo,\n sandboxId,\n workspaceId,\n sessionId,\n authContext\n ).catch(() => [])\n : undefined;\n\n if (!result.done) {\n // vibe-plugins build still running in the background. Append a note so\n // the user knows the answer is partial and the artifacts will finish.\n result = {\n ...result,\n content: `${result.content}\\n\\n_Still building in the background — any artifacts below will finish shortly. Re-open this conversation to pick up the completed plugin._`,\n };\n }\n\n applyAssistantResponse(result.content, artifacts, sessionId, sandboxId);\n\n if (result.tokens) {\n patchMessage(conversationId, assistantMessageId, { tokens: result.tokens });\n // Charge the real token usage against the AI-credits quota (the\n // gateway records it via @usage(trackUsage)). We AWAIT it before\n // marking the turn complete / re-enabling input: otherwise a rapid\n // follow-up send would run its pre-flight checkAiCredits against a\n // stale balance (this turn's charge still in flight) and could\n // dispatch a prompt that should have been blocked, letting fast\n // sends bypass the credit cap. Still best-effort — a charge failure\n // never blocks the displayed answer.\n try {\n await reportAssistantAiTokenUsage(\n apollo,\n workspaceId,\n sessionId,\n result.tokens,\n authContext\n );\n notifyAiCreditsUpdated();\n } catch {\n // ignore — server-side @usage tracking is the source of truth\n }\n }\n setConversationProcessing(conversationId, 'complete', assistantMessageId, null);\n } catch (error) {\n if (attempt === 1 && isRecoverableAssistantError(error)) {\n clearBackendSessionId(conversationId);\n clearSandbox(selectedMode);\n return sendWithRealBackend(2);\n }\n\n throw error;\n }\n };\n\n try {\n if (!workspaceId) {\n throw new Error('Assistant backend is unavailable without an active workspace context.');\n }\n await sendWithRealBackend();\n } catch (error) {\n // A quota error reaching here is the sandbox-environment wall hit\n // during runtime provisioning (createSandbox @usage). Surface the\n // upgrade dialog instead of a generic failure (the AI-credit wall is\n // already handled by the pre-flight gate above).\n if (isQuotaExhaustedError(error)) {\n dispatchAssistantQuotaExhausted('sandbox');\n applyAssistantResponse(\n \"You've reached your sandbox limit on the current plan. Upgrade to start the AI assistant.\"\n );\n setConversationProcessing(conversationId, 'error', assistantMessageId, null);\n return;\n }\n const errorMessage = error instanceof Error ? error.message : 'Something went wrong';\n setConversationProcessing(conversationId, 'error', assistantMessageId, errorMessage);\n updateMessage(\n conversationId,\n assistantMessageId,\n `Sorry, an error occurred: ${errorMessage}. Please try again.`\n );\n }\n },\n [\n activeConversationId,\n addMessage,\n apollo,\n clearBackendSessionId,\n clearSandbox,\n conversations,\n createConversation,\n ensureAssistantRuntime,\n getAccessToken,\n getWorkspaceToken,\n patchMessage,\n processingByConversationId,\n setBackendSessionId,\n setConversationMode,\n setConversationProcessing,\n updateConversationStage,\n updateMessage,\n userId,\n ]\n );\n\n const handleSuggestionClick = useCallback(\n (suggestion: string) => {\n void handleSend(suggestion);\n },\n [handleSend]\n );\n\n // Auto-send any prompt that was queued by `useOpenAssistantHelp` (from\n // the shared GetHelpButton). We keep the latest handleSend in a ref so\n // the subscription effect below doesn't need to tear down on every\n // render — the store subscription lives for the component lifetime and\n // always calls the freshest handler.\n const handleSendRef = useRef(handleSend);\n useEffect(() => {\n handleSendRef.current = handleSend;\n }, [handleSend]);\n\n useEffect(() => {\n // Flush any prompt that was queued before this component mounted.\n const initial = useAssistantStore.getState().consumePendingPrompt();\n if (initial) {\n void handleSendRef.current(initial);\n }\n\n // Watch for new prompts queued while we're already mounted.\n const unsubscribe = useAssistantStore.subscribe((state, prev) => {\n if (state.pendingPrompt && state.pendingPrompt !== prev.pendingPrompt) {\n const queued = useAssistantStore.getState().consumePendingPrompt();\n if (queued) {\n void handleSendRef.current(queued);\n }\n }\n });\n return unsubscribe;\n }, []);\n\n const handleModeChange = useCallback(\n (newMode: AssistantMode) => {\n const currentConversation = activeConversationId\n ? useAssistantStore\n .getState()\n .conversations.find((conversation) => conversation.id === activeConversationId)\n : undefined;\n\n if (\n currentConversation &&\n (currentConversation.messages.length > 0 || currentConversation.backendSessionId)\n ) {\n if (currentConversation.mode !== newMode) {\n const reusableDraft = useAssistantStore\n .getState()\n .conversations.find(\n (conversation) =>\n conversation.mode === newMode &&\n conversation.messages.length === 0 &&\n !conversation.backendSessionId &&\n !useAssistantStore.getState().processingByConversationId[conversation.id]\n );\n\n if (reusableDraft) {\n setActiveConversation(reusableDraft.id);\n } else {\n createConversation(undefined, newMode);\n }\n }\n } else if (activeConversationId) {\n setConversationMode(activeConversationId, newMode);\n }\n\n setMode(newMode);\n },\n [activeConversationId, createConversation, setActiveConversation, setConversationMode, setMode]\n );\n\n return (\n <div className=\"flex flex-col flex-1 overflow-hidden pt-3\">\n {messages.length === 0 ? (\n <AssistantWelcome mode={mode} onSuggestionClick={handleSuggestionClick} />\n ) : (\n <AssistantMessageList messages={messages} streamingMessageId={activeStreamingMessageId} />\n )}\n\n <div>\n <div className=\"px-3 pb-1\">\n <AssistantModeSelector mode={mode} onModeChange={handleModeChange} />\n </div>\n <AssistantChatInput\n onSend={(value) => void handleSend(value)}\n disabled={activeIsProcessing}\n placeholder={tr(\n 'vibecontrols.assistant.chatArea.placeholder',\n `Ask about ${mode.replace(/-/g, ' ')}...`\n )}\n />\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|