@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,394 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - Command Health Checker
5
+ *
6
+ * Automatically checks all CLI commands in the ecosystem.
7
+ * Ensures commands don't break silently.
8
+ *
9
+ * Usage:
10
+ * kb-devkit-check-commands # Check all commands
11
+ * kb-devkit-check-commands --fast # Quick check (only --help)
12
+ * kb-devkit-check-commands --timeout 10 # Custom timeout (seconds)
13
+ * kb-devkit-check-commands --json # Output JSON
14
+ */
15
+
16
+ import { execSync, spawn } from 'node:child_process';
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
+
20
+ // ANSI colors
21
+ const colors = {
22
+ reset: '\x1b[0m',
23
+ red: '\x1b[31m',
24
+ green: '\x1b[32m',
25
+ yellow: '\x1b[33m',
26
+ blue: '\x1b[34m',
27
+ magenta: '\x1b[35m',
28
+ cyan: '\x1b[36m',
29
+ gray: '\x1b[90m',
30
+ bold: '\x1b[1m',
31
+ };
32
+
33
+ function log(message, color = 'reset') {
34
+ if (!options.json) {
35
+ console.log(`${colors[color]}${message}${colors.reset}`);
36
+ }
37
+ }
38
+
39
+ // Parse CLI arguments
40
+ const args = process.argv.slice(2);
41
+ const options = {
42
+ fast: args.includes('--fast'),
43
+ json: args.includes('--json'),
44
+ verbose: args.includes('--verbose') || args.includes('-v'),
45
+ timeout: parseInt(args.find((arg) => arg.startsWith('--timeout='))?.split('=')[1] || '5', 10) * 1000,
46
+ };
47
+
48
+ /**
49
+ * Find all plugin manifests in monorepo
50
+ */
51
+ function findPluginManifests(rootDir) {
52
+ const manifests = [];
53
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
54
+
55
+ for (const entry of entries) {
56
+ if (!entry.isDirectory() || !entry.name.startsWith('kb-labs-')) {continue;}
57
+
58
+ const repoPath = path.join(rootDir, entry.name);
59
+ const packagesDir = path.join(repoPath, 'packages');
60
+
61
+ if (!fs.existsSync(packagesDir)) {continue;}
62
+
63
+ const packageDirs = fs.readdirSync(packagesDir, { withFileTypes: true });
64
+
65
+ for (const pkgDir of packageDirs) {
66
+ if (!pkgDir.isDirectory()) {continue;}
67
+
68
+ const manifestPath = path.join(packagesDir, pkgDir.name, 'manifest.json');
69
+
70
+ if (fs.existsSync(manifestPath)) {
71
+ manifests.push(manifestPath);
72
+ }
73
+ }
74
+ }
75
+
76
+ return manifests;
77
+ }
78
+
79
+ /**
80
+ * Get list of all commands from plugin manifests
81
+ */
82
+ function getAllCommands() {
83
+ const rootDir = process.cwd();
84
+ const manifests = findPluginManifests(rootDir);
85
+
86
+ if (manifests.length === 0) {
87
+ log('āš ļø No plugin manifests found', 'yellow');
88
+ log(' Looking for kb-labs-*/packages/*/manifest.json files', 'gray');
89
+ return [];
90
+ }
91
+
92
+ const commands = new Set();
93
+
94
+ for (const manifestPath of manifests) {
95
+ try {
96
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
97
+
98
+ // Extract commands from manifest
99
+ if (manifest.commands && Array.isArray(manifest.commands)) {
100
+ for (const command of manifest.commands) {
101
+ if (command.name) {
102
+ commands.add(command.name);
103
+ }
104
+ }
105
+ }
106
+ } catch (error) {
107
+ // Skip invalid manifests
108
+ continue;
109
+ }
110
+ }
111
+
112
+ // Also try to get commands from `pnpm kb plugins commands` as fallback
113
+ try {
114
+ const output = execSync('pnpm kb plugins commands 2>/dev/null', {
115
+ encoding: 'utf-8',
116
+ stdio: ['pipe', 'pipe', 'ignore'],
117
+ timeout: 10000,
118
+ });
119
+
120
+ const lines = output.split('\n');
121
+
122
+ for (const line of lines) {
123
+ // Match lines like: " plugins:list - Description"
124
+ const match = line.match(/^\s+([a-z][a-z0-9-]*:[a-z][a-z0-9-]*)\s+-\s+/);
125
+ if (match) {
126
+ commands.add(match[1]);
127
+ }
128
+
129
+ // Also match product-level commands without colons
130
+ const productMatch = line.match(/^\s+([a-z][a-z0-9-]*)\s+-\s+/);
131
+ if (productMatch && !productMatch[1].includes(':')) {
132
+ commands.add(productMatch[1]);
133
+ }
134
+ }
135
+ } catch (error) {
136
+ // CLI might be broken, that's okay - we have manifests
137
+ }
138
+
139
+ return Array.from(commands).sort();
140
+ }
141
+
142
+ /**
143
+ * Check if a command works by running it with --help
144
+ */
145
+ function checkCommand(command) {
146
+ return new Promise((resolve) => {
147
+ const startTime = Date.now();
148
+ let stdout = '';
149
+ let stderr = '';
150
+ let timedOut = false;
151
+
152
+ const child = spawn('pnpm', ['kb', command, '--help'], {
153
+ stdio: ['pipe', 'pipe', 'pipe'],
154
+ cwd: process.cwd(),
155
+ });
156
+
157
+ const timeout = setTimeout(() => {
158
+ timedOut = true;
159
+ child.kill('SIGTERM');
160
+ }, options.timeout);
161
+
162
+ child.stdout.on('data', (data) => {
163
+ stdout += data.toString();
164
+ });
165
+
166
+ child.stderr.on('data', (data) => {
167
+ stderr += data.toString();
168
+ });
169
+
170
+ child.on('close', (code) => {
171
+ clearTimeout(timeout);
172
+ const duration = Date.now() - startTime;
173
+
174
+ let status = 'working';
175
+ let error = null;
176
+
177
+ if (timedOut) {
178
+ status = 'timeout';
179
+ error = `Timeout after ${options.timeout}ms`;
180
+ } else if (code !== 0) {
181
+ status = 'error';
182
+ error = `Exit code: ${code}`;
183
+ if (stderr) {
184
+ // Extract meaningful error from stderr
185
+ const errorLines = stderr.split('\n').filter((line) => line.trim());
186
+ if (errorLines.length > 0) {
187
+ error = errorLines[0].substring(0, 200); // First error line, max 200 chars
188
+ }
189
+ }
190
+ } else if (!stdout || stdout.trim().length === 0) {
191
+ status = 'empty';
192
+ error = 'No output (empty help)';
193
+ } else if (stderr && stderr.includes('Error:')) {
194
+ status = 'warning';
195
+ error = 'Has errors in stderr';
196
+ }
197
+
198
+ resolve({
199
+ command,
200
+ status,
201
+ error,
202
+ duration,
203
+ stdout: stdout.substring(0, 500), // Keep first 500 chars for debugging
204
+ stderr: stderr.substring(0, 500),
205
+ });
206
+ });
207
+
208
+ child.on('error', (err) => {
209
+ clearTimeout(timeout);
210
+ resolve({
211
+ command,
212
+ status: 'error',
213
+ error: err.message,
214
+ duration: Date.now() - startTime,
215
+ });
216
+ });
217
+ });
218
+ }
219
+
220
+ /**
221
+ * Check all commands
222
+ */
223
+ async function checkAllCommands(commands) {
224
+ const results = [];
225
+ const total = commands.length;
226
+
227
+ for (let i = 0; i < total; i++) {
228
+ const command = commands[i];
229
+
230
+ if (!options.json) {
231
+ process.stdout.write(
232
+ `\r${colors.gray}Checking commands... ${i + 1}/${total} (${Math.round((i / total) * 100)}%)${colors.reset}`
233
+ );
234
+ }
235
+
236
+ const result = await checkCommand(command);
237
+ results.push(result);
238
+ }
239
+
240
+ if (!options.json) {
241
+ process.stdout.write('\r' + ' '.repeat(80) + '\r'); // Clear progress line
242
+ }
243
+
244
+ return results;
245
+ }
246
+
247
+ /**
248
+ * Print results
249
+ */
250
+ function printResults(results) {
251
+ const working = results.filter((r) => r.status === 'working');
252
+ const broken = results.filter((r) => r.status !== 'working');
253
+ const errors = results.filter((r) => r.status === 'error');
254
+ const timeouts = results.filter((r) => r.status === 'timeout');
255
+ const empty = results.filter((r) => r.status === 'empty');
256
+ const warnings = results.filter((r) => r.status === 'warning');
257
+
258
+ log('\nšŸ” KB Labs Command Health Checker\n', 'bold');
259
+ log(`Found ${results.length} command(s) to check\n`, 'gray');
260
+
261
+ // Show working commands (only in verbose mode)
262
+ if (options.verbose && working.length > 0) {
263
+ log('āœ… Working commands (' + working.length + '):', 'green');
264
+ for (const result of working.slice(0, 10)) {
265
+ log(` kb ${result.command}`, 'gray');
266
+ }
267
+ if (working.length > 10) {
268
+ log(` ... and ${working.length - 10} more`, 'gray');
269
+ }
270
+ log('', 'reset');
271
+ }
272
+
273
+ // Show broken commands
274
+ if (broken.length > 0) {
275
+ log(`āŒ Broken commands (${broken.length}):\n`, 'red');
276
+
277
+ for (const result of broken) {
278
+ const icon =
279
+ result.status === 'timeout' ? 'ā±ļø'
280
+ : result.status === 'empty' ? 'šŸ“­'
281
+ : result.status === 'warning' ? 'āš ļø'
282
+ : 'āŒ';
283
+
284
+ log(` ${icon} kb ${result.command} --help`, 'yellow');
285
+ log(` └─ ${result.error}`, 'gray');
286
+
287
+ if (options.verbose && result.stderr) {
288
+ const stderrLines = result.stderr.split('\n').filter((l) => l.trim());
289
+ if (stderrLines.length > 0) {
290
+ log(` └─ stderr: ${stderrLines[0].substring(0, 100)}`, 'gray');
291
+ }
292
+ }
293
+ }
294
+ log('', 'reset');
295
+ }
296
+
297
+ // Summary
298
+ log('─'.repeat(60) + '\n', 'gray');
299
+ log('šŸ“Š Summary:\n', 'blue');
300
+
301
+ const percentage = Math.round((working.length / results.length) * 100);
302
+ log(` Total commands: ${results.length}`, 'cyan');
303
+ log(` āœ… Working: ${working.length} (${percentage}%)`, 'green');
304
+
305
+ if (errors.length > 0) {
306
+ log(` āŒ Errors: ${errors.length}`, 'red');
307
+ }
308
+ if (timeouts.length > 0) {
309
+ log(` ā±ļø Timeouts: ${timeouts.length}`, 'yellow');
310
+ }
311
+ if (empty.length > 0) {
312
+ log(` šŸ“­ Empty output: ${empty.length}`, 'yellow');
313
+ }
314
+ if (warnings.length > 0) {
315
+ log(` āš ļø Warnings: ${warnings.length}`, 'yellow');
316
+ }
317
+
318
+ log('', 'reset');
319
+
320
+ // Tips
321
+ if (broken.length > 0) {
322
+ log('šŸ’” Tips:', 'blue');
323
+ log(' • Run with --verbose to see detailed error messages', 'gray');
324
+ log(' • Run with --timeout=10 to increase timeout for slow commands', 'gray');
325
+ log(' • Check package.json dependencies for broken commands', 'gray');
326
+ log('', 'reset');
327
+ }
328
+ }
329
+
330
+ /**
331
+ * Main function
332
+ */
333
+ async function main() {
334
+ const startTime = Date.now();
335
+
336
+ if (!options.json) {
337
+ log('\nšŸš€ KB Labs Command Health Checker\n', 'bold');
338
+ log('Getting command list from `pnpm kb plugins commands`...\n', 'gray');
339
+ }
340
+
341
+ // Get all commands
342
+ const commands = getAllCommands();
343
+
344
+ if (commands.length === 0) {
345
+ log('āš ļø No commands found', 'yellow');
346
+ log(' Make sure you are in the kb-labs monorepo root', 'gray');
347
+ log(' And that `pnpm kb plugins commands` works', 'gray');
348
+ process.exit(1);
349
+ }
350
+
351
+ // Check all commands
352
+ const results = await checkAllCommands(commands);
353
+
354
+ const totalDuration = ((Date.now() - startTime) / 1000).toFixed(2);
355
+
356
+ if (options.json) {
357
+ // JSON output for CI parsing
358
+ const working = results.filter((r) => r.status === 'working');
359
+ const broken = results.filter((r) => r.status !== 'working');
360
+
361
+ const output = {
362
+ summary: {
363
+ total: results.length,
364
+ working: working.length,
365
+ broken: broken.length,
366
+ percentage: Math.round((working.length / results.length) * 100),
367
+ duration: parseFloat(totalDuration),
368
+ },
369
+ commands: results.map((r) => ({
370
+ command: r.command,
371
+ status: r.status,
372
+ error: r.error,
373
+ duration: r.duration,
374
+ })),
375
+ broken: broken.map((r) => ({
376
+ command: r.command,
377
+ status: r.status,
378
+ error: r.error,
379
+ })),
380
+ };
381
+
382
+ console.log(JSON.stringify(output, null, 2));
383
+ } else {
384
+ printResults(results);
385
+
386
+ log(`ā±ļø Duration: ${totalDuration}s\n`, 'gray');
387
+ }
388
+
389
+ // Exit with error if any commands are broken
390
+ const broken = results.filter((r) => r.status !== 'working');
391
+ process.exit(broken.length > 0 ? 1 : 0);
392
+ }
393
+
394
+ main();