pumuki-ast-hooks 6.0.13 → 6.0.16

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/README.md CHANGED
@@ -451,6 +451,33 @@ npm run ast:refresh
451
451
 
452
452
  ---
453
453
 
454
+ ## 10. Rule Exclusions (`ast-exclusions.json`)
455
+
456
+ Use `config/ast-exclusions.json` to suppress specific rules for specific files.
457
+
458
+ Example:
459
+
460
+ ```json
461
+ {
462
+ "exclusions": {
463
+ "rules": {
464
+ "ios.solid.dip.concrete_dependency": {
465
+ "files": [
466
+ "apps/ios/Infrastructure/Repositories/Auth/AuthLoginRepositoryImpl.swift"
467
+ ],
468
+ "excludePatterns": [
469
+ "**/*Auth*Repository*.swift"
470
+ ]
471
+ }
472
+ }
473
+ }
474
+ }
475
+ ```
476
+
477
+ Rules without `files`/`paths`/`globs` are treated as global exclusions.
478
+
479
+ ---
480
+
454
481
  ## 11. Typical Enterprise Use Cases
455
482
 
456
483
  - Long‑running feature development with AI assistance.
@@ -1,3 +1,47 @@
1
+ # Release Notes - v6.0.16
2
+
3
+ **Release Date**: January 13, 2026
4
+ **Type**: Patch Release
5
+ **Compatibility**: Fully backward compatible with 6.0.x
6
+
7
+ ---
8
+
9
+ ## ✅ Fixes
10
+
11
+ - **Exclude patterns**: `excludePatterns` now prevent unintended global exclusions in intelligent-audit.
12
+
13
+ ---
14
+
15
+ # Release Notes - v6.0.15
16
+
17
+ **Release Date**: January 13, 2026
18
+ **Type**: Patch Release
19
+ **Compatibility**: Fully backward compatible with 6.0.x
20
+
21
+ ---
22
+
23
+ ## ✅ Fixes
24
+
25
+ - **Exclusions-aware gate**: `ast-exclusions.json` filters violations for gate/evidence in intelligent-audit.
26
+ - **iOS DIP generics**: `any` generic constraint names now match normalized bounds.
27
+ - **iOS AST exclusions**: rule exclusions are applied per file in the iOS analyzer.
28
+
29
+ ---
30
+
31
+ # Release Notes - v6.0.14
32
+
33
+ **Release Date**: January 13, 2026
34
+ **Type**: Patch Release
35
+ **Compatibility**: Fully backward compatible with 6.0.x
36
+
37
+ ---
38
+
39
+ ## ✅ Fixes
40
+
41
+ - **iOS DIP detector**: `UseCase`/`Repository` protocol-like types are never treated as concrete.
42
+
43
+ ---
44
+
1
45
  # Release Notes - v6.0.13
2
46
 
3
47
  **Release Date**: January 13, 2026
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki-ast-hooks",
3
- "version": "6.0.13",
3
+ "version": "6.0.16",
4
4
  "description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -20,3 +20,6 @@
