Skip to content

Commit 13c2ecc

Browse files
authored
Merge pull request #2511 from MelsovCOZY/fix/global-prime-fallback
feat: support global ~/.config/beads/PRIME.md fallback (GH#2330)
2 parents 2d8f869 + 3a2d351 commit 13c2ecc

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

cmd/bd/prime.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,26 @@ var (
2323
primeExportMode bool
2424
)
2525

26+
// resolveGlobalPrimePath returns the path to ~/.config/beads/PRIME.md if it
27+
// exists. configDirOverride is used for testing; pass "" for production.
28+
func resolveGlobalPrimePath(configDirOverride string) string {
29+
var configDir string
30+
if configDirOverride != "" {
31+
configDir = configDirOverride
32+
} else {
33+
var err error
34+
configDir, err = os.UserConfigDir()
35+
if err != nil {
36+
return ""
37+
}
38+
}
39+
p := filepath.Join(configDir, "beads", "PRIME.md")
40+
if _, err := os.Stat(p); err == nil {
41+
return p
42+
}
43+
return ""
44+
}
45+
2646
var primeCmd = &cobra.Command{
2747
Use: "prime",
2848
GroupID: "setup",
@@ -86,6 +106,14 @@ Workflow customization:
86106
fmt.Print(string(content))
87107
return
88108
}
109+
// Fall back to global config (~/.config/beads/PRIME.md)
110+
// #nosec G304 -- path constructed from UserConfigDir which we control
111+
if globalPath := resolveGlobalPrimePath(""); globalPath != "" {
112+
if content, err := os.ReadFile(globalPath); err == nil {
113+
fmt.Print(string(content))
114+
return
115+
}
116+
}
89117
}
90118

91119
// Output workflow context (adaptive based on MCP and stealth mode)

cmd/bd/prime_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package main
22

33
import (
44
"bytes"
5+
"os"
6+
"path/filepath"
57
"strings"
68
"testing"
79
)
@@ -187,3 +189,40 @@ func stubPrimeHasGitRemote(hasRemote bool) func() {
187189
primeHasGitRemote = original
188190
}
189191
}
192+
193+
func TestPrimeGlobalFallback(t *testing.T) {
194+
// Create a temp directory to act as config dir
195+
tmpDir := t.TempDir()
196+
beadsConfigDir := filepath.Join(tmpDir, "beads")
197+
if err := os.MkdirAll(beadsConfigDir, 0755); err != nil {
198+
t.Fatalf("mkdir: %v", err)
199+
}
200+
201+
content := "# Global PRIME override\nCustom instructions here.\n"
202+
if err := os.WriteFile(filepath.Join(beadsConfigDir, "PRIME.md"), []byte(content), 0644); err != nil {
203+
t.Fatalf("write PRIME.md: %v", err)
204+
}
205+
206+
// Call the helper that resolves the global prime path
207+
got := resolveGlobalPrimePath(tmpDir)
208+
if got == "" {
209+
t.Fatal("resolveGlobalPrimePath returned empty, want path to global PRIME.md")
210+
}
211+
212+
data, err := os.ReadFile(got)
213+
if err != nil {
214+
t.Fatalf("ReadFile(%s): %v", got, err)
215+
}
216+
if string(data) != content {
217+
t.Errorf("content = %q, want %q", string(data), content)
218+
}
219+
}
220+
221+
func TestPrimeGlobalFallback_Missing(t *testing.T) {
222+
// When no global PRIME.md exists, should return empty string
223+
tmpDir := t.TempDir()
224+
got := resolveGlobalPrimePath(tmpDir)
225+
if got != "" {
226+
t.Errorf("resolveGlobalPrimePath = %q, want empty for missing file", got)
227+
}
228+
}

0 commit comments

Comments
 (0)