pumuki-ast-hooks 5.5.50 → 5.5.52

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 (30) hide show
  1. package/docs/MCP_SERVERS.md +16 -2
  2. package/docs/RELEASE_NOTES.md +34 -0
  3. package/hooks/git-status-monitor.ts +0 -5
  4. package/hooks/notify-macos.ts +0 -1
  5. package/hooks/pre-tool-use-evidence-validator.ts +0 -1
  6. package/package.json +2 -2
  7. package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +96 -0
  8. package/scripts/hooks-system/application/services/guard/GuardConfig.js +2 -4
  9. package/scripts/hooks-system/application/services/installation/GitEnvironmentService.js +2 -20
  10. package/scripts/hooks-system/application/services/installation/McpConfigurator.js +9 -139
  11. package/scripts/hooks-system/application/services/installation/mcp/McpGlobalConfigCleaner.js +49 -0
  12. package/scripts/hooks-system/application/services/installation/mcp/McpProjectConfigWriter.js +59 -0
  13. package/scripts/hooks-system/application/services/installation/mcp/McpServerConfigBuilder.js +103 -0
  14. package/scripts/hooks-system/infrastructure/ast/ast-core.js +1 -13
  15. package/scripts/hooks-system/infrastructure/ast/ast-intelligence.js +3 -2
  16. package/scripts/hooks-system/infrastructure/ast/backend/ast-backend.js +17 -9
  17. package/scripts/hooks-system/infrastructure/ast/backend/detectors/god-class-detector.js +2 -1
  18. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSCICDChecks.js +385 -0
  19. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSCICDRules.js +38 -408
  20. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSEnterpriseAnalyzer.js +397 -34
  21. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSSPMChecks.js +408 -0
  22. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSSPMRules.js +36 -442
  23. package/scripts/hooks-system/infrastructure/ast/ios/parsers/SourceKittenExtractor.js +146 -0
  24. package/scripts/hooks-system/infrastructure/ast/ios/parsers/SourceKittenParser.js +22 -190
  25. package/scripts/hooks-system/infrastructure/ast/ios/parsers/SourceKittenRunner.js +62 -0
  26. package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +398 -1
  27. package/scripts/hooks-system/infrastructure/orchestration/__tests__/intelligent-audit.spec.js +0 -16
  28. package/scripts/hooks-system/infrastructure/orchestration/intelligent-audit.js +14 -25
  29. package/scripts/hooks-system/infrastructure/shell/gitflow/gitflow-enforcer.sh +20 -76
  30. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSEnterpriseChecks.js +0 -350
@@ -576,9 +576,293 @@ function checkBranchChangesCoherence(branchName, uncommittedChanges) {
576
576
  return { isCoherent: true, expectedScope, detectedScope: dominantScope, reason: 'Changes match branch scope' };
577
577
  }
578
578
 
