@opengeni/react 3.3.2 → 3.4.1-canary.38960406141001

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 (855) hide show
  1. package/README.md +769 -22
  2. package/dist/accounts.js +2 -0
  3. package/dist/accounts.js.map +1 -1
  4. package/dist/approvals.d.ts +2 -1
  5. package/dist/artifacts-document.js +5 -3
  6. package/dist/artifacts-presentation.js +5 -3
  7. package/dist/artifacts-spreadsheet.d.ts +1 -1
  8. package/dist/artifacts-spreadsheet.js +5 -3
  9. package/dist/artifacts.d.ts +5 -1
  10. package/dist/artifacts.js +536 -42
  11. package/dist/artifacts.js.map +1 -1
  12. package/dist/browser-viewer-ZWR6MWJ7.js +19 -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-4EUKJXUO.js +14 -0
  16. package/dist/chunk-2DDJ6YH6.js +41 -0
  17. package/dist/chunk-2DDJ6YH6.js.map +1 -0
  18. package/dist/chunk-2HVLQ26H.js +183 -0
  19. package/dist/chunk-2HVLQ26H.js.map +1 -0
  20. package/dist/{chunk-XYRDDSXF.js → chunk-2I6R3GCZ.js} +4285 -3980
  21. package/dist/chunk-2I6R3GCZ.js.map +1 -0
  22. package/dist/{chunk-JAQ5K7W6.js → chunk-2SFFYIH3.js} +1178 -166
  23. package/dist/chunk-2SFFYIH3.js.map +1 -0
  24. package/dist/chunk-3PVDYTTB.js +24 -0
  25. package/dist/chunk-3PVDYTTB.js.map +1 -0
  26. package/dist/chunk-3RJKUVCA.js +14068 -0
  27. package/dist/chunk-3RJKUVCA.js.map +1 -0
  28. package/dist/chunk-3UZCWK46.js +298 -0
  29. package/dist/chunk-3UZCWK46.js.map +1 -0
  30. package/dist/chunk-47CKUXTW.js +293 -0
  31. package/dist/chunk-47CKUXTW.js.map +1 -0
  32. package/dist/chunk-4QYP6QUI.js +109 -0
  33. package/dist/chunk-4QYP6QUI.js.map +1 -0
  34. package/dist/chunk-5EY26VZ7.js +1053 -0
  35. package/dist/chunk-5EY26VZ7.js.map +1 -0
  36. package/dist/chunk-5I4VRWBB.js +56 -0
  37. package/dist/chunk-5I4VRWBB.js.map +1 -0
  38. package/dist/chunk-5WOR7UCL.js +191 -0
  39. package/dist/chunk-5WOR7UCL.js.map +1 -0
  40. package/dist/chunk-5YJLGOM5.js +51 -0
  41. package/dist/chunk-5YJLGOM5.js.map +1 -0
  42. package/dist/chunk-6JFN3OWG.js +386 -0
  43. package/dist/chunk-6JFN3OWG.js.map +1 -0
  44. package/dist/chunk-7QJT5O4S.js +35 -0
  45. package/dist/chunk-7QJT5O4S.js.map +1 -0
  46. package/dist/chunk-A55KV72M.js +402 -0
  47. package/dist/chunk-A55KV72M.js.map +1 -0
  48. package/dist/chunk-ADWCLI4G.js +2028 -0
  49. package/dist/chunk-ADWCLI4G.js.map +1 -0
  50. package/dist/chunk-B27E3V37.js +29 -0
  51. package/dist/chunk-B27E3V37.js.map +1 -0
  52. package/dist/chunk-B7TC2A33.js +83 -0
  53. package/dist/chunk-B7TC2A33.js.map +1 -0
  54. package/dist/chunk-BLL56F7R.js +385 -0
  55. package/dist/chunk-BLL56F7R.js.map +1 -0
  56. package/dist/chunk-BOFEQC6K.js +162 -0
  57. package/dist/chunk-BOFEQC6K.js.map +1 -0
  58. package/dist/chunk-CM7LVUKC.js +35 -0
  59. package/dist/chunk-CM7LVUKC.js.map +1 -0
  60. package/dist/chunk-CORUP6JB.js +122 -0
  61. package/dist/chunk-CORUP6JB.js.map +1 -0
  62. package/dist/chunk-CSX5FFKZ.js +35 -0
  63. package/dist/chunk-CSX5FFKZ.js.map +1 -0
  64. package/dist/chunk-EGVHJKGJ.js +3125 -0
  65. package/dist/chunk-EGVHJKGJ.js.map +1 -0
  66. package/dist/{chunk-NEXLLTP4.js → chunk-G76LSA76.js} +6 -5
  67. package/dist/chunk-G76LSA76.js.map +1 -0
  68. package/dist/{chunk-PEI6RANI.js → chunk-GQMRL52F.js} +311 -75
  69. package/dist/chunk-GQMRL52F.js.map +1 -0
  70. package/dist/{chunk-ELIYWBZR.js → chunk-GUUXOISA.js} +1113 -457
  71. package/dist/chunk-GUUXOISA.js.map +1 -0
  72. package/dist/{chunk-HUIKIDM5.js → chunk-I7X2P4FU.js} +225 -116
  73. package/dist/chunk-I7X2P4FU.js.map +1 -0
  74. package/dist/chunk-IGFZFLI2.js +1390 -0
  75. package/dist/chunk-IGFZFLI2.js.map +1 -0
  76. package/dist/{chunk-4MDLEHXL.js → chunk-IMSUVYQB.js} +26 -13
  77. package/dist/chunk-IMSUVYQB.js.map +1 -0
  78. package/dist/chunk-IOYHDEP3.js +38 -0
  79. package/dist/chunk-IOYHDEP3.js.map +1 -0
  80. package/dist/chunk-IZV5FTJC.js +55 -0
  81. package/dist/chunk-IZV5FTJC.js.map +1 -0
  82. package/dist/chunk-KF33GTWN.js +343 -0
  83. package/dist/chunk-KF33GTWN.js.map +1 -0
  84. package/dist/chunk-KSGQ5ODA.js +457 -0
  85. package/dist/chunk-KSGQ5ODA.js.map +1 -0
  86. package/dist/{chunk-ZPBTI3TE.js → chunk-KZC6QRNR.js} +1513 -697
  87. package/dist/chunk-KZC6QRNR.js.map +1 -0
  88. package/dist/chunk-LJUMYUBO.js +218 -0
  89. package/dist/chunk-LJUMYUBO.js.map +1 -0
  90. package/dist/chunk-LSW2OJVV.js +380 -0
  91. package/dist/chunk-LSW2OJVV.js.map +1 -0
  92. package/dist/chunk-M357MHH3.js +2 -0
  93. package/dist/chunk-M357MHH3.js.map +1 -0
  94. package/dist/chunk-MK2TQO4Y.js +24 -0
  95. package/dist/chunk-MK2TQO4Y.js.map +1 -0
  96. package/dist/chunk-N7S72EXK.js +25 -0
  97. package/dist/chunk-N7S72EXK.js.map +1 -0
  98. package/dist/{chunk-YVCHAQZY.js → chunk-NKMYZFHA.js} +616 -621
  99. package/dist/chunk-NKMYZFHA.js.map +1 -0
  100. package/dist/chunk-NX4ADH73.js +14 -0
  101. package/dist/chunk-NX4ADH73.js.map +1 -0
  102. package/dist/chunk-O7F6UJO4.js +71 -0
  103. package/dist/chunk-O7F6UJO4.js.map +1 -0
  104. package/dist/chunk-OYQQJL3J.js +16 -0
  105. package/dist/chunk-OYQQJL3J.js.map +1 -0
  106. package/dist/{chunk-H5YGYNXS.js → chunk-P4BNUO57.js} +60 -17
  107. package/dist/chunk-P4BNUO57.js.map +1 -0
  108. package/dist/{chunk-JVYQRRC4.js → chunk-PEHTX3V7.js} +21 -1
  109. package/dist/chunk-PEHTX3V7.js.map +1 -0
  110. package/dist/chunk-PMV53IMM.js +26 -0
  111. package/dist/chunk-PMV53IMM.js.map +1 -0
  112. package/dist/{chunk-KCGXPP5V.js → chunk-PYEOPA4M.js} +13 -7
  113. package/dist/chunk-PYEOPA4M.js.map +1 -0
  114. package/dist/{chunk-KZ73RL76.js → chunk-QHUE7E4N.js} +8 -3
  115. package/dist/chunk-QHUE7E4N.js.map +1 -0
  116. package/dist/chunk-QV3DJVRZ.js +11 -0
  117. package/dist/chunk-QV3DJVRZ.js.map +1 -0
  118. package/dist/chunk-R5SBNG7S.js +810 -0
  119. package/dist/chunk-R5SBNG7S.js.map +1 -0
  120. package/dist/chunk-RI42H5IU.js +326 -0
  121. package/dist/chunk-RI42H5IU.js.map +1 -0
  122. package/dist/chunk-S2QH6EZ5.js +211 -0
  123. package/dist/chunk-S2QH6EZ5.js.map +1 -0
  124. package/dist/chunk-SHLZMAJN.js +304 -0
  125. package/dist/chunk-SHLZMAJN.js.map +1 -0
  126. package/dist/chunk-TGXK4BAZ.js +293 -0
  127. package/dist/chunk-TGXK4BAZ.js.map +1 -0
  128. package/dist/{chunk-5YK2ZDIG.js → chunk-TNEZNMSN.js} +4 -10
  129. package/dist/chunk-TNEZNMSN.js.map +1 -0
  130. package/dist/{chunk-22KP6LR5.js → chunk-TXS65BB2.js} +3 -1
  131. package/dist/{chunk-22KP6LR5.js.map → chunk-TXS65BB2.js.map} +1 -1
  132. package/dist/chunk-UNJPZGNK.js +63 -0
  133. package/dist/chunk-UNJPZGNK.js.map +1 -0
  134. package/dist/{chunk-IOLVN74D.js → chunk-V5ZUJT2T.js} +175 -42
  135. package/dist/chunk-V5ZUJT2T.js.map +1 -0
  136. package/dist/chunk-WBJY57A3.js +402 -0
  137. package/dist/chunk-WBJY57A3.js.map +1 -0
  138. package/dist/chunk-WIUKB3LD.js +1911 -0
  139. package/dist/chunk-WIUKB3LD.js.map +1 -0
  140. package/dist/{chunk-ICA6R6TW.js → chunk-WNN7NO2N.js} +1451 -355
  141. package/dist/chunk-WNN7NO2N.js.map +1 -0
  142. package/dist/{chunk-3AGBGTRT.js → chunk-X5UVUIMF.js} +1712 -1174
  143. package/dist/chunk-X5UVUIMF.js.map +1 -0
  144. package/dist/chunk-XDA5QJE7.js +402 -0
  145. package/dist/chunk-XDA5QJE7.js.map +1 -0
  146. package/dist/{chunk-VZTQ73XT.js → chunk-XEA5BCMA.js} +3 -1
  147. package/dist/{chunk-VZTQ73XT.js.map → chunk-XEA5BCMA.js.map} +1 -1
  148. package/dist/chunk-XHF7OYAN.js +1150 -0
  149. package/dist/chunk-XHF7OYAN.js.map +1 -0
  150. package/dist/chunk-YSRBFJMQ.js +43 -0
  151. package/dist/chunk-YSRBFJMQ.js.map +1 -0
  152. package/dist/chunk-ZOZAPAUO.js +174 -0
  153. package/dist/chunk-ZOZAPAUO.js.map +1 -0
  154. package/dist/chunk-ZQV5W7YC.js +809 -0
  155. package/dist/chunk-ZQV5W7YC.js.map +1 -0
  156. package/dist/chunk-ZUWF4NF7.js +13 -0
  157. package/dist/chunk-ZUWF4NF7.js.map +1 -0
  158. package/dist/client.d.ts +16 -7
  159. package/dist/clipboard.js +3 -1
  160. package/dist/commands/types.d.ts +2 -0
  161. package/dist/components/anthropic-mark.d.ts +3 -0
  162. package/dist/components/approval-surface.d.ts +19 -6
  163. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  164. package/dist/components/artifacts/artifact-sandbox.d.ts +30 -0
  165. package/dist/components/artifacts/artifact-surface.d.ts +4 -2
  166. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  167. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  168. package/dist/components/artifacts/document-editor.d.ts +4 -2
  169. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  170. package/dist/components/artifacts/editable-artifact-view.d.ts +48 -0
  171. package/dist/components/artifacts/editable-document.d.ts +1 -1
  172. package/dist/components/artifacts/editable-presentation.d.ts +2 -2
  173. package/dist/components/artifacts/editable-spreadsheet.d.ts +8 -3
  174. package/dist/components/artifacts/index.d.ts +9 -2
  175. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  176. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  177. package/dist/components/artifacts/presentation-editor.d.ts +6 -2
  178. package/dist/components/artifacts/published-html-artifact-frame.d.ts +23 -3
  179. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  180. package/dist/components/artifacts/site-view.d.ts +26 -0
  181. package/dist/components/artifacts/spreadsheet-command-queue.d.ts +20 -0
  182. package/dist/components/artifacts/spreadsheet-download.d.ts +7 -0
  183. package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
  184. package/dist/components/artifacts/spreadsheet-grid.d.ts +10 -3
  185. package/dist/components/artifacts/spreadsheet-resize.d.ts +50 -0
  186. package/dist/components/artifacts/spreadsheet-submissions.d.ts +9 -0
  187. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  188. package/dist/components/browser-select-control.d.ts +16 -0
  189. package/dist/components/browser-viewer.d.ts +11 -2
  190. package/dist/components/chat-composer.d.ts +21 -3
  191. package/dist/components/child-session-link.d.ts +9 -0
  192. package/dist/components/claude-mark.d.ts +3 -0
  193. package/dist/components/code-editor.d.ts +1 -4
  194. package/dist/components/composer-transcription-control.d.ts +7 -0
  195. package/dist/components/composer.d.ts +34 -67
  196. package/dist/components/computer-viewer.d.ts +1 -1
  197. package/dist/components/copy-button.d.ts +3 -1
  198. package/dist/components/desktop-viewer.d.ts +1 -1
  199. package/dist/components/grok-mark.d.ts +26 -0
  200. package/dist/components/human-input-form.d.ts +28 -32
  201. package/dist/components/human-input-surface.d.ts +7 -2
  202. package/dist/components/linkified-text.d.ts +18 -0
  203. package/dist/components/machine-input-display.d.ts +22 -1
  204. package/dist/components/machines/agent-status-icon.d.ts +6 -0
  205. package/dist/components/machines/machine-detail.d.ts +7 -1
  206. package/dist/components/machines/machine-status.d.ts +48 -0
  207. package/dist/components/markdown-table-layout.d.ts +18 -0
  208. package/dist/components/markdown.d.ts +37 -4
  209. package/dist/components/message-timeline.d.ts +86 -7
  210. package/dist/components/model-mark.d.ts +29 -0
  211. package/dist/components/model-policy-picker-menu.d.ts +9 -0
  212. package/dist/components/model-policy-picker.d.ts +35 -28
  213. package/dist/components/new-conversation.d.ts +32 -0
  214. package/dist/components/open-geni-chat.d.ts +73 -0
  215. package/dist/components/open-geni-links.d.ts +68 -0
  216. package/dist/components/openrouter-mark.d.ts +6 -0
  217. package/dist/components/opper-mark.d.ts +7 -0
  218. package/dist/components/preview-loading.d.ts +2 -0
  219. package/dist/components/provider-recovery-notice.d.ts +16 -0
  220. package/dist/components/queue-item-content.d.ts +9 -0
  221. package/dist/components/rehype-secret-refs.d.ts +23 -0
  222. package/dist/components/remark-soft-line-breaks.d.ts +38 -0
  223. package/dist/components/sandbox-files.d.ts +3 -1
  224. package/dist/components/sandbox-workspace.d.ts +18 -0
  225. package/dist/components/secret-question-field.d.ts +31 -0
  226. package/dist/components/secret-ref-chip.d.ts +35 -0
  227. package/dist/components/session-capability-frame.d.ts +37 -0
  228. package/dist/components/session-chrome.d.ts +57 -8
  229. package/dist/components/session-commands-panel.d.ts +6 -0
  230. package/dist/components/session-commands.d.ts +6 -0
  231. package/dist/components/session-connection-request.d.ts +8 -0
  232. package/dist/components/session-conversation.d.ts +157 -0
  233. package/dist/components/session-list.d.ts +39 -0
  234. package/dist/components/session-mcp-capability-card.d.ts +41 -0
  235. package/dist/components/session-proxy-scope.d.ts +35 -0
  236. package/dist/components/session-status.d.ts +4 -1
  237. package/dist/components/session-usage-limit-notice.d.ts +39 -0
  238. package/dist/components/timeline-anchor.d.ts +24 -0
  239. package/dist/components/timeline-annotation-chrome.d.ts +25 -0
  240. package/dist/components/timeline-annotation-layout.d.ts +42 -0
  241. package/dist/components/timeline-annotation-markers.d.ts +8 -0
  242. package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
  243. package/dist/components/timeline-annotation-shared.d.ts +31 -0
  244. package/dist/components/timeline-annotations-dialog.d.ts +3 -2
  245. package/dist/components/timeline-annotations.d.ts +13 -3
  246. package/dist/components/timeline-reading-progress.d.ts +11 -0
  247. package/dist/components/timeline-search.d.ts +34 -0
  248. package/dist/components/timeline-settlement.d.ts +16 -0
  249. package/dist/components/tool-action-review.d.ts +47 -0
  250. package/dist/components/tool-review-history.d.ts +25 -0
  251. package/dist/components/usage-limit-notice.d.ts +49 -0
  252. package/dist/components/usage-member-list.d.ts +91 -0
  253. package/dist/components/usage-meter.d.ts +73 -0
  254. package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
  255. package/dist/components/user-message-body.d.ts +10 -1
  256. package/dist/composer-messages.d.ts +74 -0
  257. package/dist/composer-messages.js +9 -0
  258. package/dist/composer-messages.js.map +1 -0
  259. package/dist/composer-voice-events.d.ts +8 -0
  260. package/dist/composer.d.ts +5 -4
  261. package/dist/composer.js +26 -13
  262. package/dist/computer-viewer-GMLDXPON.js +20 -0
  263. package/dist/computer-viewer-GMLDXPON.js.map +1 -0
  264. package/dist/connect-account-identity.d.ts +8 -0
  265. package/dist/connect-accounts.d.ts +15 -0
  266. package/dist/connect-chooser.d.ts +18 -0
  267. package/dist/connect-panel.d.ts +18 -0
  268. package/dist/connect-setup.d.ts +18 -0
  269. package/dist/connect.d.ts +21 -0
  270. package/dist/connect.js +2149 -0
  271. package/dist/connect.js.map +1 -0
  272. package/dist/connection-catalog.d.ts +38 -0
  273. package/dist/connection-discovery.d.ts +12 -0
  274. package/dist/connection-installed.d.ts +17 -0
  275. package/dist/connection-logo.d.ts +9 -0
  276. package/dist/connection-service-logo.d.ts +8 -0
  277. package/dist/connection-service-presentation.d.ts +13 -0
  278. package/dist/connection-skeleton.d.ts +5 -0
  279. package/dist/connection-type-picker.d.ts +6 -0
  280. package/dist/conversation-timeline.d.ts +5 -0
  281. package/dist/desktop.d.ts +7 -0
  282. package/dist/desktop.js +27 -0
  283. package/dist/desktop.js.map +1 -0
  284. package/dist/device-authorization.d.ts +23 -0
  285. package/dist/diffs.d.ts +8 -0
  286. package/dist/diffs.js +15 -0
  287. package/dist/diffs.js.map +1 -0
  288. package/dist/discovery-cache.d.ts +5 -0
  289. package/dist/editor.d.ts +7 -0
  290. package/dist/editor.js +22 -0
  291. package/dist/editor.js.map +1 -0
  292. package/dist/embedded-new-voice-OCRNT6U5.js +18 -0
  293. package/dist/embedded-new-voice-OCRNT6U5.js.map +1 -0
  294. package/dist/embedded-voice-RPHPYVBT.js +18 -0
  295. package/dist/embedded-voice-RPHPYVBT.js.map +1 -0
  296. package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-SI63O5V4.js} +4 -1
  297. package/dist/fleet-decision-row-SI63O5V4.js.map +1 -0
  298. package/dist/hooks/latest-question.d.ts +25 -0
  299. package/dist/hooks/shared-machines-list.d.ts +4 -0
  300. package/dist/hooks/shared-query.d.ts +113 -0
  301. package/dist/hooks/use-attached-browsers.d.ts +1 -1
  302. package/dist/hooks/use-auth-runs.d.ts +1 -4
  303. package/dist/hooks/use-available-models.d.ts +1 -1
  304. package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
  305. package/dist/hooks/use-browser-session.d.ts +12 -1
  306. package/dist/hooks/use-client-config-flags.d.ts +49 -0
  307. package/dist/hooks/use-codex-accounts.d.ts +59 -10
  308. package/dist/hooks/use-composer.d.ts +24 -2
  309. package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
  310. package/dist/hooks/use-computer-input-posture.d.ts +13 -0
  311. package/dist/hooks/use-computer-session.d.ts +4 -0
  312. package/dist/hooks/use-connect.d.ts +23 -0
  313. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  314. package/dist/hooks/use-file-attachments.d.ts +12 -0
  315. package/dist/hooks/use-goal.d.ts +2 -1
  316. package/dist/hooks/use-last-started-turn-policy.d.ts +5 -1
  317. package/dist/hooks/use-new-conversation.d.ts +56 -0
  318. package/dist/hooks/use-new-session-draft.d.ts +74 -0
  319. package/dist/hooks/use-realtime-voice-models.d.ts +7 -0
  320. package/dist/hooks/use-sandbox-files.d.ts +4 -1
  321. package/dist/hooks/use-session-conversation.d.ts +49 -0
  322. package/dist/hooks/use-session-events.d.ts +26 -5
  323. package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
  324. package/dist/hooks/use-session-model-account.d.ts +48 -0
  325. package/dist/hooks/use-supergrok-accounts.d.ts +7 -1
  326. package/dist/hooks/use-terminal-stream.d.ts +11 -5
  327. package/dist/hooks/use-usage.d.ts +40 -0
  328. package/dist/hooks/use-vaults.d.ts +53 -0
  329. package/dist/hooks/use-voice-input.d.ts +8 -1
  330. package/dist/hooks/use-workspace-edit.d.ts +4 -0
  331. package/dist/hooks/use-workspace-sessions.d.ts +24 -5
  332. package/dist/human-input-model.d.ts +122 -0
  333. package/dist/identity-link-accounts.d.ts +11 -0
  334. package/dist/identity-link-consent.d.ts +18 -0
  335. package/dist/index.d.ts +82 -20
  336. package/dist/index.js +2340 -6603
  337. package/dist/index.js.map +1 -1
  338. package/dist/interaction.d.ts +1 -1
  339. package/dist/interaction.js +14 -24
  340. package/dist/interaction.js.map +1 -1
  341. package/dist/latest-question-R77KWSUP.js +118 -0
  342. package/dist/latest-question-R77KWSUP.js.map +1 -0
  343. package/dist/lib/clipboard.d.ts +7 -0
  344. package/dist/lib/error-message.d.ts +7 -0
  345. package/dist/lib/format.d.ts +58 -4
  346. package/dist/lib/host-theme.d.ts +77 -0
  347. package/dist/lib/interaction-errors.d.ts +3 -0
  348. package/dist/lib/menu-styles.d.ts +22 -0
  349. package/dist/lib/notify-observer.d.ts +2 -0
  350. package/dist/lib/pierre-diffs-loader.d.ts +20 -0
  351. package/dist/lib/provider-recovery.d.ts +55 -0
  352. package/dist/lib/scrollbars.d.ts +11 -0
  353. package/dist/lib/terminal-input-readiness.d.ts +11 -0
  354. package/dist/lib/transient-retry.d.ts +25 -0
  355. package/dist/lib/workbench-peers.d.ts +36 -0
  356. package/dist/lib/xterm-theme.d.ts +7 -5
  357. package/dist/machines.js +9 -5
  358. package/dist/markdown-table-layout-3PV2UAAH.js +113 -0
  359. package/dist/markdown-table-layout-3PV2UAAH.js.map +1 -0
  360. package/dist/mcp-connection-status.d.ts +14 -0
  361. package/dist/model-mark-paths.d.ts +34 -0
  362. package/dist/model-mark-paths.js +16 -0
  363. package/dist/model-mark-paths.js.map +1 -0
  364. package/dist/model-picker-model.d.ts +111 -0
  365. package/dist/model-picker-model.js +25 -0
  366. package/dist/model-picker-model.js.map +1 -0
  367. package/dist/model-policy-picker-menu-7GJ5URPR.js +17 -0
  368. package/dist/model-policy-picker-menu-7GJ5URPR.js.map +1 -0
  369. package/dist/model-policy.d.ts +30 -3
  370. package/dist/model-policy.js +14 -1
  371. package/dist/native-previews.d.ts +28 -0
  372. package/dist/native-previews.js +82 -0
  373. package/dist/native-previews.js.map +1 -0
  374. package/dist/new-session-draft.d.ts +7 -0
  375. package/dist/new-session-draft.js +639 -0
  376. package/dist/new-session-draft.js.map +1 -0
  377. package/dist/notification-text.d.ts +27 -0
  378. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js → noto-sans-arabic-loader-XSH2KYWJ.js} +3 -1
  379. package/dist/{noto-sans-arabic-loader-IA2T4X2A.js.map → noto-sans-arabic-loader-XSH2KYWJ.js.map} +1 -1
  380. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js → noto-sans-jp-loader.generated-MR5L6V7K.js} +3 -1
  381. package/dist/{noto-sans-jp-loader.generated-HFGLYBR3.js.map → noto-sans-jp-loader.generated-MR5L6V7K.js.map} +1 -1
  382. package/dist/older-history.d.ts +3 -2
  383. package/dist/organization-model.d.ts +32 -0
  384. package/dist/organization-model.js +65 -0
  385. package/dist/organization-model.js.map +1 -0
  386. package/dist/{platform-activity-row-BJHUHXAT.js → platform-activity-row-5OCKOQWZ.js} +16 -78
  387. package/dist/platform-activity-row-5OCKOQWZ.js.map +1 -0
  388. package/dist/plugin-details.d.ts +14 -0
  389. package/dist/plugin-discovery.d.ts +25 -0
  390. package/dist/preview-loading-paint.d.ts +20 -0
  391. package/dist/provider.d.ts +25 -2
  392. package/dist/queue-presentation-model.d.ts +72 -0
  393. package/dist/queue-presentation-model.js +38 -0
  394. package/dist/queue-presentation-model.js.map +1 -0
  395. package/dist/{queue-surface-implementation-BSKUWHRI.js → queue-surface-implementation-GJBH7NKO.js} +65 -265
  396. package/dist/queue-surface-implementation-GJBH7NKO.js.map +1 -0
  397. package/dist/realtime/embedded-new-voice.d.ts +1 -0
  398. package/dist/realtime/embedded-voice.d.ts +1 -0
  399. package/dist/realtime/realtime-control.d.ts +4 -65
  400. package/dist/realtime/session-realtime.d.ts +78 -0
  401. package/dist/realtime.js +25 -1333
  402. package/dist/realtime.js.map +1 -1
  403. package/dist/sandbox-files-O27IPOZW.js +21 -0
  404. package/dist/sandbox-files-O27IPOZW.js.map +1 -0
  405. package/dist/sandbox-label-model.d.ts +30 -0
  406. package/dist/sandbox-label-model.js +20 -0
  407. package/dist/sandbox-label-model.js.map +1 -0
  408. package/dist/scrollbars.d.ts +1 -0
  409. package/dist/scrollbars.js +10 -0
  410. package/dist/scrollbars.js.map +1 -0
  411. package/dist/secret-reference-label.d.ts +14 -0
  412. package/dist/secrets-ui.d.ts +57 -0
  413. package/dist/session-agents-model.d.ts +10 -0
  414. package/dist/session-agents-model.js +25 -0
  415. package/dist/session-agents-model.js.map +1 -0
  416. package/dist/session-attention-model.d.ts +8 -0
  417. package/dist/session-attention-model.js +47 -0
  418. package/dist/session-attention-model.js.map +1 -0
  419. package/dist/session-auth-recommendation.d.ts +5 -0
  420. package/dist/session-capability-policy.d.ts +31 -0
  421. package/dist/session-feedback-model.d.ts +20 -0
  422. package/dist/session-feedback-model.js +56 -0
  423. package/dist/session-feedback-model.js.map +1 -0
  424. package/dist/session-list-model.d.ts +138 -0
  425. package/dist/session-list-model.js +274 -0
  426. package/dist/session-list-model.js.map +1 -0
  427. package/dist/session-realtime-7DJOIHQW.js +21 -0
  428. package/dist/session-realtime-7DJOIHQW.js.map +1 -0
  429. package/dist/session-realtime.d.ts +7 -0
  430. package/dist/session-realtime.js +19 -0
  431. package/dist/session-realtime.js.map +1 -0
  432. package/dist/session-status-model.d.ts +36 -0
  433. package/dist/session-ui.d.ts +39 -1
  434. package/dist/session-ui.js +126 -12
  435. package/dist/session-ui.js.map +1 -1
  436. package/dist/session.d.ts +8 -2
  437. package/dist/session.js +35 -20
  438. package/dist/site-snapshot.d.ts +14 -0
  439. package/dist/sites-ui.d.ts +24 -0
  440. package/dist/sites.d.ts +3 -0
  441. package/dist/sites.js +14 -0
  442. package/dist/sites.js.map +1 -0
  443. package/dist/skill-discovery.d.ts +47 -0
  444. package/dist/terminal.d.ts +8 -0
  445. package/dist/terminal.js +32 -0
  446. package/dist/terminal.js.map +1 -0
  447. package/dist/testing/session-scenarios.d.ts +10 -0
  448. package/dist/testing/session-scenarios.js +367 -0
  449. package/dist/testing/session-scenarios.js.map +1 -0
  450. package/dist/timeline/activity-rail.d.ts +11 -2
  451. package/dist/timeline/agent-identity.d.ts +30 -0
  452. package/dist/timeline/agent-row.d.ts +31 -0
  453. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  454. package/dist/timeline/compaction-copy.d.ts +46 -0
  455. package/dist/timeline/focus-sequence.d.ts +9 -0
  456. package/dist/timeline/genie-copy.d.ts +3 -0
  457. package/dist/timeline/genie-loading.d.ts +47 -0
  458. package/dist/timeline/index.d.ts +10 -5
  459. package/dist/timeline/knowledge-receipt.d.ts +17 -0
  460. package/dist/timeline/message-sender.d.ts +19 -0
  461. package/dist/timeline/notice-presentation.d.ts +13 -0
  462. package/dist/timeline/parsers.d.ts +11 -0
  463. package/dist/timeline/patch-apply-command.d.ts +18 -0
  464. package/dist/timeline/platform-activity-presentation.d.ts +21 -0
  465. package/dist/timeline/platform-activity-row.d.ts +1 -2
  466. package/dist/timeline/presented-image.d.ts +11 -0
  467. package/dist/timeline/projection.d.ts +31 -2
  468. package/dist/timeline/provider-logo.d.ts +15 -0
  469. package/dist/timeline/question-nav-model.d.ts +23 -0
  470. package/dist/timeline/registry.d.ts +12 -1
  471. package/dist/timeline/retained-image.d.ts +18 -0
  472. package/dist/timeline/retained-loaders.d.ts +27 -0
  473. package/dist/timeline/rolling-activity.d.ts +11 -0
  474. package/dist/timeline/screenshot-lightbox.d.ts +23 -1
  475. package/dist/timeline/session-usage-limit-row.d.ts +11 -0
  476. package/dist/timeline/shared.d.ts +4 -1
  477. package/dist/timeline/startup-dispatch-details.d.ts +5 -0
  478. package/dist/timeline/startup-preference.d.ts +3 -0
  479. package/dist/timeline/startup-timings.d.ts +4 -0
  480. package/dist/timeline/tool-display-name.d.ts +5 -2
  481. package/dist/timeline/tool-presentation.d.ts +172 -0
  482. package/dist/timeline/turn-summary-model.d.ts +95 -0
  483. package/dist/timeline/turn-summary.d.ts +20 -54
  484. package/dist/timeline/types.d.ts +179 -7
  485. package/dist/timeline/work-presentation.d.ts +60 -0
  486. package/dist/timeline-annotation-markers-U3G66KUD.js +166 -0
  487. package/dist/timeline-annotation-markers-U3G66KUD.js.map +1 -0
  488. package/dist/timeline-annotation-selection-BI7QTPTZ.js +242 -0
  489. package/dist/timeline-annotation-selection-BI7QTPTZ.js.map +1 -0
  490. package/dist/timeline-annotations-dialog-FOMHSDTE.js +274 -0
  491. package/dist/timeline-annotations-dialog-FOMHSDTE.js.map +1 -0
  492. package/dist/timeline-model.d.ts +29 -0
  493. package/dist/timeline-model.js +254 -0
  494. package/dist/timeline-model.js.map +1 -0
  495. package/dist/usage/allowance-copy.d.ts +25 -0
  496. package/dist/usage/session-usage-limit.d.ts +88 -0
  497. package/dist/usage/summary.d.ts +35 -0
  498. package/dist/usage.d.ts +17 -0
  499. package/dist/usage.js +1187 -0
  500. package/dist/usage.js.map +1 -0
  501. package/dist/voice-recording-owner.d.ts +7 -0
  502. package/package.json +106 -7
  503. package/src/approvals.ts +8 -1
  504. package/src/artifacts-spreadsheet.ts +1 -0
  505. package/src/artifacts.ts +44 -0
  506. package/src/assets/README.md +8 -0
  507. package/src/assets/gmail.ico +0 -0
  508. package/src/assets/outlook.ico +0 -0
  509. package/src/capability-catalog-row.tsx +94 -0
  510. package/src/capability-logo-fallback.ts +22 -0
  511. package/src/client.ts +20 -31
  512. package/src/commands/registry.ts +18 -15
  513. package/src/commands/types.ts +2 -0
  514. package/src/components/anthropic-mark.tsx +10 -0
  515. package/src/components/approval-surface.tsx +401 -138
  516. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  517. package/src/components/artifacts/artifact-sandbox.tsx +193 -0
  518. package/src/components/artifacts/artifact-surface.tsx +40 -20
  519. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  520. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  521. package/src/components/artifacts/document-editor.tsx +141 -16
  522. package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
  523. package/src/components/artifacts/editable-artifact-view.tsx +197 -0
  524. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  525. package/src/components/artifacts/editable-document.tsx +37 -36
  526. package/src/components/artifacts/editable-presentation.tsx +36 -18
  527. package/src/components/artifacts/editable-spreadsheet.tsx +543 -103
  528. package/src/components/artifacts/index.ts +45 -0
  529. package/src/components/artifacts/inline-html-document.ts +24 -0
  530. package/src/components/artifacts/latest-task-runner.ts +49 -0
  531. package/src/components/artifacts/presentation-editor.tsx +323 -67
  532. package/src/components/artifacts/published-html-artifact-frame.tsx +122 -5
  533. package/src/components/artifacts/session-artifact-viewer.tsx +378 -0
  534. package/src/components/artifacts/site-view.tsx +121 -0
  535. package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
  536. package/src/components/artifacts/spreadsheet-command-queue.ts +184 -0
  537. package/src/components/artifacts/spreadsheet-download.tsx +109 -0
  538. package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
  539. package/src/components/artifacts/spreadsheet-grid.tsx +344 -144
  540. package/src/components/artifacts/spreadsheet-resize.tsx +421 -0
  541. package/src/components/artifacts/spreadsheet-submissions.tsx +46 -0
  542. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  543. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  544. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  545. package/src/components/browser-select-control.tsx +312 -0
  546. package/src/components/browser-viewer.tsx +778 -318
  547. package/src/components/chat-composer.tsx +47 -5
  548. package/src/components/child-session-link.tsx +36 -0
  549. package/src/components/claude-mark.tsx +11 -0
  550. package/src/components/code-editor.tsx +13 -16
  551. package/src/components/composer-transcription-control.tsx +128 -30
  552. package/src/components/composer.tsx +404 -195
  553. package/src/components/computer-viewer.tsx +880 -253
  554. package/src/components/copy-button.tsx +13 -5
  555. package/src/components/desktop-viewer.tsx +1 -1
  556. package/src/components/enrollment-consent.tsx +1 -1
  557. package/src/components/enrollment-device-flow.tsx +1 -1
  558. package/src/components/file-browser.tsx +10 -14
  559. package/src/components/fleet-tile.tsx +5 -3
  560. package/src/components/generated-video-player.tsx +4 -2
  561. package/src/components/grok-mark.tsx +34 -0
  562. package/src/components/human-input-form.tsx +590 -283
  563. package/src/components/human-input-surface.tsx +11 -0
  564. package/src/components/interaction-intervention-banner.tsx +2 -2
  565. package/src/components/linkified-text.tsx +79 -0
  566. package/src/components/machine-card.tsx +35 -78
  567. package/src/components/machine-dock-bar.tsx +1 -1
  568. package/src/components/machine-input-display.ts +197 -3
  569. package/src/components/machines/agent-status-icon.tsx +31 -0
  570. package/src/components/machines/machine-detail.tsx +200 -31
  571. package/src/components/machines/machine-operation-policy.tsx +1 -1
  572. package/src/components/machines/machine-status.ts +241 -0
  573. package/src/components/machines-dashboard.tsx +2 -17
  574. package/src/components/markdown-table-layout.ts +143 -0
  575. package/src/components/markdown.tsx +466 -129
  576. package/src/components/message-timeline.tsx +2370 -667
  577. package/src/components/model-mark.tsx +102 -0
  578. package/src/components/model-picker.tsx +15 -4
  579. package/src/components/model-policy-picker-menu.tsx +371 -0
  580. package/src/components/model-policy-picker.tsx +252 -429
  581. package/src/components/new-conversation.tsx +221 -0
  582. package/src/components/open-geni-chat.tsx +309 -0
  583. package/src/components/open-geni-links.tsx +179 -0
  584. package/src/components/openrouter-mark.tsx +13 -0
  585. package/src/components/opper-mark.tsx +18 -0
  586. package/src/components/pierre-diff.tsx +41 -16
  587. package/src/components/pierre-file.tsx +35 -10
  588. package/src/components/preview-loading.tsx +109 -0
  589. package/src/components/provider-recovery-notice.tsx +49 -0
  590. package/src/components/queue-item-content.ts +14 -0
  591. package/src/components/queue-surface-implementation.tsx +51 -356
  592. package/src/components/queue-surface-state.tsx +3 -1
  593. package/src/components/rehype-secret-refs.ts +98 -0
  594. package/src/components/remark-soft-line-breaks.ts +166 -0
  595. package/src/components/sandbox-files.tsx +91 -15
  596. package/src/components/sandbox-terminal.tsx +84 -13
  597. package/src/components/sandbox-workspace.tsx +147 -51
  598. package/src/components/secret-question-field.tsx +324 -0
  599. package/src/components/secret-ref-chip.tsx +185 -0
  600. package/src/components/session-capability-frame.tsx +197 -0
  601. package/src/components/session-chrome.tsx +842 -251
  602. package/src/components/session-commands-panel.tsx +126 -0
  603. package/src/components/session-commands.tsx +18 -0
  604. package/src/components/session-connection-request.tsx +97 -0
  605. package/src/components/session-conversation.tsx +876 -0
  606. package/src/components/session-list.tsx +257 -0
  607. package/src/components/session-mcp-capability-card.tsx +680 -0
  608. package/src/components/session-proxy-scope.tsx +153 -0
  609. package/src/components/session-status.tsx +26 -17
  610. package/src/components/session-usage-limit-notice.tsx +174 -0
  611. package/src/components/timeline-anchor.tsx +119 -0
  612. package/src/components/timeline-annotation-chrome.tsx +196 -0
  613. package/src/components/timeline-annotation-layout.ts +268 -0
  614. package/src/components/timeline-annotation-markers.tsx +185 -0
  615. package/src/components/timeline-annotation-reveal-context.ts +9 -0
  616. package/src/components/timeline-annotation-selection.tsx +106 -54
  617. package/src/components/timeline-annotation-shared.ts +245 -0
  618. package/src/components/timeline-annotations-dialog.tsx +185 -128
  619. package/src/components/timeline-annotations.tsx +189 -45
  620. package/src/components/timeline-reading-progress.ts +80 -0
  621. package/src/components/timeline-search.tsx +168 -0
  622. package/src/components/timeline-settlement.ts +60 -0
  623. package/src/components/tool-action-review.tsx +650 -0
  624. package/src/components/tool-review-history.tsx +88 -0
  625. package/src/components/usage-limit-notice.tsx +179 -0
  626. package/src/components/usage-member-list.tsx +792 -0
  627. package/src/components/usage-meter.tsx +382 -0
  628. package/src/components/use-viewer-menu-dismiss.ts +33 -0
  629. package/src/components/user-message-body.tsx +27 -2
  630. package/src/components/workspace-dock.tsx +18 -1
  631. package/src/composer-messages.ts +150 -0
  632. package/src/composer-voice-events.ts +12 -0
  633. package/src/composer.ts +6 -1
  634. package/src/connect-account-identity.tsx +34 -0
  635. package/src/connect-accounts.tsx +233 -0
  636. package/src/connect-chooser.tsx +336 -0
  637. package/src/connect-panel.tsx +99 -0
  638. package/src/connect-setup.tsx +355 -0
  639. package/src/connect.ts +60 -0
  640. package/src/connection-assets.d.ts +4 -0
  641. package/src/connection-catalog.tsx +162 -0
  642. package/src/connection-discovery.tsx +238 -0
  643. package/src/connection-installed.tsx +51 -0
  644. package/src/connection-logo.tsx +37 -0
  645. package/src/connection-service-logo.tsx +55 -0
  646. package/src/connection-service-presentation.ts +46 -0
  647. package/src/connection-skeleton.tsx +16 -0
  648. package/src/connection-type-picker.tsx +36 -0
  649. package/src/conversation-timeline.ts +92 -0
  650. package/src/desktop.ts +24 -0
  651. package/src/device-authorization.tsx +98 -0
  652. package/src/diffs.ts +16 -0
  653. package/src/discovery-cache.ts +42 -0
  654. package/src/editor.ts +13 -0
  655. package/src/hooks/internal.ts +3 -2
  656. package/src/hooks/latest-question.ts +164 -0
  657. package/src/hooks/shared-machines-list.ts +34 -1
  658. package/src/hooks/shared-query.ts +721 -0
  659. package/src/hooks/use-attached-browsers.ts +1 -1
  660. package/src/hooks/use-auth-runs.ts +0 -27
  661. package/src/hooks/use-available-models.ts +2 -2
  662. package/src/hooks/use-browser-frame-stream.ts +19 -2
  663. package/src/hooks/use-browser-session.ts +680 -205
  664. package/src/hooks/use-browser-sessions.ts +32 -1
  665. package/src/hooks/use-client-config-flags.ts +118 -0
  666. package/src/hooks/use-codex-accounts.ts +247 -47
  667. package/src/hooks/use-composer.ts +227 -44
  668. package/src/hooks/use-computer-frame-stream.ts +25 -7
  669. package/src/hooks/use-computer-input-posture.ts +94 -0
  670. package/src/hooks/use-computer-session.ts +409 -95
  671. package/src/hooks/use-connect.ts +23 -0
  672. package/src/hooks/use-desktop-stream.ts +19 -28
  673. package/src/hooks/use-file-attachments.ts +80 -4
  674. package/src/hooks/use-goal.ts +79 -9
  675. package/src/hooks/use-last-started-turn-policy.ts +37 -11
  676. package/src/hooks/use-machines.ts +4 -0
  677. package/src/hooks/use-new-conversation.ts +374 -0
  678. package/src/hooks/use-new-session-draft.ts +813 -0
  679. package/src/hooks/use-realtime-voice-models.ts +46 -0
  680. package/src/hooks/use-sandbox-files.ts +68 -20
  681. package/src/hooks/use-session-background-commands.ts +22 -11
  682. package/src/hooks/use-session-capabilities.ts +3 -2
  683. package/src/hooks/use-session-conversation.ts +150 -0
  684. package/src/hooks/use-session-events.ts +531 -335
  685. package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
  686. package/src/hooks/use-session-model-account.ts +174 -0
  687. package/src/hooks/use-session.ts +30 -2
  688. package/src/hooks/use-slash-commands.ts +6 -11
  689. package/src/hooks/use-supergrok-accounts.ts +22 -8
  690. package/src/hooks/use-terminal-stream.ts +153 -27
  691. package/src/hooks/use-transcription.ts +6 -0
  692. package/src/hooks/use-turn-queue.ts +2 -1
  693. package/src/hooks/use-usage.ts +100 -0
  694. package/src/hooks/use-vaults.ts +153 -0
  695. package/src/hooks/use-video-artifact-playback.ts +1 -1
  696. package/src/hooks/use-voice-input.ts +127 -19
  697. package/src/hooks/use-workspace-capture.ts +3 -2
  698. package/src/hooks/use-workspace-edit.ts +23 -5
  699. package/src/hooks/use-workspace-sessions.ts +74 -7
  700. package/src/human-input-model.ts +359 -0
  701. package/src/identity-link-accounts.tsx +148 -0
  702. package/src/identity-link-consent.tsx +192 -0
  703. package/src/index.ts +262 -16
  704. package/src/interaction.ts +1 -0
  705. package/src/lib/clipboard.ts +29 -0
  706. package/src/lib/error-message.ts +37 -0
  707. package/src/lib/format.ts +205 -10
  708. package/src/lib/host-theme.ts +529 -0
  709. package/src/lib/interaction-errors.ts +15 -0
  710. package/src/lib/menu-styles.ts +44 -0
  711. package/src/lib/notify-observer.ts +15 -0
  712. package/src/lib/pierre-diffs-loader.ts +53 -0
  713. package/src/lib/provider-recovery.ts +243 -0
  714. package/src/lib/scrollbars.ts +30 -0
  715. package/src/lib/terminal-input-readiness.ts +51 -0
  716. package/src/lib/transient-retry.ts +99 -0
  717. package/src/lib/workbench-peers.ts +62 -0
  718. package/src/lib/xterm-theme.ts +23 -21
  719. package/src/mcp-connection-status.ts +35 -0
  720. package/src/model-mark-paths.ts +53 -0
  721. package/src/model-picker-model.ts +330 -0
  722. package/src/model-policy.ts +299 -74
  723. package/src/native-previews.ts +100 -0
  724. package/src/new-session-draft.ts +22 -0
  725. package/src/notification-text.ts +81 -0
  726. package/src/older-history.ts +22 -4
  727. package/src/organization-model.ts +118 -0
  728. package/src/plugin-details.tsx +185 -0
  729. package/src/plugin-discovery.tsx +196 -0
  730. package/src/preview-loading-paint.ts +68 -0
  731. package/src/provider.tsx +74 -15
  732. package/src/queue-presentation-model.ts +464 -0
  733. package/src/realtime/dropdown-menu.tsx +19 -12
  734. package/src/realtime/embedded-new-voice.tsx +1 -0
  735. package/src/realtime/embedded-voice.tsx +3 -0
  736. package/src/realtime/realtime-control.tsx +138 -550
  737. package/src/realtime/session-realtime.ts +566 -0
  738. package/src/sandbox-label-model.ts +53 -0
  739. package/src/scrollbars.ts +3 -0
  740. package/src/secret-reference-label.ts +43 -0
  741. package/src/secrets-ui.tsx +59 -0
  742. package/src/session-agents-model.ts +33 -0
  743. package/src/session-attention-model.ts +62 -0
  744. package/src/session-auth-recommendation.ts +48 -0
  745. package/src/session-capability-policy.ts +196 -0
  746. package/src/session-context.ts +3 -4
  747. package/src/session-feedback-model.ts +95 -0
  748. package/src/session-list-model.ts +434 -0
  749. package/src/session-realtime.ts +18 -0
  750. package/src/session-status-model.ts +99 -0
  751. package/src/session-ui.ts +98 -1
  752. package/src/session.ts +17 -1
  753. package/src/site-snapshot.ts +74 -0
  754. package/src/sites-ui.tsx +348 -0
  755. package/src/sites.ts +3 -0
  756. package/src/skill-discovery.tsx +208 -0
  757. package/src/terminal.ts +26 -0
  758. package/src/testing/session-scenarios.ts +404 -0
  759. package/src/timeline/activity-rail.tsx +242 -101
  760. package/src/timeline/agent-identity.tsx +84 -0
  761. package/src/timeline/agent-row.tsx +231 -0
  762. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  763. package/src/timeline/compaction-copy.ts +115 -0
  764. package/src/timeline/fleet-decision-projection.ts +2 -1
  765. package/src/timeline/fleet-decision-row.tsx +1 -0
  766. package/src/timeline/focus-sequence.ts +44 -0
  767. package/src/timeline/genie-copy.ts +19 -0
  768. package/src/timeline/genie-loading.tsx +143 -0
  769. package/src/timeline/index.ts +30 -2
  770. package/src/timeline/knowledge-receipt.tsx +100 -0
  771. package/src/timeline/message-sender.tsx +71 -0
  772. package/src/timeline/notice-presentation.ts +48 -0
  773. package/src/timeline/parsers.ts +42 -2
  774. package/src/timeline/patch-apply-command.tsx +135 -0
  775. package/src/timeline/platform-activity-presentation.ts +166 -0
  776. package/src/timeline/platform-activity-row.tsx +15 -90
  777. package/src/timeline/presented-image.ts +63 -0
  778. package/src/timeline/projection.ts +1742 -76
  779. package/src/timeline/provider-logo.tsx +53 -0
  780. package/src/timeline/question-nav-model.ts +28 -0
  781. package/src/timeline/registry.ts +26 -4
  782. package/src/timeline/retained-image.ts +97 -0
  783. package/src/timeline/retained-loaders.ts +91 -0
  784. package/src/timeline/rolling-activity.tsx +80 -0
  785. package/src/timeline/screenshot-lightbox.tsx +228 -5
  786. package/src/timeline/session-usage-limit-row.tsx +42 -0
  787. package/src/timeline/shared.tsx +42 -15
  788. package/src/timeline/startup-dispatch-details.tsx +36 -0
  789. package/src/timeline/startup-preference.ts +33 -0
  790. package/src/timeline/startup-timings.tsx +145 -0
  791. package/src/timeline/tool-display-name.ts +19 -7
  792. package/src/timeline/tool-presentation.ts +1316 -0
  793. package/src/timeline/tool-renderers.tsx +835 -1138
  794. package/src/timeline/turn-summary-model.ts +343 -0
  795. package/src/timeline/turn-summary.tsx +272 -365
  796. package/src/timeline/types.ts +189 -6
  797. package/src/timeline/work-presentation.ts +189 -0
  798. package/src/timeline-model.ts +143 -0
  799. package/src/usage/allowance-copy.ts +64 -0
  800. package/src/usage/session-usage-limit.ts +266 -0
  801. package/src/usage/summary.ts +93 -0
  802. package/src/usage.ts +70 -0
  803. package/src/voice-recording-owner.ts +22 -0
  804. package/styles/compiled.css +2319 -748
  805. package/styles/connect.css +290 -0
  806. package/styles/connect.d.ts +1 -0
  807. package/styles/effective-tokens.css +1 -0
  808. package/styles/index.css +309 -9
  809. package/styles/responsive.css +99 -7
  810. package/styles/session-capability.css +44 -0
  811. package/styles/tokens.css +134 -66
  812. package/dist/browser-viewer-MKKFRRRV.js +0 -14
  813. package/dist/chunk-2DZVYHVO.js +0 -470
  814. package/dist/chunk-2DZVYHVO.js.map +0 -1
  815. package/dist/chunk-3AGBGTRT.js.map +0 -1
  816. package/dist/chunk-4MDLEHXL.js.map +0 -1
  817. package/dist/chunk-5YK2ZDIG.js.map +0 -1
  818. package/dist/chunk-7EAFGICR.js +0 -302
  819. package/dist/chunk-7EAFGICR.js.map +0 -1
  820. package/dist/chunk-ELIYWBZR.js.map +0 -1
  821. package/dist/chunk-H5YGYNXS.js.map +0 -1
  822. package/dist/chunk-HUIKIDM5.js.map +0 -1
  823. package/dist/chunk-ICA6R6TW.js.map +0 -1
  824. package/dist/chunk-IOLVN74D.js.map +0 -1
  825. package/dist/chunk-JAQ5K7W6.js.map +0 -1
  826. package/dist/chunk-JVYQRRC4.js.map +0 -1
  827. package/dist/chunk-KCGXPP5V.js.map +0 -1
  828. package/dist/chunk-KZ73RL76.js.map +0 -1
  829. package/dist/chunk-NEXLLTP4.js.map +0 -1
  830. package/dist/chunk-PEI6RANI.js.map +0 -1
  831. package/dist/chunk-VTOREEXF.js +0 -142
  832. package/dist/chunk-VTOREEXF.js.map +0 -1
  833. package/dist/chunk-WSK7G5LE.js +0 -170
  834. package/dist/chunk-WSK7G5LE.js.map +0 -1
  835. package/dist/chunk-X4A66EWZ.js +0 -223
  836. package/dist/chunk-X4A66EWZ.js.map +0 -1
  837. package/dist/chunk-XYRDDSXF.js.map +0 -1
  838. package/dist/chunk-YG4QEQF5.js +0 -9557
  839. package/dist/chunk-YG4QEQF5.js.map +0 -1
  840. package/dist/chunk-YVCHAQZY.js.map +0 -1
  841. package/dist/chunk-ZPBTI3TE.js.map +0 -1
  842. package/dist/computer-viewer-FWEZISW4.js +0 -16
  843. package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
  844. package/dist/hooks/use-environments.d.ts +0 -41
  845. package/dist/hooks/use-packs.d.ts +0 -32
  846. package/dist/platform-activity-row-BJHUHXAT.js.map +0 -1
  847. package/dist/queue-surface-implementation-BSKUWHRI.js.map +0 -1
  848. package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
  849. package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
  850. package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
  851. package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
  852. package/src/hooks/use-environments.ts +0 -182
  853. package/src/hooks/use-packs.ts +0 -157
  854. /package/dist/{browser-viewer-MKKFRRRV.js.map → browser-viewer-ZWR6MWJ7.js.map} +0 -0
  855. /package/dist/{computer-viewer-FWEZISW4.js.map → chat-interactive-block-4EUKJXUO.js.map} +0 -0
