Skip to content
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ On Windows, install the same self-contained binary (to `%USERPROFILE%\.altimate\
powershell -c "irm https://www.altimate.sh/install.ps1 | iex"
```

The standalone install drops a single self-contained binary named `altimate`. The npm install exposes both `altimate` and `altimate-code` on PATH; the standalone install only exposes `altimate`. Alpine Linux (musl) and Windows on ARM64 are not currently supported by the standalone binary — use `apk add gcompat` on Alpine, or use WSL on Windows-on-ARM.
The standalone install drops a single self-contained binary named `altimate`, plus an `altimate-code` alias for it — the same two names the npm install exposes. On Windows that alias is an `altimate-code.cmd` shim, which passes its arguments through `cmd.exe` (`%VAR%` expands, unquoted `&` `|` `^` are interpreted), so scripts should call `altimate`. Alpine Linux (musl) and Windows on ARM64 are not currently supported by the standalone binary — use `apk add gcompat` on Alpine, or use WSL on Windows-on-ARM.

For GitHub, [install the Altimate Code App](https://github.com/apps/altimate-code-agent/installations/new)
to select repositories for interactive agent tasks. Automatic dbt pull-request
Expand Down
4 changes: 1 addition & 3 deletions docs/docs/reference/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ description: "Fix common Altimate Code installation and runtime issues including

**Symptoms:** `altimate-code: command not found` after running `curl -fsSL https://www.altimate.sh/install | bash`.

As of v0.7.1 the curl-installed binary is named `altimate`, not `altimate-code`. The npm package continues to ship both names. If you scripted against the curl install:
As of v0.7.1 the curl-installed binary is named `altimate`, and curl installs from v0.7.1 until the `altimate-code` alias was added put only that name on PATH (v0.7.0 and earlier installed `altimate-code` under `~/.altimate-code/bin` instead). Re-run the installer — it adds `altimate-code` next to `altimate` in `~/.altimate/bin` — or call `altimate` directly:

```bash
# Before (v0.7.0 and earlier curl install):
Expand All @@ -20,8 +20,6 @@ As of v0.7.1 the curl-installed binary is named `altimate`, not `altimate-code`.
~/.altimate/bin/altimate run "..."
```

Or stay on the `altimate-code` name by installing via npm: `npm install -g altimate-code`.

### `Cannot find module '@altimateai/altimate-code-core'`

**Symptoms:** Binary crashes on first run with the above error (curl-installed v0.7.0 and earlier).
Expand Down
5 changes: 4 additions & 1 deletion docs/docs/reference/windows-wsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ powershell -c "irm https://www.altimate.sh/install.ps1 | iex"
```

This downloads `altimate.exe` to `%USERPROFILE%\.altimate\bin` and adds that
directory to your user PATH (open a new terminal afterwards). The installer
directory to your user PATH (open a new terminal afterwards). It also writes an
`altimate-code` alias there: `altimate-code.cmd` for cmd.exe and PowerShell, and
an extensionless shim for Git Bash. Inside WSL, install the Linux build with the
curl one-liner; the Windows shim refuses to run there. The installer

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This sentence refers to “the curl one-liner” without showing or linking it, while the WSL steps below only document the npm path. Include the actual Linux installer command here (or link to it) so users can follow the documented standalone path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At docs/docs/reference/windows-wsl.md, line 25:

<comment>This sentence refers to “the curl one-liner” without showing or linking it, while the WSL steps below only document the npm path. Include the actual Linux installer command here (or link to it) so users can follow the documented standalone path.</comment>

<file context>
@@ -19,7 +19,10 @@ powershell -c "irm https://www.altimate.sh/install.ps1 | iex"
+directory to your user PATH (open a new terminal afterwards). It also writes an
+`altimate-code` alias there: `altimate-code.cmd` for cmd.exe and PowerShell, and
+an extensionless shim for Git Bash. Inside WSL, install the Linux build with the
+curl one-liner; the Windows shim refuses to run there. The installer
 auto-detects AVX2 support and falls back to the baseline build on older CPUs.
 
</file context>
Suggested change
curl one-liner; the Windows shim refuses to run there. The installer
curl one-liner (`curl -fsSL https://www.altimate.sh/install | bash`); the Windows shim refuses to run there. The installer

auto-detects AVX2 support and falls back to the baseline build on older CPUs.

Options (pass via a script block):
Expand Down
85 changes: 77 additions & 8 deletions install
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ check_version() {
# treat an empty==empty as "already installed" — fall through and reinstall.
if [ -n "$specific_version" ] && [[ "$installed_version" == "$specific_version" ]]; then
print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed${NC}"
# A standalone install from before the alias existed still gets it, but only
# when the matching binary is the one in INSTALL_DIR, so the alias never runs a
# different version than the one just checked.
# -ef compares the directories themselves, so a PATH entry spelled differently
# (a symlinked HOME, a trailing slash) still matches.
if [ "$(dirname "$(command -v "$probe")")" -ef "$INSTALL_DIR" ]; then
link_alias "$binary_name"
fi
exit 0
elif [ -n "$installed_version" ]; then
print_message info "${MUTED}Installed version: ${NC}$installed_version."
Expand Down Expand Up @@ -453,18 +461,77 @@ download_and_install() {
mv "$tmp_dir/$binary_name" "${INSTALL_DIR}/$binary_name"
chmod 755 "${INSTALL_DIR}/$binary_name"

# If the previous install dropped `altimate-code` here (pre-v0.7.1 curl
# install), remove it so users don't end up running a stale binary by
# name. The npm/Homebrew/AUR paths still expose both names; only the
# standalone $INSTALL_DIR has the rename collapse.
if [ "$os" != "windows" ] && [ -f "${INSTALL_DIR}/altimate-code" ]; then
rm -f "${INSTALL_DIR}/altimate-code"
print_message info "${MUTED}Removed stale ${NC}altimate-code${MUTED} from ${NC}$INSTALL_DIR${MUTED} (renamed to altimate in v0.7.1)${NC}"
fi
link_alias "$binary_name"

rm -rf "$tmp_dir"
}

# Expose `altimate-code` next to the installed binary, matching npm, Homebrew and
# AUR, which all ship both names. A relative symlink keeps following the binary
# across upgrades. `ln -sfn` also replaces a pre-v0.7.1 standalone `altimate-code`
# binary, so that name can never run a stale build, and replaces a link to a
# directory instead of writing into that directory. Under Git Bash, MSYS and
# Cygwin, where `ln -s` usually makes a full copy, the shims install.ps1 writes
# are written instead, so both Windows installers leave the same layout.
link_alias() {
local target="$1"
local alias_name
case "$target" in
altimate) alias_name="altimate-code" ;;
altimate.exe) alias_name="altimate-code.exe" ;;
*) return 0 ;;
esac
[ -f "${INSTALL_DIR}/$target" ] || return 0

case "$(uname -s)" in
MINGW*|MSYS*|CYGWIN*)
[ "$target" = "altimate.exe" ] && write_windows_shims

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The Bash installer drops the alias when --binary is named altimate under Git Bash/MSYS/Cygwin. install_from_binary supports both altimate and altimate.exe, but this branch only invokes the shim writer for the .exe name; handle both target names and make the generated shims invoke the actual installed target.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At install, line 488:

