@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,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @kb-labs/devkit - Core Platform Gate
5
+ *
6
+ * Checks if the 6 core platform monorepos meet quality requirements.
7
+ * Reads from the last `pnpm qa` run (.qa-history/history.json) — no recompilation.
8
+ *
9
+ * Core monorepos (from stabilization.md):
10
+ * kb-labs-cli, kb-labs-core, kb-labs-shared,
11
+ * kb-labs-sdk, kb-labs-rest-api, kb-labs-plugin
12
+ *
13
+ * Requirements for core:
14
+ * build → zero failures
15
+ * types → zero errors
16
+ * lint → zero errors
17
+ *
18
+ * Flow:
19
+ * pnpm qa # run checks (auto-saves to history)
20
+ * pnpm core:gate # inspect core result
21
+ *
22
+ * Usage:
23
+ * kb-devkit-core-gate # gate check
24
+ * kb-devkit-core-gate --verbose # show failing packages
25
+ * kb-devkit-core-gate --json # JSON output
26
+ */
27
+
28
+ import fs from 'node:fs';
29
+ import path from 'node:path';
30
+ import { fileURLToPath } from 'node:url';
31
+
32
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
33
+
34
+ const colors = {
35
+ reset: '\x1b[0m',
36
+ red: '\x1b[31m',
37
+ green: '\x1b[32m',
38
+ yellow: '\x1b[33m',
39
+ cyan: '\x1b[36m',
40
+ gray: '\x1b[90m',
41
+ bold: '\x1b[1m',
42
+ dim: '\x1b[2m',
43
+ };
44
+
45
+ const args = process.argv.slice(2);
46
+ const jsonOutput = args.includes('--json');
47
+ const verbose = args.includes('--verbose');
48
+
49
+ // Core monorepos — matches stabilization.md
50
+ const CORE_REPOS = [
51
+ 'kb-labs-cli',
52
+ 'kb-labs-core',
53
+ 'kb-labs-shared',
54
+ 'kb-labs-sdk',
55
+ 'kb-labs-rest-api',
56
+ 'kb-labs-plugin',
57
+ ];
58
+
59
+ function findMonorepoRoot() {
60
+ let dir = process.cwd();
61
+ while (dir !== '/') {
62
+ if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) return dir;
63
+ dir = path.dirname(dir);
64
+ }
65
+ throw new Error('Not in a pnpm workspace');
66
+ }
67
+
68
+ /**
69
+ * Build map: package name → repo name, for core repos only.
70
+ */
71
+ function buildCorePackageMap(rootDir) {
72
+ const map = new Map();
73
+ for (const repo of CORE_REPOS) {
74
+ const repoDir = path.join(rootDir, repo, 'packages');
75
+ if (!fs.existsSync(repoDir)) continue;
76
+ for (const entry of fs.readdirSync(repoDir, { withFileTypes: true })) {
77
+ if (!entry.isDirectory()) continue;
78
+ const pkgJsonPath = path.join(repoDir, entry.name, 'package.json');
79
+ if (!fs.existsSync(pkgJsonPath)) continue;
80
+ try {
81
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
82
+ if (pkg.name) map.set(pkg.name, repo);
83
+ } catch { /* skip */ }
84
+ }
85
+ }
86
+ return map;
87
+ }
88
+
89
+ /**
90
+ * Read the last-run.json written by `pnpm qa` after each run.
91
+ * Falls back to null if no run has happened yet.
92
+ */
93
+ function readLastQaRun(rootDir) {
94
+ const lastRunPath = path.join(rootDir, '.qa-cache', 'last-run.json');
95
+ if (!fs.existsSync(lastRunPath)) return null;
96
+ try {
97
+ return JSON.parse(fs.readFileSync(lastRunPath, 'utf-8'));
98
+ } catch { return null; }
99
+ }
100
+
101
+ function runGate() {
102
+ const rootDir = findMonorepoRoot();
103
+ const corePackageMap = buildCorePackageMap(rootDir);
104
+
105
+ if (corePackageMap.size === 0) {
106
+ console.error(`${colors.red}Could not find any core packages. Run from monorepo root.${colors.reset}`);
107
+ process.exit(1);
108
+ }
109
+
110
+ const lastRun = readLastQaRun(rootDir);
111
+
112
+ if (!lastRun) {
113
+ console.error(`${colors.red}No QA run found. Run ${colors.cyan}pnpm qa${colors.red} first.${colors.reset}`);
114
+ process.exit(1);
115
+ }
116
+
117
+ const runAge = Math.round((Date.now() - new Date(lastRun.timestamp).getTime()) / 60000);
118
+ const failedPackages = lastRun.failedPackages ?? {};
119
+
120
+ const buildFailed = new Set(failedPackages.build ?? []);
121
+ const typesFailed = new Set(failedPackages.typeCheck ?? failedPackages.types ?? []);
122
+ const lintFailed = new Set(failedPackages.lint ?? []);
123
+
124
+ // Per-repo rollup
125
+ const repoResults = {};
126
+ for (const repo of CORE_REPOS) {
127
+ repoResults[repo] = {
128
+ build: { pass: true, packages: [] },
129
+ types: { pass: true, packages: [] },
130
+ lint: { pass: true, packages: [] },
131
+ };
132
+ }
133
+
134
+ for (const [pkgName, repo] of corePackageMap) {
135
+ if (buildFailed.has(pkgName)) {
136
+ repoResults[repo].build.pass = false;
137
+ repoResults[repo].build.packages.push(pkgName);
138
+ }
139
+ if (typesFailed.has(pkgName)) {
140
+ repoResults[repo].types.pass = false;
141
+ repoResults[repo].types.packages.push(pkgName);
142
+ }
143
+ if (lintFailed.has(pkgName)) {
144
+ repoResults[repo].lint.pass = false;
145
+ repoResults[repo].lint.packages.push(pkgName);
146
+ }
147
+ }
148
+
149
+ const allPass = CORE_REPOS.every(repo => {
150
+ const r = repoResults[repo];
151
+ return r.build.pass && r.types.pass && r.lint.pass;
152
+ });
153
+
154
+ // JSON output
155
+ if (jsonOutput) {
156
+ console.log(JSON.stringify({
157
+ pass: allPass,
158
+ runAge,
159
+ timestamp: lastRun.timestamp,
160
+ commit: lastRun.git?.commit,
161
+ repos: repoResults,
162
+ }, null, 2));
163
+ process.exit(allPass ? 0 : 1);
164
+ }
165
+
166
+ // Human output
167
+ console.log(`\n${colors.bold}${colors.cyan}Platform Core Gate${colors.reset}`);
168
+ const commitInfo = lastRun.git?.commit ? ` ${colors.dim}· ${lastRun.git.commit.slice(0, 9)}${colors.reset}` : '';
169
+ console.log(`${colors.dim}Last qa run: ${runAge}m ago${colors.reset}${commitInfo}`);
170
+ console.log();
171
+
172
+ const colRepo = 22;
173
+ const colCheck = 9;
174
+ console.log(`${colors.dim} ${'Monorepo'.padEnd(colRepo)}${'Build'.padEnd(colCheck)}${'Types'.padEnd(colCheck)}${'Lint'.padEnd(colCheck)}${colors.reset}`);
175
+ console.log(`${colors.dim} ${'─'.repeat(colRepo + colCheck * 3)}${colors.reset}`);
176
+
177
+ for (const repo of CORE_REPOS) {
178
+ const r = repoResults[repo];
179
+ const repoPass = r.build.pass && r.types.pass && r.lint.pass;
180
+
181
+ const icon = repoPass ? `${colors.green}✅${colors.reset}` : `${colors.red}❌${colors.reset}`;
182
+ const buildS = r.build.pass ? `${colors.green}pass${colors.reset}` : `${colors.red}FAIL${colors.reset}`;
183
+ const typesS = r.types.pass ? `${colors.green}pass${colors.reset}` : `${colors.red}${r.types.packages.length}pkg${colors.reset}`;
184
+ const lintS = r.lint.pass ? `${colors.green}pass${colors.reset}` : `${colors.red}${r.lint.packages.length}pkg${colors.reset}`;
185
+
186
+ const repoLabel = `${icon} ${repo}`;
187
+ const visibleLen = 3 + repo.length;
188
+ const pad = ' '.repeat(Math.max(0, colRepo - visibleLen + 2));
189
+
190
+ // Each colored string adds ~9 invisible chars — pad accordingly
191
+ console.log(` ${repoLabel}${pad}${buildS.padEnd(colCheck + 9)}${typesS.padEnd(colCheck + 9)}${lintS}`);
192
+
193
+ if (verbose && !repoPass) {
194
+ for (const p of r.build.packages) console.log(`${colors.dim} build ${p}${colors.reset}`);
195
+ for (const p of r.types.packages) console.log(`${colors.dim} types ${p}${colors.reset}`);
196
+ for (const p of r.lint.packages) console.log(`${colors.dim} lint ${p}${colors.reset}`);
197
+ }
198
+ }
199
+
200
+ console.log();
201
+
202
+ if (allPass) {
203
+ console.log(`${colors.green}${colors.bold}✅ Core is stable. Ready for release.${colors.reset}`);
204
+ } else {
205
+ const failCount = CORE_REPOS.filter(r => {
206
+ const res = repoResults[r];
207
+ return !res.build.pass || !res.types.pass || !res.lint.pass;
208
+ }).length;
209
+ console.log(`${colors.red}${colors.bold}❌ Core is NOT stable. ${failCount} repo(s) failing.${colors.reset}`);
210
+ if (!verbose) {
211
+ console.log(`${colors.dim} Run with --verbose to see failing packages.${colors.reset}`);
212
+ }
213
+ console.log(`${colors.dim} After fixing — run: pnpm qa && pnpm core:gate${colors.reset}`);
214
+ }
215
+
216
+ console.log();
217
+ process.exit(allPass ? 0 : 1);
218
+ }
219
+
220
+ try {
221
+ runGate();
222
+ } catch (err) {
223
+ console.error(`${colors.red}Gate failed: ${err.message}${colors.reset}`);
224
+ process.exit(1);
225
+ }