@eddacraft/anvil-core 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 (215) hide show
  1. package/LICENSE +14 -0
  2. package/dist/antipattern/index.d.ts +11 -0
  3. package/dist/antipattern/index.d.ts.map +1 -0
  4. package/dist/antipattern/index.js +31 -0
  5. package/dist/antipattern/patterns-css.d.ts +17 -0
  6. package/dist/antipattern/patterns-css.d.ts.map +1 -0
  7. package/dist/antipattern/patterns-css.js +72 -0
  8. package/dist/antipattern/patterns-html.d.ts +21 -0
  9. package/dist/antipattern/patterns-html.d.ts.map +1 -0
  10. package/dist/antipattern/patterns-html.js +139 -0
  11. package/dist/antipattern/patterns.d.ts +72 -0
  12. package/dist/antipattern/patterns.d.ts.map +1 -0
  13. package/dist/antipattern/patterns.js +301 -0
  14. package/dist/antipattern/scanner.d.ts +32 -0
  15. package/dist/antipattern/scanner.d.ts.map +1 -0
  16. package/dist/antipattern/scanner.js +89 -0
  17. package/dist/antipattern/types.d.ts +318 -0
  18. package/dist/antipattern/types.d.ts.map +1 -0
  19. package/dist/antipattern/types.js +278 -0
  20. package/dist/architecture/analyzer.d.ts +123 -0
  21. package/dist/architecture/analyzer.d.ts.map +1 -0
  22. package/dist/architecture/analyzer.js +321 -0
  23. package/dist/architecture/baseline.d.ts +112 -0
  24. package/dist/architecture/baseline.d.ts.map +1 -0
  25. package/dist/architecture/baseline.js +245 -0
  26. package/dist/architecture/compiler.d.ts +24 -0
  27. package/dist/architecture/compiler.d.ts.map +1 -0
  28. package/dist/architecture/compiler.js +57 -0
  29. package/dist/architecture/context.d.ts +129 -0
  30. package/dist/architecture/context.d.ts.map +1 -0
  31. package/dist/architecture/context.js +116 -0
  32. package/dist/architecture/dc-generator.d.ts +9 -0
  33. package/dist/architecture/dc-generator.d.ts.map +1 -0
  34. package/dist/architecture/dc-generator.js +220 -0
  35. package/dist/architecture/definition-schema.d.ts +128 -0
  36. package/dist/architecture/definition-schema.d.ts.map +1 -0
  37. package/dist/architecture/definition-schema.js +94 -0
  38. package/dist/architecture/edge-detector-html.d.ts +6 -0
  39. package/dist/architecture/edge-detector-html.d.ts.map +1 -0
  40. package/dist/architecture/edge-detector-html.js +5 -0
  41. package/dist/architecture/edge-detector-web.d.ts +32 -0
  42. package/dist/architecture/edge-detector-web.d.ts.map +1 -0
  43. package/dist/architecture/edge-detector-web.js +133 -0
  44. package/dist/architecture/edge-detector.d.ts +116 -0
  45. package/dist/architecture/edge-detector.d.ts.map +1 -0
  46. package/dist/architecture/edge-detector.js +229 -0
  47. package/dist/architecture/entry-detector.d.ts +44 -0
  48. package/dist/architecture/entry-detector.d.ts.map +1 -0
  49. package/dist/architecture/entry-detector.js +263 -0
  50. package/dist/architecture/index.d.ts +21 -0
  51. package/dist/architecture/index.d.ts.map +1 -0
  52. package/dist/architecture/index.js +48 -0
  53. package/dist/architecture/layer-detector.d.ts +60 -0
  54. package/dist/architecture/layer-detector.d.ts.map +1 -0
  55. package/dist/architecture/layer-detector.js +331 -0
  56. package/dist/architecture/rego-generator.d.ts +25 -0
  57. package/dist/architecture/rego-generator.d.ts.map +1 -0
  58. package/dist/architecture/rego-generator.js +229 -0
  59. package/dist/architecture/templates/index.d.ts +39 -0
  60. package/dist/architecture/templates/index.d.ts.map +1 -0
  61. package/dist/architecture/templates/index.js +124 -0
  62. package/dist/architecture/types.d.ts +280 -0
  63. package/dist/architecture/types.d.ts.map +1 -0
  64. package/dist/architecture/types.js +269 -0
  65. package/dist/architecture/yaml-parser.d.ts +13 -0
  66. package/dist/architecture/yaml-parser.d.ts.map +1 -0
  67. package/dist/architecture/yaml-parser.js +234 -0
  68. package/dist/config/constants.d.ts +9 -0
  69. package/dist/config/constants.d.ts.map +1 -0
  70. package/dist/config/constants.js +20 -0
  71. package/dist/config/index.d.ts +9 -0
  72. package/dist/config/index.d.ts.map +1 -0
  73. package/dist/config/index.js +8 -0
  74. package/dist/config/loader.d.ts +41 -0
  75. package/dist/config/loader.d.ts.map +1 -0
  76. package/dist/config/loader.js +76 -0
  77. package/dist/config/nudge-config.d.ts +35 -0
  78. package/dist/config/nudge-config.d.ts.map +1 -0
  79. package/dist/config/nudge-config.js +34 -0
  80. package/dist/config/types.d.ts +30 -0
  81. package/dist/config/types.d.ts.map +1 -0
  82. package/dist/config/types.js +4 -0
  83. package/dist/contracts/index.d.ts +14 -0
  84. package/dist/contracts/index.d.ts.map +1 -0
  85. package/dist/contracts/index.js +13 -0
  86. package/dist/contracts/schemas/aps.schema.d.ts +269 -0
  87. package/dist/contracts/schemas/aps.schema.d.ts.map +1 -0
  88. package/dist/contracts/schemas/aps.schema.js +183 -0
  89. package/dist/contracts/schemas/index.d.ts +12 -0
  90. package/dist/contracts/schemas/index.d.ts.map +1 -0
  91. package/dist/contracts/schemas/index.js +14 -0
  92. package/dist/contracts/schemas/json-schema.d.ts +14 -0
  93. package/dist/contracts/schemas/json-schema.d.ts.map +1 -0
  94. package/dist/contracts/schemas/json-schema.js +31 -0
  95. package/dist/contracts/schemas/warning.schema.d.ts +171 -0
  96. package/dist/contracts/schemas/warning.schema.d.ts.map +1 -0
  97. package/dist/contracts/schemas/warning.schema.js +123 -0
  98. package/dist/contracts/types/gate.types.d.ts +194 -0
  99. package/dist/contracts/types/gate.types.d.ts.map +1 -0
  100. package/dist/contracts/types/gate.types.js +19 -0
  101. package/dist/contracts/types/index.d.ts +9 -0
  102. package/dist/contracts/types/index.d.ts.map +1 -0
  103. package/dist/contracts/types/index.js +8 -0
  104. package/dist/crypto/hash.d.ts +47 -0
  105. package/dist/crypto/hash.d.ts.map +1 -0
  106. package/dist/crypto/hash.js +110 -0
  107. package/dist/crypto/index.d.ts +7 -0
  108. package/dist/crypto/index.d.ts.map +1 -0
  109. package/dist/crypto/index.js +6 -0
  110. package/dist/drift/index.d.ts +6 -0
  111. package/dist/drift/index.d.ts.map +1 -0
  112. package/dist/drift/index.js +5 -0
  113. package/dist/drift/report-generator.d.ts +21 -0
  114. package/dist/drift/report-generator.d.ts.map +1 -0
  115. package/dist/drift/report-generator.js +240 -0
  116. package/dist/drift/snapshot-capture.d.ts +26 -0
  117. package/dist/drift/snapshot-capture.d.ts.map +1 -0
  118. package/dist/drift/snapshot-capture.js +195 -0
  119. package/dist/drift/snapshot-compare.d.ts +50 -0
  120. package/dist/drift/snapshot-compare.d.ts.map +1 -0
  121. package/dist/drift/snapshot-compare.js +142 -0
  122. package/dist/drift/snapshot-schema.d.ts +197 -0
  123. package/dist/drift/snapshot-schema.d.ts.map +1 -0
  124. package/dist/drift/snapshot-schema.js +193 -0
  125. package/dist/drift/snapshot-storage.d.ts +25 -0
  126. package/dist/drift/snapshot-storage.d.ts.map +1 -0
  127. package/dist/drift/snapshot-storage.js +179 -0
  128. package/dist/explain/antipattern-explainer.d.ts +4 -0
  129. package/dist/explain/antipattern-explainer.d.ts.map +1 -0
  130. package/dist/explain/antipattern-explainer.js +196 -0
  131. package/dist/explain/boundary-explainer.d.ts +5 -0
  132. package/dist/explain/boundary-explainer.d.ts.map +1 -0
  133. package/dist/explain/boundary-explainer.js +261 -0
  134. package/dist/explain/explain-service.d.ts +19 -0
  135. package/dist/explain/explain-service.d.ts.map +1 -0
  136. package/dist/explain/explain-service.js +106 -0
  137. package/dist/explain/index.d.ts +7 -0
  138. package/dist/explain/index.d.ts.map +1 -0
  139. package/dist/explain/index.js +5 -0
  140. package/dist/explain/template-loader.d.ts +9 -0
  141. package/dist/explain/template-loader.d.ts.map +1 -0
  142. package/dist/explain/template-loader.js +51 -0
  143. package/dist/explain/types.d.ts +46 -0
  144. package/dist/explain/types.d.ts.map +1 -0
  145. package/dist/explain/types.js +31 -0
  146. package/dist/index.d.ts +26 -0
  147. package/dist/index.d.ts.map +1 -0
  148. package/dist/index.js +37 -0
  149. package/dist/provenance/collector.d.ts +86 -0
  150. package/dist/provenance/collector.d.ts.map +1 -0
  151. package/dist/provenance/collector.js +425 -0
  152. package/dist/provenance/git-ai-standard/git-notes.d.ts +85 -0
  153. package/dist/provenance/git-ai-standard/git-notes.d.ts.map +1 -0
  154. package/dist/provenance/git-ai-standard/git-notes.js +292 -0
  155. package/dist/provenance/git-ai-standard/index.d.ts +44 -0
  156. package/dist/provenance/git-ai-standard/index.d.ts.map +1 -0
  157. package/dist/provenance/git-ai-standard/index.js +47 -0
  158. package/dist/provenance/git-ai-standard/serializer.d.ts +54 -0
  159. package/dist/provenance/git-ai-standard/serializer.d.ts.map +1 -0
  160. package/dist/provenance/git-ai-standard/serializer.js +224 -0
  161. package/dist/provenance/git-ai-standard/session.d.ts +51 -0
  162. package/dist/provenance/git-ai-standard/session.d.ts.map +1 -0
  163. package/dist/provenance/git-ai-standard/session.js +118 -0
  164. package/dist/provenance/git-ai-standard/types.d.ts +173 -0
  165. package/dist/provenance/git-ai-standard/types.d.ts.map +1 -0
  166. package/dist/provenance/git-ai-standard/types.js +109 -0
  167. package/dist/provenance/index.d.ts +5 -0
  168. package/dist/provenance/index.d.ts.map +1 -0
  169. package/dist/provenance/index.js +6 -0
  170. package/dist/provenance/store.d.ts +83 -0
  171. package/dist/provenance/store.d.ts.map +1 -0
  172. package/dist/provenance/store.js +248 -0
  173. package/dist/provenance/types.d.ts +160 -0
  174. package/dist/provenance/types.d.ts.map +1 -0
  175. package/dist/provenance/types.js +112 -0
  176. package/dist/suppression/index.d.ts +4 -0
  177. package/dist/suppression/index.d.ts.map +1 -0
  178. package/dist/suppression/index.js +3 -0
  179. package/dist/suppression/parser.d.ts +31 -0
  180. package/dist/suppression/parser.d.ts.map +1 -0
  181. package/dist/suppression/parser.js +219 -0
  182. package/dist/suppression/service.d.ts +29 -0
  183. package/dist/suppression/service.d.ts.map +1 -0
  184. package/dist/suppression/service.js +132 -0
  185. package/dist/suppression/store.d.ts +61 -0
  186. package/dist/suppression/store.d.ts.map +1 -0
  187. package/dist/suppression/store.js +169 -0
  188. package/dist/utils/debug.d.ts +48 -0
  189. package/dist/utils/debug.d.ts.map +1 -0
  190. package/dist/utils/debug.js +100 -0
  191. package/dist/utils/index.d.ts +4 -0
  192. package/dist/utils/index.d.ts.map +1 -0
  193. package/dist/utils/index.js +3 -0
  194. package/dist/utils/path-safety.d.ts +21 -0
  195. package/dist/utils/path-safety.d.ts.map +1 -0
  196. package/dist/utils/path-safety.js +49 -0
  197. package/dist/utils/severity.d.ts +37 -0
  198. package/dist/utils/severity.d.ts.map +1 -0
  199. package/dist/utils/severity.js +22 -0
  200. package/dist/validation/aps-validator.d.ts +66 -0
  201. package/dist/validation/aps-validator.d.ts.map +1 -0
  202. package/dist/validation/aps-validator.js +173 -0
  203. package/dist/validation/errors.d.ts +52 -0
  204. package/dist/validation/errors.d.ts.map +1 -0
  205. package/dist/validation/errors.js +115 -0
  206. package/dist/validation/index.d.ts +8 -0
  207. package/dist/validation/index.d.ts.map +1 -0
  208. package/dist/validation/index.js +13 -0
  209. package/dist/warnings/index.d.ts +2 -0
  210. package/dist/warnings/index.d.ts.map +1 -0
  211. package/dist/warnings/index.js +1 -0
  212. package/dist/warnings/warning-id.d.ts +180 -0
  213. package/dist/warnings/warning-id.d.ts.map +1 -0
  214. package/dist/warnings/warning-id.js +257 -0
  215. package/package.json +79 -0
