@agent-native/core 0.102.1 → 0.103.0

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 (295) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +15 -0
  3. package/corpus/core/docs/content/local-file-mode.mdx +99 -489
  4. package/corpus/core/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
  5. package/corpus/core/docs/content/locales/ar-SA/template-content.mdx +10 -24
  6. package/corpus/core/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
  7. package/corpus/core/docs/content/locales/de-DE/template-content.mdx +10 -24
  8. package/corpus/core/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
  9. package/corpus/core/docs/content/locales/es-ES/template-content.mdx +10 -24
  10. package/corpus/core/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
  11. package/corpus/core/docs/content/locales/fr-FR/template-content.mdx +10 -24
  12. package/corpus/core/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
  13. package/corpus/core/docs/content/locales/hi-IN/template-content.mdx +10 -24
  14. package/corpus/core/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
  15. package/corpus/core/docs/content/locales/ja-JP/template-content.mdx +10 -24
  16. package/corpus/core/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
  17. package/corpus/core/docs/content/locales/ko-KR/template-content.mdx +10 -24
  18. package/corpus/core/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
  19. package/corpus/core/docs/content/locales/pt-BR/template-content.mdx +10 -24
  20. package/corpus/core/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
  21. package/corpus/core/docs/content/locales/zh-CN/template-content.mdx +9 -24
  22. package/corpus/core/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
  23. package/corpus/core/docs/content/locales/zh-TW/template-content.mdx +9 -24
  24. package/corpus/core/docs/content/template-content.mdx +26 -42
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/cli/content-local.ts +86 -18
  27. package/corpus/core/src/cli/index.ts +2 -2
  28. package/corpus/core/src/cli/skills-content/content-skill.ts +36 -25
  29. package/corpus/core/src/cli/skills.ts +47 -13
  30. package/corpus/core/src/client/AgentPanel.tsx +7 -0
  31. package/corpus/core/src/client/AssistantChat.tsx +7 -0
  32. package/corpus/core/src/client/agent-chat-adapter.ts +7 -1
  33. package/corpus/core/src/client/chat/message-components.tsx +17 -3
  34. package/corpus/core/src/client/composer/ComposerPlusMenu.tsx +96 -6
  35. package/corpus/core/src/client/composer/asset-picker-url.ts +80 -0
  36. package/corpus/core/src/client/error-format.ts +24 -0
  37. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +8 -1
  38. package/corpus/core/src/local-artifacts/index.ts +65 -0
  39. package/corpus/templates/assets/app/components/library/GenerationPresetsPanel.tsx +325 -0
  40. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +12 -0
  41. package/corpus/templates/assets/app/i18n/zh-TW.ts +21 -0
  42. package/corpus/templates/assets/app/i18n-data.ts +215 -0
  43. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +19 -479
  44. package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +1 -1
  45. package/corpus/templates/assets/app/routes/brand-kits.$id_.settings.tsx +446 -0
  46. package/corpus/templates/assets/app/routes/library.tsx +69 -0
  47. package/corpus/templates/assets/changelog/2026-07-15-fixed-top-level-image-picker-selections-returning-to-the-com.md +6 -0
  48. package/corpus/templates/clips/actions/disconnect-calendar.ts +57 -9
  49. package/corpus/templates/clips/actions/generate-workflow.ts +102 -59
  50. package/corpus/templates/clips/actions/get-recording-player-data.ts +64 -1
  51. package/corpus/templates/clips/actions/regenerate-summary.ts +7 -0
  52. package/corpus/templates/clips/actions/regenerate-title.ts +29 -11
  53. package/corpus/templates/clips/app/components/editor/editor-layout.tsx +34 -13
  54. package/corpus/templates/clips/app/components/editor/thumbnail-picker.tsx +87 -9
  55. package/corpus/templates/clips/app/components/editor/trim-handles.tsx +15 -0
  56. package/corpus/templates/clips/app/components/editor/waveform.tsx +21 -8
  57. package/corpus/templates/clips/app/components/library/folder-tree.tsx +52 -0
  58. package/corpus/templates/clips/app/components/player/settings-panel.tsx +116 -58
  59. package/corpus/templates/clips/app/components/player/share-dialog.tsx +43 -37
  60. package/corpus/templates/clips/app/components/player/video-player.tsx +50 -2
  61. package/corpus/templates/clips/app/components/recorder/microphone-visualizer.tsx +22 -3
  62. package/corpus/templates/clips/app/i18n/ar-SA.ts +5 -2
  63. package/corpus/templates/clips/app/i18n/de-DE.ts +6 -2
  64. package/corpus/templates/clips/app/i18n/en-US.ts +5 -2
  65. package/corpus/templates/clips/app/i18n/es-ES.ts +6 -2
  66. package/corpus/templates/clips/app/i18n/fr-FR.ts +5 -2
  67. package/corpus/templates/clips/app/i18n/hi-IN.ts +5 -2
  68. package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -1
  69. package/corpus/templates/clips/app/i18n/ko-KR.ts +5 -2
  70. package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -2
  71. package/corpus/templates/clips/app/i18n/zh-CN.ts +5 -2
  72. package/corpus/templates/clips/app/i18n/zh-TW.ts +5 -2
  73. package/corpus/templates/clips/app/lib/timestamp-mapping.ts +14 -0
  74. package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -2
  75. package/corpus/templates/clips/app/routes/_index.tsx +1 -2
  76. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +98 -32
  77. package/corpus/templates/clips/app/routes/share.$shareId.tsx +4 -1
  78. package/corpus/templates/clips/changelog/2026-07-15-ai-workflow-generation-now-stays-visible-avoids-duplicate-re.md +6 -0
  79. package/corpus/templates/clips/changelog/2026-07-15-clip-playback-and-cta-controls-remain-interactive-through-ed.md +6 -0
  80. package/corpus/templates/clips/changelog/2026-07-15-clip-titles-no-longer-describe-the-product-as-a-loom-alterna.md +6 -0
  81. package/corpus/templates/clips/changelog/2026-07-15-description-regeneration-now-opens-the-agent-chat-so-progres.md +6 -0
  82. package/corpus/templates/clips/changelog/2026-07-15-direct-recording-urls-now-respect-share-link-and-password-ac.md +6 -0
  83. package/corpus/templates/clips/changelog/2026-07-15-disconnecting-a-calendar-now-clears-unrecorded-synced-meetin.md +6 -0
  84. package/corpus/templates/clips/changelog/2026-07-15-folders-now-expose-rename-and-delete-actions-directly-in-the.md +6 -0
  85. package/corpus/templates/clips/changelog/2026-07-15-recording-pages-now-explain-sign-in-access-and-avoid-showing.md +6 -0
  86. package/corpus/templates/clips/changelog/2026-07-15-the-clips-extension-quick-actions-toolbar-can-be-moved-out-o.md +6 -0
  87. package/corpus/templates/clips/changelog/2026-07-15-the-editor-now-skips-cut-sections-during-preview-and-keeps-t.md +6 -0
  88. package/corpus/templates/clips/changelog/2026-07-15-thumbnail-capture-now-updates-previews-while-scrubbing-and-l.md +6 -0
  89. package/corpus/templates/clips/changelog/2026-07-15-windows-permission-links-open-the-matching-settings-page.md +6 -0
  90. package/corpus/templates/clips/chrome-extension/src/content-script.ts +117 -2
  91. package/corpus/templates/clips/chrome-extension/src/overlay.ts +27 -0
  92. package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -1
  93. package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +139 -101
  94. package/corpus/templates/clips/server/lib/recording-page-access.ts +35 -0
  95. package/corpus/templates/clips/server/lib/share-password.ts +6 -3
  96. package/corpus/templates/content/.agents/skills/content/SKILL.md +26 -39
  97. package/corpus/templates/content/AGENTS.md +25 -30
  98. package/corpus/templates/content/actions/_builder-docs-client.ts +23 -0
  99. package/corpus/templates/content/actions/_content-database-source-adapters.ts +21 -3
  100. package/corpus/templates/content/actions/_content-files.ts +338 -0
  101. package/corpus/templates/content/actions/_content-space-access.ts +135 -0
  102. package/corpus/templates/content/actions/_content-spaces.ts +640 -0
  103. package/corpus/templates/content/actions/_database-source-utils.ts +90 -7
  104. package/corpus/templates/content/actions/_database-utils.ts +7 -1
  105. package/corpus/templates/content/actions/_local-file-documents.ts +0 -9
  106. package/corpus/templates/content/actions/_local-folder-source.ts +53 -0
  107. package/corpus/templates/content/actions/_property-utils.ts +9 -4
  108. package/corpus/templates/content/actions/add-database-item.ts +108 -65
  109. package/corpus/templates/content/actions/backfill-content-files.ts +22 -0
  110. package/corpus/templates/content/actions/connect-local-folder-source.ts +221 -0
  111. package/corpus/templates/content/actions/create-content-database.ts +129 -3
  112. package/corpus/templates/content/actions/create-document.ts +65 -55
  113. package/corpus/templates/content/actions/create-inline-content-database.ts +6 -1
  114. package/corpus/templates/content/actions/delete-content-database.ts +3 -0
  115. package/corpus/templates/content/actions/delete-document.ts +7 -11
  116. package/corpus/templates/content/actions/disconnect-local-folder-source.ts +175 -0
  117. package/corpus/templates/content/actions/duplicate-database-item.ts +10 -0
  118. package/corpus/templates/content/actions/duplicate-database-items.ts +13 -0
  119. package/corpus/templates/content/actions/edit-document.ts +2 -28
  120. package/corpus/templates/content/actions/ensure-content-spaces.ts +26 -0
  121. package/corpus/templates/content/actions/export-content-source.ts +47 -9
  122. package/corpus/templates/content/actions/get-document.ts +0 -14
  123. package/corpus/templates/content/actions/import-content-source.ts +43 -3
  124. package/corpus/templates/content/actions/list-content-spaces.ts +103 -0
  125. package/corpus/templates/content/actions/list-documents.ts +12 -9
  126. package/corpus/templates/content/actions/move-document.ts +3 -14
  127. package/corpus/templates/content/actions/pull-document.ts +0 -23
  128. package/corpus/templates/content/actions/remove-local-file-source.ts +50 -29
  129. package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +442 -0
  130. package/corpus/templates/content/actions/reveal-local-source-file.ts +6 -17
  131. package/corpus/templates/content/actions/search-documents.ts +0 -34
  132. package/corpus/templates/content/actions/share-local-file-document.ts +25 -1
  133. package/corpus/templates/content/actions/submit-content-database-form.ts +12 -0
  134. package/corpus/templates/content/actions/sync-local-folder-source.ts +731 -0
  135. package/corpus/templates/content/actions/sync-manifest-local-folder-source.ts +123 -0
  136. package/corpus/templates/content/actions/update-content-database-view.ts +10 -1
  137. package/corpus/templates/content/actions/update-document.ts +0 -15
  138. package/corpus/templates/content/actions/view-screen.ts +2 -50
  139. package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +76 -62
  140. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +70 -22
  141. package/corpus/templates/content/app/components/editor/database/grouping.ts +2 -1
  142. package/corpus/templates/content/app/components/editor/database/settings.tsx +23 -20
  143. package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
  144. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +330 -0
  145. package/corpus/templates/content/app/components/editor/database/types.ts +1 -0
  146. package/corpus/templates/content/app/components/editor/database/view-config.ts +3 -1
  147. package/corpus/templates/content/app/components/layout/Layout.tsx +25 -1
  148. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +209 -113
  149. package/corpus/templates/content/app/components/sidebar/select-content-space.ts +31 -0
  150. package/corpus/templates/content/app/hooks/use-content-database.ts +16 -0
  151. package/corpus/templates/content/app/hooks/use-content-spaces.ts +39 -0
  152. package/corpus/templates/content/app/i18n/zh-TW.ts +11 -0
  153. package/corpus/templates/content/app/i18n-data.ts +75 -0
  154. package/corpus/templates/content/app/routes/_app.local-files.tsx +174 -65
  155. package/corpus/templates/content/changelog/2026-07-16-content-callouts-can-now-be-reviewed-and-published-to-builder.md +6 -0
  156. package/corpus/templates/content/changelog/2026-07-16-heading-5-and-heading-6-are-available-from-the-editor-slash-.md +6 -0
  157. package/corpus/templates/content/changelog/2026-07-16-organize-every-workspace-through-a-customizable-files-databa.md +6 -0
  158. package/corpus/templates/content/parity/matrix.md +2 -1
  159. package/corpus/templates/content/parity/matrix.ts +37 -1
  160. package/corpus/templates/content/scripts/dev-database.mjs +7 -5
  161. package/corpus/templates/content/server/db/schema.ts +113 -40
  162. package/corpus/templates/content/server/lib/document-context.ts +15 -1
  163. package/corpus/templates/content/server/lib/notion-sync.ts +6 -0
  164. package/corpus/templates/content/server/plugins/db.ts +153 -0
  165. package/corpus/templates/content/shared/api.ts +17 -3
  166. package/corpus/templates/content/shared/builder-mdx.ts +163 -16
  167. package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +59 -0
  168. package/corpus/templates/design/AGENTS.md +6 -1
  169. package/corpus/templates/design/actions/create-design-from-template.ts +19 -7
  170. package/corpus/templates/design/actions/list-design-templates.ts +69 -21
  171. package/corpus/templates/design/actions/navigate.ts +2 -2
  172. package/corpus/templates/design/actions/view-screen.ts +15 -2
  173. package/corpus/templates/design/agent-native.app-skill.json +5 -0
  174. package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +7 -3
  175. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +281 -56
  176. package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +14 -2
  177. package/corpus/templates/design/app/hooks/use-navigation-state.ts +3 -2
  178. package/corpus/templates/design/app/i18n/zh-TW.ts +3 -3
  179. package/corpus/templates/design/app/i18n-data.ts +21 -2
  180. package/corpus/templates/design/app/i18n-template-feature.ts +218 -10
  181. package/corpus/templates/design/app/pages/Index.tsx +195 -24
  182. package/corpus/templates/design/app/pages/Templates.tsx +144 -55
  183. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +12 -1
  184. package/corpus/templates/design/changelog/2026-07-14-templates-now-appear-in-the-new-design-picker-with-previews-.md +6 -0
  185. package/corpus/templates/design/changelog/2026-07-15-prototype-print-and-download-buttons-now-work-in-preview.md +6 -0
  186. package/corpus/templates/design/changelog/2026-07-15-templates-now-open-immediately-after-copying-even-while-the-.md +6 -0
  187. package/corpus/templates/design/server/plugins/agent-chat.ts +1 -1
  188. package/corpus/templates/mail/AGENTS.md +23 -18
  189. package/corpus/templates/mail/actions/bulk-archive.ts +32 -28
  190. package/corpus/templates/mail/actions/mark-read.ts +131 -20
  191. package/corpus/templates/mail/actions/mark-thread-read.ts +1 -1
  192. package/corpus/templates/mail/actions/move-email.ts +30 -24
  193. package/corpus/templates/mail/actions/send-email.ts +73 -68
  194. package/corpus/templates/mail/changelog/2026-07-15-unread-inbox-cleanup-now-completes-reliably.md +6 -0
  195. package/corpus/templates/mail/server/handlers/emails.ts +218 -209
  196. package/corpus/templates/mail/server/lib/bulk-mark-read.ts +30 -0
  197. package/corpus/templates/mail/server/lib/email-state.ts +198 -113
  198. package/corpus/templates/mail/server/lib/google-auth.ts +218 -25
  199. package/corpus/templates/mail/server/lib/jobs.ts +69 -74
  200. package/corpus/templates/mail/server/lib/local-email-store.ts +265 -0
  201. package/corpus/templates/mail/server/plugins/agent-chat.ts +6 -0
  202. package/corpus/templates/slides/actions/extract-pdf.ts +1 -1
  203. package/corpus/templates/slides/actions/import-file.ts +4 -1
  204. package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
  205. package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +9 -12
  206. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +29 -21
  207. package/corpus/templates/slides/app/i18n/ar-SA.ts +1 -0
  208. package/corpus/templates/slides/app/i18n/de-DE.ts +1 -0
  209. package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
  210. package/corpus/templates/slides/app/i18n/es-ES.ts +1 -0
  211. package/corpus/templates/slides/app/i18n/fr-FR.ts +1 -0
  212. package/corpus/templates/slides/app/i18n/hi-IN.ts +1 -0
  213. package/corpus/templates/slides/app/i18n/ja-JP.ts +1 -0
  214. package/corpus/templates/slides/app/i18n/ko-KR.ts +1 -0
  215. package/corpus/templates/slides/app/i18n/pt-BR.ts +1 -0
  216. package/corpus/templates/slides/app/i18n/zh-CN.ts +1 -0
  217. package/corpus/templates/slides/app/i18n/zh-TW.ts +1 -0
  218. package/corpus/templates/slides/changelog/2026-07-15-image-search-and-generation-controls-now-use-the-registered-.md +6 -0
  219. package/corpus/templates/slides/changelog/2026-07-15-pdf-deck-references-can-be-imported-for-slide-inspiration-ag.md +6 -0
  220. package/corpus/templates/slides/changelog/2026-07-15-stable-style-inspector-dock.md +6 -0
  221. package/dist/cli/content-local.d.ts +1 -0
  222. package/dist/cli/content-local.d.ts.map +1 -1
  223. package/dist/cli/content-local.js +75 -17
  224. package/dist/cli/content-local.js.map +1 -1
  225. package/dist/cli/index.js +2 -2
  226. package/dist/cli/index.js.map +1 -1
  227. package/dist/cli/skills-content/content-skill.d.ts +1 -1
  228. package/dist/cli/skills-content/content-skill.d.ts.map +1 -1
  229. package/dist/cli/skills-content/content-skill.js +36 -25
  230. package/dist/cli/skills-content/content-skill.js.map +1 -1
  231. package/dist/cli/skills.d.ts.map +1 -1
  232. package/dist/cli/skills.js +47 -14
  233. package/dist/cli/skills.js.map +1 -1
  234. package/dist/client/AgentPanel.d.ts.map +1 -1
  235. package/dist/client/AgentPanel.js +5 -0
  236. package/dist/client/AgentPanel.js.map +1 -1
  237. package/dist/client/AssistantChat.d.ts.map +1 -1
  238. package/dist/client/AssistantChat.js +7 -0
  239. package/dist/client/AssistantChat.js.map +1 -1
  240. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  241. package/dist/client/agent-chat-adapter.js +8 -1
  242. package/dist/client/agent-chat-adapter.js.map +1 -1
  243. package/dist/client/chat/message-components.d.ts +4 -0
  244. package/dist/client/chat/message-components.d.ts.map +1 -1
  245. package/dist/client/chat/message-components.js +10 -3
  246. package/dist/client/chat/message-components.js.map +1 -1
  247. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
  248. package/dist/client/composer/ComposerPlusMenu.js +58 -6
  249. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  250. package/dist/client/composer/asset-picker-url.d.ts +16 -0
  251. package/dist/client/composer/asset-picker-url.d.ts.map +1 -0
  252. package/dist/client/composer/asset-picker-url.js +64 -0
  253. package/dist/client/composer/asset-picker-url.js.map +1 -0
  254. package/dist/client/error-format.d.ts.map +1 -1
  255. package/dist/client/error-format.js +17 -0
  256. package/dist/client/error-format.js.map +1 -1
  257. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  258. package/dist/client/resources/McpIntegrationDialog.js +6 -1
  259. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  260. package/dist/collab/awareness.d.ts +2 -2
  261. package/dist/collab/awareness.d.ts.map +1 -1
  262. package/dist/collab/struct-routes.d.ts +1 -1
  263. package/dist/local-artifacts/index.d.ts +10 -0
  264. package/dist/local-artifacts/index.d.ts.map +1 -1
  265. package/dist/local-artifacts/index.js +39 -0
  266. package/dist/local-artifacts/index.js.map +1 -1
  267. package/dist/notifications/routes.d.ts +1 -1
  268. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  269. package/dist/resources/handlers.d.ts +3 -3
  270. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  271. package/dist/server/transcribe-voice.d.ts +1 -1
  272. package/docs/content/local-file-mode.mdx +99 -489
  273. package/docs/content/locales/ar-SA/local-file-mode.mdx +35 -490
  274. package/docs/content/locales/ar-SA/template-content.mdx +10 -24
  275. package/docs/content/locales/de-DE/local-file-mode.mdx +37 -491
  276. package/docs/content/locales/de-DE/template-content.mdx +10 -24
  277. package/docs/content/locales/es-ES/local-file-mode.mdx +35 -493
  278. package/docs/content/locales/es-ES/template-content.mdx +10 -24
  279. package/docs/content/locales/fr-FR/local-file-mode.mdx +38 -491
  280. package/docs/content/locales/fr-FR/template-content.mdx +10 -24
  281. package/docs/content/locales/hi-IN/local-file-mode.mdx +33 -492
  282. package/docs/content/locales/hi-IN/template-content.mdx +10 -24
  283. package/docs/content/locales/ja-JP/local-file-mode.mdx +36 -492
  284. package/docs/content/locales/ja-JP/template-content.mdx +10 -24
  285. package/docs/content/locales/ko-KR/local-file-mode.mdx +35 -490
  286. package/docs/content/locales/ko-KR/template-content.mdx +10 -24
  287. package/docs/content/locales/pt-BR/local-file-mode.mdx +35 -493
  288. package/docs/content/locales/pt-BR/template-content.mdx +10 -24
  289. package/docs/content/locales/zh-CN/local-file-mode.mdx +31 -489
  290. package/docs/content/locales/zh-CN/template-content.mdx +9 -24
  291. package/docs/content/locales/zh-TW/local-file-mode.mdx +31 -489
  292. package/docs/content/locales/zh-TW/template-content.mdx +9 -24
  293. package/docs/content/template-content.mdx +26 -42
  294. package/package.json +1 -1
  295. package/corpus/templates/assets/app/components/library/EditLibraryDialog.tsx +0 -126
