refactor: remove unused bd pin/unpin/hook commands (bd-x0zl)

Analysis found these commands are dead code:
- gt never calls `bd pin` - uses `bd update --status=pinned` instead
- Beads.Pin() wrapper exists but is never called
- bd hook functionality duplicated by gt mol status
- Code comment says "pinned field is cosmetic for bd hook visibility"

Removed:
- cmd/bd/pin.go
- cmd/bd/unpin.go
- cmd/bd/hook.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-27 16:02:15 -08:00
parent c8b912cbe6
commit 1611f16751
178 changed files with 10291 additions and 1682 deletions

View File

@@ -426,6 +426,24 @@ With --stealth: configures per-repository git settings for invisible beads usage
fmt.Fprintf(os.Stderr, "Warning: failed to close database: %v\n", err)
}
// Fork detection: offer to configure .git/info/exclude (GH#742)
setupExclude, _ := cmd.Flags().GetBool("setup-exclude")
if setupExclude {
// Manual flag - always configure
if err := setupForkExclude(!quiet); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to configure git exclude: %v\n", err)
}
} else if !stealth && isGitRepo() {
// Auto-detect fork and prompt (skip if stealth - it handles exclude already)
if isFork, upstreamURL := detectForkSetup(); isFork {
if promptForkExclude(upstreamURL, quiet) {
if err := setupForkExclude(!quiet); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to configure git exclude: %v\n", err)
}
}
}
}
// Check if we're in a git repo and hooks aren't installed
// Install by default unless --skip-hooks is passed
if !skipHooks && isGitRepo() && !hooksInstalled() {
@@ -491,6 +509,7 @@ func init() {
initCmd.Flags().Bool("contributor", false, "Run OSS contributor setup wizard")
initCmd.Flags().Bool("team", false, "Run team workflow setup wizard")
initCmd.Flags().Bool("stealth", false, "Enable stealth mode: global gitattributes and gitignore, no local repo tracking")
initCmd.Flags().Bool("setup-exclude", false, "Configure .git/info/exclude to keep beads files local (for forks)")
initCmd.Flags().Bool("skip-hooks", false, "Skip git hooks installation")
initCmd.Flags().Bool("skip-merge-driver", false, "Skip git merge driver setup")
initCmd.Flags().Bool("force", false, "Force re-initialization even if JSONL already has issues (may cause data loss)")
@@ -1463,6 +1482,103 @@ func setupGitExclude(verbose bool) error {
return nil
}
// setupForkExclude configures .git/info/exclude for fork workflows (GH#742)
// Adds beads files and Claude artifacts to keep PRs to upstream clean.
// This is separate from stealth mode - fork protection is specifically about
// preventing beads/Claude files from appearing in upstream PRs.
func setupForkExclude(verbose bool) error {
gitDir, err := exec.Command("git", "rev-parse", "--git-dir").Output()
if err != nil {
return fmt.Errorf("not a git repository")
}
gitDirPath := strings.TrimSpace(string(gitDir))
excludePath := filepath.Join(gitDirPath, "info", "exclude")
// Ensure info directory exists
if err := os.MkdirAll(filepath.Join(gitDirPath, "info"), 0755); err != nil {
return fmt.Errorf("failed to create git info directory: %w", err)
}
// Read existing content
var existingContent string
// #nosec G304 - git config path
if content, err := os.ReadFile(excludePath); err == nil {
existingContent = string(content)
}
// Patterns to add for fork protection
patterns := []string{".beads/", "**/RECOVERY*.md", "**/SESSION*.md"}
var toAdd []string
for _, p := range patterns {
// Check for exact line match (pattern alone on a line)
// This avoids false positives like ".beads/issues.jsonl" matching ".beads/"
if !containsExactPattern(existingContent, p) {
toAdd = append(toAdd, p)
}
}
if len(toAdd) == 0 {
if verbose {
fmt.Printf("%s Git exclude already configured\n", ui.RenderPass("✓"))
}
return nil
}
// Append patterns
newContent := existingContent
if !strings.HasSuffix(newContent, "\n") && len(newContent) > 0 {
newContent += "\n"
}
newContent += "\n# Beads fork protection (bd init)\n"
for _, p := range toAdd {
newContent += p + "\n"
}
// #nosec G306 - config file needs 0644
if err := os.WriteFile(excludePath, []byte(newContent), 0644); err != nil {
return fmt.Errorf("failed to write git exclude: %w", err)
}
if verbose {
fmt.Printf("\n%s Added to .git/info/exclude:\n", ui.RenderPass("✓"))
for _, p := range toAdd {
fmt.Printf(" %s\n", p)
}
fmt.Println("\nNote: .git/info/exclude is local-only and won't affect upstream.")
}
return nil
}
// containsExactPattern checks if content contains the pattern as an exact line
// This avoids false positives like ".beads/issues.jsonl" matching ".beads/"
func containsExactPattern(content, pattern string) bool {
for _, line := range strings.Split(content, "\n") {
if strings.TrimSpace(line) == pattern {
return true
}
}
return false
}
// promptForkExclude asks if user wants to configure .git/info/exclude for fork workflow (GH#742)
func promptForkExclude(upstreamURL string, quiet bool) bool {
if quiet {
return false // Don't prompt in quiet mode
}
fmt.Printf("\n%s Detected fork (upstream: %s)\n\n", ui.RenderAccent("▶"), upstreamURL)
fmt.Println("Would you like to configure .git/info/exclude to keep beads files local?")
fmt.Println("This prevents beads from appearing in PRs to upstream.")
fmt.Print("\n[Y/n]: ")
reader := bufio.NewReader(os.Stdin)
response, _ := reader.ReadString('\n')
response = strings.TrimSpace(strings.ToLower(response))
// Default to yes (empty or "y" or "yes")
return response == "" || response == "y" || response == "yes"
}
// setupGlobalGitIgnore configures global gitignore to ignore beads and claude files for a specific project
// DEPRECATED: This function uses absolute paths which don't work in gitignore (GitHub #704).
// Use setupGitExclude instead for new code.