@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,637 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - TypeScript Types Order Calculator
5
+ *
6
+ * Calculates the correct order for TypeScript types generation.
7
+ * Unlike build-order which tracks runtime dependencies, this tracks
8
+ * TYPE dependencies - which types are imported from which packages.
9
+ *
10
+ * This is critical in monorepos because:
11
+ * - ProjectA imports type G from PackageB
12
+ * - PackageB imports type L from PackageM
13
+ * - If PackageM doesn't generate types (dts: false), ProjectA breaks!
14
+ *
15
+ * Usage:
16
+ * kb-devkit-types-order # Show types order
17
+ * kb-devkit-types-order --layers # Show parallel layers
18
+ * kb-devkit-types-order --package=cli # For specific package
19
+ * kb-devkit-types-order --broken # Show only broken chains
20
+ * kb-devkit-types-order --json # JSON output
21
+ */
22
+
23
+ import fs from 'node:fs';
24
+ import path from 'node:path';
25
+ import { fileURLToPath } from 'node:url';
26
+
27
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
28
+
29
+ // ANSI colors
30
+ const colors = {
31
+ reset: '\x1b[0m',
32
+ red: '\x1b[31m',
33
+ green: '\x1b[32m',
34
+ yellow: '\x1b[33m',
35
+ blue: '\x1b[34m',
36
+ magenta: '\x1b[35m',
37
+ cyan: '\x1b[36m',
38
+ gray: '\x1b[90m',
39
+ bold: '\x1b[1m',
40
+ };
41
+
42
+ function log(message, color = 'reset') {
43
+ if (!options.json) {
44
+ console.log(`${colors[color]}${message}${colors.reset}`);
45
+ }
46
+ }
47
+
48
+ // Parse CLI arguments
49
+ const args = process.argv.slice(2);
50
+ const options = {
51
+ layers: args.includes('--layers'),
52
+ json: args.includes('--json'),
53
+ broken: args.includes('--broken'),
54
+ verbose: args.includes('--verbose') || args.includes('-v'),
55
+ package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
56
+ };
57
+
58
+ /**
59
+ * Find all packages
60
+ */
61
+ function findPackages(rootDir) {
62
+ const packages = [];
63
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
64
+
65
+ for (const entry of entries) {
66
+ if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
67
+
68
+ const repoPath = path.join(rootDir, entry.name);
69
+ const packagesDir = path.join(repoPath, 'packages');
70
+
71
+ if (!fs.existsSync(packagesDir)) {continue;}
72
+
73
+ const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
74
+
75
+ for (const pkgDir of packageDirs) {
76
+ if (!pkgDir.isDirectory()) {continue;}
77
+
78
+ const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
79
+
80
+ if (fs.existsSync(packageJsonPath)) {
81
+ packages.push({
82
+ path: packageJsonPath,
83
+ dir: path.join(packagesDir, pkgDir.name),
84
+ });
85
+ }
86
+ }
87
+ }
88
+
89
+ return packages;
90
+ }
91
+
92
+ /**
93
+ * Check if package generates types
94
+ */
95
+ function checkTypesGeneration(packageDir) {
96
+ // Check tsup.config.ts for dts setting
97
+ const tsupConfigPath = path.join(packageDir, 'tsup.config.ts');
98
+
99
+ if (fs.existsSync(tsupConfigPath)) {
100
+ const content = fs.readFileSync(tsupConfigPath, 'utf-8');
101
+
102
+ // Check for dts: false (bad!)
103
+ if (/dts\s*:\s*false/.test(content)) {
104
+ return { generates: false, reason: 'dts: false in tsup.config.ts' };
105
+ }
106
+
107
+ // Check for dts: true (good!)
108
+ if (/dts\s*:\s*true/.test(content)) {
109
+ return { generates: true, reason: 'dts: true in tsup.config.ts' };
110
+ }
111
+
112
+ // No explicit dts setting - tsup defaults to true
113
+ return { generates: true, reason: 'tsup default (dts: true)' };
114
+ }
115
+
116
+ // No tsup config - check if it's a TypeScript package
117
+ const srcDir = path.join(packageDir, 'src');
118
+ if (fs.existsSync(srcDir)) {
119
+ const hasTS = walkDir(srcDir, (file) => /\.(ts|tsx)$/.test(file));
120
+ if (hasTS) {
121
+ return { generates: false, reason: 'No tsup.config.ts found' };
122
+ }
123
+ }
124
+
125
+ return { generates: false, reason: 'No TypeScript sources' };
126
+ }
127
+
128
+ /**
129
+ * Walk directory to check for files
130
+ */
131
+ function walkDir(dir, predicate) {
132
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
133
+
134
+ for (const entry of entries) {
135
+ const fullPath = path.join(dir, entry.name);
136
+
137
+ if (entry.isDirectory()) {
138
+ if (walkDir(fullPath, predicate)) {return true;}
139
+ } else if (entry.isFile() && predicate(entry.name)) {
140
+ return true;
141
+ }
142
+ }
143
+
144
+ return false;
145
+ }
146
+
147
+ /**
148
+ * Extract type imports from TypeScript files
149
+ * Looks for:
150
+ * - import type { X } from '@kb-labs/...'
151
+ * - import { type X } from '@kb-labs/...'
152
+ * - import { X } from '@kb-labs/...' (might be type or value)
153
+ */
154
+ function extractTypeImports(packageDir) {
155
+ const srcDir = path.join(packageDir, 'src');
156
+ if (!fs.existsSync(srcDir)) {return new Set();}
157
+
158
+ const typeImports = new Set();
159
+
160
+ function scanFile(filePath) {
161
+ const content = fs.readFileSync(filePath, 'utf-8');
162
+
163
+ // Match import statements
164
+ const importRegex = /import\s+(?:type\s+)?{([^}]+)}\s+from\s+['"](@kb-labs\/[^'"]+)['"]/g;
165
+ const importTypeRegex = /import\s+type\s+(?:{[^}]+}|\*\s+as\s+\w+)\s+from\s+['"](@kb-labs\/[^'"]+)['"]/g;
166
+
167
+ let match;
168
+
169
+ // Extract from 'import type { ... } from @kb-labs/...'
170
+ while ((match = importTypeRegex.exec(content)) !== null) {
171
+ typeImports.add(match[1]);
172
+ }
173
+
174
+ // Extract from 'import { ... } from @kb-labs/...'
175
+ // These might be types or values, but we track them as potential type dependencies
176
+ while ((match = importRegex.exec(content)) !== null) {
177
+ typeImports.add(match[2]);
178
+ }
179
+ }
180
+
181
+ function walkFiles(dir) {
182
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
183
+
184
+ for (const entry of entries) {
185
+ const fullPath = path.join(dir, entry.name);
186
+
187
+ if (entry.isDirectory()) {
188
+ walkFiles(fullPath);
189
+ } else if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name)) {
190
+ scanFile(fullPath);
191
+ }
192
+ }
193
+ }
194
+
195
+ walkFiles(srcDir);
196
+ return typeImports;
197
+ }
198
+
199
+ /**
200
+ * Build types dependency graph
201
+ */
202
+ function buildTypesDependencyGraph(packages) {
203
+ const graph = new Map(); // packageName -> { typeDeps: Set, generates: boolean, reason: string }
204
+
205
+ // First pass: collect all packages and their types generation status
206
+ for (const { path: packagePath, dir: packageDir } of packages) {
207
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
208
+ const packageName = packageJson.name;
209
+
210
+ if (!packageName || !packageName.startsWith('@kb-labs/')) {continue;}
211
+
212
+ const typesStatus = checkTypesGeneration(packageDir);
213
+
214
+ graph.set(packageName, {
215
+ typeDeps: new Set(),
216
+ generates: typesStatus.generates,
217
+ reason: typesStatus.reason,
218
+ dir: packageDir,
219
+ });
220
+ }
221
+
222
+ // Second pass: extract type imports
223
+ for (const { path: packagePath, dir: packageDir } of packages) {
224
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf-8'));
225
+ const packageName = packageJson.name;
226
+
227
+ if (!packageName || !packageName.startsWith('@kb-labs/')) {continue;}
228
+
229
+ const typeImports = extractTypeImports(packageDir);
230
+
231
+ for (const dep of typeImports) {
232
+ // Only track workspace type dependencies
233
+ if (dep.startsWith('@kb-labs/') && graph.has(dep)) {
234
+ graph.get(packageName).typeDeps.add(dep);
235
+ }
236
+ }
237
+ }
238
+
239
+ return graph;
240
+ }
241
+
242
+ /**
243
+ * Topological sort for types
244
+ */
245
+ function topologicalSort(graph) {
246
+ const inDegree = new Map();
247
+ const reverseDeps = new Map();
248
+
249
+ for (const [pkg, { typeDeps }] of graph.entries()) {
250
+ if (!inDegree.has(pkg)) {
251
+ inDegree.set(pkg, 0);
252
+ }
253
+ if (!reverseDeps.has(pkg)) {
254
+ reverseDeps.set(pkg, new Set());
255
+ }
256
+
257
+ for (const dep of typeDeps) {
258
+ inDegree.set(pkg, (inDegree.get(pkg) || 0) + 1);
259
+
260
+ if (!reverseDeps.has(dep)) {
261
+ reverseDeps.set(dep, new Set());
262
+ }
263
+ reverseDeps.get(dep).add(pkg);
264
+ }
265
+ }
266
+
267
+ const queue = [];
268
+ for (const [pkg, degree] of inDegree.entries()) {
269
+ if (degree === 0) {
270
+ queue.push(pkg);
271
+ }
272
+ }
273
+
274
+ const layers = [];
275
+ const sorted = [];
276
+
277
+ while (queue.length > 0) {
278
+ const layer = [...queue];
279
+ layers.push(layer);
280
+ sorted.push(...layer);
281
+
282
+ queue.length = 0;
283
+
284
+ for (const pkg of layer) {
285
+ for (const dependent of reverseDeps.get(pkg) || []) {
286
+ inDegree.set(dependent, inDegree.get(dependent) - 1);
287
+
288
+ if (inDegree.get(dependent) === 0) {
289
+ queue.push(dependent);
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ if (sorted.length !== graph.size) {
296
+ const missing = Array.from(graph.keys()).filter((pkg) => !sorted.includes(pkg));
297
+ return { layers, sorted, circular: missing };
298
+ }
299
+
300
+ return { layers, sorted, circular: [] };
301
+ }
302
+
303
+ /**
304
+ * Find broken type chains
305
+ * A chain is broken if:
306
+ * 1. Package A imports types from Package B
307
+ * 2. Package B doesn't generate types (dts: false)
308
+ */
309
+ function findBrokenChains(graph) {
310
+ const broken = [];
311
+
312
+ for (const [pkg, { typeDeps }] of graph.entries()) {
313
+ for (const dep of typeDeps) {
314
+ const depNode = graph.get(dep);
315
+
316
+ if (!depNode.generates) {
317
+ broken.push({
318
+ consumer: pkg,
319
+ provider: dep,
320
+ reason: depNode.reason,
321
+ });
322
+ }
323
+ }
324
+ }
325
+
326
+ return broken;
327
+ }
328
+
329
+ /**
330
+ * Find circular type dependencies
331
+ */
332
+ function findCircularTypeDependencies(graph, circularPackages) {
333
+ const cycles = [];
334
+ const visited = new Set();
335
+ const recursionStack = new Set();
336
+ const path = [];
337
+
338
+ function dfs(pkg) {
339
+ if (recursionStack.has(pkg)) {
340
+ const cycleStart = path.indexOf(pkg);
341
+ const cycle = [...path.slice(cycleStart), pkg];
342
+
343
+ const cycleKey = cycle.slice(0, -1).sort().join('→');
344
+ if (!cycles.some((c) => c.key === cycleKey)) {
345
+ cycles.push({ cycle, key: cycleKey });
346
+ }
347
+ return;
348
+ }
349
+
350
+ if (visited.has(pkg)) {
351
+ return;
352
+ }
353
+
354
+ visited.add(pkg);
355
+ recursionStack.add(pkg);
356
+ path.push(pkg);
357
+
358
+ const node = graph.get(pkg);
359
+ if (node) {
360
+ for (const dep of node.typeDeps) {
361
+ if (circularPackages.includes(dep)) {
362
+ dfs(dep);
363
+ }
364
+ }
365
+ }
366
+
367
+ path.pop();
368
+ recursionStack.delete(pkg);
369
+ }
370
+
371
+ for (const pkg of circularPackages) {
372
+ if (!visited.has(pkg)) {
373
+ dfs(pkg);
374
+ }
375
+ }
376
+
377
+ return cycles;
378
+ }
379
+
380
+ /**
381
+ * Get types order for specific package
382
+ */
383
+ function getTypesOrderForPackage(graph, packageName) {
384
+ const visited = new Set();
385
+ const order = [];
386
+
387
+ function visit(pkg) {
388
+ if (visited.has(pkg)) {return;}
389
+ visited.add(pkg);
390
+
391
+ const node = graph.get(pkg);
392
+ if (!node) {return;}
393
+
394
+ for (const dep of node.typeDeps) {
395
+ visit(dep);
396
+ }
397
+
398
+ order.push(pkg);
399
+ }
400
+
401
+ visit(packageName);
402
+ return order;
403
+ }
404
+
405
+ /**
406
+ * Print types order
407
+ */
408
+ function printTypesOrder(result, graph) {
409
+ log('\nšŸ“˜ KB Labs TypeScript Types Order\n', 'bold');
410
+
411
+ // Check for broken chains first
412
+ const brokenChains = findBrokenChains(graph);
413
+
414
+ if (brokenChains.length > 0) {
415
+ log(`āŒ Broken Type Chains: ${brokenChains.length}\n`, 'red');
416
+
417
+ for (const { consumer, provider, reason } of brokenChains) {
418
+ log(` ${consumer}`, 'yellow');
419
+ log(` └─ imports types from: ${provider}`, 'gray');
420
+ log(` └─ āŒ ${provider} doesn't generate types: ${reason}`, 'red');
421
+ log('', 'reset');
422
+ }
423
+
424
+ log('šŸ’” Fix with: npx kb-devkit-check-types --fix\n', 'cyan');
425
+ }
426
+
427
+ if (result.circular.length > 0) {
428
+ log('šŸ”„ Circular Type Dependencies\n', 'yellow');
429
+
430
+ const cycles = findCircularTypeDependencies(graph, result.circular);
431
+
432
+ if (cycles.length > 0) {
433
+ log(`Found ${cycles.length} circular type dependency cycle(s):\n`, 'yellow');
434
+
435
+ for (let i = 0; i < cycles.length; i++) {
436
+ const { cycle } = cycles[i];
437
+ log(`${i + 1}. ${cycle.join(' → ')}`, 'red');
438
+ log('', 'reset');
439
+ }
440
+ }
441
+
442
+ log('šŸ’” To fix: Break the cycle by extracting shared types into a separate package\n', 'cyan');
443
+ }
444
+
445
+ if (brokenChains.length === 0 && result.circular.length === 0) {
446
+ log(`āœ… All type chains are healthy!\n`, 'green');
447
+ }
448
+
449
+ log(`Found ${result.sorted.length} packages with TypeScript\n`, 'gray');
450
+
451
+ if (options.layers) {
452
+ log('šŸ“¦ Types Generation Layers (parallel):\n', 'blue');
453
+
454
+ for (let i = 0; i < result.layers.length; i++) {
455
+ const layer = result.layers[i];
456
+ log(`Layer ${i + 1} (${layer.length} packages):`, 'cyan');
457
+
458
+ for (const pkg of layer) {
459
+ const node = graph.get(pkg);
460
+ const status = node.generates ? 'āœ…' : 'āŒ';
461
+ log(` ${status} ${pkg}`, node.generates ? 'gray' : 'red');
462
+
463
+ if (options.verbose && node.typeDeps.size > 0) {
464
+ log(` type deps: ${Array.from(node.typeDeps).join(', ')}`, 'gray');
465
+ }
466
+ }
467
+ log('', 'reset');
468
+ }
469
+
470
+ log(`Total layers: ${result.layers.length}`, 'blue');
471
+ log(`Max parallelism: ${Math.max(...result.layers.map((l) => l.length))} packages\n`, 'blue');
472
+ } else {
473
+ log('šŸ“¦ Types Generation Order (sequential):\n', 'blue');
474
+
475
+ for (let i = 0; i < result.sorted.length; i++) {
476
+ const pkg = result.sorted[i];
477
+ const node = graph.get(pkg);
478
+ const status = node.generates ? 'āœ…' : 'āŒ';
479
+
480
+ log(`${(i + 1).toString().padStart(3)}. ${status} ${pkg}`, node.generates ? 'cyan' : 'red');
481
+
482
+ if (options.verbose && node.typeDeps.size > 0) {
483
+ log(` type deps: ${Array.from(node.typeDeps).join(', ')}`, 'gray');
484
+ }
485
+ }
486
+ log('', 'reset');
487
+ }
488
+
489
+ // Summary
490
+ log('─'.repeat(60) + '\n', 'gray');
491
+ log('šŸ“Š Summary:\n', 'blue');
492
+
493
+ const generating = Array.from(graph.values()).filter((n) => n.generates).length;
494
+ const notGenerating = graph.size - generating;
495
+
496
+ log(` Total packages: ${graph.size}`, 'cyan');
497
+ log(` āœ… Generating types: ${generating}`, 'green');
498
+ if (notGenerating > 0) {
499
+ log(` āŒ Not generating: ${notGenerating}`, 'red');
500
+ }
501
+ if (brokenChains.length > 0) {
502
+ log(` šŸ”“ Broken chains: ${brokenChains.length}`, 'red');
503
+ }
504
+ if (result.circular.length > 0) {
505
+ log(` šŸ”„ Circular deps: ${result.circular.length}`, 'yellow');
506
+ }
507
+
508
+ log('', 'reset');
509
+
510
+ // Tips
511
+ log('šŸ’” Tips:', 'blue');
512
+ log(' • Use --broken to show only broken type chains', 'gray');
513
+ log(' • Use --layers to see parallel generation opportunities', 'gray');
514
+ log(' • Use npx kb-devkit-check-types --fix to fix dts: false', 'gray');
515
+ log('', 'reset');
516
+ }
517
+
518
+ /**
519
+ * Main function
520
+ */
521
+ function main() {
522
+ const rootDir = process.cwd();
523
+
524
+ if (!options.json) {
525
+ log('\nšŸš€ KB Labs TypeScript Types Order Calculator\n', 'bold');
526
+ }
527
+
528
+ const packages = findPackages(rootDir);
529
+
530
+ if (packages.length === 0) {
531
+ log('āš ļø No KB Labs packages found', 'yellow');
532
+ process.exit(0);
533
+ }
534
+
535
+ const graph = buildTypesDependencyGraph(packages);
536
+
537
+ if (options.broken) {
538
+ // Only show broken chains
539
+ const brokenChains = findBrokenChains(graph);
540
+
541
+ if (options.json) {
542
+ console.log(JSON.stringify({ brokenChains }, null, 2));
543
+ } else {
544
+ log('\nāŒ Broken Type Chains\n', 'red');
545
+
546
+ if (brokenChains.length === 0) {
547
+ log('āœ… No broken type chains found!\n', 'green');
548
+ } else {
549
+ for (const { consumer, provider, reason } of brokenChains) {
550
+ log(` ${consumer}`, 'yellow');
551
+ log(` └─ imports types from: ${provider}`, 'gray');
552
+ log(` └─ āŒ ${provider} doesn't generate types: ${reason}`, 'red');
553
+ log('', 'reset');
554
+ }
555
+
556
+ log(`\nTotal broken chains: ${brokenChains.length}`, 'red');
557
+ log('šŸ’” Fix with: npx kb-devkit-check-types --fix\n', 'cyan');
558
+ }
559
+ }
560
+
561
+ process.exit(brokenChains.length > 0 ? 1 : 0);
562
+ }
563
+
564
+ if (options.package) {
565
+ // Types order for specific package
566
+ const fullPackageName = options.package.startsWith('@kb-labs/')
567
+ ? options.package
568
+ : `@kb-labs/${options.package}`;
569
+
570
+ if (!graph.has(fullPackageName)) {
571
+ log(`āš ļø Package not found: ${fullPackageName}`, 'yellow');
572
+ log('\nAvailable packages:', 'gray');
573
+ for (const pkg of Array.from(graph.keys()).sort()) {
574
+ log(` ${pkg}`, 'gray');
575
+ }
576
+ process.exit(1);
577
+ }
578
+
579
+ const order = getTypesOrderForPackage(graph, fullPackageName);
580
+
581
+ if (options.json) {
582
+ console.log(JSON.stringify({ package: fullPackageName, order }, null, 2));
583
+ } else {
584
+ log(`\nšŸ“˜ Types generation order for ${fullPackageName}:\n`, 'blue');
585
+
586
+ for (let i = 0; i < order.length; i++) {
587
+ const pkg = order[i];
588
+ const node = graph.get(pkg);
589
+ const isCurrent = pkg === fullPackageName;
590
+ const status = node.generates ? 'āœ…' : 'āŒ';
591
+
592
+ log(
593
+ `${(i + 1).toString().padStart(3)}. ${status} ${pkg}${isCurrent ? ' ⬅ target' : ''}`,
594
+ isCurrent ? 'yellow' : node.generates ? 'gray' : 'red'
595
+ );
596
+ }
597
+ log('', 'reset');
598
+ }
599
+ }
600
+
601
+ // Full types order
602
+ const result = topologicalSort(graph);
603
+ const brokenChains = findBrokenChains(graph);
604
+
605
+ if (!options.package && !options.broken) {
606
+ if (options.json) {
607
+ const output = {
608
+ total: graph.size,
609
+ layers: result.layers,
610
+ sorted: result.sorted,
611
+ circular: result.circular,
612
+ brokenChains,
613
+ stats: {
614
+ generating: Array.from(graph.values()).filter((n) => n.generates).length,
615
+ notGenerating: Array.from(graph.values()).filter((n) => !n.generates).length,
616
+ brokenChains: brokenChains.length,
617
+ },
618
+ };
619
+
620
+ if (result.circular.length > 0) {
621
+ const cycles = findCircularTypeDependencies(graph, result.circular);
622
+ output.cycles = cycles.map((c) => c.cycle);
623
+ }
624
+
625
+ console.log(JSON.stringify(output, null, 2));
626
+ } else {
627
+ printTypesOrder(result, graph);
628
+ }
629
+ }
630
+
631
+ // Exit with error if there are broken chains or circular deps
632
+ const hasIssues = brokenChains.length > 0 || result.circular.length > 0;
633
+
634
+ process.exit(hasIssues ? 1 : 0);
635
+ }
636
+
637
+ main();