@flamingo-stack/openframe-frontend-core 0.0.680 → 0.0.682-snapshot.20260929132237

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 (132) hide show
  1. package/dist/{chunk-F5N2P2GD.js → chunk-325BPWHV.js} +9 -9
  2. package/dist/{chunk-T7GIFC5Y.cjs → chunk-3OZUPFWU.cjs} +53 -53
  3. package/dist/{chunk-T7GIFC5Y.cjs.map → chunk-3OZUPFWU.cjs.map} +1 -1
  4. package/dist/{chunk-IGKXYFCP.js → chunk-46XNKZIN.js} +12 -4
  5. package/dist/chunk-46XNKZIN.js.map +1 -0
  6. package/dist/{chunk-ULOUTQBX.js → chunk-4H5DDABI.js} +4 -4
  7. package/dist/{chunk-4DA64VEW.js → chunk-5ERJPXKL.js} +5 -5
  8. package/dist/{chunk-EWZPMPQP.js → chunk-AWZSP7PN.js} +3 -3
  9. package/dist/{chunk-UL2TY6GY.cjs → chunk-BOM6MMWB.cjs} +3 -3
  10. package/dist/{chunk-UL2TY6GY.cjs.map → chunk-BOM6MMWB.cjs.map} +1 -1
  11. package/dist/{chunk-3YWZNB2S.cjs → chunk-BQII6F44.cjs} +12 -12
  12. package/dist/{chunk-3YWZNB2S.cjs.map → chunk-BQII6F44.cjs.map} +1 -1
  13. package/dist/{chunk-DIWJ6NBT.js → chunk-D5MMX7WM.js} +3 -3
  14. package/dist/{chunk-KSDOCJ7B.cjs → chunk-DGPQ7SDN.cjs} +410 -410
  15. package/dist/{chunk-KSDOCJ7B.cjs.map → chunk-DGPQ7SDN.cjs.map} +1 -1
  16. package/dist/{chunk-RLUXVMSD.cjs → chunk-EIPRHSCB.cjs} +54 -54
  17. package/dist/{chunk-RLUXVMSD.cjs.map → chunk-EIPRHSCB.cjs.map} +1 -1
  18. package/dist/{chunk-RSDTLURW.cjs → chunk-EX7ANL73.cjs} +20 -20
  19. package/dist/{chunk-RSDTLURW.cjs.map → chunk-EX7ANL73.cjs.map} +1 -1
  20. package/dist/{chunk-ZFQ3ZHMR.cjs → chunk-H4MWNJEN.cjs} +3 -3
  21. package/dist/{chunk-ZFQ3ZHMR.cjs.map → chunk-H4MWNJEN.cjs.map} +1 -1
  22. package/dist/{chunk-YC7DIARJ.js → chunk-HNEVJK5K.js} +5 -5
  23. package/dist/{chunk-F7EZBJTL.cjs → chunk-L7TFT7T3.cjs} +5 -5
  24. package/dist/{chunk-F7EZBJTL.cjs.map → chunk-L7TFT7T3.cjs.map} +1 -1
  25. package/dist/{chunk-YDJBSKLB.js → chunk-MJSHUJAV.js} +3 -3
  26. package/dist/{chunk-QFGPSBAX.cjs → chunk-MKBYCHZZ.cjs} +43 -43
  27. package/dist/{chunk-QFGPSBAX.cjs.map → chunk-MKBYCHZZ.cjs.map} +1 -1
  28. package/dist/{chunk-BGHQW5D5.js → chunk-NBKMGIHG.js} +2 -2
  29. package/dist/{chunk-SJC2XUTE.cjs → chunk-ND4YQJUE.cjs} +26 -26
  30. package/dist/{chunk-SJC2XUTE.cjs.map → chunk-ND4YQJUE.cjs.map} +1 -1
  31. package/dist/{chunk-JV7SNSYT.js → chunk-NMNFUW7W.js} +6 -6
  32. package/dist/{chunk-XRQKJ22I.cjs → chunk-NMXL34Z2.cjs} +4 -4
  33. package/dist/{chunk-XRQKJ22I.cjs.map → chunk-NMXL34Z2.cjs.map} +1 -1
  34. package/dist/{chunk-ILAHSBZI.cjs → chunk-OOJSD5TO.cjs} +12 -4
  35. package/dist/chunk-OOJSD5TO.cjs.map +1 -0
  36. package/dist/{chunk-FQDHQNSU.js → chunk-P7LRG6QL.js} +2 -2
  37. package/dist/{chunk-FN7DMNA4.js → chunk-Q76YVNCQ.js} +4 -4
  38. package/dist/chunk-Q76YVNCQ.js.map +1 -0
  39. package/dist/{chunk-FRXIDN6T.cjs → chunk-QKXDT4L2.cjs} +5 -5
  40. package/dist/{chunk-FRXIDN6T.cjs.map → chunk-QKXDT4L2.cjs.map} +1 -1
  41. package/dist/{chunk-SPI7DCD3.js → chunk-R24HDQHH.js} +3 -3
  42. package/dist/{chunk-M7ILWHDA.js → chunk-RF2EYX3B.js} +2 -2
  43. package/dist/{chunk-D5QSGV3I.js → chunk-RXVFDCZG.js} +2 -2
  44. package/dist/{chunk-757VTCIH.cjs → chunk-TQFNFMGO.cjs} +17 -17
  45. package/dist/{chunk-757VTCIH.cjs.map → chunk-TQFNFMGO.cjs.map} +1 -1
  46. package/dist/{chunk-FCGZIXI5.cjs → chunk-UMYRFI5B.cjs} +86 -86
  47. package/dist/{chunk-FCGZIXI5.cjs.map → chunk-UMYRFI5B.cjs.map} +1 -1
  48. package/dist/{chunk-V4L2MYXY.js → chunk-UXV77VAJ.js} +4 -4
  49. package/dist/{chunk-2UTUZGMF.cjs → chunk-WBZBGHJ6.cjs} +12 -12
  50. package/dist/{chunk-2UTUZGMF.cjs.map → chunk-WBZBGHJ6.cjs.map} +1 -1
  51. package/dist/{chunk-7OZ5P7Z2.js → chunk-WHLWSMI5.js} +6 -6
  52. package/dist/{chunk-WTNFYZB6.js → chunk-XQQYMP7D.js} +4 -4
  53. package/dist/{chunk-VWYK6TSE.cjs → chunk-XXGQUVFO.cjs} +13 -13
  54. package/dist/{chunk-VWYK6TSE.cjs.map → chunk-XXGQUVFO.cjs.map} +1 -1
  55. package/dist/{chunk-4NUKFUPW.cjs → chunk-Y6NJCG2F.cjs} +7 -7
  56. package/dist/{chunk-4NUKFUPW.cjs.map → chunk-Y6NJCG2F.cjs.map} +1 -1
  57. package/dist/{chunk-C5RRTWYW.js → chunk-YPQSZEF3.js} +5 -5
  58. package/dist/{chunk-75S3RKYX.js → chunk-YRTI6VJE.js} +9 -9
  59. package/dist/{chunk-KQXKQ4PX.cjs → chunk-Z2YYFGIY.cjs} +22 -22
  60. package/dist/{chunk-KQXKQ4PX.cjs.map → chunk-Z2YYFGIY.cjs.map} +1 -1
  61. package/dist/{chunk-YFU7BULM.cjs → chunk-ZVRVMJTL.cjs} +39 -39
  62. package/dist/{chunk-YFU7BULM.cjs.map → chunk-ZVRVMJTL.cjs.map} +1 -1
  63. package/dist/components/case-studies/index.cjs +17 -17
  64. package/dist/components/case-studies/index.js +5 -5
  65. package/dist/components/chat/index.cjs +3 -3
  66. package/dist/components/chat/index.js +2 -2
  67. package/dist/components/contact/index.cjs +6 -6
  68. package/dist/components/contact/index.js +5 -5
  69. package/dist/components/docs/index.cjs +9 -9
  70. package/dist/components/docs/index.js +8 -8
  71. package/dist/components/embeds/index.cjs +6 -6
  72. package/dist/components/embeds/index.js +5 -5
  73. package/dist/components/empty-state.d.ts.map +1 -1
  74. package/dist/components/faq/index.cjs +6 -6
  75. package/dist/components/faq/index.js +5 -5
  76. package/dist/components/features/index.cjs +5 -5
  77. package/dist/components/features/index.js +4 -4
  78. package/dist/components/help-center-pages/index.cjs +85 -85
  79. package/dist/components/help-center-pages/index.js +18 -18
  80. package/dist/components/index.cjs +47 -47
  81. package/dist/components/index.js +17 -17
  82. package/dist/components/meeting-scheduler/index.cjs +37 -37
  83. package/dist/components/meeting-scheduler/index.js +6 -6
  84. package/dist/components/navigation/index.cjs +8 -8
  85. package/dist/components/navigation/index.js +7 -7
  86. package/dist/components/onboarding-guides/index.cjs +8 -8
  87. package/dist/components/onboarding-guides/index.js +7 -7
  88. package/dist/components/tickets/index.cjs +10 -10
  89. package/dist/components/tickets/index.js +9 -9
  90. package/dist/components/tool-icon.d.ts.map +1 -1
  91. package/dist/components/ui/index.cjs +5 -5
  92. package/dist/components/ui/index.js +4 -4
  93. package/dist/hooks/index.cjs +3 -3
  94. package/dist/hooks/index.js +2 -2
  95. package/dist/index.cjs +10 -10
  96. package/dist/index.js +8 -8
  97. package/dist/types/index.cjs +6 -2
  98. package/dist/types/index.cjs.map +1 -1
  99. package/dist/types/index.js +6 -2
  100. package/dist/types/index.js.map +1 -1
  101. package/dist/types/tool.types.d.ts +2 -0
  102. package/dist/types/tool.types.d.ts.map +1 -1
  103. package/dist/utils/index.cjs +3 -1
  104. package/dist/utils/index.cjs.map +1 -1
  105. package/dist/utils/index.js +3 -1
  106. package/dist/utils/index.js.map +1 -1
  107. package/package.json +1 -1
  108. package/src/components/__tests__/empty-state-cta.test.tsx +31 -0
  109. package/src/components/empty-state.tsx +5 -6
  110. package/src/components/tool-icon.tsx +4 -0
  111. package/src/types/tool.types.ts +4 -0
  112. package/dist/chunk-FN7DMNA4.js.map +0 -1
  113. package/dist/chunk-IGKXYFCP.js.map +0 -1
  114. package/dist/chunk-ILAHSBZI.cjs.map +0 -1
  115. /package/dist/{chunk-F5N2P2GD.js.map → chunk-325BPWHV.js.map} +0 -0
  116. /package/dist/{chunk-ULOUTQBX.js.map → chunk-4H5DDABI.js.map} +0 -0
  117. /package/dist/{chunk-4DA64VEW.js.map → chunk-5ERJPXKL.js.map} +0 -0
  118. /package/dist/{chunk-EWZPMPQP.js.map → chunk-AWZSP7PN.js.map} +0 -0
  119. /package/dist/{chunk-DIWJ6NBT.js.map → chunk-D5MMX7WM.js.map} +0 -0
  120. /package/dist/{chunk-YC7DIARJ.js.map → chunk-HNEVJK5K.js.map} +0 -0
  121. /package/dist/{chunk-YDJBSKLB.js.map → chunk-MJSHUJAV.js.map} +0 -0
  122. /package/dist/{chunk-BGHQW5D5.js.map → chunk-NBKMGIHG.js.map} +0 -0
  123. /package/dist/{chunk-JV7SNSYT.js.map → chunk-NMNFUW7W.js.map} +0 -0
  124. /package/dist/{chunk-FQDHQNSU.js.map → chunk-P7LRG6QL.js.map} +0 -0
  125. /package/dist/{chunk-SPI7DCD3.js.map → chunk-R24HDQHH.js.map} +0 -0
  126. /package/dist/{chunk-M7ILWHDA.js.map → chunk-RF2EYX3B.js.map} +0 -0
  127. /package/dist/{chunk-D5QSGV3I.js.map → chunk-RXVFDCZG.js.map} +0 -0
  128. /package/dist/{chunk-V4L2MYXY.js.map → chunk-UXV77VAJ.js.map} +0 -0
  129. /package/dist/{chunk-7OZ5P7Z2.js.map → chunk-WHLWSMI5.js.map} +0 -0
  130. /package/dist/{chunk-WTNFYZB6.js.map → chunk-XQQYMP7D.js.map} +0 -0
  131. /package/dist/{chunk-C5RRTWYW.js.map → chunk-YPQSZEF3.js.map} +0 -0
  132. /package/dist/{chunk-75S3RKYX.js.map → chunk-YRTI6VJE.js.map} +0 -0
@@ -150,7 +150,9 @@ var ToolTypeValues = {
150
150
  OPENFRAME_CLIENT: "OPENFRAME_CLIENT",
151
151
  OPENFRAME_RMM: "OPENFRAME_RMM",
152
152
  OSQUERY: "OSQUERY",
153
- SYSTEM: "SYSTEM"
153
+ SYSTEM: "SYSTEM",
154
+ MICROSOFT_365: "MICROSOFT_365",
155
+ GOOGLE_WORKSPACE: "GOOGLE_WORKSPACE"
154
156
  };
