@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 +23 -11
- package/dist/cloud-setup-cli.cjs +1 -1
- package/dist/cloud-setup-cli.cjs.map +1 -1
- package/dist/cloud-setup-cli.mjs +2 -2
- package/dist/cloud-setup-cli.mjs.map +1 -1
- package/dist/toolchain-changed.cjs +80 -9
- package/dist/toolchain-changed.cjs.map +1 -1
- package/dist/toolchain-changed.mjs +80 -9
- package/dist/toolchain-changed.mjs.map +1 -1
- package/dist/toolchain-guard.cjs +10 -2
- package/dist/toolchain-guard.cjs.map +1 -1
- package/dist/toolchain-guard.mjs +11 -3
- package/dist/toolchain-guard.mjs.map +1 -1
- package/dist/toolchain-inputs.cjs +182 -57
- package/dist/toolchain-inputs.cjs.map +1 -1
- package/dist/toolchain-inputs.mjs +169 -56
- package/dist/toolchain-inputs.mjs.map +1 -1
- package/dist/toolchain-schema.mjs +1 -1
- package/package.json +1 -1
|
@@ -174,7 +174,7 @@ const postgresInstall = String.raw`
|
|
|
174
174
|
rm -- "$key"
|
|
175
175
|
printf '%s\n' '@PGDG_SOURCE@' > /etc/apt/sources.list.d/stll-pgdg.list
|
|
176
176
|
fi
|
|
177
|
-
|
|
177
|
+
apt_refresh_for postgresql-@POSTGRES@ postgresql-client-@POSTGRES@
|
|
178
178
|
apt_install postgresql-@POSTGRES@ postgresql-client-@POSTGRES@
|
|
179
179
|
fi
|
|
180
180
|
postgres_ready || fail 'PostgreSQL toolchain is incomplete or differs from the policy major'
|
|
@@ -197,7 +197,7 @@ const valkeyInstall = String.raw`
|
|
|
197
197
|
[[ "$(dpkg-deb -f "$scratch/$package.deb" Version)" == '@VALKEY@-1.noble' ]] || fail 'Valkey artifact version mismatch'
|
|
198
198
|
[[ "$(dpkg-deb -f "$scratch/$package.deb" Architecture)" == "$ARCH" ]] || fail 'Valkey artifact architecture mismatch'
|
|
199
199
|
done
|
|
200
|
-
|
|
200
|
+
apt_refresh_for "$scratch/valkey-server.deb" "$scratch/valkey-tools.deb"
|
|
201
201
|
apt_install "$scratch/valkey-server.deb" "$scratch/valkey-tools.deb"
|
|
202
202
|
rm -rf -- "$scratch"
|
|
203
203
|
fi
|
|
@@ -298,6 +298,15 @@ apt_network() {
|
|
|
298
298
|
[[ -n "$hosts" ]] || hosts='configured APT hosts'
|
|
299
299
|
network_run "$hosts" 180 apt-get -o Acquire::http::Timeout=20 -o Acquire::https::Timeout=20 -o Acquire::Retries=3 -o APT::Update::Error-Mode=any "$@"
|
|
300
300
|
}
|
|
301
|
+
apt_refresh_for() {
|
|
302
|
+
# Skip the refresh only when the install downloads nothing: then no package
|
|
303
|
+
# source is contacted and stale cached indexes cannot point at missing files.
|
|
304
|
+
local uris
|
|
305
|
+
if uris="$(DEBIAN_FRONTEND=noninteractive apt-get --print-uris -qq -y --no-install-recommends install "$@" 2>/dev/null)" && [[ -z "$uris" ]]; then
|
|
306
|
+
return 0
|
|
307
|
+
fi
|
|
308
|
+
apt_network update
|
|
309
|
+
}
|
|
301
310
|
`;
|
|
302
311
|
//#endregion
|
|
303
312
|
//#region src/cloud-setup-artifacts.ts
|
|
@@ -417,12 +426,29 @@ const getCloudSetupArtifact = (tool, version) => {
|
|
|
417
426
|
if (artifact === void 0) throw new Error(`Unsupported ${tool} version ${version}; supported versions: ${releases.map((release) => release.version).join(", ")}`);
|
|
418
427
|
return artifact;
|
|
419
428
|
};
|
|
429
|
+
/** Ubuntu 24.04 packages; apt resolves them from the image's configured sources. */
|
|
430
|
+
const cloudSetupPackages = { time: {
|
|
431
|
+
version: "1.9",
|
|
432
|
+
package: "time",
|
|
433
|
+
binary: "/usr/bin/time",
|
|
434
|
+
identity: "time (GNU Time) "
|
|
435
|
+
} };
|
|
436
|
+
/** Ubuntu 24.04 ships one release per package; other versions are unsupported. */
|
|
437
|
+
const getCloudSetupPackage = (tool, version) => {
|
|
438
|
+
const release = cloudSetupPackages[tool];
|
|
439
|
+
if (release.version !== version) throw new Error(`Unsupported ${tool} version ${version}; supported versions: ${release.version}`);
|
|
440
|
+
return release;
|
|
441
|
+
};
|
|
420
442
|
//#endregion
|
|
421
443
|
//#region src/cloud-setup-schema.ts
|
|
422
444
|
const cloudServices = ["postgres", "valkey"];
|
|
423
|
-
const
|
|
445
|
+
const cloudArtifactTools = Object.keys(cloudSetupArtifacts).filter((tool) => tool !== "rustup-init" && Object.hasOwn(cloudSetupArtifacts, tool));
|
|
446
|
+
const cloudPackageTools = Object.keys(cloudSetupPackages).filter((tool) => Object.hasOwn(cloudSetupPackages, tool));
|
|
447
|
+
const cloudExtraTools = [...cloudArtifactTools, ...cloudPackageTools];
|
|
448
|
+
const isCloudPackageTool = (tool) => cloudPackageTools.some((candidate) => candidate === tool);
|
|
424
449
|
const object = (input) => typeof input === "object" && input !== null && !Array.isArray(input);
|
|
425
450
|
const exactPin = (input) => typeof input === "string" && /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/.test(input);
|
|
451
|
+
const exactToolPin = (tool, input) => isCloudPackageTool(tool) ? typeof input === "string" && /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:\.(?:0|[1-9]\d*))?$/.test(input) : exactPin(input);
|
|
426
452
|
const cloudRustComponentBinaries = {
|
|
427
453
|
clippy: ["cargo-clippy", "clippy-driver"],
|
|
428
454
|
rustfmt: ["rustfmt", "cargo-fmt"],
|
|
@@ -466,12 +492,14 @@ const parseTools = (input) => {
|
|
|
466
492
|
if (Object.hasOwn(input, tool)) throw new Error(`cloud.tools.${tool} must be an exact stable release`);
|
|
467
493
|
continue;
|
|
468
494
|
}
|
|
469
|
-
if (!
|
|
495
|
+
if (!exactToolPin(tool, pin)) throw new Error(`cloud.tools.${tool} must be an exact stable release`);
|
|
470
496
|
result[tool] = pin;
|
|
471
497
|
}
|
|
472
498
|
return result;
|
|
473
499
|
};
|
|
474
500
|
const cloudInstallCommand = "bun install --frozen-lockfile";
|
|
501
|
+
const cloudInstallCommands = [cloudInstallCommand, `${cloudInstallCommand} --ignore-scripts`];
|
|
502
|
+
const cloudInstall = (value) => cloudInstallCommands.some((command) => value === command);
|
|
475
503
|
const cloudService = (value) => cloudServices.some((service) => value === service);
|
|
476
504
|
const parseEnvFile = (input) => {
|
|
477
505
|
if (!("envFile" in input) || typeof input.envFile !== "string") throw new Error("cloud.envFile must be a canonical repository-relative path");
|
|
@@ -492,7 +520,8 @@ const parseCloudSetup = (input) => {
|
|
|
492
520
|
};
|
|
493
521
|
const selected = "services" in input ? input.services : [];
|
|
494
522
|
if (!Array.isArray(selected)) throw new Error("cloud.services must be an array when provided");
|
|
495
|
-
if (!("install" in input) || input.install
|
|
523
|
+
if (!("install" in input) || !cloudInstall(input.install)) throw new Error(`cloud.install must be exactly one of: ${cloudInstallCommands.join(", ")}`);
|
|
524
|
+
const install = input.install;
|
|
496
525
|
const seen = /* @__PURE__ */ new Set();
|
|
497
526
|
const services = Array.from(selected, (service) => {
|
|
498
527
|
if (!cloudService(service)) throw new Error("cloud.services contains an unsupported service");
|
|
@@ -503,7 +532,7 @@ const parseCloudSetup = (input) => {
|
|
|
503
532
|
if (services.length === 0 && "envFile" in input) throw new Error("cloud.envFile is not allowed without services");
|
|
504
533
|
return {
|
|
505
534
|
services,
|
|
506
|
-
install
|
|
535
|
+
install,
|
|
507
536
|
...extensions,
|
|
508
537
|
...services.length === 0 ? {} : { envFile: parseEnvFile(input) }
|
|
509
538
|
};
|
|
@@ -765,9 +794,12 @@ const resolveCloudToolchains = ({ cloud, files, rust, rustExceptions }) => {
|
|
|
765
794
|
}
|
|
766
795
|
const components = [.../* @__PURE__ */ new Set([...parseCloudRustNames(declared?.["components"], "components"), ...cloud.rust?.components ?? []])].sort();
|
|
767
796
|
const targets = [.../* @__PURE__ */ new Set([...parseCloudRustNames(declared?.["targets"], "targets"), ...cloud.rust?.targets ?? []])].sort();
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
797
|
+
const resolveTool = (tool, version) => {
|
|
798
|
+
if (isCloudPackageTool(tool)) return {
|
|
799
|
+
type: "package",
|
|
800
|
+
tool,
|
|
801
|
+
release: getCloudSetupPackage(tool, version)
|
|
802
|
+
};
|
|
771
803
|
if (tool === "cargo-nextest" && !rustEnabled) throw new Error("cloud.tools.cargo-nextest requires a Rust toolchain");
|
|
772
804
|
if (tool === "wasm-bindgen-cli") {
|
|
773
805
|
const lock = files["Cargo.lock"];
|
|
@@ -777,10 +809,15 @@ const resolveCloudToolchains = ({ cloud, files, rust, rustExceptions }) => {
|
|
|
777
809
|
const versions = new Set(packages.flatMap((entry) => record$2(entry) && entry["name"] === "wasm-bindgen" ? [entry["version"]] : []));
|
|
778
810
|
if (versions.size !== 1 || !versions.has(version)) throw new Error(`cloud.tools.wasm-bindgen-cli ${version} must equal the unique wasm-bindgen crate version in Cargo.lock (found ${[...versions].join(", ") || "none"})`);
|
|
779
811
|
}
|
|
780
|
-
return
|
|
812
|
+
return {
|
|
813
|
+
type: "artifact",
|
|
781
814
|
tool,
|
|
782
815
|
release: getCloudSetupArtifact(tool, version)
|
|
783
|
-
}
|
|
816
|
+
};
|
|
817
|
+
};
|
|
818
|
+
const tools = cloudExtraTools.flatMap((tool) => {
|
|
819
|
+
const version = cloud.tools?.[tool];
|
|
820
|
+
return version === void 0 ? [] : [resolveTool(tool, version)];
|
|
784
821
|
});
|
|
785
822
|
return {
|
|
786
823
|
rust: rustEnabled && typeof channel === "string" ? {
|
|
@@ -838,7 +875,7 @@ rust_ready() {
|
|
|
838
875
|
verify_rust() { rust_ready || fail 'Pinned Rust, components or targets are unavailable; run install'; }
|
|
839
876
|
install_rust() (
|
|
840
877
|
if ! command -v cc >/dev/null || ! command -v ld >/dev/null || [[ ! -f /usr/include/stdlib.h ]]; then
|
|
841
|
-
|
|
878
|
+
apt_refresh_for build-essential
|
|
842
879
|
apt_install build-essential
|
|
843
880
|
fi
|
|
844
881
|
local artifact_url artifact_sha
|
|
@@ -875,14 +912,31 @@ install_rust() (
|
|
|
875
912
|
)
|
|
876
913
|
`.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 "));
|
|
877
914
|
};
|
|
878
|
-
const
|
|
879
|
-
const
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
915
|
+
const packageToolInstall = ({ tool, release }) => {
|
|
916
|
+
const name = tool.replaceAll("-", "_");
|
|
917
|
+
return {
|
|
918
|
+
name,
|
|
919
|
+
text: `verify_${name}() {
|
|
920
|
+
[[ -x ${quote(release.binary)} && "$(${quote(release.binary)} --version 2>/dev/null)" == ${quote(release.identity)}* ]] || return 1
|
|
921
|
+
[[ "$(dpkg-query -W -f='\${Version}' ${quote(release.package)} 2>/dev/null)" == ${quote(`${release.version}-`)}* ]]
|
|
922
|
+
}
|
|
923
|
+
install_${name}() {
|
|
924
|
+
if ! verify_${name}; then
|
|
925
|
+
apt_network update
|
|
926
|
+
apt_install ${quote(release.package)}
|
|
927
|
+
verify_${name} || fail ${quote(`Installed ${tool} version differs from its pin`)}
|
|
928
|
+
fi
|
|
929
|
+
}
|
|
930
|
+
`
|
|
931
|
+
};
|
|
932
|
+
};
|
|
933
|
+
const artifactToolInstall = ({ tool, release }) => {
|
|
934
|
+
const directory = `/opt/stll-cloud/tools/${tool}/${release.version}`;
|
|
935
|
+
const command = tool === "wasm-bindgen-cli" ? "wasm-bindgen" : tool;
|
|
936
|
+
const marker = `${tool === "cargo-nextest" ? "cargo-nextest" : command} ${release.version}`;
|
|
937
|
+
return {
|
|
938
|
+
name: tool.replaceAll("-", "_"),
|
|
939
|
+
text: `verify_${tool.replaceAll("-", "_")}() {
|
|
886
940
|
${Object.keys(release.amd64.binaries).map((binary) => `[[ -x ${quote(`${directory}/${binary}`)} ]] || return 1`).join("\n ")}
|
|
887
941
|
[[ "$( ${quote(`${directory}/${command}`)} --version)" == ${quote(marker)} || "$( ${quote(`${directory}/${command}`)} --version)" == ${quote(`${marker} `)}* ]]
|
|
888
942
|
}
|
|
@@ -904,7 +958,15 @@ ${["amd64", "arm64"].map((arch) => ` ${arch})\n${Object.entries(release[arc
|
|
|
904
958
|
${Object.keys(release.amd64.binaries).map((binary) => ` ln -sfnT -- ${quote(`${directory}/${binary}`)} ${quote(`/usr/local/bin/${binary}`)}`).join("\n")}
|
|
905
959
|
)
|
|
906
960
|
`
|
|
907
|
-
|
|
961
|
+
};
|
|
962
|
+
};
|
|
963
|
+
const renderCloudToolInstall = ({ rust, tools }) => {
|
|
964
|
+
const installs = tools.map((entry) => {
|
|
965
|
+
switch (entry.type) {
|
|
966
|
+
case "package": return packageToolInstall(entry);
|
|
967
|
+
case "artifact": return artifactToolInstall(entry);
|
|
968
|
+
default: throw new Error(`Unsupported cloud tool: ${String(entry)}`);
|
|
969
|
+
}
|
|
908
970
|
});
|
|
909
971
|
return `${helpers}${rust === void 0 ? "" : rustInstall(rust)}\n${installs.map(({ text }) => text).join("\n")}
|
|
910
972
|
install_tools() {
|
|
@@ -955,6 +1017,14 @@ usage() { echo 'Usage: cloud-setup.sh install|start' >&2; exit 2; }
|
|
|
955
1017
|
case "$1" in install|start) MODE="$1" ;; *) usage ;; esac
|
|
956
1018
|
fail() { echo "cloud-setup: $*" >&2; exit 1; }
|
|
957
1019
|
trap 'echo "cloud-setup: command failed at line $LINENO" >&2' ERR
|
|
1020
|
+
# Each phase logs its start and duration so a stalled phase is visible in the task log.
|
|
1021
|
+
step() {
|
|
1022
|
+
local name="$1" started="$SECONDS"
|
|
1023
|
+
shift
|
|
1024
|
+
echo "cloud-setup: $name started" >&2
|
|
1025
|
+
"$@"
|
|
1026
|
+
echo "cloud-setup: $name done in $((SECONDS - started))s" >&2
|
|
1027
|
+
}
|
|
958
1028
|
[[ -f /etc/os-release ]] || fail 'Ubuntu 24.04 is required'
|
|
959
1029
|
. /etc/os-release
|
|
960
1030
|
[[ "$ID" == ubuntu && "$VERSION_ID" == 24.04 && "$VERSION_CODENAME" == noble ]] || fail 'Only Ubuntu 24.04 (noble) is supported'
|
|
@@ -998,7 +1068,7 @@ runtime_ready() {
|
|
|
998
1068
|
}
|
|
999
1069
|
install_runtimes() {
|
|
1000
1070
|
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
|
|
1001
|
-
|
|
1071
|
+
apt_refresh_for ca-certificates curl unzip xz-utils openssl gnupg util-linux libatomic1
|
|
1002
1072
|
DEBIAN_FRONTEND=noninteractive apt_install ca-certificates curl unzip xz-utils openssl gnupg util-linux libatomic1
|
|
1003
1073
|
fi
|
|
1004
1074
|
local scratch node_archive bun_archive bun_folder
|
|
@@ -1064,7 +1134,7 @@ for (const input of inputs) {
|
|
|
1064
1134
|
process.stdout.write([...hosts].sort().join(","));
|
|
1065
1135
|
')"
|
|
1066
1136
|
# Bun 1.4.3 socket inactivity timeout, in seconds; the outer bound includes scripts.
|
|
1067
|
-
network_run "$download_hosts" 240 runuser -u "$OUTPUT_USER" -- env HOME="$OUTPUT_HOME" BUN_INSTALL_CACHE_DIR="$BUN_CACHE" PATH="$PATH" BUN_CONFIG_HTTP_IDLE_TIMEOUT=20 "$BUN_DIR/bun"
|
|
1137
|
+
network_run "$download_hosts" 240 runuser -u "$OUTPUT_USER" -- env HOME="$OUTPUT_HOME" BUN_INSTALL_CACHE_DIR="$BUN_CACHE" PATH="$PATH" BUN_CONFIG_HTTP_IDLE_TIMEOUT=20 "$BUN_DIR/bun" @INSTALL_ARGS@
|
|
1068
1138
|
}
|
|
1069
1139
|
|
|
1070
1140
|
@SERVICE_INSTALL@
|
|
@@ -1077,20 +1147,20 @@ process.stdout.write([...hosts].sort().join(","));
|
|
|
1077
1147
|
@ENV_FUNCTIONS@
|
|
1078
1148
|
|
|
1079
1149
|
if [[ "$MODE" == install ]]; then
|
|
1080
|
-
install_runtimes
|
|
1081
|
-
install_services
|
|
1082
|
-
install_tools
|
|
1083
|
-
install_shell_environment
|
|
1084
|
-
dependency_install
|
|
1150
|
+
step runtimes install_runtimes
|
|
1151
|
+
step services install_services
|
|
1152
|
+
step tools install_tools
|
|
1153
|
+
step shell install_shell_environment
|
|
1154
|
+
step dependencies dependency_install
|
|
1085
1155
|
exit 0
|
|
1086
1156
|
fi
|
|
1087
|
-
runtime_ready
|
|
1088
|
-
verify_tools
|
|
1089
|
-
install_shell_environment
|
|
1090
|
-
verify_shell_environment
|
|
1157
|
+
step runtime-check runtime_ready
|
|
1158
|
+
step tool-check verify_tools
|
|
1159
|
+
step shell install_shell_environment
|
|
1160
|
+
step shell-check verify_shell_environment
|
|
1091
1161
|
@ENV_VALIDATE@
|
|
1092
|
-
prepare_state
|
|
1093
|
-
start_services
|
|
1162
|
+
step state prepare_state
|
|
1163
|
+
step service-start start_services
|
|
1094
1164
|
@ENV_WRITE@
|
|
1095
1165
|
`;
|
|
1096
1166
|
const environmentFunctions = String.raw`
|
|
@@ -1135,6 +1205,7 @@ const generateCloudSetup = ({ policy, cloud, nodeVersion, files = {}, rustExcept
|
|
|
1135
1205
|
});
|
|
1136
1206
|
const services = cloudServices.filter((service) => selected.services.includes(service));
|
|
1137
1207
|
const replacements = /* @__PURE__ */ new Map([
|
|
1208
|
+
["@INSTALL_ARGS@", selected.install.replace(/^bun /, "")],
|
|
1138
1209
|
["@NETWORK@", renderCloudNetwork()],
|
|
1139
1210
|
["@TOOL_INSTALL@", renderCloudToolInstall(toolchains) + renderCloudShellInstall({
|
|
1140
1211
|
nodeVersion: exactNode,
|
|
@@ -1178,12 +1249,12 @@ const generateCloudSetup = ({ policy, cloud, nodeVersion, files = {}, rustExcept
|
|
|
1178
1249
|
//#endregion
|
|
1179
1250
|
//#region src/cloud-setup-claude.ts
|
|
1180
1251
|
const cloudClaudeSettingsPath = ".claude/settings.json";
|
|
1181
|
-
const
|
|
1252
|
+
const sessionStartHook = (script) => ({
|
|
1182
1253
|
matcher: "",
|
|
1183
1254
|
hooks: [{
|
|
1184
1255
|
type: "command",
|
|
1185
1256
|
command: `if [ "\${CLAUDE_CODE_REMOTE:-}" = "true" ]; then
|
|
1186
|
-
|
|
1257
|
+
${script} start || exit "$?"
|
|
1187
1258
|
if [ -n "\${CLAUDE_ENV_FILE:-}" ]; then
|
|
1188
1259
|
if [ ! -f ${cloudShellProfilePath} ]; then
|
|
1189
1260
|
printf '%s\\n' 'cloud-setup: cloud shell profile is unavailable; run install' >&2
|
|
@@ -1194,6 +1265,12 @@ const cloudSessionStartHook = {
|
|
|
1194
1265
|
fi
|
|
1195
1266
|
fi`
|
|
1196
1267
|
}]
|
|
1268
|
+
});
|
|
1269
|
+
const cloudSessionStartHook = sessionStartHook(`bash "$CLAUDE_PROJECT_DIR/${cloudSetupPath}"`);
|
|
1270
|
+
const previousCloudSessionStartHooks = [sessionStartHook(`bash ${cloudSetupPath}`)];
|
|
1271
|
+
const cloudAttribution = {
|
|
1272
|
+
commit: "",
|
|
1273
|
+
pr: ""
|
|
1197
1274
|
};
|
|
1198
1275
|
const record$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1199
1276
|
const array = (value) => Array.isArray(value);
|
|
@@ -1225,33 +1302,69 @@ const readSettings = (text) => {
|
|
|
1225
1302
|
};
|
|
1226
1303
|
const cloudHookGroups = (sessionStart) => sessionStart.filter((entry) => record$1(entry) && array(entry["hooks"]) && entry["hooks"].some((hook) => record$1(hook) && typeof hook["command"] === "string" && hook["command"].includes(".agents/cloud-setup.sh")));
|
|
1227
1304
|
const cloudSessionStartFix = `preserve unrelated settings in ${cloudClaudeSettingsPath}, repair its JSON/hooks structure and set disableAllHooks to false if needed, and ensure hooks.SessionStart contains exactly this cloud setup entry (replace conflicting cloud setup entries):\n` + JSON.stringify(cloudSessionStartHook, null, 2);
|
|
1228
|
-
|
|
1229
|
-
const
|
|
1305
|
+
const cloudAttributionFix = `preserve unrelated settings in ${cloudClaudeSettingsPath} and set its top-level attribution to exactly:\n` + JSON.stringify({ attribution: cloudAttribution }, null, 2);
|
|
1306
|
+
const sessionStartState = (sessionStart) => {
|
|
1307
|
+
const groups = cloudHookGroups(sessionStart);
|
|
1308
|
+
const group = groups.at(0);
|
|
1309
|
+
if (group === void 0) return { type: "missing" };
|
|
1310
|
+
if (groups.length === 1 && (0, node_util.isDeepStrictEqual)(group, cloudSessionStartHook)) return { type: "current" };
|
|
1311
|
+
if (groups.length === 1 && previousCloudSessionStartHooks.some((hook) => (0, node_util.isDeepStrictEqual)(group, hook))) return {
|
|
1312
|
+
type: "previous",
|
|
1313
|
+
group
|
|
1314
|
+
};
|
|
1315
|
+
return { type: "conflict" };
|
|
1316
|
+
};
|
|
1317
|
+
const attributionState = (settings) => {
|
|
1318
|
+
const attribution = settings["attribution"];
|
|
1319
|
+
if (attribution === void 0) return "missing";
|
|
1320
|
+
return (0, node_util.isDeepStrictEqual)(attribution, cloudAttribution) ? "current" : "conflict";
|
|
1321
|
+
};
|
|
1322
|
+
const mergeError = (reason, fix) => /* @__PURE__ */ new Error(`cannot safely merge ${cloudClaudeSettingsPath}: ${reason}; ${fix}`);
|
|
1323
|
+
const readMergeableSettings = (text) => {
|
|
1230
1324
|
try {
|
|
1231
|
-
|
|
1232
|
-
const cloudGroups = cloudHookGroups(sessionStart);
|
|
1233
|
-
if (cloudGroups.length !== 0) {
|
|
1234
|
-
if (cloudGroups.length === 1 && (0, node_util.isDeepStrictEqual)(cloudGroups.at(0), cloudSessionStartHook) && text !== void 0) return text;
|
|
1235
|
-
throw new Error("existing cloud setup SessionStart hook differs");
|
|
1236
|
-
}
|
|
1237
|
-
return `${JSON.stringify({
|
|
1238
|
-
...settings,
|
|
1239
|
-
hooks: {
|
|
1240
|
-
...hooks,
|
|
1241
|
-
SessionStart: [...sessionStart, cloudSessionStartHook]
|
|
1242
|
-
}
|
|
1243
|
-
}, null, 2)}\n`;
|
|
1325
|
+
return readSettings(text);
|
|
1244
1326
|
} catch (error) {
|
|
1245
|
-
throw
|
|
1327
|
+
throw mergeError(error instanceof Error ? error.message : String(error), cloudSessionStartFix);
|
|
1246
1328
|
}
|
|
1247
1329
|
};
|
|
1330
|
+
/** Add the cloud hook and attribution; never overwrite conflicting values. */
|
|
1331
|
+
const mergeCloudClaudeSettings = (text) => {
|
|
1332
|
+
const { settings, hooks, sessionStart } = readMergeableSettings(text);
|
|
1333
|
+
const hook = sessionStartState(sessionStart);
|
|
1334
|
+
if (hook.type === "conflict") throw mergeError("existing cloud setup SessionStart hook differs", cloudSessionStartFix);
|
|
1335
|
+
const attribution = attributionState(settings);
|
|
1336
|
+
if (attribution === "conflict") throw mergeError("existing attribution differs", cloudAttributionFix);
|
|
1337
|
+
if (hook.type === "current" && attribution === "current" && text !== void 0) return text;
|
|
1338
|
+
const mergedSessionStart = (() => {
|
|
1339
|
+
switch (hook.type) {
|
|
1340
|
+
case "current": return sessionStart;
|
|
1341
|
+
case "missing": return [...sessionStart, cloudSessionStartHook];
|
|
1342
|
+
case "previous": return sessionStart.map((entry) => entry === hook.group ? cloudSessionStartHook : entry);
|
|
1343
|
+
default: throw new Error(`Unsupported hook state: ${String(hook)}`);
|
|
1344
|
+
}
|
|
1345
|
+
})();
|
|
1346
|
+
return `${JSON.stringify({
|
|
1347
|
+
...settings,
|
|
1348
|
+
attribution: cloudAttribution,
|
|
1349
|
+
hooks: {
|
|
1350
|
+
...hooks,
|
|
1351
|
+
SessionStart: mergedSessionStart
|
|
1352
|
+
}
|
|
1353
|
+
}, null, 2)}\n`;
|
|
1354
|
+
};
|
|
1248
1355
|
/** Settings formatting and unrelated hooks do not affect the generated contract. */
|
|
1249
1356
|
const hasCloudSessionStartHook = (text) => {
|
|
1250
1357
|
if (text === void 0) return false;
|
|
1251
1358
|
try {
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
return
|
|
1359
|
+
return sessionStartState(readSettings(text).sessionStart).type === "current";
|
|
1360
|
+
} catch {
|
|
1361
|
+
return false;
|
|
1362
|
+
}
|
|
1363
|
+
};
|
|
1364
|
+
const hasCloudAttribution = (text) => {
|
|
1365
|
+
if (text === void 0) return false;
|
|
1366
|
+
try {
|
|
1367
|
+
return attributionState(readSettings(text).settings) === "current";
|
|
1255
1368
|
} catch {
|
|
1256
1369
|
return false;
|
|
1257
1370
|
}
|
|
@@ -1430,6 +1543,12 @@ const toolchainInputKind = (file, text = "") => {
|
|
|
1430
1543
|
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";
|
|
1431
1544
|
};
|
|
1432
1545
|
//#endregion
|
|
1546
|
+
Object.defineProperty(exports, "cloudAttributionFix", {
|
|
1547
|
+
enumerable: true,
|
|
1548
|
+
get: function() {
|
|
1549
|
+
return cloudAttributionFix;
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
1433
1552
|
Object.defineProperty(exports, "cloudClaudeSettingsPath", {
|
|
1434
1553
|
enumerable: true,
|
|
1435
1554
|
get: function() {
|
|
@@ -1466,6 +1585,12 @@ Object.defineProperty(exports, "githubAutomationFileKind", {
|
|
|
1466
1585
|
return githubAutomationFileKind;
|
|
1467
1586
|
}
|
|
1468
1587
|
});
|
|
1588
|
+
Object.defineProperty(exports, "hasCloudAttribution", {
|
|
1589
|
+
enumerable: true,
|
|
1590
|
+
get: function() {
|
|
1591
|
+
return hasCloudAttribution;
|
|
1592
|
+
}
|
|
1593
|
+
});
|
|
1469
1594
|
Object.defineProperty(exports, "hasCloudSessionStartHook", {
|
|
1470
1595
|
enumerable: true,
|
|
1471
1596
|
get: function() {
|
|
@@ -1520,10 +1645,10 @@ Object.defineProperty(exports, "javascriptDependencyLockfiles", {
|
|
|
1520
1645
|
return javascriptDependencyLockfiles;
|
|
1521
1646
|
}
|
|
1522
1647
|
});
|
|
1523
|
-
Object.defineProperty(exports, "
|
|
1648
|
+
Object.defineProperty(exports, "mergeCloudClaudeSettings", {
|
|
1524
1649
|
enumerable: true,
|
|
1525
1650
|
get: function() {
|
|
1526
|
-
return
|
|
1651
|
+
return mergeCloudClaudeSettings;
|
|
1527
1652
|
}
|
|
1528
1653
|
});
|
|
1529
1654
|
Object.defineProperty(exports, "nodePolicyValid", {
|