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

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 (384) hide show
  1. package/dist/{ConnectedDataExplorerComponent-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
  2. package/dist/ErrorBoundary-Bfp74qVG.js +200 -0
  3. package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-Dlm5aWnH.js} +4 -4
  4. package/dist/{Plot-C-9MQeGP.js → Plot-CTyjbQDT.js} +21032 -20666
  5. package/dist/_baseMerge-BiGRwuqv.js +165 -0
  6. package/dist/{abnfDiagram-N423BO3Z-CQKwzX8t.js → abnfDiagram-VCTEODGH-CpN0FRda.js} +17 -18
  7. package/dist/{any-language-editor-DmQ7dyCx.js → any-language-editor-CycIVIeP.js} +17 -17
  8. package/dist/arc-7ra3iNdN.js +81 -0
  9. package/dist/architecture-7GRP2DOG-BWLylgiA.js +3 -0
  10. package/dist/{architectureDiagram-T3A2C74G-CncrDpfa.js → architectureDiagram-5GKGNRK7-DDyj5SRB.js} +25 -25
  11. package/dist/assets/__vite-browser-external-BajL8aoc.js +1 -0
  12. package/dist/assets/worker-BemUy60C.js +109 -0
  13. package/dist/blockDiagram-I7D4REHJ-BbXEXJRu.js +1922 -0
  14. package/dist/{button-CKBkqR9J.js → button-DdXAm8iz.js} +5 -5
  15. package/dist/{c4Diagram-5PPSVZJV-DarUk3Yq.js → c4Diagram-7LVT6UL2-DcLsbQmR.js} +696 -668
  16. package/dist/{capabilities-CMBBJTcc.js → capabilities-B3ce_GNu.js} +1 -1
  17. package/dist/{html-to-image-BhNoIBSU.js → cells-BSgNCBZ8.js} +6740 -10126
  18. package/dist/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
  19. package/dist/chat-ui-CygzVJ9s.js +5786 -0
  20. package/dist/{check-CHig47QV.js → check-B7cIK6gb.js} +1 -1
  21. package/dist/{chunk-2Q5K7J3B-BMuJl2jB.js → chunk-2Q5K7J3B-BMkUkeuy.js} +2 -2
  22. package/dist/chunk-4HAMMTFA-D2qv8E0X.js +4188 -0
  23. package/dist/{chunk-5VM5RSS4-Bcq0ftdy.js → chunk-5VM5RSS4-DKsmPCL6.js} +2 -2
  24. package/dist/{chunk-NSK5VX7P-CDTMcJB0.js → chunk-75Z2AOVW-5_HsvXwr.js} +23 -23
  25. package/dist/{chunk-I66GZJ75-BqyTCAPf.js → chunk-DU6HZSFF-BUgAHvnM.js} +21 -4
  26. package/dist/{chunk-2GRJ4B5K-DgO8Qudq.js → chunk-F27PBJKO-DHmYWZXr.js} +4 -4
  27. package/dist/{chunk-KEIR6QF5-C4KX3XYh.js → chunk-FOHPRMQF-BpYR8RqP.js} +4 -4
  28. package/dist/{chunk-WRU74C26-BpWsbiDK.js → chunk-GMAD6QVW-Czynz8aA.js} +486 -258
  29. package/dist/chunk-GVQU2GXP-yQEdulRS.js +37 -0
  30. package/dist/{chunk-5RXB4S5H-tLNUVDdO.js → chunk-IMKFNOWR-BfwTebD0.js} +11 -11
  31. package/dist/{chunk-JWPE2WC7-BJwjGUnF.js → chunk-JWPE2WC7-DJvv1t8U.js} +2 -2
  32. package/dist/chunk-L3NEJ4N5-DwRWnDDK.js +245 -0
  33. package/dist/{chunk-7Z6QIM7H-Dc18hFxH.js → chunk-OSK3NFVY-BBKU_Ign.js} +222 -144
  34. package/dist/{chunk-W5SLKNZC-DLnvpEtV.js → chunk-P2QGCYS3-C0iGU29N.js} +20 -20
  35. package/dist/{chunk-KBJHAD2P-BuqWqkcW.js → chunk-POPQ4Y6H-BCbS3Ozc.js} +4 -4
  36. package/dist/{chunk-4I5QYGJK-DpytHuZQ.js → chunk-PWAF6VOD-CTFCL0jI.js} +4 -4
  37. package/dist/{chunk-JQJVKLGR-CgqCwe8E.js → chunk-SHT3W25Y-BspJEJ5H.js} +109 -63
  38. package/dist/{chunk-6Q2QTUOP-DmTcEBMn.js → chunk-SVP7TREG-DX3rFNTe.js} +5 -5
  39. package/dist/{chunk-GF5L2VYU-B0wgCQgS.js → chunk-TICWLB2K-fVF7Uujg.js} +13 -13
  40. package/dist/{chunk-XXDRQBXY-D73H4IN0.js → chunk-XXDRQBXY-Dnl5VBqG.js} +3 -3
  41. package/dist/{chunk-Y2CYZVJY-DoegUj_e.js → chunk-Y2CYZVJY-DKKS1VyV.js} +1 -1
  42. package/dist/{chunk-5FQGJX7Z-B85XCPv6.js → chunk-YOKDWASO-DrWbKnxA.js} +6925 -5460
  43. package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +30 -0
  44. package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +30 -0
  45. package/dist/code-visibility-qtEE1_Zi.js +138 -0
  46. package/dist/{common-xHoep60C.js → common-BmP252R5.js} +8839 -12646
  47. package/dist/{compiler-runtime-CAH9RLw2.js → compiler-runtime-Cj8ZWiNS.js} +2 -2
  48. package/dist/copy-icon-CLdENY__.js +190 -0
  49. package/dist/{cose-bilkent-JH36ORCC-FUWHkXFX.js → cose-bilkent-JH36ORCC-_LyRKVqm.js} +2 -2
  50. package/dist/cubic-OaEBhQPK.js +1404 -0
  51. package/dist/cynefin-OW5HDTMX-obq-i80l.js +3 -0
  52. package/dist/{cynefinDiagram-MW4NZA55-BXSFK93J.js → cynefinDiagram-5FMLGOSQ-CFQrqzSX.js} +10 -10
  53. package/dist/{dagre-CGyalH38.js → dagre-BGSfXNEb.js} +678 -537
  54. package/dist/dagre-GXQ25YYZ-xHNAUTyG.js +425 -0
  55. package/dist/{data-grid-overlay-editor-DZM4BAaI.js → data-grid-overlay-editor-DtaTjDfe.js} +8 -9
  56. package/dist/{data-grid-types-BnZwWG8z.js → data-grid-types-BucVmDDp.js} +1 -1
  57. package/dist/{defaultLocale-DKaU_opG.js → defaultLocale-JI_lnoCe.js} +1 -1
  58. package/dist/{diagram-7IWD3JNH-BjfzDNvj.js → diagram-S7CK7UJ4-Bt1rPbAx.js} +40 -39
  59. package/dist/{diagram-UB23O5K3-DDg-7wLA.js → diagram-UQ7AKVKN-D1sq5FoZ.js} +10 -10
  60. package/dist/{diagram-B4RE2ZJO-CKccR9eE.js → diagram-VSXAHHWV-BKpmG23x.js} +10 -10
  61. package/dist/{diagram-Q27KOJAE-Zhz01ss7.js → diagram-VX7I27RA-BMwGFVD6.js} +21 -21
  62. package/dist/{diagram-LBJQPF4R-CJ-bOruh.js → diagram-Z3DM3KII--KLDR9Pl.js} +10 -10
  63. package/dist/dialog-CgNq6y9-.js +94 -0
  64. package/dist/{dist-dAqZAPcF.js → dist-1HDa70oE.js} +3 -3
  65. package/dist/{dist-Re9sOPOx.js → dist-9x1ZRe-e.js} +2 -2
  66. package/dist/{dist-DEeLqRlU.js → dist-B1vYLK28.js} +1 -1
  67. package/dist/{dist-C5Bn52W4.js → dist-B8D7McG3.js} +3 -3
  68. package/dist/{dist-_XvgytiS.js → dist-BHCHt1NI.js} +1 -1
  69. package/dist/{dist-CRjAdnqF.js → dist-BRxfaJgs.js} +3 -3
  70. package/dist/{dist-Byj2bV8o.js → dist-BVGtK7Ht.js} +1 -1
  71. package/dist/{dist-BIN5LKyE.js → dist-BaHjhkpZ.js} +2 -2
  72. package/dist/{dist-DVFbIwc5.js → dist-BtKIs9N-.js} +1 -1
  73. package/dist/{dist-BrQGcfQ9.js → dist-C2KzV-vf.js} +2 -2
  74. package/dist/{dist-DJFiGP2k.js → dist-C2wDlYdD.js} +2 -2
  75. package/dist/{dist-BVRM2y1P.js → dist-C8xMLVYi.js} +2 -2
  76. package/dist/dist-CMh_W4y4.js +538 -0
  77. package/dist/{extends-BPB6_lTK.js → dist-CO1AwwG_.js} +516 -561
  78. package/dist/{dist-BzN60Z2s.js → dist-CPGxfVGX.js} +1 -1
  79. package/dist/{dist-C7v-9nUK.js → dist-Cm3iAFMD.js} +3 -3
  80. package/dist/{dist-CGAxEiaM.js → dist-Cs2FijYk.js} +2 -2
  81. package/dist/{dist-hXd65f0_.js → dist-D1PpnuZB.js} +1 -1
  82. package/dist/{dist-VdvbxG72.js → dist-DHOTQar0.js} +1 -1
  83. package/dist/{dist-DcgzXCfy.js → dist-DPcEtqmG.js} +2 -2
  84. package/dist/{dist-D4Z_qdP4.js → dist-Df0wKI0F.js} +1 -1
  85. package/dist/{dist-qhLI-SHd.js → dist-DszxuxS1.js} +2 -2
  86. package/dist/{dist-BEmkrGoQ.js → dist-Kxgjxakw.js} +1 -1
  87. package/dist/{dist-BbSMhhD2.js → dist-KzZ7WELx.js} +2 -2
  88. package/dist/{dist-jWUab2d1.js → dist-lA1Cttkb.js} +1 -1
  89. package/dist/dropdown-menu-CZgjYSAh.js +4502 -0
  90. package/dist/{ebnfDiagram-BXEA7PRR-Dm75pCAS.js → ebnfDiagram-PWID7BFC-WnG4cvSQ.js} +17 -18
  91. package/dist/{erDiagram-JOGREHBK-rVDG3VSQ.js → erDiagram-RLTQ6QDP-DhzKiYHc.js} +1037 -798
  92. package/dist/error-banner-B94dcDmP.js +391 -0
  93. package/dist/error-entries-iJn-Nryx.js +56 -0
  94. package/dist/{esm-CR1nhb1c.js → esm-BElI3qKH.js} +22 -22
  95. package/dist/{esm-C1d0g6Bv.js → esm-G4Fhsgng.js} +51 -37
  96. package/dist/{esm-CesmlDrs.js → esm-h8f7-1CJ.js} +423 -423
  97. package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +3 -0
  98. package/dist/feedback-button-D_YQdd5e.js +380 -0
  99. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +16 -0
  100. package/dist/{formats-CJMVUfb3.js → formats-BR5iGb4s.js} +8 -8
  101. package/dist/{ganttDiagram-PKOTCBZU-9D-LXF6P.js → ganttDiagram-EL5Y4UJY-DbzEBLbl.js} +15 -15
  102. package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +3 -0
  103. package/dist/{gitGraphDiagram-DS77QQ5N-BfpsXTLf.js → gitGraphDiagram-WWUBYQGX-BMf0iKi1.js} +10 -10
  104. package/dist/{glide-data-editor-sPZ8fUFn.js → glide-data-editor-CV4eSJ7N.js} +2143 -1910
  105. package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
  106. package/dist/globals-DdrpcXQY.js +19 -0
  107. package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
  108. package/dist/html-to-image-kpuRfdfZ.js +3253 -0
  109. package/dist/info-A6RAGUB7-DKoayiHY.js +3 -0
  110. package/dist/{infoDiagram-6WML65LV-DqCTXHVy.js → infoDiagram-27XIBGKW-BagtCX_5.js} +7 -7
  111. package/dist/{ishikawaDiagram-WSZJBQD7-BCUYmZ1v.js → ishikawaDiagram-5VMMS53U-DByDehYy.js} +8 -8
  112. package/dist/{journeyDiagram-NVQOT4AX-BXB6M4zN.js → journeyDiagram-3NMN7TZE-D2LcKDUO.js} +8 -8
  113. package/dist/{jsx-runtime-CpoKNRgu.js → jsx-runtime-DgDPJV9S.js} +1 -1
  114. package/dist/{kanban-definition-27J2QSJJ-CGRhrDUX.js → kanban-definition-UXKFOSKX-BxwkbBI_.js} +29 -29
  115. package/dist/katex-DFBiSucW.js +21840 -0
  116. package/dist/{label-lwzzBHUW.js → label-BJ49YTvk.js} +6 -6
  117. package/dist/{linear-D5r_1YqD.js → linear-Cnaq3Tfb.js} +4 -4
  118. package/dist/{loader-VZ__bv4g.js → loader-D2W4oM-3.js} +15 -15
  119. package/dist/main.js +8105 -13485
  120. package/dist/mermaid-DPNuhemn.js +3084 -0
  121. package/dist/mermaid-HWGCJPDP-DYCzSILp.js +2 -0
  122. package/dist/mermaid-parser.core-DxuSfYwJ.js +638 -0
  123. package/dist/{mhchem-BjwrxcV-.js → mhchem-DWCF06w9.js} +1 -1
  124. package/dist/{micromark-factory-space-DruVGzeG.js → micromark-factory-space-DGxAzmw8.js} +2 -2
  125. package/dist/{mindmap-definition-FAOFIHXS-C9gRhzZq.js → mindmap-definition-YA3MSWOX-Cgvojw3y.js} +17 -17
  126. package/dist/{node-sql-parser-DesT1xNw.js → node-sql-parser-BiZOJ-FS.js} +0 -3
  127. package/dist/{number-overlay-editor-De2CabLL.js → number-overlay-editor-DXWRr4gK.js} +5 -5
  128. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +23 -0
  129. package/dist/packet-AYTQ26CC-Yw7ajchJ.js +3 -0
  130. package/dist/{pegDiagram-VL7TDLO6-Df9IUjMD.js → pegDiagram-XKGWAZYB-DahHhYyN.js} +19 -20
  131. package/dist/{pick-SnHlmIBN.js → pick-CJeoxYOS.js} +1 -1
  132. package/dist/pie-WAS4IAKB-BKdKOAkL.js +3 -0
  133. package/dist/{pieDiagram-7S7Q4E2Y-BmRzQ8ZP.js → pieDiagram-E7YTZNPT-CCtX0oCK.js} +29 -31
  134. package/dist/{process-output-CpK6fX_C.js → process-output-DFe2tVIY.js} +7 -6
  135. package/dist/purify.es-DgKyQviY.js +805 -0
  136. package/dist/{quadrantDiagram-CIZ2JOQS-wFBvWcxS.js → quadrantDiagram-AXDQQJYC-DftINo6g.js} +5 -5
  137. package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +3 -0
  138. package/dist/railroad-74A4TZTK-DQvPSdo5.js +3 -0
  139. package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +3 -0
  140. package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +3 -0
  141. package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +3 -0
  142. package/dist/{railroadDiagram-AXF67PYL-DxbIatiN.js → railroadDiagram-O6MQD6OU-Du5NsPUb.js} +17 -18
  143. package/dist/{react-dom-C94wmq5w.js → react-dom-BUgJ-ab_.js} +3 -3
  144. package/dist/{react-DMWcHin-.js → react-ofJbxM4x.js} +2 -2
  145. package/dist/{react-vega-DSD5aT7_.js → react-vega-5AcMW8gG.js} +10012 -9369
  146. package/dist/{requirementDiagram-LRYGKXZP-X_x-Y713.js → requirementDiagram-BXWQKSXE-0pmmxL6_.js} +20 -19
  147. package/dist/{reveal-component-DwuC-61O.js → reveal-component-DLxDt6wQ.js} +1303 -1237
  148. package/dist/{sankeyDiagram-W5VNT64P-BYJALbbm.js → sankeyDiagram-P5KCCOFB-CDKR5TJH.js} +4 -4
  149. package/dist/{select-3qHpFKF9.js → select-C6plhmZr.js} +317 -562
  150. package/dist/{sequenceDiagram-SI44F4Z6-BiPBe3Sv.js → sequenceDiagram-WJ2MYXX4-DB-ChWwU.js} +11 -11
  151. package/dist/{sizeCapture-X5ZJPWSS-BKLDeh5H.js → sizeCapture-INFHLROL-Dx5SpkQF.js} +2 -2
  152. package/dist/{spec-CutWdqo3.js → spec-CAYwFeV6.js} +4 -4
  153. package/dist/{src-C31ngt98.js → src-CA_m4ONl.js} +298 -303
  154. package/dist/{stateDiagram-OKZ733FA-B7QyNBxH.js → stateDiagram-D77RDMKH-orN6AwMx.js} +19 -20
  155. package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +30 -0
  156. package/dist/style.css +2 -2
  157. package/dist/{swimlanes-SLNWSIFB-B4f8VP3b.js → swimlanes-42K2YHIH-BkSDcqDT.js} +1501 -1591
  158. package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +30 -0
  159. package/dist/{swiper-component-C90YjhaV.js → swiper-component-IOUowglM.js} +39 -26
  160. package/dist/{time-aWGfjN8x.js → time-BieKwdYS.js} +42 -42
  161. package/dist/{timeline-definition-Z64GVDOM-Dacq_5lr.js → timeline-definition-24CTP7MA-BuqJUIRZ.js} +7 -7
  162. package/dist/{toDate-D-Rx3ux5.js → toDate-WXg1yLcI.js} +10 -9
  163. package/dist/toast-DvY70eFX.js +1834 -0
  164. package/dist/tooltip-qB8NlSqV.js +1742 -0
  165. package/dist/treeView-Q6P3EWNA-DuRV97YF.js +3 -0
  166. package/dist/treemap-WGGIJYW6-AsLq-uwC.js +3 -0
  167. package/dist/use-restore-focus-D5D9xEjZ.js +5946 -0
  168. package/dist/{use-vega-container-remeasure-DUW4tRxq.js → use-vega-container-remeasure-4DwJbPWu.js} +2 -2
  169. package/dist/{useAsyncData-CH6-CgJF.js → useAsyncData-BD6AStMt.js} +3 -3
  170. package/dist/{useDateFormatter-Cp9Jdxls.js → useDateFormatter-BRTPsUK7.js} +8 -8
  171. package/dist/{useDeepCompareMemoize-JC87C_jO.js → useDeepCompareMemoize-D_HNdyvI.js} +2 -2
  172. package/dist/{useIframeCapabilities-De3C-9b4.js → useIframeCapabilities-CVtNkI3Y.js} +2 -2
  173. package/dist/{useLifecycle-B4RGlyf0.js → useLifecycle-DPgiiwwU.js} +6 -6
  174. package/dist/useNumberFormatter-BfDpa21j.js +251 -0
  175. package/dist/useTheme-DzXmYZ5V.js +904 -0
  176. package/dist/{vega-component-CPehZbUb.js → vega-component-D0QXopU8.js} +34 -34
  177. package/dist/{vega-embed-container-TJ5z5dZw.js → vega-embed-container-CbnTccZi.js} +6 -6
  178. package/dist/vega-loader.browser-D95WfUcj.js +1139 -0
  179. package/dist/{vennDiagram-T6HMQDX7-D-Rcq3Iu.js → vennDiagram-4TSXK5OY-CTUlJ2PK.js} +9 -9
  180. package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +3 -0
  181. package/dist/{wardleyDiagram-T6FBY63Y-Z-Og7_Wd.js → wardleyDiagram-VM6X3IG4-3evLUb0M.js} +10 -10
  182. package/dist/{xychartDiagram-ELKLHX3M-BDJ2dITA.js → xychartDiagram-S5SC5T6Z-DL2E3K8-.js} +248 -139
  183. package/package.json +54 -57
  184. package/src/__mocks__/requests.ts +7 -0
  185. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
  186. package/src/__tests__/fixtures/pair-preview.ts +19 -0
  187. package/src/__tests__/mount.test.ts +18 -0
  188. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +270 -0
  189. package/src/components/chat/acp/agent-panel.tsx +45 -44
  190. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
  191. package/src/components/data-table/column-summary/chart-spec-model.tsx +1 -1
  192. package/src/components/data-table/columns.tsx +64 -67
  193. package/src/components/editor/RecoveryButton.tsx +1 -0
  194. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
  195. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +115 -0
  196. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +218 -0
  197. package/src/components/editor/actions/pair-with-agent-commands.ts +46 -9
  198. package/src/components/editor/actions/pair-with-agent-modal.tsx +49 -23
  199. package/src/components/editor/ai/add-cell-with-ai.tsx +1 -0
  200. package/src/components/editor/ai/ai-completion-editor.tsx +3 -1
  201. package/src/components/editor/alerts/connecting-alert.tsx +1 -66
  202. package/src/components/editor/alerts/connection-notice.tsx +140 -0
  203. package/src/components/editor/app-container.tsx +9 -3
  204. package/src/components/editor/boundary/ErrorBoundary.tsx +38 -16
  205. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +311 -0
  206. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +50 -0
  207. package/src/components/editor/cell/code/cell-editor.tsx +41 -42
  208. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +94 -0
  209. package/src/components/editor/chrome/components/feedback-button.tsx +63 -42
  210. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +114 -7
  211. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +165 -0
  212. package/src/components/editor/chrome/panels/packages-panel.tsx +93 -166
  213. package/src/components/editor/chrome/panels/sandbox-controller.tsx +106 -0
  214. package/src/components/editor/chrome/panels/sandbox-panel.tsx +173 -0
  215. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -1
  216. package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
  217. package/src/components/editor/code/readonly-diff.tsx +1 -1
  218. package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +98 -98
  219. package/src/components/editor/connections/database/__tests__/as-code.test.ts +11 -5
  220. package/src/components/editor/dynamic-favicon.tsx +17 -10
  221. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  222. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  223. package/src/components/editor/header/__tests__/status.test.tsx +8 -20
  224. package/src/components/editor/header/filename-input.tsx +2 -0
  225. package/src/components/editor/header/status.tsx +5 -3
  226. package/src/components/editor/notebook-cell.tsx +4 -2
  227. package/src/components/editor/output/JsonOutput.tsx +182 -632
  228. package/src/components/editor/output/Outputs.css +50 -17
  229. package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
  230. package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
  231. package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
  232. package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
  233. package/src/components/editor/output/json-output/formatting.ts +167 -0
  234. package/src/components/editor/output/json-output/pagination.ts +155 -0
  235. package/src/components/editor/output/json-output/renderers.tsx +196 -0
  236. package/src/components/editor/output/json-output/themes.ts +52 -0
  237. package/src/components/editor/renderers/cell-array.tsx +1 -5
  238. package/src/components/home/components.tsx +17 -0
  239. package/src/components/pages/gallery-page.tsx +2 -4
  240. package/src/components/pages/home-page.tsx +2 -4
  241. package/src/components/slides/slide-form.tsx +1 -0
  242. package/src/components/slides/slide-notes-editor.tsx +1 -0
  243. package/src/components/terminal/terminal.tsx +4 -4
  244. package/src/components/tracing/tracing-spec.ts +1 -1
  245. package/src/components/ui/table.tsx +1 -1
  246. package/src/components/ui/use-toast.ts +8 -0
  247. package/src/core/MarimoApp.tsx +0 -2
  248. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +259 -259
  249. package/src/core/cells/__tests__/cell.test.ts +61 -0
  250. package/src/core/cells/__tests__/cells.test.ts +37 -37
  251. package/src/core/cells/cell.ts +9 -1
  252. package/src/core/cells/pending-delete-service.ts +12 -16
  253. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  254. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  255. package/src/core/codemirror/rtc/extension.ts +5 -2
  256. package/src/core/config/pair.ts +19 -0
  257. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  258. package/src/core/datasets/data-source-connections.ts +15 -10
  259. package/src/core/edit-app.tsx +8 -5
  260. package/src/core/errors/state.ts +1 -2
  261. package/src/core/islands/__tests__/parse.test.ts +140 -7
  262. package/src/core/islands/bootstrap.ts +1 -0
  263. package/src/core/islands/bridge.ts +3 -0
  264. package/src/core/islands/parse.ts +20 -0
  265. package/src/core/network/connection-notice.ts +84 -0
  266. package/src/core/network/requests-lazy.ts +3 -0
  267. package/src/core/network/requests-network.ts +12 -0
  268. package/src/core/network/requests-static.ts +3 -0
  269. package/src/core/network/requests-toasting.tsx +3 -0
  270. package/src/core/network/resolve.ts +2 -1
  271. package/src/core/network/types.ts +7 -0
  272. package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
  273. package/src/core/packages/__tests__/useSandboxController.test.tsx +165 -0
  274. package/src/core/packages/package-data.ts +35 -0
  275. package/src/core/packages/sandbox-state.ts +15 -0
  276. package/src/core/packages/toast-components.tsx +11 -0
  277. package/src/core/packages/useInstallPackage.ts +1 -1
  278. package/src/core/packages/usePackageAction.ts +51 -0
  279. package/src/core/packages/usePackageDependencies.ts +22 -0
  280. package/src/core/packages/useSandboxController.ts +188 -0
  281. package/src/core/run-app.tsx +2 -0
  282. package/src/core/runtime/__tests__/runtime.test.ts +11 -0
  283. package/src/core/runtime/runtime.ts +7 -2
  284. package/src/core/wasm/bridge.ts +11 -0
  285. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +212 -2
  286. package/src/core/websocket/transports/transport.ts +1 -1
  287. package/src/core/websocket/transports/ws.ts +1 -1
  288. package/src/core/websocket/types.ts +11 -1
  289. package/src/core/websocket/useMarimoKernelConnection.tsx +43 -8
  290. package/src/css/app/Cell.css +2 -0
  291. package/src/hooks/useDebounce.ts +2 -0
  292. package/src/mount.tsx +3 -0
  293. package/src/plugins/core/BadPlugin.tsx +3 -14
  294. package/src/plugins/core/RenderHTML.tsx +22 -2
  295. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  296. package/src/plugins/core/registerReactComponent.tsx +0 -1
  297. package/src/plugins/impl/FormPlugin.tsx +2 -0
  298. package/src/plugins/impl/MatrixPlugin.tsx +2 -0
  299. package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
  300. package/src/plugins/impl/SliderPlugin.tsx +2 -0
  301. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
  302. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  303. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +1 -1
  304. package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +15 -0
  305. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  306. package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
  307. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  308. package/src/stories/sandbox.stories.tsx +308 -0
  309. package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
  310. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  311. package/dist/_initCloneObject---vediN2.js +0 -95
  312. package/dist/arc-DOVLrCPd.js +0 -82
  313. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  314. package/dist/array-CApNbSU9.js +0 -6
  315. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  316. package/dist/assets/worker-DlIBfp9S.js +0 -98
  317. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  318. package/dist/chat-ui-DjTMZRVP.js +0 -8455
  319. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  320. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  321. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  322. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  323. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  324. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  325. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  326. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  327. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  328. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  329. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  330. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  331. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  332. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  333. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  334. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  335. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  336. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  337. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  338. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  339. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  340. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  341. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  342. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  343. package/dist/click-outside-container-D_URcm3D.js +0 -167
  344. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  345. package/dist/copy-CD7S58CY.js +0 -141
  346. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  347. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  348. package/dist/dist-3_o3T78I.js +0 -1360
  349. package/dist/dist-ABQjhuek.js +0 -64
  350. package/dist/dist-CO5R6VMi.js +0 -538
  351. package/dist/dropdown-menu-DhCfcscX.js +0 -5858
  352. package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
  353. package/dist/error-banner-CsXbEEjo.js +0 -611
  354. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  355. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  356. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  357. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  358. package/dist/line-CuKjIQa1.js +0 -34
  359. package/dist/map-BJpOfPlL.js +0 -149
  360. package/dist/math-BXtKgYah.js +0 -10
  361. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  362. package/dist/mermaid-Bi23Ibnw.js +0 -1173
  363. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  364. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  365. package/dist/path-BNHuHZP8.js +0 -87
  366. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  367. package/dist/purify.es-CB-YO1Hn.js +0 -774
  368. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  369. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  370. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  371. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  372. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  373. package/dist/schemas-DzK6U94N.js +0 -6057
  374. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  375. package/dist/step-CKczO72Q.js +0 -670
  376. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  377. package/dist/timer-DpDyj9G0.js +0 -596
  378. package/dist/tooltip-Dt77sBeT.js +0 -390
  379. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  380. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  381. package/dist/useTheme-CVJ0UOf2.js +0 -841
  382. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  383. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
  384. package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
