feat(v0.4.1): add config.SearchRoots for multi-root workspace lookup
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,35 @@ func ResolveProjectRoot() string {
|
||||
return expandPath(v)
|
||||
}
|
||||
|
||||
// SearchRoots returns the deduplicated list of workspace roots that all query
|
||||
// and listing operations must consult. Always includes CTASK_ROOT; also
|
||||
// includes CTASK_PROJECT_ROOT when set and different from CTASK_ROOT.
|
||||
func SearchRoots() []string {
|
||||
taskRoot := ResolveRoot()
|
||||
roots := []string{taskRoot}
|
||||
|
||||
projRoot := ResolveProjectRoot()
|
||||
if projRoot == "" {
|
||||
return roots
|
||||
}
|
||||
|
||||
if samePath(taskRoot, projRoot) {
|
||||
return roots
|
||||
}
|
||||
return append(roots, projRoot)
|
||||
}
|
||||
|
||||
// samePath reports whether two absolute paths refer to the same directory
|
||||
// on the current platform. Uses case-insensitive compare on Windows.
|
||||
func samePath(a, b string) bool {
|
||||
ac := filepath.Clean(a)
|
||||
bc := filepath.Clean(b)
|
||||
if runtime.GOOS == "windows" {
|
||||
return strings.EqualFold(ac, bc)
|
||||
}
|
||||
return ac == bc
|
||||
}
|
||||
|
||||
// EnvVars returns the environment variables to export into child sessions.
|
||||
// taskType must be "task" or "project"; an empty value defaults to "task".
|
||||
func EnvVars(slug, mode, root, workspace, category, taskType string) map[string]string {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSearchRootsUnsetProjectRoot(t *testing.T) {
|
||||
os.Unsetenv("CTASK_PROJECT_ROOT")
|
||||
os.Setenv("CTASK_ROOT", t.TempDir())
|
||||
defer os.Unsetenv("CTASK_ROOT")
|
||||
|
||||
roots := SearchRoots()
|
||||
if len(roots) != 1 {
|
||||
t.Fatalf("expected 1 root, got %d: %v", len(roots), roots)
|
||||
}
|
||||
if roots[0] != ResolveRoot() {
|
||||
t.Errorf("root mismatch: got %q, want %q", roots[0], ResolveRoot())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchRootsDistinctProjectRoot(t *testing.T) {
|
||||
taskRoot := t.TempDir()
|
||||
projRoot := t.TempDir()
|
||||
os.Setenv("CTASK_ROOT", taskRoot)
|
||||
os.Setenv("CTASK_PROJECT_ROOT", projRoot)
|
||||
defer os.Unsetenv("CTASK_ROOT")
|
||||
defer os.Unsetenv("CTASK_PROJECT_ROOT")
|
||||
|
||||
roots := SearchRoots()
|
||||
if len(roots) != 2 {
|
||||
t.Fatalf("expected 2 roots, got %d: %v", len(roots), roots)
|
||||
}
|
||||
absTask, _ := filepath.Abs(taskRoot)
|
||||
absProj, _ := filepath.Abs(projRoot)
|
||||
if roots[0] != absTask || roots[1] != absProj {
|
||||
t.Errorf("roots: got %v, want [%q, %q]", roots, absTask, absProj)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchRootsSameRootDedupes(t *testing.T) {
|
||||
d := t.TempDir()
|
||||
os.Setenv("CTASK_ROOT", d)
|
||||
os.Setenv("CTASK_PROJECT_ROOT", d)
|
||||
defer os.Unsetenv("CTASK_ROOT")
|
||||
defer os.Unsetenv("CTASK_PROJECT_ROOT")
|
||||
|
||||
roots := SearchRoots()
|
||||
if len(roots) != 1 {
|
||||
t.Fatalf("expected 1 root (dedup), got %d: %v", len(roots), roots)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user