@marimo-team/islands 0.25.3-dev21 → 0.25.3-dev211

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 (717) hide show
  1. package/dist/{ConnectedDataExplorerComponent-DfG3PRaJ.js → ConnectedDataExplorerComponent-D6RHJV8D.js} +120 -116
  2. package/dist/{ErrorBoundary-ttSr7_91.js → ErrorBoundary-BpGAot_X.js} +16 -16
  3. package/dist/{abnfDiagram-VCTEODGH-B3w-XWX8.js → abnfDiagram-VCTEODGH-0q7Lbmii.js} +2 -2
  4. package/dist/any-language-editor-jGaR0EAo.js +75 -0
  5. package/dist/{architectureDiagram-5GKGNRK7-C18U9A6k.js → architectureDiagram-5GKGNRK7-1PydKPmE.js} +1 -1
  6. package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
  7. package/dist/assets/__vite-browser-external-CBRgnYY0.js +1 -0
  8. package/dist/assets/worker-DiPNP__U.js +113 -0
  9. package/dist/{button-CvjkwdSk.js → button-B6RjDKJx.js} +227 -217
  10. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CkVzWJEX.js} +2 -2
  11. package/dist/{chat-ui-w8SVynkn.js → chat-ui-B5pH_aXk.js} +1277 -1275
  12. package/dist/{check-BMKBBrdc.js → check-Z_vtI3OL.js} +1 -1
  13. package/dist/{chunk-IMKFNOWR-CrS5bzqW.js → chunk-IMKFNOWR-DEzZZ1Zc.js} +1 -1
  14. package/dist/{chunk-SHT3W25Y-StpvPvUG.js → chunk-SHT3W25Y-CuHj-hnn.js} +1 -1
  15. package/dist/{chunk-SVP7TREG-CBXjbYZC.js → chunk-SVP7TREG-BPiZK2bA.js} +1 -1
  16. package/dist/{chunk-TICWLB2K-Dp6bIb-q.js → chunk-TICWLB2K-DF6XcIjM.js} +1 -1
  17. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  18. package/dist/{classDiagram-ZZMXUADV-BFYuxV5g.js → classDiagram-ZZMXUADV-CMdR-cP4.js} +2 -2
  19. package/dist/{classDiagram-v2-VYDZK3BY-D_tjXVMl.js → classDiagram-v2-VYDZK3BY-DRvc3_7Y.js} +2 -2
  20. package/dist/code-visibility-B5trOyTh.js +134 -0
  21. package/dist/{common-CeebhhhO.js → common-BiM3Xm_d.js} +9837 -9658
  22. package/dist/config-DbjzjwxX.js +636 -0
  23. package/dist/{copy-icon-BgUO8jsi.js → copy-icon-CG57cxwb.js} +3 -3
  24. package/dist/createReducer-DePYJ0F3.js +63 -0
  25. package/dist/{cynefinDiagram-5FMLGOSQ-DSgYrHB2.js → cynefinDiagram-5FMLGOSQ-BkBjEY9l.js} +1 -1
  26. package/dist/{dagre-GXQ25YYZ-GYlruCBf.js → dagre-GXQ25YYZ-D-HEaW4I.js} +1 -1
  27. package/dist/{data-grid-overlay-editor-vxQ4E6k1.js → data-grid-overlay-editor-GxGkM-Al.js} +5 -5
  28. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  29. package/dist/{diagram-S7CK7UJ4-DRu5LX5_.js → diagram-S7CK7UJ4-Bn-oF-rB.js} +1 -1
  30. package/dist/{diagram-UQ7AKVKN-DD7uiejP.js → diagram-UQ7AKVKN-BpzzXWBj.js} +1 -1
  31. package/dist/{diagram-VX7I27RA-ByH9KAJJ.js → diagram-VX7I27RA-COOtvfBP.js} +1 -1
  32. package/dist/{diagram-Z3DM3KII-BsQHPRke.js → diagram-Z3DM3KII-K5cXvbrl.js} +1 -1
  33. package/dist/{dialog-Cc479ZEH.js → dialog-DsZ49mmU.js} +26 -26
  34. package/dist/{dist-Bvs24R_E.js → dist-11T5wq3_.js} +31 -30
  35. package/dist/{dist-F8Ep36rk.js → dist-17ugwGZc.js} +59 -58
  36. package/dist/{dist-BMQf5zIS.js → dist-7cRjf--y.js} +123 -122
  37. package/dist/{dist-diIx5qJW.js → dist-B8pkfkzc.js} +31 -30
  38. package/dist/{dist-CN_BeG2I.js → dist-B9UoM_wq.js} +58 -57
  39. package/dist/{dist-CLdpGQVr.js → dist-BGuMTs1i.js} +118 -117
  40. package/dist/{dist-BK4Oj99o.js → dist-BHW11fni.js} +18 -17
  41. package/dist/dist-BLY4m1Wi.js +850 -0
  42. package/dist/{dist-PXYI_yuP.js → dist-BNlcVoxs.js} +24 -23
  43. package/dist/{dist-D6d86eNJ.js → dist-BQYe5Bju.js} +47 -46
  44. package/dist/{dist-CkTTIdBe.js → dist-BX1mn8na.js} +337 -337
  45. package/dist/{dist-DiDibOYr.js → dist-Bh0PTKUW.js} +151 -150
  46. package/dist/{dist-CSJ0MDRw.js → dist-CKaXK92p.js} +56 -55
  47. package/dist/{dist-C8fAKSH1.js → dist-CLhwfhpJ.js} +53 -52
  48. package/dist/{dist-DoE4XJBC.js → dist-CYeqK4Xw.js} +9801 -10649
  49. package/dist/{dist-BLfKmR-l.js → dist-Cxlp3WH6.js} +16 -15
  50. package/dist/{dist-D-wwqlzJ.js → dist-DSJPGj42.js} +158 -157
  51. package/dist/{dist-BorMD-uX.js → dist-DU9ICsWZ.js} +75 -74
  52. package/dist/{dist-DBtSl3sf.js → dist-DWv0ALBi.js} +47 -46
  53. package/dist/{dist-OR1OnN-y.js → dist-DiBpWEsB.js} +31 -30
  54. package/dist/{dist-CrSP_H1M.js → dist-DiLFTlnl.js} +242 -242
  55. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  56. package/dist/{dist-CSbh1PNP.js → dist-cVDV5IuI.js} +23 -22
  57. package/dist/{dist-BuaRHxOc.js → dist-fRfaOoq8.js} +44 -43
  58. package/dist/{dist-Cg7gzw-a.js → dist-gTTI-9Px.js} +78 -77
  59. package/dist/dropdown-menu-CSNdPSnS.js +6083 -0
  60. package/dist/{ebnfDiagram-PWID7BFC-CQRK5_eT.js → ebnfDiagram-PWID7BFC-BI1ZmjVm.js} +2 -2
  61. package/dist/{erDiagram-RLTQ6QDP-BKtWrDVh.js → erDiagram-RLTQ6QDP-BtWjj9xy.js} +1 -1
  62. package/dist/{error-banner-CFPHFw4h.js → error-banner-IsonnvA0.js} +84 -83
  63. package/dist/error-entries-CRPfxMqm.js +2505 -0
  64. package/dist/{esm-D2gTsXEV.js → esm-BgKjMvWw.js} +530 -529
  65. package/dist/{esm-AMFssoNp.js → esm-CHjVSexr.js} +328 -329
  66. package/dist/feedback-button-CAxVqhvl.js +374 -0
  67. package/dist/{flowDiagram-HODETNUW-1IN-ih2E.js → flowDiagram-HODETNUW-DQvZh96A.js} +2 -2
  68. package/dist/{formats-X4mMQWzX.js → formats-BK4VefeF.js} +6 -6
  69. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  70. package/dist/{glide-data-editor-CSYHMRDu.js → glide-data-editor-CBX2wLtn.js} +417 -415
  71. package/dist/{glide-utils-DM9zBO4W.js → glide-utils-CQddGpa-.js} +16 -16
  72. package/dist/{globals-Fpiwkv4D.js → globals-DuCA4LSq.js} +3 -3
  73. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  74. package/dist/{error-entries-Damuuclv.js → html-to-image-CgAnxFi8.js} +26911 -26769
  75. package/dist/{infoDiagram-27XIBGKW-CkB-zr4p.js → infoDiagram-27XIBGKW-BdAObnc_.js} +1 -1
  76. package/dist/{ishikawaDiagram-5VMMS53U-wlyLjBmM.js → ishikawaDiagram-5VMMS53U-DP-jE8dw.js} +1 -1
  77. package/dist/{kanban-definition-UXKFOSKX-C2usY0i-.js → kanban-definition-UXKFOSKX-BkMgPjfm.js} +1 -1
  78. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  79. package/dist/{loader-BQOfjTIJ.js → loader-BisjOLiW.js} +12 -12
  80. package/dist/main.js +10128 -8127
  81. package/dist/{mermaid-BA-Z6wGL.js → mermaid-B-OFqheA.js} +52 -52
  82. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  83. package/dist/{mindmap-definition-YA3MSWOX-nKOWS8RR.js → mindmap-definition-YA3MSWOX-Du7toAZX.js} +1 -1
  84. package/dist/{number-overlay-editor-BOjqsq7D.js → number-overlay-editor-KvS7Rgw9.js} +3 -3
  85. package/dist/{dist-CN8zI-XC.js → objectWithoutPropertiesLoose-ai5NUqGa.js} +262 -240
  86. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  87. package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
  88. package/dist/{pegDiagram-XKGWAZYB-Dac9EIKD.js → pegDiagram-XKGWAZYB-CX_729j0.js} +2 -2
  89. package/dist/{pieDiagram-E7YTZNPT-B7S-DsW_.js → pieDiagram-E7YTZNPT-dtTFJcVI.js} +1 -1
  90. package/dist/precisionRound-DhAzeRcm.js +49 -0
  91. package/dist/{process-output-CTPTtxXB.js → process-output-Bmev5azU.js} +4 -4
  92. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  93. package/dist/{railroadDiagram-O6MQD6OU-Cfa5Q-hr.js → railroadDiagram-O6MQD6OU-Dsc2Cf4c.js} +2 -2
  94. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  95. package/dist/{requirementDiagram-BXWQKSXE-d8zXCJIk.js → requirementDiagram-BXWQKSXE-D3g0c60I.js} +1 -1
  96. package/dist/{reveal-component-Brpo7CP8.js → reveal-component-CqBvRKJz.js} +426 -403
  97. package/dist/schemas-CdscWNy_.js +4747 -0
  98. package/dist/select-BSxlITBo.js +1200 -0
  99. package/dist/{sequenceDiagram-WJ2MYXX4-b6pei3lJ.js → sequenceDiagram-WJ2MYXX4-w1pWbIpk.js} +1 -1
  100. package/dist/{spec-BJzgmvVa.js → spec-Dq8RNplp.js} +41 -11
  101. package/dist/{stateDiagram-D77RDMKH-Be-xSpaZ.js → stateDiagram-D77RDMKH-BCv7kP4H.js} +2 -2
  102. package/dist/{stateDiagram-v2-MP3YSRHH-5Y-FxesJ.js → stateDiagram-v2-MP3YSRHH-D1cTOt0x.js} +2 -2
  103. package/dist/static-state-BldGd99T.js +72 -0
  104. package/dist/strings-BGW-fXVJ.js +507 -0
  105. package/dist/style.css +1 -1
  106. package/dist/{swimlanes-42K2YHIH-nRRl4NU0.js → swimlanes-42K2YHIH-DNO6jDnd.js} +1 -1
  107. package/dist/{swimlanesDiagram-VR7AAH4N-BS79510V.js → swimlanesDiagram-VR7AAH4N-CkSWsxYJ.js} +2 -2
  108. package/dist/{swiper-component-DKntyn8p.js → swiper-component-Dir1o8ml.js} +2 -2
  109. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  110. package/dist/{timeline-definition-24CTP7MA-Cfzf8WPf.js → timeline-definition-24CTP7MA-DQvqGFM9.js} +1 -1
  111. package/dist/toast-BWIPi3aF.js +491 -0
  112. package/dist/{tooltip-CtBZ5q8p.js → tooltip-C3UnvsRe.js} +329 -305
  113. package/dist/use-restore-focus-BWO0z1lo.js +1672 -0
  114. package/dist/{useAsyncData-BD534XmW.js → useAsyncData-DsZMvNXn.js} +15 -14
  115. package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-ChB4eyim.js} +2 -2
  116. package/dist/{useDeepCompareMemoize-C72_RNsu.js → useDeepCompareMemoize-KMBBux8C.js} +1 -1
  117. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-cMNQ80CK.js} +1 -1
  118. package/dist/useLifecycle-BquH9ET-.js +112 -0
  119. package/dist/useTheme-B9C1JIy9.js +307 -0
  120. package/dist/utils-DXkj82sK.js +813 -0
  121. package/dist/{vega-component-DfcYgj-Y.js → vega-component-9NOEITbg.js} +170 -169
  122. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  123. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  124. package/dist/{vennDiagram-4TSXK5OY-CeY6Z1xZ.js → vennDiagram-4TSXK5OY-BfzXp4SH.js} +1 -1
  125. package/dist/{wardleyDiagram-VM6X3IG4-Cxs9NtVi.js → wardleyDiagram-VM6X3IG4-CiqEE8eq.js} +1 -1
  126. package/dist/{xychartDiagram-S5SC5T6Z-DNWbvPK7.js → xychartDiagram-S5SC5T6Z-BTIHCVOI.js} +2 -2
  127. package/package.json +16 -20
  128. package/src/__mocks__/document.tsx +63 -0
  129. package/src/__mocks__/notebook.ts +3 -4
  130. package/src/__mocks__/partial.ts +26 -0
  131. package/src/__mocks__/requests.ts +1 -4
  132. package/src/__tests__/main.test.tsx +24 -1
  133. package/src/__tests__/module-entry.test.ts +44 -0
  134. package/src/__tests__/mount.test.ts +1 -21
  135. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  136. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  137. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  138. package/src/components/app-config/ai-config.tsx +7 -2
  139. package/src/components/app-config/app-config-form.tsx +5 -9
  140. package/src/components/app-config/user-config-form.tsx +35 -56
  141. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  142. package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
  143. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  144. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  145. package/src/components/chat/acp/blocks.tsx +3 -2
  146. package/src/components/chat/acp/session-tabs.tsx +8 -3
  147. package/src/components/chat/chat-components.tsx +2 -0
  148. package/src/components/chat/chat-panel.tsx +20 -101
  149. package/src/components/chat/chat-utils.ts +4 -8
  150. package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
  151. package/src/components/chat/notebook-access-selector.tsx +100 -0
  152. package/src/components/data-table/TableBottomBar.tsx +4 -1
  153. package/src/components/data-table/TableTopBar.tsx +2 -0
  154. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  155. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  156. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  157. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  158. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  159. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  160. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  161. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  162. package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
  163. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  164. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  165. package/src/components/data-table/cell-selection/feature.ts +2 -2
  166. package/src/components/data-table/cell-selection/types.ts +2 -2
  167. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  168. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  169. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  170. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  171. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  172. package/src/components/data-table/charts/charts.tsx +40 -30
  173. package/src/components/data-table/charts/storage.ts +16 -5
  174. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  175. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  176. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  177. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  178. package/src/components/data-table/columns.tsx +45 -46
  179. package/src/components/data-table/context-menu.tsx +36 -20
  180. package/src/components/data-table/data-table.tsx +17 -1
  181. package/src/components/data-table/date-popover.tsx +6 -4
  182. package/src/components/data-table/export-actions.tsx +76 -48
  183. package/src/components/data-table/pagination.tsx +44 -33
  184. package/src/components/data-table/range-focus/atoms.ts +4 -6
  185. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  186. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  187. package/src/components/data-table/renderers.tsx +16 -7
  188. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  189. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  190. package/src/components/data-table/search-highlight.tsx +79 -0
  191. package/src/components/data-table/types.ts +1 -0
  192. package/src/components/data-table/url-detector.tsx +49 -9
  193. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  194. package/src/components/datasources/__tests__/column-preview.test.tsx +96 -5
  195. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  196. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  197. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  198. package/src/components/datasources/column-preview.tsx +17 -12
  199. package/src/components/datasources/datasources.tsx +56 -43
  200. package/src/components/datasources/utils.ts +32 -23
  201. package/src/components/debugger/debugger-code.tsx +5 -0
  202. package/src/components/dependency-graph/custom-node.tsx +1 -1
  203. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  204. package/src/components/dependency-graph/elements.ts +24 -21
  205. package/src/components/dependency-graph/minimap-content.tsx +13 -19
  206. package/src/components/dependency-graph/panels.tsx +4 -2
  207. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  208. package/src/components/editor/SortableCell.tsx +1 -3
  209. package/src/components/editor/__tests__/Output.test.tsx +50 -32
  210. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  211. package/src/components/editor/__tests__/data-attributes.test.tsx +28 -14
  212. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  213. package/src/components/editor/__tests__/output-persistence.test.tsx +6 -2
  214. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  215. package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
  216. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +34 -8
  217. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +2 -6
  218. package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +113 -0
  219. package/src/components/editor/actions/name-cell-input.tsx +4 -3
  220. package/src/components/editor/actions/pair-with-agent-commands.ts +2 -2
  221. package/src/components/editor/actions/pair-with-agent-modal.tsx +19 -16
  222. package/src/components/editor/actions/useCellActionButton.tsx +36 -31
  223. package/src/components/editor/actions/useConfigActions.tsx +3 -4
  224. package/src/components/editor/actions/useNotebookActions.tsx +19 -23
  225. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  226. package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
  227. package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
  228. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  229. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  230. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  231. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  232. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  233. package/src/components/editor/alerts/stdin-blocking-alert.tsx +1 -1
  234. package/src/components/editor/app-container.tsx +1 -1
  235. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  236. package/src/components/editor/cell/CreateCellButton.tsx +15 -21
  237. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  238. package/src/components/editor/cell/RunButton.tsx +2 -2
  239. package/src/components/editor/cell/StagedAICell.tsx +10 -2
  240. package/src/components/editor/cell/StopButton.tsx +2 -2
  241. package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +4 -2
  242. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  243. package/src/components/editor/cell/cell-actions.tsx +12 -1
  244. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  245. package/src/components/editor/cell/code/cell-editor.tsx +46 -165
  246. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  247. package/src/components/editor/cell/collapse.tsx +11 -4
  248. package/src/components/editor/cell/useAddCell.ts +4 -8
  249. package/src/components/editor/cell/useDeleteCell.tsx +10 -36
  250. package/src/components/editor/cell/useRunCells.ts +2 -5
  251. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  252. package/src/components/editor/cell/useSplitCell.tsx +10 -6
  253. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  254. package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
  255. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  256. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  257. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  258. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  259. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
  260. package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
  261. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  262. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  263. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  264. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  265. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  266. package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
  267. package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
  268. package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
  269. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +6 -9
  270. package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
  271. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +62 -3
  272. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  273. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  274. package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
  275. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  276. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  277. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  278. package/src/components/editor/chrome/wrapper/footer.tsx +2 -2
  279. package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
  280. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  281. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  282. package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
  283. package/src/components/editor/columns/cell-column.tsx +1 -1
  284. package/src/components/editor/columns/sortable-column.tsx +2 -2
  285. package/src/components/editor/connections/components.tsx +5 -10
  286. package/src/components/editor/controls/Controls.tsx +4 -4
  287. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  288. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  289. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +10 -4
  290. package/src/components/editor/controls/command-palette.tsx +22 -10
  291. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  292. package/src/components/editor/documentation.css +34 -11
  293. package/src/components/editor/dynamic-favicon.tsx +21 -40
  294. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +25 -20
  295. package/src/components/editor/errors/auto-fix.tsx +4 -8
  296. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  297. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  298. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  299. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  300. package/src/components/editor/file-tree/file-explorer.tsx +48 -15
  301. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  302. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  303. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  304. package/src/components/editor/header/__tests__/filename-form.test.tsx +1 -4
  305. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  306. package/src/components/editor/header/app-header.tsx +1 -1
  307. package/src/components/editor/header/filename-form.tsx +1 -1
  308. package/src/components/editor/header/status.tsx +40 -20
  309. package/src/components/editor/links/__tests__/cell-link.test.tsx +148 -0
  310. package/src/components/editor/links/cell-link-list.tsx +1 -1
  311. package/src/components/editor/links/cell-link.tsx +17 -7
  312. package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
  313. package/src/components/editor/navigation/__tests__/navigation.test.ts +108 -85
  314. package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
  315. package/src/components/editor/navigation/clipboard.ts +17 -14
  316. package/src/components/editor/navigation/focus-utils.ts +23 -4
  317. package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
  318. package/src/components/editor/navigation/navigation.ts +71 -70
  319. package/src/components/editor/navigation/selection.ts +30 -29
  320. package/src/components/editor/notebook-banner.tsx +1 -0
  321. package/src/components/editor/notebook-cell.tsx +29 -32
  322. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  323. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  324. package/src/components/editor/output/Outputs.css +8 -0
  325. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  326. package/src/components/editor/output/ansi-reduce.ts +33 -20
  327. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  328. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
  329. package/src/components/editor/package-alert.tsx +14 -7
  330. package/src/components/editor/renderers/cell-array.tsx +22 -33
  331. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  332. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -1
  333. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
  334. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
  335. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  336. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
  337. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
  338. package/src/components/editor/stdin-blocking-alert.tsx +1 -1
  339. package/src/components/home/components.tsx +17 -31
  340. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  341. package/src/components/icons/large-spinner.tsx +3 -14
  342. package/src/components/icons/spinner.tsx +1 -1
  343. package/src/components/markdown/markdown-renderer.tsx +4 -8
  344. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  345. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  346. package/src/components/pages/edit-page.tsx +19 -17
  347. package/src/components/pages/home-page.tsx +164 -91
  348. package/src/components/scratchpad/scratchpad.test.tsx +89 -0
  349. package/src/components/scratchpad/scratchpad.tsx +43 -32
  350. package/src/components/scratchpad/state.ts +7 -0
  351. package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
  352. package/src/components/slides/__tests__/minimap.test.ts +38 -19
  353. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
  354. package/src/components/slides/minimap.tsx +17 -12
  355. package/src/components/slides/reveal-component.tsx +58 -26
  356. package/src/components/slides/reveal-slides.css +5 -4
  357. package/src/components/slides/slide-cell-view.tsx +4 -5
  358. package/src/components/slides/slide-form.tsx +1 -0
  359. package/src/components/slides/slide-scroll-hint.tsx +3 -1
  360. package/src/components/sort/SortableCellsProvider.tsx +8 -25
  361. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  362. package/src/components/tracing/tracing.tsx +46 -42
  363. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  364. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  365. package/src/components/ui/alert-dialog.tsx +1 -1
  366. package/src/components/ui/draggable-popover.tsx +24 -2
  367. package/src/components/ui/range-slider.tsx +22 -9
  368. package/src/core/MarimoApp.tsx +1 -1
  369. package/src/core/ai/__tests__/staged-cells.test.ts +32 -33
  370. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
  371. package/src/core/ai/context/providers/cell-output.ts +2 -2
  372. package/src/core/ai/context/providers/datasource.ts +6 -2
  373. package/src/core/ai/staged-cells.ts +18 -19
  374. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +40 -88
  375. package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
  376. package/src/core/ai/tools/base.ts +18 -15
  377. package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
  378. package/src/core/ai/tools/registry.ts +13 -10
  379. package/src/core/ai/tools/sample-tool.ts +6 -7
  380. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -37
  381. package/src/core/cells/__tests__/actions.test.ts +624 -35
  382. package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
  383. package/src/core/cells/__tests__/arrange.test.ts +432 -0
  384. package/src/core/cells/__tests__/cell.test.ts +39 -0
  385. package/src/core/cells/__tests__/cells.test.ts +251 -2540
  386. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  387. package/src/core/cells/__tests__/document.test.ts +164 -0
  388. package/src/core/cells/__tests__/editor.test.ts +57 -0
  389. package/src/core/cells/__tests__/flush-document.test.ts +40 -0
  390. package/src/core/cells/__tests__/harness.ts +106 -0
  391. package/src/core/cells/__tests__/layout.test.ts +177 -0
  392. package/src/core/cells/__tests__/notebook-outline.test.ts +122 -0
  393. package/src/core/cells/__tests__/outputs.test.tsx +71 -53
  394. package/src/core/cells/__tests__/session.test.ts +445 -211
  395. package/src/core/cells/__tests__/utils.test.ts +9 -108
  396. package/src/core/cells/actions.ts +675 -6
  397. package/src/core/cells/add-missing-import.ts +47 -43
  398. package/src/core/cells/arrange.ts +529 -0
  399. package/src/core/cells/cell.ts +14 -3
  400. package/src/core/cells/cells.ts +126 -1363
  401. package/src/core/cells/columns.ts +38 -0
  402. package/src/core/cells/document.ts +178 -0
  403. package/src/core/cells/edit.ts +30 -0
  404. package/src/core/cells/editor.ts +82 -0
  405. package/src/core/cells/layout.ts +221 -0
  406. package/src/core/cells/outputs.ts +12 -28
  407. package/src/core/cells/pending-delete-service.ts +3 -7
  408. package/src/core/cells/session.ts +76 -53
  409. package/src/core/cells/types.ts +22 -6
  410. package/src/core/cells/utils.ts +10 -8
  411. package/src/core/codemirror/__tests__/format.test.ts +0 -34
  412. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  413. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  414. package/src/core/codemirror/ai/resources.ts +1 -1
  415. package/src/core/codemirror/cells/__tests__/extensions.test.ts +2 -6
  416. package/src/core/codemirror/cells/extensions.ts +30 -28
  417. package/src/core/codemirror/cells/state.ts +1 -6
  418. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
  419. package/src/core/codemirror/copilot/getCodes.ts +2 -2
  420. package/src/core/codemirror/format.ts +6 -23
  421. package/src/core/codemirror/keymaps/vim.ts +4 -8
  422. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  423. package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
  424. package/src/core/codemirror/language/cell-code.ts +114 -0
  425. package/src/core/codemirror/language/extension.ts +52 -35
  426. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  427. package/src/core/codemirror/language/languages/python.ts +16 -10
  428. package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
  429. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  430. package/src/core/codemirror/language/types.ts +7 -7
  431. package/src/core/codemirror/language/utils.ts +9 -39
  432. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
  433. package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
  434. package/src/core/codemirror/lsp/utils.ts +1 -1
  435. package/src/core/codemirror/misc/__tests__/paste.test.ts +3 -1
  436. package/src/core/codemirror/misc/paste.ts +1 -1
  437. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  438. package/src/core/codemirror/readonly/extension.ts +2 -2
  439. package/src/core/codemirror/utils.ts +1 -0
  440. package/src/core/config/__tests__/app-config.test.ts +64 -0
  441. package/src/core/config/__tests__/config-schema.test.ts +13 -6
  442. package/src/core/config/config-schema.ts +13 -4
  443. package/src/core/config/config.ts +26 -12
  444. package/src/core/config/feature-flag.tsx +0 -2
  445. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  446. package/src/core/datasets/data-source-discovery.ts +4 -6
  447. package/src/core/documentation/doc-lookup.ts +1 -1
  448. package/src/core/edit-app.tsx +21 -28
  449. package/src/core/errors/error-entries.ts +4 -1
  450. package/src/core/export/hooks.ts +1 -1
  451. package/src/core/export/layout.ts +2 -2
  452. package/src/core/hotkeys/actions.ts +2 -4
  453. package/src/core/islands/__tests__/bootstrap.test.ts +69 -17
  454. package/src/core/islands/__tests__/bridge.test.ts +72 -25
  455. package/src/core/islands/bootstrap.ts +46 -53
  456. package/src/core/islands/bridge.ts +75 -24
  457. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  458. package/src/core/islands/components/web-components.tsx +1 -1
  459. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  460. package/src/core/islands/worker/controller.ts +4 -10
  461. package/src/core/islands/worker/worker.tsx +33 -33
  462. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  463. package/src/core/kernel/__tests__/handlers.test.ts +7 -153
  464. package/src/core/kernel/handlers.ts +19 -72
  465. package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
  466. package/src/core/meta/code-visibility.ts +18 -9
  467. package/src/core/network/__tests__/connection.test.ts +1 -1
  468. package/src/core/network/__tests__/requests-lazy.test.ts +1 -3
  469. package/src/core/network/connection-notice.ts +1 -1
  470. package/src/core/network/connection.ts +1 -1
  471. package/src/core/network/requests-lazy.ts +2 -5
  472. package/src/core/network/requests-network.ts +5 -31
  473. package/src/core/network/requests-static.ts +1 -4
  474. package/src/core/network/requests-toasting.tsx +1 -4
  475. package/src/core/network/types.ts +6 -14
  476. package/src/core/network/useConnectionNotice.ts +8 -2
  477. package/src/core/notebook/__tests__/operations.test.ts +51 -0
  478. package/src/core/notebook/attachments.ts +38 -0
  479. package/src/core/notebook/document/__tests__/codemirror.test.ts +758 -0
  480. package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
  481. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  482. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  483. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  484. package/src/core/notebook/document/__tests__/model.test.ts +247 -0
  485. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  486. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  487. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  488. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  489. package/src/core/notebook/document/__tests__/state.test.ts +459 -0
  490. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  491. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  492. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  493. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  494. package/src/core/notebook/document/__tests__/user.ts +61 -0
  495. package/src/core/notebook/document/codemirror.ts +216 -0
  496. package/src/core/notebook/document/draft.ts +502 -0
  497. package/src/core/notebook/document/hooks.tsx +118 -0
  498. package/src/core/notebook/document/index.ts +24 -0
  499. package/src/core/notebook/document/model.ts +102 -0
  500. package/src/core/notebook/document/select.ts +41 -0
  501. package/src/core/notebook/document/state.ts +378 -0
  502. package/src/core/notebook/document/sync.ts +369 -0
  503. package/src/core/notebook/index.ts +19 -0
  504. package/src/core/notebook/operations.ts +30 -0
  505. package/src/core/notebook/replica/AGENTS.md +11 -0
  506. package/src/core/{host → notebook/replica}/__tests__/attachments.test.ts +9 -10
  507. package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
  508. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  509. package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
  510. package/src/core/notebook/replica/backend.ts +19 -0
  511. package/src/core/notebook/replica/connection.ts +42 -0
  512. package/src/core/notebook/replica/index.ts +13 -0
  513. package/src/core/notebook/replica/replica.ts +286 -0
  514. package/src/core/{host → notebook/replica}/resources/attachments.ts +6 -3
  515. package/src/core/{host → notebook/replica}/resources/document.ts +4 -4
  516. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  517. package/src/core/packages/useSandboxController.ts +1 -1
  518. package/src/core/run-app.tsx +48 -51
  519. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  520. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  521. package/src/core/runtime/__tests__/runtime.test.ts +32 -74
  522. package/src/core/runtime/adapter.ts +1 -1
  523. package/src/core/runtime/config.ts +2 -2
  524. package/src/core/runtime/runtime.ts +33 -46
  525. package/src/core/runtime/types.ts +0 -2
  526. package/src/core/saving/__tests__/document.test.tsx +123 -0
  527. package/src/core/saving/__tests__/state.test.ts +111 -0
  528. package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
  529. package/src/core/saving/document.ts +33 -0
  530. package/src/core/saving/filename.ts +1 -1
  531. package/src/core/saving/save-component.tsx +39 -60
  532. package/src/core/saving/state.ts +38 -39
  533. package/src/core/saving/useAutoSave.ts +17 -53
  534. package/src/core/session/__tests__/backend.test.ts +236 -0
  535. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +184 -0
  536. package/src/core/{websocket → session}/__tests__/useNotebookSession.hook.test.tsx +213 -262
  537. package/src/core/session/active-notebook.ts +28 -0
  538. package/src/core/session/backend.ts +123 -0
  539. package/src/core/session/embedded.ts +7 -0
  540. package/src/core/{websocket → session}/types.ts +2 -2
  541. package/src/core/session/useNotebookReplica.ts +74 -0
  542. package/src/core/{websocket → session}/useNotebookSession.tsx +77 -64
  543. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  544. package/src/core/state/jotai.ts +1 -1
  545. package/src/core/static/__tests__/files.test.ts +38 -10
  546. package/src/core/static/files.ts +2 -0
  547. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  548. package/src/core/transports/__tests__/server.test.ts +408 -0
  549. package/src/core/transports/__tests__/static.test.ts +306 -0
  550. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  551. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  552. package/src/core/transports/server.ts +152 -0
  553. package/src/core/transports/static.ts +166 -0
  554. package/src/core/transports/wasm.ts +97 -0
  555. package/src/core/wasm/__tests__/bridge.test.ts +105 -65
  556. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  557. package/src/core/wasm/bridge.ts +60 -71
  558. package/src/core/wasm/rpc.ts +15 -3
  559. package/src/core/wasm/store.ts +3 -3
  560. package/src/core/wasm/worker/bootstrap.ts +55 -51
  561. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  562. package/src/core/wasm/worker/save-worker.ts +9 -10
  563. package/src/core/wasm/worker/types.ts +29 -18
  564. package/src/core/wasm/worker/worker.ts +89 -45
  565. package/src/css/app/codemirror.css +1 -1
  566. package/src/css/globals.css +66 -22
  567. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  568. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  569. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  570. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  571. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  572. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  573. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  574. package/src/hooks/useAsyncData.ts +3 -3
  575. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  576. package/src/hooks/useDebounce.ts +6 -10
  577. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  578. package/src/hooks/useDelayElapsed.ts +14 -10
  579. package/src/hooks/useElapsedTime.ts +3 -3
  580. package/src/hooks/useEventListener.ts +1 -2
  581. package/src/hooks/useInputHistory.ts +4 -7
  582. package/src/hooks/useInternalStateWithSync.ts +6 -6
  583. package/src/hooks/useResizeObserver.ts +4 -7
  584. package/src/hooks/useScript.ts +67 -70
  585. package/src/hooks/useStateForKey.ts +93 -0
  586. package/src/mount.tsx +20 -15
  587. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  588. package/src/plugins/core/registerReactComponent.tsx +1 -1
  589. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  590. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  591. package/src/plugins/impl/DataTablePlugin.tsx +69 -37
  592. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  593. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  594. package/src/plugins/impl/FormPlugin.tsx +1 -1
  595. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  596. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  597. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  598. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
  599. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  600. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  601. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  602. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  603. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  604. package/src/plugins/impl/anywidget/model.ts +3 -1
  605. package/src/plugins/impl/anywidget/registry.ts +18 -14
  606. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  607. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  608. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  609. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  610. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  611. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  612. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  613. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  614. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  615. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  616. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  617. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  618. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  619. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  620. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  621. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  622. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  623. package/src/plugins/impl/panel/utils.ts +17 -0
  624. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  625. package/src/plugins/impl/plotly/selection.ts +25 -19
  626. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  627. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  628. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  629. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  630. package/src/stories/button.stories.tsx +1 -0
  631. package/src/stories/cell.stories.tsx +2 -5
  632. package/src/stories/data-table.stories.tsx +31 -0
  633. package/src/stories/editor.stories.tsx +24 -17
  634. package/src/stories/form-wrapper.stories.tsx +2 -2
  635. package/src/stories/layout/vertical/one-column.stories.tsx +28 -23
  636. package/src/stories/runtime-story.tsx +23 -17
  637. package/src/stories/select.stories.tsx +2 -2
  638. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  639. package/src/utils/__tests__/arrays.test.ts +35 -0
  640. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  641. package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +29 -0
  642. package/src/utils/__tests__/numbers.test.ts +105 -1
  643. package/src/utils/__tests__/objects.test.ts +21 -0
  644. package/src/utils/arrays.ts +11 -2
  645. package/src/utils/blob.ts +1 -1
  646. package/src/utils/createReducer.ts +53 -26
  647. package/src/utils/maps.ts +0 -3
  648. package/src/utils/numbers.ts +79 -18
  649. package/src/utils/objects.ts +4 -9
  650. package/src/utils/once.ts +19 -19
  651. package/src/utils/tracer.ts +9 -5
  652. package/src/utils/zod-utils.ts +1 -3
  653. package/dist/any-language-editor-D4q-IFcM.js +0 -76
  654. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  655. package/dist/assets/worker-HPY9fbhz.js +0 -114
  656. package/dist/code-visibility-DPm4oWK1.js +0 -138
  657. package/dist/dropdown-menu-DHP9P4VE.js +0 -4678
  658. package/dist/feedback-button-DVgw4Y7F.js +0 -379
  659. package/dist/html-to-image-BdA59IUD.js +0 -3251
  660. package/dist/label-DoysmLMW.js +0 -281
  661. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  662. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +0 -23
  663. package/dist/precisionRound-DMIVQrt2.js +0 -97
  664. package/dist/select-DemoKT4G.js +0 -1344
  665. package/dist/toDate-B5mIgxwZ.js +0 -1185
  666. package/dist/toast-PkdZraM8.js +0 -1830
  667. package/dist/use-restore-focus-CKjfFjLM.js +0 -6369
  668. package/dist/useLifecycle-BGWzTwHK.js +0 -169
  669. package/dist/useTheme-BhQvec43.js +0 -904
  670. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
  671. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
  672. package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
  673. package/src/components/editor/navigation/state.ts +0 -65
  674. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
  675. package/src/core/ai/tools/run-cells-tool.ts +0 -303
  676. package/src/core/attachments/state.ts +0 -18
  677. package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
  678. package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
  679. package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
  680. package/src/core/cells/document-changes.ts +0 -944
  681. package/src/core/codemirror/rtc/extension.ts +0 -453
  682. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
  683. package/src/core/codemirror/rtc/loro/awareness.ts +0 -531
  684. package/src/core/codemirror/rtc/loro/colors.ts +0 -38
  685. package/src/core/codemirror/rtc/loro/sync.ts +0 -168
  686. package/src/core/host/AGENTS.md +0 -11
  687. package/src/core/host/__tests__/events.test.ts +0 -46
  688. package/src/core/host/__tests__/fixtures.ts +0 -39
  689. package/src/core/host/__tests__/notebook-client.test.ts +0 -433
  690. package/src/core/host/__tests__/protocol.test.ts +0 -214
  691. package/src/core/host/__tests__/stream.test.ts +0 -211
  692. package/src/core/host/connection.ts +0 -81
  693. package/src/core/host/events.ts +0 -61
  694. package/src/core/host/notebook-client.ts +0 -290
  695. package/src/core/host/protocol.ts +0 -1943
  696. package/src/core/host/resources/resource.ts +0 -59
  697. package/src/core/host/stream.ts +0 -213
  698. package/src/core/rtc/state.ts +0 -34
  699. package/src/core/state/__tests__/jotai.test.ts +0 -25
  700. package/src/core/wasm/worker/message-buffer.ts +0 -33
  701. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  702. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -170
  703. package/src/core/websocket/state.ts +0 -7
  704. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  705. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  706. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  707. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  708. package/src/core/websocket/transports/basic.ts +0 -102
  709. package/src/core/websocket/transports/create.ts +0 -31
  710. package/src/core/websocket/transports/sse.ts +0 -308
  711. package/src/core/websocket/transports/transport.ts +0 -50
  712. package/src/core/websocket/transports/ws.ts +0 -98
  713. package/src/core/websocket/useNotebookClient.ts +0 -88
  714. package/src/utils/__tests__/id-tree.test.ts +0 -2145
  715. package/src/utils/id-tree.tsx +0 -1134
  716. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  717. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
