aiblueprint-cli 1.0.3 → 1.1.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 (38) hide show
  1. package/claude-code-config/agents/explore-codebase.md +57 -0
  2. package/claude-code-config/agents/snipper.md +34 -0
  3. package/claude-code-config/agents/websearch.md +45 -0
  4. package/claude-code-config/commands/claude-memory.md +190 -0
  5. package/claude-code-config/commands/cleanup-context.md +82 -0
  6. package/claude-code-config/commands/commit.md +42 -10
  7. package/claude-code-config/commands/create-pull-request.md +33 -17
  8. package/claude-code-config/commands/deep-code-analysis.md +69 -19
  9. package/claude-code-config/commands/epct.md +49 -21
  10. package/claude-code-config/commands/explain-architecture.md +113 -0
  11. package/claude-code-config/commands/fix-pr-comments.md +45 -6
  12. package/claude-code-config/commands/prompt-agent.md +126 -0
  13. package/claude-code-config/commands/prompt-command.md +225 -0
  14. package/claude-code-config/commands/run-tasks.md +80 -25
  15. package/claude-code-config/commands/watch-ci.md +37 -16
  16. package/claude-code-config/hooks/hook-post-file.ts +162 -0
  17. package/claude-code-config/scripts/statusline-ccusage.sh +42 -10
  18. package/claude-code-config/scripts/validate-command.js +128 -42
  19. package/dist/cli.js +30709 -2535
  20. package/package.json +12 -4
  21. package/claude-code-config/agents/epct/code.md +0 -28
  22. package/claude-code-config/agents/epct/explore-orchestrator.md +0 -32
  23. package/claude-code-config/agents/epct/explore.md +0 -28
  24. package/claude-code-config/agents/epct/plan.md +0 -14
  25. package/claude-code-config/agents/epct/test.md +0 -12
  26. package/claude-code-config/agents/product/feedback-synthesizer.md +0 -146
  27. package/claude-code-config/agents/product/sprint-prioritizer.md +0 -102
  28. package/claude-code-config/agents/product/trend-researcher.md +0 -157
  29. package/claude-code-config/agents/tasks/app-store-optimizer.md +0 -192
  30. package/claude-code-config/agents/tasks/backend-reliability-engineer.md +0 -126
  31. package/claude-code-config/agents/tasks/code.md +0 -12
  32. package/claude-code-config/agents/tasks/frontend-ux-specialist.md +0 -136
  33. package/claude-code-config/agents/tasks/growth-hacker.md +0 -209
  34. package/claude-code-config/agents/tasks/prd-writer.md +0 -141
  35. package/claude-code-config/agents/tasks/senior-software-engineer.md +0 -75
  36. package/claude-code-config/agents/tasks/twitter-engager.md +0 -126
  37. package/claude-code-config/commands/deploy.md +0 -20
  38. package/claude-code-config/commands/epct-agent.md +0 -28
