fix(dolt): enable server mode for Gas Town integration (bd-nnjik)

- Skip Bootstrap when ServerMode is true (bootstrap is for embedded cold-start)
- Fix doltExists() to follow symlinks using os.Stat
- Pass database name from metadata.json to DoltStore config

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
beads/crew/emma
2026-01-23 22:24:55 -08:00
committed by Steve Yegge
parent a9c8c952f6
commit db0c6fbd3f
4 changed files with 51 additions and 24 deletions

View File

@@ -262,3 +262,16 @@ func (c *Config) GetDoltServerUser() string {
}
return c.DoltServerUser
}
// GetDoltDatabase returns the database name for Dolt server mode.
// This is different from DatabasePath which returns the on-disk path.
// For server mode, Database field contains the database name on the server
// (e.g., "hq", "gastown", "beads"). Defaults to "beads".
func (c *Config) GetDoltDatabase() string {
db := strings.TrimSpace(c.Database)
if db == "" || db == "beads.db" || db == "dolt" {
return "beads"
}
// Strip any path components - just want the database name
return filepath.Base(db)
}

View File

@@ -101,9 +101,15 @@ func doltExists(doltPath string) bool {
}
for _, entry := range entries {
if entry.IsDir() {
doltDir := filepath.Join(doltPath, entry.Name(), ".dolt")
if info, err := os.Stat(doltDir); err == nil && info.IsDir() {
// Use os.Stat to follow symlinks - entry.IsDir() returns false for symlinks
fullPath := filepath.Join(doltPath, entry.Name())
info, err := os.Stat(fullPath)
if err != nil {
continue
}
if info.IsDir() {
doltDir := filepath.Join(fullPath, ".dolt")
if doltInfo, err := os.Stat(doltDir); err == nil && doltInfo.IsDir() {
return true
}
}

View File

@@ -32,6 +32,7 @@ type Options struct {
ServerHost string // Server host (default: 127.0.0.1)
ServerPort int // Server port (default: 3306)
ServerUser string // MySQL user (default: root)
Database string // Database name for Dolt server mode (default: beads)
}
// New creates a storage backend based on the backend type.
@@ -101,6 +102,9 @@ func NewFromConfigWithOptions(ctx context.Context, beadsDir string, opts Options
if opts.ServerUser == "" {
opts.ServerUser = cfg.GetDoltServerUser()
}
if opts.Database == "" {
opts.Database = cfg.GetDoltDatabase()
}
}
return NewWithOptions(ctx, backend, cfg.DatabasePath(beadsDir), opts)
default:

View File

@@ -15,34 +15,38 @@ import (
func init() {
RegisterBackend(configfile.BackendDolt, func(ctx context.Context, path string, opts Options) (storage.Storage, error) {
// Check if bootstrap is needed (JSONL exists but Dolt doesn't)
// Path is the dolt subdirectory, parent is .beads directory
beadsDir := filepath.Dir(path)
// Only bootstrap in embedded mode - server mode has database on server
if !opts.ServerMode {
// Check if bootstrap is needed (JSONL exists but Dolt doesn't)
// Path is the dolt subdirectory, parent is .beads directory
beadsDir := filepath.Dir(path)
bootstrapped, result, err := dolt.Bootstrap(ctx, dolt.BootstrapConfig{
BeadsDir: beadsDir,
DoltPath: path,
LockTimeout: opts.LockTimeout,
})
if err != nil {
return nil, fmt.Errorf("bootstrap failed: %w", err)
}
bootstrapped, result, err := dolt.Bootstrap(ctx, dolt.BootstrapConfig{
BeadsDir: beadsDir,
DoltPath: path,
LockTimeout: opts.LockTimeout,
})
if err != nil {
return nil, fmt.Errorf("bootstrap failed: %w", err)
}
if bootstrapped && result != nil {
// Report bootstrap results
fmt.Fprintf(os.Stderr, "Bootstrapping Dolt from JSONL...\n")
if len(result.ParseErrors) > 0 {
fmt.Fprintf(os.Stderr, " Skipped %d malformed lines (see above for details)\n", len(result.ParseErrors))
if bootstrapped && result != nil {
// Report bootstrap results
fmt.Fprintf(os.Stderr, "Bootstrapping Dolt from JSONL...\n")
if len(result.ParseErrors) > 0 {
fmt.Fprintf(os.Stderr, " Skipped %d malformed lines (see above for details)\n", len(result.ParseErrors))
}
fmt.Fprintf(os.Stderr, " Imported %d issues", result.IssuesImported)
if result.IssuesSkipped > 0 {
fmt.Fprintf(os.Stderr, ", skipped %d duplicates", result.IssuesSkipped)
}
fmt.Fprintf(os.Stderr, "\n Dolt database ready\n")
}
fmt.Fprintf(os.Stderr, " Imported %d issues", result.IssuesImported)
if result.IssuesSkipped > 0 {
fmt.Fprintf(os.Stderr, ", skipped %d duplicates", result.IssuesSkipped)
}
fmt.Fprintf(os.Stderr, "\n Dolt database ready\n")
}
return dolt.New(ctx, &dolt.Config{
Path: path,
Database: opts.Database,
ReadOnly: opts.ReadOnly,
ServerMode: opts.ServerMode,
ServerHost: opts.ServerHost,