@burdenoff/microfe-vibecontrols 2026.525.6 → 2026.525.7

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.
@@ -721,50 +721,46 @@ function nt() {
721
721
  children: O("vibeDetails.featuresDescription", "Toggle which sections show up on this vibe. Changes apply to everyone viewing the vibe.")
722
722
  })]
723
723
  }), /* @__PURE__ */ N("div", {
724
- className: "p-4 space-y-2",
725
- children: at.map((e) => {
726
- let t = U(e.id);
727
- return /* @__PURE__ */ P("label", {
728
- className: "flex items-center justify-between gap-4 py-2 cursor-pointer",
729
- children: [/* @__PURE__ */ N("span", {
730
- className: "text-sm font-medium text-text-primary",
731
- children: e.label
732
- }), /* @__PURE__ */ N("input", {
733
- type: "checkbox",
734
- role: "switch",
735
- "aria-label": e.label,
736
- checked: t,
737
- disabled: st || !V.id,
738
- onChange: async (t) => {
739
- let n = t.target.checked;
740
- try {
741
- await ot({
742
- variables: {
743
- id: V.id,
744
- featureId: e.id,
745
- enabled: n
724
+ className: "divide-y divide-border-default",
725
+ children: at.map((e) => /* @__PURE__ */ P("label", {
726
+ className: "flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-bg-sunken transition-colors",
727
+ children: [/* @__PURE__ */ N("input", {
728
+ type: "checkbox",
729
+ role: "switch",
730
+ checked: U(e.id),
731
+ disabled: st || !V.id,
732
+ onChange: async (t) => {
733
+ let n = t.target.checked;
734
+ try {
735
+ await ot({
736
+ variables: {
737
+ id: V.id,
738
+ featureId: e.id,
739
+ enabled: n
740
+ },
741
+ optimisticResponse: { setVibeFeatureFlag: {
742
+ __typename: "Vibe",
743
+ id: V.id,
744
+ featureFlags: {
745
+ ...H?.featureFlags ?? {},
746
+ [e.id]: n
746
747
  },
747
- optimisticResponse: { setVibeFeatureFlag: {
748
- __typename: "Vibe",
749
- id: V.id,
750
- featureFlags: {
751
- ...H?.featureFlags ?? {},
752
- [e.id]: n
753
- },
754
- effectiveFeatureFlags: {
755
- ...H?.effectiveFeatureFlags ?? {},
756
- [e.id]: n
757
- }
758
- } }
759
- });
760
- } catch (e) {
761
- console.error("Failed to toggle vibe feature:", e);
762
- }
763
- },
764
- className: "h-5 w-5 accent-action-primary-bg"
765
- })]
766
- }, e.id);
767
- })
748
+ effectiveFeatureFlags: {
749
+ ...H?.effectiveFeatureFlags ?? {},
750
+ [e.id]: n
751
+ }
752
+ } }
753
+ });
754
+ } catch (e) {
755
+ console.error("Failed to toggle vibe feature:", e);
756
+ }
757
+ },
758
+ className: "h-4 w-4 shrink-0 accent-action-primary-bg disabled:opacity-50"
759
+ }), /* @__PURE__ */ N("span", {
760
+ className: "text-sm font-medium text-text-primary",
761
+ children: e.label
762
+ })]
763
+ }, e.id))
768
764
  })] })
769
765
  ]
770
766
  }, "config"),
