@a11ign/screenreader-fleet 0.5.2 → 0.6.0

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.
Files changed (49) hide show
  1. package/README.md +37 -0
  2. package/dist/{capture-client.d.mts → capture-client.d.ts} +2 -2
  3. package/dist/{check-worker-code.d.mts → check-worker-code.d.ts} +2 -3
  4. package/dist/check-worker-code.mjs +1 -1
  5. package/dist/{cli-flags.d.mts → cli-flags.d.ts} +5 -5
  6. package/dist/{code-drift.d.mts → code-drift.d.ts} +7 -7
  7. package/dist/{command-line-census.d.mts → command-line-census.d.ts} +3 -3
  8. package/dist/{compare-workers.d.mts → compare-workers.d.ts} +1 -1
  9. package/dist/{control-plane-isolation.d.mts → control-plane-isolation.d.ts} +1 -1
  10. package/dist/{doctor.d.mts → doctor.d.ts} +57 -31
  11. package/dist/doctor.mjs +4 -4
  12. package/dist/{fleet-consistency.d.mts → fleet-consistency.d.ts} +50 -85
  13. package/dist/fleet-consistency.mjs +4 -0
  14. package/dist/{fleet-env.d.mts → fleet-env.d.ts} +45 -45
  15. package/dist/{fleet-scripts.d.mts → fleet-scripts.d.ts} +1 -1
  16. package/dist/{git-safe-env.d.mts → git-safe-env.d.ts} +3 -3
  17. package/dist/{guest-run.d.mts → guest-run.d.ts} +5 -5
  18. package/dist/{host-address.d.mts → host-address.d.ts} +4 -4
  19. package/dist/{host-capacity.d.mts → host-capacity.d.ts} +5 -5
  20. package/dist/{host-metrics.d.mts → host-metrics.d.ts} +23 -15
  21. package/dist/index.mjs +1 -1
  22. package/dist/{measure-guard.d.mts → measure-guard.d.ts} +14 -14
  23. package/dist/{npm-cli-executable.d.mts → npm-cli-executable.d.ts} +4 -4
  24. package/dist/{probe-outcome.d.mts → probe-outcome.d.ts} +43 -44
  25. package/dist/{protocol-guard.d.mts → protocol-guard.d.ts} +3 -3
  26. package/dist/source-walk.d.ts +11 -0
  27. package/dist/{transient-fault.d.mts → transient-fault.d.ts} +1 -1
  28. package/dist/tsx-import.d.ts +6 -0
  29. package/dist/{utm-deprecated.d.mts → utm-deprecated.d.ts} +1 -1
  30. package/dist/worker-code-check.d.ts +95 -0
  31. package/dist/worker-code-check.mjs +1 -1
  32. package/dist/{worker-health.d.mts → worker-health.d.ts} +2 -2
  33. package/dist/{worker-http.d.mts → worker-http.d.ts} +51 -51
  34. package/dist/{worker-stats.d.mts → worker-stats.d.ts} +40 -20
  35. package/package.json +30 -19
  36. package/src/local-worker/build-vm.sh +2 -2
  37. package/src/local-worker/clone-worker.sh +1 -1
  38. package/src/local-worker/create-utm-vm.sh +1 -1
  39. package/src/local-worker/fetch-windows-iso.sh +5 -5
  40. package/src/local-worker/worker-ctl.sh +12 -12
  41. package/src/provisioning/apply-foreground-lock-timeout.ps1 +1 -1
  42. package/src/provisioning/bootstrap-windows-worker.ps1 +1 -1
  43. package/src/provisioning/diagnose-nvda-worker.ps1 +1 -1
  44. package/src/provisioning/stamp-provision-revision.ps1 +3 -3
  45. package/dist/source-walk.d.mts +0 -11
  46. package/dist/worker-code-check.d.mts +0 -54
  47. /package/dist/{normalise-fleet.d.mts → normalise-fleet.d.ts} +0 -0
  48. /package/dist/{src_fleet-scripts_mjs.mjs → src_fleet-scripts_ts.mjs} +0 -0
  49. /package/dist/{src_git-safe-env_mjs.mjs → src_git-safe-env_ts.mjs} +0 -0
@@ -52,6 +52,10 @@ const REPORTED_ONLY = [
52
52
  {
53
53
  path: "displayAdapter",
54
54
  why: "the adapter is what decides whether a pinned display mode can be held at all -- on 2026-09-22 workers 7-11 were on Microsoft's Basic Display Adapter and captured at 640x480 under a `provisionRevision` identical to their peers' (#1955); the pinned Intel driver install resolved that, and all ten read an Intel adapter at CM_PROB_NONE on 2026-09-23. NOT a gate, and no longer because nobody reports it: 10 of 10 guests report it since 2026-09-23T18:02Z, reading `Intel(R) UHD Graphics 630` on nine and `Intel(R) HD Graphics 630` on one as of 2026-09-23. That single letter is a real hardware difference rather than a driver fallback, so no provisioning run can converge it and a gate would refuse that guest for ever (#2063, reading on #2170)"
55
+ },
56
+ {
57
+ path: "windowsBuild",
58
+ why: "two boxes one cumulative update apart share a `windowsVersion` and are not the same Windows; the revision (`CurrentBuild.UBR`) is what tells them apart. NOT a gate yet: it graduates to MUST_MATCH once the fleet reads one value (#4433, #4405)"
55
59
  }
56
60
  ];
