Skip to content
This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 129 additions & 13 deletions .agents/cloud-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
# Supported platform: Ubuntu 24.04 (noble), amd64/arm64, root or passwordless sudo.
set -euo pipefail

usage() { echo 'Usage: cloud-setup.sh install|start' >&2; exit 2; }
usage() { echo 'Usage: cloud-setup.sh install|start|session' >&2; exit 2; }
[[ "$#" == 1 ]] || usage
case "$1" in install|start) MODE="$1" ;; *) usage ;; esac
case "$1" in install|start|session) MODE="$1" ;; *) usage ;; esac
fail() { echo "cloud-setup: $*" >&2; exit 1; }
trap 'echo "cloud-setup: command failed at line $LINENO" >&2' ERR
# Each phase logs its start and duration so a stalled phase is visible in the task log.
Expand Down Expand Up @@ -45,12 +45,14 @@ service_run() (
done
exec runuser -u stll-cloud -- "$@"
)
BUN_VERSION='1.4.3'
BUN_VERSION='1.4.4'
NODE_VERSION='26.10.0'
NODE_DIR="/opt/stll-cloud/node/$NODE_VERSION"
BUN_DIR="/opt/stll-cloud/bun/$BUN_VERSION"
export PATH="$NODE_DIR/bin:$BUN_DIR:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
BUN_CACHE="/var/cache/stll-cloud/bun/$OUTPUT_UID"
DEPENDENCY_STATE_ROOT=/var/lib/stll-cloud
DEPENDENCY_STAMP="$DEPENDENCY_STATE_ROOT/dependencies-$(printf '%s' "$REPO_ROOT" | sha256sum | cut -d' ' -f1).sha256"

