[Home](/content/site-root.html)

Log in

# Merge branch 'main' into nina/palette-remaining-huh-forms

`6134664`→[main](/content/gh/entireio/cli/commits/main/index.html)·

computermode·1w ago·24 files·+1,351 added/-263 removed

## Changes

24

- MCHANGELOG.md+21

- MCLAUDE.md+8/-1

- MREADME.md+4

- cmd/entire/cli

- Mcell\_fanout.go+103/-6

- Mcell\_fanout\_test.go+170/-1

- Mcorecmd.go+25/-3

- Mgrant.go+4/-5

- Mlabs.go-24

- Morg.go+4/-6

- Mproject.go+4/-6

- Mrepo.go+4/-6

- Mrepo\_mirror.go+236/-23

- Mrepo\_mirror\_test.go+433/-7

- review

- Mcmd.go+23/-24

- Mrun.go+13/-22

- Mrun\_test.go+43/-39

- Msynthesis\_sink.go+6/-2

- Msynthesis\_sink\_test.go+6/-5

- types

- Mreviewer.go+5/-4

- Mroot.go+4/-4

- Msearch\_cmd.go+44/-17

- Msearch\_cmd\_test.go+80/-17

- Msetup.go+55/-41

- Msetup\_test.go+56

```
4 unmodified lines

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

4 unmodified lines

The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [0.8.42] - 2026-07-08

### Added

- Cross-region code search (work in progress, behind `ENTIRE_CODE_SEARCH=1`): `--code` and `--case-sensitive` flags on `entire search` plus a Code tab in the search TUI, backed by peregrine. It fans out across mirror placements — listing repos, grouping them by cell, searching each cell in parallel with per-cell timeouts, and merging/deduping results client-side — rather than only hitting the home cell ([#1616](https://github.com/entireio/cli/pull/1616), [#1674](https://github.com/entireio/cli/pull/1674))
- `entire repo mirror list` gained a `--name` filter (matches the owner/repo form shown in the table) and `--sort` with shell-friendly kebab-case column keys, failing fast on an unknown sort key ([#1665](https://github.com/entireio/cli/pull/1665), [#1679](https://github.com/entireio/cli/pull/1679))

### Changed

- `entire review` no longer imposes a default reviewer timeout — reviewers run until done — while the judge's default rises from 5m to 20m; `--timeout` still governs both ([#1664](https://github.com/entireio/cli/pull/1664))
- `org`, `project`, `repo`, and `grant` are promoted out of `entire labs` into the visible top-level command surface, so they now appear in `entire --help` (canonical paths unchanged) ([#1672](https://github.com/entireio/cli/pull/1672))
- git-remote-entire prints an actionable hint when the cluster host is missing, and only suggests `clone` for a complete forge/owner/repo ref ([#1649](https://github.com/entireio/cli/pull/1649))

### Fixed

- `entire repo mirror get` resolves clone URLs via the owning cluster's login server instead of the control-plane core ([#1676](https://github.com/entireio/cli/pull/1676))

### Housekeeping

- Bump aws-actions/configure-aws-credentials from 6.2.1 to 6.2.2 ([#1670](https://github.com/entireio/cli/pull/1670))

## [0.8.1] - 2026-07-07

### Added
```

MCHANGELOG.md+21

```
21 unmodified lines

22
23
24
25
25
26
27
28
29 unmodified lines

58
59
60
61
62
63
64
65
66
67
68
69
70

21 unmodified lines

### Command Layout

The visible CLI is organized around five noun groups plus a small set of
The visible CLI is organized around a set of noun groups plus a small set of
top-level verbs. The groups are the canonical home for each verb; legacy
top-level shortcuts remain functional but hidden, and emit a deprecation hint
pointing at the canonical group form. Newer experimental command families are
29 unmodified lines

takes `--everywhere` (revoke every session on the active core, not just the
  current one) and `--all-contexts` (log out of every saved login)
- `doctor`: bare runs the scan-and-fix flow, plus `trace`, `logs`, `bundle`
- `org`: control-plane organization management — `create`, `list`, `get`, `delete`
- `project`: control-plane project management — `create`, `list`, `get`, `delete`
- `repo`: control-plane repository lifecycle — `create`, `list`, `get`, `delete`,
  `clone`, plus the `mirror` and `visibility` subtrees. Git content operations
  (log, diff, …) are intentionally out of scope.
- `grant`: manage access grants and org membership — `org`, `project`, and `repo`
  each support `add` / `list` / `remove`

Experimental command families advertised through `entire labs`:
```

MCLAUDE.md+8/-1

```
249 unmodified lines

250
251
252
253
254
255
256
257
258
259

249 unmodified lines

| `entire checkpoint explain` | Explain a session, commit, or checkpoint                                               |
| `entire checkpoint rewind` | Rewind to a previous checkpoint (deprecated, will be removed in a future release)       |
| `entire login`   | Authenticate the CLI with Entire device auth                                                      |
| `entire org`     | Manage Entire organizations (create, list, get, delete)                                           |
| `entire project` | Manage Entire projects (create, list, get, delete)                                                |
| `entire repo`    | Manage Entire repositories (create, list, get, delete, clone, mirror, visibility)                 |
| `entire grant`   | Manage access grants and org membership (org, project, repo)                                      |
| `entire session` | View and manage agent sessions tracked by Entire                                                  |
| `entire session resume`    | Switch to a branch, restore latest checkpointed session metadata, and show command(s) |
| `entire session attach`    | Attach to a previously detached session                                                |
```

MREADME.md+4

```
1 unmodified line

2
3
4
5
6
7
8
44 unmodified lines

53
54
55
56
57
58
59
60
61
62
63
64
57
58
65
66
67
68
60
69
70
62
63
71
72
73
74
75
76
77
78
69
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
23 unmodified lines

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
17 unmodified lines

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

1 unmodified line

import (
	"context"
	"net/url"
	"sort"
	"strings"
	"sync"
44 unmodified lines

// includes the jurisdiction so entries whose index row carries no cell don't
// collapse across jurisdictions into one group routed by whichever repo came
// first — they stay per-jurisdiction and route via the jurisdiction fallback.
//
// When a RepoIndexEntry has Placements, each placement is added to the group
// for its own cell/jurisdiction with its placement-specific repo ID. This
// ensures mirror placements in other regions (e.g. a US-homed repo with an EU
// mirror) are searched in both cells — matching the BFF's fan-out behavior.
// When Placements is empty, the top-level Cell/Jurisdiction/ID are used as
// before (backward compat for index responses that predate placements).
func groupReposByCell(repos []coreapi.RepoIndexEntry) []cellGroup {
	byCell := make(map[string]*cellGroup)
	for _, r := range repos {
		id := strings.TrimSpace(r.ID)

addToGroup := func(id, cell, jurisdiction, clusterSlug string) {
		id = strings.TrimSpace(id)
		if id == "" {
			continue
			return
		}
		cell := strings.ToLower(strings.TrimSpace(r.Cell))
		jurisdiction := strings.ToLower(strings.TrimSpace(r.Jurisdiction))
		cell = strings.ToLower(strings.TrimSpace(cell))
		jurisdiction = strings.ToLower(strings.TrimSpace(jurisdiction))
		clusterSlug = strings.ToLower(strings.TrimSpace(clusterSlug))
		key := cell + "\x00" + jurisdiction
		g, ok := byCell[key]
		if !ok {
			g = &cellGroup{
				cell:         cell,
				clusterSlug:  strings.ToLower(strings.TrimSpace(r.ClusterSlug)),
				clusterSlug:  clusterSlug,
				jurisdiction: jurisdiction,
			}
			byCell[key] = g
		}
		// Upgrade an empty slug if a later entry provides one (a mirror
		// placement may create the group before the home placement adds the
		// slug).
		if g.clusterSlug == "" && clusterSlug != "" {
			g.clusterSlug = clusterSlug
		}
		g.repoIDs = append(g.repoIDs, id)
	}

for _, r := range repos {
		if len(r.Placements) > 0 {
			for _, p := range r.Placements {
				// Placements don't carry a cluster slug; the top-level slug
				// applies only to the home placement. RepoPlacement.Mirror is
				// the contract-guaranteed home(false)/mirror(true) marker, so
				// assign the slug to the home placement and leave mirrors
				// slugless — resolveCellBaseURLs falls back to cell/jurisdiction
				// matching for groups without a slug. (Keying off Mirror rather
				// than p.Cell == r.Cell means the join still works if the index
				// omits the top-level Cell alongside the placement array.)
				slug := ""
				if !p.Mirror {
					slug = r.ClusterSlug
				}
				addToGroup(p.ID, p.Cell, p.Jurisdiction, slug)
			}
		} else {
			addToGroup(r.ID, r.Cell, r.Jurisdiction, r.ClusterSlug)
		}
	}

cells := make([]cellGroup, 0, len(byCell))
	for _, g := range byCell {
		cells = append(cells, *g)
23 unmodified lines

return
	}
	bySlug := make(map[string]coreapi.Cluster, len(clusters.Clusters))
	byJurisdiction := make(map[string]coreapi.Cluster, len(clusters.Clusters))
	for _, cl := range clusters.Clusters {
		bySlug[strings.ToLower(strings.TrimSpace(cl.Slug))] = cl
		// Prefer the default cluster per jurisdiction — matches the auth
		// layer's resolution when routing by jurisdiction alone. A non-default
		// cluster is kept only when no default has been seen yet.
		j := strings.ToLower(strings.TrimSpace(cl.Jurisdiction))
		if j != "" {
			existing, exists := byJurisdiction[j]
			if !exists || (cl.IsDefault && !existing.IsDefault) {
				byJurisdiction[j] = cl
			}
		}
	}
	for i := range cells {
		cl, ok := bySlug[cells[i].clusterSlug]
		if !ok && cells[i].cell != "" {
			// Try matching the group's cell name against catalog apiUrl
			// hosts (e.g. cell "aws-eu-central-1" matches
			// "https://aws-eu-central-1.api.entire.io"). This is more
			// precise than jurisdiction when a jurisdiction has multiple
			// cells — mirroring matchClusterByHost in cell_target.go.
			cl, ok = matchClusterByCellInURL(clusters.Clusters, cells[i].cell)
		}
		if !ok && cells[i].jurisdiction != "" {
			// Last resort: jurisdiction-level fallback using the default
			// cluster. Less precise, but still routes to the right
			// jurisdiction when the cell name doesn't appear in any URL.
			if cl, ok = byJurisdiction[cells[i].jurisdiction]; ok {
				// This binds the group to the jurisdiction's DEFAULT cluster,
				// which may not be the cell hosting this placement's repo. If
				// the placement lives in a non-default cell of the jurisdiction
				// the query can hit a cell that returns nothing — a silent
				// mirror miss. Log it so such a miss is diagnosable.
				logging.Debug(ctx, "cell fan-out: jurisdiction-default fallback used (cell name not in any catalog URL); may mis-route within jurisdiction",
					"cell", cells[i].cell, "jurisdiction", cells[i].jurisdiction, "resolved_cluster", cl.Slug)
			}
		}
		if !ok {
			logging.Debug(ctx, "cell fan-out: cluster not in catalog, using jurisdiction routing",
				"cluster_slug", cells[i].clusterSlug, "cell", cells[i].cell)
17 unmodified lines

}
}

// matchClusterByCellInURL finds a catalog cluster whose ApiUrl or PublicUrl
// host contains the cell name as a prefix (e.g. cell "aws-eu-central-1"
// matches "https://aws-eu-central-1.api.entire.io"). This is more precise
// than a jurisdiction-level fallback when multiple clusters share a
// jurisdiction — each cluster serves a different cell.
func matchClusterByCellInURL(clusters []coreapi.Cluster, cell string) (coreapi.Cluster, bool) {
	prefix := strings.ToLower(strings.TrimSpace(cell)) + "."
	for _, cl := range clusters {
		for _, rawURL := range []string{cl.ApiUrl.Or(""), cl.PublicUrl} {
			rawURL = strings.TrimSpace(rawURL)
			if rawURL == "" {
				continue
			}
			u, err := url.Parse(rawURL)
			if err != nil {
				continue
			}
			if strings.HasPrefix(strings.ToLower(u.Hostname()), prefix) {
				return cl, true
			}
		}
	}
	return coreapi.Cluster{}, false
}

// cellTarget converts the group's routing coordinates into the auth layer's
// CellTarget: full target when the catalog resolved a baseURL,
// jurisdiction-only when it didn't, nil (home routing) when neither is known.
```

Mcmd/entire/cli/cell\_fanout.go+103/-6

