From 90006cb4f6b3ca0bf2a99536e380af53adf00d4a Mon Sep 17 00:00:00 2001 From: fullstackjam Date: Sun, 2 Aug 2026 01:23:37 +0800 Subject: [PATCH] fix: align docs with current CLI --- AGENTS.md | 4 ++-- CHANGELOG.md | 6 ++---- README.md | 4 +++- docs/HARNESS.md | 6 +----- internal/archtest/README.md | 2 ++ internal/cli/helpers.go | 2 +- internal/cli/helpers_test.go | 30 +++++++++++++++++++++--------- 7 files changed, 32 insertions(+), 22 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 32924dc..0e8da81 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -88,7 +88,7 @@ internal/ diff/ # Pure-logic system-vs-config comparison dotfiles/ # Clone + stow with .openboot.bak backup httputil/ # HTTP Do() with rate-limit + Retry-After - installer/ # 7-step wizard orchestrator + snapshot restore + installer/ # Install planning + linear apply + snapshot restore macos/ # defaults write + app restart npm/ # Batch install with sequential fallback permissions/ # macOS screen-recording probe @@ -115,7 +115,7 @@ scripts/ |------|----------|-------| | Add CLI command | `internal/cli/` | Register in `root.go init()`, follow cobra pattern | | Change install flow | `internal/installer/installer.go` | plan -> apply orchestrator; `PlanFromSelection` builds a plan from TUI picks | -| Change interactive install TUI | `internal/ui/tui/wizard/` | Redesign v5: boot/select/install screens; live install streams `internal/progress` events (brew/npm `SetProgressSink`) | +| Change interactive install TUI | `internal/ui/tui/wizard/` | Redesign v5 planning screens: boot -> select -> git -> review; apply starts only after the wizard exits | | Change sync behavior | `internal/sync/diff.go`, `internal/sync/plan.go` | Diff -> confirm -> execute | | Add package category | `openboot.dev/src/lib/package-metadata.ts` | Server is source of truth; CLI fetches `/api/packages` and caches 24h in `~/.openboot/packages-cache.json`. `data/packages.yaml` is fallback only. | | Modify presets | `internal/config/data/presets.yaml` | 3 presets: minimal, developer, full | diff --git a/CHANGELOG.md b/CHANGELOG.md index dc14c60..bac956d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,11 @@ ## v1.0 (unreleased) -OpenBoot v1.0 narrows the product to two verbs: **`install`** (add things to your Mac) and **`snapshot`** (save your current state somewhere). Everything else is either cloud-config CRUD or independent tooling. +OpenBoot v1.0 narrows the core workflow to two verbs: **`install`** (add things to your Mac) and **`snapshot`** (save your current state somewhere). The supporting **`doctor`** and **`update`** maintenance commands remain available; everything else is either cloud-config CRUD or independent tooling. ### Breaking changes -Six commands are removed outright. Each prints an error with a migration hint when invoked: +Eight commands are removed outright: | Removed | Use instead | |---------|-------------| @@ -18,8 +18,6 @@ Six commands are removed outright. Each prints an error with a migration hint wh | `openboot restore` | **no replacement** — version history is dropped | | `openboot init` | **no replacement** — use your project's own tooling (npm/pip/go/cargo) | | `openboot setup-agent` | **no replacement** — existed only to service `openboot init` | -| `openboot doctor` | **no replacement** — use `brew doctor` and `git config --list` directly | -| `openboot update` | **no replacement** — use `brew upgrade` directly; OpenBoot self-updates on launch | Three flat commands are removed with no replacement — manage configs directly at openboot.dev: diff --git a/README.md b/README.md index 97d6e35..202fd9a 100644 --- a/README.md +++ b/README.md @@ -167,10 +167,12 @@ openboot snapshot --publish # Upload to openboot.dev openboot snapshot --import FILE # Restore from a snapshot file openboot login / logout # openboot.dev auth +openboot doctor # Check system health and diagnose issues +openboot update # Update, pin, or roll back OpenBoot openboot version # Print version ``` -Removed in v1.0: `pull`, `push`, `diff`, `clean`, `log`, `restore`, `init`, `setup-agent`, `doctor`, `update`. See [CHANGELOG.md](CHANGELOG.md) for migration. +Removed in v1.0: `pull`, `push`, `diff`, `clean`, `log`, `restore`, `init`, `setup-agent`. See [CHANGELOG.md](CHANGELOG.md) for migration. diff --git a/docs/HARNESS.md b/docs/HARNESS.md index 8e7368e..8caa48c 100644 --- a/docs/HARNESS.md +++ b/docs/HARNESS.md @@ -46,7 +46,7 @@ Three regulation categories: | Arch. | `no-raw-http` | L1 | `internal/archtest/http_test.go` | | Arch. | `no-os-getenv-home` | L1 | `internal/archtest/envhome_test.go` | | Arch. | `dryrun` — destructive ops must check `DryRun` | L1 | `internal/archtest/dryrun_test.go` | -| Arch. | `no-raw-fmtprint` — UI output via `ui.*` helpers, not raw `fmt.Print*` | L1 | `internal/archtest/fmtprint_test.go` | +| Arch. | `fmtprint` — UI output via `ui.*` helpers, not raw `fmt.Print*` | L1 | `internal/archtest/fmtprint_test.go` | | Arch. | `install.sh` must not prompt on stdin — under `curl \| bash` stdin is the script | L1 | `internal/archtest/installsh_test.go` | | Behav. | L1 unit + integration + contract (faked runners *and* real brew/git/npm in temp dirs) | pre-push, CI | `make test-unit` | | Behav. | L2 contract schema (against openboot-contract repo) | CI | `.github/workflows/test.yml` `contract` job | @@ -93,10 +93,6 @@ it survives doc rot. - **No coverage gate that fails PRs.** Coverage is informational (`codecov.yml` `informational: true`). Hard coverage gates push toward test-shaped code without raising actual quality. -- **No fmt.Print/Println archtest rule yet.** The convention exists in - AGENTS.md but the codebase has ~150 existing call sites and the rule - would be mostly noise. Reconsider after the UI helpers cover all the - cases currently using raw stdout. - **No agent-driven changes to `main` without human review.** All AI changes go through PR review and the existing CI matrix. - **No retroactive refactors triggered by new archtest rules.** New rules diff --git a/internal/archtest/README.md b/internal/archtest/README.md index 7b8fb5e..0c60dca 100644 --- a/internal/archtest/README.md +++ b/internal/archtest/README.md @@ -29,6 +29,8 @@ from the baseline) are logged but do not fail the test. | `no-raw-http` | `http_test.go` | yes | "Use `httputil.Do()` — handles 429 + Retry-After" | | `no-os-getenv-home` | `envhome_test.go` | no (hard rule) | "Use `os.UserHomeDir()` — never hardcode `~` or `/Users/...`" | | `dryrun` | `dryrun_test.go` | yes | "Destructive ops: check `cfg.DryRun` first. Always." | +| `fmtprint` | `fmtprint_test.go` | yes | "UI output must go through `ui.*` helpers" | +| `installsh` | `installsh_test.go` | no (hard rule) | "`install.sh` must not prompt on stdin" | | `agent-config` | `agentconfig_test.go` | no (hard rule) | "Keep `AGENTS.md` and shared skills canonical across agent tools" | ## Workflow diff --git a/internal/cli/helpers.go b/internal/cli/helpers.go index 8f97916..97b810e 100644 --- a/internal/cli/helpers.go +++ b/internal/cli/helpers.go @@ -27,7 +27,7 @@ func parseConflictError(body []byte) error { msg = errResp.Error } if msg != "" && strings.Contains(strings.ToLower(msg), "maximum") { - return errors.New("config limit reached (max 20): delete an existing config with 'openboot delete ' first") + return errors.New("config limit reached (max 20): delete an existing config at https://openboot.dev/dashboard first") } if msg != "" { return errors.New(msg) diff --git a/internal/cli/helpers_test.go b/internal/cli/helpers_test.go index 6a13b6d..8ee1533 100644 --- a/internal/cli/helpers_test.go +++ b/internal/cli/helpers_test.go @@ -10,19 +10,25 @@ import ( func TestParseConflictError_MaxConfigsMessage(t *testing.T) { tests := []struct { - name string - body []byte - wantContain string + name string + body []byte + wantContain string + wantAlsoContain string + wantNotContain string }{ { - name: "message field contains maximum", - body: mustMarshalJSON(t, map[string]string{"message": "You have reached the maximum number of configs"}), - wantContain: "config limit reached", + name: "message field contains maximum", + body: mustMarshalJSON(t, map[string]string{"message": "You have reached the maximum number of configs"}), + wantContain: "config limit reached", + wantAlsoContain: "https://openboot.dev/dashboard", + wantNotContain: "openboot delete", }, { - name: "error field contains maximum", - body: mustMarshalJSON(t, map[string]string{"error": "Maximum configs exceeded"}), - wantContain: "config limit reached", + name: "error field contains maximum", + body: mustMarshalJSON(t, map[string]string{"error": "Maximum configs exceeded"}), + wantContain: "config limit reached", + wantAlsoContain: "https://openboot.dev/dashboard", + wantNotContain: "openboot delete", }, { name: "plain message field returned as-is", @@ -51,6 +57,12 @@ func TestParseConflictError_MaxConfigsMessage(t *testing.T) { err := parseConflictError(tt.body) require.Error(t, err) assert.Contains(t, err.Error(), tt.wantContain) + if tt.wantAlsoContain != "" { + assert.Contains(t, err.Error(), tt.wantAlsoContain) + } + if tt.wantNotContain != "" { + assert.NotContains(t, err.Error(), tt.wantNotContain) + } }) } }