@orkestrel/probe 0.0.24 → 0.0.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -843,6 +843,8 @@ export declare function parseRevisionOwner(revision: string): number | undefined
843
843
  * Answers claims through its type, lint, and runtime stages.
844
844
  *
845
845
  * @remarks
846
+ * The workspace peers are TypeScript `^6.0.3 || ^7.0.2` and Vitest `^4.1.12 || ^5.0.5`.
847
+ * Starting refuses TypeScript majors outside 6 and 7 before a stage starts.
846
848
  * Construction resolves the target workspace's toolchain. Starting warms every stage and waits
847
849
  * for lint and runtime; type warming and the boot controls continue behind that gate. The boot
848
850
  * controls mutate imported dependencies and refuse service unless the type and runtime stages
@@ -891,7 +893,7 @@ export declare function parseRevisionOwner(revision: string): number | undefined
891
893
  * const probe = new Probe({ workspace: process.cwd() })
892
894
  * const verdict = await probe.prove(claim)
893
895
  * verdict.digest // 'bdf03e5dfd6bd413ead671c7a2940fcf'
894
- * verdict.receipt // 'probe:bdf03e5dfd6bd413ead671c7a2940fcf:type:typescript@6.0.3:oxlint@1.89.0:vitest@4.1.12:configs/src/tsconfig.core.json@434f59254d58cf2683d453a26bd0d837'
896
+ * verdict.receipt?.startsWith(`probe:${verdict.digest}:type:`) // true
895
897
  * await probe.destroy()
896
898
  * ```
897
899
  */
@@ -1183,6 +1185,8 @@ export declare function releaseListeners(emitter: EventEmitter, capture: Listene
1183
1185
  * @remarks
1184
1186
  * A package publishes its binaries under keys of its own choosing, and that key is often not the
1185
1187
  * package name: `typescript` publishes `tsc`. Name the key as `command` wherever the two differ.
1188
+ * Resolution reads `package.json` and its `bin` field, so TypeScript 6 and 7 need no exported
1189
+ * `typescript/bin/tsc` subpath.
1186
1190
  * Default: the package name.
1187
1191
  *
1188
1192
  * @param workspace - The target workspace root
@@ -1247,6 +1251,11 @@ export declare function resolveWorkspaceModule(workspace: string, specifier: str
1247
1251
  * Inspects tests through one resident Vitest service from the target workspace.
1248
1252
  *
1249
1253
  * @remarks
1254
+ * Vitest 4.1.12 and 5.0.5 share the mode-first `createVitest` overload used by this stage.
1255
+ * Result eviction removes one file from Vitest 4's results cache. Vitest 5 exposes only a full
1256
+ * cache clear, so eviction clears its results, dependency, and filesystem module caches.
1257
+ * Warming removes termination handlers registered within the factory's async context before
1258
+ * signal delivery, while retaining handlers the host registers outside that context.
1250
1259
  * Starting launches Vitest with the threads pool and instruments each inline or function-declared
1251
1260
  * project with a Vite plugin that reads the active inspection's candidate overlay. A selected
1252
1261
  * string-declared project reports a workspace issue because its configuration carries no runtime
@@ -1447,6 +1456,8 @@ export declare interface StageInterface {
1447
1456
  * Inspects TypeScript source by running the target workspace's own compiler over a mirror of it.
1448
1457
  *
1449
1458
  * @remarks
1459
+ * TypeScript 6 and 7 run through the `tsc` entry in their package manifest; neither a compiler API
1460
+ * nor an exported binary subpath is required.
1450
1461
  * The compiler is a process this stage spawns rather than a module it loads, so nothing here holds
1451
1462
  * a resident program and the host's event loop is free for the whole check. Starting sweeps a
1452
1463
  * mirror an earlier host left behind, copies the workspace into a fresh one under
@@ -1513,6 +1524,8 @@ export declare class TypeStage implements TypeStageInterface {
1513
1524
  * refreshed from the workspace first on a cache miss, so the digest names the configuration the
1514
1525
  * check applies. The reading is cached per project for the life of the stage, so a draft written
1515
1526
  * afterward cannot move it.
1527
+ * Before returning the identity, validates the project with `--noEmit` unless an unoverlaid check
1528
+ * already validated it. TypeScript 7's `--showConfig` can succeed for a malformed project.
1516
1529
  *
1517
1530
  * @param project - The workspace-relative TypeScript project to resolve
1518
1531
  * @returns The resolved workspace-relative path and the digest of its compiler options
@@ -1559,6 +1572,10 @@ export declare interface TypeStageInterface extends StageInterface {
1559
1572
  * Resolves one project to the path and digest the stage applies for it.
1560
1573
  * Calls `start()` before reading the project.
1561
1574
  *
1575
+ * @remarks
1576
+ * Validates the project with `--noEmit` unless warming or an earlier unoverlaid check already
1577
+ * validated it, because TypeScript 7's `--showConfig` can print partial JSON for a malformed project.
1578
+ *
1562
1579
  * @param project - The workspace-relative TypeScript project to resolve
1563
1580
  * @returns The resolved workspace-relative path and the digest of its compiler options
1564
1581
  * @throws When the project escapes the workspace, when the compiler refuses it, or when the
@@ -843,6 +843,8 @@ export declare function parseRevisionOwner(revision: string): number | undefined
843
843
  * Answers claims through its type, lint, and runtime stages.
844
844
  *
845
845
  * @remarks
846
+ * The workspace peers are TypeScript `^6.0.3 || ^7.0.2` and Vitest `^4.1.12 || ^5.0.5`.
847
+ * Starting refuses TypeScript majors outside 6 and 7 before a stage starts.
846
848
  * Construction resolves the target workspace's toolchain. Starting warms every stage and waits
847
849
  * for lint and runtime; type warming and the boot controls continue behind that gate. The boot
848
850
  * controls mutate imported dependencies and refuse service unless the type and runtime stages
@@ -891,7 +893,7 @@ export declare function parseRevisionOwner(revision: string): number | undefined
891
893
  * const probe = new Probe({ workspace: process.cwd() })
892
894
  * const verdict = await probe.prove(claim)
893
895
  * verdict.digest // 'bdf03e5dfd6bd413ead671c7a2940fcf'
894
- * verdict.receipt // 'probe:bdf03e5dfd6bd413ead671c7a2940fcf:type:typescript@6.0.3:oxlint@1.89.0:vitest@4.1.12:configs/src/tsconfig.core.json@434f59254d58cf2683d453a26bd0d837'
896
+ * verdict.receipt?.startsWith(`probe:${verdict.digest}:type:`) // true
895
897
  * await probe.destroy()
896
898
  * ```