<comment>The Bash installer drops the alias when `--binary` is named `altimate` under Git Bash/MSYS/Cygwin. `install_from_binary` supports both `altimate` and `altimate.exe`, but this branch only invokes the shim writer for the `.exe` name; handle both target names and make the generated shims invoke the actual installed target.</comment>

<file context>
@@ -482,6 +483,13 @@ link_alias() {
 
+    case "$(uname -s)" in
+        MINGW*|MSYS*|CYGWIN*)
+            [ "$target" = "altimate.exe" ] && write_windows_shims
+            return 0
+            ;;
</file context>

return 0
;;
esac

if [ -d "${INSTALL_DIR}/$alias_name" ] && [ ! -L "${INSTALL_DIR}/$alias_name" ]; then
Comment thread
hkaltai marked this conversation as resolved.
print_message warning "${MUTED}Skipped the ${NC}$alias_name${MUTED} alias: ${NC}${INSTALL_DIR}/$alias_name${MUTED} is a directory${NC}"
return 0
fi

if ! (cd "$INSTALL_DIR" && ln -sfn "$target" "$alias_name"); then
print_message warning "${MUTED}Could not create the ${NC}$alias_name${MUTED} alias in ${NC}$INSTALL_DIR"
fi
}

# The two shims Install-Alias in install.ps1 writes, byte for byte; keep both
# copies in step. The .cmd first, and a stray altimate-code.exe (which PATHEXT
# would put in front of it, and which older Git Bash installs left as a full copy)
# goes only once it exists. The sh shim only runs under Git Bash, MSYS or Cygwin:
# WSL also sees this directory on PATH, and there it must not pass for a Linux
# install of the same version.
write_windows_shims() {
local exe="${INSTALL_DIR}/altimate-code.exe"
rm -f "$exe.old" 2>/dev/null || true
write_shim altimate-code.cmd '@echo off\r\n"%%~dp0altimate.exe" %%*\r\nexit /b %%ERRORLEVEL%%\r\n' || return 0
if [ -f "$exe" ] || [ -L "$exe" ]; then
rm -f "$exe" 2>/dev/null || mv -f "$exe" "$exe.old" 2>/dev/null ||
print_message warning "${MUTED}Could not remove ${NC}$exe${MUTED}, which shadows the altimate-code.cmd alias${NC}"
fi
write_shim altimate-code '#!/bin/sh\ncase "$(uname -s)" in\n MINGW*|MSYS*|CYGWIN*) exec "$(dirname "$0")/altimate.exe" "$@" ;;\nesac\necho "altimate-code: this is the Windows build; it runs only from Git Bash, MSYS or Cygwin" >&2\nexit 127\n' || return 0
}