@@ -13,6 +13,7 @@ export interface TrimHandlesProps {
13
13
  /** Fires when the user releases the mouse after drag. */
14
14
  onCommit?: (value: { startMs: number; endMs: number }) => void;
15
15
  durationMs: number;
16
+ splitPoints?: number[];
16
17
  className?: string;
17
18
  }
18
19
 
@@ -44,6 +45,7 @@ export function TrimHandles({
44
45
  onChange,
45
46
  onCommit,
46
47
  durationMs,
48
+ splitPoints = [],
47
49
  className,
48
50
  }: TrimHandlesProps) {
49
51
  const rootRef = useRef<HTMLDivElement | null>(null);
@@ -111,6 +113,9 @@ export function TrimHandles({
111
113
 
112
114
  const startX = (value.startMs / Math.max(durationMs, 1)) * width;
113
115
  const endX = (value.endMs / Math.max(durationMs, 1)) * width;
116
+ const visibleSplitPoints = splitPoints.filter(
117
+ (ms) => ms > value.startMs && ms < value.endMs, // i18n-ignore numeric range predicate, not visible UI copy
118
+ );
114
119
 
115
120
  return (
116
121
  <div
@@ -133,6 +138,16 @@ export function TrimHandles({
133
138
  <div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-full bg-foreground text-background text-[10px] px-1.5 py-0.5 rounded font-mono whitespace-nowrap">
134
139
  {formatMs(value.endMs - value.startMs)}
135
140
  </div>
141
+ {visibleSplitPoints.map((splitMs) => (
142
+ <div
143
+ key={splitMs}
144
+ className="absolute top-0 h-full w-0.5 -translate-x-1/2 bg-rose-500/95"
145
+ style={{
146
+ left: `${((splitMs - value.startMs) / Math.max(value.endMs - value.startMs, 1)) * 100}%`,
147
+ }}
148
+ aria-hidden="true"
149
+ />
150
+ ))}
136
151
  </div>
137
152
 
138
153
  {/* Left handle */}
@@ -18,6 +18,8 @@ export interface WaveformProps {
18
18
  durationMs: number;
19
19
  /** Excluded ranges (original time) — drawn as striped overlays. */
20
20
  excludedRanges?: Array<{ startMs: number; endMs: number }>;
21
+ /** Split markers (original time) — drawn over the active selection. */
22
+ splitPoints?: number[];
21
23
  /** Optional selection range (original time) highlighted in brand color. */
22
24
  selectionRange?: { startMs: number; endMs: number } | null;
23
25
  /** Transcript-backed activity ranges used when browser audio decoding fails. */
@@ -87,6 +89,7 @@ export function Waveform({
87
89
  playheadMs,
88
90
  durationMs,
89
91
  excludedRanges,
92
+ splitPoints = [],
90
93
  selectionRange,
91
94
  activityRanges = [],
92
95
  onSeek,
@@ -220,19 +223,28 @@ export function Waveform({
220
223
 
221
224
  // Selection overlay
222
225
  if (selectionRange) {
223
- const xStart =
224
- (Math.min(selectionRange.startMs, selectionRange.endMs) /
225
- Math.max(durationMs, 1)) *
226
- totalWidth;
227
- const xEnd =
228
- (Math.max(selectionRange.startMs, selectionRange.endMs) /
229
- Math.max(durationMs, 1)) *
230
- totalWidth;
226
+ const startMs = Math.min(selectionRange.startMs, selectionRange.endMs);
227
+ const endMs = Math.max(selectionRange.startMs, selectionRange.endMs);
228
+ const xStart = (startMs / Math.max(durationMs, 1)) * totalWidth;
229
+ const xEnd = (endMs / Math.max(durationMs, 1)) * totalWidth;
231
230
  ctx.fillStyle = getBrandColorAlpha(0.28);
232
231
  ctx.fillRect(xStart, 0, xEnd - xStart, height);
233
232
  ctx.strokeStyle = getBrandColor();
234
233
  ctx.lineWidth = 1;
235
234
  ctx.strokeRect(xStart + 0.5, 0.5, xEnd - xStart - 1, height - 1);
235
+
236
+ // Keep split markers visible on the selected track as well as on the
237
+ // ruler so a split is visibly actionable within the selection.
238
+ for (const splitMs of splitPoints) {
239
+ if (splitMs <= startMs || splitMs >= endMs) continue;
240
+ const splitX = (splitMs / Math.max(durationMs, 1)) * totalWidth;
241
+ ctx.strokeStyle = "rgba(244, 63, 94, 0.95)";
242
+ ctx.lineWidth = 2;
243
+ ctx.beginPath();
244
+ ctx.moveTo(splitX, 0);
245
+ ctx.lineTo(splitX, height);
246
+ ctx.stroke();
247
+ }
236
248
  }
237
249
  }, [
238
250
  peaks,
@@ -240,6 +252,7 @@ export function Waveform({
240
252
  height,
241
253
  excludedRanges,
242
254
  selectionRange,
255
+ splitPoints,
243
256
  durationMs,
244
257
  activityRanges,
245
258
  ]);
@@ -6,6 +6,7 @@ import {
6
6
  IconFolderPlus,
7
7
  IconTrash,
8
8
  IconEdit,
9
+ IconDots,
9
10
  } from "@tabler/icons-react";
10
11
  import { useMemo, useState } from "react";
11
12
  import { NavLink } from "react-router";
@@ -33,6 +34,13 @@ import {
33
34
  ContextMenuSeparator,
34
35
  ContextMenuTrigger,
35
36
  } from "@/components/ui/context-menu";
37
+ import {
38
+ DropdownMenu,
39
+ DropdownMenuContent,
40
+ DropdownMenuItem,
41
+ DropdownMenuSeparator,
42
+ DropdownMenuTrigger,
43
+ } from "@/components/ui/dropdown-menu";
36
44
  import {
37
45
  useCreateFolder,
38
46
  useDeleteFolder,
@@ -186,6 +194,50 @@ function FolderItem({
186
194
  {node.name}
187
195
  </span>
188
196
  </NavLink>
197
+ <DropdownMenu>
198
+ <DropdownMenuTrigger asChild>
199
+ <button
200
+ type="button"
201
+ aria-label={`${node.name}: ${t("root.commandActions")}`}
202
+ title={`${node.name}: ${t("root.commandActions")}`}
203
+ className="rounded p-0.5 text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100"
204
+ >
205
+ <IconDots className="h-3.5 w-3.5" />
206
+ </button>
207
+ </DropdownMenuTrigger>
208
+ <DropdownMenuContent align="start" side="right">
209
+ <DropdownMenuItem
210
+ onSelect={() => {
211
+ setTimeout(() => {
212
+ setRenameValue(node.name);
213
+ setRenameOpen(true);
214
+ }, 0);
215
+ }}
216
+ >
217
+ <IconEdit className="h-3.5 w-3.5 me-2" />{" "}
218
+ {t("folderTree.rename")}
219
+ </DropdownMenuItem>
220
+ <DropdownMenuItem
221
+ onSelect={() => {
222
+ setTimeout(() => {
223
+ setNewValue("");
224
+ setNewOpen(true);
225
+ }, 0);
226
+ }}
227
+ >
228
+ <IconFolderPlus className="h-3.5 w-3.5 me-2" />{" "}
229
+ {t("folderTree.newSubfolder")}
230
+ </DropdownMenuItem>
231
+ <DropdownMenuSeparator />
232
+ <DropdownMenuItem
233
+ onSelect={() => setTimeout(() => setConfirmDelete(true), 0)}
234
+ className="text-destructive"
235
+ >
236
+ <IconTrash className="h-3.5 w-3.5 me-2" />{" "}
237
+ {t("folderTree.delete")}
238
+ </DropdownMenuItem>
239
+ </DropdownMenuContent>
240
+ </DropdownMenu>
189
241
  </div>
190
242
  </ContextMenuTrigger>
191
243
  <ContextMenuContent>
@@ -156,7 +156,7 @@ export function SettingsPanel(props: SettingsPanelProps) {
156
156
  <Label className="text-xs">
157
157
  {t("playerSettings.passwordProtection")}
158
158
  </Label>
159
- <div className="flex gap-2 mt-1">
159
+ <div className="mt-1 space-y-2">
160
160
  <Input
161
161
  type="text"
162
162
  value={password}
@@ -166,18 +166,36 @@ export function SettingsPanel(props: SettingsPanelProps) {
166
166
  ? t("playerSettings.passwordSetPlaceholder")
167
167
  : t("playerSettings.noPasswordPlaceholder")
168
168
  }
169
- className="flex-1"
170
169
  />
171
- <Button
172
- variant="outline"
173
- onClick={() => {
174
- patch({ password: password || null });
175
- setPassword("");
176
- }}
177
- disabled={update.isPending}
178
- >
179
- {t("common.save")}
180
- </Button>
170
+ {password.length > 0 && !password.trim() ? (
171
+ <p className="text-xs text-muted-foreground">
172
+ {t("playerSettings.passwordWhitespaceOnly")}
173
+ </p>
174
+ ) : null}
175
+ <div className="flex gap-2">
176
+ <Button
177
+ variant="outline"
178
+ onClick={() => {
179
+ patch({ password: password.trim() });
180
+ setPassword("");
181
+ }}
182
+ disabled={update.isPending || !password.trim()}
183
+ >
184
+ {t("common.save")}
185
+ </Button>
186
+ {recording.hasPassword ? (
187
+ <Button
188
+ variant="outline"
189
+ onClick={() => {
190
+ patch({ password: null });
191
+ setPassword("");
192
+ }}
193
+ disabled={update.isPending}
194
+ >
195
+ {t("playerSettings.removePassword")}
196
+ </Button>
197
+ ) : null}
198
+ </div>
181
199
  </div>
182
200
  </div>
183
201
 
@@ -361,6 +379,7 @@ function CtaEditor({
361
379
  // editing this card, so an agent edit to the CTA shows up live. `editing`
362
380
  // flips true while focus is anywhere inside the card.
363
381
  const editing = useRef(false);
382
+ const [collapsed, setCollapsed] = useState(true);
364
383
  const [label, setLabel] = useReconciledState(cta.label, {
365
384
  active: editing.current,
366
385
  });
@@ -387,52 +406,91 @@ function CtaEditor({
387
406
  }
388
407
  }}
389
408
  >
390
- <Input
391
- value={label}
392
- onChange={(e) => setLabel(e.target.value)}
393
- placeholder={t("playerSettings.buttonLabelPlaceholder")}
394
- />
395
- <Input
396
- value={url}
397
- onChange={(e) => setUrl(e.target.value)}
398
- placeholder="https://…"
399
- />
400
- <div className="flex gap-2">
401
- <input
402
- type="color"
403
- value={color}
404
- onChange={(e) => setColor(e.target.value)}
405
- className="h-9 w-12 rounded cursor-pointer border border-border"
406
- />
407
- <Select
408
- value={placement}
409
- onValueChange={(v) => setPlacement(v as "end" | "throughout")}
410
- >
411
- <SelectTrigger className="flex-1">
412
- <SelectValue />
413
- </SelectTrigger>
414
- <SelectContent>
415
- <SelectItem value="throughout">
416
- {t("playerSettings.placementThroughout")}
417
- </SelectItem>
418
- <SelectItem value="end">
419
- {t("playerSettings.placementEnd")}
420
- </SelectItem>
421
- </SelectContent>
422
- </Select>
423
- </div>
424
- <div className="flex gap-2">
425
- <Button
426
- size="sm"
427
- className="bg-primary hover:bg-primary/90 text-primary-foreground"
428
- onClick={() => onSave({ label, url, color, placement })}
429
- >
430
- {t("common.save")}
431
- </Button>
432
- <Button size="sm" variant="ghost" onClick={onDelete}>
433
- {t("playerSettings.delete")}
434
- </Button>
435
- </div>
409
+ {collapsed ? (
410
+ <div className="flex items-center gap-2">
411
+ <div className="min-w-0 flex-1">
412
+ <p className="truncate text-sm font-medium">{cta.label}</p>
413
+ <p className="text-xs text-muted-foreground">
414
+ {cta.placement === "throughout"
415
+ ? t("playerSettings.placementThroughout")
416
+ : t("playerSettings.placementEnd")}
417
+ </p>
418
+ </div>
419
+ <Button
420
+ type="button"
421
+ size="sm"
422
+ variant="ghost"
423
+ title={t("recordingPage.edit")}
424
+ onClick={() => setCollapsed(false)}
425
+ >
426
+ {t("recordingPage.edit")}
427
+ </Button>
428
+ <Button type="button" size="sm" variant="ghost" onClick={onDelete}>
429
+ {t("playerSettings.delete")}
430
+ </Button>
431
+ </div>
432
+ ) : (
433
+ <>
434
+ <Input
435
+ value={label}
436
+ onChange={(e) => setLabel(e.target.value)}
437
+ placeholder={t("playerSettings.buttonLabelPlaceholder")}
438
+ />
439
+ <Input
440
+ value={url}
441
+ onChange={(e) => setUrl(e.target.value)}
442
+ placeholder="https://…"
443
+ />
444
+ <div className="flex gap-2">
445
+ <input
446
+ type="color"
447
+ value={color}
448
+ onChange={(e) => setColor(e.target.value)}
449
+ className="h-9 w-12 rounded cursor-pointer border border-border"
450
+ />
451
+ <Select
452
+ value={placement}
453
+ onValueChange={(v) => setPlacement(v as "end" | "throughout")}
454
+ >
455
+ <SelectTrigger className="flex-1">
456
+ <SelectValue />
457
+ </SelectTrigger>
458
+ <SelectContent>
459
+ <SelectItem value="throughout">
460
+ {t("playerSettings.placementThroughout")}
461
+ </SelectItem>
462
+ <SelectItem value="end">
463
+ {t("playerSettings.placementEnd")}
464
+ </SelectItem>
465
+ </SelectContent>
466
+ </Select>
467
+ </div>
468
+ <div className="flex gap-2">
469
+ <Button
470
+ type="button"
471
+ size="sm"
472
+ className="bg-primary text-primary-foreground hover:bg-primary/90"
473
+ onClick={() => {
474
+ onSave({ label, url, color, placement });
475
+ setCollapsed(true);
476
+ }}
477
+ >
478
+ {t("common.save")}
479
+ </Button>
480
+ <Button
481
+ type="button"
482
+ size="sm"
483
+ variant="ghost"
484
+ onClick={() => setCollapsed(true)}
485
+ >
486
+ {t("recordingPage.done")}
487
+ </Button>
488
+ <Button type="button" size="sm" variant="ghost" onClick={onDelete}>
489
+ {t("playerSettings.delete")}
490
+ </Button>
491
+ </div>
492
+ </>
493
+ )}
436
494
  </div>
437
495
  );
438
496
  }
@@ -380,49 +380,55 @@ function LinkTab({
380
380
  )}
381
381
 
382
382
  <CopyField
383
- label={t("shareDialog.shareWithHumans")}
383
+ label={
384
+ isPublic
385
+ ? t("shareDialog.shareLink")
386
+ : t("shareDialog.shareWithHumans")
387
+ }
384
388
  value={shareUrl}
385
389
  disabled={
386
390
  visibilityPending || !sharesLoaded || (!isPublic && canManage)
387
391
  }
388
392
  />
389
393
 
390
- <div className="space-y-2">
391
- <CopyField
392
- label={t("shareDialog.shareWithAgents")}
393
- value={agentLink}
394
- disabled={agentShareDisabled}
395
- />
396
- {sharesLoaded && !isPublic ? (
397
- <>
398
- <p className="text-xs text-muted-foreground">
399
- {t("shareDialog.agentTokenDescription")}
400
- </p>
401
- {agentLinkError ? (
402
- <div className="flex items-center justify-between gap-2 rounded-md border border-border bg-muted/30 px-3 py-2">
403
- <p className="text-xs text-muted-foreground">
404
- {t("shareDialog.agentLinkUnavailable")}
405
- </p>
406
- <Button
407
- type="button"
408
- variant="ghost"
409
- size="sm"
410
- className="h-7"
411
- onClick={() => void loadAgentContextUrl()}
412
- disabled={createAgentLink.isPending}
413
- >
414
- {t("shareDialog.retryAgentLink")}
415
- </Button>
416
- </div>
417
- ) : null}
418
- <CopyField
419
- label={t("shareDialog.copyAgentPrompt")}
420
- value={agentPrompt}
421
- disabled={agentShareDisabled}
422
- />
423
- </>
424
- ) : null}
425
- </div>
394
+ {!isPublic ? (
395
+ <div className="space-y-2">
396
+ <CopyField
397
+ label={t("shareDialog.shareWithAgents")}
398
+ value={agentLink}
399
+ disabled={agentShareDisabled}
400
+ />
401
+ {sharesLoaded ? (
402
+ <>
403
+ <p className="text-xs text-muted-foreground">
404
+ {t("shareDialog.agentTokenDescription")}
405
+ </p>
406
+ {agentLinkError ? (
407
+ <div className="flex items-center justify-between gap-2 rounded-md border border-border bg-muted/30 px-3 py-2">
408
+ <p className="text-xs text-muted-foreground">
409
+ {t("shareDialog.agentLinkUnavailable")}
410
+ </p>
411
+ <Button
412
+ type="button"
413
+ variant="ghost"
414
+ size="sm"
415
+ className="h-7"
416
+ onClick={() => void loadAgentContextUrl()}
417
+ disabled={createAgentLink.isPending}
418
+ >
419
+ {t("shareDialog.retryAgentLink")}
420
+ </Button>
421
+ </div>
422
+ ) : null}
423
+ <CopyField
424
+ label={t("shareDialog.copyAgentPrompt")}
425
+ value={agentPrompt}
426
+ disabled={agentShareDisabled}
427
+ />
428
+ </>
429
+ ) : null}
430
+ </div>
431
+ ) : null}
426
432
 
427
433
  {sharesLoaded && !isPublic && canManage ? (
428
434
  <MakePublicCard
@@ -592,6 +592,14 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
592
592
  pauseVideo();
593
593
  return;
594
594
  }
595
+ if (v.ended) {
596
+ try {
597
+ v.currentTime = 0;
598
+ setCurrentMs(0);
599
+ } catch {
600
+ // Let the normal play attempt report a media error if the seek fails.
601
+ }
602
+ }
595
603
  requestPlay();
596
604
  }, [isPlaying, pauseVideo, requestPlay]);
597
605
 
@@ -671,7 +679,10 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
671
679
  (isPlaying || playAttemptPendingRef.current || !v.paused),
672
680
  );
673
681
 
674
- if (v) v.playbackRate = nextSpeed;
682
+ if (v) {
683
+ v.defaultPlaybackRate = nextSpeed;
684
+ v.playbackRate = nextSpeed;
685
+ }
675
686
  setSpeed(nextSpeed);
676
687
  savePlaybackSpeedPreference(nextSpeed);
677
688
  onSpeedChange?.(nextSpeed);
@@ -770,6 +781,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
770
781
  const v = videoRef.current;
771
782
  if (!v) return;
772
783
  const initialSpeed = readPlaybackSpeedPreference(defaultSpeed);
784
+ v.defaultPlaybackRate = initialSpeed;
773
785
  v.playbackRate = initialSpeed;
774
786
  setSpeed(initialSpeed);
775
787
  onSpeedChange?.(initialSpeed);
@@ -1423,6 +1435,21 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
1423
1435
  </div>
1424
1436
  )}
1425
1437
 
1438
+ {thumbnailUrl &&
1439
+ !autoPlay &&
1440
+ !hasPlaybackStarted &&
1441
+ (!startMs || startMs <= 0) ? (
1442
+ <img
1443
+ src={resolveLocalUrl(thumbnailUrl)}
1444
+ alt=""
1445
+ aria-hidden="true"
1446
+ className={cn(
1447
+ "pointer-events-none absolute inset-0 z-[1] h-full w-full",
1448
+ cover ? "object-cover" : "object-contain",
1449
+ )}
1450
+ />
1451
+ ) : null}
1452
+
1426
1453
  {centerOverlayMode ? (
1427
1454
  <CenterPlaybackOverlay
1428
1455
  mode={centerOverlayMode}
@@ -1462,7 +1489,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
1462
1489
 
1463
1490
  {/* Floating CTA (throughout placement) */}
1464
1491
  {showThroughoutCta ? (
1465
- <div data-player-ui className="absolute bottom-16 right-4 z-20">
1492
+ <div data-player-ui className="absolute bottom-16 right-4 z-30">
1466
1493
  <CtaButton
1467
1494
  cta={cta!}
1468
1495
  onClick={() => onCtaClick?.(cta!.id)}
@@ -1484,6 +1511,27 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
1484
1511
  onClick={() => onCtaClick?.(cta!.id)}
1485
1512
  large
1486
1513
  />
1514
+ <button
1515
+ type="button"
1516
+ data-player-ui
1517
+ aria-label={t("videoPlayer.playClip")}
1518
+ onClick={(e) => {
1519
+ e.stopPropagation();
1520
+ const v = videoRef.current;
1521
+ if (!v) return;
1522
+ try {
1523
+ v.currentTime = 0;
1524
+ setCurrentMs(0);
1525
+ } catch {
1526
+ // The regular play path will surface any media error.
1527
+ }
1528
+ requestPlay();
1529
+ }}
1530
+ className="pointer-events-auto inline-flex items-center gap-2 rounded-md border border-white/30 bg-white/10 px-3 py-2 text-sm font-medium text-white transition-colors hover:bg-white/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white"
1531
+ >
1532
+ <IconPlayerPlay className="h-4 w-4 fill-current" />
1533
+ {t("videoPlayer.playClip")}
1534
+ </button>
1487
1535
  </div>
1488
1536
  </div>
1489
1537
  ) : null}
@@ -41,6 +41,26 @@ function stopStream(stream: MediaStream | null): void {
41
41
 
42
42
  type MicrophonePermissionState = PermissionState | "unknown";
43
43
 
44
+ function isDesktopShell(): boolean {
45
+ if (typeof window === "undefined") return false;
46
+ const w = window as typeof window & {
47
+ electronAPI?: unknown;
48
+ __TAURI_INTERNALS__?: unknown;
49
+ __TAURI__?: unknown;
50
+ };
51
+ if (w.electronAPI || w.__TAURI_INTERNALS__ || w.__TAURI__) return true;
52
+ return (
53
+ typeof navigator !== "undefined" && /Electron/i.test(navigator.userAgent)
54
+ );
55
+ }
56
+
57
+ function micBlockedMessage(): string {
58
+ if (isDesktopShell()) {
59
+ return "Microphone access is blocked for this app. Enable the microphone for the app in your system Privacy settings, then reopen the recorder.";
60
+ }
61
+ return "Your browser has blocked microphone access for this site, so it won't prompt. Allow the microphone in this site's settings, then reload.";
62
+ }
63
+
44
64
  function isMicrophoneBlockedByPolicy(): boolean {
45
65
  const policy =
46
66
  (
@@ -96,7 +116,7 @@ export async function friendlyMicError(err: unknown): Promise<string> {
96
116
  return "Microphone prompts require HTTPS or localhost. Open this app on localhost or an HTTPS URL, then try again.";
97
117
  }
98
118
  if (permissionState === "denied") {
99
- return "This site is blocked from using the microphone. Open the browser site settings, set Microphone to Allow, then reload.";
119
+ return micBlockedMessage();
100
120
  }
101
121
  if (/NotAllowedError|Permission denied|denied|blocked/i.test(combined)) {
102
122
  return "The browser or operating system denied microphone access. Check this site's microphone setting and your system privacy settings for this browser, then reload.";
@@ -328,8 +348,7 @@ export function MicrophoneVisualizer({
328
348
  const permissionState = await getMicrophonePermissionState();
329
349
  if (runIdRef.current !== runId) return;
330
350
  if (permissionState === "denied") {
331
- const message =
332
- "Brave already has Microphone set to Block for this site, so it will not show the popup. Click the lock/tune icon in the address bar → Site settings → Microphone → Allow, then reload.";
351
+ const message = micBlockedMessage();
333
352
  setError(message);
334
353
  setStatus("error");
335
354
  onStatusChange?.("error", { error: message });
@@ -455,6 +455,8 @@ const messages = {
455
455
  retryAgentLink: "إعادة المحاولة",
456
456
  gifPreview: "معاينة GIF",
457
457
  openPlayer: "مشغل مفتوح",
458
+ chooseFile: "اختيار ملف",
459
+ remove: "إزالة",
458
460
  downloadMp4: "تحميل MP4",
459
461
  embedsNeedPublic: "التضمينات تحتاج إلى مقطع عام",
460
462
  embedPublicDescription:
@@ -1225,9 +1227,10 @@ const messages = {
1225
1227
  visibilityOrg: "Organization (مترجم)",
1226
1228
  visibilityPublic: "Public (مترجم)",
1227
1229
  passwordProtection: "Password protection (مترجم)",
1228
- passwordSetPlaceholder:
1229
- "Password is set — type to replace, leave empty + Save to clear (مترجم)",
1230
+ passwordSetPlaceholder: "Password is set — type to replace (مترجم)",
1230
1231
  noPasswordPlaceholder: "No password (مترجم)",
1232
+ passwordWhitespaceOnly: "Spaces alone aren't a valid password. (مترجم)",
1233
+ removePassword: "Remove (مترجم)",
1231
1234
  expiry: "Expiry (مترجم)",
1232
1235
  viewerOptions: "Viewer options (مترجم)",
1233
1236
  comments: "Comments (مترجم)",
@@ -468,6 +468,8 @@ const messages = {
468
468
  retryAgentLink: "Erneut versuchen",
469
469
  gifPreview: "GIF-Vorschau",
470
470
  openPlayer: "Spieler öffnen",
471
+ chooseFile: "Datei auswählen",
472
+ remove: "Entfernen",
471
473
  downloadMp4: "Laden Sie MP4 herunter",
472
474
  embedsNeedPublic: "Für Einbettungen ist ein öffentlicher Clip erforderlich",
473
475
  embedPublicDescription:
@@ -1251,9 +1253,11 @@ Alle sichtbaren Änderungen für Clips-Nutzer werden hier dokumentiert. Du kanns
1251
1253
  visibilityOrg: "Organization (Lokalisiert)",
1252
1254
  visibilityPublic: "Public (Lokalisiert)",
1253
1255
  passwordProtection: "Password protection (Lokalisiert)",
1254
- passwordSetPlaceholder:
1255
- "Password is set — type to replace, leave empty + Save to clear (Lokalisiert)",
1256
+ passwordSetPlaceholder: "Password is set — type to replace (Lokalisiert)",
1256
1257
  noPasswordPlaceholder: "No password (Lokalisiert)",
1258
+ passwordWhitespaceOnly:
1259
+ "Spaces alone aren't a valid password. (Lokalisiert)",
1260
+ removePassword: "Remove (Lokalisiert)",
1257
1261
  expiry: "Expiry (Lokalisiert)",
1258
1262
  viewerOptions: "Viewer options (Lokalisiert)",
1259
1263
  comments: "Comments (Lokalisiert)",