579
+ /**
580
+ * Load platform rules from .cursor/rules or .windsurf/rules
581
+ * Returns the content of the rules file for the detected platform
582
+ */
583
+ async function loadPlatformRules(platforms) {
584
+ const DynamicRulesLoader = require('../../application/services/DynamicRulesLoader');
585
+ const loader = new DynamicRulesLoader();
586
+ const rules = {};
587
+ const criticalRules = [];
588
+
589
+ for (const platform of platforms) {
590
+ try {
591
+ const content = await loader.loadRule(`rules${platform}.mdc`);
592
+ if (content) {
593
+ rules[platform] = content;
594
+ const criticalPatterns = extractCriticalPatterns(content, platform);
595
+ criticalRules.push(...criticalPatterns);
596
+ }
597
+ } catch (error) {
598
+ if (process.env.DEBUG) {
599
+ process.stderr.write(`[MCP] Failed to load rules for ${platform}: ${error.message}\n`);
600
+ }
601
+ }
602
+ }
603
+
604
+ try {
605
+ const goldContent = await loader.loadRule('rulesgold.mdc');
606
+ if (goldContent) {
607
+ rules.gold = goldContent;
608
+ const goldPatterns = extractCriticalPatterns(goldContent, 'gold');
609
+ criticalRules.push(...goldPatterns);
610
+ }
611
+ } catch (error) {
612
+ if (process.env.DEBUG) {
613
+ process.stderr.write(`[MCP] Failed to load gold rules: ${error.message}\n`);
614
+ }
615
+ }
616
+
617
+ return { rules, criticalRules };
618
+ }
619
+
620
+ /**
621
+ * Extract critical patterns from rules content that AI MUST follow
622
+ */
623
+ function extractCriticalPatterns(content, platform) {
624
+ const patterns = [];
625
+ if (!content) return patterns;
626
+
627
+ const lines = content.split('\n');
628
+ for (const line of lines) {
629
+ if (line.includes('❌') || line.includes('NUNCA') || line.includes('PROHIBIDO') || line.includes('NO ')) {
630
+ patterns.push({ platform, rule: line.trim(), severity: 'CRITICAL' });
631
+ }
632
+ if (line.includes('✅') && (line.includes('OBLIGATORIO') || line.includes('SIEMPRE'))) {
633
+ patterns.push({ platform, rule: line.trim(), severity: 'MANDATORY' });
634
+ }
635
+ }
636
+
637
+ if (platform === 'ios') {
638
+ // PROHIBICIONES CRÍTICAS iOS
639
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar GCD (DispatchQueue.main.async, DispatchQueue.global) - usar Swift Concurrency (async/await, Task, actor, @MainActor)', severity: 'CRITICAL' });
640
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar completion handlers/@escaping callbacks - usar async/await', severity: 'CRITICAL' });
641
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA dejar catch vacíos - siempre gestionar errores (log/rethrow/wrap)', severity: 'CRITICAL' });
642
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA mezclar operaciones de escritura (commands) con lecturas (queries) en el mismo flujo/servicio - aplicar CQRS', severity: 'CRITICAL' });
643
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar Singleton - usar Inyección de Dependencias (DI por init/protocols)', severity: 'CRITICAL' });
644
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar force unwrap (!) - usar guard let/if let/?? (excepción: IBOutlets)', severity: 'CRITICAL' });
645
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar librerías de terceros (Alamofire, Swinject, Quick/Nimble, etc.) - usar APIs nativas (URLSession, DI manual, Swift Testing)', severity: 'CRITICAL' });
646
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA añadir comentarios en el código - nombres autodescriptivos', severity: 'CRITICAL' });
647
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar prints/logs ad-hoc - usar Logger del framework os', severity: 'CRITICAL' });
648
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar AnyView - afecta performance, usar @ViewBuilder o generics', severity: 'CRITICAL' });
649
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar ObservableObject - usar @Observable (iOS 17+)', severity: 'CRITICAL' });
650
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar Storyboards/XIBs - usar SwiftUI o Programmatic UI', severity: 'CRITICAL' });
651
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar CocoaPods/Carthage - usar Swift Package Manager', severity: 'CRITICAL' });
652
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar JSONSerialization - usar Codable', severity: 'CRITICAL' });
653
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar OperationQueue para async - usar Task/TaskGroup', severity: 'CRITICAL' });
654
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar any (type erasure) - usar generics con protocolos de frontera', severity: 'CRITICAL' });
655
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA usar Localizable.strings - usar String Catalogs (.xcstrings)', severity: 'CRITICAL' });
656
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA ignorar warnings - warnings = errores futuros', severity: 'CRITICAL' });
657
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA crear Massive View Controllers (>300 líneas) - separar lógica en ViewModels', severity: 'CRITICAL' });
658
+ patterns.push({ platform: 'ios', rule: '❌ NUNCA crear retain cycles - usar [weak self] en closures', severity: 'CRITICAL' });
659
+
660
+ // OBLIGATORIOS iOS
661
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar Swift 6.2 con Strict Concurrency Checking en Complete', severity: 'MANDATORY' });
662
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar async/await para TODAS las operaciones asíncronas', severity: 'MANDATORY' });
663
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar SwiftUI (UIKit solo si estrictamente necesario)', severity: 'MANDATORY' });
664
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar @Observable (iOS 17+) con @Bindable para bindings', severity: 'MANDATORY' });
665
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar NavigationStack + NavigationPath para navegación', severity: 'MANDATORY' });
666
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar guard/early returns - evitar pyramid of doom', severity: 'MANDATORY' });
667
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO seguir Clean Architecture (Domain → Application → Infrastructure → Presentation)', severity: 'MANDATORY' });
668
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO aplicar CQRS (Command Query Responsibility Segregation): separar comandos (write) de consultas (read)', severity: 'MANDATORY' });
669
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO verificar SOLID (SRP, OCP, LSP, ISP, DIP)', severity: 'MANDATORY' });
670
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO nombres autodescriptivos en inglés', severity: 'MANDATORY' });
671
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO comprobar que compila (Xcode build) ANTES de sugerir', severity: 'MANDATORY' });
672
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar Sendable conformance para tipos thread-safe', severity: 'MANDATORY' });
673
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar actor para estado compartido thread-safe', severity: 'MANDATORY' });
674
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar @MainActor para código UI', severity: 'MANDATORY' });
675
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar Task {} para lanzar contextos asíncronos desde código síncrono', severity: 'MANDATORY' });
676
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar Keychain nativo para datos sensibles (NO UserDefaults)', severity: 'MANDATORY' });
677
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar SwiftData (iOS 17+) para persistencia (CoreData solo legacy)', severity: 'MANDATORY' });
678
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar Swift Testing framework para tests (XCTest solo legacy)', severity: 'MANDATORY' });
679
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar makeSUT pattern en tests', severity: 'MANDATORY' });
680
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar trackForMemoryLeaks helper en tests', severity: 'MANDATORY' });
681
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar spies en vez de mocks/stubs', severity: 'MANDATORY' });
682
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar protocols para testability (inyectar protocols, no tipos concretos)', severity: 'MANDATORY' });
683
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar struct por defecto, class solo cuando necesites identity/herencia', severity: 'MANDATORY' });
684
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO usar let > var (inmutabilidad por defecto)', severity: 'MANDATORY' });
685
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO cero warnings en el proyecto', severity: 'MANDATORY' });
686
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO seguir flujo BDD → TDD (Feature files → Specs → Implementación)', severity: 'MANDATORY' });
687
+ patterns.push({ platform: 'ios', rule: '✅ OBLIGATORIO en producción todo real contra APIs/persistencia (cero mocks/spies)', severity: 'MANDATORY' });
688
+ }
689
+
690
+ if (platform === 'android') {
691
+ // PROHIBICIONES CRÍTICAS Android
692
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar Singleton - usar Hilt para Inyección de Dependencias', severity: 'CRITICAL' });
693
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar XML layouts - usar Jetpack Compose', severity: 'CRITICAL' });
694
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar Java en código nuevo - usar Kotlin 100%', severity: 'CRITICAL' });
695
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar LiveData - usar StateFlow/SharedFlow', severity: 'CRITICAL' });
696
+ patterns.push({ platform: 'android', rule: '❌ NUNCA dejar catch vacíos - siempre gestionar errores', severity: 'CRITICAL' });
697
+ patterns.push({ platform: 'android', rule: '❌ NUNCA mezclar operaciones de escritura (commands) con lecturas (queries) en el mismo caso de uso/repository - aplicar CQRS', severity: 'CRITICAL' });
698
+ patterns.push({ platform: 'android', rule: '❌ NUNCA añadir comentarios en el código', severity: 'CRITICAL' });
699
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar force unwrap (!!) - usar ?, ?:, let, requireNotNull', severity: 'CRITICAL' });
700
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar AsyncTask (deprecated) - usar Coroutines', severity: 'CRITICAL' });
701
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar RxJava en código nuevo - usar Flow', severity: 'CRITICAL' });
702
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar findViewById - usar Compose o View Binding', severity: 'CRITICAL' });
703
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar Context leaks - no referencias a Activity en objetos long-lived', severity: 'CRITICAL' });
704
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar God Activities - Single Activity + Composables', severity: 'CRITICAL' });
705
+ patterns.push({ platform: 'android', rule: '❌ NUNCA hardcodear strings - usar strings.xml', severity: 'CRITICAL' });
706
+ patterns.push({ platform: 'android', rule: '❌ NUNCA usar callbacks para async - usar suspend functions', severity: 'CRITICAL' });
707
+
708
+ // OBLIGATORIOS Android
709
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Jetpack Compose + Material 3', severity: 'MANDATORY' });
710
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Hilt para DI (@HiltAndroidApp, @AndroidEntryPoint, @Inject)', severity: 'MANDATORY' });
711
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Kotlin Coroutines + Flow para async', severity: 'MANDATORY' });
712
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar StateFlow para exponer estado del ViewModel', severity: 'MANDATORY' });
713
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar sealed classes para estados (Success, Error, Loading)', severity: 'MANDATORY' });
714
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO seguir Clean Architecture (Domain → Data → Presentation)', severity: 'MANDATORY' });
715
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO aplicar CQRS (Command Query Responsibility Segregation): separar comandos (write) de consultas (read)', severity: 'MANDATORY' });
716
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO verificar SOLID', severity: 'MANDATORY' });
717
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar MVVM + Single Activity', severity: 'MANDATORY' });
718
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Navigation Compose para navegación', severity: 'MANDATORY' });
719
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Room para persistencia local', severity: 'MANDATORY' });
720
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Retrofit + Moshi para networking', severity: 'MANDATORY' });
721
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Coil para carga de imágenes', severity: 'MANDATORY' });
722
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Kotlin DSL (build.gradle.kts)', severity: 'MANDATORY' });
723
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Version Catalogs (libs.versions.toml)', severity: 'MANDATORY' });
724
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar JUnit5 + MockK para testing', severity: 'MANDATORY' });
725
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar Timber para logging (solo en DEBUG)', severity: 'MANDATORY' });
726
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO usar EncryptedSharedPreferences para datos sensibles', severity: 'MANDATORY' });
727
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO nombres autodescriptivos en inglés', severity: 'MANDATORY' });
728
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO comprobar que compila (Gradle build) ANTES de sugerir', severity: 'MANDATORY' });
729
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO seguir flujo BDD → TDD', severity: 'MANDATORY' });
730
+ patterns.push({ platform: 'android', rule: '✅ OBLIGATORIO en producción todo real contra APIs/persistencia', severity: 'MANDATORY' });
731
+ }
732
+
733
+ if (platform === 'backend') {
734
+ // PROHIBICIONES CRÍTICAS Backend
735
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA usar Singleton - usar NestJS DI (@Injectable)', severity: 'CRITICAL' });
736
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA usar console.log/console.error - usar Logger de NestJS', severity: 'CRITICAL' });
737
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA usar any/unknown en TypeScript - usar tipos explícitos o generics', severity: 'CRITICAL' });
738
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA dejar catch vacíos - siempre loggear o propagar (common.error.empty_catch)', severity: 'CRITICAL' });
739
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA mezclar Command y Query en el mismo handler/service - aplicar CQRS', severity: 'CRITICAL' });
740
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA hardcodear secretos - usar variables de entorno (AWS Secrets Manager, Vault)', severity: 'CRITICAL' });
741
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA añadir comentarios en el código', severity: 'CRITICAL' });
742
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA exponer datos sin validar - usar class-validator + DTOs', severity: 'CRITICAL' });
743
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA exponer stack traces en producción', severity: 'CRITICAL' });
744
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA usar mocks en producción - solo datos reales', severity: 'CRITICAL' });
745
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA loggear datos sensibles (passwords, tokens, PII)', severity: 'CRITICAL' });
746
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA usar God classes (servicios >500 líneas)', severity: 'CRITICAL' });
747
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA usar callback hell - usar async/await', severity: 'CRITICAL' });
748
+ patterns.push({ platform: 'backend', rule: '❌ NUNCA poner lógica en controllers - mover a servicios/use cases', severity: 'CRITICAL' });
749
+
750
+ // OBLIGATORIOS Backend
751
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar Repository Pattern (interfaces en domain, impl en infrastructure)', severity: 'MANDATORY' });
752
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar DTOs + class-validator para validación de entrada/salida', severity: 'MANDATORY' });
753
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar Guards para autenticación/autorización (@UseGuards)', severity: 'MANDATORY' });
754
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO paginación en TODOS los endpoints de listado', severity: 'MANDATORY' });
755
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO seguir Clean Architecture (Domain → Application → Infrastructure → Presentation)', severity: 'MANDATORY' });
756
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO aplicar CQRS (Command Query Responsibility Segregation): Commands (write) separados de Queries (read)', severity: 'MANDATORY' });
757
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO verificar SOLID', severity: 'MANDATORY' });
758
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO TypeScript strict mode', severity: 'MANDATORY' });
759
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar Use Cases explícitos (CreateOrderUseCase, etc.)', severity: 'MANDATORY' });
760
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar Exception Filters para manejo global de errores', severity: 'MANDATORY' });
761
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar Swagger/OpenAPI para documentación (@nestjs/swagger)', severity: 'MANDATORY' });
762
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar queries parametrizadas (prevenir SQL injection)', severity: 'MANDATORY' });
763
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar índices en columnas frecuentes en WHERE/JOIN', severity: 'MANDATORY' });
764
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar transacciones para operaciones críticas', severity: 'MANDATORY' });
765
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar soft deletes (deleted_at) por defecto', severity: 'MANDATORY' });
766
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar JWT + refresh tokens para autenticación', severity: 'MANDATORY' });
767
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar rate limiting (@nestjs/throttler)', severity: 'MANDATORY' });
768
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar Helmet para security headers', severity: 'MANDATORY' });
769
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar health checks (/health endpoint)', severity: 'MANDATORY' });
770
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO usar correlation IDs para tracing distribuido', severity: 'MANDATORY' });
771
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO nombres autodescriptivos en inglés', severity: 'MANDATORY' });
772
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO comprobar que compila (npm run build) ANTES de sugerir', severity: 'MANDATORY' });
773
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO seguir flujo BDD → TDD', severity: 'MANDATORY' });
774
+ patterns.push({ platform: 'backend', rule: '✅ OBLIGATORIO coverage >95% en lógica crítica', severity: 'MANDATORY' });
775
+ }
776
+
777
+ if (platform === 'frontend') {
778
+ // PROHIBICIONES CRÍTICAS Frontend
779
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA usar any/unknown en TypeScript - usar tipos explícitos o generics', severity: 'CRITICAL' });
780
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA usar class components - usar functional components + hooks', severity: 'CRITICAL' });
781
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA hardcodear strings - usar i18n (useTranslation)', severity: 'CRITICAL' });
782
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA dejar catch vacíos - siempre gestionar errores (common.error.empty_catch)', severity: 'CRITICAL' });
783
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA mezclar operaciones de escritura (commands/mutations) con lecturas (queries) en el mismo hook/service - aplicar CQRS', severity: 'CRITICAL' });
784
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA añadir comentarios en el código', severity: 'CRITICAL' });
785
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA usar console.log en producción', severity: 'CRITICAL' });
786
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA usar Singleton - usar providers/context para DI', severity: 'CRITICAL' });
787
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA usar índice como key en listas si el orden puede cambiar', severity: 'CRITICAL' });
788
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA usar prop drilling excesivo - usar Context/Zustand', severity: 'CRITICAL' });
789
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA renderizar HTML de usuario sin sanitizar (DOMPurify)', severity: 'CRITICAL' });
790
+ patterns.push({ platform: 'frontend', rule: '❌ NUNCA poner tokens en URLs - usar Authorization headers', severity: 'CRITICAL' });
791
+
792
+ // OBLIGATORIOS Frontend
793
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar TypeScript strict mode', severity: 'MANDATORY' });
794
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar React functional components + hooks', severity: 'MANDATORY' });
795
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar TailwindCSS para estilos', severity: 'MANDATORY' });
796
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar Next.js 15 App Router (app/ directory)', severity: 'MANDATORY' });
797
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar Server Components por defecto ("use client" solo cuando necesario)', severity: 'MANDATORY' });
798
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar React Query para server state', severity: 'MANDATORY' });
799
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar Zustand para estado global', severity: 'MANDATORY' });
800
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar React Hook Form + Zod para forms', severity: 'MANDATORY' });
801
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO API client en capa infrastructure (abstraer axios/fetch)', severity: 'MANDATORY' });
802
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO tests con React Testing Library + Playwright', severity: 'MANDATORY' });
803
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO seguir Clean Architecture', severity: 'MANDATORY' });
804
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO aplicar CQRS (Command Query Responsibility Segregation): separar writes (mutations) de reads (queries)', severity: 'MANDATORY' });
805
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO verificar SOLID', severity: 'MANDATORY' });
806
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar Next/Image para imágenes', severity: 'MANDATORY' });
807
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar loading.tsx/error.tsx en cada ruta', severity: 'MANDATORY' });
808
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar semantic HTML + ARIA labels', severity: 'MANDATORY' });
809
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO usar keyboard navigation en todos los interactivos', severity: 'MANDATORY' });
810
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO WCAG AA mínimo (contraste 4.5:1)', severity: 'MANDATORY' });
811
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO nombres autodescriptivos en inglés', severity: 'MANDATORY' });
812
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO comprobar que compila y pasa tests ANTES de sugerir', severity: 'MANDATORY' });
813
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO seguir flujo BDD → TDD', severity: 'MANDATORY' });
814
+ patterns.push({ platform: 'frontend', rule: '✅ OBLIGATORIO en producción todo real contra APIs', severity: 'MANDATORY' });
815
+ }
816
+
817
+ if (platform === 'gold') {
818
+ // PROHIBICIONES CRÍTICAS Gold (comunes a todas las plataformas)
819
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA usar Singleton - usar Inyección de Dependencias', severity: 'CRITICAL' });
820
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA dejar catch vacíos - siempre loggear o propagar (AST: common.error.empty_catch)', severity: 'CRITICAL' });
821
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA añadir comentarios en el código - nombres autodescriptivos', severity: 'CRITICAL' });
822
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA usar mocks/spies en producción - todo real contra BBDD/servicios', severity: 'CRITICAL' });
823
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA usar --no-verify o GIT_BYPASS_HOOK sin autorización explícita verbal', severity: 'CRITICAL' });
824
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA hardcodear secretos en código - usar variables de entorno', severity: 'CRITICAL' });
825
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA silenciar errores - siempre loggear o propagar', severity: 'CRITICAL' });
826
+ patterns.push({ platform: 'gold', rule: '❌ NUNCA modificar librerías locales (node_modules/@pumuki/...) - reportar bugs', severity: 'CRITICAL' });
827
+
828
+ // OBLIGATORIOS Gold (comunes a todas las plataformas)
829
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO responder siempre en español', severity: 'MANDATORY' });
830
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO actuar como Arquitecto de Soluciones y Software Designer', severity: 'MANDATORY' });
831
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO seguir flujo BDD → TDD (Feature files → Specs → Implementación)', severity: 'MANDATORY' });
832
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO seguir Clean Architecture y Clean Code (capas, dependencias hacia adentro)', severity: 'MANDATORY' });
833
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO verificar SOLID (SRP, OCP, LSP, ISP, DIP) en cada cambio', severity: 'MANDATORY' });
834
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO preferir guard/early returns - evitar pyramid of doom', severity: 'MANDATORY' });
835
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO nombres autodescriptivos en inglés (todo el código)', severity: 'MANDATORY' });
836
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO comprobar que compila ANTES de sugerir cualquier cambio', severity: 'MANDATORY' });
837
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO analizar estructura existente antes de implementar', severity: 'MANDATORY' });
838
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO usar makeSUT pattern en tests', severity: 'MANDATORY' });
839
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO usar trackForMemoryLeaks en tests', severity: 'MANDATORY' });
840
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO preferir spies frente a stubs/mocks en tests', severity: 'MANDATORY' });
841
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO validar SIEMPRE entradas de usuario', severity: 'MANDATORY' });
842
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO sanitizar datos (prevenir XSS, SQL Injection)', severity: 'MANDATORY' });
843
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO principio de menor privilegio (permisos mínimos)', severity: 'MANDATORY' });
844
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO paginación en todas las listas', severity: 'MANDATORY' });
845
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO tests como documentación viva (AAA/Given-When-Then)', severity: 'MANDATORY' });
846
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO cobertura mínima 80%, objetivo 95%+ en lógica crítica', severity: 'MANDATORY' });
847
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO commits atómicos con Conventional Commits (feat:, fix:, etc.)', severity: 'MANDATORY' });
848
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO branch naming (feature/, bugfix/, hotfix/, refactor/)', severity: 'MANDATORY' });
849
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO i18n desde día 1 - no hardcodear strings', severity: 'MANDATORY' });
850
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO WCAG 2.1 AA mínimo para accesibilidad', severity: 'MANDATORY' });
851
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO "Measure twice, cut once" - planificar bien antes de implementar', severity: 'MANDATORY' });
852
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO YAGNI - You Ain\'t Gonna Need It (no sobre-ingeniería)', severity: 'MANDATORY' });
853
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO KISS - Keep It Simple, Stupid (solución más simple que funcione)', severity: 'MANDATORY' });
854
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO Fail Fast - validar precondiciones al inicio', severity: 'MANDATORY' });
855
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO inmutabilidad por defecto (const, readonly, let > var)', severity: 'MANDATORY' });
856
+ patterns.push({ platform: 'gold', rule: '✅ OBLIGATORIO composición > herencia', severity: 'MANDATORY' });
857
+ }
858
+
859
+ return patterns;
860
+ }
861
+
579
862
  /**
580
863
  * AI Gate Check - MANDATORY at start of every AI response
581
864
  * Returns BLOCKED or ALLOWED status with auto-fixes applied
865
+ * NOW INCLUDES: mandatory_rules that AI MUST read and follow
582
866
  */
