pumuki-ast-hooks 5.5.3 → 5.5.4

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 (80) hide show
  1. package/package.json +2 -2
  2. package/scripts/hooks-system/.audit-reports/auto-recovery.log +1 -0
  3. package/scripts/hooks-system/.audit-reports/install-wizard.log +4 -0
  4. package/scripts/hooks-system/.audit_tmp/audit.log +0 -0
  5. package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +24 -0
  6. package/scripts/hooks-system/.hook-system/config.json +8 -0
  7. package/scripts/hooks-system/application/CompositionRoot.js +31 -19
  8. package/scripts/hooks-system/application/factories/AdapterFactory.js +6 -6
  9. package/scripts/hooks-system/application/services/PredictiveHookAdvisor.js +0 -2
  10. package/scripts/hooks-system/application/services/RealtimeGuardService.js +146 -2
  11. package/scripts/hooks-system/application/services/SmartDirtyTreeAnalyzer.js +0 -1
  12. package/scripts/hooks-system/application/services/guard/EvidenceManager.js +31 -7
  13. package/scripts/hooks-system/application/services/guard/GitTreeManager.js +43 -11
  14. package/scripts/hooks-system/application/services/guard/GuardNotifier.js +2 -2
  15. package/scripts/hooks-system/application/services/installation/ConfigurationGeneratorService.js +0 -2
  16. package/scripts/hooks-system/application/services/installation/GitEnvironmentService.js +0 -3
  17. package/scripts/hooks-system/application/services/installation/InstallService.js +0 -1
  18. package/scripts/hooks-system/application/services/installation/McpConfigurator.js +9 -2
  19. package/scripts/hooks-system/application/services/logging/UnifiedLogger.js +1 -1
  20. package/scripts/hooks-system/application/services/monitoring/AstMonitor.js +0 -2
  21. package/scripts/hooks-system/application/services/monitoring/DevDocsMonitor.js +0 -2
  22. package/scripts/hooks-system/application/services/monitoring/GitTreeMonitorService.js +0 -3
  23. package/scripts/hooks-system/application/services/notification/NotificationCenterService.js +22 -0
  24. package/scripts/hooks-system/application/services/notification/components/NotificationRetryExecutor.js +1 -1
  25. package/scripts/hooks-system/application/services/recovery/AutoRecoveryManager.js +0 -1
  26. package/scripts/hooks-system/application/services/token/TokenMetricsService.js +1 -1
  27. package/scripts/hooks-system/application/services/token/TokenMonitorService.js +0 -1
  28. package/scripts/hooks-system/application/use-cases/AnalyzeCodebaseUseCase.js +0 -2
  29. package/scripts/hooks-system/application/use-cases/AnalyzeStagedFilesUseCase.js +0 -2
  30. package/scripts/hooks-system/application/use-cases/AutoExecuteAIStartUseCase.js +0 -1
  31. package/scripts/hooks-system/application/use-cases/BlockCommitUseCase.js +0 -2
  32. package/scripts/hooks-system/application/use-cases/GenerateAuditReportUseCase.js +0 -3
  33. package/scripts/hooks-system/bin/cli.js +16 -0
  34. package/scripts/hooks-system/domain/services/AuditResultSerializer.js +0 -5
  35. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidASTIntelligentAnalyzer.js +0 -2
  36. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidASTParser.js +0 -2
  37. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidAnalysisOrchestrator.js +0 -2
  38. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidArchitectureDetector.js +5 -7
  39. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidClassAnalyzer.js +0 -3
  40. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidForbiddenLiteralsAnalyzer.js +0 -1
  41. package/scripts/hooks-system/infrastructure/ast/android/analyzers/AndroidSOLIDAnalyzer.js +0 -2
  42. package/scripts/hooks-system/infrastructure/ast/archive/ios-rules.js +0 -2
  43. package/scripts/hooks-system/infrastructure/ast/archive/kotlin-analyzer.js +0 -2
  44. package/scripts/hooks-system/infrastructure/ast/archive/kotlin-parser.js +0 -2
  45. package/scripts/hooks-system/infrastructure/ast/archive/swift-analyzer.js +0 -2
  46. package/scripts/hooks-system/infrastructure/ast/backend/analyzers/BackendArchitectureDetector.js +0 -2
  47. package/scripts/hooks-system/infrastructure/ast/backend/analyzers/BackendPatternDetector.js +0 -2
  48. package/scripts/hooks-system/infrastructure/ast/common/BDDTDDWorkflowRules.js +0 -2
  49. package/scripts/hooks-system/infrastructure/ast/common/rules/BDDRules.js +0 -2
  50. package/scripts/hooks-system/infrastructure/ast/common/rules/ImplementationRules.js +0 -2
  51. package/scripts/hooks-system/infrastructure/ast/common/rules/TDDRules.js +0 -2
  52. package/scripts/hooks-system/infrastructure/ast/common/rules/WorkflowRules.js +0 -2
  53. package/scripts/hooks-system/infrastructure/ast/frontend/analyzers/FrontendArchitectureDetector.js +14 -16
  54. package/scripts/hooks-system/infrastructure/ast/frontend/analyzers/FrontendForbiddenLiteralsAnalyzer.js +0 -5
  55. package/scripts/hooks-system/infrastructure/ast/frontend/analyzers/FrontendSOLIDAnalyzer.js +0 -2
  56. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSASTIntelligentAnalyzer.js +17 -2
  57. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSArchitectureDetector.js +10 -12
  58. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSArchitectureRules.js +0 -2
  59. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSCICDRules.js +0 -2
  60. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSEnterpriseAnalyzer.js +0 -2
  61. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSForbiddenLiteralsAnalyzer.js +0 -1
  62. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSNetworkingAdvancedRules.js +0 -2
  63. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSPerformanceRules.js +0 -3
  64. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSSPMRules.js +0 -2
  65. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSSwiftUIAdvancedRules.js +0 -2
  66. package/scripts/hooks-system/infrastructure/ast/ios/analyzers/iOSTestingAdvancedRules.js +0 -2
  67. package/scripts/hooks-system/infrastructure/ast/ios/native-bridge.js +0 -1
  68. package/scripts/hooks-system/infrastructure/ast/ios/parsers/SourceKittenParser.js +0 -2
  69. package/scripts/hooks-system/infrastructure/logging/UnifiedLoggerFactory.js +1 -1
  70. package/scripts/hooks-system/infrastructure/mcp/ast-intelligence-automation.js +149 -57
  71. package/scripts/hooks-system/infrastructure/mcp/services/McpProtocolHandler.js +14 -6
  72. package/scripts/hooks-system/infrastructure/repositories/CursorTokenRepository.js +0 -2
  73. package/scripts/hooks-system/infrastructure/repositories/FileFindingsRepository.js +0 -2
  74. package/scripts/hooks-system/infrastructure/repositories/datasources/CursorApiDataSource.js +1 -3
  75. package/scripts/hooks-system/infrastructure/repositories/datasources/CursorFileDataSource.js +0 -2
  76. package/scripts/hooks-system/infrastructure/severity/severity-evaluator.js +0 -2
  77. package/scripts/hooks-system/infrastructure/telemetry/TelemetryService.js +0 -2
  78. package/scripts/hooks-system/infrastructure/utils/token-manager.js +0 -2
  79. package/scripts/hooks-system/infrastructure/validators/enforce-english-literals.js +1 -1
  80. package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +6 -0
