Skip to content

Commit e0ddb8e

Browse files
sgx-labsclaude
andcommitted
Seed install UX: number selection, friendly errors, backup on force
- Allow selecting seeds by number (e.g. `same seed install 1`) - Show green checkmark instead of error for already-installed seeds - Back up existing seed to .bak before --force reinstall - Friendlier error messages with reinstall hints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent dc79c88 commit e0ddb8e

3 files changed

Lines changed: 44 additions & 10 deletions

File tree

cmd/same/seed_cmd.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"encoding/json"
55
"fmt"
6+
"strconv"
67
"strings"
78

89
"github.com/spf13/cobra"
@@ -88,6 +89,13 @@ func seedInstallCmd() *cobra.Command {
8889
RunE: func(cmd *cobra.Command, args []string) error {
8990
name := args[0]
9091

92+
// Allow selecting by number (e.g. "same seed install 1")
93+
if n, err := strconv.Atoi(name); err == nil && n >= 1 {
94+
if m, mErr := seed.FetchManifest(false); mErr == nil && n <= len(m.Seeds) {
95+
name = m.Seeds[n-1].Name
96+
}
97+
}
98+
9199
fmt.Println()
92100
fmt.Printf(" %sSeed Install:%s %s\n\n", cli.Bold, cli.Reset, name)
93101

@@ -127,6 +135,10 @@ func seedInstallCmd() *cobra.Command {
127135
if strings.Contains(errMsg, "requires SAME") {
128136
return userError(errMsg, "Run 'same update' to get the latest version")
129137
}
138+
if strings.Contains(errMsg, "already installed") {
139+
fmt.Printf(" %s✓%s %s\n", cli.Green, cli.Reset, errMsg)
140+
return nil
141+
}
130142
return fmt.Errorf("install failed: %w", err)
131143
}
132144

@@ -153,15 +165,24 @@ func seedInfoCmd() *cobra.Command {
153165
Args: cobra.ExactArgs(1),
154166
ValidArgsFunction: seedNameCompleter,
155167
RunE: func(cmd *cobra.Command, args []string) error {
168+
name := args[0]
169+
170+
// Allow selecting by number (e.g. "same seed info 1")
171+
if n, err := strconv.Atoi(name); err == nil && n >= 1 {
172+
if m, mErr := seed.FetchManifest(false); mErr == nil && n <= len(m.Seeds) {
173+
name = m.Seeds[n-1].Name
174+
}
175+
}
176+
156177
manifest, err := seed.FetchManifest(false)
157178
if err != nil {
158179
return userError("Could not fetch seed list", "Check your internet connection")
159180
}
160181

161-
s := seed.FindSeed(manifest, args[0])
182+
s := seed.FindSeed(manifest, name)
162183
if s == nil {
163184
return userError(
164-
fmt.Sprintf("Seed %q not found", args[0]),
185+
fmt.Sprintf("Seed %q not found", name),
165186
"Run 'same seed list' to see available seeds",
166187
)
167188
}

internal/seed/install.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,18 @@ func Install(opts InstallOptions) (*InstallResult, error) {
105105
// 5. Check if directory exists
106106
if info, err := os.Stat(absDir); err == nil && info.IsDir() {
107107
if !opts.Force {
108-
return nil, fmt.Errorf("directory already exists: %s — use --force to overwrite", absDir)
108+
return nil, fmt.Errorf("already installed at %s\n To reinstall, run: same seed install %s --force\n Back up your notes first if you've added any to this seed", absDir, opts.Name)
109109
}
110-
// Remove existing to start fresh
111-
if err := os.RemoveAll(absDir); err != nil {
112-
return nil, fmt.Errorf("remove existing directory: %w", err)
110+
// Back up to .bak before removing
111+
bakDir := absDir + ".bak"
112+
_ = os.RemoveAll(bakDir) // remove stale backup
113+
if err := os.Rename(absDir, bakDir); err != nil {
114+
// Rename failed, fall back to remove
115+
if err := os.RemoveAll(absDir); err != nil {
116+
return nil, fmt.Errorf("remove existing directory: %w", err)
117+
}
118+
} else {
119+
fmt.Fprintf(os.Stderr, " Backed up existing to %s\n", filepath.Base(bakDir))
113120
}
114121
}
115122

internal/setup/init.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -673,8 +673,11 @@ func offerSeedInstall(opts InitOptions) bool {
673673

674674
result, err := seed.Install(installOpts)
675675
if err != nil {
676-
fmt.Printf(" %s!%s Install failed: %v\n", cli.Yellow, cli.Reset, err)
677-
fmt.Printf(" %sYou can try again with: same seed install %s%s\n\n", cli.Dim, chosen.Name, cli.Reset)
676+
if strings.Contains(err.Error(), "already installed") {
677+
fmt.Printf(" %s✓%s %v\n\n", cli.Green, cli.Reset, err)
678+
} else {
679+
fmt.Printf(" %s!%s %v\n\n", cli.Yellow, cli.Reset, err)
680+
}
678681
continue
679682
}
680683

@@ -803,8 +806,11 @@ func showSeedIntro(opts InitOptions) {
803806

804807
result, err := seed.Install(installOpts)
805808
if err != nil {
806-
fmt.Printf(" %s!%s Install failed: %v\n", cli.Yellow, cli.Reset, err)
807-
fmt.Printf(" %sYou can try again with: same seed install %s%s\n\n", cli.Dim, chosen.Name, cli.Reset)
809+
if strings.Contains(err.Error(), "already installed") {
810+
fmt.Printf(" %s✓%s %v\n\n", cli.Green, cli.Reset, err)
811+
} else {
812+
fmt.Printf(" %s!%s %v\n\n", cli.Yellow, cli.Reset, err)
813+
}
808814
continue
809815
}
810816

0 commit comments

Comments
 (0)