@burdenoff/microfe-vibecontrols 2026.623.1 → 2026.623.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/actions/ActionCard.js +2 -2
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/actions/ActionTypeBadge.js +1 -1
- package/dist/components/actions/ActionTypeBadge.js.map +1 -1
- package/dist/components/actions/ExecutionHistory.js +1 -1
- package/dist/components/actions/ExecutionHistory.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerChatPane.js +2 -2
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js +4 -4
- package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerLayout.js +1 -1
- package/dist/components/agent-manager/AgentManagerLayout.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerSidebar.js +5 -5
- package/dist/components/agent-manager/AgentManagerSidebar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerTab.js +1 -1
- package/dist/components/agent-manager/AgentManagerTab.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerTabBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerTabBar.js.map +1 -1
- package/dist/components/agent-manager/BridleConfigPanel.js +24 -24
- package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/PluginInstallModal.js +1 -1
- package/dist/components/agent-manager/PluginInstallModal.js.map +1 -1
- package/dist/components/agent-manager/ProfilesPanel.js +5 -5
- package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionConfigPanel.js +6 -6
- package/dist/components/agent-manager/detail/SessionConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionLogsPanel.js +5 -5
- package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionToolsPanel.js +1 -1
- package/dist/components/agent-manager/detail/SessionToolsPanel.js.map +1 -1
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js +2 -2
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
- package/dist/components/agent-manager/dialogs/RenameSessionDialog.js +1 -1
- package/dist/components/agent-manager/dialogs/RenameSessionDialog.js.map +1 -1
- package/dist/components/agents/AgentCard.js +14 -11
- package/dist/components/agents/AgentCard.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +1 -1
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AIOverviewTab.js +4 -4
- package/dist/components/ai/AIOverviewTab.js.map +1 -1
- package/dist/components/ai/AIPlanPanel.js +4 -4
- package/dist/components/ai/AIPlanPanel.js.map +1 -1
- package/dist/components/ai/AIPlaygroundTab.js +1 -1
- package/dist/components/ai/AIPlaygroundTab.js.map +1 -1
- package/dist/components/ai/AIPromptsTab.js +2 -2
- package/dist/components/ai/AIPromptsTab.js.map +1 -1
- package/dist/components/ai/AIProviderCredentialsCard.js +4 -4
- package/dist/components/ai/AIProviderCredentialsCard.js.map +1 -1
- package/dist/components/ai/AIQueueTab.js +4 -4
- package/dist/components/ai/AIQueueTab.js.map +1 -1
- package/dist/components/ai/AISessionsTab.js +4 -4
- package/dist/components/ai/AISessionsTab.js.map +1 -1
- package/dist/components/ai/AITasksTab.js +1 -1
- package/dist/components/ai/AITasksTab.js.map +1 -1
- package/dist/components/ai/ClaudeCredentialsCard.js +3 -3
- package/dist/components/ai/ClaudeCredentialsCard.js.map +1 -1
- package/dist/components/ai/PluginHarnessPicker.js +3 -3
- package/dist/components/ai/PluginHarnessPicker.js.map +1 -1
- package/dist/components/analytics/AnalyticsBreakdownChart.js +8 -8
- package/dist/components/analytics/AnalyticsBreakdownChart.js.map +1 -1
- package/dist/components/analytics/AnalyticsTimeSeriesChart.js +5 -5
- package/dist/components/analytics/AnalyticsTimeSeriesChart.js.map +1 -1
- package/dist/components/audit/AuditDeleteDialog.js +2 -2
- package/dist/components/audit/AuditDeleteDialog.js.map +1 -1
- package/dist/components/audit/AuditExportButton.js +5 -5
- package/dist/components/audit/AuditExportButton.js.map +1 -1
- package/dist/components/audit/AuditLogDetail.js +9 -9
- package/dist/components/audit/AuditLogDetail.js.map +1 -1
- package/dist/components/audit/AuditLogFilters.js +1 -1
- package/dist/components/audit/AuditLogFilters.js.map +1 -1
- package/dist/components/audit/AuditLogStats.js +1 -1
- package/dist/components/audit/AuditLogStats.js.map +1 -1
- package/dist/components/audit/AuditLogTable.js +28 -28
- package/dist/components/audit/AuditLogTable.js.map +1 -1
- package/dist/components/catalog/CatalogCard.js +3 -3
- package/dist/components/catalog/CatalogCard.js.map +1 -1
- package/dist/components/catalog/CatalogForm.js +1 -1
- package/dist/components/catalog/CatalogForm.js.map +1 -1
- package/dist/components/common/ActionAgentTargetNotice.js +6 -6
- package/dist/components/common/ActionAgentTargetNotice.js.map +1 -1
- package/dist/components/common/CommandEditor.js +1 -1
- package/dist/components/common/CommandEditor.js.map +1 -1
- package/dist/components/docs/DocsPageTree.js +1 -1
- package/dist/components/docs/DocsPageTree.js.map +1 -1
- package/dist/components/docs/DocsPreviewPanel.js +1 -1
- package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
- package/dist/components/docs/DocsRevisionHistory.js +4 -4
- package/dist/components/docs/DocsRevisionHistory.js.map +1 -1
- package/dist/components/docs/DocsSettingsPanel.js +7 -7
- package/dist/components/docs/DocsSettingsPanel.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +1 -1
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
- package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
- package/dist/components/graph/MeshDeployWizard.js +3 -3
- package/dist/components/graph/MeshDeployWizard.js.map +1 -1
- package/dist/components/graph/MeshRequestPanel.js +2 -2
- package/dist/components/graph/MeshRequestPanel.js.map +1 -1
- package/dist/components/idp-components/ComponentCard.js +5 -5
- package/dist/components/idp-components/ComponentCard.js.map +1 -1
- package/dist/components/idp-components/ComponentForm.js +1 -1
- package/dist/components/idp-components/ComponentForm.js.map +1 -1
- package/dist/components/idp-components/DependencyGraphTab.js +7 -7
- package/dist/components/idp-components/DependencyGraphTab.js.map +1 -1
- package/dist/components/logs/LogViewer.js +14 -14
- package/dist/components/logs/LogViewer.js.map +1 -1
- package/dist/components/notes/NoteCard.js +1 -1
- package/dist/components/notes/NoteCard.js.map +1 -1
- package/dist/components/notes/NoteEditor.js +2 -2
- package/dist/components/notes/NoteEditor.js.map +1 -1
- package/dist/components/notes/NoteList.js +1 -1
- package/dist/components/notes/NoteList.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +1 -1
- package/dist/components/notes/NotesTabPanel.js.map +1 -1
- package/dist/components/scorecard/ScorecardEmptyState.js +1 -1
- package/dist/components/scorecard/ScorecardEmptyState.js.map +1 -1
- package/dist/components/scorecard/ScorecardPanel.js +3 -3
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/security/SecurityScanList.js +11 -11
- package/dist/components/security/SecurityScanList.js.map +1 -1
- package/dist/components/sessions/SessionCard.js +26 -19
- package/dist/components/sessions/SessionCard.js.map +1 -1
- package/dist/components/sessions/SessionStatusBadge.js +7 -7
- package/dist/components/sessions/SessionStatusBadge.js.map +1 -1
- package/dist/components/shared/AgentSelector.js +4 -4
- package/dist/components/shared/AgentSelector.js.map +1 -1
- package/dist/components/shared/AgentSetupBanner.js +4 -4
- package/dist/components/shared/AgentSetupBanner.js.map +1 -1
- package/dist/components/shared/Card.js +4 -4
- package/dist/components/shared/Card.js.map +1 -1
- package/dist/components/shared/ErrorState.js +15 -9
- package/dist/components/shared/ErrorState.js.map +1 -1
- package/dist/components/shared/FilterDropdown.js +2 -2
- package/dist/components/shared/FilterDropdown.js.map +1 -1
- package/dist/components/shared/PageSkeleton.js +6 -6
- package/dist/components/shared/PageSkeleton.js.map +1 -1
- package/dist/components/shared/SearchInput.js +1 -1
- package/dist/components/shared/SearchInput.js.map +1 -1
- package/dist/components/shared/StatCard.js +7 -7
- package/dist/components/shared/StatCard.js.map +1 -1
- package/dist/components/templates/PublishTemplateForm.js +2 -2
- package/dist/components/templates/PublishTemplateForm.js.map +1 -1
- package/dist/components/templates/TemplateCard.js +5 -5
- package/dist/components/templates/TemplateCard.js.map +1 -1
- package/dist/components/templates/TemplateWizard.js +2 -2
- package/dist/components/templates/TemplateWizard.js.map +1 -1
- package/dist/components/tunnels/DomainVerificationBadge.js +4 -4
- package/dist/components/tunnels/DomainVerificationBadge.js.map +1 -1
- package/dist/components/tunnels/ProviderBadge.js +1 -1
- package/dist/components/tunnels/ProviderBadge.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +16 -16
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
- package/dist/components/tunnels/TunnelStatusBadge.js +4 -4
- package/dist/components/tunnels/TunnelStatusBadge.js.map +1 -1
- package/dist/components/vibecalendar/LogsDrawer.js +2 -2
- package/dist/components/vibecalendar/LogsDrawer.js.map +1 -1
- package/dist/components/vibecalendar/ScheduleTaskModal.js +5 -5
- package/dist/components/vibecalendar/ScheduleTaskModal.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalAgendaView.js +2 -2
- package/dist/components/vibecalendar/VibeCalAgendaView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalDayView.js +3 -3
- package/dist/components/vibecalendar/VibeCalDayView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalMonthView.js +1 -1
- package/dist/components/vibecalendar/VibeCalMonthView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalWeekView.js +4 -4
- package/dist/components/vibecalendar/VibeCalWeekView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalendarHeader.js +4 -4
- package/dist/components/vibecalendar/VibeCalendarHeader.js.map +1 -1
- package/dist/components/vibecalendar/VibeTaskBlock.js +2 -2
- package/dist/components/vibecalendar/VibeTaskBlock.js.map +1 -1
- package/dist/components/vibecalendar/types.js +7 -7
- package/dist/components/vibecalendar/types.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonForm.js +9 -9
- package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonTile.js +6 -6
- package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckExecutionLog.js +10 -10
- package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckForm.js +8 -8
- package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
- package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +2 -2
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckSwitcher.js +8 -8
- package/dist/components/vibedeck/VibeDeckSwitcher.js.map +1 -1
- package/dist/components/vibes/VibeCard.js +22 -18
- package/dist/components/vibes/VibeCard.js.map +1 -1
- package/dist/components/vibes/VibeList.js +16 -12
- package/dist/components/vibes/VibeList.js.map +1 -1
- package/dist/pages/ActionsPage.js +4 -3
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js +9 -9
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsLandingPage.js +4 -4
- package/dist/pages/AgentsLandingPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +14 -14
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/AnalyticsPage.js +8 -8
- package/dist/pages/AnalyticsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +11 -11
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +12 -9
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +7 -7
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +12 -9
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/EnvTopologyPage.js +2 -2
- package/dist/pages/EnvTopologyPage.js.map +1 -1
- package/dist/pages/GettingStartedPage.js +12 -12
- package/dist/pages/GettingStartedPage.js.map +1 -1
- package/dist/pages/HealthPage.js +12 -12
- package/dist/pages/HealthPage.js.map +1 -1
- package/dist/pages/LogsPage.js +4 -4
- package/dist/pages/LogsPage.js.map +1 -1
- package/dist/pages/NoteDetailsPage.js +5 -5
- package/dist/pages/NoteDetailsPage.js.map +1 -1
- package/dist/pages/OverviewPage.js +76 -43
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/PluginsCatalogPage.js +7 -4
- package/dist/pages/PluginsCatalogPage.js.map +1 -1
- package/dist/pages/ScheduledJobDetailPage.js +7 -7
- package/dist/pages/ScheduledJobDetailPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +21 -21
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +20 -20
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/SettingsPage.js +64 -52
- package/dist/pages/SettingsPage.js.map +1 -1
- package/dist/pages/SharedSessionPage.js +21 -21
- package/dist/pages/SharedSessionPage.js.map +1 -1
- package/dist/pages/SharedVibeDeckPage.js +5 -5
- package/dist/pages/SharedVibeDeckPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +56 -65
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +4 -4
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +10 -10
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +6 -5
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeAuditPage.js +3 -3
- package/dist/pages/VibeAuditPage.js.map +1 -1
- package/dist/pages/VibeCalendarPage.js +3 -3
- package/dist/pages/VibeCalendarPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +3 -3
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +15 -15
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibeTaskDetailPage.js +5 -5
- package/dist/pages/VibeTaskDetailPage.js.map +1 -1
- package/dist/pages/VibesPage.js +18 -18
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/WebhooksPage.js +11 -11
- package/dist/pages/WebhooksPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +1 -1
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +6 -6
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/dist/pages/tunnels/AuditTab.js +1 -1
- package/dist/pages/tunnels/AuditTab.js.map +1 -1
- package/dist/pages/tunnels/DomainsTab.js +1 -1
- package/dist/pages/tunnels/DomainsTab.js.map +1 -1
- package/dist/pages/tunnels/ProvidersTab.js +1 -1
- package/dist/pages/tunnels/ProvidersTab.js.map +1 -1
- package/dist/pages/tunnels/SessionsTab.js +1 -1
- package/dist/pages/tunnels/SessionsTab.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +3 -3
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/UsageTab.js +1 -1
- package/dist/pages/tunnels/UsageTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +16 -16
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +52 -49
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +9 -9
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerInputArea.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerInputArea.tsx"],"sourcesContent":["/**\n * Rich input area for the Agent Manager chat.\n *\n * Sits at the bottom of the chat pane. Contains a toolbar row with\n * control selectors and a resizable textarea with send/cancel buttons.\n * Supports file attachment preview, keyboard shortcuts, and slash\n * commands for quick actions.\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo, type KeyboardEvent } from 'react';\nimport {\n ArrowUp,\n Square,\n X,\n ChevronDown,\n Clock,\n FolderOpen,\n FileText,\n Sparkles,\n} from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useVoiceMode } from '@/hooks/useVoiceMode';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchProviders, type AIProvider } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { schedulePrompt } from '@/services/schedulerApi';\nimport { ModelSelector } from './controls/ModelSelector';\nimport { SdkSelector } from './controls/SdkSelector';\nimport { AutonomySelector } from './controls/AutonomySelector';\nimport { McpServerSelector } from './controls/McpServerSelector';\nimport { VoiceToggle } from './controls/VoiceToggle';\nimport { FileAttachButton } from './controls/FileAttachButton';\nimport { createDropHandlers } from './controls/createDropHandlers';\nimport { ContextLevelToggle } from './controls/ContextLevelToggle';\nimport { ChatInsertPicker } from './ChatInsertPicker';\nimport { FilePickerModal } from './FilePickerModal';\nimport { GENERIC_MODEL_FALLBACK, resolveProviderDefaultModel } from './modelDefaults';\nimport type { AgentSdkType, McpServer, ProviderMode } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Slash commands */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface SlashCommand {\n command: string;\n description: string;\n args?: string;\n}\n\nconst SLASH_COMMANDS: SlashCommand[] = [\n { command: '/new', description: 'Create new session' },\n { command: '/rename', description: 'Rename current session', args: '<name>' },\n { command: '/model', description: 'Switch model', args: '<model-name>' },\n {\n command: '/sdk',\n description: 'Switch SDK',\n args: '<claude|codex|gemini|opencode|openai-compat>',\n },\n { command: '/mode', description: 'Switch mode', args: '<sdk|cli>' },\n { command: '/export', description: 'Export conversation', args: '[json|md]' },\n { command: '/clear', description: 'Clear conversation' },\n { command: '/help', description: 'Show available commands' },\n];\n\nconst VALID_SDKS: AgentSdkType[] = [\n 'claude',\n 'codex',\n 'gemini',\n 'opencode',\n 'cursor',\n 'openrouter',\n 'minimax',\n 'ollama',\n 'openai-compat',\n 'goose',\n 'amp',\n 'copilot',\n 'crush',\n 'pi',\n 'aider',\n 'plandex',\n];\nconst VALID_MODES: ProviderMode[] = ['sdk', 'cli'];\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Component */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface AgentManagerInputAreaProps {\n agentId: string;\n sessionId: string;\n onSend: (text: string, attachments?: File[]) => void;\n onCancel?: () => void;\n mcpServers?: McpServer[];\n agentTunnelUrl?: string;\n}\n\nexport function AgentManagerInputArea({\n agentId,\n sessionId,\n onSend,\n onCancel,\n mcpServers = [],\n agentTunnelUrl,\n}: AgentManagerInputAreaProps) {\n const [text, setText] = useState('');\n const [pendingFiles, setPendingFiles] = useState<File[]>([]);\n const [showSlashMenu, setShowSlashMenu] = useState(false);\n const [slashFilter, setSlashFilter] = useState('');\n const [showScheduleMenu, setShowScheduleMenu] = useState(false);\n const [showSchedulePopup, setShowSchedulePopup] = useState(false);\n const [scheduleDateTime, setScheduleDateTime] = useState('');\n const [providers, setProviders] = useState<AIProvider[]>([]);\n const [filePickerOpen, setFilePickerOpen] = useState(false);\n const tr = useTr();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const scheduleMenuRef = useRef<HTMLDivElement>(null);\n\n // Auto-focus textarea when session is opened or switched\n useEffect(() => {\n textareaRef.current?.focus({ preventScroll: true });\n }, []);\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const setSessionModel = useAgentManagerStore((s) => s.setSessionModel);\n const setSessionSdk = useAgentManagerStore((s) => s.setSessionSdk);\n const setSessionMode = useAgentManagerStore((s) => s.setSessionMode);\n const setSessionPermissionMode = useAgentManagerStore((s) => s.setSessionPermissionMode);\n const toggleVoice = useAgentManagerStore((s) => s.toggleVoice);\n const toggleThinking = useAgentManagerStore((s) => s.toggleThinking);\n const setSessionContextLevel = useAgentManagerStore((s) => s.setSessionContextLevel);\n const setSessionVibe = useAgentManagerStore((s) => s.setSessionVibe);\n const setSessionRootPath = useAgentManagerStore((s) => s.setSessionRootPath);\n const openSession = useAgentManagerStore((s) => s.openSession);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n const removeSessionContext = useAgentManagerStore((s) => s.removeSessionContext);\n const addSessionContext = useAgentManagerStore((s) => s.addSessionContext);\n const pendingChatInsert = useAgentManagerStore((s) => s.pendingChatInsert);\n const setPendingChatInsert = useAgentManagerStore((s) => s.setPendingChatInsert);\n\n // Consume a pending \"insert into chat\" request set by a \"Use in chat\" action\n // elsewhere (ai-tools tabs, vibe panels): append its text to the composer and\n // attach its contexts to this session, then clear it so it fires once.\n useEffect(() => {\n if (!pendingChatInsert) return;\n if (pendingChatInsert.text) {\n const insertText = pendingChatInsert.text;\n setText((prev) => (prev ? `${prev}\\n${insertText}` : insertText));\n }\n for (const ctx of pendingChatInsert.contexts ?? []) {\n addSessionContext(sessionId, ctx);\n }\n setPendingChatInsert(null);\n textareaRef.current?.focus({ preventScroll: true });\n }, [pendingChatInsert, sessionId, addSessionContext, setPendingChatInsert]);\n\n const { vibes, agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { isListening, transcript, startListening, stopListening } = useVoiceMode();\n\n const isStreaming = sessionState?.status === 'streaming';\n const canSend = text.trim().length > 0 && !isStreaming;\n\n // Append voice transcript to textarea\n useEffect(() => {\n if (transcript && isListening) {\n setText((prev) => prev + (prev ? ' ' : '') + transcript);\n }\n }, [transcript, isListening]);\n\n useEffect(() => {\n let cancelled = false;\n void fetchProviders(agentRef)\n .then((items) => {\n if (!cancelled) setProviders(items);\n })\n .catch(() => {\n if (!cancelled) setProviders([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agentRef]);\n\n // ── Slash command filtering ──\n useEffect(() => {\n if (text.startsWith('/') && !text.includes(' ')) {\n setShowSlashMenu(true);\n setSlashFilter(text.slice(1));\n } else {\n setShowSlashMenu(false);\n }\n }, [text]);\n\n const filteredCommands = useMemo(\n () =>\n SLASH_COMMANDS.filter((cmd) =>\n cmd.command.toLowerCase().includes(`/${slashFilter.toLowerCase()}`)\n ),\n [slashFilter]\n );\n\n // Auto-resize textarea\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = 'auto';\n const maxRows = 10;\n const lineHeight = 20;\n const maxHeight = maxRows * lineHeight;\n el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;\n }, [text]);\n\n // Close schedule menu on outside click\n useEffect(() => {\n if (!showScheduleMenu && !showSchedulePopup) return;\n const handler = (e: MouseEvent) => {\n if (scheduleMenuRef.current && !scheduleMenuRef.current.contains(e.target as Node)) {\n setShowScheduleMenu(false);\n setShowSchedulePopup(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [showScheduleMenu, showSchedulePopup]);\n\n const addSystemMessage = useCallback(\n (content: string) => {\n addMessage(sessionId, {\n id: `sys-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n role: 'system',\n content,\n timestamp: new Date().toISOString(),\n });\n },\n [addMessage, sessionId]\n );\n\n const handleScheduleSend = useCallback(async () => {\n if (!text.trim() || !scheduleDateTime || !agentId) return;\n try {\n const result = await schedulePrompt({\n sessionId,\n agentRef: { agentId, profile: activeProfile ?? 'default' },\n prompt: text.trim(),\n scheduledAt: new Date(scheduleDateTime).toISOString(),\n });\n addSystemMessage(\n `Prompt scheduled for ${new Date(result.scheduledAt).toLocaleString()} (Job: ${result.jobId.slice(0, 8)})`\n );\n setText('');\n setScheduleDateTime('');\n setShowSchedulePopup(false);\n setShowScheduleMenu(false);\n } catch (err) {\n addSystemMessage(\n `Failed to schedule: ${err instanceof Error ? err.message : 'Unknown error'}`\n );\n }\n }, [text, scheduleDateTime, sessionId, agentId, activeProfile, addSystemMessage]);\n\n const executeSlashCommand = useCallback(\n (input: string) => {\n const parts = input.trim().split(/\\s+/);\n const cmd = parts[0].toLowerCase();\n const arg = parts.slice(1).join(' ');\n\n switch (cmd) {\n case '/new': {\n const newId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n openSession(newId);\n break;\n }\n case '/rename':\n if (arg) {\n addSystemMessage(`Session renamed to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /rename <name>');\n }\n break;\n case '/model':\n if (arg) {\n setSessionModel(sessionId, arg);\n addSystemMessage(`Model switched to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /model <model-name>');\n }\n break;\n case '/sdk':\n if (arg && VALID_SDKS.includes(arg as AgentSdkType)) {\n const nextSdk = arg as AgentSdkType;\n setSessionSdk(sessionId, nextSdk);\n void resolveProviderDefaultModel(\n agentRef,\n nextSdk,\n sessionState?.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState?.model ?? GENERIC_MODEL_FALLBACK)\n );\n addSystemMessage(`SDK switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /sdk <${VALID_SDKS.join('|')}>`);\n }\n break;\n case '/mode':\n if (arg && VALID_MODES.includes(arg as ProviderMode)) {\n setSessionMode(sessionId, arg as ProviderMode);\n addSystemMessage(`Mode switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /mode <${VALID_MODES.join('|')}>`);\n }\n break;\n case '/export': {\n const format = arg === 'md' ? 'md' : 'json';\n const messages = sessionState?.messages ?? [];\n const exported =\n format === 'json'\n ? JSON.stringify(messages, null, 2)\n : messages\n .map((m) => `**${m.role}** (${m.timestamp ?? ''}):\\n${m.content ?? ''}`)\n .join('\\n\\n---\\n\\n');\n const blob = new Blob([exported], {\n type: format === 'json' ? 'application/json' : 'text/markdown',\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `conversation-${sessionId}.${format}`;\n a.click();\n URL.revokeObjectURL(url);\n addSystemMessage(`Conversation exported as ${format}.`);\n break;\n }\n case '/clear':\n addSystemMessage('Conversation cleared.');\n break;\n case '/help': {\n const helpText = SLASH_COMMANDS.map(\n (c) => ` ${c.command}${c.args ? ' ' + c.args : ''} - ${c.description}`\n ).join('\\n');\n addSystemMessage(`Available commands:\\n${helpText}`);\n break;\n }\n default:\n addSystemMessage(`Unknown command: ${cmd}. Type /help for available commands.`);\n }\n },\n [\n sessionId,\n sessionState?.messages,\n sessionState?.model,\n openSession,\n setSessionModel,\n setSessionSdk,\n setSessionMode,\n addSystemMessage,\n agentRef,\n ]\n );\n\n const handleSlashSelect = useCallback(\n (cmd: SlashCommand) => {\n // If command takes args, fill the text and let user type args\n if (cmd.args) {\n setText(`${cmd.command} `);\n } else {\n executeSlashCommand(cmd.command);\n setText('');\n }\n setShowSlashMenu(false);\n textareaRef.current?.focus();\n },\n [executeSlashCommand]\n );\n\n const handleSend = useCallback(() => {\n if (!canSend) return;\n\n const trimmed = text.trim();\n\n // Handle slash commands locally\n if (trimmed.startsWith('/')) {\n executeSlashCommand(trimmed);\n setText('');\n setPendingFiles([]);\n return;\n }\n\n onSend(trimmed, pendingFiles.length > 0 ? pendingFiles : undefined);\n setText('');\n setPendingFiles([]);\n }, [canSend, text, pendingFiles, onSend, executeSlashCommand]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n // Enter sends, Shift+Enter inserts newline\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend]\n );\n\n const handleCancel = useCallback(() => {\n onCancel?.();\n }, [onCancel]);\n\n const handleFileSelect = useCallback((files: File[]) => {\n setPendingFiles((prev) => [...prev, ...files]);\n }, []);\n\n const removeFile = useCallback((index: number) => {\n setPendingFiles((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const dropHandlers = createDropHandlers(handleFileSelect);\n\n if (!sessionState) return null;\n\n return (\n <div className=\"relative z-30 border-t border-border-default bg-bg-surface\" {...dropHandlers}>\n {/* Slash command popup */}\n {showSlashMenu && filteredCommands.length > 0 && (\n <div className=\"absolute bottom-full left-0 right-0 mb-1 mx-3 bg-bg-elevated border border-border-default rounded-lg shadow-lg max-h-48 overflow-y-auto z-50\">\n {filteredCommands.map((cmd) => (\n <button\n key={cmd.command}\n type=\"button\"\n onClick={() => handleSlashSelect(cmd)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left hover:bg-bg-sunken transition-colors\"\n >\n <span className=\"font-mono text-xs text-text-primary\">{cmd.command}</span>\n {cmd.args && <span className=\"text-text-tertiary text-xs\">{cmd.args}</span>}\n <span className=\"text-text-secondary text-xs ml-auto\">{cmd.description}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Attached context chips (backend prompts/contexts + Files-module files\n materialised on the agent). Sent to the agent as contexts[] on send. */}\n {(sessionState?.contexts?.length ?? 0) > 0 && (\n <div\n className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\"\n data-testid=\"chat-context-chips\"\n >\n {sessionState?.contexts.map((ctx) => (\n <div\n key={ctx.id}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n title={ctx.path ?? ctx.label}\n >\n {ctx.kind === 'file' ? (\n <FolderOpen className=\"size-3 flex-shrink-0\" />\n ) : ctx.kind === 'prompt' ? (\n <Sparkles className=\"size-3 flex-shrink-0\" />\n ) : (\n <FileText className=\"size-3 flex-shrink-0\" />\n )}\n <span className=\"truncate max-w-[140px]\">{ctx.label}</span>\n <button\n type=\"button\"\n onClick={() => removeSessionContext(sessionId, ctx.id)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label=\"Remove context\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* File attachment preview row */}\n {pendingFiles.length > 0 && (\n <div className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\">\n {pendingFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n >\n <span className=\"truncate max-w-[120px]\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(index)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Toolbar row */}\n <div className=\"flex flex-wrap items-center gap-1 px-3 pt-2 pb-1 overflow-x-auto\">\n <SdkSelector\n sdk={sessionState.sdk}\n mode={sessionState.mode}\n providers={providers}\n onSdkChange={(sdk) => {\n setSessionSdk(sessionId, sdk);\n void resolveProviderDefaultModel(\n agentRef,\n sdk,\n sessionState.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState.model ?? GENERIC_MODEL_FALLBACK)\n );\n }}\n onModeChange={(mode) => setSessionMode(sessionId, mode)}\n />\n <ModelSelector\n value={sessionState.model}\n onChange={(model) => setSessionModel(sessionId, model)}\n provider={sessionState.sdk}\n agentId={agentId}\n />\n <AutonomySelector\n value={sessionState.permissionMode}\n mode={sessionState.mode}\n onChange={(permissionMode) => setSessionPermissionMode(sessionId, permissionMode)}\n />\n <McpServerSelector\n selected={sessionState.mcpServers}\n available={mcpServers}\n onChange={() => {\n // Update via store -- MCP servers are part of session state\n // For now we store them directly\n }}\n />\n <ContextLevelToggle\n agentId=\"\"\n sessionId={sessionId}\n contextLevel={sessionState.contextLevel}\n rootPath={sessionState.rootPath}\n onChange={(level, rootPath, vibeId) => {\n setSessionContextLevel(sessionId, level);\n setSessionRootPath(sessionId, rootPath ?? null);\n setSessionVibe(sessionId, vibeId ?? null, rootPath ?? null);\n }}\n vibes={vibes.map((v) => ({ id: v.id, name: v.name, path: v.path }))}\n />\n\n <div className=\"flex-1\" />\n\n {/* Show Thinking toggle */}\n <button\n type=\"button\"\n onClick={() => toggleThinking(sessionId)}\n className={`p-1.5 rounded text-xs font-medium transition-colors ${\n sessionState.showThinking\n ? 'bg-action-primary-bg/10 text-action-primary-text'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n sessionState.showThinking\n ? tr('vibecontrols.agentManager.inputArea.hideThinking', 'Hide thinking')\n : tr('vibecontrols.agentManager.inputArea.showThinking', 'Show thinking')\n }\n >\n Think\n </button>\n {/* Context history limit */}\n <button\n type=\"button\"\n onClick={() => {\n const val = window.prompt(\n 'Context history limit (messages sent with each prompt):',\n String(sessionState.contextHistoryLimit)\n );\n if (val !== null) {\n const num = parseInt(val, 10);\n if (!isNaN(num) && num >= 0) {\n const store = useAgentManagerStore.getState();\n const s = store.sessionStates[sessionId];\n if (s) {\n useAgentManagerStore.setState((prev) => ({\n sessionStates: {\n ...prev.sessionStates,\n [sessionId]: { ...s, contextHistoryLimit: num },\n },\n }));\n }\n }\n }\n }}\n className=\"p-1.5 rounded text-[10px] font-mono text-text-tertiary hover:text-text-secondary transition-colors\"\n title={`Context history: last ${sessionState.contextHistoryLimit} messages sent with each prompt`}\n >\n H:{sessionState.contextHistoryLimit}\n </button>\n <VoiceToggle\n enabled={sessionState.voiceEnabled}\n onToggle={() => {\n toggleVoice(sessionId);\n if (!sessionState.voiceEnabled) startListening();\n else stopListening();\n }}\n isListening={isListening}\n />\n <FileAttachButton onFileSelect={handleFileSelect} />\n\n {/* Insert a backend prompt (rendered) into the composer, or attach a\n shared AiContext to the session. */}\n <ChatInsertPicker\n sessionId={sessionId}\n vibeId={sessionState?.vibeId}\n onInsertText={(t) => setText((prev) => (prev ? `${prev}\\n${t}` : t))}\n />\n\n {/* Attach a Files-module file: the agent fetches + materialises it on\n the server and its path becomes conversation context. */}\n <button\n type=\"button\"\n onClick={() => setFilePickerOpen(true)}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs text-text-secondary hover:bg-bg-sunken transition-colors\"\n title=\"Add a file from the Files module as context\"\n data-testid=\"chat-add-from-files\"\n >\n <FolderOpen className=\"size-4\" />\n <span className=\"hidden sm:inline\">Files</span>\n </button>\n </div>\n\n {/* Textarea + send/cancel */}\n <div className=\"flex items-end gap-2 px-3 pb-3 pt-1\">\n <textarea\n aria-label=\"control\"\n ref={textareaRef}\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={tr(\n 'vibecontrols.agentManager.inputArea.placeholder',\n 'Type a message or / for commands... (Enter to send)'\n )}\n rows={1}\n className=\"flex-1 resize-none rounded-lg border border-border-default bg-bg-primary px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors\"\n disabled={isStreaming}\n />\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"flex-shrink-0 p-2 rounded-lg bg-status-error-bg text-status-error-text hover:opacity-90 transition-opacity\"\n title={tr('vibecontrols.agentManager.inputArea.cancel', 'Cancel')}\n >\n <Square className=\"size-4\" />\n </button>\n ) : (\n <div className=\"flex items-end flex-shrink-0 relative\" ref={scheduleMenuRef}>\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"p-2 rounded-l-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.send', 'Send (Enter)')}\n >\n <ArrowUp className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowScheduleMenu(!showScheduleMenu)}\n disabled={!canSend}\n className=\"ml-1 p-2 rounded-r-lg border-l border-action-primary-text/20 bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.scheduleSend', 'Schedule send')}\n >\n <ChevronDown className=\"size-3\" />\n </button>\n\n {/* Schedule dropdown */}\n {showScheduleMenu && (\n <div className=\"absolute bottom-full right-0 mb-1 w-56 bg-bg-surface border border-border-default rounded-md shadow-lg py-1 z-50\">\n {!showSchedulePopup ? (\n <button\n type=\"button\"\n onClick={() => setShowSchedulePopup(true)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Clock className=\"size-3.5 text-text-secondary\" />\n {tr(\n 'vibecontrols.agentManager.inputArea.scheduleSendEllipsis',\n 'Schedule Send...'\n )}\n </button>\n ) : (\n <div className=\"px-3 py-2 space-y-2\">\n <label className=\"block text-[11px] font-medium text-text-secondary\">\n {tr('vibecontrols.agentManager.inputArea.sendAt', 'Send at:')}\n </label>\n <input\n aria-label=\"control\"\n type=\"datetime-local\"\n value={scheduleDateTime}\n onChange={(e) => setScheduleDateTime(e.target.value)}\n className=\"w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-primary text-text-primary focus:outline-none focus:border-border-strong\"\n />\n <button\n type=\"button\"\n onClick={() => void handleScheduleSend()}\n disabled={!scheduleDateTime || !agentId}\n className=\"w-full px-2 py-1.5 text-xs font-medium rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.agentManager.inputArea.schedule', 'Schedule')}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Files-module picker → agent materialises the file → session context. */}\n <FilePickerModal\n isOpen={filePickerOpen}\n onClose={() => setFilePickerOpen(false)}\n agent={agentRef}\n sessionId={sessionId}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentManagerInputArea.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerInputArea.tsx"],"sourcesContent":["/**\n * Rich input area for the Agent Manager chat.\n *\n * Sits at the bottom of the chat pane. Contains a toolbar row with\n * control selectors and a resizable textarea with send/cancel buttons.\n * Supports file attachment preview, keyboard shortcuts, and slash\n * commands for quick actions.\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo, type KeyboardEvent } from 'react';\nimport {\n ArrowUp,\n Square,\n X,\n ChevronDown,\n Clock,\n FolderOpen,\n FileText,\n Sparkles,\n} from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useVoiceMode } from '@/hooks/useVoiceMode';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchProviders, type AIProvider } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { schedulePrompt } from '@/services/schedulerApi';\nimport { ModelSelector } from './controls/ModelSelector';\nimport { SdkSelector } from './controls/SdkSelector';\nimport { AutonomySelector } from './controls/AutonomySelector';\nimport { McpServerSelector } from './controls/McpServerSelector';\nimport { VoiceToggle } from './controls/VoiceToggle';\nimport { FileAttachButton } from './controls/FileAttachButton';\nimport { createDropHandlers } from './controls/createDropHandlers';\nimport { ContextLevelToggle } from './controls/ContextLevelToggle';\nimport { ChatInsertPicker } from './ChatInsertPicker';\nimport { FilePickerModal } from './FilePickerModal';\nimport { GENERIC_MODEL_FALLBACK, resolveProviderDefaultModel } from './modelDefaults';\nimport type { AgentSdkType, McpServer, ProviderMode } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Slash commands */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface SlashCommand {\n command: string;\n description: string;\n args?: string;\n}\n\nconst SLASH_COMMANDS: SlashCommand[] = [\n { command: '/new', description: 'Create new session' },\n { command: '/rename', description: 'Rename current session', args: '<name>' },\n { command: '/model', description: 'Switch model', args: '<model-name>' },\n {\n command: '/sdk',\n description: 'Switch SDK',\n args: '<claude|codex|gemini|opencode|openai-compat>',\n },\n { command: '/mode', description: 'Switch mode', args: '<sdk|cli>' },\n { command: '/export', description: 'Export conversation', args: '[json|md]' },\n { command: '/clear', description: 'Clear conversation' },\n { command: '/help', description: 'Show available commands' },\n];\n\nconst VALID_SDKS: AgentSdkType[] = [\n 'claude',\n 'codex',\n 'gemini',\n 'opencode',\n 'cursor',\n 'openrouter',\n 'minimax',\n 'ollama',\n 'openai-compat',\n 'goose',\n 'amp',\n 'copilot',\n 'crush',\n 'pi',\n 'aider',\n 'plandex',\n];\nconst VALID_MODES: ProviderMode[] = ['sdk', 'cli'];\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Component */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface AgentManagerInputAreaProps {\n agentId: string;\n sessionId: string;\n onSend: (text: string, attachments?: File[]) => void;\n onCancel?: () => void;\n mcpServers?: McpServer[];\n agentTunnelUrl?: string;\n}\n\nexport function AgentManagerInputArea({\n agentId,\n sessionId,\n onSend,\n onCancel,\n mcpServers = [],\n agentTunnelUrl,\n}: AgentManagerInputAreaProps) {\n const [text, setText] = useState('');\n const [pendingFiles, setPendingFiles] = useState<File[]>([]);\n const [showSlashMenu, setShowSlashMenu] = useState(false);\n const [slashFilter, setSlashFilter] = useState('');\n const [showScheduleMenu, setShowScheduleMenu] = useState(false);\n const [showSchedulePopup, setShowSchedulePopup] = useState(false);\n const [scheduleDateTime, setScheduleDateTime] = useState('');\n const [providers, setProviders] = useState<AIProvider[]>([]);\n const [filePickerOpen, setFilePickerOpen] = useState(false);\n const tr = useTr();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const scheduleMenuRef = useRef<HTMLDivElement>(null);\n\n // Auto-focus textarea when session is opened or switched\n useEffect(() => {\n textareaRef.current?.focus({ preventScroll: true });\n }, []);\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const setSessionModel = useAgentManagerStore((s) => s.setSessionModel);\n const setSessionSdk = useAgentManagerStore((s) => s.setSessionSdk);\n const setSessionMode = useAgentManagerStore((s) => s.setSessionMode);\n const setSessionPermissionMode = useAgentManagerStore((s) => s.setSessionPermissionMode);\n const toggleVoice = useAgentManagerStore((s) => s.toggleVoice);\n const toggleThinking = useAgentManagerStore((s) => s.toggleThinking);\n const setSessionContextLevel = useAgentManagerStore((s) => s.setSessionContextLevel);\n const setSessionVibe = useAgentManagerStore((s) => s.setSessionVibe);\n const setSessionRootPath = useAgentManagerStore((s) => s.setSessionRootPath);\n const openSession = useAgentManagerStore((s) => s.openSession);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n const removeSessionContext = useAgentManagerStore((s) => s.removeSessionContext);\n const addSessionContext = useAgentManagerStore((s) => s.addSessionContext);\n const pendingChatInsert = useAgentManagerStore((s) => s.pendingChatInsert);\n const setPendingChatInsert = useAgentManagerStore((s) => s.setPendingChatInsert);\n\n // Consume a pending \"insert into chat\" request set by a \"Use in chat\" action\n // elsewhere (ai-tools tabs, vibe panels): append its text to the composer and\n // attach its contexts to this session, then clear it so it fires once.\n useEffect(() => {\n if (!pendingChatInsert) return;\n if (pendingChatInsert.text) {\n const insertText = pendingChatInsert.text;\n setText((prev) => (prev ? `${prev}\\n${insertText}` : insertText));\n }\n for (const ctx of pendingChatInsert.contexts ?? []) {\n addSessionContext(sessionId, ctx);\n }\n setPendingChatInsert(null);\n textareaRef.current?.focus({ preventScroll: true });\n }, [pendingChatInsert, sessionId, addSessionContext, setPendingChatInsert]);\n\n const { vibes, agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { isListening, transcript, startListening, stopListening } = useVoiceMode();\n\n const isStreaming = sessionState?.status === 'streaming';\n const canSend = text.trim().length > 0 && !isStreaming;\n\n // Append voice transcript to textarea\n useEffect(() => {\n if (transcript && isListening) {\n setText((prev) => prev + (prev ? ' ' : '') + transcript);\n }\n }, [transcript, isListening]);\n\n useEffect(() => {\n let cancelled = false;\n void fetchProviders(agentRef)\n .then((items) => {\n if (!cancelled) setProviders(items);\n })\n .catch(() => {\n if (!cancelled) setProviders([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agentRef]);\n\n // ── Slash command filtering ──\n useEffect(() => {\n if (text.startsWith('/') && !text.includes(' ')) {\n setShowSlashMenu(true);\n setSlashFilter(text.slice(1));\n } else {\n setShowSlashMenu(false);\n }\n }, [text]);\n\n const filteredCommands = useMemo(\n () =>\n SLASH_COMMANDS.filter((cmd) =>\n cmd.command.toLowerCase().includes(`/${slashFilter.toLowerCase()}`)\n ),\n [slashFilter]\n );\n\n // Auto-resize textarea\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = 'auto';\n const maxRows = 10;\n const lineHeight = 20;\n const maxHeight = maxRows * lineHeight;\n el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;\n }, [text]);\n\n // Close schedule menu on outside click\n useEffect(() => {\n if (!showScheduleMenu && !showSchedulePopup) return;\n const handler = (e: MouseEvent) => {\n if (scheduleMenuRef.current && !scheduleMenuRef.current.contains(e.target as Node)) {\n setShowScheduleMenu(false);\n setShowSchedulePopup(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [showScheduleMenu, showSchedulePopup]);\n\n const addSystemMessage = useCallback(\n (content: string) => {\n addMessage(sessionId, {\n id: `sys-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n role: 'system',\n content,\n timestamp: new Date().toISOString(),\n });\n },\n [addMessage, sessionId]\n );\n\n const handleScheduleSend = useCallback(async () => {\n if (!text.trim() || !scheduleDateTime || !agentId) return;\n try {\n const result = await schedulePrompt({\n sessionId,\n agentRef: { agentId, profile: activeProfile ?? 'default' },\n prompt: text.trim(),\n scheduledAt: new Date(scheduleDateTime).toISOString(),\n });\n addSystemMessage(\n `Prompt scheduled for ${new Date(result.scheduledAt).toLocaleString()} (Job: ${result.jobId.slice(0, 8)})`\n );\n setText('');\n setScheduleDateTime('');\n setShowSchedulePopup(false);\n setShowScheduleMenu(false);\n } catch (err) {\n addSystemMessage(\n `Failed to schedule: ${err instanceof Error ? err.message : 'Unknown error'}`\n );\n }\n }, [text, scheduleDateTime, sessionId, agentId, activeProfile, addSystemMessage]);\n\n const executeSlashCommand = useCallback(\n (input: string) => {\n const parts = input.trim().split(/\\s+/);\n const cmd = parts[0].toLowerCase();\n const arg = parts.slice(1).join(' ');\n\n switch (cmd) {\n case '/new': {\n const newId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n openSession(newId);\n break;\n }\n case '/rename':\n if (arg) {\n addSystemMessage(`Session renamed to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /rename <name>');\n }\n break;\n case '/model':\n if (arg) {\n setSessionModel(sessionId, arg);\n addSystemMessage(`Model switched to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /model <model-name>');\n }\n break;\n case '/sdk':\n if (arg && VALID_SDKS.includes(arg as AgentSdkType)) {\n const nextSdk = arg as AgentSdkType;\n setSessionSdk(sessionId, nextSdk);\n void resolveProviderDefaultModel(\n agentRef,\n nextSdk,\n sessionState?.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState?.model ?? GENERIC_MODEL_FALLBACK)\n );\n addSystemMessage(`SDK switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /sdk <${VALID_SDKS.join('|')}>`);\n }\n break;\n case '/mode':\n if (arg && VALID_MODES.includes(arg as ProviderMode)) {\n setSessionMode(sessionId, arg as ProviderMode);\n addSystemMessage(`Mode switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /mode <${VALID_MODES.join('|')}>`);\n }\n break;\n case '/export': {\n const format = arg === 'md' ? 'md' : 'json';\n const messages = sessionState?.messages ?? [];\n const exported =\n format === 'json'\n ? JSON.stringify(messages, null, 2)\n : messages\n .map((m) => `**${m.role}** (${m.timestamp ?? ''}):\\n${m.content ?? ''}`)\n .join('\\n\\n---\\n\\n');\n const blob = new Blob([exported], {\n type: format === 'json' ? 'application/json' : 'text/markdown',\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `conversation-${sessionId}.${format}`;\n a.click();\n URL.revokeObjectURL(url);\n addSystemMessage(`Conversation exported as ${format}.`);\n break;\n }\n case '/clear':\n addSystemMessage('Conversation cleared.');\n break;\n case '/help': {\n const helpText = SLASH_COMMANDS.map(\n (c) => ` ${c.command}${c.args ? ' ' + c.args : ''} - ${c.description}`\n ).join('\\n');\n addSystemMessage(`Available commands:\\n${helpText}`);\n break;\n }\n default:\n addSystemMessage(`Unknown command: ${cmd}. Type /help for available commands.`);\n }\n },\n [\n sessionId,\n sessionState?.messages,\n sessionState?.model,\n openSession,\n setSessionModel,\n setSessionSdk,\n setSessionMode,\n addSystemMessage,\n agentRef,\n ]\n );\n\n const handleSlashSelect = useCallback(\n (cmd: SlashCommand) => {\n // If command takes args, fill the text and let user type args\n if (cmd.args) {\n setText(`${cmd.command} `);\n } else {\n executeSlashCommand(cmd.command);\n setText('');\n }\n setShowSlashMenu(false);\n textareaRef.current?.focus();\n },\n [executeSlashCommand]\n );\n\n const handleSend = useCallback(() => {\n if (!canSend) return;\n\n const trimmed = text.trim();\n\n // Handle slash commands locally\n if (trimmed.startsWith('/')) {\n executeSlashCommand(trimmed);\n setText('');\n setPendingFiles([]);\n return;\n }\n\n onSend(trimmed, pendingFiles.length > 0 ? pendingFiles : undefined);\n setText('');\n setPendingFiles([]);\n }, [canSend, text, pendingFiles, onSend, executeSlashCommand]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n // Enter sends, Shift+Enter inserts newline\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend]\n );\n\n const handleCancel = useCallback(() => {\n onCancel?.();\n }, [onCancel]);\n\n const handleFileSelect = useCallback((files: File[]) => {\n setPendingFiles((prev) => [...prev, ...files]);\n }, []);\n\n const removeFile = useCallback((index: number) => {\n setPendingFiles((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const dropHandlers = createDropHandlers(handleFileSelect);\n\n if (!sessionState) return null;\n\n return (\n <div className=\"relative z-30 border-t border-border-default bg-bg-surface\" {...dropHandlers}>\n {/* Slash command popup */}\n {showSlashMenu && filteredCommands.length > 0 && (\n <div className=\"absolute bottom-full left-0 right-0 mb-1 mx-3 bg-bg-elevated border border-border-default rounded-lg shadow-lg max-h-48 overflow-y-auto z-50\">\n {filteredCommands.map((cmd) => (\n <button\n key={cmd.command}\n type=\"button\"\n onClick={() => handleSlashSelect(cmd)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left hover:bg-bg-sunken transition-colors\"\n >\n <span className=\"font-mono text-xs text-text-primary\">{cmd.command}</span>\n {cmd.args && <span className=\"text-text-tertiary text-xs\">{cmd.args}</span>}\n <span className=\"text-text-secondary text-xs ml-auto\">{cmd.description}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Attached context chips (backend prompts/contexts + Files-module files\n materialised on the agent). Sent to the agent as contexts[] on send. */}\n {(sessionState?.contexts?.length ?? 0) > 0 && (\n <div\n className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\"\n data-testid=\"chat-context-chips\"\n >\n {sessionState?.contexts.map((ctx) => (\n <div\n key={ctx.id}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n title={ctx.path ?? ctx.label}\n >\n {ctx.kind === 'file' ? (\n <FolderOpen className=\"size-3 flex-shrink-0\" />\n ) : ctx.kind === 'prompt' ? (\n <Sparkles className=\"size-3 flex-shrink-0\" />\n ) : (\n <FileText className=\"size-3 flex-shrink-0\" />\n )}\n <span className=\"truncate max-w-[140px]\">{ctx.label}</span>\n <button\n type=\"button\"\n onClick={() => removeSessionContext(sessionId, ctx.id)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label=\"Remove context\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* File attachment preview row */}\n {pendingFiles.length > 0 && (\n <div className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\">\n {pendingFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n >\n <span className=\"truncate max-w-[120px]\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(index)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Toolbar row */}\n <div className=\"flex flex-wrap items-center gap-1 px-3 pt-2 pb-1 overflow-x-auto\">\n <SdkSelector\n sdk={sessionState.sdk}\n mode={sessionState.mode}\n providers={providers}\n onSdkChange={(sdk) => {\n setSessionSdk(sessionId, sdk);\n void resolveProviderDefaultModel(\n agentRef,\n sdk,\n sessionState.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState.model ?? GENERIC_MODEL_FALLBACK)\n );\n }}\n onModeChange={(mode) => setSessionMode(sessionId, mode)}\n />\n <ModelSelector\n value={sessionState.model}\n onChange={(model) => setSessionModel(sessionId, model)}\n provider={sessionState.sdk}\n agentId={agentId}\n />\n <AutonomySelector\n value={sessionState.permissionMode}\n mode={sessionState.mode}\n onChange={(permissionMode) => setSessionPermissionMode(sessionId, permissionMode)}\n />\n <McpServerSelector\n selected={sessionState.mcpServers}\n available={mcpServers}\n onChange={() => {\n // Update via store -- MCP servers are part of session state\n // For now we store them directly\n }}\n />\n <ContextLevelToggle\n agentId=\"\"\n sessionId={sessionId}\n contextLevel={sessionState.contextLevel}\n rootPath={sessionState.rootPath}\n onChange={(level, rootPath, vibeId) => {\n setSessionContextLevel(sessionId, level);\n setSessionRootPath(sessionId, rootPath ?? null);\n setSessionVibe(sessionId, vibeId ?? null, rootPath ?? null);\n }}\n vibes={vibes.map((v) => ({ id: v.id, name: v.name, path: v.path }))}\n />\n\n <div className=\"flex-1\" />\n\n {/* Show Thinking toggle */}\n <button\n type=\"button\"\n onClick={() => toggleThinking(sessionId)}\n className={`p-1.5 rounded text-xs font-medium transition-colors ${\n sessionState.showThinking\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n sessionState.showThinking\n ? tr('vibecontrols.agentManager.inputArea.hideThinking', 'Hide thinking')\n : tr('vibecontrols.agentManager.inputArea.showThinking', 'Show thinking')\n }\n >\n Think\n </button>\n {/* Context history limit */}\n <button\n type=\"button\"\n onClick={() => {\n const val = window.prompt(\n 'Context history limit (messages sent with each prompt):',\n String(sessionState.contextHistoryLimit)\n );\n if (val !== null) {\n const num = parseInt(val, 10);\n if (!isNaN(num) && num >= 0) {\n const store = useAgentManagerStore.getState();\n const s = store.sessionStates[sessionId];\n if (s) {\n useAgentManagerStore.setState((prev) => ({\n sessionStates: {\n ...prev.sessionStates,\n [sessionId]: { ...s, contextHistoryLimit: num },\n },\n }));\n }\n }\n }\n }}\n className=\"p-1.5 rounded text-[10px] font-mono text-text-tertiary hover:text-text-secondary transition-colors\"\n title={`Context history: last ${sessionState.contextHistoryLimit} messages sent with each prompt`}\n >\n H:{sessionState.contextHistoryLimit}\n </button>\n <VoiceToggle\n enabled={sessionState.voiceEnabled}\n onToggle={() => {\n toggleVoice(sessionId);\n if (!sessionState.voiceEnabled) startListening();\n else stopListening();\n }}\n isListening={isListening}\n />\n <FileAttachButton onFileSelect={handleFileSelect} />\n\n {/* Insert a backend prompt (rendered) into the composer, or attach a\n shared AiContext to the session. */}\n <ChatInsertPicker\n sessionId={sessionId}\n vibeId={sessionState?.vibeId}\n onInsertText={(t) => setText((prev) => (prev ? `${prev}\\n${t}` : t))}\n />\n\n {/* Attach a Files-module file: the agent fetches + materialises it on\n the server and its path becomes conversation context. */}\n <button\n type=\"button\"\n onClick={() => setFilePickerOpen(true)}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs text-text-secondary hover:bg-bg-sunken transition-colors\"\n title=\"Add a file from the Files module as context\"\n data-testid=\"chat-add-from-files\"\n >\n <FolderOpen className=\"size-4\" />\n <span className=\"hidden sm:inline\">Files</span>\n </button>\n </div>\n\n {/* Textarea + send/cancel */}\n <div className=\"flex items-end gap-2 px-3 pb-3 pt-1\">\n <textarea\n aria-label=\"control\"\n ref={textareaRef}\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={tr(\n 'vibecontrols.agentManager.inputArea.placeholder',\n 'Type a message or / for commands... (Enter to send)'\n )}\n rows={1}\n className=\"flex-1 resize-none rounded-lg border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors\"\n disabled={isStreaming}\n />\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"flex-shrink-0 p-2 rounded-lg bg-status-error-bg-subtle text-status-error-text hover:opacity-90 transition-opacity\"\n title={tr('vibecontrols.agentManager.inputArea.cancel', 'Cancel')}\n >\n <Square className=\"size-4\" />\n </button>\n ) : (\n <div className=\"flex items-end flex-shrink-0 relative\" ref={scheduleMenuRef}>\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"p-2 rounded-l-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.send', 'Send (Enter)')}\n >\n <ArrowUp className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowScheduleMenu(!showScheduleMenu)}\n disabled={!canSend}\n className=\"ml-1 p-2 rounded-r-lg border-l border-action-primary-text/20 bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.scheduleSend', 'Schedule send')}\n >\n <ChevronDown className=\"size-3\" />\n </button>\n\n {/* Schedule dropdown */}\n {showScheduleMenu && (\n <div className=\"absolute bottom-full right-0 mb-1 w-56 bg-bg-surface border border-border-default rounded-md shadow-lg py-1 z-50\">\n {!showSchedulePopup ? (\n <button\n type=\"button\"\n onClick={() => setShowSchedulePopup(true)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Clock className=\"size-3.5 text-text-secondary\" />\n {tr(\n 'vibecontrols.agentManager.inputArea.scheduleSendEllipsis',\n 'Schedule Send...'\n )}\n </button>\n ) : (\n <div className=\"px-3 py-2 space-y-2\">\n <label className=\"block text-[11px] font-medium text-text-secondary\">\n {tr('vibecontrols.agentManager.inputArea.sendAt', 'Send at:')}\n </label>\n <input\n aria-label=\"control\"\n type=\"datetime-local\"\n value={scheduleDateTime}\n onChange={(e) => setScheduleDateTime(e.target.value)}\n className=\"w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:border-border-strong\"\n />\n <button\n type=\"button\"\n onClick={() => void handleScheduleSend()}\n disabled={!scheduleDateTime || !agentId}\n className=\"w-full px-2 py-1.5 text-xs font-medium rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.agentManager.inputArea.schedule', 'Schedule')}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Files-module picker → agent materialises the file → session context. */}\n <FilePickerModal\n isOpen={filePickerOpen}\n onClose={() => setFilePickerOpen(false)}\n agent={agentRef}\n sessionId={sessionId}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -73,7 +73,7 @@ function d({ sidebar: d, children: f, detailPanel: p }) {
|
|
|
73
73
|
})] })
|
|
74
74
|
}),
|
|
75
75
|
/* @__PURE__ */ l("main", {
|
|
76
|
-
className: "flex flex-col flex-1 min-w-0 overflow-hidden bg-bg-
|
|
76
|
+
className: "flex flex-col flex-1 min-w-0 overflow-hidden bg-bg-surface",
|
|
77
77
|
children: f
|
|
78
78
|
}),
|
|
79
79
|
!h && p && !v && /* @__PURE__ */ l("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerLayout.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerLayout.tsx"],"sourcesContent":["/**\n * Three-pane layout for the Agent Manager.\n *\n * Left: session sidebar (280px, collapsible)\n * Center: main content area (flex-1)\n * Right: detail panel (320px, collapsible)\n */\n\nimport type { ReactNode } from 'react';\nimport { PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen } from 'lucide-react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerLayoutProps {\n sidebar: ReactNode;\n children: ReactNode;\n detailPanel?: ReactNode;\n}\n\nexport function AgentManagerLayout({ sidebar, children, detailPanel }: AgentManagerLayoutProps) {\n const sidebarOpen = useAgentManagerStore((s) => s.sidebarOpen);\n const detailPanelOpen = useAgentManagerStore((s) => s.detailPanelOpen);\n const toggleSidebar = useAgentManagerStore((s) => s.toggleSidebar);\n const toggleDetailPanel = useAgentManagerStore((s) => s.toggleDetailPanel);\n const isFullscreen = useAgentManagerStore((s) => s.isFullscreen);\n const tr = useTr();\n\n return (\n <div className=\"flex h-full min-h-0 overflow-hidden\">\n {/* Sidebar toggle (visible when sidebar is closed, hidden in fullscreen) */}\n {!sidebarOpen && !isFullscreen && (\n <div className=\"flex-shrink-0 border-r border-border-default bg-bg-surface\">\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"p-2 m-1 rounded hover:bg-bg-elevated transition-colors text-text-secondary hover:text-text-primary\"\n title={tr('vibecontrols.agentManager.layout.openSidebar', 'Open sidebar')}\n >\n <PanelLeftOpen className=\"size-4\" />\n </button>\n </div>\n )}\n\n {/* Left sidebar — hidden in fullscreen */}\n <AnimatePresence initial={false}>\n {sidebarOpen && !isFullscreen && (\n <>\n {/* Mobile overlay backdrop */}\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n className=\"fixed inset-0 bg-bg-overlay z-30 md:hidden\"\n onClick={toggleSidebar}\n />\n <motion.aside\n initial={{ width: 0, opacity: 0 }}\n animate={{ width: 280, opacity: 1 }}\n exit={{ width: 0, opacity: 0 }}\n transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}\n className=\"fixed md:relative z-40 md:z-auto inset-y-0 left-0 md:inset-auto flex-shrink-0 border-r border-border-default bg-bg-surface overflow-hidden w-full md:w-[280px]\"\n >\n <div className=\"flex flex-col h-full w-[280px]\">\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-border-default\">\n <span className=\"text-xs font-semibold uppercase tracking-wider text-text-secondary\">\n {tr('vibecontrols.agentManager.layout.sessions', 'Sessions')}\n </span>\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-secondary hover:text-text-primary\"\n title={tr('vibecontrols.agentManager.layout.closeSidebar', 'Close sidebar')}\n >\n <PanelLeftClose className=\"size-4\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-y-auto overflow-x-hidden\">{sidebar}</div>\n </div>\n </motion.aside>\n </>\n )}\n </AnimatePresence>\n\n {/* Center content */}\n <main className=\"flex flex-col flex-1 min-w-0 overflow-hidden bg-bg-
|
|
1
|
+
{"version":3,"file":"AgentManagerLayout.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerLayout.tsx"],"sourcesContent":["/**\n * Three-pane layout for the Agent Manager.\n *\n * Left: session sidebar (280px, collapsible)\n * Center: main content area (flex-1)\n * Right: detail panel (320px, collapsible)\n */\n\nimport type { ReactNode } from 'react';\nimport { PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen } from 'lucide-react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerLayoutProps {\n sidebar: ReactNode;\n children: ReactNode;\n detailPanel?: ReactNode;\n}\n\nexport function AgentManagerLayout({ sidebar, children, detailPanel }: AgentManagerLayoutProps) {\n const sidebarOpen = useAgentManagerStore((s) => s.sidebarOpen);\n const detailPanelOpen = useAgentManagerStore((s) => s.detailPanelOpen);\n const toggleSidebar = useAgentManagerStore((s) => s.toggleSidebar);\n const toggleDetailPanel = useAgentManagerStore((s) => s.toggleDetailPanel);\n const isFullscreen = useAgentManagerStore((s) => s.isFullscreen);\n const tr = useTr();\n\n return (\n <div className=\"flex h-full min-h-0 overflow-hidden\">\n {/* Sidebar toggle (visible when sidebar is closed, hidden in fullscreen) */}\n {!sidebarOpen && !isFullscreen && (\n <div className=\"flex-shrink-0 border-r border-border-default bg-bg-surface\">\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"p-2 m-1 rounded hover:bg-bg-elevated transition-colors text-text-secondary hover:text-text-primary\"\n title={tr('vibecontrols.agentManager.layout.openSidebar', 'Open sidebar')}\n >\n <PanelLeftOpen className=\"size-4\" />\n </button>\n </div>\n )}\n\n {/* Left sidebar — hidden in fullscreen */}\n <AnimatePresence initial={false}>\n {sidebarOpen && !isFullscreen && (\n <>\n {/* Mobile overlay backdrop */}\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.15 }}\n className=\"fixed inset-0 bg-bg-overlay z-30 md:hidden\"\n onClick={toggleSidebar}\n />\n <motion.aside\n initial={{ width: 0, opacity: 0 }}\n animate={{ width: 280, opacity: 1 }}\n exit={{ width: 0, opacity: 0 }}\n transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}\n className=\"fixed md:relative z-40 md:z-auto inset-y-0 left-0 md:inset-auto flex-shrink-0 border-r border-border-default bg-bg-surface overflow-hidden w-full md:w-[280px]\"\n >\n <div className=\"flex flex-col h-full w-[280px]\">\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-border-default\">\n <span className=\"text-xs font-semibold uppercase tracking-wider text-text-secondary\">\n {tr('vibecontrols.agentManager.layout.sessions', 'Sessions')}\n </span>\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-secondary hover:text-text-primary\"\n title={tr('vibecontrols.agentManager.layout.closeSidebar', 'Close sidebar')}\n >\n <PanelLeftClose className=\"size-4\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-y-auto overflow-x-hidden\">{sidebar}</div>\n </div>\n </motion.aside>\n </>\n )}\n </AnimatePresence>\n\n {/* Center content */}\n <main className=\"flex flex-col flex-1 min-w-0 overflow-hidden bg-bg-surface\">{children}</main>\n\n {/* Detail panel toggle (visible when panel is closed, hidden on mobile, hidden in fullscreen) */}\n {!detailPanelOpen && detailPanel && !isFullscreen && (\n <div className=\"hidden md:block flex-shrink-0 border-l border-border-default bg-bg-surface\">\n <button\n type=\"button\"\n onClick={toggleDetailPanel}\n className=\"p-2 m-1 rounded hover:bg-bg-elevated transition-colors text-text-secondary hover:text-text-primary\"\n title={tr('vibecontrols.agentManager.layout.openDetailPanel', 'Open detail panel')}\n >\n <PanelRightOpen className=\"size-4\" />\n </button>\n </div>\n )}\n\n {/* Right detail panel (hidden on mobile, hidden in fullscreen) */}\n <AnimatePresence initial={false}>\n {detailPanelOpen && detailPanel && !isFullscreen && (\n <motion.aside\n initial={{ width: 0, opacity: 0 }}\n animate={{ width: 320, opacity: 1 }}\n exit={{ width: 0, opacity: 0 }}\n transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}\n className=\"hidden md:block flex-shrink-0 border-l border-border-default bg-bg-surface overflow-hidden\"\n >\n <div className=\"flex flex-col h-full w-[320px]\">\n <div className=\"flex items-center justify-between px-3 py-2 border-b border-border-default\">\n <span className=\"text-xs font-semibold uppercase tracking-wider text-text-secondary\">\n {tr('vibecontrols.agentManager.layout.details', 'Details')}\n </span>\n <button\n type=\"button\"\n onClick={toggleDetailPanel}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-secondary hover:text-text-primary\"\n title={tr(\n 'vibecontrols.agentManager.layout.closeDetailPanel',\n 'Close detail panel'\n )}\n >\n <PanelRightClose className=\"size-4\" />\n </button>\n </div>\n <div className=\"flex-1 overflow-y-auto overflow-x-hidden\">{detailPanel}</div>\n </div>\n </motion.aside>\n )}\n </AnimatePresence>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@ function h(e, t) {
|
|
|
13
13
|
if (!t) return e;
|
|
14
14
|
let n = e.toLowerCase(), r = t.toLowerCase(), i = [], a = 0, o = n.indexOf(r, a);
|
|
15
15
|
for (; o !== -1;) o > a && i.push(e.slice(a, o)), i.push(/* @__PURE__ */ d("mark", {
|
|
16
|
-
className: "bg-status-warning-bg text-status-warning-text rounded-sm px-0.5",
|
|
16
|
+
className: "bg-status-warning-bg-subtle text-status-warning-text rounded-sm px-0.5",
|
|
17
17
|
children: e.slice(o, o + t.length)
|
|
18
18
|
}, o)), a = o + t.length, o = n.indexOf(r, a);
|
|
19
19
|
return a < e.length && i.push(e.slice(a)), i.length > 0 ? /* @__PURE__ */ d(u, { children: i }) : e;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerMessageItem.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerMessageItem.tsx"],"sourcesContent":["/**\n * Single message bubble for the Agent Manager chat.\n *\n * User messages are right-aligned; assistant messages are left-aligned.\n * Uses AssistantMarkdownRenderer for rich content in assistant messages.\n * Supports optional search query highlighting.\n */\n\nimport { useState, type FC, type ReactNode } from 'react';\nimport { Bot, Bookmark, BookmarkCheck, Copy, Check, User } from 'lucide-react';\nimport { AssistantMarkdownRenderer } from '@/components/assistant/AssistantMarkdownRenderer';\nimport { relativeTime } from '@/utils/relativeTime';\nimport type { AgentManagerMessage } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\nconst ANSI_ESCAPE_RE = new RegExp(\n `${String.fromCharCode(27)}(?:[@-Z\\\\-_]|\\\\[[0-?]*[ -/]*[@-~])`,\n 'g'\n);\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_ESCAPE_RE, '');\n}\n\n/** Highlight occurrences of `query` within `text`. */\nfunction highlightText(text: string, query: string): ReactNode {\n if (!query) return text;\n\n const lowerText = text.toLowerCase();\n const lowerQuery = query.toLowerCase();\n const parts: ReactNode[] = [];\n let lastIndex = 0;\n let matchIndex = lowerText.indexOf(lowerQuery, lastIndex);\n\n while (matchIndex !== -1) {\n if (matchIndex > lastIndex) {\n parts.push(text.slice(lastIndex, matchIndex));\n }\n parts.push(\n <mark\n key={matchIndex}\n className=\"bg-status-warning-bg text-status-warning-text rounded-sm px-0.5\"\n >\n {text.slice(matchIndex, matchIndex + query.length)}\n </mark>\n );\n lastIndex = matchIndex + query.length;\n matchIndex = lowerText.indexOf(lowerQuery, lastIndex);\n }\n\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n\n return parts.length > 0 ? <>{parts}</> : text;\n}\n\ninterface AgentManagerMessageItemProps {\n message: AgentManagerMessage;\n searchQuery?: string;\n isBookmarked?: boolean;\n onToggleBookmark?: (messageId: string) => void;\n flashMessageId?: string | null;\n}\n\nexport const AgentManagerMessageItem: FC<AgentManagerMessageItemProps> = ({\n message,\n searchQuery = '',\n isBookmarked = false,\n onToggleBookmark,\n flashMessageId,\n}) => {\n const [copied, setCopied] = useState(false);\n const [hovered, setHovered] = useState(false);\n const isUser = message.role === 'user';\n const tr = useTr();\n const displayContent = stripAnsi(message.content);\n const isFlashing = flashMessageId === message.id;\n\n const handleCopy = () => {\n navigator.clipboard.writeText(displayContent);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleToggleBookmark = () => {\n if (onToggleBookmark) onToggleBookmark(message.id);\n };\n\n const totalTokens = message.tokens ? message.tokens.input + message.tokens.output : null;\n\n return (\n <div\n data-message-id={message.id}\n className={`flex gap-2.5 scroll-mt-16 transition-shadow duration-300 ${\n isUser ? 'flex-row-reverse' : 'flex-row'\n } ${isFlashing ? 'ring-2 ring-status-warning-bg/60 rounded-lg' : ''}`}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n >\n {/* Avatar */}\n <div\n className={`flex-shrink-0 size-6 rounded-full flex items-center justify-center mt-0.5 ${\n isUser ? 'bg-action-primary-bg' : 'bg-bg-elevated border border-border-default'\n }`}\n >\n {isUser ? (\n <User className=\"size-3.5 text-action-primary-text\" />\n ) : (\n <Bot className=\"size-3.5 text-text-secondary\" />\n )}\n </div>\n\n {/* Message bubble */}\n <div\n className={`relative max-w-[85%] rounded-lg px-3 py-2 ${\n isUser\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-elevated border border-border-subtle'\n }`}\n >\n {/* Content */}\n {isUser ? (\n <p className=\"text-xs whitespace-pre-wrap leading-relaxed break-words\">\n {searchQuery ? highlightText(displayContent, searchQuery) : displayContent}\n </p>\n ) : searchQuery ? (\n <p className=\"text-xs whitespace-pre-wrap leading-relaxed break-words text-text-primary\">\n {highlightText(displayContent, searchQuery)}\n </p>\n ) : (\n <AssistantMarkdownRenderer content={displayContent} />\n )}\n\n {/* Footer: timestamp, tokens, bookmark, copy */}\n <div\n className={`flex items-center gap-2 text-[10px] mt-1 ${\n isUser ? 'text-action-primary-text/60' : 'text-text-muted'\n }`}\n >\n <span>{relativeTime(message.timestamp)}</span>\n\n {totalTokens !== null && !isUser && (\n <span>\n {totalTokens} {tr('vibecontrols.agentManager.messageItem.tokens', 'tokens')}\n </span>\n )}\n\n {message.sdk && (\n <span className=\"px-1 py-0.5 rounded bg-bg-elevated text-text-muted uppercase font-mono text-[9px]\">\n {message.sdk}\n </span>\n )}\n\n {message.model && !isUser && <span>{message.model}</span>}\n\n {/* Bookmark + Copy buttons on hover (or when bookmarked) */}\n {(hovered || isBookmarked) && onToggleBookmark && (\n <button\n type=\"button\"\n onClick={handleToggleBookmark}\n className={`ml-auto p-0.5 rounded transition-colors ${\n isUser ? 'hover:bg-action-primary-bg-hover' : 'hover:bg-bg-sunken'\n }`}\n aria-label={\n isBookmarked\n ? tr('vibecontrols.agentManager.messageItem.removeBookmark', 'Remove bookmark')\n : tr('vibecontrols.agentManager.messageItem.bookmarkMessage', 'Bookmark message')\n }\n title={\n isBookmarked\n ? tr('vibecontrols.agentManager.messageItem.removeBookmark', 'Remove bookmark')\n : tr('vibecontrols.agentManager.messageItem.bookmarkMessage', 'Bookmark message')\n }\n data-testid=\"agent-manager-bookmark-toggle\"\n >\n {isBookmarked ? (\n <BookmarkCheck className=\"size-3 text-status-warning-text\" />\n ) : (\n <Bookmark className=\"size-3\" />\n )}\n </button>\n )}\n\n {hovered && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${onToggleBookmark ? '' : 'ml-auto'} p-0.5 rounded transition-colors ${\n isUser ? 'hover:bg-action-primary-bg-hover' : 'hover:bg-bg-sunken'\n }`}\n aria-label={tr('vibecontrols.agentManager.messageItem.copyMessage', 'Copy message')}\n title={tr('vibecontrols.agentManager.messageItem.copyMessage', 'Copy message')}\n >\n {copied ? (\n <Check className=\"size-3 text-status-success-text\" />\n ) : (\n <Copy className=\"size-3\" />\n )}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentManagerMessageItem.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerMessageItem.tsx"],"sourcesContent":["/**\n * Single message bubble for the Agent Manager chat.\n *\n * User messages are right-aligned; assistant messages are left-aligned.\n * Uses AssistantMarkdownRenderer for rich content in assistant messages.\n * Supports optional search query highlighting.\n */\n\nimport { useState, type FC, type ReactNode } from 'react';\nimport { Bot, Bookmark, BookmarkCheck, Copy, Check, User } from 'lucide-react';\nimport { AssistantMarkdownRenderer } from '@/components/assistant/AssistantMarkdownRenderer';\nimport { relativeTime } from '@/utils/relativeTime';\nimport type { AgentManagerMessage } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\nconst ANSI_ESCAPE_RE = new RegExp(\n `${String.fromCharCode(27)}(?:[@-Z\\\\-_]|\\\\[[0-?]*[ -/]*[@-~])`,\n 'g'\n);\n\nfunction stripAnsi(value: string): string {\n return value.replace(ANSI_ESCAPE_RE, '');\n}\n\n/** Highlight occurrences of `query` within `text`. */\nfunction highlightText(text: string, query: string): ReactNode {\n if (!query) return text;\n\n const lowerText = text.toLowerCase();\n const lowerQuery = query.toLowerCase();\n const parts: ReactNode[] = [];\n let lastIndex = 0;\n let matchIndex = lowerText.indexOf(lowerQuery, lastIndex);\n\n while (matchIndex !== -1) {\n if (matchIndex > lastIndex) {\n parts.push(text.slice(lastIndex, matchIndex));\n }\n parts.push(\n <mark\n key={matchIndex}\n className=\"bg-status-warning-bg-subtle text-status-warning-text rounded-sm px-0.5\"\n >\n {text.slice(matchIndex, matchIndex + query.length)}\n </mark>\n );\n lastIndex = matchIndex + query.length;\n matchIndex = lowerText.indexOf(lowerQuery, lastIndex);\n }\n\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n\n return parts.length > 0 ? <>{parts}</> : text;\n}\n\ninterface AgentManagerMessageItemProps {\n message: AgentManagerMessage;\n searchQuery?: string;\n isBookmarked?: boolean;\n onToggleBookmark?: (messageId: string) => void;\n flashMessageId?: string | null;\n}\n\nexport const AgentManagerMessageItem: FC<AgentManagerMessageItemProps> = ({\n message,\n searchQuery = '',\n isBookmarked = false,\n onToggleBookmark,\n flashMessageId,\n}) => {\n const [copied, setCopied] = useState(false);\n const [hovered, setHovered] = useState(false);\n const isUser = message.role === 'user';\n const tr = useTr();\n const displayContent = stripAnsi(message.content);\n const isFlashing = flashMessageId === message.id;\n\n const handleCopy = () => {\n navigator.clipboard.writeText(displayContent);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n };\n\n const handleToggleBookmark = () => {\n if (onToggleBookmark) onToggleBookmark(message.id);\n };\n\n const totalTokens = message.tokens ? message.tokens.input + message.tokens.output : null;\n\n return (\n <div\n data-message-id={message.id}\n className={`flex gap-2.5 scroll-mt-16 transition-shadow duration-300 ${\n isUser ? 'flex-row-reverse' : 'flex-row'\n } ${isFlashing ? 'ring-2 ring-status-warning-bg/60 rounded-lg' : ''}`}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n >\n {/* Avatar */}\n <div\n className={`flex-shrink-0 size-6 rounded-full flex items-center justify-center mt-0.5 ${\n isUser ? 'bg-action-primary-bg' : 'bg-bg-elevated border border-border-default'\n }`}\n >\n {isUser ? (\n <User className=\"size-3.5 text-action-primary-text\" />\n ) : (\n <Bot className=\"size-3.5 text-text-secondary\" />\n )}\n </div>\n\n {/* Message bubble */}\n <div\n className={`relative max-w-[85%] rounded-lg px-3 py-2 ${\n isUser\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-elevated border border-border-subtle'\n }`}\n >\n {/* Content */}\n {isUser ? (\n <p className=\"text-xs whitespace-pre-wrap leading-relaxed break-words\">\n {searchQuery ? highlightText(displayContent, searchQuery) : displayContent}\n </p>\n ) : searchQuery ? (\n <p className=\"text-xs whitespace-pre-wrap leading-relaxed break-words text-text-primary\">\n {highlightText(displayContent, searchQuery)}\n </p>\n ) : (\n <AssistantMarkdownRenderer content={displayContent} />\n )}\n\n {/* Footer: timestamp, tokens, bookmark, copy */}\n <div\n className={`flex items-center gap-2 text-[10px] mt-1 ${\n isUser ? 'text-action-primary-text/60' : 'text-text-muted'\n }`}\n >\n <span>{relativeTime(message.timestamp)}</span>\n\n {totalTokens !== null && !isUser && (\n <span>\n {totalTokens} {tr('vibecontrols.agentManager.messageItem.tokens', 'tokens')}\n </span>\n )}\n\n {message.sdk && (\n <span className=\"px-1 py-0.5 rounded bg-bg-elevated text-text-muted uppercase font-mono text-[9px]\">\n {message.sdk}\n </span>\n )}\n\n {message.model && !isUser && <span>{message.model}</span>}\n\n {/* Bookmark + Copy buttons on hover (or when bookmarked) */}\n {(hovered || isBookmarked) && onToggleBookmark && (\n <button\n type=\"button\"\n onClick={handleToggleBookmark}\n className={`ml-auto p-0.5 rounded transition-colors ${\n isUser ? 'hover:bg-action-primary-bg-hover' : 'hover:bg-bg-sunken'\n }`}\n aria-label={\n isBookmarked\n ? tr('vibecontrols.agentManager.messageItem.removeBookmark', 'Remove bookmark')\n : tr('vibecontrols.agentManager.messageItem.bookmarkMessage', 'Bookmark message')\n }\n title={\n isBookmarked\n ? tr('vibecontrols.agentManager.messageItem.removeBookmark', 'Remove bookmark')\n : tr('vibecontrols.agentManager.messageItem.bookmarkMessage', 'Bookmark message')\n }\n data-testid=\"agent-manager-bookmark-toggle\"\n >\n {isBookmarked ? (\n <BookmarkCheck className=\"size-3 text-status-warning-text\" />\n ) : (\n <Bookmark className=\"size-3\" />\n )}\n </button>\n )}\n\n {hovered && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={`${onToggleBookmark ? '' : 'ml-auto'} p-0.5 rounded transition-colors ${\n isUser ? 'hover:bg-action-primary-bg-hover' : 'hover:bg-bg-sunken'\n }`}\n aria-label={tr('vibecontrols.agentManager.messageItem.copyMessage', 'Copy message')}\n title={tr('vibecontrols.agentManager.messageItem.copyMessage', 'Copy message')}\n >\n {copied ? (\n <Check className=\"size-3 text-status-success-text\" />\n ) : (\n <Copy className=\"size-3\" />\n )}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -96,7 +96,7 @@ function v({ agent: v, onDeleteSession: y, onDeleteSelected: b }) {
|
|
|
96
96
|
children: [/* @__PURE__ */ h("button", {
|
|
97
97
|
type: "button",
|
|
98
98
|
onClick: () => z(!R),
|
|
99
|
-
className: "flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-
|
|
99
|
+
className: "flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-surface text-text-secondary hover:bg-bg-elevated text-xs transition-colors",
|
|
100
100
|
children: [
|
|
101
101
|
/* @__PURE__ */ m("span", {
|
|
102
102
|
className: "text-text-tertiary",
|
|
@@ -129,7 +129,7 @@ function v({ agent: v, onDeleteSession: y, onDeleteSelected: b }) {
|
|
|
129
129
|
/* @__PURE__ */ h("button", {
|
|
130
130
|
type: "button",
|
|
131
131
|
onClick: () => V(!B),
|
|
132
|
-
className: "flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-
|
|
132
|
+
className: "flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-surface text-text-secondary hover:bg-bg-elevated text-xs transition-colors",
|
|
133
133
|
children: [
|
|
134
134
|
/* @__PURE__ */ m("span", {
|
|
135
135
|
className: "text-text-tertiary",
|
|
@@ -162,7 +162,7 @@ function v({ agent: v, onDeleteSession: y, onDeleteSelected: b }) {
|
|
|
162
162
|
value: O,
|
|
163
163
|
onChange: (e) => k(e.target.value),
|
|
164
164
|
placeholder: x("vibecontrols.agentManager.sidebar.filterByTags", "Filter by tags..."),
|
|
165
|
-
className: "w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-
|
|
165
|
+
className: "w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors"
|
|
166
166
|
})
|
|
167
167
|
}),
|
|
168
168
|
/* @__PURE__ */ h("div", {
|
|
@@ -173,7 +173,7 @@ function v({ agent: v, onDeleteSession: y, onDeleteSelected: b }) {
|
|
|
173
173
|
type: "date",
|
|
174
174
|
value: A,
|
|
175
175
|
onChange: (e) => j(e.target.value),
|
|
176
|
-
className: "flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-
|
|
176
|
+
className: "flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-surface text-text-primary"
|
|
177
177
|
}),
|
|
178
178
|
/* @__PURE__ */ m("span", {
|
|
179
179
|
className: "text-[10px] text-text-tertiary",
|
|
@@ -184,7 +184,7 @@ function v({ agent: v, onDeleteSession: y, onDeleteSelected: b }) {
|
|
|
184
184
|
type: "date",
|
|
185
185
|
value: M,
|
|
186
186
|
onChange: (e) => N(e.target.value),
|
|
187
|
-
className: "flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-
|
|
187
|
+
className: "flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-surface text-text-primary"
|
|
188
188
|
})
|
|
189
189
|
]
|
|
190
190
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerSidebar.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerSidebar.tsx"],"sourcesContent":["/**\n * Session list sidebar for the Agent Manager.\n *\n * Includes a \"New Session\" button, search input, filter dropdown,\n * group-by selector, the session list, and bulk action bar.\n */\n\nimport { useCallback, useState } from 'react';\nimport { Plus, ListFilter, ChevronDown, SlidersHorizontal } from 'lucide-react';\nimport { AnimatePresence } from 'framer-motion';\nimport { SearchInput } from '@/components/shared';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport type { SidebarGroupBy } from '@/types/agentManager';\nimport { AgentManagerSessionList } from './AgentManagerSessionList';\nimport { AgentManagerBulkActions } from './AgentManagerBulkActions';\nimport { NewSessionDialog } from './dialogs/NewSessionDialog';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type { AgentRef } from '@/services/aiApi';\n\ninterface AgentManagerSidebarProps {\n agent: AgentRef;\n onDeleteSession: (sessionId: string) => void;\n onDeleteSelected: (sessionIds: string[]) => void;\n}\n\nconst GROUP_BY_OPTIONS = [\n { value: 'date', label: 'Date' },\n { value: 'model', label: 'Model' },\n { value: 'status', label: 'Status' },\n { value: 'sdk', label: 'SDK' },\n { value: 'none', label: 'None' },\n];\n\nconst STATUS_OPTIONS = [\n { value: 'active', label: 'Active' },\n { value: 'idle', label: 'Idle' },\n { value: 'processing', label: 'Processing' },\n { value: 'error', label: 'Error' },\n { value: 'terminated', label: 'Terminated' },\n];\n\nexport function AgentManagerSidebar({\n agent,\n onDeleteSession,\n onDeleteSelected,\n}: AgentManagerSidebarProps) {\n const tr = useTr();\n const sidebarSearchQuery = useAgentManagerStore((s) => s.sidebarSearchQuery);\n const setSidebarSearchQuery = useAgentManagerStore((s) => s.setSidebarSearchQuery);\n const sidebarGroupBy = useAgentManagerStore((s) => s.sidebarGroupBy);\n const setSidebarGroupBy = useAgentManagerStore((s) => s.setSidebarGroupBy);\n const [filterStatus, setFilterStatus] = useState<string | null>(null);\n const [tagFilter, setTagFilter] = useState('');\n const [dateFrom, setDateFrom] = useState('');\n const [dateTo, setDateTo] = useState('');\n const [showNewDialog, setShowNewDialog] = useState(false);\n const [showFilters, setShowFilters] = useState(false);\n const [statusDropdownOpen, setStatusDropdownOpen] = useState(false);\n const [groupDropdownOpen, setGroupDropdownOpen] = useState(false);\n\n const filterTags = tagFilter\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n\n const handleGroupByChange = useCallback(\n (value: string) => {\n setSidebarGroupBy(value as SidebarGroupBy);\n setGroupDropdownOpen(false);\n },\n [setSidebarGroupBy]\n );\n\n const handleStatusFilterChange = useCallback((value: string) => {\n setFilterStatus(value === 'all' ? null : value);\n setStatusDropdownOpen(false);\n }, []);\n\n const statusLabel = filterStatus\n ? (STATUS_OPTIONS.find((o) => o.value === filterStatus)?.label ?? 'All')\n : 'All';\n\n const groupLabel = GROUP_BY_OPTIONS.find((o) => o.value === sidebarGroupBy)?.label ?? 'Date';\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* New session button */}\n <div className=\"px-3 py-2\">\n <button\n type=\"button\"\n onClick={() => setShowNewDialog(true)}\n className=\"flex items-center justify-center gap-1.5 w-full px-3 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.agentManager.sidebar.newSession', 'New Session')}\n </button>\n </div>\n\n {/* Search + filter toggle */}\n <div className=\"flex items-center gap-1.5 px-3 pb-2\">\n <div className=\"flex-1 min-w-0\">\n <SearchInput\n value={sidebarSearchQuery}\n onChange={setSidebarSearchQuery}\n placeholder={tr(\n 'vibecontrols.agentManager.sidebar.searchSessions',\n 'Search sessions...'\n )}\n />\n </div>\n <button\n type=\"button\"\n onClick={() => setShowFilters((p) => !p)}\n title={\n showFilters\n ? tr('vibecontrols.agentManager.sidebar.hideFilters', 'Hide filters')\n : tr('vibecontrols.agentManager.sidebar.showFilters', 'Show filters')\n }\n className={`flex-shrink-0 p-1.5 rounded transition-colors ${\n showFilters\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-elevated'\n }`}\n >\n <SlidersHorizontal className=\"size-3.5\" />\n </button>\n </div>\n\n {/* Collapsible filters */}\n {showFilters && (\n <>\n {/* Status + Group By row */}\n <div className=\"flex items-center gap-2 px-3 pb-2 text-xs\">\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setStatusDropdownOpen(!statusDropdownOpen)}\n className=\"flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-primary text-text-secondary hover:bg-bg-elevated text-xs transition-colors\"\n >\n <span className=\"text-text-tertiary\">Status:</span>\n <span className=\"font-medium text-text-primary\">{statusLabel}</span>\n <ChevronDown\n className={`size-3 transition-transform ${statusDropdownOpen ? 'rotate-180' : ''}`}\n />\n </button>\n {statusDropdownOpen && (\n <div className=\"absolute z-50 mt-1 w-36 bg-bg-surface border border-border-default rounded-md shadow-lg py-1\">\n <button\n type=\"button\"\n onClick={() => handleStatusFilterChange('all')}\n className=\"block w-full px-3 py-1.5 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n All\n </button>\n {STATUS_OPTIONS.map((opt) => (\n <button\n type=\"button\"\n key={opt.value}\n onClick={() => handleStatusFilterChange(opt.value)}\n className={`block w-full px-3 py-1.5 text-left text-xs hover:bg-bg-sunken transition-colors ${\n filterStatus === opt.value\n ? 'text-action-primary-bg font-medium'\n : 'text-text-primary'\n }`}\n >\n {opt.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n <div className=\"relative ml-auto flex items-center gap-1\">\n <ListFilter className=\"size-3.5 text-text-secondary flex-shrink-0\" />\n <button\n type=\"button\"\n onClick={() => setGroupDropdownOpen(!groupDropdownOpen)}\n className=\"flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-primary text-text-secondary hover:bg-bg-elevated text-xs transition-colors\"\n >\n <span className=\"text-text-tertiary\">Group:</span>\n <span className=\"font-medium text-text-primary\">{groupLabel}</span>\n <ChevronDown\n className={`size-3 transition-transform ${groupDropdownOpen ? 'rotate-180' : ''}`}\n />\n </button>\n {groupDropdownOpen && (\n <div className=\"absolute right-0 z-50 mt-1 top-full w-32 bg-bg-surface border border-border-default rounded-md shadow-lg py-1\">\n {GROUP_BY_OPTIONS.map((opt) => (\n <button\n type=\"button\"\n key={opt.value}\n onClick={() => handleGroupByChange(opt.value)}\n className={`block w-full px-3 py-1.5 text-left text-xs hover:bg-bg-sunken transition-colors ${\n sidebarGroupBy === opt.value\n ? 'text-action-primary-bg font-medium'\n : 'text-text-primary'\n }`}\n >\n {opt.label}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Tag filter */}\n <div className=\"px-3 pb-2\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={tagFilter}\n onChange={(e) => setTagFilter(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.sidebar.filterByTags',\n 'Filter by tags...'\n )}\n className=\"w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-primary text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors\"\n />\n </div>\n\n {/* Date range filter */}\n <div className=\"flex gap-1 items-center px-3 pb-2\">\n <input\n aria-label=\"control\"\n type=\"date\"\n value={dateFrom}\n onChange={(e) => setDateFrom(e.target.value)}\n className=\"flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-primary text-text-primary\"\n />\n <span className=\"text-[10px] text-text-tertiary\">to</span>\n <input\n aria-label=\"control\"\n type=\"date\"\n value={dateTo}\n onChange={(e) => setDateTo(e.target.value)}\n className=\"flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-primary text-text-primary\"\n />\n </div>\n </>\n )}\n\n {/* Session list */}\n <div className=\"flex-1 overflow-y-auto\">\n <AgentManagerSessionList\n agent={agent}\n onDeleteSession={onDeleteSession}\n filterTags={filterTags}\n dateFrom={dateFrom}\n dateTo={dateTo}\n />\n </div>\n\n {/* Bulk actions */}\n <AnimatePresence>\n <AgentManagerBulkActions onDeleteSelected={onDeleteSelected} />\n </AnimatePresence>\n\n {/* New session dialog */}\n <NewSessionDialog\n agent={agent}\n isOpen={showNewDialog}\n onClose={() => setShowNewDialog(false)}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AgentManagerSidebar.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerSidebar.tsx"],"sourcesContent":["/**\n * Session list sidebar for the Agent Manager.\n *\n * Includes a \"New Session\" button, search input, filter dropdown,\n * group-by selector, the session list, and bulk action bar.\n */\n\nimport { useCallback, useState } from 'react';\nimport { Plus, ListFilter, ChevronDown, SlidersHorizontal } from 'lucide-react';\nimport { AnimatePresence } from 'framer-motion';\nimport { SearchInput } from '@/components/shared';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport type { SidebarGroupBy } from '@/types/agentManager';\nimport { AgentManagerSessionList } from './AgentManagerSessionList';\nimport { AgentManagerBulkActions } from './AgentManagerBulkActions';\nimport { NewSessionDialog } from './dialogs/NewSessionDialog';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type { AgentRef } from '@/services/aiApi';\n\ninterface AgentManagerSidebarProps {\n agent: AgentRef;\n onDeleteSession: (sessionId: string) => void;\n onDeleteSelected: (sessionIds: string[]) => void;\n}\n\nconst GROUP_BY_OPTIONS = [\n { value: 'date', label: 'Date' },\n { value: 'model', label: 'Model' },\n { value: 'status', label: 'Status' },\n { value: 'sdk', label: 'SDK' },\n { value: 'none', label: 'None' },\n];\n\nconst STATUS_OPTIONS = [\n { value: 'active', label: 'Active' },\n { value: 'idle', label: 'Idle' },\n { value: 'processing', label: 'Processing' },\n { value: 'error', label: 'Error' },\n { value: 'terminated', label: 'Terminated' },\n];\n\nexport function AgentManagerSidebar({\n agent,\n onDeleteSession,\n onDeleteSelected,\n}: AgentManagerSidebarProps) {\n const tr = useTr();\n const sidebarSearchQuery = useAgentManagerStore((s) => s.sidebarSearchQuery);\n const setSidebarSearchQuery = useAgentManagerStore((s) => s.setSidebarSearchQuery);\n const sidebarGroupBy = useAgentManagerStore((s) => s.sidebarGroupBy);\n const setSidebarGroupBy = useAgentManagerStore((s) => s.setSidebarGroupBy);\n const [filterStatus, setFilterStatus] = useState<string | null>(null);\n const [tagFilter, setTagFilter] = useState('');\n const [dateFrom, setDateFrom] = useState('');\n const [dateTo, setDateTo] = useState('');\n const [showNewDialog, setShowNewDialog] = useState(false);\n const [showFilters, setShowFilters] = useState(false);\n const [statusDropdownOpen, setStatusDropdownOpen] = useState(false);\n const [groupDropdownOpen, setGroupDropdownOpen] = useState(false);\n\n const filterTags = tagFilter\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n\n const handleGroupByChange = useCallback(\n (value: string) => {\n setSidebarGroupBy(value as SidebarGroupBy);\n setGroupDropdownOpen(false);\n },\n [setSidebarGroupBy]\n );\n\n const handleStatusFilterChange = useCallback((value: string) => {\n setFilterStatus(value === 'all' ? null : value);\n setStatusDropdownOpen(false);\n }, []);\n\n const statusLabel = filterStatus\n ? (STATUS_OPTIONS.find((o) => o.value === filterStatus)?.label ?? 'All')\n : 'All';\n\n const groupLabel = GROUP_BY_OPTIONS.find((o) => o.value === sidebarGroupBy)?.label ?? 'Date';\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* New session button */}\n <div className=\"px-3 py-2\">\n <button\n type=\"button\"\n onClick={() => setShowNewDialog(true)}\n className=\"flex items-center justify-center gap-1.5 w-full px-3 py-2 text-sm font-medium bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.agentManager.sidebar.newSession', 'New Session')}\n </button>\n </div>\n\n {/* Search + filter toggle */}\n <div className=\"flex items-center gap-1.5 px-3 pb-2\">\n <div className=\"flex-1 min-w-0\">\n <SearchInput\n value={sidebarSearchQuery}\n onChange={setSidebarSearchQuery}\n placeholder={tr(\n 'vibecontrols.agentManager.sidebar.searchSessions',\n 'Search sessions...'\n )}\n />\n </div>\n <button\n type=\"button\"\n onClick={() => setShowFilters((p) => !p)}\n title={\n showFilters\n ? tr('vibecontrols.agentManager.sidebar.hideFilters', 'Hide filters')\n : tr('vibecontrols.agentManager.sidebar.showFilters', 'Show filters')\n }\n className={`flex-shrink-0 p-1.5 rounded transition-colors ${\n showFilters\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-elevated'\n }`}\n >\n <SlidersHorizontal className=\"size-3.5\" />\n </button>\n </div>\n\n {/* Collapsible filters */}\n {showFilters && (\n <>\n {/* Status + Group By row */}\n <div className=\"flex items-center gap-2 px-3 pb-2 text-xs\">\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={() => setStatusDropdownOpen(!statusDropdownOpen)}\n className=\"flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-surface text-text-secondary hover:bg-bg-elevated text-xs transition-colors\"\n >\n <span className=\"text-text-tertiary\">Status:</span>\n <span className=\"font-medium text-text-primary\">{statusLabel}</span>\n <ChevronDown\n className={`size-3 transition-transform ${statusDropdownOpen ? 'rotate-180' : ''}`}\n />\n </button>\n {statusDropdownOpen && (\n <div className=\"absolute z-50 mt-1 w-36 bg-bg-surface border border-border-default rounded-md shadow-lg py-1\">\n <button\n type=\"button\"\n onClick={() => handleStatusFilterChange('all')}\n className=\"block w-full px-3 py-1.5 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n All\n </button>\n {STATUS_OPTIONS.map((opt) => (\n <button\n type=\"button\"\n key={opt.value}\n onClick={() => handleStatusFilterChange(opt.value)}\n className={`block w-full px-3 py-1.5 text-left text-xs hover:bg-bg-sunken transition-colors ${\n filterStatus === opt.value\n ? 'text-action-primary-bg font-medium'\n : 'text-text-primary'\n }`}\n >\n {opt.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n <div className=\"relative ml-auto flex items-center gap-1\">\n <ListFilter className=\"size-3.5 text-text-secondary flex-shrink-0\" />\n <button\n type=\"button\"\n onClick={() => setGroupDropdownOpen(!groupDropdownOpen)}\n className=\"flex items-center gap-1 px-2 py-1 rounded border border-border-default bg-bg-surface text-text-secondary hover:bg-bg-elevated text-xs transition-colors\"\n >\n <span className=\"text-text-tertiary\">Group:</span>\n <span className=\"font-medium text-text-primary\">{groupLabel}</span>\n <ChevronDown\n className={`size-3 transition-transform ${groupDropdownOpen ? 'rotate-180' : ''}`}\n />\n </button>\n {groupDropdownOpen && (\n <div className=\"absolute right-0 z-50 mt-1 top-full w-32 bg-bg-surface border border-border-default rounded-md shadow-lg py-1\">\n {GROUP_BY_OPTIONS.map((opt) => (\n <button\n type=\"button\"\n key={opt.value}\n onClick={() => handleGroupByChange(opt.value)}\n className={`block w-full px-3 py-1.5 text-left text-xs hover:bg-bg-sunken transition-colors ${\n sidebarGroupBy === opt.value\n ? 'text-action-primary-bg font-medium'\n : 'text-text-primary'\n }`}\n >\n {opt.label}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n\n {/* Tag filter */}\n <div className=\"px-3 pb-2\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={tagFilter}\n onChange={(e) => setTagFilter(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.sidebar.filterByTags',\n 'Filter by tags...'\n )}\n className=\"w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-surface text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors\"\n />\n </div>\n\n {/* Date range filter */}\n <div className=\"flex gap-1 items-center px-3 pb-2\">\n <input\n aria-label=\"control\"\n type=\"date\"\n value={dateFrom}\n onChange={(e) => setDateFrom(e.target.value)}\n className=\"flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-surface text-text-primary\"\n />\n <span className=\"text-[10px] text-text-tertiary\">to</span>\n <input\n aria-label=\"control\"\n type=\"date\"\n value={dateTo}\n onChange={(e) => setDateTo(e.target.value)}\n className=\"flex-1 px-1.5 py-1 text-[11px] rounded border border-border-default bg-bg-surface text-text-primary\"\n />\n </div>\n </>\n )}\n\n {/* Session list */}\n <div className=\"flex-1 overflow-y-auto\">\n <AgentManagerSessionList\n agent={agent}\n onDeleteSession={onDeleteSession}\n filterTags={filterTags}\n dateFrom={dateFrom}\n dateTo={dateTo}\n />\n </div>\n\n {/* Bulk actions */}\n <AnimatePresence>\n <AgentManagerBulkActions onDeleteSelected={onDeleteSelected} />\n </AnimatePresence>\n\n {/* New session dialog */}\n <NewSessionDialog\n agent={agent}\n isOpen={showNewDialog}\n onClose={() => setShowNewDialog(false)}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ var o = ({ sessionId: o, name: s, isActive: c, isPinned: l, isProcessing: u, onA
|
|
|
21
21
|
className: `
|
|
22
22
|
group relative flex items-center gap-1.5 pl-3 pr-6 py-1.5 text-xs font-medium
|
|
23
23
|
whitespace-nowrap select-none w-[160px] border-b-2 border-r transition-colors
|
|
24
|
-
${c ? "bg-bg-surface text-text-primary border-b-action-primary-bg border-r-border-default" : "bg-bg-
|
|
24
|
+
${c ? "bg-bg-surface text-text-primary border-b-action-primary-bg border-r-border-default" : "bg-bg-surface text-text-secondary border-b-transparent border-r-border-subtle hover:text-text-primary hover:bg-bg-elevated"}
|
|
25
25
|
`,
|
|
26
26
|
children: [
|
|
27
27
|
u && /* @__PURE__ */ i("span", { className: "flex-shrink-0 size-2 rounded-full bg-status-info-text animate-pulse" }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerTab.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerTab.tsx"],"sourcesContent":["/**\n * Individual tab component for the Agent Manager tab bar.\n *\n * Visual states: active (highlighted bg), inactive, pinned (pin icon),\n * processing (animated dot). Close button hidden on pinned tabs unless hovered.\n */\n\nimport { useState, type FC, type MouseEvent } from 'react';\nimport { Pin, X } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerTabProps {\n sessionId: string;\n name: string;\n isActive: boolean;\n isPinned: boolean;\n isProcessing: boolean;\n onActivate: () => void;\n onClose: () => void;\n onRename?: (sessionId: string) => void;\n}\n\nexport const AgentManagerTab: FC<AgentManagerTabProps> = ({\n sessionId,\n name,\n isActive,\n isPinned,\n isProcessing,\n onActivate,\n onClose,\n onRename,\n}) => {\n const [hovered, setHovered] = useState(false);\n const tr = useTr();\n\n const truncatedName = name.length > 20 ? `${name.slice(0, 20)}...` : name;\n\n const handleClose = (e: MouseEvent) => {\n e.stopPropagation();\n onClose();\n };\n\n const handleAuxClick = (e: MouseEvent) => {\n // Middle-click to close\n if (e.button === 1) {\n e.preventDefault();\n onClose();\n }\n };\n\n return (\n <button\n type=\"button\"\n data-session-id={sessionId}\n title={name}\n onClick={onActivate}\n onDoubleClick={() => onRename?.(sessionId)}\n onAuxClick={handleAuxClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n className={`\n group relative flex items-center gap-1.5 pl-3 pr-6 py-1.5 text-xs font-medium\n whitespace-nowrap select-none w-[160px] border-b-2 border-r transition-colors\n ${\n isActive\n ? 'bg-bg-surface text-text-primary border-b-action-primary-bg border-r-border-default'\n : 'bg-bg-
|
|
1
|
+
{"version":3,"file":"AgentManagerTab.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerTab.tsx"],"sourcesContent":["/**\n * Individual tab component for the Agent Manager tab bar.\n *\n * Visual states: active (highlighted bg), inactive, pinned (pin icon),\n * processing (animated dot). Close button hidden on pinned tabs unless hovered.\n */\n\nimport { useState, type FC, type MouseEvent } from 'react';\nimport { Pin, X } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerTabProps {\n sessionId: string;\n name: string;\n isActive: boolean;\n isPinned: boolean;\n isProcessing: boolean;\n onActivate: () => void;\n onClose: () => void;\n onRename?: (sessionId: string) => void;\n}\n\nexport const AgentManagerTab: FC<AgentManagerTabProps> = ({\n sessionId,\n name,\n isActive,\n isPinned,\n isProcessing,\n onActivate,\n onClose,\n onRename,\n}) => {\n const [hovered, setHovered] = useState(false);\n const tr = useTr();\n\n const truncatedName = name.length > 20 ? `${name.slice(0, 20)}...` : name;\n\n const handleClose = (e: MouseEvent) => {\n e.stopPropagation();\n onClose();\n };\n\n const handleAuxClick = (e: MouseEvent) => {\n // Middle-click to close\n if (e.button === 1) {\n e.preventDefault();\n onClose();\n }\n };\n\n return (\n <button\n type=\"button\"\n data-session-id={sessionId}\n title={name}\n onClick={onActivate}\n onDoubleClick={() => onRename?.(sessionId)}\n onAuxClick={handleAuxClick}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n className={`\n group relative flex items-center gap-1.5 pl-3 pr-6 py-1.5 text-xs font-medium\n whitespace-nowrap select-none w-[160px] border-b-2 border-r transition-colors\n ${\n isActive\n ? 'bg-bg-surface text-text-primary border-b-action-primary-bg border-r-border-default'\n : 'bg-bg-surface text-text-secondary border-b-transparent border-r-border-subtle hover:text-text-primary hover:bg-bg-elevated'\n }\n `}\n >\n {/* Processing indicator */}\n {isProcessing && (\n <span className=\"flex-shrink-0 size-2 rounded-full bg-status-info-text animate-pulse\" />\n )}\n\n {/* Pin icon */}\n {isPinned && <Pin className=\"flex-shrink-0 size-3 text-text-muted\" />}\n\n {/* Tab name */}\n <span className=\"truncate\">{truncatedName}</span>\n\n {/* Close button: absolutely positioned at top-right corner */}\n {(!isPinned || hovered) && (\n <span\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (handleClose as (...a: unknown[]) => unknown)();\n }\n }}\n role=\"button\"\n tabIndex={-1}\n onClick={handleClose}\n className={`\n absolute right-1 top-1/2 -translate-y-1/2 p-0.5 rounded hover:bg-bg-sunken transition-colors\n ${hovered ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'}\n `}\n aria-label={`${tr('vibecontrols.agentManager.tab.close', 'Close')} ${name}`}\n >\n <X className=\"size-3\" />\n </span>\n )}\n </button>\n );\n};\n"],"mappings":";;;;;AAsBA,IAAa,KAA6C,EACxD,cACA,SACA,aACA,aACA,iBACA,eACA,YACA,kBACI;CACJ,IAAM,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,IAAK,GAAO,EAEZ,IAAgB,EAAK,SAAS,KAAK,GAAG,EAAK,MAAM,GAAG,GAAG,CAAC,OAAO,GAE/D,KAAe,MAAkB;AAErC,EADA,EAAE,iBAAiB,EACnB,GAAS;;AAWX,QACE,kBAAC,UAAD;EACE,MAAK;EACL,mBAAiB;EACjB,OAAO;EACP,SAAS;EACT,qBAAqB,IAAW,EAAU;EAC1C,aAfoB,MAAkB;AAExC,GAAI,EAAE,WAAW,MACf,EAAE,gBAAgB,EAClB,GAAS;;EAYT,oBAAoB,EAAW,GAAK;EACpC,oBAAoB,EAAW,GAAM;EACrC,WAAW;;;UAIP,IACI,uFACA,6HACL;;YAhBL;GAoBG,KACC,kBAAC,QAAD,EAAM,WAAU,uEAAwE,CAAA;GAIzF,KAAY,kBAAC,GAAD,EAAK,WAAU,wCAAyC,CAAA;GAGrE,kBAAC,QAAD;IAAM,WAAU;cAAY;IAAqB,CAAA;IAG/C,CAAC,KAAY,MACb,kBAAC,QAAD;IACE,YAAY,MAAM;AAChB,MAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EACjB,GAA8C;;IAGnD,MAAK;IACL,UAAU;IACV,SAAS;IACT,WAAW;;cAEP,IAAU,gBAAgB,oCAAoC;;IAElE,cAAY,GAAG,EAAG,uCAAuC,QAAQ,CAAC,GAAG;cAErE,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;IACnB,CAAA;GAEF"}
|
|
@@ -67,7 +67,7 @@ var x = ({ agent: x, onSearch: S, onShowShortcuts: C }) => {
|
|
|
67
67
|
} catch {}
|
|
68
68
|
}, [x, j]), te = R ? w.find((e) => e.sessionId === R) : null;
|
|
69
69
|
return /* @__PURE__ */ b("div", {
|
|
70
|
-
className: "flex items-stretch bg-bg-
|
|
70
|
+
className: "flex items-stretch bg-bg-surface border-b border-border-default w-full",
|
|
71
71
|
children: [
|
|
72
72
|
H && /* @__PURE__ */ y("button", {
|
|
73
73
|
type: "button",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentManagerTabBar.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerTabBar.tsx"],"sourcesContent":["/**\n * Browser-style tab bar for the Agent Manager.\n *\n * Horizontal scrolling tabs with a \"+\" button to create new sessions.\n * Supports drag-to-reorder via simple index swap.\n */\n\nimport { useRef, useState, useCallback, useEffect, type FC, type DragEvent } from 'react';\nimport {\n Plus,\n Download,\n ChevronLeft,\n ChevronRight,\n Search,\n HelpCircle,\n Maximize2,\n Minimize2,\n} from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { renameSession, createSession, type AgentRef } from '@/services/aiApi';\nimport { AgentManagerTab } from './AgentManagerTab';\nimport { RenameSessionDialog } from './dialogs/RenameSessionDialog';\nimport { ExportSessionDialog } from './dialogs/ExportSessionDialog';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerTabBarProps {\n agent: AgentRef;\n onSearch?: () => void;\n onShowShortcuts?: () => void;\n}\n\nexport const AgentManagerTabBar: FC<AgentManagerTabBarProps> = ({\n agent,\n onSearch,\n onShowShortcuts,\n}) => {\n const tabs = useAgentManagerStore((s) => s.tabs);\n const activeTabSessionId = useAgentManagerStore((s) => s.activeTabSessionId);\n const sessionStates = useAgentManagerStore((s) => s.sessionStates);\n const setActiveTab = useAgentManagerStore((s) => s.setActiveTab);\n const closeTab = useAgentManagerStore((s) => s.closeTab);\n const reorderTabs = useAgentManagerStore((s) => s.reorderTabs);\n const openSession = useAgentManagerStore((s) => s.openSession);\n const renameTab = useAgentManagerStore((s) => s.renameTab);\n const isFullscreen = useAgentManagerStore((s) => s.isFullscreen);\n const toggleFullscreen = useAgentManagerStore((s) => s.toggleFullscreen);\n const scrollRef = useRef<HTMLDivElement>(null);\n const tr = useTr();\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n const [renamingSessionId, setRenamingSessionId] = useState<string | null>(null);\n const [exportOpen, setExportOpen] = useState(false);\n const [showLeftArrow, setShowLeftArrow] = useState(false);\n const [showRightArrow, setShowRightArrow] = useState(false);\n\n const checkScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n setShowLeftArrow(el.scrollLeft > 0);\n setShowRightArrow(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);\n }, []);\n\n const scrollTabs = useCallback(\n (direction: 'left' | 'right') => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollBy({ left: direction === 'left' ? -200 : 200, behavior: 'smooth' });\n // Update arrow visibility after scroll animation\n setTimeout(checkScroll, 300);\n },\n [checkScroll]\n );\n\n useEffect(() => {\n checkScroll();\n }, [tabs.length, checkScroll]);\n\n // Re-check scroll whenever the container is resized\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n const ro = new ResizeObserver(() => checkScroll());\n ro.observe(el);\n return () => ro.disconnect();\n }, [checkScroll]);\n\n const bumpSessionsRefresh = useAgentManagerStore((s) => s.bumpSessionsRefresh);\n const handleNewSession = useCallback(async () => {\n try {\n const session = await createSession(agent, {\n name: `Session ${tabs.length + 1}`,\n agentType: 'claude',\n config: { model: 'default', mode: 'cli', tags: [] },\n });\n openSession(session.id, session.name);\n bumpSessionsRefresh();\n } catch (err) {\n console.error('[AgentManagerTabBar] createSession failed:', err);\n }\n }, [agent, tabs.length, openSession, bumpSessionsRefresh]);\n\n const handleDragStart = (e: DragEvent, index: number) => {\n setDragIndex(index);\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('text/plain', String(index));\n };\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n };\n\n const handleDrop = (e: DragEvent, dropIndex: number) => {\n e.preventDefault();\n if (dragIndex === null || dragIndex === dropIndex) return;\n\n const reordered = [...tabs];\n const [moved] = reordered.splice(dragIndex, 1);\n reordered.splice(dropIndex, 0, moved);\n\n // Update order values\n const updated = reordered.map((tab, i) => ({ ...tab, order: i }));\n reorderTabs(updated);\n setDragIndex(null);\n };\n\n const handleDragEnd = () => {\n setDragIndex(null);\n };\n\n const handleRename = useCallback(\n async (sessionId: string, newName: string) => {\n renameTab(sessionId, newName);\n try {\n await renameSession(agent, sessionId, newName);\n } catch {\n // Best-effort API sync -- local rename already applied\n }\n },\n [agent, renameTab]\n );\n\n const renamingTab = renamingSessionId\n ? tabs.find((t) => t.sessionId === renamingSessionId)\n : null;\n\n return (\n <div className=\"flex items-stretch bg-bg-primary border-b border-border-default w-full\">\n {showLeftArrow && (\n <button\n type=\"button\"\n onClick={() => scrollTabs('left')}\n className=\"flex-shrink-0 p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-r border-border-default\"\n aria-label=\"Scroll tabs left\"\n >\n <ChevronLeft className=\"size-3.5\" />\n </button>\n )}\n {/* Clip wrapper hides the browser scrollbar while keeping scroll functional */}\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <div\n ref={scrollRef}\n onScroll={checkScroll}\n className=\"flex items-stretch overflow-x-auto h-full\"\n style={{ scrollbarWidth: 'none' }}\n >\n {tabs.map((tab, index) => {\n const sessionState = sessionStates[tab.sessionId];\n const isProcessing =\n sessionState?.status === 'streaming' || sessionState?.status === 'processing';\n\n return (\n <div\n key={tab.sessionId}\n draggable\n onDragStart={(e) => handleDragStart(e, index)}\n onDragOver={handleDragOver}\n onDrop={(e) => handleDrop(e, index)}\n onDragEnd={handleDragEnd}\n className={`flex-shrink-0${dragIndex === index ? ' opacity-50' : ''}`}\n >\n <AgentManagerTab\n sessionId={tab.sessionId}\n name={tab.name}\n isActive={tab.sessionId === activeTabSessionId}\n isPinned={tab.pinned}\n isProcessing={isProcessing}\n onActivate={() => setActiveTab(tab.sessionId)}\n onClose={() => closeTab(tab.sessionId)}\n onRename={setRenamingSessionId}\n />\n </div>\n );\n })}\n </div>\n </div>\n {showRightArrow && (\n <button\n type=\"button\"\n onClick={() => scrollTabs('right')}\n className=\"flex-shrink-0 p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n aria-label=\"Scroll tabs right\"\n >\n <ChevronRight className=\"size-3.5\" />\n </button>\n )}\n\n {/* Export session button */}\n {activeTabSessionId && (\n <button\n type=\"button\"\n onClick={() => setExportOpen(true)}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr('vibecontrols.agentManager.tabBar.exportSession', 'Export session')}\n aria-label={tr('vibecontrols.agentManager.tabBar.exportSession', 'Export session')}\n >\n <Download className=\"size-4\" />\n </button>\n )}\n\n {/* New session button */}\n <button\n type=\"button\"\n onClick={handleNewSession}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr('vibecontrols.agentManager.tabBar.newSession', 'New session (Ctrl/Cmd+Shift+N)')}\n aria-label={tr('vibecontrols.agentManager.tabBar.createNewSession', 'Create new session')}\n >\n <Plus className=\"size-4\" />\n </button>\n\n {/* Search sessions */}\n {onSearch && (\n <button\n type=\"button\"\n onClick={onSearch}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr(\n 'vibecontrols.agentManager.tabBar.searchSessions',\n 'Search sessions (Ctrl/Cmd+Shift+K)'\n )}\n aria-label={tr('vibecontrols.agentManager.tabBar.searchSessions', 'Search sessions')}\n >\n <Search className=\"size-4\" />\n </button>\n )}\n\n {/* Keyboard shortcuts */}\n {onShowShortcuts && (\n <button\n type=\"button\"\n onClick={onShowShortcuts}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr('vibecontrols.agentManager.tabBar.keyboardShortcuts', 'Keyboard shortcuts')}\n aria-label={tr(\n 'vibecontrols.agentManager.tabBar.keyboardShortcuts',\n 'Keyboard shortcuts'\n )}\n >\n <HelpCircle className=\"size-4\" />\n </button>\n )}\n\n {/* Fullscreen toggle */}\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={\n isFullscreen\n ? tr('vibecontrols.agentManager.tabBar.exitFullscreen', 'Exit fullscreen')\n : tr('vibecontrols.agentManager.tabBar.enterFullscreen', 'Enter fullscreen')\n }\n aria-label={\n isFullscreen\n ? tr('vibecontrols.agentManager.tabBar.exitFullscreen', 'Exit fullscreen')\n : tr('vibecontrols.agentManager.tabBar.enterFullscreen', 'Enter fullscreen')\n }\n >\n {isFullscreen ? <Minimize2 className=\"size-4\" /> : <Maximize2 className=\"size-4\" />}\n </button>\n\n {/* Export session dialog */}\n <ExportSessionDialog\n isOpen={exportOpen}\n onClose={() => setExportOpen(false)}\n sessionId={activeTabSessionId ?? ''}\n agent={agent}\n />\n\n {/* Rename session dialog */}\n <RenameSessionDialog\n isOpen={renamingSessionId !== null}\n sessionId={renamingSessionId ?? ''}\n currentName={renamingTab?.name ?? ''}\n onClose={() => setRenamingSessionId(null)}\n onRename={(sessionId, newName) => void handleRename(sessionId, newName)}\n />\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;AA+BA,IAAa,KAAmD,EAC9D,UACA,aACA,yBACI;CACJ,IAAM,IAAO,GAAsB,MAAM,EAAE,KAAK,EAC1C,IAAqB,GAAsB,MAAM,EAAE,mBAAmB,EACtE,IAAgB,GAAsB,MAAM,EAAE,cAAc,EAC5D,IAAe,GAAsB,MAAM,EAAE,aAAa,EAC1D,IAAW,GAAsB,MAAM,EAAE,SAAS,EAClD,IAAc,GAAsB,MAAM,EAAE,YAAY,EACxD,IAAc,GAAsB,MAAM,EAAE,YAAY,EACxD,IAAY,GAAsB,MAAM,EAAE,UAAU,EACpD,IAAe,GAAsB,MAAM,EAAE,aAAa,EAC1D,IAAmB,GAAsB,MAAM,EAAE,iBAAiB,EAClE,IAAY,EAAuB,KAAK,EACxC,IAAK,GAAO,EACZ,CAAC,GAAW,KAAgB,EAAwB,KAAK,EACzD,CAAC,GAAmB,KAAwB,EAAwB,KAAK,EACzE,CAAC,GAAY,KAAiB,EAAS,GAAM,EAC7C,CAAC,GAAe,KAAoB,EAAS,GAAM,EACnD,CAAC,GAAgB,KAAqB,EAAS,GAAM,EAErD,IAAc,QAAkB;EACpC,IAAM,IAAK,EAAU;AAChB,QACL,EAAiB,EAAG,aAAa,EAAE,EACnC,EAAkB,EAAG,aAAa,EAAG,cAAc,EAAG,cAAc,EAAE;IACrE,EAAE,CAAC,EAEA,IAAa,GAChB,MAAgC;EAC/B,IAAM,IAAK,EAAU;AAChB,QACL,EAAG,SAAS;GAAE,MAAM,MAAc,SAAS,OAAO;GAAK,UAAU;GAAU,CAAC,EAE5E,WAAW,GAAa,IAAI;IAE9B,CAAC,EAAY,CACd;AAOD,CALA,QAAgB;AACd,KAAa;IACZ,CAAC,EAAK,QAAQ,EAAY,CAAC,EAG9B,QAAgB;EACd,IAAM,IAAK,EAAU;AACrB,MAAI,CAAC,EAAI;EACT,IAAM,IAAK,IAAI,qBAAqB,GAAa,CAAC;AAElD,SADA,EAAG,QAAQ,EAAG,QACD,EAAG,YAAY;IAC3B,CAAC,EAAY,CAAC;CAEjB,IAAM,IAAsB,GAAsB,MAAM,EAAE,oBAAoB,EACxE,IAAmB,EAAY,YAAY;AAC/C,MAAI;GACF,IAAM,IAAU,MAAM,EAAc,GAAO;IACzC,MAAM,WAAW,EAAK,SAAS;IAC/B,WAAW;IACX,QAAQ;KAAE,OAAO;KAAW,MAAM;KAAO,MAAM,EAAE;KAAE;IACpD,CAAC;AAEF,GADA,EAAY,EAAQ,IAAI,EAAQ,KAAK,EACrC,GAAqB;WACd,GAAK;AACZ,WAAQ,MAAM,8CAA8C,EAAI;;IAEjE;EAAC;EAAO,EAAK;EAAQ;EAAa;EAAoB,CAAC,EAEpD,KAAmB,GAAc,MAAkB;AAGvD,EAFA,EAAa,EAAM,EACnB,EAAE,aAAa,gBAAgB,QAC/B,EAAE,aAAa,QAAQ,cAAc,OAAO,EAAM,CAAC;IAG/C,KAAkB,MAAiB;AAEvC,EADA,EAAE,gBAAgB,EAClB,EAAE,aAAa,aAAa;IAGxB,KAAc,GAAc,MAAsB;AAEtD,MADA,EAAE,gBAAgB,EACd,MAAc,QAAQ,MAAc,EAAW;EAEnD,IAAM,IAAY,CAAC,GAAG,EAAK,EACrB,CAAC,KAAS,EAAU,OAAO,GAAW,EAAE;AAM9C,EALA,EAAU,OAAO,GAAW,GAAG,EAAM,EAIrC,EADgB,EAAU,KAAK,GAAK,OAAO;GAAE,GAAG;GAAK,OAAO;GAAG,EAAE,CAC7C,EACpB,EAAa,KAAK;IAGd,UAAsB;AAC1B,IAAa,KAAK;IAGd,KAAe,EACnB,OAAO,GAAmB,MAAoB;AAC5C,IAAU,GAAW,EAAQ;AAC7B,MAAI;AACF,SAAM,EAAc,GAAO,GAAW,EAAQ;UACxC;IAIV,CAAC,GAAO,EAAU,CACnB,EAEK,KAAc,IAChB,EAAK,MAAM,MAAM,EAAE,cAAc,EAAkB,GACnD;AAEJ,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACG,KACC,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,OAAO;IACjC,WAAU;IACV,cAAW;cAEX,kBAAC,GAAD,EAAa,WAAU,YAAa,CAAA;IAC7B,CAAA;GAGX,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KACE,KAAK;KACL,UAAU;KACV,WAAU;KACV,OAAO,EAAE,gBAAgB,QAAQ;eAEhC,EAAK,KAAK,GAAK,MAAU;MACxB,IAAM,IAAe,EAAc,EAAI,YACjC,IACJ,GAAc,WAAW,eAAe,GAAc,WAAW;AAEnE,aACE,kBAAC,OAAD;OAEE,WAAA;OACA,cAAc,MAAM,EAAgB,GAAG,EAAM;OAC7C,YAAY;OACZ,SAAS,MAAM,EAAW,GAAG,EAAM;OACnC,WAAW;OACX,WAAW,gBAAgB,MAAc,IAAQ,gBAAgB;iBAEjE,kBAAC,GAAD;QACE,WAAW,EAAI;QACf,MAAM,EAAI;QACV,UAAU,EAAI,cAAc;QAC5B,UAAU,EAAI;QACA;QACd,kBAAkB,EAAa,EAAI,UAAU;QAC7C,eAAe,EAAS,EAAI,UAAU;QACtC,UAAU;QACV,CAAA;OACE,EAlBC,EAAI,UAkBL;OAER;KACE,CAAA;IACF,CAAA;GACL,KACC,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,QAAQ;IAClC,WAAU;IACV,cAAW;cAEX,kBAAC,GAAD,EAAc,WAAU,YAAa,CAAA;IAC9B,CAAA;GAIV,KACC,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAc,GAAK;IAClC,WAAU;IACV,OAAO,EAAG,kDAAkD,iBAAiB;IAC7E,cAAY,EAAG,kDAAkD,iBAAiB;cAElF,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;IACxB,CAAA;GAIX,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IACV,OAAO,EAAG,+CAA+C,iCAAiC;IAC1F,cAAY,EAAG,qDAAqD,qBAAqB;cAEzF,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;IACpB,CAAA;GAGR,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IACV,OAAO,EACL,mDACA,qCACD;IACD,cAAY,EAAG,mDAAmD,kBAAkB;cAEpF,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;IACtB,CAAA;GAIV,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IACV,OAAO,EAAG,sDAAsD,qBAAqB;IACrF,cAAY,EACV,sDACA,qBACD;cAED,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;IAC1B,CAAA;GAIX,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IACV,OACE,IACI,EAAG,mDAAmD,kBAAkB,GACxE,EAAG,oDAAoD,mBAAmB;IAEhF,cACE,IACI,EAAG,mDAAmD,kBAAkB,GACxE,EAAG,oDAAoD,mBAAmB;cAGhE,EAAf,IAAgB,IAAmC,GAApC,EAAW,WAAU,UAAW,CAAmC;IAC5E,CAAA;GAGT,kBAAC,GAAD;IACE,QAAQ;IACR,eAAe,EAAc,GAAM;IACnC,WAAW,KAAsB;IAC1B;IACP,CAAA;GAGF,kBAAC,GAAD;IACE,QAAQ,MAAsB;IAC9B,WAAW,KAAqB;IAChC,aAAa,IAAa,QAAQ;IAClC,eAAe,EAAqB,KAAK;IACzC,WAAW,GAAW,MAAY,KAAK,GAAa,GAAW,EAAQ;IACvE,CAAA;GACE"}
|
|
1
|
+
{"version":3,"file":"AgentManagerTabBar.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerTabBar.tsx"],"sourcesContent":["/**\n * Browser-style tab bar for the Agent Manager.\n *\n * Horizontal scrolling tabs with a \"+\" button to create new sessions.\n * Supports drag-to-reorder via simple index swap.\n */\n\nimport { useRef, useState, useCallback, useEffect, type FC, type DragEvent } from 'react';\nimport {\n Plus,\n Download,\n ChevronLeft,\n ChevronRight,\n Search,\n HelpCircle,\n Maximize2,\n Minimize2,\n} from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { renameSession, createSession, type AgentRef } from '@/services/aiApi';\nimport { AgentManagerTab } from './AgentManagerTab';\nimport { RenameSessionDialog } from './dialogs/RenameSessionDialog';\nimport { ExportSessionDialog } from './dialogs/ExportSessionDialog';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerTabBarProps {\n agent: AgentRef;\n onSearch?: () => void;\n onShowShortcuts?: () => void;\n}\n\nexport const AgentManagerTabBar: FC<AgentManagerTabBarProps> = ({\n agent,\n onSearch,\n onShowShortcuts,\n}) => {\n const tabs = useAgentManagerStore((s) => s.tabs);\n const activeTabSessionId = useAgentManagerStore((s) => s.activeTabSessionId);\n const sessionStates = useAgentManagerStore((s) => s.sessionStates);\n const setActiveTab = useAgentManagerStore((s) => s.setActiveTab);\n const closeTab = useAgentManagerStore((s) => s.closeTab);\n const reorderTabs = useAgentManagerStore((s) => s.reorderTabs);\n const openSession = useAgentManagerStore((s) => s.openSession);\n const renameTab = useAgentManagerStore((s) => s.renameTab);\n const isFullscreen = useAgentManagerStore((s) => s.isFullscreen);\n const toggleFullscreen = useAgentManagerStore((s) => s.toggleFullscreen);\n const scrollRef = useRef<HTMLDivElement>(null);\n const tr = useTr();\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n const [renamingSessionId, setRenamingSessionId] = useState<string | null>(null);\n const [exportOpen, setExportOpen] = useState(false);\n const [showLeftArrow, setShowLeftArrow] = useState(false);\n const [showRightArrow, setShowRightArrow] = useState(false);\n\n const checkScroll = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n setShowLeftArrow(el.scrollLeft > 0);\n setShowRightArrow(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);\n }, []);\n\n const scrollTabs = useCallback(\n (direction: 'left' | 'right') => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollBy({ left: direction === 'left' ? -200 : 200, behavior: 'smooth' });\n // Update arrow visibility after scroll animation\n setTimeout(checkScroll, 300);\n },\n [checkScroll]\n );\n\n useEffect(() => {\n checkScroll();\n }, [tabs.length, checkScroll]);\n\n // Re-check scroll whenever the container is resized\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n const ro = new ResizeObserver(() => checkScroll());\n ro.observe(el);\n return () => ro.disconnect();\n }, [checkScroll]);\n\n const bumpSessionsRefresh = useAgentManagerStore((s) => s.bumpSessionsRefresh);\n const handleNewSession = useCallback(async () => {\n try {\n const session = await createSession(agent, {\n name: `Session ${tabs.length + 1}`,\n agentType: 'claude',\n config: { model: 'default', mode: 'cli', tags: [] },\n });\n openSession(session.id, session.name);\n bumpSessionsRefresh();\n } catch (err) {\n console.error('[AgentManagerTabBar] createSession failed:', err);\n }\n }, [agent, tabs.length, openSession, bumpSessionsRefresh]);\n\n const handleDragStart = (e: DragEvent, index: number) => {\n setDragIndex(index);\n e.dataTransfer.effectAllowed = 'move';\n e.dataTransfer.setData('text/plain', String(index));\n };\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n };\n\n const handleDrop = (e: DragEvent, dropIndex: number) => {\n e.preventDefault();\n if (dragIndex === null || dragIndex === dropIndex) return;\n\n const reordered = [...tabs];\n const [moved] = reordered.splice(dragIndex, 1);\n reordered.splice(dropIndex, 0, moved);\n\n // Update order values\n const updated = reordered.map((tab, i) => ({ ...tab, order: i }));\n reorderTabs(updated);\n setDragIndex(null);\n };\n\n const handleDragEnd = () => {\n setDragIndex(null);\n };\n\n const handleRename = useCallback(\n async (sessionId: string, newName: string) => {\n renameTab(sessionId, newName);\n try {\n await renameSession(agent, sessionId, newName);\n } catch {\n // Best-effort API sync -- local rename already applied\n }\n },\n [agent, renameTab]\n );\n\n const renamingTab = renamingSessionId\n ? tabs.find((t) => t.sessionId === renamingSessionId)\n : null;\n\n return (\n <div className=\"flex items-stretch bg-bg-surface border-b border-border-default w-full\">\n {showLeftArrow && (\n <button\n type=\"button\"\n onClick={() => scrollTabs('left')}\n className=\"flex-shrink-0 p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-r border-border-default\"\n aria-label=\"Scroll tabs left\"\n >\n <ChevronLeft className=\"size-3.5\" />\n </button>\n )}\n {/* Clip wrapper hides the browser scrollbar while keeping scroll functional */}\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <div\n ref={scrollRef}\n onScroll={checkScroll}\n className=\"flex items-stretch overflow-x-auto h-full\"\n style={{ scrollbarWidth: 'none' }}\n >\n {tabs.map((tab, index) => {\n const sessionState = sessionStates[tab.sessionId];\n const isProcessing =\n sessionState?.status === 'streaming' || sessionState?.status === 'processing';\n\n return (\n <div\n key={tab.sessionId}\n draggable\n onDragStart={(e) => handleDragStart(e, index)}\n onDragOver={handleDragOver}\n onDrop={(e) => handleDrop(e, index)}\n onDragEnd={handleDragEnd}\n className={`flex-shrink-0${dragIndex === index ? ' opacity-50' : ''}`}\n >\n <AgentManagerTab\n sessionId={tab.sessionId}\n name={tab.name}\n isActive={tab.sessionId === activeTabSessionId}\n isPinned={tab.pinned}\n isProcessing={isProcessing}\n onActivate={() => setActiveTab(tab.sessionId)}\n onClose={() => closeTab(tab.sessionId)}\n onRename={setRenamingSessionId}\n />\n </div>\n );\n })}\n </div>\n </div>\n {showRightArrow && (\n <button\n type=\"button\"\n onClick={() => scrollTabs('right')}\n className=\"flex-shrink-0 p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n aria-label=\"Scroll tabs right\"\n >\n <ChevronRight className=\"size-3.5\" />\n </button>\n )}\n\n {/* Export session button */}\n {activeTabSessionId && (\n <button\n type=\"button\"\n onClick={() => setExportOpen(true)}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr('vibecontrols.agentManager.tabBar.exportSession', 'Export session')}\n aria-label={tr('vibecontrols.agentManager.tabBar.exportSession', 'Export session')}\n >\n <Download className=\"size-4\" />\n </button>\n )}\n\n {/* New session button */}\n <button\n type=\"button\"\n onClick={handleNewSession}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr('vibecontrols.agentManager.tabBar.newSession', 'New session (Ctrl/Cmd+Shift+N)')}\n aria-label={tr('vibecontrols.agentManager.tabBar.createNewSession', 'Create new session')}\n >\n <Plus className=\"size-4\" />\n </button>\n\n {/* Search sessions */}\n {onSearch && (\n <button\n type=\"button\"\n onClick={onSearch}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr(\n 'vibecontrols.agentManager.tabBar.searchSessions',\n 'Search sessions (Ctrl/Cmd+Shift+K)'\n )}\n aria-label={tr('vibecontrols.agentManager.tabBar.searchSessions', 'Search sessions')}\n >\n <Search className=\"size-4\" />\n </button>\n )}\n\n {/* Keyboard shortcuts */}\n {onShowShortcuts && (\n <button\n type=\"button\"\n onClick={onShowShortcuts}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={tr('vibecontrols.agentManager.tabBar.keyboardShortcuts', 'Keyboard shortcuts')}\n aria-label={tr(\n 'vibecontrols.agentManager.tabBar.keyboardShortcuts',\n 'Keyboard shortcuts'\n )}\n >\n <HelpCircle className=\"size-4\" />\n </button>\n )}\n\n {/* Fullscreen toggle */}\n <button\n type=\"button\"\n onClick={toggleFullscreen}\n className=\"flex-shrink-0 px-2 py-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-elevated transition-colors border-l border-border-default\"\n title={\n isFullscreen\n ? tr('vibecontrols.agentManager.tabBar.exitFullscreen', 'Exit fullscreen')\n : tr('vibecontrols.agentManager.tabBar.enterFullscreen', 'Enter fullscreen')\n }\n aria-label={\n isFullscreen\n ? tr('vibecontrols.agentManager.tabBar.exitFullscreen', 'Exit fullscreen')\n : tr('vibecontrols.agentManager.tabBar.enterFullscreen', 'Enter fullscreen')\n }\n >\n {isFullscreen ? <Minimize2 className=\"size-4\" /> : <Maximize2 className=\"size-4\" />}\n </button>\n\n {/* Export session dialog */}\n <ExportSessionDialog\n isOpen={exportOpen}\n onClose={() => setExportOpen(false)}\n sessionId={activeTabSessionId ?? ''}\n agent={agent}\n />\n\n {/* Rename session dialog */}\n <RenameSessionDialog\n isOpen={renamingSessionId !== null}\n sessionId={renamingSessionId ?? ''}\n currentName={renamingTab?.name ?? ''}\n onClose={() => setRenamingSessionId(null)}\n onRename={(sessionId, newName) => void handleRename(sessionId, newName)}\n />\n </div>\n );\n};\n"],"mappings":"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"}
|