@opengeni/react 1.0.1 → 1.0.2-canary.37202341988001

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 (632) hide show
  1. package/README.md +660 -21
  2. package/dist/accounts.d.ts +64 -0
  3. package/dist/accounts.js +822 -0
  4. package/dist/accounts.js.map +1 -0
  5. package/dist/approvals.d.ts +2 -1
  6. package/dist/artifacts-document.js +3 -2
  7. package/dist/artifacts-presentation.js +3 -2
  8. package/dist/artifacts-spreadsheet.js +2 -2
  9. package/dist/artifacts.d.ts +4 -1
  10. package/dist/artifacts.js +518 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-SHYKQRNX.js +16 -0
  13. package/dist/capability-catalog-row.d.ts +20 -0
  14. package/dist/capability-logo-fallback.d.ts +3 -0
  15. package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
  16. package/dist/chat-interactive-block-UGBTNB3L.js.map +1 -0
  17. package/dist/chunk-26ZNDDLZ.js +453 -0
  18. package/dist/chunk-26ZNDDLZ.js.map +1 -0
  19. package/dist/chunk-3CTRFMAK.js +359 -0
  20. package/dist/chunk-3CTRFMAK.js.map +1 -0
  21. package/dist/chunk-447JLCBU.js +209 -0
  22. package/dist/chunk-447JLCBU.js.map +1 -0
  23. package/dist/chunk-4RVYOY4O.js +379 -0
  24. package/dist/chunk-4RVYOY4O.js.map +1 -0
  25. package/dist/chunk-5CVXZA3Y.js +292 -0
  26. package/dist/chunk-5CVXZA3Y.js.map +1 -0
  27. package/dist/chunk-5J4FOW6Q.js +108 -0
  28. package/dist/chunk-5J4FOW6Q.js.map +1 -0
  29. package/dist/chunk-742CZ3L3.js +481 -0
  30. package/dist/chunk-742CZ3L3.js.map +1 -0
  31. package/dist/chunk-A2PI6UMY.js +41 -0
  32. package/dist/chunk-A2PI6UMY.js.map +1 -0
  33. package/dist/{chunk-7WCLAEFV.js → chunk-A4UJB2MM.js} +37 -27
  34. package/dist/chunk-A4UJB2MM.js.map +1 -0
  35. package/dist/chunk-B3V6TG77.js +41 -0
  36. package/dist/chunk-B3V6TG77.js.map +1 -0
  37. package/dist/chunk-BRM6FVZA.js +302 -0
  38. package/dist/chunk-BRM6FVZA.js.map +1 -0
  39. package/dist/chunk-C5X5AJXK.js +182 -0
  40. package/dist/chunk-C5X5AJXK.js.map +1 -0
  41. package/dist/{chunk-6KLX2RH5.js → chunk-DO544OSV.js} +1075 -79
  42. package/dist/chunk-DO544OSV.js.map +1 -0
  43. package/dist/{chunk-R3AZOAB5.js → chunk-DYWBUX5Q.js} +29 -123
  44. package/dist/chunk-DYWBUX5Q.js.map +1 -0
  45. package/dist/{chunk-HA46CYQK.js → chunk-EESD3PY3.js} +792 -537
  46. package/dist/chunk-EESD3PY3.js.map +1 -0
  47. package/dist/{chunk-5UQPNLIO.js → chunk-EN3YTHKR.js} +4117 -3896
  48. package/dist/chunk-EN3YTHKR.js.map +1 -0
  49. package/dist/chunk-ERGYJIBB.js +21 -0
  50. package/dist/chunk-ERGYJIBB.js.map +1 -0
  51. package/dist/chunk-FZCP527Y.js +116 -0
  52. package/dist/chunk-FZCP527Y.js.map +1 -0
  53. package/dist/chunk-GIMRELBW.js +14 -0
  54. package/dist/chunk-GIMRELBW.js.map +1 -0
  55. package/dist/chunk-GYVRFZDY.js +2733 -0
  56. package/dist/chunk-GYVRFZDY.js.map +1 -0
  57. package/dist/{chunk-LLOLUHVG.js → chunk-HDJWDK7W.js} +1358 -2746
  58. package/dist/chunk-HDJWDK7W.js.map +1 -0
  59. package/dist/chunk-I7IWRQLN.js +1608 -0
  60. package/dist/chunk-I7IWRQLN.js.map +1 -0
  61. package/dist/chunk-IT4BJUGF.js +13055 -0
  62. package/dist/chunk-IT4BJUGF.js.map +1 -0
  63. package/dist/chunk-IWIDV7SB.js +1 -0
  64. package/dist/chunk-IWIDV7SB.js.map +1 -0
  65. package/dist/chunk-J2QWVSQY.js +312 -0
  66. package/dist/chunk-J2QWVSQY.js.map +1 -0
  67. package/dist/chunk-J6DBS4T3.js +371 -0
  68. package/dist/chunk-J6DBS4T3.js.map +1 -0
  69. package/dist/{chunk-B6WPZSTT.js → chunk-JIQYUGVL.js} +1331 -1163
  70. package/dist/chunk-JIQYUGVL.js.map +1 -0
  71. package/dist/chunk-JT4JW7BC.js +54 -0
  72. package/dist/chunk-JT4JW7BC.js.map +1 -0
  73. package/dist/chunk-K3HQAKQX.js +24 -0
  74. package/dist/chunk-K3HQAKQX.js.map +1 -0
  75. package/dist/{chunk-PEI6RANI.js → chunk-PNY3JKBJ.js} +309 -74
  76. package/dist/chunk-PNY3JKBJ.js.map +1 -0
  77. package/dist/chunk-RHREZ7BO.js +11 -0
  78. package/dist/chunk-RHREZ7BO.js.map +1 -0
  79. package/dist/chunk-RLUSC2WA.js +299 -0
  80. package/dist/chunk-RLUSC2WA.js.map +1 -0
  81. package/dist/{chunk-IGC6A2ZI.js → chunk-RSI7XYXL.js} +777 -246
  82. package/dist/chunk-RSI7XYXL.js.map +1 -0
  83. package/dist/chunk-SCOTPE2I.js +589 -0
  84. package/dist/chunk-SCOTPE2I.js.map +1 -0
  85. package/dist/{chunk-C5ZPSSS5.js → chunk-TKOTKRWY.js} +5 -4
  86. package/dist/{chunk-C5ZPSSS5.js.map → chunk-TKOTKRWY.js.map} +1 -1
  87. package/dist/chunk-TMYGL6X5.js +742 -0
  88. package/dist/chunk-TMYGL6X5.js.map +1 -0
  89. package/dist/chunk-UGLEYEMP.js +33 -0
  90. package/dist/chunk-UGLEYEMP.js.map +1 -0
  91. package/dist/chunk-UK4TINKT.js +27 -0
  92. package/dist/chunk-UK4TINKT.js.map +1 -0
  93. package/dist/chunk-UTRTG6LH.js +220 -0
  94. package/dist/chunk-UTRTG6LH.js.map +1 -0
  95. package/dist/chunk-WEHMPOXK.js +39 -0
  96. package/dist/chunk-WEHMPOXK.js.map +1 -0
  97. package/dist/chunk-WGXVEJO5.js +319 -0
  98. package/dist/chunk-WGXVEJO5.js.map +1 -0
  99. package/dist/chunk-WRHIZYZF.js +988 -0
  100. package/dist/chunk-WRHIZYZF.js.map +1 -0
  101. package/dist/{chunk-HUIKIDM5.js → chunk-WUISZ3WU.js} +223 -115
  102. package/dist/chunk-WUISZ3WU.js.map +1 -0
  103. package/dist/chunk-XCHWDJ22.js +107 -0
  104. package/dist/chunk-XCHWDJ22.js.map +1 -0
  105. package/dist/{chunk-KCGXPP5V.js → chunk-Y2PRMYLC.js} +11 -6
  106. package/dist/chunk-Y2PRMYLC.js.map +1 -0
  107. package/dist/chunk-YBXQDQFX.js +1772 -0
  108. package/dist/chunk-YBXQDQFX.js.map +1 -0
  109. package/dist/chunk-YM2DE7BQ.js +3124 -0
  110. package/dist/chunk-YM2DE7BQ.js.map +1 -0
  111. package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
  112. package/dist/chunk-YQEAA6LT.js.map +1 -0
  113. package/dist/chunk-YV4L3ILF.js +9 -0
  114. package/dist/chunk-YV4L3ILF.js.map +1 -0
  115. package/dist/chunk-ZYRGEKWS.js +216 -0
  116. package/dist/chunk-ZYRGEKWS.js.map +1 -0
  117. package/dist/client.d.ts +7 -4
  118. package/dist/clipboard.js +1 -0
  119. package/dist/commands/types.d.ts +2 -0
  120. package/dist/components/anthropic-mark.d.ts +3 -0
  121. package/dist/components/approval-surface.d.ts +15 -0
  122. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  123. package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
  124. package/dist/components/artifacts/artifact-surface.d.ts +3 -1
  125. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  126. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  127. package/dist/components/artifacts/document-editor.d.ts +4 -2
  128. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  129. package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
  130. package/dist/components/artifacts/editable-document.d.ts +1 -1
  131. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  132. package/dist/components/artifacts/editable-spreadsheet.d.ts +2 -1
  133. package/dist/components/artifacts/index.d.ts +8 -1
  134. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  135. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  136. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  137. package/dist/components/artifacts/published-html-artifact-frame.d.ts +48 -3
  138. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  139. package/dist/components/artifacts/site-view.d.ts +23 -0
  140. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  141. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  142. package/dist/components/browser-select-control.d.ts +16 -0
  143. package/dist/components/browser-viewer.d.ts +10 -1
  144. package/dist/components/chat-composer.d.ts +21 -3
  145. package/dist/components/child-session-link.d.ts +5 -0
  146. package/dist/components/claude-mark.d.ts +3 -0
  147. package/dist/components/code-editor.d.ts +1 -4
  148. package/dist/components/composer.d.ts +45 -4
  149. package/dist/components/computer-viewer.d.ts +4 -1
  150. package/dist/components/copy-button.d.ts +3 -1
  151. package/dist/components/desktop-viewer.d.ts +1 -1
  152. package/dist/components/enrollment-consent.d.ts +6 -3
  153. package/dist/components/file-browser.d.ts +10 -1
  154. package/dist/components/fleet-tile.d.ts +2 -2
  155. package/dist/components/grok-mark.d.ts +26 -0
  156. package/dist/components/human-input-form.d.ts +21 -2
  157. package/dist/components/human-input-surface.d.ts +6 -3
  158. package/dist/components/machine-card.d.ts +4 -1
  159. package/dist/components/machines/machine-detail.d.ts +4 -1
  160. package/dist/components/machines/machine-operation-policy.d.ts +11 -0
  161. package/dist/components/machines-dashboard.d.ts +3 -1
  162. package/dist/components/markdown-table-layout.d.ts +12 -0
  163. package/dist/components/markdown.d.ts +47 -3
  164. package/dist/components/message-timeline.d.ts +72 -9
  165. package/dist/components/model-mark.d.ts +29 -0
  166. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  167. package/dist/components/model-policy-picker.d.ts +62 -13
  168. package/dist/components/open-geni-chat.d.ts +58 -0
  169. package/dist/components/open-geni-links.d.ts +68 -0
  170. package/dist/components/openrouter-mark.d.ts +6 -0
  171. package/dist/components/pierre-file.d.ts +1 -1
  172. package/dist/components/preview-loading.d.ts +2 -0
  173. package/dist/components/queue-item-content.d.ts +9 -0
  174. package/dist/components/sandbox-files.d.ts +13 -2
  175. package/dist/components/sandbox-workspace.d.ts +43 -3
  176. package/dist/components/session-capability-frame.d.ts +35 -0
  177. package/dist/components/session-chrome.d.ts +66 -8
  178. package/dist/components/session-commands-panel.d.ts +6 -0
  179. package/dist/components/session-commands.d.ts +6 -0
  180. package/dist/components/session-connection-request.d.ts +8 -0
  181. package/dist/components/session-conversation.d.ts +89 -0
  182. package/dist/components/session-list.d.ts +36 -0
  183. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  184. package/dist/components/session-proxy-scope.d.ts +21 -0
  185. package/dist/components/timeline-anchor.d.ts +24 -0
  186. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  187. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  188. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  189. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  190. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  191. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  192. package/dist/components/timeline-annotations.d.ts +13 -3
  193. package/dist/components/timeline-reading-progress.d.ts +11 -0
  194. package/dist/components/timeline-search.d.ts +34 -0
  195. package/dist/components/timeline-settlement.d.ts +16 -0
  196. package/dist/components/tip-follow.d.ts +16 -0
  197. package/dist/components/usage-limit-notice.d.ts +49 -0
  198. package/dist/components/usage-member-list.d.ts +91 -0
  199. package/dist/components/usage-meter.d.ts +73 -0
  200. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  201. package/dist/components/user-message-body.d.ts +10 -1
  202. package/dist/components/workspace-dock.d.ts +6 -2
  203. package/dist/composer.d.ts +5 -4
  204. package/dist/composer.js +15 -9
  205. package/dist/computer-viewer-6SRGWRUX.js +19 -0
  206. package/dist/computer-viewer-6SRGWRUX.js.map +1 -0
  207. package/dist/connect-account-identity.d.ts +8 -0
  208. package/dist/connect-accounts.d.ts +15 -0
  209. package/dist/connect-chooser.d.ts +18 -0
  210. package/dist/connect-panel.d.ts +18 -0
  211. package/dist/connect-setup.d.ts +16 -0
  212. package/dist/connect.d.ts +21 -0
  213. package/dist/connect.js +2129 -0
  214. package/dist/connect.js.map +1 -0
  215. package/dist/connection-catalog.d.ts +38 -0
  216. package/dist/connection-discovery.d.ts +12 -0
  217. package/dist/connection-installed.d.ts +17 -0
  218. package/dist/connection-logo.d.ts +9 -0
  219. package/dist/connection-service-logo.d.ts +8 -0
  220. package/dist/connection-service-presentation.d.ts +13 -0
  221. package/dist/connection-skeleton.d.ts +5 -0
  222. package/dist/connection-type-picker.d.ts +6 -0
  223. package/dist/conversation-timeline.d.ts +5 -0
  224. package/dist/desktop.d.ts +7 -0
  225. package/dist/desktop.js +26 -0
  226. package/dist/desktop.js.map +1 -0
  227. package/dist/device-authorization.d.ts +23 -0
  228. package/dist/diffs.d.ts +8 -0
  229. package/dist/diffs.js +14 -0
  230. package/dist/diffs.js.map +1 -0
  231. package/dist/discovery-cache.d.ts +5 -0
  232. package/dist/editor.d.ts +7 -0
  233. package/dist/editor.js +21 -0
  234. package/dist/editor.js.map +1 -0
  235. package/dist/embedded-session-client.d.ts +23 -0
  236. package/dist/file-node-visibility.d.ts +15 -0
  237. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-YZ3ZKWMM.js} +2 -1
  238. package/dist/fleet-decision-row-YZ3ZKWMM.js.map +1 -0
  239. package/dist/hooks/channel-cache.d.ts +23 -0
  240. package/dist/hooks/latest-question.d.ts +25 -0
  241. package/dist/hooks/shared-machines-list.d.ts +14 -0
  242. package/dist/hooks/use-attached-browsers.d.ts +2 -1
  243. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  244. package/dist/hooks/use-browser-session.d.ts +12 -1
  245. package/dist/hooks/use-channels.d.ts +1 -0
  246. package/dist/hooks/use-codex-accounts.d.ts +25 -7
  247. package/dist/hooks/use-composer.d.ts +45 -9
  248. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  249. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  250. package/dist/hooks/use-computer-session.d.ts +2 -0
  251. package/dist/hooks/use-connect.d.ts +22 -0
  252. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  253. package/dist/hooks/use-file-attachments.d.ts +21 -2
  254. package/dist/hooks/use-machine-chip.d.ts +3 -3
  255. package/dist/hooks/use-machines.d.ts +19 -1
  256. package/dist/hooks/use-sandbox-files.d.ts +5 -1
  257. package/dist/hooks/use-session-background-commands.d.ts +14 -0
  258. package/dist/hooks/use-session-events.d.ts +30 -8
  259. package/dist/hooks/use-session-lineage.d.ts +4 -0
  260. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  261. package/dist/hooks/use-session.d.ts +6 -0
  262. package/dist/hooks/use-turn-queue.d.ts +12 -0
  263. package/dist/hooks/use-usage.d.ts +40 -0
  264. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  265. package/dist/hooks/use-workspace-sessions.d.ts +27 -5
  266. package/dist/human-input.d.ts +3 -1
  267. package/dist/identity-link-accounts.d.ts +11 -0
  268. package/dist/identity-link-consent.d.ts +18 -0
  269. package/dist/index.d.ts +60 -17
  270. package/dist/index.js +2238 -6201
  271. package/dist/index.js.map +1 -1
  272. package/dist/interaction.d.ts +1 -1
  273. package/dist/interaction.js +35 -184
  274. package/dist/interaction.js.map +1 -1
  275. package/dist/latest-question-HTRIS4KJ.js +117 -0
  276. package/dist/latest-question-HTRIS4KJ.js.map +1 -0
  277. package/dist/lib/error-message.d.ts +7 -0
  278. package/dist/lib/format.d.ts +36 -2
  279. package/dist/lib/host-theme.d.ts +70 -0
  280. package/dist/lib/interaction-errors.d.ts +6 -0
  281. package/dist/lib/menu-styles.d.ts +22 -0
  282. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  283. package/dist/lib/workbench-peers.d.ts +36 -0
  284. package/dist/lib/xterm-theme.d.ts +7 -5
  285. package/dist/machines.d.ts +4 -2
  286. package/dist/machines.js +14 -4
  287. package/dist/markdown-table-layout-QXSLK4BY.js +106 -0
  288. package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
  289. package/dist/mcp-connection-status.d.ts +14 -0
  290. package/dist/model-policy-picker-menu-M54ISBMN.js +14 -0
  291. package/dist/model-policy-picker-menu-M54ISBMN.js.map +1 -0
  292. package/dist/model-policy.d.ts +19 -3
  293. package/dist/model-policy.js +9 -1
  294. package/dist/older-history.d.ts +30 -0
  295. package/dist/platform-activity-row-627BFZ46.js +182 -0
  296. package/dist/platform-activity-row-627BFZ46.js.map +1 -0
  297. package/dist/plugin-details.d.ts +14 -0
  298. package/dist/plugin-discovery.d.ts +25 -0
  299. package/dist/provider.d.ts +13 -1
  300. package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-ZHFI5JBP.js} +131 -44
  301. package/dist/queue-surface-implementation-ZHFI5JBP.js.map +1 -0
  302. package/dist/realtime/realtime-control.d.ts +6 -3
  303. package/dist/realtime.js +133 -74
  304. package/dist/realtime.js.map +1 -1
  305. package/dist/sandbox-files-GORZOUUJ.js +20 -0
  306. package/dist/sandbox-files-GORZOUUJ.js.map +1 -0
  307. package/dist/session-auth-recommendation.d.ts +5 -0
  308. package/dist/session-capability-policy.d.ts +12 -0
  309. package/dist/session-ui.d.ts +30 -2
  310. package/dist/session-ui.js +85 -7
  311. package/dist/session-ui.js.map +1 -1
  312. package/dist/session.d.ts +8 -2
  313. package/dist/session.js +30 -19
  314. package/dist/sites-ui.d.ts +34 -0
  315. package/dist/sites.d.ts +3 -0
  316. package/dist/sites.js +11 -0
  317. package/dist/sites.js.map +1 -0
  318. package/dist/skill-discovery.d.ts +47 -0
  319. package/dist/terminal.d.ts +8 -0
  320. package/dist/terminal.js +31 -0
  321. package/dist/terminal.js.map +1 -0
  322. package/dist/timeline/activity-rail.d.ts +11 -2
  323. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  324. package/dist/timeline/compaction-copy.d.ts +10 -0
  325. package/dist/timeline/entrance.d.ts +13 -1
  326. package/dist/timeline/genie-loading.d.ts +34 -0
  327. package/dist/timeline/index.d.ts +6 -2
  328. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  329. package/dist/timeline/platform-activity-row.d.ts +14 -0
  330. package/dist/timeline/presented-image.d.ts +6 -0
  331. package/dist/timeline/projection.d.ts +31 -2
  332. package/dist/timeline/registry.d.ts +2 -0
  333. package/dist/timeline/retained-image.d.ts +18 -0
  334. package/dist/timeline/rolling-activity.d.ts +11 -0
  335. package/dist/timeline/screenshot-lightbox.d.ts +16 -1
  336. package/dist/timeline/shared.d.ts +8 -3
  337. package/dist/timeline/startup-preference.d.ts +3 -0
  338. package/dist/timeline/startup-timings.d.ts +4 -0
  339. package/dist/timeline/tool-display-name.d.ts +2 -1
  340. package/dist/timeline/turn-summary.d.ts +34 -3
  341. package/dist/timeline/types.d.ts +147 -7
  342. package/dist/timeline-annotation-markers-GNDHTGBD.js +165 -0
  343. package/dist/timeline-annotation-markers-GNDHTGBD.js.map +1 -0
  344. package/dist/timeline-annotation-selection-DMLMM2TX.js +241 -0
  345. package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
  346. package/dist/timeline-annotations-dialog-ELRDBHTS.js +273 -0
  347. package/dist/timeline-annotations-dialog-ELRDBHTS.js.map +1 -0
  348. package/dist/types/machines.d.ts +2 -2
  349. package/dist/usage/allowance-copy.d.ts +25 -0
  350. package/dist/usage/summary.d.ts +35 -0
  351. package/dist/usage.d.ts +13 -0
  352. package/dist/usage.js +1074 -0
  353. package/dist/usage.js.map +1 -0
  354. package/package.json +44 -4
  355. package/src/accounts.tsx +1072 -0
  356. package/src/approvals.ts +8 -1
  357. package/src/artifacts.ts +42 -0
  358. package/src/assets/README.md +8 -0
  359. package/src/assets/gmail.ico +0 -0
  360. package/src/assets/outlook.ico +0 -0
  361. package/src/capability-catalog-row.tsx +94 -0
  362. package/src/capability-logo-fallback.ts +22 -0
  363. package/src/client.ts +22 -13
  364. package/src/commands/registry.ts +18 -15
  365. package/src/commands/types.ts +2 -0
  366. package/src/components/anthropic-mark.tsx +10 -0
  367. package/src/components/approval-surface.tsx +171 -37
  368. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  369. package/src/components/artifacts/artifact-sandbox.tsx +185 -0
  370. package/src/components/artifacts/artifact-surface.tsx +39 -19
  371. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  372. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  373. package/src/components/artifacts/document-editor.tsx +141 -16
  374. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  375. package/src/components/artifacts/editable-artifact-view.tsx +187 -0
  376. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  377. package/src/components/artifacts/editable-document.tsx +37 -36
  378. package/src/components/artifacts/editable-presentation.tsx +36 -18
  379. package/src/components/artifacts/editable-spreadsheet.tsx +5 -2
  380. package/src/components/artifacts/index.ts +44 -0
  381. package/src/components/artifacts/inline-html-document.ts +24 -0
  382. package/src/components/artifacts/latest-task-runner.ts +49 -0
  383. package/src/components/artifacts/presentation-editor.tsx +323 -67
  384. package/src/components/artifacts/published-html-artifact-frame.tsx +338 -5
  385. package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
  386. package/src/components/artifacts/site-view.tsx +116 -0
  387. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  388. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  389. package/src/components/artifacts/spreadsheet-grid.tsx +12 -13
  390. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  391. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  392. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  393. package/src/components/browser-select-control.tsx +312 -0
  394. package/src/components/browser-viewer.tsx +1054 -314
  395. package/src/components/chat-composer.tsx +131 -85
  396. package/src/components/child-session-link.tsx +27 -0
  397. package/src/components/claude-mark.tsx +10 -0
  398. package/src/components/code-editor.tsx +13 -16
  399. package/src/components/composer-transcription-control.tsx +7 -5
  400. package/src/components/composer.tsx +376 -49
  401. package/src/components/computer-viewer.tsx +1041 -329
  402. package/src/components/copy-button.tsx +13 -5
  403. package/src/components/desktop-viewer.tsx +1 -1
  404. package/src/components/enrollment-consent.tsx +65 -7
  405. package/src/components/enrollment-device-flow.tsx +1 -1
  406. package/src/components/file-browser.tsx +158 -34
  407. package/src/components/fleet-tile.tsx +8 -16
  408. package/src/components/generated-video-player.tsx +4 -2
  409. package/src/components/grok-mark.tsx +33 -0
  410. package/src/components/human-input-form.tsx +455 -114
  411. package/src/components/human-input-surface.tsx +18 -7
  412. package/src/components/interaction-intervention-banner.tsx +2 -2
  413. package/src/components/machine-card.tsx +119 -4
  414. package/src/components/machine-dock-bar.tsx +1 -1
  415. package/src/components/machine-input-display.ts +23 -2
  416. package/src/components/machines/machine-detail.tsx +52 -2
  417. package/src/components/machines/machine-operation-policy.tsx +179 -0
  418. package/src/components/machines-dashboard.tsx +8 -17
  419. package/src/components/markdown-table-layout.ts +132 -0
  420. package/src/components/markdown.tsx +473 -44
  421. package/src/components/message-timeline.tsx +2754 -665
  422. package/src/components/model-mark.tsx +90 -0
  423. package/src/components/model-picker.tsx +15 -4
  424. package/src/components/model-policy-picker-menu.tsx +424 -0
  425. package/src/components/model-policy-picker.tsx +337 -381
  426. package/src/components/open-geni-chat.tsx +338 -0
  427. package/src/components/open-geni-links.tsx +179 -0
  428. package/src/components/openrouter-mark.tsx +13 -0
  429. package/src/components/pierre-diff.tsx +41 -16
  430. package/src/components/pierre-file.tsx +36 -11
  431. package/src/components/preview-loading.tsx +154 -0
  432. package/src/components/queue-item-content.ts +14 -0
  433. package/src/components/queue-surface-implementation.tsx +132 -42
  434. package/src/components/queue-surface-state.tsx +3 -1
  435. package/src/components/sandbox-files.tsx +267 -35
  436. package/src/components/sandbox-terminal.tsx +48 -11
  437. package/src/components/sandbox-workspace.tsx +337 -135
  438. package/src/components/session-capability-frame.tsx +192 -0
  439. package/src/components/session-chrome.tsx +1027 -328
  440. package/src/components/session-commands-panel.tsx +126 -0
  441. package/src/components/session-commands.tsx +18 -0
  442. package/src/components/session-connection-request.tsx +97 -0
  443. package/src/components/session-conversation.tsx +526 -0
  444. package/src/components/session-list.tsx +250 -0
  445. package/src/components/session-mcp-capability-card.tsx +680 -0
  446. package/src/components/session-proxy-scope.tsx +92 -0
  447. package/src/components/session-status.tsx +1 -1
  448. package/src/components/timeline-anchor.tsx +119 -0
  449. package/src/components/timeline-annotation-chrome.tsx +196 -0
  450. package/src/components/timeline-annotation-layout.ts +268 -0
  451. package/src/components/timeline-annotation-markers.tsx +185 -0
  452. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  453. package/src/components/timeline-annotation-selection.tsx +106 -54
  454. package/src/components/timeline-annotation-shared.ts +245 -0
  455. package/src/components/timeline-annotations-dialog.tsx +185 -128
  456. package/src/components/timeline-annotations.tsx +189 -45
  457. package/src/components/timeline-reading-progress.ts +80 -0
  458. package/src/components/timeline-search.tsx +168 -0
  459. package/src/components/timeline-settlement.ts +60 -0
  460. package/src/components/tip-follow.ts +70 -7
  461. package/src/components/tooltip.tsx +38 -5
  462. package/src/components/usage-limit-notice.tsx +179 -0
  463. package/src/components/usage-member-list.tsx +792 -0
  464. package/src/components/usage-meter.tsx +382 -0
  465. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  466. package/src/components/user-message-body.tsx +194 -49
  467. package/src/components/workspace-dock.tsx +141 -175
  468. package/src/composer.ts +6 -1
  469. package/src/connect-account-identity.tsx +34 -0
  470. package/src/connect-accounts.tsx +233 -0
  471. package/src/connect-chooser.tsx +336 -0
  472. package/src/connect-panel.tsx +99 -0
  473. package/src/connect-setup.tsx +307 -0
  474. package/src/connect.ts +60 -0
  475. package/src/connection-assets.d.ts +4 -0
  476. package/src/connection-catalog.tsx +162 -0
  477. package/src/connection-discovery.tsx +235 -0
  478. package/src/connection-installed.tsx +51 -0
  479. package/src/connection-logo.tsx +37 -0
  480. package/src/connection-service-logo.tsx +55 -0
  481. package/src/connection-service-presentation.ts +46 -0
  482. package/src/connection-skeleton.tsx +16 -0
  483. package/src/connection-type-picker.tsx +36 -0
  484. package/src/conversation-timeline.ts +92 -0
  485. package/src/desktop.ts +24 -0
  486. package/src/device-authorization.tsx +98 -0
  487. package/src/diffs.ts +16 -0
  488. package/src/discovery-cache.ts +42 -0
  489. package/src/editor.ts +13 -0
  490. package/src/embedded-session-client.ts +104 -0
  491. package/src/file-node-visibility.ts +66 -0
  492. package/src/hooks/channel-cache.ts +104 -0
  493. package/src/hooks/internal.ts +3 -2
  494. package/src/hooks/latest-question.ts +164 -0
  495. package/src/hooks/shared-machines-list.ts +239 -0
  496. package/src/hooks/use-attached-browsers.ts +5 -1
  497. package/src/hooks/use-available-models.ts +20 -14
  498. package/src/hooks/use-browser-frame-stream.ts +25 -3
  499. package/src/hooks/use-browser-session.ts +271 -71
  500. package/src/hooks/use-browser-sessions.ts +7 -1
  501. package/src/hooks/use-channels.ts +32 -10
  502. package/src/hooks/use-codex-accounts.ts +78 -21
  503. package/src/hooks/use-composer.ts +1034 -320
  504. package/src/hooks/use-computer-frame-stream.ts +39 -16
  505. package/src/hooks/use-computer-input-posture.ts +94 -0
  506. package/src/hooks/use-computer-session.ts +110 -32
  507. package/src/hooks/use-computer-sessions.ts +8 -1
  508. package/src/hooks/use-connect.ts +23 -0
  509. package/src/hooks/use-desktop-stream.ts +19 -28
  510. package/src/hooks/use-file-attachments.ts +118 -10
  511. package/src/hooks/use-goal.ts +36 -9
  512. package/src/hooks/use-human-input.ts +31 -4
  513. package/src/hooks/use-last-started-turn-policy.ts +15 -13
  514. package/src/hooks/use-machine-chip.ts +23 -6
  515. package/src/hooks/use-machines.ts +104 -6
  516. package/src/hooks/use-sandbox-files.ts +253 -150
  517. package/src/hooks/use-sandbox-git.ts +58 -29
  518. package/src/hooks/use-session-background-commands.ts +67 -0
  519. package/src/hooks/use-session-capabilities.ts +21 -2
  520. package/src/hooks/use-session-events.ts +759 -433
  521. package/src/hooks/use-session-lineage.ts +28 -6
  522. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  523. package/src/hooks/use-session.ts +75 -16
  524. package/src/hooks/use-slash-commands.ts +6 -11
  525. package/src/hooks/use-turn-queue.ts +113 -13
  526. package/src/hooks/use-usage.ts +100 -0
  527. package/src/hooks/use-video-artifact-playback.ts +1 -1
  528. package/src/hooks/use-voice-input.ts +12 -1
  529. package/src/hooks/use-workspace-capture.ts +3 -2
  530. package/src/hooks/use-workspace-edit.ts +23 -5
  531. package/src/hooks/use-workspace-sessions.ts +99 -11
  532. package/src/human-input.ts +12 -1
  533. package/src/identity-link-accounts.tsx +148 -0
  534. package/src/identity-link-consent.tsx +192 -0
  535. package/src/index.ts +157 -12
  536. package/src/interaction.ts +1 -0
  537. package/src/lib/error-message.ts +37 -0
  538. package/src/lib/format.ts +150 -14
  539. package/src/lib/host-theme.ts +511 -0
  540. package/src/lib/interaction-errors.ts +33 -0
  541. package/src/lib/menu-styles.ts +44 -0
  542. package/src/lib/pierre-diffs-loader.ts +53 -0
  543. package/src/lib/workbench-peers.ts +62 -0
  544. package/src/lib/xterm-theme.ts +23 -21
  545. package/src/machines.ts +9 -1
  546. package/src/mcp-connection-status.ts +35 -0
  547. package/src/model-policy.ts +223 -69
  548. package/src/older-history.ts +87 -0
  549. package/src/plugin-details.tsx +185 -0
  550. package/src/plugin-discovery.tsx +196 -0
  551. package/src/provider.tsx +55 -14
  552. package/src/realtime/dropdown-menu.tsx +19 -12
  553. package/src/realtime/realtime-control.tsx +133 -46
  554. package/src/session-auth-recommendation.ts +48 -0
  555. package/src/session-capability-policy.ts +83 -0
  556. package/src/session-context.ts +4 -3
  557. package/src/session-ui.ts +66 -2
  558. package/src/session.ts +18 -1
  559. package/src/sites-ui.tsx +402 -0
  560. package/src/sites.ts +3 -0
  561. package/src/skill-discovery.tsx +208 -0
  562. package/src/terminal.ts +26 -0
  563. package/src/timeline/activity-rail.tsx +171 -80
  564. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  565. package/src/timeline/compaction-copy.ts +42 -0
  566. package/src/timeline/entrance.tsx +28 -3
  567. package/src/timeline/fleet-decision-projection.ts +2 -1
  568. package/src/timeline/fleet-decision-row.tsx +1 -0
  569. package/src/timeline/genie-loading.tsx +136 -0
  570. package/src/timeline/index.ts +11 -0
  571. package/src/timeline/knowledge-receipt.tsx +100 -0
  572. package/src/timeline/parsers.ts +2 -2
  573. package/src/timeline/platform-activity-row.tsx +216 -0
  574. package/src/timeline/presented-image.ts +49 -0
  575. package/src/timeline/projection.ts +1609 -84
  576. package/src/timeline/registry.ts +15 -3
  577. package/src/timeline/retained-image.ts +97 -0
  578. package/src/timeline/rolling-activity.tsx +92 -0
  579. package/src/timeline/screenshot-lightbox.tsx +115 -17
  580. package/src/timeline/shared.tsx +47 -15
  581. package/src/timeline/startup-preference.ts +33 -0
  582. package/src/timeline/startup-timings.tsx +145 -0
  583. package/src/timeline/tool-display-name.ts +8 -6
  584. package/src/timeline/tool-renderers.tsx +497 -128
  585. package/src/timeline/turn-summary.tsx +218 -44
  586. package/src/timeline/types.ts +192 -7
  587. package/src/types/machines.ts +10 -0
  588. package/src/usage/allowance-copy.ts +64 -0
  589. package/src/usage/summary.ts +93 -0
  590. package/src/usage.ts +50 -0
  591. package/styles/compiled.css +2098 -757
  592. package/styles/connect.css +284 -0
  593. package/styles/connect.d.ts +1 -0
  594. package/styles/effective-tokens.css +1 -0
  595. package/styles/index.css +201 -9
  596. package/styles/responsive.css +27 -1
  597. package/styles/session-capability.css +44 -0
  598. package/styles/tokens.css +135 -65
  599. package/dist/chunk-5UQPNLIO.js.map +0 -1
  600. package/dist/chunk-6KLX2RH5.js.map +0 -1
  601. package/dist/chunk-7WCLAEFV.js.map +0 -1
  602. package/dist/chunk-B6WPZSTT.js.map +0 -1
  603. package/dist/chunk-FK6VG4LL.js +0 -90
  604. package/dist/chunk-FK6VG4LL.js.map +0 -1
  605. package/dist/chunk-HA46CYQK.js.map +0 -1
  606. package/dist/chunk-HUIKIDM5.js.map +0 -1
  607. package/dist/chunk-IGC6A2ZI.js.map +0 -1
  608. package/dist/chunk-KCGXPP5V.js.map +0 -1
  609. package/dist/chunk-KZ73RL76.js.map +0 -1
  610. package/dist/chunk-LAKLF4PA.js +0 -141
  611. package/dist/chunk-LAKLF4PA.js.map +0 -1
  612. package/dist/chunk-LLOLUHVG.js.map +0 -1
  613. package/dist/chunk-MKPIAGVL.js +0 -465
  614. package/dist/chunk-MKPIAGVL.js.map +0 -1
  615. package/dist/chunk-PEI6RANI.js.map +0 -1
  616. package/dist/chunk-R3AZOAB5.js.map +0 -1
  617. package/dist/chunk-WSK7G5LE.js +0 -170
  618. package/dist/chunk-WSK7G5LE.js.map +0 -1
  619. package/dist/chunk-XBZWOM2K.js +0 -218
  620. package/dist/chunk-XBZWOM2K.js.map +0 -1
  621. package/dist/chunk-Y7OEDUJ5.js +0 -8810
  622. package/dist/chunk-Y7OEDUJ5.js.map +0 -1
  623. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  624. package/dist/hooks/use-packs.d.ts +0 -32
  625. package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
  626. package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
  627. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  628. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  629. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  630. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  631. package/src/hooks/use-packs.ts +0 -157
  632. /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-SHYKQRNX.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { CheckIcon, CopyIcon } from "lucide-react";
