@grafema/cli 0.3.18 → 0.3.21
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/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +2 -0
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/analyzeAction.d.ts +1 -0
- package/dist/commands/analyzeAction.d.ts.map +1 -1
- package/dist/commands/analyzeAction.js +34 -3
- package/dist/commands/analyzeAction.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +7 -74
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/registry.d.ts +10 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +113 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/trace.d.ts.map +1 -1
- package/dist/commands/trace.js +1 -0
- package/dist/commands/trace.js.map +1 -1
- package/dist/commands/wtf.d.ts.map +1 -1
- package/dist/commands/wtf.js +3 -1
- package/dist/commands/wtf.js.map +1 -1
- package/dist/utils/quickstart.d.ts +35 -0
- package/dist/utils/quickstart.d.ts.map +1 -0
- package/dist/utils/quickstart.js +175 -0
- package/dist/utils/quickstart.js.map +1 -0
- package/package.json +4 -4
- package/src/cli.ts +2 -0
- package/src/commands/analyze.ts +2 -0
- package/src/commands/analyzeAction.ts +36 -3
- package/src/commands/init.ts +7 -82
- package/src/commands/registry.ts +138 -0
- package/src/commands/trace.ts +1 -0
- package/src/commands/wtf.ts +4 -1
- package/src/utils/quickstart.ts +192 -0
package/dist/commands/wtf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wtf.js","sourceRoot":"","sources":["../../src/commands/wtf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"wtf.js","sourceRoot":"","sources":["../../src/commands/wtf.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for project initialization and quickstart.
|
|
3
|
+
*
|
|
4
|
+
* Used by both `grafema init` and `grafema analyze --quickstart`.
|
|
5
|
+
*/
|
|
6
|
+
/** All file extensions supported by Grafema's analyzers. */
|
|
7
|
+
export declare const SUPPORTED_EXTENSIONS: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Scan a project directory for supported file extensions.
|
|
10
|
+
* Returns a Map of extension → file count for detected extensions.
|
|
11
|
+
*/
|
|
12
|
+
export declare function scanExtensions(projectPath: string): Map<string, number>;
|
|
13
|
+
/**
|
|
14
|
+
* Generate config YAML content.
|
|
15
|
+
*
|
|
16
|
+
* If `detectedExtensions` is provided and non-empty, only includes those extensions.
|
|
17
|
+
* Otherwise falls back to all supported extensions (same as `grafema init`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateSmartConfig(detectedExtensions?: Map<string, number>): string;
|
|
20
|
+
/**
|
|
21
|
+
* Write config file to .grafema/config.yaml, creating the directory if needed.
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeConfig(projectPath: string, configContent: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Add Grafema entries to .gitignore if it exists and doesn't already have them.
|
|
26
|
+
*/
|
|
27
|
+
export declare function updateGitignore(projectPath: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Format detected extensions as a human-readable string.
|
|
30
|
+
* Groups by language and shows total file count per language.
|
|
31
|
+
*
|
|
32
|
+
* Example: "TypeScript (342 files), JavaScript (18 files), Python (5 files)"
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatDetected(detected: Map<string, number>): string;
|
|
35
|
+
//# sourceMappingURL=quickstart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quickstart.d.ts","sourceRoot":"","sources":["../../src/utils/quickstart.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,4DAA4D;AAC5D,eAAO,MAAM,oBAAoB,UAmBhC,CAAC;AAaF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoCvE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,kBAAkB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAoCpF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,CAM5E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAa5D;AAiBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAWpE"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for project initialization and quickstart.
|
|
3
|
+
*
|
|
4
|
+
* Used by both `grafema init` and `grafema analyze --quickstart`.
|
|
5
|
+
*/
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'fs';
|
|
8
|
+
import { stringify as stringifyYAML } from 'yaml';
|
|
9
|
+
import { GRAFEMA_VERSION, getSchemaVersion } from '@grafema/util';
|
|
10
|
+
/** All file extensions supported by Grafema's analyzers. */
|
|
11
|
+
export const SUPPORTED_EXTENSIONS = [
|
|
12
|
+
// JavaScript / TypeScript
|
|
13
|
+
'js', 'jsx', 'mjs', 'cjs', 'ts', 'tsx',
|
|
14
|
+
// Rust
|
|
15
|
+
'rs',
|
|
16
|
+
// Java / Kotlin
|
|
17
|
+
'java', 'kt', 'kts',
|
|
18
|
+
// Python
|
|
19
|
+
'py', 'pyi',
|
|
20
|
+
// Go
|
|
21
|
+
'go',
|
|
22
|
+
// Haskell
|
|
23
|
+
'hs',
|
|
24
|
+
// C / C++
|
|
25
|
+
'c', 'h', 'cpp', 'hpp', 'cc', 'cxx', 'hxx', 'hh', 'inl', 'ipp', 'tpp', 'txx',
|
|
26
|
+
// Swift / Objective-C
|
|
27
|
+
'swift', 'm', 'mm',
|
|
28
|
+
// BEAM (Elixir / Erlang)
|
|
29
|
+
'ex', 'exs', 'erl', 'hrl',
|
|
30
|
+
];
|
|
31
|
+
/** Directories to skip during project scanning. */
|
|
32
|
+
const SKIP_DIRS = new Set([
|
|
33
|
+
'node_modules', 'dist', 'build', 'target', 'vendor',
|
|
34
|
+
'.git', '.grafema', 'coverage', '.next', '.nuxt',
|
|
35
|
+
'__pycache__', '.tox', '.venv',
|
|
36
|
+
]);
|
|
37
|
+
const SUPPORTED_SET = new Set(SUPPORTED_EXTENSIONS);
|
|
38
|
+
const MAX_DEPTH = 10;
|
|
39
|
+
const MAX_FILES = 50_000;
|
|
40
|
+
/**
|
|
41
|
+
* Scan a project directory for supported file extensions.
|
|
42
|
+
* Returns a Map of extension → file count for detected extensions.
|
|
43
|
+
*/
|
|
44
|
+
export function scanExtensions(projectPath) {
|
|
45
|
+
const counts = new Map();
|
|
46
|
+
let filesScanned = 0;
|
|
47
|
+
function walk(dir, depth) {
|
|
48
|
+
if (depth > MAX_DEPTH || filesScanned >= MAX_FILES)
|
|
49
|
+
return;
|
|
50
|
+
let entries;
|
|
51
|
+
try {
|
|
52
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return; // Permission denied or similar — skip
|
|
56
|
+
}
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
if (filesScanned >= MAX_FILES)
|
|
59
|
+
return;
|
|
60
|
+
if (entry.isDirectory()) {
|
|
61
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) {
|
|
62
|
+
walk(join(dir, entry.name), depth + 1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else if (entry.isFile()) {
|
|
66
|
+
filesScanned++;
|
|
67
|
+
const dot = entry.name.lastIndexOf('.');
|
|
68
|
+
if (dot !== -1) {
|
|
69
|
+
const ext = entry.name.slice(dot + 1);
|
|
70
|
+
if (SUPPORTED_SET.has(ext)) {
|
|
71
|
+
counts.set(ext, (counts.get(ext) ?? 0) + 1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
walk(projectPath, 0);
|
|
78
|
+
return counts;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generate config YAML content.
|
|
82
|
+
*
|
|
83
|
+
* If `detectedExtensions` is provided and non-empty, only includes those extensions.
|
|
84
|
+
* Otherwise falls back to all supported extensions (same as `grafema init`).
|
|
85
|
+
*/
|
|
86
|
+
export function generateSmartConfig(detectedExtensions) {
|
|
87
|
+
const exts = (detectedExtensions && detectedExtensions.size > 0)
|
|
88
|
+
? [...detectedExtensions.keys()]
|
|
89
|
+
: SUPPORTED_EXTENSIONS;
|
|
90
|
+
const extensions = `*.{${exts.join(',')}}`;
|
|
91
|
+
const config = {
|
|
92
|
+
version: getSchemaVersion(GRAFEMA_VERSION),
|
|
93
|
+
root: '..',
|
|
94
|
+
include: [`**/${extensions}`],
|
|
95
|
+
exclude: [
|
|
96
|
+
'**/*.test.*',
|
|
97
|
+
'**/__tests__/**',
|
|
98
|
+
'**/node_modules/**',
|
|
99
|
+
'**/dist/**',
|
|
100
|
+
'**/build/**',
|
|
101
|
+
'**/target/**',
|
|
102
|
+
'**/vendor/**',
|
|
103
|
+
'**/.git/**',
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
const yaml = stringifyYAML(config, {
|
|
107
|
+
lineWidth: 0,
|
|
108
|
+
});
|
|
109
|
+
return `# Grafema Configuration
|
|
110
|
+
# Documentation: https://github.com/grafema/grafema#configuration
|
|
111
|
+
# Supported: JS/TS, Rust, Java, Kotlin, Python, Go, Haskell, C/C++, Swift, Elixir/Erlang
|
|
112
|
+
|
|
113
|
+
${yaml}
|
|
114
|
+
# services: # Explicit service definitions (overrides auto-discovery)
|
|
115
|
+
# - name: "api"
|
|
116
|
+
# path: "."
|
|
117
|
+
# entryPoint: "src/index.ts"
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Write config file to .grafema/config.yaml, creating the directory if needed.
|
|
122
|
+
*/
|
|
123
|
+
export function writeConfig(projectPath, configContent) {
|
|
124
|
+
const grafemaDir = join(projectPath, '.grafema');
|
|
125
|
+
if (!existsSync(grafemaDir)) {
|
|
126
|
+
mkdirSync(grafemaDir, { recursive: true });
|
|
127
|
+
}
|
|
128
|
+
writeFileSync(join(grafemaDir, 'config.yaml'), configContent);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Add Grafema entries to .gitignore if it exists and doesn't already have them.
|
|
132
|
+
*/
|
|
133
|
+
export function updateGitignore(projectPath) {
|
|
134
|
+
const gitignorePath = join(projectPath, '.gitignore');
|
|
135
|
+
if (existsSync(gitignorePath)) {
|
|
136
|
+
const gitignore = readFileSync(gitignorePath, 'utf-8');
|
|
137
|
+
if (!gitignore.includes('.grafema/graph.rfdb')) {
|
|
138
|
+
writeFileSync(gitignorePath, gitignore + '\n# Grafema\n.grafema/graph.rfdb\n.grafema/rfdb.sock\n');
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
/** Map of extension to human-readable language name. */
|
|
145
|
+
const EXT_LANGUAGE = {
|
|
146
|
+
js: 'JavaScript', jsx: 'JavaScript', mjs: 'JavaScript', cjs: 'JavaScript',
|
|
147
|
+
ts: 'TypeScript', tsx: 'TypeScript',
|
|
148
|
+
rs: 'Rust',
|
|
149
|
+
java: 'Java', kt: 'Kotlin', kts: 'Kotlin',
|
|
150
|
+
py: 'Python', pyi: 'Python',
|
|
151
|
+
go: 'Go',
|
|
152
|
+
hs: 'Haskell',
|
|
153
|
+
c: 'C', h: 'C/C++', cpp: 'C++', hpp: 'C++', cc: 'C++', cxx: 'C++', hxx: 'C++', hh: 'C++',
|
|
154
|
+
inl: 'C++', ipp: 'C++', tpp: 'C++', txx: 'C++',
|
|
155
|
+
swift: 'Swift', m: 'Objective-C', mm: 'Objective-C++',
|
|
156
|
+
ex: 'Elixir', exs: 'Elixir', erl: 'Erlang', hrl: 'Erlang',
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Format detected extensions as a human-readable string.
|
|
160
|
+
* Groups by language and shows total file count per language.
|
|
161
|
+
*
|
|
162
|
+
* Example: "TypeScript (342 files), JavaScript (18 files), Python (5 files)"
|
|
163
|
+
*/
|
|
164
|
+
export function formatDetected(detected) {
|
|
165
|
+
// Group counts by language
|
|
166
|
+
const langCounts = new Map();
|
|
167
|
+
for (const [ext, count] of detected) {
|
|
168
|
+
const lang = EXT_LANGUAGE[ext] ?? ext;
|
|
169
|
+
langCounts.set(lang, (langCounts.get(lang) ?? 0) + count);
|
|
170
|
+
}
|
|
171
|
+
// Sort by count descending
|
|
172
|
+
const sorted = [...langCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
173
|
+
return sorted.map(([lang, count]) => `${lang} (${count} files)`).join(', ');
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=quickstart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quickstart.js","sourceRoot":"","sources":["../../src/utils/quickstart.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafema/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.21",
|
|
4
4
|
"description": "CLI for Grafema code analysis toolkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"commander": "^13.0.0",
|
|
37
37
|
"yaml": "^2.8.2",
|
|
38
|
-
"@grafema/api": "0.3.
|
|
39
|
-
"@grafema/util": "0.3.
|
|
40
|
-
"@grafema/types": "0.3.
|
|
38
|
+
"@grafema/api": "0.3.21",
|
|
39
|
+
"@grafema/util": "0.3.21",
|
|
40
|
+
"@grafema/types": "0.3.21"
|
|
41
41
|
},
|
|
42
42
|
"optionalDependencies": {
|
|
43
43
|
"@grafema/grafema-darwin-arm64": "0.3.16",
|
package/src/cli.ts
CHANGED
|
@@ -33,6 +33,7 @@ import { explainCommand } from './commands/explain.js';
|
|
|
33
33
|
import { fileCommand } from './commands/file.js';
|
|
34
34
|
import { setupSkillCommand } from './commands/setup-skill.js';
|
|
35
35
|
import { gitIngestCommand } from './commands/git-ingest.js';
|
|
36
|
+
import { registryCommand } from './commands/registry.js';
|
|
36
37
|
|
|
37
38
|
// Read version from package.json
|
|
38
39
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -74,5 +75,6 @@ program.addCommand(explainCommand);
|
|
|
74
75
|
program.addCommand(fileCommand);
|
|
75
76
|
program.addCommand(setupSkillCommand);
|
|
76
77
|
program.addCommand(gitIngestCommand);
|
|
78
|
+
program.addCommand(registryCommand);
|
|
77
79
|
|
|
78
80
|
program.parse();
|
package/src/commands/analyze.ts
CHANGED
|
@@ -21,6 +21,7 @@ export const analyzeCommand = new Command('analyze')
|
|
|
21
21
|
.option('--log-file <path>', 'Write all log output to a file')
|
|
22
22
|
.option('--strict', 'Enable strict mode (fail on unresolved references)')
|
|
23
23
|
.option('--no-auto-start', 'Do not auto-start RFDB server (require manual start)')
|
|
24
|
+
.option('--quickstart', 'Auto-initialize if no config exists (scan project, generate config)')
|
|
24
25
|
.addHelpText('after', `
|
|
25
26
|
Examples:
|
|
26
27
|
grafema analyze Analyze current project
|
|
@@ -32,5 +33,6 @@ Examples:
|
|
|
32
33
|
grafema analyze --log-file out.log Write all logs to a file
|
|
33
34
|
grafema analyze --strict Fail on unresolved references (debugging)
|
|
34
35
|
grafema analyze --no-auto-start Require manual server start
|
|
36
|
+
grafema analyze --quickstart Auto-init and analyze (no grafema init needed)
|
|
35
37
|
`)
|
|
36
38
|
.action(analyzeAction);
|
|
@@ -19,8 +19,10 @@ import {
|
|
|
19
19
|
findAnalyzerBinary,
|
|
20
20
|
ensureBinary,
|
|
21
21
|
ManifestGenerator,
|
|
22
|
+
ManifestResolver,
|
|
22
23
|
} from '@grafema/util';
|
|
23
24
|
import type { LogLevel } from '@grafema/util';
|
|
25
|
+
import { scanExtensions, generateSmartConfig, writeConfig, updateGitignore, formatDetected } from '../utils/quickstart.js';
|
|
24
26
|
|
|
25
27
|
export interface NodeEdgeCountBackend {
|
|
26
28
|
nodeCount: () => Promise<number>;
|
|
@@ -148,7 +150,7 @@ async function ensureLanguageBinaries(configPath: string, log: (...args: unknown
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
export async function analyzeAction(path: string, options: { service?: string; entrypoint?: string; clear?: boolean; quiet?: boolean; verbose?: boolean; debug?: boolean; logLevel?: string; logFile?: string; strict?: boolean; autoStart?: boolean }): Promise<void> {
|
|
153
|
+
export async function analyzeAction(path: string, options: { service?: string; entrypoint?: string; clear?: boolean; quiet?: boolean; verbose?: boolean; debug?: boolean; logLevel?: string; logFile?: string; strict?: boolean; autoStart?: boolean; quickstart?: boolean }): Promise<void> {
|
|
152
154
|
const projectPath = resolve(path);
|
|
153
155
|
const grafemaDir = join(projectPath, '.grafema');
|
|
154
156
|
const dbPath = join(grafemaDir, 'graph.rfdb');
|
|
@@ -191,7 +193,24 @@ export async function analyzeAction(path: string, options: { service?: string; e
|
|
|
191
193
|
debug(`Using orchestrator: ${orchestratorBinary}`);
|
|
192
194
|
|
|
193
195
|
// Find config file for the orchestrator
|
|
194
|
-
|
|
196
|
+
let configPath = findConfigFile(projectPath);
|
|
197
|
+
if (!configPath && options.quickstart) {
|
|
198
|
+
// Quickstart: auto-generate config by scanning the project
|
|
199
|
+
const detected = scanExtensions(projectPath);
|
|
200
|
+
const configContent = generateSmartConfig(detected);
|
|
201
|
+
writeConfig(projectPath, configContent);
|
|
202
|
+
updateGitignore(projectPath);
|
|
203
|
+
|
|
204
|
+
if (detected.size > 0) {
|
|
205
|
+
info(`Quickstart: detected ${formatDetected(detected)}`);
|
|
206
|
+
} else {
|
|
207
|
+
info('Quickstart: no supported files detected, using all extensions');
|
|
208
|
+
}
|
|
209
|
+
info('Created .grafema/config.yaml');
|
|
210
|
+
info('');
|
|
211
|
+
|
|
212
|
+
configPath = findConfigFile(projectPath);
|
|
213
|
+
}
|
|
195
214
|
if (!configPath) {
|
|
196
215
|
console.error('');
|
|
197
216
|
console.error('No grafema config file found.');
|
|
@@ -200,7 +219,7 @@ export async function analyzeAction(path: string, options: { service?: string; e
|
|
|
200
219
|
console.error(` ${join(projectPath, 'grafema.config.yaml')}`);
|
|
201
220
|
console.error(` ${join(projectPath, '.grafema', 'config.yaml')}`);
|
|
202
221
|
console.error('');
|
|
203
|
-
console.error('
|
|
222
|
+
console.error('Run with --quickstart to auto-generate, or create manually:');
|
|
204
223
|
console.error(' root: "."');
|
|
205
224
|
console.error(' include:');
|
|
206
225
|
console.error(' - "**/*.js"');
|
|
@@ -300,6 +319,20 @@ export async function analyzeAction(path: string, options: { service?: string; e
|
|
|
300
319
|
} catch (err) {
|
|
301
320
|
debug(`Manifest generation skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
302
321
|
}
|
|
322
|
+
|
|
323
|
+
// Auto-load registry manifests for cross-package resolution
|
|
324
|
+
const registryDir = join(projectPath, 'registry');
|
|
325
|
+
if (existsSync(registryDir)) {
|
|
326
|
+
try {
|
|
327
|
+
const resolver = new ManifestResolver();
|
|
328
|
+
const loaded = resolver.loadFromRegistry(registryDir);
|
|
329
|
+
if (loaded > 0) {
|
|
330
|
+
info(` Registry: ${loaded} package manifests loaded`);
|
|
331
|
+
}
|
|
332
|
+
} catch (err) {
|
|
333
|
+
debug(`Registry loading skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
303
336
|
} else {
|
|
304
337
|
console.error('');
|
|
305
338
|
console.error(`Analysis failed with exit code ${exitCode}`);
|
package/src/commands/init.ts
CHANGED
|
@@ -4,77 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import { Command } from 'commander';
|
|
6
6
|
import { resolve, join } from 'path';
|
|
7
|
-
import { existsSync
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
8
|
import { spawn } from 'child_process';
|
|
9
9
|
import { createInterface } from 'readline';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
|
-
import { stringify as stringifyYAML } from 'yaml';
|
|
12
|
-
import { GRAFEMA_VERSION, getSchemaVersion } from '@grafema/util';
|
|
13
11
|
import { installSkill } from './setup-skill.js';
|
|
12
|
+
import { generateSmartConfig, writeConfig, updateGitignore } from '../utils/quickstart.js';
|
|
14
13
|
|
|
15
14
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
16
15
|
|
|
17
|
-
/** All file extensions supported by Grafema's analyzers. */
|
|
18
|
-
const SUPPORTED_EXTENSIONS = [
|
|
19
|
-
// JavaScript / TypeScript
|
|
20
|
-
'js', 'jsx', 'mjs', 'cjs', 'ts', 'tsx',
|
|
21
|
-
// Rust
|
|
22
|
-
'rs',
|
|
23
|
-
// Java / Kotlin
|
|
24
|
-
'java', 'kt', 'kts',
|
|
25
|
-
// Python
|
|
26
|
-
'py', 'pyi',
|
|
27
|
-
// Go
|
|
28
|
-
'go',
|
|
29
|
-
// Haskell
|
|
30
|
-
'hs',
|
|
31
|
-
// C / C++
|
|
32
|
-
'c', 'h', 'cpp', 'hpp', 'cc', 'cxx', 'hxx', 'hh', 'inl', 'ipp', 'tpp', 'txx',
|
|
33
|
-
// Swift / Objective-C
|
|
34
|
-
'swift', 'm', 'mm',
|
|
35
|
-
// BEAM (Elixir / Erlang)
|
|
36
|
-
'ex', 'exs', 'erl', 'hrl',
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Generate config.yaml content.
|
|
41
|
-
* Minimal config — the Rust orchestrator has its own built-in analysis pipeline.
|
|
42
|
-
* Includes all supported extensions; orchestrator skips languages with no matching files.
|
|
43
|
-
*/
|
|
44
|
-
function generateConfigYAML(): string {
|
|
45
|
-
const extensions = `*.{${SUPPORTED_EXTENSIONS.join(',')}}`;
|
|
46
|
-
const config = {
|
|
47
|
-
version: getSchemaVersion(GRAFEMA_VERSION),
|
|
48
|
-
root: '..',
|
|
49
|
-
include: [`**/${extensions}`],
|
|
50
|
-
exclude: [
|
|
51
|
-
'**/*.test.*',
|
|
52
|
-
'**/__tests__/**',
|
|
53
|
-
'**/node_modules/**',
|
|
54
|
-
'**/dist/**',
|
|
55
|
-
'**/build/**',
|
|
56
|
-
'**/target/**',
|
|
57
|
-
'**/vendor/**',
|
|
58
|
-
'**/.git/**',
|
|
59
|
-
],
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const yaml = stringifyYAML(config, {
|
|
63
|
-
lineWidth: 0,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
return `# Grafema Configuration
|
|
67
|
-
# Documentation: https://github.com/grafema/grafema#configuration
|
|
68
|
-
# Supported: JS/TS, Rust, Java, Kotlin, Python, Go, Haskell, C/C++, Swift, Elixir/Erlang
|
|
69
|
-
|
|
70
|
-
${yaml}
|
|
71
|
-
# services: # Explicit service definitions (overrides auto-discovery)
|
|
72
|
-
# - name: "api"
|
|
73
|
-
# path: "."
|
|
74
|
-
# entryPoint: "src/index.ts"
|
|
75
|
-
`;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
16
|
/**
|
|
79
17
|
* Ask user a yes/no question. Returns true for yes (default), false for no.
|
|
80
18
|
*/
|
|
@@ -187,27 +125,14 @@ Examples:
|
|
|
187
125
|
return;
|
|
188
126
|
}
|
|
189
127
|
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Write config
|
|
196
|
-
const configContent = generateConfigYAML();
|
|
197
|
-
writeFileSync(configPath, configContent);
|
|
128
|
+
// Write config (generateSmartConfig with no args = all extensions, same as before)
|
|
129
|
+
const configContent = generateSmartConfig();
|
|
130
|
+
writeConfig(projectPath, configContent);
|
|
198
131
|
console.log('✓ Created .grafema/config.yaml');
|
|
199
132
|
|
|
200
133
|
// Add to .gitignore if exists
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const gitignore = readFileSync(gitignorePath, 'utf-8');
|
|
204
|
-
if (!gitignore.includes('.grafema/graph.rfdb')) {
|
|
205
|
-
writeFileSync(
|
|
206
|
-
gitignorePath,
|
|
207
|
-
gitignore + '\n# Grafema\n.grafema/graph.rfdb\n.grafema/rfdb.sock\n'
|
|
208
|
-
);
|
|
209
|
-
console.log('✓ Updated .gitignore');
|
|
210
|
-
}
|
|
134
|
+
if (updateGitignore(projectPath)) {
|
|
135
|
+
console.log('✓ Updated .gitignore');
|
|
211
136
|
}
|
|
212
137
|
|
|
213
138
|
// Auto-install Agent Skill for AI-assisted development
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry command — build and manage the local manifest registry.
|
|
3
|
+
*
|
|
4
|
+
* grafema registry build [--packages <names>] [--all] [--force] [--verbose]
|
|
5
|
+
* grafema registry list
|
|
6
|
+
* grafema registry status
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { resolve, join } from 'path';
|
|
11
|
+
import { existsSync, readFileSync } from 'fs';
|
|
12
|
+
import { parse as parseYaml } from 'yaml';
|
|
13
|
+
import { RegistryBuilder } from '@grafema/util';
|
|
14
|
+
import type { RegistryIndex } from '@grafema/util';
|
|
15
|
+
|
|
16
|
+
function getRegistryDir(path: string): string {
|
|
17
|
+
return join(resolve(path), 'registry');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const buildCommand = new Command('build')
|
|
21
|
+
.description('Build manifest registry for npm dependencies')
|
|
22
|
+
.argument('[path]', 'Project path', '.')
|
|
23
|
+
.option('-p, --packages <names>', 'Comma-separated package names to build')
|
|
24
|
+
.option('-a, --all', 'Build all discovered dependencies')
|
|
25
|
+
.option('-f, --force', 'Rebuild even if manifest exists')
|
|
26
|
+
.option('-v, --verbose', 'Show detailed output')
|
|
27
|
+
.option('--skip <names>', 'Comma-separated package names to skip')
|
|
28
|
+
.option('--timeout <ms>', 'Max per-package timeout in ms (adaptive by default)', '600000')
|
|
29
|
+
.option('--max-files <count>', 'Skip packages exceeding this file count', '5000')
|
|
30
|
+
.action(async (path: string, options: {
|
|
31
|
+
packages?: string;
|
|
32
|
+
all?: boolean;
|
|
33
|
+
force?: boolean;
|
|
34
|
+
verbose?: boolean;
|
|
35
|
+
skip?: string;
|
|
36
|
+
timeout?: string;
|
|
37
|
+
maxFiles?: string;
|
|
38
|
+
}) => {
|
|
39
|
+
const projectPath = resolve(path);
|
|
40
|
+
const registryDir = getRegistryDir(path);
|
|
41
|
+
|
|
42
|
+
const builder = new RegistryBuilder({
|
|
43
|
+
projectPath,
|
|
44
|
+
registryDir,
|
|
45
|
+
force: options.force,
|
|
46
|
+
verbose: options.verbose,
|
|
47
|
+
skip: options.skip?.split(',').map(s => s.trim()) ?? [],
|
|
48
|
+
timeout: parseInt(options.timeout ?? '120000', 10),
|
|
49
|
+
maxFiles: parseInt(options.maxFiles ?? '5000', 10),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (options.packages) {
|
|
53
|
+
const names = options.packages.split(',').map(s => s.trim());
|
|
54
|
+
await builder.buildPackages(names);
|
|
55
|
+
} else if (options.all) {
|
|
56
|
+
await builder.buildAll();
|
|
57
|
+
} else {
|
|
58
|
+
console.error('Specify --packages <names> or --all');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Write index and print summary
|
|
63
|
+
const indexPath = builder.writeIndex();
|
|
64
|
+
builder.printSummary();
|
|
65
|
+
console.log(`\nIndex: ${indexPath}`);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const listCommand = new Command('list')
|
|
69
|
+
.description('List packages in the local registry')
|
|
70
|
+
.argument('[path]', 'Project path', '.')
|
|
71
|
+
.action((path: string) => {
|
|
72
|
+
const registryDir = getRegistryDir(path);
|
|
73
|
+
const indexPath = join(registryDir, 'index.yaml');
|
|
74
|
+
|
|
75
|
+
if (!existsSync(indexPath)) {
|
|
76
|
+
console.log('No registry found. Run `grafema registry build --all` first.');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const index = parseYaml(readFileSync(indexPath, 'utf-8')) as RegistryIndex;
|
|
81
|
+
if (!index?.entries?.length) {
|
|
82
|
+
console.log('Registry is empty.');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(`Registry: ${index.entries.length} packages (analyzer ${index.analyzer_version})\n`);
|
|
87
|
+
|
|
88
|
+
const nameWidth = Math.max(...index.entries.map(e => e.name.length), 7);
|
|
89
|
+
console.log(`${'Package'.padEnd(nameWidth)} Version Exports Confidence Source`);
|
|
90
|
+
console.log(`${'─'.repeat(nameWidth)} ────────── ─────── ────────── ──────`);
|
|
91
|
+
|
|
92
|
+
for (const entry of index.entries) {
|
|
93
|
+
console.log(
|
|
94
|
+
`${entry.name.padEnd(nameWidth)} ${entry.version.padEnd(10)} ${String(entry.total_exports).padStart(7)} ${entry.confidence.toFixed(2).padStart(10)} ${entry.source_type}`,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const statusCommand = new Command('status')
|
|
100
|
+
.description('Show registry build status vs installed dependencies')
|
|
101
|
+
.argument('[path]', 'Project path', '.')
|
|
102
|
+
.action((path: string) => {
|
|
103
|
+
const projectPath = resolve(path);
|
|
104
|
+
const registryDir = getRegistryDir(path);
|
|
105
|
+
|
|
106
|
+
const builder = new RegistryBuilder({ projectPath, registryDir });
|
|
107
|
+
const deps = builder.discoverDependencies();
|
|
108
|
+
|
|
109
|
+
const indexPath = join(registryDir, 'index.yaml');
|
|
110
|
+
const builtNames = new Set<string>();
|
|
111
|
+
if (existsSync(indexPath)) {
|
|
112
|
+
const index = parseYaml(readFileSync(indexPath, 'utf-8')) as RegistryIndex;
|
|
113
|
+
if (index?.entries) {
|
|
114
|
+
for (const e of index.entries) builtNames.add(e.name);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const built = deps.filter(d => builtNames.has(d));
|
|
119
|
+
const missing = deps.filter(d => !builtNames.has(d));
|
|
120
|
+
|
|
121
|
+
console.log(`Dependencies: ${deps.length} total, ${built.length} in registry, ${missing.length} missing\n`);
|
|
122
|
+
|
|
123
|
+
if (missing.length > 0) {
|
|
124
|
+
console.log('Missing from registry:');
|
|
125
|
+
for (const name of missing) {
|
|
126
|
+
console.log(` ${name}`);
|
|
127
|
+
}
|
|
128
|
+
console.log(`\nRun: grafema registry build --packages ${missing.join(',')}`);
|
|
129
|
+
} else {
|
|
130
|
+
console.log('All dependencies have manifests in the registry.');
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
export const registryCommand = new Command('registry')
|
|
135
|
+
.description('Manage local manifest registry for npm dependencies')
|
|
136
|
+
.addCommand(buildCommand)
|
|
137
|
+
.addCommand(listCommand)
|
|
138
|
+
.addCommand(statusCommand);
|
package/src/commands/trace.ts
CHANGED
package/src/commands/wtf.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { Spinner } from '../utils/spinner.js';
|
|
|
23
23
|
interface WtfCommandOptions {
|
|
24
24
|
project: string;
|
|
25
25
|
depth: string;
|
|
26
|
+
detail: 'summary' | 'normal' | 'full';
|
|
26
27
|
json?: boolean;
|
|
27
28
|
}
|
|
28
29
|
|
|
@@ -31,12 +32,14 @@ export const wtfCommand = new Command('wtf')
|
|
|
31
32
|
.argument('<symbol>', 'Variable, constant, or parameter name to trace')
|
|
32
33
|
.option('-p, --project <path>', 'Project path', '.')
|
|
33
34
|
.option('-d, --depth <n>', 'Max trace depth', '10')
|
|
35
|
+
.option('--detail <level>', 'Level of detail: summary, normal (default), full', 'normal')
|
|
34
36
|
.option('-j, --json', 'Output as JSON')
|
|
35
37
|
.addHelpText('after', `
|
|
36
38
|
Examples:
|
|
37
39
|
grafema wtf req.user Trace where req.user comes from
|
|
38
40
|
grafema wtf config.apiKey Where does this value originate?
|
|
39
41
|
grafema wtf userId --depth 5 Limit trace depth
|
|
42
|
+
grafema wtf token --detail full Show complete chain (no compression)
|
|
40
43
|
grafema wtf token --json Output as JSON
|
|
41
44
|
`)
|
|
42
45
|
.action(async (symbol: string, options: WtfCommandOptions) => {
|
|
@@ -130,7 +133,7 @@ Examples:
|
|
|
130
133
|
} else {
|
|
131
134
|
console.log(`${found.name} (${found.type}) — ${found.file}${found.line ? ':' + found.line : ''}`);
|
|
132
135
|
console.log('');
|
|
133
|
-
const narrative = renderTraceNarrative(results, found.name, { detail: 'normal' });
|
|
136
|
+
const narrative = renderTraceNarrative(results, found.name, { detail: options.detail || 'normal', hintStyle: 'cli' });
|
|
134
137
|
console.log(narrative);
|
|
135
138
|
}
|
|
136
139
|
} finally {
|