@burdenoff/microfe-vibecontrols 2026.613.1 → 2026.617.1

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 (49) hide show
  1. package/dist/components/agents/AgentConnectionRecovery.js +100 -94
  2. package/dist/components/agents/AgentConnectionRecovery.js.map +1 -1
  3. package/dist/components/agents/AgentMaintenanceTab.js +177 -160
  4. package/dist/components/agents/AgentMaintenanceTab.js.map +1 -1
  5. package/dist/components/agents/OpenInBrowserEditorButton.js +102 -94
  6. package/dist/components/agents/OpenInBrowserEditorButton.js.map +1 -1
  7. package/dist/components/tunnels/TunnelCard.js +3 -3
  8. package/dist/components/tunnels/TunnelCard.js.map +1 -1
  9. package/dist/components/tunnels/TunnelPublicAccessPanel.js +36 -36
  10. package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
  11. package/dist/constants/permissions.js +38 -6
  12. package/dist/constants/permissions.js.map +1 -1
  13. package/dist/pages/CatalogDetailPage.js +155 -155
  14. package/dist/pages/CatalogDetailPage.js.map +1 -1
  15. package/dist/pages/CatalogPage.js +110 -109
  16. package/dist/pages/CatalogPage.js.map +1 -1
  17. package/dist/pages/ComponentDetailPage.js +338 -338
  18. package/dist/pages/ComponentDetailPage.js.map +1 -1
  19. package/dist/pages/ComponentsPage.js +104 -103
  20. package/dist/pages/ComponentsPage.js.map +1 -1
  21. package/dist/pages/TargetDetailsPage.js +140 -132
  22. package/dist/pages/TargetDetailsPage.js.map +1 -1
  23. package/dist/pages/TemplateDetailPage.js +201 -199
  24. package/dist/pages/TemplateDetailPage.js.map +1 -1
  25. package/dist/pages/TemplatesPage.js +62 -61
  26. package/dist/pages/TemplatesPage.js.map +1 -1
  27. package/dist/pages/VibeDetailsPage.js +568 -555
  28. package/dist/pages/VibeDetailsPage.js.map +1 -1
  29. package/dist/pages/ai/AIBookmarksPage.js +104 -89
  30. package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
  31. package/dist/pages/ai/AIPage.js +116 -107
  32. package/dist/pages/ai/AIPage.js.map +1 -1
  33. package/dist/pages/ai/AISessionDetailPage.js +46 -34
  34. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  35. package/dist/pages/ai/AgentManagerPage.js +112 -100
  36. package/dist/pages/ai/AgentManagerPage.js.map +1 -1
  37. package/dist/pages/tunnels/TunnelDetailsPage.js +177 -153
  38. package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
  39. package/dist/pages/tunnels/TunnelsTab.js +119 -111
  40. package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
  41. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +24 -24
  42. package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
  43. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +9 -8
  44. package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
  45. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +13 -13
  46. package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
  47. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +19 -15
  48. package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
  49. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n onStart: (id: string) => void;\n onStop: (id: string) => void;\n onDelete: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 hover:border-border-default transition-colors\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1\">\n <h3 className=\"text-base font-semibold text-text-primary truncate\">{tunnel.name}</h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs text-text-muted mt-1\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-md bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-fg hover:bg-action-primary-bg-hover\"\n >\n <Play className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n >\n <Square className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <EntityVibeLinkControl\n entityType={VibeEntityType.Tunnel}\n entityId={tunnel.id}\n currentVibeId={tunnel.vibeId ?? null}\n currentVisibility={tunnel.visibility ?? null}\n refetchQueries={['ListTunnels']}\n />\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-md border border-border-default px-2 py-1.5 text-xs text-status-error-fg hover:bg-status-error-bg\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-3 rounded-md bg-status-error-bg px-3 py-2 text-xs text-status-error-fg\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;AAqBA,SAAgB,EAAW,EACzB,WACA,eAAY,IACZ,WACA,YACA,WACA,eACkB;CAClB,IAAM,IAAK,GAAO,EACZ,IACJ,CAAC,KACD,EAAO,WAAW,EAAa,UAC/B,EAAO,WAAW,EAAa,cAC3B,IAAU,CAAC,KAAa,EAAO,WAAW,EAAa,QACvD,IAAW,EAAO,eAAe,UACjC,IAAY,IACd,GAAG,EAAO,SAAS,aAAa,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAClE;AAEJ,QACE,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,WAAU;YAHZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAO,EAAO,GAAG;IAChC,WAAU;cAHZ;KAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBAAsD,EAAO;QAAU,CAAA;OACrF,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;OAC9C;;KACL,IACC,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAc,CAAA,GAEnE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iCAAiC,qBAAqB;MACxD,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAO;OAAS;OAAE,EAAO;OAAU;OAAK,EAAO;OAC9C;;KACG;OAET,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;MACV,UAAU,MAAM,EAAE,iBAAiB;gBALrC,CAOE,kBAAC,GAAD,EAAc,WAAU,iBAAkB,CAAA,EACzC,EAAG,6BAA6B,OAAO,CACtC;;KAEL,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,8BAA+B,CAAA,EACjD,EAAO,WAAW,WACf,EAAG,iCAAiC,YAAY,GAChD,EAAG,iCAAiC,YAAY,CAC/C;;KAER,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAQ,EAAO,GAAG;MACjC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,iBAAkB,CAAA,EACjC,EAAG,8BAA8B,QAAQ,CACnC;;KAEV,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAO,EAAO,GAAG;MAChC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,iBAAkB,CAAA,EACnC,EAAG,6BAA6B,OAAO,CACjC;;KAEX,kBAAC,GAAD;MACE,YAAY,EAAe;MAC3B,UAAU,EAAO;MACjB,eAAe,EAAO,UAAU;MAChC,mBAAmB,EAAO,cAAc;MACxC,gBAAgB,CAAC,cAAc;MAC/B,CAAA;KACF,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,EAAO,IAAI,EAAO,KAAK;MAC/C,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA;MACxB,CAAA;KACL;MACF;MACL,EAAO,aACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAO;GACJ,CAAA,CAEG"}
