@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,47 @@
1
+ /**
2
+ * Hash Generation Utilities
3
+ *
4
+ * Provides deterministic hashing functions for APS plans
5
+ * ensuring data integrity and immutability.
6
+ */
7
+ /**
8
+ * Generates a SHA-256 hash of the provided data
9
+ * @param data - The data to hash (will be canonicalized if object)
10
+ * @returns Hexadecimal string representation of the hash
11
+ */
12
+ export declare function generateHash(data: unknown): string;
13
+ /**
14
+ * Converts an object to a canonical JSON string with sorted keys
15
+ * This ensures consistent hashing regardless of property order
16
+ *
17
+ * @param obj - The object to serialize
18
+ * @returns Canonical JSON string representation
19
+ * @throws {TypeError} If obj is `undefined` (not a valid JSON value)
20
+ */
21
+ export declare function canonicalizeJSON(obj: unknown): string;
22
+ /**
23
+ * Verifies that the provided hash matches the hash of the data
24
+ * Uses constant-time comparison to prevent timing attacks
25
+ * @param data - The data to verify
26
+ * @param expectedHash - The expected hash value
27
+ * @returns True if hashes match, false otherwise
28
+ */
29
+ export declare function verifyHash(data: unknown, expectedHash: string): boolean;
30
+ /**
31
+ * Generates a unique plan ID in the format 'aps-[16 hex chars]'
32
+ * @returns A unique plan identifier
33
+ */
34
+ export declare function generatePlanId(): string;
35
+ /**
36
+ * Validates that a string is a valid plan ID format
37
+ * @param id - The ID to validate
38
+ * @returns True if valid, false otherwise
39
+ */
40
+ export declare function isValidPlanId(id: string): boolean;
41
+ /**
42
+ * Validates that a string is a valid SHA-256 hash
43
+ * @param hash - The hash to validate
44
+ * @returns True if valid, false otherwise
45
+ */
46
+ export declare function isValidHash(hash: string): boolean;
47
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/crypto/hash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAQlD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAgDrD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAUvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAGjD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Hash Generation Utilities
3
+ *
4
+ * Provides deterministic hashing functions for APS plans
5
+ * ensuring data integrity and immutability.
6
+ */
7
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
8
+ /**
9
+ * Generates a SHA-256 hash of the provided data
10
+ * @param data - The data to hash (will be canonicalized if object)
11
+ * @returns Hexadecimal string representation of the hash
12
+ */
13
+ export function generateHash(data) {
14
+ // Convert data to canonical JSON string if it's an object
15
+ const content = typeof data === 'object' && data !== null ? canonicalizeJSON(data) : String(data);
16
+ // Create SHA-256 hash
17
+ const hash = createHash('sha256');
18
+ hash.update(content, 'utf8');
19
+ return hash.digest('hex');
20
+ }
21
+ /**
22
+ * Converts an object to a canonical JSON string with sorted keys
23
+ * This ensures consistent hashing regardless of property order
24
+ *
25
+ * @param obj - The object to serialize
26
+ * @returns Canonical JSON string representation
27
+ * @throws {TypeError} If obj is `undefined` (not a valid JSON value)
28
+ */
29
+ export function canonicalizeJSON(obj) {
30
+ if (obj === null) {
31
+ return 'null';
32
+ }
33
+ if (obj === undefined) {
34
+ throw new TypeError('canonicalizeJSON does not accept undefined — it is not a valid JSON value. Use null instead.');
35
+ }
36
+ if (typeof obj === 'string') {
37
+ return JSON.stringify(obj);
38
+ }
39
+ if (typeof obj === 'number' || typeof obj === 'boolean') {
40
+ return String(obj);
41
+ }
42
+ if (Array.isArray(obj)) {
43
+ // Recursively canonicalize array elements
44
+ const elements = obj.map((element) => canonicalizeJSON(element));
45
+ return `[${elements.join(',')}]`;
46
+ }
47
+ if (obj instanceof Date) {
48
+ return JSON.stringify(obj.toISOString());
49
+ }
50
+ if (typeof obj === 'object') {
51
+ // Sort object keys and recursively canonicalize values
52
+ const sortedKeys = Object.keys(obj).sort();
53
+ const pairs = sortedKeys
54
+ .map((key) => {
55
+ const value = obj[key];
56
+ // Skip undefined values (like JSON.stringify does)
57
+ if (value === undefined) {
58
+ return null;
59
+ }
60
+ return `${JSON.stringify(key)}:${canonicalizeJSON(value)}`;
61
+ })
62
+ .filter((pair) => pair !== null);
63
+ return `{${pairs.join(',')}}`;
64
+ }
65
+ // Fallback for other types
66
+ return JSON.stringify(obj);
67
+ }
68
+ /**
69
+ * Verifies that the provided hash matches the hash of the data
70
+ * Uses constant-time comparison to prevent timing attacks
71
+ * @param data - The data to verify
72
+ * @param expectedHash - The expected hash value
73
+ * @returns True if hashes match, false otherwise
74
+ */
75
+ export function verifyHash(data, expectedHash) {
76
+ const actualHash = generateHash(data);
77
+ // Use constant-time comparison to prevent timing attacks
78
+ // Both hashes must be the same length for timingSafeEqual
79
+ if (actualHash.length !== expectedHash.length) {
80
+ return false;
81
+ }
82
+ return timingSafeEqual(Buffer.from(actualHash, 'utf8'), Buffer.from(expectedHash, 'utf8'));
83
+ }
84
+ /**
85
+ * Generates a unique plan ID in the format 'aps-[16 hex chars]'
86
+ * @returns A unique plan identifier
87
+ */
88
+ export function generatePlanId() {
89
+ // Generate 8 random bytes (16 hex characters) for sufficient entropy
90
+ const buffer = randomBytes(8);
91
+ const hexString = buffer.toString('hex');
92
+ return `aps-${hexString}`;
93
+ }
94
+ /**
95
+ * Validates that a string is a valid plan ID format
96
+ * @param id - The ID to validate
97
+ * @returns True if valid, false otherwise
98
+ */
99
+ export function isValidPlanId(id) {
100
+ // Accept both legacy 8-char and new 16-char IDs
101
+ return /^aps-[a-f0-9]{8}$/.test(id) || /^aps-[a-f0-9]{16}$/.test(id);
102
+ }
103
+ /**
104
+ * Validates that a string is a valid SHA-256 hash
105
+ * @param hash - The hash to validate
106
+ * @returns True if valid, false otherwise
107
+ */
108
+ export function isValidHash(hash) {
109
+ return /^[a-f0-9]{64}$/.test(hash);
110
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Crypto Module Public API
3
+ *
4
+ * Exports cryptographic utilities for hashing and ID generation.
5
+ */
6
+ export { generateHash, canonicalizeJSON, verifyHash, generatePlanId, isValidPlanId, isValidHash, } from './hash.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,cAAc,EACd,aAAa,EACb,WAAW,GACZ,MAAM,WAAW,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Crypto Module Public API
3
+ *
4
+ * Exports cryptographic utilities for hashing and ID generation.
5
+ */
6
+ export { generateHash, canonicalizeJSON, verifyHash, generatePlanId, isValidPlanId, isValidHash, } from './hash.js';
@@ -0,0 +1,6 @@
1
+ export { SNAPSHOT_SCHEMA_VERSION, SnapshotViolationSchema, type SnapshotViolation, SnapshotAntiPatternSchema, type SnapshotAntiPattern, SnapshotSuppressionSchema, type SnapshotSuppression, SnapshotMetricsSchema, type SnapshotMetrics, AntiPatternBreakdownSchema, type AntiPatternBreakdown, HotspotSchema, type Hotspot, DriftSnapshotSchema, type DriftSnapshot, SnapshotMetadataSchema, type SnapshotMetadata, generateSnapshotFilename, generateNamedSnapshotFilename, parseSnapshotFilename, createEmptySnapshot, validateSnapshot, } from './snapshot-schema.js';
2
+ export { SNAPSHOTS_DIR, ensureSnapshotsDir, saveSnapshot, loadSnapshot, listSnapshots, deleteSnapshot, snapshotExists, getLatestSnapshot, resolveSnapshotName, SnapshotStore, } from './snapshot-storage.js';
3
+ export { type CaptureOptions, type CaptureContext, captureSnapshot, SnapshotCaptureService, createSnapshotCaptureService, } from './snapshot-capture.js';
4
+ export { type ItemChange, type MetricChange, type MetricsComparison, type AntiPatternChange, type SnapshotComparison, compareSnapshots, formatComparisonSummary, } from './snapshot-compare.js';
5
+ export { type ReportOptions, type DriftReport, type ReportSection, generateReport, formatReportAsText, formatReportAsJson, } from './report-generator.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/drift/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,KAAK,eAAe,EACpB,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,aAAa,EACb,KAAK,OAAO,EACZ,mBAAmB,EACnB,KAAK,aAAa,EAClB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,eAAe,EACf,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,gBAAgB,EAChB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,cAAc,EACd,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { SNAPSHOT_SCHEMA_VERSION, SnapshotViolationSchema, SnapshotAntiPatternSchema, SnapshotSuppressionSchema, SnapshotMetricsSchema, AntiPatternBreakdownSchema, HotspotSchema, DriftSnapshotSchema, SnapshotMetadataSchema, generateSnapshotFilename, generateNamedSnapshotFilename, parseSnapshotFilename, createEmptySnapshot, validateSnapshot, } from './snapshot-schema.js';
2
+ export { SNAPSHOTS_DIR, ensureSnapshotsDir, saveSnapshot, loadSnapshot, listSnapshots, deleteSnapshot, snapshotExists, getLatestSnapshot, resolveSnapshotName, SnapshotStore, } from './snapshot-storage.js';
3
+ export { captureSnapshot, SnapshotCaptureService, createSnapshotCaptureService, } from './snapshot-capture.js';
4
+ export { compareSnapshots, formatComparisonSummary, } from './snapshot-compare.js';
5
+ export { generateReport, formatReportAsText, formatReportAsJson, } from './report-generator.js';
@@ -0,0 +1,21 @@
1
+ import type { SnapshotComparison } from './snapshot-compare.js';
2
+ export interface ReportOptions {
3
+ format?: 'text' | 'json';
4
+ includeDetails?: boolean;
5
+ maxEdges?: number;
6
+ maxHotspots?: number;
7
+ }
8
+ export interface DriftReport {
9
+ summary: string;
10
+ sections: ReportSection[];
11
+ recommendation: string;
12
+ json?: unknown;
13
+ }
14
+ export interface ReportSection {
15
+ title: string;
16
+ content: string[];
17
+ }
18
+ export declare function generateReport(comparison: SnapshotComparison, options?: ReportOptions): DriftReport;
19
+ export declare function formatReportAsText(report: DriftReport): string;
20
+ export declare function formatReportAsJson(report: DriftReport): string;
21
+ //# sourceMappingURL=report-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-generator.d.ts","sourceRoot":"","sources":["../../src/drift/report-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAKhE,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAqND,wBAAgB,cAAc,CAC5B,UAAU,EAAE,kBAAkB,EAC9B,OAAO,GAAE,aAAkB,GAC1B,WAAW,CAiCb;AAiDD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE9D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE9D"}
@@ -0,0 +1,240 @@
1
+ import { createDebugger } from '../utils/debug.js';
2
+ const debug = createDebugger('drift');
3
+ const SEPARATOR = '\u2500'.repeat(56);
4
+ function formatDelta(delta) {
5
+ if (delta > 0)
6
+ return `+${delta}`;
7
+ if (delta < 0)
8
+ return `${delta}`;
9
+ return '0';
10
+ }
11
+ function formatTrend(trend) {
12
+ switch (trend) {
13
+ case 'increasing':
14
+ return '\u26A0\uFE0F';
15
+ case 'decreasing':
16
+ return '\u2705';
17
+ default:
18
+ return '\u2796';
19
+ }
20
+ }
21
+ function formatOverallTrend(trend) {
22
+ switch (trend) {
23
+ case 'improving':
24
+ return 'IMPROVING \u2705';
25
+ case 'degrading':
26
+ return 'INCREASING \u26A0\uFE0F';
27
+ default:
28
+ return 'STABLE \u2796';
29
+ }
30
+ }
31
+ function formatDate(isoDate) {
32
+ return isoDate.split('T')[0];
33
+ }
34
+ function generateHeader(comparison) {
35
+ const beforeName = comparison.before.name ?? formatDate(comparison.before.created_at);
36
+ const afterName = comparison.after.name ?? formatDate(comparison.after.created_at);
37
+ return [
38
+ ` Drift Report: ${beforeName} \u2192 ${afterName} (${comparison.duration_days} days)`,
39
+ '',
40
+ SEPARATOR,
41
+ ];
42
+ }
43
+ function generateBoundarySection(comparison, options) {
44
+ const content = [];
45
+ const metrics = comparison.metrics.boundary_violations;
46
+ content.push(` New violations: ${formatDelta(comparison.violations.added.length)} (was ${metrics.before}, now ${metrics.after})`);
47
+ content.push(` Resolved: ${formatDelta(-comparison.violations.removed.length)}`);
48
+ content.push(` Net change: ${formatDelta(comparison.net_change.violations)} ${formatTrend(metrics.trend)}`);
49
+ if (options.includeDetails && comparison.violations.added.length > 0) {
50
+ content.push('');
51
+ content.push(' New edges detected:');
52
+ const maxEdges = options.maxEdges ?? 5;
53
+ const edgesToShow = comparison.violations.added.slice(0, maxEdges);
54
+ for (const v of edgesToShow) {
55
+ const rule = v.rule ?? `${v.from_layer}\u2192${v.to_layer}`;
56
+ content.push(` \u2022 ${v.from_file} \u2192 ${v.to_file} (${rule})`);
57
+ }
58
+ if (comparison.violations.added.length > maxEdges) {
59
+ content.push(` ... and ${comparison.violations.added.length - maxEdges} more`);
60
+ }
61
+ }
62
+ return { title: 'ARCHITECTURE BOUNDARIES', content };
63
+ }
64
+ function generateAntiPatternSection(comparison, options) {
65
+ const content = [];
66
+ const metrics = comparison.metrics.antipattern_count;
67
+ content.push(` New introductions: ${formatDelta(comparison.antipatterns.added.length)}`);
68
+ content.push(` Resolved: ${formatDelta(-comparison.antipatterns.removed.length)}`);
69
+ content.push(` Net change: ${formatDelta(comparison.net_change.antipatterns)} ${formatTrend(metrics.trend)}`);
70
+ if (comparison.antipattern_changes.length > 0) {
71
+ content.push('');
72
+ content.push(' By type:');
73
+ for (const change of comparison.antipattern_changes.slice(0, 5)) {
74
+ content.push(` \u2022 ${change.id}: ${formatDelta(change.delta)}`);
75
+ }
76
+ }
77
+ if (options.includeDetails) {
78
+ const hotspots = findAntiPatternHotspots(comparison);
79
+ if (hotspots.length > 0) {
80
+ content.push('');
81
+ content.push(' Hotspots:');
82
+ const maxHotspots = options.maxHotspots ?? 3;
83
+ for (const hs of hotspots.slice(0, maxHotspots)) {
84
+ content.push(` \u2022 ${hs.path} \u2014 ${hs.count} new violations`);
85
+ }
86
+ }
87
+ }
88
+ return { title: 'ANTI-PATTERNS', content };
89
+ }
90
+ function findAntiPatternHotspots(comparison) {
91
+ const dirCounts = new Map();
92
+ for (const ap of comparison.antipatterns.added) {
93
+ const parts = ap.file.split('/');
94
+ const dir = parts.slice(0, -1).join('/') || '.';
95
+ dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);
96
+ }
97
+ return Array.from(dirCounts.entries())
98
+ .filter(([_, count]) => count > 1)
99
+ .sort((a, b) => b[1] - a[1])
100
+ .map(([path, count]) => ({ path, count }));
101
+ }
102
+ function generateSuppressionSection(comparison) {
103
+ const content = [];
104
+ const expiredMetrics = comparison.metrics.expired_suppressions;
105
+ content.push(` New suppressions: ${formatDelta(comparison.suppressions.added.length)}`);
106
+ content.push(` Expired: ${formatDelta(expiredMetrics.delta)}`);
107
+ content.push(` Net change: ${formatDelta(comparison.net_change.suppressions)}`);
108
+ const oldestUnexpired = findOldestUnexpiredSuppression(comparison);
109
+ if (oldestUnexpired) {
110
+ content.push('');
111
+ content.push(` Oldest unexpired: ${oldestUnexpired.age} days (${oldestUnexpired.file})`);
112
+ }
113
+ return { title: 'SUPPRESSIONS', content };
114
+ }
115
+ function findOldestUnexpiredSuppression(comparison) {
116
+ const activeSuppressions = comparison.suppressions.unchanged.filter((s) => !s.is_expired);
117
+ if (activeSuppressions.length === 0)
118
+ return null;
119
+ return {
120
+ age: comparison.duration_days,
121
+ file: activeSuppressions[0].file,
122
+ };
123
+ }
124
+ function generateSummarySection(comparison) {
125
+ const content = [];
126
+ content.push(` Overall drift: ${formatOverallTrend(comparison.overall_trend)}`);
127
+ return { title: 'SUMMARY', content };
128
+ }
129
+ function generateRecommendation(comparison) {
130
+ if (comparison.overall_trend === 'degrading') {
131
+ if (comparison.violations.added.length > 0) {
132
+ const topViolationDir = getMostAffectedDirectory(comparison.violations.added);
133
+ return `Review new violations in ${topViolationDir}`;
134
+ }
135
+ if (comparison.antipatterns.added.length > 0) {
136
+ const topPattern = comparison.antipattern_changes[0]?.id ?? 'anti-patterns';
137
+ return `Address increasing ${topPattern} occurrences`;
138
+ }
139
+ }
140
+ if (comparison.overall_trend === 'improving') {
141
+ return 'Good progress! Continue addressing remaining issues.';
142
+ }
143
+ return 'Architecture is stable. Monitor for new changes.';
144
+ }
145
+ function getMostAffectedDirectory(violations) {
146
+ const dirCounts = new Map();
147
+ for (const v of violations) {
148
+ const parts = v.from_file.split('/');
149
+ const dir = parts.slice(0, 2).join('/') || '.';
150
+ dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);
151
+ }
152
+ let maxDir = '.';
153
+ let maxCount = 0;
154
+ for (const [dir, count] of dirCounts) {
155
+ if (count > maxCount) {
156
+ maxCount = count;
157
+ maxDir = dir;
158
+ }
159
+ }
160
+ return maxDir + '/';
161
+ }
162
+ export function generateReport(comparison, options = {}) {
163
+ debug('generating drift report', {
164
+ format: options.format,
165
+ includeDetails: options.includeDetails,
166
+ trend: comparison.overall_trend,
167
+ });
168
+ const { includeDetails = true } = options;
169
+ const effectiveOptions = { ...options, includeDetails };
170
+ const sections = [
171
+ generateBoundarySection(comparison, effectiveOptions),
172
+ generateAntiPatternSection(comparison, effectiveOptions),
173
+ generateSuppressionSection(comparison),
174
+ generateSummarySection(comparison),
175
+ ];
176
+ const recommendation = generateRecommendation(comparison);
177
+ const header = generateHeader(comparison);
178
+ const sectionTexts = sections.map((s) => {
179
+ return [` ${s.title}`, '', ...s.content, '', SEPARATOR].join('\n');
180
+ });
181
+ const summary = [...header, '', ...sectionTexts, ` Recommendation: ${recommendation}`, ''].join('\n');
182
+ return {
183
+ summary,
184
+ sections,
185
+ recommendation,
186
+ json: options.format === 'json' ? generateJsonReport(comparison) : undefined,
187
+ };
188
+ }
189
+ function generateJsonReport(comparison) {
190
+ return {
191
+ before: comparison.before,
192
+ after: comparison.after,
193
+ duration_days: comparison.duration_days,
194
+ metrics: {
195
+ boundary_violations: {
196
+ before: comparison.metrics.boundary_violations.before,
197
+ after: comparison.metrics.boundary_violations.after,
198
+ delta: comparison.metrics.boundary_violations.delta,
199
+ },
200
+ antipattern_count: {
201
+ before: comparison.metrics.antipattern_count.before,
202
+ after: comparison.metrics.antipattern_count.after,
203
+ delta: comparison.metrics.antipattern_count.delta,
204
+ },
205
+ suppression_count: {
206
+ before: comparison.metrics.suppression_count.before,
207
+ after: comparison.metrics.suppression_count.after,
208
+ delta: comparison.metrics.suppression_count.delta,
209
+ },
210
+ },
211
+ net_change: comparison.net_change,
212
+ changes: {
213
+ violations: {
214
+ added: comparison.violations.added.length,
215
+ removed: comparison.violations.removed.length,
216
+ unchanged: comparison.violations.unchanged.length,
217
+ },
218
+ antipatterns: {
219
+ added: comparison.antipatterns.added.length,
220
+ removed: comparison.antipatterns.removed.length,
221
+ unchanged: comparison.antipatterns.unchanged.length,
222
+ },
223
+ suppressions: {
224
+ added: comparison.suppressions.added.length,
225
+ removed: comparison.suppressions.removed.length,
226
+ unchanged: comparison.suppressions.unchanged.length,
227
+ },
228
+ },
229
+ antipattern_changes: comparison.antipattern_changes,
230
+ overall_trend: comparison.overall_trend,
231
+ added_violations: comparison.violations.added,
232
+ added_antipatterns: comparison.antipatterns.added,
233
+ };
234
+ }
235
+ export function formatReportAsText(report) {
236
+ return report.summary;
237
+ }
238
+ export function formatReportAsJson(report) {
239
+ return JSON.stringify(report.json ?? {}, null, 2);
240
+ }
@@ -0,0 +1,26 @@
1
+ import { type DriftSnapshot } from './snapshot-schema.js';
2
+ import { type ArchitectureBaseline } from '../architecture/index.js';
3
+ import { type ScanResult } from '../antipattern/index.js';
4
+ import { type FileSuppressions } from '../suppression/index.js';
5
+ export interface CaptureOptions {
6
+ name?: string;
7
+ includeOptInPatterns?: boolean;
8
+ sourcePatterns?: string[];
9
+ }
10
+ export interface CaptureContext {
11
+ workspaceRoot: string;
12
+ files: string[];
13
+ baseline: ArchitectureBaseline | null;
14
+ scanResults: ScanResult[];
15
+ suppressions: FileSuppressions[];
16
+ gitRef?: string;
17
+ }
18
+ export declare function captureSnapshot(context: CaptureContext, options?: CaptureOptions): Promise<DriftSnapshot>;
19
+ export declare class SnapshotCaptureService {
20
+ private workspaceRoot;
21
+ constructor(workspaceRoot: string);
22
+ capture(files: string[], options?: CaptureOptions): Promise<DriftSnapshot>;
23
+ captureWithContext(context: Partial<CaptureContext>, options?: CaptureOptions): Promise<DriftSnapshot>;
24
+ }
25
+ export declare function createSnapshotCaptureService(workspaceRoot: string): SnapshotCaptureService;
26
+ //# sourceMappingURL=snapshot-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-capture.d.ts","sourceRoot":"","sources":["../../src/drift/snapshot-capture.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,aAAa,EAQnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAMpF,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0ID,wBAAsB,eAAe,CACnC,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA0BxB;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,aAAa,CAAS;gBAElB,aAAa,EAAE,MAAM;IAI3B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwC9E,kBAAkB,CACtB,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,EAChC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC;CAY1B;AAED,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,sBAAsB,CAE1F"}