@aiready/change-amplification 0.9.2 → 0.9.5

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.
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @aiready/change-amplification@0.9.1 build /Users/pengcao/projects/aiready/packages/change-amplification
3
+ > @aiready/change-amplification@0.9.4 build /Users/pengcao/projects/aiready/packages/change-amplification
4
4
  > tsup src/index.ts src/cli.ts --format cjs,esm --dts
5
5
 
6
6
  CLI Building entry: src/cli.ts, src/index.ts
@@ -10,7 +10,7 @@
10
10
  CJS Build start
11
11
  ESM Build start
12
12
 
13
-  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 8:13:08 pm
13
+  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 9:38:41 pm
14
14
 
15
15
  package.json:33:6:
16
16
   33 │ "types": "./dist/index.d.ts"
@@ -31,7 +31,7 @@
31
31
 
32
32
 
33
33
 
34
-  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 8:13:08 pm
34
+  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 9:38:41 pm
35
35
 
36
36
  package.json:38:6:
37
37
   38 │ "types": "./dist/cli.d.ts"
@@ -52,7 +52,7 @@
52
52
 
53
53
 
54
54
 
55
-  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 8:13:08 pm
55
+  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 9:38:41 pm
56
56
 
57
57
  package.json:33:6:
58
58
   33 │ "types": "./dist/index.d.ts"
@@ -73,7 +73,7 @@
73
73
 
74
74
 
75
75
 
76
-  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 8:13:08 pm
76
+  WARN  ▲ [WARNING] The condition "types" here will never be used as it comes after both "import" and "require" [package.json] 9:38:41 pm
77
77
 
78
78
  package.json:38:6:
79
79
   38 │ "types": "./dist/cli.d.ts"
@@ -93,16 +93,16 @@
93
93
 
94
94
 
95
95
 
96
- CJS dist/index.js 4.73 KB
97
- CJS dist/cli.js 7.60 KB
98
- CJS ⚡️ Build success in 54ms
99
96
  ESM dist/index.mjs 110.00 B
100
- ESM dist/chunk-3CM4X7K3.mjs 3.47 KB
101
97
  ESM dist/cli.mjs 2.78 KB
102
- ESM ⚡️ Build success in 55ms
98
+ ESM dist/chunk-GLHIV53G.mjs 3.79 KB
99
+ ESM ⚡️ Build success in 154ms
100
+ CJS dist/index.js 5.11 KB
101
+ CJS dist/cli.js 7.98 KB
102
+ CJS ⚡️ Build success in 155ms
103
103
  DTS Build start
104
- DTS ⚡️ Build success in 915ms
104
+ DTS ⚡️ Build success in 3747ms
105
105
  DTS dist/cli.d.ts 152.00 B
106
- DTS dist/index.d.ts 999.00 B
106
+ DTS dist/index.d.ts 941.00 B
107
107
  DTS dist/cli.d.mts 152.00 B
108
- DTS dist/index.d.mts 999.00 B
108
+ DTS dist/index.d.mts 941.00 B
@@ -1,16 +1,16 @@
1
1
 
2
2
  
3
- > @aiready/change-amplification@0.9.1 test /Users/pengcao/projects/aiready/packages/change-amplification
3
+ > @aiready/change-amplification@0.9.4 test /Users/pengcao/projects/aiready/packages/change-amplification
4
4
  > vitest run
5
5
 