583
867
  async function aiGateCheck() {
584
868
  const startedAt = Date.now();
@@ -683,6 +967,57 @@ async function aiGateCheck() {
683
967
  }
684
968
  }
685
969
 
970
+ let detectedPlatforms = [];
971
+ try {
972
+ const orchestrator = getCompositionRoot().getOrchestrator();
973
+ const contextDecision = await orchestrator.analyzeContext();
974
+ if (contextDecision && contextDecision.platforms) {
975
+ detectedPlatforms = contextDecision.platforms.map(p => p.platform || p);
976
+ }
977
+ } catch (err) {
978
+ if (process.env.DEBUG) {
979
+ process.stderr.write(`[MCP] analyzeContext failed, using fallback: ${err.message}\n`);
980
+ }
981
+ }
982
+
983
+ if (detectedPlatforms.length === 0) {
984
+ try {
985
+ const PlatformDetectionService = require('../../application/services/PlatformDetectionService');
986
+ const detector = new PlatformDetectionService();
987
+ detectedPlatforms = await detector.detectPlatforms(REPO_ROOT);
988
+ } catch (err) {
989
+ if (process.env.DEBUG) {
990
+ process.stderr.write(`[MCP] PlatformDetectionService failed: ${err.message}\n`);
991
+ }
992
+ }
993
+ }
994
+
995
+ const platformsToLoad = detectedPlatforms.length > 0
996
+ ? detectedPlatforms.map(p => String(p).toLowerCase())
997
+ : ['backend', 'frontend', 'ios', 'android'];
998
+
999
+ let mandatoryRules = null;
1000
+ try {
1001
+ const rulesData = await loadPlatformRules(platformsToLoad);
1002
+ mandatoryRules = {
1003
+ platforms: platformsToLoad,
1004
+ criticalRules: rulesData.criticalRules || [],
1005
+ rulesLoaded: Object.keys(rulesData.rules || {}),
1006
+ warning: '⚠️ AI MUST read and follow these rules before ANY code generation or modification'
1007
+ };
1008
+ } catch (err) {
1009
+ if (process.env.DEBUG) {
1010
+ process.stderr.write(`[MCP] loadPlatformRules failed: ${err.message}\n`);
1011
+ }
1012
+ mandatoryRules = {
1013
+ platforms: platformsToLoad,
1014
+ criticalRules: [],
1015
+ rulesLoaded: [],
1016
+ warning: '⚠️ Rules loading failed but AI MUST still follow project conventions',
1017
+ error: err.message
1018
+ };
1019
+ }
1020
+
686
1021
  return {
687
1022
  status: isBlocked ? 'BLOCKED' : 'ALLOWED',
688
1023
  timestamp: new Date().toISOString(),
@@ -690,12 +1025,15 @@ async function aiGateCheck() {
690
1025
  violations,
691
1026
  warnings,
692
1027
  autoFixes,
1028
+ mandatory_rules: mandatoryRules,
693
1029
  summary: isBlocked
694
1030
  ? `🚫 BLOCKED: ${violations.length} violation(s). Fix before proceeding.`
695
1031
  : `🚦 ALLOWED: Gate passed.${warnings.length > 0 ? ` ${warnings.length} warning(s).` : ''}`,
696
1032
  instructions: isBlocked
697
1033
  ? 'DO NOT proceed with user task. Announce violations and fix them first.'
698
- : 'You may proceed with user task.'
1034
+ : mandatoryRules
1035
+ ? `You may proceed with user task. CRITICAL: Review mandatory_rules.criticalRules BEFORE generating ANY code.`
1036
+ : 'You may proceed with user task.'
699
1037
  };
700
1038
  };