```
46 unmodified lines

47
48
49
50
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
36 unmodified lines

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

46 unmodified lines

if got := strings.Join(us.repoIDs, ","); got != "01B,01C" {
		t.Fatalf("us repoIDs = %q, want 01B,01C", got)
	}
	if us.clusterSlug != "us-prod" || us.jurisdiction != "us" {
	if us.clusterSlug != testClusterSlugUS || us.jurisdiction != "us" {
		t.Fatalf("us group coordinates = %+v, want us-prod/us", us)
	}
}

// TestGroupReposByCell_Placements verifies that when a repo has Placements,
// each placement is grouped into its own cell group with the placement-specific
// repo ID. This is the fix for cross-region fan-out: a US-homed repo with an
// EU mirror produces two cell groups so both cells are searched.
func TestGroupReposByCell_Placements(t *testing.T) {
	t.Parallel()
	repos := []coreapi.RepoIndexEntry{
		{
			// US-homed repo with an EU mirror — the real-world scenario.
			ID: "01US", Cell: "aws-us-east-2", ClusterSlug: "us-prod", Jurisdiction: "us",
			Placements: []coreapi.RepoPlacement{
				{ID: "01US", Cell: "aws-us-east-2", Jurisdiction: "us"},
				{ID: "01EU", Cell: "aws-eu-central-1", Jurisdiction: "eu", Mirror: true},
			},
		},
		{
			// Repo without placements (legacy index) — top-level fields used.
			ID: "01LEGACY", Cell: "aws-us-east-2", ClusterSlug: "us-prod", Jurisdiction: "us",
		},
	}
	cells := groupReposByCell(repos)
	if len(cells) != 2 {
		t.Fatalf("groups = %d, want 2 (one per cell): %+v", len(cells), cells)
	}
	// Sorted: aws-eu-central-1 < aws-us-east-2.
	eu := cells[0]
	us := cells[1]
	if eu.cell != "aws-eu-central-1" || eu.jurisdiction != "eu" {
		t.Fatalf("eu group = %+v", eu)
	}
	if got := strings.Join(eu.repoIDs, ","); got != "01EU" {
		t.Fatalf("eu repoIDs = %q, want 01EU", got)
	}
	// EU placement has no cluster slug (cell differs from top-level).
	if eu.clusterSlug != "" {
		t.Fatalf("eu clusterSlug = %q, want empty", eu.clusterSlug)
	}
	if us.cell != "aws-us-east-2" || us.jurisdiction != "us" {
		t.Fatalf("us group = %+v", us)
	}
	// US group has both the placement ID and the legacy entry.
	if got := strings.Join(us.repoIDs, ","); got != "01US,01LEGACY" {
		t.Fatalf("us repoIDs = %q, want 01US,01LEGACY", got)
	}
	// Home placement inherits the top-level cluster slug.
	if us.clusterSlug != testClusterSlugUS {
		t.Fatalf("us clusterSlug = %q, want us-prod", us.clusterSlug)
	}
}

// TestGroupReposByCell_PlacementEmptyID verifies that placements with empty IDs
// are skipped, matching the top-level behavior.
func TestGroupReposByCell_PlacementEmptyID(t *testing.T) {
	t.Parallel()
	repos := []coreapi.RepoIndexEntry{
		{
			ID: "01A", Cell: "aws-us-east-2", Jurisdiction: "us",
			Placements: []coreapi.RepoPlacement{
				{ID: "", Cell: "aws-us-east-2", Jurisdiction: "us"}, // empty ID → skipped
			},
		},
	}
	cells := groupReposByCell(repos)
	if len(cells) != 0 {
		t.Fatalf("groups = %d, want 0 (all placement IDs empty): %+v", len(cells), cells)
	}
}

// TestGroupReposByCell_PlacementSlugFromMirrorFlag verifies the home
// placement's cluster slug is assigned via RepoPlacement.Mirror rather than by
// string-matching the top-level Cell. When the index omits the top-level Cell
// alongside the placement array, the string-match would find no home and drop
// every group to the fuzzier fallback; keying off Mirror keeps the precise
// slug->catalog join.
func TestGroupReposByCell_PlacementSlugFromMirrorFlag(t *testing.T) {
	t.Parallel()
	repos := []coreapi.RepoIndexEntry{
		{
			// Top-level Cell intentionally empty; the home placement is
			// identified by Mirror=false, not by matching the top-level Cell.
			ID: "01US", ClusterSlug: "us-prod", Jurisdiction: "us",
			Placements: []coreapi.RepoPlacement{
				{ID: "01US", Cell: "aws-us-east-2", Jurisdiction: "us", Mirror: false},
				{ID: "01EU", Cell: "aws-eu-central-1", Jurisdiction: "eu", Mirror: true},
			},
		},
	}
	cells := groupReposByCell(repos)
	if len(cells) != 2 {
		t.Fatalf("groups = %d, want 2: %+v", len(cells), cells)
	}
	// Sorted: aws-eu-central-1 < aws-us-east-2.
	eu := cells[0]
	us := cells[1]
	if us.cell != "aws-us-east-2" || us.clusterSlug != testClusterSlugUS {
		t.Fatalf("home group = %+v, want cell aws-us-east-2 with slug us-prod", us)
	}
	if eu.cell != "aws-eu-central-1" || eu.clusterSlug != "" {
		t.Fatalf("mirror group = %+v, want cell aws-eu-central-1 with empty slug", eu)
	}
}

// TestResolveCellBaseURLs_RefusesBaseURLWithoutJurisdiction pins the guard: a
// concrete baseURL is only usable together with the jurisdiction its token
// must be minted for; a catalog row with no jurisdiction leaves the group on
36 unmodified lines

}
}

// TestResolveCellBaseURLs_JurisdictionFallbackForPlacements verifies that
// groups without a cluster slug (from placement-derived groups) resolve their
// baseURL via jurisdiction matching against the cluster catalog.
func TestResolveCellBaseURLs_JurisdictionFallbackForPlacements(t *testing.T) {
	t.Parallel()
	cells := []cellGroup{
		// Home group with slug — resolved via slug join.
		{cell: "aws-us-east-2", clusterSlug: "us-prod", jurisdiction: "us"},
		// Mirror group without slug — must fall back to jurisdiction join.
		{cell: "aws-eu-central-1", clusterSlug: "", jurisdiction: "eu"},
	}
	fake := &fakeCellCore{clusters: []coreapi.Cluster{
		{Slug: "us-prod", Jurisdiction: "us", ApiUrl: coreapi.NewOptString("https://aws-us-east-2.api.entire.io")},
		{Slug: "eu-prod", Jurisdiction: "eu", ApiUrl: coreapi.NewOptString("https://aws-eu-central-1.api.entire.io")},
	}}
	resolveCellBaseURLs(context.Background(), fake, cells)
	if cells[0].baseURL != "https://aws-us-east-2.api.entire.io" {
		t.Fatalf("us baseURL = %q, want resolved via slug", cells[0].baseURL)
	}
	if cells[1].baseURL != "https://aws-eu-central-1.api.entire.io" {
		t.Fatalf("eu baseURL = %q, want resolved via jurisdiction fallback", cells[1].baseURL)
	}
}

// TestResolveCellBaseURLs_CellURLMatchOverJurisdiction verifies that when a
// jurisdiction has multiple clusters, the resolver matches the group's cell
// name against cluster ApiUrl hosts rather than picking an arbitrary one.
// This prevents binding a mirror group to the wrong cell's baseURL.
func TestResolveCellBaseURLs_CellURLMatchOverJurisdiction(t *testing.T) {
	t.Parallel()
	cells := []cellGroup{
		// Mirror group whose cell name appears in the second cluster's URL.
		{cell: "aws-eu-central-1", clusterSlug: "", jurisdiction: "eu"},
	}
	fake := &fakeCellCore{clusters: []coreapi.Cluster{
		// Different EU cell — must NOT be picked even though it's first and default.
		{Slug: "eu-west-prod", Jurisdiction: "eu", IsDefault: true, ApiUrl: coreapi.NewOptString("https://aws-eu-west-1.api.entire.io")},
		// Matching cell — should be picked by cell-URL matching.
		{Slug: "eu-central-prod", Jurisdiction: "eu", ApiUrl: coreapi.NewOptString("https://aws-eu-central-1.api.entire.io")},
	}}
	resolveCellBaseURLs(context.Background(), fake, cells)
	if cells[0].baseURL != "https://aws-eu-central-1.api.entire.io" {
		t.Fatalf("eu baseURL = %q, want cell-matched URL, not default cluster", cells[0].baseURL)
	}
}

// TestResolveCellBaseURLs_JurisdictionFallbackPrefersDefault verifies that
// when cell-URL matching doesn't find a match, the jurisdiction fallback
// picks the cluster with IsDefault=true.
func TestResolveCellBaseURLs_JurisdictionFallbackPrefersDefault(t *testing.T) {
	t.Parallel()
	cells := []cellGroup{
		// Cell name doesn't appear in any cluster URL — falls through to jurisdiction.
		{cell: "aws-eu-unknown-1", clusterSlug: "", jurisdiction: "eu"},
	}
	fake := &fakeCellCore{clusters: []coreapi.Cluster{
		// Non-default listed first — must not win.
		{Slug: "eu-staging", Jurisdiction: "eu", ApiUrl: coreapi.NewOptString("https://eu-staging.api.entire.io")},
		// Default cluster — should be preferred.
		{Slug: "eu-prod", Jurisdiction: "eu", IsDefault: true, ApiUrl: coreapi.NewOptString("https://eu-default.api.entire.io")},
	}}
	resolveCellBaseURLs(context.Background(), fake, cells)
	if cells[0].baseURL != "https://eu-default.api.entire.io" {
		t.Fatalf("eu baseURL = %q, want default cluster's URL", cells[0].baseURL)
	}
}

func TestResolveCellBaseURLs_CatalogErrorLeavesJurisdictionRouting(t *testing.T) {
	t.Parallel()
	cells := []cellGroup{{cell: euWestCell, clusterSlug: "eu-prod", jurisdiction: "eu"}}
```

Mcmd/entire/cli/cell\_fanout\_test.go+170/-1

```
214 unmodified lines

215
216
217
218
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
2 unmodified lines

240
241
242
227
243
244
245
246
153 unmodified lines

400
401
402
403
404
405
406
407
408
409
410
411
14 unmodified lines

426
427
428
407
429
430
431
432

214 unmodified lines

// field/value list (default) or raw JSON (--json), reusing the same column
// definition as the matching list view.
func runCoreObject[T any](cmd *cobra.Command, headers []string, row func(T) []string, fn func(ctx context.Context, c *coreapi.Client) (*T, error)) error {
	return runCore(cmd, func(ctx context.Context, c *coreapi.Client) error {
	return runCore(cmd, renderCoreObject(cmd, headers, row, fn))
}

// runCoreObjectForCluster is runCoreObject for a resource-provider command (see
// runCoreForCluster): identical field/JSON rendering, but dialing the core that
// fronts clusterHost rather than the active context.
func runCoreObjectForCluster[T any](cmd *cobra.Command, clusterHost string, headers []string, row func(T) []string, fn func(ctx context.Context, c *coreapi.Client) (*T, error)) error {
	return runCoreForCluster(cmd, clusterHost, renderCoreObject(cmd, headers, row, fn))
}

// renderCoreObject builds the run-function shared by runCoreObject and
// runCoreObjectForCluster: fetch via fn, then render as a field/value list
// (default) or raw JSON (--json). Kept separate from the client-selection so
// the two object variants differ only in which core they dial (mirroring
// renderCoreList).
func renderCoreObject[T any](cmd *cobra.Command, headers []string, row func(T) []string, fn func(ctx context.Context, c *coreapi.Client) (*T, error)) func(context.Context, *coreapi.Client) error {
	return func(ctx context.Context, c *coreapi.Client) error {
		item, err := fn(ctx, c)
		if err != nil {
			return err
2 unmodified lines

return printJSON(cmd.OutOrStdout(), item)
		}
		return printFields(cmd.OutOrStdout(), headers, row(*item))
	})
	}
}

// tableStyles holds the foreground styles for the human table/field views,
153 unmodified lines

// without standing up the auth/context/TLS stack.
var activeCoreClient = func(context.Context) (*coreapi.Client, error) { return coreapi.New() }

// clusterCoreClient builds the control-plane client for cluster-addressed
// commands (see runCoreForCluster). Same test seam as activeCoreClient —
// production wiring is coreapi.NewForCluster, which does live /.well-known
// discovery that command-level tests must not reach.
var clusterCoreClient func(ctx context.Context, clusterHost string) (*coreapi.Client, error) = coreapi.NewForCluster

// runCore is the shared base for every active-context control-plane command:
// it owns the preamble only — silence usage, build the client, map API
// errors — and leaves all rendering to fn. The delete/revoke verbs call it
14 unmodified lines

// cluster_host". See coreapi.NewForCluster.
func runCoreForCluster(cmd *cobra.Command, clusterHost string, fn func(ctx context.Context, c *coreapi.Client) error) error {
	return runCoreClient(cmd, func(ctx context.Context) (*coreapi.Client, error) {
		return coreapi.NewForCluster(ctx, clusterHost)
		return clusterCoreClient(ctx, clusterHost)
	}, fn)
}
```

Mcmd/entire/cli/corecmd.go+25/-3

```
41 unmodified lines

42
43
44
45
45
46
47
47
48
49
50
1 unmodified line

52
53
54
55
56
57
55
56
57
58
59

41 unmodified lines

}
}

// newGrantCmd is the hidden `entire grant` command group: manage access
// newGrantCmd is the `entire grant` command group: manage access
// grants and org membership on the Entire control plane. Org, project, and
// repo each support add / list / remove. Surfaced via `entire labs`.
// repo each support add / list / remove.
//
// Grantees are addressed by a provider-qualified handle (e.g. github:alice),
// which the CLI resolves to the provider account behind the scenes. `remove`
1 unmodified line

// repo) are addressed by name or ULID.
func newGrantCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:    "grant",
		Short:  "Manage Entire access grants and org membership",
		Hidden: true,
		Use:   "grant",
		Short: "Manage Entire access grants and org membership",
	}
	addControlPlaneFlags(cmd)
	cmd.AddCommand(newGrantOrgCmd())
```