# Writes printf format $2 to $INSTALL_DIR/$1 as an executable file (Cygwin keeps
# POSIX modes, so the sh shim needs the bit), replacing a file or link there
# instead of writing through it. A real directory is left alone.
write_shim() {
local path="${INSTALL_DIR}/$1"
if [ -d "$path" ] && [ ! -L "$path" ]; then
print_message warning "${MUTED}Skipped the ${NC}$1${MUTED} alias: ${NC}$path${MUTED} is a directory${NC}"
return 1
fi
if ! { rm -f "$path" && printf "$2" > "$path" && chmod 755 "$path"; } 2>/dev/null; then
print_message warning "${MUTED}Could not create the ${NC}$1${MUTED} alias in ${NC}$INSTALL_DIR"
return 1
fi
}

install_from_binary() {
# --binary may point to either altimate or altimate.exe; preserve the
# caller's basename so the installed file matches what was supplied.
Expand All @@ -479,12 +546,14 @@ install_from_binary() {
if [ -f "$dest_path" ] && [ "$binary_path" -ef "$dest_path" ]; then
print_message info "${MUTED}Source and destination are the same file — nothing to do: ${NC}$dest_path"
chmod 755 "$dest_path"
link_alias "$dest_name"
return 0
fi

print_message info "\n${MUTED}Installing ${NC}$dest_name ${MUTED}from: ${NC}$binary_path"
cp "$binary_path" "$dest_path"
chmod 755 "$dest_path"
link_alias "$dest_name"
}

# Write the same post-install marker that npm's postinstall.mjs writes, so the
Expand Down
91 changes: 89 additions & 2 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,85 @@ $InstalledBinary = Join-Path $InstallDir $BinaryName
function Write-Muted($msg) { Write-Host $msg -ForegroundColor DarkGray }
function Write-Err($msg) { Write-Host "error: $msg" -ForegroundColor Red }

# Expose `altimate-code` next to altimate.exe, matching npm, Homebrew and AUR,
# which all ship both names. Shims instead of a copy or link: they follow the
# binary across upgrades (which rename the running exe aside) and need no symlink
# privilege. cmd.exe and PowerShell resolve the .cmd; Git Bash and other MSYS
# shells only resolve the extensionless script. The bash installer writes the
# same two shims under Git Bash (write_windows_shims); keep both copies in step.
# npm also writes a .ps1 shim, left out here because an execution policy that
# blocks scripts would break the name. Like every .cmd shim, the .cmd hands its
# arguments to cmd.exe, which expands %VAR% and interprets unquoted & | < > ^;
# scripts should call `altimate`. A stray altimate-code.exe would win over the
# .cmd through PATHEXT order and could run a stale build, so it is moved out of
# the way.
#
# Best-effort: a failure here warns and never aborts the install.
function Install-Alias {
param([string]$Dir)

try {
if (-not (Test-Path -LiteralPath ([IO.Path]::Combine($Dir, "altimate.exe")) -PathType Leaf)) { return }

$shadowingExe = [IO.Path]::Combine($Dir, "altimate-code.exe")
Remove-Item -LiteralPath "$shadowingExe.old" -Force -ErrorAction SilentlyContinue

# Replaces an existing file or link instead of writing through it, so a link at the
# shim's path can never overwrite the file it points to; GetAttributes does not follow
# links, so a dangling one is caught too. The old entry is deleted before the write,
# so a failed write leaves no shim of that name. A real directory is left alone and
# the write throws into the catch.
$writeShim = {
param([string]$Name, [string]$Text)
$path = [IO.Path]::Combine($Dir, $Name)
$attrs = $null
try { $attrs = [IO.File]::GetAttributes($path) } catch {}
if ($null -ne $attrs) {
$isDir = [bool]($attrs -band [IO.FileAttributes]::Directory)
if ($isDir -and ($attrs -band [IO.FileAttributes]::ReparsePoint)) { [IO.Directory]::Delete($path) }
elseif (-not $isDir) { [IO.File]::Delete($path) }
}
[IO.File]::WriteAllText($path, $Text, [Text.Encoding]::ASCII)
}

# The .cmd first, and the exe that would shadow it goes only once it exists: if it
# cannot be written, an existing altimate-code.exe stays usable. `altimate-code
# upgrade` run through the .cmd rewrites it while cmd.exe is still reading it by byte
# offset, which is safe only while its content stays byte-identical.
& $writeShim "altimate-code.cmd" "@echo off`r`n`"%~dp0altimate.exe`" %*`r`nexit /b %ERRORLEVEL%`r`n"

if (Test-Path -LiteralPath $shadowingExe -PathType Leaf) {
try { Remove-Item -LiteralPath $shadowingExe -Force } catch {
Remove-Item -LiteralPath "$shadowingExe.old" -Force -ErrorAction SilentlyContinue
Move-Item -LiteralPath $shadowingExe -Destination "$shadowingExe.old" -Force
}
}

# Only under Git Bash, MSYS or Cygwin: WSL also sees this directory on PATH, and there
# the shim must not pass for a Linux install of the same version.
& $writeShim "altimate-code" ((@(
'#!/bin/sh'
'case "$(uname -s)" in'
' MINGW*|MSYS*|CYGWIN*) exec "$(dirname "$0")/altimate.exe" "$@" ;;'
'esac'
'echo "altimate-code: this is the Windows build; it runs only from Git Bash, MSYS or Cygwin" >&2'
'exit 127'
) -join "`n") + "`n")
} catch {
Write-Muted "Could not create the altimate-code alias in ${Dir}: $($_.Exception.Message)"
}
}

# Whether $Path names a file directly in $Dir. Compared as full paths, ignoring case and
# a trailing separator, since a PATH entry can spell the directory differently.
function Test-PathInDir {
param([string]$Path, [string]$Dir)

$separators = [char[]]@('\', '/')
$parent = [IO.Path]::GetDirectoryName([IO.Path]::GetFullPath($Path)).TrimEnd($separators)
return $parent -eq [IO.Path]::GetFullPath($Dir).TrimEnd($separators)
}

function Show-Usage {
Write-Host @"
Altimate Code Installer (Windows)
Expand Down Expand Up @@ -198,8 +277,8 @@ if ([string]::IsNullOrWhiteSpace($Version)) {
# ---------------------------------------------------------------------------
# Skip if the requested version is already installed
# ---------------------------------------------------------------------------
# Probe both names: the standalone install ships `altimate`, but an npm install
# also exposes the `altimate-code` alias.
# Probe both names: either can be the only one on PATH (a standalone install from
# before the `altimate-code` shims, or a package manager that exposes one name).
$probe = $null
foreach ($name in @("altimate", "altimate-code")) {
$cmd = Get-Command $name -ErrorAction SilentlyContinue
Expand All @@ -210,6 +289,12 @@ if ($probe) {
try { $installedVersion = (& $probe --version 2>$null | Select-Object -First 1).ToString().Trim() } catch {}
if ($installedVersion -eq $specificVersion) {
Write-Muted "Version $specificVersion already installed"
# A standalone install from before the alias existed still gets it, but only when
# the matching binary is the one in $InstallDir, so the alias never runs a different
# version than the one just checked.
if (Test-PathInDir -Path $probe -Dir $InstallDir) {
Install-Alias -Dir $InstallDir
}
exit 0
} elseif ($installedVersion) {
Write-Muted "Installed version: $installedVersion."
Expand Down Expand Up @@ -304,6 +389,8 @@ if (-not $needsBaseline) {
}
}

Install-Alias -Dir $InstallDir

# ---------------------------------------------------------------------------
# Post-install marker (install telemetry)
# ---------------------------------------------------------------------------
Expand Down
Loading
Loading