@stll/oxlint-config 1.3.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +341 -28
  2. package/dist/cloud-setup-cli.cjs +20 -40
  3. package/dist/cloud-setup-cli.cjs.map +1 -1
  4. package/dist/cloud-setup-cli.mjs +21 -41
  5. package/dist/cloud-setup-cli.mjs.map +1 -1
  6. package/dist/consumer-compat-cli.cjs +52 -251
  7. package/dist/consumer-compat-cli.cjs.map +1 -1
  8. package/dist/consumer-compat-cli.mjs +7 -206
  9. package/dist/consumer-compat-cli.mjs.map +1 -1
  10. package/dist/consumer-node-support.cjs +497 -0
  11. package/dist/consumer-node-support.cjs.map +1 -0
  12. package/dist/consumer-node-support.mjs +381 -0
  13. package/dist/consumer-node-support.mjs.map +1 -0
  14. package/dist/dependabot-cli.cjs +91 -0
  15. package/dist/dependabot-cli.cjs.map +1 -0
  16. package/dist/dependabot-cli.d.cts +1 -0
  17. package/dist/dependabot-cli.d.mts +1 -0
  18. package/dist/dependabot-cli.mjs +91 -0
  19. package/dist/dependabot-cli.mjs.map +1 -0
  20. package/dist/dependabot.cjs +7 -0
  21. package/dist/dependabot.d.cts +118 -0
  22. package/dist/dependabot.d.mts +118 -0
  23. package/dist/dependabot.mjs +3 -0
  24. package/dist/generated-file.cjs +61 -0
  25. package/dist/generated-file.cjs.map +1 -0
  26. package/dist/generated-file.mjs +44 -0
  27. package/dist/generated-file.mjs.map +1 -0
  28. package/dist/git-tracked-output.cjs +2 -2
  29. package/dist/git-tracked-output.mjs +1 -1
  30. package/dist/jsonc.cjs +66 -0
  31. package/dist/jsonc.cjs.map +1 -0
  32. package/dist/jsonc.mjs +61 -0
  33. package/dist/jsonc.mjs.map +1 -0
  34. package/dist/publish-artifact-syntax.cjs +1309 -0
  35. package/dist/publish-artifact-syntax.cjs.map +1 -0
  36. package/dist/publish-artifact-syntax.mjs +1265 -0
  37. package/dist/publish-artifact-syntax.mjs.map +1 -0
  38. package/dist/publish-build-target-vite-dts-helper2.cjs +1 -1
  39. package/dist/publish-build-target-vite-dts-helper2.mjs +1 -1
  40. package/dist/publish-contract-cli.cjs +55 -14
  41. package/dist/publish-contract-cli.cjs.map +1 -1
  42. package/dist/publish-contract-cli.mjs +50 -9
  43. package/dist/publish-contract-cli.mjs.map +1 -1
  44. package/dist/quarantine-cli.cjs +66 -0
  45. package/dist/quarantine-cli.cjs.map +1 -0
  46. package/dist/quarantine-cli.d.cts +1 -0
  47. package/dist/quarantine-cli.d.mts +1 -0
  48. package/dist/quarantine-cli.mjs +66 -0
  49. package/dist/quarantine-cli.mjs.map +1 -0
  50. package/dist/quarantine-policy.cjs +10 -0
  51. package/dist/quarantine-policy.d.cts +27 -0
  52. package/dist/quarantine-policy.d.mts +27 -0
  53. package/dist/quarantine-policy.mjs +1 -0
  54. package/dist/quarantine-policy2.cjs +399 -0
  55. package/dist/quarantine-policy2.cjs.map +1 -0
  56. package/dist/quarantine-policy2.mjs +352 -0
  57. package/dist/quarantine-policy2.mjs.map +1 -0
  58. package/dist/toolchain-changed.cjs +16 -67
  59. package/dist/toolchain-changed.cjs.map +1 -1
  60. package/dist/toolchain-changed.mjs +19 -70
  61. package/dist/toolchain-changed.mjs.map +1 -1
  62. package/dist/toolchain-check-cli.cjs +1 -0
  63. package/dist/toolchain-check-cli.cjs.map +1 -1
  64. package/dist/toolchain-check-cli.mjs +1 -0
  65. package/dist/toolchain-check-cli.mjs.map +1 -1
  66. package/dist/toolchain-dependabot.cjs +529 -0
  67. package/dist/toolchain-dependabot.cjs.map +1 -0
  68. package/dist/toolchain-dependabot.mjs +485 -0
  69. package/dist/toolchain-dependabot.mjs.map +1 -0
  70. package/dist/toolchain-guard.cjs +1143 -432
  71. package/dist/toolchain-guard.cjs.map +1 -1
  72. package/dist/toolchain-guard.mjs +1132 -421
  73. package/dist/toolchain-guard.mjs.map +1 -1
  74. package/dist/toolchain-inputs.cjs +216 -38
  75. package/dist/toolchain-inputs.cjs.map +1 -1
  76. package/dist/toolchain-inputs.mjs +213 -41
  77. package/dist/toolchain-inputs.mjs.map +1 -1
  78. package/dist/toolchain-schema.cjs +0 -493
  79. package/dist/toolchain-schema.cjs.map +1 -1
  80. package/dist/toolchain-schema.mjs +3 -379
  81. package/dist/toolchain-schema.mjs.map +1 -1
  82. package/dist/typecheck-parity.cjs +4 -3
  83. package/dist/typecheck-parity.cjs.map +1 -1
  84. package/dist/typecheck-parity.mjs +4 -3
  85. package/dist/typecheck-parity.mjs.map +1 -1
  86. package/dist/typecheck-probe-cli.cjs +3 -3
  87. package/dist/typecheck-probe-cli.cjs.map +1 -1
  88. package/dist/typecheck-probe-cli.mjs +3 -3
  89. package/dist/typecheck-probe-cli.mjs.map +1 -1
  90. package/package.json +25 -1
  91. package/toolchain.json +11 -4
  92. package/dist/publish-contract.cjs +0 -431
  93. package/dist/publish-contract.cjs.map +0 -1
  94. package/dist/publish-contract.mjs +0 -396
  95. package/dist/publish-contract.mjs.map +0 -1
