@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,261 @@
1
+ import { registerTemplate } from './template-loader.js';
2
+ const ARCH_RULES = {
3
+ 'ARCH-001': {
4
+ id: 'ARCH-001',
5
+ name: 'Circular dependency',
6
+ description: 'A circular dependency chain was detected in imports.',
7
+ },
8
+ 'ARCH-002': {
9
+ id: 'ARCH-002',
10
+ name: 'Orphan module',
11
+ description: 'This module is not imported by any other module.',
12
+ },
13
+ 'ARCH-003': {
14
+ id: 'ARCH-003',
15
+ name: 'Layer boundary violation',
16
+ description: 'An import crosses an architectural layer boundary.',
17
+ },
18
+ 'ARCH-004': {
19
+ id: 'ARCH-004',
20
+ name: 'Architecture violation',
21
+ description: 'General architecture rule violation detected.',
22
+ },
23
+ 'BOUND-001': {
24
+ id: 'BOUND-001',
25
+ name: 'Boundary violation',
26
+ description: 'A new cross-boundary dependency was detected.',
27
+ },
28
+ };
29
+ function createBoundaryExplanation(ruleId, context) {
30
+ const ruleInfo = ARCH_RULES[ruleId];
31
+ if (!ruleInfo) {
32
+ return createFallbackExplanation(ruleId, context);
33
+ }
34
+ const locationSummary = formatLocationSummary(ruleId, context);
35
+ return {
36
+ ruleId,
37
+ title: ruleInfo.name,
38
+ summary: locationSummary,
39
+ whyItMatters: {
40
+ title: 'WHY THIS WARNING EXISTS',
41
+ content: getWhyContent(ruleId, context),
42
+ },
43
+ howToAddress: {
44
+ title: 'HOW TO ADDRESS',
45
+ content: getHowContent(ruleId, context),
46
+ },
47
+ whenToSuppress: {
48
+ title: 'WHEN TO SUPPRESS',
49
+ content: getWhenToSuppressContent(ruleId),
50
+ },
51
+ related: {
52
+ ruleDefinition: `${ruleId} in architecture rules`,
53
+ similarWarnings: context.similarCount,
54
+ },
55
+ };
56
+ }
57
+ function formatLocationSummary(ruleId, context) {
58
+ if (context.fromFile && context.toFile) {
59
+ return `${context.fromFile} → ${context.toFile}`;
60
+ }
61
+ return `${ruleId} at ${context.file}:${context.line}`;
62
+ }
63
+ function getWhyContent(ruleId, context) {
64
+ const layerContext = context.fromLayer && context.toLayer
65
+ ? `\n\nIn this case, ${context.fromLayer} is importing from ${context.toLayer}.`
66
+ : '';
67
+ const whyContent = {
68
+ 'ARCH-001': `
69
+ Circular dependencies create tightly coupled code that is:
70
+
71
+ - Difficult to test in isolation
72
+ - Hard to understand (dependencies loop back)
73
+ - Prone to initialisation order bugs
74
+ - Resistant to refactoring
75
+
76
+ The dependency chain forms a cycle, meaning module A depends on B,
77
+ which depends on C, which depends back on A.${layerContext}`,
78
+ 'ARCH-002': `
79
+ Orphan modules are files that no other code imports. This may indicate:
80
+
81
+ - Dead code that should be removed
82
+ - Missing integration (forgot to wire it up)
83
+ - Incorrect file organisation
84
+ - A utility that lost its callers after refactoring
85
+
86
+ While not always a problem, orphans often represent unused code
87
+ that adds maintenance burden.`,
88
+ 'ARCH-003': `
89
+ This import violates defined layer boundaries. Layer violations:
90
+
91
+ - Break architectural contracts
92
+ - Create hidden dependencies
93
+ - Make changes risky (unknown blast radius)
94
+ - Complicate testing and deployment${layerContext}`,
95
+ 'ARCH-004': `
96
+ This code violates an architecture rule defined for your project.
97
+
98
+ Architecture rules exist to:
99
+ - Enforce separation of concerns
100
+ - Prevent coupling between unrelated modules
101
+ - Maintain clear dependency direction
102
+ - Enable independent testing and deployment${layerContext}`,
103
+ 'BOUND-001': `
104
+ A NEW cross-boundary dependency was introduced. This means code
105
+ that previously didn't exist is now crossing an architectural boundary.
106
+
107
+ New boundary violations are significant because:
108
+ - They indicate potential architecture drift
109
+ - The change was made without considering boundaries
110
+ - They may create precedent for further violations${layerContext}`,
111
+ };
112
+ return (whyContent[ruleId] ?? ARCH_RULES[ruleId]?.description ?? 'Architecture violation detected.');
113
+ }
114
+ function getHowContent(ruleId, context) {
115
+ const howContent = {
116
+ 'ARCH-001': `
117
+ 1. Identify the cycle
118
+ Look at the import chain to understand how modules connect
119
+
120
+ 2. Break the cycle using one of these patterns:
121
+ - Extract shared code to a common module
122
+ - Use dependency injection
123
+ - Introduce an interface/abstraction layer
124
+ - Merge tightly coupled modules
125
+
126
+ 3. Consider if the modules should be combined
127
+ Sometimes circular deps indicate a single concept split artificially`,
128
+ 'ARCH-002': `
129
+ 1. Verify the module is actually unused
130
+ Search for dynamic imports or test files that might use it
131
+
132
+ 2. If unused, consider removing it
133
+ Dead code adds maintenance burden
134
+
135
+ 3. If it should be used, add the missing integration
136
+ Wire it into the appropriate consumer
137
+
138
+ 4. If it's a utility, document its purpose
139
+ Make sure others know it exists and when to use it`,
140
+ 'ARCH-003': `
141
+ 1. Understand the layer structure
142
+ Review which layer should depend on which
143
+
144
+ 2. Consider using an intermediary
145
+ If presentation needs data, go through application layer
146
+
147
+ 3. Move the code to the appropriate layer
148
+ Sometimes code is in the wrong place
149
+
150
+ 4. Use dependency inversion
151
+ Depend on abstractions, not concretions`,
152
+ 'ARCH-004': `
153
+ 1. Review the architecture rule being violated
154
+ Understand why the rule exists
155
+
156
+ 2. Determine if the violation is intentional
157
+ Sometimes rules need exceptions
158
+
159
+ 3. Refactor to comply with the rule
160
+ Or propose a rule change if it's outdated`,
161
+ 'BOUND-001': `
162
+ 1. Understand what boundary was crossed
163
+ ${context.fromLayer ? `From: ${context.fromLayer}` : ''}
164
+ ${context.toLayer ? `To: ${context.toLayer}` : ''}
165
+
166
+ 2. Consider the proper path
167
+ Is there an existing service or abstraction to use?
168
+
169
+ 3. If the boundary is wrong, update architecture
170
+ Boundaries should reflect actual needs
171
+
172
+ 4. If crossing is necessary, suppress with explanation
173
+ Document why this exception exists`,
174
+ };
175
+ return howContent[ruleId] ?? 'Review the architecture and consider refactoring.';
176
+ }
177
+ function getWhenToSuppressContent(ruleId) {
178
+ const suppressionContent = {
179
+ 'ARCH-001': `
180
+ Suppress only if:
181
+ - The cycle is intentional and well-understood
182
+ - Breaking it would require major refactoring with a planned ticket
183
+ - The modules are conceptually a single unit
184
+
185
+ Example:
186
+ // @anvil-ignore ARCH-001: mutually recursive parsers, by design`,
187
+ 'ARCH-002': `
188
+ Suppress only if:
189
+ - The module is a valid entry point (e.g., CLI, test setup)
190
+ - It's dynamically imported in ways not detected
191
+ - It's intentionally a standalone utility
192
+
193
+ Example:
194
+ // @anvil-ignore ARCH-002: CLI entry point, not imported`,
195
+ 'ARCH-003': `
196
+ Suppress only if:
197
+ - The layer structure doesn't fit this use case
198
+ - You're actively migrating and have a ticket
199
+ - This is a pragmatic exception with clear reasoning
200
+
201
+ Example:
202
+ // @anvil-ignore ARCH-003: legacy code, migrating in JIRA-789`,
203
+ 'ARCH-004': `
204
+ Suppress only if:
205
+ - The rule is overly strict for this case
206
+ - A rule change is pending
207
+ - This is a documented exception
208
+
209
+ Example:
210
+ // @anvil-ignore ARCH-004: approved exception per ADR-042`,
211
+ 'BOUND-001': `
212
+ Suppress only if:
213
+ - The new dependency is intentional and reviewed
214
+ - The architecture definition needs updating
215
+ - This is a temporary bridge during migration
216
+
217
+ Example:
218
+ // @anvil-ignore BOUND-001: approved in PR review, updating baseline`,
219
+ };
220
+ return (suppressionContent[ruleId] ??
221
+ `
222
+ Suppress only with clear justification.
223
+ Use: // @anvil-ignore ${ruleId}: [your reason]`);
224
+ }
225
+ function createFallbackExplanation(ruleId, context) {
226
+ return {
227
+ ruleId,
228
+ title: `Architecture violation ${ruleId}`,
229
+ summary: `Violation at ${context.file}:${context.line}`,
230
+ whyItMatters: {
231
+ title: 'WHY THIS WARNING EXISTS',
232
+ content: 'This warning indicates an architecture boundary violation.',
233
+ },
234
+ howToAddress: {
235
+ title: 'HOW TO ADDRESS',
236
+ content: 'Review the architecture and consider refactoring.',
237
+ },
238
+ whenToSuppress: {
239
+ title: 'WHEN TO SUPPRESS',
240
+ content: `Use: // @anvil-ignore ${ruleId}: [reason]`,
241
+ },
242
+ };
243
+ }
244
+ export function registerBoundaryTemplates() {
245
+ for (const ruleId of Object.keys(ARCH_RULES)) {
246
+ const template = {
247
+ ruleId,
248
+ render: (context) => createBoundaryExplanation(ruleId, context),
249
+ };
250
+ registerTemplate(template);
251
+ }
252
+ }
253
+ export function getBoundaryExplanation(ruleId, context) {
254
+ if (!ARCH_RULES[ruleId]) {
255
+ return null;
256
+ }
257
+ return createBoundaryExplanation(ruleId, context);
258
+ }
259
+ export function isArchitectureRule(ruleId) {
260
+ return ruleId in ARCH_RULES;
261
+ }
@@ -0,0 +1,19 @@
1
+ import type { Warning } from '../antipattern/types.js';
2
+ import type { ExplanationContext, WarningExplanation } from './types.js';
3
+ export declare function resetExplainService(): void;
4
+ export declare function initExplainService(): void;
5
+ export declare function explainWarning(warning: Warning, allWarnings?: Warning[]): WarningExplanation;
6
+ export declare function explainById(warningId: string, warnings: Warning[]): WarningExplanation | null;
7
+ export declare function explainByRule(ruleId: string, context?: Partial<ExplanationContext>): WarningExplanation | null;
8
+ export interface ListWarningsResult {
9
+ warningId: string;
10
+ ruleId: string;
11
+ file: string;
12
+ line: number;
13
+ title: string;
14
+ severity: string;
15
+ }
16
+ export declare function listWarnings(warnings: Warning[]): ListWarningsResult[];
17
+ export declare function isExplainable(ruleId: string): boolean;
18
+ export declare function getExplainableRules(): string[];
19
+ //# sourceMappingURL=explain-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain-service.d.ts","sourceRoot":"","sources":["../../src/explain/explain-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA+BzE,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAoBD,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAkB5F;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,kBAAkB,GAAG,IAAI,CAgB7F;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACpC,kBAAkB,GAAG,IAAI,CAuB3B;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,kBAAkB,EAAE,CAWtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGrD;AAED,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAK9C"}
@@ -0,0 +1,106 @@
1
+ import { hasTemplate, renderExplanation, createGenericExplanation, clearTemplates, } from './template-loader.js';
2
+ import { registerAntiPatternTemplates } from './antipattern-explainer.js';
3
+ import { registerBoundaryTemplates, isArchitectureRule } from './boundary-explainer.js';
4
+ import { parseWarningId, findWarningById, findWarningsByRule, getWarningIds, } from '../warnings/warning-id.js';
5
+ import { getPattern } from '../antipattern/patterns.js';
6
+ import { createDebugger } from '../utils/debug.js';
7
+ const debug = createDebugger('explain');
8
+ let templatesInitialised = false;
9
+ function ensureTemplatesInitialised() {
10
+ if (!templatesInitialised) {
11
+ clearTemplates();
12
+ registerAntiPatternTemplates();
13
+ registerBoundaryTemplates();
14
+ templatesInitialised = true;
15
+ }
16
+ }
17
+ export function resetExplainService() {
18
+ clearTemplates();
19
+ templatesInitialised = false;
20
+ }
21
+ export function initExplainService() {
22
+ ensureTemplatesInitialised();
23
+ }
24
+ function buildContext(warning, allWarnings) {
25
+ const context = {
26
+ file: warning.location.file,
27
+ line: warning.location.line,
28
+ patternName: warning.pattern,
29
+ };
30
+ if (allWarnings) {
31
+ const sameRuleWarnings = findWarningsByRule(allWarnings, warning.id);
32
+ const sameFileWarnings = sameRuleWarnings.filter((w) => w.location.file === warning.location.file);
33
+ context.similarCount = sameFileWarnings.length - 1;
34
+ }
35
+ return context;
36
+ }
37
+ export function explainWarning(warning, allWarnings) {
38
+ debug('explaining warning', {
39
+ id: warning.id,
40
+ file: warning.location.file,
41
+ line: warning.location.line,
42
+ });
43
+ ensureTemplatesInitialised();
44
+ const context = buildContext(warning, allWarnings);
45
+ if (hasTemplate(warning.id)) {
46
+ const explanation = renderExplanation(warning.id, context);
47
+ if (explanation) {
48
+ return explanation;
49
+ }
50
+ }
51
+ return createGenericExplanation(warning.id, warning.title, context);
52
+ }
53
+ export function explainById(warningId, warnings) {
54
+ debug('explaining by id', warningId);
55
+ ensureTemplatesInitialised();
56
+ const parsed = parseWarningId(warningId);
57
+ if (!parsed) {
58
+ debug('invalid warning id format', warningId);
59
+ return null;
60
+ }
61
+ const warning = findWarningById(warnings, warningId);
62
+ if (!warning) {
63
+ return null;
64
+ }
65
+ return explainWarning(warning, warnings);
66
+ }
67
+ export function explainByRule(ruleId, context) {
68
+ ensureTemplatesInitialised();
69
+ const fullContext = {
70
+ file: context?.file ?? 'unknown',
71
+ line: context?.line ?? 1,
72
+ ...context,
73
+ };
74
+ if (hasTemplate(ruleId)) {
75
+ return renderExplanation(ruleId, fullContext);
76
+ }
77
+ const pattern = getPattern(ruleId);
78
+ if (pattern) {
79
+ return renderExplanation(ruleId, fullContext);
80
+ }
81
+ if (isArchitectureRule(ruleId)) {
82
+ return renderExplanation(ruleId, fullContext);
83
+ }
84
+ return null;
85
+ }
86
+ export function listWarnings(warnings) {
87
+ const warningIds = getWarningIds(warnings);
88
+ return warnings.map((w, i) => ({
89
+ warningId: warningIds[i],
90
+ ruleId: w.id,
91
+ file: w.location.file,
92
+ line: w.location.line,
93
+ title: w.title,
94
+ severity: w.severity,
95
+ }));
96
+ }
97
+ export function isExplainable(ruleId) {
98
+ ensureTemplatesInitialised();
99
+ return hasTemplate(ruleId);
100
+ }
101
+ export function getExplainableRules() {
102
+ ensureTemplatesInitialised();
103
+ const antiPatternIds = ['AP-001', 'AP-002', 'AP-003', 'AP-004', 'AP-005', 'AP-006', 'AP-007'];
104
+ const archIds = ['ARCH-001', 'ARCH-002', 'ARCH-003', 'ARCH-004', 'BOUND-001'];
105
+ return [...antiPatternIds, ...archIds];
106
+ }
@@ -0,0 +1,7 @@
1
+ export type { ExplanationSection, WarningExplanation, ExplanationContext, ExplanationTemplate, } from './types.js';
2
+ export { ExplanationSectionSchema, WarningExplanationSchema, ExplanationContextSchema, } from './types.js';
3
+ export { registerTemplate, getTemplate, hasTemplate, getRegisteredRuleIds, renderExplanation, clearTemplates, createGenericExplanation, } from './template-loader.js';
4
+ export { registerAntiPatternTemplates, getAntiPatternExplanation, } from './antipattern-explainer.js';
5
+ export { registerBoundaryTemplates, getBoundaryExplanation, isArchitectureRule, } from './boundary-explainer.js';
6
+ export { resetExplainService, initExplainService, explainWarning, explainById, explainByRule, listWarnings, isExplainable, getExplainableRules, type ListWarningsResult, } from './explain-service.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/explain/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,cAAc,EACd,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,aAAa,EACb,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { ExplanationSectionSchema, WarningExplanationSchema, ExplanationContextSchema, } from './types.js';
2
+ export { registerTemplate, getTemplate, hasTemplate, getRegisteredRuleIds, renderExplanation, clearTemplates, createGenericExplanation, } from './template-loader.js';
3
+ export { registerAntiPatternTemplates, getAntiPatternExplanation, } from './antipattern-explainer.js';
4
+ export { registerBoundaryTemplates, getBoundaryExplanation, isArchitectureRule, } from './boundary-explainer.js';
5
+ export { resetExplainService, initExplainService, explainWarning, explainById, explainByRule, listWarnings, isExplainable, getExplainableRules, } from './explain-service.js';
@@ -0,0 +1,9 @@
1
+ import type { ExplanationTemplate, ExplanationContext, WarningExplanation } from './types.js';
2
+ export declare function registerTemplate(template: ExplanationTemplate): void;
3
+ export declare function getTemplate(ruleId: string): ExplanationTemplate | undefined;
4
+ export declare function hasTemplate(ruleId: string): boolean;
5
+ export declare function getRegisteredRuleIds(): string[];
6
+ export declare function renderExplanation(ruleId: string, context: ExplanationContext): WarningExplanation | null;
7
+ export declare function clearTemplates(): void;
8
+ export declare function createGenericExplanation(ruleId: string, title: string, context: ExplanationContext): WarningExplanation;
9
+ //# sourceMappingURL=template-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-loader.d.ts","sourceRoot":"","sources":["../../src/explain/template-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAO9F,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAGpE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAE3E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAE/C;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,GAAG,IAAI,CAO3B;AAED,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,kBAAkB,GAC1B,kBAAkB,CA0BpB"}
@@ -0,0 +1,51 @@
1
+ import { createDebugger } from '../utils/debug.js';
2
+ const debug = createDebugger('explain');
3
+ const templateRegistry = new Map();
4
+ export function registerTemplate(template) {
5
+ debug('registering template', template.ruleId);
6
+ templateRegistry.set(template.ruleId, template);
7
+ }
8
+ export function getTemplate(ruleId) {
9
+ return templateRegistry.get(ruleId);
10
+ }
11
+ export function hasTemplate(ruleId) {
12
+ return templateRegistry.has(ruleId);
13
+ }
14
+ export function getRegisteredRuleIds() {
15
+ return Array.from(templateRegistry.keys());
16
+ }
17
+ export function renderExplanation(ruleId, context) {
18
+ const template = templateRegistry.get(ruleId);
19
+ if (!template) {
20
+ debug('no template found for rule', ruleId);
21
+ return null;
22
+ }
23
+ return template.render(context);
24
+ }
25
+ export function clearTemplates() {
26
+ templateRegistry.clear();
27
+ }
28
+ export function createGenericExplanation(ruleId, title, context) {
29
+ return {
30
+ ruleId,
31
+ title,
32
+ summary: `Warning ${ruleId} detected at ${context.file}:${context.line}`,
33
+ whyItMatters: {
34
+ title: 'WHY THIS WARNING EXISTS',
35
+ content: 'This warning indicates a potential issue in your code. ' +
36
+ 'Please refer to the warning message for specific details.',
37
+ },
38
+ howToAddress: {
39
+ title: 'HOW TO ADDRESS',
40
+ content: 'Review the flagged code and consider the warning message. ' +
41
+ 'Determine if changes are needed based on your project requirements.',
42
+ },
43
+ whenToSuppress: {
44
+ title: 'WHEN TO SUPPRESS',
45
+ content: 'Suppress only if you understand the warning and have a valid reason. ' +
46
+ 'Use: // @anvil-ignore ' +
47
+ ruleId +
48
+ ': [your reason]',
49
+ },
50
+ };
51
+ }
@@ -0,0 +1,46 @@
1
+ import { z } from 'zod';
2
+ export declare const ExplanationSectionSchema: z.ZodObject<{
3
+ title: z.ZodString;
4
+ content: z.ZodString;
5
+ }, z.core.$strip>;
6
+ export type ExplanationSection = z.infer<typeof ExplanationSectionSchema>;
7
+ export declare const WarningExplanationSchema: z.ZodObject<{
8
+ ruleId: z.ZodString;
9
+ title: z.ZodString;
10
+ summary: z.ZodString;
11
+ whyItMatters: z.ZodObject<{
12
+ title: z.ZodString;
13
+ content: z.ZodString;
14
+ }, z.core.$strip>;
15
+ howToAddress: z.ZodObject<{
16
+ title: z.ZodString;
17
+ content: z.ZodString;
18
+ }, z.core.$strip>;
19
+ whenToSuppress: z.ZodObject<{
20
+ title: z.ZodString;
21
+ content: z.ZodString;
22
+ }, z.core.$strip>;
23
+ related: z.ZodOptional<z.ZodObject<{
24
+ documentation: z.ZodOptional<z.ZodString>;
25
+ ruleDefinition: z.ZodOptional<z.ZodString>;
26
+ similarWarnings: z.ZodOptional<z.ZodNumber>;
27
+ }, z.core.$strip>>;
28
+ }, z.core.$strip>;
29
+ export type WarningExplanation = z.infer<typeof WarningExplanationSchema>;
30
+ export declare const ExplanationContextSchema: z.ZodObject<{
31
+ file: z.ZodString;
32
+ line: z.ZodNumber;
33
+ code: z.ZodOptional<z.ZodString>;
34
+ fromFile: z.ZodOptional<z.ZodString>;
35
+ toFile: z.ZodOptional<z.ZodString>;
36
+ fromLayer: z.ZodOptional<z.ZodString>;
37
+ toLayer: z.ZodOptional<z.ZodString>;
38
+ patternName: z.ZodOptional<z.ZodString>;
39
+ similarCount: z.ZodOptional<z.ZodNumber>;
40
+ }, z.core.$strip>;
41
+ export type ExplanationContext = z.infer<typeof ExplanationContextSchema>;
42
+ export interface ExplanationTemplate {
43
+ ruleId: string;
44
+ render(context: ExplanationContext): WarningExplanation;
45
+ }
46
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/explain/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;iBAGnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;iBAcnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,wBAAwB;;;;;;;;;;iBAUnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,kBAAkB,CAAC;CACzD"}
@@ -0,0 +1,31 @@
1
+ import { z } from 'zod';
2
+ export const ExplanationSectionSchema = z.object({
3
+ title: z.string().describe('Section title (e.g., "WHY THIS WARNING EXISTS")'),
4
+ content: z.string().describe('Section content, may contain placeholders'),
5
+ });
6
+ export const WarningExplanationSchema = z.object({
7
+ ruleId: z.string().describe('Rule ID (e.g., AP-003, ARCH-001)'),
8
+ title: z.string().describe('Warning title'),
9
+ summary: z.string().describe('One-line summary of the warning'),
10
+ whyItMatters: ExplanationSectionSchema.describe('Why this warning exists'),
11
+ howToAddress: ExplanationSectionSchema.describe('How to fix or address'),
12
+ whenToSuppress: ExplanationSectionSchema.describe('When suppression is appropriate'),
13
+ related: z
14
+ .object({
15
+ documentation: z.string().optional(),
16
+ ruleDefinition: z.string().optional(),
17
+ similarWarnings: z.number().int().nonnegative().optional(),
18
+ })
19
+ .optional(),
20
+ });
21
+ export const ExplanationContextSchema = z.object({
22
+ file: z.string().describe('File path where warning occurred'),
23
+ line: z.number().int().positive().describe('Line number'),
24
+ code: z.string().optional().describe('Source code snippet at the location'),
25
+ fromFile: z.string().optional().describe('Source file (for boundary violations)'),
26
+ toFile: z.string().optional().describe('Target file (for boundary violations)'),
27
+ fromLayer: z.string().optional().describe('Source layer (for boundary violations)'),
28
+ toLayer: z.string().optional().describe('Target layer (for boundary violations)'),
29
+ patternName: z.string().optional().describe('Pattern name (for anti-patterns)'),
30
+ similarCount: z.number().int().nonnegative().optional(),
31
+ });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @eddacraft/anvil-core
3
+ *
4
+ * Core domain logic for the Anvil system.
5
+ * Contains antipattern detection, architecture analysis, drift detection,
6
+ * suppression management, validation, and other core functionality.
7
+ *
8
+ * Note: Some modules perform filesystem I/O (provenance, drift snapshots,
9
+ * architecture baseline, suppression store). Heavy I/O orchestration
10
+ * (gate runner, caching, OPA execution) lives in @eddacraft/anvil-runtime.
11
+ *
12
+ * @module @eddacraft/anvil-core
13
+ */
14
+ export * from './contracts/index.js';
15
+ export * from './config/index.js';
16
+ export * from './antipattern/index.js';
17
+ export * from './suppression/index.js';
18
+ export * from './architecture/index.js';
19
+ export * from './drift/index.js';
20
+ export * from './provenance/index.js';
21
+ export * from './warnings/index.js';
22
+ export * from './explain/index.js';
23
+ export * from './validation/index.js';
24
+ export * from './crypto/index.js';
25
+ export * from './utils/index.js';
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,cAAc,sBAAsB,CAAC;AAGrC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @eddacraft/anvil-core
3
+ *
4
+ * Core domain logic for the Anvil system.
5
+ * Contains antipattern detection, architecture analysis, drift detection,
6
+ * suppression management, validation, and other core functionality.
7
+ *
8
+ * Note: Some modules perform filesystem I/O (provenance, drift snapshots,
9
+ * architecture baseline, suppression store). Heavy I/O orchestration
10
+ * (gate runner, caching, OPA execution) lives in @eddacraft/anvil-runtime.
11
+ *
12
+ * @module @eddacraft/anvil-core
13
+ */
14
+ // Contracts (schemas, types, events) — formerly @eddacraft/anvil-contracts
15
+ export * from './contracts/index.js';
16
+ // Platform config — formerly @eddacraft/anvil-platform-config
17
+ export * from './config/index.js';
18
+ // Antipattern detection
19
+ export * from './antipattern/index.js';
20
+ // Suppression management
21
+ export * from './suppression/index.js';
22
+ // Architecture analysis
23
+ export * from './architecture/index.js';
24
+ // Drift detection
25
+ export * from './drift/index.js';
26
+ // Provenance tracking
27
+ export * from './provenance/index.js';
28
+ // Warning utilities
29
+ export * from './warnings/index.js';
30
+ // Explain functionality
31
+ export * from './explain/index.js';
32
+ // Validation
33
+ export * from './validation/index.js';
34
+ // Crypto utilities
35
+ export * from './crypto/index.js';
36
+ // General utilities
37
+ export * from './utils/index.js';