@marimo-team/islands 0.24.3-dev4 → 0.24.3-dev41

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 (370) hide show
  1. package/dist/{ConnectedDataExplorerComponent-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
  2. package/dist/ErrorBoundary-Cg8Ff5uL.js +200 -0
  3. package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-RspMflu6.js} +3 -3
  4. package/dist/{Plot-C-9MQeGP.js → Plot-CTyjbQDT.js} +21032 -20666
  5. package/dist/_baseMerge-BiGRwuqv.js +165 -0
  6. package/dist/{abnfDiagram-N423BO3Z-CQKwzX8t.js → abnfDiagram-VCTEODGH-CpN0FRda.js} +17 -18
  7. package/dist/{any-language-editor-DmQ7dyCx.js → any-language-editor-CycIVIeP.js} +17 -17
  8. package/dist/arc-7ra3iNdN.js +81 -0
  9. package/dist/architecture-7GRP2DOG-BWLylgiA.js +3 -0
  10. package/dist/{architectureDiagram-T3A2C74G-CncrDpfa.js → architectureDiagram-5GKGNRK7-DDyj5SRB.js} +25 -25
  11. package/dist/assets/__vite-browser-external-BajL8aoc.js +1 -0
  12. package/dist/assets/worker-BemUy60C.js +109 -0
  13. package/dist/blockDiagram-I7D4REHJ-BbXEXJRu.js +1922 -0
  14. package/dist/{button-CKBkqR9J.js → button-DdXAm8iz.js} +5 -5
  15. package/dist/{c4Diagram-5PPSVZJV-DarUk3Yq.js → c4Diagram-7LVT6UL2-DcLsbQmR.js} +696 -668
  16. package/dist/{capabilities-CMBBJTcc.js → capabilities-B3ce_GNu.js} +1 -1
  17. package/dist/{html-to-image-BhNoIBSU.js → cells-BSgNCBZ8.js} +6740 -10126
  18. package/dist/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
  19. package/dist/chat-ui-CygzVJ9s.js +5786 -0
  20. package/dist/{check-CHig47QV.js → check-B7cIK6gb.js} +1 -1
  21. package/dist/{chunk-2Q5K7J3B-BMuJl2jB.js → chunk-2Q5K7J3B-BMkUkeuy.js} +2 -2
  22. package/dist/chunk-4HAMMTFA-D2qv8E0X.js +4188 -0
  23. package/dist/{chunk-5VM5RSS4-Bcq0ftdy.js → chunk-5VM5RSS4-DKsmPCL6.js} +2 -2
  24. package/dist/{chunk-NSK5VX7P-CDTMcJB0.js → chunk-75Z2AOVW-5_HsvXwr.js} +23 -23
  25. package/dist/{chunk-I66GZJ75-BqyTCAPf.js → chunk-DU6HZSFF-BUgAHvnM.js} +21 -4
  26. package/dist/{chunk-2GRJ4B5K-DgO8Qudq.js → chunk-F27PBJKO-DHmYWZXr.js} +4 -4
  27. package/dist/{chunk-KEIR6QF5-C4KX3XYh.js → chunk-FOHPRMQF-BpYR8RqP.js} +4 -4
  28. package/dist/{chunk-WRU74C26-BpWsbiDK.js → chunk-GMAD6QVW-Czynz8aA.js} +486 -258
  29. package/dist/chunk-GVQU2GXP-yQEdulRS.js +37 -0
  30. package/dist/{chunk-5RXB4S5H-tLNUVDdO.js → chunk-IMKFNOWR-BfwTebD0.js} +11 -11
  31. package/dist/{chunk-JWPE2WC7-BJwjGUnF.js → chunk-JWPE2WC7-DJvv1t8U.js} +2 -2
  32. package/dist/chunk-L3NEJ4N5-DwRWnDDK.js +245 -0
  33. package/dist/{chunk-7Z6QIM7H-Dc18hFxH.js → chunk-OSK3NFVY-BBKU_Ign.js} +222 -144
  34. package/dist/{chunk-W5SLKNZC-DLnvpEtV.js → chunk-P2QGCYS3-C0iGU29N.js} +20 -20
  35. package/dist/{chunk-KBJHAD2P-BuqWqkcW.js → chunk-POPQ4Y6H-BCbS3Ozc.js} +4 -4
  36. package/dist/{chunk-4I5QYGJK-DpytHuZQ.js → chunk-PWAF6VOD-CTFCL0jI.js} +4 -4
  37. package/dist/{chunk-JQJVKLGR-CgqCwe8E.js → chunk-SHT3W25Y-BspJEJ5H.js} +109 -63
  38. package/dist/{chunk-6Q2QTUOP-DmTcEBMn.js → chunk-SVP7TREG-DX3rFNTe.js} +5 -5
  39. package/dist/{chunk-GF5L2VYU-B0wgCQgS.js → chunk-TICWLB2K-fVF7Uujg.js} +13 -13
  40. package/dist/{chunk-XXDRQBXY-D73H4IN0.js → chunk-XXDRQBXY-Dnl5VBqG.js} +3 -3
  41. package/dist/{chunk-Y2CYZVJY-DoegUj_e.js → chunk-Y2CYZVJY-DKKS1VyV.js} +1 -1
  42. package/dist/{chunk-5FQGJX7Z-B85XCPv6.js → chunk-YOKDWASO-DrWbKnxA.js} +6925 -5460
  43. package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +30 -0
  44. package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +30 -0
  45. package/dist/code-visibility-BB9okzzY.js +138 -0
  46. package/dist/{common-BDlauhCU.js → common-aCHtzRnQ.js} +8853 -12653
  47. package/dist/{compiler-runtime-CAH9RLw2.js → compiler-runtime-Cj8ZWiNS.js} +2 -2
  48. package/dist/copy-icon-CLdENY__.js +190 -0
  49. package/dist/{cose-bilkent-JH36ORCC-FUWHkXFX.js → cose-bilkent-JH36ORCC-_LyRKVqm.js} +2 -2
  50. package/dist/cubic-OaEBhQPK.js +1404 -0
  51. package/dist/cynefin-OW5HDTMX-obq-i80l.js +3 -0
  52. package/dist/{cynefinDiagram-MW4NZA55-BXSFK93J.js → cynefinDiagram-5FMLGOSQ-CFQrqzSX.js} +10 -10
  53. package/dist/{dagre-CGyalH38.js → dagre-BGSfXNEb.js} +678 -537
  54. package/dist/dagre-GXQ25YYZ-xHNAUTyG.js +425 -0
  55. package/dist/{data-grid-overlay-editor-DZM4BAaI.js → data-grid-overlay-editor-yiwy9Vea.js} +8 -9
  56. package/dist/{data-grid-types-BnZwWG8z.js → data-grid-types-BucVmDDp.js} +1 -1
  57. package/dist/{defaultLocale-DKaU_opG.js → defaultLocale-JI_lnoCe.js} +1 -1
  58. package/dist/{diagram-7IWD3JNH-BjfzDNvj.js → diagram-S7CK7UJ4-Bt1rPbAx.js} +40 -39
  59. package/dist/{diagram-UB23O5K3-DDg-7wLA.js → diagram-UQ7AKVKN-D1sq5FoZ.js} +10 -10
  60. package/dist/{diagram-B4RE2ZJO-CKccR9eE.js → diagram-VSXAHHWV-BKpmG23x.js} +10 -10
  61. package/dist/{diagram-Q27KOJAE-Zhz01ss7.js → diagram-VX7I27RA-BMwGFVD6.js} +21 -21
  62. package/dist/{diagram-LBJQPF4R-CJ-bOruh.js → diagram-Z3DM3KII--KLDR9Pl.js} +10 -10
  63. package/dist/dialog-CgNq6y9-.js +94 -0
  64. package/dist/{dist-dAqZAPcF.js → dist-1HDa70oE.js} +3 -3
  65. package/dist/{dist-Re9sOPOx.js → dist-9x1ZRe-e.js} +2 -2
  66. package/dist/{dist-DEeLqRlU.js → dist-B1vYLK28.js} +1 -1
  67. package/dist/{dist-C5Bn52W4.js → dist-B8D7McG3.js} +3 -3
  68. package/dist/{dist-_XvgytiS.js → dist-BHCHt1NI.js} +1 -1
  69. package/dist/{dist-CRjAdnqF.js → dist-BRxfaJgs.js} +3 -3
  70. package/dist/{dist-Byj2bV8o.js → dist-BVGtK7Ht.js} +1 -1
  71. package/dist/{dist-BIN5LKyE.js → dist-BaHjhkpZ.js} +2 -2
  72. package/dist/{dist-DVFbIwc5.js → dist-BtKIs9N-.js} +1 -1
  73. package/dist/{dist-BrQGcfQ9.js → dist-C2KzV-vf.js} +2 -2
  74. package/dist/{dist-DJFiGP2k.js → dist-C2wDlYdD.js} +2 -2
  75. package/dist/{dist-BVRM2y1P.js → dist-C8xMLVYi.js} +2 -2
  76. package/dist/dist-CMh_W4y4.js +538 -0
  77. package/dist/{extends-BPB6_lTK.js → dist-CO1AwwG_.js} +516 -561
  78. package/dist/{dist-BzN60Z2s.js → dist-CPGxfVGX.js} +1 -1
  79. package/dist/{dist-C7v-9nUK.js → dist-Cm3iAFMD.js} +3 -3
  80. package/dist/{dist-CGAxEiaM.js → dist-Cs2FijYk.js} +2 -2
  81. package/dist/{dist-hXd65f0_.js → dist-D1PpnuZB.js} +1 -1
  82. package/dist/{dist-VdvbxG72.js → dist-DHOTQar0.js} +1 -1
  83. package/dist/{dist-DcgzXCfy.js → dist-DPcEtqmG.js} +2 -2
  84. package/dist/{dist-D4Z_qdP4.js → dist-Df0wKI0F.js} +1 -1
  85. package/dist/{dist-qhLI-SHd.js → dist-DszxuxS1.js} +2 -2
  86. package/dist/{dist-BEmkrGoQ.js → dist-Kxgjxakw.js} +1 -1
  87. package/dist/{dist-BbSMhhD2.js → dist-KzZ7WELx.js} +2 -2
  88. package/dist/{dist-jWUab2d1.js → dist-lA1Cttkb.js} +1 -1
  89. package/dist/dropdown-menu-CZgjYSAh.js +4502 -0
  90. package/dist/{ebnfDiagram-BXEA7PRR-Dm75pCAS.js → ebnfDiagram-PWID7BFC-WnG4cvSQ.js} +17 -18
  91. package/dist/{erDiagram-JOGREHBK-rVDG3VSQ.js → erDiagram-RLTQ6QDP-DhzKiYHc.js} +1037 -798
  92. package/dist/error-banner-B94dcDmP.js +391 -0
  93. package/dist/error-entries-iJn-Nryx.js +56 -0
  94. package/dist/{esm-CR1nhb1c.js → esm-BElI3qKH.js} +22 -22
  95. package/dist/{esm-C1d0g6Bv.js → esm-G4Fhsgng.js} +51 -37
  96. package/dist/{esm-CesmlDrs.js → esm-h8f7-1CJ.js} +423 -423
  97. package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +3 -0
  98. package/dist/feedback-button-CfL-qWDi.js +380 -0
  99. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +16 -0
  100. package/dist/{formats-CJMVUfb3.js → formats-BR5iGb4s.js} +8 -8
  101. package/dist/{ganttDiagram-PKOTCBZU-9D-LXF6P.js → ganttDiagram-EL5Y4UJY-DbzEBLbl.js} +15 -15
  102. package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +3 -0
  103. package/dist/{gitGraphDiagram-DS77QQ5N-BfpsXTLf.js → gitGraphDiagram-WWUBYQGX-BMf0iKi1.js} +10 -10
  104. package/dist/{glide-data-editor-sPZ8fUFn.js → glide-data-editor-MNFAmb3B.js} +2143 -1910
  105. package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
  106. package/dist/globals-DZfCplvV.js +19 -0
  107. package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
  108. package/dist/html-to-image-kpuRfdfZ.js +3253 -0
  109. package/dist/info-A6RAGUB7-DKoayiHY.js +3 -0
  110. package/dist/{infoDiagram-6WML65LV-DqCTXHVy.js → infoDiagram-27XIBGKW-BagtCX_5.js} +7 -7
  111. package/dist/{ishikawaDiagram-WSZJBQD7-BCUYmZ1v.js → ishikawaDiagram-5VMMS53U-DByDehYy.js} +8 -8
  112. package/dist/{journeyDiagram-NVQOT4AX-BXB6M4zN.js → journeyDiagram-3NMN7TZE-D2LcKDUO.js} +8 -8
  113. package/dist/{jsx-runtime-CpoKNRgu.js → jsx-runtime-DgDPJV9S.js} +1 -1
  114. package/dist/{kanban-definition-27J2QSJJ-CGRhrDUX.js → kanban-definition-UXKFOSKX-BxwkbBI_.js} +29 -29
  115. package/dist/katex-DFBiSucW.js +21840 -0
  116. package/dist/{label-lwzzBHUW.js → label-BJ49YTvk.js} +6 -6
  117. package/dist/{linear-D5r_1YqD.js → linear-Cnaq3Tfb.js} +4 -4
  118. package/dist/{loader-VZ__bv4g.js → loader-D2W4oM-3.js} +15 -15
  119. package/dist/main.js +8105 -13485
  120. package/dist/mermaid-DPNuhemn.js +3084 -0
  121. package/dist/mermaid-HWGCJPDP-DYCzSILp.js +2 -0
  122. package/dist/mermaid-parser.core-DxuSfYwJ.js +638 -0
  123. package/dist/{mhchem-BjwrxcV-.js → mhchem-DWCF06w9.js} +1 -1
  124. package/dist/{micromark-factory-space-DruVGzeG.js → micromark-factory-space-DGxAzmw8.js} +2 -2
  125. package/dist/{mindmap-definition-FAOFIHXS-C9gRhzZq.js → mindmap-definition-YA3MSWOX-Cgvojw3y.js} +17 -17
  126. package/dist/{node-sql-parser-DesT1xNw.js → node-sql-parser-BiZOJ-FS.js} +0 -3
  127. package/dist/{number-overlay-editor-De2CabLL.js → number-overlay-editor-BZuSsCs5.js} +5 -5
  128. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +23 -0
  129. package/dist/packet-AYTQ26CC-Yw7ajchJ.js +3 -0
  130. package/dist/{pegDiagram-VL7TDLO6-Df9IUjMD.js → pegDiagram-XKGWAZYB-DahHhYyN.js} +19 -20
  131. package/dist/{pick-SnHlmIBN.js → pick-CJeoxYOS.js} +1 -1
  132. package/dist/pie-WAS4IAKB-BKdKOAkL.js +3 -0
  133. package/dist/{pieDiagram-7S7Q4E2Y-BmRzQ8ZP.js → pieDiagram-E7YTZNPT-CCtX0oCK.js} +29 -31
  134. package/dist/{process-output-CpK6fX_C.js → process-output-DFe2tVIY.js} +7 -6
  135. package/dist/purify.es-DgKyQviY.js +805 -0
  136. package/dist/{quadrantDiagram-CIZ2JOQS-wFBvWcxS.js → quadrantDiagram-AXDQQJYC-DftINo6g.js} +5 -5
  137. package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +3 -0
  138. package/dist/railroad-74A4TZTK-DQvPSdo5.js +3 -0
  139. package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +3 -0
  140. package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +3 -0
  141. package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +3 -0
  142. package/dist/{railroadDiagram-AXF67PYL-DxbIatiN.js → railroadDiagram-O6MQD6OU-Du5NsPUb.js} +17 -18
  143. package/dist/{react-dom-C94wmq5w.js → react-dom-BUgJ-ab_.js} +3 -3
  144. package/dist/{react-DMWcHin-.js → react-ofJbxM4x.js} +2 -2
  145. package/dist/{react-vega-DSD5aT7_.js → react-vega-5AcMW8gG.js} +10012 -9369
  146. package/dist/{requirementDiagram-LRYGKXZP-X_x-Y713.js → requirementDiagram-BXWQKSXE-0pmmxL6_.js} +20 -19
  147. package/dist/{reveal-component-BthxSdRc.js → reveal-component-ONiOVUUx.js} +1303 -1237
  148. package/dist/{sankeyDiagram-W5VNT64P-BYJALbbm.js → sankeyDiagram-P5KCCOFB-CDKR5TJH.js} +4 -4
  149. package/dist/{select-3qHpFKF9.js → select-C6plhmZr.js} +317 -562
  150. package/dist/{sequenceDiagram-SI44F4Z6-BiPBe3Sv.js → sequenceDiagram-WJ2MYXX4-DB-ChWwU.js} +11 -11
  151. package/dist/{sizeCapture-X5ZJPWSS-BKLDeh5H.js → sizeCapture-INFHLROL-Dx5SpkQF.js} +2 -2
  152. package/dist/{spec-CutWdqo3.js → spec-CAYwFeV6.js} +4 -4
  153. package/dist/{src-C31ngt98.js → src-CA_m4ONl.js} +298 -303
  154. package/dist/{stateDiagram-OKZ733FA-B7QyNBxH.js → stateDiagram-D77RDMKH-orN6AwMx.js} +19 -20
  155. package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +30 -0
  156. package/dist/style.css +2 -2
  157. package/dist/{swimlanes-SLNWSIFB-B4f8VP3b.js → swimlanes-42K2YHIH-BkSDcqDT.js} +1501 -1591
  158. package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +30 -0
  159. package/dist/{swiper-component-C90YjhaV.js → swiper-component-IOUowglM.js} +39 -26
  160. package/dist/{time-aWGfjN8x.js → time-BieKwdYS.js} +42 -42
  161. package/dist/{timeline-definition-Z64GVDOM-Dacq_5lr.js → timeline-definition-24CTP7MA-BuqJUIRZ.js} +7 -7
  162. package/dist/{toDate-D-Rx3ux5.js → toDate-WXg1yLcI.js} +10 -9
  163. package/dist/toast-DvY70eFX.js +1834 -0
  164. package/dist/tooltip-qB8NlSqV.js +1742 -0
  165. package/dist/treeView-Q6P3EWNA-DuRV97YF.js +3 -0
  166. package/dist/treemap-WGGIJYW6-AsLq-uwC.js +3 -0
  167. package/dist/use-restore-focus-D5D9xEjZ.js +5946 -0
  168. package/dist/{use-vega-container-remeasure-DUW4tRxq.js → use-vega-container-remeasure-4DwJbPWu.js} +2 -2
  169. package/dist/{useAsyncData-CH6-CgJF.js → useAsyncData-BD6AStMt.js} +3 -3
  170. package/dist/{useDateFormatter-Cp9Jdxls.js → useDateFormatter-BRTPsUK7.js} +8 -8
  171. package/dist/{useDeepCompareMemoize-JC87C_jO.js → useDeepCompareMemoize-D_HNdyvI.js} +2 -2
  172. package/dist/{useIframeCapabilities-De3C-9b4.js → useIframeCapabilities-CVtNkI3Y.js} +2 -2
  173. package/dist/{useLifecycle-B4RGlyf0.js → useLifecycle-DPgiiwwU.js} +6 -6
  174. package/dist/useNumberFormatter-BfDpa21j.js +251 -0
  175. package/dist/useTheme-DzXmYZ5V.js +904 -0
  176. package/dist/{vega-component-CPehZbUb.js → vega-component-D0QXopU8.js} +34 -34
  177. package/dist/{vega-embed-container-TJ5z5dZw.js → vega-embed-container-CbnTccZi.js} +6 -6
  178. package/dist/vega-loader.browser-D95WfUcj.js +1139 -0
  179. package/dist/{vennDiagram-T6HMQDX7-D-Rcq3Iu.js → vennDiagram-4TSXK5OY-CTUlJ2PK.js} +9 -9
  180. package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +3 -0
  181. package/dist/{wardleyDiagram-T6FBY63Y-Z-Og7_Wd.js → wardleyDiagram-VM6X3IG4-3evLUb0M.js} +10 -10
  182. package/dist/{xychartDiagram-ELKLHX3M-BDJ2dITA.js → xychartDiagram-S5SC5T6Z-DL2E3K8-.js} +248 -139
  183. package/package.json +54 -57
  184. package/src/__mocks__/requests.ts +7 -0
  185. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
  186. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +270 -0
  187. package/src/components/chat/acp/agent-panel.tsx +45 -44
  188. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
  189. package/src/components/data-table/column-summary/chart-spec-model.tsx +1 -1
  190. package/src/components/data-table/column-visibility-dropdown.tsx +9 -3
  191. package/src/components/data-table/columns.tsx +64 -67
  192. package/src/components/datasources/components.tsx +4 -2
  193. package/src/components/editor/RecoveryButton.tsx +1 -0
  194. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
  195. package/src/components/editor/alerts/connecting-alert.tsx +1 -66
  196. package/src/components/editor/alerts/connection-notice.tsx +140 -0
  197. package/src/components/editor/app-container.tsx +9 -3
  198. package/src/components/editor/boundary/ErrorBoundary.tsx +38 -16
  199. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +311 -0
  200. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +50 -0
  201. package/src/components/editor/cell/code/cell-editor.tsx +41 -42
  202. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +94 -0
  203. package/src/components/editor/chrome/components/feedback-button.tsx +63 -42
  204. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +114 -7
  205. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +165 -0
  206. package/src/components/editor/chrome/panels/packages-panel.tsx +93 -166
  207. package/src/components/editor/chrome/panels/sandbox-controller.tsx +106 -0
  208. package/src/components/editor/chrome/panels/sandbox-panel.tsx +173 -0
  209. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -1
  210. package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
  211. package/src/components/editor/code/readonly-diff.tsx +1 -1
  212. package/src/components/editor/dynamic-favicon.tsx +17 -10
  213. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  214. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  215. package/src/components/editor/header/__tests__/status.test.tsx +8 -20
  216. package/src/components/editor/header/filename-input.tsx +2 -0
  217. package/src/components/editor/header/status.tsx +5 -3
  218. package/src/components/editor/notebook-cell.tsx +4 -2
  219. package/src/components/editor/output/JsonOutput.tsx +182 -632
  220. package/src/components/editor/output/Outputs.css +50 -17
  221. package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
  222. package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
  223. package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
  224. package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
  225. package/src/components/editor/output/json-output/formatting.ts +167 -0
  226. package/src/components/editor/output/json-output/pagination.ts +155 -0
  227. package/src/components/editor/output/json-output/renderers.tsx +196 -0
  228. package/src/components/editor/output/json-output/themes.ts +52 -0
  229. package/src/components/editor/renderers/cell-array.tsx +1 -5
  230. package/src/components/home/components.tsx +17 -0
  231. package/src/components/pages/gallery-page.tsx +2 -4
  232. package/src/components/pages/home-page.tsx +2 -4
  233. package/src/components/slides/slide-form.tsx +1 -0
  234. package/src/components/slides/slide-notes-editor.tsx +1 -0
  235. package/src/components/terminal/terminal.tsx +4 -4
  236. package/src/components/tracing/tracing-spec.ts +1 -1
  237. package/src/components/ui/table.tsx +1 -1
  238. package/src/components/ui/use-toast.ts +8 -0
  239. package/src/core/MarimoApp.tsx +0 -2
  240. package/src/core/cells/__tests__/cell.test.ts +61 -0
  241. package/src/core/cells/cell.ts +9 -1
  242. package/src/core/cells/pending-delete-service.ts +12 -16
  243. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  244. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  245. package/src/core/codemirror/rtc/extension.ts +5 -2
  246. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  247. package/src/core/datasets/data-source-connections.ts +15 -10
  248. package/src/core/edit-app.tsx +8 -5
  249. package/src/core/errors/state.ts +1 -2
  250. package/src/core/islands/__tests__/parse.test.ts +140 -7
  251. package/src/core/islands/bootstrap.ts +1 -0
  252. package/src/core/islands/bridge.ts +3 -0
  253. package/src/core/islands/parse.ts +20 -0
  254. package/src/core/network/connection-notice.ts +84 -0
  255. package/src/core/network/requests-lazy.ts +3 -0
  256. package/src/core/network/requests-network.ts +12 -0
  257. package/src/core/network/requests-static.ts +3 -0
  258. package/src/core/network/requests-toasting.tsx +3 -0
  259. package/src/core/network/resolve.ts +2 -1
  260. package/src/core/network/types.ts +7 -0
  261. package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
  262. package/src/core/packages/__tests__/useSandboxController.test.tsx +165 -0
  263. package/src/core/packages/package-data.ts +35 -0
  264. package/src/core/packages/sandbox-state.ts +15 -0
  265. package/src/core/packages/toast-components.tsx +11 -0
  266. package/src/core/packages/useInstallPackage.ts +1 -1
  267. package/src/core/packages/usePackageAction.ts +51 -0
  268. package/src/core/packages/usePackageDependencies.ts +22 -0
  269. package/src/core/packages/useSandboxController.ts +188 -0
  270. package/src/core/run-app.tsx +2 -0
  271. package/src/core/runtime/__tests__/runtime.test.ts +11 -0
  272. package/src/core/runtime/runtime.ts +7 -2
  273. package/src/core/wasm/bridge.ts +11 -0
  274. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +212 -2
  275. package/src/core/websocket/transports/transport.ts +1 -1
  276. package/src/core/websocket/transports/ws.ts +1 -1
  277. package/src/core/websocket/types.ts +11 -1
  278. package/src/core/websocket/useMarimoKernelConnection.tsx +43 -8
  279. package/src/css/app/Cell.css +2 -0
  280. package/src/hooks/useDebounce.ts +2 -0
  281. package/src/plugins/core/BadPlugin.tsx +3 -14
  282. package/src/plugins/core/RenderHTML.tsx +22 -2
  283. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  284. package/src/plugins/core/registerReactComponent.tsx +0 -1
  285. package/src/plugins/impl/FormPlugin.tsx +2 -0
  286. package/src/plugins/impl/MatrixPlugin.tsx +2 -0
  287. package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
  288. package/src/plugins/impl/SliderPlugin.tsx +2 -0
  289. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
  290. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  291. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  292. package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
  293. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  294. package/src/stories/sandbox.stories.tsx +308 -0
  295. package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
  296. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  297. package/dist/_initCloneObject---vediN2.js +0 -95
  298. package/dist/arc-DOVLrCPd.js +0 -82
  299. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  300. package/dist/array-CApNbSU9.js +0 -6
  301. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  302. package/dist/assets/worker-DlIBfp9S.js +0 -98
  303. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  304. package/dist/chat-ui-DjTMZRVP.js +0 -8455
  305. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  306. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  307. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  308. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  309. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  310. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  311. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  312. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  313. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  314. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  315. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  316. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  317. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  318. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  319. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  320. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  321. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  322. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  323. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  324. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  325. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  326. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  327. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  328. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  329. package/dist/click-outside-container-D_URcm3D.js +0 -167
  330. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  331. package/dist/copy-CD7S58CY.js +0 -141
  332. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  333. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  334. package/dist/dist-3_o3T78I.js +0 -1360
  335. package/dist/dist-ABQjhuek.js +0 -64
  336. package/dist/dist-CO5R6VMi.js +0 -538
  337. package/dist/dropdown-menu-DhCfcscX.js +0 -5858
  338. package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
  339. package/dist/error-banner-CsXbEEjo.js +0 -611
  340. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  341. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  342. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  343. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  344. package/dist/line-CuKjIQa1.js +0 -34
  345. package/dist/map-BJpOfPlL.js +0 -149
  346. package/dist/math-BXtKgYah.js +0 -10
  347. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  348. package/dist/mermaid-Bi23Ibnw.js +0 -1173
  349. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  350. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  351. package/dist/path-BNHuHZP8.js +0 -87
  352. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  353. package/dist/purify.es-CB-YO1Hn.js +0 -774
  354. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  355. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  356. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  357. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  358. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  359. package/dist/schemas-DzK6U94N.js +0 -6057
  360. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  361. package/dist/step-CKczO72Q.js +0 -670
  362. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  363. package/dist/timer-DpDyj9G0.js +0 -596
  364. package/dist/tooltip-Dt77sBeT.js +0 -390
  365. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  366. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  367. package/dist/useTheme-CVJ0UOf2.js +0 -841
  368. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  369. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
  370. package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
