Standalone npm package at packages/buildthis/. Probes running Nexus instance, opens browser if found, guides install with hardware-aware provider recommendations if not. 14 tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
145 lines
4.1 KiB
TypeScript
145 lines
4.1 KiB
TypeScript
import * as p from "@clack/prompts";
|
|
import pc from "picocolors";
|
|
import { detectHardware, type HardwareTier } from "./hardware.js";
|
|
import { printBuildthisBanner } from "./banner.js";
|
|
|
|
/**
|
|
* Probe whether a Nexus instance is running on the given port.
|
|
* Returns true if the health endpoint responds with HTTP 200 within 2 seconds.
|
|
*/
|
|
export async function probeRunningInstance(port: number): Promise<boolean> {
|
|
try {
|
|
const res = await fetch(`http://127.0.0.1:${port}/api/health`, {
|
|
signal: AbortSignal.timeout(2000),
|
|
});
|
|
return res.ok;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build the provider selection options based on hardware tier.
|
|
* Excludes local AI for cpu_only machines (too slow for practical use).
|
|
*/
|
|
export function getProviderOptions(tier: HardwareTier): Array<{ value: string; label: string; hint: string }> {
|
|
const options: Array<{ value: string; label: string; hint: string }> = [
|
|
{
|
|
value: "puter",
|
|
label: "Puter — free, zero-config",
|
|
hint: "No API key needed",
|
|
},
|
|
{
|
|
value: "google",
|
|
label: "Google — Gemini free tier",
|
|
hint: "Sign in with Google",
|
|
},
|
|
{
|
|
value: "apikey",
|
|
label: "API key — subscription provider",
|
|
hint: "OpenAI, Anthropic, Groq",
|
|
},
|
|
];
|
|
|
|
if (tier !== "cpu_only") {
|
|
options.push({
|
|
value: "local",
|
|
label: "Local AI (Ollama)",
|
|
hint: "Private, offline",
|
|
});
|
|
}
|
|
|
|
options.push({
|
|
value: "skip",
|
|
label: "Skip for now",
|
|
hint: "Set up a provider later",
|
|
});
|
|
|
|
return options;
|
|
}
|
|
|
|
/**
|
|
* Main bootstrap function.
|
|
*
|
|
* Two paths:
|
|
* 1. Nexus is already running on port 3100 — open the browser
|
|
* 2. Fresh install — detect hardware, show provider options, print next steps
|
|
*/
|
|
export async function bootstrap(): Promise<void> {
|
|
printBuildthisBanner();
|
|
|
|
const port = 3100;
|
|
|
|
// Non-TTY guard: prevent hanging in CI/piped environments
|
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
console.log(pc.bold("Run this command in an interactive terminal."));
|
|
console.log("");
|
|
console.log(" To open Nexus in your browser:");
|
|
console.log(pc.cyan(` http://127.0.0.1:${port}`));
|
|
console.log("");
|
|
console.log(" To install Nexus on this machine:");
|
|
console.log(pc.cyan(" npx paperclipai@latest onboard"));
|
|
process.exit(0);
|
|
return;
|
|
}
|
|
|
|
// Path 1: Running instance detected
|
|
const isRunning = await probeRunningInstance(port);
|
|
if (isRunning) {
|
|
const s = p.spinner();
|
|
s.start("Opening Nexus...");
|
|
const { default: open } = await import("open");
|
|
await open(`http://127.0.0.1:${port}`);
|
|
s.stop(pc.green("Nexus opened in your browser"));
|
|
return;
|
|
}
|
|
|
|
// Path 2: Fresh install — detect hardware and guide setup
|
|
const s = p.spinner();
|
|
s.start("Detecting hardware...");
|
|
const hw = await detectHardware();
|
|
s.stop("Hardware detected");
|
|
|
|
// Display hardware info
|
|
if (hw.tier === "apple_silicon") {
|
|
p.log.info(
|
|
`${pc.bold("Apple Silicon detected")} — unified memory (${hw.totalGb} GB), runs entirely on your machine`
|
|
);
|
|
} else if (hw.tier === "gpu") {
|
|
p.log.info(
|
|
`${pc.bold("GPU detected")}: ${hw.gpuName} (${hw.gpuVramGb} GB VRAM) — ${hw.totalGb} GB RAM`
|
|
);
|
|
} else {
|
|
p.log.info(
|
|
`${pc.bold("CPU-only machine")} (${hw.totalGb} GB RAM) — cloud AI recommended for best experience`
|
|
);
|
|
}
|
|
|
|
// Provider selection
|
|
const provider = await p.select({
|
|
message: "Which AI provider would you like to use?",
|
|
options: getProviderOptions(hw.tier),
|
|
});
|
|
|
|
if (p.isCancel(provider)) {
|
|
p.cancel("Cancelled");
|
|
process.exit(0);
|
|
return;
|
|
}
|
|
|
|
// Print next-step instructions
|
|
console.log("");
|
|
console.log(pc.bold("To install and start Nexus:"));
|
|
console.log(pc.cyan(" npx paperclipai@latest onboard"));
|
|
console.log("");
|
|
|
|
if (provider === "local") {
|
|
console.log(pc.dim("Make sure Ollama is installed: https://ollama.com"));
|
|
console.log("");
|
|
} else if (provider === "puter") {
|
|
console.log(pc.dim("Puter provides free AI — no setup needed"));
|
|
console.log("");
|
|
}
|
|
|
|
p.outro(pc.bold("Happy building!"));
|
|
}
|