fix(hooks): remove Stop hook that caused 30s timeouts (gt-quoj)
The Stop hook with `gt costs record` was causing 30-second timeouts on every session stop due to beads socket connection issues. Since cost tracking is disabled anyway (Claude Code doesn't expose session costs), this hook provided no value. Changes: - Remove Stop hook from settings-autonomous.json and settings-interactive.json - Remove Stop hook validation from claude_settings_check.go - Update tests to not expect Stop hook The cost tracking infrastructure remains in costs.go for future use when Claude Code exposes session costs via API or environment variable. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -65,17 +65,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"Stop": [
|
|
||||||
{
|
|
||||||
"matcher": "",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "export PATH=\"$HOME/go/bin:$HOME/bin:$PATH\" && gt costs record"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,17 +65,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"Stop": [
|
|
||||||
{
|
|
||||||
"matcher": "",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "export PATH=\"$HOME/go/bin:$HOME/bin:$PATH\" && gt costs record"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -335,8 +335,8 @@ func (c *ClaudeSettingsCheck) checkSettings(path, _ string) []string {
|
|||||||
// All templates should have:
|
// All templates should have:
|
||||||
// 1. enabledPlugins
|
// 1. enabledPlugins
|
||||||
// 2. PATH export in hooks
|
// 2. PATH export in hooks
|
||||||
// 3. Stop hook with gt costs record (for autonomous)
|
// 3. gt nudge deacon session-started in SessionStart
|
||||||
// 4. gt nudge deacon session-started in SessionStart
|
// Note: Stop hook was removed (gt-quoj) - cost tracking is disabled
|
||||||
|
|
||||||
// Check enabledPlugins
|
// Check enabledPlugins
|
||||||
if _, ok := actual["enabledPlugins"]; !ok {
|
if _, ok := actual["enabledPlugins"]; !ok {
|
||||||
@@ -359,10 +359,9 @@ func (c *ClaudeSettingsCheck) checkSettings(path, _ string) []string {
|
|||||||
missing = append(missing, "deacon nudge")
|
missing = append(missing, "deacon nudge")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Stop hook exists with gt costs record (for all roles)
|
// Note: Stop hook with gt costs record was removed in gt-quoj.
|
||||||
if !c.hookHasPattern(hooks, "Stop", "gt costs record") {
|
// Cost tracking is disabled - Claude Code doesn't expose session costs.
|
||||||
missing = append(missing, "Stop hook")
|
// The Stop hook was causing 30s timeouts on session stop with no benefit.
|
||||||
}
|
|
||||||
|
|
||||||
return missing
|
return missing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,17 +56,6 @@ func createValidSettings(t *testing.T, path string) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Stop": []any{
|
|
||||||
map[string]any{
|
|
||||||
"matcher": "**",
|
|
||||||
"hooks": []any{
|
|
||||||
map[string]any{
|
|
||||||
"type": "command",
|
|
||||||
"command": "gt costs record --session $CLAUDE_SESSION_ID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,17 +95,6 @@ func createStaleSettings(t *testing.T, path string, missingElements ...string) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"Stop": []any{
|
|
||||||
map[string]any{
|
|
||||||
"matcher": "**",
|
|
||||||
"hooks": []any{
|
|
||||||
map[string]any{
|
|
||||||
"type": "command",
|
|
||||||
"command": "gt costs record --session $CLAUDE_SESSION_ID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,9 +134,6 @@ func createStaleSettings(t *testing.T, path string, missingElements ...string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
hookObj["hooks"] = filtered
|
hookObj["hooks"] = filtered
|
||||||
case "Stop":
|
|
||||||
hooks := settings["hooks"].(map[string]any)
|
|
||||||
delete(hooks, "Stop")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,33 +349,6 @@ func TestClaudeSettingsCheck_MissingDeaconNudge(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClaudeSettingsCheck_MissingStopHook(t *testing.T) {
|
|
||||||
tmpDir := t.TempDir()
|
|
||||||
|
|
||||||
// Create stale settings missing Stop hook (at correct location)
|
|
||||||
mayorSettings := filepath.Join(tmpDir, "mayor", ".claude", "settings.json")
|
|
||||||
createStaleSettings(t, mayorSettings, "Stop")
|
|
||||||
|
|
||||||
check := NewClaudeSettingsCheck()
|
|
||||||
ctx := &CheckContext{TownRoot: tmpDir}
|
|
||||||
|
|
||||||
result := check.Run(ctx)
|
|
||||||
|
|
||||||
if result.Status != StatusError {
|
|
||||||
t.Errorf("expected StatusError for missing Stop hook, got %v", result.Status)
|
|
||||||
}
|
|
||||||
found := false
|
|
||||||
for _, d := range result.Details {
|
|
||||||
if strings.Contains(d, "Stop hook") {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
t.Errorf("expected details to mention Stop hook, got %v", result.Details)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClaudeSettingsCheck_WrongLocationWitness(t *testing.T) {
|
func TestClaudeSettingsCheck_WrongLocationWitness(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
rigName := "testrig"
|
rigName := "testrig"
|
||||||
@@ -468,7 +416,7 @@ func TestClaudeSettingsCheck_MultipleStaleFiles(t *testing.T) {
|
|||||||
createStaleSettings(t, mayorSettings, "PATH")
|
createStaleSettings(t, mayorSettings, "PATH")
|
||||||
|
|
||||||
deaconSettings := filepath.Join(tmpDir, "deacon", ".claude", "settings.json")
|
deaconSettings := filepath.Join(tmpDir, "deacon", ".claude", "settings.json")
|
||||||
createStaleSettings(t, deaconSettings, "Stop")
|
createStaleSettings(t, deaconSettings, "deacon-nudge")
|
||||||
|
|
||||||
// Settings inside git repo (witness/rig/.claude/) are wrong location
|
// Settings inside git repo (witness/rig/.claude/) are wrong location
|
||||||
witnessWrong := filepath.Join(tmpDir, rigName, "witness", "rig", ".claude", "settings.json")
|
witnessWrong := filepath.Join(tmpDir, rigName, "witness", "rig", ".claude", "settings.json")
|
||||||
@@ -1037,8 +985,7 @@ func TestClaudeSettingsCheck_TownRootSettingsWarnsInsteadOfKilling(t *testing.T)
|
|||||||
"env": {"PATH": "/usr/bin"},
|
"env": {"PATH": "/usr/bin"},
|
||||||
"enabledPlugins": ["claude-code-expert"],
|
"enabledPlugins": ["claude-code-expert"],
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"SessionStart": [{"matcher": "", "hooks": [{"type": "command", "command": "gt prime"}]}],
|
"SessionStart": [{"matcher": "", "hooks": [{"type": "command", "command": "gt prime"}]}]
|
||||||
"Stop": [{"matcher": "", "hooks": [{"type": "command", "command": "gt handoff"}]}]
|
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
if err := os.WriteFile(staleTownRootSettings, []byte(settingsContent), 0644); err != nil {
|
if err := os.WriteFile(staleTownRootSettings, []byte(settingsContent), 0644); err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user