155
157
  var toolLabels = {
156
158
  FLEET_MDM: "Fleet",
@@ -161,7 +163,9 @@ var toolLabels = {
161
163
  OPENFRAME_CLIENT: "OpenFrame Client",
162
164
  OPENFRAME_RMM: "RMM",
163
165
  OSQUERY: "Osquery",
164
- SYSTEM: "System"
166
+ SYSTEM: "System",
167
+ MICROSOFT_365: "Microsoft 365",
168
+ GOOGLE_WORKSPACE: "Google Workspace"
165
169
  };
166
170
  function ShellIcon({
167
171
  className = "w-5 h-5",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/announcement.ts","../../src/types/product-release.ts","../../src/types/delivery.ts","../../src/types/video-processing.ts","../../src/utils/escape-regexp.ts","../../src/types/trust-center.ts","../../src/types/tool.types.ts","../../src/components/icons/shell-icon.tsx","../../src/utils/cn.ts","../../src/components/icons/cmd-icon.tsx","../../src/components/icons/bash-icon.tsx","../../src/components/icons/nushell-icon.tsx","../../src/components/icons/deno-icon.tsx","../../src/components/icons-v2-generated/brand-logos/powershell-logo-icon.tsx","../../src/components/icons-v2-generated/brand-logos/python-logo-icon.tsx","../../src/types/shell.types.ts","../../src/components/icons-v2-generated/brand-logos/apple-logo-icon.tsx","../../src/components/icons-v2-generated/brand-logos/linux-logo-icon.tsx","../../src/components/icons-v2-generated/brand-logos/windows-logo-grey-icon.tsx","../../src/types/os.types.ts","../../src/types/tmcg.ts"],"names":["jsx","extendTailwindMerge","jsxs"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { EntityPlatformAssoc } from './entity-platform';\n// Announcement system TypeScript types\nimport type { LegacyPlatform, PlatformFilter } from './platform';\n\n// Database Models\nexport interface Announcement {\n id: string;\n title: string;\n description: string;\n background_color: string;\n icon_name?: string;\n icon_url?: string;\n /** Extra props for the main bar/icon */\n icon_props?: Record<string, unknown>;\n /** Hydrated entity_platforms associations (featured-first) — what the hub\n * DAL's attachPlatformsToRow(s) emits. No singular platform/platform_id. */\n announcement_platforms?: EntityPlatformAssoc[];\n is_active: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled?: boolean;\n cta_text?: string;\n cta_icon_name?: string;\n cta_show_icon?: boolean;\n cta_url?: string;\n cta_target?: '_self' | '_blank';\n // Custom CTA button colors (hex codes like #FFFFFF). Optional.\n cta_button_background_color?: string | null;\n cta_button_text_color?: string | null;\n /** Additional props to spread onto the CTA icon component */\n cta_icon_props?: Record<string, unknown>;\n created_at: string;\n updated_at: string;\n created_by?: string;\n created_by_user?: {\n id: string;\n email: string;\n full_name?: string;\n };\n announcement_assets?: AnnouncementAsset[];\n}\n\nexport interface AnnouncementAsset {\n id: string;\n announcement_id: string;\n file_name: string;\n file_url: string;\n file_size: number;\n mime_type: string;\n upload_path: string;\n created_at: string;\n}\n\n// API Request/Response Types\nexport interface CreateAnnouncementData {\n title: string;\n description: string;\n background_color: string;\n icon_name?: string;\n icon_url?: string;\n /** Extra props for the main bar/icon */\n icon_props?: Record<string, unknown>;\n platforms?: string[]; // entity_platforms set (multi-select)\n is_active?: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled?: boolean;\n cta_text?: string;\n cta_icon_name?: string;\n cta_show_icon?: boolean;\n cta_url?: string;\n cta_target?: '_self' | '_blank';\n cta_button_background_color?: string;\n cta_button_text_color?: string;\n cta_icon_props?: Record<string, unknown>;\n created_by: string;\n}\n\nexport interface UpdateAnnouncementData {\n title?: string;\n description?: string;\n background_color?: string;\n icon_name?: string;\n icon_url?: string;\n /** Extra props for the main bar/icon */\n icon_props?: Record<string, unknown>;\n platforms?: string[]; // entity_platforms set (multi-select)\n is_active?: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled?: boolean;\n cta_text?: string;\n cta_icon_name?: string;\n cta_show_icon?: boolean;\n cta_url?: string;\n cta_target?: '_self' | '_blank';\n cta_button_background_color?: string;\n cta_button_text_color?: string;\n cta_icon_props?: Record<string, unknown>;\n}\n\nexport interface AnnouncementListResponse {\n announcements: Announcement[];\n pagination: {\n page: number;\n page_size: number;\n total_count: number;\n total_pages: number;\n };\n filters?: {\n platform?: LegacyPlatform;\n is_active?: boolean;\n };\n}\n\n/**\n * Wire shape of GET /api/announcements/active — the single typed home for the\n * `{ announcement }` envelope (hub route return + AnnouncementBar's\n * useSelfFetch generic). `null` when no active announcement exists.\n */\nexport interface AnnouncementResponse {\n announcement: Announcement | null;\n}\n\n/**\n * Default CTA button colors — one home for the pair the DAL create/update\n * defaults and the admin form both reference. Announcement colors are\n * admin-chosen data (not ODS-token surfaces) by design.\n */\nexport const ANNOUNCEMENT_CTA_DEFAULTS = {\n background: '#1A1A1A',\n text: '#FAFAFA',\n} as const;\n\n// Form Data Types\nexport interface AnnouncementFormData {\n title: string;\n description: string;\n background_color: string;\n icon_name: string;\n icon_url?: string;\n platforms: string[]; // entity_platforms set (multi-select; no single platform_id)\n is_active: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled: boolean;\n cta_text: string;\n cta_icon_name: string;\n cta_show_icon: boolean;\n cta_url: string;\n cta_target: '_self' | '_blank';\n // New CTA button custom colors\n cta_button_background_color?: string;\n cta_button_text_color?: string;\n cta_icon_props?: string; // JSON string in form\n /** Extra props for the main bar/icon */\n icon_props?: string;\n}\n\n// API Query Parameters\nexport interface GetAnnouncementsOptions {\n platform?: PlatformFilter; // Changed from Platform to PlatformFilter to include 'all'\n is_active?: boolean;\n page?: number;\n pageSize?: number;\n sortBy?: 'created_at' | 'updated_at' | 'title';\n sortOrder?: 'asc' | 'desc';\n}\n\n// File Upload Types\nexport interface IconUploadResponse {\n success: boolean;\n file_url?: string;\n file_name?: string;\n file_size?: number;\n error?: string;\n}\n\nexport interface IconUploadData {\n file: File;\n announcement_id?: string;\n}\n\n// Available SVG Icons (extend as needed)\nexport interface AvailableSvgIcon {\n name: string;\n display_name: string;\n component_name: string;\n}\n\n// Error Types\nexport interface AnnouncementError {\n code: string;\n message: string;\n details?: string;\n}\n\n// Validation Types\nexport interface AnnouncementValidation {\n title: {\n required: boolean;\n minLength: number;\n maxLength: number;\n };\n description: {\n required: boolean;\n minLength: number;\n maxLength: number;\n };\n background_color: {\n required: boolean;\n pattern: RegExp;\n };\n icon_name: {\n required: boolean;\n validOptions: string[];\n };\n platform: {\n required: boolean;\n validOptions: LegacyPlatform[];\n };\n}\n\n// Import unified platform configuration (removed duplicate definition)\nexport type { PlatformConfig } from './platform';\n\n// Component Props Types\nexport interface AnnouncementBarProps {\n /**\n * SSR mode seed. `null` = the server resolved \"nothing to show\" (no active\n * announcement, or dismissed via cookie) — seeds the fetch hook and skips\n * the mount fetch. Absent (`undefined`) = client-only mode: the bar\n * self-fetches on mount from the EndpointsRuntime provider's\n * `announcementsUrl` (see react-embedding-example — no per-component URL\n * or platform knobs; the server resolves its own platform via\n * currentPlatform()).\n */\n initialAnnouncement?: Announcement | null;\n /**\n * Render-only mode for the admin live preview: no fetch/revalidation, inert\n * dismiss button, and no storage side effects (never writes dismissal\n * cookies or touches localStorage).\n */\n previewMode?: boolean;\n /**\n * When false, the dismiss (X) button is not rendered — the bar can only\n * disappear by deactivating the announcement. Default true.\n */\n dismissible?: boolean;\n className?: string;\n}\n\nexport interface AnnouncementFormProps {\n announcement?: Announcement;\n onSubmit: (data: AnnouncementFormData) => Promise<void>;\n onCancel: () => void;\n isLoading?: boolean;\n availableIcons: AvailableSvgIcon[];\n}\n\nexport interface AnnouncementListProps {\n announcements: Announcement[];\n onEdit: (announcement: Announcement) => void;\n onDelete: (announcementId: string) => void;\n onToggleActive: (announcementId: string, isActive: boolean) => void;\n isLoading?: boolean;\n}\n\n// Database Utility Types\nexport interface AnnouncementFilters {\n platform?: LegacyPlatform;\n is_active?: boolean;\n created_by?: string;\n search?: string;\n}\n\nexport interface AnnouncementSortOptions {\n field: 'created_at' | 'updated_at' | 'title' | 'platform';\n direction: 'asc' | 'desc';\n}\n\n// SVG Icon Type\nexport interface SvgIcon {\n name: string;\n label: string;\n /** Optional pre-resolved glyph component. Every registry below (and every\n * known consumer) passes `null` and renders by `name` through the shared\n * icon resolver — the slot is kept for callers that carry a component. */\n component: React.ComponentType<React.SVGProps<SVGSVGElement>> | null;\n}\n\n// Platform display configuration\n// PLATFORM_CONFIGS removed - all platform data now comes from database via getPlatformsConfig()\n\n// Available SVG icons configuration\nexport const AVAILABLE_SVG_ICONS: SvgIcon[] = [\n // OpenFrame Logo Options\n { name: 'openframe-logo', label: 'OpenFrame Logo', component: null },\n\n // Platform Logos\n { name: 'openmsp-logo', label: 'OpenMSP Logo', component: null },\n { name: 'flamingo-logo', label: 'Flamingo Logo', component: null },\n\n // Lucide Icons\n { name: 'megaphone', label: 'Megaphone', component: null },\n { name: 'bell', label: 'Bell', component: null },\n { name: 'info', label: 'Information', component: null },\n { name: 'star', label: 'Star', component: null },\n { name: 'rocket', label: 'Rocket', component: null },\n { name: 'package', label: 'Package', component: null },\n];\n","// Product Release Types\n// Following the blog.ts pattern for consistency\n\nimport type { BlogTag, TagAssoc } from './blog';\nimport type { EntityAuthor } from './entity-author';\nimport type { PlatformRecord } from './platform';\nimport type { VideoTeaser, TranscriptWord, SpeakerMapping } from './video-processing';\n\nexport interface ChangelogEntry {\n title: string;\n description?: string;\n /**\n * Per-entry visibility flag. Optional so product releases (which always render\n * publicly) remain backwards compatible. Investor updates require this field\n * because each entry can be marked internal — see investor-update-utils.ts.\n */\n visibility?: 'public' | 'internal';\n /**\n * Optional per-entry classification chosen from the manager's `tagOptions`\n * (e.g. an owner, a priority, a severity). Product releases never set it.\n */\n tag?: string;\n}\n\nexport interface ReleaseMedia {\n id: number;\n release_id: number;\n media_type: 'image' | 'video' | 'screenshot' | 'demo';\n media_url: string;\n display_order: number | null;\n title: string | null;\n description: string | null;\n created_at: string;\n updated_at: string;\n created_by: string;\n}\n\nexport interface ProductReleaseGitHubLink {\n id: number;\n release_id: number;\n github_release_url: string; // Full URL (e.g., https://github.com/org/repo/releases/tag/v2.0.0)\n display_order: number | null;\n created_at: string;\n}\n\nexport interface KnowledgeBaseLink {\n id: number;\n release_id: number;\n kb_article_path: string; // Relative path (e.g., /api/authentication/api-keys.md)\n display_order: number | null;\n created_at: string;\n}\n\nexport interface ClickUpRoadmapTask {\n id: number;\n release_id: number;\n clickup_task_id: string; // Just the task ID - details from roadmap folder\n display_order: number | null;\n created_at: string;\n}\n\nexport interface ClickUpDeliveryTask {\n id: number;\n release_id: number;\n clickup_task_id: string; // Just the task ID - details from delivery list\n display_order: number | null;\n created_at: string;\n}\n\nexport interface ProductRelease {\n id: number;\n title: string;\n slug: string;\n version: string;\n summary: string | null;\n content: string | null;\n\n // Release metadata\n release_type: 'major' | 'minor' | 'patch' | 'beta' | 'alpha';\n release_status: 'alpha' | 'beta' | 'stable' | 'deprecated';\n release_date: string;\n\n // Changelog (JSONB arrays)\n features_added: ChangelogEntry[];\n bugs_fixed: ChangelogEntry[];\n improvements: ChangelogEntry[];\n breaking_changes: ChangelogEntry[];\n\n // External relationships (one-to-many)\n github_releases?: ProductReleaseGitHubLink[];\n knowledge_base_links?: KnowledgeBaseLink[];\n clickup_roadmap_tasks?: ClickUpRoadmapTask[];\n clickup_delivery_tasks?: ClickUpDeliveryTask[];\n release_media?: ReleaseMedia[];\n\n // Media (keeping featured_image for hero)\n featured_image: string | null;\n\n // Documentation\n migration_guide_url: string | null;\n documentation_url: string | null;\n\n // Video (youtube_url for embeds, main_video_url for AI processing)\n youtube_url: string | null;\n main_video_url: string | null;\n transcript: string | null;\n transcript_words_data?: TranscriptWord[];\n srt_content?: string | null;\n highlight_srt_content?: string | null;\n video_summary: string | null; // AI-generated summary from video transcription\n video_bites: VideoTeaser[]; // JSONB array of extracted video clips\n highlight_video_url: string | null;\n highlight_video_thumbnail: string | null;\n highlight_video_duration_ms: number | null;\n highlight_video_source: 'manual' | 'ai_generated' | null;\n main_video_thumbnail: string | null;\n ai_transcript_formatted?: string;\n speaker_mapping?: SpeakerMapping;\n ai_confidence_transcript: number | null;\n ai_confidence_video_summary: number | null; // Confidence for video-generated summary\n ai_confidence_summary: number | null; // Confidence for entity summary (Release Content Generation)\n\n // SEO\n seo_title: string | null;\n seo_description: string | null;\n seo_keywords: string | null;\n og_image_url: string | null;\n\n // Publishing\n status: 'draft' | 'published' | 'archived';\n published_at: string | null;\n author_id: string | null;\n\n // HubSpot marketing email (mirrors InvestorUpdate). `hubspot_email_id` is the\n // stored HubSpot email id; `hubspot_email_url` is computed by the admin GET\n // route from the production portal id (never persisted).\n hubspot_email_id?: string | null;\n hubspot_email_url?: string | null;\n /**\n * Hydrated by `getRelease` (detail) and `getReleases` (list) via\n * `hydrateAuthor` in the hub DAL. Optional so admin form + every existing\n * consumer that doesn't read author stay backward-compatible.\n */\n author?: EntityAuthor;\n\n // Timestamps\n created_at: string;\n updated_at: string;\n\n // Editor-provided AI generation instructions (steers Generate Content prompt)\n custom_instructions: string | null;\n\n // Analytics\n view_count: number;\n download_count: number;\n\n // Relations (populated by joins)\n platforms?: PlatformRecord[];\n tags?: BlogTag[];\n product_release_platforms?: Array<{\n platform_id: string;\n is_featured: boolean;\n featured_order: number | null;\n // The release DAL flattens the joined `platforms` row onto each junction\n // entry (`...platform.platforms`), so `name`/`display_name` are present at\n // runtime — `composeContentUrlFromPlatforms` reads `name` to resolve the\n // target platform. Declared here so callers can pass this array to the\n // `composeContentUrl` seam without a cast.\n name?: string;\n display_name?: string;\n }>;\n // Flat unified tag-association shape (hydrated by entity-tag-utils).\n product_release_tags?: TagAssoc[];\n}\n\nexport interface CreateProductReleaseData {\n title: string;\n slug: string;\n version: string;\n summary?: string;\n content?: string;\n release_type: 'major' | 'minor' | 'patch' | 'beta' | 'alpha';\n release_status: 'alpha' | 'beta' | 'stable' | 'deprecated';\n release_date: string;\n features_added?: ChangelogEntry[];\n bugs_fixed?: ChangelogEntry[];\n improvements?: ChangelogEntry[];\n breaking_changes?: ChangelogEntry[];\n github_releases?: Array<{ github_release_url: string; display_order?: number }>;\n knowledge_base_links?: Array<{ kb_article_path: string; display_order?: number }>;\n clickup_roadmap_tasks?: Array<{ clickup_task_id: string; display_order?: number }>;\n clickup_delivery_tasks?: Array<{ clickup_task_id: string; display_order?: number }>;\n release_media?: Array<{\n media_type: 'image' | 'video' | 'screenshot' | 'demo';\n media_url: string;\n title?: string;\n description?: string;\n display_order?: number;\n }>;\n featured_image?: string;\n migration_guide_url?: string;\n documentation_url?: string;\n youtube_url?: string;\n main_video_url?: string;\n transcript?: string;\n srt_content?: string | null;\n highlight_srt_content?: string | null;\n video_summary?: string; // AI-generated summary from video transcription\n video_bites?: VideoTeaser[];\n highlight_video_url?: string | null;\n highlight_video_thumbnail?: string | null;\n highlight_video_duration_ms?: number | null;\n highlight_video_source?: 'manual' | 'ai_generated' | null;\n main_video_thumbnail?: string | null;\n seo_title?: string;\n seo_description?: string;\n seo_keywords?: string;\n og_image_url?: string;\n status: 'draft' | 'published' | 'archived';\n published_at?: string | null;\n author_id: string;\n platforms: string[]; // Array of platform IDs (UUIDs)\n featured_platform?: string; // Platform ID for featured\n tags: number[]; // Array of tag IDs\n custom_instructions?: string | null;\n}\n\nexport type UpdateProductReleaseData = Partial<CreateProductReleaseData>;\n\nexport interface ProductReleaseFilters {\n platform?: string | 'all';\n tags?: string[];\n version?: string;\n release_type?: ('major' | 'minor' | 'patch' | 'beta' | 'alpha')[];\n release_status?: ('alpha' | 'beta' | 'stable' | 'deprecated')[];\n has_breaking_changes?: boolean;\n search?: string;\n featured?: boolean;\n status?: string;\n limit?: number;\n offset?: number;\n ids?: (number | string)[];\n}\n\nexport interface ProductReleaseListResponse {\n data: ProductRelease[];\n count: number;\n}\n\n// GitHub Release interface (for wizard)\nexport interface GitHubRelease {\n id: string;\n tag_name: string;\n name: string;\n body: string;\n published_at: string;\n html_url: string;\n prerelease: boolean;\n draft: boolean;\n}\n\n// Release type options for dropdowns\nexport const releaseTypeOptions = [\n { value: 'major', label: 'Major Release', description: 'Breaking changes, new architecture', color: 'red' },\n { value: 'minor', label: 'Minor Release', description: 'New features, backward compatible', color: 'blue' },\n { value: 'patch', label: 'Patch Release', description: 'Bug fixes only', color: 'green' },\n { value: 'beta', label: 'Beta Release', description: 'Pre-release testing version', color: 'yellow' },\n { value: 'alpha', label: 'Alpha Release', description: 'Early testing version', color: 'orange' },\n] as const;\n\n// Release status options\nexport const releaseStatusOptions = [\n { value: 'alpha', label: 'Alpha', description: 'Early development, unstable', color: 'orange' },\n { value: 'beta', label: 'Beta', description: 'Feature complete, testing', color: 'yellow' },\n { value: 'stable', label: 'Stable', description: 'Production ready', color: 'green' },\n { value: 'deprecated', label: 'Deprecated', description: 'No longer supported', color: 'gray' },\n] as const;\n\n// Changelog category labels\nexport const changelogLabels = {\n features_added: 'Features Added',\n bugs_fixed: 'Bugs Fixed',\n improvements: 'Improvements',\n breaking_changes: 'Breaking Changes',\n} as const;\n\n// Semantic versioning validation regex\nexport const SEMVER_REGEX = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$/;\n","/**\n * Delivery (ClickUp Bug-fixes & Enhancements) wire types — shared between the\n * hub's `/api/delivery*` route shapes and the lib's `DeliveryTable`/`DeliveryLists`/\n * `DeliverySection` components.\n *\n * Lifted from hub `types/delivery.ts` so embedders consuming the lib's\n * delivery surfaces and the lib's own `ReleaseDetailPage` (which renders\n * related delivery items) share one canonical shape.\n */\n\n/**\n * Display identity for a task assignee — WIRE-SAFE shape: name + avatar\n * only, resolved server-side (ClickUp assignee × profiles). Emails are\n * deliberately NOT on the wire; the roadmap/delivery boards are public\n * surfaces (same policy as the RAG mappers). Feeds `AvatarStack`\n * directly.\n */\nexport interface TaskAssigneeDisplay {\n /** ClickUp member id — stable render key. */\n id: number;\n name: string | null;\n avatarUrl: string | null;\n}\n\nexport interface DeliveryItem {\n id: string;\n title: string;\n description: string;\n status: string;\n statusColor: string; // ClickUp status color\n taskType: 'Request' | 'Bug' | string; // ClickUp task type\n /**\n * Canonical ClickUp custom_item_id (1008 = Bug, 1009 = Request, …).\n * Surfaced here so the chat's compact card can render a type-specific\n * lucide icon via `TaskTypeIcon` instead of the two-letter initials\n * fallback. Single source of truth lives in\n * `lib/utils/clickup-task-type-utils.ts` (hub-side).\n */\n customItemId: number | null;\n /** Assignee display identities (name + avatar, never email) — powers\n * the AvatarStack on cards. Optional: producers that don't enrich\n * (e.g. activity-cache recent_tasks) simply omit it. */\n assignees?: TaskAssigneeDisplay[];\n /**\n * Every ClickUp list the task is associated with (home list + ClickUp's\n * \"Tasks in Multiple Lists\" locations). UI joins these for display.\n * Falls back to a single-element array containing the home list when\n * there are no additional locations.\n */\n listNames: string[];\n dateOpened: number; // Unix timestamp\n dateUpdated: number; // Unix timestamp\n dateClosed: number | null; // Unix timestamp or null if not closed\n clickupUrl: string;\n}\n\nexport interface DeliveryResponse {\n completed: DeliveryItem[];\n inProgress: DeliveryItem[];\n}\n\n// Task type to badge label mapping\nexport const TASK_TYPE_LABELS = {\n Request: 'ENHANCEMENT',\n Bug: 'BUG-FIX',\n} as const;\n\n// Task type to badge text-color mapping (ODS attention-red for Bug; default for others)\nexport const TASK_TYPE_TEXT_COLORS = {\n Request: '', // Default white/grey\n Bug: 'text-[var(--ods-attention-red-error)]',\n} as const;\n","// Video Processing Shared Types\n// Used by CustomerInterview, ProductRelease, and future video-enabled entities\n\n/**\n * VideoTeaser represents a short video clip extracted from a longer video.\n * Used for teasers/bites that can be shown on preview pages.\n *\n * CANONICAL BITE SHAPE: this is the base persistence type — the TRUE SUPERSET\n * of every field persisted in the `video_bites` / `teasers` jsonb columns.\n * `VideoTeaserWithRatio` (video-ratio-tabs.tsx) adds only `aspect_ratio` and is\n * the one type display/aggregation code extends. The AI-extraction `VideoClip`\n * below stays a separate shape by design.\n */\nexport interface VideoTeaser {\n id?: string; // Stable 8-char lowercase-hex element id (see utils/video-bite-id.ts). Stamped at creation (editor + AI save) and lazily backfilled by the Mux reconciliation sweep. Identity key for the Mux transcode pipeline — never derived from url (urls have real-world duplicates).\n url: string;\n source_url?: string; // Original storage URL, set by the Mux pipeline when it flips `url` to the HLS playback URL. Merge-identity leg for redelivered ingests + transcode dedup. Never set by editors.\n title?: string;\n thumbnail_url?: string; // Optional thumbnail image URL for video preview. If not provided, video player will show first frame automatically.\n published?: boolean; // Controls visibility on public preview page (default: false, admin must select)\n featured?: boolean; // Opts the bite into cross-entity featured pulls (homepage/configured surfaces). Independent of `published`.\n featured_at?: string; // ISO timestamp stamped when an admin features the bite (cleared on unfeature; all featured bites backfilled 2026-08-19). Featured surfaces rank by THIS — ranking by created_at made featuring an old bite invisible under the surface cap.\n source?: 'manual' | 'ai_generated'; // Track origin of teaser\n created_at?: string; // ISO timestamp for sorting (newer items first)\n start_time_ms?: number; // Vizard extraction: clip start offset in the source video\n end_time_ms?: number; // Vizard extraction: clip end offset in the source video\n confidence?: number; // Vizard extraction: 0-100 virality confidence\n viral_reason?: string; // Vizard extraction: why this clip was picked\n // Duration auto-detected from video file\n}\n\n/**\n * Speaker identification for transcription\n */\n/**\n * A short customer quote pulled from a video entity (case study, customer\n * interview) — a headline line in the customer's own words. Attribution is NOT\n * stored on the item: it is the entity's customer (`user_id` → profile + MSP).\n * `key` is stable across edits so list editors can reconcile rows.\n */\nexport interface EntityQuote {\n key: string;\n text: string;\n /** Who said it, when the recording has several voices (a prospect call). Case studies attribute to their customer instead. */\n speaker?: string | null;\n /** `ai` while the text is exactly what Transcribe & Summarize extracted; an editor edit makes it `manual`. */\n source?: 'ai' | 'manual';\n}\n\n/** The caption every quote list carries: the admin editor and the `EntityQuotesPanel` display. */\nexport const ENTITY_QUOTES_TITLE = 'Key Quotes';\n\nexport interface Speaker {\n label: string;\n name?: string;\n confidence?: number;\n}\n\n/**\n * VideoClip represents a segment identified by AI analysis\n */\nexport interface VideoClip {\n start_time: number;\n end_time: number;\n description: string;\n query_used: string;\n confidence: number;\n twelve_labs_id?: string;\n thumbnail_url?: string;\n}\n\n/**\n * Word-level transcript data for precise video processing\n */\nexport interface TranscriptWord {\n text: string;\n start: number; // milliseconds\n end: number; // milliseconds\n confidence: number;\n speaker?: string;\n}\n\n/**\n * Speaker mapping for interview/video transcripts\n * Maps AssemblyAI labels (\"A\", \"B\") to actual person info\n */\nexport interface SpeakerMapping {\n [label: string]: {\n name: string;\n role: 'interviewer' | 'interviewee' | 'presenter' | 'host' | 'guest';\n userId?: string;\n };\n}\n\n/**\n * Excluded time ranges (e.g., for incentive mentions)\n */\nexport interface ExcludedRange {\n start: number; // seconds\n end: number; // seconds\n}\n\n/**\n * Base video processing fields shared across entities\n */\nexport interface VideoProcessingFields {\n main_video_url: string | null;\n transcript: string | null;\n transcript_words_data?: TranscriptWord[];\n srt_content?: string | null;\n highlight_video_url?: string | null;\n highlight_video_thumbnail?: string | null;\n highlight_video_duration_ms?: number | null;\n highlight_video_source?: 'manual' | 'ai_generated' | null;\n /** Persisted first-frame thumbnail from main video upload (client-side canvas extraction) */\n main_video_thumbnail?: string | null;\n ai_transcript_formatted?: string;\n speaker_mapping?: SpeakerMapping;\n ai_confidence_transcript?: number | null;\n ai_confidence_summary?: number | null;\n}\n\n/**\n * Entity types that support agent processing\n * - customer_interview: Customer interview videos with transcription/bites/highlight\n * - product_release: Product release videos with transcription/bites/highlight\n * - marketing_campaign: Marketing campaign content generation (autonomous workflow)\n * - case_study: Case study generation from customer interviews\n * - onboarding_guide: Step-by-step onboarding guides with optional video walkthrough\n * - what_i_shipped: Monthly employee \"What I Shipped\" entries (people-hub) with transcription/bites/highlight\n * - how_i_work: Recorded employee AI-workflow sessions (people-hub) with transcription/bites/highlight\n */\nexport type VideoProcessingEntityType =\n | 'customer_interview'\n | 'product_release'\n | 'marketing_campaign'\n | 'case_study'\n | 'webinar'\n | 'podcast_episode'\n | 'investor_update'\n | 'onboarding_guide'\n | 'what_i_shipped'\n | 'how_i_work'\n | 'walkthrough_video'\n | 'prospect_call';\n// Fri May 15 14:58:59 EDT 2026\n","/**\n * Escape every RegExp meta-character in `value`, so text can be matched\n * literally inside a `new RegExp(...)` (a search query of `(c)` or `a+b`, a URL\n * prefix). Zero-dependency and server-safe.\n */\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * Trust Center wire types + vocabulary — the ONE contract between the hub's\n * `/api/trust-center` projection (Vanta snapshot → public-safe payload) and the\n * lib's `<TrustCenterPage>`.\n *\n * Server-safe (no React, no DOM): the hub DAL, route and chat mapper import it\n * from `@flamingo-stack/openframe-frontend-core/types`.\n *\n * PUBLICATION POLICY lives hub-side (`lib/data/trust-center-public.ts`); this\n * module only names the shape and the vocabulary every surface renders:\n * - only PASSING controls are ever on the wire (Vanta's SHOW_OK_ONLY practice);\n * - `percent` is present only when the hub decided it is publishable;\n * - no totals, failing counts, owners, people or remediation text exist here.\n */\nimport { escapeRegExp } from '../utils/escape-regexp';\nimport type { Faq } from './faq';\n\n/**\n * A framework's MONITORING state, from Vanta's live data — Vanta keeps no\n * certification status, so none is claimed. `monitored` always carries Vanta's\n * own completion (`percent`: controls completed / total, as Vanta's app shows\n * it); `not_monitored` is a framework on the Trust Center that Vanta does not\n * monitor yet, shown as \"Planned\". Label, badge colour and icon are owned\n * HERE, once.\n */\nexport const TRUST_FRAMEWORK_MONITORING = [\n { state: 'monitored', label: 'Monitored', color: 'cyan', icon: 'shield-check' },\n { state: 'not_monitored', label: 'Planned', color: 'pinkSoft', icon: 'file-shield' },\n] as const;\n\nexport type TrustFrameworkMonitoring = (typeof TRUST_FRAMEWORK_MONITORING)[number]['state'];\nexport type TrustFrameworkMonitoringEntry = (typeof TRUST_FRAMEWORK_MONITORING)[number];\n\nexport function trustFrameworkMonitoringEntry(state: TrustFrameworkMonitoring): TrustFrameworkMonitoringEntry {\n return TRUST_FRAMEWORK_MONITORING.find(entry => entry.state === state) ?? TRUST_FRAMEWORK_MONITORING[1];\n}\n\n/** THE badge text of a framework: \"16% complete\" (Vanta's completion), else \"Planned\". */\nexport function trustFrameworkBadge(framework: Pick<TrustCenterFramework, 'monitoring' | 'percent'>): string {\n return framework.monitoring === 'monitored' && typeof framework.percent === 'number'\n ? `${framework.percent}% complete`\n : trustFrameworkMonitoringEntry(framework.monitoring).label;\n}\n\n/**\n * Sections of the page, in reading order — the anchor ids (`#controls`) and the\n * sticky section rail. AI & data use follows Subprocessors: the AI statements\n * read as the continuation of who processes the data (Anthropic among them);\n * Contact comes before the FAQ.\n */\nexport const TRUST_CENTER_SECTIONS = [\n { id: 'compliance', label: 'Compliance' },\n { id: 'controls', label: 'Controls' },\n { id: 'documents', label: 'Documents' },\n { id: 'subprocessors', label: 'Subprocessors' },\n { id: 'ai', label: 'AI & data use' },\n { id: 'contact', label: 'Contact' },\n { id: 'faq', label: 'FAQ' },\n] as const;\n\nexport type TrustCenterSectionId = (typeof TRUST_CENTER_SECTIONS)[number]['id'];\n\n/** The product name and the brand-neutral tagline every surface shows (page, chat card, SEO, nav). */\nexport const TRUST_CENTER_TITLE = 'Trust Center';\nexport const TRUST_CENTER_TAGLINE = 'Security, privacy and AI governance.';\n\n/** THE route path. The page default, chat card list-url and embed EPs all read it. */\nexport const TRUST_CENTER_API_PATH = '/api/trust-center';\n\n/** How long a copy counts as fresh: the route's s-maxage AND the page's revalidate-on-visible. */\nexport const TRUST_CENTER_CACHE_SECONDS = 300;\n\n/** CDN freshness of a document file served through the hub (`…/documents/{id}`): a file changes rarely. */\nexport const TRUST_CENTER_DOCUMENT_CACHE_SECONDS = 3600;\n\n/** The single chat card id (`[card://trust_center:main]`). */\nexport const TRUST_CENTER_CARD_ID = 'main';\n\n/** Chat `documentType` of the trust-center card (`[card://trust_center:main]`). */\nexport const TRUST_CENTER_DOCUMENT_TYPE = 'trust_center';\n\n/** Default public page route (the hub's `/trust-center`). The chat card links here\n * unless the host re-homes the type through its `composeContentUrl` overrides. */\nexport const TRUST_CENTER_PAGE_PATH = '/trust-center';\n\n/** A framework as the company's Vanta Trust Center lists it, with its monitoring state from Vanta's control data. */\nexport interface TrustCenterFramework {\n id: string;\n label: string;\n /** Vanta's standard id (e.g. `soc2`), which picks the framework's logo (`complianceStandardForName`). */\n standard: string | null;\n /** The framework's description in the Vanta Trust Center. */\n description: string | null;\n monitoring: TrustFrameworkMonitoring;\n /** Vanta's completion for the framework (controls completed / total, 0–100) — present when `monitoring` is `monitored`. */\n percent?: number;\n}\n\nexport interface TrustCenterControl {\n id: string;\n name: string;\n description?: string | null;\n}\n\nexport interface TrustCenterControlDomain {\n /** Human label, e.g. \"Identification & authentication\". */\n domain: string;\n controls: TrustCenterControl[];\n}\n\n/**\n * A document from the company's Vanta Trust Center: a Resource (a file), or a\n * link it holds (the privacy policy). `public` ones open — a link at\n * `externalUrl`, a file through the hub (`trustCenterDocumentUrl`); `request`\n * ones go through the access request.\n */\nexport interface TrustCenterDocument {\n id: string;\n title: string;\n description: string | null;\n access: 'public' | 'request';\n /** An absolute link Vanta holds (e.g. the privacy policy); null for a file. */\n externalUrl: string | null;\n}\n\n/** A subprocessor, as the company's Vanta Trust Center lists it (Vanta's fields). */\nexport interface TrustCenterSubprocessor {\n name: string;\n /** What it does for us (\"Cloud hosting\"). */\n purpose: string | null;\n description: string | null;\n /** Where it processes data, e.g. \"United States\" (the page adds the flag). */\n location: string | null;\n url: string | null;\n /** Its site's icon, looked up by the hub from the `url` Vanta holds (Vanta's API carries no logo). */\n logoUrl: string | null;\n}\n\n/** An AI statement: one FAQ of the company's Vanta Trust Center, in its AI category. */\nexport interface TrustCenterAiPractice {\n /** The FAQ question. */\n label: string;\n /** The FAQ answer, as Vanta stores it. */\n value: string;\n /** The first statement of the category — the headline data-use commitment, marked with the success shield. */\n commitment?: boolean;\n}\n\nexport interface TrustCenterPublic {\n frameworks: TrustCenterFramework[];\n controlDomains: TrustCenterControlDomain[];\n /** Names of approved policies only. */\n policies: string[];\n documents: TrustCenterDocument[];\n subprocessors: TrustCenterSubprocessor[];\n aiPractices: TrustCenterAiPractice[];\n faqs: Faq[];\n /** ISO instant: most recent passing test run (falls back to the pull time). */\n checkedAt: string | null;\n /** ISO instant: start of the last successful Vanta pull. */\n syncedAt: string | null;\n /** The client derives \"monitored\" as `now - syncedAt <= monitoredWindowMs` (a CDN copy can't lie). */\n monitoredWindowMs: number;\n /** False when Vanta is not connected / never synced — a config-only projection. */\n connected: boolean;\n /** Where the monitoring data is synced from, for the page's `DataAttribution` line: named and pictured by the hub. */\n dataSource: TrustCenterDataSource;\n /**\n * The contact form's help category for a document request: one of the serving\n * platform's own categories, named by the hub. The page never invents one.\n */\n documentRequestCategory: string;\n}\n\nexport interface TrustCenterDataSource {\n name: string;\n /** Its site's icon (the same lookup the subprocessor logos use), or null. */\n logoUrl: string | null;\n}\n\n/** Client-side \"monitored\" rule (after mount only — never in SSR output). */\nexport function isTrustCenterMonitored(\n data: Pick<TrustCenterPublic, 'connected' | 'syncedAt' | 'monitoredWindowMs'>,\n nowMs: number,\n): boolean {\n if (!data.connected || !data.syncedAt) return false;\n const synced = Date.parse(data.syncedAt);\n return Number.isFinite(synced) && nowMs - synced <= data.monitoredWindowMs;\n}\n\n/** \"SOC 2 Type II: In progress · ISO 27001: Planned\" — the ONE framework summary line (chat card, RAG mapper). */\nexport function trustFrameworksSummary(\n frameworks: ReadonlyArray<Pick<TrustCenterFramework, 'label' | 'monitoring' | 'percent'>>,\n): string {\n return frameworks.map(f => `${f.label}: ${trustFrameworkBadge(f)}`).join(' · ');\n}\n\n/**\n * Where a public document opens: its own link, or — for a file — the hub's\n * documents route beside the page's `endpoint` (which may carry a query string,\n * e.g. an embed proxy). `null` for a document that is only available on request.\n */\nexport function trustCenterDocumentUrl(\n endpoint: string,\n document: Pick<TrustCenterDocument, 'id' | 'access' | 'externalUrl'>,\n): string | null {\n if (document.access !== 'public') return null;\n if (document.externalUrl) return document.externalUrl;\n const [path, query] = endpoint.split('?', 2);\n return `${path}/documents/${encodeURIComponent(document.id)}${query ? `?${query}` : ''}`;\n}\n\n// ---------------------------------------------------------------------------\n// Controls — answered by the SERVER (`GET TRUST_CENTER_API_PATH/controls?domain=&q=`):\n// the categories, their counts and one category's controls, per request.\n// The page never filters: it renders what the route returns.\n// ---------------------------------------------------------------------------\n\n/** The controls endpoint's search parameter. */\nexport const TRUST_CENTER_SEARCH_PARAM = 'q';\n/** Longest query the controls endpoint reads; the rest is ignored. */\nexport const TRUST_CENTER_SEARCH_MAX_CHARS = 100;\n/** How long the page waits after the last keystroke before asking the server. */\nexport const TRUST_CENTER_SEARCH_DEBOUNCE_MS = 250;\n\n/** One control category, with its count: the controls matching the query, else all of its controls. */\nexport interface TrustCenterControlCategory {\n domain: string;\n count: number;\n}\n\n/**\n * The controls endpoint's answer (`trustCenterControlsUrl`): the server decides\n * everything the Controls section shows — which categories exist and their\n * counts (for the query), which category is shown, and its controls.\n */\nexport interface TrustCenterControlsPage {\n /** The category answered: the one asked for, else the first; null when there are none. */\n domain: string | null;\n /** The normalized query this answers, so a late answer to an older one is recognisable. */\n query: string;\n categories: TrustCenterControlCategory[];\n /** The controls of `domain` that match `query`. */\n controls: TrustCenterControl[];\n /** Every published control, across categories (the \"of N\" in \"2 of N match\"). */\n total: number;\n}\n\n/** The controls endpoint's category parameter. */\nexport const TRUST_CENTER_DOMAIN_PARAM = 'domain';\n\n/** THE query normalization: trimmed and capped. Empty = no search. */\nexport function normalizeTrustControlQuery(query: string | null | undefined): string {\n return (query ?? '').trim().slice(0, TRUST_CENTER_SEARCH_MAX_CHARS);\n}\n\n/**\n * THE control matcher: the escaped query, case-insensitive, matched on the\n * ORIGINAL text (lowercasing first misaligns offsets wherever it changes a\n * string's length, `İ` → `i̇`). The server filters the controls with it.\n */\nexport function trustControlQueryMatcher(query: string): RegExp | null {\n const needle = normalizeTrustControlQuery(query);\n return needle ? new RegExp(escapeRegExp(needle), 'iu') : null;\n}\n\n/** The controls whose name or description matches; empty categories dropped. Server-side only by convention. */\nexport function filterTrustControlDomains(\n domains: readonly TrustCenterControlDomain[],\n query: string,\n): TrustCenterControlDomain[] {\n const matcher = trustControlQueryMatcher(query);\n if (!matcher) return [...domains];\n return domains\n .map(domain => ({\n ...domain,\n controls: domain.controls.filter(\n control => matcher.test(control.name) || matcher.test(control.description ?? ''),\n ),\n }))\n .filter(domain => domain.controls.length > 0);\n}\n\n/**\n * The controls endpoint beside the page's `endpoint` (which may carry a query\n * string, e.g. an embed proxy): `…/controls?domain=…&q=…`. Every tab switch and\n * every search is one request here — the page never filters.\n */\nexport function trustCenterControlsUrl(\n endpoint: string,\n params: { domain?: string | null; query?: string | null } = {},\n): string {\n const [path, existing] = endpoint.split('?', 2);\n const search = new URLSearchParams(existing ?? '');\n if (params.domain) search.set(TRUST_CENTER_DOMAIN_PARAM, params.domain);\n const query = normalizeTrustControlQuery(params.query);\n if (query) search.set(TRUST_CENTER_SEARCH_PARAM, query);\n const qs = search.toString();\n return `${path}/controls${qs ? `?${qs}` : ''}`;\n}\n","/**\n * Centralized Tool Types\n *\n * Single source of truth for all tool-related types across the entire platform.\n * Used by ToolBadge, ToolIcon, and any component that needs tool type information.\n */\n\nexport const ToolTypeValues = {\n FLEET_MDM: 'FLEET_MDM',\n MESHCENTRAL: 'MESHCENTRAL',\n AUTHENTIK: 'AUTHENTIK',\n OPENFRAME: 'OPENFRAME',\n OPENFRAME_CHAT: 'OPENFRAME_CHAT',\n OPENFRAME_CLIENT: 'OPENFRAME_CLIENT',\n OPENFRAME_RMM: 'OPENFRAME_RMM',\n OSQUERY: 'OSQUERY',\n SYSTEM: 'SYSTEM',\n} as const;\n\nexport type ToolType = (typeof ToolTypeValues)[keyof typeof ToolTypeValues];\n\n/**\n * Maps tool types to display labels\n */\nexport const toolLabels: Record<ToolType, string> = {\n FLEET_MDM: 'Fleet',\n MESHCENTRAL: 'MeshCentral',\n AUTHENTIK: 'Authentik',\n OPENFRAME: 'OpenFrame',\n OPENFRAME_CHAT: 'OpenFrame Chat',\n OPENFRAME_CLIENT: 'OpenFrame Client',\n OPENFRAME_RMM: 'RMM',\n OSQUERY: 'Osquery',\n SYSTEM: 'System',\n};\n","/** @deprecated Use icons from icons-v2-generated instead. */\nexport function ShellIcon({\n className = 'w-5 h-5',\n size = 22,\n color = 'white',\n}: {\n className?: string;\n size?: number;\n color?: string;\n}) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} viewBox=\"0 0 48 48\" className={className}>\n <path\n fill=\"transparent\"\n stroke={color}\n d=\"M6.5 8.4a2 2 0 0 0-2 2v27.2a2 2 0 0 0 2 2h35a2 2 0 0 0 2-2V10.4a2 2 0 0 0-2-2zM9 23.16l7.72 6L9 35.13v-12zm20.46 11.97h-11\"\n />\n </svg>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * EVERY custom `text-*` utility we add in `tailwind.config.ts` MUST be listed here.\n *\n * tailwind-merge has no knowledge of our utilities, and `text-<word>` is\n * indistinguishable from a text COLOUR to it. So an unlisted `text-badge` gets\n * filed in tailwind-merge's `text-color` group, where it and any real colour\n * class silently annihilate each other — last one wins, the other is dropped\n * from the output entirely:\n *\n * cn('text-badge', 'text-ods-text-on-accent') -> 'text-ods-text-on-accent' (size lost)\n * cn('text-[--some-colour]', 'text-badge') -> 'text-badge' (colour lost)\n *\n * Listing them in their own group makes them non-conflicting with colours, so\n * both survive. This is why `text-h1`…`text-h6` are here; `text-code` and\n * `text-badge` were added to the config later and missing them shipped exactly\n * the two failures above (huge badges, and badge text losing its colour).\n */\nconst twMerge = extendTailwindMerge<'ods-typography'>({\n extend: {\n classGroups: {\n 'ods-typography': ['text-h1', 'text-h2', 'text-h3', 'text-h4', 'text-h5', 'text-h6', 'text-code', 'text-badge'],\n },\n },\n});\n\n/**\n * Combine class names with Tailwind's merge utility\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type React from 'react';\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface CmdIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const CmdIcon: React.FC<CmdIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n >\n <path\n d=\"M3 4C3 3.44772 3.44772 3 4 3H20C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4Z\"\n stroke={color}\n />\n <text x=\"12\" y=\"16\" textAnchor=\"middle\" fill={color} fontSize=\"10\" fontFamily=\"monospace\" fontWeight=\"bold\">\n &gt;\n </text>\n </svg>\n );\n};\n\nCmdIcon.displayName = 'CmdIcon';\n","import type React from 'react';\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface BashIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const BashIcon: React.FC<BashIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} className={className} viewBox=\"0 0 24 24\">\n <path\n fill={color}\n d=\"M5 9h2.31l.32-3h2l-.32 3h2l.32-3h2l-.32 3H15v2h-1.9l-.2 2H15v2h-2.31l-.32 3h-2l.32-3h-2l-.32 3h-2l.32-3H5v-2h1.9l.2-2H5zm4.1 2l-.2 2h2l.2-2M19 6h-2v8h2m0 2h-2v2h2Z\"\n />\n </svg>\n );\n};\n\nBashIcon.displayName = 'BashIcon';\n","import type React from 'react';\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface NushellIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const NushellIcon: React.FC<NushellIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} className={className} viewBox=\"0 0 24 24\">\n <path\n fill={color}\n d=\"M0 16.338h1.25v-5.7c.417-.624 1.205-1.309 2.127-1.309c1.176 0 1.34.64 1.34 2.247v4.762h1.25v-5.685c0-1.458-.67-2.32-2.202-2.32c-.923 0-1.964.46-2.59 1.264l-.103-1.1H0Zm10.177-7.842h-1.25v5.698c0 1.46.745 2.307 2.263 2.307c.921 0 1.889-.431 2.514-1.22l.104 1.057h1.072V8.496h-1.25v5.773c-.432.67-1.265 1.25-2.129 1.25c-.907 0-1.324-.446-1.324-1.458zm8.11-.997l-.61.952l5.251 3.229l-5.251 3.244l.669.922L24 12.32v-1.28z\"\n />\n </svg>\n );\n};\n\nNushellIcon.displayName = 'NushellIcon';\n","import type React from 'react';\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface DenoIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const DenoIcon: React.FC<DenoIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg\n version=\"1.1\"\n width={size}\n height={size}\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 122.87 122.88\"\n >\n <g>\n <path\n fill={color}\n d=\"M56.6,0.03c-0.29,0.03-1.21,0.14-2.04,0.21C42.74,1.48,31.11,6.48,21.62,14.43c-1.75,1.45-5.74,5.44-7.19,7.19 C6.57,31.01,1.98,41.54,0.28,54.01c-0.38,2.77-0.38,12.1,0,14.87c1.69,12.47,6.29,23,14.14,32.38c1.45,1.75,5.44,5.74,7.19,7.19 C31,116.31,41.54,120.9,54,122.6c2.77,0.38,12.1,0.38,14.87,0c12.47-1.69,23-6.29,32.38-14.14c1.75-1.45,5.74-5.44,7.19-7.19 c7.86-9.38,12.45-19.92,14.14-32.38c0.38-2.77,0.38-12.1,0-14.87c-1.69-12.47-6.29-23-14.14-32.38c-1.45-1.75-5.44-5.74-7.19-7.19 C91.9,6.6,81.26,1.95,68.96,0.3c-1.33-0.18-3.26-0.26-6.85-0.29C59.38-0.01,56.89,0,56.6,0.03L56.6,0.03z M57.36,6.56 c0,1.77,0.12,5.61,0.29,9.25c0.09,1.78,0.2,4.34,0.24,5.67c0.17,4.71,0.67,17.09,0.74,18.19l0.08,1.1l-0.68-0.08 c-0.38-0.03-0.73-0.12-0.79-0.17c-0.05-0.06-0.15-1.1-0.21-2.33c-0.27-5.38-1.16-26.25-1.25-29.3l-0.09-3.35l0.42-0.06 c0.23-0.03,0.6-0.08,0.85-0.09l0.41-0.01L57.36,6.56L57.36,6.56L57.36,6.56z M71.82,6.2c0.02,0.02,0.06,4.58,0.11,10.14 c0.06,5.58,0.14,10.58,0.18,11.12c0.05,0.56,0.03,1.04-0.05,1.07c-0.06,0.05-0.44,0.05-0.82,0l-0.7-0.06l-0.11-4.4 c-0.06-2.43-0.14-5.12-0.17-6c-0.12-2.67-0.23-11.76-0.14-11.98C70.2,5.93,70.37,5.91,71,6.02C71.44,6.11,71.8,6.18,71.82,6.2 L71.82,6.2L71.82,6.2z M36.87,11.26c0.09,0.14,0.8,8.46,1.68,19.36c0.29,3.7,0.57,7.09,0.62,7.51c0.08,0.77,0.06,0.8-0.42,1.1 c-0.27,0.17-0.54,0.3-0.6,0.3c-0.05,0-0.14-0.39-0.18-0.88c-0.21-1.96-1.03-11.45-1.6-18.31c-0.33-4.03-0.63-7.65-0.68-8.04 c-0.08-0.67-0.06-0.73,0.33-0.94C36.49,11.11,36.76,11.06,36.87,11.26L36.87,11.26L36.87,11.26z M78.47,14.3 c0.42,0.15,0.47,0.23,0.56,1.09c0.15,1.51,0.11,8.73-0.06,8.73c-0.44,0-1.35-0.51-1.42-0.8c-0.05-0.18-0.09-2.33-0.09-4.76 C77.45,13.65,77.39,13.93,78.47,14.3L78.47,14.3z M50.56,15.01c0,0.41,0.11,2.66,0.23,5.03c0.12,2.37,0.26,5.38,0.32,6.68 c0.11,2.63,0.14,2.54-0.88,2.6c-0.5,0.02-0.5,0.02-0.53-0.74c-0.03-0.42-0.11-1.74-0.2-2.95c-0.08-1.21-0.26-3.82-0.38-5.82 c-0.12-1.99-0.27-3.97-0.32-4.4c-0.09-0.76-0.08-0.79,0.33-0.94c0.24-0.09,0.67-0.17,0.94-0.17C50.56,14.3,50.56,14.3,50.56,15.01 L50.56,15.01L50.56,15.01z M92.47,17.08l0.51,0.21l0.11,2.02c0.05,1.1,0.08,3.49,0.05,5.29l-0.05,3.29l-0.63-0.32l-0.63-0.3 l-0.05-5.02c-0.03-2.77-0.02-5.11,0.02-5.21C91.85,16.82,91.85,16.82,92.47,17.08L92.47,17.08L92.47,17.08z M64.88,19.06 c0.09,0.09,0.3,7.42,0.32,11.14l0.02,2.24l-0.71-0.11c-0.41-0.05-0.74-0.09-0.76-0.11c-0.05-0.03-0.5-11.23-0.5-12.32v-1.12 l0.77,0.09C64.46,18.94,64.84,19.01,64.88,19.06L64.88,19.06L64.88,19.06z M99.68,20.13c0.18,0.21,0.21,3.52,0.26,21.77 c0.05,20.96,0.05,21.5-0.23,21.5c-0.17,0-0.39-0.09-0.53-0.2c-0.23-0.17-0.26-1.99-0.33-19.9c-0.06-10.85-0.14-20.7-0.18-21.9 l-0.09-2.18l0.44,0.32C99.27,19.74,99.56,19.99,99.68,20.13L99.68,20.13L99.68,20.13z M86.13,23.23c0.08,0.06,0.15,0.92,0.17,1.9 c0.08,3.34,0.09,23.81,0.02,23.88c-0.03,0.03-0.3-0.05-0.6-0.17l-0.54-0.23l0-25.7L85.58,23C85.81,23.06,86.05,23.15,86.13,23.23 L86.13,23.23L86.13,23.23z M44.42,24.07c0.05,0.41,0.12,1.33,0.17,2.09c0.05,0.74,0.15,2.43,0.24,3.75 c0.18,2.66,0.15,2.83-0.71,2.83c-0.45,0-0.51-0.05-0.57-0.5c-0.15-0.89-0.68-8.33-0.6-8.45c0.08-0.11,0.86-0.38,1.22-0.41 C44.26,23.36,44.38,23.68,44.42,24.07L44.42,24.07z M19.43,27.93c0.17,1.6,0.5,4.96,0.74,7.45c0.26,2.49,0.47,4.61,0.47,4.7 c0,0.18-1.16,0.76-1.28,0.63c-0.08-0.08-1.59-13.45-1.59-14.05c0-0.36,1.16-1.89,1.31-1.72C19.13,24.96,19.28,26.31,19.43,27.93 L19.43,27.93z M78.68,29.51l0.44,0.26l0.02,3.26c0.01,1.78,0.05,3.78,0.05,4.43c0.03,1.36-0.14,1.59-0.95,1.3l-0.47-0.17v-1.3 c0-0.73-0.05-2.83-0.11-4.68l-0.09-3.35h0.35C78.09,29.26,78.44,29.38,78.68,29.51L78.68,29.51L78.68,29.51z M26.06,35.38 c0.27,2.9,0.71,7.8,1,10.88l0.51,5.59l-0.59,0.59l-0.57,0.59l-0.11-1.19c-0.06-0.67-0.36-3.75-0.68-6.86 c-0.32-3.11-0.77-7.63-1-10.03l-0.42-4.35l0.59-0.54c0.53-0.5,0.59-0.51,0.7-0.24C25.55,29.95,25.81,32.46,26.06,35.38L26.06,35.38 L26.06,35.38z M14.74,37.2c0.33,2.98,1.21,10.89,1.96,17.59c0.76,6.69,1.47,13.15,1.6,14.36c0.12,1.21,0.33,3.04,0.45,4.08 c0.21,1.77,0.21,1.89-0.03,2.07c-0.36,0.27-0.51,0.24-0.51-0.08c0-0.14-0.14-1.28-0.3-2.52c-0.27-2.07-0.73-5.58-1.74-13.45 c-0.21-1.59-0.62-4.74-0.91-7.03c-0.3-2.28-0.74-5.68-0.98-7.56c-0.24-1.87-0.65-5.08-0.91-7.15c-0.27-2.05-0.44-3.88-0.39-4.08 c0.11-0.41,1-1.83,1.09-1.74C14.11,31.75,14.41,34.21,14.74,37.2L14.74,37.2L14.74,37.2z M10.12,43.72 c0.23,1.81,0.65,5.12,0.94,7.37c0.29,2.24,0.65,5.03,0.82,6.2l0.29,2.12l-0.32,0.27c-0.18,0.15-0.36,0.21-0.42,0.15 c-0.06-0.06-0.18-0.67-0.27-1.33c-0.09-0.67-0.65-4.55-1.25-8.61l-1.07-7.4l0.35-1.03c0.18-0.56,0.38-1.01,0.42-1.01 C9.65,40.44,9.88,41.92,10.12,43.72L10.12,43.72L10.12,43.72z M93.08,41.74c0.21,0.21,0.24,1.15,0.24,8.08v7.84H92.9 c-0.92,0-0.91,0.23-0.97-8.36l-0.05-7.81h0.48C92.63,41.5,92.96,41.6,93.08,41.74L93.08,41.74z M60,44.44 c3.41,0.51,6.39,1.47,9.34,2.98c1.9,0.98,2.81,1.66,4.93,3.69c3.14,3.01,5.08,5.64,6.89,9.35c2.64,5.41,3.67,10.2,4.97,23.04 c0.59,5.76,1.36,16.2,1.53,20.48c0.05,1.24,0.15,3.28,0.24,4.53c0.17,2.66,0.36,2.3-1.98,3.43c-3.25,1.57-6.38,2.66-10.5,3.67 c-5.05,1.24-8.31,1.63-13.3,1.65l-3.63,0.01l0.03-1.74c0-0.95,0.09-3.17,0.18-4.91c0.45-8.42,0.36-19.04-0.23-24.93 c-0.33-3.38-0.98-7.49-1.35-8.4c-0.08-0.2,0.27-0.36,1.77-0.88c2.74-0.95,5.11-2.15,5.47-2.73c0.65-1.12-0.51-2.72-1.99-2.72 c-0.26,0-1.03,0.27-1.74,0.59c-3.39,1.56-10.17,3.39-14.08,3.79c-2.7,0.29-6.91,0.12-9.82-0.41c-1.59-0.29-4.43-1.36-6.8-2.58 c-2.73-1.42-4.41-3.31-4.91-5.55c-0.27-1.21-0.2-3.63,0.15-4.99c0.38-1.5,1.44-3.67,2.4-4.94c4.31-5.67,13.19-10.58,22.3-12.3 C52.78,44.03,56.89,43.97,60,44.44L60,44.44L60,44.44z M106.62,44.91c0.54,0.23,0.6,0.29,0.6,0.8c0.03,4.13-0.06,13.55-0.14,13.95 c-0.02,0.14-0.8,0.15-1.13,0.03c-0.21-0.08-0.24-0.89-0.24-7.56c0-4.77,0.06-7.46,0.15-7.46 C105.94,44.67,106.29,44.77,106.62,44.91L106.62,44.91z M113.22,53.21l0.54,0.23l-0.11,12.51c-0.12,15.94-0.14,16.41-0.71,17.79 c-0.94,2.25-0.89,2.7-0.8-7.18c0.03-4.94,0.11-9.94,0.14-11.11c0.03-1.16,0.06-4.44,0.08-7.3c0-3.45,0.05-5.17,0.15-5.17 C112.6,52.98,112.92,53.09,113.22,53.21L113.22,53.21z M22.34,56.97c0.09,1.22,0.06,1.35-0.38,2.31l-0.48,1.03L21.3,58.8 c-0.29-2.42-0.29-2.52,0.29-2.89c0.26-0.18,0.53-0.3,0.57-0.27C22.21,55.67,22.3,56.27,22.34,56.97L22.34,56.97z M13.01,66.08 c0.14,1.24,1.19,9.46,1.74,13.49c0.82,6.24,0.88,7.13,0.51,6.75c-0.05-0.05-0.39-2.15-0.76-4.67c-2.36-16.29-2.34-16.18-2.15-16.3 C12.76,65.08,12.9,65.23,13.01,66.08L13.01,66.08L13.01,66.08z M23.89,73c0.09,0.38,0.53,4.47,0.53,4.97 c0,0.42-0.54,0.82-0.79,0.57c-0.08-0.08-0.27-1.36-0.42-2.84c-0.17-1.5-0.33-3.05-0.38-3.46l-0.09-0.76l0.53,0.6 C23.57,72.43,23.84,72.84,23.89,73L23.89,73L23.89,73z M36.08,78.7c0.17,0.15,0.27,0.76,0.41,2.39c0.23,2.95,0.26,2.72-0.36,2.72 c-0.63,0-0.62,0.05-0.83-2.61c-0.21-2.7-0.21-2.67,0.2-2.67C35.69,78.52,35.94,78.61,36.08,78.7L36.08,78.7z M48.05,78.93 c0.03,0.15,0.11,1.06,0.17,2.01c0.05,0.95,0.18,3.1,0.3,4.76c0.42,6.1,0.44,6.88,0.18,6.88c-0.29,0-0.32-0.23-0.65-4.53 c-0.12-1.78-0.35-4.59-0.5-6.24c-0.14-1.65-0.23-3.02-0.18-3.05C47.54,78.56,47.97,78.7,48.05,78.93L48.05,78.93L48.05,78.93z M19.64,81.83c0.09,0.14,0.67,4.97,1.37,11.57c0.21,1.99,0.42,3.91,0.47,4.28l0.08,0.65l-0.38-0.24c-0.29-0.2-0.39-0.39-0.39-0.74 c0-0.95-0.65-7.22-1.15-11.06c-0.29-2.18-0.51-4.09-0.51-4.28C19.13,81.69,19.49,81.57,19.64,81.83L19.64,81.83z M106.85,88.14 l-0.11,6.32l-0.38,0.56c-0.86,1.27-0.82,1.51-0.77-5.56l0.03-6.48l0.56-0.57c0.3-0.3,0.6-0.56,0.67-0.56 C106.89,81.84,106.89,84.68,106.85,88.14L106.85,88.14L106.85,88.14z M92.87,98.16c0.08,8.78,0.06,9.46-0.18,9.73 c-0.15,0.17-0.29,0.27-0.33,0.23c-0.11-0.12-0.26-19.27-0.14-19.37c0.06-0.06,0.21-0.09,0.35-0.08 C92.76,88.72,92.81,89.79,92.87,98.16L92.87,98.16L92.87,98.16z M43.52,92.15c0.11,0.94,0.48,5.42,0.63,7.54 c0.09,1.42,0.09,1.47-0.24,1.57c-0.18,0.06-0.39,0.05-0.45-0.03c-0.11-0.11-0.44-3.46-0.85-8.63l-0.11-1.24h0.47 C43.41,91.36,43.44,91.39,43.52,92.15L43.52,92.15z M31.64,97.44c0.11,0.11,0.18,0.48,0.18,0.86c0,0.39,0.18,2.43,0.38,4.55 c0.57,5.79,0.62,6.57,0.36,6.42c-0.39-0.23-0.74-0.57-0.67-0.67c0.03-0.06-0.03-0.82-0.15-1.68c-0.11-0.88-0.24-2.3-0.3-3.17 c-0.06-0.88-0.2-2.48-0.32-3.55c-0.29-2.64-0.27-2.95,0.06-2.95C31.34,97.25,31.53,97.33,31.64,97.44L31.64,97.44L31.64,97.44z M38.79,107.61c0.05,0.33,0.14,1.57,0.2,2.75c0.11,2.27,0.06,2.43-0.56,1.96c-0.18-0.14-0.3-0.71-0.48-2.43 c-0.32-3.11-0.33-2.99,0.26-2.93C38.63,107,38.7,107.06,38.79,107.61L38.79,107.61L38.79,107.61z\"\n />\n <path\n fill={color}\n d=\"M33.39,51.68c-1.57,0.68-1.69,2.81-0.21,3.57c1.07,0.54,2.16,0.29,2.72-0.65 C36.96,52.87,35.23,50.88,33.39,51.68L33.39,51.68L33.39,51.68z M43.64,53.13c-1.45,0.89-1.45,3.04,0,3.93 c1.44,0.86,3.29-0.27,3.29-1.99C46.93,53.4,45.03,52.29,43.64,53.13L43.64,53.13z\"\n />\n </g>\n </svg>\n );\n};\nDenoIcon.displayName = 'DenoIcon';\n","import type { SVGProps } from \"react\";\nexport interface PowershellLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function PowershellLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: PowershellLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill=\"#2671BE\"\n fillRule=\"evenodd\"\n d=\"M10.274 19.708c-2.345 0-4.69.01-7.034-.005-1.19-.008-1.405-.287-1.138-1.442.908-3.919 1.844-7.83 2.732-11.754C5.07 5.455 5.584 4.99 6.719 5c4.69.043 9.379.014 14.068.019 1.176 0 1.374.25 1.11 1.436-.857 3.848-1.72 7.694-2.598 11.537-.328 1.438-.707 1.713-2.23 1.716-2.265.005-4.53.001-6.795 0\"\n clipRule=\"evenodd\"\n />\n <path\n fill=\"#FDFDFE\"\n fillRule=\"evenodd\"\n d=\"M12.269 12.029c-.157-.184-.33-.395-.513-.596-1.036-1.144-2.063-2.297-3.118-3.423C8.155 7.494 8 6.993 8.58 6.484c.573-.503 1.136-.458 1.661.12 1.464 1.612 2.925 3.225 4.413 4.815.556.593.426.997-.185 1.437a942 942 0 0 0-7.016 5.106c-.524.385-1.024.481-1.448-.087-.467-.626-.035-1 .45-1.35a759 759 0 0 0 5.186-3.782c.24-.177.584-.28.627-.714\"\n clipRule=\"evenodd\"\n />\n <path\n fill=\"#FCFDFD\"\n fillRule=\"evenodd\"\n d=\"M13.011 18.09c-.631 0-1.263.02-1.893-.008-.502-.022-.805-.301-.799-.827.006-.497.259-.871.76-.885a90 90 0 0 1 4.142-.002c.439.009.763.293.76.747-.003.52-.279.925-.84.958-.708.043-1.42.01-2.13.01z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n","import type { SVGProps } from \"react\";\nexport interface PythonLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function PythonLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: PythonLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"M11.966 2C7.244 2 7.193 3.833 7.193 4.21V6.5h4.864v.687H5.26C3.816 7.187 2 8.067 2 11.96c0 3.577 1.417 4.96 2.847 4.96h1.698v-2.386c0-.998.495-2.847 2.802-2.847h4.823c.71 0 2.71-.308 2.71-2.619V4.665C16.88 4.09 16.784 2 11.967 2M9.284 3.54a.874.874 0 1 1 0 1.75.874.874 0 1 1 0-1.75\"\n />\n <path\n fill={color}\n d=\"M12.034 22c4.72 0 4.778-1.867 4.778-2.21V17.5h-4.869v-.687h6.795c1.457 0 3.262-.901 3.262-4.773 0-4.24-1.916-4.96-2.847-4.96h-1.699v2.386c0 .998-.478 2.847-2.8 2.847H9.828c-.707 0-2.71.344-2.71 2.619v4.403c0 .951.581 2.665 4.915 2.665m2.682-1.54a.874.874 0 1 1-.002-1.748.874.874 0 0 1 .002 1.748\"\n />\n </svg>\n );\n}\n","import type { ComponentType } from 'react';\nimport { BashIcon, CmdIcon, DenoIcon, NushellIcon, ShellIcon } from '../components/icons';\n/**\n * Centralized Shell Types\n *\n * Single source of truth for all shell/script type information across the platform.\n * Based on the RMM-supported shell types.\n */\nimport { PowershellLogoIcon } from '../components/icons-v2-generated/brand-logos/powershell-logo-icon';\nimport { PythonLogoIcon } from '../components/icons-v2-generated/brand-logos/python-logo-icon';\nimport type { IconProps } from './icons';\n\nexport const ShellTypeValues = {\n POWERSHELL: 'POWERSHELL',\n CMD: 'CMD',\n BASH: 'BASH',\n PYTHON: 'PYTHON',\n NUSHELL: 'NUSHELL',\n DENO: 'DENO',\n SHELL: 'SHELL',\n} as const;\n\nexport type ShellType = (typeof ShellTypeValues)[keyof typeof ShellTypeValues];\n\n/**\n * Shell type definition with all metadata\n */\nexport interface ShellTypeDefinition {\n id: ShellType;\n label: string;\n value: string;\n icon: ComponentType<IconProps>;\n}\n\n/**\n * Complete list of all shell types with icons and labels\n * SINGLE SOURCE OF TRUTH - Use this everywhere\n */\nexport const SHELL_TYPES: ShellTypeDefinition[] = [\n { id: ShellTypeValues.POWERSHELL, label: 'PowerShell', value: 'powershell', icon: PowershellLogoIcon },\n { id: ShellTypeValues.CMD, label: 'Batch', value: 'cmd', icon: CmdIcon },\n { id: ShellTypeValues.BASH, label: 'Bash', value: 'bash', icon: BashIcon },\n { id: ShellTypeValues.PYTHON, label: 'Python', value: 'python', icon: PythonLogoIcon },\n { id: ShellTypeValues.NUSHELL, label: 'Nu', value: 'nushell', icon: NushellIcon },\n { id: ShellTypeValues.DENO, label: 'Deno', value: 'deno', icon: DenoIcon },\n { id: ShellTypeValues.SHELL, label: 'Shell', value: 'shell', icon: ShellIcon },\n];\n\n/**\n * Maps shell types to display labels\n */\nexport const shellLabels: Record<ShellType, string> = {\n [ShellTypeValues.POWERSHELL]: 'PowerShell',\n [ShellTypeValues.CMD]: 'Batch',\n [ShellTypeValues.BASH]: 'Bash',\n [ShellTypeValues.PYTHON]: 'Python',\n [ShellTypeValues.NUSHELL]: 'Nu',\n [ShellTypeValues.DENO]: 'Deno',\n [ShellTypeValues.SHELL]: 'Shell',\n};\n","import type { SVGProps } from \"react\";\nexport interface AppleLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function AppleLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: AppleLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"M17.57 12.628c-.024-2.531 2.062-3.747 2.156-3.805-1.174-1.72-2.999-1.957-3.649-1.983-1.552-.16-3.03.917-3.82.917s-2.005-.895-3.293-.869c-1.694.024-3.257.987-4.13 2.507-1.758 3.054-.448 7.59 1.268 10.073.84 1.213 1.837 2.581 3.151 2.53 1.266-.05 1.743-.82 3.269-.82s1.957.82 3.293.796c1.36-.026 2.222-1.24 3.054-2.458.958-1.411 1.356-2.775 1.38-2.847-.032-.012-2.65-1.018-2.68-4.041M15.06 5.194c.697-.846 1.167-2.021 1.039-3.194-1.004.041-2.22.67-2.94 1.518-.644.748-1.21 1.944-1.056 3.093 1.115.086 2.26-.572 2.956-1.417\"\n />\n </svg>\n );\n}\n","import type { SVGProps } from \"react\";\nexport interface LinuxLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function LinuxLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: LinuxLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"M19.567 18.314c-.528-.217-.963-.558-.931-1.213.03-.653-.467-1.086-.467-1.086s.435-1.43.031-2.612c-.403-1.183-1.737-3.078-2.76-4.507-1.023-1.43-.155-3.08-1.085-5.192-.932-2.113-3.351-1.99-4.654-1.087-1.304.9-.901 3.137-.84 4.196.062 1.056.028 1.808-.092 2.082-.123.273-.961 1.276-1.52 2.114-.559.84-.962 2.58-1.367 3.295-.403.715-.124 1.368-.124 1.368s-.28.092-.497.56c-.217.465-.65.683-1.427.837-.775.155-.775.655-.59 1.214.187.559.001.871-.216 1.585-.217.713.869.932 1.923 1.054 1.055.126 2.234.81 3.228.934.992.125 1.303-.683 1.303-.683s1.116-.25 2.294-.28c1.18-.031 2.295.249 2.295.249s.218.497.62.714c.405.218 1.273.25 1.832-.34.559-.592 2.048-1.337 2.885-1.804.84-.468.686-1.182.159-1.398M12.306 4.606c.532 0 .961.528.961 1.18 0 .463-.215.862-.53 1.056l-.254-.11c.19-.094.324-.335.324-.617 0-.367-.227-.666-.507-.666-.277 0-.505.3-.505.666a.8.8 0 0 0 .088.373c-.165-.066-.318-.127-.437-.172a1.4 1.4 0 0 1-.102-.53c0-.652.43-1.18.962-1.18m-.07 2.488c.267.093.562.266.532.438-.032.172-.172.172-.531.393-.36.218-1.142.703-1.392.735-.251.031-.39-.11-.657-.281-.266-.173-.766-.582-.64-.8 0 0 .39-.298.561-.455s.61-.532.876-.483c.266.045.986.36 1.252.453M9.84 4.793c.42 0 .76.5.76 1.118q0 .168-.032.32a1 1 0 0 0-.307.177 4 4 0 0 0-.14.12.8.8 0 0 0 .063-.49c-.056-.337-.28-.583-.503-.547-.221.038-.355.341-.299.68.057.34.28.585.502.548l.038-.01a3 3 0 0 1-.31.27c-.307-.143-.532-.567-.532-1.07 0-.617.34-1.116.76-1.116M9.019 20.5c-.098.445-.62.77-.62.77-.471.148-1.784-.423-2.38-.673-.593-.247-2.106-.324-2.305-.544-.197-.226.099-.722.175-1.192.073-.474-.148-.77-.075-1.094.075-.322 1.042-.322 1.412-.545.373-.225.447-.87.745-1.044.297-.175.842.446 1.065.795.222.346 1.066 1.837 1.412 2.21.348.372.67.87.572 1.317m5.488-4.332c-.09.438-.09 2.021-.09 2.021s-.961 1.335-2.452 1.554c-1.49.219-2.234.061-2.234.061l-.838-.962s.65-.095.559-.747c-.094-.653-1.985-1.555-2.327-2.363-.34-.808-.062-2.177.373-2.86.434-.684.712-2.175 1.147-2.674.434-.495.774-1.553.62-2.02 0 0 .93 1.12 1.58.935.652-.187 2.112-1.276 2.328-1.089s2.078 4.29 2.263 5.595-.125 2.3-.125 2.3-.712-.187-.804.249m4.761 2.928c-.29.267-1.902.92-2.386 1.428-.48.505-1.109.916-1.493.796-.387-.122-.724-.652-.555-1.426.168-.771.314-1.617.29-2.1s-.122-1.137 0-1.233c.12-.094.312-.047.312-.047s-.095.916.458 1.16c.554.239 1.35-.097 1.59-.34.243-.24.412-.602.412-.602s.24.122.216.507c-.024.386.168.943.531 1.135.36.19.915.458.625.722\"\n />\n </svg>\n );\n}\n","import type { SVGProps } from \"react\";\nexport interface WindowsLogoGreyIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function WindowsLogoGreyIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: WindowsLogoGreyIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"m2 4.832 8.173-1.11.004 7.86-8.17.046zm8.17 7.655.006 7.867-8.17-1.12v-6.8zm.99-8.91L21.997 2v9.482l-10.837.085zM22 12.56 21.997 22 11.16 20.475l-.015-7.932z\"\n />\n </svg>\n );\n}\n","/**\n * Centralized OS Types\n *\n * Single source of truth for all operating system type information across the platform.\n * Handles normalization of OS values from various sources (Fleet MDM, OpenFrame RMM, GraphQL).\n */\n\nimport type React from 'react';\nimport { AppleLogoIcon } from '../components/icons-v2-generated/brand-logos/apple-logo-icon';\nimport { LinuxLogoIcon } from '../components/icons-v2-generated/brand-logos/linux-logo-icon';\nimport { WindowsLogoGreyIcon } from '../components/icons-v2-generated/brand-logos/windows-logo-grey-icon';\nimport type { OSPlatformId } from '../utils/os-platforms';\n\nexport const OSTypeValues = {\n WINDOWS: 'WINDOWS',\n MACOS: 'MACOS',\n LINUX: 'LINUX',\n} as const;\n\nexport type OSType = (typeof OSTypeValues)[keyof typeof OSTypeValues];\n\n/**\n * OS type definition with all metadata\n */\nexport interface OSTypeDefinition {\n id: OSType;\n label: string;\n value: string;\n icon: React.ComponentType<React.SVGProps<SVGSVGElement>>;\n platformId: OSPlatformId;\n aliases: string[]; // Alternative names/values that map to this OS\n}\n\n/**\n * Complete list of all OS types with icons and labels\n * SINGLE SOURCE OF TRUTH - Use this everywhere\n */\nexport const OS_TYPES: OSTypeDefinition[] = [\n {\n id: OSTypeValues.MACOS,\n label: 'macOS',\n value: OSTypeValues.MACOS,\n icon: AppleLogoIcon,\n platformId: 'darwin',\n aliases: ['darwin', 'macos', 'mac os', 'osx', 'os x', 'mac'], // Put more specific ones first, 'mac' last to avoid false matches\n },\n {\n id: OSTypeValues.WINDOWS,\n label: 'Windows',\n value: OSTypeValues.WINDOWS,\n icon: WindowsLogoGreyIcon,\n platformId: 'windows',\n aliases: ['windows', 'win32', 'win64', 'win'], // 'win' last since it's shortest\n },\n {\n id: OSTypeValues.LINUX,\n label: 'Linux',\n value: OSTypeValues.LINUX,\n icon: LinuxLogoIcon,\n platformId: 'linux',\n aliases: ['linux', 'ubuntu', 'debian', 'centos', 'redhat', 'fedora', 'pop', 'pop!_os', 'arch', 'manjaro'],\n },\n];\n\n/**\n * Maps OS types to display labels\n */\nexport const osLabels: Record<OSType, string> = {\n [OSTypeValues.WINDOWS]: 'Windows',\n [OSTypeValues.MACOS]: 'macOS',\n [OSTypeValues.LINUX]: 'Linux',\n};\n","/**\n * TMCG (The Miami Cyber Gang) related types and interfaces\n */\n\nexport interface TMCGMemberSocialLink {\n platform: string;\n url: string;\n username?: string;\n}\n\nexport interface TMCGMember {\n id: string;\n full_name: string;\n avatar_url?: string | null;\n company?: string | null;\n about?: string | null;\n job_title?: string | null;\n tmcg_roles: string[];\n social_links: TMCGMemberSocialLink[];\n created_at: string;\n updated_at: string;\n}\n\nexport interface TMCGMembersResponse {\n success: boolean;\n data: {\n members: TMCGMember[];\n count: number;\n };\n error?: string;\n}\n\nexport interface TMCGMemberResponse {\n success: boolean;\n data: TMCGMember;\n error?: string;\n}\n\n/**\n * TMCG Member Card Props\n */\nexport interface TMCGMemberCardProps {\n member: TMCGMember;\n className?: string;\n compact?: boolean;\n}\n\n/**\n * TMCG Members Grid Props\n */\nexport interface TMCGMembersGridProps {\n members: TMCGMember[];\n isLoading?: boolean;\n error?: string | null;\n className?: string;\n}\n\n/**\n * TMCG Social Links Props\n */\nexport interface TMCGSocialLinksProps {\n socialLinks: TMCGMemberSocialLink[];\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\n/**\n * Hook return types\n */\nexport interface UseTMCGMembersResult {\n members: TMCGMember[];\n isLoading: boolean;\n error: string | null;\n refetch: () => void;\n}\n\nexport interface UseTMCGMemberResult {\n member: TMCGMember | null;\n isLoading: boolean;\n error: string | null;\n refetch: () => void;\n}\n\n/**\n * TMCG specific constants\n */\nexport const TMCG_ROLES = {\n FOUNDER: 'founder',\n ORGANIZER: 'organizer',\n MEMBER: 'member',\n CONTRIBUTOR: 'contributor',\n SPEAKER: 'speaker',\n MENTOR: 'mentor',\n} as const;\n\nexport type TMCGRole = (typeof TMCG_ROLES)[keyof typeof TMCG_ROLES];\n\n/**\n * TMCG role display names\n */\nexport const TMCG_ROLE_DISPLAY_NAMES: Record<string, string> = {\n [TMCG_ROLES.FOUNDER]: 'Founder',\n [TMCG_ROLES.ORGANIZER]: 'Organizer',\n [TMCG_ROLES.MEMBER]: 'Member',\n [TMCG_ROLES.CONTRIBUTOR]: 'Contributor',\n [TMCG_ROLES.SPEAKER]: 'Speaker',\n [TMCG_ROLES.MENTOR]: 'Mentor',\n};\n"]}
1
+ {"version":3,"sources":["../../src/types/announcement.ts","../../src/types/product-release.ts","../../src/types/delivery.ts","../../src/types/video-processing.ts","../../src/utils/escape-regexp.ts","../../src/types/trust-center.ts","../../src/types/tool.types.ts","../../src/components/icons/shell-icon.tsx","../../src/utils/cn.ts","../../src/components/icons/cmd-icon.tsx","../../src/components/icons/bash-icon.tsx","../../src/components/icons/nushell-icon.tsx","../../src/components/icons/deno-icon.tsx","../../src/components/icons-v2-generated/brand-logos/powershell-logo-icon.tsx","../../src/components/icons-v2-generated/brand-logos/python-logo-icon.tsx","../../src/types/shell.types.ts","../../src/components/icons-v2-generated/brand-logos/apple-logo-icon.tsx","../../src/components/icons-v2-generated/brand-logos/linux-logo-icon.tsx","../../src/components/icons-v2-generated/brand-logos/windows-logo-grey-icon.tsx","../../src/types/os.types.ts","../../src/types/tmcg.ts"],"names":["jsx","extendTailwindMerge","jsxs"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { EntityPlatformAssoc } from './entity-platform';\n// Announcement system TypeScript types\nimport type { LegacyPlatform, PlatformFilter } from './platform';\n\n// Database Models\nexport interface Announcement {\n id: string;\n title: string;\n description: string;\n background_color: string;\n icon_name?: string;\n icon_url?: string;\n /** Extra props for the main bar/icon */\n icon_props?: Record<string, unknown>;\n /** Hydrated entity_platforms associations (featured-first) — what the hub\n * DAL's attachPlatformsToRow(s) emits. No singular platform/platform_id. */\n announcement_platforms?: EntityPlatformAssoc[];\n is_active: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled?: boolean;\n cta_text?: string;\n cta_icon_name?: string;\n cta_show_icon?: boolean;\n cta_url?: string;\n cta_target?: '_self' | '_blank';\n // Custom CTA button colors (hex codes like #FFFFFF). Optional.\n cta_button_background_color?: string | null;\n cta_button_text_color?: string | null;\n /** Additional props to spread onto the CTA icon component */\n cta_icon_props?: Record<string, unknown>;\n created_at: string;\n updated_at: string;\n created_by?: string;\n created_by_user?: {\n id: string;\n email: string;\n full_name?: string;\n };\n announcement_assets?: AnnouncementAsset[];\n}\n\nexport interface AnnouncementAsset {\n id: string;\n announcement_id: string;\n file_name: string;\n file_url: string;\n file_size: number;\n mime_type: string;\n upload_path: string;\n created_at: string;\n}\n\n// API Request/Response Types\nexport interface CreateAnnouncementData {\n title: string;\n description: string;\n background_color: string;\n icon_name?: string;\n icon_url?: string;\n /** Extra props for the main bar/icon */\n icon_props?: Record<string, unknown>;\n platforms?: string[]; // entity_platforms set (multi-select)\n is_active?: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled?: boolean;\n cta_text?: string;\n cta_icon_name?: string;\n cta_show_icon?: boolean;\n cta_url?: string;\n cta_target?: '_self' | '_blank';\n cta_button_background_color?: string;\n cta_button_text_color?: string;\n cta_icon_props?: Record<string, unknown>;\n created_by: string;\n}\n\nexport interface UpdateAnnouncementData {\n title?: string;\n description?: string;\n background_color?: string;\n icon_name?: string;\n icon_url?: string;\n /** Extra props for the main bar/icon */\n icon_props?: Record<string, unknown>;\n platforms?: string[]; // entity_platforms set (multi-select)\n is_active?: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled?: boolean;\n cta_text?: string;\n cta_icon_name?: string;\n cta_show_icon?: boolean;\n cta_url?: string;\n cta_target?: '_self' | '_blank';\n cta_button_background_color?: string;\n cta_button_text_color?: string;\n cta_icon_props?: Record<string, unknown>;\n}\n\nexport interface AnnouncementListResponse {\n announcements: Announcement[];\n pagination: {\n page: number;\n page_size: number;\n total_count: number;\n total_pages: number;\n };\n filters?: {\n platform?: LegacyPlatform;\n is_active?: boolean;\n };\n}\n\n/**\n * Wire shape of GET /api/announcements/active — the single typed home for the\n * `{ announcement }` envelope (hub route return + AnnouncementBar's\n * useSelfFetch generic). `null` when no active announcement exists.\n */\nexport interface AnnouncementResponse {\n announcement: Announcement | null;\n}\n\n/**\n * Default CTA button colors — one home for the pair the DAL create/update\n * defaults and the admin form both reference. Announcement colors are\n * admin-chosen data (not ODS-token surfaces) by design.\n */\nexport const ANNOUNCEMENT_CTA_DEFAULTS = {\n background: '#1A1A1A',\n text: '#FAFAFA',\n} as const;\n\n// Form Data Types\nexport interface AnnouncementFormData {\n title: string;\n description: string;\n background_color: string;\n icon_name: string;\n icon_url?: string;\n platforms: string[]; // entity_platforms set (multi-select; no single platform_id)\n is_active: boolean;\n // CTA (Call-To-Action) fields\n cta_enabled: boolean;\n cta_text: string;\n cta_icon_name: string;\n cta_show_icon: boolean;\n cta_url: string;\n cta_target: '_self' | '_blank';\n // New CTA button custom colors\n cta_button_background_color?: string;\n cta_button_text_color?: string;\n cta_icon_props?: string; // JSON string in form\n /** Extra props for the main bar/icon */\n icon_props?: string;\n}\n\n// API Query Parameters\nexport interface GetAnnouncementsOptions {\n platform?: PlatformFilter; // Changed from Platform to PlatformFilter to include 'all'\n is_active?: boolean;\n page?: number;\n pageSize?: number;\n sortBy?: 'created_at' | 'updated_at' | 'title';\n sortOrder?: 'asc' | 'desc';\n}\n\n// File Upload Types\nexport interface IconUploadResponse {\n success: boolean;\n file_url?: string;\n file_name?: string;\n file_size?: number;\n error?: string;\n}\n\nexport interface IconUploadData {\n file: File;\n announcement_id?: string;\n}\n\n// Available SVG Icons (extend as needed)\nexport interface AvailableSvgIcon {\n name: string;\n display_name: string;\n component_name: string;\n}\n\n// Error Types\nexport interface AnnouncementError {\n code: string;\n message: string;\n details?: string;\n}\n\n// Validation Types\nexport interface AnnouncementValidation {\n title: {\n required: boolean;\n minLength: number;\n maxLength: number;\n };\n description: {\n required: boolean;\n minLength: number;\n maxLength: number;\n };\n background_color: {\n required: boolean;\n pattern: RegExp;\n };\n icon_name: {\n required: boolean;\n validOptions: string[];\n };\n platform: {\n required: boolean;\n validOptions: LegacyPlatform[];\n };\n}\n\n// Import unified platform configuration (removed duplicate definition)\nexport type { PlatformConfig } from './platform';\n\n// Component Props Types\nexport interface AnnouncementBarProps {\n /**\n * SSR mode seed. `null` = the server resolved \"nothing to show\" (no active\n * announcement, or dismissed via cookie) — seeds the fetch hook and skips\n * the mount fetch. Absent (`undefined`) = client-only mode: the bar\n * self-fetches on mount from the EndpointsRuntime provider's\n * `announcementsUrl` (see react-embedding-example — no per-component URL\n * or platform knobs; the server resolves its own platform via\n * currentPlatform()).\n */\n initialAnnouncement?: Announcement | null;\n /**\n * Render-only mode for the admin live preview: no fetch/revalidation, inert\n * dismiss button, and no storage side effects (never writes dismissal\n * cookies or touches localStorage).\n */\n previewMode?: boolean;\n /**\n * When false, the dismiss (X) button is not rendered — the bar can only\n * disappear by deactivating the announcement. Default true.\n */\n dismissible?: boolean;\n className?: string;\n}\n\nexport interface AnnouncementFormProps {\n announcement?: Announcement;\n onSubmit: (data: AnnouncementFormData) => Promise<void>;\n onCancel: () => void;\n isLoading?: boolean;\n availableIcons: AvailableSvgIcon[];\n}\n\nexport interface AnnouncementListProps {\n announcements: Announcement[];\n onEdit: (announcement: Announcement) => void;\n onDelete: (announcementId: string) => void;\n onToggleActive: (announcementId: string, isActive: boolean) => void;\n isLoading?: boolean;\n}\n\n// Database Utility Types\nexport interface AnnouncementFilters {\n platform?: LegacyPlatform;\n is_active?: boolean;\n created_by?: string;\n search?: string;\n}\n\nexport interface AnnouncementSortOptions {\n field: 'created_at' | 'updated_at' | 'title' | 'platform';\n direction: 'asc' | 'desc';\n}\n\n// SVG Icon Type\nexport interface SvgIcon {\n name: string;\n label: string;\n /** Optional pre-resolved glyph component. Every registry below (and every\n * known consumer) passes `null` and renders by `name` through the shared\n * icon resolver — the slot is kept for callers that carry a component. */\n component: React.ComponentType<React.SVGProps<SVGSVGElement>> | null;\n}\n\n// Platform display configuration\n// PLATFORM_CONFIGS removed - all platform data now comes from database via getPlatformsConfig()\n\n// Available SVG icons configuration\nexport const AVAILABLE_SVG_ICONS: SvgIcon[] = [\n // OpenFrame Logo Options\n { name: 'openframe-logo', label: 'OpenFrame Logo', component: null },\n\n // Platform Logos\n { name: 'openmsp-logo', label: 'OpenMSP Logo', component: null },\n { name: 'flamingo-logo', label: 'Flamingo Logo', component: null },\n\n // Lucide Icons\n { name: 'megaphone', label: 'Megaphone', component: null },\n { name: 'bell', label: 'Bell', component: null },\n { name: 'info', label: 'Information', component: null },\n { name: 'star', label: 'Star', component: null },\n { name: 'rocket', label: 'Rocket', component: null },\n { name: 'package', label: 'Package', component: null },\n];\n","// Product Release Types\n// Following the blog.ts pattern for consistency\n\nimport type { BlogTag, TagAssoc } from './blog';\nimport type { EntityAuthor } from './entity-author';\nimport type { PlatformRecord } from './platform';\nimport type { VideoTeaser, TranscriptWord, SpeakerMapping } from './video-processing';\n\nexport interface ChangelogEntry {\n title: string;\n description?: string;\n /**\n * Per-entry visibility flag. Optional so product releases (which always render\n * publicly) remain backwards compatible. Investor updates require this field\n * because each entry can be marked internal — see investor-update-utils.ts.\n */\n visibility?: 'public' | 'internal';\n /**\n * Optional per-entry classification chosen from the manager's `tagOptions`\n * (e.g. an owner, a priority, a severity). Product releases never set it.\n */\n tag?: string;\n}\n\nexport interface ReleaseMedia {\n id: number;\n release_id: number;\n media_type: 'image' | 'video' | 'screenshot' | 'demo';\n media_url: string;\n display_order: number | null;\n title: string | null;\n description: string | null;\n created_at: string;\n updated_at: string;\n created_by: string;\n}\n\nexport interface ProductReleaseGitHubLink {\n id: number;\n release_id: number;\n github_release_url: string; // Full URL (e.g., https://github.com/org/repo/releases/tag/v2.0.0)\n display_order: number | null;\n created_at: string;\n}\n\nexport interface KnowledgeBaseLink {\n id: number;\n release_id: number;\n kb_article_path: string; // Relative path (e.g., /api/authentication/api-keys.md)\n display_order: number | null;\n created_at: string;\n}\n\nexport interface ClickUpRoadmapTask {\n id: number;\n release_id: number;\n clickup_task_id: string; // Just the task ID - details from roadmap folder\n display_order: number | null;\n created_at: string;\n}\n\nexport interface ClickUpDeliveryTask {\n id: number;\n release_id: number;\n clickup_task_id: string; // Just the task ID - details from delivery list\n display_order: number | null;\n created_at: string;\n}\n\nexport interface ProductRelease {\n id: number;\n title: string;\n slug: string;\n version: string;\n summary: string | null;\n content: string | null;\n\n // Release metadata\n release_type: 'major' | 'minor' | 'patch' | 'beta' | 'alpha';\n release_status: 'alpha' | 'beta' | 'stable' | 'deprecated';\n release_date: string;\n\n // Changelog (JSONB arrays)\n features_added: ChangelogEntry[];\n bugs_fixed: ChangelogEntry[];\n improvements: ChangelogEntry[];\n breaking_changes: ChangelogEntry[];\n\n // External relationships (one-to-many)\n github_releases?: ProductReleaseGitHubLink[];\n knowledge_base_links?: KnowledgeBaseLink[];\n clickup_roadmap_tasks?: ClickUpRoadmapTask[];\n clickup_delivery_tasks?: ClickUpDeliveryTask[];\n release_media?: ReleaseMedia[];\n\n // Media (keeping featured_image for hero)\n featured_image: string | null;\n\n // Documentation\n migration_guide_url: string | null;\n documentation_url: string | null;\n\n // Video (youtube_url for embeds, main_video_url for AI processing)\n youtube_url: string | null;\n main_video_url: string | null;\n transcript: string | null;\n transcript_words_data?: TranscriptWord[];\n srt_content?: string | null;\n highlight_srt_content?: string | null;\n video_summary: string | null; // AI-generated summary from video transcription\n video_bites: VideoTeaser[]; // JSONB array of extracted video clips\n highlight_video_url: string | null;\n highlight_video_thumbnail: string | null;\n highlight_video_duration_ms: number | null;\n highlight_video_source: 'manual' | 'ai_generated' | null;\n main_video_thumbnail: string | null;\n ai_transcript_formatted?: string;\n speaker_mapping?: SpeakerMapping;\n ai_confidence_transcript: number | null;\n ai_confidence_video_summary: number | null; // Confidence for video-generated summary\n ai_confidence_summary: number | null; // Confidence for entity summary (Release Content Generation)\n\n // SEO\n seo_title: string | null;\n seo_description: string | null;\n seo_keywords: string | null;\n og_image_url: string | null;\n\n // Publishing\n status: 'draft' | 'published' | 'archived';\n published_at: string | null;\n author_id: string | null;\n\n // HubSpot marketing email (mirrors InvestorUpdate). `hubspot_email_id` is the\n // stored HubSpot email id; `hubspot_email_url` is computed by the admin GET\n // route from the production portal id (never persisted).\n hubspot_email_id?: string | null;\n hubspot_email_url?: string | null;\n /**\n * Hydrated by `getRelease` (detail) and `getReleases` (list) via\n * `hydrateAuthor` in the hub DAL. Optional so admin form + every existing\n * consumer that doesn't read author stay backward-compatible.\n */\n author?: EntityAuthor;\n\n // Timestamps\n created_at: string;\n updated_at: string;\n\n // Editor-provided AI generation instructions (steers Generate Content prompt)\n custom_instructions: string | null;\n\n // Analytics\n view_count: number;\n download_count: number;\n\n // Relations (populated by joins)\n platforms?: PlatformRecord[];\n tags?: BlogTag[];\n product_release_platforms?: Array<{\n platform_id: string;\n is_featured: boolean;\n featured_order: number | null;\n // The release DAL flattens the joined `platforms` row onto each junction\n // entry (`...platform.platforms`), so `name`/`display_name` are present at\n // runtime — `composeContentUrlFromPlatforms` reads `name` to resolve the\n // target platform. Declared here so callers can pass this array to the\n // `composeContentUrl` seam without a cast.\n name?: string;\n display_name?: string;\n }>;\n // Flat unified tag-association shape (hydrated by entity-tag-utils).\n product_release_tags?: TagAssoc[];\n}\n\nexport interface CreateProductReleaseData {\n title: string;\n slug: string;\n version: string;\n summary?: string;\n content?: string;\n release_type: 'major' | 'minor' | 'patch' | 'beta' | 'alpha';\n release_status: 'alpha' | 'beta' | 'stable' | 'deprecated';\n release_date: string;\n features_added?: ChangelogEntry[];\n bugs_fixed?: ChangelogEntry[];\n improvements?: ChangelogEntry[];\n breaking_changes?: ChangelogEntry[];\n github_releases?: Array<{ github_release_url: string; display_order?: number }>;\n knowledge_base_links?: Array<{ kb_article_path: string; display_order?: number }>;\n clickup_roadmap_tasks?: Array<{ clickup_task_id: string; display_order?: number }>;\n clickup_delivery_tasks?: Array<{ clickup_task_id: string; display_order?: number }>;\n release_media?: Array<{\n media_type: 'image' | 'video' | 'screenshot' | 'demo';\n media_url: string;\n title?: string;\n description?: string;\n display_order?: number;\n }>;\n featured_image?: string;\n migration_guide_url?: string;\n documentation_url?: string;\n youtube_url?: string;\n main_video_url?: string;\n transcript?: string;\n srt_content?: string | null;\n highlight_srt_content?: string | null;\n video_summary?: string; // AI-generated summary from video transcription\n video_bites?: VideoTeaser[];\n highlight_video_url?: string | null;\n highlight_video_thumbnail?: string | null;\n highlight_video_duration_ms?: number | null;\n highlight_video_source?: 'manual' | 'ai_generated' | null;\n main_video_thumbnail?: string | null;\n seo_title?: string;\n seo_description?: string;\n seo_keywords?: string;\n og_image_url?: string;\n status: 'draft' | 'published' | 'archived';\n published_at?: string | null;\n author_id: string;\n platforms: string[]; // Array of platform IDs (UUIDs)\n featured_platform?: string; // Platform ID for featured\n tags: number[]; // Array of tag IDs\n custom_instructions?: string | null;\n}\n\nexport type UpdateProductReleaseData = Partial<CreateProductReleaseData>;\n\nexport interface ProductReleaseFilters {\n platform?: string | 'all';\n tags?: string[];\n version?: string;\n release_type?: ('major' | 'minor' | 'patch' | 'beta' | 'alpha')[];\n release_status?: ('alpha' | 'beta' | 'stable' | 'deprecated')[];\n has_breaking_changes?: boolean;\n search?: string;\n featured?: boolean;\n status?: string;\n limit?: number;\n offset?: number;\n ids?: (number | string)[];\n}\n\nexport interface ProductReleaseListResponse {\n data: ProductRelease[];\n count: number;\n}\n\n// GitHub Release interface (for wizard)\nexport interface GitHubRelease {\n id: string;\n tag_name: string;\n name: string;\n body: string;\n published_at: string;\n html_url: string;\n prerelease: boolean;\n draft: boolean;\n}\n\n// Release type options for dropdowns\nexport const releaseTypeOptions = [\n { value: 'major', label: 'Major Release', description: 'Breaking changes, new architecture', color: 'red' },\n { value: 'minor', label: 'Minor Release', description: 'New features, backward compatible', color: 'blue' },\n { value: 'patch', label: 'Patch Release', description: 'Bug fixes only', color: 'green' },\n { value: 'beta', label: 'Beta Release', description: 'Pre-release testing version', color: 'yellow' },\n { value: 'alpha', label: 'Alpha Release', description: 'Early testing version', color: 'orange' },\n] as const;\n\n// Release status options\nexport const releaseStatusOptions = [\n { value: 'alpha', label: 'Alpha', description: 'Early development, unstable', color: 'orange' },\n { value: 'beta', label: 'Beta', description: 'Feature complete, testing', color: 'yellow' },\n { value: 'stable', label: 'Stable', description: 'Production ready', color: 'green' },\n { value: 'deprecated', label: 'Deprecated', description: 'No longer supported', color: 'gray' },\n] as const;\n\n// Changelog category labels\nexport const changelogLabels = {\n features_added: 'Features Added',\n bugs_fixed: 'Bugs Fixed',\n improvements: 'Improvements',\n breaking_changes: 'Breaking Changes',\n} as const;\n\n// Semantic versioning validation regex\nexport const SEMVER_REGEX = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$/;\n","/**\n * Delivery (ClickUp Bug-fixes & Enhancements) wire types — shared between the\n * hub's `/api/delivery*` route shapes and the lib's `DeliveryTable`/`DeliveryLists`/\n * `DeliverySection` components.\n *\n * Lifted from hub `types/delivery.ts` so embedders consuming the lib's\n * delivery surfaces and the lib's own `ReleaseDetailPage` (which renders\n * related delivery items) share one canonical shape.\n */\n\n/**\n * Display identity for a task assignee — WIRE-SAFE shape: name + avatar\n * only, resolved server-side (ClickUp assignee × profiles). Emails are\n * deliberately NOT on the wire; the roadmap/delivery boards are public\n * surfaces (same policy as the RAG mappers). Feeds `AvatarStack`\n * directly.\n */\nexport interface TaskAssigneeDisplay {\n /** ClickUp member id — stable render key. */\n id: number;\n name: string | null;\n avatarUrl: string | null;\n}\n\nexport interface DeliveryItem {\n id: string;\n title: string;\n description: string;\n status: string;\n statusColor: string; // ClickUp status color\n taskType: 'Request' | 'Bug' | string; // ClickUp task type\n /**\n * Canonical ClickUp custom_item_id (1008 = Bug, 1009 = Request, …).\n * Surfaced here so the chat's compact card can render a type-specific\n * lucide icon via `TaskTypeIcon` instead of the two-letter initials\n * fallback. Single source of truth lives in\n * `lib/utils/clickup-task-type-utils.ts` (hub-side).\n */\n customItemId: number | null;\n /** Assignee display identities (name + avatar, never email) — powers\n * the AvatarStack on cards. Optional: producers that don't enrich\n * (e.g. activity-cache recent_tasks) simply omit it. */\n assignees?: TaskAssigneeDisplay[];\n /**\n * Every ClickUp list the task is associated with (home list + ClickUp's\n * \"Tasks in Multiple Lists\" locations). UI joins these for display.\n * Falls back to a single-element array containing the home list when\n * there are no additional locations.\n */\n listNames: string[];\n dateOpened: number; // Unix timestamp\n dateUpdated: number; // Unix timestamp\n dateClosed: number | null; // Unix timestamp or null if not closed\n clickupUrl: string;\n}\n\nexport interface DeliveryResponse {\n completed: DeliveryItem[];\n inProgress: DeliveryItem[];\n}\n\n// Task type to badge label mapping\nexport const TASK_TYPE_LABELS = {\n Request: 'ENHANCEMENT',\n Bug: 'BUG-FIX',\n} as const;\n\n// Task type to badge text-color mapping (ODS attention-red for Bug; default for others)\nexport const TASK_TYPE_TEXT_COLORS = {\n Request: '', // Default white/grey\n Bug: 'text-[var(--ods-attention-red-error)]',\n} as const;\n","// Video Processing Shared Types\n// Used by CustomerInterview, ProductRelease, and future video-enabled entities\n\n/**\n * VideoTeaser represents a short video clip extracted from a longer video.\n * Used for teasers/bites that can be shown on preview pages.\n *\n * CANONICAL BITE SHAPE: this is the base persistence type — the TRUE SUPERSET\n * of every field persisted in the `video_bites` / `teasers` jsonb columns.\n * `VideoTeaserWithRatio` (video-ratio-tabs.tsx) adds only `aspect_ratio` and is\n * the one type display/aggregation code extends. The AI-extraction `VideoClip`\n * below stays a separate shape by design.\n */\nexport interface VideoTeaser {\n id?: string; // Stable 8-char lowercase-hex element id (see utils/video-bite-id.ts). Stamped at creation (editor + AI save) and lazily backfilled by the Mux reconciliation sweep. Identity key for the Mux transcode pipeline — never derived from url (urls have real-world duplicates).\n url: string;\n source_url?: string; // Original storage URL, set by the Mux pipeline when it flips `url` to the HLS playback URL. Merge-identity leg for redelivered ingests + transcode dedup. Never set by editors.\n title?: string;\n thumbnail_url?: string; // Optional thumbnail image URL for video preview. If not provided, video player will show first frame automatically.\n published?: boolean; // Controls visibility on public preview page (default: false, admin must select)\n featured?: boolean; // Opts the bite into cross-entity featured pulls (homepage/configured surfaces). Independent of `published`.\n featured_at?: string; // ISO timestamp stamped when an admin features the bite (cleared on unfeature; all featured bites backfilled 2026-08-19). Featured surfaces rank by THIS — ranking by created_at made featuring an old bite invisible under the surface cap.\n source?: 'manual' | 'ai_generated'; // Track origin of teaser\n created_at?: string; // ISO timestamp for sorting (newer items first)\n start_time_ms?: number; // Vizard extraction: clip start offset in the source video\n end_time_ms?: number; // Vizard extraction: clip end offset in the source video\n confidence?: number; // Vizard extraction: 0-100 virality confidence\n viral_reason?: string; // Vizard extraction: why this clip was picked\n // Duration auto-detected from video file\n}\n\n/**\n * Speaker identification for transcription\n */\n/**\n * A short customer quote pulled from a video entity (case study, customer\n * interview) — a headline line in the customer's own words. Attribution is NOT\n * stored on the item: it is the entity's customer (`user_id` → profile + MSP).\n * `key` is stable across edits so list editors can reconcile rows.\n */\nexport interface EntityQuote {\n key: string;\n text: string;\n /** Who said it, when the recording has several voices (a prospect call). Case studies attribute to their customer instead. */\n speaker?: string | null;\n /** `ai` while the text is exactly what Transcribe & Summarize extracted; an editor edit makes it `manual`. */\n source?: 'ai' | 'manual';\n}\n\n/** The caption every quote list carries: the admin editor and the `EntityQuotesPanel` display. */\nexport const ENTITY_QUOTES_TITLE = 'Key Quotes';\n\nexport interface Speaker {\n label: string;\n name?: string;\n confidence?: number;\n}\n\n/**\n * VideoClip represents a segment identified by AI analysis\n */\nexport interface VideoClip {\n start_time: number;\n end_time: number;\n description: string;\n query_used: string;\n confidence: number;\n twelve_labs_id?: string;\n thumbnail_url?: string;\n}\n\n/**\n * Word-level transcript data for precise video processing\n */\nexport interface TranscriptWord {\n text: string;\n start: number; // milliseconds\n end: number; // milliseconds\n confidence: number;\n speaker?: string;\n}\n\n/**\n * Speaker mapping for interview/video transcripts\n * Maps AssemblyAI labels (\"A\", \"B\") to actual person info\n */\nexport interface SpeakerMapping {\n [label: string]: {\n name: string;\n role: 'interviewer' | 'interviewee' | 'presenter' | 'host' | 'guest';\n userId?: string;\n };\n}\n\n/**\n * Excluded time ranges (e.g., for incentive mentions)\n */\nexport interface ExcludedRange {\n start: number; // seconds\n end: number; // seconds\n}\n\n/**\n * Base video processing fields shared across entities\n */\nexport interface VideoProcessingFields {\n main_video_url: string | null;\n transcript: string | null;\n transcript_words_data?: TranscriptWord[];\n srt_content?: string | null;\n highlight_video_url?: string | null;\n highlight_video_thumbnail?: string | null;\n highlight_video_duration_ms?: number | null;\n highlight_video_source?: 'manual' | 'ai_generated' | null;\n /** Persisted first-frame thumbnail from main video upload (client-side canvas extraction) */\n main_video_thumbnail?: string | null;\n ai_transcript_formatted?: string;\n speaker_mapping?: SpeakerMapping;\n ai_confidence_transcript?: number | null;\n ai_confidence_summary?: number | null;\n}\n\n/**\n * Entity types that support agent processing\n * - customer_interview: Customer interview videos with transcription/bites/highlight\n * - product_release: Product release videos with transcription/bites/highlight\n * - marketing_campaign: Marketing campaign content generation (autonomous workflow)\n * - case_study: Case study generation from customer interviews\n * - onboarding_guide: Step-by-step onboarding guides with optional video walkthrough\n * - what_i_shipped: Monthly employee \"What I Shipped\" entries (people-hub) with transcription/bites/highlight\n * - how_i_work: Recorded employee AI-workflow sessions (people-hub) with transcription/bites/highlight\n */\nexport type VideoProcessingEntityType =\n | 'customer_interview'\n | 'product_release'\n | 'marketing_campaign'\n | 'case_study'\n | 'webinar'\n | 'podcast_episode'\n | 'investor_update'\n | 'onboarding_guide'\n | 'what_i_shipped'\n | 'how_i_work'\n | 'walkthrough_video'\n | 'prospect_call';\n// Fri May 15 14:58:59 EDT 2026\n","/**\n * Escape every RegExp meta-character in `value`, so text can be matched\n * literally inside a `new RegExp(...)` (a search query of `(c)` or `a+b`, a URL\n * prefix). Zero-dependency and server-safe.\n */\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","/**\n * Trust Center wire types + vocabulary — the ONE contract between the hub's\n * `/api/trust-center` projection (Vanta snapshot → public-safe payload) and the\n * lib's `<TrustCenterPage>`.\n *\n * Server-safe (no React, no DOM): the hub DAL, route and chat mapper import it\n * from `@flamingo-stack/openframe-frontend-core/types`.\n *\n * PUBLICATION POLICY lives hub-side (`lib/data/trust-center-public.ts`); this\n * module only names the shape and the vocabulary every surface renders:\n * - only PASSING controls are ever on the wire (Vanta's SHOW_OK_ONLY practice);\n * - `percent` is present only when the hub decided it is publishable;\n * - no totals, failing counts, owners, people or remediation text exist here.\n */\nimport { escapeRegExp } from '../utils/escape-regexp';\nimport type { Faq } from './faq';\n\n/**\n * A framework's MONITORING state, from Vanta's live data — Vanta keeps no\n * certification status, so none is claimed. `monitored` always carries Vanta's\n * own completion (`percent`: controls completed / total, as Vanta's app shows\n * it); `not_monitored` is a framework on the Trust Center that Vanta does not\n * monitor yet, shown as \"Planned\". Label, badge colour and icon are owned\n * HERE, once.\n */\nexport const TRUST_FRAMEWORK_MONITORING = [\n { state: 'monitored', label: 'Monitored', color: 'cyan', icon: 'shield-check' },\n { state: 'not_monitored', label: 'Planned', color: 'pinkSoft', icon: 'file-shield' },\n] as const;\n\nexport type TrustFrameworkMonitoring = (typeof TRUST_FRAMEWORK_MONITORING)[number]['state'];\nexport type TrustFrameworkMonitoringEntry = (typeof TRUST_FRAMEWORK_MONITORING)[number];\n\nexport function trustFrameworkMonitoringEntry(state: TrustFrameworkMonitoring): TrustFrameworkMonitoringEntry {\n return TRUST_FRAMEWORK_MONITORING.find(entry => entry.state === state) ?? TRUST_FRAMEWORK_MONITORING[1];\n}\n\n/** THE badge text of a framework: \"16% complete\" (Vanta's completion), else \"Planned\". */\nexport function trustFrameworkBadge(framework: Pick<TrustCenterFramework, 'monitoring' | 'percent'>): string {\n return framework.monitoring === 'monitored' && typeof framework.percent === 'number'\n ? `${framework.percent}% complete`\n : trustFrameworkMonitoringEntry(framework.monitoring).label;\n}\n\n/**\n * Sections of the page, in reading order — the anchor ids (`#controls`) and the\n * sticky section rail. AI & data use follows Subprocessors: the AI statements\n * read as the continuation of who processes the data (Anthropic among them);\n * Contact comes before the FAQ.\n */\nexport const TRUST_CENTER_SECTIONS = [\n { id: 'compliance', label: 'Compliance' },\n { id: 'controls', label: 'Controls' },\n { id: 'documents', label: 'Documents' },\n { id: 'subprocessors', label: 'Subprocessors' },\n { id: 'ai', label: 'AI & data use' },\n { id: 'contact', label: 'Contact' },\n { id: 'faq', label: 'FAQ' },\n] as const;\n\nexport type TrustCenterSectionId = (typeof TRUST_CENTER_SECTIONS)[number]['id'];\n\n/** The product name and the brand-neutral tagline every surface shows (page, chat card, SEO, nav). */\nexport const TRUST_CENTER_TITLE = 'Trust Center';\nexport const TRUST_CENTER_TAGLINE = 'Security, privacy and AI governance.';\n\n/** THE route path. The page default, chat card list-url and embed EPs all read it. */\nexport const TRUST_CENTER_API_PATH = '/api/trust-center';\n\n/** How long a copy counts as fresh: the route's s-maxage AND the page's revalidate-on-visible. */\nexport const TRUST_CENTER_CACHE_SECONDS = 300;\n\n/** CDN freshness of a document file served through the hub (`…/documents/{id}`): a file changes rarely. */\nexport const TRUST_CENTER_DOCUMENT_CACHE_SECONDS = 3600;\n\n/** The single chat card id (`[card://trust_center:main]`). */\nexport const TRUST_CENTER_CARD_ID = 'main';\n\n/** Chat `documentType` of the trust-center card (`[card://trust_center:main]`). */\nexport const TRUST_CENTER_DOCUMENT_TYPE = 'trust_center';\n\n/** Default public page route (the hub's `/trust-center`). The chat card links here\n * unless the host re-homes the type through its `composeContentUrl` overrides. */\nexport const TRUST_CENTER_PAGE_PATH = '/trust-center';\n\n/** A framework as the company's Vanta Trust Center lists it, with its monitoring state from Vanta's control data. */\nexport interface TrustCenterFramework {\n id: string;\n label: string;\n /** Vanta's standard id (e.g. `soc2`), which picks the framework's logo (`complianceStandardForName`). */\n standard: string | null;\n /** The framework's description in the Vanta Trust Center. */\n description: string | null;\n monitoring: TrustFrameworkMonitoring;\n /** Vanta's completion for the framework (controls completed / total, 0–100) — present when `monitoring` is `monitored`. */\n percent?: number;\n}\n\nexport interface TrustCenterControl {\n id: string;\n name: string;\n description?: string | null;\n}\n\nexport interface TrustCenterControlDomain {\n /** Human label, e.g. \"Identification & authentication\". */\n domain: string;\n controls: TrustCenterControl[];\n}\n\n/**\n * A document from the company's Vanta Trust Center: a Resource (a file), or a\n * link it holds (the privacy policy). `public` ones open — a link at\n * `externalUrl`, a file through the hub (`trustCenterDocumentUrl`); `request`\n * ones go through the access request.\n */\nexport interface TrustCenterDocument {\n id: string;\n title: string;\n description: string | null;\n access: 'public' | 'request';\n /** An absolute link Vanta holds (e.g. the privacy policy); null for a file. */\n externalUrl: string | null;\n}\n\n/** A subprocessor, as the company's Vanta Trust Center lists it (Vanta's fields). */\nexport interface TrustCenterSubprocessor {\n name: string;\n /** What it does for us (\"Cloud hosting\"). */\n purpose: string | null;\n description: string | null;\n /** Where it processes data, e.g. \"United States\" (the page adds the flag). */\n location: string | null;\n url: string | null;\n /** Its site's icon, looked up by the hub from the `url` Vanta holds (Vanta's API carries no logo). */\n logoUrl: string | null;\n}\n\n/** An AI statement: one FAQ of the company's Vanta Trust Center, in its AI category. */\nexport interface TrustCenterAiPractice {\n /** The FAQ question. */\n label: string;\n /** The FAQ answer, as Vanta stores it. */\n value: string;\n /** The first statement of the category — the headline data-use commitment, marked with the success shield. */\n commitment?: boolean;\n}\n\nexport interface TrustCenterPublic {\n frameworks: TrustCenterFramework[];\n controlDomains: TrustCenterControlDomain[];\n /** Names of approved policies only. */\n policies: string[];\n documents: TrustCenterDocument[];\n subprocessors: TrustCenterSubprocessor[];\n aiPractices: TrustCenterAiPractice[];\n faqs: Faq[];\n /** ISO instant: most recent passing test run (falls back to the pull time). */\n checkedAt: string | null;\n /** ISO instant: start of the last successful Vanta pull. */\n syncedAt: string | null;\n /** The client derives \"monitored\" as `now - syncedAt <= monitoredWindowMs` (a CDN copy can't lie). */\n monitoredWindowMs: number;\n /** False when Vanta is not connected / never synced — a config-only projection. */\n connected: boolean;\n /** Where the monitoring data is synced from, for the page's `DataAttribution` line: named and pictured by the hub. */\n dataSource: TrustCenterDataSource;\n /**\n * The contact form's help category for a document request: one of the serving\n * platform's own categories, named by the hub. The page never invents one.\n */\n documentRequestCategory: string;\n}\n\nexport interface TrustCenterDataSource {\n name: string;\n /** Its site's icon (the same lookup the subprocessor logos use), or null. */\n logoUrl: string | null;\n}\n\n/** Client-side \"monitored\" rule (after mount only — never in SSR output). */\nexport function isTrustCenterMonitored(\n data: Pick<TrustCenterPublic, 'connected' | 'syncedAt' | 'monitoredWindowMs'>,\n nowMs: number,\n): boolean {\n if (!data.connected || !data.syncedAt) return false;\n const synced = Date.parse(data.syncedAt);\n return Number.isFinite(synced) && nowMs - synced <= data.monitoredWindowMs;\n}\n\n/** \"SOC 2 Type II: In progress · ISO 27001: Planned\" — the ONE framework summary line (chat card, RAG mapper). */\nexport function trustFrameworksSummary(\n frameworks: ReadonlyArray<Pick<TrustCenterFramework, 'label' | 'monitoring' | 'percent'>>,\n): string {\n return frameworks.map(f => `${f.label}: ${trustFrameworkBadge(f)}`).join(' · ');\n}\n\n/**\n * Where a public document opens: its own link, or — for a file — the hub's\n * documents route beside the page's `endpoint` (which may carry a query string,\n * e.g. an embed proxy). `null` for a document that is only available on request.\n */\nexport function trustCenterDocumentUrl(\n endpoint: string,\n document: Pick<TrustCenterDocument, 'id' | 'access' | 'externalUrl'>,\n): string | null {\n if (document.access !== 'public') return null;\n if (document.externalUrl) return document.externalUrl;\n const [path, query] = endpoint.split('?', 2);\n return `${path}/documents/${encodeURIComponent(document.id)}${query ? `?${query}` : ''}`;\n}\n\n// ---------------------------------------------------------------------------\n// Controls — answered by the SERVER (`GET TRUST_CENTER_API_PATH/controls?domain=&q=`):\n// the categories, their counts and one category's controls, per request.\n// The page never filters: it renders what the route returns.\n// ---------------------------------------------------------------------------\n\n/** The controls endpoint's search parameter. */\nexport const TRUST_CENTER_SEARCH_PARAM = 'q';\n/** Longest query the controls endpoint reads; the rest is ignored. */\nexport const TRUST_CENTER_SEARCH_MAX_CHARS = 100;\n/** How long the page waits after the last keystroke before asking the server. */\nexport const TRUST_CENTER_SEARCH_DEBOUNCE_MS = 250;\n\n/** One control category, with its count: the controls matching the query, else all of its controls. */\nexport interface TrustCenterControlCategory {\n domain: string;\n count: number;\n}\n\n/**\n * The controls endpoint's answer (`trustCenterControlsUrl`): the server decides\n * everything the Controls section shows — which categories exist and their\n * counts (for the query), which category is shown, and its controls.\n */\nexport interface TrustCenterControlsPage {\n /** The category answered: the one asked for, else the first; null when there are none. */\n domain: string | null;\n /** The normalized query this answers, so a late answer to an older one is recognisable. */\n query: string;\n categories: TrustCenterControlCategory[];\n /** The controls of `domain` that match `query`. */\n controls: TrustCenterControl[];\n /** Every published control, across categories (the \"of N\" in \"2 of N match\"). */\n total: number;\n}\n\n/** The controls endpoint's category parameter. */\nexport const TRUST_CENTER_DOMAIN_PARAM = 'domain';\n\n/** THE query normalization: trimmed and capped. Empty = no search. */\nexport function normalizeTrustControlQuery(query: string | null | undefined): string {\n return (query ?? '').trim().slice(0, TRUST_CENTER_SEARCH_MAX_CHARS);\n}\n\n/**\n * THE control matcher: the escaped query, case-insensitive, matched on the\n * ORIGINAL text (lowercasing first misaligns offsets wherever it changes a\n * string's length, `İ` → `i̇`). The server filters the controls with it.\n */\nexport function trustControlQueryMatcher(query: string): RegExp | null {\n const needle = normalizeTrustControlQuery(query);\n return needle ? new RegExp(escapeRegExp(needle), 'iu') : null;\n}\n\n/** The controls whose name or description matches; empty categories dropped. Server-side only by convention. */\nexport function filterTrustControlDomains(\n domains: readonly TrustCenterControlDomain[],\n query: string,\n): TrustCenterControlDomain[] {\n const matcher = trustControlQueryMatcher(query);\n if (!matcher) return [...domains];\n return domains\n .map(domain => ({\n ...domain,\n controls: domain.controls.filter(\n control => matcher.test(control.name) || matcher.test(control.description ?? ''),\n ),\n }))\n .filter(domain => domain.controls.length > 0);\n}\n\n/**\n * The controls endpoint beside the page's `endpoint` (which may carry a query\n * string, e.g. an embed proxy): `…/controls?domain=…&q=…`. Every tab switch and\n * every search is one request here — the page never filters.\n */\nexport function trustCenterControlsUrl(\n endpoint: string,\n params: { domain?: string | null; query?: string | null } = {},\n): string {\n const [path, existing] = endpoint.split('?', 2);\n const search = new URLSearchParams(existing ?? '');\n if (params.domain) search.set(TRUST_CENTER_DOMAIN_PARAM, params.domain);\n const query = normalizeTrustControlQuery(params.query);\n if (query) search.set(TRUST_CENTER_SEARCH_PARAM, query);\n const qs = search.toString();\n return `${path}/controls${qs ? `?${qs}` : ''}`;\n}\n","/**\n * Centralized Tool Types\n *\n * Single source of truth for all tool-related types across the entire platform.\n * Used by ToolBadge, ToolIcon, and any component that needs tool type information.\n */\n\nexport const ToolTypeValues = {\n FLEET_MDM: 'FLEET_MDM',\n MESHCENTRAL: 'MESHCENTRAL',\n AUTHENTIK: 'AUTHENTIK',\n OPENFRAME: 'OPENFRAME',\n OPENFRAME_CHAT: 'OPENFRAME_CHAT',\n OPENFRAME_CLIENT: 'OPENFRAME_CLIENT',\n OPENFRAME_RMM: 'OPENFRAME_RMM',\n OSQUERY: 'OSQUERY',\n SYSTEM: 'SYSTEM',\n MICROSOFT_365: 'MICROSOFT_365',\n GOOGLE_WORKSPACE: 'GOOGLE_WORKSPACE',\n} as const;\n\nexport type ToolType = (typeof ToolTypeValues)[keyof typeof ToolTypeValues];\n\n/**\n * Maps tool types to display labels\n */\nexport const toolLabels: Record<ToolType, string> = {\n FLEET_MDM: 'Fleet',\n MESHCENTRAL: 'MeshCentral',\n AUTHENTIK: 'Authentik',\n OPENFRAME: 'OpenFrame',\n OPENFRAME_CHAT: 'OpenFrame Chat',\n OPENFRAME_CLIENT: 'OpenFrame Client',\n OPENFRAME_RMM: 'RMM',\n OSQUERY: 'Osquery',\n SYSTEM: 'System',\n MICROSOFT_365: 'Microsoft 365',\n GOOGLE_WORKSPACE: 'Google Workspace',\n};\n","/** @deprecated Use icons from icons-v2-generated instead. */\nexport function ShellIcon({\n className = 'w-5 h-5',\n size = 22,\n color = 'white',\n}: {\n className?: string;\n size?: number;\n color?: string;\n}) {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} viewBox=\"0 0 48 48\" className={className}>\n <path\n fill=\"transparent\"\n stroke={color}\n d=\"M6.5 8.4a2 2 0 0 0-2 2v27.2a2 2 0 0 0 2 2h35a2 2 0 0 0 2-2V10.4a2 2 0 0 0-2-2zM9 23.16l7.72 6L9 35.13v-12zm20.46 11.97h-11\"\n />\n </svg>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\n/**\n * EVERY custom `text-*` utility we add in `tailwind.config.ts` MUST be listed here.\n *\n * tailwind-merge has no knowledge of our utilities, and `text-<word>` is\n * indistinguishable from a text COLOUR to it. So an unlisted `text-badge` gets\n * filed in tailwind-merge's `text-color` group, where it and any real colour\n * class silently annihilate each other — last one wins, the other is dropped\n * from the output entirely:\n *\n * cn('text-badge', 'text-ods-text-on-accent') -> 'text-ods-text-on-accent' (size lost)\n * cn('text-[--some-colour]', 'text-badge') -> 'text-badge' (colour lost)\n *\n * Listing them in their own group makes them non-conflicting with colours, so\n * both survive. This is why `text-h1`…`text-h6` are here; `text-code` and\n * `text-badge` were added to the config later and missing them shipped exactly\n * the two failures above (huge badges, and badge text losing its colour).\n */\nconst twMerge = extendTailwindMerge<'ods-typography'>({\n extend: {\n classGroups: {\n 'ods-typography': ['text-h1', 'text-h2', 'text-h3', 'text-h4', 'text-h5', 'text-h6', 'text-code', 'text-badge'],\n },\n },\n});\n\n/**\n * Combine class names with Tailwind's merge utility\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import type React from 'react';\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface CmdIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const CmdIcon: React.FC<CmdIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n className={className}\n >\n <path\n d=\"M3 4C3 3.44772 3.44772 3 4 3H20C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4Z\"\n stroke={color}\n />\n <text x=\"12\" y=\"16\" textAnchor=\"middle\" fill={color} fontSize=\"10\" fontFamily=\"monospace\" fontWeight=\"bold\">\n &gt;\n </text>\n </svg>\n );\n};\n\nCmdIcon.displayName = 'CmdIcon';\n","import type React from 'react';\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface BashIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const BashIcon: React.FC<BashIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} className={className} viewBox=\"0 0 24 24\">\n <path\n fill={color}\n d=\"M5 9h2.31l.32-3h2l-.32 3h2l.32-3h2l-.32 3H15v2h-1.9l-.2 2H15v2h-2.31l-.32 3h-2l.32-3h-2l-.32 3h-2l.32-3H5v-2h1.9l.2-2H5zm4.1 2l-.2 2h2l.2-2M19 6h-2v8h2m0 2h-2v2h2Z\"\n />\n </svg>\n );\n};\n\nBashIcon.displayName = 'BashIcon';\n","import type React from 'react';\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface NushellIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const NushellIcon: React.FC<NushellIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width={size} height={size} className={className} viewBox=\"0 0 24 24\">\n <path\n fill={color}\n d=\"M0 16.338h1.25v-5.7c.417-.624 1.205-1.309 2.127-1.309c1.176 0 1.34.64 1.34 2.247v4.762h1.25v-5.685c0-1.458-.67-2.32-2.202-2.32c-.923 0-1.964.46-2.59 1.264l-.103-1.1H0Zm10.177-7.842h-1.25v5.698c0 1.46.745 2.307 2.263 2.307c.921 0 1.889-.431 2.514-1.22l.104 1.057h1.072V8.496h-1.25v5.773c-.432.67-1.265 1.25-2.129 1.25c-.907 0-1.324-.446-1.324-1.458zm8.11-.997l-.61.952l5.251 3.229l-5.251 3.244l.669.922L24 12.32v-1.28z\"\n />\n </svg>\n );\n};\n\nNushellIcon.displayName = 'NushellIcon';\n","import type React from 'react';\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport interface DenoIconProps {\n size?: number;\n className?: string;\n color?: string;\n}\n/** @deprecated Use icons from icons-v2-generated instead. */\nexport const DenoIcon: React.FC<DenoIconProps> = ({ size = 16, className = '', color = 'white' }) => {\n return (\n <svg\n version=\"1.1\"\n width={size}\n height={size}\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 122.87 122.88\"\n >\n <g>\n <path\n fill={color}\n d=\"M56.6,0.03c-0.29,0.03-1.21,0.14-2.04,0.21C42.74,1.48,31.11,6.48,21.62,14.43c-1.75,1.45-5.74,5.44-7.19,7.19 C6.57,31.01,1.98,41.54,0.28,54.01c-0.38,2.77-0.38,12.1,0,14.87c1.69,12.47,6.29,23,14.14,32.38c1.45,1.75,5.44,5.74,7.19,7.19 C31,116.31,41.54,120.9,54,122.6c2.77,0.38,12.1,0.38,14.87,0c12.47-1.69,23-6.29,32.38-14.14c1.75-1.45,5.74-5.44,7.19-7.19 c7.86-9.38,12.45-19.92,14.14-32.38c0.38-2.77,0.38-12.1,0-14.87c-1.69-12.47-6.29-23-14.14-32.38c-1.45-1.75-5.44-5.74-7.19-7.19 C91.9,6.6,81.26,1.95,68.96,0.3c-1.33-0.18-3.26-0.26-6.85-0.29C59.38-0.01,56.89,0,56.6,0.03L56.6,0.03z M57.36,6.56 c0,1.77,0.12,5.61,0.29,9.25c0.09,1.78,0.2,4.34,0.24,5.67c0.17,4.71,0.67,17.09,0.74,18.19l0.08,1.1l-0.68-0.08 c-0.38-0.03-0.73-0.12-0.79-0.17c-0.05-0.06-0.15-1.1-0.21-2.33c-0.27-5.38-1.16-26.25-1.25-29.3l-0.09-3.35l0.42-0.06 c0.23-0.03,0.6-0.08,0.85-0.09l0.41-0.01L57.36,6.56L57.36,6.56L57.36,6.56z M71.82,6.2c0.02,0.02,0.06,4.58,0.11,10.14 c0.06,5.58,0.14,10.58,0.18,11.12c0.05,0.56,0.03,1.04-0.05,1.07c-0.06,0.05-0.44,0.05-0.82,0l-0.7-0.06l-0.11-4.4 c-0.06-2.43-0.14-5.12-0.17-6c-0.12-2.67-0.23-11.76-0.14-11.98C70.2,5.93,70.37,5.91,71,6.02C71.44,6.11,71.8,6.18,71.82,6.2 L71.82,6.2L71.82,6.2z M36.87,11.26c0.09,0.14,0.8,8.46,1.68,19.36c0.29,3.7,0.57,7.09,0.62,7.51c0.08,0.77,0.06,0.8-0.42,1.1 c-0.27,0.17-0.54,0.3-0.6,0.3c-0.05,0-0.14-0.39-0.18-0.88c-0.21-1.96-1.03-11.45-1.6-18.31c-0.33-4.03-0.63-7.65-0.68-8.04 c-0.08-0.67-0.06-0.73,0.33-0.94C36.49,11.11,36.76,11.06,36.87,11.26L36.87,11.26L36.87,11.26z M78.47,14.3 c0.42,0.15,0.47,0.23,0.56,1.09c0.15,1.51,0.11,8.73-0.06,8.73c-0.44,0-1.35-0.51-1.42-0.8c-0.05-0.18-0.09-2.33-0.09-4.76 C77.45,13.65,77.39,13.93,78.47,14.3L78.47,14.3z M50.56,15.01c0,0.41,0.11,2.66,0.23,5.03c0.12,2.37,0.26,5.38,0.32,6.68 c0.11,2.63,0.14,2.54-0.88,2.6c-0.5,0.02-0.5,0.02-0.53-0.74c-0.03-0.42-0.11-1.74-0.2-2.95c-0.08-1.21-0.26-3.82-0.38-5.82 c-0.12-1.99-0.27-3.97-0.32-4.4c-0.09-0.76-0.08-0.79,0.33-0.94c0.24-0.09,0.67-0.17,0.94-0.17C50.56,14.3,50.56,14.3,50.56,15.01 L50.56,15.01L50.56,15.01z M92.47,17.08l0.51,0.21l0.11,2.02c0.05,1.1,0.08,3.49,0.05,5.29l-0.05,3.29l-0.63-0.32l-0.63-0.3 l-0.05-5.02c-0.03-2.77-0.02-5.11,0.02-5.21C91.85,16.82,91.85,16.82,92.47,17.08L92.47,17.08L92.47,17.08z M64.88,19.06 c0.09,0.09,0.3,7.42,0.32,11.14l0.02,2.24l-0.71-0.11c-0.41-0.05-0.74-0.09-0.76-0.11c-0.05-0.03-0.5-11.23-0.5-12.32v-1.12 l0.77,0.09C64.46,18.94,64.84,19.01,64.88,19.06L64.88,19.06L64.88,19.06z M99.68,20.13c0.18,0.21,0.21,3.52,0.26,21.77 c0.05,20.96,0.05,21.5-0.23,21.5c-0.17,0-0.39-0.09-0.53-0.2c-0.23-0.17-0.26-1.99-0.33-19.9c-0.06-10.85-0.14-20.7-0.18-21.9 l-0.09-2.18l0.44,0.32C99.27,19.74,99.56,19.99,99.68,20.13L99.68,20.13L99.68,20.13z M86.13,23.23c0.08,0.06,0.15,0.92,0.17,1.9 c0.08,3.34,0.09,23.81,0.02,23.88c-0.03,0.03-0.3-0.05-0.6-0.17l-0.54-0.23l0-25.7L85.58,23C85.81,23.06,86.05,23.15,86.13,23.23 L86.13,23.23L86.13,23.23z M44.42,24.07c0.05,0.41,0.12,1.33,0.17,2.09c0.05,0.74,0.15,2.43,0.24,3.75 c0.18,2.66,0.15,2.83-0.71,2.83c-0.45,0-0.51-0.05-0.57-0.5c-0.15-0.89-0.68-8.33-0.6-8.45c0.08-0.11,0.86-0.38,1.22-0.41 C44.26,23.36,44.38,23.68,44.42,24.07L44.42,24.07z M19.43,27.93c0.17,1.6,0.5,4.96,0.74,7.45c0.26,2.49,0.47,4.61,0.47,4.7 c0,0.18-1.16,0.76-1.28,0.63c-0.08-0.08-1.59-13.45-1.59-14.05c0-0.36,1.16-1.89,1.31-1.72C19.13,24.96,19.28,26.31,19.43,27.93 L19.43,27.93z M78.68,29.51l0.44,0.26l0.02,3.26c0.01,1.78,0.05,3.78,0.05,4.43c0.03,1.36-0.14,1.59-0.95,1.3l-0.47-0.17v-1.3 c0-0.73-0.05-2.83-0.11-4.68l-0.09-3.35h0.35C78.09,29.26,78.44,29.38,78.68,29.51L78.68,29.51L78.68,29.51z M26.06,35.38 c0.27,2.9,0.71,7.8,1,10.88l0.51,5.59l-0.59,0.59l-0.57,0.59l-0.11-1.19c-0.06-0.67-0.36-3.75-0.68-6.86 c-0.32-3.11-0.77-7.63-1-10.03l-0.42-4.35l0.59-0.54c0.53-0.5,0.59-0.51,0.7-0.24C25.55,29.95,25.81,32.46,26.06,35.38L26.06,35.38 L26.06,35.38z M14.74,37.2c0.33,2.98,1.21,10.89,1.96,17.59c0.76,6.69,1.47,13.15,1.6,14.36c0.12,1.21,0.33,3.04,0.45,4.08 c0.21,1.77,0.21,1.89-0.03,2.07c-0.36,0.27-0.51,0.24-0.51-0.08c0-0.14-0.14-1.28-0.3-2.52c-0.27-2.07-0.73-5.58-1.74-13.45 c-0.21-1.59-0.62-4.74-0.91-7.03c-0.3-2.28-0.74-5.68-0.98-7.56c-0.24-1.87-0.65-5.08-0.91-7.15c-0.27-2.05-0.44-3.88-0.39-4.08 c0.11-0.41,1-1.83,1.09-1.74C14.11,31.75,14.41,34.21,14.74,37.2L14.74,37.2L14.74,37.2z M10.12,43.72 c0.23,1.81,0.65,5.12,0.94,7.37c0.29,2.24,0.65,5.03,0.82,6.2l0.29,2.12l-0.32,0.27c-0.18,0.15-0.36,0.21-0.42,0.15 c-0.06-0.06-0.18-0.67-0.27-1.33c-0.09-0.67-0.65-4.55-1.25-8.61l-1.07-7.4l0.35-1.03c0.18-0.56,0.38-1.01,0.42-1.01 C9.65,40.44,9.88,41.92,10.12,43.72L10.12,43.72L10.12,43.72z M93.08,41.74c0.21,0.21,0.24,1.15,0.24,8.08v7.84H92.9 c-0.92,0-0.91,0.23-0.97-8.36l-0.05-7.81h0.48C92.63,41.5,92.96,41.6,93.08,41.74L93.08,41.74z M60,44.44 c3.41,0.51,6.39,1.47,9.34,2.98c1.9,0.98,2.81,1.66,4.93,3.69c3.14,3.01,5.08,5.64,6.89,9.35c2.64,5.41,3.67,10.2,4.97,23.04 c0.59,5.76,1.36,16.2,1.53,20.48c0.05,1.24,0.15,3.28,0.24,4.53c0.17,2.66,0.36,2.3-1.98,3.43c-3.25,1.57-6.38,2.66-10.5,3.67 c-5.05,1.24-8.31,1.63-13.3,1.65l-3.63,0.01l0.03-1.74c0-0.95,0.09-3.17,0.18-4.91c0.45-8.42,0.36-19.04-0.23-24.93 c-0.33-3.38-0.98-7.49-1.35-8.4c-0.08-0.2,0.27-0.36,1.77-0.88c2.74-0.95,5.11-2.15,5.47-2.73c0.65-1.12-0.51-2.72-1.99-2.72 c-0.26,0-1.03,0.27-1.74,0.59c-3.39,1.56-10.17,3.39-14.08,3.79c-2.7,0.29-6.91,0.12-9.82-0.41c-1.59-0.29-4.43-1.36-6.8-2.58 c-2.73-1.42-4.41-3.31-4.91-5.55c-0.27-1.21-0.2-3.63,0.15-4.99c0.38-1.5,1.44-3.67,2.4-4.94c4.31-5.67,13.19-10.58,22.3-12.3 C52.78,44.03,56.89,43.97,60,44.44L60,44.44L60,44.44z M106.62,44.91c0.54,0.23,0.6,0.29,0.6,0.8c0.03,4.13-0.06,13.55-0.14,13.95 c-0.02,0.14-0.8,0.15-1.13,0.03c-0.21-0.08-0.24-0.89-0.24-7.56c0-4.77,0.06-7.46,0.15-7.46 C105.94,44.67,106.29,44.77,106.62,44.91L106.62,44.91z M113.22,53.21l0.54,0.23l-0.11,12.51c-0.12,15.94-0.14,16.41-0.71,17.79 c-0.94,2.25-0.89,2.7-0.8-7.18c0.03-4.94,0.11-9.94,0.14-11.11c0.03-1.16,0.06-4.44,0.08-7.3c0-3.45,0.05-5.17,0.15-5.17 C112.6,52.98,112.92,53.09,113.22,53.21L113.22,53.21z M22.34,56.97c0.09,1.22,0.06,1.35-0.38,2.31l-0.48,1.03L21.3,58.8 c-0.29-2.42-0.29-2.52,0.29-2.89c0.26-0.18,0.53-0.3,0.57-0.27C22.21,55.67,22.3,56.27,22.34,56.97L22.34,56.97z M13.01,66.08 c0.14,1.24,1.19,9.46,1.74,13.49c0.82,6.24,0.88,7.13,0.51,6.75c-0.05-0.05-0.39-2.15-0.76-4.67c-2.36-16.29-2.34-16.18-2.15-16.3 C12.76,65.08,12.9,65.23,13.01,66.08L13.01,66.08L13.01,66.08z M23.89,73c0.09,0.38,0.53,4.47,0.53,4.97 c0,0.42-0.54,0.82-0.79,0.57c-0.08-0.08-0.27-1.36-0.42-2.84c-0.17-1.5-0.33-3.05-0.38-3.46l-0.09-0.76l0.53,0.6 C23.57,72.43,23.84,72.84,23.89,73L23.89,73L23.89,73z M36.08,78.7c0.17,0.15,0.27,0.76,0.41,2.39c0.23,2.95,0.26,2.72-0.36,2.72 c-0.63,0-0.62,0.05-0.83-2.61c-0.21-2.7-0.21-2.67,0.2-2.67C35.69,78.52,35.94,78.61,36.08,78.7L36.08,78.7z M48.05,78.93 c0.03,0.15,0.11,1.06,0.17,2.01c0.05,0.95,0.18,3.1,0.3,4.76c0.42,6.1,0.44,6.88,0.18,6.88c-0.29,0-0.32-0.23-0.65-4.53 c-0.12-1.78-0.35-4.59-0.5-6.24c-0.14-1.65-0.23-3.02-0.18-3.05C47.54,78.56,47.97,78.7,48.05,78.93L48.05,78.93L48.05,78.93z M19.64,81.83c0.09,0.14,0.67,4.97,1.37,11.57c0.21,1.99,0.42,3.91,0.47,4.28l0.08,0.65l-0.38-0.24c-0.29-0.2-0.39-0.39-0.39-0.74 c0-0.95-0.65-7.22-1.15-11.06c-0.29-2.18-0.51-4.09-0.51-4.28C19.13,81.69,19.49,81.57,19.64,81.83L19.64,81.83z M106.85,88.14 l-0.11,6.32l-0.38,0.56c-0.86,1.27-0.82,1.51-0.77-5.56l0.03-6.48l0.56-0.57c0.3-0.3,0.6-0.56,0.67-0.56 C106.89,81.84,106.89,84.68,106.85,88.14L106.85,88.14L106.85,88.14z M92.87,98.16c0.08,8.78,0.06,9.46-0.18,9.73 c-0.15,0.17-0.29,0.27-0.33,0.23c-0.11-0.12-0.26-19.27-0.14-19.37c0.06-0.06,0.21-0.09,0.35-0.08 C92.76,88.72,92.81,89.79,92.87,98.16L92.87,98.16L92.87,98.16z M43.52,92.15c0.11,0.94,0.48,5.42,0.63,7.54 c0.09,1.42,0.09,1.47-0.24,1.57c-0.18,0.06-0.39,0.05-0.45-0.03c-0.11-0.11-0.44-3.46-0.85-8.63l-0.11-1.24h0.47 C43.41,91.36,43.44,91.39,43.52,92.15L43.52,92.15z M31.64,97.44c0.11,0.11,0.18,0.48,0.18,0.86c0,0.39,0.18,2.43,0.38,4.55 c0.57,5.79,0.62,6.57,0.36,6.42c-0.39-0.23-0.74-0.57-0.67-0.67c0.03-0.06-0.03-0.82-0.15-1.68c-0.11-0.88-0.24-2.3-0.3-3.17 c-0.06-0.88-0.2-2.48-0.32-3.55c-0.29-2.64-0.27-2.95,0.06-2.95C31.34,97.25,31.53,97.33,31.64,97.44L31.64,97.44L31.64,97.44z M38.79,107.61c0.05,0.33,0.14,1.57,0.2,2.75c0.11,2.27,0.06,2.43-0.56,1.96c-0.18-0.14-0.3-0.71-0.48-2.43 c-0.32-3.11-0.33-2.99,0.26-2.93C38.63,107,38.7,107.06,38.79,107.61L38.79,107.61L38.79,107.61z\"\n />\n <path\n fill={color}\n d=\"M33.39,51.68c-1.57,0.68-1.69,2.81-0.21,3.57c1.07,0.54,2.16,0.29,2.72-0.65 C36.96,52.87,35.23,50.88,33.39,51.68L33.39,51.68L33.39,51.68z M43.64,53.13c-1.45,0.89-1.45,3.04,0,3.93 c1.44,0.86,3.29-0.27,3.29-1.99C46.93,53.4,45.03,52.29,43.64,53.13L43.64,53.13z\"\n />\n </g>\n </svg>\n );\n};\nDenoIcon.displayName = 'DenoIcon';\n","import type { SVGProps } from \"react\";\nexport interface PowershellLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function PowershellLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: PowershellLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill=\"#2671BE\"\n fillRule=\"evenodd\"\n d=\"M10.274 19.708c-2.345 0-4.69.01-7.034-.005-1.19-.008-1.405-.287-1.138-1.442.908-3.919 1.844-7.83 2.732-11.754C5.07 5.455 5.584 4.99 6.719 5c4.69.043 9.379.014 14.068.019 1.176 0 1.374.25 1.11 1.436-.857 3.848-1.72 7.694-2.598 11.537-.328 1.438-.707 1.713-2.23 1.716-2.265.005-4.53.001-6.795 0\"\n clipRule=\"evenodd\"\n />\n <path\n fill=\"#FDFDFE\"\n fillRule=\"evenodd\"\n d=\"M12.269 12.029c-.157-.184-.33-.395-.513-.596-1.036-1.144-2.063-2.297-3.118-3.423C8.155 7.494 8 6.993 8.58 6.484c.573-.503 1.136-.458 1.661.12 1.464 1.612 2.925 3.225 4.413 4.815.556.593.426.997-.185 1.437a942 942 0 0 0-7.016 5.106c-.524.385-1.024.481-1.448-.087-.467-.626-.035-1 .45-1.35a759 759 0 0 0 5.186-3.782c.24-.177.584-.28.627-.714\"\n clipRule=\"evenodd\"\n />\n <path\n fill=\"#FCFDFD\"\n fillRule=\"evenodd\"\n d=\"M13.011 18.09c-.631 0-1.263.02-1.893-.008-.502-.022-.805-.301-.799-.827.006-.497.259-.871.76-.885a90 90 0 0 1 4.142-.002c.439.009.763.293.76.747-.003.52-.279.925-.84.958-.708.043-1.42.01-2.13.01z\"\n clipRule=\"evenodd\"\n />\n </svg>\n );\n}\n","import type { SVGProps } from \"react\";\nexport interface PythonLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function PythonLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: PythonLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"M11.966 2C7.244 2 7.193 3.833 7.193 4.21V6.5h4.864v.687H5.26C3.816 7.187 2 8.067 2 11.96c0 3.577 1.417 4.96 2.847 4.96h1.698v-2.386c0-.998.495-2.847 2.802-2.847h4.823c.71 0 2.71-.308 2.71-2.619V4.665C16.88 4.09 16.784 2 11.967 2M9.284 3.54a.874.874 0 1 1 0 1.75.874.874 0 1 1 0-1.75\"\n />\n <path\n fill={color}\n d=\"M12.034 22c4.72 0 4.778-1.867 4.778-2.21V17.5h-4.869v-.687h6.795c1.457 0 3.262-.901 3.262-4.773 0-4.24-1.916-4.96-2.847-4.96h-1.699v2.386c0 .998-.478 2.847-2.8 2.847H9.828c-.707 0-2.71.344-2.71 2.619v4.403c0 .951.581 2.665 4.915 2.665m2.682-1.54a.874.874 0 1 1-.002-1.748.874.874 0 0 1 .002 1.748\"\n />\n </svg>\n );\n}\n","import type { ComponentType } from 'react';\nimport { BashIcon, CmdIcon, DenoIcon, NushellIcon, ShellIcon } from '../components/icons';\n/**\n * Centralized Shell Types\n *\n * Single source of truth for all shell/script type information across the platform.\n * Based on the RMM-supported shell types.\n */\nimport { PowershellLogoIcon } from '../components/icons-v2-generated/brand-logos/powershell-logo-icon';\nimport { PythonLogoIcon } from '../components/icons-v2-generated/brand-logos/python-logo-icon';\nimport type { IconProps } from './icons';\n\nexport const ShellTypeValues = {\n POWERSHELL: 'POWERSHELL',\n CMD: 'CMD',\n BASH: 'BASH',\n PYTHON: 'PYTHON',\n NUSHELL: 'NUSHELL',\n DENO: 'DENO',\n SHELL: 'SHELL',\n} as const;\n\nexport type ShellType = (typeof ShellTypeValues)[keyof typeof ShellTypeValues];\n\n/**\n * Shell type definition with all metadata\n */\nexport interface ShellTypeDefinition {\n id: ShellType;\n label: string;\n value: string;\n icon: ComponentType<IconProps>;\n}\n\n/**\n * Complete list of all shell types with icons and labels\n * SINGLE SOURCE OF TRUTH - Use this everywhere\n */\nexport const SHELL_TYPES: ShellTypeDefinition[] = [\n { id: ShellTypeValues.POWERSHELL, label: 'PowerShell', value: 'powershell', icon: PowershellLogoIcon },\n { id: ShellTypeValues.CMD, label: 'Batch', value: 'cmd', icon: CmdIcon },\n { id: ShellTypeValues.BASH, label: 'Bash', value: 'bash', icon: BashIcon },\n { id: ShellTypeValues.PYTHON, label: 'Python', value: 'python', icon: PythonLogoIcon },\n { id: ShellTypeValues.NUSHELL, label: 'Nu', value: 'nushell', icon: NushellIcon },\n { id: ShellTypeValues.DENO, label: 'Deno', value: 'deno', icon: DenoIcon },\n { id: ShellTypeValues.SHELL, label: 'Shell', value: 'shell', icon: ShellIcon },\n];\n\n/**\n * Maps shell types to display labels\n */\nexport const shellLabels: Record<ShellType, string> = {\n [ShellTypeValues.POWERSHELL]: 'PowerShell',\n [ShellTypeValues.CMD]: 'Batch',\n [ShellTypeValues.BASH]: 'Bash',\n [ShellTypeValues.PYTHON]: 'Python',\n [ShellTypeValues.NUSHELL]: 'Nu',\n [ShellTypeValues.DENO]: 'Deno',\n [ShellTypeValues.SHELL]: 'Shell',\n};\n","import type { SVGProps } from \"react\";\nexport interface AppleLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function AppleLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: AppleLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"M17.57 12.628c-.024-2.531 2.062-3.747 2.156-3.805-1.174-1.72-2.999-1.957-3.649-1.983-1.552-.16-3.03.917-3.82.917s-2.005-.895-3.293-.869c-1.694.024-3.257.987-4.13 2.507-1.758 3.054-.448 7.59 1.268 10.073.84 1.213 1.837 2.581 3.151 2.53 1.266-.05 1.743-.82 3.269-.82s1.957.82 3.293.796c1.36-.026 2.222-1.24 3.054-2.458.958-1.411 1.356-2.775 1.38-2.847-.032-.012-2.65-1.018-2.68-4.041M15.06 5.194c.697-.846 1.167-2.021 1.039-3.194-1.004.041-2.22.67-2.94 1.518-.644.748-1.21 1.944-1.056 3.093 1.115.086 2.26-.572 2.956-1.417\"\n />\n </svg>\n );\n}\n","import type { SVGProps } from \"react\";\nexport interface LinuxLogoIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function LinuxLogoIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: LinuxLogoIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"M19.567 18.314c-.528-.217-.963-.558-.931-1.213.03-.653-.467-1.086-.467-1.086s.435-1.43.031-2.612c-.403-1.183-1.737-3.078-2.76-4.507-1.023-1.43-.155-3.08-1.085-5.192-.932-2.113-3.351-1.99-4.654-1.087-1.304.9-.901 3.137-.84 4.196.062 1.056.028 1.808-.092 2.082-.123.273-.961 1.276-1.52 2.114-.559.84-.962 2.58-1.367 3.295-.403.715-.124 1.368-.124 1.368s-.28.092-.497.56c-.217.465-.65.683-1.427.837-.775.155-.775.655-.59 1.214.187.559.001.871-.216 1.585-.217.713.869.932 1.923 1.054 1.055.126 2.234.81 3.228.934.992.125 1.303-.683 1.303-.683s1.116-.25 2.294-.28c1.18-.031 2.295.249 2.295.249s.218.497.62.714c.405.218 1.273.25 1.832-.34.559-.592 2.048-1.337 2.885-1.804.84-.468.686-1.182.159-1.398M12.306 4.606c.532 0 .961.528.961 1.18 0 .463-.215.862-.53 1.056l-.254-.11c.19-.094.324-.335.324-.617 0-.367-.227-.666-.507-.666-.277 0-.505.3-.505.666a.8.8 0 0 0 .088.373c-.165-.066-.318-.127-.437-.172a1.4 1.4 0 0 1-.102-.53c0-.652.43-1.18.962-1.18m-.07 2.488c.267.093.562.266.532.438-.032.172-.172.172-.531.393-.36.218-1.142.703-1.392.735-.251.031-.39-.11-.657-.281-.266-.173-.766-.582-.64-.8 0 0 .39-.298.561-.455s.61-.532.876-.483c.266.045.986.36 1.252.453M9.84 4.793c.42 0 .76.5.76 1.118q0 .168-.032.32a1 1 0 0 0-.307.177 4 4 0 0 0-.14.12.8.8 0 0 0 .063-.49c-.056-.337-.28-.583-.503-.547-.221.038-.355.341-.299.68.057.34.28.585.502.548l.038-.01a3 3 0 0 1-.31.27c-.307-.143-.532-.567-.532-1.07 0-.617.34-1.116.76-1.116M9.019 20.5c-.098.445-.62.77-.62.77-.471.148-1.784-.423-2.38-.673-.593-.247-2.106-.324-2.305-.544-.197-.226.099-.722.175-1.192.073-.474-.148-.77-.075-1.094.075-.322 1.042-.322 1.412-.545.373-.225.447-.87.745-1.044.297-.175.842.446 1.065.795.222.346 1.066 1.837 1.412 2.21.348.372.67.87.572 1.317m5.488-4.332c-.09.438-.09 2.021-.09 2.021s-.961 1.335-2.452 1.554c-1.49.219-2.234.061-2.234.061l-.838-.962s.65-.095.559-.747c-.094-.653-1.985-1.555-2.327-2.363-.34-.808-.062-2.177.373-2.86.434-.684.712-2.175 1.147-2.674.434-.495.774-1.553.62-2.02 0 0 .93 1.12 1.58.935.652-.187 2.112-1.276 2.328-1.089s2.078 4.29 2.263 5.595-.125 2.3-.125 2.3-.712-.187-.804.249m4.761 2.928c-.29.267-1.902.92-2.386 1.428-.48.505-1.109.916-1.493.796-.387-.122-.724-.652-.555-1.426.168-.771.314-1.617.29-2.1s-.122-1.137 0-1.233c.12-.094.312-.047.312-.047s-.095.916.458 1.16c.554.239 1.35-.097 1.59-.34.243-.24.412-.602.412-.602s.24.122.216.507c-.024.386.168.943.531 1.135.36.19.915.458.625.722\"\n />\n </svg>\n );\n}\n","import type { SVGProps } from \"react\";\nexport interface WindowsLogoGreyIconProps\n extends Omit<SVGProps<SVGSVGElement>, \"width\" | \"height\"> {\n className?: string;\n size?: number;\n color?: string;\n}\nexport function WindowsLogoGreyIcon({\n className = \"\",\n size = 24,\n color = \"currentColor\",\n ...props\n}: WindowsLogoGreyIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n className={className}\n {...props}\n >\n <path\n fill={color}\n d=\"m2 4.832 8.173-1.11.004 7.86-8.17.046zm8.17 7.655.006 7.867-8.17-1.12v-6.8zm.99-8.91L21.997 2v9.482l-10.837.085zM22 12.56 21.997 22 11.16 20.475l-.015-7.932z\"\n />\n </svg>\n );\n}\n","/**\n * Centralized OS Types\n *\n * Single source of truth for all operating system type information across the platform.\n * Handles normalization of OS values from various sources (Fleet MDM, OpenFrame RMM, GraphQL).\n */\n\nimport type React from 'react';\nimport { AppleLogoIcon } from '../components/icons-v2-generated/brand-logos/apple-logo-icon';\nimport { LinuxLogoIcon } from '../components/icons-v2-generated/brand-logos/linux-logo-icon';\nimport { WindowsLogoGreyIcon } from '../components/icons-v2-generated/brand-logos/windows-logo-grey-icon';\nimport type { OSPlatformId } from '../utils/os-platforms';\n\nexport const OSTypeValues = {\n WINDOWS: 'WINDOWS',\n MACOS: 'MACOS',\n LINUX: 'LINUX',\n} as const;\n\nexport type OSType = (typeof OSTypeValues)[keyof typeof OSTypeValues];\n\n/**\n * OS type definition with all metadata\n */\nexport interface OSTypeDefinition {\n id: OSType;\n label: string;\n value: string;\n icon: React.ComponentType<React.SVGProps<SVGSVGElement>>;\n platformId: OSPlatformId;\n aliases: string[]; // Alternative names/values that map to this OS\n}\n\n/**\n * Complete list of all OS types with icons and labels\n * SINGLE SOURCE OF TRUTH - Use this everywhere\n */\nexport const OS_TYPES: OSTypeDefinition[] = [\n {\n id: OSTypeValues.MACOS,\n label: 'macOS',\n value: OSTypeValues.MACOS,\n icon: AppleLogoIcon,\n platformId: 'darwin',\n aliases: ['darwin', 'macos', 'mac os', 'osx', 'os x', 'mac'], // Put more specific ones first, 'mac' last to avoid false matches\n },\n {\n id: OSTypeValues.WINDOWS,\n label: 'Windows',\n value: OSTypeValues.WINDOWS,\n icon: WindowsLogoGreyIcon,\n platformId: 'windows',\n aliases: ['windows', 'win32', 'win64', 'win'], // 'win' last since it's shortest\n },\n {\n id: OSTypeValues.LINUX,\n label: 'Linux',\n value: OSTypeValues.LINUX,\n icon: LinuxLogoIcon,\n platformId: 'linux',\n aliases: ['linux', 'ubuntu', 'debian', 'centos', 'redhat', 'fedora', 'pop', 'pop!_os', 'arch', 'manjaro'],\n },\n];\n\n/**\n * Maps OS types to display labels\n */\nexport const osLabels: Record<OSType, string> = {\n [OSTypeValues.WINDOWS]: 'Windows',\n [OSTypeValues.MACOS]: 'macOS',\n [OSTypeValues.LINUX]: 'Linux',\n};\n","/**\n * TMCG (The Miami Cyber Gang) related types and interfaces\n */\n\nexport interface TMCGMemberSocialLink {\n platform: string;\n url: string;\n username?: string;\n}\n\nexport interface TMCGMember {\n id: string;\n full_name: string;\n avatar_url?: string | null;\n company?: string | null;\n about?: string | null;\n job_title?: string | null;\n tmcg_roles: string[];\n social_links: TMCGMemberSocialLink[];\n created_at: string;\n updated_at: string;\n}\n\nexport interface TMCGMembersResponse {\n success: boolean;\n data: {\n members: TMCGMember[];\n count: number;\n };\n error?: string;\n}\n\nexport interface TMCGMemberResponse {\n success: boolean;\n data: TMCGMember;\n error?: string;\n}\n\n/**\n * TMCG Member Card Props\n */\nexport interface TMCGMemberCardProps {\n member: TMCGMember;\n className?: string;\n compact?: boolean;\n}\n\n/**\n * TMCG Members Grid Props\n */\nexport interface TMCGMembersGridProps {\n members: TMCGMember[];\n isLoading?: boolean;\n error?: string | null;\n className?: string;\n}\n\n/**\n * TMCG Social Links Props\n */\nexport interface TMCGSocialLinksProps {\n socialLinks: TMCGMemberSocialLink[];\n className?: string;\n size?: 'sm' | 'md' | 'lg';\n}\n\n/**\n * Hook return types\n */\nexport interface UseTMCGMembersResult {\n members: TMCGMember[];\n isLoading: boolean;\n error: string | null;\n refetch: () => void;\n}\n\nexport interface UseTMCGMemberResult {\n member: TMCGMember | null;\n isLoading: boolean;\n error: string | null;\n refetch: () => void;\n}\n\n/**\n * TMCG specific constants\n */\nexport const TMCG_ROLES = {\n FOUNDER: 'founder',\n ORGANIZER: 'organizer',\n MEMBER: 'member',\n CONTRIBUTOR: 'contributor',\n SPEAKER: 'speaker',\n MENTOR: 'mentor',\n} as const;\n\nexport type TMCGRole = (typeof TMCG_ROLES)[keyof typeof TMCG_ROLES];\n\n/**\n * TMCG role display names\n */\nexport const TMCG_ROLE_DISPLAY_NAMES: Record<string, string> = {\n [TMCG_ROLES.FOUNDER]: 'Founder',\n [TMCG_ROLES.ORGANIZER]: 'Organizer',\n [TMCG_ROLES.MEMBER]: 'Member',\n [TMCG_ROLES.CONTRIBUTOR]: 'Contributor',\n [TMCG_ROLES.SPEAKER]: 'Speaker',\n [TMCG_ROLES.MENTOR]: 'Mentor',\n};\n"]}
@@ -148,7 +148,9 @@ var ToolTypeValues = {
148
148
  OPENFRAME_CLIENT: "OPENFRAME_CLIENT",
149
149
  OPENFRAME_RMM: "OPENFRAME_RMM",
150
150
  OSQUERY: "OSQUERY",
151
- SYSTEM: "SYSTEM"
151
+ SYSTEM: "SYSTEM",
152
+ MICROSOFT_365: "MICROSOFT_365",
153
+ GOOGLE_WORKSPACE: "GOOGLE_WORKSPACE"
152
154
  };
153
155
  var toolLabels = {
154
156
  FLEET_MDM: "Fleet",
@@ -159,7 +161,9 @@ var toolLabels = {
159
161
  OPENFRAME_CLIENT: "OpenFrame Client",
160
162
  OPENFRAME_RMM: "RMM",
161
163
  OSQUERY: "Osquery",
162
- SYSTEM: "System"
164
+ SYSTEM: "System",
165
+ MICROSOFT_365: "Microsoft 365",
166
+ GOOGLE_WORKSPACE: "Google Workspace"
163
167
  };
164
168
  function ShellIcon({
165
169
  className = "w-5 h-5",