@burdenoff/microfe-vibecontrols 2026.602.2 → 2026.602.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/sessions/SessionShareDialog.js +24 -462
- package/dist/components/sessions/SessionShareDialog.js.map +1 -1
- package/dist/components/sharing/entityShareOps.js +106 -0
- package/dist/components/sharing/entityShareOps.js.map +1 -1
- package/dist/components/sharing/shareRegistry.js +3 -3
- package/dist/components/sharing/shareRegistry.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckShareDialog.js +19 -335
- package/dist/components/vibedeck/VibeDeckShareDialog.js.map +1 -1
- package/dist/constants/permissions.js +1 -0
- package/dist/constants/permissions.js.map +1 -1
- package/dist/generated/wspace-types.js +9 -11
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/pages/SessionsPage.js +1011 -1007
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +40 -41
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/shareUrl.js +0 -41
- package/dist/utils/shareUrl.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VibeDeckPage.js","names":[],"sources":["../../src/pages/VibeDeckPage.tsx"],"sourcesContent":["import { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport { Copy, Eye, Pencil, Play, RefreshCw, Share2, Star, Trash2 } from 'lucide-react';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport { isNative, nativeNotify } from '../utils/nativeBridge';\nimport { AnimatePresence } from 'framer-motion';\nimport {\n PageHeader,\n EmptyState,\n LoadingState,\n ErrorState,\n ConfirmDialog,\n QuotaExhaustedDialog,\n EnableRemoteTaskDialog,\n SelectionCheckbox,\n GetHelpButton,\n LinkToVibePanel,\n LINK_TO_VIBE_DEFAULT,\n linkToVibeInput,\n type LinkToVibeValue,\n} from '@/components/shared';\nimport {\n VibeDeckGrid,\n VibeDeckSwitcher,\n VibeDeckForm,\n VibeDeckButtonForm,\n VibeDeckShareDialog,\n VibeDeckExecutionLog,\n} from '@/components/vibedeck';\nimport type { ExecutionLogEntry } from '@/components/vibedeck';\nimport {\n useListVibeDecksQuery,\n useGetVibeDeckQuery,\n useListAgentsQuery,\n useCreateVibeDeckMutation,\n useUpdateVibeDeckMutation,\n useDeleteVibeDeckMutation,\n useSetDefaultVibeDeckMutation,\n useDuplicateVibeDeckMutation,\n useCreateVibeDeckButtonMutation,\n useUpdateVibeDeckButtonMutation,\n useDeleteVibeDeckButtonMutation,\n useMoveVibeDeckButtonMutation,\n useExecuteVibeDeckButtonMutation,\n} from '@/generated/wspace-operations';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { isQuotaExhaustedError, markQuotaHandledLocally } from '@/utils/quotaUtils';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport {\n enableRemoteTaskExecution,\n isRemoteTaskDeniedError,\n} from '@/services/agentRemoteTaskGates';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\n\ntype ModalState =\n | { type: 'none' }\n | { type: 'createDeck' }\n | { type: 'editDeck'; deckId: string }\n | { type: 'createButton'; row: number; column: number }\n | { type: 'editButton'; buttonId: string }\n | { type: 'confirmDelete'; target: 'deck' | 'button'; id: string; name: string }\n | { type: 'confirmExecute'; buttonId: string; label: string; detail: string }\n | { type: 'duplicateDeck'; deckId: string }\n | { type: 'shareDeck'; deckId: string; deckName: string };\n\ninterface ErrorToast {\n message: string;\n variant: 'success' | 'error';\n detail?: string | null;\n id: number;\n}\n\nexport function VibeDeckPage() {\n const navigate = useVibeNavigate();\n const { workspaceId } = useVibeControls();\n const bus = useEventBus();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const tr = (\n (i18n) =>\n (key: string, fallback: string): string => {\n const v = i18n.t(key);\n return v === key ? fallback : v;\n }\n )(useI18n());\n\n const deckPermsRegistered = (\n Array.isArray(permissions) ? permissions : permissions?.permissionStrings\n )?.some?.((p: string) => p.startsWith('vibedeck:'));\n const canList = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_LIST) : true;\n const canCreate = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_CREATE) : true;\n const canUpdate = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_UPDATE) : true;\n const canDelete = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_DELETE) : true;\n const canExecute = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_EXECUTE) : true;\n const shouldSkipQueries = permissionsLoading;\n\n const { activeVibeDeckId, setActiveVibeDeckId, vibeDeckMode, setVibeDeckMode } =\n useVibeControlsStore();\n const isPreview = vibeDeckMode === 'preview';\n const effectiveCanCreate = isPreview ? false : canCreate;\n const effectiveCanUpdate = isPreview ? false : canUpdate;\n const effectiveCanDelete = isPreview ? false : canDelete;\n\n const [modal, setModal] = useState<ModalState>({ type: 'none' });\n const [executingButtonId, setExecutingButtonId] = useState<string | null>(null);\n const [selectedDeckIds, setSelectedDeckIds] = useState<Set<string>>(new Set());\n const [selectedButtonIds, setSelectedButtonIds] = useState<Set<string>>(new Set());\n const [bulkDeckAction, setBulkDeckAction] = useState<'delete' | null>(null);\n const [bulkButtonAction, setBulkButtonAction] = useState<'execute' | 'delete' | null>(null);\n const [bulkBusy, setBulkBusy] = useState<\n 'duplicateDeck' | 'deleteDeck' | 'setDefaultDeck' | 'executeButton' | 'deleteButton' | null\n >(null);\n const [toasts, setToasts] = useState<ErrorToast[]>([]);\n const toastTimers = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());\n\n // F9: Optional link to a Vibe + visibility. Default is unlinked + PRIVATE.\n // We thread these into the create-deck mutation defensively — if the\n // svc schema does not yet define them, the resolver ignores them.\n const [createDeckLink, setCreateDeckLink] = useState<LinkToVibeValue>(LINK_TO_VIBE_DEFAULT);\n\n // Execution log state\n const [executionLog, setExecutionLog] = useState<ExecutionLogEntry[]>([]);\n const [executionLogExpanded, setExecutionLogExpanded] = useState(true);\n const [buttonStatuses, setButtonStatuses] = useState<\n Map<string, 'idle' | 'executing' | 'success' | 'error'>\n >(new Map());\n const [quotaDialog, setQuotaDialog] = useState<{ title: string; message: string } | null>(null);\n // Reactive \"enable remote execution\" prompt when a deck-button run is denied\n // because the target agent's remote-task gate is off.\n const [remoteTaskPrompt, setRemoteTaskPrompt] = useState<{\n buttonId: string;\n agentId: string;\n } | null>(null);\n const [enablingRemoteTask, setEnablingRemoteTask] = useState(false);\n const { profiles: deniedAgentProfiles } = useActiveAgentProfile(\n remoteTaskPrompt?.agentId ?? null\n );\n // The runner targets the agent's DEFAULT profile, so the gate must be written\n // there — not the UI's \"active\" profile (which can differ on multi-profile\n // agents and would unlock the wrong daemon, leaving the run still denied).\n const deniedAgentExecProfile = deniedAgentProfiles.find((p) => p.isDefault)?.name ?? 'default';\n const statusTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n const timers = statusTimers.current;\n return () => {\n for (const timer of timers.values()) clearTimeout(timer);\n };\n }, []);\n\n const addLogEntry = useCallback((entry: Omit<ExecutionLogEntry, 'id'>) => {\n const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const newEntry = { ...entry, id };\n setExecutionLog((prev) => [...prev.slice(-49), newEntry]);\n return id;\n }, []);\n\n const updateLogEntry = useCallback((id: string, updates: Partial<ExecutionLogEntry>) => {\n setExecutionLog((prev) =>\n prev.map((entry) => (entry.id === id ? { ...entry, ...updates } : entry))\n );\n }, []);\n\n const setButtonStatus = useCallback(\n (buttonId: string, status: 'idle' | 'executing' | 'success' | 'error') => {\n setButtonStatuses((prev) => {\n const next = new Map(prev);\n next.set(buttonId, status);\n return next;\n });\n if (status === 'success' || status === 'error') {\n const timer = setTimeout(() => {\n setButtonStatuses((prev) => {\n const next = new Map(prev);\n if (next.get(buttonId) === status) next.delete(buttonId);\n return next;\n });\n statusTimers.current.delete(buttonId);\n }, 3000);\n const existing = statusTimers.current.get(buttonId);\n if (existing) clearTimeout(existing);\n statusTimers.current.set(buttonId, timer);\n }\n },\n []\n );\n\n useEffect(() => {\n const timers = toastTimers.current;\n return () => {\n for (const timer of timers.values()) clearTimeout(timer);\n };\n }, []);\n\n const showToast = useCallback(\n (message: string, variant: 'success' | 'error', detail?: string | null, duration?: number) => {\n const id = Date.now() + Math.random();\n setToasts((prev) => [...prev, { message, variant, detail, id }]);\n const autoDismiss = duration ?? (variant === 'success' ? 10000 : 30000);\n const timer = setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n toastTimers.current.delete(id);\n }, autoDismiss);\n toastTimers.current.set(id, timer);\n },\n []\n );\n\n const dismissToast = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n const timer = toastTimers.current.get(id);\n if (timer) {\n clearTimeout(timer);\n toastTimers.current.delete(id);\n }\n }, []);\n\n const showQuotaDialog = useCallback((title: string, message: string) => {\n // Coordinate with the global QuotaExhaustedProvider so it skips its\n // own dialog when this page renders a local one (BOFF-2625 review).\n markQuotaHandledLocally();\n setQuotaDialog({ title, message });\n }, []);\n\n const {\n data: decksData,\n loading: decksLoading,\n error: decksError,\n refetch: refetchDecks,\n } = useListVibeDecksQuery({\n variables: { pagination: { limit: 50 } },\n skip: shouldSkipQueries,\n });\n\n const decks = useMemo(() => decksData?.vibeDecks?.items || [], [decksData]);\n\n const effectiveActiveDeckId =\n activeVibeDeckId ||\n decks.find((d: { isDefault: boolean }) => d.isDefault)?.id ||\n decks[0]?.id ||\n null;\n\n const {\n data: deckData,\n loading: deckLoading,\n refetch: refetchDeck,\n } = useGetVibeDeckQuery({\n variables: { id: effectiveActiveDeckId! },\n skip: !effectiveActiveDeckId || shouldSkipQueries,\n });\n\n const activeDeck = deckData?.vibeDeck;\n\n const selectedDecks = useMemo(\n () => decks.filter((deck: { id: string }) => selectedDeckIds.has(deck.id)),\n [decks, selectedDeckIds]\n );\n\n const selectedButtons = useMemo(\n () =>\n activeDeck?.buttons?.filter((button: { id: string }) => selectedButtonIds.has(button.id)) ??\n [],\n [activeDeck?.buttons, selectedButtonIds]\n );\n\n const allDecksSelected =\n decks.length > 0 && decks.every((deck: { id: string }) => selectedDeckIds.has(deck.id));\n const partiallySelectedDecks =\n decks.some((deck: { id: string }) => selectedDeckIds.has(deck.id)) && !allDecksSelected;\n const allButtonsSelected =\n (activeDeck?.buttons?.length ?? 0) > 0 &&\n (activeDeck?.buttons ?? []).every((button: { id: string }) => selectedButtonIds.has(button.id));\n const partiallySelectedButtons =\n (activeDeck?.buttons ?? []).some((button: { id: string }) =>\n selectedButtonIds.has(button.id)\n ) && !allButtonsSelected;\n\n const { data: agentsData } = useListAgentsQuery({\n variables: { pagination: { limit: 100 } },\n fetchPolicy: 'cache-and-network',\n skip: shouldSkipQueries,\n });\n const agents = (agentsData?.vibecontrolsAgents ?? []).map(\n (a: { id: string; name: string; isActive: boolean }) => ({\n id: a.id,\n name: a.name,\n isActive: a.isActive,\n })\n );\n\n const [createDeck, { loading: createDeckLoading }] = useCreateVibeDeckMutation({\n refetchQueries: ['ListVibeDecks'],\n });\n const { setDraftTagIds: setDeckDraftTagIds, flushTags: flushDeckTags } =\n useDraftEntityTags('VIBECONTROLS_VIBEDECK');\n const [updateDeck, { loading: updateDeckLoading }] = useUpdateVibeDeckMutation({\n refetchQueries: ['ListVibeDecks', 'GetVibeDeck'],\n });\n const [deleteDeck] = useDeleteVibeDeckMutation({\n refetchQueries: ['ListVibeDecks'],\n });\n const [setDefaultDeck] = useSetDefaultVibeDeckMutation({\n refetchQueries: ['ListVibeDecks', 'GetVibeDeck'],\n });\n const [duplicateDeck] = useDuplicateVibeDeckMutation({\n refetchQueries: ['ListVibeDecks'],\n });\n const [createButton, { loading: createButtonLoading }] = useCreateVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [updateButton, { loading: updateButtonLoading }] = useUpdateVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [deleteButton] = useDeleteVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [moveButton] = useMoveVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [executeButton] = useExecuteVibeDeckButtonMutation();\n\n useEffect(() => {\n setSelectedButtonIds(new Set());\n }, [effectiveActiveDeckId]);\n\n const toggleDeckSelection = useCallback((deckId: string, checked: boolean) => {\n setSelectedDeckIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(deckId);\n } else {\n next.delete(deckId);\n }\n return next;\n });\n }, []);\n\n const toggleAllDecks = useCallback(\n (checked: boolean) => {\n setSelectedDeckIds((prev) => {\n const next = new Set(prev);\n decks.forEach((deck: { id: string }) => {\n if (checked) {\n next.add(deck.id);\n } else {\n next.delete(deck.id);\n }\n });\n return next;\n });\n },\n [decks]\n );\n\n const clearDeckSelection = useCallback(() => {\n setSelectedDeckIds(new Set());\n }, []);\n\n const toggleButtonSelection = useCallback((buttonId: string, checked: boolean) => {\n setSelectedButtonIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(buttonId);\n } else {\n next.delete(buttonId);\n }\n return next;\n });\n }, []);\n\n const toggleAllButtons = useCallback(\n (checked: boolean) => {\n setSelectedButtonIds((prev) => {\n const next = new Set(prev);\n (activeDeck?.buttons ?? []).forEach((button: { id: string }) => {\n if (checked) {\n next.add(button.id);\n } else {\n next.delete(button.id);\n }\n });\n return next;\n });\n },\n [activeDeck?.buttons]\n );\n\n const clearButtonSelection = useCallback(() => {\n setSelectedButtonIds(new Set());\n }, []);\n\n const handleCreateDeck = useCallback(\n async (data: {\n name: string;\n description: string;\n colorTheme: string;\n gridColumns: number;\n gridRows: number;\n }) => {\n try {\n // F9: Thread the optional Vibe link through the mutation input.\n // `CreateVibeDeckInput` now declares `vibeId` + `visibility`, so the\n // link fields type-check directly — no defensive cast needed.\n const res = await createDeck({\n variables: {\n input: {\n name: data.name,\n description: data.description || null,\n colorTheme: data.colorTheme || null,\n gridColumns: data.gridColumns,\n gridRows: data.gridRows,\n ...linkToVibeInput(createDeckLink),\n },\n },\n });\n const newDeckId = res.data?.createVibeDeck?.id;\n setModal({ type: 'none' });\n showToast('Deck created', 'success');\n setCreateDeckLink(LINK_TO_VIBE_DEFAULT);\n if (newDeckId) await flushDeckTags(newDeckId);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setModal({ type: 'none' });\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to create more decks.'\n );\n return;\n }\n\n showToast(err instanceof Error ? err.message : 'Failed to create deck', 'error');\n }\n },\n [createDeck, flushDeckTags, showQuotaDialog, showToast, createDeckLink]\n );\n\n const handleUpdateDeck = useCallback(\n async (data: {\n name: string;\n description: string;\n colorTheme: string;\n gridColumns: number;\n gridRows: number;\n }) => {\n if (modal.type !== 'editDeck') return;\n try {\n await updateDeck({\n variables: {\n id: modal.deckId,\n input: {\n name: data.name,\n description: data.description || null,\n colorTheme: data.colorTheme || null,\n gridColumns: data.gridColumns,\n gridRows: data.gridRows,\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Deck updated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to update deck', 'error');\n }\n },\n [updateDeck, modal, showToast]\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (modal.type !== 'confirmDelete') return;\n try {\n if (modal.target === 'deck') {\n await deleteDeck({ variables: { id: modal.id } });\n if (activeVibeDeckId === modal.id) {\n setActiveVibeDeckId(null);\n }\n showToast('Deck deleted', 'success');\n } else {\n await deleteButton({ variables: { id: modal.id } });\n showToast('Button deleted', 'success');\n }\n setModal({ type: 'none' });\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete', 'error');\n if (isNative()) void nativeNotify('error');\n }\n }, [modal, deleteDeck, deleteButton, activeVibeDeckId, setActiveVibeDeckId, showToast]);\n\n const doExecuteButton = useCallback(\n async (buttonId: string, allowRemotePrompt = true) => {\n const button = activeDeck?.buttons?.find((b: { id: string }) => b.id === buttonId);\n if (!button || !button.action) return;\n\n const action = button.action;\n\n // Add log entry\n const logId = addLogEntry({\n buttonId,\n buttonLabel: button.label,\n actionType: action.actionType as any,\n command:\n action.actionType === 'WEBHOOK'\n ? `POST ${action.webhookUrl || ''}`\n : action.command || undefined,\n status: 'running',\n startedAt: new Date(),\n });\n\n setExecutingButtonId(buttonId);\n setButtonStatus(buttonId, 'executing');\n\n try {\n const result = await executeButton({ variables: { id: buttonId } });\n const exec = result.data?.executeVibeDeckButton;\n // The agent rejected the run because its remote-task gate is off — offer\n // to enable it in context (and retry) instead of a dead-end error.\n if (exec && isRemoteTaskDeniedError(exec) && exec.agentId) {\n setButtonStatus(buttonId, 'error');\n updateLogEntry(logId, {\n status: 'error',\n error: allowRemotePrompt\n ? 'Remote task execution is disabled on this agent.'\n : 'Remote execution still blocked after enabling — check the agent’s Security settings.',\n output: exec.output,\n completedAt: new Date(),\n });\n // allowRemotePrompt is false on the post-enable retry so a still-denied\n // run does not re-open the dialog in a loop.\n if (allowRemotePrompt) {\n setRemoteTaskPrompt({ buttonId, agentId: exec.agentId });\n }\n return;\n }\n if (exec) {\n const isSuccess = exec.status === 'success';\n setButtonStatus(buttonId, isSuccess ? 'success' : 'error');\n updateLogEntry(logId, {\n status: isSuccess ? 'success' : 'error',\n output: exec.output,\n exitCode: exec.exitCode,\n webhookStatusCode: exec.webhookStatusCode,\n completedAt: new Date(),\n });\n if (isSuccess) {\n bus.emitCustom('vibecontrols.vibedeck.button_executed', {\n workspaceId: workspaceId ?? undefined,\n buttonId,\n deckId: effectiveActiveDeckId ?? undefined,\n });\n }\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setButtonStatus(buttonId, 'error');\n updateLogEntry(logId, {\n status: 'error',\n error: 'Usage quota exhausted',\n completedAt: new Date(),\n });\n showQuotaDialog(\n 'Execution Quota Reached',\n 'You have used the execution quota for your current plan. Upgrade to continue running Vibe Deck actions.'\n );\n return;\n }\n\n const errorMsg = err instanceof Error ? err.message : 'Execution failed';\n setButtonStatus(buttonId, 'error');\n updateLogEntry(logId, {\n status: 'error',\n error: errorMsg,\n completedAt: new Date(),\n });\n } finally {\n setExecutingButtonId(null);\n }\n },\n [\n activeDeck,\n executeButton,\n addLogEntry,\n updateLogEntry,\n setButtonStatus,\n showQuotaDialog,\n bus,\n workspaceId,\n effectiveActiveDeckId,\n ]\n );\n\n const handleEnableRemoteTaskConfirm = useCallback(\n async ({ shell, file }: { shell: boolean; file: boolean }) => {\n if (!remoteTaskPrompt) return;\n const { buttonId, agentId } = remoteTaskPrompt;\n setEnablingRemoteTask(true);\n try {\n await enableRemoteTaskExecution(\n { id: agentId, profile: deniedAgentExecProfile },\n { shell, file }\n );\n setRemoteTaskPrompt(null);\n // Retry the run ONCE (allowRemotePrompt=false) so a still-denied result\n // does not re-open this dialog in a loop.\n await doExecuteButton(buttonId, false);\n } catch (err) {\n showToast(\n err instanceof Error ? err.message : 'Failed to enable remote execution',\n 'error'\n );\n } finally {\n setEnablingRemoteTask(false);\n }\n },\n [remoteTaskPrompt, deniedAgentExecProfile, doExecuteButton, showToast]\n );\n\n const handleExecuteButton = useCallback(\n async (buttonId: string) => {\n const button = activeDeck?.buttons?.find((b: { id: string }) => b.id === buttonId);\n if (!button) return;\n\n bus.emitCustom('vibecontrols.vibedeck.button_executed_clicked', {\n workspaceId: workspaceId ?? undefined,\n buttonId,\n deckId: effectiveActiveDeckId ?? undefined,\n });\n\n if (button.confirmationRequired) {\n const action = button.action;\n const detail =\n action?.actionType === 'WEBHOOK'\n ? `POST ${action.webhookUrl || ''}`\n : action?.command || '';\n setModal({ type: 'confirmExecute', buttonId, label: button.label, detail });\n return;\n }\n\n await doExecuteButton(buttonId);\n },\n [activeDeck, doExecuteButton, bus, workspaceId, effectiveActiveDeckId]\n );\n\n const handleConfirmExecute = useCallback(async () => {\n if (modal.type !== 'confirmExecute') return;\n const buttonId = modal.buttonId;\n setModal({ type: 'none' });\n await doExecuteButton(buttonId);\n }, [modal, doExecuteButton]);\n\n const handleCreateButton = useCallback(\n async (data: {\n label: string;\n color: string;\n category: string;\n keyboardShortcut: string;\n confirmationRequired: boolean;\n rowSpan: number;\n colSpan: number;\n actionId: string;\n }) => {\n if (modal.type !== 'createButton' || !effectiveActiveDeckId) return;\n\n try {\n await createButton({\n variables: {\n input: {\n vibeDeckId: effectiveActiveDeckId,\n label: data.label,\n actionId: data.actionId,\n row: modal.row,\n column: modal.column,\n rowSpan: data.rowSpan,\n colSpan: data.colSpan,\n color: data.color || null,\n category: data.category || null,\n keyboardShortcut: data.keyboardShortcut || null,\n confirmationRequired: data.confirmationRequired,\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Button created', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to create button', 'error');\n }\n },\n [modal, createButton, effectiveActiveDeckId, showToast]\n );\n\n const handleUpdateButton = useCallback(\n async (data: {\n label: string;\n color: string;\n category: string;\n keyboardShortcut: string;\n confirmationRequired: boolean;\n rowSpan: number;\n colSpan: number;\n actionId: string;\n }) => {\n if (modal.type !== 'editButton') return;\n\n try {\n await updateButton({\n variables: {\n id: modal.buttonId,\n input: {\n label: data.label,\n actionId: data.actionId,\n color: data.color || null,\n category: data.category || null,\n keyboardShortcut: data.keyboardShortcut || null,\n confirmationRequired: data.confirmationRequired,\n rowSpan: data.rowSpan,\n colSpan: data.colSpan,\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Button updated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to update button', 'error');\n }\n },\n [modal, updateButton, showToast]\n );\n\n const handleDropButton = useCallback(\n async (buttonId: string, targetRow: number, targetColumn: number) => {\n try {\n await moveButton({\n variables: {\n id: buttonId,\n input: { row: targetRow, column: targetColumn },\n },\n });\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to move button', 'error');\n }\n },\n [moveButton, showToast]\n );\n\n const handleDuplicateDeck = useCallback(\n async (deckId: string) => {\n const deck = decks.find((d: { id: string; name: string }) => d.id === deckId);\n if (!deck) return;\n try {\n const newName = `${deck.name} (Copy)`;\n await duplicateDeck({ variables: { id: deckId, name: newName } });\n showToast('Deck duplicated', 'success');\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to duplicate more decks.'\n );\n return;\n }\n\n showToast(err instanceof Error ? err.message : 'Failed to duplicate deck', 'error');\n }\n },\n [decks, duplicateDeck, showQuotaDialog, showToast]\n );\n\n const handleSetDefault = useCallback(\n async (id: string) => {\n try {\n await setDefaultDeck({ variables: { id } });\n showToast('Default deck set', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to set default', 'error');\n }\n },\n [setDefaultDeck, showToast]\n );\n\n const handleSetSelectedDefault = useCallback(async () => {\n if (selectedDecks.length !== 1) return;\n setBulkBusy('setDefaultDeck');\n try {\n await setDefaultDeck({ variables: { id: selectedDecks[0].id } });\n showToast('Default deck set', 'success');\n clearDeckSelection();\n await refetchDecks();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to set default deck', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedDecks, setDefaultDeck, showToast, clearDeckSelection, refetchDecks]);\n\n const handleBulkDuplicateDecks = useCallback(async () => {\n if (selectedDecks.length === 0) return;\n setBulkBusy('duplicateDeck');\n try {\n const results = await Promise.allSettled(\n selectedDecks.map((deck: { id: string; name: string }) =>\n duplicateDeck({ variables: { id: deck.id, name: `${deck.name} (Copy)` } })\n )\n );\n\n const quotaRejected = results.some(\n (result: PromiseSettledResult<unknown>): result is PromiseRejectedResult =>\n result.status === 'rejected' && isQuotaExhaustedError(result.reason)\n );\n\n if (quotaRejected) {\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to duplicate more decks.'\n );\n return;\n }\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n showToast(\n `Duplicated ${succeeded} deck${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearDeckSelection();\n await refetchDecks();\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to duplicate more decks.'\n );\n return;\n }\n\n showToast(err instanceof Error ? err.message : 'Failed to duplicate decks', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedDecks, duplicateDeck, showQuotaDialog, showToast, clearDeckSelection, refetchDecks]);\n\n const handleBulkDeleteDecks = useCallback(async () => {\n if (selectedDecks.length === 0) return;\n setBulkBusy('deleteDeck');\n try {\n const results = await Promise.allSettled(\n selectedDecks.map((deck: { id: string }) => deleteDeck({ variables: { id: deck.id } }))\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n if (selectedDecks.some((deck: { id: string }) => deck.id === activeVibeDeckId)) {\n setActiveVibeDeckId(null);\n }\n showToast(\n `Deleted ${succeeded} deck${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearDeckSelection();\n setBulkDeckAction(null);\n await refetchDecks();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete decks', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [\n selectedDecks,\n deleteDeck,\n activeVibeDeckId,\n setActiveVibeDeckId,\n showToast,\n clearDeckSelection,\n refetchDecks,\n ]);\n\n const handleBulkExecuteButtons = useCallback(async () => {\n if (selectedButtons.length === 0) return;\n setBulkBusy('executeButton');\n let succeeded = 0;\n let failed = 0;\n try {\n for (const button of selectedButtons) {\n try {\n const result = await executeButton({ variables: { id: button.id } });\n const exec = result.data?.executeVibeDeckButton;\n if (exec?.status === 'success') {\n succeeded += 1;\n } else {\n failed += 1;\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setBulkButtonAction(null);\n showQuotaDialog(\n 'Execution Quota Reached',\n 'You have used the execution quota for your current plan. Upgrade to continue running Vibe Deck actions.'\n );\n return;\n }\n\n failed += 1;\n }\n }\n showToast(\n `Executed ${succeeded} button${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearButtonSelection();\n setBulkButtonAction(null);\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to execute buttons', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedButtons, executeButton, showQuotaDialog, showToast, clearButtonSelection]);\n\n const handleBulkDeleteButtons = useCallback(async () => {\n if (selectedButtons.length === 0) return;\n setBulkBusy('deleteButton');\n try {\n const results = await Promise.allSettled(\n selectedButtons.map((button: { id: string }) =>\n deleteButton({ variables: { id: button.id } })\n )\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n showToast(\n `Deleted ${succeeded} button${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearButtonSelection();\n setBulkButtonAction(null);\n await refetchDeck();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete buttons', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedButtons, deleteButton, showToast, clearButtonSelection, refetchDeck]);\n\n if (permissionsLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading permissions...\" />\n </MotionPage>\n );\n }\n\n if (permissions && (permissions.permissionStrings?.length ?? 0) > 0 && !canList) {\n return (\n <MotionPage>\n <AccessDenied />\n </MotionPage>\n );\n }\n\n if (decksLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading Vibe Decks...\" />\n </MotionPage>\n );\n }\n\n if (decksError) {\n return (\n <MotionPage>\n <ErrorState message={decksError.message} onRetry={() => refetchDecks()} />\n </MotionPage>\n );\n }\n\n const editingButton =\n modal.type === 'editButton'\n ? activeDeck?.buttons?.find((b: { id: string }) => b.id === modal.buttonId)\n : null;\n const editingDeck =\n modal.type === 'editDeck' ? decks.find((d: { id: string }) => d.id === modal.deckId) : null;\n\n return (\n <MotionPage className=\"p-4 sm:p-6 space-y-6\">\n <PageHeader\n title={tr('nav.vibeDeck', 'Vibe Deck')}\n description=\"Your digital command board — execute commands or trigger webhooks with one click\"\n actions={\n <div className=\"flex items-center gap-2\">\n <div\n data-tour=\"vibedeck-mode-switcher\"\n className=\"flex items-center rounded-lg border border-border-default bg-bg-secondary p-0.5\"\n >\n <button\n type=\"button\"\n onClick={() => setVibeDeckMode('preview')}\n className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all ${\n isPreview\n ? 'bg-action-primary-bg text-action-primary-text shadow-sm'\n : 'text-text-tertiary hover:text-text-primary'\n }`}\n title={isPreview ? 'Preview mode — execute only' : 'Switch to Preview mode'}\n aria-pressed={isPreview}\n >\n <Eye size={14} />\n Preview\n </button>\n <button\n type=\"button\"\n onClick={() => setVibeDeckMode('edit')}\n className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all ${\n !isPreview\n ? 'bg-action-primary-bg text-action-primary-text shadow-sm'\n : 'text-text-tertiary hover:text-text-primary'\n }`}\n title={!isPreview ? 'Edit mode — full editing' : 'Switch to Edit mode'}\n aria-pressed={!isPreview}\n >\n <Pencil size={14} />\n Edit\n </button>\n </div>\n {effectiveActiveDeckId && activeDeck && canUpdate && (\n // Sharing a deck is a `vibedeck:update`-scoped action — all four\n // backend ops (create / update / revoke share-link, plus the\n // owner-only LIST query `vibeDeckShareLinks`) carry\n // `@rbac(action:\"update\", resource:\"vibedeck\")`. Viewers would\n // see this button, click it, hit the share dialog, then bounce\n // off a Forbidden error from the gateway. Gate the trigger.\n <button\n type=\"button\"\n onClick={() =>\n setModal({\n type: 'shareDeck',\n deckId: effectiveActiveDeckId,\n deckName: activeDeck.name,\n })\n }\n className=\"p-2 rounded-lg hover:bg-bg-tertiary text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Share deck\"\n >\n <Share2 size={16} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={() => {\n refetchDecks();\n if (effectiveActiveDeckId) refetchDeck();\n }}\n className=\"p-2 rounded-lg hover:bg-bg-tertiary text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Refresh\"\n >\n <RefreshCw size={16} />\n </button>\n </div>\n }\n />\n\n {!isPreview && decks.length > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allDecksSelected}\n indeterminate={partiallySelectedDecks}\n onChange={toggleAllDecks}\n ariaLabel=\"Select all vibe decks\"\n />\n <span className=\"text-sm font-medium text-text-primary\">Select all decks</span>\n </div>\n {selectedDeckIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearDeckSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedDeckIds.size} selected\n </span>\n <button\n type=\"button\"\n onClick={handleSetSelectedDefault}\n disabled={\n selectedDecks.length !== 1 || selectedDecks[0]?.isDefault || bulkBusy !== null\n }\n className=\"rounded-md border border-status-warning-border px-3 py-2 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Star size={14} />\n Set Selected Default\n </span>\n </button>\n <button\n type=\"button\"\n onClick={handleBulkDuplicateDecks}\n disabled={selectedDecks.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-border-default px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Copy size={14} />\n Duplicate Selected{selectedDecks.length > 0 ? ` (${selectedDecks.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setBulkDeckAction('delete')}\n disabled={selectedDecks.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Trash2 size={14} />\n Delete Selected{selectedDecks.length > 0 ? ` (${selectedDecks.length})` : ''}\n </span>\n </button>\n </div>\n </div>\n </div>\n )}\n\n <div data-tour=\"vibedeck-switcher\">\n <VibeDeckSwitcher\n decks={decks.map((d: any) => ({\n id: d.id,\n name: d.name,\n icon: d.icon || null,\n colorTheme: d.colorTheme || null,\n isDefault: d.isDefault,\n }))}\n activeDeckId={effectiveActiveDeckId}\n selectedDeckIds={selectedDeckIds}\n onSelectDeck={(id) => setActiveVibeDeckId(id)}\n onToggleSelectDeck={toggleDeckSelection}\n onCreateDeck={() => setModal({ type: 'createDeck' })}\n onSetDefault={handleSetDefault}\n onDuplicate={(id) => handleDuplicateDeck(id)}\n onDelete={(id) => {\n const deck = decks.find((d: { id: string }) => d.id === id);\n setModal({\n type: 'confirmDelete',\n target: 'deck',\n id,\n name: deck?.name || 'this deck',\n });\n }}\n onEdit={(id) => setModal({ type: 'editDeck', deckId: id })}\n onShare={(id) => {\n const deck = decks.find((d: { id: string; name: string }) => d.id === id);\n if (deck) setModal({ type: 'shareDeck', deckId: id, deckName: deck.name });\n }}\n // Create button is ungated by preview mode so users can always add a\n // new deck. Update/delete stay gated because they mutate selected decks.\n canCreate={canCreate}\n canUpdate={effectiveCanUpdate}\n canDelete={effectiveCanDelete}\n />\n </div>\n\n <AnimatePresence mode=\"wait\">\n {!activeDeck && !deckLoading && decks.length === 0 && (\n <EmptyState\n title=\"No Vibe Decks yet\"\n description=\"Create your first Vibe Deck to start organizing your commands and webhooks\"\n action={\n <div className=\"flex items-center gap-2\">\n {canCreate && (\n <button\n type=\"button\"\n onClick={() => setModal({ type: 'createDeck' })}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:opacity-90 text-sm font-medium\"\n >\n Create Vibe Deck\n </button>\n )}\n <GetHelpButton prompt=\"What is a VibeDeck and how do I use it to organise controls?\" />\n </div>\n }\n />\n )}\n\n {deckLoading && <LoadingState message=\"Loading deck...\" />}\n </AnimatePresence>\n\n {activeDeck && (\n <div className=\"space-y-4\">\n {!isPreview && (activeDeck.buttons?.length ?? 0) > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allButtonsSelected}\n indeterminate={partiallySelectedButtons}\n onChange={toggleAllButtons}\n ariaLabel=\"Select all buttons in active deck\"\n />\n <span className=\"text-sm font-medium text-text-primary\">\n Select all buttons in this deck\n </span>\n </div>\n {selectedButtonIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearButtonSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedButtonIds.size} selected\n </span>\n <button\n type=\"button\"\n onClick={() => setBulkButtonAction('execute')}\n disabled={selectedButtons.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-success-border px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Play size={14} />\n Execute Selected\n {selectedButtons.length > 0 ? ` (${selectedButtons.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setBulkButtonAction('delete')}\n disabled={selectedButtons.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Trash2 size={14} />\n Delete Selected\n {selectedButtons.length > 0 ? ` (${selectedButtons.length})` : ''}\n </span>\n </button>\n </div>\n </div>\n </div>\n )}\n\n <div data-tour=\"vibedeck-grid\" className=\"relative\">\n <VibeDeckGrid\n gridColumns={activeDeck.gridColumns}\n gridRows={activeDeck.gridRows}\n buttons={(activeDeck.buttons || []).map((b: any) => ({\n id: b.id,\n label: b.label,\n icon: b.icon || null,\n color: b.color || null,\n category: b.category || null,\n confirmationRequired: b.confirmationRequired,\n keyboardShortcut: b.keyboardShortcut || null,\n actionId: b.actionId || null,\n action: b.action\n ? {\n id: b.action.id,\n name: b.action.name,\n displayName: b.action.displayName || null,\n actionType: b.action.actionType,\n command: b.action.command || null,\n script: b.action.script || null,\n webhookUrl: b.action.webhookUrl || null,\n targetAgentId: b.action.targetAgentId || null,\n }\n : null,\n row: b.row,\n column: b.column,\n rowSpan: b.rowSpan,\n colSpan: b.colSpan,\n }))}\n onExecuteButton={handleExecuteButton}\n onEditButton={(id) => setModal({ type: 'editButton', buttonId: id })}\n onDeleteButton={(id) => {\n const btn = activeDeck.buttons?.find((b: { id: string }) => b.id === id);\n setModal({\n type: 'confirmDelete',\n target: 'button',\n id,\n name: btn?.label || 'this button',\n });\n }}\n onDropButton={handleDropButton}\n onAddButton={(row, column) => setModal({ type: 'createButton', row, column })}\n executingButtonId={executingButtonId}\n canCreate={effectiveCanCreate}\n canUpdate={effectiveCanUpdate}\n canDelete={effectiveCanDelete}\n canExecute={canExecute}\n previewMode={isPreview}\n />\n\n {/* Fresh-deck guidance — overlay in preview mode when the\n deck has zero buttons. Prompts the user to switch to\n Edit mode, the canonical place to add buttons. */}\n {(activeDeck.buttons?.length ?? 0) === 0 && isPreview && (\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-none\">\n <div className=\"bg-bg-elevated/90 backdrop-blur-md border border-border-default rounded-lg p-6 max-w-md pointer-events-auto shadow-xl text-center\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibeDeck.emptyDeckTitle', 'This deck is empty')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-2\">\n {tr('vibeDeck.emptyDeckDescription', 'Switch to Edit mode to add buttons.')}\n </p>\n {canUpdate && (\n <button\n type=\"button\"\n onClick={() => setVibeDeckMode('edit')}\n className=\"mt-4 inline-flex items-center gap-2 px-4 py-2 rounded-md bg-action-primary-bg text-action-primary-text text-sm font-medium hover:opacity-90 transition-opacity\"\n >\n {tr('vibeDeck.editDeck', 'Edit deck')}\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n\n {executionLog.length > 0 && (\n <div data-tour=\"vibedeck-execution-log\">\n <VibeDeckExecutionLog\n entries={executionLog}\n expanded={executionLogExpanded}\n onToggleExpanded={() => setExecutionLogExpanded((prev) => !prev)}\n onClear={() => setExecutionLog([])}\n />\n </div>\n )}\n\n <AnimatePresence>\n {toasts.length > 0 && (\n <div className=\"fixed bottom-4 left-4 right-4 sm:left-auto sm:bottom-6 sm:right-6 z-50 flex flex-col gap-2 max-w-[calc(100vw-2rem)] sm:max-w-md\">\n {toasts.slice(-3).map((toast) => (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => dismissToast(toast.id))();\n }\n }}\n key={toast.id}\n className={`p-4 rounded-xl shadow-lg border cursor-pointer ${\n toast.variant === 'success'\n ? 'bg-status-success-bg/10 border-status-success-border/30 text-status-success-text'\n : 'bg-status-error-bg/10 border-status-error-border/30 text-status-error-text'\n }`}\n onClick={() => dismissToast(toast.id)}\n >\n <div className=\"font-medium text-sm\">{toast.message}</div>\n {toast.detail && (\n <pre className=\"text-xs font-mono opacity-80 mt-1 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {toast.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n </AnimatePresence>\n\n {modal.type === 'createDeck' && (\n <VibeDeckForm\n title=\"Create Vibe Deck\"\n onSubmit={handleCreateDeck}\n onCancel={() => {\n setModal({ type: 'none' });\n setCreateDeckLink(LINK_TO_VIBE_DEFAULT);\n }}\n isLoading={createDeckLoading}\n extraSection={\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('vibeDeck.tags', 'Tags')}\n </h3>\n <EntityTagPicker\n entityType=\"VIBECONTROLS_VIBEDECK\"\n onDraftChange={setDeckDraftTagIds}\n />\n </div>\n <LinkToVibePanel value={createDeckLink} onChange={setCreateDeckLink} />\n </div>\n }\n />\n )}\n\n {modal.type === 'editDeck' && editingDeck && (\n <VibeDeckForm\n title=\"Edit Vibe Deck\"\n initialData={{\n name: editingDeck.name,\n description: editingDeck.description || '',\n colorTheme: editingDeck.colorTheme || '',\n gridColumns: editingDeck.gridColumns,\n gridRows: editingDeck.gridRows,\n }}\n onSubmit={handleUpdateDeck}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={updateDeckLoading}\n extraSection={\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('vibeDeck.tags', 'Tags')}\n </h3>\n <EntityTagPicker entityType=\"VIBECONTROLS_VIBEDECK\" entityId={editingDeck.id} />\n </div>\n }\n />\n )}\n\n {modal.type === 'createButton' && (\n <VibeDeckButtonForm\n title=\"Add Button\"\n agents={agents}\n onSubmit={handleCreateButton}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={createButtonLoading}\n gridColumns={activeDeck?.gridColumns}\n gridRows={activeDeck?.gridRows}\n buttonRow={modal.row}\n buttonColumn={modal.column}\n />\n )}\n\n {modal.type === 'editButton' && editingButton && (\n <VibeDeckButtonForm\n title=\"Edit Button\"\n initialData={\n {\n label: editingButton.label,\n actionId: (editingButton as any).actionId || '',\n color: editingButton.color || '',\n category: editingButton.category || '',\n keyboardShortcut: editingButton.keyboardShortcut || '',\n confirmationRequired: editingButton.confirmationRequired,\n rowSpan: editingButton.rowSpan,\n colSpan: editingButton.colSpan,\n } as any\n }\n agents={agents}\n onSubmit={handleUpdateButton}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={updateButtonLoading}\n gridColumns={activeDeck?.gridColumns}\n gridRows={activeDeck?.gridRows}\n buttonRow={editingButton.row}\n buttonColumn={editingButton.column}\n />\n )}\n\n {modal.type === 'confirmDelete' && (\n <ConfirmDialog\n isOpen={true}\n title={`Delete ${modal.target === 'deck' ? 'Vibe Deck' : 'Button'}`}\n message={`Are you sure you want to delete \"${modal.name}\"?${modal.target === 'deck' ? ' All buttons in this deck will also be deleted.' : ''}`}\n confirmLabel=\"Delete\"\n variant=\"danger\"\n onConfirm={handleDeleteConfirm}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n {modal.type === 'confirmExecute' && (\n <ConfirmDialog\n isOpen={true}\n title={`Execute: ${modal.label}`}\n message={`Are you sure you want to execute this action?\\n\\n${modal.detail}`}\n confirmLabel=\"Execute\"\n variant=\"warning\"\n onConfirm={handleConfirmExecute}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n <ConfirmDialog\n isOpen={bulkDeckAction === 'delete'}\n title=\"Delete Vibe Decks\"\n message={`Are you sure you want to delete ${selectedDecks.length} selected deck${selectedDecks.length === 1 ? '' : 's'}? All buttons in those decks will also be deleted.`}\n confirmLabel=\"Delete Decks\"\n variant=\"danger\"\n onConfirm={handleBulkDeleteDecks}\n onClose={() => setBulkDeckAction(null)}\n isLoading={bulkBusy === 'deleteDeck'}\n />\n\n <ConfirmDialog\n isOpen={bulkButtonAction === 'execute'}\n title=\"Execute Vibe Deck Buttons\"\n message={`Execute ${selectedButtons.length} selected button${selectedButtons.length === 1 ? '' : 's'}? This may trigger commands, scripts, or webhooks immediately.`}\n confirmLabel=\"Execute Buttons\"\n variant=\"warning\"\n onConfirm={handleBulkExecuteButtons}\n onClose={() => setBulkButtonAction(null)}\n isLoading={bulkBusy === 'executeButton'}\n />\n\n <ConfirmDialog\n isOpen={bulkButtonAction === 'delete'}\n title=\"Delete Vibe Deck Buttons\"\n message={`Delete ${selectedButtons.length} selected button${selectedButtons.length === 1 ? '' : 's'}? This cannot be undone.`}\n confirmLabel=\"Delete Buttons\"\n variant=\"danger\"\n onConfirm={handleBulkDeleteButtons}\n onClose={() => setBulkButtonAction(null)}\n isLoading={bulkBusy === 'deleteButton'}\n />\n\n {modal.type === 'shareDeck' && (\n <VibeDeckShareDialog\n vibeDeckId={modal.deckId}\n vibeDeckName={modal.deckName}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n <QuotaExhaustedDialog\n isOpen={quotaDialog !== null}\n onClose={() => setQuotaDialog(null)}\n onConfirm={() => {\n setQuotaDialog(null);\n navigate('/billing/plans');\n }}\n title={quotaDialog?.title || 'Quota Reached'}\n message={quotaDialog?.message || 'Upgrade your plan to continue.'}\n />\n\n <EnableRemoteTaskDialog\n isOpen={remoteTaskPrompt !== null}\n agentName={\n remoteTaskPrompt\n ? agents.find((a: { id: string; name: string }) => a.id === remoteTaskPrompt.agentId)\n ?.name\n : undefined\n }\n isLoading={enablingRemoteTask}\n onClose={() => setRemoteTaskPrompt(null)}\n onConfirm={handleEnableRemoteTaskConfirm}\n />\n </MotionPage>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,SAAgB,KAAe;CAC7B,IAAM,KAAW,IAAiB,EAC5B,EAAE,mBAAgB,IAAiB,EACnC,IAAM,IAAa,EACnB,EAAE,kBAAe,WAAW,IAAoB,mBAAgB,IAAgB,EAChF,MACH,OACA,GAAa,MAA6B;EACzC,IAAM,IAAI,EAAK,EAAE,EAAI;AACrB,SAAO,MAAM,IAAM,IAAW;IAEhC,IAAS,CAAC,EAEN,KACJ,MAAM,QAAQ,EAAY,GAAG,IAAc,GAAa,oBACvD,QAAQ,MAAc,EAAE,WAAW,YAAY,CAAC,EAC7C,KAAU,IAAsB,EAAc,EAAiB,cAAc,GAAG,IAChF,KAAY,IAAsB,EAAc,EAAiB,gBAAgB,GAAG,IACpF,KAAY,IAAsB,EAAc,EAAiB,gBAAgB,GAAG,IACpF,KAAY,IAAsB,EAAc,EAAiB,gBAAgB,GAAG,IACpF,KAAa,IAAsB,EAAc,EAAiB,iBAAiB,GAAG,IACtF,KAAoB,IAEpB,EAAE,qBAAkB,wBAAqB,kBAAc,wBAC3D,IAAsB,EAClB,IAAY,OAAiB,WAC7B,KAAqB,IAAY,KAAQ,IACzC,KAAqB,IAAY,KAAQ,IACzC,KAAqB,IAAY,KAAQ,IAEzC,CAAC,GAAO,KAAY,EAAqB,EAAE,MAAM,QAAQ,CAAC,EAC1D,CAAC,IAAmB,MAAwB,EAAwB,KAAK,EACzE,CAAC,GAAiB,MAAsB,kBAAsB,IAAI,KAAK,CAAC,EACxE,CAAC,GAAmB,KAAwB,kBAAsB,IAAI,KAAK,CAAC,EAC5E,CAAC,IAAgB,MAAqB,EAA0B,KAAK,EACrE,CAAC,IAAkB,KAAuB,EAAsC,KAAK,EACrF,CAAC,GAAU,KAAe,EAE9B,KAAK,EACD,CAAC,IAAQ,MAAa,EAAuB,EAAE,CAAC,EAChD,IAAc,mBAAmD,IAAI,KAAK,CAAC,EAK3E,CAAC,IAAgB,MAAqB,EAA0B,GAAqB,EAGrF,CAAC,IAAc,MAAmB,EAA8B,EAAE,CAAC,EACnE,CAAC,IAAsB,MAA2B,EAAS,GAAK,EAChE,CAAC,IAAgB,MAAqB,kBAE1C,IAAI,KAAK,CAAC,EACN,CAAC,IAAa,MAAkB,EAAoD,KAAK,EAGzF,CAAC,GAAkB,MAAuB,EAGtC,KAAK,EACT,CAAC,IAAoB,MAAyB,EAAS,GAAM,EAC7D,EAAE,UAAU,OAAwB,GACxC,GAAkB,WAAW,KAC9B,EAIK,KAAyB,GAAoB,MAAM,MAAM,EAAE,UAAU,EAAE,QAAQ,WAC/E,IAAe,mBAAmD,IAAI,KAAK,CAAC;AAElF,UAAgB;EACd,IAAM,IAAS,EAAa;AAC5B,eAAa;AACX,QAAK,IAAM,KAAS,EAAO,QAAQ,CAAE,cAAa,EAAM;;IAEzD,EAAE,CAAC;CAEN,IAAM,KAAc,GAAa,MAAyC;EACxE,IAAM,IAAK,GAAG,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,IAC5D,IAAW;GAAE,GAAG;GAAO;GAAI;AAEjC,SADA,IAAiB,MAAS,CAAC,GAAG,EAAK,MAAM,IAAI,EAAE,EAAS,CAAC,EAClD;IACN,EAAE,CAAC,EAEA,IAAiB,GAAa,GAAY,MAAwC;AACtF,MAAiB,MACf,EAAK,KAAK,MAAW,EAAM,OAAO,IAAK;GAAE,GAAG;GAAO,GAAG;GAAS,GAAG,EAAO,CAC1E;IACA,EAAE,CAAC,EAEA,IAAkB,GACrB,GAAkB,MAAuD;AAMxE,MALA,IAAmB,MAAS;GAC1B,IAAM,IAAO,IAAI,IAAI,EAAK;AAE1B,UADA,EAAK,IAAI,GAAU,EAAO,EACnB;IACP,EACE,MAAW,aAAa,MAAW,SAAS;GAC9C,IAAM,IAAQ,iBAAiB;AAM7B,IALA,IAAmB,MAAS;KAC1B,IAAM,IAAO,IAAI,IAAI,EAAK;AAE1B,YADI,EAAK,IAAI,EAAS,KAAK,KAAQ,EAAK,OAAO,EAAS,EACjD;MACP,EACF,EAAa,QAAQ,OAAO,EAAS;MACpC,IAAK,EACF,IAAW,EAAa,QAAQ,IAAI,EAAS;AAEnD,GADI,KAAU,aAAa,EAAS,EACpC,EAAa,QAAQ,IAAI,GAAU,EAAM;;IAG7C,EAAE,CACH;AAED,UAAgB;EACd,IAAM,IAAS,EAAY;AAC3B,eAAa;AACX,QAAK,IAAM,KAAS,EAAO,QAAQ,CAAE,cAAa,EAAM;;IAEzD,EAAE,CAAC;CAEN,IAAM,IAAY,GACf,GAAiB,GAA8B,GAAwB,MAAsB;EAC5F,IAAM,IAAK,KAAK,KAAK,GAAG,KAAK,QAAQ;AACrC,MAAW,MAAS,CAAC,GAAG,GAAM;GAAE;GAAS;GAAS;GAAQ;GAAI,CAAC,CAAC;EAEhE,IAAM,KAAQ,iBAAiB;AAE7B,GADA,IAAW,MAAS,EAAK,QAAQ,MAAM,EAAE,OAAO,EAAG,CAAC,EACpD,EAAY,QAAQ,OAAO,EAAG;KAHZ,MAAa,MAAY,YAAY,MAAQ,KAIlD;AACf,IAAY,QAAQ,IAAI,GAAI,GAAM;IAEpC,EAAE,CACH,EAEK,KAAe,GAAa,MAAe;AAC/C,MAAW,MAAS,EAAK,QAAQ,MAAM,EAAE,OAAO,EAAG,CAAC;EACpD,IAAM,IAAQ,EAAY,QAAQ,IAAI,EAAG;AACzC,EAAI,MACF,aAAa,EAAM,EACnB,EAAY,QAAQ,OAAO,EAAG;IAE/B,EAAE,CAAC,EAEA,IAAkB,GAAa,GAAe,MAAoB;AAItE,EADA,IAAyB,EACzB,GAAe;GAAE;GAAO;GAAS,CAAC;IACjC,EAAE,CAAC,EAEA,EACJ,MAAM,IACN,SAAS,IACT,OAAO,IACP,SAAS,MACP,GAAsB;EACxB,WAAW,EAAE,YAAY,EAAE,OAAO,IAAI,EAAE;EACxC,MAAM;EACP,CAAC,EAEI,IAAQ,SAAc,IAAW,WAAW,SAAS,EAAE,EAAE,CAAC,GAAU,CAAC,EAErE,IACJ,KACA,EAAM,MAAM,MAA8B,EAAE,UAAU,EAAE,MACxD,EAAM,IAAI,MACV,MAEI,EACJ,MAAM,IACN,SAAS,IACT,SAAS,OACP,GAAoB;EACtB,WAAW,EAAE,IAAI,GAAwB;EACzC,MAAM,CAAC,KAAyB;EACjC,CAAC,EAEI,IAAa,IAAU,UAEvB,IAAgB,SACd,EAAM,QAAQ,MAAyB,EAAgB,IAAI,EAAK,GAAG,CAAC,EAC1E,CAAC,GAAO,EAAgB,CACzB,EAEK,IAAkB,SAEpB,GAAY,SAAS,QAAQ,MAA2B,EAAkB,IAAI,EAAO,GAAG,CAAC,IACzF,EAAE,EACJ,CAAC,GAAY,SAAS,EAAkB,CACzC,EAEK,KACJ,EAAM,SAAS,KAAK,EAAM,OAAO,MAAyB,EAAgB,IAAI,EAAK,GAAG,CAAC,EACnF,KACJ,EAAM,MAAM,MAAyB,EAAgB,IAAI,EAAK,GAAG,CAAC,IAAI,CAAC,IACnE,MACH,GAAY,SAAS,UAAU,KAAK,MACpC,GAAY,WAAW,EAAE,EAAE,OAAO,MAA2B,EAAkB,IAAI,EAAO,GAAG,CAAC,EAC3F,MACH,GAAY,WAAW,EAAE,EAAE,MAAM,MAChC,EAAkB,IAAI,EAAO,GAAG,CACjC,IAAI,CAAC,IAEF,EAAE,MAAM,OAAe,GAAmB;EAC9C,WAAW,EAAE,YAAY,EAAE,OAAO,KAAK,EAAE;EACzC,aAAa;EACb,MAAM;EACP,CAAC,EACI,MAAU,IAAY,sBAAsB,EAAE,EAAE,KACnD,OAAwD;EACvD,IAAI,EAAE;EACN,MAAM,EAAE;EACR,UAAU,EAAE;EACb,EACF,EAEK,CAAC,IAAY,EAAE,SAAS,QAAuB,EAA0B,EAC7E,gBAAgB,CAAC,gBAAgB,EAClC,CAAC,EACI,EAAE,gBAAgB,IAAoB,WAAW,OACrD,GAAmB,wBAAwB,EACvC,CAAC,IAAY,EAAE,SAAS,QAAuB,GAA0B,EAC7E,gBAAgB,CAAC,iBAAiB,cAAc,EACjD,CAAC,EACI,CAAC,KAAc,EAA0B,EAC7C,gBAAgB,CAAC,gBAAgB,EAClC,CAAC,EACI,CAAC,KAAkB,GAA8B,EACrD,gBAAgB,CAAC,iBAAiB,cAAc,EACjD,CAAC,EACI,CAAC,KAAiB,EAA6B,EACnD,gBAAgB,CAAC,gBAAgB,EAClC,CAAC,EACI,CAAC,IAAc,EAAE,SAAS,QAAyB,EAAgC,EACvF,gBAAgB,CAAC,cAAc,EAChC,CAAC,EACI,CAAC,IAAc,EAAE,SAAS,QAAyB,GAAgC,EACvF,gBAAgB,CAAC,cAAc,EAChC,CAAC,EACI,CAAC,KAAgB,EAAgC,EACrD,gBAAgB,CAAC,cAAc,EAChC,CAAC,EACI,CAAC,MAAc,GAA8B,EACjD,gBAAgB,CAAC,cAAc,EAChC,CAAC,EACI,CAAC,KAAiB,IAAkC;AAE1D,UAAgB;AACd,oBAAqB,IAAI,KAAK,CAAC;IAC9B,CAAC,EAAsB,CAAC;CAE3B,IAAM,KAAsB,GAAa,GAAgB,MAAqB;AAC5E,MAAoB,MAAS;GAC3B,IAAM,IAAO,IAAI,IAAI,EAAK;AAM1B,UALI,IACF,EAAK,IAAI,EAAO,GAEhB,EAAK,OAAO,EAAO,EAEd;IACP;IACD,EAAE,CAAC,EAEA,KAAiB,GACpB,MAAqB;AACpB,MAAoB,MAAS;GAC3B,IAAM,IAAO,IAAI,IAAI,EAAK;AAQ1B,UAPA,EAAM,SAAS,MAAyB;AACtC,IAAI,IACF,EAAK,IAAI,EAAK,GAAG,GAEjB,EAAK,OAAO,EAAK,GAAG;KAEtB,EACK;IACP;IAEJ,CAAC,EAAM,CACR,EAEK,IAAqB,QAAkB;AAC3C,qBAAmB,IAAI,KAAK,CAAC;IAC5B,EAAE,CAAC;AAEwB,IAAa,GAAkB,MAAqB;AAChF,KAAsB,MAAS;GAC7B,IAAM,IAAO,IAAI,IAAI,EAAK;AAM1B,UALI,IACF,EAAK,IAAI,EAAS,GAElB,EAAK,OAAO,EAAS,EAEhB;IACP;IACD,EAAE,CAAC;CAEN,IAAM,KAAmB,GACtB,MAAqB;AACpB,KAAsB,MAAS;GAC7B,IAAM,IAAO,IAAI,IAAI,EAAK;AAQ1B,WAPC,GAAY,WAAW,EAAE,EAAE,SAAS,MAA2B;AAC9D,IAAI,IACF,EAAK,IAAI,EAAO,GAAG,GAEnB,EAAK,OAAO,EAAO,GAAG;KAExB,EACK;IACP;IAEJ,CAAC,GAAY,QAAQ,CACtB,EAEK,IAAuB,QAAkB;AAC7C,oBAAqB,IAAI,KAAK,CAAC;IAC9B,EAAE,CAAC,EAEA,KAAmB,EACvB,OAAO,MAMD;AACJ,MAAI;GAgBF,IAAM,KAZM,MAAM,GAAW,EAC3B,WAAW,EACT,OAAO;IACL,MAAM,EAAK;IACX,aAAa,EAAK,eAAe;IACjC,YAAY,EAAK,cAAc;IAC/B,aAAa,EAAK;IAClB,UAAU,EAAK;IACf,GAAG,GAAgB,GAAe;IACnC,EACF,EACF,CAAC,EACoB,MAAM,gBAAgB;AAI5C,GAHA,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,EAAU,gBAAgB,UAAU,EACpC,GAAkB,GAAqB,EACnC,KAAW,MAAM,GAAc,EAAU;WACtC,GAAK;AACZ,OAAI,EAAsB,EAAI,EAAE;AAE9B,IADA,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,EACE,2BACA,4FACD;AACD;;AAGF,KAAU,aAAe,QAAQ,EAAI,UAAU,yBAAyB,QAAQ;;IAGpF;EAAC;EAAY;EAAe;EAAiB;EAAW;EAAe,CACxE,EAEK,KAAmB,EACvB,OAAO,MAMD;AACA,QAAM,SAAS,WACnB,KAAI;AAcF,GAbA,MAAM,GAAW,EACf,WAAW;IACT,IAAI,EAAM;IACV,OAAO;KACL,MAAM,EAAK;KACX,aAAa,EAAK,eAAe;KACjC,YAAY,EAAK,cAAc;KAC/B,aAAa,EAAK;KAClB,UAAU,EAAK;KAChB;IACF,EACF,CAAC,EACF,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,EAAU,gBAAgB,UAAU;WAC7B,GAAK;AACZ,KAAU,aAAe,QAAQ,EAAI,UAAU,yBAAyB,QAAQ;;IAGpF;EAAC;EAAY;EAAO;EAAU,CAC/B,EAEK,KAAsB,EAAY,YAAY;AAC9C,QAAM,SAAS,gBACnB,KAAI;AAYF,GAXI,EAAM,WAAW,UACnB,MAAM,EAAW,EAAE,WAAW,EAAE,IAAI,EAAM,IAAI,EAAE,CAAC,EAC7C,MAAqB,EAAM,MAC7B,EAAoB,KAAK,EAE3B,EAAU,gBAAgB,UAAU,KAEpC,MAAM,EAAa,EAAE,WAAW,EAAE,IAAI,EAAM,IAAI,EAAE,CAAC,EACnD,EAAU,kBAAkB,UAAU,GAExC,EAAS,EAAE,MAAM,QAAQ,CAAC,EACtB,IAAU,IAAO,GAAa,UAAU;WACrC,GAAK;AAEZ,GADA,EAAU,aAAe,QAAQ,EAAI,UAAU,oBAAoB,QAAQ,EACvE,IAAU,IAAO,GAAa,QAAQ;;IAE3C;EAAC;EAAO;EAAY;EAAc;EAAkB;EAAqB;EAAU,CAAC,EAEjF,IAAkB,EACtB,OAAO,GAAkB,IAAoB,OAAS;EACpD,IAAM,IAAS,GAAY,SAAS,MAAM,MAAsB,EAAE,OAAO,EAAS;AAClF,MAAI,CAAC,KAAU,CAAC,EAAO,OAAQ;EAE/B,IAAM,IAAS,EAAO,QAGhB,IAAQ,GAAY;GACxB;GACA,aAAa,EAAO;GACpB,YAAY,EAAO;GACnB,SACE,EAAO,eAAe,YAClB,QAAQ,EAAO,cAAc,OAC7B,EAAO,WAAW,KAAA;GACxB,QAAQ;GACR,2BAAW,IAAI,MAAM;GACtB,CAAC;AAGF,EADA,GAAqB,EAAS,EAC9B,EAAgB,GAAU,YAAY;AAEtC,MAAI;GAEF,IAAM,KADS,MAAM,EAAc,EAAE,WAAW,EAAE,IAAI,GAAU,EAAE,CAAC,EAC/C,MAAM;AAG1B,OAAI,KAAQ,GAAwB,EAAK,IAAI,EAAK,SAAS;AAYzD,IAXA,EAAgB,GAAU,QAAQ,EAClC,EAAe,GAAO;KACpB,QAAQ;KACR,OAAO,IACH,qDACA;KACJ,QAAQ,EAAK;KACb,6BAAa,IAAI,MAAM;KACxB,CAAC,EAGE,KACF,GAAoB;KAAE;KAAU,SAAS,EAAK;KAAS,CAAC;AAE1D;;AAEF,OAAI,GAAM;IACR,IAAM,IAAY,EAAK,WAAW;AASlC,IARA,EAAgB,GAAU,IAAY,YAAY,QAAQ,EAC1D,EAAe,GAAO;KACpB,QAAQ,IAAY,YAAY;KAChC,QAAQ,EAAK;KACb,UAAU,EAAK;KACf,mBAAmB,EAAK;KACxB,6BAAa,IAAI,MAAM;KACxB,CAAC,EACE,KACF,EAAI,WAAW,yCAAyC;KACtD,aAAa,KAAe,KAAA;KAC5B;KACA,QAAQ,KAAyB,KAAA;KAClC,CAAC;;WAGC,GAAK;AACZ,OAAI,EAAsB,EAAI,EAAE;AAO9B,IANA,EAAgB,GAAU,QAAQ,EAClC,EAAe,GAAO;KACpB,QAAQ;KACR,OAAO;KACP,6BAAa,IAAI,MAAM;KACxB,CAAC,EACF,EACE,2BACA,0GACD;AACD;;GAGF,IAAM,IAAW,aAAe,QAAQ,EAAI,UAAU;AAEtD,GADA,EAAgB,GAAU,QAAQ,EAClC,EAAe,GAAO;IACpB,QAAQ;IACR,OAAO;IACP,6BAAa,IAAI,MAAM;IACxB,CAAC;YACM;AACR,MAAqB,KAAK;;IAG9B;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF,EAEK,KAAgC,EACpC,OAAO,EAAE,UAAO,cAA8C;AAC5D,MAAI,CAAC,EAAkB;EACvB,IAAM,EAAE,aAAU,eAAY;AAC9B,KAAsB,GAAK;AAC3B,MAAI;AAQF,GAPA,MAAM,GACJ;IAAE,IAAI;IAAS,SAAS;IAAwB,EAChD;IAAE;IAAO;IAAM,CAChB,EACD,GAAoB,KAAK,EAGzB,MAAM,EAAgB,GAAU,GAAM;WAC/B,GAAK;AACZ,KACE,aAAe,QAAQ,EAAI,UAAU,qCACrC,QACD;YACO;AACR,MAAsB,GAAM;;IAGhC;EAAC;EAAkB;EAAwB;EAAiB;EAAU,CACvE,EAEK,KAAsB,EAC1B,OAAO,MAAqB;EAC1B,IAAM,IAAS,GAAY,SAAS,MAAM,MAAsB,EAAE,OAAO,EAAS;AAC7E,SAQL;OANA,EAAI,WAAW,iDAAiD;IAC9D,aAAa,KAAe,KAAA;IAC5B;IACA,QAAQ,KAAyB,KAAA;IAClC,CAAC,EAEE,EAAO,sBAAsB;IAC/B,IAAM,IAAS,EAAO,QAChB,IACJ,GAAQ,eAAe,YACnB,QAAQ,EAAO,cAAc,OAC7B,GAAQ,WAAW;AACzB,MAAS;KAAE,MAAM;KAAkB;KAAU,OAAO,EAAO;KAAO;KAAQ,CAAC;AAC3E;;AAGF,SAAM,EAAgB,EAAS;;IAEjC;EAAC;EAAY;EAAiB;EAAK;EAAa;EAAsB,CACvE,EAEK,KAAuB,EAAY,YAAY;AACnD,MAAI,EAAM,SAAS,iBAAkB;EACrC,IAAM,IAAW,EAAM;AAEvB,EADA,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,MAAM,EAAgB,EAAS;IAC9B,CAAC,GAAO,EAAgB,CAAC,EAEtB,KAAqB,EACzB,OAAO,MASD;AACA,UAAM,SAAS,kBAAkB,CAAC,GAEtC,KAAI;AAmBF,GAlBA,MAAM,GAAa,EACjB,WAAW,EACT,OAAO;IACL,YAAY;IACZ,OAAO,EAAK;IACZ,UAAU,EAAK;IACf,KAAK,EAAM;IACX,QAAQ,EAAM;IACd,SAAS,EAAK;IACd,SAAS,EAAK;IACd,OAAO,EAAK,SAAS;IACrB,UAAU,EAAK,YAAY;IAC3B,kBAAkB,EAAK,oBAAoB;IAC3C,sBAAsB,EAAK;IAC5B,EACF,EACF,CAAC,EACF,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,EAAU,kBAAkB,UAAU;WAC/B,GAAK;AACZ,KAAU,aAAe,QAAQ,EAAI,UAAU,2BAA2B,QAAQ;;IAGtF;EAAC;EAAO;EAAc;EAAuB;EAAU,CACxD,EAEK,KAAqB,EACzB,OAAO,MASD;AACA,QAAM,SAAS,aAEnB,KAAI;AAiBF,GAhBA,MAAM,GAAa,EACjB,WAAW;IACT,IAAI,EAAM;IACV,OAAO;KACL,OAAO,EAAK;KACZ,UAAU,EAAK;KACf,OAAO,EAAK,SAAS;KACrB,UAAU,EAAK,YAAY;KAC3B,kBAAkB,EAAK,oBAAoB;KAC3C,sBAAsB,EAAK;KAC3B,SAAS,EAAK;KACd,SAAS,EAAK;KACf;IACF,EACF,CAAC,EACF,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,EAAU,kBAAkB,UAAU;WAC/B,GAAK;AACZ,KAAU,aAAe,QAAQ,EAAI,UAAU,2BAA2B,QAAQ;;IAGtF;EAAC;EAAO;EAAc;EAAU,CACjC,EAEK,KAAmB,EACvB,OAAO,GAAkB,GAAmB,MAAyB;AACnE,MAAI;AACF,SAAM,GAAW,EACf,WAAW;IACT,IAAI;IACJ,OAAO;KAAE,KAAK;KAAW,QAAQ;KAAc;IAChD,EACF,CAAC;WACK,GAAK;AACZ,KAAU,aAAe,QAAQ,EAAI,UAAU,yBAAyB,QAAQ;;IAGpF,CAAC,IAAY,EAAU,CACxB,EAEK,KAAsB,EAC1B,OAAO,MAAmB;EACxB,IAAM,IAAO,EAAM,MAAM,MAAoC,EAAE,OAAO,EAAO;AACxE,QACL,KAAI;AAGF,GADA,MAAM,EAAc,EAAE,WAAW;IAAE,IAAI;IAAQ,MAD/B,GAAG,EAAK,KAAK;IACiC,EAAE,CAAC,EACjE,EAAU,mBAAmB,UAAU;WAChC,GAAK;AACZ,OAAI,EAAsB,EAAI,EAAE;AAC9B,MACE,2BACA,+FACD;AACD;;AAGF,KAAU,aAAe,QAAQ,EAAI,UAAU,4BAA4B,QAAQ;;IAGvF;EAAC;EAAO;EAAe;EAAiB;EAAU,CACnD,EAEK,KAAmB,EACvB,OAAO,MAAe;AACpB,MAAI;AAEF,GADA,MAAM,EAAe,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC,EAC3C,EAAU,oBAAoB,UAAU;WACjC,GAAK;AACZ,KAAU,aAAe,QAAQ,EAAI,UAAU,yBAAyB,QAAQ;;IAGpF,CAAC,GAAgB,EAAU,CAC5B,EAEK,KAA2B,EAAY,YAAY;AACnD,QAAc,WAAW,GAC7B;KAAY,iBAAiB;AAC7B,OAAI;AAIF,IAHA,MAAM,EAAe,EAAE,WAAW,EAAE,IAAI,EAAc,GAAG,IAAI,EAAE,CAAC,EAChE,EAAU,oBAAoB,UAAU,EACxC,GAAoB,EACpB,MAAM,GAAc;YACb,GAAK;AACZ,MAAU,aAAe,QAAQ,EAAI,UAAU,8BAA8B,QAAQ;aAC7E;AACR,MAAY,KAAK;;;IAElB;EAAC;EAAe;EAAgB;EAAW;EAAoB;EAAa,CAAC,EAE1E,KAA2B,EAAY,YAAY;AACnD,QAAc,WAAW,GAC7B;KAAY,gBAAgB;AAC5B,OAAI;IACF,IAAM,IAAU,MAAM,QAAQ,WAC5B,EAAc,KAAK,MACjB,EAAc,EAAE,WAAW;KAAE,IAAI,EAAK;KAAI,MAAM,GAAG,EAAK,KAAK;KAAU,EAAE,CAAC,CAC3E,CACF;AAOD,QALsB,EAAQ,MAC3B,MACC,EAAO,WAAW,cAAc,EAAsB,EAAO,OAAO,CACvE,EAEkB;AACjB,OACE,2BACA,+FACD;AACD;;IAGF,IAAM,IAAY,EAAQ,QACvB,MAA0C,EAAO,WAAW,YAC9D,CAAC,QACI,IAAS,EAAQ,SAAS;AAMhC,IALA,EACE,cAAc,EAAU,OAAO,MAAc,IAAI,KAAK,MAAM,IAAS,IAAI,MAAM,EAAO,WAAW,MACjG,IAAS,IAAI,UAAU,UACxB,EACD,GAAoB,EACpB,MAAM,GAAc;YACb,GAAK;AACZ,QAAI,EAAsB,EAAI,EAAE;AAC9B,OACE,2BACA,+FACD;AACD;;AAGF,MAAU,aAAe,QAAQ,EAAI,UAAU,6BAA6B,QAAQ;aAC5E;AACR,MAAY,KAAK;;;IAElB;EAAC;EAAe;EAAe;EAAiB;EAAW;EAAoB;EAAa,CAAC,EAE1F,KAAwB,EAAY,YAAY;AAChD,QAAc,WAAW,GAC7B;KAAY,aAAa;AACzB,OAAI;IACF,IAAM,IAAU,MAAM,QAAQ,WAC5B,EAAc,KAAK,MAAyB,EAAW,EAAE,WAAW,EAAE,IAAI,EAAK,IAAI,EAAE,CAAC,CAAC,CACxF,EACK,IAAY,EAAQ,QACvB,MAA0C,EAAO,WAAW,YAC9D,CAAC,QACI,IAAS,EAAQ,SAAS;AAUhC,IATI,EAAc,MAAM,MAAyB,EAAK,OAAO,EAAiB,IAC5E,EAAoB,KAAK,EAE3B,EACE,WAAW,EAAU,OAAO,MAAc,IAAI,KAAK,MAAM,IAAS,IAAI,MAAM,EAAO,WAAW,MAC9F,IAAS,IAAI,UAAU,UACxB,EACD,GAAoB,EACpB,GAAkB,KAAK,EACvB,MAAM,GAAc;YACb,GAAK;AACZ,MAAU,aAAe,QAAQ,EAAI,UAAU,0BAA0B,QAAQ;aACzE;AACR,MAAY,KAAK;;;IAElB;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,EAEI,KAA2B,EAAY,YAAY;AACvD,MAAI,EAAgB,WAAW,EAAG;AAClC,IAAY,gBAAgB;EAC5B,IAAI,IAAY,GACZ,IAAS;AACb,MAAI;AACF,QAAK,IAAM,KAAU,EACnB,KAAI;AAGF,KAFe,MAAM,EAAc,EAAE,WAAW,EAAE,IAAI,EAAO,IAAI,EAAE,CAAC,EAChD,MAAM,uBAChB,WAAW,YACnB,KAAa,IAEb,KAAU;YAEL,GAAK;AACZ,QAAI,EAAsB,EAAI,EAAE;AAE9B,KADA,EAAoB,KAAK,EACzB,EACE,2BACA,0GACD;AACD;;AAGF,SAAU;;AAQd,GALA,EACE,YAAY,EAAU,SAAS,MAAc,IAAI,KAAK,MAAM,IAAS,IAAI,MAAM,EAAO,WAAW,MACjG,IAAS,IAAI,UAAU,UACxB,EACD,GAAsB,EACtB,EAAoB,KAAK;WAClB,GAAK;AACZ,KAAU,aAAe,QAAQ,EAAI,UAAU,6BAA6B,QAAQ;YAC5E;AACR,KAAY,KAAK;;IAElB;EAAC;EAAiB;EAAe;EAAiB;EAAW;EAAqB,CAAC,EAEhF,KAA0B,EAAY,YAAY;AAClD,QAAgB,WAAW,GAC/B;KAAY,eAAe;AAC3B,OAAI;IACF,IAAM,IAAU,MAAM,QAAQ,WAC5B,EAAgB,KAAK,MACnB,EAAa,EAAE,WAAW,EAAE,IAAI,EAAO,IAAI,EAAE,CAAC,CAC/C,CACF,EACK,IAAY,EAAQ,QACvB,MAA0C,EAAO,WAAW,YAC9D,CAAC,QACI,IAAS,EAAQ,SAAS;AAOhC,IANA,EACE,WAAW,EAAU,SAAS,MAAc,IAAI,KAAK,MAAM,IAAS,IAAI,MAAM,EAAO,WAAW,MAChG,IAAS,IAAI,UAAU,UACxB,EACD,GAAsB,EACtB,EAAoB,KAAK,EACzB,MAAM,IAAa;YACZ,GAAK;AACZ,MAAU,aAAe,QAAQ,EAAI,UAAU,4BAA4B,QAAQ;aAC3E;AACR,MAAY,KAAK;;;IAElB;EAAC;EAAiB;EAAc;EAAW;EAAsB;EAAY,CAAC;AAEjF,KAAI,GACF,QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAc,SAAQ,0BAA2B,CAAA,EACtC,CAAA;AAIjB,KAAI,MAAgB,EAAY,mBAAmB,UAAU,KAAK,KAAK,CAAC,GACtE,QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD,EAAgB,CAAA,EACL,CAAA;AAIjB,KAAI,GACF,QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAc,SAAQ,yBAA0B,CAAA,EACrC,CAAA;AAIjB,KAAI,GACF,QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD;EAAY,SAAS,GAAW;EAAS,eAAe,GAAc;EAAI,CAAA,EAC/D,CAAA;CAIjB,IAAM,IACJ,EAAM,SAAS,eACX,GAAY,SAAS,MAAM,MAAsB,EAAE,OAAO,EAAM,SAAS,GACzE,MACA,IACJ,EAAM,SAAS,aAAa,EAAM,MAAM,MAAsB,EAAE,OAAO,EAAM,OAAO,GAAG;AAEzF,QACE,kBAAC,GAAD;EAAY,WAAU;YAAtB;GACE,kBAAC,IAAD;IACE,OAAO,EAAG,gBAAgB,YAAY;IACtC,aAAY;IACZ,SACE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OACE,aAAU;OACV,WAAU;iBAFZ,CAIE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,GAAgB,UAAU;QACzC,WAAW,uFACT,IACI,4DACA;QAEN,OAAO,IAAY,gCAAgC;QACnD,gBAAc;kBAThB,CAWE,kBAAC,IAAD,EAAK,MAAM,IAAM,CAAA,EAAA,UAEV;WACT,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,GAAgB,OAAO;QACtC,WAAW,uFACR,IAEG,+CADA;QAGN,OAAQ,IAAyC,wBAA7B;QACpB,gBAAc,CAAC;kBATjB,CAWE,kBAAC,IAAD,EAAQ,MAAM,IAAM,CAAA,EAAA,OAEb;UACL;;MACL,KAAyB,KAAc,MAOtC,kBAAC,UAAD;OACE,MAAK;OACL,eACE,EAAS;QACP,MAAM;QACN,QAAQ;QACR,UAAU,EAAW;QACtB,CAAC;OAEJ,WAAU;OACV,OAAM;iBAEN,kBAAC,IAAD,EAAQ,MAAM,IAAM,CAAA;OACb,CAAA;MAEX,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AAEb,QADA,GAAc,EACV,KAAuB,IAAa;;OAE1C,WAAU;OACV,OAAM;iBAEN,kBAAC,IAAD,EAAW,MAAM,IAAM,CAAA;OAChB,CAAA;MACL;;IAER,CAAA;GAED,CAAC,KAAa,EAAM,SAAS,KAC5B,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,IAAD;QACE,SAAS;QACT,eAAe;QACf,UAAU;QACV,WAAU;QACV,CAAA,EACF,kBAAC,QAAD;QAAM,WAAU;kBAAwC;QAAuB,CAAA,CAC3E;UACL,EAAgB,OAAO,KACtB,kBAAC,UAAD;OACE,MAAK;OACL,SAAS;OACT,WAAU;iBACX;OAEQ,CAAA,CAEP;SAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACG,EAAgB,MAAK,YACjB;;OACP,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,UACE,EAAc,WAAW,KAAK,EAAc,IAAI,aAAa,MAAa;QAE5E,WAAU;kBAEV,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,IAAD,EAAM,MAAM,IAAM,CAAA,EAAA,uBAEb;;QACA,CAAA;OACT,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,UAAU,EAAc,WAAW,KAAK,MAAa;QACrD,WAAU;kBAEV,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,IAAD,EAAM,MAAM,IAAM,CAAA;;UACC,EAAc,SAAS,IAAI,KAAK,EAAc,OAAO,KAAK;UACxE;;QACA,CAAA;OACT,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,GAAkB,SAAS;QAC1C,UAAU,EAAc,WAAW,KAAK,MAAa;QACrD,WAAU;kBAEV,kBAAC,QAAD;SAAM,WAAU;mBAAhB;UACE,kBAAC,IAAD,EAAQ,MAAM,IAAM,CAAA;;UACJ,EAAc,SAAS,IAAI,KAAK,EAAc,OAAO,KAAK;UACrE;;QACA,CAAA;OACL;QACF;;IACF,CAAA;GAGR,kBAAC,OAAD;IAAK,aAAU;cACb,kBAAC,IAAD;KACE,OAAO,EAAM,KAAK,OAAY;MAC5B,IAAI,EAAE;MACN,MAAM,EAAE;MACR,MAAM,EAAE,QAAQ;MAChB,YAAY,EAAE,cAAc;MAC5B,WAAW,EAAE;MACd,EAAE;KACH,cAAc;KACG;KACjB,eAAe,MAAO,EAAoB,EAAG;KAC7C,oBAAoB;KACpB,oBAAoB,EAAS,EAAE,MAAM,cAAc,CAAC;KACpD,cAAc;KACd,cAAc,MAAO,GAAoB,EAAG;KAC5C,WAAW,MAAO;AAEhB,QAAS;OACP,MAAM;OACN,QAAQ;OACR;OACA,MALW,EAAM,MAAM,MAAsB,EAAE,OAAO,EAAG,EAK7C,QAAQ;OACrB,CAAC;;KAEJ,SAAS,MAAO,EAAS;MAAE,MAAM;MAAY,QAAQ;MAAI,CAAC;KAC1D,UAAU,MAAO;MACf,IAAM,IAAO,EAAM,MAAM,MAAoC,EAAE,OAAO,EAAG;AACzE,MAAI,KAAM,EAAS;OAAE,MAAM;OAAa,QAAQ;OAAI,UAAU,EAAK;OAAM,CAAC;;KAIjE;KACX,WAAW;KACX,WAAW;KACX,CAAA;IACE,CAAA;GAEN,kBAAC,IAAD;IAAiB,MAAK;cAAtB,CACG,CAAC,KAAc,CAAC,MAAe,EAAM,WAAW,KAC/C,kBAAC,IAAD;KACE,OAAM;KACN,aAAY;KACZ,QACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,MACC,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,EAAS,EAAE,MAAM,cAAc,CAAC;OAC/C,WAAU;iBACX;OAEQ,CAAA,EAEX,kBAAC,IAAD,EAAe,QAAO,gEAAiE,CAAA,CACnF;;KAER,CAAA,EAGH,MAAe,kBAAC,GAAD,EAAc,SAAQ,mBAAoB,CAAA,CAC1C;;GAEjB,KACC,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,CAAC,MAAc,EAAW,SAAS,UAAU,KAAK,KACjD,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,IAAD;SACE,SAAS;SACT,eAAe;SACf,UAAU;SACV,WAAU;SACV,CAAA,EACF,kBAAC,QAAD;SAAM,WAAU;mBAAwC;SAEjD,CAAA,CACH;WACL,EAAkB,OAAO,KACxB,kBAAC,UAAD;QACE,MAAK;QACL,SAAS;QACT,WAAU;kBACX;QAEQ,CAAA,CAEP;UAEN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACG,EAAkB,MAAK,YACnB;;QACP,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAoB,UAAU;SAC7C,UAAU,EAAgB,WAAW,KAAK,MAAa;SACvD,WAAU;mBAEV,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WACE,kBAAC,IAAD,EAAM,MAAM,IAAM,CAAA;;WAEjB,EAAgB,SAAS,IAAI,KAAK,EAAgB,OAAO,KAAK;WAC1D;;SACA,CAAA;QACT,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAoB,SAAS;SAC5C,UAAU,EAAgB,WAAW,KAAK,MAAa;SACvD,WAAU;mBAEV,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WACE,kBAAC,IAAD,EAAQ,MAAM,IAAM,CAAA;;WAEnB,EAAgB,SAAS,IAAI,KAAK,EAAgB,OAAO,KAAK;WAC1D;;SACA,CAAA;QACL;SACF;;KACF,CAAA,EAGR,kBAAC,OAAD;KAAK,aAAU;KAAgB,WAAU;eAAzC,CACE,kBAAC,IAAD;MACE,aAAa,EAAW;MACxB,UAAU,EAAW;MACrB,UAAU,EAAW,WAAW,EAAE,EAAE,KAAK,OAAY;OACnD,IAAI,EAAE;OACN,OAAO,EAAE;OACT,MAAM,EAAE,QAAQ;OAChB,OAAO,EAAE,SAAS;OAClB,UAAU,EAAE,YAAY;OACxB,sBAAsB,EAAE;OACxB,kBAAkB,EAAE,oBAAoB;OACxC,UAAU,EAAE,YAAY;OACxB,QAAQ,EAAE,SACN;QACE,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,OAAO;QACf,aAAa,EAAE,OAAO,eAAe;QACrC,YAAY,EAAE,OAAO;QACrB,SAAS,EAAE,OAAO,WAAW;QAC7B,QAAQ,EAAE,OAAO,UAAU;QAC3B,YAAY,EAAE,OAAO,cAAc;QACnC,eAAe,EAAE,OAAO,iBAAiB;QAC1C,GACD;OACJ,KAAK,EAAE;OACP,QAAQ,EAAE;OACV,SAAS,EAAE;OACX,SAAS,EAAE;OACZ,EAAE;MACH,iBAAiB;MACjB,eAAe,MAAO,EAAS;OAAE,MAAM;OAAc,UAAU;OAAI,CAAC;MACpE,iBAAiB,MAAO;OACtB,IAAM,IAAM,EAAW,SAAS,MAAM,MAAsB,EAAE,OAAO,EAAG;AACxE,SAAS;QACP,MAAM;QACN,QAAQ;QACR;QACA,MAAM,GAAK,SAAS;QACrB,CAAC;;MAEJ,cAAc;MACd,cAAc,GAAK,MAAW,EAAS;OAAE,MAAM;OAAgB;OAAK;OAAQ,CAAC;MAC1D;MACnB,WAAW;MACX,WAAW;MACX,WAAW;MACC;MACZ,aAAa;MACb,CAAA,GAKA,EAAW,SAAS,UAAU,OAAO,KAAK,KAC1C,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,2BAA2B,qBAAqB;SACjD,CAAA;QACL,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAG,iCAAiC,sCAAsC;SACzE,CAAA;QACH,MACC,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,GAAgB,OAAO;SACtC,WAAU;mBAET,EAAG,qBAAqB,YAAY;SAC9B,CAAA;QAEP;;MACF,CAAA,CAEJ;OACF;;GAGP,GAAa,SAAS,KACrB,kBAAC,OAAD;IAAK,aAAU;cACb,kBAAC,IAAD;KACE,SAAS;KACT,UAAU;KACV,wBAAwB,IAAyB,MAAS,CAAC,EAAK;KAChE,eAAe,GAAgB,EAAE,CAAC;KAClC,CAAA;IACE,CAAA;GAGR,kBAAC,IAAD,EAAA,UACG,GAAO,SAAS,KACf,kBAAC,OAAD;IAAK,WAAU;cACZ,GAAO,MAAM,GAAG,CAAC,KAAK,MACrB,kBAAC,OAAD;KACE,MAAK;KACL,UAAU;KACV,YAAY,MAAM;AAChB,OAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EACX,GAAa,EAAM,GAAG;;KAIjC,WAAW,kDACT,EAAM,YAAY,YACd,qFACA;KAEN,eAAe,GAAa,EAAM,GAAG;eAfvC,CAiBE,kBAAC,OAAD;MAAK,WAAU;gBAAuB,EAAM;MAAc,CAAA,EACzD,EAAM,UACL,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAM;MACH,CAAA,CAEJ;OAdC,EAAM,GAcP,CACN;IACE,CAAA,EAEQ,CAAA;GAEjB,EAAM,SAAS,gBACd,kBAAC,IAAD;IACE,OAAM;IACN,UAAU;IACV,gBAAgB;AAEd,KADA,EAAS,EAAE,MAAM,QAAQ,CAAC,EAC1B,GAAkB,GAAqB;;IAEzC,WAAW;IACX,cACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,iBAAiB,OAAO;MACzB,CAAA,EACL,kBAAC,IAAD;MACE,YAAW;MACX,eAAe;MACf,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,IAAD;MAAiB,OAAO;MAAgB,UAAU;MAAqB,CAAA,CACnE;;IAER,CAAA;GAGH,EAAM,SAAS,cAAc,KAC5B,kBAAC,IAAD;IACE,OAAM;IACN,aAAa;KACX,MAAM,EAAY;KAClB,aAAa,EAAY,eAAe;KACxC,YAAY,EAAY,cAAc;KACtC,aAAa,EAAY;KACzB,UAAU,EAAY;KACvB;IACD,UAAU;IACV,gBAAgB,EAAS,EAAE,MAAM,QAAQ,CAAC;IAC1C,WAAW;IACX,cACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,iBAAiB,OAAO;KACzB,CAAA,EACL,kBAAC,IAAD;KAAiB,YAAW;KAAwB,UAAU,EAAY;KAAM,CAAA,CAC5E,EAAA,CAAA;IAER,CAAA;GAGH,EAAM,SAAS,kBACd,kBAAC,IAAD;IACE,OAAM;IACE;IACR,UAAU;IACV,gBAAgB,EAAS,EAAE,MAAM,QAAQ,CAAC;IAC1C,WAAW;IACX,aAAa,GAAY;IACzB,UAAU,GAAY;IACtB,WAAW,EAAM;IACjB,cAAc,EAAM;IACpB,CAAA;GAGH,EAAM,SAAS,gBAAgB,KAC9B,kBAAC,IAAD;IACE,OAAM;IACN,aACE;KACE,OAAO,EAAc;KACrB,UAAW,EAAsB,YAAY;KAC7C,OAAO,EAAc,SAAS;KAC9B,UAAU,EAAc,YAAY;KACpC,kBAAkB,EAAc,oBAAoB;KACpD,sBAAsB,EAAc;KACpC,SAAS,EAAc;KACvB,SAAS,EAAc;KACxB;IAEK;IACR,UAAU;IACV,gBAAgB,EAAS,EAAE,MAAM,QAAQ,CAAC;IAC1C,WAAW;IACX,aAAa,GAAY;IACzB,UAAU,GAAY;IACtB,WAAW,EAAc;IACzB,cAAc,EAAc;IAC5B,CAAA;GAGH,EAAM,SAAS,mBACd,kBAAC,GAAD;IACE,QAAQ;IACR,OAAO,UAAU,EAAM,WAAW,SAAS,cAAc;IACzD,SAAS,oCAAoC,EAAM,KAAK,IAAI,EAAM,WAAW,SAAS,oDAAoD;IAC1I,cAAa;IACb,SAAQ;IACR,WAAW;IACX,eAAe,EAAS,EAAE,MAAM,QAAQ,CAAC;IACzC,CAAA;GAGH,EAAM,SAAS,oBACd,kBAAC,GAAD;IACE,QAAQ;IACR,OAAO,YAAY,EAAM;IACzB,SAAS,oDAAoD,EAAM;IACnE,cAAa;IACb,SAAQ;IACR,WAAW;IACX,eAAe,EAAS,EAAE,MAAM,QAAQ,CAAC;IACzC,CAAA;GAGJ,kBAAC,GAAD;IACE,QAAQ,OAAmB;IAC3B,OAAM;IACN,SAAS,mCAAmC,EAAc,OAAO,gBAAgB,EAAc,WAAW,IAAI,KAAK,IAAI;IACvH,cAAa;IACb,SAAQ;IACR,WAAW;IACX,eAAe,GAAkB,KAAK;IACtC,WAAW,MAAa;IACxB,CAAA;GAEF,kBAAC,GAAD;IACE,QAAQ,OAAqB;IAC7B,OAAM;IACN,SAAS,WAAW,EAAgB,OAAO,kBAAkB,EAAgB,WAAW,IAAI,KAAK,IAAI;IACrG,cAAa;IACb,SAAQ;IACR,WAAW;IACX,eAAe,EAAoB,KAAK;IACxC,WAAW,MAAa;IACxB,CAAA;GAEF,kBAAC,GAAD;IACE,QAAQ,OAAqB;IAC7B,OAAM;IACN,SAAS,UAAU,EAAgB,OAAO,kBAAkB,EAAgB,WAAW,IAAI,KAAK,IAAI;IACpG,cAAa;IACb,SAAQ;IACR,WAAW;IACX,eAAe,EAAoB,KAAK;IACxC,WAAW,MAAa;IACxB,CAAA;GAED,EAAM,SAAS,eACd,kBAAC,IAAD;IACE,YAAY,EAAM;IAClB,cAAc,EAAM;IACpB,eAAe,EAAS,EAAE,MAAM,QAAQ,CAAC;IACzC,CAAA;GAGJ,kBAAC,IAAD;IACE,QAAQ,OAAgB;IACxB,eAAe,GAAe,KAAK;IACnC,iBAAiB;AAEf,KADA,GAAe,KAAK,EACpB,GAAS,iBAAiB;;IAE5B,OAAO,IAAa,SAAS;IAC7B,SAAS,IAAa,WAAW;IACjC,CAAA;GAEF,kBAAC,IAAD;IACE,QAAQ,MAAqB;IAC7B,WACE,IACI,GAAO,MAAM,MAAoC,EAAE,OAAO,EAAiB,QAAQ,EAC/E,OACJ,KAAA;IAEN,WAAW;IACX,eAAe,GAAoB,KAAK;IACxC,WAAW;IACX,CAAA;GACS"}
|
|
1
|
+
{"version":3,"file":"VibeDeckPage.js","names":[],"sources":["../../src/pages/VibeDeckPage.tsx"],"sourcesContent":["import { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport { Copy, Eye, Pencil, Play, RefreshCw, Star, Trash2 } from 'lucide-react';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { useDraftEntityTags } from '@/hooks/useDraftEntityTags';\nimport { isNative, nativeNotify } from '../utils/nativeBridge';\nimport { AnimatePresence } from 'framer-motion';\nimport {\n PageHeader,\n EmptyState,\n LoadingState,\n ErrorState,\n ConfirmDialog,\n QuotaExhaustedDialog,\n EnableRemoteTaskDialog,\n SelectionCheckbox,\n GetHelpButton,\n LinkToVibePanel,\n LINK_TO_VIBE_DEFAULT,\n linkToVibeInput,\n type LinkToVibeValue,\n} from '@/components/shared';\nimport {\n VibeDeckGrid,\n VibeDeckSwitcher,\n VibeDeckForm,\n VibeDeckButtonForm,\n VibeDeckShareDialog,\n VibeDeckExecutionLog,\n} from '@/components/vibedeck';\nimport type { ExecutionLogEntry } from '@/components/vibedeck';\nimport { EntityShareButton } from '@/components/sharing';\nimport {\n useListVibeDecksQuery,\n useGetVibeDeckQuery,\n useListAgentsQuery,\n useCreateVibeDeckMutation,\n useUpdateVibeDeckMutation,\n useDeleteVibeDeckMutation,\n useSetDefaultVibeDeckMutation,\n useDuplicateVibeDeckMutation,\n useCreateVibeDeckButtonMutation,\n useUpdateVibeDeckButtonMutation,\n useDeleteVibeDeckButtonMutation,\n useMoveVibeDeckButtonMutation,\n useExecuteVibeDeckButtonMutation,\n} from '@/generated/wspace-operations';\nimport { AccessDenied } from '@burdenoff/fe-libs/shared/components';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '@/constants/permissions';\nimport { useVibeControlsStore } from '@/store/vibeControlsStore';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { isQuotaExhaustedError, markQuotaHandledLocally } from '@/utils/quotaUtils';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport {\n enableRemoteTaskExecution,\n isRemoteTaskDeniedError,\n} from '@/services/agentRemoteTaskGates';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\n\ntype ModalState =\n | { type: 'none' }\n | { type: 'createDeck' }\n | { type: 'editDeck'; deckId: string }\n | { type: 'createButton'; row: number; column: number }\n | { type: 'editButton'; buttonId: string }\n | { type: 'confirmDelete'; target: 'deck' | 'button'; id: string; name: string }\n | { type: 'confirmExecute'; buttonId: string; label: string; detail: string }\n | { type: 'duplicateDeck'; deckId: string }\n | { type: 'shareDeck'; deckId: string; deckName: string };\n\ninterface ErrorToast {\n message: string;\n variant: 'success' | 'error';\n detail?: string | null;\n id: number;\n}\n\nexport function VibeDeckPage() {\n const navigate = useVibeNavigate();\n const { workspaceId } = useVibeControls();\n const bus = useEventBus();\n const { hasPermission, isLoading: permissionsLoading, permissions } = usePermissions();\n const tr = (\n (i18n) =>\n (key: string, fallback: string): string => {\n const v = i18n.t(key);\n return v === key ? fallback : v;\n }\n )(useI18n());\n\n const deckPermsRegistered = (\n Array.isArray(permissions) ? permissions : permissions?.permissionStrings\n )?.some?.((p: string) => p.startsWith('vibedeck:'));\n const canList = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_LIST) : true;\n const canCreate = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_CREATE) : true;\n const canUpdate = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_UPDATE) : true;\n const canDelete = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_DELETE) : true;\n const canExecute = deckPermsRegistered ? hasPermission(VIBE_PERMISSIONS.VIBEDECK_EXECUTE) : true;\n const shouldSkipQueries = permissionsLoading;\n\n const { activeVibeDeckId, setActiveVibeDeckId, vibeDeckMode, setVibeDeckMode } =\n useVibeControlsStore();\n const isPreview = vibeDeckMode === 'preview';\n const effectiveCanCreate = isPreview ? false : canCreate;\n const effectiveCanUpdate = isPreview ? false : canUpdate;\n const effectiveCanDelete = isPreview ? false : canDelete;\n\n const [modal, setModal] = useState<ModalState>({ type: 'none' });\n const [executingButtonId, setExecutingButtonId] = useState<string | null>(null);\n const [selectedDeckIds, setSelectedDeckIds] = useState<Set<string>>(new Set());\n const [selectedButtonIds, setSelectedButtonIds] = useState<Set<string>>(new Set());\n const [bulkDeckAction, setBulkDeckAction] = useState<'delete' | null>(null);\n const [bulkButtonAction, setBulkButtonAction] = useState<'execute' | 'delete' | null>(null);\n const [bulkBusy, setBulkBusy] = useState<\n 'duplicateDeck' | 'deleteDeck' | 'setDefaultDeck' | 'executeButton' | 'deleteButton' | null\n >(null);\n const [toasts, setToasts] = useState<ErrorToast[]>([]);\n const toastTimers = useRef<Map<number, ReturnType<typeof setTimeout>>>(new Map());\n\n // F9: Optional link to a Vibe + visibility. Default is unlinked + PRIVATE.\n // We thread these into the create-deck mutation defensively — if the\n // svc schema does not yet define them, the resolver ignores them.\n const [createDeckLink, setCreateDeckLink] = useState<LinkToVibeValue>(LINK_TO_VIBE_DEFAULT);\n\n // Execution log state\n const [executionLog, setExecutionLog] = useState<ExecutionLogEntry[]>([]);\n const [executionLogExpanded, setExecutionLogExpanded] = useState(true);\n const [buttonStatuses, setButtonStatuses] = useState<\n Map<string, 'idle' | 'executing' | 'success' | 'error'>\n >(new Map());\n const [quotaDialog, setQuotaDialog] = useState<{ title: string; message: string } | null>(null);\n // Reactive \"enable remote execution\" prompt when a deck-button run is denied\n // because the target agent's remote-task gate is off.\n const [remoteTaskPrompt, setRemoteTaskPrompt] = useState<{\n buttonId: string;\n agentId: string;\n } | null>(null);\n const [enablingRemoteTask, setEnablingRemoteTask] = useState(false);\n const { profiles: deniedAgentProfiles } = useActiveAgentProfile(\n remoteTaskPrompt?.agentId ?? null\n );\n // The runner targets the agent's DEFAULT profile, so the gate must be written\n // there — not the UI's \"active\" profile (which can differ on multi-profile\n // agents and would unlock the wrong daemon, leaving the run still denied).\n const deniedAgentExecProfile = deniedAgentProfiles.find((p) => p.isDefault)?.name ?? 'default';\n const statusTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n useEffect(() => {\n const timers = statusTimers.current;\n return () => {\n for (const timer of timers.values()) clearTimeout(timer);\n };\n }, []);\n\n const addLogEntry = useCallback((entry: Omit<ExecutionLogEntry, 'id'>) => {\n const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n const newEntry = { ...entry, id };\n setExecutionLog((prev) => [...prev.slice(-49), newEntry]);\n return id;\n }, []);\n\n const updateLogEntry = useCallback((id: string, updates: Partial<ExecutionLogEntry>) => {\n setExecutionLog((prev) =>\n prev.map((entry) => (entry.id === id ? { ...entry, ...updates } : entry))\n );\n }, []);\n\n const setButtonStatus = useCallback(\n (buttonId: string, status: 'idle' | 'executing' | 'success' | 'error') => {\n setButtonStatuses((prev) => {\n const next = new Map(prev);\n next.set(buttonId, status);\n return next;\n });\n if (status === 'success' || status === 'error') {\n const timer = setTimeout(() => {\n setButtonStatuses((prev) => {\n const next = new Map(prev);\n if (next.get(buttonId) === status) next.delete(buttonId);\n return next;\n });\n statusTimers.current.delete(buttonId);\n }, 3000);\n const existing = statusTimers.current.get(buttonId);\n if (existing) clearTimeout(existing);\n statusTimers.current.set(buttonId, timer);\n }\n },\n []\n );\n\n useEffect(() => {\n const timers = toastTimers.current;\n return () => {\n for (const timer of timers.values()) clearTimeout(timer);\n };\n }, []);\n\n const showToast = useCallback(\n (message: string, variant: 'success' | 'error', detail?: string | null, duration?: number) => {\n const id = Date.now() + Math.random();\n setToasts((prev) => [...prev, { message, variant, detail, id }]);\n const autoDismiss = duration ?? (variant === 'success' ? 10000 : 30000);\n const timer = setTimeout(() => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n toastTimers.current.delete(id);\n }, autoDismiss);\n toastTimers.current.set(id, timer);\n },\n []\n );\n\n const dismissToast = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n const timer = toastTimers.current.get(id);\n if (timer) {\n clearTimeout(timer);\n toastTimers.current.delete(id);\n }\n }, []);\n\n const showQuotaDialog = useCallback((title: string, message: string) => {\n // Coordinate with the global QuotaExhaustedProvider so it skips its\n // own dialog when this page renders a local one (BOFF-2625 review).\n markQuotaHandledLocally();\n setQuotaDialog({ title, message });\n }, []);\n\n const {\n data: decksData,\n loading: decksLoading,\n error: decksError,\n refetch: refetchDecks,\n } = useListVibeDecksQuery({\n variables: { pagination: { limit: 50 } },\n skip: shouldSkipQueries,\n });\n\n const decks = useMemo(() => decksData?.vibeDecks?.items || [], [decksData]);\n\n const effectiveActiveDeckId =\n activeVibeDeckId ||\n decks.find((d: { isDefault: boolean }) => d.isDefault)?.id ||\n decks[0]?.id ||\n null;\n\n const {\n data: deckData,\n loading: deckLoading,\n refetch: refetchDeck,\n } = useGetVibeDeckQuery({\n variables: { id: effectiveActiveDeckId! },\n skip: !effectiveActiveDeckId || shouldSkipQueries,\n });\n\n const activeDeck = deckData?.vibeDeck;\n\n const selectedDecks = useMemo(\n () => decks.filter((deck: { id: string }) => selectedDeckIds.has(deck.id)),\n [decks, selectedDeckIds]\n );\n\n const selectedButtons = useMemo(\n () =>\n activeDeck?.buttons?.filter((button: { id: string }) => selectedButtonIds.has(button.id)) ??\n [],\n [activeDeck?.buttons, selectedButtonIds]\n );\n\n const allDecksSelected =\n decks.length > 0 && decks.every((deck: { id: string }) => selectedDeckIds.has(deck.id));\n const partiallySelectedDecks =\n decks.some((deck: { id: string }) => selectedDeckIds.has(deck.id)) && !allDecksSelected;\n const allButtonsSelected =\n (activeDeck?.buttons?.length ?? 0) > 0 &&\n (activeDeck?.buttons ?? []).every((button: { id: string }) => selectedButtonIds.has(button.id));\n const partiallySelectedButtons =\n (activeDeck?.buttons ?? []).some((button: { id: string }) =>\n selectedButtonIds.has(button.id)\n ) && !allButtonsSelected;\n\n const { data: agentsData } = useListAgentsQuery({\n variables: { pagination: { limit: 100 } },\n fetchPolicy: 'cache-and-network',\n skip: shouldSkipQueries,\n });\n const agents = (agentsData?.vibecontrolsAgents ?? []).map(\n (a: { id: string; name: string; isActive: boolean }) => ({\n id: a.id,\n name: a.name,\n isActive: a.isActive,\n })\n );\n\n const [createDeck, { loading: createDeckLoading }] = useCreateVibeDeckMutation({\n refetchQueries: ['ListVibeDecks'],\n });\n const { setDraftTagIds: setDeckDraftTagIds, flushTags: flushDeckTags } =\n useDraftEntityTags('VIBECONTROLS_VIBEDECK');\n const [updateDeck, { loading: updateDeckLoading }] = useUpdateVibeDeckMutation({\n refetchQueries: ['ListVibeDecks', 'GetVibeDeck'],\n });\n const [deleteDeck] = useDeleteVibeDeckMutation({\n refetchQueries: ['ListVibeDecks'],\n });\n const [setDefaultDeck] = useSetDefaultVibeDeckMutation({\n refetchQueries: ['ListVibeDecks', 'GetVibeDeck'],\n });\n const [duplicateDeck] = useDuplicateVibeDeckMutation({\n refetchQueries: ['ListVibeDecks'],\n });\n const [createButton, { loading: createButtonLoading }] = useCreateVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [updateButton, { loading: updateButtonLoading }] = useUpdateVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [deleteButton] = useDeleteVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [moveButton] = useMoveVibeDeckButtonMutation({\n refetchQueries: ['GetVibeDeck'],\n });\n const [executeButton] = useExecuteVibeDeckButtonMutation();\n\n useEffect(() => {\n setSelectedButtonIds(new Set());\n }, [effectiveActiveDeckId]);\n\n const toggleDeckSelection = useCallback((deckId: string, checked: boolean) => {\n setSelectedDeckIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(deckId);\n } else {\n next.delete(deckId);\n }\n return next;\n });\n }, []);\n\n const toggleAllDecks = useCallback(\n (checked: boolean) => {\n setSelectedDeckIds((prev) => {\n const next = new Set(prev);\n decks.forEach((deck: { id: string }) => {\n if (checked) {\n next.add(deck.id);\n } else {\n next.delete(deck.id);\n }\n });\n return next;\n });\n },\n [decks]\n );\n\n const clearDeckSelection = useCallback(() => {\n setSelectedDeckIds(new Set());\n }, []);\n\n const toggleButtonSelection = useCallback((buttonId: string, checked: boolean) => {\n setSelectedButtonIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(buttonId);\n } else {\n next.delete(buttonId);\n }\n return next;\n });\n }, []);\n\n const toggleAllButtons = useCallback(\n (checked: boolean) => {\n setSelectedButtonIds((prev) => {\n const next = new Set(prev);\n (activeDeck?.buttons ?? []).forEach((button: { id: string }) => {\n if (checked) {\n next.add(button.id);\n } else {\n next.delete(button.id);\n }\n });\n return next;\n });\n },\n [activeDeck?.buttons]\n );\n\n const clearButtonSelection = useCallback(() => {\n setSelectedButtonIds(new Set());\n }, []);\n\n const handleCreateDeck = useCallback(\n async (data: {\n name: string;\n description: string;\n colorTheme: string;\n gridColumns: number;\n gridRows: number;\n }) => {\n try {\n // F9: Thread the optional Vibe link through the mutation input.\n // `CreateVibeDeckInput` now declares `vibeId` + `visibility`, so the\n // link fields type-check directly — no defensive cast needed.\n const res = await createDeck({\n variables: {\n input: {\n name: data.name,\n description: data.description || null,\n colorTheme: data.colorTheme || null,\n gridColumns: data.gridColumns,\n gridRows: data.gridRows,\n ...linkToVibeInput(createDeckLink),\n },\n },\n });\n const newDeckId = res.data?.createVibeDeck?.id;\n setModal({ type: 'none' });\n showToast('Deck created', 'success');\n setCreateDeckLink(LINK_TO_VIBE_DEFAULT);\n if (newDeckId) await flushDeckTags(newDeckId);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setModal({ type: 'none' });\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to create more decks.'\n );\n return;\n }\n\n showToast(err instanceof Error ? err.message : 'Failed to create deck', 'error');\n }\n },\n [createDeck, flushDeckTags, showQuotaDialog, showToast, createDeckLink]\n );\n\n const handleUpdateDeck = useCallback(\n async (data: {\n name: string;\n description: string;\n colorTheme: string;\n gridColumns: number;\n gridRows: number;\n }) => {\n if (modal.type !== 'editDeck') return;\n try {\n await updateDeck({\n variables: {\n id: modal.deckId,\n input: {\n name: data.name,\n description: data.description || null,\n colorTheme: data.colorTheme || null,\n gridColumns: data.gridColumns,\n gridRows: data.gridRows,\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Deck updated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to update deck', 'error');\n }\n },\n [updateDeck, modal, showToast]\n );\n\n const handleDeleteConfirm = useCallback(async () => {\n if (modal.type !== 'confirmDelete') return;\n try {\n if (modal.target === 'deck') {\n await deleteDeck({ variables: { id: modal.id } });\n if (activeVibeDeckId === modal.id) {\n setActiveVibeDeckId(null);\n }\n showToast('Deck deleted', 'success');\n } else {\n await deleteButton({ variables: { id: modal.id } });\n showToast('Button deleted', 'success');\n }\n setModal({ type: 'none' });\n if (isNative()) void nativeNotify('success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete', 'error');\n if (isNative()) void nativeNotify('error');\n }\n }, [modal, deleteDeck, deleteButton, activeVibeDeckId, setActiveVibeDeckId, showToast]);\n\n const doExecuteButton = useCallback(\n async (buttonId: string, allowRemotePrompt = true) => {\n const button = activeDeck?.buttons?.find((b: { id: string }) => b.id === buttonId);\n if (!button || !button.action) return;\n\n const action = button.action;\n\n // Add log entry\n const logId = addLogEntry({\n buttonId,\n buttonLabel: button.label,\n actionType: action.actionType as any,\n command:\n action.actionType === 'WEBHOOK'\n ? `POST ${action.webhookUrl || ''}`\n : action.command || undefined,\n status: 'running',\n startedAt: new Date(),\n });\n\n setExecutingButtonId(buttonId);\n setButtonStatus(buttonId, 'executing');\n\n try {\n const result = await executeButton({ variables: { id: buttonId } });\n const exec = result.data?.executeVibeDeckButton;\n // The agent rejected the run because its remote-task gate is off — offer\n // to enable it in context (and retry) instead of a dead-end error.\n if (exec && isRemoteTaskDeniedError(exec) && exec.agentId) {\n setButtonStatus(buttonId, 'error');\n updateLogEntry(logId, {\n status: 'error',\n error: allowRemotePrompt\n ? 'Remote task execution is disabled on this agent.'\n : 'Remote execution still blocked after enabling — check the agent’s Security settings.',\n output: exec.output,\n completedAt: new Date(),\n });\n // allowRemotePrompt is false on the post-enable retry so a still-denied\n // run does not re-open the dialog in a loop.\n if (allowRemotePrompt) {\n setRemoteTaskPrompt({ buttonId, agentId: exec.agentId });\n }\n return;\n }\n if (exec) {\n const isSuccess = exec.status === 'success';\n setButtonStatus(buttonId, isSuccess ? 'success' : 'error');\n updateLogEntry(logId, {\n status: isSuccess ? 'success' : 'error',\n output: exec.output,\n exitCode: exec.exitCode,\n webhookStatusCode: exec.webhookStatusCode,\n completedAt: new Date(),\n });\n if (isSuccess) {\n bus.emitCustom('vibecontrols.vibedeck.button_executed', {\n workspaceId: workspaceId ?? undefined,\n buttonId,\n deckId: effectiveActiveDeckId ?? undefined,\n });\n }\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setButtonStatus(buttonId, 'error');\n updateLogEntry(logId, {\n status: 'error',\n error: 'Usage quota exhausted',\n completedAt: new Date(),\n });\n showQuotaDialog(\n 'Execution Quota Reached',\n 'You have used the execution quota for your current plan. Upgrade to continue running Vibe Deck actions.'\n );\n return;\n }\n\n const errorMsg = err instanceof Error ? err.message : 'Execution failed';\n setButtonStatus(buttonId, 'error');\n updateLogEntry(logId, {\n status: 'error',\n error: errorMsg,\n completedAt: new Date(),\n });\n } finally {\n setExecutingButtonId(null);\n }\n },\n [\n activeDeck,\n executeButton,\n addLogEntry,\n updateLogEntry,\n setButtonStatus,\n showQuotaDialog,\n bus,\n workspaceId,\n effectiveActiveDeckId,\n ]\n );\n\n const handleEnableRemoteTaskConfirm = useCallback(\n async ({ shell, file }: { shell: boolean; file: boolean }) => {\n if (!remoteTaskPrompt) return;\n const { buttonId, agentId } = remoteTaskPrompt;\n setEnablingRemoteTask(true);\n try {\n await enableRemoteTaskExecution(\n { id: agentId, profile: deniedAgentExecProfile },\n { shell, file }\n );\n setRemoteTaskPrompt(null);\n // Retry the run ONCE (allowRemotePrompt=false) so a still-denied result\n // does not re-open this dialog in a loop.\n await doExecuteButton(buttonId, false);\n } catch (err) {\n showToast(\n err instanceof Error ? err.message : 'Failed to enable remote execution',\n 'error'\n );\n } finally {\n setEnablingRemoteTask(false);\n }\n },\n [remoteTaskPrompt, deniedAgentExecProfile, doExecuteButton, showToast]\n );\n\n const handleExecuteButton = useCallback(\n async (buttonId: string) => {\n const button = activeDeck?.buttons?.find((b: { id: string }) => b.id === buttonId);\n if (!button) return;\n\n bus.emitCustom('vibecontrols.vibedeck.button_executed_clicked', {\n workspaceId: workspaceId ?? undefined,\n buttonId,\n deckId: effectiveActiveDeckId ?? undefined,\n });\n\n if (button.confirmationRequired) {\n const action = button.action;\n const detail =\n action?.actionType === 'WEBHOOK'\n ? `POST ${action.webhookUrl || ''}`\n : action?.command || '';\n setModal({ type: 'confirmExecute', buttonId, label: button.label, detail });\n return;\n }\n\n await doExecuteButton(buttonId);\n },\n [activeDeck, doExecuteButton, bus, workspaceId, effectiveActiveDeckId]\n );\n\n const handleConfirmExecute = useCallback(async () => {\n if (modal.type !== 'confirmExecute') return;\n const buttonId = modal.buttonId;\n setModal({ type: 'none' });\n await doExecuteButton(buttonId);\n }, [modal, doExecuteButton]);\n\n const handleCreateButton = useCallback(\n async (data: {\n label: string;\n color: string;\n category: string;\n keyboardShortcut: string;\n confirmationRequired: boolean;\n rowSpan: number;\n colSpan: number;\n actionId: string;\n }) => {\n if (modal.type !== 'createButton' || !effectiveActiveDeckId) return;\n\n try {\n await createButton({\n variables: {\n input: {\n vibeDeckId: effectiveActiveDeckId,\n label: data.label,\n actionId: data.actionId,\n row: modal.row,\n column: modal.column,\n rowSpan: data.rowSpan,\n colSpan: data.colSpan,\n color: data.color || null,\n category: data.category || null,\n keyboardShortcut: data.keyboardShortcut || null,\n confirmationRequired: data.confirmationRequired,\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Button created', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to create button', 'error');\n }\n },\n [modal, createButton, effectiveActiveDeckId, showToast]\n );\n\n const handleUpdateButton = useCallback(\n async (data: {\n label: string;\n color: string;\n category: string;\n keyboardShortcut: string;\n confirmationRequired: boolean;\n rowSpan: number;\n colSpan: number;\n actionId: string;\n }) => {\n if (modal.type !== 'editButton') return;\n\n try {\n await updateButton({\n variables: {\n id: modal.buttonId,\n input: {\n label: data.label,\n actionId: data.actionId,\n color: data.color || null,\n category: data.category || null,\n keyboardShortcut: data.keyboardShortcut || null,\n confirmationRequired: data.confirmationRequired,\n rowSpan: data.rowSpan,\n colSpan: data.colSpan,\n },\n },\n });\n setModal({ type: 'none' });\n showToast('Button updated', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to update button', 'error');\n }\n },\n [modal, updateButton, showToast]\n );\n\n const handleDropButton = useCallback(\n async (buttonId: string, targetRow: number, targetColumn: number) => {\n try {\n await moveButton({\n variables: {\n id: buttonId,\n input: { row: targetRow, column: targetColumn },\n },\n });\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to move button', 'error');\n }\n },\n [moveButton, showToast]\n );\n\n const handleDuplicateDeck = useCallback(\n async (deckId: string) => {\n const deck = decks.find((d: { id: string; name: string }) => d.id === deckId);\n if (!deck) return;\n try {\n const newName = `${deck.name} (Copy)`;\n await duplicateDeck({ variables: { id: deckId, name: newName } });\n showToast('Deck duplicated', 'success');\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to duplicate more decks.'\n );\n return;\n }\n\n showToast(err instanceof Error ? err.message : 'Failed to duplicate deck', 'error');\n }\n },\n [decks, duplicateDeck, showQuotaDialog, showToast]\n );\n\n const handleSetDefault = useCallback(\n async (id: string) => {\n try {\n await setDefaultDeck({ variables: { id } });\n showToast('Default deck set', 'success');\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to set default', 'error');\n }\n },\n [setDefaultDeck, showToast]\n );\n\n const handleSetSelectedDefault = useCallback(async () => {\n if (selectedDecks.length !== 1) return;\n setBulkBusy('setDefaultDeck');\n try {\n await setDefaultDeck({ variables: { id: selectedDecks[0].id } });\n showToast('Default deck set', 'success');\n clearDeckSelection();\n await refetchDecks();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to set default deck', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedDecks, setDefaultDeck, showToast, clearDeckSelection, refetchDecks]);\n\n const handleBulkDuplicateDecks = useCallback(async () => {\n if (selectedDecks.length === 0) return;\n setBulkBusy('duplicateDeck');\n try {\n const results = await Promise.allSettled(\n selectedDecks.map((deck: { id: string; name: string }) =>\n duplicateDeck({ variables: { id: deck.id, name: `${deck.name} (Copy)` } })\n )\n );\n\n const quotaRejected = results.some(\n (result: PromiseSettledResult<unknown>): result is PromiseRejectedResult =>\n result.status === 'rejected' && isQuotaExhaustedError(result.reason)\n );\n\n if (quotaRejected) {\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to duplicate more decks.'\n );\n return;\n }\n\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n showToast(\n `Duplicated ${succeeded} deck${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearDeckSelection();\n await refetchDecks();\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n showQuotaDialog(\n 'Vibe Deck Quota Reached',\n 'You have reached the Vibe Deck limit for your current plan. Upgrade to duplicate more decks.'\n );\n return;\n }\n\n showToast(err instanceof Error ? err.message : 'Failed to duplicate decks', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedDecks, duplicateDeck, showQuotaDialog, showToast, clearDeckSelection, refetchDecks]);\n\n const handleBulkDeleteDecks = useCallback(async () => {\n if (selectedDecks.length === 0) return;\n setBulkBusy('deleteDeck');\n try {\n const results = await Promise.allSettled(\n selectedDecks.map((deck: { id: string }) => deleteDeck({ variables: { id: deck.id } }))\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n if (selectedDecks.some((deck: { id: string }) => deck.id === activeVibeDeckId)) {\n setActiveVibeDeckId(null);\n }\n showToast(\n `Deleted ${succeeded} deck${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearDeckSelection();\n setBulkDeckAction(null);\n await refetchDecks();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete decks', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [\n selectedDecks,\n deleteDeck,\n activeVibeDeckId,\n setActiveVibeDeckId,\n showToast,\n clearDeckSelection,\n refetchDecks,\n ]);\n\n const handleBulkExecuteButtons = useCallback(async () => {\n if (selectedButtons.length === 0) return;\n setBulkBusy('executeButton');\n let succeeded = 0;\n let failed = 0;\n try {\n for (const button of selectedButtons) {\n try {\n const result = await executeButton({ variables: { id: button.id } });\n const exec = result.data?.executeVibeDeckButton;\n if (exec?.status === 'success') {\n succeeded += 1;\n } else {\n failed += 1;\n }\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setBulkButtonAction(null);\n showQuotaDialog(\n 'Execution Quota Reached',\n 'You have used the execution quota for your current plan. Upgrade to continue running Vibe Deck actions.'\n );\n return;\n }\n\n failed += 1;\n }\n }\n showToast(\n `Executed ${succeeded} button${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearButtonSelection();\n setBulkButtonAction(null);\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to execute buttons', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedButtons, executeButton, showQuotaDialog, showToast, clearButtonSelection]);\n\n const handleBulkDeleteButtons = useCallback(async () => {\n if (selectedButtons.length === 0) return;\n setBulkBusy('deleteButton');\n try {\n const results = await Promise.allSettled(\n selectedButtons.map((button: { id: string }) =>\n deleteButton({ variables: { id: button.id } })\n )\n );\n const succeeded = results.filter(\n (result: PromiseSettledResult<unknown>) => result.status === 'fulfilled'\n ).length;\n const failed = results.length - succeeded;\n showToast(\n `Deleted ${succeeded} button${succeeded === 1 ? '' : 's'}${failed > 0 ? ` • ${failed} failed` : ''}`,\n failed > 0 ? 'error' : 'success'\n );\n clearButtonSelection();\n setBulkButtonAction(null);\n await refetchDeck();\n } catch (err) {\n showToast(err instanceof Error ? err.message : 'Failed to delete buttons', 'error');\n } finally {\n setBulkBusy(null);\n }\n }, [selectedButtons, deleteButton, showToast, clearButtonSelection, refetchDeck]);\n\n if (permissionsLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading permissions...\" />\n </MotionPage>\n );\n }\n\n if (permissions && (permissions.permissionStrings?.length ?? 0) > 0 && !canList) {\n return (\n <MotionPage>\n <AccessDenied />\n </MotionPage>\n );\n }\n\n if (decksLoading) {\n return (\n <MotionPage>\n <LoadingState message=\"Loading Vibe Decks...\" />\n </MotionPage>\n );\n }\n\n if (decksError) {\n return (\n <MotionPage>\n <ErrorState message={decksError.message} onRetry={() => refetchDecks()} />\n </MotionPage>\n );\n }\n\n const editingButton =\n modal.type === 'editButton'\n ? activeDeck?.buttons?.find((b: { id: string }) => b.id === modal.buttonId)\n : null;\n const editingDeck =\n modal.type === 'editDeck' ? decks.find((d: { id: string }) => d.id === modal.deckId) : null;\n\n return (\n <MotionPage className=\"p-4 sm:p-6 space-y-6\">\n <PageHeader\n title={tr('nav.vibeDeck', 'Vibe Deck')}\n description=\"Your digital command board — execute commands or trigger webhooks with one click\"\n actions={\n <div className=\"flex items-center gap-2\">\n <div\n data-tour=\"vibedeck-mode-switcher\"\n className=\"flex items-center rounded-lg border border-border-default bg-bg-secondary p-0.5\"\n >\n <button\n type=\"button\"\n onClick={() => setVibeDeckMode('preview')}\n className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all ${\n isPreview\n ? 'bg-action-primary-bg text-action-primary-text shadow-sm'\n : 'text-text-tertiary hover:text-text-primary'\n }`}\n title={isPreview ? 'Preview mode — execute only' : 'Switch to Preview mode'}\n aria-pressed={isPreview}\n >\n <Eye size={14} />\n Preview\n </button>\n <button\n type=\"button\"\n onClick={() => setVibeDeckMode('edit')}\n className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm font-medium transition-all ${\n !isPreview\n ? 'bg-action-primary-bg text-action-primary-text shadow-sm'\n : 'text-text-tertiary hover:text-text-primary'\n }`}\n title={!isPreview ? 'Edit mode — full editing' : 'Switch to Edit mode'}\n aria-pressed={!isPreview}\n >\n <Pencil size={14} />\n Edit\n </button>\n </div>\n {effectiveActiveDeckId && activeDeck && (\n // Generic Share entry point for the active deck. The button\n // self-gates on the `vibedeck:share` RBAC permission (via its\n // internal PermissionGate) + the `vibecontrols.sharing.vibedeck`\n // feature flag, then renders the generic `<ShareDialog>` (email\n // invite + accept-gate + four visibility modes + expiry + public\n // link), backed by the generic `shareVibeDeckGrant` mutations.\n // Realtime/exec behaviour of the deck is unaffected — this only\n // manages share grants.\n <EntityShareButton\n entity=\"vibedeck\"\n resource={{ id: effectiveActiveDeckId, name: activeDeck.name }}\n label={tr('vibecontrols.vibedeck.share.shareDeck', 'Share deck')}\n />\n )}\n <button\n type=\"button\"\n onClick={() => {\n refetchDecks();\n if (effectiveActiveDeckId) refetchDeck();\n }}\n className=\"p-2 rounded-lg hover:bg-bg-tertiary text-text-tertiary hover:text-text-primary transition-colors\"\n title=\"Refresh\"\n >\n <RefreshCw size={16} />\n </button>\n </div>\n }\n />\n\n {!isPreview && decks.length > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allDecksSelected}\n indeterminate={partiallySelectedDecks}\n onChange={toggleAllDecks}\n ariaLabel=\"Select all vibe decks\"\n />\n <span className=\"text-sm font-medium text-text-primary\">Select all decks</span>\n </div>\n {selectedDeckIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearDeckSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedDeckIds.size} selected\n </span>\n <button\n type=\"button\"\n onClick={handleSetSelectedDefault}\n disabled={\n selectedDecks.length !== 1 || selectedDecks[0]?.isDefault || bulkBusy !== null\n }\n className=\"rounded-md border border-status-warning-border px-3 py-2 text-sm font-medium text-status-warning-text hover:bg-status-warning-bg-subtle disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Star size={14} />\n Set Selected Default\n </span>\n </button>\n <button\n type=\"button\"\n onClick={handleBulkDuplicateDecks}\n disabled={selectedDecks.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-border-default px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Copy size={14} />\n Duplicate Selected{selectedDecks.length > 0 ? ` (${selectedDecks.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setBulkDeckAction('delete')}\n disabled={selectedDecks.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Trash2 size={14} />\n Delete Selected{selectedDecks.length > 0 ? ` (${selectedDecks.length})` : ''}\n </span>\n </button>\n </div>\n </div>\n </div>\n )}\n\n <div data-tour=\"vibedeck-switcher\">\n <VibeDeckSwitcher\n decks={decks.map((d: any) => ({\n id: d.id,\n name: d.name,\n icon: d.icon || null,\n colorTheme: d.colorTheme || null,\n isDefault: d.isDefault,\n }))}\n activeDeckId={effectiveActiveDeckId}\n selectedDeckIds={selectedDeckIds}\n onSelectDeck={(id) => setActiveVibeDeckId(id)}\n onToggleSelectDeck={toggleDeckSelection}\n onCreateDeck={() => setModal({ type: 'createDeck' })}\n onSetDefault={handleSetDefault}\n onDuplicate={(id) => handleDuplicateDeck(id)}\n onDelete={(id) => {\n const deck = decks.find((d: { id: string }) => d.id === id);\n setModal({\n type: 'confirmDelete',\n target: 'deck',\n id,\n name: deck?.name || 'this deck',\n });\n }}\n onEdit={(id) => setModal({ type: 'editDeck', deckId: id })}\n onShare={(id) => {\n const deck = decks.find((d: { id: string; name: string }) => d.id === id);\n if (deck) setModal({ type: 'shareDeck', deckId: id, deckName: deck.name });\n }}\n // Create button is ungated by preview mode so users can always add a\n // new deck. Update/delete stay gated because they mutate selected decks.\n canCreate={canCreate}\n canUpdate={effectiveCanUpdate}\n canDelete={effectiveCanDelete}\n />\n </div>\n\n <AnimatePresence mode=\"wait\">\n {!activeDeck && !deckLoading && decks.length === 0 && (\n <EmptyState\n title=\"No Vibe Decks yet\"\n description=\"Create your first Vibe Deck to start organizing your commands and webhooks\"\n action={\n <div className=\"flex items-center gap-2\">\n {canCreate && (\n <button\n type=\"button\"\n onClick={() => setModal({ type: 'createDeck' })}\n className=\"px-4 py-2 rounded-lg bg-action-primary-bg text-action-primary-text hover:opacity-90 text-sm font-medium\"\n >\n Create Vibe Deck\n </button>\n )}\n <GetHelpButton prompt=\"What is a VibeDeck and how do I use it to organise controls?\" />\n </div>\n }\n />\n )}\n\n {deckLoading && <LoadingState message=\"Loading deck...\" />}\n </AnimatePresence>\n\n {activeDeck && (\n <div className=\"space-y-4\">\n {!isPreview && (activeDeck.buttons?.length ?? 0) > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 xl:flex-row xl:items-center xl:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allButtonsSelected}\n indeterminate={partiallySelectedButtons}\n onChange={toggleAllButtons}\n ariaLabel=\"Select all buttons in active deck\"\n />\n <span className=\"text-sm font-medium text-text-primary\">\n Select all buttons in this deck\n </span>\n </div>\n {selectedButtonIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearButtonSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n Clear selection\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedButtonIds.size} selected\n </span>\n <button\n type=\"button\"\n onClick={() => setBulkButtonAction('execute')}\n disabled={selectedButtons.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-success-border px-3 py-2 text-sm font-medium text-status-success-text hover:bg-status-success-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Play size={14} />\n Execute Selected\n {selectedButtons.length > 0 ? ` (${selectedButtons.length})` : ''}\n </span>\n </button>\n <button\n type=\"button\"\n onClick={() => setBulkButtonAction('delete')}\n disabled={selectedButtons.length === 0 || bulkBusy !== null}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <Trash2 size={14} />\n Delete Selected\n {selectedButtons.length > 0 ? ` (${selectedButtons.length})` : ''}\n </span>\n </button>\n </div>\n </div>\n </div>\n )}\n\n <div data-tour=\"vibedeck-grid\" className=\"relative\">\n <VibeDeckGrid\n gridColumns={activeDeck.gridColumns}\n gridRows={activeDeck.gridRows}\n buttons={(activeDeck.buttons || []).map((b: any) => ({\n id: b.id,\n label: b.label,\n icon: b.icon || null,\n color: b.color || null,\n category: b.category || null,\n confirmationRequired: b.confirmationRequired,\n keyboardShortcut: b.keyboardShortcut || null,\n actionId: b.actionId || null,\n action: b.action\n ? {\n id: b.action.id,\n name: b.action.name,\n displayName: b.action.displayName || null,\n actionType: b.action.actionType,\n command: b.action.command || null,\n script: b.action.script || null,\n webhookUrl: b.action.webhookUrl || null,\n targetAgentId: b.action.targetAgentId || null,\n }\n : null,\n row: b.row,\n column: b.column,\n rowSpan: b.rowSpan,\n colSpan: b.colSpan,\n }))}\n onExecuteButton={handleExecuteButton}\n onEditButton={(id) => setModal({ type: 'editButton', buttonId: id })}\n onDeleteButton={(id) => {\n const btn = activeDeck.buttons?.find((b: { id: string }) => b.id === id);\n setModal({\n type: 'confirmDelete',\n target: 'button',\n id,\n name: btn?.label || 'this button',\n });\n }}\n onDropButton={handleDropButton}\n onAddButton={(row, column) => setModal({ type: 'createButton', row, column })}\n executingButtonId={executingButtonId}\n canCreate={effectiveCanCreate}\n canUpdate={effectiveCanUpdate}\n canDelete={effectiveCanDelete}\n canExecute={canExecute}\n previewMode={isPreview}\n />\n\n {/* Fresh-deck guidance — overlay in preview mode when the\n deck has zero buttons. Prompts the user to switch to\n Edit mode, the canonical place to add buttons. */}\n {(activeDeck.buttons?.length ?? 0) === 0 && isPreview && (\n <div className=\"absolute inset-0 flex items-center justify-center pointer-events-none\">\n <div className=\"bg-bg-elevated/90 backdrop-blur-md border border-border-default rounded-lg p-6 max-w-md pointer-events-auto shadow-xl text-center\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibeDeck.emptyDeckTitle', 'This deck is empty')}\n </h3>\n <p className=\"text-sm text-text-secondary mt-2\">\n {tr('vibeDeck.emptyDeckDescription', 'Switch to Edit mode to add buttons.')}\n </p>\n {canUpdate && (\n <button\n type=\"button\"\n onClick={() => setVibeDeckMode('edit')}\n className=\"mt-4 inline-flex items-center gap-2 px-4 py-2 rounded-md bg-action-primary-bg text-action-primary-text text-sm font-medium hover:opacity-90 transition-opacity\"\n >\n {tr('vibeDeck.editDeck', 'Edit deck')}\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n\n {executionLog.length > 0 && (\n <div data-tour=\"vibedeck-execution-log\">\n <VibeDeckExecutionLog\n entries={executionLog}\n expanded={executionLogExpanded}\n onToggleExpanded={() => setExecutionLogExpanded((prev) => !prev)}\n onClear={() => setExecutionLog([])}\n />\n </div>\n )}\n\n <AnimatePresence>\n {toasts.length > 0 && (\n <div className=\"fixed bottom-4 left-4 right-4 sm:left-auto sm:bottom-6 sm:right-6 z-50 flex flex-col gap-2 max-w-[calc(100vw-2rem)] sm:max-w-md\">\n {toasts.slice(-3).map((toast) => (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => dismissToast(toast.id))();\n }\n }}\n key={toast.id}\n className={`p-4 rounded-xl shadow-lg border cursor-pointer ${\n toast.variant === 'success'\n ? 'bg-status-success-bg/10 border-status-success-border/30 text-status-success-text'\n : 'bg-status-error-bg/10 border-status-error-border/30 text-status-error-text'\n }`}\n onClick={() => dismissToast(toast.id)}\n >\n <div className=\"font-medium text-sm\">{toast.message}</div>\n {toast.detail && (\n <pre className=\"text-xs font-mono opacity-80 mt-1 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {toast.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n )}\n </AnimatePresence>\n\n {modal.type === 'createDeck' && (\n <VibeDeckForm\n title=\"Create Vibe Deck\"\n onSubmit={handleCreateDeck}\n onCancel={() => {\n setModal({ type: 'none' });\n setCreateDeckLink(LINK_TO_VIBE_DEFAULT);\n }}\n isLoading={createDeckLoading}\n extraSection={\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('vibeDeck.tags', 'Tags')}\n </h3>\n <EntityTagPicker\n entityType=\"VIBECONTROLS_VIBEDECK\"\n onDraftChange={setDeckDraftTagIds}\n />\n </div>\n <LinkToVibePanel value={createDeckLink} onChange={setCreateDeckLink} />\n </div>\n }\n />\n )}\n\n {modal.type === 'editDeck' && editingDeck && (\n <VibeDeckForm\n title=\"Edit Vibe Deck\"\n initialData={{\n name: editingDeck.name,\n description: editingDeck.description || '',\n colorTheme: editingDeck.colorTheme || '',\n gridColumns: editingDeck.gridColumns,\n gridRows: editingDeck.gridRows,\n }}\n onSubmit={handleUpdateDeck}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={updateDeckLoading}\n extraSection={\n <div>\n <h3 className=\"text-sm font-medium text-text-secondary mb-2\">\n {tr('vibeDeck.tags', 'Tags')}\n </h3>\n <EntityTagPicker entityType=\"VIBECONTROLS_VIBEDECK\" entityId={editingDeck.id} />\n </div>\n }\n />\n )}\n\n {modal.type === 'createButton' && (\n <VibeDeckButtonForm\n title=\"Add Button\"\n agents={agents}\n onSubmit={handleCreateButton}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={createButtonLoading}\n gridColumns={activeDeck?.gridColumns}\n gridRows={activeDeck?.gridRows}\n buttonRow={modal.row}\n buttonColumn={modal.column}\n />\n )}\n\n {modal.type === 'editButton' && editingButton && (\n <VibeDeckButtonForm\n title=\"Edit Button\"\n initialData={\n {\n label: editingButton.label,\n actionId: (editingButton as any).actionId || '',\n color: editingButton.color || '',\n category: editingButton.category || '',\n keyboardShortcut: editingButton.keyboardShortcut || '',\n confirmationRequired: editingButton.confirmationRequired,\n rowSpan: editingButton.rowSpan,\n colSpan: editingButton.colSpan,\n } as any\n }\n agents={agents}\n onSubmit={handleUpdateButton}\n onCancel={() => setModal({ type: 'none' })}\n isLoading={updateButtonLoading}\n gridColumns={activeDeck?.gridColumns}\n gridRows={activeDeck?.gridRows}\n buttonRow={editingButton.row}\n buttonColumn={editingButton.column}\n />\n )}\n\n {modal.type === 'confirmDelete' && (\n <ConfirmDialog\n isOpen={true}\n title={`Delete ${modal.target === 'deck' ? 'Vibe Deck' : 'Button'}`}\n message={`Are you sure you want to delete \"${modal.name}\"?${modal.target === 'deck' ? ' All buttons in this deck will also be deleted.' : ''}`}\n confirmLabel=\"Delete\"\n variant=\"danger\"\n onConfirm={handleDeleteConfirm}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n {modal.type === 'confirmExecute' && (\n <ConfirmDialog\n isOpen={true}\n title={`Execute: ${modal.label}`}\n message={`Are you sure you want to execute this action?\\n\\n${modal.detail}`}\n confirmLabel=\"Execute\"\n variant=\"warning\"\n onConfirm={handleConfirmExecute}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n <ConfirmDialog\n isOpen={bulkDeckAction === 'delete'}\n title=\"Delete Vibe Decks\"\n message={`Are you sure you want to delete ${selectedDecks.length} selected deck${selectedDecks.length === 1 ? '' : 's'}? All buttons in those decks will also be deleted.`}\n confirmLabel=\"Delete Decks\"\n variant=\"danger\"\n onConfirm={handleBulkDeleteDecks}\n onClose={() => setBulkDeckAction(null)}\n isLoading={bulkBusy === 'deleteDeck'}\n />\n\n <ConfirmDialog\n isOpen={bulkButtonAction === 'execute'}\n title=\"Execute Vibe Deck Buttons\"\n message={`Execute ${selectedButtons.length} selected button${selectedButtons.length === 1 ? '' : 's'}? This may trigger commands, scripts, or webhooks immediately.`}\n confirmLabel=\"Execute Buttons\"\n variant=\"warning\"\n onConfirm={handleBulkExecuteButtons}\n onClose={() => setBulkButtonAction(null)}\n isLoading={bulkBusy === 'executeButton'}\n />\n\n <ConfirmDialog\n isOpen={bulkButtonAction === 'delete'}\n title=\"Delete Vibe Deck Buttons\"\n message={`Delete ${selectedButtons.length} selected button${selectedButtons.length === 1 ? '' : 's'}? This cannot be undone.`}\n confirmLabel=\"Delete Buttons\"\n variant=\"danger\"\n onConfirm={handleBulkDeleteButtons}\n onClose={() => setBulkButtonAction(null)}\n isLoading={bulkBusy === 'deleteButton'}\n />\n\n {modal.type === 'shareDeck' && (\n <VibeDeckShareDialog\n vibeDeckId={modal.deckId}\n vibeDeckName={modal.deckName}\n onClose={() => setModal({ type: 'none' })}\n />\n )}\n\n <QuotaExhaustedDialog\n isOpen={quotaDialog !== null}\n onClose={() => setQuotaDialog(null)}\n onConfirm={() => {\n setQuotaDialog(null);\n navigate('/billing/plans');\n }}\n title={quotaDialog?.title || 'Quota Reached'}\n message={quotaDialog?.message || 'Upgrade your plan to continue.'}\n />\n\n <EnableRemoteTaskDialog\n isOpen={remoteTaskPrompt !== null}\n agentName={\n remoteTaskPrompt\n ? agents.find((a: { id: string; name: string }) => a.id === remoteTaskPrompt.agentId)\n ?.name\n : undefined\n }\n isLoading={enablingRemoteTask}\n onClose={() => setRemoteTaskPrompt(null)}\n onConfirm={handleEnableRemoteTaskConfirm}\n />\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/dist/utils/shareUrl.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
//#region src/utils/shareUrl.ts
|
|
2
|
-
function e(e) {
|
|
3
|
-
if (typeof window > "u") return e;
|
|
4
|
-
try {
|
|
5
|
-
let t = new URL(e, window.location.origin);
|
|
6
|
-
if ((t.protocol === "http:" || t.protocol === "https:") && t.pathname.startsWith("/vibecontrols/")) return `${window.location.origin}${t.pathname}${t.search}${t.hash}`;
|
|
7
|
-
} catch {
|
|
8
|
-
return e;
|
|
9
|
-
}
|
|
10
|
-
return e;
|
|
11
|
-
}
|
|
12
|
-
function t(t) {
|
|
13
|
-
let n = e(t);
|
|
14
|
-
try {
|
|
15
|
-
let e = typeof window > "u" ? new URL(n) : new URL(n, window.location.origin);
|
|
16
|
-
return e.protocol !== "http:" && e.protocol !== "https:" ? n : (e.searchParams.set("embed", "true"), e.toString());
|
|
17
|
-
} catch {
|
|
18
|
-
let e = n.indexOf("#"), t = e >= 0 ? n.slice(0, e) : n, r = e >= 0 ? n.slice(e) : "";
|
|
19
|
-
return `${t}${t.includes("?") ? "&" : "?"}embed=true${r}`;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function n(e) {
|
|
23
|
-
return e.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
24
|
-
}
|
|
25
|
-
async function r(e) {
|
|
26
|
-
try {
|
|
27
|
-
await navigator.clipboard.writeText(e);
|
|
28
|
-
} catch {
|
|
29
|
-
let t = document.createElement("textarea");
|
|
30
|
-
t.value = e, t.style.position = "fixed", t.style.opacity = "0", document.body.appendChild(t);
|
|
31
|
-
try {
|
|
32
|
-
if (t.select(), !document.execCommand("copy")) throw Error("Clipboard copy failed");
|
|
33
|
-
} finally {
|
|
34
|
-
document.body.removeChild(t);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
export { t as buildEmbedUrl, r as copyTextToClipboard, n as escapeHtmlAttribute, e as normalizeShareUrl };
|
|
40
|
-
|
|
41
|
-
//# sourceMappingURL=shareUrl.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shareUrl.js","names":[],"sources":["../../src/utils/shareUrl.ts"],"sourcesContent":["export function normalizeShareUrl(url: string): string {\n if (typeof window === 'undefined') return url;\n try {\n const parsed = new URL(url, window.location.origin);\n if (\n (parsed.protocol === 'http:' || parsed.protocol === 'https:') &&\n parsed.pathname.startsWith('/vibecontrols/')\n ) {\n return `${window.location.origin}${parsed.pathname}${parsed.search}${parsed.hash}`;\n }\n } catch {\n return url;\n }\n return url;\n}\n\nexport function buildEmbedUrl(url: string): string {\n const normalized = normalizeShareUrl(url);\n try {\n const parsed =\n typeof window === 'undefined'\n ? new URL(normalized)\n : new URL(normalized, window.location.origin);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return normalized;\n }\n parsed.searchParams.set('embed', 'true');\n return parsed.toString();\n } catch {\n const hashIndex = normalized.indexOf('#');\n const base = hashIndex >= 0 ? normalized.slice(0, hashIndex) : normalized;\n const hash = hashIndex >= 0 ? normalized.slice(hashIndex) : '';\n const separator = base.includes('?') ? '&' : '?';\n return `${base}${separator}embed=true${hash}`;\n }\n}\n\nexport function escapeHtmlAttribute(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nexport async function copyTextToClipboard(text: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n document.body.appendChild(textarea);\n try {\n textarea.select();\n if (!document.execCommand('copy')) {\n throw new Error('Clipboard copy failed');\n }\n } finally {\n document.body.removeChild(textarea);\n }\n }\n}\n"],"mappings":";AAAA,SAAgB,EAAkB,GAAqB;AACrD,KAAI,OAAO,SAAW,IAAa,QAAO;AAC1C,KAAI;EACF,IAAM,IAAS,IAAI,IAAI,GAAK,OAAO,SAAS,OAAO;AACnD,OACG,EAAO,aAAa,WAAW,EAAO,aAAa,aACpD,EAAO,SAAS,WAAW,iBAAiB,CAE5C,QAAO,GAAG,OAAO,SAAS,SAAS,EAAO,WAAW,EAAO,SAAS,EAAO;SAExE;AACN,SAAO;;AAET,QAAO;;AAGT,SAAgB,EAAc,GAAqB;CACjD,IAAM,IAAa,EAAkB,EAAI;AACzC,KAAI;EACF,IAAM,IACJ,OAAO,SAAW,MACd,IAAI,IAAI,EAAW,GACnB,IAAI,IAAI,GAAY,OAAO,SAAS,OAAO;AAKjD,SAJI,EAAO,aAAa,WAAW,EAAO,aAAa,WAC9C,KAET,EAAO,aAAa,IAAI,SAAS,OAAO,EACjC,EAAO,UAAU;SAClB;EACN,IAAM,IAAY,EAAW,QAAQ,IAAI,EACnC,IAAO,KAAa,IAAI,EAAW,MAAM,GAAG,EAAU,GAAG,GACzD,IAAO,KAAa,IAAI,EAAW,MAAM,EAAU,GAAG;AAE5D,SAAO,GAAG,IADQ,EAAK,SAAS,IAAI,GAAG,MAAM,IAClB,YAAY;;;AAI3C,SAAgB,EAAoB,GAAuB;AACzD,QAAO,EACJ,QAAQ,MAAM,QAAQ,CACtB,QAAQ,MAAM,SAAS,CACvB,QAAQ,MAAM,QAAQ,CACtB,QAAQ,MAAM,OAAO,CACrB,QAAQ,MAAM,OAAO;;AAG1B,eAAsB,EAAoB,GAA6B;AACrE,KAAI;AACF,QAAM,UAAU,UAAU,UAAU,EAAK;SACnC;EACN,IAAM,IAAW,SAAS,cAAc,WAAW;AAInD,EAHA,EAAS,QAAQ,GACjB,EAAS,MAAM,WAAW,SAC1B,EAAS,MAAM,UAAU,KACzB,SAAS,KAAK,YAAY,EAAS;AACnC,MAAI;AAEF,OADA,EAAS,QAAQ,EACb,CAAC,SAAS,YAAY,OAAO,CAC/B,OAAU,MAAM,wBAAwB;YAElC;AACR,YAAS,KAAK,YAAY,EAAS"}
|