@@ -195,6 +195,85 @@ func regionLabel(r regionChoice) string {
195195 }
196196}
197197
198+ // resolveOneShotClusterHost picks the cluster `repo mirror create
199+ // <github-url>` targets when [cluster-host] is omitted. Non-interactive
200+ // callers keep the fixed defaultClusterHost so scripts stay stable and
201+ // offline-resolvable; on a terminal the control plane's cluster catalog is
202+ // offered as a single-select (skipped when only one cluster exists),
203+ // pre-selecting the caller's jurisdiction default — the same
204+ // prompt-only-when-there-is-a-choice shape `repo clone` uses for
205+ // multi-cluster placements.
206+ func resolveOneShotClusterHost (cmd * cobra.Command ) (string , error ) {
207+ if ! interactive .CanPromptInteractively () {
208+ return defaultClusterHost , nil
209+ }
210+ errW := cmd .ErrOrStderr ()
211+ var (
212+ regions []regionChoice
213+ jurisdiction string
214+ )
215+ if err := runCore (cmd , func (ctx context.Context , c * coreapi.Client ) error {
216+ stop := startSpinner (errW , "Fetching clusters" )
217+ var err error
218+ if regions , err = availableRegions (ctx , c ); err != nil {
219+ stop (false )
220+ return err
221+ }
222+ // The jurisdiction only pre-selects the picker's default; a /me
223+ // hiccup shouldn't sink the create, so fall back to no pre-selection.
224+ if me , merr := c .GetMe (ctx ); merr == nil {
225+ jurisdiction , _ = me .Jurisdiction .Get ()
226+ }
227+ stop (true )
228+ return nil
229+ }); err != nil {
230+ return "" , err
231+ }
232+ if len (regions ) == 0 {
233+ return "" , errors .New ("no clusters available to mirror into; pass [cluster-host] explicitly" )
234+ }
235+ if len (regions ) == 1 {
236+ fmt .Fprintf (errW , "Using cluster %s\n " , regions [0 ].host )
237+ return regions [0 ].host , nil
238+ }
239+ return pickOneCluster (cmd .Context (), errW , regions , jurisdiction )
240+ }
241+
242+ // pickOneCluster runs the one-shot create's cluster single-select,
243+ // pre-selecting the default cluster for the caller's jurisdiction. A clean
244+ // cancel (Ctrl+C / cancelled ctx) surfaces as a SilentError so the create
245+ // stops instead of falling through to a cluster the user didn't choose.
246+ func pickOneCluster (ctx context.Context , w io.Writer , regions []regionChoice , jurisdiction string ) (string , error ) {
247+ opts , defaults := clusterChoices (regions , jurisdiction )
248+ var selected string
249+ if len (defaults ) > 0 {
250+ selected = defaults [0 ]
251+ }
252+ form := NewAccessibleForm (
253+ huh .NewGroup (
254+ huh .NewSelect [string ]().
255+ Title ("Select the cluster to mirror into" ).
256+ Options (opts ... ).
257+ Value (& selected ),
258+ ),
259+ )
260+ if err := form .RunWithContext (ctx ); err != nil {
261+ if cerr := handleFormCancellation (w , "Mirror create" , err ); cerr != nil {
262+ return "" , cerr
263+ }
264+ return "" , NewSilentError (errors .New ("mirror create cancelled" ))
265+ }
266+ // Guard the selection against the offered hosts (like repo clone's
267+ // picker) so a zero-value fall-through can't reach the caller as a
268+ // misleading "invalid [cluster-host]" error.
269+ for _ , r := range regions {
270+ if r .host == selected {
271+ return selected , nil
272+ }
273+ }
274+ return "" , NewSilentError (errors .New ("mirror create cancelled" ))
275+ }
276+
198277// mirrorTarget is one unit of work: a selected repo to be mirrored into a
199278// selected region. The wizard creates the cross-product of repos × regions.
200279type mirrorTarget struct {
0 commit comments