@marimo-team/islands 0.23.7-dev4 → 0.23.7-dev43

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 (514) hide show
  1. package/dist/{ConnectedDataExplorerComponent-PmilQqXR.js → ConnectedDataExplorerComponent-2lBNiUv6.js} +14 -14
  2. package/dist/{ErrorBoundary-Da4UeYxT.js → ErrorBoundary-D3wrPNma.js} +1 -1
  3. package/dist/{any-language-editor-BVR0l12r.js → any-language-editor-VWs_7v27.js} +15 -15
  4. package/dist/apl-Bdc61P1y.js +4 -0
  5. package/dist/{arc-CHF8PiiF.js → arc-DfkSnvZm.js} +2 -2
  6. package/dist/{architecture-7HQA4BMR-D0JB_3hE.js → architecture-7HQA4BMR-CS9jOrqM.js} +1 -1
  7. package/dist/{architectureDiagram-VXUJARFQ-BXQEUDtK.js → architectureDiagram-VXUJARFQ-CXVJxFhH.js} +16 -16
  8. package/dist/asciiarmor-DVRHDGzT.js +4 -0
  9. package/dist/asn1-BmuKfkfu.js +4 -0
  10. package/dist/assets/__vite-browser-external-CAdMKBac.js +1 -0
  11. package/dist/assets/worker-CpBbwbQo.js +73 -0
  12. package/dist/{blockDiagram-VD42YOAC-DhJe-Y9i.js → blockDiagram-VD42YOAC-DGDaxR8I.js} +11 -11
  13. package/dist/brainfuck-DPrRpyTV.js +4 -0
  14. package/dist/{button-CA5pI2YF.js → button-Dj4BTre0.js} +5 -0
  15. package/dist/{c4Diagram-YG6GDRKO-9dSfzOFR.js → c4Diagram-YG6GDRKO-C2hc6ne8.js} +5 -5
  16. package/dist/{capabilities-6laDasij.js → capabilities-C9rrYCzf.js} +1 -1
  17. package/dist/{channel-MqYIiKgS.js → channel-BBoIVUrJ.js} +1 -1
  18. package/dist/{chat-ui-B-gbqk_F.js → chat-ui-CufH8sfF.js} +626 -234
  19. package/dist/{check-CFM2mVDr.js → check-BcUIXnUT.js} +1 -1
  20. package/dist/{chunk-4BX2VUAB-BwfrWBqN.js → chunk-4BX2VUAB-CzXltWHN.js} +1 -1
  21. package/dist/{chunk-55IACEB6-D8THf2mi.js → chunk-55IACEB6-B-1mjMMC.js} +1 -1
  22. package/dist/{chunk-5FQGJX7Z-CO1e63h_.js → chunk-5FQGJX7Z-BOg95xG5.js} +2 -2
  23. package/dist/{chunk-ABZYJK2D-BrBb_0yY.js → chunk-ABZYJK2D-D0cLy8Bb.js} +2 -2
  24. package/dist/{chunk-ATLVNIR6-D-0XqNah.js → chunk-ATLVNIR6-BXsEjlHF.js} +2 -2
  25. package/dist/{chunk-B4BG7PRW-8iRKvugR.js → chunk-B4BG7PRW-Q1usn6T3.js} +7 -7
  26. package/dist/{chunk-CVBHYZKI-B6xhgaBd.js → chunk-CVBHYZKI-B_c5YBcW.js} +1 -1
  27. package/dist/{chunk-DI55MBZ5-C0_2D4m4.js → chunk-DI55MBZ5-D1qLYNrb.js} +6 -6
  28. package/dist/{chunk-EXTU4WIE-Jiw9ca1u.js → chunk-EXTU4WIE-BKNXdLmD.js} +2 -2
  29. package/dist/{chunk-FMBD7UC4-CHdus51S.js → chunk-FMBD7UC4-Ie8M9q0W.js} +1 -1
  30. package/dist/{chunk-HN2XXSSU-2Vfbq-kU.js → chunk-HN2XXSSU-E3n-Ys7Z.js} +1 -1
  31. package/dist/{chunk-JA3XYJ7Z-6wbaigKe.js → chunk-JA3XYJ7Z-D6c6cOBG.js} +3 -3
  32. package/dist/{chunk-JZLCHNYA-_rfptlUP.js → chunk-JZLCHNYA-BvsPHJmL.js} +6 -6
  33. package/dist/{chunk-MI3HLSF2-Do0-KRc0.js → chunk-MI3HLSF2-CUYEasXO.js} +1 -1
  34. package/dist/{chunk-N4CR4FBY-DIZG9dVD.js → chunk-N4CR4FBY-8ycT-O9a.js} +7 -7
  35. package/dist/{chunk-QN33PNHL-Cc64y40m.js → chunk-QN33PNHL-Bb-eUBW3.js} +2 -2
  36. package/dist/{chunk-QXUST7PY-BDG0-0Or.js → chunk-QXUST7PY-DV8yRwBd.js} +10 -10
  37. package/dist/{chunk-QZHKN3VN-B_Mdb8GC.js → chunk-QZHKN3VN-DRjXVwuJ.js} +1 -1
  38. package/dist/{chunk-S3R3BYOJ-DphMP0FA.js → chunk-S3R3BYOJ-mQeCz5CE.js} +4 -4
  39. package/dist/{chunk-TZMSLE5B-C9LUoYkc.js → chunk-TZMSLE5B-BqW10dHe.js} +3 -3
  40. package/dist/classDiagram-2ON5EDUG--Yh__LHb.js +30 -0
  41. package/dist/classDiagram-v2-WZHVMYZB-BC7X7Xtc.js +30 -0
  42. package/dist/{clike-sBZrGeF8.js → clike-DTxNUn7l.js} +1 -1
  43. package/dist/clojure-DEttQW5T.js +4 -0
  44. package/dist/cmake-jNlx_DaM.js +4 -0
  45. package/dist/cobol-BvvIm5MJ.js +4 -0
  46. package/dist/{code-block-37QAKDTI-0JNwiPGv.js → code-block-37QAKDTI-BsGy1AOJ.js} +1 -1
  47. package/dist/{code-visibility-zYxaYsuj.js → code-visibility-Cu7CFm0r.js} +573 -585
  48. package/dist/coffeescript-DTpBMyFU.js +4 -0
  49. package/dist/commonlisp-BmmUG8jb.js +4 -0
  50. package/dist/{copy-TGGAUEWp.js → copy-DLf4aN7I.js} +2 -2
  51. package/dist/{cose-bilkent-S5V4N54A-DXHZkJKX.js → cose-bilkent-S5V4N54A-kjoZoid4.js} +2 -2
  52. package/dist/crystal-BxyqmEWC.js +4 -0
  53. package/dist/css-BGoCtuG3.js +4 -0
  54. package/dist/cypher-BmCbdl3u.js +4 -0
  55. package/dist/d-CFrlbjZt.js +4 -0
  56. package/dist/{dagre-6UL2VRFP-tH87fkPA.js → dagre-6UL2VRFP-DRBWoQUw.js} +10 -10
  57. package/dist/{data-grid-overlay-editor-CWUN78-s.js → data-grid-overlay-editor-efe5ZagF.js} +2 -2
  58. package/dist/{diagram-PSM6KHXK-2VjPSCDn.js → diagram-PSM6KHXK-H66ATWP2.js} +18 -18
  59. package/dist/{diagram-QEK2KX5R-CiLmNyta.js → diagram-QEK2KX5R-DItl5Wns.js} +14 -14
  60. package/dist/{diagram-S2PKOQOG-Zha_1CLx.js → diagram-S2PKOQOG-CtuW_ZuL.js} +14 -14
  61. package/dist/diff-D6XwL6P8.js +4 -0
  62. package/dist/{dist-Brkazupz.js → dist--sWVZwjW.js} +1 -1
  63. package/dist/{dist-FN0ZA_8F.js → dist-21ButRCu.js} +1 -1
  64. package/dist/{dist-BetEKbPG.js → dist-B8RaFTRF.js} +1 -1
  65. package/dist/dist-BoHGySTM.js +5 -0
  66. package/dist/dist-ByAz19Qc.js +5 -0
  67. package/dist/dist-C93EysN4.js +5 -0
  68. package/dist/{dist-BHnX0ia_.js → dist-CY-lVor6.js} +1 -1
  69. package/dist/{dist-YP-G7W0f.js → dist-CYDuv4bR.js} +1 -1
  70. package/dist/{dist-CMjD5MQb.js → dist-Cfo5EE2t.js} +1 -1
  71. package/dist/dist-CjivSDvN.js +5 -0
  72. package/dist/dist-Cqwx-MH7.js +5 -0
  73. package/dist/{dist-ESg7xyoD.js → dist-D3ZI9nhS.js} +2 -2
  74. package/dist/{dist-DkC6YEo0.js → dist-DMZNjfX4.js} +1 -1
  75. package/dist/{dist-ChC1BhqM.js → dist-DbpcoFAV.js} +1 -1
  76. package/dist/dist-FUNenbiQ.js +5 -0
  77. package/dist/{dist-BEOU2g1b.js → dist-zhSud5X3.js} +1 -1
  78. package/dist/{dockerfile-COvlVLcE.js → dockerfile-twL37N91.js} +1 -1
  79. package/dist/dtd-Bw0lRN0-.js +4 -0
  80. package/dist/dylan-B55eBHTt.js +4 -0
  81. package/dist/ecl-C8G4p0wn.js +4 -0
  82. package/dist/eiffel-BmH46VJl.js +4 -0
  83. package/dist/elm-DhzeFqkl.js +4 -0
  84. package/dist/{erDiagram-Q2GNP2WA-biHZS05w.js → erDiagram-Q2GNP2WA--19X2kU5.js} +14 -14
  85. package/dist/erlang-CY-wdlsU.js +4 -0
  86. package/dist/{error-banner-DnBPzEWg.js → error-banner-CVkfBUT3.js} +2 -2
  87. package/dist/{esm-Dd1z1auZ.js → esm-CWp0KQeK.js} +1 -1
  88. package/dist/{esm-CYEyrE3Y.js → esm-DjNnlmpf.js} +96 -96
  89. package/dist/{extends-CzJgxo2J.js → extends-vAi97cpa.js} +4 -4
  90. package/dist/{factor-C2GT7jfQ.js → factor-CajWS6mS.js} +1 -1
  91. package/dist/factor-DWkgl0xw.js +4 -0
  92. package/dist/{flowDiagram-NV44I4VS-CWWlUpBR.js → flowDiagram-NV44I4VS-DQmWlo7f.js} +16 -16
  93. package/dist/{formats-CgaK7Gmx.js → formats-CpgZM9BM.js} +3 -3
  94. package/dist/forth-Cij_ie2t.js +4 -0
  95. package/dist/fortran-Br3X9cfm.js +4 -0
  96. package/dist/{ganttDiagram-JELNMOA3-D7B2c4Z9.js → ganttDiagram-JELNMOA3-BOGXJ8Lk.js} +7 -7
  97. package/dist/gas-DYsGcMN2.js +4 -0
  98. package/dist/gherkin-eVgXQ0fQ.js +4 -0
  99. package/dist/{gitGraph-G5XIXVHT-BdepdFa_.js → gitGraph-G5XIXVHT-DGlbae5m.js} +1 -1
  100. package/dist/{gitGraphDiagram-V2S2FVAM-CtLvNR1S.js → gitGraphDiagram-V2S2FVAM-DjzxfF0P.js} +14 -14
  101. package/dist/{glide-data-editor-CvlvtPWJ.js → glide-data-editor-BK9s_dqy.js} +13 -13
  102. package/dist/groovy-_NFHIXG7.js +4 -0
  103. package/dist/haskell-D6xNG_bH.js +4 -0
  104. package/dist/haxe-sU_rzAwn.js +5 -0
  105. package/dist/{html-to-image-hMMPiNe_.js → html-to-image-DxWM1HVj.js} +2395 -2301
  106. package/dist/idl-Ds_VbrUx.js +4 -0
  107. package/dist/{info-VBDWY6EO--JNA2rNu.js → info-VBDWY6EO-D2lvLLw5.js} +1 -1
  108. package/dist/{infoDiagram-HS3SLOUP-BbZyOxsP.js → infoDiagram-HS3SLOUP-ChNufFsP.js} +12 -12
  109. package/dist/{input-BAOe64zx.js → input-Cc1Vvw9A.js} +6 -6
  110. package/dist/javascript-CztfIl0i.js +4 -0
  111. package/dist/{journeyDiagram-XKPGCS4Q-BU2mjjzl.js → journeyDiagram-XKPGCS4Q-BO_O4Ij1.js} +6 -6
  112. package/dist/julia-DDv40QMV.js +4 -0
  113. package/dist/{kanban-definition-3W4ZIXB7-BlmczUuw.js → kanban-definition-3W4ZIXB7-CPpiiiWk.js} +11 -11
  114. package/dist/{katex-qPqrBHZ8.js → katex-9-9QRhxz.js} +1 -1
  115. package/dist/{label-BCWi-Oqu.js → label-BLqV33b1.js} +2 -2
  116. package/dist/{line-BWRi3U3S.js → line-C5s_12ee.js} +3 -3
  117. package/dist/{linear-DnHwODZa.js → linear-2NnK4cxi.js} +2 -2
  118. package/dist/livescript-BEOngLLc.js +4 -0
  119. package/dist/{loader-BvW0-YWZ.js → loader-Dr8Qem8p.js} +1 -1
  120. package/dist/lua-9-7BhQ4Y.js +4 -0
  121. package/dist/main.js +1175 -1142
  122. package/dist/mathematica-DDa0Pfxm.js +4 -0
  123. package/dist/mbox-iO03mmoE.js +4 -0
  124. package/dist/{mermaid-4DMBBIKO-CG1ECj5W.js → mermaid-4DMBBIKO-B7VQMwJx.js} +1 -1
  125. package/dist/{mermaid-CEbzCxCc.js → mermaid-DO-Daq7u.js} +46 -46
  126. package/dist/{mermaid-parser.core-CleJseNW.js → mermaid-parser.core-DreccfmS.js} +7 -7
  127. package/dist/{mhchem-BwoRNwg_.js → mhchem-yiCCuiEF.js} +1 -1
  128. package/dist/{mindmap-definition-VGOIOE7T-CcSYqYP9.js → mindmap-definition-VGOIOE7T-CC1_Vl0f.js} +13 -13
  129. package/dist/mirc-C9z5LT4X.js +4 -0
  130. package/dist/mllike-jGJbdm_C.js +6 -0
  131. package/dist/modelica-DzF7oIEL.js +4 -0
  132. package/dist/mscgen-DB-u125o.js +6 -0
  133. package/dist/mumps-CRTFHhzh.js +4 -0
  134. package/dist/nsis-C4NPTuox.js +4 -0
  135. package/dist/{nsis-B5K1qoyo.js → nsis-ClF3r5Tr.js} +1 -1
  136. package/dist/ntriples-BCOoGph1.js +4 -0
  137. package/dist/{number-overlay-editor-_GnlYFHC.js → number-overlay-editor-CpKi64Fy.js} +1 -1
  138. package/dist/octave-DTwNlazz.js +4 -0
  139. package/dist/{ordinal-2jIulmcR.js → ordinal-B43ZeR68.js} +1 -1
  140. package/dist/oz-DD38AzSz.js +4 -0
  141. package/dist/{packet-DYOGHKS2-CBxXGWNr.js → packet-DYOGHKS2-CmWtF3uO.js} +1 -1
  142. package/dist/pascal-BohSp9jV.js +4 -0
  143. package/dist/perl-f5OutoPM.js +4 -0
  144. package/dist/{pie-VRWISCQL-Bmdnqjip.js → pie-VRWISCQL-B6u8vus8.js} +1 -1
  145. package/dist/{pieDiagram-ADFJNKIX-DNyLF5H2.js → pieDiagram-ADFJNKIX-Di34MOFQ.js} +19 -19
  146. package/dist/pig-Dv7wSmHb.js +4 -0
  147. package/dist/powershell-rYgjKB39.js +4 -0
  148. package/dist/{process-output-Bza_GK7Q.js → process-output-DBYxXdrN.js} +30 -25
  149. package/dist/properties-BFUNLRDN.js +4 -0
  150. package/dist/protobuf-B9QJQPPv.js +4 -0
  151. package/dist/{pug-tjbzJCFk.js → pug-B_rby2yb.js} +1 -1
  152. package/dist/pug-DzvWpaMC.js +4 -0
  153. package/dist/puppet-B_K-n_xK.js +4 -0
  154. package/dist/python-CAiFcaA2.js +4 -0
  155. package/dist/q-cLeFIBLK.js +4 -0
  156. package/dist/{quadrantDiagram-AYHSOK5B-rXwjifrj.js → quadrantDiagram-AYHSOK5B-B9kVk1ny.js} +3 -3
  157. package/dist/r-04Y-Wco3.js +4 -0
  158. package/dist/{radar-ZZBFDIW7-BmCWDffL.js → radar-ZZBFDIW7-XAmXSa8s.js} +1 -1
  159. package/dist/{react-vega-B-rkEqtS.js → react-vega-Cavbrg4l.js} +1 -1
  160. package/dist/{react-vega-k9ODWPlI.js → react-vega-Dh6-UKKe.js} +13 -13
  161. package/dist/{requirementDiagram-UZGBJVZJ-DBdrMVbs.js → requirementDiagram-UZGBJVZJ-BxGfGYEx.js} +13 -13
  162. package/dist/{reveal-component-h0_DDpxE.js → reveal-component-CSA3g_zD.js} +10 -10
  163. package/dist/rpm-FUdrIia9.js +5 -0
  164. package/dist/ruby-DMjFXuEW.js +4 -0
  165. package/dist/{sankeyDiagram-TZEHDZUN-CxmzalGv.js → sankeyDiagram-TZEHDZUN-D09PBJ-n.js} +4 -4
  166. package/dist/sas-DzHZxjXK.js +4 -0
  167. package/dist/scheme-DxHd_Rb9.js +4 -0
  168. package/dist/semaphore-CNDGTzkX.js +46 -0
  169. package/dist/{sequenceDiagram-WL72ISMW-CVCDsJ9h.js → sequenceDiagram-WL72ISMW-t_Dpemj0.js} +7 -7
  170. package/dist/shell-C8Kwypgf.js +4 -0
  171. package/dist/sieve-DdyqOKXZ.js +4 -0
  172. package/dist/smalltalk-pB7X1D9y.js +4 -0
  173. package/dist/sparql-NhBO6oOa.js +4 -0
  174. package/dist/{spec-DSIuqd3f.js → spec-hVaaZsY5.js} +4 -4
  175. package/dist/{src-BY0BGg6V.js → src-Bf2iLOlr.js} +1 -1
  176. package/dist/{stateDiagram-FKZM4ZOC-D_2djEhW.js → stateDiagram-FKZM4ZOC-B18gTP_j.js} +16 -16
  177. package/dist/stateDiagram-v2-4FDKWEC3-B6e_t14A.js +29 -0
  178. package/dist/{step-DGAGWg3y.js → step-CWipAYTY.js} +1 -1
  179. package/dist/{strings-B_FOH6eV.js → strings-BiIhGaI8.js} +4 -4
  180. package/dist/style.css +1 -1
  181. package/dist/stylus-SfWSnzPv.js +4 -0
  182. package/dist/swift-jRPdq2zR.js +4 -0
  183. package/dist/{swiper-component-KkEVUDd3.js → swiper-component-DlD2GU2g.js} +2 -2
  184. package/dist/tcl-_hpTHGX3.js +4 -0
  185. package/dist/textile-C9h8slqH.js +4 -0
  186. package/dist/{time-CMdrp3hw.js → time-C1SGcFMH.js} +2 -2
  187. package/dist/{timeline-definition-IT6M3QCI-E4NzxCs3.js → timeline-definition-IT6M3QCI-DJnh1ks5.js} +3 -3
  188. package/dist/{toDate-CHtl9vts.js → toDate-CJWlVNGD.js} +3 -3
  189. package/dist/toml-DWvtinD4.js +4 -0
  190. package/dist/{tooltip-B0mtKTXm.js → tooltip-DRaMBu06.js} +3 -3
  191. package/dist/{treemap-GDKQZRPO-CoKHPxa7.js → treemap-GDKQZRPO-Du95DV6u.js} +1 -1
  192. package/dist/troff-Dwo_A0y7.js +4 -0
  193. package/dist/ttcn-V--CPFKq.js +4 -0
  194. package/dist/ttcn-cfg-CPSMchTG.js +4 -0
  195. package/dist/turtle-B4rPGBWu.js +4 -0
  196. package/dist/{types-DBtDeUKD.js → types-Dzuoc3LN.js} +1 -1
  197. package/dist/{useAsyncData-B6hCGywC.js → useAsyncData-C56Khv_R.js} +1 -1
  198. package/dist/{useDateFormatter-B3mCQMP3.js → useDateFormatter-B_9k85Ex.js} +2 -2
  199. package/dist/{useDeepCompareMemoize-CmwDuYUH.js → useDeepCompareMemoize-Dt98v2ua.js} +1 -1
  200. package/dist/{useIframeCapabilities-DbdLoEDm.js → useIframeCapabilities-BkYHTrss.js} +1 -1
  201. package/dist/{useLifecycle-CjMjllqy.js → useLifecycle-BF6-z62y.js} +3 -3
  202. package/dist/{useTheme-CByZUW0p.js → useTheme-DykuNHR2.js} +2 -2
  203. package/dist/vb-DaMBBd4j.js +4 -0
  204. package/dist/vbscript-BMJQqcE2.js +4 -0
  205. package/dist/{vega-component-CC8TqWWV.js → vega-component-BtvQ-Kc4.js} +26 -24
  206. package/dist/velocity-CGq2QRq2.js +4 -0
  207. package/dist/verilog-CUNo8F5u.js +4 -0
  208. package/dist/vhdl-CCzA0msW.js +4 -0
  209. package/dist/webidl-CqIMDIBL.js +4 -0
  210. package/dist/xquery-XC5Kbr-1.js +4 -0
  211. package/dist/{xychartDiagram-PRI3JC2R-CuxTvjw5.js → xychartDiagram-PRI3JC2R-Dk2d_bX0.js} +10 -10
  212. package/dist/yacas-CGOv7Dzy.js +4 -0
  213. package/dist/z80-CXhVmi-f.js +4 -0
  214. package/dist/{zod-BxdsqRPd.js → zod-BWkcDORu.js} +1 -1
  215. package/package.json +3 -3
  216. package/src/components/chat/chat-components.tsx +47 -0
  217. package/src/components/chat/chat-display.tsx +41 -7
  218. package/src/components/chat/chat-panel.tsx +37 -10
  219. package/src/components/chat/chat-utils.ts +42 -20
  220. package/src/components/chat/reasoning-accordion.tsx +14 -3
  221. package/src/components/chat/tool-call/shared.ts +13 -0
  222. package/src/components/chat/tool-call/tool-approval-card.tsx +62 -0
  223. package/src/components/chat/tool-call/tool-args.tsx +26 -0
  224. package/src/components/chat/tool-call/tool-call-view.tsx +99 -0
  225. package/src/components/chat/tool-call/tool-error-card.tsx +81 -0
  226. package/src/components/chat/tool-call/tool-history-row.tsx +153 -0
  227. package/src/components/chat/tool-call/tool-result.tsx +101 -0
  228. package/src/components/data-table/TableTopBar.tsx +5 -1
  229. package/src/components/data-table/data-table.tsx +5 -0
  230. package/src/components/data-table/download-policy/atoms.ts +10 -0
  231. package/src/components/data-table/export-actions.tsx +31 -4
  232. package/src/components/editor/actions/pair-with-agent-modal.tsx +140 -49
  233. package/src/components/editor/actions/useNotebookActions.tsx +3 -1
  234. package/src/components/editor/app-container.tsx +7 -1
  235. package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +10 -2
  236. package/src/components/editor/chrome/wrapper/app-chrome.tsx +1 -0
  237. package/src/components/editor/chrome/wrapper/footer.tsx +4 -1
  238. package/src/components/editor/chrome/wrapper/panels.tsx +4 -1
  239. package/src/components/editor/chrome/wrapper/sidebar.tsx +4 -1
  240. package/src/components/editor/controls/Controls.tsx +11 -3
  241. package/src/components/editor/file-tree/requesting-tree.tsx +27 -25
  242. package/src/components/editor/file-tree/upload.tsx +23 -24
  243. package/src/components/editor/header/__tests__/status.test.tsx +108 -0
  244. package/src/components/editor/header/status.tsx +44 -10
  245. package/src/components/editor/navigation/__tests__/clipboard.test.ts +106 -0
  246. package/src/components/editor/navigation/__tests__/navigation.test.ts +70 -0
  247. package/src/components/editor/navigation/clipboard.ts +99 -25
  248. package/src/components/editor/navigation/navigation.ts +15 -1
  249. package/src/components/editor/notebook-cell.tsx +3 -0
  250. package/src/components/home/components.tsx +6 -0
  251. package/src/components/pages/run-page.tsx +4 -1
  252. package/src/core/ai/tools/__tests__/registry.test.ts +10 -12
  253. package/src/core/ai/tools/registry.ts +9 -5
  254. package/src/core/cells/__tests__/cells.test.ts +187 -0
  255. package/src/core/cells/__tests__/pending-cut-service.test.tsx +123 -0
  256. package/src/core/cells/cells.ts +102 -17
  257. package/src/core/cells/document-changes.ts +6 -1
  258. package/src/core/cells/pending-cut-service.ts +55 -0
  259. package/src/core/cells/utils.ts +11 -0
  260. package/src/core/codemirror/cells/extensions.ts +10 -0
  261. package/src/core/codemirror/markdown/__tests__/commands.test.ts +3 -3
  262. package/src/core/codemirror/markdown/commands.ts +1 -2
  263. package/src/core/edit-app.tsx +2 -1
  264. package/src/core/hotkeys/hotkeys.ts +5 -0
  265. package/src/core/islands/worker/worker.tsx +3 -2
  266. package/src/core/network/requests-network.ts +21 -3
  267. package/src/core/network/types.ts +12 -1
  268. package/src/core/run-app.tsx +2 -1
  269. package/src/core/wasm/__tests__/utils.test.ts +34 -0
  270. package/src/core/wasm/bridge.ts +14 -1
  271. package/src/core/wasm/utils.ts +14 -0
  272. package/src/core/wasm/worker/bootstrap.ts +3 -2
  273. package/src/core/wasm/worker/worker.ts +3 -2
  274. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +155 -0
  275. package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +137 -0
  276. package/src/core/websocket/transports/basic.ts +2 -0
  277. package/src/core/websocket/transports/transport.ts +1 -0
  278. package/src/core/websocket/useMarimoKernelConnection.tsx +130 -55
  279. package/src/core/websocket/useWebSocket.tsx +5 -2
  280. package/src/css/app/Cell.css +10 -0
  281. package/src/plugins/impl/DataTablePlugin.tsx +12 -0
  282. package/src/plugins/impl/TabsPlugin.tsx +35 -7
  283. package/src/plugins/impl/__tests__/TabsPlugin.test.tsx +154 -0
  284. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +6 -0
  285. package/src/plugins/impl/vega/resolve-data.ts +8 -1
  286. package/src/utils/__tests__/id-tree.test.ts +71 -0
  287. package/src/utils/__tests__/semaphore.test.ts +218 -0
  288. package/src/utils/fileToBase64.ts +8 -7
  289. package/src/utils/id-tree.tsx +89 -0
  290. package/src/utils/semaphore.ts +88 -0
  291. package/dist/apl-BKoVld9y.js +0 -4
  292. package/dist/asciiarmor-DQrKIjoo.js +0 -4
  293. package/dist/asn1-BZvnj0dq.js +0 -4
  294. package/dist/assets/__vite-browser-external-rrUYDKRl.js +0 -1
  295. package/dist/assets/worker-Bfy15ViQ.js +0 -73
  296. package/dist/brainfuck-D558nlUv.js +0 -4
  297. package/dist/classDiagram-2ON5EDUG-CBHMR6ZU.js +0 -30
  298. package/dist/classDiagram-v2-WZHVMYZB-BsUtUGM_.js +0 -30
  299. package/dist/clojure-Cq8mTSrE.js +0 -4
  300. package/dist/cmake-D8HCovWK.js +0 -4
  301. package/dist/cobol-UolN-9iU.js +0 -4
  302. package/dist/coffeescript-VdNuWrt5.js +0 -4
  303. package/dist/commonlisp-ALX7fpDc.js +0 -4
  304. package/dist/crystal-PbyO9Q_s.js +0 -4
  305. package/dist/css-DFklJkr_.js +0 -4
  306. package/dist/cypher-BifNeYlv.js +0 -4
  307. package/dist/d-BA-JP4PJ.js +0 -4
  308. package/dist/diff-CtkDpav4.js +0 -4
  309. package/dist/dist-BuBwsFva.js +0 -5
  310. package/dist/dist-BzmEQ9u7.js +0 -5
  311. package/dist/dist-Cih01ssx.js +0 -5
  312. package/dist/dist-CqfONiY9.js +0 -5
  313. package/dist/dist-D0iD0Fi9.js +0 -5
  314. package/dist/dist-DtNLXm8d.js +0 -5
  315. package/dist/dtd-DW3_UFEG.js +0 -4
  316. package/dist/dylan-pDhodO2N.js +0 -4
  317. package/dist/ecl-BJT8-YD7.js +0 -4
  318. package/dist/eiffel-Dmns-9vS.js +0 -4
  319. package/dist/elm-Da4sO4Bz.js +0 -4
  320. package/dist/erlang-C-zBsDi7.js +0 -4
  321. package/dist/factor-4xPWlWB5.js +0 -4
  322. package/dist/forth-l-c75zSd.js +0 -4
  323. package/dist/fortran-DIujSODW.js +0 -4
  324. package/dist/gas-CXnG5g_b.js +0 -4
  325. package/dist/gherkin-VPeqd4-X.js +0 -4
  326. package/dist/groovy-CphhZQgg.js +0 -4
  327. package/dist/haskell-CCvlS5Iq.js +0 -4
  328. package/dist/haxe-C_bi66fP.js +0 -5
  329. package/dist/idl-1DcP4Dm8.js +0 -4
  330. package/dist/javascript-DUIGhBvO.js +0 -4
  331. package/dist/julia-Cs2G4PQi.js +0 -4
  332. package/dist/livescript-DMtVFaAN.js +0 -4
  333. package/dist/lua-BAoLtdJg.js +0 -4
  334. package/dist/mathematica-C_NoFtbo.js +0 -4
  335. package/dist/mbox-DcFJFYrH.js +0 -4
  336. package/dist/mirc-71dccf_u.js +0 -4
  337. package/dist/mllike-CWcOFVDq.js +0 -6
  338. package/dist/modelica-Ape2VXxx.js +0 -4
  339. package/dist/mscgen-Cc6TwbSN.js +0 -6
  340. package/dist/mumps-h-ZbdkJ9.js +0 -4
  341. package/dist/nsis-C0p3m7JW.js +0 -4
  342. package/dist/ntriples-c9lEeT5w.js +0 -4
  343. package/dist/octave-DzEgB_74.js +0 -4
  344. package/dist/oz-CAxvHkyQ.js +0 -4
  345. package/dist/pascal-BJzu1sgP.js +0 -4
  346. package/dist/perl--IrOzZ2Z.js +0 -4
  347. package/dist/pig-CiBKKNhC.js +0 -4
  348. package/dist/powershell-KY0j6Qop.js +0 -4
  349. package/dist/properties-BW8q3ziV.js +0 -4
  350. package/dist/protobuf-BGaeuTGV.js +0 -4
  351. package/dist/pug-DjOKK-4J.js +0 -4
  352. package/dist/puppet-DWm2o6zX.js +0 -4
  353. package/dist/python-Bp2gezZy.js +0 -4
  354. package/dist/q-DljPshos.js +0 -4
  355. package/dist/r-BajPMnEu.js +0 -4
  356. package/dist/rpm-BKx-ZZ62.js +0 -5
  357. package/dist/ruby-DJq_HNKc.js +0 -4
  358. package/dist/sas-WANvpcOU.js +0 -4
  359. package/dist/scheme-CliBbhGF.js +0 -4
  360. package/dist/shell-BwhrNUvM.js +0 -4
  361. package/dist/sieve-BIVePvMp.js +0 -4
  362. package/dist/smalltalk-D6G48JmY.js +0 -4
  363. package/dist/sparql-jjc3BmEP.js +0 -4
  364. package/dist/stateDiagram-v2-4FDKWEC3-Cv9Av10H.js +0 -29
  365. package/dist/stylus-WPBPQ4PE.js +0 -4
  366. package/dist/swift-O1Qy6iCm.js +0 -4
  367. package/dist/tcl-BAFdhvsi.js +0 -4
  368. package/dist/textile-DFuzhNLG.js +0 -4
  369. package/dist/toml-DRSTeely.js +0 -4
  370. package/dist/troff-B_ZjwBW0.js +0 -4
  371. package/dist/ttcn-CAyiB3ic.js +0 -4
  372. package/dist/ttcn-cfg-BS5_BGBJ.js +0 -4
  373. package/dist/turtle-CUBEDy3E.js +0 -4
  374. package/dist/vb-DY9S6-U2.js +0 -4
  375. package/dist/vbscript-gaHC39Jq.js +0 -4
  376. package/dist/velocity-TfCOtJZ_.js +0 -4
  377. package/dist/verilog-c2JOX8mv.js +0 -4
  378. package/dist/vhdl-dHBirRiO.js +0 -4
  379. package/dist/webidl-Bauj-i07.js +0 -4
  380. package/dist/xquery-CtaEAOt8.js +0 -4
  381. package/dist/yacas-BZ85agQP.js +0 -4
  382. package/dist/z80-hCgR-L4U.js +0 -4
  383. package/src/components/chat/tool-call-accordion.tsx +0 -247
  384. /package/dist/{ImageComparisonComponent-DaocPIse.js → ImageComparisonComponent-CNHIsPDj.js} +0 -0
  385. /package/dist/{Plot-PIeIvFnD.js → Plot-4wn-lMVn.js} +0 -0
  386. /package/dist/{apl-Dt8GMXYg.js → apl-BCgCq9iM.js} +0 -0
  387. /package/dist/{array-B-MVxRIF.js → array-tvvEqPy7.js} +0 -0
  388. /package/dist/{asciiarmor-CitDQ85h.js → asciiarmor-BtqU-KJQ.js} +0 -0
  389. /package/dist/{asn1-abrf9SMK.js → asn1-Dmb-dTMx.js} +0 -0
  390. /package/dist/{asterisk-BUZwqih-.js → asterisk-DaVJJDnV.js} +0 -0
  391. /package/dist/{brainfuck-BL-Boof0.js → brainfuck-C1HoZKlE.js} +0 -0
  392. /package/dist/{chunk-4F5CHEZ2-C6tO9vjs.js → chunk-4F5CHEZ2-BZq7Kom7.js} +0 -0
  393. /package/dist/{chunk-B2363JML-Ds8wZXyP.js → chunk-B2363JML-D9-XOau1.js} +0 -0
  394. /package/dist/{chunk-DR5Q36YT-CP69aZS_.js → chunk-DR5Q36YT-BflwErH1.js} +0 -0
  395. /package/dist/{chunk-FRFDVMJY-BgQv1HBE.js → chunk-FRFDVMJY-BSBUAX7r.js} +0 -0
  396. /package/dist/{chunk-PL6DKKU2-DHfTUHy8.js → chunk-PL6DKKU2-B0MTXvyc.js} +0 -0
  397. /package/dist/{chunk-SJTYNZTY-Diciw4sx.js → chunk-SJTYNZTY-CEG4F0pB.js} +0 -0
  398. /package/dist/{chunk-TQ3KTPDO-CQfP9npd.js → chunk-TQ3KTPDO-DiCtqVSi.js} +0 -0
  399. /package/dist/{chunk-UMXZTB3W-MSKeGL7W.js → chunk-UMXZTB3W-97iS1iEl.js} +0 -0
  400. /package/dist/{click-outside-container-BZgN7xS_.js → click-outside-container-BDd67_1U.js} +0 -0
  401. /package/dist/{clike-RWg7anhx.js → clike-CdT0yHjt.js} +0 -0
  402. /package/dist/{clojure-DaojKHow.js → clojure-CdyrCpUv.js} +0 -0
  403. /package/dist/{cmake-DN-_v0XE.js → cmake-BFlPxym7.js} +0 -0
  404. /package/dist/{cobol-C3VpMyux.js → cobol-CcJXewp8.js} +0 -0
  405. /package/dist/{coffeescript-DIkz3Tbt.js → coffeescript-DnKuIKRo.js} +0 -0
  406. /package/dist/{colors-Cn2p_FA3.js → colors-CQAOa8cK.js} +0 -0
  407. /package/dist/{common-keywords-hbLeU7VU.js → common-keywords-FBrXPTcz.js} +0 -0
  408. /package/dist/{commonlisp-CB1boOiP.js → commonlisp-B-kok83Z.js} +0 -0
  409. /package/dist/{crystal-DI2oCml6.js → crystal-FYRYjI1I.js} +0 -0
  410. /package/dist/{css-BdEVwQDV.js → css-B45lc2V3.js} +0 -0
  411. /package/dist/{cypher-BNHToqxU.js → cypher-DZMLyVY_.js} +0 -0
  412. /package/dist/{cytoscape.esm-WbbDoCfu.js → cytoscape.esm-ayF70frT.js} +0 -0
  413. /package/dist/{d-D7we7I1b.js → d-x-VVT4o9.js} +0 -0
  414. /package/dist/{diff-Cia6fzjN.js → diff-Dxe2mpXk.js} +0 -0
  415. /package/dist/{dist-BK-3fF4P.js → dist-B4LJpMEg.js} +0 -0
  416. /package/dist/{dist-CxdUraQr.js → dist-B507mf_I.js} +0 -0
  417. /package/dist/{dist-C89sHDXk.js → dist-BGdYVvOu.js} +0 -0
  418. /package/dist/{dist-DquyVv5H.js → dist-BNyrZfqT.js} +0 -0
  419. /package/dist/{dist-Zn0KNbo9.js → dist-Bc5pmZIw.js} +0 -0
  420. /package/dist/{dist-C-J0pt5p.js → dist-BvCfQQQE.js} +0 -0
  421. /package/dist/{dist-D9r7Cmw7.js → dist-C2ej4eOH.js} +0 -0
  422. /package/dist/{dist-HVuryI1a.js → dist-C34oIrQ9.js} +0 -0
  423. /package/dist/{dist-CGLzXdrt.js → dist-CDFZi-QD.js} +0 -0
  424. /package/dist/{dist-C9fmTOin.js → dist-CYEylvZA.js} +0 -0
  425. /package/dist/{dist-DadjmS-4.js → dist-DJ6zJQZ4.js} +0 -0
  426. /package/dist/{dist-CtCY55Jf.js → dist-Dh3wkoyH.js} +0 -0
  427. /package/dist/{dist-C474qFoq.js → dist-Dhk6FMb0.js} +0 -0
  428. /package/dist/{dist-DZjQ_MBo.js → dist-KnujRhFL.js} +0 -0
  429. /package/dist/{dist-CinA9Enb.js → dist-WdPUFc56.js} +0 -0
  430. /package/dist/{dist-DBLeRrPp.js → dist-t_qL7eB8.js} +0 -0
  431. /package/dist/{dist-CyFFzJTb.js → dist-usPCDYx8.js} +0 -0
  432. /package/dist/{dtd-H4Hubdwp.js → dtd-C9VM_Wfu.js} +0 -0
  433. /package/dist/{duckdb-keywords-CZ_ZTscu.js → duckdb-keywords-CvJhR_Yd.js} +0 -0
  434. /package/dist/{dylan-fVO6rnq3.js → dylan-DTSnEIFO.js} +0 -0
  435. /package/dist/{ebnf-WEXPLEWb.js → ebnf-2D4Ctp3y.js} +0 -0
  436. /package/dist/{ecl-B94VPjNR.js → ecl-N04ptnRK.js} +0 -0
  437. /package/dist/{eiffel-C_R6TusS.js → eiffel-Dd8rpqr_.js} +0 -0
  438. /package/dist/{elm-DzCHbO2g.js → elm-GT2E866W.js} +0 -0
  439. /package/dist/{erlang-BGNkx6JU.js → erlang-Cf0Bp5pY.js} +0 -0
  440. /package/dist/{esm-Bb_hbWan.js → esm-BaaaPNGl.js} +0 -0
  441. /package/dist/{fcl-B_Gv5Jfx.js → fcl-Ccj8Z5Xd.js} +0 -0
  442. /package/dist/{forth-Bybw0cJ7.js → forth-wd_XzGTg.js} +0 -0
  443. /package/dist/{fortran-C6PoCLkI.js → fortran-DcwUTZFe.js} +0 -0
  444. /package/dist/{gas-BBlhenj4.js → gas-DeALIER3.js} +0 -0
  445. /package/dist/{gherkin-NXtNG85X.js → gherkin-CKTqaJNX.js} +0 -0
  446. /package/dist/{groovy-BoFYK9xM.js → groovy-Bwdp_d8D.js} +0 -0
  447. /package/dist/{haskell-BtBdvQ1n.js → haskell-DCdCcPLK.js} +0 -0
  448. /package/dist/{haxe-D--o6dr0.js → haxe-DAyktQWJ.js} +0 -0
  449. /package/dist/{http-Dc2fv19V.js → http-_DVAYWoR.js} +0 -0
  450. /package/dist/{idl-AqTq5l7e.js → idl-CBuZiRYu.js} +0 -0
  451. /package/dist/{init-D-g0ONX1.js → init-uv0kkh4g.js} +0 -0
  452. /package/dist/{javascript-DvwNVye9.js → javascript-DzigE11c.js} +0 -0
  453. /package/dist/{julia-DoKiagZC.js → julia-PwfB-0Cm.js} +0 -0
  454. /package/dist/{katex-B7pMJpE0.js → katex-C_XRmjAP.js} +0 -0
  455. /package/dist/{livescript-DxBZMiWB.js → livescript-BJLz1EbT.js} +0 -0
  456. /package/dist/{lua-DmS_0NTu.js → lua-ZC-XC2jf.js} +0 -0
  457. /package/dist/{math-BYK36kWZ.js → math-DFcdCCU8.js} +0 -0
  458. /package/dist/{mathematica-ChlDFeIC.js → mathematica-DCYMx6qB.js} +0 -0
  459. /package/dist/{mbox-CguZuODr.js → mbox-OxMK_9XI.js} +0 -0
  460. /package/dist/{mirc-CFtY8dqz.js → mirc-nJVyhA0H.js} +0 -0
  461. /package/dist/{mllike-C0EJrEOk.js → mllike-DRO89bsU.js} +0 -0
  462. /package/dist/{modelica-C1kO1nfS.js → modelica-Don3E6ZD.js} +0 -0
  463. /package/dist/{mscgen-DEYdr7AY.js → mscgen-DJfqD3bN.js} +0 -0
  464. /package/dist/{mumps-B3NVJs2V.js → mumps-SjGTvDYL.js} +0 -0
  465. /package/dist/{nginx-ComVAAGN.js → nginx-DasThI7R.js} +0 -0
  466. /package/dist/{node-sql-parser-DNGGJ-Rw.js → node-sql-parser-B8nBD36q.js} +0 -0
  467. /package/dist/{ntriples-DHol9X9H.js → ntriples-CNBKRl3I.js} +0 -0
  468. /package/dist/{octave-CYGz0bfo.js → octave-DdeVHNlx.js} +0 -0
  469. /package/dist/{oz-kPxb2ni5.js → oz-CcKSoNvN.js} +0 -0
  470. /package/dist/{pascal-bZ0yrJKy.js → pascal-6leftwNj.js} +0 -0
  471. /package/dist/{path-Du6n3sOU.js → path-BGaWgPKg.js} +0 -0
  472. /package/dist/{perl-z4hvqyqz.js → perl-BhJIwWzN.js} +0 -0
  473. /package/dist/{pig-DZO8QDF9.js → pig-r-xDHqRf.js} +0 -0
  474. /package/dist/{powershell-BSuaDQEC.js → powershell-D-BELeNi.js} +0 -0
  475. /package/dist/{properties-BXhGLlIx.js → properties-CnuDhbll.js} +0 -0
  476. /package/dist/{protobuf-DM6iybWV.js → protobuf-CO8RBhvX.js} +0 -0
  477. /package/dist/{puppet-Bn05sQT8.js → puppet-NmXHjLy8.js} +0 -0
  478. /package/dist/{python-Cvnhm0g7.js → python-DAQXi720.js} +0 -0
  479. /package/dist/{q-B9V8hzex.js → q-DlikXfV0.js} +0 -0
  480. /package/dist/{r-Cf0gFqmq.js → r-CuohilwT.js} +0 -0
  481. /package/dist/{rpm-D-LMkTV1.js → rpm-0Pjwp0Pb.js} +0 -0
  482. /package/dist/{ruby-DeuPikpK.js → ruby-Dq8NJTDG.js} +0 -0
  483. /package/dist/{sas-C9tjgAo9.js → sas-CuwonyVP.js} +0 -0
  484. /package/dist/{scheme-D1_bUF0G.js → scheme-CYU-RRIf.js} +0 -0
  485. /package/dist/{shell-CJBmnks3.js → shell-COPmX2qE.js} +0 -0
  486. /package/dist/{sieve-1fSV75CF.js → sieve-B_3zyLne.js} +0 -0
  487. /package/dist/{simple-mode-B90Wdavj.js → simple-mode-DSBniks8.js} +0 -0
  488. /package/dist/{smalltalk-sZNPD0HO.js → smalltalk-DRft7iPv.js} +0 -0
  489. /package/dist/{solr-DTkyqJ-Z.js → solr-RZ9uTl59.js} +0 -0
  490. /package/dist/{sparql-oHc1nm77.js → sparql-CN6qj55H.js} +0 -0
  491. /package/dist/{spreadsheet-CER0raqY.js → spreadsheet-BNNUNXA2.js} +0 -0
  492. /package/dist/{sql-ByOoEONQ.js → sql-B4x8IkwU.js} +0 -0
  493. /package/dist/{stylus-KzkX6zRB.js → stylus-Bn_ZjOQ3.js} +0 -0
  494. /package/dist/{swift-DqVxZvKo.js → swift-BLUJhMbz.js} +0 -0
  495. /package/dist/{tcl-BtWSwXfA.js → tcl-C86fxecl.js} +0 -0
  496. /package/dist/{textile-CWDbn9Ql.js → textile-DmHh2rsK.js} +0 -0
  497. /package/dist/{tiddlywiki-Cr9xyOY1.js → tiddlywiki-DI0mF2WJ.js} +0 -0
  498. /package/dist/{tiki-D5JONyfZ.js → tiki-2HU6XLLn.js} +0 -0
  499. /package/dist/{timer-D7JVdX9U.js → timer-YZl28NYN.js} +0 -0
  500. /package/dist/{toml-BfehlgmL.js → toml-GWANRNAD.js} +0 -0
  501. /package/dist/{treemap-qFGzn7xk.js → treemap-D-ka1hvx.js} +0 -0
  502. /package/dist/{troff-BZBk6AAu.js → troff-BHTsomIy.js} +0 -0
  503. /package/dist/{ttcn-DVwvXg0_.js → ttcn-DQuhn5Mn.js} +0 -0
  504. /package/dist/{ttcn-cfg-gjbVLf1L.js → ttcn-cfg-HjFYtdB-.js} +0 -0
  505. /package/dist/{turtle-CgxKXorV.js → turtle-nCay33Nv.js} +0 -0
  506. /package/dist/{vb-B9kSwTdM.js → vb-BG-XlqqJ.js} +0 -0
  507. /package/dist/{vbscript-DrUKSCdb.js → vbscript-B6vyW0-D.js} +0 -0
  508. /package/dist/{velocity-AlMYTnMy.js → velocity-CWegueqO.js} +0 -0
  509. /package/dist/{verilog-DLUaM05j.js → verilog-CzSQm4cG.js} +0 -0
  510. /package/dist/{vhdl-DUJOtSmO.js → vhdl-DqnNVL7r.js} +0 -0
  511. /package/dist/{webidl-CQp4aHk_.js → webidl-DXEUpDWH.js} +0 -0
  512. /package/dist/{xquery-IxkjlwOD.js → xquery-Ba_NB5bD.js} +0 -0
  513. /package/dist/{yacas-Bnctn5w8.js → yacas-HKQU6hyk.js} +0 -0
  514. /package/dist/{z80-DrFwhx53.js → z80-CXkHXLdj.js} +0 -0
