Files
seewis-hsl-ui/.claude/hooks/permission-retry.cjs
T

60 lines
2.1 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict';
// VibeCoding Athena PermissionDenied hook v9.6
// 协议: stdout JSON { retry: true } (CC v2.1.89+ 官方标准)
// 参考: https://code.claude.com/docs/en/hooks#permissiondenied
//
// 设计:
// 当 auto mode classifier 拒绝某个工具调用 → 提示 model 可以重试 (但只针对一次)
// 并 systemMessage 建议用户加入全局 deny (如果是反复出现的 pattern)
const fs = require('fs');
const path = require('path');
const PROJECT_DIR = process.env.CLAUDE_PROJECT_DIR || process.cwd();
const STATE_DIR = path.join(PROJECT_DIR, '.ai_state');
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', d => input += d);
process.stdin.on('end', () => {
let event = {};
try { event = JSON.parse(input); } catch (e) { process.exit(0); return; }
const tool = event.tool_name || '';
const cmd = (event.tool_input && event.tool_input.command) || '';
const reason = event.reason || '';
// 软提示: 如果是 Bash + 看起来是项目本地命令 → 提示用户考虑加入项目 allow
let suggestion = '';
if (tool === 'Bash' && cmd) {
// 抽取命令名 (第一个 token)
const cmdName = cmd.trim().split(/\s+/)[0];
if (['npm', 'pnpm', 'yarn', 'pytest', 'cargo', 'go', 'make'].includes(cmdName)) {
suggestion = `如果这是项目常用命令, 可: /athena:remember-allow "Bash(${cmdName}:*)" 加入全局 allow`;
}
}
if (suggestion) {
process.stderr.write(`[permission-retry] suggest: ${suggestion}\n`);
process.stdout.write(JSON.stringify({
retry: true,
systemMessage: `[Athena] permission denied. ${suggestion}`
}));
} else {
// 默认让 model 知道可以一次性重试
process.stdout.write(JSON.stringify({ retry: true }));
}
try {
const trace = JSON.stringify({
ts: new Date().toISOString(),
hook: 'permission-retry',
tool, cmd_head: cmd.slice(0, 60), reason: reason.slice(0, 100)
}) + '\n';
fs.appendFileSync(path.join(STATE_DIR, 'hook-trace.jsonl'), trace);
} catch (e) {}
process.exit(0);
});