Fix #528: non-TTY installer hardcodes the Claude agent

Merged
JE
4mo ago
+1056-13

Fixes #528.

Both symptoms

  1. Installer hardcoded setup claude — the piped install (curl -fsSL https://basecamp.com/install-cli | bash, a 302 redirect to this repo's scripts/install.sh) took the non-TTY branch, which unconditionally ran basecamp setup claude. The BASECAMP_SKIP_SETUP=1 branch did the same.
  2. Claude-first login nudge — printAgentNudge pointed at the first detected-unhealthy agent in registry order, so it always recommended Claude when both agents were present.

Approach — detection proves presence, not intent

New basecamp setup agents command (always non-interactive): installs the baseline skill and connects coding agents by intent.

  • BASECAMP_SETUP_AGENT wins: claude | codex | all | none.
  • Auto (unset): 0 detected → skill only · 1 → connect it · ≥2 → skill only + surface setup <id> choices (never guess).
  • all forces every registered handler and synthesizes symmetric missing-binary remediation — the Claude handler treats an absent binary as no-op success while Codex errors, so the aggregate runner fills the gap for either.
  • Invalid value → structured warning + baseline only. BASECAMP_SKIP_SETUP=1 skips only the interactive wizard; setup agents still runs.

Styled-safe result envelope

curl | bash renders styled output (piped stdin, TTY stdout), and the styled renderer skips nested map/[]map. So every safety-critical outcome — skill_installed, selector, ambiguous, detected_before, attempted_agents, errors (union of baseline + id-prefixed per-agent), warnings, manual_commands — lives in a top-level flat field; the agents array is JSON-only detail. Ordering is deterministic: set-like fields sorted by id; manual_commands/errors preserve each handler's own sequence with stable first-seen dedup (Codex's remediation is an ordered marketplace-add → upgrade → plugin-add sequence, never lexicographically sorted).

Changes

  • internal/commands/wizard_agents.go — newSetupAgentsCmd + runNonInteractiveAgentSetup and the typed envelope. Existing setup claude/setup codex unchanged.
  • internal/commands/auth.go — rewrite printAgentNudge: one detected-unhealthy agent → its setup <id>; several → every choice printed directly.
  • scripts/install.sh / scripts/install.ps1 — both non-TTY and skip branches run setup agents; install.sh gains an if-form source guard and documents BASECAMP_SETUP_AGENT.
  • .surface regenerated (only setup agents additions); smoke declaration + new e2e/installer.bats; install.md updated.

Tests

  • internal/commands/setup_agents_test.go — full-CLI (cobra Execute) coverage: styled-output regression (failure survives via top-level errors), 0/1/≥2 detection, baseline-skill failure, =all zero/one/two, =codex missing-binary contract, Codex manual-order preservation (guards against string-sorting), =claude no-binary (symlink + detection flip + synthesized remediation), =none, invalid selector.
  • internal/commands/auth_test.go — nudge: none / single / multiple detected-unhealthy.
  • e2e/installer.bats — sourcing guard, post_install_setup dispatch (non-TTY + skip → setup agents, never setup claude), static branch assertions for both scripts.

Verified: make build, targeted go test, make check-surface/check-skill-drift/check-bare-groups/check-naming/check-smoke-coverage/fmt-check/vet/lint, and the smoke + installer bats suites all green. (The full unit suite has a pre-existing network-dependent todos-reposition test that hangs offline; unrelated to this change.)


Summary by cubic

Replaces the non-TTY installer’s hardcoded Claude path with an intent-based, non-interactive agent setup. Adds basecamp setup agents, makes installers cross-version safe, and prevents old releases from launching the interactive wizard.

  • New Features

    • Added basecamp setup agents (non-interactive): installs the baseline skill and connects coding agents by intent; honors BASECAMP_SETUP_AGENT = claude | codex | all | none (unset auto-detects: 0→skill only, 1→connect it, ≥2→skill only + surface setup <id> choices).
    • Installers (scripts/install.sh, scripts/install.ps1) run setup agents for non-TTY and BASECAMP_SKIP_SETUP=1. Docs updated with piped-install auto-connect and how to set BASECAMP_SETUP_AGENT in Bash/PowerShell.
    • Styled-safe result: all critical outcomes are top-level flat fields so they render in styled output; the agents array is JSON-only detail.
  • Bug Fixes

    • Cross-version installers: probe for setup agents. On older binaries, fall back without reintroducing Claude-first behavior—all runs each supported per-agent setup; explicit claude/codex is capability-checked and degrades to skill install if unsupported; all calls are guarded so failures never abort install.
    • PowerShell Invoke-PostInstallSetup: marks attempted agents on dispatch (not success) to match Bash, so =all only falls back to skill install when no supported per-agent subcommands exist.
    • setup agents rejects positional args to prevent accidental setup <id> typos.
    • Login nudge points to the detected-unhealthy agent; with multiple, it lists each basecamp setup <id> option (no bias).