@orkestrel/probe 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/main.js +1 -1
- package/dist/bin/main.js.map +1 -1
- package/dist/src/core/index.cjs +137 -3
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +189 -53
- package/dist/src/core/index.d.ts +189 -53
- package/dist/src/core/index.js +131 -4
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +161 -78
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +90 -32
- package/dist/src/server/index.d.ts +90 -32
- package/dist/src/server/index.js +162 -81
- package/dist/src/server/index.js.map +1 -1
- package/package.json +18 -18
|
@@ -38,6 +38,64 @@ function normalizePath(path) {
|
|
|
38
38
|
return path.replaceAll("\\", "/");
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
+
* Reads the condition code a native fault carries.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* A caller catches `unknown`, so every reading of a caught value's own property calls into code
|
|
45
|
+
* this package does not own: a proxy whose `has` trap throws and a value whose `code` getter throws
|
|
46
|
+
* both arrive here. The read is guarded, so a fault that refuses inspection reports no code rather
|
|
47
|
+
* than raising a second fault over the first. A `code` the host reports as anything other than a
|
|
48
|
+
* string is no code this package compares against, so it reports none either.
|
|
49
|
+
*
|
|
50
|
+
* One reading serves every site that classifies a native fault, so a host condition is admitted the
|
|
51
|
+
* same way wherever it is read.
|
|
52
|
+
*
|
|
53
|
+
* @param error - The caught value to read
|
|
54
|
+
* @returns The fault's `code` when it carries a string one; `undefined` otherwise
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* readFaultCode(Object.assign(new Error('no such file'), { code: 'ENOENT' })) // 'ENOENT'
|
|
59
|
+
* readFaultCode(new Error('the runtime stage was destroyed')) // undefined
|
|
60
|
+
* readFaultCode('ENOENT') // undefined
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
function readFaultCode(error) {
|
|
64
|
+
if (typeof error !== "object" || error === null) return void 0;
|
|
65
|
+
const fault = error;
|
|
66
|
+
const reading = (0, _orkestrel_contract.attempt)(() => "code" in fault ? fault.code : void 0);
|
|
67
|
+
if (!reading.success) return void 0;
|
|
68
|
+
return typeof reading.value === "string" ? reading.value : void 0;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Reports whether one path resolves outside the root it is read against.
|
|
72
|
+
*
|
|
73
|
+
* @remarks
|
|
74
|
+
* Containment decides which paths a claim may reach and which absolute paths a digest may rewrite,
|
|
75
|
+
* so one reading serves every site that asks the question. A target resolving to the root itself is
|
|
76
|
+
* contained, and each caller decides on its own what that empty relative path means for it.
|
|
77
|
+
*
|
|
78
|
+
* The test reads the relative path rather than a string prefix of the root, so a sibling directory
|
|
79
|
+
* whose name begins with the root's own text is outside rather than beneath it. An absolute
|
|
80
|
+
* relative path is the answer a host returns for two paths on different volumes, which no root
|
|
81
|
+
* contains.
|
|
82
|
+
*
|
|
83
|
+
* @param root - The root the target is read against
|
|
84
|
+
* @param target - The path to test, absolute or root-relative
|
|
85
|
+
* @returns True if the target resolves outside the root; false otherwise
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* escapesRoot('/srv/checkout', 'src/core/greeting.ts') // false
|
|
90
|
+
* escapesRoot('/srv/checkout', '../secrets.env') // true
|
|
91
|
+
* escapesRoot('/srv/checkout', '/srv/checkout-backup/secrets.env') // true
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
function escapesRoot(root, target) {
|
|
95
|
+
const path = (0, node_path.relative)((0, node_path.resolve)(root), (0, node_path.resolve)(root, target));
|
|
96
|
+
return path === ".." || path.startsWith(`..${node_path.sep}`) || (0, node_path.isAbsolute)(path);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
41
99
|
* Resolves a path inside a target workspace and rejects traversal outside it.
|
|
42
100
|
*
|
|
43
101
|
* @remarks
|
|
@@ -65,7 +123,7 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
|
|
|
65
123
|
const root = (0, node_path.resolve)(workspace);
|
|
66
124
|
const file = (0, node_path.resolve)(root, target);
|
|
67
125
|
const path = (0, node_path.relative)(root, file);
|
|
68
|
-
if (path === "" ||
|
|
126
|
+
if (path === "" || escapesRoot(root, file)) throw new _src_core.ProbeError(`Path escapes the workspace: ${target}`, {
|
|
69
127
|
origin: "claimant",
|
|
70
128
|
code: "refused",
|
|
71
129
|
context: { path: target }
|
|
@@ -78,18 +136,16 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
|
|
|
78
136
|
descendant = (0, node_path.resolve)(descendant, segment);
|
|
79
137
|
const outcome = (0, _orkestrel_contract.attempt)(() => (0, node_fs.lstatSync)(descendant));
|
|
80
138
|
if (!outcome.success) {
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
throw error;
|
|
139
|
+
const code = readFaultCode(outcome.error);
|
|
140
|
+
if (code === "ENOENT" || code === "ENOTDIR") break;
|
|
141
|
+
throw outcome.error;
|
|
84
142
|
}
|
|
85
143
|
if (outcome.value.isSymbolicLink()) throw new _src_core.ProbeError(`Path crosses a symbolic link: ${target}`, {
|
|
86
144
|
origin: "workspace",
|
|
87
145
|
code: "refused",
|
|
88
146
|
context: { path: target }
|
|
89
147
|
});
|
|
90
|
-
|
|
91
|
-
const remainder = (0, node_path.relative)(canonical, resolved);
|
|
92
|
-
if (remainder === ".." || remainder.startsWith(`..${node_path.sep}`) || (0, node_path.isAbsolute)(remainder)) throw new _src_core.ProbeError(`Path escapes the workspace: ${target}`, {
|
|
148
|
+
if (escapesRoot(canonical, (0, node_fs.realpathSync)(descendant))) throw new _src_core.ProbeError(`Path escapes the workspace: ${target}`, {
|
|
93
149
|
origin: "claimant",
|
|
94
150
|
code: "refused",
|
|
95
151
|
context: { path: target }
|
|
@@ -97,7 +153,8 @@ function resolveWorkspaceFile(workspace, target, mutate = false) {
|
|
|
97
153
|
}
|
|
98
154
|
} catch (error) {
|
|
99
155
|
if (error instanceof _src_core.ProbeError) throw error;
|
|
100
|
-
const
|
|
156
|
+
const code = readFaultCode(error);
|
|
157
|
+
const claimant = code === "ENAMETOOLONG" || code === "ERR_INVALID_ARG_VALUE";
|
|
101
158
|
throw new _src_core.ProbeError(`The workspace path cannot be inspected: ${target}`, {
|
|
102
159
|
origin: claimant ? "claimant" : "workspace",
|
|
103
160
|
code: claimant ? "refused" : "malformed",
|
|
@@ -177,7 +234,7 @@ function overwriteFile(file, text) {
|
|
|
177
234
|
*
|
|
178
235
|
* @param file - The path whose creation failed
|
|
179
236
|
* @param error - The fault the failed operation raised
|
|
180
|
-
* @returns True
|
|
237
|
+
* @returns True if the fault means the host refuses this name; false otherwise
|
|
181
238
|
*
|
|
182
239
|
* @example
|
|
183
240
|
* ```ts
|
|
@@ -190,11 +247,7 @@ function overwriteFile(file, text) {
|
|
|
190
247
|
* ```
|
|
191
248
|
*/
|
|
192
249
|
function isRefusedName(file, error) {
|
|
193
|
-
|
|
194
|
-
const fault = error;
|
|
195
|
-
const reading = (0, _orkestrel_contract.attempt)(() => "code" in fault ? fault.code : void 0);
|
|
196
|
-
if (!reading.success) return false;
|
|
197
|
-
const code = reading.value;
|
|
250
|
+
const code = readFaultCode(error);
|
|
198
251
|
if (code === "ENAMETOOLONG") return true;
|
|
199
252
|
if (code === "ERR_INVALID_ARG_VALUE") return file.includes("\0");
|
|
200
253
|
if (code !== "ENOENT") return false;
|
|
@@ -289,7 +342,7 @@ function resolveWorkspaceModule(workspace, specifier) {
|
|
|
289
342
|
const outcome = (0, _orkestrel_contract.attempt)(() => (0, node_module.createRequire)((0, node_path.resolve)(workspace, "package.json")).resolve(specifier));
|
|
290
343
|
if (outcome.success) return outcome.value;
|
|
291
344
|
const error = outcome.error;
|
|
292
|
-
const missing =
|
|
345
|
+
const missing = readFaultCode(error) === "MODULE_NOT_FOUND";
|
|
293
346
|
throw new _src_core.ProbeError(`The workspace cannot resolve ${specifier}`, {
|
|
294
347
|
origin: "workspace",
|
|
295
348
|
code: missing ? "missing" : "malformed",
|
|
@@ -304,7 +357,7 @@ function loadWorkspaceModule(workspace, specifier) {
|
|
|
304
357
|
});
|
|
305
358
|
if (outcome.success) return outcome.value;
|
|
306
359
|
const error = outcome.error;
|
|
307
|
-
const missing =
|
|
360
|
+
const missing = readFaultCode(error) === "MODULE_NOT_FOUND";
|
|
308
361
|
throw new _src_core.ProbeError(`The workspace cannot load ${specifier}`, {
|
|
309
362
|
origin: "workspace",
|
|
310
363
|
code: missing ? "missing" : "malformed",
|
|
@@ -342,7 +395,8 @@ function readWorkspaceManifest(workspace, name) {
|
|
|
342
395
|
const reading = (0, _orkestrel_contract.attempt)(() => (0, node_fs.readFileSync)(path, "utf8"));
|
|
343
396
|
if (!reading.success) {
|
|
344
397
|
const error = reading.error;
|
|
345
|
-
const
|
|
398
|
+
const code = readFaultCode(error);
|
|
399
|
+
const missing = code === "ENOENT" || code === "ENOTDIR";
|
|
346
400
|
throw new _src_core.ProbeError(`${name} does not publish a readable manifest`, {
|
|
347
401
|
origin: "workspace",
|
|
348
402
|
code: missing ? "missing" : "malformed",
|
|
@@ -486,23 +540,24 @@ function inferDocumentLanguage(path) {
|
|
|
486
540
|
return "typescript";
|
|
487
541
|
}
|
|
488
542
|
/**
|
|
489
|
-
*
|
|
543
|
+
* Builds the fresh sibling path a revision's file is written at, preserving the test's resolution
|
|
544
|
+
* directory.
|
|
490
545
|
*
|
|
491
546
|
* @param workspace - The target workspace root
|
|
492
547
|
* @param path - The workspace-relative test path
|
|
493
548
|
* @param revision - The fresh revision identity
|
|
494
|
-
* @returns
|
|
549
|
+
* @returns The absolute sibling path
|
|
495
550
|
*
|
|
496
551
|
* @example
|
|
497
552
|
* ```ts
|
|
498
553
|
* relativeWorkspaceFile(
|
|
499
554
|
* '/srv/checkout',
|
|
500
|
-
*
|
|
555
|
+
* buildRevisionPath('/srv/checkout', 'tmp/probe/greeting.test.ts', '4821-9f0c'),
|
|
501
556
|
* )
|
|
502
557
|
* // 'tmp/probe/greeting.test.probe-4821-9f0c.ts'
|
|
503
558
|
* ```
|
|
504
559
|
*/
|
|
505
|
-
function
|
|
560
|
+
function buildRevisionPath(workspace, path, revision) {
|
|
506
561
|
const file = resolveWorkspaceFile(workspace, path);
|
|
507
562
|
const extension = (0, node_path.extname)(file);
|
|
508
563
|
return `${extension === "" ? file : file.slice(0, -extension.length)}.probe-${revision}${extension}`;
|
|
@@ -511,7 +566,7 @@ function createRevisionFile(workspace, path, revision) {
|
|
|
511
566
|
* Reports whether a path is a workspace module Vitest can cache.
|
|
512
567
|
*
|
|
513
568
|
* @param path - The candidate file path
|
|
514
|
-
* @returns True
|
|
569
|
+
* @returns True if the path is a script, TypeScript, Vue, or JSON module; false otherwise
|
|
515
570
|
*
|
|
516
571
|
* @example
|
|
517
572
|
* ```ts
|
|
@@ -638,7 +693,7 @@ function normalizeValue(workspace, value) {
|
|
|
638
693
|
if (!(0, node_path.isAbsolute)(value)) return value;
|
|
639
694
|
const path = (0, node_path.relative)(root, (0, node_path.resolve)(value));
|
|
640
695
|
if (path === "") return ".";
|
|
641
|
-
if (
|
|
696
|
+
if (escapesRoot(root, value)) return value;
|
|
642
697
|
return normalizePath(path);
|
|
643
698
|
}
|
|
644
699
|
if ((0, _orkestrel_contract.isArray)(value)) return value.map((entry) => normalizeValue(workspace, entry));
|
|
@@ -824,11 +879,11 @@ var Overlay = class {
|
|
|
824
879
|
};
|
|
825
880
|
//#endregion
|
|
826
881
|
//#region package.json
|
|
827
|
-
var version = "0.0.
|
|
882
|
+
var version = "0.0.12";
|
|
828
883
|
var peerDependencies = {
|
|
829
|
-
"oxlint": "^1.
|
|
830
|
-
"typescript": "^6.0.
|
|
831
|
-
"vitest": "^4.1.
|
|
884
|
+
"oxlint": "^1.80.0",
|
|
885
|
+
"typescript": "^6.0.3",
|
|
886
|
+
"vitest": "^4.1.11"
|
|
832
887
|
};
|
|
833
888
|
//#endregion
|
|
834
889
|
//#region src/server/stages/LintStage.ts
|
|
@@ -837,10 +892,11 @@ var peerDependencies = {
|
|
|
837
892
|
*
|
|
838
893
|
* @remarks
|
|
839
894
|
* Construction starts the target workspace's Oxlint binary with its Language Server Protocol mode
|
|
840
|
-
* and hands the conversation to `@orkestrel/lsp`: `
|
|
841
|
-
* its bytes, and `createLSPClient` owns the framing, the request correlation, the
|
|
842
|
-
* stage advertises, and the choice between pulled and pushed diagnostics. This
|
|
843
|
-
* workspace, the candidate identity, and the projection from a diagnostic to an
|
|
895
|
+
* and hands the conversation to `@orkestrel/lsp`: `createStdioClientTransport` owns the child
|
|
896
|
+
* process and its bytes, and `createLSPClient` owns the framing, the request correlation, the
|
|
897
|
+
* capabilities this stage advertises, and the choice between pulled and pushed diagnostics. This
|
|
898
|
+
* stage owns the workspace, the candidate identity, and the projection from a diagnostic to an
|
|
899
|
+
* `Issue`.
|
|
844
900
|
*
|
|
845
901
|
* Each inspection opens the supplied text by URI, waits for the client's diagnostics, and closes the
|
|
846
902
|
* document without writing it to disk. The caller's own signal is what bounds that wait, so a server
|
|
@@ -870,7 +926,6 @@ var peerDependencies = {
|
|
|
870
926
|
*/
|
|
871
927
|
var LintStage = class {
|
|
872
928
|
#workspace;
|
|
873
|
-
#deadline = 2e3;
|
|
874
929
|
#documents = /* @__PURE__ */ new Set();
|
|
875
930
|
#warmth;
|
|
876
931
|
#client;
|
|
@@ -878,7 +933,6 @@ var LintStage = class {
|
|
|
878
933
|
#closing;
|
|
879
934
|
#progress = 0;
|
|
880
935
|
#revision = 0;
|
|
881
|
-
#destroyed = false;
|
|
882
936
|
/**
|
|
883
937
|
* Starts warming the target workspace's Oxlint language server.
|
|
884
938
|
*
|
|
@@ -900,12 +954,11 @@ var LintStage = class {
|
|
|
900
954
|
}
|
|
901
955
|
destroy() {
|
|
902
956
|
if (this.#closing !== void 0) return this.#closing;
|
|
903
|
-
this.#destroyed = true;
|
|
904
957
|
this.#closing = guardStage(this.stage, this.#destroy());
|
|
905
958
|
return this.#closing;
|
|
906
959
|
}
|
|
907
960
|
async #inspect(subject, options) {
|
|
908
|
-
if (this.#
|
|
961
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("lint stage");
|
|
909
962
|
if (options === void 0) throw new _src_core.ProbeError("The lint stage inspects only under a bound its caller supplies", {
|
|
910
963
|
origin: "claimant",
|
|
911
964
|
code: "refused",
|
|
@@ -913,7 +966,7 @@ var LintStage = class {
|
|
|
913
966
|
});
|
|
914
967
|
const started = performance.now();
|
|
915
968
|
const client = await this.#warmed();
|
|
916
|
-
if (this.#
|
|
969
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("lint stage");
|
|
917
970
|
const issues = [];
|
|
918
971
|
for (const draft of [...subject.files, subject.test]) issues.push(...await this.#document(client, draft, options.signal));
|
|
919
972
|
return {
|
|
@@ -928,7 +981,7 @@ var LintStage = class {
|
|
|
928
981
|
async #warm() {
|
|
929
982
|
const binary = resolveWorkspaceBinary(this.#workspace, "oxlint");
|
|
930
983
|
const client = (0, _orkestrel_lsp.createLSPClient)({
|
|
931
|
-
transport: (0, _orkestrel_lsp_server.
|
|
984
|
+
transport: (0, _orkestrel_lsp_server.createStdioClientTransport)({
|
|
932
985
|
server: {
|
|
933
986
|
command: [
|
|
934
987
|
process.execPath,
|
|
@@ -937,10 +990,10 @@ var LintStage = class {
|
|
|
937
990
|
],
|
|
938
991
|
directory: this.#workspace
|
|
939
992
|
},
|
|
940
|
-
grace:
|
|
993
|
+
grace: _src_core.LINT_DEADLINE / 2
|
|
941
994
|
}),
|
|
942
995
|
workspace: (0, node_url.pathToFileURL)(this.#workspace).href,
|
|
943
|
-
timeout:
|
|
996
|
+
timeout: _src_core.LINT_DEADLINE
|
|
944
997
|
});
|
|
945
998
|
this.#client = client;
|
|
946
999
|
client.emitter.on("exit", (exit) => this.#retire(exit));
|
|
@@ -998,7 +1051,7 @@ var LintStage = class {
|
|
|
998
1051
|
});
|
|
999
1052
|
}
|
|
1000
1053
|
#translate(error, path) {
|
|
1001
|
-
if (this.#
|
|
1054
|
+
if (this.#closing !== void 0) return (0, _src_core.createDestroyedError)("lint stage");
|
|
1002
1055
|
const ending = this.#ending;
|
|
1003
1056
|
if (ending !== void 0) return this.#fault(`The Oxlint language server exited with ${ending}`, error, path);
|
|
1004
1057
|
if (error instanceof Error) return error;
|
|
@@ -1053,6 +1106,11 @@ var LintStage = class {
|
|
|
1053
1106
|
* The runtime overlay leaves bare specifier resolution to Vite: it replaces a bare import only
|
|
1054
1107
|
* after Vite resolves that import to a covered file. The type stage overlays the declared test
|
|
1055
1108
|
* path, while this stage executes a generated sibling and overlays only the candidate files.
|
|
1109
|
+
* This stage mints its overlay with the default exact-match sensitivity, because it declares no
|
|
1110
|
+
* file-name case sensitivity to Vite. A covered path whose spelling an importer wrote differs from
|
|
1111
|
+
* the recorded candidate path is therefore served by whatever answers first, and `#misses` reports
|
|
1112
|
+
* it as `The workspace configuration served this module before the runtime overlay` with origin
|
|
1113
|
+
* `workspace` rather than leaving it answered silently.
|
|
1056
1114
|
*
|
|
1057
1115
|
* Vite retains one unresolved URL for every specification path, so the stage replaces its whole
|
|
1058
1116
|
* Vitest service after 64 specifications rather than deleting from each map that service owns. Any
|
|
@@ -1101,7 +1159,6 @@ var RuntimeStage = class {
|
|
|
1101
1159
|
#specifications = 0;
|
|
1102
1160
|
#closing;
|
|
1103
1161
|
#progress = 0;
|
|
1104
|
-
#destroyed = false;
|
|
1105
1162
|
/**
|
|
1106
1163
|
* Starts warming the target workspace's Vitest service.
|
|
1107
1164
|
*
|
|
@@ -1123,16 +1180,15 @@ var RuntimeStage = class {
|
|
|
1123
1180
|
}
|
|
1124
1181
|
destroy() {
|
|
1125
1182
|
if (this.#closing !== void 0) return this.#closing;
|
|
1126
|
-
this.#destroyed = true;
|
|
1127
1183
|
this.#closing = guardStage(this.stage, this.#destroy());
|
|
1128
1184
|
return this.#closing;
|
|
1129
1185
|
}
|
|
1130
1186
|
async #inspect(subject) {
|
|
1131
|
-
if (this.#
|
|
1187
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("runtime stage");
|
|
1132
1188
|
const started = performance.now();
|
|
1133
1189
|
const exitCode = process.exitCode;
|
|
1134
1190
|
const vitest = await this.#runner();
|
|
1135
|
-
if (this.#
|
|
1191
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("runtime stage");
|
|
1136
1192
|
const project = this.#project(vitest, subject.test.path);
|
|
1137
1193
|
if ("message" in project) return {
|
|
1138
1194
|
stage: this.stage,
|
|
@@ -1274,7 +1330,7 @@ var RuntimeStage = class {
|
|
|
1274
1330
|
return {
|
|
1275
1331
|
...config,
|
|
1276
1332
|
plugins: [...config.plugins ?? [], {
|
|
1277
|
-
name:
|
|
1333
|
+
name: _src_core.RUNTIME_PLUGIN,
|
|
1278
1334
|
enforce: "pre",
|
|
1279
1335
|
resolveId: this.#resolve.bind(this),
|
|
1280
1336
|
load: this.#load.bind(this)
|
|
@@ -1316,7 +1372,7 @@ var RuntimeStage = class {
|
|
|
1316
1372
|
let generated;
|
|
1317
1373
|
const outcome = (0, _orkestrel_contract.attempt)(() => {
|
|
1318
1374
|
const revision = `${process.pid}-${(0, node_crypto.randomUUID)()}`;
|
|
1319
|
-
const file =
|
|
1375
|
+
const file = buildRevisionPath(this.#workspace, test.path, revision);
|
|
1320
1376
|
generated = file;
|
|
1321
1377
|
const target = (0, node_path.relative)(this.#workspace, file);
|
|
1322
1378
|
resolveWorkspaceFile(this.#workspace, target, true);
|
|
@@ -1374,7 +1430,7 @@ var RuntimeStage = class {
|
|
|
1374
1430
|
path
|
|
1375
1431
|
}
|
|
1376
1432
|
});
|
|
1377
|
-
if (!project.vite.config.plugins.some((plugin) => plugin.name ===
|
|
1433
|
+
if (!project.vite.config.plugins.some((plugin) => plugin.name === _src_core.RUNTIME_PLUGIN)) return {
|
|
1378
1434
|
origin: "workspace",
|
|
1379
1435
|
path,
|
|
1380
1436
|
message: `The runtime stage cannot instrument the string-declared Vitest project ${name} because its configuration carries no runtime overlay plugin`
|
|
@@ -1463,14 +1519,14 @@ var RuntimeStage = class {
|
|
|
1463
1519
|
}
|
|
1464
1520
|
#runner() {
|
|
1465
1521
|
const current = this.#vitest;
|
|
1466
|
-
if (current !== void 0 && this.#specifications <
|
|
1522
|
+
if (current !== void 0 && this.#specifications < _src_core.PROBE_SPECIFICATIONS) return current;
|
|
1467
1523
|
if (current !== void 0) return this.#store(this.#replace(current));
|
|
1468
1524
|
const runner = loadWorkspaceModule(this.#workspace, "vitest/node");
|
|
1469
|
-
return this.#store(this.#specifications <
|
|
1525
|
+
return this.#store(this.#specifications < _src_core.PROBE_SPECIFICATIONS ? this.#warm(runner.createVitest) : this.#replace(void 0, runner.createVitest));
|
|
1470
1526
|
}
|
|
1471
1527
|
async #replace(current, create) {
|
|
1472
1528
|
if (current !== void 0) await (await current).close();
|
|
1473
|
-
if (this.#
|
|
1529
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("runtime stage");
|
|
1474
1530
|
const runner = create ?? loadWorkspaceModule(this.#workspace, "vitest/node").createVitest;
|
|
1475
1531
|
const replacement = await this.#warm(runner);
|
|
1476
1532
|
this.#specifications = 0;
|
|
@@ -1548,7 +1604,7 @@ var RuntimeStage = class {
|
|
|
1548
1604
|
process.kill(id, 0);
|
|
1549
1605
|
return true;
|
|
1550
1606
|
} catch (error) {
|
|
1551
|
-
return error
|
|
1607
|
+
return readFaultCode(error) === "EPERM";
|
|
1552
1608
|
}
|
|
1553
1609
|
}
|
|
1554
1610
|
*#walk() {
|
|
@@ -1721,7 +1777,6 @@ var TypeStage = class {
|
|
|
1721
1777
|
#recycled;
|
|
1722
1778
|
#closing;
|
|
1723
1779
|
#progress = 0;
|
|
1724
|
-
#destroyed = false;
|
|
1725
1780
|
/**
|
|
1726
1781
|
* Starts warming the target workspace's TypeScript service.
|
|
1727
1782
|
*
|
|
@@ -1775,15 +1830,14 @@ var TypeStage = class {
|
|
|
1775
1830
|
}
|
|
1776
1831
|
destroy() {
|
|
1777
1832
|
if (this.#closing !== void 0) return this.#closing;
|
|
1778
|
-
this.#destroyed = true;
|
|
1779
1833
|
this.#closing = guardStage(this.stage, this.#destroy());
|
|
1780
1834
|
return this.#closing;
|
|
1781
1835
|
}
|
|
1782
1836
|
async #inspect(subject, project) {
|
|
1783
|
-
if (this.#
|
|
1837
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("type stage");
|
|
1784
1838
|
const started = performance.now();
|
|
1785
1839
|
const typescript = await this.#typescript;
|
|
1786
|
-
if (this.#
|
|
1840
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("type stage");
|
|
1787
1841
|
const selections = subject.files.map((draft) => ({
|
|
1788
1842
|
draft,
|
|
1789
1843
|
path: resolveWorkspaceFile(this.#workspace, draft.path)
|
|
@@ -1827,9 +1881,9 @@ var TypeStage = class {
|
|
|
1827
1881
|
}
|
|
1828
1882
|
}
|
|
1829
1883
|
async #resolve(project) {
|
|
1830
|
-
if (this.#
|
|
1884
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("type stage");
|
|
1831
1885
|
const typescript = await this.#typescript;
|
|
1832
|
-
if (this.#
|
|
1886
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("type stage");
|
|
1833
1887
|
const resolved = resolveWorkspaceFile(this.#workspace, project);
|
|
1834
1888
|
this.#progress += 1;
|
|
1835
1889
|
this.#service(typescript, project);
|
|
@@ -1872,7 +1926,7 @@ var TypeStage = class {
|
|
|
1872
1926
|
}
|
|
1873
1927
|
async #unblock() {
|
|
1874
1928
|
await (0, node_timers_promises.setTimeout)(0);
|
|
1875
|
-
if (this.#
|
|
1929
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("type stage");
|
|
1876
1930
|
}
|
|
1877
1931
|
#record(draft, overlay) {
|
|
1878
1932
|
overlay.set(resolveWorkspaceFile(this.#workspace, draft.path), draft.text);
|
|
@@ -2060,7 +2114,6 @@ var Probe = class {
|
|
|
2060
2114
|
#typeTail = Promise.resolve();
|
|
2061
2115
|
#arming;
|
|
2062
2116
|
#closing;
|
|
2063
|
-
#destroyed = false;
|
|
2064
2117
|
/**
|
|
2065
2118
|
* Resolves the target toolchain and starts warming the resident stages.
|
|
2066
2119
|
*
|
|
@@ -2068,7 +2121,7 @@ var Probe = class {
|
|
|
2068
2121
|
*/
|
|
2069
2122
|
constructor(options) {
|
|
2070
2123
|
this.#workspace = options?.workspace ?? process.cwd();
|
|
2071
|
-
this.#deadline = (0, _orkestrel_timeout.createTimeout)({ ms: options?.deadline ??
|
|
2124
|
+
this.#deadline = (0, _orkestrel_timeout.createTimeout)({ ms: options?.deadline ?? _src_core.PROBE_DEADLINE }).ms;
|
|
2072
2125
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
2073
2126
|
...options?.on === void 0 ? {} : { on: options.on },
|
|
2074
2127
|
...options?.error === void 0 ? {} : { error: options.error }
|
|
@@ -2110,7 +2163,7 @@ var Probe = class {
|
|
|
2110
2163
|
this.#support();
|
|
2111
2164
|
this.#admit(claim);
|
|
2112
2165
|
await this.#ready();
|
|
2113
|
-
if (this.#
|
|
2166
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe");
|
|
2114
2167
|
const started = performance.now();
|
|
2115
2168
|
const id = (0, node_crypto.randomUUID)();
|
|
2116
2169
|
const project = await this.#resolve(claim);
|
|
@@ -2144,7 +2197,6 @@ var Probe = class {
|
|
|
2144
2197
|
}
|
|
2145
2198
|
destroy() {
|
|
2146
2199
|
if (this.#closing !== void 0) return this.#closing;
|
|
2147
|
-
this.#destroyed = true;
|
|
2148
2200
|
this.#closing = this.#destroy();
|
|
2149
2201
|
return this.#closing;
|
|
2150
2202
|
}
|
|
@@ -2154,7 +2206,7 @@ var Probe = class {
|
|
|
2154
2206
|
await attempt;
|
|
2155
2207
|
return;
|
|
2156
2208
|
} catch (error) {
|
|
2157
|
-
if (this.#
|
|
2209
|
+
if (this.#closing !== void 0) throw error;
|
|
2158
2210
|
}
|
|
2159
2211
|
if (this.#arming === attempt) {
|
|
2160
2212
|
this.#arming = this.#arm();
|
|
@@ -2206,8 +2258,8 @@ var Probe = class {
|
|
|
2206
2258
|
}
|
|
2207
2259
|
async #boot(created) {
|
|
2208
2260
|
const revision = `${process.pid}-${(0, node_crypto.randomUUID)()}`;
|
|
2209
|
-
const typeDependency =
|
|
2210
|
-
const runtimeDependency =
|
|
2261
|
+
const typeDependency = buildRevisionPath(this.#workspace, "tmp/probe/arm-type.ts", revision);
|
|
2262
|
+
const runtimeDependency = buildRevisionPath(this.#workspace, "tmp/probe/arm-runtime.ts", revision);
|
|
2211
2263
|
const typeModule = (0, node_path.basename)(typeDependency, ".ts");
|
|
2212
2264
|
const runtimeModule = (0, node_path.basename)(runtimeDependency, ".ts");
|
|
2213
2265
|
const typeTest = {
|
|
@@ -2348,7 +2400,7 @@ var Probe = class {
|
|
|
2348
2400
|
}
|
|
2349
2401
|
}
|
|
2350
2402
|
async #recycle(stage) {
|
|
2351
|
-
if (this.#
|
|
2403
|
+
if (this.#closing !== void 0) return false;
|
|
2352
2404
|
const timeout = (0, _orkestrel_timeout.createTimeout)({ ms: this.#deadline });
|
|
2353
2405
|
timeout.start();
|
|
2354
2406
|
try {
|
|
@@ -2356,7 +2408,7 @@ var Probe = class {
|
|
|
2356
2408
|
} catch {} finally {
|
|
2357
2409
|
timeout.clear();
|
|
2358
2410
|
}
|
|
2359
|
-
if (this.#
|
|
2411
|
+
if (this.#closing !== void 0) return false;
|
|
2360
2412
|
if (stage === this.#type) {
|
|
2361
2413
|
this.#type = new TypeStage(this.#workspace);
|
|
2362
2414
|
return true;
|
|
@@ -2414,13 +2466,17 @@ var Probe = class {
|
|
|
2414
2466
|
}
|
|
2415
2467
|
async #destroy() {
|
|
2416
2468
|
try {
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2469
|
+
try {
|
|
2470
|
+
await this.#arming;
|
|
2471
|
+
} catch {}
|
|
2472
|
+
await Promise.all([
|
|
2473
|
+
this.#destroyStage(this.#type),
|
|
2474
|
+
this.#destroyStage(this.#lint),
|
|
2475
|
+
this.#destroyStage(this.#runtime)
|
|
2476
|
+
]);
|
|
2477
|
+
} finally {
|
|
2478
|
+
this.#emitter.destroy();
|
|
2479
|
+
}
|
|
2424
2480
|
}
|
|
2425
2481
|
async #destroyStage(stage) {
|
|
2426
2482
|
try {
|
|
@@ -2505,6 +2561,7 @@ var ProbeServer = class {
|
|
|
2505
2561
|
#close;
|
|
2506
2562
|
#error;
|
|
2507
2563
|
#signal;
|
|
2564
|
+
#server;
|
|
2508
2565
|
#owns;
|
|
2509
2566
|
#closing;
|
|
2510
2567
|
/**
|
|
@@ -2515,7 +2572,8 @@ var ProbeServer = class {
|
|
|
2515
2572
|
constructor(options) {
|
|
2516
2573
|
this.#probe = new Probe(options);
|
|
2517
2574
|
this.#stream = new node_stream.PassThrough();
|
|
2518
|
-
this.#
|
|
2575
|
+
this.#server = this.#publish();
|
|
2576
|
+
this.#transport = (0, _orkestrel_mcp_server.createStdioServer)((0, _orkestrel_mcp.createMCPLegacy)(this.#server), { input: this.#stream });
|
|
2519
2577
|
this.#data = this.#receive.bind(this);
|
|
2520
2578
|
this.#close = this.#finish.bind(this);
|
|
2521
2579
|
this.#error = this.#fail.bind(this);
|
|
@@ -2580,6 +2638,7 @@ var ProbeServer = class {
|
|
|
2580
2638
|
version
|
|
2581
2639
|
},
|
|
2582
2640
|
tools,
|
|
2641
|
+
limit: { keys: _src_core.PROBE_KEYS },
|
|
2583
2642
|
execution: this.#execute.bind(this)
|
|
2584
2643
|
});
|
|
2585
2644
|
}
|
|
@@ -2602,13 +2661,35 @@ var ProbeServer = class {
|
|
|
2602
2661
|
code: "malformed",
|
|
2603
2662
|
context: { value: result.value }
|
|
2604
2663
|
});
|
|
2605
|
-
|
|
2664
|
+
const record = result.value;
|
|
2665
|
+
const limit = this.#server.limit;
|
|
2666
|
+
const bounds = {
|
|
2667
|
+
bytes: limit.content,
|
|
2668
|
+
keys: limit.keys,
|
|
2669
|
+
depth: limit.depth
|
|
2670
|
+
};
|
|
2671
|
+
const rendered = {
|
|
2606
2672
|
resultType: "complete",
|
|
2607
2673
|
content: [{
|
|
2608
2674
|
type: "text",
|
|
2609
|
-
text: (0, _src_core.formatVerdict)(
|
|
2675
|
+
text: (0, _src_core.formatVerdict)(record)
|
|
2610
2676
|
}]
|
|
2611
2677
|
};
|
|
2678
|
+
const minimal = {
|
|
2679
|
+
resultType: "complete",
|
|
2680
|
+
content: [{
|
|
2681
|
+
type: "text",
|
|
2682
|
+
text: (0, _src_core.formatReceipt)(record)
|
|
2683
|
+
}]
|
|
2684
|
+
};
|
|
2685
|
+
return ((0, _orkestrel_mcp.isBoundedJSON)(record, bounds) ? [
|
|
2686
|
+
{
|
|
2687
|
+
...rendered,
|
|
2688
|
+
structuredContent: record
|
|
2689
|
+
},
|
|
2690
|
+
rendered,
|
|
2691
|
+
minimal
|
|
2692
|
+
] : [rendered, minimal]).find((arm) => (0, _orkestrel_mcp.isBoundedJSON)(arm, bounds)) ?? minimal;
|
|
2612
2693
|
}
|
|
2613
2694
|
};
|
|
2614
2695
|
//#endregion
|
|
@@ -2618,10 +2699,11 @@ exports.Probe = Probe;
|
|
|
2618
2699
|
exports.ProbeServer = ProbeServer;
|
|
2619
2700
|
exports.RuntimeStage = RuntimeStage;
|
|
2620
2701
|
exports.TypeStage = TypeStage;
|
|
2702
|
+
exports.buildRevisionPath = buildRevisionPath;
|
|
2621
2703
|
exports.captureListeners = captureListeners;
|
|
2622
2704
|
exports.computeDigest = computeDigest;
|
|
2623
|
-
exports.createRevisionFile = createRevisionFile;
|
|
2624
2705
|
exports.describeUnknown = describeUnknown;
|
|
2706
|
+
exports.escapesRoot = escapesRoot;
|
|
2625
2707
|
exports.findRefusedPaths = findRefusedPaths;
|
|
2626
2708
|
exports.guardStage = guardStage;
|
|
2627
2709
|
exports.inferDocumentLanguage = inferDocumentLanguage;
|
|
@@ -2633,6 +2715,7 @@ exports.matchesWorkspaceModule = matchesWorkspaceModule;
|
|
|
2633
2715
|
exports.normalizePath = normalizePath;
|
|
2634
2716
|
exports.normalizeValue = normalizeValue;
|
|
2635
2717
|
exports.overwriteFile = overwriteFile;
|
|
2718
|
+
exports.readFaultCode = readFaultCode;
|
|
2636
2719
|
exports.readWorkspaceManifest = readWorkspaceManifest;
|
|
2637
2720
|
exports.relativeWorkspaceFile = relativeWorkspaceFile;
|
|
2638
2721
|
exports.relativeWorkspaceMessage = relativeWorkspaceMessage;
|