@marimo-team/islands 0.25.3-dev15 → 0.25.3-dev151

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 (502) hide show
  1. package/dist/{ConnectedDataExplorerComponent-CNMliVzw.js → ConnectedDataExplorerComponent-BAiSVaHj.js} +17 -15
  2. package/dist/{ErrorBoundary-z1rqMOCq.js → ErrorBoundary-BcVeWpOS.js} +16 -16
  3. package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-BBHN92-F.js} +2 -2
  4. package/dist/any-language-editor-3E24SnCV.js +75 -0
  5. package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-C0Rd64qh.js} +1 -1
  6. package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
  7. package/dist/assets/__vite-browser-external-BgQNn4dS.js +1 -0
  8. package/dist/assets/worker-FKe3RHT4.js +113 -0
  9. package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
  10. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CI4xUPsp.js} +2 -2
  11. package/dist/{chat-ui-DaHynk8g.js → chat-ui-CvB8Map3.js} +1142 -1141
  12. package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
  13. package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-hJXey5p2.js} +1 -1
  14. package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-JMzTmmVW.js} +1 -1
  15. package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-BIyoHTXi.js} +1 -1
  16. package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-CCzH2Uwa.js} +1 -1
  17. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  18. package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-DB1kOPS6.js} +2 -2
  19. package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-CPaFL0OB.js} +2 -2
  20. package/dist/{code-visibility-BFMjPeTv.js → code-visibility-DwvgNXfD.js} +6 -6
  21. package/dist/{common-JHV-U5GC.js → common-DbeFugQS.js} +6827 -6647
  22. package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
  23. package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-CF93uliH.js} +1 -1
  24. package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-BBB-_p9D.js} +1 -1
  25. package/dist/{data-grid-overlay-editor-BkL0DXBi.js → data-grid-overlay-editor-CcwDweHQ.js} +5 -5
  26. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  27. package/dist/{diagram-S7CK7UJ4-BsSJJldB.js → diagram-S7CK7UJ4-BynCnbyt.js} +1 -1
  28. package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-svOxikMa.js} +1 -1
  29. package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-BVQSnPx0.js} +1 -1
  30. package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-nR1J0BH5.js} +1 -1
  31. package/dist/{dialog-CEBFZNyc.js → dialog-DgeqyrEZ.js} +3 -3
  32. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  33. package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-GWcGCcxE.js} +1277 -1229
  34. package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-C9tq9-Qo.js} +2 -2
  35. package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-BiaeB7Fi.js} +1 -1
  36. package/dist/{error-banner-D-WCIiMt.js → error-banner-D40pmfQQ.js} +83 -83
  37. package/dist/{error-entries-Bv6bZPF3.js → error-entries-CmFDQ9CA.js} +1018 -977
  38. package/dist/{feedback-button-do3RdfYX.js → feedback-button-CMOX9MZM.js} +23 -23
  39. package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-f-sLm87k.js} +2 -2
  40. package/dist/{formats-27CW_UP4.js → formats-CCxaLPNs.js} +3 -3
  41. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  42. package/dist/{glide-data-editor-B2KXsLT5.js → glide-data-editor-C2oatpsM.js} +370 -368
  43. package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
  44. package/dist/{globals-Cnjg2Own.js → globals-CIJRWTWH.js} +3 -3
  45. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  46. package/dist/{html-to-image-Bf8QMGi4.js → html-to-image-BrC8OJcj.js} +632 -595
  47. package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-BHrWywBe.js} +1 -1
  48. package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-Da4s0Reg.js} +1 -1
  49. package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-DDf1GVLj.js} +1 -1
  50. package/dist/{label-BDKF3Afc.js → label-D9_-zSg-.js} +3 -3
  51. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  52. package/dist/{loader-BQOfjTIJ.js → loader-DOVB0Syl.js} +12 -12
  53. package/dist/main.js +7553 -7232
  54. package/dist/{mermaid-CHo49Yv-.js → mermaid-ClwTt7OD.js} +38 -38
  55. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  56. package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-D60oMZtT.js} +1 -1
  57. package/dist/{number-overlay-editor-DBsAEYkJ.js → number-overlay-editor-Cw7gLBQL.js} +3 -3
  58. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  59. package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
  60. package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-B9wFpMga.js} +2 -2
  61. package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-BZwvMuBT.js} +1 -1
  62. package/dist/precisionRound-DhAzeRcm.js +49 -0
  63. package/dist/{process-output-BZg56CCb.js → process-output-Bw-vzyoy.js} +5 -5
  64. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  65. package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-DqhZGsN2.js} +2 -2
  66. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  67. package/dist/{requirementDiagram-BXWQKSXE-a_MxGvxe.js → requirementDiagram-BXWQKSXE-CL5dYARV.js} +1 -1
  68. package/dist/{reveal-component-IkMCCFzA.js → reveal-component-msJ58E5g.js} +14 -14
  69. package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
  70. package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-BSUCRd2x.js} +1 -1
  71. package/dist/{spec-BwarBpUJ.js → spec-DiSh_qJC.js} +41 -11
  72. package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-B-1Hvyb0.js} +2 -2
  73. package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH--HtiR4yB.js} +2 -2
  74. package/dist/style.css +1 -1
  75. package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-Bdfhrd-2.js} +1 -1
  76. package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-BJIfxSz0.js} +2 -2
  77. package/dist/{swiper-component-DKntyn8p.js → swiper-component-BkCm-kLg.js} +2 -2
  78. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  79. package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-Cs4EfFD3.js} +1 -1
  80. package/dist/{toDate-UtiwmnH2.js → toDate-DGvRHwTk.js} +19 -18
  81. package/dist/{toast-B9UMEi8u.js → toast-Btbve3Lm.js} +231 -213
  82. package/dist/{tooltip-BO1REbqs.js → tooltip-CJ4Rqasp.js} +327 -303
  83. package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-CmGwRNId.js} +1482 -1433
  84. package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-BmVgnMP5.js} +15 -14
  85. package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-eCL_SdeG.js} +2 -2
  86. package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-Ch_AeGu6.js} +1 -1
  87. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
  88. package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-B5BX921H.js} +3 -3
  89. package/dist/{useTheme-CRnjkku0.js → useTheme-Bq9pi_vz.js} +6 -6
  90. package/dist/{vega-component-BeF9dfyO.js → vega-component-BgyZ-COt.js} +147 -147
  91. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  92. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  93. package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-DRu0vRjO.js} +1 -1
  94. package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-DzbDxwDY.js} +1 -1
  95. package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-CLWj6ZFQ.js} +2 -2
  96. package/package.json +16 -16
  97. package/src/__tests__/module-entry.test.ts +44 -0
  98. package/src/__tests__/mount.test.ts +1 -21
  99. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  100. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  101. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  102. package/src/components/app-config/ai-config.tsx +7 -2
  103. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  104. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  105. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  106. package/src/components/chat/acp/blocks.tsx +3 -2
  107. package/src/components/chat/acp/session-tabs.tsx +8 -3
  108. package/src/components/chat/chat-components.tsx +2 -0
  109. package/src/components/chat/chat-panel.tsx +9 -8
  110. package/src/components/chat/chat-utils.ts +4 -8
  111. package/src/components/data-table/TableTopBar.tsx +2 -0
  112. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  113. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  114. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  115. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  116. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  117. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  118. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  119. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  120. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  121. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  122. package/src/components/data-table/cell-selection/feature.ts +2 -2
  123. package/src/components/data-table/cell-selection/types.ts +2 -2
  124. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  125. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  126. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  127. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  128. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  129. package/src/components/data-table/charts/charts.tsx +40 -30
  130. package/src/components/data-table/charts/storage.ts +16 -5
  131. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  132. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  133. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  134. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  135. package/src/components/data-table/columns.tsx +45 -46
  136. package/src/components/data-table/context-menu.tsx +36 -20
  137. package/src/components/data-table/data-table.tsx +13 -1
  138. package/src/components/data-table/date-popover.tsx +6 -4
  139. package/src/components/data-table/export-actions.tsx +76 -48
  140. package/src/components/data-table/range-focus/atoms.ts +4 -6
  141. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  142. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  143. package/src/components/data-table/renderers.tsx +16 -7
  144. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  145. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  146. package/src/components/data-table/search-highlight.tsx +79 -0
  147. package/src/components/data-table/types.ts +1 -0
  148. package/src/components/data-table/url-detector.tsx +49 -9
  149. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  150. package/src/components/datasources/__tests__/column-preview.test.tsx +98 -5
  151. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  152. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  153. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  154. package/src/components/datasources/column-preview.tsx +13 -4
  155. package/src/components/datasources/datasources.tsx +51 -39
  156. package/src/components/datasources/utils.ts +32 -23
  157. package/src/components/debugger/debugger-code.tsx +5 -0
  158. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  159. package/src/components/dependency-graph/elements.ts +24 -21
  160. package/src/components/dependency-graph/panels.tsx +2 -1
  161. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  162. package/src/components/editor/SortableCell.tsx +1 -3
  163. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  164. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  165. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  166. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +24 -0
  167. package/src/components/editor/actions/pair-with-agent-modal.tsx +18 -15
  168. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  169. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  170. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  171. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  172. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  173. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  174. package/src/components/editor/app-container.tsx +1 -1
  175. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  176. package/src/components/editor/cell/CreateCellButton.tsx +10 -12
  177. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  178. package/src/components/editor/cell/RunButton.tsx +2 -2
  179. package/src/components/editor/cell/StopButton.tsx +2 -2
  180. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  181. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  182. package/src/components/editor/cell/code/cell-editor.tsx +2 -2
  183. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  184. package/src/components/editor/cell/collapse.tsx +5 -3
  185. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  186. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  187. package/src/components/editor/chrome/components/feedback-button.tsx +1 -1
  188. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  189. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  190. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  191. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  192. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  193. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  194. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  195. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  196. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  197. package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -1
  198. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +9 -18
  199. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
  200. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  201. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  202. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  203. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  204. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  205. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  206. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  207. package/src/components/editor/connections/components.tsx +1 -1
  208. package/src/components/editor/controls/Controls.tsx +2 -2
  209. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  210. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  211. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +1 -1
  212. package/src/components/editor/controls/command-palette.tsx +22 -10
  213. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  214. package/src/components/editor/dynamic-favicon.tsx +21 -40
  215. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +9 -23
  216. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  217. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  218. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  219. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  220. package/src/components/editor/file-tree/file-explorer.tsx +45 -8
  221. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  222. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  223. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  224. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  225. package/src/components/editor/header/app-header.tsx +1 -1
  226. package/src/components/editor/header/status.tsx +40 -20
  227. package/src/components/editor/links/__tests__/cell-link.test.tsx +146 -0
  228. package/src/components/editor/links/cell-link.tsx +14 -5
  229. package/src/components/editor/navigation/focus-utils.ts +4 -4
  230. package/src/components/editor/notebook-banner.tsx +1 -0
  231. package/src/components/editor/notebook-cell.tsx +12 -3
  232. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  233. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  234. package/src/components/editor/output/ansi-reduce.ts +33 -20
  235. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  236. package/src/components/editor/package-alert.tsx +14 -7
  237. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  238. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  239. package/src/components/home/components.tsx +17 -31
  240. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  241. package/src/components/icons/large-spinner.tsx +3 -14
  242. package/src/components/icons/spinner.tsx +1 -1
  243. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  244. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  245. package/src/components/pages/home-page.tsx +164 -91
  246. package/src/components/scratchpad/scratchpad.test.tsx +95 -0
  247. package/src/components/scratchpad/scratchpad.tsx +16 -3
  248. package/src/components/slides/reveal-component.tsx +4 -2
  249. package/src/components/slides/slide-cell-view.tsx +1 -1
  250. package/src/components/slides/slide-form.tsx +1 -0
  251. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  252. package/src/components/tracing/tracing.tsx +45 -41
  253. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  254. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  255. package/src/components/ui/alert-dialog.tsx +1 -1
  256. package/src/components/ui/draggable-popover.tsx +24 -2
  257. package/src/components/ui/range-slider.tsx +22 -9
  258. package/src/core/ai/context/providers/datasource.ts +6 -2
  259. package/src/core/ai/tools/base.ts +16 -7
  260. package/src/core/ai/tools/edit-notebook-tool.ts +47 -45
  261. package/src/core/ai/tools/registry.ts +13 -8
  262. package/src/core/ai/tools/sample-tool.ts +6 -7
  263. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
  264. package/src/core/cells/__tests__/cell.test.ts +39 -0
  265. package/src/core/cells/__tests__/cells.test.ts +3 -1
  266. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  267. package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
  268. package/src/core/cells/__tests__/session.test.ts +117 -36
  269. package/src/core/cells/cell.ts +14 -3
  270. package/src/core/cells/cells.ts +3 -1
  271. package/src/core/cells/pending-delete-service.ts +2 -6
  272. package/src/core/cells/session.ts +1 -1
  273. package/src/core/cells/types.ts +10 -1
  274. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  275. package/src/core/codemirror/cells/__tests__/extensions.test.ts +15 -0
  276. package/src/core/codemirror/cells/extensions.ts +7 -3
  277. package/src/core/codemirror/keymaps/vim.ts +2 -6
  278. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  279. package/src/core/codemirror/language/extension.ts +8 -8
  280. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  281. package/src/core/codemirror/language/languages/python.ts +16 -10
  282. package/src/core/codemirror/language/languages/sql/sql.ts +9 -7
  283. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  284. package/src/core/codemirror/language/types.ts +7 -7
  285. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  286. package/src/core/codemirror/readonly/extension.ts +2 -2
  287. package/src/core/codemirror/rtc/extension.ts +24 -12
  288. package/src/core/codemirror/rtc/loro/awareness.ts +34 -19
  289. package/src/core/codemirror/rtc/loro/sync.ts +1 -0
  290. package/src/core/codemirror/utils.ts +1 -0
  291. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  292. package/src/core/datasets/data-source-discovery.ts +4 -6
  293. package/src/core/edit-app.tsx +2 -2
  294. package/src/core/export/hooks.ts +1 -1
  295. package/src/core/hotkeys/actions.ts +2 -4
  296. package/src/core/islands/__tests__/bootstrap.test.ts +16 -42
  297. package/src/core/islands/__tests__/bridge.test.ts +31 -26
  298. package/src/core/islands/bootstrap.ts +22 -52
  299. package/src/core/islands/bridge.ts +31 -20
  300. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  301. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  302. package/src/core/islands/worker/controller.ts +4 -10
  303. package/src/core/islands/worker/worker.tsx +33 -33
  304. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  305. package/src/core/network/__tests__/connection.test.ts +1 -1
  306. package/src/core/network/connection-notice.ts +1 -1
  307. package/src/core/network/connection.ts +5 -3
  308. package/src/core/network/requests-lazy.ts +1 -1
  309. package/src/core/network/useConnectionNotice.ts +8 -2
  310. package/src/core/notebook/attachments.ts +38 -0
  311. package/src/core/notebook/document/__tests__/codemirror.test.ts +485 -0
  312. package/src/core/notebook/document/__tests__/draft.test.ts +322 -0
  313. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  314. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  315. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  316. package/src/core/notebook/document/__tests__/model.test.ts +191 -0
  317. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  318. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  319. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  320. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  321. package/src/core/notebook/document/__tests__/state.test.ts +438 -0
  322. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  323. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  324. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  325. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  326. package/src/core/notebook/document/__tests__/user.ts +61 -0
  327. package/src/core/notebook/document/codemirror.ts +311 -0
  328. package/src/core/notebook/document/draft.ts +472 -0
  329. package/src/core/notebook/document/hooks.tsx +118 -0
  330. package/src/core/notebook/document/index.ts +15 -0
  331. package/src/core/notebook/document/model.ts +55 -0
  332. package/src/core/notebook/document/select.ts +41 -0
  333. package/src/core/notebook/document/state.ts +374 -0
  334. package/src/core/notebook/document/sync.ts +369 -0
  335. package/src/core/notebook/index.ts +18 -0
  336. package/src/core/notebook/replica/AGENTS.md +11 -0
  337. package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
  338. package/src/core/notebook/replica/__tests__/document.test.ts +126 -0
  339. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  340. package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
  341. package/src/core/notebook/replica/backend.ts +19 -0
  342. package/src/core/notebook/replica/connection.ts +42 -0
  343. package/src/core/notebook/replica/index.ts +13 -0
  344. package/src/core/notebook/replica/replica.ts +286 -0
  345. package/src/core/notebook/replica/resources/attachments.ts +22 -0
  346. package/src/core/notebook/replica/resources/document.ts +101 -0
  347. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  348. package/src/core/packages/useSandboxController.ts +1 -1
  349. package/src/core/run-app.tsx +3 -3
  350. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  351. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  352. package/src/core/runtime/__tests__/runtime.test.ts +32 -58
  353. package/src/core/runtime/adapter.ts +1 -1
  354. package/src/core/runtime/config.ts +2 -2
  355. package/src/core/runtime/runtime.ts +38 -42
  356. package/src/core/runtime/types.ts +0 -2
  357. package/src/core/saving/filename.ts +1 -1
  358. package/src/core/saving/save-component.tsx +13 -4
  359. package/src/core/saving/useAutoSave.ts +1 -1
  360. package/src/core/session/__tests__/backend.test.ts +235 -0
  361. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +183 -0
  362. package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +609 -0
  363. package/src/core/session/active-notebook.ts +7 -0
  364. package/src/core/session/backend.ts +125 -0
  365. package/src/core/{websocket → session}/types.ts +2 -2
  366. package/src/core/session/useNotebookReplica.ts +72 -0
  367. package/src/core/{websocket → session}/useNotebookSession.tsx +18 -25
  368. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  369. package/src/core/state/jotai.ts +1 -1
  370. package/src/core/static/__tests__/files.test.ts +38 -10
  371. package/src/core/static/files.ts +2 -0
  372. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  373. package/src/core/transports/__tests__/server.test.ts +408 -0
  374. package/src/core/transports/__tests__/static.test.ts +175 -0
  375. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  376. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  377. package/src/core/transports/server.ts +152 -0
  378. package/src/core/transports/static.ts +84 -0
  379. package/src/core/transports/wasm.ts +97 -0
  380. package/src/core/wasm/__tests__/bridge.test.ts +213 -50
  381. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  382. package/src/core/wasm/bridge.ts +81 -52
  383. package/src/core/wasm/rpc.ts +15 -3
  384. package/src/core/wasm/store.ts +3 -3
  385. package/src/core/wasm/worker/bootstrap.ts +55 -51
  386. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  387. package/src/core/wasm/worker/save-worker.ts +9 -10
  388. package/src/core/wasm/worker/types.ts +29 -18
  389. package/src/core/wasm/worker/worker.ts +97 -44
  390. package/src/css/globals.css +5 -0
  391. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  392. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  393. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  394. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  395. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  396. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  397. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  398. package/src/hooks/useAsyncData.ts +3 -3
  399. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  400. package/src/hooks/useDebounce.ts +6 -10
  401. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  402. package/src/hooks/useDelayElapsed.ts +14 -10
  403. package/src/hooks/useElapsedTime.ts +3 -3
  404. package/src/hooks/useEventListener.ts +1 -2
  405. package/src/hooks/useInputHistory.ts +4 -7
  406. package/src/hooks/useInternalStateWithSync.ts +6 -6
  407. package/src/hooks/useResizeObserver.ts +4 -7
  408. package/src/hooks/useScript.ts +67 -70
  409. package/src/hooks/useStateForKey.ts +93 -0
  410. package/src/mount.tsx +1 -5
  411. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  412. package/src/plugins/core/registerReactComponent.tsx +1 -1
  413. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  414. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  415. package/src/plugins/impl/DataTablePlugin.tsx +29 -33
  416. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  417. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  418. package/src/plugins/impl/FormPlugin.tsx +1 -1
  419. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  420. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  421. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  422. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +117 -1
  423. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  424. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  425. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  426. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +2 -0
  427. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  428. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  429. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  430. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  431. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  432. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  433. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  434. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  435. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  436. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  437. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  438. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  439. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  440. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  441. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  442. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  443. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  444. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  445. package/src/plugins/impl/panel/utils.ts +17 -0
  446. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  447. package/src/plugins/impl/plotly/selection.ts +25 -19
  448. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  449. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  450. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  451. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  452. package/src/stories/button.stories.tsx +1 -0
  453. package/src/stories/cell.stories.tsx +1 -1
  454. package/src/stories/editor.stories.tsx +24 -17
  455. package/src/stories/form-wrapper.stories.tsx +2 -2
  456. package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
  457. package/src/stories/runtime-story.tsx +1 -1
  458. package/src/stories/select.stories.tsx +2 -2
  459. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  460. package/src/utils/__tests__/arrays.test.ts +35 -0
  461. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  462. package/src/utils/__tests__/numbers.test.ts +105 -1
  463. package/src/utils/__tests__/objects.test.ts +21 -0
  464. package/src/utils/arrays.ts +11 -2
  465. package/src/utils/blob.ts +1 -1
  466. package/src/utils/maps.ts +0 -3
  467. package/src/utils/numbers.ts +79 -18
  468. package/src/utils/objects.ts +4 -9
  469. package/src/utils/once.ts +19 -19
  470. package/src/utils/tracer.ts +9 -5
  471. package/src/utils/zod-utils.ts +1 -3
  472. package/dist/any-language-editor-DZ_YTVus.js +0 -76
  473. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  474. package/dist/assets/worker-HPY9fbhz.js +0 -114
  475. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  476. package/dist/precisionRound-DMIVQrt2.js +0 -97
  477. package/src/core/attachments/state.ts +0 -21
  478. package/src/core/host/AGENTS.md +0 -6
  479. package/src/core/host/__tests__/events.test.ts +0 -46
  480. package/src/core/host/__tests__/notebook-client.test.ts +0 -191
  481. package/src/core/host/__tests__/protocol.test.ts +0 -214
  482. package/src/core/host/connection.ts +0 -81
  483. package/src/core/host/events.ts +0 -60
  484. package/src/core/host/notebook-client.ts +0 -226
  485. package/src/core/host/protocol.ts +0 -1943
  486. package/src/core/state/__tests__/jotai.test.ts +0 -25
  487. package/src/core/wasm/worker/message-buffer.ts +0 -33
  488. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  489. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -140
  490. package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +0 -883
  491. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  492. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  493. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  494. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  495. package/src/core/websocket/transports/basic.ts +0 -102
  496. package/src/core/websocket/transports/create.ts +0 -31
  497. package/src/core/websocket/transports/sse.ts +0 -308
  498. package/src/core/websocket/transports/transport.ts +0 -50
  499. package/src/core/websocket/transports/ws.ts +0 -98
  500. package/src/core/websocket/useNotebookClient.ts +0 -80
  501. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  502. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -9,11 +9,7 @@ import {
9
9
  } from "@/plugins/impl/anywidget/registry";
