@eclipse-lyra/extension-notebook 0.7.33 → 0.7.37

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.
@@ -7,8 +7,8 @@ import { unsafeHTML } from "lit/directives/unsafe-html.js";
7
7
  import { marked } from "marked";
8
8
  import * as monaco from "monaco-editor";
9
9
  import monacoStyles from "monaco-editor/min/vs/editor/editor.main.css?raw";
10
- import { LyraPart, workspaceService, createLogger } from "@eclipse-lyra/core";
11
- import { PyEnv, pythonPackageManagerService } from "@eclipse-lyra/extension-python-runtime/api";
10
+ import { LyraPart, unsubscribe, subscribe, TOPIC_CONTRIBUTEIONS_CHANGED, contributionRegistry, createLogger } from "@eclipse-lyra/core";
11
+ import { T as TARGET_NOTEBOOK_KERNELS } from "./notebook-kernel-api--RBL5TaE.js";
12
12
  var __defProp = Object.defineProperty;
13
13
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
14
14
  var __decorateClass = (decorators, target, key, kind) => {
@@ -25,8 +25,12 @@ let LyraNotebookEditor = class extends LyraPart {
25
25
  super(...arguments);
26
26
  this.cellOutputs = /* @__PURE__ */ new Map();
27
27
  this.executingCells = /* @__PURE__ */ new Set();
28
- this.pyConnected = false;
29
- this.pyConnecting = false;
28
+ this.availableKernels = [];
29
+ this.selectedKernelId = null;
30
+ this.kernel = null;
31
+ this.kernelConnected = false;
32
+ this.kernelConnecting = false;
33
+ this.kernelVersion = void 0;
30
34
  this.editingMarkdownCells = /* @__PURE__ */ new Set();
31
35
  this.executionCounter = 0;
32
36
  this.isRunningAll = false;
@@ -49,12 +53,16 @@ let LyraNotebookEditor = class extends LyraPart {
49
53
  this.themeObserver.disconnect();
50
54
  this.themeObserver = void 0;
51
55
  }
52
- if (this.pyenv) {
53
- this.pyenv.close();
54
- this.pyenv = void 0;
56
+ if (this.unsubscribeContributionsToken) {
57
+ unsubscribe(this.unsubscribeContributionsToken);
58
+ this.unsubscribeContributionsToken = void 0;
55
59
  }
56
- this.pyConnected = false;
57
- this.pyVersion = void 0;
60
+ if (this.kernel?.close) {
61
+ void Promise.resolve(this.kernel.close());
62
+ }
63
+ this.kernel = null;
64
+ this.kernelConnected = false;
65
+ this.kernelVersion = void 0;
58
66
  }
59
67
  async save() {
60
68
  if (!this.notebook || !this.input) return;
@@ -78,10 +86,39 @@ let LyraNotebookEditor = class extends LyraPart {
78
86
  doBeforeUI() {
79
87
  this.loadNotebook();
80
88
  }
89
+ async onKernelDropdownSelect(e) {
90
+ const value = e.detail?.item?.value ?? "";
91
+ const nextId = value || null;
92
+ if (this.selectedKernelId === nextId) return;
93
+ if (this.kernel?.close) void Promise.resolve(this.kernel.close());
94
+ this.kernel = null;
95
+ this.kernelConnected = false;
96
+ this.kernelVersion = void 0;
97
+ this.selectedKernelId = nextId;
98
+ if (this.notebook) {
99
+ if (!this.notebook.metadata) this.notebook.metadata = {};
100
+ this.notebook.metadata.kernel = nextId ?? void 0;
101
+ }
102
+ this.cellOutputs.clear();
103
+ this.executionCounter = 0;
104
+ this.notebook?.cells?.forEach((cell) => {
105
+ if (cell.cell_type === "code") {
106
+ cell.execution_count = null;
107
+ cell.outputs = [];
108
+ }
109
+ });
110
+ this.resetCellState();
111
+ await this.ensureKernelLoaded();
112
+ this.requestUpdate();
113
+ this.updateToolbar();
114
+ }
81
115
  renderToolbar() {
82
- const connectionTitle = this.pyConnecting ? "Connecting to Python..." : this.pyConnected ? "Python Connected" : "Python Disconnected - Click to connect";
83
- const connectionText = this.pyConnecting ? "Connecting..." : this.pyConnected && this.pyVersion ? `Python ${this.pyVersion}` : "Not connected";
84
- const iconColor = this.pyConnected ? "var(--wa-color-green-40)" : this.pyConnecting ? "var(--wa-color-warning-500)" : "var(--wa-color-red-40)";
116
+ const kernels = this.availableKernels;
117
+ kernels.length > 0;
118
+ const currentLabel = this.selectedKernelId ? kernels.find((c) => c.id === this.selectedKernelId)?.label ?? this.selectedKernelId : "Select kernel";
119
+ const connectionTitle = this.kernelConnecting ? "Connecting..." : this.kernelConnected ? "Kernel connected" : "Kernel disconnected";
120
+ const connectionText = this.kernelConnecting ? "Connecting..." : this.kernelConnected ? this.kernelVersion ?? "Connected" : "Not connected";
121
+ const iconColor = this.kernelConnected ? "var(--wa-color-green-40)" : this.kernelConnecting ? "var(--wa-color-warning-500)" : "var(--wa-color-red-40)";
85
122
  const runAllButton = this.isRunningAll ? html`
86
123
  <wa-button size="small" appearance="plain" @click=${() => this.cancelAllCells()} title="Cancel running all cells">
87
124
  <wa-icon name="stop" label="Stop"></wa-icon>
@@ -94,50 +131,174 @@ let LyraNotebookEditor = class extends LyraPart {
94
131
  </wa-button>
95
132
  `;
96
133
  return html`
97
- <wa-button
98
- appearance="plain"
134
+ <wa-dropdown
135
+ class="kernel-select"
136
+ placement="bottom-start"
137
+ distance="4"
99
138
  size="small"
100
- style="display: flex; align-items: center; gap: 0.5rem;"
101
- ?disabled=${this.pyConnecting}
102
- @click=${() => this.connectPython()}
103
- title=${connectionTitle}>
104
- <wa-icon
105
- name="circle"
106
- label="Python status"
107
- style=${styleMap({ color: iconColor })}
108
- ></wa-icon>
109
- ${connectionText}
110
- </wa-button>
139
+ @wa-select=${(e) => void this.onKernelDropdownSelect(e)}
140
+ >
141
+ <wa-button
142
+ slot="trigger"
143
+ appearance="plain"
144
+ size="small"
145
+ with-caret
146
+ title="Notebook kernel"
147
+ >
148
+ ${currentLabel}
149
+ </wa-button>
150
+ ${kernels.map(
151
+ (c) => html`
152
+ <wa-dropdown-item
153
+ value=${c.id}
154
+ type="checkbox"
155
+ ?checked=${c.id === this.selectedKernelId}
156
+ >
157
+ ${c.label}
158
+ </wa-dropdown-item>
159
+ `
160
+ )}
161
+ </wa-dropdown>
111
162
  ${runAllButton}
112
- <wa-button
113
- size="small"
163
+ <wa-button
164
+ size="small"
114
165
  appearance="plain"
115
166
  @click=${() => this.clearAllOutputs()}
116
- title="Clear all outputs and reset execution counter">
167
+ title="Clear all outputs and reset execution counter"
168
+ >
117
169
  <wa-icon name="eraser" label="Clear"></wa-icon>
118
170
  Clear Outputs
119
171
  </wa-button>
120
- <wa-button
121
- size="small"
122
- appearance="plain"
123
- @click=${() => this.restartKernel()}
124
- title="Restart Python kernel (clears all variables and state)"
125
- ?disabled=${!this.pyConnected || this.pyConnecting}>
126
- <wa-icon name="arrows-rotate" label="Restart"></wa-icon>
127
- Restart Kernel
128
- </wa-button>
129
- <wa-button
130
- size="small"
131
- appearance="plain"
132
- @click=${() => this.openPackageManager()}
133
- title="Manage required packages for this notebook">
134
- <wa-icon name="box" label="Packages"></wa-icon>
135
- Packages
136
- </wa-button>
172
+ ${this.kernel?.restart ? html`
173
+ <wa-button
174
+ size="small"
175
+ appearance="plain"
176
+ @click=${() => void this.restartKernel()}
177
+ title="Restart kernel"
178
+ ?disabled=${!this.kernelConnected || this.kernelConnecting}
179
+ >
180
+ <wa-icon name="arrows-rotate" label="Restart"></wa-icon>
181
+ Restart Kernel
182
+ </wa-button>
183
+ ` : ""}
184
+ ${this.kernel?.openPackageManager ? html`
185
+ <wa-button
186
+ size="small"
187
+ appearance="plain"
188
+ @click=${() => this.openPackageManager()}
189
+ title="Manage packages"
190
+ >
191
+ <wa-icon name="box" label="Packages"></wa-icon>
192
+ Packages
193
+ </wa-button>
194
+ ` : ""}
195
+ ${this.kernel ? this.kernel.connect ? html`
196
+ <wa-button
197
+ appearance="plain"
198
+ size="small"
199
+ style="display: flex; align-items: center; gap: 0.5rem;"
200
+ ?disabled=${this.kernelConnecting}
201
+ @click=${() => void this.connectKernel()}
202
+ title=${connectionTitle}
203
+ >
204
+ <wa-icon name="circle" label="Kernel status" style=${styleMap({ color: iconColor })}></wa-icon>
205
+ ${connectionText}
206
+ </wa-button>
207
+ ` : html`
208
+ <span style="display: flex; align-items: center; gap: 0.5rem;" title=${connectionTitle}>
209
+ <wa-icon name="circle" label="Kernel status" style=${styleMap({ color: iconColor })}></wa-icon>
210
+ ${connectionText}
211
+ </span>
212
+ ` : ""}
137
213
  `;
138
214
  }
139
- doInitUI() {
215
+ async connectKernel() {
216
+ if (this.kernelConnecting || !this.kernel?.connect) return;
217
+ try {
218
+ this.kernelConnecting = true;
219
+ this.requestUpdate();
220
+ this.updateToolbar();
221
+ await this.kernel.connect({
222
+ requiredPackages: this.notebook?.metadata?.required_packages
223
+ });
224
+ this.kernelConnected = true;
225
+ if (this.kernel.getVersion) this.kernelVersion = await this.kernel.getVersion();
226
+ } catch (err) {
227
+ logger.error("Failed to connect kernel", err);
228
+ } finally {
229
+ this.kernelConnecting = false;
230
+ this.requestUpdate();
231
+ this.updateToolbar();
232
+ }
233
+ }
234
+ async doInitUI() {
140
235
  this.setupThemeObserver();
236
+ this.unsubscribeContributionsToken = subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event) => {
237
+ if (event?.target === TARGET_NOTEBOOK_KERNELS) {
238
+ void this.refreshKernels();
239
+ }
240
+ });
241
+ await this.refreshKernels();
242
+ }
243
+ resolveDefaultKernelId(contributions) {
244
+ if (!contributions.length) return null;
245
+ const fromMeta = this.notebook?.metadata?.kernel;
246
+ if (fromMeta && contributions.some((c) => c.id === fromMeta)) return fromMeta;
247
+ const python = contributions.find((c) => c.id === "python");
248
+ if (python) return python.id;
249
+ const js = contributions.find((c) => c.id === "javascript");
250
+ if (js) return js.id;
251
+ return contributions[0].id;
252
+ }
253
+ async refreshKernels() {
254
+ const contributions = contributionRegistry.getContributions(TARGET_NOTEBOOK_KERNELS);
255
+ this.availableKernels = contributions;
256
+ if (!this.selectedKernelId && contributions.length) {
257
+ this.selectedKernelId = this.resolveDefaultKernelId(contributions);
258
+ if (this.notebook && this.selectedKernelId) {
259
+ if (!this.notebook.metadata) this.notebook.metadata = {};
260
+ this.notebook.metadata.kernel = this.selectedKernelId;
261
+ }
262
+ }
263
+ if (this.selectedKernelId && !contributions.some((c) => c.id === this.selectedKernelId)) {
264
+ this.selectedKernelId = contributions.length ? contributions[0].id : null;
265
+ }
266
+ this.requestUpdate();
267
+ await this.ensureKernelLoaded();
268
+ this.updateToolbar();
269
+ }
270
+ async ensureKernelLoaded() {
271
+ const id = this.selectedKernelId;
272
+ if (!id || this.kernel?.id === id) return;
273
+ if (this.kernel?.close) void Promise.resolve(this.kernel.close());
274
+ this.kernel = null;
275
+ this.kernelConnected = false;
276
+ this.kernelVersion = void 0;
277
+ const contribution = this.availableKernels.find((c) => c.id === id);
278
+ if (!contribution) return;
279
+ try {
280
+ this.kernelConnecting = true;
281
+ this.requestUpdate();
282
+ this.updateToolbar();
283
+ const k = await contribution.loadKernel();
284
+ if (this.selectedKernelId !== id) return;
285
+ this.kernel = k;
286
+ if (k.connect) {
287
+ await k.connect({
288
+ requiredPackages: this.notebook?.metadata?.required_packages
289
+ });
290
+ }
291
+ this.kernelConnected = true;
292
+ if (k.getVersion) {
293
+ this.kernelVersion = await k.getVersion();
294
+ }
295
+ } catch (err) {
296
+ logger.error("Failed to load kernel", id, err);
297
+ } finally {
298
+ this.kernelConnecting = false;
299
+ this.requestUpdate();
300
+ this.updateToolbar();
301
+ }
141
302
  }
142
303
  async loadNotebook() {
143
304
  const file = this.input.data;
@@ -153,6 +314,9 @@ let LyraNotebookEditor = class extends LyraPart {
153
314
  }]
154
315
  };
155
316
  }
317
+ if (this.notebook?.metadata?.kernel) {
318
+ this.selectedKernelId = this.notebook.metadata.kernel;
319
+ }
156
320
  if (this.notebook?.cells) {
157
321
  const maxCount = this.notebook.cells.filter((cell) => cell.cell_type === "code").map((cell) => cell.execution_count ?? 0).reduce((max, count) => Math.max(max, count), 0);
158
322
  this.executionCounter = maxCount;
@@ -165,6 +329,7 @@ let LyraNotebookEditor = class extends LyraPart {
165
329
  }
166
330
  });
