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
13 changes: 12 additions & 1 deletion INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@

The installer downloads Autter into `~/.autter/bin`, adds it to your user `PATH`, configures supported coding agents and editors, and starts the background service. On macOS, Linux, and WSL it then starts onboarding when the shell is interactive. Automated or non-interactive installs can finish onboarding later.

### System requirements

- **git** 2.22 or newer (required)
- **Linux**: glibc 2.35 or newer (Ubuntu 22.04+, Debian 12+, Fedora 36+). Ubuntu 20.04 and older WSL2 distros are not supported natively — use a newer WSL distro or run inside an `ubuntu:22.04` Docker container

Check notice on line 43 in INSTALL.md

View check run for this annotation

Autter.dev / autter/review-gate

🟡 Low · markdownlint: MD013

Line length: Expected: 80; Actual: 210 Suggested fix: Fix the markdownlint `MD013` issue at INSTALL.md:43: Line length: Expected: 80; Actual: 210

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 210

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at INSTALL.md:43: Line length: Expected: 80; Actual: 210

Flagged by Autter security & observability checks.

- **macOS**: 11 (Big Sur) or newer
- **Windows**: 10 or newer
- **npm path**: Node.js 18+

On macOS, Linux, and WSL, make `autter` available in the terminal you already have open (the installer prints this command at the end too):

