@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.
Files changed (295) hide show
  1. package/.cursorrules +32 -0
  2. package/.github/CODEOWNERS +2 -0
  3. package/.github/actions/setup-node-pnpm/action.yml +47 -0
  4. package/.github/workflow-templates/ci.yml +13 -0
  5. package/.github/workflow-templates/drift-check.yml +10 -0
  6. package/.github/workflow-templates/profiles-validate.yml +16 -0
  7. package/.github/workflow-templates/release.yml +8 -0
  8. package/.github/workflows/ci-reusable.yml +131 -0
  9. package/.github/workflows/drift-check-reusable.yml +23 -0
  10. package/.github/workflows/fixtures.yml +74 -0
  11. package/.github/workflows/profiles-validate-reusable.yml +67 -0
  12. package/.github/workflows/release-reusable.yml +50 -0
  13. package/.vscode/settings.json +23 -0
  14. package/AGENTS.md +130 -0
  15. package/LICENSE +21 -0
  16. package/README.md +1542 -0
  17. package/agents/devkit-maintainer/context.globs +15 -0
  18. package/agents/devkit-maintainer/permissions.yml +17 -0
  19. package/agents/devkit-maintainer/prompt.md +28 -0
  20. package/agents/devkit-maintainer/runbook.md +31 -0
  21. package/agents/docs-crafter/prompt.md +24 -0
  22. package/agents/docs-crafter/runbook.md +18 -0
  23. package/agents/release-manager/context.globs +7 -0
  24. package/agents/release-manager/prompt.md +27 -0
  25. package/agents/release-manager/runbook.md +17 -0
  26. package/agents/test-generator/context.globs +7 -0
  27. package/agents/test-generator/prompt.md +27 -0
  28. package/agents/test-generator/runbook.md +18 -0
  29. package/bin/devkit-architecture.mjs +1225 -0
  30. package/bin/devkit-build-order.mjs +500 -0
  31. package/bin/devkit-check-build-readiness.mjs +222 -0
  32. package/bin/devkit-check-commands.mjs +394 -0
  33. package/bin/devkit-check-configs.mjs +461 -0
  34. package/bin/devkit-check-deprecated.mjs +532 -0
  35. package/bin/devkit-check-duplicates.mjs +431 -0
  36. package/bin/devkit-check-exports.mjs +561 -0
  37. package/bin/devkit-check-imports.mjs +712 -0
  38. package/bin/devkit-check-paths.mjs +670 -0
  39. package/bin/devkit-check-scripts.mjs +335 -0
  40. package/bin/devkit-check-structure.mjs +495 -0
  41. package/bin/devkit-check-types.mjs +450 -0
  42. package/bin/devkit-ci.mjs +261 -0
  43. package/bin/devkit-core-gate.mjs +225 -0
  44. package/bin/devkit-fix-deps.mjs +1169 -0
  45. package/bin/devkit-freshness.mjs +199 -0
  46. package/bin/devkit-health.mjs +489 -0
  47. package/bin/devkit-migrate-configs.mjs +370 -0
  48. package/bin/devkit-paths.mjs +192 -0
  49. package/bin/devkit-stats.mjs +453 -0
  50. package/bin/devkit-sync.mjs +12 -0
  51. package/bin/devkit-tsup-external.mjs +148 -0
  52. package/bin/devkit-types-audit.mjs +615 -0
  53. package/bin/devkit-types-order.mjs +637 -0
  54. package/bin/devkit-validate-naming.mjs +203 -0
  55. package/bin/devkit-visualize.mjs +452 -0
  56. package/bin/kb-devkit-qa-history.mjs +453 -0
  57. package/bin/kb-devkit-qa.mjs +915 -0
  58. package/eslint/node.js +134 -0
  59. package/eslint/react.js +260 -0
  60. package/package.json +186 -0
  61. package/prettier/index.json +10 -0
  62. package/sync/index.mjs +693 -0
  63. package/templates/configs/README.md +306 -0
  64. package/templates/configs/eslint.config.js +27 -0
  65. package/templates/configs/package.json.bin +25 -0
  66. package/templates/configs/package.json.lib +30 -0
  67. package/templates/configs/tsconfig.build.json +15 -0
  68. package/templates/configs/tsconfig.json +9 -0
  69. package/templates/configs/tsup.config.bin.ts +34 -0
  70. package/templates/configs/tsup.config.cli.ts +41 -0
  71. package/templates/configs/tsup.config.dual.ts +46 -0
  72. package/templates/configs/tsup.config.ts +36 -0
  73. package/templates/package-json/README.md +290 -0
  74. package/templates/package-json/package.json.bin.template +40 -0
  75. package/templates/package-json/package.json.template +45 -0
  76. package/tsconfig/base.json +21 -0
  77. package/tsconfig/cli.json +12 -0
  78. package/tsconfig/dist/__tests__/cache.spec.d.ts +6 -0
  79. package/tsconfig/dist/__tests__/cache.spec.d.ts.map +1 -0
  80. package/tsconfig/dist/__tests__/cache.spec.js +85 -0
  81. package/tsconfig/dist/__tests__/cache.spec.js.map +1 -0
  82. package/tsconfig/dist/__tests__/fs-atomic.spec.d.ts +6 -0
  83. package/tsconfig/dist/__tests__/fs-atomic.spec.d.ts.map +1 -0
  84. package/tsconfig/dist/__tests__/fs-atomic.spec.js +153 -0
  85. package/tsconfig/dist/__tests__/fs-atomic.spec.js.map +1 -0
  86. package/tsconfig/dist/__tests__/init-workspace.spec.d.ts +6 -0
  87. package/tsconfig/dist/__tests__/init-workspace.spec.d.ts.map +1 -0
  88. package/tsconfig/dist/__tests__/init-workspace.spec.js +99 -0
  89. package/tsconfig/dist/__tests__/init-workspace.spec.js.map +1 -0
  90. package/tsconfig/dist/__tests__/kb-error.spec.d.ts +6 -0
  91. package/tsconfig/dist/__tests__/kb-error.spec.d.ts.map +1 -0
  92. package/tsconfig/dist/__tests__/kb-error.spec.js +190 -0
  93. package/tsconfig/dist/__tests__/kb-error.spec.js.map +1 -0
  94. package/tsconfig/dist/__tests__/preset-lockfile.spec.d.ts +6 -0
  95. package/tsconfig/dist/__tests__/preset-lockfile.spec.d.ts.map +1 -0
  96. package/tsconfig/dist/__tests__/preset-lockfile.spec.js +142 -0
  97. package/tsconfig/dist/__tests__/preset-lockfile.spec.js.map +1 -0
  98. package/tsconfig/dist/__tests__/product-config-profiles.spec.d.ts +6 -0
  99. package/tsconfig/dist/__tests__/product-config-profiles.spec.d.ts.map +1 -0
  100. package/tsconfig/dist/__tests__/product-config-profiles.spec.js +100 -0
  101. package/tsconfig/dist/__tests__/product-config-profiles.spec.js.map +1 -0
  102. package/tsconfig/dist/__tests__/product-config.spec.d.ts +6 -0
  103. package/tsconfig/dist/__tests__/product-config.spec.d.ts.map +1 -0
  104. package/tsconfig/dist/__tests__/product-config.spec.js +298 -0
  105. package/tsconfig/dist/__tests__/product-config.spec.js.map +1 -0
  106. package/tsconfig/dist/__tests__/runtime.spec.d.ts +2 -0
  107. package/tsconfig/dist/__tests__/runtime.spec.d.ts.map +1 -0
  108. package/tsconfig/dist/__tests__/runtime.spec.js +127 -0
  109. package/tsconfig/dist/__tests__/runtime.spec.js.map +1 -0
  110. package/tsconfig/dist/__tests__/upsert-lockfile.spec.d.ts +6 -0
  111. package/tsconfig/dist/__tests__/upsert-lockfile.spec.d.ts.map +1 -0
  112. package/tsconfig/dist/__tests__/upsert-lockfile.spec.js +251 -0
  113. package/tsconfig/dist/__tests__/upsert-lockfile.spec.js.map +1 -0
  114. package/tsconfig/dist/__tests__/validate-config.spec.d.ts +2 -0
  115. package/tsconfig/dist/__tests__/validate-config.spec.d.ts.map +1 -0
  116. package/tsconfig/dist/__tests__/validate-config.spec.js +14 -0
  117. package/tsconfig/dist/__tests__/validate-config.spec.js.map +1 -0
  118. package/tsconfig/dist/api/init-workspace.d.ts +10 -0
  119. package/tsconfig/dist/api/init-workspace.d.ts.map +1 -0
  120. package/tsconfig/dist/api/init-workspace.js +191 -0
  121. package/tsconfig/dist/api/init-workspace.js.map +1 -0
  122. package/tsconfig/dist/api/product-config.d.ts +21 -0
  123. package/tsconfig/dist/api/product-config.d.ts.map +1 -0
  124. package/tsconfig/dist/api/product-config.js +192 -0
  125. package/tsconfig/dist/api/product-config.js.map +1 -0
  126. package/tsconfig/dist/api/read-config.d.ts +22 -0
  127. package/tsconfig/dist/api/read-config.d.ts.map +1 -0
  128. package/tsconfig/dist/api/read-config.js +105 -0
  129. package/tsconfig/dist/api/read-config.js.map +1 -0
  130. package/tsconfig/dist/api/upsert-lockfile.d.ts +10 -0
  131. package/tsconfig/dist/api/upsert-lockfile.d.ts.map +1 -0
  132. package/tsconfig/dist/api/upsert-lockfile.js +63 -0
  133. package/tsconfig/dist/api/upsert-lockfile.js.map +1 -0
  134. package/tsconfig/dist/cache/fs-cache.d.ts +38 -0
  135. package/tsconfig/dist/cache/fs-cache.d.ts.map +1 -0
  136. package/tsconfig/dist/cache/fs-cache.js +142 -0
  137. package/tsconfig/dist/cache/fs-cache.js.map +1 -0
  138. package/tsconfig/dist/errors/kb-error.d.ts +32 -0
  139. package/tsconfig/dist/errors/kb-error.d.ts.map +1 -0
  140. package/tsconfig/dist/errors/kb-error.js +54 -0
  141. package/tsconfig/dist/errors/kb-error.js.map +1 -0
  142. package/tsconfig/dist/fs/__tests__/fs.spec.d.ts +2 -0
  143. package/tsconfig/dist/fs/__tests__/fs.spec.d.ts.map +1 -0
  144. package/tsconfig/dist/fs/__tests__/fs.spec.js +22 -0
  145. package/tsconfig/dist/fs/__tests__/fs.spec.js.map +1 -0
  146. package/tsconfig/dist/fs/fs.d.ts +6 -0
  147. package/tsconfig/dist/fs/fs.d.ts.map +1 -0
  148. package/tsconfig/dist/fs/fs.js +12 -0
  149. package/tsconfig/dist/fs/fs.js.map +1 -0
  150. package/tsconfig/dist/fs/index.d.ts +2 -0
  151. package/tsconfig/dist/fs/index.d.ts.map +1 -0
  152. package/tsconfig/dist/fs/index.js +2 -0
  153. package/tsconfig/dist/fs/index.js.map +1 -0
  154. package/tsconfig/dist/hash/config-hash.d.ts +17 -0
  155. package/tsconfig/dist/hash/config-hash.d.ts.map +1 -0
  156. package/tsconfig/dist/hash/config-hash.js +55 -0
  157. package/tsconfig/dist/hash/config-hash.js.map +1 -0
  158. package/tsconfig/dist/index.d.ts +5 -0
  159. package/tsconfig/dist/index.d.ts.map +1 -0
  160. package/tsconfig/dist/index.js +5 -0
  161. package/tsconfig/dist/index.js.map +1 -0
  162. package/tsconfig/dist/lockfile/lockfile.d.ts +54 -0
  163. package/tsconfig/dist/lockfile/lockfile.d.ts.map +1 -0
  164. package/tsconfig/dist/lockfile/lockfile.js +141 -0
  165. package/tsconfig/dist/lockfile/lockfile.js.map +1 -0
  166. package/tsconfig/dist/logging/__tests__/logger.spec.d.ts +2 -0
  167. package/tsconfig/dist/logging/__tests__/logger.spec.d.ts.map +1 -0
  168. package/tsconfig/dist/logging/__tests__/logger.spec.js +65 -0
  169. package/tsconfig/dist/logging/__tests__/logger.spec.js.map +1 -0
  170. package/tsconfig/dist/logging/__tests__/redaction.spec.d.ts +2 -0
  171. package/tsconfig/dist/logging/__tests__/redaction.spec.d.ts.map +1 -0
  172. package/tsconfig/dist/logging/__tests__/redaction.spec.js +34 -0
  173. package/tsconfig/dist/logging/__tests__/redaction.spec.js.map +1 -0
  174. package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.d.ts +2 -0
  175. package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.d.ts.map +1 -0
  176. package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.js +90 -0
  177. package/tsconfig/dist/logging/__tests__/sinks-and-env.spec.js.map +1 -0
  178. package/tsconfig/dist/logging/index.d.ts +6 -0
  179. package/tsconfig/dist/logging/index.d.ts.map +1 -0
  180. package/tsconfig/dist/logging/index.js +6 -0
  181. package/tsconfig/dist/logging/index.js.map +1 -0
  182. package/tsconfig/dist/logging/logger.d.ts +9 -0
  183. package/tsconfig/dist/logging/logger.d.ts.map +1 -0
  184. package/tsconfig/dist/logging/logger.js +101 -0
  185. package/tsconfig/dist/logging/logger.js.map +1 -0
  186. package/tsconfig/dist/logging/redaction.d.ts +7 -0
  187. package/tsconfig/dist/logging/redaction.d.ts.map +1 -0
  188. package/tsconfig/dist/logging/redaction.js +23 -0
  189. package/tsconfig/dist/logging/redaction.js.map +1 -0
  190. package/tsconfig/dist/logging/sinks/json.d.ts +4 -0
  191. package/tsconfig/dist/logging/sinks/json.d.ts.map +1 -0
  192. package/tsconfig/dist/logging/sinks/json.js +23 -0
  193. package/tsconfig/dist/logging/sinks/json.js.map +1 -0
  194. package/tsconfig/dist/logging/sinks/stdout.d.ts +3 -0
  195. package/tsconfig/dist/logging/sinks/stdout.d.ts.map +1 -0
  196. package/tsconfig/dist/logging/sinks/stdout.js +24 -0
  197. package/tsconfig/dist/logging/sinks/stdout.js.map +1 -0
  198. package/tsconfig/dist/logging/types/index.d.ts +2 -0
  199. package/tsconfig/dist/logging/types/index.d.ts.map +1 -0
  200. package/tsconfig/dist/logging/types/index.js +2 -0
  201. package/tsconfig/dist/logging/types/index.js.map +1 -0
  202. package/tsconfig/dist/logging/types/types.d.ts +37 -0
  203. package/tsconfig/dist/logging/types/types.d.ts.map +1 -0
  204. package/tsconfig/dist/logging/types/types.js +2 -0
  205. package/tsconfig/dist/logging/types/types.js.map +1 -0
  206. package/tsconfig/dist/merge/layered-merge.d.ts +16 -0
  207. package/tsconfig/dist/merge/layered-merge.d.ts.map +1 -0
  208. package/tsconfig/dist/merge/layered-merge.js +97 -0
  209. package/tsconfig/dist/merge/layered-merge.js.map +1 -0
  210. package/tsconfig/dist/preset/resolve-preset.d.ts +29 -0
  211. package/tsconfig/dist/preset/resolve-preset.d.ts.map +1 -0
  212. package/tsconfig/dist/preset/resolve-preset.js +104 -0
  213. package/tsconfig/dist/preset/resolve-preset.js.map +1 -0
  214. package/tsconfig/dist/repo/__tests__/repo.spec.d.ts +2 -0
  215. package/tsconfig/dist/repo/__tests__/repo.spec.d.ts.map +1 -0
  216. package/tsconfig/dist/repo/__tests__/repo.spec.js +25 -0
  217. package/tsconfig/dist/repo/__tests__/repo.spec.js.map +1 -0
  218. package/tsconfig/dist/repo/index.d.ts +2 -0
  219. package/tsconfig/dist/repo/index.d.ts.map +1 -0
  220. package/tsconfig/dist/repo/index.js +2 -0
  221. package/tsconfig/dist/repo/index.js.map +1 -0
  222. package/tsconfig/dist/repo/repo.d.ts +6 -0
  223. package/tsconfig/dist/repo/repo.d.ts.map +1 -0
  224. package/tsconfig/dist/repo/repo.js +25 -0
  225. package/tsconfig/dist/repo/repo.js.map +1 -0
  226. package/tsconfig/dist/runtime/index.d.ts +2 -0
  227. package/tsconfig/dist/runtime/index.d.ts.map +1 -0
  228. package/tsconfig/dist/runtime/index.js +2 -0
  229. package/tsconfig/dist/runtime/index.js.map +1 -0
  230. package/tsconfig/dist/runtime/runtime.d.ts +46 -0
  231. package/tsconfig/dist/runtime/runtime.d.ts.map +1 -0
  232. package/tsconfig/dist/runtime/runtime.js +126 -0
  233. package/tsconfig/dist/runtime/runtime.js.map +1 -0
  234. package/tsconfig/dist/tsconfig.tools.tsbuildinfo +1 -0
  235. package/tsconfig/dist/tsconfig.tsbuildinfo +1 -0
  236. package/tsconfig/dist/types/index.d.ts +2 -0
  237. package/tsconfig/dist/types/index.d.ts.map +1 -0
  238. package/tsconfig/dist/types/index.js +2 -0
  239. package/tsconfig/dist/types/index.js.map +1 -0
  240. package/tsconfig/dist/types/init.d.ts +34 -0
  241. package/tsconfig/dist/types/init.d.ts.map +1 -0
  242. package/tsconfig/dist/types/init.js +6 -0
  243. package/tsconfig/dist/types/init.js.map +1 -0
  244. package/tsconfig/dist/types/preset.d.ts +27 -0
  245. package/tsconfig/dist/types/preset.d.ts.map +1 -0
  246. package/tsconfig/dist/types/preset.js +6 -0
  247. package/tsconfig/dist/types/preset.js.map +1 -0
  248. package/tsconfig/dist/types/types.d.ts +6 -0
  249. package/tsconfig/dist/types/types.d.ts.map +1 -0
  250. package/tsconfig/dist/types/types.js +2 -0
  251. package/tsconfig/dist/types/types.js.map +1 -0
  252. package/tsconfig/dist/utils/__tests__/env.spec.d.ts +2 -0
  253. package/tsconfig/dist/utils/__tests__/env.spec.d.ts.map +1 -0
  254. package/tsconfig/dist/utils/__tests__/env.spec.js +33 -0
  255. package/tsconfig/dist/utils/__tests__/env.spec.js.map +1 -0
  256. package/tsconfig/dist/utils/env.d.ts +7 -0
  257. package/tsconfig/dist/utils/env.d.ts.map +1 -0
  258. package/tsconfig/dist/utils/env.js +25 -0
  259. package/tsconfig/dist/utils/env.js.map +1 -0
  260. package/tsconfig/dist/utils/fs-atomic.d.ts +15 -0
  261. package/tsconfig/dist/utils/fs-atomic.d.ts.map +1 -0
  262. package/tsconfig/dist/utils/fs-atomic.js +45 -0
  263. package/tsconfig/dist/utils/fs-atomic.js.map +1 -0
  264. package/tsconfig/dist/utils/index.d.ts +3 -0
  265. package/tsconfig/dist/utils/index.d.ts.map +1 -0
  266. package/tsconfig/dist/utils/index.js +3 -0
  267. package/tsconfig/dist/utils/index.js.map +1 -0
  268. package/tsconfig/dist/utils/paths.d.ts +21 -0
  269. package/tsconfig/dist/utils/paths.d.ts.map +1 -0
  270. package/tsconfig/dist/utils/paths.js +32 -0
  271. package/tsconfig/dist/utils/paths.js.map +1 -0
  272. package/tsconfig/dist/utils/product-normalize.d.ts +27 -0
  273. package/tsconfig/dist/utils/product-normalize.d.ts.map +1 -0
  274. package/tsconfig/dist/utils/product-normalize.js +45 -0
  275. package/tsconfig/dist/utils/product-normalize.js.map +1 -0
  276. package/tsconfig/dist/validation/validate-config.d.ts +7 -0
  277. package/tsconfig/dist/validation/validate-config.d.ts.map +1 -0
  278. package/tsconfig/dist/validation/validate-config.js +22 -0
  279. package/tsconfig/dist/validation/validate-config.js.map +1 -0
  280. package/tsconfig/lib.json +13 -0
  281. package/tsconfig/node.json +12 -0
  282. package/tsconfig/react-app.json +8 -0
  283. package/tsconfig/react-lib.json +8 -0
  284. package/tsconfig/test.json +15 -0
  285. package/tsup/bin.js +172 -0
  286. package/tsup/dual.js +155 -0
  287. package/tsup/external-sync.mjs +41 -0
  288. package/tsup/external.mjs +109 -0
  289. package/tsup/node.js +65 -0
  290. package/tsup/react-lib.js +18 -0
  291. package/tsup/sdk.js +118 -0
  292. package/vite/react-app.js +50 -0
  293. package/vitest/node.js +37 -0
  294. package/vitest/react.js +39 -0
  295. package/vitest/vitest-setup.ts +9 -0
