@marimo-team/islands 0.22.1-dev3 → 0.22.1-dev31
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.
- package/dist/{ConnectedDataExplorerComponent-Dl1grr8z.js → ConnectedDataExplorerComponent-DTOsfq2x.js} +54 -54
- package/dist/_basePickBy-Sow3pJjS.js +41 -0
- package/dist/{_baseUniq-B4eL5sTC.js → _baseUniq-C87CckHL.js} +15 -54
- package/dist/{any-language-editor-CT_9yBde.js → any-language-editor-BHH_pQ6M.js} +21 -21
- package/dist/architecture-7HQA4BMR-BHdkAMvZ.js +6 -0
- package/dist/{architectureDiagram-VXUJARFQ-vxgYGIMP.js → architectureDiagram-VXUJARFQ-B3YQo9At.js} +15 -15
- package/dist/{arrays-Du-jRBAy.js → arrays-beUWo8RF.js} +1 -1
- package/dist/assets/__vite-browser-external-WSlCcXn_.js +1 -0
- package/dist/assets/{worker-D10K3OOz.js → worker-DUYMdbtA.js} +2 -2
- package/dist/{blockDiagram-VD42YOAC-C7x6YTH7.js → blockDiagram-VD42YOAC-CpQ3TKEN.js} +7 -7
- package/dist/{button-qsiIHncQ.js → button-DNlNlZY_.js} +82 -84
- package/dist/{c4Diagram-YG6GDRKO-Cx4oseGg.js → c4Diagram-YG6GDRKO-CZSU4uqU.js} +4 -4
- package/dist/{capabilities-26mwv03y.js → capabilities-Coe9eM9T.js} +2 -2
- package/dist/{channel-C_50jIAn.js → channel-X3JKk8gE.js} +1 -1
- package/dist/{chat-ui-CtqUthFR.js → chat-ui-eH46RYWT.js} +147 -146
- package/dist/{check-D_YwHEgY.js → check-CWUkiHmb.js} +1 -1
- package/dist/{chunk-4F5CHEZ2-Dvo_CFnR.js → chunk-4F5CHEZ2-D5mClyDv.js} +1 -1
- package/dist/{chunk-ABZYJK2D-D5YIs71w.js → chunk-ABZYJK2D-CZYCCtLy.js} +1 -1
- package/dist/{chunk-ATLVNIR6-CyOjzOcf.js → chunk-ATLVNIR6-DaOzLLgN.js} +1 -1
- package/dist/{chunk-B2363JML-BzZqINRO.js → chunk-B2363JML-Br0eA2T3.js} +1 -1
- package/dist/{chunk-B4BG7PRW-ZJeV3KdD.js → chunk-B4BG7PRW-4BjV11Br.js} +4 -4
- package/dist/{chunk-DI55MBZ5-Dx_wwX6l.js → chunk-DI55MBZ5-DITY3EyP.js} +4 -4
- package/dist/{chunk-EXTU4WIE-CgefpSXQ.js → chunk-EXTU4WIE-jUPSAk3i.js} +1 -1
- package/dist/{chunk-FRFDVMJY-Derq8UzY.js → chunk-FRFDVMJY-DnEvEFRR.js} +1 -1
- package/dist/{chunk-JA3XYJ7Z-CcIOIFpc.js → chunk-JA3XYJ7Z-BcPEfxk_.js} +2 -2
- package/dist/{chunk-JZLCHNYA-CgO0GG1p.js → chunk-JZLCHNYA-2bnLL3xL.js} +4 -4
- package/dist/{chunk-N4CR4FBY-2qzGzAxT.js → chunk-N4CR4FBY-CpZSuGSU.js} +5 -5
- package/dist/{chunk-PL6DKKU2-KoG71Zin.js → chunk-PL6DKKU2-DnId6G-x.js} +1 -1
- package/dist/{chunk-QN33PNHL-Dp1qBo28.js → chunk-QN33PNHL-B9p5ojHB.js} +1 -1
- package/dist/{chunk-QXUST7PY-BxmmeIwf.js → chunk-QXUST7PY-Ch6F5Obl.js} +5 -5
- package/dist/{chunk-S3R3BYOJ-D3Rys9ZW.js → chunk-S3R3BYOJ-B0UOFJwq.js} +3 -3
- package/dist/{chunk-SJTYNZTY-Co-DhKAG.js → chunk-SJTYNZTY-BsBZnJUj.js} +1 -1
- package/dist/{chunk-TCCFYFTB-BAhzIqBO.js → chunk-TCCFYFTB-Clbl-fTg.js} +8 -7
- package/dist/{chunk-TQ3KTPDO-DxYI735Z.js → chunk-TQ3KTPDO-CFkSQ30e.js} +1 -1
- package/dist/{chunk-TZMSLE5B-Dxumt0wv.js → chunk-TZMSLE5B-D45397J2.js} +1 -1
- package/dist/{chunk-UMXZTB3W-CuahpKin.js → chunk-UMXZTB3W-D-A834Bq.js} +1 -1
- package/dist/{classDiagram-v2-WZHVMYZB-CYoFMQKE.js → classDiagram-2ON5EDUG-C8-zE3Zv.js} +10 -10
- package/dist/{classDiagram-2ON5EDUG-DkOvXRlx.js → classDiagram-v2-WZHVMYZB-DrmbGANl.js} +10 -10
- package/dist/{clone-DDndUqI0.js → clone-DZFQCtFJ.js} +1 -1
- package/dist/{constants-D1Am36hX.js → constants-CvyfaCvs.js} +3 -3
- package/dist/{copy-CBo9JcJW.js → copy-B7781WJ3.js} +2 -2
- package/dist/{dagre-6UL2VRFP-BXBaU8PB.js → dagre-6UL2VRFP-OMItEBnY.js} +12 -12
- package/dist/{dagre-D3dlYz-r.js → dagre-QVd-lCXU.js} +13 -23
- package/dist/{data-grid-overlay-editor-nZux6_d2.js → data-grid-overlay-editor-lKF301ME.js} +1 -1
- package/dist/{diagram-PSM6KHXK-CJxjk4LG.js → diagram-PSM6KHXK-CkKbohWI.js} +16 -16
- package/dist/{diagram-QEK2KX5R-IMILPh_p.js → diagram-QEK2KX5R-DjUMpVcx.js} +14 -14
- package/dist/{diagram-S2PKOQOG-6O0g6Boj.js → diagram-S2PKOQOG-b-c0d-wZ.js} +14 -14
- package/dist/{dist-BkXs8bw0.js → dist--6TSlp8H.js} +1 -1
- package/dist/dist-7K5doRvB.js +6 -0
- package/dist/{dist-CQidOwep.js → dist-B43sbpd0.js} +3 -3
- package/dist/dist-B6I_A2-E.js +8 -0
- package/dist/dist-BEQsmaZY.js +5 -0
- package/dist/dist-BasY2RHp.js +8 -0
- package/dist/{dist-BemtTYzN.js → dist-Bfp1XXWt.js} +5 -5
- package/dist/{dist-v-1kgqZ3.js → dist-BjDuO5JW.js} +1 -1
- package/dist/dist-Bosc00dY.js +5 -0
- package/dist/{dist-DLNKBPsk.js → dist-BrxqmS9Q.js} +4 -4
- package/dist/{dist-DBYL08Lu.js → dist-BvhGByxL.js} +4 -4
- package/dist/{dist-CVqlhD3M.js → dist-C4bq5Ioy.js} +2 -2
- package/dist/{dist-DwmxBUOe.js → dist-CFKdzOIu.js} +2 -2
- package/dist/{dist-5nTQE2yt.js → dist-CIB8w0Fl.js} +2 -2
- package/dist/{dist-C-EcLtO9.js → dist-CNF0QBLR.js} +1 -1
- package/dist/dist-CQMZOn-_.js +8 -0
- package/dist/dist-CViQhWZ8.js +5 -0
- package/dist/{dist-Dg65j0em.js → dist-CcMfr7jD.js} +1 -1
- package/dist/{dist-C0XYIHKJ.js → dist-Ci0CXEFt.js} +1 -1
- package/dist/dist-Cz6rLfwY.js +5 -0
- package/dist/dist-D8eq8st3.js +6 -0
- package/dist/{dist-qoCY8giM.js → dist-DAfcmt-d.js} +2 -2
- package/dist/{dist-B6Op2ogv.js → dist-DD_cYHOl.js} +2 -2
- package/dist/{dist-BUSLKXcu.js → dist-DFK94vuS.js} +2 -2
- package/dist/{dist-DBXPlQ0D.js → dist-DGNtjMZu.js} +1 -1
- package/dist/{dist-C9qF7MRB.js → dist-DJ9F1eHs.js} +2 -2
- package/dist/{dist-Ci_jEudG.js → dist-DJKubHDd.js} +1 -1
- package/dist/{dist-CnFp2Kcl.js → dist-DLafRu9s.js} +2 -2
- package/dist/dist-DM1UDXdl.js +5 -0
- package/dist/dist-DNrtWPgS.js +5 -0
- package/dist/dist-D_UjpfOY.js +1381 -0
- package/dist/{dist-DmFS6KZW.js → dist-DbnBiLNH.js} +3 -3
- package/dist/{dist-BiZZAo22.js → dist-DlSUOIm9.js} +1 -1
- package/dist/{dist-DStU8He1.js → dist-Doy0mQDg.js} +2 -2
- package/dist/{dist-CxAX99oC.js → dist-DpkJHKB8.js} +2 -2
- package/dist/{dist-DjaZNkZ7.js → dist-LhQNUe5A.js} +3 -3
- package/dist/dist-V7q2qnpA.js +5 -0
- package/dist/{dist-BJ3fhRYu.js → dist-VqF3W_ue.js} +2 -2
- package/dist/dist-a5_hPgu2.js +8 -0
- package/dist/{dist-B9KLrfoh.js → dist-ej6AQKaS.js} +1 -1
- package/dist/{dist-Brb6VNc4.js → dist-m9tsXsFf.js} +2 -2
- package/dist/{dist-CBwMSFDu.js → dist-tGk0aZ--.js} +2 -2
- package/dist/dist-uVyZcV1-.js +5 -0
- package/dist/{erDiagram-Q2GNP2WA-sho7Cl9f.js → erDiagram-Q2GNP2WA-CDhLaOZ1.js} +10 -10
- package/dist/{error-banner-Bx9kIgrs.js → error-banner-Cjf0RU9I.js} +79 -79
- package/dist/{esm-CMg2ABu6.js → esm-4wmsH2lp.js} +6 -6
- package/dist/{esm-cqK9POGH.js → esm-CD1iby2n.js} +23 -23
- package/dist/{flowDiagram-NV44I4VS-C4nY4Fbz.js → flowDiagram-NV44I4VS-BDi4O4CL.js} +10 -10
- package/dist/{ganttDiagram-JELNMOA3-CtxNcCM2.js → ganttDiagram-JELNMOA3-BpZE6kVp.js} +3 -3
- package/dist/{gitGraph-G5XIXVHT-SL6TDof6.js → gitGraph-G5XIXVHT-B_c6xFJv.js} +3 -3
- package/dist/{gitGraphDiagram-V2S2FVAM-D9885mxd.js → gitGraphDiagram-V2S2FVAM-iQnXzbPM.js} +13 -13
- package/dist/{glide-data-editor-CkVEV-Gk.js → glide-data-editor-VgPtWvhu.js} +63 -63
- package/dist/{graphlib-CxWdvYQt.js → graphlib-BV1_gi0C.js} +4 -3
- package/dist/hasIn-DnfJcYpY.js +108 -0
- package/dist/{info-VBDWY6EO-6MXPTSmi.js → info-VBDWY6EO-BTyzxmhr.js} +3 -3
- package/dist/{infoDiagram-HS3SLOUP-Bw2FlRwF.js → infoDiagram-HS3SLOUP-OYrX6uO3.js} +13 -13
- package/dist/{input-BSde8uV4.js → input-CFY9gApZ.js} +5055 -5055
- package/dist/{isEmpty-BQtUinxJ.js → isEmpty-B7FX9wKt.js} +1 -1
- package/dist/{isSymbol-DFp8040B.js → isSymbol-DCbjQG_U.js} +1 -1
- package/dist/{journeyDiagram-XKPGCS4Q-BXlCEth8.js → journeyDiagram-XKPGCS4Q-ClPC94aN.js} +3 -3
- package/dist/{kanban-definition-3W4ZIXB7-CorxzSYm.js → kanban-definition-3W4ZIXB7-DHEAKdZt.js} +7 -7
- package/dist/{label-DTNqw9tv.js → label-DbZGAoCH.js} +538 -569
- package/dist/{loader-3c9hT4kT.js → loader-Bd1kgLn7.js} +19 -16
- package/dist/main.js +2602 -2594
- package/dist/{memoize-CuHciEBb.js → memoize-CSTI9eOX.js} +1 -1
- package/dist/{merge-CA_buyY3.js → merge-CVhG7q_o.js} +1 -1
- package/dist/{mermaid-CEKslOkI.js → mermaid-B2HDLx2g.js} +54 -54
- package/dist/{mermaid-parser.core-cq4YDee-.js → mermaid-parser.core-ntCgyx0x.js} +8 -8
- package/dist/min-Ds3gG0Ff.js +96 -0
- package/dist/{mindmap-definition-VGOIOE7T-DRsT8UaN.js → mindmap-definition-VGOIOE7T-CxEUZZvY.js} +9 -9
- package/dist/{now-CXAdKY5k.js → now-nrrrOr01.js} +1 -1
- package/dist/{once-CZno0h-b.js → once-C_TIu-kR.js} +1 -1
- package/dist/{packet-DYOGHKS2-Dw08gMaZ.js → packet-DYOGHKS2-BhvnpoGi.js} +3 -3
- package/dist/{pie-VRWISCQL-C5SPSvT8.js → pie-VRWISCQL-dILuA3iG.js} +3 -3
- package/dist/{pieDiagram-ADFJNKIX-DhJ1Cx2O.js → pieDiagram-ADFJNKIX-U3LrUqAS.js} +14 -14
- package/dist/{process-output-KyzWazB-.js → process-output-BbUNe4iH.js} +3181 -3204
- package/dist/{quadrantDiagram-AYHSOK5B-DXUFIWlz.js → quadrantDiagram-AYHSOK5B-BVWuq-3R.js} +2 -2
- package/dist/{radar-ZZBFDIW7-BvY0bgSg.js → radar-ZZBFDIW7-DwFrOJDj.js} +3 -3
- package/dist/range-fJeId9Ri.js +30 -0
- package/dist/{requirementDiagram-UZGBJVZJ-DO_gtQIb.js → requirementDiagram-UZGBJVZJ-D0zpQnKC.js} +9 -9
- package/dist/{sankeyDiagram-TZEHDZUN-OZzXEkuG.js → sankeyDiagram-TZEHDZUN-CExy1joT.js} +2 -2
- package/dist/{sequenceDiagram-WL72ISMW-K7nZRifV.js → sequenceDiagram-WL72ISMW-D1BJxLjH.js} +4 -4
- package/dist/{slides-component-CIcSvFh7.js → slides-component-CX2JC-Ws.js} +2 -2
- package/dist/{spec-DYaR1rJh.js → spec-CiHus5Bb.js} +3 -3
- package/dist/{stateDiagram-FKZM4ZOC-DzXJZAq7.js → stateDiagram-FKZM4ZOC-B1S8jGMn.js} +12 -12
- package/dist/{stateDiagram-v2-4FDKWEC3-BZBPUmyF.js → stateDiagram-v2-4FDKWEC3-BH5ozUbc.js} +10 -10
- package/dist/stex-CQDv3aS8.js +4 -0
- package/dist/style.css +1 -1
- package/dist/{timeline-definition-IT6M3QCI-DNoLAh-i.js → timeline-definition-IT6M3QCI-BDT9JAmn.js} +2 -2
- package/dist/{toDate-D6VXexnV.js → toDate-BzYZtEK7.js} +4 -4
- package/dist/{toNumber-xFPoy1OI.js → toNumber-55tjPCWr.js} +2 -2
- package/dist/tooltip-BXEpXV3R.js +404 -0
- package/dist/{treemap-GDKQZRPO-C5OoxpmV.js → treemap-GDKQZRPO-bx2ngsgN.js} +3 -3
- package/dist/{types-CQ-RbYxp.js → types-D_ntCXg0.js} +3 -3
- package/dist/{useAsyncData-Cd4Urlww.js → useAsyncData-rN1nzPaS.js} +2 -2
- package/dist/{useDeepCompareMemoize-X7clcrcQ.js → useDeepCompareMemoize-iM1YNTEF.js} +4 -4
- package/dist/{useIframeCapabilities-BVQrlRBd.js → useIframeCapabilities-CqhrVue6.js} +1 -1
- package/dist/{useLifecycle-Dids8BPm.js → useLifecycle-DgDTfOLZ.js} +9 -9
- package/dist/{useTheme-Dm1WaAGy.js → useTheme-MWfxn4oz.js} +4 -5
- package/dist/{vega-component-A6unyUJS.js → vega-component-CkpTXaRx.js} +23 -23
- package/dist/{xychartDiagram-PRI3JC2R-ehVeySMW.js → xychartDiagram-PRI3JC2R-CuAZiqHS.js} +5 -5
- package/dist/{Combination-B--d1_LV.js → zod-C6UGQ3fz.js} +8085 -8151
- package/package.json +8 -41
- package/src/__tests__/branded.ts +6 -0
- package/src/__tests__/main.test.tsx +12 -14
- package/src/components/ai/ai-provider-icon.tsx +3 -2
- package/src/components/app-config/user-config-form.tsx +0 -27
- package/src/components/chat/acp/agent-docs.tsx +3 -3
- package/src/components/chat/acp/agent-panel.tsx +69 -22
- package/src/components/chat/acp/agent-selector.tsx +2 -11
- package/src/components/chat/acp/state.ts +14 -2
- package/src/components/chat/chat-panel.tsx +2 -1
- package/src/components/data-table/TableBottomBar.tsx +12 -1
- package/src/components/data-table/TableTopBar.tsx +31 -35
- package/src/components/data-table/cell-selection/types.ts +3 -2
- package/src/components/data-table/charts/charts.tsx +42 -13
- package/src/components/data-table/charts/components/chart-items.tsx +1 -1
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-formatting/types.ts +3 -2
- package/src/components/data-table/column-header.tsx +4 -2
- package/src/components/data-table/column-wrapping/types.ts +3 -2
- package/src/components/data-table/columns.tsx +4 -1
- package/src/components/data-table/copy-column/types.ts +3 -2
- package/src/components/data-table/data-table.tsx +6 -1
- package/src/components/data-table/focus-row/types.ts +3 -2
- package/src/components/data-table/loading-table.tsx +4 -1
- package/src/components/data-table/range-focus/__tests__/atoms.test.ts +11 -11
- package/src/components/data-table/range-focus/__tests__/use-cell-range-selection.test.ts +9 -11
- package/src/components/data-table/range-focus/cell-selection-stats.tsx +3 -1
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +1 -1
- package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +2 -2
- package/src/components/editor/__tests__/data-attributes.test.tsx +93 -94
- package/src/components/editor/actions/name-cell-input.tsx +4 -2
- package/src/components/editor/actions/useCellActionButton.tsx +4 -2
- package/src/components/editor/ai/add-cell-with-ai.tsx +2 -1
- package/src/components/editor/cell/CellStatus.tsx +4 -5
- package/src/components/editor/cell/cell-context-menu.tsx +4 -2
- package/src/components/editor/cell/code/cell-editor.tsx +2 -1
- package/src/components/editor/cell/toolbar.tsx +2 -1
- package/src/components/editor/chrome/components/contribute-snippet-button.tsx +4 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +4 -1
- package/src/components/editor/chrome/panels/context-aware-panel/context-aware-panel.tsx +1 -1
- package/src/components/editor/chrome/panels/file-explorer-panel.tsx +0 -10
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +4 -1
- package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +2 -1
- package/src/components/editor/header/filename-input.tsx +4 -1
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +11 -12
- package/src/components/storage/__tests__/storage-snippets.test.ts +4 -6
- package/src/components/tracing/tracing.test.tsx +30 -30
- package/src/components/ui/accordion.tsx +1 -1
- package/src/components/ui/alert-dialog.tsx +1 -1
- package/src/components/ui/badge.tsx +2 -1
- package/src/components/ui/button.tsx +4 -3
- package/src/components/ui/calendar.tsx +3 -2
- package/src/components/ui/checkbox.tsx +1 -1
- package/src/components/ui/combobox.tsx +2 -1
- package/src/components/ui/command.tsx +4 -1
- package/src/components/ui/context-menu.tsx +1 -1
- package/src/components/ui/date-input.tsx +7 -6
- package/src/components/ui/date-picker.tsx +6 -4
- package/src/components/ui/dialog.tsx +1 -1
- package/src/components/ui/draggable-popover.tsx +1 -1
- package/src/components/ui/dropdown-menu.tsx +2 -1
- package/src/components/ui/field.tsx +1 -2
- package/src/components/ui/form.tsx +4 -5
- package/src/components/ui/fullscreen.tsx +4 -1
- package/src/components/ui/label.tsx +1 -1
- package/src/components/ui/navigation.tsx +1 -1
- package/src/components/ui/popover.tsx +1 -1
- package/src/components/ui/progress.tsx +4 -3
- package/src/components/ui/query-param-preserving-link.tsx +4 -2
- package/src/components/ui/radio-group.tsx +1 -1
- package/src/components/ui/range-slider.tsx +1 -1
- package/src/components/ui/scroll-area.tsx +1 -1
- package/src/components/ui/select.tsx +1 -1
- package/src/components/ui/sheet.tsx +3 -2
- package/src/components/ui/slider.tsx +1 -1
- package/src/components/ui/switch.tsx +1 -1
- package/src/components/ui/tabs.tsx +1 -1
- package/src/components/ui/textarea.tsx +1 -2
- package/src/components/ui/toast.tsx +1 -1
- package/src/components/ui/toggle.tsx +1 -1
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/core/ai/context/providers/cell-output.ts +1 -2
- package/src/core/ai/tools/edit-notebook-tool.ts +4 -3
- package/src/core/ai/tools/run-cells-tool.ts +4 -3
- package/src/core/cells/__tests__/add-missing-import.test.ts +23 -22
- package/src/core/cells/__tests__/apply-transaction.test.ts +12 -11
- package/src/core/cells/__tests__/cell.test.ts +14 -13
- package/src/core/cells/document-changes.ts +9 -9
- package/src/core/cells/logs.ts +1 -1
- package/src/core/codemirror/cells/__tests__/extensions.test.ts +15 -17
- package/src/core/codemirror/copilot/__tests__/transport.test.ts +128 -2
- package/src/core/codemirror/copilot/client.ts +9 -2
- package/src/core/codemirror/copilot/language-server.ts +11 -0
- package/src/core/codemirror/copilot/transport.ts +33 -8
- package/src/core/codemirror/language/languages/markdown.ts +1 -3
- package/src/core/codemirror/language/languages/python.ts +4 -0
- package/src/core/codemirror/language/languages/sql/completion-sources.tsx +4 -6
- package/src/core/codemirror/language/languages/sql/sql.ts +1 -3
- package/src/core/codemirror/language/panel/sql.tsx +4 -1
- package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +28 -42
- package/src/core/config/__tests__/config-schema.test.ts +2 -6
- package/src/core/config/config-schema.ts +0 -1
- package/src/core/config/feature-flag.tsx +0 -2
- package/src/core/datasets/data-source-connections.ts +4 -2
- package/src/core/dom/__tests__/htmlUtils.test.ts +8 -14
- package/src/core/dom/__tests__/outline.test.ts +2 -3
- package/src/core/edit-app.tsx +4 -1
- package/src/core/islands/__tests__/bridge.test.ts +20 -10
- package/src/core/islands/__tests__/parse.test.ts +8 -7
- package/src/core/network/__tests__/requests-lazy.test.ts +30 -14
- package/src/core/saving/__tests__/filename.test.ts +7 -6
- package/src/core/static/__tests__/download-html.test.ts +16 -15
- package/src/core/static/__tests__/files.test.ts +30 -28
- package/src/core/websocket/useMarimoKernelConnection.tsx +5 -11
- package/src/core/websocket/useWebSocket.tsx +3 -1
- package/src/css/app/Cell.css +25 -1
- package/src/css/globals.css +40 -14
- package/src/css/table.css +17 -0
- package/src/plugins/core/BadPlugin.tsx +7 -6
- package/src/plugins/impl/CheckboxPlugin.tsx +4 -1
- package/src/plugins/impl/DataEditorPlugin.tsx +8 -3
- package/src/plugins/impl/DataTablePlugin.tsx +5 -1
- package/src/plugins/impl/FormPlugin.tsx +1 -2
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +4 -1
- package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +43 -15
- package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +2 -11
- package/src/plugins/impl/chat/chat-ui.tsx +4 -1
- package/src/plugins/impl/data-frames/forms/__tests__/form.test.tsx +7 -9
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +12 -68
- package/src/plugins/impl/plotly/__tests__/selection.test.ts +237 -0
- package/src/plugins/impl/plotly/selection.ts +115 -0
- package/src/plugins/impl/vega/__tests__/make-selectable.test.ts +13 -14
- package/src/plugins/impl/vega/__tests__/utils.test.ts +68 -0
- package/src/plugins/impl/vega/utils.ts +14 -5
- package/src/plugins/impl/vega/vega.css +2 -1
- package/src/plugins/layout/ImageComparisonPlugin.tsx +1 -3
- package/src/plugins/stateless-plugin.ts +4 -2
- package/src/utils/__tests__/cell-urls.test.ts +24 -21
- package/src/utils/__tests__/filenames.test.ts +15 -14
- package/src/utils/__tests__/json-parser.test.ts +14 -21
- package/src/utils/__tests__/path.test.ts +34 -31
- package/src/utils/__tests__/urls.test.ts +19 -18
- package/src/utils/json/base64.ts +2 -5
- package/src/utils/time.ts +4 -2
- package/src/utils/tracer.ts +1 -0
- package/src/utils/typed.ts +2 -2
- package/dist/_basePickBy-QjOmBDRE.js +0 -110
- package/dist/_baseSet-xgn1IbGV.js +0 -27
- package/dist/architecture-7HQA4BMR-BRyVh_Za.js +0 -6
- package/dist/assets/__vite-browser-external-Us1ds95c.js +0 -1
- package/dist/dist-B0R_ZM4-.js +0 -6
- package/dist/dist-B4a9_9pj.js +0 -5
- package/dist/dist-BCSUKEwO.js +0 -5
- package/dist/dist-BONIDQq6.js +0 -5
- package/dist/dist-BYeRx2hb.js +0 -5
- package/dist/dist-D2Rk1j4R.js +0 -1381
- package/dist/dist-DZjX5TYv.js +0 -5
- package/dist/dist-Dkw9x6kc.js +0 -5
- package/dist/dist-Ds6UaXGR.js +0 -6
- package/dist/dist-KuEJ1Q53.js +0 -8
- package/dist/dist-S72WNyTZ.js +0 -5
- package/dist/dist-bTG-yssT.js +0 -5
- package/dist/dist-diF0sguc.js +0 -8
- package/dist/dist-mJ84BIgu.js +0 -8
- package/dist/dist-wSIhFWQz.js +0 -8
- package/dist/get-CqrzlV1v.js +0 -68
- package/dist/range-CYz5jI--.js +0 -17
- package/dist/stex-CZyTRGVB.js +0 -4
- package/dist/tooltip-DGHTbHl5.js +0 -404
- /package/dist/{dist-KZI_BHqV.js → dist-CxZvoNao.js} +0 -0
- /package/dist/{invariant-D4hPsZFI.js → invariant-e8eBgdux.js} +0 -0
- /package/dist/{isArrayLikeObject-C-hFPChh.js → isArrayLikeObject-LXbTYiBa.js} +0 -0
- /package/dist/{main-CvkAPtaq.js → main-XimWhSi_.js} +0 -0
- /package/dist/{purify.es-ukiMXY-F.js → purify.es-hTCfRGdl.js} +0 -0
- /package/dist/{react-dom-BKwCWYPW.js → react-dom-BSUuJjCR.js} +0 -0
- /package/dist/{stex-Ze8D4R_5.js → stex-D887Ylhf.js} +0 -0
|
@@ -6,8 +6,7 @@ import { useDebounceControlledState } from "@/hooks/useDebounce";
|
|
|
6
6
|
import { cn } from "@/utils/cn";
|
|
7
7
|
import { Events } from "@/utils/events";
|
|
8
8
|
|
|
9
|
-
export interface TextareaProps
|
|
10
|
-
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
9
|
+
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
11
10
|
bottomAdornment?: React.ReactNode;
|
|
12
11
|
}
|
|
13
12
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import * as ToastPrimitives from "@radix-ui/react-toast";
|
|
4
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
5
4
|
import { X } from "lucide-react";
|
|
5
|
+
import { Toast as ToastPrimitives } from "radix-ui";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
|
|
8
8
|
import { cn } from "@/utils/cn";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import * as TogglePrimitive from "@radix-ui/react-toggle";
|
|
4
3
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
import { Toggle as TogglePrimitive } from "radix-ui";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
|
|
7
7
|
import { cn } from "@/utils/cn";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { StyleNamespace } from "@/theme/namespace";
|
|
6
6
|
import { cn } from "@/utils/cn";
|
|
@@ -34,8 +34,7 @@ export interface CellOutputData {
|
|
|
34
34
|
// For the context provider
|
|
35
35
|
// Currently, we enforce that cellOutput is present.
|
|
36
36
|
interface CellOutputContextData
|
|
37
|
-
extends CellOutputData,
|
|
38
|
-
Record<string, unknown> {
|
|
37
|
+
extends CellOutputData, Record<string, unknown> {
|
|
39
38
|
cellOutput: BaseOutput;
|
|
40
39
|
}
|
|
41
40
|
|
|
@@ -72,9 +72,10 @@ type EditNotebookInput = z.infer<typeof editNotebookSchema>;
|
|
|
72
72
|
type EditOperation = EditNotebookInput["edit"];
|
|
73
73
|
export type EditType = EditOperation["type"];
|
|
74
74
|
|
|
75
|
-
export class EditNotebookTool
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
export class EditNotebookTool implements AiTool<
|
|
76
|
+
EditNotebookInput,
|
|
77
|
+
ToolOutputBase
|
|
78
|
+
> {
|
|
78
79
|
readonly name = "edit_notebook_tool";
|
|
79
80
|
readonly description = description;
|
|
80
81
|
readonly schema = editNotebookSchema;
|
|
@@ -50,9 +50,10 @@ const filePartSchema = z.object({
|
|
|
50
50
|
mediaType: z.string(),
|
|
51
51
|
}) satisfies z.ZodType<FileUIPart>;
|
|
52
52
|
|
|
53
|
-
export class RunStaleCellsTool
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
export class RunStaleCellsTool implements AiTool<
|
|
54
|
+
EmptyToolInput,
|
|
55
|
+
RunStaleCellsOutput
|
|
56
|
+
> {
|
|
56
57
|
readonly name = "run_stale_cells_tool";
|
|
57
58
|
readonly description = description;
|
|
58
59
|
readonly schema = z.object({});
|
|
@@ -48,28 +48,29 @@ describe("maybeAddMissingImport", () => {
|
|
|
48
48
|
"import marimo as mo\nimport marimo as mo",
|
|
49
49
|
"import marimo as mo",
|
|
50
50
|
];
|
|
51
|
-
it.each(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
51
|
+
it.each(VALID_IMPORTS)(
|
|
52
|
+
"should not add an import if the import statement already exists in the notebook",
|
|
53
|
+
(code) => {
|
|
54
|
+
const appStore = createStore();
|
|
55
|
+
appStore.set(variablesAtom, {} as Variables);
|
|
56
|
+
appStore.set(
|
|
57
|
+
notebookAtom,
|
|
58
|
+
MockNotebook.notebookState({
|
|
59
|
+
cellData: {
|
|
60
|
+
[Cell1]: { code: code },
|
|
61
|
+
},
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
64
|
+
const onAddImport = vi.fn();
|
|
65
|
+
maybeAddMissingImport({
|
|
66
|
+
moduleName: "marimo",
|
|
67
|
+
variableName: "mo",
|
|
68
|
+
onAddImport,
|
|
69
|
+
appStore,
|
|
70
|
+
});
|
|
71
|
+
expect(onAddImport).not.toHaveBeenCalled();
|
|
72
|
+
},
|
|
73
|
+
);
|
|
73
74
|
|
|
74
75
|
it("should add an import if the variable is not in the variables state and the import statement does not exist in the notebook", () => {
|
|
75
76
|
const appStore = createStore();
|
|
@@ -18,6 +18,7 @@ import { python } from "@codemirror/lang-python";
|
|
|
18
18
|
import { EditorState } from "@codemirror/state";
|
|
19
19
|
import { EditorView } from "@codemirror/view";
|
|
20
20
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
21
|
+
import { cellId } from "@/__tests__/branded";
|
|
21
22
|
import type { CellHandle } from "@/components/editor/notebook-cell";
|
|
22
23
|
import { adaptiveLanguageConfiguration } from "@/core/codemirror/language/extension";
|
|
23
24
|
import { OverridingHotkeyProvider } from "@/core/hotkeys/hotkeys";
|
|
@@ -121,7 +122,7 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
121
122
|
apply([
|
|
122
123
|
{
|
|
123
124
|
type: "create-cell",
|
|
124
|
-
cellId: "new-cell",
|
|
125
|
+
cellId: cellId("new-cell"),
|
|
125
126
|
code: "configured",
|
|
126
127
|
name: "",
|
|
127
128
|
config: { hide_code: true, disabled: true, column: 1 },
|
|
@@ -141,12 +142,12 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
141
142
|
apply([
|
|
142
143
|
{
|
|
143
144
|
type: "create-cell",
|
|
144
|
-
cellId: "new-cell",
|
|
145
|
+
cellId: cellId("new-cell"),
|
|
145
146
|
code: "new",
|
|
146
147
|
name: "",
|
|
147
148
|
config: {},
|
|
148
149
|
},
|
|
149
|
-
{ type: "move-cell", cellId: "new-cell", before: a },
|
|
150
|
+
{ type: "move-cell", cellId: cellId("new-cell"), before: a },
|
|
150
151
|
]);
|
|
151
152
|
expect(pretty(state)).toMatchInlineSnapshot(`
|
|
152
153
|
"
|
|
@@ -162,12 +163,12 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
162
163
|
apply([
|
|
163
164
|
{
|
|
164
165
|
type: "create-cell",
|
|
165
|
-
cellId: "new-cell",
|
|
166
|
+
cellId: cellId("new-cell"),
|
|
166
167
|
code: "initial",
|
|
167
168
|
name: "",
|
|
168
169
|
config: {},
|
|
169
170
|
},
|
|
170
|
-
{ type: "set-code", cellId: "new-cell", code: "updated" },
|
|
171
|
+
{ type: "set-code", cellId: cellId("new-cell"), code: "updated" },
|
|
171
172
|
]);
|
|
172
173
|
expect(pretty(state)).toMatchInlineSnapshot(`
|
|
173
174
|
"
|
|
@@ -182,12 +183,12 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
182
183
|
apply([
|
|
183
184
|
{
|
|
184
185
|
type: "create-cell",
|
|
185
|
-
cellId: "ephemeral",
|
|
186
|
+
cellId: cellId("ephemeral"),
|
|
186
187
|
code: "tmp",
|
|
187
188
|
name: "",
|
|
188
189
|
config: {},
|
|
189
190
|
},
|
|
190
|
-
{ type: "delete-cell", cellId: "ephemeral" },
|
|
191
|
+
{ type: "delete-cell", cellId: cellId("ephemeral") },
|
|
191
192
|
]);
|
|
192
193
|
expect(pretty(state)).toMatchInlineSnapshot(`
|
|
193
194
|
"
|
|
@@ -228,7 +229,7 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
228
229
|
it("move-cell with missing after anchor falls back to end", () => {
|
|
229
230
|
setup("a", "b");
|
|
230
231
|
const [a] = state.cellIds.inOrderIds;
|
|
231
|
-
apply([{ type: "move-cell", cellId: a, after: "nonexistent"
|
|
232
|
+
apply([{ type: "move-cell", cellId: a, after: cellId("nonexistent") }]);
|
|
232
233
|
expect(pretty(state)).toMatchInlineSnapshot(`
|
|
233
234
|
"
|
|
234
235
|
1: 'b'
|
|
@@ -240,7 +241,7 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
240
241
|
it("move-cell with missing before anchor falls back to start", () => {
|
|
241
242
|
setup("a", "b");
|
|
242
243
|
const [, b] = state.cellIds.inOrderIds;
|
|
243
|
-
apply([{ type: "move-cell", cellId: b, before: "nonexistent"
|
|
244
|
+
apply([{ type: "move-cell", cellId: b, before: cellId("nonexistent") }]);
|
|
244
245
|
expect(pretty(state)).toMatchInlineSnapshot(`
|
|
245
246
|
"
|
|
246
247
|
1: 'b'
|
|
@@ -254,8 +255,8 @@ describe("applyTransactionChanges edge cases", () => {
|
|
|
254
255
|
apply([
|
|
255
256
|
{
|
|
256
257
|
type: "move-cell",
|
|
257
|
-
cellId: "nonexistent"
|
|
258
|
-
after: "0"
|
|
258
|
+
cellId: cellId("nonexistent"),
|
|
259
|
+
after: cellId("0"),
|
|
259
260
|
},
|
|
260
261
|
]);
|
|
261
262
|
expect(pretty(state)).toMatchInlineSnapshot(`
|
|
@@ -43,19 +43,20 @@ describe("outputIsLoading", () => {
|
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
describe("outputIsStale", () => {
|
|
46
|
-
it.each(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
it.each(STATUSES)(
|
|
47
|
+
"should return true if the cell is edited and status is %s",
|
|
48
|
+
(status) => {
|
|
49
|
+
const cell = {
|
|
50
|
+
status: status,
|
|
51
|
+
staleInputs: true,
|
|
52
|
+
output: null,
|
|
53
|
+
runStartTimestamp: null,
|
|
54
|
+
interrupted: false,
|
|
55
|
+
};
|
|
56
|
+
const edited = true;
|
|
57
|
+
expect(outputIsStale(cell, edited)).toBe(true);
|
|
58
|
+
},
|
|
59
|
+
);
|
|
59
60
|
|
|
60
61
|
it("should return true if the cell is loading", () => {
|
|
61
62
|
const cell = {
|
|
@@ -425,7 +425,7 @@ export function fromDocumentChanges(
|
|
|
425
425
|
cellId,
|
|
426
426
|
before,
|
|
427
427
|
code: change.code,
|
|
428
|
-
newCellId: change.cellId
|
|
428
|
+
newCellId: change.cellId,
|
|
429
429
|
autoFocus: false,
|
|
430
430
|
hideCode: change.config?.hide_code ?? false,
|
|
431
431
|
},
|
|
@@ -433,14 +433,14 @@ export function fromDocumentChanges(
|
|
|
433
433
|
if (change.name) {
|
|
434
434
|
actions.push({
|
|
435
435
|
type: "updateCellName",
|
|
436
|
-
payload: { cellId: change.cellId
|
|
436
|
+
payload: { cellId: change.cellId, name: change.name },
|
|
437
437
|
});
|
|
438
438
|
}
|
|
439
439
|
if (change.config?.disabled != null || change.config?.column != null) {
|
|
440
440
|
actions.push({
|
|
441
441
|
type: "updateCellConfig",
|
|
442
442
|
payload: {
|
|
443
|
-
cellId: change.cellId
|
|
443
|
+
cellId: change.cellId,
|
|
444
444
|
config: {
|
|
445
445
|
...(change.config.disabled != null && {
|
|
446
446
|
disabled: change.config.disabled,
|
|
@@ -460,7 +460,7 @@ export function fromDocumentChanges(
|
|
|
460
460
|
case "delete-cell":
|
|
461
461
|
actions.push({
|
|
462
462
|
type: "deleteCell",
|
|
463
|
-
payload: { cellId: change.cellId
|
|
463
|
+
payload: { cellId: change.cellId },
|
|
464
464
|
});
|
|
465
465
|
break;
|
|
466
466
|
|
|
@@ -471,7 +471,7 @@ export function fromDocumentChanges(
|
|
|
471
471
|
// missing. No-ops if the cell itself doesn't exist.
|
|
472
472
|
case "move-cell": {
|
|
473
473
|
const ids = [...getCurrentCellIds()];
|
|
474
|
-
const cellId = change.cellId
|
|
474
|
+
const cellId = change.cellId;
|
|
475
475
|
const idx = ids.indexOf(cellId);
|
|
476
476
|
if (idx < 0) {
|
|
477
477
|
break;
|
|
@@ -507,7 +507,7 @@ export function fromDocumentChanges(
|
|
|
507
507
|
case "reorder-cells":
|
|
508
508
|
actions.push({
|
|
509
509
|
type: "setCellIds",
|
|
510
|
-
payload: { cellIds: change.cellIds
|
|
510
|
+
payload: { cellIds: change.cellIds },
|
|
511
511
|
});
|
|
512
512
|
break;
|
|
513
513
|
|
|
@@ -518,7 +518,7 @@ export function fromDocumentChanges(
|
|
|
518
518
|
actions.push({
|
|
519
519
|
type: "setCellCodes",
|
|
520
520
|
payload: {
|
|
521
|
-
ids: [change.cellId
|
|
521
|
+
ids: [change.cellId],
|
|
522
522
|
codes: [change.code],
|
|
523
523
|
codeIsStale: true,
|
|
524
524
|
},
|
|
@@ -530,7 +530,7 @@ export function fromDocumentChanges(
|
|
|
530
530
|
case "set-name":
|
|
531
531
|
actions.push({
|
|
532
532
|
type: "updateCellName",
|
|
533
|
-
payload: { cellId: change.cellId
|
|
533
|
+
payload: { cellId: change.cellId, name: change.name },
|
|
534
534
|
});
|
|
535
535
|
break;
|
|
536
536
|
|
|
@@ -542,7 +542,7 @@ export function fromDocumentChanges(
|
|
|
542
542
|
actions.push({
|
|
543
543
|
type: "updateCellConfig",
|
|
544
544
|
payload: {
|
|
545
|
-
cellId: change.cellId
|
|
545
|
+
cellId: change.cellId,
|
|
546
546
|
config: {
|
|
547
547
|
...(change.hideCode != null && { hide_code: change.hideCode }),
|
|
548
548
|
...(change.disabled != null && { disabled: change.disabled }),
|
package/src/core/cells/logs.ts
CHANGED
|
@@ -98,7 +98,7 @@ const CellLogLogger = {
|
|
|
98
98
|
? "red"
|
|
99
99
|
: "orange";
|
|
100
100
|
const status = payload.level.toUpperCase();
|
|
101
|
-
|
|
101
|
+
// oxlint-disable-next-line no-console -- intentional debug logging
|
|
102
102
|
console.log(
|
|
103
103
|
`%c[${status}]`,
|
|
104
104
|
`color:${color}; padding:2px 0; border-radius:2px; font-weight:bold`,
|
|
@@ -18,24 +18,22 @@ function createTransaction(spec: TransactionSpec) {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
describe("shouldAutorunMarkdownUpdate", () => {
|
|
21
|
-
it.each([
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
changes: { from: 0, insert: "#" },
|
|
29
|
-
annotations: [Transaction.userEvent.of(userEvent)],
|
|
30
|
-
});
|
|
21
|
+
it.each(["input.type", "delete.backward", "undo", "redo"])(
|
|
22
|
+
"accepts local %s transactions",
|
|
23
|
+
(userEvent) => {
|
|
24
|
+
const transaction = createTransaction({
|
|
25
|
+
changes: { from: 0, insert: "#" },
|
|
26
|
+
annotations: [Transaction.userEvent.of(userEvent)],
|
|
27
|
+
});
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
expect(
|
|
30
|
+
shouldAutorunMarkdownUpdate({
|
|
31
|
+
docChanged: transaction.docChanged,
|
|
32
|
+
transactions: [transaction],
|
|
33
|
+
}),
|
|
34
|
+
).toBe(true);
|
|
35
|
+
},
|
|
36
|
+
);
|
|
39
37
|
|
|
40
38
|
it("ignores formatting changes", () => {
|
|
41
39
|
const transaction = createTransaction({
|
|
@@ -365,7 +365,7 @@ describe("LazyWebsocketTransport", () => {
|
|
|
365
365
|
expect(delegate.connect).toHaveBeenCalled();
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
-
it("should
|
|
368
|
+
it("should use maxTimeoutMs as default when no timeout is provided", async () => {
|
|
369
369
|
const transport = new LazyWebsocketTransport({
|
|
370
370
|
getWsUrl: mockGetWsUrl,
|
|
371
371
|
waitForReady: mockWaitForReady,
|
|
@@ -376,12 +376,29 @@ describe("LazyWebsocketTransport", () => {
|
|
|
376
376
|
await transport.connect();
|
|
377
377
|
|
|
378
378
|
const data: any = { method: "test", params: [] };
|
|
379
|
-
await transport.sendData(data,
|
|
379
|
+
await transport.sendData(data, undefined);
|
|
380
380
|
|
|
381
381
|
const delegate = (transport as any).delegate;
|
|
382
382
|
expect(delegate.sendData).toHaveBeenCalledWith(data, 5000);
|
|
383
383
|
});
|
|
384
384
|
|
|
385
|
+
it("should respect caller-provided timeout without clamping", async () => {
|
|
386
|
+
const transport = new LazyWebsocketTransport({
|
|
387
|
+
getWsUrl: mockGetWsUrl,
|
|
388
|
+
waitForReady: mockWaitForReady,
|
|
389
|
+
showError: mockShowError,
|
|
390
|
+
maxTimeoutMs: 5000,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
await transport.connect();
|
|
394
|
+
|
|
395
|
+
const data: any = { method: "test", params: [] };
|
|
396
|
+
await transport.sendData(data, 30_000);
|
|
397
|
+
|
|
398
|
+
const delegate = (transport as any).delegate;
|
|
399
|
+
expect(delegate.sendData).toHaveBeenCalledWith(data, 30_000);
|
|
400
|
+
});
|
|
401
|
+
|
|
385
402
|
it("should throw error if reconnection fails", async () => {
|
|
386
403
|
const connectionError = new Error("Connection failed");
|
|
387
404
|
(WebSocketTransport as any).mockImplementation(function (this: any) {
|
|
@@ -407,6 +424,115 @@ describe("LazyWebsocketTransport", () => {
|
|
|
407
424
|
});
|
|
408
425
|
});
|
|
409
426
|
|
|
427
|
+
describe("onReconnect", () => {
|
|
428
|
+
it("should call onReconnect after close + sendData reconnection", async () => {
|
|
429
|
+
const transport = new LazyWebsocketTransport({
|
|
430
|
+
getWsUrl: mockGetWsUrl,
|
|
431
|
+
waitForReady: mockWaitForReady,
|
|
432
|
+
showError: mockShowError,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
const onReconnect = vi.fn().mockResolvedValue(undefined);
|
|
436
|
+
transport.onReconnect = onReconnect;
|
|
437
|
+
|
|
438
|
+
// Initial connect
|
|
439
|
+
await transport.connect();
|
|
440
|
+
expect(onReconnect).not.toHaveBeenCalled();
|
|
441
|
+
|
|
442
|
+
// Close the transport (simulates failure handling)
|
|
443
|
+
transport.close();
|
|
444
|
+
|
|
445
|
+
// sendData should reconnect and call onReconnect
|
|
446
|
+
const data: any = { method: "test", params: [] };
|
|
447
|
+
await transport.sendData(data, 5000);
|
|
448
|
+
|
|
449
|
+
expect(onReconnect).toHaveBeenCalledTimes(1);
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
it("should NOT call onReconnect on initial sendData connection", async () => {
|
|
453
|
+
const transport = new LazyWebsocketTransport({
|
|
454
|
+
getWsUrl: mockGetWsUrl,
|
|
455
|
+
waitForReady: mockWaitForReady,
|
|
456
|
+
showError: mockShowError,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const onReconnect = vi.fn().mockResolvedValue(undefined);
|
|
460
|
+
transport.onReconnect = onReconnect;
|
|
461
|
+
|
|
462
|
+
// sendData without prior connect — this is the initial connection
|
|
463
|
+
const data: any = { method: "test", params: [] };
|
|
464
|
+
await transport.sendData(data, 5000);
|
|
465
|
+
|
|
466
|
+
expect(onReconnect).not.toHaveBeenCalled();
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it("should call onReconnect after tryConnect failure + retry via sendData", async () => {
|
|
470
|
+
let connectAttempt = 0;
|
|
471
|
+
(WebSocketTransport as any).mockImplementation(function (this: any) {
|
|
472
|
+
this.connect = vi.fn().mockImplementation(() => {
|
|
473
|
+
connectAttempt++;
|
|
474
|
+
// First 2 attempts fail (retries=2 exhausted), then succeed on next sendData
|
|
475
|
+
if (connectAttempt <= 2) {
|
|
476
|
+
return Promise.reject(new Error("Connection failed"));
|
|
477
|
+
}
|
|
478
|
+
return Promise.resolve(undefined);
|
|
479
|
+
});
|
|
480
|
+
this.close = vi.fn();
|
|
481
|
+
this.sendData = vi.fn().mockResolvedValue({ result: "success" });
|
|
482
|
+
this.subscribe = vi.fn();
|
|
483
|
+
this.unsubscribe = vi.fn();
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
const transport = new LazyWebsocketTransport({
|
|
487
|
+
getWsUrl: mockGetWsUrl,
|
|
488
|
+
waitForReady: mockWaitForReady,
|
|
489
|
+
showError: mockShowError,
|
|
490
|
+
retries: 2,
|
|
491
|
+
retryDelayMs: 10,
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
const onReconnect = vi.fn().mockResolvedValue(undefined);
|
|
495
|
+
transport.onReconnect = onReconnect;
|
|
496
|
+
|
|
497
|
+
// Initial connect fails (all retries exhausted)
|
|
498
|
+
await expect(transport.connect()).rejects.toThrow("Connection failed");
|
|
499
|
+
expect(onReconnect).not.toHaveBeenCalled();
|
|
500
|
+
|
|
501
|
+
// Now sendData reconnects successfully
|
|
502
|
+
const data: any = { method: "test", params: [] };
|
|
503
|
+
await transport.sendData(data, 5000);
|
|
504
|
+
|
|
505
|
+
expect(onReconnect).toHaveBeenCalledTimes(1);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it("should propagate onReconnect rejection and allow retry", async () => {
|
|
509
|
+
const transport = new LazyWebsocketTransport({
|
|
510
|
+
getWsUrl: mockGetWsUrl,
|
|
511
|
+
waitForReady: mockWaitForReady,
|
|
512
|
+
showError: mockShowError,
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
const reconnectError = new Error("Re-initialization failed");
|
|
516
|
+
const onReconnect = vi.fn().mockRejectedValueOnce(reconnectError);
|
|
517
|
+
transport.onReconnect = onReconnect;
|
|
518
|
+
|
|
519
|
+
await transport.connect();
|
|
520
|
+
transport.close();
|
|
521
|
+
|
|
522
|
+
const data: any = { method: "test", params: [] };
|
|
523
|
+
await expect(transport.sendData(data, 5000)).rejects.toThrow(
|
|
524
|
+
"Re-initialization failed",
|
|
525
|
+
);
|
|
526
|
+
expect(onReconnect).toHaveBeenCalledTimes(1);
|
|
527
|
+
|
|
528
|
+
// needsReInitialization should still be true, so a subsequent retry
|
|
529
|
+
// will attempt onReconnect again
|
|
530
|
+
onReconnect.mockResolvedValueOnce(undefined);
|
|
531
|
+
await transport.sendData(data, 5000);
|
|
532
|
+
expect(onReconnect).toHaveBeenCalledTimes(2);
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
|
|
410
536
|
describe("close", () => {
|
|
411
537
|
it("should close delegate and clear it", async () => {
|
|
412
538
|
const transport = new LazyWebsocketTransport({
|
|
@@ -37,13 +37,20 @@ export const createWSTransport = once(() => {
|
|
|
37
37
|
export const getCopilotClient = once(() => {
|
|
38
38
|
const userConfig = store.get(resolvedMarimoConfigAtom);
|
|
39
39
|
const copilotSettings = userConfig.ai?.github?.copilot_settings ?? {};
|
|
40
|
+
const transport = createWSTransport();
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
const client = new CopilotLanguageServerClient({
|
|
42
43
|
rootUri: FILE_URI,
|
|
43
44
|
workspaceFolders: null,
|
|
44
|
-
transport
|
|
45
|
+
transport,
|
|
45
46
|
copilotSettings,
|
|
46
47
|
});
|
|
48
|
+
|
|
49
|
+
// Re-run the LSP initialize handshake when the transport reconnects
|
|
50
|
+
// after a close or connection failure.
|
|
51
|
+
transport.onReconnect = () => client.reInitialize();
|
|
52
|
+
|
|
53
|
+
return client;
|
|
47
54
|
});
|
|
48
55
|
|
|
49
56
|
export function copilotServer() {
|
|
@@ -86,6 +86,17 @@ export class CopilotLanguageServerClient extends LanguageServerClient {
|
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Re-run the LSP initialize handshake and send configuration.
|
|
91
|
+
* Called by the transport's onReconnect callback after reconnecting.
|
|
92
|
+
*/
|
|
93
|
+
async reInitialize(): Promise<void> {
|
|
94
|
+
logger.log("#reInitialize: Re-initializing LSP connection");
|
|
95
|
+
this.initializePromise = this.initialize();
|
|
96
|
+
await this.initializePromise;
|
|
97
|
+
await this.sendConfiguration();
|
|
98
|
+
}
|
|
99
|
+
|
|
89
100
|
private async sendConfiguration() {
|
|
90
101
|
const settings = this.copilotSettings;
|
|
91
102
|
// Skip if no settings are provided
|
|
@@ -36,7 +36,8 @@ export interface LazyWebsocketTransportOptions {
|
|
|
36
36
|
retryDelayMs?: number;
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
*
|
|
39
|
+
* Default timeout for sendData operations in milliseconds.
|
|
40
|
+
* Used when the caller does not provide an explicit timeout.
|
|
40
41
|
* @default 5000
|
|
41
42
|
*/
|
|
42
43
|
maxTimeoutMs?: number;
|
|
@@ -60,6 +61,13 @@ export class LazyWebsocketTransport extends Transport {
|
|
|
60
61
|
private delegate: WebSocketTransport | undefined;
|
|
61
62
|
private pendingSubscriptions: Subscription[] = [];
|
|
62
63
|
private readonly options: Required<LazyWebsocketTransportOptions>;
|
|
64
|
+
private needsReInitialization = false;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Callback invoked after the transport reconnects following a close or connection failure.
|
|
68
|
+
* Used by the LSP client to re-run the initialize handshake on the new connection.
|
|
69
|
+
*/
|
|
70
|
+
onReconnect?: () => Promise<void>;
|
|
63
71
|
|
|
64
72
|
constructor(options: LazyWebsocketTransportOptions) {
|
|
65
73
|
super();
|
|
@@ -157,11 +165,11 @@ export class LazyWebsocketTransport extends Transport {
|
|
|
157
165
|
);
|
|
158
166
|
if (attempt === this.options.retries) {
|
|
159
167
|
this.delegate = undefined;
|
|
168
|
+
this.needsReInitialization = true;
|
|
160
169
|
// Show error toast on final retry
|
|
161
170
|
this.options.showError(
|
|
162
171
|
"GitHub Copilot Connection Error",
|
|
163
|
-
|
|
164
|
-
prettyError(error),
|
|
172
|
+
`Failed to connect to GitHub Copilot. Please check your settings and try again.\n\n${prettyError(error)}`,
|
|
165
173
|
);
|
|
166
174
|
throw error;
|
|
167
175
|
}
|
|
@@ -183,6 +191,7 @@ export class LazyWebsocketTransport extends Transport {
|
|
|
183
191
|
override close(): void {
|
|
184
192
|
this.delegate?.close();
|
|
185
193
|
this.delegate = undefined;
|
|
194
|
+
this.needsReInitialization = true;
|
|
186
195
|
}
|
|
187
196
|
|
|
188
197
|
override async sendData(
|
|
@@ -202,6 +211,25 @@ export class LazyWebsocketTransport extends Transport {
|
|
|
202
211
|
"Unable to connect to GitHub Copilot. Please check your settings and try again.",
|
|
203
212
|
);
|
|
204
213
|
}
|
|
214
|
+
|
|
215
|
+
// Re-run LSP initialization handshake after reconnecting
|
|
216
|
+
if (this.needsReInitialization && this.onReconnect) {
|
|
217
|
+
Logger.log(
|
|
218
|
+
"Copilot#sendData: Re-initializing LSP after reconnection...",
|
|
219
|
+
);
|
|
220
|
+
try {
|
|
221
|
+
await this.onReconnect();
|
|
222
|
+
this.needsReInitialization = false;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
// Close the uninitialized connection so the next attempt starts fresh
|
|
225
|
+
this.close();
|
|
226
|
+
Logger.error(
|
|
227
|
+
"Copilot#sendData: LSP re-initialization after reconnection failed",
|
|
228
|
+
error,
|
|
229
|
+
);
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
205
233
|
}
|
|
206
234
|
|
|
207
235
|
// After reconnection, delegate should be initialized
|
|
@@ -211,11 +239,8 @@ export class LazyWebsocketTransport extends Transport {
|
|
|
211
239
|
);
|
|
212
240
|
}
|
|
213
241
|
|
|
214
|
-
//
|
|
215
|
-
timeout =
|
|
216
|
-
timeout ?? this.options.maxTimeoutMs,
|
|
217
|
-
this.options.maxTimeoutMs,
|
|
218
|
-
);
|
|
242
|
+
// Use maxTimeoutMs as default when no timeout is provided
|
|
243
|
+
timeout = timeout ?? this.options.maxTimeoutMs;
|
|
219
244
|
return this.delegate.sendData(data, timeout);
|
|
220
245
|
}
|
|
221
246
|
}
|