@stll/oxlint-config 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -306,7 +306,8 @@ Add an explicit declaration to tracked root `stll-toolchain.json`:
306
306
  "tools": {
307
307
  "cargo-nextest": "0.9.148",
308
308
  "wasm-bindgen-cli": "0.2.126",
309
- "uv": "0.13.1"
309
+ "uv": "0.13.1",
310
+ "time": "1.9"
310
311
  }
311
312
  }
312
313
  }
@@ -336,10 +337,15 @@ setup also provisions Ubuntu's `build-essential` package for native compilation
336
337
  and linking.
337
338
 
338
339
  `cloud.tools` is a closed object: the supported keys are `cargo-nextest`,
339
- `wasm-bindgen-cli`, and `uv`. Each value must be an exact release supported by
340
+ `wasm-bindgen-cli`, `uv`, and `time`. Each value must be an exact release supported by
340
341
  the installed tooling package. Unknown tools and unsupported versions fail
341
- generation. These tools use versioned upstream Linux binaries with committed
342
+ generation. `cargo-nextest`, `wasm-bindgen-cli`, and `uv` use versioned upstream Linux binaries with committed
342
343
  SHA256 pins for amd64 and arm64; setup does not build them with `cargo install`.
344
+ `time` installs GNU time (`/usr/bin/time`, needed for `/usr/bin/time -v`) from
345
+ Ubuntu's `time` package with bounded apt; its value is the upstream release
346
+ (`1.9` on Ubuntu 24.04). GNU time reports its version as `UNKNOWN`, so setup
347
+ verifies the binary's GNU identity and the installed package release. A present,
348
+ matching package is reused without network access.
343
349
  `wasm-bindgen-cli` requires the matching `wasm-bindgen` crate version in tracked
344
350
  root `Cargo.lock`. Regenerate after updating the lockfile or any tool pin.
345
351
 
@@ -353,17 +359,22 @@ SHA256 pins, and installs those local files with apt. It does not resolve Valkey
353
359
  from a mutable package index.
354
360
  The command writes `.agents/cloud-setup.sh` with executable permissions and
355
361
  merges a `SessionStart` hook into `.claude/settings.json`. The hook runs
356
- `bash .agents/cloud-setup.sh start` only when `CLAUDE_CODE_REMOTE=true`, including
357
- sessions that reuse cached filesystems. After successful startup, it appends the
362
+ `bash "$CLAUDE_PROJECT_DIR/.agents/cloud-setup.sh" start` only when
363
+ `CLAUDE_CODE_REMOTE=true`, including sessions that reuse cached filesystems and
364
+ sessions started from a repository subdirectory. Generation replaces the
365
+ relative-path hook written by 1.1.0 in place. After successful startup, it appends the
358
366
  managed shell profile's literal exports to `CLAUDE_ENV_FILE` when available, so
359
367
  subsequent Claude commands select pinned runtimes and tools before preinstalled
360
- versions while retaining their inherited `PATH`. Existing environment-file
368
+ versions while retaining their inherited `PATH`. The settings also set
369
+ `"attribution": {"commit": "", "pr": ""}`, so cloud sessions add no tool
370
+ attribution to commits or pull requests. Existing environment-file
361
371
  content, unrelated settings, and hooks are preserved. Invalid JSON, disabled
362
- hooks, or conflicting cloud startup entries stop generation with a repair
363
- instruction. Commit both generated files.
372
+ hooks, conflicting cloud startup entries, or a different `attribution` value stop
373
+ generation with a repair instruction. Commit both generated files.
364
374
  Generation refuses symlink parents or destinations and hard-linked destinations.
365
- `stll-toolchain-check` rejects missing, drifted, or undeclared tracked scripts and
366
- missing or conflicting startup hooks with mandatory `cloud-setup-drift`.
375
+ `stll-toolchain-check` rejects missing, drifted, or undeclared tracked scripts,
376
+ missing or conflicting startup hooks, and missing or different attribution
377
+ settings with mandatory `cloud-setup-drift`.
367
378
  Regenerate after changing the policy or declaration. `stll-cloud-setup --help`
368
379
  prints usage without reading repository configuration.
