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,206 @@
1
+ /**
2
+ * The `@` menu (and the `/` menu of the agent's commands): when typing counts as an `@` or a `/`, which items show,
3
+ * and in what order.
4
+ *
5
+ * Pure logic; the Lexical half is in MentionMenuPlugin. Kept apart so these rules can be
6
+ * tested on plain strings: an email address opening the menu, or the best match ranked
7
+ * eighth, raises no error.
8
+ */
9
+ import type React from 'react';
10
+ import type { PromptReference, PromptReferenceKind } from './prompt-text';
11
+
12
+ /**
13
+ * One menu item.
14
+ *
15
+ * It does not know whether it stands for a moment or a file; the provider does. Here it
16
+ * is only an icon, a label, what typing finds it, and the reference it yields.
17
+ */
18
+ export interface MentionItem {
19
+ /** Unique in the menu. The id of the reference it will become is simplest. */
20
+ id: string;
21
+ /** The kind of reference it yields; the menu draws the same icon as the pill. */
22
+ kind: PromptReferenceKind;
23
+ label: string;
24
+ /** The small text after the label: a file size, a timecode. */
25
+ detail?: string;
26
+ /** Other words that find it besides the label: English aliases, the full path. */
27
+ keywords?: string[];
28
+ /** Not usable now; with no film yet, there is no current time. */
29
+ disabled?: boolean;
30
+ /** Why it is not usable; a gray item without a reason looks broken. */
31
+ disabledHint?: string;
32
+ /** The detail is a description (an agent's command): the label keeps its width, the detail is cut. */
33
+ describes?: boolean;
34
+ /** Its own icon, instead of its kind's (an agent's command). */
35
+ icon?: React.ComponentType<{ size?: number; className?: string }>;
36
+ /**
37
+ * Picks it: records what it needs and returns how it appears in the sentence, possibly
38
+ * several references (the current selection is every selected thing), or plain text
39
+ * (`{ text }`: an agent's command). Null or empty means it failed (too many references,
40
+ * or the thing is gone).
41
+ */
42
+ select: () => PromptReference | PromptReference[] | { text: string } | null;
43
+ }
44
+
45
+ /**
46
+ * A group of things `@` can pick.
47
+ *
48
+ * The menu only knows groups, not moments or files. Something new to mention is a new
49
+ * provider in the array.
50
+ */
51
+ export interface MentionProvider {
52
+ /** The group's id, used as the render key; unique within one menu. */
53
+ id: string;
54
+ /** The group title, already localized; this layer has no i18n. */
55
+ groupLabel: string;
56
+ items: MentionItem[];
57
+ }
58
+
59
+ /** One menu row: the item, its group, and whether the group title goes above it. */
60
+ export interface MentionEntry {
61
+ item: MentionItem;
62
+ providerId: string;
63
+ groupLabel: string;
64
+ firstOfGroup: boolean;
65
+ }
66
+
67
+ /** The longest query after `@`; anything longer is an ordinary @ in the text. */
68
+ const MAX_QUERY_CHARS = 32;
69
+
70
+ /* ASCII characters of an email local part: after one of them, `@` does not open the
71
+ menu, so typing a@b.com is not taken as a mention.
72
+ Deliberately looser than "`@` must follow whitespace or line start": Chinese and
73
+ Japanese text has no spaces, so `@` must work right after a word there. */
74
+ const EMAIL_LOCAL_CHAR = /[A-Za-z0-9._%+-]/;
75
+
76
+ export interface MentionTrigger {
77
+ /** The index of `@` in the text; the popup anchors there and replacement starts there. */
78
+ leadOffset: number;
79
+ /** What has been typed after `@`, used to filter. */
80
+ query: string;
81
+ /** The text replaced on pick, including `@`. */
82
+ replaceableString: string;
83
+ }
84
+
85
+ /**
86
+ * Whether the text before the caret ends in an `@` being typed.
87
+ *
88
+ * Only the last `@` counts: earlier ones are already pills or ordinary characters.
89
+ */
90
+ export function matchMentionTrigger(textBeforeCursor: string): MentionTrigger | null {
91
+ const at = textBeforeCursor.lastIndexOf('@');
92
+ if (at < 0) return null;
93
+ const before = at > 0 ? textBeforeCursor[at - 1]! : '';
94
+ if (before && EMAIL_LOCAL_CHAR.test(before)) return null;
95
+ const query = textBeforeCursor.slice(at + 1);
96
+ /* Whitespace ends the mention: file names can have spaces, but what follows a space is
97
+ usually the next word, and a lingering menu would cover it. */
98
+ if (query.length > MAX_QUERY_CHARS || /\s/.test(query)) return null;
99
+ return { leadOffset: at, query, replaceableString: textBeforeCursor.slice(at) };
100
+ }
101
+
102
+ /**
103
+ * Whether the message so far is a `/` being typed at its very start: an agent's command, as in its own chat (`/` in
104
+ * the middle of a sentence is a path or a fraction). The query is what follows, up to the first space.
105
+ */
106
+ export function matchSlashTrigger(textBeforeCursor: string): MentionTrigger | null {
107
+ const m = /^\s*\/([^\s/]{0,40})$/.exec(textBeforeCursor);
108
+ if (!m) return null;
109
+ const at = textBeforeCursor.indexOf('/');
110
+ return { leadOffset: at, query: m[1]!, replaceableString: textBeforeCursor.slice(at) };
111
+ }
112
+
113
+ /* Ranking: prefix < word start < substring < subsequence (other characters in between).
114
+ Within a tier, an earlier match ranks higher: "video" at position 3 of my-video.mp4
115
+ beats position 20 of a-really-long-name-video.mp4.
116
+ Both are packed into one number: tier × TIER_STEP + match position. */
117
+ const TIER_STEP = 1000;
118
+ const TIER_PREFIX = 0;
119
+ const TIER_WORD = 1;
120
+ const TIER_SUBSTRING = 2;
121
+ const TIER_SUBSEQUENCE = 3;
122
+
123
+ /** Characters that separate words in file names: `-`, `_`, `.` and path separators start a word. */
124
+ const WORD_BOUNDARY = /[\s._\-/\\]/;
125
+
126
+ /**
127
+ * How well the text matches the query; lower is better, null is no match.
128
+ *
129
+ * The last tier is a subsequence (`bgm` matches `background-music.mp3`): file names are
130
+ * long and hard to remember, so a few remembered letters should be enough.
131
+ */
132
+ export function scoreMentionText(text: string, query: string): number | null {
133
+ if (!query) return TIER_PREFIX * TIER_STEP;
134
+ const haystack = text.toLowerCase();
135
+ const needle = query.toLowerCase();
136
+ if (haystack.startsWith(needle)) return TIER_PREFIX * TIER_STEP;
137
+ const index = haystack.indexOf(needle);
138
+ if (index >= 0) {
139
+ const tier = WORD_BOUNDARY.test(haystack[index - 1] ?? '') ? TIER_WORD : TIER_SUBSTRING;
140
+ return tier * TIER_STEP + Math.min(index, TIER_STEP - 1);
141
+ }
142
+ const start = subsequenceStart(haystack, needle);
143
+ return start == null ? null : TIER_SUBSEQUENCE * TIER_STEP + Math.min(start, TIER_STEP - 1);
144
+ }
145
+
146
+ /** Matches if every character of the query appears in order; returns where the first one is. */
147
+ function subsequenceStart(haystack: string, needle: string): number | null {
148
+ let start: number | null = null;
149
+ let cursor = 0;
150
+ for (const char of needle) {
151
+ const found = haystack.indexOf(char, cursor);
152
+ if (found < 0) return null;
153
+ if (start == null) start = found;
154
+ cursor = found + 1;
155
+ }
156
+ return start;
157
+ }
158
+
159
+ /** Tries the label and every keyword and keeps the best score. */
160
+ export function scoreMentionItem(item: MentionItem, query: string): number | null {
161
+ let best: number | null = null;
162
+ for (const text of [item.label, ...(item.keywords ?? [])]) {
163
+ const score = scoreMentionText(text, query);
164
+ if (score != null && (best == null || score < best)) best = score;
165
+ }
166
+ return best;
167
+ }
168
+
169
+ /** The most rows the menu shows; with hundreds of files, typing a little more beats scrolling. */
170
+ export const MENTION_MENU_LIMIT = 20;
171
+
172
+ /**
173
+ * Flattens the providers into the menu's rows.
174
+ *
175
+ * Groups stay together, each one kind of thing; sorting happens only within a group.
176
+ */
177
+ export function buildMentionMenu(
178
+ providers: MentionProvider[],
179
+ query: string,
180
+ limit: number = MENTION_MENU_LIMIT,
181
+ ): MentionEntry[] {
182
+ const entries: MentionEntry[] = [];
183
+ for (const provider of providers) {
184
+ provider.items
185
+ .map((item, order) => ({ item, order, score: scoreMentionItem(item, query) }))
186
+ .filter((row): row is { item: MentionItem; order: number; score: number } => row.score != null)
187
+ .sort((a, b) => {
188
+ /* Disabled items sink to the bottom of their group: they must not push down a
189
+ usable item or be picked by Enter. */
190
+ if (!!a.item.disabled !== !!b.item.disabled) return a.item.disabled ? 1 : -1;
191
+ if (a.score !== b.score) return a.score - b.score;
192
+ // Ties keep the provider's order (files come newest first).
193
+ return a.order - b.order;
194
+ })
195
+ .forEach((row, index) => {
196
+ entries.push({
197
+ item: row.item,
198
+ providerId: provider.id,
199
+ groupLabel: provider.groupLabel,
200
+ firstOfGroup: index === 0,
201
+ });
202
+ });
203
+ }
204
+ /* Cut from the end, so every remaining group keeps its first row and title. */
205
+ return entries.slice(0, limit);
206
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * References on the editor side: splitting markers, unknown markers, and what they
3
+ * expand to on send.
4
+ *
5
+ * The marker and a reference's stored shape live in `prompt-reference` in
6
+ * `@openfilm/shared`: the text with markers is stored, so it is a shared contract.
7
+ */
8
+ import {
9
+ splitPromptReferenceText,
10
+ type PromptReference as StoredPromptReference,
11
+ } from '@openfilm/shared';
12
+
13
+ export {
14
+ promptReferenceToken,
15
+ splitPromptReferenceText,
16
+ stripPromptReferenceTokens,
17
+ type PromptTextSegment,
18
+ } from '@openfilm/shared';
19
+
20
+ /**
21
+ * A reference in the editor.
22
+ *
23
+ * It does not know whether it is an element, a region or a clip; the host translates
24
+ * that. Here it is only an icon, a label, and who handles a click.
25
+ *
26
+ * The shape lives in @openfilm/shared; this narrows `kind` to the kinds the icon table
27
+ * knows, since every pill inserted here needs an icon, while stored references can have
28
+ * kinds this UI does not know (see `promptReferenceSchema`).
29
+ */
30
+ export interface PromptReference extends StoredPromptReference {
31
+ kind: PromptReferenceKind;
32
+ }
33
+
34
+ /**
35
+ * clip* = a whole clip on the timeline (an MG, a voice line), unlike time (a moment).
36
+ * file = a file in the project workspace; on send it becomes a path (see below).
37
+ * card = a canvas card. The sentence holds a pointer; the content is read on send.
38
+ * skill = a way of working (a package), not something in the film.
39
+ * range = a span of the film (in to out on the timeline); track = a whole timeline track.
40
+ * subtitle = a subtitle line (or some of its words), with its time in the film.
41
+ *
42
+ * Clips are six kinds rather than one `clip` only for their icons, so an MG, a video and
43
+ * a voice line in one sentence look different.
44
+ */
45
+ export type PromptReferenceKind =
46
+ | 'element' | 'region' | 'time' | 'range' | 'track' | 'subtitle' | 'showcase' | 'file' | 'card' | 'skill' | 'example'
47
+ | 'clipMg' | 'clipVideo' | 'clipVoice' | 'clipSfx' | 'clipMusic' | 'clipCaption';
48
+
49
+ /* The id prefix of a file reference, followed by the workspace-relative path, which is
50
+ all the reference holds. It is in the id rather than a separate table because the
51
+ agent needs exactly that path (to read it, or put it in <video src>), so the text
52
+ carries it with no translation on send. */
53
+ const FILE_REFERENCE_PREFIX = 'file:';
54
+
55
+ export function fileReferenceId(path: string): string {
56
+ return `${FILE_REFERENCE_PREFIX}${path}`;
57
+ }
58
+
59
+ /** Null if not a file reference (or the path is empty). */
60
+ export function fileReferencePath(id: string): string | null {
61
+ if (!id.startsWith(FILE_REFERENCE_PREFIX)) return null;
62
+ return id.slice(FILE_REFERENCE_PREFIX.length) || null;
63
+ }
64
+
65
+ /* The id prefix of a skill reference, followed by the package name (as imported). As
66
+ with files, the name is all the reference holds, so it expands without the host, even
67
+ for a draft restored from localStorage with no references loaded. */
68
+ const SKILL_REFERENCE_PREFIX = 'skill:';
69
+
70
+ export function skillReferenceId(packageName: string): string {
71
+ return `${SKILL_REFERENCE_PREFIX}${packageName}`;
72
+ }
73
+
74
+ /** Null if not a skill reference (or the package name is empty). */
75
+ export function skillReferencePackage(id: string): string | null {
76
+ if (!id.startsWith(SKILL_REFERENCE_PREFIX)) return null;
77
+ return id.slice(SKILL_REFERENCE_PREFIX.length) || null;
78
+ }
79
+
80
+ /** The skill packages this message names, deduplicated, in order. */
81
+ export function activatedSkillIds(
82
+ references: readonly { id: string }[] | undefined,
83
+ ): string[] {
84
+ if (!references?.length) return [];
85
+ const seen = new Set<string>();
86
+ const out: string[] = [];
87
+ for (const ref of references) {
88
+ const name = skillReferencePackage(ref.id);
89
+ if (!name || seen.has(name)) continue;
90
+ seen.add(name);
91
+ out.push(name);
92
+ }
93
+ return out;
94
+ }
95
+
96
+ /**
97
+ * Replaces the markers in the text with what the model reads.
98
+ *
99
+ * `render` gets the index of the reference's first appearance (from 1), in the same order
100
+ * as the references sent with the request, which is how the prompt lists the referenced
101
+ * context. That is how the model knows which item "make this blue" means.
102
+ *
103
+ * `render` returning null means unknown (a draft restored from localStorage with no
104
+ * references loaded, or an undo bringing back a sent pill): it is dropped and takes no
105
+ * number. The numbers must match collectPromptReferences exactly; an off-by-one raises
106
+ * no error, it just makes the model edit the wrong thing.
107
+ *
108
+ * File references are the exception: they become the path in the id, skip `render`, and
109
+ * take no number. No render, because a path needs no translation, and after a draft
110
+ * restore render would drop it as unknown. No number, because files are not in the
111
+ * references sent with the request (that list holds only timestamp, region and element),
112
+ * so numbering them would shift every later reference.
113
+ *
114
+ * `verbatim` opens the same exception to others: any reference that explains itself and
115
+ * is not in that list expands as is, without a number. Canvas cards use it.
116
+ */
117
+ export function resolvePromptReferences(
118
+ text: string,
119
+ render: (id: string, index: number) => string | null,
120
+ verbatim?: (id: string) => string | null,
121
+ ): string {
122
+ const order = new Map<string, number>();
123
+ let out = '';
124
+ for (const segment of splitPromptReferenceText(text)) {
125
+ if (segment.kind === 'text') {
126
+ out += segment.value;
127
+ continue;
128
+ }
129
+ const { id } = segment;
130
+ const path = fileReferencePath(id);
131
+ if (path) {
132
+ out += path;
133
+ continue;
134
+ }
135
+ const raw = verbatim?.(id);
136
+ if (raw != null) {
137
+ out += raw;
138
+ continue;
139
+ }
140
+ const seen = order.get(id);
141
+ if (seen != null) {
142
+ out += render(id, seen) ?? '';
143
+ continue;
144
+ }
145
+ const next = order.size + 1;
146
+ const rendered = render(id, next);
147
+ if (rendered == null) continue;
148
+ order.set(id, next);
149
+ out += rendered;
150
+ }
151
+ return out;
152
+ }
153
+
154
+ /** The references used in the text, deduplicated, in order; the order is the numbering. */
155
+ export function collectPromptReferences(
156
+ text: string,
157
+ lookup: (id: string) => PromptReference | undefined,
158
+ ): PromptReference[] {
159
+ const seen = new Set<string>();
160
+ const out: PromptReference[] = [];
161
+ for (const segment of splitPromptReferenceText(text)) {
162
+ if (segment.kind === 'text') continue;
163
+ const { id } = segment;
164
+ if (seen.has(id)) continue;
165
+ seen.add(id);
166
+ const reference = lookup(id);
167
+ /* Unknown markers are dropped rather than kept as empty references. */
168
+ if (reference) out.push(reference);
169
+ }
170
+ return out;
171
+ }
@@ -0,0 +1,320 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+
5
+ /**
6
+ * Keeps the conversation pinned to its latest line unless the user scrolls up.
7
+ *
8
+ * Re-renders are the wrong trigger: a streaming answer, an image finishing decoding, a
9
+ * code block reflowing, a finished turn collapsing into a summary, or the composer
10
+ * growing all change height without a new turn. So this watches size instead: a
11
+ * ResizeObserver on the viewport and the content re-pins whenever either changes height
12
+ * (the same approach as the use-stick-to-bottom library).
13
+ *
14
+ * Scrolling up releases the pin; scrolling back to the bottom resumes it. The release is
15
+ * decided on `wheel`, not `scroll`: while content grows every frame and the observer
16
+ * re-pins every frame, waiting for `scroll` makes the wheel feel stuck.
17
+ */
18
+
19
+ /** How long the glide to the bottom takes after sending: visible, but no wait. */
20
+ const GLIDE_MS = 360;
21
+
22
+ /** How close to the bottom still counts as "at the bottom": about one line. */
23
+ const NEAR_BOTTOM_PX = 96;
24
+
25
+ export type StickToBottom = {
26
+ /**
27
+ * Goes on the overflow-y-auto box.
28
+ *
29
+ * A callback ref, not a ref object: the viewport may mount after the hook (the project
30
+ * shows a loading screen first). A ref object would not notify anyone, so the
31
+ * subscription would try once on the first frame, miss, and never follow.
32
+ */
33
+ viewportRef: (node: HTMLDivElement | null) => void;
34
+ /** The viewport box itself, for other hooks (the tail spacer) to measure. */
35
+ viewport: HTMLDivElement | null;
36
+ /** Goes on the box that wraps all messages (a callback ref, so a swapped content box is picked up). */
37
+ contentRef: (node: HTMLDivElement | null) => void;
38
+ /** Whether the view is at the bottom now; decides whether "Back to latest" shows. */
39
+ atBottom: boolean;
40
+ /**
41
+ * Pins to the bottom again and resumes following. Called on send and on "Back to latest".
42
+ *
43
+ * `smooth` glides instead of jumping, since a jump looks like a page reload. The glide
44
+ * re-measures the bottom every frame, because the new bubble and the spacer grow meanwhile.
45
+ */
46
+ scrollToBottom: (opts?: { smooth?: boolean }) => void;
47
+ /**
48
+ * If following, pins again at the current height now. Does not change following.
49
+ *
50
+ * For content that grows or shrinks at the bottom while the viewport stays the same,
51
+ * such as the padding under the asset drawer. Waiting for the observer would be one
52
+ * frame late, which shows as a flash when the drawer closes.
53
+ */
54
+ pinIfFollowing: () => void;
55
+ /**
56
+ * Skips pinning on the next height change and stops following, unless the view is
57
+ * still at the bottom once the change settles.
58
+ *
59
+ * Expanding or collapsing a summary changes height, and the observer would pin back to
60
+ * the bottom, pulling away the row the user just clicked.
61
+ */
62
+ skipNextPin: () => void;
63
+ };
64
+
65
+ export const StickToBottomContext = React.createContext<StickToBottom | null>(null);
66
+
67
+ /**
68
+ * While a turn runs, it may grow but not shrink.
69
+ *
70
+ * Finished tool rows collapse into a summary while the answer keeps growing; that
71
+ * shrink would make the bottom-pinned view bounce back. So the running turn gets a
72
+ * min-height equal to the tallest it has been, released when the run ends.
73
+ *
74
+ * The min-height only applies when the turn shrinks, so it is never a frame late: the
75
+ * value was recorded while the turn grew.
76
+ */
77
+ export function useTailSpacer(
78
+ viewport: HTMLDivElement | null,
79
+ pinIfFollowing: () => void,
80
+ active = false,
81
+ ): { lastTurnRef: (node: HTMLDivElement | null) => void } {
82
+ const lastTurn = React.useRef<HTMLDivElement | null>(null);
83
+ const observer = React.useRef<ResizeObserver | null>(null);
84
+ const activeRef = React.useRef(active);
85
+ activeRef.current = active;
86
+ const tallest = React.useRef(0);
87
+ const viewportSize = React.useRef('');
88
+
89
+ const measure = React.useCallback(() => {
90
+ const node = lastTurn.current;
91
+ if (!viewport || !node) return;
92
+ const size = `${viewport.clientWidth}:${viewport.clientHeight}`;
93
+ if (viewportSize.current !== size) { tallest.current = 0; viewportSize.current = size; }
94
+ let min = 0;
95
+ if (activeRef.current) {
96
+ tallest.current = Math.max(tallest.current, node.getBoundingClientRect().height);
97
+ min = Math.max(min, Math.floor(tallest.current));
98
+ } else tallest.current = 0;
99
+ const next = min > 0 ? `${min}px` : '';
100
+ if (node.style.minHeight !== next) {
101
+ node.style.minHeight = next;
102
+ pinIfFollowing();
103
+ }
104
+ }, [viewport, pinIfFollowing]);
105
+
106
+ React.useLayoutEffect(() => { measure(); }, [active, measure]);
107
+
108
+ React.useLayoutEffect(() => {
109
+ if (!viewport) return undefined;
110
+ const ro = new ResizeObserver(() => measure());
111
+ observer.current = ro;
112
+ ro.observe(viewport);
113
+ if (lastTurn.current) ro.observe(lastTurn.current);
114
+ measure();
115
+ return () => {
116
+ observer.current = null;
117
+ ro.disconnect();
118
+ };
119
+ }, [measure, viewport]);
120
+
121
+ /* A callback ref: each new turn becomes the last one, so the previous turn's min-height
122
+ is cleared and the observer moves to the new box. */
123
+ const lastTurnRef = React.useCallback((node: HTMLDivElement | null) => {
124
+ const previous = lastTurn.current;
125
+ if (previous && previous !== node) {
126
+ observer.current?.unobserve(previous);
127
+ previous.style.minHeight = '';
128
+ tallest.current = 0;
129
+ }
130
+ lastTurn.current = node;
131
+ if (node) observer.current?.observe(node);
132
+ measure();
133
+ }, [measure]);
134
+
135
+ return { lastTurnRef };
136
+ }
137
+
138
+ export function useStickToBottom(): StickToBottom {
139
+ /* The node is kept twice: the ref for synchronous reads in callbacks, the state so the
140
+ subscription below re-attaches when the viewport finally mounts. */
141
+ const viewportNode = React.useRef<HTMLDivElement | null>(null);
142
+ const [viewport, setViewport] = React.useState<HTMLDivElement | null>(null);
143
+ const viewportRef = React.useCallback((node: HTMLDivElement | null) => {
144
+ viewportNode.current = node;
145
+ setViewport(node);
146
+ }, []);
147
+ const contentNode = React.useRef<HTMLDivElement | null>(null);
148
+ const observer = React.useRef<ResizeObserver | null>(null);
149
+ /* Following lives in a ref, not state: the observer reads it every frame and needs the
150
+ current value, while state in its closure would be last frame's snapshot. */
151
+ const following = React.useRef(true);
152
+ const [atBottom, setAtBottom] = React.useState(true);
153
+
154
+ /* While gliding, the glide pins each frame; the observer must not jump it to the end. */
155
+ const glide = React.useRef<number | null>(null);
156
+ const pin = React.useCallback(() => {
157
+ const el = viewportNode.current;
158
+ if (glide.current != null) return;
159
+ // Overshoot and let the browser clamp to scrollHeight - clientHeight. Computing it
160
+ // ourselves is half a pixel short at fractional scaling (125% displays).
161
+ if (el) el.scrollTop = el.scrollHeight;
162
+ }, []);
163
+ const stopGlide = React.useCallback(() => {
164
+ if (glide.current != null) cancelAnimationFrame(glide.current);
165
+ glide.current = null;
166
+ }, []);
167
+
168
+ const scrollToBottom = React.useCallback((opts?: { smooth?: boolean }) => {
169
+ following.current = true;
170
+ setAtBottom(true);
171
+ stopGlide();
172
+ const el = viewportNode.current;
173
+ const reduced = typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
174
+ if (!el || !opts?.smooth || reduced) { pin(); return; }
175
+ const from = el.scrollTop;
176
+ const started = performance.now();
177
+ const step = (now: number) => {
178
+ const k = Math.min(1, (now - started) / GLIDE_MS);
179
+ const eased = 1 - (1 - k) ** 3;
180
+ const target = el.scrollHeight - el.clientHeight;
181
+ if (!following.current) { glide.current = null; return; }
182
+ if (k >= 1) { glide.current = null; el.scrollTop = el.scrollHeight; return; }
183
+ el.scrollTop = from + (target - from) * eased;
184
+ glide.current = requestAnimationFrame(step);
185
+ };
186
+ glide.current = requestAnimationFrame(step);
187
+ }, [pin, stopGlide]);
188
+
189
+ const pinIfFollowing = React.useCallback(() => {
190
+ if (following.current) pin();
191
+ }, [pin]);
192
+
193
+ const skipPin = React.useRef(false);
194
+ const skipGen = React.useRef(0);
195
+ const skipNextPin = React.useCallback(() => {
196
+ skipPin.current = true;
197
+ following.current = false;
198
+ const gen = ++skipGen.current;
199
+ /* The content grows on the click frame and the spacer shrinks on the next, so both
200
+ observations are skipped. On repeated clicks only the last one counts. */
201
+ requestAnimationFrame(() => {
202
+ requestAnimationFrame(() => {
203
+ if (skipGen.current !== gen) return;
204
+ skipPin.current = false;
205
+ /* Still at the very bottom: nothing went below the view (the running turn's
206
+ min-height took the change), so keep following and hide "Jump to latest". */
207
+ const el = viewportNode.current;
208
+ if (el && el.scrollHeight - el.scrollTop - el.clientHeight <= 2) {
209
+ following.current = true;
210
+ setAtBottom(true);
211
+ }
212
+ });
213
+ });
214
+ }, []);
215
+
216
+ /* The content box can be swapped (empty state and conversation list), so a callback ref
217
+ moves the observer to the new box. `observe` fires once right away, which pins. */
218
+ const contentRef = React.useCallback((node: HTMLDivElement | null) => {
219
+ if (contentNode.current) observer.current?.unobserve(contentNode.current);
220
+ contentNode.current = node;
221
+ if (node) observer.current?.observe(node);
222
+ }, []);
223
+
224
+ /* Re-subscribes whenever the viewport changes (first mount or a replaced tree); that is
225
+ why `viewport` is a dependency. */
226
+ React.useLayoutEffect(() => {
227
+ const el = viewport;
228
+ if (!el) return undefined;
229
+
230
+ const nearBottom = () => el.scrollHeight - el.scrollTop - el.clientHeight <= NEAR_BOTTOM_PX;
231
+ let previousTop = el.scrollTop;
232
+ const sync = () => {
233
+ const near = nearBottom();
234
+ const top = el.scrollTop;
235
+ /* During a glide the bottom can move up (a turn collapsed) and scrollTop with it; that is not the user scrolling up */
236
+ if (glide.current == null && top < previousTop - 1 && el.scrollHeight - top - el.clientHeight > 2) following.current = false;
237
+ // Resizes and our own pin also emit scroll events. Only a downward user
238
+ // scroll all the way to the bottom resumes following after an upward wheel.
239
+ if (!following.current && top > previousTop && el.scrollHeight - top - el.clientHeight <= 2) {
240
+ following.current = true;
241
+ }
242
+ previousTop = top;
243
+ /* A collapse at the bottom clamps scrollTop; during the skip that is not leaving the bottom */
244
+ setAtBottom((following.current || skipPin.current) && near);
245
+ };
246
+ const release = () => {
247
+ // When the content does not scroll yet, a wheel up does nothing and does not release.
248
+ if (el.scrollHeight <= el.clientHeight + 1) return;
249
+ stopGlide();
250
+ following.current = false;
251
+ setAtBottom(false);
252
+ };
253
+
254
+ const onWheel = (e: WheelEvent) => {
255
+ if (e.deltaY < 0) release();
256
+ };
257
+ let lastTouchY = 0;
258
+ const onTouchStart = (e: TouchEvent) => {
259
+ lastTouchY = e.touches[0]?.clientY ?? 0;
260
+ };
261
+ const onTouchMove = (e: TouchEvent) => {
262
+ const y = e.touches[0]?.clientY ?? 0;
263
+ if (y > lastTouchY + 2) release();
264
+ lastTouchY = y;
265
+ };
266
+
267
+ el.addEventListener('scroll', sync, { passive: true });
268
+ el.addEventListener('wheel', onWheel, { passive: true });
269
+ el.addEventListener('touchstart', onTouchStart, { passive: true });
270
+ el.addEventListener('touchmove', onTouchMove, { passive: true });
271
+
272
+ const ro = new ResizeObserver(() => {
273
+ if (skipPin.current) {
274
+ /* Only update `atBottom`; do not resume following or clear the flag. This height
275
+ change came from a click, not from content growing; sync() would resume
276
+ following while still at the bottom, and the spacer frame would pin again. */
277
+ const near = el.scrollHeight - el.scrollTop - el.clientHeight <= NEAR_BOTTOM_PX;
278
+ setAtBottom((was) => (was === near ? was : near));
279
+ return;
280
+ }
281
+ if (following.current) pin();
282
+ /* Not following (a row was expanded): show "Jump to latest" once new content goes below the view */
283
+ else if (el.scrollHeight - el.scrollTop - el.clientHeight > NEAR_BOTTOM_PX) setAtBottom(false);
284
+ });
285
+ observer.current = ro;
286
+ ro.observe(el);
287
+ if (contentNode.current) ro.observe(contentNode.current);
288
+ pin();
289
+
290
+ return () => {
291
+ observer.current = null;
292
+ ro.disconnect();
293
+ el.removeEventListener('scroll', sync);
294
+ el.removeEventListener('wheel', onWheel);
295
+ el.removeEventListener('touchstart', onTouchStart);
296
+ el.removeEventListener('touchmove', onTouchMove);
297
+ };
298
+ }, [pin, stopGlide, viewport]);
299
+
300
+ return React.useMemo(
301
+ () => ({
302
+ viewportRef,
303
+ viewport,
304
+ contentRef,
305
+ atBottom,
306
+ scrollToBottom,
307
+ pinIfFollowing,
308
+ skipNextPin,
309
+ }),
310
+ [
311
+ viewportRef,
312
+ viewport,
313
+ contentRef,
314
+ atBottom,
315
+ scrollToBottom,
316
+ pinIfFollowing,
317
+ skipNextPin,
318
+ ],
319
+ );
320
+ }