@@ -902,6 +902,18 @@ const AgentPanel: React.FC = () => {
902
902
  return;
903
903
  }
904
904
 
905
+ let absoluteFilename: string;
906
+ try {
907
+ absoluteFilename = getAbsoluteFilename();
908
+ } catch {
909
+ toast({
910
+ title: "Notebook must be named",
911
+ description: "Please name the notebook to use the agent",
912
+ variant: "danger",
913
+ });
914
+ return;
915
+ }
916
+
905
917
  logger.debug("Submitting prompt to agent", {
906
918
  sessionId: activeSessionId,
907
919
  });
@@ -914,62 +926,51 @@ const AgentPanel: React.FC = () => {
914
926
  setSessionState((prev) => updateSessionTitle(prev, prompt));
915
927
  }
916
928
 
917
- let absoluteFilename: string;
918
929
  try {
919
- absoluteFilename = getAbsoluteFilename();
920
- } catch {
921
- toast({
922
- title: "Notebook must be named",
923
- description: "Please name the notebook to use the agent",
924
- variant: "danger",
925
- });
926
- return;
927
- }
928
-
929
- const promptBlocks: ContentBlock[] = [{ type: "text", text: prompt }];
930
+ const promptBlocks: ContentBlock[] = [{ type: "text", text: prompt }];
930
931
 
