Files
gastown/internal/claude/settings.go
mayor f6f6acdb2d Consolidate Claude settings management
Settings creation was scattered across multiple places (createPatrolHooks,
ensurePatrolHooks, inline code). Now unified via claude.EnsureSettingsForRole().

Changes:
- Add "deacon" to autonomous roles in claude/settings.go
- Remove ensurePatrolHooks() from cmd/deacon.go, use EnsureSettingsForRole
- Remove createPatrolHooks() from rig/manager.go (no longer needed at rig add)
- Add EnsureSettingsForRole call in crew_lifecycle.go
- Add doctor check for stale/missing Claude settings files
- Wire up claude-settings check in cmd/doctor.go

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 01:51:24 -08:00

81 lines
2.2 KiB
Go

// Package claude provides Claude Code configuration management.
package claude
import (
"embed"
"fmt"
"os"
"path/filepath"
)
//go:embed config/*.json
var configFS embed.FS
// RoleType indicates whether a role is autonomous or interactive.
type RoleType string
const (
// Autonomous roles (polecat, witness, refinery) need mail in SessionStart
// because they may be triggered externally without user input.
Autonomous RoleType = "autonomous"
// Interactive roles (mayor, crew) wait for user input, so UserPromptSubmit
// handles mail injection.
Interactive RoleType = "interactive"
)
// RoleTypeFor returns the RoleType for a given role name.
func RoleTypeFor(role string) RoleType {
switch role {
case "polecat", "witness", "refinery", "deacon":
return Autonomous
default:
return Interactive
}
}
// EnsureSettings ensures .claude/settings.json exists in the given directory.
// For worktrees, we use sparse checkout to exclude source repo's .claude/ directory,
// so our settings.json is the only one Claude Code sees.
func EnsureSettings(workDir string, roleType RoleType) error {
claudeDir := filepath.Join(workDir, ".claude")
settingsPath := filepath.Join(claudeDir, "settings.json")
// If settings already exist, don't overwrite
if _, err := os.Stat(settingsPath); err == nil {
return nil
}
// Create .claude directory if needed
if err := os.MkdirAll(claudeDir, 0755); err != nil {
return fmt.Errorf("creating .claude directory: %w", err)
}
// Select template based on role type
var templateName string
switch roleType {
case Autonomous:
templateName = "config/settings-autonomous.json"
default:
templateName = "config/settings-interactive.json"
}
// Read template
content, err := configFS.ReadFile(templateName)
if err != nil {
return fmt.Errorf("reading template %s: %w", templateName, err)
}
// Write settings file
if err := os.WriteFile(settingsPath, content, 0600); err != nil {
return fmt.Errorf("writing settings: %w", err)
}
return nil
}
// EnsureSettingsForRole is a convenience function that combines RoleTypeFor and EnsureSettings.
func EnsureSettingsForRole(workDir, role string) error {
return EnsureSettings(workDir, RoleTypeFor(role))
}