701
1039
 
@@ -717,6 +1055,47 @@ async function aiGateCheck() {
717
1055
  };
718
1056
  }
719
1057
 
1058
+ /**
1059
+ * Read platform rules handler - returns critical rules for a specific platform
1060
+ */
1061
+ async function readPlatformRulesHandler(params) {
1062
+ const platform = params.platform;
1063
+ if (!platform) {
1064
+ return {
1065
+ success: false,
1066
+ error: 'Platform is required. Use: ios, android, backend, or frontend'
1067
+ };
1068
+ }
1069
+
1070
+ try {
1071
+ const rulesData = await loadPlatformRules([platform]);
1072
+ const DynamicRulesLoader = require('../../application/services/DynamicRulesLoader');
1073
+ const loader = new DynamicRulesLoader();
1074
+ const fullContent = await loader.loadRule(`rules${platform}.mdc`);
1075
+
1076
+ return {
1077
+ success: true,
1078
+ platform,
1079
+ rulesLoaded: true,
1080
+ criticalRules: rulesData.criticalRules,
1081
+ fullRulesContent: fullContent,
1082
+ warning: `⚠️ YOU MUST FOLLOW ALL THESE RULES. Violations will block commits.`,
1083
+ instructions: [
1084
+ `❌ NEVER violate any rule marked with ❌ or NUNCA/PROHIBIDO`,
1085
+ `✅ ALWAYS follow rules marked with ✅ or OBLIGATORIO/SIEMPRE`,
1086
+ `🚨 If you violate these rules, the commit will be BLOCKED`,
1087
+ `📝 Read the fullRulesContent carefully before generating ANY code`
1088
+ ]
1089
+ };
1090
+ } catch (error) {
1091
+ return {
1092
+ success: false,
1093
+ platform,
1094
+ error: `Failed to load rules: ${error.message}`
1095
+ };
1096
+ }
1097
+ }
1098
+
720
1099
  /**
721
1100
  * Validate and fix common issues
722
1101
  */
