Skip to content

Commit d832fdc

Browse files
carlkiblerclaude
andcommitted
feat: port fork patterns to hook-policy.mjs
Adds GIT_VERBOSE_PATTERNS, LS_TREE_PATTERNS, WRITE_VIA_BASH_PATTERNS, SED_AWK_EDIT_PATTERNS, plus grep/find/ls-tree/git-verbose/sed-awk/write-via-bash nudges and large JSON/YAML detection to the centralised policy module. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d5ca2b2 commit d832fdc

1 file changed

Lines changed: 104 additions & 4 deletions

File tree

src/hook-policy.mjs

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,34 @@ const TAIL_PATTERNS = [
1919
/^\s*tail\s+/,
2020
];
2121

22+
const GIT_VERBOSE_PATTERNS = [
23+
/^\s*git\s+log\b(?!.*--oneline)(?!.*-n\s*[1-9])/,
24+
/^\s*git\s+diff\b(?!.*--stat)(?!.*--name-only)/,
25+
/^\s*git\s+show\b(?!.*--stat)(?!.*--name-only)/,
26+
];
27+
28+
const LS_TREE_PATTERNS = [
29+
/^\s*ls\s+-[a-z]*R/,
30+
/^\s*ls\s+-[a-z]*l/,
31+
/^\s*tree\b/,
32+
];
33+
34+
const WRITE_VIA_BASH_PATTERNS = [
35+
/<<\s*['"]?EOF/i,
36+
/>\s*\S+\.(js|ts|py|rb|go|rs|java|cs|cpp|c|h|sh|json|yaml|yml|toml|md)/,
37+
];
38+
39+
const SED_AWK_EDIT_PATTERNS = [
40+
/^\s*sed\s+-i/,
41+
/^\s*awk\s+.*>\s*\S+/,
42+
];
43+
2244
const NON_CODE_EXTS = new Set([
23-
'md', 'txt', 'json', 'yaml', 'yml', 'toml', 'xml', 'csv',
24-
'lock', 'svg', 'html', 'css', 'log', 'env',
45+
'md', 'txt', 'toml', 'xml', 'csv', 'lock', 'svg', 'html', 'css', 'log', 'env',
2546
]);
2647

27-
const LARGE_FILE_BYTES = 12000; // ~300 lines of code
48+
const LARGE_FILE_BYTES = 12000; // ~300 lines of code
49+
const LARGE_JSON_BYTES = 50000; // 50KB JSON/YAML worth flagging
2850

2951
function normalizeToolCall(data = {}) {
3052
const toolName = data.tool_name || data.tool || data.name || '';
@@ -45,11 +67,23 @@ export function evaluateToolCall(data = {}, options = {}) {
4567
if (!filePath) return null;
4668

4769
const ext = filePath.split('.').pop().toLowerCase();
48-
if (NON_CODE_EXTS.has(ext)) return null;
4970

5071
let size;
5172
try { size = stat(filePath).size; } catch { return null; }
5273

74+
if (size > LARGE_JSON_BYTES && (ext === 'json' || ext === 'yaml' || ext === 'yml')) {
75+
return {
76+
id: 'read-large-json',
77+
severity: 'nudge',
78+
action: 'suggest',
79+
message: `[tl] ${Math.round(size / 1024)}KB ${ext} — use tl-snippet to extract a specific path`,
80+
alternative: 'tl snippet <key> <file>',
81+
toolName,
82+
};
83+
}
84+
85+
if (NON_CODE_EXTS.has(ext)) return null;
86+
5387
if (size > LARGE_FILE_BYTES) {
5488
return {
5589
id: 'read-large',
@@ -111,6 +145,72 @@ export function evaluateToolCall(data = {}, options = {}) {
111145
};
112146
}
113147

148+
if (/^\s*(grep|rg|ag)\s/.test(cmd)) {
149+
return {
150+
id: 'bash-grep',
151+
severity: 'nudge',
152+
action: 'replace',
153+
message: '[tl] use Grep tool, not bash',
154+
alternative: 'Grep tool',
155+
toolName,
156+
};
157+
}
158+
159+
if (/^\s*(find|fd)\s/.test(cmd)) {
160+
return {
161+
id: 'bash-find',
162+
severity: 'nudge',
163+
action: 'replace',
164+
message: '[tl] use Glob tool, not bash',
165+
alternative: 'Glob tool',
166+
toolName,
167+
};
168+
}
169+
170+
if (LS_TREE_PATTERNS.some(p => p.test(cmd))) {
171+
return {
172+
id: 'bash-ls-tree',
173+
severity: 'nudge',
174+
action: 'replace',
175+
message: '[tl] use tl-structure or Glob for directory exploration',
176+
alternative: 'tl structure',
177+
toolName,
178+
};
179+
}
180+
181+
if (GIT_VERBOSE_PATTERNS.some(p => p.test(cmd))) {
182+
return {
183+
id: 'bash-git-verbose',
184+
severity: 'nudge',
185+
action: 'replace',
186+
message: '[tl] use tl-diff for token-efficient git output',
187+
alternative: 'tl diff',
188+
toolName,
189+
};
190+
}
191+
192+
if (WRITE_VIA_BASH_PATTERNS.some(p => p.test(cmd))) {
193+
return {
194+
id: 'bash-write',
195+
severity: 'nudge',
196+
action: 'replace',
197+
message: '[tl] use Write tool instead of writing via bash',
198+
alternative: 'Write tool',
199+
toolName,
200+
};
201+
}
202+
203+
if (SED_AWK_EDIT_PATTERNS.some(p => p.test(cmd))) {
204+
return {
205+
id: 'bash-sed-awk',
206+
severity: 'nudge',
207+
action: 'replace',
208+
message: '[tl] use Edit tool for targeted edits',
209+
alternative: 'Edit tool',
210+
toolName,
211+
};
212+
}
213+
114214
if (/^\s*curl\s/.test(cmd) && !/(-X\s|--data|--header.*auth|-d\s)/i.test(cmd)) {
115215
const url = cmd.match(/https?:\/\/\S+/)?.[0];
116216
return {

0 commit comments

Comments
 (0)