@vibecheckai/cli 3.7.0 → 3.8.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 (99) hide show
  1. package/README.md +135 -63
  2. package/bin/_deprecations.js +447 -19
  3. package/bin/_router.js +1 -1
  4. package/bin/registry.js +347 -280
  5. package/bin/runners/context/generators/cursor-enhanced.js +2439 -0
  6. package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
  7. package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
  8. package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
  9. package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
  10. package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
  11. package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
  12. package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
  13. package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
  14. package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
  15. package/bin/runners/lib/agent-firewall/index.js +200 -0
  16. package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
  17. package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
  18. package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +622 -0
  19. package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
  20. package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
  21. package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
  22. package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
  23. package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
  24. package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
  25. package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
  26. package/bin/runners/lib/agent-firewall/session/index.js +26 -0
  27. package/bin/runners/lib/artifact-envelope.js +540 -0
  28. package/bin/runners/lib/auth-shared.js +977 -0
  29. package/bin/runners/lib/checkpoint.js +941 -0
  30. package/bin/runners/lib/cleanup/engine.js +571 -0
  31. package/bin/runners/lib/cleanup/index.js +53 -0
  32. package/bin/runners/lib/cleanup/output.js +375 -0
  33. package/bin/runners/lib/cleanup/rules.js +1060 -0
  34. package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
  35. package/bin/runners/lib/doctor/failure-signatures.js +526 -0
  36. package/bin/runners/lib/doctor/fix-script.js +336 -0
  37. package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
  38. package/bin/runners/lib/doctor/modules/index.js +62 -3
  39. package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
  40. package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
  41. package/bin/runners/lib/doctor/safe-repair.js +384 -0
  42. package/bin/runners/lib/engines/attack-detector.js +1192 -0
  43. package/bin/runners/lib/entitlements-v2.js +2 -2
  44. package/bin/runners/lib/missions/briefing.js +427 -0
  45. package/bin/runners/lib/missions/checkpoint.js +753 -0
  46. package/bin/runners/lib/missions/hardening.js +851 -0
  47. package/bin/runners/lib/missions/plan.js +421 -32
  48. package/bin/runners/lib/missions/safety-gates.js +645 -0
  49. package/bin/runners/lib/missions/schema.js +478 -0
  50. package/bin/runners/lib/packs/bundle.js +675 -0
  51. package/bin/runners/lib/packs/evidence-pack.js +671 -0
  52. package/bin/runners/lib/packs/pack-factory.js +837 -0
  53. package/bin/runners/lib/packs/permissions-pack.js +686 -0
  54. package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
  55. package/bin/runners/lib/safelist/index.js +96 -0
  56. package/bin/runners/lib/safelist/integration.js +334 -0
  57. package/bin/runners/lib/safelist/matcher.js +696 -0
  58. package/bin/runners/lib/safelist/schema.js +948 -0
  59. package/bin/runners/lib/safelist/store.js +438 -0
  60. package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
  61. package/bin/runners/lib/ship-gate.js +832 -0
  62. package/bin/runners/lib/ship-manifest.js +1153 -0
  63. package/bin/runners/lib/ship-output.js +1 -1
  64. package/bin/runners/lib/unified-cli-output.js +710 -383
  65. package/bin/runners/lib/upsell.js +3 -3
  66. package/bin/runners/lib/why-tree.js +650 -0
  67. package/bin/runners/runAllowlist.js +33 -4
  68. package/bin/runners/runApprove.js +240 -1122
  69. package/bin/runners/runAudit.js +692 -0
  70. package/bin/runners/runAuth.js +325 -29
  71. package/bin/runners/runCheckpoint.js +442 -494
  72. package/bin/runners/runCleanup.js +343 -0
  73. package/bin/runners/runDoctor.js +269 -19
  74. package/bin/runners/runFix.js +411 -32
  75. package/bin/runners/runForge.js +411 -0
  76. package/bin/runners/runIntent.js +906 -0
  77. package/bin/runners/runKickoff.js +878 -0
  78. package/bin/runners/runLaunch.js +2000 -0
  79. package/bin/runners/runLink.js +785 -0
  80. package/bin/runners/runMcp.js +1741 -837
  81. package/bin/runners/runPacks.js +2089 -0
  82. package/bin/runners/runPolish.js +41 -0
  83. package/bin/runners/runSafelist.js +1190 -0
  84. package/bin/runners/runScan.js +21 -9
  85. package/bin/runners/runShield.js +1282 -0
  86. package/bin/runners/runShip.js +395 -16
  87. package/bin/vibecheck.js +34 -6
  88. package/mcp-server/README.md +117 -158
  89. package/mcp-server/handlers/tool-handler.ts +3 -3
  90. package/mcp-server/index.js +16 -0
  91. package/mcp-server/intent-firewall-interceptor.js +529 -0
  92. package/mcp-server/manifest.json +473 -0
  93. package/mcp-server/package.json +1 -1
  94. package/mcp-server/registry/tool-registry.js +315 -523
  95. package/mcp-server/registry/tools.json +442 -428
  96. package/mcp-server/tier-auth.js +68 -11
  97. package/mcp-server/tools-v3.js +70 -16
  98. package/package.json +1 -1
  99. package/bin/runners/runProof.zip +0 -0
