diff --git a/cmd/bd/config.go b/cmd/bd/config.go index e3c7045e..9d30090d 100644 --- a/cmd/bd/config.go +++ b/cmd/bd/config.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os" + "path/filepath" "regexp" "sort" "strings" @@ -14,6 +15,9 @@ import ( "github.com/steveyegge/beads/internal/syncbranch" ) +// gitSSHRemotePattern matches standard git SSH remote URLs (user@host:path) +var gitSSHRemotePattern = regexp.MustCompile(`^[a-zA-Z0-9._-]+@[a-zA-Z0-9][a-zA-Z0-9._-]*:.+$`) + var configCmd = &cobra.Command{ Use: "config", GroupID: "setup", @@ -347,7 +351,7 @@ func validateSyncConfig(repoPath string) []string { var issues []string // Load config.yaml directly from the repo path - configPath := repoPath + "/.beads/config.yaml" + configPath := filepath.Join(repoPath, ".beads", "config.yaml") v := viper.New() v.SetConfigType("yaml") v.SetConfigFile(configPath) @@ -433,22 +437,19 @@ func isValidRemoteURL(url string) bool { } // Also allow standard git remote patterns (user@host:path) - // The host must have at least one character before the colon - // Pattern: username@hostname:path where hostname has at least 2 chars - gitSSHPattern := regexp.MustCompile(`^[a-zA-Z0-9._-]+@[a-zA-Z0-9][a-zA-Z0-9._-]*:.+$`) - return gitSSHPattern.MatchString(url) + return gitSSHRemotePattern.MatchString(url) } // findBeadsRepoRoot walks up from the given path to find the repo root (containing .beads) func findBeadsRepoRoot(startPath string) string { path := startPath for { - beadsDir := path + "/.beads" + beadsDir := filepath.Join(path, ".beads") if info, err := os.Stat(beadsDir); err == nil && info.IsDir() { return path } - parent := path[:strings.LastIndex(path, "/")] - if parent == path || parent == "" { + parent := filepath.Dir(path) + if parent == path { return "" } path = parent