@@ -0,0 +1,229 @@
1
+ import { writeFile, mkdir, readFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { join, dirname } from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import { createDebugger } from '../utils/debug.js';
6
+ const debug = createDebugger('compiler');
7
+ export const GENERATED_POLICIES_DIR = '.anvil/policies/.generated';
8
+ export const REGO_FILENAME = 'architecture.rego';
9
+ export const REGO_PACKAGE = 'anvil.policies.architecture';
10
+ /**
11
+ * Get the path to the generated Rego file
12
+ */
13
+ export function getRegoPath(workspaceRoot) {
14
+ return join(workspaceRoot, GENERATED_POLICIES_DIR, REGO_FILENAME);
15
+ }
16
+ /**
17
+ * Check if generated Rego file exists
18
+ */
19
+ export function regoExists(workspaceRoot) {
20
+ return existsSync(getRegoPath(workspaceRoot));
21
+ }
22
+ /**
23
+ * Check if Rego needs regeneration based on definition hash
24
+ */
25
+ export async function needsRegoRegeneration(workspaceRoot, definition) {
26
+ const regoPath = getRegoPath(workspaceRoot);
27
+ if (!existsSync(regoPath)) {
28
+ return true;
29
+ }
30
+ const existingContent = await readFile(regoPath, 'utf-8');
31
+ const hashMatch = existingContent.match(/# hash: ([a-f0-9]+)/);
32
+ if (!hashMatch) {
33
+ return true;
34
+ }
35
+ const currentHash = computeDefinitionHash(definition);
36
+ return hashMatch[1] !== currentHash;
37
+ }
38
+ function computeDefinitionHash(definition) {
39
+ const content = JSON.stringify(definition);
40
+ return createHash('sha256').update(content).digest('hex').slice(0, 16);
41
+ }
42
+ /**
43
+ * Write generated Rego policy file
44
+ */
45
+ export async function writeRegoPolicy(workspaceRoot, definition) {
46
+ const regoPath = getRegoPath(workspaceRoot);
47
+ debug('writing Rego policy', regoPath);
48
+ const regoDir = dirname(regoPath);
49
+ if (!existsSync(regoDir)) {
50
+ await mkdir(regoDir, { recursive: true });
51
+ }
52
+ const content = generateRegoPolicy(definition);
53
+ await writeFile(regoPath, content, 'utf-8');
54
+ return regoPath;
55
+ }
56
+ /**
57
+ * Generate Rego policy content from architecture definition
58
+ */
59
+ export function generateRegoPolicy(definition) {
60
+ const hash = computeDefinitionHash(definition);
61
+ const lines = [];
62
+ // Header
63
+ lines.push('# Auto-generated by Anvil - do not edit manually');
64
+ lines.push(`# hash: ${hash}`);
65
+ lines.push('# Generated from: .anvil/architecture.yaml');
66
+ lines.push('#');
67
+ lines.push('# This policy enforces architecture boundaries defined in architecture.yaml.');
68
+ lines.push('# It uses the architecture context provided by ArchitectureCheck.');
69
+ lines.push('');
70
+ lines.push(`package ${REGO_PACKAGE}`);
71
+ lines.push('');
72
+ lines.push('import rego.v1');
73
+ lines.push('');
74
+ // Generate layer definitions as data
75
+ lines.push('# Layer definitions from architecture.yaml');
76
+ lines.push(`layers := ${JSON.stringify(Object.keys(definition.layers))}`);
77
+ lines.push('');
78
+ // Generate allowed dependencies map
79
+ const allowedDeps = {};
80
+ for (const [layerName, layerDef] of Object.entries(definition.layers)) {
81
+ allowedDeps[layerName] = layerDef.depends_on;
82
+ }
83
+ lines.push('# Allowed dependencies per layer');
84
+ lines.push(`allowed_deps := ${JSON.stringify(allowedDeps)}`);
85
+ lines.push('');
86
+ // Generate options
87
+ const options = definition.options ?? {
88
+ detect_circular: true,
89
+ default_severity: 'error',
90
+ };
91
+ lines.push('# Options');
92
+ lines.push(`detect_circular := ${options.detect_circular ?? true}`);
93
+ lines.push(`default_severity := "${options.default_severity ?? 'error'}"`);
94
+ lines.push('');
95
+ // Helper function to check if a layer can depend on another
96
+ lines.push('# Check if source layer is allowed to depend on target layer');
97
+ lines.push('layer_can_depend(source, target) if {');
98
+ lines.push(' source == target # Same layer is always allowed');
99
+ lines.push('}');
100
+ lines.push('');
101
+ lines.push('layer_can_depend(source, target) if {');
102
+ lines.push(' allowed := allowed_deps[source]');
103
+ lines.push(' target in allowed');
104
+ lines.push('}');
105
+ lines.push('');
106
+ // Violation rule for layer boundary violations
107
+ lines.push('# Detect layer boundary violations from architecture context');
108
+ lines.push('violation contains result if {');
109
+ lines.push(' some v in input.architecture.violations');
110
+ lines.push(' v.from_layer != null');
111
+ lines.push(' v.to_layer != null');
112
+ lines.push(' not layer_can_depend(v.from_layer, v.to_layer)');
113
+ lines.push(' v.is_new');
114
+ lines.push(' result := {');
115
+ lines.push(' "rule": "layer-boundary",');
116
+ lines.push(' "severity": v.severity,');
117
+ lines.push(' "message": sprintf("%s (%s) cannot depend on %s (%s)", [v.from, v.from_layer, v.to, v.to_layer]),');
118
+ lines.push(' "path": v.from,');
119
+ lines.push(' "category": "architecture",');
120
+ lines.push(' }');
121
+ lines.push('}');
122
+ lines.push('');
123
+ // Violation rule for circular dependencies
124
+ lines.push('# Detect circular dependencies');
125
+ lines.push('violation contains result if {');
126
+ lines.push(' detect_circular');
127
+ lines.push(' some v in input.architecture.violations');
128
+ lines.push(' v.is_circular');
129
+ lines.push(' v.is_new');
130
+ lines.push(' result := {');
131
+ lines.push(' "rule": "no-circular",');
132
+ lines.push(' "severity": default_severity,');
133
+ lines.push(' "message": sprintf("Circular dependency: %s -> %s", [v.from, v.to]),');
134
+ lines.push(' "path": v.from,');
135
+ lines.push(' "category": "architecture",');
136
+ lines.push(' }');
137
+ lines.push('}');
138
+ lines.push('');
139
+ // Violation rule for new violations (not in baseline)
140
+ lines.push('# Flag new violations (not in baseline)');
141
+ lines.push('violation contains result if {');
142
+ lines.push(' some v in input.architecture.violations');
143
+ lines.push(' v.is_new');
144
+ lines.push(' result := {');
145
+ lines.push(' "rule": "new-violation",');
146
+ lines.push(' "severity": "warning",');
147
+ lines.push(' "message": sprintf("New architecture violation: %s -> %s (%s)", [v.from, v.to, v.rule]),');
148
+ lines.push(' "path": v.from,');
149
+ lines.push(' "category": "architecture",');
150
+ lines.push(' }');
151
+ lines.push('}');
152
+ lines.push('');
153
+ // Generate explicit rules from definition
154
+ if (definition.rules.length > 0) {
155
+ lines.push('# Explicit rules from architecture.yaml');
156
+ for (const rule of definition.rules) {
157
+ if (!rule.allowed) {
158
+ // This is a forbidden dependency rule
159
+ const fromLayer = definition.layers[rule.from];
160
+ const toLayer = definition.layers[rule.to];
161
+ if (fromLayer && toLayer) {
162
+ const ruleName = sanitiseRuleName(rule.name);
163
+ lines.push(`# Rule: ${rule.name}`);
164
+ lines.push(`violation contains result if {`);
165
+ lines.push(` some v in input.architecture.violations`);
166
+ lines.push(` v.from_layer == "${rule.from}"`);
167
+ lines.push(` v.to_layer == "${rule.to}"`);
168
+ lines.push(` v.is_new`);
169
+ lines.push(` result := {`);
170
+ lines.push(` "rule": "${ruleName}",`);
171
+ lines.push(` "severity": "${rule.severity}",`);
172
+ lines.push(` "message": "${escapeString(rule.message || `${rule.from} must not depend on ${rule.to}`)}",`);
173
+ lines.push(` "path": v.from,`);
174
+ lines.push(` "category": "architecture",`);
175
+ lines.push(` }`);
176
+ lines.push(`}`);
177
+ lines.push('');
178
+ }
179
+ }
180
+ }
181
+ }
182
+ // Summary helper for external use
183
+ lines.push('# Summary of architecture health');
184
+ lines.push('summary := {');
185
+ lines.push(' "total_violations": count(violation),');
186
+ lines.push(' "layer_violations": count([v | some v in violation; v.rule == "layer-boundary"]),');
187
+ lines.push(' "circular_violations": count([v | some v in violation; v.rule == "no-circular"]),');
188
+ lines.push(' "new_violations": count([v | some v in violation; v.rule == "new-violation"]),');
189
+ lines.push('}');
190
+ lines.push('');
191
+ // Deny rule for blocking on errors
192
+ lines.push('# Deny if any error-level violations exist');
193
+ lines.push('deny contains msg if {');
194
+ lines.push(' some v in violation');
195
+ lines.push(' v.severity == "error"');
196
+ lines.push(' msg := v.message');
197
+ lines.push('}');
198
+ lines.push('');
199
+ // Warn rule for warning-level violations
200
+ lines.push('# Warn for warning-level violations');
201
+ lines.push('warn contains msg if {');
202
+ lines.push(' some v in violation');
203
+ lines.push(' v.severity == "warn"');
204
+ lines.push(' msg := v.message');
205
+ lines.push('}');
206
+ lines.push('');
207
+ lines.push('warn contains msg if {');
208
+ lines.push(' some v in violation');
209
+ lines.push(' v.severity == "warning"');
210
+ lines.push(' msg := v.message');
211
+ lines.push('}');
212
+ lines.push('');
213
+ return lines.join('\n');
214
+ }
215
+ /**
216
+ * Sanitise rule name for use in Rego
217
+ */
218
+ function sanitiseRuleName(name) {
219
+ return name
220
+ .toLowerCase()
221
+ .replace(/[^a-z0-9]+/g, '-')
222
+ .replace(/^-|-$/g, '');
223
+ }
224
+ /**
225
+ * Escape string for Rego string literal
226
+ */
227
+ function escapeString(str) {
228
+ return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
229
+ }
@@ -0,0 +1,39 @@
1
+ import { z } from 'zod';
2
+ import type { ArchitectureTemplate, LayerDefinition } from '../definition-schema.js';
3
+ declare const TemplateFileSchema: z.ZodObject<{
4
+ name: z.ZodString;
5
+ description: z.ZodString;
6
+ layers: z.ZodRecord<z.ZodString, z.ZodObject<{
7
+ patterns: z.ZodArray<z.ZodString>;
8
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString>>;
9
+ description: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>>;
11
+ }, z.core.$strip>;
12
+ export type TemplateFile = z.infer<typeof TemplateFileSchema>;
13
+ export interface LoadedTemplate {
14
+ name: ArchitectureTemplate;
15
+ description: string;
16
+ layers: Record<string, LayerDefinition>;
17
+ }
18
+ export declare class TemplateLoader {
19
+ private cache;
20
+ private templatesDir;
21
+ constructor(templatesDir?: string);
22
+ list(): Promise<ArchitectureTemplate[]>;
23
+ get(name: ArchitectureTemplate): Promise<LoadedTemplate>;
24
+ validate(name: ArchitectureTemplate): Promise<{
25
+ valid: boolean;
26
+ errors: string[];
27
+ }>;
28
+ getAll(): Promise<LoadedTemplate[]>;
29
+ clearCache(): void;
30
+ }
31
+ export declare function getTemplateLoader(): TemplateLoader;
32
+ export declare function listTemplates(): Promise<ArchitectureTemplate[]>;
33
+ export declare function getTemplate(name: ArchitectureTemplate): Promise<LoadedTemplate>;
34
+ export declare function validateTemplate(name: ArchitectureTemplate): Promise<{
35
+ valid: boolean;
36
+ errors: string[];
37
+ }>;
38
+ export {};
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/architecture/templates/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAWrF,QAAA,MAAM,kBAAkB;;;;;;;;iBAItB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CACzC;AAaD,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,YAAY,CAAS;gBAEjB,YAAY,CAAC,EAAE,MAAM;IAI3B,IAAI,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAcvC,GAAG,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAsCxD,QAAQ,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IA0BnF,MAAM,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAKzC,UAAU,IAAI,IAAI;CAGnB;AAID,wBAAgB,iBAAiB,IAAI,cAAc,CAKlD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAErE;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAErF;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAE/C"}
@@ -0,0 +1,124 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import YAML from 'yaml';
5
+ import { z } from 'zod';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ const TemplateLayerSchema = z.object({
9
+ patterns: z.array(z.string()),
10
+ depends_on: z.array(z.string()).default([]),
11
+ description: z.string().optional(),
12
+ });
13
+ const TemplateFileSchema = z.object({
14
+ name: z.string(),
15
+ description: z.string(),
16
+ layers: z.record(z.string(), TemplateLayerSchema),
17
+ });
18
+ const TEMPLATE_FILES = {
19
+ starter: 'starter.yaml',
20
+ layered: 'layered.yaml',
21
+ hexagonal: 'hexagonal.yaml',
22
+ clean: 'clean.yaml',
23
+ ddd: 'ddd.yaml',
24
+ monorepo: 'monorepo.yaml',
25
+ serverless: 'serverless.yaml',
26
+ 'nx-workspace': 'nx-workspace.yaml',
27
+ };
28
+ export class TemplateLoader {
29
+ cache = new Map();
30
+ templatesDir;
31
+ constructor(templatesDir) {
32
+ this.templatesDir = templatesDir ?? __dirname;
33
+ }
34
+ async list() {
35
+ return [
36
+ 'starter',
37
+ 'layered',
38
+ 'hexagonal',
39
+ 'clean',
40
+ 'ddd',
41
+ 'monorepo',
42
+ 'serverless',
43
+ 'nx-workspace',
44
+ 'custom',
45
+ ];
46
+ }
47
+ async get(name) {
48
+ if (name === 'custom') {
49
+ return {
50
+ name: 'custom',
51
+ description: 'Empty template for custom architecture definitions',
52
+ layers: {},
53
+ };
54
+ }
55
+ const cached = this.cache.get(name);
56
+ if (cached) {
57
+ return cached;
58
+ }
59
+ const filename = TEMPLATE_FILES[name];
60
+ if (!filename) {
61
+ throw new Error(`Unknown template: ${name}`);
62
+ }
63
+ const filePath = join(this.templatesDir, filename);
64
+ const content = await readFile(filePath, 'utf-8');
65
+ const parsed = YAML.parse(content);
66
+ const validated = TemplateFileSchema.safeParse(parsed);
67
+ if (!validated.success) {
68
+ throw new Error(`Invalid template file ${filename}: ${validated.error.message}`);
69
+ }
70
+ const template = {
71
+ name,
72
+ description: validated.data.description,
73
+ layers: validated.data.layers,
74
+ };
75
+ this.cache.set(name, template);
76
+ return template;
77
+ }
78
+ async validate(name) {
79
+ try {
80
+ const template = await this.get(name);
81
+ const errors = [];
82
+ for (const [layerName, layer] of Object.entries(template.layers)) {
83
+ for (const dep of layer.depends_on) {
84
+ if (!template.layers[dep]) {
85
+ errors.push(`Layer "${layerName}" depends on unknown layer "${dep}"`);
86
+ }
87
+ }
88
+ if (layer.patterns.length === 0) {
89
+ errors.push(`Layer "${layerName}" has no patterns defined`);
90
+ }
91
+ }
92
+ return { valid: errors.length === 0, errors };
93
+ }
94
+ catch (err) {
95
+ return {
96
+ valid: false,
97
+ errors: [err instanceof Error ? err.message : 'Unknown error'],
98
+ };
99
+ }
100
+ }
101
+ async getAll() {
102
+ const names = await this.list();
103
+ return Promise.all(names.map((name) => this.get(name)));
104
+ }
105
+ clearCache() {
106
+ this.cache.clear();
107
+ }
108
+ }
109
+ let defaultLoader = null;
110
+ export function getTemplateLoader() {
111
+ if (!defaultLoader) {
112
+ defaultLoader = new TemplateLoader();
113
+ }
114
+ return defaultLoader;
115
+ }
116
+ export async function listTemplates() {
117
+ return getTemplateLoader().list();
118
+ }
119
+ export async function getTemplate(name) {
120
+ return getTemplateLoader().get(name);
121
+ }
122
+ export async function validateTemplate(name) {
123
+ return getTemplateLoader().validate(name);
124
+ }
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Architecture baseline types
3
+ *
4
+ * Defines the schema for .anvil/architecture.json - the architecture baseline
5
+ * that enables NEW vs existing violation detection.
6
+ */
7
+ import { z } from 'zod';
8
+ /**
9
+ * Entry point types detected in the codebase
10
+ */
11
+ export declare const EntryPointTypeSchema: z.ZodEnum<{
12
+ unknown: "unknown";
13
+ cli: "cli";
14
+ api: "api";
15
+ test: "test";
16
+ package: "package";
17
+ application: "application";
18
+ http: "http";
19
+ worker: "worker";
20
+ }>;
21
+ export type EntryPointType = z.infer<typeof EntryPointTypeSchema>;
22
+ /**
23
+ * Confidence level for detection
24
+ */
25
+ export declare const DetectionConfidenceSchema: z.ZodEnum<{
26
+ high: "high";
27
+ medium: "medium";
28
+ low: "low";
29
+ }>;
30
+ export type DetectionConfidence = z.infer<typeof DetectionConfidenceSchema>;
31
+ /**
32
+ * A detected entry point in the codebase
33
+ */
34
+ export declare const EntryPointSchema: z.ZodObject<{
35
+ path: z.ZodString;
36
+ type: z.ZodEnum<{
37
+ unknown: "unknown";
38
+ cli: "cli";
39
+ api: "api";
40
+ test: "test";
41
+ package: "package";
42
+ application: "application";
43
+ http: "http";
44
+ worker: "worker";
45
+ }>;
46
+ confidence: z.ZodEnum<{
47
+ high: "high";
48
+ medium: "medium";
49
+ low: "low";
50
+ }>;
51
+ exports: z.ZodOptional<z.ZodArray<z.ZodString>>;
52
+ }, z.core.$strip>;
53
+ export type EntryPoint = z.infer<typeof EntryPointSchema>;
54
+ /**
55
+ * Standard layer names (can be extended)
56
+ */
57
+ export declare const StandardLayerSchema: z.ZodEnum<{
58
+ application: "application";
59
+ presentation: "presentation";
60
+ domain: "domain";
61
+ infrastructure: "infrastructure";
62
+ shared: "shared";
63
+ }>;
64
+ export type StandardLayer = z.infer<typeof StandardLayerSchema>;
65
+ /**
66
+ * Layer definition with dependency rules
67
+ */
68
+ export declare const LayerSchema: z.ZodObject<{
69
+ patterns: z.ZodArray<z.ZodString>;
70
+ depends_on: z.ZodArray<z.ZodString>;
71
+ description: z.ZodOptional<z.ZodString>;
72
+ }, z.core.$strip>;
73
+ export type Layer = z.infer<typeof LayerSchema>;
74
+ /**
75
+ * Map of layer name to layer definition
76
+ */
77
+ export declare const LayersSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
78
+ patterns: z.ZodArray<z.ZodString>;
79
+ depends_on: z.ZodArray<z.ZodString>;
80
+ description: z.ZodOptional<z.ZodString>;
81
+ }, z.core.$strip>>;
82
+ export type Layers = z.infer<typeof LayersSchema>;
83
+ /**
84
+ * Explicit boundary rule
85
+ */
86
+ export declare const BoundarySchema: z.ZodObject<{
87
+ name: z.ZodString;
88
+ from: z.ZodString;
89
+ to: z.ZodString;
90
+ severity: z.ZodEnum<{
91
+ warning: "warning";
92
+ error: "error";
93
+ info: "info";
94
+ }>;
95
+ message: z.ZodString;
96
+ confidence: z.ZodOptional<z.ZodEnum<{
97
+ high: "high";
98
+ medium: "medium";
99
+ low: "low";
100
+ }>>;
101
+ }, z.core.$strip>;
102
+ export type Boundary = z.infer<typeof BoundarySchema>;
103
+ /**
104
+ * A recorded violation in the baseline
105
+ */
106
+ export declare const BaselineViolationSchema: z.ZodObject<{
107
+ id: z.ZodString;
108
+ from_layer: z.ZodString;
109
+ to_layer: z.ZodString;
110
+ from_file: z.ZodString;
111
+ to_file: z.ZodString;
112
+ import_line: z.ZodNumber;
113
+ rule: z.ZodOptional<z.ZodString>;
114
+ }, z.core.$strip>;
115
+ export type BaselineViolation = z.infer<typeof BaselineViolationSchema>;
116
+ /**
117
+ * Snapshot of the architecture state at baseline time
118
+ */
119
+ export declare const BaselineSnapshotSchema: z.ZodObject<{
120
+ module_count: z.ZodNumber;
121
+ timestamp: z.ZodString;
122
+ violations: z.ZodArray<z.ZodObject<{
123
+ id: z.ZodString;
124
+ from_layer: z.ZodString;
125
+ to_layer: z.ZodString;
126
+ from_file: z.ZodString;
127
+ to_file: z.ZodString;
128
+ import_line: z.ZodNumber;
129
+ rule: z.ZodOptional<z.ZodString>;
130
+ }, z.core.$strip>>;
131
+ }, z.core.$strip>;
132
+ export type BaselineSnapshot = z.infer<typeof BaselineSnapshotSchema>;
133
+ /**
134
+ * Complete architecture baseline stored in .anvil/architecture.json
135
+ */
136
+ export declare const ArchitectureBaselineSchema: z.ZodObject<{
137
+ schema_version: z.ZodLiteral<"0.1.0">;
138
+ created_at: z.ZodString;
139
+ updated_at: z.ZodString;
140
+ entry_points: z.ZodArray<z.ZodObject<{
141
+ path: z.ZodString;
142
+ type: z.ZodEnum<{
143
+ unknown: "unknown";
144
+ cli: "cli";
145
+ api: "api";
146
+ test: "test";
147
+ package: "package";
148
+ application: "application";
149
+ http: "http";
150
+ worker: "worker";
151
+ }>;
152
+ confidence: z.ZodEnum<{
153
+ high: "high";
154
+ medium: "medium";
155
+ low: "low";
156
+ }>;
157
+ exports: z.ZodOptional<z.ZodArray<z.ZodString>>;
158
+ }, z.core.$strip>>;
159
+ layers: z.ZodRecord<z.ZodString, z.ZodObject<{
160
+ patterns: z.ZodArray<z.ZodString>;
161
+ depends_on: z.ZodArray<z.ZodString>;
162
+ description: z.ZodOptional<z.ZodString>;
163
+ }, z.core.$strip>>;
164
+ boundaries: z.ZodArray<z.ZodObject<{
165
+ name: z.ZodString;
166
+ from: z.ZodString;
167
+ to: z.ZodString;
168
+ severity: z.ZodEnum<{
169
+ warning: "warning";
170
+ error: "error";
171
+ info: "info";
172
+ }>;
173
+ message: z.ZodString;
174
+ confidence: z.ZodOptional<z.ZodEnum<{
175
+ high: "high";
176
+ medium: "medium";
177
+ low: "low";
178
+ }>>;
179
+ }, z.core.$strip>>;
180
+ baseline_snapshot: z.ZodObject<{
181
+ module_count: z.ZodNumber;
182
+ timestamp: z.ZodString;
183
+ violations: z.ZodArray<z.ZodObject<{
184
+ id: z.ZodString;
185
+ from_layer: z.ZodString;
186
+ to_layer: z.ZodString;
187
+ from_file: z.ZodString;
188
+ to_file: z.ZodString;
189
+ import_line: z.ZodNumber;
190
+ rule: z.ZodOptional<z.ZodString>;
191
+ }, z.core.$strip>>;
192
+ }, z.core.$strip>;
193
+ }, z.core.$strip>;
194
+ export type ArchitectureBaseline = z.infer<typeof ArchitectureBaselineSchema>;
195
+ /**
196
+ * Result of layer detection for a file
197
+ */
198
+ export declare const LayerAssignmentSchema: z.ZodObject<{
199
+ file: z.ZodString;
200
+ layer: z.ZodNullable<z.ZodString>;
201
+ confidence: z.ZodEnum<{
202
+ high: "high";
203
+ medium: "medium";
204
+ low: "low";
205
+ }>;
206
+ matched_pattern: z.ZodOptional<z.ZodString>;
207
+ }, z.core.$strip>;
208
+ export type LayerAssignment = z.infer<typeof LayerAssignmentSchema>;
209
+ /**
210
+ * A dependency edge between two files
211
+ */
212
+ export declare const DependencyEdgeSchema: z.ZodObject<{
213
+ from: z.ZodString;
214
+ to: z.ZodString;
215
+ from_layer: z.ZodNullable<z.ZodString>;
216
+ to_layer: z.ZodNullable<z.ZodString>;
217
+ line: z.ZodNumber;
218
+ type: z.ZodEnum<{
219
+ import: "import";
220
+ require: "require";
221
+ dynamic: "dynamic";
222
+ }>;
223
+ }, z.core.$strip>;
224
+ export type DependencyEdge = z.infer<typeof DependencyEdgeSchema>;
225
+ /**
226
+ * A detected boundary violation
227
+ */
228
+ export declare const BoundaryViolationSchema: z.ZodObject<{
229
+ edge: z.ZodObject<{
230
+ from: z.ZodString;
231
+ to: z.ZodString;
232
+ from_layer: z.ZodNullable<z.ZodString>;
233
+ to_layer: z.ZodNullable<z.ZodString>;
234
+ line: z.ZodNumber;
235
+ type: z.ZodEnum<{
236
+ import: "import";
237
+ require: "require";
238
+ dynamic: "dynamic";
239
+ }>;
240
+ }, z.core.$strip>;
241
+ boundary: z.ZodOptional<z.ZodObject<{
242
+ name: z.ZodString;
243
+ from: z.ZodString;
244
+ to: z.ZodString;
245
+ severity: z.ZodEnum<{
246
+ warning: "warning";
247
+ error: "error";
248
+ info: "info";
249
+ }>;
250
+ message: z.ZodString;
251
+ confidence: z.ZodOptional<z.ZodEnum<{
252
+ high: "high";
253
+ medium: "medium";
254
+ low: "low";
255
+ }>>;
256
+ }, z.core.$strip>>;
257
+ is_new: z.ZodBoolean;
258
+ baseline_id: z.ZodOptional<z.ZodString>;
259
+ }, z.core.$strip>;
260
+ export type BoundaryViolation = z.infer<typeof BoundaryViolationSchema>;
261
+ /**
262
+ * Create a violation ID from edge details
263
+ */
264
+ export declare function createViolationId(fromFile: string, toFile: string, line: number): string;
265
+ /**
266
+ * Check if a violation exists in the baseline
267
+ */
268
+ export declare function isExistingViolation(violation: BoundaryViolation, baseline: BaselineSnapshot): boolean;
269
+ /**
270
+ * Create default layer structure for common patterns.
271
+ *
272
+ * Patterns use **\/ prefix to match files in any directory structure,
273
+ * supporting both single-app (src/) and monorepo (packages/star/src/) layouts.
274
+ */
275
+ export declare function createDefaultLayers(): Layers;
276
+ /**
277
+ * Create default boundaries from layer structure
278
+ */
279
+ export declare function createDefaultBoundaries(layers: Layers): Boundary[];
280
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/architecture/types.ts"],"names":[],"mappings":"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"}