feat: context window monitor hook with agent-side WARNING/CRITICAL alerts

Adds PostToolUse hook that reads context metrics from statusline bridge file and injects alerts into agent conversation when context is low.

Features:
- Two-tier alerts: WARNING (<=35% remaining) and CRITICAL (<=25%)
- Smart debounce: 5 tool uses between warnings, severity escalation bypasses
- Silent fail: never blocks tool execution
- Security: session_id sanitized to prevent path traversal

Ref #212
This commit is contained in:
vinicius-tersi
2026-02-20 17:40:08 -03:00
committed by GitHub
parent bfdd64fd59
commit 7542d364b4
5 changed files with 286 additions and 4 deletions

View File

@@ -892,7 +892,7 @@ function uninstall(isGlobal, runtime = 'claude') {
// 4. Remove GSD hooks
const hooksDir = path.join(targetDir, 'hooks');
if (fs.existsSync(hooksDir)) {
const gsdHooks = ['gsd-statusline.js', 'gsd-check-update.js', 'gsd-check-update.sh'];
const gsdHooks = ['gsd-statusline.js', 'gsd-check-update.js', 'gsd-check-update.sh', 'gsd-context-monitor.js'];
let hookCount = 0;
for (const hook of gsdHooks) {
const hookPath = path.join(hooksDir, hook);
@@ -958,10 +958,32 @@ function uninstall(isGlobal, runtime = 'claude') {
if (settings.hooks.SessionStart.length === 0) {
delete settings.hooks.SessionStart;
}
// Clean up empty hooks object
if (Object.keys(settings.hooks).length === 0) {
delete settings.hooks;
}
// Remove GSD hooks from PostToolUse
if (settings.hooks && settings.hooks.PostToolUse) {
const before = settings.hooks.PostToolUse.length;
settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(entry => {
if (entry.hooks && Array.isArray(entry.hooks)) {
const hasGsdHook = entry.hooks.some(h =>
h.command && h.command.includes('gsd-context-monitor')
);
return !hasGsdHook;
}
return true;
});
if (settings.hooks.PostToolUse.length < before) {
settingsModified = true;
console.log(` ${green}✓${reset} Removed context monitor hook from settings`);
}
if (settings.hooks.PostToolUse.length === 0) {
delete settings.hooks.PostToolUse;
}
}
// Clean up empty hooks object
if (settings.hooks && Object.keys(settings.hooks).length === 0) {
delete settings.hooks;
}
if (settingsModified) {
@@ -1520,6 +1542,9 @@ function install(isGlobal, runtime = 'claude') {
const updateCheckCommand = isGlobal
? buildHookCommand(targetDir, 'gsd-check-update.js')
: 'node ' + dirName + '/hooks/gsd-check-update.js';
const contextMonitorCommand = isGlobal
? buildHookCommand(targetDir, 'gsd-context-monitor.js')
: 'node ' + dirName + '/hooks/gsd-context-monitor.js';
// Enable experimental agents for Gemini CLI (required for custom sub-agents)
if (isGemini) {
@@ -1556,6 +1581,27 @@ function install(isGlobal, runtime = 'claude') {
});
console.log(` ${green}✓${reset} Configured update check hook`);
}
// Configure PostToolUse hook for context window monitoring
if (!settings.hooks.PostToolUse) {
settings.hooks.PostToolUse = [];
}
const hasContextMonitorHook = settings.hooks.PostToolUse.some(entry =>
entry.hooks && entry.hooks.some(h => h.command && h.command.includes('gsd-context-monitor'))
);
if (!hasContextMonitorHook) {
settings.hooks.PostToolUse.push({
hooks: [
{
type: 'command',
command: contextMonitorCommand
}
]
});
console.log(` ${green}✓${reset} Configured context window monitor hook`);
}
}
// Write file manifest for future modification detection