fix(enable): make GitHub repo creation and push explicit opt-ins · Entire

fix(enable): make GitHub repo creation and push explicit opt-ins

06b38b5→main·

computermode·4d ago·3 files·+147 added/-56 removed

Previously the bootstrap seeded push := useGitHub && commit (true) and useGitHub := !opts.NoGitHub (true), flipping them to No only via the interactive prompt. So a non-interactive run (e.g. entire enable --init-repo in CI) created a GitHub repo and pushed the directory's contents with no explicit opt-in — the interactive default-No was not the real default.

Now both are explicit opt-ins:

Adds a --push flag (implies creating the remote; mutually exclusive with --no-github and --skip-initial-commit) and updates --yes help to mention push.

Tests updated to reflect the new default (no-flags stays local; repo flags create-without-push) and cover the --push path and flag exclusivity.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Sessions

01KXE4XZ12S5VJGDTTVCSQG0SNView transcript

Changes

3

934 unmodified lines

935
936
937
938
938
939
940
941
3 unmodified lines

945
946
947
948
949
950
951
952
953
954
955
956
957

934 unmodified lines

cmd.Flags().BoolVar(&opts.AbsoluteGitHookPath, flagAbsoluteGitHookPath, false, "Embed full binary path in git hooks (for GUI git clients that don't source shell profiles)")
    cmd.Flags().BoolVar(&opts.SearchSkill, flagSearchSkill, false, "Install the optional Entire search skill for selected agent(s)")
    cmd.Flags().BoolVar(&opts.AgentHelpSkill, flagAgentHelpSkill, false, "Install the stable Entire agent-help skill (points agents at `entire agent-help`) for selected agent(s)")
    cmd.Flags().BoolVarP(&opts.Yes, "yes", "y", false, "Accept all defaults without prompting (in a non-repo directory: init git, create private GitHub repo, commit; then enable all agents and accept telemetry)")
    cmd.Flags().BoolVarP(&opts.Yes, "yes", "y", false, "Accept all defaults without prompting (in a non-repo directory: init git, create private GitHub repo, commit, and push; then enable all agents and accept telemetry)")
    addInsecureHTTPAuthFlag(cmd, &insecureHTTPAuth)

// Bootstrap flags for non-git-repo folders.
3 unmodified lines

cmd.Flags().StringVar(&bootstrapOpts.RepoOwner, "repo-owner", "", "GitHub user or organization login for the new repo")
    cmd.Flags().StringVar(&bootstrapOpts.RepoVisibility, "repo-visibility", "", "GitHub repository visibility: public, private, or internal")
    cmd.Flags().BoolVar(&bootstrapOpts.NoGitHub, "no-github", false, "Initialize local git repo only; skip creating a GitHub remote")
    cmd.Flags().BoolVar(&bootstrapOpts.Push, "push", false, "When bootstrapping a new repo, push the initial commit to the created GitHub remote (implies creating the remote; without it the repo is created but not pushed)")
    cmd.Flags().StringVar(&bootstrapOpts.InitialCommitMessage, "initial-commit-message", "", "Commit message for the initial commit when bootstrapping a new repo")
    cmd.Flags().BoolVar(&bootstrapOpts.SkipInitialCommit, "skip-initial-commit", false, "Don't create the initial commit when bootstrapping a new repo")
    cmd.MarkFlagsMutuallyExclusive("init-repo", "no-init-repo")
    cmd.MarkFlagsMutuallyExclusive("initial-commit-message", "skip-initial-commit")
    cmd.MarkFlagsMutuallyExclusive("push", "no-github")
    cmd.MarkFlagsMutuallyExclusive("push", "skip-initial-commit")

// Provide a helpful error when --agent is used without a value
    defaultFlagErr := cmd.FlagErrorFunc()

Mcmd/entire/cli/setup.go+4/-1

41 unmodified lines

42
43
44
45
46
45
46
47
48
49
50
51
52
53
54
110 unmodified lines

165
166
167
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
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
197
198
199
26 unmodified lines

226
227
228
223
224
225
226
227
228
229
230
231
232
233
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
235
246
247
248
93 unmodified lines

342
343
344
345
346
347
348
349
350
351
352
353
354
355

41 unmodified lines

// still created, but nothing is pushed.
    SkipInitialCommit bool
    // Yes accepts all defaults without prompting: init repo, create GitHub
    // repo under the user's account (private), default commit message.
    // Explicit flags (--no-github, --repo-owner, etc.) take precedence.
    // repo under the user's account (private), default commit message, and
    // push. Explicit flags (--no-github, --repo-owner, etc.) take precedence.
    Yes bool
    // Push opts into pushing the initial commit to the created GitHub remote
    // without prompting. Pushing is otherwise an explicit, separate opt-in
    // (interactive "yes" or --yes). Implies creating the remote.
    Push bool
}

// bootstrapRunner executes external commands. Tests override this to avoid
110 unmodified lines