+ import { createRPCRequestHandler } from "rpc-anywhere";
4
5
  import { toast } from "@/components/ui/use-toast";
5
6
  import { userConfigAtom } from "@/core/config/config";
6
7
  import { serializeBlob } from "@/utils/blob";
@@ -8,9 +9,12 @@ import { Deferred } from "@/utils/Deferred";
8
9
  import { throwNotImplemented } from "@/utils/functions";
9
10
  import { Logger } from "@/utils/Logger";
10
11
  import { reloadSafe } from "@/utils/reload-safe";
12
+ import { once } from "@/utils/once";
11
13
  import { generateUUID } from "@/utils/uuid";
12
14
  import { createModuleWorker } from "@/utils/worker";
13
15
  import { notebookIsRunningAtom } from "../cells/cells";
16
+ import { flushDocument } from "../cells/document";
17
+ import { createWasmNotebookBackend } from "../transports/wasm";
14
18
  import type { ClientCommand } from "../kernel/messages";
15
19
  import { getInitialAppMode } from "../mode";
16
20
  import { API } from "../network/api";
@@ -38,10 +42,8 @@ import type {
38
42
  } from "../network/types";
39
43
  import { filenameAtom } from "../saving/file-state";
40
44
  import { store } from "../state/jotai";
41
- import { BasicTransport } from "../websocket/transports/basic";
42
- import type { IConnectionTransport } from "../websocket/transports/transport";
43
45
  import { PyodideRouter } from "./router";