10
10
  import { initializePlugins } from "@/plugins/plugins";
11
11
  import { Functions } from "@/utils/functions";
12
- import {
13
- safeExtractSetUIElementMessageBuffers,
14
- type JsonString,
15
- } from "@/utils/json/base64";
16
- import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
12
+ import { safeExtractSetUIElementMessageBuffers } from "@/utils/json/base64";
17
13
  import { Logger } from "@/utils/Logger";
18
14
  import { logNever } from "@/utils/assertNever";
19
15
  import {
@@ -30,10 +26,7 @@ import {
30
26
  handleKernelReady,
31
27
  handleRemoveUIElements,
32
28
  } from "../kernel/handlers";
33
- import type {
34
- NotificationMessage,
35
- NotificationMessageType,
36
- } from "../kernel/messages";
29
+ import type { NotificationMessage } from "../kernel/messages";
37
30
  import { queryParamHandlers } from "../kernel/queryParamHandlers";
38
31
  import { RuntimeState } from "../kernel/RuntimeState";
39
32
  import { initialModeAtom } from "../mode";
@@ -126,19 +119,9 @@ export async function initializeIslands(
126
119
  }
127
120
  });
128
121
 
129
- // Wire up kernel message handling
130
- // The wire format is {"op": "...", "data": {"op": "...", ...}} — both
131
- // the envelope and the payload carry the op. The bridge types the message
132
- // as NotificationPayload (just {data}), but the actual wire format
133
- // includes the outer op too.
134
- // Worker metadata identifies the session that emitted the message.
135
- bridge.consumeMessages(({ message, sessionGeneration }) => {
136
- handleMessage(
137
- message as unknown as JsonString<IslandsNotificationMessage>,
138
- actions,
139
- store,
140
- sessionGeneration,
141
- );
122
+ // Each notification names the session that sent it.
123
+ bridge.consumeNotifications((notification, sessionGeneration) => {
124
+ handleNotification(notification, actions, store, sessionGeneration);
142
125
  });
143
126
 
144
127
  // Track first user interaction before initialization completes
@@ -154,27 +137,15 @@ export async function initializeIslands(
154
137
  RuntimeState.INSTANCE.start(bridge.sendComponentValues);
155
138
  }
156
139
 
157
- type IslandsNotificationMessage = {
158
- [K in NotificationMessageType]: {
159
- data: Extract<NotificationMessage, { op: K }>;
160
- op: K;
161
- };
162
- }[NotificationMessageType];
163
-
164
- /**
165
- * Handles a single message from the kernel.
166
- *
167
- * Wire format from Python: {"op": "<name>", "data": {"op": "<name>", ...}}
168
- */
140
+ /** Handles a single notification from the kernel. */
169
141
  // oxlint-disable-next-line marimo/prefer-object-params
170
- function handleMessage(
171
- message: JsonString<IslandsNotificationMessage>,
142
+ function handleNotification(
143
+ msg: NotificationMessage,
172
144
  actions: NotebookActions,
173
145
  store: Store,
174
146
  sessionGeneration: number,
175
147
  ): void {
176
148
  try {
177
- const msg = jsonParseWithSpecialChar(message);
178
149
  Logger.debug("Islands received message:", msg.op);
179
150
 
180
151
  switch (msg.op) {
@@ -209,7 +180,6 @@ function handleMessage(
209
180
  case "cache-info":
210
181
  case "kernel-startup-error":
211
182
  case "notebook-document-transaction":
212
- case "attachments":
213
183
  return;
214
184
 
215
185
  case "completed-run":
@@ -224,7 +194,7 @@ function handleMessage(
224
194
  return;
225
195
 
226
196
  case "kernel-ready":
227
- handleKernelReady(msg.data, {
197
+ handleKernelReady(msg, {
228
198
  autoInstantiate: true,
229
199
  setCells: actions.setCells,
230
200
  setLayoutData: Functions.NOOP,
@@ -240,47 +210,47 @@ function handleMessage(
240
210
 
241
211
  case "send-ui-element-message":
242
212
  UI_ELEMENT_REGISTRY.broadcastMessage(
243
- msg.data.ui_element,
244
- msg.data.message,
245
- safeExtractSetUIElementMessageBuffers(msg.data),
213
+ msg.ui_element,
214
+ msg.message,
215
+ safeExtractSetUIElementMessageBuffers(msg),
246
216
  );
247
217
  return;
248
218
 
249
219
  case "remove-ui-elements":
250
- handleRemoveUIElements(msg.data);
220
+ handleRemoveUIElements(msg);
251
221
  return;
252
222
 
253
223
  case "function-call-result":
254
- FUNCTIONS_REGISTRY.resolve(msg.data.function_call_id, msg.data);
224
+ FUNCTIONS_REGISTRY.resolve(msg.function_call_id, msg);
255
225
  return;
256
226
 
257
227
  case "cell-op":
258
- handleCellNotificationeration(msg.data, actions.handleCellMessage);
228
+ handleCellNotificationeration(msg, actions.handleCellMessage);
259
229
  return;
260
230
 
261
231
  case "alert":
262
232
  toast({
263
- title: msg.data.title,
264
- description: renderHTML({ html: msg.data.description }),
265
- variant: msg.data.variant,
233
+ title: msg.title,
234
+ description: renderHTML({ html: msg.description }),
235
+ variant: msg.variant,
266
236
  });
267
237
  return;
268
238
 
269
239
  case "query-params-append":
270
- queryParamHandlers.append(msg.data);
240
+ queryParamHandlers.append(msg);
271
241
  return;
272
242
  case "query-params-set":
273
- queryParamHandlers.set(msg.data);
243
+ queryParamHandlers.set(msg);
274
244
  return;
275
245
  case "query-params-delete":
276
- queryParamHandlers.delete(msg.data);
246
+ queryParamHandlers.delete(msg);
277
247
  return;
278
248
  case "query-params-clear":
279
249
  queryParamHandlers.clear();
280
250
  return;
281
251
 
282
252
  case "model-lifecycle":
283
- handleWidgetMessage(WIDGET_REGISTRY, msg.data);
253
+ handleWidgetMessage(WIDGET_REGISTRY, msg);
284
254
  return;
285
255
 
286
256
  case "consumer-capabilities":
@@ -5,15 +5,16 @@ import { getWorkerRPC } from "@/core/wasm/rpc";
5
5
  import { Deferred } from "@/utils/Deferred";
6
6
  import { throwNotImplemented } from "@/utils/functions";
7
7
  import { Logger } from "@/utils/Logger";
8
+ import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
8
9
  import { generateUUID } from "@/utils/uuid";
9
10
  import { initialNotebookState, notebookAtom } from "../cells/cells";
10
- import type { ClientCommand } from "../kernel/messages";
11
+ import type { ClientCommand, NotificationMessage } from "../kernel/messages";
11
12
  import type { EditRequests, RunRequests } from "../network/types";
12
13
  import { store as defaultStore } from "../state/jotai";
13
14
  import { getMarimoExportContext } from "../static/export-context";
14
15
  import { createMarimoFile, parseMarimoIslandApps } from "./parse";
15
16
  import { islandsInitializedAtom, islandsPendingInitialRunsAtom } from "./state";
16
- import type { IslandsKernelMessage, WorkerSchema } from "./worker/worker";
17
+ import type { WorkerSchema } from "./worker/worker";
17
18
  import type { WorkerFactory } from "./worker-factory";
18
19
  import { DefaultWorkerFactory } from "./worker-factory";
19
20
 
@@ -52,14 +53,14 @@ interface AppSession {
52
53
  * @example
53
54
  * ```ts
54
55
  * const bridge = new IslandsPyodideBridge();
55
- * bridge.consumeMessages(message => console.log(message));
56
+ * bridge.consumeNotifications((notification) => console.log(notification.op));
56
57
  * await bridge.initializeApps();
57
58
  * ```
58
59
  */
59
60
  export class IslandsPyodideBridge implements RunRequests, EditRequests {
60
61
  private rpc: ReturnType<typeof getWorkerRPC<WorkerSchema>>;
61
- private messageConsumer:
62
- | ((message: IslandsKernelMessage) => void)
62
+ private notificationConsumer:
63
+ | ((notification: NotificationMessage, sessionGeneration: number) => void)
63
64
  | undefined;
64
65
  private readonly store: typeof defaultStore;
65
66
  private readonly root: Document | Element;
@@ -110,14 +111,24 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
110
111
  },
111
112
  );
112
113
 
113
- this.rpc.addMessageListener("kernelMessage", (message) => {
114
- // A stopped session can still have messages in transit after the next
115
- // app takes ownership of the shared frontend state.
116
- if (!this.activeSessionGenerations.has(message.sessionGeneration)) {
117
- return;
118
- }
119
- this.messageConsumer?.(message);
120
- });
114
+ this.rpc.addMessageListener(
115
+ "notebookEvent",
116
+ ({ event, sessionGeneration }) => {
117
+ // A stopped session can still have events in transit after the next
118
+ // app takes ownership of the shared frontend state.
119
+ if (!this.activeSessionGenerations.has(sessionGeneration)) {
120
+ return;
121
+ }
122
+ // Islands follow only the notebook's marimo notifications.
123
+ const frame = jsonParseWithSpecialChar(event) as {
124
+ event: string;
125
+ data: { marimo?: NotificationMessage };
126
+ };
127
+ if (frame.event === "marimo" && frame.data.marimo) {
128
+ this.notificationConsumer?.(frame.data.marimo, sessionGeneration);
129
+ }
130
+ },
131
+ );
121
132
  }
122
133
 
123
134
  public async initializeApps(): Promise<void> {
@@ -246,14 +257,14 @@ export class IslandsPyodideBridge implements RunRequests, EditRequests {
246
257
  await this.rpc.proxy.request.startSession(opts);
247
258
  }
248
259
 
249
- /**
250
- * Sets up a consumer for kernel messages
251
- */
252
- public consumeMessages(
253
- consumer: (message: IslandsKernelMessage) => void,
260
+ /** Receive each running session's marimo notifications. */
261
+ public consumeNotifications(
262
+ consumer: (
263
+ notification: NotificationMessage,
264
+ sessionGeneration: number,
265
+ ) => void,
254
266
  ): void {
255
- this.messageConsumer = consumer;
256
- this.rpc.proxy.send.consumerReady({});
267
+ this.notificationConsumer = consumer;
257
268
  }
258
269
 
259
270
  // ============================================================================
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { fireEvent, render, screen } from "@testing-library/react";
4
4
  import { beforeEach, describe, expect, it, vi } from "vitest";
5
+ import { MockRequestClient } from "@/__mocks__/requests";
5
6
  import { TooltipProvider } from "@/components/ui/tooltip";
6
7
  import type { CellId } from "@/core/cells/ids";
7
8
  import * as requestsModule from "@/core/network/requests";
@@ -18,7 +19,8 @@ vi.mock("@/utils/copy", () => ({
18
19
  }));
19
20
 
20
21
  describe("IslandControls", () => {
21
- const mockSendRun = vi.fn();
22
+ const mockSendRun =
23
+ vi.fn<ReturnType<typeof requestsModule.useRequestClient>["sendRun"]>();
22
24
  const mockCopyToClipboard = vi.fn();
23
25
  const mockCodeCallback = vi.fn(() => "print('test code')");
24
26
  const cellId = "test-cell-id" as CellId;
@@ -30,11 +32,11 @@ describe("IslandControls", () => {
30
32
 
31
33
  beforeEach(() => {
32
34
  vi.clearAllMocks();
33
- mockSendRun.mockResolvedValue(undefined);
35
+ mockSendRun.mockResolvedValue(null);
34
36
 
35
- vi.spyOn(requestsModule, "useRequestClient").mockReturnValue({
36
- sendRun: mockSendRun,
37
- } as any);
37
+ vi.spyOn(requestsModule, "useRequestClient").mockReturnValue(
38
+ MockRequestClient.create({ sendRun: mockSendRun }),
39
+ );
38
40
 
39
41
  vi.spyOn(copyModule, "copyToClipboard").mockImplementation(
40
42
  mockCopyToClipboard,
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type { PyodideInterface } from "pyodide";
4
4
  import { describe, expect, it, vi } from "vitest";
5
+ import { Deferred } from "@/utils/Deferred";
5
6
  import { ReadonlyWasmController } from "../controller";
6
7
 
7
8
  class TestController extends ReadonlyWasmController {
@@ -50,15 +51,71 @@ function createPyodideStub(
50
51
  };
51
52
  }
52
53
 
53
- function startSession(controller: TestController, code: string) {
54
- return controller.startSession({
54
+ function prepareSession(controller: TestController, code: string) {
55
+ return controller.prepareSession({
55
56
  code,
56
57
  filename: `${code}.py`,
57
- onMessage: vi.fn(),
58
58
  });
59
59
  }
60
60
 
61
+ async function startSession(controller: TestController, code: string) {
62
+ const session = await prepareSession(controller, code);
63
+ void session.start();
64
+ return session;
65
+ }
66
+
61
67
  describe("WASM controller session lifecycle", () => {
68
+ it("releases a prepared session and ignores start after stop", async () => {
69
+ const { init, pyodide } = createPyodideStub();
70
+ const controller = new TestController();
71
+ controller.setPyodide(pyodide);
72
+
73
+ const session = await prepareSession(controller, "current");
74
+ await session.stop();
75
+ expect(init.destroy).toHaveBeenCalledOnce();
76
+ await session.start();
77
+ expect(init).not.toHaveBeenCalled();
78
+ });
79
+
80
+ it.each(["resolve", "reject"] as const)(
81
+ "releases a stopped session before its dependencies %s",
82
+ async (outcome) => {
83
+ const dependencies = new Deferred<void>();
84
+ const { init, loadPackagesFromImports, pyodide, bridge, stop } =
85
+ createPyodideStub();
86
+ loadPackagesFromImports.mockReturnValue(dependencies.promise);
87
+ const controller = new TestController();
88
+ controller.setPyodide(pyodide);
89
+ const session = await prepareSession(controller, "current");
90
+ const starting = session.start();
91
+ expect(init).not.toHaveBeenCalled();
92
+ await session.stop();
93
+ expect(init.destroy).toHaveBeenCalledOnce();
94
+ expect(bridge.destroy).toHaveBeenCalledOnce();
95
+ if (outcome === "resolve") {
96
+ dependencies.resolve();
97
+ } else {
98
+ dependencies.reject(new Error("Loading failed after stop"));
99
+ }
100
+ await starting;
101
+ await session.stop();
102
+ expect(stop).toHaveBeenCalledOnce();
103
+ expect(init).not.toHaveBeenCalled();
104
+ },
105
+ );
106
+
107
+ it("reports dependency failures when starting an active session", async () => {
108
+ const { init, loadPackagesFromImports, pyodide } = createPyodideStub();
109
+ loadPackagesFromImports.mockRejectedValue(new Error("Dependency failed"));
110
+ const controller = new TestController();
111
+ controller.setPyodide(pyodide);
112
+ const session = await prepareSession(controller, "current");
113
+ await expect(session.start()).rejects.toThrow("Dependency failed");
114
+ expect(init).not.toHaveBeenCalled();
115
+ expect(init.destroy).toHaveBeenCalledOnce();
116
+ await session.stop();
117
+ });
118
+
62
119
  it("stops and releases the active session", async () => {
63
120
  const { init, packages, pyodide, sessionResources, stop } =
64
121
  createPyodideStub();
@@ -116,7 +173,6 @@ describe("WASM controller session lifecycle", () => {
116
173
 
117
174
  await startSession(controller, "first");
118
175
  await startSession(controller, "second");
119
- second.bridge.destroy();
120
176
 
121
177
  expect(first.stop.destroy).not.toHaveBeenCalled();
122
178
 
@@ -126,6 +182,8 @@ describe("WASM controller session lifecycle", () => {
126
182
  expect(second.stop).toHaveBeenCalledOnce();
127
183
  expect(first.stop.destroy).toHaveBeenCalledOnce();
128
184
  expect(second.stop.destroy).toHaveBeenCalledOnce();
185
+ expect(first.bridge.destroy).toHaveBeenCalledOnce();
186
+ expect(second.bridge.destroy).toHaveBeenCalledOnce();
129
187
  });
130
188
 
131
189
  it("continues stopping sessions after one stop fails", async () => {
@@ -1,11 +1,9 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import type { PyodideInterface } from "pyodide";
3
3
  import { defaultUserConfig } from "@/core/config/config-schema";
4
- import type { NotificationPayload } from "@/core/kernel/messages";
5
4
  import { DefaultWasmController } from "@/core/wasm/worker/bootstrap";
6
5
  import { WasmFileSystem } from "@/core/wasm/worker/fs";
7
- import type { SerializedBridge } from "@/core/wasm/worker/types";
8
- import type { JsonString } from "@/utils/json/base64";
6
+ import type { WasmSession } from "@/core/wasm/worker/types";
9
7
  import { Logger } from "../../../utils/Logger";
10
8
 
11
9
  export class ReadonlyWasmController extends DefaultWasmController {
@@ -37,19 +35,15 @@ export class ReadonlyWasmController extends DefaultWasmController {
37
35
  return { code, filename };
38
36
  }
39
37
 
40
- public override async startSession(opts: {
38
+ public override async prepareSession(opts: {
41
39
  code: string;
42
40
  filename: string | null;
43
- onMessage: (message: JsonString<NotificationPayload>) => void;
44
- }): Promise<SerializedBridge> {
45
- const bridge = super.startSession({
41
+ }): Promise<WasmSession> {
42
+ return super.prepareSession({
46
43
  queryParameters: {},
47
44
  code: opts.code,
48
45
  filename: opts.filename,
49
- onMessage: opts.onMessage,
50
46
  userConfig: defaultUserConfig(),
51
47
  });
52
-
53
- return bridge;
54
48
  }
55
49
  }
@@ -1,21 +1,17 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import type { PyodideInterface } from "pyodide";
4
- import type { PyProxy } from "pyodide/ffi";
5
4
  import {
6
5
  createRPC,
7
6
  createRPCRequestHandler,
8
7
  createWorkerParentTransport,
9
8
  type RPCSchema,
10
9
  } from "rpc-anywhere";
11
- import type { NotificationPayload } from "@/core/kernel/messages";
12
10
  import type { ParentSchema } from "@/core/wasm/rpc";
13
11
  import { shouldLoadDuckDBPackages } from "@/core/wasm/utils";
14
12
  import { TRANSPORT_ID } from "@/core/wasm/worker/constants";
15
13
  import { getPyodideVersion } from "@/core/wasm/worker/getPyodideVersion";
16
- import { MessageBuffer } from "@/core/wasm/worker/message-buffer";
17
14
  import type { RawBridge, SerializedBridge } from "@/core/wasm/worker/types";
18
- import type { JsonString } from "@/utils/json/base64";
19
15
  import { Logger } from "@/utils/Logger";
20
16
  import { prettyError } from "../../../utils/errors";
21
17
  import { invariant } from "../../../utils/invariant";
@@ -45,14 +41,11 @@ async function loadPyodideAndPackages() {
45
41
  }
46
42
 
47
43
  const pyodideReadyPromise = loadPyodideAndPackages();
48
- export interface IslandsKernelMessage {
49
- message: JsonString<NotificationPayload>;
44
+ /** An event of one session's notebook stream. */
45
+ export interface IslandsNotebookEvent {
46
+ event: string;
50
47
  sessionGeneration: number;
51
48
  }
52
-
53
- const messageBuffer = new MessageBuffer<IslandsKernelMessage>((payload) => {
54
- rpc.send.kernelMessage(payload);
55
- });
56
49
  interface SessionRequest {
57
50
  code: string;
58
51
  appId: string;
@@ -79,21 +72,22 @@ async function startSession(
79
72
  code: opts.code,
80
73
  filename: `app-${opts.appId}.py`,
81
74
  });
82
- const nextBridge = await self.controller.startSession({
83
- ...notebook,
84
- onMessage: (message) => {
85
- messageBuffer.push({
86
- message,
87
- sessionGeneration: opts.sessionGeneration,
88
- });
89
- },
75
+ const session = await self.controller.prepareSession(notebook);
76
+ // Follow before the session instantiates. Each subscription begins with
77
+ // its own kernel-ready and the session's retained notifications.
78
+ try {
79
+ await follow(session.bridge, opts.sessionGeneration);
80
+ } catch (error) {
81
+ await session.stop();
82
+ throw error;
83
+ }
84
+ void session.start().catch((error: unknown) => {
85
+ rpc.send.initializedError({ error: prettyError(error) });
90
86
  });
91
- if (activeSession) {
92
- (nextBridge as unknown as PyProxy).destroy();
93
- } else {
87
+ if (!activeSession) {
94
88
  activeSession = {
95
89
  appId: opts.appId,
96
- bridge: nextBridge,
90
+ bridge: session.bridge,
97
91
  sessionGeneration: opts.sessionGeneration,
98
92
  };
99
93
  }
@@ -107,10 +101,23 @@ async function startSession(
107
101
  }
108
102
 
109
103
  async function stopActiveSession(): Promise<void> {
110
- const session = activeSession;
104
+ // Stopping closes every session and its notebook subscriptions.
111
105
  await self.controller.stopSession();
112
106
  activeSession = undefined;
113
- (session?.bridge as unknown as PyProxy | undefined)?.destroy();
107
+ }
108
+
109
+ async function follow(
110
+ bridge: SerializedBridge,
111
+ sessionGeneration: number,
112
+ ): Promise<void> {
113
+ const notebook = bridge.notebook;
114
+ try {
115
+ await notebook.subscribe(`island-${sessionGeneration}`, null, (event) => {
116
+ rpc.send.notebookEvent({ event, sessionGeneration });
117
+ });
118
+ } finally {
119
+ notebook.destroy();
120
+ }
114
121
  }
115
122
 
116
123
  function enqueueSession<T>(operation: () => Promise<T>): Promise<T> {
@@ -243,8 +250,8 @@ export type WorkerSchema = RPCSchema<
243
250
  messages: {
244
251
  // Emitted when the worker is ready
245
252
  ready: {};
246
- // Emitted when the kernel sends a message
247
- kernelMessage: IslandsKernelMessage;
253
+ // Emitted for each event of a session's notebook stream
254
+ notebookEvent: IslandsNotebookEvent;
248
255
  // Emitted when the Pyodide is initialized
249
256
  initialized: {};
250
257
  // Emitted when the Pyodide fails to initialize
@@ -263,13 +270,6 @@ const rpc = createRPC<WorkerSchema, ParentSchema>({
263
270
 
264
271
  rpc.send("ready", {});
265
272
 
266
- /// Listeners
267
- // When the consumer is ready, start the message buffer
268
- rpc.addMessageListener("consumerReady", async () => {
269
- await pyodideReadyPromise; // Make sure loading is done
270
- messageBuffer.start();
271
- });
272
-
273
273
  function getMarimoVersion() {
274
274
  return self.name; // We store the version in the worker name
275
275
  }
@@ -25,7 +25,7 @@ describe("RuntimeState", () => {
25
25
 
26
26
  beforeEach(() => {
27
27
  vi.clearAllMocks();
28
- mockSendComponentValues = vi.fn((args) => Promise.resolve(null));
28
+ mockSendComponentValues = vi.fn(() => Promise.resolve(null));
29
29
  uiElementRegistry = UIElementRegistry.INSTANCE;
30
30
  uiElementRegistry.entries.clear();
31
31
 
@@ -3,7 +3,7 @@
3
3
  import { afterEach, describe, expect, it } from "vitest";
4
4
  import { initialModeAtom } from "@/core/mode";
5
5
  import { store } from "@/core/state/jotai";
6
- import { ConnectionState } from "../../websocket/types";
6
+ import { ConnectionState } from "../../session/types";
7
7
  import { connectionAtom, waitForConnectionOpenIfNotebook } from "../connection";
8
8
 
9
9
  const NEVER = Symbol("never");
@@ -6,7 +6,7 @@ import {
6
6
  type ConnectionPhase,
7
7
  WebSocketClosedReason,
8
8
  ConnectionState,
9
- } from "@/core/websocket/types";
9
+ } from "@/core/session/types";
10
10
  import { connectionAtom } from "./connection";
11
11
 
12
12
  export interface ConnectionNotice {
@@ -4,11 +4,13 @@ import { atomWithReducer } from "jotai/utils";
4
4
  import type { NotificationMessageData } from "../kernel/messages";
5
5
  import { isNotebookPage } from "../mode";
6
6
  import { waitFor } from "../state/jotai";
7
- import { type ConnectionStatus, ConnectionState } from "../websocket/types";
7
+ import { type ConnectionStatus, ConnectionState } from "../session/types";
8
8
 
9
9
  /**
10
- * Atom for storing the connection status.
11
- * Initialized to NOT_STARTED.
10
+ * Shared application state, not the actual event-stream status.
11
+ *
12
+ * TODO(MO-8051) Expose read-only connection state and derive UI availability
13
+ * separately.
12
14
  */
13
15
  export const connectionAtom = atom<ConnectionStatus>({
14
16
  state: ConnectionState.NOT_STARTED,
@@ -7,7 +7,7 @@ import { memoizeLastValue } from "@/utils/once";
7
7
  import { waitForKernelToBeInstantiated } from "../kernel/state";
8
8
  import type { RuntimeManager } from "../runtime/runtime";
9
9
  import { store } from "../state/jotai";
10
- import { ConnectionState } from "../websocket/types";
10
+ import { ConnectionState } from "../session/types";
11
11
  import { connectionAtom, waitForConnectionOpen } from "./connection";
12
12
  import type { EditRequests, RunRequests } from "./types";
13
13
 
@@ -17,11 +17,17 @@ export function useConnectionNotice(
17
17
  const notice = useAtomValue(connectionNoticeAtom);
18
18
  const connected = useAtomValue(isConnectedAtom);
19
19
  const elapsed = useDelayElapsed(notice?.pending ? delayMs : 0);
20
- const [previous, setPrevious] = useState<ConnectionNotice | null>(null);
20
+ const [previous, setPrevious] = useState<ConnectionNotice | null>(
21
+ elapsed ? notice : null,
22
+ );
23
+
24
+ const visibleNotice = elapsed ? notice : null;
25
+ if ((notice || !connected) && previous !== visibleNotice) {
26
+ setPrevious(visibleNotice);
27
+ }
21
28
 
22
29
  useEffect(() => {
23
30
  if (notice || !connected) {
24
- setPrevious(elapsed ? notice : null);
25
31
  return;
26
32
  }
27
33
  const timeout = setTimeout(() => setPrevious(null), 1500);
@@ -0,0 +1,38 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { dequal } from "dequal";
4
+ import { atom, useAtomValue } from "jotai";
5
+ import { selectAtom } from "jotai/vanilla/utils";
6
+ import { useMemo } from "react";
7
+ import type { Attachment } from "@marimo-team/client/protocol";
8
+ import { activeNotebookReplicaAtom } from "../session/active-notebook";
9
+
10
+ export type { Attachment } from "@marimo-team/client/protocol";
11
+
12
+ const EMPTY_ATTACHMENTS: readonly Attachment[] = [];
13
+
14
+ /** Attachments visible to this session, empty while no notebook is available. */
15
+ export const notebookAttachmentsAtom = atom((get) => {
16
+ const replica = get(activeNotebookReplicaAtom);
17
+ return replica ? get(replica.attachmentsAtom) : EMPTY_ATTACHMENTS;
18
+ });
19
+
20
+ /** Current notebook attachments, optionally restricted to one kind. */
21
+ export function useNotebookAttachments(kind?: Attachment["kind"]) {
22
+ const attachments = useMemo(
23
+ () =>
24
+ kind === undefined
25
+ ? notebookAttachmentsAtom
26
+ : selectAtom(
27
+ notebookAttachmentsAtom,
28
+ (value) => value.filter((attachment) => attachment.kind === kind),
29
+ dequal,
30
+ ),
31
+ [kind],
32
+ );
33
+ return useAtomValue(attachments);
34
+ }
35
+
36
+ export function attachmentLabel(attachment: Attachment): string {
37
+ return attachment.name || "Agent";
38
+ }