@@ -1010,6 +1389,21 @@ async function handleMcpMessage(message) {
1010
1389
  name: 'ai_gate_check',
1011
1390
  description: '🚦 MANDATORY gate check',
1012
1391
  inputSchema: { type: 'object', properties: {} }
1392
+ },
1393
+ {
1394
+ name: 'read_platform_rules',
1395
+ description: '📚 MANDATORY: Read platform-specific rules BEFORE any code generation. Returns critical rules that AI MUST follow.',
1396
+ inputSchema: {
1397
+ type: 'object',
1398
+ properties: {
1399
+ platform: {
1400
+ type: 'string',
1401
+ enum: ['ios', 'android', 'backend', 'frontend'],
1402
+ description: 'Platform to load rules for'
1403
+ }
1404
+ },
1405
+ required: ['platform']
1406
+ }
1013
1407
  }
1014
1408
  ]
1015
1409
  }
@@ -1043,6 +1437,9 @@ async function handleMcpMessage(message) {
1043
1437
  case 'ai_gate_check':
1044
1438
  result = await aiGateCheck();
1045
1439
  break;
1440
+ case 'read_platform_rules':
1441
+ result = await readPlatformRulesHandler(toolParams);
1442
+ break;
1046
1443
  default:
1047
1444
  return {
1048
1445
  jsonrpc: '2.0',
@@ -11,22 +11,6 @@ describe('intelligent-audit', () => {
11
11
  const mod = require('../intelligent-audit');
12
12
  expect(typeof mod.runIntelligentAudit).toBe('function');
13
13
  });
14
-
15
- it('should filter staged violations strictly (no substring matches, no .audit_tmp)', () => {
16
- const mod = require('../intelligent-audit');
17
-
18
- expect(typeof mod.isViolationInStagedFiles).toBe('function');
19
-
20
- const stagedSet = new Set([
21
- 'apps/ios/Application/AppCoordinator.swift'
22
- ]);
23
-
24
- expect(mod.isViolationInStagedFiles('apps/ios/Application/AppCoordinator.swift', stagedSet)).toBe(true);
25
- expect(mod.isViolationInStagedFiles('apps/ios/Application/AppCoordinator.swift.backup', stagedSet)).toBe(false);
26
- expect(mod.isViolationInStagedFiles('.audit_tmp/AppCoordinator.123.staged.swift', stagedSet)).toBe(false);
27
- expect(mod.isViolationInStagedFiles('some/dir/.audit_tmp/AppCoordinator.123.staged.swift', stagedSet)).toBe(false);
28
- expect(mod.isViolationInStagedFiles('apps/ios/Application/AppCoordinator', stagedSet)).toBe(false);
29
- });
30
14
  });
