aiblueprint-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +120 -0
  2. package/claude-code-config/agents/epct/code.md +28 -0
  3. package/claude-code-config/agents/epct/explore-orchestrator.md +32 -0
  4. package/claude-code-config/agents/epct/explore.md +28 -0
  5. package/claude-code-config/agents/epct/plan.md +14 -0
  6. package/claude-code-config/agents/epct/test.md +12 -0
  7. package/claude-code-config/agents/product/feedback-synthesizer.md +146 -0
  8. package/claude-code-config/agents/product/sprint-prioritizer.md +102 -0
  9. package/claude-code-config/agents/product/trend-researcher.md +157 -0
  10. package/claude-code-config/agents/tasks/app-store-optimizer.md +192 -0
  11. package/claude-code-config/agents/tasks/backend-reliability-engineer.md +126 -0
  12. package/claude-code-config/agents/tasks/code.md +12 -0
  13. package/claude-code-config/agents/tasks/frontend-ux-specialist.md +136 -0
  14. package/claude-code-config/agents/tasks/growth-hacker.md +209 -0
  15. package/claude-code-config/agents/tasks/prd-writer.md +141 -0
  16. package/claude-code-config/agents/tasks/senior-software-engineer.md +75 -0
  17. package/claude-code-config/agents/tasks/twitter-engager.md +126 -0
  18. package/claude-code-config/commands/commit.md +15 -0
  19. package/claude-code-config/commands/create-pull-request.md +31 -0
  20. package/claude-code-config/commands/deep-code-analysis.md +37 -0
  21. package/claude-code-config/commands/deploy.md +20 -0
  22. package/claude-code-config/commands/epct-agent.md +28 -0
  23. package/claude-code-config/commands/epct.md +41 -0
  24. package/claude-code-config/commands/fix-pr-comments.md +10 -0
  25. package/claude-code-config/commands/run-tasks.md +50 -0
  26. package/claude-code-config/commands/watch-ci.md +22 -0
  27. package/claude-code-config/output-styles/assistant.md +15 -0
  28. package/claude-code-config/output-styles/honnest.md +9 -0
  29. package/claude-code-config/output-styles/senior-dev.md +14 -0
  30. package/claude-code-config/scripts/statusline-ccusage.sh +156 -0
  31. package/claude-code-config/scripts/statusline.readme.md +194 -0
  32. package/claude-code-config/scripts/validate-command.js +621 -0
  33. package/claude-code-config/scripts/validate-command.readme.md +283 -0
  34. package/claude-code-config/song/finish.mp3 +0 -0
  35. package/claude-code-config/song/need-human.mp3 +0 -0
  36. package/dist/cli.js +5395 -0
  37. package/package.json +46 -0