369
380
 
@@ -425,7 +436,8 @@ GitHub release downloads redirect to `release-assets.githubusercontent.com`;
425
436
  allow that host as well. This includes Bun and the optional prebuilt tools.
426
437
  Rust provisioning uses `static.rust-lang.org` for both distribution and update endpoints.
427
438
 
428
- System prerequisites use the image's configured Ubuntu apt repositories:
439
+ System prerequisites and the optional `time` package use the image's configured
440
+ Ubuntu apt repositories:
429
441
  standard Ubuntu 24.04 images use `archive.ubuntu.com`, `security.ubuntu.com`,
430
442
  or `ports.ubuntu.com`, depending on architecture. Images configured with a
431
443
  mirror need that mirror's host instead. Frozen Bun installation also needs
@@ -84,7 +84,7 @@ const main = async () => {
84
84
  await checkOutput(destination);
85
85
  const settingsDestination = (0, node_path.join)(root, require_toolchain_inputs.cloudClaudeSettingsPath);
86
86
  const settings = await readClaudeSettings(settingsDestination);
87
- const mergedSettings = require_toolchain_inputs.mergeCloudSessionStartHook(settings?.text);
87
+ const mergedSettings = require_toolchain_inputs.mergeCloudClaudeSettings(settings?.text);
88
88
  await writeOutput({
89
89
  destination,
90
90
  text: script,
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-setup-cli.cjs","names":["lstat","dirname","mkdir","open","constants","cloudClaudeSettingsPath","cloudSessionStartFix","realpath","readToolchainInputs","parseToolchainConfiguration","parseToolchainPolicy","readFile","generateCloudSetup","join","cloudSetupPath","mergeCloudSessionStartHook"],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n mergeCloudSessionStartHook,\n} from \"./cloud-setup-claude\";\nimport {\n parseToolchainConfiguration,\n readToolchainInputs,\n} from \"./toolchain-guard\";\nimport { parseToolchainPolicy } from \"./toolchain-schema\";\n\nconst usage =\n \"Usage: stll-cloud-setup (run from repository root)\\n stll-cloud-setup --help\";\nconst optionalStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }\n};\n\nconst checkOutput = async (destination: string) => {\n const parent = dirname(destination);\n const parentStat = await optionalStat(parent);\n if (\n parentStat !== undefined &&\n (parentStat.isSymbolicLink() || !parentStat.isDirectory())\n )\n throw new Error(\"cloud setup parent must be a real repository directory\");\n const destinationStat = await optionalStat(destination);\n if (\n destinationStat !== undefined &&\n (destinationStat.isSymbolicLink() ||\n !destinationStat.isFile() ||\n destinationStat.nlink !== 1)\n )\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n return destinationStat;\n};\n\ntype WriteOutputOptions = {\n destination: string;\n text: string;\n mode: number;\n};\n\nconst writeOutput = async ({ destination, text, mode }: WriteOutputOptions) => {\n await checkOutput(destination);\n await mkdir(dirname(destination), { recursive: true });\n const output = await open(\n destination,\n constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW,\n mode,\n );\n try {\n const opened = await output.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n await output.truncate(0);\n await output.writeFile(text, \"utf8\");\n await output.chmod(mode);\n } finally {\n await output.close();\n }\n};\n\nconst readClaudeSettings = async (destination: string) => {\n try {\n if ((await checkOutput(destination)) === undefined) return undefined;\n const input = await open(\n destination,\n constants.O_RDONLY | constants.O_NOFOLLOW,\n );\n try {\n const opened = await input.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"settings must be a single-link regular repository file\",\n );\n return { text: await input.readFile(\"utf8\"), mode: opened.mode & 0o777 };\n } finally {\n await input.close();\n }\n } catch (error) {\n throw new Error(\n `cannot safely merge ${cloudClaudeSettingsPath}: ${error instanceof Error ? error.message : String(error)}; ${cloudSessionStartFix}`,\n );\n }\n};\n\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n if (args.length !== 0) throw new Error(usage);\n const root = await realpath(process.cwd());\n const { files, diagnostics } = readToolchainInputs(root);\n if (diagnostics.length > 0)\n throw new Error(\n diagnostics\n .map(\n ({ path, message }) =>\n `${path}: ${message}${path === cloudClaudeSettingsPath ? `; ${cloudSessionStartFix}` : \"\"}`,\n )\n .join(\"\\n\"),\n );\n const text = files[\"stll-toolchain.json\"];\n if (text === undefined)\n throw new Error(\"requires tracked stll-toolchain.json\");\n const { cloud, rustExceptions } = parseToolchainConfiguration(\n JSON.parse(text),\n );\n if (cloud === undefined)\n throw new Error(\"requires an explicit cloud declaration\");\n const nodeVersion = files[\".node-version\"];\n if (nodeVersion === undefined)\n throw new Error(\"requires tracked root .node-version\");\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const script = generateCloudSetup({\n policy,\n cloud,\n nodeVersion: nodeVersion.trim(),\n files,\n rustExceptions,\n });\n const destination = join(root, cloudSetupPath);\n await checkOutput(destination);\n const settingsDestination = join(root, cloudClaudeSettingsPath);\n const settings = await readClaudeSettings(settingsDestination);\n const mergedSettings = mergeCloudSessionStartHook(settings?.text);\n await writeOutput({ destination, text: script, mode: 0o755 });\n if (mergedSettings !== settings?.text)\n await writeOutput({\n destination: settingsDestination,\n text: mergedSettings,\n mode: settings?.mode ?? 0o644,\n });\n process.stdout.write(\n `Generated ${cloudSetupPath} and ${cloudClaudeSettingsPath}\\n`,\n );\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `cloud-setup: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cloud-setup-cli.cjs","names":["lstat","dirname","mkdir","open","constants","cloudClaudeSettingsPath","cloudSessionStartFix","realpath","readToolchainInputs","parseToolchainConfiguration","parseToolchainPolicy","readFile","generateCloudSetup","join","cloudSetupPath","mergeCloudClaudeSettings"],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n mergeCloudClaudeSettings,\n} from \"./cloud-setup-claude\";\nimport {\n parseToolchainConfiguration,\n readToolchainInputs,\n} from \"./toolchain-guard\";\nimport { parseToolchainPolicy } from \"./toolchain-schema\";\n\nconst usage =\n \"Usage: stll-cloud-setup (run from repository root)\\n stll-cloud-setup --help\";\nconst optionalStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }\n};\n\nconst checkOutput = async (destination: string) => {\n const parent = dirname(destination);\n const parentStat = await optionalStat(parent);\n if (\n parentStat !== undefined &&\n (parentStat.isSymbolicLink() || !parentStat.isDirectory())\n )\n throw new Error(\"cloud setup parent must be a real repository directory\");\n const destinationStat = await optionalStat(destination);\n if (\n destinationStat !== undefined &&\n (destinationStat.isSymbolicLink() ||\n !destinationStat.isFile() ||\n destinationStat.nlink !== 1)\n )\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n return destinationStat;\n};\n\ntype WriteOutputOptions = {\n destination: string;\n text: string;\n mode: number;\n};\n\nconst writeOutput = async ({ destination, text, mode }: WriteOutputOptions) => {\n await checkOutput(destination);\n await mkdir(dirname(destination), { recursive: true });\n const output = await open(\n destination,\n constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW,\n mode,\n );\n try {\n const opened = await output.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n await output.truncate(0);\n await output.writeFile(text, \"utf8\");\n await output.chmod(mode);\n } finally {\n await output.close();\n }\n};\n\nconst readClaudeSettings = async (destination: string) => {\n try {\n if ((await checkOutput(destination)) === undefined) return undefined;\n const input = await open(\n destination,\n constants.O_RDONLY | constants.O_NOFOLLOW,\n );\n try {\n const opened = await input.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"settings must be a single-link regular repository file\",\n );\n return { text: await input.readFile(\"utf8\"), mode: opened.mode & 0o777 };\n } finally {\n await input.close();\n }\n } catch (error) {\n throw new Error(\n `cannot safely merge ${cloudClaudeSettingsPath}: ${error instanceof Error ? error.message : String(error)}; ${cloudSessionStartFix}`,\n );\n }\n};\n\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n if (args.length !== 0) throw new Error(usage);\n const root = await realpath(process.cwd());\n const { files, diagnostics } = readToolchainInputs(root);\n if (diagnostics.length > 0)\n throw new Error(\n diagnostics\n .map(\n ({ path, message }) =>\n `${path}: ${message}${path === cloudClaudeSettingsPath ? `; ${cloudSessionStartFix}` : \"\"}`,\n )\n .join(\"\\n\"),\n );\n const text = files[\"stll-toolchain.json\"];\n if (text === undefined)\n throw new Error(\"requires tracked stll-toolchain.json\");\n const { cloud, rustExceptions } = parseToolchainConfiguration(\n JSON.parse(text),\n );\n if (cloud === undefined)\n throw new Error(\"requires an explicit cloud declaration\");\n const nodeVersion = files[\".node-version\"];\n if (nodeVersion === undefined)\n throw new Error(\"requires tracked root .node-version\");\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const script = generateCloudSetup({\n policy,\n cloud,\n nodeVersion: nodeVersion.trim(),\n files,\n rustExceptions,\n });\n const destination = join(root, cloudSetupPath);\n await checkOutput(destination);\n const settingsDestination = join(root, cloudClaudeSettingsPath);\n const settings = await readClaudeSettings(settingsDestination);\n const mergedSettings = mergeCloudClaudeSettings(settings?.text);\n await writeOutput({ destination, text: script, mode: 0o755 });\n if (mergedSettings !== settings?.text)\n await writeOutput({\n destination: settingsDestination,\n text: mergedSettings,\n mode: settings?.mode ?? 0o644,\n });\n process.stdout.write(\n `Generated ${cloudSetupPath} and ${cloudClaudeSettingsPath}\\n`,\n );\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `cloud-setup: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as mergeCloudSessionStartHook, h as cloudSessionStartFix, m as cloudClaudeSettingsPath, v as cloudSetupPath, y as generateCloudSetup } from "./toolchain-inputs.mjs";
2
+ import { b as cloudSetupPath, g as cloudSessionStartFix, h as cloudClaudeSettingsPath, x as generateCloudSetup, y as mergeCloudClaudeSettings } from "./toolchain-inputs.mjs";
3
3
  import { n as parseToolchainConfiguration, r as readToolchainInputs } from "./toolchain-guard.mjs";
4
4
  import { t as parseToolchainPolicy } from "./toolchain-schema.mjs";
5
5
  import { constants } from "node:fs";
@@ -83,7 +83,7 @@ const main = async () => {
83
83
  await checkOutput(destination);
84
84
  const settingsDestination = join(root, cloudClaudeSettingsPath);
85
85
  const settings = await readClaudeSettings(settingsDestination);
86
- const mergedSettings = mergeCloudSessionStartHook(settings?.text);
86
+ const mergedSettings = mergeCloudClaudeSettings(settings?.text);
87
87
  await writeOutput({
88
88
  destination,
89
89
  text: script,
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-setup-cli.mjs","names":[],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n mergeCloudSessionStartHook,\n} from \"./cloud-setup-claude\";\nimport {\n parseToolchainConfiguration,\n readToolchainInputs,\n} from \"./toolchain-guard\";\nimport { parseToolchainPolicy } from \"./toolchain-schema\";\n\nconst usage =\n \"Usage: stll-cloud-setup (run from repository root)\\n stll-cloud-setup --help\";\nconst optionalStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }\n};\n\nconst checkOutput = async (destination: string) => {\n const parent = dirname(destination);\n const parentStat = await optionalStat(parent);\n if (\n parentStat !== undefined &&\n (parentStat.isSymbolicLink() || !parentStat.isDirectory())\n )\n throw new Error(\"cloud setup parent must be a real repository directory\");\n const destinationStat = await optionalStat(destination);\n if (\n destinationStat !== undefined &&\n (destinationStat.isSymbolicLink() ||\n !destinationStat.isFile() ||\n destinationStat.nlink !== 1)\n )\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n return destinationStat;\n};\n\ntype WriteOutputOptions = {\n destination: string;\n text: string;\n mode: number;\n};\n\nconst writeOutput = async ({ destination, text, mode }: WriteOutputOptions) => {\n await checkOutput(destination);\n await mkdir(dirname(destination), { recursive: true });\n const output = await open(\n destination,\n constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW,\n mode,\n );\n try {\n const opened = await output.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n await output.truncate(0);\n await output.writeFile(text, \"utf8\");\n await output.chmod(mode);\n } finally {\n await output.close();\n }\n};\n\nconst readClaudeSettings = async (destination: string) => {\n try {\n if ((await checkOutput(destination)) === undefined) return undefined;\n const input = await open(\n destination,\n constants.O_RDONLY | constants.O_NOFOLLOW,\n );\n try {\n const opened = await input.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"settings must be a single-link regular repository file\",\n );\n return { text: await input.readFile(\"utf8\"), mode: opened.mode & 0o777 };\n } finally {\n await input.close();\n }\n } catch (error) {\n throw new Error(\n `cannot safely merge ${cloudClaudeSettingsPath}: ${error instanceof Error ? error.message : String(error)}; ${cloudSessionStartFix}`,\n );\n }\n};\n\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n if (args.length !== 0) throw new Error(usage);\n const root = await realpath(process.cwd());\n const { files, diagnostics } = readToolchainInputs(root);\n if (diagnostics.length > 0)\n throw new Error(\n diagnostics\n .map(\n ({ path, message }) =>\n `${path}: ${message}${path === cloudClaudeSettingsPath ? `; ${cloudSessionStartFix}` : \"\"}`,\n )\n .join(\"\\n\"),\n );\n const text = files[\"stll-toolchain.json\"];\n if (text === undefined)\n throw new Error(\"requires tracked stll-toolchain.json\");\n const { cloud, rustExceptions } = parseToolchainConfiguration(\n JSON.parse(text),\n );\n if (cloud === undefined)\n throw new Error(\"requires an explicit cloud declaration\");\n const nodeVersion = files[\".node-version\"];\n if (nodeVersion === undefined)\n throw new Error(\"requires tracked root .node-version\");\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const script = generateCloudSetup({\n policy,\n cloud,\n nodeVersion: nodeVersion.trim(),\n files,\n rustExceptions,\n });\n const destination = join(root, cloudSetupPath);\n await checkOutput(destination);\n const settingsDestination = join(root, cloudClaudeSettingsPath);\n const settings = await readClaudeSettings(settingsDestination);\n const mergedSettings = mergeCloudSessionStartHook(settings?.text);\n await writeOutput({ destination, text: script, mode: 0o755 });\n if (mergedSettings !== settings?.text)\n await writeOutput({\n destination: settingsDestination,\n text: mergedSettings,\n mode: settings?.mode ?? 0o644,\n });\n process.stdout.write(\n `Generated ${cloudSetupPath} and ${cloudClaudeSettingsPath}\\n`,\n );\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `cloud-setup: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"cloud-setup-cli.mjs","names":[],"sources":["../src/cloud-setup-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { constants } from \"node:fs\";\nimport { lstat, mkdir, open, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { cloudSetupPath, generateCloudSetup } from \"./cloud-setup\";\nimport {\n cloudClaudeSettingsPath,\n cloudSessionStartFix,\n mergeCloudClaudeSettings,\n} from \"./cloud-setup-claude\";\nimport {\n parseToolchainConfiguration,\n readToolchainInputs,\n} from \"./toolchain-guard\";\nimport { parseToolchainPolicy } from \"./toolchain-schema\";\n\nconst usage =\n \"Usage: stll-cloud-setup (run from repository root)\\n stll-cloud-setup --help\";\nconst optionalStat = async (path: string) => {\n try {\n return await lstat(path);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }\n};\n\nconst checkOutput = async (destination: string) => {\n const parent = dirname(destination);\n const parentStat = await optionalStat(parent);\n if (\n parentStat !== undefined &&\n (parentStat.isSymbolicLink() || !parentStat.isDirectory())\n )\n throw new Error(\"cloud setup parent must be a real repository directory\");\n const destinationStat = await optionalStat(destination);\n if (\n destinationStat !== undefined &&\n (destinationStat.isSymbolicLink() ||\n !destinationStat.isFile() ||\n destinationStat.nlink !== 1)\n )\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n return destinationStat;\n};\n\ntype WriteOutputOptions = {\n destination: string;\n text: string;\n mode: number;\n};\n\nconst writeOutput = async ({ destination, text, mode }: WriteOutputOptions) => {\n await checkOutput(destination);\n await mkdir(dirname(destination), { recursive: true });\n const output = await open(\n destination,\n constants.O_WRONLY | constants.O_CREAT | constants.O_NOFOLLOW,\n mode,\n );\n try {\n const opened = await output.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"cloud setup destination must be a single-link regular repository file\",\n );\n await output.truncate(0);\n await output.writeFile(text, \"utf8\");\n await output.chmod(mode);\n } finally {\n await output.close();\n }\n};\n\nconst readClaudeSettings = async (destination: string) => {\n try {\n if ((await checkOutput(destination)) === undefined) return undefined;\n const input = await open(\n destination,\n constants.O_RDONLY | constants.O_NOFOLLOW,\n );\n try {\n const opened = await input.stat();\n if (!opened.isFile() || opened.nlink !== 1)\n throw new Error(\n \"settings must be a single-link regular repository file\",\n );\n return { text: await input.readFile(\"utf8\"), mode: opened.mode & 0o777 };\n } finally {\n await input.close();\n }\n } catch (error) {\n throw new Error(\n `cannot safely merge ${cloudClaudeSettingsPath}: ${error instanceof Error ? error.message : String(error)}; ${cloudSessionStartFix}`,\n );\n }\n};\n\nconst main = async () => {\n const args = process.argv.slice(2);\n if (args.length === 1 && args.at(0) === \"--help\") {\n process.stdout.write(`${usage}\\n`);\n return;\n }\n if (args.length !== 0) throw new Error(usage);\n const root = await realpath(process.cwd());\n const { files, diagnostics } = readToolchainInputs(root);\n if (diagnostics.length > 0)\n throw new Error(\n diagnostics\n .map(\n ({ path, message }) =>\n `${path}: ${message}${path === cloudClaudeSettingsPath ? `; ${cloudSessionStartFix}` : \"\"}`,\n )\n .join(\"\\n\"),\n );\n const text = files[\"stll-toolchain.json\"];\n if (text === undefined)\n throw new Error(\"requires tracked stll-toolchain.json\");\n const { cloud, rustExceptions } = parseToolchainConfiguration(\n JSON.parse(text),\n );\n if (cloud === undefined)\n throw new Error(\"requires an explicit cloud declaration\");\n const nodeVersion = files[\".node-version\"];\n if (nodeVersion === undefined)\n throw new Error(\"requires tracked root .node-version\");\n const policy = parseToolchainPolicy(\n JSON.parse(\n await readFile(new URL(\"../toolchain.json\", import.meta.url), \"utf8\"),\n ),\n );\n const script = generateCloudSetup({\n policy,\n cloud,\n nodeVersion: nodeVersion.trim(),\n files,\n rustExceptions,\n });\n const destination = join(root, cloudSetupPath);\n await checkOutput(destination);\n const settingsDestination = join(root, cloudClaudeSettingsPath);\n const settings = await readClaudeSettings(settingsDestination);\n const mergedSettings = mergeCloudClaudeSettings(settings?.text);\n await writeOutput({ destination, text: script, mode: 0o755 });\n if (mergedSettings !== settings?.text)\n await writeOutput({\n destination: settingsDestination,\n text: mergedSettings,\n mode: settings?.mode ?? 0o644,\n });\n process.stdout.write(\n `Generated ${cloudSetupPath} and ${cloudClaudeSettingsPath}\\n`,\n );\n};\n\nmain().catch((error: unknown) => {\n process.stderr.write(\n `cloud-setup: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n});\n"],"mappings":"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"}
@@ -278,12 +278,17 @@ const importerDependencies = (value) => {
278
278
  }
279
279
  return result;
280
280
  };
281
+ const BUN_TEXT_LOCKFILE_VERSIONS = /* @__PURE__ */ new Set([
282
+ 0,
283
+ 1,
284
+ 2
285
+ ]);
281
286
  const parseChangedLock = ({ file, text }) => {
282
287
  const resolutions = [];
283
288
  const importers = {};
284
289
  if (file.endsWith("bun.lock")) {
285
290
  const parsed = parseChangedJson(text);
286
- if (!changedRecord(parsed) || ![0, 1].includes(Number(parsed["lockfileVersion"])) || !changedRecord(parsed["packages"]) || !changedRecord(parsed["workspaces"])) throw new Error("Unsupported Bun lockfile shape");
291
+ if (!changedRecord(parsed) || !BUN_TEXT_LOCKFILE_VERSIONS.has(Number(parsed["lockfileVersion"])) || !changedRecord(parsed["packages"]) || !changedRecord(parsed["workspaces"])) throw new Error("Unsupported Bun lockfile shape");
287
292
  for (const [directory, workspace] of Object.entries(parsed["workspaces"])) importers[directory || "."] = importerDependencies(workspace);
288
293
  for (const [location, value] of Object.entries(parsed["packages"])) {
289
294
  const dependency = dependencyName(location);
@@ -581,27 +586,93 @@ const snapshotText = ({ snapshot, file, visited = /* @__PURE__ */ new Set() }) =
581
586
  visited
582
587
  });
583
588
  };
584
- /** Read declared selector files too, without executing workflows or inspecting installed tools. */
589
+ /**
590
+ * What one `actions/checkout` step puts where, or `undefined` for any other step.
591
+ *
592
+ * A selector such as `base/package.json` after a checkout of this repository
593
+ * with `path: base` names the repository's own `package.json` at another ref,
594
+ * so it is read as that tracked file. A path built from an expression could
595
+ * replace any directory, so it is `unknown`.
596
+ */
597
+ const checkoutStep = (step) => {
598
+ if (!changedRecord(step)) return void 0;
599
+ const uses = step["uses"];
600
+ if (typeof uses !== "string" || !uses.startsWith("actions/checkout@")) return void 0;
601
+ const options = changedRecord(step["with"]) ? step["with"] : {};
602
+ const repository = options["repository"];
603
+ const sameRepository = repository === void 0 || repository === "${{ github.repository }}";
604
+ const checkoutPath = options["path"];
605
+ if (checkoutPath === void 0) return {
606
+ kind: "root",
607
+ sameRepository
608
+ };
609
+ if (typeof checkoutPath !== "string" || checkoutPath.includes("${{") || node_path.default.posix.isAbsolute(checkoutPath)) return { kind: "unknown" };
610
+ const normalized = node_path.default.posix.normalize(checkoutPath).replace(/\/+$/, "");
611
+ if (normalized === "" || normalized === ".") return {
612
+ kind: "root",
613
+ sameRepository
614
+ };
615
+ if (normalized.split("/").includes("..")) return { kind: "unknown" };
616
+ return {
617
+ kind: "path",
618
+ path: normalized,
619
+ sameRepository
620
+ };
621
+ };
622
+ /**
623
+ * The tracked file a declared selector names under the checkouts preceding
624
+ * its step. The most specific checkout directory decides; a selector inside
625
+ * another repository's checkout is not a tracked file, whatever this
626
+ * repository tracks at the same path.
627
+ */
628
+ const resolveCheckoutSelector = (declared, checkouts) => {
629
+ const file = node_path.default.posix.normalize(declared);
630
+ let owner;
631
+ for (const directory of checkouts.keys()) if ((directory === "" || file.startsWith(`${directory}/`)) && (owner === void 0 || directory.length > owner.length)) owner = directory;
632
+ if (owner === void 0) return file;
633
+ if (checkouts.get(owner) !== true) throw new Error(`Setup version-file names a file outside this repository: ${declared}`);
634
+ return owner === "" ? file : file.slice(owner.length + 1);
635
+ };
636
+ /** Visit each step with only the checkouts that precede it. */
637
+ const visitStepsInOrder = (steps, checkouts, visitStep) => {
638
+ const scope = new Map(checkouts);
639
+ for (const step of steps) {
640
+ visitStep(step, scope);
641
+ const checkout = checkoutStep(step);
642
+ if (checkout === void 0) continue;
643
+ if (checkout.kind !== "path") {
644
+ scope.clear();
645
+ scope.set("", checkout.kind === "root" && checkout.sameRepository);
646
+ continue;
647
+ }
648
+ for (const directory of scope.keys()) if (directory === checkout.path || directory.startsWith(`${checkout.path}/`)) scope.delete(directory);
649
+ scope.set(checkout.path, checkout.sameRepository);
650
+ }
651
+ };
585
652
  const selectorFiles = (snapshot) => {
586
653
  const files = /* @__PURE__ */ new Map();
587
- const visit = (value) => {
654
+ const visit = (value, checkouts = /* @__PURE__ */ new Map()) => {
588
655
  if (Array.isArray(value)) {
589
- for (const entry of value) visit(entry);
656
+ for (const entry of value) visit(entry, checkouts);
590
657
  return;
591
658
  }
592
659
  if (!changedRecord(value)) return;
593
660
  for (const [key, entry] of Object.entries(value)) {
661
+ if (key === "steps" && Array.isArray(entry)) {
662
+ visitStepsInOrder(entry, checkouts, visit);
663
+ continue;
664
+ }
594
665
  const input = key.toLowerCase();
595
666
  if (!/(?:^|-)version-file$/.test(input) && ![
596
667
  "toolchain-file",
597
668
  "rust-toolchain-file",
598
669
  "global-json-file"
599
670
  ].includes(input)) {
600
- visit(entry);
671
+ visit(entry, checkouts);
601
672
  continue;
602
673
  }
603
674
  if (typeof entry !== "string" || entry.trim() === "" || entry.includes("${{") || node_path.default.posix.isAbsolute(entry) || entry.split("/").includes("..")) throw new Error("Unclassifiable setup version-file declaration");
604
- const file = node_path.default.posix.normalize(entry);
675
+ const file = resolveCheckoutSelector(entry, checkouts);
605
676
  if (file === "." || file.split("/").some((part) => part === "vendor" || part === "node_modules")) throw new Error("Setup version-file leaves the tracked toolchain scope");
606
677
  let tool = "shared";
607
678
  if (input === "node-version-file") tool = "node";
@@ -957,7 +1028,7 @@ const setupRuntimeFileVersion = ({ snapshot, file, runtime }) => {
957
1028
  };
958
1029
  const setupRuntimeVersions = (snapshot) => {
959
1030
  const versions = [];
960
- const step = (value, file) => {
1031
+ const step = (value, file, checkouts) => {
961
1032
  if (!changedRecord(value) || typeof value["uses"] !== "string") return;
962
1033
  const action = value["uses"].split("@").at(0)?.toLowerCase();
963
1034
  let runtime = /(?:^|\/)setup-([^/]+)$/.exec(action ?? "")?.[1];
@@ -1008,7 +1079,7 @@ const setupRuntimeVersions = (snapshot) => {
1008
1079
  if (typeof input !== "string" || input.trim() === "" || input.includes("${{")) throw new Error("Unclassifiable setup version-file declaration");
1009
1080
  version = setupRuntimeFileVersion({
1010
1081
  snapshot,
1011
- file: node_path.default.posix.normalize(input),
1082
+ file: resolveCheckoutSelector(input, checkouts),
1012
1083
  runtime: inputRuntime
1013
1084
  });
1014
1085
  } else version = setupRuntimeVersion(input);
@@ -1026,7 +1097,7 @@ const setupRuntimeVersions = (snapshot) => {
1026
1097
  return;
1027
1098
  }
1028
1099
  if (!changedRecord(value)) return;
1029
- for (const [key, entry] of Object.entries(value)) if (key === "steps" && Array.isArray(entry)) for (const child of entry) step(child, file);
1100
+ for (const [key, entry] of Object.entries(value)) if (key === "steps" && Array.isArray(entry)) visitStepsInOrder(entry, /* @__PURE__ */ new Map(), (child, checkouts) => step(child, file, checkouts));
1030
1101
  else visit(entry, file);
1031
1102
  };
1032
1103
  for (const file of snapshot.entries.keys()) {