You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@texera.apache.org by gi...@apache.org on 2026/07/05 09:13:08 UTC

(texera) branch main updated: chore(frontend): upgrade frontend to monaco-languageclient v10 (#4997)

This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git


The following commit(s) were added to refs/heads/main by this push:
     new 3d4301f448 chore(frontend): upgrade frontend to monaco-languageclient v10 (#4997)
3d4301f448 is described below

commit 3d4301f4486699ac2a3484cf887e62fbcfc803a9
Author: Xinyuan Lin <xi...@uci.edu>
AuthorDate: Sun Jul 5 02:02:45 2026 -0700

    chore(frontend): upgrade frontend to monaco-languageclient v10 (#4997)
    
    ### What changes were proposed in this PR?
    
    Brings the frontend's Monaco / VS Code language-client stack up to
    `monaco-languageclient` v10 (from v8.8.3) and the matching
    `@codingame/monaco-vscode-*` v25.1.2 ecosystem. v10 split the old
    single-wrapper API into three composable pieces
    (`MonacoVscodeApiWrapper` + `EditorApp` + `LanguageClientWrapper`), so
    the editor component is rewritten and the build/test pipeline picks up
    the codingame v25 quirks the new packages introduce. Adjacent dep
    cleanups land here too — several codingame side-deps and the R UDF
    editor become superfluous once v10 is in place.
    
    #### API shape: v8 → v10
    
    ```
    v8 (before)                                      v10 (after)
    ─────────────────                                ──────────────────────────────────
    new MonacoEditorLanguageClientWrapper(           const api  = new MonacoVscodeApiWrapper(...)
      // single config with editor + LSP + workers   const app  = new EditorApp(...)
      // all in one bag                              const lc   = new LanguageClientWrapper(...)
    ).start(htmlContainer)                           await api.start();         // global vscode-api init
                                                     await app.start(container);// mount editor
                                                     await lc.start();          // open WebSocket to LS
    ```
    
    The editor component is rewritten against the new shape, plus a
    `whenReady()` handshake on the default language extensions and a
    post-mount `forceTokenization` loop to fix a TextMate first-paint race
    that otherwise renders every token as the default `mtk1` class.
    
    #### Worker bundling: why three trampolines
    
    `new Worker(new URL("./relative", import.meta.url))` is the only shape
    webpack 5 treats as a worker entry point AND that esbuild can resolve at
    spec pre-bundle time. Inlining `new URL("@codingame/...",
    import.meta.url)` makes webpack happy but esbuild treats the spec as a
    literal relative URL and the spec pre-bundle fails. A
    `fileReplacements`-swapped factory file works but adds an `angular.json`
    delta. Three thin re-export trampolines satisfy both bundlers with zero
    `angular.json` change.
    
    #### What gets dropped
    
    - `@codingame/monaco-vscode-textmate-service-override` — now a
    transitive of the v25 wrapper; not needed at top level
    - `@codingame/monaco-vscode-theme-defaults-default-extension` — same;
    pulled in transitively by the language extensions
    - `@codingame/monaco-vscode-r-default-extension` — upstream stopped
    publishing; R UDF editor retired
    - `vscode` (package alias + `resolutions`) — v10 no longer needs the
    alias for type-only `vscode.Uri` references
    - `webpack-bundle-analyzer` + `analyze` script — dead; script never ran
    in CI
    - `content-disposition` + `@types/content-disposition` — dead `require`,
    never read
    
    ### Any related issues, documentation, discussions?
    
    Closes #4996.
    
    ### How was this PR tested?
    
    - `yarn install` resolves cleanly
    - `yarn build` exits 0; worker chunks identical hashes/sizes (~1.3 MB
    textmate, ~518 KB ext-host, ~220 KB editor)
    - `yarn test` stays at 63 / 269 spec parity
    
    Manual smoke-test plan:
    - [ ] Open a workflow with a Python UDF — confirm syntax highlighting
    renders correctly on first open
    - [ ] Set / clear / step through a breakpoint with the debugger panel
    - [ ] Verify the AI-assistant "Add Type Annotation" / "Add All Type
    Annotations" actions still work
    - [ ] Check that two browser tabs editing the same workflow show each
    other's coeditor cursors
    - [ ] Run a Java UDF and confirm the editor shows Java syntax (no LSP,
    just grammar)
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Code (Opus 4.7)
    
    ---------
    
    Co-authored-by: Yicong Huang <17...@users.noreply.github.com>
    Co-authored-by: Claude Fable 5 <no...@anthropic.com>
---
 frontend/LICENSE-binary                            |  61 +-
 frontend/custom-webpack.config.js                  |  72 ++-
 frontend/package.json                              |  14 +-
 .../code-editor-dialog/code-debugger.component.ts  |   3 -
 .../code-editor.component.browser.spec.ts          | 109 +++-
 .../code-editor.component.spec.ts                  |  14 +-
 .../code-editor-dialog/code-editor.component.ts    | 334 ++++++----
 .../code-editor-dialog/workers/editor.worker.ts    |  24 +
 .../workers/extension-host.worker.ts               |  21 +
 .../code-editor-dialog/workers/textmate.worker.ts  |  21 +
 frontend/src/jsdom-svg-polyfill.ts                 | 337 +++++-----
 frontend/src/tsconfig.app.json                     |   7 +-
 frontend/vitest.config.ts                          |  11 -
 frontend/yarn.lock                                 | 676 ++++++++++++---------
 14 files changed, 1049 insertions(+), 655 deletions(-)

diff --git a/frontend/LICENSE-binary b/frontend/LICENSE-binary
index 27ec9a61df..aab1349ea8 100644
--- a/frontend/LICENSE-binary
+++ b/frontend/LICENSE-binary
@@ -211,6 +211,7 @@ Dependencies under the Apache License, Version 2.0
 --------------------------------------------------------------------------------
 
 Angular / npm packages:
+  - dompurify@3.3.1
   - fuse.js@6.5.3
   - jschardet@3.1.3
   - rxjs@7.8.1
@@ -247,30 +248,40 @@ Angular / npm packages:
   - @ant-design/icons-angular@21.0.0
   - @auth0/angular-jwt@5.1.0
   - @babel/runtime@7.29.2
-  - @codingame/monaco-vscode-api@8.0.4
-  - @codingame/monaco-vscode-base-service-override@8.0.4
-  - @codingame/monaco-vscode-configuration-service-override@8.0.4
-  - @codingame/monaco-vscode-editor-api@8.0.4
-  - @codingame/monaco-vscode-environment-service-override@8.0.4
-  - @codingame/monaco-vscode-extensions-service-override@8.0.4
-  - @codingame/monaco-vscode-files-service-override@8.0.4
-  - @codingame/monaco-vscode-host-service-override@8.0.4
-  - @codingame/monaco-vscode-java-default-extension@8.0.4
-  - @codingame/monaco-vscode-languages-service-override@8.0.4
-  - @codingame/monaco-vscode-layout-service-override@8.0.4
-  - @codingame/monaco-vscode-model-service-override@8.0.4
-  - @codingame/monaco-vscode-monarch-service-override@8.0.4
-  - @codingame/monaco-vscode-python-default-extension@8.0.4
-  - @codingame/monaco-vscode-quickaccess-service-override@8.0.4
-  - @codingame/monaco-vscode-r-default-extension@8.0.4
-  - @codingame/monaco-vscode-textmate-service-override@8.0.4
-  - @codingame/monaco-vscode-theme-defaults-default-extension@8.0.4
-  - @codingame/monaco-vscode-theme-service-override@8.0.4
+  - @codingame/monaco-vscode-api@25.1.2
+  - @codingame/monaco-vscode-base-service-override@25.1.2
+  - @codingame/monaco-vscode-bulk-edit-service-override@25.1.2
+  - @codingame/monaco-vscode-configuration-service-override@25.1.2
+  - @codingame/monaco-vscode-editor-api@25.1.2
+  - @codingame/monaco-vscode-editor-service-override@25.1.2
+  - @codingame/monaco-vscode-environment-service-override@25.1.2
+  - @codingame/monaco-vscode-extension-api@25.1.2
+  - @codingame/monaco-vscode-extensions-service-override@25.1.2
+  - @codingame/monaco-vscode-files-service-override@25.1.2
+  - @codingame/monaco-vscode-host-service-override@25.1.2
+  - @codingame/monaco-vscode-java-default-extension@25.1.2
+  - @codingame/monaco-vscode-keybindings-service-override@25.1.2
+  - @codingame/monaco-vscode-languages-service-override@25.1.2
+  - @codingame/monaco-vscode-layout-service-override@25.1.2
+  - @codingame/monaco-vscode-log-service-override@25.1.2
+  - @codingame/monaco-vscode-model-service-override@25.1.2
+  - @codingame/monaco-vscode-monarch-service-override@25.1.2
+  - @codingame/monaco-vscode-python-default-extension@25.1.2
+  - @codingame/monaco-vscode-quickaccess-service-override@25.1.2
+  - @codingame/monaco-vscode-textmate-service-override@25.1.2
+  - @codingame/monaco-vscode-theme-defaults-default-extension@25.1.2
+  - @codingame/monaco-vscode-theme-service-override@25.1.2
+  - @codingame/monaco-vscode-view-banner-service-override@25.1.2
+  - @codingame/monaco-vscode-view-common-service-override@25.1.2
+  - @codingame/monaco-vscode-view-status-bar-service-override@25.1.2
+  - @codingame/monaco-vscode-view-title-bar-service-override@25.1.2
+  - @codingame/monaco-vscode-views-service-override@25.1.2
+  - @codingame/monaco-vscode-workbench-service-override@25.1.2
   - @ctrl/tinycolor@3.6.1
   - @ngneat/until-destroy@8.1.4
   - @ngx-formly/core@6.3.12
   - @ngx-formly/ng-zorro-antd@6.3.12
-  - @vscode/iconv-lite-umd@0.7.0
+  - @vscode/iconv-lite-umd@0.7.1
   - ajv@8.10.0
   - backbone@1.4.1
   - balanced-match@1.0.2
@@ -290,11 +301,10 @@ Angular / npm packages:
   - lib0@0.2.117
   - lodash@4.18.1
   - lodash-es@4.18.1
-  - marked@17.0.1
+  - marked@14.0.0
   - mobx@4.14.1
   - monaco-breakpoints@0.2.0
-  - monaco-editor-wrapper@5.5.3
-  - monaco-languageclient@8.8.3
+  - monaco-languageclient@10.7.0
   - ng-zorro-antd@21.3.1
   - ngx-color-picker@12.0.1
   - ngx-file-drop@16.0.0
@@ -305,7 +315,6 @@ Angular / npm packages:
   - point-in-polygon@1.1.0
   - python@1.0.0
   - quill-cursors@3.1.2
-  - r@1.0.0
   - rbush@4.0.1
   - read-excel-file@5.7.1
   - ring-buffer-ts@1.0.3
@@ -317,9 +326,7 @@ Angular / npm packages:
   - vscode-languageclient@9.0.1
   - vscode-languageserver-protocol@3.17.5
   - vscode-languageserver-types@3.17.5
-  - vscode-oniguruma@1.7.0
-  - vscode-textmate@9.0.0
-  - vscode-ws-jsonrpc@3.3.2
+  - vscode-ws-jsonrpc@3.5.0
   - y-monaco@0.1.5
   - y-protocols@1.0.7
   - y-quill@0.1.5
diff --git a/frontend/custom-webpack.config.js b/frontend/custom-webpack.config.js
index 47a804cf43..e39a43e1f1 100644
--- a/frontend/custom-webpack.config.js
+++ b/frontend/custom-webpack.config.js
@@ -17,46 +17,92 @@
  * under the License.
  */
 
+const path = require("path");
 const { LicenseWebpackPlugin } = require("license-webpack-plugin");
 
+const nodeModule = (...segments) => path.resolve(__dirname, "node_modules", ...segments);
+const codingameCssRe = /node_modules[\\/](?:@codingame[\\/]monaco-vscode-[^\\/]+|monaco-editor|vscode)[\\/].*\.css$/;
+
 module.exports = {
   module: {
     rules: [
+      {
+        // codingame monaco-vscode-* ships raw assets (svg/ttf/png/woff*) that
+        // webpack must emit as static files rather than try to parse as JS.
+        test: /\.(svg|ttf|woff2?|png|jpg|jpeg|gif)$/,
+        include: [nodeModule("@codingame")],
+        type: "asset/resource",
+      },
       {
         test: /\.css$/,
-        use: ["style-loader", "css-loader"],
-        include: [
-          require("path").resolve(__dirname, "node_modules/monaco-editor"),
-          require("path").resolve(__dirname, "node_modules/monaco-breakpoints")
+        oneOf: [
+          {
+            // codingame monaco-vscode-* CSS ships as Constructable Stylesheet
+            // imports — must skip style-loader and use css-loader's
+            // `exportType: 'css-style-sheet'`.
+            // https://github.com/CodinGame/monaco-vscode-api/wiki/Troubleshooting
+            test: codingameCssRe,
+            use: [
+              {
+                loader: "css-loader",
+                options: { esModule: false, exportType: "css-style-sheet", url: true, import: true },
+              },
+            ],
+          },
+          {
+            // monaco-breakpoints ships a plain stylesheet that needs
+            // style-loader so it injects at runtime.
+            include: [nodeModule("monaco-breakpoints")],
+            use: ["style-loader", "css-loader"],
+          },
         ],
       },
     ],
-    // Enable URL handling in webpack's JavaScript parser, required for loading .wasm files.
+    // Angular's webpack config disables both `new URL(...)` asset modules
+    // (url: false) and `new Worker(new URL(...))` handling (worker: false
+    // unless webWorkerTsConfig is set). monaco-vscode-api needs both: the
+    // textmate service fetches onig.wasm via `new URL(..., import.meta.url)`,
+    // and the editor/textmate/extension-host workers are spawned the same way.
+    // Without this, webpack inlines `import.meta.url` as a build-machine
+    // file:// path and everything 404s at runtime (no syntax highlighting).
     // See https://github.com/angular/angular-cli/issues/24617
     parser: {
       javascript: {
         url: true,
+        worker: true,
       },
     },
   },
+  resolve: {
+    // css-loader emits relative imports (e.g. '../../../../../../../css-loader/
+    // dist/runtime/api.js') computed from the source CSS location. The codingame
+    // monaco-vscode-* packages live one namespace level deeper (under
+    // `node_modules/@codingame/...`) than css-loader assumes, so the emitted
+    // path lands at `node_modules/@codingame/css-loader/...` instead of
+    // `node_modules/css-loader/...`. Alias the missing leg back to the real
+    // install so webpack can resolve the runtime files.
+    alias: {
+      [nodeModule("@codingame/css-loader")]: nodeModule("css-loader"),
+      [nodeModule("@codingame/style-loader")]: nodeModule("style-loader"),
+    },
+  },
   plugins: [
     new LicenseWebpackPlugin({
       perChunkOutput: false,
       outputFilename: "3rdpartylicenses.json",
+      // Some codingame monaco-vscode-* sub-modules don't expose a license file
+      // license-webpack-plugin can find; treat that as soft instead of fatal.
+      handleMissingLicenseText: () => null,
       renderLicenses: (modules) =>
         JSON.stringify(
           modules
+            .filter((m) => m.packageJson?.name && m.packageJson?.version)
             .map((m) => ({
-              name: m.packageJson && m.packageJson.name,
-              version: m.packageJson && m.packageJson.version,
+              name: m.packageJson.name,
+              version: m.packageJson.version,
               license: m.licenseId,
             }))
-            .filter((e) => e.name && e.version)
-            .sort((a, b) =>
-              a.name === b.name
-                ? a.version.localeCompare(b.version)
-                : a.name.localeCompare(b.name),
-            ),
+            .sort((a, b) => a.name.localeCompare(b.name) || a.version.localeCompare(b.version)),
           null,
           2,
         ),
diff --git a/frontend/package.json b/frontend/package.json
index 418b166ee8..889e7e2c72 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -34,9 +34,8 @@
     "@angular/platform-browser-dynamic": "21.2.10",
     "@angular/router": "21.2.10",
     "@auth0/angular-jwt": "5.1.0",
-    "@codingame/monaco-vscode-java-default-extension": "8.0.4",
-    "@codingame/monaco-vscode-python-default-extension": "8.0.4",
-    "@codingame/monaco-vscode-r-default-extension": "8.0.4",
+    "@codingame/monaco-vscode-java-default-extension": "25.1.2",
+    "@codingame/monaco-vscode-python-default-extension": "25.1.2",
     "@lezer/python": "1.1.18",
     "@ngneat/until-destroy": "8.1.4",
     "@ngx-formly/core": "6.3.12",
@@ -54,9 +53,8 @@
     "lodash-es": "4.18.1",
     "marked": "17.0.1",
     "monaco-breakpoints": "0.2.0",
-    "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@8.0.4",
-    "monaco-editor-wrapper": "5.5.3",
-    "monaco-languageclient": "8.8.3",
+    "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@25.1.2",
+    "monaco-languageclient": "10.7.0",
     "ng-zorro-antd": "21.3.1",
     "ngx-color-picker": "12.0.1",
     "ngx-file-drop": "16.0.0",
@@ -73,7 +71,6 @@
     "tinyqueue": "2.0.3",
     "tslib": "2.3.1",
     "uuid": "14.0.0",
-    "vscode": "npm:@codingame/monaco-vscode-api@8.0.4",
     "y-monaco": "0.1.5",
     "y-protocols": "1.0.5",
     "y-quill": "0.1.5",
@@ -83,8 +80,7 @@
     "zone.js": "0.15.1"
   },
   "resolutions": {
-    "vscode": "npm:@codingame/monaco-vscode-api@8.0.4",
-    "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@8.0.4",
+    "monaco-editor": "npm:@codingame/monaco-vscode-editor-api@25.1.2",
     "webpack": "5.104.1",
     "jschardet": "portal:./tools/jschardet-stub"
   },
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/code-debugger.component.ts b/frontend/src/app/workspace/component/code-editor-dialog/code-debugger.component.ts
index 14384524cf..d46b19f734 100644
--- a/frontend/src/app/workspace/component/code-editor-dialog/code-debugger.component.ts
+++ b/frontend/src/app/workspace/component/code-editor-dialog/code-debugger.component.ts
@@ -20,9 +20,6 @@
 import { AfterViewInit, Component, Input, ViewChild } from "@angular/core";
 import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";
 import { SafeStyle } from "@angular/platform-browser";
-import "@codingame/monaco-vscode-python-default-extension";
-import "@codingame/monaco-vscode-r-default-extension";
-import "@codingame/monaco-vscode-java-default-extension";
 import { isDefined } from "../../../common/util/predicate";
 import * as monaco from "monaco-editor";
 import { MonacoBreakpoint } from "monaco-breakpoints";
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.browser.spec.ts b/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.browser.spec.ts
index d6a3266fd1..677dd54c1f 100644
--- a/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.browser.spec.ts
+++ b/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.browser.spec.ts
@@ -21,11 +21,13 @@
 // spec covers the constructor, language detection, getFileSuffixByLanguage,
 // onFocus, getCoeditorCursorStyles, and the accept/reject annotation paths,
 // but cannot reach anything gated on a real Monaco editor — the
-// `initAndStart` subscribe body, `initializeDiffEditor`, AI-action run
-// callbacks, `handleTypeAnnotation`'s position branch, and the resize
-// handler. This spec drives those by swapping the component's editorWrapper
-// for a fake-with-real-DOM and running in vitest's Playwright/Chromium
-// browser mode, where monaco-editor's codingame fork can be imported without
+// `initializeMonacoEditor` subscribe body, `initializeDiffEditor`, AI-action
+// run callbacks, `handleTypeAnnotation`'s position branch, and the resize
+// handler. This spec drives those by stubbing the v10 editor seams — the
+// global vscode-api init (`ensureVscodeApiStarted`) and the per-editor
+// `EditorApp` — so the subscribe body runs against a fake editor, then running
+// in vitest's Playwright/Chromium browser mode, where monaco-editor's codingame
+// fork can be imported without
 // jsdom's missing-canvas / Node-Buffer-allocation tripwires (the Buffer/process
 // shim is wired as the first setupFile in vitest.browser.config.ts — see
 // src/browser-buffer-polyfill.ts).
@@ -70,6 +72,38 @@ vi.mock("y-monaco", () => ({
   },
 }));
 
+// monaco-languageclient v10 split the old single wrapper into a process-wide
+// `MonacoVscodeApiWrapper` (started once) and a per-editor `EditorApp`. The
+// component `new`s the EditorApp inside its start path, so there is no instance
+// field to swap — intercept the class instead. This recording stand-in captures
+// the `EditorAppConfig` handed to the constructor (the non-diff vs diff branch
+// is the assertion target), records the host element passed to `start()`, and
+// hands back the test's fake editor from `getEditor()`. The global vscode-api
+// init is stubbed separately in `beforeEach`.
+const { editorAppMock } = vi.hoisted(() => ({
+  editorAppMock: {
+    configs: [] as unknown[],
+    start: vi.fn(),
+    getEditor: vi.fn(),
+  },
+}));
+vi.mock("monaco-languageclient/editorApp", () => ({
+  EditorApp: class {
+    constructor(config: unknown) {
+      editorAppMock.configs.push(config);
+    }
+    start(host: unknown) {
+      return editorAppMock.start(host);
+    }
+    getEditor() {
+      return editorAppMock.getEditor();
+    }
+    dispose() {
+      return Promise.resolve();
+    }
+  },
+}));
+
 // Re-use the augmented stub from the jsdom spec so the component constructor
 // can resolve its highlighted operator regardless of operatorType.
 const baseSchema = mockOperatorMetaData.operators.find(op => op.operatorType === "PythonUDF");
@@ -134,14 +168,6 @@ function makeFakeEditor(): FakeEditor {
   };
 }
 
-function makeFakeWrapper(editor: FakeEditor) {
-  return {
-    initAndStart: vi.fn().mockResolvedValue(undefined),
-    getEditor: vi.fn(() => editor),
-    dispose: vi.fn(),
-  };
-}
-
 describe("CodeEditorComponent (browser)", () => {
   let displayVersionStream$: BehaviorSubject<boolean>;
   let aiEnabled$: BehaviorSubject<string>;
@@ -151,6 +177,15 @@ describe("CodeEditorComponent (browser)", () => {
 
   beforeEach(async () => {
     monacoBindingCalls.length = 0;
+    editorAppMock.configs.length = 0;
+    editorAppMock.start.mockReset().mockResolvedValue(undefined);
+    editorAppMock.getEditor.mockReset();
+    // The global vscode-api wrapper's start() spins up codingame workers and
+    // pulls the default language extensions over dynamic import — neither is
+    // needed here. Stub the lazy initializer so the editor start path resolves
+    // straight through to the EditorApp seam above.
+    vi.spyOn(CodeEditorComponent as any, "ensureVscodeApiStarted").mockResolvedValue(undefined);
+
     displayVersionStream$ = new BehaviorSubject<boolean>(false);
     aiEnabled$ = new BehaviorSubject<string>("OpenAI");
     getTypeAnnotationsSpy = vi.fn().mockReturnValue(of({ choices: [{ message: { content: ": int" } }] }));
@@ -182,10 +217,16 @@ describe("CodeEditorComponent (browser)", () => {
     workflowActionService = TestBed.inject(WorkflowActionService);
   });
 
+  afterEach(() => {
+    // Restore the `ensureVscodeApiStarted` spy so the next test re-stubs from a
+    // clean slate (vitest is not configured to auto-restore mocks).
+    vi.restoreAllMocks();
+  });
+
   // Builds a fixture for the highlighted operator, but defers the
-  // detectChanges/ngAfterViewInit step so the caller can swap in the fake
-  // editor wrapper and stage `code` / `formControl` before the subscribe body
-  // fires. Returns the fixture, the fake wrapper, and the fake editor.
+  // detectChanges/ngAfterViewInit step so the caller can stage `code` /
+  // `formControl` (and the EditorApp's fake editor) before the subscribe body
+  // fires. Returns the fixture, the fake editor, and the component instance.
   function makeFixtureWithFakes() {
     const predicate = { ...mockJavaUDFPredicate };
     workflowActionService.addOperator(predicate, mockPoint);
@@ -193,18 +234,20 @@ describe("CodeEditorComponent (browser)", () => {
 
     const fixture = TestBed.createComponent(CodeEditorComponent);
     const editor = makeFakeEditor();
-    const wrapper = makeFakeWrapper(editor);
+    // The component pulls the editor back out of `EditorApp.getEditor()` inside
+    // its start path (and again from `adjustEditorSize`), so the mocked
+    // EditorApp must hand back this same fake.
+    editorAppMock.getEditor.mockReturnValue(editor);
     const c = fixture.componentInstance as any;
-    c.editorWrapper = wrapper;
     c.formControl = new FormControl({ value: "", disabled: false });
     // A YText must live inside a Y.Doc to be useful; the binding stub doesn't
     // care, but we stage it as if it came from the shared model so the
     // subscribe body crosses the `if (!this.code) return;` gate.
     c.code = new Y.Doc().getText("code");
-    return { fixture, wrapper, editor, c: c as CodeEditorComponent };
+    return { fixture, editor, c: c as CodeEditorComponent };
   }
 
-  // The component's subscribe path runs `from(initAndStart(...)).pipe(...)`,
+  // The component's subscribe path runs `from(startEditor()).pipe(...)`,
   // which is microtask-async. One macrotask flush after detectChanges is
   // enough for the RxJS chain to deliver the editor into the subscribe body.
   async function flush(): Promise<void> {
@@ -213,16 +256,19 @@ describe("CodeEditorComponent (browser)", () => {
   }
 
   it("initializeMonacoEditor: wires the editor + MonacoBinding + AI actions when code exists", async () => {
-    const { fixture, wrapper, editor } = makeFixtureWithFakes();
+    const { fixture, editor } = makeFixtureWithFakes();
 
     fixture.detectChanges();
     await flush();
 
-    // The non-diff config branch should fire with the editor host element.
-    expect(wrapper.initAndStart).toHaveBeenCalledOnce();
-    const [userConfig, host] = wrapper.initAndStart.mock.calls[0];
-    expect((userConfig as any).wrapperConfig.editorAppConfig.useDiffEditor).toBeUndefined();
-    expect((userConfig as any).wrapperConfig.editorAppConfig.codeResources.main.uri).toMatch(/^in-memory-.*\.\.java$/);
+    // The non-diff branch should construct exactly one EditorApp and start it
+    // against the editor host element.
+    expect(editorAppMock.start).toHaveBeenCalledOnce();
+    expect(editorAppMock.configs).toHaveLength(1);
+    const config = editorAppMock.configs[0] as any;
+    const host = editorAppMock.start.mock.calls[0][0];
+    expect(config.useDiffEditor).toBeUndefined();
+    expect(config.codeResources.modified.uri).toMatch(/^in-memory-.*\.java$/);
     expect(host).toBeInstanceOf(HTMLElement);
 
     // The subscribe body should: push readOnly via updateOptions, construct
@@ -243,7 +289,7 @@ describe("CodeEditorComponent (browser)", () => {
   });
 
   it("initializeDiffEditor: when displayParticularVersion is true, runs the diff config path", async () => {
-    const { fixture, wrapper } = makeFixtureWithFakes();
+    const { fixture } = makeFixtureWithFakes();
     // Seed the stream BEFORE detectChanges so the subscribe in ngAfterViewInit
     // picks `true` on first emission and takes the diff branch.
     displayVersionStream$.next(true);
@@ -251,11 +297,12 @@ describe("CodeEditorComponent (browser)", () => {
     fixture.detectChanges();
     await flush();
 
-    expect(wrapper.initAndStart).toHaveBeenCalledOnce();
-    const [userConfig] = wrapper.initAndStart.mock.calls[0];
-    expect((userConfig as any).wrapperConfig.editorAppConfig.useDiffEditor).toBe(true);
+    expect(editorAppMock.start).toHaveBeenCalledOnce();
+    expect(editorAppMock.configs).toHaveLength(1);
+    const config = editorAppMock.configs[0] as any;
+    expect(config.useDiffEditor).toBe(true);
     // `original` is the previous-version source, only set on the diff path.
-    expect((userConfig as any).wrapperConfig.editorAppConfig.codeResources.original).toBeDefined();
+    expect(config.codeResources.original).toBeDefined();
   });
 
   it("setupAIAssistantActions: registers only the 'all' action when the gate is not OpenAI", async () => {
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.spec.ts b/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.spec.ts
index 0f37f851aa..c262036e87 100644
--- a/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.spec.ts
+++ b/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.spec.ts
@@ -271,16 +271,16 @@ describe("CodeEditorComponent", () => {
       const fixture = makeFixture(mockJavaUDFPredicate);
       const c = fixture.componentInstance;
 
-      // The accept path reaches into the underlying MonacoEditorLanguageClientWrapper
-      // for `.getEditor()` and into the YText `.code` for `.insert()`. Both are
-      // private so we stub them through bracket access to a minimum that lets
-      // insertTypeAnnotations no-op cleanly. `dispose` is needed because
-      // ngOnDestroy fires at teardown and calls it.
-      (c as any).editorWrapper = {
+      // The accept path reaches into the underlying EditorApp for `.getEditor()`
+      // and into the YText `.code` for `.insert()`. Both are private so we stub
+      // them through bracket access to a minimum that lets insertTypeAnnotations
+      // no-op cleanly. `dispose` is needed because ngOnDestroy fires at teardown
+      // and calls it.
+      (c as any).editorApp = {
         getEditor: () => ({
           getModel: () => ({ getOffsetAt: () => 0 }),
         }),
-        dispose: vi.fn(),
+        dispose: vi.fn().mockResolvedValue(undefined),
       };
       (c as any).code = { insert: vi.fn() };
 
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.ts b/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.ts
index 5f934fe6e0..5dd1a6791f 100644
--- a/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.ts
+++ b/frontend/src/app/workspace/component/code-editor-dialog/code-editor.component.ts
@@ -33,7 +33,7 @@ import { WorkflowVersionService } from "../../../dashboard/service/user/workflow
 import type { Text as YText } from "yjs";
 import { getWebsocketUrl } from "src/app/common/util/url";
 import { MonacoBinding } from "y-monaco";
-import { catchError, from, of, Subject, take, timeout } from "rxjs";
+import { from, Subject, take } from "rxjs";
 import { CoeditorPresenceService } from "../../service/workflow-graph/model/coeditor-presence.service";
 import { DomSanitizer, SafeStyle } from "@angular/platform-browser";
 import { Coeditor } from "../../../common/type/user";
@@ -41,13 +41,16 @@ import { YType } from "../../types/shared-editing.interface";
 import { FormControl } from "@angular/forms";
 import { AIAssistantService, TypeAnnotationResponse } from "../../service/ai-assistant/ai-assistant.service";
 import { AnnotationSuggestionComponent } from "./annotation-suggestion.component";
-import { MonacoEditorLanguageClientWrapper, UserConfig } from "monaco-editor-wrapper";
 import * as monaco from "monaco-editor";
-import "@codingame/monaco-vscode-python-default-extension";
-import "@codingame/monaco-vscode-r-default-extension";
-import "@codingame/monaco-vscode-java-default-extension";
+import {
+  MonacoVscodeApiWrapper,
+  type MonacoVscodeApiConfig,
+  getEnhancedMonacoEnvironment,
+} from "monaco-languageclient/vscodeApiWrapper";
+import { LanguageClientWrapper, type LanguageClientConfig } from "monaco-languageclient/lcwrapper";
+import { EditorApp, type EditorAppConfig } from "monaco-languageclient/editorApp";
 import { isDefined } from "../../../common/util/predicate";
-import { filter, switchMap } from "rxjs/operators";
+import { filter } from "rxjs/operators";
 import { BreakpointConditionInputComponent } from "./breakpoint-condition-input/breakpoint-condition-input.component";
 import { CodeDebuggerComponent } from "./code-debugger.component";
 import { GuiConfigService } from "src/app/common/service/gui-config.service";
@@ -103,7 +106,9 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
   public language: string = "";
   public languageTitle: string = "";
 
-  private editorWrapper: MonacoEditorLanguageClientWrapper = new MonacoEditorLanguageClientWrapper();
+  private static apiWrapperStartPromise?: Promise<void>;
+  private editorApp?: EditorApp;
+  private languageClientWrapper?: LanguageClientWrapper;
   private monacoBinding?: MonacoBinding;
 
   // Boolean to determine whether the suggestion UI should be shown
@@ -122,14 +127,16 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
   public codeDebuggerComponent!: Type<any> | null;
   public editorToPass!: MonacoEditor;
 
-  private generateLanguageTitle(language: string): string {
-    return `${language.charAt(0).toUpperCase()}${language.slice(1)} UDF`;
-  }
-
-  setLanguage(newLanguage: string) {
-    this.language = newLanguage;
-    this.languageTitle = this.generateLanguageTitle(newLanguage);
-  }
+  // Operator-type → editor language. The R types are kept on the frontend
+  // even though Texera's R UDF backend now ships as a separate plugin —
+  // when that plugin is installed, the workflow may still surface `RUDF` /
+  // `RUDFSource` operators and the editor needs to open them in R mode.
+  private static readonly PYTHON_OPERATOR_TYPES: ReadonlySet<string> = new Set([
+    "PythonUDFV2",
+    "PythonUDFSourceV2",
+    "DualInputPortsPythonUDFV2",
+  ]);
+  private static readonly R_OPERATOR_TYPES: ReadonlySet<string> = new Set(["RUDFSource", "RUDF"]);
 
   constructor(
     private sanitizer: DomSanitizer,
@@ -141,18 +148,14 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
   ) {
     this.currentOperatorId = this.workflowActionService.getJointGraphWrapper().getCurrentHighlightedOperatorIDs()[0];
     const operatorType = this.workflowActionService.getTexeraGraph().getOperator(this.currentOperatorId).operatorType;
-
-    if (operatorType === "RUDFSource" || operatorType === "RUDF") {
-      this.setLanguage("r");
-    } else if (
-      operatorType === "PythonUDFV2" ||
-      operatorType === "PythonUDFSourceV2" ||
-      operatorType === "DualInputPortsPythonUDFV2"
-    ) {
-      this.setLanguage("python");
+    if (CodeEditorComponent.PYTHON_OPERATOR_TYPES.has(operatorType)) {
+      this.language = "python";
+    } else if (CodeEditorComponent.R_OPERATOR_TYPES.has(operatorType)) {
+      this.language = "r";
     } else {
-      this.setLanguage("java");
+      this.language = "java";
     }
+    this.languageTitle = `${this.language[0].toUpperCase()}${this.language.slice(1)} UDF`;
     this.workflowActionService.getTexeraGraph().updateSharedModelAwareness("editingCode", true);
     this.title = this.workflowActionService.getTexeraGraph().getOperator(this.currentOperatorId).customDisplayName;
     this.code = (
@@ -185,30 +188,113 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
     this.workflowActionService.getTexeraGraph().updateSharedModelAwareness("editingCode", false);
     localStorage.setItem(this.currentOperatorId, this.containerElement.nativeElement.style.cssText);
 
-    if (isDefined(this.monacoBinding)) {
-      this.monacoBinding.destroy();
-    }
-
-    this.editorWrapper.dispose(true);
+    this.monacoBinding?.destroy();
+    this.languageClientWrapper?.dispose().catch(() => {});
+    this.languageClientWrapper = undefined;
+    this.editorApp?.dispose().catch(() => {});
+    this.editorApp = undefined;
 
-    if (isDefined(this.workflowVersionStreamSubject)) {
-      this.workflowVersionStreamSubject.next();
-      this.workflowVersionStreamSubject.complete();
-    }
+    this.workflowVersionStreamSubject.next();
+    this.workflowVersionStreamSubject.complete();
   }
 
   /**
    * Specify the co-editor's cursor style. This step is missing from MonacoBinding.
+   *
+   * `coeditor.clientId` and `coeditor.color` come from yjs awareness state,
+   * which any peer can write to. Both are interpolated into a `<style>` tag
+   * passed through `bypassSecurityTrustHtml`, so anything that escapes the
+   * tag would land in the page as raw HTML. Validate both to a tight
+   * allow-list (digits-only id, hex / `rgb(a)` / `hsl(a)` colour) and bail
+   * out otherwise; nothing else should reach the sanitiser.
    * @param coeditor
    */
   public getCoeditorCursorStyles(coeditor: Coeditor) {
-    const textCSS =
+    if (!CodeEditorComponent.SAFE_CLIENT_ID.test(coeditor.clientId)) {
+      return this.sanitizer.bypassSecurityTrustHtml("");
+    }
+    if (!coeditor.color || !CodeEditorComponent.SAFE_CSS_COLOR.test(coeditor.color)) {
+      return this.sanitizer.bypassSecurityTrustHtml("");
+    }
+    const id = coeditor.clientId;
+    const color = coeditor.color;
+    const selectionBg = color.replace("0.8", "0.5");
+    return this.sanitizer.bypassSecurityTrustHtml(
       "<style>" +
-      `.yRemoteSelection-${coeditor.clientId} { background-color: ${coeditor.color?.replace("0.8", "0.5")}}` +
-      `.yRemoteSelectionHead-${coeditor.clientId}::after { border-color: ${coeditor.color}}` +
-      `.yRemoteSelectionHead-${coeditor.clientId} { border-color: ${coeditor.color}}` +
-      "</style>";
-    return this.sanitizer.bypassSecurityTrustHtml(textCSS);
+        `.yRemoteSelection-${id} { background-color: ${selectionBg}}` +
+        `.yRemoteSelectionHead-${id}::after { border-color: ${color}}` +
+        `.yRemoteSelectionHead-${id} { border-color: ${color}}` +
+        "</style>"
+    );
+  }
+
+  // Allow-lists for the two awareness-derived values that flow into a `<style>`
+  // tag in `getCoeditorCursorStyles`. yjs serialises clientIDs as the decimal
+  // form of a 32-bit integer, and the colours we generate elsewhere only use
+  // these notations — anything outside these patterns is rejected.
+  private static readonly SAFE_CLIENT_ID = /^\d{1,10}$/;
+  private static readonly SAFE_CSS_COLOR = /^(?:#[0-9a-fA-F]{3,8}|rgba?\([\d.,\s]+\)|hsla?\([\d.,%\s]+\))$/;
+
+  /**
+   * Lazily start the global monaco-vscode-api wrapper. The vscode API services are
+   * a process-wide singleton in v10; calling start() twice would throw, so we share
+   * a single Promise across every CodeEditorComponent instance.
+   */
+  private static async ensureVscodeApiStarted(): Promise<void> {
+    CodeEditorComponent.apiWrapperStartPromise ??= (async () => {
+      try {
+        const apiConfig: MonacoVscodeApiConfig = {
+          $type: "extended",
+          viewsConfig: { $type: "EditorService" },
+          userConfiguration: {
+            json: JSON.stringify({ "workbench.colorTheme": "Default Dark Modern" }),
+          },
+          // Wire workers via thin trampolines in `./workers/`. Webpack 5 only
+          // treats `new Worker(new URL("./relative", import.meta.url))` as a
+          // worker entry point and bundles the dep tree into a chunk; bare
+          // package URLs `new URL("@codingame/...", import.meta.url)` become
+          // static assets whose relative imports 404 at runtime. Esbuild
+          // (used by @angular/build:unit-test) also requires a real on-disk
+          // file for the URL spec — trampolines satisfy both bundlers.
+          monacoWorkerFactory: () => {
+            const env = getEnhancedMonacoEnvironment();
+            env.getWorker = (_workerId: string, label: string): Worker => {
+              switch (label) {
+                case "editorWorkerService":
+                  return new Worker(new URL("./workers/editor.worker", import.meta.url), { type: "module" });
+                case "extensionHostWorkerMain":
+                  return new Worker(new URL("./workers/extension-host.worker", import.meta.url), { type: "module" });
+                case "TextMateWorker":
+                  return new Worker(new URL("./workers/textmate.worker", import.meta.url), { type: "module" });
+                default:
+                  throw new Error(`No worker configured for label: ${label}`);
+              }
+            };
+          },
+        };
+        await new MonacoVscodeApiWrapper(apiConfig).start();
+
+        // Load AND fully activate the default language extensions. Each
+        // module exports a `whenReady()` that resolves after its TextMate
+        // grammar / configuration files are registered with the host —
+        // without waiting, the editor opens with every token rendered as
+        // the default `mtk1` class (no syntax colours). Dynamic `import(...)`
+        // is used so the Angular build pipeline doesn't tree-shake the
+        // side-effect imports.
+        const extensions = await Promise.all([
+          import("@codingame/monaco-vscode-python-default-extension"),
+          import("@codingame/monaco-vscode-java-default-extension"),
+        ]);
+        await Promise.all(extensions.map(ext => ext.whenReady?.()));
+      } catch (err) {
+        // Clear the cached promise so a later editor open can retry; without
+        // this the rejected promise would be returned forever and every
+        // subsequent open would fail with the same error.
+        CodeEditorComponent.apiWrapperStartPromise = undefined;
+        throw err;
+      }
+    })();
+    return CodeEditorComponent.apiWrapperStartPromise;
   }
 
   private getFileSuffixByLanguage(language: string): string {
@@ -232,50 +318,59 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
    */
   private initializeMonacoEditor() {
     const fileSuffix = this.getFileSuffixByLanguage(this.language);
-    const userConfig: UserConfig = {
-      wrapperConfig: {
-        editorAppConfig: {
-          $type: "extended",
-          codeResources: {
-            main: {
-              text: this.code?.toString() ?? "",
-              uri: `in-memory-${this.currentOperatorId}.${fileSuffix}`,
-            },
-          },
-          userConfiguration: {
-            json: JSON.stringify({
-              "workbench.colorTheme": "Default Dark Modern",
-            }),
-          },
+    const editorAppConfig: EditorAppConfig = {
+      codeResources: {
+        modified: {
+          text: this.code?.toString() ?? "",
+          uri: `in-memory-${this.currentOperatorId}${fileSuffix}`,
         },
       },
     };
 
-    // optionally, configure python language client.
-    // it may fail if no valid connection is established, yet the failure would be ignored.
     const languageServerWebsocketUrl = getWebsocketUrl(
       "/python-language-server",
       this.config.env.pythonLanguageServerPort
     );
-    if (this.language === "python") {
-      userConfig.languageClientConfig = {
-        languageId: this.language,
-        options: {
-          $type: "WebSocketUrl",
-          url: languageServerWebsocketUrl,
-        },
-      };
-    }
 
-    // init monaco editor, optionally with attempt on language client.
-    from(this.editorWrapper.initAndStart(userConfig, this.editorElement.nativeElement))
-      .pipe(
-        timeout(LANGUAGE_SERVER_CONNECTION_TIMEOUT_MS),
-        switchMap(() => of(this.editorWrapper.getEditor())),
-        catchError(() => of(this.editorWrapper.getEditor())),
-        filter(isDefined),
-        untilDestroyed(this)
-      )
+    const startEditor = async (): Promise<MonacoEditor | undefined> => {
+      await CodeEditorComponent.ensureVscodeApiStarted();
+      this.editorApp = new EditorApp(editorAppConfig);
+      await this.editorApp.start(this.editorElement.nativeElement);
+
+      // Configure the python language client as a best-effort step — a
+      // missing or unreachable language server should not block the editor
+      // from being usable. The timeout / catch is scoped tightly around
+      // `languageClientWrapper.start()` so the editor mount above is always
+      // awaited to completion (codingame v25 first-load init can take
+      // multiple seconds and easily exceed the LSP timeout).
+      if (this.language === "python") {
+        const lcConfig: LanguageClientConfig = {
+          languageId: this.language,
+          connection: {
+            options: { $type: "WebSocketUrl", url: languageServerWebsocketUrl },
+          },
+          clientOptions: { documentSelector: [this.language] },
+        };
+        this.languageClientWrapper = new LanguageClientWrapper(lcConfig);
+        try {
+          await Promise.race([
+            this.languageClientWrapper.start(),
+            new Promise<never>((_, reject) =>
+              setTimeout(
+                () => reject(new Error("Language server connection timed out")),
+                LANGUAGE_SERVER_CONNECTION_TIMEOUT_MS
+              )
+            ),
+          ]);
+        } catch {
+          // Editor stays usable without the LSP.
+        }
+      }
+      return this.editorApp.getEditor();
+    };
+
+    from(startEditor())
+      .pipe(filter(isDefined), untilDestroyed(this))
       .subscribe((editor: MonacoEditor) => {
         editor.updateOptions({ readOnly: this.formControl.disabled });
         if (!this.code) {
@@ -290,6 +385,22 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
           new Set([editor]),
           this.workflowActionService.getTexeraGraph().getSharedModelAwareness()
         );
+        // The TextMate grammar registers asynchronously (the host fetches the
+        // .tmLanguage.json from the codingame extension and spins up a worker).
+        // Even after the editor mounts, the model may have already been painted
+        // with the no-grammar tokens (everything as the default `mtk1` class).
+        // Force a re-tokenize so the syntax colours show up on first paint.
+        const model = editor.getModel();
+        const tokenization = (
+          model as unknown as {
+            tokenization?: { forceTokenization?: (line: number) => void };
+          }
+        )?.tokenization;
+        if (model && tokenization?.forceTokenization) {
+          for (let line = 1; line <= model.getLineCount(); line++) {
+            tokenization.forceTokenization(line);
+          }
+        }
         this.setupAIAssistantActions(editor);
         this.initCodeDebuggerComponent(editor);
       });
@@ -302,34 +413,29 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
       ?.content.operators?.find(({ operatorID }) => operatorID === this.currentOperatorId);
     const latestVersionCode: string = latestVersionOperator?.operatorProperties?.code ?? "";
     const oldVersionCode: string = this.code?.toString() ?? "";
-    const userConfig: UserConfig = {
-      wrapperConfig: {
-        editorAppConfig: {
-          $type: "extended",
-          codeResources: {
-            main: {
-              text: latestVersionCode,
-              uri: `in-memory-${this.currentOperatorId}.${fileSuffix}`,
-            },
-            original: {
-              text: oldVersionCode,
-              uri: `in-memory-${this.currentOperatorId}-version.${fileSuffix}`,
-            },
-          },
-          useDiffEditor: true,
-          diffEditorOptions: {
-            readOnly: true,
-          },
-          userConfiguration: {
-            json: JSON.stringify({
-              "workbench.colorTheme": "Default Dark Modern",
-            }),
-          },
+    const editorAppConfig: EditorAppConfig = {
+      codeResources: {
+        modified: {
+          text: latestVersionCode,
+          uri: `in-memory-${this.currentOperatorId}${fileSuffix}`,
+        },
+        original: {
+          text: oldVersionCode,
+          uri: `in-memory-${this.currentOperatorId}-version${fileSuffix}`,
         },
       },
+      useDiffEditor: true,
+      diffEditorOptions: {
+        readOnly: true,
+      },
     };
 
-    this.editorWrapper.initAndStart(userConfig, this.editorElement.nativeElement);
+    const startDiffEditor = async () => {
+      await CodeEditorComponent.ensureVscodeApiStarted();
+      this.editorApp = new EditorApp(editorAppConfig);
+      await this.editorApp.start(this.editorElement.nativeElement);
+    };
+    from(startDiffEditor()).pipe(untilDestroyed(this)).subscribe();
   }
 
   private initCodeDebuggerComponent(editor: MonacoEditor) {
@@ -503,21 +609,10 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
     if (!this.showAnnotationSuggestion || !this.currentRange || !this.currentSuggestion) {
       return;
     }
-
-    if (this.currentRange && this.currentSuggestion) {
-      const selection = new monaco.Selection(
-        this.currentRange.startLineNumber,
-        this.currentRange.startColumn,
-        this.currentRange.endLineNumber,
-        this.currentRange.endColumn
-      );
-
-      this.insertTypeAnnotations(this.editorWrapper.getEditor()!, selection, this.currentSuggestion);
-
-      // Only for "Add All Type Annotation"
-      if (this.isMultipleVariables && this.userResponseSubject) {
-        this.userResponseSubject.next();
-      }
+    this.insertTypeAnnotations(this.editorApp!.getEditor()!, this.currentRange, this.currentSuggestion);
+    // Only for "Add All Type Annotation"
+    if (this.isMultipleVariables && this.userResponseSubject) {
+      this.userResponseSubject.next();
     }
     // close the UI after adding the annotation
     this.showAnnotationSuggestion = false;
@@ -536,12 +631,9 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
     }
   }
 
-  private insertTypeAnnotations(editor: MonacoEditor, selection: monaco.Selection, annotations: string) {
-    const endLineNumber = selection.endLineNumber;
-    const endColumn = selection.endColumn;
-    const insertPosition = new monaco.Position(endLineNumber, endColumn);
-    const insertOffset = editor.getModel()?.getOffsetAt(insertPosition) || 0;
-    this.code?.insert(insertOffset, annotations);
+  private insertTypeAnnotations(editor: MonacoEditor, range: monaco.Range, annotations: string) {
+    const offset = editor.getModel()?.getOffsetAt(new monaco.Position(range.endLineNumber, range.endColumn)) ?? 0;
+    this.code?.insert(offset, annotations);
   }
 
   @HostListener("window:resize")
@@ -560,7 +652,7 @@ export class CodeEditorComponent implements AfterViewInit, SafeStyle, OnDestroy
     if (rect.bottom > viewportHeight) {
       container.style.height = `${viewportHeight - rect.top}px`;
     }
-    this.editorWrapper.getEditor()?.layout();
+    this.editorApp?.getEditor()?.layout();
   }
   onFocus() {
     this.workflowActionService.getJointGraphWrapper().highlightOperators(this.currentOperatorId);
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/workers/editor.worker.ts b/frontend/src/app/workspace/component/code-editor-dialog/workers/editor.worker.ts
new file mode 100644
index 0000000000..ed2a08a486
--- /dev/null
+++ b/frontend/src/app/workspace/component/code-editor-dialog/workers/editor.worker.ts
@@ -0,0 +1,24 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// Worker trampoline — re-exports the codingame-shipped editor worker so a
+// relative-path `new Worker(new URL(...))` in code-editor.component.ts pulls
+// the dep tree into a webpack worker chunk. See the `monacoWorkerFactory`
+// comment there for the full rationale.
+import "@codingame/monaco-vscode-editor-api/esm/vs/editor/editor.worker.js";
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/workers/extension-host.worker.ts b/frontend/src/app/workspace/component/code-editor-dialog/workers/extension-host.worker.ts
new file mode 100644
index 0000000000..6d66702557
--- /dev/null
+++ b/frontend/src/app/workspace/component/code-editor-dialog/workers/extension-host.worker.ts
@@ -0,0 +1,21 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// See ./editor.worker.ts for why this trampoline exists.
+import "@codingame/monaco-vscode-api/workers/extensionHost.worker";
diff --git a/frontend/src/app/workspace/component/code-editor-dialog/workers/textmate.worker.ts b/frontend/src/app/workspace/component/code-editor-dialog/workers/textmate.worker.ts
new file mode 100644
index 0000000000..796224f901
--- /dev/null
+++ b/frontend/src/app/workspace/component/code-editor-dialog/workers/textmate.worker.ts
@@ -0,0 +1,21 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// See ./editor.worker.ts for why this trampoline exists.
+import "@codingame/monaco-vscode-textmate-service-override/worker";
diff --git a/frontend/src/jsdom-svg-polyfill.ts b/frontend/src/jsdom-svg-polyfill.ts
index 34bccf59ce..4e659d7b6a 100644
--- a/frontend/src/jsdom-svg-polyfill.ts
+++ b/frontend/src/jsdom-svg-polyfill.ts
@@ -17,128 +17,181 @@
  * under the License.
  */
 
-/**
- * jsdom doesn't implement the SVG geometry APIs (`SVGSVGElement#createSVGMatrix`,
- * `createSVGPoint`, `createSVGTransform`, `getScreenCTM`, `getCTM`,
- * `getBBox`). jointjs reaches into these during graph layout and crashes
- * the spec build with `TypeError: svgDocument.createSVGMatrix is not a
- * function` etc.
- *
- * The stubs below return identity-ish geometry: matrices/points behave like
- * the identity, bounding boxes report zero dimensions. That's enough for
- * jointjs construction code to not throw; specs that actually depend on
- * accurate geometry should run under Vitest browser mode rather than
- * jsdom (tracked in #4861), but the bulk of the texera specs only need
- * jointjs to instantiate cleanly.
- */
+// Test-env polyfills loaded via `setupFiles` in `angular.json`. Most of
+// the gaps below were introduced by the monaco-languageclient v10 upgrade,
+// which pulls in `@codingame/monaco-vscode-*` v25 — that stack calls into
+// browser APIs jsdom doesn't ship (Constructable Stylesheets, `CSS.escape`,
+// `matchMedia`, `requestIdleCallback`, …). jointjs's SVG geometry stubs
+// are the only block that predates the upgrade.
+
+// CSS-import shim: the unit-test builder pre-bundles specs with
+// `externalPackages: true`, so transitive `.css` imports from the codingame
+// stack reach Node's native ESM loader and crash with
+// `Unknown file extension ".css"`. Register a hook that resolves any `.css`
+// specifier to a `CSSStyleSheet`-shaped no-op module. Source is inlined as
+// a `data:` URL (no `.mjs` sidecar). Gated by a `globalThis` flag because
+// `setupFiles` re-runs per spec file and `module.register` chains.
+import { register as registerLoader } from "node:module";
+
+const CSS_HOOK_FLAG = Symbol.for("texera.cssLoaderHookRegistered");
+const PROCESS_HANDLERS_FLAG = Symbol.for("texera.processErrorHandlersInstalled");
+const flagHolder = globalThis as Record<symbol, boolean | undefined>;
+if (!flagHolder[CSS_HOOK_FLAG]) {
+  // The hook's default export is a CSSStyleSheet-shaped stub rather than a
+  // bare `{}` — a few transitive consumers (codingame v25's
+  // `css-style-sheet` export form) read `.replaceSync` / `.cssRules` off
+  // the imported value, and a plain empty object would crash them.
+  const stubModule =
+    "const s = { cssRules: [] };" +
+    "s.replaceSync = () => {};" +
+    "s.replace = () => Promise.resolve();" +
+    "s.insertRule = () => 0;" +
+    "s.deleteRule = () => {};" +
+    "export default s;";
+  const stubUrl = `data:text/javascript;charset=utf-8,${encodeURIComponent(stubModule)}`;
+  const cssLoaderHookSource = `
+const STUB_URL = ${JSON.stringify(stubUrl)};
+export function resolve(specifier, context, nextResolve) {
+  if (specifier.endsWith(".css") || /\\.css(\\?|$)/.test(specifier)) {
+    return { url: STUB_URL, shortCircuit: true, format: "module" };
+  }
+  return nextResolve(specifier, context);
+}
+`;
+  registerLoader(`data:text/javascript;charset=utf-8,${encodeURIComponent(cssLoaderHookSource)}`);
+  flagHolder[CSS_HOOK_FLAG] = true;
+}
 
 type AnyFn = (...args: unknown[]) => unknown;
+// Loose `globalThis` accessor — jsdom installs DOM globals here, but TS's
+// `lib.dom.d.ts` types many of them as never-undefined. Cast through `any`
+// so the `?.prototype` short-circuits below stay typed-light.
+const G = globalThis as Record<string, any>;
+const installIfMissing = (proto: Record<string, AnyFn> | undefined, fns: Record<string, AnyFn>) => {
+  if (!proto) return;
+  for (const [name, impl] of Object.entries(fns)) {
+    if (typeof proto[name] !== "function") proto[name] = impl;
+  }
+};
 
-function fakeMatrix() {
-  // Minimal SVGMatrix shape — just the methods jointjs touches.
+// SVG geometry APIs (`SVGSVGElement#createSVGMatrix`, `createSVGPoint`,
+// `createSVGTransform`, `getScreenCTM`, `getCTM`, `getBBox`). jsdom doesn't
+// implement these and jointjs reaches into them during graph layout, so the
+// spec build crashes with `TypeError: svgDocument.createSVGMatrix is not a
+// function`. Stubs return identity-ish geometry — enough for jointjs to
+// instantiate. Specs needing accurate geometry should run under Vitest
+// browser mode rather than jsdom (tracked in #4861).
+// Method names are space-separated to keep the prettier-formatted source on
+// one line each; both stubs only need their named methods to exist as
+// callables, so the contents don't matter beyond returning the right shape.
+const MATRIX_METHODS =
+  "multiply inverse translate scale scaleNonUniform rotate rotateFromVector flipX flipY skewX skewY";
+const TRANSFORM_METHODS = "setMatrix setTranslate setScale setRotate setSkewX setSkewY";
+function fakeMatrix(): Record<string, unknown> {
   const m: Record<string, unknown> = { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
-  m.multiply = () => fakeMatrix();
-  m.inverse = () => fakeMatrix();
-  m.translate = () => fakeMatrix();
-  m.scale = () => fakeMatrix();
-  m.scaleNonUniform = () => fakeMatrix();
-  m.rotate = () => fakeMatrix();
-  m.rotateFromVector = () => fakeMatrix();
-  m.flipX = () => fakeMatrix();
-  m.flipY = () => fakeMatrix();
-  m.skewX = () => fakeMatrix();
-  m.skewY = () => fakeMatrix();
+  for (const fn of MATRIX_METHODS.split(" ")) m[fn] = () => fakeMatrix();
   return m;
 }
-
-function fakePoint() {
-  const p: Record<string, unknown> = { x: 0, y: 0 };
-  p.matrixTransform = () => fakePoint();
-  return p;
+function fakeTransform(): Record<string, unknown> {
+  const t: Record<string, unknown> = { type: 0, matrix: fakeMatrix(), angle: 0 };
+  for (const fn of TRANSFORM_METHODS.split(" ")) t[fn] = () => undefined;
+  return t;
 }
+const fakePoint = (): Record<string, unknown> => ({ x: 0, y: 0, matrixTransform: () => fakePoint() });
+const fakeRect = () => ({ x: 0, y: 0, width: 0, height: 0 });
+installIfMissing(G.SVGSVGElement?.prototype, {
+  createSVGMatrix: fakeMatrix as AnyFn,
+  createSVGPoint: fakePoint as AnyFn,
+  createSVGTransform: fakeTransform as AnyFn,
+  createSVGTransformFromMatrix: fakeTransform as AnyFn,
+});
+installIfMissing(G.SVGGraphicsElement?.prototype, {
+  getScreenCTM: fakeMatrix as AnyFn,
+  getCTM: fakeMatrix as AnyFn,
+  getBBox: fakeRect as AnyFn,
+});
 
-function fakeTransform() {
-  return {
-    type: 0,
-    matrix: fakeMatrix(),
-    angle: 0,
-    setMatrix: () => undefined,
-    setTranslate: () => undefined,
-    setScale: () => undefined,
-    setRotate: () => undefined,
-    setSkewX: () => undefined,
-    setSkewY: () => undefined,
+// Constructable Stylesheets API (`new CSSStyleSheet().replaceSync(...)`) —
+// jsdom doesn't ship it, but @codingame/monaco-vscode-api v25 calls it at
+// module load. Stub with an inert constructor; specs don't visually render
+// anything, so swallowing CSS is safe.
+if (!G.CSSStyleSheet) {
+  G.CSSStyleSheet = class {
+    cssRules: unknown[] = [];
+    replaceSync = () => undefined;
+    replace = () => Promise.resolve();
+    insertRule = () => 0;
+    deleteRule = () => undefined;
   };
+} else {
+  installIfMissing(G.CSSStyleSheet.prototype, {
+    replaceSync: (() => undefined) as AnyFn,
+    replace: (() => Promise.resolve()) as AnyFn,
+  });
 }
 
-function fakeRect() {
-  return { x: 0, y: 0, width: 0, height: 0 };
+// `Document.prototype` shims — jsdom is missing `adoptedStyleSheets` (used by
+// the codingame runtime to push Constructable Stylesheets at it) and the
+// legacy `queryCommandSupported` (probed by monaco-editor on init).
+const docProto = G.Document?.prototype as Record<string, unknown> | undefined;
+if (docProto && !("adoptedStyleSheets" in docProto)) {
+  Object.defineProperty(docProto, "adoptedStyleSheets", {
+    configurable: true,
+    get() {
+      return (this as { __adoptedStyleSheets?: unknown[] }).__adoptedStyleSheets ?? [];
+    },
+    set(v: unknown[]) {
+      (this as { __adoptedStyleSheets?: unknown[] }).__adoptedStyleSheets = v;
+    },
+  });
 }
+installIfMissing(docProto as Record<string, AnyFn> | undefined, { queryCommandSupported: (() => false) as AnyFn });
 
-const SVG_GLOBAL = (globalThis as unknown as { SVGSVGElement?: { prototype: Record<string, AnyFn> } }).SVGSVGElement;
-const SVG_ELEMENT_GLOBAL = (globalThis as unknown as { SVGGraphicsElement?: { prototype: Record<string, AnyFn> } })
-  .SVGGraphicsElement;
+// `CSS` global namespace (`CSS.escape`, `CSS.supports`) — jsdom doesn't
+// ship it; the codingame v25 theme service calls `CSS.escape(...)` from an
+// idle-callback runner and crashes without the stub. The escape impl mirrors
+// the spec (https://drafts.csswg.org/cssom/#serialize-an-identifier) just
+// enough that `value === out` for the common case — otherwise a noisy
+// `console.warn` fires every paint.
+G.CSS ??= {};
+installIfMissing(G.CSS, {
+  escape: ((v: string) => String(v).replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&")) as AnyFn,
+  supports: (() => false) as AnyFn,
+});
 
-if (SVG_GLOBAL?.prototype) {
-  const proto = SVG_GLOBAL.prototype;
-  if (typeof proto.createSVGMatrix !== "function") proto.createSVGMatrix = fakeMatrix as AnyFn;
-  if (typeof proto.createSVGPoint !== "function") proto.createSVGPoint = fakePoint as AnyFn;
-  if (typeof proto.createSVGTransform !== "function") proto.createSVGTransform = fakeTransform as AnyFn;
-  if (typeof proto.createSVGTransformFromMatrix !== "function")
-    proto.createSVGTransformFromMatrix = fakeTransform as AnyFn;
-}
+// `window.matchMedia` — jsdom doesn't implement it; the codingame v25 theme
+// service calls it in a deferred idle callback to detect dark/light preference.
+// Stub returns an inert MediaQueryList that always reports no match.
+const matchMediaStub: AnyFn = ((query: string) => ({
+  matches: false,
+  media: query,
+  onchange: null,
+  addListener: () => undefined,
+  removeListener: () => undefined,
+  addEventListener: () => undefined,
+  removeEventListener: () => undefined,
+  dispatchEvent: () => false,
+})) as AnyFn;
+if (typeof G.matchMedia !== "function") G.matchMedia = matchMediaStub;
+if (G.window && typeof G.window.matchMedia !== "function") G.window.matchMedia = matchMediaStub;
 
-if (SVG_ELEMENT_GLOBAL?.prototype) {
-  const proto = SVG_ELEMENT_GLOBAL.prototype;
-  if (typeof proto.getScreenCTM !== "function") proto.getScreenCTM = fakeMatrix as AnyFn;
-  if (typeof proto.getCTM !== "function") proto.getCTM = fakeMatrix as AnyFn;
-  if (typeof proto.getBBox !== "function") proto.getBBox = fakeRect as AnyFn;
-}
+// `requestIdleCallback` / `cancelIdleCallback` — Chrome-only APIs jsdom
+// doesn't ship; monaco-related modules crash at construction without them.
+// Approximate with `setTimeout`; the deadline arg is a coarse stub for
+// callers that only read `didTimeout`.
+G.requestIdleCallback ??= (cb: (d: { didTimeout: boolean; timeRemaining: () => number }) => void) =>
+  setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 50 }), 0);
+G.cancelIdleCallback ??= (id: number) => clearTimeout(id);
 
-/**
- * jsdom doesn't implement the legacy `document.queryCommandSupported`,
- * which monaco-editor probes during initialization. Without it the
- * editor's setup throws even when no spec actually exercises monaco.
- */
-const docProto = (globalThis as unknown as { Document?: { prototype: Record<string, AnyFn> } }).Document?.prototype;
-if (docProto && typeof docProto.queryCommandSupported !== "function") {
-  docProto.queryCommandSupported = (() => false) as AnyFn;
-}
-
-/**
- * jsdom doesn't implement `requestIdleCallback` / `cancelIdleCallback`
- * (a Chrome-only API). Specs that pull in monaco-related modules
- * crash at construction with `ReferenceError: requestIdleCallback is
- * not defined`.
- *
- * Approximate with `setTimeout` so callbacks still fire. The deadline
- * argument is a coarse stub — enough for callers that only read
- * `didTimeout`.
- */
-const idleGlobal = globalThis as unknown as Record<string, AnyFn | undefined>;
-if (typeof idleGlobal.requestIdleCallback !== "function") {
-  idleGlobal.requestIdleCallback = ((cb: (d: { didTimeout: boolean; timeRemaining: () => number }) => void) =>
-    setTimeout(() => cb({ didTimeout: false, timeRemaining: () => 50 }), 0)) as AnyFn;
-}
-if (typeof idleGlobal.cancelIdleCallback !== "function") {
-  idleGlobal.cancelIdleCallback = ((id: number) => clearTimeout(id)) as AnyFn;
-}
-
-/**
- * y-websocket schedules a reconnect timer the moment a service that uses
- * collaborative editing is constructed. When that timer fires AFTER vitest
- * has begun tearing down the jsdom window, jsdom's WebSocket implementation
- * crashes during construction (`Cannot read properties of null (reading
- * '_cookieJar')` → `Invalid value used as weak map key`). Vitest catches
- * this as an unhandled error and fails the run even though every test
- * passed.
- *
- * Stub WebSocket with an inert no-op so the timer can fire without
- * touching jsdom. The collaborative-editing specs that actually exercise
- * WebSocket behaviour are excluded from the test suite (component specs +
- * the workflow-action suite is the only collaboration-touching active
- * spec). Real WebSocket testing belongs under Vitest browser mode.
- */
+// `WebSocket` — y-websocket schedules a reconnect timer the moment a
+// collaborative-editing service is constructed. When that timer fires AFTER
+// vitest has begun tearing down the jsdom window, jsdom's WebSocket
+// implementation crashes during construction (`Cannot read properties of null
+// (reading '_cookieJar')` → `Invalid value used as weak map key`) and vitest
+// fails the run even though every test passed. Stub with an inert no-op so
+// the timer can fire without touching jsdom; the only specs that genuinely
+// exercise WebSocket behaviour are already excluded from the suite. Real
+// WebSocket testing belongs under Vitest browser mode.
 class InertWebSocket {
   static readonly CONNECTING = 0;
   static readonly OPEN = 1;
@@ -158,45 +211,51 @@ class InertWebSocket {
   onerror: AnyFn | null = null;
   onmessage: AnyFn | null = null;
   onclose: AnyFn | null = null;
-  send(): void {}
-  close(): void {}
-  addEventListener(): void {}
-  removeEventListener(): void {}
-  dispatchEvent(): boolean {
-    return false;
-  }
+  send = () => undefined;
+  close = () => undefined;
+  addEventListener = () => undefined;
+  removeEventListener = () => undefined;
+  dispatchEvent = () => false;
   constructor(_url?: string, _protocols?: string | string[]) {}
 }
-(globalThis as unknown as { WebSocket: typeof InertWebSocket }).WebSocket = InertWebSocket;
+G.WebSocket = InertWebSocket;
 
-/**
- * NgZorro's NzIconService dynamically fetches icon SVGs over HTTP from
- * `/assets/...` when the icon isn't pre-registered. jsdom's XHR
- * implementation rejects those requests with an `AggregateError`, and
- * downstream the icon lookup re-throws as `IconNotFoundError`. Vitest
- * catches both as unhandled errors, which CI treats as a hard failure
- * (locally Vitest only reports them as non-fatal warnings).
- *
- * Stubbing every spec with `NzIconModule.forChild([...])` for every
- * icon its template uses is impractical — there are dozens. Instead,
- * suppress the two specific error patterns at the process level: they
- * originate inside ngZorro's icon plumbing and don't affect the
- * assertions specs actually make.
- */
+// Process-level error suppression for benign ngZorro icon / codingame
+// extension fetches. NzIconService fetches icon SVGs from `/assets/...` when
+// the icon isn't pre-registered; jsdom's XHR rejects with `AggregateError`
+// and the lookup re-throws as `IconNotFoundError`. Vitest catches both as
+// unhandled errors and CI treats that as a hard failure. Stubbing every spec
+// with `NzIconModule.forChild([...])` is impractical — dozens of icons.
+// Suppress just these patterns at the process level.
 function isBenignIconError(err: unknown): boolean {
   const msg = err instanceof Error ? err.message : String(err);
+  const stack = err instanceof Error ? err.stack ?? "" : "";
   return (
     msg.includes("[@ant-design/icons-angular]") ||
-    (err instanceof Error && err.name === "AggregateError" && /xhr-utils/.test(err.stack ?? ""))
+    (err instanceof Error && err.name === "AggregateError" && /xhr-utils/.test(stack)) ||
+    // codingame v25 default extensions try to fetch their bundled themes /
+    // language configs over `extension-file://` URIs at activation time.
+    // jsdom can't resolve the scheme so the fetch rejects, but it's cosmetic
+    // — the spec body never depends on the theme/grammar being applied.
+    msg.includes("extension-file://") ||
+    /workbenchThemeService|monaco-vscode-theme|monaco-vscode-.*-default-extension/.test(stack)
   );
 }
-process.on("uncaughtException", err => {
-  if (isBenignIconError(err)) return;
-  // Re-throwing inside `uncaughtException` aborts the Node process, which
-  // crashes the Vitest worker mid-run and leaves the runner hanging.
-  console.error(err);
-});
-process.on("unhandledRejection", reason => {
-  if (isBenignIconError(reason)) return;
-  console.error(reason);
-});
+// Same gating pattern as the CSS loader hook above — vitest re-evaluates
+// this setup file once per spec file, and attaching fresh `process.on(...)`
+// handlers each time grows the listener chain (`MaxListenersExceededWarning`
+// after ~11 specs) and reruns the benign-error filter on every captured
+// rejection.
+if (!flagHolder[PROCESS_HANDLERS_FLAG]) {
+  process.on("uncaughtException", err => {
+    if (isBenignIconError(err)) return;
+    // Re-throwing inside `uncaughtException` aborts the Node process, which
+    // crashes the Vitest worker mid-run and leaves the runner hanging.
+    console.error(err);
+  });
+  process.on("unhandledRejection", reason => {
+    if (isBenignIconError(reason)) return;
+    console.error(reason);
+  });
+  flagHolder[PROCESS_HANDLERS_FLAG] = true;
+}
diff --git a/frontend/src/tsconfig.app.json b/frontend/src/tsconfig.app.json
index a05a55217b..a45e321c52 100644
--- a/frontend/src/tsconfig.app.json
+++ b/frontend/src/tsconfig.app.json
@@ -18,6 +18,11 @@
       }
     }
   },
-  "files": ["main.ts"],
+  "files": [
+    "main.ts",
+    "app/workspace/component/code-editor-dialog/workers/editor.worker.ts",
+    "app/workspace/component/code-editor-dialog/workers/extension-host.worker.ts",
+    "app/workspace/component/code-editor-dialog/workers/textmate.worker.ts"
+  ],
   "include": ["**/*.d.ts"]
 }
diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts
index 82a35b7afe..9cb2f82f88 100644
--- a/frontend/vitest.config.ts
+++ b/frontend/vitest.config.ts
@@ -34,17 +34,6 @@ export default defineConfig({
     // which Angular's `fakeAsync` requires. Karma+Jasmine installed this
     // implicitly; the @angular/build:unit-test path doesn't.
     setupFiles: ["src/test-zone-setup.ts"],
-    // monaco-breakpoints' entry does `import './style.css'`. By default
-    // Vitest leaves third-party deps externalized, so Node's ESM loader
-    // tries to import the .css and crashes with
-    // `TypeError: Unknown file extension ".css"`. Inlining the package
-    // routes its imports through Vite/esbuild, which rewrites the CSS
-    // import to a no-op.
-    server: {
-      deps: {
-        inline: [/monaco-breakpoints/],
-      },
-    },
     // Per-spec exclusions live in `angular.json` (the unit-test builder
     // applies them at the discovery stage, before Vitest's own filter,
     // which is what the Vitest team recommends — see the Vite warning
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index eda557ccf8..be83dc8cea 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -2066,307 +2066,428 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-base-service-override@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-base-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-api@npm:25.1.2, @codingame/monaco-vscode-api@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-api@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/d47b59e95fb287f8fb9abbfc3bcaeb0afca7cadd9293d4ee06302798840cccb7e78a4de955048a27bf6766675d0ed91c1f418d5c6dca576ada0e8130618a115d
+    "@codingame/monaco-vscode-base-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-environment-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-extensions-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-host-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-layout-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-quickaccess-service-override": "npm:25.1.2"
+    "@vscode/iconv-lite-umd": "npm:0.7.1"
+    dompurify: "npm:3.3.1"
+    jschardet: "npm:3.1.4"
+    marked: "npm:14.0.0"
+  checksum: 10c0/c2d2be484906bc81575a70b3e00b3a15098793955ff02ebc172061ce6d570a19b3d14dc236a7cd09ad5c030a348283be9d83e907a6248fbf68ac5ab9333eed01
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-configuration-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-configuration-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-base-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-base-service-override@npm:25.1.2"
   dependencies:
-    "@codingame/monaco-vscode-files-service-override": "npm:8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/04cc87a27bc2e93e6f8ade15e53e8635bf6db55eb341b043e1583abd18eaa396065144308651de67a1ccbd2edd3148f89dcf798af0a9926362370634bfa9e9b8
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/2194d5fcdf1b606e2c0e09b702c2bd3288958f5dde4403afb165737fcc837fc11d07cc6266b6cfa0aa6f1783da92add3024da3689fc7f7237dbbcd135da974a8
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-editor-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-editor-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-bulk-edit-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-bulk-edit-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/82362f7df94bcf72ca21810e18f0a2f251f299f0d8fa9544e5460da38243b07340cbd82f83045fa505d3609bb57402def5011814656522b76dde1e6bd55c1622
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/8b8fea1cd62ffeef47909d775b68966d0c9f495e49ff62e87fb04af5e7cd9307f8ab4764995d0801b87ce8651b6eb5754965cb2a8e6415b5d87c3685e11cb25b
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-environment-service-override@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-environment-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-configuration-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-configuration-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/5c438986315a9a22eef3d5d927350f362179e19d6293d651cf6ecb3b32446d2ba7333b53463473230329aaa3a1db77a39362274a3703ab7e3914b2bb538e8f28
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+  checksum: 10c0/1733039adbf653b0105cd176a9679621aa0d174dc488b3c943b0cb3cfb11c0a65bfbf0898d895027520b31ed0121f5d3d789ddf6b9631ae5bbf2e087f933fc7f
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-extensions-service-override@npm:8.0.4, @codingame/monaco-vscode-extensions-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-extensions-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-editor-api@npm:^25.1.2, monaco-editor@npm:@codingame/monaco-vscode-editor-api@25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-editor-api@npm:25.1.2"
   dependencies:
-    "@codingame/monaco-vscode-files-service-override": "npm:8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/624b819238c017e20f29fc908ede2cd8f641d659ec23ba04879ea2f87a829d9777a6ea9c1898cacdf9e7a07734ae8eb2d00cd2ccd136356bb3e8ca3cf0bb90bc
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/46678d8eabaa487a8f8ffce9717818dc08afed748582a89b7d306113a593e5243d4e7e023a046b3cdd65e2f4de06e2be779aa82b21a3c9cc9b72cbad24565d4d
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-files-service-override@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-files-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-editor-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-editor-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/956b7d5636cab22e3ab66deb7f71bf2f3c9d95c166d6068a0f8d4e742f58cc7e8400b64aa2eb420cab1896ee38c62c7132c4765f997b6b5ceacbd8e01e5175d2
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/e159bb2a1fb8ae8ee883bd02d95f2fb05e21b4caabb30bc21544b87cdf05f3932a4d2a6fe5b2a31f63e87c02455a36351322ed081ff4b6b55ea36e916d8cf1fd
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-host-service-override@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-host-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-environment-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-environment-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/a9cee88b06868ec84914bf891d42133b30ab309be41ce0eab3dd604fd4ef6756d419dd891e2ad0a271e69da3cce0c0f6c8cb289f057329bb1115f6161877c600
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/cfa7b5997a91d2b8d01acccf9fd63e998e130a2e6ded9938b4412787ae1265a0667ce47a3bd1d3f8fea2a833ff893e3efc978d1261a09af2bba1394fa0c90a35
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-java-default-extension@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-java-default-extension@npm:8.0.4"
+"@codingame/monaco-vscode-extension-api@npm:^25.1.2, vscode@npm:@codingame/monaco-vscode-extension-api@^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-extension-api@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/58f34897c29e006395a754c6cd87189ea5b30a10e879d2720777889b1f6842b5e5c931a30ffef98d369fc9420a23fcf7cf2f775077adffbf1fbd2f5702eaee3a
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-extensions-service-override": "npm:25.1.2"
+  checksum: 10c0/182f90e359bd3d57aaf9a58eaabe9eff226d6bc94e4f51c43f846308352982cbbe3b2dade60177c5ab90e49d8d437493715cd224c1a6063e5c52e1c5e75b9be3
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-cs@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-cs@npm:8.0.4"
+"@codingame/monaco-vscode-extensions-service-override@npm:25.1.2, @codingame/monaco-vscode-extensions-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-extensions-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/87700f4599d8404e746f03ce1073396b25c268fdae55ddd65d85404d1b71cbb08c43f281745494857cda6e9ef2c88624e647335f3597a7082991ac03622f906f
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+  checksum: 10c0/fbbbcfae26b61582dde6ebe3f2e40a040a6593e30948d557b4ebd2c2f80fa011235fe2f8be20ccc62fa91dadfa7274a245482e1fb04a94facaa56dc33efe706a
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-de@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-de@npm:8.0.4"
+"@codingame/monaco-vscode-files-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-files-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/dfb4b7a2e7abe6574fd15b40b7ee7089445917900ff2611d0fd7d309b0233e6e90c811392685e6be4b976b751dcb001b42bf422842d53b8dac80abd834e11761
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/d8d700507199c4cac564751d9c8f8bb3514cc39256d1e6381b492c80833f8428f3b6490082bbfee1b3e73b0b65dbefa6e5966280678b9ebd35f27c93b49f9c9c
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-es@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-es@npm:8.0.4"
+"@codingame/monaco-vscode-host-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-host-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/c3c60adab9fb60a5e376a37260f80b95998ac94d88424b5b824751240bcc3997cb5e83c4c4f01cf18a1ccb9bce48f8e8e50a31fd87a92949c7d0bb3c0bb5a6e3
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/12522ef3494b94b195d643ffd4f3ab0e66e3be949809c19daab329661d781a8a836273914d96de15046121b562510324e75b1802fd7d8f01a59f5f371f18fff1
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-fr@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-fr@npm:8.0.4"
+"@codingame/monaco-vscode-java-default-extension@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-java-default-extension@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/abe94f70eea98cddddcadb6a6c2f3b0964fa034489cf3d8d99b6953919fc2b34e74fbb2321a7623c8fb37afd80db8206d2c1c0f83a1f5bc01a2085ec28fb8b0c
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/ad00d914f1236102b1e387aff0cc61e004d0aa4bffba6dda38f3b310950372974e059383131955876ed3882dc339a06944af13529706e11f10ea27ca0d64e071
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-it@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-it@npm:8.0.4"
+"@codingame/monaco-vscode-keybindings-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-keybindings-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/9e47ce0458bc37787a3d5763720657d357acbee9792b0520524f0609be90b3adf015327a03db630a7b82f391cfbb8f8293fd28f7749f83b941c3f2e322d6115a
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+  checksum: 10c0/81399b35c85cdcef067059370979282a282bac560b0e3f033b8dcf2877c2f33618fc75c31e671fb7486e45f0f791d7575afa40509f13b017088ee242caff65ed
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-ja@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-ja@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-cs@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-cs@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/65bc3e1e6544cb690f1b99973da1b6845d26594daf0bf95dd692ed665e58de7de0d39e15ef72bd6dc6801636c414229f07b0a6359e7e8c001ea226944181c6e1
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/55a977b197f3bf35f3061587020598ec533068d0a50d3020378bd7ea07b48d4cfb720d6584136266cc29fd18454ad47b66a4a4e0411371d7729619ccab81b709
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-ko@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-ko@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-de@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-de@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/7bc457932db34fb26cd4e2c11494c5e3b4e6757de32ddd5045a46c7c5a47ab4fa3789418a51e722af706098eab35c022f56e7027966b6894136f93d664870ede
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/45440482e91bf70fa0ec5982dc6b39b7541902b10edf2c6eb50de3ab71a9b400edb3e3ce0bb86f53a6edc587baf8b9320fe3e7536a80121acab5dc33bd3f220e
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-pl@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-pl@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-es@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-es@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/80274df3bb40b0669d522fc88064a7926f61ae436ffe557e1cd2822017b6fe3b6e8571018f3e22dcf39a074af84021f3bc7a6e7634e4f4fda9f8e7a285d1dcc8
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/58011acd0e2a247d2e38a5f9ee14c142744e889ddfd4b7863fa3b9f876fd3ef6833e6e11fa8563eec9bf66100fa39dd9b47c5895729e1053cd772a35788d9e55
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-pt-br@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-pt-br@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-fr@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-fr@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/bb61c3a6dd102b8d636101ce547a00a82806f12c38f697d2603b8ef8dc585e673a8e5e6a177a7e39721535b0773508d791ae982f61d5aad3e1291b1d87a2bd25
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/0dcef4989cce25a0a7e8dbfe352be348f691163914912cffff8d2788d468de313c60b834f2f2f8ec7f153fc6dfb9cdcde6bee1bb8cbe980bef6c4a6de64d60c9
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-qps-ploc@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-qps-ploc@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-it@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-it@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/be864dcbfe746e34c8f981ba190e3db4352b2672cf52f2471042b33ddaa600a5783a2c28b28a70cc5d8783a3a3c7f310a91cdc71ab02d65301eee89cebd5b4ec
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/f05af4dc4629be34ba87188b7700195f4e5dce747d0937792463bdfb1b0fbf7ef4653600cef0b4febf16ba6b1dec76a94dd7f7417f47e1f94e05859aad0baea8
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-ru@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-ru@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-ja@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-ja@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/345d42252634261be208df7989148b7115624a778a491afb3249e1d750fa2e7469f906c9ab11c5a8df9201ec4cd7fefab82e46d88714c27d64b9a1b8ecdd83d6
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/d816fe97a4db813875a38f25766a22d9cd5724f8919d092b4b9ffbe622e3f161f314a702af7ae0c2b9b14c7bb564a261d014613ef3ad97bf1f1295980a759132
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-tr@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-tr@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-ko@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-ko@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/fdaeff22f5b52f565f391e14be6ec6b06ef337dd148e2542e8b9c6b578bf395274c1d540bf530b91b71ad54714871941e916e618c43d526203c3d5c7c8bc310a
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/96a97f07c0f35436ba56fac26b3a227243bc27faae40152ca34d58f58a2aebf667fc2d4b039c9f8c1e51c27a90c943b1cab6eb306327b1b1f9bd6158efebf0e3
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-zh-hans@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-zh-hans@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-pl@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-pl@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/9997fc23adae93cc6bd33916085b341bdd2cdcc15a83d492809f6328bc95c14ec9c579b5dae6d35224b4eb96ab35f006c19539a765afd4c1713e8ca5eb10645b
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/d81fecd1f5858a39b9e58340883cac0198a3f855ea926fd7147f149fd98e7e070dcf6f42c713634f32a5d3bd721ce011de13df51ff9052aabd99561a523ffbe4
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-language-pack-zh-hant@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-language-pack-zh-hant@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-pt-br@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-pt-br@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/23fe87f2938cf00e2906fed63f23965a910ea8f9d3e15a6d39d3d3ef2f9e7a41dd423a59ce3a816924995479743dad6d6a67116bc2e152f9624586344dd102ba
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/4c55969eed67b15066fc2d0482f8de06694b10df48f65a239b2f34182e53bd3ebc07c28c0bf38a6b2cb637a6f5fdab979a80a38d65ec51322b08062264a310b0
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-languages-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-languages-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-qps-ploc@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-qps-ploc@npm:25.1.2"
   dependencies:
-    "@codingame/monaco-vscode-files-service-override": "npm:8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/f376fb13b75c57d8f509f3465c01dc6509bcae3b4b8f40b9adbee4f7b1b9027def0a1489d1f84b7a72eeebe08570eb968dcc4bbb624279974c1b3c3c336a6d17
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/425119b73c53687a209cc05554f3b562e98b6b8ee4e531a3ddd4e10b77b1a26684597ac30da164a77b4fb0b88d61faa354507af04de3d448ad400b8dd8e388b4
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-layout-service-override@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-layout-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-ru@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-ru@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/114d5d47e25719e01a23337bbbe1d051f2e50589cc27ee171bb4c49363618029d25124b7ea7eb37cf255467f2535cef4129f3be433161c7014ff5652c19488aa
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/038be50b55f39381a4f075a549e1f07febf8019ea6cc8e094b413047e5339cd6004dc2ebcc79e9ea97180757851f1e4079b101448bedbdcae61719717ee54fb6
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-localization-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-localization-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-tr@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-tr@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/77ad94652bdc9ea82453bbe6c3d8b3d1741dbb8cd311b477639a795751de2e52c4938fca27458b8be5f71bf35252bb6d0e752d3d2012f15150b254cb26f601c3
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/4a338cbb20449a07d721e5ed80e9f99abe7102827772591df3e4b076d4c893e9c0408d4c2a96acee20b36dee32bba7a021c59d6cab2015ac63e07d50b4af606a
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-model-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-model-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-zh-hans@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-zh-hans@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/5c95c11dd93d7b4f6c912b5e8c87b107406e72a1409c8ccf0acf5ef87b0fd464566a5b13661fe80e44c4f1dd9a216ae25f560ce7c1614a950af8f1fb64bcf625
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/65ce7622860502addf813631cbb70170d534764d7de3ef2318a44e39b5a3808e3c2b39945f6b7612ecdf3dbba2653f223bb834a62c6d7ac3b0657f96b6fa06c1
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-monarch-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-monarch-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-language-pack-zh-hant@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-language-pack-zh-hant@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/0cd64ee6e5ae23fbadde35833c86a009428088c93052bef979c51db9e22dcd53fa04177b907d77e23c133769b277845ef79c5407dab214ed27b15c4ae2f5fb81
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/4bb8461d30c6b5ddba2bb23c1890fe3397642c9b1d97b926caf7e7af9a0347624b97a9d95a67f7de5efdbf8a026e99873b3020410b46beae3435bc70ccc0a222
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-python-default-extension@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-python-default-extension@npm:8.0.4"
+"@codingame/monaco-vscode-languages-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-languages-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/d1e638b8a716f5c81ebd90ea15f7380f6448d959343118989dc5022f43e2bd7615ac9c7805d6d961380ecef2dcce21f4f08edbd562f2186c15afa6c0b8ca5b68
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+  checksum: 10c0/f4590a9d33df071c7649094ec99b50f2289e70e7a147a1a2f9905650da84078fc9562d35dd5da38b193a7738501e87a71d49c0cc55a2f5ef6069950d6dfbfa49
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-quickaccess-service-override@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-quickaccess-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-layout-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-layout-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/9dbe054be90b4ae57f295df4071382b71c8ec5e46194af07dc03bc4aeac375e019f068c2ef883453f4234f2b53b8426f2f5475ff8d0e61ebb4892379c07bdb96
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/eca1f91e750129cc1f07be960d7c1a9f2490f5c0ea798875707ef6a0b9fec6c6cdd9c7dc54c4e2ce32c26d2d517d7f8ee65f37cb4e72739d6c25cd80195ceb0e
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-r-default-extension@npm:8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-r-default-extension@npm:8.0.4"
+"@codingame/monaco-vscode-localization-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-localization-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/b83948b58b0e37693f29663fb34a896a689a1abfef28babf848d854574df27ef8b9d8dce6d53df1ac65b015e21929d7abdedf0a662dd6f7ed060fe2b84188471
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/c50d04d622443fddec26d489da060a729a3ff683111162755cdb83ee159bc8b78e5ce7b8d5f521abf0e44357d7049c3d4d67a508d10142f39da64d3e984a1fff
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-textmate-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-textmate-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-log-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-log-service-override@npm:25.1.2"
   dependencies:
-    "@codingame/monaco-vscode-files-service-override": "npm:8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-    vscode-oniguruma: "npm:1.7.0"
-    vscode-textmate: "npm:9.0.0"
-  checksum: 10c0/5a7ffd954bb801e2cb512efa2ff725b37a3dfb6661f050c7ab71761cd73a7d575f857cfd518d65a9412e6e45cd0c9c379a7781275eb3de19188714ee95905540
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-environment-service-override": "npm:25.1.2"
+  checksum: 10c0/f5c98c3afc02bb327afb59562b8d4fc30aba3a6fbd63369de68db63bac28bfe6fbec34f3d9acf1f6e1ece9fccda3d3e70c3e3260c973352cbdd1c8bcfc8d1243
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-theme-defaults-default-extension@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-theme-defaults-default-extension@npm:8.0.4"
+"@codingame/monaco-vscode-model-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-model-service-override@npm:25.1.2"
   dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/500dc8a1ff507a455b405477ea9558e997f23f2777562bb9cb54df0ab0b6e9bf349f0a970bcc321f28ae336379b3444787626c9d70716ce14d4e7efce55c4ec1
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/4c7a15cd3088cd41df076bc9935c154c001c3d33ae353145bf632a31ea2b40c17b1660b92c7742dcc9d447f004f376fce2bdf3a10370d6781f5cc5635c451bb6
   languageName: node
   linkType: hard
 
-"@codingame/monaco-vscode-theme-service-override@npm:~8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-theme-service-override@npm:8.0.4"
+"@codingame/monaco-vscode-monarch-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-monarch-service-override@npm:25.1.2"
   dependencies:
-    "@codingame/monaco-vscode-files-service-override": "npm:8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/9ce94a254f54c95313b59e8db63fe56031584fdb7ea76cf045557ce0076a684d5f2ffdad18fd7d3580331391b529b55d552ea39eac05a0fc2e11ee19122ed2a0
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/ba43c4463f8e641f13408e9c271ee24e57d573b7c6fd54e56d6d8e9cf3b170d0e82a8950bc3ab90ed24de82482249fb532df319b6aba40e24234fdb8a9e66e7d
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-python-default-extension@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-python-default-extension@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/a43b5023805be6237070117065ecb350817596b0819a944a5a4bbce4db9ef71fb45dea06bcbbe871389b4a79489ac1d42b84be02b7a82515338ffbdd521160f7
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-quickaccess-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-quickaccess-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/03e86955a6f1dcbce91d5c13d50f28824452675e5560992118b0e7a1005d50fbebe9ef8b0869b61bcc587abea7d1d5bfa89c60a731c4ee62b9c821a840934b83
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-textmate-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-textmate-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+  checksum: 10c0/1986ced74e425b5d918e9a4b262c3f6a6fa4b7699f3eff5bbfbf397b457f6de5d6d7a6cc74da522aea203f356c0ecd9ac0400beb68a07d85e4fab9d700ed8842
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-theme-defaults-default-extension@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-theme-defaults-default-extension@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/2d5c9af28b18e116ec2962d7c0f4c8d38e729d385243150b2bcd8d513056700b93d17bd020cc038fc0a28ed23795eb100530b5ba1dfdec53a9d391920b4bdde8
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-theme-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-theme-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-files-service-override": "npm:25.1.2"
+  checksum: 10c0/041e562624bcfbf34afb76c4a06f5f1de34a1a654151763d02f25a92fe24ed3e60d35d9087d823cf52edde8d6abf8dfdfb3a6547ba1fd39bf045e5cb4589fbf9
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-view-banner-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-view-banner-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/47030d59c8b702c09954bea6cee5678927bda6b1a619f005a40f2733e07db1262d26af3faa66d88b7fdcf11e80c6a574581e55b6f86e6592384a9a1a9ce4cfa3
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-view-common-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-view-common-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-bulk-edit-service-override": "npm:25.1.2"
+  checksum: 10c0/b17311fbfd1157d0787762b89091841ec37572096f013fe0a37c105f258923360e851c50058f2129869a8f74758cbdbf5c7ce66eb7894565632a9ceb557d1721
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-view-status-bar-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-view-status-bar-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/136a130ff4bdf6ed87c2c7b60b63186751497b7e20e1bdc2af39c6ecdb6747418ecf274736d7377ed1df8dd1571d3b5ecd3a254d83ede2ac9a0285f3310d003e
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-view-title-bar-service-override@npm:25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-view-title-bar-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+  checksum: 10c0/636628e73854043c41a7bd9b3020a8b6830c26f1a96b24fbf24b993a90a98efd3d8df0073b1c8f76bbd9436e53cdb05853534ec70459f0eeaee54aa277189e38
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-views-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-views-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-keybindings-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-layout-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-quickaccess-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-view-common-service-override": "npm:25.1.2"
+  checksum: 10c0/2df81bc7504965b99d39a144f0ae04b2bbde442e28295edd19cd66be19ec71d7b9b63ae30d634f1c3e9bff0abd342d25cdceedf2885e69a7ad85040cffee88ea
+  languageName: node
+  linkType: hard
+
+"@codingame/monaco-vscode-workbench-service-override@npm:^25.1.2":
+  version: 25.1.2
+  resolution: "@codingame/monaco-vscode-workbench-service-override@npm:25.1.2"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:25.1.2"
+    "@codingame/monaco-vscode-keybindings-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-quickaccess-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-view-banner-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-view-common-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-view-status-bar-service-override": "npm:25.1.2"
+    "@codingame/monaco-vscode-view-title-bar-service-override": "npm:25.1.2"
+  checksum: 10c0/594d488fc896ad30cb88e1ac3d094580d771d45528491e4485662a1b0af3733008e6f11e9911dd874fdee45c94acdd5ade87876f1c7ad70438b7af198bbc74ce
   languageName: node
   linkType: hard
 
@@ -6177,6 +6298,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/trusted-types@npm:^2.0.7":
+  version: 2.0.7
+  resolution: "@types/trusted-types@npm:2.0.7"
+  checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c
+  languageName: node
+  linkType: hard
+
 "@types/underscore@npm:*":
   version: 1.13.0
   resolution: "@types/underscore@npm:1.13.0"
@@ -6745,10 +6873,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@vscode/iconv-lite-umd@npm:0.7.0":
-  version: 0.7.0
-  resolution: "@vscode/iconv-lite-umd@npm:0.7.0"
-  checksum: 10c0/3316664f65f2b2089f58d5f31d09ebc931da01d826c7f57d44740689bc862ba970224ebcf70da6b823b138c80c070f484c98a21ecfddf49c84c614a0b0bd3f6f
+"@vscode/iconv-lite-umd@npm:0.7.1":
+  version: 0.7.1
+  resolution: "@vscode/iconv-lite-umd@npm:0.7.1"
+  checksum: 10c0/ed6026004465fd2b034cae2b4f03df15b16b90d701ac380f2596972cc651dbd143a9fcf4e68472d7cceaf3d8f91fad5b45b72077127f0b275395f6358d841e5a
   languageName: node
   linkType: hard
 
@@ -7022,7 +7150,16 @@ __metadata:
   languageName: node
   linkType: hard
 
-"acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0":
+"acorn@npm:^8.0.4":
+  version: 8.17.0
+  resolution: "acorn@npm:8.17.0"
+  bin:
+    acorn: bin/acorn
+  checksum: 10c0/5dcefea5f8f023b6cc24cbe71fb5a8112b601d36c4fa07d14e4e6ffc2ee47383332c46b36c766d9437725aa6660156eae50efa0c838719823b50d7c327c4ed42
+  languageName: node
+  linkType: hard
+
+"acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.4.1, acorn@npm:^8.9.0":
   version: 8.16.0
   resolution: "acorn@npm:8.16.0"
   bin:
@@ -9094,6 +9231,18 @@ __metadata:
   languageName: node
   linkType: hard
 
+"dompurify@npm:3.3.1":
+  version: 3.3.1
+  resolution: "dompurify@npm:3.3.1"
+  dependencies:
+    "@types/trusted-types": "npm:^2.0.7"
+  dependenciesMeta:
+    "@types/trusted-types":
+      optional: true
+  checksum: 10c0/fa0a8c55a436ba0d54389195e3d2337e311f56de709a2fc9efc98dbbc7746fa53bb4b74b6ac043b77a279a8f2ebd8685f0ebaa6e58c9e32e92051d529bc0baf8
+  languageName: node
+  linkType: hard
+
 "domutils@npm:^3.0.1, domutils@npm:^3.2.2":
   version: 3.2.2
   resolution: "domutils@npm:3.2.2"
@@ -10658,9 +10807,8 @@ __metadata:
     "@angular/platform-browser-dynamic": "npm:21.2.10"
     "@angular/router": "npm:21.2.10"
     "@auth0/angular-jwt": "npm:5.1.0"
-    "@codingame/monaco-vscode-java-default-extension": "npm:8.0.4"
-    "@codingame/monaco-vscode-python-default-extension": "npm:8.0.4"
-    "@codingame/monaco-vscode-r-default-extension": "npm:8.0.4"
+    "@codingame/monaco-vscode-java-default-extension": "npm:25.1.2"
+    "@codingame/monaco-vscode-python-default-extension": "npm:25.1.2"
     "@lezer/python": "npm:1.1.18"
     "@ngneat/until-destroy": "npm:8.1.4"
     "@ngx-formly/core": "npm:6.3.12"
@@ -10707,9 +10855,8 @@ __metadata:
     lodash-es: "npm:4.18.1"
     marked: "npm:17.0.1"
     monaco-breakpoints: "npm:0.2.0"
-    monaco-editor: "npm:@codingame/monaco-vscode-editor-api@8.0.4"
-    monaco-editor-wrapper: "npm:5.5.3"
-    monaco-languageclient: "npm:8.8.3"
+    monaco-editor: "npm:@codingame/monaco-vscode-editor-api@25.1.2"
+    monaco-languageclient: "npm:10.7.0"
     ng-zorro-antd: "npm:21.3.1"
     ngx-color-picker: "npm:12.0.1"
     ngx-file-drop: "npm:16.0.0"
@@ -10736,7 +10883,6 @@ __metadata:
     typescript: "npm:5.9.3"
     uuid: "npm:14.0.0"
     vitest: "npm:4.1.9"
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
     webpack-bundle-analyzer: "npm:4.5.0"
     y-monaco: "npm:0.1.5"
     y-protocols: "npm:1.0.5"
@@ -12577,6 +12723,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"marked@npm:14.0.0":
+  version: 14.0.0
+  resolution: "marked@npm:14.0.0"
+  bin:
+    marked: bin/marked.js
+  checksum: 10c0/57a47cb110f7b1a10f398b0a7236f9183aad2dcd5345ee73f2732b6387e585d04cef472bc655d2f84c542296be9728e179aebe3ed7f2f8666b8a0a9dae592876
+  languageName: node
+  linkType: hard
+
 "marked@npm:17.0.1":
   version: 17.0.1
   resolution: "marked@npm:17.0.1"
@@ -12939,79 +13094,45 @@ __metadata:
   languageName: node
   linkType: hard
 
-"monaco-editor-wrapper@npm:5.5.3":
-  version: 5.5.3
-  resolution: "monaco-editor-wrapper@npm:5.5.3"
-  dependencies:
-    "@codingame/monaco-vscode-configuration-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-editor-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-cs": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-de": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-es": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-fr": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-it": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-ja": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-ko": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-pl": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-pt-br": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-qps-ploc": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-ru": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-tr": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-zh-hans": "npm:~8.0.4"
-    "@codingame/monaco-vscode-language-pack-zh-hant": "npm:~8.0.4"
-    "@codingame/monaco-vscode-monarch-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-textmate-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-theme-defaults-default-extension": "npm:~8.0.4"
-    "@codingame/monaco-vscode-theme-service-override": "npm:~8.0.4"
-    monaco-editor: "npm:@codingame/monaco-vscode-editor-api@~8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@~8.0.4"
+"monaco-languageclient@npm:10.7.0":
+  version: 10.7.0
+  resolution: "monaco-languageclient@npm:10.7.0"
+  dependencies:
+    "@codingame/monaco-vscode-api": "npm:^25.1.2"
+    "@codingame/monaco-vscode-configuration-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-editor-api": "npm:^25.1.2"
+    "@codingame/monaco-vscode-editor-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-extension-api": "npm:^25.1.2"
+    "@codingame/monaco-vscode-extensions-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-cs": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-de": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-es": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-fr": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-it": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-ja": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-ko": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-pl": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-pt-br": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-qps-ploc": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-ru": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-tr": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-zh-hans": "npm:^25.1.2"
+    "@codingame/monaco-vscode-language-pack-zh-hant": "npm:^25.1.2"
+    "@codingame/monaco-vscode-languages-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-localization-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-log-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-model-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-monarch-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-textmate-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-theme-defaults-default-extension": "npm:^25.1.2"
+    "@codingame/monaco-vscode-theme-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-views-service-override": "npm:^25.1.2"
+    "@codingame/monaco-vscode-workbench-service-override": "npm:^25.1.2"
+    vscode: "npm:@codingame/monaco-vscode-extension-api@^25.1.2"
     vscode-languageclient: "npm:~9.0.1"
     vscode-languageserver-protocol: "npm:~3.17.5"
-    vscode-ws-jsonrpc: "npm:~3.3.2"
-  peerDependencies:
-    monaco-editor: "*"
-    monaco-languageclient: ~8.8.3
-    vscode: "*"
-  peerDependenciesMeta:
-    monaco-editor:
-      optional: false
-    monaco-languageclient:
-      optional: false
-    vscode:
-      optional: false
-  checksum: 10c0/d113ea5408cc178d7f5558e943c9fe59e060ead59d38bcc4944f19f9120814e68d7f39f97ebb1f9ab8df862cfe4810c23bd9744e6543525b607ed0676f60e268
-  languageName: node
-  linkType: hard
-
-"monaco-editor@npm:@codingame/monaco-vscode-editor-api@8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-editor-api@npm:8.0.4"
-  dependencies:
-    vscode: "npm:@codingame/monaco-vscode-api@8.0.4"
-  checksum: 10c0/8ab6eab164826cbca220868c07a6c071e1730ac8cd7e2057353af70d7ff58f054863bb04538ac609a09aea0b0a942eed1651e9d81434e097dfc1b3251fa5ebec
-  languageName: node
-  linkType: hard
-
-"monaco-languageclient@npm:8.8.3":
-  version: 8.8.3
-  resolution: "monaco-languageclient@npm:8.8.3"
-  dependencies:
-    "@codingame/monaco-vscode-extensions-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-languages-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-localization-service-override": "npm:~8.0.4"
-    "@codingame/monaco-vscode-model-service-override": "npm:~8.0.4"
-    monaco-editor: "npm:@codingame/monaco-vscode-editor-api@~8.0.4"
-    vscode: "npm:@codingame/monaco-vscode-api@~8.0.4"
-    vscode-languageclient: "npm:~9.0.1"
-  peerDependencies:
-    monaco-editor: "*"
-    vscode: "*"
-  peerDependenciesMeta:
-    monaco-editor:
-      optional: false
-    vscode:
-      optional: false
-  checksum: 10c0/ed32080a773de3537cae8042c83a79e90e6010f9f9fe8bb1cb57518b75330c676788b2975963ce5a97e12ebbbb32dc561570fa22c5fbeef0f88fa7d0068284b5
+    vscode-ws-jsonrpc: "npm:~3.5.0"
+  checksum: 10c0/b8fd931cc0a490d1a744ab54f8d596eb82808e471d2fbd1f2aec55d1b65fb24243a13a9ff0bd6998af75984289c631aa606c76e3198c6dec691ada151b71ec4a
   languageName: node
   linkType: hard
 
@@ -17698,43 +17819,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"vscode-oniguruma@npm:1.7.0":
-  version: 1.7.0
-  resolution: "vscode-oniguruma@npm:1.7.0"
-  checksum: 10c0/bef0073c665ddf8c86e51da94529c905856559e9aba97a9882f951acd572da560384775941ab6e7e8db94d9c578b25fefb951e4b73c37e8712e16b0231de2689
-  languageName: node
-  linkType: hard
-
-"vscode-textmate@npm:9.0.0":
-  version: 9.0.0
-  resolution: "vscode-textmate@npm:9.0.0"
-  checksum: 10c0/83d874e1776d93d926eb0eb562476d4fd3f9633074efef056a443aee0f809d6648600b73e451f74687706435a16578a2037629247fac82a8f108ea3ff434048d
-  languageName: node
-  linkType: hard
-
-"vscode-ws-jsonrpc@npm:~3.3.2":
-  version: 3.3.2
-  resolution: "vscode-ws-jsonrpc@npm:3.3.2"
+"vscode-ws-jsonrpc@npm:~3.5.0":
+  version: 3.5.0
+  resolution: "vscode-ws-jsonrpc@npm:3.5.0"
   dependencies:
     vscode-jsonrpc: "npm:~8.2.1"
-  checksum: 10c0/35b71071ccd3c9478d8b4f2c07ef80fa2d988f6e6d4e5d1bfc7109a8282cf091905a5c9f056bb5be8946461cb3be8e50f608825cb82b16e9b7998afc13da5783
-  languageName: node
-  linkType: hard
-
-"vscode@npm:@codingame/monaco-vscode-api@8.0.4":
-  version: 8.0.4
-  resolution: "@codingame/monaco-vscode-api@npm:8.0.4"
-  dependencies:
-    "@codingame/monaco-vscode-base-service-override": "npm:8.0.4"
-    "@codingame/monaco-vscode-environment-service-override": "npm:8.0.4"
-    "@codingame/monaco-vscode-extensions-service-override": "npm:8.0.4"
-    "@codingame/monaco-vscode-files-service-override": "npm:8.0.4"
-    "@codingame/monaco-vscode-host-service-override": "npm:8.0.4"
-    "@codingame/monaco-vscode-layout-service-override": "npm:8.0.4"
-    "@codingame/monaco-vscode-quickaccess-service-override": "npm:8.0.4"
-    "@vscode/iconv-lite-umd": "npm:0.7.0"
-    jschardet: "npm:3.1.3"
-  checksum: 10c0/268b6584f3e5473ecd1e4ee5492477cbf9a670204fe82d8d97490987415b63bf9b40bc539d639e7f0aaf19b982d9445b746465acf6a0b4b669050b5c2c380d21
+  checksum: 10c0/be2297cddeb3850218b1c4529345e2335ead38f8114036eb02f754911a833af6d18f3b7f19ee3596692386f8f00f7d94cb85f3e65ff44381525f0e174b249cfb
   languageName: node
   linkType: hard
 
@@ -18158,8 +18248,8 @@ __metadata:
   linkType: hard
 
 "ws@npm:^7.3.1":
-  version: 7.5.10
-  resolution: "ws@npm:7.5.10"
+  version: 7.5.11
+  resolution: "ws@npm:7.5.11"
   peerDependencies:
     bufferutil: ^4.0.1
     utf-8-validate: ^5.0.2
@@ -18168,7 +18258,7 @@ __metadata:
       optional: true
     utf-8-validate:
       optional: true
-  checksum: 10c0/bd7d5f4aaf04fae7960c23dcb6c6375d525e00f795dd20b9385902bd008c40a94d3db3ce97d878acc7573df852056ca546328b27b39f47609f80fb22a0a9b61d
+  checksum: 10c0/7972670b676fb1ccba73b0899ca3c2e04e8c2075629c2614cced7f556536f96a672bbf4619fc5a06c8b8720bb839a47ca88c69c95dc14c9c61a99fbecba1c866
   languageName: node
   linkType: hard