@grafema/cli 0.1.1-alpha → 0.2.1-beta

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 (79) hide show
  1. package/dist/cli.js +10 -0
  2. package/dist/commands/analyze.d.ts.map +1 -1
  3. package/dist/commands/analyze.js +69 -11
  4. package/dist/commands/check.d.ts +6 -0
  5. package/dist/commands/check.d.ts.map +1 -1
  6. package/dist/commands/check.js +177 -1
  7. package/dist/commands/coverage.d.ts.map +1 -1
  8. package/dist/commands/coverage.js +7 -0
  9. package/dist/commands/doctor/checks.d.ts +55 -0
  10. package/dist/commands/doctor/checks.d.ts.map +1 -0
  11. package/dist/commands/doctor/checks.js +534 -0
  12. package/dist/commands/doctor/output.d.ts +20 -0
  13. package/dist/commands/doctor/output.d.ts.map +1 -0
  14. package/dist/commands/doctor/output.js +94 -0
  15. package/dist/commands/doctor/types.d.ts +42 -0
  16. package/dist/commands/doctor/types.d.ts.map +1 -0
  17. package/dist/commands/doctor/types.js +4 -0
  18. package/dist/commands/doctor.d.ts +17 -0
  19. package/dist/commands/doctor.d.ts.map +1 -0
  20. package/dist/commands/doctor.js +80 -0
  21. package/dist/commands/explain.d.ts +16 -0
  22. package/dist/commands/explain.d.ts.map +1 -0
  23. package/dist/commands/explain.js +145 -0
  24. package/dist/commands/explore.d.ts +7 -1
  25. package/dist/commands/explore.d.ts.map +1 -1
  26. package/dist/commands/explore.js +204 -85
  27. package/dist/commands/get.d.ts.map +1 -1
  28. package/dist/commands/get.js +16 -4
  29. package/dist/commands/impact.d.ts.map +1 -1
  30. package/dist/commands/impact.js +48 -50
  31. package/dist/commands/init.d.ts.map +1 -1
  32. package/dist/commands/init.js +93 -15
  33. package/dist/commands/ls.d.ts +14 -0
  34. package/dist/commands/ls.d.ts.map +1 -0
  35. package/dist/commands/ls.js +132 -0
  36. package/dist/commands/overview.d.ts.map +1 -1
  37. package/dist/commands/overview.js +15 -2
  38. package/dist/commands/query.d.ts +98 -0
  39. package/dist/commands/query.d.ts.map +1 -1
  40. package/dist/commands/query.js +549 -136
  41. package/dist/commands/schema.d.ts +13 -0
  42. package/dist/commands/schema.d.ts.map +1 -0
  43. package/dist/commands/schema.js +279 -0
  44. package/dist/commands/server.d.ts.map +1 -1
  45. package/dist/commands/server.js +13 -6
  46. package/dist/commands/stats.d.ts.map +1 -1
  47. package/dist/commands/stats.js +7 -0
  48. package/dist/commands/trace.d.ts +73 -0
  49. package/dist/commands/trace.d.ts.map +1 -1
  50. package/dist/commands/trace.js +500 -5
  51. package/dist/commands/types.d.ts +12 -0
  52. package/dist/commands/types.d.ts.map +1 -0
  53. package/dist/commands/types.js +79 -0
  54. package/dist/utils/formatNode.d.ts +13 -0
  55. package/dist/utils/formatNode.d.ts.map +1 -1
  56. package/dist/utils/formatNode.js +35 -2
  57. package/package.json +3 -3
  58. package/src/cli.ts +10 -0
  59. package/src/commands/analyze.ts +84 -9
  60. package/src/commands/check.ts +201 -0
  61. package/src/commands/coverage.ts +7 -0
  62. package/src/commands/doctor/checks.ts +612 -0
  63. package/src/commands/doctor/output.ts +115 -0
  64. package/src/commands/doctor/types.ts +45 -0
  65. package/src/commands/doctor.ts +106 -0
  66. package/src/commands/explain.ts +173 -0
  67. package/src/commands/explore.tsx +247 -97
  68. package/src/commands/get.ts +20 -6
  69. package/src/commands/impact.ts +55 -61
  70. package/src/commands/init.ts +101 -14
  71. package/src/commands/ls.ts +166 -0
  72. package/src/commands/overview.ts +15 -2
  73. package/src/commands/query.ts +643 -149
  74. package/src/commands/schema.ts +345 -0
  75. package/src/commands/server.ts +13 -6
  76. package/src/commands/stats.ts +7 -0
  77. package/src/commands/trace.ts +647 -6
  78. package/src/commands/types.ts +94 -0
  79. package/src/utils/formatNode.ts +42 -2
