feat(enable): restore the checkpoint-storage question, git-refs recommended · Entire

feat(enable): restore the checkpoint-storage question, git-refs recommended

a9112fd→main·

peyton-alt·9h ago·3 files·+81 added/-7 removed

Team decision on the removed wizard question (#1789): keep it, but flip the recommendation — git-refs listed first, pre-selected, labeled '(recommended)' instead of branch being 'the default'. One Enter accepts refs; the choice is written explicitly either way. Non-interactive, --yes, and cancelled first runs take the recommendation silently, and the prompt is skipped while ENTIRE_CHECKPOINTS_PRIMARY is active (an answer could not take effect and would only write diverging config). Existing repos remain untouched.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Changes

3

6 unmodified lines

7
8
9
10
11
12
13
14
61 unmodified lines

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

6 unmodified lines

"slices"
    "strings"

"charm.land/huh/v2"

"github.com/entireio/cli/cmd/entire/cli/checkpoint"
    "github.com/entireio/cli/cmd/entire/cli/paths"
    "github.com/entireio/cli/cmd/entire/cli/settings"
61 unmodified lines

return nil
}

// checkpointBackendChoices returns the storage picker's options — git-refs
// first, pre-selected, labeled recommended — and the recommended default.
// Split from promptCheckpointBackend so the ordering/labeling contract is
// unit-testable without a TTY.
func checkpointBackendChoices() (opts []huh.Option[string], recommended string) {
    return []huh.Option[string]{
        huh.NewOption("Refs — one git ref per checkpoint (recommended)", checkpoint.BackendTypeGitRefs),
        huh.NewOption("Branch — one shared branch, entire/checkpoints/v1", checkpoint.BackendTypeGitBranch),
    }, checkpoint.BackendTypeGitRefs
}

// promptCheckpointBackend asks the user to choose a checkpoint storage backend
// during first-time interactive setup, with the git-refs backend pre-selected
// as the recommendation — most users should just press Enter. It returns the
// chosen canonical backend type; cancellation (Ctrl+C or a cancelled ctx)
// returns "" so the caller falls through to the recommended default, matching
// the optional-prompt behavior elsewhere in setup. Callers must gate this on
// an interactive terminal (and skip it when ENTIRE_CHECKPOINTS_PRIMARY is
// active — the env fully replaces settings, so an answer could not take
// effect and would only write diverging config).
func promptCheckpointBackend(ctx context.Context, w io.Writer) (string, error) {
    opts, recommended := checkpointBackendChoices()
    choice := recommended
    form := NewAccessibleForm(
        huh.NewGroup(
            huh.NewSelect[string]().
                Title("Checkpoint storage").
                Description("How Entire stores committed session checkpoints in your repo.").
                Options(opts...).
                Value(&choice),
            ),
        )
    if err := form.RunWithContext(ctx); err != nil {
        return "", handleFormCancellation(w, "Checkpoint storage selection", err)
    }
    return choice, nil
}

// updateCheckpointBackend persists opts.CheckpointBackend to the target settings
// file. Used by `entire configure` and by `entire enable` on repos that are
// already set up (both operate on an on-disk file rather than the in-memory

Mcmd/entire/cli/checkpoint_backend.go+40

9 unmodified lines

10
11
12
13
14
15
16
113 unmodified lines

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

9 unmodified lines

"github.com/entireio/cli/cmd/entire/cli/checkpoint"
    "github.com/entireio/cli/cmd/entire/cli/settings"
    "strings"
)

func TestResolveCheckpointBackendType(t *testing.T) {
113 unmodified lines

require.Error(t, err)
    assert.Contains(t, err.Error(), flagCheckpointBackend)
}

// The storage picker's contract from the team decision: the question stays,
// but git-refs is listed first and pre-selected as the recommendation —
// "default" wording is gone, one Enter accepts refs.
func TestCheckpointBackendChoices_RefsRecommendedFirst(t *testing.T) {
    t.Parallel()
    opts, recommended := checkpointBackendChoices()
    if recommended != checkpoint.BackendTypeGitRefs {
             t.Errorf("recommended = %q, want git-refs pre-selected", recommended)
    }
    if len(opts) != 2 || opts[0].Value != checkpoint.BackendTypeGitRefs {
             t.Fatalf("options = %+v, want refs listed first", opts)
    }
    if !strings.Contains(opts[0].Key, "(recommended)") {
             t.Errorf("refs label = %q, want '(recommended)' suffix", opts[0].Key)
    }
    if strings.Contains(opts[0].Key+opts[1].Key, "default") {
             t.Errorf("labels must not say 'default' (team decision: recommended, not default): %q / %q", opts[0].Key, opts[1].Key)
    }
}

