Files
pad/internal/cli/workspace.go
T

90 lines
1.9 KiB
Go

package cli
import (
"fmt"
"os"
"path/filepath"
"github.com/BurntSushi/toml"
)
// PadToml represents the per-project workspace link file.
type PadToml struct {
Workspace string `toml:"workspace"`
AgentName string `toml:"agent_name,omitempty"` // optional: identifies which AI agent is acting
}
// DetectWorkspace walks up the directory tree from cwd looking for .pad.toml.
func DetectWorkspace(flagOverride string) (string, error) {
if flagOverride != "" {
return flagOverride, nil
}
cwd, err := os.Getwd()
if err != nil {
return "", err
}
dir := cwd
for {
configPath := filepath.Join(dir, ".pad.toml")
if _, err := os.Stat(configPath); err == nil {
var cfg PadToml
if _, err := toml.DecodeFile(configPath, &cfg); err != nil {
return "", fmt.Errorf("parse %s: %w", configPath, err)
}
if cfg.Workspace != "" {
return cfg.Workspace, nil
}
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
return "", fmt.Errorf("no workspace linked. Run 'pad workspace init' to create one")
}
// LoadPadToml finds and reads the nearest .pad.toml by walking up from cwd.
// Returns nil if no .pad.toml is found (not an error).
func LoadPadToml() (*PadToml, error) {
cwd, err := os.Getwd()
if err != nil {
return nil, err
}
dir := cwd
for {
configPath := filepath.Join(dir, ".pad.toml")
if _, err := os.Stat(configPath); err == nil {
var cfg PadToml
if _, err := toml.DecodeFile(configPath, &cfg); err != nil {
return nil, fmt.Errorf("parse %s: %w", configPath, err)
}
return &cfg, nil
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
return nil, nil
}
// WriteWorkspaceLink writes a .pad.toml in the given directory.
func WriteWorkspaceLink(dir, slug string) error {
path := filepath.Join(dir, ".pad.toml")
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
return toml.NewEncoder(f).Encode(PadToml{Workspace: slug})
}