package/dist/cli.js CHANGED
@@ -7,6 +7,8 @@ import { initCommand } from './commands/init.js';
7
7
  import { analyzeCommand } from './commands/analyze.js';
8
8
  import { overviewCommand } from './commands/overview.js';
9
9
  import { queryCommand } from './commands/query.js';
10
+ import { typesCommand } from './commands/types.js';
11
+ import { lsCommand } from './commands/ls.js';
10
12
  import { getCommand } from './commands/get.js';
11
13
  import { traceCommand } from './commands/trace.js';
12
14
  import { impactCommand } from './commands/impact.js';
@@ -15,6 +17,9 @@ import { statsCommand } from './commands/stats.js';
15
17
  import { checkCommand } from './commands/check.js';
16
18
  import { serverCommand } from './commands/server.js';
17
19
  import { coverageCommand } from './commands/coverage.js';
20
+ import { doctorCommand } from './commands/doctor.js';
21
+ import { schemaCommand } from './commands/schema.js';
22
+ import { explainCommand } from './commands/explain.js';
18
23
  const program = new Command();
19
24
  program
20
25
  .name('grafema')
@@ -25,6 +30,8 @@ program.addCommand(initCommand);
25
30
  program.addCommand(analyzeCommand);
26
31
  program.addCommand(overviewCommand);
27
32
  program.addCommand(queryCommand);
33
+ program.addCommand(typesCommand);
34
+ program.addCommand(lsCommand);
28
35
  program.addCommand(getCommand);
29
36
  program.addCommand(traceCommand);
30
37
  program.addCommand(impactCommand);
@@ -33,4 +40,7 @@ program.addCommand(statsCommand); // Keep for backwards compat
33
40
  program.addCommand(coverageCommand);
34
41
  program.addCommand(checkCommand);
35
42
  program.addCommand(serverCommand);
43
+ program.addCommand(doctorCommand);
44
+ program.addCommand(schemaCommand);
45
+ program.addCommand(explainCommand);
36
46
  program.parse();