897
899
  */
@@ -1183,6 +1185,8 @@ export declare function releaseListeners(emitter: EventEmitter, capture: Listene
1183
1185
  * @remarks
1184
1186
  * A package publishes its binaries under keys of its own choosing, and that key is often not the
1185
1187
  * package name: `typescript` publishes `tsc`. Name the key as `command` wherever the two differ.
1188
+ * Resolution reads `package.json` and its `bin` field, so TypeScript 6 and 7 need no exported
1189
+ * `typescript/bin/tsc` subpath.
1186
1190
  * Default: the package name.
1187
1191
  *
1188
1192
  * @param workspace - The target workspace root
@@ -1247,6 +1251,11 @@ export declare function resolveWorkspaceModule(workspace: string, specifier: str
1247
1251
  * Inspects tests through one resident Vitest service from the target workspace.
1248
1252
  *
1249
1253
  * @remarks
1254
+ * Vitest 4.1.12 and 5.0.5 share the mode-first `createVitest` overload used by this stage.
1255
+ * Result eviction removes one file from Vitest 4's results cache. Vitest 5 exposes only a full
1256
+ * cache clear, so eviction clears its results, dependency, and filesystem module caches.
1257
+ * Warming removes termination handlers registered within the factory's async context before
1258
+ * signal delivery, while retaining handlers the host registers outside that context.
1250
1259
  * Starting launches Vitest with the threads pool and instruments each inline or function-declared
1251
1260
  * project with a Vite plugin that reads the active inspection's candidate overlay. A selected
1252
1261
  * string-declared project reports a workspace issue because its configuration carries no runtime
@@ -1447,6 +1456,8 @@ export declare interface StageInterface {
1447
1456
  * Inspects TypeScript source by running the target workspace's own compiler over a mirror of it.
1448
1457
  *
1449
1458
  * @remarks
1459
+ * TypeScript 6 and 7 run through the `tsc` entry in their package manifest; neither a compiler API
1460
+ * nor an exported binary subpath is required.
1450
1461
  * The compiler is a process this stage spawns rather than a module it loads, so nothing here holds
1451
1462
  * a resident program and the host's event loop is free for the whole check. Starting sweeps a
1452
1463
  * mirror an earlier host left behind, copies the workspace into a fresh one under
@@ -1513,6 +1524,8 @@ export declare class TypeStage implements TypeStageInterface {
1513
1524
  * refreshed from the workspace first on a cache miss, so the digest names the configuration the
1514
1525
  * check applies. The reading is cached per project for the life of the stage, so a draft written
1515
1526
  * afterward cannot move it.
1527
+ * Before returning the identity, validates the project with `--noEmit` unless an unoverlaid check
1528
+ * already validated it. TypeScript 7's `--showConfig` can succeed for a malformed project.
1516
1529
  *
1517
1530
  * @param project - The workspace-relative TypeScript project to resolve
1518
1531
  * @returns The resolved workspace-relative path and the digest of its compiler options
@@ -1559,6 +1572,10 @@ export declare interface TypeStageInterface extends StageInterface {
1559
1572
  * Resolves one project to the path and digest the stage applies for it.
1560
1573
  * Calls `start()` before reading the project.
1561
1574
  *
1575
+ * @remarks
1576
+ * Validates the project with `--noEmit` unless warming or an earlier unoverlaid check already
1577
+ * validated it, because TypeScript 7's `--showConfig` can print partial JSON for a malformed project.
1578
+ *
1562
1579
  * @param project - The workspace-relative TypeScript project to resolve
1563
1580
  * @returns The resolved workspace-relative path and the digest of its compiler options
1564
1581
  * @throws When the project escapes the workspace, when the compiler refuses it, or when the
@@ -4,7 +4,7 @@ import { closeSync, constants, existsSync, ftruncateSync, lstatSync, mkdirSync,
4
4
  import { createHash, randomUUID } from "node:crypto";
5
5
  import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
6
  import { fileURLToPath, pathToFileURL } from "node:url";
7
- import { attempt, compileGuard, compileSchema, isArray, isError, isNumber, isObject, isRecord, isString, parseJSON, schemaToParameters } from "@orkestrel/contract";
7
+ import { attempt, compileGuard, compileSchema, isArray, isError, isFunction, isNumber, isObject, isRecord, isString, parseJSON, schemaToParameters } from "@orkestrel/contract";
8
8
  import { CLAIM_SHAPE, LINT_DEADLINE, LINT_TEARDOWN, PROBE_DEADLINE, PROBE_KEYS, PROBE_RESTARTS, PROBE_SPECIFICATIONS, PROBE_WARM, ProbeError, RUNTIME_PLUGIN, TYPE_MIRROR, computeReceipt, createDestroyedError, formatCheck, formatReceipt, formatSpecification, formatVerdict, isClaim, isDraft, isProbeError, isVerdict, matchesSpecification } from "../core/index.js";
9
9
  import { Emitter } from "@orkestrel/emitter";
10
10
  import { createPool, isPoolError } from "@orkestrel/pool";
@@ -13,6 +13,7 @@ import { addAbortListener } from "node:events";
13
13
  import { createTimeout } from "@orkestrel/timeout";
14
14
  import { createStdioClientTransport } from "@orkestrel/lsp/server";
15
15
  import { PassThrough } from "node:stream";
16
+ import { AsyncLocalStorage } from "node:async_hooks";
16
17
  import { spawn, spawnSync } from "node:child_process";
17
18
  import { createStdioServer } from "@orkestrel/mcp/server";
18
19
  import { createTool, createToolManager } from "@orkestrel/tool";
@@ -532,6 +533,8 @@ function readWorkspaceManifest(workspace, name) {
532
533
  * @remarks
533
534
  * A package publishes its binaries under keys of its own choosing, and that key is often not the
534
535
  * package name: `typescript` publishes `tsc`. Name the key as `command` wherever the two differ.
536
+ * Resolution reads `package.json` and its `bin` field, so TypeScript 6 and 7 need no exported
537
+ * `typescript/bin/tsc` subpath.
535
538
  * Default: the package name.
536
539
  *
537
540
  * @param workspace - The target workspace root
@@ -974,7 +977,7 @@ function captureListeners(emitter, events) {
974
977
  */
975
978
  function releaseListeners(emitter, capture) {
976
979
  for (const [event, captured] of capture) for (const listener of emitter.listeners(event)) {
977
- if (captured.includes(listener)) continue;
980
+ if (captured.includes(listener) || !isFunction(listener)) continue;
978
981
  emitter.removeListener(event, listener);
979
982
  }
980
983
  }
@@ -1123,10 +1126,10 @@ var Overlay = class {
1123
1126
  };
1124
1127
  //#endregion
1125
1128
  //#region package.json
1126
- var version = "0.0.24";
1129
+ var version = "0.0.25";
1127
1130
  var peerDependencies = {
1128
- "typescript": "^6.0.3",
1129
- "vitest": "^4.1.12"
1131
+ "typescript": "^6.0.3 || ^7.0.2",
1132
+ "vitest": "^4.1.12 || ^5.0.5"
1130
1133
  };
1131
1134
  //#endregion
1132
1135
  //#region src/server/stages/LintStage.ts
@@ -1348,6 +1351,11 @@ var LintStage = class {
1348
1351
  * Inspects tests through one resident Vitest service from the target workspace.
1349
1352
  *
1350
1353
  * @remarks
1354
+ * Vitest 4.1.12 and 5.0.5 share the mode-first `createVitest` overload used by this stage.
1355
+ * Result eviction removes one file from Vitest 4's results cache. Vitest 5 exposes only a full
1356
+ * cache clear, so eviction clears its results, dependency, and filesystem module caches.
1357
+ * Warming removes termination handlers registered within the factory's async context before
1358
+ * signal delivery, while retaining handlers the host registers outside that context.
1351
1359
  * Starting launches Vitest with the threads pool and instruments each inline or function-declared
1352
1360
  * project with a Vite plugin that reads the active inspection's candidate overlay. A selected
1353
1361
  * string-declared project reports a workspace issue because its configuration carries no runtime
@@ -1572,38 +1580,46 @@ var RuntimeStage = class {
1572
1580
  this.#sweep();
1573
1581
  const output = new PassThrough();
1574
1582
  output.resume();
1583
+ const scope = new AsyncLocalStorage();
1584
+ const listener = this.#captureSignal.bind(this, scope);
1575
1585
  const signals = captureListeners(process, ["SIGINT", "SIGTERM"]);
1576
- let warming;
1586
+ process.on("newListener", listener);
1577
1587
  try {
1578
- warming = factory("test", {
1579
- root: this.#workspace,
1580
- config: resolveWorkspaceFile(this.#workspace, "vite.config.ts"),
1581
- watch: false,
1582
- run: true,
1583
- pool: "threads",
1584
- reporters: [{
1585
- onInit() {},
1586
- onTestRunEnd() {}
1587
- }]
1588
- }, { plugins: [{
1589
- name: "orkestrel-project-instrumentation",
1590
- enforce: "post",
1591
- config: this.#configure.bind(this)
1592
- }] }, {
1593
- stdout: output,
1594
- stderr: process.stderr
1588
+ return await scope.run(true, () => {
1589
+ try {
1590
+ return factory("test", {
1591
+ root: this.#workspace,
1592
+ config: resolveWorkspaceFile(this.#workspace, "vite.config.ts"),
1593
+ watch: false,
1594
+ run: true,
1595
+ pool: "threads",
1596
+ reporters: [{
1597
+ onInit() {},
1598
+ onTestRunEnd() {}
1599
+ }]
1600
+ }, { plugins: [{
1601
+ name: "orkestrel-project-instrumentation",
1602
+ enforce: "post",
1603
+ config: this.#configure.bind(this)
1604
+ }] }, {
1605
+ stdout: output,
1606
+ stderr: process.stderr
1607
+ });
1608
+ } finally {
1609
+ releaseListeners(process, signals);
1610
+ }
1595
1611
  });
1596
1612
  } catch (error) {
1597
1613
  throw this.#configuration(error);
1598
1614
  } finally {
1599
- releaseListeners(process, signals);
1600
- }
1601
- try {
1602
- return await warming;
1603
- } catch (error) {
1604
- throw this.#configuration(error);
1615
+ process.off("newListener", listener);
1616
+ scope.disable();
1605
1617
  }
1606
1618
  }
1619
+ #captureSignal(scope, event, listener) {
1620
+ if (scope.getStore() !== true || event !== "SIGINT" && event !== "SIGTERM") return;
1621
+ queueMicrotask(() => process.off(event, listener));
1622
+ }
1607
1623
  #configure(config) {
1608
1624
  const test = config.test;
1609
1625
  if (test?.projects === void 0) return;
@@ -1797,8 +1813,16 @@ var RuntimeStage = class {
1797
1813
  }
1798
1814
  vitest.watcher.onFileDelete(file);
1799
1815
  vitest.watcher.invalidates.delete(file);
1800
- vitest.cache.results.removeFromCache(normalizePath(relative(this.#workspace, file)));
1801
- await vitest.cache.results.writeToCache();
1816
+ const results = "results" in vitest.cache ? vitest.cache.results : void 0;
1817
+ if (isObject(results) && "removeFromCache" in results && typeof results.removeFromCache === "function" && "writeToCache" in results && typeof results.writeToCache === "function") {
1818
+ results.removeFromCache(normalizePath(relative(this.#workspace, file)));
1819
+ await results.writeToCache();
1820
+ } else if ("clearCache" in vitest && typeof vitest.clearCache === "function") await vitest.clearCache();
1821
+ else throw new ProbeError("Vitest exposes no cache eviction API", {
1822
+ origin: "instrument",
1823
+ code: "malformed",
1824
+ context: { stage: this.stage }
1825
+ });
1802
1826
  return [];
1803
1827
  } catch (error) {
1804
1828
  return [{
@@ -2007,6 +2031,8 @@ var RuntimeStage = class {
2007
2031
  * Inspects TypeScript source by running the target workspace's own compiler over a mirror of it.
2008
2032
  *
2009
2033
  * @remarks
2034
+ * TypeScript 6 and 7 run through the `tsc` entry in their package manifest; neither a compiler API
2035
+ * nor an exported binary subpath is required.
2010
2036
  * The compiler is a process this stage spawns rather than a module it loads, so nothing here holds
2011
2037
  * a resident program and the host's event loop is free for the whole check. Starting sweeps a
2012
2038
  * mirror an earlier host left behind, copies the workspace into a fresh one under
@@ -2044,6 +2070,7 @@ var TypeStage = class {
2044
2070
  #revision = `${process.pid}-${randomUUID()}`;
2045
2071
  #mirror;
2046
2072
  #configs = /* @__PURE__ */ new Map();
2073
+ #validated = /* @__PURE__ */ new Set();
2047
2074
  #mirrored = /* @__PURE__ */ new Map();
2048
2075
  #drafts = /* @__PURE__ */ new Set();
2049
2076
  #children = /* @__PURE__ */ new Set();
@@ -2097,6 +2124,8 @@ var TypeStage = class {
2097
2124
  * refreshed from the workspace first on a cache miss, so the digest names the configuration the
2098
2125
  * check applies. The reading is cached per project for the life of the stage, so a draft written
2099
2126
  * afterward cannot move it.
2127
+ * Before returning the identity, validates the project with `--noEmit` unless an unoverlaid check
2128
+ * already validated it. TypeScript 7's `--showConfig` can succeed for a malformed project.
2100
2129
  *
2101
2130
  * @param project - The workspace-relative TypeScript project to resolve
2102
2131
  * @returns The resolved workspace-relative path and the digest of its compiler options
@@ -2156,6 +2185,10 @@ var TypeStage = class {
2156
2185
  const contained = this.#contain(project);
2157
2186
  this.#progress += 1;
2158
2187
  const config = await this.#configure(contained);
2188
+ if (!this.#validated.has(contained)) {
2189
+ this.#refresh();
2190
+ await this.#check(contained, []);
2191
+ }
2159
2192
  return {
2160
2193
  path: contained,
2161
2194
  digest: computeDigest(this.#workspace, config.compilerOptions)
@@ -2175,6 +2208,7 @@ var TypeStage = class {
2175
2208
  });
2176
2209
  } catch {}
2177
2210
  this.#configs.clear();
2211
+ this.#validated.clear();
2178
2212
  this.#mirrored.clear();
2179
2213
  this.#drafts.clear();
2180
2214
  }
@@ -2348,7 +2382,9 @@ var TypeStage = class {
2348
2382
  }
2349
2383
  });
2350
2384
  }
2351
- return this.#issues(diagnostics, project);
2385
+ const issues = this.#issues(diagnostics, project, scratch);
2386
+ if (this.#drafts.size === 0) this.#validated.add(this.#contain(project));
2387
+ return issues;
2352
2388
  }
2353
2389
  #scratch(project, config, drafts) {
2354
2390
  const directory = dirname(project);
@@ -2373,13 +2409,13 @@ var TypeStage = class {
2373
2409
  writeFileSync(target, `${JSON.stringify(body, void 0, " ")}\n`, "utf8");
2374
2410
  return contained;
2375
2411
  }
2376
- #issues(diagnostics, project) {
2412
+ #issues(diagnostics, project, scratch) {
2377
2413
  const issues = [];
2378
2414
  for (const diagnostic of diagnostics) {
2379
2415
  const message = this.#translate(diagnostic.message);
2380
2416
  const resolved = diagnostic.path === void 0 ? void 0 : resolve(this.#mirror, diagnostic.path);
2381
2417
  const drafted = resolved !== void 0 && this.#drafts.has(escapesRoot(this.#mirror, resolved) ? relativeWorkspaceFile(this.#workspace, resolved) : relativeWorkspaceFile(this.#mirror, resolved));
2382
- if (resolved === void 0 || !drafted && extname(resolved) === ".json") throw new ProbeError(message, {
2418
+ if (resolved === void 0 || !drafted && extname(resolved) === ".json") throw new ProbeError(message.replaceAll(normalizePath(scratch), normalizePath(project)), {
2383
2419
  origin: "workspace",
2384
2420
  code: "malformed",
2385
2421
  context: {
@@ -2489,6 +2525,8 @@ var TypeStage = class {
2489
2525
  * Answers claims through its type, lint, and runtime stages.
2490
2526
  *
2491
2527
  * @remarks
2528
+ * The workspace peers are TypeScript `^6.0.3 || ^7.0.2` and Vitest `^4.1.12 || ^5.0.5`.
2529
+ * Starting refuses TypeScript majors outside 6 and 7 before a stage starts.
2492
2530
  * Construction resolves the target workspace's toolchain. Starting warms every stage and waits
2493
2531
  * for lint and runtime; type warming and the boot controls continue behind that gate. The boot
2494
2532
  * controls mutate imported dependencies and refuse service unless the type and runtime stages
@@ -2537,7 +2575,7 @@ var TypeStage = class {
2537
2575
  * const probe = new Probe({ workspace: process.cwd() })
2538
2576
  * const verdict = await probe.prove(claim)
2539
2577
  * verdict.digest // 'bdf03e5dfd6bd413ead671c7a2940fcf'
2540
- * verdict.receipt // 'probe:bdf03e5dfd6bd413ead671c7a2940fcf:type:typescript@6.0.3:oxlint@1.89.0:vitest@4.1.12:configs/src/tsconfig.core.json@434f59254d58cf2683d453a26bd0d837'
2578
+ * verdict.receipt?.startsWith(`probe:${verdict.digest}:type:`) // true
2541
2579
  * await probe.destroy()
2542
2580
  * ```
2543
2581
  */
@@ -3013,9 +3051,9 @@ var Probe = class {
3013
3051
  #support() {
3014
3052
  const version = this.#toolchain.typescript;
3015
3053
  const range = peerDependencies.typescript;
3016
- const supported = /^\^(\d+)\./u.exec(range)?.[1];
3017
3054
  const found = /^(\d+)\./u.exec(version)?.[1];
3018
- if (supported === void 0 || found !== supported) throw new ProbeError(`The supported TypeScript range is ${range}; found ${version}`, {
3055
+ const supported = range.split(" || ").some((entry) => /^\^(\d+)\./u.exec(entry)?.[1] === found);
3056
+ if (found === void 0 || !supported) throw new ProbeError(`The supported TypeScript range is ${range}; found ${version}`, {
3019
3057
  origin: "workspace",
3020
3058
  code: "malformed",
3021
3059
  context: {