57
61
  const POLICY_MUST_MATCH = [
@@ -1,3 +1,4 @@
1
+ export declare const DEFAULT_WORKER_PORT = 8765;
1
2
  /**
2
3
  * The fleet named by the environment — ONE parser, because there were three that did not agree.
3
4
  *
@@ -16,7 +17,7 @@
16
17
  *
17
18
  * @returns {Array<{ name: string, url: string }>}
18
19
  */
19
- export function configuredWorkers(): Array<{
20
+ export declare function configuredWorkers(): Array<{
20
21
  name: string;
21
22
  url: string;
22
23
  }>;
@@ -34,13 +35,46 @@ export function configuredWorkers(): Array<{
34
35
  * @param {{ argv?: readonly string[], baseDir?: string }} [options]
35
36
  * @returns {{ inventoryPath: string, groupVarsPath: string }}
36
37
  */
37
- export function inventoryPathsFor({ argv, baseDir }?: {
38
+ export declare function inventoryPathsFor({ argv, baseDir }?: {
38
39
  argv?: readonly string[];
39
40
  baseDir?: string;
40
41
  }): {
41
42
  inventoryPath: string;
42
43
  groupVarsPath: string;
43
44
  };
45
+ /**
46
+ * The inventory group whose hosts are capture workers.
47
+ *
48
+ * This reader was GROUPLESS until 2026-08-21, and that was a live hazard rather than an untidiness: every
49
+ * `ansible_host:` in the file became `http://<addr>:8765`, so adding any non-worker host to `inventory.yml`
50
+ * -- the lab container, the control container, a switch -- would have silently added a phantom worker to
51
+ * `A11Y_WORKERS`, and a run would have dispatched capture cases to it. That is the exact failure this
52
+ * module's own header says it exists to prevent ("dispatched to but never updated", "both of those are
53
+ * silent"), arriving through the door nobody had shut.
54
+ */
55
+ export declare const WORKER_GROUP = "a11y_workers";
56
+ /**
57
+ * One frame of the indentation stack: a key and the column it started at.
58
+ */
59
+ export type Frame = {
60
+ indent: number;
61
+ key: string;
62
+ };
63
+ /**
64
+ * A host as the inventory declares it — the ADDRESS and the NAME together.
65
+ *
66
+ * They travel as one value because separating them is what sent `fleet:sleep` at the wrong machine: every
67
+ * tool that ACTS on a worker takes the name, every tool that REPORTS on one printed the address, and
68
+ * nothing mapped between them. `collectHost` explains the incident.
69
+ *
70
+ * `capture` is false for a host that declares `a11y_capture: false`: enrolled, served, deployed to, and not
71
+ * handed corpus cases.
72
+ */
73
+ export type Host = {
74
+ name: string | undefined;
75
+ host: string;
76
+ capture: boolean;
77
+ };
44
78
  /**
45
79
  * Which group each line of the inventory sits in, index-aligned with `text.split(/\r?\n/)`.
46
80
  *
@@ -53,7 +87,7 @@ export function inventoryPathsFor({ argv, baseDir }?: {
53
87
  * @param {string} text
54
88
  * @returns {Array<string | undefined>}
55
89
  */
56
- export function groupPerLine(text: string): Array<string | undefined>;
90
+ export declare function groupPerLine(text: string): Array<string | undefined>;
57
91
  /**
58
92
  * Worker URLs from the text of an inventory file.
59
93
  *
@@ -70,7 +104,7 @@ export function groupPerLine(text: string): Array<string | undefined>;
70
104
  * @param {{ port?: number, group?: string, scope?: "fleet" | "capture" }} [options]
71
105
  * @returns {string[]}
72
106
  */
73
- export function workersFromInventory(text: string, { port, group, scope }?: {
107
+ export declare function workersFromInventory(text: string, { port, group, scope }?: {
74
108
  port?: number;
75
109
  group?: string;
76
110
  scope?: "fleet" | "capture";
@@ -82,7 +116,7 @@ export function workersFromInventory(text: string, { port, group, scope }?: {
82
116
  * @param {{ port?: number, group?: string }} [options]
83
117
  * @returns {{name: string, url: string}[]}
84
118
  */
85
- export function hostsOutOfCaptureSet(text: string, { port, group }?: {
119
+ export declare function hostsOutOfCaptureSet(text: string, { port, group }?: {
86
120
  port?: number;
87
121
  group?: string;
88
122
  }): {
@@ -99,13 +133,13 @@ export function hostsOutOfCaptureSet(text: string, { port, group }?: {
99
133
  * @param {{ port?: number, group?: string }} [options]
100
134
  * @returns {Record<string, string>}
101
135
  */
102
- export function workerNamesFromInventory(text: string, { port, group }?: {
136
+ export declare function workerNamesFromInventory(text: string, { port, group }?: {
103
137
  port?: number;
104
138
  group?: string;
105
139
  }): Record<string, string>;
106
140
  /** The port the group vars declare, so it is stated once and not guessed here. */
107
141
  /** @param {string} text @returns {number} */
108
- export function portFromGroupVars(text: string): number;
142
+ export declare function portFromGroupVars(text: string): number;
109
143
  /**
110
144
  * The workers declared in `inventory.yml` — i.e. the BARE-METAL fleet.
111
145
  *
@@ -122,7 +156,7 @@ export function portFromGroupVars(text: string): number;
122
156
  *
123
157
  * @param {{ inventoryPath?: string, groupVarsPath?: string }} [paths]
124
158
  */
125
- export function inventoryWorkerUrls({ inventoryPath, groupVarsPath }?: {
159
+ export declare function inventoryWorkerUrls({ inventoryPath, groupVarsPath }?: {
126
160
  inventoryPath?: string;
127
161
  groupVarsPath?: string;
128
162
  }): string[];
@@ -142,7 +176,7 @@ export function inventoryWorkerUrls({ inventoryPath, groupVarsPath }?: {
142
176
  * @param {{ inventoryPath?: string, groupVarsPath?: string }} [paths]
143
177
  * @returns {{name: string, url: string}[]} empty when no inventory is declared, like `inventoryWorkerUrls`
144
178
  */
145
- export function namedInventoryWorkers({ inventoryPath, groupVarsPath }?: {
179
+ export declare function namedInventoryWorkers({ inventoryPath, groupVarsPath }?: {
146
180
  inventoryPath?: string;
147
181
  groupVarsPath?: string;
148
182
  }): {
@@ -183,7 +217,7 @@ export function namedInventoryWorkers({ inventoryPath, groupVarsPath }?: {
183
217
  * @param {{ named?: () => {url: string}[], inventory?: () => string[], local?: () => string[] }} readers
184
218
  * @returns {{ urls: string[], source: string }}
185
219
  */
186
- export function resolveWorkerPool({ named, inventory, local, }?: {
220
+ export declare function resolveWorkerPool({ named, inventory, local, }?: {
187
221
  named?: () => {
188
222
  url: string;
189
223
  }[];
@@ -205,44 +239,10 @@ export function resolveWorkerPool({ named, inventory, local, }?: {
205
239
  * @param {{ port?: number, mode?: "env" | "list" }} [options]
206
240
  * @returns {{stdout: string, stderr: string}}
207
241
  */
208
- export function fleetEnvOutput(text: string, { port, mode }?: {
242
+ export declare function fleetEnvOutput(text: string, { port, mode }?: {
209
243
  port?: number;
210
244
  mode?: "env" | "list";
211
245
  }): {
212
246
  stdout: string;
213
247
  stderr: string;
214
248
  };
215
- export const DEFAULT_WORKER_PORT: 8765;
216
- /**
217
- * The inventory group whose hosts are capture workers.
218
- *
219
- * This reader was GROUPLESS until 2026-08-21, and that was a live hazard rather than an untidiness: every
220
- * `ansible_host:` in the file became `http://<addr>:8765`, so adding any non-worker host to `inventory.yml`
221
- * -- the lab container, the control container, a switch -- would have silently added a phantom worker to
222
- * `A11Y_WORKERS`, and a run would have dispatched capture cases to it. That is the exact failure this
223
- * module's own header says it exists to prevent ("dispatched to but never updated", "both of those are
224
- * silent"), arriving through the door nobody had shut.
225
- */
226
- export const WORKER_GROUP: "a11y_workers";
227
- /**
228
- * One frame of the indentation stack: a key and the column it started at.
229
- */
230
- export type Frame = {
231
- indent: number;
232
- key: string;
233
- };
234
- /**
235
- * A host as the inventory declares it — the ADDRESS and the NAME together.
236
- *
237
- * They travel as one value because separating them is what sent `fleet:sleep` at the wrong machine: every
238
- * tool that ACTS on a worker takes the name, every tool that REPORTS on one printed the address, and
239
- * nothing mapped between them. `collectHost` explains the incident.
240
- *
241
- * `capture` is false for a host that declares `a11y_capture: false`: enrolled, served, deployed to, and not
242
- * handed corpus cases.
243
- */
244
- export type Host = {
245
- name: string | undefined;
246
- host: string;
247
- capture: boolean;
248
- };
@@ -1,5 +1,5 @@
1
1
  /** Absolute paths to the provisioning and lifecycle scripts. Absolute, because a consumer spawns them. */
2
- export function fleetScriptPaths(): {
2
+ export declare function fleetScriptPaths(): {
3
3
  dir: string;
4
4
  workerCtl: string;
5
5
  buildVm: string;
@@ -1,9 +1,9 @@
1
+ /** @type {readonly string[]} */
2
+ export declare const KNOWN_GIT_REDIRECT_VARS: readonly string[];
1
3
  /**
2
4
  * `process.env` with every `GIT_*` key removed, `extra` applied on top. A prefix strip, never a list
3
5
  * lookup, so a new `GIT_*` variable is caught without this file needing to know its name.
4
6
  * @param {Record<string, string>} [extra]
5
7
  * @returns {Record<string, string | undefined>}
6
8
  */
7
- export function sandboxGitEnv(extra?: Record<string, string>): Record<string, string | undefined>;
8
- /** @type {readonly string[]} */
9
- export const KNOWN_GIT_REDIRECT_VARS: readonly string[];
9
+ export declare function sandboxGitEnv(extra?: Record<string, string>): Record<string, string | undefined>;
@@ -1,3 +1,5 @@
1
+ /** Written by the wrapper as its last act. Absent means still running, or it died. */
2
+ export declare const DONE_SENTINEL = "---GUEST-RUN-DONE---";
1
3
  /**
2
4
  * The cmd line that registers and starts the elevated task.
3
5
  *
@@ -5,7 +7,7 @@
5
7
  * a guest, because it is the part that silently produces wrong answers rather than errors.
6
8
  */
7
9
  /** @param {{ scriptPath: string, taskName?: string }} where */
8
- export function scheduleCommand({ scriptPath, taskName }: {
10
+ export declare function scheduleCommand({ scriptPath, taskName }: {
9
11
  scriptPath: string;
10
12
  taskName?: string;
11
13
  }): string;
@@ -16,10 +18,8 @@ export function scheduleCommand({ scriptPath, taskName }: {
16
18
  * exactly how a trim that crashed immediately looked identical to a trim in progress, for three boots.
17
19
  */
18
20
  /** @param {string} body @param {string} outputFile */
19
- export function wrapScript(body: string, outputFile: string): string;
21
+ export declare function wrapScript(body: string, outputFile: string): string;
20
22
  /** Did the run finish? Exported because "no sentinel" and "no file" are different failures. */
21
23
  /** @param {string} output */
22
24
  /** @param {string | null} output */
23
- export function isComplete(output: string | null): boolean;
24
- /** Written by the wrapper as its last act. Absent means still running, or it died. */
25
- export const DONE_SENTINEL: "---GUEST-RUN-DONE---";
25
+ export declare function isComplete(output: string | null): boolean;
@@ -1,6 +1,6 @@
1
1
  /** Dotted quad to a comparable integer, or null if it is not one (a hostname, IPv6, nonsense). */
2
2
  /** @param {string} ip */
3
- export function ipv4ToInt(ip: string): number | null;
3
+ export declare function ipv4ToInt(ip: string): number | null;
4
4
  /**
5
5
  * This host's address on the same subnet as `guestIp`, or undefined if we have no interface onto it.
6
6
  *
@@ -10,14 +10,14 @@ export function ipv4ToInt(ip: string): number | null;
10
10
  * @param {string} guestIp
11
11
  * @returns {string | undefined}
12
12
  */
13
- export function hostAddressFor(guestIp: string): string | undefined;
13
+ export declare function hostAddressFor(guestIp: string): string | undefined;
14
14
  /**
15
15
  * This host's address as seen from a worker at `workerUrl`, when the two share a subnet.
16
16
  *
17
17
  * @param {string} workerUrl
18
18
  * @returns {string | undefined}
19
19
  */
20
- export function hostAddressForWorker(workerUrl: string): string | undefined;
20
+ export declare function hostAddressForWorker(workerUrl: string): string | undefined;
21
21
  /**
22
22
  * The base URL a worker should use to fetch host-served pages.
23
23
  *
@@ -29,4 +29,4 @@ export function hostAddressForWorker(workerUrl: string): string | undefined;
29
29
  * @param {number | string} [port]
30
30
  * @returns {string}
31
31
  */
32
- export function hostPagesBase(workerUrl: string, port?: number | string): string;
32
+ export declare function hostPagesBase(workerUrl: string, port?: number | string): string;
@@ -9,9 +9,9 @@
9
9
  * not stop a run. This codebase already applies that rule to foregroundLockTimeout(): a broken
10
10
  * diagnostic taking the pool offline is worse than the fault it looks for.
11
11
  */
12
- export function availableHostMemoryMb(): number | null;
12
+ export declare function availableHostMemoryMb(): number | null;
13
13
  /** Physical RAM in MB. Unlike `os.freemem()` this cannot lie — it is a property of the machine. */
14
- export function totalHostMemoryMb(): number;
14
+ export declare function totalHostMemoryMb(): number;
15
15
  /**
16
16
  * The most workers this machine can EVER hold, from physical RAM alone.
17
17
  *
@@ -23,7 +23,7 @@ export function totalHostMemoryMb(): number;
23
23
  *
24
24
  * @returns {number} workers, from physical memory
25
25
  */
26
- export function workerCeilingFromTotalRam(totalMb?: number): number;
26
+ export declare function workerCeilingFromTotalRam(totalMb?: number): number;
27
27
  /**
28
28
  * How many workers may be RUNNING at once, given what the host has spare.
29
29
  *
@@ -45,7 +45,7 @@ export function workerCeilingFromTotalRam(totalMb?: number): number;
45
45
  * @param {{ availableMb: number | null, alreadyRunning: number, totalMb?: number }} host
46
46
  * @returns {number}
47
47
  */
48
- export function workersHostCanRun({ availableMb, alreadyRunning, totalMb }: {
48
+ export declare function workersHostCanRun({ availableMb, alreadyRunning, totalMb }: {
49
49
  availableMb: number | null;
50
50
  alreadyRunning: number;
51
51
  totalMb?: number;
@@ -56,7 +56,7 @@ export function workersHostCanRun({ availableMb, alreadyRunning, totalMb }: {
56
56
  * @param {{ limit: number, wanted: number, availableMb: number | null }} cap
57
57
  * @returns {string | null}
58
58
  */
59
- export function capacityReason({ limit, wanted, availableMb }: {
59
+ export declare function capacityReason({ limit, wanted, availableMb }: {
60
60
  limit: number;
61
61
  wanted: number;
62
62
  availableMb: number | null;
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @param {string} output
8
8
  */
9
- export function parseVmStat(output: string): {
9
+ export declare function parseVmStat(output: string): {
10
10
  freeMb: number;
11
11
  activeMb: number;
12
12
  inactiveMb: number;
@@ -24,7 +24,7 @@ export function parseVmStat(output: string): {
24
24
  * @param {string} output
25
25
  * @returns {Array<{device: string, kbPerTransfer: number, transfersPerSecond: number, mbPerSecond: number}>}
26
26
  */
27
- export function parseIostat(output: string): Array<{
27
+ export declare function parseIostat(output: string): Array<{
28
28
  device: string;
29
29
  kbPerTransfer: number;
30
30
  transfersPerSecond: number;
@@ -34,7 +34,7 @@ export function parseIostat(output: string): Array<{
34
34
  * Load averages, or null.
35
35
  * @param {string} output
36
36
  */
37
- export function parseLoadAverage(output: string): {
37
+ export declare function parseLoadAverage(output: string): {
38
38
  one: number;
39
39
  five: number;
40
40
  fifteen: number;
@@ -46,7 +46,7 @@ export function parseLoadAverage(output: string): {
46
46
  * @param {string} psOutput output of `ps -o pid=,rss=,comm=`
47
47
  * @param {string} match substring of the command to keep
48
48
  */
49
- export function parseProcessMemory(psOutput: string, match: string): {
49
+ export declare function parseProcessMemory(psOutput: string, match: string): {
50
50
  pid: number;
51
51
  residentMb: number;
52
52
  command: string;
@@ -60,7 +60,7 @@ export function parseProcessMemory(psOutput: string, match: string): {
60
60
  *
61
61
  * @param {{ processMatch?: string }} options
62
62
  */
63
- export function sampleHost({ processMatch }?: {
63
+ export declare function sampleHost({ processMatch }?: {
64
64
  processMatch?: string;
65
65
  }): {
66
66
  at: string;
@@ -91,18 +91,14 @@ export function sampleHost({ processMatch }?: {
91
91
  }[];
92
92
  };
93
93
  /**
94
- * @param {HostSnapshot} before
95
- * @param {HostSnapshot} after
94
+ * What changed between two snapshots.
95
+ *
96
+ * Paging is reported as a DELTA because the absolute counters are since-boot and therefore enormous
97
+ * and useless: 6.6 GB of swap left over from an incident hours ago looks identical to a host swapping
98
+ * right now. Only the delta distinguishes them, and that distinction was worth an afternoon.
96
99
  */
97
- export function diffHost(before: HostSnapshot, after: HostSnapshot): {
98
- pageoutsDelta: number;
99
- pageinsDelta: number;
100
- swappingDuringRun: boolean;
101
- compressorMb: number | null;
102
- freeMb: number | null;
103
- residentMbTotal: number;
104
- };
105
100
  /**
101
+ *
106
102
  * Named because the first attempt at annotating this called it `Record<string, number>` -- flat numbers,
107
103
  * which is what the CALL SITES read out of it and not what it is. A shape guessed from its uses is the
108
104
  * same defect as a type inferred from its defaults, one file over.
@@ -113,3 +109,15 @@ export type HostSnapshot = {
113
109
  residentMb: number;
114
110
  }[];
115
111
  };
112
+ /**
113
+ * @param {HostSnapshot} before
114
+ * @param {HostSnapshot} after
115
+ */
116
+ export declare function diffHost(before: HostSnapshot, after: HostSnapshot): {
117
+ pageoutsDelta: number;
118
+ pageinsDelta: number;
119
+ swappingDuringRun: boolean;
120
+ compressorMb: number | null;
121
+ freeMb: number | null;
122
+ residentMbTotal: number;
123
+ };
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
3
  import { networkInterfaces } from "node:os";
4
4
  import { capacityReason, availableHostMemoryMb, workersHostCanRun } from "./host-capacity.mjs";
5
- import { fleetScriptPaths as fleet_scripts_fleetScriptPaths } from "./src_fleet-scripts_mjs.mjs";
5
+ import { fleetScriptPaths as fleet_scripts_fleetScriptPaths } from "./src_fleet-scripts_ts.mjs";
6
6
  import { inventoryWorkerUrls } from "./fleet-env.mjs";
7
7
  function warnUtmDeprecated(what) {
8
8
  process.stderr.write(`DEPRECATED: ${what} manages a local UTM worker VM. UTM was a testing path and is not the fleet.\nCapture on the bare-metal fleet instead: npm run fleet:status, npm run fleet:deploy. See CLAUDE.md's\n"Working on a Mac" section.\n`);
@@ -1,33 +1,33 @@
1
1
  /**
2
2
  * @param {string[]} workers
3
- * @param {{ what: string, timeoutMs?: number, request?: import("./probe-outcome.mjs").ProbeRequest }} about
3
+ * @param {{ what: string, timeoutMs?: number, request?: import("./probe-outcome.ts").ProbeRequest }} about
4
4
  * `what` names the measurement, so a refusal says what was NOT measured; `timeoutMs` and `request` are injectable
5
5
  * @returns {Promise<void>} resolves when every worker is free; throws naming the busy ones
6
6
  */
7
- export function refuseIfBusy(workers: string[], { what, timeoutMs, request }: {
7
+ export declare function refuseIfBusy(workers: string[], { what, timeoutMs, request }: {
8
8
  what: string;
9
9
  timeoutMs?: number;
10
- request?: import("./probe-outcome.mjs").ProbeRequest;
10
+ request?: import("./probe-outcome.js").ProbeRequest;
11
11
  }): Promise<void>;
12
+ /**
13
+ * THE VITALS PROBE'S TIMEOUT, WITH ITS READING (#2683). `worker:compare` reads `vitals` before the rounds and again
14
+ * straight AFTER the last capture, so the second read is the LOADED case: a box that has just finished one can take
15
+ * up to about 10 s to answer (#2671, the reading beside `WORKER_PROBE_TIMEOUT_MS`), against 3.09 s for the slowest
16
+ * healthy first-after-idle answer. 20 s is that ceiling twice over, kept from before #2683 because it already clears
17
+ * both. A vitals sample that times out costs the run one column, so there is no reason to give it less.
18
+ */
19
+ export declare const VITALS_TIMEOUT_MS = 20000;
12
20
  /**
13
21
  * A worker's `/health` `vitals`, or `null` when there are none to be had, and SAYS WHY through `warn`: a box that did
14
22
  * not answer, one that refused, and one that answered without vitals are three different reasons for the same empty
15
23
  * column in the report, and the run used to print none of them.
16
24
  *
17
25
  * @param {string} worker
18
- * @param {{ timeoutMs?: number, request?: import("./probe-outcome.mjs").ProbeRequest, warn?: (line: string) => void }} [options]
26
+ * @param {{ timeoutMs?: number, request?: import("./probe-outcome.ts").ProbeRequest, warn?: (line: string) => void }} [options]
19
27
  * @returns {Promise<any>}
20
28
  */
21
- export function sampleVitals(worker: string, { timeoutMs, request, warn }?: {
29
+ export declare function sampleVitals(worker: string, { timeoutMs, request, warn }?: {
22
30
  timeoutMs?: number;
23
- request?: import("./probe-outcome.mjs").ProbeRequest;
31
+ request?: import("./probe-outcome.js").ProbeRequest;
24
32
  warn?: (line: string) => void;
25
33
  }): Promise<any>;
26
- /**
27
- * THE VITALS PROBE'S TIMEOUT, WITH ITS READING (#2683). `worker:compare` reads `vitals` before the rounds and again
28
- * straight AFTER the last capture, so the second read is the LOADED case: a box that has just finished one can take
29
- * up to about 10 s to answer (#2671, the reading beside `WORKER_PROBE_TIMEOUT_MS`), against 3.09 s for the slowest
30
- * healthy first-after-idle answer. 20 s is that ceiling twice over, kept from before #2683 because it already clears
31
- * both. A vitals sample that times out costs the run one column, so there is no reason to give it less.
32
- */
33
- export const VITALS_TIMEOUT_MS: 20000;
@@ -2,18 +2,18 @@
2
2
  * @param {"npx" | "npm"} name
3
3
  * @returns {string[]}
4
4
  */
5
- export function npmCliScriptCandidates(name: "npx" | "npm"): string[];
5
+ export declare function npmCliScriptCandidates(name: "npx" | "npm"): string[];
6
6
  /**
7
7
  * @param {"npx" | "npm"} name
8
8
  * @returns {string}
9
9
  */
10
- export function resolveNpmCliScript(name: "npx" | "npm"): string;
10
+ export declare function resolveNpmCliScript(name: "npx" | "npm"): string;
11
11
  /**
12
12
  * @param {"npx" | "npm"} name
13
13
  * @param {string[]} args
14
14
  * @returns {{ command: string, args: string[] }}
15
15
  */
16
- export function npmCliInvocation(name: "npx" | "npm", args: string[]): {
16
+ export declare function npmCliInvocation(name: "npx" | "npm", args: string[]): {
17
17
  command: string;
18
18
  args: string[];
19
19
  };
@@ -35,7 +35,7 @@ export function npmCliInvocation(name: "npx" | "npm", args: string[]): {
35
35
  * @param {string[]} args
36
36
  * @returns {{ command: string, args: string[] }}
37
37
  */
38
- export function pnpmCliInvocation(args: string[]): {
38
+ export declare function pnpmCliInvocation(args: string[]): {
39
39
  command: string;
40
40
  args: string[];
41
41
  };
@@ -1,46 +1,3 @@
1
- /**
2
- * @param {string} worker the worker's base URL
3
- * @param {{ timeoutMs?: number, request?: ProbeRequest }} [options]
4
- * @returns {Promise<Probe>}
5
- */
6
- export function probeHealth(worker: string, { timeoutMs, request }?: {
7
- timeoutMs?: number;
8
- request?: ProbeRequest;
9
- }): Promise<Probe>;
10
- /**
11
- * One sentence per outcome, in the words of what was OBSERVED. Only `refused`, `not-ready` and `busy` say the box is
12
- * up, because only those are things the box itself said; a silent probe says "did not answer" and never "down".
13
- *
14
- * @param {Probe} probe
15
- * @param {{ worker: string, timeoutMs?: number }} about
16
- * @returns {string}
17
- */
18
- export function describeProbe(probe: Probe, { worker, timeoutMs }: {
19
- worker: string;
20
- timeoutMs?: number;
21
- }): string;
22
- /** @typedef {typeof requestJson} ProbeRequest */
23
- /**
24
- * THE PER-PROBE TIMEOUT, WITH ITS READING. A probe that outlives it is UNKNOWN, never "down", so this number
25
- * decides how much slowness a healthy box is allowed.
26
- *
27
- * All of it READ by others on the real fleet (`orchestrator`, #2671) and none measured by this row, whose
28
- * engineer is barred from probing it:
29
- * - the slowest HEALTHY box: 2.80 to 3.09 s on a11y-worker-13, -14 and -16, twelve others 0.53 to 0.76 s;
30
- * - that is the FIRST answer after the box has been quiet more than 5 s, because the worker rebuilds its
31
- * environment block with two synchronous `powershell.exe` calls when it is older than that, so a probe made
32
- * by hand is nearly always the slow case;
33
- * - a LOADED box (one that has just stopped a capture) can take up to about 10 s: each of the two calls is
34
- * bounded at 5 s and they stop the worker's event loop for the whole time.
35
- * 12 s is that loaded ceiling plus 2 s, the number `fleet-wake.mjs` `HEALTH_TIMEOUT_MS` states for the same
36
- * reading. Before #2683 these entries used 5 s (`witness`, 1.91 s over the 3.09 s box and none over a loaded
37
- * one), 8 s (`auth:leak-check`) and 10 s (`worker:compare`'s busy guard), read at `d119fb0f2`. Cost of the
38
- * generosity: a box that really is off costs one 12 s wait before the message. A refusal costs nothing, it comes
39
- * back at once.
40
- */
41
- export const WORKER_PROBE_TIMEOUT_MS: 12000;
42
- /** How to wake a box from a checkout of this repo. The published entries do not do it themselves. */
43
- export const WAKE_HINT: string;
44
1
  /**
45
2
  * WHAT ONE `/health` PROBE CAN SAY, for the entries that reach a worker from the PUBLISHED side and by hand
46
3
  * (`witness`, `worker:compare`, `auth:leak-check`, #2683 of #2655).
@@ -84,5 +41,47 @@ export type Probe = {
84
41
  message: string;
85
42
  timedOut: boolean;
86
43
  };
44
+ import { requestJson } from "./worker-http.js";
87
45
  export type ProbeRequest = typeof requestJson;
88
- import { requestJson } from "./worker-http.mjs";
46
+ /**
47
+ * THE PER-PROBE TIMEOUT, WITH ITS READING. A probe that outlives it is UNKNOWN, never "down", so this number
48
+ * decides how much slowness a healthy box is allowed.
49
+ *
50
+ * All of it READ by others on the real fleet (`orchestrator`, #2671) and none measured by this row, whose
51
+ * engineer is barred from probing it:
52
+ * - the slowest HEALTHY box: 2.80 to 3.09 s on a11y-worker-13, -14 and -16, twelve others 0.53 to 0.76 s;
53
+ * - that is the FIRST answer after the box has been quiet more than 5 s, because the worker rebuilds its
54
+ * environment block with two synchronous `powershell.exe` calls when it is older than that, so a probe made
55
+ * by hand is nearly always the slow case;
56
+ * - a LOADED box (one that has just stopped a capture) can take up to about 10 s: each of the two calls is
57
+ * bounded at 5 s and they stop the worker's event loop for the whole time.
58
+ * 12 s is that loaded ceiling plus 2 s, the number `fleet-wake.mjs` `HEALTH_TIMEOUT_MS` states for the same
59
+ * reading. Before #2683 these entries used 5 s (`witness`, 1.91 s over the 3.09 s box and none over a loaded
60
+ * one), 8 s (`auth:leak-check`) and 10 s (`worker:compare`'s busy guard), read at `d119fb0f2`. Cost of the
61
+ * generosity: a box that really is off costs one 12 s wait before the message. A refusal costs nothing, it comes
62
+ * back at once.
63
+ */
64
+ export declare const WORKER_PROBE_TIMEOUT_MS = 12000;
65
+ /**
66
+ * @param {string} worker the worker's base URL
67
+ * @param {{ timeoutMs?: number, request?: ProbeRequest }} [options]
68
+ * @returns {Promise<Probe>}
69
+ */
70
+ export declare function probeHealth(worker: string, { timeoutMs, request }?: {
71
+ timeoutMs?: number;
72
+ request?: ProbeRequest;
73
+ }): Promise<Probe>;
74
+ /** How to wake a box from a checkout of this repo. The published entries do not do it themselves. */
75
+ export declare const WAKE_HINT: string;
76
+ /**
77
+ * One sentence per outcome, in the words of what was OBSERVED. Only `refused`, `not-ready` and `busy` say the box is
78
+ * up, because only those are things the box itself said; a silent probe says "did not answer" and never "down".
79
+ *
80
+ * @param {Probe} probe
81
+ * @param {{ worker: string, timeoutMs?: number }} about
82
+ * @returns {string}
83
+ */
84
+ export declare function describeProbe(probe: Probe, { worker, timeoutMs }: {
85
+ worker: string;
86
+ timeoutMs?: number;
87
+ }): string;
@@ -1,3 +1,4 @@
1
+ export declare const RECAPTURE_COST: string;
1
2
  /**
2
3
  * Decide whether a deploy may proceed.
3
4
  *
@@ -5,7 +6,7 @@
5
6
  * allowed: boolean, source?: string }} input
6
7
  * @returns {{ refuse: boolean, message: string }}
7
8
  */
8
- export function protocolVerdict({ local, served, allowed, source }: {
9
+ export declare function protocolVerdict({ local, served, allowed, source }: {
9
10
  local: number | string | null;
10
11
  served: {
11
12
  worker: string;
@@ -26,8 +27,7 @@ export function protocolVerdict({ local, served, allowed, source }: {
26
27
  * @param {string[]} urls
27
28
  * @returns {Promise<{worker: string, protocol: number|string|null}[]>}
28
29
  */
29
- export function servedProtocols(urls: string[]): Promise<{
30
+ export declare function servedProtocols(urls: string[]): Promise<{
30
31
  worker: string;
31
32
  protocol: number | string | null;
32
33
  }[]>;
33
- export const RECAPTURE_COST: string;
@@ -0,0 +1,11 @@
1
+ /** The repository root, resolved from this module rather than from the caller's cwd. */
2
+ export declare const REPOSITORY: string;
3
+ /**
4
+ * Every non-test source file under the repository root, as `[relativePath, source]`.
5
+ *
6
+ * @param {{ root?: string }} [options]
7
+ * @returns {Array<[string, string]>}
8
+ */
9
+ export declare function sourceFiles({ root }?: {
10
+ root?: string;
11
+ }): Array<[string, string]>;
@@ -2,4 +2,4 @@
2
2
  * @param {unknown} error anything a failed request threw — a node:http Error, an undici one, a string
3
3
  * @returns {boolean}
4
4
  */
5
- export function isTransient(error: unknown): boolean;
5
+ export declare function isTransient(error: unknown): boolean;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The arguments that let a plain `node` run a `.ts` file (ADR 0043, Decision 8): the host's Node has no type stripping, so a test that
3
+ * starts a source file as a child process, as an operator would, starts it under `tsx`. Resolved to an absolute URL because those children
4
+ * run from a temporary directory, where a bare `tsx` would not resolve.
5
+ */
6
+ export declare const TSX_ARGS: string[];
@@ -2,4 +2,4 @@
2
2
  * @param {string} what The command or module the caller is about to run — named so the message is
3
3
  * specific to what actually fired, not a generic banner every UTM-adjacent file prints identically.
4
4
  */
5
- export function warnUtmDeprecated(what: string): void;
5
+ export declare function warnUtmDeprecated(what: string): void;