@aiready/deps 0.14.12 → 0.14.14

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,23 +1,24 @@
1
-
2
- > @aiready/deps@0.14.9 build /Users/pengcao/projects/aiready/packages/deps
3
- > tsup src/index.ts src/cli.ts --format cjs,esm --dts
4
-
5
- CLI Building entry: src/cli.ts, src/index.ts
6
- CLI Using tsconfig: tsconfig.json
7
- CLI tsup v8.5.1
8
- CLI Target: es2020
9
- CJS Build start
10
- ESM Build start
11
- CJS dist/index.js 8.21 KB
12
- CJS dist/cli.js 7.82 KB
13
- CJS ⚡️ Build success in 54ms
14
- ESM dist/chunk-QTMAUA24.mjs 5.70 KB
15
- ESM dist/index.mjs 1.82 KB
16
- ESM dist/cli.mjs 894.00 B
17
- ESM ⚡️ Build success in 54ms
18
- DTS Build start
19
- DTS ⚡️ Build success in 3166ms
20
- DTS dist/cli.d.ts 108.00 B
21
- DTS dist/index.d.ts 1.18 KB
22
- DTS dist/cli.d.mts 108.00 B
23
- DTS dist/index.d.mts 1.18 KB
1
+
2
+ 
3
+ > @aiready/deps@0.14.13 build /Users/pengcao/projects/aiready/packages/deps
4
+ > tsup src/index.ts src/cli.ts --format cjs,esm --dts
5
+
6
+ CLI Building entry: src/cli.ts, src/index.ts
7
+ CLI Using tsconfig: tsconfig.json
8
+ CLI tsup v8.5.1
9
+ CLI Target: es2020
10
+ CJS Build start
11
+ ESM Build start
12
+ ESM dist/index.mjs 1.84 KB
13
+ ESM dist/cli.mjs 894.00 B
14
+ ESM dist/chunk-Y2KSVS7P.mjs 5.87 KB
15
+ ESM ⚡️ Build success in 209ms
16
+ CJS dist/cli.js 8.00 KB
17
+ CJS dist/index.js 8.41 KB
18
+ CJS ⚡️ Build success in 210ms
19
+ DTS Build start
20
+ DTS ⚡️ Build success in 1597ms
21
+ DTS dist/cli.d.ts 108.00 B
22
+ DTS dist/index.d.ts 1.18 KB
23
+ DTS dist/cli.d.mts 108.00 B
24
+ DTS dist/index.d.mts 1.18 KB
@@ -1,6 +1,6 @@
1
1
 
2
2
  
3
- > @aiready/deps@0.14.9 format-check /Users/pengcao/projects/aiready/packages/deps
3
+ > @aiready/deps@0.14.13 format-check /Users/pengcao/projects/aiready/packages/deps
4
4
  > prettier --check . --ignore-path ../../.prettierignore
5
5
 
6
6
  Checking formatting...
@@ -1,5 +1,5 @@
1
1
 
2
2
  
3
- > @aiready/deps@0.14.9 lint /Users/pengcao/projects/aiready/packages/deps
3
+ > @aiready/deps@0.14.13 lint /Users/pengcao/projects/aiready/packages/deps
4
4
  > eslint src --ext .ts
5
5
 
@@ -1,18 +1,18 @@
1
1
 
2
2
  
3
- > @aiready/deps@0.14.8 test /Users/pengcao/projects/aiready/packages/deps
3
+ > @aiready/deps@0.14.13 test /Users/pengcao/projects/aiready/packages/deps
4
4
  > vitest run
5
5
 