6
6
  [?25l
7
7
   RUN  v4.0.18 /Users/pengcao/projects/aiready/packages/change-amplification
8
8
 
9
- ✓ src/__tests__/dummy.test.ts (1 test) 1ms
9
+ ✓ src/__tests__/dummy.test.ts (1 test) 2ms
10
10
 
11
11
   Test Files  1 passed (1)
12
12
   Tests  1 passed (1)
13
-  Start at  20:13:24
14
-  Duration  478ms (transform 52ms, setup 0ms, import 70ms, tests 1ms, environment 0ms)
13
+  Start at  21:39:02
14
+  Duration  395ms (transform 81ms, setup 0ms, import 98ms, tests 2ms, environment 0ms)
15
15
 
16
16
  [?25h
@@ -0,0 +1,112 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/analyzer.ts
9
+ import * as fs from "fs";
10
+ import * as path from "path";
11
+ import {
12
+ scanFiles,
13
+ calculateChangeAmplification,
14
+ getParser,
15
+ Severity
16
+ } from "@aiready/core";
17
+ async function analyzeChangeAmplification(options) {
18
+ const files = await scanFiles({
19
+ ...options,
20
+ include: options.include || ["**/*.{ts,tsx,js,jsx,py,go}"]
21
+ });
22
+ const dependencyGraph = /* @__PURE__ */ new Map();
23
+ const reverseGraph = /* @__PURE__ */ new Map();
24
+ for (const file of files) {
25
+ dependencyGraph.set(file, []);
26
+ reverseGraph.set(file, []);
27
+ }
28
+ let processed = 0;
29
+ for (const file of files) {
30
+ processed++;
31
+ options.onProgress?.(
32
+ processed,
33
+ files.length,
34
+ `change-amplification: analyzing files`
35
+ );
36
+ try {
37
+ const parser = getParser(file);
38
+ if (!parser) continue;
39
+ const content = fs.readFileSync(file, "utf8");
40
+ const parseResult = parser.parse(content, file);
41
+ const dependencies = parseResult.imports.map((i) => i.source);
42
+ for (const dep of dependencies) {
43
+ const depDir = path.dirname(file);
44
+ const resolvedPath = files.find((f) => {
45
+ if (dep.startsWith(".")) {
46
+ return f.startsWith(path.resolve(depDir, dep));
47
+ } else {
48
+ return f.includes(dep);
49
+ }
50
+ });
51
+ if (resolvedPath) {
52
+ dependencyGraph.get(file)?.push(resolvedPath);
53
+ reverseGraph.get(resolvedPath)?.push(file);
54
+ }
55
+ }
56
+ } catch (err) {
57
+ void err;
58
+ }
59
+ }
60
+ const fileMetrics = files.map((file) => {
61
+ const fanOut = dependencyGraph.get(file)?.length || 0;
62
+ const fanIn = reverseGraph.get(file)?.length || 0;
63
+ return { file, fanOut, fanIn };
64
+ });
65
+ const riskResult = calculateChangeAmplification({ files: fileMetrics });
66
+ const results = [];
67
+ for (const hotspot of riskResult.hotspots) {
68
+ const issues = [];
69
+ if (hotspot.amplificationFactor > 20) {
70
+ issues.push({
71
+ type: "change-amplification",
72
+ severity: hotspot.amplificationFactor > 40 ? Severity.Critical : Severity.Major,
73
+ message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
74
+ location: { file: hotspot.file, line: 1 },
75
+ suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`
76
+ });
77
+ }
78
+ if (hotspot.amplificationFactor > 5) {
79
+ results.push({
80
+ fileName: hotspot.file,
81
+ issues,
82
+ metrics: {
83
+ aiSignalClarityScore: 100 - hotspot.amplificationFactor
84
+ // Just a rough score
85
+ }
86
+ });
87
+ }
88
+ }
89
+ return {
90
+ summary: {
91
+ totalFiles: files.length,
92
+ totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
93
+ criticalIssues: results.reduce(
94
+ (sum, r) => sum + r.issues.filter((i) => i.severity === Severity.Critical || i.severity === "critical").length,
95
+ 0
96
+ ),
97
+ majorIssues: results.reduce(
98
+ (sum, r) => sum + r.issues.filter((i) => i.severity === Severity.Major || i.severity === "major").length,
99
+ 0
100
+ ),
101
+ score: riskResult.score,
102
+ rating: riskResult.rating,
103
+ recommendations: riskResult.recommendations
104
+ },
105
+ results
106
+ };
107
+ }
108
+
109
+ export {
110
+ __require,
111
+ analyzeChangeAmplification
112
+ };
@@ -0,0 +1,128 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/analyzer.ts
9
+ import * as fs from "fs";
10
+ import * as path from "path";
11
+ import {
12
+ scanFiles,
13
+ calculateChangeAmplification,
14
+ getParser,
15
+ Severity,
16
+ IssueType
17
+ } from "@aiready/core";
18
+ async function analyzeChangeAmplification(options) {
19
+ const files = await scanFiles({
20
+ ...options,
21
+ include: options.include || ["**/*.{ts,tsx,js,jsx,py,go}"]
22
+ });
23
+ const dependencyGraph = /* @__PURE__ */ new Map();
24
+ const reverseGraph = /* @__PURE__ */ new Map();
25
+ for (const file of files) {
26
+ dependencyGraph.set(file, []);
27
+ reverseGraph.set(file, []);
28
+ }
29
+ let processed = 0;
30
+ for (const file of files) {
31
+ processed++;
32
+ options.onProgress?.(
33
+ processed,
34
+ files.length,
35
+ `change-amplification: analyzing files`
36
+ );
37
+ try {
38
+ const parser = getParser(file);
39
+ if (!parser) continue;
40
+ const content = fs.readFileSync(file, "utf8");
41
+ const parseResult = parser.parse(content, file);
42
+ const dependencies = parseResult.imports.map((i) => i.source);
43
+ for (const dep of dependencies) {
44
+ const depDir = path.dirname(file);
45
+ const resolvedPath = files.find((f) => {
46
+ if (dep.startsWith(".")) {
47
+ return f.startsWith(path.resolve(depDir, dep));
48
+ } else {
49
+ return f.includes(dep);
50
+ }
51
+ });
52
+ if (resolvedPath) {
53
+ dependencyGraph.get(file)?.push(resolvedPath);
54
+ reverseGraph.get(resolvedPath)?.push(file);
55
+ }
56
+ }
57
+ } catch (err) {
58
+ void err;
59
+ }
60
+ }
61
+ const fileMetrics = files.map((file) => {
62
+ const fanOut = dependencyGraph.get(file)?.length || 0;
63
+ const fanIn = reverseGraph.get(file)?.length || 0;
64
+ return { file, fanOut, fanIn };
65
+ });
66
+ const riskResult = calculateChangeAmplification({ files: fileMetrics });
67
+ const results = [];
68
+ const getLevel = (s) => {
69
+ const map = {
70
+ [Severity.Critical]: 4,
71
+ [Severity.Major]: 3,
72
+ [Severity.Minor]: 2,
73
+ [Severity.Info]: 1,
74
+ critical: 4,
75
+ major: 3,
76
+ minor: 2,
77
+ info: 1
78
+ };
79
+ if (map[s] !== void 0) return map[s];
80
+ const lower = String(s).toLowerCase();
81
+ return map[lower] ?? 0;
82
+ };
83
+ for (const hotspot of riskResult.hotspots) {
84
+ const issues = [];
85
+ if (hotspot.amplificationFactor > 20) {
86
+ issues.push({
87
+ type: IssueType.ChangeAmplification,
88
+ severity: hotspot.amplificationFactor > 40 ? Severity.Critical : Severity.Major,
89
+ message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
90
+ location: { file: hotspot.file, line: 1 },
91
+ suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`
92
+ });
93
+ }
94
+ if (hotspot.amplificationFactor > 5) {
95
+ results.push({
96
+ fileName: hotspot.file,
97
+ issues,
98
+ metrics: {
99
+ aiSignalClarityScore: 100 - hotspot.amplificationFactor
100
+ // Just a rough score
101
+ }
102
+ });
103
+ }
104
+ }
105
+ return {
106
+ summary: {
107
+ totalFiles: files.length,
108
+ totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
109
+ criticalIssues: results.reduce(
110
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 4).length,
111
+ 0
112
+ ),
113
+ majorIssues: results.reduce(
114
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 3).length,
115
+ 0
116
+ ),
117
+ score: riskResult.score,
118
+ rating: riskResult.rating,
119
+ recommendations: riskResult.recommendations
120
+ },
121
+ results
122
+ };
123
+ }
124
+
125
+ export {
126
+ __require,
127
+ analyzeChangeAmplification
128
+ };
@@ -0,0 +1,120 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/analyzer.ts
9
+ import * as fs from "fs";
10
+ import * as path from "path";
11
+ import {
12
+ scanFiles,
13
+ calculateChangeAmplification,
14
+ getParser,
15
+ Severity,
16
+ IssueType
17
+ } from "@aiready/core";
18
+ async function analyzeChangeAmplification(options) {
19
+ const files = await scanFiles({
20
+ ...options,
21
+ include: options.include || ["**/*.{ts,tsx,js,jsx,py,go}"]
22
+ });
23
+ const dependencyGraph = /* @__PURE__ */ new Map();
24
+ const reverseGraph = /* @__PURE__ */ new Map();
25
+ for (const file of files) {
26
+ dependencyGraph.set(file, []);
27
+ reverseGraph.set(file, []);
28
+ }
29
+ let processed = 0;
30
+ for (const file of files) {
31
+ processed++;
32
+ options.onProgress?.(
33
+ processed,
34
+ files.length,
35
+ `change-amplification: analyzing files`
36
+ );
37
+ try {
38
+ const parser = getParser(file);
39
+ if (!parser) continue;
40
+ const content = fs.readFileSync(file, "utf8");
41
+ const parseResult = parser.parse(content, file);
42
+ const dependencies = parseResult.imports.map((i) => i.source);
43
+ for (const dep of dependencies) {
44
+ const depDir = path.dirname(file);
45
+ const resolvedPath = files.find((f) => {
46
+ if (dep.startsWith(".")) {
47
+ return f.startsWith(path.resolve(depDir, dep));
48
+ } else {
49
+ return f.includes(dep);
50
+ }
51
+ });
52
+ if (resolvedPath) {
53
+ dependencyGraph.get(file)?.push(resolvedPath);
54
+ reverseGraph.get(resolvedPath)?.push(file);
55
+ }
56
+ }
57
+ } catch (err) {
58
+ void err;
59
+ }
60
+ }
61
+ const fileMetrics = files.map((file) => {
62
+ const fanOut = dependencyGraph.get(file)?.length || 0;
63
+ const fanIn = reverseGraph.get(file)?.length || 0;
64
+ return { file, fanOut, fanIn };
65
+ });
66
+ const riskResult = calculateChangeAmplification({ files: fileMetrics });
67
+ const results = [];
68
+ const getLevel = (s) => {
69
+ if (s === Severity.Critical || s === "critical") return 4;
70
+ if (s === Severity.Major || s === "major") return 3;
71
+ if (s === Severity.Minor || s === "minor") return 2;
72
+ if (s === Severity.Info || s === "info") return 1;
73
+ return 0;
74
+ };
75
+ for (const hotspot of riskResult.hotspots) {
76
+ const issues = [];
77
+ if (hotspot.amplificationFactor > 20) {
78
+ issues.push({
79
+ type: IssueType.ChangeAmplification,
80
+ severity: hotspot.amplificationFactor > 40 ? Severity.Critical : Severity.Major,
81
+ message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
82
+ location: { file: hotspot.file, line: 1 },
83
+ suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`
84
+ });
85
+ }
86
+ if (hotspot.amplificationFactor > 5) {
87
+ results.push({
88
+ fileName: hotspot.file,
89
+ issues,
90
+ metrics: {
91
+ aiSignalClarityScore: 100 - hotspot.amplificationFactor
92
+ // Just a rough score
93
+ }
94
+ });
95
+ }
96
+ }
97
+ return {
98
+ summary: {
99
+ totalFiles: files.length,
100
+ totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
101
+ criticalIssues: results.reduce(
102
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 4).length,
103
+ 0
104
+ ),
105
+ majorIssues: results.reduce(
106
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 3).length,
107
+ 0
108
+ ),
109
+ score: riskResult.score,
110
+ rating: riskResult.rating,
111
+ recommendations: riskResult.recommendations
112
+ },
113
+ results
114
+ };
115
+ }
116
+
117
+ export {
118
+ __require,
119
+ analyzeChangeAmplification
120
+ };
@@ -0,0 +1,129 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/analyzer.ts
9
+ import * as fs from "fs";
10
+ import * as path from "path";
11
+ import {
12
+ scanFiles,
13
+ calculateChangeAmplification,
14
+ getParser,
15
+ Severity,
16
+ IssueType
17
+ } from "@aiready/core";
18
+ async function analyzeChangeAmplification(options) {
19
+ const files = await scanFiles({
20
+ ...options,
21
+ include: options.include || ["**/*.{ts,tsx,js,jsx,py,go}"]
22
+ });
23
+ const dependencyGraph = /* @__PURE__ */ new Map();
24
+ const reverseGraph = /* @__PURE__ */ new Map();
25
+ for (const file of files) {
26
+ dependencyGraph.set(file, []);
27
+ reverseGraph.set(file, []);
28
+ }
29
+ let processed = 0;
30
+ for (const file of files) {
31
+ processed++;
32
+ options.onProgress?.(
33
+ processed,
34
+ files.length,
35
+ `change-amplification: analyzing files`
36
+ );
37
+ try {
38
+ const parser = getParser(file);
39
+ if (!parser) continue;
40
+ const content = fs.readFileSync(file, "utf8");
41
+ const parseResult = parser.parse(content, file);
42
+ const dependencies = parseResult.imports.map((i) => i.source);
43
+ for (const dep of dependencies) {
44
+ const depDir = path.dirname(file);
45
+ const resolvedPath = files.find((f) => {
46
+ if (dep.startsWith(".")) {
47
+ return f.startsWith(path.resolve(depDir, dep));
48
+ } else {
49
+ return f.includes(dep);
50
+ }
51
+ });
52
+ if (resolvedPath) {
53
+ dependencyGraph.get(file)?.push(resolvedPath);
54
+ reverseGraph.get(resolvedPath)?.push(file);
55
+ }
56
+ }
57
+ } catch (err) {
58
+ void err;
59
+ }
60
+ }
61
+ const fileMetrics = files.map((file) => {
62
+ const fanOut = dependencyGraph.get(file)?.length || 0;
63
+ const fanIn = reverseGraph.get(file)?.length || 0;
64
+ return { file, fanOut, fanIn };
65
+ });
66
+ const riskResult = calculateChangeAmplification({ files: fileMetrics });
67
+ const results = [];
68
+ const getLevel = (s) => {
69
+ const enumMap = {
70
+ [Severity.Critical]: 4,
71
+ [Severity.Major]: 3,
72
+ [Severity.Minor]: 2,
73
+ [Severity.Info]: 1
74
+ };
75
+ const stringMap = {
76
+ critical: 4,
77
+ major: 3,
78
+ minor: 2,
79
+ info: 1
80
+ };
81
+ if (typeof s === "string") return stringMap[s.toLowerCase()] ?? 0;
82
+ return enumMap[s] ?? 0;
83
+ };
84
+ for (const hotspot of riskResult.hotspots) {
85
+ const issues = [];
86
+ if (hotspot.amplificationFactor > 20) {
87
+ issues.push({
88
+ type: IssueType.ChangeAmplification,
89
+ severity: hotspot.amplificationFactor > 40 ? Severity.Critical : Severity.Major,
90
+ message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
91
+ location: { file: hotspot.file, line: 1 },
92
+ suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`
93
+ });
94
+ }
95
+ if (hotspot.amplificationFactor > 5) {
96
+ results.push({
97
+ fileName: hotspot.file,
98
+ issues,
99
+ metrics: {
100
+ aiSignalClarityScore: 100 - hotspot.amplificationFactor
101
+ // Just a rough score
102
+ }
103
+ });
104
+ }
105
+ }
106
+ return {
107
+ summary: {
108
+ totalFiles: files.length,
109
+ totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
110
+ criticalIssues: results.reduce(
111
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 4).length,
112
+ 0
113
+ ),
114
+ majorIssues: results.reduce(
115
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 3).length,
116
+ 0
117
+ ),
118
+ score: riskResult.score,
119
+ rating: riskResult.rating,
120
+ recommendations: riskResult.recommendations
121
+ },
122
+ results
123
+ };
124
+ }
125
+
126
+ export {
127
+ __require,
128
+ analyzeChangeAmplification
129
+ };
package/dist/cli.js CHANGED
@@ -93,12 +93,19 @@ async function analyzeChangeAmplification(options) {
93
93
  });