@@ -1,7 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { useAtomValue, useStore } from "jotai";
4
- import { useMemo } from "react";
5
4
  import {
6
5
  useDeleteCellCallback,
7
6
  useDeleteManyCellsCallback,
@@ -130,21 +129,18 @@ export function usePendingDeleteService() {
130
129
  const { entries } = useAtomValue(pendingDeleteStateAtom);
131
130
  const deleteCell = useDeleteCellCallback();
132
131
  const deleteManyCells = useDeleteManyCellsCallback();
133
- return useMemo(
134
- () => ({
135
- submit: (cellIds: CellId[]) => {
136
- submit({ cellIds, deleteCell, deleteManyCells, store });
137
- },
138
- clear,
139
- get idle() {
140
- return entries.size === 0;
141
- },
142
- get shouldConfirmDelete() {
143
- return entries.size > 1;
144
- },
145
- }),
146
- [store, submit, clear, entries, deleteCell, deleteManyCells],
147
- );
132
+ return {
133
+ submit: (cellIds: CellId[]) => {
134
+ submit({ cellIds, deleteCell, deleteManyCells, store });
135
+ },
136
+ clear,
137
+ get idle() {
138
+ return entries.size === 0;
139
+ },
140
+ get shouldConfirmDelete() {
141
+ return entries.size > 1;
142
+ },
143
+ };
148
144
  }
149
145
 
150
146
  export function usePendingDelete(cellId: CellId) {
@@ -17,6 +17,7 @@ import type {
17
17
  import type { DataSourceConnection } from "@/core/datasets/data-source-connections";
18
18
  import {
19
19
  dataSourceConnectionsAtom,
20
+ exportedForTesting as dataSourceTesting,
20
21
  setLatestEngineSelected,
21
22
  } from "@/core/datasets/data-source-connections";
22
23
  import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines";
@@ -550,8 +551,8 @@ _df = mo.sql(
550
551
  const getLatestEngine = () =>
551
552
  store.get(dataSourceConnectionsAtom).latestEngineSelected;
552
553
 
553
- it("should use default engine initially", () => {
554
- expect(getLatestEngine()).toBe(DUCKDB_ENGINE);
554
+ it("should have no selected engine initially", () => {
555
+ expect(getLatestEngine()).toBeNull();
555
556
  });
556
557
 
557
558
  it("should persist the selected engine", () => {
@@ -622,6 +623,73 @@ _df = mo.sql(
622
623
  });
623
624
 
624
625
  describe("defaultCode", () => {
626
+ it("should prefer the newest usable connection until an engine is selected", () => {
627
+ const previousState = store.get(dataSourceConnectionsAtom);
628
+ const connection: DataSourceConnection = {
629
+ name: "first_connection" as ConnectionName,
630
+ source: "sqlite",
631
+ display_name: "SQLite",
632
+ dialect: "sqlite",
633
+ databases: [],
634
+ };
635
+ const newestConnection = {
636
+ ...connection,
637
+ name: "newest_connection" as ConnectionName,
638
+ };
639
+ const icebergConnection = {
640
+ ...connection,
641
+ name: "catalog" as ConnectionName,
642
+ source: "iceberg",
643
+ };
644
+ try {
645
+ store.set(dataSourceConnectionsAtom, {
646
+ latestEngineSelected: null,
647
+ connectionsMap: new Map(),
648
+ });
649
+ expect(adapter.defaultMetadata.engine).toBe(DUCKDB_ENGINE);
650
+ expect(adapter.defaultCode).toBe('_df = mo.sql(f"""SELECT * FROM """)');
651
+
652
+ store.set(dataSourceConnectionsAtom, {
653
+ latestEngineSelected: null,
654
+ connectionsMap: new Map([
655
+ [connection.name, connection],
656
+ [newestConnection.name, newestConnection],
657
+ [icebergConnection.name, icebergConnection],
658
+ [DUCKDB_ENGINE, { ...connection, name: DUCKDB_ENGINE }],
659
+ ]),
660
+ });
661
+ expect(adapter.defaultMetadata.engine).toBe(newestConnection.name);
662
+ expect(adapter.defaultCode).toContain("engine=newest_connection");
663
+ expect(
664
+ store.get(dataSourceConnectionsAtom).latestEngineSelected,
665
+ ).toBeNull();
666
+
667
+ const refreshConnection = (connection: DataSourceConnection) => {
668
+ store.set(
669
+ dataSourceConnectionsAtom,
670
+ dataSourceTesting.reducer(store.get(dataSourceConnectionsAtom), {
671
+ type: "addDataSourceConnection",
672
+ payload: { connections: [connection] },
673
+ }),
674
+ );
675
+ };
676
+ refreshConnection(connection);
677
+ expect(adapter.defaultMetadata.engine).toBe(connection.name);
678
+ expect(adapter.defaultCode).toContain("engine=first_connection");
679
+
680
+ setLatestEngineSelected(connection.name);
681
+ refreshConnection(newestConnection);
682
+ expect(adapter.defaultCode).toContain("engine=first_connection");
683
+
684
+ setLatestEngineSelected(DUCKDB_ENGINE);
685
+ refreshConnection(connection);
686
+ expect(adapter.defaultMetadata.engine).toBe(DUCKDB_ENGINE);
687
+ expect(adapter.defaultCode).toBe('_df = mo.sql(f"""SELECT * FROM """)');
688
+ } finally {
689
+ store.set(dataSourceConnectionsAtom, previousState);
690
+ }
691
+ });
692
+
625
693
  it("should include engine in defaultCode when selected", () => {
626
694
  const engine = "postgres_engine" as ConnectionName;
627
695
  setLatestEngineSelected(engine);
@@ -76,7 +76,22 @@ export interface SQLLanguageAdapterMetadata extends SQLMetadata {
76
76
  }
77
77
 
78
78
  function getLatestEngine(): ConnectionName {
79
- return store.get(dataSourceConnectionsAtom).latestEngineSelected;
79
+ const { latestEngineSelected, connectionsMap } = store.get(
80
+ dataSourceConnectionsAtom,
81
+ );
82
+ if (latestEngineSelected !== null) {
83
+ return latestEngineSelected;
84
+ }
85
+
86
+ // Map insertion order prefers the most recently discovered connection.
87
+ const connections = [...connectionsMap.values()].reverse();
88
+ return (
89
+ connections.find(
90
+ (connection) =>
91
+ !INTERNAL_SQL_ENGINES.has(connection.name) &&
92
+ connection.source !== "iceberg",
93
+ )?.name ?? DUCKDB_ENGINE
94
+ );
80
95
  }
81
96
 
82
97
  /**
@@ -47,7 +47,10 @@ const awarenessLogger = logger.get("awareness").disabled();
47
47
  const AWARENESS_PREFIX = "awareness:";
48
48
 
49
49
  // Utility functions for message handling
50
- function prefixMessage(token: string, message: Uint8Array): Uint8Array {
50
+ function prefixMessage(
51
+ token: string,
52
+ message: Uint8Array,
53
+ ): Uint8Array<ArrayBuffer> {
51
54
  const tokenBytes = new TextEncoder().encode(token);
52
55
  return new Uint8Array([...tokenBytes, ...message]);
53
56
  }
@@ -154,7 +157,7 @@ if (isRtcEnabled()) {
154
157
  doc.subscribeLocalUpdates((update) => {
155
158
  logger.debug("local update, sending to server");
156
159
  const ws = getWs();
157
- ws.send(update);
160
+ ws.send(new Uint8Array(update));
158
161
  });
159
162
 
160
163
  // Handle awareness changes
@@ -106,6 +106,7 @@ describe("data source connections", () => {
106
106
 
107
107
  let newState = addConnection(connections, state);
108
108
  expect(newState.connectionsMap.size).toBe(defaultConnSize + 2);
109
+ newState = { ...newState, latestEngineSelected: connections[0].name };
109
110
 
110
111
  newState = reducer(newState, {
111
112
  type: "removeDataSourceConnection",
@@ -113,6 +114,7 @@ describe("data source connections", () => {
113
114
  });
114
115
  expect(newState.connectionsMap.size).toBe(defaultConnSize + 1);
115
116
  expect(newState.connectionsMap.has("conn2" as ConnectionName)).toBe(true);
117
+ expect(newState.latestEngineSelected).toBeNull();
116
118
  });
117
119
 
118
120
  it("can clear all connections", () => {
@@ -44,7 +44,8 @@ export interface DataSourceConnection extends Omit<
44
44
  export type ConnectionsMap = ReadonlyMap<ConnectionName, DataSourceConnection>;
45
45
 
46
46
  export interface DataSourceState {
47
- latestEngineSelected: ConnectionName;
47
+ // Null permits automatic selection; DuckDB can also be an explicit choice.
48
+ latestEngineSelected: ConnectionName | null;
48
49
  connectionsMap: ConnectionsMap;
49
50
  }
50
51
 
@@ -110,7 +111,7 @@ function tableSchemaPath(sqlTableContext: SQLTableContext): string[] {
110
111
 
111
112
  function initialState(): DataSourceState {
112
113
  return {
113
- latestEngineSelected: DUCKDB_ENGINE,
114
+ latestEngineSelected: null,
114
115
  connectionsMap: initialConnections,
115
116
  };
116
117
  }
@@ -136,6 +137,8 @@ const {
136
137
  // Backend will dedupe by connection name & keep the latest, so we use this as the key
137
138
  const newMap = new Map(connectionsMap);
138
139
  for (const conn of opts.connections) {
140
+ // Refresh insertion order so automatic selection follows discovery recency.
141
+ newMap.delete(conn.name);
139
142
  newMap.set(conn.name, conn);
140
143
  }
141
144
 
@@ -161,16 +164,17 @@ const {
161
164
  }),
162
165
  );
163
166
  return {
164
- // If the latest engine selected is not in the new map, use the default engine
165
- latestEngineSelected: newMap.has(latestEngineSelected)
166
- ? latestEngineSelected
167
- : DUCKDB_ENGINE,
167
+ // Allow automatic selection again when the selected connection disappears.
168
+ latestEngineSelected:
169
+ latestEngineSelected && newMap.has(latestEngineSelected)
170
+ ? latestEngineSelected
171
+ : null,
168
172
  connectionsMap: newMap,
169
173
  };
170
174
  },
171
175
 
172
176
  clearDataSourceConnections: (): DataSourceState => ({
173
- latestEngineSelected: DUCKDB_ENGINE,
177
+ latestEngineSelected: null,
174
178
  connectionsMap: new Map(),
175
179
  }),
176
180
 
@@ -183,9 +187,10 @@ const {
183
187
  const newMap = new Map(connectionsMap);
184
188
  newMap.delete(connectionName);
185
189
  return {
186
- latestEngineSelected: newMap.has(latestEngineSelected)
187
- ? latestEngineSelected
188
- : DUCKDB_ENGINE,
190
+ latestEngineSelected:
191
+ latestEngineSelected && newMap.has(latestEngineSelected)
192
+ ? latestEngineSelected
193
+ : null,
189
194
  connectionsMap: newMap,
190
195
  };
191
196
  },
@@ -9,7 +9,8 @@ import { useAtomValue, useSetAtom } from "jotai";
9
9
  import { useEffect } from "react";
10
10
  import { NotStartedConnectionAlert } from "@/components/editor/alerts/connecting-alert";
11
11
  import { Controls } from "@/components/editor/controls/Controls";
12
- import { AppHeader } from "@/components/editor/header/app-header";
12
+ import { SandboxController } from "@/components/editor/chrome/panels/sandbox-controller";
13
+ import { ConnectionNotice } from "@/components/editor/alerts/connection-notice";
13
14
  import { FilenameForm } from "@/components/editor/header/filename-form";
14
15
  import { MultiCellActionToolbar } from "@/components/editor/navigation/multi-cell-action-toolbar";
15
16
  import { ViewerBanner } from "@/components/editor/viewer-banner";
@@ -158,6 +159,7 @@ export const EditApp: React.FC<AppProps> = ({
158
159
 
159
160
  return (
160
161
  <>
162
+ <SandboxController onReconnect={reconnect} />
161
163
  <AppContainer
162
164
  connection={connection}
163
165
  isRunning={isRunning}
@@ -165,10 +167,9 @@ export const EditApp: React.FC<AppProps> = ({
165
167
  onReconnect={reconnect}
166
168
  >
167
169
  <ViewerBanner />
168
- <AppHeader
169
- connection={connection}
170
+ <div
170
171
  className={cn(
171
- "pt-4 sm:pt-12 pb-2 mb-4 print:hidden z-50",
172
+ "pt-4 sm:pt-12 pb-6 print:hidden z-50",
172
173
  // Keep the header sticky when scrolling horizontally, for column mode
173
174
  "sticky left-0",
174
175
  )}
@@ -178,7 +179,9 @@ export const EditApp: React.FC<AppProps> = ({
178
179
  <FilenameForm filename={filename} />
179
180
  </div>
180
181
  )}
181
- </AppHeader>
182
+ </div>
183
+
184
+ <ConnectionNotice appConfig={appConfig} onRetry={reconnect} />
182
185
 
183
186
  {/* Don't render until we have a single cell. NotStartedConnectionAlert
184
187
  still covers the "no remote runtime started" prompt. */}
@@ -7,8 +7,7 @@ import { generateUUID } from "@/utils/uuid";
7
7
  import type { Banner } from "../kernel/messages";
8
8
 
9
9
  /**
10
- * Atom for storing kernel startup error message.
11
- * When set to a non-null value, shows a modal with the error details.
10
+ * Full startup diagnostics, retained until a new connection attempt or readiness.
12
11
  */
13
12
  export const kernelStartupErrorAtom = atom<string | null>(null);
14
13
 
@@ -19,6 +19,13 @@ import {
19
19
  } from "../parse";
20
20
  import { createMockIslandElement, createMockIslands } from "./test-utils.tsx";
21
21
 
22
+ function islandSnapshotPath(filename: string): string {
23
+ return new URL(
24
+ `../../../../../tests/_islands/snapshots/${filename}`,
25
+ import.meta.url,
26
+ ).pathname.replace(/^\/@fs/, "");
27
+ }
28
+
22
29
  function createPayloadCell(
23
30
  overrides: Partial<{
24
31
  cellId: string;
@@ -47,6 +54,7 @@ function appendPayload(
47
54
  payload: {
48
55
  schemaVersion: number;
49
56
  appId: string;
57
+ dependencies?: unknown;
50
58
  cells: ReturnType<typeof createPayloadCell>[];
51
59
  },
52
60
  ) {
@@ -58,6 +66,33 @@ function appendPayload(
58
66
  }
59
67
 
60
68
  describe("createMarimoFile", () => {
69
+ it("should serialize dependencies as top-level script metadata", () => {
70
+ const file = createMarimoFile({
71
+ dependencies: ['cowsay==6.1; sys_platform == "emscripten"'],
72
+ cells: [{ code: "import cowsay" }],
73
+ });
74
+ expect(file).toBe(
75
+ [
76
+ "# /// script",
77
+ '# dependencies = ["cowsay==6.1; sys_platform == \\"emscripten\\""]',
78
+ "# ///",
79
+ "import marimo",
80
+ "app = marimo.App()",
81
+ "@app.cell",
82
+ "def __():",
83
+ " import cowsay",
84
+ " return",
85
+ ].join("\n"),
86
+ );
87
+ });
88
+
89
+ it("should omit metadata for empty dependencies", () => {
90
+ const cells = [{ code: "import cowsay" }];
91
+ expect(createMarimoFile({ cells, dependencies: [] })).toBe(
92
+ createMarimoFile({ cells }),
93
+ );
94
+ });
95
+
61
96
  it("should return a string", () => {
62
97
  const app = {
63
98
  cells: [
@@ -736,13 +771,7 @@ describe("parseMarimoIslandApps", () => {
736
771
  });
737
772
 
738
773
  it("should parse Python-generated island payload snapshots", () => {
739
- const html = readFileSync(
740
- new URL(
741
- "../../../../../tests/_islands/snapshots/html-payload.txt",
742
- import.meta.url,
743
- ).pathname.replace(/^\/@fs/, ""),
744
- "utf8",
745
- );
774
+ const html = readFileSync(islandSnapshotPath("html-payload.txt"), "utf8");
746
775
  container.innerHTML = html;
747
776
 
748
777
  const result = parseMarimoIslandApps(container);
@@ -775,6 +804,108 @@ describe("parseMarimoIslandApps", () => {
775
804
  expect(islands[2].getAttribute(ISLAND_DATA_ATTRIBUTES.CELL_IDX)).toBe("1");
776
805
  });
777
806
 
807
+ it("should restore metadata from a Python-generated dependency payload", () => {
808
+ container.innerHTML = readFileSync(
809
+ islandSnapshotPath("body-dependencies.txt"),
810
+ "utf8",
811
+ );
812
+
813
+ const probed = parseMarimoIslandApps(container, { materialize: false });
814
+ const apps = parseMarimoIslandApps(container);
815
+
816
+ expect(probed).toEqual(apps);
817
+ expect(apps).toEqual([
818
+ {
819
+ id: "main",
820
+ payloadBacked: true,
821
+ dependencies: [
822
+ 'cowsay==6.1; sys_platform == "emscripten"',
823
+ "rich[jupyter]>=13",
824
+ "desktop; sys_platform != 'emscripten'",
825
+ "older-python; python_version < '3.13'",
826
+ "newer-python; python_version >= '3.13'",
827
+ ],
828
+ cells: [{ cellId: "Hbol", code: "import cowsay", output: "", idx: 0 }],
829
+ },
830
+ ]);
831
+ // The Python Pyodide test reads this file with the real metadata parser.
832
+ expect(createMarimoFile(apps[0])).toBe(
833
+ readFileSync(islandSnapshotPath("notebook-dependencies.txt"), "utf8"),
834
+ );
835
+ });
836
+
837
+ it("should carry dependencies from payloads into each generated notebook", () => {
838
+ for (const [appId, dependencies] of [
839
+ ["app1", ["cowsay==6.1"]],
840
+ ["app2", ["rich[jupyter]>=13"]],
841
+ ] as const) {
842
+ container.appendChild(
843
+ createMockIslandElement({ appId, cellId: "cell-1" }),
844
+ );
845
+ appendPayload(container, {
846
+ schemaVersion: 1,
847
+ appId,
848
+ dependencies,
849
+ cells: [createPayloadCell()],
850
+ });
851
+ }
852
+
853
+ const apps = parseMarimoIslandApps(container);
854
+ expect(apps.map((app) => [app.id, app.dependencies])).toEqual([
855
+ ["app1", ["cowsay==6.1"]],
856
+ ["app2", ["rich[jupyter]>=13"]],
857
+ ]);
858
+ expect(createMarimoFile(apps[0])).toContain(
859
+ '# /// script\n# dependencies = ["cowsay==6.1"]\n# ///\n',
860
+ );
861
+ });
862
+
863
+ it.each([null, "cowsay", [123], ["cowsay", null]])(
864
+ "should ignore payloads with malformed dependencies: %j",
865
+ (dependencies) => {
866
+ const island = createMockIslandElement({
867
+ appId: "app1",
868
+ cellId: "cell-1",
869
+ code: "import cowsay",
870
+ innerHTML: "<div>dom</div>",
871
+ });
872
+ island.setAttribute(ISLAND_DATA_ATTRIBUTES.REACTIVE, "true");
873
+ container.appendChild(island);
874
+ appendPayload(container, {
875
+ schemaVersion: 1,
876
+ appId: "app1",
877
+ dependencies,
878
+ cells: [createPayloadCell()],
879
+ });
880
+
881
+ expect(parseMarimoIslandApps(container)).toEqual([
882
+ {
883
+ id: "app1",
884
+ cells: [{ code: "import cowsay", output: "<div>dom</div>", idx: 0 }],
885
+ },
886
+ ]);
887
+ },
888
+ );
889
+
890
+ it("should merge dependencies from payloads belonging to the same app", () => {
891
+ for (const [cellId, dependencies] of [
892
+ ["cell-1", ["cowsay"]],
893
+ ["cell-2", ["cowsay", "rich"]],
894
+ ] as const) {
895
+ container.appendChild(createMockIslandElement({ appId: "app1", cellId }));
896
+ appendPayload(container, {
897
+ schemaVersion: 1,
898
+ appId: "app1",
899
+ dependencies,
900
+ cells: [createPayloadCell({ cellId })],
901
+ });
902
+ }
903
+
904
+ expect(
905
+ parseMarimoIslandApps(container).map((app) => app.dependencies),
906
+ ).toEqual([["cowsay", "rich"]]);
907
+ });
908
+
778
909
  it("should fall back to DOM islands for unsupported payload versions", () => {
779
910
  const island = createMockIslandElement({
780
911
  appId: "app1",
@@ -990,6 +1121,7 @@ describe("parseMarimoIslandApps", () => {
990
1121
  outputHtml: "<div>payload only</div>",
991
1122
  }),
992
1123
  ],
1124
+ dependencies: ["cowsay"],
993
1125
  });
994
1126
 
995
1127
  const result = parseMarimoIslandApps(container);
@@ -1076,6 +1208,7 @@ describe("parseMarimoIslandApps", () => {
1076
1208
  reactive: false,
1077
1209
  }),
1078
1210
  ],
1211
+ dependencies: ["cowsay"],
1079
1212
  });
1080
1213
 
1081
1214
  const result = parseMarimoIslandApps(container);
@@ -201,6 +201,7 @@ function handleMessage(
201
201
  case "storage-download-ready":
202
202
  case "secret-keys-result":
203
203
  case "startup-logs":
204
+ case "startup-progress":
204
205
  case "interrupted":
205
206
  case "reconnected":
206
207
  case "cache-cleared":
@@ -370,6 +370,9 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
370
370
  addPackage = throwNotImplemented;
371
371
  removePackage = throwNotImplemented;
372
372
  getPackageList = throwNotImplemented;
373
+ getSandbox = throwNotImplemented;
374
+ updateManifest = throwNotImplemented;
375
+ syncSandbox = throwNotImplemented;
373
376
  getDependencyTree = throwNotImplemented;
374
377
  getRecentFiles = throwNotImplemented;
375
378
  getWorkspaceFiles = throwNotImplemented;
@@ -30,6 +30,8 @@ export interface MarimoIslandApp {
30
30
  * Whether cells came from a supported JSON payload instead of DOM parsing.
31
31
  */
32
32
  payloadBacked?: boolean;
33
+ /** Explicit notebook dependencies to install before starting the app. */
34
+ dependencies?: string[];
33
35
  /**
34
36
  * Cells in the app.
35
37
  */
@@ -62,6 +64,7 @@ interface MarimoIslandCell {
62
64
  interface MarimoIslandPayload {
63
65
  schemaVersion: 1;
64
66
  appId: string;
67
+ dependencies?: string[];
65
68
  cells: MarimoIslandPayloadCell[];
66
69
  }
67
70
 
@@ -235,6 +238,12 @@ function parsePayloadBackedApps({
235
238
  embed?.setAttribute(ISLAND_DATA_ATTRIBUTES.CELL_IDX, idx.toString());
236
239
  }
237
240
  }
241
+ const app = apps.get(payload.appId);
242
+ if (app && payload.dependencies?.length) {
243
+ app.dependencies = [
244
+ ...new Set([...(app.dependencies ?? []), ...payload.dependencies]),
245
+ ];
246
+ }
238
247
  }
239
248
 
240
249
  // A supported payload is the runtime source for its app. Extra same-app DOM
@@ -371,6 +380,7 @@ export function parseIslandElement(
371
380
 
372
381
  export function createMarimoFile(app: {
373
382
  cells: { code: string; disabled?: boolean }[];
383
+ dependencies?: string[];
374
384
  }): string {
375
385
  const lines = [
376
386
  "import marimo",
@@ -402,6 +412,13 @@ export function createMarimoFile(app: {
402
412
  .join("\n"),
403
413
  ];
404
414
 
415
+ if (app.dependencies?.length) {
416
+ lines.unshift(
417
+ "# /// script",
418
+ `# dependencies = ${JSON.stringify(app.dependencies)}`,
419
+ "# ///",
420
+ );
421
+ }
405
422
  return lines.join("\n");
406
423
  }
407
424
 
@@ -507,6 +524,9 @@ function isMarimoIslandPayload(
507
524
  return (
508
525
  payload.schemaVersion === 1 &&
509
526
  typeof payload.appId === "string" &&
527
+ (payload.dependencies === undefined ||
528
+ (Array.isArray(payload.dependencies) &&
529
+ payload.dependencies.every((dep) => typeof dep === "string"))) &&
510
530
  Array.isArray(payload.cells) &&
511
531
  payload.cells.every(isMarimoIslandPayloadCell)
512
532
  );
@@ -0,0 +1,84 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import { atom } from "jotai";
3
+ import { kernelStartupErrorAtom } from "@/core/errors/state";
4
+ import { sandboxAtom, sandboxSyncAtom } from "@/core/packages/sandbox-state";
5
+ import { WebSocketClosedReason, WebSocketState } from "@/core/websocket/types";
6
+ import { connectionAtom } from "./connection";
7
+
8
+ export const connectionNoticeAtom = atom((get) => {
9
+ const connection = get(connectionAtom);
10
+ const backend = get(sandboxAtom)?.backend;
11
+ const sandbox = Boolean(backend);
12
+ const sync = get(sandboxSyncAtom);
13
+ if (
14
+ sandbox &&
15
+ (sync.pending || sync.error) &&
16
+ connection.state === WebSocketState.OPEN
17
+ ) {
18
+ return {
19
+ sandbox,
20
+ title: sync.pending ? "Syncing sandbox…" : "Sandbox sync failed",
21
+ description: sync.pending
22
+ ? "Applying the saved manifest to this notebook’s environment."
23
+ : "Review the error details, then try again.",
24
+ pending: sync.pending,
25
+ error: sync.error,
26
+ };
27
+ }
28
+ if (connection.state === WebSocketState.CONNECTING) {
29
+ const messages = {
30
+ "preparing-environment": {
31
+ title: backend
32
+ ? `Preparing ${backend} sandbox…`
33
+ : "Preparing environment…",
34
+ description:
35
+ "Getting this notebook’s Python environment ready. The first start can take a few minutes.",
36
+ },
37
+ "starting-kernel": {
38
+ title: "Starting notebook…",
39
+ description:
40
+ "The environment is prepared. Waiting for the Python kernel to connect to this notebook.",
41
+ },
42
+ reconnecting: {
43
+ title: "Reconnecting…",
44
+ description:
45
+ "The connection was interrupted. Your notebook and existing outputs stay visible while the kernel reconnects.",
46
+ },
47
+ };
48
+ return {
49
+ sandbox,
50
+ ...(connection.phase
51
+ ? messages[connection.phase]
52
+ : {
53
+ title: "Connecting…",
54
+ description: "Waiting for the notebook’s kernel to connect.",
55
+ }),
56
+ pending: true,
57
+ error: null,
58
+ };
59
+ }
60
+ if (connection.state === WebSocketState.CLOSED) {
61
+ const startupFailed =
62
+ connection.code === WebSocketClosedReason.KERNEL_STARTUP_ERROR;
63
+ const environmentFailed =
64
+ startupFailed && connection.phase === "preparing-environment";
65
+ return {
66
+ sandbox,
67
+ title: environmentFailed
68
+ ? "Sandbox setup failed"
69
+ : startupFailed
70
+ ? "Kernel failed to start"
71
+ : connection.reason,
72
+ description: environmentFailed
73
+ ? "The notebook can’t run yet."
74
+ : startupFailed
75
+ ? "The Python kernel could not start. Check the error details, then try again."
76
+ : "The connection to the notebook’s kernel was lost.",
77
+ pending: false,
78
+ error: startupFailed
79
+ ? (get(kernelStartupErrorAtom) ?? connection.reason)
80
+ : null,
81
+ };
82
+ }
83
+ return null;
84
+ });
@@ -93,6 +93,9 @@ const ACTIONS: Record<keyof AllRequests, Action> = {
93
93
  saveUserConfig: "throwError",
94
94
  sendShutdown: "throwError",
95
95
  getPackageList: "throwError",
96
+ getSandbox: "serverOnly",
97
+ updateManifest: "serverOnly",
98
+ syncSandbox: "serverOnly",
96
99
  getDependencyTree: "throwError",
97
100
  addPackage: "throwError",
98
101
  removePackage: "throwError",