docs(35): create phase plan for npx buildthis CLI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fef0b48771
commit
c65fa168e6
2 changed files with 301 additions and 2 deletions
|
|
@ -186,7 +186,10 @@ Plans:
|
|||
**Success Criteria** (what must be TRUE):
|
||||
1. Running `npx buildthis` on a machine where Nexus is already running opens the Nexus UI in the default browser; running it on a machine with no Nexus guides the user through installation steps
|
||||
2. The CLI bootstrapper detects the same hardware tier (GPU / Apple Silicon / CPU-only) as the web onboarding and presents the matching provider tier recommendations in the terminal prompt
|
||||
**Plans**: TBD
|
||||
**Plans**: 1 plan
|
||||
|
||||
Plans:
|
||||
- [ ] 35-01-PLAN.md — Package scaffold, hardware detection, two-path bootstrap (probe running vs guide install), provider selection, tests
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -239,4 +242,4 @@ All 21 v1.5 requirements are mapped to exactly one phase. No orphans.
|
|||
| 32. Multi-Step Onboarding Wizard | v1.5 | 1/1 | Complete | 2026-04-03 |
|
||||
| 33. Persistent Memory + Personal Assistant Mode | v1.5 | 3/3 | Complete | 2026-04-03 |
|
||||
| 34. Voice | v1.5 | 2/2 | Complete | 2026-04-03 |
|
||||
| 35. npx buildthis CLI | v1.5 | 0/TBD | Not started | - |
|
||||
| 35. npx buildthis CLI | v1.5 | 0/1 | Not started | - |
|
||||
|
|
|
|||
296
.planning/phases/35-npx-buildthis-cli/35-01-PLAN.md
Normal file
296
.planning/phases/35-npx-buildthis-cli/35-01-PLAN.md
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
---
|
||||
phase: 35-npx-buildthis-cli
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- packages/buildthis/package.json
|
||||
- packages/buildthis/tsconfig.json
|
||||
- packages/buildthis/esbuild.config.mjs
|
||||
- packages/buildthis/vitest.config.ts
|
||||
- packages/buildthis/src/index.ts
|
||||
- packages/buildthis/src/bootstrap.ts
|
||||
- packages/buildthis/src/hardware.ts
|
||||
- packages/buildthis/src/banner.ts
|
||||
- packages/buildthis/src/__tests__/bootstrap.test.ts
|
||||
- packages/buildthis/src/__tests__/hardware.test.ts
|
||||
autonomous: true
|
||||
requirements:
|
||||
- CLI-01
|
||||
- CLI-02
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Running `npx buildthis` on a machine with Nexus running opens the browser to the Nexus UI"
|
||||
- "Running `npx buildthis` on a machine without Nexus shows hardware tier and provider recommendations"
|
||||
- "CLI detects Apple Silicon / GPU / CPU-only with the same logic as the web onboarding"
|
||||
- "Non-TTY environments get a clean non-interactive output and exit 0"
|
||||
artifacts:
|
||||
- path: "packages/buildthis/package.json"
|
||||
provides: "npm package config with bin.buildthis pointing to dist/index.js"
|
||||
contains: "\"buildthis\""
|
||||
- path: "packages/buildthis/src/index.ts"
|
||||
provides: "CLI entry point with commander setup"
|
||||
contains: "program"
|
||||
- path: "packages/buildthis/src/bootstrap.ts"
|
||||
provides: "Two-path bootstrap logic: probe running instance vs guide install"
|
||||
exports: ["bootstrap"]
|
||||
- path: "packages/buildthis/src/hardware.ts"
|
||||
provides: "Hardware tier detection matching server/src/services/hardware.ts"
|
||||
exports: ["detectHardware", "HardwareTier"]
|
||||
- path: "packages/buildthis/src/__tests__/hardware.test.ts"
|
||||
provides: "Unit tests for hardware detection tiers"
|
||||
min_lines: 30
|
||||
- path: "packages/buildthis/src/__tests__/bootstrap.test.ts"
|
||||
provides: "Unit tests for probe and bootstrap paths"
|
||||
min_lines: 30
|
||||
key_links:
|
||||
- from: "packages/buildthis/src/index.ts"
|
||||
to: "packages/buildthis/src/bootstrap.ts"
|
||||
via: "import and call bootstrap()"
|
||||
pattern: "import.*bootstrap"
|
||||
- from: "packages/buildthis/src/bootstrap.ts"
|
||||
to: "packages/buildthis/src/hardware.ts"
|
||||
via: "import detectHardware for fresh-install path"
|
||||
pattern: "import.*detectHardware"
|
||||
- from: "packages/buildthis/src/bootstrap.ts"
|
||||
to: "http://127.0.0.1:3100/api/health"
|
||||
via: "fetch probe for running-instance detection"
|
||||
pattern: "api/health"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the `packages/buildthis/` npm package — a standalone CLI bootstrapper that a developer runs via `npx buildthis` on a fresh machine. Two paths: (1) if Nexus is already running on port 3100, open the browser; (2) if not, detect hardware tier and present provider recommendations matching the web onboarding, then print next-step install instructions.
|
||||
|
||||
Purpose: Final phase of v1.5 — gives developers a single command to get started with Nexus.
|
||||
Output: Working `buildthis` package with tests, buildable via esbuild.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/35-npx-buildthis-cli/35-RESEARCH.md
|
||||
|
||||
@cli/esbuild.config.mjs
|
||||
@cli/package.json
|
||||
@cli/tsconfig.json
|
||||
@cli/src/utils/banner.ts
|
||||
@server/src/services/hardware.ts
|
||||
@pnpm-workspace.yaml
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 1: Scaffold buildthis package with hardware detection and tests</name>
|
||||
<files>
|
||||
packages/buildthis/package.json,
|
||||
packages/buildthis/tsconfig.json,
|
||||
packages/buildthis/esbuild.config.mjs,
|
||||
packages/buildthis/vitest.config.ts,
|
||||
packages/buildthis/src/hardware.ts,
|
||||
packages/buildthis/src/banner.ts,
|
||||
packages/buildthis/src/__tests__/hardware.test.ts
|
||||
</files>
|
||||
<read_first>
|
||||
@server/src/services/hardware.ts — copy-adapt the detection logic (Apple Silicon via os.cpus + platform, GPU via si.graphics with 3s timeout, cpu_only fallback)
|
||||
@cli/esbuild.config.mjs — mirror the esbuild pattern (banner shebang, node20 target, esm format, external native deps)
|
||||
@cli/package.json — reference dependency versions for consistency
|
||||
@cli/tsconfig.json — mirror the tsconfig extends pattern
|
||||
@packages/branding/vitest.config.ts — mirror vitest config pattern
|
||||
</read_first>
|
||||
<behavior>
|
||||
- detectHardware() returns { tier: "apple_silicon", totalGb } when process.platform === "darwin" AND os.cpus()[0].model starts with "Apple"
|
||||
- detectHardware() returns { tier: "gpu", totalGb, gpuName, gpuVramGb } when si.graphics() resolves with a controller having vram >= 4096 MB within 3 seconds
|
||||
- detectHardware() returns { tier: "cpu_only", totalGb } when si.graphics() throws or times out after 3 seconds
|
||||
- detectHardware() returns { tier: "cpu_only", totalGb } when GPU VRAM is below 4 GB
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create `packages/buildthis/package.json`:
|
||||
- name: "buildthis", version: "0.1.0", type: "module"
|
||||
- bin: { "buildthis": "./dist/index.js" }
|
||||
- files: ["dist"]
|
||||
- publishConfig: { access: "public" }
|
||||
- engines: { node: ">=20" }
|
||||
- scripts: dev ("tsx src/index.ts"), build (esbuild + chmod), clean, typecheck, test ("vitest run")
|
||||
- dependencies: @clack/prompts ^0.10.0, commander ^13.1.0, picocolors ^1.1.1, open ^11.0.0, systeminformation 5
|
||||
- devDependencies: @types/node ^22.12.0, tsx ^4.19.2, typescript ^5.7.3, vitest ^2.0.0, esbuild (latest)
|
||||
|
||||
2. Create `packages/buildthis/tsconfig.json` extending `../../tsconfig.base.json` with outDir "dist", rootDir "src", include ["src"].
|
||||
|
||||
3. Create `packages/buildthis/esbuild.config.mjs` — simple config:
|
||||
- entryPoints: ["src/index.ts"], bundle: true, platform: "node", target: "node20", format: "esm"
|
||||
- outfile: "dist/index.js"
|
||||
- banner: { js: "#!/usr/bin/env node" }
|
||||
- external: ["systeminformation", "open", "@clack/prompts", "commander", "picocolors"]
|
||||
- treeShaking: true, sourcemap: true
|
||||
|
||||
4. Create `packages/buildthis/vitest.config.ts` matching the branding package pattern: defineConfig with test.include ["src/**/*.test.ts"].
|
||||
|
||||
5. Create `packages/buildthis/src/hardware.ts`:
|
||||
- Export type HardwareTier = "gpu" | "apple_silicon" | "cpu_only"
|
||||
- Export interface HardwareResult { tier: HardwareTier; totalGb: number; gpuName?: string; gpuVramGb?: number }
|
||||
- Export async function detectHardware(): Promise<HardwareResult>
|
||||
- Apple Silicon path: process.platform === "darwin" && os.cpus()[0]?.model?.startsWith("Apple") -> return apple_silicon
|
||||
- GPU path: Promise.race([si.graphics(), 3s timeout]), check controllers[0].vram >= 4096 (MB), return gpu with gpuName + gpuVramGb
|
||||
- Fallback: cpu_only
|
||||
- Copy logic from server/src/services/hardware.ts but simplified (no cache, no freeGb/usableGb — not needed for CLI display)
|
||||
|
||||
6. Create `packages/buildthis/src/banner.ts`:
|
||||
- Export function printBuildthisBanner(): void
|
||||
- Print a compact "buildthis" ASCII art header using picocolors (simpler than the full Nexus banner — just the word "buildthis" stylized, or reuse NEXUS_ART from cli/src/utils/banner.ts with a different tagline like "Bootstrap your AI workspace")
|
||||
|
||||
7. Create `packages/buildthis/src/__tests__/hardware.test.ts`:
|
||||
- Mock os.cpus, os.totalmem, process.platform, si.graphics
|
||||
- Test apple_silicon detection (darwin + Apple M4)
|
||||
- Test gpu detection (linux + NVIDIA with 8GB VRAM)
|
||||
- Test cpu_only fallback (si.graphics timeout)
|
||||
- Test cpu_only when VRAM < 4GB
|
||||
|
||||
8. Run `pnpm install` from repo root to link the new workspace package.
|
||||
|
||||
9. Run `npx vitest run packages/buildthis/src/__tests__/hardware.test.ts` — all tests pass.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /opt/nexus && npx vitest run packages/buildthis/src/__tests__/hardware.test.ts</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- grep -q '"buildthis"' packages/buildthis/package.json
|
||||
- grep -q 'dist/index.js' packages/buildthis/package.json
|
||||
- grep -q 'HardwareTier' packages/buildthis/src/hardware.ts
|
||||
- grep -q 'detectHardware' packages/buildthis/src/hardware.ts
|
||||
- grep -q 'apple_silicon' packages/buildthis/src/__tests__/hardware.test.ts
|
||||
- grep -q 'cpu_only' packages/buildthis/src/__tests__/hardware.test.ts
|
||||
- grep -q 'banner' packages/buildthis/esbuild.config.mjs
|
||||
- test -f packages/buildthis/vitest.config.ts
|
||||
</acceptance_criteria>
|
||||
<done>
|
||||
Package scaffolded with package.json, tsconfig, esbuild config, vitest config, hardware detection module, banner module, and passing hardware detection unit tests covering all three tiers.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Implement bootstrap logic, CLI entry point, and integration tests</name>
|
||||
<files>
|
||||
packages/buildthis/src/bootstrap.ts,
|
||||
packages/buildthis/src/index.ts,
|
||||
packages/buildthis/src/__tests__/bootstrap.test.ts
|
||||
</files>
|
||||
<read_first>
|
||||
@packages/buildthis/src/hardware.ts — use detectHardware() for fresh-install path (created in Task 1)
|
||||
@packages/buildthis/src/banner.ts — call printBuildthisBanner() at startup (created in Task 1)
|
||||
@server/src/services/hardware.ts — reference HardwareInfo interface for the server probe path
|
||||
@cli/src/commands/onboard.ts — reference the health-check pattern and non-TTY guard (line ~395)
|
||||
</read_first>
|
||||
<behavior>
|
||||
- probeRunningInstance(3100) returns true when fetch to http://127.0.0.1:3100/api/health responds 200 within 2 seconds
|
||||
- probeRunningInstance(3100) returns false when fetch throws (connection refused) or times out
|
||||
- bootstrap() in TTY mode with running instance: opens browser and exits
|
||||
- bootstrap() in TTY mode without running instance: detects hardware, shows provider options via clack select, prints next-step instructions
|
||||
- bootstrap() in non-TTY mode: prints non-interactive instructions and exits 0
|
||||
- Provider options include "Local AI (Ollama)" only when tier is NOT cpu_only
|
||||
</behavior>
|
||||
<action>
|
||||
1. Create `packages/buildthis/src/bootstrap.ts`:
|
||||
- Export async function probeRunningInstance(port: number): Promise<boolean>
|
||||
- fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(2000) })
|
||||
- Return res.ok on success, false on any error
|
||||
- Export async function bootstrap(): Promise<void>
|
||||
- Import printBuildthisBanner from ./banner.ts, call it first
|
||||
- Non-TTY guard: if !process.stdin.isTTY || !process.stdout.isTTY, print "Run this command in an interactive terminal" with the URL and exit 0
|
||||
- const port = 3100 (hardcoded default — no config reading needed)
|
||||
- Path 1 (running): if await probeRunningInstance(port), use clack spinner "Opening Nexus...", import open, await open(`http://127.0.0.1:${port}`), log success, return
|
||||
- Path 2 (fresh install):
|
||||
- Use clack spinner "Detecting hardware..."
|
||||
- const hw = await detectHardware()
|
||||
- p.log.info with hardware tier and RAM
|
||||
- If tier is apple_silicon: note "Apple Silicon detected — unified memory, runs entirely on your machine"
|
||||
- If tier is gpu: note GPU name and VRAM
|
||||
- If tier is cpu_only: note "Cloud AI recommended for best experience"
|
||||
- p.select for provider choice:
|
||||
- puter: "Puter -- free, zero-config" (hint: "No API key needed")
|
||||
- google: "Google -- Gemini free tier" (hint: "Sign in with Google")
|
||||
- apikey: "API key -- subscription provider" (hint: "OpenAI, Anthropic, Groq")
|
||||
- local (only if tier !== "cpu_only"): "Local AI (Ollama)" (hint: "Private, offline")
|
||||
- skip: "Skip for now"
|
||||
- Handle p.isCancel(provider) — call p.cancel("Cancelled") and process.exit(0)
|
||||
- Print next-step instructions based on selection:
|
||||
- All paths: "To install and start Nexus:\n npx paperclipai@latest onboard"
|
||||
- If provider is "local": also print "Make sure Ollama is installed: https://ollama.com"
|
||||
- If provider is "puter": also print "Puter provides free AI — no setup needed"
|
||||
- p.outro with "Happy building!"
|
||||
|
||||
2. Create `packages/buildthis/src/index.ts`:
|
||||
- #!/usr/bin/env node (handled by esbuild banner, but add comment)
|
||||
- Import { program } from "commander"
|
||||
- Import { bootstrap } from "./bootstrap.js"
|
||||
- program.name("buildthis").description("Bootstrap your AI workspace").version("0.1.0")
|
||||
- program.action(async () => { await bootstrap(); })
|
||||
- program.parse()
|
||||
|
||||
3. Create `packages/buildthis/src/__tests__/bootstrap.test.ts`:
|
||||
- Mock global fetch for probeRunningInstance tests
|
||||
- Test probeRunningInstance returns true on 200 response
|
||||
- Test probeRunningInstance returns false on connection error
|
||||
- Test probeRunningInstance returns false on timeout
|
||||
- Test that provider options array includes "local" when tier is not cpu_only
|
||||
- Test that provider options array excludes "local" when tier is cpu_only
|
||||
- Export a helper function getProviderOptions(tier: HardwareTier) from bootstrap.ts to make this testable — extract the options-building logic into a pure function
|
||||
|
||||
4. Run the full test suite: `npx vitest run packages/buildthis/src/__tests__/`
|
||||
|
||||
5. Run `pnpm --filter buildthis build` to verify esbuild produces dist/index.js with shebang.
|
||||
|
||||
6. Verify the built file: head -1 packages/buildthis/dist/index.js should show "#!/usr/bin/env node".
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /opt/nexus && npx vitest run packages/buildthis/src/__tests__/ && pnpm --filter buildthis build && head -1 packages/buildthis/dist/index.js | grep -q "#!/usr/bin/env node"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- grep -q 'probeRunningInstance' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'api/health' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'detectHardware' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'isTTY' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'getProviderOptions' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'cpu_only' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'npx paperclipai' packages/buildthis/src/bootstrap.ts
|
||||
- grep -q 'program' packages/buildthis/src/index.ts
|
||||
- grep -q 'bootstrap' packages/buildthis/src/index.ts
|
||||
- grep -q 'probeRunningInstance' packages/buildthis/src/__tests__/bootstrap.test.ts
|
||||
- grep -q 'getProviderOptions' packages/buildthis/src/__tests__/bootstrap.test.ts
|
||||
- test -f packages/buildthis/dist/index.js
|
||||
</acceptance_criteria>
|
||||
<done>
|
||||
CLI entry point, bootstrap logic with two-path flow (running instance vs fresh install), provider selection with hardware-aware options, and all unit tests pass. Build produces dist/index.js with correct shebang.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. All tests pass: `npx vitest run packages/buildthis/src/__tests__/`
|
||||
2. Build succeeds: `pnpm --filter buildthis build`
|
||||
3. Built file has shebang: `head -1 packages/buildthis/dist/index.js` starts with `#!/usr/bin/env node`
|
||||
4. TypeScript compiles: `pnpm --filter buildthis typecheck`
|
||||
5. Package.json has correct bin field: `grep buildthis packages/buildthis/package.json`
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- `packages/buildthis/` is a complete npm package with bin entry, esbuild config, and vitest config
|
||||
- Hardware detection covers all three tiers (apple_silicon, gpu, cpu_only) with 3-second GPU timeout
|
||||
- Bootstrap probes port 3100, opens browser if running, guides install if not
|
||||
- Provider options exclude local AI for cpu_only tier
|
||||
- Non-TTY guard prevents hanging in CI/piped environments
|
||||
- All unit tests pass, build produces valid CLI binary with shebang
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/35-npx-buildthis-cli/35-01-SUMMARY.md`
|
||||
</output>
|
||||
Loading…
Add table
Reference in a new issue