@vibgrate/cli 1.0.23 → 1.0.25
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.
|
@@ -286,21 +286,24 @@ var FileCache = class _FileCache {
|
|
|
286
286
|
}
|
|
287
287
|
let entries;
|
|
288
288
|
try {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
289
|
+
entries = await sem.run(async () => {
|
|
290
|
+
const readPromise = fs.readdir(dir, { withFileTypes: true });
|
|
291
|
+
const result = await Promise.race([
|
|
292
|
+
readPromise.then((e) => ({ ok: true, entries: e })),
|
|
293
|
+
new Promise(
|
|
294
|
+
(resolve7) => setTimeout(() => resolve7({ ok: false }), STUCK_TIMEOUT_MS)
|
|
295
|
+
)
|
|
296
|
+
]);
|
|
297
|
+
if (!result.ok) {
|
|
298
|
+
stuckDirs.push(relDir || dir);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
return result.entries;
|
|
302
|
+
});
|
|
301
303
|
} catch {
|
|
302
304
|
return;
|
|
303
305
|
}
|
|
306
|
+
if (!entries) return;
|
|
304
307
|
const subWalks = [];
|
|
305
308
|
for (const e of entries) {
|
|
306
309
|
const absPath = path2.join(dir, e.name);
|
|
@@ -309,7 +312,7 @@ var FileCache = class _FileCache {
|
|
|
309
312
|
if (e.isDirectory()) {
|
|
310
313
|
if (SKIP_DIRS.has(e.name) || extraSkip.has(e.name)) continue;
|
|
311
314
|
results.push({ absPath, relPath, name: e.name, isFile: false, isDirectory: true });
|
|
312
|
-
subWalks.push(
|
|
315
|
+
subWalks.push(walk(absPath));
|
|
313
316
|
} else if (e.isFile()) {
|
|
314
317
|
const ext = path2.extname(e.name).toLowerCase();
|
|
315
318
|
if (SKIP_EXTENSIONS.has(ext)) continue;
|
|
@@ -323,7 +326,7 @@ var FileCache = class _FileCache {
|
|
|
323
326
|
}
|
|
324
327
|
await Promise.all(subWalks);
|
|
325
328
|
}
|
|
326
|
-
await
|
|
329
|
+
await walk(rootDir);
|
|
327
330
|
if (onProgress && foundCount !== lastReported) {
|
|
328
331
|
onProgress(foundCount, "");
|
|
329
332
|
}
|
|
@@ -436,7 +439,7 @@ async function quickTreeCount(rootDir, excludePatterns) {
|
|
|
436
439
|
async function count(dir) {
|
|
437
440
|
let entries;
|
|
438
441
|
try {
|
|
439
|
-
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
442
|
+
entries = await sem.run(() => fs.readdir(dir, { withFileTypes: true }));
|
|
440
443
|
} catch {
|
|
441
444
|
return;
|
|
442
445
|
}
|
|
@@ -447,7 +450,7 @@ async function quickTreeCount(rootDir, excludePatterns) {
|
|
|
447
450
|
if (e.isDirectory()) {
|
|
448
451
|
if (SKIP_DIRS.has(e.name) || extraSkip.has(e.name)) continue;
|
|
449
452
|
totalDirs++;
|
|
450
|
-
subs.push(
|
|
453
|
+
subs.push(count(path2.join(dir, e.name)));
|
|
451
454
|
} else if (e.isFile()) {
|
|
452
455
|
const ext = path2.extname(e.name).toLowerCase();
|
|
453
456
|
if (!SKIP_EXTENSIONS.has(ext)) totalFiles++;
|
|
@@ -455,7 +458,7 @@ async function quickTreeCount(rootDir, excludePatterns) {
|
|
|
455
458
|
}
|
|
456
459
|
await Promise.all(subs);
|
|
457
460
|
}
|
|
458
|
-
await
|
|
461
|
+
await count(rootDir);
|
|
459
462
|
return { totalFiles, totalDirs };
|
|
460
463
|
}
|
|
461
464
|
async function findFiles(rootDir, predicate) {
|
|
@@ -466,7 +469,7 @@ async function findFiles(rootDir, predicate) {
|
|
|
466
469
|
async function walk(dir) {
|
|
467
470
|
let entries;
|
|
468
471
|
try {
|
|
469
|
-
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
472
|
+
entries = await readDirSemaphore.run(() => fs.readdir(dir, { withFileTypes: true }));
|
|
470
473
|
} catch {
|
|
471
474
|
return;
|
|
472
475
|
}
|
|
@@ -474,7 +477,7 @@ async function findFiles(rootDir, predicate) {
|
|
|
474
477
|
for (const e of entries) {
|
|
475
478
|
if (e.isDirectory()) {
|
|
476
479
|
if (SKIP_DIRS.has(e.name)) continue;
|
|
477
|
-
subDirectoryWalks.push(
|
|
480
|
+
subDirectoryWalks.push(walk(path2.join(dir, e.name)));
|
|
478
481
|
} else if (e.isFile() && predicate(e.name)) {
|
|
479
482
|
const ext = path2.extname(e.name).toLowerCase();
|
|
480
483
|
if (!SKIP_EXTENSIONS.has(ext)) results.push(path2.join(dir, e.name));
|
|
@@ -482,7 +485,7 @@ async function findFiles(rootDir, predicate) {
|
|
|
482
485
|
}
|
|
483
486
|
await Promise.all(subDirectoryWalks);
|
|
484
487
|
}
|
|
485
|
-
await
|
|
488
|
+
await walk(rootDir);
|
|
486
489
|
return results;
|
|
487
490
|
}
|
|
488
491
|
async function findPackageJsonFiles(rootDir) {
|
|
@@ -1050,13 +1053,15 @@ function formatArchitectureDiagram(arch) {
|
|
|
1050
1053
|
const layer = visibleLayers[i];
|
|
1051
1054
|
const icon = LAYER_ICONS[layer.layer] ?? "\xB7";
|
|
1052
1055
|
const label = LAYER_LABELS[layer.layer] ?? layer.layer;
|
|
1053
|
-
const
|
|
1056
|
+
const hasScore = layer.driftScore !== null;
|
|
1057
|
+
const ds = layer.driftScore ?? 0;
|
|
1058
|
+
const scoreColor = !hasScore ? chalk.dim : ds >= 70 ? chalk.green : ds >= 40 ? chalk.yellow : chalk.red;
|
|
1054
1059
|
const riskBadgeStr = layer.riskLevel === "low" ? chalk.bgGreen.black(" LOW ") : layer.riskLevel === "moderate" ? chalk.bgYellow.black(" MOD ") : chalk.bgRed.white(" HIGH ");
|
|
1055
1060
|
if (i === 0) {
|
|
1056
1061
|
lines.push(chalk.cyan(` \u250C${"\u2500".repeat(boxWidth)}\u2510`));
|
|
1057
1062
|
}
|
|
1058
1063
|
const nameStr = `${icon} ${label}`;
|
|
1059
|
-
const scoreStr = `${layer.driftScore}/100
|
|
1064
|
+
const scoreStr = hasScore ? `${layer.driftScore}/100` : "n/a";
|
|
1060
1065
|
const fileSuffix = `${layer.fileCount} file${layer.fileCount !== 1 ? "s" : ""}`;
|
|
1061
1066
|
const leftContent = ` ${nameStr}`;
|
|
1062
1067
|
const rightContent = `${fileSuffix} ${scoreStr} `;
|
|
@@ -1067,11 +1072,17 @@ function formatArchitectureDiagram(arch) {
|
|
|
1067
1072
|
chalk.cyan(" \u2502") + ` ${icon} ${chalk.bold(label)}` + " ".repeat(padLen) + chalk.dim(fileSuffix) + " " + scoreColor.bold(scoreStr) + " " + chalk.cyan("\u2502")
|
|
1068
1073
|
);
|
|
1069
1074
|
const barWidth = boxWidth - 8;
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
)
|
|
1075
|
+
if (hasScore) {
|
|
1076
|
+
const filled = Math.round(layer.driftScore / 100 * barWidth);
|
|
1077
|
+
const empty = barWidth - filled;
|
|
1078
|
+
lines.push(
|
|
1079
|
+
chalk.cyan(" \u2502") + " " + scoreColor("\u2588".repeat(filled)) + chalk.dim("\u2591".repeat(empty)) + " " + chalk.cyan("\u2502")
|
|
1080
|
+
);
|
|
1081
|
+
} else {
|
|
1082
|
+
lines.push(
|
|
1083
|
+
chalk.cyan(" \u2502") + " " + chalk.dim("\xB7".repeat(barWidth)) + " " + chalk.cyan("\u2502")
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1075
1086
|
if (layer.techStack.length > 0) {
|
|
1076
1087
|
const techNames = layer.techStack.slice(0, 6).map((t) => t.name);
|
|
1077
1088
|
const moreCount = layer.techStack.length > 6 ? ` +${layer.techStack.length - 6}` : "";
|
|
@@ -1620,6 +1631,7 @@ async function npmViewJson(args, cwd) {
|
|
|
1620
1631
|
return new Promise((resolve7, reject) => {
|
|
1621
1632
|
const child = spawn("npm", ["view", ...args, "--json"], {
|
|
1622
1633
|
cwd,
|
|
1634
|
+
shell: true,
|
|
1623
1635
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1624
1636
|
});
|
|
1625
1637
|
let out = "";
|
|
@@ -1656,19 +1668,30 @@ var NpmCache = class {
|
|
|
1656
1668
|
if (existing) return existing;
|
|
1657
1669
|
const p = this.sem.run(async () => {
|
|
1658
1670
|
let latest = null;
|
|
1659
|
-
try {
|
|
1660
|
-
const dist = await npmViewJson([pkg2, "dist-tags"], this.cwd);
|
|
1661
|
-
if (dist && typeof dist === "object" && typeof dist.latest === "string") {
|
|
1662
|
-
latest = dist.latest;
|
|
1663
|
-
}
|
|
1664
|
-
} catch {
|
|
1665
|
-
}
|
|
1666
1671
|
let versions = [];
|
|
1667
1672
|
try {
|
|
1668
|
-
const
|
|
1669
|
-
if (
|
|
1670
|
-
|
|
1673
|
+
const data = await npmViewJson([pkg2, "dist-tags.latest", "versions"], this.cwd);
|
|
1674
|
+
if (data && typeof data === "object") {
|
|
1675
|
+
const dt = data["dist-tags.latest"];
|
|
1676
|
+
if (typeof dt === "string") latest = dt;
|
|
1677
|
+
const v = data.versions;
|
|
1678
|
+
if (Array.isArray(v)) versions = v.map(String);
|
|
1679
|
+
else if (typeof v === "string") versions = [v];
|
|
1680
|
+
}
|
|
1671
1681
|
} catch {
|
|
1682
|
+
try {
|
|
1683
|
+
const dist = await npmViewJson([pkg2, "dist-tags"], this.cwd);
|
|
1684
|
+
if (dist && typeof dist === "object" && typeof dist.latest === "string") {
|
|
1685
|
+
latest = dist.latest;
|
|
1686
|
+
}
|
|
1687
|
+
} catch {
|
|
1688
|
+
}
|
|
1689
|
+
try {
|
|
1690
|
+
const v = await npmViewJson([pkg2, "versions"], this.cwd);
|
|
1691
|
+
if (Array.isArray(v)) versions = v.map(String);
|
|
1692
|
+
else if (typeof v === "string") versions = [v];
|
|
1693
|
+
} catch {
|
|
1694
|
+
}
|
|
1672
1695
|
}
|
|
1673
1696
|
const stable = stableOnly(versions);
|
|
1674
1697
|
const latestStableOverall = maxStable(stable);
|
|
@@ -1679,6 +1702,14 @@ var NpmCache = class {
|
|
|
1679
1702
|
return p;
|
|
1680
1703
|
}
|
|
1681
1704
|
};
|
|
1705
|
+
async function checkRegistryAccess(cwd) {
|
|
1706
|
+
try {
|
|
1707
|
+
const result = await npmViewJson(["npm", "dist-tags.latest"], cwd);
|
|
1708
|
+
return typeof result === "string" && result.length > 0;
|
|
1709
|
+
} catch {
|
|
1710
|
+
return false;
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1682
1713
|
function isSemverSpec(spec) {
|
|
1683
1714
|
const s = spec.trim();
|
|
1684
1715
|
if (!s) return false;
|
|
@@ -5175,7 +5206,7 @@ function classifyFile(filePath, archetype) {
|
|
|
5175
5206
|
}
|
|
5176
5207
|
function computeLayerDrift(packages) {
|
|
5177
5208
|
if (packages.length === 0) {
|
|
5178
|
-
return { score:
|
|
5209
|
+
return { score: null, riskLevel: null };
|
|
5179
5210
|
}
|
|
5180
5211
|
let current = 0;
|
|
5181
5212
|
let oneBehind = 0;
|
|
@@ -5193,7 +5224,7 @@ function computeLayerDrift(packages) {
|
|
|
5193
5224
|
}
|
|
5194
5225
|
}
|
|
5195
5226
|
const known = current + oneBehind + twoPlusBehind;
|
|
5196
|
-
if (known === 0) return { score:
|
|
5227
|
+
if (known === 0) return { score: null, riskLevel: null };
|
|
5197
5228
|
const currentPct = current / known;
|
|
5198
5229
|
const onePct = oneBehind / known;
|
|
5199
5230
|
const twoPct = twoPlusBehind / known;
|
|
@@ -5375,6 +5406,24 @@ async function runScan(rootDir, opts) {
|
|
|
5375
5406
|
];
|
|
5376
5407
|
progress.setSteps(steps);
|
|
5377
5408
|
progress.completeStep("config", "loaded");
|
|
5409
|
+
const registryOk = await checkRegistryAccess(rootDir);
|
|
5410
|
+
if (!registryOk) {
|
|
5411
|
+
progress.finish();
|
|
5412
|
+
const msg = [
|
|
5413
|
+
"",
|
|
5414
|
+
chalk5.red.bold(" \u2716 Vibgrate cannot connect to the npm registry to check package versions."),
|
|
5415
|
+
"",
|
|
5416
|
+
chalk5.dim(" Possible causes:"),
|
|
5417
|
+
chalk5.dim(" \u2022 No internet connection"),
|
|
5418
|
+
chalk5.dim(" \u2022 Corporate proxy/firewall blocking registry.npmjs.org"),
|
|
5419
|
+
chalk5.dim(" \u2022 npm is not installed or not in PATH"),
|
|
5420
|
+
"",
|
|
5421
|
+
chalk5.dim(" Try running: ") + chalk5.cyan("npm view npm dist-tags.latest"),
|
|
5422
|
+
""
|
|
5423
|
+
].join("\n");
|
|
5424
|
+
console.error(msg);
|
|
5425
|
+
process.exit(1);
|
|
5426
|
+
}
|
|
5378
5427
|
progress.startStep("discovery");
|
|
5379
5428
|
const treeCount = await quickTreeCount(rootDir, excludePatterns);
|
|
5380
5429
|
progress.updateStats({ treeSummary: treeCount });
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-GN3IWKSY.js";
|
|
5
5
|
import {
|
|
6
6
|
baselineCommand
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NQOMFDK2.js";
|
|
8
8
|
import {
|
|
9
9
|
VERSION,
|
|
10
10
|
dsnCommand,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
readJsonFile,
|
|
16
16
|
scanCommand,
|
|
17
17
|
writeDefaultConfig
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-6FJ3NIG6.js";
|
|
19
19
|
|
|
20
20
|
// src/cli.ts
|
|
21
21
|
import { Command as Command4 } from "commander";
|
|
@@ -38,7 +38,7 @@ var initCommand = new Command("init").description("Initialize vibgrate in a proj
|
|
|
38
38
|
console.log(chalk.green("\u2714") + ` Created ${chalk.bold("vibgrate.config.ts")}`);
|
|
39
39
|
}
|
|
40
40
|
if (opts.baseline) {
|
|
41
|
-
const { runBaseline } = await import("./baseline-
|
|
41
|
+
const { runBaseline } = await import("./baseline-UOKU2UYD.js");
|
|
42
42
|
await runBaseline(rootDir);
|
|
43
43
|
}
|
|
44
44
|
console.log("");
|
package/dist/index.d.ts
CHANGED
|
@@ -268,10 +268,10 @@ interface LayerSummary {
|
|
|
268
268
|
layer: ArchitectureLayer;
|
|
269
269
|
/** Number of files in this layer */
|
|
270
270
|
fileCount: number;
|
|
271
|
-
/** Drift score for dependencies used in this layer (0–100) */
|
|
272
|
-
driftScore: number;
|
|
273
|
-
/** Risk level derived from drift score */
|
|
274
|
-
riskLevel: RiskLevel;
|
|
271
|
+
/** Drift score for dependencies used in this layer (0–100, null = no data) */
|
|
272
|
+
driftScore: number | null;
|
|
273
|
+
/** Risk level derived from drift score (null when no packages in layer) */
|
|
274
|
+
riskLevel: RiskLevel | null;
|
|
275
275
|
/** Tech stack components detected in this layer */
|
|
276
276
|
techStack: InventoryItem[];
|
|
277
277
|
/** Services/integrations used in this layer */
|
package/dist/index.js
CHANGED