Files
CIAgent 135ea21a61 merge: hotfix/fresh-box-experience → main (v0.3.5 fresh-box experience)
Fixes the v0.3.4 fresh-box failures: silent CLI under bare-word PATH
invocation (SEA argv detection), bootstrap dying on venv creation without an
actionable hint (poisoned-partial-venv recovery + apt hint + doctor
venv-capability probe + preflight), installer falsely 'verifying' a silent
binary, and localhost-only server binding (network mode: 0.0.0.0 + wildcard
CORS + hostname-derived API URL — remote browsing zero-config).

38 CLI tests, 3 web tests, 409 ai-service tests green; build/typecheck/lint
clean.

---ci---
phase: hotfix
milestone: v0.4
status: complete
type: hotfix
requirements:
  covered: [REQ-4-001, REQ-4-002, REQ-4-003, REQ-4-004, REQ-4-005]
  partial: []
---/ci---
2026-09-13 00:05:37 +00:00

100 lines
4.2 KiB
Bash
Executable File

#!/bin/sh
# Nextcraft CLI installer — the one-liner:
# curl -fsSL https://git.coreci.dev/coreci/nextcraft/raw/main/scripts/install.sh | sh
# Resolves the latest release from the Gitea API, downloads the linux x64 binary
# + sha256 sidecar, verifies the checksum, installs to ~/.local/bin.
# Any failure degrades to printed source-bootstrap instructions (G-103) — never
# installs an unverified artifact. Checksum mismatch = hard stop (exit 1).
set -eu
FORGE_BASE="${NEXTCRAFT_FORGE_BASE:-https://git.coreci.dev}"
OWNER="coreci"
REPO="nextcraft"
DEST="${DEST:-$HOME/.local/bin}"
API="$FORGE_BASE/api/v1/repos/$OWNER/$REPO/releases/latest"
say() { printf '%s\n' "$*"; }
die() { printf '%s\n' "$*" >&2; exit 1; }
[ "$(uname -s)" = "Linux" ] && [ "$(uname -m)" = "x86_64" ] || {
say "nextcraft: no binary for $(uname -s)/$(uname -m) (linux x64 only for now)."
say "Source bootstrap instead:"
say " git clone $FORGE_BASE/$OWNER/$REPO.git && cd $REPO"
say " pnpm --filter @nextcraft/cli dev -- doctor # or scripts/bootstrap.sh path"
exit 0
}
command -v curl >/dev/null 2>&1 || {
say "nextcraft: curl is required. Install curl, or source bootstrap:"
say " git clone $FORGE_BASE/$OWNER/$REPO.git"
exit 0
}
RELEASE_JSON="$(curl -fsSL "$API" 2>/dev/null)" || {
say "nextcraft: could not reach $API."
say "Source bootstrap instead: git clone $FORGE_BASE/$OWNER/$REPO.git"
exit 0
}
TAG="$(printf '%s' "$RELEASE_JSON" | sed -n 's/.*"tag_name":"\([^"]*\)".*/\1/p' | head -1)"
BIN_URL="$(printf '%s' "$RELEASE_JSON" | sed -n 's/.*"browser_download_url":"\([^"]*nextcraft-linux-x64\)".*/\1/p' | head -1)"
SUM_URL="$(printf '%s' "$RELEASE_JSON" | sed -n 's/.*"browser_download_url":"\([^"]*nextcraft-linux-x64\.sha256\)".*/\1/p' | head -1)"
if [ -z "$TAG" ] || [ -z "$BIN_URL" ] || [ -z "$SUM_URL" ]; then
say "nextcraft: latest release ($TAG) has no linux x64 binary assets yet."
say "Source bootstrap instead:"
say " git clone $FORGE_BASE/$OWNER/$REPO.git && cd $REPO"
say " pnpm install && pnpm --filter @nextcraft/cli dev -- doctor"
exit 0
fi
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
say "nextcraft: downloading $TAG ..."
curl -fsSL "$BIN_URL" -o "$TMP/nextcraft-linux-x64" || {
say "nextcraft: download failed. Source bootstrap: git clone $FORGE_BASE/$OWNER/$REPO.git"
exit 0
}
curl -fsSL "$SUM_URL" -o "$TMP/nextcraft-linux-x64.sha256" || {
say "nextcraft: checksum download failed — refusing to install unverified binary."
say "Source bootstrap instead: git clone $FORGE_BASE/$OWNER/$REPO.git"
exit 0
}
EXPECTED="$(sed 's/ .*$//' "$TMP/nextcraft-linux-x64.sha256" | tr -d '[:space:]')"
if command -v sha256sum >/dev/null 2>&1; then
ACTUAL="$(sha256sum "$TMP/nextcraft-linux-x64" | sed 's/ .*$//')"
elif command -v shasum >/dev/null 2>&1; then
ACTUAL="$(shasum -a 256 "$TMP/nextcraft-linux-x64" | sed 's/ .*$//')"
else
die "nextcraft: no sha256 tool available — cannot verify. DO NOT install an unverified binary. Install sha256sum (coreutils) and retry."
fi
[ "$ACTUAL" = "$EXPECTED" ] || die "nextcraft: CHECKSUM MISMATCH for $TAG — do not run this binary. Aborting."
mkdir -p "$DEST"
mv "$TMP/nextcraft-linux-x64" "$DEST/nextcraft"
chmod +x "$DEST/nextcraft"
say "nextcraft: installed $DEST/nextcraft ($TAG)"
INSTALLED_VERSION="$("$DEST/nextcraft" --version 2>/dev/null || true)"
if [ -z "$INSTALLED_VERSION" ]; then
die "nextcraft: installed binary produced no output for --version — it is broken. Do not use it; remove $DEST/nextcraft, report the issue, and fall back to source bootstrap (git clone $FORGE_BASE/$OWNER/$REPO.git)."
fi
if [ "$INSTALLED_VERSION" != "$TAG" ]; then
die "nextcraft: binary reports version $INSTALLED_VERSION but release is $TAG — integrity mismatch. Remove $DEST/nextcraft and re-run the installer."
fi
say "nextcraft: verified binary version: $INSTALLED_VERSION"
case ":$PATH:" in
*":$DEST:"*) ;;
*)
say ""
say "$DEST is not on your PATH. Add it:"
say " echo 'export PATH=\"$DEST:\$PATH\"' >> ~/.profile && source ~/.profile"
;;
esac
say ""
say "Next steps:"
say " nextcraft doctor # check prerequisites"
say " git clone $FORGE_BASE/$OWNER/$REPO.git && cd nextcraft"
say " nextcraft bootstrap # set up the monorepo"
say " nextcraft verify && nextcraft dev"