@kb-labs/devkit 1.0.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.
- package/.cursorrules +32 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/actions/setup-node-pnpm/action.yml +47 -0
- package/.github/workflow-templates/ci.yml +13 -0
- package/.github/workflow-templates/drift-check.yml +10 -0
- package/.github/workflow-templates/profiles-validate.yml +16 -0
- package/.github/workflow-templates/release.yml +8 -0
- package/.github/workflows/ci-reusable.yml +131 -0
- package/.github/workflows/drift-check-reusable.yml +23 -0
- package/.github/workflows/fixtures.yml +74 -0
- package/.github/workflows/profiles-validate-reusable.yml +67 -0
- package/.github/workflows/release-reusable.yml +50 -0
- package/.vscode/settings.json +23 -0
- package/AGENTS.md +130 -0
- package/LICENSE +21 -0
- package/README.md +1542 -0
- package/agents/devkit-maintainer/context.globs +15 -0
- package/agents/devkit-maintainer/permissions.yml +17 -0
- package/agents/devkit-maintainer/prompt.md +28 -0
- package/agents/devkit-maintainer/runbook.md +31 -0
- package/agents/docs-crafter/prompt.md +24 -0
- package/agents/docs-crafter/runbook.md +18 -0
- package/agents/release-manager/context.globs +7 -0
- package/agents/release-manager/prompt.md +27 -0
- package/agents/release-manager/runbook.md +17 -0
- package/agents/test-generator/context.globs +7 -0
- package/agents/test-generator/prompt.md +27 -0
- package/agents/test-generator/runbook.md +18 -0
- package/bin/devkit-architecture.mjs +1225 -0
- package/bin/devkit-build-order.mjs +500 -0
- package/bin/devkit-check-build-readiness.mjs +222 -0
- package/bin/devkit-check-commands.mjs +394 -0
- package/bin/devkit-check-configs.mjs +461 -0
- package/bin/devkit-check-deprecated.mjs +532 -0
- package/bin/devkit-check-duplicates.mjs +431 -0
- package/bin/devkit-check-exports.mjs +561 -0
- package/bin/devkit-check-imports.mjs +712 -0
- package/bin/devkit-check-paths.mjs +670 -0
- package/bin/devkit-check-scripts.mjs +335 -0
- package/bin/devkit-check-structure.mjs +495 -0
- package/bin/devkit-check-types.mjs +450 -0
- package/bin/devkit-ci.mjs +261 -0
- package/bin/devkit-core-gate.mjs +225 -0
- package/bin/devkit-fix-deps.mjs +1169 -0
- package/bin/devkit-freshness.mjs +199 -0
- package/bin/devkit-health.mjs +489 -0
- package/bin/devkit-migrate-configs.mjs +370 -0
- package/bin/devkit-paths.mjs +192 -0
- package/bin/devkit-stats.mjs +453 -0
- package/bin/devkit-sync.mjs +12 -0
- package/bin/devkit-tsup-external.mjs +148 -0
- package/bin/devkit-types-audit.mjs +615 -0
- package/bin/devkit-types-order.mjs +637 -0
- package/bin/devkit-validate-naming.mjs +203 -0
- package/bin/devkit-visualize.mjs +452 -0
- package/bin/kb-devkit-qa-history.mjs +453 -0
- package/bin/kb-devkit-qa.mjs +915 -0
- package/eslint/node.js +134 -0
- package/eslint/react.js +260 -0
- package/package.json +186 -0
- package/prettier/index.json +10 -0
- package/sync/index.mjs +693 -0
- package/templates/configs/README.md +306 -0
- package/templates/configs/eslint.config.js +27 -0
- package/templates/configs/package.json.bin +25 -0
- package/templates/configs/package.json.lib +30 -0
- package/templates/configs/tsconfig.build.json +15 -0
- package/templates/configs/tsconfig.json +9 -0
- package/templates/configs/tsup.config.bin.ts +34 -0
- package/templates/configs/tsup.config.cli.ts +41 -0
- package/templates/configs/tsup.config.dual.ts +46 -0
- package/templates/configs/tsup.config.ts +36 -0
- package/templates/package-json/README.md +290 -0
- package/templates/package-json/package.json.bin.template +40 -0
- package/templates/package-json/package.json.template +45 -0
- package/tsconfig/base.json +21 -0
- package/tsconfig/cli.json +12 -0
- package/tsconfig/dist/__tests__/cache.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/cache.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/cache.spec.js +85 -0
- package/tsconfig/dist/__tests__/cache.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.js +153 -0
- package/tsconfig/dist/__tests__/fs-atomic.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.js +99 -0
- package/tsconfig/dist/__tests__/init-workspace.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/kb-error.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/kb-error.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/kb-error.spec.js +190 -0
- package/tsconfig/dist/__tests__/kb-error.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.js +142 -0
- package/tsconfig/dist/__tests__/preset-lockfile.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.js +100 -0
- package/tsconfig/dist/__tests__/product-config-profiles.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/product-config.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/product-config.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/product-config.spec.js +298 -0
- package/tsconfig/dist/__tests__/product-config.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/runtime.spec.d.ts +2 -0
- package/tsconfig/dist/__tests__/runtime.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/runtime.spec.js +127 -0
- package/tsconfig/dist/__tests__/runtime.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.d.ts +6 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.js +251 -0
- package/tsconfig/dist/__tests__/upsert-lockfile.spec.js.map +1 -0
- package/tsconfig/dist/__tests__/validate-config.spec.d.ts +2 -0
- package/tsconfig/dist/__tests__/validate-config.spec.d.ts.map +1 -0
- package/tsconfig/dist/__tests__/validate-config.spec.js +14 -0
- package/tsconfig/dist/__tests__/validate-config.spec.js.map +1 -0
- package/tsconfig/dist/api/init-workspace.d.ts +10 -0
- package/tsconfig/dist/api/init-workspace.d.ts.map +1 -0
- package/tsconfig/dist/api/init-workspace.js +191 -0
- package/tsconfig/dist/api/init-workspace.js.map +1 -0
- package/tsconfig/dist/api/product-config.d.ts +21 -0
- package/tsconfig/dist/api/product-config.d.ts.map +1 -0
- package/tsconfig/dist/api/product-config.js +192 -0
- package/tsconfig/dist/api/product-config.js.map +1 -0
- package/tsconfig/dist/api/read-config.d.ts +22 -0
- package/tsconfig/dist/api/read-config.d.ts.map +1 -0
- package/tsconfig/dist/api/read-config.js +105 -0
- package/tsconfig/dist/api/read-config.js.map +1 -0
- package/tsconfig/dist/api/upsert-lockfile.d.ts +10 -0
- package/tsconfig/dist/api/upsert-lockfile.d.ts.map +1 -0
- package/tsconfig/dist/api/upsert-lockfile.js +63 -0
- package/tsconfig/dist/api/upsert-lockfile.js.map +1 -0
- package/tsconfig/dist/cache/fs-cache.d.ts +38 -0
- package/tsconfig/dist/cache/fs-cache.d.ts.map +1 -0
- package/tsconfig/dist/cache/fs-cache.js +142 -0
- package/tsconfig/dist/cache/fs-cache.js.map +1 -0
- package/tsconfig/dist/errors/kb-error.d.ts +32 -0
- package/tsconfig/dist/errors/kb-error.d.ts.map +1 -0
- package/tsconfig/dist/errors/kb-error.js +54 -0
- package/tsconfig/dist/errors/kb-error.js.map +1 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.d.ts +2 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.d.ts.map +1 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.js +22 -0
- package/tsconfig/dist/fs/__tests__/fs.spec.js.map +1 -0
- package/tsconfig/dist/fs/fs.d.ts +6 -0
- package/tsconfig/dist/fs/fs.d.ts.map +1 -0
- package/tsconfig/dist/fs/fs.js +12 -0
- package/tsconfig/dist/fs/fs.js.map +1 -0
- package/tsconfig/dist/fs/index.d.ts +2 -0
- package/tsconfig/dist/fs/index.d.ts.map +1 -0
- package/tsconfig/dist/fs/index.js +2 -0
- package/tsconfig/dist/fs/index.js.map +1 -0
- package/tsconfig/dist/hash/config-hash.d.ts +17 -0
- package/tsconfig/dist/hash/config-hash.d.ts.map +1 -0
- package/tsconfig/dist/hash/config-hash.js +55 -0
- package/tsconfig/dist/hash/config-hash.js.map +1 -0
- package/tsconfig/dist/index.d.ts +5 -0
- package/tsconfig/dist/index.d.ts.map +1 -0
- package/tsconfig/dist/index.js +5 -0
- package/tsconfig/dist/index.js.map +1 -0
- package/tsconfig/dist/lockfile/lockfile.d.ts +54 -0
- package/tsconfig/dist/lockfile/lockfile.d.ts.map +1 -0
- package/tsconfig/dist/lockfile/lockfile.js +141 -0
- package/tsconfig/dist/lockfile/lockfile.js.map +1 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.d.ts +2 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.d.ts.map +1 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.js +65 -0
- package/tsconfig/dist/logging/__tests__/logger.spec.js.map +1 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.d.ts +2 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.d.ts.map +1 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.js +34 -0
- package/tsconfig/dist/logging/__tests__/redaction.spec.js.map +1 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.d.ts +2 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.d.ts.map +1 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.js +90 -0
- package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.js.map +1 -0
- package/tsconfig/dist/logging/index.d.ts +6 -0
- package/tsconfig/dist/logging/index.d.ts.map +1 -0
- package/tsconfig/dist/logging/index.js +6 -0
- package/tsconfig/dist/logging/index.js.map +1 -0
- package/tsconfig/dist/logging/logger.d.ts +9 -0
- package/tsconfig/dist/logging/logger.d.ts.map +1 -0
- package/tsconfig/dist/logging/logger.js +101 -0
- package/tsconfig/dist/logging/logger.js.map +1 -0
- package/tsconfig/dist/logging/redaction.d.ts +7 -0
- package/tsconfig/dist/logging/redaction.d.ts.map +1 -0
- package/tsconfig/dist/logging/redaction.js +23 -0
- package/tsconfig/dist/logging/redaction.js.map +1 -0
- package/tsconfig/dist/logging/sinks/json.d.ts +4 -0
- package/tsconfig/dist/logging/sinks/json.d.ts.map +1 -0
- package/tsconfig/dist/logging/sinks/json.js +23 -0
- package/tsconfig/dist/logging/sinks/json.js.map +1 -0
- package/tsconfig/dist/logging/sinks/stdout.d.ts +3 -0
- package/tsconfig/dist/logging/sinks/stdout.d.ts.map +1 -0
- package/tsconfig/dist/logging/sinks/stdout.js +24 -0
- package/tsconfig/dist/logging/sinks/stdout.js.map +1 -0
- package/tsconfig/dist/logging/types/index.d.ts +2 -0
- package/tsconfig/dist/logging/types/index.d.ts.map +1 -0
- package/tsconfig/dist/logging/types/index.js +2 -0
- package/tsconfig/dist/logging/types/index.js.map +1 -0
- package/tsconfig/dist/logging/types/types.d.ts +37 -0
- package/tsconfig/dist/logging/types/types.d.ts.map +1 -0
- package/tsconfig/dist/logging/types/types.js +2 -0
- package/tsconfig/dist/logging/types/types.js.map +1 -0
- package/tsconfig/dist/merge/layered-merge.d.ts +16 -0
- package/tsconfig/dist/merge/layered-merge.d.ts.map +1 -0
- package/tsconfig/dist/merge/layered-merge.js +97 -0
- package/tsconfig/dist/merge/layered-merge.js.map +1 -0
- package/tsconfig/dist/preset/resolve-preset.d.ts +29 -0
- package/tsconfig/dist/preset/resolve-preset.d.ts.map +1 -0
- package/tsconfig/dist/preset/resolve-preset.js +104 -0
- package/tsconfig/dist/preset/resolve-preset.js.map +1 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.d.ts +2 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.d.ts.map +1 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.js +25 -0
- package/tsconfig/dist/repo/__tests__/repo.spec.js.map +1 -0
- package/tsconfig/dist/repo/index.d.ts +2 -0
- package/tsconfig/dist/repo/index.d.ts.map +1 -0
- package/tsconfig/dist/repo/index.js +2 -0
- package/tsconfig/dist/repo/index.js.map +1 -0
- package/tsconfig/dist/repo/repo.d.ts +6 -0
- package/tsconfig/dist/repo/repo.d.ts.map +1 -0
- package/tsconfig/dist/repo/repo.js +25 -0
- package/tsconfig/dist/repo/repo.js.map +1 -0
- package/tsconfig/dist/runtime/index.d.ts +2 -0
- package/tsconfig/dist/runtime/index.d.ts.map +1 -0
- package/tsconfig/dist/runtime/index.js +2 -0
- package/tsconfig/dist/runtime/index.js.map +1 -0
- package/tsconfig/dist/runtime/runtime.d.ts +46 -0
- package/tsconfig/dist/runtime/runtime.d.ts.map +1 -0
- package/tsconfig/dist/runtime/runtime.js +126 -0
- package/tsconfig/dist/runtime/runtime.js.map +1 -0
- package/tsconfig/dist/tsconfig.tools.tsbuildinfo +1 -0
- package/tsconfig/dist/tsconfig.tsbuildinfo +1 -0
- package/tsconfig/dist/types/index.d.ts +2 -0
- package/tsconfig/dist/types/index.d.ts.map +1 -0
- package/tsconfig/dist/types/index.js +2 -0
- package/tsconfig/dist/types/index.js.map +1 -0
- package/tsconfig/dist/types/init.d.ts +34 -0
- package/tsconfig/dist/types/init.d.ts.map +1 -0
- package/tsconfig/dist/types/init.js +6 -0
- package/tsconfig/dist/types/init.js.map +1 -0
- package/tsconfig/dist/types/preset.d.ts +27 -0
- package/tsconfig/dist/types/preset.d.ts.map +1 -0
- package/tsconfig/dist/types/preset.js +6 -0
- package/tsconfig/dist/types/preset.js.map +1 -0
- package/tsconfig/dist/types/types.d.ts +6 -0
- package/tsconfig/dist/types/types.d.ts.map +1 -0
- package/tsconfig/dist/types/types.js +2 -0
- package/tsconfig/dist/types/types.js.map +1 -0
- package/tsconfig/dist/utils/__tests__/env.spec.d.ts +2 -0
- package/tsconfig/dist/utils/__tests__/env.spec.d.ts.map +1 -0
- package/tsconfig/dist/utils/__tests__/env.spec.js +33 -0
- package/tsconfig/dist/utils/__tests__/env.spec.js.map +1 -0
- package/tsconfig/dist/utils/env.d.ts +7 -0
- package/tsconfig/dist/utils/env.d.ts.map +1 -0
- package/tsconfig/dist/utils/env.js +25 -0
- package/tsconfig/dist/utils/env.js.map +1 -0
- package/tsconfig/dist/utils/fs-atomic.d.ts +15 -0
- package/tsconfig/dist/utils/fs-atomic.d.ts.map +1 -0
- package/tsconfig/dist/utils/fs-atomic.js +45 -0
- package/tsconfig/dist/utils/fs-atomic.js.map +1 -0
- package/tsconfig/dist/utils/index.d.ts +3 -0
- package/tsconfig/dist/utils/index.d.ts.map +1 -0
- package/tsconfig/dist/utils/index.js +3 -0
- package/tsconfig/dist/utils/index.js.map +1 -0
- package/tsconfig/dist/utils/paths.d.ts +21 -0
- package/tsconfig/dist/utils/paths.d.ts.map +1 -0
- package/tsconfig/dist/utils/paths.js +32 -0
- package/tsconfig/dist/utils/paths.js.map +1 -0
- package/tsconfig/dist/utils/product-normalize.d.ts +27 -0
- package/tsconfig/dist/utils/product-normalize.d.ts.map +1 -0
- package/tsconfig/dist/utils/product-normalize.js +45 -0
- package/tsconfig/dist/utils/product-normalize.js.map +1 -0
- package/tsconfig/dist/validation/validate-config.d.ts +7 -0
- package/tsconfig/dist/validation/validate-config.d.ts.map +1 -0
- package/tsconfig/dist/validation/validate-config.js +22 -0
- package/tsconfig/dist/validation/validate-config.js.map +1 -0
- package/tsconfig/lib.json +13 -0
- package/tsconfig/node.json +12 -0
- package/tsconfig/react-app.json +8 -0
- package/tsconfig/react-lib.json +8 -0
- package/tsconfig/test.json +15 -0
- package/tsup/bin.js +172 -0
- package/tsup/dual.js +155 -0
- package/tsup/external-sync.mjs +41 -0
- package/tsup/external.mjs +109 -0
- package/tsup/node.js +65 -0
- package/tsup/react-lib.js +18 -0
- package/tsup/sdk.js +118 -0
- package/vite/react-app.js +50 -0
- package/vitest/node.js +37 -0
- package/vitest/react.js +39 -0
- package/vitest/vitest-setup.ts +9 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @kb-labs/devkit - Duplicate Checker
|
|
5
|
+
*
|
|
6
|
+
* Checks for:
|
|
7
|
+
* 1. Duplicate dependencies (same package, different versions)
|
|
8
|
+
* 2. Version mismatches across packages
|
|
9
|
+
* 3. Duplicate code patterns (similar file names/content)
|
|
10
|
+
* 4. Redundant similar packages
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* kb-devkit-check-duplicates # Check all packages
|
|
14
|
+
* kb-devkit-check-duplicates --package cli-core # Check specific package
|
|
15
|
+
* kb-devkit-check-duplicates --code # Include code duplication check
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
|
|
22
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
|
|
24
|
+
// ANSI colors
|
|
25
|
+
const colors = {
|
|
26
|
+
reset: '\x1b[0m',
|
|
27
|
+
red: '\x1b[31m',
|
|
28
|
+
green: '\x1b[32m',
|
|
29
|
+
yellow: '\x1b[33m',
|
|
30
|
+
blue: '\x1b[34m',
|
|
31
|
+
magenta: '\x1b[35m',
|
|
32
|
+
cyan: '\x1b[36m',
|
|
33
|
+
gray: '\x1b[90m',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function log(message, color = 'reset') {
|
|
37
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Parse CLI arguments
|
|
41
|
+
const args = process.argv.slice(2);
|
|
42
|
+
const options = {
|
|
43
|
+
package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
|
|
44
|
+
code: args.includes('--code'),
|
|
45
|
+
verbose: args.includes('--verbose') || args.includes('-v'),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Find all packages in monorepo
|
|
50
|
+
*/
|
|
51
|
+
function findPackages(rootDir, filterPackage) {
|
|
52
|
+
const packages = [];
|
|
53
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
54
|
+
|
|
55
|
+
for (const entry of entries) {
|
|
56
|
+
if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
|
|
57
|
+
|
|
58
|
+
const repoPath = path.join(rootDir, entry.name);
|
|
59
|
+
const packagesDir = path.join(repoPath, 'packages');
|
|
60
|
+
|
|
61
|
+
if (!fs.existsSync(packagesDir)) {continue;}
|
|
62
|
+
|
|
63
|
+
const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
|
|
64
|
+
|
|
65
|
+
for (const pkgDir of packageDirs) {
|
|
66
|
+
if (!pkgDir.isDirectory()) {continue;}
|
|
67
|
+
|
|
68
|
+
// Filter by package name if specified
|
|
69
|
+
if (filterPackage && pkgDir.name !== filterPackage) {continue;}
|
|
70
|
+
|
|
71
|
+
const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
|
|
72
|
+
|
|
73
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
74
|
+
packages.push(packageJsonPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return packages;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Collect all dependencies from all packages
|
|
84
|
+
*/
|
|
85
|
+
function collectDependencies(packages) {
|
|
86
|
+
const dependencyMap = new Map(); // dep -> [{package, version}]
|
|
87
|
+
|
|
88
|
+
for (const packagePath of packages) {
|
|
89
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
|
|
90
|
+
const packageName = packageJson.name;
|
|
91
|
+
|
|
92
|
+
if (!packageName || !packageName.startsWith('@kb-labs/')) {continue;}
|
|
93
|
+
|
|
94
|
+
const allDeps = {
|
|
95
|
+
...packageJson.dependencies,
|
|
96
|
+
...packageJson.devDependencies,
|
|
97
|
+
...packageJson.peerDependencies,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
for (const [dep, version] of Object.entries(allDeps)) {
|
|
101
|
+
// Skip workspace packages and local links
|
|
102
|
+
if (version.startsWith('workspace:') || version.startsWith('link:')) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!dependencyMap.has(dep)) {
|
|
107
|
+
dependencyMap.set(dep, []);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
dependencyMap.get(dep).push({
|
|
111
|
+
package: packageName,
|
|
112
|
+
version,
|
|
113
|
+
path: packagePath,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return dependencyMap;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Find duplicate versions of dependencies
|
|
123
|
+
*/
|
|
124
|
+
function findDuplicateVersions(dependencyMap) {
|
|
125
|
+
const duplicates = [];
|
|
126
|
+
|
|
127
|
+
for (const [dep, usages] of dependencyMap.entries()) {
|
|
128
|
+
// Get unique versions
|
|
129
|
+
const versions = new Set(usages.map((u) => u.version));
|
|
130
|
+
|
|
131
|
+
if (versions.size > 1) {
|
|
132
|
+
// Group by version
|
|
133
|
+
const byVersion = new Map();
|
|
134
|
+
for (const usage of usages) {
|
|
135
|
+
if (!byVersion.has(usage.version)) {
|
|
136
|
+
byVersion.set(usage.version, []);
|
|
137
|
+
}
|
|
138
|
+
byVersion.get(usage.version).push(usage.package);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
duplicates.push({
|
|
142
|
+
dependency: dep,
|
|
143
|
+
versions: Array.from(byVersion.entries()).map(([version, packages]) => ({
|
|
144
|
+
version,
|
|
145
|
+
packages,
|
|
146
|
+
count: packages.length,
|
|
147
|
+
})),
|
|
148
|
+
totalPackages: usages.length,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Sort by number of packages affected (most impactful first)
|
|
154
|
+
duplicates.sort((a, b) => b.totalPackages - a.totalPackages);
|
|
155
|
+
|
|
156
|
+
return duplicates;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Find outdated common dependencies
|
|
161
|
+
*/
|
|
162
|
+
function findOutdatedCommon(dependencyMap) {
|
|
163
|
+
const outdated = [];
|
|
164
|
+
|
|
165
|
+
for (const [dep, usages] of dependencyMap.entries()) {
|
|
166
|
+
if (usages.length < 3) {continue;} // Only check widely-used deps
|
|
167
|
+
|
|
168
|
+
const versions = usages.map((u) => u.version);
|
|
169
|
+
const uniqueVersions = new Set(versions);
|
|
170
|
+
|
|
171
|
+
if (uniqueVersions.size === 1) {continue;} // All same version
|
|
172
|
+
|
|
173
|
+
// Try to determine which version is newest (simple semver comparison)
|
|
174
|
+
const sortedVersions = Array.from(uniqueVersions).sort((a, b) => {
|
|
175
|
+
// Remove ^ and ~ prefixes for comparison
|
|
176
|
+
const cleanA = a.replace(/^[\^~]/, '');
|
|
177
|
+
const cleanB = b.replace(/^[\^~]/, '');
|
|
178
|
+
|
|
179
|
+
return cleanB.localeCompare(cleanA, undefined, { numeric: true });
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const newestVersion = sortedVersions[0];
|
|
183
|
+
const outdatedUsages = usages.filter((u) => u.version !== newestVersion);
|
|
184
|
+
|
|
185
|
+
if (outdatedUsages.length > 0) {
|
|
186
|
+
outdated.push({
|
|
187
|
+
dependency: dep,
|
|
188
|
+
newestVersion,
|
|
189
|
+
outdatedUsages: outdatedUsages.map((u) => ({
|
|
190
|
+
package: u.package,
|
|
191
|
+
version: u.version,
|
|
192
|
+
})),
|
|
193
|
+
totalAffected: outdatedUsages.length,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Sort by impact
|
|
199
|
+
outdated.sort((a, b) => b.totalAffected - a.totalAffected);
|
|
200
|
+
|
|
201
|
+
return outdated;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Find similar file names across packages (potential code duplication)
|
|
206
|
+
*/
|
|
207
|
+
function findSimilarFiles(packages) {
|
|
208
|
+
const fileMap = new Map(); // filename -> [{package, path}]
|
|
209
|
+
|
|
210
|
+
for (const packagePath of packages) {
|
|
211
|
+
const packageDir = path.dirname(packagePath);
|
|
212
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
|
|
213
|
+
const packageName = packageJson.name;
|
|
214
|
+
|
|
215
|
+
if (!packageName || !packageName.startsWith('@kb-labs/')) {continue;}
|
|
216
|
+
|
|
217
|
+
const srcDir = path.join(packageDir, 'src');
|
|
218
|
+
if (!fs.existsSync(srcDir)) {continue;}
|
|
219
|
+
|
|
220
|
+
function walk(dir) {
|
|
221
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
222
|
+
|
|
223
|
+
for (const entry of entries) {
|
|
224
|
+
const fullPath = path.join(dir, entry.name);
|
|
225
|
+
|
|
226
|
+
if (entry.isDirectory()) {
|
|
227
|
+
walk(fullPath);
|
|
228
|
+
} else if (entry.isFile() && /\.(ts|tsx|js|jsx)$/.test(entry.name)) {
|
|
229
|
+
// Skip test files and common names
|
|
230
|
+
if (
|
|
231
|
+
entry.name.includes('.test.') ||
|
|
232
|
+
entry.name.includes('.spec.') ||
|
|
233
|
+
entry.name === 'index.ts' ||
|
|
234
|
+
entry.name === 'index.tsx' ||
|
|
235
|
+
entry.name === 'index.js'
|
|
236
|
+
) {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!fileMap.has(entry.name)) {
|
|
241
|
+
fileMap.set(entry.name, []);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
fileMap.get(entry.name).push({
|
|
245
|
+
package: packageName,
|
|
246
|
+
path: path.relative(packageDir, fullPath),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
walk(srcDir);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Find files that appear in multiple packages
|
|
256
|
+
const duplicates = [];
|
|
257
|
+
|
|
258
|
+
for (const [filename, locations] of fileMap.entries()) {
|
|
259
|
+
if (locations.length > 1) {
|
|
260
|
+
duplicates.push({
|
|
261
|
+
filename,
|
|
262
|
+
locations,
|
|
263
|
+
count: locations.length,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Sort by frequency
|
|
269
|
+
duplicates.sort((a, b) => b.count - a.count);
|
|
270
|
+
|
|
271
|
+
return duplicates;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Main function
|
|
276
|
+
*/
|
|
277
|
+
function main() {
|
|
278
|
+
const rootDir = process.cwd();
|
|
279
|
+
|
|
280
|
+
log('\nš KB Labs Duplicate Checker\n', 'blue');
|
|
281
|
+
|
|
282
|
+
if (options.package) {
|
|
283
|
+
log(`Checking package: ${options.package}\n`, 'gray');
|
|
284
|
+
} else {
|
|
285
|
+
log('Checking all packages...\n', 'gray');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (options.code) {
|
|
289
|
+
log('š Code duplication check enabled\n', 'cyan');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const packages = findPackages(rootDir, options.package);
|
|
293
|
+
|
|
294
|
+
if (packages.length === 0) {
|
|
295
|
+
log('ā ļø No KB Labs packages found', 'yellow');
|
|
296
|
+
log(' Run this command from the monorepo root\n', 'gray');
|
|
297
|
+
process.exit(0);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
log(`Found ${packages.length} package(s) to check\n`, 'gray');
|
|
301
|
+
|
|
302
|
+
// Collect dependencies
|
|
303
|
+
const dependencyMap = collectDependencies(packages);
|
|
304
|
+
log(`Analyzing ${dependencyMap.size} unique dependencies...\n`, 'gray');
|
|
305
|
+
|
|
306
|
+
// Find duplicate versions
|
|
307
|
+
const duplicates = findDuplicateVersions(dependencyMap);
|
|
308
|
+
|
|
309
|
+
// Find outdated common deps
|
|
310
|
+
const outdated = findOutdatedCommon(dependencyMap);
|
|
311
|
+
|
|
312
|
+
// Find similar files (if enabled)
|
|
313
|
+
let similarFiles = [];
|
|
314
|
+
if (options.code) {
|
|
315
|
+
log('Scanning for code duplication patterns...\n', 'gray');
|
|
316
|
+
similarFiles = findSimilarFiles(packages);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Print results
|
|
320
|
+
let hasIssues = false;
|
|
321
|
+
|
|
322
|
+
// Print duplicate versions
|
|
323
|
+
if (duplicates.length > 0) {
|
|
324
|
+
hasIssues = true;
|
|
325
|
+
log('š“ Duplicate Dependencies (Different Versions):\n', 'red');
|
|
326
|
+
|
|
327
|
+
for (let i = 0; i < duplicates.length; i++) {
|
|
328
|
+
const dup = duplicates[i];
|
|
329
|
+
log(`${i + 1}. ${dup.dependency}`, 'yellow');
|
|
330
|
+
log(` Used by ${dup.totalPackages} package(s) with ${dup.versions.length} different versions:`, 'gray');
|
|
331
|
+
|
|
332
|
+
for (const ver of dup.versions) {
|
|
333
|
+
log(` ⢠${ver.version} (${ver.count} package(s))`, 'cyan');
|
|
334
|
+
if (options.verbose) {
|
|
335
|
+
for (const pkg of ver.packages.slice(0, 3)) {
|
|
336
|
+
log(` - ${pkg}`, 'gray');
|
|
337
|
+
}
|
|
338
|
+
if (ver.packages.length > 3) {
|
|
339
|
+
log(` ... and ${ver.packages.length - 3} more`, 'gray');
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
log('', 'gray');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
log(' š” Different versions can lead to:' , 'blue');
|
|
348
|
+
log(' - Larger bundle sizes (multiple copies bundled)', 'gray');
|
|
349
|
+
log(' - Type conflicts and build errors', 'gray');
|
|
350
|
+
log(' - Runtime bugs from version incompatibilities', 'gray');
|
|
351
|
+
log(' š” Run: pnpm dedupe or align versions manually\n', 'blue');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Print outdated common dependencies
|
|
355
|
+
if (outdated.length > 0 && options.verbose) {
|
|
356
|
+
hasIssues = true;
|
|
357
|
+
log('š” Outdated Common Dependencies:\n', 'yellow');
|
|
358
|
+
|
|
359
|
+
for (let i = 0; i < Math.min(outdated.length, 10); i++) {
|
|
360
|
+
const dep = outdated[i];
|
|
361
|
+
log(`${i + 1}. ${dep.dependency}`, 'yellow');
|
|
362
|
+
log(` Latest: ${dep.newestVersion}`, 'green');
|
|
363
|
+
log(` ${dep.totalAffected} package(s) using older versions:`, 'gray');
|
|
364
|
+
|
|
365
|
+
for (const usage of dep.outdatedUsages.slice(0, 3)) {
|
|
366
|
+
log(` ⢠${usage.package}: ${usage.version}`, 'gray');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
if (dep.outdatedUsages.length > 3) {
|
|
370
|
+
log(` ... and ${dep.outdatedUsages.length - 3} more`, 'gray');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
log('', 'gray');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
log(' š” Consider upgrading to the latest version for consistency\n', 'blue');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Print similar files (code duplication)
|
|
380
|
+
if (similarFiles.length > 0) {
|
|
381
|
+
hasIssues = true;
|
|
382
|
+
log('š Potential Code Duplication (Similar File Names):\n', 'yellow');
|
|
383
|
+
|
|
384
|
+
for (let i = 0; i < Math.min(similarFiles.length, 15); i++) {
|
|
385
|
+
const file = similarFiles[i];
|
|
386
|
+
log(`${i + 1}. ${file.filename}`, 'yellow');
|
|
387
|
+
log(` Found in ${file.count} package(s):`, 'gray');
|
|
388
|
+
|
|
389
|
+
for (const loc of file.locations) {
|
|
390
|
+
log(` ⢠${loc.package}`, 'cyan');
|
|
391
|
+
log(` ${loc.path}`, 'gray');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
log('', 'gray');
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
log(' ā ļø This may indicate duplicated code that could be shared', 'yellow');
|
|
398
|
+
log(' š” Consider extracting common code to a shared package\n', 'blue');
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Summary
|
|
402
|
+
log('ā'.repeat(60) + '\n', 'gray');
|
|
403
|
+
|
|
404
|
+
if (!hasIssues) {
|
|
405
|
+
log('ā
No duplicate dependencies found!\n', 'green');
|
|
406
|
+
process.exit(0);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
log('š Summary:\n', 'blue');
|
|
410
|
+
|
|
411
|
+
if (duplicates.length > 0) {
|
|
412
|
+
log(` š“ ${duplicates.length} dependencies with version conflicts`, 'red');
|
|
413
|
+
}
|
|
414
|
+
if (outdated.length > 0 && options.verbose) {
|
|
415
|
+
log(` š” ${outdated.length} common dependencies with outdated versions`, 'yellow');
|
|
416
|
+
}
|
|
417
|
+
if (similarFiles.length > 0) {
|
|
418
|
+
log(` š ${similarFiles.length} potential code duplication patterns`, 'yellow');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
log('\nš” Tips:', 'blue');
|
|
422
|
+
log(' ⢠Use --verbose to see full package lists and outdated deps', 'gray');
|
|
423
|
+
log(' ⢠Use --code to check for code duplication patterns', 'gray');
|
|
424
|
+
log(' ⢠Run: pnpm dedupe to resolve version conflicts', 'gray');
|
|
425
|
+
log(' ⢠Consider using pnpm overrides for enforcing versions', 'gray');
|
|
426
|
+
log('');
|
|
427
|
+
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
main();
|