Skip to content
Merged
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
42 changes: 25 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,17 @@ jobs:
matrix:
include:
# Each target builds ONE binary in parallel (~5 min each)
# Index matches allTargets array in build.ts
# Index matches allTargets array in build.ts. Targets without a
# @altimateai/altimate-core NAPI prebuild (linux-*-musl, win32-arm64)
# are intentionally excluded — see allTargets in build.ts.
- { index: 0, name: "linux-arm64" }
- { index: 1, name: "linux-x64" }
- { index: 2, name: "linux-x64-baseline" }
- { index: 3, name: "linux-arm64-musl" }
- { index: 4, name: "linux-x64-musl" }
- { index: 5, name: "linux-x64-baseline-musl" }
- { index: 6, name: "darwin-arm64" }
- { index: 7, name: "darwin-x64" }
- { index: 8, name: "darwin-x64-baseline" }
- { index: 9, name: "win32-arm64" }
- { index: 10, name: "win32-x64" }
- { index: 11, name: "win32-x64-baseline" }
- { index: 3, name: "darwin-arm64" }
- { index: 4, name: "darwin-x64" }
- { index: 5, name: "darwin-x64-baseline" }
- { index: 6, name: "win32-x64" }
- { index: 7, name: "win32-x64-baseline" }
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

Expand Down Expand Up @@ -106,17 +104,22 @@ jobs:
- name: Smoke test binary
if: matrix.name == 'linux-x64'
run: |
BINARY=$(find packages/opencode/dist -name altimate -type f | head -1)
# Resolve to an absolute path before we cd away from the workspace.
BINARY=$(find "$(pwd)/packages/opencode/dist" -name altimate -type f | head -1)
if [ -z "$BINARY" ]; then
echo "::error::No binary found in dist/"
exit 1
fi
chmod +x "$BINARY"

# Set NODE_PATH so the binary can resolve external NAPI modules
# (mirrors what the npm bin wrapper does at runtime)
NODE_PATH="$(pwd)/packages/opencode/node_modules:$(pwd)/node_modules" "$BINARY" --version
echo "Smoke test passed: binary starts and prints version"
# Run with NO pre-set NODE_PATH AND from a directory with no
# node_modules anywhere upward. Bun's compiled binary would
# otherwise walk the workspace tree for node_modules and resolve
# altimate-core that way — the test would pass for the wrong
# reason if the staged shim ever silently misses.
cd "${RUNNER_TEMP:-/tmp}"
env -u NODE_PATH "$BINARY" --version
echo "Smoke test passed: standalone binary starts hermetically"

- name: Upload build artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
Expand Down Expand Up @@ -256,13 +259,18 @@ jobs:
# compile-time checks miss (e.g. missing NAPI externals like v0.5.10).
- name: Pre-publish smoke test
run: |
BINARY=$(find packages/opencode/dist -path '*altimate-code-linux-x64/bin/altimate' -type f | head -1)
# Resolve to an absolute path before we cd away from the workspace.
BINARY=$(find "$(pwd)/packages/opencode/dist" -path '*altimate-code-linux-x64/bin/altimate' -type f | head -1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Pre-publish smoke test still looks for the old altimate-code-linux-x64 artifact path, which can break release verification after the binary/archive rename to altimate.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/release.yml, line 263:

<comment>Pre-publish smoke test still looks for the old `altimate-code-linux-x64` artifact path, which can break release verification after the binary/archive rename to `altimate`.</comment>

<file context>
@@ -256,14 +259,17 @@ jobs:
         run: |
-          BINARY=$(find packages/opencode/dist -path '*altimate-code-linux-x64/bin/altimate' -type f | head -1)
+          # Resolve to an absolute path before we cd away from the workspace.
+          BINARY=$(find "$(pwd)/packages/opencode/dist" -path '*altimate-code-linux-x64/bin/altimate' -type f | head -1)
           if [ -z "$BINARY" ]; then
             echo "::error::No linux-x64 binary found in artifacts — cannot verify release"
</file context>
Suggested change
BINARY=$(find "$(pwd)/packages/opencode/dist" -path '*altimate-code-linux-x64/bin/altimate' -type f | head -1)
BINARY=$(find "$(pwd)/packages/opencode/dist" -path '*altimate-linux-x64/bin/altimate' -type f | head -1)

Tip: Review your code locally with the cubic CLI to iterate faster.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a bug — false positive. The path glob matches the dist subdirectory layout, not the release archive name. The build script writes binaries to dist/@altimateai/altimate-code-<target>/bin/altimate (per build.ts:280-291, the per-target dir name is pkg.name + os + arch + ... = @altimateai/altimate-code-<target>). That layout is unchanged by this PR — only the archive filename produced at build.ts:459-468 was renamed to altimate-<target>.{zip,tar.gz}. The find pattern *altimate-code-linux-x64/bin/altimate correctly resolves the dist binary; locally verified with ls packages/opencode/dist/@altimateai/altimate-code-darwin-arm64/bin/ → contains altimate.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

if [ -z "$BINARY" ]; then
echo "::error::No linux-x64 binary found in artifacts — cannot verify release"
exit 1
else
chmod +x "$BINARY"
NODE_PATH="$(pwd)/packages/opencode/node_modules:$(pwd)/node_modules" "$BINARY" --version
# No NODE_PATH AND hermetic cwd: see the build-time smoke test
# comment for why this matters. The binary must start without
# walking the workspace for node_modules.
cd "${RUNNER_TEMP:-/tmp}"
env -u NODE_PATH "$BINARY" --version
echo "Pre-publish smoke test passed"
fi

Expand Down
78 changes: 53 additions & 25 deletions install
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
APP=altimate-code
APP=altimate

MUTED='\033[0;2m'
RED='\033[0;31m'
Expand All @@ -22,7 +22,7 @@ Options:
Examples:
curl -fsSL https://altimate.ai/install | bash
curl -fsSL https://altimate.ai/install | bash -s -- --version 1.0.180
./install --binary /path/to/altimate-code
./install --binary /path/to/altimate
EOF
}