@@ -1 +1 @@
1
- {"version":3,"file":"VibeDetailsPage.js","names":[],"sources":["../../src/pages/VibeDetailsPage.tsx"],"sourcesContent":["import { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useParams } from 'react-router-dom';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport {\n ArrowLeft,\n Zap,\n Play,\n Pause,\n Archive,\n ExternalLink,\n Server,\n Terminal,\n GitBranch,\n Folder,\n Variable,\n Tag,\n Clock,\n Plus,\n RefreshCw,\n Info,\n Settings,\n Link2,\n FileText,\n BookOpen,\n BarChart3,\n Globe,\n Network,\n GitMerge,\n Library,\n X,\n Check,\n ExternalLink as ExternalLinkIcon,\n Loader2,\n Shield,\n MoreVertical,\n Bot,\n} from 'lucide-react';\nimport {\n PageHeader,\n Card,\n StatusBadge,\n EmptyState,\n ErrorState,\n PluginGate,\n} from '@/components/shared';\nimport {\n GIT_PACKAGE,\n GRAPHQL_PLAYGROUND_PACKAGE,\n SESSION_MANAGER_PACKAGE,\n SESSION_PROVIDER_PACKAGES,\n} from '@/constants/pluginCatalog';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { VibeOpenInEditorMenu } from '@/components/agents';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { NotesTabPanel } from '@/components/notes';\nimport { DocsTabPanel } from '@/components/docs';\nimport { ScorecardPanel } from '@/components/scorecard';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useQueryBackedTab } from '@/hooks/useQueryBackedTab';\nimport {\n useGetVibeQuery,\n useUpdateVibeStatusMutation,\n useArchiveVibeMutation,\n useCreateSessionMutation,\n useGetVibeCatalogsQuery,\n useAddVibeToCatalogMutation,\n useRemoveVibeFromCatalogMutation,\n useGetVibeFeatureCatalogQuery,\n useGetVibeFeatureFlagsQuery,\n useSetVibeFeatureFlagMutation,\n} from '@/generated/wspace-operations';\nimport { VibeGitOpsTab } from '@/components/gitops/VibeGitOpsTab';\nimport { VibeAgentEmptyState } from '@/components/vibe/VibeAgentEmptyState';\nimport { VibeAgentSwitcher } from '@/components/vibe/VibeAgentSwitcher';\nimport {\n DEFAULT_VIBE_FEATURE_CATALOG,\n isVibeFeatureEnabled,\n type VibeFeatureDefinition,\n} from '@/lib/vibeFeatures';\nimport { useFeatureFlagDetails } from '@burdenoff/fe-libs/shared/feature-flags';\nimport {\n PluginIframe,\n type DiscoveredContribution,\n type MountTunnel,\n usePluginContributions,\n} from '@burdenoff/fe-libs/shared/plugins';\nimport {\n mintScopedIframeToken,\n scheduleScopedIframeTokenRefresh,\n appendIframeTokenParam,\n type IframeTokenAutoRefreshHandle,\n type IframeTokenResponse,\n} from '@/services/iframeToken';\nimport { AddTabDialog } from '@/components/plugins/AddTabDialog';\nimport { PluginIframeMount } from '@/components/plugins/PluginIframeMount';\nimport { SecurityTabPanel } from '@/components/security';\nimport { VibeLlmContextTabPanel } from '@/components/vibe/VibeLlmContextTabPanel';\n\n// `PluginIframeTabBody` was the per-page helper that minted a token,\n// rendered the iframe, and lacked refresh + error handling. PR-86's\n// review surfaced the missing refresh / loading-stuck-on-error\n// problems; the consolidated logic now lives in\n// `@/components/plugins/PluginIframeMount` and is consumed by every\n// surface that mounts an iframe-served plugin (Vibe + Agent detail\n// pages and the standalone route).\n\ntype VibeTab =\n | 'overview'\n | 'config'\n | 'git'\n | 'sessions'\n | 'notes'\n | 'docs'\n | 'scorecard'\n | 'catalogs'\n | 'graphqlPlayground'\n | 'gitops'\n | 'security'\n | 'related'\n | 'llmContext';\n\nconst VIBE_TABS: readonly VibeTab[] = [\n 'overview',\n 'config',\n 'git',\n 'sessions',\n 'notes',\n 'docs',\n 'scorecard',\n 'catalogs',\n 'graphqlPlayground',\n 'gitops',\n 'security',\n 'related',\n 'llmContext',\n];\n\n// Tabs that are always visible regardless of per-vibe feature flags.\nconst ALWAYS_VISIBLE_TABS: ReadonlySet<VibeTab> = new Set<VibeTab>(['overview', 'config']);\nconst HIDDEN_VIBE_FEATURE_IDS = new Set<string>(['apiPlayground']);\n// Tabs whose content can only be rendered against an attached agent.\nconst AGENT_REQUIRED_TABS: ReadonlySet<VibeTab> = new Set<VibeTab>([\n 'sessions',\n 'gitops',\n 'graphqlPlayground',\n 'git',\n 'security',\n]);\n\n/**\n * Vibe details page - shows comprehensive information about a single vibe\n */\nexport function VibeDetailsPage() {\n const { t } = useI18n();\n const { id } = useParams<{ id: string }>();\n const { basePath: basePathProp } = useVibeControls();\n const basePath = basePathProp || '';\n const navigate = useVibeNavigate();\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n // Active-tab state is declared AFTER `iframeContributions` (further\n // down in this component) so the valid-id set can include both the\n // static `VIBE_TABS` AND the discovered plugin contribution ids.\n // Forward-declaration placeholder so downstream code can reference\n // the binding via the actual hook call below.\n\n const [updateVibeStatus] = useUpdateVibeStatusMutation({ refetchQueries: ['GetVibe'] });\n const [archiveVibe] = useArchiveVibeMutation({ refetchQueries: ['GetVibe'] });\n const [createSession] = useCreateSessionMutation({ refetchQueries: ['GetVibe', 'ListSessions'] });\n\n // Per-vibe feature catalog (drives the toggles in the Config tab and the\n // tab visibility filter below). Falls back to the static catalog if the\n // query is still loading or the backend hasn't shipped this field yet.\n const { data: featureCatalogData } = useGetVibeFeatureCatalogQuery({\n fetchPolicy: 'cache-first',\n errorPolicy: 'ignore',\n });\n const rawFeatureCatalog: readonly VibeFeatureDefinition[] = useMemo(() => {\n const merged = new Map<string, VibeFeatureDefinition>(\n DEFAULT_VIBE_FEATURE_CATALOG.map((feature) => [feature.id, feature])\n );\n\n for (const feature of featureCatalogData?.vibeFeatureCatalog ?? []) {\n merged.set(feature.id, feature);\n }\n\n return Array.from(merged.values());\n }, [featureCatalogData?.vibeFeatureCatalog]);\n const featureCatalog: readonly VibeFeatureDefinition[] = useMemo(\n () => rawFeatureCatalog.filter((feature) => !HIDDEN_VIBE_FEATURE_IDS.has(feature.id)),\n [rawFeatureCatalog]\n );\n\n const [setVibeFeatureFlagMutation, { loading: setFeatureFlagLoading }] =\n useSetVibeFeatureFlagMutation({ refetchQueries: ['GetVibe'] });\n\n // Session creation modal state\n const [showSessionModal, setShowSessionModal] = useState(false);\n const [sessionCreateError, setSessionCreateError] = useState<string | null>(null);\n const [sessionCreateLoading, setSessionCreateLoading] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n // Session form refs\n const sessionNameRef = useRef<HTMLInputElement>(null);\n const sessionTypeRef = useRef<HTMLSelectElement>(null);\n const sessionCommandRef = useRef<HTMLInputElement>(null);\n const sessionWorkDirRef = useRef<HTMLInputElement>(null);\n\n // Fetch vibe by ID from GraphQL API\n const { data, loading, error, refetch } = useGetVibeQuery({\n variables: { id: id || '' },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\n // Get vibe from response\n const vibe = data?.vibe;\n const { data: featureFlagsData } = useGetVibeFeatureFlagsQuery({\n variables: { id: id || '' },\n skip: !id,\n fetchPolicy: 'cache-first',\n errorPolicy: 'ignore',\n });\n // Feature flags live on the Vibe but may not be reflected in the generated\n // types until `bun run codegen` is re-run after the schema update — read\n // them through an untyped view so this file stays compilable in either state.\n const vibeFlagsView = vibe as\n | (typeof vibe & {\n featureFlags?: Record<string, boolean> | null;\n effectiveFeatureFlags?: Record<string, boolean> | null;\n })\n | undefined;\n const effectiveVibeFlags = featureFlagsData?.vibe ?? vibeFlagsView;\n\n // Per-vibe feature enablement check. Hoisted to the top of the component\n // (before any early-return guards) to keep React hook ordering stable.\n const isFeatureEnabled = useCallback(\n (featureId: string) =>\n isVibeFeatureEnabled(effectiveVibeFlags ?? null, featureId, featureCatalog),\n [effectiveVibeFlags, featureCatalog]\n );\n\n // Platform-level tab gates (component-level feature flags). Missing flag details\n // fail open so platform flag fetch gaps do not hide per-vibe enabled tabs.\n const gitTabDetails = useFeatureFlagDetails('vibes.tabs.git');\n const scorecardTabDetails = useFeatureFlagDetails('vibes.tabs.scorecard');\n const graphqlPlaygroundTabDetails = useFeatureFlagDetails('vibes.tabs.graphql-playground');\n // PR-12 migration flags. When on, the inline tab is filtered out\n // and the corresponding iframe contribution from\n // `vibe-plugin-tool-git` / `vibe-plugin-tool-graphiql` takes its\n // slot in the strip. Both flags default to OFF — the iframe\n // implementations have to prove parity in alpha before promotion.\n const gitIframeMigrationFlag = useFeatureFlagDetails('vibes.tabs.git-iframe');\n const graphiqlIframeMigrationFlag = useFeatureFlagDetails('vibes.tabs.graphiql-iframe');\n const gitopsIframeMigrationFlag = useFeatureFlagDetails('vibes.tabs.gitops-iframe');\n\n // Returns false for platform-gated tabs when the flag is off; true for all other tabs.\n const isPlatformTabEnabled = useCallback(\n (tabId: string): boolean => {\n switch (tabId) {\n case 'git':\n return gitTabDetails ? Boolean(gitTabDetails.value) : true;\n case 'scorecard':\n return scorecardTabDetails ? Boolean(scorecardTabDetails.value) : true;\n case 'graphqlPlayground':\n return graphqlPlaygroundTabDetails ? Boolean(graphqlPlaygroundTabDetails.value) : true;\n default:\n return true; // No platform gate for other tabs\n }\n },\n [gitTabDetails, scorecardTabDetails, graphqlPlaygroundTabDetails]\n );\n\n // Get related data from the vibe response (already included in the query).\n // Multi-agent: a vibe carries zero, one, or many attached agents. The\n // \"effective agent\" for THIS user on THIS vibe is picked here using the\n // store's per-vibe persisted choice plus the fallback chain (own host →\n // own dev VM → first shared → first usable).\n const attachedAgents = vibe?.agents ?? [];\n const vibeSessions = vibe?.sessions || [];\n const childVibes = vibe?.children || [];\n const parentVibe = vibe?.parent || null;\n\n // Per-Vibe default agent persisted in vibeControlsStore (write-through\n // cache against wspace-vibecontrols-svc UserPreferences.defaultAgentForVibe).\n // The user explicitly \"Set as default for this Vibe\" via the agent picker\n // and the choice follows them across machines once backend hydration\n // wires up (PR-7 ships the local cache; PR-10 / future ties in hydration).\n const defaultAgentIdForThisVibe = useVibeControlsStore((s) =>\n id ? s.defaultAgentForVibe?.[id] : undefined\n );\n\n // Auto-pick logic: explicit per-Vibe default wins; otherwise when exactly\n // one usable agent is attached, select it. When multiple, fall back to\n // the first agent with a tunnel URL. Personal agents not owned by the\n // current user are filtered out so we never accidentally route an action\n // through a teammate's laptop.\n const effectiveAgent =\n (defaultAgentIdForThisVibe\n ? (attachedAgents.find(\n (a: (typeof attachedAgents)[number]) => a.id === defaultAgentIdForThisVibe\n ) ?? null)\n : null) ??\n (attachedAgents.length === 1\n ? attachedAgents[0]\n : (attachedAgents.find((a: (typeof attachedAgents)[number]) => Boolean(a.tunnelUrl)) ??\n attachedAgents[0] ??\n null));\n // Back-compat alias for the legacy single-agent code paths below; downstream\n // sections still reference `agent` while we incrementally migrate to\n // `effectiveAgent` + the multi-agent picker UX.\n const agent = effectiveAgent;\n const effectiveTunnelUrl: string | null = effectiveAgent?.tunnelUrl ?? null;\n const effectiveApiKey: string | null = effectiveAgent?.agentApiKey ?? null;\n const { active: effectiveProfile } = useActiveAgentProfile(effectiveAgent?.id ?? null);\n\n // ── iframe-mount discovery ───────────────────────────────────────────\n // Gated by the platform feature flag `vibes.tabs.iframe-host`. When\n // off, the inline tabs render exactly as before with zero additional\n // behaviour. When on, the host fetches contributions from the\n // effective agent's tunnel and renders them as ADDITIONAL tabs in the\n // strip (alongside the inline ones). PR-12abc later replaces the\n // inline Git / GraphiQL / Ungit tabs with their iframe equivalents.\n // Hooks live HERE (above all early returns) so the React Rules of\n // Hooks order stays stable across renders.\n const iframeHostFlag = useFeatureFlagDetails('vibes.tabs.iframe-host');\n const enableIframeHost = iframeHostFlag?.value === true;\n\n const iframePluginTunnels = useMemo<MountTunnel[]>(() => {\n if (!enableIframeHost || !effectiveAgent?.tunnelUrl) return [];\n const agentIdForToken = effectiveAgent.id;\n const profile = effectiveProfile ?? 'default';\n return [\n {\n tunnelUrl: effectiveAgent.tunnelUrl,\n profile,\n label: effectiveAgent.name ?? effectiveAgent.id,\n mintIframeToken: async ({ pathPrefixes }) => {\n return mintScopedIframeToken(agentIdForToken, profile, pathPrefixes);\n },\n },\n ];\n }, [enableIframeHost, effectiveAgent, effectiveProfile]);\n\n const iframeContributions = usePluginContributions(iframePluginTunnels, {\n mountPoint: 'vibe.detailTab',\n enabled: enableIframeHost && iframePluginTunnels.length > 0,\n });\n\n // Active-tab state: the valid id set is the static `VIBE_TABS` UNION\n // the discovered plugin contribution ids. The dynamic ids are merged\n // in here so `?tab=plugin:hello` deep-links survive a reload —\n // `useQueryBackedTab` rejects unknown ids and falls back to default,\n // so a plugin id missing from this set would silently land on\n // `'overview'`. The hook re-runs every render so adding ids as\n // contributions arrive is a no-op for the activeTab transition.\n const validTabIds = useMemo<readonly string[]>(() => {\n const fromContribs = iframeContributions.data\n .filter((c) => c.contribution.mountPoint === 'vibe.detailTab')\n .map((c) => c.contribution.id);\n return [...(VIBE_TABS as readonly string[]), ...fromContribs];\n }, [iframeContributions.data]);\n const [activeTab, setActiveTab] = useQueryBackedTab<string>(validTabIds, 'overview');\n\n // \"+ Add tab\" picker open state. The dialog itself queries the\n // agent for installable contributions and triggers `refetch` once\n // an install completes so the new tab appears without a full reload.\n const [addTabOpen, setAddTabOpen] = useState(false);\n\n // ── Sync active context ────────────────────────────────────────────────\n useEffect(() => {\n if (vibe) {\n useVibeControlsStore.setState({\n activeAgentId: effectiveAgent?.id ?? null,\n selectedAgentId: effectiveAgent?.id ?? null,\n activeVibeId: vibe.id,\n selectedVibeId: vibe.id,\n activeSessionId: null,\n selectedSessionId: null,\n });\n }\n // Only sync when vibe or effective-agent identity changes, not on every field update.\n // useVibeControlsStore.setState is a stable Zustand reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [vibe?.id, effectiveAgent?.id]);\n\n // If the currently selected tab is for a feature that just got disabled\n // (either per-vibe, platform-level, or because the vibe has no attached\n // agent), bounce back to overview so the user is not stranded on an empty\n // panel. Multi-agent: gate on attachedAgents.length, not the legacy\n // singular vibe.agentId.\n const hasAttachedAgent = attachedAgents.length > 0;\n useEffect(() => {\n // Don't bounce while data is still loading — `vibe?.agents` may briefly\n // be empty during cache-and-network revalidation and we don't want to\n // snap an explicitly-selected tab back to overview just because the\n // refetch hasn't landed yet. The panel body shows its own empty state\n // when no agent is attached, so leaving the URL intact is correct.\n if (loading) return;\n if (ALWAYS_VISIBLE_TABS.has(activeTab as VibeTab)) return;\n if (!isFeatureEnabled(activeTab) || !isPlatformTabEnabled(activeTab)) {\n setActiveTab('overview');\n return;\n }\n // Previously bounced to overview when no agent attached; that broke\n // deep links and made tab clicks appear to \"do nothing\". Render the\n // empty state inside the panel instead.\n }, [activeTab, isFeatureEnabled, isPlatformTabEnabled, hasAttachedAgent, setActiveTab, loading]);\n\n const handleBack = () => {\n navigate('/vibes');\n };\n\n const handleActivateVibe = async () => {\n if (!vibe?.id) return;\n try {\n await updateVibeStatus({ variables: { id: vibe.id, status: 'ACTIVE' as const } });\n } catch (err) {\n console.error('Failed to activate vibe:', err);\n }\n };\n\n const handleDeactivateVibe = async () => {\n if (!vibe?.id) return;\n try {\n await updateVibeStatus({ variables: { id: vibe.id, status: 'INACTIVE' as const } });\n } catch (err) {\n console.error('Failed to deactivate vibe:', err);\n }\n };\n\n const [confirmArchive, setConfirmArchive] = useState(false);\n const [moreMenuOpen, setMoreMenuOpen] = useState(false);\n const moreMenuRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!moreMenuOpen) return;\n const onDocClick = (e: MouseEvent) => {\n if (!moreMenuRef.current?.contains(e.target as Node)) setMoreMenuOpen(false);\n };\n document.addEventListener('mousedown', onDocClick);\n return () => document.removeEventListener('mousedown', onDocClick);\n }, [moreMenuOpen]);\n\n const handleArchiveVibe = async () => {\n if (!vibe?.id) return;\n try {\n await archiveVibe({ variables: { id: vibe.id } });\n setConfirmArchive(false);\n } catch (err) {\n console.error('Failed to archive vibe:', err);\n }\n };\n\n const handleStartSession = () => {\n setSessionCreateError(null);\n setShowSessionModal(true);\n };\n\n const handleSubmitCreateSession = async () => {\n const name = sessionNameRef.current?.value?.trim();\n const type = sessionTypeRef.current?.value as 'TERMINAL' | 'TMUX' | 'SSH' | 'SCRIPT' | 'CUSTOM';\n const command = sessionCommandRef.current?.value?.trim() || undefined;\n const workingDirectory = sessionWorkDirRef.current?.value?.trim() || undefined;\n\n if (!name) {\n setSessionCreateError(tr('vibeDetails.sessionNameRequired', 'Session name is required'));\n return;\n }\n\n // Use the effective agent already resolved from vibe.agents (multi-agent aware).\n const agentId = effectiveAgent?.id;\n if (!agentId) {\n setSessionCreateError(\n attachedAgents.length === 0\n ? tr(\n 'vibeDetails.noAgentAttached',\n 'This vibe has no agent attached. Connect an agent to this vibe before creating a session.'\n )\n : tr(\n 'vibeDetails.selectAgent',\n 'Select an agent for this vibe before creating a session.'\n )\n );\n return;\n }\n\n setSessionCreateLoading(true);\n setSessionCreateError(null);\n try {\n await createSession({\n variables: {\n input: {\n name,\n type: type || 'TERMINAL',\n agentId,\n vibeId: vibe?.id,\n command,\n workingDirectory: workingDirectory || vibe?.path || undefined,\n },\n },\n });\n setShowSessionModal(false);\n // Clear form refs to prevent stale values on next open\n if (sessionNameRef.current) sessionNameRef.current.value = '';\n if (sessionTypeRef.current) sessionTypeRef.current.selectedIndex = 0;\n if (sessionCommandRef.current) sessionCommandRef.current.value = '';\n if (sessionWorkDirRef.current) sessionWorkDirRef.current.value = '';\n setSuccessMessage(tr('sessions.createdSuccess', 'Session created successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch (err) {\n setSessionCreateError(\n err instanceof Error ? err.message : tr('sessions.failedCreate', 'Failed to create session')\n );\n } finally {\n setSessionCreateLoading(false);\n }\n };\n\n const handleAgentClick = () => {\n if (!agent) return;\n navigate(`/agents/${agent.id}`);\n };\n\n const handleSessionClick = (sessionId: string) => {\n navigate(`/sessions/${sessionId}`);\n };\n\n const handleVibeClick = (vibeId: string) => {\n navigate(`/vibes/${vibeId}`);\n };\n\n const formatTimestamp = (timestamp: string | null | undefined) => {\n if (!timestamp) return tr('health.never', 'Never');\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return tr('health.justNow', 'Just now');\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return new Date(timestamp).toLocaleDateString();\n };\n\n const getGitStatusColor = (status: string | null | undefined) => {\n switch (status) {\n case 'clean':\n return 'text-status-success-text';\n case 'modified':\n return 'text-status-warning-text';\n case 'ahead':\n return 'text-status-info-text';\n default:\n return 'text-text-secondary';\n }\n };\n\n // Guard states wrapped in MotionPage to prevent unmount/remount animation replay\n if (loading && !vibe) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (error && !vibe) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n <ErrorState\n title={tr('vibeDetails.failedLoad', 'Failed to load vibe')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n if (!vibe) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n <EmptyState\n icon={<Zap className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.notFound', 'Vibe not found')}\n description={`${tr('vibeDetails.notFoundDescriptionPrefix', 'No vibe with ID')} \"${id}\" ${tr('vibeDetails.notFoundDescriptionSuffix', 'exists')}`}\n action={\n <button\n onClick={handleBack}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n // Types for sessions and child vibes from the query\n type SessionItem = NonNullable<typeof vibeSessions>[number];\n type ChildVibeItem = NonNullable<typeof childVibes>[number];\n\n const isActive = vibe.status === 'ACTIVE' || vibe.status === 'RUNNING';\n const runningSessions = vibeSessions.filter((s: SessionItem) => s.status === 'RUNNING').length;\n\n // Tab definitions\n const relatedCount = childVibes.length + (parentVibe ? 1 : 0) + (agent ? 1 : 0);\n const hasGitInfo = Boolean(vibe.gitBranch || vibe.gitRemote);\n\n const allVibeTabs: { id: VibeTab; label: string; icon: typeof Zap; badge?: string }[] = [\n { id: 'overview', label: tr('nav.overview', 'Overview'), icon: Info },\n { id: 'config', label: tr('vibeDetails.config', 'Config'), icon: Settings },\n {\n id: 'git',\n label: tr('vibeDetails.git', 'Git'),\n icon: GitBranch,\n badge: hasGitInfo ? vibe.gitBranch || undefined : undefined,\n },\n {\n id: 'sessions',\n label: tr('nav.sessions', 'Sessions'),\n icon: Terminal,\n badge: `${vibeSessions.length}`,\n },\n { id: 'notes', label: tr('vibeDetails.notes', 'Notes'), icon: FileText },\n { id: 'docs', label: tr('vibeDetails.docs', 'Docs'), icon: BookOpen },\n { id: 'scorecard', label: tr('vibeDetails.scorecard', 'Scorecard'), icon: BarChart3 },\n { id: 'catalogs', label: tr('vibeDetails.catalogs', 'Catalogs'), icon: Library },\n {\n id: 'graphqlPlayground',\n label: tr('vibeDetails.graphqlPlayground', 'GraphQL'),\n icon: Network,\n },\n { id: 'gitops', label: tr('vibeDetails.gitops', 'GitOps'), icon: GitMerge },\n { id: 'security', label: tr('vibeDetails.security', 'Security'), icon: Shield },\n {\n id: 'related',\n label: tr('vibeDetails.related', 'Related'),\n icon: Link2,\n badge: relatedCount > 0 ? `${relatedCount}` : undefined,\n },\n {\n id: 'llmContext',\n label: tr('vibeDetails.llmContext', 'LLM Context'),\n icon: Bot,\n },\n ];\n\n // Hide any non-core tab whose feature is disabled — either per-vibe,\n // platform-level, or because the vibe has no attached agent.\n const vibeTabs = allVibeTabs.filter((tab) => {\n if (ALWAYS_VISIBLE_TABS.has(tab.id)) return true;\n if (!isFeatureEnabled(tab.id) || !isPlatformTabEnabled(tab.id)) return false;\n if (!hasAttachedAgent && AGENT_REQUIRED_TABS.has(tab.id)) return false;\n if (tab.id === 'git' && gitIframeMigrationFlag?.value === true) return false;\n if (tab.id === 'graphqlPlayground' && graphiqlIframeMigrationFlag?.value === true) return false;\n if (tab.id === 'gitops' && gitopsIframeMigrationFlag?.value === true) return false;\n return true;\n });\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-success-bg text-status-success-text px-4 py-3 rounded-md shadow-lg\">\n {successMessage}\n </div>\n )}\n\n {/* Back Button */}\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n\n {/* Header */}\n <PageHeader\n title={vibe.name}\n description={vibe.description || tr('vibeDetails.noDescription', 'No description')}\n breadcrumb={[\n { label: tr('nav.vibes', 'Vibes'), path: basePath ? `${basePath}/vibes` : '/vibes' },\n { label: vibe.name },\n ]}\n actions={\n <div className=\"flex items-center gap-2 flex-wrap\">\n <button\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken/80 transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <VibeOpenInEditorMenu\n vibeId={vibe.id}\n workspacePath={vibe.path}\n tunnelUrl={effectiveTunnelUrl}\n agentApiKey={effectiveApiKey}\n profile={effectiveProfile ?? 'default'}\n browserEditorEnabled={isFeatureEnabled('browserEditor')}\n />\n <PermissionButton\n permission={VIBE_PERMISSIONS.SESSION_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip=\"You don't have permission to create sessions\"\n >\n <button\n onClick={handleStartSession}\n className=\"flex items-center gap-1.5 px-2.5 py-1.5 sm:px-3 sm:py-2 text-xs sm:text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <Plus className=\"w-3.5 h-3.5 sm:w-4 sm:h-4\" />\n <span className=\"hidden sm:inline\">{tr('vibeDetails.new', 'New')}</span>\n <span className=\"hidden sm:inline\">{tr('nav.sessions', 'Session')}</span>\n </button>\n </PermissionButton>\n <PermissionButton\n permission={VIBE_PERMISSIONS.VIBE_UPDATE}\n deniedBehavior=\"disable\"\n deniedTooltip=\"You don't have permission to manage this vibe\"\n >\n <div className=\"relative\" ref={moreMenuRef}>\n <button\n type=\"button\"\n onClick={() => setMoreMenuOpen((v) => !v)}\n aria-haspopup=\"menu\"\n aria-expanded={moreMenuOpen}\n aria-label={tr('common.moreActions', 'More actions')}\n title={tr('common.moreActions', 'More actions')}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken/80 transition-colors\"\n >\n <MoreVertical className=\"w-4 h-4\" />\n </button>\n {moreMenuOpen && (\n <div\n role=\"menu\"\n className=\"absolute right-0 mt-2 min-w-[12rem] bg-bg-elevated border border-border-default rounded-md shadow-lg z-20 py-1\"\n >\n <button\n role=\"menuitem\"\n onClick={() => {\n setMoreMenuOpen(false);\n if (isActive) handleDeactivateVibe();\n else handleActivateVibe();\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-text-primary hover:bg-action-ghost-bg-hover text-left\"\n >\n {isActive ? (\n <>\n <Pause className=\"w-4 h-4 text-text-secondary\" />\n <span>\n {tr('vibeDetails.pauseVibe', 'Pause vibe (stop scheduled runs)')}\n </span>\n </>\n ) : (\n <>\n <Play className=\"w-4 h-4 text-status-success-text\" />\n <span>\n {tr('vibeDetails.resumeVibe', 'Resume vibe (re-enable scheduled runs)')}\n </span>\n </>\n )}\n </button>\n <div className=\"border-t border-border-subtle my-1\" />\n <button\n role=\"menuitem\"\n onClick={() => {\n setMoreMenuOpen(false);\n setConfirmArchive(true);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-status-warning-text hover:bg-action-ghost-bg-hover text-left\"\n >\n <Archive className=\"w-4 h-4\" />\n <span>{tr('vibeDetails.archive', 'Archive vibe…')}</span>\n </button>\n </div>\n )}\n </div>\n </PermissionButton>\n </div>\n }\n />\n\n {confirmArchive && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"archive-vibe-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onClick={(e) => {\n if (e.target === e.currentTarget) setConfirmArchive(false);\n }}\n >\n <div className=\"w-full max-w-md rounded-lg bg-bg-elevated border border-border-default shadow-xl p-5\">\n <h2 id=\"archive-vibe-title\" className=\"text-base font-semibold text-text-primary mb-2\">\n {tr('vibeDetails.archiveConfirmTitle', 'Archive this vibe?')}\n </h2>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n 'vibeDetails.archiveConfirmBody',\n 'Archived vibes are hidden from the active list and their scheduled actions stop firing. You can restore the vibe later from the archived view. Existing sessions, tunnels, and audit history are preserved.'\n )}\n </p>\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setConfirmArchive(false)}\n className=\"text-sm px-3 py-1.5 rounded-md border border-border-default text-text-primary hover:bg-action-ghost-bg-hover\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleArchiveVibe}\n className=\"text-sm px-3 py-1.5 rounded-md bg-status-warning-bg text-status-warning-text hover:opacity-80\"\n >\n {tr('vibeDetails.archive', 'Archive')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Status Cards */}\n <MotionList stagger={0.04} className=\"grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4\">\n <MotionItem>\n <Card className=\"p-3 sm:p-4\">\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <div className=\"w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n <Zap className=\"w-4 h-4 sm:w-5 sm:h-5 text-text-secondary\" />\n </div>\n <div className=\"min-w-0\">\n <p\n className=\"text-xs sm:text-sm text-text-secondary\"\n title={tr(\n 'vibeDetails.statusTooltip',\n 'ACTIVE: vibe is in your default working set and can run sessions, tunnels and GitOps via its attached agent(s). INACTIVE: vibe is parked — still visible, no sessions auto-resume. RUNNING: at least one session is live. ARCHIVED: hidden from default lists; can be restored.'\n )}\n >\n {tr('sessions.filterStatus', 'Status')}\n </p>\n <StatusBadge status={vibe.status} size=\"md\" />\n </div>\n </div>\n </Card>\n </MotionItem>\n <MotionItem>\n <Card className=\"p-3 sm:p-4\">\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <div className=\"w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n <Server className=\"w-4 h-4 sm:w-5 sm:h-5 text-text-secondary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs sm:text-sm text-text-secondary\">\n {tr('sessions.filterAgent', 'Agent')}\n </p>\n <p className=\"font-semibold text-text-primary text-sm sm:text-base truncate\">\n {agent?.name || tr('targets.unknown', 'Unknown')}\n </p>\n </div>\n </div>\n </Card>\n </MotionItem>\n <MotionItem>\n <Card className=\"p-3 sm:p-4\">\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <div className=\"w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n <Terminal className=\"w-4 h-4 sm:w-5 sm:h-5 text-text-secondary\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs sm:text-sm text-text-secondary\">\n {tr('nav.sessions', 'Sessions')}\n </p>\n <p className=\"font-semibold text-text-primary text-sm sm:text-base\">\n {runningSessions} {tr('health.active', 'active')}\n </p>\n </div>\n </div>\n </Card>\n </MotionItem>\n </MotionList>\n\n {/* ── Tab Navigation Bar ─────────────────────────────────────────── */}\n <div className=\"border-b border-border-default\">\n <nav\n className=\"flex gap-1 -mb-px overflow-x-auto pb-1\"\n aria-label={tr('vibeDetails.tabsAriaLabel', 'Vibe tabs')}\n >\n {vibeTabs.map((tab) => {\n const Icon = tab.icon;\n const isActiveTab = activeTab === tab.id;\n return (\n <button\n key={tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex shrink-0 items-center gap-1.5 px-3 py-2.5 text-xs sm:gap-2 sm:px-4 sm:text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${\n isActiveTab\n ? 'border-action-primary-bg text-action-primary-bg'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n aria-selected={isActiveTab}\n role=\"tab\"\n >\n <Icon className=\"w-4 h-4\" />\n {tab.label}\n {tab.badge && (\n <span\n className={`hidden rounded-full px-1.5 py-0.5 text-[10px] sm:inline-flex sm:text-xs ${\n isActiveTab\n ? 'bg-action-primary-bg/10 text-action-primary-bg'\n : 'bg-bg-sunken text-text-muted'\n }`}\n >\n {tab.badge}\n </span>\n )}\n </button>\n );\n })}\n {/* iframe-mounted UI plugin tabs (PR-7). Appended after the\n inline strip so the visual order is \"builtins then\n plugins\". Gated by `vibes.tabs.iframe-host`. */}\n {enableIframeHost &&\n iframeContributions.data.map((c) => {\n const isActiveTab = activeTab === c.contribution.id;\n return (\n <button\n key={`plugin-${c.contribution.id}`}\n onClick={() => setActiveTab(c.contribution.id)}\n className={`flex shrink-0 items-center gap-1.5 px-3 py-2.5 text-xs sm:gap-2 sm:px-4 sm:text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${\n isActiveTab\n ? 'border-action-primary-bg text-action-primary-bg'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n aria-selected={isActiveTab}\n role=\"tab\"\n title={`${c.contribution.title} (plugin: ${c.pluginKey})`}\n >\n {c.contribution.title}\n </button>\n );\n })}\n {/* \"+ Add tab\" affordance — always at the trailing end of\n the strip, after both inline and plugin tabs. Standard\n UX pattern; PR-86 review flagged the misplacement. */}\n {enableIframeHost && effectiveAgent && (\n <button\n type=\"button\"\n onClick={() => setAddTabOpen(true)}\n className=\"flex shrink-0 items-center gap-1 px-2 py-2 text-xs sm:text-sm border-b-2 border-transparent text-text-secondary hover:text-text-primary hover:border-border-default\"\n title=\"Install a UI plugin tab\"\n aria-label=\"Add tab\"\n >\n <span aria-hidden>+</span>\n <span className=\"hidden sm:inline\">Add tab</span>\n </button>\n )}\n </nav>\n </div>\n\n {/* ── Tab Panels ─────────────────────────────────────────────────── */}\n <AnimatePresence mode=\"wait\">\n {/* Overview Tab */}\n {activeTab === 'overview' && (\n <motion.div\n key=\"overview\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {/* Description */}\n {vibe.description && (\n <Card>\n <div className=\"p-4\">\n <p className=\"text-text-primary\">{vibe.description}</p>\n </div>\n </Card>\n )}\n\n {/* No-agent empty state — shown only on the overview tab so it does\n not push tab content out of frame. Agent-dependent tabs are\n already hidden when this is rendered. */}\n {!hasAttachedAgent && (\n <VibeAgentEmptyState vibeId={vibe.id} tr={tr} onAttached={() => refetch()} />\n )}\n\n {hasAttachedAgent && (\n <VibeAgentSwitcher\n vibeId={vibe.id}\n attachedAgents={attachedAgents}\n effectiveAgentId={effectiveAgent?.id ?? null}\n />\n )}\n\n {/* Path */}\n <Card>\n <div className=\"p-3 sm:p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2 text-sm sm:text-base\">\n <Folder className=\"w-4 h-4 sm:w-5 sm:h-5\" />\n {tr('vibeDetails.path', 'Path')}\n </h3>\n </div>\n <div className=\"p-3 sm:p-4\">\n <div className=\"bg-bg-sunken rounded-md p-2 sm:p-3 font-mono text-xs sm:text-sm text-text-primary overflow-x-auto break-all\">\n {vibe.path}\n </div>\n </div>\n </Card>\n\n {/* Timeline */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Clock className=\"w-5 h-5\" />\n {tr('vibeDetails.timeline', 'Timeline')}\n </h3>\n </div>\n <div className=\"p-4\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-secondary\">{tr('vibeDetails.created', 'Created')}</p>\n <p className=\"font-medium text-text-primary\">\n {formatTimestamp(vibe.createdAt)}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">{tr('vibeDetails.updated', 'Updated')}</p>\n <p className=\"font-medium text-text-primary\">\n {formatTimestamp(vibe.updatedAt)}\n </p>\n </div>\n </div>\n </div>\n </Card>\n </motion.div>\n )}\n\n {/* Config Tab */}\n {activeTab === 'config' && (\n <motion.div\n key=\"config\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {/* Environment Variables */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Variable className=\"w-5 h-5\" />\n {tr('vibeDetails.environmentVariables', 'Environment Variables')}\n </h3>\n </div>\n <div className=\"p-4\">\n {vibe.environmentVariables && Object.keys(vibe.environmentVariables).length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {Object.entries(vibe.environmentVariables).map(([key, value]) => (\n <span\n key={key}\n className=\"px-3 py-1 bg-bg-sunken text-text-primary text-sm rounded-full font-mono\"\n >\n {key}={String(value)}\n </span>\n ))}\n </div>\n ) : (\n <p className=\"text-text-secondary\">\n {tr(\n 'vibeDetails.noEnvironmentVariables',\n 'No environment variables configured'\n )}\n </p>\n )}\n </div>\n </Card>\n\n {/* Tags */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Tag className=\"w-5 h-5\" />\n {tr('vibeDetails.tags', 'Tags')}\n </h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_VIBE\" entityId={vibe.id} />\n </div>\n </Card>\n\n {/* Features — per-vibe feature toggles */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Settings className=\"w-5 h-5\" />\n {tr('vibeDetails.features', 'Features')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tr(\n 'vibeDetails.featuresDescription',\n 'Toggle which sections show up on this vibe. Changes apply to everyone viewing the vibe.'\n )}\n </p>\n </div>\n <div className=\"p-4 space-y-2\">\n {featureCatalog.map((feature) => {\n const enabled = isFeatureEnabled(feature.id);\n return (\n <label\n key={feature.id}\n className=\"flex items-center justify-between gap-4 py-2 cursor-pointer\"\n >\n <span className=\"text-sm font-medium text-text-primary\">{feature.label}</span>\n <input\n type=\"checkbox\"\n role=\"switch\"\n aria-label={feature.label}\n checked={enabled}\n disabled={setFeatureFlagLoading || !vibe.id}\n onChange={async (e) => {\n const next = e.target.checked;\n try {\n await setVibeFeatureFlagMutation({\n variables: {\n id: vibe.id,\n featureId: feature.id,\n enabled: next,\n },\n optimisticResponse: {\n setVibeFeatureFlag: {\n __typename: 'Vibe',\n id: vibe.id,\n featureFlags: {\n ...(effectiveVibeFlags?.featureFlags ?? {}),\n [feature.id]: next,\n },\n effectiveFeatureFlags: {\n ...(effectiveVibeFlags?.effectiveFeatureFlags ?? {}),\n [feature.id]: next,\n },\n } as never,\n },\n });\n } catch (err) {\n console.error('Failed to toggle vibe feature:', err);\n }\n }}\n className=\"h-5 w-5 accent-action-primary-bg\"\n />\n </label>\n );\n })}\n </div>\n </Card>\n </motion.div>\n )}\n\n {/* Git Tab */}\n {activeTab === 'git' && isFeatureEnabled('git') && (\n <motion.div\n key=\"git\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <PluginGate\n agentId={effectiveAgent?.id ?? null}\n required={[GIT_PACKAGE]}\n mode=\"all\"\n eyebrow={tr('vibeDetails.gitPluginEyebrow', 'Git plugin required')}\n title={tr('vibeDetails.gitPluginTitle', 'Install the git plugin')}\n description={tr(\n 'vibeDetails.gitPluginDescription',\n 'Live git branch, status, and remote data for this vibe are served by the vibe-plugin-tool-git agent plugin.'\n )}\n >\n {hasGitInfo ? (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <GitBranch className=\"w-5 h-5\" />\n {tr('vibeDetails.gitInformation', 'Git Information')}\n </h3>\n </div>\n <div className=\"p-4 space-y-3\">\n <div className=\"flex items-center gap-4 flex-wrap\">\n {vibe.gitBranch && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.branch', 'Branch')}:\n </span>\n <span className=\"px-2 py-1 bg-bg-sunken text-text-primary text-sm rounded font-mono\">\n {vibe.gitBranch}\n </span>\n </div>\n )}\n {vibe.gitStatus && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">\n {tr('sessions.filterStatus', 'Status')}:\n </span>\n <span className={`font-medium ${getGitStatusColor(vibe.gitStatus)}`}>\n {vibe.gitStatus}\n </span>\n </div>\n )}\n </div>\n {vibe.gitRemote && (\n <div>\n <span className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.remote', 'Remote')}:\n </span>\n <p className=\"font-mono text-sm text-text-primary mt-1 break-all\">\n {vibe.gitRemote}\n </p>\n </div>\n )}\n </div>\n </Card>\n ) : (\n <EmptyState\n icon={<GitBranch className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noGitInformation', 'No git information')}\n description={tr(\n 'vibeDetails.noGitInformationDescription',\n 'This vibe does not have any git repository linked'\n )}\n />\n )}\n </PluginGate>\n </motion.div>\n )}\n\n {/* Sessions Tab */}\n {activeTab === 'sessions' && isFeatureEnabled('sessions') && (\n <motion.div\n key=\"sessions\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n >\n <PluginGate\n agentId={effectiveAgent?.id ?? null}\n requirements={[\n {\n packages: [SESSION_MANAGER_PACKAGE],\n mode: 'all',\n eyebrow: tr('vibeDetails.sessionsManagerEyebrow', 'Session manager required'),\n title: tr('vibeDetails.sessionsManagerTitle', 'Install the session manager'),\n description: tr(\n 'vibeDetails.sessionsManagerDescription',\n 'Sessions are orchestrated by the unified session manager plugin. Install it to continue.'\n ),\n },\n {\n packages: SESSION_PROVIDER_PACKAGES,\n mode: 'any',\n eyebrow: tr('vibeDetails.sessionProviderEyebrow', 'Session provider required'),\n title: tr('vibeDetails.sessionProviderTitle', 'Pick a session provider'),\n description: tr(\n 'vibeDetails.sessionProviderDescription',\n 'Choose the terminal multiplexer your sessions should run on. You can install more providers later.'\n ),\n },\n ]}\n >\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center justify-between\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"w-5 h-5\" />\n {tr('nav.sessions', 'Sessions')} ({vibeSessions.length})\n </h3>\n <button\n onClick={handleStartSession}\n className=\"flex items-center gap-1 px-2 py-1 text-sm bg-bg-sunken text-text-primary rounded hover:bg-bg-sunken/80 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibeDetails.new', 'New')}\n </button>\n </div>\n {vibeSessions.length > 0 ? (\n <MotionList className=\"divide-y divide-border-primary\">\n {vibeSessions.map((session: SessionItem) => (\n <MotionItem key={session.id} variant=\"fadeRight\">\n <div\n onClick={() => handleSessionClick(session.id)}\n className=\"p-4 flex items-center justify-between cursor-pointer hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Terminal className=\"w-5 h-5 text-text-secondary flex-shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">\n {session.name}\n </p>\n <p className=\"text-sm text-text-secondary truncate\">{session.type}</p>\n </div>\n </div>\n <StatusBadge status={session.status} />\n </div>\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"p-6 text-center text-text-secondary\">\n {tr('vibeDetails.noSessionsForVibe', 'No sessions for this vibe')}\n </div>\n )}\n </Card>\n </PluginGate>\n </motion.div>\n )}\n\n {/* Notes Tab */}\n {activeTab === 'notes' && isFeatureEnabled('notes') && (\n <motion.div\n key=\"notes\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <NotesTabPanel context=\"vibe\" vibeId={vibe.id} />\n </motion.div>\n )}\n\n {/* Docs Tab */}\n {activeTab === 'docs' && isFeatureEnabled('docs') && (\n <motion.div\n key=\"docs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <DocsTabPanel vibeId={vibe.id} />\n </motion.div>\n )}\n\n {/* Scorecard Tab */}\n {activeTab === 'scorecard' && isFeatureEnabled('scorecard') && (\n <motion.div\n key=\"scorecard\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <ScorecardPanel ownerType=\"VIBE\" ownerId={vibe.id} />\n </motion.div>\n )}\n\n {/* Catalogs Tab */}\n {activeTab === 'catalogs' && isFeatureEnabled('catalogs') && (\n <motion.div\n key=\"catalogs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <VibeCatalogsTab vibeId={vibe.id} tr={tr} navigate={navigate} />\n </motion.div>\n )}\n\n {/* GraphQL Playground Tab */}\n {activeTab === 'graphqlPlayground' && isFeatureEnabled('graphqlPlayground') && (\n <motion.div\n key=\"graphqlPlayground\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <PluginGate\n agentId={effectiveAgent?.id ?? null}\n required={[GRAPHQL_PLAYGROUND_PACKAGE]}\n mode=\"all\"\n eyebrow={tr('vibeDetails.graphqlPluginEyebrow', 'GraphQL playground plugin required')}\n title={tr('vibeDetails.graphqlPluginTitle', 'Install the GraphQL playground')}\n description={tr(\n 'vibeDetails.graphqlPluginDescription',\n 'The GraphQL Playground is served by the graphiql agent plugin. Install it to continue.'\n )}\n >\n {effectiveTunnelUrl ? (\n <PlaygroundTab\n vibeId={vibe.id}\n agentId={effectiveAgent?.id ?? null}\n profile={effectiveProfile}\n tunnelUrl={effectiveTunnelUrl}\n apiKey={effectiveApiKey}\n type=\"graphql\"\n tr={tr}\n />\n ) : (\n <EmptyState\n icon={<Network className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noAgentTunnel', 'No agent tunnel available')}\n description={tr(\n 'vibeDetails.noAgentTunnelDesc2',\n 'The GraphQL playground requires an active agent with a tunnel URL.'\n )}\n />\n )}\n </PluginGate>\n </motion.div>\n )}\n\n {/* GitOps Tab */}\n {activeTab === 'gitops' && isFeatureEnabled('gitops') && (\n <VibeGitOpsTab\n vibeId={id || ''}\n agentId={effectiveAgent?.id ?? ''}\n profile={effectiveProfile}\n tunnelUrl={effectiveTunnelUrl}\n apiKey={effectiveApiKey}\n tr={tr}\n />\n )}\n\n {activeTab === 'security' && isFeatureEnabled('security') && (\n <motion.div\n key=\"security\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <SecurityTabPanel vibeId={id || ''} />\n </motion.div>\n )}\n\n {/* Related Tab */}\n {activeTab === 'related' && isFeatureEnabled('related') && (\n <motion.div\n key=\"related\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {relatedCount > 0 ? (\n <>\n {/* Child Vibes */}\n {childVibes.length > 0 && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Zap className=\"w-5 h-5\" />\n {tr('vibeDetails.childVibes', 'Child Vibes')} ({childVibes.length})\n </h3>\n </div>\n <MotionList className=\"divide-y divide-border-primary\">\n {childVibes.map((child: ChildVibeItem) => (\n <MotionItem key={child.id} variant=\"fadeRight\">\n <div\n onClick={() => handleVibeClick(child.id)}\n className=\"p-4 flex items-center justify-between cursor-pointer hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Zap className=\"w-5 h-5 text-text-secondary flex-shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">\n {child.name}\n </p>\n <p className=\"text-sm text-text-secondary truncate\">{child.type}</p>\n </div>\n </div>\n <StatusBadge status={child.status} />\n </div>\n </MotionItem>\n ))}\n </MotionList>\n </Card>\n )}\n\n {/* Parent Vibe */}\n {parentVibe && (\n <Card onClick={() => handleVibeClick(parentVibe.id)} hoverable>\n <div className=\"p-4 flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-bg-sunken flex items-center justify-center\">\n <Zap className=\"w-5 h-5 text-text-secondary\" />\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.parentVibe', 'Parent Vibe')}\n </p>\n <p className=\"font-medium text-text-primary\">{parentVibe.name}</p>\n </div>\n </div>\n </Card>\n )}\n\n {/* Related Agent */}\n {agent && (\n <Card onClick={handleAgentClick} hoverable>\n <div className=\"p-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-bg-sunken flex items-center justify-center\">\n <Server className=\"w-5 h-5 text-text-secondary\" />\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.runningOnAgent', 'Running on Agent')}\n </p>\n <p className=\"font-medium text-text-primary\">{agent.name}</p>\n <p className=\"text-sm text-text-secondary\">{agent.hostname}</p>\n </div>\n </div>\n <StatusBadge status={agent.isActive ? 'ACTIVE' : 'OFFLINE'} />\n </div>\n </Card>\n )}\n </>\n ) : (\n <EmptyState\n icon={<Link2 className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noRelatedEntities', 'No related entities')}\n description={tr(\n 'vibeDetails.noRelatedEntitiesDescription',\n 'This vibe has no child vibes, parent vibe, or linked agent'\n )}\n />\n )}\n </motion.div>\n )}\n\n {/* LLM Context Tab — signed-URL feature, mount the panel verbatim */}\n {activeTab === 'llmContext' && (\n <motion.div\n key=\"llmContext\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <VibeLlmContextTabPanel\n vibeId={vibe.id}\n attachedAgents={attachedAgents.map((a: { id: string; name: string }) => ({\n id: a.id,\n name: a.name,\n }))}\n />\n </motion.div>\n )}\n {/* iframe-mounted UI plugin tab body (PR-7). Renders when the\n active tab id matches a discovered contribution. The host\n translates a small set of capability-gated RPCs from the\n plugin via `onRpcRequest`; for now the host returns a\n \"method not implemented\" response. PR-10 wires real\n handlers (navigate, toast, storage, getContext, …). */}\n {enableIframeHost &&\n (() => {\n const active: DiscoveredContribution | undefined = iframeContributions.data.find(\n (c) => c.contribution.id === activeTab\n );\n if (!active) return null;\n const tunnel = active.tunnel;\n const restPaths =\n active.capabilities.restPaths.length > 0\n ? active.capabilities.restPaths\n : [`/ui/${active.pluginKey}`];\n return (\n <motion.div\n key={`plugin-${active.contribution.id}`}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <Card>\n <div className=\"p-0 h-[600px]\">\n <PluginIframeMount\n contribution={active}\n tunnel={tunnel}\n restPaths={restPaths}\n context={{ vibeId: vibe.id }}\n // Canonical agent id — `tunnel.label` is a\n // display string and plugin RPC logic that\n // looks up the agent by id would miss with that.\n agentId={effectiveAgent?.id ?? ''}\n profile={tunnel.profile}\n theme={{ colorMode: 'light', tokens: {} }}\n locale=\"en\"\n featureFlags={effectiveVibeFlags?.featureFlags ?? {}}\n // Real version string surfaced via host:init so\n // plugin authors can do version-based feature\n // detection.\n hostVersion=\"1.0.0\"\n />\n </div>\n </Card>\n </motion.div>\n );\n })()}\n </AnimatePresence>\n\n {/* PR-10 \"+ Add tab\" dialog. Mounts off the AnimatePresence so\n opening it doesn't fight the tab-body transitions. */}\n {enableIframeHost && effectiveAgent && (\n <AddTabDialog\n isOpen={addTabOpen}\n onClose={() => setAddTabOpen(false)}\n mountPoint=\"vibe.detailTab\"\n agentId={effectiveAgent.id}\n profile={effectiveProfile ?? 'default'}\n onInstalled={() => {\n void iframeContributions.refetch();\n }}\n />\n )}\n\n {/* Create Session Modal */}\n {showSessionModal && (\n <div className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\">\n <div className=\"bg-bg-surface rounded-lg p-6 w-full max-w-lg\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr('vibeDetails.newSessionFor', 'New Session for')} {vibe.name}\n </h2>\n {sessionCreateError && (\n <div className=\"mb-4 p-3 bg-status-error-bg text-status-error-text rounded-md text-sm\">\n {sessionCreateError}\n </div>\n )}\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibeDetails.sessionName', 'Session Name')}\n </label>\n <input\n ref={sessionNameRef}\n type=\"text\"\n placeholder={tr('vibeDetails.sessionNamePlaceholder', 'dev-terminal')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('sessions.filterType', 'Type')}\n </label>\n <select\n ref={sessionTypeRef}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"TERMINAL\">{tr('sessions.typeTerminal', 'Terminal')}</option>\n <option value=\"TMUX\">{tr('sessions.typeTmux', 'TMUX')}</option>\n <option value=\"SSH\">{tr('sessions.typeSsh', 'SSH')}</option>\n <option value=\"SCRIPT\">{tr('sessions.typeScript', 'Script')}</option>\n <option value=\"CUSTOM\">{tr('sessions.typeCustom', 'Custom')}</option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('sessions.command', 'Command')}\n </label>\n <input\n ref={sessionCommandRef}\n type=\"text\"\n placeholder={tr('vibeDetails.sessionCommandPlaceholder', 'bash')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibeDetails.workingDirectory', 'Working Directory')}\n </label>\n <input\n ref={sessionWorkDirRef}\n type=\"text\"\n defaultValue={vibe.path || ''}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n />\n </div>\n </div>\n <div className=\"flex flex-col sm:flex-row justify-end gap-3 mt-6\">\n <button\n onClick={() => setShowSessionModal(false)}\n disabled={sessionCreateLoading}\n className=\"px-4 py-2 text-text-primary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n onClick={handleSubmitCreateSession}\n disabled={sessionCreateLoading}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {sessionCreateLoading\n ? tr('sessions.creating', 'Creating...')\n : tr('sessions.createSession', 'Create Session')}\n </button>\n </div>\n </div>\n </div>\n )}\n </MotionPage>\n );\n}\n\n/* ── Vibe Catalogs Tab ─────────────────────────────────────────────────── */\n\nfunction VibeCatalogsTab({\n vibeId,\n tr,\n navigate,\n}: {\n vibeId: string;\n tr: (key: string, fallback: string) => string;\n navigate: (path: string) => void;\n}) {\n const [showAddDialog, setShowAddDialog] = useState(false);\n\n const { data, loading, refetch } = useGetVibeCatalogsQuery({ fetchPolicy: 'cache-and-network' });\n\n const [addVibeToCatalog] = useAddVibeToCatalogMutation({\n refetchQueries: ['GetVibeCatalogs'],\n });\n const [removeVibeFromCatalog] = useRemoveVibeFromCatalogMutation({\n refetchQueries: ['GetVibeCatalogs'],\n });\n\n const allCatalogs = data?.vibecontrolsCatalogs?.items ?? [];\n\n const memberCatalogs = allCatalogs.filter(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (cat: any) => cat.vibes?.some((v: any) => v.vibeId === vibeId)\n );\n\n const availableCatalogs = allCatalogs.filter(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (cat: any) => !cat.vibes?.some((v: any) => v.vibeId === vibeId)\n );\n\n const handleAdd = async (catalogId: string) => {\n await addVibeToCatalog({ variables: { catalogId, vibeId } });\n await refetch();\n setShowAddDialog(false);\n };\n\n const handleRemove = async (catalogId: string) => {\n await removeVibeFromCatalog({ variables: { catalogId, vibeId } });\n await refetch();\n };\n\n if (loading && allCatalogs.length === 0) {\n return <PageSkeleton variant=\"detail\" />;\n }\n\n return (\n <>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Library className=\"w-5 h-5\" />\n {tr('vibeDetails.catalogsTitle', 'Catalogs')}\n <span className=\"text-sm font-normal text-text-secondary\">({memberCatalogs.length})</span>\n </h3>\n <button\n onClick={() => setShowAddDialog(true)}\n className=\"flex items-center gap-2 px-3 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibeDetails.addToCatalog', 'Add to Catalog')}\n </button>\n </div>\n\n {memberCatalogs.length > 0 ? (\n <div className=\"space-y-2\">\n {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}\n {memberCatalogs.map((cat: any) => (\n <Card key={cat.id}>\n <div className=\"p-3 flex items-center justify-between\">\n <button\n onClick={() => navigate(`/catalogs/${cat.id}`)}\n className=\"flex items-center gap-3 text-left hover:opacity-80 transition-opacity\"\n >\n <Library className=\"w-5 h-5 text-action-primary-bg flex-shrink-0\" />\n <div>\n <p className=\"font-medium text-text-primary text-sm\">{cat.name}</p>\n <p className=\"text-xs text-text-secondary\">{cat.visibility}</p>\n </div>\n </button>\n <button\n onClick={() => handleRemove(cat.id)}\n className=\"p-1.5 text-text-muted hover:text-status-error-text hover:bg-status-error-bg rounded-md transition-colors\"\n title={tr('vibeDetails.removeFromCatalog', 'Remove from catalog')}\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Library className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noCatalogs', 'Not in any catalogs')}\n description={tr(\n 'vibeDetails.noCatalogsDesc',\n 'Add this vibe to catalogs to organize and track it alongside other components'\n )}\n />\n )}\n\n {/* Add to Catalog Dialog */}\n {showAddDialog && (\n <div className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\">\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n className=\"bg-bg-surface rounded-lg w-full max-w-md max-h-[60vh] flex flex-col\"\n >\n <div className=\"p-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibeDetails.addToCatalogTitle', 'Add Vibe to Catalog')}\n </h2>\n </div>\n <div className=\"flex-1 overflow-y-auto p-2\">\n {availableCatalogs.length === 0 ? (\n <div className=\"p-4 text-center text-text-secondary text-sm\">\n {tr(\n 'vibeDetails.noAvailableCatalogs',\n 'No available catalogs. This vibe is already in all catalogs.'\n )}\n </div>\n ) : (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n availableCatalogs.map((cat: any) => (\n <button\n key={cat.id}\n onClick={() => handleAdd(cat.id)}\n className=\"w-full flex items-center justify-between p-3 rounded-md hover:bg-bg-sunken transition-colors text-left\"\n >\n <div>\n <p className=\"font-medium text-text-primary text-sm\">{cat.name}</p>\n <p className=\"text-xs text-text-secondary\">{cat.visibility}</p>\n </div>\n <Plus className=\"w-4 h-4 text-text-secondary\" />\n </button>\n ))\n )}\n </div>\n <div className=\"p-4 border-t border-border-default\">\n <button\n onClick={() => setShowAddDialog(false)}\n className=\"w-full px-4 py-2 text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n {tr('common.close', 'Close')}\n </button>\n </div>\n </motion.div>\n </div>\n )}\n </>\n );\n}\n\n/* ── Playground Tab (REST / GraphQL) ───────────────────────────────────── */\n\nfunction PlaygroundTab({\n vibeId,\n agentId,\n profile,\n tunnelUrl,\n apiKey,\n type,\n tr,\n}: {\n vibeId: string;\n agentId: string | null;\n profile: string;\n tunnelUrl: string;\n apiKey: string | null;\n type: 'rest' | 'graphql';\n tr: (key: string, fallback: string) => string;\n}) {\n const isRest = type === 'rest';\n const pluginPath = 'graphiql';\n // Canonical agent → profile → plugins/data hierarchy.\n const configUrl = `${tunnelUrl}/api/profiles/${encodeURIComponent(profile)}/${pluginPath}/config/${vibeId}`;\n\n const [endpointUrl, setEndpointUrl] = useState('');\n const [configLoaded, setConfigLoaded] = useState(false);\n const [saving, setSaving] = useState(false);\n const [saved, setSaved] = useState(false);\n const [iframeKey, setIframeKey] = useState(0);\n\n // Load existing config on mount\n useEffect(() => {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (apiKey) headers['x-agent-api-key'] = apiKey;\n\n fetch(configUrl, { headers })\n .then((r) => (r.ok ? r.json() : null))\n .then((data) => {\n if (data) {\n const url = isRest ? data.openapiUrl || data.url : data.graphqlUrl || data.url;\n if (url) setEndpointUrl(url);\n }\n setConfigLoaded(true);\n })\n .catch(() => setConfigLoaded(true));\n }, [configUrl, apiKey, isRest]);\n\n const handleSave = async () => {\n if (!endpointUrl.trim()) return;\n setSaving(true);\n setSaved(false);\n try {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (apiKey) headers['x-agent-api-key'] = apiKey;\n\n const body = isRest ? { openapiUrl: endpointUrl.trim() } : { graphqlUrl: endpointUrl.trim() };\n\n await fetch(configUrl, {\n method: 'PUT',\n headers,\n body: JSON.stringify(body),\n });\n setSaved(true);\n setIframeKey((k) => k + 1); // reload iframe\n setTimeout(() => setSaved(false), 3000);\n } catch {\n // silently fail\n } finally {\n setSaving(false);\n }\n };\n\n // Iframe-token (Phase C): replaces the previous ?apiKey= URL param.\n // Token TTL <= 600s; refresh ~60s before expiry.\n const [iframeToken, setIframeToken] = useState<IframeTokenResponse | null>(null);\n const [tokenError, setTokenError] = useState<string | null>(null);\n // 3 prefixes the iframe hits: /ui/<plugin> (HTML), the profile-scoped config call, and the bare /api/<plugin> the agent rewrites profile-scoped calls to (so the token must cover it). `profile` encoded to match the request path (configUrl/agentApiPath also encode it).\n const iframeTokenPrefixes = useMemo(\n () => [\n `/ui/${pluginPath}`,\n `/api/profiles/${encodeURIComponent(profile)}/${pluginPath}`,\n `/api/${pluginPath}`,\n ],\n [profile, pluginPath]\n );\n\n useEffect(() => {\n if (!agentId) return;\n let cancelled = false;\n let handle: IframeTokenAutoRefreshHandle | null = null;\n\n const onRefresh = (next: IframeTokenResponse) => {\n if (cancelled) return;\n setIframeToken(next);\n handle = scheduleScopedIframeTokenRefresh(\n agentId,\n profile,\n iframeTokenPrefixes,\n next,\n onRefresh,\n (err) => setTokenError(err.message)\n );\n };\n\n mintScopedIframeToken(agentId, profile, iframeTokenPrefixes)\n .then((tok) => {\n if (cancelled) return;\n setIframeToken(tok);\n handle = scheduleScopedIframeTokenRefresh(\n agentId,\n profile,\n iframeTokenPrefixes,\n tok,\n onRefresh,\n (err) => setTokenError(err.message)\n );\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setTokenError(err instanceof Error ? err.message : String(err));\n });\n\n return () => {\n cancelled = true;\n handle?.cancel();\n };\n }, [agentId, profile, iframeTokenPrefixes]);\n\n // Pass the owning profile so the iframe builds profile-scoped API URLs.\n const iframeBaseUrl = `${tunnelUrl}/ui/${pluginPath}?vibeId=${vibeId}&profile=${encodeURIComponent(profile)}`;\n const iframeSrc = iframeToken\n ? appendIframeTokenParam(iframeBaseUrl, iframeToken.token)\n : iframeBaseUrl;\n\n return (\n <div className=\"space-y-4\">\n {/* Config Bar */}\n <Card>\n <div className=\"p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n {isRest ? (\n <Globe className=\"w-5 h-5 text-text-secondary\" />\n ) : (\n <Network className=\"w-5 h-5 text-text-secondary\" />\n )}\n <h3 className=\"font-semibold text-text-primary\">\n {isRest\n ? tr('vibeDetails.restPlaygroundTitle', 'REST API Playground')\n : tr('vibeDetails.graphqlPlaygroundTitle', 'GraphQL Playground')}\n </h3>\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n type=\"url\"\n value={endpointUrl}\n onChange={(e) => setEndpointUrl(e.target.value)}\n placeholder={\n isRest\n ? tr(\n 'vibeDetails.enterSwaggerUrl',\n 'Enter OpenAPI/Swagger URL (e.g. https://petstore3.swagger.io/api/v3/openapi.json)'\n )\n : tr(\n 'vibeDetails.enterGraphqlUrl',\n 'Enter GraphQL endpoint URL (e.g. https://countries.trevorblades.com/graphql)'\n )\n }\n className=\"flex-1 px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder text-sm\"\n onKeyDown={(e) => e.key === 'Enter' && handleSave()}\n />\n <button\n onClick={handleSave}\n disabled={saving || !endpointUrl.trim()}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50 text-sm whitespace-nowrap\"\n >\n {saving ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : saved ? (\n <Check className=\"w-4 h-4\" />\n ) : (\n <ExternalLinkIcon className=\"w-4 h-4\" />\n )}\n {saving\n ? tr('common.saving', 'Saving...')\n : saved\n ? tr('common.saved', 'Saved!')\n : tr('vibeDetails.loadApi', 'Load API')}\n </button>\n </div>\n {!configLoaded && (\n <p className=\"text-xs text-text-muted mt-1\">\n {tr('vibeDetails.loadingConfig', 'Loading saved configuration...')}\n </p>\n )}\n </div>\n </Card>\n\n {/* Iframe (gated on iframe-token mint when agentId is present) */}\n {agentId && !iframeToken ? (\n <div className=\"p-8 text-center text-sm text-text-secondary rounded-md border border-border-default bg-bg-sunken\">\n {tokenError\n ? tr('vibeDetails.iframeTokenError', `Iframe token error: ${tokenError}`)\n : tr('vibeDetails.mintingIframeToken', 'Authorizing iframe…')}\n </div>\n ) : (\n <iframe\n key={iframeKey}\n src={iframeSrc}\n title={isRest ? 'REST API Playground' : 'GraphQL Playground'}\n className=\"w-full rounded-md border border-border-default bg-bg-sunken\"\n style={{ height: '700px' }}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"VibeDetailsPage.js","names":[],"sources":["../../src/pages/VibeDetailsPage.tsx"],"sourcesContent":["import { useState, useRef, useEffect, useCallback, useMemo } from 'react';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { useParams } from 'react-router-dom';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport {\n ArrowLeft,\n Zap,\n Play,\n Pause,\n Archive,\n ExternalLink,\n Server,\n Terminal,\n GitBranch,\n Folder,\n Variable,\n Tag,\n Clock,\n Plus,\n RefreshCw,\n Info,\n Settings,\n Link2,\n FileText,\n BookOpen,\n BarChart3,\n Globe,\n Network,\n GitMerge,\n Library,\n X,\n Check,\n ExternalLink as ExternalLinkIcon,\n Loader2,\n Shield,\n MoreVertical,\n Bot,\n} from 'lucide-react';\nimport {\n PageHeader,\n Card,\n StatusBadge,\n EmptyState,\n ErrorState,\n PluginGate,\n} from '@/components/shared';\nimport {\n GIT_PACKAGE,\n GRAPHQL_PLAYGROUND_PACKAGE,\n SESSION_MANAGER_PACKAGE,\n SESSION_PROVIDER_PACKAGES,\n} from '@/constants/pluginCatalog';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { VibeOpenInEditorMenu } from '@/components/agents';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { NotesTabPanel } from '@/components/notes';\nimport { DocsTabPanel } from '@/components/docs';\nimport { ScorecardPanel } from '@/components/scorecard';\nimport { PermissionButton } from '@burdenoff/fe-libs/shared/components';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useQueryBackedTab } from '@/hooks/useQueryBackedTab';\nimport {\n useGetVibeQuery,\n useUpdateVibeStatusMutation,\n useArchiveVibeMutation,\n useCreateSessionMutation,\n useGetVibeCatalogsQuery,\n useAddVibeToCatalogMutation,\n useRemoveVibeFromCatalogMutation,\n useGetVibeFeatureCatalogQuery,\n useGetVibeFeatureFlagsQuery,\n useSetVibeFeatureFlagMutation,\n} from '@/generated/wspace-operations';\nimport { VibeGitOpsTab } from '@/components/gitops/VibeGitOpsTab';\nimport { VibeAgentEmptyState } from '@/components/vibe/VibeAgentEmptyState';\nimport { VibeAgentSwitcher } from '@/components/vibe/VibeAgentSwitcher';\nimport {\n DEFAULT_VIBE_FEATURE_CATALOG,\n isVibeFeatureEnabled,\n type VibeFeatureDefinition,\n} from '@/lib/vibeFeatures';\nimport { useFeatureFlagDetails } from '@burdenoff/fe-libs/shared/feature-flags';\nimport {\n PluginIframe,\n type DiscoveredContribution,\n type MountTunnel,\n usePluginContributions,\n} from '@burdenoff/fe-libs/shared/plugins';\nimport {\n mintScopedIframeToken,\n scheduleScopedIframeTokenRefresh,\n appendIframeTokenParam,\n type IframeTokenAutoRefreshHandle,\n type IframeTokenResponse,\n} from '@/services/iframeToken';\nimport { AddTabDialog } from '@/components/plugins/AddTabDialog';\nimport { PluginIframeMount } from '@/components/plugins/PluginIframeMount';\nimport { SecurityTabPanel } from '@/components/security';\nimport { VibeLlmContextTabPanel } from '@/components/vibe/VibeLlmContextTabPanel';\n\n// `PluginIframeTabBody` was the per-page helper that minted a token,\n// rendered the iframe, and lacked refresh + error handling. PR-86's\n// review surfaced the missing refresh / loading-stuck-on-error\n// problems; the consolidated logic now lives in\n// `@/components/plugins/PluginIframeMount` and is consumed by every\n// surface that mounts an iframe-served plugin (Vibe + Agent detail\n// pages and the standalone route).\n\ntype VibeTab =\n | 'overview'\n | 'config'\n | 'git'\n | 'sessions'\n | 'notes'\n | 'docs'\n | 'scorecard'\n | 'catalogs'\n | 'graphqlPlayground'\n | 'gitops'\n | 'security'\n | 'related'\n | 'llmContext';\n\nconst VIBE_TABS: readonly VibeTab[] = [\n 'overview',\n 'config',\n 'git',\n 'sessions',\n 'notes',\n 'docs',\n 'scorecard',\n 'catalogs',\n 'graphqlPlayground',\n 'gitops',\n 'security',\n 'related',\n 'llmContext',\n];\n\n// Tabs that are always visible regardless of per-vibe feature flags.\nconst ALWAYS_VISIBLE_TABS: ReadonlySet<VibeTab> = new Set<VibeTab>(['overview', 'config']);\nconst HIDDEN_VIBE_FEATURE_IDS = new Set<string>(['apiPlayground']);\n// Tabs whose content can only be rendered against an attached agent.\nconst AGENT_REQUIRED_TABS: ReadonlySet<VibeTab> = new Set<VibeTab>([\n 'sessions',\n 'gitops',\n 'graphqlPlayground',\n 'git',\n 'security',\n]);\n\n/**\n * Vibe details page - shows comprehensive information about a single vibe\n */\nexport function VibeDetailsPage() {\n const { t } = useI18n();\n const { id } = useParams<{ id: string }>();\n const { basePath: basePathProp } = useVibeControls();\n const basePath = basePathProp || '';\n const navigate = useVibeNavigate();\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n // Active-tab state is declared AFTER `iframeContributions` (further\n // down in this component) so the valid-id set can include both the\n // static `VIBE_TABS` AND the discovered plugin contribution ids.\n // Forward-declaration placeholder so downstream code can reference\n // the binding via the actual hook call below.\n\n const [updateVibeStatus] = useUpdateVibeStatusMutation({ refetchQueries: ['GetVibe'] });\n const [archiveVibe] = useArchiveVibeMutation({ refetchQueries: ['GetVibe'] });\n const [createSession] = useCreateSessionMutation({ refetchQueries: ['GetVibe', 'ListSessions'] });\n\n // Per-vibe feature catalog (drives the toggles in the Config tab and the\n // tab visibility filter below). Falls back to the static catalog if the\n // query is still loading or the backend hasn't shipped this field yet.\n const { data: featureCatalogData } = useGetVibeFeatureCatalogQuery({\n fetchPolicy: 'cache-first',\n errorPolicy: 'ignore',\n });\n const rawFeatureCatalog: readonly VibeFeatureDefinition[] = useMemo(() => {\n const merged = new Map<string, VibeFeatureDefinition>(\n DEFAULT_VIBE_FEATURE_CATALOG.map((feature) => [feature.id, feature])\n );\n\n for (const feature of featureCatalogData?.vibeFeatureCatalog ?? []) {\n merged.set(feature.id, feature);\n }\n\n return Array.from(merged.values());\n }, [featureCatalogData?.vibeFeatureCatalog]);\n const featureCatalog: readonly VibeFeatureDefinition[] = useMemo(\n () => rawFeatureCatalog.filter((feature) => !HIDDEN_VIBE_FEATURE_IDS.has(feature.id)),\n [rawFeatureCatalog]\n );\n\n const [setVibeFeatureFlagMutation, { loading: setFeatureFlagLoading }] =\n useSetVibeFeatureFlagMutation({ refetchQueries: ['GetVibe'] });\n\n // Session creation modal state\n const [showSessionModal, setShowSessionModal] = useState(false);\n const [sessionCreateError, setSessionCreateError] = useState<string | null>(null);\n const [sessionCreateLoading, setSessionCreateLoading] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n // Session form refs\n const sessionNameRef = useRef<HTMLInputElement>(null);\n const sessionTypeRef = useRef<HTMLSelectElement>(null);\n const sessionCommandRef = useRef<HTMLInputElement>(null);\n const sessionWorkDirRef = useRef<HTMLInputElement>(null);\n\n // Fetch vibe by ID from GraphQL API\n const { data, loading, error, refetch } = useGetVibeQuery({\n variables: { id: id || '' },\n skip: !id,\n fetchPolicy: 'cache-and-network',\n });\n\n // Get vibe from response\n const vibe = data?.vibe;\n const { data: featureFlagsData } = useGetVibeFeatureFlagsQuery({\n variables: { id: id || '' },\n skip: !id,\n fetchPolicy: 'cache-first',\n errorPolicy: 'ignore',\n });\n // Feature flags live on the Vibe but may not be reflected in the generated\n // types until `bun run codegen` is re-run after the schema update — read\n // them through an untyped view so this file stays compilable in either state.\n const vibeFlagsView = vibe as\n | (typeof vibe & {\n featureFlags?: Record<string, boolean> | null;\n effectiveFeatureFlags?: Record<string, boolean> | null;\n })\n | undefined;\n const effectiveVibeFlags = featureFlagsData?.vibe ?? vibeFlagsView;\n\n // Per-vibe feature enablement check. Hoisted to the top of the component\n // (before any early-return guards) to keep React hook ordering stable.\n const isFeatureEnabled = useCallback(\n (featureId: string) =>\n isVibeFeatureEnabled(effectiveVibeFlags ?? null, featureId, featureCatalog),\n [effectiveVibeFlags, featureCatalog]\n );\n\n // Platform-level tab gates (component-level feature flags). Missing flag details\n // fail open so platform flag fetch gaps do not hide per-vibe enabled tabs.\n const gitTabDetails = useFeatureFlagDetails('vibes.tabs.git');\n const scorecardTabDetails = useFeatureFlagDetails('vibes.tabs.scorecard');\n const graphqlPlaygroundTabDetails = useFeatureFlagDetails('vibes.tabs.graphql-playground');\n // PR-12 migration flags. When on, the inline tab is filtered out\n // and the corresponding iframe contribution from\n // `vibe-plugin-tool-git` / `vibe-plugin-tool-graphiql` takes its\n // slot in the strip. Both flags default to OFF — the iframe\n // implementations have to prove parity in alpha before promotion.\n const gitIframeMigrationFlag = useFeatureFlagDetails('vibes.tabs.git-iframe');\n const graphiqlIframeMigrationFlag = useFeatureFlagDetails('vibes.tabs.graphiql-iframe');\n const gitopsIframeMigrationFlag = useFeatureFlagDetails('vibes.tabs.gitops-iframe');\n\n // Returns false for platform-gated tabs when the flag is off; true for all other tabs.\n const isPlatformTabEnabled = useCallback(\n (tabId: string): boolean => {\n switch (tabId) {\n case 'git':\n return gitTabDetails ? Boolean(gitTabDetails.value) : true;\n case 'scorecard':\n return scorecardTabDetails ? Boolean(scorecardTabDetails.value) : true;\n case 'graphqlPlayground':\n return graphqlPlaygroundTabDetails ? Boolean(graphqlPlaygroundTabDetails.value) : true;\n default:\n return true; // No platform gate for other tabs\n }\n },\n [gitTabDetails, scorecardTabDetails, graphqlPlaygroundTabDetails]\n );\n\n // Get related data from the vibe response (already included in the query).\n // Multi-agent: a vibe carries zero, one, or many attached agents. The\n // \"effective agent\" for THIS user on THIS vibe is picked here using the\n // store's per-vibe persisted choice plus the fallback chain (own host →\n // own dev VM → first shared → first usable).\n const attachedAgents = vibe?.agents ?? [];\n const vibeSessions = vibe?.sessions || [];\n const childVibes = vibe?.children || [];\n const parentVibe = vibe?.parent || null;\n\n // Per-Vibe default agent persisted in vibeControlsStore (write-through\n // cache against wspace-vibecontrols-svc UserPreferences.defaultAgentForVibe).\n // The user explicitly \"Set as default for this Vibe\" via the agent picker\n // and the choice follows them across machines once backend hydration\n // wires up (PR-7 ships the local cache; PR-10 / future ties in hydration).\n const defaultAgentIdForThisVibe = useVibeControlsStore((s) =>\n id ? s.defaultAgentForVibe?.[id] : undefined\n );\n\n // Auto-pick logic: explicit per-Vibe default wins; otherwise when exactly\n // one usable agent is attached, select it. When multiple, fall back to\n // the first agent with a tunnel URL. Personal agents not owned by the\n // current user are filtered out so we never accidentally route an action\n // through a teammate's laptop.\n const effectiveAgent =\n (defaultAgentIdForThisVibe\n ? (attachedAgents.find(\n (a: (typeof attachedAgents)[number]) => a.id === defaultAgentIdForThisVibe\n ) ?? null)\n : null) ??\n (attachedAgents.length === 1\n ? attachedAgents[0]\n : (attachedAgents.find((a: (typeof attachedAgents)[number]) => Boolean(a.tunnelUrl)) ??\n attachedAgents[0] ??\n null));\n // Back-compat alias for the legacy single-agent code paths below; downstream\n // sections still reference `agent` while we incrementally migrate to\n // `effectiveAgent` + the multi-agent picker UX.\n const agent = effectiveAgent;\n const effectiveTunnelUrl: string | null = effectiveAgent?.tunnelUrl ?? null;\n const effectiveApiKey: string | null = effectiveAgent?.agentApiKey ?? null;\n const { active: effectiveProfile } = useActiveAgentProfile(effectiveAgent?.id ?? null);\n\n // ── iframe-mount discovery ───────────────────────────────────────────\n // Gated by the platform feature flag `vibes.tabs.iframe-host`. When\n // off, the inline tabs render exactly as before with zero additional\n // behaviour. When on, the host fetches contributions from the\n // effective agent's tunnel and renders them as ADDITIONAL tabs in the\n // strip (alongside the inline ones). PR-12abc later replaces the\n // inline Git / GraphiQL / Ungit tabs with their iframe equivalents.\n // Hooks live HERE (above all early returns) so the React Rules of\n // Hooks order stays stable across renders.\n const iframeHostFlag = useFeatureFlagDetails('vibes.tabs.iframe-host');\n const enableIframeHost = iframeHostFlag?.value === true;\n\n const iframePluginTunnels = useMemo<MountTunnel[]>(() => {\n if (!enableIframeHost || !effectiveAgent?.tunnelUrl) return [];\n const agentIdForToken = effectiveAgent.id;\n const profile = effectiveProfile ?? 'default';\n return [\n {\n tunnelUrl: effectiveAgent.tunnelUrl,\n profile,\n label: effectiveAgent.name ?? effectiveAgent.id,\n mintIframeToken: async ({ pathPrefixes }) => {\n return mintScopedIframeToken(agentIdForToken, profile, pathPrefixes);\n },\n },\n ];\n }, [enableIframeHost, effectiveAgent, effectiveProfile]);\n\n const iframeContributions = usePluginContributions(iframePluginTunnels, {\n mountPoint: 'vibe.detailTab',\n enabled: enableIframeHost && iframePluginTunnels.length > 0,\n });\n\n // Active-tab state: the valid id set is the static `VIBE_TABS` UNION\n // the discovered plugin contribution ids. The dynamic ids are merged\n // in here so `?tab=plugin:hello` deep-links survive a reload —\n // `useQueryBackedTab` rejects unknown ids and falls back to default,\n // so a plugin id missing from this set would silently land on\n // `'overview'`. The hook re-runs every render so adding ids as\n // contributions arrive is a no-op for the activeTab transition.\n const validTabIds = useMemo<readonly string[]>(() => {\n const fromContribs = iframeContributions.data\n .filter((c) => c.contribution.mountPoint === 'vibe.detailTab')\n .map((c) => c.contribution.id);\n return [...(VIBE_TABS as readonly string[]), ...fromContribs];\n }, [iframeContributions.data]);\n const [activeTab, setActiveTab] = useQueryBackedTab<string>(validTabIds, 'overview');\n\n // \"+ Add tab\" picker open state. The dialog itself queries the\n // agent for installable contributions and triggers `refetch` once\n // an install completes so the new tab appears without a full reload.\n const [addTabOpen, setAddTabOpen] = useState(false);\n\n // ── Sync active context ────────────────────────────────────────────────\n useEffect(() => {\n if (vibe) {\n useVibeControlsStore.setState({\n activeAgentId: effectiveAgent?.id ?? null,\n selectedAgentId: effectiveAgent?.id ?? null,\n activeVibeId: vibe.id,\n selectedVibeId: vibe.id,\n activeSessionId: null,\n selectedSessionId: null,\n });\n }\n // Only sync when vibe or effective-agent identity changes, not on every field update.\n // useVibeControlsStore.setState is a stable Zustand reference.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [vibe?.id, effectiveAgent?.id]);\n\n // If the currently selected tab is for a feature that just got disabled\n // (either per-vibe, platform-level, or because the vibe has no attached\n // agent), bounce back to overview so the user is not stranded on an empty\n // panel. Multi-agent: gate on attachedAgents.length, not the legacy\n // singular vibe.agentId.\n const hasAttachedAgent = attachedAgents.length > 0;\n useEffect(() => {\n // Don't bounce while data is still loading — `vibe?.agents` may briefly\n // be empty during cache-and-network revalidation and we don't want to\n // snap an explicitly-selected tab back to overview just because the\n // refetch hasn't landed yet. The panel body shows its own empty state\n // when no agent is attached, so leaving the URL intact is correct.\n if (loading) return;\n if (ALWAYS_VISIBLE_TABS.has(activeTab as VibeTab)) return;\n if (!isFeatureEnabled(activeTab) || !isPlatformTabEnabled(activeTab)) {\n setActiveTab('overview');\n return;\n }\n // Previously bounced to overview when no agent attached; that broke\n // deep links and made tab clicks appear to \"do nothing\". Render the\n // empty state inside the panel instead.\n }, [activeTab, isFeatureEnabled, isPlatformTabEnabled, hasAttachedAgent, setActiveTab, loading]);\n\n const handleBack = () => {\n navigate('/vibes');\n };\n\n const handleActivateVibe = async () => {\n if (!vibe?.id) return;\n try {\n await updateVibeStatus({ variables: { id: vibe.id, status: 'ACTIVE' as const } });\n } catch (err) {\n console.error('Failed to activate vibe:', err);\n }\n };\n\n const handleDeactivateVibe = async () => {\n if (!vibe?.id) return;\n try {\n await updateVibeStatus({ variables: { id: vibe.id, status: 'INACTIVE' as const } });\n } catch (err) {\n console.error('Failed to deactivate vibe:', err);\n }\n };\n\n const [confirmArchive, setConfirmArchive] = useState(false);\n const [moreMenuOpen, setMoreMenuOpen] = useState(false);\n const moreMenuRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!moreMenuOpen) return;\n const onDocClick = (e: MouseEvent) => {\n if (!moreMenuRef.current?.contains(e.target as Node)) setMoreMenuOpen(false);\n };\n document.addEventListener('mousedown', onDocClick);\n return () => document.removeEventListener('mousedown', onDocClick);\n }, [moreMenuOpen]);\n\n const handleArchiveVibe = async () => {\n if (!vibe?.id) return;\n try {\n await archiveVibe({ variables: { id: vibe.id } });\n setConfirmArchive(false);\n } catch (err) {\n console.error('Failed to archive vibe:', err);\n }\n };\n\n const handleStartSession = () => {\n setSessionCreateError(null);\n setShowSessionModal(true);\n };\n\n const handleSubmitCreateSession = async () => {\n const name = sessionNameRef.current?.value?.trim();\n const type = sessionTypeRef.current?.value as 'TERMINAL' | 'TMUX' | 'SSH' | 'SCRIPT' | 'CUSTOM';\n const command = sessionCommandRef.current?.value?.trim() || undefined;\n const workingDirectory = sessionWorkDirRef.current?.value?.trim() || undefined;\n\n if (!name) {\n setSessionCreateError(tr('vibeDetails.sessionNameRequired', 'Session name is required'));\n return;\n }\n\n // Use the effective agent already resolved from vibe.agents (multi-agent aware).\n const agentId = effectiveAgent?.id;\n if (!agentId) {\n setSessionCreateError(\n attachedAgents.length === 0\n ? tr(\n 'vibeDetails.noAgentAttached',\n 'This vibe has no agent attached. Connect an agent to this vibe before creating a session.'\n )\n : tr(\n 'vibeDetails.selectAgent',\n 'Select an agent for this vibe before creating a session.'\n )\n );\n return;\n }\n\n setSessionCreateLoading(true);\n setSessionCreateError(null);\n try {\n await createSession({\n variables: {\n input: {\n name,\n type: type || 'TERMINAL',\n agentId,\n vibeId: vibe?.id,\n command,\n workingDirectory: workingDirectory || vibe?.path || undefined,\n },\n },\n });\n setShowSessionModal(false);\n // Clear form refs to prevent stale values on next open\n if (sessionNameRef.current) sessionNameRef.current.value = '';\n if (sessionTypeRef.current) sessionTypeRef.current.selectedIndex = 0;\n if (sessionCommandRef.current) sessionCommandRef.current.value = '';\n if (sessionWorkDirRef.current) sessionWorkDirRef.current.value = '';\n setSuccessMessage(tr('sessions.createdSuccess', 'Session created successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch (err) {\n setSessionCreateError(\n err instanceof Error ? err.message : tr('sessions.failedCreate', 'Failed to create session')\n );\n } finally {\n setSessionCreateLoading(false);\n }\n };\n\n const handleAgentClick = () => {\n if (!agent) return;\n navigate(`/agents/${agent.id}`);\n };\n\n const handleSessionClick = (sessionId: string) => {\n navigate(`/sessions/${sessionId}`);\n };\n\n const handleVibeClick = (vibeId: string) => {\n navigate(`/vibes/${vibeId}`);\n };\n\n const formatTimestamp = (timestamp: string | null | undefined) => {\n if (!timestamp) return tr('health.never', 'Never');\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return tr('health.justNow', 'Just now');\n if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago`;\n if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago`;\n return new Date(timestamp).toLocaleDateString();\n };\n\n const getGitStatusColor = (status: string | null | undefined) => {\n switch (status) {\n case 'clean':\n return 'text-status-success-text';\n case 'modified':\n return 'text-status-warning-text';\n case 'ahead':\n return 'text-status-info-text';\n default:\n return 'text-text-secondary';\n }\n };\n\n // Guard states wrapped in MotionPage to prevent unmount/remount animation replay\n if (loading && !vibe) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (error && !vibe) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n <ErrorState\n title={tr('vibeDetails.failedLoad', 'Failed to load vibe')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n if (!vibe) {\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n <EmptyState\n icon={<Zap className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.notFound', 'Vibe not found')}\n description={`${tr('vibeDetails.notFoundDescriptionPrefix', 'No vibe with ID')} \"${id}\" ${tr('vibeDetails.notFoundDescriptionSuffix', 'exists')}`}\n action={\n <button\n onClick={handleBack}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n // Types for sessions and child vibes from the query\n type SessionItem = NonNullable<typeof vibeSessions>[number];\n type ChildVibeItem = NonNullable<typeof childVibes>[number];\n\n const isActive = vibe.status === 'ACTIVE' || vibe.status === 'RUNNING';\n const runningSessions = vibeSessions.filter((s: SessionItem) => s.status === 'RUNNING').length;\n\n // Tab definitions\n const relatedCount = childVibes.length + (parentVibe ? 1 : 0) + (agent ? 1 : 0);\n const hasGitInfo = Boolean(vibe.gitBranch || vibe.gitRemote);\n\n const allVibeTabs: { id: VibeTab; label: string; icon: typeof Zap; badge?: string }[] = [\n { id: 'overview', label: tr('nav.overview', 'Overview'), icon: Info },\n { id: 'config', label: tr('vibeDetails.config', 'Config'), icon: Settings },\n {\n id: 'git',\n label: tr('vibeDetails.git', 'Git'),\n icon: GitBranch,\n badge: hasGitInfo ? vibe.gitBranch || undefined : undefined,\n },\n {\n id: 'sessions',\n label: tr('nav.sessions', 'Sessions'),\n icon: Terminal,\n badge: `${vibeSessions.length}`,\n },\n { id: 'notes', label: tr('vibeDetails.notes', 'Notes'), icon: FileText },\n { id: 'docs', label: tr('vibeDetails.docs', 'Docs'), icon: BookOpen },\n { id: 'scorecard', label: tr('vibeDetails.scorecard', 'Scorecard'), icon: BarChart3 },\n { id: 'catalogs', label: tr('vibeDetails.catalogs', 'Catalogs'), icon: Library },\n {\n id: 'graphqlPlayground',\n label: tr('vibeDetails.graphqlPlayground', 'GraphQL'),\n icon: Network,\n },\n { id: 'gitops', label: tr('vibeDetails.gitops', 'GitOps'), icon: GitMerge },\n { id: 'security', label: tr('vibeDetails.security', 'Security'), icon: Shield },\n {\n id: 'related',\n label: tr('vibeDetails.related', 'Related'),\n icon: Link2,\n badge: relatedCount > 0 ? `${relatedCount}` : undefined,\n },\n {\n id: 'llmContext',\n label: tr('vibeDetails.llmContext', 'LLM Context'),\n icon: Bot,\n },\n ];\n\n // Hide any non-core tab whose feature is disabled — either per-vibe,\n // platform-level, or because the vibe has no attached agent.\n const vibeTabs = allVibeTabs.filter((tab) => {\n if (ALWAYS_VISIBLE_TABS.has(tab.id)) return true;\n if (!isFeatureEnabled(tab.id) || !isPlatformTabEnabled(tab.id)) return false;\n if (!hasAttachedAgent && AGENT_REQUIRED_TABS.has(tab.id)) return false;\n if (tab.id === 'git' && gitIframeMigrationFlag?.value === true) return false;\n if (tab.id === 'graphqlPlayground' && graphiqlIframeMigrationFlag?.value === true) return false;\n if (tab.id === 'gitops' && gitopsIframeMigrationFlag?.value === true) return false;\n return true;\n });\n\n return (\n <MotionPage className=\"space-y-6 p-4 sm:p-6 bg-bg-surface min-h-screen\">\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-success-bg text-status-success-text px-4 py-3 rounded-md shadow-lg\">\n {successMessage}\n </div>\n )}\n\n {/* Back Button */}\n <button\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"w-4 h-4\" />\n {tr('vibeDetails.backToVibes', 'Back to Vibes')}\n </button>\n\n {/* Header */}\n <PageHeader\n title={vibe.name}\n description={vibe.description || tr('vibeDetails.noDescription', 'No description')}\n breadcrumb={[\n { label: tr('nav.vibes', 'Vibes'), path: basePath ? `${basePath}/vibes` : '/vibes' },\n { label: vibe.name },\n ]}\n actions={\n <div className=\"flex items-center gap-2 flex-wrap\">\n <button\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken/80 transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <VibeOpenInEditorMenu\n vibeId={vibe.id}\n workspacePath={vibe.path}\n tunnelUrl={effectiveTunnelUrl}\n agentApiKey={effectiveApiKey}\n profile={effectiveProfile ?? 'default'}\n browserEditorEnabled={isFeatureEnabled('browserEditor')}\n />\n <PermissionButton\n permission={VIBE_PERMISSIONS.SESSION_CREATE}\n deniedBehavior=\"disable\"\n deniedTooltip=\"You don't have permission to create sessions\"\n >\n <button\n onClick={handleStartSession}\n className=\"flex items-center gap-1.5 px-2.5 py-1.5 sm:px-3 sm:py-2 text-xs sm:text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n <Plus className=\"w-3.5 h-3.5 sm:w-4 sm:h-4\" />\n <span className=\"hidden sm:inline\">{tr('vibeDetails.new', 'New')}</span>\n <span className=\"hidden sm:inline\">{tr('nav.sessions', 'Session')}</span>\n </button>\n </PermissionButton>\n <PermissionButton\n permission={VIBE_PERMISSIONS.VIBE_UPDATE}\n deniedBehavior=\"disable\"\n deniedTooltip=\"You don't have permission to manage this vibe\"\n >\n <div className=\"relative\" ref={moreMenuRef}>\n <button\n type=\"button\"\n onClick={() => setMoreMenuOpen((v) => !v)}\n aria-haspopup=\"menu\"\n aria-expanded={moreMenuOpen}\n aria-label={tr('common.moreActions', 'More actions')}\n title={tr('common.moreActions', 'More actions')}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-bg-sunken/80 transition-colors\"\n >\n <MoreVertical className=\"w-4 h-4\" />\n </button>\n {moreMenuOpen && (\n <div\n role=\"menu\"\n className=\"absolute right-0 mt-2 min-w-[12rem] bg-bg-elevated border border-border-default rounded-md shadow-lg z-20 py-1\"\n >\n <button\n role=\"menuitem\"\n onClick={() => {\n setMoreMenuOpen(false);\n if (isActive) handleDeactivateVibe();\n else handleActivateVibe();\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-text-primary hover:bg-action-ghost-bg-hover text-left\"\n >\n {isActive ? (\n <>\n <Pause className=\"w-4 h-4 text-text-secondary\" />\n <span>\n {tr('vibeDetails.pauseVibe', 'Pause vibe (stop scheduled runs)')}\n </span>\n </>\n ) : (\n <>\n <Play className=\"w-4 h-4 text-status-success-text\" />\n <span>\n {tr('vibeDetails.resumeVibe', 'Resume vibe (re-enable scheduled runs)')}\n </span>\n </>\n )}\n </button>\n <div className=\"border-t border-border-subtle my-1\" />\n <button\n role=\"menuitem\"\n onClick={() => {\n setMoreMenuOpen(false);\n setConfirmArchive(true);\n }}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm text-status-warning-text hover:bg-action-ghost-bg-hover text-left\"\n >\n <Archive className=\"w-4 h-4\" />\n <span>{tr('vibeDetails.archive', 'Archive vibe…')}</span>\n </button>\n </div>\n )}\n </div>\n </PermissionButton>\n </div>\n }\n />\n\n {confirmArchive && (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"archive-vibe-title\"\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n onClick={(e) => {\n if (e.target === e.currentTarget) setConfirmArchive(false);\n }}\n >\n <div className=\"w-full max-w-md rounded-lg bg-bg-elevated border border-border-default shadow-xl p-5\">\n <h2 id=\"archive-vibe-title\" className=\"text-base font-semibold text-text-primary mb-2\">\n {tr('vibeDetails.archiveConfirmTitle', 'Archive this vibe?')}\n </h2>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n 'vibeDetails.archiveConfirmBody',\n 'Archived vibes are hidden from the active list and their scheduled actions stop firing. You can restore the vibe later from the archived view. Existing sessions, tunnels, and audit history are preserved.'\n )}\n </p>\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setConfirmArchive(false)}\n className=\"text-sm px-3 py-1.5 rounded-md border border-border-default text-text-primary hover:bg-action-ghost-bg-hover\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleArchiveVibe}\n className=\"text-sm px-3 py-1.5 rounded-md bg-status-warning-bg text-status-warning-text hover:opacity-80\"\n >\n {tr('vibeDetails.archive', 'Archive')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Status Cards */}\n <MotionList stagger={0.04} className=\"grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4\">\n <MotionItem>\n <Card className=\"p-3 sm:p-4\">\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <div className=\"w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n <Zap className=\"w-4 h-4 sm:w-5 sm:h-5 text-text-secondary\" />\n </div>\n <div className=\"min-w-0\">\n <p\n className=\"text-xs sm:text-sm text-text-secondary\"\n title={tr(\n 'vibeDetails.statusTooltip',\n 'ACTIVE: vibe is in your default working set and can run sessions, tunnels and GitOps via its attached agent(s). INACTIVE: vibe is parked — still visible, no sessions auto-resume. RUNNING: at least one session is live. ARCHIVED: hidden from default lists; can be restored.'\n )}\n >\n {tr('sessions.filterStatus', 'Status')}\n </p>\n <StatusBadge status={vibe.status} size=\"md\" />\n </div>\n </div>\n </Card>\n </MotionItem>\n <MotionItem>\n <Card className=\"p-3 sm:p-4\">\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <div className=\"w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n <Server className=\"w-4 h-4 sm:w-5 sm:h-5 text-text-secondary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-xs sm:text-sm text-text-secondary\">\n {tr('sessions.filterAgent', 'Agent')}\n </p>\n <p className=\"font-semibold text-text-primary text-sm sm:text-base truncate\">\n {agent?.name || tr('targets.unknown', 'Unknown')}\n </p>\n </div>\n </div>\n </Card>\n </MotionItem>\n <MotionItem>\n <Card className=\"p-3 sm:p-4\">\n <div className=\"flex items-center gap-2 sm:gap-3\">\n <div className=\"w-8 h-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center flex-shrink-0\">\n <Terminal className=\"w-4 h-4 sm:w-5 sm:h-5 text-text-secondary\" />\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-xs sm:text-sm text-text-secondary\">\n {tr('nav.sessions', 'Sessions')}\n </p>\n <p className=\"font-semibold text-text-primary text-sm sm:text-base\">\n {runningSessions} {tr('health.active', 'active')}\n </p>\n </div>\n </div>\n </Card>\n </MotionItem>\n </MotionList>\n\n {/* ── Tab Navigation Bar ─────────────────────────────────────────── */}\n <div className=\"border-b border-border-default\">\n <nav\n className=\"flex gap-1 -mb-px overflow-x-auto pb-1\"\n aria-label={tr('vibeDetails.tabsAriaLabel', 'Vibe tabs')}\n >\n {vibeTabs.map((tab) => {\n const Icon = tab.icon;\n const isActiveTab = activeTab === tab.id;\n return (\n <button\n key={tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex shrink-0 items-center gap-1.5 px-3 py-2.5 text-xs sm:gap-2 sm:px-4 sm:text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${\n isActiveTab\n ? 'border-action-primary-bg text-action-primary-bg'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n aria-selected={isActiveTab}\n role=\"tab\"\n >\n <Icon className=\"w-4 h-4\" />\n {tab.label}\n {tab.badge && (\n <span\n className={`hidden rounded-full px-1.5 py-0.5 text-[10px] sm:inline-flex sm:text-xs ${\n isActiveTab\n ? 'bg-action-primary-bg/10 text-action-primary-bg'\n : 'bg-bg-sunken text-text-muted'\n }`}\n >\n {tab.badge}\n </span>\n )}\n </button>\n );\n })}\n {/* iframe-mounted UI plugin tabs (PR-7). Appended after the\n inline strip so the visual order is \"builtins then\n plugins\". Gated by `vibes.tabs.iframe-host`. */}\n {enableIframeHost &&\n iframeContributions.data.map((c) => {\n const isActiveTab = activeTab === c.contribution.id;\n return (\n <button\n key={`plugin-${c.contribution.id}`}\n onClick={() => setActiveTab(c.contribution.id)}\n className={`flex shrink-0 items-center gap-1.5 px-3 py-2.5 text-xs sm:gap-2 sm:px-4 sm:text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${\n isActiveTab\n ? 'border-action-primary-bg text-action-primary-bg'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n aria-selected={isActiveTab}\n role=\"tab\"\n title={`${c.contribution.title} (plugin: ${c.pluginKey})`}\n >\n {c.contribution.title}\n </button>\n );\n })}\n {/* \"+ Add tab\" affordance — always at the trailing end of\n the strip, after both inline and plugin tabs. Standard\n UX pattern; PR-86 review flagged the misplacement. */}\n {enableIframeHost && effectiveAgent && (\n <button\n type=\"button\"\n onClick={() => setAddTabOpen(true)}\n className=\"flex shrink-0 items-center gap-1 px-2 py-2 text-xs sm:text-sm border-b-2 border-transparent text-text-secondary hover:text-text-primary hover:border-border-default\"\n title=\"Install a UI plugin tab\"\n aria-label=\"Add tab\"\n >\n <span aria-hidden>+</span>\n <span className=\"hidden sm:inline\">Add tab</span>\n </button>\n )}\n </nav>\n </div>\n\n {/* ── Tab Panels ─────────────────────────────────────────────────── */}\n <AnimatePresence mode=\"wait\">\n {/* Overview Tab */}\n {activeTab === 'overview' && (\n <motion.div\n key=\"overview\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {/* Description */}\n {vibe.description && (\n <Card>\n <div className=\"p-4\">\n <p className=\"text-text-primary\">{vibe.description}</p>\n </div>\n </Card>\n )}\n\n {/* No-agent empty state — shown only on the overview tab so it does\n not push tab content out of frame. Agent-dependent tabs are\n already hidden when this is rendered. */}\n {!hasAttachedAgent && (\n <VibeAgentEmptyState vibeId={vibe.id} tr={tr} onAttached={() => refetch()} />\n )}\n\n {hasAttachedAgent && (\n <VibeAgentSwitcher\n vibeId={vibe.id}\n attachedAgents={attachedAgents}\n effectiveAgentId={effectiveAgent?.id ?? null}\n />\n )}\n\n {/* Path */}\n <Card>\n <div className=\"p-3 sm:p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2 text-sm sm:text-base\">\n <Folder className=\"w-4 h-4 sm:w-5 sm:h-5\" />\n {tr('vibeDetails.path', 'Path')}\n </h3>\n </div>\n <div className=\"p-3 sm:p-4\">\n <div className=\"bg-bg-sunken rounded-md p-2 sm:p-3 font-mono text-xs sm:text-sm text-text-primary overflow-x-auto break-all\">\n {vibe.path}\n </div>\n </div>\n </Card>\n\n {/* Timeline */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Clock className=\"w-5 h-5\" />\n {tr('vibeDetails.timeline', 'Timeline')}\n </h3>\n </div>\n <div className=\"p-4\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-secondary\">{tr('vibeDetails.created', 'Created')}</p>\n <p className=\"font-medium text-text-primary\">\n {formatTimestamp(vibe.createdAt)}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">{tr('vibeDetails.updated', 'Updated')}</p>\n <p className=\"font-medium text-text-primary\">\n {formatTimestamp(vibe.updatedAt)}\n </p>\n </div>\n </div>\n </div>\n </Card>\n </motion.div>\n )}\n\n {/* Config Tab */}\n {activeTab === 'config' && (\n <motion.div\n key=\"config\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {/* Environment Variables */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Variable className=\"w-5 h-5\" />\n {tr('vibeDetails.environmentVariables', 'Environment Variables')}\n </h3>\n </div>\n <div className=\"p-4\">\n {vibe.environmentVariables && Object.keys(vibe.environmentVariables).length > 0 ? (\n <div className=\"flex flex-wrap gap-2\">\n {Object.entries(vibe.environmentVariables).map(([key, value]) => (\n <span\n key={key}\n className=\"px-3 py-1 bg-bg-sunken text-text-primary text-sm rounded-full font-mono\"\n >\n {key}={String(value)}\n </span>\n ))}\n </div>\n ) : (\n <p className=\"text-text-secondary\">\n {tr(\n 'vibeDetails.noEnvironmentVariables',\n 'No environment variables configured'\n )}\n </p>\n )}\n </div>\n </Card>\n\n {/* Tags */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Tag className=\"w-5 h-5\" />\n {tr('vibeDetails.tags', 'Tags')}\n </h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_VIBE\" entityId={vibe.id} />\n </div>\n </Card>\n\n {/* Features — per-vibe feature toggles */}\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Settings className=\"w-5 h-5\" />\n {tr('vibeDetails.features', 'Features')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-1\">\n {tr(\n 'vibeDetails.featuresDescription',\n 'Toggle which sections show up on this vibe. Changes apply to everyone viewing the vibe.'\n )}\n </p>\n </div>\n <div className=\"divide-y divide-border-default\">\n {featureCatalog.map((feature) => {\n const enabled = isFeatureEnabled(feature.id);\n return (\n <label\n key={feature.id}\n className=\"flex items-center gap-3 px-4 py-3 cursor-pointer hover:bg-bg-sunken transition-colors\"\n >\n <input\n type=\"checkbox\"\n role=\"switch\"\n checked={enabled}\n disabled={setFeatureFlagLoading || !vibe.id}\n onChange={async (e) => {\n const next = e.target.checked;\n try {\n await setVibeFeatureFlagMutation({\n variables: {\n id: vibe.id,\n featureId: feature.id,\n enabled: next,\n },\n optimisticResponse: {\n setVibeFeatureFlag: {\n __typename: 'Vibe',\n id: vibe.id,\n featureFlags: {\n ...(effectiveVibeFlags?.featureFlags ?? {}),\n [feature.id]: next,\n },\n effectiveFeatureFlags: {\n ...(effectiveVibeFlags?.effectiveFeatureFlags ?? {}),\n [feature.id]: next,\n },\n } as never,\n },\n });\n } catch (err) {\n console.error('Failed to toggle vibe feature:', err);\n }\n }}\n className=\"h-4 w-4 shrink-0 accent-action-primary-bg disabled:opacity-50\"\n />\n <span className=\"text-sm font-medium text-text-primary\">{feature.label}</span>\n </label>\n );\n })}\n </div>\n </Card>\n </motion.div>\n )}\n\n {/* Git Tab */}\n {activeTab === 'git' && isFeatureEnabled('git') && (\n <motion.div\n key=\"git\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <PluginGate\n agentId={effectiveAgent?.id ?? null}\n required={[GIT_PACKAGE]}\n mode=\"all\"\n eyebrow={tr('vibeDetails.gitPluginEyebrow', 'Git plugin required')}\n title={tr('vibeDetails.gitPluginTitle', 'Install the git plugin')}\n description={tr(\n 'vibeDetails.gitPluginDescription',\n 'Live git branch, status, and remote data for this vibe are served by the vibe-plugin-tool-git agent plugin.'\n )}\n >\n {hasGitInfo ? (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <GitBranch className=\"w-5 h-5\" />\n {tr('vibeDetails.gitInformation', 'Git Information')}\n </h3>\n </div>\n <div className=\"p-4 space-y-3\">\n <div className=\"flex items-center gap-4 flex-wrap\">\n {vibe.gitBranch && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.branch', 'Branch')}:\n </span>\n <span className=\"px-2 py-1 bg-bg-sunken text-text-primary text-sm rounded font-mono\">\n {vibe.gitBranch}\n </span>\n </div>\n )}\n {vibe.gitStatus && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">\n {tr('sessions.filterStatus', 'Status')}:\n </span>\n <span className={`font-medium ${getGitStatusColor(vibe.gitStatus)}`}>\n {vibe.gitStatus}\n </span>\n </div>\n )}\n </div>\n {vibe.gitRemote && (\n <div>\n <span className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.remote', 'Remote')}:\n </span>\n <p className=\"font-mono text-sm text-text-primary mt-1 break-all\">\n {vibe.gitRemote}\n </p>\n </div>\n )}\n </div>\n </Card>\n ) : (\n <EmptyState\n icon={<GitBranch className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noGitInformation', 'No git information')}\n description={tr(\n 'vibeDetails.noGitInformationDescription',\n 'This vibe does not have any git repository linked'\n )}\n />\n )}\n </PluginGate>\n </motion.div>\n )}\n\n {/* Sessions Tab */}\n {activeTab === 'sessions' && isFeatureEnabled('sessions') && (\n <motion.div\n key=\"sessions\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n >\n <PluginGate\n agentId={effectiveAgent?.id ?? null}\n requirements={[\n {\n packages: [SESSION_MANAGER_PACKAGE],\n mode: 'all',\n eyebrow: tr('vibeDetails.sessionsManagerEyebrow', 'Session manager required'),\n title: tr('vibeDetails.sessionsManagerTitle', 'Install the session manager'),\n description: tr(\n 'vibeDetails.sessionsManagerDescription',\n 'Sessions are orchestrated by the unified session manager plugin. Install it to continue.'\n ),\n },\n {\n packages: SESSION_PROVIDER_PACKAGES,\n mode: 'any',\n eyebrow: tr('vibeDetails.sessionProviderEyebrow', 'Session provider required'),\n title: tr('vibeDetails.sessionProviderTitle', 'Pick a session provider'),\n description: tr(\n 'vibeDetails.sessionProviderDescription',\n 'Choose the terminal multiplexer your sessions should run on. You can install more providers later.'\n ),\n },\n ]}\n >\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center justify-between\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"w-5 h-5\" />\n {tr('nav.sessions', 'Sessions')} ({vibeSessions.length})\n </h3>\n <button\n onClick={handleStartSession}\n className=\"flex items-center gap-1 px-2 py-1 text-sm bg-bg-sunken text-text-primary rounded hover:bg-bg-sunken/80 transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibeDetails.new', 'New')}\n </button>\n </div>\n {vibeSessions.length > 0 ? (\n <MotionList className=\"divide-y divide-border-primary\">\n {vibeSessions.map((session: SessionItem) => (\n <MotionItem key={session.id} variant=\"fadeRight\">\n <div\n onClick={() => handleSessionClick(session.id)}\n className=\"p-4 flex items-center justify-between cursor-pointer hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Terminal className=\"w-5 h-5 text-text-secondary flex-shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">\n {session.name}\n </p>\n <p className=\"text-sm text-text-secondary truncate\">{session.type}</p>\n </div>\n </div>\n <StatusBadge status={session.status} />\n </div>\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"p-6 text-center text-text-secondary\">\n {tr('vibeDetails.noSessionsForVibe', 'No sessions for this vibe')}\n </div>\n )}\n </Card>\n </PluginGate>\n </motion.div>\n )}\n\n {/* Notes Tab */}\n {activeTab === 'notes' && isFeatureEnabled('notes') && (\n <motion.div\n key=\"notes\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <NotesTabPanel context=\"vibe\" vibeId={vibe.id} />\n </motion.div>\n )}\n\n {/* Docs Tab */}\n {activeTab === 'docs' && isFeatureEnabled('docs') && (\n <motion.div\n key=\"docs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <DocsTabPanel vibeId={vibe.id} />\n </motion.div>\n )}\n\n {/* Scorecard Tab */}\n {activeTab === 'scorecard' && isFeatureEnabled('scorecard') && (\n <motion.div\n key=\"scorecard\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <ScorecardPanel ownerType=\"VIBE\" ownerId={vibe.id} />\n </motion.div>\n )}\n\n {/* Catalogs Tab */}\n {activeTab === 'catalogs' && isFeatureEnabled('catalogs') && (\n <motion.div\n key=\"catalogs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <VibeCatalogsTab vibeId={vibe.id} tr={tr} navigate={navigate} />\n </motion.div>\n )}\n\n {/* GraphQL Playground Tab */}\n {activeTab === 'graphqlPlayground' && isFeatureEnabled('graphqlPlayground') && (\n <motion.div\n key=\"graphqlPlayground\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <PluginGate\n agentId={effectiveAgent?.id ?? null}\n required={[GRAPHQL_PLAYGROUND_PACKAGE]}\n mode=\"all\"\n eyebrow={tr('vibeDetails.graphqlPluginEyebrow', 'GraphQL playground plugin required')}\n title={tr('vibeDetails.graphqlPluginTitle', 'Install the GraphQL playground')}\n description={tr(\n 'vibeDetails.graphqlPluginDescription',\n 'The GraphQL Playground is served by the graphiql agent plugin. Install it to continue.'\n )}\n >\n {effectiveTunnelUrl ? (\n <PlaygroundTab\n vibeId={vibe.id}\n agentId={effectiveAgent?.id ?? null}\n profile={effectiveProfile}\n tunnelUrl={effectiveTunnelUrl}\n apiKey={effectiveApiKey}\n type=\"graphql\"\n tr={tr}\n />\n ) : (\n <EmptyState\n icon={<Network className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noAgentTunnel', 'No agent tunnel available')}\n description={tr(\n 'vibeDetails.noAgentTunnelDesc2',\n 'The GraphQL playground requires an active agent with a tunnel URL.'\n )}\n />\n )}\n </PluginGate>\n </motion.div>\n )}\n\n {/* GitOps Tab */}\n {activeTab === 'gitops' && isFeatureEnabled('gitops') && (\n <VibeGitOpsTab\n vibeId={id || ''}\n agentId={effectiveAgent?.id ?? ''}\n profile={effectiveProfile}\n tunnelUrl={effectiveTunnelUrl}\n apiKey={effectiveApiKey}\n tr={tr}\n />\n )}\n\n {activeTab === 'security' && isFeatureEnabled('security') && (\n <motion.div\n key=\"security\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <SecurityTabPanel vibeId={id || ''} />\n </motion.div>\n )}\n\n {/* Related Tab */}\n {activeTab === 'related' && isFeatureEnabled('related') && (\n <motion.div\n key=\"related\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {relatedCount > 0 ? (\n <>\n {/* Child Vibes */}\n {childVibes.length > 0 && (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Zap className=\"w-5 h-5\" />\n {tr('vibeDetails.childVibes', 'Child Vibes')} ({childVibes.length})\n </h3>\n </div>\n <MotionList className=\"divide-y divide-border-primary\">\n {childVibes.map((child: ChildVibeItem) => (\n <MotionItem key={child.id} variant=\"fadeRight\">\n <div\n onClick={() => handleVibeClick(child.id)}\n className=\"p-4 flex items-center justify-between cursor-pointer hover:bg-bg-sunken/50 transition-colors\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Zap className=\"w-5 h-5 text-text-secondary flex-shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">\n {child.name}\n </p>\n <p className=\"text-sm text-text-secondary truncate\">{child.type}</p>\n </div>\n </div>\n <StatusBadge status={child.status} />\n </div>\n </MotionItem>\n ))}\n </MotionList>\n </Card>\n )}\n\n {/* Parent Vibe */}\n {parentVibe && (\n <Card onClick={() => handleVibeClick(parentVibe.id)} hoverable>\n <div className=\"p-4 flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-bg-sunken flex items-center justify-center\">\n <Zap className=\"w-5 h-5 text-text-secondary\" />\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.parentVibe', 'Parent Vibe')}\n </p>\n <p className=\"font-medium text-text-primary\">{parentVibe.name}</p>\n </div>\n </div>\n </Card>\n )}\n\n {/* Related Agent */}\n {agent && (\n <Card onClick={handleAgentClick} hoverable>\n <div className=\"p-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-bg-sunken flex items-center justify-center\">\n <Server className=\"w-5 h-5 text-text-secondary\" />\n </div>\n <div>\n <p className=\"text-sm text-text-secondary\">\n {tr('vibeDetails.runningOnAgent', 'Running on Agent')}\n </p>\n <p className=\"font-medium text-text-primary\">{agent.name}</p>\n <p className=\"text-sm text-text-secondary\">{agent.hostname}</p>\n </div>\n </div>\n <StatusBadge status={agent.isActive ? 'ACTIVE' : 'OFFLINE'} />\n </div>\n </Card>\n )}\n </>\n ) : (\n <EmptyState\n icon={<Link2 className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noRelatedEntities', 'No related entities')}\n description={tr(\n 'vibeDetails.noRelatedEntitiesDescription',\n 'This vibe has no child vibes, parent vibe, or linked agent'\n )}\n />\n )}\n </motion.div>\n )}\n\n {/* LLM Context Tab — signed-URL feature, mount the panel verbatim */}\n {activeTab === 'llmContext' && (\n <motion.div\n key=\"llmContext\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <VibeLlmContextTabPanel\n vibeId={vibe.id}\n attachedAgents={attachedAgents.map((a: { id: string; name: string }) => ({\n id: a.id,\n name: a.name,\n }))}\n />\n </motion.div>\n )}\n {/* iframe-mounted UI plugin tab body (PR-7). Renders when the\n active tab id matches a discovered contribution. The host\n translates a small set of capability-gated RPCs from the\n plugin via `onRpcRequest`; for now the host returns a\n \"method not implemented\" response. PR-10 wires real\n handlers (navigate, toast, storage, getContext, …). */}\n {enableIframeHost &&\n (() => {\n const active: DiscoveredContribution | undefined = iframeContributions.data.find(\n (c) => c.contribution.id === activeTab\n );\n if (!active) return null;\n const tunnel = active.tunnel;\n const restPaths =\n active.capabilities.restPaths.length > 0\n ? active.capabilities.restPaths\n : [`/ui/${active.pluginKey}`];\n return (\n <motion.div\n key={`plugin-${active.contribution.id}`}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <Card>\n <div className=\"p-0 h-[600px]\">\n <PluginIframeMount\n contribution={active}\n tunnel={tunnel}\n restPaths={restPaths}\n context={{ vibeId: vibe.id }}\n // Canonical agent id — `tunnel.label` is a\n // display string and plugin RPC logic that\n // looks up the agent by id would miss with that.\n agentId={effectiveAgent?.id ?? ''}\n profile={tunnel.profile}\n theme={{ colorMode: 'light', tokens: {} }}\n locale=\"en\"\n featureFlags={effectiveVibeFlags?.featureFlags ?? {}}\n // Real version string surfaced via host:init so\n // plugin authors can do version-based feature\n // detection.\n hostVersion=\"1.0.0\"\n />\n </div>\n </Card>\n </motion.div>\n );\n })()}\n </AnimatePresence>\n\n {/* PR-10 \"+ Add tab\" dialog. Mounts off the AnimatePresence so\n opening it doesn't fight the tab-body transitions. */}\n {enableIframeHost && effectiveAgent && (\n <AddTabDialog\n isOpen={addTabOpen}\n onClose={() => setAddTabOpen(false)}\n mountPoint=\"vibe.detailTab\"\n agentId={effectiveAgent.id}\n profile={effectiveProfile ?? 'default'}\n onInstalled={() => {\n void iframeContributions.refetch();\n }}\n />\n )}\n\n {/* Create Session Modal */}\n {showSessionModal && (\n <div className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\">\n <div className=\"bg-bg-surface rounded-lg p-6 w-full max-w-lg\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-4\">\n {tr('vibeDetails.newSessionFor', 'New Session for')} {vibe.name}\n </h2>\n {sessionCreateError && (\n <div className=\"mb-4 p-3 bg-status-error-bg text-status-error-text rounded-md text-sm\">\n {sessionCreateError}\n </div>\n )}\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibeDetails.sessionName', 'Session Name')}\n </label>\n <input\n ref={sessionNameRef}\n type=\"text\"\n placeholder={tr('vibeDetails.sessionNamePlaceholder', 'dev-terminal')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('sessions.filterType', 'Type')}\n </label>\n <select\n ref={sessionTypeRef}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"TERMINAL\">{tr('sessions.typeTerminal', 'Terminal')}</option>\n <option value=\"TMUX\">{tr('sessions.typeTmux', 'TMUX')}</option>\n <option value=\"SSH\">{tr('sessions.typeSsh', 'SSH')}</option>\n <option value=\"SCRIPT\">{tr('sessions.typeScript', 'Script')}</option>\n <option value=\"CUSTOM\">{tr('sessions.typeCustom', 'Custom')}</option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('sessions.command', 'Command')}\n </label>\n <input\n ref={sessionCommandRef}\n type=\"text\"\n placeholder={tr('vibeDetails.sessionCommandPlaceholder', 'bash')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibeDetails.workingDirectory', 'Working Directory')}\n </label>\n <input\n ref={sessionWorkDirRef}\n type=\"text\"\n defaultValue={vibe.path || ''}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n />\n </div>\n </div>\n <div className=\"flex flex-col sm:flex-row justify-end gap-3 mt-6\">\n <button\n onClick={() => setShowSessionModal(false)}\n disabled={sessionCreateLoading}\n className=\"px-4 py-2 text-text-primary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n onClick={handleSubmitCreateSession}\n disabled={sessionCreateLoading}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {sessionCreateLoading\n ? tr('sessions.creating', 'Creating...')\n : tr('sessions.createSession', 'Create Session')}\n </button>\n </div>\n </div>\n </div>\n )}\n </MotionPage>\n );\n}\n\n/* ── Vibe Catalogs Tab ─────────────────────────────────────────────────── */\n\nfunction VibeCatalogsTab({\n vibeId,\n tr,\n navigate,\n}: {\n vibeId: string;\n tr: (key: string, fallback: string) => string;\n navigate: (path: string) => void;\n}) {\n const [showAddDialog, setShowAddDialog] = useState(false);\n\n const { data, loading, refetch } = useGetVibeCatalogsQuery({ fetchPolicy: 'cache-and-network' });\n\n const [addVibeToCatalog] = useAddVibeToCatalogMutation({\n refetchQueries: ['GetVibeCatalogs'],\n });\n const [removeVibeFromCatalog] = useRemoveVibeFromCatalogMutation({\n refetchQueries: ['GetVibeCatalogs'],\n });\n\n const allCatalogs = data?.vibecontrolsCatalogs?.items ?? [];\n\n const memberCatalogs = allCatalogs.filter(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (cat: any) => cat.vibes?.some((v: any) => v.vibeId === vibeId)\n );\n\n const availableCatalogs = allCatalogs.filter(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (cat: any) => !cat.vibes?.some((v: any) => v.vibeId === vibeId)\n );\n\n const handleAdd = async (catalogId: string) => {\n await addVibeToCatalog({ variables: { catalogId, vibeId } });\n await refetch();\n setShowAddDialog(false);\n };\n\n const handleRemove = async (catalogId: string) => {\n await removeVibeFromCatalog({ variables: { catalogId, vibeId } });\n await refetch();\n };\n\n if (loading && allCatalogs.length === 0) {\n return <PageSkeleton variant=\"detail\" />;\n }\n\n return (\n <>\n <div className=\"flex items-center justify-between\">\n <h3 className=\"font-semibold text-text-primary flex items-center gap-2\">\n <Library className=\"w-5 h-5\" />\n {tr('vibeDetails.catalogsTitle', 'Catalogs')}\n <span className=\"text-sm font-normal text-text-secondary\">({memberCatalogs.length})</span>\n </h3>\n <button\n onClick={() => setShowAddDialog(true)}\n className=\"flex items-center gap-2 px-3 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"w-4 h-4\" />\n {tr('vibeDetails.addToCatalog', 'Add to Catalog')}\n </button>\n </div>\n\n {memberCatalogs.length > 0 ? (\n <div className=\"space-y-2\">\n {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}\n {memberCatalogs.map((cat: any) => (\n <Card key={cat.id}>\n <div className=\"p-3 flex items-center justify-between\">\n <button\n onClick={() => navigate(`/catalogs/${cat.id}`)}\n className=\"flex items-center gap-3 text-left hover:opacity-80 transition-opacity\"\n >\n <Library className=\"w-5 h-5 text-action-primary-bg flex-shrink-0\" />\n <div>\n <p className=\"font-medium text-text-primary text-sm\">{cat.name}</p>\n <p className=\"text-xs text-text-secondary\">{cat.visibility}</p>\n </div>\n </button>\n <button\n onClick={() => handleRemove(cat.id)}\n className=\"p-1.5 text-text-muted hover:text-status-error-text hover:bg-status-error-bg rounded-md transition-colors\"\n title={tr('vibeDetails.removeFromCatalog', 'Remove from catalog')}\n >\n <X className=\"w-4 h-4\" />\n </button>\n </div>\n </Card>\n ))}\n </div>\n ) : (\n <EmptyState\n icon={<Library className=\"w-8 h-8 text-text-secondary\" />}\n title={tr('vibeDetails.noCatalogs', 'Not in any catalogs')}\n description={tr(\n 'vibeDetails.noCatalogsDesc',\n 'Add this vibe to catalogs to organize and track it alongside other components'\n )}\n />\n )}\n\n {/* Add to Catalog Dialog */}\n {showAddDialog && (\n <div className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\">\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n className=\"bg-bg-surface rounded-lg w-full max-w-md max-h-[60vh] flex flex-col\"\n >\n <div className=\"p-4 border-b border-border-default\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibeDetails.addToCatalogTitle', 'Add Vibe to Catalog')}\n </h2>\n </div>\n <div className=\"flex-1 overflow-y-auto p-2\">\n {availableCatalogs.length === 0 ? (\n <div className=\"p-4 text-center text-text-secondary text-sm\">\n {tr(\n 'vibeDetails.noAvailableCatalogs',\n 'No available catalogs. This vibe is already in all catalogs.'\n )}\n </div>\n ) : (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n availableCatalogs.map((cat: any) => (\n <button\n key={cat.id}\n onClick={() => handleAdd(cat.id)}\n className=\"w-full flex items-center justify-between p-3 rounded-md hover:bg-bg-sunken transition-colors text-left\"\n >\n <div>\n <p className=\"font-medium text-text-primary text-sm\">{cat.name}</p>\n <p className=\"text-xs text-text-secondary\">{cat.visibility}</p>\n </div>\n <Plus className=\"w-4 h-4 text-text-secondary\" />\n </button>\n ))\n )}\n </div>\n <div className=\"p-4 border-t border-border-default\">\n <button\n onClick={() => setShowAddDialog(false)}\n className=\"w-full px-4 py-2 text-text-primary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n {tr('common.close', 'Close')}\n </button>\n </div>\n </motion.div>\n </div>\n )}\n </>\n );\n}\n\n/* ── Playground Tab (REST / GraphQL) ───────────────────────────────────── */\n\nfunction PlaygroundTab({\n vibeId,\n agentId,\n profile,\n tunnelUrl,\n apiKey,\n type,\n tr,\n}: {\n vibeId: string;\n agentId: string | null;\n profile: string;\n tunnelUrl: string;\n apiKey: string | null;\n type: 'rest' | 'graphql';\n tr: (key: string, fallback: string) => string;\n}) {\n const isRest = type === 'rest';\n const pluginPath = 'graphiql';\n // Canonical agent → profile → plugins/data hierarchy.\n const configUrl = `${tunnelUrl}/api/profiles/${encodeURIComponent(profile)}/${pluginPath}/config/${vibeId}`;\n\n const [endpointUrl, setEndpointUrl] = useState('');\n const [configLoaded, setConfigLoaded] = useState(false);\n const [saving, setSaving] = useState(false);\n const [saved, setSaved] = useState(false);\n const [iframeKey, setIframeKey] = useState(0);\n\n // Load existing config on mount\n useEffect(() => {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (apiKey) headers['x-agent-api-key'] = apiKey;\n\n fetch(configUrl, { headers })\n .then((r) => (r.ok ? r.json() : null))\n .then((data) => {\n if (data) {\n const url = isRest ? data.openapiUrl || data.url : data.graphqlUrl || data.url;\n if (url) setEndpointUrl(url);\n }\n setConfigLoaded(true);\n })\n .catch(() => setConfigLoaded(true));\n }, [configUrl, apiKey, isRest]);\n\n const handleSave = async () => {\n if (!endpointUrl.trim()) return;\n setSaving(true);\n setSaved(false);\n try {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (apiKey) headers['x-agent-api-key'] = apiKey;\n\n const body = isRest ? { openapiUrl: endpointUrl.trim() } : { graphqlUrl: endpointUrl.trim() };\n\n await fetch(configUrl, {\n method: 'PUT',\n headers,\n body: JSON.stringify(body),\n });\n setSaved(true);\n setIframeKey((k) => k + 1); // reload iframe\n setTimeout(() => setSaved(false), 3000);\n } catch {\n // silently fail\n } finally {\n setSaving(false);\n }\n };\n\n // Iframe-token (Phase C): replaces the previous ?apiKey= URL param.\n // Token TTL <= 600s; refresh ~60s before expiry.\n const [iframeToken, setIframeToken] = useState<IframeTokenResponse | null>(null);\n const [tokenError, setTokenError] = useState<string | null>(null);\n // 3 prefixes the iframe hits: /ui/<plugin> (HTML), the profile-scoped config call, and the bare /api/<plugin> the agent rewrites profile-scoped calls to (so the token must cover it). `profile` encoded to match the request path (configUrl/agentApiPath also encode it).\n const iframeTokenPrefixes = useMemo(\n () => [\n `/ui/${pluginPath}`,\n `/api/profiles/${encodeURIComponent(profile)}/${pluginPath}`,\n `/api/${pluginPath}`,\n ],\n [profile, pluginPath]\n );\n\n useEffect(() => {\n if (!agentId) return;\n let cancelled = false;\n let handle: IframeTokenAutoRefreshHandle | null = null;\n\n const onRefresh = (next: IframeTokenResponse) => {\n if (cancelled) return;\n setIframeToken(next);\n handle = scheduleScopedIframeTokenRefresh(\n agentId,\n profile,\n iframeTokenPrefixes,\n next,\n onRefresh,\n (err) => setTokenError(err.message)\n );\n };\n\n mintScopedIframeToken(agentId, profile, iframeTokenPrefixes)\n .then((tok) => {\n if (cancelled) return;\n setIframeToken(tok);\n handle = scheduleScopedIframeTokenRefresh(\n agentId,\n profile,\n iframeTokenPrefixes,\n tok,\n onRefresh,\n (err) => setTokenError(err.message)\n );\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n setTokenError(err instanceof Error ? err.message : String(err));\n });\n\n return () => {\n cancelled = true;\n handle?.cancel();\n };\n }, [agentId, profile, iframeTokenPrefixes]);\n\n // Pass the owning profile so the iframe builds profile-scoped API URLs.\n const iframeBaseUrl = `${tunnelUrl}/ui/${pluginPath}?vibeId=${vibeId}&profile=${encodeURIComponent(profile)}`;\n const iframeSrc = iframeToken\n ? appendIframeTokenParam(iframeBaseUrl, iframeToken.token)\n : iframeBaseUrl;\n\n return (\n <div className=\"space-y-4\">\n {/* Config Bar */}\n <Card>\n <div className=\"p-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n {isRest ? (\n <Globe className=\"w-5 h-5 text-text-secondary\" />\n ) : (\n <Network className=\"w-5 h-5 text-text-secondary\" />\n )}\n <h3 className=\"font-semibold text-text-primary\">\n {isRest\n ? tr('vibeDetails.restPlaygroundTitle', 'REST API Playground')\n : tr('vibeDetails.graphqlPlaygroundTitle', 'GraphQL Playground')}\n </h3>\n </div>\n <div className=\"flex items-center gap-2\">\n <input\n type=\"url\"\n value={endpointUrl}\n onChange={(e) => setEndpointUrl(e.target.value)}\n placeholder={\n isRest\n ? tr(\n 'vibeDetails.enterSwaggerUrl',\n 'Enter OpenAPI/Swagger URL (e.g. https://petstore3.swagger.io/api/v3/openapi.json)'\n )\n : tr(\n 'vibeDetails.enterGraphqlUrl',\n 'Enter GraphQL endpoint URL (e.g. https://countries.trevorblades.com/graphql)'\n )\n }\n className=\"flex-1 px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder text-sm\"\n onKeyDown={(e) => e.key === 'Enter' && handleSave()}\n />\n <button\n onClick={handleSave}\n disabled={saving || !endpointUrl.trim()}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50 text-sm whitespace-nowrap\"\n >\n {saving ? (\n <Loader2 className=\"w-4 h-4 animate-spin\" />\n ) : saved ? (\n <Check className=\"w-4 h-4\" />\n ) : (\n <ExternalLinkIcon className=\"w-4 h-4\" />\n )}\n {saving\n ? tr('common.saving', 'Saving...')\n : saved\n ? tr('common.saved', 'Saved!')\n : tr('vibeDetails.loadApi', 'Load API')}\n </button>\n </div>\n {!configLoaded && (\n <p className=\"text-xs text-text-muted mt-1\">\n {tr('vibeDetails.loadingConfig', 'Loading saved configuration...')}\n </p>\n )}\n </div>\n </Card>\n\n {/* Iframe (gated on iframe-token mint when agentId is present) */}\n {agentId && !iframeToken ? (\n <div className=\"p-8 text-center text-sm text-text-secondary rounded-md border border-border-default bg-bg-sunken\">\n {tokenError\n ? tr('vibeDetails.iframeTokenError', `Iframe token error: ${tokenError}`)\n : tr('vibeDetails.mintingIframeToken', 'Authorizing iframe…')}\n </div>\n ) : (\n <iframe\n key={iframeKey}\n src={iframeSrc}\n title={isRest ? 'REST API Playground' : 'GraphQL Playground'}\n className=\"w-full rounded-md border border-border-default bg-bg-sunken\"\n style={{ height: '700px' }}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups\"\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-vibecontrols",
3
- "version": "2026.525.6",
3
+ "version": "2026.525.7",
4
4
  "description": "VibeControls microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [