@marimo-team/islands 0.25.3-dev23 → 0.25.3-dev230

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 (745) hide show
  1. package/dist/{ConnectedDataExplorerComponent-DfG3PRaJ.js → ConnectedDataExplorerComponent-BBihxHrr.js} +120 -116
  2. package/dist/{ErrorBoundary-h0Ea26dF.js → ErrorBoundary-DZwEkAT6.js} +16 -16
  3. package/dist/_baseSet-BfI5FjBM.js +328 -0
  4. package/dist/{abnfDiagram-VCTEODGH-B3w-XWX8.js → abnfDiagram-VCTEODGH-DBcJVxYP.js} +2 -2
  5. package/dist/any-language-editor-jGaR0EAo.js +75 -0
  6. package/dist/{architectureDiagram-5GKGNRK7-C18U9A6k.js → architectureDiagram-5GKGNRK7-BcHZXF4S.js} +1 -1
  7. package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
  8. package/dist/assets/__vite-browser-external-BKBpimif.js +1 -0
  9. package/dist/assets/worker-CgoMtD-_.js +113 -0
  10. package/dist/{blockDiagram-I7D4REHJ-Cg25UrxT.js → blockDiagram-I7D4REHJ-Dkhe6_PP.js} +1 -1
  11. package/dist/{button-CvjkwdSk.js → button-B6RjDKJx.js} +227 -217
  12. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CkVzWJEX.js} +2 -2
  13. package/dist/{chat-ui-w8SVynkn.js → chat-ui-DljFsfWf.js} +1277 -1275
  14. package/dist/{check-BMKBBrdc.js → check-Z_vtI3OL.js} +1 -1
  15. package/dist/{chunk-IMKFNOWR-CrS5bzqW.js → chunk-IMKFNOWR-CTZlwBAA.js} +1 -1
  16. package/dist/{chunk-SHT3W25Y-StpvPvUG.js → chunk-SHT3W25Y-53g_RZHm.js} +1 -1
  17. package/dist/{chunk-SVP7TREG-CBXjbYZC.js → chunk-SVP7TREG-P6abNGV_.js} +1 -1
  18. package/dist/{chunk-TICWLB2K-Dp6bIb-q.js → chunk-TICWLB2K-BTJJqkyF.js} +1 -1
  19. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  20. package/dist/{classDiagram-ZZMXUADV-BFYuxV5g.js → classDiagram-ZZMXUADV-BUGqOrTm.js} +2 -2
  21. package/dist/{classDiagram-v2-VYDZK3BY-D_tjXVMl.js → classDiagram-v2-VYDZK3BY-CXpQvO-s.js} +2 -2
  22. package/dist/code-visibility-BOmgV0Fh.js +134 -0
  23. package/dist/{common-DNPxRLm_.js → common-DdHcuklD.js} +9837 -9658
  24. package/dist/config-DbjzjwxX.js +636 -0
  25. package/dist/{copy-icon-BgUO8jsi.js → copy-icon-CG57cxwb.js} +3 -3
  26. package/dist/createReducer-DePYJ0F3.js +63 -0
  27. package/dist/{cynefinDiagram-5FMLGOSQ-DSgYrHB2.js → cynefinDiagram-5FMLGOSQ-DOcnl8wW.js} +1 -1
  28. package/dist/{dagre-GXQ25YYZ-GYlruCBf.js → dagre-GXQ25YYZ-CuHR9QfG.js} +3 -3
  29. package/dist/{dagre-BGSfXNEb.js → dagre-mqiMAsFY.js} +531 -680
  30. package/dist/{data-grid-overlay-editor-B9QxYH-I.js → data-grid-overlay-editor-Dxdsrndd.js} +5 -5
  31. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  32. package/dist/{debounce-C3jyATpc.js → debounce-DrhhziJv.js} +2 -2
  33. package/dist/{diagram-S7CK7UJ4-DRu5LX5_.js → diagram-S7CK7UJ4-BPiG4kso.js} +1 -1
  34. package/dist/{diagram-UQ7AKVKN-DD7uiejP.js → diagram-UQ7AKVKN-_piBOvOC.js} +1 -1
  35. package/dist/{diagram-VX7I27RA-ByH9KAJJ.js → diagram-VX7I27RA-DCzVeJ8M.js} +1 -1
  36. package/dist/{diagram-Z3DM3KII-BsQHPRke.js → diagram-Z3DM3KII-D64CF1jQ.js} +1 -1
  37. package/dist/{dialog-Cc479ZEH.js → dialog-DsZ49mmU.js} +26 -26
  38. package/dist/{dist-Bvs24R_E.js → dist-11T5wq3_.js} +31 -30
  39. package/dist/{dist-F8Ep36rk.js → dist-17ugwGZc.js} +59 -58
  40. package/dist/{dist-BMQf5zIS.js → dist-7cRjf--y.js} +123 -122
  41. package/dist/{dist-diIx5qJW.js → dist-B8pkfkzc.js} +31 -30
  42. package/dist/{dist-CN_BeG2I.js → dist-B9UoM_wq.js} +58 -57
  43. package/dist/{dist-CLdpGQVr.js → dist-BGuMTs1i.js} +118 -117
  44. package/dist/{dist-BK4Oj99o.js → dist-BHW11fni.js} +18 -17
  45. package/dist/dist-BLY4m1Wi.js +850 -0
  46. package/dist/{dist-PXYI_yuP.js → dist-BNlcVoxs.js} +24 -23
  47. package/dist/{dist-D6d86eNJ.js → dist-BQYe5Bju.js} +47 -46
  48. package/dist/{dist-CkTTIdBe.js → dist-BX1mn8na.js} +337 -337
  49. package/dist/{dist-DiDibOYr.js → dist-Bh0PTKUW.js} +151 -150
  50. package/dist/{dist-CSJ0MDRw.js → dist-CKaXK92p.js} +56 -55
  51. package/dist/{dist-C8fAKSH1.js → dist-CLhwfhpJ.js} +53 -52
  52. package/dist/{dist-DoE4XJBC.js → dist-CYeqK4Xw.js} +9801 -10649
  53. package/dist/{dist-BLfKmR-l.js → dist-Cxlp3WH6.js} +16 -15
  54. package/dist/{dist-D-wwqlzJ.js → dist-DSJPGj42.js} +158 -157
  55. package/dist/{dist-BorMD-uX.js → dist-DU9ICsWZ.js} +75 -74
  56. package/dist/{dist-DBtSl3sf.js → dist-DWv0ALBi.js} +47 -46
  57. package/dist/{dist-OR1OnN-y.js → dist-DiBpWEsB.js} +31 -30
  58. package/dist/{dist-CrSP_H1M.js → dist-DiLFTlnl.js} +242 -242
  59. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  60. package/dist/{dist-CSbh1PNP.js → dist-cVDV5IuI.js} +23 -22
  61. package/dist/{dist-BuaRHxOc.js → dist-fRfaOoq8.js} +44 -43
  62. package/dist/{dist-Cg7gzw-a.js → dist-gTTI-9Px.js} +78 -77
  63. package/dist/dropdown-menu-BRiE7Vnp.js +6083 -0
  64. package/dist/{ebnfDiagram-PWID7BFC-CQRK5_eT.js → ebnfDiagram-PWID7BFC-BapQPML-.js} +2 -2
  65. package/dist/{erDiagram-RLTQ6QDP-BKtWrDVh.js → erDiagram-RLTQ6QDP-CNQvC2_Q.js} +1 -1
  66. package/dist/{error-banner-CFPHFw4h.js → error-banner-IsonnvA0.js} +84 -83
  67. package/dist/error-entries-CRPfxMqm.js +2505 -0
  68. package/dist/{esm-D2gTsXEV.js → esm-BgKjMvWw.js} +530 -529
  69. package/dist/{esm-AMFssoNp.js → esm-CHjVSexr.js} +328 -329
  70. package/dist/feedback-button-bkhTNCeV.js +374 -0
  71. package/dist/{flowDiagram-HODETNUW-1IN-ih2E.js → flowDiagram-HODETNUW-BBt6S6oe.js} +2 -2
  72. package/dist/{formats-X4mMQWzX.js → formats-BK4VefeF.js} +6 -6
  73. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  74. package/dist/{glide-data-editor-BIYjd9hQ.js → glide-data-editor-Cd5G4gkf.js} +417 -415
  75. package/dist/{glide-utils-DM9zBO4W.js → glide-utils-CQddGpa-.js} +16 -16
  76. package/dist/{globals-BX22lYk2.js → globals-Cm5hDd9R.js} +3 -3
  77. package/dist/{graphlib-BmY_CCV9.js → graphlib-nlwT3Wvy.js} +177 -220
  78. package/dist/hasIn-C20JsQ2m.js +28 -0
  79. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  80. package/dist/{error-entries-Damuuclv.js → html-to-image-0FooaKop.js} +26911 -26769
  81. package/dist/{infoDiagram-27XIBGKW-CkB-zr4p.js → infoDiagram-27XIBGKW-Hd8Ifz82.js} +1 -1
  82. package/dist/isArrayLikeObject-B-HXCsex.js +626 -0
  83. package/dist/isEmpty-CdX7MTE1.js +14 -0
  84. package/dist/{ishikawaDiagram-5VMMS53U-wlyLjBmM.js → ishikawaDiagram-5VMMS53U-CP7hnHWx.js} +1 -1
  85. package/dist/{kanban-definition-UXKFOSKX-C2usY0i-.js → kanban-definition-UXKFOSKX-CX91sa9b.js} +1 -1
  86. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  87. package/dist/{loader-BQOfjTIJ.js → loader-BisjOLiW.js} +12 -12
  88. package/dist/main.js +10253 -8126
  89. package/dist/{mermaid-BA-Z6wGL.js → mermaid-Djb3Ni9t.js} +54 -54
  90. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  91. package/dist/{mindmap-definition-YA3MSWOX-nKOWS8RR.js → mindmap-definition-YA3MSWOX-DgCNo07O.js} +1 -1
  92. package/dist/{now-jM8-M7IR.js → now-BKZCLE5P.js} +12 -13
  93. package/dist/{number-overlay-editor-DK-HbLsV.js → number-overlay-editor-BLCXOIUf.js} +3 -3
  94. package/dist/{dist-CN8zI-XC.js → objectWithoutPropertiesLoose-ai5NUqGa.js} +262 -240
  95. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  96. package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
  97. package/dist/{pegDiagram-XKGWAZYB-Dac9EIKD.js → pegDiagram-XKGWAZYB-SGJhnIKo.js} +2 -2
  98. package/dist/pick-tCszMUbm.js +35 -0
  99. package/dist/{pieDiagram-E7YTZNPT-B7S-DsW_.js → pieDiagram-E7YTZNPT-1stXIWCQ.js} +1 -1
  100. package/dist/precisionRound-DhAzeRcm.js +49 -0
  101. package/dist/{process-output-CTPTtxXB.js → process-output-BOvkTEDt.js} +4 -4
  102. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  103. package/dist/{railroadDiagram-O6MQD6OU-Cfa5Q-hr.js → railroadDiagram-O6MQD6OU-DY1mojzB.js} +2 -2
  104. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  105. package/dist/{requirementDiagram-BXWQKSXE-d8zXCJIk.js → requirementDiagram-BXWQKSXE-gHzhUp0D.js} +1 -1
  106. package/dist/{reveal-component-Dl9ZugRb.js → reveal-component-BcLwP52P.js} +426 -403
  107. package/dist/schemas-CdscWNy_.js +4747 -0
  108. package/dist/select-BSxlITBo.js +1200 -0
  109. package/dist/{sequenceDiagram-WJ2MYXX4-b6pei3lJ.js → sequenceDiagram-WJ2MYXX4-rjPtD9fB.js} +1 -1
  110. package/dist/{spec-BJzgmvVa.js → spec-Dq8RNplp.js} +41 -11
  111. package/dist/{stateDiagram-D77RDMKH-Be-xSpaZ.js → stateDiagram-D77RDMKH-DMNxjUxV.js} +4 -4
  112. package/dist/{stateDiagram-v2-MP3YSRHH-5Y-FxesJ.js → stateDiagram-v2-MP3YSRHH-CumAaqGo.js} +2 -2
  113. package/dist/static-state-BldGd99T.js +72 -0
  114. package/dist/strings-BGW-fXVJ.js +507 -0
  115. package/dist/style.css +1 -1
  116. package/dist/{swimlanes-42K2YHIH-nRRl4NU0.js → swimlanes-42K2YHIH-BU14_Tej.js} +1 -1
  117. package/dist/{swimlanesDiagram-VR7AAH4N-BS79510V.js → swimlanesDiagram-VR7AAH4N-CieAnPqJ.js} +2 -2
  118. package/dist/{swiper-component-DKntyn8p.js → swiper-component-Dir1o8ml.js} +2 -2
  119. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  120. package/dist/{timeline-definition-24CTP7MA-Cfzf8WPf.js → timeline-definition-24CTP7MA-CrVj4E1K.js} +1 -1
  121. package/dist/toast-BWIPi3aF.js +491 -0
  122. package/dist/{tooltip-CtBZ5q8p.js → tooltip-C3UnvsRe.js} +329 -305
  123. package/dist/use-restore-focus-BWO0z1lo.js +1672 -0
  124. package/dist/{useAsyncData-BD534XmW.js → useAsyncData-DsZMvNXn.js} +15 -14
  125. package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-ChB4eyim.js} +2 -2
  126. package/dist/{useDeepCompareMemoize-C72_RNsu.js → useDeepCompareMemoize-KMBBux8C.js} +1 -1
  127. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-cMNQ80CK.js} +1 -1
  128. package/dist/useLifecycle-BquH9ET-.js +112 -0
  129. package/dist/useTheme-DgOLVISn.js +337 -0
  130. package/dist/utils-DXkj82sK.js +813 -0
  131. package/dist/{vega-component-DfcYgj-Y.js → vega-component-Bwg_Kuh-.js} +171 -170
  132. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  133. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  134. package/dist/{vennDiagram-4TSXK5OY-CeY6Z1xZ.js → vennDiagram-4TSXK5OY-ZLxQ8yhm.js} +1 -1
  135. package/dist/{wardleyDiagram-VM6X3IG4-Cxs9NtVi.js → wardleyDiagram-VM6X3IG4-D88pcLY1.js} +1 -1
  136. package/dist/{xychartDiagram-S5SC5T6Z-DNWbvPK7.js → xychartDiagram-S5SC5T6Z-_13d4g8g.js} +2 -2
  137. package/package.json +16 -20
  138. package/src/__mocks__/document.tsx +63 -0
  139. package/src/__mocks__/notebook.ts +3 -4
  140. package/src/__mocks__/partial.ts +26 -0
  141. package/src/__mocks__/requests.ts +1 -4
  142. package/src/__tests__/main.test.tsx +24 -1
  143. package/src/__tests__/module-entry.test.ts +44 -0
  144. package/src/__tests__/mount.test.ts +1 -21
  145. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  146. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  147. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  148. package/src/components/app-config/ai-config.tsx +155 -149
  149. package/src/components/app-config/app-config-button.tsx +6 -5
  150. package/src/components/app-config/app-config-form.tsx +5 -9
  151. package/src/components/app-config/common.tsx +7 -9
  152. package/src/components/app-config/data-form.tsx +112 -113
  153. package/src/components/app-config/mcp-config.tsx +30 -53
  154. package/src/components/app-config/user-config-form.css +91 -0
  155. package/src/components/app-config/user-config-form.tsx +266 -349
  156. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  157. package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
  158. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  159. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  160. package/src/components/chat/acp/blocks.tsx +3 -2
  161. package/src/components/chat/acp/session-tabs.tsx +8 -3
  162. package/src/components/chat/capabilities-popover.tsx +1 -5
  163. package/src/components/chat/chat-components.tsx +2 -0
  164. package/src/components/chat/chat-panel.tsx +23 -104
  165. package/src/components/chat/chat-utils.ts +4 -8
  166. package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
  167. package/src/components/chat/notebook-access-selector.tsx +100 -0
  168. package/src/components/data-table/TableBottomBar.tsx +4 -1
  169. package/src/components/data-table/TableTopBar.tsx +2 -0
  170. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  171. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  172. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  173. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  174. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  175. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  176. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  177. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  178. package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
  179. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  180. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  181. package/src/components/data-table/cell-selection/feature.ts +2 -2
  182. package/src/components/data-table/cell-selection/types.ts +2 -2
  183. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  184. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  185. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  186. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  187. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  188. package/src/components/data-table/charts/charts.tsx +40 -30
  189. package/src/components/data-table/charts/storage.ts +16 -5
  190. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  191. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  192. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  193. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  194. package/src/components/data-table/columns.tsx +45 -46
  195. package/src/components/data-table/context-menu.tsx +36 -20
  196. package/src/components/data-table/data-table.tsx +17 -1
  197. package/src/components/data-table/date-popover.tsx +6 -4
  198. package/src/components/data-table/export-actions.tsx +76 -48
  199. package/src/components/data-table/pagination.tsx +44 -33
  200. package/src/components/data-table/range-focus/atoms.ts +4 -6
  201. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  202. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  203. package/src/components/data-table/renderers.tsx +16 -7
  204. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  205. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  206. package/src/components/data-table/search-highlight.tsx +79 -0
  207. package/src/components/data-table/types.ts +1 -0
  208. package/src/components/data-table/url-detector.tsx +49 -9
  209. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  210. package/src/components/datasources/__tests__/column-preview.test.tsx +96 -5
  211. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  212. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  213. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  214. package/src/components/datasources/column-preview.tsx +17 -12
  215. package/src/components/datasources/datasources.tsx +56 -43
  216. package/src/components/datasources/utils.ts +32 -23
  217. package/src/components/debugger/debugger-code.tsx +5 -0
  218. package/src/components/dependency-graph/custom-node.tsx +1 -1
  219. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  220. package/src/components/dependency-graph/elements.ts +24 -21
  221. package/src/components/dependency-graph/minimap-content.tsx +13 -19
  222. package/src/components/dependency-graph/panels.tsx +4 -2
  223. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  224. package/src/components/editor/SortableCell.tsx +1 -3
  225. package/src/components/editor/__tests__/Output.test.tsx +50 -32
  226. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  227. package/src/components/editor/__tests__/data-attributes.test.tsx +28 -14
  228. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  229. package/src/components/editor/__tests__/output-persistence.test.tsx +6 -2
  230. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  231. package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
  232. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +40 -10
  233. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +6 -10
  234. package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +113 -0
  235. package/src/components/editor/actions/name-cell-input.tsx +4 -3
  236. package/src/components/editor/actions/pair-with-agent-commands.ts +2 -2
  237. package/src/components/editor/actions/pair-with-agent-modal.tsx +24 -21
  238. package/src/components/editor/actions/pair-with-agent.tsx +15 -10
  239. package/src/components/editor/actions/useCellActionButton.tsx +36 -31
  240. package/src/components/editor/actions/useConfigActions.tsx +3 -4
  241. package/src/components/editor/actions/useNotebookActions.tsx +19 -23
  242. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  243. package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
  244. package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
  245. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  246. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  247. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  248. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  249. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  250. package/src/components/editor/alerts/stdin-blocking-alert.tsx +1 -1
  251. package/src/components/editor/app-container.tsx +1 -1
  252. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  253. package/src/components/editor/cell/CreateCellButton.tsx +15 -21
  254. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  255. package/src/components/editor/cell/RunButton.tsx +2 -2
  256. package/src/components/editor/cell/StagedAICell.tsx +10 -2
  257. package/src/components/editor/cell/StopButton.tsx +2 -2
  258. package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +4 -2
  259. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  260. package/src/components/editor/cell/cell-actions.tsx +12 -1
  261. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  262. package/src/components/editor/cell/code/cell-editor.tsx +46 -165
  263. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  264. package/src/components/editor/cell/collapse.tsx +11 -4
  265. package/src/components/editor/cell/useAddCell.ts +4 -8
  266. package/src/components/editor/cell/useDeleteCell.tsx +10 -36
  267. package/src/components/editor/cell/useRunCells.ts +2 -5
  268. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  269. package/src/components/editor/cell/useSplitCell.tsx +10 -6
  270. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  271. package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
  272. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  273. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  274. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  275. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  276. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
  277. package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
  278. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  279. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  280. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  281. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  282. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  283. package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
  284. package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
  285. package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
  286. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +6 -9
  287. package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
  288. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +62 -3
  289. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  290. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  291. package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
  292. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  293. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  294. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  295. package/src/components/editor/chrome/wrapper/footer.tsx +2 -2
  296. package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
  297. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  298. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  299. package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
  300. package/src/components/editor/columns/cell-column.tsx +1 -1
  301. package/src/components/editor/columns/sortable-column.tsx +2 -2
  302. package/src/components/editor/connections/components.tsx +5 -10
  303. package/src/components/editor/controls/Controls.tsx +4 -4
  304. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  305. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  306. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +10 -4
  307. package/src/components/editor/controls/command-palette.tsx +22 -10
  308. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  309. package/src/components/editor/documentation.css +34 -11
  310. package/src/components/editor/dynamic-favicon.tsx +21 -40
  311. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +25 -20
  312. package/src/components/editor/errors/auto-fix.tsx +4 -8
  313. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  314. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  315. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  316. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  317. package/src/components/editor/file-tree/file-explorer.tsx +48 -15
  318. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  319. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  320. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  321. package/src/components/editor/header/__tests__/filename-form.test.tsx +1 -4
  322. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  323. package/src/components/editor/header/app-header.tsx +1 -1
  324. package/src/components/editor/header/filename-form.tsx +1 -1
  325. package/src/components/editor/header/status.tsx +40 -20
  326. package/src/components/editor/links/__tests__/cell-link.test.tsx +148 -0
  327. package/src/components/editor/links/cell-link-list.tsx +1 -1
  328. package/src/components/editor/links/cell-link.tsx +17 -7
  329. package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
  330. package/src/components/editor/navigation/__tests__/navigation.test.ts +108 -85
  331. package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
  332. package/src/components/editor/navigation/clipboard.ts +17 -14
  333. package/src/components/editor/navigation/focus-utils.ts +23 -4
  334. package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
  335. package/src/components/editor/navigation/navigation.ts +71 -70
  336. package/src/components/editor/navigation/selection.ts +30 -29
  337. package/src/components/editor/notebook-banner.tsx +1 -0
  338. package/src/components/editor/notebook-cell.tsx +29 -32
  339. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  340. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  341. package/src/components/editor/output/Outputs.css +8 -0
  342. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  343. package/src/components/editor/output/ansi-reduce.ts +33 -20
  344. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  345. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
  346. package/src/components/editor/package-alert.tsx +14 -7
  347. package/src/components/editor/renderers/cell-array.tsx +22 -33
  348. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  349. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -1
  350. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
  351. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
  352. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  353. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
  354. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
  355. package/src/components/editor/stdin-blocking-alert.tsx +1 -1
  356. package/src/components/home/components.tsx +17 -31
  357. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  358. package/src/components/icons/large-spinner.tsx +3 -14
  359. package/src/components/icons/spinner.tsx +1 -1
  360. package/src/components/markdown/markdown-renderer.tsx +4 -8
  361. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  362. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  363. package/src/components/pages/edit-page.tsx +19 -17
  364. package/src/components/pages/home-page.tsx +164 -91
  365. package/src/components/scratchpad/scratchpad.test.tsx +89 -0
  366. package/src/components/scratchpad/scratchpad.tsx +43 -32
  367. package/src/components/scratchpad/state.ts +7 -0
  368. package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
  369. package/src/components/slides/__tests__/minimap.test.ts +38 -19
  370. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
  371. package/src/components/slides/minimap.tsx +17 -12
  372. package/src/components/slides/reveal-component.tsx +58 -26
  373. package/src/components/slides/reveal-slides.css +5 -4
  374. package/src/components/slides/slide-cell-view.tsx +4 -5
  375. package/src/components/slides/slide-form.tsx +1 -0
  376. package/src/components/slides/slide-scroll-hint.tsx +3 -1
  377. package/src/components/sort/SortableCellsProvider.tsx +8 -25
  378. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  379. package/src/components/tracing/tracing.tsx +46 -42
  380. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  381. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  382. package/src/components/ui/alert-dialog.tsx +1 -1
  383. package/src/components/ui/draggable-popover.tsx +24 -2
  384. package/src/components/ui/range-slider.tsx +22 -9
  385. package/src/core/MarimoApp.tsx +1 -1
  386. package/src/core/ai/__tests__/staged-cells.test.ts +32 -33
  387. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
  388. package/src/core/ai/context/providers/cell-output.ts +2 -2
  389. package/src/core/ai/context/providers/datasource.ts +6 -2
  390. package/src/core/ai/staged-cells.ts +18 -19
  391. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +40 -88
  392. package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
  393. package/src/core/ai/tools/base.ts +18 -15
  394. package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
  395. package/src/core/ai/tools/registry.ts +13 -10
  396. package/src/core/ai/tools/sample-tool.ts +6 -7
  397. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -37
  398. package/src/core/cells/__tests__/actions.test.ts +624 -35
  399. package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
  400. package/src/core/cells/__tests__/arrange.test.ts +432 -0
  401. package/src/core/cells/__tests__/cell.test.ts +39 -0
  402. package/src/core/cells/__tests__/cells.test.ts +251 -2540
  403. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  404. package/src/core/cells/__tests__/document.test.ts +164 -0
  405. package/src/core/cells/__tests__/editor.test.ts +57 -0
  406. package/src/core/cells/__tests__/flush-document.test.ts +40 -0
  407. package/src/core/cells/__tests__/harness.ts +106 -0
  408. package/src/core/cells/__tests__/layout.test.ts +177 -0
  409. package/src/core/cells/__tests__/notebook-outline.test.ts +122 -0
  410. package/src/core/cells/__tests__/outputs.test.tsx +71 -53
  411. package/src/core/cells/__tests__/session.test.ts +445 -211
  412. package/src/core/cells/__tests__/utils.test.ts +9 -108
  413. package/src/core/cells/actions.ts +675 -6
  414. package/src/core/cells/add-missing-import.ts +47 -43
  415. package/src/core/cells/arrange.ts +529 -0
  416. package/src/core/cells/cell.ts +14 -3
  417. package/src/core/cells/cells.ts +126 -1363
  418. package/src/core/cells/columns.ts +38 -0
  419. package/src/core/cells/document.ts +178 -0
  420. package/src/core/cells/edit.ts +30 -0
  421. package/src/core/cells/editor.ts +82 -0
  422. package/src/core/cells/layout.ts +221 -0
  423. package/src/core/cells/outputs.ts +12 -28
  424. package/src/core/cells/pending-delete-service.ts +3 -7
  425. package/src/core/cells/session.ts +76 -53
  426. package/src/core/cells/types.ts +22 -6
  427. package/src/core/cells/utils.ts +10 -8
  428. package/src/core/codemirror/__tests__/format.test.ts +0 -34
  429. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  430. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  431. package/src/core/codemirror/ai/resources.ts +1 -1
  432. package/src/core/codemirror/cells/__tests__/extensions.test.ts +2 -6
  433. package/src/core/codemirror/cells/extensions.ts +30 -28
  434. package/src/core/codemirror/cells/state.ts +1 -6
  435. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
  436. package/src/core/codemirror/copilot/getCodes.ts +2 -2
  437. package/src/core/codemirror/format.ts +6 -23
  438. package/src/core/codemirror/keymaps/vim.ts +4 -8
  439. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  440. package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
  441. package/src/core/codemirror/language/cell-code.ts +114 -0
  442. package/src/core/codemirror/language/extension.ts +52 -35
  443. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  444. package/src/core/codemirror/language/languages/python.ts +16 -10
  445. package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
  446. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  447. package/src/core/codemirror/language/types.ts +7 -7
  448. package/src/core/codemirror/language/utils.ts +9 -39
  449. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
  450. package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
  451. package/src/core/codemirror/lsp/utils.ts +1 -1
  452. package/src/core/codemirror/misc/__tests__/paste.test.ts +3 -1
  453. package/src/core/codemirror/misc/paste.ts +1 -1
  454. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  455. package/src/core/codemirror/readonly/extension.ts +2 -2
  456. package/src/core/codemirror/utils.ts +1 -0
  457. package/src/core/config/__tests__/app-config.test.ts +64 -0
  458. package/src/core/config/__tests__/config-schema.test.ts +56 -6
  459. package/src/core/config/config-schema.ts +17 -4
  460. package/src/core/config/config.ts +65 -20
  461. package/src/core/config/feature-flag.tsx +0 -2
  462. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  463. package/src/core/datasets/data-source-discovery.ts +4 -6
  464. package/src/core/documentation/doc-lookup.ts +1 -1
  465. package/src/core/edit-app.tsx +21 -28
  466. package/src/core/errors/error-entries.ts +4 -1
  467. package/src/core/export/hooks.ts +1 -1
  468. package/src/core/export/layout.ts +2 -2
  469. package/src/core/hotkeys/actions.ts +2 -4
  470. package/src/core/islands/__tests__/bootstrap.test.ts +69 -17
  471. package/src/core/islands/__tests__/bridge.test.ts +85 -27
  472. package/src/core/islands/bootstrap.ts +46 -53
  473. package/src/core/islands/bridge.ts +84 -25
  474. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  475. package/src/core/islands/components/web-components.tsx +1 -1
  476. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  477. package/src/core/islands/worker/controller.ts +4 -10
  478. package/src/core/islands/worker/worker.tsx +33 -33
  479. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  480. package/src/core/kernel/__tests__/handlers.test.ts +7 -153
  481. package/src/core/kernel/handlers.ts +19 -72
  482. package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
  483. package/src/core/meta/code-visibility.ts +18 -9
  484. package/src/core/network/__tests__/connection.test.ts +1 -1
  485. package/src/core/network/__tests__/requests-lazy.test.ts +1 -3
  486. package/src/core/network/connection-notice.ts +1 -1
  487. package/src/core/network/connection.ts +1 -1
  488. package/src/core/network/requests-lazy.ts +2 -5
  489. package/src/core/network/requests-network.ts +5 -31
  490. package/src/core/network/requests-static.ts +1 -4
  491. package/src/core/network/requests-toasting.tsx +1 -4
  492. package/src/core/network/types.ts +6 -14
  493. package/src/core/network/useConnectionNotice.ts +8 -2
  494. package/src/core/notebook/__tests__/operations.test.ts +51 -0
  495. package/src/core/notebook/attachments.ts +38 -0
  496. package/src/core/notebook/document/__tests__/codemirror.test.ts +758 -0
  497. package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
  498. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  499. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  500. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  501. package/src/core/notebook/document/__tests__/model.test.ts +247 -0
  502. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  503. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  504. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  505. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  506. package/src/core/notebook/document/__tests__/state.test.ts +459 -0
  507. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  508. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  509. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  510. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  511. package/src/core/notebook/document/__tests__/user.ts +61 -0
  512. package/src/core/notebook/document/codemirror.ts +216 -0
  513. package/src/core/notebook/document/draft.ts +502 -0
  514. package/src/core/notebook/document/hooks.tsx +118 -0
  515. package/src/core/notebook/document/index.ts +24 -0
  516. package/src/core/notebook/document/model.ts +102 -0
  517. package/src/core/notebook/document/select.ts +41 -0
  518. package/src/core/notebook/document/state.ts +378 -0
  519. package/src/core/notebook/document/sync.ts +369 -0
  520. package/src/core/notebook/index.ts +19 -0
  521. package/src/core/notebook/operations.ts +30 -0
  522. package/src/core/notebook/replica/AGENTS.md +11 -0
  523. package/src/core/{host → notebook/replica}/__tests__/attachments.test.ts +9 -10
  524. package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
  525. package/src/core/notebook/replica/__tests__/executions.test.ts +201 -0
  526. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  527. package/src/core/notebook/replica/__tests__/replica.test.ts +559 -0
  528. package/src/core/notebook/replica/__tests__/results.test.ts +193 -0
  529. package/src/core/notebook/replica/__tests__/runtime.test.ts +78 -0
  530. package/src/core/notebook/replica/backend.ts +19 -0
  531. package/src/core/notebook/replica/connection.ts +42 -0
  532. package/src/core/notebook/replica/index.ts +20 -0
  533. package/src/core/notebook/replica/replica.ts +336 -0
  534. package/src/core/{host → notebook/replica}/resources/attachments.ts +6 -3
  535. package/src/core/{host → notebook/replica}/resources/document.ts +4 -4
  536. package/src/core/notebook/replica/resources/executions.ts +157 -0
  537. package/src/core/notebook/replica/resources/results.ts +48 -0
  538. package/src/core/notebook/replica/resources/runtime.ts +14 -0
  539. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  540. package/src/core/packages/useSandboxController.ts +1 -1
  541. package/src/core/run-app.tsx +48 -51
  542. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  543. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  544. package/src/core/runtime/__tests__/runtime.test.ts +32 -74
  545. package/src/core/runtime/adapter.ts +1 -1
  546. package/src/core/runtime/config.ts +2 -2
  547. package/src/core/runtime/runtime.ts +33 -46
  548. package/src/core/runtime/types.ts +0 -2
  549. package/src/core/saving/__tests__/document.test.tsx +123 -0
  550. package/src/core/saving/__tests__/state.test.ts +111 -0
  551. package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
  552. package/src/core/saving/document.ts +33 -0
  553. package/src/core/saving/filename.ts +1 -1
  554. package/src/core/saving/save-component.tsx +39 -60
  555. package/src/core/saving/state.ts +38 -39
  556. package/src/core/saving/useAutoSave.ts +17 -53
  557. package/src/core/session/__tests__/backend.test.ts +236 -0
  558. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +184 -0
  559. package/src/core/{websocket → session}/__tests__/useNotebookSession.hook.test.tsx +213 -262
  560. package/src/core/session/active-notebook.ts +28 -0
  561. package/src/core/session/backend.ts +123 -0
  562. package/src/core/session/embedded.ts +7 -0
  563. package/src/core/{websocket → session}/types.ts +2 -2
  564. package/src/core/session/useNotebookReplica.ts +74 -0
  565. package/src/core/{websocket → session}/useNotebookSession.tsx +77 -64
  566. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  567. package/src/core/state/jotai.ts +1 -1
  568. package/src/core/static/__tests__/files.test.ts +38 -10
  569. package/src/core/static/files.ts +2 -0
  570. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  571. package/src/core/transports/__tests__/server.test.ts +408 -0
  572. package/src/core/transports/__tests__/static.test.ts +306 -0
  573. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  574. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  575. package/src/core/transports/server.ts +152 -0
  576. package/src/core/transports/static.ts +166 -0
  577. package/src/core/transports/wasm.ts +97 -0
  578. package/src/core/wasm/__tests__/bridge.test.ts +105 -65
  579. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  580. package/src/core/wasm/bridge.ts +69 -72
  581. package/src/core/wasm/rpc.ts +15 -3
  582. package/src/core/wasm/store.ts +3 -3
  583. package/src/core/wasm/worker/bootstrap.ts +55 -51
  584. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  585. package/src/core/wasm/worker/save-worker.ts +9 -10
  586. package/src/core/wasm/worker/types.ts +29 -18
  587. package/src/core/wasm/worker/worker.ts +89 -45
  588. package/src/css/app/codemirror.css +1 -1
  589. package/src/css/globals.css +66 -22
  590. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  591. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  592. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  593. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  594. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  595. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  596. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  597. package/src/hooks/useAsyncData.ts +3 -3
  598. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  599. package/src/hooks/useDebounce.ts +6 -10
  600. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  601. package/src/hooks/useDelayElapsed.ts +14 -10
  602. package/src/hooks/useElapsedTime.ts +3 -3
  603. package/src/hooks/useEventListener.ts +1 -2
  604. package/src/hooks/useInputHistory.ts +4 -7
  605. package/src/hooks/useInternalStateWithSync.ts +6 -6
  606. package/src/hooks/useResizeObserver.ts +4 -7
  607. package/src/hooks/useScript.ts +67 -70
  608. package/src/hooks/useStateForKey.ts +93 -0
  609. package/src/mount.tsx +20 -15
  610. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  611. package/src/plugins/core/registerReactComponent.tsx +1 -1
  612. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  613. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  614. package/src/plugins/impl/DataTablePlugin.tsx +69 -37
  615. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  616. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  617. package/src/plugins/impl/FormPlugin.tsx +1 -1
  618. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  619. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  620. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  621. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
  622. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  623. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  624. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  625. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  626. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  627. package/src/plugins/impl/anywidget/model.ts +3 -1
  628. package/src/plugins/impl/anywidget/registry.ts +18 -14
  629. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  630. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  631. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  632. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  633. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  634. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  635. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  636. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  637. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  638. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  639. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  640. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  641. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  642. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  643. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  644. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  645. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  646. package/src/plugins/impl/panel/utils.ts +17 -0
  647. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  648. package/src/plugins/impl/plotly/selection.ts +25 -19
  649. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  650. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  651. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  652. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  653. package/src/stories/button.stories.tsx +1 -0
  654. package/src/stories/cell.stories.tsx +2 -5
  655. package/src/stories/data-table.stories.tsx +31 -0
  656. package/src/stories/editor.stories.tsx +24 -17
  657. package/src/stories/form-wrapper.stories.tsx +2 -2
  658. package/src/stories/layout/vertical/one-column.stories.tsx +28 -23
  659. package/src/stories/runtime-story.tsx +23 -17
  660. package/src/stories/select.stories.tsx +2 -2
  661. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  662. package/src/utils/__tests__/arrays.test.ts +35 -0
  663. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  664. package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +29 -0
  665. package/src/utils/__tests__/numbers.test.ts +105 -1
  666. package/src/utils/__tests__/objects.test.ts +21 -0
  667. package/src/utils/arrays.ts +11 -2
  668. package/src/utils/blob.ts +1 -1
  669. package/src/utils/createReducer.ts +53 -26
  670. package/src/utils/maps.ts +0 -3
  671. package/src/utils/numbers.ts +79 -18
  672. package/src/utils/objects.ts +4 -9
  673. package/src/utils/tracer.ts +9 -5
  674. package/src/utils/zod-utils.ts +1 -3
  675. package/dist/_baseMerge-BiGRwuqv.js +0 -165
  676. package/dist/any-language-editor-D4q-IFcM.js +0 -76
  677. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  678. package/dist/assets/worker-HPY9fbhz.js +0 -114
  679. package/dist/code-visibility-vqPDeo1_.js +0 -138
  680. package/dist/dropdown-menu-DHP9P4VE.js +0 -4678
  681. package/dist/feedback-button-BPcyKSZd.js +0 -379
  682. package/dist/hasIn-o2Us0uVx.js +0 -132
  683. package/dist/html-to-image-BdA59IUD.js +0 -3251
  684. package/dist/isArrayLikeObject-BZl-15ir.js +0 -450
  685. package/dist/isEmpty-BSZ1LaUo.js +0 -35
  686. package/dist/isSymbol-kQcfYbNX.js +0 -8
  687. package/dist/label-DoysmLMW.js +0 -281
  688. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  689. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +0 -23
  690. package/dist/pick-CJeoxYOS.js +0 -51
  691. package/dist/precisionRound-DMIVQrt2.js +0 -97
  692. package/dist/select-DemoKT4G.js +0 -1344
  693. package/dist/toDate-B5mIgxwZ.js +0 -1185
  694. package/dist/toast-PkdZraM8.js +0 -1830
  695. package/dist/use-restore-focus-CKjfFjLM.js +0 -6369
  696. package/dist/useLifecycle-BGWzTwHK.js +0 -169
  697. package/dist/useTheme-BhQvec43.js +0 -904
  698. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
  699. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
  700. package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
  701. package/src/components/editor/navigation/state.ts +0 -65
  702. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
  703. package/src/core/ai/tools/run-cells-tool.ts +0 -303
  704. package/src/core/attachments/state.ts +0 -18
  705. package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
  706. package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
  707. package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
  708. package/src/core/cells/document-changes.ts +0 -944
  709. package/src/core/codemirror/rtc/extension.ts +0 -453
  710. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
  711. package/src/core/codemirror/rtc/loro/awareness.ts +0 -531
  712. package/src/core/codemirror/rtc/loro/colors.ts +0 -38
  713. package/src/core/codemirror/rtc/loro/sync.ts +0 -168
  714. package/src/core/host/AGENTS.md +0 -11
  715. package/src/core/host/__tests__/events.test.ts +0 -46
  716. package/src/core/host/__tests__/fixtures.ts +0 -39
  717. package/src/core/host/__tests__/notebook-client.test.ts +0 -433
  718. package/src/core/host/__tests__/protocol.test.ts +0 -214
  719. package/src/core/host/__tests__/stream.test.ts +0 -211
  720. package/src/core/host/connection.ts +0 -81
  721. package/src/core/host/events.ts +0 -61
  722. package/src/core/host/notebook-client.ts +0 -290
  723. package/src/core/host/protocol.ts +0 -1943
  724. package/src/core/host/resources/resource.ts +0 -59
  725. package/src/core/host/stream.ts +0 -213
  726. package/src/core/rtc/state.ts +0 -34
  727. package/src/core/state/__tests__/jotai.test.ts +0 -25
  728. package/src/core/wasm/worker/message-buffer.ts +0 -33
  729. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  730. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -170
  731. package/src/core/websocket/state.ts +0 -7
  732. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  733. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  734. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  735. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  736. package/src/core/websocket/transports/basic.ts +0 -102
  737. package/src/core/websocket/transports/create.ts +0 -31
  738. package/src/core/websocket/transports/sse.ts +0 -308
  739. package/src/core/websocket/transports/transport.ts +0 -50
  740. package/src/core/websocket/transports/ws.ts +0 -98
  741. package/src/core/websocket/useNotebookClient.ts +0 -88
  742. package/src/utils/__tests__/id-tree.test.ts +0 -2145
  743. package/src/utils/id-tree.tsx +0 -1134
  744. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  745. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -0,0 +1,28 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { atom } from "jotai";
