auricui-skill 0.0.0-stage → 0.1.2

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 (362) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -2
  3. package/bin/install.mjs +66 -0
  4. package/package.json +29 -4
  5. package/skill/SKILL.md +64 -0
  6. package/skill/agents/openai.yaml +4 -0
  7. package/skill/assets/examples/ApprovalCard.tsx +8 -0
  8. package/skill/assets/examples/BasicApp.tsx +38 -0
  9. package/skill/assets/examples/BriefingCard.tsx +8 -0
  10. package/skill/assets/examples/ChatControls.tsx +49 -0
  11. package/skill/assets/examples/ChatPanel.tsx +73 -0
  12. package/skill/assets/examples/Checkbox.tsx +13 -0
  13. package/skill/assets/examples/Combobox.tsx +14 -0
  14. package/skill/assets/examples/Drawer.tsx +10 -0
  15. package/skill/assets/examples/MemoryCard.tsx +9 -0
  16. package/skill/assets/examples/MessageList.tsx +8 -0
  17. package/skill/assets/examples/Theme.tsx +14 -0
  18. package/skill/assets/examples/ToolCall.tsx +8 -0
  19. package/skill/assets/examples/Tree.tsx +15 -0
  20. package/skill/assets/examples/examples.css +11 -0
  21. package/skill/assets/library/auricui-0.1.0-preview.1.tgz +0 -0
  22. package/skill/assets/library/auricui-0.1.0-preview.3.tgz +0 -0
  23. package/skill/assets/library/auricui-0.1.0-preview.4.tgz +0 -0
  24. package/skill/assets/upstream/LICENSE +21 -0
  25. package/skill/assets/upstream/apps/desktop/chat/src/App.tsx +1099 -0
  26. package/skill/assets/upstream/apps/desktop/chat/src/app-bridge.ts +154 -0
  27. package/skill/assets/upstream/apps/desktop/chat/src/chat.css +1812 -0
  28. package/skill/assets/upstream/apps/desktop/chat/src/components/AddSkill.tsx +223 -0
  29. package/skill/assets/upstream/apps/desktop/chat/src/components/AgentActivityRow.tsx +716 -0
  30. package/skill/assets/upstream/apps/desktop/chat/src/components/AgentIcons.tsx +46 -0
  31. package/skill/assets/upstream/apps/desktop/chat/src/components/AttachmentCard.tsx +34 -0
  32. package/skill/assets/upstream/apps/desktop/chat/src/components/AttachmentPreview.tsx +331 -0
  33. package/skill/assets/upstream/apps/desktop/chat/src/components/BalanceNotice.tsx +22 -0
  34. package/skill/assets/upstream/apps/desktop/chat/src/components/BrandLogo.tsx +35 -0
  35. package/skill/assets/upstream/apps/desktop/chat/src/components/ComposerCard.tsx +182 -0
  36. package/skill/assets/upstream/apps/desktop/chat/src/components/ConversationSessionBar.tsx +292 -0
  37. package/skill/assets/upstream/apps/desktop/chat/src/components/CopyDiagnostics.tsx +24 -0
  38. package/skill/assets/upstream/apps/desktop/chat/src/components/Divider.tsx +47 -0
  39. package/skill/assets/upstream/apps/desktop/chat/src/components/FileChangesList.tsx +119 -0
  40. package/skill/assets/upstream/apps/desktop/chat/src/components/Markdown.tsx +198 -0
  41. package/skill/assets/upstream/apps/desktop/chat/src/components/ModelPopover.tsx +280 -0
  42. package/skill/assets/upstream/apps/desktop/chat/src/components/NoticeCard.tsx +87 -0
  43. package/skill/assets/upstream/apps/desktop/chat/src/components/Popover.tsx +195 -0
  44. package/skill/assets/upstream/apps/desktop/chat/src/components/PreviewFrame.tsx +129 -0
  45. package/skill/assets/upstream/apps/desktop/chat/src/components/ProjectConversation.tsx +852 -0
  46. package/skill/assets/upstream/apps/desktop/chat/src/components/ProjectStarters.tsx +118 -0
  47. package/skill/assets/upstream/apps/desktop/chat/src/components/Tooltip.tsx +191 -0
  48. package/skill/assets/upstream/apps/desktop/chat/src/components/TurnLog.tsx +583 -0
  49. package/skill/assets/upstream/apps/desktop/chat/src/components/TurnQuestionCard.tsx +133 -0
  50. package/skill/assets/upstream/apps/desktop/chat/src/components/dock-pane-bar.ts +14 -0
  51. package/skill/assets/upstream/apps/desktop/chat/src/components/project-version.ts +37 -0
  52. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/MentionMenuPlugin.tsx +372 -0
  53. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptEditor.tsx +476 -0
  54. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptPill.tsx +399 -0
  55. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/PromptReferenceNode.tsx +164 -0
  56. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/index.ts +31 -0
  57. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/mention-menu.ts +206 -0
  58. package/skill/assets/upstream/apps/desktop/chat/src/components/prompt-editor/prompt-text.ts +171 -0
  59. package/skill/assets/upstream/apps/desktop/chat/src/components/useStickToBottom.ts +320 -0
  60. package/skill/assets/upstream/apps/desktop/chat/src/components/useTicker.ts +55 -0
  61. package/skill/assets/upstream/apps/desktop/chat/src/i18n/index.ts +42 -0
  62. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/en-US.ts +408 -0
  63. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/es.ts +407 -0
  64. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/ja.ts +407 -0
  65. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/ko.ts +403 -0
  66. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/words.ts +6 -0
  67. package/skill/assets/upstream/apps/desktop/chat/src/i18n/locales/zh-CN.ts +407 -0
  68. package/skill/assets/upstream/apps/desktop/chat/src/i18n/lookup.ts +12 -0
  69. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-activity-runs.ts +154 -0
  70. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-menu-rows.ts +41 -0
  71. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-refs.ts +105 -0
  72. package/skill/assets/upstream/apps/desktop/chat/src/lib/agent-transcript.ts +440 -0
  73. package/skill/assets/upstream/apps/desktop/chat/src/lib/asset-lists.ts +75 -0
  74. package/skill/assets/upstream/apps/desktop/chat/src/lib/attachment-place.ts +17 -0
  75. package/skill/assets/upstream/apps/desktop/chat/src/lib/balance.ts +16 -0
  76. package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-layer.ts +10 -0
  77. package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-menu.ts +18 -0
  78. package/skill/assets/upstream/apps/desktop/chat/src/lib/chat-store.ts +101 -0
  79. package/skill/assets/upstream/apps/desktop/chat/src/lib/composer-attachments.ts +189 -0
  80. package/skill/assets/upstream/apps/desktop/chat/src/lib/desktop-attachments.ts +178 -0
  81. package/skill/assets/upstream/apps/desktop/chat/src/lib/desktop-bridge.ts +291 -0
  82. package/skill/assets/upstream/apps/desktop/chat/src/lib/developer.ts +39 -0
  83. package/skill/assets/upstream/apps/desktop/chat/src/lib/esc-stop.ts +23 -0
  84. package/skill/assets/upstream/apps/desktop/chat/src/lib/file-changes.ts +32 -0
  85. package/skill/assets/upstream/apps/desktop/chat/src/lib/live-activity.ts +20 -0
  86. package/skill/assets/upstream/apps/desktop/chat/src/lib/local-agent-run.ts +1174 -0
  87. package/skill/assets/upstream/apps/desktop/chat/src/lib/local-sessions.ts +25 -0
  88. package/skill/assets/upstream/apps/desktop/chat/src/lib/model-calls.ts +87 -0
  89. package/skill/assets/upstream/apps/desktop/chat/src/lib/pretty-json.ts +12 -0
  90. package/skill/assets/upstream/apps/desktop/chat/src/lib/preview-top.ts +15 -0
  91. package/skill/assets/upstream/apps/desktop/chat/src/lib/project-resources.ts +66 -0
  92. package/skill/assets/upstream/apps/desktop/chat/src/lib/project-sessions.ts +66 -0
  93. package/skill/assets/upstream/apps/desktop/chat/src/lib/project-versions.ts +116 -0
  94. package/skill/assets/upstream/apps/desktop/chat/src/lib/ref-pictures.ts +119 -0
  95. package/skill/assets/upstream/apps/desktop/chat/src/lib/relative-time.ts +46 -0
  96. package/skill/assets/upstream/apps/desktop/chat/src/lib/skill-pages.ts +29 -0
  97. package/skill/assets/upstream/apps/desktop/chat/src/lib/step-file.ts +23 -0
  98. package/skill/assets/upstream/apps/desktop/chat/src/lib/structural-share.ts +52 -0
  99. package/skill/assets/upstream/apps/desktop/chat/src/lib/studio-film.ts +44 -0
  100. package/skill/assets/upstream/apps/desktop/chat/src/lib/studio-transfer.ts +40 -0
  101. package/skill/assets/upstream/apps/desktop/chat/src/lib/unprompted.ts +27 -0
  102. package/skill/assets/upstream/apps/desktop/chat/src/lib/upload-limits.ts +53 -0
  103. package/skill/assets/upstream/apps/desktop/chat/src/mount.tsx +19 -0
  104. package/skill/assets/upstream/apps/desktop/chat/src/state/local-agent-store.ts +296 -0
  105. package/skill/assets/upstream/apps/desktop/chat/src/studio-refs.ts +307 -0
  106. package/skill/assets/upstream/apps/desktop/package.json +51 -0
  107. package/skill/assets/upstream/apps/desktop/shell/bridge.ts +415 -0
  108. package/skill/assets/upstream/apps/desktop/shell/index.html +27 -0
  109. package/skill/assets/upstream/apps/desktop/shell/main.tsx +17 -0
  110. package/skill/assets/upstream/apps/desktop/shell/shell.css +17 -0
  111. package/skill/assets/upstream/apps/desktop/shell/vite.config.ts +65 -0
  112. package/skill/assets/upstream/apps/desktop/src/agent-definitions.mjs +31 -0
  113. package/skill/assets/upstream/packages/openfilm/LICENSE +21 -0
  114. package/skill/assets/upstream/packages/openfilm/package.json +88 -0
  115. package/skill/assets/upstream/packages/openfilm/src/film-doc.d.mts +125 -0
  116. package/skill/assets/upstream/packages/openfilm/src/film-doc.mjs +986 -0
  117. package/skill/assets/upstream/packages/openfilm/src/overrides.mjs +73 -0
  118. package/skill/assets/upstream/packages/openfilm/src/timeline.mjs +1280 -0
  119. package/skill/assets/upstream/packages/openfilm/studio/server/bridge.js +209 -0
  120. package/skill/assets/upstream/packages/openfilm/studio/server/film-subtitle.mjs +785 -0
  121. package/skill/assets/upstream/packages/openfilm/studio/server/ops.mjs +403 -0
  122. package/skill/assets/upstream/packages/openfilm/studio/server/stage.js +1649 -0
  123. package/skill/assets/upstream/packages/openfilm/studio/server/track-layout.mjs +43 -0
  124. package/skill/assets/upstream/packages/openfilm/studio/ui/src/App.tsx +156 -0
  125. package/skill/assets/upstream/packages/openfilm/studio/ui/src/api.ts +328 -0
  126. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/AudioMeters.tsx +188 -0
  127. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BlockThumbs.tsx +84 -0
  128. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BlockWaveform.tsx +201 -0
  129. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BrandLoadingScreen.tsx +56 -0
  130. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/BrandLogo.tsx +25 -0
  131. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Card.tsx +89 -0
  132. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ColorPicker.tsx +204 -0
  133. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ConfirmDialog.tsx +96 -0
  134. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ContextMenu.tsx +422 -0
  135. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/DesktopDialog.tsx +271 -0
  136. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ExamplesGallery.tsx +372 -0
  137. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmFullscreenBar.tsx +147 -0
  138. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmInspector.tsx +2310 -0
  139. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FilmStageSelect.tsx +3296 -0
  140. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FocusNav.tsx +28 -0
  141. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FontFamilyPicker.tsx +293 -0
  142. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/FramePicker.tsx +69 -0
  143. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/InspectorPanel.tsx +25 -0
  144. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Launcher.tsx +38 -0
  145. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/LayersPanel.tsx +277 -0
  146. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/LiveTime.tsx +101 -0
  147. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MediaPool.tsx +1413 -0
  148. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MediaPreview.tsx +188 -0
  149. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MenuSelect.tsx +161 -0
  150. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/MgOutline.tsx +24 -0
  151. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/OperationHistory.tsx +184 -0
  152. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PaneDivider.tsx +292 -0
  153. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PasteAttrsDialog.tsx +69 -0
  154. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PlaybackMenu.tsx +110 -0
  155. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Popover.tsx +159 -0
  156. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectCover.tsx +60 -0
  157. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectHistoryControls.tsx +748 -0
  158. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectLayoutMenu.tsx +82 -0
  159. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectMenu.tsx +111 -0
  160. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectSources.tsx +587 -0
  161. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectView.tsx +3222 -0
  162. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectsLibrary.tsx +567 -0
  163. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ProjectsView.tsx +1593 -0
  164. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/PropertiesSection.tsx +418 -0
  165. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ResourceInspector.tsx +100 -0
  166. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SelectionToolbar.tsx +157 -0
  167. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SkillsLibrary.tsx +504 -0
  168. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SourcePreview.tsx +464 -0
  169. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SpendAsks.tsx +88 -0
  170. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/StageMaskOverlay.tsx +299 -0
  171. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/StageTransformFrame.tsx +246 -0
  172. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleInspector.module.css +46 -0
  173. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleInspector.tsx +884 -0
  174. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleOverlay.tsx +148 -0
  175. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/SubtitleRow.tsx +419 -0
  176. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/TabStrip.tsx +188 -0
  177. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Timeline.tsx +4911 -0
  178. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/TimelineMarkers.tsx +329 -0
  179. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Toast.tsx +55 -0
  180. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/Tooltip.tsx +193 -0
  181. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/UpdateButton.tsx +104 -0
  182. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/ViewerBar.tsx +98 -0
  183. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/WhatsNew.tsx +147 -0
  184. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/dock-pane-bar.ts +16 -0
  185. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/export/ExportCenter.tsx +1502 -0
  186. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/export/ExportTray.tsx +284 -0
  187. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/film-stage-hit.ts +18 -0
  188. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/inspector-fields.tsx +863 -0
  189. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/inspector-look.tsx +1357 -0
  190. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/player-controls/controls-bar.tsx +397 -0
  191. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/player-controls/transport.tsx +294 -0
  192. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/replace-drop.ts +20 -0
  193. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/AgentsSection.tsx +613 -0
  194. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/CustomServices.tsx +104 -0
  195. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/DiagnosticsGroup.tsx +202 -0
  196. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ModelsSection.tsx +179 -0
  197. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ProviderMark.tsx +24 -0
  198. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ProvidersSection.tsx +177 -0
  199. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/SettingsModal.tsx +511 -0
  200. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/SettingsSelect.tsx +84 -0
  201. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ShortcutsSection.tsx +291 -0
  202. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/StorageGroup.tsx +119 -0
  203. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/theme.ts +47 -0
  204. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/ui.tsx +139 -0
  205. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/settings/use-settings.ts +10 -0
  206. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/stage-menu.tsx +283 -0
  207. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/timeline-head-extras.tsx +91 -0
  208. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/typing-target.ts +45 -0
  209. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-editor-tools.tsx +408 -0
  210. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-page-changes.ts +48 -0
  211. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/use-project-history.ts +113 -0
  212. package/skill/assets/upstream/packages/openfilm/studio/ui/src/components/useBlockDrag.ts +639 -0
  213. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/Preview.tsx +426 -0
  214. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/player.ts +558 -0
  215. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/preview-frames.ts +36 -0
  216. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/steps.ts +36 -0
  217. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/undo.ts +156 -0
  218. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/use-film.ts +212 -0
  219. package/skill/assets/upstream/packages/openfilm/studio/ui/src/editor/use-preview-renders.ts +89 -0
  220. package/skill/assets/upstream/packages/openfilm/studio/ui/src/globals.css +559 -0
  221. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/en.ts +1901 -0
  222. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/es.ts +1900 -0
  223. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/index.ts +130 -0
  224. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/ja.ts +1900 -0
  225. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/ko.ts +1896 -0
  226. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/words.ts +6 -0
  227. package/skill/assets/upstream/packages/openfilm/studio/ui/src/i18n/zh-CN.ts +1901 -0
  228. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/agent-row.ts +21 -0
  229. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/asset-timeline.ts +469 -0
  230. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/audio-levels.ts +60 -0
  231. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/batch-map.ts +28 -0
  232. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/browser.ts +10 -0
  233. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/canvas-fit.ts +116 -0
  234. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/chat-marks.ts +114 -0
  235. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-attrs.ts +102 -0
  236. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-fade.ts +70 -0
  237. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-look.ts +520 -0
  238. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-mask.ts +536 -0
  239. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/clip-replace.ts +60 -0
  240. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/component-props.ts +128 -0
  241. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/context-length.ts +12 -0
  242. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/desktop-build.ts +44 -0
  243. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/diagnostics.ts +68 -0
  244. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/double-press.ts +22 -0
  245. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/dropped-overrides.ts +139 -0
  246. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/export-jobs.ts +191 -0
  247. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/export-spec.ts +261 -0
  248. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/field-input.ts +155 -0
  249. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-clip-edits.ts +82 -0
  250. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-frame.ts +134 -0
  251. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-overrides.ts +107 -0
  252. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film-shape.ts +172 -0
  253. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/film.ts +80 -0
  254. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/font-menu.ts +236 -0
  255. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/font-styles.ts +129 -0
  256. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/freeze-frame.ts +49 -0
  257. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/host.ts +438 -0
  258. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/inspect-scrub.ts +26 -0
  259. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/keymap-store.ts +74 -0
  260. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/keymap.ts +529 -0
  261. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/layers-tree.ts +133 -0
  262. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/look.ts +83 -0
  263. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/loudness.ts +58 -0
  264. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/markers.ts +152 -0
  265. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-bar.ts +58 -0
  266. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-folders.ts +45 -0
  267. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-place.ts +102 -0
  268. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-queue.ts +107 -0
  269. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/media-selection.ts +64 -0
  270. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/menu-position.ts +77 -0
  271. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/mg-transform.ts +111 -0
  272. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/mixed.ts +3 -0
  273. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/page-changes.ts +45 -0
  274. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/picture-files.ts +19 -0
  275. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/preview-prefs.ts +46 -0
  276. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/preview-renders.ts +71 -0
  277. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-delete.ts +20 -0
  278. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-folders.ts +144 -0
  279. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-history.ts +188 -0
  280. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/project-sources.ts +283 -0
  281. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/projects-page.ts +40 -0
  282. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/provider-marks.ts +35 -0
  283. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/providers.ts +163 -0
  284. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/resource-drag.ts +131 -0
  285. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/retry-image.ts +17 -0
  286. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/saved-insert.ts +40 -0
  287. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/saved.ts +125 -0
  288. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/selection-toolbar.ts +158 -0
  289. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/shortcut-hint.ts +21 -0
  290. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/similar-layers.ts +46 -0
  291. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/solo.ts +19 -0
  292. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-clip.ts +60 -0
  293. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-crop.ts +232 -0
  294. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-gesture.ts +277 -0
  295. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-layers.ts +71 -0
  296. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-mask.ts +176 -0
  297. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-measure.ts +53 -0
  298. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/stage-types.ts +155 -0
  299. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/studio-refs.ts +248 -0
  300. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/studio-version.ts +41 -0
  301. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/subtitle-cues.ts +238 -0
  302. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/subtitles.ts +263 -0
  303. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/tab-menu.ts +6 -0
  304. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/template-controls.ts +131 -0
  305. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/theme-changes.ts +31 -0
  306. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-cache.ts +63 -0
  307. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-cell.ts +8 -0
  308. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-frame.ts +76 -0
  309. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/thumb-pick.ts +42 -0
  310. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timecode.ts +161 -0
  311. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-clipboard.ts +279 -0
  312. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-drag.ts +589 -0
  313. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-edit.ts +1138 -0
  314. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-keys.ts +63 -0
  315. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-layout.ts +1038 -0
  316. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-nav.ts +160 -0
  317. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-prefs.ts +73 -0
  318. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-split.ts +40 -0
  319. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/timeline-view.ts +105 -0
  320. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/title.ts +39 -0
  321. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/track-heights.ts +55 -0
  322. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/track-lock.ts +27 -0
  323. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/transitions.ts +459 -0
  324. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/type-metrics.ts +83 -0
  325. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-film-subtitles.ts +111 -0
  326. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-fonts.ts +181 -0
  327. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-loaded-thumbs.ts +91 -0
  328. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-edits.ts +134 -0
  329. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-font.ts +51 -0
  330. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/use-subtitle-style.ts +68 -0
  331. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/waveform-columns.ts +48 -0
  332. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/web-update.ts +41 -0
  333. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/whats-new.ts +401 -0
  334. package/skill/assets/upstream/packages/openfilm/studio/ui/src/lib/workspace-resources.ts +373 -0
  335. package/skill/assets/upstream/packages/openfilm/studio/ui/src/main.tsx +10 -0
  336. package/skill/assets/upstream/packages/openfilm/studio/ui/vite.config.ts +12 -0
  337. package/skill/assets/upstream/packages/shared/package.json +45 -0
  338. package/skill/assets/upstream/packages/shared/src/agent-activity.ts +263 -0
  339. package/skill/assets/upstream/packages/shared/src/contract.ts +285 -0
  340. package/skill/assets/upstream/packages/shared/src/index.ts +17 -0
  341. package/skill/assets/upstream/packages/shared/src/markdown-blocks.ts +252 -0
  342. package/skill/assets/upstream/packages/shared/src/modality.ts +4 -0
  343. package/skill/assets/upstream/packages/shared/src/prompt-reference.ts +113 -0
  344. package/skill/assets/upstream/packages/shared/src/title.ts +76 -0
  345. package/skill/assets/upstream/packages/shared/src/turn.ts +68 -0
  346. package/skill/assets/upstream/packages/shared/src/video.ts +26 -0
  347. package/skill/references/agent-components.md +33 -0
  348. package/skill/references/api-index.json +2693 -0
  349. package/skill/references/chat-components.md +65 -0
  350. package/skill/references/components.md +23 -0
  351. package/skill/references/core-components.md +44 -0
  352. package/skill/references/dependencies.md +22 -0
  353. package/skill/references/esm-package.md +48 -0
  354. package/skill/references/integration.md +43 -0
  355. package/skill/references/library-manifest.json +12 -0
  356. package/skill/references/source-manifest.json +325 -0
  357. package/skill/references/studio-components.md +24 -0
  358. package/skill/references/theme-motion.md +49 -0
  359. package/skill/references/troubleshooting.md +27 -0
  360. package/skill/references/verification.md +13 -0
  361. package/skill/scripts/check_dependencies.py +109 -0
  362. package/skill/scripts/inspect_api.py +60 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Settings → Services, under which service makes each kind of media: the person's custom services. Any service at an