```bash
Expand All @@ -47,9 +55,12 @@

```bash
autter --version
autter debug
autter doctor # v1.6.10+ — focused setup validation (exits 1 on failure)
autter debug # full support dump (always exits 0)
```

`autter doctor` runs end-to-end checks (git proxy, hooks, checkpoint round-trip). On v1.6.9 and earlier, use `autter debug` instead.

Check notice on line 62 in INSTALL.md

View check run for this annotation

Autter.dev / autter/review-gate

🟡 Low · markdownlint: MD013

Line length: Expected: 80; Actual: 132 Suggested fix: Fix the markdownlint `MD013` issue at INSTALL.md:62: Line length: Expected: 80; Actual: 132

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 132

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at INSTALL.md:62: Line length: Expected: 80; Actual: 132

Flagged by Autter security & observability checks.


You do not need to configure each repository separately. Continue using Git, your IDE, and your coding agents as usual.

> Using Nix? See the [Nix installation guide](README-nix.md) for NixOS, nix-darwin, and Home Manager options.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@

The npm package is a thin bootstrapper: it downloads the same release binary into `~/.autter/bin` and verifies its checksum, so hooks and self-updates work identically to the script installs.

**System requirements:** git 2.22+, Linux glibc 2.35+ (Ubuntu 22.04+), macOS 11+, Windows 10+, Node.js 18+ for the npm path. See [INSTALL.md](INSTALL.md) for details including Docker-based setup on older Linux distros.

Check notice on line 57 in README.md

View check run for this annotation

Autter.dev / autter/review-gate

🟡 Low · markdownlint: MD013

Line length: Expected: 80; Actual: 218 Suggested fix: Fix the markdownlint `MD013` issue at README.md:57: Line length: Expected: 80; Actual: 218

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 [deterministic] markdownlint: MD013 — Risk: 30/100

Line length: Expected: 80; Actual: 218

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the markdownlint `MD013` issue at README.md:57: Line length: Expected: 80; Actual: 218

Flagged by Autter security & observability checks.


> **Git Bash is not WSL.** The bash installer needs a real Linux environment, so on Windows it only runs inside [WSL](https://learn.microsoft.com/windows/wsl/about) — in Git Bash it exits with instructions. Use the Windows command instead (it works from Git Bash too), and install the CLI where your coding agents actually run: agents launched from Windows need the native install, agents inside WSL need the WSL install.

Signed in to Autter? [**Settings → CLI setup**](https://app.autter.dev/cli/install) in the dashboard generates a single-use command that runs this same installer **and signs the machine in automatically** via a short-lived signed token — no separate login step.
Expand Down
24 changes: 24 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,16 @@
}
$os = 'windows'

# git is required — autter wraps git and cannot function without it.

Check warning on line 338 in install.ps1

View check run for this annotation

Autter.dev / autter/review-gate

🟠 Medium · Missing CODEOWNERS reviewer approval

The Windows installer now fails early on missing git and verifies the downloaded executable before success, but there is no CODEOWNERS-backed approval for this installer path. If this check is wrong, Windows users can be blocked from installing Autter or see a false success after a broken download. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: dependent files `npm/bin/autter.js`. **References:** - https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write - https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write Suggested fix: Request an approval from the responsible installer owner/team for `install.ps1`, or add CODEOWNERS rules that require the right reviewer for the Windows bootstrap path. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: dependent files `npm/bin/autter.js`.

Check warning on line 338 in install.ps1

View check run for this annotation

Autter.dev / autter/review-gate

🟠 Medium · Missing CODEOWNERS reviewer approval

The Windows installer now fails early on missing git and verifies the downloaded executable before success, but there is no CODEOWNERS-backed approval for this installer path. If this check is wrong, Windows users can be blocked from installing Autter or see a false success after a broken download. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: dependent files `npm/bin/autter.js`. **References:** - https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write - https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write Suggested fix: Request an approval from the responsible installer owner/team for `install.ps1`, or add CODEOWNERS rules that require the right reviewer for the Windows bootstrap path. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: dependent files `npm/bin/autter.js`.
try {
$null = & git --version 2>&1

Check failure on line 340 in install.ps1

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Reject old Git versions in the PowerShell installer

The PowerShell preflight treats a successful `git --version` process as sufficient and never reads or compares its version. Consequently Windows users with Git older than 2.22 proceed through download and installation as successful, despite the requirement added by this PR and the CLI's explicit statement that Git below 2.22 will not work correctly. This makes the advertised upfront validation ineffective on the Windows install path. Suggested fix: Capture and parse `git --version` in install.ps1, and invoke `Write-ErrorAndExit` when it is below 2.22.0, before any download or replacement.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] Reject old Git versions in the PowerShell installer — Risk: 72/100

The PowerShell preflight treats a successful git --version process as sufficient and never reads or compares its version. Consequently Windows users with Git older than 2.22 proceed through download and installation as successful, despite the requirement added by this PR and the CLI's explicit statement that Git below 2.22 will not work correctly. This makes the advertised upfront validation ineffective on the Windows install path.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: install.ps1, src/commands/install_hooks.rs
🛠 AI fix prompt (copy & paste into your coding agent)
Capture and parse `git --version` in install.ps1, and invoke `Write-ErrorAndExit` when it is below 2.22.0, before any download or replacement.

Flagged by Autter security & observability checks.

if ($LASTEXITCODE -ne 0) {
Write-ErrorAndExit 'git is required but not found. Install Git for Windows (https://git-scm.com/download/win) and re-run the installer.'
}
} catch {
Write-ErrorAndExit 'git is required but not found. Install Git for Windows (https://git-scm.com/download/win) and re-run the installer.'
}

# Determine binary name and download URLs
$binaryName = "autter-$os-$arch"

Expand Down Expand Up @@ -604,6 +614,20 @@
Move-Item -Force -Path $tmpFile -Destination $finalExe
try { Unblock-File -Path $finalExe -ErrorAction SilentlyContinue } catch { }

# Verify the binary runs before reporting success.
try {
$installedVersion = & $finalExe --version 2>&1 | Out-String
$installedVersion = $installedVersion.Trim()
if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($installedVersion)) {
Remove-Item -Force -ErrorAction SilentlyContinue $finalExe

Check failure on line 622 in install.ps1

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Restore the previous Windows executable on validation failure

`Move-Item -Force` overwrites the prior `autter.exe` before the new `--version` validation. When that command fails or returns blank output, both failure branches delete `$finalExe` and exit rather than rolling back. Thus an incompatible or otherwise non-runnable release removes a functioning Autter CLI; moreover, when a `git.exe` shim already exists it is not refreshed because execution stops, leaving the install directory with the old shim but no `autter.exe`. The failure is detected but the multi-step replacement is not recovered. Suggested fix: Validate the candidate file before replacing `$finalExe`, or rename the previous `$finalExe` to a backup and restore it in both validation-failure branches. Do not remove the old executable until the candidate has run successfully; update `git.exe` only after that successful commit point.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [ai] Restore the previous Windows executable on validation failure — Risk: 88/100

Move-Item -Force overwrites the prior autter.exe before the new --version validation. When that command fails or returns blank output, both failure branches delete $finalExe and exit rather than rolling back. Thus an incompatible or otherwise non-runnable release removes a functioning Autter CLI; moreover, when a git.exe shim already exists it is not refreshed because execution stops, leaving the install directory with the old shim but no autter.exe. The failure is detected but the multi-step replacement is not recovered.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: install.ps1
🛠 AI fix prompt (copy & paste into your coding agent)
Validate the candidate file before replacing `$finalExe`, or rename the previous `$finalExe` to a backup and restore it in both validation-failure branches. Do not remove the old executable until the candidate has run successfully; update `git.exe` only after that successful commit point.

Flagged by Autter security & observability checks.

Write-ErrorAndExit "The autter binary could not run on this system:`n$installedVersion"
}
Write-Host "Installed autter $installedVersion"
} catch {
Remove-Item -Force -ErrorAction SilentlyContinue $finalExe
Write-ErrorAndExit "The autter binary could not run on this system: $($_.Exception.Message)"
}