Mcmd/entire/cli/grant.go+4/-5

```
44 unmodified lines

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
48
49
50
54 unmodified lines

105
106
107
128
129
130
131
108
109
110

44 unmodified lines

Invocation:  "entire session tokens",
		Summary:     "Show token usage and recommendations for a session",
	},
	{
		CommandPath: []string{"org"},
		Invocation:  "entire org",
		Summary:     "Manage Entire organizations (create, list, get, delete)",
	},
	{
		CommandPath: []string{"project"},
		Invocation:  "entire project",
		Summary:     "Manage Entire projects (create, list, get, delete)",
	},
	{
		CommandPath: []string{"repo"},
		Invocation:  "entire repo",
		Summary:     "Manage Entire repositories (create, list, get, delete, clone, mirror, visibility)",
	},
	{
		CommandPath: []string{"grant"},
		Invocation:  "entire grant",
		Summary:     "Manage access grants and org membership (org, project, repo)",
	},
	{
		CommandPath: []string{"blame"},
		Invocation:  "entire blame",
54 unmodified lines

entire tokens --help
  entire tokens profile --help
  entire session tokens --help
  entire org --help
  entire project --help
  entire repo --help
  entire grant --help
  entire blame --help
  entire why --help
  entire experts --help
```

Mcmd/entire/cli/labs.go-24

```
8 unmodified lines

9
10
11
12
13
14
12
13
14
15
17
18
19
16
17
18
19
20

8 unmodified lines

"github.com/entireio/cli/internal/coreapi"
)

// newOrgCmd is the hidden `entire org` command group: create, list, get, and
// delete organizations on the Entire control plane. Surfaced via `entire
// labs` while the control-plane surface matures.
// newOrgCmd is the `entire org` command group: create, list, get, and
// delete organizations on the Entire control plane.
func newOrgCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:    "org",
		Short:  "Manage Entire organizations",
		Hidden: true,
		Use:   "org",
		Short: "Manage Entire organizations",
	}
	addControlPlaneFlags(cmd)
	cmd.AddCommand(newOrgCreateCmd())
```

Mcmd/entire/cli/org.go+4/-6

```
8 unmodified lines

9
10
11
12
13
14
12
13
14
15
17
18
19
16
17
18
19
20

8 unmodified lines

"github.com/entireio/cli/internal/coreapi"
)

// newProjectCmd is the hidden `entire project` command group: create, list,
// get, and delete projects on the Entire control plane. Surfaced via `entire
// labs`.
// newProjectCmd is the `entire project` command group: create, list,
// get, and delete projects on the Entire control plane.
func newProjectCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:    "project",
		Short:  "Manage Entire projects",
		Hidden: true,
		Use:   "project",
		Short: "Manage Entire projects",
	}
	addControlPlaneFlags(cmd)
	cmd.AddCommand(newProjectCreateCmd())
```

Mcmd/entire/cli/project.go+4/-6

```
11 unmodified lines

12
13
14
15
15
16
17
18
19
20
19
20
21
23
24
25
22
23
24
25
26

11 unmodified lines

"github.com/entireio/cli/internal/coreapi"
)

// newRepoCmd is the hidden `entire repo` command group: control-plane
// newRepoCmd is the `entire repo` command group: control-plane
// repository lifecycle (create, list within a project, get, delete), the
// `mirror` and `visibility` subtrees, plus the `clone` convenience that
// resolves a mirror and shells out to `git clone`. Other git content
// operations (log, diff, …) remain intentionally out of scope here. Surfaced
// via `entire labs`.
// operations (log, diff, …) remain intentionally out of scope here.
func newRepoCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:    "repo",
		Short:  "Manage Entire repositories",
		Hidden: true,
		Use:   "repo",
		Short: "Manage Entire repositories",
	}
	addControlPlaneFlags(cmd)
	cmd.AddCommand(newRepoCreateCmd())
```

Mcmd/entire/cli/repo.go+4/-6

```
1
2
3
4
5
6
7
1 unmodified line

9
10
11
12
13
14
15
2 unmodified lines

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
20
21
22
23
24
25
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
30
31
32
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
34
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
3 unmodified lines

200
201
202
44
203
204
205
206
298 unmodified lines

505
506
507
349
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
357
528
529
530
531
9 unmodified lines

541
542
543
373
544
545
546
547
548
549
550
376
551
552
553
554
7 unmodified lines

562
563
564
390
565
566
567
568
13 unmodified lines

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
2 unmodified lines

606
607
608
424
425
426
609
610
611
612
613
614
615
616
617
618
619
431
432
620
621
622
623
624
625
626
437
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
10 unmodified lines

657
658
659
454
660
661
662
663
56 unmodified lines

720
721
722
723
724
725
726
727
728
729
730
731
732

package cli

import (
	"cmp"
	"context"
	"errors"
	"fmt"
1 unmodified line

"net"
	"net/url"
	"regexp"
	"slices"
	"strings"
	"time"

2 unmodified lines

"github.com/entireio/cli/internal/coreapi"
)

// column is a table column with two separable identities: key is the canonical
// name a caller types for --sort (and the value parseSortColumn returns, so the
// sort switches compare against these constants directly); header is the text
// shown in the table. They differ only where the header carries a display hint
// the sort key shouldn't — e.g. NAME's inline "(owner/repo)" — which keeps
// --sort matching a simple equality on key with no header parsing.
type column struct {
	key    string
	header string
}

// Keys are lower-case, single shell tokens (kebab-case for multi-word columns)
// so `--sort clone-url` needs no quoting; headers stay upper-case display text.
var (
	colName     = column{key: "name", header: "NAME (owner/repo)"}
	colCloneURL = column{key: "clone-url", header: "CLONE URL"}
	colPrivate  = column{key: "private", header: "PRIVATE"}
	colAccess   = column{key: "access", header: "ACCESS"}
	colStatus   = column{key: "status", header: "STATUS"}
)

// columnHeaders is the display-header view of a column set, for the table/field
// renderers (runCoreList/runCoreObject) which take plain header strings.
func columnHeaders(cols []column) []string {
	h := make([]string, len(cols))
	for i, c := range cols {
		h[i] = c.header
	}
	return h
}

// mirrorColumns is the human table/field view of a mirror: the scannable
// repo name, the clone URL you'd copy, and whether the upstream is
// private. The cluster is omitted — it's already embedded in the clone
// URL — and the wire model's internal ids are dropped entirely. The clone
// URL is synthesised from the mirror's coords (the form `git clone`
// accepts), since the list API doesn't return it.
var mirrorColumns = []string{"REPO", "CLONE URL", "PRIVATE"}
// owner/repo name, the clone URL you'd copy, and whether the upstream is
// private. Owner, provider, and cluster aren't columns of their own — they're
// inferable from the owner/repo pair and the clone URL
// (entire://<cluster>/gh/<owner>/<repo>). `--name` filters on the owner/repo
// name only; owner/provider/cluster stay server-side filters, and the wire
// model's internal ids are dropped. The clone URL is synthesised from the
// mirror's coords (the form `git clone` accepts), since the list API doesn't
// return it.
var mirrorColumns = []column{colName, colCloneURL, colPrivate}

// mirrorPrivate renders the PRIVATE column ("yes"/"no"), shared by the table
// row and the --sort private key so both agree on the cell value.
func mirrorPrivate(m coreapi.Mirror) string {
	if m.IsPrivate.Or(false) {
		return "yes"
	}
	return "no"
}