Mcmd/entire/cli/checkpoint_backend_test.go+21

784 unmodified lines

785
786
787
788
788
789
790
791
139 unmodified lines

931
932
933
934
934
935
936
937
301 unmodified lines

1239
1240
1241
1242
1243
1244
1245
1246
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262

784 unmodified lines

cmd.Flags().BoolVarP(&opts.ForceHooks, flagForce, "f", false, "Reinstall the Entire git hook")
    cmd.Flags().BoolVar(&opts.SkipPushSessions, flagSkipPushSessions, false, "Disable automatic pushing of session logs on git push")
    cmd.Flags().StringVar(&opts.CheckpointRemote, flagCheckpointRemote, "", "Checkpoint remote in provider:owner/repo format (e.g., github:org/checkpoints-repo)")
    cmd.Flags().StringVar(&opts.CheckpointBackend, flagCheckpointBackend, "", "Checkpoint storage backend: refs (one git ref per checkpoint; default for new setups) or branch (shared entire/checkpoints/v1 branch)")
    cmd.Flags().StringVar(&opts.CheckpointBackend, flagCheckpointBackend, "", "Checkpoint storage backend: refs (one git ref per checkpoint; recommended) or branch (shared entire/checkpoints/v1 branch)")
    cmd.Flags().StringVar(&summarizeProvider, flagSummarizeAgent, "", "Set the provider used by explain --generate (e.g., claude-code, codex, gemini, pi, cursor, copilot-cli)")
    cmd.Flags().StringVar(&summarizeModel, flagSummarizeModel, "", "Set the model hint used by explain --generate")
    cmd.Flags().IntVar(&summarizeTimeoutSeconds, flagSummarizeTimeout, 0, "Set the hard deadline (seconds) for explain --generate summary generation. 0 clears (falls back to 5m default).")
139 unmodified lines

cmd.Flags().BoolVarP(&opts.ForceHooks, flagForce, "f", false, "Force reinstall hooks (removes existing Entire hooks first)")
    cmd.Flags().BoolVar(&opts.SkipPushSessions, flagSkipPushSessions, false, "Disable automatic pushing of session logs on git push")
    cmd.Flags().StringVar(&opts.CheckpointRemote, flagCheckpointRemote, "", "Checkpoint remote in provider:owner/repo format (e.g., github:org/checkpoints-repo)")
    cmd.Flags().StringVar(&opts.CheckpointBackend, flagCheckpointBackend, "", "Checkpoint storage backend: refs (one git ref per checkpoint; recommended) or branch (shared entire/checkpoints/v1 branch)")
    cmd.Flags().BoolVar(&opts.Telemetry, flagTelemetry, true, "Enable anonymous usage analytics")
    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)")
301 unmodified lines

opts.applyStrategyOptions(settings)

// Checkpoint storage backend. An explicit --checkpoint-backend always wins.
    // Otherwise every first run gets the git-refs backend, written explicitly
    // into the new settings file: a storage-topology question is unanswerable
    // during first-time setup (the old wizard prompt), and the config-less
    // runtime default stays git-branch so existing repos are untouched.
    // Checkpoint storage backend. An explicit --checkpoint-backend always
    // wins. Otherwise a first interactive setup asks, with git-refs
    // pre-selected as the recommendation (one Enter for most users);
    // non-interactive/--yes/cancelled first runs take the recommendation
    // silently. Either way the choice is written explicitly into the new
    // settings file, and the config-less runtime fallback stays git-branch
    // so existing repos are untouched. The prompt is skipped while
    // ENTIRE_CHECKPOINTS_PRIMARY is active (firstRunCheckpointBackendDefault
    // returns ""): the env fully replaces settings, so an answer could not
    // take effect and would only write diverging config.
    if opts.CheckpointBackend == "" && firstRun && !opts.Yes &&
            firstRunCheckpointBackendDefault() != "" && interactive.CanPromptInteractively() {
        chosen, err := promptCheckpointBackend(ctx, w)
        if err != nil {
            return err
        }
        opts.CheckpointBackend = chosen // "" (cancelled) falls through to the recommendation
    }
    if opts.CheckpointBackend == "" && firstRun {
        opts.CheckpointBackend = firstRunCheckpointBackendDefault()
    }