# Refresh git.exe for existing wrapper users (it's a copy, not a symlink on Windows)
$gitShim = Join-Path $installDir 'git.exe'
if (Test-Path -LiteralPath $gitShim) {
Expand Down
73 changes: 70 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,74 @@
;;
esac

# Minimum glibc for Linux release binaries (built on Ubuntu 22.04).
MIN_GLIBC_MAJOR=2
MIN_GLIBC_MINOR=35

# Require git before downloading — autter wraps git and cannot function without it.
check_git() {

Check failure on line 285 in install.sh

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Enforce the documented minimum Git version before installing

The new preflight only checks that `git` can be found, then the installer downloads, replaces, and reports success for any Git version. This accepts Git 2.21 or older even though this PR documents Git 2.22+ as a requirement and the CLI's own install-hooks path states that versions below 2.22 lack functionality Autter relies on. Thus a user with an old but executable Git gets a successful installation of a CLI that cannot operate correctly with its required trace/worktree behavior, rather than the intended upfront failure and remediation guidance. Suggested fix: Parse `git --version` in install.sh and reject versions below 2.22.0 before downloading or replacing the installed binary; retain the existing not-found error path.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] Enforce the documented minimum Git version before installing — Risk: 72/100

The new preflight only checks that git can be found, then the installer downloads, replaces, and reports success for any Git version. This accepts Git 2.21 or older even though this PR documents Git 2.22+ as a requirement and the CLI's own install-hooks path states that versions below 2.22 lack functionality Autter relies on. Thus a user with an old but executable Git gets a successful installation of a CLI that cannot operate correctly with its required trace/worktree behavior, rather than the intended upfront failure and remediation guidance.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: install.sh, src/commands/install_hooks.rs
🛠 AI fix prompt (copy & paste into your coding agent)
Parse `git --version` in install.sh and reject versions below 2.22.0 before downloading or replacing the installed binary; retain the existing not-found error path.

Flagged by Autter security & observability checks.

if ! command -v git >/dev/null 2>&1; then
error "git is required but not found. Install git 2.22 or newer, then re-run the installer."
fi
}

# Linux release binaries need glibc 2.35+ (Ubuntu 22.04). Ubuntu 20.04 / older WSL2
# distros fail at runtime with GLIBC_2.32+ symbol errors — catch that up front.
check_linux_glibc() {
if [ "$OS" != "linux" ] || [ -n "${AUTTER_LOCAL_BINARY:-}" ]; then
return 0
fi

if ! command -v ldd >/dev/null 2>&1; then
return 0
fi

local glibc_version
glibc_version=$(ldd --version 2>&1 | head -n1 | grep -oE '[0-9]+\.[0-9]+' | head -n1)
if [ -z "$glibc_version" ]; then
return 0
fi

local major minor
major=${glibc_version%%.*}
minor=${glibc_version#*.}

if [ "$major" -lt "$MIN_GLIBC_MAJOR" ] \
|| { [ "$major" -eq "$MIN_GLIBC_MAJOR" ] && [ "$minor" -lt "$MIN_GLIBC_MINOR" ]; }; then
error "Unsupported glibc version ($glibc_version). autter requires glibc ${MIN_GLIBC_MAJOR}.${MIN_GLIBC_MINOR} or newer (Ubuntu 22.04+, Debian 12+, Fedora 36+).

On Ubuntu 20.04 or older WSL2 distros, use a newer base image or run inside Docker:
docker run -it --rm -v \"\$PWD\":/work -w /work ubuntu:22.04 bash
# then re-run this installer inside the container"
fi
}

# Fail the install when the downloaded binary cannot execute (glibc mismatch, etc.).
verify_binary_runs() {
local bin="$1"
local output
if output=$("$bin" --version 2>&1); then
printf '%s' "$output"
return 0
fi

rm -f "$bin" 2>/dev/null || true
if [ "$OS" = "linux" ] && printf '%s' "$output" | grep -q 'GLIBC_'; then
error "The autter binary could not run on this system (incompatible glibc).

$output

autter requires glibc ${MIN_GLIBC_MAJOR}.${MIN_GLIBC_MINOR} or newer (Ubuntu 22.04+). On Ubuntu 20.04 / older WSL2, switch to a newer distro or use Docker:
docker run -it --rm -v \"\$PWD\":/work -w /work ubuntu:22.04 bash"
fi
error "The autter binary could not run on this system:

$output"
}

check_git
check_linux_glibc

# Map OS to binary name
case $OS in
"darwin")
Expand Down Expand Up @@ -459,11 +527,10 @@
warn "Failed to create ~/.local/bin/autter symlink. This is non-fatal."
fi

# Verify the binary runs before reporting success (catches glibc mismatches, etc.).
INSTALLED_VERSION=$(verify_binary_runs "${INSTALL_DIR}/autter")

Check failure on line 531 in install.sh

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Preserve the prior CLI when runtime validation fails

The installer atomically replaces `~/.autter/bin/autter` before running the new executable. If `--version` then fails (for example, an OS/CPU loader incompatibility not identified by the glibc preflight, a corrupt local-binary override, or a quarantine/signing failure), `verify_binary_runs` deletes that newly installed path and exits. This also removes the only prior working CLI and leaves the existing `~/.local/bin/autter` symlink dangling, so a failed upgrade converts a usable installation into a broken one. Validation needs to happen on the temporary artifact, or the displaced binary must be retained and restored on failure. Suggested fix: Before replacing the installed executable, validate the downloaded temporary artifact (including executable mode) or move the existing executable to a backup. If validation fails, remove only the candidate and restore the backup; only update the installed path and symlinks after successful validation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [ai] Preserve the prior CLI when runtime validation fails — Risk: 88/100

The installer atomically replaces ~/.autter/bin/autter before running the new executable. If --version then fails (for example, an OS/CPU loader incompatibility not identified by the glibc preflight, a corrupt local-binary override, or a quarantine/signing failure), verify_binary_runs deletes that newly installed path and exits. This also removes the only prior working CLI and leaves the existing ~/.local/bin/autter symlink dangling, so a failed upgrade converts a usable installation into a broken one. Validation needs to happen on the temporary artifact, or the displaced binary must be retained and restored on failure.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: install.sh
🛠 AI fix prompt (copy & paste into your coding agent)
Before replacing the installed executable, validate the downloaded temporary artifact (including executable mode) or move the existing executable to a backup. If validation fails, remove only the candidate and restore the backup; only update the installed path and symlinks after successful validation.

Flagged by Autter security & observability checks.

success "Successfully installed autter into ${INSTALL_DIR}"
success "You can now run 'autter' from your terminal"

# Print installed version
INSTALLED_VERSION=$(${INSTALL_DIR}/autter --version 2>&1 || echo "unknown")
echo "Installed autter ${INSTALLED_VERSION}"

# Login user with install token if provided
Expand Down
61 changes: 61 additions & 0 deletions npm/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,57 @@
}
}

