@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,615 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - TypeScript Types Audit
5
+ *
6
+ * Deep type safety analysis for the entire monorepo using TypeScript Compiler API.
7
+ * Shows centralized audit report with type coverage, errors, and dependency chains.
8
+ *
9
+ * Unlike simple linting, this:
10
+ * - Uses TypeScript Compiler API for semantic analysis
11
+ * - Tracks type inheritance chains across packages
12
+ * - Shows impact: what breaks if type X is wrong
13
+ * - Provides single audit report for entire monorepo
14
+ *
15
+ * Usage:
16
+ * kb-devkit-types-audit # Full audit report
17
+ * kb-devkit-types-audit --package=cli-core # Specific package
18
+ * kb-devkit-types-audit --errors-only # Only show errors
19
+ * kb-devkit-types-audit --coverage # Type coverage report
20
+ * kb-devkit-types-audit --json # JSON output
21
+ */
22
+
23
+ import ts from 'typescript';
24
+ import fs from 'node:fs';
25
+ import path from 'node:path';
26
+ import { fileURLToPath } from 'node:url';
27
+
28
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
29
+
30
+ // ANSI colors
31
+ const colors = {
32
+ reset: '\x1b[0m',
33
+ red: '\x1b[31m',
34
+ green: '\x1b[32m',
35
+ yellow: '\x1b[33m',
36
+ blue: '\x1b[34m',
37
+ magenta: '\x1b[35m',
38
+ cyan: '\x1b[36m',
39
+ gray: '\x1b[90m',
40
+ bold: '\x1b[1m',
41
+ };
42
+
43
+ function log(message, color = 'reset') {
44
+ if (!options.json) {
45
+ console.log(`${colors[color]}${message}${colors.reset}`);
46
+ }
47
+ }
48
+
49
+ // Parse CLI arguments
50
+ const args = process.argv.slice(2);
51
+ const options = {
52
+ json: args.includes('--json'),
53
+ errorsOnly: args.includes('--errors-only'),
54
+ coverage: args.includes('--coverage'),
55
+ verbose: args.includes('--verbose') || args.includes('-v'),
56
+ package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
57
+ };
58
+
59
+ /**
60
+ * Find all packages
61
+ */
62
+ function findPackages(rootDir) {
63
+ const packages = [];
64
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
65
+
66
+ for (const entry of entries) {
67
+ if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
68
+
69
+ const repoPath = path.join(rootDir, entry.name);
70
+ const packagesDir = path.join(repoPath, 'packages');
71
+
72
+ if (!fs.existsSync(packagesDir)) {continue;}
73
+
74
+ const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
75
+
76
+ for (const pkgDir of packageDirs) {
77
+ if (!pkgDir.isDirectory()) {continue;}
78
+
79
+ const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
80
+ const tsconfigPath = path.join(packagesDir, pkgDir.name, 'tsconfig.json');
81
+
82
+ if (fs.existsSync(packageJsonPath) && fs.existsSync(tsconfigPath)) {
83
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
84
+
85
+ packages.push({
86
+ name: packageJson.name,
87
+ path: packageJsonPath,
88
+ dir: path.join(packagesDir, pkgDir.name),
89
+ tsconfigPath,
90
+ });
91
+ }
92
+ }
93
+ }
94
+
95
+ return packages;
96
+ }
97
+
98
+ /**
99
+ * Create TypeScript program for a package
100
+ */
101
+ function createProgram(packageDir, tsconfigPath) {
102
+ const configFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
103
+
104
+ if (configFile.error) {
105
+ return null;
106
+ }
107
+
108
+ const parsedConfig = ts.parseJsonConfigFileContent(
109
+ configFile.config,
110
+ ts.sys,
111
+ packageDir
112
+ );
113
+
114
+ if (parsedConfig.errors.length > 0) {
115
+ return null;
116
+ }
117
+
118
+ return ts.createProgram({
119
+ rootNames: parsedConfig.fileNames,
120
+ options: parsedConfig.options,
121
+ });
122
+ }
123
+
124
+ /**
125
+ * Analyze type errors in a package
126
+ */
127
+ function analyzeTypeErrors(program, packageName) {
128
+ const diagnostics = ts.getPreEmitDiagnostics(program);
129
+
130
+ const errors = [];
131
+ const warnings = [];
132
+
133
+ for (const diagnostic of diagnostics) {
134
+ if (!diagnostic.file) {continue;}
135
+
136
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(
137
+ diagnostic.start
138
+ );
139
+
140
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
141
+ const severity = diagnostic.category === ts.DiagnosticCategory.Error ? 'error' : 'warning';
142
+
143
+ const issue = {
144
+ severity,
145
+ message,
146
+ file: diagnostic.file.fileName,
147
+ line: line + 1,
148
+ column: character + 1,
149
+ code: diagnostic.code,
150
+ };
151
+
152
+ if (severity === 'error') {
153
+ errors.push(issue);
154
+ } else {
155
+ warnings.push(issue);
156
+ }
157
+ }
158
+
159
+ return { errors, warnings };
160
+ }
161
+
162
+ /**
163
+ * Calculate type coverage for a package
164
+ */
165
+ function calculateTypeCoverage(program) {
166
+ const checker = program.getTypeChecker();
167
+ const sourceFiles = program.getSourceFiles().filter(
168
+ (sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
169
+ );
170
+
171
+ let totalSymbols = 0;
172
+ let typedSymbols = 0;
173
+ let anyCount = 0;
174
+ let unknownCount = 0;
175
+ let tsIgnoreCount = 0;
176
+
177
+ for (const sourceFile of sourceFiles) {
178
+ // Count @ts-ignore comments
179
+ const text = sourceFile.getFullText();
180
+ const tsIgnoreMatches = text.match(/@ts-ignore/g);
181
+ tsIgnoreCount += tsIgnoreMatches ? tsIgnoreMatches.length : 0;
182
+
183
+ ts.forEachChild(sourceFile, function visit(node) {
184
+ // Check for 'any' type
185
+ if (ts.isTypeNode(node)) {
186
+ totalSymbols++;
187
+
188
+ const type = checker.getTypeAtLocation(node);
189
+
190
+ if (type.flags & ts.TypeFlags.Any) {
191
+ anyCount++;
192
+ } else if (type.flags & ts.TypeFlags.Unknown) {
193
+ unknownCount++;
194
+ } else {
195
+ typedSymbols++;
196
+ }
197
+ }
198
+
199
+ // Check variables, parameters, properties
200
+ if (
201
+ ts.isVariableDeclaration(node) ||
202
+ ts.isParameter(node) ||
203
+ ts.isPropertyDeclaration(node)
204
+ ) {
205
+ totalSymbols++;
206
+
207
+ if (node.type) {
208
+ const type = checker.getTypeAtLocation(node.type);
209
+
210
+ if (type.flags & ts.TypeFlags.Any) {
211
+ anyCount++;
212
+ } else if (type.flags & ts.TypeFlags.Unknown) {
213
+ unknownCount++;
214
+ } else {
215
+ typedSymbols++;
216
+ }
217
+ } else {
218
+ // No explicit type annotation - check inferred type
219
+ const symbol = checker.getSymbolAtLocation(node.name);
220
+ if (symbol) {
221
+ const type = checker.getTypeOfSymbolAtLocation(symbol, node);
222
+
223
+ if (type.flags & ts.TypeFlags.Any) {
224
+ anyCount++;
225
+ } else {
226
+ typedSymbols++;
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ ts.forEachChild(node, visit);
233
+ });
234
+ }
235
+
236
+ const coverage = totalSymbols > 0 ? (typedSymbols / totalSymbols) * 100 : 100;
237
+
238
+ return {
239
+ coverage: Math.round(coverage * 10) / 10,
240
+ totalSymbols,
241
+ typedSymbols,
242
+ anyCount,
243
+ unknownCount,
244
+ tsIgnoreCount,
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Find type dependencies and inheritance chains
250
+ */
251
+ function findTypeDependencies(program, packageName) {
252
+ const checker = program.getTypeChecker();
253
+ const sourceFiles = program.getSourceFiles().filter(
254
+ (sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules')
255
+ );
256
+
257
+ const imports = new Set();
258
+ const extendsChains = [];
259
+ const implementsChains = [];
260
+
261
+ for (const sourceFile of sourceFiles) {
262
+ ts.forEachChild(sourceFile, function visit(node) {
263
+ // Track type imports
264
+ if (ts.isImportDeclaration(node)) {
265
+ const moduleSpecifier = node.moduleSpecifier;
266
+ if (ts.isStringLiteral(moduleSpecifier)) {
267
+ const moduleName = moduleSpecifier.text;
268
+ if (moduleName.startsWith('@kb-labs/')) {
269
+ imports.add(moduleName);
270
+ }
271
+ }
272
+ }
273
+
274
+ // Track interface/class extensions
275
+ if (ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node)) {
276
+ if (node.heritageClauses) {
277
+ for (const clause of node.heritageClauses) {
278
+ for (const type of clause.types) {
279
+ const typeName = type.expression.getText();
280
+
281
+ if (clause.token === ts.SyntaxKind.ExtendsKeyword) {
282
+ extendsChains.push({
283
+ child: node.name?.getText() || 'anonymous',
284
+ parent: typeName,
285
+ file: sourceFile.fileName,
286
+ });
287
+ } else if (clause.token === ts.SyntaxKind.ImplementsKeyword) {
288
+ implementsChains.push({
289
+ class: node.name?.getText() || 'anonymous',
290
+ interface: typeName,
291
+ file: sourceFile.fileName,
292
+ });
293
+ }
294
+ }
295
+ }
296
+ }
297
+ }
298
+
299
+ ts.forEachChild(node, visit);
300
+ });
301
+ }
302
+
303
+ return {
304
+ imports: Array.from(imports),
305
+ extends: extendsChains,
306
+ implements: implementsChains,
307
+ };
308
+ }
309
+
310
+ /**
311
+ * Audit a single package
312
+ */
313
+ function auditPackage(packageInfo) {
314
+ const { name, dir, tsconfigPath } = packageInfo;
315
+
316
+ log(` Analyzing ${name}...`, 'gray');
317
+
318
+ const program = createProgram(dir, tsconfigPath);
319
+
320
+ if (!program) {
321
+ return {
322
+ name,
323
+ success: false,
324
+ reason: 'Failed to create TypeScript program',
325
+ };
326
+ }
327
+
328
+ const { errors, warnings } = analyzeTypeErrors(program, name);
329
+ const coverage = calculateTypeCoverage(program);
330
+ const dependencies = findTypeDependencies(program, name);
331
+
332
+ return {
333
+ name,
334
+ success: true,
335
+ errors,
336
+ warnings,
337
+ coverage,
338
+ dependencies,
339
+ };
340
+ }
341
+
342
+ /**
343
+ * Build impact graph (what breaks if this package has type errors)
344
+ */
345
+ function buildImpactGraph(results) {
346
+ const graph = new Map();
347
+
348
+ // Build reverse dependency map
349
+ for (const result of results) {
350
+ if (!result.success) {continue;}
351
+
352
+ graph.set(result.name, new Set());
353
+
354
+ for (const dep of result.dependencies.imports) {
355
+ if (!graph.has(dep)) {
356
+ graph.set(dep, new Set());
357
+ }
358
+ graph.get(dep).add(result.name);
359
+ }
360
+ }
361
+
362
+ return graph;
363
+ }
364
+
365
+ /**
366
+ * Calculate impact score (how many packages depend on this)
367
+ */
368
+ function calculateImpact(packageName, impactGraph) {
369
+ const visited = new Set();
370
+ const queue = [packageName];
371
+
372
+ while (queue.length > 0) {
373
+ const current = queue.shift();
374
+ if (visited.has(current)) {continue;}
375
+ visited.add(current);
376
+
377
+ const dependents = impactGraph.get(current);
378
+ if (dependents) {
379
+ for (const dep of dependents) {
380
+ if (!visited.has(dep)) {
381
+ queue.push(dep);
382
+ }
383
+ }
384
+ }
385
+ }
386
+
387
+ return visited.size - 1; // Exclude the package itself
388
+ }
389
+
390
+ /**
391
+ * Print audit report
392
+ */
393
+ function printAuditReport(results, impactGraph) {
394
+ log('\nšŸ“Š TypeScript Type Safety Audit Report\n', 'bold');
395
+
396
+ const successful = results.filter((r) => r.success);
397
+ const failed = results.filter((r) => !r.success);
398
+
399
+ log(`Analyzed ${successful.length} package(s)\n`, 'gray');
400
+
401
+ // Critical Issues
402
+ const withErrors = successful.filter((r) => r.errors.length > 0);
403
+
404
+ if (withErrors.length > 0) {
405
+ log(`āŒ Critical Issues (${withErrors.length} packages with type errors):\n`, 'red');
406
+
407
+ for (const result of withErrors.slice(0, 5)) {
408
+ const impact = calculateImpact(result.name, impactGraph);
409
+
410
+ log(` ${result.name}`, 'yellow');
411
+ log(` ${result.errors.length} error(s) - impacts ${impact} package(s)`, 'red');
412
+
413
+ if (options.verbose) {
414
+ for (const error of result.errors.slice(0, 3)) {
415
+ const relPath = error.file.replace(process.cwd(), '.');
416
+ log(` └─ ${relPath}:${error.line}:${error.column}`, 'gray');
417
+ log(` ${error.message}`, 'gray');
418
+ }
419
+ }
420
+ }
421
+
422
+ if (withErrors.length > 5) {
423
+ log(` ... and ${withErrors.length - 5} more packages with errors`, 'gray');
424
+ }
425
+
426
+ log('', 'reset');
427
+ }
428
+
429
+ // Warnings
430
+ if (!options.errorsOnly) {
431
+ const totalWarnings = successful.reduce((sum, r) => sum + r.warnings.length, 0);
432
+
433
+ if (totalWarnings > 0) {
434
+ log(`āš ļø Warnings (${totalWarnings} total):\n`, 'yellow');
435
+
436
+ const topWarnings = successful
437
+ .filter((r) => r.warnings.length > 0)
438
+ .sort((a, b) => b.warnings.length - a.warnings.length)
439
+ .slice(0, 5);
440
+
441
+ for (const result of topWarnings) {
442
+ log(` ${result.name}: ${result.warnings.length} warning(s)`, 'gray');
443
+ }
444
+
445
+ log('', 'reset');
446
+ }
447
+ }
448
+
449
+ // Type Safety Issues
450
+ if (!options.errorsOnly) {
451
+ const anyUsage = successful.filter((r) => r.coverage.anyCount > 0);
452
+ const tsIgnoreUsage = successful.filter((r) => r.coverage.tsIgnoreCount > 0);
453
+
454
+ if (anyUsage.length > 0 || tsIgnoreUsage.length > 0) {
455
+ log(`šŸ” Type Safety Issues:\n`, 'yellow');
456
+
457
+ const totalAny = successful.reduce((sum, r) => sum + r.coverage.anyCount, 0);
458
+ const totalTsIgnore = successful.reduce((sum, r) => sum + r.coverage.tsIgnoreCount, 0);
459
+
460
+ log(` ${totalAny} usage(s) of 'any' type`, totalAny > 50 ? 'red' : 'yellow');
461
+ log(` ${totalTsIgnore} @ts-ignore comment(s)`, totalTsIgnore > 20 ? 'red' : 'yellow');
462
+
463
+ log('', 'reset');
464
+ }
465
+ }
466
+
467
+ // Type Coverage
468
+ if (options.coverage || !options.errorsOnly) {
469
+ log(`šŸ“ˆ Type Coverage:\n`, 'blue');
470
+
471
+ const sorted = [...successful].sort((a, b) => a.coverage.coverage - b.coverage.coverage);
472
+
473
+ const excellent = sorted.filter((r) => r.coverage.coverage >= 90);
474
+ const good = sorted.filter((r) => r.coverage.coverage >= 70 && r.coverage.coverage < 90);
475
+ const poor = sorted.filter((r) => r.coverage.coverage < 70);
476
+
477
+ log(` āœ… Excellent (≄90%): ${excellent.length} packages`, 'green');
478
+ log(` āš ļø Good (70-90%): ${good.length} packages`, 'yellow');
479
+ log(` āŒ Poor (<70%): ${poor.length} packages`, 'red');
480
+
481
+ if (options.verbose || options.coverage) {
482
+ log('\n Top packages by coverage:', 'cyan');
483
+ for (const result of sorted.slice(-5).reverse()) {
484
+ const coverage = result.coverage.coverage;
485
+ const color = coverage >= 90 ? 'green' : coverage >= 70 ? 'yellow' : 'red';
486
+ log(` ${result.name.padEnd(35)} ${coverage.toFixed(1)}%`, color);
487
+ }
488
+
489
+ log('\n Bottom packages by coverage:', 'cyan');
490
+ for (const result of sorted.slice(0, 5)) {
491
+ const coverage = result.coverage.coverage;
492
+ const color = coverage >= 90 ? 'green' : coverage >= 70 ? 'yellow' : 'red';
493
+ log(` ${result.name.padEnd(35)} ${coverage.toFixed(1)}%`, color);
494
+ }
495
+ }
496
+
497
+ log('', 'reset');
498
+ }
499
+
500
+ // Summary
501
+ log('─'.repeat(60) + '\n', 'gray');
502
+ log('šŸ“Š Summary:\n', 'blue');
503
+
504
+ const totalErrors = successful.reduce((sum, r) => sum + r.errors.length, 0);
505
+ const totalWarnings = successful.reduce((sum, r) => sum + r.warnings.length, 0);
506
+ const avgCoverage =
507
+ successful.reduce((sum, r) => sum + r.coverage.coverage, 0) / successful.length;
508
+
509
+ log(` Total packages: ${successful.length}`, 'cyan');
510
+ log(` āŒ Type errors: ${totalErrors}`, totalErrors > 0 ? 'red' : 'green');
511
+ log(` āš ļø Warnings: ${totalWarnings}`, totalWarnings > 0 ? 'yellow' : 'green');
512
+ log(` šŸ“ˆ Avg coverage: ${avgCoverage.toFixed(1)}%`, avgCoverage >= 80 ? 'green' : 'yellow');
513
+
514
+ if (failed.length > 0) {
515
+ log(` āš ļø Failed to analyze: ${failed.length}`, 'yellow');
516
+ }
517
+
518
+ log('', 'reset');
519
+
520
+ // Tips
521
+ log('šŸ’” Tips:', 'blue');
522
+ log(' • Use --errors-only to show only critical issues', 'gray');
523
+ log(' • Use --coverage to see detailed coverage report', 'gray');
524
+ log(' • Use --package=name to audit specific package', 'gray');
525
+ log(' • Fix type errors to improve type safety', 'gray');
526
+ log('', 'reset');
527
+ }
528
+
529
+ /**
530
+ * Main function
531
+ */
532
+ async function main() {
533
+ const rootDir = process.cwd();
534
+
535
+ if (!options.json) {
536
+ log('\nšŸš€ KB Labs TypeScript Type Safety Audit\n', 'bold');
537
+ }
538
+
539
+ let packages = findPackages(rootDir);
540
+
541
+ if (options.package) {
542
+ const fullPackageName = options.package.startsWith('@kb-labs/')
543
+ ? options.package
544
+ : `@kb-labs/${options.package}`;
545
+
546
+ packages = packages.filter((p) => p.name === fullPackageName);
547
+
548
+ if (packages.length === 0) {
549
+ log(`āš ļø Package not found: ${fullPackageName}`, 'yellow');
550
+ process.exit(1);
551
+ }
552
+ }
553
+
554
+ if (packages.length === 0) {
555
+ log('āš ļø No packages found with TypeScript configuration', 'yellow');
556
+ process.exit(0);
557
+ }
558
+
559
+ log(`Found ${packages.length} package(s) to audit\n`, 'gray');
560
+
561
+ // Audit all packages
562
+ const results = [];
563
+ for (const pkg of packages) {
564
+ const result = auditPackage(pkg);
565
+ results.push(result);
566
+ }
567
+
568
+ const impactGraph = buildImpactGraph(results);
569
+
570
+ if (options.json) {
571
+ const successful = results.filter((r) => r.success);
572
+ const totalErrors = successful.reduce((sum, r) => sum + r.errors.length, 0);
573
+ const totalWarnings = successful.reduce((sum, r) => sum + r.warnings.length, 0);
574
+ const avgCoverage =
575
+ successful.reduce((sum, r) => sum + r.coverage.coverage, 0) / successful.length;
576
+
577
+ const output = {
578
+ summary: {
579
+ total: results.length,
580
+ successful: successful.length,
581
+ failed: results.filter((r) => !r.success).length,
582
+ totalErrors,
583
+ totalWarnings,
584
+ avgCoverage: Math.round(avgCoverage * 10) / 10,
585
+ },
586
+ packages: results.map((r) => ({
587
+ name: r.name,
588
+ success: r.success,
589
+ errors: r.errors?.length || 0,
590
+ warnings: r.warnings?.length || 0,
591
+ coverage: r.coverage?.coverage,
592
+ anyCount: r.coverage?.anyCount,
593
+ tsIgnoreCount: r.coverage?.tsIgnoreCount,
594
+ impact: calculateImpact(r.name, impactGraph),
595
+ })),
596
+ issues: results
597
+ .filter((r) => r.success && r.errors.length > 0)
598
+ .map((r) => ({
599
+ package: r.name,
600
+ errors: r.errors,
601
+ impact: calculateImpact(r.name, impactGraph),
602
+ })),
603
+ };
604
+
605
+ console.log(JSON.stringify(output, null, 2));
606
+ } else {
607
+ printAuditReport(results, impactGraph);
608
+ }
609
+
610
+ // Exit with error if there are type errors
611
+ const hasErrors = results.some((r) => r.success && r.errors.length > 0);
612
+ process.exit(hasErrors ? 1 : 0);
613
+ }
614
+
615
+ main();