Skip to content

Commit 146bccc

Browse files
authored
[feat] Auto-derive opinionated config fields (#82)
[feat] Auto-derive opinionated config fields (#80) Make worktree_dir, default_source, and copy_files optional with auto-derivation. rimba init now writes only copy_files to settings.toml. Existing configs with explicit values continue working unchanged.
1 parent cd4e386 commit 146bccc

8 files changed

Lines changed: 172 additions & 81 deletions

File tree

cmd/init.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ directory is already personal.`,
101101
return err
102102
}
103103

104-
cfg := config.DefaultConfig(repoName, defaultBranch)
104+
// Write minimal config — only copy_files (everything else auto-derived)
105+
cfg := &config.Config{
106+
CopyFiles: config.DefaultCopyFiles(),
107+
}
105108

106109
if err := os.MkdirAll(dirPath, 0750); err != nil {
107110
return fmt.Errorf("failed to create config directory: %w", err)
@@ -117,8 +120,8 @@ directory is already personal.`,
117120
}
118121
}
119122

120-
// Create the worktree directory
121-
wtDir := filepath.Join(repoRoot, cfg.WorktreeDir)
123+
// Create the worktree directory using convention
124+
wtDir := filepath.Join(repoRoot, config.DefaultWorktreeDir(repoName))
122125
if err := os.MkdirAll(wtDir, 0750); err != nil {
123126
return fmt.Errorf("failed to create worktree directory: %w", err)
124127
}

cmd/init_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func TestInitSuccess(t *testing.T) {
5454

5555
// Verify worktree dir was created
5656
repoName := filepath.Base(repoDir)
57-
wtDir := filepath.Join(repoDir, "../"+repoName+"-worktrees")
57+
wtDir := filepath.Join(repoDir, config.DefaultWorktreeDir(repoName))
5858
if _, err := os.Stat(wtDir); os.IsNotExist(err) {
5959
t.Errorf("worktree dir not created at %s", wtDir)
6060
}

cmd/mcp.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cmd
22

33
import (
4+
"path/filepath"
5+
46
"github.com/lugassawan/rimba/internal/config"
57
"github.com/lugassawan/rimba/internal/git"
68
mcppkg "github.com/lugassawan/rimba/internal/mcp"
@@ -33,6 +35,14 @@ To configure in Claude Code, add to .claude/settings.json:
3335

3436
// Config is optional — some tools work without it.
3537
cfg, _ := config.Resolve(repoRoot)
38+
if cfg != nil {
39+
repoName := filepath.Base(repoRoot)
40+
var defaultBranch string
41+
if cfg.DefaultSource == "" {
42+
defaultBranch, _ = git.DefaultBranch(r)
43+
}
44+
cfg.FillDefaults(repoName, defaultBranch)
45+
}
3646

3747
hctx := &mcppkg.HandlerContext{
3848
Runner: r,

cmd/root.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"path/filepath"
45
"strings"
56
"time"
67

@@ -57,6 +58,18 @@ var rootCmd = &cobra.Command{
5758
if err != nil {
5859
return err
5960
}
61+
62+
// Auto-derive missing fields
63+
repoName := filepath.Base(repoRoot)
64+
var defaultBranch string
65+
if cfg.DefaultSource == "" {
66+
defaultBranch, err = git.DefaultBranch(r)
67+
if err != nil {
68+
return err
69+
}
70+
}
71+
cfg.FillDefaults(repoName, defaultBranch)
72+
6073
cmd.SetContext(config.WithConfig(cmd.Context(), cfg))
6174
return nil
6275
},

internal/config/config.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package config
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"os"
87
"path/filepath"
@@ -21,8 +20,8 @@ const (
2120
)
2221

2322
type Config struct {
24-
WorktreeDir string `toml:"worktree_dir"`
25-
DefaultSource string `toml:"default_source"`
23+
WorktreeDir string `toml:"worktree_dir,omitempty"`
24+
DefaultSource string `toml:"default_source,omitempty"`
2625
CopyFiles []string `toml:"copy_files"`
2726
PostCreate []string `toml:"post_create,omitempty"`
2827

@@ -44,12 +43,6 @@ type ModuleConfig struct {
4443
WorkDir string `toml:"work_dir,omitempty"`
4544
}
4645

47-
// Validation error messages for required config fields.
48-
const (
49-
ErrMsgEmptyWorktreeDir = "worktree_dir must not be empty"
50-
ErrMsgEmptyDefaultSource = "default_source must not be empty"
51-
)
52-
5346
// IsAutoDetectDeps returns whether automatic dependency detection is enabled.
5447
// Defaults to true when Deps or AutoDetect is not configured.
5548
func (c *Config) IsAutoDetectDeps() bool {
@@ -59,29 +52,41 @@ func (c *Config) IsAutoDetectDeps() bool {
5952
return *c.Deps.AutoDetect
6053
}
6154

62-
// Validate checks that required config fields are present.
55+
// Validate checks config fields for consistency.
6356
func (c *Config) Validate() error {
64-
var errs []error
57+
return nil
58+
}
59+
60+
// DefaultWorktreeDir returns the conventional worktree directory path for a repo.
61+
func DefaultWorktreeDir(repoName string) string {
62+
return "../" + repoName + "-worktrees"
63+
}
64+
65+
// DefaultCopyFiles returns the default list of files copied to new worktrees.
66+
func DefaultCopyFiles() []string {
67+
return []string{".env", ".env.local", ".envrc", ".tool-versions"}
68+
}
69+
70+
// FillDefaults fills missing config fields with auto-derived values.
71+
// repoName is used for WorktreeDir; defaultBranch is used for DefaultSource.
72+
func (c *Config) FillDefaults(repoName, defaultBranch string) {
6573
if c.WorktreeDir == "" {
66-
errs = append(errs, errors.New(ErrMsgEmptyWorktreeDir))
74+
c.WorktreeDir = DefaultWorktreeDir(repoName)
6775
}
6876
if c.DefaultSource == "" {
69-
errs = append(errs, errors.New(ErrMsgEmptyDefaultSource))
77+
c.DefaultSource = defaultBranch
7078
}
71-
if len(errs) > 0 {
72-
return fmt.Errorf("invalid config: %w", errors.Join(errs...))
79+
if c.CopyFiles == nil {
80+
c.CopyFiles = DefaultCopyFiles()
7381
}
74-
return nil
7582
}
7683

7784
type ctxKey struct{}
7885

7986
func DefaultConfig(repoName, defaultBranch string) *Config {
80-
return &Config{
81-
WorktreeDir: "../" + repoName + "-worktrees",
82-
DefaultSource: defaultBranch,
83-
CopyFiles: []string{".env", ".env.local", ".envrc", ".tool-versions"},
84-
}
87+
cfg := &Config{}
88+
cfg.FillDefaults(repoName, defaultBranch)
89+
return cfg
8590
}
8691

8792
func Load(path string) (*Config, error) {

0 commit comments

Comments
 (0)