2
- import { useEffect, useRef, useState, type MouseEvent, type ReactNode } from "react";
2
+ import { memo, useEffect, useRef, useState, type MouseEvent, type ReactNode } from "react";
3
3
  import { cn } from "../lib/cn";
4
4
  import { copyTextToClipboard } from "../lib/clipboard";
5
5
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip";
@@ -22,8 +22,10 @@ export type CopyButtonProps = {
22
22
  /**
23
23
  * Ghost icon copy control — no chrome box, no "Copy code" label.
24
24
  * Copy → check flash. Hover-reveal via `group/copy` on a parent.
25
+ * Keep unchanged controls out of parent message rerenders: mounting history
26
+ * already has to commit each new tooltip, without redoing the retained suffix.
25
27
  */
26
- export function CopyButton({
28
+ export const CopyButton = memo(function CopyButton({
27
29
  text,
28
30
  label = "Copy",
29
31
  className,
@@ -113,7 +115,7 @@ export function CopyButton({
113
115
  <TooltipContent side="top">{tip}</TooltipContent>
114
116
  </Tooltip>
115
117
  );
116
- }
118
+ });
117
119
 
118
120
  /** Hover-reveal chrome around a message / turn so {@link CopyButton} can fade in. */
119
121
  export function CopyHoverFrame({
@@ -140,12 +142,18 @@ export function CopyHoverFrame({
140
142
  {children}
141
143
  {/* Sit under the body — top-right overlay collided with the first line. */}
142
144
  <div
145
+ data-og-annotation-chrome=""
143
146
  className={cn(
144
- "mt-1 flex h-7 items-center gap-1.5",
147
+ "flex h-6 items-center gap-1.5 pointer-coarse:h-11",
145
148
  align === "end" ? "justify-end" : "justify-start",
146
149
  )}
147
150
  >
148
- <CopyButton text={copyText} label={label} reveal="group-hover" />
151
+ <CopyButton
152
+ text={copyText}
153
+ label={label}
154
+ reveal="group-hover"
155
+ className="size-6 pointer-coarse:size-11"
156
+ />
149
157
  {trailing}
150
158
  </div>
151
159
  </div>
@@ -30,7 +30,7 @@ export type DesktopViewerProps = {
30
30
  /** Render the built-in Watching ⇄ Take control toggle (default true). */
31
31
  showControlToggle?: boolean | undefined;
32
32
  scaleViewport?: boolean | undefined;
33
- /** Custom RFB factory (tests / a WebRTC swap). Defaults to lazy @novnc/novnc. */
33
+ /** Custom RFB factory; otherwise enableDesktopViewer() supplies lazy noVNC. */
34
34
  rfbFactory?: DesktopRfbFactory | undefined;
35
35
  /** Authenticated controller protocols for proxied RFB transports. */
36
36
  webSocketProtocols?: string[] | undefined;
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode, useState } from "react";
2
+ import type { ResourceAuthorityScope } from "@opengeni/sdk";
2
3
  import {
3
4
  CircleAlertIcon,
4
5
  LaptopIcon,
@@ -30,8 +31,10 @@ export type EnrollmentConsentProps = {
30
31
  userCode: string;
31
32
  machine: EnrollmentConsentMachine;
32
33
  phase?: EnrollmentConsentPhase | undefined;
33
- /** Approve with the chosen screen-control consent. */
34
- onApprove?: ((allowScreenControl: boolean) => void) | undefined;
34
+ /** Whether this caller may publish the machine to the whole organization. */
35
+ allowOrganizationScope?: boolean | undefined;
36
+ /** Approve with the chosen screen-control consent and explicit access scope. */
37
+ onApprove?: ((allowScreenControl: boolean, scope: ResourceAuthorityScope) => void) | undefined;
35
38
  onDeny?: (() => void) | undefined;
36
39
  /** Error message when phase === "error". */
37
40
  errorMessage?: string | undefined;
@@ -61,13 +64,29 @@ export function EnrollmentConsent({
61
64
  userCode,
62
65
  machine,
63
66
  phase = "review",
67
+ allowOrganizationScope = false,
64
68
  onApprove,
65
69
  onDeny,
66
70
  errorMessage,
67
71
  className,
68
72
  }: EnrollmentConsentProps) {
69
73
  const [allowScreenControl, setAllowScreenControl] = useState(machine.requestsScreenControl);
74
+ const [scope, setScope] = useState<ResourceAuthorityScope>("user");
70
75
  const busy = phase === "approving";
76
+ const scopeCopy = {
77
+ user: {
78
+ label: "Personal",
79
+ body: "Only you can use this machine, from any workspace you can access in this organization.",
80
+ },
81
+ workspace: {
82
+ label: "Workspace",
83
+ body: "Everyone with access to this workspace can use this machine.",
84
+ },
85
+ organization: {
86
+ label: "Organization",
87
+ body: "Members of this organization can use this machine from their workspaces.",
88
+ },
89
+ } satisfies Record<ResourceAuthorityScope, { label: string; body: string }>;
71
90
 
72
91
  if (phase === "approved") {
73
92
  return (
@@ -75,7 +94,7 @@ export function EnrollmentConsent({
75
94
  className={className}
76
95
  tone="ok"
77
96
  title="Machine connected"
78
- body={`${machine.machineName} is now enrolled in this workspace. You can close this page — it will appear in your Machines dashboard.`}
97
+ body={`${machine.machineName} is now connected with ${scopeCopy[scope].label.toLowerCase()} access. You can close this page — it will appear in your Machines dashboard.`}
79
98
  />
80
99
  );
81
100
  }
@@ -120,7 +139,7 @@ export function EnrollmentConsent({
120
139
  Give the agent your whole machine?
121
140
  </h1>
122
141
  <p className="mt-1 text-og-base text-og-fg-muted">
123
- Approving lets the OpenGeni agent run on{" "}
142
+ Approving lets the Opengeni agent run on{" "}
124
143
  <span className="font-medium text-og-fg">{machine.machineName}</span> with full access.
125
144
  This is your real computer — not a sandbox.
126
145
  </p>
@@ -156,11 +175,50 @@ export function EnrollmentConsent({
156
175
  ) : null}
157
176
  <Capability
158
177
  icon={<UsersIcon className="size-4" aria-hidden />}
159
- title="Shared while connected"
160
- body="Any session in this workspace can use this machine while it is online. Disconnect the agent to revoke access instantly."
178
+ title={`${scopeCopy[scope].label} access while connected`}
179
+ body={`${scopeCopy[scope].body} Disconnect the agent to revoke access instantly.`}
161
180
  />
162
181
  </ul>
163
182
 
183
+ <fieldset className="flex flex-col gap-2" disabled={busy}>
184
+ <legend className="mb-1 text-og-sm font-medium text-og-fg">
185
+ Who can use this machine?
186
+ </legend>
187
+ {(["user", "workspace", "organization"] as const).map((candidate) => {
188
+ const disabled = candidate === "organization" && !allowOrganizationScope;
189
+ return (
190
+ <label
191
+ key={candidate}
192
+ data-enrollment-scope={candidate}
193
+ data-disabled={disabled ? "true" : "false"}
194
+ className={cn(
195
+ "flex items-start gap-2.5 rounded-og-md border border-og-border bg-og-bg px-3 py-2.5",
196
+ disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
197
+ )}
198
+ >
199
+ <input
200
+ type="radio"
201
+ name="enrollment-scope"
202
+ value={candidate}
203
+ checked={scope === candidate}
204
+ disabled={disabled || busy}
205
+ onChange={() => setScope(candidate)}
206
+ className="mt-0.5 size-4 accent-og-accent"
207
+ />
208
+ <span className="min-w-0">
209
+ <span className="block text-og-base font-medium text-og-fg">
210
+ {scopeCopy[candidate].label}
211
+ {disabled ? " · organization admin required" : ""}
212
+ </span>
213
+ <span className="block text-og-sm text-og-fg-muted">
214
+ {scopeCopy[candidate].body}
215
+ </span>
216
+ </span>
217
+ </label>
218
+ );
219
+ })}
220
+ </fieldset>
221
+
164
222
  {machine.canOfferDisplay ? (
165
223
  <label
166
224
  data-screen-control-toggle
@@ -206,7 +264,7 @@ export function EnrollmentConsent({
206
264
  type="button"
207
265
  data-approve
208
266
  disabled={busy}
209
- onClick={() => onApprove?.(allowScreenControl)}
267
+ onClick={() => onApprove?.(allowScreenControl, scope)}
210
268
  className="flex-1 rounded-og-sm bg-og-status-failed px-3 py-2 text-og-sm font-semibold text-og-accent-fg transition-colors hover:opacity-90 disabled:opacity-50 pointer-coarse:min-h-11"
211
269
  >
212
270
  {busy ? "Connecting…" : "Grant full access"}
@@ -156,7 +156,7 @@ export function EnrollmentDeviceFlow({
156
156
  target="_blank"
157
157
  rel="noreferrer"
158
158
  onClick={onOpenVerification}
159
- className="inline-flex items-center justify-center gap-1.5 rounded-og-sm bg-og-accent px-3 py-2 text-og-menu font-medium text-og-accent-fg transition-colors hover:bg-og-accent-strong"
159
+ className="inline-flex items-center justify-center gap-1.5 rounded-og-sm border border-og-primary-border bg-og-primary text-og-primary-fg px-3 py-2 text-og-menu font-medium transition-colors hover:bg-og-primary-hover"
160
160
  >
161
161
  Open approval page
162
162
  <ExternalLinkIcon className="size-3.5" aria-hidden />
@@ -24,6 +24,7 @@ import {
24
24
  import { AlertDialog } from "radix-ui";
25
25
  import { VList, type VListHandle } from "virtua";
26
26
  import { cn } from "../lib/cn";
27
+ import { MENU_BUTTON_CLASS, MENU_SEPARATOR_CLASS, MENU_SURFACE_CLASS } from "../lib/menu-styles";
27
28
  import {
28
29
  type PortalTokenStyle,
29
30
  usePortalTokenSource,
@@ -31,6 +32,7 @@ import {
31
32
  } from "../lib/use-portal-token-style";
32
33
  import { useUnicodeFallbackFonts } from "../lib/use-unicode-fonts";
33
34
  import type { FileTreeNode, UseSandboxFilesResult } from "../hooks/use-sandbox-files";
35
+ import { visibleFileTree, type FileNodeVisibilityPredicate } from "../file-node-visibility";
34
36
 
35
37
  export type FileBrowserProps = {
36
38
  /** From `useSandboxFiles(...)`. */
@@ -43,6 +45,14 @@ export type FileBrowserProps = {
43
45
  /** Selection callback for the preview pane. */
44
46
  onSelectFile?: ((path: string) => void) | undefined;
45
47
  selectedPath?: string | undefined;
48
+ /** Presentation-only node filter. Hidden parents never expose their children. */
49
+ isNodeVisible?: FileNodeVisibilityPredicate | undefined;
50
+ /** Deliberately reveal this selected path by lazily opening every loaded
51
+ * ancestor and scrolling its row into view. The path is opaque and is never
52
+ * normalized or re-rooted here. */
53
+ revealPath?: string | undefined;
54
+ /** Increment/change to reveal the same path again after a user collapses it. */
55
+ revealPathRequestId?: string | number | undefined;
46
56
  /** Render-prop to theme/replace a row entirely (the Pierre-swap escape hatch). */
47
57
  renderNode?: ((node: FileTreeNode, depth: number, expanded: boolean) => ReactNode) | undefined;
48
58
  /** Shown when the tree is empty (no files / not loaded yet). */
@@ -96,11 +106,18 @@ function itemKey(item: RenderItem): string {
96
106
  }
97
107
  }
98
108
 
99
- /** Walk the tree to find a node by path. */
109
+ function pathIsInsideDirectory(path: string, directory: string): boolean {
110
+ if (!path.startsWith(directory) || path === directory) return false;
111
+ if (directory.endsWith("/") || directory.endsWith("\\")) return true;
112
+ const boundary = path[directory.length];
113
+ return boundary === "/" || boundary === "\\";
114
+ }
115
+
116
+ /** Walk the authoritative tree without assuming its target-owned separator. */
100
117
  function findNode(nodes: FileTreeNode[], path: string): FileTreeNode | undefined {
101
118
  for (const node of nodes) {
102
119
  if (node.path === path) return node;
103
- if (node.kind === "dir" && node.children && path.startsWith(`${node.path}/`)) {
120
+ if (node.kind === "dir" && node.children && pathIsInsideDirectory(path, node.path)) {
104
121
  const hit = findNode(node.children, path);
105
122
  if (hit) return hit;
106
123
  }
@@ -108,6 +125,34 @@ function findNode(nodes: FileTreeNode[], path: string): FileTreeNode | undefined
108
125
  return undefined;
109
126
  }
110
127
 
128
+ type RevealTrace = {
129
+ directories: string[];
130
+ frontier: string | null;
131
+ };
132
+
133
+ /** Follow only paths already named by the authoritative tree. This deliberately
134
+ * avoids manufacturing ancestors from a platform-specific path string. */
135
+ function traceRevealPath(nodes: FileTreeNode[], targetPath: string): RevealTrace {
136
+ for (const node of nodes) {
137
+ if (node.path === targetPath) {
138
+ return {
139
+ directories: node.kind === "dir" ? [node.path] : [],
140
+ frontier: node.kind === "dir" && node.children === undefined ? node.path : null,
141
+ };
142
+ }
143
+ if (node.kind !== "dir" || !pathIsInsideDirectory(targetPath, node.path)) continue;
144
+ if (node.children === undefined) {
145
+ return { directories: [node.path], frontier: node.path };
146
+ }
147
+ const child = traceRevealPath(node.children, targetPath);
148
+ return {
149
+ directories: [node.path, ...child.directories],
150
+ frontier: child.frontier,
151
+ };
152
+ }
153
+ return { directories: [], frontier: null };
154
+ }
155
+
111
156
  /** A pending inline-create: a phantom input row under `parent`. */
112
157
  type DraftCreate = { parent: string; kind: "file" | "dir" };
113
158
  /** A pending inline-rename of an existing node. */
@@ -142,6 +187,9 @@ export function FileBrowser({
142
187
  fallback,
143
188
  onSelectFile,
144
189
  selectedPath,
190
+ isNodeVisible,
191
+ revealPath,
192
+ revealPathRequestId,
145
193
  renderNode,
146
194
  emptyState,
147
195
  editable = true,
@@ -158,6 +206,15 @@ export function FileBrowser({
158
206
  const [pendingDelete, setPendingDelete] = useState<FileTreeNode | null>(null);
159
207
  const [busy, setBusy] = useState(false);
160
208
  const [coarsePointer, setCoarsePointer] = useState(false);
209
+ const [revealRequest, setRevealRequest] = useState<{
210
+ path: string;
211
+ requestId: string | number;
212
+ } | null>(null);
213
+ const handledRevealRequestRef = useRef<{
214
+ path: string;
215
+ requestId: string | number;
216
+ } | null>(null);
217
+ const attemptedRevealPathsRef = useRef<Set<string>>(new Set());
161
218
  const treeId = useId();
162
219
  const container = usePortalTokenSource<HTMLDivElement>();
163
220
  const containerRef = container.currentRef;
@@ -168,6 +225,10 @@ export function FileBrowser({
168
225
  () => (typeof document === "undefined" ? null : document.getElementById(treeId)),
169
226
  [treeId],
170
227
  );
228
+ const visibleTree = useMemo(
229
+ () => visibleFileTree(result.tree, isNodeVisible),
230
+ [isNodeVisible, result.tree],
231
+ );
171
232
 
172
233
  useBrowserLayoutEffect(() => {
173
234
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
@@ -184,13 +245,35 @@ export function FileBrowser({
184
245
  }
185
246
  }, []);
186
247
 
248
+ const effectiveRevealRequestId = revealPath ? (revealPathRequestId ?? revealPath) : null;
249
+ useEffect(() => {
250
+ if (!revealPath || effectiveRevealRequestId === null) {
251
+ setRevealRequest(null);
252
+ return;
253
+ }
254
+ const handled = handledRevealRequestRef.current;
255
+ if (handled?.path === revealPath && handled.requestId === effectiveRevealRequestId) return;
256
+ handledRevealRequestRef.current = {
257
+ path: revealPath,
258
+ requestId: effectiveRevealRequestId,
259
+ };
260
+ attemptedRevealPathsRef.current = new Set();
261
+ setActive(null);
262
+ setRevealRequest({ path: revealPath, requestId: effectiveRevealRequestId });
263
+ }, [effectiveRevealRequestId, revealPath]);
264
+
187
265
  // The keyboard cursor: an explicitly-navigated node falls back to the
188
266
  // externally-selected file so arrow keys pick up where the preview pane is.
189
- const cursor = active ?? selectedPath ?? null;
267
+ const visibleActive = active && findNode(visibleTree, active) ? active : null;
268
+ const cursor =
269
+ visibleActive ?? (selectedPath && findNode(visibleTree, selectedPath) ? selectedPath : null);
270
+ useEffect(() => {
271
+ if (active !== null && visibleActive === null) setActive(null);
272
+ }, [active, visibleActive]);
190
273
 
191
274
  const expand = useCallback(
192
275
  async (path: string) => {
193
- const node = findNode(result.tree, path);
276
+ const node = findNode(visibleTree, path);
194
277
  if (node && node.kind === "dir" && node.children === undefined) {
195
278
  setLoadingPaths((prev) => new Set(prev).add(path));
196
279
  try {
@@ -204,7 +287,7 @@ export function FileBrowser({
204
287
  }
205
288
  }
206
289
  },
207
- [result],
290
+ [result, visibleTree],
208
291
  );
209
292
 
210
293
  const open = useCallback(
@@ -215,6 +298,34 @@ export function FileBrowser({
215
298
  [expand],
216
299
  );
217
300
 
301
+ useEffect(() => {
302
+ if (!revealRequest) return;
303
+ const trace = traceRevealPath(visibleTree, revealRequest.path);
304
+ if (trace.directories.length > 0) {
305
+ setExpanded((previous) => {
306
+ const next = new Set(previous);
307
+ let changed = false;
308
+ for (const path of trace.directories) {
309
+ if (next.has(path)) continue;
310
+ next.add(path);
311
+ changed = true;
312
+ }
313
+ return changed ? next : previous;
314
+ });
315
+ }
316
+ const frontier = trace.frontier;
317
+ if (
318
+ !frontier ||
319
+ attemptedRevealPathsRef.current.has(frontier) ||
320
+ loadingPaths.has(frontier) ||
321
+ result.expandingPaths.has(frontier)
322
+ ) {
323
+ return;
324
+ }
325
+ attemptedRevealPathsRef.current.add(frontier);
326
+ void expand(frontier);
327
+ }, [expand, loadingPaths, result.expandingPaths, revealRequest, visibleTree]);
328
+
218
329
  const toggle = useCallback(
219
330
  async (node: FileTreeNode) => {
220
331
  if (node.kind !== "dir") return;
@@ -265,9 +376,9 @@ export function FileBrowser({
265
376
  }
266
377
  }
267
378
  };
268
- walk(result.tree, 0);
379
+ walk(visibleTree, 0);
269
380
  return items;
270
- }, [result.tree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);
381
+ }, [visibleTree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);
271
382
  const unicodeFontPaths = useMemo(
272
383
  () => renderItems.flatMap((item) => (item.type === "node" ? [item.node.path] : [])),
273
384
  [renderItems],
@@ -294,9 +405,9 @@ export function FileBrowser({
294
405
  if (node.children) visit(node.children);
295
406
  });
296
407
  };
297
- visit(result.tree);
408
+ visit(visibleTree);
298
409
  return positions;
299
- }, [result.tree]);
410
+ }, [visibleTree]);
300
411
  const cursorIndex = cursor ? (rowIndexByPath.get(cursor) ?? -1) : -1;
301
412
  const activeDescendantId = cursorIndex >= 0 ? `${treeId}-item-${cursorIndex}` : undefined;
302
413
 
@@ -388,7 +499,7 @@ export function FileBrowser({
388
499
  const draft = draftRename;
389
500
  setDraftRename(null);
390
501
  if (!draft || !supportsMutation) return;
391
- const node = findNode(result.tree, draft.path);
502
+ const node = findNode(visibleTree, draft.path);
392
503
  const trimmed = name.trim().replace(/\/+$/, "");
393
504
  if (!node || !trimmed || trimmed === node.name) return;
394
505
  const newPath = joinPath(parentOf(draft.path), trimmed);
@@ -405,21 +516,21 @@ export function FileBrowser({
405
516
  setBusy(false);
406
517
  }
407
518
  },
408
- [draftRename, supportsMutation, result, selectedPath, active, onSelectFile],
519
+ [draftRename, supportsMutation, result, selectedPath, active, onSelectFile, visibleTree],
409
520
  );
410
521
 
411
522
  // Begin a new file/folder under the active node's directory (or root).
412
523
  const startCreate = useCallback(
413
524
  (kind: "file" | "dir") => {
414
525
  if (!supportsMutation) return;
415
- const anchor = cursor ? findNode(result.tree, cursor) : undefined;
526
+ const anchor = cursor ? findNode(visibleTree, cursor) : undefined;
416
527
  const parent = anchor ? (anchor.kind === "dir" ? anchor.path : parentOf(anchor.path)) : "";
417
528
  if (parent) open(parent);
418
529
  setDraftRename(null);
419
530
  setMenu(null);
420
531
  setDraftCreate({ parent, kind });
421
532
  },
422
- [supportsMutation, cursor, result.tree, open],
533
+ [supportsMutation, cursor, open, visibleTree],
423
534
  );
424
535
 
425
536
  const startRename = useCallback(
@@ -437,7 +548,7 @@ export function FileBrowser({
437
548
  async (targetDir: string, sourcePath: string) => {
438
549
  setDragOver(null);
439
550
  if (!supportsMutation || !sourcePath) return;
440
- const src = findNode(result.tree, sourcePath);
551
+ const src = findNode(visibleTree, sourcePath);
441
552
  if (!src) return;
442
553
  // No-op drops: onto its own current parent, onto itself, or into its own subtree.
443
554
  if (parentOf(sourcePath) === targetDir) return;
@@ -457,7 +568,7 @@ export function FileBrowser({
457
568
  setBusy(false);
458
569
  }
459
570
  },
460
- [supportsMutation, result, selectedPath, active, onSelectFile],
571
+ [supportsMutation, result, selectedPath, active, onSelectFile, visibleTree],
461
572
  );
462
573
 
463
574
  const onKeyDown = useCallback(
@@ -594,9 +705,9 @@ export function FileBrowser({
594
705
  };
595
706
  }, [menu]);
596
707
 
597
- const showErrorEmpty = result.error && result.tree.length === 0 && !draftCreate;
598
- const showDegradedTree = result.error && result.tree.length > 0;
599
- const showEmpty = !result.loading && result.tree.length === 0 && !draftCreate;
708
+ const showErrorEmpty = result.error && visibleTree.length === 0 && !draftCreate;
709
+ const showDegradedTree = result.error && visibleTree.length > 0;
710
+ const showEmpty = !result.loading && visibleTree.length === 0 && !draftCreate;
600
711
  // Retry lives next to the state it explains (the degraded/empty notice), so do
601
712
  // not render a second toolbar retry for the same failure.
602
713
  const showToolbar = supportsMutation || result.loading;
@@ -800,6 +911,24 @@ export function FileBrowser({
800
911
  if (index >= 0) vlistRef.current?.scrollToIndex(index);
801
912
  }, [cursor, renderItems]);
802
913
 
914
+ useEffect(() => {
915
+ if (!revealRequest) return;
916
+ const index = renderItems.findIndex(
917
+ (item) => item.type === "node" && item.node.path === revealRequest.path,
918
+ );
919
+ if (index < 0) return;
920
+ if (usesVirtualTree) {
921
+ vlistRef.current?.scrollToIndex(index);
922
+ } else {
923
+ document.getElementById(`${treeId}-item-${index}`)?.scrollIntoView?.({ block: "nearest" });
924
+ }
925
+ setRevealRequest((current) =>
926
+ current?.path === revealRequest.path && current.requestId === revealRequest.requestId
927
+ ? null
928
+ : current,
929
+ );
930
+ }, [renderItems, revealRequest, treeId, usesVirtualTree]);
931
+
803
932
  return (
804
933
  <div className={cn("flex min-h-0 min-w-0 flex-col", className)}>
805
934
  {showToolbar && (
@@ -819,7 +948,7 @@ export function FileBrowser({
819
948
  <ToolbarButton
820
949
  label="Rename"
821
950
  onClick={() => {
822
- const node = cursor ? findNode(result.tree, cursor) : undefined;
951
+ const node = cursor ? findNode(visibleTree, cursor) : undefined;
823
952
  if (node) startRename(node);
824
953
  }}
825
954
  disabled={busy || !cursor}
@@ -829,7 +958,7 @@ export function FileBrowser({
829
958
  <ToolbarButton
830
959
  label="Delete"
831
960
  onClick={(event) => {
832
- const node = cursor ? findNode(result.tree, cursor) : undefined;
961
+ const node = cursor ? findNode(visibleTree, cursor) : undefined;
833
962
  if (node) void runDelete(node, event.currentTarget);
834
963
  }}
835
964
  disabled={busy || !cursor}
@@ -1121,7 +1250,7 @@ function DeleteDialog({
1121
1250
  closeIntentRef.current = "confirm";
1122
1251
  }}
1123
1252
  disabled={busy}
1124
- className="min-h-9 rounded-og-md bg-og-status-failed px-3 text-og-sm font-semibold text-white shadow-sm hover:brightness-110 disabled:opacity-50 pointer-coarse:min-h-11"
1253
+ className="min-h-9 rounded-og-md bg-og-danger-fill px-3 text-og-sm font-semibold text-og-danger-fg shadow-sm hover:brightness-110 disabled:opacity-50 pointer-coarse:min-h-11"
1125
1254
  >
1126
1255
  Delete permanently
1127
1256
  </button>
@@ -1301,9 +1430,8 @@ function ContextMenu({
1301
1430
  onClick();
1302
1431
  }}
1303
1432
  className={cn(
1304
- "flex w-full items-center gap-2 px-2.5 py-1 text-left text-og-sm pointer-coarse:min-h-11",
1305
- "hover:bg-og-surface-2",
1306
- danger ? "text-og-status-failed" : "text-og-fg",
1433
+ MENU_BUTTON_CLASS,
1434
+ danger && "text-og-status-failed [&_svg]:text-og-status-failed!",
1307
1435
  )}
1308
1436
  >
1309
1437
  {icon}
@@ -1319,21 +1447,17 @@ function ContextMenu({
1319
1447
  onKeyDown={onKeyDown}
1320
1448
  onClick={(e) => e.stopPropagation()}
1321
1449
  style={{ left, top }}
1322
- className={cn(
1323
- "fixed z-50 min-w-[160px] overflow-hidden rounded-md border py-1 shadow-lg",
1324
- "border-og-border",
1325
- "bg-og-surface-1",
1326
- )}
1450
+ className={cn(MENU_SURFACE_CLASS, "fixed z-50 min-w-[180px] overflow-hidden")}
1327
1451
  >
1328
1452
  {isDir && (
1329
1453
  <>
1330
- {item("New file", <FilePlusIcon className="size-3.5" />, onNewFile)}
1331
- {item("New folder", <FolderPlusIcon className="size-3.5" />, onNewFolder)}
1332
- <div role="separator" className="my-1 h-px bg-og-border" />
1454
+ {item("New file", <FilePlusIcon />, onNewFile)}
1455
+ {item("New folder", <FolderPlusIcon />, onNewFolder)}
1456
+ <div role="separator" className={MENU_SEPARATOR_CLASS} />
1333
1457
  </>
1334
1458
  )}
1335
- {item("Rename", <PencilIcon className="size-3.5" />, onRename)}
1336
- {item("Delete", <Trash2Icon className="size-3.5" />, onDelete, true)}
1459
+ {item("Rename", <PencilIcon />, onRename)}
1460
+ {item("Delete", <Trash2Icon />, onDelete, true)}
1337
1461
  </div>
1338
1462
  );
1339
1463
  }
@@ -1,11 +1,14 @@
1
- import type { Session } from "@opengeni/sdk";
1
+ import { deriveSessionDisplayTitle, type Session } from "@opengeni/sdk";
2
+ import { modelDisplayName } from "@opengeni/sdk/model-display";
2
3
  import { cn } from "../lib/cn";
3
- import { formatRelativeTime, truncate } from "../lib/format";
4
+ import { formatRelativeTime } from "../lib/format";
4
5
  import { SessionStatus } from "./session-status";
5
6
 
7
+ const SESSION_METADATA_TITLE_KEYS = ["title", "name"] as const;
8
+
6
9
  export type FleetTileProps = {
7
10
  session: Session;
8
- /** Overrides the derived title (metadata.title/name, else the initial message). */
11
+ /** Overrides the derived title (durable title, metadata, prompt preview, or safe fallback). */
9
12
  title?: string | undefined;
10
13
  /** Extra line under the title — e.g. "drift check" or the worker's task. */
11
14
  subtitle?: string | undefined;
@@ -15,18 +18,7 @@ export type FleetTileProps = {
15
18
 
16
19
  /** Best-effort display title for a session. */
17
20
  export function sessionDisplayTitle(session: Session): string {
18
- // A set title (agent-generated or user-renamed) wins over metadata + the
19
- // initial-message fallback.
20
- if (typeof session.title === "string" && session.title.trim().length > 0) {
21
- return session.title;
22
- }
23
- for (const key of ["title", "name"] as const) {
24
- const value = session.metadata[key];
25
- if (typeof value === "string" && value.trim().length > 0) {
26
- return value;
27
- }
28
- }
29
- return truncate(session.initialMessage, 100) || session.id.slice(0, 8);
21
+ return deriveSessionDisplayTitle(session, { metadataKeys: SESSION_METADATA_TITLE_KEYS });
30
22
  }
31
23
 
32
24
  /**
@@ -76,7 +68,7 @@ export function FleetTile({ session, title, subtitle, onOpen, className }: Fleet
76
68
  <span className="mt-auto flex w-full items-center gap-2 text-og-xs text-og-fg-subtle">
77
69
  <span className="font-og-mono">{session.id.slice(0, 8)}</span>
78
70
  <span aria-hidden>·</span>
79
- <span className="truncate">{session.model}</span>
71
+ <span className="truncate">{modelDisplayName(session.model)}</span>
80
72
  <span className="ml-auto shrink-0" title={session.updatedAt}>
81
73
  {formatRelativeTime(session.updatedAt)}
82
74
  </span>
@@ -1,6 +1,7 @@
1
1
  import type { GeneratedVideoReceipt, VideoArtifactPlaybackSource } from "@opengeni/sdk";
2
2
  import { useEffect, useState } from "react";
3
3
  import { cn } from "../lib/cn";
4
+ import { useErrorMessage } from "../lib/error-message";
4
5
  import type { VideoArtifactPlaybackLoader } from "../timeline";
5
6
 
6
7
  export type GeneratedVideoPlayerProps = {
@@ -22,6 +23,7 @@ export function GeneratedVideoPlayer({
22
23
  className,
23
24
  label = "Generated video",
24
25
  }: GeneratedVideoPlayerProps) {
26
+ const formatError = useErrorMessage();
25
27
  const [retry, setRetry] = useState(0);
26
28
  const [state, setState] = useState<SourceState>({ kind: "loading" });
27
29
 
@@ -36,12 +38,12 @@ export function GeneratedVideoPlayer({
36
38
  if (controller.signal.aborted) return;
37
39
  setState({
38
40
  kind: "error",
39
- message: error instanceof Error ? error.message : "Playback is unavailable.",
41
+ message: formatError(error),
40
42
  });
41
43
  },
42
44
  );
43
45
  return () => controller.abort();
44
- }, [loadPlaybackSource, receipt.artifact.artifactId, retry]);
46
+ }, [loadPlaybackSource, receipt.artifact.artifactId, retry, formatError]);
45
47
 
46
48
  if (state.kind === "loading") {
47
49
  return (