@@ -0,0 +1,670 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - Path Validator
5
+ *
6
+ * Validates all paths and references in the monorepo:
7
+ * 1. package.json dependencies pointing to non-existent packages
8
+ * 2. package.json exports pointing to non-existent files
9
+ * 3. package.json bin pointing to non-existent scripts
10
+ * 4. tsconfig.json extends/references pointing to non-existent configs
11
+ * 5. Workspace protocol references to non-existent packages
12
+ *
13
+ * Usage:
14
+ * kb-devkit-check-paths # Check all paths
15
+ * kb-devkit-check-paths --package=cli-core # Check specific package
16
+ * kb-devkit-check-paths --fix # Auto-fix what's possible
17
+ * kb-devkit-check-paths --json # JSON output
18
+ */
19
+
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
25
+
26
+ // ANSI colors
27
+ const colors = {
28
+ reset: '\x1b[0m',
29
+ red: '\x1b[31m',
30
+ green: '\x1b[32m',
31
+ yellow: '\x1b[33m',
32
+ blue: '\x1b[34m',
33
+ magenta: '\x1b[35m',
34
+ cyan: '\x1b[36m',
35
+ gray: '\x1b[90m',
36
+ bold: '\x1b[1m',
37
+ };
38
+
39
+ function log(message, color = 'reset') {
40
+ if (!options.json) {
41
+ console.log(`${colors[color] || colors.reset}${message}${colors.reset}`);
42
+ }
43
+ }
44
+
45
+ // Parse CLI arguments
46
+ const args = process.argv.slice(2);
47
+ const options = {
48
+ fix: args.includes('--fix'),
49
+ json: args.includes('--json'),
50
+ verbose: args.includes('--verbose') || args.includes('-v'),
51
+ package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
52
+ };
53
+
54
+ /**
55
+ * Find all packages in monorepo
56
+ */
57
+ function findPackages(rootDir, filterPackage) {
58
+ const packages = [];
59
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
60
+
61
+ for (const entry of entries) {
62
+ if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
63
+
64
+ const repoPath = path.join(rootDir, entry.name);
65
+ const packagesDir = path.join(repoPath, 'packages');
66
+
67
+ if (!fs.existsSync(packagesDir)) {continue;}
68
+
69
+ const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
70
+
71
+ for (const pkgDir of packageDirs) {
72
+ if (!pkgDir.isDirectory()) {continue;}
73
+
74
+ if (filterPackage && pkgDir.name !== filterPackage) {continue;}
75
+
76
+ const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
77
+
78
+ if (fs.existsSync(packageJsonPath)) {
79
+ packages.push({
80
+ path: packageJsonPath,
81
+ dir: path.join(packagesDir, pkgDir.name),
82
+ repo: entry.name,
83
+ });
84
+ }
85
+ }
86
+ }
87
+
88
+ return packages;
89
+ }
90
+
91
+ /**
92
+ * Get all workspace package names
93
+ */
94
+ function getWorkspacePackageNames(packages) {
95
+ const names = new Set();
96
+
97
+ for (const pkg of packages) {
98
+ try {
99
+ const packageJson = JSON.parse(fs.readFileSync(pkg.path, 'utf-8'));
100
+ if (packageJson.name) {
101
+ names.add(packageJson.name);
102
+ }
103
+ } catch {
104
+ // Skip invalid package.json
105
+ }
106
+ }
107
+
108
+ return names;
109
+ }
110
+
111
+ /**
112
+ * Check if a path exists (file or directory)
113
+ */
114
+ function pathExists(basePath, relativePath) {
115
+ const fullPath = path.resolve(basePath, relativePath);
116
+
117
+ // Try exact path
118
+ if (fs.existsSync(fullPath)) {
119
+ return { exists: true, resolved: fullPath };
120
+ }
121
+
122
+ // Try with common extensions
123
+ const extensions = ['.js', '.mjs', '.cjs', '.ts', '.tsx', '.json', '.d.ts'];
124
+ for (const ext of extensions) {
125
+ if (fs.existsSync(fullPath + ext)) {
126
+ return { exists: true, resolved: fullPath + ext };
127
+ }
128
+ }
129
+
130
+ // Try index files
131
+ const indexFiles = ['index.js', 'index.mjs', 'index.ts', 'index.tsx'];
132
+ for (const indexFile of indexFiles) {
133
+ const indexPath = path.join(fullPath, indexFile);
134
+ if (fs.existsSync(indexPath)) {
135
+ return { exists: true, resolved: indexPath };
136
+ }
137
+ }
138
+
139
+ return { exists: false, resolved: fullPath };
140
+ }
141
+
142
+ /**
143
+ * Check package.json dependencies
144
+ */
145
+ function checkDependencies(packageJson, packageDir, workspaceNames) {
146
+ const issues = [];
147
+
148
+ const allDeps = {
149
+ ...packageJson.dependencies,
150
+ ...packageJson.devDependencies,
151
+ ...packageJson.peerDependencies,
152
+ ...packageJson.optionalDependencies,
153
+ };
154
+
155
+ for (const [dep, version] of Object.entries(allDeps)) {
156
+ // Check workspace: protocol references
157
+ if (version.startsWith('workspace:')) {
158
+ if (dep.startsWith('@kb-labs/') && !workspaceNames.has(dep)) {
159
+ issues.push({
160
+ type: 'missing_workspace_package',
161
+ severity: 'error',
162
+ path: `dependencies.${dep}`,
163
+ message: `Workspace package "${dep}" does not exist in monorepo`,
164
+ value: version,
165
+ });
166
+ }
167
+ }
168
+
169
+ // Check link: protocol references
170
+ if (version.startsWith('link:')) {
171
+ const linkPath = version.replace('link:', '');
172
+ const { exists } = pathExists(packageDir, linkPath);
173
+
174
+ if (!exists) {
175
+ issues.push({
176
+ type: 'broken_link',
177
+ severity: 'error',
178
+ path: `dependencies.${dep}`,
179
+ message: `Link path does not exist: ${linkPath}`,
180
+ value: version,
181
+ });
182
+ }
183
+ }
184
+
185
+ // Check file: protocol references
186
+ if (version.startsWith('file:')) {
187
+ const filePath = version.replace('file:', '');
188
+ const { exists } = pathExists(packageDir, filePath);
189
+
190
+ if (!exists) {
191
+ issues.push({
192
+ type: 'broken_file_ref',
193
+ severity: 'error',
194
+ path: `dependencies.${dep}`,
195
+ message: `File path does not exist: ${filePath}`,
196
+ value: version,
197
+ });
198
+ }
199
+ }
200
+ }
201
+
202
+ return issues;
203
+ }
204
+
205
+ /**
206
+ * Check package.json exports
207
+ */
208
+ function checkExports(packageJson, packageDir) {
209
+ const issues = [];
210
+
211
+ if (!packageJson.exports) {return issues;}
212
+
213
+ function checkExportPath(exportKey, exportValue, parentPath = 'exports') {
214
+ if (typeof exportValue === 'string') {
215
+ // Skip conditions like "import", "require", "types", "default"
216
+ if (exportValue.startsWith('./') || exportValue.startsWith('../')) {
217
+ // Skip glob patterns (e.g., ./dist/*)
218
+ if (exportValue.includes('*')) {return;}
219
+
220
+ const { exists } = pathExists(packageDir, exportValue);
221
+
222
+ if (!exists) {
223
+ // Check if it's a dist file (expected to not exist before build)
224
+ const isDist = exportValue.includes('/dist/') || exportValue.startsWith('./dist/');
225
+
226
+ issues.push({
227
+ type: 'broken_export',
228
+ severity: isDist ? 'warning' : 'error',
229
+ path: `${parentPath}["${exportKey}"]`,
230
+ message: `Export path does not exist: ${exportValue}${isDist ? ' (needs build)' : ''}`,
231
+ value: exportValue,
232
+ });
233
+ }
234
+ }
235
+ } else if (typeof exportValue === 'object' && exportValue !== null) {
236
+ // Handle conditional exports
237
+ for (const [key, value] of Object.entries(exportValue)) {
238
+ checkExportPath(key, value, `${parentPath}["${exportKey}"]`);
239
+ }
240
+ }
241
+ }
242
+
243
+ for (const [key, value] of Object.entries(packageJson.exports)) {
244
+ checkExportPath(key, value);
245
+ }
246
+
247
+ return issues;
248
+ }
249
+
250
+ /**
251
+ * Check package.json bin
252
+ */
253
+ function checkBin(packageJson, packageDir) {
254
+ const issues = [];
255
+
256
+ if (!packageJson.bin) {return issues;}
257
+
258
+ const bins = typeof packageJson.bin === 'string'
259
+ ? { [packageJson.name]: packageJson.bin }
260
+ : packageJson.bin;
261
+
262
+ for (const [binName, binPath] of Object.entries(bins)) {
263
+ const { exists } = pathExists(packageDir, binPath);
264
+
265
+ if (!exists) {
266
+ issues.push({
267
+ type: 'broken_bin',
268
+ severity: 'error',
269
+ path: `bin["${binName}"]`,
270
+ message: `Bin script does not exist: ${binPath}`,
271
+ value: binPath,
272
+ });
273
+ }
274
+ }
275
+
276
+ return issues;
277
+ }
278
+
279
+ /**
280
+ * Check package.json main, module, types fields
281
+ */
282
+ function checkEntryPoints(packageJson, packageDir) {
283
+ const issues = [];
284
+
285
+ const entryFields = ['main', 'module', 'types', 'typings', 'browser'];
286
+
287
+ for (const field of entryFields) {
288
+ if (packageJson[field]) {
289
+ const { exists } = pathExists(packageDir, packageJson[field]);
290
+
291
+ if (!exists) {
292
+ // Check if it's a dist file that might not exist yet
293
+ const isDist = packageJson[field].includes('/dist/') || packageJson[field].startsWith('dist/');
294
+
295
+ issues.push({
296
+ type: 'broken_entry_point',
297
+ severity: isDist ? 'warning' : 'error',
298
+ path: field,
299
+ message: `Entry point does not exist: ${packageJson[field]}${isDist ? ' (may need build)' : ''}`,
300
+ value: packageJson[field],
301
+ });
302
+ }
303
+ }
304
+ }
305
+
306
+ return issues;
307
+ }
308
+
309
+ /**
310
+ * Check tsconfig.json
311
+ */
312
+ function checkTsconfig(packageDir) {
313
+ const issues = [];
314
+ const tsconfigPath = path.join(packageDir, 'tsconfig.json');
315
+
316
+ if (!fs.existsSync(tsconfigPath)) {return issues;}
317
+
318
+ try {
319
+ const content = fs.readFileSync(tsconfigPath, 'utf-8');
320
+ // Remove comments for JSON parsing (but not // inside strings)
321
+ // Only remove // comments that are not inside quotes
322
+ const cleanContent = content
323
+ .replace(/\/\*[\s\S]*?\*\//g, '') // Remove /* */ comments
324
+ .replace(/^(\s*)\/\/.*$/gm, '$1'); // Remove // comments at start of lines only
325
+ const tsconfig = JSON.parse(cleanContent);
326
+
327
+ // Check extends (can be string or array in TS 5.0+)
328
+ if (tsconfig.extends) {
329
+ const extendsList = Array.isArray(tsconfig.extends)
330
+ ? tsconfig.extends
331
+ : [tsconfig.extends];
332
+
333
+ for (let i = 0; i < extendsList.length; i++) {
334
+ const extendsPath = extendsList[i];
335
+
336
+ // Skip non-string values or node_modules references
337
+ if (typeof extendsPath !== 'string') {continue;}
338
+ if (extendsPath.startsWith('@') || extendsPath.includes('node_modules')) {continue;}
339
+
340
+ const { exists } = pathExists(packageDir, extendsPath);
341
+
342
+ if (!exists) {
343
+ const pathLabel = Array.isArray(tsconfig.extends)
344
+ ? `tsconfig.json:extends[${i}]`
345
+ : 'tsconfig.json:extends';
346
+
347
+ issues.push({
348
+ type: 'broken_tsconfig_extends',
349
+ severity: 'error',
350
+ path: pathLabel,
351
+ message: `tsconfig extends path does not exist: ${extendsPath}`,
352
+ value: extendsPath,
353
+ });
354
+ }
355
+ }
356
+ }
357
+
358
+ // Check references
359
+ if (tsconfig.references && Array.isArray(tsconfig.references)) {
360
+ for (let i = 0; i < tsconfig.references.length; i++) {
361
+ const ref = tsconfig.references[i];
362
+ if (ref.path) {
363
+ const { exists } = pathExists(packageDir, ref.path);
364
+
365
+ if (!exists) {
366
+ issues.push({
367
+ type: 'broken_tsconfig_reference',
368
+ severity: 'error',
369
+ path: `tsconfig.json:references[${i}]`,
370
+ message: `tsconfig reference path does not exist: ${ref.path}`,
371
+ value: ref.path,
372
+ });
373
+ }
374
+ }
375
+ }
376
+ }
377
+
378
+ // Check paths aliases
379
+ if (tsconfig.compilerOptions?.paths) {
380
+ for (const [alias, targets] of Object.entries(tsconfig.compilerOptions.paths)) {
381
+ for (let i = 0; i < targets.length; i++) {
382
+ const target = targets[i];
383
+
384
+ // Skip wildcards
385
+ if (target.includes('*')) {continue;}
386
+
387
+ const baseUrl = tsconfig.compilerOptions.baseUrl || '.';
388
+ const basePath = path.resolve(packageDir, baseUrl);
389
+ const { exists } = pathExists(basePath, target);
390
+
391
+ if (!exists) {
392
+ issues.push({
393
+ type: 'broken_tsconfig_path',
394
+ severity: 'warning',
395
+ path: `tsconfig.json:compilerOptions.paths["${alias}"][${i}]`,
396
+ message: `tsconfig path alias target does not exist: ${target}`,
397
+ value: target,
398
+ });
399
+ }
400
+ }
401
+ }
402
+ }
403
+ } catch (error) {
404
+ issues.push({
405
+ type: 'invalid_tsconfig',
406
+ severity: 'error',
407
+ path: 'tsconfig.json',
408
+ message: `Invalid tsconfig.json: ${error.message}`,
409
+ });
410
+ }
411
+
412
+ return issues;
413
+ }
414
+
415
+ /**
416
+ * Check package.json files field
417
+ */
418
+ function checkFilesField(packageJson, packageDir) {
419
+ const issues = [];
420
+
421
+ if (!packageJson.files || !Array.isArray(packageJson.files)) {return issues;}
422
+
423
+ for (const file of packageJson.files) {
424
+ // Skip glob patterns
425
+ if (file.includes('*')) {continue;}
426
+
427
+ const { exists } = pathExists(packageDir, file);
428
+
429
+ if (!exists) {
430
+ // Check if it's a dist folder
431
+ const isDist = file === 'dist' || file.startsWith('dist/');
432
+
433
+ issues.push({
434
+ type: 'broken_files_entry',
435
+ severity: isDist ? 'warning' : 'error',
436
+ path: `files`,
437
+ message: `File/folder in "files" field does not exist: ${file}${isDist ? ' (may need build)' : ''}`,
438
+ value: file,
439
+ });
440
+ }
441
+ }
442
+
443
+ return issues;
444
+ }
445
+
446
+ /**
447
+ * Check single package
448
+ */
449
+ function checkPackage(pkg, workspaceNames) {
450
+ const { path: packagePath, dir: packageDir, repo } = pkg;
451
+
452
+ try {
453
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
454
+ const packageName = packageJson.name;
455
+
456
+ if (!packageName) {
457
+ return {
458
+ name: 'unknown',
459
+ dir: packageDir,
460
+ repo,
461
+ issues: [{
462
+ type: 'missing_name',
463
+ severity: 'error',
464
+ path: 'name',
465
+ message: 'package.json missing "name" field',
466
+ }],
467
+ };
468
+ }
469
+
470
+ const issues = [
471
+ ...checkDependencies(packageJson, packageDir, workspaceNames),
472
+ ...checkExports(packageJson, packageDir),
473
+ ...checkBin(packageJson, packageDir),
474
+ ...checkEntryPoints(packageJson, packageDir),
475
+ ...checkFilesField(packageJson, packageDir),
476
+ ...checkTsconfig(packageDir),
477
+ ];
478
+
479
+ return {
480
+ name: packageName,
481
+ dir: packageDir,
482
+ repo,
483
+ issues,
484
+ };
485
+ } catch (error) {
486
+ return {
487
+ name: 'unknown',
488
+ dir: packageDir,
489
+ repo,
490
+ issues: [{
491
+ type: 'invalid_package_json',
492
+ severity: 'error',
493
+ path: 'package.json',
494
+ message: `Invalid package.json: ${error.message}`,
495
+ }],
496
+ };
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Print results
502
+ */
503
+ function printResults(results) {
504
+ log('\nšŸ”— KB Labs Path Validator\n', 'bold');
505
+
506
+ const packagesWithIssues = results.filter(r => r.issues.length > 0);
507
+ const errorCount = results.reduce((sum, r) =>
508
+ sum + r.issues.filter(i => i.severity === 'error').length, 0);
509
+ const warningCount = results.reduce((sum, r) =>
510
+ sum + r.issues.filter(i => i.severity === 'warning').length, 0);
511
+
512
+ if (packagesWithIssues.length === 0) {
513
+ log('āœ… All paths are valid!\n', 'green');
514
+ log(`Checked ${results.length} package(s)`, 'gray');
515
+ return;
516
+ }
517
+
518
+ // Group by issue type
519
+ const byType = new Map();
520
+ for (const result of packagesWithIssues) {
521
+ for (const issue of result.issues) {
522
+ if (!byType.has(issue.type)) {
523
+ byType.set(issue.type, []);
524
+ }
525
+ byType.get(issue.type).push({ ...issue, package: result.name, repo: result.repo });
526
+ }
527
+ }
528
+
529
+ // Print by severity first - errors
530
+ const issueTypeNames = {
531
+ missing_workspace_package: 'šŸ“¦ Missing Workspace Packages',
532
+ broken_link: 'šŸ”— Broken Link References',
533
+ broken_file_ref: 'šŸ“ Broken File References',
534
+ broken_export: 'šŸ“¤ Broken Exports',
535
+ broken_bin: 'āš™ļø Broken Bin Scripts',
536
+ broken_entry_point: '🚪 Broken Entry Points',
537
+ broken_tsconfig_extends: 'šŸ“ Broken tsconfig Extends',
538
+ broken_tsconfig_reference: 'šŸ“ Broken tsconfig References',
539
+ broken_tsconfig_path: 'šŸ“ Broken tsconfig Paths',
540
+ broken_files_entry: 'šŸ“‹ Broken Files Field Entries',
541
+ invalid_tsconfig: 'āŒ Invalid tsconfig.json',
542
+ invalid_package_json: 'āŒ Invalid package.json',
543
+ missing_name: 'āŒ Missing Package Name',
544
+ };
545
+
546
+ // Print errors first
547
+ for (const [type, issues] of byType.entries()) {
548
+ const errors = issues.filter(i => i.severity === 'error');
549
+ if (errors.length === 0) {continue;}
550
+
551
+ log(`\n${issueTypeNames[type] || type} (${errors.length}):\n`, 'red');
552
+
553
+ // Group by repo
554
+ const byRepo = new Map();
555
+ for (const issue of errors) {
556
+ if (!byRepo.has(issue.repo)) {
557
+ byRepo.set(issue.repo, []);
558
+ }
559
+ byRepo.get(issue.repo).push(issue);
560
+ }
561
+
562
+ for (const [repo, repoIssues] of byRepo.entries()) {
563
+ log(` ${repo}/`, 'yellow');
564
+ for (const issue of repoIssues) {
565
+ log(` ${issue.package}`, 'cyan');
566
+ log(` ${issue.message}`, 'gray');
567
+ if (issue.value && options.verbose) {
568
+ log(` Value: ${issue.value}`, 'gray');
569
+ }
570
+ }
571
+ }
572
+ }
573
+
574
+ // Print warnings
575
+ for (const [type, issues] of byType.entries()) {
576
+ const warnings = issues.filter(i => i.severity === 'warning');
577
+ if (warnings.length === 0) {continue;}
578
+
579
+ log(`\n${issueTypeNames[type] || type} (${warnings.length}) āš ļø:\n`, 'yellow');
580
+
581
+ for (const issue of warnings.slice(0, 10)) {
582
+ log(` ${issue.package}: ${issue.message}`, 'gray');
583
+ }
584
+ if (warnings.length > 10) {
585
+ log(` ... and ${warnings.length - 10} more`, 'gray');
586
+ }
587
+ }
588
+
589
+ // Summary
590
+ log('\n' + '─'.repeat(60), 'gray');
591
+ log('šŸ“Š Summary:', 'blue');
592
+ log(` Packages checked: ${results.length}`, 'cyan');
593
+ log(` Packages with issues: ${packagesWithIssues.length}`, packagesWithIssues.length > 0 ? 'yellow' : 'green');
594
+ log(` āŒ Errors: ${errorCount}`, errorCount > 0 ? 'red' : 'green');
595
+ log(` āš ļø Warnings: ${warningCount}`, warningCount > 0 ? 'yellow' : 'green');
596
+ log('', 'reset');
597
+
598
+ if (errorCount > 0) {
599
+ log('šŸ’” Tips:', 'blue');
600
+ log(' • Missing workspace packages: Remove or fix the dependency', 'gray');
601
+ log(' • Broken exports/bin: Update path or create missing file', 'gray');
602
+ log(' • Broken entry points with "(may need build)": Run pnpm build', 'gray');
603
+ log(' • Broken tsconfig: Fix extends/references paths', 'gray');
604
+ log('', 'reset');
605
+ }
606
+ }
607
+
608
+ /**
609
+ * Main function
610
+ */
611
+ function main() {
612
+ const rootDir = process.cwd();
613
+
614
+ if (!options.json) {
615
+ log('\nšŸ”— KB Labs Path Validator\n', 'bold');
616
+ log('Validating all paths and references...\n', 'gray');
617
+ }
618
+
619
+ const packages = findPackages(rootDir, options.package);
620
+
621
+ if (packages.length === 0) {
622
+ if (!options.json) {
623
+ log('āš ļø No KB Labs packages found', 'yellow');
624
+ }
625
+ process.exit(0);
626
+ }
627
+
628
+ if (!options.json) {
629
+ log(`Found ${packages.length} package(s) to check\n`, 'gray');
630
+ }
631
+
632
+ // Get all workspace package names for reference validation
633
+ const workspaceNames = getWorkspacePackageNames(packages);
634
+
635
+ // Check all packages
636
+ const results = packages.map(pkg => checkPackage(pkg, workspaceNames));
637
+
638
+ if (options.json) {
639
+ const errorCount = results.reduce((sum, r) =>
640
+ sum + r.issues.filter(i => i.severity === 'error').length, 0);
641
+ const warningCount = results.reduce((sum, r) =>
642
+ sum + r.issues.filter(i => i.severity === 'warning').length, 0);
643
+
644
+ console.log(JSON.stringify({
645
+ totalPackages: results.length,
646
+ packagesWithIssues: results.filter(r => r.issues.length > 0).length,
647
+ errorCount,
648
+ warningCount,
649
+ issues: results
650
+ .filter(r => r.issues.length > 0)
651
+ .map(r => ({
652
+ package: r.name,
653
+ repo: r.repo,
654
+ issues: r.issues,
655
+ })),
656
+ }, null, 2));
657
+
658
+ process.exit(errorCount > 0 ? 1 : 0);
659
+ }
660
+
661
+ printResults(results);
662
+
663
+ // Exit with error if there are errors
664
+ const errorCount = results.reduce((sum, r) =>
665
+ sum + r.issues.filter(i => i.severity === 'error').length, 0);
666
+
667
+ process.exit(errorCount > 0 ? 1 : 0);
668
+ }
669
+
670
+ main();