@stll/oxlint-config 3.0.0 → 3.1.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.
@@ -34,9 +34,9 @@ const repositoryBun = (floor, manifest) => {
34
34
  };
35
35
  //#endregion
36
36
  //#region src/toolchain-consumer-checks.ts
37
- const consumerRunnerVersion = "3.0.0";
37
+ const consumerRunnerVersion = "3.1.0";
38
38
  const consumerCheckWorkflow = "stella/.github/.github/workflows/package-consumer-compat.yml";
39
- const record$10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
39
+ const record$11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
40
40
  const repositoryDirectory = (value) => typeof value === "string" && value !== "" && !value.includes("\\") && !value.includes("${{") && !value.split("").some((character) => {
41
41
  const code = character.charCodeAt(0);
42
42
  return code < 32 || code === 127;
@@ -122,12 +122,12 @@ const validConsumerCron = (text) => {
122
122
  });
123
123
  };
124
124
  const nightlySchedule = (value) => {
125
- if (!record$10(value)) return false;
125
+ if (!record$11(value)) return false;
126
126
  const schedule = value["schedule"];
127
127
  if (!Array.isArray(schedule) || schedule.length === 0) return false;
128
128
  const coveredDays = /* @__PURE__ */ new Set();
129
129
  for (const entry of schedule) {
130
- if (!record$10(entry) || typeof entry["cron"] !== "string" || !validConsumerCron(entry["cron"])) return false;
130
+ if (!record$11(entry) || typeof entry["cron"] !== "string" || !validConsumerCron(entry["cron"])) return false;
131
131
  const fields = entry["cron"].trim().split(/\s+/);
132
132
  const selections = cronFields.map((field, index) => {
133
133
  const text = fields.at(index);
@@ -143,7 +143,7 @@ const parseConsumerChecks = (input) => {
143
143
  if (!Array.isArray(input)) throw new Error("consumerChecks must be an array");
144
144
  const targets = /* @__PURE__ */ new Set();
145
145
  return input.map((entry) => {
146
- if (!record$10(entry) || Object.keys(entry).some((key) => ![
146
+ if (!record$11(entry) || Object.keys(entry).some((key) => ![
147
147
  "workflow",
148
148
  "job",
149
149
  "packages",
@@ -181,9 +181,9 @@ const checkConsumerChecks = ({ declarations, files, policy }) => {
181
181
  });
182
182
  if (document.errors.length > 0) throw new Error("invalid workflow YAML");
183
183
  const source = document.toJS({ maxAliasCount: 100 });
184
- if (!record$10(source) || !record$10(source["jobs"])) continue;
184
+ if (!record$11(source) || !record$11(source["jobs"])) continue;
185
185
  for (const [jobName, job] of Object.entries(source["jobs"])) {
186
- if (!record$10(job) || typeof job["uses"] !== "string") continue;
186
+ if (!record$11(job) || typeof job["uses"] !== "string") continue;
187
187
  const [workflowPath, ref] = job["uses"].split("@");
188
188
  if (workflowPath?.toLowerCase() !== "stella/.github/.github/workflows/package-consumer-compat.yml") continue;
189
189
  const declaration = declarations.find((entry) => entry.workflow === workflow && entry.job === jobName);
@@ -197,7 +197,7 @@ const checkConsumerChecks = ({ declarations, files, policy }) => {
197
197
  const approved = Object.entries(policy.actions).find(([name]) => name.toLowerCase() === consumerCheckWorkflow)?.[1];
198
198
  if (job["uses"].split("@").length !== 2 || ref === void 0 || !/^[a-f0-9]{40}$/.test(ref) || approved === void 0 || ref !== approved.sha || "steps" in job || "runs-on" in job) throw new Error(`${workflow}:${jobName} must invoke the approved immutable consumer workflow as a reusable job`);
199
199
  const inputs = job["with"];
200
- if (!record$10(inputs)) throw new Error(`${workflow}:${jobName} requires consumer inputs`);
200
+ if (!record$11(inputs)) throw new Error(`${workflow}:${jobName} requires consumer inputs`);
201
201
  const names = /* @__PURE__ */ new Set();
202
202
  for (const key of Object.keys(inputs)) {
203
203
  const normalized = key.toLowerCase();
@@ -267,7 +267,7 @@ const locatorValidators = {
267
267
  "bun-source": /^(?:jobs\.[\w-]+|runs)\.steps\.[\w-]+$/
268
268
  };
269
269
  const knownKind = (value) => typeof value === "string" && Object.hasOwn(locatorValidators, value);
270
- const record$9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
270
+ const record$10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
271
271
  /** One reviewed declaration identifies one unresolved selector, never a rule. */
272
272
  const parseDynamicSelectors = (input) => {
273
273
  if (input === void 0) return [];
@@ -275,7 +275,7 @@ const parseDynamicSelectors = (input) => {
275
275
  const result = [];
276
276
  const keys = /* @__PURE__ */ new Set();
277
277
  for (const entry of input) {
278
- if (!record$9(entry) || Object.keys(entry).some((key) => ![
278
+ if (!record$10(entry) || Object.keys(entry).some((key) => ![
279
279
  "path",
280
280
  "kind",
281
281
  "reason",
@@ -311,7 +311,7 @@ const parseDynamicSelectors = (input) => {
311
311
  };
312
312
  //#endregion
313
313
  //#region src/toolchain-engine-floors.ts
314
- const record$8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
314
+ const record$9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
315
315
  const repositoryPath = (value) => typeof value === "string" && value !== "" && !/^[A-Za-z]:/.test(value) && !/[\\\s]/.test(value) && !Array.from(value).some((character) => character.charCodeAt(0) < 32) && value.split("/").every((part) => part !== "" && part !== "." && part !== "..");
316
316
  const parseEngineFloors = (input) => {
317
317
  if (input === void 0) return [];
@@ -319,7 +319,7 @@ const parseEngineFloors = (input) => {
319
319
  const result = [];
320
320
  const jobs = /* @__PURE__ */ new Set();
321
321
  for (const entry of input) {
322
- if (!record$8(entry) || Object.keys(entry).some((key) => ![
322
+ if (!record$9(entry) || Object.keys(entry).some((key) => ![
323
323
  "package",
324
324
  "workflow",
325
325
  "job"
@@ -340,16 +340,16 @@ const resolveEngineFloor = (entry, files) => {
340
340
  const workflowText = files[entry.workflow];
341
341
  if (manifestText === void 0 || workflowText === void 0) throw new Error("engine floor package and workflow must be tracked");
342
342
  const manifest = JSON.parse(manifestText);
343
- if (!record$8(manifest) || manifest["private"] === true || typeof manifest["name"] !== "string" || manifest["name"].trim() === "" || !record$8(manifest["engines"]) || typeof manifest["engines"]["node"] !== "string") throw new Error("engine floor package must be published and declare engines.node");
343
+ if (!record$9(manifest) || manifest["private"] === true || typeof manifest["name"] !== "string" || manifest["name"].trim() === "" || !record$9(manifest["engines"]) || typeof manifest["engines"]["node"] !== "string") throw new Error("engine floor package must be published and declare engines.node");
344
344
  const range = manifest["engines"]["node"];
345
345
  const minimum = (0, semver.validRange)(range) === null ? null : (0, semver.minVersion)(range);
346
346
  if (minimum === null || minimum.prerelease.length !== 0) throw new Error("engine floor engines.node must declare a stable minimum");
347
347
  const document = (0, yaml.parseDocument)(workflowText, { merge: true });
348
348
  if (document.errors.length !== 0) throw new Error("engine floor workflow must be valid YAML");
349
349
  const workflow = document.toJS({ maxAliasCount: 100 });
350
- if (!record$8(workflow) || !record$8(workflow["jobs"])) throw new Error("engine floor job must exist in its tracked workflow");
350
+ if (!record$9(workflow) || !record$9(workflow["jobs"])) throw new Error("engine floor job must exist in its tracked workflow");
351
351
  const job = workflow["jobs"][entry.job];
352
- if (!record$8(job)) throw new Error("engine floor job must exist in its tracked workflow");
352
+ if (!record$9(job)) throw new Error("engine floor job must exist in its tracked workflow");
353
353
  if (!Array.isArray(job["steps"]) || Object.hasOwn(job, "uses")) throw new Error("engine floor job must declare steps and cannot reuse a workflow");
354
354
  return {
355
355
  ...entry,
@@ -379,7 +379,7 @@ const installSections = [
379
379
  "optionalDependencies"
380
380
  ];
381
381
  const allowlistFile = "stll-toolchain.json";
382
- const record$7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
382
+ const record$8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
383
383
  /** `npm:typescript@7.0.2` installs a compiler under another name; returns its version. */
384
384
  const typescriptAliasVersion = (spec) => {
385
385
  if (typeof spec !== "string") return void 0;
@@ -409,7 +409,7 @@ const parseTypescriptAllowlist = (input) => {
409
409
  return input.map((entry) => {
410
410
  const shown = JSON.stringify(entry);
411
411
  const text = (key) => {
412
- const value = record$7(entry) ? entry[key] : void 0;
412
+ const value = record$8(entry) ? entry[key] : void 0;
413
413
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
414
414
  };
415
415
  const workspace = text("workspace");
@@ -417,7 +417,7 @@ const parseTypescriptAllowlist = (input) => {
417
417
  const spec = text("spec");
418
418
  const dependency = text("dependency");
419
419
  const reason = text("reason");
420
- if (!record$7(entry) || Object.keys(entry).length !== allowlistKeys.length || workspace === void 0 || name === void 0 || spec === void 0 || dependency === void 0 || reason === void 0) throw new Error(`typescriptAllowlist entry ${shown} must have exactly workspace, name, spec, dependency and reason as nonempty strings: ${allowlistFormat}`);
420
+ if (!record$8(entry) || Object.keys(entry).length !== allowlistKeys.length || workspace === void 0 || name === void 0 || spec === void 0 || dependency === void 0 || reason === void 0) throw new Error(`typescriptAllowlist entry ${shown} must have exactly workspace, name, spec, dependency and reason as nonempty strings: ${allowlistFormat}`);
421
421
  if (workspace !== "." && (node_path.default.posix.normalize(workspace) !== workspace || workspace.startsWith("/") || workspace.endsWith("/") || workspace === ".." || workspace.startsWith("../"))) throw new Error(`typescriptAllowlist entry ${shown}: workspace must be "." for the root or a normalized relative package directory such as "apps/web"`);
422
422
  if (!exactTypescriptSpec(spec)) throw new Error(`typescriptAllowlist entry ${shown}: spec must be the exact spec the manifest resolves to, such as "6.0.3" or "npm:typescript@6.0.3", not a range or catalog reference`);
423
423
  if (!isTypescriptInstall(name, spec)) throw new Error(`typescriptAllowlist entry ${shown}: name must be typescript or @typescript/native, or an alias whose spec is npm:typescript@<version> or npm:@typescript/native@<version>`);
@@ -993,10 +993,10 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
993
993
  const document = pnpm ? (0, yaml.parseDocument)(text, { lineCounter }) : void 0;
994
994
  if (document !== void 0 && document.errors.length > 0) throw new Error("invalid YAML");
995
995
  const json = document === void 0 ? JSON.parse(text) : document.toJS();
996
- if (!record$7(json)) throw new Error("manifest must be an object");
996
+ if (!record$8(json)) throw new Error("manifest must be an object");
997
997
  if (pnpm) {
998
- if (json["catalog"] !== void 0 && !record$7(json["catalog"])) throw new Error("catalog must be a mapping");
999
- if (json["catalogs"] !== void 0 && (!record$7(json["catalogs"]) || Object.values(json["catalogs"]).some((catalog) => !record$7(catalog)))) throw new Error("named catalogs must be mappings");
998
+ if (json["catalog"] !== void 0 && !record$8(json["catalog"])) throw new Error("catalog must be a mapping");
999
+ if (json["catalogs"] !== void 0 && (!record$8(json["catalogs"]) || Object.values(json["catalogs"]).some((catalog) => !record$8(catalog)))) throw new Error("named catalogs must be mappings");
1000
1000
  if (json["packages"] !== void 0 && (!Array.isArray(json["packages"]) || !json["packages"].every((pattern) => typeof pattern === "string"))) throw new Error("workspace packages must be patterns");
1001
1001
  }
1002
1002
  manifests.set(file, json);
@@ -1010,13 +1010,13 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1010
1010
  catalog: json["overrides"],
1011
1011
  prefix: ["overrides"]
1012
1012
  },
1013
- ...record$7(json["catalogs"]) ? Object.entries(json["catalogs"]).map(([name, catalog]) => ({
1013
+ ...record$8(json["catalogs"]) ? Object.entries(json["catalogs"]).map(([name, catalog]) => ({
1014
1014
  catalog,
1015
1015
  prefix: ["catalogs", name]
1016
1016
  })) : []
1017
1017
  ];
1018
1018
  for (const { catalog, prefix } of catalogEntries) {
1019
- if (!record$7(catalog)) continue;
1019
+ if (!record$8(catalog)) continue;
1020
1020
  for (const [name, value] of Object.entries(catalog)) {
1021
1021
  const node = document.getIn([...prefix, name], true);
1022
1022
  if (!(0, yaml.isNode)(node) || node.range === void 0 || node.range === null) continue;
@@ -1035,7 +1035,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1035
1035
  });
1036
1036
  }
1037
1037
  }
1038
- const catalogSources = (json) => [json, ...record$7(json["workspaces"]) ? [json["workspaces"]] : []];
1038
+ const catalogSources = (json) => [json, ...record$8(json["workspaces"]) ? [json["workspaces"]] : []];
1039
1039
  const pnpmWorkspaceFor = (file) => {
1040
1040
  let directory = node_path.default.posix.dirname(file);
1041
1041
  while (true) {
@@ -1058,8 +1058,8 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1058
1058
  patterns: workspace["packages"],
1059
1059
  rootMembership: "implicit"
1060
1060
  })) return void 0;
1061
- if (name === "" || name === "default") return workspace["catalog"] ?? (record$7(workspace["catalogs"]) ? workspace["catalogs"]["default"] : void 0);
1062
- return record$7(workspace["catalogs"]) ? workspace["catalogs"][name] : void 0;
1061
+ if (name === "" || name === "default") return workspace["catalog"] ?? (record$8(workspace["catalogs"]) ? workspace["catalogs"]["default"] : void 0);
1062
+ return record$8(workspace["catalogs"]) ? workspace["catalogs"][name] : void 0;
1063
1063
  }
1064
1064
  let directory = node_path.default.posix.dirname(file);
1065
1065
  while (true) {
@@ -1067,7 +1067,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1067
1067
  if (manifest !== void 0) {
1068
1068
  for (const source of catalogSources(manifest)) {
1069
1069
  if (name === "" && source["catalog"] !== void 0) return source["catalog"];
1070
- if (record$7(source["catalogs"]) && source["catalogs"][name] !== void 0) return source["catalogs"][name];
1070
+ if (record$8(source["catalogs"]) && source["catalogs"][name] !== void 0) return source["catalogs"][name];
1071
1071
  }
1072
1072
  if (manifest["workspaces"] !== void 0) return void 0;
1073
1073
  }
@@ -1085,7 +1085,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1085
1085
  };
1086
1086
  visited.add(value);
1087
1087
  const catalog = catalogFor(file, value.slice(8));
1088
- if (!record$7(catalog)) return {
1088
+ if (!record$8(catalog)) return {
1089
1089
  value: void 0,
1090
1090
  catalogs
1091
1091
  };
@@ -1110,7 +1110,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1110
1110
  const workspaces = manifests.get(node_path.default.posix.join(directory, "package.json"))?.["workspaces"];
1111
1111
  if (workspaces !== void 0) return {
1112
1112
  directory,
1113
- patterns: record$7(workspaces) ? workspaces["packages"] : workspaces,
1113
+ patterns: record$8(workspaces) ? workspaces["packages"] : workspaces,
1114
1114
  source: "json"
1115
1115
  };
1116
1116
  if (directory === ".") return void 0;
@@ -1144,7 +1144,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1144
1144
  if (json === void 0) continue;
1145
1145
  for (const section of installSections) {
1146
1146
  const entries = json[section];
1147
- if (!record$7(entries) || !Object.hasOwn(entries, entry.name)) continue;
1147
+ if (!record$8(entries) || !Object.hasOwn(entries, entry.name)) continue;
1148
1148
  const { value, catalogs } = resolveThrough(file, entry.name, entries[entry.name]);
1149
1149
  if (value !== entry.spec) continue;
1150
1150
  for (const catalog of catalogs) {
@@ -1189,7 +1189,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1189
1189
  message: `packageManager Bun version must be ${policy.bun} (one exact release at or above the shared minimum, the same in every manifest), found ${JSON.stringify(manager)}`
1190
1190
  });
1191
1191
  const checkEntries = (entries, scope, location) => {
1192
- if (!record$7(entries)) return;
1192
+ if (!record$8(entries)) return;
1193
1193
  for (const [name, raw] of Object.entries(entries)) {
1194
1194
  const value = resolve(file, name, raw);
1195
1195
  if (isTypescriptInstall(name, value)) {
@@ -1229,13 +1229,13 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1229
1229
  }
1230
1230
  };
1231
1231
  for (const key of installSections) checkEntries(json[key], "install");
1232
- if (record$7(json["peerDependencies"])) for (const [name, value] of Object.entries(json["peerDependencies"])) {
1232
+ if (record$8(json["peerDependencies"])) for (const [name, value] of Object.entries(json["peerDependencies"])) {
1233
1233
  const resolved = resolve(file, name, value);
1234
1234
  if (isTypescriptInstall(name, resolved) && !peerRange(resolved)) checkEntries({ [name]: value }, "peer");
1235
1235
  }
1236
1236
  for (const source of catalogSources(json)) {
1237
1237
  checkEntries(source["catalog"], "catalog");
1238
- if (!record$7(source["catalogs"])) continue;
1238
+ if (!record$8(source["catalogs"])) continue;
1239
1239
  for (const catalog of Object.values(source["catalogs"])) checkEntries(catalog, "catalog");
1240
1240
  }
1241
1241
  const ownedNames = /* @__PURE__ */ new Set([...pins.keys(), ...typescriptPackages]);
@@ -1247,11 +1247,11 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1247
1247
  "optionalDependencies"
1248
1248
  ]) {
1249
1249
  const entries = resolutionRoot[section];
1250
- if (!record$7(entries)) continue;
1250
+ if (!record$8(entries)) continue;
1251
1251
  for (const [name, value] of Object.entries(entries)) resolutionDependencies[name] = resolve(file, name, value);
1252
1252
  }
1253
1253
  const checkResolutionMap = (entries, parent) => {
1254
- if (!record$7(entries)) return;
1254
+ if (!record$8(entries)) return;
1255
1255
  for (const [selector, replacement] of Object.entries(entries)) {
1256
1256
  const target = selector === "." ? parent : selector;
1257
1257
  if (target === void 0) continue;
@@ -1270,7 +1270,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1270
1270
  });
1271
1271
  continue;
1272
1272
  }
1273
- if (record$7(replacement)) {
1273
+ if (record$8(replacement)) {
1274
1274
  checkResolutionMap(replacement, target);
1275
1275
  continue;
1276
1276
  }
@@ -1290,8 +1290,8 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1290
1290
  };
1291
1291
  checkResolutionMap(json["overrides"]);
1292
1292
  checkResolutionMap(json["resolutions"]);
1293
- if (record$7(json["pnpm"])) checkResolutionMap(json["pnpm"]["overrides"]);
1294
- const command = record$7(json["scripts"]) ? json["scripts"]["typecheck"] : void 0;
1293
+ if (record$8(json["pnpm"])) checkResolutionMap(json["pnpm"]["overrides"]);
1294
+ const command = record$8(json["scripts"]) ? json["scripts"]["typecheck"] : void 0;
1295
1295
  if (typeof command === "string") for (const words of compilerCommandSegments(command)) {
1296
1296
  if (!invokesCompiler(words)) continue;
1297
1297
  const normalized = words.join(" ");
@@ -1305,7 +1305,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1305
1305
  });
1306
1306
  break;
1307
1307
  }
1308
- if (record$7(json["peerDependencies"])) for (const [name, raw] of Object.entries(json["peerDependencies"])) {
1308
+ if (record$8(json["peerDependencies"])) for (const [name, raw] of Object.entries(json["peerDependencies"])) {
1309
1309
  if (!typescriptPackages.has(name)) continue;
1310
1310
  const range = resolve(file, name, raw);
1311
1311
  if (!peerRange(range)) continue;
@@ -1329,7 +1329,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1329
1329
  message: `${name} peer support range must include ${release}, found ${range}`
1330
1330
  });
1331
1331
  }
1332
- if (record$7(json["engines"]) && json["engines"]["node"] !== void 0 && (typeof json["engines"]["node"] !== "string" || !require_toolchain_inputs.nodeSupportRangeMatches(policy.node, json["engines"]["node"]))) add({
1332
+ if (record$8(json["engines"]) && json["engines"]["node"] !== void 0 && (typeof json["engines"]["node"] !== "string" || !require_toolchain_inputs.nodeSupportRangeMatches(policy.node, json["engines"]["node"]))) add({
1333
1333
  file,
1334
1334
  rule: "node-engine",
1335
1335
  key: "node",
@@ -1343,7 +1343,7 @@ const checkPackageFiles = ({ files, policy, typescriptAllowlist }) => {
1343
1343
  if (json === void 0) return `${file} is missing or invalid; remove the entry`;
1344
1344
  const declares = (name) => installSections.some((section) => {
1345
1345
  const entries = json[section];
1346
- return record$7(entries) && Object.hasOwn(entries, name);
1346
+ return record$8(entries) && Object.hasOwn(entries, name);
1347
1347
  });
1348
1348
  if (!declares(entry.name)) return `${file} no longer declares ${entry.name} in dependencies, devDependencies or optionalDependencies; remove the entry`;
1349
1349
  if (!declares(entry.dependency)) return `${file} no longer depends on ${entry.dependency}; remove the entry and the ${entry.name} declaration, or name the dependency that still needs it`;
@@ -1382,9 +1382,9 @@ const extensionKinds = new Map(Object.entries({
1382
1382
  const scriptSourceKind = (file) => extensionKinds.get((0, node_path.extname)(file));
1383
1383
  //#endregion
1384
1384
  //#region src/toolchain-script-lifecycle.ts
1385
- const record$6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1385
+ const record$7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1386
1386
  const declaredManager = (value) => typeof value === "string" ? /^(bun|npm|pnpm|yarn)@(\d+\.\d+\.\d+)(?:\+\S+)?$/u.exec(value) : null;
1387
- const rootScriptManager = (manifest, context) => declaredManager(context.packageManager ?? (record$6(manifest) ? manifest["packageManager"] : void 0))?.at(1);
1387
+ const rootScriptManager = (manifest, context) => declaredManager(context.packageManager ?? (record$7(manifest) ? manifest["packageManager"] : void 0))?.at(1);
1388
1388
  const npmHooksEnabled = (file) => {
1389
1389
  if (file?.type === "unknown") throw new Error("npm lifecycle configuration must be a tracked regular file");
1390
1390
  if (file?.type !== "tracked") return true;
@@ -1415,12 +1415,12 @@ const yamlSettings = (file, manager) => {
1415
1415
  } catch {
1416
1416
  throw new Error(`Cannot parse ${manager} lifecycle configuration`);
1417
1417
  }
1418
- if (!record$6(settings)) throw new Error(`${manager} lifecycle configuration must be a mapping`);
1418
+ if (!record$7(settings)) throw new Error(`${manager} lifecycle configuration must be a mapping`);
1419
1419
  return settings;
1420
1420
  };
1421
1421
  const pnpmHooksEnabled = (manifest, context) => {
1422
1422
  const declared = declaredManager(context.packageManager ?? manifest["packageManager"]);
1423
- const dependency = [manifest["dependencies"], manifest["devDependencies"]].flatMap((field) => record$6(field) ? [field["pnpm"]] : []).find((value) => typeof value === "string");
1423
+ const dependency = [manifest["dependencies"], manifest["devDependencies"]].flatMap((field) => record$7(field) ? [field["pnpm"]] : []).find((value) => typeof value === "string");
1424
1424
  if ((declared?.at(1) === "pnpm" ? declared.at(2) : dependency) !== "12.9.1") throw new Error("pnpm lifecycle discovery requires declared pnpm@12.9.1");
1425
1425
  const enabled = yamlSettings(context.pnpmWorkspace, "pnpm")["enablePrePostScripts"];
1426
1426
  if (enabled === void 0) return true;
@@ -1464,7 +1464,7 @@ const scriptLifecycleStages = ({ name, manager, manifest, scripts, context }) =>
1464
1464
  };
1465
1465
  //#endregion
1466
1466
  //#region src/toolchain-lint-command.ts
1467
- const record$5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1467
+ const record$6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1468
1468
  const scriptManagers = /* @__PURE__ */ new Set([
1469
1469
  "bun",
1470
1470
  "npm",
@@ -1581,7 +1581,7 @@ const lintInventoryCommands = (manifest, forceEnabled = false, context = {}) =>
1581
1581
  const errors = [];
1582
1582
  const workspaceTasks = /* @__PURE__ */ new Set();
1583
1583
  const filteredBuilds = /* @__PURE__ */ new Set();
1584
- const declaresEngine = record$5(manifest) && [manifest["dependencies"], manifest["devDependencies"]].some((dependencies) => record$5(dependencies) && "oxlint-tsgolint" in dependencies);
1584
+ const declaresEngine = record$6(manifest) && [manifest["dependencies"], manifest["devDependencies"]].some((dependencies) => record$6(dependencies) && "oxlint-tsgolint" in dependencies);
1585
1585
  const enabled = forceEnabled || declaresEngine;
1586
1586
  if (!enabled) return {
1587
1587
  commands,
@@ -1589,14 +1589,14 @@ const lintInventoryCommands = (manifest, forceEnabled = false, context = {}) =>
1589
1589
  enabled,
1590
1590
  workspaceTask: false
1591
1591
  };
1592
- if (!record$5(manifest)) return {
1592
+ if (!record$6(manifest)) return {
1593
1593
  commands,
1594
1594
  errors: ["lint inventory requires an object package manifest"],
1595
1595
  enabled,
1596
1596
  workspaceTask: false
1597
1597
  };
1598
1598
  const scripts = manifest["scripts"];
1599
- if (!record$5(scripts)) return {
1599
+ if (!record$6(scripts)) return {
1600
1600
  commands,
1601
1601
  errors: ["type-aware linting requires a root lint script"],
1602
1602
  enabled,
@@ -1738,7 +1738,7 @@ const checkProjectOwnership = ({ trackedFiles, lintedFiles, projectFiles }) => [
1738
1738
  line: 1,
1739
1739
  message: "type-aware lint would use an inferred project; include this file in a declared tsconfig project (for Node scripts, add scripts/tsconfig.json extending @stll/typescript-config/node.json; see the Node scripts recipe in stella/tooling README)"
1740
1740
  }));
1741
- const record$4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1741
+ const record$5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1742
1742
  const stringList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string");
1743
1743
  const readCommand = ({ root, executable, args, runtime }) => {
1744
1744
  const result = (0, node_child_process.spawnSync)(runtime, [
@@ -1782,7 +1782,7 @@ const resolveProjectApi = (root) => {
1782
1782
  for (const base of [require("url").pathToFileURL(__filename).href, node_path.default.join(root, "package.json")]) try {
1783
1783
  return (0, node_url.pathToFileURL)((0, node_module.createRequire)(base).resolve("tsrs/unstable/async")).href;
1784
1784
  } catch (error) {
1785
- const code = record$4(error) ? error["code"] : void 0;
1785
+ const code = record$5(error) ? error["code"] : void 0;
1786
1786
  if (code !== "MODULE_NOT_FOUND" && code !== "ERR_MODULE_NOT_FOUND") throw error;
1787
1787
  }
1788
1788
  throw new Error("configuration discovery needs tsrs: reinstall @stll/oxlint-config, which depends on it");
@@ -1805,7 +1805,7 @@ const readProjectConfig = (root, config) => {
1805
1805
  if (result.error !== void 0) throw result.error;
1806
1806
  if (result.status !== 0) throw new Error(`configuration discovery failed: ${(result.stderr + result.stdout).trim()}`);
1807
1807
  const parsed = JSON.parse(result.stdout);
1808
- if (!record$4(parsed) || !stringList(parsed["files"]) || !stringList(parsed["references"]) || typeof parsed["allowJs"] !== "boolean" || typeof parsed["checkJs"] !== "boolean") throw new Error("compiler configuration must list files and references");
1808
+ if (!record$5(parsed) || !stringList(parsed["files"]) || !stringList(parsed["references"]) || typeof parsed["allowJs"] !== "boolean" || typeof parsed["checkJs"] !== "boolean") throw new Error("compiler configuration must list files and references");
1809
1809
  return {
1810
1810
  files: parsed["files"],
1811
1811
  references: parsed["references"],
@@ -1830,7 +1830,7 @@ const lifecycleFile = (root, file, tracked) => {
1830
1830
  };
1831
1831
  /** Inventory and config expansion only: neither subprocess lints or typechecks. */
1832
1832
  const checkNodeProjects = ({ root, manifest, trackedFiles }) => {
1833
- const packageManager = record$4(manifest) ? manifest["packageManager"] : void 0;
1833
+ const packageManager = record$5(manifest) ? manifest["packageManager"] : void 0;
1834
1834
  const managerUsesPnpmWorkspace = packageManager === void 0 || typeof packageManager === "string" && packageManager.startsWith("pnpm@");
1835
1835
  const discovered = /* @__PURE__ */ new Map();
1836
1836
  const workspaceMembers = (pnpmMembership) => {
@@ -1866,7 +1866,7 @@ const checkNodeProjects = ({ root, manifest, trackedFiles }) => {
1866
1866
  return nestedLifecycle;
1867
1867
  };
1868
1868
  const lifecycle = {
1869
- packageManager: record$4(manifest) ? manifest["packageManager"] : void 0,
1869
+ packageManager: record$5(manifest) ? manifest["packageManager"] : void 0,
1870
1870
  npmrc: lifecycleFile(root, ".npmrc", trackedFiles),
1871
1871
  pnpmWorkspace: lifecycleFile(root, "pnpm-workspace.yaml", trackedFiles),
1872
1872
  yarnrc: lifecycleFile(root, ".yarnrc.yml", trackedFiles),
@@ -1877,7 +1877,7 @@ const checkNodeProjects = ({ root, manifest, trackedFiles }) => {
1877
1877
  if (member === void 0) throw new Error("Missing selected workspace");
1878
1878
  const [directory, pkg] = member;
1879
1879
  const scripts = pkg["scripts"];
1880
- if (!record$4(scripts) || typeof scripts["build"] !== "string") throw new Error("Filtered Bun build requires a literal build script");
1880
+ if (!record$5(scripts) || typeof scripts["build"] !== "string") throw new Error("Filtered Bun build requires a literal build script");
1881
1881
  if (["prebuild", "postbuild"].some((name) => scripts[name] !== void 0 && scripts[name] !== "")) throw new Error("Filtered Bun build lifecycle hooks are unsupported for lint inventory; invoke lint scopes explicitly");
1882
1882
  if (activeBuilds.has(directory)) throw new Error("Cyclic filtered Bun build delegation");
1883
1883
  activeBuilds.add(directory);
@@ -1919,7 +1919,7 @@ const checkNodeProjects = ({ root, manifest, trackedFiles }) => {
1919
1919
  for (const [directory, workspace] of workspaceMembers(managerUsesPnpmWorkspace)) {
1920
1920
  if (directory === ".") continue;
1921
1921
  const file = `${directory}/package.json`;
1922
- if (!record$4(workspace["scripts"]) || workspace["scripts"]["lint"] === void 0) continue;
1922
+ if (!record$5(workspace["scripts"]) || workspace["scripts"]["lint"] === void 0) continue;
1923
1923
  const nestedLifecycle = workspaceLifecycle(directory);
1924
1924
  const nested = lintInventoryCommands(workspace, true, nestedLifecycle);
1925
1925
  if (nested.workspaceTask) throw new Error(`nested workspace lint delegation is unsupported: ${file}`);
@@ -2028,7 +2028,7 @@ const checkNodeProjects = ({ root, manifest, trackedFiles }) => {
2028
2028
  };
2029
2029
  //#endregion
2030
2030
  //#region src/toolchain-rust.ts
2031
- const record$3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2031
+ const record$4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2032
2032
  /**
2033
2033
  * Exceptions authorize one immutable release, never a channel or an entire
2034
2034
  * rule. Expiry is scoped separately by checkRustExceptionExpiry.
@@ -2038,7 +2038,7 @@ const parseRustExceptions = (input) => {
2038
2038
  if (!Array.isArray(input)) throw new Error("rustExceptions must be an array");
2039
2039
  const pins = /* @__PURE__ */ new Set();
2040
2040
  return input.map((entry) => {
2041
- if (!record$3(entry) || Object.keys(entry).length !== 4 || Object.keys(entry).some((key) => ![
2041
+ if (!record$4(entry) || Object.keys(entry).length !== 4 || Object.keys(entry).some((key) => ![
2042
2042
  "pin",
2043
2043
  "reason",
2044
2044
  "tracking",
@@ -2056,8 +2056,8 @@ const parseRustExceptions = (input) => {
2056
2056
  /** Whether the base stll-toolchain.json declares this exception with the same expiry. */
2057
2057
  const declaresException = (baseText, { pin, expires }) => {
2058
2058
  const base = JSON.parse(baseText);
2059
- const exceptions = record$3(base) ? base["rustExceptions"] : void 0;
2060
- return Array.isArray(exceptions) && exceptions.some((entry) => record$3(entry) && entry["pin"] === pin && entry["expires"] === expires);
2059
+ const exceptions = record$4(base) ? base["rustExceptions"] : void 0;
2060
+ return Array.isArray(exceptions) && exceptions.some((entry) => record$4(entry) && entry["pin"] === pin && entry["expires"] === expires);
2061
2061
  };
2062
2062
  /** An exception expires on its date; the scope decides whether that fails this run. */
2063
2063
  const checkRustExceptionExpiry = ({ exceptions, now = /* @__PURE__ */ new Date(), scope }) => {
@@ -2195,7 +2195,9 @@ const checkRustReferences = (options) => {
2195
2195
  }
2196
2196
  if (token.value.startsWith("-")) continue;
2197
2197
  selected++;
2198
- select(token.value, "rustup toolchain", token.line);
2198
+ const installFixture = options.type === "file" && require_toolchain_inputs.isShellScript(file, text) && subcommand === "toolchain" && invocation.at(1)?.value === "install" && !invocation.some((word) => word.value === "--default") ? options.installFixtures?.find((entry) => entry.path === file && entry.pin === token.value) : void 0;
2199
+ if (installFixture !== void 0) options.onInstallFixture?.(installFixture);
2200
+ else select(token.value, "rustup toolchain", token.line);
2199
2201
  if (firstSelectorOnly) break;
2200
2202
  }
2201
2203
  if (selected === 0 && requiresSelector) select(void 0, "rustup toolchain", firstLine);
@@ -2216,7 +2218,7 @@ const checkRustReferences = (options) => {
2216
2218
  if (require_toolchain_inputs.isShellScript(file, text)) shell(text);
2217
2219
  if (/(?:^|\/)package\.json$/.test(file)) try {
2218
2220
  const object = JSON.parse(text);
2219
- if (record$3(object) && record$3(object["scripts"])) {
2221
+ if (record$4(object) && record$4(object["scripts"])) {
2220
2222
  for (const [name, script] of Object.entries(object["scripts"])) if (typeof script === "string") shell(script, lineOf(`"${name}"`));
2221
2223
  }
2222
2224
  } catch {}
@@ -2227,7 +2229,7 @@ const checkRustReferences = (options) => {
2227
2229
  const version = tag === void 0 ? void 0 : require_toolchain_dependabot.rustImageVersion(tag);
2228
2230
  select(version, "Rust service image", lineOf(value));
2229
2231
  } else if (Array.isArray(value)) value.forEach(images);
2230
- else if (record$3(value)) {
2232
+ else if (record$4(value)) {
2231
2233
  for (const [key, entry] of Object.entries(value)) if (key !== "name") images(entry);
2232
2234
  }
2233
2235
  };
@@ -2251,13 +2253,13 @@ const checkRustReferences = (options) => {
2251
2253
  value.forEach(visit);
2252
2254
  return;
2253
2255
  }
2254
- if (!record$3(value)) return;
2255
- if (record$3(value["env"]) && value["env"]["RUSTUP_TOOLCHAIN"] !== void 0) select(value["env"]["RUSTUP_TOOLCHAIN"], "RUSTUP_TOOLCHAIN", lineOf("RUSTUP_TOOLCHAIN"));
2256
+ if (!record$4(value)) return;
2257
+ if (record$4(value["env"]) && value["env"]["RUSTUP_TOOLCHAIN"] !== void 0) select(value["env"]["RUSTUP_TOOLCHAIN"], "RUSTUP_TOOLCHAIN", lineOf("RUSTUP_TOOLCHAIN"));
2256
2258
  if (typeof value["run"] === "string") shell(value["run"], lineOf("run:"));
2257
2259
  const uses = value["uses"];
2258
2260
  if (typeof uses === "string") {
2259
2261
  const action = uses.split("@").at(0)?.toLowerCase();
2260
- const inputs = record$3(value["with"]) ? value["with"] : {};
2262
+ const inputs = record$4(value["with"]) ? value["with"] : {};
2261
2263
  if (action === "dtolnay/rust-toolchain" || action === "actions-rust-lang/setup-rust-toolchain") {
2262
2264
  const entries = Object.entries(inputs).filter(([key]) => key.toLowerCase() === "toolchain");
2263
2265
  if (entries.length !== 1) select(void 0, `${action} requires an explicit exact toolchain input`, lineOf(uses));
@@ -2271,8 +2273,8 @@ const checkRustReferences = (options) => {
2271
2273
  }
2272
2274
  }
2273
2275
  for (const [key, child] of Object.entries(value)) {
2274
- if (key === "workflow_call" && record$3(child) && record$3(child["inputs"])) {
2275
- for (const [input, declaration] of Object.entries(child["inputs"])) if (["toolchain", "rust-toolchain"].includes(input) && record$3(declaration) && declaration["default"] !== void 0) select(declaration["default"], `reusable workflow default ${input}`, lineOf("default:"));
2276
+ if (key === "workflow_call" && record$4(child) && record$4(child["inputs"])) {
2277
+ for (const [input, declaration] of Object.entries(child["inputs"])) if (["toolchain", "rust-toolchain"].includes(input) && record$4(declaration) && declaration["default"] !== void 0) select(declaration["default"], `reusable workflow default ${input}`, lineOf("default:"));
2276
2278
  }
2277
2279
  visit(child);
2278
2280
  }
@@ -2283,7 +2285,7 @@ const checkRustReferences = (options) => {
2283
2285
  };
2284
2286
  //#endregion
2285
2287
  //#region src/toolchain-workflow-trust.ts
2286
- const record$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2288
+ const record$3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2287
2289
  const booleanParts = (source, operator) => {
2288
2290
  const parts = [];
2289
2291
  let depth = 0;
@@ -2533,7 +2535,7 @@ const safeAction = (uses, inputs) => {
2533
2535
  const approved = Object.entries(workflowTrustBootstrapCatalog.actions).find(([name]) => name === repository);
2534
2536
  if (approved === void 0) return false;
2535
2537
  if (inputs === void 0) return repository === "actions/checkout";
2536
- if (!record$2(inputs)) return false;
2538
+ if (!record$3(inputs)) return false;
2537
2539
  if (repository !== "actions/checkout") {
2538
2540
  const version = inputs["bun-version"];
2539
2541
  if (typeof version !== "string" || !/^v?[0-9]+(?:\.(?:[0-9]+|x)){0,2}$/u.test(version)) return false;
@@ -2546,7 +2548,7 @@ const safeAction = (uses, inputs) => {
2546
2548
  ].includes(typeof value) && (name !== "submodules" || value === false || value === "false"));
2547
2549
  };
2548
2550
  const safeShell = (shell) => shell === void 0 || shell === "bash" || shell === "sh";
2549
- const safeEnvironment = (value) => value === void 0 || record$2(value) && Object.keys(value).every((name) => [
2551
+ const safeEnvironment = (value) => value === void 0 || record$3(value) && Object.keys(value).every((name) => [
2550
2552
  "HEAD_REPO",
2551
2553
  "BASE_REPO",
2552
2554
  "HAS_RUN_CI_LABEL",
@@ -2560,25 +2562,25 @@ const safeEnvironment = (value) => value === void 0 || record$2(value) && Object
2560
2562
  "HAWK_VERSION",
2561
2563
  "HAWK_X86_64_UNKNOWN_LINUX_GNU_SHA256"
2562
2564
  ].includes(name));
2563
- const configuredShell = (value) => record$2(value) && record$2(value["run"]) ? value["run"]["shell"] : void 0;
2565
+ const configuredShell = (value) => record$3(value) && record$3(value["run"]) ? value["run"]["shell"] : void 0;
2564
2566
  const workflowTrustRules = ["workflow-trust"];
2565
2567
  const workflowEvents = (triggers) => {
2566
2568
  if (typeof triggers === "string") return [triggers];
2567
2569
  if (Array.isArray(triggers)) return triggers;
2568
- if (record$2(triggers)) return Object.keys(triggers);
2570
+ if (record$3(triggers)) return Object.keys(triggers);
2569
2571
  return [];
2570
2572
  };
2571
2573
  /** Enforce a workflow's declared trust boundary before repository dependency execution. */
2572
2574
  const checkWorkflowTrust = (workflow) => {
2573
2575
  const findings = [];
2574
- if (!record$2(workflow) || !record$2(workflow["jobs"])) return findings;
2576
+ if (!record$3(workflow) || !record$3(workflow["jobs"])) return findings;
2575
2577
  const jobs = workflow["jobs"];
2576
- if (!record$2(jobs["trust-check"])) return findings;
2578
+ if (!record$3(jobs["trust-check"])) return findings;
2577
2579
  const triggers = workflow["on"];
2578
2580
  const pullRequests = workflowEvents(triggers).filter((event) => event === "pull_request" || event === "pull_request_target");
2579
2581
  if (pullRequests.length === 0) return findings;
2580
2582
  for (const [name, job] of Object.entries(jobs)) {
2581
- if (!record$2(job)) continue;
2583
+ if (!record$3(job)) continue;
2582
2584
  const needs = job["needs"];
2583
2585
  const ordered = name !== "trust-check" && (needs === "trust-check" || Array.isArray(needs) && needs.includes("trust-check"));
2584
2586
  const permitsExecution = (stepCondition) => {
@@ -2615,7 +2617,7 @@ const checkWorkflowTrust = (workflow) => {
2615
2617
  message
2616
2618
  });
2617
2619
  const services = job["services"];
2618
- if (services !== void 0 && (!record$2(services) || Object.keys(services).length > 0)) findings.push({
2620
+ if (services !== void 0 && (!record$3(services) || Object.keys(services).length > 0)) findings.push({
2619
2621
  type: "job",
2620
2622
  property: "services",
2621
2623
  job: name,
@@ -2624,7 +2626,7 @@ const checkWorkflowTrust = (workflow) => {
2624
2626
  }
2625
2627
  if (!Array.isArray(job["steps"])) continue;
2626
2628
  for (const [index, step] of job["steps"].entries()) {
2627
- if (!record$2(step)) continue;
2629
+ if (!record$3(step)) continue;
2628
2630
  const run = step["run"];
2629
2631
  const uses = step["uses"];
2630
2632
  const unsafeRun = typeof run === "string" && (invokesRepositoryCode(run) || !safeShell(step["shell"] ?? configuredShell(job["defaults"]) ?? configuredShell(workflow["defaults"])) || ![
@@ -2662,7 +2664,7 @@ const runtimeRules = [
2662
2664
  "action-pins",
2663
2665
  ...workflowTrustRules
2664
2666
  ];
2665
- const record$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2667
+ const record$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2666
2668
  const dockerEnvironmentAssignments = ({ source, escape }) => {
2667
2669
  const words = [];
2668
2670
  let word = "";
@@ -2795,13 +2797,15 @@ const pythonRequirementMatches = (requirement, version) => {
2795
2797
  });
2796
2798
  };
2797
2799
  /** Check runtime declarations only in the files that declare or configure them. */
2798
- const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, repository, onDelegated, dynamicSelectors = [], onDynamicSelector, rustExceptions = [], engineFloors = [], onEngineFloor }) => {
2800
+ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, repository, onDelegated, dynamicSelectors = [], onDynamicSelector, rustExceptions = [], rustInstallFixtures = [], onRustInstallFixture, engineFloors = [], onEngineFloor }) => {
2799
2801
  const diagnostics = checkRustReferences({
2800
2802
  type: "file",
2801
2803
  file,
2802
2804
  text,
2803
2805
  rust: policy.rust,
2804
- exceptions: rustExceptions
2806
+ exceptions: rustExceptions,
2807
+ installFixtures: rustInstallFixtures,
2808
+ onInstallFixture: onRustInstallFixture
2805
2809
  });
2806
2810
  const name = node_path.default.posix.basename(file);
2807
2811
  const lines = text.split(/\r?\n/);
@@ -2897,7 +2901,7 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2897
2901
  const toolchain = parsed["toolchain"];
2898
2902
  pin({
2899
2903
  rule: "rust-version",
2900
- value: record$1(toolchain) ? toolchain["channel"] : void 0,
2904
+ value: record$2(toolchain) ? toolchain["channel"] : void 0,
2901
2905
  expected: policy.rust,
2902
2906
  label: "Rust channel",
2903
2907
  line: lineOf("channel")
@@ -2925,15 +2929,15 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2925
2929
  };
2926
2930
  if (parsed !== void 0) {
2927
2931
  const workspace = parsed["workspace"];
2928
- const defaults = record$1(workspace) ? workspace["package"] : void 0;
2929
- if (record$1(defaults) && defaults["rust-version"] !== void 0) rustFloor(defaults["rust-version"]);
2932
+ const defaults = record$2(workspace) ? workspace["package"] : void 0;
2933
+ if (record$2(defaults) && defaults["rust-version"] !== void 0) rustFloor(defaults["rust-version"]);
2930
2934
  const pkg = parsed["package"];
2931
- const version = record$1(pkg) ? pkg["rust-version"] : void 0;
2935
+ const version = record$2(pkg) ? pkg["rust-version"] : void 0;
2932
2936
  if (version !== void 0) {
2933
- if (!record$1(version)) rustFloor(version);
2937
+ if (!record$2(version)) rustFloor(version);
2934
2938
  else {
2935
2939
  let inherited;
2936
- if (version["workspace"] === true && record$1(pkg)) {
2940
+ if (version["workspace"] === true && record$2(pkg)) {
2937
2941
  const explicit = pkg["workspace"];
2938
2942
  let directory = node_path.default.posix.dirname(file);
2939
2943
  const explicitPath = typeof explicit === "string" && !explicit.includes("\\") && !explicit.includes(":") && !explicit.includes("${{") && !node_path.default.posix.isAbsolute(explicit) ? node_path.default.posix.normalize(node_path.default.posix.join(directory, explicit)) : void 0;
@@ -2941,9 +2945,9 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2941
2945
  if (explicitPath !== void 0) directory = explicitPath;
2942
2946
  while (true) {
2943
2947
  const table = readManifest(node_path.default.posix.join(directory, "Cargo.toml"))?.["workspace"];
2944
- if (record$1(table)) {
2948
+ if (record$2(table)) {
2945
2949
  const fields = table["package"];
2946
- inherited = record$1(fields) ? fields["rust-version"] : void 0;
2950
+ inherited = record$2(fields) ? fields["rust-version"] : void 0;
2947
2951
  break;
2948
2952
  }
2949
2953
  if (explicit !== void 0 || directory === ".") break;
@@ -2958,7 +2962,7 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2958
2962
  }
2959
2963
  if (name === "Pipfile") {
2960
2964
  const requires = toml("python-version")?.["requires"];
2961
- if (record$1(requires)) {
2965
+ if (record$2(requires)) {
2962
2966
  const minor = requires["python_version"];
2963
2967
  if (minor !== void 0 && minor !== policy.python.split(".").slice(0, 2).join(".")) add({
2964
2968
  rule: "python-version",
@@ -2977,7 +2981,7 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2977
2981
  const parsed = toml("python-version");
2978
2982
  if (parsed !== void 0) {
2979
2983
  const project = parsed["project"];
2980
- if (record$1(project) && project["requires-python"] !== void 0) {
2984
+ if (record$2(project) && project["requires-python"] !== void 0) {
2981
2985
  if (!pythonRequirementMatches(project["requires-python"], policy.python)) add({
2982
2986
  rule: "python-version",
2983
2987
  line: lineOf("requires-python"),
@@ -2985,9 +2989,9 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2985
2989
  });
2986
2990
  }
2987
2991
  const tool = parsed["tool"];
2988
- const configuredUv = record$1(tool) ? tool["uv"] : void 0;
2992
+ const configuredUv = record$2(tool) ? tool["uv"] : void 0;
2989
2993
  const uv = name === "uv.toml" ? parsed : configuredUv;
2990
- if (record$1(uv) && uv["python"] !== void 0) pin({
2994
+ if (record$2(uv) && uv["python"] !== void 0) pin({
2991
2995
  rule: "python-version",
2992
2996
  value: uv["python"],
2993
2997
  expected: policy.python,
@@ -2998,11 +3002,11 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
2998
3002
  }
2999
3003
  if (require_toolchain_inputs.isMiseConfigPath(file)) {
3000
3004
  const tools = toml("runtime-manager")?.["tools"];
3001
- if (record$1(tools)) for (const [tool, expected] of Object.entries(versions)) {
3005
+ if (record$2(tools)) for (const [tool, expected] of Object.entries(versions)) {
3002
3006
  const configured = tools[tool];
3003
3007
  if (configured !== void 0) pin({
3004
3008
  rule: tool === "rust" || tool === "core:rust" ? "rust-version" : "runtime-manager",
3005
- value: record$1(configured) ? configured["version"] : configured,
3009
+ value: record$2(configured) ? configured["version"] : configured,
3006
3010
  expected,
3007
3011
  selector: nodeTools.has(tool) ? "node" : void 0,
3008
3012
  label: `mise ${tool}`,
@@ -3350,7 +3354,7 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
3350
3354
  return diagnostics;
3351
3355
  }
3352
3356
  const nodeLine = (node) => {
3353
- if (!record$1(node) || !Array.isArray(node["range"])) return 1;
3357
+ if (!record$2(node) || !Array.isArray(node["range"])) return 1;
3354
3358
  const offset = node["range"].at(0);
3355
3359
  return typeof offset === "number" ? text.slice(0, offset).split("\n").length : 1;
3356
3360
  };
@@ -3464,7 +3468,7 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
3464
3468
  const manifest = JSON.parse(content ?? "");
3465
3469
  pin({
3466
3470
  rule,
3467
- value: record$1(manifest) ? manifest["packageManager"] : void 0,
3471
+ value: record$2(manifest) ? manifest["packageManager"] : void 0,
3468
3472
  expected: `bun@${policy.bun}`,
3469
3473
  label: "setup-bun version file packageManager",
3470
3474
  line
@@ -3664,10 +3668,21 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
3664
3668
  const selector = staticRepositoryPath(value) ? node_path.default.posix.normalize(value) : void 0;
3665
3669
  const providers = checkoutProvidersFor(selector);
3666
3670
  const binding = selector === void 0 ? void 0 : providers.at(-1);
3667
- if (selector === void 0 || unknownCheckoutDestination || binding !== void 0 && binding.source !== "tracked" || hasAmbiguousCheckoutWriters(selector, providers)) add({
3668
- rule: "action-pins",
3671
+ if (selector === void 0 || unknownCheckoutDestination || binding?.source === "untrusted" || binding?.source === "delegated" && !/^(?:inputs\.[A-Za-z_][A-Za-z0-9_]*|github\.event\.workflow_run\.head_sha)$/.test(dynamicRefBody(binding.ref) ?? "") || hasAmbiguousCheckoutWriters(selector, providers)) {
3672
+ add({
3673
+ rule: "action-pins",
3674
+ line,
3675
+ message: "local actions require an unambiguous checkout of the current source snapshot"
3676
+ });
3677
+ return;
3678
+ }
3679
+ if (binding?.source === "delegated") onDelegated?.({
3680
+ path: file,
3669
3681
  line,
3670
- message: "local actions require an unambiguous checkout of the current source snapshot"
3682
+ tool: "action",
3683
+ selector,
3684
+ checkoutPath: binding.path,
3685
+ ref: binding.ref
3671
3686
  });
3672
3687
  return;
3673
3688
  }
@@ -3965,6 +3980,54 @@ const checkRuntimeFile = ({ file, text, policy, trackedFiles, readFile, reposito
3965
3980
  return diagnostics;
3966
3981
  };
3967
3982
  //#endregion
3983
+ //#region src/toolchain-rust-fixtures.ts
3984
+ const record$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3985
+ const date = (value) => /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(value)) && new Date(value).toISOString().slice(0, 10) === value;
3986
+ /** Historical install probes do not authorize using an older compiler. */
3987
+ const parseRustInstallFixtures = (input) => {
3988
+ if (input === void 0) return [];
3989
+ if (!Array.isArray(input)) throw new Error("rustInstallFixtures must be an array");
3990
+ const identities = /* @__PURE__ */ new Set();
3991
+ return input.map((entry) => {
3992
+ if (!record$1(entry) || Object.keys(entry).length !== 5 || Object.keys(entry).some((key) => ![
3993
+ "path",
3994
+ "pin",
3995
+ "reason",
3996
+ "tracking",
3997
+ "expires"
3998
+ ].includes(key)) || typeof entry["path"] !== "string" || !/^(?:[A-Za-z0-9_-]+\/)*[A-Za-z0-9_-]+\.sh$/.test(entry["path"]) || typeof entry["pin"] !== "string" || !(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/.test(entry["pin"]) || entry["pin"].startsWith("nightly-") && date(entry["pin"].slice(8))) || typeof entry["reason"] !== "string" || entry["reason"].trim() === "" || typeof entry["tracking"] !== "string" || !/^https:\/\/github\.com\/[^/\s]+\/[^/\s]+\/(?:issues|pull)\/[1-9]\d*$/.test(entry["tracking"]) || typeof entry["expires"] !== "string" || !date(entry["expires"])) throw new Error("each Rust install fixture requires an exact shell path, stable or dated nightly pin, reason, GitHub tracking URL and valid expiry date");
3999
+ const identity = `${entry["path"]}:${entry["pin"]}`;
4000
+ if (identities.has(identity)) throw new Error("Rust install fixture path/pin pairs must be unique");
4001
+ identities.add(identity);
4002
+ return {
4003
+ path: entry["path"],
4004
+ pin: entry["pin"],
4005
+ reason: entry["reason"],
4006
+ tracking: entry["tracking"],
4007
+ expires: entry["expires"]
4008
+ };
4009
+ });
4010
+ };
4011
+ const checkRustInstallFixtureExpiry = ({ fixtures, scope, now = /* @__PURE__ */ new Date() }) => {
4012
+ const errors = [];
4013
+ const warnings = [];
4014
+ for (const fixture of fixtures) {
4015
+ if (fixture.expires > now.toISOString().slice(0, 10)) continue;
4016
+ const verdict = require_quarantine_policy.overdueVerdict(scope, "stll-toolchain.json", (text) => {
4017
+ const base = JSON.parse(text);
4018
+ const declarations = record$1(base) ? base["rustInstallFixtures"] : void 0;
4019
+ return Array.isArray(declarations) && declarations.some((entry) => record$1(entry) && entry["path"] === fixture.path && entry["pin"] === fixture.pin && entry["expires"] === fixture.expires);
4020
+ });
4021
+ const message = `Rust install fixture ${fixture.path}:${fixture.pin} expired on ${fixture.expires}; remove it or renew the documented fixture boundary`;
4022
+ if (!verdict.fail) warnings.push(message);
4023
+ else errors.push(verdict.unavailable === void 0 ? message : `${message}; cannot determine whether this change adds it: ${verdict.unavailable}`);
4024
+ }
4025
+ return {
4026
+ errors,
4027
+ warnings
4028
+ };
4029
+ };
4030
+ //#endregion
3968
4031
  //#region src/toolchain-guard.ts
3969
4032
  const toolchainRules = [.../* @__PURE__ */ new Set([
3970
4033
  ...packageRules,
@@ -3979,7 +4042,7 @@ const record = (value) => typeof value === "object" && value !== null && !Array.
3979
4042
  const array = (value) => Array.isArray(value);
3980
4043
  /** Repository-owned declarations are explicit; malformed decisions fail closed. */
3981
4044
  const parseToolchainConfiguration = (input) => {
3982
- if (!record(input) || Object.keys(input).some((key) => key !== "optOuts" && key !== "cloud" && key !== "engineFloors" && key !== "dynamicSelectors" && key !== "consumerChecks" && key !== "rustExceptions" && key !== "dependabotIgnores" && key !== "typescriptAllowlist") || input["optOuts"] !== void 0 && !array(input["optOuts"])) throw new Error("stll-toolchain.json accepts only optOuts, cloud, engineFloors, dynamicSelectors, consumerChecks, rustExceptions, dependabotIgnores and typescriptAllowlist declarations");
4045
+ if (!record(input) || Object.keys(input).some((key) => key !== "optOuts" && key !== "cloud" && key !== "engineFloors" && key !== "dynamicSelectors" && key !== "consumerChecks" && key !== "rustExceptions" && key !== "rustInstallFixtures" && key !== "dependabotIgnores" && key !== "typescriptAllowlist") || input["optOuts"] !== void 0 && !array(input["optOuts"])) throw new Error("stll-toolchain.json accepts only optOuts, cloud, engineFloors, dynamicSelectors, consumerChecks, rustExceptions, rustInstallFixtures, dependabotIgnores and typescriptAllowlist declarations");
3983
4046
  const disabled = /* @__PURE__ */ new Set();
3984
4047
  const optOuts = input["optOuts"] ?? [];
3985
4048
  if (!array(optOuts)) throw new Error("optOuts must be an array");
@@ -3996,6 +4059,7 @@ const parseToolchainConfiguration = (input) => {
3996
4059
  return {
3997
4060
  disabled,
3998
4061
  rustExceptions: parseRustExceptions(input["rustExceptions"]),
4062
+ rustInstallFixtures: parseRustInstallFixtures(input["rustInstallFixtures"]),
3999
4063
  cloud: require_toolchain_inputs.parseCloudSetup(input["cloud"]),
4000
4064
  engineFloors: parseEngineFloors(input["engineFloors"]),
4001
4065
  dynamicSelectors: parseDynamicSelectors(input["dynamicSelectors"]),
@@ -4088,11 +4152,20 @@ const checkToolchain = ({ root, policy: sharedPolicy, onDelegated, onWarning, no
4088
4152
  if (files["stll-toolchain.json"] !== void 0) try {
4089
4153
  configuration = parseToolchainConfiguration(JSON.parse(files["stll-toolchain.json"]));
4090
4154
  dynamicSelectors = configuration.dynamicSelectors;
4091
- const expiry = checkRustExceptionExpiry({
4155
+ const rustExpiry = checkRustExceptionExpiry({
4092
4156
  exceptions: configuration.rustExceptions,
4093
4157
  now,
4094
4158
  scope: expiryScope
4095
4159
  });
4160
+ const fixtureExpiry = checkRustInstallFixtureExpiry({
4161
+ fixtures: configuration.rustInstallFixtures,
4162
+ now,
4163
+ scope: expiryScope
4164
+ });
4165
+ const expiry = {
4166
+ errors: [...rustExpiry.errors, ...fixtureExpiry.errors],
4167
+ warnings: [...rustExpiry.warnings, ...fixtureExpiry.warnings]
4168
+ };
4096
4169
  for (const message of expiry.errors) diagnostics.push({
4097
4170
  rule: "configuration",
4098
4171
  path: "stll-toolchain.json",
@@ -4226,6 +4299,7 @@ const checkToolchain = ({ root, policy: sharedPolicy, onDelegated, onWarning, no
4226
4299
  trackedFiles
4227
4300
  }));
4228
4301
  }
4302
+ const usedRustFixtures = /* @__PURE__ */ new Set();
4229
4303
  for (const [file, text] of Object.entries(files)) diagnostics.push(...checkRuntimeFile({
4230
4304
  file,
4231
4305
  text,
@@ -4238,6 +4312,8 @@ const checkToolchain = ({ root, policy: sharedPolicy, onDelegated, onWarning, no
4238
4312
  },
4239
4313
  trackedFiles,
4240
4314
  rustExceptions: configuration.rustExceptions,
4315
+ rustInstallFixtures: configuration.rustInstallFixtures,
4316
+ onRustInstallFixture: (entry) => usedRustFixtures.add(entry),
4241
4317
  dynamicSelectors: dynamicSelectors.filter((entry) => entry.path === file),
4242
4318
  onDynamicSelector: (entry) => selectorMatches.set(entry, (selectorMatches.get(entry) ?? 0) + 1),
4243
4319
  repository,
@@ -4249,6 +4325,12 @@ const checkToolchain = ({ root, policy: sharedPolicy, onDelegated, onWarning, no
4249
4325
  },
4250
4326
  readFile: (target) => files[target]
4251
4327
  }));
4328
+ for (const entry of configuration.rustInstallFixtures) if (!usedRustFixtures.has(entry)) diagnostics.push({
4329
+ rule: "configuration",
4330
+ path: "stll-toolchain.json",
4331
+ line: 1,
4332
+ message: `Rust install fixture ${entry.path}:${entry.pin} must match a tracked rustup toolchain install probe`
4333
+ });
4252
4334
  for (const entry of engineFloors) if (!exercisedFloors.has(entry) || mismatchedFloors.has(entry)) diagnostics.push({
4253
4335
  rule: "configuration",
4254
4336
  path: "stll-toolchain.json",