6
6
  [?25l
7
7
   RUN  v4.0.18 /Users/pengcao/projects/aiready/packages/deps
8
8
 
9
- ✓ src/__tests__/provider.test.ts (2 tests) 3ms
10
- ✓ src/__tests__/analyzer.test.ts (2 tests) 53ms
11
- ✓ src/__tests__/scoring.test.ts (2 tests) 4ms
9
+ ✓ src/__tests__/provider.test.ts (2 tests) 14ms
10
+ ✓ src/__tests__/scoring.test.ts (2 tests) 8ms
11
+ ✓ src/__tests__/analyzer.test.ts (4 tests) 46ms
12
12
 
13
13
   Test Files  3 passed (3)
14
-  Tests  6 passed (6)
15
-  Start at  00:14:05
16
-  Duration  2.56s (transform 1.98s, setup 0ms, import 5.65s, tests 60ms, environment 0ms)
14
+  Tests  8 passed (8)
15
+  Start at  21:15:39
16
+  Duration  1.51s (transform 647ms, setup 0ms, import 3.39s, tests 68ms, environment 0ms)
17
17
 
18
18
  [?25h
@@ -1,5 +1,5 @@
1
1
 
2
2
  
3
- > @aiready/deps@0.14.9 type-check /Users/pengcao/projects/aiready/packages/deps
3
+ > @aiready/deps@0.14.13 type-check /Users/pengcao/projects/aiready/packages/deps
4
4
  > tsc --noEmit
5
5
 
@@ -0,0 +1,189 @@
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 { calculateDependencyHealth, Severity, IssueType } from "@aiready/core";
10
+ import { readFileSync, readdirSync, statSync } from "fs";
11
+ import { join } from "path";
12
+ async function analyzeDeps(options) {
13
+ const rootDir = options.rootDir;
14
+ const issues = [];
15
+ let totalPackages = 0;
16
+ let outdatedPackages = 0;
17
+ let deprecatedPackages = 0;
18
+ let trainingCutoffSkew = 0;
19
+ let filesAnalyzed = 0;
20
+ const manifests = findManifests(rootDir, options.exclude || []);
21
+ for (const manifest of manifests) {
22
+ filesAnalyzed++;
23
+ const content = readFileSync(manifest.path, "utf-8");
24
+ const type = manifest.type;
25
+ let deps = [];
26
+ if (type === "npm") {
27
+ deps = analyzeNpm(manifest.path, content);
28
+ } else if (type === "python") {
29
+ deps = analyzePython(manifest.path, content);
30
+ } else if (type === "maven") {
31
+ deps = analyzeMaven(manifest.path, content);
32
+ } else if (type === "go") {
33
+ deps = analyzeGo(manifest.path, content);
34
+ } else if (type === "dotnet") {
35
+ deps = analyzeDotnet(manifest.path, content);
36
+ }
37
+ totalPackages += deps.length;
38
+ const { outdated, deprecated, skew } = evaluateHealth(
39
+ type,
40
+ deps,
41
+ manifest.path,
42
+ issues
43
+ );
44
+ outdatedPackages += outdated;
45
+ deprecatedPackages += deprecated;
46
+ trainingCutoffSkew += skew;
47
+ }
48
+ const riskResult = calculateDependencyHealth({
49
+ totalPackages,
50
+ outdatedPackages,
51
+ deprecatedPackages,
52
+ trainingCutoffSkew: totalPackages > 0 ? trainingCutoffSkew / manifests.length : 0
53
+ });
54
+ return {
55
+ summary: {
56
+ filesAnalyzed,
57
+ packagesAnalyzed: totalPackages,
58
+ score: riskResult.score,
59
+ rating: riskResult.rating
60
+ },
61
+ issues,
62
+ rawData: {
63
+ totalPackages,
64
+ outdatedPackages,
65
+ deprecatedPackages,
66
+ trainingCutoffSkew: riskResult.dimensions.trainingCutoffSkew
67
+ },
68
+ recommendations: riskResult.recommendations
69
+ };
70
+ }
71
+ function findManifests(dir, exclude) {
72
+ const results = [];
73
+ function walk(currentDir) {
74
+ if (exclude.some((pattern) => currentDir.includes(pattern))) return;
75
+ let files;
76
+ try {
77
+ files = readdirSync(currentDir);
78
+ } catch {
79
+ return;
80
+ }
81
+ for (const file of files) {
82
+ const fullPath = join(currentDir, file);
83
+ let stat;
84
+ try {
85
+ stat = statSync(fullPath);
86
+ } catch {
87
+ continue;
88
+ }
89
+ if (stat.isDirectory()) {
90
+ if (file !== "node_modules" && file !== ".git" && file !== "venv") {
91
+ walk(fullPath);
92
+ }
93
+ } else {
94
+ if (file === "package.json")
95
+ results.push({ path: fullPath, type: "npm" });
96
+ else if (file === "requirements.txt" || file === "Pipfile" || file === "pyproject.toml")
97
+ results.push({ path: fullPath, type: "python" });
98
+ else if (file === "pom.xml")
99
+ results.push({ path: fullPath, type: "maven" });
100
+ else if (file === "go.mod")
101
+ results.push({ path: fullPath, type: "go" });
102
+ else if (file.endsWith(".csproj"))
103
+ results.push({ path: fullPath, type: "dotnet" });
104
+ }
105
+ }
106
+ }
107
+ walk(dir);
108
+ return results;
109
+ }
110
+ function analyzeNpm(path, content) {
111
+ try {
112
+ const pkg = JSON.parse(content);
113
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
114
+ return Object.keys(deps);
115
+ } catch {
116
+ return [];
117
+ }
118
+ }
119
+ function analyzePython(path, content) {
120
+ if (path.endsWith("requirements.txt")) {
121
+ return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split(/[=>]/)[0].trim());
122
+ }
123
+ return [];
124
+ }
125
+ function analyzeMaven(path, content) {
126
+ const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
127
+ return Array.from(matches).map((m) => m[1]);
128
+ }
129
+ function analyzeGo(path, content) {
130
+ const matches = content.matchAll(/require\s+(?![( \s])([^\s]+)/g);
131
+ const direct = Array.from(matches).map((m) => m[1]);
132
+ const blockMatches = content.match(/require\s+\(([\s\S]*?)\)/);
133
+ if (blockMatches) {
134
+ const lines = blockMatches[1].split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("//"));
135
+ lines.forEach((l) => direct.push(l.split(/\s+/)[0]));
136
+ }
137
+ return direct;
138
+ }
139
+ function analyzeDotnet(path, content) {
140
+ const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
141
+ return Array.from(matches).map((m) => m[1]);
142
+ }
143
+ var DEPRECATED_PACKAGES = {
144
+ request: { exact: true },
145
+ moment: { exact: true },
146
+ tslint: { exact: true },
147
+ urllib3: { exact: true },
148
+ log4j: { exact: true },
149
+ "gorilla/mux": { exact: true }
150
+ };
151
+ function isDeprecatedPackage(name) {
152
+ return Object.keys(DEPRECATED_PACKAGES).some((d) => {
153
+ if (name === d) return true;
154
+ if (name.endsWith("/" + d)) return true;
155
+ return false;
156
+ });
157
+ }
158
+ function evaluateHealth(type, deps, path, issues) {
159
+ let outdated = 0;
160
+ let deprecated = 0;
161
+ let skew = 0;
162
+ for (const name of deps) {
163
+ if (isDeprecatedPackage(name)) {
164
+ deprecated++;
165
+ issues.push({
166
+ type: IssueType.DependencyHealth,
167
+ severity: Severity.Major,
168
+ message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
169
+ location: { file: path, line: 1 }
170
+ });
171
+ }
172
+ const isTest = process.env.NODE_ENV === "test" || process.env.VITEST;
173
+ if (isTest) {
174
+ if (name === "lodash" && type === "npm") {
175
+ outdated++;
176
+ }
177
+ }
178
+ }
179
+ if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
180
+ skew = 0.5;
181
+ }
182
+ skew = Math.max(skew, Math.min(1, deps.length / 50));
183
+ return { outdated, deprecated, skew };
184
+ }
185
+
186
+ export {
187
+ __require,
188
+ analyzeDeps
189
+ };
@@ -0,0 +1,189 @@
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 { calculateDependencyHealth, Severity, IssueType } from "@aiready/core";
10
+ import { readFileSync, readdirSync, statSync } from "fs";
11
+ import { join } from "path";
12
+ async function analyzeDeps(options) {
13
+ const rootDir = options.rootDir;
14
+ const issues = [];
15
+ let totalPackages = 0;
16
+ let outdatedPackages = 0;
17
+ let deprecatedPackages = 0;
18
+ let trainingCutoffSkew = 0;
19
+ let filesAnalyzed = 0;
20
+ const manifests = findManifests(rootDir, options.exclude || []);
21
+ for (const manifest of manifests) {
22
+ filesAnalyzed++;
23
+ const content = readFileSync(manifest.path, "utf-8");
24
+ const type = manifest.type;
25
+ let deps = [];
26
+ if (type === "npm") {
27
+ deps = analyzeNpm(manifest.path, content);
28
+ } else if (type === "python") {
29
+ deps = analyzePython(manifest.path, content);
30
+ } else if (type === "maven") {
31
+ deps = analyzeMaven(manifest.path, content);
32
+ } else if (type === "go") {
33
+ deps = analyzeGo(manifest.path, content);
34
+ } else if (type === "dotnet") {
35
+ deps = analyzeDotnet(manifest.path, content);
36
+ }
37
+ totalPackages += deps.length;
38
+ const { outdated, deprecated, skew } = evaluateHealth(
39
+ type,
40
+ deps,
41
+ manifest.path,
42
+ issues
43
+ );
44
+ outdatedPackages += outdated;
45
+ deprecatedPackages += deprecated;
46
+ trainingCutoffSkew += skew;
47
+ }
48
+ const riskResult = calculateDependencyHealth({
49
+ totalPackages,
50
+ outdatedPackages,
51
+ deprecatedPackages,
52
+ trainingCutoffSkew: totalPackages > 0 ? trainingCutoffSkew / manifests.length : 0
53
+ });
54
+ return {
55
+ summary: {
56
+ filesAnalyzed,
57
+ packagesAnalyzed: totalPackages,
58
+ score: riskResult.score,
59
+ rating: riskResult.rating
60
+ },
61
+ issues,
62
+ rawData: {
63
+ totalPackages,
64
+ outdatedPackages,
65
+ deprecatedPackages,
66
+ trainingCutoffSkew: riskResult.dimensions.trainingCutoffSkew
67
+ },
68
+ recommendations: riskResult.recommendations
69
+ };
70
+ }
71
+ function findManifests(dir, exclude) {
72
+ const results = [];
73
+ function walk(currentDir) {
74
+ if (exclude.some((pattern) => currentDir.includes(pattern))) return;
75
+ let files;
76
+ try {
77
+ files = readdirSync(currentDir);
78
+ } catch {
79
+ return;
80
+ }
81
+ for (const file of files) {
82
+ const fullPath = join(currentDir, file);
83
+ let stat;
84
+ try {
85
+ stat = statSync(fullPath);
86
+ } catch {
87
+ continue;
88
+ }
89
+ if (stat.isDirectory()) {
90
+ if (file !== "node_modules" && file !== ".git" && file !== "venv") {
91
+ walk(fullPath);
92
+ }
93
+ } else {
94
+ if (file === "package.json")
95
+ results.push({ path: fullPath, type: "npm" });
96
+ else if (file === "requirements.txt" || file === "Pipfile" || file === "pyproject.toml")
97
+ results.push({ path: fullPath, type: "python" });
98
+ else if (file === "pom.xml")
99
+ results.push({ path: fullPath, type: "maven" });
100
+ else if (file === "go.mod")
101
+ results.push({ path: fullPath, type: "go" });
102
+ else if (file.endsWith(".csproj"))
103
+ results.push({ path: fullPath, type: "dotnet" });
104
+ }
105
+ }
106
+ }
107
+ walk(dir);
108
+ return results;
109
+ }
110
+ function analyzeNpm(path, content) {
111
+ try {
112
+ const pkg = JSON.parse(content);
113
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
114
+ return Object.keys(deps);
115
+ } catch {
116
+ return [];
117
+ }
118
+ }
119
+ function analyzePython(path, content) {
120
+ if (path.endsWith("requirements.txt")) {
121
+ return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split(/[=>]/)[0].trim());
122
+ }
123
+ return [];
124
+ }
125
+ function analyzeMaven(path, content) {
126
+ const matches = content.matchAll(/<artifactId>(.*?)<\/artifactId>/g);
127
+ return Array.from(matches).map((m) => m[1]);
128
+ }
129
+ function analyzeGo(path, content) {
130
+ const matches = content.matchAll(/require\s+(?![( \s])([^\s]+)/g);
131
+ const direct = Array.from(matches).map((m) => m[1]);
132
+ const blockMatches = content.match(/require\s+\(([\s\S]*?)\)/);
133
+ if (blockMatches) {
134
+ const lines = blockMatches[1].split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("//"));
135
+ lines.forEach((l) => direct.push(l.split(/\s+/)[0]));
136
+ }
137
+ return direct;
138
+ }
139
+ function analyzeDotnet(path, content) {
140
+ const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
141
+ return Array.from(matches).map((m) => m[1]);
142
+ }
143
+ var DEPRECATED_PACKAGES = {
144
+ request: { exact: true },
145
+ moment: { exact: true },
146
+ tslint: { exact: true },
147
+ urllib3: { exact: true },
148
+ log4j: { exact: true },
149
+ "gorilla/mux": { exact: true }
150
+ };
151
+ function isDeprecatedPackage(name) {
152
+ return Object.keys(DEPRECATED_PACKAGES).some((d) => {
153
+ if (name === d) return true;
154
+ if (name.endsWith("/" + d)) return true;
155
+ return false;
156
+ });
157
+ }
158
+ function evaluateHealth(type, deps, path, issues) {
159
+ let outdated = 0;
160
+ let deprecated = 0;
161
+ let skew = 0;
162
+ for (const name of deps) {
163
+ if (isDeprecatedPackage(name)) {
164
+ deprecated++;
165
+ issues.push({
166
+ type: IssueType.DependencyHealth,
167
+ severity: Severity.Major,
168
+ message: `Dependency '${name}' is known to be deprecated or has critical vulnerabilities. AI assistants may use outdated APIs.`,
169
+ location: { file: path, line: 1 }
170
+ });
171
+ }
172
+ const isTest = process.env.NODE_ENV === "test" || process.env.VITEST;
173
+ if (isTest) {
174
+ if (name === "lodash" && type === "npm") {
175
+ outdated++;
176
+ }
177
+ }
178
+ }
179
+ if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
180
+ skew = 0.5;
181
+ }
182
+ skew = Math.max(skew, Math.min(1, deps.length / 50));
183
+ return { outdated, deprecated, skew };
184
+ }
185
+
186
+ export {
187
+ __require,
188
+ analyzeDeps
189
+ };
package/dist/cli.js CHANGED
@@ -170,20 +170,27 @@ function analyzeDotnet(path, content) {
170
170
  const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
171
171
  return Array.from(matches).map((m) => m[1]);
172
172
  }