@@ -0,0 +1,453 @@
1
+ /**
2
+ * Build Tools Diagnostics Module
3
+ *
4
+ * Checks tsconfig, ESLint, Prettier, Jest, Vitest, and build configuration
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const { execSync } = require('child_process');
10
+ const { SEVERITY, CATEGORY, FIX_TYPE } = require('../types');
11
+
12
+ const MODULE_ID = 'build';
13
+
14
+ function createDiagnostics(projectPath) {
15
+ return [
16
+ {
17
+ id: `${MODULE_ID}.tsconfig`,
18
+ name: 'TypeScript Config',
19
+ category: CATEGORY.PROJECT,
20
+ parallel: true,
21
+ check: async () => {
22
+ const tsconfigPath = path.join(projectPath, 'tsconfig.json');
23
+
24
+ if (!fs.existsSync(tsconfigPath)) {
25
+ // Check for jsconfig.json as fallback
26
+ const jsconfigPath = path.join(projectPath, 'jsconfig.json');
27
+ if (fs.existsSync(jsconfigPath)) {
28
+ return {
29
+ severity: SEVERITY.PASS,
30
+ message: 'jsconfig.json found (JavaScript project)',
31
+ metadata: { type: 'javascript', path: jsconfigPath },
32
+ };
33
+ }
34
+
35
+ return {
36
+ severity: SEVERITY.INFO,
37
+ message: 'Not found (JavaScript project)',
38
+ metadata: { type: 'javascript' },
39
+ };
40
+ }
41
+
42
+ try {
43
+ const content = fs.readFileSync(tsconfigPath, 'utf8');
44
+ const config = JSON.parse(content);
45
+
46
+ const issues = [];
47
+ const metadata = { path: tsconfigPath, config: {} };
48
+
49
+ // Check for common misconfigurations
50
+ const compilerOptions = config.compilerOptions || {};
51
+ metadata.config = compilerOptions;
52
+
53
+ // Check strict mode
54
+ if (!compilerOptions.strict) {
55
+ issues.push('strict mode disabled');
56
+ }
57
+
58
+ // Check module resolution
59
+ if (compilerOptions.moduleResolution === 'node' && compilerOptions.module?.toLowerCase().includes('esnext')) {
60
+ issues.push('moduleResolution should be "bundler" or "nodenext" for ESM');
61
+ }
62
+
63
+ // Check for skipLibCheck (acceptable but worth noting)
64
+ if (compilerOptions.skipLibCheck === false) {
65
+ metadata.slowBuild = true;
66
+ }
67
+
68
+ // Check target
69
+ const target = (compilerOptions.target || 'es5').toLowerCase();
70
+ if (['es5', 'es6', 'es2015', 'es2016'].includes(target)) {
71
+ issues.push(`target "${compilerOptions.target}" is outdated, recommend ES2020+`);
72
+ }
73
+
74
+ if (issues.length > 0) {
75
+ return {
76
+ severity: SEVERITY.WARNING,
77
+ message: issues.length === 1 ? issues[0] : `${issues.length} issues found`,
78
+ detail: issues.join('; '),
79
+ metadata,
80
+ fixes: [{
81
+ type: FIX_TYPE.LINK,
82
+ description: 'TypeScript configuration reference',
83
+ url: 'https://www.typescriptlang.org/tsconfig',
84
+ }],
85
+ };
86
+ }
87
+
88
+ return {
89
+ severity: SEVERITY.PASS,
90
+ message: `Valid (target: ${compilerOptions.target || 'default'})`,
91
+ metadata,
92
+ };
93
+ } catch (err) {
94
+ return {
95
+ severity: SEVERITY.ERROR,
96
+ message: 'Invalid tsconfig.json',
97
+ detail: err.message,
98
+ fixes: [{
99
+ type: FIX_TYPE.MANUAL,
100
+ description: 'Fix JSON syntax errors in tsconfig.json',
101
+ autoFixable: false,
102
+ }],
103
+ };
104
+ }
105
+ },
106
+ },
107
+ {
108
+ id: `${MODULE_ID}.eslint`,
109
+ name: 'ESLint Configuration',
110
+ category: CATEGORY.PROJECT,
111
+ parallel: true,
112
+ check: async () => {
113
+ const eslintConfigs = [
114
+ 'eslint.config.js',
115
+ 'eslint.config.mjs',
116
+ 'eslint.config.cjs',
117
+ '.eslintrc.js',
118
+ '.eslintrc.cjs',
119
+ '.eslintrc.json',
120
+ '.eslintrc.yml',
121
+ '.eslintrc.yaml',
122
+ '.eslintrc',
123
+ ];
124
+
125
+ let foundConfig = null;
126
+ for (const configFile of eslintConfigs) {
127
+ const configPath = path.join(projectPath, configFile);
128
+ if (fs.existsSync(configPath)) {
129
+ foundConfig = configFile;
130
+ break;
131
+ }
132
+ // Also check config/ directory
133
+ const configDirPath = path.join(projectPath, 'config', configFile);
134
+ if (fs.existsSync(configDirPath)) {
135
+ foundConfig = `config/${configFile}`;
136
+ break;
137
+ }
138
+ }
139
+
140
+ // Check package.json for eslintConfig
141
+ const pkgPath = path.join(projectPath, 'package.json');
142
+ let pkgHasEslint = false;
143
+ if (fs.existsSync(pkgPath)) {
144
+ try {
145
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
146
+ if (pkg.eslintConfig) {
147
+ pkgHasEslint = true;
148
+ }
149
+ } catch {}
150
+ }
151
+
152
+ if (!foundConfig && !pkgHasEslint) {
153
+ return {
154
+ severity: SEVERITY.INFO,
155
+ message: 'No ESLint config found',
156
+ fixes: [{
157
+ type: FIX_TYPE.COMMAND,
158
+ description: 'Initialize ESLint',
159
+ command: 'npm init @eslint/config',
160
+ autoFixable: false,
161
+ }],
162
+ };
163
+ }
164
+
165
+ const configType = foundConfig?.startsWith('eslint.config') ? 'flat config' : 'legacy config';
166
+ const metadata = { config: foundConfig || 'package.json', type: configType };
167
+
168
+ // Check if eslint is installed
169
+ try {
170
+ execSync('npx eslint --version', {
171
+ cwd: projectPath,
172
+ encoding: 'utf8',
173
+ timeout: 10000,
174
+ stdio: ['pipe', 'pipe', 'pipe'],
175
+ });
176
+
177
+ return {
178
+ severity: SEVERITY.PASS,
179
+ message: `${foundConfig || 'package.json'} (${configType})`,
180
+ metadata,
181
+ };
182
+ } catch {
183
+ return {
184
+ severity: SEVERITY.WARNING,
185
+ message: `Config found but ESLint not installed`,
186
+ metadata,
187
+ fixes: [{
188
+ type: FIX_TYPE.COMMAND,
189
+ description: 'Install ESLint',
190
+ command: 'npm install -D eslint',
191
+ autoFixable: true,
192
+ }],
193
+ };
194
+ }
195
+ },
196
+ },
197
+ {
198
+ id: `${MODULE_ID}.prettier`,
199
+ name: 'Prettier Configuration',
200
+ category: CATEGORY.PROJECT,
201
+ parallel: true,
202
+ check: async () => {
203
+ const prettierConfigs = [
204
+ '.prettierrc',
205
+ '.prettierrc.json',
206
+ '.prettierrc.yml',
207
+ '.prettierrc.yaml',
208
+ '.prettierrc.js',
209
+ '.prettierrc.cjs',
210
+ '.prettierrc.mjs',
211
+ 'prettier.config.js',
212
+ 'prettier.config.cjs',
213
+ 'prettier.config.mjs',
214
+ ];
215
+
216
+ let foundConfig = null;
217
+ for (const configFile of prettierConfigs) {
218
+ if (fs.existsSync(path.join(projectPath, configFile))) {
219
+ foundConfig = configFile;
220
+ break;
221
+ }
222
+ }
223
+
224
+ // Check package.json
225
+ const pkgPath = path.join(projectPath, 'package.json');
226
+ let pkgHasPrettier = false;
227
+ if (fs.existsSync(pkgPath)) {
228
+ try {
229
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
230
+ if (pkg.prettier) {
231
+ pkgHasPrettier = true;
232
+ }
233
+ } catch {}
234
+ }
235
+
236
+ if (!foundConfig && !pkgHasPrettier) {
237
+ return {
238
+ severity: SEVERITY.INFO,
239
+ message: 'No Prettier config found',
240
+ fixes: [{
241
+ type: FIX_TYPE.FILE_CREATE,
242
+ description: 'Create default Prettier config',
243
+ path: '.prettierrc',
244
+ content: JSON.stringify({ semi: true, singleQuote: true, tabWidth: 2 }, null, 2),
245
+ autoFixable: true,
246
+ }],
247
+ };
248
+ }
249
+
250
+ return {
251
+ severity: SEVERITY.PASS,
252
+ message: foundConfig || 'package.json',
253
+ metadata: { config: foundConfig || 'package.json' },
254
+ };
255
+ },
256
+ },
257
+ {
258
+ id: `${MODULE_ID}.test_framework`,
259
+ name: 'Test Framework',
260
+ category: CATEGORY.PROJECT,
261
+ parallel: true,
262
+ check: async () => {
263
+ const pkgPath = path.join(projectPath, 'package.json');
264
+ if (!fs.existsSync(pkgPath)) {
265
+ return {
266
+ severity: SEVERITY.INFO,
267
+ message: 'No package.json',
268
+ };
269
+ }
270
+
271
+ try {
272
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
273
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
274
+
275
+ const frameworks = [];
276
+
277
+ if (deps.vitest) frameworks.push({ name: 'Vitest', version: deps.vitest });
278
+ if (deps.jest) frameworks.push({ name: 'Jest', version: deps.jest });
279
+ if (deps.mocha) frameworks.push({ name: 'Mocha', version: deps.mocha });
280
+ if (deps.ava) frameworks.push({ name: 'AVA', version: deps.ava });
281
+ if (deps.playwright || deps['@playwright/test']) {
282
+ frameworks.push({ name: 'Playwright', version: deps.playwright || deps['@playwright/test'] });
283
+ }
284
+ if (deps.cypress) frameworks.push({ name: 'Cypress', version: deps.cypress });
285
+
286
+ if (frameworks.length === 0) {
287
+ return {
288
+ severity: SEVERITY.INFO,
289
+ message: 'No test framework detected',
290
+ fixes: [{
291
+ type: FIX_TYPE.COMMAND,
292
+ description: 'Install Vitest (recommended)',
293
+ command: 'npm install -D vitest',
294
+ autoFixable: false,
295
+ }],
296
+ };
297
+ }
298
+
299
+ // Check for test config files
300
+ const configFiles = [];
301
+ const testConfigs = [
302
+ 'vitest.config.ts', 'vitest.config.js',
303
+ 'jest.config.ts', 'jest.config.js', 'jest.config.json',
304
+ 'playwright.config.ts', 'playwright.config.js',
305
+ ];
306
+
307
+ for (const config of testConfigs) {
308
+ if (fs.existsSync(path.join(projectPath, config))) {
309
+ configFiles.push(config);
310
+ }
311
+ if (fs.existsSync(path.join(projectPath, 'config', config))) {
312
+ configFiles.push(`config/${config}`);
313
+ }
314
+ }
315
+
316
+ const primary = frameworks[0];
317
+ return {
318
+ severity: SEVERITY.PASS,
319
+ message: `${primary.name}${frameworks.length > 1 ? ` (+${frameworks.length - 1} more)` : ''}`,
320
+ metadata: { frameworks, configFiles },
321
+ };
322
+ } catch (err) {
323
+ return {
324
+ severity: SEVERITY.WARNING,
325
+ message: 'Could not parse package.json',
326
+ detail: err.message,
327
+ };
328
+ }
329
+ },
330
+ },
331
+ {
332
+ id: `${MODULE_ID}.bundler`,
333
+ name: 'Build/Bundler',
334
+ category: CATEGORY.PROJECT,
335
+ parallel: true,
336
+ check: async () => {
337
+ const pkgPath = path.join(projectPath, 'package.json');
338
+ if (!fs.existsSync(pkgPath)) {
339
+ return { severity: SEVERITY.INFO, message: 'No package.json' };
340
+ }
341
+
342
+ try {
343
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
344
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
345
+
346
+ const bundlers = [];
347
+
348
+ // Frameworks (which include bundlers)
349
+ if (deps.next) bundlers.push({ name: 'Next.js', version: deps.next, type: 'framework' });
350
+ if (deps.nuxt) bundlers.push({ name: 'Nuxt', version: deps.nuxt, type: 'framework' });
351
+ if (deps['@remix-run/node'] || deps.remix) bundlers.push({ name: 'Remix', type: 'framework' });
352
+ if (deps.astro) bundlers.push({ name: 'Astro', version: deps.astro, type: 'framework' });
353
+
354
+ // Bundlers
355
+ if (deps.vite) bundlers.push({ name: 'Vite', version: deps.vite, type: 'bundler' });
356
+ if (deps.webpack) bundlers.push({ name: 'Webpack', version: deps.webpack, type: 'bundler' });
357
+ if (deps.esbuild) bundlers.push({ name: 'esbuild', version: deps.esbuild, type: 'bundler' });
358
+ if (deps.rollup) bundlers.push({ name: 'Rollup', version: deps.rollup, type: 'bundler' });
359
+ if (deps.parcel) bundlers.push({ name: 'Parcel', version: deps.parcel, type: 'bundler' });
360
+ if (deps.turbo || deps.turbopack) bundlers.push({ name: 'Turbopack', type: 'bundler' });
361
+ if (deps.tsup) bundlers.push({ name: 'tsup', version: deps.tsup, type: 'bundler' });
362
+
363
+ if (bundlers.length === 0) {
364
+ return {
365
+ severity: SEVERITY.INFO,
366
+ message: 'No bundler detected (possibly Node.js project)',
367
+ metadata: { type: 'node' },
368
+ };
369
+ }
370
+
371
+ const primary = bundlers[0];
372
+ return {
373
+ severity: SEVERITY.PASS,
374
+ message: `${primary.name}${primary.version ? ` ${primary.version}` : ''}`,
375
+ metadata: { bundlers, primary: primary.name },
376
+ };
377
+ } catch (err) {
378
+ return {
379
+ severity: SEVERITY.WARNING,
380
+ message: 'Could not detect bundler',
381
+ detail: err.message,
382
+ };
383
+ }
384
+ },
385
+ },
386
+ {
387
+ id: `${MODULE_ID}.typescript_installed`,
388
+ name: 'TypeScript Installation',
389
+ category: CATEGORY.PROJECT,
390
+ parallel: true,
391
+ dependsOn: [`${MODULE_ID}.tsconfig`],
392
+ check: async () => {
393
+ const tsconfigPath = path.join(projectPath, 'tsconfig.json');
394
+ if (!fs.existsSync(tsconfigPath)) {
395
+ return {
396
+ severity: SEVERITY.INFO,
397
+ message: 'Not applicable (no tsconfig.json)',
398
+ };
399
+ }
400
+
401
+ // Check if TypeScript is installed
402
+ try {
403
+ const version = execSync('npx tsc --version', {
404
+ cwd: projectPath,
405
+ encoding: 'utf8',
406
+ timeout: 15000,
407
+ stdio: ['pipe', 'pipe', 'pipe'],
408
+ }).trim();
409
+
410
+ const match = version.match(/Version\s+(\d+\.\d+\.\d+)/);
411
+ const versionNum = match ? match[1] : version;
412
+ const major = parseInt(versionNum.split('.')[0]);
413
+
414
+ const metadata = { version: versionNum, major };
415
+
416
+ if (major < 5) {
417
+ return {
418
+ severity: SEVERITY.WARNING,
419
+ message: `${versionNum} — recommend TypeScript 5+`,
420
+ metadata,
421
+ fixes: [{
422
+ type: FIX_TYPE.COMMAND,
423
+ description: 'Update TypeScript',
424
+ command: 'npm install -D typescript@latest',
425
+ autoFixable: true,
426
+ }],
427
+ };
428
+ }
429
+
430
+ return {
431
+ severity: SEVERITY.PASS,
432
+ message: versionNum,
433
+ metadata,
434
+ };
435
+ } catch (err) {
436
+ return {
437
+ severity: SEVERITY.ERROR,
438
+ message: 'TypeScript not installed',
439
+ detail: 'tsconfig.json exists but TypeScript is not installed',
440
+ fixes: [{
441
+ type: FIX_TYPE.COMMAND,
442
+ description: 'Install TypeScript',
443
+ command: 'npm install -D typescript',
444
+ autoFixable: true,
445
+ }],
446
+ };
447
+ }
448
+ },
449
+ },
450
+ ];
451
+ }
452
+
453
+ module.exports = { MODULE_ID, createDiagnostics };
@@ -1,7 +1,19 @@
1
1
  /**
2
2
  * Diagnostic Modules Index
3
3
  *
4
- * Exports all diagnostic modules for the Doctor service
4
+ * Exports all diagnostic modules for the Doctor service.
5
+ *
6
+ * Modules:
7
+ * - system: OS, memory, disk, CPU resources
8
+ * - runtime: Node.js, npm, package managers
9
+ * - project: package.json, dependencies, config files
10
+ * - dependencies: Outdated packages, vulnerabilities
11
+ * - security: Secrets, gitignore, env files
12
+ * - network: Internet, npm registry, API connectivity
13
+ * - vibecheck: Config, truth pack, scan status
14
+ * - buildTools: TypeScript, ESLint, Prettier, test frameworks
15
+ * - repoIntegrity: Git state, lock files, caches
16
+ * - osQuirks: Windows/macOS/Linux specific checks
5
17
  */
