updates to add AI packages and an opt out of AI flag #17
@@ -4,7 +4,7 @@ A Go-based bootstrap tool that installs a development environment across
|
||||
macOS, Debian/Ubuntu, RHEL/Fedora, and Arch Linux on `x86_64` and `aarch64`.
|
||||
It installs system packages, optional Flatpak GUI apps, and a set of custom
|
||||
third-party tools (Go, Neovim, Zig, NVM, pyenv, oh-my-zsh, Firecracker on
|
||||
Linux).
|
||||
Linux, agy, claude, codex, and copilot).
|
||||
|
||||
## Install
|
||||
|
||||
@@ -40,5 +40,6 @@ Flags:
|
||||
headless: both are skipped.
|
||||
- `--no-vm` — macOS only: skip provisioning the Fedora-on-QEMU/VirtualBox VM
|
||||
that backs the `firecracker()` zsh wrapper.
|
||||
- `--no-ai` — skip installation of AI/LLM CLI tools (agy, claude, codex, copilot).
|
||||
|
||||
Package lists live in `packages.go`. Edit and rebuild.
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
@@ -54,6 +55,7 @@ var defaultInstallPaths = map[string]string{
|
||||
"pyenv": "~/.pyenv",
|
||||
"neovim": "/usr/local/bin/nvim",
|
||||
"oh-my-zsh": "~/.oh-my-zsh",
|
||||
"agy": "~/.local/bin/agy",
|
||||
}
|
||||
|
||||
func expandHome(p string) string {
|
||||
@@ -84,10 +86,42 @@ func pipInstalled() bool {
|
||||
// isCustomPkgInstalled returns (installed, checkPath). pip ships inside the
|
||||
// Python distribution rather than at a fixed path, so it's detected with
|
||||
// `python3 -m pip --version`.
|
||||
func npmInstalled(cmdName string) (bool, string) {
|
||||
if hasCmd(cmdName) {
|
||||
if p, err := exec.LookPath(cmdName); err == nil {
|
||||
return true, p
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
matches, _ := filepath.Glob(filepath.Join(home, ".local/share/pnpm/bin", cmdName))
|
||||
if len(matches) > 0 {
|
||||
return true, matches[0]
|
||||
}
|
||||
matches, _ = filepath.Glob(filepath.Join(home, ".nvm/versions/node/*/bin", cmdName))
|
||||
if len(matches) > 0 {
|
||||
return true, matches[0]
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func isCustomPkgInstalled(pkg *CustomPackage) (bool, string) {
|
||||
if strings.ToLower(pkg.Name) == "pip" {
|
||||
name := strings.ToLower(pkg.Name)
|
||||
if name == "pip" {
|
||||
return pipInstalled(), ""
|
||||
}
|
||||
if name == "claude" {
|
||||
return npmInstalled("claude")
|
||||
}
|
||||
if name == "codex" {
|
||||
return npmInstalled("codex")
|
||||
}
|
||||
if name == "copilot" {
|
||||
return npmInstalled("copilot")
|
||||
}
|
||||
raw := pkg.InstallPath
|
||||
if raw == "" {
|
||||
raw = defaultInstallPath(pkg)
|
||||
@@ -428,6 +462,7 @@ func resolveLatest(pkg *CustomPackage) {
|
||||
|
||||
func installCustomPackages(toInstall []*CustomPackage) {
|
||||
fmt.Println("\n=== Custom Packages ===")
|
||||
ensureNodeLTS()
|
||||
for _, pkg := range toInstall {
|
||||
name := strings.ToLower(pkg.Name)
|
||||
_, checkPath := isCustomPkgInstalled(pkg)
|
||||
@@ -448,6 +483,7 @@ func installCustomPackages(toInstall []*CustomPackage) {
|
||||
switch name {
|
||||
case "nvm":
|
||||
installNVM()
|
||||
ensureNodeLTS()
|
||||
continue
|
||||
case "pyenv":
|
||||
installPyenv()
|
||||
@@ -467,6 +503,18 @@ func installCustomPackages(toInstall []*CustomPackage) {
|
||||
installNeovim(pkg, tmp)
|
||||
os.RemoveAll(tmp)
|
||||
continue
|
||||
case "agy":
|
||||
installAgy()
|
||||
continue
|
||||
case "claude":
|
||||
installNpmPackage("@anthropic-ai/claude-code")
|
||||
continue
|
||||
case "codex":
|
||||
installNpmPackage("@openai/codex")
|
||||
continue
|
||||
case "copilot":
|
||||
installNpmPackage("@github/copilot")
|
||||
continue
|
||||
}
|
||||
|
||||
resolveLatest(pkg)
|
||||
|
||||
@@ -33,6 +33,7 @@ func main() {
|
||||
only := flag.String("only", "", "Install only the named section (system|flatpak|custom)")
|
||||
gui := flag.Bool("gui", false, "Include GUI applications (headed environments).")
|
||||
noVM := flag.Bool("no-vm", false, "macOS only: skip provisioning the Fedora-on-QEMU VM that backs the firecracker() zsh wrapper.")
|
||||
noAI := flag.Bool("no-ai", false, "Skip installation of LLM/AI CLI tools (agy, claude, codex, copilot).")
|
||||
flag.Parse()
|
||||
|
||||
switch *only {
|
||||
@@ -54,6 +55,12 @@ func main() {
|
||||
if isMacOS && strings.ToLower(custom[i].Name) == "firecracker" {
|
||||
continue
|
||||
}
|
||||
if *noAI {
|
||||
name := strings.ToLower(custom[i].Name)
|
||||
if name == "agy" || name == "claude" || name == "codex" || name == "copilot" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
customPtrs = append(customPtrs, &custom[i])
|
||||
}
|
||||
|
||||
|
||||
@@ -136,5 +136,9 @@ func customPackages() []CustomPackage {
|
||||
{Name: "pyenv"},
|
||||
{Name: "pip"},
|
||||
{Name: "oh-my-zsh"},
|
||||
{Name: "agy"},
|
||||
{Name: "claude"},
|
||||
{Name: "codex"},
|
||||
{Name: "copilot"},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +243,11 @@ func ensureNodeLTS() {
|
||||
if !runShell(`bash -c "source ~/.nvm/nvm.sh && nvm alias default 'lts/*' && nvm use --lts"`, CmdOpts{}).OK() {
|
||||
errLog("Setting nvm default to LTS failed")
|
||||
}
|
||||
|
||||
fmt.Println("[NVM] Enabling corepack and installing latest pnpm ...")
|
||||
if !runShell(`bash -c 'source ~/.nvm/nvm.sh && corepack enable && corepack prepare pnpm@latest --activate && pnpm config set global-bin-dir "$HOME/.local/share/pnpm/bin"'`, CmdOpts{}).OK() {
|
||||
errLog("Failed to enable corepack and prepare pnpm")
|
||||
}
|
||||
}
|
||||
|
||||
// ── oh-my-zsh ───────────────────────────────────────────────────────────
|
||||
@@ -455,3 +460,24 @@ func askYN(prompt string) bool {
|
||||
answer := strings.ToLower(strings.TrimSpace(string(buf[:n])))
|
||||
return answer == "y"
|
||||
}
|
||||
|
||||
func installAgy() {
|
||||
fmt.Println(" Installing agy via curl ...")
|
||||
if !runShell("curl -fsSL https://antigravity.google/cli/install.sh | bash", CmdOpts{}).OK() {
|
||||
errLog("agy installation failed")
|
||||
}
|
||||
}
|
||||
|
||||
func installNpmPackage(pkgName string) {
|
||||
home, _ := os.UserHomeDir()
|
||||
if _, err := os.Stat(filepath.Join(home, ".nvm")); err != nil {
|
||||
errLog("NVM is not installed — cannot install " + pkgName)
|
||||
return
|
||||
}
|
||||
ensureNodeLTS()
|
||||
fmt.Printf(" Installing %s via pnpm ...\n", pkgName)
|
||||
if !runShell(fmt.Sprintf(`bash -c "source ~/.nvm/nvm.sh && pnpm add -g %s"`, pkgName), CmdOpts{}).OK() {
|
||||
errLog(fmt.Sprintf("%s installation failed", pkgName))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user