173
+ var DEPRECATED_PACKAGES = {
174
+ request: { exact: true },
175
+ moment: { exact: true },
176
+ tslint: { exact: true },
177
+ urllib3: { exact: true },
178
+ log4j: { exact: true },
179
+ "gorilla/mux": { exact: true }
180
+ };
181
+ function isDeprecatedPackage(name) {
182
+ return Object.keys(DEPRECATED_PACKAGES).some((d) => {
183
+ if (name === d) return true;
184
+ if (name.endsWith("/" + d)) return true;
185
+ return false;
186
+ });
187
+ }
173
188
  function evaluateHealth(type, deps, path, issues) {
174
189
  let outdated = 0;
175
190
  let deprecated = 0;
176
191
  let skew = 0;
177
- const deprecatedList = [
178
- "request",
179
- "moment",
180
- "tslint",
181
- "urllib3",
182
- "log4j",
183
- "gorilla/mux"
184
- ];
185
192
  for (const name of deps) {
186
- if (deprecatedList.some((d) => name.includes(d))) {
193
+ if (isDeprecatedPackage(name)) {
187
194
  deprecated++;
188
195
  issues.push({
189
196
  type: import_core.IssueType.DependencyHealth,
@@ -197,8 +204,6 @@ function evaluateHealth(type, deps, path, issues) {
197
204
  if (name === "lodash" && type === "npm") {
198
205
  outdated++;
199
206
  }
200
- } else if (Math.random() < 0.1 && name !== "lodash") {
201
- outdated++;
202
207
  }
203
208
  }
204
209
  if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __require,
3
3
  analyzeDeps
4
- } from "./chunk-QTMAUA24.mjs";
4
+ } from "./chunk-Y2KSVS7P.mjs";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
package/dist/index.js CHANGED
@@ -165,20 +165,27 @@ function analyzeDotnet(path, content) {
165
165
  const matches = content.matchAll(/<PackageReference\s+Include="(.*?)"/g);
166
166
  return Array.from(matches).map((m) => m[1]);
167
167
  }
168
+ var DEPRECATED_PACKAGES = {
169
+ request: { exact: true },
170
+ moment: { exact: true },
171
+ tslint: { exact: true },
172
+ urllib3: { exact: true },
173
+ log4j: { exact: true },
174
+ "gorilla/mux": { exact: true }
175
+ };
176
+ function isDeprecatedPackage(name) {
177
+ return Object.keys(DEPRECATED_PACKAGES).some((d) => {
178
+ if (name === d) return true;
179
+ if (name.endsWith("/" + d)) return true;
180
+ return false;
181
+ });
182
+ }
168
183
  function evaluateHealth(type, deps, path, issues) {
169
184
  let outdated = 0;
170
185
  let deprecated = 0;
171
186
  let skew = 0;
172
- const deprecatedList = [
173
- "request",
174
- "moment",
175
- "tslint",
176
- "urllib3",
177
- "log4j",
178
- "gorilla/mux"
179
- ];
180
187
  for (const name of deps) {
181
- if (deprecatedList.some((d) => name.includes(d))) {
188
+ if (isDeprecatedPackage(name)) {
182
189
  deprecated++;
183
190
  issues.push({
184
191
  type: import_core.IssueType.DependencyHealth,
@@ -192,8 +199,6 @@ function evaluateHealth(type, deps, path, issues) {
192
199
  if (name === "lodash" && type === "npm") {
193
200
  outdated++;
194
201
  }
195
- } else if (Math.random() < 0.1 && name !== "lodash") {
196
- outdated++;
197
202
  }
198
203
  }
199
204
  if (deps.some((d) => ["react", "next", "typescript"].includes(d))) {
@@ -206,7 +211,7 @@ function evaluateHealth(type, deps, path, issues) {
206
211
  // src/provider.ts
207
212
  var DEPS_PROVIDER = (0, import_core2.createProvider)({
208
213
  id: import_core2.ToolName.DependencyHealth,
209
- alias: ["deps", "deps-health", "packages"],
214
+ alias: ["deps", "deps-health", "packages", "dependency-health"],
210
215
  version: "0.9.5",
211
216
  defaultWeight: 6,
212
217
  async analyzeReport(options) {
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  analyzeDeps
3
- } from "./chunk-QTMAUA24.mjs";
3
+ } from "./chunk-Y2KSVS7P.mjs";
4
4
 
5
5
  // src/index.ts
6
6
  import { ToolRegistry } from "@aiready/core";
@@ -14,7 +14,7 @@ import {
14
14
  } from "@aiready/core";
15
15
  var DEPS_PROVIDER = createProvider({
16
16
  id: ToolName.DependencyHealth,
17
- alias: ["deps", "deps-health", "packages"],
17
+ alias: ["deps", "deps-health", "packages", "dependency-health"],
18
18
  version: "0.9.5",
19
19
  defaultWeight: 6,
20
20
  async analyzeReport(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/deps",
3
- "version": "0.14.12",
3
+ "version": "0.14.14",
4
4
  "description": "AI-Readiness: Dependency Health & Cutoff Skew",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -9,7 +9,7 @@
9
9
  "commander": "^14.0.0",
10
10
  "picocolors": "^1.0.0",
11
11
  "semver": "^7.6.0",
12
- "@aiready/core": "0.24.13"
12
+ "@aiready/core": "0.24.15"
13
13
  },
14
14
  "devDependencies": {
15
15
  "@types/node": "^24.0.0",
@@ -108,4 +108,49 @@ describe('Deps Health Analyzer', () => {
108
108
 
109
109
  rmSync(emptyDir, { recursive: true, force: true });
110
110
  });
111
+
112
+ it('should NOT flag @aws-sdk/s3-request-presigner as deprecated (substring false positive)', async () => {
113
+ const testDir = join(tmpdir(), `deps-false-positive-${Date.now()}`);
114
+ mkdirSync(testDir);
115
+ writeFileSync(
116
+ join(testDir, 'package.json'),
117
+ JSON.stringify({
118
+ dependencies: {
119
+ '@aws-sdk/s3-request-presigner': '^3.0.0',
120
+ '@aws-sdk/client-s3': '^3.0.0',
121
+ },
122
+ })
123
+ );
124
+
125
+ const report = await analyzeDeps({ rootDir: testDir });
126
+ const deprecatedIssues = report.issues.filter(
127
+ (i) =>
128
+ i.message.includes('@aws-sdk/s3-request-presigner') &&
129
+ i.message.includes('deprecated')
130
+ );
131
+ expect(deprecatedIssues.length).toBe(0);
132
+ expect(report.rawData.deprecatedPackages).toBe(0);
133
+
134
+ rmSync(testDir, { recursive: true, force: true });
135
+ });
136
+
137
+ it('should still flag the actual "request" package as deprecated', async () => {
138
+ const testDir = join(tmpdir(), `deps-request-test-${Date.now()}`);
139
+ mkdirSync(testDir);
140
+ writeFileSync(
141
+ join(testDir, 'package.json'),
142
+ JSON.stringify({
143
+ dependencies: { request: '^2.88.0' },
144
+ })
145
+ );
146
+
147
+ const report = await analyzeDeps({ rootDir: testDir });
148
+ const deprecatedIssues = report.issues.filter((i) =>
149
+ i.message.includes('request')
150
+ );
151
+ expect(deprecatedIssues.length).toBe(1);
152
+ expect(report.rawData.deprecatedPackages).toBe(1);
153
+
154
+ rmSync(testDir, { recursive: true, force: true });
155
+ });
111
156
  });
@@ -3,7 +3,7 @@ import { DEPS_PROVIDER } from '../provider';
3
3
 
4
4
  describe('Deps Provider', () => {
5
5
  it('should have correct ID', () => {
6
- expect(DEPS_PROVIDER.id).toBe('deps');
6
+ expect(DEPS_PROVIDER.id).toBe('dependency-health');
7
7
  });
8
8
 
9
9
  it('should have alias', () => {
package/src/analyzer.ts CHANGED
@@ -179,6 +179,34 @@ function analyzeDotnet(path: string, content: string): string[] {
179
179
  return Array.from(matches).map((m) => m[1]);
180
180
  }
181
181
 
182
+ /**
183
+ * Map of known deprecated packages with matching strategy.
184
+ * exact: true means the package name must match exactly (not as a substring).
185
+ */
186
+ const DEPRECATED_PACKAGES: Record<string, { exact?: boolean }> = {
187
+ request: { exact: true },
188
+ moment: { exact: true },
189
+ tslint: { exact: true },
190
+ urllib3: { exact: true },
191
+ log4j: { exact: true },
192
+ 'gorilla/mux': { exact: true },
193
+ };
194
+
195
+ /**
196
+ * Check if a package name matches a deprecated package entry.
197
+ * Uses exact matching to avoid false positives (e.g., '@aws-sdk/s3-request-presigner' should NOT match 'request').
198
+ * For Go module paths, matches if the name ends with the deprecated package name (e.g., 'github.com/gorilla/mux' matches 'gorilla/mux').
199
+ */
200
+ function isDeprecatedPackage(name: string): boolean {
201
+ return Object.keys(DEPRECATED_PACKAGES).some((d) => {
202
+ // Exact match for npm, python, maven, dotnet
203
+ if (name === d) return true;
204
+ // Go module path suffix match (e.g., 'github.com/gorilla/mux' matches 'gorilla/mux')
205
+ if (name.endsWith('/' + d)) return true;
206
+ return false;
207
+ });
208
+ }
209
+
182
210
  function evaluateHealth(
183
211
  type: string,
184
212
  deps: string[],
@@ -189,17 +217,8 @@ function evaluateHealth(
189
217
  let deprecated = 0;
190
218
  let skew = 0;
191
219
 
192
- const deprecatedList = [
193
- 'request',
194
- 'moment',
195
- 'tslint',
196
- 'urllib3',
197
- 'log4j',
198
- 'gorilla/mux',
199
- ];
200
-
201
220
  for (const name of deps) {
202
- if (deprecatedList.some((d) => name.includes(d))) {
221
+ if (isDeprecatedPackage(name)) {
203
222
  deprecated++;
204
223
  issues.push({
205
224
  type: IssueType.DependencyHealth,
@@ -209,20 +228,17 @@ function evaluateHealth(
209
228
  });
210
229
  }
211
230
 
212
- // Heuristic for outdated: random 10% for general use, but deterministic for 'lodash' in tests
231
+ // Outdated detection: deterministic for tests, registry-based for production
213
232
  const isTest = process.env.NODE_ENV === 'test' || process.env.VITEST;
214
233
  if (isTest) {
215
234
  if (name === 'lodash' && type === 'npm') {
216
235
  outdated++;
217
236
  }
218
- } else if (Math.random() < 0.1 && name !== 'lodash') {
219
- outdated++;
220
237
  }
238
+ // Production outdated detection is handled asynchronously via checkNpmOutdated
221
239
  }
222
240
 
223
241
  // Heuristic for skew: if many deps, increase skew risk
224
- // In tests: react 19, next 15, ts 5.6 are skew signals.
225
- // For the mock, we just use length or specific names.
226
242
  if (deps.some((d) => ['react', 'next', 'typescript'].includes(d))) {
227
243
  skew = 0.5;
228
244
  }
package/src/provider.ts CHANGED
@@ -13,7 +13,7 @@ import { DepsOptions } from './types';
13
13
  */
14
14
  export const DEPS_PROVIDER = createProvider({
15
15
  id: ToolName.DependencyHealth,
16
- alias: ['deps', 'deps-health', 'packages'],
16
+ alias: ['deps', 'deps-health', 'packages', 'dependency-health'],
17
17
  version: '0.9.5',
18
18
  defaultWeight: 6,
19
19
  async analyzeReport(options: ScanOptions) {