Files
CIAgent 2c68b44c1a merge: milestone/v0.4-distribution → main (v0.4 Distribution & Bootstrap CLI complete)
The nextcraft bootstrap CLI ships: doctor/bootstrap/verify/dev commands, a
one-liner install script with checksum + version integrity gates, and linux
x64 SEA binaries published on every release going forward (v0.3.2 onward).
Fresh-clone E2E proven; 34 CLI tests + full monorepo gates green.

Escalation note: merge_to_main hook — proceeding per full autonomy + founder
directive D-016 (streamlined install + bootstrap CLI + ongoing binaries,
recorded at P0 SPECIFY).

---ci---
phase: 4
milestone: v0.4
status: complete
requirements:
  covered: [REQ-4-001, REQ-4-002, REQ-4-003, REQ-4-004, REQ-4-005]
  partial: []
---/ci---
2026-09-12 23:17:43 +00:00

48 lines
3.3 KiB
Markdown

# @nextcraft/cli — nextcraft
The bootstrap CLI for the Nextcraft monorepo, shipped as a self-contained linux x64 binary (Node SEA) on every release.
## Commands
See the [root README quickstart](../../README.md) for the user-facing flow. Internals:
- `src/index.ts` — argv dispatch, exit-code contract (0 ok / 1 failure / 2 usage), direct-run guard (`argv[0] === argv[1]` detects SEA context — the installer renames the binary, so filename matching is unreliable)
- `src/commands/` — doctor / bootstrap / verify / dev; all orchestration delegates to `apps/ai-service/scripts/*.sh` via `src/lib/spawn.ts` (array-args only, SIGTERM→SIGKILL timeout ladder)
- `src/checks/` — pure logic: version compare, `.env` template diff
- `tests/` — node:test suites: dispatch, checks, spawn, command stubs, real-box doctor integration, install.sh fixture-server E2E (tamper rejection, degradation), release-assets token isolation, fresh-clone E2E
## Build
```sh
pnpm cli:typecheck # tsc --noEmit
pnpm cli:test # node:test suites
pnpm cli:build # tsc -p tsconfig.build.json -> dist/
pnpm --filter @nextcraft/cli build:binary <tag> # SEA binary + sha256 sidecar
```
`build:binary <tag>`: esbuild bundle (CJS, node18 target, version stamped via `NEXTCRAFT_VERSION_STAMP` define — `--version` reports the tag it was built as) → `node --experimental-sea-config` → postject injection into a copy of the system node binary → `dist/nextcraft-linux-x64` + `dist/nextcraft-linux-x64.sha256`. The binary runs without node on PATH (runtime embedded, ~117 MB).
## Release pipeline
Every ship from v0.3.2 onward runs `scripts/release-assets.sh <tag>` after tag+merge:
1. Builds the binary stamped with the tag
2. Resolves `GITEA_TOKEN` from `.env*` files ONLY (`.ciagent/.env.secrets` first) — never from shell env
3. Attaches `nextcraft-linux-x64` + `nextcraft-linux-x64.sha256` to the Gitea release (bounded retry, best-effort — never blocks the ship)
`scripts/install.sh` (POSIX sh, dash-safe): platform gate → Gitea latest-release API resolve → exact-name asset match → sha256 verify BEFORE install (mismatch = hard stop) → `~/.local/bin` install → PATH hint. Any failure degrades to printed source-bootstrap instructions.
## Secrets policy
The CLI never generates, writes, or echoes secrets. `bootstrap` copies `.env.example``.env` only when absent and warns on missing optional keys (mock providers keep the stack runnable keyless). Real keys live only in gitignored `.ciagent/.env.secrets`, exported by `apps/ai-service/scripts/dev.sh`.
## Troubleshooting
| Symptom | Cause / fix |
|---------|-------------|
| `pnpm not found` in doctor | `corepack enable pnpm` (installs to ~/.local/bin — ensure PATH includes it) |
| doctor passes but verify fails on venv | re-run `nextcraft bootstrap` (venv/pip resolution is idempotent) |
| `port 8420 busy` in verify | stop the process on :8420 (`kill $(lsof -t -i:8420)`) or set `AI_PORT` |
| install.sh says "no binary assets yet" | release predates the binary pipeline (pre-v0.3.2); use source bootstrap |
| Binary silent after rename | fixed since v0.3.2 (SEA argv detection); re-download the latest release |
| Checksum mismatch on install | do NOT run the download; delete it and retry — report if it persists |