@marimo-team/islands 0.22.1-dev37 → 0.22.1-dev39

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 (172) hide show
  1. package/dist/{ConnectedDataExplorerComponent-DTOsfq2x.js → ConnectedDataExplorerComponent-DuD8BVl6.js} +2 -2
  2. package/dist/{Plot-WhbJAbBh.js → Plot-BxlSHo0G.js} +47 -38
  3. package/dist/{chat-ui-CJCTr1kq.js → chat-ui-Cel1kBfc.js} +1 -1
  4. package/dist/{glide-data-editor-BQPLhydy.js → glide-data-editor-BqnvTmDo.js} +1712 -1681
  5. package/dist/main.js +360 -354
  6. package/dist/{process-output-D0SEeV3t.js → process-output-DC1TOnIl.js} +1 -1
  7. package/dist/{spec-CiHus5Bb.js → spec-CD7QaCV-.js} +1 -1
  8. package/dist/style.css +1 -1
  9. package/dist/useLifecycle-4fA1pHoh.js +177 -0
  10. package/package.json +1 -1
  11. package/src/__mocks__/common.ts +4 -4
  12. package/src/components/chat/acp/agent-panel.tsx +2 -2
  13. package/src/components/data-table/__tests__/columns.test.tsx +7 -7
  14. package/src/components/data-table/cell-hover-template/types.ts +1 -1
  15. package/src/components/data-table/cell-hover-text/types.ts +1 -1
  16. package/src/components/data-table/cell-selection/__tests__/feature.test.ts +1 -1
  17. package/src/components/data-table/cell-selection/types.ts +1 -1
  18. package/src/components/data-table/cell-styling/types.ts +1 -1
  19. package/src/components/data-table/charts/chart-spec/altair-generator.ts +2 -2
  20. package/src/components/data-table/column-formatting/types.ts +2 -2
  21. package/src/components/data-table/column-summary/legacy-chart-spec.ts +1 -1
  22. package/src/components/data-table/column-wrapping/types.ts +1 -1
  23. package/src/components/data-table/copy-column/types.ts +1 -1
  24. package/src/components/data-table/focus-row/types.ts +1 -1
  25. package/src/components/data-table/loading-table.tsx +1 -1
  26. package/src/components/data-table/range-focus/__tests__/atoms.test.ts +2 -2
  27. package/src/components/data-table/range-focus/atoms.ts +2 -2
  28. package/src/components/dependency-graph/dependency-graph-tree.tsx +1 -1
  29. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +1 -1
  30. package/src/components/editor/actions/pair-with-agent-modal.tsx +142 -0
  31. package/src/components/editor/actions/useNotebookActions.tsx +10 -0
  32. package/src/components/editor/ai/ai-completion-editor.tsx +1 -1
  33. package/src/components/editor/app-container.tsx +1 -1
  34. package/src/components/editor/chrome/panels/empty-state.tsx +1 -0
  35. package/src/components/editor/controls/keyboard-shortcuts.tsx +1 -1
  36. package/src/components/editor/navigation/__tests__/navigation.test.ts +1 -1
  37. package/src/components/editor/navigation/navigation.ts +1 -1
  38. package/src/components/editor/notebook-cell.tsx +1 -1
  39. package/src/components/editor/output/JsonOutput.tsx +4 -4
  40. package/src/components/editor/output/ansi-reduce.ts +2 -2
  41. package/src/components/editor/output/console/ConsoleOutput.tsx +1 -1
  42. package/src/components/editor/renderers/cells-renderer.tsx +1 -1
  43. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +1 -1
  44. package/src/components/editor/renderers/plugins.ts +1 -1
  45. package/src/components/editor/renderers/slides-layout/types.ts +2 -2
  46. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +2 -2
  47. package/src/components/editor/renderers/vertical-layout/__tests__/vertical-layout.test.ts +1 -1
  48. package/src/components/find-replace/find-replace.tsx +3 -1
  49. package/src/components/forms/form.tsx +1 -1
  50. package/src/components/forms/options.ts +1 -1
  51. package/src/components/static-html/static-banner.tsx +2 -2
  52. package/src/components/terminal/terminal.tsx +4 -4
  53. package/src/components/ui/button.tsx +1 -1
  54. package/src/components/ui/command.tsx +1 -1
  55. package/src/core/ai/context/providers/__tests__/datasource.test.ts +1 -1
  56. package/src/core/ai/context/providers/__tests__/error.test.ts +1 -1
  57. package/src/core/ai/context/providers/__tests__/variable.test.ts +1 -1
  58. package/src/core/ai/context/registry.ts +2 -2
  59. package/src/core/ai/tools/registry.ts +1 -1
  60. package/src/core/cells/__tests__/cells.test.ts +2 -2
  61. package/src/core/cells/__tests__/scrollCellIntoView.test.ts +1 -1
  62. package/src/core/cells/__tests__/session.test.ts +1 -1
  63. package/src/core/cells/__tests__/utils.test.ts +1 -1
  64. package/src/core/cells/cells.ts +1 -1
  65. package/src/core/cells/ids.ts +1 -1
  66. package/src/core/codemirror/ai/request.ts +1 -1
  67. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +1 -1
  68. package/src/core/codemirror/copilot/__tests__/transport.test.ts +1 -1
  69. package/src/core/codemirror/copilot/language-server.ts +1 -1
  70. package/src/core/codemirror/copilot/types.ts +1 -1
  71. package/src/core/codemirror/facet.ts +1 -1
  72. package/src/core/codemirror/language/__tests__/sql.test.ts +4 -4
  73. package/src/core/codemirror/language/languages/sql/completion-builder.ts +1 -1
  74. package/src/core/codemirror/language/metadata.ts +1 -1
  75. package/src/core/codemirror/language/types.ts +1 -1
  76. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -1
  77. package/src/core/codemirror/lsp/notebook-lsp.ts +1 -1
  78. package/src/core/codemirror/misc/__tests__/dnd.test.ts +1 -1
  79. package/src/core/codemirror/rtc/loro/awareness.ts +1 -1
  80. package/src/core/config/feature-flag.tsx +1 -1
  81. package/src/core/dom/outline.ts +1 -1
  82. package/src/core/export/__tests__/hooks.test.ts +1 -1
  83. package/src/core/hotkeys/__tests__/hotkeys.test.ts +1 -1
  84. package/src/core/hotkeys/shortcuts.ts +1 -1
  85. package/src/core/islands/__tests__/bridge.test.ts +2 -2
  86. package/src/core/islands/bridge.ts +2 -2
  87. package/src/core/islands/components/output-wrapper.tsx +1 -1
  88. package/src/core/islands/parse.ts +1 -1
  89. package/src/core/lsp/__tests__/transport.test.ts +1 -1
  90. package/src/core/network/DeferredRequestRegistry.ts +1 -1
  91. package/src/core/network/__tests__/requests-network.test.ts +1 -1
  92. package/src/core/network/api.ts +2 -2
  93. package/src/core/network/requests-lazy.ts +1 -1
  94. package/src/core/network/requests-toasting.tsx +1 -1
  95. package/src/core/static/files.ts +1 -1
  96. package/src/core/vscode/vscode-bindings.ts +1 -1
  97. package/src/core/wasm/bridge.ts +3 -3
  98. package/src/core/wasm/worker/tracer.ts +1 -1
  99. package/src/core/websocket/useWebSocket.tsx +2 -2
  100. package/src/css/globals.css +37 -61
  101. package/src/custom.d.ts +1 -1
  102. package/src/hooks/__tests__/useDuplicateShortcuts.test.ts +2 -2
  103. package/src/hooks/debug.ts +3 -3
  104. package/src/hooks/useDebounce.ts +1 -1
  105. package/src/hooks/useEventListener.ts +1 -1
  106. package/src/hooks/useHotkey.ts +1 -1
  107. package/src/hooks/useLifecycle.ts +2 -2
  108. package/src/hooks/useNonce.ts +1 -1
  109. package/src/hooks/useResizeObserver.ts +2 -2
  110. package/src/main.tsx +1 -1
  111. package/src/plugins/core/RenderHTML.tsx +3 -3
  112. package/src/plugins/core/__test__/registerReactComponent.test.ts +1 -1
  113. package/src/plugins/core/registerReactComponent.tsx +4 -4
  114. package/src/plugins/core/rpc.ts +1 -1
  115. package/src/plugins/impl/DataTablePlugin.tsx +1 -1
  116. package/src/plugins/impl/FileBrowserPlugin.tsx +1 -1
  117. package/src/plugins/impl/FormPlugin.tsx +1 -1
  118. package/src/plugins/impl/__tests__/MatrixPlugin.test.tsx +1 -1
  119. package/src/plugins/impl/anywidget/AnyWidgetPlugin.tsx +1 -1
  120. package/src/plugins/impl/anywidget/model.ts +1 -1
  121. package/src/plugins/impl/anywidget/types.ts +2 -2
  122. package/src/plugins/impl/anywidget/widget-binding.ts +1 -1
  123. package/src/plugins/impl/chat/ChatPlugin.tsx +1 -1
  124. package/src/plugins/impl/chat/chat-ui.tsx +1 -1
  125. package/src/plugins/impl/data-editor/glide-data-editor.tsx +1 -1
  126. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +2 -2
  127. package/src/plugins/impl/data-explorer/components/query-form.tsx +1 -1
  128. package/src/plugins/impl/data-explorer/functions/function.ts +1 -1
  129. package/src/plugins/impl/data-explorer/queries/types.ts +1 -1
  130. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -1
  131. package/src/plugins/impl/data-frames/forms/renderers.tsx +1 -1
  132. package/src/plugins/impl/data-frames/utils/operators.ts +1 -1
  133. package/src/plugins/impl/matplotlib/MatplotlibPlugin.tsx +1 -1
  134. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +1 -1
  135. package/src/plugins/impl/panel/PanelPlugin.tsx +2 -2
  136. package/src/plugins/impl/plotly/Plot.tsx +3 -3
  137. package/src/plugins/impl/vega/batched.ts +1 -1
  138. package/src/plugins/impl/vega/make-selectable.ts +1 -1
  139. package/src/plugins/impl/vega/types.ts +1 -1
  140. package/src/plugins/layout/DownloadPlugin.tsx +1 -1
  141. package/src/plugins/layout/LazyPlugin.tsx +1 -1
  142. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  143. package/src/plugins/layout/mermaid/mermaid.tsx +1 -1
  144. package/src/plugins/plugins.ts +1 -1
  145. package/src/stories/data-explorer.stories.tsx +1 -1
  146. package/src/stories/dataframe.stories.tsx +1 -1
  147. package/src/stories/editor.stories.tsx +1 -1
  148. package/src/stories/select.stories.tsx +1 -1
  149. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  150. package/src/utils/Logger.ts +1 -1
  151. package/src/utils/__tests__/arrays.test.ts +1 -1
  152. package/src/utils/__tests__/blob.test.ts +1 -1
  153. package/src/utils/__tests__/dates.test.ts +1 -1
  154. package/src/utils/__tests__/errors.test.ts +1 -1
  155. package/src/utils/__tests__/objects.test.ts +3 -3
  156. package/src/utils/__tests__/waitForWs.test.ts +1 -1
  157. package/src/utils/arrays.ts +1 -1
  158. package/src/utils/assertNever.ts +1 -1
  159. package/src/utils/batch-requests.ts +2 -2
  160. package/src/utils/createReducer.ts +2 -2
  161. package/src/utils/id-tree.tsx +2 -2
  162. package/src/utils/idle.ts +1 -1
  163. package/src/utils/invariant.ts +1 -2
  164. package/src/utils/maps.ts +1 -1
  165. package/src/utils/math.ts +0 -1
  166. package/src/utils/multi-map.ts +1 -1
  167. package/src/utils/objects.ts +1 -1
  168. package/src/utils/once.ts +2 -2
  169. package/src/utils/staticImplements.ts +1 -1
  170. package/src/utils/storage/jotai.ts +1 -1
  171. package/src/utils/tracer.ts +2 -2
  172. package/dist/useLifecycle-DgDTfOLZ.js +0 -173
