Skip to content

fix(cli): rebuild on stale dist, not just SHA advance, in ao update#2058

Open
suraj-markup wants to merge 4 commits into
AgentWrapper:mainfrom
suraj-markup:fix/ao-update-rebuild-staleness
Open

fix(cli): rebuild on stale dist, not just SHA advance, in ao update#2058
suraj-markup wants to merge 4 commits into
AgentWrapper:mainfrom
suraj-markup:fix/ao-update-rebuild-staleness

Conversation

@suraj-markup
Copy link
Copy Markdown
Contributor

What

ao update (git / source installs) only rebuilt when git fetch advanced the local SHA. If dist/ was out of sync with src/ at the same commit, the script printed Already on latest version and skipped the rebuild — so the running binary kept executing stale compiled code.

Causes of a stale dist/ at HEAD:

  • a manual git pull before ao update (HEAD already matches remote → no rebuild)
  • a branch switch
  • an interrupted previous build (SHA advanced but build never finished; re-run sees matching SHA → no rebuild)
  • a manual pnpm clean

Closes #2057.

How

Gate the rebuild on whether the compiled output is in sync with HEAD, not on the SHA advancing:

  • A gitignored marker node_modules/.ao-build-sha records the commit dist/ was last built from, written only after a fully successful build + launcher refresh.
  • Rebuild when: the marker ≠ HEAD, the build output is missing (catches a wiped dist/), or --force-rebuild is passed.
  • New flag ao update --force-rebuild forces a rebuild on demand.

Mirrored in the PowerShell port (ao-update.ps1) and wired through update.ts (rejected on non-git installs, like the other build-only flags).

Tests

  • Updated the "already latest" test to require a fresh build (sentinel + marker) before skipping the rebuild.
  • Added coverage: rebuild on stale marker at matching SHA, and rebuild on --force-rebuild when the build is already fresh.
  • Full ao-cli update suite green (192 passed, 4 Windows-only skipped); prettier + typecheck clean.

🤖 Generated with Claude Code

`ao update` only rebuilt when `git fetch` advanced the local SHA. If dist
fell out of sync with src at the *same* commit — a manual `git pull`, a
branch switch, an interrupted earlier build, or a manual `pnpm clean` —
the script printed "Already on latest version" and skipped the rebuild,
leaving the running binary built from stale source.

Gate the rebuild on whether the compiled output is actually in sync with
HEAD instead. A gitignored `node_modules/.ao-build-sha` marker records the
commit dist was last built from (written only after a fully successful
build + launcher refresh), and a build-output existence check catches a
wiped dist even when the marker still matches. Add `ao update
--force-rebuild` to rebuild on demand.

Mirrored in the PowerShell port and wired through update.ts (rejected on
non-git installs, like the other build-only flags). Updates the
already-latest test to require a fresh build and adds stale-marker and
--force-rebuild coverage.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 25, 2026

Greptile Summary

This PR fixes ao update (git/source installs) to rebuild whenever the compiled output is stale relative to HEAD, rather than only when git fetch advances the SHA. A gitignored marker file (node_modules/.ao-build-sha) records the commit dist/ was last successfully built from, and a new --force-rebuild flag provides an on-demand escape hatch.

  • Shell script (ao-update.sh) and PowerShell port (ao-update.ps1): refactored the SHA-advance gate into a three-condition rebuild check (force flag, missing sentinels, stale marker), writing the marker only after a fully successful build+link+clean-tree sequence.
  • update.ts: wires up --force-rebuild as a new Commander option, correctly rejects it on non-git installs, and passes it through to the underlying script args.
  • GitHub Actions workflows: all action references are pinned to full commit SHAs (replacing @v4 / @v3 tags), tightening supply-chain security.
  • Tests: the "already latest" case is updated to require a fresh sentinel+marker; three new test cases cover fresh-build skip, stale-marker rebuild, and --force-rebuild.

Confidence Score: 5/5

Safe to merge — the rebuild-gate logic is correct in both the bash and PowerShell scripts, cross-platform marker reads/writes interoperate correctly, and the new flag is properly validated and plumbed through the TypeScript command layer.

The change is well-scoped: it replaces a single SHA-advance condition with a three-condition check, writes the marker only after a fully successful build+link+clean sequence, and the PowerShell port mirrors the bash changes faithfully. Bash command substitution correctly strips trailing newlines so SHA comparisons are reliable; the PowerShell .Trim() handles both LF and no-newline variants. The new tests cover the key new scenarios and all existing tests continue to pass per the PR description.

No files require special attention.

Important Files Changed

Filename Overview
packages/cli/src/assets/scripts/ao-update.sh Adds BUILD_SHA_FILE marker, 28-path sentinel array, rebuild-decision logic, and write_built_sha (called only after fully successful build). Logic is correct: bash command substitution strips trailing newlines so SHA comparisons are safe, and all_build_outputs_present
packages/cli/src/assets/scripts/ao-update.ps1 PowerShell port mirrors the bash changes: adds $ForceRebuild flag, Read-BuiltSha/Write-BuiltSha helpers, Get-MissingBuildOutput, and the same three-condition rebuild gate. Cross-reads are handled correctly in both directions.
packages/cli/src/commands/update.ts Adds --force-rebuild Commander option, correctly rejects it for non-git installs alongside --skip-smoke and --smoke-only, extends handleGitUpdate opts type, and pushes the flag into the script args array.
packages/cli/tests/scripts/update-script.test.ts Existing process.platform === 'win32' inline checks replaced with isWindows() (cross-platform guide compliant). Three new tests cover: fresh-build skip, stale-marker rebuild, and --force-rebuild override.
.github/workflows/ci.yml All action references pinned to full commit SHAs, eliminating mutable tag risk. No functional workflow changes.
.changeset/ao-update-rebuild-staleness.md Correct patch-level changeset for @aoagents/ao-cli describing the staleness fix accurately.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ao update invoked] -->|non-git install + flag| B[Error: flag only applies to git installs]
    A -->|git install| C[git fetch origin main]
    C --> D{local SHA == remote SHA?}
    D -->|No| E[git pull --ff-only\nupdate local_sha]
    D -->|Yes| F[Skip pull]
    E --> G
    F --> G[Read node_modules/.ao-build-sha]
    G --> H{--force-rebuild?}
    H -->|Yes| I[rebuild_reason = forced via --force-rebuild]
    H -->|No| J{Any sentinel\nmissing?}
    J -->|Yes| K[rebuild_reason = build output missing]
    J -->|No| L{built_sha == local_sha?}
    L -->|No| M[rebuild_reason = build is stale]
    L -->|Yes| N[Already on latest version;\nbuild is up to date]
    I --> O[pnpm install + clean + build\nnpm link --force]
    K --> O
    M --> O
    O --> P[ensure_repo_clean]
    P -->|clean| Q[write_built_sha HEAD]
    P -->|dirty| R[Error: update modified tracked files]
    Q --> S[Run smoke tests]
    N --> S
Loading

Reviews (3): Last reviewed commit: "Address ao update script review nits" | Re-trigger Greptile

Comment thread packages/cli/__tests__/scripts/update-script.test.ts Outdated
Comment thread packages/cli/__tests__/scripts/update-script.test.ts
Comment thread packages/cli/src/assets/scripts/ao-update.sh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ao update skips rebuild when dist is stale at the current commit

3 participants