func mirrorRow(m coreapi.Mirror) []string {
	repo := m.Owner + "/" + m.Repo
	cloneURL := mirrorCloneURL(m.ClusterHost, m.Owner, m.Repo)
	private := "no"
	if m.IsPrivate.Or(false) {
		private = "yes"
	return []string{repo, cloneURL, mirrorPrivate(m)}
}

// parseSortColumn resolves a --sort spec to the column it names and a
// direction. It trims first, then reads the '-' prefix, so leading/trailing
// whitespace is handled identically on every path (the direction and the column
// name never disagree). An empty spec selects the first column. A spec matches a
// column by its key (case-insensitive) — a plain equality, since key holds no
// display hint. An unknown name errors naming the valid keys. Returning the
// matched column lets callers switch on the col* constants directly.
func parseSortColumn(spec string, columns []column) (col column, desc bool, err error) {
	spec = strings.TrimSpace(spec)
	desc = strings.HasPrefix(spec, "-")
	name := strings.TrimSpace(strings.TrimPrefix(spec, "-"))
	if name == "" {
		return columns[0], desc, nil
	}
	return []string{repo, cloneURL, private}
	for _, c := range columns {
		if strings.EqualFold(c.key, name) {
			return c, desc, nil
		}
	}
	valid := make([]string, len(columns))
	for i, c := range columns {
		valid[i] = c.key
	}
	return column{}, false, fmt.Errorf("unknown sort column %q; valid columns: %s", name, strings.Join(valid, ", "))
}

// sortMirrors orders mirrors in place by the --sort spec: by the named column's
// value ascending (case-insensitive), always breaking ties by owner/repo then
// cluster host so a repo mirrored across clusters (or rows equal on any other
// column) has a stable, deterministic order rather than arbitrary server order.
// A '-' prefix reverses the whole ordering. `name`/default sorts by the
// tiebreak alone.
func sortMirrors(mirrors []coreapi.Mirror, spec string) error {
	col, desc, err := parseSortColumn(spec, mirrorColumns)
	if err != nil {
		return err
	}
	key := func(m coreapi.Mirror) string {
		switch col {
		case colCloneURL:
			return strings.ToLower(mirrorCloneURL(m.ClusterHost, m.Owner, m.Repo))
		case colPrivate:
			return mirrorPrivate(m)
		default: // name -> tiebreak alone
			return ""
		}
	}
	slices.SortStableFunc(mirrors, func(a, b coreapi.Mirror) int {
		c := cmp.Compare(key(a), key(b))
		if c == 0 {
			c = cmp.Compare(strings.ToLower(a.Owner+"/"+a.Repo), strings.ToLower(b.Owner+"/"+b.Repo))
		}
		if c == 0 {
			c = cmp.Compare(strings.ToLower(a.ClusterHost), strings.ToLower(b.ClusterHost))
		}
		if desc {
			return -c
		}
		return c
	})
	return nil
}

// sortAvailable orders available mirrors in place by the --sort spec, matching
// sortMirrors: by the named column ascending (case-insensitive) with an
// owner/repo tiebreak for a deterministic order on equal keys. AvailableMirror
// has no cluster host (the onboardable set is cluster-agnostic), so owner/repo
// is the only secondary key. A '-' prefix reverses the whole ordering.
func sortAvailable(avail []coreapi.AvailableMirror, spec string) error {
	col, desc, err := parseSortColumn(spec, availableMirrorColumns)
	if err != nil {
		return err
	}
	key := func(m coreapi.AvailableMirror) string {
		switch col {
		case colAccess:
			return strings.ToLower(string(m.Access))
		case colStatus:
			return strings.ToLower(string(m.Status))
		default: // name -> tiebreak alone
			return ""
		}
	}
	slices.SortStableFunc(avail, func(a, b coreapi.AvailableMirror) int {
		c := cmp.Compare(key(a), key(b))
		if c == 0 {
			c = cmp.Compare(strings.ToLower(a.Owner+"/"+a.Repo), strings.ToLower(b.Owner+"/"+b.Repo))
		}
		if desc {
			return -c
		}
		return c
	})
	return nil
}

// filterByName keeps items whose owner/repo name contains substr (case-
// insensitive). The control plane already filters by owner/provider/cluster
// server-side but not by name, so `repo mirror list --name` narrows that last
// dimension client-side. nameOf returns the item's displayed identifier — the
// callers pass the owner/repo form shown in the NAME column, so a value copied
// from the table (e.g. acme/web) matches the row it came from. An empty substr
// returns items unchanged.
func filterByName[T any](items []T, nameOf func(T) string, substr string) []T {
	substr = strings.TrimSpace(substr)
	if substr == "" {
		return items
	}
	substr = strings.ToLower(substr)
	out := make([]T, 0, len(items))
	for _, it := range items {
		if strings.Contains(strings.ToLower(nameOf(it)), substr) {
			out = append(out, it)
		}
	}
	return out
}

// availableMirrorColumns is the view of a repo you *could* mirror: the
3 unmodified lines

// clone URL), or "owner-only" (a personal repo of another user; only its
// owner may mirror it). No clone URL column: an un-onboarded repo doesn't
// have one yet.
var availableMirrorColumns = []string{"REPO", "ACCESS", "STATUS"}
var availableMirrorColumns = []column{colName, colAccess, colStatus}

func availableMirrorRow(m coreapi.AvailableMirror) []string {
	return []string{m.Owner + "/" + m.Repo, string(m.Access), string(m.Status)}
298 unmodified lines

}

func newRepoMirrorListCmd() *cobra.Command {
	var cluster, provider, owner string
	var cluster, provider, owner, name string
	var sortSpec string
	var showAvailable bool
	cmd := &cobra.Command{
		Use:   "list",
		Short: "List mirrors you can see (or, with --show-available, repos you could mirror)",
		Args:  cobra.NoArgs,
		// Validate --sort before RunE so a bad column fails fast, without the
		// network round-trip RunE would otherwise do first. The valid column
		// set depends on --show-available (different table shape).
		PreRunE: func(_ *cobra.Command, _ []string) error {
			cols := mirrorColumns
			if showAvailable {
				cols = availableMirrorColumns
			}
			_, _, err := parseSortColumn(sortSpec, cols)
			return err
		},
		RunE: func(cmd *cobra.Command, _ []string) error {
			if showAvailable {
				return runCoreList(cmd, "No repos available to mirror.", availableMirrorColumns, availableMirrorRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.AvailableMirror, error) {
				return runCoreList(cmd, "No repos available to mirror.", columnHeaders(availableMirrorColumns), availableMirrorRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.AvailableMirror, error) {
					// Computed live from GitHub using your own login, so name the
					// core being dialled (same rationale as the existing-mirror
					// banner). --cluster/--provider don't apply here: the
9 unmodified lines

if err != nil {
						return nil, err
					}
					return out.Available, nil
					avail := filterByName(out.Available, func(m coreapi.AvailableMirror) string { return m.Owner + "/" + m.Repo }, name)
					if err := sortAvailable(avail, sortSpec); err != nil {
						return nil, err
					}
					return avail, nil
				})
			}
			return runCoreList(cmd, "No mirrors found.", mirrorColumns, mirrorRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.Mirror, error) {
			return runCoreList(cmd, "No mirrors found.", columnHeaders(mirrorColumns), mirrorRow, func(ctx context.Context, c *coreapi.Client) ([]coreapi.Mirror, error) {
				// mirror list is identity-scoped: it shows the mirrors visible
				// from the active login's federation, so naming that login server
				// makes a surprising empty result legible — e.g. mirrors in a
7 unmodified lines

if !jsonRequested(cmd) {
					fmt.Fprintf(cmd.ErrOrStderr(), "Listing mirrors on %s\n", c.CoreOrigin())
				}
				return fetchAllPages(ctx, func(ctx context.Context, cursor string) ([]coreapi.Mirror, string, error) {
				mirrors, err := fetchAllPages(ctx, func(ctx context.Context, cursor string) ([]coreapi.Mirror, string, error) {
					params := coreapi.ListMirrorsParams{}
					if cluster != "" {
						params.Cluster = coreapi.NewOptString(cluster)
13 unmodified lines

}
					return out.Mirrors, out.NextPageToken.Or(""), nil
				})
				if err != nil {
					return nil, err
				}
				mirrors = filterByName(mirrors, func(m coreapi.Mirror) string { return m.Owner + "/" + m.Repo }, name)
				if err := sortMirrors(mirrors, sortSpec); err != nil {
					return nil, err
				}
				return mirrors, nil
			})
		},
	}
	cmd.Flags().StringVar(&cluster, "cluster", "", "Filter by cluster public host")
	cmd.Flags().StringVar(&provider, "provider", "", "Filter by upstream provider (e.g. github)")
	cmd.Flags().StringVar(&owner, "owner", "", "Filter by upstream owner login")
	cmd.Flags().StringVar(&name, "name", "", "Filter by owner/repo substring, matching the NAME column (case-insensitive)")
	cmd.Flags().StringVar(&sortSpec, "sort", "", "Sort by column key (e.g. name, clone-url; prefix '-' for descending). Default: name ascending")
	cmd.Flags().BoolVar(&showAvailable, "show-available", false, "Instead of existing mirrors, list GitHub repos you could onboard as mirrors (ignores --cluster/--provider)")
	return cmd
}
2 unmodified lines

return &cobra.Command{
		Use:   "get <mirror>",
		Short: "Show a mirror by ULID or clone URL",
		Long: "Show a mirror. <mirror> is either a mirror ULID or an entire:// clone " +
			"URL\n(entire://<cluster>/gh/<owner>/<repo>) — the form `mirror list` " +
			"prints and `git clone` accepts.",
		Long: "Show a mirror. <mirror> is either a mirror ULID or an entire:// clone URL\n" +
			"(entire://<cluster>/gh/<owner>/<repo>) — the form `mirror list` prints and\n" +
			"`git clone` accepts; a trailing .git, as pasted from `git remote -v`, is\n" +
			"accepted too. A clone URL is looked up on the login server fronting its\n" +
			"cluster, so it resolves even when that cluster belongs to a federation other\n" +
			"than the active auth context; a ULID is looked up on the active context's\n" +
			"login server.",
		Example: "  entire repo mirror get 01KS6KFJR2XS6PZ188MVYE07AN\n" +
			"  entire repo mirror get entire://aws-us-east-2.entire.io/gh/octocat/hello-world",
		Args: cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return runCoreObject(cmd, mirrorColumns, mirrorRow, func(ctx context.Context, c *coreapi.Client) (*coreapi.Mirror, error) {
				mirrorID, err := resolveMirrorRef(ctx, c, args[0])
			ref := args[0]
			show := func(ctx context.Context, c *coreapi.Client) (*coreapi.Mirror, error) {
				mirrorID, err := resolveMirrorRef(ctx, c, ref)
				if err != nil {
					return nil, err
				}
				return c.GetMirror(ctx, coreapi.GetMirrorParams{MirrorId: mirrorID})
			})
			}
			// A ULID carries no cluster coordinate, so it can only be looked up
			// on the active context's core. A clone URL names its cluster — dial
			// the core fronting that cluster (discovered from its well-known and
			// authenticated with the matching local context, the same path
			// create/remove use), so the lookup works when the mirror lives in a
			// federation other than the active login instead of failing with
			// "no mirror matching".
			if looksLikeULID(ref) {
				return runCoreObject(cmd, columnHeaders(mirrorColumns), mirrorRow, show)
			}
			clusterHost, _, _, _, err := parseMirrorCloneURL(ref)
			if err != nil {
				cmd.SilenceUsage = true
				return badMirrorRefErr(err)
			}
			return runCoreObjectForCluster(cmd, clusterHost, columnHeaders(mirrorColumns), mirrorRow, show)
		},
	}
}
10 unmodified lines

}
	clusterHost, provider, owner, repo, err := parseMirrorCloneURL(ref)
	if err != nil {
		return "", fmt.Errorf("%w; pass a mirror ULID or a clone URL (entire://<cluster>/gh/<owner>/<repo>)", err)
		return "", badMirrorRefErr(err)
	}
	mirrors, err := fetchAllPages(ctx, func(ctx context.Context, cursor string) ([]coreapi.Mirror, string, error) {
		params := coreapi.ListMirrorsParams{
56 unmodified lines

return fmt.Errorf("no mirror matching %q (run `entire repo mirror list` to see clone URLs, or pass a ULID)", ref)
}

// badMirrorRefErr wraps a clone-URL parse failure with the accepted <mirror>
// forms. Shared by the pre-dial parse in `mirror get` and resolveMirrorRef so
// both boundaries report identically.
func badMirrorRefErr(err error) error {
	return fmt.Errorf("%w; pass a mirror ULID or a clone URL (entire://<cluster>/gh/<owner>/<repo>)", err)
}

func newRepoMirrorRemoveCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "remove <github-url> [cluster-host]",
```

Mcmd/entire/cli/repo\_mirror.go+236/-23

```
377 unmodified lines

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
385
386
387
388
389
390
391
401
402
403
404
405
406
82 unmodified lines

489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
182 unmodified lines

858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
244 unmodified lines

1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343

377 unmodified lines

return recCh
}

// execMirrorList runs `list` under a parent that carries the control-plane
// persistent flags (--json lives there, not on the list command itself), so
// tests can exercise --json and the client-side --name/--sort together.
func execMirrorList(t *testing.T, args ...string) (stdout, stderr string, err error) {
	t.Helper()
	parent := &cobra.Command{Use: "mirror"}
	addControlPlaneFlags(parent)
	parent.AddCommand(newRepoMirrorListCmd())
	var out, errOut bytes.Buffer
	parent.SetOut(&out)
	parent.SetErr(&errOut)
	parent.SetArgs(append([]string{"list"}, args...))
	err = parent.ExecuteContext(t.Context())
	return out.String(), errOut.String(), err
}

// runMirrorList executes `repo mirror list` with args against the fake server,
// returning stdout (the table/JSON) and stderr (the routing banner).
func runMirrorList(t *testing.T, args ...string) (stdout, stderr string) {
	t.Helper()
	cmd := newRepoMirrorListCmd()
	var out, errOut bytes.Buffer
	cmd.SetOut(&out)
	cmd.SetErr(&errOut)
	cmd.SetArgs(args)
	require.NoError(t, cmd.ExecuteContext(t.Context()))
	return out.String(), errOut.String()
	stdout, stderr, err := execMirrorList(t, args...)
	require.NoError(t, err)
	return stdout, stderr
}

// TestRepoMirrorList_ShowAvailableRouting locks in the flag-driven branch of
82 unmodified lines

})
}

// runMirrorListErr is runMirrorList for the error paths (bad --sort column): it
// returns the command error instead of asserting success.
func runMirrorListErr(t *testing.T, args ...string) error {
	t.Helper()
	_, _, err := execMirrorList(t, args...)
	return err
}

// requireOrder asserts each needle appears in s, in the given order. It guards
// presence first: strings.Index returns -1 for an absent needle, so a bare
// index comparison would pass when the earlier needle is missing entirely
// (-1 < anyPresentIndex). This fails loudly instead.
func requireOrder(t *testing.T, s string, needles ...string) {
	t.Helper()
	prev := -1
	for _, n := range needles {
		i := strings.Index(s, n)
		require.GreaterOrEqualf(t, i, 0, "expected %q in output", n)
		require.Greaterf(t, i, prev, "expected %q to come after the previous item", n)
		prev = i
	}
}