Expand Down Expand Up @@ -65,7 +65,7 @@ while [[ $# -gt 0 ]]; do
esac
done

INSTALL_DIR=$HOME/.altimate-code/bin
INSTALL_DIR=$HOME/.altimate/bin
mkdir -p "$INSTALL_DIR"

# If --binary is provided, skip all download/detection logic
Expand Down Expand Up @@ -121,12 +121,30 @@ else
fi

if command -v ldd >/dev/null 2>&1; then
if ldd --version 2>&1 | grep -qi musl; then
# ldd --version exits non-zero on musl by design. With `set -o pipefail`
# (line 2), a pipeline `ldd --version 2>&1 | grep -qi musl` would inherit
# ldd's failure and the if-block would never fire — defeating musl
# detection on every non-Alpine musl distro (Void, Adelie, custom builds).
# Capture output first, then grep.
ldd_out="$(ldd --version 2>&1 || true)"
if printf '%s' "$ldd_out" | grep -qi musl; then
is_musl=true
fi
fi
fi

# @altimateai/altimate-core has no NAPI prebuild for musl. Without a
# musl-shaped archive, the install would 404 silently (without --fail
# curl writes the 404 HTML to disk, and tar then dies "not in gzip
# format"). Fail fast with an actionable message instead.
if [ "$is_musl" = "true" ]; then
echo -e "${RED}Alpine Linux (musl) is not currently supported by the standalone install.${NC}"
echo -e "${MUTED}altimate-core has no NAPI prebuild for musl yet. Workarounds:${NC}"
echo -e " • apk add gcompat ${MUTED}# run glibc binaries on Alpine${NC}"
echo -e " • Use npm: npm install -g altimate-code"
exit 1
fi

needs_baseline=false
if [ "$arch" = "x64" ]; then
if [ "$os" = "linux" ]; then
Expand Down Expand Up @@ -161,11 +179,14 @@ else
if [ "$needs_baseline" = "true" ]; then
target="$target-baseline"
fi
if [ "$is_musl" = "true" ]; then
target="$target-musl"
fi
# is_musl=true would have exited above — no musl target suffix is constructed.

filename="$APP-$target$archive_ext"
# Windows release archives ship altimate.exe, every other target ships altimate.
binary_name="$APP"
if [ "$os" = "windows" ]; then
binary_name="$APP.exe"
fi


if [ "$os" = "linux" ]; then
Expand Down Expand Up @@ -219,11 +240,11 @@ print_message() {
}

check_version() {
if command -v altimate-code >/dev/null 2>&1; then
altimate_code_path=$(which altimate-code)
if command -v altimate >/dev/null 2>&1; then
altimate_path=$(which altimate)

## Check the installed version
installed_version=$(altimate-code --version 2>/dev/null || echo "")
installed_version=$(altimate --version 2>/dev/null || echo "")

if [[ "$installed_version" != "$specific_version" ]]; then
print_message info "${MUTED}Installed version: ${NC}$installed_version."
Expand Down Expand Up @@ -275,7 +296,7 @@ download_with_progress() {
fi

local tmp_dir=${TMPDIR:-/tmp}
local basename="${tmp_dir}/altimate_code_install_$$"
local basename="${tmp_dir}/altimate_install_$$"
local tracefile="${basename}.trace"

rm -f "$tracefile"
Expand All @@ -287,7 +308,9 @@ download_with_progress() {
trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN

(
curl --trace-ascii "$tracefile" -s -L -o "$output" "$url"
# --fail so HTTP errors (e.g. 404 on an unknown target archive) become
# a non-zero exit instead of silently writing the error page to disk.
curl --fail --trace-ascii "$tracefile" -s -L -o "$output" "$url"
) &
local curl_pid=$!

Expand Down Expand Up @@ -325,13 +348,14 @@ download_with_progress() {
}

download_and_install() {
print_message info "\n${MUTED}Installing ${NC}altimate-code ${MUTED}version: ${NC}$specific_version"
local tmp_dir="${TMPDIR:-/tmp}/altimate_code_install_$$"
print_message info "\n${MUTED}Installing ${NC}altimate ${MUTED}version: ${NC}$specific_version"
local tmp_dir="${TMPDIR:-/tmp}/altimate_install_$$"
mkdir -p "$tmp_dir"

if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then
# Fallback to standard curl on Windows, non-TTY environments, or if custom progress fails
curl -# -L -o "$tmp_dir/$filename" "$url"
# Fallback to standard curl on Windows, non-TTY environments, or if custom progress fails.
# --fail so 404s exit non-zero instead of writing the error page to $tmp_dir/$filename.
curl --fail -# -L -o "$tmp_dir/$filename" "$url"
fi

if [ "$os" = "linux" ]; then
Expand All @@ -340,15 +364,19 @@ download_and_install() {
unzip -q "$tmp_dir/$filename" -d "$tmp_dir"
fi

mv "$tmp_dir/altimate-code" "$INSTALL_DIR"
chmod 755 "${INSTALL_DIR}/altimate-code"
mv "$tmp_dir/$binary_name" "${INSTALL_DIR}/$binary_name"
chmod 755 "${INSTALL_DIR}/$binary_name"
rm -rf "$tmp_dir"
}

install_from_binary() {
print_message info "\n${MUTED}Installing ${NC}altimate-code ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "${INSTALL_DIR}/altimate-code"
chmod 755 "${INSTALL_DIR}/altimate-code"
# --binary may point to either altimate or altimate.exe; preserve the
# caller's basename so the installed file matches what was supplied.
local dest_name
dest_name=$(basename "$binary_path")
print_message info "\n${MUTED}Installing ${NC}$dest_name ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "${INSTALL_DIR}/$dest_name"
chmod 755 "${INSTALL_DIR}/$dest_name"
}

if [ -n "$binary_path" ]; then
Expand All @@ -366,9 +394,9 @@ add_to_path() {
if grep -Fxq "$command" "$config_file"; then
print_message info "Command already exists in $config_file, skipping write."
elif [[ -w $config_file ]]; then
echo -e "\n# altimate-code" >> "$config_file"
echo -e "\n# altimate" >> "$config_file"
echo "$command" >> "$config_file"
print_message info "${MUTED}Successfully added ${NC}altimate-code ${MUTED}to \$PATH in ${NC}$config_file"
print_message info "${MUTED}Successfully added ${NC}altimate ${MUTED}to \$PATH in ${NC}$config_file"
else
print_message warning "Manually add the directory to $config_file (or similar):"
print_message info " $command"
Expand Down Expand Up @@ -448,8 +476,8 @@ echo -e ""
echo -e ""
echo -e "${MUTED}To start:${NC}"
echo -e ""
echo -e "cd <project> ${MUTED}# Open your project directory${NC}"
echo -e "altimate-code ${MUTED}# Launch the interactive TUI${NC}"
echo -e "cd <project> ${MUTED}# Open directory${NC}"
echo -e "altimate ${MUTED}# Run command${NC}"
echo -e ""
echo -e "${MUTED}For more information visit ${NC}https://altimate.ai"
echo -e ""
Expand Down
67 changes: 38 additions & 29 deletions packages/opencode/bin/altimate
Original file line number Diff line number Diff line change
Expand Up @@ -153,42 +153,51 @@ function supportsAvx2() {
return false
}

function isMusl() {
if (platform !== "linux") return false
try {
if (fs.existsSync("/etc/alpine-release")) return true
} catch {
// ignore
}
try {
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
if (text.includes("musl")) return true
} catch {
// ignore
}
return false
}

// @altimateai/altimate-core has no NAPI prebuild for musl or win32-arm64,
// and the altimate binary embeds altimate-core's .node file at build time.
// Hard-error early instead of letting findBinary() walk the whole tree and
// emit a misleading "package manager failed to install the right version"
// message — the right diagnosis is that these platforms aren't built.
if (isMusl()) {
console.error("altimate-code is not currently supported on Alpine Linux (musl).")
console.error("Workarounds:")
console.error(" • apk add gcompat # run glibc binaries on Alpine")
console.error(" • Use a glibc-based container (debian/ubuntu/alpine+gcompat)")
process.exit(1)
}
if (platform === "windows" && arch === "arm64") {
console.error("altimate-code is not currently built for Windows on ARM64.")
console.error("Run the x64 build under Windows ARM's x64 emulation, or use WSL.")
process.exit(1)
}

const names = (() => {
const avx2 = supportsAvx2()
const baseline = arch === "x64" && !avx2

if (platform === "linux") {
const musl = (() => {
try {
if (fs.existsSync("/etc/alpine-release")) return true
} catch {
// ignore
}

try {
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
if (text.includes("musl")) return true
} catch {
// ignore
}

return false
})()

if (musl) {
if (arch === "x64") {
if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
}
return [`${base}-musl`, base]
}

if (arch === "x64") {
if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
if (baseline) return [`${base}-baseline`, base]
return [base, `${base}-baseline`]
}
return [base, `${base}-musl`]
return [base]
}

if (arch === "x64") {
Expand Down
Loading
Loading