// Name: Install Node + Vercel + pnpm // Description: Installs Node.js (if missing), then pnpm and Vercel CLI globally. // Author: alexdev888 // GitHub: alexdev888 import "@johnlindquist/kit" const has = (cmd: string) => { try { return !!which(cmd) } catch { return false } } const run = async (command: string) => { try { const { all } = await exec(command) return { ok: true, out: all || "" } } catch (err: any) { return { ok: false, out: err?.all || String(err) } } } let logs: string[] = [] const log = (s: string) => { logs.push(s) console.log(s) } const ensureNode = async () => { if (has("node")) { log(`✅ Node is already installed: ${(await exec("node -v")).all?.trim()}`) return } log("⬇️ Installing Node.js...") if (isMac) { if (has("brew")) { const r = await run("brew install node") log(r.out) } else { // Fallback to nvm on macOS if Homebrew not found const nvmInstall = await run( 'bash -lc \'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash\'' ) log(nvmInstall.out) const nvmUse = await run('bash -lc "source ~/.nvm/nvm.sh && nvm install --lts && nvm use --lts"') log(nvmUse.out) } } else if (isLinux) { if (has("apt-get")) { const ns = await run( "curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -" ) log(ns.out) const inst = await run("sudo apt-get install -y nodejs") log(inst.out) } else if (has("pacman")) { const inst = await run("sudo pacman -S --noconfirm nodejs npm") log(inst.out) } else if (has("dnf")) { const enable = await run("sudo dnf module enable nodejs:20 -y || true") log(enable.out) const inst = await run("sudo dnf install -y nodejs") log(inst.out) } else { // Fallback to nvm on unknown Linux const nvmInstall = await run( 'bash -lc \'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash\'' ) log(nvmInstall.out) const nvmUse = await run('bash -lc "source ~/.nvm/nvm.sh && nvm install --lts && nvm use --lts"') log(nvmUse.out) } } else if (isWin) { if (has("winget")) { const r = await run('winget install -e --id OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements') log(r.out) } else if (has("choco")) { const r = await run("choco install nodejs-lts -y") log(r.out) } else if (has("scoop")) { const r = await run("scoop install nodejs-lts") log(r.out) } else { log("❌ No supported package manager found on Windows (winget/choco/scoop). Please install Node.js LTS manually from https://nodejs.org") } } if (has("node")) { log(`✅ Node installed: ${(await exec("node -v")).all?.trim()}`) } else { log("❌ Node installation appears to have failed or requires a new shell session.") } } const ensurePnpm = async () => { if (has("pnpm")) { log(`✅ pnpm is already installed: ${(await exec("pnpm -v")).all?.trim()}`) return } log("⬇️ Installing pnpm...") // Try corepack first (Node 16.13+) let r = await run("corepack enable || true") log(r.out) r = await run("corepack prepare pnpm@latest --activate") log(r.out) if (!has("pnpm")) { // Fallback to npm -g r = await run("npm i -g pnpm") log(r.out) } if (has("pnpm")) { log(`✅ pnpm installed: ${(await exec("pnpm -v")).all?.trim()}`) } else { log("❌ pnpm installation appears to have failed.") } } const ensureVercel = async () => { if (has("vercel")) { log(`✅ Vercel CLI is already installed: ${(await exec("vercel --version")).all?.trim()}`) return } log("⬇️ Installing Vercel CLI globally...") if (has("pnpm")) { const r = await run("pnpm add -g vercel") log(r.out) } else { const r = await run("npm i -g vercel") log(r.out) } if (has("vercel")) { log(`✅ Vercel CLI installed: ${(await exec("vercel --version")).all?.trim()}`) } else { log("❌ Vercel CLI installation appears to have failed.") } } // Execute await ensureNode() await ensurePnpm() await ensureVercel() // Versions summary const nodeV = has("node") ? (await exec("node -v")).all?.trim() : "not found" const npmV = has("npm") ? (await exec("npm -v")).all?.trim() : "not found" const pnpmV = has("pnpm") ? (await exec("pnpm -v")).all?.trim() : "not found" const vercelV = has("vercel") ? (await exec("vercel --version")).all?.trim() : "not found" const summary = md(` # Installation Summary - Node: ${nodeV} - npm: ${npmV} - pnpm: ${pnpmV} - Vercel: ${vercelV} ${isWin ? "_If commands aren't found, open a new terminal window so PATH updates take effect._" : ""} `) await div(summary)