@@ -0,0 +1,621 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Claude Code "Before Tools" Hook - Command Validation Script
5
+ *
6
+ * This script validates commands before execution to prevent harmful operations.
7
+ * It receives command data via stdin and returns exit code 0 (allow) or 1 (block).
8
+ *
9
+ * Usage: Called automatically by Claude Code PreToolUse hook
10
+ * Manual test: echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' | bun validate-command.js
11
+ */
12
+
13
+ // Comprehensive dangerous command patterns database
14
+ const SECURITY_RULES = {
15
+ // Critical system destruction commands
16
+ CRITICAL_COMMANDS: [
17
+ "del",
18
+ "format",
19
+ "mkfs",
20
+ "shred",
21
+ "dd",
22
+ "fdisk",
23
+ "parted",
24
+ "gparted",
25
+ "cfdisk",
26
+ ],
27
+
28
+ // Privilege escalation and system access
29
+ PRIVILEGE_COMMANDS: [
30
+ "sudo",
31
+ "su",
32
+ "passwd",
33
+ "chpasswd",
34
+ "usermod",
35
+ "chmod",
36
+ "chown",
37
+ "chgrp",
38
+ "setuid",
39
+ "setgid",
40
+ ],
41
+
42
+ // Network and remote access tools
43
+ NETWORK_COMMANDS: [
44
+ "nc",
45
+ "netcat",
46
+ "nmap",
47
+ "telnet",
48
+ "ssh-keygen",
49
+ "iptables",
50
+ "ufw",
51
+ "firewall-cmd",
52
+ "ipfw",
53
+ ],
54
+
55
+ // System service and process manipulation
56
+ SYSTEM_COMMANDS: [
57
+ "systemctl",
58
+ "service",
59
+ "kill",
60
+ "killall",
61
+ "pkill",
62
+ "mount",
63
+ "umount",
64
+ "swapon",
65
+ "swapoff",
66
+ ],
67
+
68
+ // Dangerous regex patterns
69
+ DANGEROUS_PATTERNS: [
70
+ // File system destruction - block rm -rf with absolute paths
71
+ /rm\s+.*-rf\s*\/\s*$/i, // rm -rf ending at root directory
72
+ /rm\s+.*-rf\s*\/\w+/i, // rm -rf with any absolute path
73
+ /rm\s+.*-rf\s*\/etc/i, // rm -rf in /etc
74
+ /rm\s+.*-rf\s*\/usr/i, // rm -rf in /usr
75
+ /rm\s+.*-rf\s*\/bin/i, // rm -rf in /bin
76
+ /rm\s+.*-rf\s*\/sys/i, // rm -rf in /sys
77
+ /rm\s+.*-rf\s*\/proc/i, // rm -rf in /proc
78
+ /rm\s+.*-rf\s*\/boot/i, // rm -rf in /boot
79
+ /rm\s+.*-rf\s*\/home\/[^\/]*\s*$/i, // rm -rf entire home directory
80
+ /rm\s+.*-rf\s*\.\.+\//i, // rm -rf with parent directory traversal
81
+ /rm\s+.*-rf\s*\*.*\*/i, // rm -rf with multiple wildcards
82
+ /rm\s+.*-rf\s*\$\w+/i, // rm -rf with variables (could be dangerous)
83
+ />\s*\/dev\/(sda|hda|nvme)/i,
84
+ /dd\s+.*of=\/dev\//i,
85
+ /shred\s+.*\/dev\//i,
86
+ /mkfs\.\w+\s+\/dev\//i,
87
+
88
+ // Fork bomb and resource exhaustion
89
+ /:\(\)\{\s*:\|:&\s*\};:/,
90
+ /while\s+true\s*;\s*do.*done/i,
91
+ /for\s*\(\(\s*;\s*;\s*\)\)/i,
92
+
93
+ // Command injection (but allow general chaining - we'll validate each command separately)
94
+ // /;\s*(rm|dd|mkfs|format)/i, // Commented out - handled by individual command validation
95
+ // /&&\s*(rm|dd|mkfs|format)/i, // Commented out - handled by individual command validation
96
+ // /\|\|\s*(rm|dd|mkfs|format)/i, // Commented out - handled by individual command validation
97
+
98
+ // Remote code execution
99
+ /\|\s*(sh|bash|zsh|fish)$/i,
100
+ /(wget|curl)\s+.*\|\s*(sh|bash)/i,
101
+ /(wget|curl)\s+.*-O-.*\|\s*(sh|bash)/i,
102
+
103
+ // Command substitution with dangerous commands
104
+ /`.*rm.*`/i,
105
+ /\$\(.*rm.*\)/i,
106
+ /`.*dd.*`/i,
107
+ /\$\(.*dd.*\)/i,
108
+
109
+ // Sensitive file access
110
+ /cat\s+\/etc\/(passwd|shadow|sudoers)/i,
111
+ />\s*\/etc\/(passwd|shadow|sudoers)/i,
112
+ /echo\s+.*>>\s*\/etc\/(passwd|shadow|sudoers)/i,
113
+
114
+ // Network exfiltration
115
+ /\|\s*nc\s+\S+\s+\d+/i,
116
+ /curl\s+.*-d.*\$\(/i,
117
+ /wget\s+.*--post-data.*\$\(/i,
118
+
119
+ // Log manipulation
120
+ />\s*\/var\/log\//i,
121
+ /rm\s+\/var\/log\//i,
122
+ /echo\s+.*>\s*~?\/?\.bash_history/i,
123
+
124
+ // Backdoor creation
125
+ /nc\s+.*-l.*-e/i,
126
+ /nc\s+.*-e.*-l/i,
127
+ /ncat\s+.*--exec/i,
128
+ /ssh-keygen.*authorized_keys/i,
129
+
130
+ // Crypto mining and malicious downloads
131
+ /(wget|curl).*\.(sh|py|pl|exe|bin).*\|\s*(sh|bash|python)/i,
132
+ /(xmrig|ccminer|cgminer|bfgminer)/i,
133
+
134
+ // Hardware direct access
135
+ /cat\s+\/dev\/(mem|kmem)/i,
136
+ /echo\s+.*>\s*\/dev\/(mem|kmem)/i,
137
+
138
+ // Kernel module manipulation
139
+ /(insmod|rmmod|modprobe)\s+/i,
140
+
141
+ // Cron job manipulation
142
+ /crontab\s+-e/i,
143
+ /echo\s+.*>>\s*\/var\/spool\/cron/i,
144
+
145
+ // Environment variable exposure
146
+ /env\s*\|\s*grep.*PASSWORD/i,
147
+ /printenv.*PASSWORD/i,
148
+ ],
149
+
150
+
151
+ // Paths that should never be written to
152
+ PROTECTED_PATHS: [
153
+ "/etc/",
154
+ "/usr/",
155
+ "/bin/",
156
+ "/sbin/",
157
+ "/boot/",
158
+ "/sys/",
159
+ "/proc/",
160
+ "/dev/",
161
+ "/root/",
162
+ ],
163
+ };
164
+
165
+ // Allowlist of safe commands (when used appropriately)
166
+ const SAFE_COMMANDS = [
167
+ "ls",
168
+ "dir",
169
+ "pwd",
170
+ "whoami",
171
+ "date",
172
+ "echo",
173
+ "cat",
174
+ "head",
175
+ "tail",
176
+ "grep",
177
+ "find",
178
+ "wc",
179
+ "sort",
180
+ "uniq",
181
+ "cut",
182
+ "awk",
183
+ "sed",
184
+ "git",
185
+ "npm",
186
+ "pnpm",
187
+ "node",
188
+ "bun",
189
+ "python",
190
+ "pip",
191
+ "source",
192
+ "cd",
193
+ "cp",
194
+ "mv",
195
+ "mkdir",
196
+ "touch",
197
+ "ln",
198
+ ];
199
+
200
+ class CommandValidator {
201
+ constructor() {
202
+ this.logFile = "/Users/melvynx/.claude/security.log";
203
+ }
204
+
205
+ /**
206
+ * Main validation function
207
+ */
208
+ validate(command, toolName = "Unknown") {
209
+ const result = {
210
+ isValid: true,
211
+ severity: "LOW",
212
+ violations: [],
213
+ sanitizedCommand: command,
214
+ };
215
+
216
+ if (!command || typeof command !== "string") {
217
+ result.isValid = false;
218
+ result.violations.push("Invalid command format");
219
+ return result;
220
+ }
221
+
222
+ // Normalize command for analysis
223
+ const normalizedCmd = command.trim().toLowerCase();
224
+ const cmdParts = normalizedCmd.split(/\s+/);
225
+ const mainCommand = cmdParts[0];
226
+
227
+ // Allow source and python commands unconditionally
228
+ if (mainCommand === 'source' || mainCommand === 'python') {
229
+ return result; // Always allow
230
+ }
231
+
232
+ // Check against critical commands
233
+ if (SECURITY_RULES.CRITICAL_COMMANDS.includes(mainCommand)) {
234
+ result.isValid = false;
235
+ result.severity = "CRITICAL";
236
+ result.violations.push(`Critical dangerous command: ${mainCommand}`);
237
+ }
238
+
239
+ // Check privilege escalation commands
240
+ if (SECURITY_RULES.PRIVILEGE_COMMANDS.includes(mainCommand)) {
241
+ result.isValid = false;
242
+ result.severity = "HIGH";
243
+ result.violations.push(`Privilege escalation command: ${mainCommand}`);
244
+ }
245
+
246
+ // Check network commands
247
+ if (SECURITY_RULES.NETWORK_COMMANDS.includes(mainCommand)) {
248
+ result.isValid = false;
249
+ result.severity = "HIGH";
250
+ result.violations.push(`Network/remote access command: ${mainCommand}`);
251
+ }
252
+
253
+ // Check system commands
254
+ if (SECURITY_RULES.SYSTEM_COMMANDS.includes(mainCommand)) {
255
+ result.isValid = false;
256
+ result.severity = "HIGH";
257
+ result.violations.push(`System manipulation command: ${mainCommand}`);
258
+ }
259
+
260
+ // Check dangerous patterns
261
+ for (const pattern of SECURITY_RULES.DANGEROUS_PATTERNS) {
262
+ if (pattern.test(command)) {
263
+ result.isValid = false;
264
+ result.severity = "CRITICAL";
265
+ result.violations.push(`Dangerous pattern detected: ${pattern.source}`);
266
+ }
267
+ }
268
+
269
+ // Allow && chaining for safe commands like source and python
270
+ if (command.includes('&&')) {
271
+ const chainedCommands = this.splitCommandChain(command);
272
+ let allSafe = true;
273
+ for (const chainedCmd of chainedCommands) {
274
+ const trimmedCmd = chainedCmd.trim();
275
+ const cmdParts = trimmedCmd.split(/\s+/);
276
+ const mainCommand = cmdParts[0];
277
+
278
+ // Allow source and python commands in && chains
279
+ if (mainCommand === 'source' || mainCommand === 'python' || SAFE_COMMANDS.includes(mainCommand)) {
280
+ continue;
281
+ }
282
+
283
+ const chainResult = this.validateSingleCommand(trimmedCmd, toolName);
284
+ if (!chainResult.isValid) {
285
+ result.isValid = false;
286
+ result.severity = chainResult.severity;
287
+ result.violations.push(`Chained command violation: ${trimmedCmd} - ${chainResult.violations.join(', ')}`);
288
+ allSafe = false;
289
+ }
290
+ }
291
+ if (allSafe) {
292
+ return result; // Allow safe && chains
293
+ }
294
+ }
295
+
296
+ // Check other command chaining (; and ||)
297
+ if (command.includes(';') || command.includes('||')) {
298
+ const chainedCommands = this.splitCommandChain(command);
299
+ for (const chainedCmd of chainedCommands) {
300
+ const chainResult = this.validateSingleCommand(chainedCmd.trim(), toolName);
301
+ if (!chainResult.isValid) {
302
+ result.isValid = false;
303
+ result.severity = chainResult.severity;
304
+ result.violations.push(`Chained command violation: ${chainedCmd.trim()} - ${chainResult.violations.join(', ')}`);
305
+ }
306
+ }
307
+ return result;
308
+ }
309
+
310
+
311
+ // Check for protected path access (but allow common redirections like /dev/null)
312
+ for (const path of SECURITY_RULES.PROTECTED_PATHS) {
313
+ if (command.includes(path)) {
314
+ // Allow common safe redirections
315
+ if (path === "/dev/" && (command.includes("/dev/null") || command.includes("/dev/stderr") || command.includes("/dev/stdout"))) {
316
+ continue;
317
+ }
318
+ result.isValid = false;
319
+ result.severity = "HIGH";
320
+ result.violations.push(`Access to protected path: ${path}`);
321
+ }
322
+ }
323
+
324
+ // Additional safety checks
325
+ if (command.length > 2000) {
326
+ result.isValid = false;
327
+ result.severity = "MEDIUM";
328
+ result.violations.push("Command too long (potential buffer overflow)");
329
+ }
330
+
331
+ // Check for binary/encoded content
332
+ if (/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]/.test(command)) {
333
+ result.isValid = false;
334
+ result.severity = "HIGH";
335
+ result.violations.push("Binary or encoded content detected");
336
+ }
337
+
338
+ return result;
339
+ }
340
+
341
+
342
+ /**
343
+ * Validate a single command (without chaining logic to avoid recursion)
344
+ */
345
+ validateSingleCommand(command, toolName = "Unknown") {
346
+ const result = {
347
+ isValid: true,
348
+ severity: "LOW",
349
+ violations: [],
350
+ sanitizedCommand: command,
351
+ };
352
+
353
+ if (!command || typeof command !== "string") {
354
+ result.isValid = false;
355
+ result.violations.push("Invalid command format");
356
+ return result;
357
+ }
358
+
359
+ // Normalize command for analysis
360
+ const normalizedCmd = command.trim().toLowerCase();
361
+ const cmdParts = normalizedCmd.split(/\s+/);
362
+ const mainCommand = cmdParts[0];
363
+
364
+ // Allow source and python commands unconditionally in single command validation too
365
+ if (mainCommand === 'source' || mainCommand === 'python') {
366
+ return result; // Always allow
367
+ }
368
+
369
+ // Check against critical commands
370
+ if (SECURITY_RULES.CRITICAL_COMMANDS.includes(mainCommand)) {
371
+ result.isValid = false;
372
+ result.severity = "CRITICAL";
373
+ result.violations.push(`Critical dangerous command: ${mainCommand}`);
374
+ }
375
+
376
+ // Check privilege escalation commands
377
+ if (SECURITY_RULES.PRIVILEGE_COMMANDS.includes(mainCommand)) {
378
+ result.isValid = false;
379
+ result.severity = "HIGH";
380
+ result.violations.push(`Privilege escalation command: ${mainCommand}`);
381
+ }
382
+
383
+ // Check network commands
384
+ if (SECURITY_RULES.NETWORK_COMMANDS.includes(mainCommand)) {
385
+ result.isValid = false;
386
+ result.severity = "HIGH";
387
+ result.violations.push(`Network/remote access command: ${mainCommand}`);
388
+ }
389
+
390
+ // Check system commands
391
+ if (SECURITY_RULES.SYSTEM_COMMANDS.includes(mainCommand)) {
392
+ result.isValid = false;
393
+ result.severity = "HIGH";
394
+ result.violations.push(`System manipulation command: ${mainCommand}`);
395
+ }
396
+
397
+ // Check dangerous patterns (but skip chaining patterns since we're validating individual commands)
398
+ for (const pattern of SECURITY_RULES.DANGEROUS_PATTERNS) {
399
+ if (pattern.test(command)) {
400
+ result.isValid = false;
401
+ result.severity = "CRITICAL";
402
+ result.violations.push(`Dangerous pattern detected: ${pattern.source}`);
403
+ }
404
+ }
405
+
406
+ // Check for protected path access
407
+ for (const path of SECURITY_RULES.PROTECTED_PATHS) {
408
+ if (command.includes(path)) {
409
+ if (path === "/dev/" && (command.includes("/dev/null") || command.includes("/dev/stderr") || command.includes("/dev/stdout"))) {
410
+ continue;
411
+ }
412
+ result.isValid = false;
413
+ result.severity = "HIGH";
414
+ result.violations.push(`Access to protected path: ${path}`);
415
+ }
416
+ }
417
+
418
+ // Additional safety checks
419
+ if (command.length > 2000) {
420
+ result.isValid = false;
421
+ result.severity = "MEDIUM";
422
+ result.violations.push("Command too long (potential buffer overflow)");
423
+ }
424
+
425
+ // Check for binary/encoded content
426
+ if (/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\xFF]/.test(command)) {
427
+ result.isValid = false;
428
+ result.severity = "HIGH";
429
+ result.violations.push("Binary or encoded content detected");
430
+ }
431
+
432
+ return result;
433
+ }
434
+
435
+ /**
436
+ * Split command chain into individual commands
437
+ */
438
+ splitCommandChain(command) {
439
+ // Simple splitting on && ; ||
440
+ // This is basic - doesn't handle complex quoting, but good enough for basic validation
441
+ const commands = [];
442
+ let current = '';
443
+ let inQuotes = false;
444
+ let quoteChar = '';
445
+
446
+ for (let i = 0; i < command.length; i++) {
447
+ const char = command[i];
448
+ const nextChar = command[i + 1];
449
+
450
+ // Handle quotes
451
+ if ((char === '"' || char === "'") && !inQuotes) {
452
+ inQuotes = true;
453
+ quoteChar = char;
454
+ current += char;
455
+ } else if (char === quoteChar && inQuotes) {
456
+ inQuotes = false;
457
+ quoteChar = '';
458
+ current += char;
459
+ } else if (inQuotes) {
460
+ current += char;
461
+ } else if (char === '&' && nextChar === '&') {
462
+ commands.push(current.trim());
463
+ current = '';
464
+ i++; // skip next &
465
+ } else if (char === '|' && nextChar === '|') {
466
+ commands.push(current.trim());
467
+ current = '';
468
+ i++; // skip next |
469
+ } else if (char === ';') {
470
+ commands.push(current.trim());
471
+ current = '';
472
+ } else {
473
+ current += char;
474
+ }
475
+ }
476
+
477
+ if (current.trim()) {
478
+ commands.push(current.trim());
479
+ }
480
+
481
+ return commands.filter(cmd => cmd.length > 0);
482
+ }
483
+
484
+ /**
485
+ * Log security events
486
+ */
487
+ async logSecurityEvent(command, toolName, result, sessionId = null) {
488
+ const timestamp = new Date().toISOString();
489
+ const logEntry = {
490
+ timestamp,
491
+ sessionId,
492
+ toolName,
493
+ command: command.substring(0, 500), // Truncate for logs
494
+ blocked: !result.isValid,
495
+ severity: result.severity,
496
+ violations: result.violations,
497
+ source: "claude-code-hook",
498
+ };
499
+
500
+ try {
501
+ // Write to log file
502
+ const logLine = JSON.stringify(logEntry) + "\n";
503
+ await Bun.write(this.logFile, logLine, { createPath: true, flag: "a" });
504
+
505
+ // Also output to stderr for immediate visibility
506
+ console.error(
507
+ `[SECURITY] ${
508
+ result.isValid ? "ALLOWED" : "BLOCKED"
509
+ }: ${command.substring(0, 100)}`
510
+ );
511
+ } catch (error) {
512
+ console.error("Failed to write security log:", error);
513
+ }
514
+ }
515
+
516
+ /**
517
+ * Check if command matches any allowed patterns from settings
518
+ */
519
+ isExplicitlyAllowed(command, allowedPatterns = []) {
520
+ for (const pattern of allowedPatterns) {
521
+ // Convert Claude Code permission pattern to regex
522
+ // e.g., "Bash(git *)" becomes /^git\s+.*$/
523
+ if (pattern.startsWith("Bash(") && pattern.endsWith(")")) {
524
+ const cmdPattern = pattern.slice(5, -1); // Remove "Bash(" and ")"
525
+ const regex = new RegExp(
526
+ "^" + cmdPattern.replace(/\*/g, ".*") + "$",
527
+ "i"
528
+ );
529
+ if (regex.test(command)) {
530
+ return true;
531
+ }
532
+ }
533
+ }
534
+ return false;
535
+ }
536
+ }
537
+
538
+ /**
539
+ * Main execution function
540
+ */
541
+ async function main() {
542
+ const validator = new CommandValidator();
543
+
544
+ try {
545
+ // Read hook input from stdin
546
+ const stdin = process.stdin;
547
+ const chunks = [];
548
+
549
+ for await (const chunk of stdin) {
550
+ chunks.push(chunk);
551
+ }
552
+
553
+ const input = Buffer.concat(chunks).toString();
554
+
555
+ if (!input.trim()) {
556
+ console.error("No input received from stdin");
557
+ process.exit(1);
558
+ }
559
+
560
+ // Parse Claude Code hook JSON format
561
+ let hookData;
562
+ try {
563
+ hookData = JSON.parse(input);
564
+ } catch (error) {
565
+ console.error("Invalid JSON input:", error.message);
566
+ process.exit(1);
567
+ }
568
+
569
+ const toolName = hookData.tool_name || "Unknown";
570
+ const toolInput = hookData.tool_input || {};
571
+ const sessionId = hookData.session_id || null;
572
+
573
+ // Only validate Bash commands for now
574
+ if (toolName !== "Bash") {
575
+ console.log(`Skipping validation for tool: ${toolName}`);
576
+ process.exit(0);
577
+ }
578
+
579
+ const command = toolInput.command;
580
+ if (!command) {
581
+ console.error("No command found in tool input");
582
+ process.exit(1);
583
+ }
584
+
585
+ // Validate the command
586
+ const result = validator.validate(command, toolName);
587
+
588
+ // Log the security event
589
+ await validator.logSecurityEvent(command, toolName, result, sessionId);
590
+
591
+ // Output result and exit with appropriate code
592
+ if (result.isValid) {
593
+ console.log("Command validation passed");
594
+ process.exit(0); // Allow execution
595
+ } else {
596
+ // Instead of blocking, ask user for confirmation
597
+ const confirmationMessage = `⚠️ Potentially dangerous command detected!\n\nCommand: ${command}\nViolations: ${result.violations.join(", ")}\nSeverity: ${result.severity}\n\nDo you want to proceed with this command?`;
598
+
599
+ const hookOutput = {
600
+ hookSpecificOutput: {
601
+ hookEventName: "PreToolUse",
602
+ permissionDecision: "ask",
603
+ permissionDecisionReason: confirmationMessage
604
+ }
605
+ };
606
+
607
+ console.log(JSON.stringify(hookOutput));
608
+ process.exit(0); // Exit with 0 to trigger user prompt
609
+ }
610
+ } catch (error) {
611
+ console.error("Validation script error:", error);
612
+ // Fail safe - block execution on any script error
613
+ process.exit(2);
614
+ }
615
+ }
616
+
617
+ // Execute main function
618
+ main().catch((error) => {
619
+ console.error("Fatal error:", error);
620
+ process.exit(2);
621
+ });