Files
ECC/scripts/hooks/hook-input-limits.js
T

112 lines
3.0 KiB
JavaScript

'use strict';
const REGISTERED_HOOK_MAX_STDIN_BYTES = 1024 * 1024;
const MAX_CONTEXT_TOKEN_CHARS = 256;
function decodeJsonString(raw) {
try {
return JSON.parse(`"${raw}"`);
} catch {
return '';
}
}
function createHookContextScanner() {
const context = { hookEventName: '', toolName: '', stopHookActive: null };
let depth = 0;
let inString = false;
let escaped = false;
let stringRole = '';
let stringBuffer = '';
let currentKey = '';
let state = 'root';
let primitive = '';
const commitPrimitive = () => {
if (currentKey === 'stop_hook_active') {
if (primitive === 'true') context.stopHookActive = true;
else if (primitive === 'false') context.stopHookActive = false;
}
primitive = '';
};
const push = chunk => {
for (const char of String(chunk || '')) {
if (inString) {
if (escaped) {
if (stringRole && stringBuffer.length < MAX_CONTEXT_TOKEN_CHARS) {
stringBuffer += `\\${char}`;
}
escaped = false;
continue;
}
if (char === '\\') {
escaped = true;
continue;
}
if (char === '"') {
const value = decodeJsonString(stringBuffer);
if (stringRole === 'key') {
currentKey = value;
state = 'colon';
} else if (stringRole === 'value') {
if (currentKey === 'hook_event_name') context.hookEventName = value;
else if (currentKey === 'tool_name') context.toolName = value;
state = 'afterValue';
}
inString = false;
stringRole = '';
stringBuffer = '';
continue;
}
if (stringRole && stringBuffer.length < MAX_CONTEXT_TOKEN_CHARS) stringBuffer += char;
continue;
}
if (char === '"') {
inString = true;
stringRole = depth === 1 && state === 'key'
? 'key'
: depth === 1 && state === 'value'
&& (currentKey === 'hook_event_name' || currentKey === 'tool_name')
? 'value'
: '';
stringBuffer = '';
continue;
}
if (char === '{' || char === '[') {
depth += 1;
if (depth === 1) state = 'key';
continue;
}
if (char === '}' || char === ']') {
if (depth === 1 && primitive) commitPrimitive();
depth = Math.max(0, depth - 1);
continue;
}
if (depth !== 1 || /\s/.test(char)) continue;
if (state === 'colon' && char === ':') {
state = 'value';
primitive = '';
continue;
}
if ((state === 'value' || state === 'afterValue') && char === ',') {
if (state === 'value') commitPrimitive();
currentKey = '';
state = 'key';
continue;
}
if (state === 'value' && currentKey === 'stop_hook_active' && primitive.length < 5) {
primitive += char;
}
}
};
return { context, push };
}
module.exports = {
REGISTERED_HOOK_MAX_STDIN_BYTES,
createHookContextScanner,
};