@marimo-team/islands 0.24.3-dev5 → 0.24.3-dev50

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 (376) hide show
  1. package/dist/{ConnectedDataExplorerComponent-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
  2. package/dist/ErrorBoundary-BW0xr_AR.js +200 -0
  3. package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-Dlm5aWnH.js} +4 -4
  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-BdKqYmPi.js +138 -0
  46. package/dist/{common-xHoep60C.js → common-D9PY0k7A.js} +8839 -12646
  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-BZiw7m3d.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-BAHeJT2Q.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-Bp9hhneH.js} +2143 -1910
  105. package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
  106. package/dist/globals-BUgvsAck.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-C743iqsh.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-DwuC-61O.js → reveal-component-CgMzL2w5.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/columns.tsx +64 -67
  191. package/src/components/editor/RecoveryButton.tsx +1 -0
  192. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
  193. package/src/components/editor/ai/add-cell-with-ai.tsx +1 -0
  194. package/src/components/editor/ai/ai-completion-editor.tsx +3 -1
  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/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +98 -98
  213. package/src/components/editor/connections/database/__tests__/as-code.test.ts +11 -5
  214. package/src/components/editor/dynamic-favicon.tsx +17 -10
  215. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  216. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  217. package/src/components/editor/header/__tests__/status.test.tsx +8 -20
  218. package/src/components/editor/header/filename-input.tsx +2 -0
  219. package/src/components/editor/header/status.tsx +5 -3
  220. package/src/components/editor/notebook-cell.tsx +4 -2
  221. package/src/components/editor/output/JsonOutput.tsx +182 -632
  222. package/src/components/editor/output/Outputs.css +50 -17
  223. package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
  224. package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
  225. package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
  226. package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
  227. package/src/components/editor/output/json-output/formatting.ts +167 -0
  228. package/src/components/editor/output/json-output/pagination.ts +155 -0
  229. package/src/components/editor/output/json-output/renderers.tsx +196 -0
  230. package/src/components/editor/output/json-output/themes.ts +52 -0
  231. package/src/components/editor/renderers/cell-array.tsx +1 -5
  232. package/src/components/home/components.tsx +17 -0
  233. package/src/components/pages/gallery-page.tsx +2 -4
  234. package/src/components/pages/home-page.tsx +2 -4
  235. package/src/components/slides/slide-form.tsx +1 -0
  236. package/src/components/slides/slide-notes-editor.tsx +1 -0
  237. package/src/components/terminal/terminal.tsx +4 -4
  238. package/src/components/tracing/tracing-spec.ts +1 -1
  239. package/src/components/ui/table.tsx +1 -1
  240. package/src/components/ui/use-toast.ts +8 -0
  241. package/src/core/MarimoApp.tsx +0 -2
  242. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +259 -259
  243. package/src/core/cells/__tests__/cell.test.ts +61 -0
  244. package/src/core/cells/__tests__/cells.test.ts +37 -37
  245. package/src/core/cells/cell.ts +9 -1
  246. package/src/core/cells/pending-delete-service.ts +12 -16
  247. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  248. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  249. package/src/core/codemirror/rtc/extension.ts +5 -2
  250. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  251. package/src/core/datasets/data-source-connections.ts +15 -10
  252. package/src/core/edit-app.tsx +8 -5
  253. package/src/core/errors/state.ts +1 -2
  254. package/src/core/islands/__tests__/parse.test.ts +140 -7
  255. package/src/core/islands/bootstrap.ts +1 -0
  256. package/src/core/islands/bridge.ts +3 -0
  257. package/src/core/islands/parse.ts +20 -0
  258. package/src/core/network/connection-notice.ts +84 -0
  259. package/src/core/network/requests-lazy.ts +3 -0
  260. package/src/core/network/requests-network.ts +12 -0
  261. package/src/core/network/requests-static.ts +3 -0
  262. package/src/core/network/requests-toasting.tsx +3 -0
  263. package/src/core/network/resolve.ts +2 -1
  264. package/src/core/network/types.ts +7 -0
  265. package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
  266. package/src/core/packages/__tests__/useSandboxController.test.tsx +165 -0
  267. package/src/core/packages/package-data.ts +35 -0
  268. package/src/core/packages/sandbox-state.ts +15 -0
  269. package/src/core/packages/toast-components.tsx +11 -0
  270. package/src/core/packages/useInstallPackage.ts +1 -1
  271. package/src/core/packages/usePackageAction.ts +51 -0
  272. package/src/core/packages/usePackageDependencies.ts +22 -0
  273. package/src/core/packages/useSandboxController.ts +188 -0
  274. package/src/core/run-app.tsx +2 -0
  275. package/src/core/runtime/__tests__/runtime.test.ts +11 -0
  276. package/src/core/runtime/runtime.ts +7 -2
  277. package/src/core/wasm/bridge.ts +11 -0
  278. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +212 -2
  279. package/src/core/websocket/transports/transport.ts +1 -1
  280. package/src/core/websocket/transports/ws.ts +1 -1
  281. package/src/core/websocket/types.ts +11 -1
  282. package/src/core/websocket/useMarimoKernelConnection.tsx +43 -8
  283. package/src/css/app/Cell.css +2 -0
  284. package/src/hooks/useDebounce.ts +2 -0
  285. package/src/plugins/core/BadPlugin.tsx +3 -14
  286. package/src/plugins/core/RenderHTML.tsx +22 -2
  287. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  288. package/src/plugins/core/registerReactComponent.tsx +0 -1
  289. package/src/plugins/impl/FormPlugin.tsx +2 -0
  290. package/src/plugins/impl/MatrixPlugin.tsx +2 -0
  291. package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
  292. package/src/plugins/impl/SliderPlugin.tsx +2 -0
  293. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
  294. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  295. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +1 -1
  296. package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +15 -0
  297. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  298. package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
  299. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  300. package/src/stories/sandbox.stories.tsx +308 -0
  301. package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
  302. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  303. package/dist/_initCloneObject---vediN2.js +0 -95
  304. package/dist/arc-DOVLrCPd.js +0 -82
  305. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  306. package/dist/array-CApNbSU9.js +0 -6
  307. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  308. package/dist/assets/worker-DlIBfp9S.js +0 -98
  309. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  310. package/dist/chat-ui-DjTMZRVP.js +0 -8455
  311. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  312. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  313. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  314. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  315. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  316. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  317. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  318. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  319. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  320. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  321. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  322. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  323. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  324. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  325. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  326. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  327. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  328. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  329. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  330. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  331. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  332. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  333. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  334. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  335. package/dist/click-outside-container-D_URcm3D.js +0 -167
  336. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  337. package/dist/copy-CD7S58CY.js +0 -141
  338. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  339. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  340. package/dist/dist-3_o3T78I.js +0 -1360
  341. package/dist/dist-ABQjhuek.js +0 -64
  342. package/dist/dist-CO5R6VMi.js +0 -538
  343. package/dist/dropdown-menu-DhCfcscX.js +0 -5858
  344. package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
  345. package/dist/error-banner-CsXbEEjo.js +0 -611
  346. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  347. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  348. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  349. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  350. package/dist/line-CuKjIQa1.js +0 -34
  351. package/dist/map-BJpOfPlL.js +0 -149
  352. package/dist/math-BXtKgYah.js +0 -10
  353. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  354. package/dist/mermaid-Bi23Ibnw.js +0 -1173
  355. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  356. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  357. package/dist/path-BNHuHZP8.js +0 -87
  358. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  359. package/dist/purify.es-CB-YO1Hn.js +0 -774
  360. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  361. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  362. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  363. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  364. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  365. package/dist/schemas-DzK6U94N.js +0 -6057
  366. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  367. package/dist/step-CKczO72Q.js +0 -670
  368. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  369. package/dist/timer-DpDyj9G0.js +0 -596
  370. package/dist/tooltip-Dt77sBeT.js +0 -390
  371. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  372. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  373. package/dist/useTheme-CVJ0UOf2.js +0 -841
  374. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  375. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
  376. package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