931
- // Parse context from the prompt
932
- const { contextBlocks, attachmentBlocks } =
933
- await parseContextFromPrompt(prompt);
934
- promptBlocks.push(...contextBlocks, ...attachmentBlocks);
932
+ // Parse context from the prompt
933
+ const { contextBlocks, attachmentBlocks } =
934
+ await parseContextFromPrompt(prompt);
935
+ promptBlocks.push(...contextBlocks, ...attachmentBlocks);
935
936
 
936
- // Add manually uploaded files as resource links
937
- if (files && files.length > 0) {
938
- const fileResourceLinks = await convertFilesToResourceLinks(files);
939
- promptBlocks.push(...fileResourceLinks);
940
- }
937
+ // Add manually uploaded files as resource links
938
+ if (files && files.length > 0) {
939
+ const fileResourceLinks = await convertFilesToResourceLinks(files);
940
+ promptBlocks.push(...fileResourceLinks);
941
+ }
941
942
 
942
- const hasGivenRules = notifications.some(
943
- (notification) =>
944
- notification.type === "session_notification" &&
945
- notification.data.update.sessionUpdate === "user_message_chunk",
946
- );
947
- if (!hasGivenRules) {
948
- promptBlocks.push(
949
- {
950
- type: "resource_link",
951
- uri: absoluteFilename,
952
- mimeType: "text/x-python",
953
- name: absoluteFilename,
954
- },
955
- {
956
- type: "resource",
957
- resource: {
958
- uri: "marimo_rules.md",
959
- mimeType: "text/plain",
960
- text: getAgentPrompt(absoluteFilename),
961
- },
962
- },
943
+ const hasGivenRules = notifications.some(
944
+ (notification) =>
945
+ notification.type === "session_notification" &&
946
+ notification.data.update.sessionUpdate === "user_message_chunk",
963
947
  );
964
- }
948
+ if (!hasGivenRules) {
949
+ promptBlocks.push(
950
+ {
951
+ type: "resource_link",
952
+ uri: absoluteFilename,
953
+ mimeType: "text/x-python",
954
+ name: absoluteFilename,
955
+ },
956
+ {
957
+ type: "resource",
958
+ resource: {
959
+ uri: "marimo_rules.md",
960
+ mimeType: "text/plain",
961
+ text: getAgentPrompt(absoluteFilename),
962
+ },
963
+ },
964
+ );
965
+ }
965
966
 
966
- try {
967
967
  await agent.prompt({
968
968
  sessionId: activeSessionId,
969
969
  prompt: promptBlocks,
970
970
  });
971
971
  } catch (error) {
972
972
  logger.error("Failed to send prompt", { error });
973
+ setError(error instanceof Error ? error : String(error));
973
974
  } finally {
974
975
  setIsLoading(false);
975
976
  }
@@ -10,7 +10,7 @@ import {
10
10
  EyeIcon,
11
11
  EyeOffIcon,
12
12
  } from "lucide-react";
13
- import { useMemo, useState } from "react";
13
+ import { useState } from "react";
14
14
  import { useLocale } from "react-aria";
15
15
  import {
16
16
  AddDataframeChart,
@@ -98,11 +98,7 @@ export function ColumnExplorerPanel<TData>({
98
98
  hiddenColumns: hiddenColumnCount,
99
99
  } = getColumnCountForDisplay(table, totalColumns);
100
100
  const { visible: visibleColumnCount } = getUserColumnVisibilityCounts(table);
101
- const columnVisibility = table.getState().columnVisibility;
102
- const showOnlyColumnState = useMemo(
103
- () => getShowOnlyColumnState(table),
104
- [table, columnVisibility],
105
- );
101
+ const showOnlyColumnState = getShowOnlyColumnState(table);
106
102
 
107
103
  const { rowsAndColumns, hiddenSuffix } = prettifyRowColumnCount({
108
104
  numRows: totalRows,
@@ -573,7 +573,7 @@ export class ColumnChartSpecModel<T> {
573
573
  };
574
574
  }
575
575
  case "boolean": {
576
- if (!stats?.true || !stats?.false) {
576
+ if (stats?.true == null || stats?.false == null) {
577
577
  return getLegacyBooleanSpec(column, base, MAX_BAR_HEIGHT);
578
578
  }
579
579
 
@@ -20,7 +20,6 @@ import { Maps } from "@/utils/maps";
20
20
  import { maxFractionalDigits } from "@/utils/numbers";
21
21
  import { Objects } from "@/utils/objects";
22
22
  import { parseContent } from "@/utils/url-parser";
23
- import { EmotionCacheProvider } from "../editor/output/EmotionCacheProvider";
24
23
  import { JsonOutput } from "../editor/output/JsonOutput";
25
24
  import { CopyClipboardIcon } from "../icons/copy-icon";
26
25
  import { Button } from "../ui/button";
@@ -412,76 +411,74 @@ const PopoutColumn = ({
412
411
  : rawStringValue;
413
412
 
414
413
  return (
415
- <EmotionCacheProvider container={null}>
416
- <Popover>
417
- <PopoverTrigger
418
- ref={triggerRef}
419
- className={cn(cellStyles, "max-w-fit outline-hidden")}
420
- onClick={selectCell}
421
- onMouseDown={(e) => {
422
- // Prevent cell underneath from being selected
423
- e.stopPropagation();
424
- }}
425
- >
426
- <span
427
- className={cn(
428
- "cursor-pointer hover:text-link",
429
- wrapped && COLUMN_WRAPPING_STYLES,
430
- )}
431
- title={rawStringValue}
432
- >
433
- {edges ? <WhitespaceMarkers value={edges.leading} /> : null}
434
- {displayText}
435
- {edges ? <WhitespaceMarkers value={edges.trailing} /> : null}
436
- </span>
437
- </PopoverTrigger>
438
- <PopoverContent
414
+ <Popover>
415
+ <PopoverTrigger
416
+ ref={triggerRef}
417
+ className={cn(cellStyles, "max-w-fit outline-hidden")}
418
+ onClick={selectCell}
419
+ onMouseDown={(e) => {
420
+ // Prevent cell underneath from being selected
421
+ e.stopPropagation();
422
+ }}
423
+ >
424
+ <span
439
425
  className={cn(
440
- contentClassName,
441
- scrollable && "flex flex-col overflow-hidden",
426
+ "cursor-pointer hover:text-link",
427
+ wrapped && COLUMN_WRAPPING_STYLES,
442
428
  )}
443
- align="start"
444
- alignOffset={10}
445
- onInteractOutside={(event) => {
446
- // Radix sees the shadow host as the target. Resolve the original
447
- // target so pointer-down does not dismiss before click toggles.
448
- const target = Events.composedTarget(event.detail.originalEvent);
449
- if (triggerRef.current?.contains(target)) {
450
- event.preventDefault();
451
- }
452
- }}
429
+ title={rawStringValue}
453
430
  >
454
- <div
455
- className={cn(
456
- "flex -mt-3 -mr-2",
457
- scrollable ? "shrink-0 justify-end" : "float-right",
458
- )}
459
- >
460
- <CopyClipboardIcon
461
- value={rawStringValue}
462
- className="size-3 hover:text-link"
463
- buttonClassName="flex size-5 items-center justify-center"
464
- tooltip={false}
465
- />
466
- <PopoverClose asChild={true}>
467
- <Button
468
- variant="link"
469
- size="xs"
470
- className={cn("size-5 p-0", !buttonText && "ml-1.5 mr-1")}
471
- aria-label="Close"
472
- >
473
- {buttonText ?? "Close"}
474
- </Button>
475
- </PopoverClose>
476
- </div>
477
- {scrollable ? (
478
- <div className="min-h-0 overflow-auto">{children}</div>
479
- ) : (
480
- children
431
+ {edges ? <WhitespaceMarkers value={edges.leading} /> : null}
432
+ {displayText}
433
+ {edges ? <WhitespaceMarkers value={edges.trailing} /> : null}
434
+ </span>
435
+ </PopoverTrigger>
436
+ <PopoverContent
437
+ className={cn(
438
+ contentClassName,
439
+ scrollable && "flex flex-col overflow-hidden",
440
+ )}
441
+ align="start"
442
+ alignOffset={10}
443
+ onInteractOutside={(event) => {
444
+ // Radix sees the shadow host as the target. Resolve the original
445
+ // target so pointer-down does not dismiss before click toggles.
446
+ const target = Events.composedTarget(event.detail.originalEvent);
447
+ if (triggerRef.current?.contains(target)) {
448
+ event.preventDefault();
449
+ }
450
+ }}
451
+ >
452
+ <div
453
+ className={cn(
454
+ "flex -mt-3 -mr-2",
455
+ scrollable ? "shrink-0 justify-end" : "float-right",
481
456
  )}
482
- </PopoverContent>
483
- </Popover>
484
- </EmotionCacheProvider>
457
+ >
458
+ <CopyClipboardIcon
459
+ value={rawStringValue}
460
+ className="size-3 hover:text-link"
461
+ buttonClassName="flex size-5 items-center justify-center"
462
+ tooltip={false}
463
+ />
464
+ <PopoverClose asChild={true}>
465
+ <Button
466
+ variant="link"
467
+ size="xs"
468
+ className={cn("size-5 p-0", !buttonText && "ml-1.5 mr-1")}
469
+ aria-label="Close"
470
+ >
471
+ {buttonText ?? "Close"}
472
+ </Button>
473
+ </PopoverClose>
474
+ </div>
475
+ {scrollable ? (
476
+ <div className="min-h-0 overflow-auto">{children}</div>
477
+ ) : (
478
+ children
479
+ )}
480
+ </PopoverContent>
481
+ </Popover>
485
482
  );
486
483
  };
487
484
 
@@ -60,6 +60,7 @@ const RecoveryModal = (props: {
60
60
  // NB: we use markdown class to have sane styling for list, paragraph
61
61
  return (
62
62
  <DialogContent className="w-fit">
63
+ {/* oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- Handle Escape from any control within the recovery form. */}
63
64
  <form
64
65
  onSubmit={(e) => {
65
66
  e.preventDefault();
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { render } from "@testing-library/react";
3
+ import { render, waitFor } from "@testing-library/react";
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { useCellErrors } from "@/core/cells/cells";
6
6
  import { DynamicFavicon } from "../dynamic-favicon";
@@ -14,6 +14,10 @@ describe("DynamicFavicon", () => {
14
14
  let favicon: HTMLLinkElement;
15
15
 
16
16
  beforeEach(() => {
17
+ document
18
+ .querySelectorAll("link[rel~='icon']")
19
+ .forEach((element) => element.remove());
20
+
17
21
  // Mock favicon element
18
22
  favicon = document.createElement("link");
19
23
  favicon.rel = "icon";
@@ -28,7 +32,9 @@ describe("DynamicFavicon", () => {
28
32
  });
29
33
 
30
34
  afterEach(() => {
31
- favicon.remove();
35
+ document
36
+ .querySelectorAll("link[rel~='icon']")
37
+ .forEach((element) => element.remove());
32
38
  vi.clearAllMocks();
33
39
  vi.useRealTimers();
34
40
  });
@@ -113,6 +119,34 @@ describe("DynamicFavicon", () => {
113
119
  expect(newFavicon).not.toBeNull();
114
120
  });
115
121
 
122
+ it("recreates a removed favicon when the window regains focus", async () => {
123
+ render(<DynamicFavicon isRunning={false} />);
124
+ favicon.remove();
125
+
126
+ window.dispatchEvent(new Event("focus"));
127
+
128
+ await waitFor(() => {
129
+ const currentFavicon =
130
+ document.querySelector<HTMLLinkElement>("link[rel~='icon']");
131
+ expect(currentFavicon?.href.endsWith("favicon.ico")).toBe(true);
132
+ });
133
+ });
134
+
135
+ it("resets the current favicon after the link is replaced", async () => {
136
+ render(<DynamicFavicon isRunning={false} />);
137
+ const replacement = document.createElement("link");
138
+ replacement.rel = "icon";
139
+ replacement.href = "./replacement.ico";
140
+ favicon.replaceWith(replacement);
141
+
142
+ window.dispatchEvent(new Event("focus"));
143
+
144
+ await waitFor(() => {
145
+ expect(replacement.href.endsWith("favicon.ico")).toBe(true);
146
+ expect(document.querySelector("link[rel~='icon']")).toBe(replacement);
147
+ });
148
+ });
149
+
116
150
  describe("notifications", () => {
117
151
  beforeEach(() => {
118
152
  vi.spyOn(document, "visibilityState", "get").mockReturnValue("hidden");
@@ -10,10 +10,12 @@ import {
10
10
  maskToken,
11
11
  } from "../pair-with-agent-commands";
12
12
  import { shellQuote } from "@/utils/shell";
13
+ import { PAIR_PREVIEW } from "@/__tests__/fixtures/pair-preview";
13
14
 
14
15
  const CONNECTION: ConnectionInfo = {
15
16
  url: "http://localhost:8000",
16
17
  file: "notebooks/example.py",
18
+ session: "s_ab12cd",
17
19
  };
18
20
 
19
21
  const CONNECTION_WITHOUT_FILE: ConnectionInfo = {
@@ -104,6 +106,61 @@ describe("getMarimoCommand", () => {
104
106
  });
105
107
 
106
108
  describe("getTerminalCommand", () => {
109
+ it("uses the preview launcher in production and quotes session-only targets", () => {
110
+ vi.stubEnv("DEV", false);
111
+ try {
112
+ expect(
113
+ getTerminalCommand(
114
+ "claude",
115
+ { url: "http://host:8000?a=1&b=2", session: "s_' {file}" },
116
+ false,
117
+ { ...PAIR_PREVIEW, command: "uvx marimo@latest" },
118
+ ),
119
+ ).toBe(
120
+ String.raw`claude "$(MARIMO_PAIR_NEXT=1 uvx marimo@latest pair prompt \
121
+ --url 'http://host:8000?a=1&b=2' \
122
+ --session 's_'"'"' {file}')"`,
123
+ );
124
+ expect(
125
+ getTerminalCommand(
126
+ "codex",
127
+ CONNECTION_WITHOUT_FILE,
128
+ false,
129
+ PAIR_PREVIEW,
130
+ ),
131
+ ).toBe(
132
+ String.raw`codex "$(MARIMO_PAIR_NEXT=1 uv run marimo pair prompt \
133
+ --url http://localhost:8000)"`,
134
+ );
135
+ } finally {
136
+ vi.unstubAllEnvs();
137
+ }
138
+ });
139
+
140
+ it.each([
141
+ ["claude", "claude"],
142
+ ["codex", "codex"],
143
+ ["opencode", "opencode --prompt"],
144
+ ] as const)(
145
+ "enables the preview inside the %s prompt command",
146
+ (agent, cli) => {
147
+ expect(
148
+ getTerminalCommand(
149
+ agent,
150
+ { ...CONNECTION, session: "s_ab12cd" },
151
+ true,
152
+ PAIR_PREVIEW,
153
+ ),
154
+ ).toBe(
155
+ String.raw`${cli} "$(MARIMO_PAIR_NEXT=1 uv run marimo pair prompt \
156
+ --url http://localhost:8000 \
157
+ --file notebooks/example.py \
158
+ --session s_ab12cd \
159
+ --with-token)"`,
160
+ );
161
+ },
162
+ );
163
+
107
164
  it("includes the url and file for each agent", () => {
108
165
  expect(getTerminalCommand("claude", CONNECTION, false)).toBe(
109
166
  `claude "$(uv run marimo pair prompt --url http://localhost:8000 --file notebooks/example.py --claude)"`,
@@ -169,6 +226,64 @@ describe("getTerminalCommand", () => {
169
226
  });
170
227
 
171
228
  describe("getRawPrompt", () => {
229
+ it("uses supplied templates without reinterpreting inserted values", () => {
230
+ expect(
231
+ getRawPrompt(
232
+ {
233
+ url: "http://host/{file}",
234
+ file: "{session}/it's.py",
235
+ session: "{command}",
236
+ },
237
+ "tok'en {file} $&",
238
+ {
239
+ ...PAIR_PREVIEW,
240
+ command: "custom marimo",
241
+ templates: {
242
+ ...PAIR_PREVIEW.templates,
243
+ prompt: "{command}\n{url}\n{file}{session}{authentication}",
244
+ },
245
+ },
246
+ ),
247
+ ).toBe(
248
+ "custom marimo\nhttp://host/{file}\nFile: {session}/it's.py\nSession: {command}\n" +
249
+ `\n\nFor authenticated Pair commands, set \`export MARIMO_TOKEN='tok'"'"'en {file} $&'\` in the shell that runs marimo.`,
250
+ );
251
+ });
252
+
253
+ it.each([
254
+ [CONNECTION_WITHOUT_FILE, ""],
255
+ [
256
+ { ...CONNECTION_WITHOUT_FILE, session: "s_ab12cd" },
257
+ "Session: s_ab12cd\n",
258
+ ],
259
+ [
260
+ { ...CONNECTION_WITHOUT_FILE, file: "notebook.py" },
261
+ "File: notebook.py\n",
262
+ ],
263
+ ])("omits absent preview fields for %j", (connection, fields) => {
264
+ expect(getRawPrompt(connection, null, PAIR_PREVIEW)).toBe(
265
+ "Pair with me on this running marimo notebook.\n\n" +
266
+ `URL: http://localhost:8000\n${fields}\n` +
267
+ "Run `uv run marimo pair --help` first.\n" +
268
+ "Use `uv run marimo` for all marimo commands.\n\n" +
269
+ "Once connected, send a fun toast using `mo.status.toast(...)` (`import marimo as mo`).",
270
+ );
271
+ });
272
+
273
+ it("renders the shared preview template with optional session context", () => {
274
+ expect(
275
+ getRawPrompt({ ...CONNECTION, session: "s_ab12cd" }, null, PAIR_PREVIEW),
276
+ ).toBe(
277
+ "Pair with me on this running marimo notebook.\n\n" +
278
+ "URL: http://localhost:8000\n" +
279
+ "File: notebooks/example.py\n" +
280
+ "Session: s_ab12cd\n\n" +
281
+ "Run `uv run marimo pair --help` first.\n" +
282
+ "Use `uv run marimo` for all marimo commands.\n\n" +
283
+ "Once connected, send a fun toast using `mo.status.toast(...)` (`import marimo as mo`).",
284
+ );
285
+ });
286
+
172
287
  it("references the file-scoped execute-code command", () => {
173
288
  const prompt = getRawPrompt(CONNECTION, null);
174
289
  expect(prompt).toContain(