function checkGit() {
try {
execFileSync('git', ['--version'], { encoding: 'utf8', timeout: 10_000, stdio: 'pipe' });

Check failure on line 106 in npm/install.js

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Git prerequisite check does not enforce the minimum supported version

`checkGit()` runs `git --version` but does not parse its output or reject versions older than the documented Git 2.22 minimum. A runnable unsupported Git installation therefore passes the installer prerequisite check. Parse the reported version and emit the existing actionable install message when it is below 2.22. Suggested fix: Either parse the reported version and compare it against the required minimum, or make the prerequisite check consistent with the rest of the installer by failing fast when the detected version is below 2.22.

Check failure on line 106 in npm/install.js

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Git prerequisite check does not enforce the minimum supported version

`checkGit()` runs `git --version` but does not parse its output or reject versions older than the documented Git 2.22 minimum. A runnable unsupported Git installation therefore passes the installer prerequisite check. Parse the reported version and emit the existing actionable install message when it is below 2.22. Suggested fix: Either parse the reported version and compare it against the required minimum, or make the prerequisite check consistent with the rest of the installer by failing fast when the detected version is below 2.22.

Check failure on line 106 in npm/install.js

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Make the npm Git preflight validate the minimum version

`checkGit` only verifies that the `git --version` command exits successfully; its output is discarded. `main` relies on that check as its new up-front gate, so npm installation continues for Git 2.21 or older and can install a binary that the CLI later identifies as incompatible with required functionality. This is reachable both during postinstall and through the launcher fallback, because `ensureBinary` itself has no Git-version gate. Suggested fix: Have `checkGit` parse the output from `git --version` and throw unless the version is at least 2.22.0. Apply the check to the launcher fallback as well, or put it in `ensureBinary`, so skipped postinstall cannot bypass it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] Git prerequisite check does not enforce the minimum supported version — Risk: 74/100

checkGit() runs git --version but does not parse its output or reject versions older than the documented Git 2.22 minimum. A runnable unsupported Git installation therefore passes the installer prerequisite check. Parse the reported version and emit the existing actionable install message when it is below 2.22.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Functions/symbols: fetchBuffer, ensureBinary, verifyChecksum, reportInstallPing, binaryDest, installDir
  • Dependent files: npm/bin/autter.js, node:crypto, node:fs, node:os, node:path, node:child_process, npm/package.json
  • Scopes: @autter/cli
🛠 AI fix prompt (copy & paste into your coding agent)
Either parse the reported version and compare it against the required minimum, or make the prerequisite check consistent with the rest of the installer by failing fast when the detected version is below 2.22.

Flagged by Autter security & observability checks.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [ai] Make the npm Git preflight validate the minimum version — Risk: 72/100

checkGit only verifies that the git --version command exits successfully; its output is discarded. main relies on that check as its new up-front gate, so npm installation continues for Git 2.21 or older and can install a binary that the CLI later identifies as incompatible with required functionality. This is reachable both during postinstall and through the launcher fallback, because ensureBinary itself has no Git-version gate.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: npm/install.js, npm/bin/autter.js, src/commands/install_hooks.rs
🛠 AI fix prompt (copy & paste into your coding agent)
Have `checkGit` parse the output from `git --version` and throw unless the version is at least 2.22.0. Apply the check to the launcher fallback as well, or put it in `ensureBinary`, so skipped postinstall cannot bypass it.

Flagged by Autter security & observability checks.

} catch {
throw new Error(
'git is required but not found. Install git 2.22 or newer, then re-run: npm install -g @autter/cli'
);
}
}