44
- import { getWorkerRPC } from "./rpc";
46
+ import { getWorkerRPC, type PersistNotebookRequest } from "./rpc";
45
47
  import { getWasmRuntimeConfig } from "./runtime-config";
46
48
  import { createShareableLink } from "./share";
47
49
  import { wasmInitStateAtom } from "./state";
@@ -68,11 +70,8 @@ export class PyodideBridge implements RunRequests, EditRequests {
68
70
 
69
71
  private rpc!: ReturnType<typeof getWorkerRPC<WorkerSchema>>;
70
72
  private saveRpc: SaveWorker | undefined;
71
- private pendingSessionSave: Promise<unknown> = Promise.resolve();
73
+ private notebookConsumers = new Map<string, (event: unknown) => void>();
72
74
  private interruptBuffer?: Uint8Array;
73
- private messageConsumer:
74
- | ((message: MessageEvent<string>) => void)
75
- | undefined;
76
75
 
77
76
  public initialized = new Deferred<void>();
78
77
 
@@ -82,7 +81,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
82
81
  return {
83
82
  readFile: throwNotImplemented,
84
83
  readNotebook: async () => (await notebookFileStore.readFile()) ?? "",
85
- saveNotebook: throwNotImplemented,
84
+ writeNotebook: throwNotImplemented,
86
85
  };
87
86
  }
