@burdenoff/microfe-vibecontrols 2026.623.1 → 2026.623.2

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.
Files changed (293) hide show
  1. package/dist/components/actions/ActionCard.js +2 -2
  2. package/dist/components/actions/ActionCard.js.map +1 -1
  3. package/dist/components/actions/ExecutionHistory.js +1 -1
  4. package/dist/components/actions/ExecutionHistory.js.map +1 -1
  5. package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
  6. package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
  7. package/dist/components/agent-manager/AgentManagerChatPane.js +2 -2
  8. package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
  9. package/dist/components/agent-manager/AgentManagerInputArea.js +4 -4
  10. package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
  11. package/dist/components/agent-manager/AgentManagerLayout.js +1 -1
  12. package/dist/components/agent-manager/AgentManagerLayout.js.map +1 -1
  13. package/dist/components/agent-manager/AgentManagerMessageItem.js +1 -1
  14. package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
  15. package/dist/components/agent-manager/AgentManagerSidebar.js +5 -5
  16. package/dist/components/agent-manager/AgentManagerSidebar.js.map +1 -1
  17. package/dist/components/agent-manager/AgentManagerTab.js +1 -1
  18. package/dist/components/agent-manager/AgentManagerTab.js.map +1 -1
  19. package/dist/components/agent-manager/AgentManagerTabBar.js +1 -1
  20. package/dist/components/agent-manager/AgentManagerTabBar.js.map +1 -1
  21. package/dist/components/agent-manager/BridleConfigPanel.js +23 -23
  22. package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
  23. package/dist/components/agent-manager/PluginInstallModal.js +1 -1
  24. package/dist/components/agent-manager/PluginInstallModal.js.map +1 -1
  25. package/dist/components/agent-manager/ProfilesPanel.js +5 -5
  26. package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
  27. package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
  28. package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
  29. package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
  30. package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
  31. package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
  32. package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
  33. package/dist/components/agent-manager/detail/SessionConfigPanel.js +6 -6
  34. package/dist/components/agent-manager/detail/SessionConfigPanel.js.map +1 -1
  35. package/dist/components/agent-manager/detail/SessionLogsPanel.js +5 -5
  36. package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
  37. package/dist/components/agent-manager/detail/SessionToolsPanel.js +1 -1
  38. package/dist/components/agent-manager/detail/SessionToolsPanel.js.map +1 -1
  39. package/dist/components/agent-manager/dialogs/NewSessionDialog.js +2 -2
  40. package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
  41. package/dist/components/agent-manager/dialogs/RenameSessionDialog.js +1 -1
  42. package/dist/components/agent-manager/dialogs/RenameSessionDialog.js.map +1 -1
  43. package/dist/components/agents/AgentCard.js +14 -11
  44. package/dist/components/agents/AgentCard.js.map +1 -1
  45. package/dist/components/ai/AIContextsTab.js +1 -1
  46. package/dist/components/ai/AIContextsTab.js.map +1 -1
  47. package/dist/components/ai/AIOverviewTab.js +4 -4
  48. package/dist/components/ai/AIOverviewTab.js.map +1 -1
  49. package/dist/components/ai/AIPlanPanel.js +4 -4
  50. package/dist/components/ai/AIPlanPanel.js.map +1 -1
  51. package/dist/components/ai/AIPlaygroundTab.js +1 -1
  52. package/dist/components/ai/AIPlaygroundTab.js.map +1 -1
  53. package/dist/components/ai/AIPromptsTab.js +2 -2
  54. package/dist/components/ai/AIPromptsTab.js.map +1 -1
  55. package/dist/components/ai/AIProviderCredentialsCard.js +4 -4
  56. package/dist/components/ai/AIProviderCredentialsCard.js.map +1 -1
  57. package/dist/components/ai/AIQueueTab.js +4 -4
  58. package/dist/components/ai/AIQueueTab.js.map +1 -1
  59. package/dist/components/ai/AISessionsTab.js +4 -4
  60. package/dist/components/ai/AISessionsTab.js.map +1 -1
  61. package/dist/components/ai/AITasksTab.js +1 -1
  62. package/dist/components/ai/AITasksTab.js.map +1 -1
  63. package/dist/components/ai/ClaudeCredentialsCard.js +3 -3
  64. package/dist/components/ai/ClaudeCredentialsCard.js.map +1 -1
  65. package/dist/components/ai/PluginHarnessPicker.js +3 -3
  66. package/dist/components/ai/PluginHarnessPicker.js.map +1 -1
  67. package/dist/components/analytics/AnalyticsBreakdownChart.js +8 -8
  68. package/dist/components/analytics/AnalyticsBreakdownChart.js.map +1 -1
  69. package/dist/components/analytics/AnalyticsTimeSeriesChart.js +5 -5
  70. package/dist/components/analytics/AnalyticsTimeSeriesChart.js.map +1 -1
  71. package/dist/components/audit/AuditDeleteDialog.js +2 -2
  72. package/dist/components/audit/AuditDeleteDialog.js.map +1 -1
  73. package/dist/components/audit/AuditExportButton.js +5 -5
  74. package/dist/components/audit/AuditExportButton.js.map +1 -1
  75. package/dist/components/audit/AuditLogDetail.js +9 -9
  76. package/dist/components/audit/AuditLogDetail.js.map +1 -1
  77. package/dist/components/audit/AuditLogFilters.js +1 -1
  78. package/dist/components/audit/AuditLogFilters.js.map +1 -1
  79. package/dist/components/audit/AuditLogStats.js +1 -1
  80. package/dist/components/audit/AuditLogStats.js.map +1 -1
  81. package/dist/components/audit/AuditLogTable.js +28 -28
  82. package/dist/components/audit/AuditLogTable.js.map +1 -1
  83. package/dist/components/catalog/CatalogCard.js +3 -3
  84. package/dist/components/catalog/CatalogCard.js.map +1 -1
  85. package/dist/components/catalog/CatalogForm.js +1 -1
  86. package/dist/components/catalog/CatalogForm.js.map +1 -1
  87. package/dist/components/common/ActionAgentTargetNotice.js +6 -6
  88. package/dist/components/common/ActionAgentTargetNotice.js.map +1 -1
  89. package/dist/components/common/CommandEditor.js +1 -1
  90. package/dist/components/common/CommandEditor.js.map +1 -1
  91. package/dist/components/docs/DocsPageTree.js +1 -1
  92. package/dist/components/docs/DocsPageTree.js.map +1 -1
  93. package/dist/components/docs/DocsPreviewPanel.js +1 -1
  94. package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
  95. package/dist/components/docs/DocsRevisionHistory.js +4 -4
  96. package/dist/components/docs/DocsRevisionHistory.js.map +1 -1
  97. package/dist/components/docs/DocsSettingsPanel.js +7 -7
  98. package/dist/components/docs/DocsSettingsPanel.js.map +1 -1
  99. package/dist/components/docs/DocsTabPanel.js +1 -1
  100. package/dist/components/docs/DocsTabPanel.js.map +1 -1
  101. package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
  102. package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
  103. package/dist/components/graph/MeshDeployWizard.js +3 -3
  104. package/dist/components/graph/MeshDeployWizard.js.map +1 -1
  105. package/dist/components/graph/MeshRequestPanel.js +2 -2
  106. package/dist/components/graph/MeshRequestPanel.js.map +1 -1
  107. package/dist/components/idp-components/ComponentCard.js +5 -5
  108. package/dist/components/idp-components/ComponentCard.js.map +1 -1
  109. package/dist/components/idp-components/ComponentForm.js +1 -1
  110. package/dist/components/idp-components/ComponentForm.js.map +1 -1
  111. package/dist/components/idp-components/DependencyGraphTab.js +7 -7
  112. package/dist/components/idp-components/DependencyGraphTab.js.map +1 -1
  113. package/dist/components/logs/LogViewer.js +14 -14
  114. package/dist/components/logs/LogViewer.js.map +1 -1
  115. package/dist/components/notes/NoteCard.js +1 -1
  116. package/dist/components/notes/NoteCard.js.map +1 -1
  117. package/dist/components/notes/NoteEditor.js +2 -2
  118. package/dist/components/notes/NoteEditor.js.map +1 -1
  119. package/dist/components/notes/NoteList.js +1 -1
  120. package/dist/components/notes/NoteList.js.map +1 -1
  121. package/dist/components/notes/NotesTabPanel.js +1 -1
  122. package/dist/components/notes/NotesTabPanel.js.map +1 -1
  123. package/dist/components/scorecard/ScorecardEmptyState.js +1 -1
  124. package/dist/components/scorecard/ScorecardEmptyState.js.map +1 -1
  125. package/dist/components/scorecard/ScorecardPanel.js +3 -3
  126. package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
  127. package/dist/components/security/SecurityScanList.js +11 -11
  128. package/dist/components/security/SecurityScanList.js.map +1 -1
  129. package/dist/components/sessions/SessionCard.js +26 -19
  130. package/dist/components/sessions/SessionCard.js.map +1 -1
  131. package/dist/components/sessions/SessionStatusBadge.js +7 -7
  132. package/dist/components/sessions/SessionStatusBadge.js.map +1 -1
  133. package/dist/components/shared/AgentSelector.js +4 -4
  134. package/dist/components/shared/AgentSelector.js.map +1 -1
  135. package/dist/components/shared/AgentSetupBanner.js +3 -3
  136. package/dist/components/shared/AgentSetupBanner.js.map +1 -1
  137. package/dist/components/shared/Card.js +4 -4
  138. package/dist/components/shared/Card.js.map +1 -1
  139. package/dist/components/shared/ErrorState.js +15 -9
  140. package/dist/components/shared/ErrorState.js.map +1 -1
  141. package/dist/components/shared/FilterDropdown.js +2 -2
  142. package/dist/components/shared/FilterDropdown.js.map +1 -1
  143. package/dist/components/shared/PageSkeleton.js +6 -6
  144. package/dist/components/shared/PageSkeleton.js.map +1 -1
  145. package/dist/components/shared/SearchInput.js +1 -1
  146. package/dist/components/shared/SearchInput.js.map +1 -1
  147. package/dist/components/shared/StatCard.js +7 -7
  148. package/dist/components/shared/StatCard.js.map +1 -1
  149. package/dist/components/templates/PublishTemplateForm.js +2 -2
  150. package/dist/components/templates/PublishTemplateForm.js.map +1 -1
  151. package/dist/components/templates/TemplateCard.js +5 -5
  152. package/dist/components/templates/TemplateCard.js.map +1 -1
  153. package/dist/components/templates/TemplateWizard.js +2 -2
  154. package/dist/components/templates/TemplateWizard.js.map +1 -1
  155. package/dist/components/tunnels/DomainVerificationBadge.js +4 -4
  156. package/dist/components/tunnels/DomainVerificationBadge.js.map +1 -1
  157. package/dist/components/tunnels/ProviderBadge.js +1 -1
  158. package/dist/components/tunnels/ProviderBadge.js.map +1 -1
  159. package/dist/components/tunnels/TunnelCard.js +16 -16
  160. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  161. package/dist/components/tunnels/TunnelCreateWizard.js +1 -1
  162. package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
  163. package/dist/components/tunnels/TunnelPublicAccessPanel.js +1 -1
  164. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  165. package/dist/components/tunnels/TunnelStatusBadge.js +4 -4
  166. package/dist/components/tunnels/TunnelStatusBadge.js.map +1 -1
  167. package/dist/components/vibecalendar/LogsDrawer.js +2 -2
  168. package/dist/components/vibecalendar/LogsDrawer.js.map +1 -1
  169. package/dist/components/vibecalendar/ScheduleTaskModal.js +5 -5
  170. package/dist/components/vibecalendar/ScheduleTaskModal.js.map +1 -1
  171. package/dist/components/vibecalendar/VibeCalAgendaView.js +2 -2
  172. package/dist/components/vibecalendar/VibeCalAgendaView.js.map +1 -1
  173. package/dist/components/vibecalendar/VibeCalDayView.js +3 -3
  174. package/dist/components/vibecalendar/VibeCalDayView.js.map +1 -1
  175. package/dist/components/vibecalendar/VibeCalMonthView.js +1 -1
  176. package/dist/components/vibecalendar/VibeCalMonthView.js.map +1 -1
  177. package/dist/components/vibecalendar/VibeCalWeekView.js +4 -4
  178. package/dist/components/vibecalendar/VibeCalWeekView.js.map +1 -1
  179. package/dist/components/vibecalendar/VibeCalendarHeader.js +4 -4
  180. package/dist/components/vibecalendar/VibeCalendarHeader.js.map +1 -1
  181. package/dist/components/vibecalendar/VibeTaskBlock.js +2 -2
  182. package/dist/components/vibecalendar/VibeTaskBlock.js.map +1 -1
  183. package/dist/components/vibecalendar/types.js +6 -6
  184. package/dist/components/vibecalendar/types.js.map +1 -1
  185. package/dist/components/vibedeck/VibeDeckButtonForm.js +9 -9
  186. package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
  187. package/dist/components/vibedeck/VibeDeckButtonTile.js +6 -6
  188. package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
  189. package/dist/components/vibedeck/VibeDeckExecutionLog.js +10 -10
  190. package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
  191. package/dist/components/vibedeck/VibeDeckForm.js +8 -8
  192. package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
  193. package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
  194. package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
  195. package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +2 -2
  196. package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -1
  197. package/dist/components/vibedeck/VibeDeckSwitcher.js +8 -8
  198. package/dist/components/vibedeck/VibeDeckSwitcher.js.map +1 -1
  199. package/dist/components/vibes/VibeCard.js +22 -18
  200. package/dist/components/vibes/VibeCard.js.map +1 -1
  201. package/dist/components/vibes/VibeList.js +16 -12
  202. package/dist/components/vibes/VibeList.js.map +1 -1
  203. package/dist/pages/ActionsPage.js +4 -3
  204. package/dist/pages/ActionsPage.js.map +1 -1
  205. package/dist/pages/AgentDetailsPage.js +9 -9
  206. package/dist/pages/AgentDetailsPage.js.map +1 -1
  207. package/dist/pages/AgentsLandingPage.js +4 -4
  208. package/dist/pages/AgentsLandingPage.js.map +1 -1
  209. package/dist/pages/AgentsPage.js +14 -14
  210. package/dist/pages/AgentsPage.js.map +1 -1
  211. package/dist/pages/AnalyticsPage.js +8 -8
  212. package/dist/pages/AnalyticsPage.js.map +1 -1
  213. package/dist/pages/CatalogDetailPage.js +11 -11
  214. package/dist/pages/CatalogDetailPage.js.map +1 -1
  215. package/dist/pages/CatalogPage.js +12 -9
  216. package/dist/pages/CatalogPage.js.map +1 -1
  217. package/dist/pages/ComponentDetailPage.js +7 -7
  218. package/dist/pages/ComponentDetailPage.js.map +1 -1
  219. package/dist/pages/ComponentsPage.js +12 -9
  220. package/dist/pages/ComponentsPage.js.map +1 -1
  221. package/dist/pages/EnvTopologyPage.js +2 -2
  222. package/dist/pages/EnvTopologyPage.js.map +1 -1
  223. package/dist/pages/GettingStartedPage.js +12 -12
  224. package/dist/pages/GettingStartedPage.js.map +1 -1
  225. package/dist/pages/HealthPage.js +12 -12
  226. package/dist/pages/HealthPage.js.map +1 -1
  227. package/dist/pages/LogsPage.js +4 -4
  228. package/dist/pages/LogsPage.js.map +1 -1
  229. package/dist/pages/NoteDetailsPage.js +5 -5
  230. package/dist/pages/NoteDetailsPage.js.map +1 -1
  231. package/dist/pages/OverviewPage.js +74 -41
  232. package/dist/pages/OverviewPage.js.map +1 -1
  233. package/dist/pages/PluginsCatalogPage.js +6 -3
  234. package/dist/pages/PluginsCatalogPage.js.map +1 -1
  235. package/dist/pages/ScheduledJobDetailPage.js +7 -7
  236. package/dist/pages/ScheduledJobDetailPage.js.map +1 -1
  237. package/dist/pages/SessionDetailsPage.js +21 -21
  238. package/dist/pages/SessionDetailsPage.js.map +1 -1
  239. package/dist/pages/SessionsPage.js +20 -20
  240. package/dist/pages/SessionsPage.js.map +1 -1
  241. package/dist/pages/SettingsPage.js +64 -52
  242. package/dist/pages/SettingsPage.js.map +1 -1
  243. package/dist/pages/SharedSessionPage.js +21 -21
  244. package/dist/pages/SharedSessionPage.js.map +1 -1
  245. package/dist/pages/SharedVibeDeckPage.js +5 -5
  246. package/dist/pages/SharedVibeDeckPage.js.map +1 -1
  247. package/dist/pages/TargetDetailsPage.js +56 -65
  248. package/dist/pages/TargetDetailsPage.js.map +1 -1
  249. package/dist/pages/TargetsPage.js +4 -4
  250. package/dist/pages/TargetsPage.js.map +1 -1
  251. package/dist/pages/TemplateDetailPage.js +10 -10
  252. package/dist/pages/TemplateDetailPage.js.map +1 -1
  253. package/dist/pages/TemplatesPage.js +6 -5
  254. package/dist/pages/TemplatesPage.js.map +1 -1
  255. package/dist/pages/VibeAuditPage.js +3 -3
  256. package/dist/pages/VibeAuditPage.js.map +1 -1
  257. package/dist/pages/VibeCalendarPage.js +3 -3
  258. package/dist/pages/VibeCalendarPage.js.map +1 -1
  259. package/dist/pages/VibeDeckPage.js +3 -3
  260. package/dist/pages/VibeDeckPage.js.map +1 -1
  261. package/dist/pages/VibeDetailsPage.js +15 -15
  262. package/dist/pages/VibeDetailsPage.js.map +1 -1
  263. package/dist/pages/VibeTaskDetailPage.js +5 -5
  264. package/dist/pages/VibeTaskDetailPage.js.map +1 -1
  265. package/dist/pages/VibesPage.js +18 -18
  266. package/dist/pages/VibesPage.js.map +1 -1
  267. package/dist/pages/WebhooksPage.js +11 -11
  268. package/dist/pages/WebhooksPage.js.map +1 -1
  269. package/dist/pages/ai/AIBookmarksPage.js +1 -1
  270. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  271. package/dist/pages/ai/AISessionDetailPage.js +6 -6
  272. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  273. package/dist/pages/tunnels/AuditTab.js +1 -1
  274. package/dist/pages/tunnels/AuditTab.js.map +1 -1
  275. package/dist/pages/tunnels/DomainsTab.js +1 -1
  276. package/dist/pages/tunnels/DomainsTab.js.map +1 -1
  277. package/dist/pages/tunnels/ProvidersTab.js +1 -1
  278. package/dist/pages/tunnels/ProvidersTab.js.map +1 -1
  279. package/dist/pages/tunnels/SessionsTab.js +1 -1
  280. package/dist/pages/tunnels/SessionsTab.js.map +1 -1
  281. package/dist/pages/tunnels/TunnelDetailsPage.js +3 -3
  282. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  283. package/dist/pages/tunnels/UsageTab.js +1 -1
  284. package/dist/pages/tunnels/UsageTab.js.map +1 -1
  285. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +16 -16
  286. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  287. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +1 -1
  288. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  289. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +52 -49
  290. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  291. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +9 -9
  292. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  293. package/package.json +1 -1