167
331
  }
332
+ void this.refreshKernels();
168
333
  }
169
334
  setupThemeObserver() {
170
335
  const rootElement = document.documentElement;
@@ -276,109 +441,32 @@ let LyraNotebookEditor = class extends LyraPart {
276
441
  }
277
442
  return newCell;
278
443
  }
279
- async initPyodide() {
280
- if (!this.pyenv) {
281
- this.pyenv = new PyEnv();
282
- const workspace = await workspaceService.getWorkspace();
283
- if (workspace) {
284
- await this.pyenv.init(workspace);
285
- this.pyConnected = true;
286
- try {
287
- const response = await this.pyenv.execCode("import sys; sys.version.split()[0]");
288
- this.pyVersion = response?.result || "Unknown";
289
- } catch (error) {
290
- console.error("Failed to get Python version:", error);
291
- this.pyVersion = "Unknown";
292
- }
293
- const requiredPackages = this.notebook?.metadata?.required_packages || [];
294
- if (requiredPackages.length > 0) {
295
- try {
296
- await this.pyenv.loadPackages(requiredPackages);
297
- } catch (error) {
298
- console.error("Failed to load required packages:", error);
299
- }
300
- }
301
- try {
302
- await this.pyenv.execCode(`
303
- try:
304
- import matplotlib
305
- matplotlib.use('agg')
306
-
307
- import matplotlib.pyplot as plt
308
- import io
309
- import base64
310
-
311
- _original_show = plt.show
312
- _display_data = None
313
-
314
- def _patched_show(*args, **kwargs):
315
- """Patched plt.show() that captures the current figure for notebook display."""
316
- global _display_data
317
- if plt.get_fignums():
318
- fig = plt.gcf()
319
- buffer = io.BytesIO()
320
- fig.savefig(buffer, format='png', bbox_inches='tight', dpi=100)
321
- buffer.seek(0)
322
- _display_data = base64.b64encode(buffer.read()).decode('utf-8')
323
- plt.close(fig)
324
- # Don't call original show() as it would try to display in a window
325
-
326
- plt.show = _patched_show
327
- except ImportError:
328
- # matplotlib not installed - skip configuration
329
- pass
330
- `);
331
- } catch (error) {
332
- console.error("Failed to configure matplotlib:", error);
333
- }
334
- }
335
- }
336
- }
337
444
  async executeCell(cellIndex) {
338
445
  const cell = this.notebook.cells[cellIndex];
339
446
  if (cell.cell_type !== "code") return;
340
447
  this.executingCells.add(cellIndex);
341
448
  this.requestUpdate();
342
449
  try {
343
- await this.initPyodide();
344
- const editor = this.monacoEditors.get(cellIndex);
345
- let code = editor ? editor.getValue() : this.getCellSource(cell);
346
- const response = await this.pyenv.execCode(code);
347
- const outputParts = [];
348
- if (response && typeof response === "object" && "console" in response) {
349
- const consoleOutput = response.console;
350
- if (Array.isArray(consoleOutput) && consoleOutput.length > 0) {
351
- const filteredOutput = consoleOutput.filter((s) => s && s.trim());
352
- if (filteredOutput.length > 0) {
353
- outputParts.push(...filteredOutput);
354
- }
450
+ await this.ensureKernelLoaded();
451
+ const k = this.kernel;
452
+ if (!k) {
453
+ if (this.executingCells.has(cellIndex)) {
454
+ this.cellOutputs.set(cellIndex, { type: "error", data: "No kernel selected" });
355
455
  }
456
+ return;
356
457
  }
357
- let imageData = void 0;
358
- try {
359
- const checkDisplayData = await this.pyenv.execCode('_display_data if "_display_data" in dir() else None');
360
- const displayResult = checkDisplayData && typeof checkDisplayData === "object" ? checkDisplayData.result : checkDisplayData;
361
- if (displayResult && String(displayResult) !== "None" && String(displayResult) !== "undefined") {
362
- imageData = String(displayResult);
363
- await this.pyenv.execCode("_display_data = None");
364
- }
365
- } catch (e) {
366
- logger.debug("No display data to retrieve:", e);
367
- }
368
- if (!imageData) {
369
- const result = response && typeof response === "object" ? response.result : response;
370
- if (result !== void 0 && result !== null && String(result) !== "undefined") {
371
- const resultStr = String(result);
372
- if (resultStr && resultStr !== "undefined") {
373
- outputParts.push(resultStr);
374
- }
375
- }
458
+ const editor = this.monacoEditors.get(cellIndex);
459
+ const code = editor ? editor.getValue() : this.getCellSource(cell);
460
+ const result = await k.execute(code);
461
+ if (result.error) {
462
+ this.cellOutputs.set(cellIndex, { type: "error", data: result.error });
463
+ } else {
464
+ this.cellOutputs.set(cellIndex, {
465
+ type: "execute_result",
466
+ data: result.data,
467
+ imageData: result.imageData
468
+ });
376
469
  }
377
- this.cellOutputs.set(cellIndex, {
378
- type: "execute_result",
379
- data: outputParts.length > 0 ? outputParts.join("\n") : void 0,
380
- imageData
381
- });
382
470
  this.executionCounter++;
383
471
  cell.execution_count = this.executionCounter;
384
472
  this.markDirty(true);
@@ -386,7 +474,7 @@ except ImportError:
386
474
  if (this.executingCells.has(cellIndex)) {
387
475
  this.cellOutputs.set(cellIndex, {
388
476
  type: "error",
389
- data: String(error)
477
+ data: error instanceof Error ? error.message : String(error)
390
478
  });
391
479
  }
392
480
  } finally {
@@ -394,25 +482,15 @@ except ImportError:
394
482
  this.requestUpdate();
395
483
  }
396
484
  }
397
- async cancelExecution(cellIndex) {
398
- if (!this.pyenv) return;
399
- if (this.pyenv.canInterrupt()) {
400
- this.pyenv.interrupt();
485
+ cancelExecution(cellIndex) {
486
+ if (this.kernel?.interrupt) {
487
+ this.kernel.interrupt();
401
488
  } else {
402
489
  this.cellOutputs.set(cellIndex, {
403
490
  type: "error",
404
- data: "Execution cancelled by user (worker terminated - SharedArrayBuffer not available for graceful interrupt)"
491
+ data: "Cancellation not supported for this kernel"
405
492
  });
406
493
  this.executingCells.delete(cellIndex);
407
- this.pyenv.close();
408
- this.pyenv = void 0;
409
- this.pyConnected = false;
410
- this.pyVersion = void 0;
411
- try {
412
- await this.initPyodide();
413
- } catch (error) {
414
- console.error("Failed to reinitialize Python after cancellation:", error);
415
- }
416
494
  this.requestUpdate();
417
495
  }
418
496
  }
@@ -431,20 +509,20 @@ except ImportError:
431
509
  this.requestUpdate();
432
510
  }
433
511
  async restartKernel() {
434
- if (!this.pyenv || this.pyConnecting) return;
512
+ if (!this.kernel?.restart || this.kernelConnecting) return;
435
513
  try {
436
- this.pyConnecting = true;
437
- this.pyenv.close();
438
- this.pyenv = void 0;
439
- this.pyConnected = false;
440
- this.pyVersion = void 0;
441
- this.requestUpdate();
442
- await this.initPyodide();
514
+ this.kernelConnecting = true;
443
515
  this.requestUpdate();
516
+ this.updateToolbar();
517
+ await this.kernel.restart();
518
+ this.kernelConnected = true;
519
+ if (this.kernel.getVersion) this.kernelVersion = await this.kernel.getVersion();
444
520
  } catch (error) {
445
- console.error("Failed to restart kernel:", error);
521
+ logger.error("Failed to restart kernel", error);
446
522
  } finally {
447
- this.pyConnecting = false;
523
+ this.kernelConnecting = false;
524
+ this.requestUpdate();
525
+ this.updateToolbar();
448
526
  }
449
527
  }
450
528
  async runAllCells() {
@@ -470,6 +548,7 @@ except ImportError:
470
548
  }
471
549
  cancelAllCells() {
472
550
  this.cancelRunAll = true;
551
+ this.kernel?.interrupt?.();
473
552
  }
474
553
  toggleMarkdownEdit(index) {
475
554
  if (this.editingMarkdownCells.has(index)) {
@@ -597,7 +676,7 @@ except ImportError:
597
676
  </wa-button>
598
677
  ` : html`
599
678
  <lyra-command
600
- cmd="python"
679
+ cmd="notebook.runCell"
601
680
  icon="play"
602
681
  title="Run cell"
603
682
  size="small"
@@ -656,19 +735,6 @@ except ImportError:
656
735
  `;
657
736
  }
658
737
  }
659
- async connectPython() {
660
- if (this.pyConnecting || this.pyConnected) {
661
- return;
662
- }
663
- try {
664
- this.pyConnecting = true;
665
- await this.initPyodide();
666
- } catch (error) {
667
- console.error("Failed to initialize Pyodide:", error);
668
- } finally {
669
- this.pyConnecting = false;
670
- }
671
- }
672
738
  addCell(index, cellType = "code") {
673
739
  if (!this.notebook) return;
674
740
  this.saveEditorContents();
@@ -759,9 +825,10 @@ except ImportError:
759
825
  const minHeight = 100;
760
826
  const calculatedHeight = Math.max(minHeight, lineCount * lineHeight + padding);
761
827
  container.style.height = `${calculatedHeight}px`;
828
+ const language = this.kernel?.language ?? "javascript";
762
829
  const editor = monaco.editor.create(container, {
763
830
  value: source,
764
- language: "python",
831
+ language,
765
832
  theme: this.getMonacoTheme(),
766
833
  minimap: { enabled: false },
767
834
  scrollBeyondLastLine: false,
@@ -819,18 +886,14 @@ except ImportError:
819
886
  return "vs-dark";
820
887
  }
821
888
  openPackageManager() {
822
- const packages = this.notebook?.metadata?.required_packages || [];
823
- pythonPackageManagerService.showPackageManager({
824
- packages,
825
- pyenv: this.pyenv,
889
+ if (!this.kernel?.openPackageManager) return;
890
+ const packages = this.notebook?.metadata?.required_packages ?? [];
891
+ this.kernel.openPackageManager({
892
+ requiredPackages: packages,
826
893
  onPackageAdded: (packageName) => {
827
894
  if (!this.notebook) return;
828
- if (!this.notebook.metadata) {
829
- this.notebook.metadata = {};
830
- }
831
- if (!this.notebook.metadata.required_packages) {
832
- this.notebook.metadata.required_packages = [];
833
- }
895
+ if (!this.notebook.metadata) this.notebook.metadata = {};
896
+ if (!this.notebook.metadata.required_packages) this.notebook.metadata.required_packages = [];
834
897
  if (!this.notebook.metadata.required_packages.includes(packageName)) {
835
898
  this.notebook.metadata.required_packages.push(packageName);
836
899
  this.markDirty(true);
@@ -848,7 +911,7 @@ except ImportError:
848
911
  }
849
912
  updated(changedProperties) {
850
913
  super.updated(changedProperties);
851
- if (changedProperties.has("pyConnected") || changedProperties.has("pyConnecting") || changedProperties.has("pyVersion") || changedProperties.has("isRunningAll")) {
914
+ if (changedProperties.has("kernelConnected") || changedProperties.has("kernelConnecting") || changedProperties.has("kernelVersion") || changedProperties.has("isRunningAll") || changedProperties.has("availableKernels") || changedProperties.has("selectedKernelId")) {
852
915
  this.updateToolbar();
853
916
  }
854
917
  if (this.notebook?.cells) {
@@ -886,15 +949,8 @@ LyraNotebookEditor.styles = css`
886
949
  width: 100%;
887
950
  }
888
951
 
889
- .python-status {
890
- display: flex;
891
- align-items: center;
892
- gap: 0.5rem;
893
- }
894
-
895
- .python-version {
896
- font-size: 0.9rem;
897
- opacity: 0.8;
952
+ .kernel-select {
953
+ max-width: 10rem;
898
954
  }
899
955
 
900
956
  .noteboocells {
@@ -1127,16 +1183,22 @@ __decorateClass([
1127
1183
  ], LyraNotebookEditor.prototype, "executingCells", 2);
1128
1184
  __decorateClass([
1129
1185
  state()
1130
- ], LyraNotebookEditor.prototype, "pyenv", 2);
1186
+ ], LyraNotebookEditor.prototype, "availableKernels", 2);
1187
+ __decorateClass([
1188
+ state()
1189
+ ], LyraNotebookEditor.prototype, "selectedKernelId", 2);
1190
+ __decorateClass([
1191
+ state()
1192
+ ], LyraNotebookEditor.prototype, "kernel", 2);
1131
1193
  __decorateClass([
1132
1194
  state()
1133
- ], LyraNotebookEditor.prototype, "pyConnected", 2);
1195
+ ], LyraNotebookEditor.prototype, "kernelConnected", 2);
1134
1196
  __decorateClass([
1135
1197
  state()
1136
- ], LyraNotebookEditor.prototype, "pyConnecting", 2);
1198
+ ], LyraNotebookEditor.prototype, "kernelConnecting", 2);
1137
1199
  __decorateClass([
1138
1200
  state()
1139
- ], LyraNotebookEditor.prototype, "pyVersion", 2);
1201
+ ], LyraNotebookEditor.prototype, "kernelVersion", 2);
1140
1202
  __decorateClass([
1141
1203
  state()
1142
1204
  ], LyraNotebookEditor.prototype, "editingMarkdownCells", 2);
@@ -1155,4 +1217,4 @@ LyraNotebookEditor = __decorateClass([
1155
1217
  export {
1156
1218
  LyraNotebookEditor
1157
1219
  };
1158
- //# sourceMappingURL=notebook-runtime-yB3_aIh0.js.map
1220
+ //# sourceMappingURL=notebook-runtime-DFffRmNN.js.map