feat(setup-instructions): preflight checks both git and claude
Renames `_git_check_block` to `_preflight_block` and adds a `claude --version` check beside `git --version`. Both binaries are required by the marketplace step — git for the clone fallback, claude for `claude plugin marketplace add` / `claude plugin install` — so checking them together gives one clear failure instead of two confusing downstream errors. Install hints: `npm i -g @anthropic-ai/claude-code` for Linux / WSL plus a doc URL (https://docs.claude.com/claude-code) for the native macOS / Windows installers. We don't try to one-line a native installer; the canonical instructions live upstream. Plan: docs/superpowers/plans/2026-05-04-unified-setup-prompt.md task 3.
This commit is contained in:
parent
e16698c3cc
commit
74b7f6e254
2 changed files with 66 additions and 16 deletions
|
|
@ -430,34 +430,48 @@ def _finale_lines(*, confirm_step_num: str, has_ca: bool, has_marketplace: bool)
|
|||
]
|
||||
|
||||
|
||||
def _git_check_block(step_num: str) -> list[str]:
|
||||
"""Git pre-flight check — runs before the marketplace clone.
|
||||
def _preflight_block(step_num: str) -> list[str]:
|
||||
"""Pre-flight check — runs before the marketplace clone.
|
||||
|
||||
`claude plugin marketplace add` (and our git-clone fallback) shells out
|
||||
to `git`, so a missing git binary fails the marketplace step with a
|
||||
confusing error. Cross-platform install commands cover the three
|
||||
supported workstation OSes:
|
||||
to `git`, AND the marketplace step calls `claude` itself, so a missing
|
||||
binary on either side fails the step with a confusing error. We check
|
||||
both here so the user gets a single clear "install X" message instead
|
||||
of debugging a downstream error.
|
||||
|
||||
Cross-platform install commands cover the three supported workstation
|
||||
OSes:
|
||||
- macOS: Homebrew (`brew install git`). The Xcode CLT bundle also
|
||||
ships git; we prefer brew because it's non-interactive.
|
||||
- Windows: winget (`winget install --id Git.Git -e ...`). Bundled
|
||||
with Windows 10 1809+ and Windows 11; non-interactive with --silent.
|
||||
- Linux: apt or dnf, depending on distro family.
|
||||
|
||||
For `claude` we point at the official platform installer docs rather
|
||||
than vendoring an install one-liner — Anthropic ships per-platform
|
||||
installers (npm on Linux, native binary on macOS/Windows) and the
|
||||
canonical instructions live at https://docs.claude.com/claude-code.
|
||||
|
||||
`step_num` is parameterized because step ordering shifted between
|
||||
layouts (the marketplace block now runs before diagnose/skills, so
|
||||
git-check + marketplace are steps 4-5 instead of 6-7).
|
||||
preflight + marketplace are steps 4-5 instead of 6-7).
|
||||
"""
|
||||
return [
|
||||
"",
|
||||
f"{step_num}) Make sure git is installed (required for the marketplace clone):",
|
||||
f"{step_num}) Make sure git and claude are installed (required for the marketplace clone):",
|
||||
" git --version",
|
||||
" claude --version",
|
||||
"",
|
||||
" If that fails (\"command not found\" or similar), install git:",
|
||||
" If `git --version` fails (\"command not found\" or similar), install git:",
|
||||
" - macOS: brew install git",
|
||||
" - Windows: winget install --id Git.Git -e --source winget --silent",
|
||||
" - Linux: sudo apt-get install git OR sudo dnf install git",
|
||||
"",
|
||||
" Then re-run `git --version` to confirm before continuing.",
|
||||
" If `claude --version` fails, install Claude Code:",
|
||||
" - npm (Linux / WSL): npm i -g @anthropic-ai/claude-code",
|
||||
" - macOS / Windows native installer: see https://docs.claude.com/claude-code",
|
||||
"",
|
||||
" Then re-run both `--version` checks to confirm before continuing.",
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -733,7 +747,7 @@ def resolve_lines(
|
|||
lines.extend(_install_cli_lines(has_ca=has_ca)) # 1
|
||||
lines.extend(_init_lines()) # 2, 3
|
||||
if has_marketplace:
|
||||
lines.extend(_git_check_block(steps["preflight"])) # 4
|
||||
lines.extend(_preflight_block(steps["preflight"])) # 4
|
||||
lines.extend(_marketplace_block( # 5
|
||||
names, effective_self_signed, has_ca=has_ca, step_num=steps["marketplace"],
|
||||
))
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ def test_resolve_lines_no_plugins_unified_six_step_layout():
|
|||
assert "claude plugin marketplace add" not in joined
|
||||
assert "claude plugin install" not in joined
|
||||
# No preflight step when there's no marketplace block to gate.
|
||||
assert "Make sure git is installed" not in joined
|
||||
assert "Make sure git and claude are installed" not in joined
|
||||
# Legacy `git config sslVerify=false` downgrade must NOT be emitted.
|
||||
# Match the specific config line, not the bare substring (which appears
|
||||
# in the preamble as a "don't do this" example).
|
||||
|
|
@ -292,9 +292,10 @@ def test_resolve_lines_with_plugins_uses_install_first_diagnose_last_layout():
|
|||
server_host="agnes.example.com",
|
||||
)
|
||||
joined = "\n".join(lines)
|
||||
# Step 4 — git pre-flight, with all three platforms' install commands.
|
||||
assert "4) Make sure git is installed" in joined
|
||||
# Step 4 — pre-flight, with all three platforms' install commands.
|
||||
assert "4) Make sure git and claude are installed" in joined
|
||||
assert "git --version" in joined
|
||||
assert "claude --version" in joined
|
||||
assert "brew install git" in joined
|
||||
assert "winget install --id Git.Git -e --source winget --silent" in joined
|
||||
assert "sudo apt-get install git" in joined or "sudo dnf install git" in joined
|
||||
|
|
@ -318,7 +319,7 @@ def test_resolve_lines_with_plugins_uses_install_first_diagnose_last_layout():
|
|||
install_idx = joined.index("1) Install the CLI")
|
||||
init_idx = joined.index("2) Bootstrap your Agnes workspace")
|
||||
catalog_idx = joined.index("3) Verify the data is queryable:")
|
||||
git_idx = joined.index("4) Make sure git is installed")
|
||||
git_idx = joined.index("4) Make sure git and claude are installed")
|
||||
market_idx = joined.index("5) Register the Agnes Claude Code marketplace")
|
||||
diag_idx = joined.index("6) Run diagnostics:")
|
||||
skills_idx = joined.index("7) Skills")
|
||||
|
|
@ -333,6 +334,41 @@ def test_resolve_lines_with_plugins_uses_install_first_diagnose_last_layout():
|
|||
assert "{token}" in joined
|
||||
|
||||
|
||||
def test_preflight_checks_both_git_and_claude():
|
||||
"""Pre-flight (step 4 when marketplace is gated on) checks BOTH binaries
|
||||
before the marketplace clone — `git --version` is needed for the clone
|
||||
itself, `claude --version` is needed for the `claude plugin
|
||||
marketplace add` / `claude plugin install` calls. Either missing
|
||||
breaks the marketplace step in a confusing way, so we surface the
|
||||
failure before we get there.
|
||||
"""
|
||||
from app.web.setup_instructions import resolve_lines
|
||||
|
||||
joined = "\n".join(
|
||||
resolve_lines(
|
||||
"agnes.whl",
|
||||
plugin_install_names=["foo"],
|
||||
server_host="agnes.example.com",
|
||||
)
|
||||
)
|
||||
# Both version checks present.
|
||||
assert "git --version" in joined
|
||||
assert "claude --version" in joined
|
||||
# Header mentions both tools.
|
||||
assert "Make sure git and claude are installed" in joined
|
||||
# Install hints for claude — npm one-liner for Linux/WSL plus a doc URL
|
||||
# for native installers on macOS / Windows. We don't try to one-line a
|
||||
# native installer; the canonical instructions live upstream.
|
||||
assert "npm i -g @anthropic-ai/claude-code" in joined
|
||||
assert "https://docs.claude.com/claude-code" in joined
|
||||
# Both checks come BEFORE the marketplace add line.
|
||||
git_check_idx = joined.index("git --version")
|
||||
claude_check_idx = joined.index("claude --version")
|
||||
market_idx = joined.index("claude plugin marketplace add")
|
||||
assert git_check_idx < market_idx
|
||||
assert claude_check_idx < market_idx
|
||||
|
||||
|
||||
def test_resolve_lines_self_signed_legacy_path_adds_git_config_line():
|
||||
"""Legacy fallback (no ca_pem on disk + self_signed_tls=True): the host-scoped
|
||||
`git config sslVerify=false` downgrade is still emitted so existing
|
||||
|
|
@ -365,8 +401,8 @@ def test_resolve_lines_self_signed_no_op_without_plugins():
|
|||
# Legacy downgrade line not present.
|
||||
assert "git config --global" not in joined
|
||||
assert "claude plugin" not in joined
|
||||
# No git pre-flight either when there's no marketplace step.
|
||||
assert "Make sure git is installed" not in joined
|
||||
# No pre-flight either when there's no marketplace step.
|
||||
assert "Make sure git and claude are installed" not in joined
|
||||
assert "6) Confirm:" in joined # original layout intact
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue