@grafema/cli 0.2.5-beta → 0.2.7

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 (105) hide show
  1. package/README.md +12 -0
  2. package/dist/cli.js +6 -2
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/analyze.d.ts +3 -10
  5. package/dist/commands/analyze.d.ts.map +1 -1
  6. package/dist/commands/analyze.js +5 -347
  7. package/dist/commands/analyze.js.map +1 -1
  8. package/dist/commands/analyzeAction.d.ts +28 -0
  9. package/dist/commands/analyzeAction.d.ts.map +1 -0
  10. package/dist/commands/analyzeAction.js +243 -0
  11. package/dist/commands/analyzeAction.js.map +1 -0
  12. package/dist/commands/check.js +2 -2
  13. package/dist/commands/check.js.map +1 -1
  14. package/dist/commands/context.d.ts +16 -0
  15. package/dist/commands/context.d.ts.map +1 -0
  16. package/dist/commands/context.js +238 -0
  17. package/dist/commands/context.js.map +1 -0
  18. package/dist/commands/doctor/checks.js +1 -1
  19. package/dist/commands/doctor/checks.js.map +1 -1
  20. package/dist/commands/explain.d.ts.map +1 -1
  21. package/dist/commands/explain.js +4 -3
  22. package/dist/commands/explain.js.map +1 -1
  23. package/dist/commands/file.d.ts +15 -0
  24. package/dist/commands/file.d.ts.map +1 -0
  25. package/dist/commands/file.js +144 -0
  26. package/dist/commands/file.js.map +1 -0
  27. package/dist/commands/impact.d.ts.map +1 -1
  28. package/dist/commands/impact.js +2 -3
  29. package/dist/commands/impact.js.map +1 -1
  30. package/dist/commands/init.d.ts.map +1 -1
  31. package/dist/commands/init.js +13 -1
  32. package/dist/commands/init.js.map +1 -1
  33. package/dist/commands/ls.d.ts.map +1 -1
  34. package/dist/commands/ls.js +3 -2
  35. package/dist/commands/ls.js.map +1 -1
  36. package/dist/commands/query.d.ts +8 -0
  37. package/dist/commands/query.d.ts.map +1 -1
  38. package/dist/commands/query.js +158 -51
  39. package/dist/commands/query.js.map +1 -1
  40. package/dist/commands/schema.d.ts.map +1 -1
  41. package/dist/commands/schema.js +3 -2
  42. package/dist/commands/schema.js.map +1 -1
  43. package/dist/commands/server.d.ts.map +1 -1
  44. package/dist/commands/server.js +8 -59
  45. package/dist/commands/server.js.map +1 -1
  46. package/dist/commands/setup-skill.d.ts +17 -0
  47. package/dist/commands/setup-skill.d.ts.map +1 -0
  48. package/dist/commands/setup-skill.js +131 -0
  49. package/dist/commands/setup-skill.js.map +1 -0
  50. package/dist/commands/trace.d.ts.map +1 -1
  51. package/dist/commands/trace.js +20 -10
  52. package/dist/commands/trace.js.map +1 -1
  53. package/dist/plugins/builtinPlugins.d.ts +10 -0
  54. package/dist/plugins/builtinPlugins.d.ts.map +1 -0
  55. package/dist/plugins/builtinPlugins.js +68 -0
  56. package/dist/plugins/builtinPlugins.js.map +1 -0
  57. package/dist/plugins/pluginLoader.d.ts +16 -0
  58. package/dist/plugins/pluginLoader.d.ts.map +1 -0
  59. package/dist/plugins/pluginLoader.js +101 -0
  60. package/dist/plugins/pluginLoader.js.map +1 -0
  61. package/dist/plugins/pluginResolver.js +38 -0
  62. package/dist/utils/codePreview.d.ts +1 -0
  63. package/dist/utils/codePreview.d.ts.map +1 -1
  64. package/dist/utils/codePreview.js +5 -3
  65. package/dist/utils/codePreview.js.map +1 -1
  66. package/dist/utils/formatNode.d.ts +1 -1
  67. package/dist/utils/formatNode.d.ts.map +1 -1
  68. package/dist/utils/formatNode.js +2 -2
  69. package/dist/utils/formatNode.js.map +1 -1
  70. package/dist/utils/pathUtils.d.ts +2 -0
  71. package/dist/utils/pathUtils.d.ts.map +1 -0
  72. package/dist/utils/pathUtils.js +9 -0
  73. package/dist/utils/pathUtils.js.map +1 -0
  74. package/dist/utils/progressRenderer.d.ts +4 -0
  75. package/dist/utils/progressRenderer.d.ts.map +1 -1
  76. package/dist/utils/progressRenderer.js +23 -4
  77. package/dist/utils/progressRenderer.js.map +1 -1
  78. package/package.json +7 -9
  79. package/skills/grafema-codebase-analysis/SKILL.md +295 -0
  80. package/skills/grafema-codebase-analysis/references/node-edge-types.md +123 -0
  81. package/skills/grafema-codebase-analysis/references/query-patterns.md +205 -0
  82. package/src/cli.ts +8 -2
  83. package/src/commands/analyze.ts +5 -435
  84. package/src/commands/analyzeAction.ts +284 -0
  85. package/src/commands/check.ts +2 -2
  86. package/src/commands/context.ts +309 -0
  87. package/src/commands/doctor/checks.ts +1 -1
  88. package/src/commands/explain.ts +4 -3
  89. package/src/commands/explore.tsx +7 -5
  90. package/src/commands/file.ts +179 -0
  91. package/src/commands/impact.ts +2 -3
  92. package/src/commands/init.ts +13 -1
  93. package/src/commands/ls.ts +3 -2
  94. package/src/commands/query.ts +167 -52
  95. package/src/commands/schema.ts +3 -2
  96. package/src/commands/server.ts +8 -64
  97. package/src/commands/setup-skill.ts +162 -0
  98. package/src/commands/trace.ts +18 -9
  99. package/src/plugins/builtinPlugins.ts +108 -0
  100. package/src/plugins/pluginLoader.ts +123 -0
  101. package/src/plugins/pluginResolver.js +38 -0
  102. package/src/utils/codePreview.ts +7 -3
  103. package/src/utils/formatNode.ts +3 -3
  104. package/src/utils/pathUtils.ts +9 -0
  105. package/src/utils/progressRenderer.ts +25 -4
@@ -0,0 +1,179 @@
1
+ /**
2
+ * File command - Show structured overview of a file's entities and relationships
3
+ *
4
+ * Purpose: Give a file-level summary with imports, exports, classes, functions,
5
+ * and their key relationships (calls, extends, assigned-from).
6
+ *
7
+ * This fills the gap between:
8
+ * - explain (lists ALL nodes flat, no relationships)
9
+ * - context (shows ONE node's full neighborhood)
10
+ *
11
+ * @see REG-412
12
+ */
13
+
14
+ import { Command } from 'commander';
15
+ import { resolve, join, relative, normalize } from 'path';
16
+ import { existsSync, realpathSync } from 'fs';
17
+ import { RFDBServerBackend, FileOverview } from '@grafema/core';
18
+ import type { FileOverviewResult, FunctionOverview } from '@grafema/core';
19
+ import { exitWithError } from '../utils/errorFormatter.js';
20
+ import { Spinner } from '../utils/spinner.js';
21
+
22
+ interface FileOptions {
23
+ project: string;
24
+ json?: boolean;
25
+ edges?: boolean;
26
+ }
27
+
28
+ export const fileCommand = new Command('file')
29
+ .description(
30
+ 'Show structured overview of a file: imports, exports, classes, functions with relationships'
31
+ )
32
+ .argument('<path>', 'File path to analyze')
33
+ .option('-p, --project <path>', 'Project path', '.')
34
+ .option('-j, --json', 'Output as JSON')
35
+ .option('--no-edges', 'Skip edge resolution (faster, just list entities)')
36
+ .addHelpText('after', `
37
+ Examples:
38
+ grafema file src/app.ts Show file overview with relationships
39
+ grafema file src/app.ts --json Output as JSON for scripting
40
+ grafema file src/app.ts --no-edges Fast mode: just list entities
41
+ grafema file ./src/utils.js Works with relative paths
42
+
43
+ Output shows:
44
+ - Imports (module sources and specifiers)
45
+ - Exports (named and default)
46
+ - Classes with methods and their calls
47
+ - Functions with their calls
48
+ - Variables with assignment sources
49
+
50
+ Use 'grafema context <id>' to dive deeper into any specific entity.
51
+ `)
52
+ .action(async (file: string, options: FileOptions) => {
53
+ const projectPath = resolve(options.project);
54
+ const grafemaDir = join(projectPath, '.grafema');
55
+ const dbPath = join(grafemaDir, 'graph.rfdb');
56
+
57
+ if (!existsSync(dbPath)) {
58
+ exitWithError('No graph database found', [
59
+ 'Run: grafema init && grafema analyze',
60
+ ]);
61
+ }
62
+
63
+ // Path resolution (same as explain command)
64
+ let filePath = file;
65
+
66
+ if (file.startsWith('./') || file.startsWith('../')) {
67
+ filePath = normalize(file).replace(/^\.\//, '');
68
+ } else if (resolve(file) === file) {
69
+ filePath = relative(projectPath, file);
70
+ }
71
+
72
+ const resolvedPath = resolve(projectPath, filePath);
73
+ if (!existsSync(resolvedPath)) {
74
+ exitWithError(`File not found: ${file}`, [
75
+ 'Check the file path and try again',
76
+ ]);
77
+ }
78
+
79
+ const absoluteFilePath = realpathSync(resolvedPath);
80
+ const relativeFilePath = relative(projectPath, absoluteFilePath);
81
+
82
+ const backend = new RFDBServerBackend({ dbPath });
83
+ await backend.connect();
84
+
85
+ const spinner = new Spinner('Loading file overview...');
86
+ spinner.start();
87
+
88
+ try {
89
+ const overview = new FileOverview(backend);
90
+ const result = await overview.getOverview(relativeFilePath, {
91
+ includeEdges: options.edges !== false,
92
+ });
93
+
94
+ result.file = relativeFilePath;
95
+
96
+ spinner.stop();
97
+
98
+ if (options.json) {
99
+ console.log(JSON.stringify(result, null, 2));
100
+ return;
101
+ }
102
+
103
+ printFileOverview(result);
104
+ } finally {
105
+ spinner.stop();
106
+ await backend.close();
107
+ }
108
+ });
109
+
110
+ function printFileOverview(result: FileOverviewResult): void {
111
+ console.log(`Module: ${result.file}`);
112
+
113
+ if (result.status === 'NOT_ANALYZED') {
114
+ console.log('Status: NOT_ANALYZED');
115
+ console.log('');
116
+ console.log('This file has not been analyzed yet.');
117
+ console.log('Run: grafema analyze');
118
+ return;
119
+ }
120
+
121
+ if (result.imports.length > 0) {
122
+ const importSources = result.imports.map(i => i.source);
123
+ console.log(`Imports: ${importSources.join(', ')}`);
124
+ }
125
+
126
+ if (result.exports.length > 0) {
127
+ const exportNames = result.exports.map(e =>
128
+ e.isDefault ? `${e.name} (default)` : e.name
129
+ );
130
+ console.log(`Exports: ${exportNames.join(', ')}`);
131
+ }
132
+
133
+ if (result.classes.length > 0) {
134
+ console.log('');
135
+ console.log('Classes:');
136
+ for (const cls of result.classes) {
137
+ const extendsStr = cls.extends ? ` extends ${cls.extends}` : '';
138
+ const lineStr = cls.line ? ` (line ${cls.line})` : '';
139
+ console.log(` ${cls.name}${extendsStr}${lineStr}`);
140
+
141
+ for (const method of cls.methods) {
142
+ printFunctionLine(method, ' ');
143
+ }
144
+ }
145
+ }
146
+
147
+ if (result.functions.length > 0) {
148
+ console.log('');
149
+ console.log('Functions:');
150
+ for (const fn of result.functions) {
151
+ printFunctionLine(fn, ' ');
152
+ }
153
+ }
154
+
155
+ if (result.variables.length > 0) {
156
+ console.log('');
157
+ console.log('Variables:');
158
+ for (const v of result.variables) {
159
+ const lineStr = v.line ? `(line ${v.line})` : '';
160
+ const assignStr = v.assignedFrom ? ` = ${v.assignedFrom}` : '';
161
+ console.log(` ${v.kind} ${v.name}${assignStr} ${lineStr}`);
162
+ }
163
+ }
164
+ }
165
+
166
+ function printFunctionLine(fn: FunctionOverview, indent: string): void {
167
+ const asyncStr = fn.async ? 'async ' : '';
168
+ const paramsStr = fn.params ? `(${fn.params.join(', ')})` : '()';
169
+ const lineStr = fn.line ? `(line ${fn.line})` : '';
170
+
171
+ let callsStr = '';
172
+ if (fn.calls.length > 0) {
173
+ callsStr = ` -> ${fn.calls.join(', ')}`;
174
+ }
175
+
176
+ console.log(
177
+ `${indent}${asyncStr}${fn.name}${paramsStr}${callsStr} ${lineStr}`
178
+ );
179
+ }
@@ -7,8 +7,7 @@
7
7
  */
8
8
 
9
9
  import { Command } from 'commander';
10
- import { resolve, join, dirname } from 'path';
11
- import { relative } from 'path';
10
+ import { isAbsolute, resolve, join, dirname, relative } from 'path';
12
11
  import { existsSync } from 'fs';
13
12
  import { RFDBServerBackend, findContainingFunction as findContainingFunctionCore } from '@grafema/core';
14
13
  import { formatNodeDisplay, formatNodeInline } from '../utils/formatNode.js';
@@ -313,7 +312,7 @@ async function findCallsToNode(
313
312
  */
314
313
  function getModulePath(file: string, projectPath: string): string {
315
314
  if (!file) return '<unknown>';
316
- const relPath = relative(projectPath, file);
315
+ const relPath = isAbsolute(file) ? relative(projectPath, file) : file;
317
316
  const dir = dirname(relPath);
318
317
  return dir === '.' ? relPath : `${dir}/*`;
319
318
  }
@@ -9,7 +9,8 @@ import { spawn } from 'child_process';
9
9
  import { createInterface } from 'readline';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { stringify as stringifyYAML } from 'yaml';
12
- import { DEFAULT_CONFIG } from '@grafema/core';
12
+ import { DEFAULT_CONFIG, GRAFEMA_VERSION, getSchemaVersion } from '@grafema/core';
13
+ import { installSkill } from './setup-skill.js';
13
14
 
14
15
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
15
16
 
@@ -20,6 +21,7 @@ const __dirname = fileURLToPath(new URL('.', import.meta.url));
20
21
  function generateConfigYAML(): string {
21
22
  // Start with working default config
22
23
  const config = {
24
+ version: getSchemaVersion(GRAFEMA_VERSION),
23
25
  // Plugin list (fully implemented)
24
26
  plugins: DEFAULT_CONFIG.plugins,
25
27
  };
@@ -184,6 +186,16 @@ Examples:
184
186
  }
185
187
  }
186
188
 
189
+ // Auto-install Agent Skill for AI-assisted development
190
+ try {
191
+ const installed = installSkill(projectPath);
192
+ if (installed) {
193
+ console.log('✓ Installed Agent Skill (.claude/skills/grafema-codebase-analysis/)');
194
+ }
195
+ } catch {
196
+ // Non-critical — don't fail init if skill install fails
197
+ }
198
+
187
199
  printNextSteps();
188
200
 
189
201
  // Prompt to run analyze in interactive mode
@@ -11,7 +11,8 @@
11
11
  */
12
12
 
13
13
  import { Command } from 'commander';
14
- import { resolve, join, relative } from 'path';
14
+ import { resolve, join } from 'path';
15
+ import { toRelativeDisplay } from '../utils/pathUtils.js';
15
16
  import { existsSync } from 'fs';
16
17
  import { RFDBServerBackend } from '@grafema/core';
17
18
  import { exitWithError } from '../utils/errorFormatter.js';
@@ -142,7 +143,7 @@ Discover available types:
142
143
  * Different types show different fields.
143
144
  */
144
145
  function formatNodeForList(node: NodeInfo, nodeType: string, projectPath: string): string {
145
- const relFile = node.file ? relative(projectPath, node.file) : '';
146
+ const relFile = node.file ? toRelativeDisplay(node.file, projectPath) : '';
146
147
  const loc = node.line ? `${relFile}:${node.line}` : relFile;
147
148
 
148
149
  // HTTP routes: METHOD PATH (location)