[[ -f "$REPO_ROOT/.node-version" && ! -L "$REPO_ROOT/.node-version" ]] || fail 'A regular root .node-version is required'
[[ "$(awk 'NF { if (++count > 1 || NF != 1) exit 1; value=$1 } END { if (count != 1) exit 1; print value }' "$REPO_ROOT/.node-version")" == "$NODE_VERSION" ]] || fail 'Node selector changed; regenerate cloud-setup.sh'
Expand Down Expand Up @@ -135,6 +137,63 @@ runtime_ready() {
node_ready || fail 'Pinned Node, npm or npx is unavailable; run install'
[[ -x "$BUN_DIR/bun" && "$($BUN_DIR/bun --version)" == "$BUN_VERSION" ]] || fail 'Pinned Bun is unavailable; run install'
}
bun_route() {
local label="$1" resolved version
shift
resolved="$("$@" -c 'command -v bun')" || fail "Bun is unavailable through $label"
version="$("$@" -c 'bun --version')" || fail "Bun at $resolved failed through $label"
[[ "$version" == "$BUN_VERSION" ]] || fail "Bun at $resolved resolves version $version through $label; expected $BUN_VERSION"
}
verify_bun_routes() {
local configured_mise login_shell minimal_path mise_root root_mise shims
# Test-only overrides keep route executables and image locations inside fixtures.
login_shell="$(printenv STLL_CLOUD_TEST_LOGIN_SHELL || true)"
[[ -n "$login_shell" ]] || login_shell=bash
minimal_path="$(printenv STLL_CLOUD_TEST_MINIMAL_PATH || true)"
[[ -n "$minimal_path" ]] || minimal_path=/usr/local/bin:/usr/bin:/bin
root_mise="$(printenv STLL_CLOUD_TEST_ROOT_MISE || true)"
[[ -n "$root_mise" ]] || root_mise=/root/.local/share/mise
# An absolute shell: a PATH entry such as a user-writable mise shims
# directory must never supply the program that root runs.
bun_route 'the setup PATH' env PATH="$PATH" /bin/sh
bun_route 'sh -c' /bin/sh
bun_route 'bash -lc' "$login_shell" -l
bun_route 'the minimal system PATH' env -i PATH="$minimal_path" /bin/sh
configured_mise="$(printenv MISE_DATA_DIR || true)"
for mise_root in "$configured_mise" "$OUTPUT_HOME/.local/share/mise" "$root_mise"; do
[[ -n "$mise_root" ]] || continue
shims="$mise_root/shims"
[[ -d "$shims" ]] || continue
bun_route "mise shims PATH $shims" env PATH="$shims:$PATH" /bin/sh
done
}
replace_image_buns() {
local candidate configured_mise directory mise_root root_mise
configured_mise="$(printenv MISE_DATA_DIR || true)"
root_mise="$(printenv STLL_CLOUD_TEST_ROOT_MISE || true)"
[[ -n "$root_mise" ]] || root_mise=/root/.local/share/mise
for mise_root in "$configured_mise" "$OUTPUT_HOME/.local/share/mise" "$root_mise"; do
[[ -n "$mise_root" ]] || continue
if [[ -d "$mise_root/installs/bun" ]]; then
while IFS= read -r -d '' candidate; do
[[ -d "$candidate" ]] || ln -sfnT -- "$BUN_DIR/bun" "$candidate"
done < <(find "$mise_root/installs/bun" \( -type f -o -type l \) \( -name bun -o -name bunx \) -print0)
fi
for candidate in "$mise_root/shims/bun" "$mise_root/shims/bunx"; do
[[ -e "$candidate" || -L "$candidate" ]] || continue
[[ -d "$candidate" ]] || ln -sfnT -- "$BUN_DIR/bun" "$candidate"
done
done
while IFS= read -r directory; do
[[ -n "$directory" ]] || directory=.
for candidate in "$directory/bun" "$directory/bunx"; do
[[ -e "$candidate" || -L "$candidate" ]] || continue
[[ -d "$candidate" ]] && continue
[[ "$(readlink -f -- "$candidate")" == "$(readlink -f -- "$BUN_DIR/bun")" ]] || ln -sfnT -- "$BUN_DIR/bun" "$candidate"
done
# The trailing newline lets read return the last PATH entry too.
done < <(printf '%s\n' "$PATH" | tr : '\n')
}
install_runtimes() (
if [[ ! -s /etc/ssl/certs/ca-certificates.crt ]]; then
command -v update-ca-certificates >/dev/null || fail 'System CA certificate bundle is missing; restore ca-certificates in the base image offline before install'
Expand Down Expand Up @@ -172,6 +231,7 @@ install_runtimes() (
ln -sfnT -- "$NODE_DIR/bin/npm" /usr/local/bin/npm
ln -sfnT -- "$NODE_DIR/bin/npx" /usr/local/bin/npx
ln -sfnT -- "$BUN_DIR/bun" /usr/local/bin/bun
replace_image_buns
)

dependency_install() {
Expand Down Expand Up @@ -210,6 +270,48 @@ process.stdout.write([...hosts].sort().join(","));
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 --frozen-lockfile
}

dependency_hash() {
[[ -f bun.lock && ! -L bun.lock ]] || fail 'A regular root bun.lock is required'
sha256sum -- bun.lock | cut -d ' ' -f1
}
prepare_dependency_state() {
[[ ! -L "$DEPENDENCY_STATE_ROOT" ]] || fail 'Dependency state root must not be a symlink'
if [[ -e "$DEPENDENCY_STATE_ROOT" ]]; then
[[ -d "$DEPENDENCY_STATE_ROOT" && "$(stat -c '%u:%a' "$DEPENDENCY_STATE_ROOT")" == 0:755 ]] || fail 'Invalid dependency state root'
else
install -d -m 755 -o root -g root "$DEPENDENCY_STATE_ROOT"
fi
[[ ! -L "$DEPENDENCY_STAMP" ]] || fail 'Dependency stamp must not be a symlink'
if [[ -e "$DEPENDENCY_STAMP" ]]; then
[[ -f "$DEPENDENCY_STAMP" && "$(stat -c '%u:%a' "$DEPENDENCY_STAMP")" == 0:644 ]] || fail 'Invalid dependency stamp'
fi
}
write_dependency_stamp() {
local temporary
prepare_dependency_state
temporary="$(mktemp "$DEPENDENCY_STATE_ROOT/.dependencies.XXXXXX")"
chmod 644 "$temporary"
dependency_hash > "$temporary"
mv -f -- "$temporary" "$DEPENDENCY_STAMP"
}
install_dependencies() {
prepare_dependency_state
rm -f -- "$DEPENDENCY_STAMP"
dependency_install
write_dependency_stamp
}
sync_dependencies() {
local expected installed=''
prepare_dependency_state
expected="$(dependency_hash)"
if [[ -f "$DEPENDENCY_STAMP" ]]; then IFS= read -r installed < "$DEPENDENCY_STAMP" || true; fi
# The stamp describes an installation; without node_modules there is none.
[[ "$installed" == "$expected" && -d "$REPO_ROOT/node_modules" ]] && return
rm -f -- "$DEPENDENCY_STAMP"
dependency_install || fail 'bun.lock mismatch; dependency installation failed'
write_dependency_stamp
}


# Prevent package maintainer scripts from starting unmanaged system services.
apt_install() (
Expand Down Expand Up @@ -307,12 +409,12 @@ while :; do
*) _stll_cloud_part="$_stll_cloud_remaining"; _stll_cloud_more=no ;;
esac
case "$_stll_cloud_part" in
'/opt/stll-cloud/node/26.10.0/bin'|'/opt/stll-cloud/bun/1.4.3'|/usr/local/bin) ;;
'/opt/stll-cloud/node/26.10.0/bin'|'/opt/stll-cloud/bun/1.4.4'|/usr/local/bin) ;;
*) _stll_cloud_result="$_stll_cloud_result$_stll_cloud_separator$_stll_cloud_part"; _stll_cloud_separator=: ;;
esac
[ "$_stll_cloud_more" = yes ] || break
done
export PATH='/opt/stll-cloud/node/26.10.0/bin:/opt/stll-cloud/bun/1.4.3:/usr/local/bin'"${_stll_cloud_separator:+:}$_stll_cloud_result"
export PATH='/opt/stll-cloud/node/26.10.0/bin:/opt/stll-cloud/bun/1.4.4:/usr/local/bin'"${_stll_cloud_separator:+:}$_stll_cloud_result"
unset _stll_cloud_remaining _stll_cloud_result _stll_cloud_separator _stll_cloud_part _stll_cloud_more
STLL_CLOUD_PROFILE
if ! cmp -s "$temporary" '/etc/profile.d/stll-cloud.sh'; then install -m 644 "$temporary" '/etc/profile.d/stll-cloud.sh'; fi
Expand Down Expand Up @@ -349,7 +451,7 @@ done
)
verify_shell_environment() {
[[ -f '/etc/profile.d/stll-cloud.sh' && ! -L '/etc/profile.d/stll-cloud.sh' && "$(stat -c '%h:%u' '/etc/profile.d/stll-cloud.sh')" == 1:0 ]] || fail 'Managed shell environment is unavailable; run install'
[[ "$(sha256sum -- '/etc/profile.d/stll-cloud.sh' | cut -d ' ' -f1)" == 'a7dedf20b0380fb3ac726140bd85f0324ca3b99a499adcb850809292f82cfc7f' ]] || fail 'Managed shell environment differs; run install'
[[ "$(sha256sum -- '/etc/profile.d/stll-cloud.sh' | cut -d ' ' -f1)" == '1f0232ed3fb3271c674e32f63666d769eea47d0a1110ab3f1a05302b0435718c' ]] || fail 'Managed shell environment differs; run install'
}


