@vibecheckai/cli 3.2.4 → 3.2.6
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.
- package/bin/.generated +25 -25
- package/bin/dev/run-v2-torture.js +30 -30
- package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
- package/bin/runners/lib/api-client.js +269 -0
- package/bin/runners/lib/auth-truth.js +193 -193
- package/bin/runners/lib/backup.js +62 -62
- package/bin/runners/lib/billing.js +107 -107
- package/bin/runners/lib/claims.js +118 -118
- package/bin/runners/lib/cli-ui.js +540 -540
- package/bin/runners/lib/contracts/auth-contract.js +202 -202
- package/bin/runners/lib/contracts/env-contract.js +181 -181
- package/bin/runners/lib/contracts/external-contract.js +206 -206
- package/bin/runners/lib/contracts/guard.js +168 -168
- package/bin/runners/lib/contracts/index.js +89 -89
- package/bin/runners/lib/contracts/plan-validator.js +311 -311
- package/bin/runners/lib/contracts/route-contract.js +199 -199
- package/bin/runners/lib/contracts.js +804 -804
- package/bin/runners/lib/detect.js +89 -89
- package/bin/runners/lib/doctor/autofix.js +254 -254
- package/bin/runners/lib/doctor/index.js +37 -37
- package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
- package/bin/runners/lib/doctor/modules/index.js +46 -46
- package/bin/runners/lib/doctor/modules/network.js +250 -250
- package/bin/runners/lib/doctor/modules/project.js +312 -312
- package/bin/runners/lib/doctor/modules/runtime.js +224 -224
- package/bin/runners/lib/doctor/modules/security.js +348 -348
- package/bin/runners/lib/doctor/modules/system.js +213 -213
- package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
- package/bin/runners/lib/doctor/reporter.js +262 -262
- package/bin/runners/lib/doctor/service.js +262 -262
- package/bin/runners/lib/doctor/types.js +113 -113
- package/bin/runners/lib/doctor/ui.js +263 -263
- package/bin/runners/lib/doctor-v2.js +608 -608
- package/bin/runners/lib/drift.js +425 -425
- package/bin/runners/lib/enforcement.js +72 -72
- package/bin/runners/lib/enterprise-detect.js +603 -603
- package/bin/runners/lib/enterprise-init.js +942 -942
- package/bin/runners/lib/env-resolver.js +417 -417
- package/bin/runners/lib/env-template.js +66 -66
- package/bin/runners/lib/env.js +189 -189
- package/bin/runners/lib/extractors/client-calls.js +990 -990
- package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
- package/bin/runners/lib/extractors/fastify-routes.js +426 -426
- package/bin/runners/lib/extractors/index.js +363 -363
- package/bin/runners/lib/extractors/next-routes.js +524 -524
- package/bin/runners/lib/extractors/proof-graph.js +431 -431
- package/bin/runners/lib/extractors/route-matcher.js +451 -451
- package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
- package/bin/runners/lib/extractors/ui-bindings.js +547 -547
- package/bin/runners/lib/findings-schema.js +281 -281
- package/bin/runners/lib/firewall-prompt.js +50 -50
- package/bin/runners/lib/graph/graph-builder.js +265 -265
- package/bin/runners/lib/graph/html-renderer.js +413 -413
- package/bin/runners/lib/graph/index.js +32 -32
- package/bin/runners/lib/graph/runtime-collector.js +215 -215
- package/bin/runners/lib/graph/static-extractor.js +518 -518
- package/bin/runners/lib/html-report.js +650 -650
- package/bin/runners/lib/llm.js +75 -75
- package/bin/runners/lib/meter.js +61 -61
- package/bin/runners/lib/missions/evidence.js +126 -126
- package/bin/runners/lib/patch.js +40 -40
- package/bin/runners/lib/permissions/auth-model.js +213 -213
- package/bin/runners/lib/permissions/idor-prover.js +205 -205
- package/bin/runners/lib/permissions/index.js +45 -45
- package/bin/runners/lib/permissions/matrix-builder.js +198 -198
- package/bin/runners/lib/pkgjson.js +28 -28
- package/bin/runners/lib/policy.js +295 -295
- package/bin/runners/lib/preflight.js +142 -142
- package/bin/runners/lib/reality/correlation-detectors.js +359 -359
- package/bin/runners/lib/reality/index.js +318 -318
- package/bin/runners/lib/reality/request-hashing.js +416 -416
- package/bin/runners/lib/reality/request-mapper.js +453 -453
- package/bin/runners/lib/reality/safety-rails.js +463 -463
- package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
- package/bin/runners/lib/reality/toast-detector.js +393 -393
- package/bin/runners/lib/reality-findings.js +84 -84
- package/bin/runners/lib/receipts.js +179 -179
- package/bin/runners/lib/redact.js +29 -29
- package/bin/runners/lib/replay/capsule-manager.js +154 -154
- package/bin/runners/lib/replay/index.js +263 -263
- package/bin/runners/lib/replay/player.js +348 -348
- package/bin/runners/lib/replay/recorder.js +331 -331
- package/bin/runners/lib/report.js +135 -135
- package/bin/runners/lib/route-detection.js +1140 -1140
- package/bin/runners/lib/sandbox/index.js +59 -59
- package/bin/runners/lib/sandbox/proof-chain.js +399 -399
- package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
- package/bin/runners/lib/sandbox/worktree.js +174 -174
- package/bin/runners/lib/schema-validator.js +350 -350
- package/bin/runners/lib/schemas/contracts.schema.json +160 -160
- package/bin/runners/lib/schemas/finding.schema.json +100 -100
- package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
- package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
- package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
- package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
- package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
- package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
- package/bin/runners/lib/schemas/validator.js +438 -438
- package/bin/runners/lib/score-history.js +282 -282
- package/bin/runners/lib/share-pack.js +239 -239
- package/bin/runners/lib/snippets.js +67 -67
- package/bin/runners/lib/upsell.js +510 -510
- package/bin/runners/lib/usage.js +153 -153
- package/bin/runners/lib/validate-patch.js +156 -156
- package/bin/runners/lib/verdict-engine.js +628 -628
- package/bin/runners/reality/engine.js +917 -917
- package/bin/runners/reality/flows.js +122 -122
- package/bin/runners/reality/report.js +378 -378
- package/bin/runners/reality/session.js +193 -193
- package/bin/runners/runAgent.d.ts +5 -0
- package/bin/runners/runFirewall.d.ts +5 -0
- package/bin/runners/runFirewallHook.d.ts +5 -0
- package/bin/runners/runGuard.js +168 -168
- package/bin/runners/runScan.js +82 -0
- package/bin/runners/runTruth.d.ts +5 -0
- package/bin/vibecheck.js +45 -20
- package/mcp-server/index.js +85 -0
- package/mcp-server/lib/api-client.js +269 -0
- package/mcp-server/package.json +1 -1
- package/mcp-server/tier-auth.js +173 -113
- package/mcp-server/tools/index.js +72 -72
- package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
- package/package.json +1 -1
|
@@ -1,312 +1,312 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project Diagnostics Module
|
|
3
|
-
*
|
|
4
|
-
* Checks project structure, configuration, and build capability
|
|
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 = 'project';
|
|
13
|
-
|
|
14
|
-
function createDiagnostics(projectPath) {
|
|
15
|
-
return [
|
|
16
|
-
{
|
|
17
|
-
id: `${MODULE_ID}.package_json`,
|
|
18
|
-
name: 'package.json',
|
|
19
|
-
category: CATEGORY.PROJECT,
|
|
20
|
-
parallel: true,
|
|
21
|
-
check: async () => {
|
|
22
|
-
const pkgPath = path.join(projectPath, 'package.json');
|
|
23
|
-
|
|
24
|
-
if (!fs.existsSync(pkgPath)) {
|
|
25
|
-
return {
|
|
26
|
-
severity: SEVERITY.ERROR,
|
|
27
|
-
message: 'Not found',
|
|
28
|
-
detail: 'This doesn\'t appear to be a Node.js project',
|
|
29
|
-
fixes: [
|
|
30
|
-
{
|
|
31
|
-
type: FIX_TYPE.COMMAND,
|
|
32
|
-
description: 'Initialize a new Node.js project',
|
|
33
|
-
command: 'npm init -y',
|
|
34
|
-
autoFixable: true,
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
42
|
-
const metadata = {
|
|
43
|
-
name: pkg.name,
|
|
44
|
-
version: pkg.version,
|
|
45
|
-
hasScripts: !!pkg.scripts,
|
|
46
|
-
hasDeps: !!(pkg.dependencies || pkg.devDependencies),
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
severity: SEVERITY.PASS,
|
|
51
|
-
message: `${pkg.name || 'unnamed'}@${pkg.version || '0.0.0'}`,
|
|
52
|
-
metadata,
|
|
53
|
-
};
|
|
54
|
-
} catch (err) {
|
|
55
|
-
return {
|
|
56
|
-
severity: SEVERITY.ERROR,
|
|
57
|
-
message: 'Invalid JSON',
|
|
58
|
-
detail: err.message,
|
|
59
|
-
fixes: [{
|
|
60
|
-
type: FIX_TYPE.MANUAL,
|
|
61
|
-
description: 'Fix JSON syntax errors in package.json',
|
|
62
|
-
autoFixable: false,
|
|
63
|
-
}],
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
id: `${MODULE_ID}.node_modules`,
|
|
70
|
-
name: 'Dependencies Installed',
|
|
71
|
-
category: CATEGORY.PROJECT,
|
|
72
|
-
parallel: true,
|
|
73
|
-
dependsOn: [`${MODULE_ID}.package_json`],
|
|
74
|
-
check: async () => {
|
|
75
|
-
const nodeModulesPath = path.join(projectPath, 'node_modules');
|
|
76
|
-
|
|
77
|
-
if (!fs.existsSync(nodeModulesPath)) {
|
|
78
|
-
return {
|
|
79
|
-
severity: SEVERITY.WARNING,
|
|
80
|
-
message: 'node_modules not found',
|
|
81
|
-
detail: 'Run your package manager install command',
|
|
82
|
-
fixes: [
|
|
83
|
-
{
|
|
84
|
-
type: FIX_TYPE.COMMAND,
|
|
85
|
-
description: 'Install dependencies with pnpm',
|
|
86
|
-
command: 'pnpm install',
|
|
87
|
-
autoFixable: true,
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
type: FIX_TYPE.COMMAND,
|
|
91
|
-
description: 'Install dependencies with npm',
|
|
92
|
-
command: 'npm install',
|
|
93
|
-
autoFixable: true,
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
try {
|
|
100
|
-
const entries = fs.readdirSync(nodeModulesPath).filter(f => !f.startsWith('.'));
|
|
101
|
-
const count = entries.length;
|
|
102
|
-
|
|
103
|
-
// Check for common issues
|
|
104
|
-
const lockFiles = ['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock']
|
|
105
|
-
.filter(f => fs.existsSync(path.join(projectPath, f)));
|
|
106
|
-
|
|
107
|
-
const metadata = { packageCount: count, lockFiles };
|
|
108
|
-
|
|
109
|
-
if (lockFiles.length > 1) {
|
|
110
|
-
return {
|
|
111
|
-
severity: SEVERITY.WARNING,
|
|
112
|
-
message: `${count} packages (multiple lock files detected)`,
|
|
113
|
-
detail: `Found: ${lockFiles.join(', ')}`,
|
|
114
|
-
metadata,
|
|
115
|
-
fixes: [{
|
|
116
|
-
type: FIX_TYPE.MANUAL,
|
|
117
|
-
description: 'Remove extra lock files to avoid conflicts',
|
|
118
|
-
autoFixable: false,
|
|
119
|
-
}],
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
severity: SEVERITY.PASS,
|
|
125
|
-
message: `${count} packages installed`,
|
|
126
|
-
metadata,
|
|
127
|
-
};
|
|
128
|
-
} catch {
|
|
129
|
-
return {
|
|
130
|
-
severity: SEVERITY.WARNING,
|
|
131
|
-
message: 'Cannot read node_modules',
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
id: `${MODULE_ID}.typescript`,
|
|
138
|
-
name: 'TypeScript',
|
|
139
|
-
category: CATEGORY.PROJECT,
|
|
140
|
-
parallel: true,
|
|
141
|
-
check: async () => {
|
|
142
|
-
const tsConfigPath = path.join(projectPath, 'tsconfig.json');
|
|
143
|
-
|
|
144
|
-
if (!fs.existsSync(tsConfigPath)) {
|
|
145
|
-
return {
|
|
146
|
-
severity: SEVERITY.INFO,
|
|
147
|
-
message: 'Not configured (JavaScript project)',
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
try {
|
|
152
|
-
const tsConfig = JSON.parse(fs.readFileSync(tsConfigPath, 'utf8'));
|
|
153
|
-
const strict = tsConfig.compilerOptions?.strict === true;
|
|
154
|
-
|
|
155
|
-
const metadata = {
|
|
156
|
-
strict,
|
|
157
|
-
target: tsConfig.compilerOptions?.target,
|
|
158
|
-
module: tsConfig.compilerOptions?.module,
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
if (!strict) {
|
|
162
|
-
return {
|
|
163
|
-
severity: SEVERITY.INFO,
|
|
164
|
-
message: 'Configured (strict mode disabled)',
|
|
165
|
-
metadata,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
severity: SEVERITY.PASS,
|
|
171
|
-
message: 'Configured with strict mode',
|
|
172
|
-
metadata,
|
|
173
|
-
};
|
|
174
|
-
} catch {
|
|
175
|
-
return {
|
|
176
|
-
severity: SEVERITY.WARNING,
|
|
177
|
-
message: 'Invalid tsconfig.json',
|
|
178
|
-
fixes: [{
|
|
179
|
-
type: FIX_TYPE.COMMAND,
|
|
180
|
-
description: 'Regenerate TypeScript config',
|
|
181
|
-
command: 'npx tsc --init',
|
|
182
|
-
autoFixable: false,
|
|
183
|
-
}],
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
id: `${MODULE_ID}.source_structure`,
|
|
190
|
-
name: 'Source Structure',
|
|
191
|
-
category: CATEGORY.PROJECT,
|
|
192
|
-
parallel: true,
|
|
193
|
-
check: async () => {
|
|
194
|
-
const structures = [
|
|
195
|
-
{ dir: 'src', type: 'standard' },
|
|
196
|
-
{ dir: 'app', type: 'next-app-router' },
|
|
197
|
-
{ dir: 'pages', type: 'next-pages-router' },
|
|
198
|
-
{ dir: 'lib', type: 'library' },
|
|
199
|
-
{ dir: 'packages', type: 'monorepo' },
|
|
200
|
-
];
|
|
201
|
-
|
|
202
|
-
const found = structures.filter(s =>
|
|
203
|
-
fs.existsSync(path.join(projectPath, s.dir))
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
if (found.length === 0) {
|
|
207
|
-
return {
|
|
208
|
-
severity: SEVERITY.INFO,
|
|
209
|
-
message: 'No standard source directory detected',
|
|
210
|
-
detail: 'Consider organizing code in src/, app/, or pages/',
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const metadata = { structures: found.map(f => f.type) };
|
|
215
|
-
const primary = found[0];
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
severity: SEVERITY.PASS,
|
|
219
|
-
message: `${primary.dir}/ (${primary.type})`,
|
|
220
|
-
metadata,
|
|
221
|
-
};
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
id: `${MODULE_ID}.framework`,
|
|
226
|
-
name: 'Framework Detection',
|
|
227
|
-
category: CATEGORY.PROJECT,
|
|
228
|
-
parallel: true,
|
|
229
|
-
dependsOn: [`${MODULE_ID}.package_json`],
|
|
230
|
-
check: async () => {
|
|
231
|
-
const pkgPath = path.join(projectPath, 'package.json');
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
235
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
236
|
-
|
|
237
|
-
const frameworks = [
|
|
238
|
-
{ name: 'Next.js', packages: ['next'] },
|
|
239
|
-
{ name: 'Remix', packages: ['@remix-run/node', '@remix-run/react'] },
|
|
240
|
-
{ name: 'Fastify', packages: ['fastify'] },
|
|
241
|
-
{ name: 'Express', packages: ['express'] },
|
|
242
|
-
{ name: 'Hono', packages: ['hono'] },
|
|
243
|
-
{ name: 'NestJS', packages: ['@nestjs/core'] },
|
|
244
|
-
{ name: 'React', packages: ['react'] },
|
|
245
|
-
{ name: 'Vue', packages: ['vue'] },
|
|
246
|
-
{ name: 'Svelte', packages: ['svelte'] },
|
|
247
|
-
];
|
|
248
|
-
|
|
249
|
-
const detected = frameworks.filter(fw =>
|
|
250
|
-
fw.packages.some(p => deps[p])
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
if (detected.length === 0) {
|
|
254
|
-
return {
|
|
255
|
-
severity: SEVERITY.INFO,
|
|
256
|
-
message: 'No known framework detected',
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const metadata = { frameworks: detected.map(f => f.name) };
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
severity: SEVERITY.PASS,
|
|
264
|
-
message: detected.map(f => f.name).join(' + '),
|
|
265
|
-
metadata,
|
|
266
|
-
};
|
|
267
|
-
} catch {
|
|
268
|
-
return {
|
|
269
|
-
severity: SEVERITY.INFO,
|
|
270
|
-
message: 'Could not detect framework',
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
id: `${MODULE_ID}.build`,
|
|
277
|
-
name: 'Build Script',
|
|
278
|
-
category: CATEGORY.PROJECT,
|
|
279
|
-
parallel: true,
|
|
280
|
-
dependsOn: [`${MODULE_ID}.package_json`],
|
|
281
|
-
check: async () => {
|
|
282
|
-
const pkgPath = path.join(projectPath, 'package.json');
|
|
283
|
-
|
|
284
|
-
try {
|
|
285
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
286
|
-
|
|
287
|
-
if (!pkg.scripts?.build) {
|
|
288
|
-
return {
|
|
289
|
-
severity: SEVERITY.INFO,
|
|
290
|
-
message: 'No build script defined',
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const metadata = { buildCommand: pkg.scripts.build };
|
|
295
|
-
|
|
296
|
-
return {
|
|
297
|
-
severity: SEVERITY.PASS,
|
|
298
|
-
message: `Defined: ${pkg.scripts.build.substring(0, 40)}${pkg.scripts.build.length > 40 ? '...' : ''}`,
|
|
299
|
-
metadata,
|
|
300
|
-
};
|
|
301
|
-
} catch {
|
|
302
|
-
return {
|
|
303
|
-
severity: SEVERITY.INFO,
|
|
304
|
-
message: 'Could not check build script',
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
];
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
module.exports = { MODULE_ID, createDiagnostics };
|
|
1
|
+
/**
|
|
2
|
+
* Project Diagnostics Module
|
|
3
|
+
*
|
|
4
|
+
* Checks project structure, configuration, and build capability
|
|
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 = 'project';
|
|
13
|
+
|
|
14
|
+
function createDiagnostics(projectPath) {
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
id: `${MODULE_ID}.package_json`,
|
|
18
|
+
name: 'package.json',
|
|
19
|
+
category: CATEGORY.PROJECT,
|
|
20
|
+
parallel: true,
|
|
21
|
+
check: async () => {
|
|
22
|
+
const pkgPath = path.join(projectPath, 'package.json');
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(pkgPath)) {
|
|
25
|
+
return {
|
|
26
|
+
severity: SEVERITY.ERROR,
|
|
27
|
+
message: 'Not found',
|
|
28
|
+
detail: 'This doesn\'t appear to be a Node.js project',
|
|
29
|
+
fixes: [
|
|
30
|
+
{
|
|
31
|
+
type: FIX_TYPE.COMMAND,
|
|
32
|
+
description: 'Initialize a new Node.js project',
|
|
33
|
+
command: 'npm init -y',
|
|
34
|
+
autoFixable: true,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
42
|
+
const metadata = {
|
|
43
|
+
name: pkg.name,
|
|
44
|
+
version: pkg.version,
|
|
45
|
+
hasScripts: !!pkg.scripts,
|
|
46
|
+
hasDeps: !!(pkg.dependencies || pkg.devDependencies),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
severity: SEVERITY.PASS,
|
|
51
|
+
message: `${pkg.name || 'unnamed'}@${pkg.version || '0.0.0'}`,
|
|
52
|
+
metadata,
|
|
53
|
+
};
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return {
|
|
56
|
+
severity: SEVERITY.ERROR,
|
|
57
|
+
message: 'Invalid JSON',
|
|
58
|
+
detail: err.message,
|
|
59
|
+
fixes: [{
|
|
60
|
+
type: FIX_TYPE.MANUAL,
|
|
61
|
+
description: 'Fix JSON syntax errors in package.json',
|
|
62
|
+
autoFixable: false,
|
|
63
|
+
}],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: `${MODULE_ID}.node_modules`,
|
|
70
|
+
name: 'Dependencies Installed',
|
|
71
|
+
category: CATEGORY.PROJECT,
|
|
72
|
+
parallel: true,
|
|
73
|
+
dependsOn: [`${MODULE_ID}.package_json`],
|
|
74
|
+
check: async () => {
|
|
75
|
+
const nodeModulesPath = path.join(projectPath, 'node_modules');
|
|
76
|
+
|
|
77
|
+
if (!fs.existsSync(nodeModulesPath)) {
|
|
78
|
+
return {
|
|
79
|
+
severity: SEVERITY.WARNING,
|
|
80
|
+
message: 'node_modules not found',
|
|
81
|
+
detail: 'Run your package manager install command',
|
|
82
|
+
fixes: [
|
|
83
|
+
{
|
|
84
|
+
type: FIX_TYPE.COMMAND,
|
|
85
|
+
description: 'Install dependencies with pnpm',
|
|
86
|
+
command: 'pnpm install',
|
|
87
|
+
autoFixable: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: FIX_TYPE.COMMAND,
|
|
91
|
+
description: 'Install dependencies with npm',
|
|
92
|
+
command: 'npm install',
|
|
93
|
+
autoFixable: true,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const entries = fs.readdirSync(nodeModulesPath).filter(f => !f.startsWith('.'));
|
|
101
|
+
const count = entries.length;
|
|
102
|
+
|
|
103
|
+
// Check for common issues
|
|
104
|
+
const lockFiles = ['pnpm-lock.yaml', 'package-lock.json', 'yarn.lock']
|
|
105
|
+
.filter(f => fs.existsSync(path.join(projectPath, f)));
|
|
106
|
+
|
|
107
|
+
const metadata = { packageCount: count, lockFiles };
|
|
108
|
+
|
|
109
|
+
if (lockFiles.length > 1) {
|
|
110
|
+
return {
|
|
111
|
+
severity: SEVERITY.WARNING,
|
|
112
|
+
message: `${count} packages (multiple lock files detected)`,
|
|
113
|
+
detail: `Found: ${lockFiles.join(', ')}`,
|
|
114
|
+
metadata,
|
|
115
|
+
fixes: [{
|
|
116
|
+
type: FIX_TYPE.MANUAL,
|
|
117
|
+
description: 'Remove extra lock files to avoid conflicts',
|
|
118
|
+
autoFixable: false,
|
|
119
|
+
}],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
severity: SEVERITY.PASS,
|
|
125
|
+
message: `${count} packages installed`,
|
|
126
|
+
metadata,
|
|
127
|
+
};
|
|
128
|
+
} catch {
|
|
129
|
+
return {
|
|
130
|
+
severity: SEVERITY.WARNING,
|
|
131
|
+
message: 'Cannot read node_modules',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: `${MODULE_ID}.typescript`,
|
|
138
|
+
name: 'TypeScript',
|
|
139
|
+
category: CATEGORY.PROJECT,
|
|
140
|
+
parallel: true,
|
|
141
|
+
check: async () => {
|
|
142
|
+
const tsConfigPath = path.join(projectPath, 'tsconfig.json');
|
|
143
|
+
|
|
144
|
+
if (!fs.existsSync(tsConfigPath)) {
|
|
145
|
+
return {
|
|
146
|
+
severity: SEVERITY.INFO,
|
|
147
|
+
message: 'Not configured (JavaScript project)',
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const tsConfig = JSON.parse(fs.readFileSync(tsConfigPath, 'utf8'));
|
|
153
|
+
const strict = tsConfig.compilerOptions?.strict === true;
|
|
154
|
+
|
|
155
|
+
const metadata = {
|
|
156
|
+
strict,
|
|
157
|
+
target: tsConfig.compilerOptions?.target,
|
|
158
|
+
module: tsConfig.compilerOptions?.module,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
if (!strict) {
|
|
162
|
+
return {
|
|
163
|
+
severity: SEVERITY.INFO,
|
|
164
|
+
message: 'Configured (strict mode disabled)',
|
|
165
|
+
metadata,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
severity: SEVERITY.PASS,
|
|
171
|
+
message: 'Configured with strict mode',
|
|
172
|
+
metadata,
|
|
173
|
+
};
|
|
174
|
+
} catch {
|
|
175
|
+
return {
|
|
176
|
+
severity: SEVERITY.WARNING,
|
|
177
|
+
message: 'Invalid tsconfig.json',
|
|
178
|
+
fixes: [{
|
|
179
|
+
type: FIX_TYPE.COMMAND,
|
|
180
|
+
description: 'Regenerate TypeScript config',
|
|
181
|
+
command: 'npx tsc --init',
|
|
182
|
+
autoFixable: false,
|
|
183
|
+
}],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: `${MODULE_ID}.source_structure`,
|
|
190
|
+
name: 'Source Structure',
|
|
191
|
+
category: CATEGORY.PROJECT,
|
|
192
|
+
parallel: true,
|
|
193
|
+
check: async () => {
|
|
194
|
+
const structures = [
|
|
195
|
+
{ dir: 'src', type: 'standard' },
|
|
196
|
+
{ dir: 'app', type: 'next-app-router' },
|
|
197
|
+
{ dir: 'pages', type: 'next-pages-router' },
|
|
198
|
+
{ dir: 'lib', type: 'library' },
|
|
199
|
+
{ dir: 'packages', type: 'monorepo' },
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
const found = structures.filter(s =>
|
|
203
|
+
fs.existsSync(path.join(projectPath, s.dir))
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
if (found.length === 0) {
|
|
207
|
+
return {
|
|
208
|
+
severity: SEVERITY.INFO,
|
|
209
|
+
message: 'No standard source directory detected',
|
|
210
|
+
detail: 'Consider organizing code in src/, app/, or pages/',
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const metadata = { structures: found.map(f => f.type) };
|
|
215
|
+
const primary = found[0];
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
severity: SEVERITY.PASS,
|
|
219
|
+
message: `${primary.dir}/ (${primary.type})`,
|
|
220
|
+
metadata,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
id: `${MODULE_ID}.framework`,
|
|
226
|
+
name: 'Framework Detection',
|
|
227
|
+
category: CATEGORY.PROJECT,
|
|
228
|
+
parallel: true,
|
|
229
|
+
dependsOn: [`${MODULE_ID}.package_json`],
|
|
230
|
+
check: async () => {
|
|
231
|
+
const pkgPath = path.join(projectPath, 'package.json');
|
|
232
|
+
|
|
233
|
+
try {
|
|
234
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
235
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
236
|
+
|
|
237
|
+
const frameworks = [
|
|
238
|
+
{ name: 'Next.js', packages: ['next'] },
|
|
239
|
+
{ name: 'Remix', packages: ['@remix-run/node', '@remix-run/react'] },
|
|
240
|
+
{ name: 'Fastify', packages: ['fastify'] },
|
|
241
|
+
{ name: 'Express', packages: ['express'] },
|
|
242
|
+
{ name: 'Hono', packages: ['hono'] },
|
|
243
|
+
{ name: 'NestJS', packages: ['@nestjs/core'] },
|
|
244
|
+
{ name: 'React', packages: ['react'] },
|
|
245
|
+
{ name: 'Vue', packages: ['vue'] },
|
|
246
|
+
{ name: 'Svelte', packages: ['svelte'] },
|
|
247
|
+
];
|
|
248
|
+
|
|
249
|
+
const detected = frameworks.filter(fw =>
|
|
250
|
+
fw.packages.some(p => deps[p])
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (detected.length === 0) {
|
|
254
|
+
return {
|
|
255
|
+
severity: SEVERITY.INFO,
|
|
256
|
+
message: 'No known framework detected',
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const metadata = { frameworks: detected.map(f => f.name) };
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
severity: SEVERITY.PASS,
|
|
264
|
+
message: detected.map(f => f.name).join(' + '),
|
|
265
|
+
metadata,
|
|
266
|
+
};
|
|
267
|
+
} catch {
|
|
268
|
+
return {
|
|
269
|
+
severity: SEVERITY.INFO,
|
|
270
|
+
message: 'Could not detect framework',
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
id: `${MODULE_ID}.build`,
|
|
277
|
+
name: 'Build Script',
|
|
278
|
+
category: CATEGORY.PROJECT,
|
|
279
|
+
parallel: true,
|
|
280
|
+
dependsOn: [`${MODULE_ID}.package_json`],
|
|
281
|
+
check: async () => {
|
|
282
|
+
const pkgPath = path.join(projectPath, 'package.json');
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
286
|
+
|
|
287
|
+
if (!pkg.scripts?.build) {
|
|
288
|
+
return {
|
|
289
|
+
severity: SEVERITY.INFO,
|
|
290
|
+
message: 'No build script defined',
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const metadata = { buildCommand: pkg.scripts.build };
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
severity: SEVERITY.PASS,
|
|
298
|
+
message: `Defined: ${pkg.scripts.build.substring(0, 40)}${pkg.scripts.build.length > 40 ? '...' : ''}`,
|
|
299
|
+
metadata,
|
|
300
|
+
};
|
|
301
|
+
} catch {
|
|
302
|
+
return {
|
|
303
|
+
severity: SEVERITY.INFO,
|
|
304
|
+
message: 'Could not check build script',
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
module.exports = { MODULE_ID, createDiagnostics };
|