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,280 @@
1
+ /**
2
+ * The composer's agent button: which agent is thinking and with what (its model, reasoning effort and speed), and a
3
+ * menu to change them.
4
+ *
5
+ * The menu opens on a heading with a button to Settings → Agents, then lists the agents switched on there (none when
6
+ * only one is: there is nothing to choose, and the heading names it instead), then its model and effort, always, and
7
+ * its speed when it has one (agent-menu-rows.ts), each with its value; pointing at a row opens its choices in a side
8
+ * menu beside it. Choosing leaves both open (a model and an effort are often changed together); a click elsewhere
9
+ * closes them.
10
+ *
11
+ * The chat is a view of its own and nothing can be drawn outside it, and the two never cover each other: the side menu
12
+ * takes the room beside the card (a long name wraps to fit), the card slides left to make that room, and in a narrow
13
+ * chat the card narrows to half of it.
14
+ */
15
+ import React from 'react';
16
+ import { createPortal } from 'react-dom';
17
+ import { Check, ChevronRight, KeyRound, Settings } from 'lucide-react';
18
+ import { keepFocus, Popover } from './Popover';
19
+ import { useT } from '@/i18n';
20
+ import { Tooltip } from '@/components/Tooltip';
21
+ import { AgentIcon } from '@/components/AgentIcons';
22
+ import { POPOVER_CHROME } from '@/components/ComposerCard';
23
+ import { desktopBridge, type LocalAgentId, type RosterAgent } from '@/lib/desktop-bridge';
24
+ import { agentModelSummary, agentOptions, currentAgent, effectivePrefs, offeredChoices, offeredOption, optionLabel, optionValue, shownAgents, useLocalAgents } from '@/state/local-agent-store';
25
+ import { chatLayer } from '@/lib/chat-layer';
26
+ import { isSpeed, menuOptions, type MenuOption } from '@/lib/agent-menu-rows';
27
+
28
+ /** the card, wider when it lists the agents; the side menu's least width; the gap between them; the window's margin */
29
+ const CARD_W = 236;
30
+ const CARD_W_ONE_AGENT = 204;
31
+ const SIDE_MIN_W = 156;
32
+ /** the narrowest the card gets in a narrow chat */
33
+ const CARD_MIN_W = 150;
34
+ const SIDE_GAP = 2;
35
+ const EDGE = 8;
36
+ /** how long a side menu stays once the pointer leaves its row (to cross the gap into it) */
37
+ const SIDE_CLOSE_MS = 120;
38
+
39
+ const ROW_BASE =
40
+ 'flex min-h-[28px] w-full items-center gap-2 rounded-[6px] px-2.5 text-[13px] font-normal tracking-normal text-left outline-none transition';
41
+ const ROW = `${ROW_BASE} hover:bg-[var(--bg-hover)] focus-visible:bg-[var(--bg-hover)]`;
42
+
43
+ type Option = MenuOption;
44
+
45
+ /** A row's choices: those the agent offers there, or its one value when that is all it has (a "default" too). */
46
+ function rowChoices(agent: LocalAgentId, o: Option, chosen: unknown): NonNullable<Option['options']> {
47
+ if (o.fixed) return o.options!.slice(0, 1);
48
+ return offeredChoices(agent, o, chosen);
49
+ }
50
+
51
+ /** Why the agent could not be started for its settings, as it said, on a few lines; none when it started and offered none. */
52
+ function failureReason(error: { text: string } | undefined): string | null {
53
+ if (!error || error.text === 'no options') return null;
54
+ return error.text.replace(/\s+/g, ' ').trim().slice(0, 400) || null;
55
+ }
56
+
57
+ export function ChatAgentIcon({ id, size = 14 }: { id: LocalAgentId; size?: number }) {
58
+ if (id === 'byok') return <KeyRound size={size} />;
59
+ return <AgentIcon id={id} size={size} />;
60
+ }
61
+
62
+ export function ModelPopover({ placement = 'bottom', align = 'start' }: { placement?: 'top' | 'bottom'; align?: 'start' | 'end' } = {}) {
63
+ const t = useT();
64
+ const [open, setOpen] = React.useState(false);
65
+ /** the option whose side menu is open */
66
+ const [side, setSide] = React.useState<string | null>(null);
67
+ /** how far the card has slid left to make room for a side menu: it only grows while the menu is open */
68
+ const [cardShift, setCardShift] = React.useState(0);
69
+ const [sideStyle, setSideStyle] = React.useState<React.CSSProperties | null>(null);
70
+ const cardRef = React.useRef<HTMLDivElement | null>(null);
71
+ const sideRef = React.useRef<HTMLDivElement | null>(null);
72
+ const rowRefs = React.useRef<Record<string, HTMLElement | null>>({});
73
+ const closeTimer = React.useRef<number | null>(null);
74
+ const stopTimer = () => { if (closeTimer.current) { window.clearTimeout(closeTimer.current); closeTimer.current = null; } };
75
+ const showSide = (id: string) => { stopTimer(); setSide(id); };
76
+ const hideSideSoon = () => { stopTimer(); closeTimer.current = window.setTimeout(() => setSide(null), SIDE_CLOSE_MS); };
77
+ React.useEffect(() => { if (!open) { stopTimer(); setSide(null); setCardShift(0); } }, [open]);
78
+ React.useEffect(() => stopTimer, []);
79
+ /* the window's width while open: the card and the side menu share it */
80
+ const [windowW, setWindowW] = React.useState(() => window.innerWidth);
81
+ React.useEffect(() => {
82
+ if (!open) return;
83
+ const read = () => setWindowW(window.innerWidth);
84
+ read();
85
+ window.addEventListener('resize', read);
86
+ return () => window.removeEventListener('resize', read);
87
+ }, [open]);
88
+ const room = windowW - 2 * EDGE - SIDE_GAP;
89
+
90
+ const la = useLocalAgents();
91
+ const { hydrate, refresh, ensureOptions } = la;
92
+ React.useEffect(() => { hydrate(); }, [hydrate]);
93
+ const agent = currentAgent(la);
94
+ const shown = shownAgents(la.roster);
95
+ const ready = (id: LocalAgentId) => shown.find((a) => a.id === id)?.status === 'ready';
96
+ React.useEffect(() => { if (ready(agent)) void ensureOptions(agent); });
97
+ React.useEffect(() => {
98
+ if (!open) return;
99
+ void refresh().then(() => {
100
+ for (const a of shownAgents(useLocalAgents.getState().roster)) if (a.status === 'ready') void ensureOptions(a.id, { retry: true });
101
+ });
102
+ }, [open, refresh, ensureOptions]);
103
+
104
+ const options = agentOptions(la, agent);
105
+ const prefs = effectivePrefs(la.prefs, agent, la.roster, options);
106
+ const rows = options ? menuOptions(options, t('composer.optionDefault')).filter((o) => offeredOption(agent, la.roster, o)) : [];
107
+ const summary = agentModelSummary(options, prefs);
108
+ const triggerModel = summary.model;
109
+ const triggerEffort = rows.some((o) => o.category === 'thought_level' && !o.fixed) ? summary.effort : null;
110
+ const valueOf = (o: Option) => (o.fixed ? (optionLabel(options, o.id, optionValue(options, prefs, o.id)) ?? o.options![0]!.name)
111
+ : (o.category === 'model' ? triggerModel : null) ?? optionLabel(options, o.id, optionValue(options, prefs, o.id)) ?? '');
112
+ const rowLabel = (o: Option) => (o.category === 'model' ? t('composer.model') : o.category === 'thought_level' ? t('composer.effort') : isSpeed(o) ? t('composer.speed') : o.name);
113
+ const nameOf = (a: RosterAgent) => (a.id === 'byok' ? t('composer.agentOwnKey') : a.name);
114
+
115
+ /* an agent that is not ready: what it needs, said here; setting it up is Settings → Agents */
116
+ const statusOf = (a: RosterAgent): string | null => {
117
+ if (a.status === 'ready') return null;
118
+ if (a.status === 'checking') return t('composer.agentLoading');
119
+ if (a.status === 'missing') return t('composer.agentNotFound');
120
+ if (a.status === 'waiting') return t('composer.agentWaiting');
121
+ return t('composer.agentSetUp');
122
+ };
123
+ const chooseAgent = (a: RosterAgent) => {
124
+ setSide(null);
125
+ if (a.status === 'ready') { la.pick(a.id); return; }
126
+ if (a.status === 'checking' || a.status === 'waiting') return;
127
+ /* not connected, signed out, not found, no key: set up in Settings → Agents, where connecting and signing in are */
128
+ setOpen(false);
129
+ desktopBridge()?.openSettings?.('agents');
130
+ };
131
+ const openSettings = () => { setOpen(false); desktopBridge()?.openSettings?.('agents'); };
132
+ const current = shown.find((a) => a.id === agent);
133
+ const choosing = side ? rows.find((o) => o.id === side) : undefined;
134
+ const chosenValue = (o: Option) => (o.fixed ? o.options![0]!.value : optionValue(options, prefs, o.id));
135
+ /* a fixed row's one value is already the one in use */
136
+ const pickChoice = (o: Option, value: unknown) => { if (!o.fixed) la.setPref(agent, o.id, value); };
137
+
138
+ /* the side menu beside its row: on the right of the card, the card sliding left when the window is too narrow for
139
+ both, and over the card's right edge only when it cannot slide far enough; measured again once it is drawn */
140
+ const sidePainted = sideStyle !== null;
141
+ React.useLayoutEffect(() => {
142
+ const card = cardRef.current;
143
+ const row = choosing ? rowRefs.current[choosing.id] : null;
144
+ if (!open || !choosing || !card || !row) { setSideStyle(null); return; }
145
+ const c = card.getBoundingClientRect();
146
+ const el = sideRef.current;
147
+ const sideMax = Math.max(0, room - c.width);
148
+ const w = Math.min(sideMax, Math.max(SIDE_MIN_W, el?.offsetWidth ?? SIDE_MIN_W));
149
+ const h = el?.offsetHeight ?? 8 + (choosing.options?.length ?? 0) * 28;
150
+ const width = window.innerWidth;
151
+ const height = window.innerHeight;
152
+ let left = c.right + SIDE_GAP;
153
+ const need = left + w - (width - EDGE);
154
+ if (need > 0) {
155
+ const slide = Math.min(need, Math.max(0, c.left - EDGE));
156
+ if (slide > 0) setCardShift((s) => s + slide);
157
+ left = Math.max(EDGE, Math.min(left - slide, width - EDGE - w));
158
+ }
159
+ let top = row.getBoundingClientRect().top - 4;
160
+ if (top + h > height - EDGE) top = Math.max(EDGE, height - EDGE - h);
161
+ setSideStyle({ position: 'fixed', left, top, zIndex: 10001, minWidth: Math.min(SIDE_MIN_W, sideMax), width: 'max-content', maxWidth: sideMax, maxHeight: height - 2 * EDGE });
162
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed by the open row
163
+ }, [open, choosing?.id, cardShift, sidePainted, room]);
164
+
165
+ const sideMenu = open && choosing && typeof document !== 'undefined' ? createPortal(
166
+ <div ref={sideRef} onMouseEnter={() => showSide(choosing.id)} onMouseLeave={hideSideSoon}
167
+ style={{ ...POPOVER_CHROME, padding: 4, overflowY: 'auto', ...(sideStyle ?? { position: 'fixed', left: -9999, top: 0 }) }}>
168
+ {/* the names only: no descriptions, and the choices the menu offers (rowChoices) */}
169
+ {rowChoices(agent, choosing, chosenValue(choosing)).map((choice) => {
170
+ const selected = chosenValue(choosing) === choice.value;
171
+ return (
172
+ <button key={String(choice.value)} type="button" onMouseDown={keepFocus}
173
+ onClick={() => pickChoice(choosing, choice.value)} className={ROW}>
174
+ <span className="min-w-0 flex-1 truncate text-[var(--text)]">{choice.name}</span>
175
+ <Check size={13} className={`ml-2 shrink-0 text-[var(--text)] ${selected ? '' : 'invisible'}`} />
176
+ </button>
177
+ );
178
+ })}
179
+ </div>,
180
+ chatLayer(),
181
+ ) : null;
182
+
183
+ return (
184
+ <>
185
+ <Popover
186
+ open={open}
187
+ onOpenChange={setOpen}
188
+ placement={placement}
189
+ align={align}
190
+ bare
191
+ insideRefs={[sideRef]}
192
+ trigger={
193
+ <Tooltip label={t('composer.model')}>
194
+ <button type="button" onMouseDown={keepFocus}
195
+ className="group inline-flex h-8 max-w-full items-center rounded-full px-2 text-[12.5px] font-medium transition hover:bg-[var(--bg-hover)]">
196
+ <span className="inline-flex min-w-0 max-w-[190px] items-center gap-1.5 truncate whitespace-nowrap">
197
+ <span className="shrink-0 text-[var(--text-dim)]"><ChatAgentIcon id={agent} size={13} /></span>
198
+ <span className="truncate text-[var(--text-dim)] transition group-hover:text-[var(--text)]">
199
+ {(ready(agent) && triggerModel) || (current ? nameOf(current) : t('composer.agentNone'))}
200
+ </span>
201
+ {ready(agent) && triggerEffort ? <span className="text-[var(--text-muted)] transition group-hover:text-[var(--text-dim)]">{triggerEffort}</span> : null}
202
+ </span>
203
+ </button>
204
+ </Tooltip>
205
+ }
206
+ >
207
+ <div ref={cardRef} style={{ ...POPOVER_CHROME, width: Math.min(shown.length > 1 ? CARD_W : CARD_W_ONE_AGENT, Math.max(CARD_MIN_W, Math.floor(room / 2))), padding: 4, transform: cardShift ? `translateX(-${cardShift}px)` : undefined }}>
208
+ {shown.length === 0 && la.roster ? (
209
+ <div className="px-2.5 py-2 text-[12.5px] leading-relaxed text-[var(--text-muted)]">
210
+ {t('composer.agentNoneShown')}{' '}
211
+ <button type="button" onMouseDown={keepFocus} onClick={openSettings} className="text-[var(--text)] underline underline-offset-2">{t('composer.openSettings')}</button>
212
+ </div>
213
+ ) : (
214
+ <>
215
+ {/* the heading, and Settings → Agents beside it (where agents are switched on, connected and signed in) */}
216
+ <div className="flex items-center gap-2 pb-0.5 pl-2.5 pr-0.5 pt-0.5">
217
+ <span className="min-w-0 flex-1 truncate text-[11px] text-[var(--text-faint)]">{shown.length > 1 ? t('composer.agentSection') : current ? nameOf(current) : t('composer.agentSection')}</span>
218
+ <Tooltip label={t('composer.openSettings')}>
219
+ <button type="button" aria-label={t('composer.openSettings')} onMouseDown={keepFocus} onMouseEnter={hideSideSoon} onClick={openSettings}
220
+ className="flex h-6 w-6 shrink-0 items-center justify-center rounded-[6px] text-[var(--text-faint)] outline-none transition hover:bg-[var(--bg-hover)] hover:text-[var(--text)] focus-visible:bg-[var(--bg-hover)]">
221
+ <Settings size={13} />
222
+ </button>
223
+ </Tooltip>
224
+ </div>
225
+ {shown.length > 1 ? (
226
+ <>
227
+ {shown.map((a) => {
228
+ const status = statusOf(a);
229
+ return (
230
+ <button key={a.id} type="button" onMouseDown={keepFocus} onMouseEnter={hideSideSoon} onClick={() => chooseAgent(a)} className={ROW}>
231
+ <span className={`flex w-4 shrink-0 justify-center ${status ? 'text-[var(--text-faint)]' : 'text-[var(--text)]'}`}><ChatAgentIcon id={a.id} /></span>
232
+ <span className={`min-w-0 flex-1 truncate ${status ? 'text-[var(--text-muted)]' : 'text-[var(--text)]'}`}>{nameOf(a)}</span>
233
+ {agent === a.id && !status ? <Check size={13} className="shrink-0 text-[var(--text)]" />
234
+ : status ? <span className="min-w-0 max-w-[55%] truncate text-[11.5px] text-[var(--text-faint)]" title={status}>{status}</span> : null}
235
+ </button>
236
+ );
237
+ })}
238
+ <div className="mx-1 my-1 h-px bg-[var(--border)]" />
239
+ </>
240
+ ) : null}
241
+ {!ready(agent) ? (
242
+ <div className="px-2.5 py-1.5 text-[12px] leading-relaxed text-[var(--text-muted)]">
243
+ {current ? `${nameOf(current)}: ${statusOf(current) ?? ''}` : t('composer.agentLoading')}{' '}
244
+ <button type="button" onMouseDown={keepFocus} onClick={openSettings} className="text-[var(--text)] underline underline-offset-2">{t('composer.openSettings')}</button>
245
+ </div>
246
+ ) : rows.length === 0 ? (
247
+ <p className="px-2.5 py-1.5 text-[12px] leading-relaxed text-[var(--text-muted)]">
248
+ {la.optionsError[agent]
249
+ ? <>
250
+ {la.optionsError[agent]?.code === 'outdated' ? t('composer.agentOutdated') : t('composer.agentOptionsFailed')} <button type="button" onMouseDown={keepFocus} onClick={() => void la.ensureOptions(agent, { retry: true })} className="text-[var(--text)] underline underline-offset-2">{t('project.retry')}</button>
251
+ {/* what the agent said, so the person can fix it (a setting it cannot read) or tell us */}
252
+ {failureReason(la.optionsError[agent]) ? (
253
+ <span className="mt-1 line-clamp-4 block select-text break-words text-[11.5px] text-[var(--text-faint)]" title={la.optionsError[agent]?.text}>{failureReason(la.optionsError[agent])}</span>
254
+ ) : null}
255
+ </>
256
+ : t('composer.agentLoading')}
257
+ </p>
258
+ ) : rows.map((o, i) => (
259
+ <React.Fragment key={o.id}>
260
+ {i > 0 ? <div className="mx-1 my-0.5 h-px bg-[var(--border)]" /> : null}
261
+ <button type="button" ref={(el) => { rowRefs.current[o.id] = el; }} aria-haspopup="menu" aria-expanded={side === o.id}
262
+ onMouseDown={keepFocus} onMouseEnter={() => showSide(o.id)} onMouseLeave={hideSideSoon} onFocus={() => showSide(o.id)}
263
+ onClick={() => showSide(o.id)}
264
+ className={`${ROW_BASE} ${side === o.id ? 'bg-[var(--bg-hover)]' : 'hover:bg-[var(--bg-hover)]'}`}>
265
+ <span className="shrink-0 text-[var(--text)]">{rowLabel(o)}</span>
266
+ <span className="min-w-0 flex-1 truncate text-right text-[var(--text-dim)]">{valueOf(o)}</span>
267
+ <ChevronRight size={12} className="shrink-0 text-[var(--text-faint)]" />
268
+ </button>
269
+ </React.Fragment>
270
+ ))}
271
+ </>
272
+ )}
273
+ </div>
274
+ </Popover>
275
+ {sideMenu}
276
+ </>
277
+ );
278
+ }
279
+
280
+ export { Popover } from './Popover';
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import { useT } from '@/i18n';
5
+ import { CardActions, CardButton, ComposerCard } from './ComposerCard';
6
+
7
+ /**
8
+ * Notices above the composer: a card, not a centered modal.
9
+ *
10
+ * Shell and buttons are ComposerCard's (themed background, the same buttons).
11
+ */
12
+ export function NoticeCard({
13
+ title,
14
+ body,
15
+ onClose,
16
+ children,
17
+ role,
18
+ }: {
19
+ title: string;
20
+ body?: React.ReactNode;
21
+ onClose: () => void;
22
+ children?: React.ReactNode;
23
+ role?: React.AriaRole;
24
+ }) {
25
+ return (
26
+ <ComposerCard title={title} body={body} onClose={onClose} {...(role ? { role } : {})}>
27
+ {children}
28
+ </ComposerCard>
29
+ );
30
+ }
31
+
32
+ export function NoticeFooter({ children }: { children: React.ReactNode }) {
33
+ return <CardActions>{children}</CardActions>;
34
+ }
35
+
36
+ export const NoticeDismissButton = React.forwardRef<
37
+ HTMLButtonElement,
38
+ React.ButtonHTMLAttributes<HTMLButtonElement>
39
+ >(function NoticeDismissButton(props, ref) {
40
+ return <CardButton {...props} ref={ref} weight="quiet" />;
41
+ });
42
+
43
+ export const NoticePrimaryButton = React.forwardRef<
44
+ HTMLButtonElement,
45
+ React.ButtonHTMLAttributes<HTMLButtonElement> & { danger?: boolean }
46
+ >(function NoticePrimaryButton({ danger = false, ...props }, ref) {
47
+ return <CardButton {...props} ref={ref} weight={danger ? 'danger' : 'primary'} />;
48
+ });
49
+
50
+ /** A complete notice above the composer: title, body, Dismiss, and an optional primary button at the bottom right. */
51
+ export function ComposerNotice({
52
+ title,
53
+ body,
54
+ primaryLabel,
55
+ onPrimary,
56
+ primaryBusy,
57
+ primaryDanger,
58
+ onDismiss,
59
+ role = 'alert',
60
+ }: {
61
+ title: string;
62
+ body: React.ReactNode;
63
+ primaryLabel?: React.ReactNode;
64
+ onPrimary?: () => void;
65
+ primaryBusy?: boolean;
66
+ primaryDanger?: boolean;
67
+ onDismiss: () => void;
68
+ role?: React.AriaRole;
69
+ }) {
70
+ const t = useT();
71
+ return (
72
+ <NoticeCard title={title} body={body} onClose={onDismiss} role={role}>
73
+ <NoticeFooter>
74
+ <NoticeDismissButton onClick={onDismiss}>{t('project.dismiss')}</NoticeDismissButton>
75
+ {primaryLabel && onPrimary ? (
76
+ <NoticePrimaryButton
77
+ disabled={primaryBusy}
78
+ danger={primaryDanger}
79
+ onClick={onPrimary}
80
+ >
81
+ {primaryLabel}
82
+ </NoticePrimaryButton>
83
+ ) : null}
84
+ </NoticeFooter>
85
+ </NoticeCard>
86
+ );
87
+ }
@@ -0,0 +1,195 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * A small popover opened from a button: closes on an outside click or Esc, portalled so no overflow clips it.
5
+ * Its own file: several places use it, and it shouldn't pull in the model menu.
6
+ */
7
+ import React from 'react';
8
+ import { createPortal } from 'react-dom';
9
+ import { useChatMenu } from '@/lib/chat-menu';
10
+ import { chatLayer } from '@/lib/chat-layer';
11
+
12
+ export function keepFocus(e: React.MouseEvent) {
13
+ e.preventDefault();
14
+ }
15
+
16
+ const EMPTY_INSIDE_REFS: Array<React.RefObject<HTMLElement | null>> = [];
17
+
18
+ /**
19
+ * A modal opened from a popover (a full-screen scrim and a card), portalled on its own.
20
+ *
21
+ * It must be recognizable, or every press on it reads as an outside click: the popover closes, the component that
22
+ * rendered the modal unmounts, and the button's click never fires. A marker, not `[role="dialog"]`: any dialog
23
+ * mounted elsewhere would then keep the popover from ever closing.
24
+ */
25
+ const MODAL_LAYER = '[data-modal-layer]';
26
+
27
+ function inModalLayer(node: Node): boolean {
28
+ const el = node instanceof Element ? node : node.parentElement;
29
+ return Boolean(el?.closest(MODAL_LAYER));
30
+ }
31
+
32
+ /**
33
+ * A popover opened from a button: closes on an outside click or Esc, portalled so no overflow clips it.
34
+ * Buttons that stand side by side should open the same kind of thing, with the same rules.
35
+ */
36
+ export function Popover({
37
+ open,
38
+ onOpenChange,
39
+ trigger,
40
+ children,
41
+ placement = 'bottom',
42
+ align = 'start',
43
+ insideRefs = EMPTY_INSIDE_REFS,
44
+ bare = false,
45
+ }: {
46
+ open: boolean;
47
+ onOpenChange: (v: boolean) => void;
48
+ trigger: React.ReactNode;
49
+ children: React.ReactNode;
50
+ placement?: 'top' | 'bottom' | 'auto';
51
+ /** end: the panel's right edge aligns with the trigger's (keeps triggers near the right edge on screen). */
52
+ align?: 'start' | 'end';
53
+ insideRefs?: Array<React.RefObject<HTMLElement | null>>;
54
+ /** bare: no card styling on the panel (children draw their own, e.g. several cards side by side). */
55
+ bare?: boolean;
56
+ }) {
57
+ const ref = React.useRef<HTMLDivElement | null>(null);
58
+ const panelRef = React.useRef<HTMLDivElement | null>(null);
59
+ useChatMenu(open);
60
+ const [panelStyle, setPanelStyle] = React.useState<React.CSSProperties | null>(null);
61
+
62
+ const update = React.useCallback(() => {
63
+ const el = ref.current;
64
+ if (!el) return;
65
+ const r = el.getBoundingClientRect();
66
+ const gap = 6;
67
+ const pad = 12;
68
+ const below = window.innerHeight - r.bottom - gap - pad;
69
+ const above = r.top - gap - pad;
70
+ /* `auto` picks a side by the panel's real height: a side it fits in first, else the larger one. Before the
71
+ panel is drawn, 280 is assumed; it is measured again once drawn (see the layoutEffect below). */
72
+ const panel = panelRef.current;
73
+ const inner = panel?.firstElementChild as HTMLElement | null;
74
+ /* The inner card's scrollHeight: once the card clamps itself to --popover-max-h, the panel's height is the
75
+ clamped one and would always "fit". */
76
+ const need = panel ? Math.max(panel.scrollHeight, inner?.scrollHeight ?? 0) : 280;
77
+ const openUp = placement === 'top'
78
+ || (placement === 'auto' && below < need && above > below);
79
+ const room = Math.max(0, openUp ? above : below);
80
+ const x = align === 'end' ? '-100%' : '0%';
81
+ setPanelStyle({
82
+ position: 'fixed',
83
+ left: align === 'end' ? r.right : r.left,
84
+ top: openUp ? r.top - gap : r.bottom + gap,
85
+ transform: `translate(${x}, ${openUp ? '-100%' : '0%'})`,
86
+ zIndex: 10000,
87
+ /* The room on this side, for a bare card to use as its max-height: it scrolls inside, so its corners and
88
+ border don't scroll away with the content. */
89
+ ['--popover-max-h' as string]: `${room}px`,
90
+ ...(bare
91
+ ? { overflow: 'visible' }
92
+ : {
93
+ maxHeight: room,
94
+ overflowY: 'auto' as const,
95
+ overscrollBehavior: 'contain',
96
+ }),
97
+ });
98
+ }, [placement, align, bare]);
99
+
100
+ React.useLayoutEffect(() => {
101
+ if (!open) {
102
+ setPanelStyle(null);
103
+ return;
104
+ }
105
+ update();
106
+ window.addEventListener('resize', update);
107
+ window.addEventListener('scroll', update, true);
108
+ return () => {
109
+ window.removeEventListener('resize', update);
110
+ window.removeEventListener('scroll', update, true);
111
+ };
112
+ }, [open, update]);
113
+
114
+ /* Measure again once the panel is drawn: on the first update it wasn't in the DOM and the side was a guess.
115
+ The dependency is the "drawn" boolean, not the style object, which is new on every update and would loop. */
116
+ const painted = panelStyle !== null;
117
+ React.useLayoutEffect(() => {
118
+ if (open && painted) update();
119
+ }, [open, painted, update]);
120
+
121
+ /*
122
+ * Close on an outside click.
123
+ *
124
+ * Three details; miss one and a click outside doesn't close it:
125
+ *
126
+ * 1. Listen on window in the capture phase, not on document while bubbling. React delegates events at the root
127
+ * container, so any `stopPropagation()` on the way stops the native event there and document never hears it.
128
+ * Capture runs down from window and nothing can stop it first.
129
+ * 2. pointerdown, not mousedown: pens and touch don't always synthesise mouse events.
130
+ * 3. Close on press, not release: from the press on, the popover is no longer what the person is dealing with.
131
+ *
132
+ * Values go through a ref, not the dependency array: `insideRefs` is an inline literal at call sites and
133
+ * `onOpenChange` is new each render, so listing them would re-attach the listeners on every render.
134
+ */
135
+ const latest = React.useRef({ onOpenChange, insideRefs });
136
+ latest.current = { onOpenChange, insideRefs };
137
+ React.useEffect(() => {
138
+ if (!open) return;
139
+ const close = (e: Event) => {
140
+ const t = e.target as Node;
141
+ if (e.type === 'pointerdown') {
142
+ if (ref.current?.contains(t) || panelRef.current?.contains(t)) return;
143
+ if (inModalLayer(t)) return;
144
+ for (const extra of latest.current.insideRefs) if (extra.current?.contains(t)) return;
145
+ }
146
+ latest.current.onOpenChange(false);
147
+ };
148
+ const onKey = (e: KeyboardEvent) => {
149
+ if (e.key !== 'Escape') return;
150
+ // With a modal open, Esc belongs to the modal, not to the popover beneath it.
151
+ if (document.querySelector(MODAL_LAYER)) return;
152
+ latest.current.onOpenChange(false);
153
+ };
154
+ window.addEventListener('pointerdown', close, true);
155
+ window.addEventListener('blur', close);
156
+ window.addEventListener('keydown', onKey);
157
+ return () => {
158
+ window.removeEventListener('pointerdown', close, true);
159
+ window.removeEventListener('blur', close);
160
+ window.removeEventListener('keydown', onKey);
161
+ };
162
+ }, [open]);
163
+
164
+ const panel =
165
+ open && panelStyle ? (
166
+ <div
167
+ ref={panelRef}
168
+ data-popover-panel="true"
169
+ style={
170
+ bare
171
+ ? panelStyle
172
+ : {
173
+ minWidth: 140,
174
+ ...panelStyle,
175
+ background: 'var(--bg-surface)',
176
+ border: '1px solid var(--border-strong)',
177
+ borderRadius: 16,
178
+ boxShadow: '0 16px 40px -8px rgba(0,0,0,0.4), 0 4px 12px rgba(0,0,0,0.18)',
179
+ overflowY: 'auto',
180
+ }
181
+ }
182
+ >
183
+ {children}
184
+ </div>
185
+ ) : null;
186
+
187
+ return (
188
+ <div ref={ref} className="inline-flex w-fit">
189
+ <div className="inline-flex w-fit" onMouseDown={keepFocus} onClick={() => onOpenChange(!open)}>
190
+ {trigger}
191
+ </div>
192
+ {typeof document !== 'undefined' && panel ? createPortal(panel, chatLayer()) : null}
193
+ </div>
194
+ );
195
+ }