@@ -0,0 +1,101 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { isEmpty } from "lodash-es";
4
+ import { InfoIcon } from "lucide-react";
5
+ import React from "react";
6
+ import { z } from "zod";
7
+
8
+ // A value worth rendering: drop null/undefined and empty containers
9
+ // (`{}`, `[]`), but keep meaningful primitives (`0`, `false`, `""`).
10
+ function isUninformative(value: unknown): boolean {
11
+ if (value == null) {
12
+ return true;
13
+ }
14
+ if (typeof value === "object") {
15
+ return isEmpty(value);
16
+ }
17
+ return false;
18
+ }
19
+
20
+ // Zod schema matching the Python SuccessResult dataclass
21
+ const SuccessResultSchema = z.looseObject({
22
+ status: z.string().default("success"),
23
+ auth_required: z.boolean().default(false),
24
+ action_url: z.any(),
25
+ next_steps: z.any(),
26
+ meta: z.any(),
27
+ message: z.string().nullish(),
28
+ });
29
+
30
+ type SuccessResult = z.infer<typeof SuccessResultSchema>;
31
+
32
+ const PrettySuccessResult: React.FC<{ data: SuccessResult }> = ({ data }) => {
33
+ const {
34
+ status,
35
+ auth_required,
36
+ action_url: _action_url,
37
+ meta: _meta,
38
+ next_steps: _next_steps,
39
+ message,
40
+ ...rest
41
+ } = data;
42
+
43
+ return (
44
+ <div className="flex flex-col gap-1.5">
45
+ <div className="flex items-center justify-between">
46
+ <h3 className="text-xs font-semibold text-muted-foreground">
47
+ Tool Result
48
+ </h3>
49
+ <div className="flex items-center gap-2">
50
+ <span className="text-xs px-2 py-0.5 bg-(--grass-2) text-(--grass-11) rounded-full font-medium capitalize">
51
+ {status}
52
+ </span>
53
+ {auth_required && (
54
+ <span className="text-xs px-2 py-0.5 bg-(--amber-2) text-(--amber-11) rounded-full">
55
+ Auth Required
56
+ </span>
57
+ )}
58
+ </div>
59
+ </div>
60
+
61
+ {message && (
62
+ <div className="flex items-start gap-2">
63
+ <InfoIcon className="h-3 w-3 text-(--blue-11) mt-0.5 shrink-0" />
64
+ <div className="text-xs text-foreground">{message}</div>
65
+ </div>
66
+ )}
67
+
68
+ {rest && (
69
+ <div className="space-y-3">
70
+ {Object.entries(rest).map(([key, value]) => {
71
+ if (isUninformative(value)) {
72
+ return null;
73
+ }
74
+ return (
75
+ <div key={key} className="space-y-1.5">
76
+ <span className="text-xs text-muted-foreground">{key}</span>
77
+ <pre className="bg-(--slate-2) p-2 text-muted-foreground border border-(--slate-4) rounded text-xs overflow-auto scrollbar-thin max-h-64">
78
+ {JSON.stringify(value, null, 2)}
79
+ </pre>
80
+ </div>
81
+ );
82
+ })}
83
+ </div>
84
+ )}
85
+ </div>
86
+ );
87
+ };
88
+
89
+ export const ResultRenderer: React.FC<{ result: unknown }> = ({ result }) => {
90
+ const parseResult = SuccessResultSchema.safeParse(result);
91
+
92
+ if (parseResult.success) {
93
+ return <PrettySuccessResult data={parseResult.data} />;
94
+ }
95
+
96
+ return (
97
+ <div className="text-xs font-medium text-muted-foreground mb-1 max-h-64 overflow-y-auto scrollbar-thin">
98
+ {typeof result === "string" ? result : JSON.stringify(result, null, 2)}
99
+ </div>
100
+ );
101
+ };
@@ -34,6 +34,7 @@ interface TableTopBarProps extends Partial<ExportActionProps> {
34
34
  showTableExplorer?: boolean;
35
35
  togglePanel?: (panelType: PanelType) => void;
36
36
  isAnyPanelOpen?: boolean;
37
+ sizeBytes?: number | null;
37
38
  }