@@ -52,7 +52,7 @@ function b({ action: b, onExecute: x, onEdit: S, onDuplicate: C, onDelete: w, on
52
52
  e.stopPropagation(), x(b.id);
53
53
  },
54
54
  disabled: A,
55
- className: "p-1.5 rounded-md hover:bg-status-success-bg/20 text-status-success-text transition-colors disabled:opacity-50",
55
+ className: "p-1.5 rounded-md hover:bg-status-success-bg-subtle text-status-success-text transition-colors disabled:opacity-50",
56
56
  title: P("vibecontrols.actions.card.execute", "Execute"),
57
57
  children: /* @__PURE__ */ v(m, { size: 14 })
58
58
  }),
@@ -106,7 +106,7 @@ function b({ action: b, onExecute: x, onEdit: S, onDuplicate: C, onDelete: w, on
106
106
  onClick: (e) => {
107
107
  e.stopPropagation(), w(b.id);
108
108
  },
109
- className: "p-1.5 rounded-md hover:bg-status-error-bg/20 text-status-error-text transition-colors",
109
+ className: "p-1.5 rounded-md hover:bg-status-error-bg-subtle text-status-error-text transition-colors",
110
110
  title: P("vibecontrols.actions.card.delete", "Delete"),
111
111
  children: /* @__PURE__ */ v(h, { size: 14 })
112
112
  })
