* feat(start): implement ao start fetch/open for Windows and Linux Fill in the non-darwin branches of the bootstrapper (T6/T7): - assetName() selects the per-GOOS stable release asset: windows -> agent-orchestrator-win32-x64.exe (NSIS installer), linux -> agent-orchestrator-linux-x64.AppImage. amd64-only for now via requireAMD64(), which returns a clear unsupported-arch error. - fetchApp() dispatches per GOOS. Windows downloads the NSIS installer and runs it silently (/S) to the default per-user dir, then resolves the installed exe under %LOCALAPPDATA%\Programs. Linux downloads the AppImage to a stable path under ~/.ao (atomic temp+rename), chmods it executable, and skips any install step so re-runs resolve without re-fetching. - knownAppLocations() scans the per-user and per-machine Windows install dirs and the stable Linux AppImage path. - isUsableBundle() treats a win exe / linux AppImage as a regular file (darwin stays a directory). - openApp() launches win/linux detached via the existing StartProcess seam, forwarding --installed-via=npm-bootstrap, and falls back to manual-open on spawn failure. The Windows silent-install path is marked ponytail (untestable on the macOS build host); a wrong install dir surfaces as a clear not-found error. Tests cover asset naming, arch gating, scan locations, regular-file vs dir, and the detached-spawn + fallback paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(release): build + publish a Linux AppImage for ao start (T7) AppImage is the Linux fetch-and-run artifact for the bootstrapper (spec §11.3): a single self-contained executable ao start downloads and runs directly, no system package manager. - makers/maker-appimage.ts: a MakerBase subclass bridging to electron-builder's buildForge (appImage target), mirroring maker-nsis.ts, since Forge has no first-party AppImage maker. publish:null so Forge owns release uploads. - forge.config.ts: register MakerAppImage for linux; keep deb/rpm for users who want a system package. - frontend-release.yml: on ubuntu-latest, copy the built AppImage to the stable, space-free name agent-orchestrator-linux-x64.AppImage and upload it to the v<version> release with --clobber, mirroring the Windows step. Build-untested on this macOS host: the first ubuntu CI run must confirm the electron-builder AppImage target token and the out/make/*.AppImage output glob. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(ci): green up ao start Win/Linux PR (lint, cross-OS test, container smoke) Five golangci-lint findings in start.go, two cross-OS test failures, and the fresh-install container smoke were broken by the Win/Linux bootstrapper diff. Go lint (start.go): - gocritic filepathJoin: build "/Applications/<bundle>" as a literal instead of filepath.Join with a separator-bearing arg. - gocritic httpNoBody: pass http.NoBody, not nil, to NewRequestWithContext. - gosec G302: annotate the AppImage chmod 0755 with a nolint; an AppImage is a self-contained executable and must be executable. - nilerr: annotate openApp's intentional (false, nil) on launch failure; the failure is reported via the bool, not as an error. - unparam: resolveApp's error result was always nil; drop it and update callers. Cross-OS tests (start_test.go): - makeBundle created a directory, which only stats as usable on macOS. Make it a regular file on Windows/Linux so the marker/scan resolve tests pass there, matching isUsableBundle's per-OS rule. Container fresh-install smoke (test/cli/install-check.sh, Dockerfile): - ao start is now the desktop-app launcher and no longer runs a daemon, so the old daemon status/shutdown/stop assertions could never pass. Assert instead that on a fresh box start reaches the fetch path and exits non-zero with a clear error (404 download on amd64, unsupported-arch on arm64). Refresh the stale daemon-reaping comments in the Dockerfile. Verified locally: go build/vet ok, golangci-lint v2.12.2 reports 0 issues, go test -tags e2e ./internal/cli/... passes (the only remaining failure, TestE2E_Lifecycle, is a pre-existing daemon-shutdown flake that fails the same way on upstream/main on this host), and the container smoke passes on both linux/arm64 and linux/amd64. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| Dockerfile | ||
| README.md | ||
| install-check.sh | ||
README.md
ao CLI end-to-end tests
These tests drive the real ao binary the way a user would — start →
status → doctor → stop, plus the daemon-control HTTP surface — and assert
the whole thing works. They run against isolated, throwaway state (a per-test
temp run-file + data dir + an OS-assigned free loopback port), so they never
touch a developer's real AO installation.
Two tiers
| Tier | What | Where |
|---|---|---|
| Comprehensive (primary) | A cross-platform Go suite that builds ao and exercises the full behaviour. Runs natively on ubuntu + macOS + windows — the only way to cover the OS-specific process-detach paths (setsid vs CREATE_NEW_PROCESS_GROUP) and os.UserConfigDir() resolution. |
backend/internal/cli/e2e_test.go (build tag e2e) |
| Fresh-install (hardening) | Proves a freshly installed binary works on a clean machine with no Go toolchain and no developer state. | test/cli/Dockerfile + test/cli/install-check.sh |
Run it
The Go suite (fastest, cross-platform):
cd backend
go test -tags e2e ./internal/cli/... # run it
go test -tags e2e -v -run TestE2E ./internal/cli/... # verbose: prints every command + output
It builds its own ao binary; git must be on PATH (required by doctor).
-v logs each ao invocation and its full output, which is the audit trail you
get for free from go test.
Fresh-machine install, in a clean container:
docker build -f test/cli/Dockerfile -t ao-cli-smoke .
docker run --rm --init ao-cli-smoke
--initgives the container a real PID-1 reaper (tini) so the daemon the
check starts is reaped afterstopinstead of lingering as a zombie.
What the Go suite covers
TestE2E_VersionAndHelp (version/--version/help, daemon hidden) ·
TestE2E_DoctorDoesNotTouchTheStore (doctor text + --json; proves it does
not create/migrate ao.db) · TestE2E_StatusStopped (stopped + idempotent
stop) · TestE2E_Lifecycle (start, ready, idempotent, daemon-created store,
/healthz identity, stop, run-file cleanup) · TestE2E_ShutdownGuard (the
/shutdown CSRF + DNS-rebinding 403 guard, daemon survives) ·
TestE2E_StaleRunFile (dead-PID run-file → stale → cleaned) · TestE2E_ExitCodes
(2 usage / 1 runtime / config error) · TestE2E_Completion (all four shells).
Why a Go suite (not bash, not Python)
The bash version grew past the point where bash was a good fit, and a Linux
container can't observe the macOS/Windows code paths at all. A Go os/exec
suite is the right home: it uses the repo's own toolchain (runs under go test),
gives real assertions and structured data, and — critically — runs natively on
the Windows and macOS runners, finally covering the CREATE_NEW_PROCESS_GROUP
detach path and per-OS config-dir resolution. The container stays as a thin
"clean install actually works" check.
Extending
- Add a case: a new
TestE2E_*function (or at.Runsubtest) in
e2e_test.go. UsenewEnv(t)for isolated state and theenv.run/httpGet/
postShutdownhelpers. - Add an OS: extend the
matrix.oslist in.github/workflows/cli-e2e.yml. - Deeper per-OS path assertions (state resolves under the OS-native config dir
whenAO_RUN_FILE/AO_DATA_DIRare unset) fit best as unit tests in
internal/config.