@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,500 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @kb-labs/devkit - Build Order Calculator
|
|
5
|
+
*
|
|
6
|
+
* Calculates the correct build order for all packages based on dependencies.
|
|
7
|
+
* Uses topological sort to determine which packages need to be built first.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* kb-devkit-build-order # Show build order
|
|
11
|
+
* kb-devkit-build-order --layers # Show parallel build layers
|
|
12
|
+
* kb-devkit-build-order --package=cli # Build order for specific package
|
|
13
|
+
* kb-devkit-build-order --json # Output JSON
|
|
14
|
+
* kb-devkit-build-order --script # Generate build script
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
|
|
21
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
|
|
23
|
+
// ANSI colors
|
|
24
|
+
const colors = {
|
|
25
|
+
reset: '\x1b[0m',
|
|
26
|
+
red: '\x1b[31m',
|
|
27
|
+
green: '\x1b[32m',
|
|
28
|
+
yellow: '\x1b[33m',
|
|
29
|
+
blue: '\x1b[34m',
|
|
30
|
+
magenta: '\x1b[35m',
|
|
31
|
+
cyan: '\x1b[36m',
|
|
32
|
+
gray: '\x1b[90m',
|
|
33
|
+
bold: '\x1b[1m',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function log(message, color = 'reset') {
|
|
37
|
+
if (!options.json) {
|
|
38
|
+
console.log(`${colors[color]}${message}${colors.reset}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Parse CLI arguments
|
|
43
|
+
const args = process.argv.slice(2);
|
|
44
|
+
const options = {
|
|
45
|
+
layers: args.includes('--layers'),
|
|
46
|
+
json: args.includes('--json'),
|
|
47
|
+
script: args.includes('--script'),
|
|
48
|
+
verbose: args.includes('--verbose') || args.includes('-v'),
|
|
49
|
+
package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find all packages
|
|
54
|
+
*/
|
|
55
|
+
function findPackages(rootDir) {
|
|
56
|
+
const packages = [];
|
|
57
|
+
const entries = fs.readdirSync(rootDir, { withFileTypes: true });
|
|
58
|
+
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
|
|
61
|
+
|
|
62
|
+
const repoPath = path.join(rootDir, entry.name);
|
|
63
|
+
const packagesDir = path.join(repoPath, 'packages');
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(packagesDir)) {continue;}
|
|
66
|
+
|
|
67
|
+
const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
|
|
68
|
+
|
|
69
|
+
for (const pkgDir of packageDirs) {
|
|
70
|
+
if (!pkgDir.isDirectory()) {continue;}
|
|
71
|
+
|
|
72
|
+
const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
|
|
73
|
+
|
|
74
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
75
|
+
packages.push(packageJsonPath);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return packages;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Build dependency graph
|
|
85
|
+
*/
|
|
86
|
+
function buildDependencyGraph(packages) {
|
|
87
|
+
const graph = new Map(); // packageName -> { deps: Set, path: string }
|
|
88
|
+
const nameToPath = new Map();
|
|
89
|
+
|
|
90
|
+
// First pass: collect all package names
|
|
91
|
+
for (const packagePath of packages) {
|
|
92
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
|
|
93
|
+
const packageName = packageJson.name;
|
|
94
|
+
|
|
95
|
+
if (!packageName || !packageName.startsWith('@kb-labs/')) {continue;}
|
|
96
|
+
|
|
97
|
+
graph.set(packageName, {
|
|
98
|
+
deps: new Set(),
|
|
99
|
+
path: packagePath,
|
|
100
|
+
dir: path.dirname(packagePath),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
nameToPath.set(packageName, packagePath);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Second pass: build dependency edges
|
|
107
|
+
for (const packagePath of packages) {
|
|
108
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
|
|
109
|
+
const packageName = packageJson.name;
|
|
110
|
+
|
|
111
|
+
if (!packageName || !packageName.startsWith('@kb-labs/')) {continue;}
|
|
112
|
+
|
|
113
|
+
const allDeps = {
|
|
114
|
+
...packageJson.dependencies,
|
|
115
|
+
...packageJson.devDependencies,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
for (const [dep, version] of Object.entries(allDeps)) {
|
|
119
|
+
// Skip external dependencies
|
|
120
|
+
if (!dep.startsWith('@kb-labs/')) {continue;}
|
|
121
|
+
|
|
122
|
+
// Track ALL workspace dependencies regardless of protocol
|
|
123
|
+
// Supports: workspace:*, workspace:^1.0.0, link:../path, *
|
|
124
|
+
const isWorkspaceDep =
|
|
125
|
+
version.startsWith('workspace:') ||
|
|
126
|
+
version.startsWith('link:') ||
|
|
127
|
+
version === '*';
|
|
128
|
+
|
|
129
|
+
if (isWorkspaceDep && graph.has(dep)) {
|
|
130
|
+
graph.get(packageName).deps.add(dep);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return graph;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Topological sort using Kahn's algorithm
|
|
140
|
+
* Returns layers of packages that can be built in parallel
|
|
141
|
+
*/
|
|
142
|
+
function topologicalSort(graph) {
|
|
143
|
+
// Calculate in-degree (number of dependencies) for each package
|
|
144
|
+
const inDegree = new Map();
|
|
145
|
+
const reverseDeps = new Map(); // who depends on me
|
|
146
|
+
|
|
147
|
+
for (const [pkg, { deps }] of graph.entries()) {
|
|
148
|
+
if (!inDegree.has(pkg)) {
|
|
149
|
+
inDegree.set(pkg, 0);
|
|
150
|
+
}
|
|
151
|
+
if (!reverseDeps.has(pkg)) {
|
|
152
|
+
reverseDeps.set(pkg, new Set());
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const dep of deps) {
|
|
156
|
+
inDegree.set(pkg, (inDegree.get(pkg) || 0) + 1);
|
|
157
|
+
|
|
158
|
+
if (!reverseDeps.has(dep)) {
|
|
159
|
+
reverseDeps.set(dep, new Set());
|
|
160
|
+
}
|
|
161
|
+
reverseDeps.get(dep).add(pkg);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Find packages with no dependencies (can be built first)
|
|
166
|
+
const queue = [];
|
|
167
|
+
for (const [pkg, degree] of inDegree.entries()) {
|
|
168
|
+
if (degree === 0) {
|
|
169
|
+
queue.push(pkg);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const layers = [];
|
|
174
|
+
const sorted = [];
|
|
175
|
+
|
|
176
|
+
while (queue.length > 0) {
|
|
177
|
+
// All packages in queue can be built in parallel (same layer)
|
|
178
|
+
const layer = [...queue];
|
|
179
|
+
layers.push(layer);
|
|
180
|
+
sorted.push(...layer);
|
|
181
|
+
|
|
182
|
+
queue.length = 0;
|
|
183
|
+
|
|
184
|
+
// Process all packages in current layer
|
|
185
|
+
for (const pkg of layer) {
|
|
186
|
+
// For each package that depends on this one
|
|
187
|
+
for (const dependent of reverseDeps.get(pkg) || []) {
|
|
188
|
+
inDegree.set(dependent, inDegree.get(dependent) - 1);
|
|
189
|
+
|
|
190
|
+
// If all dependencies are satisfied, add to queue
|
|
191
|
+
if (inDegree.get(dependent) === 0) {
|
|
192
|
+
queue.push(dependent);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check for circular dependencies
|
|
199
|
+
if (sorted.length !== graph.size) {
|
|
200
|
+
const missing = Array.from(graph.keys()).filter((pkg) => !sorted.includes(pkg));
|
|
201
|
+
return { layers, sorted, circular: missing };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return { layers, sorted, circular: [] };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Find circular dependency cycles using DFS
|
|
209
|
+
*/
|
|
210
|
+
function findCircularDependencies(graph, circularPackages) {
|
|
211
|
+
const cycles = [];
|
|
212
|
+
const visited = new Set();
|
|
213
|
+
const recursionStack = new Set();
|
|
214
|
+
const path = [];
|
|
215
|
+
|
|
216
|
+
function dfs(pkg) {
|
|
217
|
+
if (recursionStack.has(pkg)) {
|
|
218
|
+
// Found a cycle - extract it from path
|
|
219
|
+
const cycleStart = path.indexOf(pkg);
|
|
220
|
+
const cycle = [...path.slice(cycleStart), pkg];
|
|
221
|
+
|
|
222
|
+
// Check if this cycle is new (not a rotation of existing cycle)
|
|
223
|
+
const cycleKey = cycle.slice(0, -1).sort().join('ā');
|
|
224
|
+
if (!cycles.some(c => c.key === cycleKey)) {
|
|
225
|
+
cycles.push({ cycle, key: cycleKey });
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (visited.has(pkg)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
visited.add(pkg);
|
|
235
|
+
recursionStack.add(pkg);
|
|
236
|
+
path.push(pkg);
|
|
237
|
+
|
|
238
|
+
const node = graph.get(pkg);
|
|
239
|
+
if (node) {
|
|
240
|
+
for (const dep of node.deps) {
|
|
241
|
+
// Only follow dependencies that are in circular packages
|
|
242
|
+
if (circularPackages.includes(dep)) {
|
|
243
|
+
dfs(dep);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
path.pop();
|
|
249
|
+
recursionStack.delete(pkg);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Start DFS from each circular package
|
|
253
|
+
for (const pkg of circularPackages) {
|
|
254
|
+
if (!visited.has(pkg)) {
|
|
255
|
+
dfs(pkg);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return cycles;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Get build order for specific package and its dependencies
|
|
264
|
+
*/
|
|
265
|
+
function getBuildOrderForPackage(graph, packageName) {
|
|
266
|
+
const visited = new Set();
|
|
267
|
+
const order = [];
|
|
268
|
+
|
|
269
|
+
function visit(pkg) {
|
|
270
|
+
if (visited.has(pkg)) {return;}
|
|
271
|
+
visited.add(pkg);
|
|
272
|
+
|
|
273
|
+
const node = graph.get(pkg);
|
|
274
|
+
if (!node) {return;}
|
|
275
|
+
|
|
276
|
+
// Visit dependencies first
|
|
277
|
+
for (const dep of node.deps) {
|
|
278
|
+
visit(dep);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
order.push(pkg);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
visit(packageName);
|
|
285
|
+
return order;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Print build order
|
|
290
|
+
*/
|
|
291
|
+
function printBuildOrder(result, graph) {
|
|
292
|
+
log('\nšØ KB Labs Build Order\n', 'bold');
|
|
293
|
+
|
|
294
|
+
if (result.circular.length > 0) {
|
|
295
|
+
log('ā Circular dependencies detected!\n', 'red');
|
|
296
|
+
|
|
297
|
+
// Find actual cycles
|
|
298
|
+
const cycles = findCircularDependencies(graph, result.circular);
|
|
299
|
+
|
|
300
|
+
if (cycles.length > 0) {
|
|
301
|
+
log(`Found ${cycles.length} circular dependency cycle(s):\n`, 'yellow');
|
|
302
|
+
|
|
303
|
+
for (let i = 0; i < cycles.length; i++) {
|
|
304
|
+
const { cycle } = cycles[i];
|
|
305
|
+
log(`${i + 1}. ${cycle.join(' ā ')}`, 'red');
|
|
306
|
+
log('', 'reset');
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
log('The following packages are involved in circular dependencies:', 'yellow');
|
|
310
|
+
for (const pkg of result.circular) {
|
|
311
|
+
log(` ${pkg}`, 'red');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
log('\nCannot determine build order. Fix circular dependencies first.', 'gray');
|
|
316
|
+
log('š” To fix: Break the cycle by extracting shared code into a separate package\n', 'cyan');
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
log(`Found ${result.sorted.length} packages\n`, 'gray');
|
|
321
|
+
|
|
322
|
+
if (options.layers) {
|
|
323
|
+
// Show parallel build layers
|
|
324
|
+
log('š¦ Build Layers (packages in same layer can build in parallel):\n', 'blue');
|
|
325
|
+
|
|
326
|
+
for (let i = 0; i < result.layers.length; i++) {
|
|
327
|
+
const layer = result.layers[i];
|
|
328
|
+
log(`Layer ${i + 1} (${layer.length} packages):`, 'cyan');
|
|
329
|
+
|
|
330
|
+
for (const pkg of layer) {
|
|
331
|
+
const deps = graph.get(pkg).deps;
|
|
332
|
+
log(` ${pkg}`, 'gray');
|
|
333
|
+
if (options.verbose && deps.size > 0) {
|
|
334
|
+
log(` depends on: ${Array.from(deps).join(', ')}`, 'gray');
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
log('', 'reset');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
log(`Total layers: ${result.layers.length}`, 'blue');
|
|
341
|
+
log(`Max parallelism: ${Math.max(...result.layers.map((l) => l.length))} packages\n`, 'blue');
|
|
342
|
+
} else {
|
|
343
|
+
// Show sequential build order
|
|
344
|
+
log('š¦ Build Order (sequential):\n', 'blue');
|
|
345
|
+
|
|
346
|
+
for (let i = 0; i < result.sorted.length; i++) {
|
|
347
|
+
const pkg = result.sorted[i];
|
|
348
|
+
const deps = graph.get(pkg).deps;
|
|
349
|
+
|
|
350
|
+
log(`${(i + 1).toString().padStart(3)}. ${pkg}`, 'cyan');
|
|
351
|
+
|
|
352
|
+
if (options.verbose && deps.size > 0) {
|
|
353
|
+
log(` depends on: ${Array.from(deps).join(', ')}`, 'gray');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
log('', 'reset');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Tips
|
|
360
|
+
log('š” Tips:', 'blue');
|
|
361
|
+
log(' ⢠Use --layers to see parallel build opportunities', 'gray');
|
|
362
|
+
log(' ⢠Use --package=name to see build order for specific package', 'gray');
|
|
363
|
+
log(' ⢠Use --script to generate a build script', 'gray');
|
|
364
|
+
log(' ⢠Use pnpm --filter to build specific packages', 'gray');
|
|
365
|
+
log('', 'reset');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Generate build script
|
|
370
|
+
*/
|
|
371
|
+
function generateBuildScript(result, graph) {
|
|
372
|
+
const lines = [
|
|
373
|
+
'#!/bin/bash',
|
|
374
|
+
'',
|
|
375
|
+
'# Auto-generated build script',
|
|
376
|
+
'# Generated by kb-devkit-build-order',
|
|
377
|
+
'',
|
|
378
|
+
'set -e # Exit on error',
|
|
379
|
+
'',
|
|
380
|
+
];
|
|
381
|
+
|
|
382
|
+
if (options.layers) {
|
|
383
|
+
// Parallel build script
|
|
384
|
+
lines.push('# Build in layers (parallel within each layer)');
|
|
385
|
+
lines.push('');
|
|
386
|
+
|
|
387
|
+
for (let i = 0; i < result.layers.length; i++) {
|
|
388
|
+
const layer = result.layers[i];
|
|
389
|
+
lines.push(`echo "Building layer ${i + 1}/${result.layers.length} (${layer.length} packages)..."`);
|
|
390
|
+
|
|
391
|
+
if (layer.length === 1) {
|
|
392
|
+
// Single package, build sequentially
|
|
393
|
+
const pkg = layer[0];
|
|
394
|
+
lines.push(`pnpm --filter ${pkg} run build`);
|
|
395
|
+
} else {
|
|
396
|
+
// Multiple packages, build in parallel
|
|
397
|
+
const filters = layer.map((pkg) => `--filter ${pkg}`).join(' ');
|
|
398
|
+
lines.push(`pnpm ${filters} run build --parallel`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
lines.push('');
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
lines.push('echo "All packages built successfully!"');
|
|
405
|
+
} else {
|
|
406
|
+
// Sequential build script
|
|
407
|
+
lines.push('# Build in order (sequential)');
|
|
408
|
+
lines.push('');
|
|
409
|
+
|
|
410
|
+
for (let i = 0; i < result.sorted.length; i++) {
|
|
411
|
+
const pkg = result.sorted[i];
|
|
412
|
+
lines.push(`echo "Building ${i + 1}/${result.sorted.length}: ${pkg}..."`);
|
|
413
|
+
lines.push(`pnpm --filter ${pkg} run build`);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
lines.push('');
|
|
417
|
+
lines.push('echo "All packages built successfully!"');
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return lines.join('\n');
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Main function
|
|
425
|
+
*/
|
|
426
|
+
function main() {
|
|
427
|
+
const rootDir = process.cwd();
|
|
428
|
+
|
|
429
|
+
if (!options.json) {
|
|
430
|
+
log('\nš KB Labs Build Order Calculator\n', 'bold');
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const packages = findPackages(rootDir);
|
|
434
|
+
|
|
435
|
+
if (packages.length === 0) {
|
|
436
|
+
log('ā ļø No KB Labs packages found', 'yellow');
|
|
437
|
+
process.exit(0);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const graph = buildDependencyGraph(packages);
|
|
441
|
+
|
|
442
|
+
if (options.package) {
|
|
443
|
+
// Build order for specific package
|
|
444
|
+
const fullPackageName = options.package.startsWith('@kb-labs/')
|
|
445
|
+
? options.package
|
|
446
|
+
: `@kb-labs/${options.package}`;
|
|
447
|
+
|
|
448
|
+
if (!graph.has(fullPackageName)) {
|
|
449
|
+
log(`ā ļø Package not found: ${fullPackageName}`, 'yellow');
|
|
450
|
+
log('\nAvailable packages:', 'gray');
|
|
451
|
+
for (const pkg of Array.from(graph.keys()).sort()) {
|
|
452
|
+
log(` ${pkg}`, 'gray');
|
|
453
|
+
}
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const order = getBuildOrderForPackage(graph, fullPackageName);
|
|
458
|
+
|
|
459
|
+
if (options.json) {
|
|
460
|
+
console.log(JSON.stringify({ package: fullPackageName, order }, null, 2));
|
|
461
|
+
} else {
|
|
462
|
+
log(`\nš¦ Build order for ${fullPackageName}:\n`, 'blue');
|
|
463
|
+
for (let i = 0; i < order.length; i++) {
|
|
464
|
+
const pkg = order[i];
|
|
465
|
+
const isCurrent = pkg === fullPackageName;
|
|
466
|
+
log(`${(i + 1).toString().padStart(3)}. ${pkg}${isCurrent ? ' ā¬
target' : ''}`, isCurrent ? 'yellow' : 'gray');
|
|
467
|
+
}
|
|
468
|
+
log('', 'reset');
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
// Full build order
|
|
472
|
+
const result = topologicalSort(graph);
|
|
473
|
+
|
|
474
|
+
if (options.json) {
|
|
475
|
+
const output = {
|
|
476
|
+
total: graph.size,
|
|
477
|
+
layers: result.layers,
|
|
478
|
+
sorted: result.sorted,
|
|
479
|
+
circular: result.circular,
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// Add cycle details if circular dependencies exist
|
|
483
|
+
if (result.circular.length > 0) {
|
|
484
|
+
const cycles = findCircularDependencies(graph, result.circular);
|
|
485
|
+
output.cycles = cycles.map(c => c.cycle);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
console.log(JSON.stringify(output, null, 2));
|
|
489
|
+
} else if (options.script) {
|
|
490
|
+
const script = generateBuildScript(result, graph);
|
|
491
|
+
console.log(script);
|
|
492
|
+
} else {
|
|
493
|
+
printBuildOrder(result, graph);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
process.exit(0);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
main();
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* KB DevKit - Build Readiness Checker
|
|
4
|
+
*
|
|
5
|
+
* Analyzes workspace to determine if packages can be successfully bundled.
|
|
6
|
+
* Specifically useful before creating standalone executables with esbuild/rollup.
|
|
7
|
+
*
|
|
8
|
+
* Checks:
|
|
9
|
+
* 1. Missing packages referenced in imports
|
|
10
|
+
* 2. Broken import paths (e.g., missing .js files after compilation)
|
|
11
|
+
* 3. Packages that would fail bundling due to dependencies
|
|
12
|
+
* 4. Dependency chains that are broken
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* npx kb-devkit-check-build-readiness
|
|
16
|
+
* npx kb-devkit-check-build-readiness --package @kb-labs/cli-bin
|
|
17
|
+
* npx kb-devkit-check-build-readiness --fix (auto-fix what's possible)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { execSync } from 'child_process';
|
|
21
|
+
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
22
|
+
import { join, dirname } from 'path';
|
|
23
|
+
import { fileURLToPath } from 'url';
|
|
24
|
+
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const rootDir = join(__dirname, '../..');
|
|
27
|
+
|
|
28
|
+
// Parse args
|
|
29
|
+
const args = process.argv.slice(2);
|
|
30
|
+
const targetPackage = args.find(a => a.startsWith('--package='))?.split('=')[1];
|
|
31
|
+
const shouldFix = args.includes('--fix');
|
|
32
|
+
|
|
33
|
+
console.log('š KB Labs Build Readiness Checker\n');
|
|
34
|
+
|
|
35
|
+
// Step 1: Find all workspace packages
|
|
36
|
+
function findWorkspacePackages() {
|
|
37
|
+
const packages = [];
|
|
38
|
+
const monorepos = readdirSync(rootDir).filter(d => d.startsWith('kb-labs-'));
|
|
39
|
+
|
|
40
|
+
for (const monorepo of monorepos) {
|
|
41
|
+
const packagesDir = join(rootDir, monorepo, 'packages');
|
|
42
|
+
if (!existsSync(packagesDir)) {continue;}
|
|
43
|
+
|
|
44
|
+
for (const pkg of readdirSync(packagesDir)) {
|
|
45
|
+
const pkgJsonPath = join(packagesDir, pkg, 'package.json');
|
|
46
|
+
if (!existsSync(pkgJsonPath)) {continue;}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf8'));
|
|
50
|
+
packages.push({
|
|
51
|
+
name: pkgJson.name,
|
|
52
|
+
path: join(packagesDir, pkg),
|
|
53
|
+
pkgJson,
|
|
54
|
+
});
|
|
55
|
+
} catch (e) {
|
|
56
|
+
// Skip invalid package.json
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return packages;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Step 2: Get import checker results
|
|
65
|
+
function getImportIssues() {
|
|
66
|
+
try {
|
|
67
|
+
return execSync('npx kb-devkit-check-imports 2>&1', {
|
|
68
|
+
cwd: rootDir,
|
|
69
|
+
encoding: 'utf8',
|
|
70
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
|
71
|
+
});
|
|
72
|
+
} catch (e) {
|
|
73
|
+
return e.stdout || e.message;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Step 3: Parse issues from output
|
|
78
|
+
function parseIssues(output) {
|
|
79
|
+
const issues = {
|
|
80
|
+
missingPackages: new Set(),
|
|
81
|
+
brokenImports: new Map(), // pkg -> [files]
|
|
82
|
+
packagesWithIssues: new Set(),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const lines = output.split('\n');
|
|
86
|
+
let currentPkg = null;
|
|
87
|
+
|
|
88
|
+
for (const line of lines) {
|
|
89
|
+
// Detect package name
|
|
90
|
+
const pkgMatch = line.match(/@kb-labs\/[\w-]+/);
|
|
91
|
+
if (pkgMatch && line.includes('ā')) {
|
|
92
|
+
currentPkg = pkgMatch[0];
|
|
93
|
+
issues.packagesWithIssues.add(currentPkg);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Detect missing packages
|
|
97
|
+
if (line.includes('Missing workspace dependencies') && currentPkg) {
|
|
98
|
+
issues.brokenImports.set(currentPkg, []);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Detect broken imports
|
|
102
|
+
if (line.includes('Cannot resolve:') && currentPkg) {
|
|
103
|
+
const pathMatch = line.match(/Cannot resolve: (.+)/);
|
|
104
|
+
if (pathMatch) {
|
|
105
|
+
const arr = issues.brokenImports.get(currentPkg) || [];
|
|
106
|
+
arr.push(pathMatch[1].trim());
|
|
107
|
+
issues.brokenImports.set(currentPkg, arr);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Collect missing package names
|
|
112
|
+
if (line.includes('@kb-labs/plugin-manifest')) {
|
|
113
|
+
issues.missingPackages.add('@kb-labs/plugin-manifest');
|
|
114
|
+
}
|
|
115
|
+
if (line.includes('@kb-labs/plugin-adapter-rest')) {
|
|
116
|
+
issues.missingPackages.add('@kb-labs/plugin-adapter-rest');
|
|
117
|
+
}
|
|
118
|
+
if (line.includes('@kb-labs/plugin-adapter-cli')) {
|
|
119
|
+
issues.missingPackages.add('@kb-labs/plugin-adapter-cli');
|
|
120
|
+
}
|
|
121
|
+
if (line.includes('@kb-labs/plugin-adapter-studio')) {
|
|
122
|
+
issues.missingPackages.add('@kb-labs/plugin-adapter-studio');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return issues;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Step 4: Check if package can be bundled
|
|
130
|
+
function checkBundleability(pkgName, issues, allPackages) {
|
|
131
|
+
const problems = [];
|
|
132
|
+
|
|
133
|
+
// Check if package itself has issues
|
|
134
|
+
if (issues.packagesWithIssues.has(pkgName)) {
|
|
135
|
+
const brokenImports = issues.brokenImports.get(pkgName) || [];
|
|
136
|
+
if (brokenImports.length > 0) {
|
|
137
|
+
problems.push(`š“ Has ${brokenImports.length} broken import(s)`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Find package deps
|
|
142
|
+
const pkg = allPackages.find(p => p.name === pkgName);
|
|
143
|
+
if (!pkg) {
|
|
144
|
+
problems.push('š“ Package not found in workspace');
|
|
145
|
+
return { canBundle: false, problems };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const deps = [
|
|
149
|
+
...Object.keys(pkg.pkgJson.dependencies || {}),
|
|
150
|
+
...Object.keys(pkg.pkgJson.peerDependencies || {})
|
|
151
|
+
];
|
|
152
|
+
|
|
153
|
+
// Check if any dependency is missing
|
|
154
|
+
for (const dep of deps) {
|
|
155
|
+
if (dep.startsWith('@kb-labs/') && issues.missingPackages.has(dep)) {
|
|
156
|
+
problems.push(`š“ Missing dependency: ${dep}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Recursively check dependencies
|
|
161
|
+
for (const dep of deps) {
|
|
162
|
+
if (dep.startsWith('@kb-labs/') && issues.packagesWithIssues.has(dep)) {
|
|
163
|
+
problems.push(`š” Dependency has issues: ${dep}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const canBundle = problems.filter(p => p.startsWith('š“')).length === 0;
|
|
168
|
+
return { canBundle, problems };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Main execution
|
|
172
|
+
const packages = findWorkspacePackages();
|
|
173
|
+
console.log(`š¦ Found ${packages.length} workspace packages\n`);
|
|
174
|
+
|
|
175
|
+
console.log('š Running import checker...\n');
|
|
176
|
+
const importOutput = getImportIssues();
|
|
177
|
+
const issues = parseIssues(importOutput);
|
|
178
|
+
|
|
179
|
+
console.log('š Analysis Results:\n');
|
|
180
|
+
console.log(`š“ Missing packages: ${issues.missingPackages.size}`);
|
|
181
|
+
if (issues.missingPackages.size > 0) {
|
|
182
|
+
for (const pkg of issues.missingPackages) {
|
|
183
|
+
console.log(` - ${pkg}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
console.log(`\nš“ Packages with issues: ${issues.packagesWithIssues.size}`);
|
|
187
|
+
console.log(`š“ Packages with broken imports: ${issues.brokenImports.size}\n`);
|
|
188
|
+
|
|
189
|
+
// If target package specified, check bundleability
|
|
190
|
+
if (targetPackage) {
|
|
191
|
+
console.log(`\nšÆ Checking bundleability for: ${targetPackage}\n`);
|
|
192
|
+
const result = checkBundleability(targetPackage, issues, packages);
|
|
193
|
+
|
|
194
|
+
if (result.canBundle) {
|
|
195
|
+
console.log('ā
Package CAN be bundled!\n');
|
|
196
|
+
} else {
|
|
197
|
+
console.log('ā Package CANNOT be bundled due to:\n');
|
|
198
|
+
for (const problem of result.problems) {
|
|
199
|
+
console.log(` ${problem}`);
|
|
200
|
+
}
|
|
201
|
+
console.log('\nš” Recommendations:');
|
|
202
|
+
console.log(' 1. Fix missing packages (create or remove references)');
|
|
203
|
+
console.log(' 2. Fix broken imports (update paths after build)');
|
|
204
|
+
console.log(' 3. Run: npx kb-devkit-fix-deps --remove-unused');
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
console.log('\nš” To check specific package:');
|
|
209
|
+
console.log(' npx kb-devkit-check-build-readiness --package @kb-labs/cli-bin\n');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Show top problematic packages
|
|
213
|
+
console.log('\nš Most problematic packages:\n');
|
|
214
|
+
const sorted = Array.from(issues.brokenImports.entries())
|
|
215
|
+
.sort((a, b) => b[1].length - a[1].length)
|
|
216
|
+
.slice(0, 10);
|
|
217
|
+
|
|
218
|
+
for (const [pkg, imports] of sorted) {
|
|
219
|
+
console.log(` ${pkg}: ${imports.length} broken import(s)`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log('\n');
|