// TestRepoMirrorList_FilterSort pins the client-side --name filter and --sort
// applied to `repo mirror list` before rendering (server handles
// owner/provider/cluster), so they shape both the table and --json output and
// work under --show-available.
//
// Not parallel: swaps the package-level activeCoreClient seam.
func TestRepoMirrorList_FilterSort(t *testing.T) {
	mirrors := []coreapi.Mirror{
		{Owner: "acme", Repo: "web", ClusterHost: "aws-us-east-2.entire.io"},
		{Owner: "acme", Repo: "cli", ClusterHost: "aws-us-east-2.entire.io"},
		{Owner: "other", Repo: "api", ClusterHost: "eu-west-1.entire.io"},
	}

t.Run("--name narrows the table by owner/repo substring", func(t *testing.T) {
		serveMirrorList(t, mirrors, nil)
		stdout, _ := runMirrorList(t, "--name", "cli")
		require.Contains(t, stdout, "acme/cli")
		require.NotContains(t, stdout, "acme/web")
		require.NotContains(t, stdout, "other/api")
	})

t.Run("--name matches the owner/repo form shown in the NAME column", func(t *testing.T) {
		// A value copied straight from the displayed NAME column must match the
		// row it came from; filtering on the bare repo name would drop it.
		serveMirrorList(t, mirrors, nil)
		stdout, _ := runMirrorList(t, "--name", "acme/web")
		require.Contains(t, stdout, "acme/web")
		require.NotContains(t, stdout, "acme/cli")
		require.NotContains(t, stdout, "other/api")
	})

t.Run("default output is owner/repo sorted", func(t *testing.T) {
		serveMirrorList(t, mirrors, nil)
		stdout, _ := runMirrorList(t)
		// acme/cli < acme/web < other/api by owner/repo
		requireOrder(t, stdout, "acme/cli", "acme/web", "other/api")
	})

t.Run("--sort -name reverses the order", func(t *testing.T) {
		serveMirrorList(t, mirrors, nil)
		stdout, _ := runMirrorList(t, "--sort", "-name")
		requireOrder(t, stdout, "other/api", "acme/web", "acme/cli")
	})

t.Run("--sort name resolves the NAME column by its key", func(t *testing.T) {
		// The NAME header carries an inline "(owner/repo)" display hint, but the
		// sort key is the plain "name" — --sort matches on key, not header.
		serveMirrorList(t, mirrors, nil)
		stdout, _ := runMirrorList(t, "--sort", "name")
		requireOrder(t, stdout, "acme/cli", "acme/web", "other/api")
	})

t.Run("--name applies to --json and keeps [] not null", func(t *testing.T) {
		serveMirrorList(t, mirrors, nil)
		// The JSON keys come from the raw coreapi model, unaffected by the NAME
		// column/flag rename — the wire field stays "repo".
		stdout, _ := runMirrorList(t, "--name", "cli", "--json")
		require.Contains(t, stdout, `"repo": "cli"`)
		require.NotContains(t, stdout, `"repo": "web"`)

serveMirrorList(t, mirrors, nil)
		stdout, _ = runMirrorList(t, "--name", "zzz", "--json")
		require.Contains(t, stdout, "[]")
		require.NotContains(t, stdout, "null")
	})

t.Run("unknown --sort column errors naming valid columns", func(t *testing.T) {
		serveMirrorList(t, mirrors, nil)
		err := runMirrorListErr(t, "--sort", "nope")
		require.Error(t, err)
		require.Contains(t, err.Error(), "unknown sort column")
	})

t.Run("default order breaks duplicate-repo ties by cluster ascending", func(t *testing.T) {
		// Same repo on two clusters, delivered eu-first; the default sort must
		// deterministically place aws before eu.
		dupes := []coreapi.Mirror{
			{Owner: "acme", Repo: "web", ClusterHost: "eu-west-1.entire.io"},
			{Owner: "acme", Repo: "web", ClusterHost: "aws-us-east-2.entire.io"},
		}
		serveMirrorList(t, dupes, nil)
		stdout, _ := runMirrorList(t)
		requireOrder(t, stdout,
			"entire://aws-us-east-2.entire.io/gh/acme/web",
			"entire://eu-west-1.entire.io/gh/acme/web",
		)
	})

t.Run("explicit --sort name keeps the cluster tiebreak (matches default)", func(t *testing.T) {
		// A repo on two clusters plus a lexically-earlier repo. Explicit
		// `--sort name` must order like the default: owner/repo ascending, and
		// within the duplicate tie, cluster ascending (aws before eu). Guards
		// against `--sort name` regressing to a plain single-key sort that would
		// drop the tiebreak.
		dupes := []coreapi.Mirror{
			{Owner: "acme", Repo: "web", ClusterHost: "eu-west-1.entire.io"},
			{Owner: "acme", Repo: "web", ClusterHost: "aws-us-east-2.entire.io"},
			{Owner: "acme", Repo: "api", ClusterHost: "aws-us-east-2.entire.io"},
		}
		serveMirrorList(t, dupes, nil)
		stdout, _ := runMirrorList(t, "--sort", "name")
		// acme/api before acme/web, and within the acme/web tie aws before eu.
		requireOrder(t, stdout,
			"entire://aws-us-east-2.entire.io/gh/acme/api",
			"entire://aws-us-east-2.entire.io/gh/acme/web",
			"entire://eu-west-1.entire.io/gh/acme/web",
		)

// -name reverses the whole ordering, tiebreak included.
		serveMirrorList(t, dupes, nil)
		stdout, _ = runMirrorList(t, "--sort", "-name")
		requireOrder(t, stdout,
			"entire://eu-west-1.entire.io/gh/acme/web",
			"entire://aws-us-east-2.entire.io/gh/acme/web",
		)
	})

t.Run("--name/--sort apply under --show-available", func(t *testing.T) {
		// --name cli keeps two rows (so --sort is observable) and drops the
		// third, so the filter and the sort are both exercised: `access` orders
		// read before write, i.e. cli-web before cli-api.
		serveMirrorList(t, nil, []coreapi.AvailableMirror{
			{Owner: "acme", Repo: "cli-api", Access: "write", Status: "available"},
			{Owner: "acme", Repo: "cli-web", Access: "read", Status: "available"},
			{Owner: "other", Repo: "srv", Access: "read", Status: "available"},
		})
		stdout, _ := runMirrorList(t, "--show-available", "--name", "cli", "--sort", "access")
		require.NotContains(t, stdout, "other/srv", "--name cli must drop the non-matching row")
		requireOrder(t, stdout, "acme/cli-web", "acme/cli-api")
	})

t.Run("--sort private breaks ties deterministically by owner/repo then cluster", func(t *testing.T) {
		// A non-name column sort: all rows share the same private value, so the
		// order must fall back to the owner/repo + cluster tiebreak rather than
		// the eu-first order the server delivered.
		dupes := []coreapi.Mirror{
			{Owner: "acme", Repo: "web", ClusterHost: "eu-west-1.entire.io"},
			{Owner: "acme", Repo: "web", ClusterHost: "aws-us-east-2.entire.io"},
			{Owner: "acme", Repo: "api", ClusterHost: "aws-us-east-2.entire.io"},
		}
		serveMirrorList(t, dupes, nil)
		stdout, _ := runMirrorList(t, "--sort", "private")
		// All rows share the private value, so acme/api sorts before acme/web,
		// and within the acme/web tie aws before eu.
		requireOrder(t, stdout,
			"entire://aws-us-east-2.entire.io/gh/acme/api",
			"entire://aws-us-east-2.entire.io/gh/acme/web",
			"entire://eu-west-1.entire.io/gh/acme/web",
		)
	})

t.Run("--sort with leading whitespace parses direction like the trimmed spec", func(t *testing.T) {
		serveMirrorList(t, mirrors, nil)
		stdout, _ := runMirrorList(t, "--sort", " -name")
		requireOrder(t, stdout, "other/api", "acme/web", "acme/cli")
	})
}

// TestParseGitHubURL is ported from entiredb's cmd/entire-repo/cli
// mirror_test.go, since parseGitHubURL was carried over verbatim.
func TestParseGitHubURL(t *testing.T) {
182 unmodified lines

})
}

// TestRepoMirrorGet_Routing pins which core `mirror get <ref>` dials. A clone
// URL names its cluster, so it must be resolved on the core fronting that
// cluster (clusterCoreClient), not the active context — the original bug:
// `mirror get entire://<cluster>/…` for a cluster in a federation other than
// the active login failed with "no mirror matching" until the user switched
// contexts. A ULID carries no cluster coordinate and stays on the active
// context; an unparseable ref must error before dialing anything.
//
// Not parallel: swaps the package-level activeCoreClient/clusterCoreClient
// seams.
func TestRepoMirrorGet_Routing(t *testing.T) {
	const mirrorULID = "0123456789ABCDEFGHJKMNPQRS"
	const clusterHost = "eukanuba.partial.to"
	const cloneURL = "entire://" + clusterHost + "/gh/entirehq/librarian"

// mirrorServer answers both the list (clone-URL resolution) and the
	// GetMirror-by-ULID calls for the librarian mirror.
	mirrorServer := func(t *testing.T) *httptest.Server {
		t.Helper()
		srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Type", "application/json")
			switch r.URL.Path {
			case mirrorsAPIPath:
				assert.NoError(t, printJSON(w, &coreapi.ListMirrorsOutputBody{Mirrors: []coreapi.Mirror{
					{MirrorId: mirrorULID, Owner: "entirehq", Repo: "librarian", ClusterHost: clusterHost},
				}}))
			case mirrorsAPIPath + "/" + mirrorULID:
				assert.NoError(t, printJSON(w, &coreapi.Mirror{
					MirrorId: mirrorULID, Owner: "entirehq", Repo: "librarian", ClusterHost: clusterHost,
					IsPrivate: coreapi.NewOptBool(true),
				}))
			default:
				t.Errorf("unexpected request path %q", r.URL.Path)
				w.WriteHeader(http.StatusNotFound)
			}
		}))
		t.Cleanup(srv.Close)
		return srv
	}
	seamActive := func(t *testing.T, fn func(context.Context) (*coreapi.Client, error)) {
		t.Helper()
		prev := activeCoreClient
		activeCoreClient = fn
		t.Cleanup(func() { activeCoreClient = prev })
	}
	seamCluster := func(t *testing.T, fn func(context.Context, string) (*coreapi.Client, error)) {
		t.Helper()
		prev := clusterCoreClient
		clusterCoreClient = fn
		t.Cleanup(func() { clusterCoreClient = prev })
	}
	runGet := func(t *testing.T, ref string) (string, error) {
		t.Helper()
		cmd := newRepoCmd()
		var out, errW bytes.Buffer
		cmd.SetOut(&out)
		cmd.SetErr(&errW)
		cmd.SetArgs([]string{"mirror", "get", ref})
		err := cmd.ExecuteContext(t.Context())
		return out.String(), err
	}

t.Run("clone URL dials the cluster's core, not the active context", func(t *testing.T) {
		srv := mirrorServer(t)
		seamActive(t, func(context.Context) (*coreapi.Client, error) {
			t.Error("clone-URL get dialed the active context's core")
			return nil, errors.New("wrong core")
		})
		var gotHost string
		seamCluster(t, func(_ context.Context, host string) (*coreapi.Client, error) {
			gotHost = host
			return coreapi.NewWithBearer(srv.URL, "tok")
		})
		out, err := runGet(t, cloneURL)
		require.NoError(t, err)
		require.Equal(t, clusterHost, gotHost, "must resolve on the clone URL's cluster")
		require.Contains(t, out, "entirehq/librarian")
		require.Contains(t, out, cloneURL)
	})

t.Run("ULID dials the active context", func(t *testing.T) {
		srv := mirrorServer(t)
		seamActive(t, func(context.Context) (*coreapi.Client, error) {
			return coreapi.NewWithBearer(srv.URL, "tok")
		})
		seamCluster(t, func(_ context.Context, host string) (*coreapi.Client, error) {
			t.Errorf("ULID get dialed cluster core %q; a ULID has no cluster coordinate", host)
			return nil, errors.New("wrong core")
		})
		out, err := runGet(t, mirrorULID)
		require.NoError(t, err)
		require.Contains(t, out, "entirehq/librarian")
	})

t.Run("unparseable ref errors before dialing any core", func(t *testing.T) {
		seamActive(t, func(context.Context) (*coreapi.Client, error) {
			t.Error("unparseable ref dialed the active context's core")
			return nil, errors.New("no dial expected")
		})
		seamCluster(t, func(context.Context, string) (*coreapi.Client, error) {
			t.Error("unparseable ref dialed a cluster core")
			return nil, errors.New("no dial expected")
		})
		_, err := runGet(t, "not-a-url")
		require.Error(t, err)
		require.ErrorContains(t, err, "pass a mirror ULID or a clone URL")
	})
}

func TestMirrorRow(t *testing.T) {
	t.Parallel()
	tests := []struct {
244 unmodified lines

require.Empty(t, out.String())
	})
}

// mirrorRepoHosts renders each mirror as "owner/repo@clusterHost" so a sorted
// slice's order (including the cluster tiebreak) is asserted in one line.
func mirrorRepoHosts(mirrors []coreapi.Mirror) []string {
	out := make([]string, len(mirrors))
	for i, m := range mirrors {
		out[i] = m.Owner + "/" + m.Repo + "@" + m.ClusterHost
	}
	return out
}

func TestSortMirrors(t *testing.T) {
	t.Parallel()

// One repo mirrored on two clusters (delivered eu-first) plus a
	// lexically-earlier repo, so both the primary key and the cluster tiebreak
	// are observable.
	base := func() []coreapi.Mirror {
		return []coreapi.Mirror{
			{Owner: "acme", Repo: "web", ClusterHost: "eu-west-1.entire.io", IsPrivate: coreapi.NewOptBool(true)},
			{Owner: "acme", Repo: "web", ClusterHost: "aws-us-east-2.entire.io", IsPrivate: coreapi.NewOptBool(false)},
			{Owner: "acme", Repo: "api", ClusterHost: "aws-us-east-2.entire.io", IsPrivate: coreapi.NewOptBool(false)},
		}
	}

t.Run("default sorts owner/repo then cluster ascending", func(t *testing.T) {
		t.Parallel()
		m := base()
		require.NoError(t, sortMirrors(m, ""))
		require.Equal(t, []string{
			"acme/api@aws-us-east-2.entire.io",
			"acme/web@aws-us-east-2.entire.io",
			"acme/web@eu-west-1.entire.io",
		}, mirrorRepoHosts(m))
	})

t.Run("-name reverses the whole ordering, tiebreak included", func(t *testing.T) {
		t.Parallel()
		m := base()
		require.NoError(t, sortMirrors(m, "-name"))
		require.Equal(t, []string{
			"acme/web@eu-west-1.entire.io",
			"acme/web@aws-us-east-2.entire.io",
			"acme/api@aws-us-east-2.entire.io",
		}, mirrorRepoHosts(m))
	})

t.Run("non-name column sorts keep the owner/repo+cluster tiebreak", func(t *testing.T) {
		t.Parallel()
		// All three sort keys collide on "private" once acme/api and the aws web
		// mirror are both public; the deterministic order must fall back to
		// owner/repo then cluster, not arbitrary input order.
		m := base()
		require.NoError(t, sortMirrors(m, "private"))
		require.Equal(t, []string{
			// "no" (public) group first, ordered by owner/repo then cluster.
			"acme/api@aws-us-east-2.entire.io",
			"acme/web@aws-us-east-2.entire.io",
			// "yes" (private) group last.
			"acme/web@eu-west-1.entire.io",
		}, mirrorRepoHosts(m))
	})

t.Run("whitespace spec parses direction from the trimmed spec", func(t *testing.T) {
		t.Parallel()
		m := base()
		require.NoError(t, sortMirrors(m, " -name"))
		require.Equal(t, []string{
			"acme/web@eu-west-1.entire.io",
			"acme/web@aws-us-east-2.entire.io",
			"acme/api@aws-us-east-2.entire.io",
		}, mirrorRepoHosts(m))
	})

t.Run("unknown column errors naming valid columns", func(t *testing.T) {
		t.Parallel()
		err := sortMirrors(base(), "nope")
		require.Error(t, err)
		require.Contains(t, err.Error(), "unknown sort column")
		require.Contains(t, err.Error(), "name")
	})
}

