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,292 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import { createPortal } from 'react-dom';
5
+ import { History, Plus } from 'lucide-react';
6
+ import { limitTitleWidth, SESSION_TITLE_MAX_WIDTH } from '@openfilm/shared';
7
+ import { Tooltip } from './Tooltip';
8
+ import { useT } from '@/i18n';
9
+ import {
10
+ groupSessionsByRecency,
11
+ type ProjectSessionItem,
12
+ type SessionRecencyKey,
13
+ } from '@/lib/project-sessions';
14
+ import { PANE_BAR, PANE_BTN, PANE_BTN_ON, PANE_ICON, PANE_TITLE } from './dock-pane-bar';
15
+ import { chatLayer } from '@/lib/chat-layer';
16
+
17
+ const RECENCY_I18N: Record<SessionRecencyKey, 'sidebar.searchToday' | 'sidebar.searchYesterday' | 'sidebar.searchPrevious7Days' | 'sidebar.searchEarlier'> = {
18
+ today: 'sidebar.searchToday',
19
+ yesterday: 'sidebar.searchYesterday',
20
+ week: 'sidebar.searchPrevious7Days',
21
+ earlier: 'sidebar.searchEarlier',
22
+ };
23
+
24
+ /**
25
+ * The title cell's maximum width.
26
+ *
27
+ * The title itself is already capped (SESSION_TITLE_MAX_WIDTH: 15 CJK or 30 Latin characters); this only keeps it
28
+ * from filling the bar. So it must be a little wider than those 30 characters, or a title within the cap gets cut
29
+ * while the bar has room to spare.
30
+ */
31
+ const TITLE_MAX = 'max-w-[15rem]';
32
+
33
+ /**
34
+ * The bar at the top of the conversation: the session's title on the left (none drawn without one), new and
35
+ * history on the right.
36
+ *
37
+ * The title comes from the first message, so it appears once something has been said. Clicking it renames, no
38
+ * separate pencil. The history popover has search on top and groups for today, yesterday, the past 7 days and
39
+ * earlier.
40
+ */
41
+ export function ConversationSessionBar({
42
+ sessions,
43
+ currentSessionId,
44
+ onNewSession,
45
+ onSelectSession,
46
+ onRenameSession,
47
+ busy = false,
48
+ }: {
49
+ sessions: ProjectSessionItem[];
50
+ currentSessionId: string;
51
+ /**
52
+ * A turn is running. A project runs one conversation at a time, so new and switch are off meanwhile; otherwise
53
+ * two agents would edit the same film.json in the same project folder. Both work again once the turn ends.
54
+ */
55
+ busy?: boolean;
56
+ onNewSession?: () => void;
57
+ onSelectSession?: (sessionId: string) => void;
58
+ onRenameSession?: (title: string) => Promise<void>;
59
+ }) {
60
+ const t = useT();
61
+ const current = sessions.find((item) => item.id === currentSessionId);
62
+ const label = current?.title.trim() ?? '';
63
+ const [renaming, setRenaming] = React.useState(false);
64
+ const [draft, setDraft] = React.useState(label);
65
+ const [historyPos, setHistoryPos] = React.useState<{ x: number; y: number } | null>(null);
66
+ const [query, setQuery] = React.useState('');
67
+ const searchRef = React.useRef<HTMLInputElement>(null);
68
+ const panelRef = React.useRef<HTMLDivElement>(null);
69
+
70
+ React.useEffect(() => {
71
+ setDraft(label);
72
+ setRenaming(false);
73
+ }, [label, currentSessionId]);
74
+
75
+ React.useEffect(() => {
76
+ if (!historyPos) return;
77
+ const close = () => setHistoryPos(null);
78
+ const onKey = (event: KeyboardEvent) => {
79
+ if (event.key === 'Escape') setHistoryPos(null);
80
+ };
81
+ const onScroll = (event: Event) => {
82
+ if (panelRef.current?.contains(event.target as Node)) return;
83
+ close();
84
+ };
85
+ window.addEventListener('click', close);
86
+ window.addEventListener('scroll', onScroll, true);
87
+ window.addEventListener('keydown', onKey);
88
+ window.addEventListener('resize', close);
89
+ const focus = window.setTimeout(() => searchRef.current?.focus(), 0);
90
+ return () => {
91
+ window.clearTimeout(focus);
92
+ window.removeEventListener('click', close);
93
+ window.removeEventListener('scroll', onScroll, true);
94
+ window.removeEventListener('keydown', onKey);
95
+ window.removeEventListener('resize', close);
96
+ };
97
+ }, [historyPos]);
98
+
99
+ React.useEffect(() => {
100
+ if (!historyPos) setQuery('');
101
+ }, [historyPos]);
102
+
103
+ /* A turn started while history is open: close it, none of its rows can be picked now. */
104
+ React.useEffect(() => {
105
+ if (busy) setHistoryPos(null);
106
+ }, [busy]);
107
+
108
+ const titleBoxRef = React.useRef<HTMLButtonElement | null>(null);
109
+ const [titleEditWidth, setTitleEditWidth] = React.useState<number | null>(null);
110
+
111
+ function startRename() {
112
+ if (!onRenameSession || !label) return;
113
+ const width = titleBoxRef.current?.getBoundingClientRect().width;
114
+ setTitleEditWidth(width && width > 0 ? width : null);
115
+ setDraft(label);
116
+ setRenaming(true);
117
+ }
118
+
119
+ async function commitRename() {
120
+ if (!onRenameSession) {
121
+ setRenaming(false);
122
+ return;
123
+ }
124
+ const clean = draft.replace(/\s+/g, ' ').trim();
125
+ setRenaming(false);
126
+ if (!clean || clean === label) {
127
+ setDraft(label);
128
+ return;
129
+ }
130
+ await onRenameSession(clean);
131
+ }
132
+
133
+ const listed = sessions.filter((item) => item.turns > 0);
134
+ const untitled = t('project.untitledSession');
135
+ const labelOf = (item: ProjectSessionItem) => item.title.trim() || untitled;
136
+ const needle = query.trim().toLowerCase();
137
+ const visible = needle
138
+ ? listed.filter((item) => labelOf(item).toLowerCase().includes(needle))
139
+ : listed;
140
+ const groups = groupSessionsByRecency(visible);
141
+
142
+ return (
143
+ <div className={PANE_BAR}>
144
+ {label ? (
145
+ renaming ? (
146
+ <input
147
+ autoFocus
148
+ value={draft}
149
+ onChange={(event) => {
150
+ const next = event.target.value;
151
+ if ((event.nativeEvent as InputEvent).isComposing) {
152
+ setDraft(next);
153
+ return;
154
+ }
155
+ setDraft(limitTitleWidth(next, SESSION_TITLE_MAX_WIDTH));
156
+ }}
157
+ onCompositionEnd={(event) => {
158
+ setDraft(limitTitleWidth(event.currentTarget.value, SESSION_TITLE_MAX_WIDTH));
159
+ }}
160
+ onBlur={() => void commitRename()}
161
+ onKeyDown={(event) => {
162
+ if (event.key === 'Enter') void commitRename();
163
+ if (event.key === 'Escape') {
164
+ setDraft(label);
165
+ setRenaming(false);
166
+ }
167
+ }}
168
+ style={titleEditWidth ? { width: titleEditWidth } : undefined}
169
+ className={`${TITLE_MAX} ${PANE_TITLE} box-border h-[22px] max-w-[min(15rem,calc(100%-52px))] bg-transparent px-1 outline-none`}
170
+ />
171
+ ) : onRenameSession ? (
172
+ <Tooltip label={t('projectMenu.rename')} side="bottom">
173
+ <button
174
+ ref={titleBoxRef}
175
+ type="button"
176
+ onClick={startRename}
177
+ className={`${TITLE_MAX} flex h-[22px] w-fit min-w-0 items-center rounded-md px-1 text-left transition hover:bg-[var(--bg-hover)]`}
178
+ >
179
+ <span title={label} className={PANE_TITLE}>
180
+ {label}
181
+ </span>
182
+ </button>
183
+ </Tooltip>
184
+ ) : (
185
+ <span
186
+ title={label}
187
+ className={`${TITLE_MAX} ${PANE_TITLE} px-1`}
188
+ >
189
+ {label}
190
+ </span>
191
+ )
192
+ ) : null}
193
+ <span className="min-w-0 flex-1" />
194
+ <div className="flex shrink-0 items-center gap-1">
195
+ {/* These buttons sit at the top edge, so tooltips open downwards. */}
196
+ {onNewSession ? (
197
+ <Tooltip label={busy ? t('project.sessionBusy') : t('projectMenu.newSession')} side="bottom">
198
+ <button
199
+ type="button"
200
+ aria-label={t('projectMenu.newSession')}
201
+ aria-disabled={busy || undefined}
202
+ onClick={busy ? undefined : onNewSession}
203
+ className={`${PANE_BTN} ${busy ? 'cursor-not-allowed opacity-40' : ''}`}
204
+ >
205
+ <Plus size={PANE_ICON} />
206
+ </button>
207
+ </Tooltip>
208
+ ) : null}
209
+ {onSelectSession ? (
210
+ <Tooltip label={busy ? t('project.sessionBusy') : t('project.sessionHistory')} side="bottom">
211
+ <button
212
+ type="button"
213
+ aria-label={t('project.sessionHistory')}
214
+ aria-expanded={historyPos != null}
215
+ aria-disabled={busy || undefined}
216
+ onClick={(event) => {
217
+ event.preventDefault();
218
+ event.stopPropagation();
219
+ if (busy) return;
220
+ const rect = event.currentTarget.getBoundingClientRect();
221
+ setHistoryPos((cur) => (cur ? null : { x: rect.right, y: rect.bottom + 4 }));
222
+ }}
223
+ className={`${PANE_BTN} ${historyPos ? PANE_BTN_ON : ''} ${busy ? 'cursor-not-allowed opacity-40' : ''}`}
224
+ >
225
+ <History size={PANE_ICON} />
226
+ </button>
227
+ </Tooltip>
228
+ ) : null}
229
+ </div>
230
+
231
+ {historyPos &&
232
+ typeof document !== 'undefined' &&
233
+ createPortal(
234
+ <div
235
+ ref={panelRef}
236
+ className="fixed z-[110] w-[216px] overflow-hidden rounded-md border border-[var(--border)] bg-[var(--surface)] shadow-[var(--shadow-lg)]"
237
+ style={{
238
+ right: Math.max(window.innerWidth - historyPos.x, 12),
239
+ top: historyPos.y,
240
+ animation: 'openfilm-rise 0.14s ease-out both',
241
+ }}
242
+ onClick={(event) => event.stopPropagation()}
243
+ >
244
+ <div className="px-2 pt-1">
245
+ <input
246
+ ref={searchRef}
247
+ value={query}
248
+ onChange={(event) => setQuery(event.target.value)}
249
+ placeholder={t('project.sessionSearchPlaceholder')}
250
+ className="h-5 w-full bg-transparent text-[11px] text-[var(--text)] outline-none placeholder:text-[var(--text-faint)]"
251
+ />
252
+ </div>
253
+ <div className="max-h-[min(320px,50vh)] overflow-y-auto pb-1">
254
+ {groups.length === 0 ? (
255
+ <div className="px-2 py-5 text-left text-[11px] text-[var(--text-faint)]">
256
+ {t('project.sessionHistoryEmpty')}
257
+ </div>
258
+ ) : (
259
+ groups.map((group) => (
260
+ <div key={group.key}>
261
+ <div className="px-2 pb-0.5 pt-1 text-left text-[10px] font-medium text-[var(--text-faint)]">
262
+ {t(RECENCY_I18N[group.key])}
263
+ </div>
264
+ {group.items.map((item) => {
265
+ const active = item.id === currentSessionId;
266
+ const name = labelOf(item);
267
+ return (
268
+ <button
269
+ key={item.id}
270
+ type="button"
271
+ onClick={() => {
272
+ setHistoryPos(null);
273
+ if (!active) onSelectSession?.(item.id);
274
+ }}
275
+ className={`mx-1 flex w-[calc(100%-8px)] items-center rounded-md px-1 py-[5px] text-left text-[12px] leading-tight transition hover:bg-[var(--bg-hover)] ${
276
+ active ? 'bg-[var(--bg-hover)] text-[var(--text)]' : 'text-[var(--text-muted)]'
277
+ }`}
278
+ >
279
+ <span className="min-w-0 flex-1 truncate">{name}</span>
280
+ </button>
281
+ );
282
+ })}
283
+ </div>
284
+ ))
285
+ )}
286
+ </div>
287
+ </div>,
288
+ chatLayer(),
289
+ )}
290
+ </div>
291
+ );
292
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * By a turn that failed: the diagnostic report on the clipboard, to paste into an issue (the app's main.mjs makes it:
3
+ * what OpenFilm finds on this computer, the last week's problems, the agents). Not shown by a shell that lacks it.
4
+ */
5
+ import React from 'react';
6
+ import { useT } from '@/i18n';
7
+ import { desktopBridge } from '@/lib/desktop-bridge';
8
+
9
+ export function CopyDiagnostics() {
10
+ const t = useT();
11
+ const copy = desktopBridge()?.agents?.copyReport;
12
+ const [state, setState] = React.useState<'idle' | 'making' | 'copied'>('idle');
13
+ if (!copy) return null;
14
+ const run = () => {
15
+ setState('making');
16
+ void copy().then((r) => setState(r.ok ? 'copied' : 'idle'), () => setState('idle'));
17
+ };
18
+ return (
19
+ <button type="button" onClick={run} disabled={state === 'making'} title={t('composer.copyDiagnosticsHint')}
20
+ className="underline underline-offset-2 hover:text-[var(--text)] disabled:opacity-60">
21
+ {state === 'copied' ? t('composer.diagnosticsCopied') : t('composer.copyDiagnostics')}
22
+ </button>
23
+ );
24
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The seam between Studio and the chat is the handle that sizes the chat, as Studio's own seams are (its
3
+ * PaneDivider): it draws nothing for a mouse (the cursor says it can be dragged, the panes say what is happening) and
4
+ * lights up only when reached by keyboard. The app owns the width (shell/bridge.ts keeps it within the window).
5
+ */
6
+ import React from 'react';
7
+ import { app as desktop } from '../app-bridge';
8
+
9
+ const STEP = 24;
10
+
11
+ /** the chat's column: its width is what the seam changes */
12
+ const columnWidth = (el: Element) => (el.closest('[data-studio-host-panel]') ?? el.parentElement ?? el).getBoundingClientRect().width;
13
+
14
+ export function Divider() {
15
+ const drag = React.useRef<{ x: number; width: number } | null>(null);
16
+ return (
17
+ <div
18
+ role="separator"
19
+ aria-orientation="vertical"
20
+ aria-label="Resize the chat"
21
+ tabIndex={0}
22
+ className="absolute bottom-0 left-0 top-0 z-20 w-[10px] cursor-col-resize outline-none focus-visible:bg-[var(--border-strong)]"
23
+ onPointerDown={(event) => {
24
+ if (event.button !== 0) return;
25
+ event.currentTarget.setPointerCapture(event.pointerId);
26
+ drag.current = { x: event.clientX, width: columnWidth(event.currentTarget) };
27
+ document.body.style.cursor = 'col-resize';
28
+ }}
29
+ onPointerMove={(event) => {
30
+ if (!drag.current) return;
31
+ desktop.setChatWidth(drag.current.width + (drag.current.x - event.clientX));
32
+ }}
33
+ onPointerUp={(event) => {
34
+ if (!drag.current) return;
35
+ desktop.setChatWidth(drag.current.width + (drag.current.x - event.clientX), true);
36
+ drag.current = null;
37
+ document.body.style.cursor = '';
38
+ }}
39
+ onPointerCancel={() => { drag.current = null; document.body.style.cursor = ''; }}
40
+ onKeyDown={(event) => {
41
+ if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
42
+ event.preventDefault();
43
+ desktop.setChatWidth(columnWidth(event.currentTarget) + (event.key === 'ArrowLeft' ? STEP : -STEP), true);
44
+ }}
45
+ />
46
+ );
47
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Under the agent's reply: what the turn changed in the project's files (lib/file-changes), as a coding agent's app
3
+ * lists them. One card, a row per file: its name, its lines added and removed, and on a click its changed lines. The
4
+ * first few rows show; the rest open from the last row. Settings → Developer turns it off.
5
+ */
6
+ import React from 'react';
7
+ import { ChevronRight, File, FileAudio, FileCode, FileImage, FileJson, FileText, FileVideo } from 'lucide-react';
8
+ import { useT } from '@/i18n';
9
+ import type { FileChange, FileHunk } from '@/lib/file-changes';
10
+ import { StickToBottomContext } from './useStickToBottom';
11
+
12
+ /** rows shown before "N more files" */
13
+ const ROWS_SHOWN = 4;
14
+
15
+ const ICONS: Array<[RegExp, typeof File]> = [
16
+ [/\.(html?|css|[cm]?js|jsx|tsx?|py|sh)$/i, FileCode],
17
+ [/\.json$/i, FileJson],
18
+ [/\.(md|txt|srt|vtt|csv|ya?ml|toml|xml)$/i, FileText],
19
+ [/\.(png|jpe?g|gif|webp|avif|svg)$/i, FileImage],
20
+ [/\.(mp3|m4a|wav|aac|ogg|flac|opus)$/i, FileAudio],
21
+ [/\.(mp4|mov|webm|mkv|m4v)$/i, FileVideo],
22
+ ];
23
+ const iconOf = (path: string) => ICONS.find(([test]) => test.test(path))?.[1] ?? File;
24
+
25
+ export function FileChangesList({ changes }: { changes: FileChange[] }) {
26
+ const t = useT();
27
+ const thread = React.useContext(StickToBottomContext);
28
+ const [all, setAll] = React.useState(false);
29
+ const shown = all ? changes : changes.slice(0, ROWS_SHOWN);
30
+ const hidden = changes.length - shown.length;
31
+ /* opening a row or the rest makes the reply taller: the thread stays where it is, as it does for the work summary */
32
+ const keepPlace = () => thread?.skipNextPin();
33
+
34
+ return (
35
+ <div className="min-w-0 overflow-hidden rounded-[10px] border border-[var(--border)]">
36
+ {shown.map((change, i) => (
37
+ <FileRow key={change.path} change={change} first={i === 0} onToggle={keepPlace} />
38
+ ))}
39
+ {hidden > 0 || changes.length > ROWS_SHOWN ? (
40
+ <button
41
+ type="button"
42
+ onClick={() => { keepPlace(); setAll((value) => !value); }}
43
+ className="flex h-9 w-full items-center border-t border-[var(--border)] px-3 text-left text-[12.5px] text-[var(--chat-hint)] transition-colors hover:bg-[var(--bg-hover)] hover:text-[var(--chat-text)]"
44
+ >
45
+ {hidden > 0 ? t('fileChanges.more').replace('{n}', String(hidden)) : t('fileChanges.fewer')}
46
+ </button>
47
+ ) : null}
48
+ </div>
49
+ );
50
+ }
51
+
52
+ function FileRow({ change, first, onToggle }: { change: FileChange; first: boolean; onToggle: () => void }) {
53
+ const t = useT();
54
+ const [open, setOpen] = React.useState(false);
55
+ const Icon = iconOf(change.path);
56
+ const slash = change.path.lastIndexOf('/');
57
+ const name = change.path.slice(slash + 1);
58
+ const folder = slash > 0 ? change.path.slice(0, slash) : '';
59
+ const lines = change.added != null || change.removed != null;
60
+ const canOpen = Boolean(change.hunks?.length);
61
+ const row = (
62
+ <>
63
+ <Icon size={14} aria-hidden className="shrink-0 text-[var(--chat-hint)]" />
64
+ <span className={`min-w-0 truncate text-[13px] text-[var(--chat-text)] ${change.change === 'removed' ? 'line-through opacity-70' : ''}`} title={change.path}>
65
+ {name}
66
+ {folder ? <span className="ml-1.5 text-[12px] text-[var(--chat-hint)]">{folder}</span> : null}
67
+ </span>
68
+ <span className="ml-auto flex shrink-0 items-center gap-1.5 pl-3 font-mono text-[12px] tabular-nums">
69
+ {lines ? (
70
+ <>
71
+ {change.added ? <span className="text-[var(--ok)]">+{change.added}</span> : null}
72
+ {change.removed ? <span className="text-[var(--err)]">−{change.removed}</span> : null}
73
+ </>
74
+ ) : (
75
+ <span className="font-sans text-[var(--chat-hint)]">{t(`fileChanges.${change.change}`)}</span>
76
+ )}
77
+ </span>
78
+ <ChevronRight size={13} aria-hidden className={`shrink-0 text-[var(--chat-hint)] transition-transform ${open ? 'rotate-90' : ''} ${canOpen ? '' : 'invisible'}`} />
79
+ </>
80
+ );
81
+ const shell = `flex h-9 w-full min-w-0 items-center gap-2 px-3 text-left ${first ? '' : 'border-t border-[var(--border)]'}`;
82
+ return (
83
+ <div className="min-w-0">
84
+ {canOpen ? (
85
+ <button type="button" aria-expanded={open} onClick={() => { onToggle(); setOpen((value) => !value); }}
86
+ className={`${shell} transition-colors hover:bg-[var(--bg-hover)]`}>
87
+ {row}
88
+ </button>
89
+ ) : <div className={shell}>{row}</div>}
90
+ {open && change.hunks ? <Hunks hunks={change.hunks} cut={change.cut === true} /> : null}
91
+ </div>
92
+ );
93
+ }
94
+
95
+ /* the changed lines as git shows them: each hunk's place, then its lines, removed (−) and added (+) */
96
+ function Hunks({ hunks, cut }: { hunks: FileHunk[]; cut: boolean }) {
97
+ const t = useT();
98
+ return (
99
+ <div className="max-h-[360px] min-w-0 overflow-auto border-t border-[var(--border)] font-mono text-[11.5px] leading-[18px]">
100
+ {hunks.map((hunk, i) => (
101
+ <React.Fragment key={i}>
102
+ <div className="w-max min-w-full whitespace-pre px-3 text-[var(--chat-hint)] opacity-80">
103
+ @@ −{hunk.oldStart},{hunk.oldLines} +{hunk.newStart},{hunk.newLines} @@
104
+ </div>
105
+ {hunk.lines.map((line, j) => {
106
+ const sign = line[0];
107
+ return (
108
+ <div key={j} className={`flex w-max min-w-full whitespace-pre pr-3 ${sign === '-' ? 'bg-[rgba(229,83,75,0.13)] text-[#e5534b]' : sign === '+' ? 'bg-[rgba(63,185,80,0.13)] text-[#3fb950]' : 'text-[var(--chat-hint)]'}`}>
109
+ <span aria-hidden className="w-6 shrink-0 select-none text-center opacity-80">{sign === '-' ? '−' : sign === '+' ? '+' : ''}</span>
110
+ <span>{line.slice(1)}</span>
111
+ </div>
112
+ );
113
+ })}
114
+ </React.Fragment>
115
+ ))}
116
+ {cut ? <div className="px-3 py-1 font-sans text-[12px] text-[var(--chat-hint)]">{t('fileChanges.cut')}</div> : null}
117
+ </div>
118
+ );
119
+ }
@@ -0,0 +1,198 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import {
5
+ parseInlineMarkdown,
6
+ rescanMarkdown,
7
+ type MarkdownBlock,
8
+ type MarkdownScan,
9
+ } from '@openfilm/shared/markdown';
10
+ import type { StudioRef } from '../app-bridge';
11
+ import { useT } from '@/i18n';
12
+ import { agentRefPill, parseAgentRefs } from '@/lib/agent-refs';
13
+ import { useClipSrc } from '@/lib/studio-film';
14
+ import { PromptPill, PromptPillRevealContext } from './prompt-editor';
15
+
16
+ /**
17
+ * Markdown in the conversation.
18
+ *
19
+ * This is speech, not a document page: the size matches the text rows around it (14px / 1.65, as tool rows and
20
+ * thoughts), blocks sit close together, headings differ only by weight and a touch of size, with no anchors or
21
+ * line numbers.
22
+ */
23
+ export function Markdown({ text, muted = false }: { text: string; muted?: boolean }) {
24
+ const blocks = useMarkdownBlocks(text);
25
+ if (!blocks.length) return null;
26
+ return (
27
+ <div className={`flex min-w-0 flex-col gap-2 text-[14px] leading-[1.65] ${muted ? 'text-[var(--chat-hint)]' : 'text-[var(--chat-text)]'}`}>
28
+ {blocks.map((block, index) => <MarkdownRow key={index} block={block} />)}
29
+ </div>
30
+ );
31
+ }
32
+
33
+ /**
34
+ * Incremental parsing, one cache per message.
35
+ *
36
+ * The text streams in token by token. Reparsing each frame isn't slow, but it makes new block objects, so every
37
+ * memoized MarkdownRow re-renders: near the end of a long reply, each token re-renders dozens of blocks.
38
+ * rescanMarkdown rescans only the part that can still change and keeps unchanged blocks as the same objects, so the
39
+ * memo works.
40
+ *
41
+ * Writing the ref is caching, not state: the same text always parses the same, so an interrupted render can't
42
+ * break it. Before continuing, the scan checks the old text is a prefix, and rescans everything if not.
43
+ */
44
+ function useMarkdownBlocks(text: string): MarkdownBlock[] {
45
+ const cache = React.useRef<MarkdownScan | null>(null);
46
+ const rows = React.useRef<MarkdownBlock[]>([]);
47
+ const next = rescanMarkdown(cache.current, text);
48
+ if (next !== cache.current) {
49
+ cache.current = next;
50
+ rows.current = next.blocks.map((entry) => entry.block);
51
+ }
52
+ return rows.current;
53
+ }
54
+
55
+ const MarkdownRow = React.memo(function MarkdownRow({ block }: { block: MarkdownBlock }) {
56
+ if (block.kind === 'heading') {
57
+ // No room for an h1 in a conversation: a heading only leads a few lines, a little top space is enough.
58
+ const cls = block.level <= 2
59
+ ? 'pt-1 text-[1.07em] font-semibold text-[var(--chat-text)]'
60
+ : 'pt-0.5 font-semibold text-[var(--chat-text)]';
61
+ return <p className={cls}>{inline(block.text)}</p>;
62
+ }
63
+ if (block.kind === 'paragraph') {
64
+ // In chat a single newline is a line break (not a space as in CommonMark): three lines the model wrote
65
+ // separately must not run into one sentence.
66
+ return <p className="whitespace-pre-wrap break-words">{inline(block.text)}</p>;
67
+ }
68
+ if (block.kind === 'quote') {
69
+ return (
70
+ <blockquote className="whitespace-pre-wrap break-words border-l-2 border-[var(--border)] pl-2.5 text-[var(--text-muted)]">
71
+ {inline(block.text)}
72
+ </blockquote>
73
+ );
74
+ }
75
+ if (block.kind === 'list') {
76
+ const Tag = block.ordered ? 'ol' : 'ul';
77
+ return (
78
+ <Tag
79
+ {...(block.ordered && block.start != null ? { start: block.start } : {})}
80
+ className={`flex flex-col gap-0.5 pl-[18px] marker:text-[var(--text-faint)] ${
81
+ block.ordered ? 'list-decimal' : 'list-disc'
82
+ }`}
83
+ >
84
+ {block.lines.map((line, index) => (
85
+ <li key={index} className="break-words">{inline(line)}</li>
86
+ ))}
87
+ </Tag>
88
+ );
89
+ }
90
+ if (block.kind === 'code') {
91
+ // No syntax highlighting: code blocks in chat are mostly a few lines of commands, not worth a highlighter
92
+ // in the bundle.
93
+ return (
94
+ <pre className="overflow-x-auto rounded-lg border border-[var(--border)] bg-[var(--surface-2)] px-2.5 py-2 font-mono text-[13.5px] leading-[1.55] text-[var(--text-dim)]">
95
+ <code>{block.text}</code>
96
+ </pre>
97
+ );
98
+ }
99
+ if (block.kind === 'table') {
100
+ const [head, ...body] = block.rows;
101
+ return (
102
+ <div className="overflow-x-auto rounded-lg border border-[var(--border)]">
103
+ <table className="w-full border-collapse text-left text-[14px]">
104
+ {head ? (
105
+ <thead className="bg-[var(--surface-2)]">
106
+ <tr>
107
+ {head.map((cell, index) => (
108
+ <th key={index} className="border-b border-[var(--border)] px-2 py-1 font-semibold">
109
+ {inline(cell)}
110
+ </th>
111
+ ))}
112
+ </tr>
113
+ </thead>
114
+ ) : null}
115
+ <tbody>
116
+ {body.map((row, rowIndex) => (
117
+ <tr key={rowIndex} className="border-b border-[var(--border)]/60 last:border-0">
118
+ {row.map((cell, cellIndex) => (
119
+ <td key={cellIndex} className="px-2 py-1 text-[var(--text-dim)]">{inline(cell)}</td>
120
+ ))}
121
+ </tr>
122
+ ))}
123
+ </tbody>
124
+ </table>
125
+ </div>
126
+ );
127
+ }
128
+ return <hr className="border-[var(--border)]" />;
129
+ });
130
+
131
+ function inline(text: string): React.ReactNode[] {
132
+ return parseInlineMarkdown(text).map((piece, index) => {
133
+ if (piece.kind === 'code') {
134
+ return (
135
+ <code key={index} className="rounded bg-[var(--surface-2)] px-1 py-0.5 font-mono text-[0.88em]">
136
+ {piece.text}
137
+ </code>
138
+ );
139
+ }
140
+ if (piece.kind === 'strong') return <strong key={index} className="font-semibold">{withRefs(piece.text)}</strong>;
141
+ if (piece.kind === 'em') return <em key={index} className="italic">{withRefs(piece.text)}</em>;
142
+ if (piece.kind === 'link') {
143
+ return (
144
+ <a
145
+ key={index}
146
+ href={piece.href}
147
+ // Always a new tab: a turn may be running here, and navigating away would lose it.
148
+ target="_blank"
149
+ rel="noopener noreferrer"
150
+ className="break-all text-[var(--accent)] underline underline-offset-2 hover:opacity-80"
151
+ >
152
+ {piece.text}
153
+ </a>
154
+ );
155
+ }
156
+ return <React.Fragment key={index}>{withRefs(piece.text)}</React.Fragment>;
157
+ });
158
+ }
159
+
160
+ /**
161
+ * The agent's words with what it points at in Studio as pills (lib/agent-refs: `[[clip:s3]]`, `[[t:13.6]]`…). Only
162
+ * in words: what it writes in code stays code, a token there being an example, not a reference.
163
+ */
164
+ function withRefs(text: string): React.ReactNode {
165
+ if (!text.includes('[[')) return text;
166
+ const segments = parseAgentRefs(text);
167
+ if (segments.length === 1 && segments[0]!.kind === 'text') return text;
168
+ return segments.map((segment, index) => (segment.kind === 'text'
169
+ ? <React.Fragment key={index}>{segment.text}</React.Fragment>
170
+ : <AgentRefPill key={index} studioRef={segment.ref} />));
171
+ }
172
+
173
+ /** A thing an agent pointed at: read-only, its hover card as a sent pill's, a click shows it in Studio. */
174
+ function AgentRefPill({ studioRef }: { studioRef: StudioRef }) {
175
+ const t = useT();
176
+ const ctx = React.useContext(PromptPillRevealContext);
177
+ const clipSrc = useClipSrc(studioRef.kind === 'clip' ? studioRef.id : null);
178
+ const reference = React.useMemo(
179
+ () => agentRefPill(studioRef, { clipSrc, trackLabel: (n) => t('agentRef.track').replace('{n}', String(n)) }),
180
+ [studioRef, clipSrc, t],
181
+ );
182
+ const reveal = ctx?.onReveal;
183
+ const label = ctx?.revealLabel;
184
+ return (
185
+ <PromptPill
186
+ reference={reference}
187
+ card={ctx?.describe?.(reference) ?? null}
188
+ {...(reveal && label ? { hint: label, title: `${reference.label} · ${label}` } : {})}
189
+ {...(reveal ? {
190
+ onClick: (event: React.MouseEvent) => {
191
+ event.preventDefault();
192
+ event.stopPropagation();
193
+ reveal(reference);
194
+ },
195
+ } : {})}
196
+ />
197
+ );
198
+ }