1
+ {"version":3,"file":"TunnelCard.js","names":[],"sources":["../../../src/components/tunnels/TunnelCard.tsx"],"sourcesContent":["import { motion } from 'framer-motion';\nimport { Loader2, Play, Square, Trash2, ExternalLink } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\n\nimport type { ListTunnelsQuery } from '@/generated/wspace-operations';\nimport { TunnelStatus, VibeEntityType } from '@/generated/wspace-types';\nimport { TunnelStatusBadge } from './TunnelStatusBadge';\nimport { ProviderBadge } from './ProviderBadge';\nimport { EntityVibeLinkControl } from '../shared/EntityVibeLinkControl';\n\ntype TunnelRow = NonNullable<ListTunnelsQuery['tunnels']>['items'][number];\n\ninterface TunnelCardProps {\n tunnel: TunnelRow;\n isPending?: boolean;\n onOpen: (id: string) => void;\n // Mutation callbacks are optional: the parent omits them when the actor\n // lacks the permission (tunnel:execute for start/stop, tunnel:delete), so\n // the corresponding control is hidden rather than 403-ing on click.\n onStart?: (id: string) => void;\n onStop?: (id: string) => void;\n onDelete?: (id: string, name: string) => void;\n}\n\nexport function TunnelCard({\n tunnel,\n isPending = false,\n onOpen,\n onStart,\n onStop,\n onDelete,\n}: TunnelCardProps) {\n const tr = useTr();\n const canStart =\n !isPending &&\n tunnel.status !== TunnelStatus.Active &&\n tunnel.status !== TunnelStatus.Provisioning;\n const canStop = !isPending && tunnel.status === TunnelStatus.Active;\n const hostname = tunnel.primaryDomain?.hostname;\n const publicUrl = hostname\n ? `${tunnel.protocol.toLowerCase() === 'tcp' ? 'tcp' : 'https'}://${hostname}`\n : null;\n\n return (\n <motion.div\n initial={{ opacity: 0, y: 4 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 hover:border-border-default transition-colors\"\n >\n <div className=\"flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3\">\n <button\n type=\"button\"\n onClick={() => onOpen(tunnel.id)}\n className=\"flex-1 text-left min-w-0\"\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-1\">\n <h3 className=\"text-base font-semibold text-text-primary truncate\">{tunnel.name}</h3>\n <TunnelStatusBadge status={tunnel.status} />\n <ProviderBadge providerKey={tunnel.providerKey} />\n </div>\n {publicUrl ? (\n <p className=\"text-sm text-text-secondary truncate\">{publicUrl}</p>\n ) : (\n <p className=\"text-sm text-text-muted\">\n {tr('vibecontrols.tunnels.noDomain', 'No domain attached')}\n </p>\n )}\n <p className=\"text-xs text-text-muted mt-1\">\n {tunnel.protocol}:{tunnel.localPort} on {tunnel.localHost}\n </p>\n </button>\n\n <div className=\"flex items-center gap-2 flex-shrink-0 flex-wrap\">\n {publicUrl && (\n <a\n href={publicUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n onClick={(e) => e.stopPropagation()}\n >\n <ExternalLink className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.open', 'Open')}\n </a>\n )}\n {isPending && (\n <span className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-muted\">\n <Loader2 className=\"size-3.5 mr-1 animate-spin\" />\n {tunnel.status === 'ACTIVE'\n ? tr('vibecontrols.tunnels.stopping', 'Stopping…')\n : tr('vibecontrols.tunnels.starting', 'Starting…')}\n </span>\n )}\n {canStart && onStart && (\n <button\n type=\"button\"\n onClick={() => onStart(tunnel.id)}\n className=\"inline-flex items-center rounded-md bg-action-primary-bg px-3 py-1.5 text-xs font-medium text-action-primary-fg hover:bg-action-primary-bg-hover\"\n >\n <Play className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.start', 'Start')}\n </button>\n )}\n {canStop && onStop && (\n <button\n type=\"button\"\n onClick={() => onStop(tunnel.id)}\n className=\"inline-flex items-center rounded-md border border-border-default px-3 py-1.5 text-xs text-text-primary hover:bg-bg-elevated\"\n >\n <Square className=\"size-3.5 mr-1\" />\n {tr('vibecontrols.tunnels.stop', 'Stop')}\n </button>\n )}\n <EntityVibeLinkControl\n entityType={VibeEntityType.Tunnel}\n entityId={tunnel.id}\n currentVibeId={tunnel.vibeId ?? null}\n currentVisibility={tunnel.visibility ?? null}\n refetchQueries={['ListTunnels']}\n />\n {onDelete && (\n <button\n type=\"button\"\n onClick={() => onDelete(tunnel.id, tunnel.name)}\n className=\"inline-flex items-center rounded-md border border-border-default px-2 py-1.5 text-xs text-status-error-fg hover:bg-status-error-bg\"\n aria-label=\"Delete tunnel\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n )}\n </div>\n </div>\n {tunnel.lastError && (\n <div className=\"mt-3 rounded-md bg-status-error-bg px-3 py-2 text-xs text-status-error-fg\">\n {tunnel.lastError}\n </div>\n )}\n </motion.div>\n );\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,EAAW,EACzB,WACA,eAAY,IACZ,WACA,YACA,WACA,eACkB;CAClB,IAAM,IAAK,GAAO,EACZ,IACJ,CAAC,KACD,EAAO,WAAW,EAAa,UAC/B,EAAO,WAAW,EAAa,cAC3B,IAAU,CAAC,KAAa,EAAO,WAAW,EAAa,QACvD,IAAW,EAAO,eAAe,UACjC,IAAY,IACd,GAAG,EAAO,SAAS,aAAa,KAAK,QAAQ,QAAQ,QAAQ,KAAK,MAClE;AAEJ,QACE,kBAAC,EAAO,KAAR;EACE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,WAAU;YAHZ,CAKE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAO,EAAO,GAAG;IAChC,WAAU;cAHZ;KAKE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,MAAD;QAAI,WAAU;kBAAsD,EAAO;QAAU,CAAA;OACrF,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OAC5C,kBAAC,GAAD,EAAe,aAAa,EAAO,aAAe,CAAA;OAC9C;;KACL,IACC,kBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAc,CAAA,GAEnE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAG,iCAAiC,qBAAqB;MACxD,CAAA;KAEN,kBAAC,KAAD;MAAG,WAAU;gBAAb;OACG,EAAO;OAAS;OAAE,EAAO;OAAU;OAAK,EAAO;OAC9C;;KACG;OAET,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,KACC,kBAAC,KAAD;MACE,MAAM;MACN,QAAO;MACP,KAAI;MACJ,WAAU;MACV,UAAU,MAAM,EAAE,iBAAiB;gBALrC,CAOE,kBAAC,GAAD,EAAc,WAAU,iBAAkB,CAAA,EACzC,EAAG,6BAA6B,OAAO,CACtC;;KAEL,KACC,kBAAC,QAAD;MAAM,WAAU;gBAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,8BAA+B,CAAA,EACjD,EAAO,WAAW,WACf,EAAG,iCAAiC,YAAY,GAChD,EAAG,iCAAiC,YAAY,CAC/C;;KAER,KAAY,KACX,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAQ,EAAO,GAAG;MACjC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,iBAAkB,CAAA,EACjC,EAAG,8BAA8B,QAAQ,CACnC;;KAEV,KAAW,KACV,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAO,EAAO,GAAG;MAChC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,iBAAkB,CAAA,EACnC,EAAG,6BAA6B,OAAO,CACjC;;KAEX,kBAAC,GAAD;MACE,YAAY,EAAe;MAC3B,UAAU,EAAO;MACjB,eAAe,EAAO,UAAU;MAChC,mBAAmB,EAAO,cAAc;MACxC,gBAAgB,CAAC,cAAc;MAC/B,CAAA;KACD,KACC,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAS,EAAO,IAAI,EAAO,KAAK;MAC/C,WAAU;MACV,cAAW;gBAEX,kBAAC,GAAD,EAAQ,WAAU,YAAa,CAAA;MACxB,CAAA;KAEP;MACF;MACL,EAAO,aACN,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAO;GACJ,CAAA,CAEG"}
@@ -22,54 +22,54 @@ var f = [
22
22
  key: "7d",
23
23
  seconds: 604800
24
24
  }
25
- ], p = ({ tunnelId: p, tunnelStatus: m, publicAccessExpiresAt: h, publicUrl: g, onChanged: _ }) => {
26
- let { t: v } = i(), y = (e, t) => {
27
- let n = v(e);
25
+ ], p = ({ tunnelId: p, tunnelStatus: m, publicAccessExpiresAt: h, publicUrl: g, canUpdate: _, onChanged: v }) => {
26
+ let { t: y } = i(), b = (e, t) => {
27
+ let n = y(e);
28
28
  return n === e ? t : n;
29
- }, [b, x] = r(f[1].seconds), [S, C] = r(!1), [w, { loading: T }] = t(), [E, { loading: D }] = e(), O = h ? new Date(h) : null, k = !!(O && O.getTime() > Date.now()), A = (e) => ({
29
+ }, [x, S] = r(f[1].seconds), [C, w] = r(!1), [T, { loading: E }] = t(), [D, { loading: O }] = e(), k = h ? new Date(h) : null, A = !!(k && k.getTime() > Date.now()), j = (e) => ({
30
30
  "1h": "1 hour",
31
31
  "4h": "4 hours",
32
32
  "24h": "24 hours",
33
33
  "7d": "7 days"
34
- })[e] ?? e, j = async () => {
34
+ })[e] ?? e, M = async () => {
35
35
  try {
36
- await w({ variables: {
36
+ await T({ variables: {
37
37
  tunnelId: p,
38
- ttlSeconds: b
39
- } }), _(), n.success(y("tunPublic.granted", "Public access granted"), y("tunPublic.grantedDesc", "The link auto-expires when the window ends."));
38
+ ttlSeconds: x
39
+ } }), v(), n.success(b("tunPublic.granted", "Public access granted"), b("tunPublic.grantedDesc", "The link auto-expires when the window ends."));
40
40
  } catch (e) {
41
- n.error(y("tunPublic.grantFailed", "Could not grant access"), e.message);
41
+ n.error(b("tunPublic.grantFailed", "Could not grant access"), e.message);
42
42
  }
43
- }, M = async () => {
43
+ }, N = async () => {
44
44
  try {
45
- await E({ variables: { tunnelId: p } }), _(), n.success(y("tunPublic.revoked", "Public access revoked — the link is dead"));
45
+ await D({ variables: { tunnelId: p } }), v(), n.success(b("tunPublic.revoked", "Public access revoked — the link is dead"));
46
46
  } catch (e) {
47
- n.error(y("tunPublic.revokeFailed", "Could not revoke"), e.message);
47
+ n.error(b("tunPublic.revokeFailed", "Could not revoke"), e.message);
48
48
  }
49
- }, N = async () => {
49
+ }, P = async () => {
50
50
  if (g) try {
51
- await navigator.clipboard.writeText(g), C(!0), n.success(y("tunPublic.copied", "Public URL copied")), window.setTimeout(() => C(!1), 1500);
51
+ await navigator.clipboard.writeText(g), w(!0), n.success(b("tunPublic.copied", "Public URL copied")), window.setTimeout(() => w(!1), 1500);
52
52
  } catch {
53
- n.error(y("tunPublic.copyFailed", "Could not copy — copy it manually"), g);
53
+ n.error(b("tunPublic.copyFailed", "Could not copy — copy it manually"), g);
54
54
  }
55
55
  };
56
56
  return /* @__PURE__ */ d("section", {
57
57
  className: "md:col-span-2 rounded-lg border border-border-subtle bg-bg-surface p-4",
58
58
  children: [/* @__PURE__ */ d("h3", {
59
59
  className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
60
- children: [/* @__PURE__ */ u(c, { className: "size-4" }), y("tunPublic.title", "Time-limited public access")]
61
- }), k && O ? /* @__PURE__ */ d("div", {
60
+ children: [/* @__PURE__ */ u(c, { className: "size-4" }), b("tunPublic.title", "Time-limited public access")]
61
+ }), A && k ? /* @__PURE__ */ d("div", {
62
62
  className: "space-y-3",
63
63
  children: [
64
64
  /* @__PURE__ */ d("div", {
65
65
  className: "flex items-center gap-2 rounded-md bg-status-success-bg px-3 py-2 text-sm text-status-success-text",
66
66
  children: [/* @__PURE__ */ u(o, { className: "size-4 shrink-0" }), /* @__PURE__ */ d("span", { children: [
67
- y("tunPublic.liveUntil", "Public until"),
67
+ b("tunPublic.liveUntil", "Public until"),
68
68
  " ",
69
- /* @__PURE__ */ u("strong", { children: O.toLocaleString() }),
69
+ /* @__PURE__ */ u("strong", { children: k.toLocaleString() }),
70
70
  m !== "ACTIVE" && /* @__PURE__ */ u("span", {
71
71
  className: "ml-1 text-text-tertiary",
72
- children: y("tunPublic.notRunning", "(start the tunnel for the URL to serve)")
72
+ children: b("tunPublic.notRunning", "(start the tunnel for the URL to serve)")
73
73
  })
74
74
  ] })]
75
75
  }),
@@ -80,47 +80,47 @@ var f = [
80
80
  children: g
81
81
  }), /* @__PURE__ */ u("button", {
82
82
  type: "button",
83
- onClick: () => void N(),
83
+ onClick: () => void P(),
84
84
  className: "p-1 text-text-secondary hover:text-text-primary",
85
- "aria-label": y("common.copy", "Copy"),
86
- children: S ? /* @__PURE__ */ u(a, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ u(s, { className: "size-4" })
85
+ "aria-label": b("common.copy", "Copy"),
86
+ children: C ? /* @__PURE__ */ u(a, { className: "size-4 text-status-success-text" }) : /* @__PURE__ */ u(s, { className: "size-4" })
87
87
  })]
88
88
  }),
89
- /* @__PURE__ */ d("button", {
89
+ _ && /* @__PURE__ */ d("button", {
90
90
  type: "button",
91
- onClick: () => void M(),
92
- disabled: D,
91
+ onClick: () => void N(),
92
+ disabled: O,
93
93
  className: "flex items-center gap-1.5 rounded-md border border-border-default px-3 py-2 text-sm text-action-danger-text hover:bg-bg-sunken disabled:opacity-50",
94
- children: [/* @__PURE__ */ u(l, { className: "size-4" }), y("tunPublic.revoke", "Revoke now")]
94
+ children: [/* @__PURE__ */ u(l, { className: "size-4" }), b("tunPublic.revoke", "Revoke now")]
95
95
  })
96
96
  ]
97
97
  }) : /* @__PURE__ */ d("div", {
98
98
  className: "space-y-3",
99
99
  children: [/* @__PURE__ */ u("p", {
100
100
  className: "text-sm text-text-secondary",
101
- children: y("tunPublic.off", "Public access is off. Grant a time-boxed window and the link tears itself down when it ends.")
101
+ children: b("tunPublic.off", "Public access is off. Grant a time-boxed window and the link tears itself down when it ends.")
102
102
  }), /* @__PURE__ */ d("div", {
103
103
  className: "flex flex-wrap items-end gap-3",
104
104
  children: [/* @__PURE__ */ d("label", {
105
105
  className: "flex-1 min-w-[10rem]",
106
106
  children: [/* @__PURE__ */ u("span", {
107
107
  className: "text-sm text-text-secondary",
108
- children: y("tunPublic.window", "Access window")
108
+ children: b("tunPublic.window", "Access window")
109
109
  }), /* @__PURE__ */ u("select", {
110
- value: b,
111
- onChange: (e) => x(Number(e.target.value)),
110
+ value: x,
111
+ onChange: (e) => S(Number(e.target.value)),
112
112
  className: "mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary",
113
113
  children: f.map((e) => /* @__PURE__ */ u("option", {
114
114
  value: e.seconds,
115
- children: y(`tunPublic.ttl.${e.key}`, A(e.key))
115
+ children: b(`tunPublic.ttl.${e.key}`, j(e.key))
116
116
  }, e.key))
117
117
  })]
118
- }), /* @__PURE__ */ d("button", {
118
+ }), _ && /* @__PURE__ */ d("button", {
119
119
  type: "button",
120
- onClick: () => void j(),
121
- disabled: T,
120
+ onClick: () => void M(),
121
+ disabled: E,
122
122
  className: "flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50",
123
- children: [/* @__PURE__ */ u(c, { className: "size-4" }), y("tunPublic.grant", "Grant public access")]
123
+ children: [/* @__PURE__ */ u(c, { className: "size-4" }), b("tunPublic.grant", "Grant public access")]
124
124
  })]
125
125
  })]
126
126
  })]
@@ -1 +1 @@
1
- {"version":3,"file":"TunnelPublicAccessPanel.js","names":[],"sources":["../../../src/components/tunnels/TunnelPublicAccessPanel.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Globe, Copy, Check, Clock, ShieldOff } from 'lucide-react';\n\nimport { notify } from '@/lib/toast';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useSetTunnelPublicAccessMutation,\n useRevokeTunnelPublicAccessMutation,\n} from '@/generated/wspace-operations';\n\ninterface TunnelPublicAccessPanelProps {\n tunnelId: string;\n tunnelStatus: string;\n publicAccessExpiresAt?: string | null;\n publicUrl?: string | null;\n onChanged: () => void;\n}\n\n// TTL choices in seconds, inside the svc's 300 (5m) … 2592000 (30d) bounds.\nconst TTL_OPTIONS = [\n { key: '1h', seconds: 3600 },\n { key: '4h', seconds: 14_400 },\n { key: '24h', seconds: 86_400 },\n { key: '7d', seconds: 604_800 },\n];\n\n/**\n * TunnelPublicAccessPanel — grant a time-boxed public link to a tunnel and have it tear itself down.\n * Picking a window stamps `publicAccessExpiresAt = now + ttl`; a backend sweep stops the tunnel (the\n * public URL goes dead) the moment it lapses, so a \"share my localhost for 4 hours\" or \"open this DB\n * port to a contractor until tonight\" link can't outlive its purpose. Revoke kills it immediately.\n * This is the UI half of the beta-tester-tunnel / local-port-share / database-port-forward stories.\n */\nexport const TunnelPublicAccessPanel: FC<TunnelPublicAccessPanelProps> = ({\n tunnelId,\n tunnelStatus,\n publicAccessExpiresAt,\n publicUrl,\n onChanged,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const [ttlSeconds, setTtlSeconds] = useState(TTL_OPTIONS[1].seconds);\n const [copied, setCopied] = useState(false);\n const [setAccess, { loading: granting }] = useSetTunnelPublicAccessMutation();\n const [revokeAccess, { loading: revoking }] = useRevokeTunnelPublicAccessMutation();\n\n const expiresAt = publicAccessExpiresAt ? new Date(publicAccessExpiresAt) : null;\n const isActive = Boolean(expiresAt && expiresAt.getTime() > Date.now());\n const ttlLabel = (key: string): string =>\n ({ '1h': '1 hour', '4h': '4 hours', '24h': '24 hours', '7d': '7 days' })[key] ?? key;\n\n const handleGrant = async (): Promise<void> => {\n try {\n await setAccess({ variables: { tunnelId, ttlSeconds } });\n onChanged();\n notify.success(\n tr('tunPublic.granted', 'Public access granted'),\n tr('tunPublic.grantedDesc', 'The link auto-expires when the window ends.')\n );\n } catch (err) {\n notify.error(tr('tunPublic.grantFailed', 'Could not grant access'), (err as Error).message);\n }\n };\n\n const handleRevoke = async (): Promise<void> => {\n try {\n await revokeAccess({ variables: { tunnelId } });\n onChanged();\n notify.success(tr('tunPublic.revoked', 'Public access revoked — the link is dead'));\n } catch (err) {\n notify.error(tr('tunPublic.revokeFailed', 'Could not revoke'), (err as Error).message);\n }\n };\n\n const copyUrl = async (): Promise<void> => {\n if (!publicUrl) return;\n try {\n await navigator.clipboard.writeText(publicUrl);\n setCopied(true);\n notify.success(tr('tunPublic.copied', 'Public URL copied'));\n window.setTimeout(() => setCopied(false), 1500);\n } catch {\n notify.error(tr('tunPublic.copyFailed', 'Could not copy — copy it manually'), publicUrl);\n }\n };\n\n return (\n <section className=\"md:col-span-2 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Globe className=\"size-4\" />\n {tr('tunPublic.title', 'Time-limited public access')}\n </h3>\n\n {isActive && expiresAt ? (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2 rounded-md bg-status-success-bg px-3 py-2 text-sm text-status-success-text\">\n <Clock className=\"size-4 shrink-0\" />\n <span>\n {tr('tunPublic.liveUntil', 'Public until')}{' '}\n <strong>{expiresAt.toLocaleString()}</strong>\n {tunnelStatus !== 'ACTIVE' && (\n <span className=\"ml-1 text-text-tertiary\">\n {tr('tunPublic.notRunning', '(start the tunnel for the URL to serve)')}\n </span>\n )}\n </span>\n </div>\n {publicUrl && (\n <div className=\"flex items-center gap-2 rounded-md border border-border-default px-3 py-2\">\n <span className=\"flex-1 truncate font-mono text-xs text-text-secondary\">\n {publicUrl}\n </span>\n <button\n type=\"button\"\n onClick={() => void copyUrl()}\n className=\"p-1 text-text-secondary hover:text-text-primary\"\n aria-label={tr('common.copy', 'Copy')}\n >\n {copied ? (\n <Check className=\"size-4 text-status-success-text\" />\n ) : (\n <Copy className=\"size-4\" />\n )}\n </button>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => void handleRevoke()}\n disabled={revoking}\n className=\"flex items-center gap-1.5 rounded-md border border-border-default px-3 py-2 text-sm text-action-danger-text hover:bg-bg-sunken disabled:opacity-50\"\n >\n <ShieldOff className=\"size-4\" />\n {tr('tunPublic.revoke', 'Revoke now')}\n </button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'tunPublic.off',\n 'Public access is off. Grant a time-boxed window and the link tears itself down when it ends.'\n )}\n </p>\n <div className=\"flex flex-wrap items-end gap-3\">\n <label className=\"flex-1 min-w-[10rem]\">\n <span className=\"text-sm text-text-secondary\">\n {tr('tunPublic.window', 'Access window')}\n </span>\n <select\n value={ttlSeconds}\n onChange={(e) => setTtlSeconds(Number(e.target.value))}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {TTL_OPTIONS.map((o) => (\n <option key={o.key} value={o.seconds}>\n {tr(`tunPublic.ttl.${o.key}`, ttlLabel(o.key))}\n </option>\n ))}\n </select>\n </label>\n <button\n type=\"button\"\n onClick={() => void handleGrant()}\n disabled={granting}\n className=\"flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Globe className=\"size-4\" />\n {tr('tunPublic.grant', 'Grant public access')}\n </button>\n </div>\n </div>\n )}\n </section>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"TunnelPublicAccessPanel.js","names":[],"sources":["../../../src/components/tunnels/TunnelPublicAccessPanel.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Globe, Copy, Check, Clock, ShieldOff } from 'lucide-react';\n\nimport { notify } from '@/lib/toast';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n useSetTunnelPublicAccessMutation,\n useRevokeTunnelPublicAccessMutation,\n} from '@/generated/wspace-operations';\n\ninterface TunnelPublicAccessPanelProps {\n tunnelId: string;\n tunnelStatus: string;\n publicAccessExpiresAt?: string | null;\n publicUrl?: string | null;\n canUpdate: boolean;\n onChanged: () => void;\n}\n\n// TTL choices in seconds, inside the svc's 300 (5m) … 2592000 (30d) bounds.\nconst TTL_OPTIONS = [\n { key: '1h', seconds: 3600 },\n { key: '4h', seconds: 14_400 },\n { key: '24h', seconds: 86_400 },\n { key: '7d', seconds: 604_800 },\n];\n\n/**\n * TunnelPublicAccessPanel — grant a time-boxed public link to a tunnel and have it tear itself down.\n * Picking a window stamps `publicAccessExpiresAt = now + ttl`; a backend sweep stops the tunnel (the\n * public URL goes dead) the moment it lapses, so a \"share my localhost for 4 hours\" or \"open this DB\n * port to a contractor until tonight\" link can't outlive its purpose. Revoke kills it immediately.\n * This is the UI half of the beta-tester-tunnel / local-port-share / database-port-forward stories.\n */\nexport const TunnelPublicAccessPanel: FC<TunnelPublicAccessPanelProps> = ({\n tunnelId,\n tunnelStatus,\n publicAccessExpiresAt,\n publicUrl,\n canUpdate,\n onChanged,\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const [ttlSeconds, setTtlSeconds] = useState(TTL_OPTIONS[1].seconds);\n const [copied, setCopied] = useState(false);\n const [setAccess, { loading: granting }] = useSetTunnelPublicAccessMutation();\n const [revokeAccess, { loading: revoking }] = useRevokeTunnelPublicAccessMutation();\n\n const expiresAt = publicAccessExpiresAt ? new Date(publicAccessExpiresAt) : null;\n const isActive = Boolean(expiresAt && expiresAt.getTime() > Date.now());\n const ttlLabel = (key: string): string =>\n ({ '1h': '1 hour', '4h': '4 hours', '24h': '24 hours', '7d': '7 days' })[key] ?? key;\n\n const handleGrant = async (): Promise<void> => {\n try {\n await setAccess({ variables: { tunnelId, ttlSeconds } });\n onChanged();\n notify.success(\n tr('tunPublic.granted', 'Public access granted'),\n tr('tunPublic.grantedDesc', 'The link auto-expires when the window ends.')\n );\n } catch (err) {\n notify.error(tr('tunPublic.grantFailed', 'Could not grant access'), (err as Error).message);\n }\n };\n\n const handleRevoke = async (): Promise<void> => {\n try {\n await revokeAccess({ variables: { tunnelId } });\n onChanged();\n notify.success(tr('tunPublic.revoked', 'Public access revoked — the link is dead'));\n } catch (err) {\n notify.error(tr('tunPublic.revokeFailed', 'Could not revoke'), (err as Error).message);\n }\n };\n\n const copyUrl = async (): Promise<void> => {\n if (!publicUrl) return;\n try {\n await navigator.clipboard.writeText(publicUrl);\n setCopied(true);\n notify.success(tr('tunPublic.copied', 'Public URL copied'));\n window.setTimeout(() => setCopied(false), 1500);\n } catch {\n notify.error(tr('tunPublic.copyFailed', 'Could not copy — copy it manually'), publicUrl);\n }\n };\n\n return (\n <section className=\"md:col-span-2 rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Globe className=\"size-4\" />\n {tr('tunPublic.title', 'Time-limited public access')}\n </h3>\n\n {isActive && expiresAt ? (\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2 rounded-md bg-status-success-bg px-3 py-2 text-sm text-status-success-text\">\n <Clock className=\"size-4 shrink-0\" />\n <span>\n {tr('tunPublic.liveUntil', 'Public until')}{' '}\n <strong>{expiresAt.toLocaleString()}</strong>\n {tunnelStatus !== 'ACTIVE' && (\n <span className=\"ml-1 text-text-tertiary\">\n {tr('tunPublic.notRunning', '(start the tunnel for the URL to serve)')}\n </span>\n )}\n </span>\n </div>\n {publicUrl && (\n <div className=\"flex items-center gap-2 rounded-md border border-border-default px-3 py-2\">\n <span className=\"flex-1 truncate font-mono text-xs text-text-secondary\">\n {publicUrl}\n </span>\n <button\n type=\"button\"\n onClick={() => void copyUrl()}\n className=\"p-1 text-text-secondary hover:text-text-primary\"\n aria-label={tr('common.copy', 'Copy')}\n >\n {copied ? (\n <Check className=\"size-4 text-status-success-text\" />\n ) : (\n <Copy className=\"size-4\" />\n )}\n </button>\n </div>\n )}\n {canUpdate && (\n <button\n type=\"button\"\n onClick={() => void handleRevoke()}\n disabled={revoking}\n className=\"flex items-center gap-1.5 rounded-md border border-border-default px-3 py-2 text-sm text-action-danger-text hover:bg-bg-sunken disabled:opacity-50\"\n >\n <ShieldOff className=\"size-4\" />\n {tr('tunPublic.revoke', 'Revoke now')}\n </button>\n )}\n </div>\n ) : (\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'tunPublic.off',\n 'Public access is off. Grant a time-boxed window and the link tears itself down when it ends.'\n )}\n </p>\n <div className=\"flex flex-wrap items-end gap-3\">\n <label className=\"flex-1 min-w-[10rem]\">\n <span className=\"text-sm text-text-secondary\">\n {tr('tunPublic.window', 'Access window')}\n </span>\n <select\n value={ttlSeconds}\n onChange={(e) => setTtlSeconds(Number(e.target.value))}\n className=\"mt-1 w-full rounded-md border border-border-default bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {TTL_OPTIONS.map((o) => (\n <option key={o.key} value={o.seconds}>\n {tr(`tunPublic.ttl.${o.key}`, ttlLabel(o.key))}\n </option>\n ))}\n </select>\n </label>\n {canUpdate && (\n <button\n type=\"button\"\n onClick={() => void handleGrant()}\n disabled={granting}\n className=\"flex items-center gap-1.5 rounded-md bg-action-primary-bg px-3 py-2 text-sm text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n <Globe className=\"size-4\" />\n {tr('tunPublic.grant', 'Grant public access')}\n </button>\n )}\n </div>\n </div>\n )}\n </section>\n );\n};\n"],"mappings":"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"}
@@ -7,16 +7,19 @@ var e = {
7
7
  VIBE_DELETE: "vibe:delete",
8
8
  VIBE_SCAN: "vibe:scan",
9
9
  VIBE_MANAGE: "vibe:manage",
10
- VIBECOMMAND_LIST: "vibecommand:list",
11
- VIBECOMMAND_READ: "vibecommand:read",
12
- VIBECOMMAND_CREATE: "vibecommand:create",
13
- VIBECOMMAND_UPDATE: "vibecommand:update",
14
- VIBECOMMAND_DELETE: "vibecommand:delete",
15
10
  AGENT_LIST: "agent:list",
16
11
  AGENT_READ: "agent:read",
17
12
  AGENT_CREATE: "agent:create",
18
13
  AGENT_UPDATE: "agent:update",
19
14
  AGENT_DELETE: "agent:delete",
15
+ AGENT_ADMIN: "agent:admin",
16
+ AGENT_MUTATE: "agent:mutate",
17
+ AGENT_INVOKE: "agent:invoke",
18
+ AGENT_MESSAGE_BOOKMARK_READ: "agent-message-bookmark:read",
19
+ AGENT_MESSAGE_BOOKMARK_CREATE: "agent-message-bookmark:create",
20
+ AGENT_MESSAGE_BOOKMARK_UPDATE: "agent-message-bookmark:update",
21
+ AGENT_MESSAGE_BOOKMARK_DELETE: "agent-message-bookmark:delete",
22
+ INTEGRATION_CONNECTION_READ: "integration-connection:read",
20
23
  SESSION_LIST: "session:list",
21
24
  SESSION_READ: "session:read",
22
25
  SESSION_CREATE: "session:create",
@@ -74,8 +77,20 @@ var e = {
74
77
  ACTION_DELETE: "action:delete",
75
78
  ACTION_EXECUTE: "action:execute",
76
79
  ACTION_SHARE: "action:share",
80
+ AIPROMPT_READ: "ai-prompt:read",
81
+ AIPROMPT_CREATE: "ai-prompt:create",
82
+ AIPROMPT_UPDATE: "ai-prompt:update",
83
+ AIPROMPT_DELETE: "ai-prompt:delete",
77
84
  AIPROMPT_SHARE: "ai-prompt:share",
85
+ AICONTEXT_READ: "ai-context:read",
86
+ AICONTEXT_CREATE: "ai-context:create",
87
+ AICONTEXT_UPDATE: "ai-context:update",
88
+ AICONTEXT_DELETE: "ai-context:delete",
78
89
  AICONTEXT_SHARE: "ai-context:share",
90
+ INSTRUCTION_FILE_READ: "instruction-file:read",
91
+ INSTRUCTION_FILE_CREATE: "instruction-file:create",
92
+ INSTRUCTION_FILE_UPDATE: "instruction-file:update",
93
+ INSTRUCTION_FILE_DELETE: "instruction-file:delete",
79
94
  INSTRUCTION_FILE_SHARE: "instruction-file:share",
80
95
  AUDIT_LIST: "audit:list",
81
96
  AUDIT_READ: "audit:read",
@@ -87,14 +102,31 @@ var e = {
87
102
  TARGET_UPDATE: "target:update",
88
103
  TARGET_DELETE: "target:delete",
89
104
  TARGET_SHARE: "target:share",
105
+ CATALOG_READ: "catalog:read",
106
+ CATALOG_CREATE: "catalog:create",
107
+ CATALOG_UPDATE: "catalog:update",
108
+ CATALOG_DELETE: "catalog:delete",
90
109
  CATALOG_SHARE: "catalog:share",
110
+ COMPONENT_READ: "component:read",
111
+ COMPONENT_CREATE: "component:create",
112
+ COMPONENT_UPDATE: "component:update",
113
+ COMPONENT_DELETE: "component:delete",
91
114
  COMPONENT_SHARE: "component:share",
115
+ TEMPLATE_READ: "template:read",
116
+ TEMPLATE_CREATE: "template:create",
117
+ TEMPLATE_UPDATE: "template:update",
118
+ TEMPLATE_DELETE: "template:delete",
92
119
  TEMPLATE_SHARE: "template:share",
120
+ SCORECARD_READ: "scorecard:read",
121
+ SCORECARD_CREATE: "scorecard:create",
122
+ SCORECARD_UPDATE: "scorecard:update",
123
+ SCORECARD_DELETE: "scorecard:delete",
93
124
  SCORECARD_SHARE: "scorecard:share",
94
- TUNNEL_LIST: "tunnel:list",
95
125
  TUNNEL_READ: "tunnel:read",
96
126
  TUNNEL_CREATE: "tunnel:create",
127
+ TUNNEL_UPDATE: "tunnel:update",
97
128
  TUNNEL_DELETE: "tunnel:delete",
129
+ TUNNEL_EXECUTE: "tunnel:execute",
98
130
  TUNNEL_SHARE: "tunnel:share",
99
131
  ANALYTICS_LIST: "analytics:list",
100
132
  ANALYTICS_READ: "analytics:read",
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.js","names":[],"sources":["../../src/constants/permissions.ts"],"sourcesContent":["/**\n * VibeControls Permission Constants\n *\n * All permission strings for VibeControls resources.\n * Use with fe-libs usePermissions hook: hasPermission(VIBE_PERMISSIONS.VIBE_CREATE)\n *\n * Resource types:\n * - vibe: list, read, create, update, delete, scan, manage\n * - vibecommand: list, read, create, update, delete\n * - agent: list, read, create, update, delete\n * - session: list, read, create, update, delete, execute\n * - note: list, read, create, update, delete\n * - webhook: list, read, create, update, delete\n * - action: list, read, create, update, delete, execute\n * - calendar-agent-task: list, read, create, update, delete, execute\n * - configuration: list, read, create, update, delete\n * - docs_site: list, read, create, update, delete, execute\n * - docs_page: list, read, create, update, delete\n * - target: list, read, create, update, delete\n * - tunnel: list, read, create, delete\n * - analytics: list, read\n * - log: list, read\n */\n\nexport const VIBE_PERMISSIONS = {\n // Vibe resources\n VIBE_LIST: 'vibe:list',\n VIBE_READ: 'vibe:read',\n VIBE_CREATE: 'vibe:create',\n VIBE_UPDATE: 'vibe:update',\n VIBE_DELETE: 'vibe:delete',\n VIBE_SCAN: 'vibe:scan',\n VIBE_MANAGE: 'vibe:manage',\n\n // VibeCommand resources\n VIBECOMMAND_LIST: 'vibecommand:list',\n VIBECOMMAND_READ: 'vibecommand:read',\n VIBECOMMAND_CREATE: 'vibecommand:create',\n VIBECOMMAND_UPDATE: 'vibecommand:update',\n VIBECOMMAND_DELETE: 'vibecommand:delete',\n\n // Agent resources\n AGENT_LIST: 'agent:list',\n AGENT_READ: 'agent:read',\n AGENT_CREATE: 'agent:create',\n AGENT_UPDATE: 'agent:update',\n AGENT_DELETE: 'agent:delete',\n\n // Session resources\n SESSION_LIST: 'session:list',\n SESSION_READ: 'session:read',\n SESSION_CREATE: 'session:create',\n SESSION_UPDATE: 'session:update',\n SESSION_DELETE: 'session:delete',\n SESSION_EXECUTE: 'session:execute',\n SESSION_SHARE: 'session:share',\n\n // Note resources\n NOTE_LIST: 'note:list',\n NOTE_READ: 'note:read',\n NOTE_CREATE: 'note:create',\n NOTE_UPDATE: 'note:update',\n NOTE_DELETE: 'note:delete',\n\n // Webhook resources\n WEBHOOK_LIST: 'webhook:list',\n WEBHOOK_READ: 'webhook:read',\n WEBHOOK_CREATE: 'webhook:create',\n WEBHOOK_UPDATE: 'webhook:update',\n WEBHOOK_DELETE: 'webhook:delete',\n\n // VibeDeck resources\n VIBEDECK_LIST: 'vibedeck:list',\n VIBEDECK_READ: 'vibedeck:read',\n VIBEDECK_CREATE: 'vibedeck:create',\n VIBEDECK_UPDATE: 'vibedeck:update',\n VIBEDECK_DELETE: 'vibedeck:delete',\n VIBEDECK_EXECUTE: 'vibedeck:execute',\n VIBEDECK_SHARE: 'vibedeck:share',\n\n // Calendar Agent Task resources\n CALENDAR_AGENT_TASK_LIST: 'calendar-agent-task:list',\n CALENDAR_AGENT_TASK_READ: 'calendar-agent-task:read',\n CALENDAR_AGENT_TASK_CREATE: 'calendar-agent-task:create',\n CALENDAR_AGENT_TASK_UPDATE: 'calendar-agent-task:update',\n CALENDAR_AGENT_TASK_DELETE: 'calendar-agent-task:delete',\n CALENDAR_AGENT_TASK_EXECUTE: 'calendar-agent-task:execute',\n\n // Schedule resources (wspace-scheduler-svc — the unified-source\n // ScheduledJobs surfaced on the Calendar agenda live here).\n // `scheduledJob`/`scheduledJobs` enforce `schedule:read`;\n // `executeJobNow` enforces `schedule:execute`. Distinct from\n // `calendar-agent-task:*` so RBAC denials don't cross-bleed\n // between the two services.\n SCHEDULE_LIST: 'schedule:list',\n SCHEDULE_READ: 'schedule:read',\n SCHEDULE_EXECUTE: 'schedule:execute',\n\n // Configuration resources\n CONFIG_LIST: 'configuration:list',\n CONFIG_READ: 'configuration:read',\n CONFIG_CREATE: 'configuration:create',\n CONFIG_UPDATE: 'configuration:update',\n CONFIG_DELETE: 'configuration:delete',\n\n // Docs Site resources\n DOCS_SITE_LIST: 'docs_site:list',\n DOCS_SITE_READ: 'docs_site:read',\n DOCS_SITE_CREATE: 'docs_site:create',\n DOCS_SITE_UPDATE: 'docs_site:update',\n DOCS_SITE_DELETE: 'docs_site:delete',\n DOCS_COMPILE: 'docs_site:execute',\n\n // Docs Page resources\n DOCS_PAGE_LIST: 'docs_page:list',\n DOCS_PAGE_READ: 'docs_page:read',\n DOCS_PAGE_CREATE: 'docs_page:create',\n DOCS_PAGE_UPDATE: 'docs_page:update',\n DOCS_PAGE_DELETE: 'docs_page:delete',\n // Docs Site generic-sharing surface (backend `shareDocs`, @rbac resource `docs_site`)\n DOCS_SITE_SHARE: 'docs_site:share',\n\n // Action resources\n ACTION_LIST: 'action:list',\n ACTION_READ: 'action:read',\n ACTION_CREATE: 'action:create',\n ACTION_UPDATE: 'action:update',\n ACTION_DELETE: 'action:delete',\n ACTION_EXECUTE: 'action:execute',\n ACTION_SHARE: 'action:share',\n\n // AI Prompt resources — generic-sharing surface (backend `shareAiPrompt`)\n AIPROMPT_SHARE: 'ai-prompt:share',\n\n // AI Context resources — generic-sharing surface (backend `shareAiContext`)\n AICONTEXT_SHARE: 'ai-context:share',\n\n // Agent Instruction File resources — generic-sharing surface\n // (backend `shareAgentInstructionFile`)\n INSTRUCTION_FILE_SHARE: 'instruction-file:share',\n\n // Audit resources\n AUDIT_LIST: 'audit:list',\n AUDIT_READ: 'audit:read',\n AUDIT_DELETE: 'audit:delete',\n AUDIT_EXPORT: 'audit:export',\n\n // Target resources — guards wired in BOFF-2034 (Remaining Pages Audit)\n TARGET_LIST: 'target:list',\n TARGET_READ: 'target:read',\n TARGET_CREATE: 'target:create',\n TARGET_UPDATE: 'target:update',\n TARGET_DELETE: 'target:delete',\n // Target generic-sharing surface (backend `shareTarget`, @rbac resource `target`)\n TARGET_SHARE: 'target:share',\n\n // Catalog resources — generic-sharing surface (backend `shareCatalog`)\n CATALOG_SHARE: 'catalog:share',\n\n // Component resources — generic-sharing surface (backend `shareComponent`)\n COMPONENT_SHARE: 'component:share',\n\n // Template resources — generic-sharing surface (backend `shareTemplate`)\n TEMPLATE_SHARE: 'template:share',\n\n // Scorecard resources — generic-sharing surface (backend `shareScorecard`)\n SCORECARD_SHARE: 'scorecard:share',\n\n // Tunnel resources — no TUNNEL_UPDATE: tunnels are create-or-delete only\n TUNNEL_LIST: 'tunnel:list',\n TUNNEL_READ: 'tunnel:read',\n TUNNEL_CREATE: 'tunnel:create',\n TUNNEL_DELETE: 'tunnel:delete',\n TUNNEL_SHARE: 'tunnel:share',\n\n // Analytics resources\n ANALYTICS_LIST: 'analytics:list',\n ANALYTICS_READ: 'analytics:read',\n\n // Log resources\n LOG_LIST: 'log:list',\n LOG_READ: 'log:read',\n} as const;\n\nexport type VibePermission = (typeof VIBE_PERMISSIONS)[keyof typeof VIBE_PERMISSIONS];\n"],"mappings":";AAwBA,IAAa,IAAmB;CAE9B,WAAW;CACX,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CACb,WAAW;CACX,aAAa;CAGb,kBAAkB;CAClB,kBAAkB;CAClB,oBAAoB;CACpB,oBAAoB;CACpB,oBAAoB;CAGpB,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,cAAc;CACd,cAAc;CAGd,cAAc;CACd,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,eAAe;CAGf,WAAW;CACX,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CAGb,cAAc;CACd,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAGhB,eAAe;CACf,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,kBAAkB;CAClB,gBAAgB;CAGhB,0BAA0B;CAC1B,0BAA0B;CAC1B,4BAA4B;CAC5B,4BAA4B;CAC5B,4BAA4B;CAC5B,6BAA6B;CAQ7B,eAAe;CACf,eAAe;CACf,kBAAkB;CAGlB,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAGf,gBAAgB;CAChB,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,cAAc;CAGd,gBAAgB;CAChB,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAElB,iBAAiB;CAGjB,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CACf,gBAAgB;CAChB,cAAc;CAGd,gBAAgB;CAGhB,iBAAiB;CAIjB,wBAAwB;CAGxB,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,cAAc;CAGd,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAEf,cAAc;CAGd,eAAe;CAGf,iBAAiB;CAGjB,gBAAgB;CAGhB,iBAAiB;CAGjB,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,cAAc;CAGd,gBAAgB;CAChB,gBAAgB;CAGhB,UAAU;CACV,UAAU;CACX"}
1
+ {"version":3,"file":"permissions.js","names":[],"sources":["../../src/constants/permissions.ts"],"sourcesContent":["/**\n * VibeControls Permission Constants\n *\n * All permission strings for VibeControls resources.\n * Use with fe-libs usePermissions hook: hasPermission(VIBE_PERMISSIONS.VIBE_CREATE)\n *\n * IMPORTANT — only strings present in the wspace-rbac-svc seed\n * (`prisma/seed-unified-rbac.ts` ACTION_DEFINITIONS) are ever returned by\n * `myPermissions`/`hasPermission`. Gating on a string the seed does NOT\n * define makes `hasPermission` return false for EVERYONE → a full lockout.\n *\n * Read/CRUD for catalog, component, template, ai-context, ai-prompt,\n * instruction-file and docs_site were seeded in the BOFF-2034 follow-up, so\n * their pages now gate on their own resource (no more `vibe:list` proxy).\n * The new resourceTypes added in that pass (scorecard, aitoolevent,\n * docs_page, docs_revision, docs_build_image) only reach ALREADY-EXISTING\n * workspaces after their cloned roles are re-synced — do NOT hard-gate a\n * page on those until the backfill has run, or pre-existing workspaces lock\n * out.\n *\n * Resource types:\n * - vibe: list, read, create, update, delete, scan, manage\n * - agent: list, read, create, update, delete, admin, mutate, invoke\n * - session: list, read, create, update, delete, execute\n * - note: list, read, create, update, delete\n * - webhook: list, read, create, update, delete\n * - action: list, read, create, update, delete, execute\n * - calendar-agent-task: list, read, create, update, delete, execute\n * - configuration: list, read, create, update, delete\n * - docs_site: list, read, create, update, delete, execute\n * - docs_page: list, read, create, update, delete\n * - target: list, read, create, update, delete\n * - tunnel: list, read, create, delete\n * - analytics: list, read\n * - log: list, read\n */\n\nexport const VIBE_PERMISSIONS = {\n // Vibe resources\n VIBE_LIST: 'vibe:list',\n VIBE_READ: 'vibe:read',\n VIBE_CREATE: 'vibe:create',\n VIBE_UPDATE: 'vibe:update',\n VIBE_DELETE: 'vibe:delete',\n VIBE_SCAN: 'vibe:scan',\n VIBE_MANAGE: 'vibe:manage',\n\n // Agent resources\n AGENT_LIST: 'agent:list',\n AGENT_READ: 'agent:read',\n AGENT_CREATE: 'agent:create',\n AGENT_UPDATE: 'agent:update',\n AGENT_DELETE: 'agent:delete',\n // Elevated agent control-plane actions (gateway enforces these on\n // remote-exec / credential / code-server control mutations).\n AGENT_ADMIN: 'agent:admin', // set/rotate API key, nuke, dry-run\n AGENT_MUTATE: 'agent:mutate', // code-server start/stop, plugin install\n AGENT_INVOKE: 'agent:invoke', // execute scheduled prompt, mint agent capabilities\n\n // Agent message bookmark resources\n AGENT_MESSAGE_BOOKMARK_READ: 'agent-message-bookmark:read',\n AGENT_MESSAGE_BOOKMARK_CREATE: 'agent-message-bookmark:create',\n AGENT_MESSAGE_BOOKMARK_UPDATE: 'agent-message-bookmark:update',\n AGENT_MESSAGE_BOOKMARK_DELETE: 'agent-message-bookmark:delete',\n\n // Integration connection resources\n INTEGRATION_CONNECTION_READ: 'integration-connection:read',\n\n // Session resources\n SESSION_LIST: 'session:list',\n SESSION_READ: 'session:read',\n SESSION_CREATE: 'session:create',\n SESSION_UPDATE: 'session:update',\n SESSION_DELETE: 'session:delete',\n SESSION_EXECUTE: 'session:execute',\n SESSION_SHARE: 'session:share',\n\n // Note resources\n NOTE_LIST: 'note:list',\n NOTE_READ: 'note:read',\n NOTE_CREATE: 'note:create',\n NOTE_UPDATE: 'note:update',\n NOTE_DELETE: 'note:delete',\n\n // Webhook resources\n WEBHOOK_LIST: 'webhook:list',\n WEBHOOK_READ: 'webhook:read',\n WEBHOOK_CREATE: 'webhook:create',\n WEBHOOK_UPDATE: 'webhook:update',\n WEBHOOK_DELETE: 'webhook:delete',\n\n // VibeDeck resources\n VIBEDECK_LIST: 'vibedeck:list',\n VIBEDECK_READ: 'vibedeck:read',\n VIBEDECK_CREATE: 'vibedeck:create',\n VIBEDECK_UPDATE: 'vibedeck:update',\n VIBEDECK_DELETE: 'vibedeck:delete',\n VIBEDECK_EXECUTE: 'vibedeck:execute',\n VIBEDECK_SHARE: 'vibedeck:share',\n\n // Calendar Agent Task resources\n CALENDAR_AGENT_TASK_LIST: 'calendar-agent-task:list',\n CALENDAR_AGENT_TASK_READ: 'calendar-agent-task:read',\n CALENDAR_AGENT_TASK_CREATE: 'calendar-agent-task:create',\n CALENDAR_AGENT_TASK_UPDATE: 'calendar-agent-task:update',\n CALENDAR_AGENT_TASK_DELETE: 'calendar-agent-task:delete',\n CALENDAR_AGENT_TASK_EXECUTE: 'calendar-agent-task:execute',\n\n // Schedule resources (wspace-scheduler-svc — the unified-source\n // ScheduledJobs surfaced on the Calendar agenda live here).\n // `scheduledJob`/`scheduledJobs` enforce `schedule:read`;\n // `executeJobNow` enforces `schedule:execute`. Distinct from\n // `calendar-agent-task:*` so RBAC denials don't cross-bleed\n // between the two services.\n SCHEDULE_LIST: 'schedule:list',\n SCHEDULE_READ: 'schedule:read',\n SCHEDULE_EXECUTE: 'schedule:execute',\n\n // Configuration resources\n CONFIG_LIST: 'configuration:list',\n CONFIG_READ: 'configuration:read',\n CONFIG_CREATE: 'configuration:create',\n CONFIG_UPDATE: 'configuration:update',\n CONFIG_DELETE: 'configuration:delete',\n\n // Docs Site resources\n DOCS_SITE_LIST: 'docs_site:list',\n DOCS_SITE_READ: 'docs_site:read',\n DOCS_SITE_CREATE: 'docs_site:create',\n DOCS_SITE_UPDATE: 'docs_site:update',\n DOCS_SITE_DELETE: 'docs_site:delete',\n DOCS_COMPILE: 'docs_site:execute',\n\n // Docs Page resources\n DOCS_PAGE_LIST: 'docs_page:list',\n DOCS_PAGE_READ: 'docs_page:read',\n DOCS_PAGE_CREATE: 'docs_page:create',\n DOCS_PAGE_UPDATE: 'docs_page:update',\n DOCS_PAGE_DELETE: 'docs_page:delete',\n // Docs Site generic-sharing surface (backend `shareDocs`, @rbac resource `docs_site`)\n DOCS_SITE_SHARE: 'docs_site:share',\n\n // Action resources\n ACTION_LIST: 'action:list',\n ACTION_READ: 'action:read',\n ACTION_CREATE: 'action:create',\n ACTION_UPDATE: 'action:update',\n ACTION_DELETE: 'action:delete',\n ACTION_EXECUTE: 'action:execute',\n ACTION_SHARE: 'action:share',\n\n // AI Prompt resources (read/CRUD seeded in BOFF-2034 follow-up)\n AIPROMPT_READ: 'ai-prompt:read',\n AIPROMPT_CREATE: 'ai-prompt:create',\n AIPROMPT_UPDATE: 'ai-prompt:update',\n AIPROMPT_DELETE: 'ai-prompt:delete',\n AIPROMPT_SHARE: 'ai-prompt:share',\n\n // AI Context resources (read/CRUD seeded in BOFF-2034 follow-up)\n AICONTEXT_READ: 'ai-context:read',\n AICONTEXT_CREATE: 'ai-context:create',\n AICONTEXT_UPDATE: 'ai-context:update',\n AICONTEXT_DELETE: 'ai-context:delete',\n AICONTEXT_SHARE: 'ai-context:share',\n\n // Agent Instruction File resources (read/CRUD seeded in BOFF-2034 follow-up)\n INSTRUCTION_FILE_READ: 'instruction-file:read',\n INSTRUCTION_FILE_CREATE: 'instruction-file:create',\n INSTRUCTION_FILE_UPDATE: 'instruction-file:update',\n INSTRUCTION_FILE_DELETE: 'instruction-file:delete',\n INSTRUCTION_FILE_SHARE: 'instruction-file:share',\n\n // Audit resources\n AUDIT_LIST: 'audit:list',\n AUDIT_READ: 'audit:read',\n AUDIT_DELETE: 'audit:delete',\n AUDIT_EXPORT: 'audit:export',\n\n // Target resources — guards wired in BOFF-2034 (Remaining Pages Audit)\n TARGET_LIST: 'target:list',\n TARGET_READ: 'target:read',\n TARGET_CREATE: 'target:create',\n TARGET_UPDATE: 'target:update',\n TARGET_DELETE: 'target:delete',\n // Target generic-sharing surface (backend `shareTarget`, @rbac resource `target`)\n TARGET_SHARE: 'target:share',\n\n // Catalog resources (read/CRUD seeded in BOFF-2034 follow-up)\n CATALOG_READ: 'catalog:read',\n CATALOG_CREATE: 'catalog:create',\n CATALOG_UPDATE: 'catalog:update',\n CATALOG_DELETE: 'catalog:delete',\n CATALOG_SHARE: 'catalog:share',\n\n // Component resources (read/CRUD seeded in BOFF-2034 follow-up)\n COMPONENT_READ: 'component:read',\n COMPONENT_CREATE: 'component:create',\n COMPONENT_UPDATE: 'component:update',\n COMPONENT_DELETE: 'component:delete',\n COMPONENT_SHARE: 'component:share',\n\n // Template resources (read/CRUD seeded in BOFF-2034 follow-up)\n TEMPLATE_READ: 'template:read',\n TEMPLATE_CREATE: 'template:create',\n TEMPLATE_UPDATE: 'template:update',\n TEMPLATE_DELETE: 'template:delete',\n TEMPLATE_SHARE: 'template:share',\n\n // Scorecard resources. NOTE: `scorecard` is a NEW resourceType — pre-existing\n // workspaces only grant these after their cloned roles are re-synced, so do\n // not hard-gate a page on scorecard:* until that backfill has run.\n SCORECARD_READ: 'scorecard:read',\n SCORECARD_CREATE: 'scorecard:create',\n SCORECARD_UPDATE: 'scorecard:update',\n SCORECARD_DELETE: 'scorecard:delete',\n SCORECARD_SHARE: 'scorecard:share',\n\n // Tunnel resources. The svc enforces `tunnel:read` on list/detail queries\n // (there is no seeded `tunnel:list`), `tunnel:execute` on start/stop/session\n // control, and `tunnel:update` on edits.\n TUNNEL_READ: 'tunnel:read',\n TUNNEL_CREATE: 'tunnel:create',\n TUNNEL_UPDATE: 'tunnel:update',\n TUNNEL_DELETE: 'tunnel:delete',\n TUNNEL_EXECUTE: 'tunnel:execute',\n TUNNEL_SHARE: 'tunnel:share',\n\n // Analytics resources\n ANALYTICS_LIST: 'analytics:list',\n ANALYTICS_READ: 'analytics:read',\n\n // Log resources\n LOG_LIST: 'log:list',\n LOG_READ: 'log:read',\n} as const;\n\nexport type VibePermission = (typeof VIBE_PERMISSIONS)[keyof typeof VIBE_PERMISSIONS];\n"],"mappings":";AAqCA,IAAa,IAAmB;CAE9B,WAAW;CACX,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CACb,WAAW;CACX,aAAa;CAGb,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,cAAc;CACd,cAAc;CAGd,aAAa;CACb,cAAc;CACd,cAAc;CAGd,6BAA6B;CAC7B,+BAA+B;CAC/B,+BAA+B;CAC/B,+BAA+B;CAG/B,6BAA6B;CAG7B,cAAc;CACd,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,iBAAiB;CACjB,eAAe;CAGf,WAAW;CACX,WAAW;CACX,aAAa;CACb,aAAa;CACb,aAAa;CAGb,cAAc;CACd,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAGhB,eAAe;CACf,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,kBAAkB;CAClB,gBAAgB;CAGhB,0BAA0B;CAC1B,0BAA0B;CAC1B,4BAA4B;CAC5B,4BAA4B;CAC5B,4BAA4B;CAC5B,6BAA6B;CAQ7B,eAAe;CACf,eAAe;CACf,kBAAkB;CAGlB,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAGf,gBAAgB;CAChB,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,cAAc;CAGd,gBAAgB;CAChB,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAElB,iBAAiB;CAGjB,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CACf,gBAAgB;CAChB,cAAc;CAGd,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,gBAAgB;CAGhB,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,iBAAiB;CAGjB,uBAAuB;CACvB,yBAAyB;CACzB,yBAAyB;CACzB,yBAAyB;CACzB,wBAAwB;CAGxB,YAAY;CACZ,YAAY;CACZ,cAAc;CACd,cAAc;CAGd,aAAa;CACb,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CAEf,cAAc;CAGd,cAAc;CACd,gBAAgB;CAChB,gBAAgB;CAChB,gBAAgB;CAChB,eAAe;CAGf,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,iBAAiB;CAGjB,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,gBAAgB;CAKhB,gBAAgB;CAChB,kBAAkB;CAClB,kBAAkB;CAClB,kBAAkB;CAClB,iBAAiB;CAKjB,aAAa;CACb,eAAe;CACf,eAAe;CACf,eAAe;CACf,gBAAgB;CAChB,cAAc;CAGd,gBAAgB;CAChB,gBAAgB;CAGhB,UAAU;CACV,UAAU;CACX"}