Better enable go extensions (#14)

* deps: run go mod tidy

* beads: Add public Go API for bd extensions

Implements a minimal public API to enable Go-based extensions without
exposing internal packages:

**New beads.go package:**
- Exports essential types: Issue, Status, IssueType, WorkFilter
- Provides status and issue type constants
- Exposes NewSQLiteStorage() as main entry point for extensions
- Includes comprehensive package documentation

**Updated EXTENDING.md:**
- Replaced internal package imports with public beads package
- Updated function calls to use new public API
- Changed sqlite.New() to beads.NewSQLiteStorage()
- Updated GetReady() to GetReadyWork() with WorkFilter

This enables clean Go-based orchestration extensions while maintaining
API stability and hiding internal implementation details.

* beads: Refine Go extensions API and documentation

Updates to the public Go API implementation following initial commit:

- Enhanced beads.go with refined extension interface
- Updated EXTENDING.md with clearer documentation
- Modified cmd/bd/main.go to support extension loading

Continues work on enabling Go-based bd extensions.

* Fix EXTENDING.md to use beads.WorkFilter instead of types.WorkFilter

The public API exports WorkFilter as beads.WorkFilter, not types.WorkFilter.
This fixes the code example to match the imports shown.

---------

Co-authored-by: Steve Yegge <steve.yegge@gmail.com>
This commit is contained in:
Travis Cline
2025-10-14 01:06:35 -07:00
committed by GitHub
parent 9f28d07a8a
commit 3b2c60d294
5 changed files with 169 additions and 93 deletions

View File

@@ -14,6 +14,7 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"github.com/steveyegge/beads"
"github.com/steveyegge/beads/internal/storage"
"github.com/steveyegge/beads/internal/storage/sqlite"
"github.com/steveyegge/beads/internal/types"
@@ -58,15 +59,11 @@ var rootCmd = &cobra.Command{
// Initialize storage
if dbPath == "" {
// Try to find database in order:
// 1. $BEADS_DB environment variable
// 2. .beads/*.db in current directory or ancestors
// 3. ~/.beads/default.db
if envDB := os.Getenv("BEADS_DB"); envDB != "" {
dbPath = envDB
} else if foundDB := findDatabase(); foundDB != "" {
// Use public API to find database (same logic as extensions)
if foundDB := beads.FindDatabasePath(); foundDB != "" {
dbPath = foundDB
} else {
// Fallback to default location (will be created by init command)
home, _ := os.UserHomeDir()
dbPath = filepath.Join(home, ".beads", "default.db")
}
@@ -128,37 +125,6 @@ var rootCmd = &cobra.Command{
},
}
// findDatabase searches for .beads/*.db in current directory and ancestors
func findDatabase() string {
dir, err := os.Getwd()
if err != nil {
return ""
}
// Walk up directory tree looking for .beads/ directory
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 ""
}
// outputJSON outputs data as pretty-printed JSON
func outputJSON(v interface{}) {
encoder := json.NewEncoder(os.Stdout)
@@ -171,26 +137,19 @@ func outputJSON(v interface{}) {
// findJSONLPath finds the JSONL file path for the current database
func findJSONLPath() string {
// Get the directory containing the database
dbDir := filepath.Dir(dbPath)
// Use public API for path discovery
jsonlPath := beads.FindJSONLPath(dbPath)
// Ensure the directory exists (important for new databases)
// This is the only difference from the public API - we create the directory
dbDir := filepath.Dir(dbPath)
if err := os.MkdirAll(dbDir, 0755); err != nil {
// If we can't create the directory, return default path anyway
// If we can't create the directory, return discovered path anyway
// (the subsequent write will fail with a clearer error)
return filepath.Join(dbDir, "issues.jsonl")
return jsonlPath
}
// 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")
return jsonlPath
}
// autoImportIfNewer checks if JSONL is newer than DB and imports if so