@@ -1 +1 @@
1
- {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyHpC,eAAO,MAAM,cAAc,SAiJvB,CAAC"}
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgLpC,eAAO,MAAM,cAAc,SAqKvB,CAAC"}
@@ -3,18 +3,19 @@
3
3
  */
4
4
  import { Command } from 'commander';
5
5
  import { resolve, join } from 'path';
6
- import { existsSync, mkdirSync } from 'fs';
6
+ import { existsSync, mkdirSync, readdirSync } from 'fs';
7
+ import { pathToFileURL } from 'url';
7
8
  import { Orchestrator, RFDBServerBackend, DiagnosticReporter, DiagnosticWriter, createLogger, loadConfig,
8
9
  // Discovery
9
10
  SimpleProjectDiscovery, MonorepoServiceDiscovery, WorkspaceDiscovery,
10
11
  // Indexing
11
12
  JSModuleIndexer, RustModuleIndexer,
12
13
  // Analysis
13
- JSASTAnalyzer, ExpressRouteAnalyzer, SocketIOAnalyzer, DatabaseAnalyzer, FetchAnalyzer, ServiceLayerAnalyzer, ReactAnalyzer, RustAnalyzer,
14
+ JSASTAnalyzer, ExpressRouteAnalyzer, ExpressResponseAnalyzer, SocketIOAnalyzer, DatabaseAnalyzer, FetchAnalyzer, ServiceLayerAnalyzer, ReactAnalyzer, RustAnalyzer,
14
15
  // Enrichment
15
- MethodCallResolver, AliasTracker, ValueDomainAnalyzer, MountPointResolver, PrefixEvaluator, InstanceOfResolver, ImportExportLinker, HTTPConnectionEnricher, RustFFIEnricher,
16
+ MethodCallResolver, ArgumentParameterLinker, AliasTracker, ValueDomainAnalyzer, MountPointResolver, PrefixEvaluator, InstanceOfResolver, ImportExportLinker, FunctionCallResolver, HTTPConnectionEnricher, RustFFIEnricher,
16
17
  // Validation
17
- CallResolverValidator, EvalBanValidator, SQLInjectionValidator, ShadowingDetector, GraphConnectivityValidator, DataFlowValidator, TypeScriptDeadCodeValidator, } from '@grafema/core';
18
+ CallResolverValidator, EvalBanValidator, SQLInjectionValidator, ShadowingDetector, GraphConnectivityValidator, DataFlowValidator, TypeScriptDeadCodeValidator, BrokenImportValidator, } from '@grafema/core';
18
19
  const BUILTIN_PLUGINS = {
19
20
  // Discovery
20
21
  SimpleProjectDiscovery: () => new SimpleProjectDiscovery(),
@@ -26,6 +27,7 @@ const BUILTIN_PLUGINS = {
26
27
  // Analysis
27
28
  JSASTAnalyzer: () => new JSASTAnalyzer(),
28
29
  ExpressRouteAnalyzer: () => new ExpressRouteAnalyzer(),
30
+ ExpressResponseAnalyzer: () => new ExpressResponseAnalyzer(),
29
31
  SocketIOAnalyzer: () => new SocketIOAnalyzer(),
30
32
  DatabaseAnalyzer: () => new DatabaseAnalyzer(),
31
33
  FetchAnalyzer: () => new FetchAnalyzer(),
@@ -34,12 +36,14 @@ const BUILTIN_PLUGINS = {
34
36
  RustAnalyzer: () => new RustAnalyzer(),
35
37
  // Enrichment
36
38
  MethodCallResolver: () => new MethodCallResolver(),
39
+ ArgumentParameterLinker: () => new ArgumentParameterLinker(),
37
40
  AliasTracker: () => new AliasTracker(),
38
41
  ValueDomainAnalyzer: () => new ValueDomainAnalyzer(),
39
42
  MountPointResolver: () => new MountPointResolver(),
40
43
  PrefixEvaluator: () => new PrefixEvaluator(),
41
44
  InstanceOfResolver: () => new InstanceOfResolver(),
42
45
  ImportExportLinker: () => new ImportExportLinker(),
46
+ FunctionCallResolver: () => new FunctionCallResolver(),
43
47
  HTTPConnectionEnricher: () => new HTTPConnectionEnricher(),
44
48
  RustFFIEnricher: () => new RustFFIEnricher(),
45
49
  // Validation
@@ -50,14 +54,49 @@ const BUILTIN_PLUGINS = {
50
54
  GraphConnectivityValidator: () => new GraphConnectivityValidator(),
51
55
  DataFlowValidator: () => new DataFlowValidator(),
52
56
  TypeScriptDeadCodeValidator: () => new TypeScriptDeadCodeValidator(),
57
+ BrokenImportValidator: () => new BrokenImportValidator(),
53
58
  };
54
- function createPlugins(config) {
59
+ /**
60
+ * Load custom plugins from .grafema/plugins/ directory
61
+ */
62
+ async function loadCustomPlugins(projectPath, log) {
63
+ const pluginsDir = join(projectPath, '.grafema', 'plugins');
64
+ if (!existsSync(pluginsDir)) {
65
+ return {};
66
+ }
67
+ const customPlugins = {};
68
+ try {
69
+ const files = readdirSync(pluginsDir).filter((f) => f.endsWith('.js') || f.endsWith('.mjs'));
70
+ for (const file of files) {
71
+ try {
72
+ const pluginPath = join(pluginsDir, file);
73
+ const pluginUrl = pathToFileURL(pluginPath).href;
74
+ const module = await import(pluginUrl);
75
+ const PluginClass = module.default || module[file.replace(/\.(m?js)$/, '')];
76
+ if (PluginClass && typeof PluginClass === 'function') {
77
+ const pluginName = PluginClass.name || file.replace(/\.(m?js)$/, '');
78
+ customPlugins[pluginName] = () => new PluginClass();
79
+ log(`Loaded custom plugin: ${pluginName}`);
80
+ }
81
+ }
82
+ catch (err) {
83
+ console.warn(`Failed to load plugin ${file}: ${err.message}`);
84
+ }
85
+ }
86
+ }
87
+ catch (err) {
88
+ console.warn(`Error loading custom plugins: ${err.message}`);
89
+ }
90
+ return customPlugins;
91
+ }
92
+ function createPlugins(config, customPlugins = {}) {
55
93
  const plugins = [];
56
94
  const phases = ['discovery', 'indexing', 'analysis', 'enrichment', 'validation'];
57
95
  for (const phase of phases) {
58
96
  const names = config[phase] || [];
59
97
  for (const name of names) {
60
- const factory = BUILTIN_PLUGINS[name];
98
+ // Check built-in first, then custom
99
+ const factory = BUILTIN_PLUGINS[name] || customPlugins[name];
61
100
  if (factory) {
62
101
  plugins.push(factory());
63
102
  }
@@ -95,6 +134,17 @@ export const analyzeCommand = new Command('analyze')
95
134
  .option('-v, --verbose', 'Show verbose logging')
96
135
  .option('--debug', 'Enable debug mode (writes diagnostics.log)')
97
136
  .option('--log-level <level>', 'Set log level (silent, errors, warnings, info, debug)')
137
+ .option('--strict', 'Enable strict mode (fail on unresolved references)')
138
+ .addHelpText('after', `
139
+ Examples:
140
+ grafema analyze Analyze current project
141
+ grafema analyze ./my-project Analyze specific directory
142
+ grafema analyze --clear Clear database and rebuild from scratch
143
+ grafema analyze -s api Analyze only "api" service (monorepo)
144
+ grafema analyze -v Verbose output with progress details
145
+ grafema analyze --debug Write diagnostics.log for debugging
146
+ grafema analyze --strict Fail on unresolved references (debugging)
147
+ `)
98
148
  .action(async (path, options) => {
99
149
  const projectPath = resolve(path);
100
150
  const grafemaDir = join(projectPath, '.grafema');
@@ -122,8 +172,15 @@ export const analyzeCommand = new Command('analyze')
122
172
  log(` - ${svc.name}: ${svc.path}${entry}`);
123
173
  }
124
174
  }
125
- const plugins = createPlugins(config.plugins);
175
+ // Load custom plugins from .grafema/plugins/
176
+ const customPlugins = await loadCustomPlugins(projectPath, log);
177
+ const plugins = createPlugins(config.plugins, customPlugins);
126
178
  log(`Loaded ${plugins.length} plugins`);
179
+ // Resolve strict mode: CLI flag overrides config
180
+ const strictMode = options.strict ?? config.strict ?? false;
181
+ if (strictMode) {
182
+ log('Strict mode enabled - analysis will fail on unresolved references');
183
+ }
127
184
  const startTime = Date.now();
128
185
  const orchestrator = new Orchestrator({
129
186
  graph: backend,
@@ -133,6 +190,7 @@ export const analyzeCommand = new Command('analyze')
133
190
  forceAnalysis: options.clear || false,
134
191
  logger,
135
192
  services: config.services.length > 0 ? config.services : undefined, // Pass config services (REG-174)
193
+ strictMode, // REG-330: Pass strict mode flag
136
194
  onProgress: (progress) => {
137
195
  if (options.verbose) {
138
196
  log(`[${progress.phase}] ${progress.message}`);
@@ -155,17 +213,17 @@ export const analyzeCommand = new Command('analyze')
155
213
  // Print summary if there are any issues
156
214
  if (diagnostics.count() > 0) {
157
215
  log('');
158
- log(reporter.summary());
216
+ log(reporter.categorizedSummary());
159
217
  // In verbose mode, print full report
160
218
  if (options.verbose) {
161
219
  log('');
162
220
  log(reporter.report({ format: 'text', includeSummary: false }));
163
221
  }
164
222
  }
165
- // Write diagnostics.log in debug mode
223
+ // Always write diagnostics.log (required for `grafema check` command)
224
+ const writer = new DiagnosticWriter();
225
+ await writer.write(diagnostics, grafemaDir);
166
226
  if (options.debug) {
167
- const writer = new DiagnosticWriter();
168
- await writer.write(diagnostics, grafemaDir);
169
227
  log(`Diagnostics written to ${writer.getLogPath(grafemaDir)}`);
170
228
  }
171
229
  // Determine exit code based on severity
@@ -6,5 +6,11 @@
6
6
  * 2. Built-in validators: --guarantee=<name> (e.g., --guarantee=node-creation)
7
7
  */
8
8
  import { Command } from 'commander';
9
+ export interface DiagnosticCheckCategory {
10
+ name: string;
11
+ description: string;
12
+ codes: string[];
13
+ }
14
+ export declare const CHECK_CATEGORIES: Record<string, DiagnosticCheckCategory>;
9
15
  export declare const checkCommand: Command;
10
16
  //# sourceMappingURL=check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,eAAO,MAAM,YAAY,SAwMtB,CAAC"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAGD,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAqBpE,CAAC;AAEF,eAAO,MAAM,YAAY,SA2OtB,CAAC"}
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Command } from 'commander';
9
9
  import { resolve, join } from 'path';
10
- import { existsSync } from 'fs';
10
+ import { existsSync, readFileSync } from 'fs';
11
11
  import { RFDBServerBackend, GuaranteeManager, NodeCreationValidator, GraphFreshnessChecker, IncrementalReanalyzer } from '@grafema/core';
12
12
  import { exitWithError } from '../utils/errorFormatter.js';
13
13
  // Available built-in validators
@@ -17,6 +17,29 @@ const BUILT_IN_VALIDATORS = {
17
17
  description: 'Validates that all nodes are created through NodeFactory'
18
18
  }
19
19
  };
20
+ // Available diagnostic categories
21
+ export const CHECK_CATEGORIES = {
22
+ 'connectivity': {
23
+ name: 'Graph Connectivity',
24
+ description: 'Check for disconnected nodes in the graph',
25
+ codes: ['ERR_DISCONNECTED_NODES', 'ERR_DISCONNECTED_NODE'],
26
+ },
27
+ 'calls': {
28
+ name: 'Call Resolution',
29
+ description: 'Check for unresolved function calls',
30
+ codes: ['ERR_UNRESOLVED_CALL'],
31
+ },
32
+ 'dataflow': {
33
+ name: 'Data Flow',
34
+ description: 'Check for missing assignments and broken references',
35
+ codes: ['ERR_MISSING_ASSIGNMENT', 'ERR_BROKEN_REFERENCE', 'ERR_NO_LEAF_NODE'],
36
+ },
37
+ 'imports': {
38
+ name: 'Import Validation',
39
+ description: 'Check for broken imports and undefined symbols',
40
+ codes: ['ERR_BROKEN_IMPORT', 'ERR_UNDEFINED_SYMBOL'],
41
+ },
42
+ };
20
43
  export const checkCommand = new Command('check')
21
44
  .description('Check invariants/guarantees')
22
45
  .argument('[rule]', 'Specific rule ID to check (or "all" for all rules)')
@@ -26,9 +49,36 @@ export const checkCommand = new Command('check')
26
49
  .option('-j, --json', 'Output results as JSON')
27
50
  .option('-q, --quiet', 'Only output failures')
28
51
  .option('--list-guarantees', 'List available built-in guarantees')
52
+ .option('--list-categories', 'List available diagnostic categories')
29
53
  .option('--skip-reanalysis', 'Skip automatic reanalysis of stale modules')
30
54
  .option('--fail-on-stale', 'Exit with error if stale modules found (CI mode)')
55
+ .addHelpText('after', `
56
+ Examples:
57
+ grafema check Run all guarantee checks
58
+ grafema check connectivity Check graph connectivity
59
+ grafema check calls Check call resolution
60
+ grafema check dataflow Check data flow integrity
61
+ grafema check all Run all diagnostic categories
62
+ grafema check --guarantee node-creation Run built-in validator
63
+ grafema check --list-categories List available categories
64
+ grafema check --list-guarantees List built-in guarantees
65
+ grafema check --fail-on-stale CI mode: fail if graph is stale
66
+ grafema check -q Only show failures (quiet mode)
67
+ `)
31
68
  .action(async (rule, options) => {
69
+ // List available categories
70
+ if (options.listCategories) {
71
+ console.log('Available diagnostic categories:');
72
+ console.log('');
73
+ for (const [key, category] of Object.entries(CHECK_CATEGORIES)) {
74
+ console.log(` ${key}`);
75
+ console.log(` ${category.name}`);
76
+ console.log(` ${category.description}`);
77
+ console.log(` Usage: grafema check ${key}`);
78
+ console.log('');
79
+ }
80
+ return;
81
+ }
32
82
  // List available guarantees
33
83
  if (options.listGuarantees) {
34
84
  console.log('Available built-in guarantees:');
@@ -40,6 +90,11 @@ export const checkCommand = new Command('check')
40
90
  }
41
91
  return;
42
92
  }
93
+ // Check if rule argument is a category name
94
+ if (rule && (rule in CHECK_CATEGORIES || rule === 'all')) {
95
+ await runCategoryCheck(rule, options);
96
+ return;
97
+ }
43
98
  // Run built-in guarantee validator
44
99
  if (options.guarantee) {
45
100
  const validatorInfo = BUILT_IN_VALIDATORS[options.guarantee];
@@ -293,3 +348,124 @@ async function runBuiltInValidator(guaranteeName, projectPath, options) {
293
348
  await backend.close();
294
349
  }
295
350
  }
351
+ /**
352
+ * Run category-based diagnostic check
353
+ */
354
+ async function runCategoryCheck(category, options) {
355
+ const resolvedPath = resolve(options.project);
356
+ const grafemaDir = join(resolvedPath, '.grafema');
357
+ const diagnosticsLogPath = join(grafemaDir, 'diagnostics.log');
358
+ if (!existsSync(diagnosticsLogPath)) {
359
+ exitWithError('No diagnostics found', [
360
+ 'Run: grafema analyze',
361
+ 'Diagnostics are collected during analysis'
362
+ ]);
363
+ }
364
+ // Read diagnostics from log file (JSON lines format)
365
+ const diagnosticsContent = readFileSync(diagnosticsLogPath, 'utf-8');
366
+ const allDiagnostics = diagnosticsContent
367
+ .split('\n')
368
+ .filter(line => line.trim())
369
+ .map(line => {
370
+ try {
371
+ return JSON.parse(line);
372
+ }
373
+ catch (e) {
374
+ return null;
375
+ }
376
+ })
377
+ .filter(Boolean);
378
+ // Filter diagnostics by category codes
379
+ let filteredDiagnostics = allDiagnostics;
380
+ if (category !== 'all') {
381
+ const categoryInfo = CHECK_CATEGORIES[category];
382
+ if (!categoryInfo) {
383
+ exitWithError(`Unknown category: ${category}`, [
384
+ 'Use --list-categories to see available options'
385
+ ]);
386
+ }
387
+ filteredDiagnostics = allDiagnostics.filter((d) => categoryInfo.codes.includes(d.code));
388
+ }
389
+ if (options.json) {
390
+ console.log(JSON.stringify({
391
+ category: category,
392
+ total: filteredDiagnostics.length,
393
+ diagnostics: filteredDiagnostics
394
+ }, null, 2));
395
+ }
396
+ else {
397
+ const categoryName = category === 'all'
398
+ ? 'All Categories'
399
+ : CHECK_CATEGORIES[category].name;
400
+ if (!options.quiet) {
401
+ console.log(`Checking ${categoryName}...`);
402
+ console.log('');
403
+ }
404
+ if (filteredDiagnostics.length === 0) {
405
+ console.log('\x1b[32m✓\x1b[0m No issues found');
406
+ }
407
+ else {
408
+ console.log(`\x1b[33m⚠\x1b[0m Found ${filteredDiagnostics.length} diagnostic(s):`);
409
+ console.log('');
410
+ // Group by severity
411
+ const errors = filteredDiagnostics.filter((d) => d.severity === 'error' || d.severity === 'fatal');
412
+ const warnings = filteredDiagnostics.filter((d) => d.severity === 'warning');
413
+ const infos = filteredDiagnostics.filter((d) => d.severity === 'info');
414
+ // Display errors first
415
+ if (errors.length > 0) {
416
+ console.log(`\x1b[31mErrors (${errors.length}):\x1b[0m`);
417
+ for (const diag of errors.slice(0, 10)) {
418
+ const location = diag.file ? `${diag.file}${diag.line ? `:${diag.line}` : ''}` : '';
419
+ console.log(` \x1b[31m•\x1b[0m [${diag.code}] ${diag.message}`);
420
+ if (location) {
421
+ console.log(` ${location}`);
422
+ }
423
+ if (diag.suggestion && !options.quiet) {
424
+ console.log(` Suggestion: ${diag.suggestion}`);
425
+ }
426
+ }
427
+ if (errors.length > 10) {
428
+ console.log(` ... and ${errors.length - 10} more errors`);
429
+ }
430
+ console.log('');
431
+ }
432
+ // Display warnings
433
+ if (warnings.length > 0) {
434
+ console.log(`\x1b[33mWarnings (${warnings.length}):\x1b[0m`);
435
+ for (const diag of warnings.slice(0, 10)) {
436
+ const location = diag.file ? `${diag.file}${diag.line ? `:${diag.line}` : ''}` : '';
437
+ console.log(` \x1b[33m•\x1b[0m [${diag.code}] ${diag.message}`);
438
+ if (location) {
439
+ console.log(` ${location}`);
440
+ }
441
+ if (diag.suggestion && !options.quiet) {
442
+ console.log(` Suggestion: ${diag.suggestion}`);
443
+ }
444
+ }
445
+ if (warnings.length > 10) {
446
+ console.log(` ... and ${warnings.length - 10} more warnings`);
447
+ }
448
+ console.log('');
449
+ }
450
+ // Display infos
451
+ if (infos.length > 0 && !options.quiet) {
452
+ console.log(`\x1b[36mInfo (${infos.length}):\x1b[0m`);
453
+ for (const diag of infos.slice(0, 5)) {
454
+ const location = diag.file ? `${diag.file}${diag.line ? `:${diag.line}` : ''}` : '';
455
+ console.log(` \x1b[36m•\x1b[0m [${diag.code}] ${diag.message}`);
456
+ if (location) {
457
+ console.log(` ${location}`);
458
+ }
459
+ }
460
+ if (infos.length > 5) {
461
+ console.log(` ... and ${infos.length - 5} more info messages`);
462
+ }
463
+ console.log('');
464
+ }
465
+ }
466
+ console.log('');
467
+ if (filteredDiagnostics.some((d) => d.severity === 'error' || d.severity === 'fatal')) {
468
+ process.exit(1);
469
+ }
470
+ }
471
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,eAAe,SA6BxB,CAAC"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,eAAe,SAoCxB,CAAC"}
@@ -16,6 +16,13 @@ export const coverageCommand = new Command('coverage')
16
16
  .option('-p, --project <path>', 'Project path', '.')
17
17
  .option('-j, --json', 'Output as JSON')
18
18
  .option('-v, --verbose', 'Show detailed file lists')
19
+ .addHelpText('after', `
20
+ Examples:
21
+ grafema coverage Show coverage summary
22
+ grafema coverage --verbose Show detailed file lists
23
+ grafema coverage --json Output coverage as JSON
24
+ grafema coverage -p ./app Coverage for specific project
25
+ `)
19
26
  .action(async (options) => {
20
27
  const projectPath = resolve(options.project);
21
28
  const grafemaDir = join(projectPath, '.grafema');
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Diagnostic check functions for `grafema doctor` command - REG-214
3
+ *
4
+ * Checks are organized in levels:
5
+ * - Level 1: Prerequisites (fail-fast) - checkGrafemaInitialized, checkServerStatus
6
+ * - Level 2: Configuration - checkConfigValidity, checkEntrypoints
7
+ * - Level 3: Graph Health - checkDatabaseExists, checkGraphStats, checkConnectivity, checkFreshness
8
+ * - Level 4: Informational - checkVersions
9
+ */
10
+ import type { DoctorCheckResult } from './types.js';
11
+ /**
12
+ * Check if .grafema directory exists with config file.
13
+ * FAIL if not initialized.
14
+ */
15
+ export declare function checkGrafemaInitialized(projectPath: string): Promise<DoctorCheckResult>;
16
+ /**
17
+ * Check if RFDB server is running and responsive.
18
+ * WARN if not running (server starts on-demand during analyze).
19
+ */
20
+ export declare function checkServerStatus(projectPath: string): Promise<DoctorCheckResult>;
21
+ /**
22
+ * Validate config file syntax and structure.
23
+ * Uses existing loadConfig() which throws on errors.
24
+ */
25
+ export declare function checkConfigValidity(projectPath: string): Promise<DoctorCheckResult>;
26
+ /**
27
+ * Check that entrypoints can be resolved.
28
+ * For config-defined services, validates that entrypoint files exist.
29
+ */
30
+ export declare function checkEntrypoints(projectPath: string): Promise<DoctorCheckResult>;
31
+ /**
32
+ * Check if database file exists and has data.
33
+ */
34
+ export declare function checkDatabaseExists(projectPath: string): Promise<DoctorCheckResult>;
35
+ /**
36
+ * Get graph statistics (requires server running).
37
+ */
38
+ export declare function checkGraphStats(projectPath: string): Promise<DoctorCheckResult>;
39
+ /**
40
+ * Check graph connectivity - find disconnected nodes.
41
+ * Thresholds:
42
+ * 0-5%: pass (normal for external modules)
43
+ * 5-20%: warn
44
+ * >20%: fail (critical issue)
45
+ */
46
+ export declare function checkConnectivity(projectPath: string): Promise<DoctorCheckResult>;
47
+ /**
48
+ * Check if graph is fresh (no stale modules).
49
+ */
50
+ export declare function checkFreshness(projectPath: string): Promise<DoctorCheckResult>;
51
+ /**
52
+ * Collect version information (always passes).
53
+ */
54
+ export declare function checkVersions(projectPath: string): Promise<DoctorCheckResult>;
55
+ //# sourceMappingURL=checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA2BpD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAgC5B;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAkC5B;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA+C5B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA+E5B;AAMD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA6B5B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA6C5B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAgI5B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA4C5B;AAMD;;GAEG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA6C5B"}