@@ -0,0 +1,177 @@
1
+ import { s as __toESM } from "./chunk-BNovOVIE.js";
2
+ import { t as require_react } from "./react-Bs6Z0kvn.js";
3
+ import { t as require_compiler_runtime } from "./compiler-runtime-B_OLMU9S.js";
4
+ import { l as createLucideIcon } from "./dist-D_UjpfOY.js";
5
+ import { g as Logger, r as cva, y as cn } from "./button-DNlNlZY_.js";
6
+ import { t as require_jsx_runtime } from "./jsx-runtime-9hcJiI23.js";
7
+ import { _ as useSetAtom, y as atom } from "./useTheme-MWfxn4oz.js";
8
+ var Calendar = createLucideIcon("calendar", [
9
+ ["path", {
10
+ d: "M8 2v4",
11
+ key: "1cmpym"
12
+ }],
13
+ ["path", {
14
+ d: "M16 2v4",
15
+ key: "4m81vk"
16
+ }],
17
+ ["rect", {
18
+ width: "18",
19
+ height: "18",
20
+ x: "3",
21
+ y: "4",
22
+ rx: "2",
23
+ key: "1hopcy"
24
+ }],
25
+ ["path", {
26
+ d: "M3 10h18",
27
+ key: "8toen8"
28
+ }]
29
+ ]), Hash = createLucideIcon("hash", [
30
+ ["line", {
31
+ x1: "4",
32
+ x2: "20",
33
+ y1: "9",
34
+ y2: "9",
35
+ key: "4lhtct"
36
+ }],
37
+ ["line", {
38
+ x1: "4",
39
+ x2: "20",
40
+ y1: "15",
41
+ y2: "15",
42
+ key: "vyu0kd"
43
+ }],
44
+ ["line", {
45
+ x1: "10",
46
+ x2: "8",
47
+ y1: "3",
48
+ y2: "21",
49
+ key: "1ggp8o"
50
+ }],
51
+ ["line", {
52
+ x1: "16",
53
+ x2: "14",
54
+ y1: "3",
55
+ y2: "21",
56
+ key: "weycgp"
57
+ }]
58
+ ]), ToggleLeft = createLucideIcon("toggle-left", [["circle", {
59
+ cx: "9",
60
+ cy: "12",
61
+ r: "3",
62
+ key: "u3jwor"
63
+ }], ["rect", {
64
+ width: "20",
65
+ height: "14",
66
+ x: "2",
67
+ y: "5",
68
+ rx: "7",
69
+ key: "g7kal2"
70
+ }]]), Type = createLucideIcon("type", [
71
+ ["path", {
72
+ d: "M12 4v16",
73
+ key: "1654pz"
74
+ }],
75
+ ["path", {
76
+ d: "M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2",
77
+ key: "e0r10z"
78
+ }],
79
+ ["path", {
80
+ d: "M9 20h6",
81
+ key: "s66wpe"
82
+ }]
83
+ ]), import_compiler_runtime$2 = require_compiler_runtime();
84
+ function createReducer(e, m) {
85
+ return {
86
+ reducer: (h, g) => (h || (h = e()), g.type in m ? m[g.type](h, g.payload) : (Logger.error(`Action type ${g.type} is not defined in reducers.`), h)),
87
+ createActions: (e2) => {
88
+ let h = {};
89
+ for (let g in m) h[g] = (m2) => {
90
+ e2({
91
+ type: g,
92
+ payload: m2
93
+ });
94
+ };
95
+ return h;
96
+ }
97
+ };
98
+ }
99
+ function createReducerAndAtoms(e, m, h) {
100
+ let g = [...h ?? []], v = (e2) => {
101
+ g.push(e2);
102
+ }, { reducer: y, createActions: b } = createReducer(e, m), x = (e2, m2) => {
103
+ try {
104
+ let h2 = y(e2, m2);
105
+ for (let v2 of g) try {
106
+ v2(e2, h2, m2);
107
+ } catch (e3) {
108
+ Logger.error(`Error in middleware for action ${m2.type}:`, e3);
109
+ }
110
+ return h2;
111
+ } catch (h2) {
112
+ return Logger.error(`Error in reducer for action ${m2.type}:`, h2), e2;
113
+ }
114
+ }, S = atom(e()), C = /* @__PURE__ */ new WeakMap();
115
+ function w(e2) {
116
+ let m2 = (0, import_compiler_runtime$2.c)(4), h2 = e2 === void 0 ? {} : e2, g2 = useSetAtom(S);
117
+ if (h2.skipMiddleware === true) {
118
+ let e3;
119
+ return m2[0] === g2 ? e3 = m2[1] : (e3 = b((e4) => {
120
+ g2((m3) => y(m3, e4));
121
+ }), m2[0] = g2, m2[1] = e3), e3;
122
+ }
123
+ C.has(g2) || C.set(g2, b((e3) => {
124
+ g2((m3) => x(m3, e3));
125
+ }));
126
+ let _;
127
+ return m2[2] === g2 ? _ = m2[3] : (_ = C.get(g2), m2[2] = g2, m2[3] = _), _;
128
+ }
129
+ return {
130
+ reducer: x,
131
+ addMiddleware: v,
132
+ createActions: b,
133
+ valueAtom: S,
134
+ useActions: w
135
+ };
136
+ }
137
+ var import_compiler_runtime$1 = require_compiler_runtime(), import_react = /* @__PURE__ */ __toESM(require_react(), 1), import_jsx_runtime = /* @__PURE__ */ __toESM(require_jsx_runtime(), 1), badgeVariants = cva("inline-flex items-center border rounded-full px-2 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2", {
138
+ variants: { variant: {
139
+ default: "bg-primary hover:bg-primary/60 border-transparent text-primary-foreground",
140
+ defaultOutline: "bg-(--blue-2) border-(--blue-8) text-(--blue-11)",
141
+ secondary: "bg-secondary hover:bg-secondary/80 border-transparent text-secondary-foreground",
142
+ destructive: "bg-(--red-2) border-(--red-6) text-(--red-9) hover:bg-(--red-3)",
143
+ success: "bg-(--grass-2) border-(--grass-5) text-(--grass-9) hover:bg-(--grass-3)",
144
+ outline: "text-foreground"
145
+ } },
146
+ defaultVariants: { variant: "default" }
147
+ }), Badge = (e) => {
148
+ let m = (0, import_compiler_runtime$1.c)(10), h, g, _;
149
+ m[0] === e ? (h = m[1], g = m[2], _ = m[3]) : ({ className: h, variant: _, ...g } = e, m[0] = e, m[1] = h, m[2] = g, m[3] = _);
150
+ let v;
151
+ m[4] !== h || m[5] !== _ ? (v = cn(badgeVariants({ variant: _ }), h), m[4] = h, m[5] = _, m[6] = v) : v = m[6];
152
+ let b;
153
+ return m[7] !== g || m[8] !== v ? (b = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
154
+ className: v,
155
+ ...g
156
+ }), m[7] = g, m[8] = v, m[9] = b) : b = m[9], b;
157
+ }, import_compiler_runtime = require_compiler_runtime();
158
+ function useOnMount(e) {
159
+ let m = (0, import_compiler_runtime.c)(1), h;
160
+ m[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (h = [], m[0] = h) : h = m[0], (0, import_react.useEffect)(e, h);
161
+ }
162
+ function useOnUnmount(e) {
163
+ let m = (0, import_compiler_runtime.c)(3), h;
164
+ m[0] === e ? h = m[1] : (h = () => e(), m[0] = e, m[1] = h);
165
+ let g;
166
+ m[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (g = [], m[2] = g) : g = m[2], (0, import_react.useEffect)(h, g);
167
+ }
168
+ export {
169
+ Type as a,
170
+ Calendar as c,
171
+ createReducerAndAtoms as i,
172
+ useOnUnmount as n,
173
+ ToggleLeft as o,
174
+ Badge as r,
175
+ Hash as s,
176
+ useOnMount as t
177
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marimo-team/islands",
3
- "version": "0.22.1-dev37",
3
+ "version": "0.22.1-dev39",
4
4
  "main": "dist/main.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /** biome-ignore-all lint/suspicious/noConsole: for debugging */
2
+ /* oxlint-disable no-console -- for debugging */
3
3
  import { type Mock, vi } from "vitest";
4
4
  import { invariant } from "@/utils/invariant";
5
5
 
@@ -137,12 +137,12 @@ export const SetupMocks = {
137
137
  store[key] = value;
138
138
  }),
139
139
  removeItem: vi.fn((key: string) => {
140
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
140
+ // oxlint-disable-next-line typescript/no-dynamic-delete
141
141
  delete store[key];
142
142
  }),
143
143
  clear: vi.fn(() => {
144
144
  for (const key of Object.keys(store)) {
145
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
145
+ // oxlint-disable-next-line typescript/no-dynamic-delete
146
146
  delete store[key];
147
147
  }
148
148
  }),
@@ -179,7 +179,7 @@ export const SetupMocks = {
179
179
  },
180
180
  };
181
181
 
182
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
+ // oxlint-disable-next-line typescript/no-explicit-any
183
183
  export function asMock<T extends (...args: any[]) => unknown>(fn: T): Mock<T> {
184
184
  invariant(
185
185
  "mock" in fn,
@@ -763,7 +763,7 @@ const AgentPanel: React.FC = () => {
763
763
  // We don't want to disconnect so users can switch between different
764
764
  // panels without losing their session
765
765
  };
766
- // eslint-disable-next-line react-hooks/exhaustive-deps
766
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
767
767
  }, [wsUrl]);
768
768
 
769
769
  const handleNewSession = useEvent(async () => {
@@ -889,7 +889,7 @@ const AgentPanel: React.FC = () => {
889
889
  };
890
890
 
891
891
  createOrResumeSession();
892
- // eslint-disable-next-line react-hooks/exhaustive-deps
892
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
893
893
  }, [isConnected, agent, tabLastActiveSessionId, activeSessionId]);
894
894
 
895
895
  // Handler for prompt submission
@@ -230,7 +230,7 @@ describe("generateColumns", () => {
230
230
  });
231
231
 
232
232
  // "age" is a number column — should auto right-align
233
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
233
+ // oxlint-disable-next-line typescript/no-explicit-any
234
234
  const cell = (columns[1].cell as any)({
235
235
  column: {
236
236
  columnDef: columns[1],
@@ -241,7 +241,7 @@ describe("generateColumns", () => {
241
241
  expect(cell?.props.className).toContain("text-right");
242
242
 
243
243
  // "name" is a string column — should remain left-aligned
244
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
244
+ // oxlint-disable-next-line typescript/no-explicit-any
245
245
  const nameCell = (columns[0].cell as any)({
246
246
  column: {
247
247
  columnDef: columns[0],
@@ -261,7 +261,7 @@ describe("generateColumns", () => {
261
261
  });
262
262
 
263
263
  // "age" is numeric but explicitly set to left
264
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
264
+ // oxlint-disable-next-line typescript/no-explicit-any
265
265
  const cell = (columns[1].cell as any)({
266
266
  column: {
267
267
  columnDef: columns[1],
@@ -301,7 +301,7 @@ describe("generateColumns", () => {
301
301
  });
302
302
 
303
303
  // Assuming getCellStyleClass is a function that returns a class name
304
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
304
+ // oxlint-disable-next-line typescript/no-explicit-any
305
305
  const cell = (columns[0].cell as any)({
306
306
  column: {
307
307
  columnDef: columns[0],
@@ -333,7 +333,7 @@ describe("generateColumns", () => {
333
333
  // Right-justified: parent wrapper should have items-end, sort/filter icons should flip to the left
334
334
  const { container: rightContainer } = render(
335
335
  <TooltipProvider>
336
- {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
336
+ {/* oxlint-disable-next-line typescript/no-explicit-any */}
337
337
  {(columns[0].header as any)({ column: mockColumn(columns[0]) })}
338
338
  </TooltipProvider>,
339
339
  );
@@ -347,7 +347,7 @@ describe("generateColumns", () => {
347
347
  // Center-justified: parent wrapper should have items-center, no flex-row-reverse
348
348
  const { container: centerContainer } = render(
349
349
  <TooltipProvider>
350
- {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
350
+ {/* oxlint-disable-next-line typescript/no-explicit-any */}
351
351
  {(columns[1].header as any)({ column: mockColumn(columns[1]) })}
352
352
  </TooltipProvider>,
353
353
  );
@@ -572,7 +572,7 @@ describe("LocaleNumber", () => {
572
572
  <LocaleNumber value={1_234_567.89} />
573
573
  </I18nProvider>,
574
574
  );
575
- // eslint-disable-next-line no-irregular-whitespace
575
+ // oxlint-disable-next-line no-irregular-whitespace
576
576
  expect(container.textContent).toMatchInlineSnapshot(`"1 234 567,89"`);
577
577
  });
578
578
 
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
 
4
4
  export interface CellHoverTemplateTableState {
5
5
  cellHoverTemplate: string | null;
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
 
4
4
  import type { RowData } from "@tanstack/react-table";
5
5
 
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* oxlint-disable typescript/no-explicit-any */
3
3
 
4
4
  import type { Cell, Column, Row, Table } from "@tanstack/react-table";
5
5
  import { describe, expect, it, vi } from "vitest";
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
  import type { OnChangeFn, RowData, Updater } from "@tanstack/react-table";
4
4
 
5
5
  export interface CellSelectionItem {
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
  import type { RowData } from "@tanstack/react-table";
4
4
 
5
5
  export type CellStyleState = Record<
@@ -78,7 +78,7 @@ export function generateAltairChart(
78
78
 
79
79
  if (encodings?.tooltip) {
80
80
  const tooltip = encodings.tooltip;
81
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ // oxlint-disable-next-line typescript/no-explicit-any
82
82
  const makeTooltip = (t: Record<string, any>) => {
83
83
  const kwargs = makeKwargs(t);
84
84
  return new FunctionCall("alt.Tooltip", kwargs);
@@ -149,7 +149,7 @@ ${variableName}
149
149
  `.trim();
150
150
  }
151
151
 
152
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
152
+ // oxlint-disable-next-line typescript/no-explicit-any
153
153
  function makeKwargs<T extends Record<string, any>>(obj: T) {
154
154
  const result: Record<string, PythonCode> = {};
155
155
 
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
 
4
4
  import type { OnChangeFn, RowData } from "@tanstack/react-table";
5
5
  import type { DataType } from "@/core/kernel/messages";
@@ -38,7 +38,7 @@ export interface ColumnFormattingInstance {
38
38
  setColumnFormatting: (value?: FormatOption) => void;
39
39
  getColumnFormatting?: () => FormatOption | undefined;
40
40
  getCanFormat?: () => boolean;
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ // oxlint-disable-next-line typescript/no-explicit-any
42
42
  applyColumnFormatting: (value: any) => any;
43
43
  }
44
44
 
@@ -282,7 +282,7 @@ export function getDataSpecAndSourceName<T>(data: string | T[]): {
282
282
  const base64 = extractBase64FromDataURL(data);
283
283
  const decoded = window.atob(base64);
284
284
 
285
- // eslint-disable-next-line unicorn/prefer-ternary
285
+ // oxlint-disable-next-line unicorn/prefer-ternary
286
286
  if (decoded.startsWith(ARROW_MAGIC_NUMBER)) {
287
287
  dataSpec = {
288
288
  values: base64ToUint8Array(base64),
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
  import type { OnChangeFn, RowData } from "@tanstack/react-table";
4
4
 
5
5
  export type ColumnWrappingState = Record<string, "nowrap" | "wrap" | undefined>;
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
  import type { RowData } from "@tanstack/react-table";
4
4
 
5
5
  export interface CopyColumnOptions {
@@ -1,5 +1,5 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
- /* eslint-disable @typescript-eslint/no-empty-interface */
2
+ /* oxlint-disable typescript/no-empty-object-type */
3
3
 
4
4
  import type { OnChangeFn, RowData } from "@tanstack/react-table";
5
5
 
@@ -43,7 +43,7 @@ export const LoadingTable = ({
43
43
  <TableBody>
44
44
  {Array.from({ length: pageSize }).map((_, i) => (
45
45
  <TableRow key={i}>
46
- {Array.from({ length: NUM_COLUMNS }).map((_, j) => (
46
+ {Array.from({ length: NUM_COLUMNS }).map((__, j) => (
47
47
  <TableCell key={j}>
48
48
  <div className="h-4 bg-(--slate-5) animate-pulse rounded-md w-[90%]" />
49
49
  </TableCell>
@@ -10,7 +10,7 @@ vi.mock("@/utils/copy", () => ({
10
10
  }));
11
11
 
12
12
  vi.mock("../utils", async (importOriginal) => {
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ // oxlint-disable-next-line typescript/no-explicit-any
14
14
  const original = (await importOriginal()) as any;
15
15
  return {
16
16
  ...original,
@@ -28,7 +28,7 @@ import {
28
28
  } from "../atoms";
29
29
  import { getCellsBetween, getCellValues } from "../utils";
30
30
 
31
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ // oxlint-disable-next-line typescript/no-explicit-any
32
32
  type T = any;
33
33
 
34
34
  // Create mock table and cells
@@ -32,9 +32,9 @@ function initialState(): CellSelectionState {
32
32
  };
33
33
  }
34
34
 
35
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
+ // oxlint-disable-next-line typescript/no-explicit-any
36
36
  type AnyTable = Table<any>;
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ // oxlint-disable-next-line typescript/no-explicit-any
38
38
  type AnyCell = Cell<any, unknown>;
39
39
 
40
40
  const {
@@ -51,7 +51,7 @@ export const DependencyGraphTree: React.FC<PropsWithChildren<Props>> = ({
51
51
  layoutDirection,
52
52
  settings,
53
53
  }) => {
54
- // eslint-disable-next-line react/hook-use-state
54
+ // oxlint-disable-next-line react/hook-use-state
55
55
  const [initial] = useState(() => {
56
56
  let elements = elementsBuilder.createElements(
57
57
  cellIds,
@@ -176,7 +176,7 @@ describe("DynamicFavicon", () => {
176
176
  const { rerender } = render(<DynamicFavicon isRunning={true} />);
177
177
  rerender(<DynamicFavicon isRunning={false} />);
178
178
 
179
- // eslint-disable-next-line @typescript-eslint/unbound-method
179
+ // oxlint-disable-next-line typescript/unbound-method
180
180
  expect(Notification.requestPermission).toHaveBeenCalled();
181
181
  });
182
182
  });
@@ -0,0 +1,142 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { useAtomValue } from "jotai";
4
+ import { CheckIcon, CopyIcon } from "lucide-react";
5
+ import React, { useState } from "react";
6
+ import { Button } from "@/components/ui/button";
7
+ import {
8
+ DialogContent,
9
+ DialogDescription,
10
+ DialogFooter,
11
+ DialogHeader,
12
+ DialogTitle,
13
+ } from "@/components/ui/dialog";
14
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
15
+ import { runtimeConfigAtom } from "@/core/runtime/config";
16
+ import { copyToClipboard } from "@/utils/copy";
17
+ import { Events } from "@/utils/events";
18
+ import { Tooltip } from "@/components/ui/tooltip";
19
+ import type { RuntimeConfig } from "@/core/runtime/types";
20
+
21
+ type AgentTab = "claude" | "codex" | "opencode";
22
+
23
+ function buildRemoteUrl(config: RuntimeConfig) {
24
+ const url = new URL(config.url);
25
+ if (config.authToken) {
26
+ url.searchParams.set("auth", config.authToken);
27
+ }
28
+ return url.toString();
29
+ }
30
+
31
+ function getPromptCommand(agent: AgentTab, remoteUrl: string): string {
32
+ const command = import.meta.env.DEV ? "uv run marimo" : "uvx marimo@latest";
33
+ const base = `${command} pair prompt --url '${remoteUrl}'`;
34
+ switch (agent) {
35
+ case "claude":
36
+ return `claude "$(${base} --claude)"`;
37
+ case "codex":
38
+ return `codex "$(${base} --codex)"`;
39
+ case "opencode":
40
+ return `opencode "$(${base} --opencode)"`;
41
+ }
42
+ }
43
+
44
+ const SKILL_INSTALL = "npx skills add marimo-team/marimo-pair";
45
+
46
+ export const PairWithAgentModal: React.FC<{
47
+ onClose: () => void;
48
+ }> = ({ onClose }) => {
49
+ const [activeTab, setActiveTab] = useState<AgentTab>("claude");
50
+ const runtimeConfig = useAtomValue(runtimeConfigAtom);
51
+ const remoteUrl = buildRemoteUrl(runtimeConfig);
52
+ const promptCommand = getPromptCommand(activeTab, remoteUrl);
53
+
54
+ return (
55
+ <DialogContent className="sm:max-w-lg">
56
+ <DialogHeader>
57
+ <DialogTitle>Pair with an agent</DialogTitle>
58
+ <DialogDescription>
59
+ Use an AI coding agent to pair-program on this notebook.{" "}
60
+ <a
61
+ href="https://links.marimo.app/marimo-pair"
62
+ target="_blank"
63
+ rel="noopener noreferrer"
64
+ className="underline"
65
+ >
66
+ Learn more
67
+ </a>
68
+ .
69
+ </DialogDescription>
70
+ </DialogHeader>
71
+
72
+ <div className="flex flex-col gap-4 py-2">
73
+ <div className="flex flex-col gap-2">
74
+ <span className="text-sm font-medium">1. Install the skill</span>
75
+ <CommandBlock command={SKILL_INSTALL} />
76
+ </div>
77
+
78
+ <div className="flex flex-col gap-2">
79
+ <span className="text-sm font-medium">2. Run in your terminal</span>
80
+ <Tabs
81
+ value={activeTab}
82
+ onValueChange={(v) => setActiveTab(v as AgentTab)}
83
+ >
84
+ <TabsList className="w-full">
85
+ <TabsTrigger value="claude" className="flex-1">
86
+ Claude
87
+ </TabsTrigger>
88
+ <TabsTrigger value="codex" className="flex-1">
89
+ Codex
90
+ </TabsTrigger>
91
+ <TabsTrigger value="opencode" className="flex-1">
92
+ OpenCode
93
+ </TabsTrigger>
94
+ </TabsList>
95
+
96
+ <TabsContent value="claude" className="mt-3">
97
+ <CommandBlock command={promptCommand} />
98
+ </TabsContent>
99
+ <TabsContent value="codex" className="mt-3">
100
+ <CommandBlock command={promptCommand} />
101
+ </TabsContent>
102
+ <TabsContent value="opencode" className="mt-3">
103
+ <CommandBlock command={promptCommand} />
104
+ </TabsContent>
105
+ </Tabs>
106
+ </div>
107
+ </div>
108
+
109
+ <DialogFooter>
110
+ <Button variant="secondary" onClick={onClose}>
111
+ Close
112
+ </Button>
113
+ </DialogFooter>
114
+ </DialogContent>
115
+ );
116
+ };
117
+
118
+ const CommandBlock: React.FC<{ command: string }> = ({ command }) => {
119
+ const [copied, setCopied] = useState(false);
120
+
121
+ const copy = Events.stopPropagation(async (e) => {
122
+ e.preventDefault();
123
+ await copyToClipboard(command);
124
+ setCopied(true);
125
+ setTimeout(() => setCopied(false), 2000);
126
+ });
127
+
128
+ return (
129
+ <div className="flex items-center gap-2 rounded-md bg-muted px-3 py-2 font-mono text-xs">
130
+ <code className="flex-1 select-all break-words">{command}</code>
131
+ <Tooltip content="Copied!" open={copied}>
132
+ <Button onClick={copy} size="xs" variant="ghost">
133
+ {copied ? (
134
+ <CheckIcon size={14} strokeWidth={1.5} />
135
+ ) : (
136
+ <CopyIcon size={14} strokeWidth={1.5} />
137
+ )}
138
+ </Button>
139
+ </Tooltip>
140
+ </div>
141
+ );
142
+ };
@@ -36,6 +36,7 @@ import {
36
36
  PresentationIcon,
37
37
  SettingsIcon,
38
38
  Share2Icon,
39
+ SparklesIcon,
39
40
  Undo2Icon,
40
41
  XCircleIcon,
41
42
  YoutubeIcon,
@@ -45,6 +46,7 @@ import { settingDialogAtom } from "@/components/app-config/state";
45
46
  import { MarkdownIcon } from "@/components/editor/cell/code/icons";
46
47
  import { useImperativeModal } from "@/components/modal/ImperativeModal";
47
48
  import { renderShortcut } from "@/components/shortcuts/renderShortcut";
49
+ import { PairWithAgentModal } from "@/components/editor/actions/pair-with-agent-modal";
48
50
  import { ShareStaticNotebookModal } from "@/components/static-html/share-modal";
49
51
  import { toast } from "@/components/ui/use-toast";
50
52
  import {
@@ -343,6 +345,14 @@ export function useNotebookActions() {
343
345
  ],
344
346
  },
345
347
 
348
+ {
349
+ icon: <SparklesIcon size={14} strokeWidth={1.5} />,
350
+ label: "Pair with an agent",
351
+ handle: async () => {
352
+ openModal(<PairWithAgentModal onClose={closeModal} />);
353
+ },
354
+ },
355
+
346
356
  {
347
357
  icon: <Share2Icon size={14} strokeWidth={1.5} />,
348
358
  label: "Share",
@@ -156,7 +156,7 @@ export const AiCompletionEditor: React.FC<Props> = ({
156
156
  // Use complete to pass the prompt directly, else input might be empty
157
157
  complete(initialPrompt);
158
158
  }
159
- // eslint-disable-next-line react-hooks/exhaustive-deps
159
+ // oxlint-disable-next-line react-hooks/exhaustive-deps
160
160
  }, [triggerImmediately]);
161
161
 
162
162
  // Focus the input
@@ -31,7 +31,7 @@ export const AppContainer: React.FC<PropsWithChildren<Props>> = ({
31
31
  <StatusOverlay connection={connection} isRunning={isRunning} />
32
32
  <PyodideLoader>
33
33
  <WrappedWithSidebar>
34
- {/** biome-ignore lint/correctness/useUniqueElementIds: ID is used by other components to grab the DOM element */}
34
+ {/** oxlint-ignore-next-line -- ID is used by other components to grab the DOM element */}
35
35
  <div
36
36
  id="App"
37
37
  data-config-width={width}