@@ -1,14 +1,12 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const glob = require('glob');
4
- const AuditLogger = require('../../application/services/logging/AuditLogger');
5
4
 
6
5
  class iOSArchitectureDetector {
7
6
  constructor(projectRoot) {
8
7
  this.projectRoot = projectRoot;
9
- this.auditLogger = new AuditLogger({ repoRoot: projectRoot });
10
8
  this.patterns = {
11
- featureFirstClean: 0,
9
+ featureFirstClean: 0,
12
10
  mvvm: 0,
13
11
  mvvmc: 0,
14
12
  mvp: 0,
@@ -83,7 +81,7 @@ class iOSArchitectureDetector {
83
81
  );
84
82
 
85
83
  if (hasFeaturesFolders) {
86
- this.patterns.featureFirstClean += 10;
84
+ this.patterns.featureFirstClean += 10;
87
85
  }
88
86
 
89
87
  if (foundCleanFolders.length >= 3) {
@@ -249,8 +247,8 @@ class iOSArchitectureDetector {
249
247
  const content = this.readFile(file);
250
248
 
251
249
  if (content.includes('protocol Coordinator') ||
252
- content.includes(': Coordinator') ||
253
- /func\s+start\(\)/.test(content) && /func\s+navigate/.test(content)) {
250
+ content.includes(': Coordinator') ||
251
+ /func\s+start\(\)/.test(content) && /func\s+navigate/.test(content)) {
254
252
  this.patterns.mvvmc += 2;
255
253
  }
256
254
  });
@@ -290,16 +288,16 @@ class iOSArchitectureDetector {
290
288
  const interactorFiles = files.filter(f => /Interactor\.swift$/.test(f));
291
289
 
292
290
  if (viewControllerFiles.length >= 2 &&
293
- viewModelFiles.length === 0 &&
294
- presenterFiles.length === 0 &&
295
- interactorFiles.length === 0) {
291
+ viewModelFiles.length === 0 &&
292
+ presenterFiles.length === 0 &&
293
+ interactorFiles.length === 0) {
296
294
 
297
295
  viewControllerFiles.forEach(file => {
298
296
  const content = this.readFile(file);
299
297
  const lines = content.split('\n').length;
300
298
 
301
299
  if (lines > 300) {
302
- this.patterns.mvc += 3;
300
+ this.patterns.mvc += 3;
303
301
  } else if (lines > 150) {
304
302
  this.patterns.mvc += 2;
305
303
  } else {
@@ -325,7 +323,7 @@ class iOSArchitectureDetector {
325
323
  }
326
324
 
327
325
  if (sorted.length > 1 && sorted[1][1] >= dominantScore * 0.7) {
328
- return 'MIXED';
326
+ return 'MIXED';
329
327
  }
330
328
 
331
329
  return this.normalizePatternName(dominant);
@@ -333,7 +331,7 @@ class iOSArchitectureDetector {
333
331
 
334
332
  normalizePatternName(pattern) {
335
333
  const mapping = {
336
- 'featureFirstClean': 'FEATURE_FIRST_CLEAN_DDD',
334
+ 'featureFirstClean': 'FEATURE_FIRST_CLEAN_DDD',
337
335
  'mvvm': 'MVVM',
338
336
  'mvvmc': 'MVVM-C',
339
337
  'mvp': 'MVP',
@@ -1,11 +1,9 @@
1
1
  const { pushFinding } = require('../../ast-core');
2
- const AuditLogger = require('../../application/services/logging/AuditLogger');
3
2
 
4
3
  class iOSArchitectureRules {
5
4
  constructor(findings, detectedPattern) {
6
5
  this.findings = findings;
7
6
  this.pattern = detectedPattern;
8
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
9
7
  }
10
8
 
11
9
  runRules(files) {
@@ -12,13 +12,11 @@ const { pushFinding } = require('../../ast-core');
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
14
  const glob = require('glob');
15
- const AuditLogger = require('../../application/services/logging/AuditLogger');
16
15
 
17
16
  class iOSCICDRules {
18
17
  constructor(findings, projectRoot) {
19
18
  this.findings = findings;
20
19
  this.projectRoot = projectRoot;
21
- this.auditLogger = new AuditLogger({ repoRoot: projectRoot });
22
20
  }
23
21
 
24
22
  analyze() {
@@ -2,13 +2,11 @@ const path = require('path');
2
2
  const fs = require('fs').promises;
3
3
  const { SourceKittenParser } = require('../parsers/SourceKittenParser');
4
4
  const { pushFinding, mapToLevel } = require(path.join(__dirname, '../../ast-core'));
5
- const AuditLogger = require('../../application/services/logging/AuditLogger');
6
5
 
7
6
  class iOSEnterpriseAnalyzer {
8
7
  constructor() {
9
8
  this.parser = new SourceKittenParser();
10
9
  this.findings = [];
11
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
12
10
  }
13
11
 
14
12
  async analyzeFile(filePath, findings) {
@@ -1,5 +1,4 @@
1
1
  const { SyntaxKind } = require('../../ast-core');
2
- const AuditLogger = require('../../application/services/logging/AuditLogger');
3
2
 
4
3
  const FORBIDDEN_STRING_LITERALS = [
5
4
  'unknown',
@@ -9,12 +9,10 @@
9
9
  const { pushFinding } = require('../../ast-core');
10
10
  const fs = require('fs');
11
11
  const glob = require('glob');
12
- const AuditLogger = require('../../application/services/logging/AuditLogger');
13
12
 
14
13
  class iOSNetworkingAdvancedRules {
15
14
  constructor(findings, projectRoot) {
16
15
  this.findings = findings;
17
- this.auditLogger = new AuditLogger({ repoRoot: projectRoot });
18
16
  this.projectRoot = projectRoot;
19
17
  }
20
18
 
@@ -1,9 +1,6 @@
1
- const AuditLogger = require('../../application/services/logging/AuditLogger');
2
-
3
1
  class iOSPerformanceRules {
4
2
  constructor(findings) {
5
3
  this.findings = findings;
6
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
7
4
  }
8
5
 
9
6
  analyzeFile(filePath, content) {
@@ -13,13 +13,11 @@
13
13
  const { pushFinding } = require('../../ast-core');
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
- const AuditLogger = require('../../application/services/logging/AuditLogger');
17
16
 
18
17
  class iOSSPMRules {
19
18
  constructor(findings, projectRoot) {
20
19
  this.findings = findings;
21
20
  this.projectRoot = projectRoot;
22
- this.auditLogger = new AuditLogger({ repoRoot: projectRoot });
23
21
  }
24
22
 
25
23
  analyze() {
@@ -12,12 +12,10 @@
12
12
 
13
13
  const { pushFinding } = require('../../ast-core');
14
14
  const fs = require('fs');
15
- const AuditLogger = require('../../application/services/logging/AuditLogger');
16
15
 
17
16
  class iOSSwiftUIAdvancedRules {
18
17
  constructor(findings) {
19
18
  this.findings = findings;
20
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
21
19
  }
22
20
 
23
21
  analyzeFile(filePath, ast) {
@@ -10,12 +10,10 @@ const { pushFinding } = require('../../ast-core');
10
10
  const fs = require('fs');
11
11
  const glob = require('glob');
12
12
  const path = require('path');
13
- const AuditLogger = require('../../application/services/logging/AuditLogger');
14
13
 
15
14
  class iOSTestingAdvancedRules {
16
15
  constructor(findings, projectRoot) {
17
16
  this.findings = findings;
18
- this.auditLogger = new AuditLogger({ repoRoot: projectRoot });
19
17
  this.projectRoot = projectRoot;
20
18
  }
21
19
 
@@ -3,7 +3,6 @@ const path = require('path');
3
3
  const fs = require('fs');
4
4
  const { pushFileFinding } = require('../ast-core');
5
5
  const env = require(path.join(__dirname, '../../../config/env'));
6
- const AuditLogger = require('../../application/services/logging/AuditLogger');
7
6
 
8
7
  function getStagedSwiftFiles(repoRoot) {
9
8
  try {
@@ -5,7 +5,6 @@ const util = require('util');
5
5
  const fs = require('fs').promises;
6
6
  const path = require('path');
7
7
  const { DomainError } = require('../../../../domain/errors');
8
- const AuditLogger = require('../../../../application/services/logging/AuditLogger');
9
8
 
10
9
  const execPromise = util.promisify(exec);
11
10
 
@@ -21,7 +20,6 @@ class SourceKittenParser {
21
20
  constructor() {
22
21
  this.sourceKittenPath = '/opt/homebrew/bin/sourcekitten';
23
22
  this.timeout = 30000;
24
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
25
23
  }
26
24
 
27
25
  /**
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const env = require('../../../config/env.js');
3
+ const env = require('../../config/env.js');
4
4
 
5
5
  const UnifiedLogger = require('../../application/services/logging/UnifiedLogger');
6
6
 
@@ -38,7 +38,10 @@ function safeGitRoot(startDir) {
38
38
  });
39
39
  const root = String(out || '').trim();
40
40
  return root || null;
41
- } catch {
41
+ } catch (error) {
42
+ if (process.env.DEBUG) {
43
+ process.stderr.write(`[MCP] safeGitRoot failed: ${error && error.message ? error.message : String(error)}\n`);
44
+ }
42
45
  return null;
43
46
  }
44
47
  }
@@ -54,6 +57,16 @@ function resolveRepoRoot() {
54
57
 
55
58
  const REPO_ROOT = resolveRepoRoot();
56
59
 
60
+ try {
61
+ if (REPO_ROOT && typeof REPO_ROOT === 'string' && fs.existsSync(REPO_ROOT)) {
62
+ process.chdir(REPO_ROOT);
63
+ }
64
+ } catch (error) {
65
+ if (process.env.DEBUG) {
66
+ process.stderr.write(`[MCP] Failed to chdir to REPO_ROOT: ${error && error.message ? error.message : String(error)}\n`);
67
+ }
68
+ }
69
+
57
70
  // NO singleton lock - Windsurf manages process lifecycle
58
71
  // Each project gets its own independent MCP process
59
72
 
@@ -186,6 +199,34 @@ function resolveUpdateEvidenceScript() {
186
199
  return null;
187
200
  }
188
201
 
202
+ async function runWithTimeout(fn, timeoutMs) {
203
+ const ms = Number(timeoutMs);
204
+ if (!Number.isFinite(ms) || ms <= 0) {
205
+ try {
206
+ return { ok: true, timedOut: false, value: await fn() };
207
+ } catch (error) {
208
+ return { ok: false, timedOut: false, error };
209
+ }
210
+ }
211
+
212
+ let timer = null;
213
+ try {
214
+ const result = await Promise.race([
215
+ Promise.resolve().then(fn).then(value => ({ ok: true, timedOut: false, value })),
216
+ new Promise(resolve => {
217
+ timer = setTimeout(() => resolve({ ok: false, timedOut: true, error: new Error('timeout') }), ms);
218
+ })
219
+ ]);
220
+ return result;
221
+ } catch (error) {
222
+ return { ok: false, timedOut: false, error };
223
+ } finally {
224
+ if (timer) {
225
+ clearTimeout(timer);
226
+ }
227
+ }
228
+ }
229
+
189
230
  // Lazy Loading Services
190
231
  function getContextEngine() {
191
232
  return getCompositionRoot().getContextDetectionEngine();
@@ -537,75 +578,123 @@ function checkBranchChangesCoherence(branchName, uncommittedChanges) {
537
578
  * Returns BLOCKED or ALLOWED status with auto-fixes applied
538
579
  */
539
580
  async function aiGateCheck() {
540
- const gitFlowService = getCompositionRoot().getGitFlowService();
541
- const gitQuery = getCompositionRoot().getGitQueryAdapter();
542
- const currentBranch = getCurrentGitBranch(REPO_ROOT);
543
- const isProtectedBranch = ['main', 'master', 'develop'].includes(currentBranch);
581
+ const startedAt = Date.now();
582
+ const gateTimeoutMs = Number(process.env.MCP_GATE_TIMEOUT_MS || 1200);
583
+ const strict = process.env.MCP_GATE_STRICT === 'true';
584
+ const allowEvidenceAutofix = process.env.MCP_GATE_AUTOFIX_EVIDENCE === 'true';
585
+
586
+ const core = async () => {
587
+ const gitFlowService = getCompositionRoot().getGitFlowService();
588
+ const gitQuery = getCompositionRoot().getGitQueryAdapter();
589
+ const currentBranch = getCurrentGitBranch(REPO_ROOT);
590
+ const isProtectedBranch = ['main', 'master', 'develop'].includes(currentBranch);
544
591
 
545
- const uncommittedChanges = gitQuery.getUncommittedChanges();
546
- const hasUncommittedChanges = uncommittedChanges && uncommittedChanges.length > 0;
592
+ let uncommittedChanges = [];
593
+ try {
594
+ uncommittedChanges = gitQuery.getUncommittedChanges();
595
+ } catch (error) {
596
+ const msg = error && error.message ? error.message : String(error);
597
+ if (process.env.DEBUG) {
598
+ process.stderr.write(`[MCP] Gate gitQuery.getUncommittedChanges failed: ${msg}\n`);
599
+ }
600
+ }
601
+ const hasUncommittedChanges = Array.isArray(uncommittedChanges) && uncommittedChanges.length > 0;
547
602
 
548
- const violations = [];
549
- const warnings = [];
550
- const autoFixes = [];
603
+ const violations = [];
604
+ const warnings = [];
605
+ const autoFixes = [];
606
+
607
+ const evidenceMonitor = getCompositionRoot().getEvidenceMonitor();
608
+ if (evidenceMonitor.isStale()) {
609
+ if (!allowEvidenceAutofix) {
610
+ violations.push('❌ EVIDENCE_STALE: Evidence is stale. Run ai-start to refresh.');
611
+ } else {
612
+ const elapsed = Date.now() - startedAt;
613
+ const remaining = Math.max(150, gateTimeoutMs - elapsed);
614
+ const refreshResult = await runWithTimeout(() => evidenceMonitor.refresh(), remaining);
615
+ if (refreshResult.ok) {
616
+ autoFixes.push('✅ Evidence was stale - AUTO-FIXED');
617
+ } else if (refreshResult.timedOut) {
618
+ violations.push('❌ EVIDENCE_STALE: Auto-fix timed out. Run ai-start to refresh.');
619
+ } else {
620
+ const msg = refreshResult.error && refreshResult.error.message ? refreshResult.error.message : String(refreshResult.error);
621
+ violations.push(`❌ EVIDENCE_STALE: Auto-fix failed: ${msg}`);
622
+ }
623
+ }
624
+ }
551
625
 
552
- // 1. Evidence Freshness Check (Auto-fix included)
553
- const evidenceMonitor = getCompositionRoot().getEvidenceMonitor();
554
- if (evidenceMonitor.isStale()) {
555
626
  try {
556
- await evidenceMonitor.refresh();
557
- autoFixes.push('✅ Evidence was stale - AUTO-FIXED');
558
- } catch (err) {
559
- violations.push(`❌ EVIDENCE_STALE: Auto-fix failed: ${err.message}`);
627
+ const elapsed = Date.now() - startedAt;
628
+ const remaining = Math.max(120, gateTimeoutMs - elapsed);
629
+ const ghAvailable = await runWithTimeout(() => gitFlowService.isGitHubAvailable(), remaining);
630
+ if (!ghAvailable.ok || ghAvailable.timedOut || ghAvailable.value === false) {
631
+ warnings.push('⚠️ GitHub CLI not available - some automations may be limited');
632
+ }
633
+ } catch (error) {
634
+ warnings.push('⚠️ GitHub CLI not available - some automations may be limited');
560
635
  }
561
- }
562
636
 
563
- // 2. Git Flow Integrity
564
- if (!gitFlowService.isGitHubAvailable()) {
565
- warnings.push('⚠️ GitHub CLI not available - some automations may be limited');
566
- }
637
+ if (isProtectedBranch) {
638
+ if (hasUncommittedChanges) {
639
+ violations.push(`❌ ON_PROTECTED_BRANCH: You are on '${currentBranch}' with uncommitted changes.`);
640
+ violations.push(` Required: create a feature branch first.`);
641
+ } else {
642
+ warnings.push(`⚠️ ON_PROTECTED_BRANCH: You are on '${currentBranch}'. Create a feature branch before making changes.`);
643
+ }
644
+ }
567
645
 
568
- if (isProtectedBranch) {
569
- if (hasUncommittedChanges) {
570
- violations.push(`❌ ON_PROTECTED_BRANCH: You are on '${currentBranch}' with uncommitted changes.`);
571
- violations.push(` Required: create a feature branch first.`);
572
- } else {
573
- warnings.push(`⚠️ ON_PROTECTED_BRANCH: You are on '${currentBranch}'. Create a feature branch before making changes.`);
646
+ if (strict) {
647
+ const elapsed = Date.now() - startedAt;
648
+ const remaining = Math.max(200, gateTimeoutMs - elapsed);
649
+ const blockCommitUseCase = getCompositionRoot().getBlockCommitUseCase();
650
+ const astAdapter = getCompositionRoot().getAstAdapter();
651
+
652
+ const astResult = await runWithTimeout(async () => {
653
+ const auditResult = await astAdapter.analyzeStagedFiles();
654
+ return blockCommitUseCase.execute(auditResult, { useStagedOnly: true });
655
+ }, remaining);
656
+
657
+ if (astResult.ok && astResult.value && astResult.value.shouldBlock) {
658
+ violations.push(`❌ AST_VIOLATIONS: ${astResult.value.reason}`);
659
+ } else if (!astResult.ok && process.env.DEBUG) {
660
+ const msg = astResult.error && astResult.error.message ? astResult.error.message : String(astResult.error);
661
+ process.stderr.write(`[MCP] Gate AST check skipped: ${astResult.timedOut ? 'timeout' : msg}\n`);
662
+ }
574
663
  }
575
- }
576
664
 
577
- // 3. Block Commit Use Case Integration
578
- const blockCommitUseCase = getCompositionRoot().getBlockCommitUseCase();
579
- const astAdapter = getCompositionRoot().getAstAdapter();
665
+ const isBlocked = violations.length > 0;
580
666
 
581
- try {
582
- const auditResult = await astAdapter.analyzeStagedFiles();
583
- const decision = await blockCommitUseCase.execute(auditResult, {
584
- useStagedOnly: true
585
- });
667
+ return {
668
+ status: isBlocked ? 'BLOCKED' : 'ALLOWED',
669
+ timestamp: new Date().toISOString(),
670
+ branch: currentBranch,
671
+ violations,
672
+ warnings,
673
+ autoFixes,
674
+ summary: isBlocked
675
+ ? `🚫 BLOCKED: ${violations.length} violation(s). Fix before proceeding.`
676
+ : `🚦 ALLOWED: Gate passed.${warnings.length > 0 ? ` ${warnings.length} warning(s).` : ''}`,
677
+ instructions: isBlocked
678
+ ? 'DO NOT proceed with user task. Announce violations and fix them first.'
679
+ : 'You may proceed with user task.'
680
+ };
681
+ };
586
682
 
587
- if (decision.shouldBlock) {
588
- violations.push(`❌ AST_VIOLATIONS: ${decision.reason}`);
589
- }
590
- } catch (err) {
591
- if (process.env.DEBUG) console.error('[MCP] AST Check failed:', err.message);
683
+ const result = await runWithTimeout(core, gateTimeoutMs);
684
+ if (result.ok) {
685
+ return result.value;
592
686
  }
593
687
 
594
- const isBlocked = violations.length > 0;
595
-
688
+ const currentBranch = getCurrentGitBranch(REPO_ROOT);
596
689
  return {
597
- status: isBlocked ? 'BLOCKED' : 'ALLOWED',
690
+ status: 'BLOCKED',
598
691
  timestamp: new Date().toISOString(),
599
692
  branch: currentBranch,
600
- violations,
601
- warnings,
602
- autoFixes,
603
- summary: isBlocked
604
- ? `🚫 BLOCKED: ${violations.length} violation(s). Fix before proceeding.`
605
- : `🚦 ALLOWED: Gate passed.${warnings.length > 0 ? ` ${warnings.length} warning(s).` : ''}`,
606
- instructions: isBlocked
607
- ? 'DO NOT proceed with user task. Announce violations and fix them first.'
608
- : 'You may proceed with user task.'
693
+ violations: ['❌ GATE_TIMEOUT: AI gate check timed out. Retry or run ai-start manually.'],
694
+ warnings: [],
695
+ autoFixes: [],
696
+ summary: '🚫 BLOCKED: Gate check timed out.',
697
+ instructions: 'DO NOT proceed with user task. Retry the gate check.'
609
698
  };
610
699
  }
611
700
 
@@ -977,15 +1066,18 @@ protocolHandler.start(async (message) => {
977
1066
  // Start polling loops ONLY after receiving 'initialized' notification from Windsurf
978
1067
  if (!mcpInitialized && message.includes('"method":"initialized"')) {
979
1068
  mcpInitialized = true;
980
- process.stderr.write(`[MCP] Received 'initialized' - starting background loops\n`);
1069
+ if (process.env.DEBUG) {
1070
+ process.stderr.write(`[MCP] Received 'initialized' - starting background loops\n`);
1071
+ }
981
1072
  startPollingLoops();
982
1073
  }
983
1074
 
984
1075
  return response;
985
1076
  });
986
1077
 
987
- // Log MCP ready
988
- process.stderr.write(`[MCP] Server ready for ${REPO_ROOT}\n`);
1078
+ if (process.env.DEBUG) {
1079
+ process.stderr.write(`[MCP] Server ready for ${REPO_ROOT}\n`);
1080
+ }
989
1081
 
990
1082
  /**
991
1083
  * Start polling loops for background notifications and automations
@@ -1,18 +1,21 @@
1
1
  const MCP_VERSION = '2024-11-05';
2
2
  const AuditLogger = require('../../../application/services/logging/AuditLogger');
3
+ const env = require('../../../config/env');
3
4
 
4
5
  class McpProtocolHandler {
5
6
  constructor(inputStream, outputStream, logger) {
6
7
  this.inputStream = inputStream;
7
8
  this.outputStream = outputStream;
8
9
  this.logger = logger;
9
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd(), logger });
10
+ const repoRoot = (env.get('REPO_ROOT') || '').trim() || process.cwd();
11
+ this.auditLogger = new AuditLogger({ repoRoot, logger });
10
12
  this.buffer = Buffer.alloc(0);
11
13
  }
12
14
 
13
15
  start(messageHandler) {
14
- // Log that we're starting
15
- process.stderr.write('[MCP] Protocol handler starting...\n');
16
+ if (process.env.DEBUG) {
17
+ process.stderr.write('[MCP] Protocol handler starting...\n');
18
+ }
16
19
 
17
20
  this.inputStream.on('data', (chunk) => {
18
21
  const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk), 'utf8');
@@ -29,8 +32,9 @@ class McpProtocolHandler {
29
32
  process.exit(1);
30
33
  });
31
34
 
32
- // Log that we're ready
33
- process.stderr.write('[MCP] Protocol handler ready\n');
35
+ if (process.env.DEBUG) {
36
+ process.stderr.write('[MCP] Protocol handler ready\n');
37
+ }
34
38
  }
35
39
 
36
40
  async _handleChunk(chunk, messageHandler) {
@@ -115,8 +119,12 @@ class McpProtocolHandler {
115
119
  }
116
120
 
117
121
  const lineBuf = this.buffer.slice(0, nl);
118
- this.buffer = this.buffer.slice(nl + 1);
119
122
  const line = lineBuf.toString('utf8').trim();
123
+ if (/^content-length:/i.test(line)) {
124
+ break;
125
+ }
126
+
127
+ this.buffer = this.buffer.slice(nl + 1);
120
128
  if (line) {
121
129
  messages.push({ body: line, framed: false });
122
130
  }
@@ -1,5 +1,4 @@
1
1
  const env = require('../../config/env');
2
- const AuditLogger = require('../../application/services/logging/AuditLogger');
3
2
 
4
3
  const path = require('path');
5
4
  const ICursorTokenRepository = require('../../domain/repositories/ICursorTokenRepository');
@@ -20,7 +19,6 @@ class CursorTokenRepository extends ICursorTokenRepository {
20
19
  this.apiDataSource = new CursorApiDataSource({ apiUrl, apiToken, fetchImpl, logger });
21
20
  this.fileDataSource = new CursorFileDataSource({ usageFile, logger });
22
21
  this.logger = logger;
23
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd(), logger });
24
22
  }
25
23
 
26
24
  /**
@@ -4,7 +4,6 @@ const path = require('path');
4
4
  const IFindingsRepository = require('../../domain/repositories/IFindingsRepository');
5
5
  const Finding = require('../../domain/entities/Finding');
6
6
  const AuditResult = require('../../domain/entities/AuditResult');
7
- const AuditLogger = require('../../application/services/logging/AuditLogger');
8
7
 
9
8
  class FileFindingsRepository extends IFindingsRepository {
10
9
  constructor(basePath = '.audit_tmp') {
@@ -12,7 +11,6 @@ class FileFindingsRepository extends IFindingsRepository {
12
11
  this.basePath = basePath;
13
12
  this.findingsFile = path.join(basePath, 'findings.json');
14
13
  this.auditResultFile = path.join(basePath, 'audit-result.json');
15
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
16
14
  }
17
15
 
18
16
  async ensureDirectory() {
@@ -1,5 +1,4 @@
1
- const env = require('../../config/env');
2
- const AuditLogger = require('../../application/services/logging/AuditLogger');
1
+ const env = require('../../../config/env.js');
3
2
 
4
3
  const { DomainError } = require('../../../domain/errors');
5
4
 
@@ -14,7 +13,6 @@ class CursorApiDataSource {
14
13
  this.apiToken = apiToken;
15
14
  this.fetch = fetchImpl;
16
15
  this.logger = logger;
17
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd(), logger });
18
16
  this.failureCount = 0;
19
17
  this.failureThreshold = 5;
20
18
  this.circuitOpenUntil = null;
@@ -1,5 +1,4 @@
1
1
  const fs = require('fs');
2
- const AuditLogger = require('../../application/services/logging/AuditLogger');
3
2
 
4
3
  class CursorFileDataSource {
5
4
  constructor({
@@ -10,7 +9,6 @@ class CursorFileDataSource {
10
9
  this.usageFile = usageFile;
11
10
  this.fs = fsModule;
12
11
  this.logger = logger;
13
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd(), logger });
14
12
  }
15
13
 
16
14
  async readUsage() {
@@ -8,7 +8,6 @@ const { ContextBuilder } = require('./context/context-builder');
8
8
  const RecommendationGenerator = require('./generators/RecommendationGenerator');
9
9
  const ContextMultiplier = require('./scorers/ContextMultiplier');
10
10
  const SeverityMapper = require('./mappers/SeverityMapper');
11
- const AuditLogger = require('../../application/services/logging/AuditLogger');
12
11
 
13
12
  /**
14
13
  * Main severity evaluator
@@ -23,7 +22,6 @@ class SeverityEvaluator {
23
22
  this.contextBuilder = new ContextBuilder();
24
23
  this.recommendationGenerator = new RecommendationGenerator();
25
24
  this.contextMultiplier = new ContextMultiplier();
26
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
27
25
 
28
26
  this.weights = {
29
27
  security: 0.40,
@@ -1,11 +1,9 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const AuditLogger = require('../../application/services/logging/AuditLogger');
4
3
 
5
4
  class TelemetryService {
6
5
  constructor(repoRoot) {
7
6
  this.repoRoot = repoRoot || process.cwd();
8
- this.auditLogger = new AuditLogger({ repoRoot: this.repoRoot });
9
7
  this.logFile = path.join(this.repoRoot, '.audit_tmp/autonomous-decisions.jsonl');
10
8
  this.thresholds = {
11
9
  autoExecute: 90,
@@ -1,12 +1,10 @@
1
1
 
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
- const AuditLogger = require('../../application/services/logging/AuditLogger');
5
4
 
6
5
  class TokenManager {
7
6
  constructor() {
8
7
  this.limit = 1000000;
9
- this.auditLogger = new AuditLogger({ repoRoot: process.cwd() });
10
8
  this.warningThresholds = [
11
9
  { percent: 75, level: 'INFO' },
12
10
  { percent: 85, level: 'WARNING' },
@@ -4,7 +4,7 @@
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
  const { execSync } = require('child_process');
7
- const env = require('../../../config/env.js');
7
+ const env = require('../../config/env.js');
8
8
 
9
9
  const REPO_ROOT = env.get('HOOK_GUARD_REPO_ROOT', process.cwd());
10
10
  const CONFIG_PATH = path.join(REPO_ROOT, 'scripts', 'hooks-system', 'config', 'language-guard.json');