Expand All @@ -360,19 +462,33 @@ verify_shell_environment() {





if [[ "$MODE" == install ]]; then
step runtimes install_runtimes
step services install_services
step tools install_tools
step shell install_shell_environment
step dependencies dependency_install
# Login routes read the installed profile, so they are checked after it.
step routes verify_bun_routes
step dependencies install_dependencies

exit 0
fi
step runtime-check runtime_ready
step tool-check verify_tools
step shell install_shell_environment
step shell-check verify_shell_environment

step state prepare_state
step service-start start_services
start_environment() {
step runtime-check runtime_ready
step dependencies sync_dependencies
step tool-check verify_tools
step shell install_shell_environment
step shell-check verify_shell_environment

step state prepare_state
step service-start start_services

}
if [[ "$MODE" == session ]]; then
start_environment >&2
else
start_environment
fi
4 changes: 4 additions & 0 deletions .changeset/bun-fmt-tooling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
---

Tooling only: Bun 1.4.4, the shared bun fmt style and the shared tooling pins. No published behavior changes.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"linked": [],
"access": "public",
"baseBranch": "main",
"format": "oxfmt",
"format": false,
"updateInternalDependencies": "patch",
"ignore": []
}
2 changes: 1 addition & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"hooks": [
{
"type": "command",
"command": "if [ \"${CLAUDE_CODE_REMOTE:-}\" = \"true\" ]; then\n cloud_setup_incomplete() {\n 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.'\n printf '%s\\n' \"cloud-setup: $1\" >&2\n exit 0\n }\n bash \"$CLAUDE_PROJECT_DIR/.agents/cloud-setup.sh\" start >&2 || cloud_setup_incomplete 'startup failed; run install'\n if [ -n \"${CLAUDE_ENV_FILE:-}\" ]; then\n if [ ! -s /etc/profile.d/stll-cloud.sh ]; then\n cloud_setup_incomplete 'cloud shell profile is unavailable; run install'\n fi\n cloud_shell_exports=\"$(cat /etc/profile.d/stll-cloud.sh)\" || cloud_setup_incomplete 'cloud shell profile could not be read; run install'\n [ -n \"$cloud_shell_exports\" ] || cloud_setup_incomplete 'cloud shell profile is unavailable; run install'\n 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'\n fi\nfi"
"command": "if [ \"${CLAUDE_CODE_REMOTE:-}\" = \"true\" ]; then\n cloud_setup_incomplete() {\n 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.'\n printf '%s\\n' \"cloud-setup: $1\" >&2\n exit 0\n }\n if [ -n \"${CLAUDE_ENV_FILE:-}\" ]; then\n cloud_session_exports=\"$(bash \"$CLAUDE_PROJECT_DIR/.agents/cloud-setup.sh\" session)\" || cloud_setup_incomplete 'startup failed; run install'\n else\n bash \"$CLAUDE_PROJECT_DIR/.agents/cloud-setup.sh\" start >&2 || cloud_setup_incomplete 'startup failed; run install'\n exit 0\n fi\n if [ -n \"${CLAUDE_ENV_FILE:-}\" ]; then\n if [ ! -s /etc/profile.d/stll-cloud.sh ]; then\n cloud_setup_incomplete 'cloud shell profile is unavailable; run install'\n fi\n cloud_shell_exports=\"$(cat /etc/profile.d/stll-cloud.sh)\" || cloud_setup_incomplete 'cloud shell profile could not be read; run install'\n [ -n \"$cloud_shell_exports\" ] || cloud_setup_incomplete 'cloud shell profile is unavailable; run install'\n if [ -e \"$CLAUDE_ENV_FILE\" ] || [ -L \"$CLAUDE_ENV_FILE\" ]; then\n [ -f \"$CLAUDE_ENV_FILE\" ] && [ ! -L \"$CLAUDE_ENV_FILE\" ] || cloud_setup_incomplete 'session environment must be a regular file; check its path and rerun start'\n fi\n cloud_env_snapshot=\"${CLAUDE_ENV_FILE}.stll-cloud\"\n case \"$cloud_env_snapshot\" in\n *\"'\"*) cloud_setup_incomplete 'session environment path must not contain a single quote; check its path and rerun start' ;;\n esac\n if [ -n \"$cloud_session_exports\" ]; then\n cloud_session_exports=\"$cloud_session_exports\n$cloud_shell_exports\"\n else\n cloud_session_exports=\"$cloud_shell_exports\"\n fi\n cloud_env_temporary=\"$(umask 077; mktemp \"${cloud_env_snapshot}.XXXXXX\")\" || cloud_setup_incomplete 'session environment could not be prepared; check its write access and rerun start'\n printf '%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'; }\n mv -f -- \"$cloud_env_temporary\" \"$cloud_env_snapshot\" || { rm -f -- \"$cloud_env_temporary\"; cloud_setup_incomplete 'session environment could not be persisted; check its write access and rerun start'; }\n cloud_env_source=\". '$cloud_env_snapshot'\"\n if [ ! -f \"$CLAUDE_ENV_FILE\" ] || ! grep -Fqx -- \"$cloud_env_source\" \"$CLAUDE_ENV_FILE\"; then\n printf '\\n%s\\n' \"$cloud_env_source\" >> \"$CLAUDE_ENV_FILE\" || cloud_setup_incomplete 'session environment could not be persisted; check its write access and rerun start'\n fi\n fi\nfi"
}
]
}
Expand Down
12 changes: 10 additions & 2 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ updates:
- version-update:semver-major
- version-update:semver-minor
- version-update:semver-patch
- dependency-name: oxfmt
- dependency-name: lefthook
update-types:
- version-update:semver-major
- version-update:semver-minor
- version-update:semver-patch
- dependency-name: lefthook
- dependency-name: npm
update-types:
- version-update:semver-major
- version-update:semver-minor
- version-update:semver-patch
- dependency-name: pnpm
update-types:
- version-update:semver-major
- version-update:semver-minor
Expand Down Expand Up @@ -80,6 +85,9 @@ updates:
cooldown:
default-days: 5
groups:
stella-shared:
patterns:
- stella/.github/*
dependencies:
patterns:
- "*"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
if: steps.toolchain.outputs.changed == 'true'
- run: bun test scripts/tooling-adoption.test.ts
- run: bun run lint
- run: bun run format:check
- run: bun fmt --check
- run: bun run test
- run: bun run knip
- run: bun run build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
)

- name: Upload tarball
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: npm-tarball-${{ matrix.package }}
path: release-artifacts/*.tgz
Expand Down
31 changes: 0 additions & 31 deletions .oxfmtrc.json

This file was deleted.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ bun run lint:ws
bun run typecheck
bun run check:typecheck-parity
bun run lint
bun run format:check
bun fmt --check
bun run test
bun run knip
bun run build
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ bun run lint:ws
bun run typecheck
bun run check:typecheck-parity
bun run lint
bun run format:check
bun fmt --check
bun run test
bun run knip
bun run build
Expand Down
Loading
Loading