@orkestrel/probe 0.0.20 → 0.0.22
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/README.md +6 -4
- package/dist/bin/main.js +1 -1
- package/dist/bin/main.js.map +1 -1
- package/dist/src/core/index.cjs +43 -3
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +69 -11
- package/dist/src/core/index.d.ts +69 -11
- package/dist/src/core/index.js +41 -4
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +345 -191
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +75 -37
- package/dist/src/server/index.d.ts +75 -37
- package/dist/src/server/index.js +346 -193
- package/dist/src/server/index.js.map +1 -1
- package/package.json +8 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let _orkestrel_mcp = require("@orkestrel/mcp");
|
|
2
3
|
let node_fs = require("node:fs");
|
|
3
4
|
let node_crypto = require("node:crypto");
|
|
4
5
|
let node_module = require("node:module");
|
|
@@ -7,15 +8,34 @@ let node_url = require("node:url");
|
|
|
7
8
|
let _orkestrel_contract = require("@orkestrel/contract");
|
|
8
9
|
let _src_core = require("../core/index.cjs");
|
|
9
10
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
10
|
-
let
|
|
11
|
-
let _orkestrel_timeout = require("@orkestrel/timeout");
|
|
11
|
+
let _orkestrel_pool = require("@orkestrel/pool");
|
|
12
12
|
let _orkestrel_lsp = require("@orkestrel/lsp");
|
|
13
|
+
let node_events = require("node:events");
|
|
14
|
+
let _orkestrel_timeout = require("@orkestrel/timeout");
|
|
13
15
|
let _orkestrel_lsp_server = require("@orkestrel/lsp/server");
|
|
14
16
|
let node_stream = require("node:stream");
|
|
15
17
|
let node_child_process = require("node:child_process");
|
|
16
|
-
let _orkestrel_mcp = require("@orkestrel/mcp");
|
|
17
18
|
let _orkestrel_mcp_server = require("@orkestrel/mcp/server");
|
|
18
19
|
let _orkestrel_tool = require("@orkestrel/tool");
|
|
20
|
+
//#region src/server/errors.ts
|
|
21
|
+
/**
|
|
22
|
+
* Creates the protocol failure returned when the MCP handshake cannot arm the probe.
|
|
23
|
+
*
|
|
24
|
+
* @param error - The classified probe failure that ended initialization
|
|
25
|
+
* @returns An MCP server error carrying the probe failure's origin and code as protocol data
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* createHandshakeError(createDestroyedError('probe server')).code // -32000
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
function createHandshakeError(error) {
|
|
33
|
+
return new _orkestrel_mcp.MCPError(`[${error.origin}] ${error.code}: ${error.message}`, _orkestrel_mcp.JSONRPC_SERVER_ERROR, {
|
|
34
|
+
origin: error.origin,
|
|
35
|
+
code: error.code
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
19
39
|
//#region src/server/helpers.ts
|
|
20
40
|
/**
|
|
21
41
|
* Rewrites one path into the forward-slash spelling this package compares and reports paths in.
|
|
@@ -1104,7 +1124,7 @@ var Overlay = class {
|
|
|
1104
1124
|
};
|
|
1105
1125
|
//#endregion
|
|
1106
1126
|
//#region package.json
|
|
1107
|
-
var version = "0.0.
|
|
1127
|
+
var version = "0.0.22";
|
|
1108
1128
|
var peerDependencies = {
|
|
1109
1129
|
"typescript": "^6.0.3",
|
|
1110
1130
|
"vitest": "^4.1.11"
|
|
@@ -1115,7 +1135,7 @@ var peerDependencies = {
|
|
|
1115
1135
|
* Inspects virtual documents through one resident Oxlint language server.
|
|
1116
1136
|
*
|
|
1117
1137
|
* @remarks
|
|
1118
|
-
*
|
|
1138
|
+
* Starting launches the target workspace's Oxlint binary with its Language Server Protocol mode
|
|
1119
1139
|
* and hands the conversation to `@orkestrel/lsp`: `createStdioClientTransport` owns the child
|
|
1120
1140
|
* process and its bytes, and `createLSPClient` owns the framing, the request correlation, the
|
|
1121
1141
|
* capabilities this stage advertises, and the choice between pulled and pushed diagnostics. This
|
|
@@ -1151,21 +1171,22 @@ var peerDependencies = {
|
|
|
1151
1171
|
var LintStage = class {
|
|
1152
1172
|
#workspace;
|
|
1153
1173
|
#documents = /* @__PURE__ */ new Set();
|
|
1154
|
-
#
|
|
1174
|
+
#warming;
|
|
1175
|
+
#exited = Promise.withResolvers();
|
|
1155
1176
|
#client;
|
|
1177
|
+
#transport;
|
|
1156
1178
|
#ending;
|
|
1157
1179
|
#closing;
|
|
1158
1180
|
#progress = 0;
|
|
1159
1181
|
#revision = 0;
|
|
1160
1182
|
/**
|
|
1161
|
-
*
|
|
1183
|
+
* Records the target workspace without starting its language server.
|
|
1162
1184
|
*
|
|
1163
1185
|
* @param workspace - The target workspace root. Default: the current working directory
|
|
1164
1186
|
*/
|
|
1165
1187
|
constructor(workspace = process.cwd()) {
|
|
1166
1188
|
this.#workspace = workspace;
|
|
1167
|
-
this.#
|
|
1168
|
-
this.#warmth.catch(() => {});
|
|
1189
|
+
this.#exited.promise.catch(() => {});
|
|
1169
1190
|
}
|
|
1170
1191
|
get stage() {
|
|
1171
1192
|
return "lint";
|
|
@@ -1173,6 +1194,15 @@ var LintStage = class {
|
|
|
1173
1194
|
get progress() {
|
|
1174
1195
|
return this.#progress;
|
|
1175
1196
|
}
|
|
1197
|
+
get exit() {
|
|
1198
|
+
return this.#exited.promise;
|
|
1199
|
+
}
|
|
1200
|
+
start() {
|
|
1201
|
+
if (this.#closing !== void 0) return Promise.reject((0, _src_core.createDestroyedError)("lint stage"));
|
|
1202
|
+
this.#warming ??= guardStage(this.stage, this.#warm());
|
|
1203
|
+
this.#warming.catch(() => {});
|
|
1204
|
+
return this.#warming;
|
|
1205
|
+
}
|
|
1176
1206
|
inspect(subject, options) {
|
|
1177
1207
|
return guardStage(this.stage, this.#inspect(subject, options));
|
|
1178
1208
|
}
|
|
@@ -1189,8 +1219,10 @@ var LintStage = class {
|
|
|
1189
1219
|
context: { stage: this.stage }
|
|
1190
1220
|
});
|
|
1191
1221
|
const started = performance.now();
|
|
1192
|
-
|
|
1222
|
+
await this.start();
|
|
1193
1223
|
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("lint stage");
|
|
1224
|
+
const client = this.#client;
|
|
1225
|
+
if (client === void 0) throw this.#fault("The Oxlint language server did not initialize");
|
|
1194
1226
|
const issues = [];
|
|
1195
1227
|
for (const draft of [...subject.files, subject.test]) issues.push(...await this.#document(client, draft, options.signal));
|
|
1196
1228
|
return {
|
|
@@ -1201,38 +1233,39 @@ var LintStage = class {
|
|
|
1201
1233
|
}
|
|
1202
1234
|
async #destroy() {
|
|
1203
1235
|
await this.#client?.destroy();
|
|
1236
|
+
await this.#transport?.close();
|
|
1204
1237
|
}
|
|
1205
1238
|
async #warm() {
|
|
1206
1239
|
const binary = resolveWorkspaceBinary(this.#workspace, "oxlint");
|
|
1240
|
+
const transport = (0, _orkestrel_lsp_server.createStdioClientTransport)({
|
|
1241
|
+
server: {
|
|
1242
|
+
command: [
|
|
1243
|
+
process.execPath,
|
|
1244
|
+
binary,
|
|
1245
|
+
"--lsp"
|
|
1246
|
+
],
|
|
1247
|
+
directory: this.#workspace
|
|
1248
|
+
},
|
|
1249
|
+
grace: _src_core.LINT_DEADLINE / 2
|
|
1250
|
+
});
|
|
1251
|
+
this.#transport = transport;
|
|
1207
1252
|
const client = (0, _orkestrel_lsp.createLSPClient)({
|
|
1208
|
-
transport
|
|
1209
|
-
server: {
|
|
1210
|
-
command: [
|
|
1211
|
-
process.execPath,
|
|
1212
|
-
binary,
|
|
1213
|
-
"--lsp"
|
|
1214
|
-
],
|
|
1215
|
-
directory: this.#workspace
|
|
1216
|
-
},
|
|
1217
|
-
grace: _src_core.LINT_DEADLINE / 2
|
|
1218
|
-
}),
|
|
1253
|
+
transport,
|
|
1219
1254
|
workspace: (0, node_url.pathToFileURL)(this.#workspace).href,
|
|
1220
1255
|
timeout: _src_core.LINT_DEADLINE
|
|
1221
1256
|
});
|
|
1222
1257
|
this.#client = client;
|
|
1223
1258
|
client.emitter.on("exit", (exit) => this.#retire(exit));
|
|
1224
|
-
await client.start();
|
|
1225
|
-
return client;
|
|
1226
|
-
}
|
|
1227
|
-
async #warmed() {
|
|
1228
1259
|
try {
|
|
1229
|
-
|
|
1260
|
+
await client.start();
|
|
1230
1261
|
} catch (error) {
|
|
1231
1262
|
throw this.#translate(error);
|
|
1232
1263
|
}
|
|
1233
1264
|
}
|
|
1234
1265
|
#retire(exit) {
|
|
1266
|
+
if (this.#closing !== void 0) return;
|
|
1235
1267
|
this.#ending = exit.signal === null ? `code ${exit.code}` : `signal ${exit.signal}`;
|
|
1268
|
+
this.#exited.reject(this.#fault(`The Oxlint language server exited with ${this.#ending}`));
|
|
1236
1269
|
}
|
|
1237
1270
|
async #document(client, draft, signal) {
|
|
1238
1271
|
const uri = (0, node_url.pathToFileURL)(resolveWorkspaceFile(this.#workspace, draft.path)).href;
|
|
@@ -1275,9 +1308,9 @@ var LintStage = class {
|
|
|
1275
1308
|
});
|
|
1276
1309
|
}
|
|
1277
1310
|
#translate(error, path) {
|
|
1278
|
-
if (this.#closing !== void 0) return (0, _src_core.createDestroyedError)("lint stage");
|
|
1279
1311
|
const ending = this.#ending;
|
|
1280
1312
|
if (ending !== void 0) return this.#fault(`The Oxlint language server exited with ${ending}`, error, path);
|
|
1313
|
+
if (this.#closing !== void 0) return (0, _src_core.createDestroyedError)("lint stage");
|
|
1281
1314
|
if ((0, _orkestrel_contract.isError)(error)) return error;
|
|
1282
1315
|
return this.#fault(describeUnknown(error), error, path);
|
|
1283
1316
|
}
|
|
@@ -1316,7 +1349,7 @@ var LintStage = class {
|
|
|
1316
1349
|
* Inspects tests through one resident Vitest service from the target workspace.
|
|
1317
1350
|
*
|
|
1318
1351
|
* @remarks
|
|
1319
|
-
*
|
|
1352
|
+
* Starting launches Vitest with the threads pool and instruments each inline or function-declared
|
|
1320
1353
|
* project with a Vite plugin that reads the active inspection's candidate overlay. A selected
|
|
1321
1354
|
* string-declared project reports a workspace issue because its configuration carries no runtime
|
|
1322
1355
|
* overlay plugin. Every inspection writes one fresh sibling specification, invalidates each
|
|
@@ -1375,6 +1408,7 @@ var LintStage = class {
|
|
|
1375
1408
|
var RuntimeStage = class {
|
|
1376
1409
|
#workspace;
|
|
1377
1410
|
#vitest;
|
|
1411
|
+
#warming;
|
|
1378
1412
|
#overlay = new Overlay();
|
|
1379
1413
|
#loads = /* @__PURE__ */ new Set();
|
|
1380
1414
|
#reads = /* @__PURE__ */ new Set();
|
|
@@ -1384,16 +1418,12 @@ var RuntimeStage = class {
|
|
|
1384
1418
|
#closing;
|
|
1385
1419
|
#progress = 0;
|
|
1386
1420
|
/**
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
* @remarks Loading starts during this call. A loader refusal rejects the owned warm operation
|
|
1390
|
-
* rather than construction, so `inspect` reports it and `destroy` remains available.
|
|
1421
|
+
* Records the target workspace without loading its Vitest service.
|
|
1391
1422
|
*
|
|
1392
1423
|
* @param workspace - The target workspace root. Default: the current working directory
|
|
1393
1424
|
*/
|
|
1394
1425
|
constructor(workspace = process.cwd()) {
|
|
1395
1426
|
this.#workspace = workspace;
|
|
1396
|
-
this.#store(this.#warm());
|
|
1397
1427
|
}
|
|
1398
1428
|
get stage() {
|
|
1399
1429
|
return "runtime";
|
|
@@ -1402,6 +1432,20 @@ var RuntimeStage = class {
|
|
|
1402
1432
|
return this.#progress;
|
|
1403
1433
|
}
|
|
1404
1434
|
/**
|
|
1435
|
+
* Begins the warm or joins the warm already begun.
|
|
1436
|
+
*
|
|
1437
|
+
* @returns A promise that resolves after the resident Vitest service is ready
|
|
1438
|
+
* @throws When warming fails or teardown has begun
|
|
1439
|
+
*/
|
|
1440
|
+
start() {
|
|
1441
|
+
if (this.#closing !== void 0) return Promise.reject((0, _src_core.createDestroyedError)("runtime stage"));
|
|
1442
|
+
this.#warming ??= guardStage(this.stage, this.#store(this.#warm()).then(() => {}));
|
|
1443
|
+
this.#warming.catch(() => {
|
|
1444
|
+
this.#warming = void 0;
|
|
1445
|
+
});
|
|
1446
|
+
return this.#warming;
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1405
1449
|
* Inspects one case.
|
|
1406
1450
|
*
|
|
1407
1451
|
* @param subject - The candidate drafts and test to inspect
|
|
@@ -1432,6 +1476,7 @@ var RuntimeStage = class {
|
|
|
1432
1476
|
async #inspect(subject) {
|
|
1433
1477
|
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("runtime stage");
|
|
1434
1478
|
const started = performance.now();
|
|
1479
|
+
await this.start();
|
|
1435
1480
|
const exitCode = process.exitCode;
|
|
1436
1481
|
const vitest = await this.#runner();
|
|
1437
1482
|
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("runtime stage");
|
|
@@ -1964,7 +2009,7 @@ var RuntimeStage = class {
|
|
|
1964
2009
|
*
|
|
1965
2010
|
* @remarks
|
|
1966
2011
|
* The compiler is a process this stage spawns rather than a module it loads, so nothing here holds
|
|
1967
|
-
* a resident program and the host's event loop is free for the whole check.
|
|
2012
|
+
* a resident program and the host's event loop is free for the whole check. Starting sweeps a
|
|
1968
2013
|
* mirror an earlier host left behind, copies the workspace into a fresh one under
|
|
1969
2014
|
* {@link TYPE_MIRROR}, and builds each declared project's incremental state there, so the first
|
|
1970
2015
|
* inspection is warm.
|
|
@@ -2007,16 +2052,13 @@ var TypeStage = class {
|
|
|
2007
2052
|
#closing;
|
|
2008
2053
|
#progress = 0;
|
|
2009
2054
|
/**
|
|
2010
|
-
*
|
|
2055
|
+
* Records the workspace and the mirror path without starting its compiler.
|
|
2011
2056
|
*
|
|
2012
2057
|
* @param workspace - The target workspace root. Default: the current working directory
|
|
2013
2058
|
*/
|
|
2014
2059
|
constructor(workspace = process.cwd()) {
|
|
2015
2060
|
this.#workspace = workspace;
|
|
2016
|
-
this.#
|
|
2017
|
-
this.#mirror = resolveWorkspaceFile(workspace, `${_src_core.TYPE_MIRROR}/${this.#revision}`);
|
|
2018
|
-
this.#warming = this.#warm();
|
|
2019
|
-
this.#warming.catch(() => {});
|
|
2061
|
+
this.#mirror = (0, node_path.resolve)(workspace, _src_core.TYPE_MIRROR, this.#revision);
|
|
2020
2062
|
}
|
|
2021
2063
|
get stage() {
|
|
2022
2064
|
return "type";
|
|
@@ -2024,6 +2066,12 @@ var TypeStage = class {
|
|
|
2024
2066
|
get progress() {
|
|
2025
2067
|
return this.#progress;
|
|
2026
2068
|
}
|
|
2069
|
+
start() {
|
|
2070
|
+
if (this.#closing !== void 0) return Promise.reject((0, _src_core.createDestroyedError)("type stage"));
|
|
2071
|
+
this.#warming ??= guardStage(this.stage, this.#warm());
|
|
2072
|
+
this.#warming.catch(() => {});
|
|
2073
|
+
return this.#warming;
|
|
2074
|
+
}
|
|
2027
2075
|
/**
|
|
2028
2076
|
* Inspects one case, against a caller-named project where the caller names one.
|
|
2029
2077
|
*
|
|
@@ -2067,7 +2115,7 @@ var TypeStage = class {
|
|
|
2067
2115
|
async #inspect(subject, project) {
|
|
2068
2116
|
this.#refuseDestroyed();
|
|
2069
2117
|
const started = performance.now();
|
|
2070
|
-
await this
|
|
2118
|
+
await this.start();
|
|
2071
2119
|
this.#refuseDestroyed();
|
|
2072
2120
|
const test = resolveWorkspaceFile(this.#workspace, subject.test.path);
|
|
2073
2121
|
const resolved = subject.files.map((draft) => ({
|
|
@@ -2103,6 +2151,8 @@ var TypeStage = class {
|
|
|
2103
2151
|
}
|
|
2104
2152
|
}
|
|
2105
2153
|
async #resolve(project) {
|
|
2154
|
+
this.#refuseDestroyed();
|
|
2155
|
+
await this.start();
|
|
2106
2156
|
this.#refuseDestroyed();
|
|
2107
2157
|
const contained = this.#contain(project);
|
|
2108
2158
|
this.#progress += 1;
|
|
@@ -2116,7 +2166,7 @@ var TypeStage = class {
|
|
|
2116
2166
|
const children = [...this.#children];
|
|
2117
2167
|
this.#children.clear();
|
|
2118
2168
|
for (const child of children) this.#terminate(child);
|
|
2119
|
-
await this.#warming
|
|
2169
|
+
await this.#warming?.catch(() => void 0);
|
|
2120
2170
|
try {
|
|
2121
2171
|
(0, node_fs.rmSync)(this.#mirror, {
|
|
2122
2172
|
recursive: true,
|
|
@@ -2130,6 +2180,7 @@ var TypeStage = class {
|
|
|
2130
2180
|
this.#drafts.clear();
|
|
2131
2181
|
}
|
|
2132
2182
|
async #warm() {
|
|
2183
|
+
this.#compiler = resolveWorkspaceBinary(this.#workspace, "typescript", "tsc");
|
|
2133
2184
|
this.#sweep();
|
|
2134
2185
|
this.#createMirror();
|
|
2135
2186
|
this.#refresh();
|
|
@@ -2364,8 +2415,10 @@ var TypeStage = class {
|
|
|
2364
2415
|
}
|
|
2365
2416
|
#spawn(args, cwd) {
|
|
2366
2417
|
this.#refuseDestroyed();
|
|
2418
|
+
const compiler = this.#compiler;
|
|
2419
|
+
if (compiler === void 0) throw (0, _src_core.createDestroyedError)("type stage");
|
|
2367
2420
|
return new Promise((settle, refuse) => {
|
|
2368
|
-
const child = (0, node_child_process.spawn)(process.execPath, [
|
|
2421
|
+
const child = (0, node_child_process.spawn)(process.execPath, [compiler, ...args], {
|
|
2369
2422
|
cwd,
|
|
2370
2423
|
stdio: [
|
|
2371
2424
|
"ignore",
|
|
@@ -2402,7 +2455,7 @@ var TypeStage = class {
|
|
|
2402
2455
|
code: "malformed",
|
|
2403
2456
|
context: {
|
|
2404
2457
|
stage: this.stage,
|
|
2405
|
-
path:
|
|
2458
|
+
path: compiler
|
|
2406
2459
|
},
|
|
2407
2460
|
cause: error
|
|
2408
2461
|
}));
|
|
@@ -2437,9 +2490,10 @@ var TypeStage = class {
|
|
|
2437
2490
|
* Answers claims through its type, lint, and runtime stages.
|
|
2438
2491
|
*
|
|
2439
2492
|
* @remarks
|
|
2440
|
-
* Construction resolves the target workspace's toolchain
|
|
2493
|
+
* Construction resolves the target workspace's toolchain. Starting warms every stage and waits
|
|
2494
|
+
* for lint and runtime; type warming and the boot controls continue behind that gate. The boot
|
|
2441
2495
|
* controls mutate imported dependencies and refuse service unless the type and runtime stages
|
|
2442
|
-
* report their respective changes. One
|
|
2496
|
+
* report their respective changes. One pool per stage admits inspections in arrival order, one at
|
|
2443
2497
|
* a time, so a stage never serves two claims at once and the deadline covers active work rather
|
|
2444
2498
|
* than queue wait. Each active stage inspection has a coordinator-owned deadline. An expiry at any
|
|
2445
2499
|
* stage abandons that stage and replaces it before the next queued inspection begins, so one slow
|
|
@@ -2484,34 +2538,36 @@ var TypeStage = class {
|
|
|
2484
2538
|
* const probe = new Probe({ workspace: process.cwd() })
|
|
2485
2539
|
* const verdict = await probe.prove(claim)
|
|
2486
2540
|
* verdict.digest // 'bdf03e5dfd6bd413ead671c7a2940fcf'
|
|
2487
|
-
* verdict.receipt // 'probe:bdf03e5dfd6bd413ead671c7a2940fcf:type:typescript@6.0.3:oxlint@1.
|
|
2541
|
+
* verdict.receipt // 'probe:bdf03e5dfd6bd413ead671c7a2940fcf:type:typescript@6.0.3:oxlint@1.87.0:vitest@4.1.11:configs/src/tsconfig.core.json@434f59254d58cf2683d453a26bd0d837'
|
|
2488
2542
|
* await probe.destroy()
|
|
2489
2543
|
* ```
|
|
2490
2544
|
*/
|
|
2491
2545
|
var Probe = class {
|
|
2492
2546
|
#workspace;
|
|
2493
2547
|
#deadline;
|
|
2548
|
+
#warmth;
|
|
2494
2549
|
#emitter;
|
|
2495
2550
|
#toolchain;
|
|
2496
2551
|
#type;
|
|
2497
2552
|
#lint;
|
|
2498
2553
|
#runtime;
|
|
2499
|
-
#typeQueue;
|
|
2500
|
-
#lintQueue;
|
|
2501
|
-
#runtimeQueue;
|
|
2502
2554
|
#deadlines = /* @__PURE__ */ new WeakSet();
|
|
2503
2555
|
#surfaced = /* @__PURE__ */ new WeakSet();
|
|
2504
|
-
#
|
|
2556
|
+
#survivors = /* @__PURE__ */ new Map();
|
|
2557
|
+
#abort = new AbortController();
|
|
2505
2558
|
#arming;
|
|
2559
|
+
#refusal;
|
|
2560
|
+
#starting;
|
|
2506
2561
|
#closing;
|
|
2507
2562
|
/**
|
|
2508
|
-
* Resolves the target toolchain and
|
|
2563
|
+
* Resolves the target toolchain and constructs the stage pools without warming them.
|
|
2509
2564
|
*
|
|
2510
|
-
* @param options - Workspace,
|
|
2565
|
+
* @param options - Workspace, inspection and warm bounds, and initial observation hooks
|
|
2511
2566
|
*/
|
|
2512
2567
|
constructor(options) {
|
|
2513
2568
|
this.#workspace = options?.workspace ?? process.cwd();
|
|
2514
2569
|
this.#deadline = (0, _orkestrel_timeout.createTimeout)({ ms: options?.deadline ?? _src_core.PROBE_DEADLINE }).ms;
|
|
2570
|
+
this.#warmth = (0, _orkestrel_timeout.createTimeout)({ ms: options?.warm ?? _src_core.PROBE_WARM }).ms;
|
|
2515
2571
|
this.#emitter = new _orkestrel_emitter.Emitter({
|
|
2516
2572
|
...options?.on === void 0 ? {} : { on: options.on },
|
|
2517
2573
|
...options?.error === void 0 ? {} : { error: options.error }
|
|
@@ -2521,26 +2577,28 @@ var Probe = class {
|
|
|
2521
2577
|
oxlint: this.#version("oxlint"),
|
|
2522
2578
|
vitest: this.#version("vitest")
|
|
2523
2579
|
});
|
|
2524
|
-
this.#type =
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
handler: this.#inspectType.bind(this)
|
|
2580
|
+
this.#type = (0, _orkestrel_pool.createPool)({
|
|
2581
|
+
create: () => this.#warm(new TypeStage(this.#workspace)),
|
|
2582
|
+
destroy: this.#dispose.bind(this),
|
|
2583
|
+
error: this.#surface.bind(this),
|
|
2584
|
+
min: 1,
|
|
2585
|
+
restarts: _src_core.PROBE_RESTARTS
|
|
2531
2586
|
});
|
|
2532
|
-
this.#
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2587
|
+
this.#lint = (0, _orkestrel_pool.createPool)({
|
|
2588
|
+
create: this.#createLint.bind(this),
|
|
2589
|
+
destroy: this.#dispose.bind(this),
|
|
2590
|
+
watch: (stage) => stage.exit,
|
|
2591
|
+
error: this.#surface.bind(this),
|
|
2592
|
+
min: 1,
|
|
2593
|
+
restarts: _src_core.PROBE_RESTARTS
|
|
2536
2594
|
});
|
|
2537
|
-
this.#
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2595
|
+
this.#runtime = (0, _orkestrel_pool.createPool)({
|
|
2596
|
+
create: () => this.#warm(new RuntimeStage(this.#workspace)),
|
|
2597
|
+
destroy: this.#dispose.bind(this),
|
|
2598
|
+
error: this.#surface.bind(this),
|
|
2599
|
+
min: 1,
|
|
2600
|
+
restarts: _src_core.PROBE_RESTARTS
|
|
2541
2601
|
});
|
|
2542
|
-
this.#arming = this.#arm();
|
|
2543
|
-
this.#arming.catch(() => {});
|
|
2544
2602
|
}
|
|
2545
2603
|
get emitter() {
|
|
2546
2604
|
return this.#emitter;
|
|
@@ -2552,7 +2610,16 @@ var Probe = class {
|
|
|
2552
2610
|
try {
|
|
2553
2611
|
this.#support();
|
|
2554
2612
|
this.#admit(claim);
|
|
2555
|
-
await this
|
|
2613
|
+
await this.start();
|
|
2614
|
+
const arming = this.#arming;
|
|
2615
|
+
try {
|
|
2616
|
+
await arming;
|
|
2617
|
+
} catch (error) {
|
|
2618
|
+
if (this.#arming === arming) this.#arming = void 0;
|
|
2619
|
+
const refusal = this.#refusal;
|
|
2620
|
+
this.#refusal = void 0;
|
|
2621
|
+
throw refusal === void 0 ? error : refusal.cause;
|
|
2622
|
+
}
|
|
2556
2623
|
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe");
|
|
2557
2624
|
const started = performance.now();
|
|
2558
2625
|
const id = (0, node_crypto.randomUUID)();
|
|
@@ -2587,45 +2654,65 @@ var Probe = class {
|
|
|
2587
2654
|
}
|
|
2588
2655
|
destroy() {
|
|
2589
2656
|
if (this.#closing !== void 0) return this.#closing;
|
|
2590
|
-
this.#closing = this.#destroy();
|
|
2657
|
+
this.#closing = Promise.resolve().then(this.#destroy.bind(this));
|
|
2591
2658
|
return this.#closing;
|
|
2592
2659
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2660
|
+
start() {
|
|
2661
|
+
if (this.#closing !== void 0) return Promise.reject((0, _src_core.createDestroyedError)("probe"));
|
|
2662
|
+
const warming = this.#type.start();
|
|
2663
|
+
warming.catch(() => {});
|
|
2664
|
+
const filling = Promise.all([this.#lint.start(), this.#runtime.start()]);
|
|
2665
|
+
filling.catch(() => {});
|
|
2666
|
+
if (this.#starting !== void 0) return this.#starting;
|
|
2667
|
+
this.#starting = this.#start(filling, warming);
|
|
2668
|
+
this.#starting.then(() => {
|
|
2669
|
+
this.#starting = void 0;
|
|
2670
|
+
}, () => {
|
|
2671
|
+
this.#starting = void 0;
|
|
2672
|
+
});
|
|
2673
|
+
return this.#starting;
|
|
2674
|
+
}
|
|
2675
|
+
async #start(filling, warming) {
|
|
2676
|
+
let created = false;
|
|
2595
2677
|
try {
|
|
2596
|
-
|
|
2597
|
-
|
|
2678
|
+
this.#support();
|
|
2679
|
+
if (this.#arming === void 0) created = this.#workbench();
|
|
2598
2680
|
} catch (error) {
|
|
2599
|
-
|
|
2681
|
+
this.#surface(error);
|
|
2682
|
+
throw error;
|
|
2683
|
+
}
|
|
2684
|
+
try {
|
|
2685
|
+
await filling;
|
|
2686
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe");
|
|
2687
|
+
} catch (error) {
|
|
2688
|
+
throw this.#refuseArm(error);
|
|
2600
2689
|
}
|
|
2601
|
-
if (this.#arming ===
|
|
2602
|
-
this.#arming = this.#arm();
|
|
2603
|
-
this.#arming.catch(() => {
|
|
2690
|
+
if (this.#arming === void 0) {
|
|
2691
|
+
this.#arming = this.#arm(warming, created);
|
|
2692
|
+
this.#arming.catch(() => {
|
|
2693
|
+
if (this.#refusal === void 0) this.#arming = void 0;
|
|
2694
|
+
});
|
|
2604
2695
|
}
|
|
2605
|
-
await this.#arming;
|
|
2606
2696
|
}
|
|
2607
|
-
async #arm() {
|
|
2608
|
-
let created;
|
|
2697
|
+
async #arm(warming, created) {
|
|
2609
2698
|
try {
|
|
2610
|
-
|
|
2699
|
+
await warming;
|
|
2611
2700
|
} catch (error) {
|
|
2612
|
-
this.#
|
|
2613
|
-
|
|
2701
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe");
|
|
2702
|
+
const cause = this.#refusal?.cause ?? ((0, _orkestrel_pool.isPoolError)(error) ? error.cause : error);
|
|
2703
|
+
this.#surface(cause);
|
|
2704
|
+
throw cause;
|
|
2614
2705
|
}
|
|
2615
2706
|
try {
|
|
2707
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe");
|
|
2616
2708
|
await this.#boot(created);
|
|
2617
2709
|
} catch (error) {
|
|
2618
|
-
|
|
2619
|
-
origin: "instrument",
|
|
2620
|
-
code: "malformed",
|
|
2621
|
-
cause: error
|
|
2622
|
-
});
|
|
2623
|
-
this.#surface(failure);
|
|
2624
|
-
throw failure;
|
|
2710
|
+
throw this.#refuseArm(error);
|
|
2625
2711
|
}
|
|
2626
2712
|
this.#emitter.emit("arm", this.#toolchain);
|
|
2627
2713
|
}
|
|
2628
2714
|
#surface(error) {
|
|
2715
|
+
if (this.#closing !== void 0) return;
|
|
2629
2716
|
if ((0, _src_core.isProbeError)(error)) this.#surfaced.add(error);
|
|
2630
2717
|
this.#emitter.emit("error", error);
|
|
2631
2718
|
}
|
|
@@ -2741,102 +2828,130 @@ var Probe = class {
|
|
|
2741
2828
|
subject,
|
|
2742
2829
|
claim
|
|
2743
2830
|
};
|
|
2744
|
-
|
|
2745
|
-
this.#
|
|
2746
|
-
this.#
|
|
2747
|
-
this.#
|
|
2748
|
-
];
|
|
2749
|
-
for (const pending of admitted) pending.catch(() => {});
|
|
2750
|
-
return Promise.all(admitted);
|
|
2831
|
+
return Promise.all([
|
|
2832
|
+
this.#inspectType(inspection),
|
|
2833
|
+
this.#inspectLint(inspection),
|
|
2834
|
+
this.#inspectRuntime(inspection)
|
|
2835
|
+
]);
|
|
2751
2836
|
}
|
|
2752
2837
|
async #inspectType(inspection) {
|
|
2753
|
-
const
|
|
2754
|
-
|
|
2755
|
-
const stage = this.#type;
|
|
2756
|
-
return await this.#inspectStage(stage, stage.progress, () => stage.inspect(inspection.subject, inspection.claim.project), inspection.claim);
|
|
2757
|
-
} finally {
|
|
2758
|
-
release();
|
|
2759
|
-
}
|
|
2838
|
+
const token = await this.#lease(this.#type);
|
|
2839
|
+
return this.#inspectStage(token, () => token.value.inspect(inspection.subject, inspection.claim.project), inspection.claim);
|
|
2760
2840
|
}
|
|
2761
|
-
#inspectLint(inspection) {
|
|
2762
|
-
const
|
|
2763
|
-
return this.#inspectStage(
|
|
2841
|
+
async #inspectLint(inspection) {
|
|
2842
|
+
const token = await this.#lease(this.#lint);
|
|
2843
|
+
return this.#inspectStage(token, (signal) => token.value.inspect(inspection.subject, { signal }), inspection.claim);
|
|
2764
2844
|
}
|
|
2765
|
-
#inspectRuntime(inspection) {
|
|
2766
|
-
const
|
|
2767
|
-
return this.#inspectStage(
|
|
2845
|
+
async #inspectRuntime(inspection) {
|
|
2846
|
+
const token = await this.#lease(this.#runtime);
|
|
2847
|
+
return this.#inspectStage(token, () => token.value.inspect(inspection.subject), inspection.claim);
|
|
2768
2848
|
}
|
|
2769
|
-
async #inspectStage(
|
|
2849
|
+
async #inspectStage(token, operation, claim, message = `The ${token.value.stage} stage exceeded ${this.#deadline} ms`) {
|
|
2850
|
+
const stage = token.value;
|
|
2770
2851
|
try {
|
|
2771
|
-
return await this.#bound(operation,
|
|
2852
|
+
return await this.#bound(operation, message, stage, stage.progress);
|
|
2772
2853
|
} catch (error) {
|
|
2773
|
-
this.#
|
|
2854
|
+
if ((0, _src_core.isProbeError)(error) && this.#deadlines.has(error)) {
|
|
2855
|
+
await token.destroy().catch(() => {});
|
|
2856
|
+
if (this.#closing === void 0) this.#emitter.emit("expire", claim);
|
|
2857
|
+
}
|
|
2774
2858
|
throw error;
|
|
2859
|
+
} finally {
|
|
2860
|
+
token.release();
|
|
2775
2861
|
}
|
|
2776
2862
|
}
|
|
2777
|
-
async #bound(operation, message, stage, progress) {
|
|
2778
|
-
const timeout = (0, _orkestrel_timeout.createTimeout)({ ms
|
|
2863
|
+
async #bound(operation, message, stage, progress, ms = this.#deadline) {
|
|
2864
|
+
const timeout = (0, _orkestrel_timeout.createTimeout)({ ms });
|
|
2779
2865
|
timeout.start();
|
|
2780
2866
|
const expiry = this.#expiry(timeout, message, stage, progress);
|
|
2781
2867
|
const refusal = expiry.catch((error) => error);
|
|
2782
2868
|
try {
|
|
2783
2869
|
return await Promise.race([operation(timeout.signal), expiry]);
|
|
2784
2870
|
} catch (error) {
|
|
2785
|
-
if (
|
|
2786
|
-
|
|
2787
|
-
throw await refusal;
|
|
2871
|
+
if (timeout.expired) throw await refusal;
|
|
2872
|
+
throw error;
|
|
2788
2873
|
} finally {
|
|
2789
2874
|
timeout.clear();
|
|
2790
2875
|
}
|
|
2791
2876
|
}
|
|
2792
|
-
async #
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
timeout.clear();
|
|
2800
|
-
}
|
|
2801
|
-
if (this.#closing !== void 0) return false;
|
|
2802
|
-
if (stage === this.#type) {
|
|
2803
|
-
this.#type = new TypeStage(this.#workspace);
|
|
2804
|
-
return true;
|
|
2805
|
-
}
|
|
2806
|
-
if (stage === this.#lint) {
|
|
2807
|
-
this.#lint = new LintStage(this.#workspace);
|
|
2808
|
-
return true;
|
|
2877
|
+
async #resolve(claim) {
|
|
2878
|
+
const token = await this.#lease(this.#type);
|
|
2879
|
+
if (this.#refusal !== void 0) {
|
|
2880
|
+
const refusal = this.#refusal;
|
|
2881
|
+
this.#refusal = void 0;
|
|
2882
|
+
token.release();
|
|
2883
|
+
throw refusal.cause;
|
|
2809
2884
|
}
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2885
|
+
const stage = token.value;
|
|
2886
|
+
return this.#inspectStage(token, () => stage.resolve(claim.project), claim, `The type stage project resolution exceeded ${this.#deadline} ms`);
|
|
2887
|
+
}
|
|
2888
|
+
async #lease(pool) {
|
|
2889
|
+
try {
|
|
2890
|
+
return await pool.acquire();
|
|
2891
|
+
} catch (error) {
|
|
2892
|
+
if ((0, _orkestrel_pool.isPoolError)(error)) {
|
|
2893
|
+
if (error.code === "destroyed") throw (0, _src_core.createDestroyedError)("probe");
|
|
2894
|
+
if (error.code === "create" && pool === this.#type) {
|
|
2895
|
+
const refusal = this.#refusal;
|
|
2896
|
+
this.#refusal = void 0;
|
|
2897
|
+
throw refusal === void 0 ? error.cause : refusal.cause;
|
|
2898
|
+
}
|
|
2899
|
+
if (error.code === "create" || error.code === "cleanup") throw error.cause;
|
|
2900
|
+
}
|
|
2901
|
+
throw error;
|
|
2813
2902
|
}
|
|
2814
|
-
return false;
|
|
2815
2903
|
}
|
|
2816
|
-
|
|
2817
|
-
const
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2904
|
+
#createLint() {
|
|
2905
|
+
for (const cause of this.#survivors.values()) throw new _src_core.ProbeError("The Oxlint language server survived cleanup; restart the probe server", {
|
|
2906
|
+
origin: "instrument",
|
|
2907
|
+
code: "malformed",
|
|
2908
|
+
context: { stage: "lint" },
|
|
2909
|
+
cause
|
|
2910
|
+
});
|
|
2911
|
+
return this.#warm(new LintStage(this.#workspace));
|
|
2822
2912
|
}
|
|
2823
|
-
async #
|
|
2824
|
-
const
|
|
2913
|
+
async #warm(stage) {
|
|
2914
|
+
const bound = stage.stage === "type" ? this.#warmth : this.#deadline;
|
|
2915
|
+
const aborted = Promise.withResolvers();
|
|
2916
|
+
aborted.promise.catch(() => {});
|
|
2917
|
+
const subscription = (0, node_events.addAbortListener)(this.#abort.signal, () => aborted.reject((0, _src_core.createDestroyedError)("probe")));
|
|
2825
2918
|
try {
|
|
2826
|
-
|
|
2919
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe");
|
|
2920
|
+
await this.#bound(() => Promise.race([stage.start(), aborted.promise]), `The ${stage.stage} stage warm exceeded ${bound} ms`, stage, stage.progress, bound);
|
|
2921
|
+
return stage;
|
|
2922
|
+
} catch (error) {
|
|
2923
|
+
if (stage.stage === "type" && this.#closing === void 0) this.#refusal ??= { cause: error };
|
|
2827
2924
|
try {
|
|
2828
|
-
|
|
2829
|
-
} catch (
|
|
2830
|
-
this.#
|
|
2831
|
-
throw
|
|
2925
|
+
await this.#dispose(stage);
|
|
2926
|
+
} catch (failure) {
|
|
2927
|
+
this.#survivors.set(stage, failure);
|
|
2928
|
+
throw failure;
|
|
2832
2929
|
}
|
|
2930
|
+
throw error;
|
|
2833
2931
|
} finally {
|
|
2834
|
-
|
|
2932
|
+
subscription[Symbol.dispose]();
|
|
2835
2933
|
}
|
|
2836
2934
|
}
|
|
2837
|
-
#
|
|
2838
|
-
|
|
2839
|
-
|
|
2935
|
+
async #dispose(stage) {
|
|
2936
|
+
const bound = stage.stage === "lint" ? Math.max(this.#deadline, _src_core.LINT_TEARDOWN) : this.#deadline;
|
|
2937
|
+
try {
|
|
2938
|
+
await this.#bound(() => stage.destroy(), `The ${stage.stage} stage teardown exceeded ${bound} ms`, stage, stage.progress, bound);
|
|
2939
|
+
} catch (error) {
|
|
2940
|
+
if ((0, _src_core.isProbeError)(error) && this.#deadlines.has(error)) return;
|
|
2941
|
+
if (this.#closing !== void 0 || stage.stage === "lint" && (0, _src_core.isProbeError)(error) && (0, _orkestrel_lsp.isLSPError)(error.cause) && error.cause.code === "timeout") throw error;
|
|
2942
|
+
this.#surface(error);
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
#refuseArm(error) {
|
|
2946
|
+
if (this.#closing !== void 0) return (0, _src_core.createDestroyedError)("probe");
|
|
2947
|
+
const cause = (0, _orkestrel_pool.isPoolError)(error) ? error.cause : error;
|
|
2948
|
+
const failure = new _src_core.ProbeError(`The probe could not arm: ${describeUnknown(cause)}`, {
|
|
2949
|
+
origin: "instrument",
|
|
2950
|
+
code: "malformed",
|
|
2951
|
+
cause
|
|
2952
|
+
});
|
|
2953
|
+
this.#surface(failure);
|
|
2954
|
+
return failure;
|
|
2840
2955
|
}
|
|
2841
2956
|
#expiry(timeout, message, stage, progress) {
|
|
2842
2957
|
return new Promise((_resolve, reject) => {
|
|
@@ -2846,7 +2961,7 @@ var Probe = class {
|
|
|
2846
2961
|
code: "deadline",
|
|
2847
2962
|
context: {
|
|
2848
2963
|
stage: stage.stage,
|
|
2849
|
-
deadline:
|
|
2964
|
+
deadline: timeout.ms
|
|
2850
2965
|
}
|
|
2851
2966
|
});
|
|
2852
2967
|
this.#deadlines.add(error);
|
|
@@ -2855,26 +2970,23 @@ var Probe = class {
|
|
|
2855
2970
|
});
|
|
2856
2971
|
}
|
|
2857
2972
|
async #destroy() {
|
|
2973
|
+
this.#abort.abort();
|
|
2974
|
+
const barriers = Promise.allSettled([
|
|
2975
|
+
this.#type.destroy(),
|
|
2976
|
+
this.#lint.destroy(),
|
|
2977
|
+
this.#runtime.destroy()
|
|
2978
|
+
]);
|
|
2858
2979
|
try {
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
await Promise.
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
this.#destroyStage(this.#runtime)
|
|
2866
|
-
]);
|
|
2980
|
+
await this.#starting?.catch(() => {});
|
|
2981
|
+
await this.#arming?.catch(() => {});
|
|
2982
|
+
const results = await barriers;
|
|
2983
|
+
const survivors = await Promise.allSettled([...this.#survivors.keys()].map((stage) => this.#dispose(stage)));
|
|
2984
|
+
this.#survivors.clear();
|
|
2985
|
+
for (const result of [...results, ...survivors]) if (result.status === "rejected") throw (0, _orkestrel_pool.isPoolError)(result.reason) ? result.reason.cause : result.reason;
|
|
2867
2986
|
} finally {
|
|
2868
2987
|
this.#emitter.destroy();
|
|
2869
2988
|
}
|
|
2870
2989
|
}
|
|
2871
|
-
async #destroyStage(stage) {
|
|
2872
|
-
try {
|
|
2873
|
-
await this.#bound(() => stage.destroy(), `The ${stage.stage} stage teardown exceeded ${this.#deadline} ms`, stage, stage.progress);
|
|
2874
|
-
} catch (error) {
|
|
2875
|
-
if (!(0, _src_core.isProbeError)(error) || !this.#deadlines.has(error)) throw error;
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
2990
|
#version(name) {
|
|
2879
2991
|
const version = readWorkspaceManifest(this.#workspace, name).contents.version;
|
|
2880
2992
|
if (!(0, _orkestrel_contract.isString)(version)) throw new _src_core.ProbeError(`${name} publishes no readable version`, {
|
|
@@ -2919,12 +3031,13 @@ var Probe = class {
|
|
|
2919
3031
|
/**
|
|
2920
3032
|
* Implements `ProbeServerInterface` over a `PassThrough` stream this server owns, binding the
|
|
2921
3033
|
* published `prove` tool and the dual-era dispatcher to this process's Model Context Protocol
|
|
2922
|
-
* stdio transport.
|
|
3034
|
+
* stdio transport. Starting creates the probe and awaits its lint and runtime onset; type warming
|
|
3035
|
+
* and the boot controls continue behind it.
|
|
2923
3036
|
*
|
|
2924
3037
|
* @remarks
|
|
2925
3038
|
* Construction snapshots the probe options, publishes the `prove` tool, and binds the dual-era
|
|
2926
|
-
* dispatcher to the stdio transport.
|
|
2927
|
-
*
|
|
3039
|
+
* dispatcher to the stdio transport.
|
|
3040
|
+
* Discovery remains available while the legacy handshake awaits that onset. Construction is held
|
|
2928
3041
|
* before it begins, so teardown entered through a construction callback waits for the resulting
|
|
2929
3042
|
* probe and releases it. A constructor refusal clears that held operation for a later retry.
|
|
2930
3043
|
*
|
|
@@ -2934,7 +3047,8 @@ var Probe = class {
|
|
|
2934
3047
|
* serving is still attached and still fires afterwards. The transport reads a stream this server
|
|
2935
3048
|
* owns rather than this process's standard input, which is what makes that possible: the
|
|
2936
3049
|
* transport's own listeners land on that stream, and the only listeners this server ever puts on
|
|
2937
|
-
* `process.stdin` are the `data`, `close`, and `error` forwarders
|
|
3050
|
+
* `process.stdin` are the `data`, `close`, and `error` forwarders and the input-end teardown.
|
|
3051
|
+
* `destroy` pauses the
|
|
2938
3052
|
* stream only when this server is what set it flowing and nothing else is reading it, so a process
|
|
2939
3053
|
* that outlives this server reads its own standard input again and receives its own signals.
|
|
2940
3054
|
* Teardown removes the signal handlers first: it takes seconds when a boot is in flight, and a
|
|
@@ -2943,7 +3057,7 @@ var Probe = class {
|
|
|
2943
3057
|
* @example
|
|
2944
3058
|
* ```ts
|
|
2945
3059
|
* const server = new ProbeServer({ workspace: process.cwd() })
|
|
2946
|
-
* server.start()
|
|
3060
|
+
* await server.start()
|
|
2947
3061
|
* await server.destroy()
|
|
2948
3062
|
* ```
|
|
2949
3063
|
*/
|
|
@@ -2955,24 +3069,28 @@ var ProbeServer = class {
|
|
|
2955
3069
|
#close;
|
|
2956
3070
|
#error;
|
|
2957
3071
|
#signal;
|
|
3072
|
+
#end;
|
|
3073
|
+
#starting;
|
|
2958
3074
|
#server;
|
|
2959
3075
|
#owns;
|
|
2960
3076
|
#construction;
|
|
2961
3077
|
#closing;
|
|
2962
3078
|
/**
|
|
2963
3079
|
* Snapshots the probe options this server will use and binds the published schema to this
|
|
2964
|
-
* process's stdio transport
|
|
3080
|
+
* process's stdio transport without warming the workspace.
|
|
2965
3081
|
*
|
|
2966
|
-
* @param options - Workspace, deadline, and initial observation hooks for the
|
|
3082
|
+
* @param options - Workspace, deadline, and initial observation hooks for the probe
|
|
2967
3083
|
*/
|
|
2968
3084
|
constructor(options) {
|
|
2969
3085
|
const workspace = options?.workspace;
|
|
2970
3086
|
const deadline = options?.deadline;
|
|
3087
|
+
const warm = options?.warm;
|
|
2971
3088
|
const on = options?.on;
|
|
2972
3089
|
const error = options?.error;
|
|
2973
3090
|
this.#options = Object.freeze({
|
|
2974
3091
|
workspace: (0, node_path.resolve)(workspace ?? process.cwd()),
|
|
2975
3092
|
...deadline === void 0 ? {} : { deadline },
|
|
3093
|
+
...warm === void 0 ? {} : { warm },
|
|
2976
3094
|
...on === void 0 ? {} : { on: Object.freeze({ ...on }) },
|
|
2977
3095
|
...error === void 0 ? {} : { error }
|
|
2978
3096
|
});
|
|
@@ -2983,22 +3101,52 @@ var ProbeServer = class {
|
|
|
2983
3101
|
this.#close = this.#finish.bind(this);
|
|
2984
3102
|
this.#error = this.#fail.bind(this);
|
|
2985
3103
|
this.#signal = this.#release.bind(this);
|
|
3104
|
+
this.#end = this.#release.bind(this);
|
|
2986
3105
|
}
|
|
2987
3106
|
start() {
|
|
2988
|
-
if (this.#closing !== void 0)
|
|
2989
|
-
|
|
3107
|
+
if (this.#closing !== void 0) return Promise.reject((0, _src_core.createDestroyedError)("probe server"));
|
|
3108
|
+
this.#starting ??= this.#setup();
|
|
3109
|
+
this.#starting.catch(() => {});
|
|
3110
|
+
return this.#starting;
|
|
3111
|
+
}
|
|
3112
|
+
destroy() {
|
|
3113
|
+
if (this.#closing !== void 0) return this.#closing;
|
|
3114
|
+
this.#closing = this.#destroy();
|
|
3115
|
+
return this.#closing;
|
|
3116
|
+
}
|
|
3117
|
+
async #setup() {
|
|
2990
3118
|
this.#owns = process.stdin.readableFlowing !== true;
|
|
2991
3119
|
this.#transport.start();
|
|
2992
3120
|
process.stdin.on("data", this.#data);
|
|
2993
3121
|
process.stdin.on("close", this.#close);
|
|
2994
3122
|
process.stdin.on("error", this.#error);
|
|
3123
|
+
process.stdin.on("end", this.#end);
|
|
2995
3124
|
process.on("SIGINT", this.#signal);
|
|
2996
3125
|
process.on("SIGTERM", this.#signal);
|
|
3126
|
+
try {
|
|
3127
|
+
const probe = await this.#resolveProbe();
|
|
3128
|
+
if (this.#closing !== void 0) return;
|
|
3129
|
+
await probe.start();
|
|
3130
|
+
if (this.#closing !== void 0) return;
|
|
3131
|
+
} catch (error) {
|
|
3132
|
+
if (this.#closing !== void 0) return;
|
|
3133
|
+
throw error;
|
|
3134
|
+
}
|
|
2997
3135
|
}
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3136
|
+
async #handshake(options) {
|
|
3137
|
+
options.signal.throwIfAborted();
|
|
3138
|
+
const aborted = Promise.withResolvers();
|
|
3139
|
+
const listener = (0, node_events.addAbortListener)(options.signal, () => aborted.reject(options.signal.reason));
|
|
3140
|
+
try {
|
|
3141
|
+
await Promise.race([this.#starting, aborted.promise]);
|
|
3142
|
+
if (this.#closing !== void 0) throw (0, _src_core.createDestroyedError)("probe server");
|
|
3143
|
+
} catch (error) {
|
|
3144
|
+
options.signal.throwIfAborted();
|
|
3145
|
+
if ((0, _src_core.isProbeError)(error)) throw createHandshakeError(error);
|
|
3146
|
+
throw error;
|
|
3147
|
+
} finally {
|
|
3148
|
+
listener[Symbol.dispose]();
|
|
3149
|
+
}
|
|
3002
3150
|
}
|
|
3003
3151
|
async #destroy() {
|
|
3004
3152
|
process.removeListener("SIGINT", this.#signal);
|
|
@@ -3007,13 +3155,17 @@ var ProbeServer = class {
|
|
|
3007
3155
|
process.stdin.removeListener("data", this.#data);
|
|
3008
3156
|
process.stdin.removeListener("close", this.#close);
|
|
3009
3157
|
process.stdin.removeListener("error", this.#error);
|
|
3158
|
+
process.stdin.removeListener("end", this.#end);
|
|
3010
3159
|
if (this.#owns === true && process.stdin.listenerCount("data") === 0) process.stdin.pause();
|
|
3011
3160
|
this.#owns = void 0;
|
|
3012
3161
|
this.#stream.destroy();
|
|
3013
3162
|
const construction = this.#construction;
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3163
|
+
try {
|
|
3164
|
+
const probe = await construction?.catch(() => void 0);
|
|
3165
|
+
if (probe !== void 0) await probe.destroy();
|
|
3166
|
+
} finally {
|
|
3167
|
+
await this.#starting?.catch(() => {});
|
|
3168
|
+
}
|
|
3017
3169
|
}
|
|
3018
3170
|
#receive(chunk) {
|
|
3019
3171
|
this.#stream.write(chunk);
|
|
@@ -3047,7 +3199,8 @@ var ProbeServer = class {
|
|
|
3047
3199
|
},
|
|
3048
3200
|
tools,
|
|
3049
3201
|
limit: { keys: _src_core.PROBE_KEYS },
|
|
3050
|
-
execution: this.#execute.bind(this)
|
|
3202
|
+
execution: this.#execute.bind(this),
|
|
3203
|
+
handshake: this.#handshake.bind(this)
|
|
3051
3204
|
});
|
|
3052
3205
|
}
|
|
3053
3206
|
async #prove(input) {
|
|
@@ -3124,6 +3277,7 @@ exports.buildRevisionPath = buildRevisionPath;
|
|
|
3124
3277
|
exports.captureListeners = captureListeners;
|
|
3125
3278
|
exports.collectWorkspaceFiles = collectWorkspaceFiles;
|
|
3126
3279
|
exports.computeDigest = computeDigest;
|
|
3280
|
+
exports.createHandshakeError = createHandshakeError;
|
|
3127
3281
|
exports.describeUnknown = describeUnknown;
|
|
3128
3282
|
exports.escapesRoot = escapesRoot;
|
|
3129
3283
|
exports.filterUniqueIssues = filterUniqueIssues;
|