Merge pull request #279 from joshuavial/fix/polecat-dotdir-scan

fix: extend polecat dot-dir filtering beyond #258
This commit is contained in:
Steve Yegge
2026-01-08 17:23:26 -08:00
committed by GitHub
8 changed files with 239 additions and 19 deletions

View File

@@ -139,7 +139,7 @@ func discoverHooks(townRoot string) ([]HookInfo, error) {
polecatsDir := filepath.Join(rigPath, "polecats")
if polecats, err := os.ReadDir(polecatsDir); err == nil {
for _, p := range polecats {
if p.IsDir() {
if p.IsDir() && !strings.HasPrefix(p.Name(), ".") {
locations = append(locations, struct {
path string
agent string

View File

@@ -0,0 +1,201 @@
package cmd
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/spf13/cobra"
"github.com/steveyegge/gastown/internal/config"
)
func TestDiscoverHooksSkipsPolecatDotDirs(t *testing.T) {
townRoot := setupTestTownForDotDir(t)
rigPath := filepath.Join(townRoot, "gastown")
settingsPath := filepath.Join(rigPath, "polecats", ".claude", ".claude", "settings.json")
if err := os.MkdirAll(filepath.Dir(settingsPath), 0755); err != nil {
t.Fatalf("mkdir settings dir: %v", err)
}
settings := `{"hooks":{"SessionStart":[{"matcher":"*","hooks":[{"type":"Stop","command":"echo hi"}]}]}}`
if err := os.WriteFile(settingsPath, []byte(settings), 0644); err != nil {
t.Fatalf("write settings: %v", err)
}
hooks, err := discoverHooks(townRoot)
if err != nil {
t.Fatalf("discoverHooks: %v", err)
}
if len(hooks) != 0 {
t.Fatalf("expected no hooks, got %d", len(hooks))
}
}
func TestStartPolecatsWithWorkSkipsDotDirs(t *testing.T) {
townRoot := setupTestTownForDotDir(t)
rigName := "gastown"
rigPath := filepath.Join(townRoot, rigName)
addRigEntry(t, townRoot, rigName)
if err := os.MkdirAll(filepath.Join(rigPath, "polecats", ".claude"), 0755); err != nil {
t.Fatalf("mkdir .claude polecat: %v", err)
}
if err := os.MkdirAll(filepath.Join(rigPath, "polecats", "toast"), 0755); err != nil {
t.Fatalf("mkdir polecat: %v", err)
}
binDir := t.TempDir()
bdScript := `#!/bin/sh
if [ "$1" = "--no-daemon" ]; then
shift
fi
cmd="$1"
case "$cmd" in
list)
if [ "$(basename "$PWD")" = ".claude" ]; then
echo '[{"id":"gt-1"}]'
else
echo '[]'
fi
exit 0
;;
*)
exit 0
;;
esac
`
writeScript(t, binDir, "bd", bdScript)
tmuxScript := `#!/bin/sh
if [ "$1" = "has-session" ]; then
echo "tmux error" 1>&2
exit 1
fi
exit 0
`
writeScript(t, binDir, "tmux", tmuxScript)
t.Setenv("PATH", fmt.Sprintf("%s:%s", binDir, os.Getenv("PATH")))
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("getwd: %v", err)
}
t.Cleanup(func() { _ = os.Chdir(cwd) })
if err := os.Chdir(townRoot); err != nil {
t.Fatalf("chdir town root: %v", err)
}
started, errs := startPolecatsWithWork(townRoot, rigName)
if len(started) != 0 {
t.Fatalf("expected no polecats started, got %v", started)
}
if len(errs) != 0 {
t.Fatalf("expected no errors, got %v", errs)
}
}
func TestRunSessionCheckSkipsDotDirs(t *testing.T) {
townRoot := setupTestTownForDotDir(t)
rigName := "gastown"
rigPath := filepath.Join(townRoot, rigName)
addRigEntry(t, townRoot, rigName)
if err := os.MkdirAll(filepath.Join(rigPath, "polecats", ".claude"), 0755); err != nil {
t.Fatalf("mkdir .claude polecat: %v", err)
}
binDir := t.TempDir()
tmuxScript := `#!/bin/sh
if [ "$1" = "has-session" ]; then
echo "can't find session" 1>&2
exit 1
fi
exit 0
`
writeScript(t, binDir, "tmux", tmuxScript)
t.Setenv("PATH", fmt.Sprintf("%s:%s", binDir, os.Getenv("PATH")))
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("getwd: %v", err)
}
t.Cleanup(func() { _ = os.Chdir(cwd) })
if err := os.Chdir(townRoot); err != nil {
t.Fatalf("chdir town root: %v", err)
}
output := captureStdout(t, func() {
if err := runSessionCheck(&cobra.Command{}, []string{rigName}); err != nil {
t.Fatalf("runSessionCheck: %v", err)
}
})
if strings.Contains(output, ".claude") {
t.Fatalf("expected .claude to be ignored, output:\n%s", output)
}
}
func addRigEntry(t *testing.T, townRoot, rigName string) {
t.Helper()
rigsPath := filepath.Join(townRoot, "mayor", "rigs.json")
rigsConfig, err := config.LoadRigsConfig(rigsPath)
if err != nil {
t.Fatalf("load rigs.json: %v", err)
}
if rigsConfig.Rigs == nil {
rigsConfig.Rigs = make(map[string]config.RigEntry)
}
rigsConfig.Rigs[rigName] = config.RigEntry{
GitURL: "file:///dev/null",
AddedAt: time.Now(),
}
if err := config.SaveRigsConfig(rigsPath, rigsConfig); err != nil {
t.Fatalf("save rigs.json: %v", err)
}
}
func setupTestTownForDotDir(t *testing.T) string {
t.Helper()
townRoot := t.TempDir()
mayorDir := filepath.Join(townRoot, "mayor")
if err := os.MkdirAll(mayorDir, 0755); err != nil {
t.Fatalf("mkdir mayor: %v", err)
}
rigsPath := filepath.Join(mayorDir, "rigs.json")
rigsConfig := &config.RigsConfig{
Version: 1,
Rigs: make(map[string]config.RigEntry),
}
if err := config.SaveRigsConfig(rigsPath, rigsConfig); err != nil {
t.Fatalf("save rigs.json: %v", err)
}
beadsDir := filepath.Join(townRoot, ".beads")
if err := os.MkdirAll(beadsDir, 0755); err != nil {
t.Fatalf("mkdir .beads: %v", err)
}
return townRoot
}
func writeScript(t *testing.T, dir, name, content string) {
t.Helper()
path := filepath.Join(dir, name)
if err := os.WriteFile(path, []byte(content), 0755); err != nil {
t.Fatalf("write %s: %v", name, err)
}
}

View File

@@ -649,6 +649,9 @@ func runSessionCheck(cmd *cobra.Command, args []string) error {
if !entry.IsDir() {
continue
}
if strings.HasPrefix(entry.Name(), ".") {
continue
}
polecatName := entry.Name()
sessionName := fmt.Sprintf("gt-%s-%s", r.Name, polecatName)
totalChecked++

View File

@@ -451,6 +451,9 @@ func startPolecatsWithWork(townRoot, rigName string) ([]string, map[string]error
if !entry.IsDir() {
continue
}
if strings.HasPrefix(entry.Name(), ".") {
continue
}
polecatName := entry.Name()
polecatPath := filepath.Join(polecatsDir, polecatName)