4
+ import type { DocumentModel } from "../notebook/document";
5
+ import type { NotebookReplica } from "../notebook/replica";
6
+
7
+ /** The replica owned by the mounted notebook session. */
8
+ export const activeNotebookReplicaAtom = atom<NotebookReplica | null>(null);
9
+
10
+ /** The document model owned by the mounted notebook session. */
11
+ export const activeDocumentModelAtom = atom<DocumentModel | null>(null);
12
+
13
+ /** The backend of the connected notebook, or null while none is. */
14
+ export const activeNotebookBackendAtom = atom((get) => {
15
+ const replica = get(activeNotebookReplicaAtom);
16
+ return replica === null ? null : get(replica.backendAtom);
17
+ });
18
+
19
+ /**
20
+ * The document the host last confirmed, or null while no notebook is
21
+ * connected. Facts the host owns read this one, such as permission, the
22
+ * app config, saved state and whether source is available. What the user
23
+ * is editing reads the model's document, which adds this browser's drafts.
24
+ */
25
+ export const confirmedDocumentAtom = atom((get) => {
26
+ const replica = get(activeNotebookReplicaAtom);
27
+ return replica === null ? null : get(replica.documentAtom);
28
+ });
@@ -0,0 +1,123 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ /** The backend the editor follows, chosen once for its mode. */
4
+
5
+ import { NotebookClient, StreamStopped } from "@marimo-team/client";
6
+ import type { NotebookId } from "@marimo-team/client/protocol";
7
+ import type { NotebookBackend } from "../notebook/replica";
8
+ import { PyodideBridge } from "../wasm/bridge";
9
+ import { isWasm } from "../wasm/utils";
10
+ import { sessionSse, websocket, withHeaders } from "../transports/server";
11
+ import {
12
+ createStaticNotebookBackend,
13
+ emptySnapshot,
14
+ type StaticNotebookSnapshot,
15
+ startWithSnapshot,
16
+ } from "../transports/static";
17
+
18
+ /** How the editor follows its notebook. */
19
+ export interface EditorBackendOptions {
20
+ static: boolean;
21
+ /** The notebook the page was served with, shown until the host answers. */
22
+ snapshot: StaticNotebookSnapshot | null;
23
+ transportType: "websocket" | "sse";
24
+ /** The session route, read before each connection. */
25
+ url: () => string;
26
+ /** The runtime's headers, read before each request. */
27
+ headers: () => Record<string, string>;
28
+ /** The host URL of a notebook the stream reported. */
29
+ notebookUrl: (notebookId: NotebookId) => URL;
30
+ /** Wait until the host can accept the first connection. */
31
+ waitUntilReady: () => Promise<void>;
32
+ /** Whether the host is reachable before an explicit reconnect. */
33
+ checkHealth: () => Promise<boolean>;
34
+ }
35
+
36
+ /**
37
+ * Read the session route once the host has started.
38
+ *
39
+ * Every connection waits for the same startup. Once it settles, even by
40
+ * giving up, connections read the route directly. An explicit reconnect
41
+ * checks the host's health instead.
42
+ */
43
+ function afterStartup({
44
+ url,
45
+ waitUntilReady,
46
+ }: Pick<EditorBackendOptions, "url" | "waitUntilReady">) {
47
+ let startup: Promise<void> | undefined;
48
+ let settled = false;
49
+ return async () => {
50
+ if (!settled) {
51
+ startup ??= waitUntilReady().finally(() => {
52
+ settled = true;
53
+ });
54
+ try {
55
+ await startup;
56
+ } catch (error) {
57
+ throw new StreamStopped("Healthy connection never made", {
58
+ cause: error,
59
+ });
60
+ }
61
+ }
62
+ return url();
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Follow the notebook running in the WASM worker.
68
+ *
69
+ * The worker's backend exists once the worker has started, so the first
70
+ * connection creates it. Commands are only for a notebook its stream reported.
71
+ */
72
+ function wasm(): NotebookBackend {
73
+ let backend: Promise<NotebookBackend> | undefined;
74
+ let started: NotebookBackend | undefined;
75
+ return {
76
+ transport: async (attempt, handlers) => {
77
+ backend ??= PyodideBridge.INSTANCE.createNotebookBackend();
78
+ try {
79
+ started = await backend;
80
+ } catch (error) {
81
+ throw new StreamStopped("The WASM notebook did not start", {
82
+ cause: error,
83
+ });
84
+ }
85
+ return started.transport(attempt, handlers);
86
+ },
87
+ notebook: (id) => {
88
+ if (started === undefined) {
89
+ throw new Error("The WASM notebook has not started");
90
+ }
91
+ return started.notebook(id);
92
+ },
93
+ };
94
+ }
95
+
96
+ /** Choose the backend for the editor's notebook. */
97
+ export function createEditorBackend(
98
+ options: EditorBackendOptions,
99
+ ): NotebookBackend {
100
+ if (options.static) {
101
+ return createStaticNotebookBackend(
102
+ options.snapshot ?? emptySnapshot("static"),
103
+ );
104
+ }
105
+ const live = isWasm() ? wasm() : server(options);
106
+ return options.snapshot ? startWithSnapshot(options.snapshot, live) : live;
107
+ }
108
+
109
+ /** Follow the notebook on the server, over SSE or a WebSocket. */
110
+ function server(options: EditorBackendOptions): NotebookBackend {
111
+ const url = afterStartup(options);
112
+ return {
113
+ transport:
114
+ options.transportType === "sse"
115
+ ? sessionSse(url, options.headers)
116
+ : websocket(url),
117
+ notebook: (id) =>
118
+ new NotebookClient(options.notebookUrl(id), {
119
+ fetch: withHeaders(options.headers),
120
+ }),
121
+ checkHealth: options.checkHealth,
122
+ };
123
+ }
@@ -0,0 +1,7 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { atom } from "jotai";
4
+ import type { StaticNotebookSnapshot } from "../transports/static";
5
+
6
+ /** The notebook the page was served with, read at mount. Null when none was. */
7
+ export const embeddedSnapshotAtom = atom<StaticNotebookSnapshot | null>(null);
@@ -1,12 +1,12 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import type { ConnectionStatus as HostConnectionStatus } from "../host/connection";
3
+ import type { ConnectionStatus as HostConnectionStatus } from "../notebook/replica";
4
4
  import type { NotificationMessageData } from "../kernel/messages";
5
5
 
6
6
  export {
7
7
  ConnectionState,
8
8
  ConnectionClosedReason as WebSocketClosedReason,
9
- } from "../host/connection";
9
+ } from "../notebook/replica";
10
10
 
11
11
  export type ConnectionPhase =
12
12
  | NotificationMessageData<"startup-progress">["phase"]
@@ -0,0 +1,74 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ /** The editor session's replica, following its backend while mounted. */
4
+
5
+ import { useStore } from "jotai";
6
+ import { useEffect, useMemo } from "react";
7
+ import useEvent from "react-use-event-hook";
8
+ import type {
9
+ NotificationMessage,
10
+ NotificationPayload,
11
+ } from "../kernel/messages";
12
+ import {
13
+ createNotebookReplica,
14
+ type NotebookReplica,
15
+ } from "../notebook/replica";
16
+ import { activeNotebookReplicaAtom } from "./active-notebook";
17
+ import { createEditorBackend, type EditorBackendOptions } from "./backend";
18
+
19
+ type Options = EditorBackendOptions & {
20
+ onNotification: (notification: NotificationPayload) => void;
21
+ };
22
+
23
+ export function useNotebookReplica(options: Options): NotebookReplica {
24
+ const store = useStore();
25
+ const { static: isStatic, snapshot, transportType } = options;
26
+ const replica = useMemo(() => createNotebookReplica(store), [store]);
27
+ const url = useEvent(options.url);
28
+ const headers = useEvent(options.headers);
29
+ const notebookUrl = useEvent(options.notebookUrl);
30
+ const waitUntilReady = useEvent(options.waitUntilReady);
31
+ const checkHealth = useEvent(options.checkHealth);
32
+ const onNotification = useEvent(options.onNotification);
33
+ // Opens nothing until the replica follows it.
34
+ const backend = useMemo(
35
+ () =>
36
+ createEditorBackend({
37
+ static: isStatic,
38
+ snapshot,
39
+ transportType,
40
+ url,
41
+ headers,
42
+ notebookUrl,
43
+ waitUntilReady,
44
+ checkHealth,
45
+ }),
46
+ [
47
+ isStatic,
48
+ snapshot,
49
+ transportType,
50
+ url,
51
+ headers,
52
+ notebookUrl,
53
+ waitUntilReady,
54
+ checkHealth,
55
+ ],
56
+ );
57
+
58
+ useEffect(() => {
59
+ store.set(activeNotebookReplicaAtom, replica);
60
+ const disconnect = replica.connect(backend, {
61
+ // The host validates the envelope, not the native notification contents.
62
+ onNotification: (notification) =>
63
+ onNotification({ data: notification as NotificationMessage }),
64
+ });
65
+ return () => {
66
+ disconnect();
67
+ if (store.get(activeNotebookReplicaAtom) === replica) {
68
+ store.set(activeNotebookReplicaAtom, null);
69
+ }
70
+ };
71
+ }, [replica, backend, store, onNotification]);
72
+
73
+ return replica;
74
+ }
@@ -2,17 +2,19 @@
2
2
 
3
3
  import { invalidatePackageData } from "@/core/packages/package-data";
4
4
  import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
5
- import { useLayoutEffect } from "react";
5
+ import { useEffect, useLayoutEffect, useMemo } from "react";
6
6
  import { useErrorBoundary } from "react-error-boundary";
7
7
  import { toast } from "@/components/ui/use-toast";
8
- import { getNotebook, useCellActions } from "@/core/cells/cells";
9
- import { applyTransactionChanges } from "@/core/cells/document-changes";
8
+ import {
9
+ getNotebook,
10
+ notebookAtom,
11
+ useReducerActions,
12
+ } from "@/core/cells/cells";
13
+ import { followDocument } from "@/core/cells/document";
10
14
  import { AUTOCOMPLETER } from "@/core/codemirror/completion/Autocompleter";
11
- import type {
12
- NotificationMessageData,
13
- NotificationPayload,
14
- } from "@/core/kernel/messages";
15
- import { useNotebookClient } from "@/core/websocket/useNotebookClient";
15
+ import { createDocumentModel } from "@/core/notebook/document";
16
+ import type { NotificationPayload } from "@/core/kernel/messages";
17
+ import { useNotebookReplica } from "@/core/session/useNotebookReplica";
16
18
  import { renderHTML } from "@/plugins/core/RenderHTML";
17
19
  import {
18
20
  handleWidgetMessage,
@@ -25,16 +27,15 @@ import { Logger } from "@/utils/Logger";
25
27
  import { reloadSafe } from "@/utils/reload-safe";
26
28
  import { useAlertActions } from "../alerts/state";
27
29
  import { cacheInfoAtom } from "../cache/requests";
28
- import { SCRATCH_CELL_ID } from "../cells/ids";
29
30
  import { useRunsActions } from "../cells/runs";
30
31
  import { focusAndScrollCellOutputIntoView } from "../cells/scrollCellIntoView";
31
32
  import {
32
33
  resyncBreakpoints,
33
34
  setActiveLine,
34
35
  } from "../codemirror/cells/debugger-state";
35
- import type { CellData } from "../cells/types";
36
+ import { notebookCells } from "../cells/utils";
36
37
  import { capabilitiesAtom } from "../config/capabilities";
37
- import { connectionTransportTypeAtom, useSetAppConfig } from "../config/config";
38
+ import { connectionTransportTypeAtom } from "../config/config";
38
39
  import { useDataSourceActions } from "../datasets/data-source-connections";
39
40
  import { invalidateDataSourceDiscovery } from "../datasets/data-source-discovery";
40
41
  import type { ConnectionName } from "../datasets/engines";
@@ -61,11 +62,12 @@ import {
61
62
  stableSessionIdAtom,
62
63
  } from "../kernel/session";
63
64
  import { initialRunCompletedAtom, kernelStateAtom } from "../kernel/state";
64
- import { type LayoutState, useLayoutActions } from "../layout/state";
65
+ import { useLayoutActions } from "../layout/state";
65
66
  import { kioskModeAtom } from "../mode";
66
67
  import { connectionAtom, startupProgressAtom } from "../network/connection";
68
+ import { savedLayoutAtom } from "../saving/state";
67
69
  import type { RequestId } from "../network/DeferredRequestRegistry";
68
- import { runtimeConfigAtom, useRuntimeManager } from "../runtime/config";
70
+ import { useRuntimeManager } from "../runtime/config";
69
71
  import { SECRETS_REGISTRY } from "../secrets/request-registry";
70
72
  import { isStaticNotebook } from "../static/static-state";
71
73
  import {
@@ -75,47 +77,28 @@ import {
75
77
  import { useStorageActions } from "../storage/state";
76
78
  import { useVariablesActions } from "../variables/state";
77
79
  import type { VariableName } from "../variables/types";
78
- import { isWasm } from "../wasm/utils";
80
+ import { activeDocumentModelAtom } from "./active-notebook";
81
+ import { embeddedSnapshotAtom } from "./embedded";
79
82
  import { WebSocketClosedReason, ConnectionState } from "./types";
80
83
 
81
- const SUPPORTS_LAZY_KERNELS = true;
82
-
83
- function getExistingCells(): CellData[] | undefined {
84
- if (!SUPPORTS_LAZY_KERNELS) {
85
- return undefined;
86
- }
87
-
88
- // Remove scratch pad
89
- return Object.values(getNotebook().cellData).filter(
90
- (cell) => cell.id !== SCRATCH_CELL_ID,
91
- );
92
- }
93
-
94
84
  /** Coordinate session startup and apply notifications to the editor. */
95
85
  export function useNotebookSession(opts: {
96
86
  sessionId: SessionId;
97
87
  autoInstantiate: boolean;
98
- setCells: (cells: CellData[], layout: LayoutState) => void;
99
88
  }) {
100
- const { autoInstantiate, sessionId, setCells } = opts;
89
+ const { autoInstantiate, sessionId } = opts;
101
90
  const { showBoundary } = useErrorBoundary();
91
+ const store = useStore();
102
92
 
103
- const { handleCellMessage } = useCellActions();
104
- const actionsWithoutMiddleware = useCellActions({ skipMiddleware: true });
105
-
106
- const handleDocumentTransaction = (
107
- transaction: NotificationMessageData<"notebook-document-transaction">["transaction"],
108
- ) => {
109
- applyTransactionChanges(
110
- transaction.changes,
111
- actionsWithoutMiddleware,
112
- () => getNotebook().cellIds.inOrderIds,
113
- );
114
- };
93
+ const {
94
+ handleCellMessage,
95
+ reconcileDocument,
96
+ setLastRun,
97
+ resetCellRuntimes,
98
+ } = useReducerActions();
115
99
  const { addCellNotification } = useRunsActions();
116
100
  const setKernelState = useSetAtom(kernelStateAtom);
117
101
  const setInitialRunCompleted = useSetAtom(initialRunCompletedAtom);
118
- const setAppConfig = useSetAppConfig();
119
102
  const { setVariables, setMetadata } = useVariablesActions();
120
103
  const { addColumnPreview } = useDatasetsActions();
121
104
  const { addDatasets, filterDatasetsFromVariables } = useDatasetsActions();
@@ -135,7 +118,6 @@ export function useNotebookSession(opts: {
135
118
  const setStableSessionId = useSetAtom(stableSessionIdAtom);
136
119
  const setCapabilities = useSetAtom(capabilitiesAtom);
137
120
  const runtimeManager = useRuntimeManager();
138
- const { notebookId } = useAtomValue(runtimeConfigAtom);
139
121
  const transportType = useAtomValue(connectionTransportTypeAtom);
140
122
  const setCacheInfo = useSetAtom(cacheInfoAtom);
141
123
  const setKernelStartupError = useSetAtom(kernelStartupErrorAtom);
@@ -167,18 +149,17 @@ export function useNotebookSession(opts: {
167
149
  setInitialRunCompleted(
168
150
  Boolean(msg.data.resumed || msg.data.auto_instantiated),
169
151
  );
170
- const existingCells = getExistingCells();
171
-
172
- handleKernelReady(msg.data, {
152
+ const layout = handleKernelReady(msg.data, {
173
153
  autoInstantiate,
174
- setCells,
154
+ cells: notebookCells(store.get(notebookAtom)),
155
+ setLastRun,
156
+ resetCellRuntimes,
175
157
  setLayoutData,
176
- setAppConfig,
177
158
  setCapabilities,
178
159
  setKernelState,
179
160
  onError: showBoundary,
180
- existingCells,
181
161
  });
162
+ store.set(savedLayoutAtom, layout);
182
163
  if (!msg.data.resumed) {
183
164
  // A freshly started kernel may expose a different environment
184
165
  // (e.g. new env vars); re-run discovery instead of reusing stale
@@ -265,13 +246,18 @@ export function useNotebookSession(opts: {
265
246
  filterStorageFromVariables(variableNames);
266
247
  return;
267
248
  case "variable-values":
268
- setMetadata(
269
- msg.data.variables.map((v) => ({
249
+ setMetadata([
250
+ ...(msg.data.removed ?? []).map((v) => ({
251
+ name: v.name as VariableName,
252
+ dataType: undefined,
253
+ value: undefined,
254
+ })),
255
+ ...msg.data.variables.map((v) => ({
270
256
  name: v.name as VariableName,
271
257
  dataType: v.datatype,
272
258
  value: v.value,
273
259
  })),
274
- );
260
+ ]);
275
261
  return;
276
262
  case "alert":
277
263
  toast({
@@ -392,7 +378,7 @@ export function useNotebookSession(opts: {
392
378
  );
393
379
  return;
394
380
  case "notebook-document-transaction":
395
- handleDocumentTransaction(msg.data.transaction);
381
+ // Edits reach the notebook through the host document.
396
382
  return;
397
383
  case "consumer-capabilities":
398
384
  setKioskMode(!msg.data.consumer_capabilities.edit);
@@ -402,7 +388,6 @@ export function useNotebookSession(opts: {
402
388
  }
403
389
  };
404
390
 
405
- const store = useStore();
406
391
  const onMessageError = (error: unknown) => {
407
392
  toast({
408
393
  title: "Failed to handle message",
@@ -410,25 +395,24 @@ export function useNotebookSession(opts: {
410
395
  variant: "danger",
411
396
  });
412
397
  };
413
- const notebook = useNotebookClient({
414
- sessionId,
398
+ const replica = useNotebookReplica({
415
399
  static: isStaticNotebook(),
400
+ snapshot: useAtomValue(embeddedSnapshotAtom),
416
401
  transportType,
417
- messageFormat:
418
- notebookId && transportType === "websocket" ? "host" : "session",
419
402
  url: () =>
420
403
  transportType === "sse"
421
404
  ? runtimeManager.getSseURL(sessionId).toString()
422
405
  : runtimeManager.getWsURL(sessionId).toString(),
423
406
  // SSE uses headers for auth. WebSockets carry the token in the URL.
424
407
  headers: () => runtimeManager.headers(),
408
+ notebookUrl: (notebookId) => runtimeManager.getNotebookURL(notebookId),
409
+ // Only the host's transports read the URL, so static and WASM never wait.
425
410
  waitUntilReady: async () => {
426
- if (!isStaticNotebook() && !isWasm() && !runtimeManager.isSameOrigin) {
411
+ if (!runtimeManager.isSameOrigin) {
427
412
  await runtimeManager.waitForHealthy();
428
413
  }
429
414
  },
430
415
  checkHealth: () => runtimeManager.reconcileFromHealth(),
431
- onMessageError,
432
416
  onNotification: (notification) => {
433
417
  try {
434
418
  handleNotification(notification);
@@ -439,10 +423,39 @@ export function useNotebookSession(opts: {
439
423
  },
440
424
  });
441
425
 
426
+ const documentModel = useMemo(
427
+ () =>
428
+ createDocumentModel({
429
+ store,
430
+ documentAtom: replica.documentAtom,
431
+ backendAtom: replica.backendAtom,
432
+ }),
433
+ [store, replica],
434
+ );
435
+ // Edits outlive reconnects and end with the session. The notebook's cells
436
+ // follow the document for as long as the session is mounted.
437
+ useEffect(() => {
438
+ const controller = new AbortController();
439
+ documentModel.start({ signal: controller.signal });
440
+ store.set(activeDocumentModelAtom, documentModel);
441
+ followDocument({
442
+ store,
443
+ model: documentModel,
444
+ reconcile: reconcileDocument,
445
+ signal: controller.signal,
446
+ });
447
+ return () => {
448
+ controller.abort();
449
+ if (store.get(activeDocumentModelAtom) === documentModel) {
450
+ store.set(activeDocumentModelAtom, null);
451
+ }
452
+ };
453
+ }, [documentModel, store, reconcileDocument]);
454
+
442
455
  // Subscribe before passive connection setup: static/WASM transports can emit synchronously.
443
456
  useLayoutEffect(() => {
444
457
  const updateConnection = () => {
445
- const status = store.get(notebook.connectionAtom);
458
+ const status = store.get(replica.connectionAtom);
446
459
  if (status.state === ConnectionState.NOT_STARTED) {
447
460
  return;
448
461
  }
@@ -473,16 +486,16 @@ export function useNotebookSession(opts: {
473
486
  return status;
474
487
  });
475
488
  };
476
- const unsubscribe = store.sub(notebook.connectionAtom, updateConnection);
489
+ const unsubscribe = store.sub(replica.connectionAtom, updateConnection);
477
490
  updateConnection();
478
491
  return unsubscribe;
479
492
  }, [
480
- notebook,
493
+ replica,
481
494
  store,
482
495
  setConnection,
483
496
  setKernelStartupError,
484
497
  updateStartupProgress,
485
498
  ]);
486
499
 
487
- return { notebook, connection, reconnect: notebook.reconnect };
500
+ return { replica, documentModel, connection, reconnect: replica.reconnect };
488
501
  }
@@ -0,0 +1,108 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { act, renderHook } from "@testing-library/react";
4
+ import { atom, Provider } from "jotai";
5
+ import type React from "react";
6
+ import { describe, expect, it, vi } from "vitest";
7
+ import { store, useJotaiEffect, waitFor } from "../jotai";
8
+
9
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
10
+ <Provider store={store}>{children}</Provider>
11
+ );
12
+
13
+ describe("waitFor function", () => {
14
+ it("should resolve when the atom satisfies the predicate", async () => {
15
+ const testAtom = atom(0);
16
+ store.set(testAtom, 10);
17
+
18
+ const result = await waitFor(testAtom, (value) => value === 10);
19
+ expect(result).toBe(10);
20
+ });
21
+
22
+ it("should resolve when the atom changes to satisfy the predicate", async () => {
23
+ const testAtom = atom(0);
24
+
25
+ setTimeout(() => store.set(testAtom, 15), 5);
26
+ setTimeout(() => store.set(testAtom, 20), 10);
27
+
28
+ const result = await waitFor(testAtom, (value) => value === 20);
29
+ expect(result).toBe(20);
30
+ });
31
+ });
32
+
33
+ describe("useJotaiEffect", () => {
34
+ it("calls the effect with the new and previous values", () => {
35
+ const testAtom = atom(0);
36
+ const effect = vi.fn();
37
+ renderHook(() => useJotaiEffect(testAtom, effect), { wrapper });
38
+
39
+ act(() => store.set(testAtom, 1));
40
+ act(() => store.set(testAtom, 2));
41
+
42
+ expect(effect.mock.calls).toEqual([
43
+ [1, 0],
44
+ [2, 1],
45
+ ]);
46
+ });
47
+
48
+ it("calls only the latest callback after a rerender", () => {
49
+ const testAtom = atom(0);
50
+ const first = vi.fn();
51
+ const second = vi.fn();
52
+ const { rerender } = renderHook(
53
+ ({ effect }) => useJotaiEffect(testAtom, effect),
54
+ { initialProps: { effect: first }, wrapper },
55
+ );
56
+
57
+ rerender({ effect: second });
58
+ act(() => store.set(testAtom, 1));
59
+
60
+ expect(first).not.toHaveBeenCalled();
61
+ expect(second).toHaveBeenCalledTimes(1);
62
+ });
63
+
64
+ it("subscribes once per rerender with an inline callback", () => {
65
+ const testAtom = atom(0);
66
+ const calls: number[] = [];
67
+ const { rerender } = renderHook(
68
+ () => useJotaiEffect(testAtom, (value) => calls.push(value)),
69
+ { wrapper },
70
+ );
71
+
72
+ rerender();
73
+ rerender();
74
+ act(() => store.set(testAtom, 1));
75
+
76
+ expect(calls).toEqual([1]);
77
+ });
78
+
79
+ it("stops listening to the previous atom when the atom changes", () => {
80
+ const firstAtom = atom(0);
81
+ const secondAtom = atom(0);
82
+ const effect = vi.fn();
83
+ const { rerender } = renderHook(
84
+ ({ target }) => useJotaiEffect(target, effect),
85
+ { initialProps: { target: firstAtom }, wrapper },
86
+ );
87
+
88
+ rerender({ target: secondAtom });
89
+ act(() => store.set(firstAtom, 1));
90
+ expect(effect).not.toHaveBeenCalled();
91
+
92
+ act(() => store.set(secondAtom, 1));
93
+ expect(effect).toHaveBeenCalledTimes(1);
94
+ });
95
+
96
+ it("unsubscribes on unmount", () => {
97
+ const testAtom = atom(0);
98
+ const effect = vi.fn();
99
+ const { unmount } = renderHook(() => useJotaiEffect(testAtom, effect), {
100
+ wrapper,
101
+ });
102
+
103
+ unmount();
104
+ act(() => store.set(testAtom, 1));
105
+
106
+ expect(effect).not.toHaveBeenCalled();
107
+ });
108
+ });
@@ -42,7 +42,7 @@ export function useJotaiEffect<T>(
42
42
  const store = useStore();
43
43
  useEffect(() => {
44
44
  let prevValue = store.get(atom);
45
- store.sub(atom, () => {
45
+ return store.sub(atom, () => {
46
46
  const value = store.get(atom);
47
47
  effect(value, prevValue);
48
48
  prevValue = value;