@@ -1 +1 @@
1
- {"version":3,"file":"ActionCard.js","names":[],"sources":["../../../src/components/actions/ActionCard.tsx"],"sourcesContent":["import { Play, Pencil, Copy, Trash2, Clock, Hash, CalendarClock, AlarmClock } from 'lucide-react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { ActionTypeBadge, TriggerTypeBadge, SourceTypeBadge } from './ActionTypeBadge';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\nimport { EntityShareButton } from '../sharing';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { VibeEntityType, VibeVisibility } from '@/generated/wspace-types';\n\ninterface ActionCardAction {\n id: string;\n name: string;\n displayName?: string | null;\n description?: string | null;\n actionType: string;\n sourceType?: string | null;\n triggerType: string;\n category?: string | null;\n tags?: string[] | null;\n executionCount?: number | null;\n lastExecutedAt?: string | null;\n confirmationRequired?: boolean;\n vibeId?: string | null;\n visibility?: VibeVisibility | null;\n}\n\ninterface ActionCardProps {\n action: ActionCardAction;\n onExecute: (id: string) => void;\n onEdit: (id: string) => void;\n onDuplicate: (id: string) => void;\n onDelete: (id: string) => void;\n onSchedule?: (id: string) => void;\n onAddToCalendar?: (id: string) => void;\n canUpdate: boolean;\n canDelete: boolean;\n canExecute: boolean;\n isExecuting?: boolean;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}\n\nexport function ActionCard({\n action,\n onExecute,\n onEdit,\n onDuplicate,\n onDelete,\n onSchedule,\n onAddToCalendar,\n canUpdate,\n canDelete,\n canExecute,\n isExecuting = false,\n selected = false,\n onToggleSelect,\n}: ActionCardProps) {\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n const formatDate = (dateStr: string | null | undefined) => {\n if (!dateStr) return tr('vibecontrols.actions.card.never', 'Never');\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return tr('vibecontrols.actions.card.justNow', 'Just now');\n if (diffMin < 60)\n return tr('vibecontrols.actions.card.minutesAgo', '{{count}}m ago', { count: diffMin });\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24)\n return tr('vibecontrols.actions.card.hoursAgo', '{{count}}h ago', { count: diffHr });\n const diffDays = Math.floor(diffHr / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n };\n\n return (\n <motion.div\n className={`bg-bg-surface border rounded-lg p-4 hover:border-border-strong transition-colors group ${\n selected\n ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25'\n : 'border-border-default'\n }`}\n whileHover={\n shouldReduceMotion\n ? undefined\n : { y: -2, boxShadow: '0 4px 12px var(--color-border-default)' }\n }\n transition={{ duration: 0.15 }}\n layout\n role=\"group\"\n aria-label={`Action: ${action.displayName || action.name}`}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between gap-3 mb-3\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={`Select action ${action.displayName || action.name}`}\n />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate\">\n {action.displayName || action.name}\n </h3>\n {action.description && (\n <p className=\"text-sm text-text-secondary mt-0.5 line-clamp-2\">\n {action.description}\n </p>\n )}\n </div>\n </div>\n {/* Action buttons */}\n <div className=\"flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\">\n {canExecute && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onExecute(action.id);\n }}\n disabled={isExecuting}\n className=\"p-1.5 rounded-md hover:bg-status-success-bg/20 text-status-success-text transition-colors disabled:opacity-50\"\n title={tr('vibecontrols.actions.card.execute', 'Execute')}\n >\n <Play size={14} />\n </button>\n )}\n {canUpdate && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onEdit(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.edit', 'Edit')}\n >\n <Pencil size={14} />\n </button>\n )}\n {onSchedule && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onSchedule(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.schedule', 'Schedule this action')}\n >\n <AlarmClock size={14} />\n </button>\n )}\n {onAddToCalendar && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onAddToCalendar(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.addToCalendar', 'Add to calendar')}\n >\n <CalendarClock size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDuplicate(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.duplicate', 'Duplicate')}\n >\n <Copy size={14} />\n </button>\n <EntityShareButton\n entity=\"action\"\n resource={{\n id: action.id,\n name: action.displayName || action.name,\n vibeId: action.vibeId ?? null,\n }}\n label={tr('vibecontrols.actions.card.share', 'Share')}\n />\n {canDelete && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDelete(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-status-error-bg/20 text-status-error-text transition-colors\"\n title={tr('vibecontrols.actions.card.delete', 'Delete')}\n >\n <Trash2 size={14} />\n </button>\n )}\n </div>\n </div>\n\n {/* Badges */}\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n <ActionTypeBadge type={action.actionType} />\n <TriggerTypeBadge type={action.triggerType} />\n {action.sourceType && <SourceTypeBadge type={action.sourceType} />}\n </div>\n\n {/* Linked vibe — map / unmap this action to a vibe */}\n <div className=\"mb-3\" onClick={(event) => event.stopPropagation()}>\n <EntityVibeLinkControl\n entityType={VibeEntityType.Action}\n entityId={action.id}\n currentVibeId={action.vibeId ?? null}\n currentVisibility={action.visibility ?? null}\n refetchQueries={['ListActions']}\n />\n </div>\n\n {/* Category and Tags */}\n {(action.category || (action.tags && action.tags.length > 0)) && (\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n {action.category && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary\">\n {action.category}\n </span>\n )}\n {action.tags?.map((tag) => (\n <span\n key={tag}\n className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-placeholder\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n\n {/* Stats */}\n <div className=\"flex items-center gap-4 text-xs text-text-placeholder\">\n <span className=\"inline-flex items-center gap-1\">\n <Hash size={12} />\n {tr('vibecontrols.actions.card.executionRuns', '{{count}} runs', {\n count: action.executionCount ?? 0,\n })}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={12} />\n {formatDate(action.lastExecutedAt)}\n </span>\n </div>\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;;;AA0CA,SAAgB,EAAW,EACzB,WACA,cACA,WACA,gBACA,aACA,eACA,oBACA,cACA,cACA,eACA,iBAAc,IACd,cAAW,IACX,qBACkB;CAClB,IAAM,IAAqB,GAAkB,EACvC,IAAK,GAAO;AAmBlB,QACE,kBAAC,EAAO,KAAR;EACE,WAAW,0FACT,IACI,8DACA;EAEN,YACE,IACI,KAAA,IACA;GAAE,GAAG;GAAI,WAAW;GAA0C;EAEpE,YAAY,EAAE,UAAU,KAAM;EAC9B,QAAA;EACA,MAAK;EACL,cAAY,WAAW,EAAO,eAAe,EAAO;YAdtD;GAiBE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,OAAD;MAAK,UAAU,MAAU,EAAM,iBAAiB;gBAC9C,kBAAC,GAAD;OACE,SAAS;OACT,UAAU;OACV,WAAW,iBAAiB,EAAO,eAAe,EAAO;OACzD,CAAA;MACE,CAAA,EAER,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAO,eAAe,EAAO;OAC3B,CAAA,EACJ,EAAO,eACN,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAO;OACN,CAAA,CAEF;QACF;QAEN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAU,EAAO,GAAG;;OAEtB,UAAU;OACV,WAAU;OACV,OAAO,EAAG,qCAAqC,UAAU;iBAEzD,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;OACX,CAAA;MAEV,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAO,EAAO,GAAG;;OAEnB,WAAU;OACV,OAAO,EAAG,kCAAkC,OAAO;iBAEnD,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;OACb,CAAA;MAEV,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAW,EAAO,GAAG;;OAEvB,WAAU;OACV,OAAO,EAAG,sCAAsC,uBAAuB;iBAEvE,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;OACjB,CAAA;MAEV,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAgB,EAAO,GAAG;;OAE5B,WAAU;OACV,OAAO,EAAG,2CAA2C,kBAAkB;iBAEvE,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;OACpB,CAAA;MAEX,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAY,EAAO,GAAG;;OAExB,WAAU;OACV,OAAO,EAAG,uCAAuC,YAAY;iBAE7D,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;OACX,CAAA;MACT,kBAAC,GAAD;OACE,QAAO;OACP,UAAU;QACR,IAAI,EAAO;QACX,MAAM,EAAO,eAAe,EAAO;QACnC,QAAQ,EAAO,UAAU;QAC1B;OACD,OAAO,EAAG,mCAAmC,QAAQ;OACrD,CAAA;MACD,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAS,EAAO,GAAG;;OAErB,WAAU;OACV,OAAO,EAAG,oCAAoC,SAAS;iBAEvD,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;OACb,CAAA;MAEP;OACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAiB,MAAM,EAAO,YAAc,CAAA;KAC5C,kBAAC,GAAD,EAAkB,MAAM,EAAO,aAAe,CAAA;KAC7C,EAAO,cAAc,kBAAC,GAAD,EAAiB,MAAM,EAAO,YAAc,CAAA;KAC9D;;GAGN,kBAAC,OAAD;IAAK,WAAU;IAAO,UAAU,MAAU,EAAM,iBAAiB;cAC/D,kBAAC,GAAD;KACE,YAAY,EAAe;KAC3B,UAAU,EAAO;KACjB,eAAe,EAAO,UAAU;KAChC,mBAAmB,EAAO,cAAc;KACxC,gBAAgB,CAAC,cAAc;KAC/B,CAAA;IACE,CAAA;IAGJ,EAAO,YAAa,EAAO,QAAQ,EAAO,KAAK,SAAS,MACxD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAO,YACN,kBAAC,QAAD;KAAM,WAAU;eACb,EAAO;KACH,CAAA,EAER,EAAO,MAAM,KAAK,MACjB,kBAAC,QAAD;KAEE,WAAU;eAFZ,CAGC,KACG,EACG;OAJA,EAIA,CACP,CACE;;GAIR,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,2CAA2C,kBAAkB,EAC/D,OAAO,EAAO,kBAAkB,GACjC,CAAC,CACG;QACP,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,IAlMP,MAAuC;AACzD,UAAI,CAAC,EAAS,QAAO,EAAG,mCAAmC,QAAQ;MACnE,IAAM,IAAO,IAAI,KAAK,EAAQ,EAExB,qBADM,IAAI,MAAM,EACH,SAAS,GAAG,EAAK,SAAS,EACvC,IAAU,KAAK,MAAM,IAAS,IAAM;AAC1C,UAAI,IAAU,EAAG,QAAO,EAAG,qCAAqC,WAAW;AAC3E,UAAI,IAAU,GACZ,QAAO,EAAG,wCAAwC,kBAAkB,EAAE,OAAO,GAAS,CAAC;MACzF,IAAM,IAAS,KAAK,MAAM,IAAU,GAAG;AACvC,UAAI,IAAS,GACX,QAAO,EAAG,sCAAsC,kBAAkB,EAAE,OAAO,GAAQ,CAAC;MACtF,IAAM,IAAW,KAAK,MAAM,IAAS,GAAG;AAExC,aADI,IAAW,IAAU,GAAG,EAAS,SAC9B,EAAK,oBAAoB;QAqLd,EAAO,eAAe,CAC7B;OACH;;GACK"}
1
+ {"version":3,"file":"ActionCard.js","names":[],"sources":["../../../src/components/actions/ActionCard.tsx"],"sourcesContent":["import { Play, Pencil, Copy, Trash2, Clock, Hash, CalendarClock, AlarmClock } from 'lucide-react';\nimport { motion, useReducedMotion } from 'framer-motion';\nimport { ActionTypeBadge, TriggerTypeBadge, SourceTypeBadge } from './ActionTypeBadge';\nimport { SelectionCheckbox } from '../shared/SelectionCheckbox';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\nimport { EntityShareButton } from '../sharing';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { VibeEntityType, VibeVisibility } from '@/generated/wspace-types';\n\ninterface ActionCardAction {\n id: string;\n name: string;\n displayName?: string | null;\n description?: string | null;\n actionType: string;\n sourceType?: string | null;\n triggerType: string;\n category?: string | null;\n tags?: string[] | null;\n executionCount?: number | null;\n lastExecutedAt?: string | null;\n confirmationRequired?: boolean;\n vibeId?: string | null;\n visibility?: VibeVisibility | null;\n}\n\ninterface ActionCardProps {\n action: ActionCardAction;\n onExecute: (id: string) => void;\n onEdit: (id: string) => void;\n onDuplicate: (id: string) => void;\n onDelete: (id: string) => void;\n onSchedule?: (id: string) => void;\n onAddToCalendar?: (id: string) => void;\n canUpdate: boolean;\n canDelete: boolean;\n canExecute: boolean;\n isExecuting?: boolean;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n}\n\nexport function ActionCard({\n action,\n onExecute,\n onEdit,\n onDuplicate,\n onDelete,\n onSchedule,\n onAddToCalendar,\n canUpdate,\n canDelete,\n canExecute,\n isExecuting = false,\n selected = false,\n onToggleSelect,\n}: ActionCardProps) {\n const shouldReduceMotion = useReducedMotion();\n const tr = useTr();\n\n const formatDate = (dateStr: string | null | undefined) => {\n if (!dateStr) return tr('vibecontrols.actions.card.never', 'Never');\n const date = new Date(dateStr);\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMin = Math.floor(diffMs / 60000);\n if (diffMin < 1) return tr('vibecontrols.actions.card.justNow', 'Just now');\n if (diffMin < 60)\n return tr('vibecontrols.actions.card.minutesAgo', '{{count}}m ago', { count: diffMin });\n const diffHr = Math.floor(diffMin / 60);\n if (diffHr < 24)\n return tr('vibecontrols.actions.card.hoursAgo', '{{count}}h ago', { count: diffHr });\n const diffDays = Math.floor(diffHr / 24);\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n };\n\n return (\n <motion.div\n className={`bg-bg-surface border rounded-lg p-4 hover:border-border-strong transition-colors group ${\n selected\n ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25'\n : 'border-border-default'\n }`}\n whileHover={\n shouldReduceMotion\n ? undefined\n : { y: -2, boxShadow: '0 4px 12px var(--color-border-default)' }\n }\n transition={{ duration: 0.15 }}\n layout\n role=\"group\"\n aria-label={`Action: ${action.displayName || action.name}`}\n >\n {/* Header */}\n <div className=\"flex items-start justify-between gap-3 mb-3\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n {onToggleSelect && (\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selected}\n onChange={onToggleSelect}\n ariaLabel={`Select action ${action.displayName || action.name}`}\n />\n </div>\n )}\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate\">\n {action.displayName || action.name}\n </h3>\n {action.description && (\n <p className=\"text-sm text-text-secondary mt-0.5 line-clamp-2\">\n {action.description}\n </p>\n )}\n </div>\n </div>\n {/* Action buttons */}\n <div className=\"flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0\">\n {canExecute && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onExecute(action.id);\n }}\n disabled={isExecuting}\n className=\"p-1.5 rounded-md hover:bg-status-success-bg-subtle text-status-success-text transition-colors disabled:opacity-50\"\n title={tr('vibecontrols.actions.card.execute', 'Execute')}\n >\n <Play size={14} />\n </button>\n )}\n {canUpdate && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onEdit(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.edit', 'Edit')}\n >\n <Pencil size={14} />\n </button>\n )}\n {onSchedule && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onSchedule(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.schedule', 'Schedule this action')}\n >\n <AlarmClock size={14} />\n </button>\n )}\n {onAddToCalendar && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onAddToCalendar(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.addToCalendar', 'Add to calendar')}\n >\n <CalendarClock size={14} />\n </button>\n )}\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDuplicate(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-bg-elevated text-text-secondary transition-colors\"\n title={tr('vibecontrols.actions.card.duplicate', 'Duplicate')}\n >\n <Copy size={14} />\n </button>\n <EntityShareButton\n entity=\"action\"\n resource={{\n id: action.id,\n name: action.displayName || action.name,\n vibeId: action.vibeId ?? null,\n }}\n label={tr('vibecontrols.actions.card.share', 'Share')}\n />\n {canDelete && (\n <button\n type=\"button\"\n onClick={(event) => {\n event.stopPropagation();\n onDelete(action.id);\n }}\n className=\"p-1.5 rounded-md hover:bg-status-error-bg-subtle text-status-error-text transition-colors\"\n title={tr('vibecontrols.actions.card.delete', 'Delete')}\n >\n <Trash2 size={14} />\n </button>\n )}\n </div>\n </div>\n\n {/* Badges */}\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n <ActionTypeBadge type={action.actionType} />\n <TriggerTypeBadge type={action.triggerType} />\n {action.sourceType && <SourceTypeBadge type={action.sourceType} />}\n </div>\n\n {/* Linked vibe — map / unmap this action to a vibe */}\n <div className=\"mb-3\" onClick={(event) => event.stopPropagation()}>\n <EntityVibeLinkControl\n entityType={VibeEntityType.Action}\n entityId={action.id}\n currentVibeId={action.vibeId ?? null}\n currentVisibility={action.visibility ?? null}\n refetchQueries={['ListActions']}\n />\n </div>\n\n {/* Category and Tags */}\n {(action.category || (action.tags && action.tags.length > 0)) && (\n <div className=\"flex flex-wrap items-center gap-1.5 mb-3\">\n {action.category && (\n <span className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-secondary\">\n {action.category}\n </span>\n )}\n {action.tags?.map((tag) => (\n <span\n key={tag}\n className=\"text-xs px-1.5 py-0.5 rounded bg-bg-sunken text-text-placeholder\"\n >\n #{tag}\n </span>\n ))}\n </div>\n )}\n\n {/* Stats */}\n <div className=\"flex items-center gap-4 text-xs text-text-placeholder\">\n <span className=\"inline-flex items-center gap-1\">\n <Hash size={12} />\n {tr('vibecontrols.actions.card.executionRuns', '{{count}} runs', {\n count: action.executionCount ?? 0,\n })}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock size={12} />\n {formatDate(action.lastExecutedAt)}\n </span>\n </div>\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;;;AA0CA,SAAgB,EAAW,EACzB,WACA,cACA,WACA,gBACA,aACA,eACA,oBACA,cACA,cACA,eACA,iBAAc,IACd,cAAW,IACX,qBACkB;CAClB,IAAM,IAAqB,GAAkB,EACvC,IAAK,GAAO;AAmBlB,QACE,kBAAC,EAAO,KAAR;EACE,WAAW,0FACT,IACI,8DACA;EAEN,YACE,IACI,KAAA,IACA;GAAE,GAAG;GAAI,WAAW;GAA0C;EAEpE,YAAY,EAAE,UAAU,KAAM;EAC9B,QAAA;EACA,MAAK;EACL,cAAY,WAAW,EAAO,eAAe,EAAO;YAdtD;GAiBE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,OAAD;MAAK,UAAU,MAAU,EAAM,iBAAiB;gBAC9C,kBAAC,GAAD;OACE,SAAS;OACT,UAAU;OACV,WAAW,iBAAiB,EAAO,eAAe,EAAO;OACzD,CAAA;MACE,CAAA,EAER,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAO,eAAe,EAAO;OAC3B,CAAA,EACJ,EAAO,eACN,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAO;OACN,CAAA,CAEF;QACF;QAEN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAU,EAAO,GAAG;;OAEtB,UAAU;OACV,WAAU;OACV,OAAO,EAAG,qCAAqC,UAAU;iBAEzD,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;OACX,CAAA;MAEV,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAO,EAAO,GAAG;;OAEnB,WAAU;OACV,OAAO,EAAG,kCAAkC,OAAO;iBAEnD,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;OACb,CAAA;MAEV,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAW,EAAO,GAAG;;OAEvB,WAAU;OACV,OAAO,EAAG,sCAAsC,uBAAuB;iBAEvE,kBAAC,GAAD,EAAY,MAAM,IAAM,CAAA;OACjB,CAAA;MAEV,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAgB,EAAO,GAAG;;OAE5B,WAAU;OACV,OAAO,EAAG,2CAA2C,kBAAkB;iBAEvE,kBAAC,GAAD,EAAe,MAAM,IAAM,CAAA;OACpB,CAAA;MAEX,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAY,EAAO,GAAG;;OAExB,WAAU;OACV,OAAO,EAAG,uCAAuC,YAAY;iBAE7D,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;OACX,CAAA;MACT,kBAAC,GAAD;OACE,QAAO;OACP,UAAU;QACR,IAAI,EAAO;QACX,MAAM,EAAO,eAAe,EAAO;QACnC,QAAQ,EAAO,UAAU;QAC1B;OACD,OAAO,EAAG,mCAAmC,QAAQ;OACrD,CAAA;MACD,KACC,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAU;AAElB,QADA,EAAM,iBAAiB,EACvB,EAAS,EAAO,GAAG;;OAErB,WAAU;OACV,OAAO,EAAG,oCAAoC,SAAS;iBAEvD,kBAAC,GAAD,EAAQ,MAAM,IAAM,CAAA;OACb,CAAA;MAEP;OACF;;GAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAiB,MAAM,EAAO,YAAc,CAAA;KAC5C,kBAAC,GAAD,EAAkB,MAAM,EAAO,aAAe,CAAA;KAC7C,EAAO,cAAc,kBAAC,GAAD,EAAiB,MAAM,EAAO,YAAc,CAAA;KAC9D;;GAGN,kBAAC,OAAD;IAAK,WAAU;IAAO,UAAU,MAAU,EAAM,iBAAiB;cAC/D,kBAAC,GAAD;KACE,YAAY,EAAe;KAC3B,UAAU,EAAO;KACjB,eAAe,EAAO,UAAU;KAChC,mBAAmB,EAAO,cAAc;KACxC,gBAAgB,CAAC,cAAc;KAC/B,CAAA;IACE,CAAA;IAGJ,EAAO,YAAa,EAAO,QAAQ,EAAO,KAAK,SAAS,MACxD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAO,YACN,kBAAC,QAAD;KAAM,WAAU;eACb,EAAO;KACH,CAAA,EAER,EAAO,MAAM,KAAK,MACjB,kBAAC,QAAD;KAEE,WAAU;eAFZ,CAGC,KACG,EACG;OAJA,EAIA,CACP,CACE;;GAIR,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,EAAG,2CAA2C,kBAAkB,EAC/D,OAAO,EAAO,kBAAkB,GACjC,CAAC,CACG;QACP,kBAAC,QAAD;KAAM,WAAU;eAAhB,CACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,IAlMP,MAAuC;AACzD,UAAI,CAAC,EAAS,QAAO,EAAG,mCAAmC,QAAQ;MACnE,IAAM,IAAO,IAAI,KAAK,EAAQ,EAExB,qBADM,IAAI,MAAM,EACH,SAAS,GAAG,EAAK,SAAS,EACvC,IAAU,KAAK,MAAM,IAAS,IAAM;AAC1C,UAAI,IAAU,EAAG,QAAO,EAAG,qCAAqC,WAAW;AAC3E,UAAI,IAAU,GACZ,QAAO,EAAG,wCAAwC,kBAAkB,EAAE,OAAO,GAAS,CAAC;MACzF,IAAM,IAAS,KAAK,MAAM,IAAU,GAAG;AACvC,UAAI,IAAS,GACX,QAAO,EAAG,sCAAsC,kBAAkB,EAAE,OAAO,GAAQ,CAAC;MACtF,IAAM,IAAW,KAAK,MAAM,IAAS,GAAG;AAExC,aADI,IAAW,IAAU,GAAG,EAAS,SAC9B,EAAK,oBAAoB;QAqLd,EAAO,eAAe,CAC7B;OACH;;GACK"}
@@ -89,7 +89,7 @@ function u({ executions: t, onClose: r, actionName: i }) {
89
89
  children: e.output
90
90
  }),
91
91
  e.errorMessage && /* @__PURE__ */ o("pre", {
92
- className: "text-xs font-mono text-status-error-text bg-status-error-bg/10 rounded p-2 max-h-20 overflow-y-auto whitespace-pre-wrap",
92
+ className: "text-xs font-mono text-status-error-text bg-status-error-bg-subtle rounded p-2 max-h-20 overflow-y-auto whitespace-pre-wrap",
93
93
  children: e.errorMessage
94
94
  })
95
95
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"ExecutionHistory.js","names":[],"sources":["../../../src/components/actions/ExecutionHistory.tsx"],"sourcesContent":["import { CheckCircle, XCircle, Clock, Loader } from 'lucide-react';\nimport { motion } from 'framer-motion';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface Execution {\n id: string;\n status: string;\n triggerType?: string | null;\n triggerSource?: string | null;\n command?: string | null;\n script?: string | null;\n output?: string | null;\n exitCode?: number | null;\n webhookStatusCode?: number | null;\n errorMessage?: string | null;\n durationMs?: number | null;\n startedAt?: string | null;\n completedAt?: string | null;\n}\n\ninterface ExecutionHistoryProps {\n executions: Execution[];\n onClose: () => void;\n actionName: string;\n}\n\nconst STATUS_ICON: Record<string, typeof CheckCircle> = {\n SUCCESS: CheckCircle,\n COMPLETED: CheckCircle,\n FAILED: XCircle,\n ERROR: XCircle,\n RUNNING: Loader,\n PENDING: Clock,\n};\n\nconst STATUS_COLOR: Record<string, string> = {\n SUCCESS: 'text-status-success-text',\n COMPLETED: 'text-status-success-text',\n FAILED: 'text-status-error-text',\n ERROR: 'text-status-error-text',\n RUNNING: 'text-status-info-text',\n PENDING: 'text-text-secondary',\n};\n\nexport function ExecutionHistory({ executions, onClose, actionName }: ExecutionHistoryProps) {\n const tr = useTr();\n\n const formatDuration = (ms: number | null | undefined) => {\n if (!ms) return '-';\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n };\n\n const formatTime = (dateStr: string | null | undefined) => {\n if (!dateStr) return '-';\n return new Date(dateStr).toLocaleString();\n };\n\n return (\n <motion.div\n className=\"bg-bg-surface border border-border-default rounded-lg overflow-hidden\"\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={{ opacity: 0, height: 0 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default bg-bg-sunken/50\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr('vibecontrols.actions.executionHistory.recentExecutions', 'Recent Executions')} -{' '}\n {actionName}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-xs text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr('vibecontrols.actions.executionHistory.close', 'Close')}\n </button>\n </div>\n\n {executions.length === 0 ? (\n <div className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n {tr('vibecontrols.actions.executionHistory.noExecutions', 'No executions yet')}\n </div>\n ) : (\n <div className=\"divide-y divide-border-default\">\n {executions.map((exec) => {\n const Icon = STATUS_ICON[exec.status] || Clock;\n const color = STATUS_COLOR[exec.status] || 'text-text-secondary';\n return (\n <div key={exec.id} className=\"px-4 py-3 space-y-1\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Icon\n size={14}\n className={`${color} ${exec.status === 'RUNNING' ? 'animate-spin' : ''}`}\n />\n <span className={`text-sm font-medium capitalize ${color}`}>\n {exec.status.toLowerCase()}\n </span>\n {exec.triggerType && (\n <span className=\"text-xs text-text-placeholder\">\n via {exec.triggerType.toLowerCase()}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-3 text-xs text-text-placeholder\">\n <span>{formatDuration(exec.durationMs)}</span>\n <span>{formatTime(exec.startedAt)}</span>\n </div>\n </div>\n {exec.output && (\n <pre className=\"text-xs font-mono text-text-secondary bg-bg-sunken rounded p-2 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {exec.output}\n </pre>\n )}\n {exec.errorMessage && (\n <pre className=\"text-xs font-mono text-status-error-text bg-status-error-bg/10 rounded p-2 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {exec.errorMessage}\n </pre>\n )}\n </div>\n );\n })}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;AA0BA,IAAM,IAAkD;CACtD,SAAS;CACT,WAAW;CACX,QAAQ;CACR,OAAO;CACP,SAAS;CACT,SAAS;CACV,EAEK,IAAuC;CAC3C,SAAS;CACT,WAAW;CACX,QAAQ;CACR,OAAO;CACP,SAAS;CACT,SAAS;CACV;AAED,SAAgB,EAAiB,EAAE,eAAY,YAAS,iBAAqC;CAC3F,IAAM,IAAK,GAAO,EAEZ,KAAkB,MACjB,IACD,IAAK,MAAa,GAAG,EAAG,MACxB,IAAK,MAAc,IAAI,IAAK,KAAM,QAAQ,EAAE,CAAC,KAC1C,IAAI,IAAK,KAAO,QAAQ,EAAE,CAAC,KAHlB,KAMZ,KAAc,MACb,IACE,IAAI,KAAK,EAAQ,CAAC,gBAAgB,GADpB;AAIvB,QACE,kBAAC,EAAO,KAAR;EACE,WAAU;EACV,SAAS;GAAE,SAAS;GAAG,QAAQ;GAAG;EAClC,SAAS;GAAE,SAAS;GAAG,QAAQ;GAAQ;EACvC,MAAM;GAAE,SAAS;GAAG,QAAQ;GAAG;EAC/B,YAAY,EAAE,UAAU,IAAK;YAL/B,CAOE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACG,EAAG,0DAA0D,oBAAoB;KAAC;KAAG;KACrF;KACE;OACL,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;cAET,EAAG,+CAA+C,QAAQ;IACpD,CAAA,CACL;MAEL,EAAW,WAAW,IACrB,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,sDAAsD,oBAAoB;GAC1E,CAAA,GAEN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAW,KAAK,MAAS;IACxB,IAAM,IAAO,EAAY,EAAK,WAAW,GACnC,IAAQ,EAAa,EAAK,WAAW;AAC3C,WACE,kBAAC,OAAD;KAAmB,WAAU;eAA7B;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,GAAD;UACE,MAAM;UACN,WAAW,GAAG,EAAM,GAAG,EAAK,WAAW,YAAY,iBAAiB;UACpE,CAAA;SACF,kBAAC,QAAD;UAAM,WAAW,kCAAkC;oBAChD,EAAK,OAAO,aAAa;UACrB,CAAA;SACN,EAAK,eACJ,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CAAgD,QACzC,EAAK,YAAY,aAAa,CAC9B;;SAEL;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAe,EAAK,WAAW,EAAQ,CAAA,EAC9C,kBAAC,QAAD,EAAA,UAAO,EAAW,EAAK,UAAU,EAAQ,CAAA,CACrC;UACF;;MACL,EAAK,UACJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAK;OACF,CAAA;MAEP,EAAK,gBACJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAK;OACF,CAAA;MAEJ;OA/BI,EAAK,GA+BT;KAER;GACE,CAAA,CAEG"}
1
+ {"version":3,"file":"ExecutionHistory.js","names":[],"sources":["../../../src/components/actions/ExecutionHistory.tsx"],"sourcesContent":["import { CheckCircle, XCircle, Clock, Loader } from 'lucide-react';\nimport { motion } from 'framer-motion';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface Execution {\n id: string;\n status: string;\n triggerType?: string | null;\n triggerSource?: string | null;\n command?: string | null;\n script?: string | null;\n output?: string | null;\n exitCode?: number | null;\n webhookStatusCode?: number | null;\n errorMessage?: string | null;\n durationMs?: number | null;\n startedAt?: string | null;\n completedAt?: string | null;\n}\n\ninterface ExecutionHistoryProps {\n executions: Execution[];\n onClose: () => void;\n actionName: string;\n}\n\nconst STATUS_ICON: Record<string, typeof CheckCircle> = {\n SUCCESS: CheckCircle,\n COMPLETED: CheckCircle,\n FAILED: XCircle,\n ERROR: XCircle,\n RUNNING: Loader,\n PENDING: Clock,\n};\n\nconst STATUS_COLOR: Record<string, string> = {\n SUCCESS: 'text-status-success-text',\n COMPLETED: 'text-status-success-text',\n FAILED: 'text-status-error-text',\n ERROR: 'text-status-error-text',\n RUNNING: 'text-status-info-text',\n PENDING: 'text-text-secondary',\n};\n\nexport function ExecutionHistory({ executions, onClose, actionName }: ExecutionHistoryProps) {\n const tr = useTr();\n\n const formatDuration = (ms: number | null | undefined) => {\n if (!ms) return '-';\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n return `${(ms / 60000).toFixed(1)}m`;\n };\n\n const formatTime = (dateStr: string | null | undefined) => {\n if (!dateStr) return '-';\n return new Date(dateStr).toLocaleString();\n };\n\n return (\n <motion.div\n className=\"bg-bg-surface border border-border-default rounded-lg overflow-hidden\"\n initial={{ opacity: 0, height: 0 }}\n animate={{ opacity: 1, height: 'auto' }}\n exit={{ opacity: 0, height: 0 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default bg-bg-sunken/50\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr('vibecontrols.actions.executionHistory.recentExecutions', 'Recent Executions')} -{' '}\n {actionName}\n </h3>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-xs text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr('vibecontrols.actions.executionHistory.close', 'Close')}\n </button>\n </div>\n\n {executions.length === 0 ? (\n <div className=\"px-4 py-6 text-center text-sm text-text-secondary\">\n {tr('vibecontrols.actions.executionHistory.noExecutions', 'No executions yet')}\n </div>\n ) : (\n <div className=\"divide-y divide-border-default\">\n {executions.map((exec) => {\n const Icon = STATUS_ICON[exec.status] || Clock;\n const color = STATUS_COLOR[exec.status] || 'text-text-secondary';\n return (\n <div key={exec.id} className=\"px-4 py-3 space-y-1\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Icon\n size={14}\n className={`${color} ${exec.status === 'RUNNING' ? 'animate-spin' : ''}`}\n />\n <span className={`text-sm font-medium capitalize ${color}`}>\n {exec.status.toLowerCase()}\n </span>\n {exec.triggerType && (\n <span className=\"text-xs text-text-placeholder\">\n via {exec.triggerType.toLowerCase()}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-3 text-xs text-text-placeholder\">\n <span>{formatDuration(exec.durationMs)}</span>\n <span>{formatTime(exec.startedAt)}</span>\n </div>\n </div>\n {exec.output && (\n <pre className=\"text-xs font-mono text-text-secondary bg-bg-sunken rounded p-2 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {exec.output}\n </pre>\n )}\n {exec.errorMessage && (\n <pre className=\"text-xs font-mono text-status-error-text bg-status-error-bg-subtle rounded p-2 max-h-20 overflow-y-auto whitespace-pre-wrap\">\n {exec.errorMessage}\n </pre>\n )}\n </div>\n );\n })}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;AA0BA,IAAM,IAAkD;CACtD,SAAS;CACT,WAAW;CACX,QAAQ;CACR,OAAO;CACP,SAAS;CACT,SAAS;CACV,EAEK,IAAuC;CAC3C,SAAS;CACT,WAAW;CACX,QAAQ;CACR,OAAO;CACP,SAAS;CACT,SAAS;CACV;AAED,SAAgB,EAAiB,EAAE,eAAY,YAAS,iBAAqC;CAC3F,IAAM,IAAK,GAAO,EAEZ,KAAkB,MACjB,IACD,IAAK,MAAa,GAAG,EAAG,MACxB,IAAK,MAAc,IAAI,IAAK,KAAM,QAAQ,EAAE,CAAC,KAC1C,IAAI,IAAK,KAAO,QAAQ,EAAE,CAAC,KAHlB,KAMZ,KAAc,MACb,IACE,IAAI,KAAK,EAAQ,CAAC,gBAAgB,GADpB;AAIvB,QACE,kBAAC,EAAO,KAAR;EACE,WAAU;EACV,SAAS;GAAE,SAAS;GAAG,QAAQ;GAAG;EAClC,SAAS;GAAE,SAAS;GAAG,QAAQ;GAAQ;EACvC,MAAM;GAAE,SAAS;GAAG,QAAQ;GAAG;EAC/B,YAAY,EAAE,UAAU,IAAK;YAL/B,CAOE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cAAd;KACG,EAAG,0DAA0D,oBAAoB;KAAC;KAAG;KACrF;KACE;OACL,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;cAET,EAAG,+CAA+C,QAAQ;IACpD,CAAA,CACL;MAEL,EAAW,WAAW,IACrB,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,sDAAsD,oBAAoB;GAC1E,CAAA,GAEN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAW,KAAK,MAAS;IACxB,IAAM,IAAO,EAAY,EAAK,WAAW,GACnC,IAAQ,EAAa,EAAK,WAAW;AAC3C,WACE,kBAAC,OAAD;KAAmB,WAAU;eAA7B;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,GAAD;UACE,MAAM;UACN,WAAW,GAAG,EAAM,GAAG,EAAK,WAAW,YAAY,iBAAiB;UACpE,CAAA;SACF,kBAAC,QAAD;UAAM,WAAW,kCAAkC;oBAChD,EAAK,OAAO,aAAa;UACrB,CAAA;SACN,EAAK,eACJ,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CAAgD,QACzC,EAAK,YAAY,aAAa,CAC9B;;SAEL;WACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAe,EAAK,WAAW,EAAQ,CAAA,EAC9C,kBAAC,QAAD,EAAA,UAAO,EAAW,EAAK,UAAU,EAAQ,CAAA,CACrC;UACF;;MACL,EAAK,UACJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAK;OACF,CAAA;MAEP,EAAK,gBACJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAK;OACF,CAAA;MAEJ;OA/BI,EAAK,GA+BT;KAER;GACE,CAAA,CAEG"}
@@ -147,7 +147,7 @@ function O({ agent: f }) {
147
147
  return /* @__PURE__ */ E("button", {
148
148
  type: "button",
149
149
  onClick: () => k(e.key),
150
- className: `flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded transition-colors whitespace-nowrap ${g && p === e.key ? "bg-action-primary-bg/10 text-action-primary-text" : "text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated"}`,
150
+ className: `flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded transition-colors whitespace-nowrap ${g && p === e.key ? "bg-[var(--color-accent-soft)] text-action-primary-bg" : "text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated"}`,
151
151
  children: [/* @__PURE__ */ T(t, { className: "size-3.5" }), /* @__PURE__ */ T("span", { children: e.label })]
152
152
  }, e.key);
153
153
  })
@@ -1 +1 @@
1
- {"version":3,"file":"AgentManagerAdminBar.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerAdminBar.tsx"],"sourcesContent":["/**\n * Admin bar for the Agent Manager.\n *\n * Horizontal tab strip rendered at the bottom of the layout. Each tab\n * opens an overlay panel with the corresponding AI management component\n * (Templates, Contexts, Prompts, Tasks, Stats, Playground).\n */\n\nimport { useState } from 'react';\nimport {\n X,\n FileText,\n BookOpen,\n MessageSquare,\n ListChecks,\n BarChart3,\n Play,\n Settings,\n ExternalLink,\n} from 'lucide-react';\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport type { AdminTab } from '@/types/agentManager';\nimport { AITemplatesTab } from '@/components/ai/AITemplatesTab';\nimport { AIContextsTab } from '@/components/ai/AIContextsTab';\nimport { AIPromptsTab } from '@/components/ai/AIPromptsTab';\nimport { AITasksTab } from '@/components/ai/AITasksTab';\nimport { AIStatsTab } from '@/components/ai/AIStatsTab';\nimport { AIPlaygroundTab } from '@/components/ai/AIPlaygroundTab';\nimport { BridleConfigPanel } from './BridleConfigPanel';\nimport { AIProviderCredentialsCard } from '@/components/ai/AIProviderCredentialsCard';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type { AgentRef } from '@/services/aiApi';\n\ninterface AgentManagerAdminBarProps {\n agent: AgentRef;\n}\n\nconst ADMIN_TABS: Array<{ key: AdminTab; label: string; icon: typeof FileText }> = [\n { key: 'templates', label: 'Templates', icon: FileText },\n { key: 'contexts', label: 'Contexts', icon: BookOpen },\n { key: 'prompts', label: 'Prompts', icon: MessageSquare },\n { key: 'tasks', label: 'Tasks', icon: ListChecks },\n { key: 'stats', label: 'Stats', icon: BarChart3 },\n { key: 'playground', label: 'Playground', icon: Play },\n // Split: AI provider API keys (Anthropic, OpenAI, Gemini, …) live here;\n // Bridle owns the harness-config files (~/.claude/, ~/.config/opencode/).\n { key: 'aiKeys', label: 'AI Keys', icon: Settings },\n { key: 'bridle', label: 'Bridle', icon: Settings },\n];\n\nexport function AgentManagerAdminBar({ agent }: AgentManagerAdminBarProps) {\n const adminTab = useAgentManagerStore((s) => s.adminTab);\n const setAdminTab = useAgentManagerStore((s) => s.setAdminTab);\n const [overlayOpen, setOverlayOpen] = useState(false);\n const shouldReduceMotion = useReducedMotion();\n const handleNavigate = useVibeNavigate();\n const tr = useTr();\n\n function handleTabClick(tab: AdminTab) {\n if (overlayOpen && adminTab === tab) {\n setOverlayOpen(false);\n } else {\n setAdminTab(tab);\n setOverlayOpen(true);\n }\n }\n\n function renderTabContent() {\n switch (adminTab) {\n case 'templates':\n return <AITemplatesTab agentId={agent.id} />;\n case 'contexts':\n return <AIContextsTab agent={agent} />;\n case 'prompts':\n return <AIPromptsTab agent={agent} />;\n case 'tasks':\n return <AITasksTab />;\n case 'stats':\n return <AIStatsTab agent={agent} />;\n case 'playground':\n return <AIPlaygroundTab agent={agent} />;\n // 'aiKeys' is the SDK-credentials surface: every AI provider plugin\n // that reads from the agent's config bag (POST /api/config) gets a\n // row here. Distinct from Bridle below, which writes harness config\n // files on disk under ~/.claude/, ~/.config/opencode/, etc.\n case 'aiKeys':\n case 'config': // back-compat alias for old saved adminTab='config'\n return <AIProviderCredentialsCard agent={agent} />;\n case 'bridle':\n return <BridleConfigPanel agent={agent} />;\n default:\n return null;\n }\n }\n\n return (\n <>\n {/* Admin overlay */}\n <AnimatePresence>\n {overlayOpen && (\n <motion.div\n className=\"fixed inset-0 z-40 flex items-center justify-center\"\n initial={shouldReduceMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n {/* Backdrop */}\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => setOverlayOpen(false))();\n }\n }}\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={() => setOverlayOpen(false)}\n />\n\n {/* Content card */}\n <motion.div\n className=\"relative w-full max-w-4xl max-h-[80vh] mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl overflow-hidden flex flex-col\"\n initial={shouldReduceMotion ? undefined : { opacity: 0, scale: 0.96, y: 16 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.96, y: 16 }}\n transition={{ duration: 0.2, ease: [0.2, 0, 0, 1] }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default\">\n <h2 className=\"text-sm font-semibold text-text-primary capitalize\">{adminTab}</h2>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleNavigate('/ai-tools/' + adminTab)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-tertiary hover:text-text-secondary\"\n title={tr('vibecontrols.agentManager.adminBar.openFullPage', 'Open full page')}\n >\n <ExternalLink className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setOverlayOpen(false)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-tertiary hover:text-text-secondary\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n </div>\n\n {/* Tab content */}\n <div className=\"flex-1 overflow-y-auto p-4\">{renderTabContent()}</div>\n </motion.div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Bottom bar */}\n <div className=\"flex items-center gap-0.5 px-2 py-1 border-t border-border-default bg-bg-surface overflow-x-auto\">\n {ADMIN_TABS.map((tab) => {\n const Icon = tab.icon;\n const isActive = overlayOpen && adminTab === tab.key;\n return (\n <button\n key={tab.key}\n type=\"button\"\n onClick={() => handleTabClick(tab.key)}\n className={`flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded transition-colors whitespace-nowrap ${\n isActive\n ? 'bg-action-primary-bg/10 text-action-primary-text'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n >\n <Icon className=\"size-3.5\" />\n <span>{tab.label}</span>\n </button>\n );\n })}\n </div>\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentManagerAdminBar.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerAdminBar.tsx"],"sourcesContent":["/**\n * Admin bar for the Agent Manager.\n *\n * Horizontal tab strip rendered at the bottom of the layout. Each tab\n * opens an overlay panel with the corresponding AI management component\n * (Templates, Contexts, Prompts, Tasks, Stats, Playground).\n */\n\nimport { useState } from 'react';\nimport {\n X,\n FileText,\n BookOpen,\n MessageSquare,\n ListChecks,\n BarChart3,\n Play,\n Settings,\n ExternalLink,\n} from 'lucide-react';\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport type { AdminTab } from '@/types/agentManager';\nimport { AITemplatesTab } from '@/components/ai/AITemplatesTab';\nimport { AIContextsTab } from '@/components/ai/AIContextsTab';\nimport { AIPromptsTab } from '@/components/ai/AIPromptsTab';\nimport { AITasksTab } from '@/components/ai/AITasksTab';\nimport { AIStatsTab } from '@/components/ai/AIStatsTab';\nimport { AIPlaygroundTab } from '@/components/ai/AIPlaygroundTab';\nimport { BridleConfigPanel } from './BridleConfigPanel';\nimport { AIProviderCredentialsCard } from '@/components/ai/AIProviderCredentialsCard';\nimport { useTr } from '../../shared/hooks/useTr';\nimport type { AgentRef } from '@/services/aiApi';\n\ninterface AgentManagerAdminBarProps {\n agent: AgentRef;\n}\n\nconst ADMIN_TABS: Array<{ key: AdminTab; label: string; icon: typeof FileText }> = [\n { key: 'templates', label: 'Templates', icon: FileText },\n { key: 'contexts', label: 'Contexts', icon: BookOpen },\n { key: 'prompts', label: 'Prompts', icon: MessageSquare },\n { key: 'tasks', label: 'Tasks', icon: ListChecks },\n { key: 'stats', label: 'Stats', icon: BarChart3 },\n { key: 'playground', label: 'Playground', icon: Play },\n // Split: AI provider API keys (Anthropic, OpenAI, Gemini, …) live here;\n // Bridle owns the harness-config files (~/.claude/, ~/.config/opencode/).\n { key: 'aiKeys', label: 'AI Keys', icon: Settings },\n { key: 'bridle', label: 'Bridle', icon: Settings },\n];\n\nexport function AgentManagerAdminBar({ agent }: AgentManagerAdminBarProps) {\n const adminTab = useAgentManagerStore((s) => s.adminTab);\n const setAdminTab = useAgentManagerStore((s) => s.setAdminTab);\n const [overlayOpen, setOverlayOpen] = useState(false);\n const shouldReduceMotion = useReducedMotion();\n const handleNavigate = useVibeNavigate();\n const tr = useTr();\n\n function handleTabClick(tab: AdminTab) {\n if (overlayOpen && adminTab === tab) {\n setOverlayOpen(false);\n } else {\n setAdminTab(tab);\n setOverlayOpen(true);\n }\n }\n\n function renderTabContent() {\n switch (adminTab) {\n case 'templates':\n return <AITemplatesTab agentId={agent.id} />;\n case 'contexts':\n return <AIContextsTab agent={agent} />;\n case 'prompts':\n return <AIPromptsTab agent={agent} />;\n case 'tasks':\n return <AITasksTab />;\n case 'stats':\n return <AIStatsTab agent={agent} />;\n case 'playground':\n return <AIPlaygroundTab agent={agent} />;\n // 'aiKeys' is the SDK-credentials surface: every AI provider plugin\n // that reads from the agent's config bag (POST /api/config) gets a\n // row here. Distinct from Bridle below, which writes harness config\n // files on disk under ~/.claude/, ~/.config/opencode/, etc.\n case 'aiKeys':\n case 'config': // back-compat alias for old saved adminTab='config'\n return <AIProviderCredentialsCard agent={agent} />;\n case 'bridle':\n return <BridleConfigPanel agent={agent} />;\n default:\n return null;\n }\n }\n\n return (\n <>\n {/* Admin overlay */}\n <AnimatePresence>\n {overlayOpen && (\n <motion.div\n className=\"fixed inset-0 z-40 flex items-center justify-center\"\n initial={shouldReduceMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: 0.2 }}\n >\n {/* Backdrop */}\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => setOverlayOpen(false))();\n }\n }}\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={() => setOverlayOpen(false)}\n />\n\n {/* Content card */}\n <motion.div\n className=\"relative w-full max-w-4xl max-h-[80vh] mx-4 rounded-lg border border-border-default bg-bg-surface shadow-xl overflow-hidden flex flex-col\"\n initial={shouldReduceMotion ? undefined : { opacity: 0, scale: 0.96, y: 16 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.96, y: 16 }}\n transition={{ duration: 0.2, ease: [0.2, 0, 0, 1] }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default\">\n <h2 className=\"text-sm font-semibold text-text-primary capitalize\">{adminTab}</h2>\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleNavigate('/ai-tools/' + adminTab)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-tertiary hover:text-text-secondary\"\n title={tr('vibecontrols.agentManager.adminBar.openFullPage', 'Open full page')}\n >\n <ExternalLink className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setOverlayOpen(false)}\n className=\"p-1 rounded hover:bg-bg-elevated transition-colors text-text-tertiary hover:text-text-secondary\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n </div>\n\n {/* Tab content */}\n <div className=\"flex-1 overflow-y-auto p-4\">{renderTabContent()}</div>\n </motion.div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Bottom bar */}\n <div className=\"flex items-center gap-0.5 px-2 py-1 border-t border-border-default bg-bg-surface overflow-x-auto\">\n {ADMIN_TABS.map((tab) => {\n const Icon = tab.icon;\n const isActive = overlayOpen && adminTab === tab.key;\n return (\n <button\n key={tab.key}\n type=\"button\"\n onClick={() => handleTabClick(tab.key)}\n className={`flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded transition-colors whitespace-nowrap ${\n isActive\n ? 'bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n >\n <Icon className=\"size-3.5\" />\n <span>{tab.label}</span>\n </button>\n );\n })}\n </div>\n </>\n );\n}\n"],"mappings":"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"}
@@ -102,7 +102,7 @@ var C = ({ sessionId: d, agentId: C }) => {
102
102
  children: [/* @__PURE__ */ x("button", {
103
103
  type: "button",
104
104
  onClick: re,
105
- className: `p-1 rounded transition-colors shrink-0 ${D ? "bg-action-primary-bg/10 text-action-primary-text" : "text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated"}`,
105
+ className: `p-1 rounded transition-colors shrink-0 ${D ? "bg-[var(--color-accent-soft)] text-action-primary-bg" : "text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated"}`,
106
106
  title: B("vibecontrols.agentManager.chatPane.searchInSession", "Search in session (Ctrl+F)"),
107
107
  "aria-label": B("vibecontrols.agentManager.chatPane.searchInSession", "Search in session"),
108
108
  children: /* @__PURE__ */ x(ee, { className: "size-3.5" })
@@ -135,7 +135,7 @@ var C = ({ sessionId: d, agentId: C }) => {
135
135
  /* @__PURE__ */ S("button", {
136
136
  type: "button",
137
137
  onClick: () => M(!0),
138
- className: "shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-elevated px-2 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken hover:border-action-primary-bg/40",
138
+ className: "shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-elevated px-2 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken hover:border-[var(--color-accent-soft)]",
139
139
  title: B("vibecontrols.agentManager.chatPane.manageProvidersTooltip", "Install or remove AI providers (Claude, Codex, Gemini, OpenCode)"),
140
140
  "aria-label": B("vibecontrols.agentManager.chatPane.manageProviders", "Manage AI providers"),
141
141
  "data-testid": "agent-manager-manage-providers",
@@ -1 +1 @@
1
- {"version":3,"file":"AgentManagerChatPane.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerChatPane.tsx"],"sourcesContent":["/**\n * Main chat interface for a single Agent Manager session.\n *\n * Renders message list + input area, manages the send/receive flow,\n * fetches existing conversation logs on mount, and provides\n * auto-scroll, cancel, and in-session search support.\n */\n\nimport { useEffect, useRef, useState, useCallback, useMemo, type FC } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Bookmark, PackagePlus, Search, X } from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useAgentManagerStreaming } from '@/hooks/useAgentManagerStreaming';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchSessionLogs } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { useToggleAgentBookmark } from '@/hooks/useToggleAgentBookmark';\nimport { AgentManagerMessageList } from './AgentManagerMessageList';\nimport { AgentManagerInputArea } from './AgentManagerInputArea';\nimport { AgentManagerBookmarksDrawer } from './AgentManagerBookmarksDrawer';\nimport { PluginInstallModal } from './PluginInstallModal';\nimport { AIProviderCredentialsCard } from '@/components/ai/AIProviderCredentialsCard';\nimport type { AgentManagerMessage } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerChatPaneProps {\n sessionId: string;\n agentId: string;\n}\n\nexport const AgentManagerChatPane: FC<AgentManagerChatPaneProps> = ({ sessionId, agentId }) => {\n const [loadingLogs, setLoadingLogs] = useState(false);\n const [searchOpen, setSearchOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n // Provider-install modal triggered from the header. Lets users add a\n // claude/codex/gemini/opencode plugin without leaving the conversation.\n const [installModalOpen, setInstallModalOpen] = useState(false);\n const [bookmarksDrawerOpen, setBookmarksDrawerOpen] = useState(false);\n const [flashMessageId, setFlashMessageId] = useState<string | null>(null);\n const [searchParams, setSearchParams] = useSearchParams();\n const pendingScrollMessageId = searchParams.get('messageId');\n const consumedScrollTargetRef = useRef<string | null>(null);\n const tr = useTr();\n\n const { agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n\n const messages = useMemo(() => sessionState?.messages ?? [], [sessionState?.messages]);\n\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { sendMessage, cancelStream, isStreaming } = useAgentManagerStreaming({\n agent: agentRef,\n sessionId,\n });\n\n const { bookmarkedIds, toggle: toggleBookmark } = useToggleAgentBookmark(sessionId);\n\n const jumpToMessage = useCallback((messageId: string) => {\n const el = document.querySelector(`[data-message-id=\"${messageId}\"]`);\n if (!el) return;\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n setFlashMessageId(messageId);\n window.setTimeout(() => {\n setFlashMessageId((current) => (current === messageId ? null : current));\n }, 1500);\n }, []);\n\n const handleToggleBookmark = useCallback(\n (messageId: string) => {\n void toggleBookmark({ agentId, sessionId, messageId });\n },\n [toggleBookmark, agentId, sessionId]\n );\n\n const toggleSearch = useCallback(() => {\n setSearchOpen((prev) => {\n if (prev) setSearchQuery('');\n return !prev;\n });\n }, []);\n\n // Fetch existing conversation logs on mount\n useEffect(() => {\n let cancelled = false;\n\n const loadExistingLogs = async () => {\n // Only load if session has no messages yet\n if (messages.length > 0) return;\n\n setLoadingLogs(true);\n try {\n const logs = await fetchSessionLogs(agentRef, sessionId, {\n types: ['input', 'output'],\n });\n\n if (cancelled || logs.length === 0) return;\n\n const seenLogKeys = new Set<string>();\n\n // Convert session logs to AgentManagerMessage format. The core AI\n // route owns logging, but older provider builds also wrote the same\n // input/output records; collapse same-second duplicates on restore.\n for (const log of logs) {\n const content = log.message || log.content || '';\n const timestamp = log.timestamp || log.createdAt;\n const timestampSecond = timestamp ? Math.floor(new Date(timestamp).getTime() / 1000) : 0;\n const logKey = [log.type, content, log.model ?? '', timestampSecond].join('\\u0000');\n if (seenLogKeys.has(logKey)) continue;\n seenLogKeys.add(logKey);\n\n const msg: AgentManagerMessage = {\n id: log.id,\n role: log.type === 'input' ? 'user' : 'assistant',\n content,\n timestamp,\n tokens: log.tokenCount ? { input: 0, output: log.tokenCount } : undefined,\n model: log.model,\n };\n addMessage(sessionId, msg);\n }\n } catch {\n // Silent fail -- session may not have logs yet\n } finally {\n if (!cancelled) setLoadingLogs(false);\n }\n };\n\n void loadExistingLogs();\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only run on mount\n }, [agentId, sessionId]);\n\n // Auto-scroll to a message linked via ?messageId=... (from drawer / cross-session page).\n // Waits for logs to finish loading and the target to be in the DOM before scrolling.\n useEffect(() => {\n if (!pendingScrollMessageId || loadingLogs) return;\n if (consumedScrollTargetRef.current === pendingScrollMessageId) return;\n\n const exists = messages.some((m) => m.id === pendingScrollMessageId);\n if (!exists) return;\n\n consumedScrollTargetRef.current = pendingScrollMessageId;\n jumpToMessage(pendingScrollMessageId);\n\n // Strip the query param so a manual refresh doesn't re-trigger the flash.\n const next = new URLSearchParams(searchParams);\n next.delete('messageId');\n setSearchParams(next, { replace: true });\n }, [pendingScrollMessageId, loadingLogs, messages, jumpToMessage, searchParams, setSearchParams]);\n\n return (\n <div className=\"flex flex-col h-full min-h-0\" data-testid=\"agent-manager-chat-pane\">\n {/* In-session search bar.\n Layout: [search controls (flex-1)] ... [Manage AI providers].\n The search input expands inside the LEFT cluster only, so the\n Manage button stays anchored on the right and never shifts. */}\n <div className=\"flex items-center gap-1 px-3 py-1 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <div className=\"flex items-center gap-1.5 min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={toggleSearch}\n className={`p-1 rounded transition-colors shrink-0 ${\n searchOpen\n ? 'bg-action-primary-bg/10 text-action-primary-text'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n title={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session (Ctrl+F)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session'\n )}\n >\n <Search className=\"size-3.5\" />\n </button>\n {searchOpen && (\n <div className=\"flex items-center gap-1.5 flex-1 min-w-0\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.chatPane.searchPlaceholder',\n 'Search in conversation...'\n )}\n className=\"flex-1 min-w-0 bg-transparent text-xs text-text-primary placeholder:text-text-tertiary focus:outline-none\"\n />\n {searchQuery && (\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n className=\"p-0.5 rounded hover:bg-bg-elevated transition-colors\"\n >\n <X className=\"size-3 text-text-tertiary\" />\n </button>\n )}\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => setBookmarksDrawerOpen(true)}\n className=\"shrink-0 p-1 rounded transition-colors text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.bookmarksTooltip',\n 'View bookmarked messages'\n )}\n aria-label={tr('vibecontrols.agentManager.chatPane.bookmarksLabel', 'Bookmarks')}\n data-testid=\"agent-manager-bookmarks-trigger\"\n >\n <Bookmark className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setInstallModalOpen(true)}\n className=\"shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-elevated px-2 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken hover:border-action-primary-bg/40\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.manageProvidersTooltip',\n 'Install or remove AI providers (Claude, Codex, Gemini, OpenCode)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.manageProviders',\n 'Manage AI providers'\n )}\n data-testid=\"agent-manager-manage-providers\"\n >\n <PackagePlus className=\"size-3.5\" />\n <span className=\"hidden sm:inline\">\n {tr('vibecontrols.agentManager.chatPane.manageProviders', 'Manage AI providers')}\n </span>\n </button>\n </div>\n\n {/* Message list */}\n {loadingLogs ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.agentManager.chatPane.loadingConversation',\n 'Loading conversation...'\n )}\n </p>\n </div>\n ) : (\n <AgentManagerMessageList\n messages={messages}\n isStreaming={isStreaming}\n onCancelStream={cancelStream}\n searchQuery={searchQuery}\n bookmarkedIds={bookmarkedIds}\n onToggleBookmark={handleToggleBookmark}\n flashMessageId={flashMessageId}\n />\n )}\n\n {/* Rich input area with controls */}\n <AgentManagerInputArea\n agentId={agentId}\n sessionId={sessionId}\n onSend={(text) => void sendMessage(text)}\n onCancel={cancelStream}\n agentTunnelUrl={activeAgent?.tunnelUrl ?? undefined}\n />\n\n {/* Per-session bookmarks drawer */}\n <AgentManagerBookmarksDrawer\n open={bookmarksDrawerOpen}\n onClose={() => setBookmarksDrawerOpen(false)}\n sessionId={sessionId}\n messages={messages}\n onJump={jumpToMessage}\n />\n\n {/* Header-triggered provider install/remove. Sits below the chat\n tree so it can render full-screen without disturbing layout. */}\n <PluginInstallModal\n open={installModalOpen}\n agentId={agentId}\n onClose={() => setInstallModalOpen(false)}\n />\n\n {/* SDK auth prompt: opens when the streaming hook detects a missing\n ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, so the user can save the\n credential inline instead of being told to go look elsewhere.\n The session's currently-selected SDK is forwarded so the picker\n can preselect the right provider. */}\n <SdkAuthPromptModal\n agentId={agentId}\n agentRef={agentRef}\n initialProviderId={sessionState?.sdk ?? undefined}\n />\n </div>\n );\n};\n\ninterface SdkAuthPromptModalProps {\n agentId: string;\n agentRef: { id: string; profile: string };\n initialProviderId?: string;\n}\n\nconst SdkAuthPromptModal: FC<SdkAuthPromptModalProps> = ({\n agentId,\n agentRef,\n initialProviderId,\n}) => {\n const sdkAuthPrompt = useAgentManagerStore((s) => s.sdkAuthPrompt);\n const setSdkAuthPrompt = useAgentManagerStore((s) => s.setSdkAuthPrompt);\n // Track whether the inner card has at least one primary credential\n // saved on the agent. The Continue button is gated on this so the user\n // can't dismiss the modal without actually persisting a key — but the\n // moment they save *any* of the either-or options it lights up.\n const [authSatisfied, setAuthSatisfied] = useState(false);\n const tr = useTr();\n\n // Reset the satisfied flag whenever the modal re-opens for a fresh\n // prompt (different agent / different session). Without this, dismissing\n // and re-opening would leave the flag stuck at its previous value.\n useEffect(() => {\n if (sdkAuthPrompt && sdkAuthPrompt.agentId === agentId) {\n setAuthSatisfied(false);\n }\n }, [sdkAuthPrompt, agentId]);\n\n if (!sdkAuthPrompt || sdkAuthPrompt.agentId !== agentId) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={() => setSdkAuthPrompt(null)}\n aria-hidden\n />\n {/* Constrain height to the viewport and let the inner body scroll so the\n modal never escapes the screen no matter how many providers/fields\n render inside AIProviderCredentialsCard. The header + footer stay\n sticky so the close + Continue buttons are always reachable. */}\n <div className=\"relative w-full max-w-xl max-h-[85vh] flex flex-col rounded-lg border border-border-default bg-bg-surface shadow-xl overflow-hidden\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <h3 className=\"text-base font-semibold text-text-primary truncate pr-2\">\n {tr('vibecontrols.ai.sdkAuth.title', 'Configure AI provider credentials')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label={tr('vibecontrols.common.close', 'Close')}\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto px-4 py-3 space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.ai.sdkAuth.body',\n \"The agent doesn't have a credential configured for this provider. Save any one of the listed keys (you don't need all of them) and click Continue to retry.\"\n )}\n </p>\n <AIProviderCredentialsCard\n agent={agentRef}\n initialProviderId={initialProviderId}\n onProviderAuthSatisfiedChange={setAuthSatisfied}\n />\n </div>\n <div className=\"flex items-center justify-end gap-2 px-4 py-3 border-t border-border-default bg-bg-surface flex-shrink-0\">\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"px-3 py-1.5 rounded-md text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n {tr('vibecontrols.common.close', 'Close')}\n </button>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n disabled={!authSatisfied}\n title={\n authSatisfied\n ? undefined\n : tr(\n 'vibecontrols.ai.sdkAuth.saveOneFirst',\n 'Save at least one of the listed credentials to continue'\n )\n }\n className=\"px-3 py-1.5 rounded-md text-sm font-medium bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.ai.sdkAuth.continue', 'Continue')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentManagerChatPane.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerChatPane.tsx"],"sourcesContent":["/**\n * Main chat interface for a single Agent Manager session.\n *\n * Renders message list + input area, manages the send/receive flow,\n * fetches existing conversation logs on mount, and provides\n * auto-scroll, cancel, and in-session search support.\n */\n\nimport { useEffect, useRef, useState, useCallback, useMemo, type FC } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Bookmark, PackagePlus, Search, X } from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useAgentManagerStreaming } from '@/hooks/useAgentManagerStreaming';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchSessionLogs } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { useToggleAgentBookmark } from '@/hooks/useToggleAgentBookmark';\nimport { AgentManagerMessageList } from './AgentManagerMessageList';\nimport { AgentManagerInputArea } from './AgentManagerInputArea';\nimport { AgentManagerBookmarksDrawer } from './AgentManagerBookmarksDrawer';\nimport { PluginInstallModal } from './PluginInstallModal';\nimport { AIProviderCredentialsCard } from '@/components/ai/AIProviderCredentialsCard';\nimport type { AgentManagerMessage } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AgentManagerChatPaneProps {\n sessionId: string;\n agentId: string;\n}\n\nexport const AgentManagerChatPane: FC<AgentManagerChatPaneProps> = ({ sessionId, agentId }) => {\n const [loadingLogs, setLoadingLogs] = useState(false);\n const [searchOpen, setSearchOpen] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n // Provider-install modal triggered from the header. Lets users add a\n // claude/codex/gemini/opencode plugin without leaving the conversation.\n const [installModalOpen, setInstallModalOpen] = useState(false);\n const [bookmarksDrawerOpen, setBookmarksDrawerOpen] = useState(false);\n const [flashMessageId, setFlashMessageId] = useState<string | null>(null);\n const [searchParams, setSearchParams] = useSearchParams();\n const pendingScrollMessageId = searchParams.get('messageId');\n const consumedScrollTargetRef = useRef<string | null>(null);\n const tr = useTr();\n\n const { agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n\n const messages = useMemo(() => sessionState?.messages ?? [], [sessionState?.messages]);\n\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { sendMessage, cancelStream, isStreaming } = useAgentManagerStreaming({\n agent: agentRef,\n sessionId,\n });\n\n const { bookmarkedIds, toggle: toggleBookmark } = useToggleAgentBookmark(sessionId);\n\n const jumpToMessage = useCallback((messageId: string) => {\n const el = document.querySelector(`[data-message-id=\"${messageId}\"]`);\n if (!el) return;\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n setFlashMessageId(messageId);\n window.setTimeout(() => {\n setFlashMessageId((current) => (current === messageId ? null : current));\n }, 1500);\n }, []);\n\n const handleToggleBookmark = useCallback(\n (messageId: string) => {\n void toggleBookmark({ agentId, sessionId, messageId });\n },\n [toggleBookmark, agentId, sessionId]\n );\n\n const toggleSearch = useCallback(() => {\n setSearchOpen((prev) => {\n if (prev) setSearchQuery('');\n return !prev;\n });\n }, []);\n\n // Fetch existing conversation logs on mount\n useEffect(() => {\n let cancelled = false;\n\n const loadExistingLogs = async () => {\n // Only load if session has no messages yet\n if (messages.length > 0) return;\n\n setLoadingLogs(true);\n try {\n const logs = await fetchSessionLogs(agentRef, sessionId, {\n types: ['input', 'output'],\n });\n\n if (cancelled || logs.length === 0) return;\n\n const seenLogKeys = new Set<string>();\n\n // Convert session logs to AgentManagerMessage format. The core AI\n // route owns logging, but older provider builds also wrote the same\n // input/output records; collapse same-second duplicates on restore.\n for (const log of logs) {\n const content = log.message || log.content || '';\n const timestamp = log.timestamp || log.createdAt;\n const timestampSecond = timestamp ? Math.floor(new Date(timestamp).getTime() / 1000) : 0;\n const logKey = [log.type, content, log.model ?? '', timestampSecond].join('\\u0000');\n if (seenLogKeys.has(logKey)) continue;\n seenLogKeys.add(logKey);\n\n const msg: AgentManagerMessage = {\n id: log.id,\n role: log.type === 'input' ? 'user' : 'assistant',\n content,\n timestamp,\n tokens: log.tokenCount ? { input: 0, output: log.tokenCount } : undefined,\n model: log.model,\n };\n addMessage(sessionId, msg);\n }\n } catch {\n // Silent fail -- session may not have logs yet\n } finally {\n if (!cancelled) setLoadingLogs(false);\n }\n };\n\n void loadExistingLogs();\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- only run on mount\n }, [agentId, sessionId]);\n\n // Auto-scroll to a message linked via ?messageId=... (from drawer / cross-session page).\n // Waits for logs to finish loading and the target to be in the DOM before scrolling.\n useEffect(() => {\n if (!pendingScrollMessageId || loadingLogs) return;\n if (consumedScrollTargetRef.current === pendingScrollMessageId) return;\n\n const exists = messages.some((m) => m.id === pendingScrollMessageId);\n if (!exists) return;\n\n consumedScrollTargetRef.current = pendingScrollMessageId;\n jumpToMessage(pendingScrollMessageId);\n\n // Strip the query param so a manual refresh doesn't re-trigger the flash.\n const next = new URLSearchParams(searchParams);\n next.delete('messageId');\n setSearchParams(next, { replace: true });\n }, [pendingScrollMessageId, loadingLogs, messages, jumpToMessage, searchParams, setSearchParams]);\n\n return (\n <div className=\"flex flex-col h-full min-h-0\" data-testid=\"agent-manager-chat-pane\">\n {/* In-session search bar.\n Layout: [search controls (flex-1)] ... [Manage AI providers].\n The search input expands inside the LEFT cluster only, so the\n Manage button stays anchored on the right and never shifts. */}\n <div className=\"flex items-center gap-1 px-3 py-1 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <div className=\"flex items-center gap-1.5 min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={toggleSearch}\n className={`p-1 rounded transition-colors shrink-0 ${\n searchOpen\n ? 'bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated'\n }`}\n title={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session (Ctrl+F)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.searchInSession',\n 'Search in session'\n )}\n >\n <Search className=\"size-3.5\" />\n </button>\n {searchOpen && (\n <div className=\"flex items-center gap-1.5 flex-1 min-w-0\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n placeholder={tr(\n 'vibecontrols.agentManager.chatPane.searchPlaceholder',\n 'Search in conversation...'\n )}\n className=\"flex-1 min-w-0 bg-transparent text-xs text-text-primary placeholder:text-text-tertiary focus:outline-none\"\n />\n {searchQuery && (\n <button\n type=\"button\"\n onClick={() => setSearchQuery('')}\n className=\"p-0.5 rounded hover:bg-bg-elevated transition-colors\"\n >\n <X className=\"size-3 text-text-tertiary\" />\n </button>\n )}\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => setBookmarksDrawerOpen(true)}\n className=\"shrink-0 p-1 rounded transition-colors text-text-tertiary hover:text-text-secondary hover:bg-bg-elevated\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.bookmarksTooltip',\n 'View bookmarked messages'\n )}\n aria-label={tr('vibecontrols.agentManager.chatPane.bookmarksLabel', 'Bookmarks')}\n data-testid=\"agent-manager-bookmarks-trigger\"\n >\n <Bookmark className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setInstallModalOpen(true)}\n className=\"shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border-default bg-bg-elevated px-2 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken hover:border-[var(--color-accent-soft)]\"\n title={tr(\n 'vibecontrols.agentManager.chatPane.manageProvidersTooltip',\n 'Install or remove AI providers (Claude, Codex, Gemini, OpenCode)'\n )}\n aria-label={tr(\n 'vibecontrols.agentManager.chatPane.manageProviders',\n 'Manage AI providers'\n )}\n data-testid=\"agent-manager-manage-providers\"\n >\n <PackagePlus className=\"size-3.5\" />\n <span className=\"hidden sm:inline\">\n {tr('vibecontrols.agentManager.chatPane.manageProviders', 'Manage AI providers')}\n </span>\n </button>\n </div>\n\n {/* Message list */}\n {loadingLogs ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.agentManager.chatPane.loadingConversation',\n 'Loading conversation...'\n )}\n </p>\n </div>\n ) : (\n <AgentManagerMessageList\n messages={messages}\n isStreaming={isStreaming}\n onCancelStream={cancelStream}\n searchQuery={searchQuery}\n bookmarkedIds={bookmarkedIds}\n onToggleBookmark={handleToggleBookmark}\n flashMessageId={flashMessageId}\n />\n )}\n\n {/* Rich input area with controls */}\n <AgentManagerInputArea\n agentId={agentId}\n sessionId={sessionId}\n onSend={(text) => void sendMessage(text)}\n onCancel={cancelStream}\n agentTunnelUrl={activeAgent?.tunnelUrl ?? undefined}\n />\n\n {/* Per-session bookmarks drawer */}\n <AgentManagerBookmarksDrawer\n open={bookmarksDrawerOpen}\n onClose={() => setBookmarksDrawerOpen(false)}\n sessionId={sessionId}\n messages={messages}\n onJump={jumpToMessage}\n />\n\n {/* Header-triggered provider install/remove. Sits below the chat\n tree so it can render full-screen without disturbing layout. */}\n <PluginInstallModal\n open={installModalOpen}\n agentId={agentId}\n onClose={() => setInstallModalOpen(false)}\n />\n\n {/* SDK auth prompt: opens when the streaming hook detects a missing\n ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, so the user can save the\n credential inline instead of being told to go look elsewhere.\n The session's currently-selected SDK is forwarded so the picker\n can preselect the right provider. */}\n <SdkAuthPromptModal\n agentId={agentId}\n agentRef={agentRef}\n initialProviderId={sessionState?.sdk ?? undefined}\n />\n </div>\n );\n};\n\ninterface SdkAuthPromptModalProps {\n agentId: string;\n agentRef: { id: string; profile: string };\n initialProviderId?: string;\n}\n\nconst SdkAuthPromptModal: FC<SdkAuthPromptModalProps> = ({\n agentId,\n agentRef,\n initialProviderId,\n}) => {\n const sdkAuthPrompt = useAgentManagerStore((s) => s.sdkAuthPrompt);\n const setSdkAuthPrompt = useAgentManagerStore((s) => s.setSdkAuthPrompt);\n // Track whether the inner card has at least one primary credential\n // saved on the agent. The Continue button is gated on this so the user\n // can't dismiss the modal without actually persisting a key — but the\n // moment they save *any* of the either-or options it lights up.\n const [authSatisfied, setAuthSatisfied] = useState(false);\n const tr = useTr();\n\n // Reset the satisfied flag whenever the modal re-opens for a fresh\n // prompt (different agent / different session). Without this, dismissing\n // and re-opening would leave the flag stuck at its previous value.\n useEffect(() => {\n if (sdkAuthPrompt && sdkAuthPrompt.agentId === agentId) {\n setAuthSatisfied(false);\n }\n }, [sdkAuthPrompt, agentId]);\n\n if (!sdkAuthPrompt || sdkAuthPrompt.agentId !== agentId) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n <div\n className=\"absolute inset-0 bg-bg-overlay\"\n onClick={() => setSdkAuthPrompt(null)}\n aria-hidden\n />\n {/* Constrain height to the viewport and let the inner body scroll so the\n modal never escapes the screen no matter how many providers/fields\n render inside AIProviderCredentialsCard. The header + footer stay\n sticky so the close + Continue buttons are always reachable. */}\n <div className=\"relative w-full max-w-xl max-h-[85vh] flex flex-col rounded-lg border border-border-default bg-bg-surface shadow-xl overflow-hidden\">\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default bg-bg-surface flex-shrink-0\">\n <h3 className=\"text-base font-semibold text-text-primary truncate pr-2\">\n {tr('vibecontrols.ai.sdkAuth.title', 'Configure AI provider credentials')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label={tr('vibecontrols.common.close', 'Close')}\n >\n <X className=\"size-5 text-text-secondary\" />\n </button>\n </div>\n <div className=\"flex-1 min-h-0 overflow-y-auto px-4 py-3 space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'vibecontrols.ai.sdkAuth.body',\n \"The agent doesn't have a credential configured for this provider. Save any one of the listed keys (you don't need all of them) and click Continue to retry.\"\n )}\n </p>\n <AIProviderCredentialsCard\n agent={agentRef}\n initialProviderId={initialProviderId}\n onProviderAuthSatisfiedChange={setAuthSatisfied}\n />\n </div>\n <div className=\"flex items-center justify-end gap-2 px-4 py-3 border-t border-border-default bg-bg-surface flex-shrink-0\">\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n className=\"px-3 py-1.5 rounded-md text-sm text-text-secondary hover:text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n {tr('vibecontrols.common.close', 'Close')}\n </button>\n <button\n type=\"button\"\n onClick={() => setSdkAuthPrompt(null)}\n disabled={!authSatisfied}\n title={\n authSatisfied\n ? undefined\n : tr(\n 'vibecontrols.ai.sdkAuth.saveOneFirst',\n 'Save at least one of the listed credentials to continue'\n )\n }\n className=\"px-3 py-1.5 rounded-md text-sm font-medium bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.ai.sdkAuth.continue', 'Continue')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -333,7 +333,7 @@ function y({ agentId: y, sessionId: b, onSend: x, onCancel: _e, mcpServers: ve =
333
333
  /* @__PURE__ */ m("button", {
334
334
  type: "button",
335
335
  onClick: () => Ee(b),
336
- className: `p-1.5 rounded text-xs font-medium transition-colors ${z.showThinking ? "bg-action-primary-bg/10 text-action-primary-text" : "text-text-tertiary hover:text-text-secondary"}`,
336
+ className: `p-1.5 rounded text-xs font-medium transition-colors ${z.showThinking ? "bg-[var(--color-accent-soft)] text-action-primary-bg" : "text-text-tertiary hover:text-text-secondary"}`,
337
337
  title: z.showThinking ? I("vibecontrols.agentManager.inputArea.hideThinking", "Hide thinking") : I("vibecontrols.agentManager.inputArea.showThinking", "Show thinking"),
338
338
  children: "Think"
339
339
  }),
@@ -395,12 +395,12 @@ function y({ agentId: y, sessionId: b, onSend: x, onCancel: _e, mcpServers: ve =
395
395
  onKeyDown: He,
396
396
  placeholder: I("vibecontrols.agentManager.inputArea.placeholder", "Type a message or / for commands... (Enter to send)"),
397
397
  rows: 1,
398
- className: "flex-1 resize-none rounded-lg border border-border-default bg-bg-primary px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors",
398
+ className: "flex-1 resize-none rounded-lg border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors",
399
399
  disabled: J
400
400
  }), J ? /* @__PURE__ */ m("button", {
401
401
  type: "button",
402
402
  onClick: Ue,
403
- className: "flex-shrink-0 p-2 rounded-lg bg-status-error-bg text-status-error-text hover:opacity-90 transition-opacity",
403
+ className: "flex-shrink-0 p-2 rounded-lg bg-status-error-bg-subtle text-status-error-text hover:opacity-90 transition-opacity",
404
404
  title: I("vibecontrols.agentManager.inputArea.cancel", "Cancel"),
405
405
  children: /* @__PURE__ */ m(ge, { className: "size-4" })
406
406
  }) : /* @__PURE__ */ h("div", {
@@ -437,7 +437,7 @@ function y({ agentId: y, sessionId: b, onSend: x, onCancel: _e, mcpServers: ve =
437
437
  type: "datetime-local",
438
438
  value: M,
439
439
  onChange: (e) => N(e.target.value),
440
- className: "w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-primary text-text-primary focus:outline-none focus:border-border-strong"
440
+ className: "w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:border-border-strong"
441
441
  }),
442
442
  /* @__PURE__ */ m("button", {
443
443
  type: "button",
@@ -1 +1 @@
1
- {"version":3,"file":"AgentManagerInputArea.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerInputArea.tsx"],"sourcesContent":["/**\n * Rich input area for the Agent Manager chat.\n *\n * Sits at the bottom of the chat pane. Contains a toolbar row with\n * control selectors and a resizable textarea with send/cancel buttons.\n * Supports file attachment preview, keyboard shortcuts, and slash\n * commands for quick actions.\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo, type KeyboardEvent } from 'react';\nimport {\n ArrowUp,\n Square,\n X,\n ChevronDown,\n Clock,\n FolderOpen,\n FileText,\n Sparkles,\n} from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useVoiceMode } from '@/hooks/useVoiceMode';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchProviders, type AIProvider } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { schedulePrompt } from '@/services/schedulerApi';\nimport { ModelSelector } from './controls/ModelSelector';\nimport { SdkSelector } from './controls/SdkSelector';\nimport { AutonomySelector } from './controls/AutonomySelector';\nimport { McpServerSelector } from './controls/McpServerSelector';\nimport { VoiceToggle } from './controls/VoiceToggle';\nimport { FileAttachButton } from './controls/FileAttachButton';\nimport { createDropHandlers } from './controls/createDropHandlers';\nimport { ContextLevelToggle } from './controls/ContextLevelToggle';\nimport { ChatInsertPicker } from './ChatInsertPicker';\nimport { FilePickerModal } from './FilePickerModal';\nimport { GENERIC_MODEL_FALLBACK, resolveProviderDefaultModel } from './modelDefaults';\nimport type { AgentSdkType, McpServer, ProviderMode } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Slash commands */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface SlashCommand {\n command: string;\n description: string;\n args?: string;\n}\n\nconst SLASH_COMMANDS: SlashCommand[] = [\n { command: '/new', description: 'Create new session' },\n { command: '/rename', description: 'Rename current session', args: '<name>' },\n { command: '/model', description: 'Switch model', args: '<model-name>' },\n {\n command: '/sdk',\n description: 'Switch SDK',\n args: '<claude|codex|gemini|opencode|openai-compat>',\n },\n { command: '/mode', description: 'Switch mode', args: '<sdk|cli>' },\n { command: '/export', description: 'Export conversation', args: '[json|md]' },\n { command: '/clear', description: 'Clear conversation' },\n { command: '/help', description: 'Show available commands' },\n];\n\nconst VALID_SDKS: AgentSdkType[] = [\n 'claude',\n 'codex',\n 'gemini',\n 'opencode',\n 'cursor',\n 'openrouter',\n 'minimax',\n 'ollama',\n 'openai-compat',\n 'goose',\n 'amp',\n 'copilot',\n 'crush',\n 'pi',\n 'aider',\n 'plandex',\n];\nconst VALID_MODES: ProviderMode[] = ['sdk', 'cli'];\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Component */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface AgentManagerInputAreaProps {\n agentId: string;\n sessionId: string;\n onSend: (text: string, attachments?: File[]) => void;\n onCancel?: () => void;\n mcpServers?: McpServer[];\n agentTunnelUrl?: string;\n}\n\nexport function AgentManagerInputArea({\n agentId,\n sessionId,\n onSend,\n onCancel,\n mcpServers = [],\n agentTunnelUrl,\n}: AgentManagerInputAreaProps) {\n const [text, setText] = useState('');\n const [pendingFiles, setPendingFiles] = useState<File[]>([]);\n const [showSlashMenu, setShowSlashMenu] = useState(false);\n const [slashFilter, setSlashFilter] = useState('');\n const [showScheduleMenu, setShowScheduleMenu] = useState(false);\n const [showSchedulePopup, setShowSchedulePopup] = useState(false);\n const [scheduleDateTime, setScheduleDateTime] = useState('');\n const [providers, setProviders] = useState<AIProvider[]>([]);\n const [filePickerOpen, setFilePickerOpen] = useState(false);\n const tr = useTr();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const scheduleMenuRef = useRef<HTMLDivElement>(null);\n\n // Auto-focus textarea when session is opened or switched\n useEffect(() => {\n textareaRef.current?.focus({ preventScroll: true });\n }, []);\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const setSessionModel = useAgentManagerStore((s) => s.setSessionModel);\n const setSessionSdk = useAgentManagerStore((s) => s.setSessionSdk);\n const setSessionMode = useAgentManagerStore((s) => s.setSessionMode);\n const setSessionPermissionMode = useAgentManagerStore((s) => s.setSessionPermissionMode);\n const toggleVoice = useAgentManagerStore((s) => s.toggleVoice);\n const toggleThinking = useAgentManagerStore((s) => s.toggleThinking);\n const setSessionContextLevel = useAgentManagerStore((s) => s.setSessionContextLevel);\n const setSessionVibe = useAgentManagerStore((s) => s.setSessionVibe);\n const setSessionRootPath = useAgentManagerStore((s) => s.setSessionRootPath);\n const openSession = useAgentManagerStore((s) => s.openSession);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n const removeSessionContext = useAgentManagerStore((s) => s.removeSessionContext);\n const addSessionContext = useAgentManagerStore((s) => s.addSessionContext);\n const pendingChatInsert = useAgentManagerStore((s) => s.pendingChatInsert);\n const setPendingChatInsert = useAgentManagerStore((s) => s.setPendingChatInsert);\n\n // Consume a pending \"insert into chat\" request set by a \"Use in chat\" action\n // elsewhere (ai-tools tabs, vibe panels): append its text to the composer and\n // attach its contexts to this session, then clear it so it fires once.\n useEffect(() => {\n if (!pendingChatInsert) return;\n if (pendingChatInsert.text) {\n const insertText = pendingChatInsert.text;\n setText((prev) => (prev ? `${prev}\\n${insertText}` : insertText));\n }\n for (const ctx of pendingChatInsert.contexts ?? []) {\n addSessionContext(sessionId, ctx);\n }\n setPendingChatInsert(null);\n textareaRef.current?.focus({ preventScroll: true });\n }, [pendingChatInsert, sessionId, addSessionContext, setPendingChatInsert]);\n\n const { vibes, agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { isListening, transcript, startListening, stopListening } = useVoiceMode();\n\n const isStreaming = sessionState?.status === 'streaming';\n const canSend = text.trim().length > 0 && !isStreaming;\n\n // Append voice transcript to textarea\n useEffect(() => {\n if (transcript && isListening) {\n setText((prev) => prev + (prev ? ' ' : '') + transcript);\n }\n }, [transcript, isListening]);\n\n useEffect(() => {\n let cancelled = false;\n void fetchProviders(agentRef)\n .then((items) => {\n if (!cancelled) setProviders(items);\n })\n .catch(() => {\n if (!cancelled) setProviders([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agentRef]);\n\n // ── Slash command filtering ──\n useEffect(() => {\n if (text.startsWith('/') && !text.includes(' ')) {\n setShowSlashMenu(true);\n setSlashFilter(text.slice(1));\n } else {\n setShowSlashMenu(false);\n }\n }, [text]);\n\n const filteredCommands = useMemo(\n () =>\n SLASH_COMMANDS.filter((cmd) =>\n cmd.command.toLowerCase().includes(`/${slashFilter.toLowerCase()}`)\n ),\n [slashFilter]\n );\n\n // Auto-resize textarea\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = 'auto';\n const maxRows = 10;\n const lineHeight = 20;\n const maxHeight = maxRows * lineHeight;\n el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;\n }, [text]);\n\n // Close schedule menu on outside click\n useEffect(() => {\n if (!showScheduleMenu && !showSchedulePopup) return;\n const handler = (e: MouseEvent) => {\n if (scheduleMenuRef.current && !scheduleMenuRef.current.contains(e.target as Node)) {\n setShowScheduleMenu(false);\n setShowSchedulePopup(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [showScheduleMenu, showSchedulePopup]);\n\n const addSystemMessage = useCallback(\n (content: string) => {\n addMessage(sessionId, {\n id: `sys-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n role: 'system',\n content,\n timestamp: new Date().toISOString(),\n });\n },\n [addMessage, sessionId]\n );\n\n const handleScheduleSend = useCallback(async () => {\n if (!text.trim() || !scheduleDateTime || !agentId) return;\n try {\n const result = await schedulePrompt({\n sessionId,\n agentRef: { agentId, profile: activeProfile ?? 'default' },\n prompt: text.trim(),\n scheduledAt: new Date(scheduleDateTime).toISOString(),\n });\n addSystemMessage(\n `Prompt scheduled for ${new Date(result.scheduledAt).toLocaleString()} (Job: ${result.jobId.slice(0, 8)})`\n );\n setText('');\n setScheduleDateTime('');\n setShowSchedulePopup(false);\n setShowScheduleMenu(false);\n } catch (err) {\n addSystemMessage(\n `Failed to schedule: ${err instanceof Error ? err.message : 'Unknown error'}`\n );\n }\n }, [text, scheduleDateTime, sessionId, agentId, activeProfile, addSystemMessage]);\n\n const executeSlashCommand = useCallback(\n (input: string) => {\n const parts = input.trim().split(/\\s+/);\n const cmd = parts[0].toLowerCase();\n const arg = parts.slice(1).join(' ');\n\n switch (cmd) {\n case '/new': {\n const newId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n openSession(newId);\n break;\n }\n case '/rename':\n if (arg) {\n addSystemMessage(`Session renamed to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /rename <name>');\n }\n break;\n case '/model':\n if (arg) {\n setSessionModel(sessionId, arg);\n addSystemMessage(`Model switched to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /model <model-name>');\n }\n break;\n case '/sdk':\n if (arg && VALID_SDKS.includes(arg as AgentSdkType)) {\n const nextSdk = arg as AgentSdkType;\n setSessionSdk(sessionId, nextSdk);\n void resolveProviderDefaultModel(\n agentRef,\n nextSdk,\n sessionState?.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState?.model ?? GENERIC_MODEL_FALLBACK)\n );\n addSystemMessage(`SDK switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /sdk <${VALID_SDKS.join('|')}>`);\n }\n break;\n case '/mode':\n if (arg && VALID_MODES.includes(arg as ProviderMode)) {\n setSessionMode(sessionId, arg as ProviderMode);\n addSystemMessage(`Mode switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /mode <${VALID_MODES.join('|')}>`);\n }\n break;\n case '/export': {\n const format = arg === 'md' ? 'md' : 'json';\n const messages = sessionState?.messages ?? [];\n const exported =\n format === 'json'\n ? JSON.stringify(messages, null, 2)\n : messages\n .map((m) => `**${m.role}** (${m.timestamp ?? ''}):\\n${m.content ?? ''}`)\n .join('\\n\\n---\\n\\n');\n const blob = new Blob([exported], {\n type: format === 'json' ? 'application/json' : 'text/markdown',\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `conversation-${sessionId}.${format}`;\n a.click();\n URL.revokeObjectURL(url);\n addSystemMessage(`Conversation exported as ${format}.`);\n break;\n }\n case '/clear':\n addSystemMessage('Conversation cleared.');\n break;\n case '/help': {\n const helpText = SLASH_COMMANDS.map(\n (c) => ` ${c.command}${c.args ? ' ' + c.args : ''} - ${c.description}`\n ).join('\\n');\n addSystemMessage(`Available commands:\\n${helpText}`);\n break;\n }\n default:\n addSystemMessage(`Unknown command: ${cmd}. Type /help for available commands.`);\n }\n },\n [\n sessionId,\n sessionState?.messages,\n sessionState?.model,\n openSession,\n setSessionModel,\n setSessionSdk,\n setSessionMode,\n addSystemMessage,\n agentRef,\n ]\n );\n\n const handleSlashSelect = useCallback(\n (cmd: SlashCommand) => {\n // If command takes args, fill the text and let user type args\n if (cmd.args) {\n setText(`${cmd.command} `);\n } else {\n executeSlashCommand(cmd.command);\n setText('');\n }\n setShowSlashMenu(false);\n textareaRef.current?.focus();\n },\n [executeSlashCommand]\n );\n\n const handleSend = useCallback(() => {\n if (!canSend) return;\n\n const trimmed = text.trim();\n\n // Handle slash commands locally\n if (trimmed.startsWith('/')) {\n executeSlashCommand(trimmed);\n setText('');\n setPendingFiles([]);\n return;\n }\n\n onSend(trimmed, pendingFiles.length > 0 ? pendingFiles : undefined);\n setText('');\n setPendingFiles([]);\n }, [canSend, text, pendingFiles, onSend, executeSlashCommand]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n // Enter sends, Shift+Enter inserts newline\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend]\n );\n\n const handleCancel = useCallback(() => {\n onCancel?.();\n }, [onCancel]);\n\n const handleFileSelect = useCallback((files: File[]) => {\n setPendingFiles((prev) => [...prev, ...files]);\n }, []);\n\n const removeFile = useCallback((index: number) => {\n setPendingFiles((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const dropHandlers = createDropHandlers(handleFileSelect);\n\n if (!sessionState) return null;\n\n return (\n <div className=\"relative z-30 border-t border-border-default bg-bg-surface\" {...dropHandlers}>\n {/* Slash command popup */}\n {showSlashMenu && filteredCommands.length > 0 && (\n <div className=\"absolute bottom-full left-0 right-0 mb-1 mx-3 bg-bg-elevated border border-border-default rounded-lg shadow-lg max-h-48 overflow-y-auto z-50\">\n {filteredCommands.map((cmd) => (\n <button\n key={cmd.command}\n type=\"button\"\n onClick={() => handleSlashSelect(cmd)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left hover:bg-bg-sunken transition-colors\"\n >\n <span className=\"font-mono text-xs text-text-primary\">{cmd.command}</span>\n {cmd.args && <span className=\"text-text-tertiary text-xs\">{cmd.args}</span>}\n <span className=\"text-text-secondary text-xs ml-auto\">{cmd.description}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Attached context chips (backend prompts/contexts + Files-module files\n materialised on the agent). Sent to the agent as contexts[] on send. */}\n {(sessionState?.contexts?.length ?? 0) > 0 && (\n <div\n className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\"\n data-testid=\"chat-context-chips\"\n >\n {sessionState?.contexts.map((ctx) => (\n <div\n key={ctx.id}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n title={ctx.path ?? ctx.label}\n >\n {ctx.kind === 'file' ? (\n <FolderOpen className=\"size-3 flex-shrink-0\" />\n ) : ctx.kind === 'prompt' ? (\n <Sparkles className=\"size-3 flex-shrink-0\" />\n ) : (\n <FileText className=\"size-3 flex-shrink-0\" />\n )}\n <span className=\"truncate max-w-[140px]\">{ctx.label}</span>\n <button\n type=\"button\"\n onClick={() => removeSessionContext(sessionId, ctx.id)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label=\"Remove context\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* File attachment preview row */}\n {pendingFiles.length > 0 && (\n <div className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\">\n {pendingFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n >\n <span className=\"truncate max-w-[120px]\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(index)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Toolbar row */}\n <div className=\"flex flex-wrap items-center gap-1 px-3 pt-2 pb-1 overflow-x-auto\">\n <SdkSelector\n sdk={sessionState.sdk}\n mode={sessionState.mode}\n providers={providers}\n onSdkChange={(sdk) => {\n setSessionSdk(sessionId, sdk);\n void resolveProviderDefaultModel(\n agentRef,\n sdk,\n sessionState.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState.model ?? GENERIC_MODEL_FALLBACK)\n );\n }}\n onModeChange={(mode) => setSessionMode(sessionId, mode)}\n />\n <ModelSelector\n value={sessionState.model}\n onChange={(model) => setSessionModel(sessionId, model)}\n provider={sessionState.sdk}\n agentId={agentId}\n />\n <AutonomySelector\n value={sessionState.permissionMode}\n mode={sessionState.mode}\n onChange={(permissionMode) => setSessionPermissionMode(sessionId, permissionMode)}\n />\n <McpServerSelector\n selected={sessionState.mcpServers}\n available={mcpServers}\n onChange={() => {\n // Update via store -- MCP servers are part of session state\n // For now we store them directly\n }}\n />\n <ContextLevelToggle\n agentId=\"\"\n sessionId={sessionId}\n contextLevel={sessionState.contextLevel}\n rootPath={sessionState.rootPath}\n onChange={(level, rootPath, vibeId) => {\n setSessionContextLevel(sessionId, level);\n setSessionRootPath(sessionId, rootPath ?? null);\n setSessionVibe(sessionId, vibeId ?? null, rootPath ?? null);\n }}\n vibes={vibes.map((v) => ({ id: v.id, name: v.name, path: v.path }))}\n />\n\n <div className=\"flex-1\" />\n\n {/* Show Thinking toggle */}\n <button\n type=\"button\"\n onClick={() => toggleThinking(sessionId)}\n className={`p-1.5 rounded text-xs font-medium transition-colors ${\n sessionState.showThinking\n ? 'bg-action-primary-bg/10 text-action-primary-text'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n sessionState.showThinking\n ? tr('vibecontrols.agentManager.inputArea.hideThinking', 'Hide thinking')\n : tr('vibecontrols.agentManager.inputArea.showThinking', 'Show thinking')\n }\n >\n Think\n </button>\n {/* Context history limit */}\n <button\n type=\"button\"\n onClick={() => {\n const val = window.prompt(\n 'Context history limit (messages sent with each prompt):',\n String(sessionState.contextHistoryLimit)\n );\n if (val !== null) {\n const num = parseInt(val, 10);\n if (!isNaN(num) && num >= 0) {\n const store = useAgentManagerStore.getState();\n const s = store.sessionStates[sessionId];\n if (s) {\n useAgentManagerStore.setState((prev) => ({\n sessionStates: {\n ...prev.sessionStates,\n [sessionId]: { ...s, contextHistoryLimit: num },\n },\n }));\n }\n }\n }\n }}\n className=\"p-1.5 rounded text-[10px] font-mono text-text-tertiary hover:text-text-secondary transition-colors\"\n title={`Context history: last ${sessionState.contextHistoryLimit} messages sent with each prompt`}\n >\n H:{sessionState.contextHistoryLimit}\n </button>\n <VoiceToggle\n enabled={sessionState.voiceEnabled}\n onToggle={() => {\n toggleVoice(sessionId);\n if (!sessionState.voiceEnabled) startListening();\n else stopListening();\n }}\n isListening={isListening}\n />\n <FileAttachButton onFileSelect={handleFileSelect} />\n\n {/* Insert a backend prompt (rendered) into the composer, or attach a\n shared AiContext to the session. */}\n <ChatInsertPicker\n sessionId={sessionId}\n vibeId={sessionState?.vibeId}\n onInsertText={(t) => setText((prev) => (prev ? `${prev}\\n${t}` : t))}\n />\n\n {/* Attach a Files-module file: the agent fetches + materialises it on\n the server and its path becomes conversation context. */}\n <button\n type=\"button\"\n onClick={() => setFilePickerOpen(true)}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs text-text-secondary hover:bg-bg-sunken transition-colors\"\n title=\"Add a file from the Files module as context\"\n data-testid=\"chat-add-from-files\"\n >\n <FolderOpen className=\"size-4\" />\n <span className=\"hidden sm:inline\">Files</span>\n </button>\n </div>\n\n {/* Textarea + send/cancel */}\n <div className=\"flex items-end gap-2 px-3 pb-3 pt-1\">\n <textarea\n aria-label=\"control\"\n ref={textareaRef}\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={tr(\n 'vibecontrols.agentManager.inputArea.placeholder',\n 'Type a message or / for commands... (Enter to send)'\n )}\n rows={1}\n className=\"flex-1 resize-none rounded-lg border border-border-default bg-bg-primary px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors\"\n disabled={isStreaming}\n />\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"flex-shrink-0 p-2 rounded-lg bg-status-error-bg text-status-error-text hover:opacity-90 transition-opacity\"\n title={tr('vibecontrols.agentManager.inputArea.cancel', 'Cancel')}\n >\n <Square className=\"size-4\" />\n </button>\n ) : (\n <div className=\"flex items-end flex-shrink-0 relative\" ref={scheduleMenuRef}>\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"p-2 rounded-l-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.send', 'Send (Enter)')}\n >\n <ArrowUp className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowScheduleMenu(!showScheduleMenu)}\n disabled={!canSend}\n className=\"ml-1 p-2 rounded-r-lg border-l border-action-primary-text/20 bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.scheduleSend', 'Schedule send')}\n >\n <ChevronDown className=\"size-3\" />\n </button>\n\n {/* Schedule dropdown */}\n {showScheduleMenu && (\n <div className=\"absolute bottom-full right-0 mb-1 w-56 bg-bg-surface border border-border-default rounded-md shadow-lg py-1 z-50\">\n {!showSchedulePopup ? (\n <button\n type=\"button\"\n onClick={() => setShowSchedulePopup(true)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Clock className=\"size-3.5 text-text-secondary\" />\n {tr(\n 'vibecontrols.agentManager.inputArea.scheduleSendEllipsis',\n 'Schedule Send...'\n )}\n </button>\n ) : (\n <div className=\"px-3 py-2 space-y-2\">\n <label className=\"block text-[11px] font-medium text-text-secondary\">\n {tr('vibecontrols.agentManager.inputArea.sendAt', 'Send at:')}\n </label>\n <input\n aria-label=\"control\"\n type=\"datetime-local\"\n value={scheduleDateTime}\n onChange={(e) => setScheduleDateTime(e.target.value)}\n className=\"w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-primary text-text-primary focus:outline-none focus:border-border-strong\"\n />\n <button\n type=\"button\"\n onClick={() => void handleScheduleSend()}\n disabled={!scheduleDateTime || !agentId}\n className=\"w-full px-2 py-1.5 text-xs font-medium rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.agentManager.inputArea.schedule', 'Schedule')}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Files-module picker → agent materialises the file → session context. */}\n <FilePickerModal\n isOpen={filePickerOpen}\n onClose={() => setFilePickerOpen(false)}\n agent={agentRef}\n sessionId={sessionId}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentManagerInputArea.js","names":[],"sources":["../../../src/components/agent-manager/AgentManagerInputArea.tsx"],"sourcesContent":["/**\n * Rich input area for the Agent Manager chat.\n *\n * Sits at the bottom of the chat pane. Contains a toolbar row with\n * control selectors and a resizable textarea with send/cancel buttons.\n * Supports file attachment preview, keyboard shortcuts, and slash\n * commands for quick actions.\n */\n\nimport { useState, useRef, useCallback, useEffect, useMemo, type KeyboardEvent } from 'react';\nimport {\n ArrowUp,\n Square,\n X,\n ChevronDown,\n Clock,\n FolderOpen,\n FileText,\n Sparkles,\n} from 'lucide-react';\nimport { useAgentManagerStore } from '@/store/agentManagerStore';\nimport { useVoiceMode } from '@/hooks/useVoiceMode';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { fetchProviders, type AIProvider } from '@/services/aiApi';\nimport { useActiveAgentProfile } from '@/hooks/useActiveAgentProfile';\nimport { schedulePrompt } from '@/services/schedulerApi';\nimport { ModelSelector } from './controls/ModelSelector';\nimport { SdkSelector } from './controls/SdkSelector';\nimport { AutonomySelector } from './controls/AutonomySelector';\nimport { McpServerSelector } from './controls/McpServerSelector';\nimport { VoiceToggle } from './controls/VoiceToggle';\nimport { FileAttachButton } from './controls/FileAttachButton';\nimport { createDropHandlers } from './controls/createDropHandlers';\nimport { ContextLevelToggle } from './controls/ContextLevelToggle';\nimport { ChatInsertPicker } from './ChatInsertPicker';\nimport { FilePickerModal } from './FilePickerModal';\nimport { GENERIC_MODEL_FALLBACK, resolveProviderDefaultModel } from './modelDefaults';\nimport type { AgentSdkType, McpServer, ProviderMode } from '@/types/agentManager';\nimport { useTr } from '../../shared/hooks/useTr';\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Slash commands */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface SlashCommand {\n command: string;\n description: string;\n args?: string;\n}\n\nconst SLASH_COMMANDS: SlashCommand[] = [\n { command: '/new', description: 'Create new session' },\n { command: '/rename', description: 'Rename current session', args: '<name>' },\n { command: '/model', description: 'Switch model', args: '<model-name>' },\n {\n command: '/sdk',\n description: 'Switch SDK',\n args: '<claude|codex|gemini|opencode|openai-compat>',\n },\n { command: '/mode', description: 'Switch mode', args: '<sdk|cli>' },\n { command: '/export', description: 'Export conversation', args: '[json|md]' },\n { command: '/clear', description: 'Clear conversation' },\n { command: '/help', description: 'Show available commands' },\n];\n\nconst VALID_SDKS: AgentSdkType[] = [\n 'claude',\n 'codex',\n 'gemini',\n 'opencode',\n 'cursor',\n 'openrouter',\n 'minimax',\n 'ollama',\n 'openai-compat',\n 'goose',\n 'amp',\n 'copilot',\n 'crush',\n 'pi',\n 'aider',\n 'plandex',\n];\nconst VALID_MODES: ProviderMode[] = ['sdk', 'cli'];\n\n/* ────────────────────────────────────────────────────────────────────── */\n/* Component */\n/* ────────────────────────────────────────────────────────────────────── */\n\ninterface AgentManagerInputAreaProps {\n agentId: string;\n sessionId: string;\n onSend: (text: string, attachments?: File[]) => void;\n onCancel?: () => void;\n mcpServers?: McpServer[];\n agentTunnelUrl?: string;\n}\n\nexport function AgentManagerInputArea({\n agentId,\n sessionId,\n onSend,\n onCancel,\n mcpServers = [],\n agentTunnelUrl,\n}: AgentManagerInputAreaProps) {\n const [text, setText] = useState('');\n const [pendingFiles, setPendingFiles] = useState<File[]>([]);\n const [showSlashMenu, setShowSlashMenu] = useState(false);\n const [slashFilter, setSlashFilter] = useState('');\n const [showScheduleMenu, setShowScheduleMenu] = useState(false);\n const [showSchedulePopup, setShowSchedulePopup] = useState(false);\n const [scheduleDateTime, setScheduleDateTime] = useState('');\n const [providers, setProviders] = useState<AIProvider[]>([]);\n const [filePickerOpen, setFilePickerOpen] = useState(false);\n const tr = useTr();\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const scheduleMenuRef = useRef<HTMLDivElement>(null);\n\n // Auto-focus textarea when session is opened or switched\n useEffect(() => {\n textareaRef.current?.focus({ preventScroll: true });\n }, []);\n\n const sessionState = useAgentManagerStore((s) => s.sessionStates[sessionId]);\n const setSessionModel = useAgentManagerStore((s) => s.setSessionModel);\n const setSessionSdk = useAgentManagerStore((s) => s.setSessionSdk);\n const setSessionMode = useAgentManagerStore((s) => s.setSessionMode);\n const setSessionPermissionMode = useAgentManagerStore((s) => s.setSessionPermissionMode);\n const toggleVoice = useAgentManagerStore((s) => s.toggleVoice);\n const toggleThinking = useAgentManagerStore((s) => s.toggleThinking);\n const setSessionContextLevel = useAgentManagerStore((s) => s.setSessionContextLevel);\n const setSessionVibe = useAgentManagerStore((s) => s.setSessionVibe);\n const setSessionRootPath = useAgentManagerStore((s) => s.setSessionRootPath);\n const openSession = useAgentManagerStore((s) => s.openSession);\n const addMessage = useAgentManagerStore((s) => s.addMessage);\n const removeSessionContext = useAgentManagerStore((s) => s.removeSessionContext);\n const addSessionContext = useAgentManagerStore((s) => s.addSessionContext);\n const pendingChatInsert = useAgentManagerStore((s) => s.pendingChatInsert);\n const setPendingChatInsert = useAgentManagerStore((s) => s.setPendingChatInsert);\n\n // Consume a pending \"insert into chat\" request set by a \"Use in chat\" action\n // elsewhere (ai-tools tabs, vibe panels): append its text to the composer and\n // attach its contexts to this session, then clear it so it fires once.\n useEffect(() => {\n if (!pendingChatInsert) return;\n if (pendingChatInsert.text) {\n const insertText = pendingChatInsert.text;\n setText((prev) => (prev ? `${prev}\\n${insertText}` : insertText));\n }\n for (const ctx of pendingChatInsert.contexts ?? []) {\n addSessionContext(sessionId, ctx);\n }\n setPendingChatInsert(null);\n textareaRef.current?.focus({ preventScroll: true });\n }, [pendingChatInsert, sessionId, addSessionContext, setPendingChatInsert]);\n\n const { vibes, agents } = useCachedInitialData();\n const activeAgent = useMemo(\n () => agents.find((a) => a.id === agentId) ?? null,\n [agents, agentId]\n );\n const { active: activeProfile } = useActiveAgentProfile(activeAgent?.id ?? null);\n const agentRef = useMemo(\n () => ({ id: agentId, profile: activeProfile }),\n [agentId, activeProfile]\n );\n\n const { isListening, transcript, startListening, stopListening } = useVoiceMode();\n\n const isStreaming = sessionState?.status === 'streaming';\n const canSend = text.trim().length > 0 && !isStreaming;\n\n // Append voice transcript to textarea\n useEffect(() => {\n if (transcript && isListening) {\n setText((prev) => prev + (prev ? ' ' : '') + transcript);\n }\n }, [transcript, isListening]);\n\n useEffect(() => {\n let cancelled = false;\n void fetchProviders(agentRef)\n .then((items) => {\n if (!cancelled) setProviders(items);\n })\n .catch(() => {\n if (!cancelled) setProviders([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [agentRef]);\n\n // ── Slash command filtering ──\n useEffect(() => {\n if (text.startsWith('/') && !text.includes(' ')) {\n setShowSlashMenu(true);\n setSlashFilter(text.slice(1));\n } else {\n setShowSlashMenu(false);\n }\n }, [text]);\n\n const filteredCommands = useMemo(\n () =>\n SLASH_COMMANDS.filter((cmd) =>\n cmd.command.toLowerCase().includes(`/${slashFilter.toLowerCase()}`)\n ),\n [slashFilter]\n );\n\n // Auto-resize textarea\n useEffect(() => {\n const el = textareaRef.current;\n if (!el) return;\n el.style.height = 'auto';\n const maxRows = 10;\n const lineHeight = 20;\n const maxHeight = maxRows * lineHeight;\n el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;\n }, [text]);\n\n // Close schedule menu on outside click\n useEffect(() => {\n if (!showScheduleMenu && !showSchedulePopup) return;\n const handler = (e: MouseEvent) => {\n if (scheduleMenuRef.current && !scheduleMenuRef.current.contains(e.target as Node)) {\n setShowScheduleMenu(false);\n setShowSchedulePopup(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [showScheduleMenu, showSchedulePopup]);\n\n const addSystemMessage = useCallback(\n (content: string) => {\n addMessage(sessionId, {\n id: `sys-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,\n role: 'system',\n content,\n timestamp: new Date().toISOString(),\n });\n },\n [addMessage, sessionId]\n );\n\n const handleScheduleSend = useCallback(async () => {\n if (!text.trim() || !scheduleDateTime || !agentId) return;\n try {\n const result = await schedulePrompt({\n sessionId,\n agentRef: { agentId, profile: activeProfile ?? 'default' },\n prompt: text.trim(),\n scheduledAt: new Date(scheduleDateTime).toISOString(),\n });\n addSystemMessage(\n `Prompt scheduled for ${new Date(result.scheduledAt).toLocaleString()} (Job: ${result.jobId.slice(0, 8)})`\n );\n setText('');\n setScheduleDateTime('');\n setShowSchedulePopup(false);\n setShowScheduleMenu(false);\n } catch (err) {\n addSystemMessage(\n `Failed to schedule: ${err instanceof Error ? err.message : 'Unknown error'}`\n );\n }\n }, [text, scheduleDateTime, sessionId, agentId, activeProfile, addSystemMessage]);\n\n const executeSlashCommand = useCallback(\n (input: string) => {\n const parts = input.trim().split(/\\s+/);\n const cmd = parts[0].toLowerCase();\n const arg = parts.slice(1).join(' ');\n\n switch (cmd) {\n case '/new': {\n const newId = `session-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;\n openSession(newId);\n break;\n }\n case '/rename':\n if (arg) {\n addSystemMessage(`Session renamed to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /rename <name>');\n }\n break;\n case '/model':\n if (arg) {\n setSessionModel(sessionId, arg);\n addSystemMessage(`Model switched to \"${arg}\".`);\n } else {\n addSystemMessage('Usage: /model <model-name>');\n }\n break;\n case '/sdk':\n if (arg && VALID_SDKS.includes(arg as AgentSdkType)) {\n const nextSdk = arg as AgentSdkType;\n setSessionSdk(sessionId, nextSdk);\n void resolveProviderDefaultModel(\n agentRef,\n nextSdk,\n sessionState?.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState?.model ?? GENERIC_MODEL_FALLBACK)\n );\n addSystemMessage(`SDK switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /sdk <${VALID_SDKS.join('|')}>`);\n }\n break;\n case '/mode':\n if (arg && VALID_MODES.includes(arg as ProviderMode)) {\n setSessionMode(sessionId, arg as ProviderMode);\n addSystemMessage(`Mode switched to \"${arg}\".`);\n } else {\n addSystemMessage(`Usage: /mode <${VALID_MODES.join('|')}>`);\n }\n break;\n case '/export': {\n const format = arg === 'md' ? 'md' : 'json';\n const messages = sessionState?.messages ?? [];\n const exported =\n format === 'json'\n ? JSON.stringify(messages, null, 2)\n : messages\n .map((m) => `**${m.role}** (${m.timestamp ?? ''}):\\n${m.content ?? ''}`)\n .join('\\n\\n---\\n\\n');\n const blob = new Blob([exported], {\n type: format === 'json' ? 'application/json' : 'text/markdown',\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = `conversation-${sessionId}.${format}`;\n a.click();\n URL.revokeObjectURL(url);\n addSystemMessage(`Conversation exported as ${format}.`);\n break;\n }\n case '/clear':\n addSystemMessage('Conversation cleared.');\n break;\n case '/help': {\n const helpText = SLASH_COMMANDS.map(\n (c) => ` ${c.command}${c.args ? ' ' + c.args : ''} - ${c.description}`\n ).join('\\n');\n addSystemMessage(`Available commands:\\n${helpText}`);\n break;\n }\n default:\n addSystemMessage(`Unknown command: ${cmd}. Type /help for available commands.`);\n }\n },\n [\n sessionId,\n sessionState?.messages,\n sessionState?.model,\n openSession,\n setSessionModel,\n setSessionSdk,\n setSessionMode,\n addSystemMessage,\n agentRef,\n ]\n );\n\n const handleSlashSelect = useCallback(\n (cmd: SlashCommand) => {\n // If command takes args, fill the text and let user type args\n if (cmd.args) {\n setText(`${cmd.command} `);\n } else {\n executeSlashCommand(cmd.command);\n setText('');\n }\n setShowSlashMenu(false);\n textareaRef.current?.focus();\n },\n [executeSlashCommand]\n );\n\n const handleSend = useCallback(() => {\n if (!canSend) return;\n\n const trimmed = text.trim();\n\n // Handle slash commands locally\n if (trimmed.startsWith('/')) {\n executeSlashCommand(trimmed);\n setText('');\n setPendingFiles([]);\n return;\n }\n\n onSend(trimmed, pendingFiles.length > 0 ? pendingFiles : undefined);\n setText('');\n setPendingFiles([]);\n }, [canSend, text, pendingFiles, onSend, executeSlashCommand]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n // Enter sends, Shift+Enter inserts newline\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n },\n [handleSend]\n );\n\n const handleCancel = useCallback(() => {\n onCancel?.();\n }, [onCancel]);\n\n const handleFileSelect = useCallback((files: File[]) => {\n setPendingFiles((prev) => [...prev, ...files]);\n }, []);\n\n const removeFile = useCallback((index: number) => {\n setPendingFiles((prev) => prev.filter((_, i) => i !== index));\n }, []);\n\n const dropHandlers = createDropHandlers(handleFileSelect);\n\n if (!sessionState) return null;\n\n return (\n <div className=\"relative z-30 border-t border-border-default bg-bg-surface\" {...dropHandlers}>\n {/* Slash command popup */}\n {showSlashMenu && filteredCommands.length > 0 && (\n <div className=\"absolute bottom-full left-0 right-0 mb-1 mx-3 bg-bg-elevated border border-border-default rounded-lg shadow-lg max-h-48 overflow-y-auto z-50\">\n {filteredCommands.map((cmd) => (\n <button\n key={cmd.command}\n type=\"button\"\n onClick={() => handleSlashSelect(cmd)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left hover:bg-bg-sunken transition-colors\"\n >\n <span className=\"font-mono text-xs text-text-primary\">{cmd.command}</span>\n {cmd.args && <span className=\"text-text-tertiary text-xs\">{cmd.args}</span>}\n <span className=\"text-text-secondary text-xs ml-auto\">{cmd.description}</span>\n </button>\n ))}\n </div>\n )}\n\n {/* Attached context chips (backend prompts/contexts + Files-module files\n materialised on the agent). Sent to the agent as contexts[] on send. */}\n {(sessionState?.contexts?.length ?? 0) > 0 && (\n <div\n className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\"\n data-testid=\"chat-context-chips\"\n >\n {sessionState?.contexts.map((ctx) => (\n <div\n key={ctx.id}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n title={ctx.path ?? ctx.label}\n >\n {ctx.kind === 'file' ? (\n <FolderOpen className=\"size-3 flex-shrink-0\" />\n ) : ctx.kind === 'prompt' ? (\n <Sparkles className=\"size-3 flex-shrink-0\" />\n ) : (\n <FileText className=\"size-3 flex-shrink-0\" />\n )}\n <span className=\"truncate max-w-[140px]\">{ctx.label}</span>\n <button\n type=\"button\"\n onClick={() => removeSessionContext(sessionId, ctx.id)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n aria-label=\"Remove context\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* File attachment preview row */}\n {pendingFiles.length > 0 && (\n <div className=\"flex items-center gap-2 px-3 pt-2 overflow-x-auto\">\n {pendingFiles.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className=\"flex items-center gap-1.5 px-2 py-1 rounded-md bg-bg-elevated border border-border-default text-xs text-text-secondary\"\n >\n <span className=\"truncate max-w-[120px]\">{file.name}</span>\n <button\n type=\"button\"\n onClick={() => removeFile(index)}\n className=\"p-0.5 rounded hover:bg-bg-sunken transition-colors flex-shrink-0\"\n >\n <X className=\"size-3\" />\n </button>\n </div>\n ))}\n </div>\n )}\n\n {/* Toolbar row */}\n <div className=\"flex flex-wrap items-center gap-1 px-3 pt-2 pb-1 overflow-x-auto\">\n <SdkSelector\n sdk={sessionState.sdk}\n mode={sessionState.mode}\n providers={providers}\n onSdkChange={(sdk) => {\n setSessionSdk(sessionId, sdk);\n void resolveProviderDefaultModel(\n agentRef,\n sdk,\n sessionState.model ?? GENERIC_MODEL_FALLBACK\n )\n .then((nextModel) => setSessionModel(sessionId, nextModel))\n .catch(() =>\n setSessionModel(sessionId, sessionState.model ?? GENERIC_MODEL_FALLBACK)\n );\n }}\n onModeChange={(mode) => setSessionMode(sessionId, mode)}\n />\n <ModelSelector\n value={sessionState.model}\n onChange={(model) => setSessionModel(sessionId, model)}\n provider={sessionState.sdk}\n agentId={agentId}\n />\n <AutonomySelector\n value={sessionState.permissionMode}\n mode={sessionState.mode}\n onChange={(permissionMode) => setSessionPermissionMode(sessionId, permissionMode)}\n />\n <McpServerSelector\n selected={sessionState.mcpServers}\n available={mcpServers}\n onChange={() => {\n // Update via store -- MCP servers are part of session state\n // For now we store them directly\n }}\n />\n <ContextLevelToggle\n agentId=\"\"\n sessionId={sessionId}\n contextLevel={sessionState.contextLevel}\n rootPath={sessionState.rootPath}\n onChange={(level, rootPath, vibeId) => {\n setSessionContextLevel(sessionId, level);\n setSessionRootPath(sessionId, rootPath ?? null);\n setSessionVibe(sessionId, vibeId ?? null, rootPath ?? null);\n }}\n vibes={vibes.map((v) => ({ id: v.id, name: v.name, path: v.path }))}\n />\n\n <div className=\"flex-1\" />\n\n {/* Show Thinking toggle */}\n <button\n type=\"button\"\n onClick={() => toggleThinking(sessionId)}\n className={`p-1.5 rounded text-xs font-medium transition-colors ${\n sessionState.showThinking\n ? 'bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'text-text-tertiary hover:text-text-secondary'\n }`}\n title={\n sessionState.showThinking\n ? tr('vibecontrols.agentManager.inputArea.hideThinking', 'Hide thinking')\n : tr('vibecontrols.agentManager.inputArea.showThinking', 'Show thinking')\n }\n >\n Think\n </button>\n {/* Context history limit */}\n <button\n type=\"button\"\n onClick={() => {\n const val = window.prompt(\n 'Context history limit (messages sent with each prompt):',\n String(sessionState.contextHistoryLimit)\n );\n if (val !== null) {\n const num = parseInt(val, 10);\n if (!isNaN(num) && num >= 0) {\n const store = useAgentManagerStore.getState();\n const s = store.sessionStates[sessionId];\n if (s) {\n useAgentManagerStore.setState((prev) => ({\n sessionStates: {\n ...prev.sessionStates,\n [sessionId]: { ...s, contextHistoryLimit: num },\n },\n }));\n }\n }\n }\n }}\n className=\"p-1.5 rounded text-[10px] font-mono text-text-tertiary hover:text-text-secondary transition-colors\"\n title={`Context history: last ${sessionState.contextHistoryLimit} messages sent with each prompt`}\n >\n H:{sessionState.contextHistoryLimit}\n </button>\n <VoiceToggle\n enabled={sessionState.voiceEnabled}\n onToggle={() => {\n toggleVoice(sessionId);\n if (!sessionState.voiceEnabled) startListening();\n else stopListening();\n }}\n isListening={isListening}\n />\n <FileAttachButton onFileSelect={handleFileSelect} />\n\n {/* Insert a backend prompt (rendered) into the composer, or attach a\n shared AiContext to the session. */}\n <ChatInsertPicker\n sessionId={sessionId}\n vibeId={sessionState?.vibeId}\n onInsertText={(t) => setText((prev) => (prev ? `${prev}\\n${t}` : t))}\n />\n\n {/* Attach a Files-module file: the agent fetches + materialises it on\n the server and its path becomes conversation context. */}\n <button\n type=\"button\"\n onClick={() => setFilePickerOpen(true)}\n className=\"inline-flex items-center gap-1 px-2 py-1 rounded-md text-xs text-text-secondary hover:bg-bg-sunken transition-colors\"\n title=\"Add a file from the Files module as context\"\n data-testid=\"chat-add-from-files\"\n >\n <FolderOpen className=\"size-4\" />\n <span className=\"hidden sm:inline\">Files</span>\n </button>\n </div>\n\n {/* Textarea + send/cancel */}\n <div className=\"flex items-end gap-2 px-3 pb-3 pt-1\">\n <textarea\n aria-label=\"control\"\n ref={textareaRef}\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={tr(\n 'vibecontrols.agentManager.inputArea.placeholder',\n 'Type a message or / for commands... (Enter to send)'\n )}\n rows={1}\n className=\"flex-1 resize-none rounded-lg border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-tertiary focus:outline-none focus:border-border-strong transition-colors\"\n disabled={isStreaming}\n />\n {isStreaming ? (\n <button\n type=\"button\"\n onClick={handleCancel}\n className=\"flex-shrink-0 p-2 rounded-lg bg-status-error-bg-subtle text-status-error-text hover:opacity-90 transition-opacity\"\n title={tr('vibecontrols.agentManager.inputArea.cancel', 'Cancel')}\n >\n <Square className=\"size-4\" />\n </button>\n ) : (\n <div className=\"flex items-end flex-shrink-0 relative\" ref={scheduleMenuRef}>\n <button\n type=\"button\"\n onClick={handleSend}\n disabled={!canSend}\n className=\"p-2 rounded-l-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.send', 'Send (Enter)')}\n >\n <ArrowUp className=\"size-4\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setShowScheduleMenu(!showScheduleMenu)}\n disabled={!canSend}\n className=\"ml-1 p-2 rounded-r-lg border-l border-action-primary-text/20 bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n title={tr('vibecontrols.agentManager.inputArea.scheduleSend', 'Schedule send')}\n >\n <ChevronDown className=\"size-3\" />\n </button>\n\n {/* Schedule dropdown */}\n {showScheduleMenu && (\n <div className=\"absolute bottom-full right-0 mb-1 w-56 bg-bg-surface border border-border-default rounded-md shadow-lg py-1 z-50\">\n {!showSchedulePopup ? (\n <button\n type=\"button\"\n onClick={() => setShowSchedulePopup(true)}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-left text-xs text-text-primary hover:bg-bg-sunken transition-colors\"\n >\n <Clock className=\"size-3.5 text-text-secondary\" />\n {tr(\n 'vibecontrols.agentManager.inputArea.scheduleSendEllipsis',\n 'Schedule Send...'\n )}\n </button>\n ) : (\n <div className=\"px-3 py-2 space-y-2\">\n <label className=\"block text-[11px] font-medium text-text-secondary\">\n {tr('vibecontrols.agentManager.inputArea.sendAt', 'Send at:')}\n </label>\n <input\n aria-label=\"control\"\n type=\"datetime-local\"\n value={scheduleDateTime}\n onChange={(e) => setScheduleDateTime(e.target.value)}\n className=\"w-full px-2 py-1 text-xs rounded border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:border-border-strong\"\n />\n <button\n type=\"button\"\n onClick={() => void handleScheduleSend()}\n disabled={!scheduleDateTime || !agentId}\n className=\"w-full px-2 py-1.5 text-xs font-medium rounded bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-40 disabled:cursor-not-allowed transition-colors\"\n >\n {tr('vibecontrols.agentManager.inputArea.schedule', 'Schedule')}\n </button>\n </div>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Files-module picker → agent materialises the file → session context. */}\n <FilePickerModal\n isOpen={filePickerOpen}\n onClose={() => setFilePickerOpen(false)}\n agent={agentRef}\n sessionId={sessionId}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -73,7 +73,7 @@ function d({ sidebar: d, children: f, detailPanel: p }) {
73
73
  })] })
74
74
  }),
75
75
  /* @__PURE__ */ l("main", {
76
- className: "flex flex-col flex-1 min-w-0 overflow-hidden bg-bg-primary",
76
+ className: "flex flex-col flex-1 min-w-0 overflow-hidden bg-bg-surface",
77
77
  children: f
78
78
  }),
79
79
  !h && p && !v && /* @__PURE__ */ l("div", {