mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-11 02:33:10 +08:00
fix: surface warn-only PreToolUse hooks (#2084)
This commit is contained in:
@@ -35,6 +35,10 @@ function runScript(scriptPath, input, env = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
function parseHookOutput(stdout) {
|
||||
return JSON.parse(stdout);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
console.log('\n=== Testing Bash hook dispatchers ===\n');
|
||||
|
||||
@@ -54,13 +58,18 @@ function runTests() {
|
||||
|
||||
const enabled = runScript(preDispatcher, input, { ECC_HOOK_PROFILE: 'strict' });
|
||||
assert.strictEqual(enabled.status, 0);
|
||||
assert.ok(enabled.stderr.includes('Review changes before push'), 'Expected git push reminder when enabled');
|
||||
assert.strictEqual(enabled.stderr, '', `Expected visible reminder via stdout JSON, got stderr: ${enabled.stderr}`);
|
||||
assert.ok(
|
||||
parseHookOutput(enabled.stdout).hookSpecificOutput.additionalContext.includes('Review changes before push'),
|
||||
'Expected git push reminder when enabled'
|
||||
);
|
||||
|
||||
const disabled = runScript(preDispatcher, input, {
|
||||
ECC_HOOK_PROFILE: 'strict',
|
||||
ECC_DISABLED_HOOKS: 'pre:bash:git-push-reminder',
|
||||
});
|
||||
assert.strictEqual(disabled.status, 0);
|
||||
assert.strictEqual(disabled.stdout, JSON.stringify(input), 'Disabled hook should pass through original input');
|
||||
assert.ok(!disabled.stderr.includes('Review changes before push'), 'Disabled hook should not emit reminder');
|
||||
})) passed++; else failed++;
|
||||
|
||||
|
||||
@@ -28,6 +28,10 @@ function runScript(input) {
|
||||
return { code: result.status || 0, stdout: result.stdout || '', stderr: result.stderr || '' };
|
||||
}
|
||||
|
||||
function parseHookOutput(stdout) {
|
||||
return JSON.parse(stdout);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
console.log('\n=== Testing doc-file-warning.js (denylist policy) ===\n');
|
||||
let passed = 0;
|
||||
@@ -138,10 +142,13 @@ function runTests() {
|
||||
];
|
||||
for (const file of deniedFiles) {
|
||||
(test(`warns on ad-hoc denylist file: ${file}`, () => {
|
||||
const { code, stderr } = runScript({ tool_input: { file_path: file } });
|
||||
const { code, stdout, stderr } = runScript({ tool_input: { file_path: file } });
|
||||
assert.strictEqual(code, 0, 'should still exit 0 (warn only)');
|
||||
assert.ok(stderr.includes('WARNING'), `expected warning in stderr for ${file}, got: ${stderr}`);
|
||||
assert.ok(stderr.includes(file), `expected file path in stderr for ${file}`);
|
||||
assert.strictEqual(stderr, '', `expected visible warning via stdout JSON, got stderr: ${stderr}`);
|
||||
const output = parseHookOutput(stdout);
|
||||
const additionalContext = output.hookSpecificOutput?.additionalContext || '';
|
||||
assert.ok(additionalContext.includes('WARNING'), `expected warning in additionalContext for ${file}, got: ${stdout}`);
|
||||
assert.ok(additionalContext.includes(file), `expected file path in additionalContext for ${file}`);
|
||||
}) ? passed++ : failed++);
|
||||
}
|
||||
|
||||
@@ -153,9 +160,10 @@ function runTests() {
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('warns on ad-hoc name with backslash in non-structured dir', () => {
|
||||
const { code, stderr } = runScript({ tool_input: { file_path: 'src\\SCRATCH.md' } });
|
||||
const { code, stdout, stderr } = runScript({ tool_input: { file_path: 'src\\SCRATCH.md' } });
|
||||
assert.strictEqual(code, 0, 'should still exit 0');
|
||||
assert.ok(stderr.includes('WARNING'), 'expected warning for non-structured backslash path');
|
||||
assert.strictEqual(stderr, '', `expected visible warning via stdout JSON, got stderr: ${stderr}`);
|
||||
assert.ok(parseHookOutput(stdout).hookSpecificOutput.additionalContext.includes('WARNING'), 'expected warning for non-structured backslash path');
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
// 8. Invalid/empty input - passes through without error
|
||||
@@ -196,10 +204,12 @@ function runTests() {
|
||||
assert.strictEqual(stdout, JSON.stringify(input));
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('passes through input to stdout for warned file', () => {
|
||||
(test('emits visible additionalContext JSON for warned file', () => {
|
||||
const input = { tool_input: { file_path: 'TODO.md' } };
|
||||
const { stdout } = runScript(input);
|
||||
assert.strictEqual(stdout, JSON.stringify(input));
|
||||
const output = parseHookOutput(stdout);
|
||||
assert.strictEqual(output.hookSpecificOutput.hookEventName, 'PreToolUse');
|
||||
assert.ok(output.hookSpecificOutput.additionalContext.includes('TODO.md'));
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('passes through input to stdout for empty input', () => {
|
||||
|
||||
@@ -35,6 +35,10 @@ function runScript(scriptPath, command, envOverrides = {}) {
|
||||
return { code: result.status || 0, stdout: result.stdout || '', stderr: result.stderr || '', inputStr };
|
||||
}
|
||||
|
||||
function parseHookOutput(stdout) {
|
||||
return JSON.parse(stdout);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
console.log('\n=== Testing pre-bash-git-push-reminder.js & pre-bash-tmux-reminder.js ===\n');
|
||||
|
||||
@@ -45,11 +49,13 @@ function runTests() {
|
||||
|
||||
console.log(' git-push-reminder:');
|
||||
|
||||
(test('git push triggers stderr warning', () => {
|
||||
(test('git push triggers visible additionalContext warning', () => {
|
||||
const result = runScript(gitPushScript, 'git push origin main');
|
||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||
assert.ok(result.stderr.includes('[Hook]'), `Expected stderr to contain [Hook], got: ${result.stderr}`);
|
||||
assert.ok(result.stderr.includes('Review changes before push'), `Expected stderr to mention review`);
|
||||
assert.strictEqual(result.stderr, '', `Expected no stderr, got: ${result.stderr}`);
|
||||
const additionalContext = parseHookOutput(result.stdout).hookSpecificOutput.additionalContext;
|
||||
assert.ok(additionalContext.includes('[Hook]'), `Expected additionalContext to contain [Hook], got: ${result.stdout}`);
|
||||
assert.ok(additionalContext.includes('Review changes before push'), `Expected additionalContext to mention review`);
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('git status has no warning', () => {
|
||||
@@ -58,9 +64,11 @@ function runTests() {
|
||||
assert.strictEqual(result.stderr, '', `Expected no stderr, got: ${result.stderr}`);
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('git push always passes through input on stdout', () => {
|
||||
(test('git push emits PreToolUse additionalContext JSON on stdout', () => {
|
||||
const result = runScript(gitPushScript, 'git push');
|
||||
assert.strictEqual(result.stdout, result.inputStr, 'Expected stdout to match original input');
|
||||
const output = parseHookOutput(result.stdout);
|
||||
assert.strictEqual(output.hookSpecificOutput.hookEventName, 'PreToolUse');
|
||||
assert.ok(output.hookSpecificOutput.additionalContext.includes('Review changes before push'));
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
// --- tmux-reminder tests (non-Windows only) ---
|
||||
@@ -70,17 +78,20 @@ function runTests() {
|
||||
if (!isWindows) {
|
||||
console.log('\n tmux-reminder:');
|
||||
|
||||
(test('npm install triggers tmux suggestion', () => {
|
||||
(test('npm install triggers visible tmux suggestion', () => {
|
||||
const result = runScript(tmuxScript, 'npm install', { TMUX: '' });
|
||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||
assert.ok(result.stderr.includes('[Hook]'), `Expected stderr to contain [Hook], got: ${result.stderr}`);
|
||||
assert.ok(result.stderr.includes('tmux'), `Expected stderr to mention tmux`);
|
||||
assert.strictEqual(result.stderr, '', `Expected no stderr, got: ${result.stderr}`);
|
||||
const additionalContext = parseHookOutput(result.stdout).hookSpecificOutput.additionalContext;
|
||||
assert.ok(additionalContext.includes('[Hook]'), `Expected additionalContext to contain [Hook], got: ${result.stdout}`);
|
||||
assert.ok(additionalContext.includes('tmux'), `Expected additionalContext to mention tmux`);
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('npm test triggers tmux suggestion', () => {
|
||||
const result = runScript(tmuxScript, 'npm test', { TMUX: '' });
|
||||
assert.strictEqual(result.code, 0, `Expected exit code 0, got ${result.code}`);
|
||||
assert.ok(result.stderr.includes('tmux'), `Expected stderr to mention tmux`);
|
||||
assert.strictEqual(result.stderr, '', `Expected no stderr, got: ${result.stderr}`);
|
||||
assert.ok(parseHookOutput(result.stdout).hookSpecificOutput.additionalContext.includes('tmux'), `Expected additionalContext to mention tmux`);
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('regular command like ls has no tmux suggestion', () => {
|
||||
@@ -89,9 +100,11 @@ function runTests() {
|
||||
assert.strictEqual(result.stderr, '', `Expected no stderr for ls, got: ${result.stderr}`);
|
||||
}) ? passed++ : failed++);
|
||||
|
||||
(test('tmux reminder always passes through input on stdout', () => {
|
||||
(test('tmux reminder emits PreToolUse additionalContext JSON on stdout', () => {
|
||||
const result = runScript(tmuxScript, 'npm install', { TMUX: '' });
|
||||
assert.strictEqual(result.stdout, result.inputStr, 'Expected stdout to match original input');
|
||||
const output = parseHookOutput(result.stdout);
|
||||
assert.strictEqual(output.hookSpecificOutput.hookEventName, 'PreToolUse');
|
||||
assert.ok(output.hookSpecificOutput.additionalContext.includes('tmux'));
|
||||
}) ? passed++ : failed++);
|
||||
} else {
|
||||
console.log('\n (skipping tmux-reminder tests on Windows)\n');
|
||||
|
||||
Reference in New Issue
Block a user