Smooth mirror onboarding: entire repo mirror create wizard#1519
Conversation
Run `entire repo mirror create` with no args to onboard repos interactively: verifies auth, multi-select repos to mirror, multi-select regions, then creates every (repo, region) mirror in parallel and prints the clone URLs. The positional `create <github-url> [cluster-host]` form is unchanged. Regions come from entire-core's GET /api/v1/clusters (ListClusters). The endpoint isn't deployed yet, so the /clusters spec fragment is hand-authored into core.openapi.json and the ogen client regenerated; a real spec refresh is idempotent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: ee0c83e58bfc
Display "Fetching available repos" and "Fetching regions" spinners before each picker so the network pause isn't a blank screen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: d5dc5f40492b
Switch both `repo mirror create <url>` and the onboarding wizard onto one shared createAndAwaitMirror path that polls GetMirror for the new Mirror.status (processing/ready/failed/suspended) instead of the smart-HTTP info/refs probe. This drops the repo-scoped token dance and data-plane round trip; suspension and clone failure now surface directly from the control plane. Removes the now-dead info/refs probe machinery (waitForMirrorClone, mirrorAdvertisesHead, checkProbeRedirect, the probe HTTP client and token source) and their tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 94e331061b08
`entire repo mirror create github.com/octocat/hello-world` (no cluster-host) now resolves the target from GET /api/v1/clusters — the is_default cluster (or the sole one) — instead of the hardcoded constant, matching the wizard. Prints the chosen cluster; errors asking for an explicit [cluster-host] when the catalog is empty or has no clear default. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: cfcf2050076d
Prints the active control-plane bearer to stdout so curl/scripts can auth without digging the JWT out of the keychain: curl -H "Authorization: Bearer $(entire auth token)" "$CORE/api/v1/clusters" Honors ENTIRE_TOKEN verbatim, else resolves and refreshes the active context's login JWT (same bearer the API client uses). Hidden; errors and the not-logged-in hint go to stderr so stdout stays clean for command substitution. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: c9e38d421945
is_default is per-jurisdiction (each of au/eu/us has its own default), so the single hardcoded "first default" was wrong. Resolve the caller's jurisdiction from /me and: - one-shot `repo mirror create <url>` (no cluster-host): pick the is_default cluster for that jurisdiction; - wizard: still list every cluster (so you can mirror into any), but pre-select only your jurisdiction's default instead of all three. Errors asking for an explicit [cluster-host] when the jurisdiction is unknown or has no default. Surfaces the jurisdiction in the wizard's "Signed in as" line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: a03b61382aa9
Revert the one-shot `repo mirror create <url>` to the fixed defaultClusterHost when [cluster-host] is omitted; catalog/jurisdiction-based cluster guessing is now confined to the no-args interactive wizard, so non-interactive invocations (and scripts) keep stable, predictable defaults. remove/collaborators were already on the fixed default and are unchanged. Drops the one-shot-only resolveDefaultClusterHost/callerJurisdiction/ pickDefaultRegionHost helpers; the wizard keeps its jurisdiction-aware region pre-selection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: a03599d356ff
The region multi-select already lists every cluster, but on a short terminal huh's scrollable viewport shows only the top rows — so the pre-checked default (the caller's jurisdiction) could sit below the fold, making it look like one unrelated option. List the caller's-jurisdiction clusters first so the visible top row is the relevant, pre-selected default; trim the description to reclaim a row. Other jurisdictions remain selectable by scrolling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 27ad338c331d
huh sizes an unset multi-select height to (rendered option lines − title/ description rows), so a short list (3 regions) collapsed to ~1 visible row while a long repo list looked fine. Set an explicit Height = option count + header slack on both pickers so every option is visible (still scrolls past the terminal). Region picker is no longer stuck showing one option at a time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 6e993f6cd3aa
Replace the single "Creating N mirror(s)…" spinner with one live line per (repo, region), each updating independently as its CreateMirror + clone poll advance (processing → ready), then the existing summary table. Lines read "owner/repo @ <cluster-host> <spinner|✓|✗> <status>". A per-poll status callback now flows through awaitMirrorReady/createAndAwaitMirror (one-shot passes nil and keeps its single spinner). Non-TTY degrades to one printed line per mirror as it finalizes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 18dbd0a73461
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 4477af226732
There was a problem hiding this comment.
Pull request overview
This PR smooths mirror onboarding by adding a zero-argument interactive wizard for entire repo mirror create, and updates clone-readiness waiting to use the control-plane Mirror.status lifecycle instead of probing the data-plane smart-HTTP endpoint. It also adds a hidden entire auth token helper for scripting/curl access.
Changes:
- Add an interactive
repo mirror createwizard to select repos and regions and create mirrors in parallel with live progress + a results table. - Replace clone readiness probing with
GET /mirrors/{id}status polling (processing→ready/failed/suspended). - Add hidden
entire auth tokencommand and document it.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/entire/cli/repo_mirror.go | Routes repo mirror create to wizard when no args; refactors create+wait into shared helpers and updates one-shot output. |
| cmd/entire/cli/repo_mirror_test.go | Replaces old probe/finish-create tests with status-polling and one-shot reporting tests. |
| cmd/entire/cli/repo_mirror_probe.go | Implements awaitMirrorReady polling against Mirror.status and updates suspension messaging helper. |
| cmd/entire/cli/repo_mirror_create_wizard.go | New interactive wizard: repo/region selection, parallel create+poll, live progress, and summary reporting. |
| cmd/entire/cli/repo_mirror_create_wizard_test.go | Unit tests for wizard helpers (selection filtering, host parsing, ordering, progress non-TTY). |
| cmd/entire/cli/repo_mirror_collaborators.go | Updates example invocation for collaborators add. |
| cmd/entire/cli/auth.go | Adds hidden entire auth token command and includes jurisdiction in auth profile for wizard defaults. |
| cmd/entire/cli/auth_token_test.go | Tests env-token printing and not-logged-in behavior for entire auth token. |
| CLAUDE.md | Documents the hidden auth token command in the CLI command layout. |
- Wizard: gate on an interactive terminal with a clear pointer at the non-interactive form; run the pickers via RunWithContext so Ctrl+C/ctx cancellation is handled cleanly (Cursor). - Wizard: a cancelled run no longer reports in-flight mirrors as failures — exit quietly (Cursor). - createAndAwaitMirror: restore the suspension check for an existing empty placement (one GetMirror) so suspended empties surface resume guidance instead of a benign "nothing to clone" (Cursor). - Wizard: suspended/failed results now carry the mirror id + resume command in the failure summary, matching the one-shot (Copilot). - auth token: enforce HTTPS on the core URL unless --insecure-http-auth, like auth status (Copilot). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: e2c7535c9951
|
Addressed the review findings in 7a0ca5c:
Not changed — false positive: Copilot flagged the Added tests for the TTY gate and non-TTY progress; |
|
@cursor review |
- handleFormCancellation: also treat a cancelled/expired context as a clean cancel, so a RunWithContext form whose context is cancelled exits quietly instead of "prompt failed: huh: context canceled" (Cursor). - Drop internal terminology from suspended/failed user messages: the wizard now says "the mirror is suspended; contact support" / "the initial clone failed; contact support", and explainSuspendedMirror points at support instead of the internal `entire-core admin mirrors resume` command (Cursor). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 9ea51e10ee42
|
@cursor review |
awaitMirrorReady previously aborted the whole wait on any GetMirror error, so a brief network/API glitch during a long initial clone failed mirror create even though the clone was still progressing. Retry on the poll interval, giving up only after maxConsecutivePollErrors consecutive failures (resets on success) or when the context ends — a persistent error (deleted mirror, revoked auth) still surfaces instead of spinning to the deadline. (Cursor) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 5d285b69feaf
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit e5692a0. Configure here.
hostFromPublicURL rejected any non-empty path, so a catalog entry like https://aws-us-east-2.entire.io/ (Path == "/") was dropped in clustersToRegions — silently removing clusters and risking "no regions available to mirror into" if the control plane emits trailing slashes. publicUrl is a trusted catalog field, so accept a bare "/" path; real paths/queries/fragments/userinfo are still refused. (Trail review) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 32af87a69f30
https://entire.io/gh/entireio/cli/trails/660
Adds an interactive onboarding flow and modernizes mirror creation.
User impact
entire repo mirror create(no args) → interactive wizard: pick repos, pick regions, watch Docker-style per-mirror progress (processing → ready), then a summary table with clone URLs.Mirror.statusAPI instead of probing smart-HTTPinfo/refs— faster, and surfacesfailed/suspendeddirectly.GET /api/v1/clusters; the wizard's default selection is jurisdiction-aware (from/me).entire auth tokenprints the active control-plane bearer for scripting/curl.Unchanged
entire repo mirror create <github-url> [cluster-host]keeps its fixed default cluster and behavior;remove/collaboratorsuntouched.Stacked on #1518 (OpenAPI refresh) — retarget to
mainonce that merges.🤖 Generated with Claude Code
Note
Medium Risk
Large user-facing change to mirror create (parallel API calls, new polling semantics) plus a hidden command that prints live bearer tokens; behavior is well-guarded (TLS, empty stdout on failure) but affects control-plane onboarding paths.
Overview
Adds interactive mirror onboarding when
entire repo mirror createruns with no arguments: onboardable repos from the API, regions fromGET /api/v1/clusters, jurisdiction-aware default region selection from/me, then parallel(repo × region)creates with per-line progress and a summary table plus clone URLs.Clone readiness no longer probes smart-HTTP
info/refsor mints repo-scoped tokens for the wait loop. One-shot and wizard paths sharecreateAndAwaitMirror, which polls control-planeMirror.statusviaawaitMirrorReadyand surfacesready,failed, andsuspendedconsistently; suspended placements now point users at support instead of an internal admin command.Also adds hidden
entire auth token(same bearer resolution as the API client, stdout-only for scripting), extends auth profile with jurisdiction, and treats cancelled wizard contexts as clean exits inhandleFormCancellation. The explicitcreate <github-url> [cluster-host]form keeps a fixed default cluster; catalog-based region picking is wizard-only.Reviewed by Cursor Bugbot for commit e5692a0. Configure here.