88
87
 
@@ -97,7 +96,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
97
96
  },
98
97
  );
99
98
 
100
- const rpc = getWorkerRPC<SaveWorkerSchema>(saveWorker);
99
+ const rpc = getWorkerRPC<SaveWorkerSchema>(saveWorker, undefined, Infinity);
101
100
  rpc.send.bootstrap(runtimeConfig);
102
101
  return rpc.proxy.request;
103
102
  }
@@ -116,9 +115,28 @@ export class PyodideBridge implements RunRequests, EditRequests {
116
115
  });
117
116
 
118
117
  // Create the RPC
119
- this.rpc = getWorkerRPC<WorkerSchema>(worker);
118
+ this.rpc = getWorkerRPC<WorkerSchema>(
119
+ worker,
120
+ createRPCRequestHandler({
121
+ persistNotebook: async (snapshot: PersistNotebookRequest) => {
122
+ if (!this.saveRpc) {
123
+ throw new Error("Notebook storage is not initialized");
124
+ }
125
+ await this.saveRpc.writeNotebook(snapshot);
126
+ notebookFileStore.saveFile(snapshot.contents);
127
+ fallbackFileStore.saveFile(snapshot.contents);
128
+ return null;
129
+ },
130
+ }),
131
+ // Synchronous Python execution can block worker requests indefinitely.
132
+ Infinity,
133
+ );
120
134
  this.rpc.send.bootstrap(runtimeConfig);