@@ -1,9 +1,9 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime.cjs");
2
2
  let node_path = require("node:path");
3
3
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
4
+ let smol_toml = require("smol-toml");
4
5
  let node_crypto = require("node:crypto");
5
6
  let semver = require("semver");
6
- let smol_toml = require("smol-toml");
7
7
  let node_util = require("node:util");
8
8
  let yaml = require("yaml");
9
9
  let picomatch = require("picomatch");
@@ -378,6 +378,21 @@ const cloudSetupArtifacts = {
378
378
  binaries: { "rustup-init": "rustup-init" }
379
379
  }
380
380
  },
381
+ gitleaks: {
382
+ version: "8.30.1",
383
+ amd64: {
384
+ url: "https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz",
385
+ sha256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb",
386
+ archive: "tar.gz",
387
+ binaries: { gitleaks: "gitleaks" }
388
+ },
389
+ arm64: {
390
+ url: "https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_arm64.tar.gz",
391
+ sha256: "e4a487ee7ccd7d3a7f7ec08657610aa3606637dab924210b3aee62570fb4b080",
392
+ archive: "tar.gz",
393
+ binaries: { gitleaks: "gitleaks" }
394
+ }
395
+ },
381
396
  "cargo-nextest": {
382
397
  version: "0.9.148",
383
398
  amd64: {
@@ -445,7 +460,8 @@ const cloudSetupArtifactVersions = {
445
460
  "rustup-init": [cloudSetupArtifacts["rustup-init"]],
446
461
  "cargo-nextest": [cloudSetupArtifacts["cargo-nextest"]],
447
462
  "wasm-bindgen-cli": wasmBindgenArtifactReleases,
448
- uv: [cloudSetupArtifacts.uv]
463
+ uv: [cloudSetupArtifacts.uv],
464
+ gitleaks: [cloudSetupArtifacts.gitleaks]
449
465
  };
450
466
  /** A new version requires an explicit, verified catalog entry; never build from source. */
451
467
  const getCloudSetupArtifact = (tool, version) => {
@@ -500,11 +516,20 @@ const parseRust = (input) => {
500
516
  if (!object(input) || Object.keys(input).some((key) => ![
501
517
  "toolchain",
502
518
  "components",
503
- "targets"
504
- ].includes(key))) throw new Error("cloud.rust accepts only toolchain, components and targets");
519
+ "targets",
520
+ "additionalToolchains"
521
+ ].includes(key))) throw new Error("cloud.rust accepts only toolchain, components, targets and additionalToolchains");
505
522
  const toolchain = input["toolchain"];
506
523
  if (toolchain !== void 0 && !exactPin(toolchain)) throw new Error("cloud.rust.toolchain must be an exact stable release");
524
+ const additional = input["additionalToolchains"];
525
+ if (additional !== void 0 && !Array.isArray(additional)) throw new Error("cloud.rust.additionalToolchains requires exact stable releases");
526
+ const additionalToolchains = additional === void 0 ? [] : Array.from(additional, (pin) => {
527
+ if (!exactPin(pin)) throw new Error("cloud.rust.additionalToolchains requires exact stable releases");
528
+ return pin;
529
+ });
530
+ if (new Set(additionalToolchains).size !== additionalToolchains.length) throw new Error("cloud.rust.additionalToolchains contains duplicates");
507
531
  return {
532
+ additionalToolchains,
508
533
  ...toolchain === void 0 ? {} : { toolchain },
509
534
  components: parseCloudRustNames(input["components"], "components"),
510
535
  targets: parseCloudRustNames(input["targets"], "targets")
@@ -675,7 +700,12 @@ const postgresStart = String.raw`
675
700
  pg_pid="$(head -n 1 "$pg_data/postmaster.pid")"
676
701
  service_process "$pg_pid" "$pg_bin/postgres"
677
702
  [[ "$(env -u PGSERVICE -u PGSERVICEFILE -u PGOPTIONS PGHOSTADDR=127.0.0.1 PGPASSWORD="$pg_password" PGCONNECT_TIMEOUT=2 "$pg_bin/psql" -X -h 127.0.0.1 -p 55432 -U stll_cloud -d postgres -At -v ON_ERROR_STOP=1 -c "SELECT count(*) FROM pg_database WHERE datname = 'cloud_test'")" == 1 ]] || env -u PGSERVICE -u PGSERVICEFILE -u PGOPTIONS PGHOSTADDR=127.0.0.1 PGPASSWORD="$pg_password" PGCONNECT_TIMEOUT=2 "$pg_bin/createdb" -h 127.0.0.1 -p 55432 -U stll_cloud cloud_test || fail "PostgreSQL test database creation failed"
678
- DATABASE_URL="postgresql://stll_cloud:$pg_password@127.0.0.1:55432/cloud_test"
703
+ POSTGRES_HOST='127.0.0.1:55432'
704
+ POSTGRES_USER='stll_cloud'
705
+ POSTGRES_PASSWORD="$pg_password"
706
+ POSTGRES_DB_NAME='cloud_test'
707
+ POSTGRES_ADDITIONAL_CONNECTION_DATA=''
708
+ DATABASE_URL="postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@$POSTGRES_HOST/$POSTGRES_DB_NAME$POSTGRES_ADDITIONAL_CONNECTION_DATA"
679
709
  printf 'postgres: %s\n' "$pg_state"
680
710
  `;
681
711
  const valkeyStart = String.raw`
@@ -838,6 +868,11 @@ const resolveCloudToolchains = ({ cloud, files, rust, rustExceptions }) => {
838
868
  if (channel !== rust && !rustExceptions.some(({ pin }) => pin === channel)) throw new Error(`cloud Rust must use shared Rust ${rust} or a recorded rustExceptions pin`);
839
869
  if (cloud.rust?.toolchain !== void 0 && cloud.rust.toolchain !== channel) throw new Error("cloud.rust.toolchain conflicts with root Rust toolchain");
840
870
  }
871
+ const additionalToolchains = cloud.rust?.additionalToolchains ?? [];
872
+ for (const pin of additionalToolchains) {
873
+ if (pin === channel) throw new Error("cloud.rust.additionalToolchains must not repeat the primary toolchain");
874
+ if (pin !== rust && !rustExceptions.some(({ pin: authorized }) => authorized === pin)) throw new Error(`cloud.rust.additionalToolchains ${pin} requires an authorized rustExceptions pin`);
875
+ }
841
876
  const components = [.../* @__PURE__ */ new Set([...parseCloudRustNames(declared?.["components"], "components"), ...cloud.rust?.components ?? []])].sort();
842
877
  const targets = [.../* @__PURE__ */ new Set([...parseCloudRustNames(declared?.["targets"], "targets"), ...cloud.rust?.targets ?? []])].sort();
843
878
  const resolveTool = (tool, version) => {
@@ -868,6 +903,7 @@ const resolveCloudToolchains = ({ cloud, files, rust, rustExceptions }) => {
868
903
  return {
869
904
  rust: rustEnabled && typeof channel === "string" ? {
870
905
  channel,
906
+ additionalToolchains: [...additionalToolchains].sort(),
871
907
  components,
872
908
  targets,
873
909
  installer: cloudSetupArtifacts["rustup-init"]
@@ -904,7 +940,7 @@ rust_run() {
904
940
  *) fail 'Invalid Rust execution mode' ;;
905
941
  esac
906
942
  }
907
- rust_ready() {
943
+ primary_rust_ready() {
908
944
  local directory
909
945
  for directory in "$RUSTUP_HOME" "$CARGO_HOME"; do
910
946
  [[ -d "$directory" && ! -L "$directory" && "$(stat -c '%u' "$directory")" == "$OUTPUT_UID" ]] || return 1
@@ -918,13 +954,19 @@ rust_ready() {
918
954
  @VERIFY_TARGETS@
919
955
  return 0
920
956
  }
957
+ rust_ready() {
958
+ local additional_version
959
+ primary_rust_ready || return 1
960
+ @VERIFY_ADDITIONAL_TOOLCHAINS@
961
+ return 0
962
+ }
921
963
  verify_rust() { rust_ready || fail 'Pinned Rust, components or targets are unavailable; run install'; }
922
964
  install_rust() (
923
965
  if ! command -v cc >/dev/null || ! command -v ld >/dev/null || [[ ! -f /usr/include/stdlib.h ]]; then
924
966
  apt_refresh_for build-essential
925
967
  apt_install build-essential
926
968
  fi
927
- local artifact_url artifact_sha
969
+ local artifact_url artifact_sha additional_version
928
970
  # Subshell scope retains scratch for EXIT cleanup after a failed command.
929
971
  scratch="$(mktemp -d)"
930
972
  trap 'rm -rf -- "$scratch"' EXIT
@@ -943,9 +985,10 @@ install_rust() (
943
985
  rust_run network "$scratch/rustup-init" -y --no-modify-path --default-toolchain none --profile minimal
944
986
  fi
945
987
  rust_run local "$CARGO_HOME/bin/rustup" set auto-self-update disable
946
- if ! rust_ready; then
988
+ if ! primary_rust_ready; then
947
989
  rust_run network "$CARGO_HOME/bin/rustup" toolchain install @RUST@ --profile minimal --no-self-update @RUST_ARGS@
948
990
  fi
991
+ @INSTALL_ADDITIONAL_TOOLCHAINS@
949
992
  rust_run local "$CARGO_HOME/bin/rustup" default @RUST@
950
993
  verify_rust
951
994
  for tool in rustup cargo rustc rustdoc @RUST_PROXIES@; do
@@ -956,7 +999,7 @@ install_rust() (
956
999
  fi
957
1000
  done
958
1001
  )
959
- `.replaceAll("@RUSTUP@", rust.installer.version).replaceAll("@RUST@", rust.channel).replace("@RUSTUP_ARTIFACT@", artifactSelection(rust.installer)).replace("@RUST_ARGS@", args).replace("@RUST_PROXIES@", Object.entries(cloudRustComponentBinaries).flatMap(([component, binaries]) => rust.components.includes(component) ? Array.from(binaries) : []).join(" ")).replace("@VERIFY_COMPONENTS@", rust.components.map((name) => `rust_run local "$CARGO_HOME/bin/rustup" component list --toolchain ${quote(rust.channel)} --installed | awk -v name=${quote(name)} -v host="$host" '$1 == name || $1 == name "-" host { found=1 } END { exit !found }' || return 1`).join("\n ")).replace("@VERIFY_TARGETS@", rust.targets.map((name) => `rust_run local "$CARGO_HOME/bin/rustup" target list --toolchain ${quote(rust.channel)} --installed | awk -v name=${quote(name)} '$1 == name { found=1 } END { exit !found }' || return 1`).join("\n "));
1002
+ `.replace("@VERIFY_ADDITIONAL_TOOLCHAINS@", rust.additionalToolchains.map((pin) => `additional_version="$(rust_run local "$CARGO_HOME/bin/rustc" +${pin} --version)" || return 1\n [[ "$additional_version" == 'rustc ${pin} '* ]] || return 1`).join("\n ")).replace("@INSTALL_ADDITIONAL_TOOLCHAINS@", rust.additionalToolchains.map((pin) => `if ! additional_version="$(rust_run local "$CARGO_HOME/bin/rustc" +${pin} --version)" || [[ "$additional_version" != 'rustc ${pin} '* ]]; then\n rust_run network "$CARGO_HOME/bin/rustup" toolchain install ${pin} --profile minimal --no-self-update\n fi`).join("\n ")).replaceAll("@RUSTUP@", rust.installer.version).replaceAll("@RUST@", rust.channel).replace("@RUSTUP_ARTIFACT@", artifactSelection(rust.installer)).replace("@RUST_ARGS@", args).replace("@RUST_PROXIES@", Object.entries(cloudRustComponentBinaries).flatMap(([component, binaries]) => rust.components.includes(component) ? Array.from(binaries) : []).join(" ")).replace("@VERIFY_COMPONENTS@", rust.components.map((name) => `rust_run local "$CARGO_HOME/bin/rustup" component list --toolchain ${quote(rust.channel)} --installed | awk -v name=${quote(name)} -v host="$host" '$1 == name || $1 == name "-" host { found=1 } END { exit !found }' || return 1`).join("\n ")).replace("@VERIFY_TARGETS@", rust.targets.map((name) => `rust_run local "$CARGO_HOME/bin/rustup" target list --toolchain ${quote(rust.channel)} --installed | awk -v name=${quote(name)} '$1 == name { found=1 } END { exit !found }' || return 1`).join("\n "));
960
1003
  };
961
1004
  const packageToolInstall = ({ tool, release }) => {
962
1005
  const name = tool.replaceAll("-", "_");
@@ -979,7 +1022,7 @@ install_${name}() {
979
1022
  const artifactToolInstall = ({ tool, release }) => {
980
1023
  const directory = `/opt/stll-cloud/tools/${tool}/${release.version}`;
981
1024
  const command = tool === "wasm-bindgen-cli" ? "wasm-bindgen" : tool;
982
- const marker = `${tool === "cargo-nextest" ? "cargo-nextest" : command} ${release.version}`;
1025
+ const marker = `${tool === "gitleaks" ? "gitleaks version" : command} ${release.version}`;
983
1026
  return {
984
1027
  name: tool.replaceAll("-", "_"),
985
1028
  text: `verify_${tool.replaceAll("-", "_")}() {
@@ -1058,9 +1101,9 @@ const script = String.raw`#!/usr/bin/env bash
1058
1101
  # Supported platform: Ubuntu 24.04 (noble), amd64/arm64, root or passwordless sudo.
1059
1102
  set -euo pipefail
1060
1103
 
1061
- usage() { echo 'Usage: cloud-setup.sh install|start' >&2; exit 2; }
1104
+ usage() { echo 'Usage: cloud-setup.sh install|start|session' >&2; exit 2; }
1062
1105
  [[ "$#" == 1 ]] || usage
1063
- case "$1" in install|start) MODE="$1" ;; *) usage ;; esac
1106
+ case "$1" in install|start|session) MODE="$1" ;; *) usage ;; esac
1064
1107
  fail() { echo "cloud-setup: $*" >&2; exit 1; }
1065
1108
  trap 'echo "cloud-setup: command failed at line $LINENO" >&2' ERR
1066
1109
  # Each phase logs its start and duration so a stalled phase is visible in the task log.
@@ -1116,19 +1159,35 @@ esac
1116
1159
 
1117
1160
  @NETWORK@
1118
1161
 
1162
+ node_ready() {
1163
+ local node_version npm_version npx_version
1164
+ [[ -x "$NODE_DIR/bin/node" && -x "$NODE_DIR/bin/npm" && -x "$NODE_DIR/bin/npx" ]] || return 1
1165
+ node_version="$("$NODE_DIR/bin/node" --version)" || return 1
1166
+ [[ "$node_version" == "v$NODE_VERSION" ]] || return 1
1167
+ npm_version="$("$NODE_DIR/bin/npm" --version)" || return 1
1168
+ [[ "$npm_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || return 1
1169
+ npx_version="$("$NODE_DIR/bin/npx" --version)" || return 1
1170
+ [[ "$npx_version" == "$npm_version" ]] || return 1
1171
+ }
1119
1172
  runtime_ready() {
1120
- [[ -x "$NODE_DIR/bin/node" && "$($NODE_DIR/bin/node --version)" == "v$NODE_VERSION" ]] || fail 'Pinned Node is unavailable; run install'
1173
+ node_ready || fail 'Pinned Node, npm or npx is unavailable; run install'
1121
1174
  [[ -x "$BUN_DIR/bun" && "$($BUN_DIR/bun --version)" == "$BUN_VERSION" ]] || fail 'Pinned Bun is unavailable; run install'
1122
1175
  }
1123
- install_runtimes() {
1176
+ install_runtimes() (
1177
+ if [[ ! -s /etc/ssl/certs/ca-certificates.crt ]]; then
1178
+ command -v update-ca-certificates >/dev/null || fail 'System CA certificate bundle is missing; restore ca-certificates in the base image offline before install'
1179
+ update-ca-certificates || fail 'System CA certificate bundle could not be repaired offline; restore ca-certificates in the base image before install'
1180
+ fi
1181
+ [[ -s /etc/ssl/certs/ca-certificates.crt ]] || fail 'System CA certificate bundle is unavailable after offline repair; restore ca-certificates in the base image before install'
1124
1182
  if ! command -v curl >/dev/null || ! command -v unzip >/dev/null || ! command -v xz >/dev/null || ! command -v openssl >/dev/null || ! command -v gpg >/dev/null || ! ldconfig -p | awk '$1 == "libatomic.so.1" { found=1 } END { exit !found }'; then
1125
1183
  apt_refresh_for ca-certificates curl unzip xz-utils openssl gnupg util-linux libatomic1
1126
1184
  DEBIAN_FRONTEND=noninteractive apt_install ca-certificates curl unzip xz-utils openssl gnupg util-linux libatomic1
1127
1185
  fi
1128
- local scratch node_archive bun_archive bun_folder
1186
+ local node_archive bun_archive bun_folder
1187
+ # Subshell scope retains scratch for EXIT cleanup after a failed command.
1129
1188
  scratch="$(mktemp -d)"
1130
- trap 'rm -rf -- "$scratch"' RETURN
1131
- if [[ ! -x "$NODE_DIR/bin/node" ]] || [[ "$($NODE_DIR/bin/node --version)" != "v$NODE_VERSION" ]]; then
1189
+ trap 'rm -rf -- "$scratch"' EXIT
1190
+ if ! node_ready; then
1132
1191
  node_archive="node-v$NODE_VERSION-linux-$NODE_ARCH.tar.xz"
1133
1192
  download_file "https://nodejs.org/dist/v$NODE_VERSION/$node_archive" "$scratch/$node_archive" 120
1134
1193
  download_file "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt" "$scratch/node-sums" 45
@@ -1151,9 +1210,7 @@ install_runtimes() {
1151
1210
  ln -sfnT -- "$NODE_DIR/bin/npm" /usr/local/bin/npm
1152
1211
  ln -sfnT -- "$NODE_DIR/bin/npx" /usr/local/bin/npx
1153
1212
  ln -sfnT -- "$BUN_DIR/bun" /usr/local/bin/bun
1154
- rm -rf -- "$scratch"
1155
- trap - RETURN
1156
- }
1213
+ )
1157
1214
 
1158
1215
  dependency_install() {
1159
1216
  local directory download_hosts
@@ -1199,6 +1256,8 @@ process.stdout.write([...hosts].sort().join(","));
1199
1256
  @INPUT_VALIDATION@
1200
1257
 
1201
1258
  @ENV_FUNCTIONS@
1259
+ @ENVIRONMENT_VALUES@
1260
+ @SESSION_ENVIRONMENT@
1202
1261
 
1203
1262
  @PREPARE_FUNCTION@
1204
1263
 
@@ -1211,14 +1270,38 @@ if [[ "$MODE" == install ]]; then
1211
1270
  @PREPARE_STEP@
1212
1271
  exit 0
1213
1272
  fi
1214
- step runtime-check runtime_ready
1215
- step tool-check verify_tools
1216
- step shell install_shell_environment
1217
- step shell-check verify_shell_environment
1218
- @ENV_VALIDATE@
1219
- step state prepare_state
1220
- step service-start start_services
1221
- @ENV_WRITE@
1273
+ @ENV_INITIALIZE@
1274
+ start_environment() {
1275
+ step runtime-check runtime_ready
1276
+ step tool-check verify_tools
1277
+ step shell install_shell_environment
1278
+ step shell-check verify_shell_environment
1279
+ @ENV_VALIDATE@
1280
+ step state prepare_state
1281
+ step service-start start_services
1282
+ @ENV_WRITE@
1283
+ }
1284
+ if [[ "$MODE" == session ]]; then
1285
+ start_environment >&2
1286
+ else
1287
+ start_environment
1288
+ fi
1289
+ @SESSION_ENVIRONMENT_CALL@
1290
+ `;
1291
+ const environmentValuesFunction = String.raw`
1292
+ environment_values() {
1293
+ local emit="$1"
1294
+ "$emit" NODE_ENV test
1295
+ if [[ -n "$DATABASE_URL" ]]; then
1296
+ "$emit" DATABASE_URL "$DATABASE_URL"
1297
+ "$emit" POSTGRES_HOST "$POSTGRES_HOST"
1298
+ "$emit" POSTGRES_USER "$POSTGRES_USER"
1299
+ "$emit" POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
1300
+ "$emit" POSTGRES_DB_NAME "$POSTGRES_DB_NAME"
1301
+ "$emit" POSTGRES_ADDITIONAL_CONNECTION_DATA "$POSTGRES_ADDITIONAL_CONNECTION_DATA"
1302
+ fi
1303
+ if [[ -n "$REDIS_URL" ]]; then "$emit" REDIS_URL "$REDIS_URL"; fi
1304
+ }
1222
1305
  `;
1223
1306
  const environmentFunctions = String.raw`
1224
1307
  validate_environment() {
@@ -1234,20 +1317,26 @@ validate_environment() {
1234
1317
  [[ "$first_line" == "$ENV_MARKER" ]] || fail 'Refusing to overwrite an unowned environment file'
1235
1318
  fi
1236
1319
  }
1320
+ environment_file_value() { printf '%s=%s\n' "$1" "$2"; }
1237
1321
  write_environment() {
1238
1322
  validate_environment
1239
1323
  local env_path="$REPO_ROOT/$ENV_FILE" temporary
1240
1324
  temporary="$(mktemp "$(dirname -- "$env_path")/.stll-cloud-env.XXXXXX")"
1241
1325
  chmod 600 "$temporary"
1242
1326
  {
1243
- printf '%s\n' "$ENV_MARKER" 'NODE_ENV=test'
1244
- if [[ -n "$DATABASE_URL" ]]; then printf 'DATABASE_URL=%s\n' "$DATABASE_URL"; fi
1245
- if [[ -n "$REDIS_URL" ]]; then printf 'REDIS_URL=%s\n' "$REDIS_URL"; fi
1327
+ printf '%s\n' "$ENV_MARKER"
1328
+ environment_values environment_file_value
1246
1329
  } > "$temporary"
1247
1330
  chown "$OUTPUT_UID:$OUTPUT_GID" "$temporary"
1248
1331
  mv -f -- "$temporary" "$env_path"
1249
1332
  }
1250
1333
  `;
1334
+ const sessionEnvironmentFunction = String.raw`
1335
+ environment_shell_value() { printf 'export %s=%q\n' "$1" "$2"; }
1336
+ emit_session_environment() {
1337
+ environment_values environment_shell_value
1338
+ }
1339
+ `;
1251
1340
  const shellQuote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
1252
1341
  const renderPrepare = (prepare, files) => {
1253
1342
  if (prepare === void 0) return "";
@@ -1301,7 +1390,11 @@ const generateCloudSetup = ({ policy, cloud, nodeVersion, files = {}, rustExcept
1301
1390
  ["@NODE@", exactNode],
1302
1391
  ["@ENV_ASSIGNMENTS@", selected.envFile === void 0 ? "" : `ENV_FILE=${shellQuote(selected.envFile)}\nENV_MARKER=${shellQuote(cloudEnvironmentMarker)}`],
1303
1392
  ["@ENV_FUNCTIONS@", selected.envFile === void 0 ? "" : environmentFunctions],
1304
- ["@ENV_VALIDATE@", selected.envFile === void 0 ? "" : "DATABASE_URL=''\nREDIS_URL=''\nvalidate_environment"],
1393
+ ["@ENVIRONMENT_VALUES@", selected.services.length === 0 ? "" : environmentValuesFunction],
1394
+ ["@ENV_INITIALIZE@", selected.services.length === 0 ? "" : "DATABASE_URL=''\nPOSTGRES_HOST=''\nPOSTGRES_USER=''\nPOSTGRES_PASSWORD=''\nPOSTGRES_DB_NAME=''\nPOSTGRES_ADDITIONAL_CONNECTION_DATA=''\nREDIS_URL=''"],
1395
+ ["@ENV_VALIDATE@", selected.envFile === void 0 ? "" : "validate_environment"],
1396
+ ["@SESSION_ENVIRONMENT@", selected.services.length === 0 ? "" : sessionEnvironmentFunction],
1397
+ ["@SESSION_ENVIRONMENT_CALL@", selected.services.length === 0 ? "" : "if [[ \"$MODE\" == session ]]; then emit_session_environment; fi"],
1305
1398
  ["@ENV_WRITE@", selected.envFile === void 0 ? "" : "write_environment"],
1306
1399
  ["@PREPARE_FUNCTION@", renderPrepare(selected.prepare, files)],
1307
1400
  ["@PREPARE_STEP@", selected.prepare === void 0 ? "" : " step prepare prepare_sources"],
@@ -1317,16 +1410,16 @@ const generateCloudSetup = ({ policy, cloud, nodeVersion, files = {}, rustExcept
1317
1410
  valkey: policy.valkey
1318
1411
  })]
1319
1412
  ]);
1320
- return script.replace(/@[A-Z0-9_]+@/g, (token) => {
1413
+ return `${script.replace(/@[A-Z0-9_]+@/g, (token) => {
1321
1414
  const value = replacements.get(token);
1322
1415
  if (value === void 0) throw new Error(`Missing cloud setup field: ${token}`);
1323
1416
  return value;
1324
- });
1417
+ }).replace(/[ \t]+$/gm, "").trimEnd()}\n`;
1325
1418
  };
1326
1419
  //#endregion
1327
1420
  //#region src/cloud-setup-claude.ts
1328
1421
  const cloudClaudeSettingsPath = ".claude/settings.json";
1329
- const sessionStartHook = (script) => ({
1422
+ const releasedSessionStartHook = (script) => ({
1330
1423
  matcher: "",
1331
1424
  hooks: [{
1332
1425
  type: "command",
@@ -1343,8 +1436,75 @@ const sessionStartHook = (script) => ({
1343
1436
  fi`
1344
1437
  }]
1345
1438
  });
1439
+ const sessionStartHook = (script) => ({
1440
+ matcher: "",
1441
+ hooks: [{
1442
+ type: "command",
1443
+ command: `if [ "\${CLAUDE_CODE_REMOTE:-}" = "true" ]; then
1444
+ cloud_setup_incomplete() {
1445
+ printf '%s\\n' 'Cloud setup could not establish a verified session environment. From the repository root, run bash .agents/cloud-setup.sh install and then bash .agents/cloud-setup.sh start. Do not assume pinned tools or services are ready until start succeeds.'
1446
+ printf '%s\\n' "cloud-setup: $1" >&2
1447
+ exit 0
1448
+ }
1449
+ if [ -n "\${CLAUDE_ENV_FILE:-}" ]; then
1450
+ cloud_session_exports="$(${script} session)" || cloud_setup_incomplete 'startup failed; run install'
1451
+ else
1452
+ ${script} start >&2 || cloud_setup_incomplete 'startup failed; run install'
1453
+ exit 0
1454
+ fi
1455
+ if [ -n "\${CLAUDE_ENV_FILE:-}" ]; then
1456
+ if [ ! -s ${cloudShellProfilePath} ]; then
1457
+ cloud_setup_incomplete 'cloud shell profile is unavailable; run install'
1458
+ fi
1459
+ cloud_shell_exports="$(cat ${cloudShellProfilePath})" || cloud_setup_incomplete 'cloud shell profile could not be read; run install'
1460
+ [ -n "$cloud_shell_exports" ] || cloud_setup_incomplete 'cloud shell profile is unavailable; run install'
1461
+ if [ -e "$CLAUDE_ENV_FILE" ] || [ -L "$CLAUDE_ENV_FILE" ]; then
1462
+ [ -f "$CLAUDE_ENV_FILE" ] && [ ! -L "$CLAUDE_ENV_FILE" ] || cloud_setup_incomplete 'session environment must be a regular file; check its path and rerun start'
1463
+ fi
1464
+ cloud_env_temporary="$(umask 077; mktemp "\${CLAUDE_ENV_FILE}.XXXXXX")" || cloud_setup_incomplete 'session environment could not be prepared; check its write access and rerun start'
1465
+ if [ -e "$CLAUDE_ENV_FILE" ] || [ -L "$CLAUDE_ENV_FILE" ]; then
1466
+ cat "$CLAUDE_ENV_FILE" > "$cloud_env_temporary" || { rm -f -- "$cloud_env_temporary"; cloud_setup_incomplete 'session environment could not be read; check its access and rerun start'; }
1467
+ fi
1468
+ if [ -n "$cloud_session_exports" ]; then
1469
+ cloud_session_exports="$cloud_session_exports
1470
+ $cloud_shell_exports"
1471
+ else
1472
+ cloud_session_exports="$cloud_shell_exports"
1473
+ fi
1474
+ printf '\\n%s\\n' "$cloud_session_exports" >> "$cloud_env_temporary" || { rm -f -- "$cloud_env_temporary"; cloud_setup_incomplete 'session environment could not be prepared; check its write access and rerun start'; }
1475
+ mv -f -- "$cloud_env_temporary" "$CLAUDE_ENV_FILE" || { rm -f -- "$cloud_env_temporary"; cloud_setup_incomplete 'session environment could not be persisted; check its write access and rerun start'; }
1476
+ fi
1477
+ fi`
1478
+ }]
1479
+ });
1480
+ const currentMainSessionStartHook = (script) => ({
1481
+ matcher: "",
1482
+ hooks: [{
1483
+ type: "command",
1484
+ command: `if [ "\${CLAUDE_CODE_REMOTE:-}" = "true" ]; then
1485
+ cloud_setup_incomplete() {
1486
+ printf '%s\\n' 'Cloud setup could not establish a verified session environment. From the repository root, run bash .agents/cloud-setup.sh install and then bash .agents/cloud-setup.sh start. Do not assume pinned tools or services are ready until start succeeds.'
1487
+ printf '%s\\n' "cloud-setup: $1" >&2
1488
+ exit 0
1489
+ }
1490
+ ${script} start >&2 || cloud_setup_incomplete 'startup failed; run install'
1491
+ if [ -n "\${CLAUDE_ENV_FILE:-}" ]; then
1492
+ if [ ! -s ${cloudShellProfilePath} ]; then
1493
+ cloud_setup_incomplete 'cloud shell profile is unavailable; run install'
1494
+ fi
1495
+ cloud_shell_exports="$(cat ${cloudShellProfilePath})" || cloud_setup_incomplete 'cloud shell profile could not be read; run install'
1496
+ [ -n "$cloud_shell_exports" ] || cloud_setup_incomplete 'cloud shell profile is unavailable; run install'
1497
+ printf '\\n%s\\n' "$cloud_shell_exports" >> "$CLAUDE_ENV_FILE" || cloud_setup_incomplete 'session environment could not be persisted; check its write access and rerun start'
1498
+ fi
1499
+ fi`
1500
+ }]
1501
+ });
1346
1502
  const cloudSessionStartHook = sessionStartHook(`bash "$CLAUDE_PROJECT_DIR/${cloudSetupPath}"`);
1347
- const previousCloudSessionStartHooks = [sessionStartHook(`bash ${cloudSetupPath}`)];
1503
+ const previousCloudSessionStartHooks = [
1504
+ releasedSessionStartHook(`bash ${cloudSetupPath}`),
1505
+ releasedSessionStartHook(`bash "$CLAUDE_PROJECT_DIR/${cloudSetupPath}"`),
1506
+ currentMainSessionStartHook(`bash "$CLAUDE_PROJECT_DIR/${cloudSetupPath}"`)
1507
+ ];
1348
1508
  const cloudAttribution = {
1349
1509
  commit: "",
1350
1510
  pr: ""
@@ -1578,6 +1738,18 @@ const javascriptDependencyLockfiles = [
1578
1738
  "yarn.lock",
1579
1739
  "pnpm-lock.yaml"
1580
1740
  ];
1741
+ const dependabotManifestEcosystems = {
1742
+ Gemfile: "bundler",
1743
+ "Gemfile.lock": "bundler",
1744
+ "composer.json": "composer",
1745
+ "composer.lock": "composer"
1746
+ };
1747
+ /** Share ecosystem inventory with snapshot selection; no dependency graph reads are needed. */
1748
+ const dependabotManifestEcosystem = (file) => {
1749
+ if (excludedInputPath(file)) return void 0;
1750
+ const basename = file.split("/").at(-1);
1751
+ for (const [name, ecosystem] of Object.entries(dependabotManifestEcosystems)) if (basename === name) return ecosystem;
1752
+ };
1581
1753
  /** Match project, environment, local, and fragment filenames recognized by mise. */
1582
1754
  const isMiseConfigPath = (file) => !excludedInputPath(file) && (/(?:^|\/)\.?mise(?:\.[^./][^/]*)?\.toml$/.test(file) || /(?:^|\/)(?:\.?mise|\.config\/mise)\/config(?:\.[^./][^/]*)?\.toml$/.test(file) || /(?:^|\/)(?:\.?mise|\.config\/mise)\/conf\.d\/[^./][^/]*\.toml$/.test(file));
1583
1755
  /** GitHub action metadata may live at the repository root or in any directory. */
@@ -1613,10 +1785,10 @@ const isDockerDefinitionPath = (file) => {
1613
1785
  const isShellScript = (file, text = "") => !excludedInputPath(file) && (/\.(?:sh|bash|zsh)$/.test(file) || /^#![ \t]*(?:\/(?:[^ \t\r\n]+\/)*(?:bash|dash|ksh|zsh|sh)|\/usr\/bin\/env[ \t]+(?:-S[ \t]+)?(?:bash|dash|ksh|zsh|sh))(?=[ \t\r\n]|$)/.test(text));
1614
1786
  /** Lockfiles establish ecosystem presence without reading their dependency graphs. */
1615
1787
  const toolchainInputKind = (file, text = "") => {
1616
- if (file === ".agents/cloud-setup.sh" || file === ".claude/settings.json" || file === "Cargo.lock") return "config";
1788
+ if (file === "bunfig.toml" || file === ".agents/cloud-setup.sh" || file === ".claude/settings.json" || file === "Cargo.lock") return "config";
1617
1789
  if (githubAutomationFileKind(file) !== void 0) return "config";
1618
1790
  if (excludedInputPath(file)) return void 0;
1619
- if (pythonDependencyManifestKind(file) === "pipfile-lock" || javascriptDependencyLockfiles.some((name) => file.split("/").at(-1) === name) || /(?:^|\/)uv\.lock$/.test(file)) return "presence";
1791
+ if (dependabotManifestEcosystem(file) !== void 0 || pythonDependencyManifestKind(file) === "pipfile-lock" || javascriptDependencyLockfiles.some((name) => file.split("/").at(-1) === name) || /(?:^|\/)uv\.lock$/.test(file)) return "presence";
1620
1792
  if (githubAutomationFileKind(file) !== void 0 || isShellScript(file, text) || /(?:^|\/)ci-service-images\.json$/.test(file) || isMiseConfigPath(file) || isPythonDependencyManifest(file) || isDockerDefinitionPath(file) || isComposeDefinitionPath(file) || isKubernetesDefinitionPath(file) || /(?:^|\/)(?:package\.json|consumer-compat\.json|pnpm-workspace\.yaml|stll-toolchain\.json|\.bun-version|\.node-version|\.nvmrc|\.python-version|rust-toolchain(?:\.toml)?|\.tool-versions|\.?mise\.toml|uv\.toml|\.uv\.toml|\.github\/dependabot\.ya?ml|Cargo\.toml)$/.test(file)) return "config";
1621
1793
  };
1622
1794
  //#endregion
@@ -1650,6 +1822,12 @@ Object.defineProperty(exports, "containerDocumentImages", {
1650
1822
  return containerDocumentImages;
1651
1823
  }
1652
1824
  });
1825
+ Object.defineProperty(exports, "dependabotManifestEcosystem", {
1826
+ enumerable: true,
1827
+ get: function() {
1828
+ return dependabotManifestEcosystem;
1829
+ }
1830
+ });
1653
1831
  Object.defineProperty(exports, "generateCloudSetup", {
1654
1832
  enumerable: true,
1655
1833
  get: function() {