func TestSortAvailable(t *testing.T) {
	t.Parallel()

base := func() []coreapi.AvailableMirror {
		return []coreapi.AvailableMirror{
			{Owner: "acme", Repo: "web", Access: "write", Status: "available"},
			{Owner: "acme", Repo: "api", Access: "read", Status: "available"},
			{Owner: "acme", Repo: "cli", Access: "read", Status: "available"},
		}
	}
	repos := func(avail []coreapi.AvailableMirror) []string {
		out := make([]string, len(avail))
		for i, m := range avail {
			out[i] = m.Owner + "/" + m.Repo
		}
		return out
	}

t.Run("sorts by access with an owner/repo tiebreak on equal keys", func(t *testing.T) {
		t.Parallel()
		a := base()
		require.NoError(t, sortAvailable(a, "access"))
		// "read" < "write"; within read, acme/api < acme/cli by owner/repo.
		require.Equal(t, []string{"acme/api", "acme/cli", "acme/web"}, repos(a))
	})

t.Run("whitespace spec parses direction from the trimmed spec", func(t *testing.T) {
		t.Parallel()
		a := base()
		require.NoError(t, sortAvailable(a, " -name"))
		require.Equal(t, []string{"acme/web", "acme/cli", "acme/api"}, repos(a))
	})

t.Run("unknown column errors naming valid columns", func(t *testing.T) {
		t.Parallel()
		err := sortAvailable(base(), "nope")
		require.Error(t, err)
		require.Contains(t, err.Error(), "unknown sort column")
		require.Contains(t, err.Error(), "access")
	})
}
```

Mcmd/entire/cli/repo\_mirror\_test.go+433/-7

```
133 unmodified lines

134
135
136
137
138
139
140
141
137
138
139
140
141
142
143
144
145
146
78 unmodified lines

225
226
227
226
227
228
229
230
231
232
228
229
230
231
232
233
234
235
236
14 unmodified lines

251
252
253
253
254
255
256
257
455 unmodified lines

713
714
715
715
716
717
718
719
720
721
722
723
724
716
717
718
719
720
721
722
723
724
725
726
503 unmodified lines

1230
1231
1232
1234
1233
1234
1235
1236

133 unmodified lines

--models       list the models each agent advertises (optionally --agent NAME)
  --profile NAME select a profile (also accepted as positional arg)
  --prompt TEXT  add one-off per-run instructions for this invocation
  --timeout DUR  max time each reviewer may run before it's cancelled and marked
                 failed; also bounds the consolidating judge, whose timeout or
                 error fails the review with no verdict (default 20m; 0 disables
                 both bounds). A timed-out reviewer's siblings and the judge
                 still proceed.
  --timeout DUR  optional hard cap on each reviewer before it's cancelled and
                 marked failed. No default — reviewers run until they finish,
                 like a directly-invoked skill. A positive value also bounds
                 the consolidating judge, which otherwise keeps its own 20m
                 default (the judge is never unbounded; its timeout or error
                 fails the review with no verdict). A timed-out reviewer's
                 siblings and the judge still proceed.
  --base REF     scope against REF instead of mainline. Useful for stacked
                 PRs where the base is the parent feature branch, not main.
                 Default: first existing of origin/HEAD, origin/main,
78 unmodified lines

if findings {
				return runReviewFindings(ctx, cmd, positionalArg, deps.NewSilentError)
			}
			// Map the flag to the RunConfig timeout convention: a non-positive
			// value (the user passed --timeout 0) means "disable", encoded as the
			// negative sentinel, which disables BOTH the per-reviewer bound and the
			// judge's deadline. A positive value passes through and bounds both.
			// (The flag's default is nonzero, so 0 only appears on --timeout 0.)
			timeoutArg := resolveReviewerTimeoutArg(reviewTimeout)
			return runReview(ctx, cmd, agentOverride, modelOverride, baseOverride, profileName, perRunPrompt, timeoutArg, deps)
			// The flag flows through unmapped: RunConfig.ReviewerTimeout is
			// two-state (positive = hard cap, anything else = no cap), so the
			// default 0, an explicit --timeout 0, and a negative all mean
			// "reviewers run until done". The judge derives its own bound via
			// judgeTimeoutArg and is never uncapped.
			return runReview(ctx, cmd, agentOverride, modelOverride, baseOverride, profileName, perRunPrompt, reviewTimeout, deps)
		},
	}
	cmd.Flags().BoolVar(&configure, "configure", false, "set up a review profile; shows available agents and accepts --set-* flags for non-interactive config")
14 unmodified lines

cmd.Flags().StringVar(&profileOverride, "profile", "", "review profile to run (default: review_default_profile or general)")
	cmd.Flags().StringVar(&perRunPrompt, "prompt", "", "one-off instructions appended to this review run")
	cmd.Flags().StringVar(&baseOverride, "base", "", "git ref to scope the review against (default: origin/HEAD → origin/main → origin/master → main → master)")
	cmd.Flags().DurationVar(&reviewTimeout, "timeout", defaultReviewerTimeout, "max time each reviewer may run before it is cancelled and marked failed; also bounds the consolidating judge, whose timeout or error fails the review (0 disables both)")
	cmd.Flags().DurationVar(&reviewTimeout, "timeout", 0, "optional hard cap per reviewer (default: none — reviewers run until they finish, like a skill invoked directly in a session). When set, it also bounds the consolidating judge; unset, the judge keeps its own 20m default")
	// The listing modes and the action modes each select a distinct command
	// behavior; combining them silently runs one and drops the rest, so reject
	// the combination up front with a clear cobra error.
455 unmodified lines

return names
}

// resolveReviewerTimeoutArg maps the --timeout flag value to the RunConfig
// timeout convention used by reviewerTimeout and the judge's providerContext: a
// non-positive value (the user passed --timeout 0) becomes the negative
// "disabled" sentinel; a positive value passes through unchanged. The flag's
// default is nonzero, so 0 only reaches here when the user explicitly set it.
func resolveReviewerTimeoutArg(flagValue time.Duration) time.Duration {
	if flagValue <= 0 {
		return -1
	}
	return flagValue
// judgeTimeoutArg maps the reviewer --timeout value to the judge's
// ProviderTimeout. The judge is a single text-generation call with no event
// stream, so unlike reviewers it always keeps a bound: an explicit positive
// --timeout governs it, anything else (unset, 0, or a negative like
// `--timeout -5m`) maps to 0 so the synthesis default (20m) applies — a
// reviewer-side "no cap" must never leak through as "judge unbounded".
func judgeTimeoutArg(reviewerArg time.Duration) time.Duration {
	return max(reviewerArg, 0)
}

// runReview executes the main review flow.
503 unmodified lines

profileName:       profileName,
		task:              profile.Task,
		masterName:        masterLabel,
		judgeTimeout:      timeout,
		judgeTimeout:      judgeTimeoutArg(timeout),
		onSynthesisResult: func(result string) {
			aggregateOutput = result
		},
```

Mcmd/entire/cli/review/cmd.go+23/-24

```
33 unmodified lines

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
37
38
39
40
41
42
43
44
45
46
47
48
49
52
53
54
55
56
57
58
59
50
51
52
53

33 unmodified lines

return ""
}

// defaultReviewerTimeout bounds a single reviewer's run when the caller
// doesn't set RunConfig.ReviewerTimeout. A stuck agent is cancelled (its
// process killed) and marked failed rather than hanging the review forever.
//
// A full reviewer pass (read the diff, run skills, write the report) regularly
// runs past 10m, especially for the consolidating judge, so the default is 20m;
// override with --timeout (0 disables).
const defaultReviewerTimeout = 20 * time.Minute

// reviewerTimeout resolves the effective per-reviewer timeout, distinguishing
// the three RunConfig.ReviewerTimeout states the zero value alone can't:
//   - positive: use it.
//   - zero (unset): use defaultReviewerTimeout.
//   - negative: disabled — return 0, and callers treat 0 as "no timeout".
// reviewerTimeout resolves the effective per-reviewer wall cap. There is
// deliberately NO default: reviewers run until they finish, exactly like the
// same skill invoked in a user's own session. Review time is dominated by
// long-running subagents inside the reviewer (measured: a single legitimate
// review subagent ran 12.6 minutes with zero parent output) — every
// wall-clock default we shipped killed real work at some diff size, and no
// reliable liveness signal exists for a headless child that would let a
// watchdog distinguish "working via a quiet subagent" from "hung". A stuck
// reviewer is Ctrl+C in interactive runs (process-group kill handles it);
// unattended callers that need a bound pass --timeout explicitly.
//   - positive: hard cap.
//   - zero or negative: no cap.
func reviewerTimeout(cfg reviewtypes.RunConfig) time.Duration {
	switch {
	case cfg.ReviewerTimeout > 0:
		return cfg.ReviewerTimeout
	case cfg.ReviewerTimeout < 0:
		return 0
	default:
		return defaultReviewerTimeout
	}
	return max(cfg.ReviewerTimeout, 0)
}

var errReviewerTimeoutCause = errors.New("reviewer timeout elapsed")
```

Mcmd/entire/cli/review/run.go+13/-22

```
995 unmodified lines

996
997
998
999
1000
999
1000
1001
1002
1003
3 unmodified lines

1007
1008
1009
1010
1011
1012
1013
1014
1010
1011
1012
1013
1014
1015
1016
1016
1017
1018
1019
1020
1021
1022
1023
1017
1018
1019
1025
1026
1027
1028
1020
1021
1022
1023
1024
1025
1026
1027
1032
1033
1034
1035
1028
1029
1030
1031
1032
1033
1037
1038
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1042
1043
1044
1045
1046
1045
1046
1047
1048
1049
1050
1051
1052
8 unmodified lines

1061
1062
1063
1061
1062
1063
1064
1065
1064
1065
1066
1067
1068
1069
1070
1067
1068
1069
1071
1072
1073
1074
1075
1072
1076
1077
1078
1079

995 unmodified lines