121
135
 
136
+ this.rpc.addMessageListener("notebookEvent", ({ id, event }) => {
137
+ this.notebookConsumers.get(id)?.(JSON.parse(event));
138
+ });
139
+
122
140
  // Listeners
123
141
  this.rpc.addMessageListener("ready", () => {
124
142
  this.startSession();
@@ -154,9 +172,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
154
172
  store.set(wasmInitStateAtom, { kind: "error", message: error });
155
173
  this.initialized.reject(new Error(error));
156
174
  });
157
- this.rpc.addMessageListener("kernelMessage", ({ message }) => {
158
- this.messageConsumer?.(new MessageEvent("message", { data: message }));
159
- });
160
175
  }
161
176
 
162
177
  private async startSession() {
@@ -208,11 +223,31 @@ export class PyodideBridge implements RunRequests, EditRequests {
208
223
  }
209
224
  }
210
225
 
211
- public attachMessageConsumer(
212
- consumer: (message: MessageEvent<string>) => void,
213
- ) {
214
- this.messageConsumer = consumer;
215
- this.rpc.proxy.send.consumerReady({});
226
+ public async createNotebookBackend() {
227
+ await this.initialized.promise;
228
+ return createWasmNotebookBackend({
229
+ subscribe: async (cursor, emit, signal) => {
230
+ signal.throwIfAborted();
231
+ const id = generateUUID();
232
+ this.notebookConsumers.set(id, emit);
233
+ const close = once(() => {
234
+ signal.removeEventListener("abort", close);
235
+ this.notebookConsumers.delete(id);
236
+ void this.rpc.proxy.request
237
+ .notebookUnsubscribe(id)
238
+ .catch(Logger.error);
239
+ });
240
+ signal.addEventListener("abort", close, { once: true });
241
+ try {
242
+ await this.rpc.proxy.request.notebookSubscribe({ id, cursor });
243
+ return close;
244
+ } catch (error) {
245
+ close();
246
+ throw error;
247
+ }
248
+ },
249
+ call: (call) => this.rpc.proxy.request.notebookCall(call),
250
+ });
216
251
  }
217
252
 
218
253
  public sendRename: EditRequests["sendRename"] = async ({ filename }) => {
@@ -230,30 +265,8 @@ export class PyodideBridge implements RunRequests, EditRequests {
230
265
  return null;
231
266
  };
232
267
 
233
- public sendSave: EditRequests["sendSave"] = async (request) => {
234
- if (!this.saveRpc) {
235
- Logger.warn("Save RPC not initialized");
236
- return null;
237
- }
238
-
239
- const durableSave = this.saveRpc.saveNotebook(request);
240
- // Generated exports read the session-owned app in the main worker.
241
- this.pendingSessionSave = this.pendingSessionSave
242
- .catch(() => undefined)
243
- .then(async () => {
244
- await durableSave;
245
- await this.rpc.proxy.request.saveNotebook(request);
246
- });
247
- void this.pendingSessionSave.catch((error) => {
248
- Logger.error(error);
249
- });
250
-
251
- await durableSave;
252
- const code = await this.readCode();
253
- if (code.contents) {
254
- notebookFileStore.saveFile(code.contents);
255
- fallbackFileStore.saveFile(code.contents);
256
- }
268
+ public saveLayout: EditRequests["saveLayout"] = async ({ layout }) => {
269
+ await this.rpc.proxy.request.setNotebookLayout(layout ?? null);
257
270
  return null;
258
271
  };
259
272
 
@@ -316,14 +329,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
316
329
  return response as FormatResponse;
317
330
  };
318
331
 
319
- public sendDeleteCell: EditRequests["sendDeleteCell"] = async (request) => {
320
- await this.putControlRequest({
321
- type: "delete-cell",
322
- ...request,
323
- });
324
- return null;
325
- };
326
-
327
332
  public sendInstallMissingPackages: EditRequests["sendInstallMissingPackages"] =
328
333
  async (request) => {
329
334
  this.putControlRequest({
@@ -373,14 +378,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
373
378
  return null;
374
379
  };
375
380
 
376
- public saveCellConfig: EditRequests["saveCellConfig"] = async (request) => {
377
- await this.putControlRequest({
378
- type: "update-cell-config",
379
- ...request,
380
- });
381
- return null;
382
- };
383
-
384
381
  public sendRestart = async (): Promise<null> => {
385
382
  // Save first
386
383
  const code = await this.readCode();
@@ -409,7 +406,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
409
406
  return response as Snippets;
410
407
  };
411
408
 
412
- public openFile: EditRequests["openFile"] = async ({ path }) => {
409
+ public openFile: EditRequests["openFile"] = async () => {
413
410
  const url = createShareableLink({
414
411
  code: null,
415
412
  baseUrl: window.location.origin,
@@ -453,7 +450,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
453
450
  return null;
454
451
  };
455
452
 
456
- public sendInstantiate: RunRequests["sendInstantiate"] = async (request) => {
453
+ public sendInstantiate: RunRequests["sendInstantiate"] = async () => {
457
454
  return null;
458
455
  };
459
456
 
@@ -535,7 +532,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
535
532
  public exportAsHTML: EditRequests["exportAsHTML"] = async (
536
533
  request: ExportAsHTMLRequest,
537
534
  ) => {
538
- await this.pendingSessionSave;
535
+ await flushDocument();
539
536
  const response = await this.rpc.proxy.request.bridge({
540
537
  functionName: "export_html",
541
538
  payload: withDevAssetUrl(request),
@@ -546,7 +543,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
546
543
  public exportAsMarkdown: EditRequests["exportAsMarkdown"] = async (
547
544
  request: ExportAsMarkdownRequest,
548
545
  ) => {
549
- await this.pendingSessionSave;
546
+ await flushDocument();
550
547
  const response = await this.rpc.proxy.request.bridge({
551
548
  functionName: "export_markdown",
552
549
  payload: request,
@@ -557,7 +554,7 @@ export class PyodideBridge implements RunRequests, EditRequests {
557
554
  public exportAsScript: EditRequests["exportAsScript"] = async (
558
555
  request: ExportAsScriptRequest,
559
556
  ) => {
560
- await this.pendingSessionSave;
557
+ await flushDocument();
561
558
  const response = await this.rpc.proxy.request.bridge({
562
559
  functionName: "export_script",
563
560
  payload: request,
@@ -628,8 +625,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
628
625
  return null;
629
626
  };
630
627
 
631
- public sendDocumentTransaction = () => Promise.resolve(null);
632
-
633
628
  public addPackage: EditRequests["addPackage"] = async (request) => {
634
629
  return this.rpc.proxy.request.addPackage(request);
635
630
  };
@@ -719,12 +714,6 @@ export class PyodideBridge implements RunRequests, EditRequests {
719
714
  }
720
715
  }
721
716
 
722
- export function createPyodideConnection(): IConnectionTransport {
723
- return BasicTransport.withProducerCallback((callback) => {
724
- PyodideBridge.INSTANCE.attachMessageConsumer(callback);
725
- });
726
- }
727
-
728
717
  // Compose the worker name. The optional "::controller" suffix tells
729
718
  // getController.ts that the host page provides a custom /wasm/controller.js
730
719
  // and that the dynamic import should be attempted. Hosts opt in by setting
@@ -9,19 +9,31 @@ import { Logger } from "@/utils/Logger";
9
9
  import type { WasmRuntimeConfig } from "./runtime-config";
10
10
  import { TRANSPORT_ID } from "./worker/constants";
11
11
 
12
+ export interface PersistNotebookRequest {
13
+ filename: string;
14
+ contents: string;
15
+ }
16
+
12
17
  export type ParentSchema = RPCSchema<{
18
+ requests: {
19
+ persistNotebook: { params: PersistNotebookRequest; response: null };
20
+ };
13
21
  messages: {
14
- consumerReady: {};
15
22
  bootstrap: WasmRuntimeConfig;
16
23
  };
17
24
  }>;
18
25
 
19
- export function getWorkerRPC<WorkerSchema extends RPCSchema>(worker: Worker) {
26
+ export function getWorkerRPC<WorkerSchema extends RPCSchema>(
27
+ worker: Worker,
28
+ requestHandler?: RPCOptions<ParentSchema, WorkerSchema>["requestHandler"],
29
+ maxRequestTime = 20_000,
30
+ ) {
20
31
  return createRPC<ParentSchema, WorkerSchema>({
21
32
  transport: createWorkerTransport(worker, {
22
33
  transportId: TRANSPORT_ID,
23
34
  }),
24
- maxRequestTime: 20_000, // 20 seconds
35
+ requestHandler,
36
+ maxRequestTime,
25
37
  _debugHooks: {
26
38
  onSend: (message) => {
27
39
  Logger.debug("[rpc] Parent -> Worker", message);
@@ -41,7 +41,7 @@ const urlFileStore: FileStore = {
41
41
  };
42
42
 
43
43
  export const domElementFileStore: FileStore = {
44
- saveFile(contents: string) {
44
+ saveFile(_contents: string) {
45
45
  // Do nothing
46
46
  },
47
47
  readFile() {
@@ -54,7 +54,7 @@ export const domElementFileStore: FileStore = {
54
54
  };
55
55
 
56
56
  const remoteDefaultFileStore: FileStore = {
57
- saveFile(contents: string) {
57
+ saveFile(_contents: string) {
58
58
  // Do nothing
59
59
  },
60
60
  readFile() {
@@ -79,7 +79,7 @@ export const mountConfigFileStore: FileStore = {
79
79
  };
80
80
 
81
81
  const emptyFileStore: FileStore = {
82
- saveFile(contents: string) {
82
+ saveFile(_contents: string) {
83
83
  // Do nothing
84
84
  },
85
85
  readFile() {
@@ -1,15 +1,13 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import { loadPyodide, type PyodideInterface } from "pyodide";
3
3
  import type { PyCallable, PyProxy } from "pyodide/ffi";
4
- import type { UserConfig } from "@/core/config/config-schema";
5
- import type { NotificationPayload } from "@/core/kernel/messages";
6
- import type { JsonString } from "@/utils/json/base64";
7
4
  import { invariant } from "../../../utils/invariant";
5
+ import { once } from "../../../utils/once";
8
6
  import { Logger } from "../../../utils/Logger";
9
7
  import { WasmFileSystem } from "./fs";
10
8
  import { getMarimoWheel } from "./getMarimoWheel";
11
9
  import { t } from "./tracer";
12
- import type { SerializedBridge, WasmController } from "./types";
10
+ import type { SerializedBridge, WasmController, WasmSession } from "./types";
13
11
  import { shouldLoadDuckDBPackages } from "../utils";
14
12
 
15
13
  const MAKE_SNAPSHOT = false;
@@ -45,7 +43,7 @@ export class DefaultWasmController implements WasmController {
45
43
  protected pyodide: PyodideInterface | null = null;
46
44
  private packageLoadQueue = Promise.resolve();
47
45
  private sessionGeneration = 0;
48
- private activeSessionStops = new Set<PyCallable>();
46
+ private sessions = new Set<WasmSession>();
49
47
 
50
48
  public get requirePyodide() {
51
49
  invariant(this.pyodide, "Pyodide not loaded");
@@ -85,7 +83,7 @@ export class DefaultWasmController implements WasmController {
85
83
  packages: [
86
84
  "micropip",
87
85
  "msgspec",
88
- getMarimoWheel(opts.version),
86
+ getMarimoWheel(),
89
87
  "Markdown",
90
88
  "pymdown-extensions",
91
89
  "narwhals",
@@ -138,28 +136,15 @@ export class DefaultWasmController implements WasmController {
138
136
  });
139
137
  }
140
138
 
141
- public async startSession(opts: {
142
- queryParameters: Record<string, string | string[]>;
143
- code: string;
144
- filename: string | null;
145
- onMessage: (message: JsonString<NotificationPayload>) => void;
146
- userConfig: UserConfig;
147
- }): Promise<SerializedBridge> {
139
+ public async prepareSession(
140
+ opts: Parameters<WasmController["prepareSession"]>[0],
141
+ ): Promise<WasmSession> {
148
142
  const sessionGeneration = this.sessionGeneration;
149
- const { code, filename, onMessage, queryParameters, userConfig } = opts;
150
- // We pass down a messenger object to the code
151
- // This is used to have synchronous communication between the JS and Python code
152
- // Previously, we used a queue, but this would not properly flush the queue
153
- // during processing of a cell's code.
154
- //
155
- // This adds a messenger object to the global scope (import js; js.messenger.callback)
156
- self.messenger = {
157
- callback: onMessage,
158
- };
143
+ const { code, filename, queryParameters, userConfig } = opts;
159
144
  self.query_params = queryParameters;
160
145
  self.user_config = userConfig;
161
146
 
162
- const span = t.startSpan("startSession.runPython");
147
+ const span = t.startSpan("prepareSession.runPython");
163
148
  const nbFilename = filename || WasmFileSystem.NOTEBOOK_FILENAME;
164
149
  const sessionResources = this.requirePyodide.runPython(
165
150
  `
@@ -169,14 +154,12 @@ export class DefaultWasmController implements WasmController {
169
154
  import js
170
155
  from marimo._pyodide.bootstrap import create_session, instantiate
171
156
 
172
- assert js.messenger, "messenger is not defined"
173
157
  assert js.query_params, "query_params is not defined"
174
158
 
175
159
  def create_session_resources():
176
160
  session, bridge = create_session(
177
161
  filename="${nbFilename}",
178
162
  query_params=js.query_params.to_py(),
179
- message_callback=js.messenger.callback,
180
163
  user_config=js.user_config.to_py(),
181
164
  )
182
165
  session_task = None
@@ -198,6 +181,7 @@ export class DefaultWasmController implements WasmController {
198
181
  if task is not None:
199
182
  await asyncio.gather(task, return_exceptions=True)
200
183
  if bridge is not None:
184
+ bridge.close()
201
185
  bridge.session = None
202
186
  task = None
203
187
  kernel_task = None
@@ -235,45 +219,65 @@ export class DefaultWasmController implements WasmController {
235
219
  } finally {
236
220
  packagesProxy.destroy();
237
221
  }
238
- this.activeSessionStops.add(stopSession);
239
-
240
- // Fire and forget:
241
- // Load notebook dependencies and instantiate the session
242
- // We don't want to wait for this to finish,
243
- // so we can show the initial code immediately giving
244
- // a sense of responsiveness.
222
+ let stopped = false;
223
+ let stopping: Promise<void> | undefined;
224
+ const releaseInit = once(() => initSession.destroy());
225
+ const isStopped = () =>
226
+ stopped || sessionGeneration !== this.sessionGeneration;
227
+ // Load in parallel with subscription setup; only start() executes cells.
245
228
  const dependenciesReady = this.packageLoadQueue.then(() => {
246
- if (sessionGeneration !== this.sessionGeneration) {
229
+ if (isStopped()) {
247
230
  return;
248
231
  }
249
232
  return this.loadNotebookDeps(code, foundPackages);
250
233
  });
251
234
  this.packageLoadQueue = dependenciesReady.catch(() => undefined);
252
- void dependenciesReady
253
- .then(() => {
254
- if (sessionGeneration !== this.sessionGeneration) {
255
- return;
235
+ const session: WasmSession = {
236
+ bridge: bridgeProxy as unknown as SerializedBridge,
237
+ start: once(async () => {
238
+ try {
239
+ if (isStopped()) {
240
+ return;
241
+ }
242
+ await dependenciesReady;
243
+ if (!isStopped()) {
244
+ initSession(userConfig.runtime.auto_instantiate);
245
+ }
246
+ } catch (error) {
247
+ if (!isStopped()) {
248
+ throw error;
249
+ }
250
+ } finally {
251
+ releaseInit();
256
252
  }
257
- return initSession(userConfig.runtime.auto_instantiate);
258
- })
259
- .catch((error: unknown) => {
260
- Logger.error("Failed to load notebook dependencies", error);
261
- })
262
- .finally(() => initSession.destroy());
263
-
264
- return bridgeProxy as unknown as SerializedBridge;
253
+ }),
254
+ stop: () => {
255
+ stopped = true;
256
+ releaseInit();
257
+ stopping ??= (async () => {
258
+ await stopSession();
259
+ stopSession.destroy();
260
+ bridgeProxy.destroy();
261
+ this.sessions.delete(session);
262
+ })().catch((error: unknown) => {
263
+ stopping = undefined;
264
+ throw error;
265
+ });
266
+ return stopping;
267
+ },
268
+ };
269
+ this.sessions.add(session);
270
+ return session;
265
271
  }
266
272
 
267
273
  public async stopSession(): Promise<void> {
268
274
  this.sessionGeneration += 1;
269
- const stops = [...this.activeSessionStops];
275
+ const sessions = [...this.sessions];
270
276
  let hasFailure = false;
271
277
  let firstFailure: unknown;
272
- for (const stop of stops) {
278
+ for (const session of sessions) {
273
279
  try {
274
- await stop();
275
- this.activeSessionStops.delete(stop);
276
- stop.destroy();
280
+ await session.stop();
277
281
  } catch (error) {
278
282
  if (!hasFailure) {
279
283
  hasFailure = true;
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- export function getMarimoWheel(version: string) {
3
+ export function getMarimoWheel() {
4
4
  if (import.meta.env.DEV && import.meta.env.VITE_WASM_MARIMO_PREBUILT_WHEEL) {
5
5
  return "marimo-base";
6
6
  }
@@ -7,12 +7,11 @@ import {
7
7
  createWorkerParentTransport,
8
8
  type RPCSchema,
9
9
  } from "rpc-anywhere";
10
- import type { SaveNotebookRequest } from "@/core/network/types";
11
10
  import { decodeUtf8 } from "@/utils/strings";
12
11
  import { Deferred } from "../../../utils/Deferred";
13
12
  import { prettyError } from "../../../utils/errors";
14
13
  import { Logger } from "../../../utils/Logger";
15
- import type { ParentSchema } from "../rpc";
14
+ import type { ParentSchema, PersistNotebookRequest } from "../rpc";
16
15
  import type { WasmRuntimeConfig } from "../runtime-config";
17
16
  import { TRANSPORT_ID } from "./constants";
18
17
  import { WasmFileSystem } from "./fs";
@@ -70,14 +69,14 @@ const requestHandler = createRPCRequestHandler({
70
69
  await pyodideReadyPromise; // Make sure loading is done
71
70
  return WasmFileSystem.readNotebook(self.pyodide);
72
71
  },
73
- saveNotebook: async (opts: SaveNotebookRequest) => {
74
- await pyodideReadyPromise; // Make sure loading is done
75
- const saveFile = self.pyodide.runPython(`
76
- from marimo._pyodide.bootstrap import save_file
77
-
78
- save_file
79
- `);
80
- await saveFile(JSON.stringify(opts), WasmFileSystem.NOTEBOOK_FILENAME);
72
+ writeNotebook: async ({ filename, contents }: PersistNotebookRequest) => {
73
+ await pyodideReadyPromise;
74
+ const directory = filename.substring(0, filename.lastIndexOf("/"));
75
+ if (directory) {
76
+ self.pyodide.FS.mkdirTree(directory);
77
+ }
78
+ self.pyodide.FS.writeFile(filename, contents);
79
+ self.pyodide.FS.writeFile(WasmFileSystem.NOTEBOOK_FILENAME, contents);
81
80
  await WasmFileSystem.persistFilesToRemote(self.pyodide);
82
81
  },
83
82
  });
@@ -2,11 +2,7 @@
2
2
  import type { PyodideInterface } from "pyodide";
3
3
  import type { WasmRuntimeConfig } from "../runtime-config";
4
4
  import type { UserConfig } from "@/core/config/config-schema";
5
- import type {
6
- ClientCommand,
7
- NotificationPayload,
8
- } from "@/core/kernel/messages";
9
- import type { JsonString } from "@/utils/json/base64";
5
+ import type { ClientCommand } from "@/core/kernel/messages";
10
6
  import type {
11
7
  CodeCompletionRequest,
12
8
  CopyNotebookRequest,
@@ -34,7 +30,6 @@ import type {
34
30
  FormatCellsRequest,
35
31
  FormatResponse,
36
32
  SaveAppConfigurationRequest,
37
- SaveNotebookRequest,
38
33
  SaveUserConfigurationRequest,
39
34
  Snippets,
40
35
  } from "../../network/types";
@@ -58,19 +53,21 @@ export interface WasmController {
58
53
  code: string;
59
54
  filename: string | null;
60
55
  }): Promise<{ code: string; filename: string }>;
61
- /**
62
- * Start the session
63
- * @param opts.code - The code to start with
64
- * @param opts.fallbackCode - The code to fallback to
65
- * @param opts.filename - The filename to start with
66
- */
67
- startSession(opts: {
56
+ /** Prepare a session and load its dependencies without executing cells. */
57
+ prepareSession(opts: {
68
58
  queryParameters: Record<string, string | string[]>;
69
59
  code: string;
70
60
  filename: string | null;
71
61
  userConfig: UserConfig;
72
- onMessage: (message: JsonString<NotificationPayload>) => void;
73
- }): Promise<SerializedBridge>;
62
+ }): Promise<WasmSession>;
63
+ }
64
+
65
+ export interface WasmSession {
66
+ readonly bridge: SerializedBridge;
67
+ /** Start once dependencies are ready. Repeated calls share the same start. */
68
+ start(): Promise<void>;
69
+ /** Prevent a pending start and release the session and its bridge. */
70
+ stop(): Promise<void>;
74
71
  }
75
72
 
76
73
  export interface RawBridge {
@@ -81,7 +78,6 @@ export interface RawBridge {
81
78
  read_snippets(): Promise<Snippets>;
82
79
  get_environment_info(): Promise<EnvironmentInfo>;
83
80
  format(request: FormatCellsRequest): Promise<FormatResponse>;
84
- save(request: SaveNotebookRequest): Promise<string>;
85
81
  copy(request: CopyNotebookRequest): Promise<string>;
86
82
  save_app_config(request: SaveAppConfigurationRequest): Promise<string>;
87
83
  save_user_config(request: SaveUserConfigurationRequest): Promise<null>;
@@ -114,11 +110,26 @@ export type BridgePayload<T extends keyof RawBridge> = T extends keyof RawBridge
114
110
  : undefined;
115
111
 
116
112
  export type SerializedBridge = {
117
- [P in Exclude<keyof RawBridge, "save">]: RawBridge[P] extends (
113
+ [P in keyof RawBridge]: RawBridge[P] extends (
118
114
  payload: string,
119
115
  ) => Promise<unknown>
120
116
  ? (payload: string) => Promise<string>
121
117
  : RawBridge[P];
122
118
  } & {
123
- save(payload: string): Promise<void>;
119
+ notebook: {
120
+ readonly id: string;
121
+ subscribe(
122
+ id: string,
123
+ cursor: string | null,
124
+ emit: (event: string) => void,
125
+ ): Promise<void>;
126
+ unsubscribe(id: string): void;
127
+ call(call: string): Promise<string>;
128
+ transaction(request: string): Promise<void>;
129
+ set_layout(layout: string): Promise<void>;
130
+ set_persistence(
131
+ persist: (contents: string, filename: string) => Promise<void>,
132
+ ): void;
133
+ destroy(): void;
134
+ };
124
135
  };