20
20
  {"timestamp":"2026-01-12T23:36:15.876Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
21
21
  {"timestamp":"2026-01-13T00:00:36.969Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
22
22
  {"timestamp":"2026-01-13T07:51:05.490Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
23
+ {"timestamp":"2026-01-13T11:12:40.853Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
24
+ {"timestamp":"2026-01-13T11:21:28.037Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
25
+ {"timestamp":"2026-01-13T11:31:00.351Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
@@ -90,3 +90,15 @@
90
90
  {"timestamp":"2026-01-13T07:51:05.577Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
91
91
  {"timestamp":"2026-01-13T07:51:05.577Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
92
92
  {"timestamp":"2026-01-13T07:51:05.577Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
93
+ {"timestamp":"2026-01-13T11:12:40.975Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
94
+ {"timestamp":"2026-01-13T11:12:40.983Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
95
+ {"timestamp":"2026-01-13T11:12:40.983Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
96
+ {"timestamp":"2026-01-13T11:12:40.983Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
97
+ {"timestamp":"2026-01-13T11:21:28.232Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
98
+ {"timestamp":"2026-01-13T11:21:28.240Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
99
+ {"timestamp":"2026-01-13T11:21:28.240Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
100
+ {"timestamp":"2026-01-13T11:21:28.240Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
101
+ {"timestamp":"2026-01-13T11:31:00.195Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
102
+ {"timestamp":"2026-01-13T11:31:00.203Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
103
+ {"timestamp":"2026-01-13T11:31:00.203Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
104
+ {"timestamp":"2026-01-13T11:31:00.203Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
@@ -794,3 +794,75 @@
794
794
  {"timestamp":1768293907758,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
795
795
  {"timestamp":1768293907758,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
796
796
  {"timestamp":1768293907758,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
797
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
798
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
799
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
800
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
801
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
802
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
803
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
804
+ {"timestamp":1768302760852,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
805
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
806
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
807
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
808
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
809
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
810
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
811
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
812
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
813
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
814
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
815
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
816
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
817
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
818
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
819
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
820
+ {"timestamp":1768302760853,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
821
+ {"timestamp":1768303288034,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
822
+ {"timestamp":1768303288035,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
823
+ {"timestamp":1768303288035,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
824
+ {"timestamp":1768303288035,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
825
+ {"timestamp":1768303288035,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
826
+ {"timestamp":1768303288035,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
827
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
828
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
829
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
830
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
831
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
832
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
833
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
834
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
835
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
836
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
837
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
838
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
839
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
840
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
841
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
842
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
843
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
844
+ {"timestamp":1768303288036,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
845
+ {"timestamp":1768303860349,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
846
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
847
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
848
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
849
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
850
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
851
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
852
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
853
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
854
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
855
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
856
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
857
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
858
+ {"timestamp":1768303860350,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
859
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
860
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
861
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
862
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
863
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
864
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
865
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
866
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
867
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
868
+ {"timestamp":1768303860351,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
@@ -47,6 +47,10 @@ class ConcreteDependencyStrategy extends DIStrategy {
47
47
  return true;
48
48
  }
49
49
 
50
+ if (this._isUseCaseProtocolBound(typename, className, context)) {
51
+ return true;
52
+ }
53
+
50
54
  if (this._isGenericConstraintType(typename, className, context)) {
51
55
  return true;
52
56
  }
@@ -80,27 +84,67 @@ class ConcreteDependencyStrategy extends DIStrategy {
80
84
 
81
85
  const genericClause = match[2];
82
86
  const constraints = genericClause.split(',').map((part) => part.trim());
87
+ const normalizedTypename = this._normalizeTypeName(typename);
83
88
 
84
89
  return constraints.some((constraint) => {
85
90
  const [name, bound] = constraint.split(':').map((value) => value.trim());
86
- return name === typename && bound;
91
+ return this._normalizeTypeName(name) === normalizedTypename && bound;
87
92
  });
88
93
  }
89
94
 
95
+ _isUseCaseProtocolBound(typename, className, context) {
96
+ const content = context?.analyzer?.fileContent || '';
97
+ if (!content) return false;
98
+
99
+ const classPattern = new RegExp(`\\b(class|struct)\\s+${className}\\s*<([^>]+)>`);
100
+ const match = content.match(classPattern);
101
+ if (!match) return false;
102
+
103
+ const genericClause = match[2];
104
+ const constraints = genericClause.split(',').map((part) => part.trim());
105
+ const normalizedTypename = this._normalizeTypeName(typename);
106
+
107
+ for (const constraint of constraints) {
108
+ const [name, bound] = constraint.split(':').map((value) => value.trim());
109
+ if (this._normalizeTypeName(name) !== normalizedTypename || !bound) {
110
+ continue;
111
+ }
112
+
113
+ const normalizedBound = this._normalizeTypeName(bound);
114
+ if (/UseCaseProtocol$/.test(normalizedBound)) {
115
+ return true;
116
+ }
117
+ }
118
+
119
+ return false;
120
+ }
121
+
90
122
  _isConcreteService(typename) {
123
+ const normalized = this._normalizeTypeName(typename);
91
124
  const hasConcretePattern = this.config.concretePatterns.some(pattern =>
92
- new RegExp(pattern).test(typename)
125
+ new RegExp(pattern).test(normalized)
93
126
  );
94
127
 
95
128
  const hasProtocolIndicator = this.config.protocolIndicators.some(indicator =>
96
- typename.includes(indicator)
129
+ normalized.includes(indicator)
97
130
  );
98
131
 
99
- return hasConcretePattern && !hasProtocolIndicator;
132
+ const isLikelyProtocol = /UseCase$|Repository$/.test(normalized) && !/Impl$/.test(normalized);
133
+
134
+ return hasConcretePattern && !hasProtocolIndicator && !isLikelyProtocol;
100
135
  }
101
136
 
102
137
  _isLikelyProtocolType(typename) {
103
- const normalized = typename
138
+ const normalized = this._normalizeTypeName(typename);
139
+
140
+ if (/Impl$/.test(normalized)) {
141
+ return false;
142
+ }
143
+ return /UseCase$|Repository$/.test(normalized);
144
+ }
145
+
146
+ _normalizeTypeName(typename) {
147
+ return typename
104
148
  .replace(/^(any|some)\s+/, '')
105
149
  .replace(/[!?]/g, '')
106
150
  .replace(/<.*>/g, '')
@@ -109,11 +153,6 @@ class ConcreteDependencyStrategy extends DIStrategy {
109
153
  .pop()
110
154
  ?.trim()
111
155
  .replace(/[^A-Za-z0-9_].*$/, '') || typename;
112
-
113
- if (/Impl$/.test(normalized)) {
114
- return false;
115
- }
116
- return /UseCase$|Repository$/.test(normalized);
117
156
  }
118
157
  }
119
158
 
@@ -0,0 +1,32 @@
1
+ const ConcreteDependencyStrategy = require('../ConcreteDependencyStrategy');
2
+
3
+ describe('ConcreteDependencyStrategy', () => {
4
+ it('skips generic constraint when type uses any and bound is UseCaseProtocol', () => {
5
+ const strategy = new ConcreteDependencyStrategy({
6
+ targetClasses: ['Auth'],
7
+ allowedTypes: [],
8
+ protocolIndicators: [],
9
+ concretePatterns: ['^Login$'],
10
+ genericTypePatterns: {
11
+ singleLetter: false,
12
+ camelCase: '^$',
13
+ contextHints: []
14
+ }
15
+ });
16
+
17
+ const context = {
18
+ className: 'AuthLoginRepo',
19
+ filePath: '/tmp/AuthLoginRepo.swift',
20
+ properties: [
21
+ { 'key.typename': 'any Login', 'key.name': 'loginUseCase' }
22
+ ],
23
+ analyzer: {
24
+ fileContent: 'class AuthLoginRepo<Login: LoginUseCaseProtocol> {}'
25
+ }
26
+ };
27
+
28
+ const violations = strategy.detect({}, context);
29
+
30
+ expect(violations).toHaveLength(0);
31
+ });
32
+ });
@@ -28,6 +28,40 @@ class iOSASTIntelligentAnalyzer {
28
28
  this.functions = [];
29
29
  this.properties = [];
30
30
  this.closures = [];
31
+ this.exclusions = this.loadExclusions();
32
+ }
33
+
34
+ loadExclusions() {
35
+ const { getRepoRoot } = require(path.join(__dirname, '../../ast-core'));
36
+ const repoRoot = getRepoRoot();
37
+ const exclusionPath = path.join(repoRoot, 'config', 'ast-exclusions.json');
38
+ try {
39
+ if (!fs.existsSync(exclusionPath)) {
40
+ return {};
41
+ }
42
+ const payload = JSON.parse(fs.readFileSync(exclusionPath, 'utf8'));
43
+ return payload.exclusions || {};
44
+ } catch (error) {
45
+ if (process.env.DEBUG) {
46
+ console.debug(`[iOSASTIntelligentAnalyzer] Failed to load exclusions: ${error.message}`);
47
+ }
48
+ return {};
49
+ }
50
+ }
51
+
52
+ isExcluded(ruleId, filePath) {
53
+ const rules = this.exclusions.rules || {};
54
+ const rule = rules[ruleId];
55
+ if (!rule) return false;
56
+
57
+ const patterns = []
58
+ .concat(rule.files || [])
59
+ .concat(rule.paths || [])
60
+ .concat(rule.globs || []);
61
+
62
+ if (patterns.length === 0) return true;
63
+
64
+ return patterns.some((pattern) => filePath.includes(pattern));
31
65
  }
32
66
 
33
67
  resolveAuditTmpDir(repoRoot) {
@@ -212,6 +246,9 @@ class iOSASTIntelligentAnalyzer {
212
246
 
213
247
 
214
248
  pushFinding(ruleId, severity, filePath, line, message) {
249
+ if (this.isExcluded(ruleId, filePath)) {
250
+ return;
251
+ }
215
252
  this.findings.push({
216
253
  ruleId,
217
254
  severity: severity.toUpperCase(),
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const os = require('os');
3
4
 
4
5
  describe('intelligent-audit', () => {
5
6
  it('should export module', () => {
@@ -60,6 +61,56 @@ describe('intelligent-audit', () => {
60
61
  expect(mod.isViolationInStagedFiles('apps/ios/Application/AppCoordinator', stagedSet)).toBe(false);
61
62
  });
62
63
 
64
+ it('should exclude violations based on ast-exclusions config', () => {
65
+ const mod = require('../intelligent-audit');
66
+
67
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-audit-'));
68
+ const previousCwd = process.cwd();
69
+ try {
70
+ process.chdir(tmpDir);
71
+
72
+ const configDir = path.join(tmpDir, 'config');
73
+ fs.mkdirSync(configDir, { recursive: true });
74
+ fs.writeFileSync(path.join(configDir, 'ast-exclusions.json'), JSON.stringify({
75
+ exclusions: {
76
+ rules: {
77
+ 'ios.solid.dip.concrete_dependency': {
78
+ files: ['apps/ios/Infrastructure/Repositories/Auth/AuthLoginRepositoryImpl.swift']
79
+ },
80
+ 'ios.solid.dip.exclude_patterns': {
81
+ excludePatterns: ['**/*Auth*Repository*.swift']
82
+ }
83
+ }
84
+ }
85
+ }));
86
+
87
+ const exclusions = mod.loadExclusions();
88
+ const violation = {
89
+ ruleId: 'ios.solid.dip.concrete_dependency',
90
+ filePath: 'apps/ios/Infrastructure/Repositories/Auth/AuthLoginRepositoryImpl.swift'
91
+ };
92
+ const otherViolation = {
93
+ ruleId: 'ios.solid.dip.concrete_dependency',
94
+ filePath: 'apps/ios/Infrastructure/Repositories/Auth/AuthLogoutRepositoryImpl.swift'
95
+ };
96
+ const patternViolation = {
97
+ ruleId: 'ios.solid.dip.exclude_patterns',
98
+ filePath: 'apps/ios/Infrastructure/Repositories/Auth/AuthLoginRepositoryImpl.swift'
99
+ };
100
+ const patternOther = {
101
+ ruleId: 'ios.solid.dip.exclude_patterns',
102
+ filePath: 'apps/ios/Infrastructure/Repositories/User/UserRepositoryImpl.swift'
103
+ };
104
+
105
+ expect(mod.isViolationExcluded(violation, exclusions)).toBe(true);
106
+ expect(mod.isViolationExcluded(otherViolation, exclusions)).toBe(false);
107
+ expect(mod.isViolationExcluded(patternViolation, exclusions)).toBe(true);
108
+ expect(mod.isViolationExcluded(patternOther, exclusions)).toBe(false);
109
+ } finally {
110
+ process.chdir(previousCwd);
111
+ }
112
+ });
113
+
63
114
  it('should refresh root timestamp when updating .AI_EVIDENCE.json', async () => {
64
115
  const evidencePath = path.join(process.cwd(), '.AI_EVIDENCE.json');
65
116
  const previous = {
@@ -414,6 +414,56 @@ function resolveAuditTmpDir() {
414
414
  return path.join(process.cwd(), '.audit_tmp');
415
415
  }
416
416
 
417
+ function loadExclusions() {
418
+ const configPath = path.join(process.cwd(), 'config', 'ast-exclusions.json');
419
+ try {
420
+ if (!fs.existsSync(configPath)) {
421
+ return {};
422
+ }
423
+ const payload = JSON.parse(fs.readFileSync(configPath, 'utf8'));
424
+ return payload.exclusions || {};
425
+ } catch (error) {
426
+ if (process.env.DEBUG) {
427
+ console.debug(`[Intelligent Audit] Failed to load exclusions: ${error.message}`);
428
+ }
429
+ return {};
430
+ }
431
+ }
432
+
433
+ function isViolationExcluded(violation, exclusions) {
434
+ const ruleId = violation.ruleId || violation.rule || '';
435
+ if (!ruleId) return false;
436
+
437
+ const rules = exclusions.rules || {};
438
+ const rule = rules[ruleId];
439
+ if (!rule) return false;
440
+
441
+ const files = rule.files || [];
442
+ const paths = rule.paths || [];
443
+ const globs = rule.globs || [];
444
+ const excludeFiles = rule.excludeFiles || [];
445
+ const excludePaths = rule.excludePaths || [];
446
+ const excludePatterns = rule.excludePatterns || [];
447
+
448
+ const hasSelectors = files.length || paths.length || globs.length || excludeFiles.length || excludePaths.length || excludePatterns.length;
449
+ if (!hasSelectors) return true;
450
+
451
+ const filePath = toRepoRelativePath(violation.filePath || violation.file || '');
452
+
453
+ if (files.some((pattern) => filePath.includes(pattern))) return true;
454
+ if (paths.some((pattern) => filePath.includes(pattern))) return true;
455
+ if (globs.some((pattern) => filePath.includes(pattern))) return true;
456
+ if (excludeFiles.some((pattern) => filePath.includes(pattern))) return true;
457
+ if (excludePaths.some((pattern) => filePath.includes(pattern))) return true;
458
+
459
+ for (const pattern of excludePatterns) {
460
+ const regex = new RegExp(pattern.replace(/\*/g, '.*'));
461
+ if (regex.test(filePath)) return true;
462
+ }
463
+
464
+ return false;
465
+ }
466
+
417
467
  /**
418
468
  * Main orchestration function
419
469
  * Called by audit.sh after AST analysis completes
@@ -424,6 +474,11 @@ async function runIntelligentAudit() {
424
474
 
425
475
  const rawViolations = loadRawViolations();
426
476
  console.log(`[Intelligent Audit] Loaded ${rawViolations.length} violations from AST`);
477
+ const exclusions = loadExclusions();
478
+ const filteredViolations = rawViolations.filter(v => !isViolationExcluded(v, exclusions));
479
+ if (filteredViolations.length !== rawViolations.length) {
480
+ console.log(`[Intelligent Audit] Excluded ${rawViolations.length - filteredViolations.length} violations via config`);
481
+ }
427
482
 
428
483
  const autoEvidenceTrigger = String(env.get('AUTO_EVIDENCE_TRIGGER', process.env.AUTO_EVIDENCE_TRIGGER || '') || '').trim().toLowerCase();
429
484
  const isAutoEvidenceRefresh = autoEvidenceTrigger === 'auto';
@@ -436,13 +491,13 @@ async function runIntelligentAudit() {
436
491
 
437
492
  if (isRepoScope) {
438
493
  console.log('[Intelligent Audit] Gate scope: REPOSITORY');
439
- violationsForGate = rawViolations;
440
- violationsForEvidence = rawViolations;
494
+ violationsForGate = filteredViolations;
495
+ violationsForEvidence = filteredViolations;
441
496
  } else {
442
497
  const stagedFiles = getStagedFiles();
443
498
  const stagedSet = new Set((Array.isArray(stagedFiles) ? stagedFiles : []).map(toRepoRelativePath));
444
499
 
445
- const stagedViolations = rawViolations.filter(v => {
500
+ const stagedViolations = filteredViolations.filter(v => {
446
501
  const violationPath = toRepoRelativePath(v.filePath || v.file || '');
447
502
  return isViolationInStagedFiles(violationPath, stagedSet);
448
503
  });
@@ -876,4 +931,12 @@ if (require.main === module) {
876
931
  });
877
932
  }
878
933
 
879
- module.exports = { runIntelligentAudit, isViolationInStagedFiles, toRepoRelativePath, updateAIEvidence, formatLocalTimestamp };
934
+ module.exports = {
935
+ runIntelligentAudit,
936
+ isViolationInStagedFiles,
937
+ toRepoRelativePath,
938
+ updateAIEvidence,
939
+ formatLocalTimestamp,
940
+ loadExclusions,
941
+ isViolationExcluded
942
+ };
@@ -64,3 +64,12 @@
64
64
  {"timestamp":"2026-01-13T07:51:07.491Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
65
65
  {"timestamp":"2026-01-13T07:51:07.492Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
66
66
  {"timestamp":"2026-01-13T07:51:07.493Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
67
+ {"timestamp":"2026-01-13T11:12:42.822Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
68
+ {"timestamp":"2026-01-13T11:12:42.825Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
69
+ {"timestamp":"2026-01-13T11:12:42.826Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
70
+ {"timestamp":"2026-01-13T11:21:29.481Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
71
+ {"timestamp":"2026-01-13T11:21:29.482Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
72
+ {"timestamp":"2026-01-13T11:21:29.482Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
73
+ {"timestamp":"2026-01-13T11:31:02.359Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
74
+ {"timestamp":"2026-01-13T11:31:02.360Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
75
+ {"timestamp":"2026-01-13T11:31:02.360Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}