@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,532 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - Deprecated Code Checker
5
+ *
6
+ * Finds all @deprecated markers in the codebase with context:
7
+ * - JSDoc @deprecated tags
8
+ * - TypeScript @deprecated decorator patterns
9
+ * - Inline // @deprecated comments
10
+ *
11
+ * Provides:
12
+ * - Location and context for each deprecated item
13
+ * - Grouping by package
14
+ * - Statistics and summary
15
+ * - Multiple output formats (table, JSON, markdown)
16
+ *
17
+ * Usage:
18
+ * kb-devkit-check-deprecated # Check all packages
19
+ * kb-devkit-check-deprecated --package cli-core # Check specific package
20
+ * kb-devkit-check-deprecated --json # JSON output for AI/CI
21
+ * kb-devkit-check-deprecated --md # Markdown output
22
+ * kb-devkit-check-deprecated --stats # Show statistics only
23
+ * kb-devkit-check-deprecated --verbose # Show full context
24
+ */
25
+
26
+ import fs from 'node:fs';
27
+ import path from 'node:path';
28
+ import { fileURLToPath } from 'node:url';
29
+
30
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
31
+
32
+ // ANSI colors
33
+ const colors = {
34
+ reset: '\x1b[0m',
35
+ red: '\x1b[31m',
36
+ green: '\x1b[32m',
37
+ yellow: '\x1b[33m',
38
+ blue: '\x1b[34m',
39
+ magenta: '\x1b[35m',
40
+ cyan: '\x1b[36m',
41
+ gray: '\x1b[90m',
42
+ bold: '\x1b[1m',
43
+ };
44
+
45
+ function log(message, color = 'reset') {
46
+ if (!options.json && !options.md) {
47
+ console.log(`${colors[color]}${message}${colors.reset}`);
48
+ }
49
+ }
50
+
51
+ // Parse CLI arguments
52
+ const args = process.argv.slice(2);
53
+ const options = {
54
+ package: args.find((arg) => arg.startsWith('--package='))?.split('=')[1],
55
+ json: args.includes('--json'),
56
+ md: args.includes('--md'),
57
+ stats: args.includes('--stats'),
58
+ verbose: args.includes('--verbose') || args.includes('-v'),
59
+ help: args.includes('--help') || args.includes('-h'),
60
+ };
61
+
62
+ if (options.help) {
63
+ console.log(`
64
+ @kb-labs/devkit - Deprecated Code Checker
65
+
66
+ Finds all @deprecated markers in the codebase.
67
+
68
+ Usage:
69
+ kb-devkit-check-deprecated # Check all packages
70
+ kb-devkit-check-deprecated --package=cli-core # Check specific package
71
+ kb-devkit-check-deprecated --json # JSON output for AI/CI
72
+ kb-devkit-check-deprecated --md # Markdown output
73
+ kb-devkit-check-deprecated --stats # Show statistics only
74
+ kb-devkit-check-deprecated --verbose # Show full context
75
+
76
+ Options:
77
+ --package=NAME Check only specific package
78
+ --json Output as JSON (for CI/AI agents)
79
+ --md Output as Markdown table
80
+ --stats Show statistics summary only
81
+ --verbose, -v Show full context around deprecated items
82
+ --help, -h Show this help message
83
+ `);
84
+ process.exit(0);
85
+ }
86
+
87
+ /**
88
+ * Find all kb-labs-* packages
89
+ */
90
+ function findPackages(rootDir, filterPackage) {
91
+ const packages = [];
92
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
93
+
94
+ for (const entry of entries) {
95
+ if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
96
+
97
+ const repoPath = path.join(rootDir, entry.name);
98
+ const packagesDir = path.join(repoPath, 'packages');
99
+
100
+ if (!fs.existsSync(packagesDir)) {continue;}
101
+
102
+ const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
103
+
104
+ for (const pkgDir of packageDirs) {
105
+ if (!pkgDir.isDirectory()) {continue;}
106
+
107
+ if (filterPackage && pkgDir.name !== filterPackage) {continue;}
108
+
109
+ const packageJsonPath = path.join(packagesDir, pkgDir.name, 'package.json');
110
+ const srcDir = path.join(packagesDir, pkgDir.name, 'src');
111
+
112
+ if (fs.existsSync(packageJsonPath) && fs.existsSync(srcDir)) {
113
+ try {
114
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
115
+ packages.push({
116
+ name: packageJson.name,
117
+ shortName: pkgDir.name,
118
+ repo: entry.name,
119
+ path: path.join(packagesDir, pkgDir.name),
120
+ srcPath: srcDir,
121
+ });
122
+ } catch {
123
+ // Skip invalid package.json
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ return packages;
130
+ }
131
+
132
+ /**
133
+ * Recursively find all TypeScript/JavaScript files
134
+ */
135
+ function findSourceFiles(dir) {
136
+ const files = [];
137
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
138
+
139
+ for (const entry of entries) {
140
+ const fullPath = path.join(dir, entry.name);
141
+
142
+ if (entry.isDirectory()) {
143
+ // Skip node_modules and dist
144
+ if (entry.name === 'node_modules' || entry.name === 'dist') {continue;}
145
+ files.push(...findSourceFiles(fullPath));
146
+ } else if (/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(entry.name)) {
147
+ files.push(fullPath);
148
+ }
149
+ }
150
+
151
+ return files;
152
+ }
153
+
154
+ /**
155
+ * Extract deprecated items from file content
156
+ */
157
+ function extractDeprecated(filePath, content) {
158
+ const deprecated = [];
159
+ const lines = content.split('\n');
160
+
161
+ // Only match JSDoc @deprecated - this is the standard way in TypeScript/JavaScript
162
+ // Pattern: /** ... @deprecated ... */
163
+ const jsdocPattern = /\/\*\*[\s\S]*?@deprecated\s*([^\n*]*)?[\s\S]*?\*\//g;
164
+
165
+ let match;
166
+ while ((match = jsdocPattern.exec(content)) !== null) {
167
+ // Skip if @deprecated is inside a regex literal or string (e.g., /@deprecated/i)
168
+ const jsdocContent = match[0];
169
+ if (/\/@deprecated\//.test(jsdocContent) || /['"`].*@deprecated.*['"`]/.test(jsdocContent)) {
170
+ continue;
171
+ }
172
+ const startIndex = match.index;
173
+ const endIndex = match.index + match[0].length;
174
+ const lineNumber = content.substring(0, startIndex).split('\n').length;
175
+ const endLine = content.substring(0, endIndex).split('\n').length;
176
+
177
+ // Extract reason from @deprecated line
178
+ const deprecatedLineMatch = match[0].match(/@deprecated\s*([^\n*]*)/);
179
+ const reason = (deprecatedLineMatch?.[1] || '').trim();
180
+
181
+ // Get context: the code AFTER the JSDoc comment
182
+ const contextLines = [];
183
+ for (let i = endLine; i < Math.min(endLine + 5, lines.length); i++) {
184
+ const line = lines[i];
185
+ // Skip empty lines
186
+ if (line.trim() === '') {continue;}
187
+
188
+ contextLines.push(line);
189
+
190
+ // Stop at declaration
191
+ if (/^\s*(export\s+)?(default\s+)?(async\s+)?(abstract\s+)?(function|class|interface|type|const|let|var|enum)\s+\w+/.test(line)) {
192
+ break;
193
+ }
194
+ if (contextLines.length >= 2) {break;}
195
+ }
196
+
197
+ // Try to extract the name of the deprecated item
198
+ let itemName = 'unknown';
199
+ const contextText = contextLines.join('\n');
200
+
201
+ // Match export declarations
202
+ const nameMatch = contextText.match(
203
+ /(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:abstract\s+)?(?:function|class|interface|type|const|let|var|enum)\s+(\w+)/
204
+ );
205
+ if (nameMatch) {
206
+ itemName = nameMatch[1];
207
+ }
208
+
209
+ // Determine item type from context
210
+ let itemType = 'unknown';
211
+ if (/\bfunction\b/.test(contextText)) {itemType = 'function';}
212
+ else if (/\bclass\b/.test(contextText)) {itemType = 'class';}
213
+ else if (/\binterface\b/.test(contextText)) {itemType = 'interface';}
214
+ else if (/\btype\s+\w+/.test(contextText)) {itemType = 'type';}
215
+ else if (/\bconst\b/.test(contextText)) {itemType = 'const';}
216
+ else if (/\benum\b/.test(contextText)) {itemType = 'enum';}
217
+ else if (/\blet\b|\bvar\b/.test(contextText)) {itemType = 'variable';}
218
+
219
+ // Skip if no code follows (orphan comment)
220
+ if (contextLines.length === 0 || itemName === 'unknown') {
221
+ continue;
222
+ }
223
+
224
+ deprecated.push({
225
+ file: filePath,
226
+ line: lineNumber,
227
+ type: 'jsdoc',
228
+ itemType,
229
+ itemName,
230
+ reason: reason || 'No reason provided',
231
+ context: contextLines.slice(0, 2).join('\n'),
232
+ });
233
+ }
234
+
235
+ // Deduplicate by item name + file (same item might have multiple @deprecated in same JSDoc)
236
+ const seen = new Set();
237
+ return deprecated.filter((item) => {
238
+ const key = `${item.file}:${item.itemName}`;
239
+ if (seen.has(key)) {return false;}
240
+ seen.add(key);
241
+ return true;
242
+ });
243
+ }
244
+
245
+ /**
246
+ * Analyze a single package
247
+ */
248
+ function analyzePackage(pkg) {
249
+ const files = findSourceFiles(pkg.srcPath);
250
+ const deprecated = [];
251
+
252
+ for (const file of files) {
253
+ try {
254
+ const content = fs.readFileSync(file, 'utf-8');
255
+ const items = extractDeprecated(file, content);
256
+ deprecated.push(...items);
257
+ } catch {
258
+ // Skip unreadable files
259
+ }
260
+ }
261
+
262
+ return {
263
+ package: pkg.name,
264
+ shortName: pkg.shortName,
265
+ repo: pkg.repo,
266
+ deprecated,
267
+ fileCount: files.length,
268
+ };
269
+ }
270
+
271
+ /**
272
+ * Format output as table (default)
273
+ */
274
+ function formatTable(results, rootDir) {
275
+ const totalDeprecated = results.reduce((sum, r) => sum + r.deprecated.length, 0);
276
+
277
+ if (totalDeprecated === 0) {
278
+ log('\nāœ… No @deprecated items found!\n', 'green');
279
+ return;
280
+ }
281
+
282
+ log(`\nšŸ“‹ Found ${totalDeprecated} @deprecated item(s)\n`, 'yellow');
283
+
284
+ for (const result of results) {
285
+ if (result.deprecated.length === 0) {continue;}
286
+
287
+ log(`\nšŸ“¦ ${result.package} (${result.deprecated.length} deprecated)`, 'cyan');
288
+ log('─'.repeat(60), 'gray');
289
+
290
+ for (const item of result.deprecated) {
291
+ const relativePath = path.relative(rootDir, item.file);
292
+ const location = `${relativePath}:${item.line}`;
293
+
294
+ log(` āš ļø ${item.itemType} ${colors.bold}${item.itemName}${colors.reset}`, 'yellow');
295
+ log(` šŸ“ ${location}`, 'gray');
296
+
297
+ if (item.reason && item.reason !== 'No reason provided') {
298
+ log(` šŸ’¬ ${item.reason}`, 'gray');
299
+ }
300
+
301
+ if (options.verbose && item.context) {
302
+ log(' ā”Œā”€ Context:', 'gray');
303
+ for (const line of item.context.split('\n')) {
304
+ log(` │ ${line}`, 'gray');
305
+ }
306
+ log(' └─', 'gray');
307
+ }
308
+ }
309
+ }
310
+
311
+ // Summary
312
+ log('\n' + '═'.repeat(60), 'gray');
313
+ log('šŸ“Š Summary:', 'blue');
314
+
315
+ const byType = {};
316
+ for (const result of results) {
317
+ for (const item of result.deprecated) {
318
+ byType[item.itemType] = (byType[item.itemType] || 0) + 1;
319
+ }
320
+ }
321
+
322
+ for (const [type, count] of Object.entries(byType).sort((a, b) => b[1] - a[1])) {
323
+ log(` ${type}: ${count}`, 'gray');
324
+ }
325
+
326
+ log(`\n Total: ${totalDeprecated} deprecated item(s) in ${results.filter((r) => r.deprecated.length > 0).length} package(s)`, 'yellow');
327
+ log('', 'reset');
328
+ }
329
+
330
+ /**
331
+ * Format output as JSON
332
+ */
333
+ function formatJSON(results, rootDir) {
334
+ const output = {
335
+ summary: {
336
+ totalDeprecated: results.reduce((sum, r) => sum + r.deprecated.length, 0),
337
+ packagesWithDeprecated: results.filter((r) => r.deprecated.length > 0).length,
338
+ totalPackages: results.length,
339
+ byType: {},
340
+ },
341
+ packages: results
342
+ .filter((r) => r.deprecated.length > 0)
343
+ .map((r) => ({
344
+ name: r.package,
345
+ shortName: r.shortName,
346
+ repo: r.repo,
347
+ deprecatedCount: r.deprecated.length,
348
+ items: r.deprecated.map((item) => ({
349
+ name: item.itemName,
350
+ type: item.itemType,
351
+ file: path.relative(rootDir, item.file),
352
+ line: item.line,
353
+ reason: item.reason,
354
+ context: options.verbose ? item.context : undefined,
355
+ })),
356
+ })),
357
+ };
358
+
359
+ // Calculate byType
360
+ for (const result of results) {
361
+ for (const item of result.deprecated) {
362
+ output.summary.byType[item.itemType] = (output.summary.byType[item.itemType] || 0) + 1;
363
+ }
364
+ }
365
+
366
+ console.log(JSON.stringify(output, null, 2));
367
+ }
368
+
369
+ /**
370
+ * Format output as Markdown
371
+ */
372
+ function formatMarkdown(results, rootDir) {
373
+ const totalDeprecated = results.reduce((sum, r) => sum + r.deprecated.length, 0);
374
+
375
+ console.log('# Deprecated Code Report\n');
376
+ console.log(`Generated: ${new Date().toISOString()}\n`);
377
+
378
+ console.log('## Summary\n');
379
+ console.log(`- **Total deprecated items:** ${totalDeprecated}`);
380
+ console.log(`- **Packages affected:** ${results.filter((r) => r.deprecated.length > 0).length}`);
381
+ console.log(`- **Total packages scanned:** ${results.length}\n`);
382
+
383
+ if (totalDeprecated === 0) {
384
+ console.log('āœ… No deprecated items found!\n');
385
+ return;
386
+ }
387
+
388
+ // By type table
389
+ const byType = {};
390
+ for (const result of results) {
391
+ for (const item of result.deprecated) {
392
+ byType[item.itemType] = (byType[item.itemType] || 0) + 1;
393
+ }
394
+ }
395
+
396
+ console.log('### By Type\n');
397
+ console.log('| Type | Count |');
398
+ console.log('|------|-------|');
399
+ for (const [type, count] of Object.entries(byType).sort((a, b) => b[1] - a[1])) {
400
+ console.log(`| ${type} | ${count} |`);
401
+ }
402
+ console.log('');
403
+
404
+ // Detailed list
405
+ console.log('## Deprecated Items\n');
406
+
407
+ for (const result of results) {
408
+ if (result.deprecated.length === 0) {continue;}
409
+
410
+ console.log(`### ${result.package}\n`);
411
+ console.log(`| Item | Type | Location | Reason |`);
412
+ console.log(`|------|------|----------|--------|`);
413
+
414
+ for (const item of result.deprecated) {
415
+ const relativePath = path.relative(rootDir, item.file);
416
+ const location = `\`${relativePath}:${item.line}\``;
417
+ const reason = item.reason.replace(/\|/g, '\\|').substring(0, 50);
418
+ console.log(`| \`${item.itemName}\` | ${item.itemType} | ${location} | ${reason} |`);
419
+ }
420
+ console.log('');
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Format output as stats only
426
+ */
427
+ function formatStats(results) {
428
+ const totalDeprecated = results.reduce((sum, r) => sum + r.deprecated.length, 0);
429
+ const packagesWithDeprecated = results.filter((r) => r.deprecated.length > 0).length;
430
+
431
+ const byType = {};
432
+ const byRepo = {};
433
+ for (const result of results) {
434
+ for (const item of result.deprecated) {
435
+ byType[item.itemType] = (byType[item.itemType] || 0) + 1;
436
+ }
437
+ if (result.deprecated.length > 0) {
438
+ byRepo[result.repo] = (byRepo[result.repo] || 0) + result.deprecated.length;
439
+ }
440
+ }
441
+
442
+ if (options.json) {
443
+ console.log(
444
+ JSON.stringify(
445
+ {
446
+ totalDeprecated,
447
+ packagesWithDeprecated,
448
+ totalPackages: results.length,
449
+ byType,
450
+ byRepo,
451
+ },
452
+ null,
453
+ 2
454
+ )
455
+ );
456
+ return;
457
+ }
458
+
459
+ log('\nšŸ“Š Deprecated Code Statistics\n', 'blue');
460
+ log(` Total deprecated items: ${totalDeprecated}`, totalDeprecated > 0 ? 'yellow' : 'green');
461
+ log(` Packages affected: ${packagesWithDeprecated} / ${results.length}`, 'gray');
462
+
463
+ if (totalDeprecated > 0) {
464
+ log('\n By Type:', 'cyan');
465
+ for (const [type, count] of Object.entries(byType).sort((a, b) => b[1] - a[1])) {
466
+ log(` ${type}: ${count}`, 'gray');
467
+ }
468
+
469
+ log('\n By Repository:', 'cyan');
470
+ for (const [repo, count] of Object.entries(byRepo).sort((a, b) => b[1] - a[1])) {
471
+ log(` ${repo}: ${count}`, 'gray');
472
+ }
473
+ }
474
+
475
+ log('', 'reset');
476
+ }
477
+
478
+ /**
479
+ * Main function
480
+ */
481
+ async function main() {
482
+ try {
483
+ const rootDir = process.cwd();
484
+
485
+ if (!options.json && !options.md && !options.stats) {
486
+ log('šŸ” KB Labs Deprecated Code Checker\n', 'blue');
487
+ }
488
+
489
+ const packages = findPackages(rootDir, options.package);
490
+
491
+ if (packages.length === 0) {
492
+ log('āŒ No packages found. Make sure you run this from kb-labs root directory.', 'red');
493
+ process.exit(2);
494
+ }
495
+
496
+ if (!options.json && !options.md) {
497
+ log(`Scanning ${packages.length} package(s)...`, 'gray');
498
+ }
499
+
500
+ const results = [];
501
+ for (const pkg of packages) {
502
+ const result = analyzePackage(pkg);
503
+ results.push(result);
504
+ }
505
+
506
+ // Sort by deprecated count (most first)
507
+ results.sort((a, b) => b.deprecated.length - a.deprecated.length);
508
+
509
+ // Output based on format
510
+ if (options.stats) {
511
+ formatStats(results);
512
+ } else if (options.json) {
513
+ formatJSON(results, rootDir);
514
+ } else if (options.md) {
515
+ formatMarkdown(results, rootDir);
516
+ } else {
517
+ formatTable(results, rootDir);
518
+ }
519
+
520
+ // Exit with code 1 if deprecated items found (useful for CI awareness, not failure)
521
+ const totalDeprecated = results.reduce((sum, r) => sum + r.deprecated.length, 0);
522
+ process.exit(totalDeprecated > 0 ? 1 : 0);
523
+ } catch (error) {
524
+ console.error(`\nāŒ Error: ${error.message}\n`);
525
+ if (process.env.DEBUG) {
526
+ console.error(error.stack);
527
+ }
528
+ process.exit(2);
529
+ }
530
+ }
531
+
532
+ main();