LangENKO

`mandu upgrade`

Self-updater for both the npm-installed `@mandujs/*` packages and the standalone compile-binary builds. SHA-256 verified, atomic swap, `--rollback` capable.

since v0.25
On this page

mandu upgrade

Self-updater for both the npm-installed @mandujs/* packages and the standalone compile-binary builds. Auto-detects which mode to use based on how the CLI was launched.

mandu upgrade                 # package mode: bun update @mandujs/*
mandu upgrade --check         # show installed vs latest (no install)
mandu upgrade                 # binary mode: self-update (when invoked as compile-binary)
mandu upgrade --dry-run       # download + verify; skip the swap
mandu upgrade --rollback      # restore the previously-replaced binary
mandu upgrade --channel=canary  # use pre-release tags

Package mode vs binary mode

The CLI auto-detects which mode to use:

Invocation Mode Action
bun run mandu / bunx @mandujs/cli Package bun update @mandujs/*
./mandu.exe / ./mandu-bun-linux-x64 Binary Download + verify + swap

Package mode

# Upgrade every @mandujs/* package pinned in package.json
mandu upgrade

# Check without installing
mandu upgrade --check

The list of packages is derived from your package.json dependencies — only packages starting with @mandujs/ are touched. Nothing else in your lockfile changes.

Binary mode

# Download the latest release matching your platform
mandu upgrade

# Use the canary channel (pre-release tags)
mandu upgrade --channel=canary

# Preview (download + verify, skip the swap)
mandu upgrade --dry-run

# Restore the previous binary after a regression
mandu upgrade --rollback

Binary integrity

Every GitHub Release ships a SHA256SUMS.txt sidecar generated by the release-binaries.yml workflow. mandu upgrade:

  1. Fetches the release metadata and sidecar.
  2. Downloads the platform-appropriate binary (mandu-bun-linux-x64, mandu-bun-darwin-arm64, mandu.exe, etc.).
  3. Computes the SHA-256 of the downloaded file.
  4. Compares against the entry in SHA256SUMS.txt.
  5. Refuses to swap if the hashes diverge — exits with code 1.

Phase 11.A SLSA Build L2 provenance is attached to every artifact via actions/attest-build-provenance. For the strongest check:

# Before invoking `mandu upgrade`, verify the attestation
gh attestation verify mandu-bun-linux-x64 \
  --repo konamgil/mandu

This confirms the binary was built by the expected workflow in the expected repo, not by a compromised mirror.

Atomic replacement

POSIX (macOS / Linux)

Plain rename(new, current) — the running process keeps its own file descriptor open, so the swap is safe even while mandu upgrade itself is executing.

/usr/local/bin/mandu          ← old binary (running)
/usr/local/bin/mandu.new      ← downloaded + verified
rename(mandu.new → mandu)
/usr/local/bin/mandu          ← new binary (next invocation uses it)

Windows

Windows doesn't allow overwriting a running .exe directly — but rename of the running .exe to a new name is allowed while the image is loaded. Mandu takes advantage:

C:\mandu\mandu.exe            ← running
rename(mandu.exe → mandu.old.<pid>.exe)
C:\mandu\mandu.old.12345.exe  ← old, stashed
move(mandu.exe.new → mandu.exe)
C:\mandu\mandu.exe            ← new binary

The old copy is moved into %USERPROFILE%\.mandu\bin\previous\. On POSIX the same stash location is used (~/.mandu/bin/previous/).

Rollback

mandu upgrade --rollback

Restores the previously-stashed binary from ~/.mandu/bin/previous/. If there's nothing to restore, exits with code 3.

Rollback only recovers the most recent swap — running --rollback twice doesn't chain back further.

Release channels

Channel npm tag Purpose
stable (default) latest Default; safe for production.
canary next Pre-release builds, ~weekly.
alpha alpha Experimental; opt-in for early testing.
mandu upgrade --channel=canary

Channels affect both package and binary mode — the binary release workflow publishes canary artifacts as separate GitHub releases tagged canary-<version>.

Exit codes

Code Meaning
0 upgrade applied (or --check)
1 network / integrity / I/O failure
2 usage error
3 rollback requested but nothing to restore

Troubleshooting

SHA-256 mismatch: expected X, got Y — the download was corrupted or tampered with. Retry. If it persists, verify the attestation with gh attestation verify.

rollback refused: no previous binary stashed--rollback was called before any binary upgrade had been performed. Nothing to restore.

CLI_E040: upgrade requires network accessmandu upgrade needs https access to api.github.com. In air-gapped environments, download the release + SHA256SUMS.txt manually and swap by hand.

Package mode: @mandujs/* packages are not upgraded — check that @mandujs/cli is actually listed as a dev dependency. mandu upgrade reads from package.json, not the global bun cache.

CI integration

# .github/workflows/bump-mandu.yml
name: Bump Mandu
on:
  schedule:
    - cron: "0 13 * * 1"   # Mondays 13:00 UTC
jobs:
  bump:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
      - run: bunx @mandujs/cli upgrade --check
      - run: bunx @mandujs/cli upgrade
      - run: bunx @mandujs/cli test
      - uses: peter-evans/create-pull-request@v6
        with:
          branch: chore/mandu-bump
          title: "chore: bump @mandujs/* to latest"

🤖 Agent Prompt

🤖 Agent Prompt — `mandu upgrade`
Apply the guidance from the Mandu docs page at https://mandujs.com/docs/cli/upgrade to my project.

Summary of the page:
`mandu upgrade` auto-detects package vs binary mode via process.execPath. Binary mode: downloads, verifies SHA256 from SHA256SUMS.txt, atomically swaps (rename on POSIX; rename-then-replace on Windows). Stashes the old binary in ~/.mandu/bin/previous/ so --rollback works. SLSA L2 provenance attached.

Required invariants — must hold after your changes:
- Package mode (`bun run mandu`): runs `bun update @mandujs/*`
- Binary mode (`mandu.exe` / `mandu-bun-linux-x64`): downloads + verifies + swaps
- SHA-256 verified against `SHA256SUMS.txt` released alongside each binary
- Windows: rename running `.exe` to `.old.<pid>.exe` first (allowed while loaded), then move new binary into place
- Previous binary stashed in `~/.mandu/bin/previous/` — `--rollback` restores it
- SLSA Build L2 provenance is attached via `actions/attest-build-provenance`

Then:
1. Make the change in my codebase consistent with the page.
2. Run `bun run guard` and `bun run check` to verify nothing
   in src/ or app/ breaks Mandu's invariants.
3. Show me the diff and any guard violations.

For Agents

{
  "schema": "mandu.upgrade/v0.25",
  "command": "mandu upgrade",
  "modes": {
    "package": "bun update @mandujs/*",
    "binary": "download + verify + atomic swap"
  },
  "mode_detection": "via process.execPath",
  "integrity": {
    "algorithm": "SHA-256",
    "sidecar": "SHA256SUMS.txt",
    "provenance": "SLSA Build L2 via actions/attest-build-provenance"
  },
  "stash_path": "~/.mandu/bin/previous/",
  "channels": ["stable", "canary", "alpha"],
  "exit_codes": {
    "0": "success",
    "1": "network / integrity / I/O",
    "2": "usage",
    "3": "rollback with nothing to restore"
  },
  "rules": [
    "Binary mode refuses to swap on SHA-256 mismatch — never yolo-overwrite",
    "Rollback only recovers the most recent swap",
    "Use `gh attestation verify` for defense-in-depth before `mandu upgrade`"
  ]
}

For Agents

AI hint

`mandu upgrade` auto-detects package vs binary mode via process.execPath. Binary mode: downloads, verifies SHA256 from SHA256SUMS.txt, atomically swaps (rename on POSIX; rename-then-replace on Windows). Stashes the old binary in ~/.mandu/bin/previous/ so --rollback works. SLSA L2 provenance attached.

Invariants
  • Package mode (`bun run mandu`): runs `bun update @mandujs/*`
  • Binary mode (`mandu.exe` / `mandu-bun-linux-x64`): downloads + verifies + swaps
  • SHA-256 verified against `SHA256SUMS.txt` released alongside each binary
  • Windows: rename running `.exe` to `.old.<pid>.exe` first (allowed while loaded), then move new binary into place
  • Previous binary stashed in `~/.mandu/bin/previous/` — `--rollback` restores it
  • SLSA Build L2 provenance is attached via `actions/attest-build-provenance`
Guard scope
upgrade