@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,495 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - Package Structure Checker
5
+ *
6
+ * Checks for:
7
+ * 1. Missing README.md files
8
+ * 2. Missing LICENSE files
9
+ * 3. Required package.json fields (name, version, main, types, exports)
10
+ * 4. Architecture violations (e.g., domain importing from infra)
11
+ * 5. Inconsistent project structure
12
+ *
13
+ * Usage:
14
+ * kb-devkit-check-structure # Check all packages
15
+ * kb-devkit-check-structure --package cli-core # Check specific package
16
+ * kb-devkit-check-structure --strict # Include warnings
17
+ */
18
+
19
+ import fs from 'node:fs';
20
+ import path from 'node:path';
21
+ import { fileURLToPath } from 'node:url';
22
+
23
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
24
+
25
+ // ANSI colors
26
+ const colors = {
27
+ reset: '\x1b[0m',
28
+ red: '\x1b[31m',
29
+ green: '\x1b[32m',
30
+ yellow: '\x1b[33m',
31
+ blue: '\x1b[34m',
32
+ magenta: '\x1b[35m',
33
+ cyan: '\x1b[36m',
34
+ gray: '\x1b[90m',
35
+ };
36
+
37
+ function log(message, color = 'reset') {
38
+ console.log(`${colors[color]}${message}${colors.reset}`);
39
+ }
40
+
41
+ // Parse CLI arguments
42
+ const args = process.argv.slice(2);
43
+ const options = {
44
+ package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
45
+ strict: args.includes('--strict'),
46
+ verbose: args.includes('--verbose') || args.includes('-v'),
47
+ };
48
+
49
+ /**
50
+ * Required package.json fields
51
+ */
52
+ const REQUIRED_FIELDS = {
53
+ critical: ['name', 'version', 'type'],
54
+ important: ['description', 'main', 'types'],
55
+ recommended: ['exports', 'files', 'scripts', 'engines'],
56
+ };
57
+
58
+ /**
59
+ * Required files in package directory
60
+ */
61
+ const REQUIRED_FILES = {
62
+ critical: ['package.json', 'src'],
63
+ important: ['README.md', 'tsconfig.json'],
64
+ recommended: ['LICENSE', '.gitignore'],
65
+ };
66
+
67
+ /**
68
+ * Check package structure
69
+ */
70
+ function checkPackage(packageJsonPath) {
71
+ const packageDir = path.dirname(packageJsonPath);
72
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
73
+ const packageName = packageJson.name;
74
+
75
+ if (!packageName || !packageName.startsWith('@kb-labs/')) {
76
+ return null; // Skip non-KB Labs packages
77
+ }
78
+
79
+ const issues = {
80
+ missingFiles: [],
81
+ missingFields: [],
82
+ structureIssues: [],
83
+ warnings: [],
84
+ };
85
+
86
+ // Check required files
87
+ for (const level of ['critical', 'important']) {
88
+ for (const file of REQUIRED_FILES[level]) {
89
+ const filePath = path.join(packageDir, file);
90
+ const exists = fs.existsSync(filePath);
91
+
92
+ if (!exists) {
93
+ issues.missingFiles.push({
94
+ file,
95
+ level,
96
+ severity: level === 'critical' ? 'error' : 'warning',
97
+ });
98
+ }
99
+ }
100
+ }
101
+
102
+ if (options.strict) {
103
+ for (const file of REQUIRED_FILES.recommended) {
104
+ const filePath = path.join(packageDir, file);
105
+ if (!fs.existsSync(filePath)) {
106
+ issues.missingFiles.push({
107
+ file,
108
+ level: 'recommended',
109
+ severity: 'info',
110
+ });
111
+ }
112
+ }
113
+ }
114
+
115
+ // Check required package.json fields
116
+ for (const level of ['critical', 'important']) {
117
+ for (const field of REQUIRED_FIELDS[level]) {
118
+ if (!packageJson[field]) {
119
+ issues.missingFields.push({
120
+ field,
121
+ level,
122
+ severity: level === 'critical' ? 'error' : 'warning',
123
+ });
124
+ }
125
+ }
126
+ }
127
+
128
+ if (options.strict) {
129
+ for (const field of REQUIRED_FIELDS.recommended) {
130
+ if (!packageJson[field]) {
131
+ issues.missingFields.push({
132
+ field,
133
+ level: 'recommended',
134
+ severity: 'info',
135
+ });
136
+ }
137
+ }
138
+ }
139
+
140
+ // Check README.md content quality
141
+ const readmePath = path.join(packageDir, 'README.md');
142
+ if (fs.existsSync(readmePath)) {
143
+ const readmeContent = fs.readFileSync(readmePath, 'utf-8');
144
+ const readmeLength = readmeContent.length;
145
+
146
+ if (readmeLength < 200) {
147
+ issues.warnings.push({
148
+ type: 'readme-too-short',
149
+ message: `README.md is very short (${readmeLength} chars)`,
150
+ suggestion: 'Add documentation about purpose, usage, and API',
151
+ });
152
+ }
153
+
154
+ // Check for common sections
155
+ const hasSections = {
156
+ install: /##\s+(Installation|Install|Setup)/i.test(readmeContent),
157
+ usage: /##\s+(Usage|Getting Started|Quick Start)/i.test(readmeContent),
158
+ api: /##\s+(API|Reference|Documentation)/i.test(readmeContent),
159
+ };
160
+
161
+ if (!hasSections.usage && options.strict) {
162
+ issues.warnings.push({
163
+ type: 'readme-missing-usage',
164
+ message: 'README.md missing "Usage" section',
165
+ suggestion: 'Add usage examples and getting started guide',
166
+ });
167
+ }
168
+ }
169
+
170
+ // Check for consistent source structure
171
+ const srcDir = path.join(packageDir, 'src');
172
+ if (fs.existsSync(srcDir)) {
173
+ const srcFiles = fs.readdirSync(srcDir);
174
+ const hasIndex = srcFiles.some((f) => /^index\.(ts|tsx|js|jsx)$/.test(f));
175
+
176
+ if (!hasIndex) {
177
+ issues.structureIssues.push({
178
+ type: 'missing-index',
179
+ message: 'No index file in src/ directory',
180
+ suggestion: 'Create src/index.ts as main entry point',
181
+ severity: 'warning',
182
+ });
183
+ }
184
+
185
+ // Check for test files in src/ (should be in tests/ or __tests__)
186
+ const hasTestsInSrc = srcFiles.some(
187
+ (f) => f.includes('.test.') || f.includes('.spec.') || f === '__tests__'
188
+ );
189
+
190
+ if (hasTestsInSrc && options.strict) {
191
+ issues.warnings.push({
192
+ type: 'tests-in-src',
193
+ message: 'Test files found in src/ directory',
194
+ suggestion: 'Consider moving tests to separate tests/ directory',
195
+ });
196
+ }
197
+ }
198
+
199
+ // Check package.json scripts
200
+ if (packageJson.scripts) {
201
+ const hasRequiredScripts = {
202
+ build: !!packageJson.scripts.build,
203
+ test: !!packageJson.scripts.test,
204
+ lint: !!packageJson.scripts.lint,
205
+ };
206
+
207
+ if (!hasRequiredScripts.build) {
208
+ issues.structureIssues.push({
209
+ type: 'missing-build-script',
210
+ message: 'No "build" script in package.json',
211
+ suggestion: 'Add "build": "tsup" to scripts',
212
+ severity: 'warning',
213
+ });
214
+ }
215
+ }
216
+
217
+ // Check TypeScript configuration
218
+ const tsconfigPath = path.join(packageDir, 'tsconfig.json');
219
+ if (fs.existsSync(tsconfigPath)) {
220
+ try {
221
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
222
+
223
+ // Check if it extends devkit preset
224
+ if (tsconfig.extends && !tsconfig.extends.includes('@kb-labs/devkit')) {
225
+ issues.warnings.push({
226
+ type: 'tsconfig-not-using-devkit',
227
+ message: 'tsconfig.json not extending @kb-labs/devkit preset',
228
+ suggestion: 'Use "@kb-labs/devkit/tsconfig/node.json" for consistency',
229
+ });
230
+ }
231
+ } catch (err) {
232
+ issues.structureIssues.push({
233
+ type: 'invalid-tsconfig',
234
+ message: 'tsconfig.json has invalid JSON',
235
+ suggestion: 'Fix JSON syntax errors',
236
+ severity: 'error',
237
+ });
238
+ }
239
+ }
240
+
241
+ // Check exports field consistency
242
+ if (packageJson.exports) {
243
+ const mainExport = packageJson.exports['.'];
244
+
245
+ if (!mainExport) {
246
+ issues.structureIssues.push({
247
+ type: 'exports-missing-main',
248
+ message: 'package.json exports field missing "." entry',
249
+ suggestion: 'Add main export: { ".": "./dist/index.js" }',
250
+ severity: 'error',
251
+ });
252
+ }
253
+ }
254
+
255
+ // Check for .npmignore or files field
256
+ const hasNpmignore = fs.existsSync(path.join(packageDir, '.npmignore'));
257
+ const hasFilesField = !!packageJson.files;
258
+
259
+ if (!hasNpmignore && !hasFilesField && !packageJson.private) {
260
+ issues.warnings.push({
261
+ type: 'no-publish-config',
262
+ message: 'No .npmignore or "files" field (will publish everything)',
263
+ suggestion: 'Add "files": ["dist", "README.md", "LICENSE"] to package.json',
264
+ });
265
+ }
266
+
267
+ return {
268
+ packageName,
269
+ packageDir,
270
+ packageJsonPath,
271
+ ...issues,
272
+ };
273
+ }
274
+
275
+ /**
276
+ * Find all packages in monorepo
277
+ */
278
+ function findPackages(rootDir, filterPackage) {
279
+ const packages = [];
280
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
281
+
282
+ for (const entry of entries) {
283
+ if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
284
+
285
+ const repoPath = path.join(rootDir, entry.name);
286
+ const packagesDir = path.join(repoPath, 'packages');
287
+
288
+ if (!fs.existsSync(packagesDir)) {continue;}
289
+
290
+ const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
291
+
292
+ for (const pkgDir of packageDirs) {
293
+ if (!pkgDir.isDirectory()) {continue;}
294
+
295
+ // Filter by package name if specified
296
+ if (filterPackage && pkgDir.name !== filterPackage) {continue;}
297
+
298
+ const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
299
+
300
+ if (fs.existsSync(packageJsonPath)) {
301
+ packages.push(packageJsonPath);
302
+ }
303
+ }
304
+ }
305
+
306
+ return packages;
307
+ }
308
+
309
+ /**
310
+ * Main function
311
+ */
312
+ function main() {
313
+ const rootDir = process.cwd();
314
+
315
+ log('\nšŸ“ KB Labs Structure Checker\n', 'blue');
316
+
317
+ if (options.package) {
318
+ log(`Checking package: ${options.package}\n`, 'gray');
319
+ } else {
320
+ log('Checking all packages...\n', 'gray');
321
+ }
322
+
323
+ if (options.strict) {
324
+ log('āš ļø Strict mode enabled (includes recommendations)\n', 'yellow');
325
+ }
326
+
327
+ const packages = findPackages(rootDir, options.package);
328
+
329
+ if (packages.length === 0) {
330
+ log('āš ļø No KB Labs packages found', 'yellow');
331
+ log(' Run this command from the monorepo root\n', 'gray');
332
+ process.exit(0);
333
+ }
334
+
335
+ log(`Found ${packages.length} package(s) to check\n`, 'gray');
336
+
337
+ const results = [];
338
+
339
+ // Check each package
340
+ for (const packagePath of packages) {
341
+ const result = checkPackage(packagePath);
342
+ if (result) {
343
+ results.push(result);
344
+ }
345
+ }
346
+
347
+ // Print results
348
+ let hasIssues = false;
349
+ let hasErrors = false;
350
+
351
+ for (const result of results) {
352
+ const errorCount = [
353
+ ...result.missingFiles.filter((f) => f.severity === 'error'),
354
+ ...result.missingFields.filter((f) => f.severity === 'error'),
355
+ ...result.structureIssues.filter((i) => i.severity === 'error'),
356
+ ].length;
357
+
358
+ const warningCount = [
359
+ ...result.missingFiles.filter((f) => f.severity === 'warning'),
360
+ ...result.missingFields.filter((f) => f.severity === 'warning'),
361
+ ...result.structureIssues.filter((i) => i.severity === 'warning'),
362
+ ...result.warnings,
363
+ ].length;
364
+
365
+ const issueCount = errorCount + warningCount;
366
+
367
+ if (issueCount === 0 && !options.verbose) {continue;}
368
+
369
+ hasIssues = issueCount > 0;
370
+ hasErrors = hasErrors || errorCount > 0;
371
+
372
+ if (errorCount > 0) {
373
+ log(`\nāŒ ${result.packageName}`, 'red');
374
+ } else if (warningCount > 0) {
375
+ log(`\nāš ļø ${result.packageName}`, 'yellow');
376
+ } else if (options.verbose) {
377
+ log(`\nāœ… ${result.packageName}`, 'green');
378
+ }
379
+
380
+ log(` ${path.relative(rootDir, result.packageDir)}`, 'gray');
381
+
382
+ // Missing files
383
+ const criticalFiles = result.missingFiles.filter((f) => f.severity === 'error');
384
+ if (criticalFiles.length > 0) {
385
+ log(`\n šŸ”“ Missing critical files (${criticalFiles.length}):`, 'red');
386
+ for (const file of criticalFiles) {
387
+ log(` ${file.file}`, 'yellow');
388
+ }
389
+ }
390
+
391
+ const warningFiles = result.missingFiles.filter((f) => f.severity === 'warning');
392
+ if (warningFiles.length > 0) {
393
+ log(`\n 🟔 Missing important files (${warningFiles.length}):`, 'yellow');
394
+ for (const file of warningFiles) {
395
+ log(` ${file.file}`, 'gray');
396
+ }
397
+ }
398
+
399
+ // Missing fields
400
+ const criticalFields = result.missingFields.filter((f) => f.severity === 'error');
401
+ if (criticalFields.length > 0) {
402
+ log(`\n šŸ”“ Missing critical fields (${criticalFields.length}):`, 'red');
403
+ for (const field of criticalFields) {
404
+ log(` ${field.field}`, 'yellow');
405
+ }
406
+ }
407
+
408
+ const warningFields = result.missingFields.filter((f) => f.severity === 'warning');
409
+ if (warningFields.length > 0) {
410
+ log(`\n 🟔 Missing important fields (${warningFields.length}):`, 'yellow');
411
+ for (const field of warningFields) {
412
+ log(` ${field.field}`, 'gray');
413
+ }
414
+ }
415
+
416
+ // Structure issues
417
+ if (result.structureIssues.length > 0) {
418
+ const errors = result.structureIssues.filter((i) => i.severity === 'error');
419
+ const warnings = result.structureIssues.filter((i) => i.severity === 'warning');
420
+
421
+ if (errors.length > 0) {
422
+ log(`\n šŸ”“ Structure errors (${errors.length}):`, 'red');
423
+ for (const issue of errors) {
424
+ log(` ${issue.message}`, 'yellow');
425
+ log(` šŸ’” ${issue.suggestion}`, 'blue');
426
+ }
427
+ }
428
+
429
+ if (warnings.length > 0) {
430
+ log(`\n 🟔 Structure warnings (${warnings.length}):`, 'yellow');
431
+ for (const issue of warnings) {
432
+ log(` ${issue.message}`, 'gray');
433
+ log(` šŸ’” ${issue.suggestion}`, 'blue');
434
+ }
435
+ }
436
+ }
437
+
438
+ // Other warnings
439
+ if (result.warnings.length > 0 && options.strict) {
440
+ log(`\n ā„¹ļø Recommendations (${result.warnings.length}):`, 'cyan');
441
+ for (const warning of result.warnings) {
442
+ log(` ${warning.message}`, 'gray');
443
+ if (warning.suggestion) {
444
+ log(` šŸ’” ${warning.suggestion}`, 'blue');
445
+ }
446
+ }
447
+ }
448
+ }
449
+
450
+ // Summary
451
+ log('\n' + '─'.repeat(60) + '\n', 'gray');
452
+
453
+ if (!hasIssues) {
454
+ log('āœ… All packages have proper structure!\n', 'green');
455
+ process.exit(0);
456
+ }
457
+
458
+ log('šŸ“Š Summary:\n', 'blue');
459
+
460
+ const totalErrors = results.reduce(
461
+ (sum, r) =>
462
+ sum +
463
+ r.missingFiles.filter((f) => f.severity === 'error').length +
464
+ r.missingFields.filter((f) => f.severity === 'error').length +
465
+ r.structureIssues.filter((i) => i.severity === 'error').length,
466
+ 0
467
+ );
468
+
469
+ const totalWarnings = results.reduce(
470
+ (sum, r) =>
471
+ sum +
472
+ r.missingFiles.filter((f) => f.severity === 'warning').length +
473
+ r.missingFields.filter((f) => f.severity === 'warning').length +
474
+ r.structureIssues.filter((i) => i.severity === 'warning').length +
475
+ r.warnings.length,
476
+ 0
477
+ );
478
+
479
+ if (totalErrors > 0) {
480
+ log(` šŸ”“ ${totalErrors} error(s)`, 'red');
481
+ }
482
+ if (totalWarnings > 0) {
483
+ log(` 🟔 ${totalWarnings} warning(s)`, 'yellow');
484
+ }
485
+
486
+ log('\nšŸ’” Tips:', 'blue');
487
+ log(' • Use --verbose to see all packages (including clean ones)', 'gray');
488
+ log(' • Use --package=<name> to check a specific package', 'gray');
489
+ log(' • Use --strict to include recommendations', 'gray');
490
+ log('');
491
+
492
+ process.exit(hasErrors ? 1 : 0);
493
+ }
494
+
495
+ main();