31
15
 
32
16
  describe('AI_EVIDENCE.json structure validation', () => {
@@ -235,28 +235,6 @@ function toRepoRelativePath(filePath) {
235
235
  return normalized;
236
236
  }
237
237
 
238
- function isAuditTmpPath(repoRelativePath) {
239
- const normalized = normalizePathForMatch(repoRelativePath);
240
- return normalized.startsWith('.audit_tmp/') || normalized.includes('/.audit_tmp/');
241
- }
242
-
243
- function isViolationInStagedFiles(violationPath, stagedSet) {
244
- if (!violationPath) {
245
- return false;
246
- }
247
-
248
- const repoRelative = toRepoRelativePath(violationPath);
249
- if (!repoRelative) {
250
- return false;
251
- }
252
-
253
- if (isAuditTmpPath(repoRelative)) {
254
- return false;
255
- }
256
-
257
- return stagedSet.has(repoRelative);
258
- }
259
-
260
238
  function resolveAuditTmpDir() {
261
239
  const configured = (env.get('AUDIT_TMP', '') || '').trim();
262
240
  if (configured.length > 0) {
@@ -295,7 +273,18 @@ async function runIntelligentAudit() {
295
273
 
296
274
  const stagedViolations = rawViolations.filter(v => {
297
275
  const violationPath = toRepoRelativePath(v.filePath || v.file || '');
298
- return isViolationInStagedFiles(violationPath, stagedSet);
276
+ if (!violationPath) {
277
+ return false;
278
+ }
279
+ if (stagedSet.has(violationPath)) {
280
+ return true;
281
+ }
282
+ for (const sf of stagedSet) {
283
+ if (sf && (violationPath === sf || violationPath.endsWith('/' + sf) || violationPath.includes('/' + sf))) {
284
+ return true;
285
+ }
286
+ }
287
+ return false;
299
288
  });
300
289
 
301
290
  console.log(`[Intelligent Audit] Gate scope: STAGING (${stagedFiles.length} files)`);
@@ -561,7 +550,7 @@ async function updateAIEvidence(violations, gateResult, tokenUsage) {
561
550
  file: v.filePath || v.file || 'unknown',
562
551
  line: v.line || null,
563
552
  severity: v.severity,
564
- rule_id: ruleId,
553
+ rule: ruleId,
565
554
  message: v.message || v.description || '',
566
555
  category: v.category || deriveCategoryFromRuleId(ruleId),
567
556
  intelligent_evaluation: v.intelligentEvaluation || false,
@@ -694,4 +683,4 @@ if (require.main === module) {
694
683
  });
695
684
  }
696
685
 
697
- module.exports = { runIntelligentAudit, isViolationInStagedFiles, toRepoRelativePath };
686
+ module.exports = { runIntelligentAudit };