@@ -0,0 +1,3125 @@
1
+ "use client";
2
+ import {
3
+ CodeEditor
4
+ } from "./chunk-LSW2OJVV.js";
5
+ import {
6
+ useThemeType
7
+ } from "./chunk-B27E3V37.js";
8
+ import {
9
+ loadPierreDiffs,
10
+ pierreDiffsRevision,
11
+ subscribePierreDiffs
12
+ } from "./chunk-YSRBFJMQ.js";
13
+ import {
14
+ prefersReducedMotion
15
+ } from "./chunk-OYQQJL3J.js";
16
+ import {
17
+ MENU_BUTTON_CLASS,
18
+ MENU_SEPARATOR_CLASS,
19
+ MENU_SURFACE_CLASS
20
+ } from "./chunk-PMV53IMM.js";
21
+ import {
22
+ usePortalTokenSource,
23
+ usePortalTokenStyle
24
+ } from "./chunk-XEA5BCMA.js";
25
+ import {
26
+ useOpenGeni
27
+ } from "./chunk-G76LSA76.js";
28
+ import {
29
+ sandboxAcceptsLiveIo
30
+ } from "./chunk-QV3DJVRZ.js";
31
+ import {
32
+ cn
33
+ } from "./chunk-TXS65BB2.js";
34
+
35
+ // src/components/sandbox-files.tsx
36
+ import { FileCode2Icon, FileWarningIcon, LoaderCircleIcon } from "lucide-react";
37
+ import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef3, useState as useState4 } from "react";
38
+ import { Group, Panel, Separator } from "react-resizable-panels";
39
+
40
+ // src/hooks/use-sandbox-files.ts
41
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
42
+ var CapturedFileUnavailableError = class extends Error {
43
+ constructor(path, reason) {
44
+ super(
45
+ reason === "too-large" ? `${path} exceeds the captured preview limit.` : reason === "content-missing" ? `${path} is no longer available in this capture.` : `${path} was not changed in this captured turn.`
46
+ );
47
+ this.path = path;
48
+ this.reason = reason;
49
+ this.name = "CapturedFileUnavailableError";
50
+ }
51
+ code = "captured_file_unavailable";
52
+ };
53
+ var FileWriteConflictError = class extends Error {
54
+ constructor(path, expectedContent, liveContent) {
55
+ super(`${path} changed on the machine. Reload it or explicitly overwrite the live version.`);
56
+ this.path = path;
57
+ this.expectedContent = expectedContent;
58
+ this.liveContent = liveContent;
59
+ this.name = "FileWriteConflictError";
60
+ }
61
+ code = "file_write_conflict";
62
+ };
63
+ function normalizeRoot(root) {
64
+ const slashNormalized = root.replaceAll("\\", "/").replace(/^\.\/+/, "");
65
+ if (slashNormalized === "/") return "/";
66
+ const normalized = slashNormalized.replace(/\/+$/, "");
67
+ return normalized === "." ? "" : normalized;
68
+ }
69
+ function isAbsoluteTreePath(path) {
70
+ return path.startsWith("/") || /^[A-Za-z]:\//u.test(path);
71
+ }
72
+ function joinTreeRoot(root, path) {
73
+ if (!root || isAbsoluteTreePath(path)) return path;
74
+ return root === "/" ? `/${path}` : `${root}/${path}`;
75
+ }
76
+ function qualifyStatusPath(root, path, treeRoot) {
77
+ const normalized = normalizeRoot(root);
78
+ const workspaceRelative = joinTreeRoot(normalized, path);
79
+ return joinTreeRoot(normalizeRoot(treeRoot), workspaceRelative);
80
+ }
81
+ function summarizeStatuses(statuses) {
82
+ const repositories = statuses.filter(({ status }) => status.isRepo);
83
+ return {
84
+ branch: repositories.length === 1 ? repositories[0]?.status.head ?? null : null,
85
+ isRepo: repositories.length > 0,
86
+ repoCount: repositories.length,
87
+ ahead: repositories.reduce((sum, { status }) => sum + status.ahead, 0),
88
+ behind: repositories.reduce((sum, { status }) => sum + status.behind, 0),
89
+ dirtyCount: repositories.reduce((sum, { status }) => sum + status.files.length, 0)
90
+ };
91
+ }
92
+ function parentOf(path) {
93
+ const i = path.lastIndexOf("/");
94
+ return i <= 0 ? "" : path.slice(0, i);
95
+ }
96
+ function parentWithinTree(path, rootPath) {
97
+ const parent = parentOf(path);
98
+ return parent === "" && normalizeRoot(rootPath) === "/" && path.startsWith("/") ? "/" : parent;
99
+ }
100
+ function leafOf(path) {
101
+ const i = path.lastIndexOf("/");
102
+ return i < 0 ? path : path.slice(i + 1);
103
+ }
104
+ function sortNodes(nodes) {
105
+ return [...nodes].sort((a, b) => {
106
+ if (a.kind !== b.kind) return a.kind === "dir" ? -1 : 1;
107
+ return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
108
+ });
109
+ }
110
+ function fsNodeToTree(node, captureComplete = false) {
111
+ const kind = node.type === "dir" ? "dir" : "file";
112
+ const mappedChildren = node.children && node.children.length > 0 ? node.children.map((child) => fsNodeToTree(child, captureComplete)) : captureComplete && kind === "dir" ? [] : void 0;
113
+ return {
114
+ path: node.path,
115
+ name: node.name,
116
+ kind,
117
+ size: node.sizeBytes,
118
+ ...kind === "dir" ? { children: mappedChildren } : {},
119
+ // A collapsed residue dir from the capture index — carried through so the
120
+ // tree can show an inline "contents on machine" row cold instead of nothing.
121
+ ...kind === "dir" && node.truncated ? { truncated: true } : {}
122
+ };
123
+ }
124
+ var GIT_STATUS_TO_TREE = {
125
+ added: "added",
126
+ modified: "modified",
127
+ deleted: "deleted",
128
+ renamed: "renamed",
129
+ copied: "added",
130
+ untracked: "untracked",
131
+ typechange: "modified"
132
+ };
133
+ function replaceChildren(nodes, targetPath, children) {
134
+ return nodes.map((node) => {
135
+ if (node.path === targetPath) {
136
+ return { ...node, children };
137
+ }
138
+ if (node.kind === "dir" && node.children && targetPath.startsWith(`${node.path}/`)) {
139
+ return {
140
+ ...node,
141
+ children: replaceChildren(node.children, targetPath, children)
142
+ };
143
+ }
144
+ return node;
145
+ });
146
+ }
147
+ function findNodeByPath(nodes, path) {
148
+ for (const node of nodes) {
149
+ if (node.path === path) return node;
150
+ if (node.kind === "dir" && node.children && path.startsWith(`${node.path}/`)) {
151
+ const hit = findNodeByPath(node.children, path);
152
+ if (hit) return hit;
153
+ }
154
+ }
155
+ return void 0;
156
+ }
157
+ var FS_LIST_BATCH_REQUEST_LIMIT = 16;
158
+ function initialDirectoryFrontier(rootPath, repoPaths) {
159
+ const root = normalizeRoot(rootPath);
160
+ const rootParts = root.split("/").filter(Boolean);
161
+ const rootPrefix = root.startsWith("//") ? "//" : root.startsWith("/") ? "/" : "";
162
+ const paths = /* @__PURE__ */ new Set();
163
+ for (const repoPath of repoPaths) {
164
+ const canonicalRepoPath = joinTreeRoot(root, normalizeRoot(repoPath));
165
+ const parts = canonicalRepoPath.split("/").filter(Boolean);
166
+ if (rootParts.some((part, index) => parts[index] !== part)) continue;
167
+ for (let depth = rootParts.length + 1; depth <= parts.length; depth += 1) {
168
+ const path = parts.slice(0, depth).join("/");
169
+ paths.add(`${rootPrefix}${path}`);
170
+ }
171
+ }
172
+ return [...paths].sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b)).slice(0, 8);
173
+ }
174
+ function parentIsLoaded(nodes, parent, rootPath = "") {
175
+ if (parent === normalizeRoot(rootPath)) return true;
176
+ const node = findNodeByPath(nodes, parent);
177
+ return Boolean(node && node.kind === "dir" && node.children !== void 0);
178
+ }
179
+ function insertNode(nodes, parent, child, rootPath = "") {
180
+ if (parent === normalizeRoot(rootPath)) {
181
+ if (nodes.some((n) => n.path === child.path)) return nodes;
182
+ return sortNodes([...nodes, child]);
183
+ }
184
+ return nodes.map((node) => {
185
+ if (node.path === parent) {
186
+ if (node.kind !== "dir" || node.children === void 0) return node;
187
+ if (node.children.some((n) => n.path === child.path)) return node;
188
+ return { ...node, children: sortNodes([...node.children, child]) };
189
+ }
190
+ if (node.kind === "dir" && node.children && parent.startsWith(`${node.path}/`)) {
191
+ return { ...node, children: insertNode(node.children, parent, child, rootPath) };
192
+ }
193
+ return node;
194
+ });
195
+ }
196
+ function removeNode(nodes, path, rootPath = "") {
197
+ const parent = parentWithinTree(path, rootPath);
198
+ if (parent === normalizeRoot(rootPath)) {
199
+ if (!nodes.some((n) => n.path === path)) return nodes;
200
+ return nodes.filter((n) => n.path !== path);
201
+ }
202
+ return nodes.map((node) => {
203
+ if (node.path === parent) {
204
+ if (node.kind !== "dir" || node.children === void 0) return node;
205
+ return {
206
+ ...node,
207
+ children: node.children.filter((n) => n.path !== path)
208
+ };
209
+ }
210
+ if (node.kind === "dir" && node.children && parent.startsWith(`${node.path}/`)) {
211
+ return { ...node, children: removeNode(node.children, path, rootPath) };
212
+ }
213
+ return node;
214
+ });
215
+ }
216
+ function sameNodeShallow(a, b) {
217
+ return a.path === b.path && a.kind === b.kind && a.name === b.name && (a.size ?? null) === (b.size ?? null) && (a.status ?? void 0) === (b.status ?? void 0) && (a.truncated ?? false) === (b.truncated ?? false);
218
+ }
219
+ function mergeChildren(current, listed) {
220
+ const byPath = new Map(current.map((n) => [n.path, n]));
221
+ const merged = listed.map((next) => {
222
+ const existing = byPath.get(next.path);
223
+ if (!existing) return next;
224
+ if (existing.kind === "dir" && next.kind === "dir" && existing.children !== void 0) {
225
+ const candidate = { ...next, children: existing.children };
226
+ return sameNodeShallow(existing, candidate) ? existing : candidate;
227
+ }
228
+ if (existing.children === next.children && sameNodeShallow(existing, next)) {
229
+ return existing;
230
+ }
231
+ return next;
232
+ });
233
+ return sortNodes(merged);
234
+ }
235
+ function mergeRootChildren(nodes, listed) {
236
+ return mergeChildren(nodes, listed);
237
+ }
238
+ function repathNode(node, fromPrefix, toPrefix) {
239
+ const newPath = toPrefix + node.path.slice(fromPrefix.length);
240
+ const next = { ...node, path: newPath, name: leafOf(newPath) };
241
+ if (node.children) next.children = node.children.map((c) => repathNode(c, fromPrefix, toPrefix));
242
+ return next;
243
+ }
244
+ function decodeBase64Bytes(value) {
245
+ const binary = atob(value);
246
+ const bytes = new Uint8Array(binary.length);
247
+ for (let index = 0; index < binary.length; index += 1) {
248
+ bytes[index] = binary.charCodeAt(index);
249
+ }
250
+ return bytes;
251
+ }
252
+ function decodeBase64Text(value) {
253
+ return new TextDecoder().decode(decodeBase64Bytes(value));
254
+ }
255
+ function encodeBase64Bytes(bytes) {
256
+ let binary = "";
257
+ const chunkSize = 32768;
258
+ for (let offset = 0; offset < bytes.length; offset += chunkSize) {
259
+ binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
260
+ }
261
+ return btoa(binary);
262
+ }
263
+ async function assertCapturedHash(bytes, expected) {
264
+ if (!expected) throw new Error("Captured file is missing its integrity hash.");
265
+ if (!globalThis.crypto?.subtle) {
266
+ throw new Error("Captured file integrity verification is unavailable in this browser.");
267
+ }
268
+ const buffer = new ArrayBuffer(bytes.byteLength);
269
+ new Uint8Array(buffer).set(bytes);
270
+ const digest = new Uint8Array(await globalThis.crypto.subtle.digest("SHA-256", buffer));
271
+ const actual = [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
272
+ if (actual !== expected) throw new Error("Captured file content failed its integrity check.");
273
+ }
274
+ function useSandboxFiles(sessionId, options = {}) {
275
+ const { client, workspaceId } = useOpenGeni(options);
276
+ const enabled = (options.enabled ?? true) && Boolean(sessionId);
277
+ const active = options.active ?? true;
278
+ const rootPath = options.rootPath ?? "";
279
+ const routeEpoch = options.route?.epoch ?? null;
280
+ const routeRoot = options.route?.root ?? null;
281
+ const route = useMemo(
282
+ () => routeEpoch !== null && routeRoot !== null ? { epoch: routeEpoch, root: routeRoot } : void 0,
283
+ [routeEpoch, routeRoot]
284
+ );
285
+ const repoPathsKey = [
286
+ ...new Set((options.repoPaths?.length ? options.repoPaths : [rootPath]).map(normalizeRoot))
287
+ ].join("\0");
288
+ const repoPaths = useMemo(() => repoPathsKey.split("\0"), [repoPathsKey]);
289
+ const capture = options.capture ?? null;
290
+ const isLive = sandboxAcceptsLiveIo(options.liveness);
291
+ const acceptsEventReads = options.liveness === void 0 || isLive;
292
+ const acceptsEventReadsRef = useRef(acceptsEventReads);
293
+ acceptsEventReadsRef.current = acceptsEventReads;
294
+ const hasLiveIoFence = options.liveness !== void 0;
295
+ const identityKey = `${workspaceId}\0${sessionId ?? ""}\0${rootPath}\0${repoPathsKey}\0${routeEpoch ?? ""}\0${routeRoot ?? ""}`;
296
+ const [tree, setTree] = useState([]);
297
+ const treeRef = useRef([]);
298
+ const [loading, setLoading] = useState(false);
299
+ const [expandingPaths, setExpandingPaths] = useState(/* @__PURE__ */ new Set());
300
+ const [error, setError] = useState(null);
301
+ const [gitSummary, setGitSummary] = useState(null);
302
+ const [gitLoading, setGitLoading] = useState(false);
303
+ const [contentRevision, setContentRevision] = useState(0);
304
+ const [stateIdentity, setStateIdentity] = useState(identityKey);
305
+ const [source, setSource] = useState(null);
306
+ const sourceRef = useRef(null);
307
+ const statusRef = useRef(/* @__PURE__ */ new Map());
308
+ const refreshGenerationRef = useRef(0);
309
+ const refreshAbortRef = useRef(null);
310
+ const identityAbortRef = useRef(new AbortController());
311
+ const eventReadAbortRef = useRef(new AbortController());
312
+ const identityGenerationRef = useRef(0);
313
+ const lastSeqRef = useRef(0);
314
+ const pendingParentsRef = useRef(/* @__PURE__ */ new Set());
315
+ const pendingGitRef = useRef(false);
316
+ const eventReconcileInFlightRef = useRef(null);
317
+ const eventReconcilePendingRef = useRef(false);
318
+ const debounceRef = useRef(null);
319
+ const ownRevisionsRef = useRef(/* @__PURE__ */ new Set());
320
+ const onMutationError = options.onMutationError;
321
+ treeRef.current = tree;
322
+ const applyStatus = useCallback((nodes) => {
323
+ const overlay = statusRef.current;
324
+ const walk = (list) => {
325
+ let changed = false;
326
+ const out = list.map((node) => {
327
+ const nextChildren = node.children ? walk(node.children) : node.children;
328
+ const wantStatus = node.kind === "file" ? overlay.get(node.path) : void 0;
329
+ const childrenChanged = nextChildren !== node.children;
330
+ const statusChanged = (node.status ?? void 0) !== (wantStatus ?? void 0);
331
+ if (!childrenChanged && !statusChanged) return node;
332
+ changed = true;
333
+ const next = {
334
+ ...node,
335
+ ...node.children ? { children: nextChildren } : {}
336
+ };
337
+ if (wantStatus) next.status = wantStatus;
338
+ else delete next.status;
339
+ return next;
340
+ });
341
+ return changed ? out : list;
342
+ };
343
+ return walk(nodes);
344
+ }, []);
345
+ const refresh = useCallback(async () => {
346
+ if (!sessionId) return;
347
+ refreshAbortRef.current?.abort();
348
+ const refreshAbort = new AbortController();
349
+ refreshAbortRef.current = refreshAbort;
350
+ const generation = refreshGenerationRef.current += 1;
351
+ setLoading(true);
352
+ setGitLoading(true);
353
+ setError(null);
354
+ try {
355
+ const frontierPaths = initialDirectoryFrontier(rootPath, repoPaths);
356
+ const listRequests = [rootPath, ...frontierPaths].map((path) => ({
357
+ path,
358
+ depth: 1,
359
+ ...route ? { route } : {}
360
+ }));
361
+ const listedBatch = await client.fsListBatch(
362
+ workspaceId,
363
+ sessionId,
364
+ { requests: listRequests },
365
+ { signal: refreshAbort.signal }
366
+ );
367
+ if (refreshGenerationRef.current !== generation) return;
368
+ const listed = listedBatch.results[0];
369
+ if (!listed) throw new Error("Workspace list batch did not return the root result.");
370
+ const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));
371
+ setTree((prev) => {
372
+ let hydrated = prev.length === 0 ? children : mergeRootChildren(prev, children);
373
+ for (const [index, path] of frontierPaths.entries()) {
374
+ const prefetched = listedBatch.results[index + 1];
375
+ if (!prefetched) continue;
376
+ hydrated = replaceChildren(
377
+ hydrated,
378
+ path,
379
+ (prefetched.root.children ?? []).map((node) => fsNodeToTree(node))
380
+ );
381
+ }
382
+ return applyStatus(hydrated);
383
+ });
384
+ sourceRef.current = "live";
385
+ setSource("live");
386
+ setLoading(false);
387
+ const statuses = repoPaths.length > 0 ? await client.gitReadBatch(
388
+ workspaceId,
389
+ sessionId,
390
+ {
391
+ requests: repoPaths.map((root) => ({
392
+ status: { path: root }
393
+ }))
394
+ },
395
+ { signal: refreshAbort.signal }
396
+ ).then(
397
+ (batch) => batch.results.map((result, index) => ({
398
+ root: repoPaths[index] ?? "",
399
+ status: result.status
400
+ }))
401
+ ).catch(() => null) : [];
402
+ if (refreshGenerationRef.current !== generation) return;
403
+ if (statuses) {
404
+ const overlay = /* @__PURE__ */ new Map();
405
+ for (const { root, status } of statuses) {
406
+ for (const file of status.files) {
407
+ const code = file.worktree ?? file.index;
408
+ const mapped = code ? GIT_STATUS_TO_TREE[code] : void 0;
409
+ if (mapped) overlay.set(qualifyStatusPath(root, file.path, rootPath), mapped);
410
+ }
411
+ }
412
+ statusRef.current = overlay;
413
+ setGitSummary(summarizeStatuses(statuses));
414
+ } else {
415
+ statusRef.current = /* @__PURE__ */ new Map();
416
+ setGitSummary(null);
417
+ }
418
+ setGitLoading(false);
419
+ setTree((prev) => applyStatus(prev));
420
+ } catch (cause) {
421
+ if (refreshGenerationRef.current !== generation) return;
422
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
423
+ } finally {
424
+ if (refreshGenerationRef.current === generation) setLoading(false);
425
+ if (refreshGenerationRef.current === generation) setGitLoading(false);
426
+ if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;
427
+ }
428
+ }, [client, workspaceId, sessionId, rootPath, repoPaths, route, applyStatus]);
429
+ const seedFromCapture = useCallback(
430
+ (manifest) => {
431
+ const overlay = /* @__PURE__ */ new Map();
432
+ for (const file of manifest.files) {
433
+ if (file.deleted) continue;
434
+ const mapped = GIT_STATUS_TO_TREE[file.status];
435
+ if (mapped) overlay.set(file.path, mapped);
436
+ }
437
+ statusRef.current = overlay;
438
+ const children = (manifest.treeIndex.children ?? []).map((node) => fsNodeToTree(node, true));
439
+ setTree(
440
+ (prev) => applyStatus(prev.length === 0 ? children : mergeRootChildren(prev, children))
441
+ );
442
+ sourceRef.current = "capture";
443
+ setSource("capture");
444
+ setGitSummary({
445
+ branch: manifest.repos.length === 1 ? manifest.repos[0]?.head ?? null : null,
446
+ isRepo: manifest.repos.length > 0,
447
+ repoCount: manifest.repos.length,
448
+ ahead: manifest.repos.reduce((sum, repo) => sum + repo.ahead, 0),
449
+ behind: manifest.repos.reduce((sum, repo) => sum + repo.behind, 0),
450
+ dirtyCount: manifest.files.length
451
+ });
452
+ setGitLoading(false);
453
+ setError(null);
454
+ },
455
+ [applyStatus]
456
+ );
457
+ const expand = useCallback(
458
+ async (path) => {
459
+ if (!sessionId) return;
460
+ if (source === "capture" && capture) return;
461
+ const identityGeneration = identityGenerationRef.current;
462
+ const identitySignal = identityAbortRef.current.signal;
463
+ setExpandingPaths((prev) => {
464
+ const next = new Set(prev);
465
+ next.add(path);
466
+ return next;
467
+ });
468
+ try {
469
+ const listed = await client.fsList(
470
+ workspaceId,
471
+ sessionId,
472
+ { path, depth: 1, ...route ? { route } : {} },
473
+ { signal: identitySignal }
474
+ );
475
+ if (identityGenerationRef.current !== identityGeneration) return;
476
+ const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));
477
+ setTree((prev) => applyStatus(replaceChildren(prev, path, children)));
478
+ } catch (cause) {
479
+ if (identityGenerationRef.current !== identityGeneration) return;
480
+ setError(cause instanceof Error ? cause : new Error(String(cause)));
481
+ } finally {
482
+ if (identityGenerationRef.current === identityGeneration) {
483
+ setExpandingPaths((prev) => {
484
+ if (!prev.has(path)) return prev;
485
+ const next = new Set(prev);
486
+ next.delete(path);
487
+ return next;
488
+ });
489
+ }
490
+ }
491
+ },
492
+ [client, workspaceId, sessionId, capture, source, route, applyStatus]
493
+ );
494
+ const readFile = useCallback(
495
+ async (path, requestOptions = {}) => {
496
+ if (!sessionId) throw new Error("no session");
497
+ const identitySignal = identityAbortRef.current.signal;
498
+ const signal = requestOptions.signal ? AbortSignal.any([identitySignal, requestOptions.signal]) : identitySignal;
499
+ const captured = capture?.files.find((file) => file.path === path && !file.deleted);
500
+ if (source === "capture" && capture) {
501
+ if (!captured) {
502
+ throw new CapturedFileUnavailableError(path, "not-captured");
503
+ }
504
+ for (let attempt = 0; attempt < 2; attempt += 1) {
505
+ const result = await client.getWorkspaceCaptureFile(
506
+ workspaceId,
507
+ sessionId,
508
+ path,
509
+ capture.revision,
510
+ { signal }
511
+ );
512
+ if (result.path !== path || result.revision !== capture.revision) {
513
+ throw new Error(
514
+ "Captured file identity did not match the requested workspace revision."
515
+ );
516
+ }
517
+ if (result.hash !== captured.hash || result.sizeBytes !== captured.sizeBytes || result.isBinary !== captured.isBinary || result.tooLarge !== captured.tooLarge) {
518
+ throw new Error("Captured file metadata did not match its manifest.");
519
+ }
520
+ if (result.tooLarge) {
521
+ throw new CapturedFileUnavailableError(path, "too-large");
522
+ }
523
+ let bytes;
524
+ let encoding;
525
+ let content;
526
+ if (result.content !== null && result.encoding !== null) {
527
+ encoding = result.encoding;
528
+ content = result.content;
529
+ bytes = encoding === "base64" ? decodeBase64Bytes(content) : new TextEncoder().encode(content);
530
+ } else if (result.contentUrl) {
531
+ const response = await fetch(result.contentUrl.url, {
532
+ credentials: "omit",
533
+ cache: "no-store",
534
+ referrerPolicy: "no-referrer",
535
+ signal: AbortSignal.any([signal, AbortSignal.timeout(3e4)])
536
+ }).catch(() => null);
537
+ if (!response?.ok) {
538
+ if (attempt === 0 && (response === null || response.status === 401 || response.status === 403)) {
539
+ continue;
540
+ }
541
+ throw new Error("Captured file download failed.");
542
+ }
543
+ bytes = new Uint8Array(await response.arrayBuffer());
544
+ encoding = result.isBinary ? "base64" : "utf8";
545
+ content = result.isBinary ? encodeBase64Bytes(bytes) : new TextDecoder().decode(bytes);
546
+ } else {
547
+ throw new CapturedFileUnavailableError(path, "content-missing");
548
+ }
549
+ if (bytes.byteLength !== result.sizeBytes) {
550
+ throw new Error("Captured file size did not match its manifest.");
551
+ }
552
+ await assertCapturedHash(bytes, result.hash);
553
+ return {
554
+ path,
555
+ encoding,
556
+ content,
557
+ sizeBytes: result.sizeBytes,
558
+ truncated: false,
559
+ isBinary: result.isBinary,
560
+ revision: result.revision
561
+ };
562
+ }
563
+ throw new Error("Captured file download failed after refreshing its URL.");
564
+ }
565
+ return await client.fsRead(
566
+ workspaceId,
567
+ sessionId,
568
+ { path, ...route ? { route } : {} },
569
+ { signal }
570
+ );
571
+ },
572
+ [client, workspaceId, sessionId, capture, source, route]
573
+ );
574
+ const reconcilePath = useCallback(
575
+ async (path, requestSignal) => {
576
+ if (!sessionId) return;
577
+ const identityGeneration = identityGenerationRef.current;
578
+ const identitySignal = identityAbortRef.current.signal;
579
+ const signal = requestSignal ? AbortSignal.any([identitySignal, requestSignal]) : identitySignal;
580
+ if (!parentIsLoaded(treeRef.current, path, rootPath)) return;
581
+ try {
582
+ const listed = await client.fsList(
583
+ workspaceId,
584
+ sessionId,
585
+ { path, depth: 1, ...route ? { route } : {} },
586
+ { signal }
587
+ );
588
+ if (identityGenerationRef.current !== identityGeneration) return;
589
+ const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));
590
+ if (path === normalizeRoot(rootPath)) {
591
+ setTree((prev) => applyStatus(mergeRootChildren(prev, children)));
592
+ } else
593
+ setTree((prev) => {
594
+ const existing = findNodeByPath(prev, path);
595
+ const merged = existing?.children ? mergeChildren(existing.children, children) : children;
596
+ return applyStatus(replaceChildren(prev, path, merged));
597
+ });
598
+ } catch {
599
+ }
600
+ },
601
+ [client, workspaceId, sessionId, rootPath, route, applyStatus]
602
+ );
603
+ const reconcilePaths = useCallback(
604
+ async (requestedPaths, requestSignal) => {
605
+ if (!sessionId) return;
606
+ const identityGeneration = identityGenerationRef.current;
607
+ const identitySignal = identityAbortRef.current.signal;
608
+ const signal = requestSignal ? AbortSignal.any([identitySignal, requestSignal]) : identitySignal;
609
+ const paths = [...new Set(requestedPaths)].filter(
610
+ (path) => parentIsLoaded(treeRef.current, path, rootPath)
611
+ );
612
+ for (let offset = 0; offset < paths.length; offset += FS_LIST_BATCH_REQUEST_LIMIT) {
613
+ const chunk = paths.slice(offset, offset + FS_LIST_BATCH_REQUEST_LIMIT);
614
+ try {
615
+ const listed = await client.fsListBatch(
616
+ workspaceId,
617
+ sessionId,
618
+ {
619
+ requests: chunk.map((path) => ({
620
+ path,
621
+ depth: 1,
622
+ ...route ? { route } : {}
623
+ }))
624
+ },
625
+ { signal }
626
+ );
627
+ if (identityGenerationRef.current !== identityGeneration) return;
628
+ setTree((previous) => {
629
+ let next = previous;
630
+ for (const [index, path] of chunk.entries()) {
631
+ const result = listed.results[index];
632
+ if (!result) continue;
633
+ const children = (result.root.children ?? []).map((node) => fsNodeToTree(node));
634
+ if (path === normalizeRoot(rootPath)) {
635
+ next = mergeRootChildren(next, children);
636
+ } else {
637
+ const existing = findNodeByPath(next, path);
638
+ const merged = existing?.children ? mergeChildren(existing.children, children) : children;
639
+ next = replaceChildren(next, path, merged);
640
+ }
641
+ }
642
+ return applyStatus(next);
643
+ });
644
+ } catch {
645
+ }
646
+ }
647
+ },
648
+ [client, workspaceId, sessionId, rootPath, route, applyStatus]
649
+ );
650
+ const runOptimistic = useCallback(
651
+ async (opName, apply, op, reconcileParents) => {
652
+ const identityGeneration = identityGenerationRef.current;
653
+ const snapshot = treeRef.current;
654
+ setError(null);
655
+ setTree(applyStatus(apply(snapshot)));
656
+ try {
657
+ const res = await op();
658
+ if (identityGenerationRef.current !== identityGeneration) return res;
659
+ if (res && typeof res === "object" && "revision" in res) {
660
+ const rev = res.revision;
661
+ if (typeof rev === "number") ownRevisionsRef.current.add(rev);
662
+ }
663
+ for (const parent of reconcileParents) {
664
+ if (identityGenerationRef.current !== identityGeneration) return res;
665
+ await reconcilePath(parent);
666
+ }
667
+ return res;
668
+ } catch (cause) {
669
+ const err = cause instanceof Error ? cause : new Error(String(cause));
670
+ if (identityGenerationRef.current !== identityGeneration) throw err;
671
+ setTree(applyStatus(snapshot));
672
+ if (err instanceof FileWriteConflictError) throw err;
673
+ setError(err);
674
+ onMutationError?.(err, opName);
675
+ throw err;
676
+ }
677
+ },
678
+ [applyStatus, reconcilePath, onMutationError]
679
+ );
680
+ const writeFile = useCallback(
681
+ async (path, content, writeOptions = {}) => {
682
+ if (!sessionId) throw new Error("no session");
683
+ const identityGeneration = identityGenerationRef.current;
684
+ const identitySignal = identityAbortRef.current.signal;
685
+ const parent = parentWithinTree(path, rootPath);
686
+ const exists = Boolean(findNodeByPath(tree, path));
687
+ const node = {
688
+ path,
689
+ name: leafOf(path),
690
+ kind: "file",
691
+ size: content.length
692
+ };
693
+ return await runOptimistic(
694
+ "write",
695
+ (nodes) => exists ? nodes : insertNode(nodes, parent, node, rootPath),
696
+ async () => {
697
+ if (!writeOptions.force && writeOptions.expectedContent !== void 0) {
698
+ const live = await client.fsRead(
699
+ workspaceId,
700
+ sessionId,
701
+ { path, ...route ? { route } : {} },
702
+ { signal: identitySignal }
703
+ );
704
+ if (identityGenerationRef.current !== identityGeneration) {
705
+ throw new Error("File save cancelled because the workspace changed.");
706
+ }
707
+ const liveContent = live.encoding === "base64" ? decodeBase64Text(live.content) : live.content;
708
+ if (live.truncated || live.isBinary || liveContent !== writeOptions.expectedContent) {
709
+ throw new FileWriteConflictError(path, writeOptions.expectedContent, liveContent);
710
+ }
711
+ }
712
+ if (identityGenerationRef.current !== identityGeneration) {
713
+ throw new Error("File save cancelled because the workspace changed.");
714
+ }
715
+ return await client.fsWrite(workspaceId, sessionId, {
716
+ path,
717
+ content,
718
+ overwrite: true,
719
+ ...route ? { route } : {}
720
+ });
721
+ },
722
+ exists ? [] : [parent]
723
+ );
724
+ },
725
+ [client, workspaceId, sessionId, tree, rootPath, route, runOptimistic]
726
+ );
727
+ const createFile = useCallback(
728
+ async (path) => {
729
+ if (!sessionId) throw new Error("no session");
730
+ const parent = parentWithinTree(path, rootPath);
731
+ const node = {
732
+ path,
733
+ name: leafOf(path),
734
+ kind: "file",
735
+ size: 0
736
+ };
737
+ await runOptimistic(
738
+ "create file",
739
+ (nodes) => insertNode(nodes, parent, node, rootPath),
740
+ () => client.fsWrite(workspaceId, sessionId, {
741
+ path,
742
+ content: "",
743
+ overwrite: false,
744
+ ...route ? { route } : {}
745
+ }),
746
+ [parent]
747
+ );
748
+ },
749
+ [client, workspaceId, sessionId, rootPath, route, runOptimistic]
750
+ );
751
+ const createDir = useCallback(
752
+ async (path) => {
753
+ if (!sessionId) throw new Error("no session");
754
+ const parent = parentWithinTree(path, rootPath);
755
+ const node = {
756
+ path,
757
+ name: leafOf(path),
758
+ kind: "dir",
759
+ children: []
760
+ };
761
+ await runOptimistic(
762
+ "create folder",
763
+ (nodes) => insertNode(nodes, parent, node, rootPath),
764
+ () => client.fsMkdir(workspaceId, sessionId, {
765
+ path,
766
+ recursive: true,
767
+ ...route ? { route } : {}
768
+ }),
769
+ [parent]
770
+ );
771
+ },
772
+ [client, workspaceId, sessionId, rootPath, route, runOptimistic]
773
+ );
774
+ const deleteEntry = useCallback(
775
+ async (path, recursive = false) => {
776
+ if (!sessionId) throw new Error("no session");
777
+ await runOptimistic(
778
+ "delete",
779
+ (nodes) => removeNode(nodes, path, rootPath),
780
+ () => client.fsDelete(workspaceId, sessionId, {
781
+ path,
782
+ recursive,
783
+ ...route ? { route } : {}
784
+ }),
785
+ [parentWithinTree(path, rootPath)]
786
+ );
787
+ },
788
+ [client, workspaceId, sessionId, rootPath, route, runOptimistic]
789
+ );
790
+ const moveEntry = useCallback(
791
+ async (path, newPath, opts) => {
792
+ if (!sessionId) throw new Error("no session");
793
+ const from = parentWithinTree(path, rootPath);
794
+ const to = parentWithinTree(newPath, rootPath);
795
+ await runOptimistic(
796
+ "move",
797
+ (nodes) => {
798
+ const moving = findNodeByPath(nodes, path);
799
+ if (!moving) return nodes;
800
+ const moved = repathNode(moving, path, newPath);
801
+ return insertNode(removeNode(nodes, path, rootPath), to, moved, rootPath);
802
+ },
803
+ () => client.fsMove(workspaceId, sessionId, {
804
+ path,
805
+ newPath,
806
+ overwrite: opts?.overwrite ?? false,
807
+ ...route ? { route } : {}
808
+ }),
809
+ to === from ? [from] : [from, to]
810
+ );
811
+ },
812
+ [client, workspaceId, sessionId, rootPath, route, runOptimistic]
813
+ );
814
+ const captureRef = useRef(capture);
815
+ captureRef.current = capture;
816
+ const captureRevision = capture?.revision ?? null;
817
+ const previousIdentityRef = useRef(identityKey);
818
+ useEffect(() => {
819
+ refreshAbortRef.current?.abort();
820
+ refreshAbortRef.current = null;
821
+ refreshGenerationRef.current += 1;
822
+ eventReadAbortRef.current.abort();
823
+ eventReadAbortRef.current = new AbortController();
824
+ const identityChanged = previousIdentityRef.current !== identityKey;
825
+ previousIdentityRef.current = identityKey;
826
+ if (identityChanged || !enabled) {
827
+ if (identityChanged) eventReconcileInFlightRef.current = null;
828
+ identityAbortRef.current.abort();
829
+ identityAbortRef.current = new AbortController();
830
+ identityGenerationRef.current += 1;
831
+ lastSeqRef.current = 0;
832
+ pendingParentsRef.current = /* @__PURE__ */ new Set();
833
+ pendingGitRef.current = false;
834
+ eventReconcilePendingRef.current = false;
835
+ if (debounceRef.current) {
836
+ clearTimeout(debounceRef.current);
837
+ debounceRef.current = null;
838
+ }
839
+ ownRevisionsRef.current = /* @__PURE__ */ new Set();
840
+ statusRef.current = /* @__PURE__ */ new Map();
841
+ treeRef.current = [];
842
+ setTree([]);
843
+ setStateIdentity(identityKey);
844
+ setExpandingPaths(/* @__PURE__ */ new Set());
845
+ sourceRef.current = null;
846
+ setSource(null);
847
+ setLoading(false);
848
+ setError(null);
849
+ setGitSummary(null);
850
+ setGitLoading(false);
851
+ setContentRevision(0);
852
+ }
853
+ if (!enabled) {
854
+ return;
855
+ }
856
+ const currentCapture = captureRevision !== null ? captureRef.current : null;
857
+ if (currentCapture && (identityChanged || !isLive || sourceRef.current !== "live")) {
858
+ seedFromCapture(currentCapture);
859
+ }
860
+ if (!active) {
861
+ if (!active) {
862
+ setLoading(false);
863
+ setGitLoading(false);
864
+ }
865
+ return;
866
+ }
867
+ if (isLive || !hasLiveIoFence && !currentCapture) {
868
+ void refresh();
869
+ }
870
+ return () => {
871
+ refreshAbortRef.current?.abort();
872
+ refreshAbortRef.current = null;
873
+ refreshGenerationRef.current += 1;
874
+ eventReadAbortRef.current.abort();
875
+ eventReconcilePendingRef.current = false;
876
+ };
877
+ }, [
878
+ enabled,
879
+ active,
880
+ isLive,
881
+ hasLiveIoFence,
882
+ captureRevision,
883
+ identityKey,
884
+ refresh,
885
+ seedFromCapture
886
+ ]);
887
+ const refreshGitOverlay = useCallback(
888
+ async (requestSignal) => {
889
+ if (!sessionId) return;
890
+ const identityGeneration = identityGenerationRef.current;
891
+ const identitySignal = identityAbortRef.current.signal;
892
+ const signal = requestSignal ? AbortSignal.any([identitySignal, requestSignal]) : identitySignal;
893
+ setGitLoading(true);
894
+ try {
895
+ const batch = await client.gitReadBatch(
896
+ workspaceId,
897
+ sessionId,
898
+ { requests: repoPaths.map((root) => ({ status: { path: root } })) },
899
+ { signal }
900
+ );
901
+ const statuses = batch.results.map((result, index) => ({
902
+ root: repoPaths[index] ?? "",
903
+ status: result.status
904
+ }));
905
+ if (identityGenerationRef.current !== identityGeneration) return;
906
+ const overlay = /* @__PURE__ */ new Map();
907
+ for (const { root, status } of statuses) {
908
+ for (const file of status.files) {
909
+ const code = file.worktree ?? file.index;
910
+ const mapped = code ? GIT_STATUS_TO_TREE[code] : void 0;
911
+ if (mapped) overlay.set(qualifyStatusPath(root, file.path, rootPath), mapped);
912
+ }
913
+ }
914
+ statusRef.current = overlay;
915
+ setGitSummary(summarizeStatuses(statuses));
916
+ setTree((prev) => applyStatus(prev));
917
+ } catch {
918
+ } finally {
919
+ if (identityGenerationRef.current === identityGeneration) setGitLoading(false);
920
+ }
921
+ },
922
+ [client, workspaceId, sessionId, repoPaths, rootPath, applyStatus]
923
+ );
924
+ const performEventReconcile = useCallback(async () => {
925
+ const parents = pendingParentsRef.current;
926
+ pendingParentsRef.current = /* @__PURE__ */ new Set();
927
+ const wantGit = pendingGitRef.current;
928
+ pendingGitRef.current = false;
929
+ const signal = eventReadAbortRef.current.signal;
930
+ const paths = [...parents];
931
+ await reconcilePaths(paths, signal);
932
+ if (wantGit) await refreshGitOverlay(signal);
933
+ }, [reconcilePaths, refreshGitOverlay]);
934
+ const performEventReconcileRef = useRef(performEventReconcile);
935
+ performEventReconcileRef.current = performEventReconcile;
936
+ const reconcilePendingEvents = useCallback(async () => {
937
+ eventReconcilePendingRef.current = true;
938
+ const existing = eventReconcileInFlightRef.current;
939
+ if (existing) return await existing;
940
+ const identityGeneration = identityGenerationRef.current;
941
+ const run = (async () => {
942
+ while (eventReconcilePendingRef.current && identityGenerationRef.current === identityGeneration) {
943
+ eventReconcilePendingRef.current = false;
944
+ await performEventReconcileRef.current();
945
+ }
946
+ })();
947
+ eventReconcileInFlightRef.current = run;
948
+ try {
949
+ await run;
950
+ } finally {
951
+ if (eventReconcileInFlightRef.current === run) eventReconcileInFlightRef.current = null;
952
+ }
953
+ }, []);
954
+ const events = options.events;
955
+ useEffect(() => {
956
+ if (!enabled || !events) return;
957
+ if (!active || !acceptsEventReads) {
958
+ for (const event of events) {
959
+ if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;
960
+ }
961
+ if (debounceRef.current) {
962
+ clearTimeout(debounceRef.current);
963
+ debounceRef.current = null;
964
+ }
965
+ pendingParentsRef.current = /* @__PURE__ */ new Set();
966
+ pendingGitRef.current = false;
967
+ eventReconcilePendingRef.current = false;
968
+ return;
969
+ }
970
+ let sawNew = false;
971
+ let contentChanged = false;
972
+ for (const event of events) {
973
+ if (event.sequence <= lastSeqRef.current) continue;
974
+ if (event.type === "fs.changed") {
975
+ sawNew = true;
976
+ const payload = event.payload;
977
+ if (!payload || typeof payload !== "object") continue;
978
+ if (payload.source === "write") continue;
979
+ if (typeof payload.revision === "number" && ownRevisionsRef.current.has(payload.revision))
980
+ continue;
981
+ contentChanged = true;
982
+ for (const change of payload.changes ?? []) {
983
+ pendingParentsRef.current.add(parentWithinTree(change.path, rootPath));
984
+ if (change.oldPath) {
985
+ pendingParentsRef.current.add(parentWithinTree(change.oldPath, rootPath));
986
+ }
987
+ }
988
+ } else if (event.type === "git.changed") {
989
+ sawNew = true;
990
+ const payload = event.payload;
991
+ if (payload && typeof payload === "object" && typeof payload.revision === "number" && ownRevisionsRef.current.has(payload.revision))
992
+ continue;
993
+ pendingGitRef.current = true;
994
+ }
995
+ }
996
+ for (const event of events)
997
+ if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;
998
+ if (!sawNew) return;
999
+ if (contentChanged) setContentRevision((revision) => revision + 1);
1000
+ if (debounceRef.current) clearTimeout(debounceRef.current);
1001
+ const identityGeneration = identityGenerationRef.current;
1002
+ debounceRef.current = setTimeout(() => {
1003
+ debounceRef.current = null;
1004
+ if (identityGenerationRef.current !== identityGeneration) return;
1005
+ if (!acceptsEventReadsRef.current) {
1006
+ pendingParentsRef.current = /* @__PURE__ */ new Set();
1007
+ pendingGitRef.current = false;
1008
+ return;
1009
+ }
1010
+ void reconcilePendingEvents();
1011
+ }, 150);
1012
+ }, [enabled, active, acceptsEventReads, events, rootPath, reconcilePendingEvents]);
1013
+ useEffect(() => {
1014
+ if (active && acceptsEventReads) return;
1015
+ if (debounceRef.current) {
1016
+ clearTimeout(debounceRef.current);
1017
+ debounceRef.current = null;
1018
+ }
1019
+ pendingParentsRef.current = /* @__PURE__ */ new Set();
1020
+ pendingGitRef.current = false;
1021
+ eventReconcilePendingRef.current = false;
1022
+ }, [active, acceptsEventReads]);
1023
+ useEffect(
1024
+ () => () => {
1025
+ refreshAbortRef.current?.abort();
1026
+ identityAbortRef.current.abort();
1027
+ eventReadAbortRef.current.abort();
1028
+ eventReconcilePendingRef.current = false;
1029
+ identityGenerationRef.current += 1;
1030
+ if (debounceRef.current) clearTimeout(debounceRef.current);
1031
+ },
1032
+ []
1033
+ );
1034
+ const identityMatches = enabled && stateIdentity === identityKey;
1035
+ return {
1036
+ tree: identityMatches ? tree : [],
1037
+ expand,
1038
+ expandingPaths: identityMatches ? expandingPaths : /* @__PURE__ */ new Set(),
1039
+ readFile,
1040
+ writeFile,
1041
+ createFile,
1042
+ createDir,
1043
+ deleteEntry,
1044
+ moveEntry,
1045
+ refresh,
1046
+ contentRevision: identityMatches ? contentRevision : 0,
1047
+ source: identityMatches ? source : null,
1048
+ capturedAt: identityMatches && source === "capture" ? capture?.capturedAt ?? null : null,
1049
+ gitSummary: identityMatches ? gitSummary : null,
1050
+ gitLoading: identityMatches && gitLoading,
1051
+ loading: identityMatches && loading,
1052
+ error: identityMatches ? error : null
1053
+ };
1054
+ }
1055
+
1056
+ // src/file-node-visibility.ts
1057
+ function pathIsInsideDirectory(path, directory) {
1058
+ if (!path.startsWith(directory) || path === directory) return false;
1059
+ if (directory.endsWith("/") || directory.endsWith("\\")) return true;
1060
+ const boundary = path[directory.length];
1061
+ return boundary === "/" || boundary === "\\";
1062
+ }
1063
+ function visibleFileTree(nodes, predicate, parent = null, depth = 0) {
1064
+ if (!predicate) return nodes;
1065
+ const visible = [];
1066
+ for (const node of nodes) {
1067
+ if (!predicate(node, { depth, parent })) continue;
1068
+ visible.push(
1069
+ node.children === void 0 ? node : {
1070
+ ...node,
1071
+ children: visibleFileTree(node.children, predicate, node, depth + 1)
1072
+ }
1073
+ );
1074
+ }
1075
+ return visible;
1076
+ }
1077
+ function filePathVisibility(nodes, path, predicate, parent = null, depth = 0) {
1078
+ if (!predicate) return "visible";
1079
+ for (const node of nodes) {
1080
+ if (node.path !== path && !pathIsInsideDirectory(path, node.path)) continue;
1081
+ if (!predicate(node, { depth, parent })) return "hidden";
1082
+ if (node.path === path) return "visible";
1083
+ if (node.kind !== "dir" || node.children === void 0) return "unknown";
1084
+ return filePathVisibility(node.children, path, predicate, node, depth + 1);
1085
+ }
1086
+ return "unknown";
1087
+ }
1088
+
1089
+ // src/components/file-browser.tsx
1090
+ import {
1091
+ ChevronRightIcon,
1092
+ FileIcon,
1093
+ FilePlusIcon,
1094
+ FolderIcon,
1095
+ FolderPlusIcon,
1096
+ PencilIcon,
1097
+ RefreshCwIcon,
1098
+ TriangleAlertIcon,
1099
+ Trash2Icon
1100
+ } from "lucide-react";
1101
+ import {
1102
+ useCallback as useCallback2,
1103
+ useEffect as useEffect3,
1104
+ useId,
1105
+ useLayoutEffect,
1106
+ useMemo as useMemo3,
1107
+ useRef as useRef2,
1108
+ useState as useState2
1109
+ } from "react";
1110
+ import { AlertDialog } from "radix-ui";
1111
+ import { VList } from "virtua";
1112
+
1113
+ // src/lib/use-unicode-fonts.ts
1114
+ import { useEffect as useEffect2, useMemo as useMemo2 } from "react";
1115
+ var japaneseScript = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff]/u;
1116
+ var arabicScript = /[\u0600-\u06ff\u0750-\u077f\u0870-\u08ff\ufb50-\ufdff\ufe70-\ufefc]/u;
1117
+ function useUnicodeFallbackFonts(values) {
1118
+ const content = useMemo2(() => collectUnicodeContent(values), [values]);
1119
+ useEffect2(() => {
1120
+ if (content.japanese) {
1121
+ void import("./noto-sans-jp-loader.generated-MR5L6V7K.js").then(({ loadNotoSansJp }) => loadNotoSansJp(content.japanese)).catch(() => void 0);
1122
+ }
1123
+ if (content.arabic) {
1124
+ void import("./noto-sans-arabic-loader-XSH2KYWJ.js").then(({ loadNotoSansArabic }) => loadNotoSansArabic()).catch(() => void 0);
1125
+ }
1126
+ }, [content.arabic, content.japanese]);
1127
+ }
1128
+ function collectUnicodeContent(values) {
1129
+ const japanese = /* @__PURE__ */ new Set();
1130
+ const arabic = /* @__PURE__ */ new Set();
1131
+ for (const value of values) {
1132
+ for (const character of value) {
1133
+ if (japaneseScript.test(character)) japanese.add(character);
1134
+ if (arabicScript.test(character)) arabic.add(character);
1135
+ }
1136
+ }
1137
+ return { japanese: [...japanese].join(""), arabic: [...arabic].join("") };
1138
+ }
1139
+
1140
+ // src/components/file-browser.tsx
1141
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1142
+ var STATUS_TINT = {
1143
+ added: "text-og-status-idle",
1144
+ modified: "text-og-status-running",
1145
+ deleted: "text-og-status-failed line-through",
1146
+ renamed: "text-og-accent",
1147
+ untracked: "text-og-fg-subtle"
1148
+ };
1149
+ var useBrowserLayoutEffect = typeof window === "undefined" ? useEffect3 : useLayoutEffect;
1150
+ function parentOf2(path) {
1151
+ const i = path.lastIndexOf("/");
1152
+ return i <= 0 ? "" : path.slice(0, i);
1153
+ }
1154
+ function joinPath(parent, name) {
1155
+ return parent ? `${parent}/${name}` : name;
1156
+ }
1157
+ function itemKey(item) {
1158
+ switch (item.type) {
1159
+ case "node":
1160
+ return item.node.path;
1161
+ case "create":
1162
+ return `create:${item.parent}`;
1163
+ case "skeleton":
1164
+ return `skeleton:${item.path}`;
1165
+ case "residue":
1166
+ return `residue:${item.path}`;
1167
+ }
1168
+ }
1169
+ function pathIsInsideDirectory2(path, directory) {
1170
+ if (!path.startsWith(directory) || path === directory) return false;
1171
+ if (directory.endsWith("/") || directory.endsWith("\\")) return true;
1172
+ const boundary = path[directory.length];
1173
+ return boundary === "/" || boundary === "\\";
1174
+ }
1175
+ function findNode(nodes, path) {
1176
+ for (const node of nodes) {
1177
+ if (node.path === path) return node;
1178
+ if (node.kind === "dir" && node.children && pathIsInsideDirectory2(path, node.path)) {
1179
+ const hit = findNode(node.children, path);
1180
+ if (hit) return hit;
1181
+ }
1182
+ }
1183
+ return void 0;
1184
+ }
1185
+ function traceRevealPath(nodes, targetPath) {
1186
+ for (const node of nodes) {
1187
+ if (node.path === targetPath) {
1188
+ return {
1189
+ directories: node.kind === "dir" ? [node.path] : [],
1190
+ frontier: node.kind === "dir" && node.children === void 0 ? node.path : null
1191
+ };
1192
+ }
1193
+ if (node.kind !== "dir" || !pathIsInsideDirectory2(targetPath, node.path)) continue;
1194
+ if (node.children === void 0) {
1195
+ return { directories: [node.path], frontier: node.path };
1196
+ }
1197
+ const child = traceRevealPath(node.children, targetPath);
1198
+ return {
1199
+ directories: [node.path, ...child.directories],
1200
+ frontier: child.frontier
1201
+ };
1202
+ }
1203
+ return { directories: [], frontier: null };
1204
+ }
1205
+ function FileBrowser({
1206
+ result,
1207
+ fallback,
1208
+ onSelectFile,
1209
+ selectedPath,
1210
+ isNodeVisible,
1211
+ revealPath,
1212
+ revealPathRequestId,
1213
+ renderNode,
1214
+ emptyState,
1215
+ editable = true,
1216
+ confirmDelete,
1217
+ className
1218
+ }) {
1219
+ const [expanded, setExpanded] = useState2(/* @__PURE__ */ new Set());
1220
+ const [loadingPaths, setLoadingPaths] = useState2(/* @__PURE__ */ new Set());
1221
+ const [active, setActive] = useState2(null);
1222
+ const [draftCreate, setDraftCreate] = useState2(null);
1223
+ const [draftRename, setDraftRename] = useState2(null);
1224
+ const [dragOver, setDragOver] = useState2(null);
1225
+ const [menu, setMenu] = useState2(null);
1226
+ const [pendingDelete, setPendingDelete] = useState2(null);
1227
+ const [busy, setBusy] = useState2(false);
1228
+ const [coarsePointer, setCoarsePointer] = useState2(false);
1229
+ const [revealRequest, setRevealRequest] = useState2(null);
1230
+ const handledRevealRequestRef = useRef2(null);
1231
+ const attemptedRevealPathsRef = useRef2(/* @__PURE__ */ new Set());
1232
+ const treeId = useId();
1233
+ const container = usePortalTokenSource();
1234
+ const containerRef = container.currentRef;
1235
+ const deleteReturnFocusRef = useRef2(null);
1236
+ const vlistRef = useRef2(null);
1237
+ const portalTokenStyle = usePortalTokenStyle(container.source);
1238
+ const getTreeElement = useCallback2(
1239
+ () => typeof document === "undefined" ? null : document.getElementById(treeId),
1240
+ [treeId]
1241
+ );
1242
+ const visibleTree = useMemo3(
1243
+ () => visibleFileTree(result.tree, isNodeVisible),
1244
+ [isNodeVisible, result.tree]
1245
+ );
1246
+ useBrowserLayoutEffect(() => {
1247
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
1248
+ const query = window.matchMedia("(pointer: coarse)");
1249
+ const update = () => setCoarsePointer(query.matches);
1250
+ update();
1251
+ if (typeof query.addEventListener === "function") {
1252
+ query.addEventListener("change", update);
1253
+ return () => query.removeEventListener("change", update);
1254
+ }
1255
+ if (typeof query.addListener === "function") {
1256
+ query.addListener(update);
1257
+ return () => query.removeListener(update);
1258
+ }
1259
+ }, []);
1260
+ const effectiveRevealRequestId = revealPath ? revealPathRequestId ?? revealPath : null;
1261
+ useEffect3(() => {
1262
+ if (!revealPath || effectiveRevealRequestId === null) {
1263
+ setRevealRequest(null);
1264
+ return;
1265
+ }
1266
+ const handled = handledRevealRequestRef.current;
1267
+ if (handled?.path === revealPath && handled.requestId === effectiveRevealRequestId) return;
1268
+ handledRevealRequestRef.current = {
1269
+ path: revealPath,
1270
+ requestId: effectiveRevealRequestId
1271
+ };
1272
+ attemptedRevealPathsRef.current = /* @__PURE__ */ new Set();
1273
+ setActive(null);
1274
+ setRevealRequest({ path: revealPath, requestId: effectiveRevealRequestId });
1275
+ }, [effectiveRevealRequestId, revealPath]);
1276
+ const visibleActive = active && findNode(visibleTree, active) ? active : null;
1277
+ const cursor = visibleActive ?? (selectedPath && findNode(visibleTree, selectedPath) ? selectedPath : null);
1278
+ useEffect3(() => {
1279
+ if (active !== null && visibleActive === null) setActive(null);
1280
+ }, [active, visibleActive]);
1281
+ const expand = useCallback2(
1282
+ async (path) => {
1283
+ const node = findNode(visibleTree, path);
1284
+ if (node && node.kind === "dir" && node.children === void 0) {
1285
+ setLoadingPaths((prev) => new Set(prev).add(path));
1286
+ try {
1287
+ await result.expand(path);
1288
+ } finally {
1289
+ setLoadingPaths((prev) => {
1290
+ const next = new Set(prev);
1291
+ next.delete(path);
1292
+ return next;
1293
+ });
1294
+ }
1295
+ }
1296
+ },
1297
+ [result, visibleTree]
1298
+ );
1299
+ const open = useCallback2(
1300
+ (path) => {
1301
+ setExpanded((prev) => new Set(prev).add(path));
1302
+ void expand(path);
1303
+ },
1304
+ [expand]
1305
+ );
1306
+ useEffect3(() => {
1307
+ if (!revealRequest) return;
1308
+ const trace = traceRevealPath(visibleTree, revealRequest.path);
1309
+ if (trace.directories.length > 0) {
1310
+ setExpanded((previous) => {
1311
+ const next = new Set(previous);
1312
+ let changed = false;
1313
+ for (const path of trace.directories) {
1314
+ if (next.has(path)) continue;
1315
+ next.add(path);
1316
+ changed = true;
1317
+ }
1318
+ return changed ? next : previous;
1319
+ });
1320
+ }
1321
+ const frontier = trace.frontier;
1322
+ if (!frontier || attemptedRevealPathsRef.current.has(frontier) || loadingPaths.has(frontier) || result.expandingPaths.has(frontier)) {
1323
+ return;
1324
+ }
1325
+ attemptedRevealPathsRef.current.add(frontier);
1326
+ void expand(frontier);
1327
+ }, [expand, loadingPaths, result.expandingPaths, revealRequest, visibleTree]);
1328
+ const toggle = useCallback2(
1329
+ async (node) => {
1330
+ if (node.kind !== "dir") return;
1331
+ const isOpen = expanded.has(node.path);
1332
+ setExpanded((prev) => {
1333
+ const next = new Set(prev);
1334
+ if (isOpen) next.delete(node.path);
1335
+ else next.add(node.path);
1336
+ return next;
1337
+ });
1338
+ if (!isOpen) await expand(node.path);
1339
+ },
1340
+ [expanded, expand]
1341
+ );
1342
+ const cold = result.source !== "live";
1343
+ const renderItems = useMemo3(() => {
1344
+ const items = [];
1345
+ if (draftCreate && draftCreate.parent === "") {
1346
+ items.push({ type: "create", parent: "", kind: draftCreate.kind, depth: 0 });
1347
+ }
1348
+ const walk = (nodes, depth) => {
1349
+ for (const node of nodes) {
1350
+ items.push({ type: "node", node, depth });
1351
+ if (node.kind !== "dir" || !expanded.has(node.path)) continue;
1352
+ if (draftCreate && draftCreate.parent === node.path) {
1353
+ items.push({
1354
+ type: "create",
1355
+ parent: node.path,
1356
+ kind: draftCreate.kind,
1357
+ depth: depth + 1
1358
+ });
1359
+ }
1360
+ const childless = node.children === void 0 || node.children.length === 0;
1361
+ const isLoading = loadingPaths.has(node.path) || result.expandingPaths.has(node.path);
1362
+ if (node.truncated && childless && cold && !isLoading) {
1363
+ items.push({ type: "residue", path: node.path, depth: depth + 1 });
1364
+ } else if (node.children && node.children.length > 0) {
1365
+ walk(node.children, depth + 1);
1366
+ } else if (isLoading && childless) {
1367
+ items.push({ type: "skeleton", path: node.path, depth: depth + 1 });
1368
+ }
1369
+ }
1370
+ };
1371
+ walk(visibleTree, 0);
1372
+ return items;
1373
+ }, [visibleTree, expanded, draftCreate, loadingPaths, result.expandingPaths, cold]);
1374
+ const unicodeFontPaths = useMemo3(
1375
+ () => renderItems.flatMap((item) => item.type === "node" ? [item.node.path] : []),
1376
+ [renderItems]
1377
+ );
1378
+ useUnicodeFallbackFonts(unicodeFontPaths);
1379
+ const flatRows = useMemo3(
1380
+ () => renderItems.flatMap(
1381
+ (item) => item.type === "node" ? [{ node: item.node, depth: item.depth }] : []
1382
+ ),
1383
+ [renderItems]
1384
+ );
1385
+ const rowIndexByPath = useMemo3(
1386
+ () => new Map(flatRows.map((row, index) => [row.node.path, index])),
1387
+ [flatRows]
1388
+ );
1389
+ const treePositionByPath = useMemo3(() => {
1390
+ const positions = /* @__PURE__ */ new Map();
1391
+ const visit = (nodes) => {
1392
+ nodes.forEach((node, index) => {
1393
+ positions.set(node.path, { position: index + 1, setSize: nodes.length });
1394
+ if (node.children) visit(node.children);
1395
+ });
1396
+ };
1397
+ visit(visibleTree);
1398
+ return positions;
1399
+ }, [visibleTree]);
1400
+ const cursorIndex = cursor ? rowIndexByPath.get(cursor) ?? -1 : -1;
1401
+ const activeDescendantId = cursorIndex >= 0 ? `${treeId}-item-${cursorIndex}` : void 0;
1402
+ const supportsMutation = editable && result.source === "live" && result.error === null && !result.loading;
1403
+ const performDelete = useCallback2(
1404
+ async (node) => {
1405
+ if (!supportsMutation) return;
1406
+ const recursive = node.kind === "dir";
1407
+ setBusy(true);
1408
+ try {
1409
+ await result.deleteEntry(node.path, recursive);
1410
+ } catch {
1411
+ } finally {
1412
+ setBusy(false);
1413
+ }
1414
+ },
1415
+ [supportsMutation, result]
1416
+ );
1417
+ const runDelete = useCallback2(
1418
+ async (node, returnFocus) => {
1419
+ if (!supportsMutation) return;
1420
+ setMenu(null);
1421
+ if (!confirmDelete) {
1422
+ deleteReturnFocusRef.current = returnFocus ?? (typeof document !== "undefined" && document.activeElement instanceof HTMLElement ? document.activeElement : null);
1423
+ setPendingDelete(node);
1424
+ return;
1425
+ }
1426
+ if (await confirmDelete(node)) await performDelete(node);
1427
+ },
1428
+ [supportsMutation, confirmDelete, performDelete]
1429
+ );
1430
+ const closePendingDelete = useCallback2(
1431
+ (restoreTrigger) => {
1432
+ const returnTarget = restoreTrigger ? deleteReturnFocusRef.current : getTreeElement();
1433
+ deleteReturnFocusRef.current = null;
1434
+ setPendingDelete(null);
1435
+ if (typeof window !== "undefined") {
1436
+ window.requestAnimationFrame(() => {
1437
+ const target = returnTarget?.isConnected ? returnTarget : getTreeElement();
1438
+ target?.focus();
1439
+ });
1440
+ }
1441
+ },
1442
+ [getTreeElement]
1443
+ );
1444
+ const commitCreate = useCallback2(
1445
+ async (name) => {
1446
+ const draft = draftCreate;
1447
+ setDraftCreate(null);
1448
+ if (!draft || !supportsMutation) return;
1449
+ const trimmed = name.trim().replace(/\/+$/, "");
1450
+ if (!trimmed) return;
1451
+ const path = joinPath(draft.parent, trimmed);
1452
+ setBusy(true);
1453
+ try {
1454
+ if (draft.kind === "dir") {
1455
+ await result.createDir(path);
1456
+ open(path);
1457
+ } else {
1458
+ await result.createFile(path);
1459
+ setActive(path);
1460
+ onSelectFile?.(path);
1461
+ }
1462
+ } catch {
1463
+ } finally {
1464
+ setBusy(false);
1465
+ }
1466
+ },
1467
+ [draftCreate, supportsMutation, result, open, onSelectFile]
1468
+ );
1469
+ const commitRename = useCallback2(
1470
+ async (name) => {
1471
+ const draft = draftRename;
1472
+ setDraftRename(null);
1473
+ if (!draft || !supportsMutation) return;
1474
+ const node = findNode(visibleTree, draft.path);
1475
+ const trimmed = name.trim().replace(/\/+$/, "");
1476
+ if (!node || !trimmed || trimmed === node.name) return;
1477
+ const newPath = joinPath(parentOf2(draft.path), trimmed);
1478
+ setBusy(true);
1479
+ try {
1480
+ await result.moveEntry(draft.path, newPath);
1481
+ if (node.kind === "file" && (selectedPath === draft.path || active === draft.path)) {
1482
+ setActive(newPath);
1483
+ onSelectFile?.(newPath);
1484
+ }
1485
+ } catch {
1486
+ } finally {
1487
+ setBusy(false);
1488
+ }
1489
+ },
1490
+ [draftRename, supportsMutation, result, selectedPath, active, onSelectFile, visibleTree]
1491
+ );
1492
+ const startCreate = useCallback2(
1493
+ (kind) => {
1494
+ if (!supportsMutation) return;
1495
+ const anchor = cursor ? findNode(visibleTree, cursor) : void 0;
1496
+ const parent = anchor ? anchor.kind === "dir" ? anchor.path : parentOf2(anchor.path) : "";
1497
+ if (parent) open(parent);
1498
+ setDraftRename(null);
1499
+ setMenu(null);
1500
+ setDraftCreate({ parent, kind });
1501
+ },
1502
+ [supportsMutation, cursor, open, visibleTree]
1503
+ );
1504
+ const startRename = useCallback2(
1505
+ (node) => {
1506
+ if (!supportsMutation) return;
1507
+ setDraftCreate(null);
1508
+ setMenu(null);
1509
+ setDraftRename({ path: node.path });
1510
+ },
1511
+ [supportsMutation]
1512
+ );
1513
+ const onDropOnto = useCallback2(
1514
+ async (targetDir, sourcePath) => {
1515
+ setDragOver(null);
1516
+ if (!supportsMutation || !sourcePath) return;
1517
+ const src = findNode(visibleTree, sourcePath);
1518
+ if (!src) return;
1519
+ if (parentOf2(sourcePath) === targetDir) return;
1520
+ if (targetDir === sourcePath || targetDir.startsWith(`${sourcePath}/`)) return;
1521
+ const newPath = joinPath(targetDir, src.name);
1522
+ if (newPath === sourcePath) return;
1523
+ setBusy(true);
1524
+ try {
1525
+ await result.moveEntry(sourcePath, newPath);
1526
+ if (src.kind === "file" && (selectedPath === sourcePath || active === sourcePath)) {
1527
+ setActive(newPath);
1528
+ onSelectFile?.(newPath);
1529
+ }
1530
+ } catch {
1531
+ } finally {
1532
+ setBusy(false);
1533
+ }
1534
+ },
1535
+ [supportsMutation, result, selectedPath, active, onSelectFile, visibleTree]
1536
+ );
1537
+ const onKeyDown = useCallback2(
1538
+ (e) => {
1539
+ if (draftCreate || draftRename) return;
1540
+ if (flatRows.length === 0) return;
1541
+ const idx = flatRows.findIndex((r) => r.node.path === cursor);
1542
+ const move = (next) => {
1543
+ const clamped = Math.max(0, Math.min(flatRows.length - 1, next));
1544
+ const row = flatRows[clamped];
1545
+ if (row) setActive(row.node.path);
1546
+ e.preventDefault();
1547
+ };
1548
+ const cur = idx >= 0 ? flatRows[idx] : void 0;
1549
+ switch (e.key) {
1550
+ case "ArrowDown":
1551
+ move(idx < 0 ? 0 : idx + 1);
1552
+ break;
1553
+ case "ArrowUp":
1554
+ move(idx < 0 ? 0 : idx - 1);
1555
+ break;
1556
+ case "Home":
1557
+ move(0);
1558
+ break;
1559
+ case "End":
1560
+ move(flatRows.length - 1);
1561
+ break;
1562
+ case "PageDown": {
1563
+ const pageSize = Math.max(
1564
+ 1,
1565
+ Math.floor((containerRef.current?.clientHeight || 280) / (coarsePointer ? 44 : 28)) - 1
1566
+ );
1567
+ move((idx < 0 ? 0 : idx) + pageSize);
1568
+ break;
1569
+ }
1570
+ case "PageUp": {
1571
+ const pageSize = Math.max(
1572
+ 1,
1573
+ Math.floor((containerRef.current?.clientHeight || 280) / (coarsePointer ? 44 : 28)) - 1
1574
+ );
1575
+ move((idx < 0 ? 0 : idx) - pageSize);
1576
+ break;
1577
+ }
1578
+ case "ArrowRight":
1579
+ if (cur?.node.kind === "dir") {
1580
+ if (!expanded.has(cur.node.path)) open(cur.node.path);
1581
+ else move(idx + 1);
1582
+ e.preventDefault();
1583
+ }
1584
+ break;
1585
+ case "ArrowLeft":
1586
+ if (cur) {
1587
+ if (cur.node.kind === "dir" && expanded.has(cur.node.path)) {
1588
+ setExpanded((prev) => {
1589
+ const n = new Set(prev);
1590
+ n.delete(cur.node.path);
1591
+ return n;
1592
+ });
1593
+ } else {
1594
+ const parent = parentOf2(cur.node.path);
1595
+ if (parent) setActive(parent);
1596
+ }
1597
+ e.preventDefault();
1598
+ }
1599
+ break;
1600
+ case "Enter":
1601
+ if (cur) {
1602
+ if (cur.node.kind === "dir") void toggle(cur.node);
1603
+ else onSelectFile?.(cur.node.path);
1604
+ e.preventDefault();
1605
+ }
1606
+ break;
1607
+ case "ContextMenu":
1608
+ case "F10":
1609
+ if (cur && supportsMutation && (e.key === "ContextMenu" || e.shiftKey)) {
1610
+ const rowIndex = rowIndexByPath.get(cur.node.path) ?? 0;
1611
+ const row = document.getElementById(`${treeId}-item-${rowIndex}`);
1612
+ const rect = row?.getBoundingClientRect();
1613
+ setMenu({
1614
+ node: cur.node,
1615
+ x: rect ? rect.left + Math.min(32, rect.width / 2) : 8,
1616
+ y: rect ? rect.bottom : 8
1617
+ });
1618
+ e.preventDefault();
1619
+ } else if (e.key === "F10") {
1620
+ break;
1621
+ }
1622
+ break;
1623
+ case "F2":
1624
+ if (cur) {
1625
+ startRename(cur.node);
1626
+ e.preventDefault();
1627
+ }
1628
+ break;
1629
+ case "Delete":
1630
+ case "Backspace":
1631
+ if (cur && supportsMutation) {
1632
+ void runDelete(cur.node);
1633
+ e.preventDefault();
1634
+ }
1635
+ break;
1636
+ }
1637
+ },
1638
+ [
1639
+ draftCreate,
1640
+ draftRename,
1641
+ flatRows,
1642
+ cursor,
1643
+ expanded,
1644
+ open,
1645
+ toggle,
1646
+ onSelectFile,
1647
+ startRename,
1648
+ runDelete,
1649
+ supportsMutation,
1650
+ coarsePointer,
1651
+ containerRef,
1652
+ rowIndexByPath,
1653
+ treeId
1654
+ ]
1655
+ );
1656
+ useEffect3(() => {
1657
+ if (!menu) return;
1658
+ const close = () => setMenu(null);
1659
+ window.addEventListener("click", close);
1660
+ window.addEventListener("scroll", close, true);
1661
+ window.addEventListener("resize", close);
1662
+ return () => {
1663
+ window.removeEventListener("click", close);
1664
+ window.removeEventListener("scroll", close, true);
1665
+ window.removeEventListener("resize", close);
1666
+ };
1667
+ }, [menu]);
1668
+ const showErrorEmpty = result.error && visibleTree.length === 0 && !draftCreate;
1669
+ const showDegradedTree = result.error && visibleTree.length > 0;
1670
+ const showEmpty = !result.loading && visibleTree.length === 0 && !draftCreate;
1671
+ const showToolbar = supportsMutation || result.loading;
1672
+ const usesVirtualTree = !showErrorEmpty && !showEmpty && renderItems.length > 500;
1673
+ const renderNodeRow = (node, depth) => {
1674
+ const isOpen = expanded.has(node.path);
1675
+ if (renderNode) {
1676
+ return /* @__PURE__ */ jsx("div", { children: renderNode(node, depth, isOpen) });
1677
+ }
1678
+ const isDir = node.kind === "dir";
1679
+ const isSelected = node.path === selectedPath || node.path === active;
1680
+ const isCursor = node.path === cursor;
1681
+ const isLoading = loadingPaths.has(node.path) || result.expandingPaths.has(node.path);
1682
+ const isRenaming = draftRename?.path === node.path;
1683
+ const isDropTarget = dragOver === (isDir ? node.path : parentOf2(node.path));
1684
+ const dropDir = isDir ? node.path : parentOf2(node.path);
1685
+ const treePosition = treePositionByPath.get(node.path);
1686
+ return /* @__PURE__ */ jsx(
1687
+ "div",
1688
+ {
1689
+ id: `${treeId}-item-${rowIndexByPath.get(node.path) ?? 0}`,
1690
+ role: "treeitem",
1691
+ "aria-level": depth + 1,
1692
+ "aria-posinset": treePosition?.position,
1693
+ "aria-setsize": treePosition?.setSize,
1694
+ "aria-expanded": isDir ? isOpen : void 0,
1695
+ "aria-selected": isCursor || void 0,
1696
+ "aria-busy": isLoading || void 0,
1697
+ onDragOver: supportsMutation ? (e) => {
1698
+ e.preventDefault();
1699
+ e.dataTransfer.dropEffect = "move";
1700
+ setDragOver(dropDir);
1701
+ } : void 0,
1702
+ onDragLeave: supportsMutation ? (e) => {
1703
+ e.stopPropagation();
1704
+ setDragOver((cur) => cur === dropDir ? null : cur);
1705
+ } : void 0,
1706
+ onDrop: supportsMutation ? (e) => {
1707
+ e.preventDefault();
1708
+ e.stopPropagation();
1709
+ const src = e.dataTransfer.getData("text/og-path");
1710
+ void onDropOnto(dropDir, src);
1711
+ } : void 0,
1712
+ children: isRenaming ? /* @__PURE__ */ jsx(
1713
+ InlineInput,
1714
+ {
1715
+ depth,
1716
+ kind: node.kind,
1717
+ initialValue: node.name,
1718
+ onCommit: (name) => void commitRename(name),
1719
+ onCancel: () => setDraftRename(null)
1720
+ }
1721
+ ) : /* @__PURE__ */ jsxs(
1722
+ "button",
1723
+ {
1724
+ type: "button",
1725
+ tabIndex: -1,
1726
+ draggable: supportsMutation || void 0,
1727
+ onDragStart: supportsMutation ? (e) => {
1728
+ e.dataTransfer.setData("text/og-path", node.path);
1729
+ e.dataTransfer.effectAllowed = "move";
1730
+ } : void 0,
1731
+ onClick: () => {
1732
+ setActive(node.path);
1733
+ if (isDir) void toggle(node);
1734
+ else onSelectFile?.(node.path);
1735
+ },
1736
+ onDoubleClick: () => supportsMutation && startRename(node),
1737
+ onContextMenu: (e) => {
1738
+ if (!supportsMutation) return;
1739
+ e.preventDefault();
1740
+ setActive(node.path);
1741
+ setMenu({ node, x: e.clientX, y: e.clientY });
1742
+ },
1743
+ className: cn(
1744
+ "group relative flex min-h-7 w-full items-center gap-1 truncate rounded-og-sm px-1 py-0.5 text-left text-og-sm pointer-coarse:min-h-11",
1745
+ "hover:bg-og-surface-2",
1746
+ isSelected && "bg-og-surface-2",
1747
+ isCursor && "outline outline-1 -outline-offset-1 outline-og-accent",
1748
+ isDropTarget && "bg-og-accent-soft ring-1 ring-inset ring-og-accent",
1749
+ // A thin progress shimmer on the expanding row — no per-node spinner.
1750
+ isLoading && "after:pointer-events-none after:absolute after:inset-x-1 after:bottom-0 after:h-px after:animate-pulse after:rounded-full after:bg-og-accent-soft",
1751
+ node.status ? STATUS_TINT[node.status] : void 0
1752
+ ),
1753
+ style: { paddingLeft: `${depth * 12 + 4}px` },
1754
+ children: [
1755
+ isDir ? /* @__PURE__ */ jsx(
1756
+ ChevronRightIcon,
1757
+ {
1758
+ className: cn(
1759
+ "size-3 shrink-0 transition-transform",
1760
+ isOpen && "rotate-90",
1761
+ isLoading && "text-og-accent"
1762
+ )
1763
+ }
1764
+ ) : /* @__PURE__ */ jsx("span", { className: "inline-block w-3 shrink-0" }),
1765
+ isDir ? /* @__PURE__ */ jsx(FolderIcon, { className: "size-3.5 shrink-0" }) : /* @__PURE__ */ jsx(FileIcon, { className: "size-3.5 shrink-0" }),
1766
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: node.name }),
1767
+ supportsMutation && /* @__PURE__ */ jsx(
1768
+ "span",
1769
+ {
1770
+ role: "button",
1771
+ tabIndex: -1,
1772
+ "aria-label": "More actions",
1773
+ onClick: (e) => {
1774
+ e.preventDefault();
1775
+ e.stopPropagation();
1776
+ setActive(node.path);
1777
+ const rect = e.currentTarget.getBoundingClientRect();
1778
+ setMenu({ node, x: rect.right, y: rect.bottom });
1779
+ },
1780
+ className: "ml-auto hidden shrink-0 px-1 text-og-fg-subtle hover:text-og-fg group-hover:inline",
1781
+ children: "\u22EF"
1782
+ }
1783
+ )
1784
+ ]
1785
+ }
1786
+ )
1787
+ }
1788
+ );
1789
+ };
1790
+ const renderItem = (item) => {
1791
+ switch (item.type) {
1792
+ case "node":
1793
+ return renderNodeRow(item.node, item.depth);
1794
+ case "create":
1795
+ return /* @__PURE__ */ jsx(
1796
+ InlineInput,
1797
+ {
1798
+ depth: item.depth,
1799
+ kind: item.kind,
1800
+ initialValue: "",
1801
+ onCommit: (name) => void commitCreate(name),
1802
+ onCancel: () => setDraftCreate(null)
1803
+ }
1804
+ );
1805
+ case "skeleton":
1806
+ return /* @__PURE__ */ jsx(
1807
+ "div",
1808
+ {
1809
+ role: "group",
1810
+ "aria-hidden": true,
1811
+ style: { paddingLeft: `${item.depth * 12 + 4}px` },
1812
+ className: "space-y-1 py-1",
1813
+ children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
1814
+ "div",
1815
+ {
1816
+ className: "h-2.5 animate-pulse rounded-og-sm bg-og-surface-2",
1817
+ style: { width: `${70 - i * 12}%` }
1818
+ },
1819
+ i
1820
+ ))
1821
+ }
1822
+ );
1823
+ case "residue":
1824
+ return /* @__PURE__ */ jsxs(
1825
+ "div",
1826
+ {
1827
+ style: { paddingLeft: `${item.depth * 12 + 4}px` },
1828
+ className: "flex items-center gap-1.5 py-0.5 pr-1 text-og-xs italic text-og-fg-subtle",
1829
+ children: [
1830
+ /* @__PURE__ */ jsx("span", { className: "inline-block w-3 shrink-0" }),
1831
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: "contents on machine \u2014 open when live" })
1832
+ ]
1833
+ }
1834
+ );
1835
+ }
1836
+ };
1837
+ useEffect3(() => {
1838
+ if (!cursor) return;
1839
+ const index = renderItems.findIndex((it) => it.type === "node" && it.node.path === cursor);
1840
+ if (index >= 0) vlistRef.current?.scrollToIndex(index);
1841
+ }, [cursor, renderItems]);
1842
+ useEffect3(() => {
1843
+ if (!revealRequest) return;
1844
+ const index = renderItems.findIndex(
1845
+ (item) => item.type === "node" && item.node.path === revealRequest.path
1846
+ );
1847
+ if (index < 0) return;
1848
+ if (usesVirtualTree) {
1849
+ vlistRef.current?.scrollToIndex(index);
1850
+ } else {
1851
+ document.getElementById(`${treeId}-item-${index}`)?.scrollIntoView?.({ block: "nearest" });
1852
+ }
1853
+ setRevealRequest(
1854
+ (current) => current?.path === revealRequest.path && current.requestId === revealRequest.requestId ? null : current
1855
+ );
1856
+ }, [renderItems, revealRequest, treeId, usesVirtualTree]);
1857
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex min-h-0 min-w-0 flex-col", className), children: [
1858
+ showToolbar && /* @__PURE__ */ jsxs(
1859
+ "div",
1860
+ {
1861
+ role: "toolbar",
1862
+ "aria-label": "File actions",
1863
+ className: "flex shrink-0 flex-wrap items-center gap-0.5 border-b border-og-border px-1 py-1",
1864
+ children: [
1865
+ supportsMutation ? /* @__PURE__ */ jsxs(Fragment, { children: [
1866
+ /* @__PURE__ */ jsx(ToolbarButton, { label: "New file", onClick: () => startCreate("file"), disabled: busy, children: /* @__PURE__ */ jsx(FilePlusIcon, { className: "size-3.5" }) }),
1867
+ /* @__PURE__ */ jsx(ToolbarButton, { label: "New folder", onClick: () => startCreate("dir"), disabled: busy, children: /* @__PURE__ */ jsx(FolderPlusIcon, { className: "size-3.5" }) }),
1868
+ /* @__PURE__ */ jsx(
1869
+ ToolbarButton,
1870
+ {
1871
+ label: "Rename",
1872
+ onClick: () => {
1873
+ const node = cursor ? findNode(visibleTree, cursor) : void 0;
1874
+ if (node) startRename(node);
1875
+ },
1876
+ disabled: busy || !cursor,
1877
+ children: /* @__PURE__ */ jsx(PencilIcon, { className: "size-3.5" })
1878
+ }
1879
+ ),
1880
+ /* @__PURE__ */ jsx(
1881
+ ToolbarButton,
1882
+ {
1883
+ label: "Delete",
1884
+ onClick: (event) => {
1885
+ const node = cursor ? findNode(visibleTree, cursor) : void 0;
1886
+ if (node) void runDelete(node, event.currentTarget);
1887
+ },
1888
+ disabled: busy || !cursor,
1889
+ children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-3.5" })
1890
+ }
1891
+ )
1892
+ ] }) : null,
1893
+ /* @__PURE__ */ jsx("span", { className: "ml-auto" }),
1894
+ /* @__PURE__ */ jsx(
1895
+ ToolbarButton,
1896
+ {
1897
+ label: "Refresh",
1898
+ onClick: () => void result.refresh(),
1899
+ disabled: busy || result.loading,
1900
+ children: /* @__PURE__ */ jsx(RefreshCwIcon, { className: cn("size-3.5", result.loading && "animate-spin") })
1901
+ }
1902
+ )
1903
+ ]
1904
+ }
1905
+ ),
1906
+ showDegradedTree ? /* @__PURE__ */ jsxs(
1907
+ "div",
1908
+ {
1909
+ role: "status",
1910
+ "aria-live": "polite",
1911
+ "data-opengeni-files-degraded": true,
1912
+ className: "flex shrink-0 items-center gap-2 border-b border-og-status-running/30 bg-og-status-running/10 px-2 py-1.5 text-og-xs text-og-fg-muted",
1913
+ children: [
1914
+ /* @__PURE__ */ jsx(TriangleAlertIcon, { className: "size-3.5 shrink-0 text-og-status-running", "aria-hidden": true }),
1915
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: result.source === "capture" ? "Live files are temporarily unavailable. Showing the latest captured revision." : "Live refresh failed. Showing the last loaded files." }),
1916
+ /* @__PURE__ */ jsxs(
1917
+ "button",
1918
+ {
1919
+ type: "button",
1920
+ onClick: () => void result.refresh(),
1921
+ disabled: result.loading,
1922
+ className: "inline-flex min-h-7 shrink-0 items-center gap-1 rounded-og-sm border border-og-border bg-og-surface-1 px-2 font-medium text-og-fg transition-colors hover:border-og-border-strong focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11",
1923
+ children: [
1924
+ /* @__PURE__ */ jsx(
1925
+ RefreshCwIcon,
1926
+ {
1927
+ className: cn("size-3", result.loading && "animate-spin motion-reduce:animate-none"),
1928
+ "aria-hidden": true
1929
+ }
1930
+ ),
1931
+ "Retry"
1932
+ ]
1933
+ }
1934
+ )
1935
+ ]
1936
+ }
1937
+ ) : null,
1938
+ /* @__PURE__ */ jsx(
1939
+ "div",
1940
+ {
1941
+ ref: container.ref,
1942
+ onFocus: (event) => {
1943
+ if (event.target.id === treeId && cursorIndex < 0) {
1944
+ const first = flatRows[0];
1945
+ if (first) setActive(first.node.path);
1946
+ }
1947
+ },
1948
+ onKeyDown,
1949
+ onDragOver: supportsMutation ? (e) => {
1950
+ e.preventDefault();
1951
+ e.dataTransfer.dropEffect = "move";
1952
+ setDragOver("");
1953
+ } : void 0,
1954
+ onDrop: supportsMutation ? (e) => {
1955
+ e.preventDefault();
1956
+ const src = e.dataTransfer.getData("text/og-path");
1957
+ void onDropOnto("", src);
1958
+ } : void 0,
1959
+ className: cn(
1960
+ "flex min-h-0 min-w-0 flex-1 flex-col p-1",
1961
+ dragOver === "" && "ring-1 ring-inset ring-og-accent"
1962
+ ),
1963
+ "data-opengeni-file-tree": true,
1964
+ children: showErrorEmpty ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-2 p-2 text-og-sm text-og-fg-subtle", children: [
1965
+ /* @__PURE__ */ jsx("div", { children: fallback ?? `Could not load files: ${result.error?.message ?? "refresh the file list to try again"}` }),
1966
+ /* @__PURE__ */ jsxs(
1967
+ "button",
1968
+ {
1969
+ type: "button",
1970
+ onClick: () => void result.refresh(),
1971
+ disabled: result.loading,
1972
+ className: "inline-flex items-center gap-1.5 rounded-og-sm border border-og-border px-2 py-1 text-og-xs font-medium text-og-fg-muted transition-colors hover:border-og-border-strong hover:text-og-fg disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:min-h-11",
1973
+ children: [
1974
+ /* @__PURE__ */ jsx(
1975
+ RefreshCwIcon,
1976
+ {
1977
+ className: cn("size-3.5", result.loading && "animate-spin"),
1978
+ "aria-hidden": true
1979
+ }
1980
+ ),
1981
+ "Retry"
1982
+ ]
1983
+ }
1984
+ )
1985
+ ] }) : showEmpty ? /* @__PURE__ */ jsx("div", { className: "p-2 text-og-sm text-og-fg-subtle", children: emptyState ?? "This directory is empty" }) : !usesVirtualTree ? /* @__PURE__ */ jsx(
1986
+ "div",
1987
+ {
1988
+ id: treeId,
1989
+ role: "tree",
1990
+ "aria-label": "Workspace files",
1991
+ "aria-activedescendant": activeDescendantId,
1992
+ "aria-multiselectable": false,
1993
+ tabIndex: 0,
1994
+ className: "min-h-0 min-w-0 flex-1 overflow-auto outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
1995
+ children: renderItems.map((item) => /* @__PURE__ */ jsx("div", { className: "min-w-0", children: renderItem(item) }, itemKey(item)))
1996
+ }
1997
+ ) : (
1998
+ // Virtualized: only the rows in/near the viewport mount, so a 3k-node
1999
+ // tree stays responsive. The flat item list already carries the
2000
+ // expanded subtree + synthetic (create/skeleton/residue) rows.
2001
+ /* @__PURE__ */ jsx(
2002
+ VList,
2003
+ {
2004
+ ref: vlistRef,
2005
+ id: treeId,
2006
+ role: "tree",
2007
+ "aria-label": "Workspace files",
2008
+ "aria-activedescendant": activeDescendantId,
2009
+ "aria-multiselectable": false,
2010
+ tabIndex: 0,
2011
+ className: "min-h-0 flex-1 outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
2012
+ itemSize: coarsePointer ? 44 : 28,
2013
+ ssrCount: Math.min(32, renderItems.length),
2014
+ children: renderItems.map((item) => /* @__PURE__ */ jsx("div", { className: "min-w-0", children: renderItem(item) }, itemKey(item)))
2015
+ }
2016
+ )
2017
+ )
2018
+ }
2019
+ ),
2020
+ menu && menu.node && /* @__PURE__ */ jsx(
2021
+ ContextMenu,
2022
+ {
2023
+ node: menu.node,
2024
+ x: menu.x,
2025
+ y: menu.y,
2026
+ onRename: () => menu.node && startRename(menu.node),
2027
+ onDelete: () => menu.node && void runDelete(menu.node),
2028
+ onNewFile: () => startCreate("file"),
2029
+ onNewFolder: () => startCreate("dir"),
2030
+ onClose: () => {
2031
+ setMenu(null);
2032
+ window.requestAnimationFrame(() => getTreeElement()?.focus());
2033
+ }
2034
+ }
2035
+ ),
2036
+ pendingDelete ? /* @__PURE__ */ jsx(
2037
+ DeleteDialog,
2038
+ {
2039
+ node: pendingDelete,
2040
+ busy,
2041
+ portalTokenStyle,
2042
+ onCancel: () => closePendingDelete(true),
2043
+ onConfirm: () => {
2044
+ const node = pendingDelete;
2045
+ closePendingDelete(false);
2046
+ void performDelete(node);
2047
+ }
2048
+ }
2049
+ ) : null
2050
+ ] });
2051
+ }
2052
+ function DeleteDialog({
2053
+ node,
2054
+ busy,
2055
+ portalTokenStyle,
2056
+ onCancel,
2057
+ onConfirm
2058
+ }) {
2059
+ const cancelRef = useRef2(null);
2060
+ const [open, setOpen] = useState2(true);
2061
+ const closeIntentRef = useRef2("cancel");
2062
+ const settledRef = useRef2(false);
2063
+ const settleTimerRef = useRef2(null);
2064
+ const settle = () => {
2065
+ if (settledRef.current) return;
2066
+ settledRef.current = true;
2067
+ if (closeIntentRef.current === "confirm") {
2068
+ onConfirm();
2069
+ } else {
2070
+ onCancel();
2071
+ }
2072
+ };
2073
+ const scheduleSettle = () => {
2074
+ if (settleTimerRef.current !== null) return;
2075
+ settleTimerRef.current = setTimeout(() => {
2076
+ settleTimerRef.current = null;
2077
+ settle();
2078
+ }, 0);
2079
+ };
2080
+ useEffect3(
2081
+ () => () => {
2082
+ if (settleTimerRef.current !== null) clearTimeout(settleTimerRef.current);
2083
+ },
2084
+ []
2085
+ );
2086
+ return /* @__PURE__ */ jsx(
2087
+ AlertDialog.Root,
2088
+ {
2089
+ open,
2090
+ onOpenChange: (nextOpen) => {
2091
+ if (!nextOpen && !busy) {
2092
+ setOpen(false);
2093
+ scheduleSettle();
2094
+ }
2095
+ },
2096
+ children: /* @__PURE__ */ jsxs(AlertDialog.Portal, { container: typeof document === "undefined" ? null : document.body, children: [
2097
+ /* @__PURE__ */ jsx(AlertDialog.Overlay, { className: "og-root fixed inset-0 z-[100] bg-black/45 backdrop-blur-[2px]" }),
2098
+ /* @__PURE__ */ jsxs(
2099
+ AlertDialog.Content,
2100
+ {
2101
+ className: "og-root fixed left-1/2 top-1/2 z-[101] max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-sm -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-og-lg border border-og-border-strong bg-og-surface-1 p-4 text-og-fg shadow-2xl outline-hidden",
2102
+ style: portalTokenStyle,
2103
+ onOpenAutoFocus: (event) => {
2104
+ event.preventDefault();
2105
+ cancelRef.current?.focus();
2106
+ },
2107
+ onCloseAutoFocus: (event) => {
2108
+ event.preventDefault();
2109
+ scheduleSettle();
2110
+ },
2111
+ onEscapeKeyDown: (event) => {
2112
+ event.stopPropagation();
2113
+ if (busy) {
2114
+ event.preventDefault();
2115
+ } else {
2116
+ closeIntentRef.current = "cancel";
2117
+ }
2118
+ },
2119
+ children: [
2120
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
2121
+ /* @__PURE__ */ jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-full bg-og-status-failed/12 text-og-status-failed", children: /* @__PURE__ */ jsx(Trash2Icon, { className: "size-4", "aria-hidden": true }) }),
2122
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2123
+ /* @__PURE__ */ jsxs(AlertDialog.Title, { className: "text-og-sm font-semibold", children: [
2124
+ "Delete ",
2125
+ node.kind === "dir" ? "folder" : "file",
2126
+ "?"
2127
+ ] }),
2128
+ /* @__PURE__ */ jsxs(AlertDialog.Description, { className: "mt-1 text-og-sm leading-relaxed text-og-fg-muted", children: [
2129
+ /* @__PURE__ */ jsx("span", { className: "break-all font-og-mono text-og-fg", children: node.path }),
2130
+ node.kind === "dir" ? " and everything inside it will be permanently removed." : " will be permanently removed."
2131
+ ] })
2132
+ ] })
2133
+ ] }),
2134
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
2135
+ /* @__PURE__ */ jsx(AlertDialog.Cancel, { asChild: true, children: /* @__PURE__ */ jsx(
2136
+ "button",
2137
+ {
2138
+ ref: cancelRef,
2139
+ type: "button",
2140
+ onClick: () => {
2141
+ closeIntentRef.current = "cancel";
2142
+ },
2143
+ disabled: busy,
2144
+ className: "min-h-9 rounded-og-md border border-og-border px-3 text-og-sm font-medium text-og-fg hover:bg-og-surface-2 disabled:opacity-50 pointer-coarse:min-h-11",
2145
+ children: "Cancel"
2146
+ }
2147
+ ) }),
2148
+ /* @__PURE__ */ jsx(AlertDialog.Action, { asChild: true, children: /* @__PURE__ */ jsx(
2149
+ "button",
2150
+ {
2151
+ type: "button",
2152
+ onClick: () => {
2153
+ closeIntentRef.current = "confirm";
2154
+ },
2155
+ disabled: busy,
2156
+ 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",
2157
+ children: "Delete permanently"
2158
+ }
2159
+ ) })
2160
+ ] })
2161
+ ]
2162
+ }
2163
+ )
2164
+ ] })
2165
+ }
2166
+ );
2167
+ }
2168
+ function ToolbarButton({
2169
+ label,
2170
+ onClick,
2171
+ disabled,
2172
+ children
2173
+ }) {
2174
+ return /* @__PURE__ */ jsx(
2175
+ "button",
2176
+ {
2177
+ type: "button",
2178
+ title: label,
2179
+ "aria-label": label,
2180
+ onClick,
2181
+ disabled,
2182
+ className: cn(
2183
+ "inline-flex size-7 items-center justify-center rounded-og-sm p-1 text-og-fg-muted max-[1023px]:size-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
2184
+ "hover:bg-og-surface-2 hover:text-og-fg",
2185
+ "disabled:cursor-not-allowed disabled:opacity-40"
2186
+ ),
2187
+ children
2188
+ }
2189
+ );
2190
+ }
2191
+ function InlineInput({
2192
+ depth,
2193
+ kind,
2194
+ initialValue,
2195
+ onCommit,
2196
+ onCancel
2197
+ }) {
2198
+ const [value, setValue] = useState2(initialValue);
2199
+ const ref = useRef2(null);
2200
+ const doneRef = useRef2(false);
2201
+ useEffect3(() => {
2202
+ const el = ref.current;
2203
+ if (!el) return;
2204
+ el.focus();
2205
+ const dot = initialValue.lastIndexOf(".");
2206
+ if (initialValue && dot > 0) el.setSelectionRange(0, dot);
2207
+ else el.select();
2208
+ }, [initialValue]);
2209
+ const finish = (commit) => {
2210
+ if (doneRef.current) return;
2211
+ doneRef.current = true;
2212
+ if (commit) onCommit(value);
2213
+ else onCancel();
2214
+ };
2215
+ return /* @__PURE__ */ jsxs(
2216
+ "div",
2217
+ {
2218
+ className: "flex items-center gap-1 px-1 py-0.5",
2219
+ style: { paddingLeft: `${depth * 12 + 4}px` },
2220
+ children: [
2221
+ /* @__PURE__ */ jsx("span", { className: "inline-block w-3 shrink-0" }),
2222
+ kind === "dir" ? /* @__PURE__ */ jsx(FolderIcon, { className: "size-3.5 shrink-0" }) : /* @__PURE__ */ jsx(FileIcon, { className: "size-3.5 shrink-0" }),
2223
+ /* @__PURE__ */ jsx(
2224
+ "input",
2225
+ {
2226
+ ref,
2227
+ value,
2228
+ spellCheck: false,
2229
+ autoComplete: "off",
2230
+ "aria-label": kind === "dir" ? "Folder name" : "File name",
2231
+ onChange: (e) => setValue(e.target.value),
2232
+ onBlur: () => finish(true),
2233
+ onKeyDown: (e) => {
2234
+ if (e.key === "Enter") {
2235
+ e.preventDefault();
2236
+ finish(true);
2237
+ } else if (e.key === "Escape") {
2238
+ e.preventDefault();
2239
+ finish(false);
2240
+ }
2241
+ e.stopPropagation();
2242
+ },
2243
+ className: cn(
2244
+ "min-w-0 flex-1 rounded-og-sm border bg-og-bg px-1 py-0 text-og-sm",
2245
+ "border-og-accent text-og-fg",
2246
+ "outline-hidden"
2247
+ )
2248
+ }
2249
+ )
2250
+ ]
2251
+ }
2252
+ );
2253
+ }
2254
+ function ContextMenu({
2255
+ node,
2256
+ x,
2257
+ y,
2258
+ onRename,
2259
+ onDelete,
2260
+ onNewFile,
2261
+ onNewFolder,
2262
+ onClose
2263
+ }) {
2264
+ const isDir = node.kind === "dir";
2265
+ const menuRef = useRef2(null);
2266
+ const vw = typeof window !== "undefined" ? window.innerWidth : 9999;
2267
+ const vh = typeof window !== "undefined" ? window.innerHeight : 9999;
2268
+ const left = Math.max(4, Math.min(x, vw - 180));
2269
+ const top = Math.max(4, Math.min(y, vh - 160));
2270
+ useEffect3(() => {
2271
+ menuRef.current?.querySelector('[role="menuitem"]')?.focus();
2272
+ }, []);
2273
+ const onKeyDown = (event) => {
2274
+ const items = Array.from(
2275
+ menuRef.current?.querySelectorAll('[role="menuitem"]') ?? []
2276
+ );
2277
+ if (items.length === 0) return;
2278
+ const current = items.findIndex((item2) => item2 === document.activeElement);
2279
+ let next = null;
2280
+ if (event.key === "ArrowDown") next = (current + 1 + items.length) % items.length;
2281
+ else if (event.key === "ArrowUp") next = (current - 1 + items.length) % items.length;
2282
+ else if (event.key === "Home") next = 0;
2283
+ else if (event.key === "End") next = items.length - 1;
2284
+ else if (event.key === "Escape") {
2285
+ event.preventDefault();
2286
+ event.stopPropagation();
2287
+ onClose();
2288
+ return;
2289
+ }
2290
+ if (next === null) return;
2291
+ event.preventDefault();
2292
+ event.stopPropagation();
2293
+ items[next]?.focus();
2294
+ };
2295
+ const item = (label, icon, onClick, danger) => /* @__PURE__ */ jsxs(
2296
+ "button",
2297
+ {
2298
+ type: "button",
2299
+ role: "menuitem",
2300
+ onClick: (e) => {
2301
+ e.stopPropagation();
2302
+ onClick();
2303
+ },
2304
+ className: cn(
2305
+ MENU_BUTTON_CLASS,
2306
+ danger && "text-og-status-failed [&_svg]:text-og-status-failed!"
2307
+ ),
2308
+ children: [
2309
+ icon,
2310
+ label
2311
+ ]
2312
+ }
2313
+ );
2314
+ return /* @__PURE__ */ jsxs(
2315
+ "div",
2316
+ {
2317
+ ref: menuRef,
2318
+ role: "menu",
2319
+ "aria-label": `Actions for ${node.name}`,
2320
+ onKeyDown,
2321
+ onClick: (e) => e.stopPropagation(),
2322
+ style: { left, top },
2323
+ className: cn(MENU_SURFACE_CLASS, "fixed z-50 min-w-[180px] overflow-hidden"),
2324
+ children: [
2325
+ isDir && /* @__PURE__ */ jsxs(Fragment, { children: [
2326
+ item("New file", /* @__PURE__ */ jsx(FilePlusIcon, {}), onNewFile),
2327
+ item("New folder", /* @__PURE__ */ jsx(FolderPlusIcon, {}), onNewFolder),
2328
+ /* @__PURE__ */ jsx("div", { role: "separator", className: MENU_SEPARATOR_CLASS })
2329
+ ] }),
2330
+ item("Rename", /* @__PURE__ */ jsx(PencilIcon, {}), onRename),
2331
+ item("Delete", /* @__PURE__ */ jsx(Trash2Icon, {}), onDelete, true)
2332
+ ]
2333
+ }
2334
+ );
2335
+ }
2336
+
2337
+ // src/components/pierre-file.tsx
2338
+ import {
2339
+ lazy,
2340
+ Suspense,
2341
+ useEffect as useEffect4,
2342
+ useState as useState3,
2343
+ useSyncExternalStore
2344
+ } from "react";
2345
+ import { jsx as jsx2 } from "react/jsx-runtime";
2346
+ var LazyFile = lazy(async () => {
2347
+ const mod = await loadPierreDiffs();
2348
+ return { default: mod.File };
2349
+ });
2350
+ function PierreFile({
2351
+ path,
2352
+ contents,
2353
+ themeType,
2354
+ theme,
2355
+ disableWorkerPool,
2356
+ loading,
2357
+ fallback,
2358
+ className
2359
+ }) {
2360
+ const [failed, setFailed] = useState3(false);
2361
+ const [ready, setReady] = useState3(false);
2362
+ const loaderRevision = useSyncExternalStore(
2363
+ subscribePierreDiffs,
2364
+ pierreDiffsRevision,
2365
+ pierreDiffsRevision
2366
+ );
2367
+ useEffect4(() => {
2368
+ let cancelled = false;
2369
+ setFailed(false);
2370
+ loadPierreDiffs().then(
2371
+ () => {
2372
+ if (!cancelled) setReady(true);
2373
+ },
2374
+ () => {
2375
+ if (!cancelled) setFailed(true);
2376
+ }
2377
+ );
2378
+ return () => {
2379
+ cancelled = true;
2380
+ };
2381
+ }, [loaderRevision]);
2382
+ const name = path.split("/").filter(Boolean).pop() ?? path;
2383
+ if (failed) {
2384
+ return /* @__PURE__ */ jsx2("div", { className, children: fallback ?? /* @__PURE__ */ jsx2(PlainFile, { name, contents }) });
2385
+ }
2386
+ const options = {
2387
+ overflow: "scroll",
2388
+ stickyHeader: true,
2389
+ showLineNumbers: true,
2390
+ ...theme ? { theme } : {
2391
+ theme: {
2392
+ dark: "github-dark-high-contrast",
2393
+ light: "github-light-high-contrast"
2394
+ }
2395
+ },
2396
+ themeType: themeType ?? "dark"
2397
+ };
2398
+ const pierreVars = {
2399
+ "--diffs-dark-bg": "var(--og-color-bg)",
2400
+ "--diffs-light-bg": "var(--og-color-bg)",
2401
+ "--diffs-bg-buffer-override": "var(--og-color-surface-1)",
2402
+ "--diffs-bg-separator-override": "var(--og-color-surface-1)",
2403
+ // Pierre's default (fg mixed 65% into bg) falls under 4.5:1 on the lifted
2404
+ // graphite separator; quiet meta text keeps AA on every diff surface.
2405
+ "--diffs-fg-number-override": "var(--og-color-fg-subtle)",
2406
+ "--diffs-font-size": "var(--og-code-font-size)",
2407
+ "--diffs-line-height": "var(--og-code-line-height)"
2408
+ };
2409
+ return /* @__PURE__ */ jsx2("div", { className: cn("min-w-0", className), "data-opengeni-pierre-file": true, style: pierreVars, children: /* @__PURE__ */ jsx2(Suspense, { fallback: loading ?? /* @__PURE__ */ jsx2(FileSkeleton, {}), children: ready ? /* @__PURE__ */ jsx2(
2410
+ LazyFile,
2411
+ {
2412
+ file: { name, contents },
2413
+ options,
2414
+ ...disableWorkerPool !== void 0 ? { disableWorkerPool } : {}
2415
+ }
2416
+ ) : loading ?? /* @__PURE__ */ jsx2(FileSkeleton, {}) }) });
2417
+ }
2418
+ function PlainFile({ name, contents }) {
2419
+ return /* @__PURE__ */ jsx2(
2420
+ "pre",
2421
+ {
2422
+ className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg",
2423
+ "data-file": name,
2424
+ children: contents
2425
+ }
2426
+ );
2427
+ }
2428
+ function FileSkeleton() {
2429
+ return /* @__PURE__ */ jsx2("div", { className: "p-3 text-og-sm text-og-fg-subtle", children: "Loading file\u2026" });
2430
+ }
2431
+
2432
+ // src/components/sandbox-files.tsx
2433
+ import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
2434
+ function SandboxFiles({
2435
+ files,
2436
+ git,
2437
+ fileSystemAvailable = true,
2438
+ usePierre = true,
2439
+ editable = true,
2440
+ onEditIntent,
2441
+ initialSelectedPath,
2442
+ onSelectedPathChange,
2443
+ isNodeVisible,
2444
+ requestedPath,
2445
+ requestedLine,
2446
+ requestedPathRequestId,
2447
+ requestedPathReady = true,
2448
+ workspaceResting = false,
2449
+ workspaceWaking = false,
2450
+ liveWorkspaceReady = true,
2451
+ workspaceError = null,
2452
+ onWakeWorkspace,
2453
+ themeType,
2454
+ className
2455
+ }) {
2456
+ const [selected, setSelected] = useState4(() => initialSelectedPath ?? null);
2457
+ const [editMode, setEditMode] = useState4(false);
2458
+ const [focusLine, setFocusLine] = useState4(null);
2459
+ const [treeRevealRequest, setTreeRevealRequest] = useState4(null);
2460
+ const [liveRequestedPath, setLiveRequestedPath] = useState4(null);
2461
+ const [viewReloadRevision, setViewReloadRevision] = useState4(0);
2462
+ const viewerScrollRef = useRef3(null);
2463
+ const pendingRequestRef = useRef3(null);
2464
+ const handledRequestRef = useRef3(null);
2465
+ const requestKey = requestedPath ? requestedPathRequestId ?? requestedPath : null;
2466
+ useEffect5(() => {
2467
+ if (!requestedPath || requestKey === null) {
2468
+ pendingRequestRef.current = null;
2469
+ handledRequestRef.current = null;
2470
+ setTreeRevealRequest(null);
2471
+ return;
2472
+ }
2473
+ if (handledRequestRef.current === requestKey) {
2474
+ return;
2475
+ }
2476
+ if (!requestedPathReady) {
2477
+ pendingRequestRef.current = requestKey;
2478
+ setTreeRevealRequest(null);
2479
+ return;
2480
+ }
2481
+ if (isNodeVisible && files.loading && files.tree.length === 0) return;
2482
+ if (isNodeVisible && !files.loading && files.tree.length === 0) {
2483
+ handledRequestRef.current = requestKey;
2484
+ pendingRequestRef.current = null;
2485
+ setTreeRevealRequest(null);
2486
+ return;
2487
+ }
2488
+ if (filePathVisibility(files.tree, requestedPath, isNodeVisible) === "hidden") {
2489
+ handledRequestRef.current = requestKey;
2490
+ pendingRequestRef.current = null;
2491
+ setTreeRevealRequest(null);
2492
+ return;
2493
+ }
2494
+ handledRequestRef.current = requestKey;
2495
+ pendingRequestRef.current = null;
2496
+ setSelected(requestedPath);
2497
+ onSelectedPathChange?.(requestedPath);
2498
+ setEditMode(false);
2499
+ setFocusLine(requestedLine != null && requestedLine > 0 ? requestedLine : null);
2500
+ setTreeRevealRequest({ path: requestedPath, requestId: requestKey });
2501
+ setViewReloadRevision((revision) => revision + 1);
2502
+ }, [
2503
+ files.loading,
2504
+ files.tree,
2505
+ isNodeVisible,
2506
+ onSelectedPathChange,
2507
+ requestKey,
2508
+ requestedLine,
2509
+ requestedPath,
2510
+ requestedPathReady
2511
+ ]);
2512
+ const rootRef = useRef3(null);
2513
+ const [wide, setWide] = useState4(false);
2514
+ useEffect5(() => {
2515
+ const el = rootRef.current;
2516
+ if (!el) return;
2517
+ const update = () => setWide(el.getBoundingClientRect().width >= 720);
2518
+ update();
2519
+ if (typeof ResizeObserver === "undefined") return;
2520
+ const observer = new ResizeObserver(update);
2521
+ observer.observe(el);
2522
+ const surface = el.closest("[data-workspace-surface]");
2523
+ const surfaceObserver = surface && typeof MutationObserver !== "undefined" ? new MutationObserver(update) : null;
2524
+ surfaceObserver?.observe(surface, {
2525
+ attributes: true,
2526
+ attributeFilter: ["class", "style"]
2527
+ });
2528
+ return () => {
2529
+ observer.disconnect();
2530
+ surfaceObserver?.disconnect();
2531
+ };
2532
+ }, []);
2533
+ const resolvedTheme = useThemeType(themeType);
2534
+ const selectedVisibility = selected ? filePathVisibility(files.tree, selected, isNodeVisible) : "unknown";
2535
+ const visibilityPending = Boolean(isNodeVisible && files.loading && files.tree.length === 0);
2536
+ const viewPath = selectedVisibility === "hidden" || visibilityPending ? null : selected;
2537
+ useEffect5(() => {
2538
+ if (selected === null || selectedVisibility !== "hidden") return;
2539
+ setSelected(null);
2540
+ onSelectedPathChange?.(null);
2541
+ setEditMode(false);
2542
+ setFocusLine(null);
2543
+ setTreeRevealRequest(null);
2544
+ setLiveRequestedPath(null);
2545
+ }, [onSelectedPathChange, selected, selectedVisibility]);
2546
+ const fileView = useFileView(
2547
+ viewPath,
2548
+ files.readFile,
2549
+ `${files.contentRevision ?? 0}:${viewReloadRevision}`
2550
+ );
2551
+ useEffect5(() => {
2552
+ if (focusLine === null && viewReloadRevision > 0 && viewerScrollRef.current) {
2553
+ viewerScrollRef.current.scrollTop = 0;
2554
+ }
2555
+ }, [focusLine, viewReloadRevision]);
2556
+ const selectFile = useCallback3(
2557
+ (path) => {
2558
+ if (pendingRequestRef.current !== null) {
2559
+ handledRequestRef.current = pendingRequestRef.current;
2560
+ pendingRequestRef.current = null;
2561
+ }
2562
+ setSelected(path);
2563
+ onSelectedPathChange?.(path);
2564
+ setEditMode(false);
2565
+ setFocusLine(null);
2566
+ setTreeRevealRequest(null);
2567
+ setLiveRequestedPath(null);
2568
+ setViewReloadRevision(0);
2569
+ },
2570
+ [onSelectedPathChange]
2571
+ );
2572
+ const canEdit = editable && viewPath !== null && !fileView.loading && fileView.error === null && !fileView.isBinary && !fileView.truncated && fileView.content !== null;
2573
+ const showEditor = canEdit && editMode;
2574
+ const captureFileUnavailable = fileView.error instanceof CapturedFileUnavailableError ? fileView.error : null;
2575
+ const waitingForSelectedFile = !workspaceError && liveRequestedPath === viewPath && (!liveWorkspaceReady || files.loading) && captureFileUnavailable !== null;
2576
+ if (workspaceError && !liveWorkspaceReady && files.source !== "capture") {
2577
+ return /* @__PURE__ */ jsxs2(Notice, { className, title: "Could not open live workspace", announce: "alert", children: [
2578
+ /* @__PURE__ */ jsx3("p", { children: workspaceError.message }),
2579
+ onWakeWorkspace ? /* @__PURE__ */ jsx3(WakeButton, { onClick: onWakeWorkspace, children: "Retry live workspace" }) : null
2580
+ ] });
2581
+ }
2582
+ if (workspaceResting || workspaceWaking) {
2583
+ return /* @__PURE__ */ jsx3("div", { className: cn("h-full", className), "data-opengeni-workspace-resting": true, children: /* @__PURE__ */ jsxs2(
2584
+ Notice,
2585
+ {
2586
+ icon: workspaceWaking ? /* @__PURE__ */ jsx3(
2587
+ LoaderCircleIcon,
2588
+ {
2589
+ className: "size-5 animate-spin motion-reduce:animate-none",
2590
+ "aria-hidden": true
2591
+ }
2592
+ ) : /* @__PURE__ */ jsx3(FileCode2Icon, { className: "size-5", "aria-hidden": true }),
2593
+ title: workspaceWaking ? "Waking workspace" : "Workspace is resting",
2594
+ announce: "status",
2595
+ children: [
2596
+ /* @__PURE__ */ jsx3("p", { children: workspaceWaking ? "Connecting to the live file system\u2026" : "No captured revision is available yet. Wake the sandbox to browse its current files." }),
2597
+ !workspaceWaking && onWakeWorkspace ? /* @__PURE__ */ jsx3(WakeButton, { onClick: onWakeWorkspace, children: "Open live workspace" }) : null
2598
+ ]
2599
+ }
2600
+ ) });
2601
+ }
2602
+ if (!fileSystemAvailable) {
2603
+ return /* @__PURE__ */ jsx3(
2604
+ Notice,
2605
+ {
2606
+ className,
2607
+ icon: /* @__PURE__ */ jsx3(FileWarningIcon, { className: "size-5", "aria-hidden": true }),
2608
+ title: "Files unavailable",
2609
+ announce: "alert",
2610
+ children: "This sandbox does not expose a file system."
2611
+ }
2612
+ );
2613
+ }
2614
+ return /* @__PURE__ */ jsxs2("div", { ref: rootRef, className: cn("flex h-full min-h-0 min-w-0 flex-col", className), children: [
2615
+ /* @__PURE__ */ jsx3(
2616
+ GitHeader,
2617
+ {
2618
+ loading: Boolean(files.loading || files.gitLoading || files.source === null || git?.loading) && files.gitSummary === null,
2619
+ git: files.gitSummary ?? {
2620
+ branch: git?.branch ?? null,
2621
+ isRepo: git?.isRepo ?? false,
2622
+ repoCount: git?.repoCount ?? 0,
2623
+ ahead: git?.ahead ?? 0,
2624
+ behind: git?.behind ?? 0,
2625
+ dirtyCount: git?.diff.length ?? 0
2626
+ }
2627
+ }
2628
+ ),
2629
+ /* @__PURE__ */ jsxs2(
2630
+ Group,
2631
+ {
2632
+ orientation: wide ? "horizontal" : "vertical",
2633
+ className: cn("min-h-0 flex-1", wide ? "flex-row" : "flex-col"),
2634
+ children: [
2635
+ /* @__PURE__ */ jsx3(
2636
+ Panel,
2637
+ {
2638
+ id: "sandbox-files-tree",
2639
+ defaultSize: wide ? "280px" : "40%",
2640
+ minSize: wide ? "180px" : "120px",
2641
+ maxSize: wide ? "60%" : "70%",
2642
+ className: "flex min-h-0 min-w-0 flex-col",
2643
+ children: /* @__PURE__ */ jsx3(
2644
+ FileBrowser,
2645
+ {
2646
+ result: files,
2647
+ isNodeVisible,
2648
+ selectedPath: selected ?? void 0,
2649
+ ...treeRevealRequest ? {
2650
+ revealPath: treeRevealRequest.path,
2651
+ revealPathRequestId: treeRevealRequest.requestId
2652
+ } : {},
2653
+ onSelectFile: selectFile,
2654
+ editable,
2655
+ emptyState: "This directory is empty",
2656
+ className: "min-w-0 flex-1"
2657
+ }
2658
+ )
2659
+ }
2660
+ ),
2661
+ /* @__PURE__ */ jsx3(
2662
+ Separator,
2663
+ {
2664
+ "aria-label": "Resize file tree",
2665
+ className: cn(
2666
+ "group relative z-10 shrink-0 cursor-col-resize outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-og-accent",
2667
+ "w-px bg-og-border after:absolute after:inset-y-0 after:left-1/2 after:w-3 after:-translate-x-1/2",
2668
+ "hover:bg-og-accent focus-visible:bg-og-accent data-[separator-state=dragging]:bg-og-accent",
2669
+ !wide && "h-px w-full cursor-row-resize after:inset-x-0 after:inset-y-auto after:top-1/2 after:h-3 after:w-full after:-translate-x-0 after:-translate-y-1/2"
2670
+ )
2671
+ }
2672
+ ),
2673
+ /* @__PURE__ */ jsxs2(
2674
+ Panel,
2675
+ {
2676
+ id: "sandbox-files-viewer",
2677
+ minSize: wide ? "240px" : "160px",
2678
+ className: cn("flex min-h-0 min-w-0 flex-col", !wide && "border-t border-og-border"),
2679
+ children: [
2680
+ /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center justify-between gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1", children: [
2681
+ /* @__PURE__ */ jsx3(
2682
+ "span",
2683
+ {
2684
+ "data-opengeni-selected-file": true,
2685
+ className: "min-w-0 truncate font-og-mono text-og-xs text-og-fg-muted",
2686
+ children: selected ? focusLine !== null ? `${selected}:${focusLine}` : selected : "No file selected"
2687
+ }
2688
+ ),
2689
+ canEdit && /* @__PURE__ */ jsx3(
2690
+ Segmented,
2691
+ {
2692
+ options: [
2693
+ { value: "view", label: "View" },
2694
+ { value: "edit", label: "Edit" }
2695
+ ],
2696
+ value: editMode ? "edit" : "view",
2697
+ onChange: (v) => setEditMode(v === "edit")
2698
+ }
2699
+ )
2700
+ ] }),
2701
+ /* @__PURE__ */ jsx3(
2702
+ "div",
2703
+ {
2704
+ ref: viewerScrollRef,
2705
+ className: "min-h-0 flex-1 overflow-auto",
2706
+ "data-opengeni-file-viewer-scroll": true,
2707
+ children: viewPath ? showEditor && fileView.content !== null ? /* @__PURE__ */ jsx3(
2708
+ CodeEditor,
2709
+ {
2710
+ path: viewPath,
2711
+ initialContents: fileView.content,
2712
+ themeType: resolvedTheme,
2713
+ onSave: (contents, expectedContents) => files.writeFile(viewPath, contents, { expectedContent: expectedContents }),
2714
+ onOverwrite: (contents) => files.writeFile(viewPath, contents, { force: true }),
2715
+ onReload: () => setViewReloadRevision((revision) => revision + 1),
2716
+ ...onEditIntent ? { onEditIntent } : {},
2717
+ className: "h-full"
2718
+ },
2719
+ viewPath
2720
+ ) : workspaceError && (liveRequestedPath === viewPath || requestedPath === viewPath) && !liveWorkspaceReady ? /* @__PURE__ */ jsxs2(Notice, { title: "Could not open live file", announce: "alert", children: [
2721
+ /* @__PURE__ */ jsx3("p", { children: workspaceError.message }),
2722
+ onWakeWorkspace ? /* @__PURE__ */ jsx3(WakeButton, { onClick: onWakeWorkspace, children: "Retry live file" }) : null
2723
+ ] }) : waitingForSelectedFile ? /* @__PURE__ */ jsxs2(
2724
+ Notice,
2725
+ {
2726
+ icon: /* @__PURE__ */ jsx3(
2727
+ LoaderCircleIcon,
2728
+ {
2729
+ className: "size-5 animate-spin motion-reduce:animate-none",
2730
+ "aria-hidden": true
2731
+ }
2732
+ ),
2733
+ title: "Waking workspace",
2734
+ announce: "status",
2735
+ children: [
2736
+ "Opening ",
2737
+ viewPath,
2738
+ " when the live file system is ready\u2026"
2739
+ ]
2740
+ }
2741
+ ) : captureFileUnavailable ? /* @__PURE__ */ jsxs2(Notice, { icon: /* @__PURE__ */ jsx3(FileCode2Icon, { className: "size-5", "aria-hidden": true }), title: "On machine", children: [
2742
+ /* @__PURE__ */ jsx3("p", { children: captureFileUnavailable.reason === "too-large" ? "This file is larger than the captured preview limit." : captureFileUnavailable.reason === "content-missing" ? "The captured copy is no longer available." : "This file was indexed, but it was not changed in the captured turn." }),
2743
+ onWakeWorkspace ? /* @__PURE__ */ jsx3(
2744
+ WakeButton,
2745
+ {
2746
+ onClick: () => {
2747
+ setLiveRequestedPath(viewPath);
2748
+ if (liveWorkspaceReady) void files.refresh();
2749
+ else onWakeWorkspace();
2750
+ },
2751
+ children: liveWorkspaceReady ? "Retry live file" : "Open live file"
2752
+ }
2753
+ ) : null
2754
+ ] }) : fileView.error ? /* @__PURE__ */ jsxs2(Notice, { announce: "alert", children: [
2755
+ "Could not open ",
2756
+ viewPath,
2757
+ ": ",
2758
+ fileView.error.message
2759
+ ] }) : fileView.loading ? /* @__PURE__ */ jsxs2(Notice, { announce: "status", children: [
2760
+ "Loading ",
2761
+ viewPath,
2762
+ "\u2026"
2763
+ ] }) : fileView.imageUrl ? /* @__PURE__ */ jsx3(
2764
+ RasterFilePreview,
2765
+ {
2766
+ src: fileView.imageUrl,
2767
+ path: viewPath
2768
+ },
2769
+ fileView.imageUrl
2770
+ ) : fileView.isBinary ? /* @__PURE__ */ jsxs2(Notice, { children: [
2771
+ viewPath,
2772
+ " is a binary file (",
2773
+ fileView.sizeBytes ?? 0,
2774
+ " bytes)."
2775
+ ] }) : fileView.content !== null ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
2776
+ fileView.truncated && /* @__PURE__ */ jsxs2("div", { className: "border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-status-running", children: [
2777
+ "Large file \u2014 showing a truncated preview (",
2778
+ fileView.sizeBytes ?? 0,
2779
+ " bytes loaded). Editing is disabled to avoid corrupting the file."
2780
+ ] }),
2781
+ usePierre && focusLine === null ? /* @__PURE__ */ jsx3(
2782
+ PierreFile,
2783
+ {
2784
+ path: viewPath,
2785
+ contents: fileView.content,
2786
+ themeType: resolvedTheme,
2787
+ fallback: /* @__PURE__ */ jsx3("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content }),
2788
+ className: "p-1"
2789
+ },
2790
+ `${viewPath}:${viewReloadRevision}`
2791
+ ) : focusLine !== null ? /* @__PURE__ */ jsx3(
2792
+ LineNumberedFile,
2793
+ {
2794
+ path: viewPath,
2795
+ contents: fileView.content,
2796
+ focusLine
2797
+ }
2798
+ ) : /* @__PURE__ */ jsx3("pre", { className: "overflow-auto whitespace-pre p-2 font-og-mono text-og-sm text-og-fg", children: fileView.content })
2799
+ ] }) : /* @__PURE__ */ jsxs2(Notice, { announce: "status", children: [
2800
+ "Loading ",
2801
+ viewPath,
2802
+ "\u2026"
2803
+ ] }) : (
2804
+ // Nothing selected — the tree shows the whole workspace; pick a file.
2805
+ requestedPath && !requestedPathReady ? workspaceError ? /* @__PURE__ */ jsxs2(Notice, { title: "Could not open live file", announce: "alert", children: [
2806
+ /* @__PURE__ */ jsx3("p", { children: workspaceError.message }),
2807
+ onWakeWorkspace ? /* @__PURE__ */ jsx3(WakeButton, { onClick: onWakeWorkspace, children: "Retry live file" }) : null
2808
+ ] }) : /* @__PURE__ */ jsxs2(
2809
+ Notice,
2810
+ {
2811
+ icon: /* @__PURE__ */ jsx3(
2812
+ LoaderCircleIcon,
2813
+ {
2814
+ className: "size-5 animate-spin motion-reduce:animate-none",
2815
+ "aria-hidden": true
2816
+ }
2817
+ ),
2818
+ title: "Waking sandbox",
2819
+ announce: "status",
2820
+ children: [
2821
+ "Opening ",
2822
+ requestedPath,
2823
+ " when the live workspace is ready\u2026"
2824
+ ]
2825
+ }
2826
+ ) : /* @__PURE__ */ jsx3(Notice, { icon: /* @__PURE__ */ jsx3(FileCode2Icon, { className: "size-5", "aria-hidden": true }), title: "Choose a file", children: "Select a file in the tree to preview it." })
2827
+ )
2828
+ }
2829
+ )
2830
+ ]
2831
+ }
2832
+ )
2833
+ ]
2834
+ }
2835
+ )
2836
+ ] });
2837
+ }
2838
+ function WakeButton({ children, onClick }) {
2839
+ return /* @__PURE__ */ jsx3(
2840
+ "button",
2841
+ {
2842
+ type: "button",
2843
+ onClick,
2844
+ className: "mt-1 inline-flex min-h-11 items-center justify-center rounded-og-md border border-og-primary-border bg-og-primary text-og-primary-fg px-3 py-2 text-og-sm font-medium transition-colors hover:bg-og-primary-hover focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent focus-visible:ring-offset-2 focus-visible:ring-offset-og-bg",
2845
+ children
2846
+ }
2847
+ );
2848
+ }
2849
+ function LineNumberedFile({
2850
+ path,
2851
+ contents,
2852
+ focusLine
2853
+ }) {
2854
+ const lines = contents.split("\n");
2855
+ const inRange = focusLine >= 1 && focusLine <= lines.length;
2856
+ const targetRef = useRef3(null);
2857
+ useEffect5(() => {
2858
+ targetRef.current?.scrollIntoView({
2859
+ block: "center",
2860
+ behavior: prefersReducedMotion() ? "auto" : "smooth"
2861
+ });
2862
+ }, [path, focusLine, contents]);
2863
+ return /* @__PURE__ */ jsxs2(
2864
+ "div",
2865
+ {
2866
+ className: "h-full min-h-0 overflow-auto font-og-mono text-og-sm text-og-fg",
2867
+ role: "region",
2868
+ "aria-label": inRange ? `${path} at line ${focusLine}` : path,
2869
+ children: [
2870
+ !inRange ? /* @__PURE__ */ jsxs2(
2871
+ "p",
2872
+ {
2873
+ className: "border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-xs text-og-fg-muted",
2874
+ role: "status",
2875
+ children: [
2876
+ "Line ",
2877
+ focusLine,
2878
+ " is past the end of this file."
2879
+ ]
2880
+ }
2881
+ ) : null,
2882
+ /* @__PURE__ */ jsx3("div", { children: lines.map((text, index) => {
2883
+ const lineNumber = index + 1;
2884
+ const focused = inRange && lineNumber === focusLine;
2885
+ return /* @__PURE__ */ jsxs2(
2886
+ "div",
2887
+ {
2888
+ ref: focused ? targetRef : void 0,
2889
+ "data-opengeni-file-line": lineNumber,
2890
+ ...focused ? { "data-opengeni-focus-line": "" } : {},
2891
+ "aria-current": focused ? "location" : void 0,
2892
+ className: cn("flex gap-3 px-2 py-0.5 leading-6", focused && "bg-og-accent-soft"),
2893
+ children: [
2894
+ /* @__PURE__ */ jsx3("span", { className: "w-11 shrink-0 select-none text-right tabular-nums text-og-fg-subtle", children: lineNumber }),
2895
+ /* @__PURE__ */ jsx3("pre", { className: "min-w-0 flex-1 whitespace-pre-wrap break-words", children: text || " " })
2896
+ ]
2897
+ },
2898
+ lineNumber
2899
+ );
2900
+ }) })
2901
+ ]
2902
+ }
2903
+ );
2904
+ }
2905
+ function GitHeader({ git, loading }) {
2906
+ if (loading) {
2907
+ return /* @__PURE__ */ jsxs2(
2908
+ "div",
2909
+ {
2910
+ className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm text-og-fg-muted",
2911
+ role: "status",
2912
+ "aria-live": "polite",
2913
+ children: [
2914
+ /* @__PURE__ */ jsx3(
2915
+ LoaderCircleIcon,
2916
+ {
2917
+ className: "size-3.5 shrink-0 animate-spin motion-reduce:animate-none",
2918
+ "aria-hidden": true
2919
+ }
2920
+ ),
2921
+ /* @__PURE__ */ jsx3("span", { children: "Loading repository\u2026" })
2922
+ ]
2923
+ }
2924
+ );
2925
+ }
2926
+ const dirty = git.dirtyCount > 0;
2927
+ return /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-2 border-b border-og-border bg-og-surface-1 px-2 py-1 text-og-sm", children: [
2928
+ /* @__PURE__ */ jsx3(
2929
+ "span",
2930
+ {
2931
+ "aria-hidden": "true",
2932
+ className: cn(
2933
+ "size-2 shrink-0 rounded-full",
2934
+ dirty ? "bg-og-status-running" : "bg-og-status-idle"
2935
+ )
2936
+ }
2937
+ ),
2938
+ /* @__PURE__ */ jsx3("span", { className: "sr-only", children: dirty ? `Uncommitted changes in ${git.dirtyCount} files` : "No uncommitted changes" }),
2939
+ /* @__PURE__ */ jsx3("span", { className: "truncate font-og-mono text-og-fg", children: git.repoCount > 1 ? `${git.repoCount} repositories` : git.branch ?? (git.isRepo ? "(detached)" : "no repo") }),
2940
+ (git.ahead > 0 || git.behind > 0) && /* @__PURE__ */ jsxs2("span", { className: "flex shrink-0 items-center gap-1.5 text-og-xs text-og-fg-subtle", children: [
2941
+ git.ahead > 0 && /* @__PURE__ */ jsxs2("span", { "data-contrast-audited": true, children: [
2942
+ "\u2191",
2943
+ git.ahead
2944
+ ] }),
2945
+ git.behind > 0 && /* @__PURE__ */ jsxs2("span", { "data-contrast-audited": true, children: [
2946
+ "\u2193",
2947
+ git.behind
2948
+ ] })
2949
+ ] }),
2950
+ dirty && /* @__PURE__ */ jsxs2(
2951
+ "span",
2952
+ {
2953
+ "aria-hidden": "true",
2954
+ "data-contrast-audited": true,
2955
+ className: "ml-auto shrink-0 text-og-xs text-og-fg-subtle",
2956
+ children: [
2957
+ git.dirtyCount,
2958
+ " changed"
2959
+ ]
2960
+ }
2961
+ )
2962
+ ] });
2963
+ }
2964
+ function Segmented({
2965
+ options,
2966
+ value,
2967
+ onChange
2968
+ }) {
2969
+ return /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap items-center rounded-og-sm border border-og-border p-0.5", children: options.map((opt) => /* @__PURE__ */ jsx3(
2970
+ "button",
2971
+ {
2972
+ type: "button",
2973
+ onClick: () => onChange(opt.value),
2974
+ className: cn(
2975
+ "min-h-7 rounded-og-xs px-1.5 py-0.5 text-og-xs focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent max-[1023px]:min-h-11 max-[1023px]:min-w-11 pointer-coarse:min-h-11 pointer-coarse:min-w-11",
2976
+ opt.value === value ? "bg-og-accent-soft text-og-fg" : "text-og-fg-subtle hover:text-og-fg"
2977
+ ),
2978
+ children: opt.label
2979
+ },
2980
+ opt.value
2981
+ )) });
2982
+ }
2983
+ function useFileView(path, readFile, reloadRevision = 0) {
2984
+ const previousPathRef = useRef3(null);
2985
+ const [state, setState] = useState4({
2986
+ content: null,
2987
+ isBinary: false,
2988
+ truncated: false,
2989
+ sizeBytes: null,
2990
+ loading: false,
2991
+ error: null
2992
+ });
2993
+ useEffect5(() => {
2994
+ if (!path) {
2995
+ previousPathRef.current = null;
2996
+ setState({
2997
+ content: null,
2998
+ isBinary: false,
2999
+ truncated: false,
3000
+ sizeBytes: null,
3001
+ loading: false,
3002
+ error: null
3003
+ });
3004
+ return;
3005
+ }
3006
+ const pathChanged = previousPathRef.current !== path;
3007
+ previousPathRef.current = path;
3008
+ let cancelled = false;
3009
+ const abort = new AbortController();
3010
+ if (pathChanged) {
3011
+ setState({
3012
+ content: null,
3013
+ isBinary: false,
3014
+ truncated: false,
3015
+ sizeBytes: null,
3016
+ loading: true,
3017
+ error: null
3018
+ });
3019
+ } else {
3020
+ setState((previous) => ({ ...previous, error: null }));
3021
+ }
3022
+ void readFile(path, { signal: abort.signal }).then((res) => {
3023
+ if (cancelled) return;
3024
+ const content = res.isBinary ? null : res.encoding === "base64" ? decodeBase64Utf8(res.content) : res.content;
3025
+ setState({
3026
+ content,
3027
+ imageUrl: !res.truncated && res.encoding === "base64" ? rasterImageUrl(path, res.content) : null,
3028
+ isBinary: res.isBinary,
3029
+ truncated: res.truncated,
3030
+ sizeBytes: res.sizeBytes,
3031
+ loading: false,
3032
+ error: null
3033
+ });
3034
+ }).catch((cause) => {
3035
+ if (cancelled) return;
3036
+ const error = cause instanceof Error ? cause : new Error(String(cause));
3037
+ setState(
3038
+ (previous) => pathChanged ? {
3039
+ content: null,
3040
+ isBinary: false,
3041
+ truncated: false,
3042
+ sizeBytes: null,
3043
+ loading: false,
3044
+ error
3045
+ } : { ...previous, loading: false, error }
3046
+ );
3047
+ });
3048
+ return () => {
3049
+ cancelled = true;
3050
+ abort.abort();
3051
+ };
3052
+ }, [path, readFile, reloadRevision]);
3053
+ return state;
3054
+ }
3055
+ function rasterImageUrl(path, content) {
3056
+ const extension = path.split(".").pop()?.toLowerCase();
3057
+ const mime = extension === "png" ? "image/png" : extension === "jpg" || extension === "jpeg" ? "image/jpeg" : extension === "gif" ? "image/gif" : extension === "webp" ? "image/webp" : null;
3058
+ return mime ? `data:${mime};base64,${content}` : null;
3059
+ }
3060
+ function RasterFilePreview({ src, path }) {
3061
+ const [failed, setFailed] = useState4(false);
3062
+ return failed ? /* @__PURE__ */ jsxs2(Notice, { title: "Image preview unavailable", announce: "alert", children: [
3063
+ "Could not decode ",
3064
+ path,
3065
+ " as an image."
3066
+ ] }) : /* @__PURE__ */ jsx3(
3067
+ "img",
3068
+ {
3069
+ src,
3070
+ alt: path,
3071
+ onError: () => setFailed(true),
3072
+ className: "max-w-full object-contain"
3073
+ }
3074
+ );
3075
+ }
3076
+ function decodeBase64Utf8(b64) {
3077
+ try {
3078
+ if (typeof atob === "function") {
3079
+ const binary = atob(b64);
3080
+ const bytes = new Uint8Array(binary.length);
3081
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
3082
+ return new TextDecoder().decode(bytes);
3083
+ }
3084
+ } catch {
3085
+ }
3086
+ return b64;
3087
+ }
3088
+ function Notice({
3089
+ children,
3090
+ className,
3091
+ icon,
3092
+ title,
3093
+ announce
3094
+ }) {
3095
+ return /* @__PURE__ */ jsx3(
3096
+ "div",
3097
+ {
3098
+ role: announce,
3099
+ "aria-atomic": announce ? "true" : void 0,
3100
+ "aria-live": announce === "alert" ? "assertive" : announce === "status" ? "polite" : void 0,
3101
+ className: cn(
3102
+ "flex h-full items-center justify-center p-4 text-center text-og-sm text-og-fg-subtle",
3103
+ className
3104
+ ),
3105
+ children: /* @__PURE__ */ jsxs2("div", { className: "flex max-w-sm flex-col items-center gap-2.5", children: [
3106
+ icon ? /* @__PURE__ */ jsx3("span", { className: "grid size-10 place-items-center rounded-og-lg border border-og-border bg-og-surface-1 text-og-fg-muted shadow-sm", children: icon }) : null,
3107
+ title ? /* @__PURE__ */ jsx3("p", { className: "font-medium text-og-fg", children: title }) : null,
3108
+ /* @__PURE__ */ jsx3("div", { "data-contrast-audited": true, className: "leading-5", children })
3109
+ ] })
3110
+ }
3111
+ );
3112
+ }
3113
+
3114
+ export {
3115
+ visibleFileTree,
3116
+ filePathVisibility,
3117
+ CapturedFileUnavailableError,
3118
+ FileWriteConflictError,
3119
+ useSandboxFiles,
3120
+ useUnicodeFallbackFonts,
3121
+ FileBrowser,
3122
+ PierreFile,
3123
+ SandboxFiles
3124
+ };
3125
+ //# sourceMappingURL=chunk-EGVHJKGJ.js.map