@@ -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",
@@ -532,6 +532,18 @@ export function createNetworkRequests(): EditRequests & RunRequests {
532
532
  })
533
533
  .then(handleResponseReturnNull);
534
534
  },
535
+ getSandbox: (request) =>
536
+ getClient()
537
+ .POST("/api/packages/sandbox", { body: request, params: getParams() })
538
+ .then(handleResponse),
539
+ updateManifest: (request) =>
540
+ getClient()
541
+ .POST("/api/packages/manifest", { body: request, params: getParams() })
542
+ .then(handleResponse),
543
+ syncSandbox: (request) =>
544
+ getClient()
545
+ .POST("/api/packages/sync", { body: request, params: getParams() })
546
+ .then(handleResponse),
535
547
  addPackage: (request) => {
536
548
  return getClient()
537
549
  .POST("/api/packages/add", {
@@ -98,6 +98,9 @@ export function createStaticRequests(): EditRequests & RunRequests {
98
98
  addPackage: throwNotInEditMode,
99
99
  removePackage: throwNotInEditMode,
100
100
  getPackageList: throwNotInEditMode,
101
+ getSandbox: throwNotInEditMode,
102
+ updateManifest: throwNotInEditMode,
103
+ syncSandbox: throwNotInEditMode,
101
104
  getDependencyTree: throwNotInEditMode,
102
105
  listSecretKeys: throwNotInEditMode,
103
106
  writeSecret: throwNotInEditMode,
@@ -79,6 +79,9 @@ export function createErrorToastingRequests(
79
79
  addPackage: "Failed to add package",
80
80
  removePackage: "Failed to remove package",
81
81
  getPackageList: "Failed to get package list",
82
+ getSandbox: "",
83
+ updateManifest: "",
84
+ syncSandbox: "",
82
85
  getDependencyTree: "Failed to get dependency tree",
83
86
  listSecretKeys: "Failed to fetch secrets",
84
87
  writeSecret: "Failed to write secret",
@@ -1,4 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
+ import { withPackageInvalidation } from "../packages/package-data";
2
3
  import { getRuntimeManager } from "../runtime/config";
3
4
  import { isStaticNotebook } from "../static/static-state";
4
5
  import { PyodideBridge } from "../wasm/bridge";
@@ -20,5 +21,5 @@ export function resolveRequestClient(): EditRequests & RunRequests {
20
21
  getRuntimeManager(),
21
22
  );
22
23
  }
23
- return createErrorToastingRequests(base);
24
+ return withPackageInvalidation(createErrorToastingRequests(base));
24
25
  }
@@ -69,6 +69,10 @@ export type ListPackagesResponse = schemas["ListPackagesResponse"];
69
69
  export type DependencyTreeResponse = schemas["DependencyTreeResponse"];
70
70
  export type DependencyTreeNode = schemas["DependencyTreeNode"];
71
71
 
72
+ export type SandboxRequest = schemas["SandboxRequest"];
73
+ export type SandboxResponse = schemas["SandboxResponse"];
74
+ export type UpdateManifestRequest = schemas["UpdateManifestRequest"];
75
+ export type SyncSandboxResponse = schemas["SyncSandboxResponse"];
72
76
  export type PackageOperationResponse = schemas["PackageOperationResponse"];
73
77
  export type InstantiateNotebookRequest = schemas["InstantiateNotebookRequest"];
74
78
  export type MarimoConfig = schemas["MarimoConfig"];
@@ -246,6 +250,9 @@ export interface EditRequests {
246
250
  autoExportAsMarkdown: (request: AutoExportAsMarkdownRequest) => Promise<null>;
247
251
  autoExportAsIPYNB: (request: AutoExportAsIPYNBRequest) => Promise<null>;
248
252
  updateCellOutputs: (request: UpdateCellOutputsRequest) => Promise<null>;
253
+ getSandbox: (request: SandboxRequest) => Promise<SandboxResponse>;
254
+ updateManifest: (request: UpdateManifestRequest) => Promise<SandboxResponse>;
255
+ syncSandbox: (request: SandboxRequest) => Promise<SyncSandboxResponse>;
249
256
  // Package requests
250
257
  getPackageList: () => Promise<ListPackagesResponse>;
251
258
  getDependencyTree: () => Promise<DependencyTreeResponse>;
@@ -0,0 +1,129 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import { act, renderHook } from "@testing-library/react";
3
+ import { createStore, Provider } from "jotai";
4
+ import { beforeEach, describe, expect, it, vi } from "vitest";
5
+ import { MockRequestClient } from "@/__mocks__/requests";
6
+ import { toast } from "@/components/ui/use-toast";
7
+ import { requestClientAtom } from "@/core/network/requests";
8
+ import type { PackageOperationResponse } from "@/core/network/types";
9
+ import { usePackageAction } from "../usePackageAction";
10
+
11
+ vi.mock("@/components/ui/use-toast", () => ({ toast: vi.fn() }));
12
+
13
+ function setup(action: "upgrade" | "remove") {
14
+ const client = MockRequestClient.create();
15
+ const store = createStore();
16
+ store.set(requestClientAtom, client);
17
+ return {
18
+ request: vi.mocked(
19
+ action === "upgrade" ? client.addPackage : client.removePackage,
20
+ ),
21
+ ...renderHook(
22
+ () =>
23
+ usePackageAction(action, "numpy", [{ kind: "group", value: "dev" }]),
24
+ {
25
+ wrapper: ({ children }) => (
26
+ <Provider store={store}>{children}</Provider>
27
+ ),
28
+ },
29
+ ),
30
+ };
31
+ }
32
+
33
+ describe("usePackageAction", () => {
34
+ beforeEach(() => vi.clearAllMocks());
35
+
36
+ it.each([
37
+ { action: "upgrade", title: "Package upgraded", upgrade: true },
38
+ { action: "remove", title: "Package removed" },
39
+ ] as const)(
40
+ "preserves dependency groups and prevents duplicate $action requests",
41
+ async ({ action, title, ...options }) => {
42
+ const { result, request } = setup(action);
43
+ const { promise, resolve } =
44
+ Promise.withResolvers<PackageOperationResponse>();
45
+ request.mockReturnValue(promise);
46
+ let pending: Promise<void>;
47
+ act(() => {
48
+ pending = result.current.run();
49
+ });
50
+ expect(result.current.loading).toBe(true);
51
+ await act(async () => {
52
+ await result.current.run();
53
+ });
54
+ expect(request).toHaveBeenCalledExactlyOnceWith({
55
+ package: "numpy",
56
+ group: "dev",
57
+ ...options,
58
+ });
59
+ await act(async () => {
60
+ resolve({ success: true });
61
+ await pending;
62
+ });
63
+ expect(result.current.loading).toBe(false);
64
+ expect(toast).toHaveBeenCalledExactlyOnceWith(
65
+ expect.objectContaining({ title }),
66
+ );
67
+ },
68
+ );
69
+
70
+ it("reports saved changes requiring a restart without claiming success", async () => {
71
+ const { result, request } = setup("upgrade");
72
+ request.mockResolvedValue({ success: false, restartRequired: true });
73
+ await act(async () => {
74
+ await result.current.run();
75
+ });
76
+ expect(toast).toHaveBeenCalledExactlyOnceWith(
77
+ expect.objectContaining({
78
+ title: "Changes saved — restart required",
79
+ }),
80
+ );
81
+ });
82
+
83
+ it.each([
84
+ {
85
+ response: { success: false, error: "resolver failed" },
86
+ description: "resolver failed",
87
+ },
88
+ { response: { success: false }, description: expect.any(String) },
89
+ ])(
90
+ "reports failed responses as errors: $response",
91
+ async ({ response, description }) => {
92
+ const { result, request } = setup("remove");
93
+ request.mockResolvedValue(response);
94
+ await act(async () => {
95
+ await result.current.run();
96
+ });
97
+ expect(toast).toHaveBeenCalledExactlyOnceWith(
98
+ expect.objectContaining({
99
+ title: "Failed to remove package",
100
+ description,
101
+ variant: "danger",
102
+ }),
103
+ );
104
+ },
105
+ );
106
+
107
+ it("reports request errors and allows a retry", async () => {
108
+ const { result, request } = setup("remove");
109
+ request.mockRejectedValueOnce(new Error("offline"));
110
+ await act(async () => {
111
+ await result.current.run();
112
+ });
113
+ expect(toast).toHaveBeenCalledExactlyOnceWith(
114
+ expect.objectContaining({
115
+ title: "Failed to remove package",
116
+ description: "offline",
117
+ variant: "danger",
118
+ }),
119
+ );
120
+ expect(result.current.loading).toBe(false);
121
+ request.mockResolvedValue({ success: true });
122
+ await act(async () => {
123
+ await result.current.run();
124
+ });
125
+ expect(toast).toHaveBeenLastCalledWith(
126
+ expect.objectContaining({ title: "Package removed" }),
127
+ );
128
+ });
129
+ });