6
18
 
7
19
  const system = require('./system');
@@ -11,11 +23,17 @@ const dependencies = require('./dependencies');
11
23
  const security = require('./security');
12
24
  const network = require('./network');
13
25
  const vibecheck = require('./vibecheck');
26
+ const buildTools = require('./build-tools');
27
+ const repoIntegrity = require('./repo-integrity');
28
+ const osQuirks = require('./os-quirks');
14
29
 
15
30
  const ALL_MODULES = [
16
31
  system,
32
+ osQuirks, // OS-specific after system
17
33
  runtime,
34
+ buildTools, // Build tools after runtime
18
35
  project,
36
+ repoIntegrity, // Repo integrity with project
19
37
  dependencies,
20
38
  security,
21
39
  network,
@@ -26,13 +44,49 @@ function getAllDiagnostics(projectPath) {
26
44
  const diagnostics = [];
27
45
 
28
46
  for (const mod of ALL_MODULES) {
29
- const moduleDiagnostics = mod.createDiagnostics(projectPath);
30
- diagnostics.push(...moduleDiagnostics);
47
+ try {
48
+ const moduleDiagnostics = mod.createDiagnostics(projectPath);
49
+ diagnostics.push(...moduleDiagnostics);
50
+ } catch (err) {
51
+ // If a module fails to load, log but continue
52
+ console.error(`Warning: Could not load diagnostics from ${mod.MODULE_ID || 'unknown'}: ${err.message}`);
53
+ }
31
54
  }
32
55
 
33
56
  return diagnostics;
34
57
  }
35
58
 
59
+ /**
60
+ * Get diagnostics for specific categories only
61
+ * @param {string} projectPath - Project path
62
+ * @param {string[]} categories - Categories to include
63
+ * @returns {object[]} Filtered diagnostics
64
+ */
65
+ function getDiagnosticsByCategory(projectPath, categories) {
66
+ const all = getAllDiagnostics(projectPath);
67
+ return all.filter(d => categories.includes(d.category));
68
+ }
69
+
70
+ /**
71
+ * Get a count of diagnostics by module
72
+ * @param {string} projectPath - Project path
73
+ * @returns {object} Module -> count mapping
74
+ */
75
+ function getDiagnosticCounts(projectPath) {
76
+ const counts = {};
77
+
78
+ for (const mod of ALL_MODULES) {
79
+ try {
80
+ const diagnostics = mod.createDiagnostics(projectPath);
81
+ counts[mod.MODULE_ID] = diagnostics.length;
82
+ } catch {
83
+ counts[mod.MODULE_ID] = 0;
84
+ }
85
+ }
86
+
87
+ return counts;
88
+ }
89
+
36
90
  module.exports = {
37
91
  system,
38
92
  runtime,
@@ -41,6 +95,11 @@ module.exports = {
41
95
  security,
42
96
  network,
43
97
  vibecheck,
98
+ buildTools,
99
+ repoIntegrity,
100
+ osQuirks,
44
101
  ALL_MODULES,
45
102
  getAllDiagnostics,
103
+ getDiagnosticsByCategory,
104
+ getDiagnosticCounts,
46
105
  };