@eddacraft/anvil-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +14 -0
  2. package/dist/cache/cache-key.d.ts +45 -0
  3. package/dist/cache/cache-key.d.ts.map +1 -0
  4. package/dist/cache/cache-key.js +135 -0
  5. package/dist/cache/index.d.ts +27 -0
  6. package/dist/cache/index.d.ts.map +1 -0
  7. package/dist/cache/index.js +38 -0
  8. package/dist/cache/providers/file-cache.d.ts +63 -0
  9. package/dist/cache/providers/file-cache.d.ts.map +1 -0
  10. package/dist/cache/providers/file-cache.js +369 -0
  11. package/dist/cache/providers/memory-cache.d.ts +52 -0
  12. package/dist/cache/providers/memory-cache.d.ts.map +1 -0
  13. package/dist/cache/providers/memory-cache.js +197 -0
  14. package/dist/cache/providers/null-cache.d.ts +26 -0
  15. package/dist/cache/providers/null-cache.d.ts.map +1 -0
  16. package/dist/cache/providers/null-cache.js +50 -0
  17. package/dist/cache/types.d.ts +114 -0
  18. package/dist/cache/types.d.ts.map +1 -0
  19. package/dist/cache/types.js +4 -0
  20. package/dist/concurrency/agent.d.ts +137 -0
  21. package/dist/concurrency/agent.d.ts.map +1 -0
  22. package/dist/concurrency/agent.js +440 -0
  23. package/dist/concurrency/atomic.d.ts +93 -0
  24. package/dist/concurrency/atomic.d.ts.map +1 -0
  25. package/dist/concurrency/atomic.js +281 -0
  26. package/dist/concurrency/git-agent.d.ts +114 -0
  27. package/dist/concurrency/git-agent.d.ts.map +1 -0
  28. package/dist/concurrency/git-agent.js +313 -0
  29. package/dist/concurrency/index.d.ts +95 -0
  30. package/dist/concurrency/index.d.ts.map +1 -0
  31. package/dist/concurrency/index.js +127 -0
  32. package/dist/concurrency/lock-manager.d.ts +170 -0
  33. package/dist/concurrency/lock-manager.d.ts.map +1 -0
  34. package/dist/concurrency/lock-manager.js +525 -0
  35. package/dist/concurrency/queue-manager.d.ts +166 -0
  36. package/dist/concurrency/queue-manager.d.ts.map +1 -0
  37. package/dist/concurrency/queue-manager.js +442 -0
  38. package/dist/concurrency/types.d.ts +382 -0
  39. package/dist/concurrency/types.d.ts.map +1 -0
  40. package/dist/concurrency/types.js +204 -0
  41. package/dist/export/constraint-collector.d.ts +175 -0
  42. package/dist/export/constraint-collector.d.ts.map +1 -0
  43. package/dist/export/constraint-collector.js +203 -0
  44. package/dist/export/formatters/llms-txt-formatter.d.ts +89 -0
  45. package/dist/export/formatters/llms-txt-formatter.d.ts.map +1 -0
  46. package/dist/export/formatters/llms-txt-formatter.js +249 -0
  47. package/dist/export/formatters/mcp-resource-formatter.d.ts +186 -0
  48. package/dist/export/formatters/mcp-resource-formatter.d.ts.map +1 -0
  49. package/dist/export/formatters/mcp-resource-formatter.js +139 -0
  50. package/dist/export/formatters/prompt-formatter.d.ts +83 -0
  51. package/dist/export/formatters/prompt-formatter.d.ts.map +1 -0
  52. package/dist/export/formatters/prompt-formatter.js +256 -0
  53. package/dist/export/index.d.ts +10 -0
  54. package/dist/export/index.d.ts.map +1 -0
  55. package/dist/export/index.js +9 -0
  56. package/dist/gate/check.interface.d.ts +15 -0
  57. package/dist/gate/check.interface.d.ts.map +1 -0
  58. package/dist/gate/check.interface.js +18 -0
  59. package/dist/gate/checks/antipattern.check.d.ts +27 -0
  60. package/dist/gate/checks/antipattern.check.d.ts.map +1 -0
  61. package/dist/gate/checks/antipattern.check.js +140 -0
  62. package/dist/gate/checks/architecture/circular-detector.d.ts +33 -0
  63. package/dist/gate/checks/architecture/circular-detector.d.ts.map +1 -0
  64. package/dist/gate/checks/architecture/circular-detector.js +71 -0
  65. package/dist/gate/checks/architecture/dependency-analyzer.d.ts +81 -0
  66. package/dist/gate/checks/architecture/dependency-analyzer.d.ts.map +1 -0
  67. package/dist/gate/checks/architecture/dependency-analyzer.js +136 -0
  68. package/dist/gate/checks/architecture/layer-validator.d.ts +75 -0
  69. package/dist/gate/checks/architecture/layer-validator.d.ts.map +1 -0
  70. package/dist/gate/checks/architecture/layer-validator.js +193 -0
  71. package/dist/gate/checks/architecture.check.d.ts +56 -0
  72. package/dist/gate/checks/architecture.check.d.ts.map +1 -0
  73. package/dist/gate/checks/architecture.check.js +394 -0
  74. package/dist/gate/checks/command-safety.check.d.ts +12 -0
  75. package/dist/gate/checks/command-safety.check.d.ts.map +1 -0
  76. package/dist/gate/checks/command-safety.check.js +230 -0
  77. package/dist/gate/checks/coverage.check.d.ts +9 -0
  78. package/dist/gate/checks/coverage.check.d.ts.map +1 -0
  79. package/dist/gate/checks/coverage.check.js +81 -0
  80. package/dist/gate/checks/dependency.check.d.ts +17 -0
  81. package/dist/gate/checks/dependency.check.d.ts.map +1 -0
  82. package/dist/gate/checks/dependency.check.js +342 -0
  83. package/dist/gate/checks/eslint.check.d.ts +14 -0
  84. package/dist/gate/checks/eslint.check.d.ts.map +1 -0
  85. package/dist/gate/checks/eslint.check.js +79 -0
  86. package/dist/gate/checks/policy.check.d.ts +78 -0
  87. package/dist/gate/checks/policy.check.d.ts.map +1 -0
  88. package/dist/gate/checks/policy.check.js +457 -0
  89. package/dist/gate/checks/secret/entropy-detector.d.ts +44 -0
  90. package/dist/gate/checks/secret/entropy-detector.d.ts.map +1 -0
  91. package/dist/gate/checks/secret/entropy-detector.js +76 -0
  92. package/dist/gate/checks/secret/git-scanner.d.ts +36 -0
  93. package/dist/gate/checks/secret/git-scanner.d.ts.map +1 -0
  94. package/dist/gate/checks/secret/git-scanner.js +90 -0
  95. package/dist/gate/checks/secret/secret-patterns.d.ts +42 -0
  96. package/dist/gate/checks/secret/secret-patterns.d.ts.map +1 -0
  97. package/dist/gate/checks/secret/secret-patterns.js +137 -0
  98. package/dist/gate/checks/secret.check.d.ts +56 -0
  99. package/dist/gate/checks/secret.check.d.ts.map +1 -0
  100. package/dist/gate/checks/secret.check.js +245 -0
  101. package/dist/gate/config/command-safety-config.d.ts +5 -0
  102. package/dist/gate/config/command-safety-config.d.ts.map +1 -0
  103. package/dist/gate/config/command-safety-config.js +69 -0
  104. package/dist/gate/config/index.d.ts +2 -0
  105. package/dist/gate/config/index.d.ts.map +1 -0
  106. package/dist/gate/config/index.js +1 -0
  107. package/dist/gate/formatters/command-safety-formatter.d.ts +10 -0
  108. package/dist/gate/formatters/command-safety-formatter.d.ts.map +1 -0
  109. package/dist/gate/formatters/command-safety-formatter.js +64 -0
  110. package/dist/gate/formatters/index.d.ts +2 -0
  111. package/dist/gate/formatters/index.d.ts.map +1 -0
  112. package/dist/gate/formatters/index.js +1 -0
  113. package/dist/gate/gate-config.d.ts +44 -0
  114. package/dist/gate/gate-config.d.ts.map +1 -0
  115. package/dist/gate/gate-config.js +334 -0
  116. package/dist/gate/gate-runner.d.ts +160 -0
  117. package/dist/gate/gate-runner.d.ts.map +1 -0
  118. package/dist/gate/gate-runner.js +531 -0
  119. package/dist/gate/index.d.ts +20 -0
  120. package/dist/gate/index.d.ts.map +1 -0
  121. package/dist/gate/index.js +14 -0
  122. package/dist/gate/parsers/command-parser.d.ts +18 -0
  123. package/dist/gate/parsers/command-parser.d.ts.map +1 -0
  124. package/dist/gate/parsers/command-parser.js +363 -0
  125. package/dist/gate/parsers/index.d.ts +2 -0
  126. package/dist/gate/parsers/index.d.ts.map +1 -0
  127. package/dist/gate/parsers/index.js +1 -0
  128. package/dist/gate/policy/index.d.ts +12 -0
  129. package/dist/gate/policy/index.d.ts.map +1 -0
  130. package/dist/gate/policy/index.js +10 -0
  131. package/dist/gate/rules/default-filesystem-rules.d.ts +3 -0
  132. package/dist/gate/rules/default-filesystem-rules.d.ts.map +1 -0
  133. package/dist/gate/rules/default-filesystem-rules.js +201 -0
  134. package/dist/gate/rules/default-git-rules.d.ts +3 -0
  135. package/dist/gate/rules/default-git-rules.d.ts.map +1 -0
  136. package/dist/gate/rules/default-git-rules.js +192 -0
  137. package/dist/gate/rules/index.d.ts +5 -0
  138. package/dist/gate/rules/index.d.ts.map +1 -0
  139. package/dist/gate/rules/index.js +3 -0
  140. package/dist/gate/rules/rule-matcher.d.ts +27 -0
  141. package/dist/gate/rules/rule-matcher.d.ts.map +1 -0
  142. package/dist/gate/rules/rule-matcher.js +228 -0
  143. package/dist/gate/rules/types.d.ts +250 -0
  144. package/dist/gate/rules/types.d.ts.map +1 -0
  145. package/dist/gate/rules/types.js +1 -0
  146. package/dist/index.d.ts +19 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +35 -0
  149. package/dist/types/gate.types.d.ts +42 -0
  150. package/dist/types/gate.types.d.ts.map +1 -0
  151. package/dist/types/gate.types.js +94 -0
  152. package/dist/watch/debouncer.d.ts +90 -0
  153. package/dist/watch/debouncer.d.ts.map +1 -0
  154. package/dist/watch/debouncer.js +135 -0
  155. package/dist/watch/file-watcher.d.ts +73 -0
  156. package/dist/watch/file-watcher.d.ts.map +1 -0
  157. package/dist/watch/file-watcher.js +121 -0
  158. package/dist/watch/git-status.d.ts +98 -0
  159. package/dist/watch/git-status.d.ts.map +1 -0
  160. package/dist/watch/git-status.js +266 -0
  161. package/dist/watch/index.d.ts +16 -0
  162. package/dist/watch/index.d.ts.map +1 -0
  163. package/dist/watch/index.js +15 -0
  164. package/dist/watch/orchestrator.d.ts +113 -0
  165. package/dist/watch/orchestrator.d.ts.map +1 -0
  166. package/dist/watch/orchestrator.js +409 -0
  167. package/dist/watch/types.d.ts +190 -0
  168. package/dist/watch/types.d.ts.map +1 -0
  169. package/dist/watch/types.js +76 -0
  170. package/package.json +60 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Dependency Analyzer - Wrapper for dependency-cruiser
