@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
|
@@ -188,7 +188,7 @@ function A({ sdk: i, mode: a, providers: s = [], onSdkChange: c, onModeChange: l
|
|
|
188
188
|
let t = k(n, e.value, a);
|
|
189
189
|
c(e.value), t !== a && l(t), d(!1);
|
|
190
190
|
},
|
|
191
|
-
className: `w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-bg-elevated transition-colors ${e.value === i ? "text-
|
|
191
|
+
className: `w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-bg-elevated transition-colors ${e.value === i ? "text-text-primary bg-[var(--color-accent-soft)]" : "text-text-primary"}`,
|
|
192
192
|
children: [
|
|
193
193
|
/* @__PURE__ */ b(t, { className: "size-4" }),
|
|
194
194
|
/* @__PURE__ */ b("span", { children: e.label }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SdkSelector.js","names":[],"sources":["../../../../src/components/agent-manager/controls/SdkSelector.tsx"],"sourcesContent":["/**\n * SDK + mode selector dropdown.\n *\n * Shows the active SDK with an icon. The dropdown lists all available SDKs\n * and includes a mode toggle (SDK / CLI) at the bottom.\n */\n\nimport { useState, useRef, useEffect, useCallback } from 'react';\nimport {\n Brain,\n Code,\n Sparkles,\n Terminal,\n Bird,\n Zap,\n Github,\n Hammer,\n Cpu,\n PenTool,\n Map as MapIcon,\n ChevronDown,\n MousePointerClick,\n Network,\n Wand2,\n CloudCog,\n} from 'lucide-react';\nimport type { AgentSdkType, ProviderMode } from '@/types/agentManager';\nimport type { AIProvider } from '@/services/aiApi';\n\ninterface SdkSelectorProps {\n sdk: AgentSdkType;\n mode: ProviderMode;\n providers?: AIProvider[];\n onSdkChange: (sdk: AgentSdkType) => void;\n onModeChange: (mode: ProviderMode) => void;\n}\n\nconst SDK_OPTIONS: Array<{ value: AgentSdkType; label: string; icon: typeof Brain }> = [\n { value: 'claude', label: 'Claude', icon: Brain },\n { value: 'codex', label: 'Codex', icon: Code },\n { value: 'gemini', label: 'Gemini', icon: Sparkles },\n { value: 'opencode', label: 'OpenCode', icon: Terminal },\n { value: 'cursor', label: 'Cursor', icon: MousePointerClick },\n { value: 'openrouter', label: 'OpenRouter', icon: Network },\n { value: 'minimax', label: 'Minimax', icon: Wand2 },\n { value: 'ollama', label: 'Ollama', icon: CloudCog },\n { value: 'openai-compat', label: 'OpenAI-compatible', icon: Brain },\n { value: 'goose', label: 'Goose', icon: Bird },\n { value: 'amp', label: 'Amp', icon: Zap },\n { value: 'copilot', label: 'Copilot', icon: Github },\n { value: 'crush', label: 'Crush', icon: Hammer },\n { value: 'pi', label: 'Pi', icon: Cpu },\n { value: 'aider', label: 'Aider', icon: PenTool },\n { value: 'plandex', label: 'Plandex', icon: MapIcon },\n];\n\n// Fallback when the agent-side `provider.supportedModes` isn't available\n// (offline / fresh install / older meta-plugin). The runtime path through\n// `providerModes()` below prefers the live value when present so adding\n// a new provider here is only a fallback affordance.\nconst STATIC_MODE_SUPPORT: Record<AgentSdkType, ProviderMode[]> = {\n claude: ['sdk', 'cli'],\n codex: ['sdk', 'cli'],\n gemini: ['sdk', 'cli'],\n opencode: ['sdk', 'cli'],\n cursor: ['sdk', 'cli'],\n openrouter: ['sdk'],\n minimax: ['sdk', 'cli'],\n ollama: ['sdk', 'cli'],\n 'openai-compat': ['sdk'],\n goose: ['cli'],\n amp: ['cli'],\n copilot: ['cli'],\n crush: ['cli'],\n pi: ['cli'],\n aider: ['cli'],\n plandex: ['cli'],\n};\n\nconst ALL_MODES: ProviderMode[] = ['sdk', 'cli'];\nconst SDK_VALUES = new Set(SDK_OPTIONS.map((option) => option.value));\n\nfunction isProviderMode(mode: unknown): mode is ProviderMode {\n return mode === 'sdk' || mode === 'cli';\n}\n\nfunction normalizeProviderSdk(provider: AIProvider): AgentSdkType | null {\n const value = (provider.name || provider.pluginName).replace(/^ai-/, '');\n return SDK_VALUES.has(value as AgentSdkType) ? (value as AgentSdkType) : null;\n}\n\nfunction providerModes(provider: AIProvider | undefined, sdk: AgentSdkType): ProviderMode[] {\n const modes = provider?.supportedModes?.filter(isProviderMode);\n return modes && modes.length > 0 ? modes : STATIC_MODE_SUPPORT[sdk];\n}\n\nfunction nextSupportedMode(\n provider: AIProvider | undefined,\n sdk: AgentSdkType,\n currentMode: ProviderMode\n): ProviderMode {\n const supported = providerModes(provider, sdk);\n if (supported.includes(currentMode)) return currentMode;\n if (provider?.defaultMode && supported.includes(provider.defaultMode))\n return provider.defaultMode;\n if (provider?.currentMode && supported.includes(provider.currentMode))\n return provider.currentMode;\n return supported[0] ?? 'cli';\n}\n\nexport function SdkSelector({\n sdk,\n mode,\n providers = [],\n onSdkChange,\n onModeChange,\n}: SdkSelectorProps) {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState('');\n const containerRef = useRef<HTMLDivElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [pos, setPos] = useState({ bottom: 0, left: 0, width: 0 });\n\n const providerBySdk = new Map<AgentSdkType, AIProvider>();\n for (const provider of providers) {\n const providerSdk = normalizeProviderSdk(provider);\n if (providerSdk) providerBySdk.set(providerSdk, provider);\n }\n\n const options = (\n providerBySdk.size > 0\n ? SDK_OPTIONS.filter((option) => providerBySdk.has(option.value))\n : SDK_OPTIONS\n ).map((option) => ({\n ...option,\n label: providerBySdk.get(option.value)?.displayName ?? option.label,\n }));\n\n const current = options.find((o) => o.value === sdk) ?? SDK_OPTIONS[0];\n const CurrentIcon = current.icon;\n const currentProvider = providerBySdk.get(sdk);\n const currentModes = providerModes(currentProvider, sdk);\n\n const handleClickOutside = useCallback((e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n }, []);\n\n useEffect(() => {\n if (open) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [open, handleClickOutside]);\n\n useEffect(() => {\n if (!open) setSearch('');\n }, [open]);\n\n const filtered = options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()));\n\n const handleToggle = () => {\n if (!open && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n setPos({\n bottom: window.innerHeight - rect.top + 4,\n left: rect.left,\n width: Math.max(rect.width, 192),\n });\n }\n setOpen((prev) => !prev);\n };\n\n return (\n <div ref={containerRef} className=\"relative\">\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleToggle}\n className=\"flex items-center gap-1.5 px-2 py-1 text-xs font-medium rounded border border-border-default bg-bg-surface text-text-secondary hover:text-text-primary hover:border-border-strong transition-colors\"\n title={`${current.label} (${mode.toUpperCase()})`}\n >\n <CurrentIcon className=\"size-3.5\" />\n <span>{current.label}</span>\n <ChevronDown className=\"size-3\" />\n </button>\n\n {open && (\n <div\n className=\"fixed rounded-lg border border-border-default bg-bg-surface shadow-lg z-[100]\"\n style={{ bottom: pos.bottom, left: pos.left, minWidth: pos.width }}\n >\n {/* Search */}\n <input\n aria-label=\"Search...\"\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search...\"\n className=\"w-full px-3 py-1.5 text-xs border-b border-border-default bg-transparent text-text-primary placeholder:text-text-tertiary focus:outline-none\"\n />\n {/* SDK list */}\n <div className=\"py-1 max-h-48 overflow-y-auto\">\n {filtered.map((option) => {\n const Icon = option.icon;\n const optionProvider = providerBySdk.get(option.value);\n const modes = providerModes(optionProvider, option.value);\n return (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => {\n const nextMode = nextSupportedMode(optionProvider, option.value, mode);\n onSdkChange(option.value);\n if (nextMode !== mode) onModeChange(nextMode);\n setOpen(false);\n }}\n className={`w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-bg-elevated transition-colors ${\n option.value === sdk\n ? 'text-action-primary-text bg-action-primary-bg/10'\n : 'text-text-primary'\n }`}\n >\n <Icon className=\"size-4\" />\n <span>{option.label}</span>\n <span className=\"ml-auto flex items-center gap-1\">\n {ALL_MODES.map((optionMode) => (\n <span\n key={optionMode}\n className={`rounded px-1 py-0.5 text-[10px] font-semibold uppercase ${\n modes.includes(optionMode)\n ? 'bg-bg-sunken text-text-secondary'\n : 'border border-border-default text-text-tertiary opacity-50'\n }`}\n >\n {optionMode}\n </span>\n ))}\n </span>\n </button>\n );\n })}\n </div>\n\n {/* Mode toggle */}\n <div className=\"border-t border-border-default px-3 py-2\">\n <div className=\"flex items-center rounded-md bg-bg-sunken p-0.5\">\n <button\n type=\"button\"\n onClick={() => currentModes.includes('sdk') && onModeChange('sdk')}\n disabled={!currentModes.includes('sdk')}\n className={`flex-1 px-2 py-1 text-xs font-medium rounded transition-colors disabled:cursor-not-allowed disabled:opacity-40 ${\n mode === 'sdk'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n currentModes.includes('sdk')\n ? 'Use SDK mode'\n : `${current.label} does not support SDK mode`\n }\n >\n SDK\n </button>\n <button\n type=\"button\"\n onClick={() => currentModes.includes('cli') && onModeChange('cli')}\n disabled={!currentModes.includes('cli')}\n className={`flex-1 px-2 py-1 text-xs font-medium rounded transition-colors disabled:cursor-not-allowed disabled:opacity-40 ${\n mode === 'cli'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n currentModes.includes('cli')\n ? 'Use CLI mode'\n : `${current.label} does not support CLI mode`\n }\n >\n CLI\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SdkSelector.js","names":[],"sources":["../../../../src/components/agent-manager/controls/SdkSelector.tsx"],"sourcesContent":["/**\n * SDK + mode selector dropdown.\n *\n * Shows the active SDK with an icon. The dropdown lists all available SDKs\n * and includes a mode toggle (SDK / CLI) at the bottom.\n */\n\nimport { useState, useRef, useEffect, useCallback } from 'react';\nimport {\n Brain,\n Code,\n Sparkles,\n Terminal,\n Bird,\n Zap,\n Github,\n Hammer,\n Cpu,\n PenTool,\n Map as MapIcon,\n ChevronDown,\n MousePointerClick,\n Network,\n Wand2,\n CloudCog,\n} from 'lucide-react';\nimport type { AgentSdkType, ProviderMode } from '@/types/agentManager';\nimport type { AIProvider } from '@/services/aiApi';\n\ninterface SdkSelectorProps {\n sdk: AgentSdkType;\n mode: ProviderMode;\n providers?: AIProvider[];\n onSdkChange: (sdk: AgentSdkType) => void;\n onModeChange: (mode: ProviderMode) => void;\n}\n\nconst SDK_OPTIONS: Array<{ value: AgentSdkType; label: string; icon: typeof Brain }> = [\n { value: 'claude', label: 'Claude', icon: Brain },\n { value: 'codex', label: 'Codex', icon: Code },\n { value: 'gemini', label: 'Gemini', icon: Sparkles },\n { value: 'opencode', label: 'OpenCode', icon: Terminal },\n { value: 'cursor', label: 'Cursor', icon: MousePointerClick },\n { value: 'openrouter', label: 'OpenRouter', icon: Network },\n { value: 'minimax', label: 'Minimax', icon: Wand2 },\n { value: 'ollama', label: 'Ollama', icon: CloudCog },\n { value: 'openai-compat', label: 'OpenAI-compatible', icon: Brain },\n { value: 'goose', label: 'Goose', icon: Bird },\n { value: 'amp', label: 'Amp', icon: Zap },\n { value: 'copilot', label: 'Copilot', icon: Github },\n { value: 'crush', label: 'Crush', icon: Hammer },\n { value: 'pi', label: 'Pi', icon: Cpu },\n { value: 'aider', label: 'Aider', icon: PenTool },\n { value: 'plandex', label: 'Plandex', icon: MapIcon },\n];\n\n// Fallback when the agent-side `provider.supportedModes` isn't available\n// (offline / fresh install / older meta-plugin). The runtime path through\n// `providerModes()` below prefers the live value when present so adding\n// a new provider here is only a fallback affordance.\nconst STATIC_MODE_SUPPORT: Record<AgentSdkType, ProviderMode[]> = {\n claude: ['sdk', 'cli'],\n codex: ['sdk', 'cli'],\n gemini: ['sdk', 'cli'],\n opencode: ['sdk', 'cli'],\n cursor: ['sdk', 'cli'],\n openrouter: ['sdk'],\n minimax: ['sdk', 'cli'],\n ollama: ['sdk', 'cli'],\n 'openai-compat': ['sdk'],\n goose: ['cli'],\n amp: ['cli'],\n copilot: ['cli'],\n crush: ['cli'],\n pi: ['cli'],\n aider: ['cli'],\n plandex: ['cli'],\n};\n\nconst ALL_MODES: ProviderMode[] = ['sdk', 'cli'];\nconst SDK_VALUES = new Set(SDK_OPTIONS.map((option) => option.value));\n\nfunction isProviderMode(mode: unknown): mode is ProviderMode {\n return mode === 'sdk' || mode === 'cli';\n}\n\nfunction normalizeProviderSdk(provider: AIProvider): AgentSdkType | null {\n const value = (provider.name || provider.pluginName).replace(/^ai-/, '');\n return SDK_VALUES.has(value as AgentSdkType) ? (value as AgentSdkType) : null;\n}\n\nfunction providerModes(provider: AIProvider | undefined, sdk: AgentSdkType): ProviderMode[] {\n const modes = provider?.supportedModes?.filter(isProviderMode);\n return modes && modes.length > 0 ? modes : STATIC_MODE_SUPPORT[sdk];\n}\n\nfunction nextSupportedMode(\n provider: AIProvider | undefined,\n sdk: AgentSdkType,\n currentMode: ProviderMode\n): ProviderMode {\n const supported = providerModes(provider, sdk);\n if (supported.includes(currentMode)) return currentMode;\n if (provider?.defaultMode && supported.includes(provider.defaultMode))\n return provider.defaultMode;\n if (provider?.currentMode && supported.includes(provider.currentMode))\n return provider.currentMode;\n return supported[0] ?? 'cli';\n}\n\nexport function SdkSelector({\n sdk,\n mode,\n providers = [],\n onSdkChange,\n onModeChange,\n}: SdkSelectorProps) {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState('');\n const containerRef = useRef<HTMLDivElement>(null);\n const buttonRef = useRef<HTMLButtonElement>(null);\n const [pos, setPos] = useState({ bottom: 0, left: 0, width: 0 });\n\n const providerBySdk = new Map<AgentSdkType, AIProvider>();\n for (const provider of providers) {\n const providerSdk = normalizeProviderSdk(provider);\n if (providerSdk) providerBySdk.set(providerSdk, provider);\n }\n\n const options = (\n providerBySdk.size > 0\n ? SDK_OPTIONS.filter((option) => providerBySdk.has(option.value))\n : SDK_OPTIONS\n ).map((option) => ({\n ...option,\n label: providerBySdk.get(option.value)?.displayName ?? option.label,\n }));\n\n const current = options.find((o) => o.value === sdk) ?? SDK_OPTIONS[0];\n const CurrentIcon = current.icon;\n const currentProvider = providerBySdk.get(sdk);\n const currentModes = providerModes(currentProvider, sdk);\n\n const handleClickOutside = useCallback((e: MouseEvent) => {\n if (containerRef.current && !containerRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n }, []);\n\n useEffect(() => {\n if (open) {\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }\n }, [open, handleClickOutside]);\n\n useEffect(() => {\n if (!open) setSearch('');\n }, [open]);\n\n const filtered = options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()));\n\n const handleToggle = () => {\n if (!open && buttonRef.current) {\n const rect = buttonRef.current.getBoundingClientRect();\n setPos({\n bottom: window.innerHeight - rect.top + 4,\n left: rect.left,\n width: Math.max(rect.width, 192),\n });\n }\n setOpen((prev) => !prev);\n };\n\n return (\n <div ref={containerRef} className=\"relative\">\n <button\n ref={buttonRef}\n type=\"button\"\n onClick={handleToggle}\n className=\"flex items-center gap-1.5 px-2 py-1 text-xs font-medium rounded border border-border-default bg-bg-surface text-text-secondary hover:text-text-primary hover:border-border-strong transition-colors\"\n title={`${current.label} (${mode.toUpperCase()})`}\n >\n <CurrentIcon className=\"size-3.5\" />\n <span>{current.label}</span>\n <ChevronDown className=\"size-3\" />\n </button>\n\n {open && (\n <div\n className=\"fixed rounded-lg border border-border-default bg-bg-surface shadow-lg z-[100]\"\n style={{ bottom: pos.bottom, left: pos.left, minWidth: pos.width }}\n >\n {/* Search */}\n <input\n aria-label=\"Search...\"\n type=\"text\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search...\"\n className=\"w-full px-3 py-1.5 text-xs border-b border-border-default bg-transparent text-text-primary placeholder:text-text-tertiary focus:outline-none\"\n />\n {/* SDK list */}\n <div className=\"py-1 max-h-48 overflow-y-auto\">\n {filtered.map((option) => {\n const Icon = option.icon;\n const optionProvider = providerBySdk.get(option.value);\n const modes = providerModes(optionProvider, option.value);\n return (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => {\n const nextMode = nextSupportedMode(optionProvider, option.value, mode);\n onSdkChange(option.value);\n if (nextMode !== mode) onModeChange(nextMode);\n setOpen(false);\n }}\n className={`w-full flex items-center gap-2 px-3 py-2 text-sm hover:bg-bg-elevated transition-colors ${\n option.value === sdk\n ? 'text-text-primary bg-[var(--color-accent-soft)]'\n : 'text-text-primary'\n }`}\n >\n <Icon className=\"size-4\" />\n <span>{option.label}</span>\n <span className=\"ml-auto flex items-center gap-1\">\n {ALL_MODES.map((optionMode) => (\n <span\n key={optionMode}\n className={`rounded px-1 py-0.5 text-[10px] font-semibold uppercase ${\n modes.includes(optionMode)\n ? 'bg-bg-sunken text-text-secondary'\n : 'border border-border-default text-text-tertiary opacity-50'\n }`}\n >\n {optionMode}\n </span>\n ))}\n </span>\n </button>\n );\n })}\n </div>\n\n {/* Mode toggle */}\n <div className=\"border-t border-border-default px-3 py-2\">\n <div className=\"flex items-center rounded-md bg-bg-sunken p-0.5\">\n <button\n type=\"button\"\n onClick={() => currentModes.includes('sdk') && onModeChange('sdk')}\n disabled={!currentModes.includes('sdk')}\n className={`flex-1 px-2 py-1 text-xs font-medium rounded transition-colors disabled:cursor-not-allowed disabled:opacity-40 ${\n mode === 'sdk'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n currentModes.includes('sdk')\n ? 'Use SDK mode'\n : `${current.label} does not support SDK mode`\n }\n >\n SDK\n </button>\n <button\n type=\"button\"\n onClick={() => currentModes.includes('cli') && onModeChange('cli')}\n disabled={!currentModes.includes('cli')}\n className={`flex-1 px-2 py-1 text-xs font-medium rounded transition-colors disabled:cursor-not-allowed disabled:opacity-40 ${\n mode === 'cli'\n ? 'bg-bg-surface text-text-primary shadow-sm'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n currentModes.includes('cli')\n ? 'Use CLI mode'\n : `${current.label} does not support CLI mode`\n }\n >\n CLI\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,7 +7,7 @@ function r({ enabled: r, onToggle: i, isListening: a = !1 }) {
|
|
|
7
7
|
return /* @__PURE__ */ n("button", {
|
|
8
8
|
type: "button",
|
|
9
9
|
onClick: i,
|
|
10
|
-
className: `p-1.5 rounded transition-colors ${a ? "bg-status-error-bg text-status-error-text animate-pulse" : r ? "bg-
|
|
10
|
+
className: `p-1.5 rounded transition-colors ${a ? "bg-status-error-bg-subtle text-status-error-text animate-pulse" : r ? "bg-[var(--color-accent-soft)] text-text-primary hover:bg-[var(--color-accent-soft)]" : "text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated"}`,
|
|
11
11
|
title: a ? o("vibecontrols.agentManager.controls.listening", "Listening...") : r ? o("vibecontrols.agentManager.controls.disableVoice", "Disable voice mode") : o("vibecontrols.agentManager.controls.enableVoice", "Enable voice mode"),
|
|
12
12
|
children: /* @__PURE__ */ n(t, { className: "size-4" })
|
|
13
13
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VoiceToggle.js","names":[],"sources":["../../../../src/components/agent-manager/controls/VoiceToggle.tsx"],"sourcesContent":["/**\n * Voice mode toggle button.\n *\n * Mic icon that toggles voice input. Turns red when actively listening.\n */\n\nimport { Mic } from 'lucide-react';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface VoiceToggleProps {\n enabled: boolean;\n onToggle: () => void;\n isListening?: boolean;\n}\n\nexport function VoiceToggle({ enabled, onToggle, isListening = false }: VoiceToggleProps) {\n const tr = useTr();\n\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n className={`p-1.5 rounded transition-colors ${\n isListening\n ? 'bg-status-error-bg text-status-error-text animate-pulse'\n : enabled\n ? 'bg-
|
|
1
|
+
{"version":3,"file":"VoiceToggle.js","names":[],"sources":["../../../../src/components/agent-manager/controls/VoiceToggle.tsx"],"sourcesContent":["/**\n * Voice mode toggle button.\n *\n * Mic icon that toggles voice input. Turns red when actively listening.\n */\n\nimport { Mic } from 'lucide-react';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface VoiceToggleProps {\n enabled: boolean;\n onToggle: () => void;\n isListening?: boolean;\n}\n\nexport function VoiceToggle({ enabled, onToggle, isListening = false }: VoiceToggleProps) {\n const tr = useTr();\n\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n className={`p-1.5 rounded transition-colors ${\n isListening\n ? 'bg-status-error-bg-subtle text-status-error-text animate-pulse'\n : enabled\n ? 'bg-[var(--color-accent-soft)] text-text-primary hover:bg-[var(--color-accent-soft)]'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n title={\n isListening\n ? tr('vibecontrols.agentManager.controls.listening', 'Listening...')\n : enabled\n ? tr('vibecontrols.agentManager.controls.disableVoice', 'Disable voice mode')\n : tr('vibecontrols.agentManager.controls.enableVoice', 'Enable voice mode')\n }\n >\n <Mic className=\"size-4\" />\n </button>\n );\n}\n"],"mappings":";;;;AAeA,SAAgB,EAAY,EAAE,YAAS,aAAU,iBAAc,MAA2B;CACxF,IAAM,IAAK,GAAO;AAElB,QACE,kBAAC,UAAD;EACE,MAAK;EACL,SAAS;EACT,WAAW,mCACT,IACI,mEACA,IACE,wFACA;EAER,OACE,IACI,EAAG,gDAAgD,eAAe,GAClE,IACE,EAAG,mDAAmD,qBAAqB,GAC3E,EAAG,kDAAkD,oBAAoB;YAGjF,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA;EACnB,CAAA"}
|
|
@@ -117,7 +117,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
117
117
|
className: "text-xs text-text-tertiary",
|
|
118
118
|
children: "Status:"
|
|
119
119
|
}), /* @__PURE__ */ f("span", {
|
|
120
|
-
className: `px-2 py-0.5 text-xs font-medium rounded-full ${y.status === "active" ? "bg-status-success-bg
|
|
120
|
+
className: `px-2 py-0.5 text-xs font-medium rounded-full ${y.status === "active" ? "bg-status-success-bg-subtle text-status-success-text" : y.status === "error" ? "bg-status-error-bg-subtle text-status-error-text" : y.status === "terminated" ? "bg-bg-sunken text-text-tertiary" : "bg-status-warning-bg-subtle text-status-warning-text"}`,
|
|
121
121
|
children: y.status
|
|
122
122
|
})]
|
|
123
123
|
}),
|
|
@@ -138,7 +138,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
138
138
|
onChange: (e) => z("model", e.target.value),
|
|
139
139
|
placeholder: v("vibecontrols.agentManager.config.modelPlaceholder", "Model ID"),
|
|
140
140
|
disabled: H,
|
|
141
|
-
className: "w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-
|
|
141
|
+
className: "w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-surface text-text-primary disabled:opacity-50"
|
|
142
142
|
})] }),
|
|
143
143
|
/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
|
|
144
144
|
className: "block text-xs text-text-secondary mb-1",
|
|
@@ -150,7 +150,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
150
150
|
placeholder: "Instructions for the AI...",
|
|
151
151
|
rows: 2,
|
|
152
152
|
disabled: H,
|
|
153
|
-
className: "w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-
|
|
153
|
+
className: "w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-surface text-text-primary resize-none disabled:opacity-50"
|
|
154
154
|
})] }),
|
|
155
155
|
/* @__PURE__ */ p("div", { children: [/* @__PURE__ */ f("label", {
|
|
156
156
|
className: "block text-xs text-text-secondary mb-1",
|
|
@@ -162,7 +162,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
162
162
|
onChange: (e) => z("maxTokens", e.target.value ? Number(e.target.value) : null),
|
|
163
163
|
placeholder: "4096",
|
|
164
164
|
disabled: H,
|
|
165
|
-
className: "w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-
|
|
165
|
+
className: "w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-surface text-text-primary disabled:opacity-50"
|
|
166
166
|
})] }),
|
|
167
167
|
/* @__PURE__ */ p("div", { children: [
|
|
168
168
|
/* @__PURE__ */ f("label", {
|
|
@@ -201,7 +201,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
201
201
|
S(e.target.value), M(null), L(e.target.value);
|
|
202
202
|
},
|
|
203
203
|
disabled: H,
|
|
204
|
-
className: "w-full h-48 rounded-lg border border-border-default bg-bg-
|
|
204
|
+
className: "w-full h-48 rounded-lg border border-border-default bg-bg-surface px-3 py-2 text-xs font-mono text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors resize-y disabled:opacity-50",
|
|
205
205
|
spellCheck: !1
|
|
206
206
|
}),
|
|
207
207
|
j && /* @__PURE__ */ f("p", {
|
|
@@ -231,7 +231,7 @@ function g({ sessionId: g, agent: _ }) {
|
|
|
231
231
|
type: "button",
|
|
232
232
|
onClick: () => P(!0),
|
|
233
233
|
disabled: H,
|
|
234
|
-
className: "flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-status-error-bg
|
|
234
|
+
className: "flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-status-error-bg-subtle text-status-error-text hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors",
|
|
235
235
|
children: [/* @__PURE__ */ f(d, { className: "size-3.5" }), v("vibecontrols.agentManager.config.terminate", "Terminate")]
|
|
236
236
|
})
|
|
237
237
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionConfigPanel.js","names":[],"sources":["../../../../src/components/agent-manager/detail/SessionConfigPanel.tsx"],"sourcesContent":["/**\n * Session configuration panel.\n *\n * Displays Quick Settings fields for common config options (model,\n * system prompt, max tokens, temperature) above an editable JSON\n * editor. Provides save and terminate actions with a confirmation dialog.\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { Save, Trash2 } from 'lucide-react';\nimport { LoadingState, ErrorState, ConfirmDialog } from '@/components/shared';\nimport {\n fetchSessions,\n updateSessionConfig,\n terminateSession,\n type AISession,\n type AgentRef,\n} from '@/services/aiApi';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface SessionConfigFields {\n model: string;\n systemPrompt: string;\n maxTokens: number | null;\n temperature: number;\n [key: string]: unknown;\n}\n\nfunction parseConfigFields(raw: Record<string, unknown>): SessionConfigFields {\n return {\n model: typeof raw.model === 'string' ? raw.model : '',\n systemPrompt: typeof raw.systemPrompt === 'string' ? raw.systemPrompt : '',\n maxTokens: typeof raw.maxTokens === 'number' ? raw.maxTokens : null,\n temperature: typeof raw.temperature === 'number' ? raw.temperature : 0.7,\n };\n}\n\nfunction mergeFieldsIntoConfig(configText: string, fields: SessionConfigFields): string {\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(configText) as Record<string, unknown>;\n } catch {\n parsed = {};\n }\n const merged = { ...parsed };\n if (fields.model) {\n merged.model = fields.model;\n } else {\n delete merged.model;\n }\n if (fields.systemPrompt) {\n merged.systemPrompt = fields.systemPrompt;\n } else {\n delete merged.systemPrompt;\n }\n if (fields.maxTokens !== null) {\n merged.maxTokens = fields.maxTokens;\n } else {\n delete merged.maxTokens;\n }\n merged.temperature = fields.temperature;\n return JSON.stringify(merged, null, 2);\n}\n\ninterface SessionConfigPanelProps {\n sessionId: string;\n agent: AgentRef;\n}\n\nexport function SessionConfigPanel({ sessionId, agent }: SessionConfigPanelProps) {\n const tr = useTr();\n const [session, setSession] = useState<AISession | null>(null);\n const [configText, setConfigText] = useState('');\n const [configFields, setConfigFields] = useState<SessionConfigFields>(parseConfigFields({}));\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [parseError, setParseError] = useState<string | null>(null);\n const [showTerminate, setShowTerminate] = useState(false);\n const [terminating, setTerminating] = useState(false);\n\n const syncFieldsFromJson = useCallback((json: string) => {\n try {\n const parsed = JSON.parse(json) as Record<string, unknown>;\n setConfigFields(parseConfigFields(parsed));\n } catch {\n // Don't update fields if JSON is invalid\n }\n }, []);\n\n const loadConfig = useCallback(async () => {\n try {\n const sessions = await fetchSessions(agent);\n const found = sessions.find((s) => s.id === sessionId);\n if (found) {\n setSession(found);\n const json = JSON.stringify(found.config ?? {}, null, 2);\n setConfigText(json);\n syncFieldsFromJson(json);\n } else {\n // Session row exists in the platform DB but the agent-side\n // session object only materialises after the first message.\n // Treat as empty defaults instead of error so the user can\n // still pre-edit config; the form save flow creates the\n // agent-side row on submit.\n setSession(null);\n setConfigText('{}');\n syncFieldsFromJson('{}');\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load config');\n } finally {\n setLoading(false);\n }\n }, [agent, sessionId, syncFieldsFromJson]);\n\n useEffect(() => {\n setLoading(true);\n loadConfig();\n }, [loadConfig]);\n\n const updateConfigField = useCallback(\n (field: keyof SessionConfigFields, value: string | number | null) => {\n setConfigFields((prev) => {\n const next = { ...prev, [field]: value };\n setConfigText(mergeFieldsIntoConfig(configText, next));\n return next;\n });\n },\n [configText]\n );\n\n const handleSave = useCallback(async () => {\n setParseError(null);\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(configText) as Record<string, unknown>;\n } catch {\n setParseError('Invalid JSON');\n return;\n }\n\n setSaving(true);\n try {\n const updated = await updateSessionConfig(agent, sessionId, parsed);\n setSession(updated);\n const json = JSON.stringify(updated.config ?? {}, null, 2);\n setConfigText(json);\n syncFieldsFromJson(json);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to save config');\n } finally {\n setSaving(false);\n }\n }, [agent, sessionId, configText, syncFieldsFromJson]);\n\n const handleTerminate = useCallback(async () => {\n setTerminating(true);\n try {\n await terminateSession(agent, sessionId);\n setShowTerminate(false);\n // Reload to reflect terminated status\n await loadConfig();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to terminate session');\n } finally {\n setTerminating(false);\n }\n }, [agent, sessionId, loadConfig]);\n\n if (loading) return <LoadingState message=\"Loading config...\" />;\n if (error && !session) return <ErrorState message={error} onRetry={loadConfig} />;\n\n const isTerminated = session?.status === 'terminated';\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"flex-1 p-3 overflow-y-auto\">\n {/* Status */}\n {session && (\n <div className=\"mb-3 flex items-center gap-2\">\n <span className=\"text-xs text-text-tertiary\">Status:</span>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded-full ${\n session.status === 'active'\n ? 'bg-status-success-bg/10 text-status-success-text'\n : session.status === 'error'\n ? 'bg-status-error-bg/10 text-status-error-text'\n : session.status === 'terminated'\n ? 'bg-bg-sunken text-text-tertiary'\n : 'bg-status-warning-bg/10 text-status-warning-text'\n }`}\n >\n {session.status}\n </span>\n </div>\n )}\n\n {/* Quick Settings */}\n <div className=\"space-y-3 mb-4\">\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.agentManager.config.quickSettings', 'Quick Settings')}\n </h4>\n\n {/* Model */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.model', 'Model')}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={configFields.model}\n onChange={(e) => updateConfigField('model', e.target.value)}\n placeholder={tr('vibecontrols.agentManager.config.modelPlaceholder', 'Model ID')}\n disabled={isTerminated}\n className=\"w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-primary text-text-primary disabled:opacity-50\"\n />\n </div>\n\n {/* System Prompt */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.systemPrompt', 'System Prompt')}\n </label>\n <textarea\n aria-label=\"Instructions for the AI...\"\n value={configFields.systemPrompt}\n onChange={(e) => updateConfigField('systemPrompt', e.target.value)}\n placeholder=\"Instructions for the AI...\"\n rows={2}\n disabled={isTerminated}\n className=\"w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-primary text-text-primary resize-none disabled:opacity-50\"\n />\n </div>\n\n {/* Max Tokens */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.maxTokens', 'Max Tokens')}\n </label>\n <input\n aria-label=\"4096\"\n type=\"number\"\n value={configFields.maxTokens ?? ''}\n onChange={(e) =>\n updateConfigField('maxTokens', e.target.value ? Number(e.target.value) : null)\n }\n placeholder=\"4096\"\n disabled={isTerminated}\n className=\"w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-primary text-text-primary disabled:opacity-50\"\n />\n </div>\n\n {/* Temperature */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.temperature', 'Temperature (0-1)')}\n </label>\n <input\n aria-label=\"control\"\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.1\"\n value={configFields.temperature}\n onChange={(e) => updateConfigField('temperature', Number(e.target.value))}\n disabled={isTerminated}\n className=\"w-full\"\n />\n <span className=\"text-xs text-text-tertiary\">{configFields.temperature}</span>\n </div>\n </div>\n\n <div className=\"border-t border-border-default pt-3\">\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.config.advancedJson', 'Advanced (JSON)')}\n </h4>\n\n {/* JSON editor */}\n <textarea\n aria-label=\"control\"\n value={configText}\n onChange={(e) => {\n setConfigText(e.target.value);\n setParseError(null);\n syncFieldsFromJson(e.target.value);\n }}\n disabled={isTerminated}\n className=\"w-full h-48 rounded-lg border border-border-default bg-bg-primary px-3 py-2 text-xs font-mono text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors resize-y disabled:opacity-50\"\n spellCheck={false}\n />\n {parseError && <p className=\"mt-1 text-xs text-status-error-text\">{parseError}</p>}\n {error && session && <p className=\"mt-1 text-xs text-status-error-text\">{error}</p>}\n </div>\n </div>\n\n {/* Action buttons */}\n <div className=\"flex items-center gap-2 p-3 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving || isTerminated}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md 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 <Save className=\"size-3.5\" />\n {saving\n ? tr('vibecontrols.agentManager.config.saving', 'Saving...')\n : tr('vibecontrols.agentManager.config.save', 'Save')}\n </button>\n <div className=\"flex-1\" />\n <button\n type=\"button\"\n onClick={() => setShowTerminate(true)}\n disabled={isTerminated}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-status-error-bg/10 text-status-error-text hover:bg-status-error-bg/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n <Trash2 className=\"size-3.5\" />\n {tr('vibecontrols.agentManager.config.terminate', 'Terminate')}\n </button>\n </div>\n\n <ConfirmDialog\n isOpen={showTerminate}\n onClose={() => setShowTerminate(false)}\n onConfirm={handleTerminate}\n title={tr('vibecontrols.agentManager.config.terminateSessionTitle', 'Terminate Session')}\n message={tr(\n 'vibecontrols.agentManager.config.terminateConfirm',\n 'Are you sure you want to terminate this session? This action cannot be undone.'\n )}\n confirmLabel={tr('vibecontrols.agentManager.config.terminate', 'Terminate')}\n variant=\"danger\"\n isLoading={terminating}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SessionConfigPanel.js","names":[],"sources":["../../../../src/components/agent-manager/detail/SessionConfigPanel.tsx"],"sourcesContent":["/**\n * Session configuration panel.\n *\n * Displays Quick Settings fields for common config options (model,\n * system prompt, max tokens, temperature) above an editable JSON\n * editor. Provides save and terminate actions with a confirmation dialog.\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { Save, Trash2 } from 'lucide-react';\nimport { LoadingState, ErrorState, ConfirmDialog } from '@/components/shared';\nimport {\n fetchSessions,\n updateSessionConfig,\n terminateSession,\n type AISession,\n type AgentRef,\n} from '@/services/aiApi';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface SessionConfigFields {\n model: string;\n systemPrompt: string;\n maxTokens: number | null;\n temperature: number;\n [key: string]: unknown;\n}\n\nfunction parseConfigFields(raw: Record<string, unknown>): SessionConfigFields {\n return {\n model: typeof raw.model === 'string' ? raw.model : '',\n systemPrompt: typeof raw.systemPrompt === 'string' ? raw.systemPrompt : '',\n maxTokens: typeof raw.maxTokens === 'number' ? raw.maxTokens : null,\n temperature: typeof raw.temperature === 'number' ? raw.temperature : 0.7,\n };\n}\n\nfunction mergeFieldsIntoConfig(configText: string, fields: SessionConfigFields): string {\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(configText) as Record<string, unknown>;\n } catch {\n parsed = {};\n }\n const merged = { ...parsed };\n if (fields.model) {\n merged.model = fields.model;\n } else {\n delete merged.model;\n }\n if (fields.systemPrompt) {\n merged.systemPrompt = fields.systemPrompt;\n } else {\n delete merged.systemPrompt;\n }\n if (fields.maxTokens !== null) {\n merged.maxTokens = fields.maxTokens;\n } else {\n delete merged.maxTokens;\n }\n merged.temperature = fields.temperature;\n return JSON.stringify(merged, null, 2);\n}\n\ninterface SessionConfigPanelProps {\n sessionId: string;\n agent: AgentRef;\n}\n\nexport function SessionConfigPanel({ sessionId, agent }: SessionConfigPanelProps) {\n const tr = useTr();\n const [session, setSession] = useState<AISession | null>(null);\n const [configText, setConfigText] = useState('');\n const [configFields, setConfigFields] = useState<SessionConfigFields>(parseConfigFields({}));\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [parseError, setParseError] = useState<string | null>(null);\n const [showTerminate, setShowTerminate] = useState(false);\n const [terminating, setTerminating] = useState(false);\n\n const syncFieldsFromJson = useCallback((json: string) => {\n try {\n const parsed = JSON.parse(json) as Record<string, unknown>;\n setConfigFields(parseConfigFields(parsed));\n } catch {\n // Don't update fields if JSON is invalid\n }\n }, []);\n\n const loadConfig = useCallback(async () => {\n try {\n const sessions = await fetchSessions(agent);\n const found = sessions.find((s) => s.id === sessionId);\n if (found) {\n setSession(found);\n const json = JSON.stringify(found.config ?? {}, null, 2);\n setConfigText(json);\n syncFieldsFromJson(json);\n } else {\n // Session row exists in the platform DB but the agent-side\n // session object only materialises after the first message.\n // Treat as empty defaults instead of error so the user can\n // still pre-edit config; the form save flow creates the\n // agent-side row on submit.\n setSession(null);\n setConfigText('{}');\n syncFieldsFromJson('{}');\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load config');\n } finally {\n setLoading(false);\n }\n }, [agent, sessionId, syncFieldsFromJson]);\n\n useEffect(() => {\n setLoading(true);\n loadConfig();\n }, [loadConfig]);\n\n const updateConfigField = useCallback(\n (field: keyof SessionConfigFields, value: string | number | null) => {\n setConfigFields((prev) => {\n const next = { ...prev, [field]: value };\n setConfigText(mergeFieldsIntoConfig(configText, next));\n return next;\n });\n },\n [configText]\n );\n\n const handleSave = useCallback(async () => {\n setParseError(null);\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(configText) as Record<string, unknown>;\n } catch {\n setParseError('Invalid JSON');\n return;\n }\n\n setSaving(true);\n try {\n const updated = await updateSessionConfig(agent, sessionId, parsed);\n setSession(updated);\n const json = JSON.stringify(updated.config ?? {}, null, 2);\n setConfigText(json);\n syncFieldsFromJson(json);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to save config');\n } finally {\n setSaving(false);\n }\n }, [agent, sessionId, configText, syncFieldsFromJson]);\n\n const handleTerminate = useCallback(async () => {\n setTerminating(true);\n try {\n await terminateSession(agent, sessionId);\n setShowTerminate(false);\n // Reload to reflect terminated status\n await loadConfig();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to terminate session');\n } finally {\n setTerminating(false);\n }\n }, [agent, sessionId, loadConfig]);\n\n if (loading) return <LoadingState message=\"Loading config...\" />;\n if (error && !session) return <ErrorState message={error} onRetry={loadConfig} />;\n\n const isTerminated = session?.status === 'terminated';\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"flex-1 p-3 overflow-y-auto\">\n {/* Status */}\n {session && (\n <div className=\"mb-3 flex items-center gap-2\">\n <span className=\"text-xs text-text-tertiary\">Status:</span>\n <span\n className={`px-2 py-0.5 text-xs font-medium rounded-full ${\n session.status === 'active'\n ? 'bg-status-success-bg-subtle text-status-success-text'\n : session.status === 'error'\n ? 'bg-status-error-bg-subtle text-status-error-text'\n : session.status === 'terminated'\n ? 'bg-bg-sunken text-text-tertiary'\n : 'bg-status-warning-bg-subtle text-status-warning-text'\n }`}\n >\n {session.status}\n </span>\n </div>\n )}\n\n {/* Quick Settings */}\n <div className=\"space-y-3 mb-4\">\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.agentManager.config.quickSettings', 'Quick Settings')}\n </h4>\n\n {/* Model */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.model', 'Model')}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={configFields.model}\n onChange={(e) => updateConfigField('model', e.target.value)}\n placeholder={tr('vibecontrols.agentManager.config.modelPlaceholder', 'Model ID')}\n disabled={isTerminated}\n className=\"w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-surface text-text-primary disabled:opacity-50\"\n />\n </div>\n\n {/* System Prompt */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.systemPrompt', 'System Prompt')}\n </label>\n <textarea\n aria-label=\"Instructions for the AI...\"\n value={configFields.systemPrompt}\n onChange={(e) => updateConfigField('systemPrompt', e.target.value)}\n placeholder=\"Instructions for the AI...\"\n rows={2}\n disabled={isTerminated}\n className=\"w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-surface text-text-primary resize-none disabled:opacity-50\"\n />\n </div>\n\n {/* Max Tokens */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.maxTokens', 'Max Tokens')}\n </label>\n <input\n aria-label=\"4096\"\n type=\"number\"\n value={configFields.maxTokens ?? ''}\n onChange={(e) =>\n updateConfigField('maxTokens', e.target.value ? Number(e.target.value) : null)\n }\n placeholder=\"4096\"\n disabled={isTerminated}\n className=\"w-full px-2 py-1.5 text-sm rounded border border-border-default bg-bg-surface text-text-primary disabled:opacity-50\"\n />\n </div>\n\n {/* Temperature */}\n <div>\n <label className=\"block text-xs text-text-secondary mb-1\">\n {tr('vibecontrols.agentManager.config.temperature', 'Temperature (0-1)')}\n </label>\n <input\n aria-label=\"control\"\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.1\"\n value={configFields.temperature}\n onChange={(e) => updateConfigField('temperature', Number(e.target.value))}\n disabled={isTerminated}\n className=\"w-full\"\n />\n <span className=\"text-xs text-text-tertiary\">{configFields.temperature}</span>\n </div>\n </div>\n\n <div className=\"border-t border-border-default pt-3\">\n <h4 className=\"text-xs font-semibold text-text-secondary uppercase tracking-wider mb-2\">\n {tr('vibecontrols.agentManager.config.advancedJson', 'Advanced (JSON)')}\n </h4>\n\n {/* JSON editor */}\n <textarea\n aria-label=\"control\"\n value={configText}\n onChange={(e) => {\n setConfigText(e.target.value);\n setParseError(null);\n syncFieldsFromJson(e.target.value);\n }}\n disabled={isTerminated}\n className=\"w-full h-48 rounded-lg border border-border-default bg-bg-surface px-3 py-2 text-xs font-mono text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors resize-y disabled:opacity-50\"\n spellCheck={false}\n />\n {parseError && <p className=\"mt-1 text-xs text-status-error-text\">{parseError}</p>}\n {error && session && <p className=\"mt-1 text-xs text-status-error-text\">{error}</p>}\n </div>\n </div>\n\n {/* Action buttons */}\n <div className=\"flex items-center gap-2 p-3 border-t border-border-default\">\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving || isTerminated}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md 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 <Save className=\"size-3.5\" />\n {saving\n ? tr('vibecontrols.agentManager.config.saving', 'Saving...')\n : tr('vibecontrols.agentManager.config.save', 'Save')}\n </button>\n <div className=\"flex-1\" />\n <button\n type=\"button\"\n onClick={() => setShowTerminate(true)}\n disabled={isTerminated}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md bg-status-error-bg-subtle text-status-error-text hover:bg-bg-sunken disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n <Trash2 className=\"size-3.5\" />\n {tr('vibecontrols.agentManager.config.terminate', 'Terminate')}\n </button>\n </div>\n\n <ConfirmDialog\n isOpen={showTerminate}\n onClose={() => setShowTerminate(false)}\n onConfirm={handleTerminate}\n title={tr('vibecontrols.agentManager.config.terminateSessionTitle', 'Terminate Session')}\n message={tr(\n 'vibecontrols.agentManager.config.terminateConfirm',\n 'Are you sure you want to terminate this session? This action cannot be undone.'\n )}\n confirmLabel={tr('vibecontrols.agentManager.config.terminate', 'Terminate')}\n variant=\"danger\"\n isLoading={terminating}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -16,11 +16,11 @@ var f = [
|
|
|
16
16
|
"error",
|
|
17
17
|
"metadata"
|
|
18
18
|
], p = {
|
|
19
|
-
input: "bg-
|
|
20
|
-
output: "bg-status-success-bg
|
|
21
|
-
thinking: "bg-status-warning-bg
|
|
19
|
+
input: "bg-[var(--color-accent-soft)] text-text-primary",
|
|
20
|
+
output: "bg-status-success-bg-subtle text-status-success-text",
|
|
21
|
+
thinking: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
22
22
|
event: "bg-bg-elevated text-text-secondary",
|
|
23
|
-
error: "bg-status-error-bg
|
|
23
|
+
error: "bg-status-error-bg-subtle text-status-error-text",
|
|
24
24
|
metadata: "bg-bg-sunken text-text-tertiary"
|
|
25
25
|
};
|
|
26
26
|
function m({ sessionId: m, agent: h }) {
|
|
@@ -62,7 +62,7 @@ function m({ sessionId: m, agent: h }) {
|
|
|
62
62
|
/* @__PURE__ */ u("button", {
|
|
63
63
|
type: "button",
|
|
64
64
|
onClick: () => E((e) => !e),
|
|
65
|
-
className: `p-1 rounded transition-colors ${T ? "text-
|
|
65
|
+
className: `p-1 rounded transition-colors ${T ? "text-text-primary bg-[var(--color-accent-soft)]" : "text-text-tertiary hover:text-text-secondary"}`,
|
|
66
66
|
title: T ? g("vibecontrols.agentManager.logs.disableAutoRefresh", "Disable auto-refresh") : g("vibecontrols.agentManager.logs.enableAutoRefresh", "Enable auto-refresh"),
|
|
67
67
|
children: /* @__PURE__ */ u(l, { className: `size-3.5 ${T ? "animate-spin" : ""}` })
|
|
68
68
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionLogsPanel.js","names":[],"sources":["../../../../src/components/agent-manager/detail/SessionLogsPanel.tsx"],"sourcesContent":["/**\n * Session logs viewer panel.\n *\n * Fetches and displays logs for a session with type filtering\n * and optional auto-refresh.\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { RefreshCw } from 'lucide-react';\nimport { LoadingState, ErrorState } from '@/components/shared';\nimport { fetchSessionLogs, type AISessionLog, type AgentRef } from '@/services/aiApi';\nimport { isSessionNotFoundError } from '@/utils/aiSessionNotFound';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface SessionLogsPanelProps {\n sessionId: string;\n agent: AgentRef;\n}\n\nconst LOG_TYPES = ['input', 'output', 'thinking', 'event', 'error', 'metadata'] as const;\n\nconst TYPE_COLORS: Record<string, string> = {\n input: 'bg-
|
|
1
|
+
{"version":3,"file":"SessionLogsPanel.js","names":[],"sources":["../../../../src/components/agent-manager/detail/SessionLogsPanel.tsx"],"sourcesContent":["/**\n * Session logs viewer panel.\n *\n * Fetches and displays logs for a session with type filtering\n * and optional auto-refresh.\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { RefreshCw } from 'lucide-react';\nimport { LoadingState, ErrorState } from '@/components/shared';\nimport { fetchSessionLogs, type AISessionLog, type AgentRef } from '@/services/aiApi';\nimport { isSessionNotFoundError } from '@/utils/aiSessionNotFound';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface SessionLogsPanelProps {\n sessionId: string;\n agent: AgentRef;\n}\n\nconst LOG_TYPES = ['input', 'output', 'thinking', 'event', 'error', 'metadata'] as const;\n\nconst TYPE_COLORS: Record<string, string> = {\n input: 'bg-[var(--color-accent-soft)] text-text-primary',\n output: 'bg-status-success-bg-subtle text-status-success-text',\n thinking: 'bg-status-warning-bg-subtle text-status-warning-text',\n event: 'bg-bg-elevated text-text-secondary',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n metadata: 'bg-bg-sunken text-text-tertiary',\n};\n\nexport function SessionLogsPanel({ sessionId, agent }: SessionLogsPanelProps) {\n const tr = useTr();\n const [logs, setLogs] = useState<AISessionLog[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [activeTypes, setActiveTypes] = useState<Set<string>>(new Set(LOG_TYPES));\n const [autoRefresh, setAutoRefresh] = useState(false);\n const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const loadLogs = useCallback(async () => {\n try {\n const data = await fetchSessionLogs(agent, sessionId, { limit: 100 });\n setLogs(data);\n setError(null);\n } catch (err) {\n // Until the user sends the first message the agent has no\n // record of this session, so /api/ai/sessions/:id/logs 404s.\n // Render that as an empty list with a hint, not as an error.\n if (isSessionNotFoundError(err)) {\n setLogs([]);\n setError(null);\n } else {\n setError(err instanceof Error ? err.message : 'Failed to load logs');\n }\n } finally {\n setLoading(false);\n }\n }, [agent, sessionId]);\n\n useEffect(() => {\n setLoading(true);\n loadLogs();\n }, [loadLogs]);\n\n useEffect(() => {\n if (autoRefresh) {\n intervalRef.current = setInterval(loadLogs, 5000);\n }\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n };\n }, [autoRefresh, loadLogs]);\n\n const toggleType = useCallback((type: string) => {\n setActiveTypes((prev) => {\n const next = new Set(prev);\n if (next.has(type)) {\n next.delete(type);\n } else {\n next.add(type);\n }\n return next;\n });\n }, []);\n\n const filteredLogs = logs.filter((log) => activeTypes.has(log.type));\n\n if (loading) return <LoadingState message=\"Loading logs...\" />;\n if (error) return <ErrorState message={error} onRetry={loadLogs} />;\n\n return (\n <div className=\"flex flex-col h-full\">\n {/* Filter bar */}\n <div className=\"flex items-center gap-1.5 p-2 border-b border-border-default flex-wrap\">\n {LOG_TYPES.map((type) => (\n <button\n key={type}\n type=\"button\"\n onClick={() => toggleType(type)}\n className={`px-2 py-0.5 text-[10px] font-medium rounded-full transition-colors ${\n activeTypes.has(type)\n ? TYPE_COLORS[type]\n : 'bg-bg-sunken text-text-tertiary opacity-50'\n }`}\n >\n {type}\n </button>\n ))}\n <div className=\"flex-1\" />\n <button\n type=\"button\"\n onClick={() => setAutoRefresh((prev) => !prev)}\n className={`p-1 rounded transition-colors ${\n autoRefresh\n ? 'text-text-primary bg-[var(--color-accent-soft)]'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n autoRefresh\n ? tr('vibecontrols.agentManager.logs.disableAutoRefresh', 'Disable auto-refresh')\n : tr('vibecontrols.agentManager.logs.enableAutoRefresh', 'Enable auto-refresh')\n }\n >\n <RefreshCw className={`size-3.5 ${autoRefresh ? 'animate-spin' : ''}`} />\n </button>\n </div>\n\n {/* Logs list */}\n <div className=\"flex-1 overflow-y-auto\">\n {filteredLogs.length === 0 ? (\n <div className=\"p-4 text-center text-sm text-text-tertiary\">\n {logs.length === 0\n ? tr(\n 'vibecontrols.agentManager.logs.empty',\n 'Logs will appear here after you send the first message.'\n )\n : tr(\n 'vibecontrols.agentManager.logs.noLogsMatch',\n 'No logs match the selected filters'\n )}\n </div>\n ) : (\n <div className=\"divide-y divide-border-default\">\n {filteredLogs.map((log) => (\n <div key={log.id} className=\"px-3 py-2\">\n <div className=\"flex items-center gap-2 mb-1\">\n <span\n className={`px-1.5 py-0.5 text-[10px] font-medium rounded ${TYPE_COLORS[log.type] ?? 'bg-bg-sunken text-text-tertiary'}`}\n >\n {log.type}\n </span>\n <span className=\"text-[10px] text-text-tertiary\">\n {new Date(log.timestamp).toLocaleTimeString()}\n </span>\n {log.tokenCount != null && (\n <span className=\"text-[10px] text-text-tertiary ml-auto\">\n {log.tokenCount} tokens\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-secondary break-words line-clamp-3\">\n {log.message || log.content}\n </p>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -39,7 +39,7 @@ function f({ agent: f }) {
|
|
|
39
39
|
className: "flex-1 text-sm font-medium text-text-primary truncate",
|
|
40
40
|
children: e.displayName || e.name
|
|
41
41
|
}), e.installed ? /* @__PURE__ */ d("span", {
|
|
42
|
-
className: "flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full bg-status-success-bg
|
|
42
|
+
className: "flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full bg-status-success-bg-subtle text-status-success-text",
|
|
43
43
|
children: [/* @__PURE__ */ u(s, { className: "size-3" }), p("vibecontrols.agentManager.tools.installed", "Installed")]
|
|
44
44
|
}) : /* @__PURE__ */ d("span", {
|
|
45
45
|
className: "flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full bg-bg-sunken text-text-tertiary",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionToolsPanel.js","names":[],"sources":["../../../../src/components/agent-manager/detail/SessionToolsPanel.tsx"],"sourcesContent":["/**\n * Session tools list panel.\n *\n * Fetches available tools from the agent and renders them as a list\n * with installed status badges and version info.\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { Wrench, CheckCircle, Circle } from 'lucide-react';\nimport { LoadingState, ErrorState } from '@/components/shared';\nimport { fetchTools, type AITool, type AgentRef } from '@/services/aiApi';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface SessionToolsPanelProps {\n agent: AgentRef;\n}\n\nexport function SessionToolsPanel({ agent }: SessionToolsPanelProps) {\n const tr = useTr();\n const [tools, setTools] = useState<AITool[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const loadTools = useCallback(async () => {\n try {\n const data = await fetchTools(agent);\n setTools(data);\n setError(null);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load tools');\n } finally {\n setLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n setLoading(true);\n loadTools();\n }, [loadTools]);\n\n if (loading) return <LoadingState message=\"Loading tools...\" />;\n if (error) return <ErrorState message={error} onRetry={loadTools} />;\n\n if (tools.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center p-6 text-center\">\n <Wrench className=\"size-8 text-text-tertiary mb-2\" />\n <p className=\"text-sm text-text-tertiary\">\n {tr('vibecontrols.agentManager.tools.noToolsAvailable', 'No tools available')}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"divide-y divide-border-default\">\n {tools.map((tool) => (\n <div key={tool.name} className=\"px-3 py-2.5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"flex-1 text-sm font-medium text-text-primary truncate\">\n {tool.displayName || tool.name}\n </span>\n {tool.installed ? (\n <span className=\"flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full bg-status-success-bg
|
|
1
|
+
{"version":3,"file":"SessionToolsPanel.js","names":[],"sources":["../../../../src/components/agent-manager/detail/SessionToolsPanel.tsx"],"sourcesContent":["/**\n * Session tools list panel.\n *\n * Fetches available tools from the agent and renders them as a list\n * with installed status badges and version info.\n */\n\nimport { useState, useEffect, useCallback } from 'react';\nimport { Wrench, CheckCircle, Circle } from 'lucide-react';\nimport { LoadingState, ErrorState } from '@/components/shared';\nimport { fetchTools, type AITool, type AgentRef } from '@/services/aiApi';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface SessionToolsPanelProps {\n agent: AgentRef;\n}\n\nexport function SessionToolsPanel({ agent }: SessionToolsPanelProps) {\n const tr = useTr();\n const [tools, setTools] = useState<AITool[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const loadTools = useCallback(async () => {\n try {\n const data = await fetchTools(agent);\n setTools(data);\n setError(null);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load tools');\n } finally {\n setLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n setLoading(true);\n loadTools();\n }, [loadTools]);\n\n if (loading) return <LoadingState message=\"Loading tools...\" />;\n if (error) return <ErrorState message={error} onRetry={loadTools} />;\n\n if (tools.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center p-6 text-center\">\n <Wrench className=\"size-8 text-text-tertiary mb-2\" />\n <p className=\"text-sm text-text-tertiary\">\n {tr('vibecontrols.agentManager.tools.noToolsAvailable', 'No tools available')}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"divide-y divide-border-default\">\n {tools.map((tool) => (\n <div key={tool.name} className=\"px-3 py-2.5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"flex-1 text-sm font-medium text-text-primary truncate\">\n {tool.displayName || tool.name}\n </span>\n {tool.installed ? (\n <span className=\"flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full bg-status-success-bg-subtle text-status-success-text\">\n <CheckCircle className=\"size-3\" />\n {tr('vibecontrols.agentManager.tools.installed', 'Installed')}\n </span>\n ) : (\n <span className=\"flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-medium rounded-full bg-bg-sunken text-text-tertiary\">\n <Circle className=\"size-3\" />\n {tr('vibecontrols.agentManager.tools.notInstalled', 'Not installed')}\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-secondary mt-0.5 line-clamp-2\">{tool.description}</p>\n {tool.version && (\n <span className=\"text-[10px] text-text-tertiary mt-0.5 inline-block\">\n v{tool.version}\n </span>\n )}\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAiBA,SAAgB,EAAkB,EAAE,YAAiC;CACnE,IAAM,IAAK,GAAO,EACZ,CAAC,GAAO,KAAY,EAAmB,EAAE,CAAC,EAC1C,CAAC,GAAS,KAAc,EAAS,GAAK,EACtC,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAY,EAAY,YAAY;AACxC,MAAI;AAGF,GADA,EADa,MAAM,EAAW,EAAM,CACtB,EACd,EAAS,KAAK;WACP,GAAK;AACZ,KAAS,aAAe,QAAQ,EAAI,UAAU,uBAAuB;YAC7D;AACR,KAAW,GAAM;;IAElB,CAAC,EAAM,CAAC;AAqBX,QAnBA,QAAgB;AAEd,EADA,EAAW,GAAK,EAChB,GAAW;IACV,CAAC,EAAU,CAAC,EAEX,IAAgB,kBAAC,GAAD,EAAc,SAAQ,oBAAqB,CAAA,GAC3D,IAAc,kBAAC,GAAD;EAAY,SAAS;EAAO,SAAS;EAAa,CAAA,GAEhE,EAAM,WAAW,IAEjB,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,kCAAmC,CAAA,EACrD,kBAAC,KAAD;GAAG,WAAU;aACV,EAAG,oDAAoD,qBAAqB;GAC3E,CAAA,CACA;MAKR,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAM,KAAK,MACV,kBAAC,OAAD;GAAqB,WAAU;aAA/B;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MAAM,WAAU;gBACb,EAAK,eAAe,EAAK;MACrB,CAAA,EACN,EAAK,YACJ,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAa,WAAU,UAAW,CAAA,EACjC,EAAG,6CAA6C,YAAY,CACxD;UAEP,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAC5B,EAAG,gDAAgD,gBAAgB,CAC/D;QAEL;;IACN,kBAAC,KAAD;KAAG,WAAU;eAAmD,EAAK;KAAgB,CAAA;IACpF,EAAK,WACJ,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAAqE,KACjE,EAAK,QACF;;IAEL;KAvBI,EAAK,KAuBT,CACN;EACE,CAAA"}
|
|
@@ -172,7 +172,7 @@ function y({ agent: _, isOpen: y, onClose: b }) {
|
|
|
172
172
|
value: x,
|
|
173
173
|
onChange: (e) => S(e.target.value),
|
|
174
174
|
placeholder: "My session",
|
|
175
|
-
className: "w-full rounded-md border border-border-default bg-bg-
|
|
175
|
+
className: "w-full rounded-md 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"
|
|
176
176
|
})] }),
|
|
177
177
|
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
178
178
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
@@ -203,7 +203,7 @@ function y({ agent: _, isOpen: y, onClose: b }) {
|
|
|
203
203
|
value: A,
|
|
204
204
|
onChange: (e) => j(e.target.value),
|
|
205
205
|
placeholder: "e.g. frontend, bugfix, prototype",
|
|
206
|
-
className: "w-full rounded-md border border-border-default bg-bg-
|
|
206
|
+
className: "w-full rounded-md 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"
|
|
207
207
|
})] }),
|
|
208
208
|
I && /* @__PURE__ */ h("p", {
|
|
209
209
|
className: "text-xs text-status-error-text",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NewSessionDialog.js","names":[],"sources":["../../../../src/components/agent-manager/dialogs/NewSessionDialog.tsx"],"sourcesContent":["/**\n * New session creation dialog.\n *\n * Modal overlay with fields for session name, SDK, model, and mode.\n * Creates a session via aiApi and opens it as a new tab.\n */\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { X } from 'lucide-react';\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion';\nimport { createSession, fetchProviders, type AIProvider, type AgentRef } from '@/services/aiApi';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { ModelSelector } from '../controls/ModelSelector';\nimport { SdkSelector } from '../controls/SdkSelector';\nimport { GENERIC_MODEL_FALLBACK, resolveProviderDefaultModel } from '../modelDefaults';\nimport type { AgentSdkType, ProviderMode } from '@/types/agentManager';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface NewSessionDialogProps {\n agent: AgentRef;\n isOpen: boolean;\n onClose: () => void;\n}\n\nconst SDK_VALUES = new Set<string>([\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]);\n\nfunction providerSdk(provider: AIProvider): AgentSdkType | null {\n const value = (provider.name || provider.pluginName).replace(/^ai-/, '');\n return SDK_VALUES.has(value) ? (value as AgentSdkType) : null;\n}\n\nexport function NewSessionDialog({ agent, isOpen, onClose }: NewSessionDialogProps) {\n const [name, setName] = useState('');\n const [sdk, setSdk] = useState<AgentSdkType>('claude');\n const [model, setModel] = useState(GENERIC_MODEL_FALLBACK);\n const [providers, setProviders] = useState<AIProvider[]>([]);\n\n // Auto-update default model when SDK changes\n const handleSdkChange = (newSdk: AgentSdkType) => {\n setSdk(newSdk);\n void resolveProviderDefaultModel(agent, newSdk, model)\n .then(setModel)\n .catch(() => setModel(model || GENERIC_MODEL_FALLBACK));\n };\n const [tags, setTags] = useState('');\n const [mode, setMode] = useState<ProviderMode>('sdk');\n const [creating, setCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const openSession = useAgentManagerStore((s) => s.openSession);\n const bumpSessionsRefresh = useAgentManagerStore((s) => s.bumpSessionsRefresh);\n const activeChatContext = useAgentManagerStore((s) => s.activeChatContext);\n const setSessionSdk = useAgentManagerStore((s) => s.setSessionSdk);\n const setSessionModel = useAgentManagerStore((s) => s.setSessionModel);\n const setSessionMode = useAgentManagerStore((s) => s.setSessionMode);\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n useEffect(() => {\n if (!isOpen) return;\n\n let cancelled = false;\n void fetchProviders(agent)\n .then((items) => {\n if (!cancelled) setProviders(items);\n })\n .catch(() => {\n if (!cancelled) setProviders([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agent, isOpen]);\n\n useEffect(() => {\n if (!isOpen || providers.length === 0) return;\n\n const current = providers.find((provider) => providerSdk(provider) === sdk);\n const fallback = providers.find((provider) => provider.isDefault) ?? providers[0];\n const nextProvider = current ?? fallback;\n if (!nextProvider) return;\n\n const nextSdk = providerSdk(nextProvider);\n if (nextSdk && !current) {\n setSdk(nextSdk);\n }\n\n const supportedModes = nextProvider.supportedModes ?? [];\n if (supportedModes.length > 0 && !supportedModes.includes(mode)) {\n setMode(nextProvider.defaultMode ?? nextProvider.currentMode ?? supportedModes[0] ?? 'cli');\n }\n }, [isOpen, mode, providers, sdk]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n let cancelled = false;\n void resolveProviderDefaultModel(agent, sdk, GENERIC_MODEL_FALLBACK)\n .then((nextModel) => {\n if (!cancelled) setModel(nextModel);\n })\n .catch(() => {\n if (!cancelled) setModel((current) => current || GENERIC_MODEL_FALLBACK);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agent, isOpen, sdk]);\n\n const handleCreate = useCallback(async () => {\n if (!name.trim()) return;\n setCreating(true);\n setError(null);\n try {\n const session = await createSession(agent, {\n name: name.trim(),\n agentType: sdk,\n config: {\n model,\n mode,\n // New sessions default to the safe autonomy level; users adjust it\n // per-session via the Autonomy control in the chat toolbar.\n permissionMode: 'acceptEdits',\n tags: tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean),\n },\n // Stamp the active \"bucket\" context (agent/vibe) onto the session.\n agentId: agent.id,\n contextLevel: activeChatContext.contextLevel,\n vibeId: activeChatContext.vibeId,\n });\n openSession(session.id, session.name);\n bumpSessionsRefresh();\n setSessionSdk(session.id, sdk);\n setSessionModel(session.id, model);\n setSessionMode(session.id, mode);\n // Reset form\n setName('');\n setSdk('claude');\n setModel(GENERIC_MODEL_FALLBACK);\n setMode('sdk');\n setTags('');\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create session');\n } finally {\n setCreating(false);\n }\n }, [\n agent,\n name,\n sdk,\n model,\n mode,\n tags,\n openSession,\n bumpSessionsRefresh,\n activeChatContext,\n setSessionSdk,\n setSessionModel,\n setSessionMode,\n onClose,\n ]);\n\n if (!isOpen) return null;\n\n return (\n <AnimatePresence>\n {isOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <motion.div\n className=\"absolute inset-0 bg-bg-overlay\"\n initial={shouldReduceMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n onClick={onClose}\n />\n <motion.div\n className=\"relative w-full max-w-md mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl\"\n initial={shouldReduceMotion ? undefined : { opacity: 0, scale: 0.95, y: 8 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: 8 }}\n transition={{ duration: 0.2, ease: [0.2, 0, 0, 1] }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.agentManager.dialogs.newSession', 'New Session')}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Body */}\n <div className=\"px-6 py-4 space-y-4\">\n {/* Name */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.name', 'Name')}\n </label>\n <input\n aria-label=\"My session\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"My session\"\n className=\"w-full rounded-md 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 />\n </div>\n\n {/* SDK + Mode */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.sdkAndMode', 'SDK & Mode')}\n </label>\n <SdkSelector\n sdk={sdk}\n mode={mode}\n providers={providers}\n onSdkChange={handleSdkChange}\n onModeChange={setMode}\n />\n </div>\n\n {/* Model */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.model', 'Model')}\n </label>\n <ModelSelector\n value={model}\n onChange={setModel}\n provider={sdk}\n agentId={agent.id}\n profile={agent.profile}\n />\n </div>\n\n {/* Tags */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.tagsLabel', 'Tags (comma-separated)')}\n </label>\n <input\n aria-label=\"e.g. frontend, bugfix, prototype\"\n type=\"text\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"e.g. frontend, bugfix, prototype\"\n className=\"w-full rounded-md 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 />\n </div>\n\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t border-border-default bg-bg-sunken rounded-b-lg\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={creating}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors disabled:opacity-50\"\n >\n {tr('vibecontrols.agentManager.dialogs.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={creating || !name.trim()}\n className=\"px-4 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {creating\n ? tr('vibecontrols.agentManager.dialogs.creating', 'Creating...')\n : tr('vibecontrols.agentManager.dialogs.create', 'Create')}\n </button>\n </div>\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NewSessionDialog.js","names":[],"sources":["../../../../src/components/agent-manager/dialogs/NewSessionDialog.tsx"],"sourcesContent":["/**\n * New session creation dialog.\n *\n * Modal overlay with fields for session name, SDK, model, and mode.\n * Creates a session via aiApi and opens it as a new tab.\n */\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { X } from 'lucide-react';\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion';\nimport { createSession, fetchProviders, type AIProvider, type AgentRef } from '@/services/aiApi';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { ModelSelector } from '../controls/ModelSelector';\nimport { SdkSelector } from '../controls/SdkSelector';\nimport { GENERIC_MODEL_FALLBACK, resolveProviderDefaultModel } from '../modelDefaults';\nimport type { AgentSdkType, ProviderMode } from '@/types/agentManager';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface NewSessionDialogProps {\n agent: AgentRef;\n isOpen: boolean;\n onClose: () => void;\n}\n\nconst SDK_VALUES = new Set<string>([\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]);\n\nfunction providerSdk(provider: AIProvider): AgentSdkType | null {\n const value = (provider.name || provider.pluginName).replace(/^ai-/, '');\n return SDK_VALUES.has(value) ? (value as AgentSdkType) : null;\n}\n\nexport function NewSessionDialog({ agent, isOpen, onClose }: NewSessionDialogProps) {\n const [name, setName] = useState('');\n const [sdk, setSdk] = useState<AgentSdkType>('claude');\n const [model, setModel] = useState(GENERIC_MODEL_FALLBACK);\n const [providers, setProviders] = useState<AIProvider[]>([]);\n\n // Auto-update default model when SDK changes\n const handleSdkChange = (newSdk: AgentSdkType) => {\n setSdk(newSdk);\n void resolveProviderDefaultModel(agent, newSdk, model)\n .then(setModel)\n .catch(() => setModel(model || GENERIC_MODEL_FALLBACK));\n };\n const [tags, setTags] = useState('');\n const [mode, setMode] = useState<ProviderMode>('sdk');\n const [creating, setCreating] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const openSession = useAgentManagerStore((s) => s.openSession);\n const bumpSessionsRefresh = useAgentManagerStore((s) => s.bumpSessionsRefresh);\n const activeChatContext = useAgentManagerStore((s) => s.activeChatContext);\n const setSessionSdk = useAgentManagerStore((s) => s.setSessionSdk);\n const setSessionModel = useAgentManagerStore((s) => s.setSessionModel);\n const setSessionMode = useAgentManagerStore((s) => s.setSessionMode);\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n useEffect(() => {\n if (!isOpen) return;\n\n let cancelled = false;\n void fetchProviders(agent)\n .then((items) => {\n if (!cancelled) setProviders(items);\n })\n .catch(() => {\n if (!cancelled) setProviders([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agent, isOpen]);\n\n useEffect(() => {\n if (!isOpen || providers.length === 0) return;\n\n const current = providers.find((provider) => providerSdk(provider) === sdk);\n const fallback = providers.find((provider) => provider.isDefault) ?? providers[0];\n const nextProvider = current ?? fallback;\n if (!nextProvider) return;\n\n const nextSdk = providerSdk(nextProvider);\n if (nextSdk && !current) {\n setSdk(nextSdk);\n }\n\n const supportedModes = nextProvider.supportedModes ?? [];\n if (supportedModes.length > 0 && !supportedModes.includes(mode)) {\n setMode(nextProvider.defaultMode ?? nextProvider.currentMode ?? supportedModes[0] ?? 'cli');\n }\n }, [isOpen, mode, providers, sdk]);\n\n useEffect(() => {\n if (!isOpen) return;\n\n let cancelled = false;\n void resolveProviderDefaultModel(agent, sdk, GENERIC_MODEL_FALLBACK)\n .then((nextModel) => {\n if (!cancelled) setModel(nextModel);\n })\n .catch(() => {\n if (!cancelled) setModel((current) => current || GENERIC_MODEL_FALLBACK);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agent, isOpen, sdk]);\n\n const handleCreate = useCallback(async () => {\n if (!name.trim()) return;\n setCreating(true);\n setError(null);\n try {\n const session = await createSession(agent, {\n name: name.trim(),\n agentType: sdk,\n config: {\n model,\n mode,\n // New sessions default to the safe autonomy level; users adjust it\n // per-session via the Autonomy control in the chat toolbar.\n permissionMode: 'acceptEdits',\n tags: tags\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean),\n },\n // Stamp the active \"bucket\" context (agent/vibe) onto the session.\n agentId: agent.id,\n contextLevel: activeChatContext.contextLevel,\n vibeId: activeChatContext.vibeId,\n });\n openSession(session.id, session.name);\n bumpSessionsRefresh();\n setSessionSdk(session.id, sdk);\n setSessionModel(session.id, model);\n setSessionMode(session.id, mode);\n // Reset form\n setName('');\n setSdk('claude');\n setModel(GENERIC_MODEL_FALLBACK);\n setMode('sdk');\n setTags('');\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create session');\n } finally {\n setCreating(false);\n }\n }, [\n agent,\n name,\n sdk,\n model,\n mode,\n tags,\n openSession,\n bumpSessionsRefresh,\n activeChatContext,\n setSessionSdk,\n setSessionModel,\n setSessionMode,\n onClose,\n ]);\n\n if (!isOpen) return null;\n\n return (\n <AnimatePresence>\n {isOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <motion.div\n className=\"absolute inset-0 bg-bg-overlay\"\n initial={shouldReduceMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n onClick={onClose}\n />\n <motion.div\n className=\"relative w-full max-w-md mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl\"\n initial={shouldReduceMotion ? undefined : { opacity: 0, scale: 0.95, y: 8 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: 8 }}\n transition={{ duration: 0.2, ease: [0.2, 0, 0, 1] }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.agentManager.dialogs.newSession', 'New Session')}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Body */}\n <div className=\"px-6 py-4 space-y-4\">\n {/* Name */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.name', 'Name')}\n </label>\n <input\n aria-label=\"My session\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"My session\"\n className=\"w-full rounded-md 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 />\n </div>\n\n {/* SDK + Mode */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.sdkAndMode', 'SDK & Mode')}\n </label>\n <SdkSelector\n sdk={sdk}\n mode={mode}\n providers={providers}\n onSdkChange={handleSdkChange}\n onModeChange={setMode}\n />\n </div>\n\n {/* Model */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.model', 'Model')}\n </label>\n <ModelSelector\n value={model}\n onChange={setModel}\n provider={sdk}\n agentId={agent.id}\n profile={agent.profile}\n />\n </div>\n\n {/* Tags */}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.agentManager.dialogs.tagsLabel', 'Tags (comma-separated)')}\n </label>\n <input\n aria-label=\"e.g. frontend, bugfix, prototype\"\n type=\"text\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"e.g. frontend, bugfix, prototype\"\n className=\"w-full rounded-md 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 />\n </div>\n\n {error && <p className=\"text-xs text-status-error-text\">{error}</p>}\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t border-border-default bg-bg-sunken rounded-b-lg\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={creating}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors disabled:opacity-50\"\n >\n {tr('vibecontrols.agentManager.dialogs.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={creating || !name.trim()}\n className=\"px-4 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {creating\n ? tr('vibecontrols.agentManager.dialogs.creating', 'Creating...')\n : tr('vibecontrols.agentManager.dialogs.create', 'Create')}\n </button>\n </div>\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
|
|
@@ -77,7 +77,7 @@ function u({ isOpen: u, sessionId: d, currentName: f, onClose: p, onRename: m })
|
|
|
77
77
|
e.key === "Enter" && y();
|
|
78
78
|
},
|
|
79
79
|
placeholder: "Session name",
|
|
80
|
-
className: "w-full rounded-md border border-border-default bg-bg-
|
|
80
|
+
className: "w-full rounded-md 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"
|
|
81
81
|
})
|
|
82
82
|
}),
|
|
83
83
|
/* @__PURE__ */ l("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RenameSessionDialog.js","names":[],"sources":["../../../../src/components/agent-manager/dialogs/RenameSessionDialog.tsx"],"sourcesContent":["/**\n * Rename session dialog.\n *\n * Simple modal with a text input for renaming a session.\n */\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { X } from 'lucide-react';\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface RenameSessionDialogProps {\n isOpen: boolean;\n sessionId: string;\n currentName: string;\n onClose: () => void;\n onRename: (sessionId: string, newName: string) => void;\n}\n\nexport function RenameSessionDialog({\n isOpen,\n sessionId,\n currentName,\n onClose,\n onRename,\n}: RenameSessionDialogProps) {\n const [name, setName] = useState(currentName);\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n useEffect(() => {\n if (isOpen) {\n setName(currentName);\n }\n }, [isOpen, currentName]);\n\n const handleSave = useCallback(() => {\n if (name.trim() && name.trim() !== currentName) {\n onRename(sessionId, name.trim());\n }\n onClose();\n }, [name, currentName, sessionId, onRename, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <AnimatePresence>\n {isOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <motion.div\n className=\"absolute inset-0 bg-bg-overlay\"\n initial={shouldReduceMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n onClick={onClose}\n />\n <motion.div\n className=\"relative w-full max-w-sm mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl\"\n initial={shouldReduceMotion ? undefined : { opacity: 0, scale: 0.95, y: 8 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: 8 }}\n transition={{ duration: 0.2, ease: [0.2, 0, 0, 1] }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.agentManager.dialogs.renameSession', 'Rename Session')}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Body */}\n <div className=\"px-6 py-4\">\n <input\n aria-label=\"Session name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleSave();\n }}\n placeholder=\"Session name\"\n className=\"w-full rounded-md border border-border-default bg-bg-
|
|
1
|
+
{"version":3,"file":"RenameSessionDialog.js","names":[],"sources":["../../../../src/components/agent-manager/dialogs/RenameSessionDialog.tsx"],"sourcesContent":["/**\n * Rename session dialog.\n *\n * Simple modal with a text input for renaming a session.\n */\n\nimport { useState, useCallback, useEffect } from 'react';\nimport { X } from 'lucide-react';\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface RenameSessionDialogProps {\n isOpen: boolean;\n sessionId: string;\n currentName: string;\n onClose: () => void;\n onRename: (sessionId: string, newName: string) => void;\n}\n\nexport function RenameSessionDialog({\n isOpen,\n sessionId,\n currentName,\n onClose,\n onRename,\n}: RenameSessionDialogProps) {\n const [name, setName] = useState(currentName);\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n useEffect(() => {\n if (isOpen) {\n setName(currentName);\n }\n }, [isOpen, currentName]);\n\n const handleSave = useCallback(() => {\n if (name.trim() && name.trim() !== currentName) {\n onRename(sessionId, name.trim());\n }\n onClose();\n }, [name, currentName, sessionId, onRename, onClose]);\n\n if (!isOpen) return null;\n\n return (\n <AnimatePresence>\n {isOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center\">\n <motion.div\n className=\"absolute inset-0 bg-bg-overlay\"\n initial={shouldReduceMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n onClick={onClose}\n />\n <motion.div\n className=\"relative w-full max-w-sm mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl\"\n initial={shouldReduceMotion ? undefined : { opacity: 0, scale: 0.95, y: 8 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: 8 }}\n transition={{ duration: 0.2, ease: [0.2, 0, 0, 1] }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-6 py-4 border-b border-border-default\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.agentManager.dialogs.renameSession', 'Rename Session')}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n\n {/* Body */}\n <div className=\"px-6 py-4\">\n <input\n aria-label=\"Session name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleSave();\n }}\n placeholder=\"Session name\"\n className=\"w-full rounded-md 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 />\n </div>\n\n {/* Footer */}\n <div className=\"flex items-center justify-end gap-3 px-6 py-4 border-t border-border-default bg-bg-sunken rounded-b-lg\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors\"\n >\n {tr('vibecontrols.agentManager.dialogs.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={!name.trim()}\n className=\"px-4 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n >\n {tr('vibecontrols.agentManager.dialogs.save', 'Save')}\n </button>\n </div>\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":";;;;;;AAmBA,SAAgB,EAAoB,EAClC,WACA,cACA,gBACA,YACA,eAC2B;CAC3B,IAAM,CAAC,GAAM,KAAW,EAAS,EAAY,EACvC,IAAqB,GAAkB,EACvC,IAAK,GAAO;AAElB,SAAgB;AACd,EAAI,KACF,EAAQ,EAAY;IAErB,CAAC,GAAQ,EAAY,CAAC;CAEzB,IAAM,IAAa,QAAkB;AAInC,EAHI,EAAK,MAAM,IAAI,EAAK,MAAM,KAAK,KACjC,EAAS,GAAW,EAAK,MAAM,CAAC,EAElC,GAAS;IACR;EAAC;EAAM;EAAa;EAAW;EAAU;EAAQ,CAAC;AAIrD,QAFK,IAGH,kBAAC,GAAD,EAAA,UACG,KACC,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,EAAO,KAAR;GACE,WAAU;GACV,SAAS,IAAqB,KAAA,IAAY,EAAE,SAAS,GAAG;GACxD,SAAS,EAAE,SAAS,GAAG;GACvB,MAAM,EAAE,SAAS,GAAG;GACpB,YAAY,EAAE,UAAU,IAAK;GAC7B,SAAS;GACT,CAAA,EACF,kBAAC,EAAO,KAAR;GACE,WAAU;GACV,SAAS,IAAqB,KAAA,IAAY;IAAE,SAAS;IAAG,OAAO;IAAM,GAAG;IAAG;GAC3E,SAAS;IAAE,SAAS;IAAG,OAAO;IAAG,GAAG;IAAG;GACvC,MAAM;IAAE,SAAS;IAAG,OAAO;IAAM,GAAG;IAAG;GACvC,YAAY;IAAE,UAAU;IAAK,MAAM;KAAC;KAAK;KAAG;KAAG;KAAE;IAAE;aALrD;IAQE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,mDAAmD,iBAAiB;MACrE,CAAA,EACL,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBAEV,kBAAC,GAAD,EAAG,WAAU,8BAA+B,CAAA;MACrC,CAAA,CACL;;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,SAAD;MACE,cAAW;MACX,MAAK;MACL,OAAO;MACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;MACxC,YAAY,MAAM;AAChB,OAAI,EAAE,QAAQ,WAAS,GAAY;;MAErC,aAAY;MACZ,WAAU;MACV,CAAA;KACE,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,WAAU;gBAET,EAAG,4CAA4C,SAAS;MAClD,CAAA,EACT,kBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,UAAU,CAAC,EAAK,MAAM;MACtB,WAAU;gBAET,EAAG,0CAA0C,OAAO;MAC9C,CAAA,CACL;;IACK;KACT;KAEQ,CAAA,GAvEA"}
|