function checkLinuxGlibc() {
if (process.platform !== 'linux') return;
try {
const out = execFileSync('ldd', ['--version'], { encoding: 'utf8', timeout: 10_000 });
const match = out.match(/(\d+)\.(\d+)/);
if (!match) return;
const major = Number(match[1]);
const minor = Number(match[2]);
if (major < 2 || (major === 2 && minor < 35)) {
throw new Error(
`Unsupported glibc version (${major}.${minor}). autter requires glibc 2.35+ (Ubuntu 22.04+, Debian 12+, Fedora 36+). ` +

Check warning on line 124 in npm/install.js

View check run for this annotation

Autter.dev / autter/review-gate

🟠 Medium · Biome: lint/style/useTemplate

Template literals are preferred over string concatenation. Suggested fix: Fix the Biome `lint/style/useTemplate` issue at npm/install.js:124: Template literals are preferred over string concatenation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/useTemplate — Risk: 55/100

Template literals are preferred over string concatenation.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useTemplate` issue at npm/install.js:124: Template literals are preferred over string concatenation.

Flagged by Autter security & observability checks.

'On Ubuntu 20.04 / older WSL2, use a newer distro or run inside ubuntu:22.04 Docker.'
);
}
} catch (err) {
if (err.message?.includes('Unsupported glibc')) throw err;
// ldd missing — rely on post-download binary verify
}
}

function verifyBinaryRuns(bin) {
try {
const out = execFileSync(bin, ['--version'], { encoding: 'utf8', timeout: 10_000 });
return out.trim().split(/\s+/)[0] || null;
} catch (err) {
const detail = err.stderr?.toString() || err.stdout?.toString() || err.message || String(err);
try {
fs.rmSync(bin, { force: true });
} catch {
// best effort
}
if (process.platform === 'linux' && detail.includes('GLIBC')) {
throw new Error(
`The autter binary could not run on this system (incompatible glibc).\n${detail}\n\n` +

Check warning on line 147 in npm/install.js

View check run for this annotation

Autter.dev / autter/review-gate

🟠 Medium · Biome: lint/style/useTemplate

Template literals are preferred over string concatenation. Suggested fix: Fix the Biome `lint/style/useTemplate` issue at npm/install.js:147: Template literals are preferred over string concatenation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [deterministic] Biome: lint/style/useTemplate — Risk: 55/100

Template literals are preferred over string concatenation.

🛠 AI fix prompt (copy & paste into your coding agent)
Fix the Biome `lint/style/useTemplate` issue at npm/install.js:147: Template literals are preferred over string concatenation.

Flagged by Autter security & observability checks.

'autter requires glibc 2.35+ (Ubuntu 22.04+). On Ubuntu 20.04 / older WSL2, use a newer distro or Docker.'
);
}
throw new Error(`The autter binary could not run on this system: ${detail}`);
}
}

// `autter --version` prints the bare version ("1.6.8", or "1.6.8 (debug)").
function installedVersion(bin) {
try {
Expand Down Expand Up @@ -188,6 +239,8 @@
}
}

verifyBinaryRuns(dest);

Check failure on line 242 in npm/install.js

View check run for this annotation

Autter.dev / autter/review-gate

🔴 High · Do not delete the installed npm binary after a failed upgrade check

`ensureBinary` replaces `dest` before invoking the new runtime check. On validation failure, `verifyBinaryRuns` unconditionally removes `bin`, then throws; `main` deliberately catches that error to keep `npm install` successful and tells the user that first run will retry. A prior working CLI has nevertheless been deleted. The npm launcher sees the missing file and attempts a network download on every invocation, so an offline user cannot run the previously installed version. The Windows rename fallback has the same destructive window: it removes `dest` before the replacement rename and does not restore it if that rename fails. Suggested fix: Keep the old destination until a candidate has passed `--version`: validate a temporary executable before renaming, or retain and restore a backup when validation/replacement fails. In the Windows fallback, restore the old destination if the second rename fails. Only report success/defer-to-first-run after preserving a usable prior binary.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 [ai] Do not delete the installed npm binary after a failed upgrade check — Risk: 86/100

ensureBinary replaces dest before invoking the new runtime check. On validation failure, verifyBinaryRuns unconditionally removes bin, then throws; main deliberately catches that error to keep npm install successful and tells the user that first run will retry. A prior working CLI has nevertheless been deleted. The npm launcher sees the missing file and attempts a network download on every invocation, so an offline user cannot run the previously installed version. The Windows rename fallback has the same destructive window: it removes dest before the replacement rename and does not restore it if that rename fails.

⚠ Downstream affected — if this fails, it cascades to the usage that depends on this file:

  • Dependent files: npm/install.js, npm/bin/autter.js
🛠 AI fix prompt (copy & paste into your coding agent)
Keep the old destination until a candidate has passed `--version`: validate a temporary executable before renaming, or retain and restore a backup when validation/replacement fails. In the Windows fallback, restore the old destination if the second rename fails. Only report success/defer-to-first-run after preserving a usable prior binary.

Flagged by Autter security & observability checks.


await reportInstallPing(tag);
return { bin: dest, downloaded: true };
}
Expand All @@ -200,6 +253,14 @@
return;
}

try {
checkGit();
checkLinuxGlibc();
} catch (err) {
console.warn(`autter: ${err.message}`);
return;
}

let result;
try {
result = await ensureBinary();
Expand Down
57 changes: 47 additions & 10 deletions src/commands/install_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,8 @@

let installers = get_all_installers();
let mut installed_tools: HashSet<String> = HashSet::new();
// Track agents whose hooks were updated (name, process_names) for restart warnings
let mut updated_agents: Vec<(String, Vec<String>)> = Vec::new();
// Track agents whose hooks were checked (updated or already up to date) for restart warnings
let mut agents_for_restart: Vec<(String, Vec<String>)> = Vec::new();
let mut not_detected: Vec<&str> = Vec::new();

for installer in &installers {
Expand Down Expand Up @@ -541,7 +541,7 @@
.map(|s| s.to_string())
.collect();
if !pnames.is_empty() {
updated_agents.push((name.to_string(), pnames));
agents_for_restart.push((name.to_string(), pnames));
}
}
}
Expand All @@ -552,6 +552,21 @@
statuses.insert(id.to_string(), InstallStatus::AlreadyInstalled);
detailed_results
.push((id.to_string(), InstallResult::already_installed()));

// Hooks may be up to date on disk but the agent still needs a

Check warning on line 556 in src/commands/install_hooks.rs

View check run for this annotation

Autter.dev / autter/review-gate

🟠 Medium · Missing CODEOWNERS reviewer approval

`install_hooks` now changes restart-warning behavior for already up-to-date hooks via `agents_for_restart`, which affects how users learn that Gemini/other agents must be restarted after hook setup. Without a CODEOWNERS approval, a regression here can leave agents running stale hook state and attribution will not take effect. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions `as_str`, `parse_git_version`, `warn_if_git_version_too_old`, `parse_git_version_no_patch`, `parse_git_version_standard`, `parse_git_version_apple_suffix`; dependent files `npm/bin/autter.js`, `crate::commands::arg_parser::{paint, paint_err}`, `crate::config`, `crate::daemon::DaemonConfig`, `crate::error::AutterError`, `crate::mdm::agents::get_all_installers`, `crate::mdm::hook_installer::HookInstallerParams`, `crate::mdm::skills_installer`. **References:** - https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write - https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write Suggested fix: Add the required approving review for the owner of `src/commands/install_hooks.rs` (or define CODEOWNERS so this path is covered) before merging. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions `as_str`, `parse_git_version`, `warn_if_git_version_too_old`, `parse_git_version_no_patch`, `parse_git_version_standard`, `parse_git_version_apple_suffix`; dependent files `npm/bin/autter.js`, `crate::commands::arg_parser::{paint, paint_err}`, `crate::config`, `crate::daemon::DaemonConfig`, `crate::error::AutterError`, `crate::mdm::agents::get_all_installers`, `crate::mdm::hook_installer::HookInstallerParams`, `crate::mdm::skills_installer`.

Check warning on line 556 in src/commands/install_hooks.rs

View check run for this annotation

Autter.dev / autter/review-gate

🟠 Medium · Missing CODEOWNERS reviewer approval

`install_hooks` now changes restart-warning behavior for already up-to-date hooks via `agents_for_restart`, which affects how users learn that Gemini/other agents must be restarted after hook setup. Without a CODEOWNERS approval, a regression here can leave agents running stale hook state and attribution will not take effect. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions `as_str`, `parse_git_version`, `warn_if_git_version_too_old`, `parse_git_version_no_patch`, `parse_git_version_standard`, `parse_git_version_apple_suffix`; dependent files `npm/bin/autter.js`, `crate::commands::arg_parser::{paint, paint_err}`, `crate::config`, `crate::daemon::DaemonConfig`, `crate::error::AutterError`, `crate::mdm::agents::get_all_installers`, `crate::mdm::hook_installer::HookInstallerParams`, `crate::mdm::skills_installer`. **References:** - https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write - https://docs.github.com/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners — # About code owners You can use a CODEOWNERS file to define individuals or teams that are responsible for code in a repository. The people you choose as code owners must have write Suggested fix: Add the required approving review for the owner of `src/commands/install_hooks.rs` (or define CODEOWNERS so this path is covered) before merging. Blast radius — skipping this guardrail cascades to the downstream usage that depends on this file: functions `as_str`, `parse_git_version`, `warn_if_git_version_too_old`, `parse_git_version_no_patch`, `parse_git_version_standard`, `parse_git_version_apple_suffix`; dependent files `npm/bin/autter.js`, `crate::commands::arg_parser::{paint, paint_err}`, `crate::config`, `crate::daemon::DaemonConfig`, `crate::error::AutterError`, `crate::mdm::agents::get_all_installers`, `crate::mdm::hook_installer::HookInstallerParams`, `crate::mdm::skills_installer`.
// restart to load them — track for the restart warning below.
if !options.dry_run {
let pnames: Vec<String> = installer
.process_names()
.iter()
.map(|s| s.to_string())
.collect();
if !pnames.is_empty()
&& !agents_for_restart.iter().any(|(n, _)| n == name)
{
agents_for_restart.push((name.to_string(), pnames));
}
}
}
Err(e) => {
let error_msg = e.to_string();
Expand Down Expand Up @@ -614,15 +629,15 @@
// Track restart detection for extras-only agents (e.g. JetBrains, VS Code)
if extras_changed
&& !options.dry_run
&& !updated_agents.iter().any(|(n, _)| n == name)
&& !agents_for_restart.iter().any(|(n, _)| n == name)
{
let pnames: Vec<String> = installer
.process_names()
.iter()
.map(|s| s.to_string())
.collect();
if !pnames.is_empty() {
updated_agents.push((name.to_string(), pnames));
agents_for_restart.push((name.to_string(), pnames));
}
}
}
Expand Down Expand Up @@ -683,11 +698,12 @@
println!("{}", paint("1", " autter install-hooks --dry-run=false"));
}

// Check for running agents that had hooks updated and warn about restart
if !options.dry_run && !updated_agents.is_empty() {
// Warn when agents that use hooks are running — they must be restarted for
// attribution to take effect, including when hooks were already up to date.
if !options.dry_run && !agents_for_restart.is_empty() {
let mut any_running = false;

for (agent_name, pnames) in &updated_agents {
for (agent_name, pnames) in &agents_for_restart {
let refs: Vec<&str> = pnames.iter().map(|s| s.as_str()).collect();
let pids = find_running_pids(&refs);
if !pids.is_empty() {
Expand Down Expand Up @@ -726,7 +742,16 @@
"This is expected — once you commit and start a fresh session, attribution will work correctly."
);
println!(
"If the issue persists, please open an issue at https://github.com/autter-dev/autter-cli/issues"
"If the issue persists, run 'autter doctor' (or 'autter debug' on older versions)."
);
} else if !agents_for_restart.is_empty() {
println!();
println!(
"{}",
paint(
"33",
"If any coding agent was open during hook setup, restart it now for AI attribution to take effect."
)
);
}
}
Expand Down Expand Up @@ -772,7 +797,19 @@
let text = String::from_utf8_lossy(&o.stdout).into_owned();
parse_git_version(&text)
}
Err(_) => None,
Err(_) => {
eprintln!();
eprintln!(
"{}",
paint_err(
"1;31",
"WARNING: git not found — autter requires git to function."
)
);
eprintln!("Install git 2.22+ and re-run: autter install-hooks");
eprintln!();
return;
}
};

if let Some(v) = version {
Expand Down
Loading
Loading