aiblueprint-cli 1.0.3 → 1.1.1
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.
- package/claude-code-config/agents/explore-codebase.md +57 -0
- package/claude-code-config/agents/snipper.md +34 -0
- package/claude-code-config/agents/websearch.md +45 -0
- package/claude-code-config/commands/claude-memory.md +190 -0
- package/claude-code-config/commands/cleanup-context.md +82 -0
- package/claude-code-config/commands/commit.md +42 -10
- package/claude-code-config/commands/create-pull-request.md +33 -17
- package/claude-code-config/commands/deep-code-analysis.md +69 -19
- package/claude-code-config/commands/epct.md +49 -21
- package/claude-code-config/commands/explain-architecture.md +113 -0
- package/claude-code-config/commands/fix-pr-comments.md +45 -6
- package/claude-code-config/commands/prompt-agent.md +126 -0
- package/claude-code-config/commands/prompt-command.md +225 -0
- package/claude-code-config/commands/run-tasks.md +80 -25
- package/claude-code-config/commands/watch-ci.md +37 -16
- package/claude-code-config/hooks/hook-post-file.ts +162 -0
- package/claude-code-config/scripts/statusline-ccusage.sh +42 -10
- package/claude-code-config/scripts/validate-command.js +128 -42
- package/dist/cli.js +30713 -2535
- package/package.json +12 -4
- package/claude-code-config/agents/epct/code.md +0 -28
- package/claude-code-config/agents/epct/explore-orchestrator.md +0 -32
- package/claude-code-config/agents/epct/explore.md +0 -28
- package/claude-code-config/agents/epct/plan.md +0 -14
- package/claude-code-config/agents/epct/test.md +0 -12
- package/claude-code-config/agents/product/feedback-synthesizer.md +0 -146
- package/claude-code-config/agents/product/sprint-prioritizer.md +0 -102
- package/claude-code-config/agents/product/trend-researcher.md +0 -157
- package/claude-code-config/agents/tasks/app-store-optimizer.md +0 -192
- package/claude-code-config/agents/tasks/backend-reliability-engineer.md +0 -126
- package/claude-code-config/agents/tasks/code.md +0 -12
- package/claude-code-config/agents/tasks/frontend-ux-specialist.md +0 -136
- package/claude-code-config/agents/tasks/growth-hacker.md +0 -209
- package/claude-code-config/agents/tasks/prd-writer.md +0 -141
- package/claude-code-config/agents/tasks/senior-software-engineer.md +0 -75
- package/claude-code-config/agents/tasks/twitter-engager.md +0 -126
- package/claude-code-config/commands/deploy.md +0 -20
- 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 ===
|
|
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
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 (
|
|
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 ===
|
|
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
|
|
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 (
|
|
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 ===
|
|
510
|
+
} else if (char === "&" && nextChar === "&") {
|
|
462
511
|
commands.push(current.trim());
|
|
463
|
-
current =
|
|
512
|
+
current = "";
|
|
464
513
|
i++; // skip next &
|
|
465
|
-
} else if (char ===
|
|
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(
|
|
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
|
}
|