94
94
  const riskResult = (0, import_core.calculateChangeAmplification)({ files: fileMetrics });
95
95
  const results = [];
96
+ const getLevel = (s) => {
97
+ if (s === import_core.Severity.Critical || s === "critical") return 4;
98
+ if (s === import_core.Severity.Major || s === "major") return 3;
99
+ if (s === import_core.Severity.Minor || s === "minor") return 2;
100
+ if (s === import_core.Severity.Info || s === "info") return 1;
101
+ return 0;
102
+ };
96
103
  for (const hotspot of riskResult.hotspots) {
97
104
  const issues = [];
98
105
  if (hotspot.amplificationFactor > 20) {
99
106
  issues.push({
100
- type: "change-amplification",
101
- severity: hotspot.amplificationFactor > 40 ? "critical" : "major",
107
+ type: import_core.IssueType.ChangeAmplification,
108
+ severity: hotspot.amplificationFactor > 40 ? import_core.Severity.Critical : import_core.Severity.Major,
102
109
  message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
103
110
  location: { file: hotspot.file, line: 1 },
104
111
  suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`
@@ -120,11 +127,11 @@ async function analyzeChangeAmplification(options) {
120
127
  totalFiles: files.length,
121
128
  totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
122
129
  criticalIssues: results.reduce(
123
- (sum, r) => sum + r.issues.filter((i) => i.severity === "critical").length,
130
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 4).length,
124
131
  0
125
132
  ),
126
133
  majorIssues: results.reduce(
127
- (sum, r) => sum + r.issues.filter((i) => i.severity === "major").length,
134
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 3).length,
128
135
  0
129
136
  ),
130
137
  score: riskResult.score,
package/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  __require,
4
4
  analyzeChangeAmplification
5
- } from "./chunk-3CM4X7K3.mjs";
5
+ } from "./chunk-GLHIV53G.mjs";
6
6
 
7
7
  // src/cli.ts
8
8
  import { Command } from "commander";
package/dist/index.d.mts CHANGED
@@ -1,15 +1,12 @@
1
- import { Issue, ScanOptions } from '@aiready/core';
1
+ import { Issue, IssueType, ScanOptions, AnalysisResult } from '@aiready/core';
2
2
 
3
- type ChangeAmplificationOptions = ScanOptions;
3
+ interface ChangeAmplificationOptions extends ScanOptions {
4
+ }
4
5
  interface ChangeAmplificationIssue extends Issue {
5
- type: 'change-amplification';
6
+ type: IssueType.ChangeAmplification;
6
7
  }
7
- interface FileChangeAmplificationResult {
8
- fileName: string;
8
+ interface FileChangeAmplificationResult extends AnalysisResult {
9
9
  issues: ChangeAmplificationIssue[];
10
- metrics: {
11
- aiSignalClarityScore?: number;
12
- };
13
10
  }
14
11
  interface ChangeAmplificationReport {
15
12
  summary: {
@@ -18,7 +15,7 @@ interface ChangeAmplificationReport {
18
15
  criticalIssues: number;
19
16
  majorIssues: number;
20
17
  score: number;
21
- rating: 'isolated' | 'contained' | 'amplified' | 'explosive';
18
+ rating: string;
22
19
  recommendations: string[];
23
20
  };
24
21
  results: FileChangeAmplificationResult[];
package/dist/index.d.ts CHANGED
@@ -1,15 +1,12 @@
1
- import { Issue, ScanOptions } from '@aiready/core';
1
+ import { Issue, IssueType, ScanOptions, AnalysisResult } from '@aiready/core';
2
2
 
3
- type ChangeAmplificationOptions = ScanOptions;
3
+ interface ChangeAmplificationOptions extends ScanOptions {
4
+ }
4
5
  interface ChangeAmplificationIssue extends Issue {
5
- type: 'change-amplification';
6
+ type: IssueType.ChangeAmplification;
6
7
  }
7
- interface FileChangeAmplificationResult {
8
- fileName: string;
8
+ interface FileChangeAmplificationResult extends AnalysisResult {
9
9
  issues: ChangeAmplificationIssue[];
10
- metrics: {
11
- aiSignalClarityScore?: number;
12
- };
13
10
  }
14
11
  interface ChangeAmplificationReport {
15
12
  summary: {
@@ -18,7 +15,7 @@ interface ChangeAmplificationReport {
18
15
  criticalIssues: number;
19
16
  majorIssues: number;
20
17
  score: number;
21
- rating: 'isolated' | 'contained' | 'amplified' | 'explosive';
18
+ rating: string;
22
19
  recommendations: string[];
23
20
  };
24
21
  results: FileChangeAmplificationResult[];
package/dist/index.js CHANGED
@@ -88,12 +88,19 @@ async function analyzeChangeAmplification(options) {
88
88
  });
89
89
  const riskResult = (0, import_core.calculateChangeAmplification)({ files: fileMetrics });
90
90
  const results = [];
91
+ const getLevel = (s) => {
92
+ if (s === import_core.Severity.Critical || s === "critical") return 4;
93
+ if (s === import_core.Severity.Major || s === "major") return 3;
94
+ if (s === import_core.Severity.Minor || s === "minor") return 2;
95
+ if (s === import_core.Severity.Info || s === "info") return 1;
96
+ return 0;
97
+ };
91
98
  for (const hotspot of riskResult.hotspots) {
92
99
  const issues = [];
93
100
  if (hotspot.amplificationFactor > 20) {
94
101
  issues.push({
95
- type: "change-amplification",
96
- severity: hotspot.amplificationFactor > 40 ? "critical" : "major",
102
+ type: import_core.IssueType.ChangeAmplification,
103
+ severity: hotspot.amplificationFactor > 40 ? import_core.Severity.Critical : import_core.Severity.Major,
97
104
  message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
98
105
  location: { file: hotspot.file, line: 1 },
99
106
  suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`
@@ -115,11 +122,11 @@ async function analyzeChangeAmplification(options) {
115
122
  totalFiles: files.length,
116
123
  totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
117
124
  criticalIssues: results.reduce(
118
- (sum, r) => sum + r.issues.filter((i) => i.severity === "critical").length,
125
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 4).length,
119
126
  0
120
127
  ),
121
128
  majorIssues: results.reduce(
122
- (sum, r) => sum + r.issues.filter((i) => i.severity === "major").length,
129
+ (sum, r) => sum + r.issues.filter((i) => getLevel(i.severity) === 3).length,
123
130
  0
124
131
  ),
125
132
  score: riskResult.score,
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  analyzeChangeAmplification
3
- } from "./chunk-3CM4X7K3.mjs";
3
+ } from "./chunk-GLHIV53G.mjs";
4
4
  export {
5
5
  analyzeChangeAmplification
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/change-amplification",
3
- "version": "0.9.2",
3
+ "version": "0.9.5",
4
4
  "description": "AI-Readiness: Change Amplification Detection",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -10,7 +10,7 @@
10
10
  "commander": "^14.0.0",
11
11
  "glob": "^13.0.0",
12
12
  "chalk": "^5.3.0",
13
- "@aiready/core": "0.19.2"
13
+ "@aiready/core": "0.19.5"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@types/node": "^24.0.0",
package/src/analyzer.ts CHANGED
@@ -4,6 +4,8 @@ import {
4
4
  scanFiles,
5
5
  calculateChangeAmplification,
6
6
  getParser,
7
+ Severity,
8
+ IssueType,
7
9
  } from '@aiready/core';
8
10
  import type {
9
11
  ChangeAmplificationOptions,
@@ -83,12 +85,22 @@ export async function analyzeChangeAmplification(
83
85
 
84
86
  const results: FileChangeAmplificationResult[] = [];
85
87
 
88
+ // Helper for severity mapping
89
+ const getLevel = (s: any): number => {
90
+ if (s === Severity.Critical || s === 'critical') return 4;
91
+ if (s === Severity.Major || s === 'major') return 3;
92
+ if (s === Severity.Minor || s === 'minor') return 2;
93
+ if (s === Severity.Info || s === 'info') return 1;
94
+ return 0;
95
+ };
96
+
86
97
  for (const hotspot of riskResult.hotspots) {
87
98
  const issues: ChangeAmplificationIssue[] = [];
88
99
  if (hotspot.amplificationFactor > 20) {
89
100
  issues.push({
90
- type: 'change-amplification',
91
- severity: hotspot.amplificationFactor > 40 ? 'critical' : 'major',
101
+ type: IssueType.ChangeAmplification,
102
+ severity:
103
+ hotspot.amplificationFactor > 40 ? Severity.Critical : Severity.Major,
92
104
  message: `High change amplification detected (Factor: ${hotspot.amplificationFactor}). Changes here cascade heavily.`,
93
105
  location: { file: hotspot.file, line: 1 },
94
106
  suggestion: `Reduce coupling. Fan-out is ${hotspot.fanOut}, Fan-in is ${hotspot.fanIn}.`,
@@ -113,11 +125,12 @@ export async function analyzeChangeAmplification(
113
125
  totalIssues: results.reduce((sum, r) => sum + r.issues.length, 0),
114
126
  criticalIssues: results.reduce(
115
127
  (sum, r) =>
116
- sum + r.issues.filter((i) => i.severity === 'critical').length,
128
+ sum + r.issues.filter((i) => getLevel(i.severity) === 4).length,
117
129
  0
118
130
  ),
119
131
  majorIssues: results.reduce(
120
- (sum, r) => sum + r.issues.filter((i) => i.severity === 'major').length,
132
+ (sum, r) =>
133
+ sum + r.issues.filter((i) => getLevel(i.severity) === 3).length,
121
134
  0
122
135
  ),
123
136
  score: riskResult.score,
package/src/types.ts CHANGED
@@ -1,17 +1,18 @@
1
- import type { ScanOptions, Issue } from '@aiready/core';
1
+ import type {
2
+ ScanOptions,
3
+ AnalysisResult,
4
+ Issue,
5
+ IssueType,
6
+ } from '@aiready/core';
2
7
 
3
- export type ChangeAmplificationOptions = ScanOptions;
8
+ export interface ChangeAmplificationOptions extends ScanOptions {}
4
9
 
5
10
  export interface ChangeAmplificationIssue extends Issue {
6
- type: 'change-amplification';
11
+ type: IssueType.ChangeAmplification;
7
12
  }
8
13
 
9
- export interface FileChangeAmplificationResult {
10
- fileName: string;
14
+ export interface FileChangeAmplificationResult extends AnalysisResult {
11
15
  issues: ChangeAmplificationIssue[];
12
- metrics: {
13
- aiSignalClarityScore?: number;
14
- };
15
16
  }
16
17
 
17
18
  export interface ChangeAmplificationReport {
@@ -21,7 +22,7 @@ export interface ChangeAmplificationReport {
21
22
  criticalIssues: number;
22
23
  majorIssues: number;
23
24
  score: number;
24
- rating: 'isolated' | 'contained' | 'amplified' | 'explosive';
25
+ rating: string;
25
26
  recommendations: string[];
26
27
  };
27
28
  results: FileChangeAmplificationResult[];