@burdenoff/microfe-vibecontrols 2026.623.2 → 2026.623.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/components/actions/ActionTypeBadge.js +1 -1
  2. package/dist/components/actions/ActionTypeBadge.js.map +1 -1
  3. package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
  4. package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
  5. package/dist/components/agent-manager/AgentManagerChatPane.js +1 -1
  6. package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
  7. package/dist/components/agent-manager/AgentManagerInputArea.js +1 -1
  8. package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
  9. package/dist/components/agent-manager/BridleConfigPanel.js +2 -2
  10. package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
  11. package/dist/components/agent-manager/ProfilesPanel.js +1 -1
  12. package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
  13. package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
  14. package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
  15. package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
  16. package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
  17. package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
  18. package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
  19. package/dist/components/agent-manager/detail/SessionLogsPanel.js +2 -2
  20. package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
  21. package/dist/components/agents/AgentForm.js +2 -2
  22. package/dist/components/agents/AgentForm.js.map +1 -1
  23. package/dist/components/ai/AIContextsTab.js +1 -1
  24. package/dist/components/ai/AIContextsTab.js.map +1 -1
  25. package/dist/components/ai/AIOverviewTab.js +1 -1
  26. package/dist/components/ai/AIOverviewTab.js.map +1 -1
  27. package/dist/components/ai/AIPromptsTab.js +1 -1
  28. package/dist/components/ai/AIPromptsTab.js.map +1 -1
  29. package/dist/components/ai/AIQueueTab.js +1 -1
  30. package/dist/components/ai/AIQueueTab.js.map +1 -1
  31. package/dist/components/ai/AISessionsTab.js +1 -1
  32. package/dist/components/ai/AISessionsTab.js.map +1 -1
  33. package/dist/components/audit/AuditLogTable.js +1 -1
  34. package/dist/components/audit/AuditLogTable.js.map +1 -1
  35. package/dist/components/docs/DocsPageTree.js +1 -1
  36. package/dist/components/docs/DocsPageTree.js.map +1 -1
  37. package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
  38. package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
  39. package/dist/components/graph/MeshDeployWizard.js +3 -3
  40. package/dist/components/graph/MeshDeployWizard.js.map +1 -1
  41. package/dist/components/graph/MeshRequestPanel.js +2 -2
  42. package/dist/components/graph/MeshRequestPanel.js.map +1 -1
  43. package/dist/components/notes/NoteCard.js +1 -1
  44. package/dist/components/notes/NoteCard.js.map +1 -1
  45. package/dist/components/notes/NoteEditor.js +1 -1
  46. package/dist/components/notes/NoteEditor.js.map +1 -1
  47. package/dist/components/notes/NoteList.js +1 -1
  48. package/dist/components/notes/NoteList.js.map +1 -1
  49. package/dist/components/shared/AgentSetupBanner.js +5 -5
  50. package/dist/components/shared/AgentSetupBanner.js.map +1 -1
  51. package/dist/components/shared/InstallTabs.js +17 -56
  52. package/dist/components/shared/InstallTabs.js.map +1 -1
  53. package/dist/components/templates/TemplateCard.js +1 -1
  54. package/dist/components/templates/TemplateCard.js.map +1 -1
  55. package/dist/components/vibecalendar/types.js +1 -1
  56. package/dist/components/vibecalendar/types.js.map +1 -1
  57. package/dist/components/vibedeck/VibeDeckButtonForm.js +1 -1
  58. package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
  59. package/dist/components/vibedeck/VibeDeckExecutionLog.js +2 -2
  60. package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
  61. package/dist/components/vibedeck/VibeDeckForm.js +1 -1
  62. package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
  63. package/dist/components/vibedeck/VibeDeckGrid.js +1 -1
  64. package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
  65. package/dist/pages/AgentsPage.js +2 -2
  66. package/dist/pages/AgentsPage.js.map +1 -1
  67. package/dist/pages/CatalogDetailPage.js +1 -1
  68. package/dist/pages/CatalogDetailPage.js.map +1 -1
  69. package/dist/pages/ComponentDetailPage.js +1 -1
  70. package/dist/pages/ComponentDetailPage.js.map +1 -1
  71. package/dist/pages/GettingStartedPage.js +130 -114
  72. package/dist/pages/GettingStartedPage.js.map +1 -1
  73. package/dist/pages/OverviewPage.js +10 -10
  74. package/dist/pages/OverviewPage.js.map +1 -1
  75. package/dist/pages/PluginsCatalogPage.js +1 -1
  76. package/dist/pages/PluginsCatalogPage.js.map +1 -1
  77. package/dist/pages/SessionsPage.js +3 -3
  78. package/dist/pages/SessionsPage.js.map +1 -1
  79. package/dist/pages/SharedSessionPage.js +2 -2
  80. package/dist/pages/SharedSessionPage.js.map +1 -1
  81. package/dist/pages/TargetsPage.js +2 -2
  82. package/dist/pages/TargetsPage.js.map +1 -1
  83. package/dist/pages/TemplateDetailPage.js +2 -2
  84. package/dist/pages/TemplateDetailPage.js.map +1 -1
  85. package/dist/pages/VibesPage.js +2 -2
  86. package/dist/pages/VibesPage.js.map +1 -1
  87. package/dist/pages/WebhooksPage.js +2 -2
  88. package/dist/pages/WebhooksPage.js.map +1 -1
  89. package/dist/pages/ai/AISessionDetailPage.js +2 -2
  90. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  91. package/dist/translations/en.js +27 -52
  92. package/dist/translations/en.js.map +1 -1
  93. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"NoteList.js","names":[],"sources":["../../../src/components/notes/NoteList.tsx"],"sourcesContent":["import type { Note } from './types';\nimport { EmptyState } from '../shared/EmptyState';\nimport {\n FileText,\n Plus,\n Pin,\n Tag,\n MoreVertical,\n Edit,\n Trash2,\n PinOff,\n Lock,\n Globe,\n Share2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface NoteListProps {\n notes: Note[];\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n /** Generic-sharing entry point (full Share dialog); see NoteCard.onShareAccess. */\n onShareAccess?: (note: Note) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n}\n\nfunction NoteRow({\n note,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n}: {\n note: Note;\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n onShareAccess?: (note: Note) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n\n const formatDate = (dateStr: string) => {\n return new Date(dateStr).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const getPreview = (content: string) => {\n const text = content\n .replace(/^#+\\s+/gm, '')\n .replace(/\\n/g, ' ')\n .trim();\n return text.length > 80 ? text.slice(0, 80) + '...' : text;\n };\n\n return (\n <tr\n className=\"border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(note)}\n >\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <FileText className=\"size-4 text-status-warning-text shrink-0\" />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{note.title}</p>\n {note.isPinned && <Pin className=\"size-3 text-status-warning-text shrink-0\" />}\n {note.visibility === 'PRIVATE' ? (\n <span title=\"Private\">\n <Lock className=\"size-3 text-text-muted shrink-0\" />\n </span>\n ) : (\n <span title=\"Workspace\">\n <Globe className=\"size-3 text-text-muted shrink-0\" />\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-muted truncate max-w-[300px]\">\n {getPreview(note.content)}\n </p>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[100px]\">\n {note.vibe?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n {/* Render tagAssignments if available, otherwise fall back to legacy string tags */}\n {note.tagAssignments && note.tagAssignments.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tagAssignments.slice(0, 2).map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-[var(--color-accent-soft)] text-action-primary-bg rounded\"\n style={\n assignment.tag?.color\n ? { borderLeft: `2px solid ${assignment.tag.color}` }\n : undefined\n }\n >\n <Tag className=\"size-2.5\" />\n {assignment.tag?.label ?? assignment.tagId.slice(0, 8)}\n </span>\n ))}\n {note.tagAssignments.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tagAssignments.length - 2}\n </span>\n )}\n </div>\n ) : note.tags && note.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-2.5\" />\n {tag}\n </span>\n ))}\n {note.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-xs text-text-muted\">{formatDate(note.updatedAt)}</span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onDelete || onPin || onUnpin || onShare || onShareAccess) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-44 bg-bg-surface border border-border-default rounded-lg shadow-lg z-50\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Edit className=\"size-4\" />\n Edit\n </button>\n )}\n {onShare && note.visibility === 'PRIVATE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share with workspace\n </button>\n )}\n {onShare && note.visibility === 'WORKSPACE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Lock className=\"size-4\" />\n Make private\n </button>\n )}\n {onShareAccess && (\n <button\n type=\"button\"\n data-testid=\"note-share-access\"\n onClick={(e) => {\n e.stopPropagation();\n onShareAccess(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share access…\n </button>\n )}\n {note.isPinned && onUnpin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onUnpin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <PinOff className=\"size-4\" />\n Unpin\n </button>\n )}\n {!note.isPinned && onPin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onPin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Pin className=\"size-4\" />\n Pin\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function NoteList({\n notes,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n onCreateNew,\n isLoading,\n}: NoteListProps) {\n const tr = useTr();\n if (!isLoading && notes.length === 0) {\n return (\n <EmptyState\n icon={<FileText className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.notes.emptyTitle', 'No notes yet')}\n description={tr(\n 'vibecontrols.notes.emptyDescription',\n 'Notes help you document your development process. Create your first note to get started.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"button\"\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.notes.createNote', 'Create Note')}\n </button>\n )\n }\n />\n );\n }\n\n // Sort: pinned first, then by updated date\n const sortedNotes = [...notes].sort((a, b) => {\n if (a.isPinned && !b.isPinned) return -1;\n if (!a.isPinned && b.isPinned) return 1;\n return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();\n });\n\n return (\n <div className=\"border border-border-default rounded-lg\">\n <div className=\"overflow-x-auto rounded-lg\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tl-lg\">\n {tr('vibecontrols.notes.columnTitle', 'Title')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnVibe', 'Vibe')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnTags', 'Tags')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnUpdated', 'Updated')}\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tr-lg\">\n {tr('vibecontrols.notes.columnActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {sortedNotes.map((note) => (\n <NoteRow\n key={note.id}\n note={note}\n onOpen={onOpen}\n onEdit={onEdit}\n onDelete={onDelete}\n onPin={onPin}\n onUnpin={onUnpin}\n onShare={onShare}\n onShareAccess={onShareAccess}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAgCA,SAAS,EAAQ,EACf,SACA,WACA,WACA,aACA,UACA,YACA,YACA,oBAUC;CACD,IAAM,CAAC,GAAU,KAAe,EAAS,GAAM;AAkB/C,QACE,kBAAC,MAAD;EACE,WAAU;EACV,eAAe,IAAS,EAAK;YAF/B;GAIE,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAU,WAAU,4CAA6C,CAAA,EACjE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAU,CAAA;QAC7E,EAAK,YAAY,kBAAC,GAAD,EAAK,WAAU,4CAA6C,CAAA;QAC7E,EAAK,eAAe,YACnB,kBAAC,QAAD;SAAM,OAAM;mBACV,kBAAC,GAAD,EAAM,WAAU,mCAAoC,CAAA;SAC/C,CAAA,GAEP,kBAAC,QAAD;SAAM,OAAM;mBACV,kBAAC,GAAD,EAAO,WAAU,mCAAoC,CAAA;SAChD,CAAA;QAEL;UACN,kBAAC,KAAD;OAAG,WAAU;mBA9BH,MAAoB;QACtC,IAAM,IAAO,EACV,QAAQ,YAAY,GAAG,CACvB,QAAQ,OAAO,IAAI,CACnB,MAAM;AACT,eAAO,EAAK,SAAS,KAAK,EAAK,MAAM,GAAG,GAAG,GAAG,QAAQ;UA0BhC,EAAK,QAAQ;OACvB,CAAA,CACA;QACF;;IACH,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,QAAD;KAAM,WAAU;eACb,EAAK,MAAM,QAAQ;KACf,CAAA;IACJ,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cAEX,EAAK,kBAAkB,EAAK,eAAe,SAAS,IACnD,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAK,eAAe,MAAM,GAAG,EAAE,CAAC,KAAK,MACpC,kBAAC,QAAD;MAEE,WAAU;MACV,OACE,EAAW,KAAK,QACZ,EAAE,YAAY,aAAa,EAAW,IAAI,SAAS,GACnD,KAAA;gBANR,CASE,kBAAC,GAAD,EAAK,WAAU,YAAa,CAAA,EAC3B,EAAW,KAAK,SAAS,EAAW,MAAM,MAAM,GAAG,EAAE,CACjD;QAVA,EAAW,GAUX,CACP,EACD,EAAK,eAAe,SAAS,KAC5B,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CAAiF,KAC7E,EAAK,eAAe,SAAS,EAC1B;QAEL;SACJ,EAAK,QAAQ,EAAK,KAAK,SAAS,IAClC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAK,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC1B,kBAAC,QAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,GAAD,EAAK,WAAU,YAAa,CAAA,EAC3B,EACI;QALA,EAKA,CACP,EACD,EAAK,KAAK,SAAS,KAClB,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CAAiF,KAC7E,EAAK,KAAK,SAAS,EAChB;QAEL;SAEN,kBAAC,QAAD;KAAM,WAAU;eAA0B;KAAQ,CAAA;IAEjD,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,QAAD;KAAM,WAAU;iBA/FF,MACX,IAAI,KAAK,EAAQ,CAAC,mBAAmB,SAAS;MACnD,OAAO;MACP,KAAK;MACL,MAAM;MACP,CAAC,EA0FwD,EAAK,UAAU;KAAQ,CAAA;IAC1E,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,OAAD;KAAK,WAAU;gBACX,KAAU,KAAY,KAAS,KAAW,KAAW,MACrD,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAM;AAEd,QADA,EAAE,iBAAiB,EACnB,EAAY,CAAC,EAAS;;OAExB,WAAU;iBAEV,kBAAC,GAAD,EAAc,WAAU,gCAAiC,CAAA;OAClD,CAAA,EACR,KACC,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACG,KACC,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAO,EAAK,EACZ,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAAA,OAEpB;;QAEV,KAAW,EAAK,eAAe,aAC9B,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAQ,EAAK,EACb,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,uBAEtB;;QAEV,KAAW,EAAK,eAAe,eAC9B,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAQ,EAAK,EACb,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAAA,eAEpB;;QAEV,KACC,kBAAC,UAAD;SACE,MAAK;SACL,eAAY;SACZ,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAc,EAAK,EACnB,EAAY,GAAM;;SAEpB,WAAU;mBARZ,CAUE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,gBAEtB;;QAEV,EAAK,YAAY,KAChB,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAQ,EAAK,EACb,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,QAEtB;;QAEV,CAAC,EAAK,YAAY,KACjB,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAM,EAAK,EACX,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA,EAAA,MAEnB;;QAEV,KACC,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAS,EAAK,EACd,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,SAEtB;;QAEP;SAEJ;;KAEJ,CAAA;IACH,CAAA;GACF;;;AAIT,SAAgB,EAAS,EACvB,UACA,WACA,WACA,aACA,UACA,YACA,YACA,kBACA,gBACA,gBACgB;CAChB,IAAM,IAAK,GAAO;AAClB,KAAI,CAAC,KAAa,EAAM,WAAW,EACjC,QACE,kBAAC,GAAD;EACE,MAAM,kBAAC,GAAD,EAAU,WAAU,8BAA+B,CAAA;EACzD,OAAO,EAAG,iCAAiC,eAAe;EAC1D,aAAa,EACX,uCACA,2FACD;EACD,QACE,KACE,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAC1B,EAAG,iCAAiC,cAAc,CAC5C;;EAGb,CAAA;CAKN,IAAM,IAAc,CAAC,GAAG,EAAM,CAAC,MAAM,GAAG,MAClC,EAAE,YAAY,CAAC,EAAE,WAAiB,KAClC,CAAC,EAAE,YAAY,EAAE,WAAiB,IAC/B,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CACxE;AAEF,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;eAAd;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,kCAAkC,QAAQ;OAC3C,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,iCAAiC,OAAO;OACzC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,iCAAiC,OAAO;OACzC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,oCAAoC,UAAU;OAC/C,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,oCAAoC,UAAU;OAC/C,CAAA;MACF;QACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAY,KAAK,MAChB,kBAAC,GAAD;KAEQ;KACE;KACA;KACE;KACH;KACE;KACA;KACM;KACf,EATK,EAAK,GASV,CACF,EACI,CAAA,CACF;;GACJ,CAAA;EACF,CAAA"}