3
+ *
4
+ * Handles loading and executing dependency-cruiser for architectural analysis.
5
+ */
6
+ /**
7
+ * Violation from dependency-cruiser
8
+ */
9
+ export interface CruiserViolation {
10
+ from: string;
11
+ to: string;
12
+ rule: {
13
+ name: string;
14
+ severity: 'error' | 'warn' | 'info' | 'ignore';
15
+ };
16
+ cycle?: string[];
17
+ comment?: string;
18
+ }
19
+ /**
20
+ * Summary from dependency-cruiser
21
+ */
22
+ export interface CruiserSummary {
23
+ violations: CruiserViolation[];
24
+ error: number;
25
+ warn: number;
26
+ info: number;
27
+ totalCruised: number;
28
+ }
29
+ /**
30
+ * Cruise result from dependency-cruiser
31
+ */
32
+ export interface ICruiseResult {
33
+ summary: CruiserSummary;
34
+ modules: unknown[];
35
+ }
36
+ /**
37
+ * Cruise function type
38
+ */
39
+ export type CruiseFn = (fileAndDirectoryArray: string[], options?: Record<string, unknown>) => Promise<{
40
+ output: ICruiseResult;
41
+ }>;
42
+ /**
43
+ * Result of dependency analysis
44
+ */
45
+ export interface AnalysisResult {
46
+ success: boolean;
47
+ result?: ICruiseResult;
48
+ error?: string;
49
+ skipped?: boolean;
50
+ reason?: string;
51
+ }
52
+ /**
53
+ * Dependency analyzer that wraps dependency-cruiser
54
+ */
55
+ export declare class DependencyAnalyzer {
56
+ private cruiseFn;
57
+ /**
58
+ * Load dependency-cruiser dynamically
59
+ */
60
+ loadCruiser(): Promise<{
61
+ success: boolean;
62
+ error?: string;
63
+ }>;
64
+ /**
65
+ * Check if dependency-cruiser is available
66
+ */
67
+ isAvailable(): boolean;
68
+ /**
69
+ * Load dependency-cruiser configuration
70
+ */
71
+ loadConfig(workspaceRoot: string, configFile: string): Promise<Record<string, unknown> | null>;
72
+ /**
73
+ * Get default cruise options when no config file exists
74
+ */
75
+ getDefaultCruiseOptions(): Record<string, unknown>;
76
+ /**
77
+ * Run dependency analysis
78
+ */
79
+ analyze(filesToCruise: string[], cruiseOptions: Record<string, unknown>): Promise<AnalysisResult>;
80
+ }
81
+ //# sourceMappingURL=dependency-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-analyzer.d.ts","sourceRoot":"","sources":["../../../../src/gate/checks/architecture/dependency-analyzer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;KAChD,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,CACrB,qBAAqB,EAAE,MAAM,EAAE,EAC/B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAyB;IAEzC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBlE;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACG,UAAU,CACd,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAkB1C;;OAEG;IACH,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAkClD;;OAEG;IACG,OAAO,CACX,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,OAAO,CAAC,cAAc,CAAC;CAwC3B"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Dependency Analyzer - Wrapper for dependency-cruiser
3
+ *
4
+ * Handles loading and executing dependency-cruiser for architectural analysis.
5
+ */
6
+ import { existsSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { createDebugger } from '@eddacraft/anvil-core';
9
+ const log = createDebugger('check');
10
+ /**
11
+ * Dependency analyzer that wraps dependency-cruiser
12
+ */
13
+ export class DependencyAnalyzer {
14
+ cruiseFn = null;
15
+ /**
16
+ * Load dependency-cruiser dynamically
17
+ */
18
+ async loadCruiser() {
19
+ log('dependency-analyzer: loading dependency-cruiser');
20
+ try {
21
+ // Dynamic import - dependency-cruiser is an optional peer dependency
22
+ // Using Function constructor to avoid bundler static analysis
23
+ const depCruiser = (await Function('return import("dependency-cruiser")')());
24
+ this.cruiseFn = depCruiser.cruise;
25
+ log('dependency-analyzer: dependency-cruiser loaded successfully');
26
+ return { success: true };
27
+ }
28
+ catch {
29
+ log('dependency-analyzer: dependency-cruiser not installed');
30
+ return {
31
+ success: false,
32
+ error: 'dependency-cruiser not installed',
33
+ };
34
+ }
35
+ }
36
+ /**
37
+ * Check if dependency-cruiser is available
38
+ */
39
+ isAvailable() {
40
+ return this.cruiseFn !== null;
41
+ }
42
+ /**
43
+ * Load dependency-cruiser configuration
44
+ */
45
+ async loadConfig(workspaceRoot, configFile) {
46
+ const configPath = join(workspaceRoot, configFile);
47
+ if (!existsSync(configPath)) {
48
+ log(`dependency-analyzer: config file not found at ${configPath}`);
49
+ return null;
50
+ }
51
+ try {
52
+ const configModule = await import(configPath);
53
+ log(`dependency-analyzer: config loaded from ${configPath}`);
54
+ return configModule.default || configModule;
55
+ }
56
+ catch {
57
+ log(`dependency-analyzer: failed to load config from ${configPath}`);
58
+ return null;
59
+ }
60
+ }
61
+ /**
62
+ * Get default cruise options when no config file exists
63
+ */
64
+ getDefaultCruiseOptions() {
65
+ return {
66
+ validate: true,
67
+ ruleSet: {
68
+ forbidden: [
69
+ {
70
+ name: 'no-circular',
71
+ severity: 'error',
72
+ comment: 'Circular dependencies are not allowed',
73
+ from: {},
74
+ to: {
75
+ circular: true,
76
+ },
77
+ },
78
+ {
79
+ name: 'no-orphans',
80
+ severity: 'warn',
81
+ comment: 'Modules without dependents or dependencies',
82
+ from: {
83
+ orphan: true,
84
+ pathNot: [
85
+ '\\.d\\.ts$',
86
+ '\\.test\\.(ts|js)$',
87
+ '\\.spec\\.(ts|js)$',
88
+ 'index\\.(ts|js)$',
89
+ ],
90
+ },
91
+ to: {},
92
+ },
93
+ ],
94
+ },
95
+ };
96
+ }
97
+ /**
98
+ * Run dependency analysis
99
+ */
100
+ async analyze(filesToCruise, cruiseOptions) {
101
+ if (!this.cruiseFn) {
102
+ log('dependency-analyzer: cruise function not available, skipping analysis');
103
+ return {
104
+ success: false,
105
+ skipped: true,
106
+ reason: 'dependency-cruiser not available',
107
+ };
108
+ }
109
+ log(`dependency-analyzer: analysing ${filesToCruise.length} files/patterns`);
110
+ try {
111
+ const cruiseResult = await this.cruiseFn(filesToCruise, {
112
+ ...cruiseOptions,
113
+ outputType: 'json',
114
+ });
115
+ const summary = cruiseResult.output.summary;
116
+ log('dependency-analyzer: analysis complete', {
117
+ totalCruised: summary.totalCruised,
118
+ violations: summary.violations.length,
119
+ error: summary.error,
120
+ warn: summary.warn,
121
+ info: summary.info,
122
+ });
123
+ return {
124
+ success: true,
125
+ result: cruiseResult.output,
126
+ };
127
+ }
128
+ catch (error) {
129
+ log(`dependency-analyzer: analysis failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
130
+ return {
131
+ success: false,
132
+ error: error instanceof Error ? error.message : 'Unknown error',
133
+ };
134
+ }
135
+ }
136
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Layer Validator - Score calculation and validation for architecture violations
3
+ *
4
+ * Handles scoring, pass/fail determination, and severity-based blocking.
5
+ */
6
+ import type { CruiserViolation } from './dependency-analyzer.js';
7
+ /**
8
+ * Configuration for architecture check
9
+ */
10
+ export interface ArchitectureCheckConfig {
11
+ /** Path to dependency-cruiser config (default: .anvil/dependency-cruiser.js) */
12
+ config_file?: string;
13
+ /** Scope of analysis: 'affected' | 'full' */
14
+ scope?: 'affected' | 'full';
15
+ /** Minimum severity to fail the check */
16
+ severity_threshold?: 'error' | 'warn' | 'info';
17
+ /** Whether circular dependencies should fail the check */
18
+ fail_on_circular?: boolean;
19
+ /** Whether orphaned modules should fail the check */
20
+ fail_on_orphan?: boolean;
21
+ /** Include patterns (glob) for full scope */
22
+ include_patterns?: string[];
23
+ /** Exclude patterns (glob) */
24
+ exclude_patterns?: string[];
25
+ }
26
+ /**
27
+ * Default configuration
28
+ */
29
+ export declare const DEFAULT_CONFIG: Required<ArchitectureCheckConfig>;
30
+ /**
31
+ * Result of score calculation
32
+ */
33
+ export interface ScoreResult {
34
+ score: number;
35
+ passed: boolean;
36
+ violationsByType: Record<string, number>;
37
+ }
38
+ /**
39
+ * Layer validator for architecture constraints
40
+ */
41
+ export declare class LayerValidator {
42
+ /**
43
+ * Parse and validate check configuration
44
+ */
45
+ parseConfig(checkConfig: Record<string, unknown>): Required<ArchitectureCheckConfig>;
46
+ /**
47
+ * Parse scope option
48
+ */
49
+ private parseScope;
50
+ /**
51
+ * Parse severity threshold
52
+ */
53
+ private parseSeverity;
54
+ /**
55
+ * Calculate score based on violations
56
+ */
57
+ calculateScore(violations: CruiserViolation[], config: Required<ArchitectureCheckConfig>): ScoreResult;
58
+ /**
59
+ * Check if a severity level should block the check
60
+ */
61
+ private isBlockingSeverity;
62
+ /**
63
+ * Check if a file should be analysed
64
+ */
65
+ isAnalysableFile(filePath: string, config: Required<ArchitectureCheckConfig>): boolean;
66
+ /**
67
+ * Simple glob pattern matching (for common patterns)
68
+ */
69
+ private matchesGlobPattern;
70
+ /**
71
+ * Build human-readable message
72
+ */
73
+ buildMessage(violations: CruiserViolation[], totalCruised: number, passed: boolean): string;
74
+ }
75
+ //# sourceMappingURL=layer-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer-validator.d.ts","sourceRoot":"","sources":["../../../../src/gate/checks/architecture/layer-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAKjE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC5B,yCAAyC;IACzC,kBAAkB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/C,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,qDAAqD;IACrD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,8BAA8B;IAC9B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,uBAAuB,CAc5D,CAAC;AAYF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB;;OAEG;IACH,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,uBAAuB,CAAC;IAoBpF;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,cAAc,CACZ,UAAU,EAAE,gBAAgB,EAAE,EAC9B,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GACxC,WAAW;IA8Dd;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GAAG,OAAO;IAgBtF;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,gBAAgB,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM;CAiB5F"}
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Layer Validator - Score calculation and validation for architecture violations
3
+ *
4
+ * Handles scoring, pass/fail determination, and severity-based blocking.
5
+ */
6
+ import { createDebugger } from '@eddacraft/anvil-core';
7
+ const log = createDebugger('check');
8
+ /**
9
+ * Default configuration
10
+ */
11
+ export const DEFAULT_CONFIG = {
12
+ config_file: '.anvil/dependency-cruiser.js',
13
+ scope: 'affected',
14
+ severity_threshold: 'error',
15
+ fail_on_circular: true,
16
+ fail_on_orphan: false,
17
+ include_patterns: ['src/**/*.ts', 'src/**/*.js'],
18
+ exclude_patterns: [
19
+ '**/*.test.ts',
20
+ '**/*.spec.ts',
21
+ '**/__fixtures__/**',
22
+ '**/__tests__/**',
23
+ '**/node_modules/**',
24
+ ],
25
+ };
26
+ /**
27
+ * Score penalties per severity
28
+ */
29
+ const SEVERITY_PENALTIES = {
30
+ error: 15,
31
+ warn: 5,
32
+ info: 1,
33
+ ignore: 0,
34
+ };
35
+ /**
36
+ * Layer validator for architecture constraints
37
+ */
38
+ export class LayerValidator {
39
+ /**
40
+ * Parse and validate check configuration
41
+ */
42
+ parseConfig(checkConfig) {
43
+ return {
44
+ config_file: typeof checkConfig.config_file === 'string'
45
+ ? checkConfig.config_file
46
+ : DEFAULT_CONFIG.config_file,
47
+ scope: this.parseScope(checkConfig.scope),
48
+ severity_threshold: this.parseSeverity(checkConfig.severity_threshold) || DEFAULT_CONFIG.severity_threshold,
49
+ fail_on_circular: checkConfig.fail_on_circular !== false,
50
+ fail_on_orphan: checkConfig.fail_on_orphan === true,
51
+ include_patterns: Array.isArray(checkConfig.include_patterns)
52
+ ? checkConfig.include_patterns.filter((p) => typeof p === 'string')
53
+ : DEFAULT_CONFIG.include_patterns,
54
+ exclude_patterns: Array.isArray(checkConfig.exclude_patterns)
55
+ ? checkConfig.exclude_patterns.filter((p) => typeof p === 'string')
56
+ : DEFAULT_CONFIG.exclude_patterns,
57
+ };
58
+ }
59
+ /**
60
+ * Parse scope option
61
+ */
62
+ parseScope(value) {
63
+ if (value === 'full' || value === 'affected') {
64
+ return value;
65
+ }
66
+ return DEFAULT_CONFIG.scope;
67
+ }
68
+ /**
69
+ * Parse severity threshold
70
+ */
71
+ parseSeverity(value) {
72
+ if (typeof value !== 'string')
73
+ return undefined;
74
+ const lower = value.toLowerCase();
75
+ if (lower === 'error' || lower === 'warn' || lower === 'info') {
76
+ return lower;
77
+ }
78
+ return undefined;
79
+ }
80
+ /**
81
+ * Calculate score based on violations
82
+ */
83
+ calculateScore(violations, config) {
84
+ log(`layer-validator: calculating score for ${violations.length} violations (threshold=${config.severity_threshold})`);
85
+ const violationsByType = {
86
+ circular: 0,
87
+ orphan: 0,
88
+ layer: 0,
89
+ other: 0,
90
+ };
91
+ let totalPenalty = 0;
92
+ let hasBlockingViolation = false;
93
+ for (const v of violations) {
94
+ // Categorise violation
95
+ if (v.cycle && v.cycle.length > 0) {
96
+ violationsByType.circular++;
97
+ if (config.fail_on_circular &&
98
+ this.isBlockingSeverity(v.rule.severity, config.severity_threshold)) {
99
+ hasBlockingViolation = true;
100
+ }
101
+ }
102
+ else if (v.rule.name.includes('orphan')) {
103
+ violationsByType.orphan++;
104
+ if (config.fail_on_orphan &&
105
+ this.isBlockingSeverity(v.rule.severity, config.severity_threshold)) {
106
+ hasBlockingViolation = true;
107
+ }
108
+ }
109
+ else if (v.rule.name.includes('layer') || v.rule.name.includes('boundary')) {
110
+ violationsByType.layer++;
111
+ if (this.isBlockingSeverity(v.rule.severity, config.severity_threshold)) {
112
+ hasBlockingViolation = true;
113
+ }
114
+ }
115
+ else {
116
+ violationsByType.other++;
117
+ if (this.isBlockingSeverity(v.rule.severity, config.severity_threshold)) {
118
+ hasBlockingViolation = true;
119
+ }
120
+ }
121
+ // Calculate penalty
122
+ totalPenalty += SEVERITY_PENALTIES[v.rule.severity] || 0;
123
+ }
124
+ const score = Math.max(0, 100 - totalPenalty);
125
+ const passed = !hasBlockingViolation;
126
+ log('layer-validator result', {
127
+ score,
128
+ passed,
129
+ penalty: totalPenalty,
130
+ blocking: hasBlockingViolation,
131
+ violationsByType,
132
+ });
133
+ return { score, passed, violationsByType };
134
+ }
135
+ /**
136
+ * Check if a severity level should block the check
137
+ */
138
+ isBlockingSeverity(severity, threshold) {
139
+ const levels = { error: 3, warn: 2, info: 1, ignore: 0 };
140
+ return levels[severity] >= levels[threshold];
141
+ }
142
+ /**
143
+ * Check if a file should be analysed
144
+ */
145
+ isAnalysableFile(filePath, config) {
146
+ const analysableExtensions = ['.js', '.ts', '.jsx', '.tsx', '.mjs', '.cjs'];
147
+ const hasValidExtension = analysableExtensions.some((ext) => filePath.endsWith(ext));
148
+ if (!hasValidExtension)
149
+ return false;
150
+ // Check exclusions
151
+ for (const pattern of config.exclude_patterns) {
152
+ if (this.matchesGlobPattern(filePath, pattern)) {
153
+ return false;
154
+ }
155
+ }
156
+ return true;
157
+ }
158
+ /**
159
+ * Simple glob pattern matching (for common patterns)
160
+ */
161
+ matchesGlobPattern(filePath, pattern) {
162
+ // Normalise to forward slashes for consistent cross-platform matching
163
+ const normalizedPath = filePath.replace(/\\/g, '/');
164
+ // Convert glob to regex (simplified)
165
+ const regexPattern = pattern
166
+ .replace(/\*\*/g, '{{GLOBSTAR}}')
167
+ .replace(/\*/g, '[^/]*')
168
+ .replace(/{{GLOBSTAR}}/g, '.*')
169
+ .replace(/\?/g, '.');
170
+ const regex = new RegExp(regexPattern);
171
+ return regex.test(normalizedPath);
172
+ }
173
+ /**
174
+ * Build human-readable message
175
+ */
176
+ buildMessage(violations, totalCruised, passed) {
177
+ if (violations.length === 0) {
178
+ return `Architecture check passed: ${totalCruised} modules analysed, no violations`;
179
+ }
180
+ const errorCount = violations.filter((v) => v.rule.severity === 'error').length;
181
+ const warnCount = violations.filter((v) => v.rule.severity === 'warn').length;
182
+ const infoCount = violations.filter((v) => v.rule.severity === 'info').length;
183
+ const parts = [];
184
+ if (errorCount > 0)
185
+ parts.push(`${errorCount} error${errorCount > 1 ? 's' : ''}`);
186
+ if (warnCount > 0)
187
+ parts.push(`${warnCount} warning${warnCount > 1 ? 's' : ''}`);
188
+ if (infoCount > 0)
189
+ parts.push(`${infoCount} info`);
190
+ const status = passed ? 'passed with issues' : 'failed';
191
+ return `Architecture check ${status}: ${parts.join(', ')} (${totalCruised} modules analysed)`;
192
+ }
193
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Architecture Check - Validate architectural constraints using dependency-cruiser
3
+ *
4
+ * Detects:
5
+ * - Circular dependencies
6
+ * - Layer/boundary violations
7
+ * - Orphaned modules (optional)
8
+ */
9
+ import { BaseCheck } from '../check.interface.js';
10
+ import { CheckContext, GateResult } from '../../types/gate.types.js';
11
+ export type { ArchitectureCheckConfig } from './architecture/layer-validator.js';
12
+ /**
13
+ * Architecture check that validates project structure using dependency-cruiser
14
+ */
15
+ export declare class ArchitectureCheck extends BaseCheck {
16
+ name: string;
17
+ description: string;
18
+ private analyzer;
19
+ private detector;
20
+ private validator;
21
+ run(context: CheckContext): Promise<GateResult>;
22
+ private convertViolationToWarning;
23
+ private mapCruiserSeverity;
24
+ private createArchWarningResult;
25
+ /**
26
+ * Get files to cruise based on scope
27
+ */
28
+ private getFilesToCruise;
29
+ /**
30
+ * Check if a file should be analysed
31
+ * @internal Reserved for future use
32
+ */
33
+ private _isAnalysableFile;
34
+ private matchesGlobPattern;
35
+ /**
36
+ * Get default cruise options when no config file exists
37
+ * @internal Reserved for future use
38
+ */
39
+ private _getDefaultCruiseOptions;
40
+ /**
41
+ * Calculate score based on violations
42
+ * @internal Reserved for future use
43
+ */
44
+ private _calculateScore;
45
+ /**
46
+ * Check if a severity level should block the check
47
+ */
48
+ private isBlockingSeverity;
49
+ /**
50
+ * Build human-readable message
51
+ * @internal Reserved for future use
52
+ */
53
+ private _buildMessage;
54
+ private buildArchitectureContext;
55
+ }
56
+ //# sourceMappingURL=architecture.check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architecture.check.d.ts","sourceRoot":"","sources":["../../../src/gate/checks/architecture.check.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AA0B1F,YAAY,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AA2CjF;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;IAC9C,IAAI,SAAkB;IACtB,WAAW,SAAiE;IAE5E,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,SAAS,CAAwB;IAEnC,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC;IAyJrD,OAAO,CAAC,yBAAyB;IAqCjC,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,uBAAuB;IAU/B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsBxB;;;OAGG;IAEH,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,kBAAkB;IAM1B;;;OAGG;IAEH,OAAO,CAAC,wBAAwB;IAkChC;;;OAGG;IAEH,OAAO,CAAC,eAAe;IA0DvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;;OAGG;IAEH,OAAO,CAAC,aAAa;IAsBrB,OAAO,CAAC,wBAAwB;CA6CjC"}