paths.ClearWorktreeRootCache()
    fmt.Fprintln(w, "  ✓ Initialized empty git repository")

// Step 3: decide whether to create a GitHub repo. If gh is missing or the
    // user passed --no-github, we skip that branch but still bootstrap the
    // local repo.
    useGitHub := !opts.NoGitHub
    if useGitHub {
        if !ghAvailable(ctx, runner) {
            fmt.Fprintln(errW, "gh CLI not found. Install it from https://cli.github.com/ and run `gh auth login` to add a GitHub remote.")
            fmt.Fprintln(errW, "Continuing with local initialization only.")
            useGitHub = false
        } else if !ghAuthenticated(ctx, runner) {
            fmt.Fprintln(errW, "gh CLI is not authenticated. Run `gh auth login` to add a GitHub remote.")
            fmt.Fprintln(errW, "Continuing with local initialization only.")
            useGitHub = false
        }
    }

// Step 3b: ask a simple yes/no before diving into owner/name/visibility
    // prompts. Skip the confirm when any gh-specific flag is set (the flag
    // implies intent) or when we're non-interactive (keep the documented
    // happy path: default to yes).
    if useGitHub && !opts.Yes && !ghFlagsProvided(opts) && interactive.CanPromptInteractively() {
        confirmed, err := confirmCreateGitHubRepo(cwd)
        if err != nil {
            return nil, err
        }
        if !confirmed {
            useGitHub = false
    // Step 3: decide whether to create a GitHub repo. Creating a remote is an
    // explicit opt-in: it happens only on an explicit signal (repo flags,
    // --push, or --yes) or an interactive "yes". A non-interactive run with no
    // such signal stays local-only — we never create a repo on the user's
    // behalf. --no-github always wins.
    useGitHub := false
    if !opts.NoGitHub {
        explicit := ghCreateRequested(opts)
        // Only probe gh (and warn about a missing/unauthenticated CLI) when the
        // user actually wants a GitHub repo — explicitly, or via the confirm
        // prompt we're about to show interactively.
        if explicit || interactive.CanPromptInteractively() {
            switch {
            case !ghAvailable(ctx, runner):
                fmt.Fprintln(errW, "gh CLI not found. Install it from https://cli.github.com/ and run `gh auth login` to add a GitHub remote.")
                fmt.Fprintln(errW, "Continuing with local initialization only.")
            case !ghAuthenticated(ctx, runner):
                fmt.Fprintln(errW, "gh CLI is not authenticated. Run `gh auth login` to add a GitHub remote.")
                fmt.Fprintln(errW, "Continuing with local initialization only.")
            case explicit:
                useGitHub = true
            default:
                // Interactive with no explicit signal: prompt, defaulting to No.
                confirmed, err := confirmCreateGitHubRepo(cwd)
                if err != nil {
                    return nil, err
                }
                useGitHub = confirmed
            }
        }
    }

// Step 6: separate guard for the push. Pushing publishes the directory's
    // contents to the remote — a distinct outward-facing action from creating
    // the repo — so confirm it on its own and default to No. Only relevant
    // when we'll create a GitHub repo and have a commit to push. Gated like
    // the create confirm: explicit flags / --yes / non-interactive keep the
    // documented happy path (push).
    push := useGitHub && commit
    if push && !opts.Yes && !ghFlagsProvided(opts) && interactive.CanPromptInteractively() {
        confirmed, err := confirmPushToRemote(fullName)
        if err != nil {
            return nil, err
    // Step 6: pushing is also an explicit opt-in, separate from creating the
    // repo. Publishing the directory's contents is a distinct outward-facing
    // action, so it happens only on an explicit signal (--push or --yes) or an
    // interactive "yes". Otherwise the repo is created but left unpushed. Only
    // relevant when we'll create a GitHub repo and have a commit to push.
    push := false
    if useGitHub && commit {
        switch {
        case opts.Yes || opts.Push:
            push = true
        case interactive.CanPromptInteractively():
            confirmed, err := confirmPushToRemote(fullName)
            if err != nil {
                return nil, err
            }
            push = confirmed
        }
        push = confirmed
    }

return &bootstrapState{
93 unmodified lines

return opts.RepoName != "" || opts.RepoOwner != "" || opts.RepoVisibility != ""
}

// ghCreateRequested reports whether the caller has explicitly opted into
// creating a GitHub repo without an interactive prompt: --yes, --push (which
// needs a remote to push to), or any repo-targeting flag. When false and the
// session is non-interactive, the bootstrap stays local-only.
func ghCreateRequested(opts GitHubBootstrapOptions) bool {
    return opts.Yes || opts.Push || ghFlagsProvided(opts)
}

// confirmCreateGitHubRepo asks the user whether they want to also create
// a matching GitHub repository. Interactive-only; callers gate on
// interactive.CanPromptInteractively. Pushing to the repo is confirmed