1
+ {"version":3,"file":"NoteList.js","names":[],"sources":["../../../src/components/notes/NoteList.tsx"],"sourcesContent":["import type { Note } from './types';\nimport { EmptyState } from '../shared/EmptyState';\nimport {\n FileText,\n Plus,\n Pin,\n Tag,\n MoreVertical,\n Edit,\n Trash2,\n PinOff,\n Lock,\n Globe,\n Share2,\n} from 'lucide-react';\nimport { useState } from 'react';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface NoteListProps {\n notes: Note[];\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n /** Generic-sharing entry point (full Share dialog); see NoteCard.onShareAccess. */\n onShareAccess?: (note: Note) => void;\n onCreateNew?: () => void;\n isLoading?: boolean;\n}\n\nfunction NoteRow({\n note,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n}: {\n note: Note;\n onOpen?: (note: Note) => void;\n onEdit?: (note: Note) => void;\n onDelete?: (note: Note) => void;\n onPin?: (note: Note) => void;\n onUnpin?: (note: Note) => void;\n onShare?: (note: Note) => void;\n onShareAccess?: (note: Note) => void;\n}) {\n const [showMenu, setShowMenu] = useState(false);\n\n const formatDate = (dateStr: string) => {\n return new Date(dateStr).toLocaleDateString('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n });\n };\n\n const getPreview = (content: string) => {\n const text = content\n .replace(/^#+\\s+/gm, '')\n .replace(/\\n/g, ' ')\n .trim();\n return text.length > 80 ? text.slice(0, 80) + '...' : text;\n };\n\n return (\n <tr\n className=\"border-b border-border-subtle hover:bg-bg-sunken/50 cursor-pointer transition-colors\"\n onClick={() => onOpen?.(note)}\n >\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-3 min-w-0\">\n <FileText className=\"size-4 text-status-warning-text shrink-0\" />\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{note.title}</p>\n {note.isPinned && <Pin className=\"size-3 text-status-warning-text shrink-0\" />}\n {note.visibility === 'PRIVATE' ? (\n <span title=\"Private\">\n <Lock className=\"size-3 text-text-muted shrink-0\" />\n </span>\n ) : (\n <span title=\"Workspace\">\n <Globe className=\"size-3 text-text-muted shrink-0\" />\n </span>\n )}\n </div>\n <p className=\"text-xs text-text-muted truncate max-w-[300px]\">\n {getPreview(note.content)}\n </p>\n </div>\n </div>\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-sm text-text-secondary truncate block max-w-[100px]\">\n {note.vibe?.name || '-'}\n </span>\n </td>\n <td className=\"px-4 py-3\">\n {/* Render tagAssignments if available, otherwise fall back to legacy string tags */}\n {note.tagAssignments && note.tagAssignments.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tagAssignments.slice(0, 2).map((assignment) => (\n <span\n key={assignment.id}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-[var(--color-accent-soft)] text-text-primary rounded\"\n style={\n assignment.tag?.color\n ? { borderLeft: `2px solid ${assignment.tag.color}` }\n : undefined\n }\n >\n <Tag className=\"size-2.5\" />\n {assignment.tag?.label ?? assignment.tagId.slice(0, 8)}\n </span>\n ))}\n {note.tagAssignments.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tagAssignments.length - 2}\n </span>\n )}\n </div>\n ) : note.tags && note.tags.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\">\n {note.tags.slice(0, 2).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-0.5 px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-2.5\" />\n {tag}\n </span>\n ))}\n {note.tags.length > 2 && (\n <span className=\"px-1.5 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{note.tags.length - 2}\n </span>\n )}\n </div>\n ) : (\n <span className=\"text-xs text-text-muted\">-</span>\n )}\n </td>\n <td className=\"px-4 py-3\">\n <span className=\"text-xs text-text-muted\">{formatDate(note.updatedAt)}</span>\n </td>\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center gap-1 justify-end\">\n {(onEdit || onDelete || onPin || onUnpin || onShare || onShareAccess) && (\n <div className=\"relative\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-3.5 text-text-secondary\" />\n </button>\n {showMenu && (\n <div className=\"absolute right-0 mt-1 w-44 bg-bg-surface border border-border-default rounded-lg shadow-lg z-50\">\n {onEdit && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onEdit(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Edit className=\"size-4\" />\n Edit\n </button>\n )}\n {onShare && note.visibility === 'PRIVATE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share with workspace\n </button>\n )}\n {onShare && note.visibility === 'WORKSPACE' && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onShare(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Lock className=\"size-4\" />\n Make private\n </button>\n )}\n {onShareAccess && (\n <button\n type=\"button\"\n data-testid=\"note-share-access\"\n onClick={(e) => {\n e.stopPropagation();\n onShareAccess(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Share2 className=\"size-4\" />\n Share access…\n </button>\n )}\n {note.isPinned && onUnpin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onUnpin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <PinOff className=\"size-4\" />\n Unpin\n </button>\n )}\n {!note.isPinned && onPin && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onPin(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n <Pin className=\"size-4\" />\n Pin\n </button>\n )}\n {onDelete && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDelete(note);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg\"\n >\n <Trash2 className=\"size-4\" />\n Delete\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </div>\n </td>\n </tr>\n );\n}\n\nexport function NoteList({\n notes,\n onOpen,\n onEdit,\n onDelete,\n onPin,\n onUnpin,\n onShare,\n onShareAccess,\n onCreateNew,\n isLoading,\n}: NoteListProps) {\n const tr = useTr();\n if (!isLoading && notes.length === 0) {\n return (\n <EmptyState\n icon={<FileText className=\"size-8 text-text-secondary\" />}\n title={tr('vibecontrols.notes.emptyTitle', 'No notes yet')}\n description={tr(\n 'vibecontrols.notes.emptyDescription',\n 'Notes help you document your development process. Create your first note to get started.'\n )}\n action={\n onCreateNew && (\n <button\n type=\"button\"\n onClick={onCreateNew}\n className=\"inline-flex items-center gap-2 px-4 py-2 text-sm font-medium text-action-primary-text bg-action-primary-bg rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('vibecontrols.notes.createNote', 'Create Note')}\n </button>\n )\n }\n />\n );\n }\n\n // Sort: pinned first, then by updated date\n const sortedNotes = [...notes].sort((a, b) => {\n if (a.isPinned && !b.isPinned) return -1;\n if (!a.isPinned && b.isPinned) return 1;\n return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();\n });\n\n return (\n <div className=\"border border-border-default rounded-lg\">\n <div className=\"overflow-x-auto rounded-lg\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tl-lg\">\n {tr('vibecontrols.notes.columnTitle', 'Title')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnVibe', 'Vibe')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnTags', 'Tags')}\n </th>\n <th className=\"px-4 py-2.5 text-left text-xs font-medium text-text-secondary uppercase tracking-wider\">\n {tr('vibecontrols.notes.columnUpdated', 'Updated')}\n </th>\n <th className=\"px-4 py-2.5 text-right text-xs font-medium text-text-secondary uppercase tracking-wider rounded-tr-lg\">\n {tr('vibecontrols.notes.columnActions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {sortedNotes.map((note) => (\n <NoteRow\n key={note.id}\n note={note}\n onOpen={onOpen}\n onEdit={onEdit}\n onDelete={onDelete}\n onPin={onPin}\n onUnpin={onUnpin}\n onShare={onShare}\n onShareAccess={onShareAccess}\n />\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAgCA,SAAS,EAAQ,EACf,SACA,WACA,WACA,aACA,UACA,YACA,YACA,oBAUC;CACD,IAAM,CAAC,GAAU,KAAe,EAAS,GAAM;AAkB/C,QACE,kBAAC,MAAD;EACE,WAAU;EACV,eAAe,IAAS,EAAK;YAF/B;GAIE,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAU,WAAU,4CAA6C,CAAA,EACjE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAU,CAAA;QAC7E,EAAK,YAAY,kBAAC,GAAD,EAAK,WAAU,4CAA6C,CAAA;QAC7E,EAAK,eAAe,YACnB,kBAAC,QAAD;SAAM,OAAM;mBACV,kBAAC,GAAD,EAAM,WAAU,mCAAoC,CAAA;SAC/C,CAAA,GAEP,kBAAC,QAAD;SAAM,OAAM;mBACV,kBAAC,GAAD,EAAO,WAAU,mCAAoC,CAAA;SAChD,CAAA;QAEL;UACN,kBAAC,KAAD;OAAG,WAAU;mBA9BH,MAAoB;QACtC,IAAM,IAAO,EACV,QAAQ,YAAY,GAAG,CACvB,QAAQ,OAAO,IAAI,CACnB,MAAM;AACT,eAAO,EAAK,SAAS,KAAK,EAAK,MAAM,GAAG,GAAG,GAAG,QAAQ;UA0BhC,EAAK,QAAQ;OACvB,CAAA,CACA;QACF;;IACH,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,QAAD;KAAM,WAAU;eACb,EAAK,MAAM,QAAQ;KACf,CAAA;IACJ,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cAEX,EAAK,kBAAkB,EAAK,eAAe,SAAS,IACnD,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAK,eAAe,MAAM,GAAG,EAAE,CAAC,KAAK,MACpC,kBAAC,QAAD;MAEE,WAAU;MACV,OACE,EAAW,KAAK,QACZ,EAAE,YAAY,aAAa,EAAW,IAAI,SAAS,GACnD,KAAA;gBANR,CASE,kBAAC,GAAD,EAAK,WAAU,YAAa,CAAA,EAC3B,EAAW,KAAK,SAAS,EAAW,MAAM,MAAM,GAAG,EAAE,CACjD;QAVA,EAAW,GAUX,CACP,EACD,EAAK,eAAe,SAAS,KAC5B,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CAAiF,KAC7E,EAAK,eAAe,SAAS,EAC1B;QAEL;SACJ,EAAK,QAAQ,EAAK,KAAK,SAAS,IAClC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAK,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC1B,kBAAC,QAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,GAAD,EAAK,WAAU,YAAa,CAAA,EAC3B,EACI;QALA,EAKA,CACP,EACD,EAAK,KAAK,SAAS,KAClB,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CAAiF,KAC7E,EAAK,KAAK,SAAS,EAChB;QAEL;SAEN,kBAAC,QAAD;KAAM,WAAU;eAA0B;KAAQ,CAAA;IAEjD,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,QAAD;KAAM,WAAU;iBA/FF,MACX,IAAI,KAAK,EAAQ,CAAC,mBAAmB,SAAS;MACnD,OAAO;MACP,KAAK;MACL,MAAM;MACP,CAAC,EA0FwD,EAAK,UAAU;KAAQ,CAAA;IAC1E,CAAA;GACL,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,OAAD;KAAK,WAAU;gBACX,KAAU,KAAY,KAAS,KAAW,KAAW,MACrD,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,UAAD;OACE,MAAK;OACL,UAAU,MAAM;AAEd,QADA,EAAE,iBAAiB,EACnB,EAAY,CAAC,EAAS;;OAExB,WAAU;iBAEV,kBAAC,GAAD,EAAc,WAAU,gCAAiC,CAAA;OAClD,CAAA,EACR,KACC,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACG,KACC,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAO,EAAK,EACZ,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAAA,OAEpB;;QAEV,KAAW,EAAK,eAAe,aAC9B,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAQ,EAAK,EACb,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,uBAEtB;;QAEV,KAAW,EAAK,eAAe,eAC9B,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAQ,EAAK,EACb,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAAA,eAEpB;;QAEV,KACC,kBAAC,UAAD;SACE,MAAK;SACL,eAAY;SACZ,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAc,EAAK,EACnB,EAAY,GAAM;;SAEpB,WAAU;mBARZ,CAUE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,gBAEtB;;QAEV,EAAK,YAAY,KAChB,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAQ,EAAK,EACb,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,QAEtB;;QAEV,CAAC,EAAK,YAAY,KACjB,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAM,EAAK,EACX,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA,EAAA,MAEnB;;QAEV,KACC,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,MAAM;AAGd,UAFA,EAAE,iBAAiB,EACnB,EAAS,EAAK,EACd,EAAY,GAAM;;SAEpB,WAAU;mBAPZ,CASE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAAA,SAEtB;;QAEP;SAEJ;;KAEJ,CAAA;IACH,CAAA;GACF;;;AAIT,SAAgB,EAAS,EACvB,UACA,WACA,WACA,aACA,UACA,YACA,YACA,kBACA,gBACA,gBACgB;CAChB,IAAM,IAAK,GAAO;AAClB,KAAI,CAAC,KAAa,EAAM,WAAW,EACjC,QACE,kBAAC,GAAD;EACE,MAAM,kBAAC,GAAD,EAAU,WAAU,8BAA+B,CAAA;EACzD,OAAO,EAAG,iCAAiC,eAAe;EAC1D,aAAa,EACX,uCACA,2FACD;EACD,QACE,KACE,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,EAC1B,EAAG,iCAAiC,cAAc,CAC5C;;EAGb,CAAA;CAKN,IAAM,IAAc,CAAC,GAAG,EAAM,CAAC,MAAM,GAAG,MAClC,EAAE,YAAY,CAAC,EAAE,WAAiB,KAClC,CAAC,EAAE,YAAY,EAAE,WAAiB,IAC/B,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CACxE;AAEF,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;eAAd;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,kCAAkC,QAAQ;OAC3C,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,iCAAiC,OAAO;OACzC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,iCAAiC,OAAO;OACzC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,oCAAoC,UAAU;OAC/C,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,oCAAoC,UAAU;OAC/C,CAAA;MACF;QACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAY,KAAK,MAChB,kBAAC,GAAD;KAEQ;KACE;KACA;KACE;KACH;KACE;KACA;KACM;KACf,EATK,EAAK,GASV,CACF,EACI,CAAA,CACF;;GACJ,CAAA;EACF,CAAA"}
@@ -10,7 +10,7 @@ import { Button as _ } from "@burdenoff/fe-libs/ui";
10
10
  //#region src/components/shared/AgentSetupBanner.tsx
11
11
  var v = "https://www.npmjs.com/package/@vibecontrols/agent";
12
12
  function y() {
13
- return typeof window > "u" ? "curl -fsSL https://app.vibecontrols.com/install | bash && hash -r 2>/dev/null" : `curl -fsSL https://${window.__VIBECONTROLS_HOST__ ?? window.location.host}/install | bash && hash -r 2>/dev/null`;
13
+ return "bun install -g @vibecontrols/agent";
14
14
  }
15
15
  function b({ variant: b = "compact", dismissible: x = !0, dismissKey: S = "vibecontrols-setup-banner-dismissed", className: C = "" }) {
16
16
  let w = e(), T = t(), E = i(() => y(), []), [D, O] = a(!1), [k, A] = a(() => {
@@ -57,7 +57,7 @@ function b({ variant: b = "compact", dismissible: x = !0, dismissKey: S = "vibec
57
57
  height: 0
58
58
  },
59
59
  transition: N,
60
- className: `relative flex flex-col items-start gap-3 px-4 py-3 bg-accent-purple-subtle border border-accent-purple/20 rounded-card sm:flex-row sm:items-center ${C}`,
60
+ className: `relative flex flex-col items-start gap-3 px-4 py-3 bg-bg-elevated border border-border-subtle rounded-card sm:flex-row sm:items-center ${C}`,
61
61
  children: [
62
62
  /* @__PURE__ */ h(c, { className: "size-5 text-accent-purple flex-shrink-0" }),
63
63
  /* @__PURE__ */ g("div", {
@@ -117,7 +117,7 @@ function b({ variant: b = "compact", dismissible: x = !0, dismissKey: S = "vibec
117
117
  height: 0
118
118
  },
119
119
  transition: N,
120
- className: `relative border border-accent-purple/20 bg-accent-purple-subtle rounded-card overflow-hidden ${C}`,
120
+ className: `relative border border-border-subtle bg-bg-elevated rounded-card overflow-hidden ${C}`,
121
121
  children: [x && /* @__PURE__ */ h("button", {
122
122
  type: "button",
123
123
  onClick: M,
@@ -130,14 +130,14 @@ function b({ variant: b = "compact", dismissible: x = !0, dismissKey: S = "vibec
130
130
  /* @__PURE__ */ g("div", {
131
131
  className: "flex items-start gap-3 mb-4",
132
132
  children: [/* @__PURE__ */ h("div", {
133
- className: "flex-shrink-0 size-10 rounded-lg bg-accent-purple/10 flex items-center justify-center",
133
+ className: "flex-shrink-0 size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center",
134
134
  children: /* @__PURE__ */ h(c, { className: "size-5 text-accent-purple" })
135
135
  }), /* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h3", {
136
136
  className: "text-base font-semibold text-text-primary",
137
137
  children: w("vibecontrols.shared.agentSetupBanner.title", "Get Started with VibeControls Agent")
138
138
  }), /* @__PURE__ */ h("p", {
139
139
  className: "text-sm text-text-secondary mt-0.5",
140
- children: w("vibecontrols.shared.agentSetupBanner.description", "Install the CLI on any machine you want to manage. The only prerequisite is bun — the curl script installs it for you.")
140
+ children: w("vibecontrols.shared.agentSetupBanner.description", "Install the agent globally on any machine you want to manage. Bun (or Node >= 18 for npm) is the only prerequisite.")
141
141
  })] })]
142
142
  }),
143
143
  /* @__PURE__ */ h("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"AgentSetupBanner.js","names":[],"sources":["../../../src/components/shared/AgentSetupBanner.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Download, Copy, Check, ExternalLink, X, Terminal } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { InstallTabs } from './InstallTabs';\n\ninterface AgentSetupBannerProps {\n /** Compact mode shows a single-line banner; full mode shows a multi-step card */\n variant?: 'compact' | 'full';\n /** Allow the banner to be dismissed */\n dismissible?: boolean;\n /** Storage key for dismissed state */\n dismissKey?: string;\n /** Additional CSS class names */\n className?: string;\n}\n\nconst NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/agent';\n\n/**\n * Build the quick-install one-liner using the live host so the command shown\n * to the user reflects the environment they are actually on (local dev,\n * alpha, prod). InstallTabs uses the same `resolveHost()` shape — keep them\n * aligned by reading from `window.__VIBECONTROLS_HOST__` first, then\n * falling back to `window.location.host`.\n */\nfunction getQuickInstallCommand(): string {\n // Trailing `&& hash -r` runs in the user's shell to flush a stale cached\n // `vibe` path so the new binary resolves immediately (the install script also\n // rebinds it on disk; this is belt-and-braces, harmless when nothing stale).\n if (typeof window === 'undefined') {\n return 'curl -fsSL https://app.vibecontrols.com/install | bash && hash -r 2>/dev/null';\n }\n const injected = (window as { __VIBECONTROLS_HOST__?: string }).__VIBECONTROLS_HOST__;\n const host = injected ?? window.location.host;\n return `curl -fsSL https://${host}/install | bash && hash -r 2>/dev/null`;\n}\n\n/**\n * Reusable banner/card prompting users to install the VibeControls Agent CLI.\n * Used across multiple pages (Overview, Agents, Sessions, Tunnels, SSH, etc.)\n *\n * The full variant mirrors the Getting Started page's tabbed install widget\n * (`InstallTabs`) so users see a single consistent install flow wherever\n * the banner shows up.\n */\nexport function AgentSetupBanner({\n variant = 'compact',\n dismissible = true,\n dismissKey = 'vibecontrols-setup-banner-dismissed',\n className = '',\n}: AgentSetupBannerProps) {\n const tr = useTr();\n const handleNavigate = useVibeNavigate();\n const quickInstall = useMemo(() => getQuickInstallCommand(), []);\n const [copied, setCopied] = useState(false);\n const [dismissed, setDismissed] = useState(() => {\n try {\n return localStorage.getItem(getProfileScopedKey(dismissKey)) === 'true';\n } catch {\n return false;\n }\n });\n\n const handleCopy = useCallback(async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n const el = document.createElement('textarea');\n el.value = text;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n }, []);\n\n const handleDismiss = useCallback(() => {\n setDismissed(true);\n try {\n localStorage.setItem(getProfileScopedKey(dismissKey), 'true');\n } catch {\n // ignore\n }\n }, [dismissKey]);\n\n const bannerTransition = { duration: 0.3, ease: [0.4, 0, 0.2, 1] as const };\n\n // ─── Compact variant: single-line info banner ─────────────────────────\n if (variant === 'compact') {\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative flex flex-col items-start gap-3 px-4 py-3 bg-accent-purple-subtle border border-accent-purple/20 rounded-card sm:flex-row sm:items-center ${className}`}\n >\n <Download className=\"size-5 text-accent-purple flex-shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-x-3 gap-y-1\">\n <span className=\"text-sm font-medium text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.installPrompt',\n 'Install the VibeControls Agent CLI to get started'\n )}\n </span>\n <code\n className=\"inline-flex min-w-0 max-w-full items-center gap-1.5 rounded border border-border-subtle bg-bg-sunken px-2.5 py-1 font-mono text-xs text-text-primary transition-colors hover:bg-bg-elevated cursor-pointer\"\n onClick={() => handleCopy(quickInstall)}\n title={tr('vibecontrols.shared.agentSetupBanner.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-3\" />\n <span className=\"min-w-0 break-all\">{quickInstall}</span>\n {copied ? (\n <Check className=\"size-3 text-status-success-text\" />\n ) : (\n <Copy className=\"size-3 text-text-muted\" />\n )}\n </code>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"text-sm text-accent-purple hover:underline flex items-center gap-1\"\n >\n {tr('vibecontrols.shared.agentSetupBanner.setupGuide', 'Setup guide')}{' '}\n <ExternalLink className=\"size-3\" />\n </button>\n </div>\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"flex-shrink-0 p-1 text-text-muted hover:text-text-secondary rounded transition-colors\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n );\n }\n\n // ─── Full variant: tabbed install card (mirrors Getting Started) ──────\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative border border-accent-purple/20 bg-accent-purple-subtle rounded-card overflow-hidden ${className}`}\n >\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"absolute top-3 right-3 p-1 text-text-muted hover:text-text-secondary rounded transition-colors z-10\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n\n <div className=\"p-5 sm:p-6\">\n <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"flex-shrink-0 size-10 rounded-lg bg-accent-purple/10 flex items-center justify-center\">\n <Download className=\"size-5 text-accent-purple\" />\n </div>\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.title',\n 'Get Started with VibeControls Agent'\n )}\n </h3>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.description',\n 'Install the CLI on any machine you want to manage. The only prerequisite is bun — the curl script installs it for you.'\n )}\n </p>\n </div>\n </div>\n\n {/* Tabbed install widget mirrors the Getting Started page */}\n <div className=\"ml-0 sm:ml-13\">\n <InstallTabs compact />\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-wrap items-center gap-3 mt-5 ml-0 sm:ml-13\">\n <Button\n variant=\"default\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"gap-2\"\n >\n {tr(\n 'vibecontrols.shared.agentSetupBanner.viewFullSetupGuide',\n 'View full setup guide'\n )}\n <ExternalLink className=\"size-3.5\" />\n </Button>\n <Button variant=\"outline\" asChild className=\"gap-2\">\n <a href={NPM_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n {tr('vibecontrols.shared.agentSetupBanner.npmPackage', 'npm package')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </Button>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":";;;;;;;;;;AAoBA,IAAM,IAAU;AAShB,SAAS,IAAiC;AASxC,QALI,OAAO,SAAW,MACb,kFAIF,sBAFW,OAA8C,yBACvC,OAAO,SAAS,KACP;;AAWpC,SAAgB,EAAiB,EAC/B,aAAU,WACV,iBAAc,IACd,gBAAa,uCACb,eAAY,MACY;CACxB,IAAM,IAAK,GAAO,EACZ,IAAiB,GAAiB,EAClC,IAAe,QAAc,GAAwB,EAAE,EAAE,CAAC,EAC1D,CAAC,GAAQ,KAAa,EAAS,GAAM,EACrC,CAAC,GAAW,KAAgB,QAAe;AAC/C,MAAI;AACF,UAAO,aAAa,QAAQ,EAAoB,EAAW,CAAC,KAAK;UAC3D;AACN,UAAO;;GAET,EAEI,IAAa,EAAY,OAAO,MAAiB;AACrD,MAAI;AAGF,GAFA,MAAM,UAAU,UAAU,UAAU,EAAK,EACzC,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;UAClC;GACN,IAAM,IAAK,SAAS,cAAc,WAAW;AAO7C,GANA,EAAG,QAAQ,GACX,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAG,QAAQ,EACX,SAAS,YAAY,OAAO,EAC5B,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;;IAEzC,EAAE,CAAC,EAEA,IAAgB,QAAkB;AACtC,IAAa,GAAK;AAClB,MAAI;AACF,gBAAa,QAAQ,EAAoB,EAAW,EAAE,OAAO;UACvD;IAGP,CAAC,EAAW,CAAC,EAEV,IAAmB;EAAE,UAAU;EAAK,MAAM;GAAC;GAAK;GAAG;GAAK;GAAE;EAAW;AA6D3E,QA1DI,MAAY,YAEZ,kBAAC,GAAD,EAAA,UACG,CAAC,KACA,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAI,QAAQ;GAAG;EACzC,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG,QAAQ;GAAQ;EAC7C,MAAM;GAAE,SAAS;GAAG,GAAG;GAAI,QAAQ;GAAG;EACtC,YAAY;EACZ,WAAW,sJAAsJ;YALnK;GAOE,kBAAC,GAAD,EAAU,WAAU,2CAA4C,CAAA;GAChE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,QAAD;MAAM,WAAU;gBACb,EACC,sDACA,oDACD;MACI,CAAA;KACP,kBAAC,QAAD;MACE,WAAU;MACV,eAAe,EAAW,EAAa;MACvC,OAAO,EAAG,oDAAoD,gBAAgB;gBAHhF;OAKE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;OAC/B,kBAAC,QAAD;QAAM,WAAU;kBAAqB;QAAoB,CAAA;OACxD,IACC,kBAAC,GAAD,EAAO,WAAU,mCAAoC,CAAA,GAErD,kBAAC,GAAD,EAAM,WAAU,0BAA2B,CAAA;OAExC;;KACP,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAe,mBAAmB;MACjD,WAAU;gBAHZ;OAKG,EAAG,mDAAmD,cAAc;OAAE;OACvE,kBAAC,GAAD,EAAc,WAAU,UAAW,CAAA;OAC5B;;KACL;;GACL,KACC,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;IACV,OAAO,EAAG,gDAAgD,UAAU;cAEpE,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;IACjB,CAAA;GAEA;KAEC,CAAA,GAMpB,kBAAC,GAAD,EAAA,UACG,CAAC,KACA,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAI,QAAQ;GAAG;EACzC,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG,QAAQ;GAAQ;EAC7C,MAAM;GAAE,SAAS;GAAG,GAAG;GAAI,QAAQ;GAAG;EACtC,YAAY;EACZ,WAAW,gGAAgG;YAL7G,CAOG,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,OAAO,EAAG,gDAAgD,UAAU;aAEpE,kBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;GACjB,CAAA,EAGX,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,GAAD,EAAU,WAAU,6BAA8B,CAAA;MAC9C,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EACC,8CACA,sCACD;MACE,CAAA,EACL,kBAAC,KAAD;MAAG,WAAU;gBACV,EACC,oDACA,yHACD;MACC,CAAA,CACA,EAAA,CAAA,CACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAa,SAAA,IAAU,CAAA;KACnB,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,SAAQ;MACR,eAAe,EAAe,mBAAmB;MACjD,WAAU;gBAHZ,CAKG,EACC,2DACA,wBACD,EACD,kBAAC,GAAD,EAAc,WAAU,YAAa,CAAA,CAC9B;SACT,kBAAC,GAAD;MAAQ,SAAQ;MAAU,SAAA;MAAQ,WAAU;gBAC1C,kBAAC,KAAD;OAAG,MAAM;OAAS,QAAO;OAAS,KAAI;iBAAtC,CACG,EAAG,mDAAmD,cAAc,EACrE,kBAAC,GAAD,EAAc,WAAU,YAAa,CAAA,CACnC;;MACG,CAAA,CACL;;IACF;KACK;KAEC,CAAA"}
1
+ {"version":3,"file":"AgentSetupBanner.js","names":[],"sources":["../../../src/components/shared/AgentSetupBanner.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport { Download, Copy, Check, ExternalLink, X, Terminal } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { getProfileScopedKey } from '@burdenoff/fe-libs/shared/utils';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { InstallTabs } from './InstallTabs';\n\ninterface AgentSetupBannerProps {\n /** Compact mode shows a single-line banner; full mode shows a multi-step card */\n variant?: 'compact' | 'full';\n /** Allow the banner to be dismissed */\n dismissible?: boolean;\n /** Storage key for dismissed state */\n dismissKey?: string;\n /** Additional CSS class names */\n className?: string;\n}\n\nconst NPM_URL = 'https://www.npmjs.com/package/@vibecontrols/agent';\n\n/**\n * The documented quick-install command — install the agent globally with bun\n * (the platform default). Mirrors `InstallTabs`' recommended method so the\n * banner and the Getting Started guide stay in sync.\n *\n * Official docs: https://docs.vibecontrols.com/users/installing-the-agent\n */\nfunction getQuickInstallCommand(): string {\n return 'bun install -g @vibecontrols/agent';\n}\n\n/**\n * Reusable banner/card prompting users to install the VibeControls Agent CLI.\n * Used across multiple pages (Overview, Agents, Sessions, Tunnels, SSH, etc.)\n *\n * The full variant mirrors the Getting Started page's tabbed install widget\n * (`InstallTabs`) so users see a single consistent install flow wherever\n * the banner shows up.\n */\nexport function AgentSetupBanner({\n variant = 'compact',\n dismissible = true,\n dismissKey = 'vibecontrols-setup-banner-dismissed',\n className = '',\n}: AgentSetupBannerProps) {\n const tr = useTr();\n const handleNavigate = useVibeNavigate();\n const quickInstall = useMemo(() => getQuickInstallCommand(), []);\n const [copied, setCopied] = useState(false);\n const [dismissed, setDismissed] = useState(() => {\n try {\n return localStorage.getItem(getProfileScopedKey(dismissKey)) === 'true';\n } catch {\n return false;\n }\n });\n\n const handleCopy = useCallback(async (text: string) => {\n try {\n await navigator.clipboard.writeText(text);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n const el = document.createElement('textarea');\n el.value = text;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n }, []);\n\n const handleDismiss = useCallback(() => {\n setDismissed(true);\n try {\n localStorage.setItem(getProfileScopedKey(dismissKey), 'true');\n } catch {\n // ignore\n }\n }, [dismissKey]);\n\n const bannerTransition = { duration: 0.3, ease: [0.4, 0, 0.2, 1] as const };\n\n // ─── Compact variant: single-line info banner ─────────────────────────\n if (variant === 'compact') {\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative flex flex-col items-start gap-3 px-4 py-3 bg-bg-elevated border border-border-subtle rounded-card sm:flex-row sm:items-center ${className}`}\n >\n <Download className=\"size-5 text-accent-purple flex-shrink-0\" />\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-x-3 gap-y-1\">\n <span className=\"text-sm font-medium text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.installPrompt',\n 'Install the VibeControls Agent CLI to get started'\n )}\n </span>\n <code\n className=\"inline-flex min-w-0 max-w-full items-center gap-1.5 rounded border border-border-subtle bg-bg-sunken px-2.5 py-1 font-mono text-xs text-text-primary transition-colors hover:bg-bg-elevated cursor-pointer\"\n onClick={() => handleCopy(quickInstall)}\n title={tr('vibecontrols.shared.agentSetupBanner.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-3\" />\n <span className=\"min-w-0 break-all\">{quickInstall}</span>\n {copied ? (\n <Check className=\"size-3 text-status-success-text\" />\n ) : (\n <Copy className=\"size-3 text-text-muted\" />\n )}\n </code>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"text-sm text-accent-purple hover:underline flex items-center gap-1\"\n >\n {tr('vibecontrols.shared.agentSetupBanner.setupGuide', 'Setup guide')}{' '}\n <ExternalLink className=\"size-3\" />\n </button>\n </div>\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"flex-shrink-0 p-1 text-text-muted hover:text-text-secondary rounded transition-colors\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n );\n }\n\n // ─── Full variant: tabbed install card (mirrors Getting Started) ──────\n return (\n <AnimatePresence>\n {!dismissed && (\n <motion.div\n initial={{ opacity: 0, y: -8, height: 0 }}\n animate={{ opacity: 1, y: 0, height: 'auto' }}\n exit={{ opacity: 0, y: -8, height: 0 }}\n transition={bannerTransition}\n className={`relative border border-border-subtle bg-bg-elevated rounded-card overflow-hidden ${className}`}\n >\n {dismissible && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"absolute top-3 right-3 p-1 text-text-muted hover:text-text-secondary rounded transition-colors z-10\"\n title={tr('vibecontrols.shared.agentSetupBanner.dismiss', 'Dismiss')}\n >\n <X className=\"size-4\" />\n </button>\n )}\n\n <div className=\"p-5 sm:p-6\">\n <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"flex-shrink-0 size-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Download className=\"size-5 text-accent-purple\" />\n </div>\n <div>\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.title',\n 'Get Started with VibeControls Agent'\n )}\n </h3>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {tr(\n 'vibecontrols.shared.agentSetupBanner.description',\n 'Install the agent globally on any machine you want to manage. Bun (or Node >= 18 for npm) is the only prerequisite.'\n )}\n </p>\n </div>\n </div>\n\n {/* Tabbed install widget mirrors the Getting Started page */}\n <div className=\"ml-0 sm:ml-13\">\n <InstallTabs compact />\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-wrap items-center gap-3 mt-5 ml-0 sm:ml-13\">\n <Button\n variant=\"default\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"gap-2\"\n >\n {tr(\n 'vibecontrols.shared.agentSetupBanner.viewFullSetupGuide',\n 'View full setup guide'\n )}\n <ExternalLink className=\"size-3.5\" />\n </Button>\n <Button variant=\"outline\" asChild className=\"gap-2\">\n <a href={NPM_URL} target=\"_blank\" rel=\"noopener noreferrer\">\n {tr('vibecontrols.shared.agentSetupBanner.npmPackage', 'npm package')}\n <ExternalLink className=\"size-3.5\" />\n </a>\n </Button>\n </div>\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n );\n}\n"],"mappings":"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"}
@@ -4,10 +4,7 @@ import { Check as i, Copy as a, Terminal as o } from "lucide-react";
4
4
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
5
5
  import { Tabs as l } from "@burdenoff/fe-libs/chrome";
6
6
  //#region src/components/shared/InstallTabs.tsx
7
- function u() {
8
- return typeof window > "u" ? "vibecontrols.local.burdenoff.com" : window.__VIBECONTROLS_HOST__ ?? window.location.host;
9
- }
10
- function d({ command: n }) {
7
+ function u({ command: n }) {
11
8
  let l = e(), [u, d] = r(!1), f = t(async () => {
12
9
  try {
13
10
  await navigator.clipboard.writeText(n);
@@ -36,75 +33,39 @@ function d({ command: n }) {
36
33
  ]
37
34
  });
38
35
  }
39
- function f({ pinnedAgentVersion: t, compact: i = !1 }) {
40
- let a = e(), o = u(), [f, p] = r("curl"), [m, h] = r("linux"), g = n(() => [{
41
- id: "curl",
42
- label: a("vibecontrols.shared.installTabs.curlRecommended", "Curl (Recommended)")
36
+ function d({ pinnedAgentVersion: t, compact: i = !1 }) {
37
+ let a = e(), [o, d] = r("bun"), f = n(() => [{
38
+ id: "bun",
39
+ label: a("vibecontrols.shared.installTabs.bunRecommended", "Bun (Recommended)")
43
40
  }, {
44
41
  id: "npm",
45
42
  label: a("vibecontrols.shared.installTabs.npm", "NPM")
46
- }], [a]), _ = n(() => [
47
- {
48
- id: "linux",
49
- label: a("vibecontrols.shared.installTabs.linux", "Linux")
50
- },
51
- {
52
- id: "macos",
53
- label: a("vibecontrols.shared.installTabs.macos", "macOS")
54
- },
55
- {
56
- id: "windows",
57
- label: a("vibecontrols.shared.installTabs.windows", "Windows")
58
- }
59
- ], [a]), v = n(() => {
43
+ }], [a]), p = n(() => {
60
44
  let e = t ? `@${t}` : "@latest";
61
- return f === "curl" ? m === "windows" ? `powershell -c "irm ${o}/install.ps1 | iex"` : `curl -fsSL https://${o}/install | bash && hash -r 2>/dev/null` : `npm install -g @vibecontrols/agent${e}`;
62
- }, [
63
- f,
64
- m,
65
- o,
66
- t
67
- ]), y = f === "curl" ? m === "windows" ? `https://${o}/install.ps1` : `https://${o}/install` : null;
45
+ return o === "bun" ? `bun install -g @vibecontrols/agent${e}` : `npm install -g @vibecontrols/agent${e}`;
46
+ }, [o, t]);
68
47
  return /* @__PURE__ */ c("div", {
69
48
  className: i ? "space-y-3" : "space-y-4",
70
49
  children: [
71
50
  /* @__PURE__ */ s(l, {
72
- items: g,
73
- activeTabId: f,
74
- onTabChange: (e) => p(e),
51
+ items: f,
52
+ activeTabId: o,
53
+ onTabChange: (e) => d(e),
75
54
  variant: "underline"
76
55
  }),
77
- /* @__PURE__ */ s(l, {
78
- items: _,
79
- activeTabId: m,
80
- onTabChange: (e) => h(e),
81
- variant: "pills",
82
- size: "sm"
83
- }),
84
- /* @__PURE__ */ s(d, { command: v }),
85
- f === "curl" && y && /* @__PURE__ */ c("p", {
56
+ /* @__PURE__ */ s(u, { command: p }),
57
+ o === "bun" && /* @__PURE__ */ s("p", {
86
58
  className: "text-xs text-text-muted",
87
- children: [
88
- a("vibecontrols.shared.installTabs.curlDescription", "The script installs bun (pinned, v1.3.10) then installs @vibecontrols/agent and core plugins. Only bun is required on your machine — no other prerequisites. The trailing “&& hash -r” refreshes your shell so “vibe” works immediately (using fish? drop it — fish auto-rehashes)."),
89
- " ",
90
- /* @__PURE__ */ s("a", {
91
- href: y,
92
- target: "_blank",
93
- rel: "noreferrer",
94
- className: "text-text-link hover:text-text-linkHover hover:underline",
95
- children: a("vibecontrols.shared.installTabs.viewInstallScript", "View the install script")
96
- }),
97
- "."
98
- ]
59
+ children: a("vibecontrols.shared.installTabs.bunDescription", "Bun is the platform default and the only prerequisite. You can pin a specific release with @<version> (defaults to the latest).")
99
60
  }),
100
- f === "npm" && /* @__PURE__ */ s("p", {
61
+ o === "npm" && /* @__PURE__ */ s("p", {
101
62
  className: "text-xs text-text-muted",
102
- children: a("vibecontrols.shared.installTabs.npmDescription", "Requires Node.js >= 18. You can also pass @<version> to pin a specific release.")
63
+ children: a("vibecontrols.shared.installTabs.npmDescription", "Requires Node.js >= 18. You can pin a specific release with @<version> (defaults to the latest).")
103
64
  })
104
65
  ]
105
66
  });
106
67
  }
107
68
  //#endregion
108
- export { f as InstallTabs };
69
+ export { d as InstallTabs };
109
70
 
110
71
  //# sourceMappingURL=InstallTabs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InstallTabs.js","names":[],"sources":["../../../src/components/shared/InstallTabs.tsx"],"sourcesContent":["import { useMemo, useState, useCallback } from 'react';\nimport { Copy, Check, Terminal } from 'lucide-react';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useTr } from '../../shared/hooks/useTr';\n\ntype InstallMethod = 'curl' | 'npm';\ntype InstallOs = 'linux' | 'macos' | 'windows';\n\n/**\n * Resolves the current host for the curl install URL so the instructions\n * always match the environment the user is looking at (local / alpha / prod).\n * The `VIBECONTROLS_HOST` global can be set by the shell if it needs to\n * override (e.g. for previews), otherwise we read from `window.location`.\n */\nfunction resolveHost(): string {\n if (typeof window === 'undefined') return 'vibecontrols.local.burdenoff.com';\n const injected = (window as unknown as { __VIBECONTROLS_HOST__?: string }).__VIBECONTROLS_HOST__;\n return injected ?? window.location.host;\n}\n\nfunction CopyableCommand({ command }: { command: string }) {\n const tr = useTr();\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(command);\n } catch {\n const el = document.createElement('textarea');\n el.value = command;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [command]);\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleCopy}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleCopy();\n }}\n className=\"flex items-center gap-2 px-3 py-2.5 bg-bg-sunken border border-border-default rounded-md cursor-pointer hover:bg-bg-elevated transition-colors group\"\n title={tr('vibecontrols.shared.installTabs.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-4 text-text-muted flex-shrink-0\" />\n <code className=\"text-sm font-mono text-text-primary flex-1 break-all\">{command}</code>\n {copied ? (\n <Check className=\"size-4 text-status-success-text flex-shrink-0\" />\n ) : (\n <Copy className=\"size-4 text-text-muted group-hover:text-text-secondary flex-shrink-0\" />\n )}\n </div>\n );\n}\n\nexport interface InstallTabsProps {\n /** Optional pinned agent version to embed in instructions */\n pinnedAgentVersion?: string;\n /** Optional compact layout when rendered inside a narrow callout card */\n compact?: boolean;\n}\n\n/**\n * Unified install instructions widget used by the Getting Started page and\n * the Agents \"Get started\" callout. Two top tabs — Curl (preferred) and\n * NPM — each with Linux/macOS/Windows sub-tabs, so the user always sees a\n * single command they can copy.\n *\n * The curl install script is served by the app shell at `/install` (bash)\n * and `/install.ps1` (PowerShell). The only prerequisite is bun, which the\n * script installs automatically at a pinned version.\n */\nexport function InstallTabs({ pinnedAgentVersion, compact = false }: InstallTabsProps) {\n const tr = useTr();\n const host = resolveHost();\n const [method, setMethod] = useState<InstallMethod>('curl');\n const [os, setOs] = useState<InstallOs>('linux');\n\n const methodTabs: TabItem[] = useMemo(\n () => [\n {\n id: 'curl',\n label: tr('vibecontrols.shared.installTabs.curlRecommended', 'Curl (Recommended)'),\n },\n { id: 'npm', label: tr('vibecontrols.shared.installTabs.npm', 'NPM') },\n ],\n [tr]\n );\n\n const osTabs: TabItem[] = useMemo(\n () => [\n { id: 'linux', label: tr('vibecontrols.shared.installTabs.linux', 'Linux') },\n { id: 'macos', label: tr('vibecontrols.shared.installTabs.macos', 'macOS') },\n { id: 'windows', label: tr('vibecontrols.shared.installTabs.windows', 'Windows') },\n ],\n [tr]\n );\n\n // Resolve the actual command string per (method, os).\n const command = useMemo(() => {\n const agentSuffix = pinnedAgentVersion ? `@${pinnedAgentVersion}` : '@latest';\n if (method === 'curl') {\n if (os === 'windows') {\n return `powershell -c \"irm ${host}/install.ps1 | iex\"`;\n }\n // The trailing `&& hash -r` runs in the user's shell (right of the pipe),\n // flushing any stale cached `vibe` path so the freshly-installed binary\n // resolves immediately — no manual `hash -r` / new terminal. The install\n // script also rebinds a stale path on disk, so this is belt-and-braces\n // (and a harmless no-op when nothing is cached). fish users: drop it.\n return `curl -fsSL https://${host}/install | bash && hash -r 2>/dev/null`;\n }\n // npm\n return `npm install -g @vibecontrols/agent${agentSuffix}`;\n }, [method, os, host, pinnedAgentVersion]);\n\n const scriptUrl =\n method === 'curl'\n ? os === 'windows'\n ? `https://${host}/install.ps1`\n : `https://${host}/install`\n : null;\n\n return (\n <div className={compact ? 'space-y-3' : 'space-y-4'}>\n <Tabs\n items={methodTabs}\n activeTabId={method}\n onTabChange={(id) => setMethod(id as InstallMethod)}\n variant=\"underline\"\n />\n\n <Tabs\n items={osTabs}\n activeTabId={os}\n onTabChange={(id) => setOs(id as InstallOs)}\n variant=\"pills\"\n size=\"sm\"\n />\n\n <CopyableCommand command={command} />\n\n {method === 'curl' && scriptUrl && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.curlDescription',\n 'The script installs bun (pinned, v1.3.10) then installs @vibecontrols/agent and core plugins. Only bun is required on your machine — no other prerequisites. The trailing “&& hash -r” refreshes your shell so “vibe” works immediately (using fish? drop it — fish auto-rehashes).'\n )}{' '}\n <a\n href={scriptUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"text-text-link hover:text-text-linkHover hover:underline\"\n >\n {tr('vibecontrols.shared.installTabs.viewInstallScript', 'View the install script')}\n </a>\n .\n </p>\n )}\n {method === 'npm' && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.npmDescription',\n 'Requires Node.js >= 18. You can also pass @<version> to pin a specific release.'\n )}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAcA,SAAS,IAAsB;AAG7B,QAFI,OAAO,SAAW,MAAoB,qCACxB,OAAyD,yBACxD,OAAO,SAAS;;AAGrC,SAAS,EAAgB,EAAE,cAAgC;CACzD,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAS,GAAM,EACrC,IAAa,EAAY,YAAY;AACzC,MAAI;AACF,SAAM,UAAU,UAAU,UAAU,EAAQ;UACtC;GACN,IAAM,IAAK,SAAS,cAAc,WAAW;AAK7C,GAJA,EAAG,QAAQ,GACX,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAG,QAAQ,EACX,SAAS,YAAY,OAAO,EAC5B,SAAS,KAAK,YAAY,EAAG;;AAG/B,EADA,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;IACvC,CAAC,EAAQ,CAAC;AAEb,QACE,kBAAC,OAAD;EACE,MAAK;EACL,UAAU;EACV,SAAS;EACT,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAK,GAAY;;EAEtD,WAAU;EACV,OAAO,EAAG,+CAA+C,gBAAgB;YAR3E;GAUE,kBAAC,GAAD,EAAU,WAAU,wCAAyC,CAAA;GAC7D,kBAAC,QAAD;IAAM,WAAU;cAAwD;IAAe,CAAA;GACtF,IACC,kBAAC,GAAD,EAAO,WAAU,iDAAkD,CAAA,GAEnE,kBAAC,GAAD,EAAM,WAAU,wEAAyE,CAAA;GAEvF;;;AAqBV,SAAgB,EAAY,EAAE,uBAAoB,aAAU,MAA2B;CACrF,IAAM,IAAK,GAAO,EACZ,IAAO,GAAa,EACpB,CAAC,GAAQ,KAAa,EAAwB,OAAO,EACrD,CAAC,GAAI,KAAS,EAAoB,QAAQ,EAE1C,IAAwB,QACtB,CACJ;EACE,IAAI;EACJ,OAAO,EAAG,mDAAmD,qBAAqB;EACnF,EACD;EAAE,IAAI;EAAO,OAAO,EAAG,uCAAuC,MAAM;EAAE,CACvE,EACD,CAAC,EAAG,CACL,EAEK,IAAoB,QAClB;EACJ;GAAE,IAAI;GAAS,OAAO,EAAG,yCAAyC,QAAQ;GAAE;EAC5E;GAAE,IAAI;GAAS,OAAO,EAAG,yCAAyC,QAAQ;GAAE;EAC5E;GAAE,IAAI;GAAW,OAAO,EAAG,2CAA2C,UAAU;GAAE;EACnF,EACD,CAAC,EAAG,CACL,EAGK,IAAU,QAAc;EAC5B,IAAM,IAAc,IAAqB,IAAI,MAAuB;AAapE,SAZI,MAAW,SACT,MAAO,YACF,sBAAsB,EAAK,uBAO7B,sBAAsB,EAAK,0CAG7B,qCAAqC;IAC3C;EAAC;EAAQ;EAAI;EAAM;EAAmB,CAAC,EAEpC,IACJ,MAAW,SACP,MAAO,YACL,WAAW,EAAK,gBAChB,WAAW,EAAK,YAClB;AAEN,QACE,kBAAC,OAAD;EAAK,WAAW,IAAU,cAAc;YAAxC;GACE,kBAAC,GAAD;IACE,OAAO;IACP,aAAa;IACb,cAAc,MAAO,EAAU,EAAoB;IACnD,SAAQ;IACR,CAAA;GAEF,kBAAC,GAAD;IACE,OAAO;IACP,aAAa;IACb,cAAc,MAAO,EAAM,EAAgB;IAC3C,SAAQ;IACR,MAAK;IACL,CAAA;GAEF,kBAAC,GAAD,EAA0B,YAAW,CAAA;GAEpC,MAAW,UAAU,KACpB,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EACC,mDACA,sRACD;KAAE;KACH,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;gBAET,EAAG,qDAAqD,0BAA0B;MACjF,CAAA;;KAEF;;GAEL,MAAW,SACV,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kDACA,kFACD;IACC,CAAA;GAEF"}
1
+ {"version":3,"file":"InstallTabs.js","names":[],"sources":["../../../src/components/shared/InstallTabs.tsx"],"sourcesContent":["import { useMemo, useState, useCallback } from 'react';\nimport { Copy, Check, Terminal } from 'lucide-react';\nimport { Tabs, type TabItem } from '@burdenoff/fe-libs/chrome';\nimport { useTr } from '../../shared/hooks/useTr';\n\ntype InstallMethod = 'bun' | 'npm';\n\nfunction CopyableCommand({ command }: { command: string }) {\n const tr = useTr();\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(command);\n } catch {\n const el = document.createElement('textarea');\n el.value = command;\n document.body.appendChild(el);\n el.select();\n document.execCommand('copy');\n document.body.removeChild(el);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [command]);\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleCopy}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') handleCopy();\n }}\n className=\"flex items-center gap-2 px-3 py-2.5 bg-bg-sunken border border-border-default rounded-md cursor-pointer hover:bg-bg-elevated transition-colors group\"\n title={tr('vibecontrols.shared.installTabs.clickToCopy', 'Click to copy')}\n >\n <Terminal className=\"size-4 text-text-muted flex-shrink-0\" />\n <code className=\"text-sm font-mono text-text-primary flex-1 break-all\">{command}</code>\n {copied ? (\n <Check className=\"size-4 text-status-success-text flex-shrink-0\" />\n ) : (\n <Copy className=\"size-4 text-text-muted group-hover:text-text-secondary flex-shrink-0\" />\n )}\n </div>\n );\n}\n\nexport interface InstallTabsProps {\n /** Optional pinned agent version to embed in instructions */\n pinnedAgentVersion?: string;\n /** Optional compact layout when rendered inside a narrow callout card */\n compact?: boolean;\n}\n\n/**\n * Unified install instructions widget used by the Getting Started page and\n * the Agents \"Get started\" callout. Two tabs — Bun (recommended, the platform\n * default) and NPM — each showing a single global install command the user\n * can copy. Bun (or Node >= 18 for npm) is the only prerequisite; an\n * optional `@<version>` suffix pins a specific release.\n *\n * Official docs: https://docs.vibecontrols.com/users/installing-the-agent\n */\nexport function InstallTabs({ pinnedAgentVersion, compact = false }: InstallTabsProps) {\n const tr = useTr();\n const [method, setMethod] = useState<InstallMethod>('bun');\n\n const methodTabs: TabItem[] = useMemo(\n () => [\n {\n id: 'bun',\n label: tr('vibecontrols.shared.installTabs.bunRecommended', 'Bun (Recommended)'),\n },\n { id: 'npm', label: tr('vibecontrols.shared.installTabs.npm', 'NPM') },\n ],\n [tr]\n );\n\n // Resolve the global install command for the selected package manager.\n // The `@<version>` suffix pins a release; default is `@latest`.\n const command = useMemo(() => {\n const ver = pinnedAgentVersion ? `@${pinnedAgentVersion}` : '@latest';\n if (method === 'bun') {\n return `bun install -g @vibecontrols/agent${ver}`;\n }\n return `npm install -g @vibecontrols/agent${ver}`;\n }, [method, pinnedAgentVersion]);\n\n return (\n <div className={compact ? 'space-y-3' : 'space-y-4'}>\n <Tabs\n items={methodTabs}\n activeTabId={method}\n onTabChange={(id) => setMethod(id as InstallMethod)}\n variant=\"underline\"\n />\n\n <CopyableCommand command={command} />\n\n {method === 'bun' && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.bunDescription',\n 'Bun is the platform default and the only prerequisite. You can pin a specific release with @<version> (defaults to the latest).'\n )}\n </p>\n )}\n {method === 'npm' && (\n <p className=\"text-xs text-text-muted\">\n {tr(\n 'vibecontrols.shared.installTabs.npmDescription',\n 'Requires Node.js >= 18. You can pin a specific release with @<version> (defaults to the latest).'\n )}\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAOA,SAAS,EAAgB,EAAE,cAAgC;CACzD,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAS,GAAM,EACrC,IAAa,EAAY,YAAY;AACzC,MAAI;AACF,SAAM,UAAU,UAAU,UAAU,EAAQ;UACtC;GACN,IAAM,IAAK,SAAS,cAAc,WAAW;AAK7C,GAJA,EAAG,QAAQ,GACX,SAAS,KAAK,YAAY,EAAG,EAC7B,EAAG,QAAQ,EACX,SAAS,YAAY,OAAO,EAC5B,SAAS,KAAK,YAAY,EAAG;;AAG/B,EADA,EAAU,GAAK,EACf,iBAAiB,EAAU,GAAM,EAAE,IAAK;IACvC,CAAC,EAAQ,CAAC;AAEb,QACE,kBAAC,OAAD;EACE,MAAK;EACL,UAAU;EACV,SAAS;EACT,YAAY,MAAM;AAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,QAAK,GAAY;;EAEtD,WAAU;EACV,OAAO,EAAG,+CAA+C,gBAAgB;YAR3E;GAUE,kBAAC,GAAD,EAAU,WAAU,wCAAyC,CAAA;GAC7D,kBAAC,QAAD;IAAM,WAAU;cAAwD;IAAe,CAAA;GACtF,IACC,kBAAC,GAAD,EAAO,WAAU,iDAAkD,CAAA,GAEnE,kBAAC,GAAD,EAAM,WAAU,wEAAyE,CAAA;GAEvF;;;AAoBV,SAAgB,EAAY,EAAE,uBAAoB,aAAU,MAA2B;CACrF,IAAM,IAAK,GAAO,EACZ,CAAC,GAAQ,KAAa,EAAwB,MAAM,EAEpD,IAAwB,QACtB,CACJ;EACE,IAAI;EACJ,OAAO,EAAG,kDAAkD,oBAAoB;EACjF,EACD;EAAE,IAAI;EAAO,OAAO,EAAG,uCAAuC,MAAM;EAAE,CACvE,EACD,CAAC,EAAG,CACL,EAIK,IAAU,QAAc;EAC5B,IAAM,IAAM,IAAqB,IAAI,MAAuB;AAI5D,SAHI,MAAW,QACN,qCAAqC,MAEvC,qCAAqC;IAC3C,CAAC,GAAQ,EAAmB,CAAC;AAEhC,QACE,kBAAC,OAAD;EAAK,WAAW,IAAU,cAAc;YAAxC;GACE,kBAAC,GAAD;IACE,OAAO;IACP,aAAa;IACb,cAAc,MAAO,EAAU,EAAoB;IACnD,SAAQ;IACR,CAAA;GAEF,kBAAC,GAAD,EAA0B,YAAW,CAAA;GAEpC,MAAW,SACV,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kDACA,kIACD;IACC,CAAA;GAEL,MAAW,SACV,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,kDACA,mGACD;IACC,CAAA;GAEF"}
@@ -5,7 +5,7 @@ import { motion as s } from "framer-motion";
5
5
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
6
6
  //#region src/components/templates/TemplateCard.tsx
7
7
  var u = {
8
- SERVICE: "bg-[var(--color-accent-soft)] text-action-primary-bg",
8
+ SERVICE: "bg-[var(--color-accent-soft)] text-text-primary",
9
9
  FRONTEND: "bg-status-info-bg-subtle text-status-info-text",
10
10
  LIBRARY: "bg-status-warning-bg-subtle text-status-warning-text",
11
11
  INFRASTRUCTURE: "bg-status-success-bg-subtle text-status-success-text",
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateCard.js","names":[],"sources":["../../../src/components/templates/TemplateCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { motion } from 'framer-motion';\nimport { FileCode, Tag, Copy, Layers, Variable } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { cardHoverVariants } from '../shared/cardMotion';\n\nexport interface TemplateCardData {\n id: string;\n name: string;\n description: string | null;\n category: string | null;\n cloneCount: number;\n variableCount: number;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TemplateCardProps {\n template: TemplateCardData;\n onOpen?: (template: TemplateCardData) => void;\n className?: string;\n}\n\nconst categoryStyles: Record<string, string> = {\n SERVICE: 'bg-[var(--color-accent-soft)] text-action-primary-bg',\n FRONTEND: 'bg-status-info-bg-subtle text-status-info-text',\n LIBRARY: 'bg-status-warning-bg-subtle text-status-warning-text',\n INFRASTRUCTURE: 'bg-status-success-bg-subtle text-status-success-text',\n STARTER: 'bg-bg-sunken text-text-secondary',\n};\n\nexport const TemplateCard: FC<TemplateCardProps> = ({ template, onOpen, className = '' }) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n return (\n <motion.div\n initial=\"rest\"\n animate=\"rest\"\n whileHover=\"hover\"\n whileTap=\"tap\"\n variants={cardHoverVariants}\n className={`bg-bg-surface border border-border-default rounded-lg p-4 hover:border-border-strong transition-colors cursor-pointer ${className}`}\n onClick={() => onOpen?.(template)}\n >\n <div className=\"flex items-start gap-2 sm:gap-3\">\n <div className=\"flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <FileCode className=\"size-4 sm:w-5 sm:h-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate text-sm sm:text-base\">\n {template.name}\n </h3>\n <div className=\"flex items-center gap-2 mt-0.5 flex-wrap\">\n {template.category && (\n <span\n className={`inline-flex items-center gap-1 px-1.5 py-0.5 text-xs rounded ${categoryStyles[template.category] || 'bg-bg-sunken text-text-secondary'}`}\n >\n <Layers className=\"size-3\" />\n {tr(`template.category.${template.category.toLowerCase()}`, template.category)}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Copy className=\"size-3\" />\n {template.cloneCount} {tr('template.clones', 'clones')}\n </span>\n {template.variableCount > 0 && (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Variable className=\"size-3\" />\n {template.variableCount} var{template.variableCount !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n </div>\n </div>\n\n {template.description && (\n <p className=\"mt-2 text-sm text-text-secondary line-clamp-2\">{template.description}</p>\n )}\n\n {template.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {template.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n {template.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{template.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":";;;;;;AAwBA,IAAM,IAAyC;CAC7C,SAAS;CACT,UAAU;CACV,SAAS;CACT,gBAAgB;CAChB,SAAS;CACV,EAEY,KAAuC,EAAE,aAAU,WAAQ,eAAY,SAAS;CAC3F,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAAqB;EAC5C,IAAM,IAAI,EAAE,EAAI;AAChB,SAAO,MAAM,IAAM,IAAW;;AAGhC,QACE,kBAAC,EAAO,KAAR;EACE,SAAQ;EACR,SAAQ;EACR,YAAW;EACX,UAAS;EACT,UAAU;EACV,WAAW,yHAAyH;EACpI,eAAe,IAAS,EAAS;YAPnC;GASE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAU,WAAU,+CAAgD,CAAA;KAChE,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAS;MACP,CAAA,EACL,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,EAAS,YACR,kBAAC,QAAD;QACE,WAAW,gEAAgE,EAAe,EAAS,aAAa;kBADlH,CAGE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAC5B,EAAG,qBAAqB,EAAS,SAAS,aAAa,IAAI,EAAS,SAAS,CACzE;;OAET,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;SAC1B,EAAS;SAAW;SAAE,EAAG,mBAAmB,SAAS;SACjD;;OACN,EAAS,gBAAgB,KACxB,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;SAC9B,EAAS;SAAc;SAAK,EAAS,kBAAkB,IAAU,KAAN;SACvD;;OAEL;QACF;OACF;;GAEL,EAAS,eACR,kBAAC,KAAD;IAAG,WAAU;cAAiD,EAAS;IAAgB,CAAA;GAGxF,EAAS,KAAK,SAAS,KACtB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAS,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC9B,kBAAC,QAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA,EACzB,EACI;OALA,EAKA,CACP,EACD,EAAS,KAAK,SAAS,KACtB,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAA+E,KAC3E,EAAS,KAAK,SAAS,EACpB;OAEL;;GAEG"}
1
+ {"version":3,"file":"TemplateCard.js","names":[],"sources":["../../../src/components/templates/TemplateCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { motion } from 'framer-motion';\nimport { FileCode, Tag, Copy, Layers, Variable } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { cardHoverVariants } from '../shared/cardMotion';\n\nexport interface TemplateCardData {\n id: string;\n name: string;\n description: string | null;\n category: string | null;\n cloneCount: number;\n variableCount: number;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface TemplateCardProps {\n template: TemplateCardData;\n onOpen?: (template: TemplateCardData) => void;\n className?: string;\n}\n\nconst categoryStyles: Record<string, string> = {\n SERVICE: 'bg-[var(--color-accent-soft)] text-text-primary',\n FRONTEND: 'bg-status-info-bg-subtle text-status-info-text',\n LIBRARY: 'bg-status-warning-bg-subtle text-status-warning-text',\n INFRASTRUCTURE: 'bg-status-success-bg-subtle text-status-success-text',\n STARTER: 'bg-bg-sunken text-text-secondary',\n};\n\nexport const TemplateCard: FC<TemplateCardProps> = ({ template, onOpen, className = '' }) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n return (\n <motion.div\n initial=\"rest\"\n animate=\"rest\"\n whileHover=\"hover\"\n whileTap=\"tap\"\n variants={cardHoverVariants}\n className={`bg-bg-surface border border-border-default rounded-lg p-4 hover:border-border-strong transition-colors cursor-pointer ${className}`}\n onClick={() => onOpen?.(template)}\n >\n <div className=\"flex items-start gap-2 sm:gap-3\">\n <div className=\"flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <FileCode className=\"size-4 sm:w-5 sm:h-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate text-sm sm:text-base\">\n {template.name}\n </h3>\n <div className=\"flex items-center gap-2 mt-0.5 flex-wrap\">\n {template.category && (\n <span\n className={`inline-flex items-center gap-1 px-1.5 py-0.5 text-xs rounded ${categoryStyles[template.category] || 'bg-bg-sunken text-text-secondary'}`}\n >\n <Layers className=\"size-3\" />\n {tr(`template.category.${template.category.toLowerCase()}`, template.category)}\n </span>\n )}\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Copy className=\"size-3\" />\n {template.cloneCount} {tr('template.clones', 'clones')}\n </span>\n {template.variableCount > 0 && (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-muted\">\n <Variable className=\"size-3\" />\n {template.variableCount} var{template.variableCount !== 1 ? 's' : ''}\n </span>\n )}\n </div>\n </div>\n </div>\n\n {template.description && (\n <p className=\"mt-2 text-sm text-text-secondary line-clamp-2\">{template.description}</p>\n )}\n\n {template.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {template.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n {template.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{template.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":";;;;;;AAwBA,IAAM,IAAyC;CAC7C,SAAS;CACT,UAAU;CACV,SAAS;CACT,gBAAgB;CAChB,SAAS;CACV,EAEY,KAAuC,EAAE,aAAU,WAAQ,eAAY,SAAS;CAC3F,IAAM,EAAE,SAAM,GAAS,EACjB,KAAM,GAAa,MAAqB;EAC5C,IAAM,IAAI,EAAE,EAAI;AAChB,SAAO,MAAM,IAAM,IAAW;;AAGhC,QACE,kBAAC,EAAO,KAAR;EACE,SAAQ;EACR,SAAQ;EACR,YAAW;EACX,UAAS;EACT,UAAU;EACV,WAAW,yHAAyH;EACpI,eAAe,IAAS,EAAS;YAPnC;GASE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAU,WAAU,+CAAgD,CAAA;KAChE,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBACX,EAAS;MACP,CAAA,EACL,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACG,EAAS,YACR,kBAAC,QAAD;QACE,WAAW,gEAAgE,EAAe,EAAS,aAAa;kBADlH,CAGE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,EAC5B,EAAG,qBAAqB,EAAS,SAAS,aAAa,IAAI,EAAS,SAAS,CACzE;;OAET,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;SAC1B,EAAS;SAAW;SAAE,EAAG,mBAAmB,SAAS;SACjD;;OACN,EAAS,gBAAgB,KACxB,kBAAC,QAAD;QAAM,WAAU;kBAAhB;SACE,kBAAC,GAAD,EAAU,WAAU,UAAW,CAAA;SAC9B,EAAS;SAAc;SAAK,EAAS,kBAAkB,IAAU,KAAN;SACvD;;OAEL;QACF;OACF;;GAEL,EAAS,eACR,kBAAC,KAAD;IAAG,WAAU;cAAiD,EAAS;IAAgB,CAAA;GAGxF,EAAS,KAAK,SAAS,KACtB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAS,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAC9B,kBAAC,QAAD;KAEE,WAAU;eAFZ,CAIE,kBAAC,GAAD,EAAK,WAAU,UAAW,CAAA,EACzB,EACI;OALA,EAKA,CACP,EACD,EAAS,KAAK,SAAS,KACtB,kBAAC,QAAD;KAAM,WAAU;eAAhB,CAA+E,KAC3E,EAAS,KAAK,SAAS,EACpB;OAEL;;GAEG"}
@@ -8,7 +8,7 @@ var e = {
8
8
  CANCELLED: "bg-bg-muted/10 text-text-tertiary border-border-subtle/30",
9
9
  DRAFT: "bg-bg-muted/10 text-text-tertiary border-border-subtle/30",
10
10
  TIMEOUT: "bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border/30",
11
- MANUAL: "bg-accent-purple-subtle text-accent-purple border-accent-purple/30",
11
+ MANUAL: "bg-accent-purple-subtle text-text-primary border-accent-purple/30",
12
12
  SCHEDULE: "bg-status-info-bg-subtle text-status-info-text border-status-info-border/30",
13
13
  ARCHIVED: "bg-bg-muted/10 text-text-tertiary border-border-subtle/30",
14
14
  DISABLED: "bg-bg-muted/10 text-text-tertiary border-border-subtle/30"
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../src/components/vibecalendar/types.ts"],"sourcesContent":["export type CalendarViewMode = 'month' | 'week' | 'day' | 'agenda';\n\n// Where a calendar tile's data originally came from. Set by\n// client-side mappers ONLY — never present on the GraphQL response.\n// Page handlers branch on this to pick the matching subgraph for\n// mutations and the matching detail route. Omitted = default\n// `vibeCalendarTask` (rows from wspace-calendar-svc).\nexport type VibeCalendarTaskSource = 'scheduledJob' | 'vibeCalendarTask';\n\nexport interface VibeCalendarTask {\n id: string;\n /**\n * Set by client-side mappers (e.g. `jobToVibeCalendarTask`). Reading\n * code branches on this to pick the correct mutation/route. Omitted\n * for real VibeCalendarTask rows fetched from wspace-calendar-svc —\n * treat `undefined` as `'vibeCalendarTask'`.\n */\n source?: VibeCalendarTaskSource;\n title: string;\n description: string | null;\n calendarId: string;\n calendarEventId: string;\n agentId: string;\n taskConfig: {\n taskType: string;\n command?: string | null;\n script?: string | null;\n interpreter?: string | null;\n cwd?: string | null;\n env?: Record<string, string> | null;\n timeout?: number | null;\n webhookUrl?: string | null;\n webhookMethod?: string | null;\n webhookHeaders?: Record<string, string> | null;\n webhookAuthType?: string | null;\n webhookPayload?: Record<string, unknown> | null;\n };\n cronExpression: string | null;\n rrule: string | null;\n scheduledAt: string | null;\n timezone: string;\n nextExecutionAt: string | null;\n lastExecutedAt: string | null;\n status: string;\n totalExecutions: number;\n consecutiveFailures: number;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface VibeCalendarExecution {\n id: string;\n taskId: string;\n status: string;\n output: string | null;\n exitCode: number | null;\n webhookStatusCode: number | null;\n startedAt: string | null;\n completedAt: string | null;\n error: string | null;\n}\n\nexport interface CalendarOccurrence {\n task: VibeCalendarTask;\n occurrenceAt: string;\n isPast: boolean;\n execution: VibeCalendarExecution | null;\n}\n\nexport const STATUS_COLORS: Record<string, string> = {\n PENDING: 'bg-status-info-bg-subtle text-status-info-text border-status-info-border/30',\n RUNNING: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border/30',\n COMPLETED: 'bg-status-success-bg-subtle text-status-success-text border-status-success-border/30',\n FAILED: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border/30',\n PAUSED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n CANCELLED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n DRAFT: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n TIMEOUT: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border/30',\n MANUAL: 'bg-accent-purple-subtle text-accent-purple border-accent-purple/30',\n SCHEDULE: 'bg-status-info-bg-subtle text-status-info-text border-status-info-border/30',\n // Scheduler-svc JobStatus exclusives — without these the badge\n // silently falls back to PENDING styling on archived/disabled jobs.\n ARCHIVED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n DISABLED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n};\n"],"mappings":";AAqEA,IAAa,IAAwC;CACnD,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,OAAO;CACP,SAAS;CACT,QAAQ;CACR,UAAU;CAGV,UAAU;CACV,UAAU;CACX"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/components/vibecalendar/types.ts"],"sourcesContent":["export type CalendarViewMode = 'month' | 'week' | 'day' | 'agenda';\n\n// Where a calendar tile's data originally came from. Set by\n// client-side mappers ONLY — never present on the GraphQL response.\n// Page handlers branch on this to pick the matching subgraph for\n// mutations and the matching detail route. Omitted = default\n// `vibeCalendarTask` (rows from wspace-calendar-svc).\nexport type VibeCalendarTaskSource = 'scheduledJob' | 'vibeCalendarTask';\n\nexport interface VibeCalendarTask {\n id: string;\n /**\n * Set by client-side mappers (e.g. `jobToVibeCalendarTask`). Reading\n * code branches on this to pick the correct mutation/route. Omitted\n * for real VibeCalendarTask rows fetched from wspace-calendar-svc —\n * treat `undefined` as `'vibeCalendarTask'`.\n */\n source?: VibeCalendarTaskSource;\n title: string;\n description: string | null;\n calendarId: string;\n calendarEventId: string;\n agentId: string;\n taskConfig: {\n taskType: string;\n command?: string | null;\n script?: string | null;\n interpreter?: string | null;\n cwd?: string | null;\n env?: Record<string, string> | null;\n timeout?: number | null;\n webhookUrl?: string | null;\n webhookMethod?: string | null;\n webhookHeaders?: Record<string, string> | null;\n webhookAuthType?: string | null;\n webhookPayload?: Record<string, unknown> | null;\n };\n cronExpression: string | null;\n rrule: string | null;\n scheduledAt: string | null;\n timezone: string;\n nextExecutionAt: string | null;\n lastExecutedAt: string | null;\n status: string;\n totalExecutions: number;\n consecutiveFailures: number;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface VibeCalendarExecution {\n id: string;\n taskId: string;\n status: string;\n output: string | null;\n exitCode: number | null;\n webhookStatusCode: number | null;\n startedAt: string | null;\n completedAt: string | null;\n error: string | null;\n}\n\nexport interface CalendarOccurrence {\n task: VibeCalendarTask;\n occurrenceAt: string;\n isPast: boolean;\n execution: VibeCalendarExecution | null;\n}\n\nexport const STATUS_COLORS: Record<string, string> = {\n PENDING: 'bg-status-info-bg-subtle text-status-info-text border-status-info-border/30',\n RUNNING: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border/30',\n COMPLETED: 'bg-status-success-bg-subtle text-status-success-text border-status-success-border/30',\n FAILED: 'bg-status-error-bg-subtle text-status-error-text border-status-error-border/30',\n PAUSED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n CANCELLED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n DRAFT: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n TIMEOUT: 'bg-status-warning-bg-subtle text-status-warning-text border-status-warning-border/30',\n MANUAL: 'bg-accent-purple-subtle text-text-primary border-accent-purple/30',\n SCHEDULE: 'bg-status-info-bg-subtle text-status-info-text border-status-info-border/30',\n // Scheduler-svc JobStatus exclusives — without these the badge\n // silently falls back to PENDING styling on archived/disabled jobs.\n ARCHIVED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n DISABLED: 'bg-bg-muted/10 text-text-tertiary border-border-subtle/30',\n};\n"],"mappings":";AAqEA,IAAa,IAAwC;CACnD,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,OAAO;CACP,SAAS;CACT,QAAQ;CACR,UAAU;CAGV,UAAU;CACV,UAAU;CACX"}
@@ -208,7 +208,7 @@ var _ = ({ initialData: _, agents: v, onSubmit: y, onCancel: b, isLoading: x, ti
208
208
  }), /* @__PURE__ */ p("div", {
209
209
  className: "text-xs text-text-tertiary flex items-center gap-1",
210
210
  children: [/* @__PURE__ */ f("span", {
211
- className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-[var(--color-accent-soft)] text-action-primary-bg",
211
+ className: "inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-semibold bg-[var(--color-accent-soft)] text-text-primary",
212
212
  children: V.actionType
213
213
  }), V.command && /* @__PURE__ */ f("span", {
214
214
  className: "font-mono truncate",