Files
beads/beads.go
Steve Yegge a971762b0e Remove ~/.beads fallback behavior
- Remove ~/.beads/default.db fallback from FindDatabasePath()
- Update daemon to error if no database found instead of falling back
- Update main.go to require explicit database initialization
- Add help/version/quickstart to commands that don't need database
- Add MCP client debug logging for database routing

Amp-Thread-ID: https://ampcode.com/threads/T-2b757a14-cf10-400e-a83c-30349182dd82
Co-authored-by: Amp <amp@ampcode.com>
2025-10-17 10:56:52 -07:00

129 lines
3.5 KiB
Go

// Package beads provides a minimal public API for extending bd with custom orchestration.
//
// Most extensions should use direct SQL queries against bd's database.
// This package exports only the essential types and functions needed for
// Go-based extensions that want to use bd's storage layer programmatically.
//
// For detailed guidance on extending bd, see EXTENDING.md.
package beads
import (
"os"
"path/filepath"
"github.com/steveyegge/beads/internal/storage"
"github.com/steveyegge/beads/internal/storage/sqlite"
"github.com/steveyegge/beads/internal/types"
)
// Core types for working with issues
type (
Issue = types.Issue
Status = types.Status
IssueType = types.IssueType
WorkFilter = types.WorkFilter
)
// Status constants
const (
StatusOpen = types.StatusOpen
StatusInProgress = types.StatusInProgress
StatusClosed = types.StatusClosed
StatusBlocked = types.StatusBlocked
)
// IssueType constants
const (
TypeBug = types.TypeBug
TypeFeature = types.TypeFeature
TypeTask = types.TypeTask
TypeEpic = types.TypeEpic
TypeChore = types.TypeChore
)
// Storage provides the minimal interface for extension orchestration
type Storage = storage.Storage
// NewSQLiteStorage opens a bd SQLite database for programmatic access.
// Most extensions should use this to query ready work and update issue status.
func NewSQLiteStorage(dbPath string) (Storage, error) {
return sqlite.New(dbPath)
}
// FindDatabasePath discovers the bd database path using bd's standard search order:
// 1. $BEADS_DB environment variable
// 2. .beads/*.db in current directory or ancestors
//
// Returns empty string if no database is found.
func FindDatabasePath() string {
// 1. Check environment variable
if envDB := os.Getenv("BEADS_DB"); envDB != "" {
return envDB
}
// 2. Search for .beads/*.db in current directory and ancestors
if foundDB := findDatabaseInTree(); foundDB != "" {
return foundDB
}
// No fallback to ~/.beads - return empty string
return ""
}
// FindJSONLPath returns the expected JSONL file path for the given database path.
// It searches for existing *.jsonl files in the database directory and returns
// the first one found, or defaults to "issues.jsonl".
//
// This function does not create directories or files - it only discovers paths.
// Use this when you need to know where bd stores its JSONL export.
func FindJSONLPath(dbPath string) string {
if dbPath == "" {
return ""
}
// Get the directory containing the database
dbDir := filepath.Dir(dbPath)
// Look for existing .jsonl files in the .beads directory
pattern := filepath.Join(dbDir, "*.jsonl")
matches, err := filepath.Glob(pattern)
if err == nil && len(matches) > 0 {
// Return the first .jsonl file found
return matches[0]
}
// Default to issues.jsonl
return filepath.Join(dbDir, "issues.jsonl")
}
// findDatabaseInTree walks up the directory tree looking for .beads/*.db
func findDatabaseInTree() string {
dir, err := os.Getwd()
if err != nil {
return ""
}
// Walk up directory tree
for {
beadsDir := filepath.Join(dir, ".beads")
if info, err := os.Stat(beadsDir); err == nil && info.IsDir() {
// Found .beads/ directory, look for *.db files
matches, err := filepath.Glob(filepath.Join(beadsDir, "*.db"))
if err == nil && len(matches) > 0 {
// Return first .db file found
return matches[0]
}
}
// Move up one directory
parent := filepath.Dir(dir)
if parent == dir {
// Reached filesystem root
break
}
dir = parent
}
return ""
}