3
+ * address (one they run on this computer, their own voice, an API not listed), with its key and their words on what it
4
+ * does and how it is called (or where its docs are). OpenFilm does not call one itself: their agent reads those words
5
+ * in `openfilm get` and calls it with `openfilm get call` (studio/server/custom-services.mjs).
6
+ */
7
+ import React from 'react';
8
+ import { Plus, Server } from 'lucide-react';
9
+ import { useT } from '@/i18n';
10
+ import type { OwnService, OwnServiceFields, ProvidersHook } from '@/lib/providers';
11
+ import { SettingsButton, SettingsField, SettingsGroup, SettingsInset, SettingsItem, SettingsStatus, settingsError, settingsLink } from './ui';
12
+
13
+ /** Whether the last change that failed was to one of the person's own services (it is said under its form). */
14
+ export const customProblem = (hook: ProvidersHook) => hook.problemFor === 'custom' || Boolean(hook.state?.custom.some((s) => s.id === hook.problemFor));
15
+
16
+ /** The person's own services: each with what it does and how it is called, and a form to add one. */
17
+ export function CustomServices({ hook }: { hook: ProvidersHook }) {
18
+ const t = useT();
19
+ const services = hook.state?.custom ?? [];
20
+ const [open, setOpen] = React.useState<string | null>(null);
21
+ if (!hook.state) return null;
22
+ return (
23
+ <SettingsGroup title={t('settings.providers.own.title')} footnote={t('settings.providers.own.note')}>
24
+ {services.map((service) => (
25
+ <SettingsItem
26
+ key={service.id}
27
+ mark={<Server size={16} />}
28
+ title={service.name}
29
+ badge={service.last4 ? <SettingsStatus tone="muted"><span className="font-mono tabular-nums">•••• {service.last4}</span></SettingsStatus> : null}
30
+ description={(
31
+ <>
32
+ <span className="font-mono text-[13px] text-[var(--text-faint)]">{service.url}</span>
33
+ {service.note ? <span className="mt-0.5 block whitespace-pre-line">{service.note}</span> : null}
34
+ </>
35
+ )}
36
+ control={open === service.id ? null : (
37
+ <>
38
+ <SettingsButton variant="quiet" disabled={hook.busy === service.id} onClick={() => void hook.removeService(service.id)}>{t('settings.providers.own.remove')}</SettingsButton>
39
+ <SettingsButton onClick={() => setOpen(service.id)}>{t('settings.providers.own.edit')}</SettingsButton>
40
+ </>
41
+ )}
42
+ >
43
+ {open === service.id ? <ServiceForm hook={hook} service={service} onDone={() => setOpen(null)} /> : null}
44
+ </SettingsItem>
45
+ ))}
46
+ {open === '' ? (
47
+ <div className="py-4"><ServiceForm hook={hook} service={null} onDone={() => setOpen(null)} /></div>
48
+ ) : (
49
+ <div className="py-4">
50
+ <SettingsButton onClick={() => setOpen('')}><Plus size={15} strokeWidth={2} />{t('settings.providers.own.add')}</SettingsButton>
51
+ </div>
52
+ )}
53
+ </SettingsGroup>
54
+ );
55
+ }
56
+
57
+ /**
58
+ * A service's name, address, key and what it does (how it is called, or its docs): added (`service` null) or changed.
59
+ * Where the key goes is not asked: the agent writes {key} where the service's docs want it, else it goes as
60
+ * `Authorization: Bearer` (a service set up when this was asked keeps its answer).
61
+ */
62
+ function ServiceForm({ hook, service, onDone }: { hook: ProvidersHook; service: OwnService | null; onDone: () => void }) {
63
+ const t = useT();
64
+ const [fields, setFields] = React.useState<OwnServiceFields>({ name: service?.name ?? '', url: service?.url ?? '', note: service?.note ?? '' });
65
+ const [key, setKey] = React.useState('');
66
+ const [dropKey, setDropKey] = React.useState(false);
67
+ const busy = hook.busy === (service?.id ?? 'custom');
68
+ const set = (name: keyof OwnServiceFields) => (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => setFields((f) => ({ ...f, [name]: e.target.value }));
69
+ const save = async () => {
70
+ if (busy || !fields.name.trim() || !fields.url.trim()) return;
71
+ /* changed without a key typed: the one it has stays (unless taken away) */
72
+ const sent: OwnServiceFields = { ...fields, ...(key.trim() ? { key: key.trim() } : dropKey || !service ? { key: '' } : {}) };
73
+ if (await hook.saveService(service?.id ?? null, sent)) onDone();
74
+ };
75
+ const label = (text: string, field: React.ReactNode) => (
76
+ <label className="flex flex-col gap-1.5 text-[13.5px] text-[var(--text-muted)]">{text}{field}</label>
77
+ );
78
+ return (
79
+ /* under its row, it lines up with the row's words; a new one stands on its own */
80
+ <form className={service ? 'pl-[52px]' : ''} onSubmit={(e) => { e.preventDefault(); void save(); }} onKeyDown={(e) => { if (e.key === 'Escape') { e.preventDefault(); onDone(); } }}>
81
+ <SettingsInset>
82
+ {label(t('settings.providers.own.name'), <SettingsField autoFocus value={fields.name} onChange={set('name')} placeholder={t('settings.providers.own.namePlaceholder')} />)}
83
+ {label(t('settings.providers.own.url'), <SettingsField value={fields.url} onChange={set('url')} placeholder="http://localhost:8000" spellCheck={false} className="font-mono placeholder:font-sans" />)}
84
+ {label(t('settings.providers.own.key'), (
85
+ <SettingsField type="password" autoComplete="off" spellCheck={false} value={key} onChange={(e) => { setKey(e.target.value); setDropKey(false); }}
86
+ placeholder={service?.last4 && !dropKey ? t('settings.providers.own.keyKeep').replaceAll('{last4}', service.last4) : t('settings.providers.own.keyOptional')}
87
+ className="font-mono placeholder:font-sans" />
88
+ ))}
89
+ {service?.last4 && !key && !dropKey ? (
90
+ <button type="button" className={`${settingsLink} self-start text-[13.5px]`} onClick={() => setDropKey(true)}>{t('settings.providers.own.removeKey')}</button>
91
+ ) : null}
92
+ {label(t('settings.providers.own.what'), (
93
+ <textarea value={fields.note} onChange={set('note')} rows={4} maxLength={2000} placeholder={t('settings.providers.own.whatPlaceholder')}
94
+ className="w-full min-w-0 resize-y rounded-[8px] border border-[var(--border)] bg-transparent px-3 py-2 text-[14px] leading-[1.5] text-[var(--text)] outline-none transition placeholder:text-[var(--text-faint)] hover:border-[var(--border-strong)] focus:border-[var(--text-muted)]" />
95
+ ))}
96
+ {hook.problem && hook.problemFor === (service?.id ?? 'custom') ? <p className={settingsError} role="alert">{hook.problem}</p> : null}
97
+ <div className="flex justify-end gap-2">
98
+ <SettingsButton variant="quiet" onClick={onDone}>{t('settings.providers.cancel')}</SettingsButton>
99
+ <SettingsButton type="submit" variant="primary" disabled={busy || !fields.name.trim() || !fields.url.trim()}>{t('settings.providers.save')}</SettingsButton>
100
+ </div>
101
+ </SettingsInset>
102
+ </form>
103
+ );
104
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Settings → Developer's Diagnostics, for when something does not work and a person wants to say why: the report to
3
+ * copy (short: `openfilm doctor` with the last week's problems, this browser, the desktop app's agents; lib/diagnostics),
4
+ * the diagnostic file to export (the rest: the logs and the failed turns, zipped; server/diagnostics.mjs), and the
5
+ * problems of the last two weeks, newest first.
6
+ */
7
+ import React from 'react';
8
+ import { Check, Copy, Download, Loader2 } from 'lucide-react';
9
+ import { useLanguage, useT } from '@/i18n';
10
+ import { studioHost } from '@/lib/host';
11
+ import { fullReport, pageFacts } from '@/lib/diagnostics';
12
+ import { api, type StudioProblem } from '@/api';
13
+ import { SettingsButton, SettingsGroup, SettingsInset, SettingsItem, SettingsSwitch } from './ui';
14
+
15
+ /** The report as text, made now: the computer's (with its problems), this browser's, and the app's agents. */
16
+ async function makeReport(): Promise<string> {
17
+ const [computer, app] = await Promise.all([api.doctor(), studioHost?.agents?.report?.().catch(() => null) ?? null]);
18
+ return fullReport(computer.text, pageFacts(), app);
19
+ }
20
+
21
+ /**
22
+ * Copying the report: its state, and the report itself when the browser does not let the page copy (an agent's
23
+ * preview pane may not), to select by hand.
24
+ */
25
+ export function useReportCopy() {
26
+ const [state, setState] = React.useState<'idle' | 'making' | 'copied' | 'failed'>('idle');
27
+ const [shown, setShown] = React.useState<string | null>(null);
28
+ const copy = () => {
29
+ setState('making');
30
+ void makeReport()
31
+ .then((text) => navigator.clipboard.writeText(text).then(() => { setShown(null); setState('copied'); }, () => { setShown(text); setState('idle'); }))
32
+ .catch(() => setState('failed'));
33
+ };
34
+ return { state, shown, copy };
35
+ }
36
+
37
+ /** The button that copies the report, as Settings → Developer and an agent with a problem (Settings → Agents) show it. */
38
+ export function CopyReportButton({ copying, variant = 'default' }: { copying: ReturnType<typeof useReportCopy>; variant?: 'default' | 'quiet' }) {
39
+ const t = useT();
40
+ const { state, copy } = copying;
41
+ return (
42
+ <SettingsButton variant={variant} disabled={state === 'making'} onClick={copy}>
43
+ {state === 'making' ? <Loader2 size={15} className="animate-spin" aria-hidden /> : state === 'copied' ? <Check size={15} aria-hidden /> : <Copy size={15} aria-hidden />}
44
+ {state === 'making' ? t('settings.report.making') : state === 'copied' ? t('settings.report.copied') : t('settings.report.copy')}
45
+ </SettingsButton>
46
+ );
47
+ }
48
+
49
+ /** The report to select, where the page could not copy it. */
50
+ export function ReportText({ text }: { text: string }) {
51
+ const t = useT();
52
+ return (
53
+ <textarea readOnly value={text} rows={12} aria-label={t('settings.report.title')} onFocus={(e) => e.currentTarget.select()}
54
+ className="mb-2 w-full resize-y rounded-md border border-[var(--border)] bg-[var(--surface-2)] p-2 font-mono text-[11.5px] leading-snug text-[var(--text)]" />
55
+ );
56
+ }
57
+
58
+ /** The report as a link to copy it, under an agent's problem (Settings → Agents). */
59
+ export function ReportLink() {
60
+ const t = useT();
61
+ const copying = useReportCopy();
62
+ return (
63
+ <>
64
+ <p className="text-[13.5px] leading-relaxed text-[var(--text-muted)]">
65
+ <button type="button" onClick={copying.copy} disabled={copying.state === 'making'} title={t('settings.report.hint')}
66
+ className="underline underline-offset-2 hover:text-[var(--text)] disabled:opacity-60">
67
+ {copying.state === 'making' ? t('settings.report.making') : copying.state === 'copied' ? t('settings.report.copied') : t('settings.report.copy')}
68
+ </button>
69
+ {copying.state === 'failed' ? ` ${t('settings.report.failed')}` : null}
70
+ </p>
71
+ {copying.shown ? <ReportText text={copying.shown} /> : null}
72
+ </>
73
+ );
74
+ }
75
+
76
+ /**
77
+ * What an exported file holds, in words, from the names of what went in (server/diagnostics.mjs): each part once, the
78
+ * logs and the turns counted.
79
+ */
80
+ function fileParts(files: string[], conversations: boolean, t: (key: string) => string): string[] {
81
+ const count = (prefix: string) => files.filter((f) => f.startsWith(prefix)).length;
82
+ const logs = count('logs/');
83
+ const turns = count('turns/');
84
+ return [
85
+ ...(files.includes('report.txt') ? [t('settings.report.partReport')] : []),
86
+ ...(files.includes('problems.jsonl') ? [t('settings.report.partProblems')] : []),
87
+ ...(logs ? [t('settings.report.partLogs').replace('{count}', String(logs))] : []),
88
+ ...(turns ? [t(conversations ? 'settings.report.partTurnsWords' : 'settings.report.partTurns').replace('{count}', String(turns))] : []),
89
+ ...(files.includes('agents/codex.txt') ? [t('settings.report.partCodex')] : []),
90
+ ];
91
+ }
92
+
93
+ /* what turning on "Include what was said" adds, said in full before it is on */
94
+ const ADDS = ['settings.report.adds1', 'settings.report.adds2', 'settings.report.adds3', 'settings.report.adds4', 'settings.report.adds5'];
95
+
96
+ /** How many problems show before "Show all". */
97
+ const PROBLEMS_SHOWN = 5;
98
+
99
+ export function DiagnosticsGroup() {
100
+ const t = useT();
101
+ const locale = useLanguage();
102
+ const copying = useReportCopy();
103
+ /* what was said in failed turns: off unless the person turns it on, and only after reading what it adds (`asking`) */
104
+ const [conversations, setConversations] = React.useState(false);
105
+ const [asking, setAsking] = React.useState(false);
106
+ const [exporting, setExporting] = React.useState<{ state: 'idle' | 'making' | 'failed' } | { state: 'done'; name: string; parts: string[] }>({ state: 'idle' });
107
+ const [problems, setProblems] = React.useState<StudioProblem[] | null>(null);
108
+ const [all, setAll] = React.useState(false);
109
+ React.useEffect(() => { void api.problems().then(setProblems, () => setProblems([])); }, []);
110
+
111
+ const exportFile = () => {
112
+ setExporting({ state: 'making' });
113
+ void makeReport()
114
+ .then((report) => api.exportDiagnostics(report, conversations))
115
+ .then((made) => setExporting({ state: 'done', name: made.path.split(/[\\/]/).pop() ?? made.path, parts: fileParts(made.files, made.conversations, t) }))
116
+ .catch(() => setExporting({ state: 'failed' }));
117
+ };
118
+
119
+ const when = (iso: string) => {
120
+ const at = new Date(iso);
121
+ return Number.isNaN(at.getTime()) ? iso : at.toLocaleString(locale, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' });
122
+ };
123
+ const shown = problems ? (all ? problems : problems.slice(0, PROBLEMS_SHOWN)) : [];
124
+
125
+ return (
126
+ <SettingsGroup title={t('settings.report.group')}>
127
+ <SettingsItem
128
+ title={t('settings.report.title')}
129
+ description={copying.state === 'failed' ? t('settings.report.failed') : copying.shown ? t('settings.report.select') : t('settings.report.hint')}
130
+ control={<CopyReportButton copying={copying} />}
131
+ >
132
+ {copying.shown ? <ReportText text={copying.shown} /> : null}
133
+ </SettingsItem>
134
+ <SettingsItem
135
+ title={t('settings.report.conversations')}
136
+ description={conversations ? t('settings.report.conversationsOn') : t('settings.report.conversationsHint')}
137
+ control={(
138
+ <SettingsSwitch checked={conversations || asking} label={t('settings.report.conversations')}
139
+ onChange={(on) => { if (on) setAsking(true); else { setAsking(false); setConversations(false); } }} />
140
+ )}
141
+ >
142
+ {asking ? (
143
+ <SettingsInset>
144
+ <p className="text-[14px] font-medium text-[var(--text)]">{t('settings.report.addsTitle')}</p>
145
+ <ul className="flex list-disc flex-col gap-1 pl-5 text-[13.5px] leading-relaxed text-[var(--text)]">
146
+ {ADDS.map((key) => <li key={key}>{t(key)}</li>)}
147
+ </ul>
148
+ <p className="text-[13px] leading-relaxed text-[var(--text-muted)]">{t('settings.report.addsKept')}</p>
149
+ <p className="text-[13px] leading-relaxed text-[var(--warn)]">{t('settings.report.addsWho')}</p>
150
+ <div className="flex justify-end gap-1.5">
151
+ <SettingsButton variant="quiet" onClick={() => setAsking(false)}>{t('settings.report.addsNo')}</SettingsButton>
152
+ <SettingsButton onClick={() => { setAsking(false); setConversations(true); }}>{t('settings.report.addsYes')}</SettingsButton>
153
+ </div>
154
+ </SettingsInset>
155
+ ) : null}
156
+ </SettingsItem>
157
+ <SettingsItem
158
+ title={t('settings.report.export')}
159
+ description={exporting.state === 'failed' ? t('settings.report.exportFailed')
160
+ : exporting.state === 'done' ? t('settings.report.exported').replace('{name}', exporting.name)
161
+ : t('settings.report.exportHint')}
162
+ control={(
163
+ <SettingsButton disabled={exporting.state === 'making' || asking} onClick={exportFile}>
164
+ {exporting.state === 'making' ? <Loader2 size={15} className="animate-spin" aria-hidden /> : <Download size={15} aria-hidden />}
165
+ {exporting.state === 'making' ? t('settings.report.exporting') : t('settings.report.exportButton')}
166
+ </SettingsButton>
167
+ )}
168
+ >
169
+ {exporting.state === 'done' ? (
170
+ <div className="mb-2 text-[13px] leading-relaxed text-[var(--text-muted)]">
171
+ <p>{t('settings.report.exportedHas')}</p>
172
+ <ul className="list-disc pl-5">{exporting.parts.map((part) => <li key={part}>{part}</li>)}</ul>
173
+ </div>
174
+ ) : null}
175
+ </SettingsItem>
176
+ <SettingsItem
177
+ title={t('settings.report.problems')}
178
+ description={problems && !problems.length ? t('settings.report.noProblems') : t('settings.report.problemsHint')}
179
+ >
180
+ {shown.length ? (
181
+ <ul className="mb-2 flex flex-col gap-1.5">
182
+ {shown.map((p, i) => (
183
+ <li key={`${p.t}:${i}`} className="min-w-0 rounded-md bg-[var(--surface-2)] px-2.5 py-1.5 text-[12.5px] leading-snug">
184
+ <div className="flex gap-2 text-[var(--text-muted)]">
185
+ <span className="shrink-0 tabular-nums">{when(p.t)}</span>
186
+ <span className="truncate">{[p.agent ?? p.area, p.step].filter(Boolean).join(' · ')}</span>
187
+ </div>
188
+ <div className="break-words text-[var(--text)]">{p.what}</div>
189
+ </li>
190
+ ))}
191
+ </ul>
192
+ ) : null}
193
+ {problems && problems.length > PROBLEMS_SHOWN && !all ? (
194
+ <button type="button" onClick={() => setAll(true)}
195
+ className="mb-2 text-[13px] text-[var(--text-muted)] underline underline-offset-2 transition hover:text-[var(--text)]">
196
+ {t('settings.report.more').replace('{count}', String(problems.length))}
197
+ </button>
198
+ ) : null}
199
+ </SettingsItem>
200
+ </SettingsGroup>
201
+ );
202
+ }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Settings → Services: which connected provider, and which of its models, makes each kind of media. One of the models
3
+ * of a provider the person has a key for ("ElevenLabs · Eleven v3"), or none, listed by the providers' names, none put
4
+ * first. Connecting a provider fills the kinds that have none, with its first model; the person changes any here.
5
+ * Under them, the person's custom services, which their agent calls itself (CustomServices).
6
+ */
7
+ import React from 'react';
8
+ import { Check, ChevronDown, ChevronRight } from 'lucide-react';
9
+ import { useLanguage, useT } from '@/i18n';
10
+ import { USE_VERBS, couldMake, offered, useProviders, type ProviderVerb, type ProvidersHook } from '@/lib/providers';
11
+ import { Popover } from '@/components/Popover';
12
+ import { ProviderMark } from './ProviderMark';
13
+ import { SettingsButton, SettingsGroup, SettingsItem, SettingsPage, settingsError } from './ui';
14
+ import { CustomServices, customProblem } from './CustomServices';
15
+
16
+ /** One thing a kind of media can be made with: a provider and its model. */
17
+ interface Choice {
18
+ value: string;
19
+ provider: string;
20
+ providerName: string;
21
+ name: string;
22
+ pick: { model?: string };
23
+ }
24
+
25
+ export function ModelsSection({ onConnect }: { onConnect: () => void }) {
26
+ const t = useT();
27
+ const hook = useProviders();
28
+ const providers = hook.state;
29
+ const anything = Boolean(providers?.providers.some((p) => p.source));
30
+
31
+ return (
32
+ <SettingsPage note={t('settings.models.desc')}>
33
+ {providers && !anything ? (
34
+ <SettingsGroup>
35
+ <SettingsItem description={t('settings.models.nothing')} title={t('settings.models.goConnect')}
36
+ control={<SettingsButton onClick={onConnect}>{t('settings.models.goConnect')}</SettingsButton>} />
37
+ </SettingsGroup>
38
+ ) : null}
39
+ {providers ? (
40
+ <SettingsGroup>
41
+ {USE_VERBS.filter((verb) => offered(providers, verb)).map((verb) => <ModelRow key={verb} verb={verb} hook={hook} onConnect={onConnect} />)}
42
+ </SettingsGroup>
43
+ ) : null}
44
+ <CustomServices hook={hook} />
45
+ {/* a custom service's problem is said under its form */}
46
+ {hook.problem && !customProblem(hook) ? <p className={settingsError}>{hook.problem}</p> : null}
47
+ </SettingsPage>
48
+ );
49
+ }
50
+
51
+ /** One kind of media and what makes it, picked from the connected providers' models. */
52
+ function ModelRow({ verb, hook, onConnect }: { verb: ProviderVerb; hook: ProvidersHook; onConnect: () => void }) {
53
+ const t = useT();
54
+ const state = hook.state!;
55
+ const label = t(`settings.providers.verbs.${verb}`);
56
+ const chosen = state.use[verb] ?? '';
57
+
58
+ const choices: Choice[] = [];
59
+ for (const p of state.providers) {
60
+ if (!((p.source && p.verbs.includes(verb)) || p.id === chosen)) continue;
61
+ for (const m of p.models[verb] ?? []) choices.push({ value: `${p.id}:${m.id}`, provider: p.id, providerName: p.name, name: m.name, pick: { model: m.id } });
62
+ }
63
+ /* by the providers' names; each provider's models stay in its own order (the sort is stable) */
64
+ choices.sort((a, b) => a.providerName.localeCompare(b.providerName));
65
+ const firstOf = (id: string) => state.providers.find((p) => p.id === id)?.models[verb]?.[0]?.id;
66
+ const value = chosen ? `${chosen}:${state.model[verb] ?? firstOf(chosen) ?? ''}` : '';
67
+ const current = choices.find((c) => c.value === value);
68
+ /* nothing connected makes it: the providers that would, once connected */
69
+ const could = couldMake(state, verb);
70
+
71
+ return (
72
+ <SettingsItem
73
+ title={label}
74
+ description={t(`settings.models.about.${verb}`)}
75
+ control={(
76
+ <ModelPicker
77
+ label={label}
78
+ choices={choices}
79
+ current={current ?? null}
80
+ busy={hook.busy === verb}
81
+ could={could}
82
+ onConnect={onConnect}
83
+ onPick={(choice) => void hook.choose(verb, choice?.provider ?? '', choice?.pick)}
84
+ />
85
+ )}
86
+ />
87
+ );
88
+ }
89
+
90
+ /**
91
+ * The button showing what makes a kind of media, and the menu of every model it could be, by provider. With nothing
92
+ * connected that makes it, it names the providers that would and goes to connect one.
93
+ */
94
+ function ModelPicker({ label, choices, current, busy, could, onConnect, onPick }: {
95
+ label: string;
96
+ choices: Choice[];
97
+ current: Choice | null;
98
+ busy: boolean;
99
+ /** the names of the providers, not connected, that make this kind of media */
100
+ could: string[];
101
+ onConnect: () => void;
102
+ onPick: (choice: Choice | null) => void;
103
+ }) {
104
+ const t = useT();
105
+ const language = useLanguage();
106
+ const [open, setOpen] = React.useState(false);
107
+ const list = React.useRef<HTMLDivElement>(null);
108
+ const empty = choices.length === 0;
109
+ const groups = choices.reduce<{ provider: string; name: string; choices: Choice[] }[]>((all, c) => {
110
+ const group = all.find((g) => g.provider === c.provider);
111
+ if (group) group.choices.push(c); else all.push({ provider: c.provider, name: c.providerName, choices: [c] });
112
+ return all;
113
+ }, []);
114
+
115
+ /* the menu opens on the chosen one; the arrow keys move between them */
116
+ React.useEffect(() => {
117
+ if (!open) return;
118
+ const r = requestAnimationFrame(() => (list.current?.querySelector<HTMLElement>('[aria-selected="true"]') ?? list.current?.querySelector<HTMLElement>('[role="option"]'))?.focus());
119
+ return () => cancelAnimationFrame(r);
120
+ }, [open]);
121
+ const onKeyDown = (e: React.KeyboardEvent) => {
122
+ if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return;
123
+ e.preventDefault();
124
+ const options = Array.from(list.current?.querySelectorAll<HTMLElement>('[role="option"]') ?? []);
125
+ const at = options.indexOf(document.activeElement as HTMLElement);
126
+ options[(at + (e.key === 'ArrowDown' ? 1 : -1) + options.length) % options.length]?.focus();
127
+ };
128
+ const pick = (choice: Choice | null) => { setOpen(false); if (choice?.value !== current?.value) onPick(choice); };
129
+
130
+ const option = (choice: Choice | null, text: string) => {
131
+ const selected = (choice?.value ?? '') === (current?.value ?? '');
132
+ return (
133
+ <button key={choice?.value ?? ''} type="button" role="option" aria-selected={selected} onClick={() => pick(choice)}
134
+ className="flex h-9 w-full items-center gap-2 rounded-[6px] px-2 text-left text-[14.5px] text-[var(--text)] outline-none hover:bg-[var(--bg-hover)] focus-visible:bg-[var(--bg-hover)]">
135
+ <span className="min-w-0 flex-1 truncate">{text}</span>
136
+ {selected ? <Check size={17} className="shrink-0 text-[var(--text-muted)]" /> : null}
137
+ </button>
138
+ );
139
+ };
140
+
141
+ const connect = could.length
142
+ ? t('settings.models.connectNamed').replace('{names}', new Intl.ListFormat(language, { type: 'disjunction' }).format(could))
143
+ : t('settings.models.goConnect');
144
+ const trigger = empty ? (
145
+ <button type="button" aria-label={`${label}: ${connect}`} title={connect} disabled={busy} onClick={onConnect}
146
+ className="flex h-10 w-[280px] items-center gap-2 rounded-[8px] border border-[var(--border)] px-3 text-left text-[14.5px] text-[var(--text-muted)] transition hover:border-[var(--border-strong)] hover:text-[var(--text)] disabled:opacity-60">
147
+ <span className="min-w-0 flex-1 truncate">{connect}</span>
148
+ <ChevronRight size={15} className="shrink-0" />
149
+ </button>
150
+ ) : (
151
+ <button type="button" aria-label={label} aria-haspopup="listbox" aria-expanded={open} disabled={busy}
152
+ className={`flex h-10 w-[280px] items-center gap-2 rounded-[8px] border px-3 text-left text-[14.5px] text-[var(--text)] transition disabled:opacity-60 ${open ? 'border-[var(--text-muted)]' : 'border-[var(--border)] hover:border-[var(--border-strong)]'}`}>
153
+ {current ? <ProviderMark id={current.provider} size={15} /> : null}
154
+ <span className={`min-w-0 flex-1 truncate ${current ? '' : 'text-[var(--text-muted)]'}`}>
155
+ {current ? `${current.providerName} · ${current.name}` : t('settings.models.none')}
156
+ </span>
157
+ <ChevronDown size={15} className="shrink-0 text-[var(--text-muted)]" />
158
+ </button>
159
+ );
160
+
161
+ return (
162
+ <div className="shrink-0">
163
+ <Popover open={open && !empty} onOpenChange={setOpen} placement="auto" align="end" layer={10060} trigger={trigger}>
164
+ <div ref={list} role="listbox" aria-label={label} onKeyDown={onKeyDown}
165
+ className="max-h-[min(360px,var(--popover-max-h))] w-[288px] overflow-y-auto rounded-[10px] border border-[var(--border)] bg-[var(--surface)] p-1 shadow-[var(--shadow-lg)]">
166
+ {groups.map((group) => (
167
+ <div key={group.provider} className="mb-1" role="group" aria-label={group.name}>
168
+ <div className="flex items-center gap-1.5 px-2 pb-1 pt-1.5 text-[14px] font-medium text-[var(--text-muted)]">
169
+ <ProviderMark id={group.provider} size={15} />{group.name}
170
+ </div>
171
+ {group.choices.map((c) => option(c, c.name))}
172
+ </div>
173
+ ))}
174
+ <div className="border-t border-[var(--border-soft)] pt-1">{option(null, t('settings.models.none'))}</div>
175
+ </div>
176
+ </Popover>
177
+ </div>
178
+ );
179
+ }
@@ -0,0 +1,24 @@
1
+ import { MARKS } from '@/lib/provider-marks';
2
+
3
+ /** A provider's or an agent's mark (lib/provider-marks.ts), or, for one with none yet, its letter in a rounded square. */
4
+ export function ProviderMark({ id, size = 18 }: { id: string; size?: number }) {
5
+ const mark = MARKS[id];
6
+ return (
7
+ <span className="inline-flex shrink-0 items-center justify-center text-[var(--text)]" style={{ width: size, height: size }} aria-hidden>
8
+ {mark ? (
9
+ <svg width={size} height={size} viewBox={mark.viewBox} fill="currentColor" fillRule="evenodd" className="block">
10
+ {mark.parts ? mark.parts.map((part) => <path key={part.d} d={part.d} fillOpacity={part.opacity} />) : <path d={mark.d} />}
11
+ </svg>
12
+ ) : id ? (
13
+ <svg width={size} height={size} viewBox="0 0 24 24" className="block">
14
+ {/* the letter cut out of a solid square, as heavy as the other marks */}
15
+ <mask id={`provider-mark-${id}`}>
16
+ <rect width="24" height="24" fill="white" />
17
+ <text x="12" y="17" textAnchor="middle" fontSize="15" fontWeight="700" fill="black" fontFamily="inherit">{id[0]!.toUpperCase()}</text>
18
+ </mask>
19
+ <rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" mask={`url(#provider-mark-${id})`} />
20
+ </svg>
21
+ ) : null}
22
+ </span>
23
+ );
24
+ }