@orkestrel/probe 0.0.26 → 0.0.28
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/src/core/index.cjs +34 -34
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +70 -70
- package/dist/src/core/index.d.ts +70 -70
- package/dist/src/core/index.js +33 -33
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +45 -37
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +46 -41
- package/dist/src/server/index.d.ts +46 -41
- package/dist/src/server/index.js +47 -39
- package/dist/src/server/index.js.map +1 -1
- package/package.json +13 -13
package/dist/src/server/index.js
CHANGED
|
@@ -5,14 +5,14 @@ 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
7
|
import { attempt, compileGuard, compileSchema, isArray, isError, isFunction, isNumber, isObject, isRecord, isString, parseJSON, schemaToParameters } from "@orkestrel/contract";
|
|
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,
|
|
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, formatReceipt, formatSpecification, formatStageResult, formatVerdict, isClaim, isDraft, isProbeError, isVerdict, matchesSpecification } from "../core/index.js";
|
|
9
9
|
import { inspectProcess, killTree } from "@orkestrel/process/server";
|
|
10
10
|
import { Emitter } from "@orkestrel/emitter";
|
|
11
11
|
import { createPool, isPoolError } from "@orkestrel/pool";
|
|
12
12
|
import { createLSPClient, isLSPError } from "@orkestrel/lsp";
|
|
13
13
|
import { addAbortListener } from "node:events";
|
|
14
14
|
import { createTimeout } from "@orkestrel/timeout";
|
|
15
|
-
import {
|
|
15
|
+
import { createLSPStdioTransport } from "@orkestrel/lsp/server";
|
|
16
16
|
import { PassThrough } from "node:stream";
|
|
17
17
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
18
|
import { spawn } from "node:child_process";
|
|
@@ -729,8 +729,12 @@ function matchesLiveProcess(id) {
|
|
|
729
729
|
* Collects every regular file a target workspace holds, skipping the trees no inspection reads.
|
|
730
730
|
*
|
|
731
731
|
* @remarks
|
|
732
|
-
* Skips a directory named `.git`, `dist`, or `node_modules` at any depth
|
|
733
|
-
*
|
|
732
|
+
* Skips a directory named `.git`, `dist`, or `node_modules` at any depth. Of the workspace-root
|
|
733
|
+
* `tmp` directory it walks only `tmp/probes`: the scaffold tmp layout holds the runtime probes there
|
|
734
|
+
* and nothing else an inspection reads, so a consumer's ignored data under `tmp/` is never read or
|
|
735
|
+
* copied. The match is the lowercase `tmp` spelling exactly, and a `tmp` directory below the root is
|
|
736
|
+
* walked like any other. The directory {@link TYPE_MIRROR} names is skipped as well, so this
|
|
737
|
+
* package's own mirror stays out of the walk if it ever moves outside `tmp`. A
|
|
734
738
|
* directory this host cannot list is skipped rather than raised, so one unreadable directory in a
|
|
735
739
|
* consumer's tree is not a reason to refuse the whole walk. A symbolic link is not carried, whether
|
|
736
740
|
* it names a file or a directory, so a file reached only through one is absent from the result; a
|
|
@@ -747,7 +751,9 @@ function matchesLiveProcess(id) {
|
|
|
747
751
|
function collectWorkspaceFiles(workspace) {
|
|
748
752
|
const excluded = normalizePath(resolveWorkspaceFile(workspace, TYPE_MIRROR));
|
|
749
753
|
const files = [];
|
|
750
|
-
const
|
|
754
|
+
const root = resolve(workspace);
|
|
755
|
+
const scratch = join(root, "tmp");
|
|
756
|
+
const directories = [root];
|
|
751
757
|
while (directories.length > 0) {
|
|
752
758
|
const directory = directories.pop();
|
|
753
759
|
if (directory === void 0) break;
|
|
@@ -755,6 +761,7 @@ function collectWorkspaceFiles(workspace) {
|
|
|
755
761
|
const entries = reading.success ? reading.value : [];
|
|
756
762
|
for (const entry of entries) {
|
|
757
763
|
if (entry.name === ".git" || entry.name === "dist" || entry.name === "node_modules") continue;
|
|
764
|
+
if (directory === scratch && entry.name !== "probes") continue;
|
|
758
765
|
const path = join(directory, entry.name);
|
|
759
766
|
if (entry.isDirectory()) {
|
|
760
767
|
if (normalizePath(path) !== excluded) directories.push(path);
|
|
@@ -814,12 +821,12 @@ async function guardStage(stage, operation) {
|
|
|
814
821
|
*
|
|
815
822
|
* @remarks
|
|
816
823
|
* The published claim schema constrains `Draft.path` to a non-empty string and nothing else, while
|
|
817
|
-
* `isDraft` also refuses an absolute path and one that
|
|
818
|
-
* the whole of the difference between the advertised contract and the enforced one, so a
|
|
819
|
-
* refused after satisfying the schema is refused here and nowhere else. The whole input must
|
|
820
|
-
* satisfy that schema. Each draft is then tested with `isDraft` itself rather than with a
|
|
821
|
-
* copy of its rule. Reports nothing for a value carrying no draft member, including one
|
|
822
|
-
* a member this contract does not declare.
|
|
824
|
+
* `isDraft` also refuses an absolute path and one that resolves outside the workspace. That one
|
|
825
|
+
* member is the whole of the difference between the advertised contract and the enforced one, so a
|
|
826
|
+
* caller refused after satisfying the schema is refused here and nowhere else. The whole input must
|
|
827
|
+
* first satisfy that schema. Each draft is then tested with `isDraft` itself rather than with a
|
|
828
|
+
* second copy of its rule. Reports nothing for a value carrying no draft member, including one
|
|
829
|
+
* refused for a member this contract does not declare.
|
|
823
830
|
*
|
|
824
831
|
* This function lives in the server helpers rather than in core: core's leaf pair, `helpers.ts` and
|
|
825
832
|
* `validators.ts`, may not consume the shapes module this function reads `CLAIM_SHAPE` from, and
|
|
@@ -854,10 +861,11 @@ function findRefusedPaths(value) {
|
|
|
854
861
|
* `tsc --showConfig` spells a path relative to the project file, so a printed record carries an
|
|
855
862
|
* absolute path only where a project itself declares one. Rewriting a contained absolute path to
|
|
856
863
|
* its relative form keeps one commit checked out at two roots reading to one digest. A path that
|
|
857
|
-
*
|
|
858
|
-
* tree by a relative spelling. Key order is the compiler's own and it differs between
|
|
859
|
-
* majors, so sorting removes a difference that means nothing. A `__proto__` key is
|
|
860
|
-
* the earlier assignment-built record dropped it, so a digest stays the same across
|
|
864
|
+
* resolves outside the workspace is left as it stands, because rewriting it would name a file
|
|
865
|
+
* outside the tree by a relative spelling. Key order is the compiler's own and it differs between
|
|
866
|
+
* the supported majors, so sorting removes a difference that means nothing. A `__proto__` key is
|
|
867
|
+
* dropped, as the earlier assignment-built record dropped it, so a digest stays the same across
|
|
868
|
+
* releases.
|
|
861
869
|
*
|
|
862
870
|
* @param workspace - The target workspace root
|
|
863
871
|
* @param value - The value to rewrite
|
|
@@ -896,10 +904,10 @@ function normalizeValue(workspace, value) {
|
|
|
896
904
|
*
|
|
897
905
|
* @example
|
|
898
906
|
* ```ts
|
|
899
|
-
*
|
|
907
|
+
* computeWorkspaceDigest('/srv/checkout', { strict: true }).length // 32
|
|
900
908
|
* ```
|
|
901
909
|
*/
|
|
902
|
-
function
|
|
910
|
+
function computeWorkspaceDigest(workspace, value) {
|
|
903
911
|
return createHash("sha256").update(JSON.stringify(normalizeValue(workspace, value))).digest("hex").slice(0, 32);
|
|
904
912
|
}
|
|
905
913
|
/**
|
|
@@ -1093,7 +1101,7 @@ var Overlay = class {
|
|
|
1093
1101
|
}
|
|
1094
1102
|
};
|
|
1095
1103
|
// package.json
|
|
1096
|
-
var version = "0.0.
|
|
1104
|
+
var version = "0.0.28";
|
|
1097
1105
|
var peerDependencies = {
|
|
1098
1106
|
"typescript": "^6.0.3 || ^7.0.2",
|
|
1099
1107
|
"vitest": "^4.1.12 || ^5.0.5"
|
|
@@ -1104,7 +1112,7 @@ var peerDependencies = {
|
|
|
1104
1112
|
*
|
|
1105
1113
|
* @remarks
|
|
1106
1114
|
* Starting launches the target workspace's Oxlint binary with its Language Server Protocol mode
|
|
1107
|
-
* and hands the conversation to `@orkestrel/lsp`: `
|
|
1115
|
+
* and hands the conversation to `@orkestrel/lsp`: `createLSPStdioTransport` owns the child
|
|
1108
1116
|
* process and its bytes, and `createLSPClient` owns the framing, the request correlation, the
|
|
1109
1117
|
* capabilities this stage advertises, and the choice between pulled and pushed diagnostics. This
|
|
1110
1118
|
* stage owns the workspace, the candidate identity, and the projection from a diagnostic to an
|
|
@@ -1132,7 +1140,7 @@ var peerDependencies = {
|
|
|
1132
1140
|
* @example
|
|
1133
1141
|
* ```ts
|
|
1134
1142
|
* const stage = new LintStage('/srv/checkout')
|
|
1135
|
-
* const
|
|
1143
|
+
* const result = await stage.inspect(subject, { signal: AbortSignal.timeout(30_000) })
|
|
1136
1144
|
* await stage.destroy()
|
|
1137
1145
|
* ```
|
|
1138
1146
|
*/
|
|
@@ -1205,7 +1213,7 @@ var LintStage = class {
|
|
|
1205
1213
|
}
|
|
1206
1214
|
async #warm() {
|
|
1207
1215
|
const binary = resolveWorkspaceBinary(this.#workspace, "oxlint");
|
|
1208
|
-
const transport =
|
|
1216
|
+
const transport = createLSPStdioTransport({
|
|
1209
1217
|
server: {
|
|
1210
1218
|
command: [
|
|
1211
1219
|
process.execPath,
|
|
@@ -1345,10 +1353,10 @@ var LintStage = class {
|
|
|
1345
1353
|
* Vitest service after 64 specifications rather than deleting from each map that service owns. Any
|
|
1346
1354
|
* bound holds the retention flat, because the replacement releases everything the instance held,
|
|
1347
1355
|
* and 64 is the value chosen. The inspection that crosses the bound pays the replacement
|
|
1348
|
-
* synchronously: it closes the resident service and warms a
|
|
1349
|
-
* over this package's own workspace on the host `guides/probe.md` § Cost names, two
|
|
1350
|
-
* inspections put that one at 480 ms and 269 ms against median inspections of 156 ms and
|
|
1351
|
-
* budget one call in 64 at 110 ms to 330 ms above the rest.
|
|
1356
|
+
* synchronously: it closes the resident service and warms a fresh service before it runs. On
|
|
1357
|
+
* 2026-08-20, over this package's own workspace on the host `guides/probe.md` § Cost names, two
|
|
1358
|
+
* runs of 66 inspections put that one at 480 ms and 269 ms against median inspections of 156 ms and
|
|
1359
|
+
* 155 ms, so budget one call in 64 at 110 ms to 330 ms above the rest.
|
|
1352
1360
|
*
|
|
1353
1361
|
* Every issue this stage emits names its party, and the stage emits an issue for every party
|
|
1354
1362
|
* `Party` declares. An `origin: 'claimant'` issue is a failure Vitest reported about the candidate.
|
|
@@ -1373,7 +1381,7 @@ var LintStage = class {
|
|
|
1373
1381
|
* @example
|
|
1374
1382
|
* ```ts
|
|
1375
1383
|
* const stage = new RuntimeStage('/srv/checkout')
|
|
1376
|
-
* const
|
|
1384
|
+
* const result = await stage.inspect(subject)
|
|
1377
1385
|
* await stage.destroy()
|
|
1378
1386
|
* ```
|
|
1379
1387
|
*/
|
|
@@ -2019,7 +2027,7 @@ var RuntimeStage = class {
|
|
|
2019
2027
|
* @example
|
|
2020
2028
|
* ```ts
|
|
2021
2029
|
* const stage = new TypeStage('/srv/checkout')
|
|
2022
|
-
* const
|
|
2030
|
+
* const result = await stage.inspect(subject, 'configs/src/tsconfig.core.json')
|
|
2023
2031
|
* await stage.destroy()
|
|
2024
2032
|
* ```
|
|
2025
2033
|
*/
|
|
@@ -2088,8 +2096,8 @@ var TypeStage = class {
|
|
|
2088
2096
|
*
|
|
2089
2097
|
* @param project - The workspace-relative TypeScript project to resolve
|
|
2090
2098
|
* @returns The resolved workspace-relative path and the digest of its compiler options
|
|
2091
|
-
* @throws When the project
|
|
2092
|
-
* stage has already been destroyed
|
|
2099
|
+
* @throws When the project resolves outside the workspace, when the compiler refuses it, or when
|
|
2100
|
+
* the stage has already been destroyed
|
|
2093
2101
|
*/
|
|
2094
2102
|
resolve(project) {
|
|
2095
2103
|
return guardStage(this.stage, this.#resolve(project));
|
|
@@ -2158,7 +2166,7 @@ var TypeStage = class {
|
|
|
2158
2166
|
}
|
|
2159
2167
|
return {
|
|
2160
2168
|
path: contained,
|
|
2161
|
-
digest:
|
|
2169
|
+
digest: computeWorkspaceDigest(this.#workspace, config.compilerOptions)
|
|
2162
2170
|
};
|
|
2163
2171
|
}
|
|
2164
2172
|
async #destroy() {
|
|
@@ -2609,7 +2617,7 @@ var Probe = class {
|
|
|
2609
2617
|
const started = performance.now();
|
|
2610
2618
|
const id = randomUUID();
|
|
2611
2619
|
const project = await this.#resolve(claim);
|
|
2612
|
-
const digest =
|
|
2620
|
+
const digest = computeWorkspaceDigest(this.#workspace, {
|
|
2613
2621
|
case: claim.case,
|
|
2614
2622
|
control: claim.control
|
|
2615
2623
|
});
|
|
@@ -2773,21 +2781,21 @@ var Probe = class {
|
|
|
2773
2781
|
const beforeType = await this.#inspect(typeClaim.case, typeClaim);
|
|
2774
2782
|
const beforeRuntime = await this.#inspect(runtimeClaim.case, runtimeClaim);
|
|
2775
2783
|
const before = [...beforeType, ...beforeRuntime];
|
|
2776
|
-
if (before.some((
|
|
2784
|
+
if (before.some((result) => result.issues.length > 0)) throw new ProbeError(`The probe boot control did not begin clean\n${before.map(formatStageResult).join("\n")}`, {
|
|
2777
2785
|
origin: "instrument",
|
|
2778
2786
|
code: "malformed"
|
|
2779
2787
|
});
|
|
2780
2788
|
resolveWorkspaceFile(this.#workspace, relative(this.#workspace, typeDependency), true);
|
|
2781
2789
|
overwriteFile(typeDependency, formatSpecification("export type Signal = number\n", revision));
|
|
2782
2790
|
const afterType = await this.#inspect(typeClaim.control, typeClaim);
|
|
2783
|
-
const type = afterType.find((
|
|
2784
|
-
const tolerant = afterType.find((
|
|
2785
|
-
if (type === void 0 || type.issues.length === 0) throw new ProbeError(`The probe boot type control did not detect a mutated dependency\n${afterType.map(
|
|
2791
|
+
const type = afterType.find((result) => result.stage === typeClaim.control.stage);
|
|
2792
|
+
const tolerant = afterType.find((result) => result.stage === "runtime");
|
|
2793
|
+
if (type === void 0 || type.issues.length === 0) throw new ProbeError(`The probe boot type control did not detect a mutated dependency\n${afterType.map(formatStageResult).join("\n")}`, {
|
|
2786
2794
|
origin: "instrument",
|
|
2787
2795
|
code: "malformed",
|
|
2788
2796
|
context: { stage: typeClaim.control.stage }
|
|
2789
2797
|
});
|
|
2790
|
-
if (tolerant === void 0 || tolerant.issues.length > 0) throw new ProbeError(`The probe boot type control did not remain runtime-clean\n${afterType.map(
|
|
2798
|
+
if (tolerant === void 0 || tolerant.issues.length > 0) throw new ProbeError(`The probe boot type control did not remain runtime-clean\n${afterType.map(formatStageResult).join("\n")}`, {
|
|
2791
2799
|
origin: "instrument",
|
|
2792
2800
|
code: "malformed",
|
|
2793
2801
|
context: { stage: "runtime" }
|
|
@@ -2795,8 +2803,8 @@ var Probe = class {
|
|
|
2795
2803
|
resolveWorkspaceFile(this.#workspace, relative(this.#workspace, runtimeDependency), true);
|
|
2796
2804
|
overwriteFile(runtimeDependency, formatSpecification("export const SIGNAL = 'after'\n", revision));
|
|
2797
2805
|
const afterRuntime = await this.#inspect(runtimeClaim.control, runtimeClaim);
|
|
2798
|
-
const runtime = afterRuntime.find((
|
|
2799
|
-
if (runtime === void 0 || runtime.issues.length === 0) throw new ProbeError(`The probe boot runtime control did not detect a mutated dependency\n${afterRuntime.map(
|
|
2806
|
+
const runtime = afterRuntime.find((result) => result.stage === runtimeClaim.control.stage);
|
|
2807
|
+
if (runtime === void 0 || runtime.issues.length === 0) throw new ProbeError(`The probe boot runtime control did not detect a mutated dependency\n${afterRuntime.map(formatStageResult).join("\n")}`, {
|
|
2800
2808
|
origin: "instrument",
|
|
2801
2809
|
code: "malformed",
|
|
2802
2810
|
context: { stage: runtimeClaim.control.stage }
|
|
@@ -3251,6 +3259,6 @@ var ProbeServer = class {
|
|
|
3251
3259
|
] : [rendered, minimal]).find((arm) => isBoundedJSON(arm, bounds)) ?? minimal;
|
|
3252
3260
|
}
|
|
3253
3261
|
};
|
|
3254
|
-
export { LintStage, Overlay, Probe, ProbeServer, RuntimeStage, TypeStage, buildRevisionPath, captureListeners, collectWorkspaceFiles,
|
|
3262
|
+
export { LintStage, Overlay, Probe, ProbeServer, RuntimeStage, TypeStage, buildRevisionPath, captureListeners, collectWorkspaceFiles, computeWorkspaceDigest, createHandshakeError, describeUnknown, escapesRoot, filterUniqueIssues, findRefusedPaths, guardStage, inferDocumentLanguage, inferTestProject, inferTypeProject, isRefusedName, loadWorkspaceVitest, matchesLiveProcess, matchesWorkspaceModule, normalizePath, normalizeValue, overwriteFile, parseProjectConfig, parseRevisionOwner, readFaultCode, readWorkspaceManifest, relativeWorkspaceFile, relativeWorkspaceMessage, releaseListeners, resolveWorkspaceBinary, resolveWorkspaceFile, resolveWorkspaceModule, scanDiagnostics };
|
|
3255
3263
|
|
|
3256
3264
|
//# sourceMappingURL=index.js.map
|