@@ -67,9 +67,8 @@ const SECURITY_RULES = {
67
67
 
68
68
  // Dangerous regex patterns
69
69
  DANGEROUS_PATTERNS: [
70
- // File system destruction - block rm -rf with absolute paths
70
+ // File system destruction - block rm -rf with absolute paths (checked separately)
71
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
72
  /rm\s+.*-rf\s*\/etc/i, // rm -rf in /etc
74
73
  /rm\s+.*-rf\s*\/usr/i, // rm -rf in /usr
75
74
  /rm\s+.*-rf\s*\/bin/i, // rm -rf in /bin
@@ -92,7 +91,7 @@ const SECURITY_RULES = {
92
91
 
93
92
  // Command injection (but allow general chaining - we'll validate each command separately)
94
93
  // /;\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
94
+ // /&&\s*(rm|dd|mkfs|format)/i, // Commented out - handled by individual command validation
96
95
  // /\|\|\s*(rm|dd|mkfs|format)/i, // Commented out - handled by individual command validation
97
96
 
98
97
  // Remote code execution
@@ -147,7 +146,6 @@ const SECURITY_RULES = {
147
146
  /printenv.*PASSWORD/i,
148
147
  ],
149
148
 
150
-
151
149
  // Paths that should never be written to
152
150
  PROTECTED_PATHS: [
153
151
  "/etc/",
@@ -160,6 +158,14 @@ const SECURITY_RULES = {
160
158
  "/dev/",
161
159
  "/root/",
162
160
  ],
161
+
162
+ // Safe paths where rm -rf is allowed
163
+ SAFE_RM_PATHS: [
164
+ "/Users/melvynx/Developer/",
165
+ "/tmp/",
166
+ "/var/tmp/",
167
+ process.cwd() + "/", // Current working directory
168
+ ],
163
169
  };
164
170
 
165
171
  // Allowlist of safe commands (when used appropriately)
@@ -225,7 +231,7 @@ class CommandValidator {
225
231
  const mainCommand = cmdParts[0];
226
232
 
227
233
  // Allow source and python commands unconditionally
228
- if (mainCommand === 'source' || mainCommand === 'python') {
234
+ if (mainCommand === "source" || mainCommand === "python") {
229
235
  return result; // Always allow
230
236
  }
231
237
 
@@ -257,9 +263,19 @@ class CommandValidator {
257
263
  result.violations.push(`System manipulation command: ${mainCommand}`);
258
264
  }
259
265
 
260
- // Check dangerous patterns
266
+ // Check for rm -rf commands first (special handling)
267
+ if (/rm\s+.*-rf\s/.test(command)) {
268
+ const isRmRfSafe = this.isRmRfCommandSafe(command);
269
+ if (!isRmRfSafe) {
270
+ result.isValid = false;
271
+ result.severity = "CRITICAL";
272
+ result.violations.push("rm -rf command targeting unsafe path");
273
+ }
274
+ }
275
+
276
+ // Check dangerous patterns (skip rm -rf patterns as they're handled above)
261
277
  for (const pattern of SECURITY_RULES.DANGEROUS_PATTERNS) {
262
- if (pattern.test(command)) {
278
+ if (pattern.test(command) && !/rm\s+.*-rf/.test(pattern.source)) {
263
279
  result.isValid = false;
264
280
  result.severity = "CRITICAL";
265
281
  result.violations.push(`Dangerous pattern detected: ${pattern.source}`);
@@ -267,24 +283,32 @@ class CommandValidator {
267
283
  }
268
284
 
269
285
  // Allow && chaining for safe commands like source and python
270
- if (command.includes('&&')) {
286
+ if (command.includes("&&")) {
271
287
  const chainedCommands = this.splitCommandChain(command);
272
288
  let allSafe = true;
273
289
  for (const chainedCmd of chainedCommands) {
274
290
  const trimmedCmd = chainedCmd.trim();
275
291
  const cmdParts = trimmedCmd.split(/\s+/);
276
292
  const mainCommand = cmdParts[0];
277
-
293
+
278
294
  // Allow source and python commands in && chains
279
- if (mainCommand === 'source' || mainCommand === 'python' || SAFE_COMMANDS.includes(mainCommand)) {
295
+ if (
296
+ mainCommand === "source" ||
297
+ mainCommand === "python" ||
298
+ SAFE_COMMANDS.includes(mainCommand)
299
+ ) {
280
300
  continue;
281
301
  }
282
-
302
+
283
303
  const chainResult = this.validateSingleCommand(trimmedCmd, toolName);
284
304
  if (!chainResult.isValid) {
285
305
  result.isValid = false;
286
306
  result.severity = chainResult.severity;
287
- result.violations.push(`Chained command violation: ${trimmedCmd} - ${chainResult.violations.join(', ')}`);
307
+ result.violations.push(
308
+ `Chained command violation: ${trimmedCmd} - ${chainResult.violations.join(
309
+ ", "
310
+ )}`
311
+ );
288
312
  allSafe = false;
289
313
  }
290
314
  }
@@ -292,27 +316,38 @@ class CommandValidator {
292
316
  return result; // Allow safe && chains
293
317
  }
294
318
  }
295
-
319
+
296
320
  // Check other command chaining (; and ||)
297
- if (command.includes(';') || command.includes('||')) {
321
+ if (command.includes(";") || command.includes("||")) {
298
322
  const chainedCommands = this.splitCommandChain(command);
299
323
  for (const chainedCmd of chainedCommands) {
300
- const chainResult = this.validateSingleCommand(chainedCmd.trim(), toolName);
324
+ const chainResult = this.validateSingleCommand(
325
+ chainedCmd.trim(),
326
+ toolName
327
+ );
301
328
  if (!chainResult.isValid) {
302
329
  result.isValid = false;
303
330
  result.severity = chainResult.severity;
304
- result.violations.push(`Chained command violation: ${chainedCmd.trim()} - ${chainResult.violations.join(', ')}`);
331
+ result.violations.push(
332
+ `Chained command violation: ${chainedCmd.trim()} - ${chainResult.violations.join(
333
+ ", "
334
+ )}`
335
+ );
305
336
  }
306
337
  }
307
338
  return result;
308
339
  }
309
340
 
310
-
311
341
  // Check for protected path access (but allow common redirections like /dev/null)
312
342
  for (const path of SECURITY_RULES.PROTECTED_PATHS) {
313
343
  if (command.includes(path)) {
314
344
  // Allow common safe redirections
315
- if (path === "/dev/" && (command.includes("/dev/null") || command.includes("/dev/stderr") || command.includes("/dev/stdout"))) {
345
+ if (
346
+ path === "/dev/" &&
347
+ (command.includes("/dev/null") ||
348
+ command.includes("/dev/stderr") ||
349
+ command.includes("/dev/stdout"))
350
+ ) {
316
351
  continue;
317
352
  }
318
353
  result.isValid = false;
@@ -338,7 +373,6 @@ class CommandValidator {
338
373
  return result;
339
374
  }
340
375
 
341
-
342
376
  /**
343
377
  * Validate a single command (without chaining logic to avoid recursion)
344
378
  */
@@ -362,7 +396,7 @@ class CommandValidator {
362
396
  const mainCommand = cmdParts[0];
363
397
 
364
398
  // Allow source and python commands unconditionally in single command validation too
365
- if (mainCommand === 'source' || mainCommand === 'python') {
399
+ if (mainCommand === "source" || mainCommand === "python") {
366
400
  return result; // Always allow
367
401
  }
368
402
 
@@ -394,9 +428,19 @@ class CommandValidator {
394
428
  result.violations.push(`System manipulation command: ${mainCommand}`);
395
429
  }
396
430
 
397
- // Check dangerous patterns (but skip chaining patterns since we're validating individual commands)
431
+ // Check for rm -rf commands first (special handling)
432
+ if (/rm\s+.*-rf\s/.test(command)) {
433
+ const isRmRfSafe = this.isRmRfCommandSafe(command);
434
+ if (!isRmRfSafe) {
435
+ result.isValid = false;
436
+ result.severity = "CRITICAL";
437
+ result.violations.push("rm -rf command targeting unsafe path");
438
+ }
439
+ }
440
+
441
+ // Check dangerous patterns (skip rm -rf patterns as they're handled above)
398
442
  for (const pattern of SECURITY_RULES.DANGEROUS_PATTERNS) {
399
- if (pattern.test(command)) {
443
+ if (pattern.test(command) && !/rm\s+.*-rf/.test(pattern.source)) {
400
444
  result.isValid = false;
401
445
  result.severity = "CRITICAL";
402
446
  result.violations.push(`Dangerous pattern detected: ${pattern.source}`);
@@ -406,7 +450,12 @@ class CommandValidator {
406
450
  // Check for protected path access
407
451
  for (const path of SECURITY_RULES.PROTECTED_PATHS) {
408
452
  if (command.includes(path)) {
409
- if (path === "/dev/" && (command.includes("/dev/null") || command.includes("/dev/stderr") || command.includes("/dev/stdout"))) {
453
+ if (
454
+ path === "/dev/" &&
455
+ (command.includes("/dev/null") ||
456
+ command.includes("/dev/stderr") ||
457
+ command.includes("/dev/stdout"))
458
+ ) {
410
459
  continue;
411
460
  }
412
461
  result.isValid = false;
@@ -439,14 +488,14 @@ class CommandValidator {
439
488
  // Simple splitting on && ; ||
440
489
  // This is basic - doesn't handle complex quoting, but good enough for basic validation
441
490
  const commands = [];
442
- let current = '';
491
+ let current = "";
443
492
  let inQuotes = false;
444
- let quoteChar = '';
445
-
493
+ let quoteChar = "";
494
+
446
495
  for (let i = 0; i < command.length; i++) {
447
496
  const char = command[i];
448
497
  const nextChar = command[i + 1];
449
-
498
+
450
499
  // Handle quotes
451
500
  if ((char === '"' || char === "'") && !inQuotes) {
452
501
  inQuotes = true;
@@ -454,31 +503,31 @@ class CommandValidator {
454
503
  current += char;
455
504
  } else if (char === quoteChar && inQuotes) {
456
505
  inQuotes = false;
457
- quoteChar = '';
506
+ quoteChar = "";
458
507
  current += char;
459
508
  } else if (inQuotes) {
460
509
  current += char;
461
- } else if (char === '&' && nextChar === '&') {
510
+ } else if (char === "&" && nextChar === "&") {
462
511
  commands.push(current.trim());
463
- current = '';
512
+ current = "";
464
513
  i++; // skip next &
465
- } else if (char === '|' && nextChar === '|') {
514
+ } else if (char === "|" && nextChar === "|") {
466
515
  commands.push(current.trim());
467
- current = '';
516
+ current = "";
468
517
  i++; // skip next |
469
- } else if (char === ';') {
518
+ } else if (char === ";") {
470
519
  commands.push(current.trim());
471
- current = '';
520
+ current = "";
472
521
  } else {
473
522
  current += char;
474
523
  }
475
524
  }
476
-
525
+
477
526
  if (current.trim()) {
478
527
  commands.push(current.trim());
479
528
  }
480
-
481
- return commands.filter(cmd => cmd.length > 0);
529
+
530
+ return commands.filter((cmd) => cmd.length > 0);
482
531
  }
483
532
 
484
533
  /**
@@ -513,6 +562,39 @@ class CommandValidator {
513
562
  }
514
563
  }
515
564
 
565
+ /**
566
+ * Check if rm -rf command targets a safe path
567
+ */
568
+ isRmRfCommandSafe(command) {
569
+ // Extract the path from rm -rf command
570
+ const rmRfMatch = command.match(/rm\s+.*-rf\s+([^\s;&|]+)/);
571
+ if (!rmRfMatch) {
572
+ return false; // Couldn't parse path, block for safety
573
+ }
574
+
575
+ const targetPath = rmRfMatch[1];
576
+
577
+ // Block if targeting root or ending at root
578
+ if (targetPath === "/" || targetPath.endsWith("/")) {
579
+ return false;
580
+ }
581
+
582
+ // Check if path starts with any safe prefix
583
+ for (const safePath of SECURITY_RULES.SAFE_RM_PATHS) {
584
+ if (targetPath.startsWith(safePath)) {
585
+ return true;
586
+ }
587
+ }
588
+
589
+ // Check if it's a relative path (safer)
590
+ if (!targetPath.startsWith("/")) {
591
+ return true;
592
+ }
593
+
594
+ // Block all other absolute paths
595
+ return false;
596
+ }
597
+
516
598
  /**
517
599
  * Check if command matches any allowed patterns from settings
518
600
  */
@@ -594,16 +676,20 @@ async function main() {
594
676
  process.exit(0); // Allow execution
595
677
  } else {
596
678
  // 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
-
679
+ const confirmationMessage = `⚠️ Potentially dangerous command detected!\n\nCommand: ${command}\nViolations: ${result.violations.join(
680
+ ", "
681
+ )}\nSeverity: ${
682
+ result.severity
683
+ }\n\nDo you want to proceed with this command?`;
684
+
599
685
  const hookOutput = {
600
686
  hookSpecificOutput: {
601
687
  hookEventName: "PreToolUse",
602
688
  permissionDecision: "ask",
603
- permissionDecisionReason: confirmationMessage
604
- }
689
+ permissionDecisionReason: confirmationMessage,
690
+ },
605
691
  };
606
-
692
+
607
693
  console.log(JSON.stringify(hookOutput));
608
694
  process.exit(0); // Exit with 0 to trigger user prompt
609
695
  }