func TestReviewerTimeout(t *testing.T) {
	t.Parallel()
	if got := reviewerTimeout(reviewtypes.RunConfig{}); got != defaultReviewerTimeout {
		t.Errorf("unset = %v, want default %v", got, defaultReviewerTimeout)
	if got := reviewerTimeout(reviewtypes.RunConfig{}); got != 0 {
		t.Errorf("unset = %v, want 0 (no default cap)", got)
	}
	if got := reviewerTimeout(reviewtypes.RunConfig{ReviewerTimeout: 5 * time.Minute}); got != 5*time.Minute {
		t.Errorf("explicit = %v, want 5m", got)
3 unmodified lines

}
}

// TestResolveReviewerTimeoutArg pins the --timeout flag -> RunConfig sentinel
// mapping: a non-positive flag value (the user passed --timeout 0) becomes the
// negative "disabled" sentinel that turns off both the reviewer bound and the
// judge's deadline; a positive value passes through unchanged.
func TestResolveReviewerTimeoutArg(t *testing.T) {
// TestReviewerTimeout_NoDefaultCap pins the deliberate absence of a default
// wall cap: an unset RunConfig.ReviewerTimeout means the reviewer runs until
// it finishes, like a skill invoked directly in a session. Every wall-clock
// default we shipped killed legitimate work at some diff size (reviewers
// spend 10+ minute stretches inside subagents with zero parent output).
func TestReviewerTimeout_NoDefaultCap(t *testing.T) {
	t.Parallel()
	cases := []struct {
		name string
		in   time.Duration
		want time.Duration
	}{
		{"explicit zero disables", 0, -1},
		{"negative disables", -5 * time.Minute, -1},
		{"positive passes through", 20 * time.Minute, 20 * time.Minute},
	if got := reviewerTimeout(reviewtypes.RunConfig{}); got != 0 {
		t.Errorf("reviewerTimeout(unset) = %v, want 0 (no cap)", got)
	}
	for _, tc := range cases {
		if got := resolveReviewerTimeoutArg(tc.in); got != tc.want {
			t.Errorf("%s: resolveReviewerTimeoutArg(%v) = %v, want %v", tc.name, tc.in, got, tc.want)
		}
	if got := reviewerTimeout(reviewtypes.RunConfig{ReviewerTimeout: -1}); got != 0 {
		t.Errorf("reviewerTimeout(negative) = %v, want 0 (no cap)", got)
	}
	if got := reviewerTimeout(reviewtypes.RunConfig{ReviewerTimeout: 30 * time.Minute}); got != 30*time.Minute {
		t.Errorf("reviewerTimeout(30m) = %v, want the explicit cap", got)
	}
}

// TestDefaultReviewerTimeoutValue pins the literal default so an accidental edit
// to the constant is caught (the other timeout tests compare against the
// constant itself and would silently follow a change).
func TestDefaultReviewerTimeoutValue(t *testing.T) {
// TestJudgeTimeoutArg pins the judge mapping: the judge is one bounded API
// call and always keeps a limit — an explicit positive --timeout governs it,
// and a reviewer-side "no cap" (zero or negative, e.g. `--timeout -5m`) must
// not leak through as "judge unbounded".
func TestJudgeTimeoutArg(t *testing.T) {
	t.Parallel()
	if defaultReviewerTimeout != 20*time.Minute {
		t.Errorf("defaultReviewerTimeout = %v, want 20m", defaultReviewerTimeout)
	if got := judgeTimeoutArg(0); got != 0 {
		t.Errorf("judgeTimeoutArg(0) = %v, want 0 (judge default applies)", got)
	}
	if got := judgeTimeoutArg(-5 * time.Minute); got != 0 {
		t.Errorf("judgeTimeoutArg(-5m) = %v, want 0 (judge default applies)", got)
	}
	if got := judgeTimeoutArg(30 * time.Minute); got != 30*time.Minute {
		t.Errorf("judgeTimeoutArg(30m) = %v, want 30m", got)
	}
}

// TestTimeoutFlag_ResolvesThroughCommand drives the real --timeout flag through
// the command (parse only, no RunE) and the resolver, covering the full
// flag -> resolveReviewerTimeoutArg chain: 0 (and the default) and a positive
// override. Guards the documented "0 disables" contract against a regression
// that bypasses the resolver.
// TestTimeoutFlag_ResolvesThroughCommand drives the real --timeout flag
// through the command (parse only, no RunE), pinning the two-state contract
// the flag value carries directly into RunConfig.ReviewerTimeout: the default
// and an explicit 0 both mean "no cap" (reviewerTimeout returns 0), and a
// positive override is the hard cap.
func TestTimeoutFlag_ResolvesThroughCommand(t *testing.T) {
	t.Parallel()
	parseTimeout := func(args []string) time.Duration {
8 unmodified lines

return d
	}

// Default (no flag) is the nonzero default and resolves to a positive bound.
	if d := parseTimeout(nil); d != defaultReviewerTimeout {
		t.Errorf("default --timeout = %v, want %v", d, defaultReviewerTimeout)
	} else if got := resolveReviewerTimeoutArg(d); got != defaultReviewerTimeout {
		t.Errorf("default resolves to %v, want %v", got, defaultReviewerTimeout)
	// Default (no flag) is zero: reviewers run until they finish unless the
	// user explicitly caps them.
	if d := parseTimeout(nil); d != 0 {
		t.Errorf("default --timeout = %v, want 0 (no cap)", d)
	} else if got := reviewerTimeout(reviewtypes.RunConfig{ReviewerTimeout: d}); got != 0 {
		t.Errorf("default resolves to %v, want 0 (no cap)", got)
	}
	// --timeout 0 resolves to the negative disable sentinel (reviewers + judge).
	if got := resolveReviewerTimeoutArg(parseTimeout([]string{"--timeout", "0"})); got != -1 {
		t.Errorf("--timeout 0 resolves to %v, want -1 (disabled)", got)
	// Explicit --timeout 0 behaves the same as the default.
	if got := reviewerTimeout(reviewtypes.RunConfig{ReviewerTimeout: parseTimeout([]string{"--timeout", "0"})}); got != 0 {
		t.Errorf("--timeout 0 resolves to %v, want 0 (no cap)", got)
	}
	// A positive override passes through unchanged.
	if got := resolveReviewerTimeoutArg(parseTimeout([]string{"--timeout", "30m"})); got != 30*time.Minute {
	if got := reviewerTimeout(reviewtypes.RunConfig{ReviewerTimeout: parseTimeout([]string{"--timeout", "30m"})}); got != 30*time.Minute {
		t.Errorf("--timeout 30m resolves to %v, want 30m", got)
	}
}
```

Mcmd/entire/cli/review/run\_test.go+43/-39

```
89 unmodified lines

90
91
92
93
94
93
94
95
96
97
98
99
100
101

89 unmodified lines

// defaultSynthesisProviderTimeout bounds the judge's single consolidation call
// when SynthesisSink.ProviderTimeout is unset. The judge reads every reviewer's
// report and writes the combined verdict in one text-generation call, which
// regularly needs more than the original 2m, so the default is 5m.
const defaultSynthesisProviderTimeout = 5 * time.Minute
// regularly needs more than the original 2m. 20m matches the judge's previous
// effective bound: before the reviewer default was dropped, the --timeout flag
// default (20m) always flowed into ProviderTimeout on the no-flag path, so
// keeping 5m here would have silently tightened the judge 4x — and a judge
// timeout discards an entire multi-reviewer run with no verdict.
const defaultSynthesisProviderTimeout = 20 * time.Minute

// AgentEvent is a no-op; SynthesisSink only acts in RunFinished.
func (SynthesisSink) AgentEvent(_ string, _ reviewtypes.Event) {}
```

Mcmd/entire/cli/review/synthesis\_sink.go+6/-2

```
311 unmodified lines

312
313
314
315
315
316
317
318
319
7 unmodified lines

327
328
329
329
330
331
331
332
332
333
334
335
336
29 unmodified lines

366
367
368
368
369
370
371
372

311 unmodified lines

}

// TestSynthesisSink_DefaultProviderTimeoutValue pins the judge's default
// deadline (~5m) when ProviderTimeout is unset, so an accidental change to
// deadline (~20m, the flag default's previous effective bound) when
// ProviderTimeout is unset, so an accidental change to
// defaultSynthesisProviderTimeout is caught rather than passing silently.
func TestSynthesisSink_DefaultProviderTimeoutValue(t *testing.T) {
	t.Parallel()
7 unmodified lines

if !provider.hadDeadline {
		t.Fatal("unset ProviderTimeout must apply the default deadline")
	}
	// The default is 5m; allow generous slack for scheduling between context
	// The default is 20m; allow generous slack for scheduling between context
	// creation and the provider reading the deadline.
	if provider.remaining < 4*time.Minute || provider.remaining > 5*time.Minute {
		t.Fatalf("default deadline remaining = %v, want ~5m", provider.remaining)
	if provider.remaining < 19*time.Minute || provider.remaining > 20*time.Minute {
		t.Fatalf("default deadline remaining = %v, want ~20m", provider.remaining)
	}
}

29 unmodified lines

if !provider.hadDeadline {
		t.Fatal("explicit ProviderTimeout must apply a deadline")
	}
	// Generous slack: the deadline should be ~1h out, far above the 5m default.
	// Generous slack: the deadline should be ~1h out, far above the 20m default.
	if provider.remaining < 30*time.Minute {
		t.Fatalf("deadline remaining = %v, want ~1h (explicit timeout not honored, fell back to default)", provider.remaining)
	}
```

Mcmd/entire/cli/review/synthesis\_sink\_test.go+6/-5

```
130 unmodified lines

131
132
133
134
135
136
137
134
135
136
137
138
139
140
141

130 unmodified lines

// ReviewerTimeout bounds how long a single reviewer may run before the
	// orchestrator cancels it (its process is killed and the run is marked
	// failed-by-timeout) so a stuck agent can't hang the review forever. Zero
	// or negative means use the orchestrator default (defaultReviewerTimeout).
	// Sibling reviewers and the judge are unaffected by one reviewer's
	// timeout.
	// failed-by-timeout). Positive is a hard cap; zero or negative means no
	// cap — reviewers run until they finish, like a skill invoked directly
	// in a session (there is deliberately no default: every wall-clock
	// default shipped killed legitimate long-running work). Sibling
	// reviewers and the judge are unaffected by one reviewer's timeout.
	ReviewerTimeout time.Duration

// EnrichSummary optionally updates the completed run summary before sinks
```

Mcmd/entire/cli/review/types/reviewer.go+5/-4

```
93 unmodified lines

94
95
96
97
98
99
100
101
102
103
104
101
102
103
104
105
106
107

93 unmodified lines

cmd.AddCommand(newLabsCmd())            // 'labs' (experimental workflow discovery)
	cmd.AddCommand(newPluginGroupCmd())     // 'plugin' (managed install/list/remove)
	cmd.AddCommand(newImportCmd())          // 'import' (hidden; import pre-existing agent history)
	cmd.AddCommand(newOrgCmd())             // 'org' — control-plane org management
	cmd.AddCommand(newProjectCmd())         // 'project' — control-plane project management
	cmd.AddCommand(newRepoCmd())            // 'repo' — control-plane repo lifecycle
	cmd.AddCommand(newGrantCmd())           // 'grant' — control-plane access grants

// Top-level lifecycle and standalone commands.
	cmd.AddCommand(cliReview.NewCommand(buildReviewDeps()))        // `review`; hidden during maturation
	cmd.AddCommand(investigate.NewCommand(buildInvestigateDeps())) // hidden during maturation; runs a multi-agent investigation
	cmd.AddCommand(newOrgCmd())                                    // hidden during maturation; control-plane org management
	cmd.AddCommand(newProjectCmd())                                // hidden during maturation; control-plane project management
	cmd.AddCommand(newRepoCmd())                                   // hidden during maturation; control-plane repo lifecycle
	cmd.AddCommand(newGrantCmd())                                  // hidden during maturation; control-plane access grants
	cmd.AddCommand(newCleanCmd())
	cmd.AddCommand(newSetupCmd()) // 'configure' — non-agent settings; agent CRUD lives under 'agent'
	cmd.AddCommand(newEnableCmd())
```

Mcmd/entire/cli/root.go+4/-4

```
706 unmodified lines

707
708
709
710
711
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
714
715
716
717
718
719
720
726
727
728
729
730
731
732
733
734
735
736
737
723
724
725
726
727
738
739
740
741
742
743
744
745
746
747
731
732
733
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763

706 unmodified lines

}
	merged.Results = deduped

// Deduplicate RepoStats by repo name, summing match/file counts.
	repoStatsMap := make(map[string]*codesearch.RepoStats, len(merged.RepoStats))
	// Deduplicate RepoStats by repo name. A repo that appears in more than one
	// cell is a mirror placement returning the SAME content (this PR fans out
	// across placements, so e.g. a US-homed repo with an EU mirror is now
	// searched in both cells) — not additional matches. Keep one representative
	// entry per repo (the max of each count; mirror copies are identical, max
	// only guards against minor per-cell skew) instead of summing, and record
	// the duplicated portion so the aggregate stats can drop the double-count.
	type repoStatAcc struct {
		idx                    int
		sumMatches, maxMatches int
		sumFiles, maxFiles     int
		cellCount              int
	}
	accByRepo := make(map[string]*repoStatAcc, len(merged.RepoStats))
	var dedupedStats []codesearch.RepoStats
	for _, rs := range merged.RepoStats {
		if existing, ok := repoStatsMap[rs.Repo]; ok {
			existing.MatchCount += rs.MatchCount
			existing.FileCount += rs.FileCount
		} else {
			entry := rs // copy
			repoStatsMap[rs.Repo] = &entry
			dedupedStats = append(dedupedStats, entry)
		acc, ok := accByRepo[rs.Repo]
		if !ok {
			acc = &repoStatAcc{idx: len(dedupedStats)}
			accByRepo[rs.Repo] = acc
			dedupedStats = append(dedupedStats, codesearch.RepoStats{Repo: rs.Repo})
		}
		acc.cellCount++
		acc.sumMatches += rs.MatchCount
		acc.sumFiles += rs.FileCount
		acc.maxMatches = max(acc.maxMatches, rs.MatchCount)
		acc.maxFiles = max(acc.maxFiles, rs.FileCount)
	}
	// Write back merged values.
	for i := range dedupedStats {
		if m, ok := repoStatsMap[dedupedStats[i].Repo]; ok {
			dedupedStats[i] = *m
		}
	var overcountMatches, overcountFiles, overcountRepos int
	for _, acc := range accByRepo {
		dedupedStats[acc.idx].MatchCount = acc.maxMatches
		dedupedStats[acc.idx].FileCount = acc.maxFiles
		overcountMatches += acc.sumMatches - acc.maxMatches
		overcountFiles += acc.sumFiles - acc.maxFiles
		overcountRepos += acc.cellCount - 1
	}
	merged.RepoStats = dedupedStats

// Stats are preserved as the sum of per-cell peregrine stats — they
	// reflect the true totals (including zero-match repos and per-cell
	// truncation), not just the deduped result slice.
	// The per-cell Stats were summed above, so a mirrored repo's matches were
	// counted once per cell. Subtract the duplicated copies identified via
	// RepoStats so the totals reflect distinct content, not the same content
	// seen from every mirror cell. This preserves per-cell truncation (the
	// base is peregrine's own totals; we only remove the provable duplicate
	// portion) and zero-match repos (they contribute 0 to the subtraction).
	// A repo with matches but no RepoStats row, or a zero-match mirror repo,
	// can't be de-duplicated from the response and keeps its summed
	// contribution — a mild over-count, far less misleading than reporting
	// every mirrored match twice. Clamp at zero against inconsistent input.
	merged.Stats.TotalMatches = max(0, merged.Stats.TotalMatches-overcountMatches)
	merged.Stats.TotalFiles = max(0, merged.Stats.TotalFiles-overcountFiles)
	merged.Stats.ReposSearched = max(0, merged.Stats.ReposSearched-overcountRepos)

// Cap to the caller's requested limit.
	if limit > 0 && len(merged.Results) > limit {
```

Mcmd/entire/cli/search\_cmd.go+44/-17

```
13 unmodified lines

14
15
16
17
18
19
17
18
19
20
21
22
23
359 unmodified lines

383
384
385
386
387
388
389
390
391
392
393
386
387
388
389
390
391
392
393
394
395
396
397
398
399
394
395
396
397
398
3 unmodified lines

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474

13 unmodified lines

// test constants used across code-search tests.
const (
	testRepoID1 = "01ABC"
	testRepoID2 = "02DEF"
	testCellEU  = "aws-eu-west-1"
	testRepoID1       = "01ABC"
	testRepoID2       = "02DEF"
	testCellEU        = "aws-eu-west-1"
	testClusterSlugUS = "us-prod"
)

// TestSearchCmd_AccessibleModeRequiresQuery verifies that accessible mode
359 unmodified lines

t.Parallel()

dup := codesearch.Result{Repo: "acme/web", Path: "main.go", Line: 10, Column: 5, Score: 0.9}
	cellVal := func() *codesearch.SearchResponse {
		return &codesearch.SearchResponse{
			Results:   []codesearch.Result{dup},
			Stats:     codesearch.Stats{TotalMatches: 1, TotalFiles: 1, ReposSearched: 1},
			RepoStats: []codesearch.RepoStats{{Repo: "acme/web", MatchCount: 1, FileCount: 1}},
		}
	}
	results := []cellCallResult[*codesearch.SearchResponse]{
		{
			group: cellGroup{cell: "", jurisdiction: ""},
			value: &codesearch.SearchResponse{
				Results: []codesearch.Result{dup},
				Stats:   codesearch.Stats{TotalMatches: 1, TotalFiles: 1, ReposSearched: 1},
			},
		},
		{
			group: cellGroup{cell: "aws-us-east-2", jurisdiction: "us"},
			value: &codesearch.SearchResponse{
				Results: []codesearch.Result{dup},
				Stats:   codesearch.Stats{TotalMatches: 1, TotalFiles: 1, ReposSearched: 1},
			},
		},
		{group: cellGroup{cell: "", jurisdiction: ""}, value: cellVal()},
		{group: cellGroup{cell: "aws-us-east-2", jurisdiction: "us"}, value: cellVal()},
	}

merged, err := mergeSearchResults(context.Background(), 0, results)
3 unmodified lines

if len(merged.Results) != 1 {
		t.Fatalf("len(Results) = %d, want 1 (duplicate removed)", len(merged.Results))
	}
	// Stats must not double-count the overlapping match either.
	if merged.Stats.TotalMatches != 1 {
		t.Errorf("TotalMatches = %d, want 1 (overlapping cells must not double-count)", merged.Stats.TotalMatches)
	}
	if merged.Stats.ReposSearched != 1 {
		t.Errorf("ReposSearched = %d, want 1 (one logical repo)", merged.Stats.ReposSearched)
	}
	if len(merged.RepoStats) != 1 || merged.RepoStats[0].MatchCount != 1 {
		t.Errorf("RepoStats = %+v, want one entry with MatchCount 1", merged.RepoStats)
	}
}

func TestMergeSearchResults_MirrorPlacementsDoNotDoubleCount(t *testing.T) {
	t.Parallel()

// A US-homed repo with an EU mirror indexes the same content, so the
	// fan-out queries both cells and each returns the SAME matches. Merged
	// results dedupe by repo+path+line; the stats must dedupe too, or the
	// summary reports "6 matches across 4 files in 2 repos" for 3 unique
	// results (and falsely claims truncation). Regression guard for the
	// mirror fan-out this trail introduced.
	matches := []codesearch.Result{
		{Repo: "acme/web", Path: "main.go", Line: 1, Column: 0, Score: 0.9},
		{Repo: "acme/web", Path: "main.go", Line: 2, Column: 0, Score: 0.8},
		{Repo: "acme/web", Path: "util.go", Line: 5, Column: 0, Score: 0.7},
	}
	cell := func(name, jur string) cellCallResult[*codesearch.SearchResponse] {
		return cellCallResult[*codesearch.SearchResponse]{
			group: cellGroup{cell: name, jurisdiction: jur},
			value: &codesearch.SearchResponse{
				Query:     "handleRequest",
				Stats:     codesearch.Stats{TotalMatches: 3, TotalFiles: 2, ReposSearched: 1, DurationMs: 10},
				RepoStats: []codesearch.RepoStats{{Repo: "acme/web", MatchCount: 3, FileCount: 2}},
				Results:   matches,
			},
		}
	}
	results := []cellCallResult[*codesearch.SearchResponse]{
		cell("aws-us-east-2", "us"),
		cell(testCellEU, "eu"),
	}

merged, err := mergeSearchResults(context.Background(), 0, results)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if len(merged.Results) != 3 {
		t.Fatalf("len(Results) = %d, want 3 (mirror duplicates removed)", len(merged.Results))
	}
	if merged.Stats.TotalMatches != 3 {
		t.Errorf("TotalMatches = %d, want 3 (mirror must not double-count)", merged.Stats.TotalMatches)
	}
	if merged.Stats.TotalFiles != 2 {
		t.Errorf("TotalFiles = %d, want 2 (mirror must not double-count)", merged.Stats.TotalFiles)
	}
	if merged.Stats.ReposSearched != 1 {
		t.Errorf("ReposSearched = %d, want 1 (one logical repo across two cells)", merged.Stats.ReposSearched)
	}
	if merged.Stats.DurationMs != 10 {
		t.Errorf("DurationMs = %v, want 10 (slowest cell preserved)", merged.Stats.DurationMs)
	}
	if len(merged.RepoStats) != 1 {
		t.Fatalf("len(RepoStats) = %d, want 1 (deduped by repo)", len(merged.RepoStats))
	}
	if merged.RepoStats[0].MatchCount != 3 || merged.RepoStats[0].FileCount != 2 {
		t.Errorf("RepoStats[0] = %+v, want representative {3,2} not summed {6,4}", merged.RepoStats[0])
	}
}

func TestResolveRepoFilters_GhPrefix(t *testing.T) {
```

Mcmd/entire/cli/search\_cmd\_test.go+80/-17

```
1457 unmodified lines

1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1465
1466
1467
1491
1492
1493
1494
1495
1496
1470
1497
1498
1499
1500
1473
1474
1501
1502
1503
1504
1505
1506
6 unmodified lines

1513
1514
1515
1487
1488
1489
1490
1491
1492
1493
1516
1517
1518
1519
1520
1521
1522
1523
1524
59 unmodified lines

1584
1585
1586
1559
1560
1561
1562
1563
1564
1587
1588
1589
1590
1591
1592
1593
1594
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605

1457 unmodified lines

return count, nil
}

// promptAgentSelection shows the interactive multi-select agent picker and
// returns the chosen agent names. It is a package-level var so tests can
// substitute it — no real TTY/form is available under `go test`.
var promptAgentSelection = func(options []huh.Option[string]) ([]string, error) {
	var selected []string
	form := NewAccessibleForm(
		huh.NewGroup(
			huh.NewMultiSelect[string]().
				Title("Select the agents you want to use").
				Description("Use space to select, enter to confirm.").
				Options(options...).
				Validate(func(sel []string) error {
					if len(sel) == 0 {
						return errors.New("please select at least one agent")
					}
					return nil
				}).
				Value(&selected),
		),
	)
	if err := form.Run(); err != nil {
		return nil, fmt.Errorf("agent selection cancelled: %w", err)
	}
	return selected, nil
}

// detectOrSelectAgent tries to auto-detect agents, or prompts the user to select.
// Returns the detected/selected agents and any error.
//
// On first run (no hooks installed):
//   - Single detected built-in agent: used automatically
//   - Single detected external agent: interactive multi-select prompt
//   - Multiple/no detected agents: interactive multi-select prompt
//   - Shows the interactive multi-select (TTY available and no selectFn override)
//   - Pre-selects detected built-in agents so the user can confirm with enter
//     or add more; detected external agents are shown but not pre-selected
//   - Non-interactive (no TTY): uses detected agents, else the default agent
//
// On re-run (hooks already installed):
//   - Always shows the interactive multi-select
//   - Shows the interactive multi-select (TTY available and no selectFn override)
//   - Pre-selects only agents that have hooks installed (respects prior deselection)
//   - Non-interactive (no TTY): keeps the currently installed agents
//
// selectFn overrides the interactive prompt for testing. When nil, the real form is used.
// It receives available agent names and returns the selected names.
// selectFn overrides the prompt with a caller-supplied selection (--yes uses
// selectAllAgents; tests inject their own), bypassing the form even on a TTY.
// When nil, the real multi-select form is shown.
func detectOrSelectAgent(ctx context.Context, w io.Writer, selectFn func(available []string) ([]string, error)) ([]agent.Agent, error) {
	// Check for agents with hooks already installed (re-run detection)
	installedAgentNames := GetAgentsWithHooksInstalled(ctx)
6 unmodified lines

if !hasInstalledHooks {
		switch {
		case len(detected) == 1:
			if isBuiltInAgent(detected[0]) {
				// When a selectFn is provided (e.g. --yes), skip the single-agent
				// shortcut so the caller's selection logic runs instead.
				if selectFn == nil {
					fmt.Fprintf(w, "Detected agent: %s\n\n", detected[0].Type())
					return detected, nil
				}
			// Announce the single detected built-in agent; it is pre-selected
			// in the multi-select form below so the user can confirm it or add
			// more. --yes (selectFn != nil) uses the caller's selection and
			// skips the announcement.
			if selectFn == nil && isBuiltInAgent(detected[0]) {
				fmt.Fprintf(w, "Detected agent: %s\n\n", detected[0].Type())
			}

case len(detected) > 1:
59 unmodified lines

availableNames = append(availableNames, opt.Value)
	}

var selectedAgentNames []string
	if selectFn != nil {
		var err error
		selectedAgentNames, err = selectFn(availableNames)
		if err != nil {
			return nil, err
	// selectFn overrides the prompt with a caller-supplied selection (--yes,
	// tests). When nil, show the real interactive multi-select. Routing both
	// through selectFn keeps a single selection step, so there is no "skip the
	// picker" path a lone detected agent can slip back into.
	if selectFn == nil {
		selectFn = func([]string) ([]string, error) {
			return promptAgentSelection(options)
		}
		if len(selectedAgentNames) == 0 {
			return nil, errors.New("no agents selected")
		}
	} else {
		form := NewAccessibleForm(
			huh.NewGroup(
				huh.NewMultiSelect[string]().
					Title("Select the agents you want to use").
					Description("Use space to select, enter to confirm.").
					Options(options...).
					Validate(func(selected []string) error {
						if len(selected) == 0 {
							return errors.New("please select at least one agent")
						}
						return nil
					}).
					Value(&selectedAgentNames),
			),
		)
		if err := form.Run(); err != nil {
			return nil, fmt.Errorf("agent selection cancelled: %w", err)
		}
	}
	selectedAgentNames, err := selectFn(availableNames)
	if err != nil {
		return nil, err
	}
	if len(selectedAgentNames) == 0 {
		return nil, errors.New("no agents selected")
	}

selectedAgents := make([]agent.Agent, 0, len(selectedAgentNames))
	for _, name := range selectedAgentNames {
```

Mcmd/entire/cli/setup.go+55/-41

```
11 unmodified lines

12
13
14
15
16
17
18
1157 unmodified lines

1176
1177
1178
1179
1180
1181
1182
1183
1184
46 unmodified lines

1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288

11 unmodified lines

"strings"
	"testing"

"charm.land/huh/v2"
	"github.com/entireio/cli/cmd/entire/cli/agent"
	_ "github.com/entireio/cli/cmd/entire/cli/agent/claudecode"
	"github.com/entireio/cli/cmd/entire/cli/agent/external"
1157 unmodified lines

t.Fatalf("Failed to create .claude directory: %v", err)
	}

// No TTY here, so this exercises the non-interactive fallback: the single
	// detected agent is used without a picker. The interactive path pre-selects
	// it in the multi-select instead (see FirstRun_SingleBuiltIn test below).
	var buf bytes.Buffer
	agents, err := detectOrSelectAgent(context.Background(), &buf, nil)
	if err != nil {
46 unmodified lines

}
}

func TestDetectOrSelectAgent_FirstRun_SingleBuiltIn_ShowsPickerPreSelected(t *testing.T) {
	// Not parallel: uses t.Chdir/t.Setenv and swaps the package-level
	// promptAgentSelection seam.
	setupTestRepo(t)
	t.Setenv("ENTIRE_TEST_TTY", "1")

// Create .claude directory so exactly one built-in agent (Claude Code) is detected.
	if err := os.MkdirAll(".claude", 0o755); err != nil {
		t.Fatalf("Failed to create .claude directory: %v", err)
	}

// First run: no hooks installed yet.
	if installed := GetAgentsWithHooksInstalled(context.Background()); len(installed) != 0 {
		t.Fatalf("Expected no installed hooks on first run, got %v", installed)
	}

// Stub the real picker so we can assert it is shown (rather than the agent
	// being auto-used) and inspect which options it was given. Driving the
	// selectFn == nil path is what makes this a real regression guard: the old
	// shortcut returned early precisely when selectFn == nil, so a test that
	// injected a selectFn would have passed even before the fix.
	prev := promptAgentSelection
	t.Cleanup(func() { promptAgentSelection = prev })
	var offered []string
	var shown bool
	promptAgentSelection = func(options []huh.Option[string]) ([]string, error) {
		shown = true
		for _, o := range options {
			offered = append(offered, o.Value)
		}
		return []string{string(agent.AgentNameClaudeCode)}, nil
	}

var buf bytes.Buffer
	agents, err := detectOrSelectAgent(context.Background(), &buf, nil)
	if err != nil {
		t.Fatalf("detectOrSelectAgent() error = %v", err)
	}

// A lone detected built-in agent must no longer be auto-used: the picker
	// must be shown so the user can confirm it or add more.
	if !shown {
		t.Fatal("Expected the picker to be shown for a single detected agent, but it was auto-used")
	}
	if !slices.Contains(offered, string(agent.AgentNameClaudeCode)) {
		t.Errorf("Expected the detected agent among the picker options, got %v", offered)
	}
	if len(agents) != 1 || agents[0].Name() != agent.AgentNameClaudeCode {
		t.Fatalf("Expected the picked agent [claude-code] to be returned, got %v", agents)
	}
}

func TestDetectOrSelectAgent_OnlyExternalDetected_WithTTY_PromptsUser(t *testing.T) {
	// Cannot use t.Parallel() because we use t.Chdir, t.Setenv, and global agent registration
	if _, err := exec.LookPath("sh"); err != nil {
```

Mcmd/entire/cli/setup\_test.go+56
