@burdenoff/microfe-vibecontrols 2026.623.2 → 2026.623.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/actions/ActionTypeBadge.js +1 -1
- package/dist/components/actions/ActionTypeBadge.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerChatPane.js +1 -1
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
- package/dist/components/agent-manager/BridleConfigPanel.js +2 -2
- package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/ProfilesPanel.js +1 -1
- package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionLogsPanel.js +2 -2
- package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +1 -1
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AIOverviewTab.js +1 -1
- package/dist/components/ai/AIOverviewTab.js.map +1 -1
- package/dist/components/ai/AIPromptsTab.js +1 -1
- package/dist/components/ai/AIPromptsTab.js.map +1 -1
- package/dist/components/ai/AIQueueTab.js +1 -1
- package/dist/components/ai/AIQueueTab.js.map +1 -1
- package/dist/components/ai/AISessionsTab.js +1 -1
- package/dist/components/ai/AISessionsTab.js.map +1 -1
- package/dist/components/audit/AuditLogTable.js +1 -1
- package/dist/components/audit/AuditLogTable.js.map +1 -1
- package/dist/components/docs/DocsPageTree.js +1 -1
- package/dist/components/docs/DocsPageTree.js.map +1 -1
- package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
- package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
- package/dist/components/graph/MeshDeployWizard.js +3 -3
- package/dist/components/graph/MeshDeployWizard.js.map +1 -1
- package/dist/components/graph/MeshRequestPanel.js +2 -2
- package/dist/components/graph/MeshRequestPanel.js.map +1 -1
- package/dist/components/notes/NoteCard.js +1 -1
- package/dist/components/notes/NoteCard.js.map +1 -1
- package/dist/components/notes/NoteEditor.js +1 -1
- package/dist/components/notes/NoteEditor.js.map +1 -1
- package/dist/components/notes/NoteList.js +1 -1
- package/dist/components/notes/NoteList.js.map +1 -1
- package/dist/components/shared/AgentSetupBanner.js +3 -3
- package/dist/components/shared/AgentSetupBanner.js.map +1 -1
- package/dist/components/templates/TemplateCard.js +1 -1
- package/dist/components/templates/TemplateCard.js.map +1 -1
- package/dist/components/vibecalendar/types.js +1 -1
- package/dist/components/vibecalendar/types.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonForm.js +1 -1
- package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckExecutionLog.js +2 -2
- package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckForm.js +1 -1
- package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckGrid.js +1 -1
- package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
- package/dist/pages/AgentsPage.js +2 -2
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +1 -1
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +1 -1
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/OverviewPage.js +10 -10
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/PluginsCatalogPage.js +1 -1
- package/dist/pages/PluginsCatalogPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +3 -3
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/SharedSessionPage.js +2 -2
- package/dist/pages/SharedSessionPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +2 -2
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +2 -2
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/VibesPage.js +2 -2
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/WebhooksPage.js +2 -2
- package/dist/pages/WebhooksPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +2 -2
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIContextsTab.js","names":[],"sources":["../../../src/components/ai/AIContextsTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { Plus, X, FileText, Trash2, Pencil } from 'lucide-react';\nimport {\n Card,\n LoadingState,\n ErrorState,\n EmptyState,\n ConfirmDialog,\n SelectionCheckbox,\n} from '@/components/shared';\nimport { EntityShareButton } from '@/components/sharing';\nimport type { AIContext, AgentRef } from '@/services/aiApi';\nimport { fetchContexts, createContext, updateContext, deleteContext } from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIContextsTabProps {\n agent: AgentRef;\n}\n\nconst contextTypes = [\n { value: 'all', label: 'All Types' },\n { value: 'system', label: 'System' },\n { value: 'user', label: 'User' },\n { value: 'file', label: 'File' },\n { value: 'project', label: 'Project' },\n { value: 'custom', label: 'Custom' },\n];\n\ninterface ContextFormData {\n name: string;\n type: string;\n content: string;\n tags: string[];\n}\n\nconst emptyForm: ContextFormData = { name: '', type: 'custom', content: '', tags: [] };\n\nexport function AIContextsTab({ agent }: AIContextsTabProps) {\n const tr = useTr();\n const [contexts, setContexts] = useState<AIContext[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [typeFilter, setTypeFilter] = useState('all');\n const [showForm, setShowForm] = useState(false);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [formData, setFormData] = useState<ContextFormData>(emptyForm);\n const [tagInput, setTagInput] = useState('');\n const [saving, setSaving] = useState(false);\n const [deleteIds, setDeleteIds] = useState<string[]>([]);\n const [deleting, setDeleting] = useState(false);\n const [selectedContextIds, setSelectedContextIds] = useState<Set<string>>(new Set());\n\n const loadContexts = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const params: Record<string, unknown> = {};\n if (typeFilter !== 'all') params.type = typeFilter;\n const result = await fetchContexts(agent, params);\n setContexts(result);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load contexts');\n } finally {\n setLoading(false);\n }\n }, [agent, typeFilter]);\n\n useEffect(() => {\n loadContexts();\n }, [loadContexts]);\n\n const selectedContexts = useMemo(\n () => contexts.filter((context) => selectedContextIds.has(context.id)),\n [contexts, selectedContextIds]\n );\n const allVisibleSelected =\n contexts.length > 0 && contexts.every((context) => selectedContextIds.has(context.id));\n const partiallySelected =\n contexts.some((context) => selectedContextIds.has(context.id)) && !allVisibleSelected;\n\n const openCreate = () => {\n setEditingId(null);\n setFormData(emptyForm);\n setTagInput('');\n setShowForm(true);\n };\n\n const openEdit = (ctx: AIContext) => {\n setEditingId(ctx.id);\n setFormData({ name: ctx.name, type: ctx.type, content: ctx.content, tags: ctx.tags ?? [] });\n setTagInput('');\n setShowForm(true);\n };\n\n const handleSave = async () => {\n setSaving(true);\n try {\n if (editingId) {\n await updateContext(agent, editingId, formData);\n } else {\n await createContext(agent, formData);\n }\n setShowForm(false);\n await loadContexts();\n } catch (err) {\n console.error('Failed to save context:', err);\n } finally {\n setSaving(false);\n }\n };\n\n const handleDelete = async () => {\n if (deleteIds.length === 0) return;\n setDeleting(true);\n try {\n await Promise.allSettled(deleteIds.map((deleteId) => deleteContext(agent, deleteId)));\n setSelectedContextIds((prev) => {\n const next = new Set(prev);\n deleteIds.forEach((deleteId) => next.delete(deleteId));\n return next;\n });\n setDeleteIds([]);\n await loadContexts();\n } catch (err) {\n console.error('Failed to delete context:', err);\n } finally {\n setDeleting(false);\n }\n };\n\n const addTag = () => {\n const tag = tagInput.trim();\n if (tag && !formData.tags.includes(tag)) {\n setFormData((prev) => ({ ...prev, tags: [...prev.tags, tag] }));\n }\n setTagInput('');\n };\n\n const removeTag = (tag: string) => {\n setFormData((prev) => ({ ...prev, tags: prev.tags.filter((t) => t !== tag) }));\n };\n\n const toggleContextSelection = (contextId: string, checked: boolean) => {\n setSelectedContextIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(contextId);\n } else {\n next.delete(contextId);\n }\n return next;\n });\n };\n\n const toggleAllVisibleContexts = (checked: boolean) => {\n setSelectedContextIds((prev) => {\n const next = new Set(prev);\n contexts.forEach((context) => {\n if (checked) {\n next.add(context.id);\n } else {\n next.delete(context.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedContextIds(new Set());\n\n if (loading)\n return <LoadingState message={tr('vibecontrols.ai.contexts.loading', 'Loading contexts...')} />;\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.contexts.loadFailed', 'Failed to load contexts')}\n message={error}\n onRetry={loadContexts}\n />\n );\n\n return (\n <div className=\"space-y-4\">\n {/* Toolbar */}\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2\">\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value)}\n className=\"px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {contextTypes.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n <div className=\"flex-1\" />\n <button\n type=\"button\"\n onClick={openCreate}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors text-sm\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.contexts.newContext', 'New Context')}\n </button>\n </div>\n\n {contexts.length > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleContexts}\n ariaLabel=\"Select all visible contexts\"\n />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('vibecontrols.ai.contexts.selectAllVisible', 'Select all visible')}\n </span>\n </div>\n {selectedContextIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('vibecontrols.ai.contexts.clearSelection', 'Clear selection')}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedContextIds.size} {tr('vibecontrols.ai.contexts.selected', 'selected')}\n </span>\n <button\n type=\"button\"\n onClick={() => setDeleteIds(selectedContexts.map((context) => context.id))}\n disabled={selectedContexts.length === 0}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr('vibecontrols.ai.contexts.deleteSelected', 'Delete Selected')}\n {selectedContexts.length > 0 ? ` (${selectedContexts.length})` : ''}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Context List */}\n {contexts.length === 0 ? (\n <EmptyState\n icon={<FileText className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.contexts.emptyTitle', 'No contexts yet')}\n description={tr(\n 'vibecontrols.ai.contexts.emptyDescription',\n 'Create contexts to provide additional information to your AI sessions'\n )}\n action={\n <button\n type=\"button\"\n onClick={openCreate}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.contexts.newContext', 'New Context')}\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {contexts.map((ctx) => (\n <Card\n key={ctx.id}\n className={`p-4 ${selectedContextIds.has(ctx.id) ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25' : ''}`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedContextIds.has(ctx.id)}\n onChange={(checked) => toggleContextSelection(ctx.id, checked)}\n ariaLabel={`Select context ${ctx.name}`}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <h4 className=\"font-semibold text-text-primary truncate\">{ctx.name}</h4>\n <span className=\"px-1.5 py-0.5 text-xs bg-[var(--color-accent-soft)] text-action-primary-bg rounded\">\n {ctx.type}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-1 flex-shrink-0\">\n <button\n type=\"button\"\n onClick={() => openEdit(ctx)}\n className=\"p-1.5 hover:bg-bg-sunken rounded-md transition-colors\"\n title=\"Edit\"\n >\n <Pencil className=\"size-3.5 text-text-secondary\" />\n </button>\n <EntityShareButton\n entity=\"aicontext\"\n resource={{ id: ctx.id, name: ctx.name }}\n label={tr('vibecontrols.ai.contexts.share', 'Share')}\n />\n <button\n type=\"button\"\n onClick={() => setDeleteIds([ctx.id])}\n className=\"p-1.5 hover:bg-status-error-bg rounded-md transition-colors\"\n title=\"Delete\"\n >\n <Trash2 className=\"size-3.5 text-status-error-text\" />\n </button>\n </div>\n </div>\n <pre className=\"mt-2 text-xs text-text-secondary bg-bg-sunken rounded p-2 max-h-20 overflow-auto whitespace-pre-wrap\">\n {ctx.content}\n </pre>\n {ctx.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {ctx.tags.map((tag) => (\n <span\n key={tag}\n className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n </Card>\n ))}\n </div>\n )}\n\n {/* Create/Edit Dialog */}\n {showForm && (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => setShowForm(false))();\n }\n }}\n className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\"\n onClick={() => setShowForm(false)}\n >\n <div\n className=\"bg-bg-surface border border-border-default rounded-lg shadow-xl w-full max-w-lg max-h-[90vh] overflow-y-auto p-6\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {editingId\n ? tr('vibecontrols.ai.contexts.editContext', 'Edit Context')\n : tr('vibecontrols.ai.contexts.newContext', 'New Context')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowForm(false)}\n className=\"p-1 hover:bg-bg-sunken rounded-md\"\n >\n <X className=\"size-4 text-text-secondary\" />\n </button>\n </div>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.name', 'Name')}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong\"\n placeholder={tr('vibecontrols.ai.contexts.namePlaceholder', 'Context name')}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.type', 'Type')}\n </label>\n <select\n value={formData.type}\n onChange={(e) => setFormData({ ...formData, type: e.target.value })}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {contextTypes\n .filter((t) => t.value !== 'all')\n .map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.content', 'Content')}\n </label>\n <textarea\n aria-label=\"control\"\n value={formData.content}\n onChange={(e) => setFormData({ ...formData, content: e.target.value })}\n rows={8}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm font-mono focus:outline-none focus:border-border-strong\"\n placeholder={tr(\n 'vibecontrols.ai.contexts.contentPlaceholder',\n 'Context content...'\n )}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.tags', 'Tags')}\n </label>\n <div className=\"flex flex-wrap gap-1 mb-2\">\n {formData.tags.map((tag) => (\n <span\n key={tag}\n className=\"flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-primary rounded\"\n >\n {tag}\n <button type=\"button\" onClick={() => removeTag(tag)}>\n <X className=\"size-3 text-text-secondary hover:text-status-error-text\" />\n </button>\n </span>\n ))}\n </div>\n <div className=\"flex gap-2\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={tagInput}\n onChange={(e) => setTagInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n addTag();\n }\n }}\n className=\"flex-1 px-3 py-1.5 bg-bg-sunken border border-border-default rounded text-sm text-text-primary focus:outline-none focus:border-border-strong\"\n placeholder={tr('vibecontrols.ai.contexts.addTagPlaceholder', 'Add a tag...')}\n />\n <button\n type=\"button\"\n onClick={addTag}\n className=\"px-3 py-1.5 text-xs bg-bg-sunken border border-border-default rounded hover:bg-bg-surface transition-colors\"\n >\n {tr('vibecontrols.ai.contexts.add', 'Add')}\n </button>\n </div>\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowForm(false)}\n className=\"px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n {tr('vibecontrols.ai.contexts.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving || !formData.name || !formData.content}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {saving\n ? tr('vibecontrols.ai.contexts.saving', 'Saving...')\n : editingId\n ? tr('vibecontrols.ai.contexts.update', 'Update')\n : tr('vibecontrols.ai.contexts.create', 'Create')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Delete Confirmation */}\n <ConfirmDialog\n isOpen={deleteIds.length > 0}\n title={deleteIds.length > 1 ? 'Delete Contexts' : 'Delete Context'}\n message={\n deleteIds.length > 1\n ? `Are you sure you want to delete ${deleteIds.length} selected contexts? This action cannot be undone.`\n : 'Are you sure you want to delete this context? This action cannot be undone.'\n }\n confirmLabel={deleting ? 'Deleting...' : 'Delete'}\n variant=\"danger\"\n onConfirm={handleDelete}\n onClose={() => setDeleteIds([])}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AIContextsTab.js","names":[],"sources":["../../../src/components/ai/AIContextsTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { Plus, X, FileText, Trash2, Pencil } from 'lucide-react';\nimport {\n Card,\n LoadingState,\n ErrorState,\n EmptyState,\n ConfirmDialog,\n SelectionCheckbox,\n} from '@/components/shared';\nimport { EntityShareButton } from '@/components/sharing';\nimport type { AIContext, AgentRef } from '@/services/aiApi';\nimport { fetchContexts, createContext, updateContext, deleteContext } from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIContextsTabProps {\n agent: AgentRef;\n}\n\nconst contextTypes = [\n { value: 'all', label: 'All Types' },\n { value: 'system', label: 'System' },\n { value: 'user', label: 'User' },\n { value: 'file', label: 'File' },\n { value: 'project', label: 'Project' },\n { value: 'custom', label: 'Custom' },\n];\n\ninterface ContextFormData {\n name: string;\n type: string;\n content: string;\n tags: string[];\n}\n\nconst emptyForm: ContextFormData = { name: '', type: 'custom', content: '', tags: [] };\n\nexport function AIContextsTab({ agent }: AIContextsTabProps) {\n const tr = useTr();\n const [contexts, setContexts] = useState<AIContext[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [typeFilter, setTypeFilter] = useState('all');\n const [showForm, setShowForm] = useState(false);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [formData, setFormData] = useState<ContextFormData>(emptyForm);\n const [tagInput, setTagInput] = useState('');\n const [saving, setSaving] = useState(false);\n const [deleteIds, setDeleteIds] = useState<string[]>([]);\n const [deleting, setDeleting] = useState(false);\n const [selectedContextIds, setSelectedContextIds] = useState<Set<string>>(new Set());\n\n const loadContexts = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const params: Record<string, unknown> = {};\n if (typeFilter !== 'all') params.type = typeFilter;\n const result = await fetchContexts(agent, params);\n setContexts(result);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load contexts');\n } finally {\n setLoading(false);\n }\n }, [agent, typeFilter]);\n\n useEffect(() => {\n loadContexts();\n }, [loadContexts]);\n\n const selectedContexts = useMemo(\n () => contexts.filter((context) => selectedContextIds.has(context.id)),\n [contexts, selectedContextIds]\n );\n const allVisibleSelected =\n contexts.length > 0 && contexts.every((context) => selectedContextIds.has(context.id));\n const partiallySelected =\n contexts.some((context) => selectedContextIds.has(context.id)) && !allVisibleSelected;\n\n const openCreate = () => {\n setEditingId(null);\n setFormData(emptyForm);\n setTagInput('');\n setShowForm(true);\n };\n\n const openEdit = (ctx: AIContext) => {\n setEditingId(ctx.id);\n setFormData({ name: ctx.name, type: ctx.type, content: ctx.content, tags: ctx.tags ?? [] });\n setTagInput('');\n setShowForm(true);\n };\n\n const handleSave = async () => {\n setSaving(true);\n try {\n if (editingId) {\n await updateContext(agent, editingId, formData);\n } else {\n await createContext(agent, formData);\n }\n setShowForm(false);\n await loadContexts();\n } catch (err) {\n console.error('Failed to save context:', err);\n } finally {\n setSaving(false);\n }\n };\n\n const handleDelete = async () => {\n if (deleteIds.length === 0) return;\n setDeleting(true);\n try {\n await Promise.allSettled(deleteIds.map((deleteId) => deleteContext(agent, deleteId)));\n setSelectedContextIds((prev) => {\n const next = new Set(prev);\n deleteIds.forEach((deleteId) => next.delete(deleteId));\n return next;\n });\n setDeleteIds([]);\n await loadContexts();\n } catch (err) {\n console.error('Failed to delete context:', err);\n } finally {\n setDeleting(false);\n }\n };\n\n const addTag = () => {\n const tag = tagInput.trim();\n if (tag && !formData.tags.includes(tag)) {\n setFormData((prev) => ({ ...prev, tags: [...prev.tags, tag] }));\n }\n setTagInput('');\n };\n\n const removeTag = (tag: string) => {\n setFormData((prev) => ({ ...prev, tags: prev.tags.filter((t) => t !== tag) }));\n };\n\n const toggleContextSelection = (contextId: string, checked: boolean) => {\n setSelectedContextIds((prev) => {\n const next = new Set(prev);\n if (checked) {\n next.add(contextId);\n } else {\n next.delete(contextId);\n }\n return next;\n });\n };\n\n const toggleAllVisibleContexts = (checked: boolean) => {\n setSelectedContextIds((prev) => {\n const next = new Set(prev);\n contexts.forEach((context) => {\n if (checked) {\n next.add(context.id);\n } else {\n next.delete(context.id);\n }\n });\n return next;\n });\n };\n\n const clearSelection = () => setSelectedContextIds(new Set());\n\n if (loading)\n return <LoadingState message={tr('vibecontrols.ai.contexts.loading', 'Loading contexts...')} />;\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.contexts.loadFailed', 'Failed to load contexts')}\n message={error}\n onRetry={loadContexts}\n />\n );\n\n return (\n <div className=\"space-y-4\">\n {/* Toolbar */}\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-center gap-2\">\n <select\n value={typeFilter}\n onChange={(e) => setTypeFilter(e.target.value)}\n className=\"px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {contextTypes.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n <div className=\"flex-1\" />\n <button\n type=\"button\"\n onClick={openCreate}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors text-sm\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.contexts.newContext', 'New Context')}\n </button>\n </div>\n\n {contexts.length > 0 && (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4\">\n <div className=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"flex items-center gap-2\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={toggleAllVisibleContexts}\n ariaLabel=\"Select all visible contexts\"\n />\n <span className=\"text-sm font-medium text-text-primary\">\n {tr('vibecontrols.ai.contexts.selectAllVisible', 'Select all visible')}\n </span>\n </div>\n {selectedContextIds.size > 0 && (\n <button\n type=\"button\"\n onClick={clearSelection}\n className=\"text-sm text-text-secondary hover:text-text-primary\"\n >\n {tr('vibecontrols.ai.contexts.clearSelection', 'Clear selection')}\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"rounded-full bg-bg-sunken px-3 py-1 text-sm font-medium text-text-secondary\">\n {selectedContextIds.size} {tr('vibecontrols.ai.contexts.selected', 'selected')}\n </span>\n <button\n type=\"button\"\n onClick={() => setDeleteIds(selectedContexts.map((context) => context.id))}\n disabled={selectedContexts.length === 0}\n className=\"rounded-md border border-status-error-border px-3 py-2 text-sm font-medium text-status-error-text hover:bg-status-error-bg disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {tr('vibecontrols.ai.contexts.deleteSelected', 'Delete Selected')}\n {selectedContexts.length > 0 ? ` (${selectedContexts.length})` : ''}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Context List */}\n {contexts.length === 0 ? (\n <EmptyState\n icon={<FileText className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.contexts.emptyTitle', 'No contexts yet')}\n description={tr(\n 'vibecontrols.ai.contexts.emptyDescription',\n 'Create contexts to provide additional information to your AI sessions'\n )}\n action={\n <button\n type=\"button\"\n onClick={openCreate}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.contexts.newContext', 'New Context')}\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n {contexts.map((ctx) => (\n <Card\n key={ctx.id}\n className={`p-4 ${selectedContextIds.has(ctx.id) ? 'border-action-primary-bg ring-1 ring-action-primary-bg/25' : ''}`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-3 min-w-0 flex-1\">\n <div onClick={(event) => event.stopPropagation()}>\n <SelectionCheckbox\n checked={selectedContextIds.has(ctx.id)}\n onChange={(checked) => toggleContextSelection(ctx.id, checked)}\n ariaLabel={`Select context ${ctx.name}`}\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <h4 className=\"font-semibold text-text-primary truncate\">{ctx.name}</h4>\n <span className=\"px-1.5 py-0.5 text-xs bg-[var(--color-accent-soft)] text-text-primary rounded\">\n {ctx.type}\n </span>\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-1 flex-shrink-0\">\n <button\n type=\"button\"\n onClick={() => openEdit(ctx)}\n className=\"p-1.5 hover:bg-bg-sunken rounded-md transition-colors\"\n title=\"Edit\"\n >\n <Pencil className=\"size-3.5 text-text-secondary\" />\n </button>\n <EntityShareButton\n entity=\"aicontext\"\n resource={{ id: ctx.id, name: ctx.name }}\n label={tr('vibecontrols.ai.contexts.share', 'Share')}\n />\n <button\n type=\"button\"\n onClick={() => setDeleteIds([ctx.id])}\n className=\"p-1.5 hover:bg-status-error-bg rounded-md transition-colors\"\n title=\"Delete\"\n >\n <Trash2 className=\"size-3.5 text-status-error-text\" />\n </button>\n </div>\n </div>\n <pre className=\"mt-2 text-xs text-text-secondary bg-bg-sunken rounded p-2 max-h-20 overflow-auto whitespace-pre-wrap\">\n {ctx.content}\n </pre>\n {ctx.tags.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {ctx.tags.map((tag) => (\n <span\n key={tag}\n className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n </Card>\n ))}\n </div>\n )}\n\n {/* Create/Edit Dialog */}\n {showForm && (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => setShowForm(false))();\n }\n }}\n className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\"\n onClick={() => setShowForm(false)}\n >\n <div\n className=\"bg-bg-surface border border-border-default rounded-lg shadow-xl w-full max-w-lg max-h-[90vh] overflow-y-auto p-6\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {editingId\n ? tr('vibecontrols.ai.contexts.editContext', 'Edit Context')\n : tr('vibecontrols.ai.contexts.newContext', 'New Context')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowForm(false)}\n className=\"p-1 hover:bg-bg-sunken rounded-md\"\n >\n <X className=\"size-4 text-text-secondary\" />\n </button>\n </div>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.name', 'Name')}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={formData.name}\n onChange={(e) => setFormData({ ...formData, name: e.target.value })}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong\"\n placeholder={tr('vibecontrols.ai.contexts.namePlaceholder', 'Context name')}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.type', 'Type')}\n </label>\n <select\n value={formData.type}\n onChange={(e) => setFormData({ ...formData, type: e.target.value })}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {contextTypes\n .filter((t) => t.value !== 'all')\n .map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.content', 'Content')}\n </label>\n <textarea\n aria-label=\"control\"\n value={formData.content}\n onChange={(e) => setFormData({ ...formData, content: e.target.value })}\n rows={8}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm font-mono focus:outline-none focus:border-border-strong\"\n placeholder={tr(\n 'vibecontrols.ai.contexts.contentPlaceholder',\n 'Context content...'\n )}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.contexts.tags', 'Tags')}\n </label>\n <div className=\"flex flex-wrap gap-1 mb-2\">\n {formData.tags.map((tag) => (\n <span\n key={tag}\n className=\"flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-primary rounded\"\n >\n {tag}\n <button type=\"button\" onClick={() => removeTag(tag)}>\n <X className=\"size-3 text-text-secondary hover:text-status-error-text\" />\n </button>\n </span>\n ))}\n </div>\n <div className=\"flex gap-2\">\n <input\n aria-label=\"control\"\n type=\"text\"\n value={tagInput}\n onChange={(e) => setTagInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n addTag();\n }\n }}\n className=\"flex-1 px-3 py-1.5 bg-bg-sunken border border-border-default rounded text-sm text-text-primary focus:outline-none focus:border-border-strong\"\n placeholder={tr('vibecontrols.ai.contexts.addTagPlaceholder', 'Add a tag...')}\n />\n <button\n type=\"button\"\n onClick={addTag}\n className=\"px-3 py-1.5 text-xs bg-bg-sunken border border-border-default rounded hover:bg-bg-surface transition-colors\"\n >\n {tr('vibecontrols.ai.contexts.add', 'Add')}\n </button>\n </div>\n </div>\n </div>\n\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowForm(false)}\n className=\"px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n {tr('vibecontrols.ai.contexts.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={saving || !formData.name || !formData.content}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {saving\n ? tr('vibecontrols.ai.contexts.saving', 'Saving...')\n : editingId\n ? tr('vibecontrols.ai.contexts.update', 'Update')\n : tr('vibecontrols.ai.contexts.create', 'Create')}\n </button>\n </div>\n </div>\n </div>\n )}\n\n {/* Delete Confirmation */}\n <ConfirmDialog\n isOpen={deleteIds.length > 0}\n title={deleteIds.length > 1 ? 'Delete Contexts' : 'Delete Context'}\n message={\n deleteIds.length > 1\n ? `Are you sure you want to delete ${deleteIds.length} selected contexts? This action cannot be undone.`\n : 'Are you sure you want to delete this context? This action cannot be undone.'\n }\n confirmLabel={deleting ? 'Deleting...' : 'Delete'}\n variant=\"danger\"\n onConfirm={handleDelete}\n onClose={() => setDeleteIds([])}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@ import { MotionItem as g, MotionList as _ } from "@burdenoff/fe-libs/shared/moti
|
|
|
13
13
|
var v = {
|
|
14
14
|
active: "bg-status-success-bg-subtle text-status-success-text",
|
|
15
15
|
idle: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
16
|
-
processing: "bg-[var(--color-accent-soft)] text-
|
|
16
|
+
processing: "bg-[var(--color-accent-soft)] text-text-primary",
|
|
17
17
|
error: "bg-status-error-bg-subtle text-status-error-text",
|
|
18
18
|
terminated: "bg-bg-sunken text-text-secondary"
|
|
19
19
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIOverviewTab.js","names":[],"sources":["../../../src/components/ai/AIOverviewTab.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { Activity, Zap, Clock, MessageSquare } from 'lucide-react';\nimport { StatCard, Card, LoadingState, ErrorState } from '@/components/shared';\nimport { MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport type { AIStatsOverview, AISession, AIDispatch, AgentRef } from '@/services/aiApi';\nimport { fetchStatsOverview, fetchSessions, fetchDispatchHistory } from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIOverviewTabProps {\n agent: AgentRef;\n onNavigateToSession?: (sessionId: string) => void;\n}\n\nconst statusColors: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n idle: 'bg-status-warning-bg-subtle text-status-warning-text',\n processing: 'bg-[var(--color-accent-soft)] text-action-primary-bg',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n terminated: 'bg-bg-sunken text-text-secondary',\n};\n\nexport function AIOverviewTab({ agent, onNavigateToSession }: AIOverviewTabProps) {\n const tr = useTr();\n const [stats, setStats] = useState<AIStatsOverview | null>(null);\n const [recentSessions, setRecentSessions] = useState<AISession[]>([]);\n const [recentPrompts, setRecentPrompts] = useState<AIDispatch[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n async function load() {\n setLoading(true);\n setError(null);\n try {\n const [s, sess, hist] = await Promise.all([\n fetchStatsOverview(agent),\n fetchSessions(agent, { limit: 5, sort: 'updatedAt:desc' }),\n fetchDispatchHistory(agent, { limit: 5 }),\n ]);\n if (cancelled) return;\n setStats(s);\n setRecentSessions(sess);\n setRecentPrompts(hist);\n } catch (err) {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load overview');\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n load();\n return () => {\n cancelled = true;\n };\n }, [agent.id, agent.profile]);\n\n if (loading)\n return (\n <LoadingState message={tr('vibecontrols.ai.overview.loading', 'Loading AI overview...')} />\n );\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.overview.loadFailed', 'Failed to load overview')}\n message={error}\n />\n );\n\n return (\n <div className=\"space-y-6\">\n {/* Quick Stats */}\n <MotionList stagger={0.04} className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.activeSessions', 'Active Sessions')}\n value={stats?.activeSessions ?? 0}\n icon={<Activity className=\"size-5\" />}\n variant=\"success\"\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.totalTokens', 'Total Tokens')}\n value={stats?.totalTokens?.toLocaleString() ?? '0'}\n subtitle={`In: ${stats?.inputTokens?.toLocaleString() ?? 0} / Out: ${stats?.outputTokens?.toLocaleString() ?? 0}`}\n icon={<Zap className=\"size-5\" />}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.queuedPrompts', 'Queued Prompts')}\n value={stats?.queuedPrompts ?? 0}\n icon={<Clock className=\"size-5\" />}\n variant={stats?.queuedPrompts && stats.queuedPrompts > 0 ? 'warning' : 'default'}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.totalSessions', 'Total Sessions')}\n value={stats?.totalSessions ?? 0}\n icon={<MessageSquare className=\"size-5\" />}\n />\n </MotionItem>\n </MotionList>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Recent Sessions */}\n <Card className=\"p-0\">\n <div className=\"px-4 py-3 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.overview.recentSessions', 'Recent Sessions')}\n </h3>\n </div>\n <div className=\"divide-y divide-border-default\">\n {recentSessions.length === 0 ? (\n <p className=\"px-4 py-6 text-sm text-text-secondary text-center\">\n {tr('vibecontrols.ai.overview.noSessions', 'No sessions yet')}\n </p>\n ) : (\n recentSessions.map((session) => (\n <button\n type=\"button\"\n key={session.id}\n onClick={() => onNavigateToSession?.(session.id)}\n className=\"flex w-full flex-col items-start gap-2 px-4 py-3 text-left transition-colors hover:bg-bg-sunken sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-medium text-text-primary text-sm truncate\">\n {session.name}\n </div>\n <div className=\"text-xs text-text-secondary\">{session.agentType}</div>\n </div>\n <span\n className={`rounded-full px-2 py-0.5 text-xs font-medium ${statusColors[session.status] ?? 'bg-bg-sunken text-text-secondary'}`}\n >\n {session.status}\n </span>\n </button>\n ))\n )}\n </div>\n </Card>\n\n {/* Recent Prompts */}\n <Card className=\"p-0\">\n <div className=\"px-4 py-3 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.overview.recentPrompts', 'Recent Prompts')}\n </h3>\n </div>\n <div className=\"divide-y divide-border-default\">\n {recentPrompts.length === 0 ? (\n <p className=\"px-4 py-6 text-sm text-text-secondary text-center\">\n {tr('vibecontrols.ai.overview.noPrompts', 'No prompts dispatched yet')}\n </p>\n ) : (\n recentPrompts.map((dispatch) => (\n <div key={dispatch.id} className=\"px-4 py-3\">\n <div className=\"text-sm text-text-primary line-clamp-2\">{dispatch.prompt}</div>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span>{dispatch.status}</span>\n {dispatch.createdAt && (\n <span>{new Date(dispatch.createdAt).toLocaleString()}</span>\n )}\n </div>\n </div>\n ))\n )}\n </div>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAaA,IAAM,IAAuC;CAC3C,QAAQ;CACR,MAAM;CACN,YAAY;CACZ,OAAO;CACP,YAAY;CACb;AAED,SAAgB,EAAc,EAAE,UAAO,0BAA2C;CAChF,IAAM,IAAK,GAAO,EACZ,CAAC,GAAO,KAAY,EAAiC,KAAK,EAC1D,CAAC,GAAgB,KAAqB,EAAsB,EAAE,CAAC,EAC/D,CAAC,GAAe,KAAoB,EAAuB,EAAE,CAAC,EAC9D,CAAC,GAAS,KAAc,EAAS,GAAK,EACtC,CAAC,GAAO,KAAY,EAAwB,KAAK;AAyCvD,QAvCA,QAAgB;EACd,IAAI,IAAY;EAChB,eAAe,IAAO;AAEpB,GADA,EAAW,GAAK,EAChB,EAAS,KAAK;AACd,OAAI;IACF,IAAM,CAAC,GAAG,GAAM,KAAQ,MAAM,QAAQ,IAAI;KACxC,EAAmB,EAAM;KACzB,EAAc,GAAO;MAAE,OAAO;MAAG,MAAM;MAAkB,CAAC;KAC1D,EAAqB,GAAO,EAAE,OAAO,GAAG,CAAC;KAC1C,CAAC;AACF,QAAI,EAAW;AAGf,IAFA,EAAS,EAAE,EACX,EAAkB,EAAK,EACvB,EAAiB,EAAK;YACf,GAAK;AACZ,IAAK,KAAW,EAAS,aAAe,QAAQ,EAAI,UAAU,0BAA0B;aAChF;AACR,IAAK,KAAW,EAAW,GAAM;;;AAIrC,SADA,GAAM,QACO;AACX,OAAY;;IAEb,CAAC,EAAM,IAAI,EAAM,QAAQ,CAAC,EAEzB,IAEA,kBAAC,GAAD,EAAc,SAAS,EAAG,oCAAoC,yBAAyB,EAAI,CAAA,GAE3F,IAEA,kBAAC,GAAD;EACE,OAAO,EAAG,uCAAuC,0BAA0B;EAC3E,SAAS;EACT,CAAA,GAIJ,kBAAC,OAAD;EAAK,WAAU;YAAf,CAEE,kBAAC,GAAD;GAAY,SAAS;GAAM,WAAU;aAArC;IACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,OAAO,EAAG,2CAA2C,kBAAkB;KACvE,OAAO,GAAO,kBAAkB;KAChC,MAAM,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;KACrC,SAAQ;KACR,CAAA,EACS,CAAA;IACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,OAAO,EAAG,wCAAwC,eAAe;KACjE,OAAO,GAAO,aAAa,gBAAgB,IAAI;KAC/C,UAAU,OAAO,GAAO,aAAa,gBAAgB,IAAI,EAAE,UAAU,GAAO,cAAc,gBAAgB,IAAI;KAC9G,MAAM,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA;KAChC,CAAA,EACS,CAAA;IACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,OAAO,EAAG,0CAA0C,iBAAiB;KACrE,OAAO,GAAO,iBAAiB;KAC/B,MAAM,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA;KAClC,SAAS,GAAO,iBAAiB,EAAM,gBAAgB,IAAI,YAAY;KACvE,CAAA,EACS,CAAA;IACb,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;KACE,OAAO,EAAG,0CAA0C,iBAAiB;KACrE,OAAO,GAAO,iBAAiB;KAC/B,MAAM,kBAAC,GAAD,EAAe,WAAU,UAAW,CAAA;KAC1C,CAAA,EACS,CAAA;IACF;MAEb,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,GAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,2CAA2C,kBAAkB;MAC9D,CAAA;KACD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAe,WAAW,IACzB,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,uCAAuC,kBAAkB;MAC3D,CAAA,GAEJ,EAAe,KAAK,MAClB,kBAAC,UAAD;MACE,MAAK;MAEL,eAAe,IAAsB,EAAQ,GAAG;MAChD,WAAU;gBAJZ,CAME,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAQ;QACL,CAAA,EACN,kBAAC,OAAD;QAAK,WAAU;kBAA+B,EAAQ;QAAgB,CAAA,CAClE;UACN,kBAAC,QAAD;OACE,WAAW,gDAAgD,EAAa,EAAQ,WAAW;iBAE1F,EAAQ;OACJ,CAAA,CACA;QAfF,EAAQ,GAeN,CACT;KAEA,CAAA,CACD;OAGP,kBAAC,GAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAG,0CAA0C,iBAAiB;MAC5D,CAAA;KACD,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAc,WAAW,IACxB,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,sCAAsC,4BAA4B;MACpE,CAAA,GAEJ,EAAc,KAAK,MACjB,kBAAC,OAAD;MAAuB,WAAU;gBAAjC,CACE,kBAAC,OAAD;OAAK,WAAU;iBAA0C,EAAS;OAAa,CAAA,EAC/E,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAS,QAAc,CAAA,EAC7B,EAAS,aACR,kBAAC,QAAD,EAAA,UAAO,IAAI,KAAK,EAAS,UAAU,CAAC,gBAAgB,EAAQ,CAAA,CAE1D;SACF;QARI,EAAS,GAQb,CACN;KAEA,CAAA,CACD;MACH;KACF"}
|
|
1
|
+
{"version":3,"file":"AIOverviewTab.js","names":[],"sources":["../../../src/components/ai/AIOverviewTab.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { Activity, Zap, Clock, MessageSquare } from 'lucide-react';\nimport { StatCard, Card, LoadingState, ErrorState } from '@/components/shared';\nimport { MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport type { AIStatsOverview, AISession, AIDispatch, AgentRef } from '@/services/aiApi';\nimport { fetchStatsOverview, fetchSessions, fetchDispatchHistory } from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIOverviewTabProps {\n agent: AgentRef;\n onNavigateToSession?: (sessionId: string) => void;\n}\n\nconst statusColors: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n idle: 'bg-status-warning-bg-subtle text-status-warning-text',\n processing: 'bg-[var(--color-accent-soft)] text-text-primary',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n terminated: 'bg-bg-sunken text-text-secondary',\n};\n\nexport function AIOverviewTab({ agent, onNavigateToSession }: AIOverviewTabProps) {\n const tr = useTr();\n const [stats, setStats] = useState<AIStatsOverview | null>(null);\n const [recentSessions, setRecentSessions] = useState<AISession[]>([]);\n const [recentPrompts, setRecentPrompts] = useState<AIDispatch[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n async function load() {\n setLoading(true);\n setError(null);\n try {\n const [s, sess, hist] = await Promise.all([\n fetchStatsOverview(agent),\n fetchSessions(agent, { limit: 5, sort: 'updatedAt:desc' }),\n fetchDispatchHistory(agent, { limit: 5 }),\n ]);\n if (cancelled) return;\n setStats(s);\n setRecentSessions(sess);\n setRecentPrompts(hist);\n } catch (err) {\n if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load overview');\n } finally {\n if (!cancelled) setLoading(false);\n }\n }\n load();\n return () => {\n cancelled = true;\n };\n }, [agent.id, agent.profile]);\n\n if (loading)\n return (\n <LoadingState message={tr('vibecontrols.ai.overview.loading', 'Loading AI overview...')} />\n );\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.overview.loadFailed', 'Failed to load overview')}\n message={error}\n />\n );\n\n return (\n <div className=\"space-y-6\">\n {/* Quick Stats */}\n <MotionList stagger={0.04} className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.activeSessions', 'Active Sessions')}\n value={stats?.activeSessions ?? 0}\n icon={<Activity className=\"size-5\" />}\n variant=\"success\"\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.totalTokens', 'Total Tokens')}\n value={stats?.totalTokens?.toLocaleString() ?? '0'}\n subtitle={`In: ${stats?.inputTokens?.toLocaleString() ?? 0} / Out: ${stats?.outputTokens?.toLocaleString() ?? 0}`}\n icon={<Zap className=\"size-5\" />}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.queuedPrompts', 'Queued Prompts')}\n value={stats?.queuedPrompts ?? 0}\n icon={<Clock className=\"size-5\" />}\n variant={stats?.queuedPrompts && stats.queuedPrompts > 0 ? 'warning' : 'default'}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('vibecontrols.ai.overview.totalSessions', 'Total Sessions')}\n value={stats?.totalSessions ?? 0}\n icon={<MessageSquare className=\"size-5\" />}\n />\n </MotionItem>\n </MotionList>\n\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-6\">\n {/* Recent Sessions */}\n <Card className=\"p-0\">\n <div className=\"px-4 py-3 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.overview.recentSessions', 'Recent Sessions')}\n </h3>\n </div>\n <div className=\"divide-y divide-border-default\">\n {recentSessions.length === 0 ? (\n <p className=\"px-4 py-6 text-sm text-text-secondary text-center\">\n {tr('vibecontrols.ai.overview.noSessions', 'No sessions yet')}\n </p>\n ) : (\n recentSessions.map((session) => (\n <button\n type=\"button\"\n key={session.id}\n onClick={() => onNavigateToSession?.(session.id)}\n className=\"flex w-full flex-col items-start gap-2 px-4 py-3 text-left transition-colors hover:bg-bg-sunken sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-medium text-text-primary text-sm truncate\">\n {session.name}\n </div>\n <div className=\"text-xs text-text-secondary\">{session.agentType}</div>\n </div>\n <span\n className={`rounded-full px-2 py-0.5 text-xs font-medium ${statusColors[session.status] ?? 'bg-bg-sunken text-text-secondary'}`}\n >\n {session.status}\n </span>\n </button>\n ))\n )}\n </div>\n </Card>\n\n {/* Recent Prompts */}\n <Card className=\"p-0\">\n <div className=\"px-4 py-3 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.overview.recentPrompts', 'Recent Prompts')}\n </h3>\n </div>\n <div className=\"divide-y divide-border-default\">\n {recentPrompts.length === 0 ? (\n <p className=\"px-4 py-6 text-sm text-text-secondary text-center\">\n {tr('vibecontrols.ai.overview.noPrompts', 'No prompts dispatched yet')}\n </p>\n ) : (\n recentPrompts.map((dispatch) => (\n <div key={dispatch.id} className=\"px-4 py-3\">\n <div className=\"text-sm text-text-primary line-clamp-2\">{dispatch.prompt}</div>\n <div className=\"mt-1 flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span>{dispatch.status}</span>\n {dispatch.createdAt && (\n <span>{new Date(dispatch.createdAt).toLocaleString()}</span>\n )}\n </div>\n </div>\n ))\n )}\n </div>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -77,7 +77,7 @@ function y({ agent: y }) {
|
|
|
77
77
|
}), /* @__PURE__ */ v("button", {
|
|
78
78
|
type: "button",
|
|
79
79
|
onClick: () => M(!j),
|
|
80
|
-
className: "flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-
|
|
80
|
+
className: "flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-text-primary bg-[var(--color-accent-soft)] rounded-md hover:bg-[var(--color-accent-soft)] transition-colors",
|
|
81
81
|
children: [/* @__PURE__ */ _(g, { className: "size-3.5" }), b("vibecontrols.ai.prompts.generateFromTemplate", "Generate from Template")]
|
|
82
82
|
})]
|
|
83
83
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIPromptsTab.js","names":[],"sources":["../../../src/components/ai/AIPromptsTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { Send, FileText, Wand2, Clock } from 'lucide-react';\nimport { Card, LoadingState, ErrorState, EmptyState } from '@/components/shared';\nimport type { AITemplate, AIContext, AISession, AIDispatch, AgentRef } from '@/services/aiApi';\nimport {\n fetchTemplates,\n fetchContexts,\n fetchSessions,\n fetchDispatchHistory,\n renderTemplate,\n recordTemplateUsage,\n sendDispatch,\n} from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIPromptsTabProps {\n agent: AgentRef;\n}\n\nexport function AIPromptsTab({ agent }: AIPromptsTabProps) {\n const tr = useTr();\n const [promptContent, setPromptContent] = useState('');\n const [selectedContextIds, setSelectedContextIds] = useState<string[]>([]);\n const [targetSessionId, setTargetSessionId] = useState('');\n const [sending, setSending] = useState(false);\n const [successMsg, setSuccessMsg] = useState<string | null>(null);\n\n // Generate from template state\n const [showTemplateGen, setShowTemplateGen] = useState(false);\n const [selectedTemplateId, setSelectedTemplateId] = useState('');\n const [sourceTemplateId, setSourceTemplateId] = useState<string | null>(null);\n const [templateVars, setTemplateVars] = useState<Record<string, string>>({});\n const [rendering, setRendering] = useState(false);\n\n // Data\n const [templates, setTemplates] = useState<AITemplate[]>([]);\n const [contexts, setContexts] = useState<AIContext[]>([]);\n const [sessions, setSessions] = useState<AISession[]>([]);\n const [history, setHistory] = useState<AIDispatch[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const loadData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const [t, c, s, h] = await Promise.all([\n fetchTemplates(agent.id),\n fetchContexts(agent),\n fetchSessions(agent),\n fetchDispatchHistory(agent, { limit: 20 }),\n ]);\n setTemplates(t);\n setContexts(c);\n setSessions(s);\n setHistory(h);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load data');\n } finally {\n setLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n loadData();\n }, [loadData]);\n\n const handleTemplateSelect = (templateId: string) => {\n setSelectedTemplateId(templateId);\n const template = templates.find((t) => t.id === templateId);\n if (template?.variables) {\n const vars: Record<string, string> = {};\n for (const key of Object.keys(template.variables)) {\n vars[key] = String(template.variables[key] ?? '');\n }\n setTemplateVars(vars);\n } else {\n setTemplateVars({});\n }\n };\n\n const handleGenerateFromTemplate = async () => {\n if (!selectedTemplateId) return;\n setRendering(true);\n try {\n const result = await renderTemplate(agent.id, selectedTemplateId, templateVars);\n setPromptContent(result.rendered);\n setSourceTemplateId(selectedTemplateId);\n setShowTemplateGen(false);\n } catch (err) {\n console.error('Failed to render template:', err);\n } finally {\n setRendering(false);\n }\n };\n\n const toggleContext = (contextId: string) => {\n setSelectedContextIds((prev) =>\n prev.includes(contextId) ? prev.filter((id) => id !== contextId) : [...prev, contextId]\n );\n };\n\n const handleSendToSession = async () => {\n if (!promptContent.trim() || !targetSessionId) return;\n setSending(true);\n setSuccessMsg(null);\n try {\n await sendDispatch(agent, {\n prompt: promptContent,\n sessionId: targetSessionId,\n contextIds: selectedContextIds.length > 0 ? selectedContextIds : undefined,\n });\n if (sourceTemplateId) {\n await recordTemplateUsage(agent.id, sourceTemplateId);\n }\n setSuccessMsg('Prompt dispatched successfully');\n setPromptContent('');\n setSourceTemplateId(null);\n setSelectedContextIds([]);\n setTimeout(() => setSuccessMsg(null), 3000);\n // Refresh history\n const h = await fetchDispatchHistory(agent, { limit: 20 });\n setHistory(h);\n } catch (err) {\n console.error('Failed to dispatch prompt:', err);\n } finally {\n setSending(false);\n }\n };\n\n if (loading)\n return <LoadingState message={tr('vibecontrols.ai.prompts.loading', 'Loading prompts...')} />;\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.prompts.loadFailed', 'Failed to load data')}\n message={error}\n onRetry={loadData}\n />\n );\n\n return (\n <div className=\"space-y-6\">\n {successMsg && (\n <div className=\"bg-status-success-bg-subtle text-status-success-text px-4 py-2 rounded-md text-sm\">\n {successMsg}\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Prompt Editor */}\n <div className=\"lg:col-span-2 space-y-4\">\n <Card className=\"p-4\">\n <div className=\"flex items-center justify-between mb-3\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.prompts.composePrompt', 'Compose Prompt')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowTemplateGen(!showTemplateGen)}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-action-primary-bg bg-[var(--color-accent-soft)] rounded-md hover:bg-[var(--color-accent-soft)] transition-colors\"\n >\n <Wand2 className=\"size-3.5\" />\n {tr('vibecontrols.ai.prompts.generateFromTemplate', 'Generate from Template')}\n </button>\n </div>\n\n {/* Template Generator */}\n {showTemplateGen && (\n <div className=\"mb-4 p-3 bg-bg-sunken rounded-md space-y-3\">\n <select\n value={selectedTemplateId}\n onChange={(e) => handleTemplateSelect(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-surface border border-border-default rounded-md text-text-primary text-sm\"\n >\n <option value=\"\">\n {tr('vibecontrols.ai.prompts.selectTemplate', 'Select a template...')}\n </option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n {Object.keys(templateVars).length > 0 && (\n <div className=\"space-y-2\">\n {Object.entries(templateVars).map(([key, val]) => (\n <div key={key}>\n <label className=\"block text-xs font-medium text-text-secondary mb-0.5\">\n {key}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={val}\n onChange={(e) =>\n setTemplateVars((prev) => ({ ...prev, [key]: e.target.value }))\n }\n className=\"w-full px-2 py-1.5 bg-bg-surface border border-border-default rounded text-sm text-text-primary focus:outline-none focus:border-border-strong\"\n />\n </div>\n ))}\n </div>\n )}\n <button\n type=\"button\"\n onClick={handleGenerateFromTemplate}\n disabled={rendering || !selectedTemplateId}\n className=\"w-full px-3 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {rendering\n ? tr('vibecontrols.ai.prompts.generating', 'Generating...')\n : tr('vibecontrols.ai.prompts.generate', 'Generate')}\n </button>\n </div>\n )}\n\n <textarea\n aria-label=\"control\"\n value={promptContent}\n onChange={(e) => {\n setPromptContent(e.target.value);\n setSourceTemplateId(null);\n }}\n rows={8}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm font-mono focus:outline-none focus:border-border-strong\"\n placeholder={tr(\n 'vibecontrols.ai.prompts.promptPlaceholder',\n 'Write your prompt here... (Markdown supported)'\n )}\n />\n\n {/* Session Target & Send */}\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-end gap-3 mt-3\">\n <div className=\"flex-1\">\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('vibecontrols.ai.prompts.targetSession', 'Target Session')}\n </label>\n <select\n value={targetSessionId}\n onChange={(e) => setTargetSessionId(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n <option value=\"\">\n {tr('vibecontrols.ai.prompts.selectSession', 'Select session...')}\n </option>\n {sessions\n .filter((s) => s.status !== 'terminated')\n .map((s) => (\n <option key={s.id} value={s.id}>\n {s.name} ({s.status})\n </option>\n ))}\n </select>\n </div>\n <button\n type=\"button\"\n onClick={handleSendToSession}\n disabled={sending || !promptContent.trim() || !targetSessionId}\n className=\"flex items-center justify-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50 text-sm\"\n >\n <Send className=\"size-4\" />\n {sending\n ? tr('vibecontrols.ai.prompts.sending', 'Sending...')\n : tr('vibecontrols.ai.prompts.sendToSession', 'Send to Session')}\n </button>\n </div>\n </Card>\n </div>\n\n {/* Context Picker */}\n <div className=\"space-y-4\">\n <Card className=\"p-4\">\n <h3 className=\"font-semibold text-text-primary mb-3\">\n {tr('vibecontrols.ai.prompts.attachContexts', 'Attach Contexts')}\n </h3>\n {contexts.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {tr('vibecontrols.ai.prompts.noContexts', 'No contexts available')}\n </p>\n ) : (\n <div className=\"space-y-2 max-h-64 overflow-y-auto\">\n {contexts.map((ctx) => (\n <label\n key={ctx.id}\n className=\"flex items-start gap-2 p-2 rounded hover:bg-bg-sunken cursor-pointer\"\n >\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={selectedContextIds.includes(ctx.id)}\n onChange={() => toggleContext(ctx.id)}\n className=\"mt-0.5 rounded border-border-default\"\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-medium text-text-primary truncate\">\n {ctx.name}\n </div>\n <div className=\"text-xs text-text-secondary\">{ctx.type}</div>\n </div>\n </label>\n ))}\n </div>\n )}\n </Card>\n </div>\n </div>\n\n {/* Dispatch History */}\n <Card className=\"p-0\">\n <div className=\"px-4 py-3 border-b border-border-default flex items-center gap-2\">\n <Clock className=\"size-4 text-text-secondary\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.prompts.dispatchHistory', 'Dispatch History')}\n </h3>\n </div>\n <div className=\"divide-y divide-border-default\">\n {history.length === 0 ? (\n <EmptyState\n icon={<FileText className=\"size-6 text-text-secondary\" />}\n title={tr('vibecontrols.ai.prompts.noDispatched', 'No dispatched prompts')}\n description={tr(\n 'vibecontrols.ai.prompts.noDispatchedDesc',\n 'Send a prompt to a session to see history here'\n )}\n />\n ) : (\n history.map((d) => (\n <div key={d.id} className=\"px-4 py-3\">\n <div className=\"text-sm text-text-primary line-clamp-2\">{d.prompt}</div>\n <div className=\"mt-1 flex items-center gap-3 text-xs text-text-secondary\">\n <span className=\"font-medium\">{d.status}</span>\n <span>Session: {d.sessionId ? `${d.sessionId.substring(0, 8)}...` : '—'}</span>\n {d.createdAt && <span>{new Date(d.createdAt).toLocaleString()}</span>}\n </div>\n </div>\n ))\n )}\n </div>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AIPromptsTab.js","names":[],"sources":["../../../src/components/ai/AIPromptsTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { Send, FileText, Wand2, Clock } from 'lucide-react';\nimport { Card, LoadingState, ErrorState, EmptyState } from '@/components/shared';\nimport type { AITemplate, AIContext, AISession, AIDispatch, AgentRef } from '@/services/aiApi';\nimport {\n fetchTemplates,\n fetchContexts,\n fetchSessions,\n fetchDispatchHistory,\n renderTemplate,\n recordTemplateUsage,\n sendDispatch,\n} from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIPromptsTabProps {\n agent: AgentRef;\n}\n\nexport function AIPromptsTab({ agent }: AIPromptsTabProps) {\n const tr = useTr();\n const [promptContent, setPromptContent] = useState('');\n const [selectedContextIds, setSelectedContextIds] = useState<string[]>([]);\n const [targetSessionId, setTargetSessionId] = useState('');\n const [sending, setSending] = useState(false);\n const [successMsg, setSuccessMsg] = useState<string | null>(null);\n\n // Generate from template state\n const [showTemplateGen, setShowTemplateGen] = useState(false);\n const [selectedTemplateId, setSelectedTemplateId] = useState('');\n const [sourceTemplateId, setSourceTemplateId] = useState<string | null>(null);\n const [templateVars, setTemplateVars] = useState<Record<string, string>>({});\n const [rendering, setRendering] = useState(false);\n\n // Data\n const [templates, setTemplates] = useState<AITemplate[]>([]);\n const [contexts, setContexts] = useState<AIContext[]>([]);\n const [sessions, setSessions] = useState<AISession[]>([]);\n const [history, setHistory] = useState<AIDispatch[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const loadData = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const [t, c, s, h] = await Promise.all([\n fetchTemplates(agent.id),\n fetchContexts(agent),\n fetchSessions(agent),\n fetchDispatchHistory(agent, { limit: 20 }),\n ]);\n setTemplates(t);\n setContexts(c);\n setSessions(s);\n setHistory(h);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load data');\n } finally {\n setLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n loadData();\n }, [loadData]);\n\n const handleTemplateSelect = (templateId: string) => {\n setSelectedTemplateId(templateId);\n const template = templates.find((t) => t.id === templateId);\n if (template?.variables) {\n const vars: Record<string, string> = {};\n for (const key of Object.keys(template.variables)) {\n vars[key] = String(template.variables[key] ?? '');\n }\n setTemplateVars(vars);\n } else {\n setTemplateVars({});\n }\n };\n\n const handleGenerateFromTemplate = async () => {\n if (!selectedTemplateId) return;\n setRendering(true);\n try {\n const result = await renderTemplate(agent.id, selectedTemplateId, templateVars);\n setPromptContent(result.rendered);\n setSourceTemplateId(selectedTemplateId);\n setShowTemplateGen(false);\n } catch (err) {\n console.error('Failed to render template:', err);\n } finally {\n setRendering(false);\n }\n };\n\n const toggleContext = (contextId: string) => {\n setSelectedContextIds((prev) =>\n prev.includes(contextId) ? prev.filter((id) => id !== contextId) : [...prev, contextId]\n );\n };\n\n const handleSendToSession = async () => {\n if (!promptContent.trim() || !targetSessionId) return;\n setSending(true);\n setSuccessMsg(null);\n try {\n await sendDispatch(agent, {\n prompt: promptContent,\n sessionId: targetSessionId,\n contextIds: selectedContextIds.length > 0 ? selectedContextIds : undefined,\n });\n if (sourceTemplateId) {\n await recordTemplateUsage(agent.id, sourceTemplateId);\n }\n setSuccessMsg('Prompt dispatched successfully');\n setPromptContent('');\n setSourceTemplateId(null);\n setSelectedContextIds([]);\n setTimeout(() => setSuccessMsg(null), 3000);\n // Refresh history\n const h = await fetchDispatchHistory(agent, { limit: 20 });\n setHistory(h);\n } catch (err) {\n console.error('Failed to dispatch prompt:', err);\n } finally {\n setSending(false);\n }\n };\n\n if (loading)\n return <LoadingState message={tr('vibecontrols.ai.prompts.loading', 'Loading prompts...')} />;\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.prompts.loadFailed', 'Failed to load data')}\n message={error}\n onRetry={loadData}\n />\n );\n\n return (\n <div className=\"space-y-6\">\n {successMsg && (\n <div className=\"bg-status-success-bg-subtle text-status-success-text px-4 py-2 rounded-md text-sm\">\n {successMsg}\n </div>\n )}\n\n <div className=\"grid grid-cols-1 lg:grid-cols-3 gap-6\">\n {/* Prompt Editor */}\n <div className=\"lg:col-span-2 space-y-4\">\n <Card className=\"p-4\">\n <div className=\"flex items-center justify-between mb-3\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.prompts.composePrompt', 'Compose Prompt')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowTemplateGen(!showTemplateGen)}\n className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-text-primary bg-[var(--color-accent-soft)] rounded-md hover:bg-[var(--color-accent-soft)] transition-colors\"\n >\n <Wand2 className=\"size-3.5\" />\n {tr('vibecontrols.ai.prompts.generateFromTemplate', 'Generate from Template')}\n </button>\n </div>\n\n {/* Template Generator */}\n {showTemplateGen && (\n <div className=\"mb-4 p-3 bg-bg-sunken rounded-md space-y-3\">\n <select\n value={selectedTemplateId}\n onChange={(e) => handleTemplateSelect(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-surface border border-border-default rounded-md text-text-primary text-sm\"\n >\n <option value=\"\">\n {tr('vibecontrols.ai.prompts.selectTemplate', 'Select a template...')}\n </option>\n {templates.map((t) => (\n <option key={t.id} value={t.id}>\n {t.name}\n </option>\n ))}\n </select>\n {Object.keys(templateVars).length > 0 && (\n <div className=\"space-y-2\">\n {Object.entries(templateVars).map(([key, val]) => (\n <div key={key}>\n <label className=\"block text-xs font-medium text-text-secondary mb-0.5\">\n {key}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={val}\n onChange={(e) =>\n setTemplateVars((prev) => ({ ...prev, [key]: e.target.value }))\n }\n className=\"w-full px-2 py-1.5 bg-bg-surface border border-border-default rounded text-sm text-text-primary focus:outline-none focus:border-border-strong\"\n />\n </div>\n ))}\n </div>\n )}\n <button\n type=\"button\"\n onClick={handleGenerateFromTemplate}\n disabled={rendering || !selectedTemplateId}\n className=\"w-full px-3 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {rendering\n ? tr('vibecontrols.ai.prompts.generating', 'Generating...')\n : tr('vibecontrols.ai.prompts.generate', 'Generate')}\n </button>\n </div>\n )}\n\n <textarea\n aria-label=\"control\"\n value={promptContent}\n onChange={(e) => {\n setPromptContent(e.target.value);\n setSourceTemplateId(null);\n }}\n rows={8}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm font-mono focus:outline-none focus:border-border-strong\"\n placeholder={tr(\n 'vibecontrols.ai.prompts.promptPlaceholder',\n 'Write your prompt here... (Markdown supported)'\n )}\n />\n\n {/* Session Target & Send */}\n <div className=\"flex flex-col sm:flex-row items-stretch sm:items-end gap-3 mt-3\">\n <div className=\"flex-1\">\n <label className=\"block text-xs font-medium text-text-secondary mb-1\">\n {tr('vibecontrols.ai.prompts.targetSession', 'Target Session')}\n </label>\n <select\n value={targetSessionId}\n onChange={(e) => setTargetSessionId(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n <option value=\"\">\n {tr('vibecontrols.ai.prompts.selectSession', 'Select session...')}\n </option>\n {sessions\n .filter((s) => s.status !== 'terminated')\n .map((s) => (\n <option key={s.id} value={s.id}>\n {s.name} ({s.status})\n </option>\n ))}\n </select>\n </div>\n <button\n type=\"button\"\n onClick={handleSendToSession}\n disabled={sending || !promptContent.trim() || !targetSessionId}\n className=\"flex items-center justify-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50 text-sm\"\n >\n <Send className=\"size-4\" />\n {sending\n ? tr('vibecontrols.ai.prompts.sending', 'Sending...')\n : tr('vibecontrols.ai.prompts.sendToSession', 'Send to Session')}\n </button>\n </div>\n </Card>\n </div>\n\n {/* Context Picker */}\n <div className=\"space-y-4\">\n <Card className=\"p-4\">\n <h3 className=\"font-semibold text-text-primary mb-3\">\n {tr('vibecontrols.ai.prompts.attachContexts', 'Attach Contexts')}\n </h3>\n {contexts.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n {tr('vibecontrols.ai.prompts.noContexts', 'No contexts available')}\n </p>\n ) : (\n <div className=\"space-y-2 max-h-64 overflow-y-auto\">\n {contexts.map((ctx) => (\n <label\n key={ctx.id}\n className=\"flex items-start gap-2 p-2 rounded hover:bg-bg-sunken cursor-pointer\"\n >\n <input\n aria-label=\"control\"\n type=\"checkbox\"\n checked={selectedContextIds.includes(ctx.id)}\n onChange={() => toggleContext(ctx.id)}\n className=\"mt-0.5 rounded border-border-default\"\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-medium text-text-primary truncate\">\n {ctx.name}\n </div>\n <div className=\"text-xs text-text-secondary\">{ctx.type}</div>\n </div>\n </label>\n ))}\n </div>\n )}\n </Card>\n </div>\n </div>\n\n {/* Dispatch History */}\n <Card className=\"p-0\">\n <div className=\"px-4 py-3 border-b border-border-default flex items-center gap-2\">\n <Clock className=\"size-4 text-text-secondary\" />\n <h3 className=\"font-semibold text-text-primary\">\n {tr('vibecontrols.ai.prompts.dispatchHistory', 'Dispatch History')}\n </h3>\n </div>\n <div className=\"divide-y divide-border-default\">\n {history.length === 0 ? (\n <EmptyState\n icon={<FileText className=\"size-6 text-text-secondary\" />}\n title={tr('vibecontrols.ai.prompts.noDispatched', 'No dispatched prompts')}\n description={tr(\n 'vibecontrols.ai.prompts.noDispatchedDesc',\n 'Send a prompt to a session to see history here'\n )}\n />\n ) : (\n history.map((d) => (\n <div key={d.id} className=\"px-4 py-3\">\n <div className=\"text-sm text-text-primary line-clamp-2\">{d.prompt}</div>\n <div className=\"mt-1 flex items-center gap-3 text-xs text-text-secondary\">\n <span className=\"font-medium\">{d.status}</span>\n <span>Session: {d.sessionId ? `${d.sessionId.substring(0, 8)}...` : '—'}</span>\n {d.createdAt && <span>{new Date(d.createdAt).toLocaleString()}</span>}\n </div>\n </div>\n ))\n )}\n </div>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIQueueTab.js","names":[],"sources":["../../../src/components/ai/AIQueueTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport {\n ListChecks,\n RefreshCw,\n X,\n AlertCircle,\n Clock,\n Loader2,\n CheckCircle2,\n Ban,\n} from 'lucide-react';\nimport { Card, LoadingState, ErrorState, EmptyState } from '@/components/shared';\nimport type { AIQueueItem, AgentRef } from '@/services/aiApi';\nimport { fetchQueueItems, cancelQueueItem } from '@/services/aiApi';\nimport { notify } from '@/lib/toast';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIQueueTabProps {\n agent: AgentRef;\n onNavigateToSession?: (sessionId: string) => void;\n}\n\nconst STATUS_META: Record<\n AIQueueItem['status'],\n { label: string; cls: string; icon: typeof Clock }\n> = {\n pending: {\n label: 'Pending',\n cls: 'bg-status-warning-bg-subtle text-status-warning-text',\n icon: Clock,\n },\n processing: {\n label: 'Processing',\n cls: 'bg-[var(--color-accent-soft)] text-action-primary-bg',\n icon: Loader2,\n },\n completed: {\n label: 'Completed',\n cls: 'bg-status-success-bg-subtle text-status-success-text',\n icon: CheckCircle2,\n },\n failed: {\n label: 'Failed',\n cls: 'bg-status-error-bg-subtle text-status-error-text',\n icon: AlertCircle,\n },\n cancelled: { label: 'Cancelled', cls: 'bg-bg-sunken text-text-secondary', icon: Ban },\n};\n\n/**\n * AIQueueTab — the \"queue overnight, review in the morning\" surface. Lists the queued AI prompts on\n * the active agent (the agent runs them in the background), with per-item status, attempts, and\n * errors, plus cancel for anything still pending. Auto-refreshes so a morning check shows the latest\n * results. Backed by the agent's `/ai/queue` API (fetchQueueItems / cancelQueueItem) — the same\n * governed agent surface the rest of AI mode uses.\n */\nexport function AIQueueTab({ agent, onNavigateToSession }: AIQueueTabProps): React.ReactElement {\n const tr = useTr();\n const [items, setItems] = useState<AIQueueItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [cancelling, setCancelling] = useState<string | null>(null);\n\n const load = useCallback(\n async (showSpinner: boolean): Promise<void> => {\n if (!agent.id) return;\n if (showSpinner) setLoading(true);\n try {\n const data = await fetchQueueItems(agent);\n setItems(data);\n setError(null);\n } catch (err) {\n setError((err as Error).message);\n } finally {\n if (showSpinner) setLoading(false);\n }\n },\n [agent]\n );\n\n useEffect(() => {\n void load(true);\n // Poll while items are still in flight so a left-open tab updates itself overnight.\n const timer = window.setInterval(() => void load(false), 15000);\n return () => window.clearInterval(timer);\n }, [load]);\n\n const handleCancel = async (id: string): Promise<void> => {\n setCancelling(id);\n try {\n await cancelQueueItem(agent, id);\n notify.success(tr('aiQueue.cancelled', 'Queued item cancelled'));\n await load(false);\n } catch (err) {\n notify.error(tr('aiQueue.cancelFailed', 'Could not cancel'), (err as Error).message);\n } finally {\n setCancelling(null);\n }\n };\n\n if (!agent.id) {\n return (\n <EmptyState\n icon={<ListChecks className=\"size-10\" />}\n title={tr('aiQueue.noAgentTitle', 'No active agent')}\n description={tr(\n 'aiQueue.noAgentDesc',\n 'Start or attach an agent to queue AI prompts for background processing.'\n )}\n />\n );\n }\n\n if (loading && items.length === 0) return <LoadingState />;\n if (error && items.length === 0) {\n return <ErrorState message={error} onRetry={() => void load(true)} />;\n }\n\n const pendingCount = items.filter(\n (i) => i.status === 'pending' || i.status === 'processing'\n ).length;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <ListChecks className=\"size-5\" />\n {tr('aiQueue.title', 'AI Queue')}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'aiQueue.subtitle',\n 'Prompts queued for background processing on this agent — queue at night, review in the morning.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => void load(true)}\n className=\"flex items-center gap-1.5 rounded-md border border-border-default px-3 py-1.5 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n {tr('common.refresh', 'Refresh')}\n </button>\n </div>\n\n {items.length === 0 ? (\n <EmptyState\n icon={<ListChecks className=\"size-10\" />}\n title={tr('aiQueue.emptyTitle', 'Queue is empty')}\n description={tr(\n 'aiQueue.emptyDesc',\n 'Dispatch a prompt with \"Queue\" instead of \"Run\" to have the agent process it in the background.'\n )}\n />\n ) : (\n <>\n {pendingCount > 0 && (\n <p className=\"text-xs text-text-tertiary\">\n {pendingCount} {tr('aiQueue.inFlight', 'in flight')} · {items.length}{' '}\n {tr('aiQueue.total', 'total')}\n </p>\n )}\n <Card>\n <ul className=\"divide-y divide-border-subtle\">\n {items.map((item) => {\n const meta = STATUS_META[item.status];\n const StatusIcon = meta.icon;\n return (\n <li key={item.id} className=\"flex items-center gap-3 px-4 py-3\">\n <span\n className={`inline-flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${meta.cls}`}\n >\n <StatusIcon\n className={`size-3.5 ${item.status === 'processing' ? 'animate-spin' : ''}`}\n />\n {meta.label}\n </span>\n <div className=\"min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={() => onNavigateToSession?.(item.sessionId)}\n className=\"truncate text-left font-mono text-sm text-text-primary hover:underline\"\n title={tr('aiQueue.openSession', 'Open the session this prompt runs in')}\n >\n {item.sessionId}\n </button>\n <div className=\"text-xs text-text-tertiary\">\n {tr('aiQueue.attempt', 'attempt')} {item.attempts}/{item.maxAttempts}\n {item.createdAt ? ` · ${new Date(item.createdAt).toLocaleString()}` : ''}\n </div>\n {item.lastError && (\n <div className=\"mt-0.5 truncate text-xs text-status-error-text\">\n {item.lastError}\n </div>\n )}\n </div>\n {item.status === 'pending' && (\n <button\n type=\"button\"\n onClick={() => void handleCancel(item.id)}\n disabled={cancelling === item.id}\n className=\"shrink-0 rounded p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-status-error-text disabled:opacity-50\"\n aria-label={tr('common.cancel', 'Cancel')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n </li>\n );\n })}\n </ul>\n </Card>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AIQueueTab.js","names":[],"sources":["../../../src/components/ai/AIQueueTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport {\n ListChecks,\n RefreshCw,\n X,\n AlertCircle,\n Clock,\n Loader2,\n CheckCircle2,\n Ban,\n} from 'lucide-react';\nimport { Card, LoadingState, ErrorState, EmptyState } from '@/components/shared';\nimport type { AIQueueItem, AgentRef } from '@/services/aiApi';\nimport { fetchQueueItems, cancelQueueItem } from '@/services/aiApi';\nimport { notify } from '@/lib/toast';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AIQueueTabProps {\n agent: AgentRef;\n onNavigateToSession?: (sessionId: string) => void;\n}\n\nconst STATUS_META: Record<\n AIQueueItem['status'],\n { label: string; cls: string; icon: typeof Clock }\n> = {\n pending: {\n label: 'Pending',\n cls: 'bg-status-warning-bg-subtle text-status-warning-text',\n icon: Clock,\n },\n processing: {\n label: 'Processing',\n cls: 'bg-[var(--color-accent-soft)] text-text-primary',\n icon: Loader2,\n },\n completed: {\n label: 'Completed',\n cls: 'bg-status-success-bg-subtle text-status-success-text',\n icon: CheckCircle2,\n },\n failed: {\n label: 'Failed',\n cls: 'bg-status-error-bg-subtle text-status-error-text',\n icon: AlertCircle,\n },\n cancelled: { label: 'Cancelled', cls: 'bg-bg-sunken text-text-secondary', icon: Ban },\n};\n\n/**\n * AIQueueTab — the \"queue overnight, review in the morning\" surface. Lists the queued AI prompts on\n * the active agent (the agent runs them in the background), with per-item status, attempts, and\n * errors, plus cancel for anything still pending. Auto-refreshes so a morning check shows the latest\n * results. Backed by the agent's `/ai/queue` API (fetchQueueItems / cancelQueueItem) — the same\n * governed agent surface the rest of AI mode uses.\n */\nexport function AIQueueTab({ agent, onNavigateToSession }: AIQueueTabProps): React.ReactElement {\n const tr = useTr();\n const [items, setItems] = useState<AIQueueItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [cancelling, setCancelling] = useState<string | null>(null);\n\n const load = useCallback(\n async (showSpinner: boolean): Promise<void> => {\n if (!agent.id) return;\n if (showSpinner) setLoading(true);\n try {\n const data = await fetchQueueItems(agent);\n setItems(data);\n setError(null);\n } catch (err) {\n setError((err as Error).message);\n } finally {\n if (showSpinner) setLoading(false);\n }\n },\n [agent]\n );\n\n useEffect(() => {\n void load(true);\n // Poll while items are still in flight so a left-open tab updates itself overnight.\n const timer = window.setInterval(() => void load(false), 15000);\n return () => window.clearInterval(timer);\n }, [load]);\n\n const handleCancel = async (id: string): Promise<void> => {\n setCancelling(id);\n try {\n await cancelQueueItem(agent, id);\n notify.success(tr('aiQueue.cancelled', 'Queued item cancelled'));\n await load(false);\n } catch (err) {\n notify.error(tr('aiQueue.cancelFailed', 'Could not cancel'), (err as Error).message);\n } finally {\n setCancelling(null);\n }\n };\n\n if (!agent.id) {\n return (\n <EmptyState\n icon={<ListChecks className=\"size-10\" />}\n title={tr('aiQueue.noAgentTitle', 'No active agent')}\n description={tr(\n 'aiQueue.noAgentDesc',\n 'Start or attach an agent to queue AI prompts for background processing.'\n )}\n />\n );\n }\n\n if (loading && items.length === 0) return <LoadingState />;\n if (error && items.length === 0) {\n return <ErrorState message={error} onRetry={() => void load(true)} />;\n }\n\n const pendingCount = items.filter(\n (i) => i.status === 'pending' || i.status === 'processing'\n ).length;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"flex items-center gap-2 text-base font-semibold text-text-primary\">\n <ListChecks className=\"size-5\" />\n {tr('aiQueue.title', 'AI Queue')}\n </h3>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'aiQueue.subtitle',\n 'Prompts queued for background processing on this agent — queue at night, review in the morning.'\n )}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() => void load(true)}\n className=\"flex items-center gap-1.5 rounded-md border border-border-default px-3 py-1.5 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n {tr('common.refresh', 'Refresh')}\n </button>\n </div>\n\n {items.length === 0 ? (\n <EmptyState\n icon={<ListChecks className=\"size-10\" />}\n title={tr('aiQueue.emptyTitle', 'Queue is empty')}\n description={tr(\n 'aiQueue.emptyDesc',\n 'Dispatch a prompt with \"Queue\" instead of \"Run\" to have the agent process it in the background.'\n )}\n />\n ) : (\n <>\n {pendingCount > 0 && (\n <p className=\"text-xs text-text-tertiary\">\n {pendingCount} {tr('aiQueue.inFlight', 'in flight')} · {items.length}{' '}\n {tr('aiQueue.total', 'total')}\n </p>\n )}\n <Card>\n <ul className=\"divide-y divide-border-subtle\">\n {items.map((item) => {\n const meta = STATUS_META[item.status];\n const StatusIcon = meta.icon;\n return (\n <li key={item.id} className=\"flex items-center gap-3 px-4 py-3\">\n <span\n className={`inline-flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium ${meta.cls}`}\n >\n <StatusIcon\n className={`size-3.5 ${item.status === 'processing' ? 'animate-spin' : ''}`}\n />\n {meta.label}\n </span>\n <div className=\"min-w-0 flex-1\">\n <button\n type=\"button\"\n onClick={() => onNavigateToSession?.(item.sessionId)}\n className=\"truncate text-left font-mono text-sm text-text-primary hover:underline\"\n title={tr('aiQueue.openSession', 'Open the session this prompt runs in')}\n >\n {item.sessionId}\n </button>\n <div className=\"text-xs text-text-tertiary\">\n {tr('aiQueue.attempt', 'attempt')} {item.attempts}/{item.maxAttempts}\n {item.createdAt ? ` · ${new Date(item.createdAt).toLocaleString()}` : ''}\n </div>\n {item.lastError && (\n <div className=\"mt-0.5 truncate text-xs text-status-error-text\">\n {item.lastError}\n </div>\n )}\n </div>\n {item.status === 'pending' && (\n <button\n type=\"button\"\n onClick={() => void handleCancel(item.id)}\n disabled={cancelling === item.id}\n className=\"shrink-0 rounded p-1.5 text-text-secondary hover:bg-bg-sunken hover:text-status-error-text disabled:opacity-50\"\n aria-label={tr('common.cancel', 'Cancel')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n </li>\n );\n })}\n </ul>\n </Card>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -12,7 +12,7 @@ import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
|
12
12
|
var h = {
|
|
13
13
|
active: "bg-status-success-bg-subtle text-status-success-text",
|
|
14
14
|
idle: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
15
|
-
processing: "bg-[var(--color-accent-soft)] text-
|
|
15
|
+
processing: "bg-[var(--color-accent-soft)] text-text-primary",
|
|
16
16
|
error: "bg-status-error-bg-subtle text-status-error-text",
|
|
17
17
|
terminated: "bg-bg-sunken text-text-secondary"
|
|
18
18
|
}, g = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AISessionsTab.js","names":[],"sources":["../../../src/components/ai/AISessionsTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { Plus, MessageSquare, X } from 'lucide-react';\nimport { Card, LoadingState, ErrorState, EmptyState } from '@/components/shared';\nimport type { AISession, AgentRef } from '@/services/aiApi';\nimport { fetchSessions, createSession } from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AISessionsTabProps {\n agent: AgentRef;\n onNavigateToSession?: (sessionId: string) => void;\n}\n\nconst statusColors: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n idle: 'bg-status-warning-bg-subtle text-status-warning-text',\n processing: 'bg-[var(--color-accent-soft)] text-action-primary-bg',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n terminated: 'bg-bg-sunken text-text-secondary',\n};\n\nconst agentTypes = [\n { value: 'claude', label: 'Claude' },\n { value: 'codex', label: 'Codex' },\n { value: 'opencode', label: 'OpenCode' },\n { value: 'gemini', label: 'Gemini' },\n { value: 'cursor', label: 'Cursor' },\n { value: 'openrouter', label: 'OpenRouter' },\n { value: 'minimax', label: 'Minimax' },\n { value: 'ollama', label: 'Ollama' },\n { value: 'openai-compat', label: 'OpenAI-compatible' },\n { value: 'copilot', label: 'Copilot' },\n { value: 'aider', label: 'Aider' },\n { value: 'amp', label: 'Amp' },\n { value: 'crush', label: 'Crush' },\n { value: 'goose', label: 'Goose' },\n { value: 'pi', label: 'Pi' },\n { value: 'plandex', label: 'Plandex' },\n];\n\nexport function AISessionsTab({ agent, onNavigateToSession }: AISessionsTabProps) {\n const tr = useTr();\n const [sessions, setSessions] = useState<AISession[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [showCreate, setShowCreate] = useState(false);\n const [creating, setCreating] = useState(false);\n const [newName, setNewName] = useState('');\n const [newAgentType, setNewAgentType] = useState('claude');\n\n const loadSessions = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchSessions(agent);\n setSessions(result);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load sessions');\n } finally {\n setLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n loadSessions();\n }, [loadSessions]);\n\n const handleCreate = async () => {\n if (!newName.trim()) return;\n setCreating(true);\n try {\n const session = await createSession(agent, {\n name: newName,\n agentType: newAgentType,\n });\n setShowCreate(false);\n setNewName('');\n setNewAgentType('claude');\n await loadSessions();\n onNavigateToSession?.(session.id);\n } catch (err) {\n console.error('Failed to create session:', err);\n } finally {\n setCreating(false);\n }\n };\n\n if (loading)\n return <LoadingState message={tr('vibecontrols.ai.sessions.loading', 'Loading sessions...')} />;\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.sessions.loadFailed', 'Failed to load sessions')}\n message={error}\n onRetry={loadSessions}\n />\n );\n\n return (\n <div className=\"space-y-4\">\n {/* Toolbar */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-text-secondary\">{sessions.length} session(s)</p>\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm text-action-primary-text transition-colors hover:bg-action-primary-bg-hover sm:w-auto\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.sessions.newSession', 'New Session')}\n </button>\n </div>\n\n {/* Session Grid */}\n {sessions.length === 0 ? (\n <EmptyState\n icon={<MessageSquare className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.sessions.emptyTitle', 'No AI sessions')}\n description={tr(\n 'vibecontrols.ai.sessions.emptyDescription',\n 'Create a new session to start interacting with an AI agent'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.sessions.newSession', 'New Session')}\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {sessions.map((session) => (\n <Card\n key={session.id}\n hoverable\n onClick={() => onNavigateToSession?.(session.id)}\n className=\"p-4 cursor-pointer\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <h4 className=\"font-semibold text-text-primary truncate\">{session.name}</h4>\n <p className=\"text-xs text-text-secondary mt-0.5\">{session.agentType}</p>\n </div>\n <span\n className={`px-2 py-0.5 text-xs rounded-full font-medium flex-shrink-0 ${statusColors[session.status] ?? 'bg-bg-sunken text-text-secondary'}`}\n >\n {session.status}\n </span>\n </div>\n\n {session.stats && (\n <div className=\"mt-3 grid grid-cols-2 gap-2 text-xs\">\n <div className=\"bg-bg-sunken rounded p-2\">\n <div className=\"text-text-secondary\">Total Tokens</div>\n <div className=\"font-semibold text-text-primary\">\n {session.stats.totalTokens?.toLocaleString() ?? 0}\n </div>\n </div>\n <div className=\"bg-bg-sunken rounded p-2\">\n <div className=\"text-text-secondary\">Input / Output</div>\n <div className=\"font-semibold text-text-primary\">\n {session.stats.inputTokens?.toLocaleString() ?? 0} /{' '}\n {session.stats.outputTokens?.toLocaleString() ?? 0}\n </div>\n </div>\n </div>\n )}\n\n {session.createdAt && (\n <p className=\"mt-2 text-xs text-text-muted\">\n Created {new Date(session.createdAt).toLocaleDateString()}\n </p>\n )}\n </Card>\n ))}\n </div>\n )}\n\n {/* Create Session Dialog */}\n {showCreate && (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => setShowCreate(false))();\n }\n }}\n className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\"\n onClick={() => setShowCreate(false)}\n >\n <div\n className=\"bg-bg-surface border border-border-default rounded-lg shadow-xl w-full max-w-sm p-6\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.ai.sessions.newAISession', 'New AI Session')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"p-1 hover:bg-bg-sunken rounded-md\"\n >\n <X className=\"size-4 text-text-secondary\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.sessions.name', 'Name')}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong\"\n placeholder={tr(\n 'vibecontrols.ai.sessions.sessionNamePlaceholder',\n 'Session name'\n )}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.sessions.agentType', 'Agent Type')}\n </label>\n <select\n value={newAgentType}\n onChange={(e) => setNewAgentType(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {agentTypes.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n {tr('vibecontrols.ai.sessions.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={creating || !newName.trim()}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creating\n ? tr('vibecontrols.ai.sessions.creating', 'Creating...')\n : tr('vibecontrols.ai.sessions.create', 'Create')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AISessionsTab.js","names":[],"sources":["../../../src/components/ai/AISessionsTab.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { Plus, MessageSquare, X } from 'lucide-react';\nimport { Card, LoadingState, ErrorState, EmptyState } from '@/components/shared';\nimport type { AISession, AgentRef } from '@/services/aiApi';\nimport { fetchSessions, createSession } from '@/services/aiApi';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface AISessionsTabProps {\n agent: AgentRef;\n onNavigateToSession?: (sessionId: string) => void;\n}\n\nconst statusColors: Record<string, string> = {\n active: 'bg-status-success-bg-subtle text-status-success-text',\n idle: 'bg-status-warning-bg-subtle text-status-warning-text',\n processing: 'bg-[var(--color-accent-soft)] text-text-primary',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n terminated: 'bg-bg-sunken text-text-secondary',\n};\n\nconst agentTypes = [\n { value: 'claude', label: 'Claude' },\n { value: 'codex', label: 'Codex' },\n { value: 'opencode', label: 'OpenCode' },\n { value: 'gemini', label: 'Gemini' },\n { value: 'cursor', label: 'Cursor' },\n { value: 'openrouter', label: 'OpenRouter' },\n { value: 'minimax', label: 'Minimax' },\n { value: 'ollama', label: 'Ollama' },\n { value: 'openai-compat', label: 'OpenAI-compatible' },\n { value: 'copilot', label: 'Copilot' },\n { value: 'aider', label: 'Aider' },\n { value: 'amp', label: 'Amp' },\n { value: 'crush', label: 'Crush' },\n { value: 'goose', label: 'Goose' },\n { value: 'pi', label: 'Pi' },\n { value: 'plandex', label: 'Plandex' },\n];\n\nexport function AISessionsTab({ agent, onNavigateToSession }: AISessionsTabProps) {\n const tr = useTr();\n const [sessions, setSessions] = useState<AISession[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [showCreate, setShowCreate] = useState(false);\n const [creating, setCreating] = useState(false);\n const [newName, setNewName] = useState('');\n const [newAgentType, setNewAgentType] = useState('claude');\n\n const loadSessions = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const result = await fetchSessions(agent);\n setSessions(result);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load sessions');\n } finally {\n setLoading(false);\n }\n }, [agent]);\n\n useEffect(() => {\n loadSessions();\n }, [loadSessions]);\n\n const handleCreate = async () => {\n if (!newName.trim()) return;\n setCreating(true);\n try {\n const session = await createSession(agent, {\n name: newName,\n agentType: newAgentType,\n });\n setShowCreate(false);\n setNewName('');\n setNewAgentType('claude');\n await loadSessions();\n onNavigateToSession?.(session.id);\n } catch (err) {\n console.error('Failed to create session:', err);\n } finally {\n setCreating(false);\n }\n };\n\n if (loading)\n return <LoadingState message={tr('vibecontrols.ai.sessions.loading', 'Loading sessions...')} />;\n if (error)\n return (\n <ErrorState\n title={tr('vibecontrols.ai.sessions.loadFailed', 'Failed to load sessions')}\n message={error}\n onRetry={loadSessions}\n />\n );\n\n return (\n <div className=\"space-y-4\">\n {/* Toolbar */}\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-text-secondary\">{sessions.length} session(s)</p>\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"flex w-full items-center justify-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm text-action-primary-text transition-colors hover:bg-action-primary-bg-hover sm:w-auto\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.sessions.newSession', 'New Session')}\n </button>\n </div>\n\n {/* Session Grid */}\n {sessions.length === 0 ? (\n <EmptyState\n icon={<MessageSquare className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.ai.sessions.emptyTitle', 'No AI sessions')}\n description={tr(\n 'vibecontrols.ai.sessions.emptyDescription',\n 'Create a new session to start interacting with an AI agent'\n )}\n action={\n <button\n type=\"button\"\n onClick={() => setShowCreate(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.ai.sessions.newSession', 'New Session')}\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {sessions.map((session) => (\n <Card\n key={session.id}\n hoverable\n onClick={() => onNavigateToSession?.(session.id)}\n className=\"p-4 cursor-pointer\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <h4 className=\"font-semibold text-text-primary truncate\">{session.name}</h4>\n <p className=\"text-xs text-text-secondary mt-0.5\">{session.agentType}</p>\n </div>\n <span\n className={`px-2 py-0.5 text-xs rounded-full font-medium flex-shrink-0 ${statusColors[session.status] ?? 'bg-bg-sunken text-text-secondary'}`}\n >\n {session.status}\n </span>\n </div>\n\n {session.stats && (\n <div className=\"mt-3 grid grid-cols-2 gap-2 text-xs\">\n <div className=\"bg-bg-sunken rounded p-2\">\n <div className=\"text-text-secondary\">Total Tokens</div>\n <div className=\"font-semibold text-text-primary\">\n {session.stats.totalTokens?.toLocaleString() ?? 0}\n </div>\n </div>\n <div className=\"bg-bg-sunken rounded p-2\">\n <div className=\"text-text-secondary\">Input / Output</div>\n <div className=\"font-semibold text-text-primary\">\n {session.stats.inputTokens?.toLocaleString() ?? 0} /{' '}\n {session.stats.outputTokens?.toLocaleString() ?? 0}\n </div>\n </div>\n </div>\n )}\n\n {session.createdAt && (\n <p className=\"mt-2 text-xs text-text-muted\">\n Created {new Date(session.createdAt).toLocaleDateString()}\n </p>\n )}\n </Card>\n ))}\n </div>\n )}\n\n {/* Create Session Dialog */}\n {showCreate && (\n <div\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (() => setShowCreate(false))();\n }\n }}\n className=\"fixed inset-0 bg-bg-overlay flex items-center justify-center z-50 p-4\"\n onClick={() => setShowCreate(false)}\n >\n <div\n className=\"bg-bg-surface border border-border-default rounded-lg shadow-xl w-full max-w-sm p-6\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"mb-4 flex items-start justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">\n {tr('vibecontrols.ai.sessions.newAISession', 'New AI Session')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"p-1 hover:bg-bg-sunken rounded-md\"\n >\n <X className=\"size-4 text-text-secondary\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.sessions.name', 'Name')}\n </label>\n <input\n aria-label=\"control\"\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm focus:outline-none focus:border-border-strong\"\n placeholder={tr(\n 'vibecontrols.ai.sessions.sessionNamePlaceholder',\n 'Session name'\n )}\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('vibecontrols.ai.sessions.agentType', 'Agent Type')}\n </label>\n <select\n value={newAgentType}\n onChange={(e) => setNewAgentType(e.target.value)}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary text-sm\"\n >\n {agentTypes.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"px-4 py-2 text-sm text-text-secondary hover:bg-bg-sunken rounded-md transition-colors\"\n >\n {tr('vibecontrols.ai.sessions.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleCreate}\n disabled={creating || !newName.trim()}\n className=\"px-4 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {creating\n ? tr('vibecontrols.ai.sessions.creating', 'Creating...')\n : tr('vibecontrols.ai.sessions.create', 'Create')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@ var c = {
|
|
|
14
14
|
CREATE: "bg-status-success-bg-subtle text-status-success-text",
|
|
15
15
|
UPDATE: "bg-status-info-bg-subtle text-status-info-text",
|
|
16
16
|
DELETE: "bg-status-error-bg-subtle text-status-error-text",
|
|
17
|
-
EXECUTE: "bg-[var(--color-accent-soft)] text-
|
|
17
|
+
EXECUTE: "bg-[var(--color-accent-soft)] text-text-primary",
|
|
18
18
|
EXPORT: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
19
19
|
SHARE: "bg-status-success-bg-subtle text-status-success-text",
|
|
20
20
|
REVOKE: "bg-status-warning-bg-subtle text-status-warning-text",
|