38
39
 
39
40
  export const TableTopBar: React.FC<TableTopBarProps> = ({
@@ -48,6 +49,7 @@ export const TableTopBar: React.FC<TableTopBarProps> = ({
48
49
  togglePanel,
49
50
  isAnyPanelOpen,
50
51
  downloadAs,
52
+ sizeBytes,
51
53
  }) => {
52
54
  const [internalValue, setInternalValue] = useState(searchQuery || "");
53
55
  const debouncedSearch = useDebounce(internalValue, 500);
@@ -130,7 +132,9 @@ export const TableTopBar: React.FC<TableTopBarProps> = ({
130
132
  Explore
131
133
  </Button>
132
134
  )}
133
- {downloadAs && <ExportMenu downloadAs={downloadAs} />}
135
+ {downloadAs && (
136
+ <ExportMenu downloadAs={downloadAs} sizeBytes={sizeBytes} />
137
+ )}
134
138
  </div>
135
139
  </div>
136
140
  );
@@ -70,6 +70,9 @@ interface DataTableProps<TData> extends Partial<ExportActionProps> {
70
70
  setSorting?: OnChangeFn<SortingState>; // controlled sorting
71
71
  // Pagination
72
72
  totalRows: number | TooManyRows;
73
+ // JSON-serialized size of the currently-rendered data. Forwarded to
74
+ // ExportMenu so hosts can size-gate the Export button via downloadSizeLimitAtom.
75
+ sizeBytes?: number | null;
73
76
  totalColumns: number;
74
77
  pagination?: boolean;
75
78
  manualPagination?: boolean; // server-side pagination
@@ -121,6 +124,7 @@ const DataTableInternal = <TData,>({
121
124
  selection,
122
125
  totalColumns,
123
126
  totalRows,
127
+ sizeBytes,
124
128
  manualSorting = false,
125
129
  sorting,
126
130
  setSorting,
@@ -309,6 +313,7 @@ const DataTableInternal = <TData,>({
309
313
  togglePanel={togglePanel}
310
314
  isAnyPanelOpen={isAnyPanelOpen}
311
315
  downloadAs={downloadAs}
316
+ sizeBytes={sizeBytes}
312
317
  />
313
318
  <Table
314
319
  className={cn(
@@ -0,0 +1,10 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { atom } from "jotai";
4
+
5
+ export interface DownloadSizeLimit {
6
+ limitBytes: number;
7
+ unavailableMessage: string;
8
+ }
9
+
10
+ export const downloadSizeLimitAtom = atom<DownloadSizeLimit | null>(null);
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import { useAtomValue } from "jotai";
3
4
  import {
4
5
  BracesIcon,
5
6
  BrickWallIcon,
@@ -9,6 +10,7 @@ import {
9
10
  } from "lucide-react";
10
11
  import React from "react";
11
12
  import { useLocale } from "react-aria";
13
+ import { downloadSizeLimitAtom } from "./download-policy/atoms";
12
14
  import { logNever } from "@/utils/assertNever";
13
15
  import { cn } from "@/utils/cn";
14
16
  import { copyToClipboard } from "@/utils/copy";
@@ -84,6 +86,11 @@ export interface ExportActionProps {
84
86
  error?: string | null;
85
87
  missing_packages?: string[] | null;
86
88
  }>;
89
+ // JSON-serialized size of the currently-rendered data. Used together with
90
+ // downloadSizeLimitAtom to disable the Export button when a host (e.g.,
91
+ // marimo-lsp inside VS Code) declares a download size cap. Null/undefined
92
+ // means "no info" and the gate stays disabled (fail-open).
93
+ sizeBytes?: number | null;
87
94
  }
88
95
 
89
96
  const labelForDownloadFormat = (format: DownloadFormat): string =>
@@ -94,12 +101,19 @@ const labelForCopyFormat = (format: CopyFormat): string =>
94
101
  export const ExportMenu: React.FC<ExportActionProps> = (props) => {
95
102
  const { locale } = useLocale();
96
103
  const [open, setOpen] = React.useState(false);
104
+ const policy = useAtomValue(downloadSizeLimitAtom);
105
+ const disabled = !!(
106
+ policy &&
107
+ props.sizeBytes != null &&
108
+ props.sizeBytes > policy.limitBytes
109
+ );
97
110
 
98
111
  const button = (
99
112
  <Button
100
113
  data-testid="export-button"
101
114
  size="xs"
102
115
  variant="text"
116
+ disabled={disabled}
103
117
  className={cn(
104
118
  "print:hidden text-xs gap-1",
105
119
  open ? "text-primary" : "text-muted-foreground",
@@ -113,7 +127,10 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
113
127
  const resolveDownloadUrl = async (
114
128
  format: DownloadFormat,
115
129
  onRetry: () => void,
116
- ): Promise<{ url: string; filename: string } | null> => {
130
+ ): Promise<{
131
+ url: string;
132
+ filename: string;
133
+ } | null> => {
117
134
  let response: Awaited<ReturnType<typeof props.downloadAs>>;
118
135
  try {
119
136
  response = await props.downloadAs({ format });
@@ -143,7 +160,10 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
143
160
  return null;
144
161
  }
145
162
 
146
- return { url: response.url, filename: response.filename };
163
+ return {
164
+ url: response.url,
165
+ filename: response.filename,
166
+ };
147
167
  };
148
168
 
149
169
  const handleDownload = async (format: DownloadFormat) => {
@@ -229,8 +249,15 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
229
249
 
230
250
  return (
231
251
  <DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
232
- <Tooltip content="Export" open={open ? false : undefined}>
233
- <DropdownMenuTrigger asChild={true}>{button}</DropdownMenuTrigger>
252
+ <Tooltip
253
+ content={disabled ? policy?.unavailableMessage : "Export"}
254
+ open={open ? false : undefined}
255
+ >
256
+ <DropdownMenuTrigger asChild={true} disabled={disabled}>
257
+ <span tabIndex={disabled ? 0 : -1} className="inline-flex">
258
+ {button}
259
+ </span>
260
+ </DropdownMenuTrigger>
234
261
  </Tooltip>
235
262
  <DropdownMenuContent side="bottom" className="print:hidden">
236
263
  <DropdownMenuLabel className="text-xs text-muted-foreground">
@@ -18,14 +18,16 @@ import { assertNever } from "@/utils/assertNever";
18
18
  import { asRemoteURL, useRuntimeManager } from "@/core/runtime/config";
19
19
  import { API } from "@/core/network/api";
20
20
 
21
- type AgentTab = "claude" | "codex" | "opencode";
21
+ type AgentTab = "claude" | "codex" | "opencode" | "prompt";
22
+
23
+ const TERMINAL_TABS = ["claude", "codex", "opencode"] as const;
22
24
 
23
25
  function getMarimoCommand(): string {
24
26
  return import.meta.env.DEV ? "uv run marimo" : "uvx marimo@latest";
25
27
  }
26
28
 
27
- function getPromptCommand(
28
- agent: AgentTab,
29
+ function getTerminalCommand(
30
+ agent: Exclude<AgentTab, "prompt">,
29
31
  url: string,
30
32
  withToken: boolean,
31
33
  ): string {
@@ -43,6 +45,21 @@ function getPromptCommand(
43
45
  }
44
46
  }
45
47
 
48
+ function getRawPrompt(url: string, token: string | null): string {
49
+ const tokenHint = token
50
+ ? `\n\nUse this auth token when calling \`execute-code.sh\`: \`execute-code.sh --url '${url}' --token '${token}'\`.`
51
+ : "";
52
+ return [
53
+ "Use the /marimo-pair skill to pair-program on a running marimo notebook.",
54
+ "",
55
+ `Connect to the notebook at: ${url}`,
56
+ "",
57
+ `Use \`execute-code.sh --url ${url}\` from the marimo-pair skill to execute code in the notebook.${tokenHint}`,
58
+ "",
59
+ "Once you are connected, send a fun toast (mo.status.toast(...)) to the user inside marimo letting them know you're ready to pair.",
60
+ ].join("\n");
61
+ }
62
+
46
63
  function maskToken(token: string): string {
47
64
  if (token.length <= 4) {
48
65
  return "****";
@@ -52,6 +69,13 @@ function maskToken(token: string): string {
52
69
 
53
70
  const SKILL_INSTALL = "npx skills add marimo-team/marimo-pair";
54
71
 
72
+ const AGENT_LABELS: Record<AgentTab, string> = {
73
+ claude: "Claude",
74
+ codex: "Codex",
75
+ opencode: "OpenCode",
76
+ prompt: "Prompt",
77
+ };
78
+
55
79
  function useAuthToken(): string | null {
56
80
  const [token, setToken] = useState<string | null>(null);
57
81
  useEffect(() => {
@@ -75,10 +99,9 @@ export const PairWithAgentModal: React.FC<{
75
99
  const authToken = useAuthToken();
76
100
  const hasToken = Boolean(authToken);
77
101
  const remoteUrl = runtimeManager.httpURL.toString();
78
- const promptCommand = getPromptCommand(activeTab, remoteUrl, hasToken);
79
102
 
80
103
  return (
81
- <DialogContent className="sm:max-w-lg">
104
+ <DialogContent className="sm:max-w-2xl">
82
105
  <DialogHeader>
83
106
  <DialogTitle>Pair with an agent</DialogTitle>
84
107
  <DialogDescription>
@@ -96,49 +119,75 @@ export const PairWithAgentModal: React.FC<{
96
119
  </DialogHeader>
97
120
 
98
121
  <div className="flex flex-col gap-4 py-2">
99
- <div className="flex flex-col gap-2">
100
- <span className="text-sm font-medium">1. Install the skill</span>
101
- <CommandBlock command={SKILL_INSTALL} />
102
- </div>
103
-
104
- <div className="flex flex-col gap-2">
105
- <span className="text-sm font-medium">2. Run in your terminal</span>
106
- <Tabs
107
- value={activeTab}
108
- onValueChange={(v) => setActiveTab(v as AgentTab)}
109
- >
110
- <TabsList className="w-full">
111
- <TabsTrigger value="claude" className="flex-1">
112
- Claude
113
- </TabsTrigger>
114
- <TabsTrigger value="codex" className="flex-1">
115
- Codex
122
+ <Tabs
123
+ value={activeTab}
124
+ onValueChange={(v) => setActiveTab(v as AgentTab)}
125
+ >
126
+ <TabsList className="w-full">
127
+ {(["claude", "codex", "opencode", "prompt"] as const).map((tab) => (
128
+ <TabsTrigger key={tab} value={tab} className="flex-1">
129
+ {AGENT_LABELS[tab]}
116
130
  </TabsTrigger>
117
- <TabsTrigger value="opencode" className="flex-1">
118
- OpenCode
119
- </TabsTrigger>
120
- </TabsList>
131
+ ))}
132
+ </TabsList>
121
133
 
122
- <TabsContent value="claude" className="mt-3">
123
- <CommandBlock command={promptCommand} />
124
- </TabsContent>
125
- <TabsContent value="codex" className="mt-3">
126
- <CommandBlock command={promptCommand} />
134
+ {TERMINAL_TABS.map((tab) => (
135
+ <TabsContent
136
+ key={tab}
137
+ value={tab}
138
+ className="mt-4 flex flex-col gap-4"
139
+ >
140
+ <Step
141
+ index={1}
142
+ title="Install the skill"
143
+ hint="Run once per machine."
144
+ >
145
+ <CommandBlock command={SKILL_INSTALL} />
146
+ </Step>
147
+ <Step index={2} title="Run in your terminal">
148
+ <CommandBlock
149
+ command={getTerminalCommand(tab, remoteUrl, hasToken)}
150
+ />
151
+ </Step>
152
+ {hasToken && authToken && (
153
+ <Step index={3} title="Paste when prompted for a token">
154
+ <CommandBlock
155
+ command={authToken}
156
+ display={maskToken(authToken)}
157
+ />
158
+ </Step>
159
+ )}
127
160
  </TabsContent>
128
- <TabsContent value="opencode" className="mt-3">
129
- <CommandBlock command={promptCommand} />
130
- </TabsContent>
131
- </Tabs>
132
- </div>
133
-
134
- {hasToken && authToken && (
135
- <div className="flex flex-col gap-2">
136
- <span className="text-sm font-medium">
137
- 3. Paste when prompted for token
138
- </span>
139
- <CommandBlock command={authToken} display={maskToken(authToken)} />
140
- </div>
141
- )}
161
+ ))}
162
+
163
+ <TabsContent value="prompt" className="mt-4 flex flex-col gap-4">
164
+ <Step
165
+ index={1}
166
+ title="Make sure the marimo-pair skill is available to your agent"
167
+ hint="Skip if your agent already has it."
168
+ >
169
+ <CommandBlock command={SKILL_INSTALL} />
170
+ </Step>
171
+ <Step
172
+ index={2}
173
+ title="Copy this prompt into your agent"
174
+ hint={
175
+ hasToken
176
+ ? "Includes your auth token — keep it private."
177
+ : undefined
178
+ }
179
+ >
180
+ <CommandBlock
181
+ command={getRawPrompt(remoteUrl, authToken)}
182
+ display={getRawPrompt(
183
+ remoteUrl,
184
+ authToken ? maskToken(authToken) : null,
185
+ )}
186
+ multiline={true}
187
+ />
188
+ </Step>
189
+ </TabsContent>
190
+ </Tabs>
142
191
  </div>
143
192
 
144
193
  <DialogFooter>
@@ -150,10 +199,28 @@ export const PairWithAgentModal: React.FC<{
150
199
  );
151
200
  };
152
201
 
153
- const CommandBlock: React.FC<{ command: string; display?: string }> = ({
154
- command,
155
- display,
156
- }) => {
202
+ const Step: React.FC<{
203
+ index: number;
204
+ title: string;
205
+ hint?: string;
206
+ children: React.ReactNode;
207
+ }> = ({ index, title, hint, children }) => (
208
+ <div className="flex flex-col gap-2">
209
+ <div className="flex items-baseline gap-2">
210
+ <span className="text-sm font-medium">
211
+ {index}. {title}
212
+ </span>
213
+ {hint && <span className="text-xs text-muted-foreground">{hint}</span>}
214
+ </div>
215
+ {children}
216
+ </div>
217
+ );
218
+
219
+ const CommandBlock: React.FC<{
220
+ command: string;
221
+ display?: string;
222
+ multiline?: boolean;
223
+ }> = ({ command, display, multiline = false }) => {
157
224
  const [copied, setCopied] = useState(false);
158
225
 
159
226
  const copy = Events.stopPropagation(async (e) => {
@@ -163,6 +230,30 @@ const CommandBlock: React.FC<{ command: string; display?: string }> = ({
163
230
  setTimeout(() => setCopied(false), 2000);
164
231
  });
165
232
 
233
+ if (multiline) {
234
+ return (
235
+ <div className="relative rounded-md bg-muted">
236
+ <pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words px-3 py-2 pr-10 font-mono text-xs select-all">
237
+ {display ?? command}
238
+ </pre>
239
+ <Tooltip content="Copied!" open={copied}>
240
+ <Button
241
+ onClick={copy}
242
+ size="xs"
243
+ variant="ghost"
244
+ className="absolute right-1 top-1"
245
+ >
246
+ {copied ? (
247
+ <CheckIcon size={14} strokeWidth={1.5} />
248
+ ) : (
249
+ <CopyIcon size={14} strokeWidth={1.5} />
250
+ )}
251
+ </Button>
252
+ </Tooltip>
253
+ </div>
254
+ );
255
+ }
256
+
166
257
  return (
167
258
  <div className="flex items-center gap-2 rounded-md bg-muted px-3 py-2 font-mono text-xs">
168
259
  <code className="flex-1 select-all break-words">
@@ -53,6 +53,7 @@ import {
53
53
  canUndoDeletesAtom,
54
54
  getNotebook,
55
55
  hasDisabledCellsAtom,
56
+ undoLabelAtom,
56
57
  useCellActions,
57
58
  } from "@/core/cells/cells";
58
59
  import { disabledCellIds } from "@/core/cells/utils";
@@ -137,6 +138,7 @@ export function useNotebookActions() {
137
138
 
138
139
  const hasDisabledCells = useAtomValue(hasDisabledCellsAtom);
139
140
  const canUndoDeletes = useAtomValue(canUndoDeletesAtom);
141
+ const undoLabel = useAtomValue(undoLabelAtom);
140
142
  const { selectedLayout } = useLayoutState();
141
143
  const { setLayoutView } = useLayoutActions();
142
144
  const togglePresenting = useTogglePresenting();
@@ -525,7 +527,7 @@ export function useNotebookActions() {
525
527
  },
526
528
  {
527
529
  icon: <Undo2Icon size={14} strokeWidth={1.5} />,
528
- label: "Undo cell deletion",
530
+ label: undoLabel,
529
531
  hidden: !canUndoDeletes || kioskMode,
530
532
  handle: () => {
531
533
  undoDeleteCell();
@@ -15,6 +15,7 @@ interface Props {
15
15
  connection: ConnectionStatus;
16
16
  isRunning: boolean;
17
17
  width: AppConfig["width"];
18
+ onReconnect?: () => void;
18
19
  }
19
20
 
20
21
  export const AppContainer: React.FC<PropsWithChildren<Props>> = ({
@@ -22,13 +23,18 @@ export const AppContainer: React.FC<PropsWithChildren<Props>> = ({
22
23
  connection,
23
24
  isRunning,
24
25
  children,
26
+ onReconnect,
25
27
  }) => {
26
28
  const connectionState = connection.state;
27
29
 
28
30
  return (
29
31
  <>
30
32
  <DynamicFavicon isRunning={isRunning} />
31
- <StatusOverlay connection={connection} isRunning={isRunning} />
33
+ <StatusOverlay
34
+ connection={connection}
35
+ isRunning={isRunning}
36
+ onReconnect={onReconnect}
37
+ />
32
38
  <PyodideLoader>
33
39
  <WrappedWithSidebar>
34
40
  {/** oxlint-ignore-next-line -- ID is used by other components to grab the DOM element */}
@@ -133,7 +133,12 @@ export const ContextAwarePanel: React.FC = () => {
133
133
  onDragging={handleDragging}
134
134
  className="resize-handle border-border z-20 print:hidden border-l"
135
135
  />
136
- <Panel defaultSize={25} minSize={25} maxSize={80}>
136
+ <Panel
137
+ data-testid="chrome-context-aware-panel"
138
+ defaultSize={25}
139
+ minSize={25}
140
+ maxSize={80}
141
+ >
137
142
  {renderBody()}
138
143
  </Panel>
139
144
  </>
@@ -167,7 +172,10 @@ const ResizableComponent = ({ children }: ResizableComponentProps) => {
167
172
  });
168
173
 
169
174
  return (
170
- <div className="absolute z-40 right-0 h-full bg-background flex flex-row">
175
+ <div
176
+ data-testid="chrome-context-aware-panel"
177
+ className="absolute z-40 right-0 h-full bg-background flex flex-row"
178
+ >
171
179
  <div
172
180
  ref={handleRefs.left}
173
181
  className="w-1 h-full cursor-col-resize border-l"
@@ -537,6 +537,7 @@ export const AppChrome: React.FC<PropsWithChildren> = ({ children }) => {
537
537
  {helperPanel}
538
538
  <Panel
539
539
  id="app-chrome-body"
540
+ data-testid="chrome-body"
540
541
  className={cn(isDeveloperPanelOpen && !isSidebarOpen && "border-l")}
541
542
  >
542
543
  <PanelGroup autoSaveId="marimo:chrome:v1:l1" direction="vertical">
@@ -58,7 +58,10 @@ export const Footer: React.FC = () => {
58
58
  });
59
59
 
60
60
  return (
61
- <footer className="h-10 py-1 gap-1 bg-background flex items-center text-muted-foreground text-md pl-2 pr-1 border-t border-border select-none print:hidden text-sm z-50 hide-on-fullscreen overflow-x-auto overflow-y-hidden scrollbar-thin">
61
+ <footer
62
+ data-testid="chrome-footer"
63
+ className="h-10 py-1 gap-1 bg-background flex items-center text-muted-foreground text-md pl-2 pr-1 border-t border-border select-none print:hidden text-sm z-50 hide-on-fullscreen overflow-x-auto overflow-y-hidden scrollbar-thin"
64
+ >
62
65
  <FooterItem
63
66
  className="h-full"
64
67
  tooltip={
@@ -3,7 +3,10 @@ import type { PropsWithChildren } from "react";
3
3
 
4
4
  export const PanelsWrapper: React.FC<PropsWithChildren> = ({ children }) => {
5
5
  return (
6
- <div className="flex flex-col flex-1 overflow-hidden absolute inset-0 print:relative">
6
+ <div
7
+ data-testid="chrome-wrapper"
8
+ className="flex flex-col flex-1 overflow-hidden absolute inset-0 print:relative"
9
+ >
7
10
  {children}
8
11
  </div>
9
12
  );
@@ -115,7 +115,10 @@ export const Sidebar: React.FC = () => {
115
115
  ]);
116
116
 
117
117
  return (
118
- <div className="h-full pt-4 pb-1 px-1 flex flex-col items-start text-muted-foreground text-md select-none text-sm z-50 dark:bg-background print:hidden hide-on-fullscreen">
118
+ <div
119
+ data-testid="chrome-sidebar"
120
+ className="h-full pt-4 pb-1 px-1 flex flex-col items-start text-muted-foreground text-md select-none text-sm z-50 dark:bg-background print:hidden hide-on-fullscreen"
121
+ >
119
122
  <ReorderableList<PanelDescriptor>
120
123
  value={sidebarItems}
121
124
  setValue={handleSetSidebarItems}
@@ -27,6 +27,7 @@ import { Functions } from "@/utils/functions";
27
27
  import {
28
28
  canUndoDeletesAtom,
29
29
  needsRunAtom,
30
+ undoLabelAtom,
30
31
  useCellActions,
31
32
  } from "../../../core/cells/cells";
32
33
  import { ConfigButton } from "../../app-config/app-config-button";
@@ -56,6 +57,7 @@ export const Controls = ({
56
57
  running,
57
58
  }: ControlsProps): JSX.Element => {
58
59
  const undoAvailable = useAtomValue(canUndoDeletesAtom);
60
+ const undoLabel = useAtomValue(undoLabelAtom);
59
61
  const needsRun = useAtomValue(needsRunAtom);
60
62
  const { undoDeleteCell } = useCellActions();
61
63
  const closed = connectionState === WebSocketState.CLOSED;
@@ -63,7 +65,7 @@ export const Controls = ({
63
65
  let undoControl: JSX.Element | null = null;
64
66
  if (!closed && undoAvailable) {
65
67
  undoControl = (
66
- <Tooltip content="Undo cell deletion">
68
+ <Tooltip content={undoLabel}>
67
69
  <Button
68
70
  data-testid="undo-delete-cell"
69
71
  size="medium"
@@ -86,7 +88,10 @@ export const Controls = ({
86
88
  {!presenting && <FindReplace />}
87
89
 
88
90
  {!closed && (
89
- <div className={topRightControls}>
91
+ <div
92
+ data-testid="chrome-controls-top-right"
93
+ className={topRightControls}
94
+ >
90
95
  {presenting && <LayoutSelect />}
91
96
  <NotebookMenuDropdown
92
97
  disabled={disabled}
@@ -101,7 +106,10 @@ export const Controls = ({
101
106
  </div>
102
107
  )}
103
108
 
104
- <div className={cn(bottomRightControls)}>
109
+ <div
110
+ data-testid="chrome-controls-bottom-right"
111
+ className={cn(bottomRightControls)}
112
+ >
105
113
  <HideInKioskMode>
106
114
  <SaveComponent kioskMode={false} />
107
115
  </HideInKioskMode>