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>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/gastown/internal/beads"
|
||||
"github.com/steveyegge/gastown/internal/claude"
|
||||
"github.com/steveyegge/gastown/internal/config"
|
||||
"github.com/steveyegge/gastown/internal/constants"
|
||||
"github.com/steveyegge/gastown/internal/crew"
|
||||
@@ -577,6 +578,11 @@ func restartCrewSession(rigName, crewName, clonePath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Claude settings exist (crew is interactive role)
|
||||
if err := claude.EnsureSettingsForRole(clonePath, "crew"); err != nil {
|
||||
return fmt.Errorf("ensuring Claude settings: %w", err)
|
||||
}
|
||||
|
||||
// Start new session
|
||||
if err := t.NewSession(sessionID, clonePath); err != nil {
|
||||
return fmt.Errorf("creating session: %w", err)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/steveyegge/gastown/internal/beads"
|
||||
"github.com/steveyegge/gastown/internal/claude"
|
||||
"github.com/steveyegge/gastown/internal/config"
|
||||
"github.com/steveyegge/gastown/internal/constants"
|
||||
"github.com/steveyegge/gastown/internal/deacon"
|
||||
@@ -274,9 +275,9 @@ func startDeaconSession(t *tmux.Tmux, sessionName string) error {
|
||||
return fmt.Errorf("creating deacon directory: %w", err)
|
||||
}
|
||||
|
||||
// Ensure deacon has patrol hooks (idempotent)
|
||||
if err := ensurePatrolHooks(deaconDir); err != nil {
|
||||
style.PrintWarning("Could not create deacon hooks: %v", err)
|
||||
// Ensure Claude settings exist (autonomous role needs mail in SessionStart)
|
||||
if err := claude.EnsureSettingsForRole(deaconDir, "deacon"); err != nil {
|
||||
style.PrintWarning("Could not create deacon settings: %v", err)
|
||||
}
|
||||
|
||||
// Create session in deacon directory
|
||||
@@ -526,64 +527,6 @@ func runDeaconTriggerPending(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensurePatrolHooks creates .claude/settings.json with hooks for patrol roles.
|
||||
// This is idempotent - if hooks already exist, it does nothing.
|
||||
func ensurePatrolHooks(workspacePath string) error {
|
||||
settingsPath := filepath.Join(workspacePath, ".claude", "settings.json")
|
||||
|
||||
// Check if already exists
|
||||
if _, err := os.Stat(settingsPath); err == nil {
|
||||
return nil // Already exists
|
||||
}
|
||||
|
||||
claudeDir := filepath.Join(workspacePath, ".claude")
|
||||
if err := os.MkdirAll(claudeDir, 0755); err != nil {
|
||||
return fmt.Errorf("creating .claude dir: %w", err)
|
||||
}
|
||||
|
||||
// Standard patrol hooks
|
||||
// Note: SessionStart nudges Deacon for GUPP backstop (agent wake notification)
|
||||
hooksJSON := `{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "gt prime && gt mail check --inject && gt nudge deacon session-started"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "gt prime"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "gt mail check --inject"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`
|
||||
return os.WriteFile(settingsPath, []byte(hooksJSON), 0600)
|
||||
}
|
||||
|
||||
// runDeaconHealthCheck implements the health-check command.
|
||||
// It sends a HEALTH_CHECK nudge to an agent, waits for response, and tracks state.
|
||||
func runDeaconHealthCheck(cmd *cobra.Command, args []string) error {
|
||||
|
||||
@@ -63,6 +63,7 @@ Routing checks (fixable):
|
||||
|
||||
Session hook checks:
|
||||
- session-hooks Check settings.json use session-start.sh
|
||||
- claude-settings Check Claude settings.json match templates (fixable)
|
||||
|
||||
Patrol checks:
|
||||
- patrol-molecules-exist Verify patrol molecules exist
|
||||
@@ -137,6 +138,7 @@ func runDoctor(cmd *cobra.Command, args []string) error {
|
||||
d.Register(doctor.NewSessionHookCheck())
|
||||
d.Register(doctor.NewRuntimeGitignoreCheck())
|
||||
d.Register(doctor.NewLegacyGastownCheck())
|
||||
d.Register(doctor.NewClaudeSettingsCheck())
|
||||
|
||||
// Crew workspace checks
|
||||
d.Register(doctor.NewCrewStateCheck())
|
||||
|
||||
Reference in New Issue
Block a user