@burdenoff/microfe-vibecontrols 2026.601.21 → 2026.601.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/actions/ActionCard.js +77 -66
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +186 -173
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AITemplatesTab.js +135 -125
- package/dist/components/ai/AITemplatesTab.js.map +1 -1
- package/dist/components/ai/InstructionFilesManager.js +151 -137
- package/dist/components/ai/InstructionFilesManager.js.map +1 -1
- package/dist/components/docs/DocsEditPanel.js +17 -16
- package/dist/components/docs/DocsEditPanel.js.map +1 -1
- package/dist/components/docs/DocsPreviewPanel.js +25 -24
- package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +110 -94
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +8 -8
- package/dist/components/scorecard/ScorecardPanel.js +271 -257
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/sharing/EntityShareButton.js +58 -0
- package/dist/components/sharing/EntityShareButton.js.map +1 -0
- package/dist/components/sharing/entityShareOps.js +603 -0
- package/dist/components/sharing/entityShareOps.js.map +1 -0
- package/dist/components/sharing/index.js +3 -0
- package/dist/components/sharing/shareRegistry.js +37 -12
- package/dist/components/sharing/shareRegistry.js.map +1 -1
- package/dist/components/sharing/useEntityShareController.js +88 -0
- package/dist/components/sharing/useEntityShareController.js.map +1 -0
- package/dist/constants/permissions.js +11 -0
- package/dist/constants/permissions.js.map +1 -1
- package/dist/pages/ActionsPage.js +162 -162
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +264 -250
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +124 -113
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +139 -126
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +78 -67
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +1 -1
- package/dist/pages/VibeDetailsPage.js +484 -484
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +91 -77
- package/dist/pages/tunnels/TunnelDetailsPage.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 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-action-primary-bg/10 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 <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-action-primary-bg/10 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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"}
|