@grafema/cli 0.2.11 → 0.3.0-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.
- package/dist/cli.js +13 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +2 -4
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/analyzeAction.d.ts +5 -3
- package/dist/commands/analyzeAction.d.ts.map +1 -1
- package/dist/commands/analyzeAction.js +109 -151
- package/dist/commands/analyzeAction.js.map +1 -1
- package/dist/commands/check.d.ts +1 -1
- package/dist/commands/check.js +4 -4
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/context.js +2 -2
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/coverage.js +2 -2
- package/dist/commands/coverage.js.map +1 -1
- package/dist/commands/describe.d.ts +13 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/describe.js +131 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/doctor/checks.d.ts +6 -1
- package/dist/commands/doctor/checks.d.ts.map +1 -1
- package/dist/commands/doctor/checks.js +128 -13
- package/dist/commands/doctor/checks.js.map +1 -1
- package/dist/commands/doctor.d.ts +10 -9
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +12 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain.js +2 -2
- package/dist/commands/explain.js.map +1 -1
- package/dist/commands/file.js +2 -2
- package/dist/commands/file.js.map +1 -1
- package/dist/commands/get.js +2 -2
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/git-ingest.d.ts +6 -0
- package/dist/commands/git-ingest.d.ts.map +1 -0
- package/dist/commands/git-ingest.js +46 -0
- package/dist/commands/git-ingest.js.map +1 -0
- package/dist/commands/impact.d.ts.map +1 -1
- package/dist/commands/impact.js +276 -50
- package/dist/commands/impact.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +20 -22
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/ls.js +2 -2
- package/dist/commands/ls.js.map +1 -1
- package/dist/commands/overview.js +2 -2
- package/dist/commands/overview.js.map +1 -1
- package/dist/commands/query.d.ts +1 -1
- package/dist/commands/query.d.ts.map +1 -1
- package/dist/commands/query.js +169 -7
- package/dist/commands/query.js.map +1 -1
- package/dist/commands/schema.js +2 -2
- package/dist/commands/schema.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +122 -76
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/stats.js +2 -2
- package/dist/commands/stats.js.map +1 -1
- package/dist/commands/tldr.d.ts +12 -0
- package/dist/commands/tldr.d.ts.map +1 -0
- package/dist/commands/tldr.js +81 -0
- package/dist/commands/tldr.js.map +1 -0
- package/dist/commands/trace.d.ts +1 -1
- package/dist/commands/trace.d.ts.map +1 -1
- package/dist/commands/trace.js +17 -133
- package/dist/commands/trace.js.map +1 -1
- package/dist/commands/types.js +2 -2
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/who.d.ts +12 -0
- package/dist/commands/who.d.ts.map +1 -0
- package/dist/commands/who.js +184 -0
- package/dist/commands/who.js.map +1 -0
- package/dist/commands/why.d.ts +12 -0
- package/dist/commands/why.d.ts.map +1 -0
- package/dist/commands/why.js +118 -0
- package/dist/commands/why.js.map +1 -0
- package/dist/commands/wtf.d.ts +12 -0
- package/dist/commands/wtf.d.ts.map +1 -0
- package/dist/commands/wtf.js +117 -0
- package/dist/commands/wtf.js.map +1 -0
- package/dist/plugins/builtinPlugins.d.ts +1 -9
- package/dist/plugins/builtinPlugins.d.ts.map +1 -1
- package/dist/plugins/builtinPlugins.js +2 -67
- package/dist/plugins/builtinPlugins.js.map +1 -1
- package/dist/plugins/pluginLoader.d.ts +1 -15
- package/dist/plugins/pluginLoader.d.ts.map +1 -1
- package/dist/plugins/pluginLoader.js +2 -100
- package/dist/plugins/pluginLoader.js.map +1 -1
- package/dist/plugins/pluginResolver.js +3 -3
- package/dist/utils/progressRenderer.d.ts +15 -1
- package/dist/utils/progressRenderer.d.ts.map +1 -1
- package/dist/utils/progressRenderer.js +19 -3
- package/dist/utils/progressRenderer.js.map +1 -1
- package/dist/utils/queryHints.d.ts +6 -0
- package/dist/utils/queryHints.d.ts.map +1 -0
- package/dist/utils/queryHints.js +36 -0
- package/dist/utils/queryHints.js.map +1 -0
- package/package.json +4 -4
- package/skills/grafema-codebase-analysis/SKILL.md +1 -1
- package/src/cli.ts +14 -0
- package/src/commands/analyze.ts +2 -4
- package/src/commands/analyzeAction.ts +122 -168
- package/src/commands/check.ts +5 -5
- package/src/commands/context.ts +3 -3
- package/src/commands/coverage.ts +2 -2
- package/src/commands/describe.ts +160 -0
- package/src/commands/doctor/checks.ts +153 -10
- package/src/commands/doctor.ts +13 -9
- package/src/commands/explain.ts +2 -2
- package/src/commands/explore.tsx +2 -2
- package/src/commands/file.ts +3 -3
- package/src/commands/get.ts +2 -2
- package/src/commands/git-ingest.ts +49 -0
- package/src/commands/impact.ts +318 -55
- package/src/commands/init.ts +20 -22
- package/src/commands/ls.ts +2 -2
- package/src/commands/overview.ts +2 -2
- package/src/commands/query.ts +197 -7
- package/src/commands/schema.ts +2 -2
- package/src/commands/server.ts +136 -84
- package/src/commands/stats.ts +2 -2
- package/src/commands/tldr.ts +103 -0
- package/src/commands/trace.ts +19 -161
- package/src/commands/types.ts +2 -2
- package/src/commands/who.ts +215 -0
- package/src/commands/why.ts +134 -0
- package/src/commands/wtf.ts +140 -0
- package/src/plugins/builtinPlugins.ts +1 -108
- package/src/plugins/pluginLoader.ts +1 -123
- package/src/plugins/pluginResolver.js +3 -3
- package/src/utils/progressRenderer.ts +34 -4
- package/src/utils/queryHints.ts +46 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* why command — "Why is it this way?"
|
|
3
|
+
*
|
|
4
|
+
* Query knowledge base for architectural decisions and facts about a symbol or module.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* grafema why auth-middleware # Why was auth middleware designed this way?
|
|
8
|
+
* grafema why UserService # Decisions about UserService
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { resolve, join } from 'path';
|
|
12
|
+
import { existsSync } from 'fs';
|
|
13
|
+
import { KnowledgeBase } from '@grafema/util';
|
|
14
|
+
import { exitWithError } from '../utils/errorFormatter.js';
|
|
15
|
+
import { Spinner } from '../utils/spinner.js';
|
|
16
|
+
export const whyCommand = new Command('why')
|
|
17
|
+
.description('Why is it this way? — query knowledge base decisions and facts')
|
|
18
|
+
.argument('<query>', 'Search text (symbol name, module, or topic)')
|
|
19
|
+
.option('-p, --project <path>', 'Project path', '.')
|
|
20
|
+
.option('-j, --json', 'Output as JSON')
|
|
21
|
+
.addHelpText('after', `
|
|
22
|
+
Examples:
|
|
23
|
+
grafema why auth-middleware Why was auth middleware designed this way?
|
|
24
|
+
grafema why UserService Decisions about UserService
|
|
25
|
+
grafema why "error handling" Facts about error handling approach
|
|
26
|
+
grafema why dataflow --json Output as JSON
|
|
27
|
+
`)
|
|
28
|
+
.action(async (query, options) => {
|
|
29
|
+
const projectPath = resolve(options.project);
|
|
30
|
+
const knowledgeDir = join(projectPath, 'knowledge');
|
|
31
|
+
if (!existsSync(knowledgeDir)) {
|
|
32
|
+
exitWithError('No knowledge base found', [
|
|
33
|
+
'Knowledge directory not found: ' + knowledgeDir,
|
|
34
|
+
'Use `add_knowledge` MCP tool to capture architectural decisions',
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
const spinner = new Spinner('Searching knowledge base...');
|
|
38
|
+
spinner.start();
|
|
39
|
+
try {
|
|
40
|
+
const kb = new KnowledgeBase(knowledgeDir);
|
|
41
|
+
await kb.load();
|
|
42
|
+
// Search DECISION nodes matching query text
|
|
43
|
+
const decisions = await kb.queryNodes({ type: 'DECISION', text: query });
|
|
44
|
+
// Search FACT nodes matching query text
|
|
45
|
+
const facts = await kb.queryNodes({ type: 'FACT', text: query });
|
|
46
|
+
spinner.stop();
|
|
47
|
+
if (options.json) {
|
|
48
|
+
console.log(JSON.stringify({
|
|
49
|
+
query,
|
|
50
|
+
decisions: decisions.map(d => ({
|
|
51
|
+
id: d.id,
|
|
52
|
+
status: d.status,
|
|
53
|
+
content: d.content,
|
|
54
|
+
applies_to: d.applies_to,
|
|
55
|
+
relates_to: d.relates_to,
|
|
56
|
+
})),
|
|
57
|
+
facts: facts.map(f => ({
|
|
58
|
+
id: f.id,
|
|
59
|
+
confidence: f.confidence,
|
|
60
|
+
content: f.content,
|
|
61
|
+
relates_to: f.relates_to,
|
|
62
|
+
})),
|
|
63
|
+
total: decisions.length + facts.length,
|
|
64
|
+
}, null, 2));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (decisions.length === 0 && facts.length === 0) {
|
|
68
|
+
console.log(`No knowledge found for: "${query}"`);
|
|
69
|
+
console.log('');
|
|
70
|
+
console.log('No decisions or facts recorded matching this query.');
|
|
71
|
+
console.log('Use `add_knowledge` MCP tool to capture architectural decisions.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Display decisions
|
|
75
|
+
if (decisions.length > 0) {
|
|
76
|
+
console.log(`Decisions (${decisions.length}):`);
|
|
77
|
+
console.log('');
|
|
78
|
+
for (const d of decisions) {
|
|
79
|
+
console.log(` [${d.status?.toUpperCase() || 'ACTIVE'}] ${d.id}`);
|
|
80
|
+
// Show first ~200 chars of content as summary
|
|
81
|
+
const summary = d.content.length > 200
|
|
82
|
+
? d.content.substring(0, 200) + '...'
|
|
83
|
+
: d.content;
|
|
84
|
+
// Indent content lines
|
|
85
|
+
for (const line of summary.split('\n')) {
|
|
86
|
+
console.log(` ${line}`);
|
|
87
|
+
}
|
|
88
|
+
if (d.applies_to && d.applies_to.length > 0) {
|
|
89
|
+
console.log(` Applies to: ${d.applies_to.join(', ')}`);
|
|
90
|
+
}
|
|
91
|
+
console.log('');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Display facts
|
|
95
|
+
if (facts.length > 0) {
|
|
96
|
+
console.log(`Facts (${facts.length}):`);
|
|
97
|
+
console.log('');
|
|
98
|
+
for (const f of facts) {
|
|
99
|
+
const confidence = f.confidence ? ` [${f.confidence}]` : '';
|
|
100
|
+
console.log(` ${f.id}${confidence}`);
|
|
101
|
+
const summary = f.content.length > 200
|
|
102
|
+
? f.content.substring(0, 200) + '...'
|
|
103
|
+
: f.content;
|
|
104
|
+
for (const line of summary.split('\n')) {
|
|
105
|
+
console.log(` ${line}`);
|
|
106
|
+
}
|
|
107
|
+
if (f.relates_to && f.relates_to.length > 0) {
|
|
108
|
+
console.log(` Relates to: ${f.relates_to.join(', ')}`);
|
|
109
|
+
}
|
|
110
|
+
console.log('');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
spinner.stop();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
//# sourceMappingURL=why.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"why.js","sourceRoot":"","sources":["../../src/commands/why.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wtf command — "Where does this come from?"
|
|
3
|
+
*
|
|
4
|
+
* Backward dataflow trace with arrow-formatted output.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* grafema wtf req.user # Backward trace
|
|
8
|
+
* grafema wtf config.apiKey # Where does this value originate?
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
export declare const wtfCommand: Command;
|
|
12
|
+
//# sourceMappingURL=wtf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wtf.d.ts","sourceRoot":"","sources":["../../src/commands/wtf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,eAAO,MAAM,UAAU,SA+GnB,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wtf command — "Where does this come from?"
|
|
3
|
+
*
|
|
4
|
+
* Backward dataflow trace with arrow-formatted output.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* grafema wtf req.user # Backward trace
|
|
8
|
+
* grafema wtf config.apiKey # Where does this value originate?
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { resolve, join } from 'path';
|
|
12
|
+
import { existsSync } from 'fs';
|
|
13
|
+
import { RFDBServerBackend, traceDataflow, renderTraceNarrative, } from '@grafema/util';
|
|
14
|
+
import { exitWithError } from '../utils/errorFormatter.js';
|
|
15
|
+
import { Spinner } from '../utils/spinner.js';
|
|
16
|
+
export const wtfCommand = new Command('wtf')
|
|
17
|
+
.description('Where does this come from? — backward dataflow trace')
|
|
18
|
+
.argument('<symbol>', 'Variable, constant, or parameter name to trace')
|
|
19
|
+
.option('-p, --project <path>', 'Project path', '.')
|
|
20
|
+
.option('-d, --depth <n>', 'Max trace depth', '10')
|
|
21
|
+
.option('-j, --json', 'Output as JSON')
|
|
22
|
+
.addHelpText('after', `
|
|
23
|
+
Examples:
|
|
24
|
+
grafema wtf req.user Trace where req.user comes from
|
|
25
|
+
grafema wtf config.apiKey Where does this value originate?
|
|
26
|
+
grafema wtf userId --depth 5 Limit trace depth
|
|
27
|
+
grafema wtf token --json Output as JSON
|
|
28
|
+
`)
|
|
29
|
+
.action(async (symbol, options) => {
|
|
30
|
+
const projectPath = resolve(options.project);
|
|
31
|
+
const grafemaDir = join(projectPath, '.grafema');
|
|
32
|
+
const dbPath = join(grafemaDir, 'graph.rfdb');
|
|
33
|
+
if (!existsSync(dbPath)) {
|
|
34
|
+
exitWithError('No graph database found', ['Run: grafema analyze']);
|
|
35
|
+
}
|
|
36
|
+
const maxDepth = parseInt(options.depth, 10);
|
|
37
|
+
if (isNaN(maxDepth) || maxDepth < 1) {
|
|
38
|
+
exitWithError('Invalid depth', ['Provide a positive integer']);
|
|
39
|
+
}
|
|
40
|
+
const backend = new RFDBServerBackend({ dbPath, clientName: 'cli' });
|
|
41
|
+
await backend.connect();
|
|
42
|
+
const spinner = new Spinner('Searching for symbol...');
|
|
43
|
+
spinner.start();
|
|
44
|
+
try {
|
|
45
|
+
// Find the node: search VARIABLE, CONSTANT, PARAMETER by name (case-insensitive)
|
|
46
|
+
// Also try PROPERTY_ACCESS by matching method part after last dot
|
|
47
|
+
const lowerSymbol = symbol.toLowerCase();
|
|
48
|
+
// If symbol has a dot, extract the part after the last dot for method matching
|
|
49
|
+
const dotIndex = symbol.lastIndexOf('.');
|
|
50
|
+
const methodPart = dotIndex >= 0 ? symbol.substring(dotIndex + 1).toLowerCase() : null;
|
|
51
|
+
let found = null;
|
|
52
|
+
for (const nodeType of ['VARIABLE', 'CONSTANT', 'PARAMETER']) {
|
|
53
|
+
for await (const n of backend.queryNodes({ type: nodeType })) {
|
|
54
|
+
const name = (n.name || '').toLowerCase();
|
|
55
|
+
if (name === lowerSymbol) {
|
|
56
|
+
found = { id: n.id, type: n.type || nodeType, name: n.name || '', file: n.file || '', line: n.line };
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (found)
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
// Try PROPERTY_ACCESS if not found and symbol has a dot
|
|
64
|
+
if (!found && methodPart) {
|
|
65
|
+
for await (const n of backend.queryNodes({ type: 'PROPERTY_ACCESS' })) {
|
|
66
|
+
const name = (n.name || '').toLowerCase();
|
|
67
|
+
// Match by full name or by the part after last dot
|
|
68
|
+
const nameMethodPart = name.lastIndexOf('.') >= 0
|
|
69
|
+
? name.substring(name.lastIndexOf('.') + 1)
|
|
70
|
+
: name;
|
|
71
|
+
if (name === lowerSymbol || nameMethodPart === methodPart) {
|
|
72
|
+
found = { id: n.id, type: n.type || 'PROPERTY_ACCESS', name: n.name || '', file: n.file || '', line: n.line };
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!found) {
|
|
78
|
+
spinner.stop();
|
|
79
|
+
exitWithError(`Symbol not found: "${symbol}"`, [
|
|
80
|
+
'Check the symbol name and try again',
|
|
81
|
+
'Use: grafema query "<name>" to search available nodes',
|
|
82
|
+
]);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
spinner.stop();
|
|
86
|
+
// Cast backend to DataflowBackend
|
|
87
|
+
const dfDb = backend;
|
|
88
|
+
// Trace backward
|
|
89
|
+
const results = await traceDataflow(dfDb, found.id, {
|
|
90
|
+
direction: 'backward',
|
|
91
|
+
maxDepth,
|
|
92
|
+
});
|
|
93
|
+
if (options.json) {
|
|
94
|
+
console.log(JSON.stringify({
|
|
95
|
+
symbol: found.name,
|
|
96
|
+
node: found,
|
|
97
|
+
results: results.map(r => ({
|
|
98
|
+
direction: r.direction,
|
|
99
|
+
startNode: r.startNode,
|
|
100
|
+
reached: r.reached,
|
|
101
|
+
totalReached: r.totalReached,
|
|
102
|
+
})),
|
|
103
|
+
}, null, 2));
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.log(`${found.name} (${found.type}) — ${found.file}${found.line ? ':' + found.line : ''}`);
|
|
107
|
+
console.log('');
|
|
108
|
+
const narrative = renderTraceNarrative(results, found.name, { detail: 'normal' });
|
|
109
|
+
console.log(narrative);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
spinner.stop();
|
|
114
|
+
await backend.close();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=wtf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wtf.js","sourceRoot":"","sources":["../../src/commands/wtf.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Built-in plugin registry — maps plugin names to factory functions.
|
|
3
|
-
*
|
|
4
|
-
* Each entry creates a fresh plugin instance. Plugin names match the class names
|
|
5
|
-
* and are referenced by name in .grafema/config.yaml under phases:
|
|
6
|
-
* discovery, indexing, analysis, enrichment, validation.
|
|
7
|
-
*/
|
|
8
|
-
import type { Plugin } from '@grafema/core';
|
|
9
|
-
export declare const BUILTIN_PLUGINS: Record<string, () => Plugin>;
|
|
1
|
+
export {};
|
|
10
2
|
//# sourceMappingURL=builtinPlugins.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtinPlugins.d.ts","sourceRoot":"","sources":["../../src/plugins/builtinPlugins.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"builtinPlugins.d.ts","sourceRoot":"","sources":["../../src/plugins/builtinPlugins.ts"],"names":[],"mappings":""}
|
|
@@ -1,68 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Each entry creates a fresh plugin instance. Plugin names match the class names
|
|
5
|
-
* and are referenced by name in .grafema/config.yaml under phases:
|
|
6
|
-
* discovery, indexing, analysis, enrichment, validation.
|
|
7
|
-
*/
|
|
8
|
-
import {
|
|
9
|
-
// Discovery
|
|
10
|
-
SimpleProjectDiscovery, MonorepoServiceDiscovery, WorkspaceDiscovery,
|
|
11
|
-
// Indexing
|
|
12
|
-
JSModuleIndexer, RustModuleIndexer,
|
|
13
|
-
// Analysis
|
|
14
|
-
JSASTAnalyzer, ExpressRouteAnalyzer, ExpressResponseAnalyzer, NestJSRouteAnalyzer, SocketIOAnalyzer, DatabaseAnalyzer, FetchAnalyzer, ServiceLayerAnalyzer, ReactAnalyzer, RustAnalyzer,
|
|
15
|
-
// Enrichment
|
|
16
|
-
MethodCallResolver, ArgumentParameterLinker, AliasTracker, ValueDomainAnalyzer, MountPointResolver, ExpressHandlerLinker, PrefixEvaluator, InstanceOfResolver, ImportExportLinker, FunctionCallResolver, HTTPConnectionEnricher, ConfigRoutingMapBuilder, ServiceConnectionEnricher, RustFFIEnricher, RejectionPropagationEnricher, CallbackCallResolver,
|
|
17
|
-
// Validation
|
|
18
|
-
CallResolverValidator, EvalBanValidator, SQLInjectionValidator, AwaitInLoopValidator, ShadowingDetector, GraphConnectivityValidator, DataFlowValidator, TypeScriptDeadCodeValidator, BrokenImportValidator, UnconnectedRouteValidator, PackageCoverageValidator, } from '@grafema/core';
|
|
19
|
-
export const BUILTIN_PLUGINS = {
|
|
20
|
-
// Discovery
|
|
21
|
-
SimpleProjectDiscovery: () => new SimpleProjectDiscovery(),
|
|
22
|
-
MonorepoServiceDiscovery: () => new MonorepoServiceDiscovery(),
|
|
23
|
-
WorkspaceDiscovery: () => new WorkspaceDiscovery(),
|
|
24
|
-
// Indexing
|
|
25
|
-
JSModuleIndexer: () => new JSModuleIndexer(),
|
|
26
|
-
RustModuleIndexer: () => new RustModuleIndexer(),
|
|
27
|
-
// Analysis
|
|
28
|
-
JSASTAnalyzer: () => new JSASTAnalyzer(),
|
|
29
|
-
ExpressRouteAnalyzer: () => new ExpressRouteAnalyzer(),
|
|
30
|
-
ExpressResponseAnalyzer: () => new ExpressResponseAnalyzer(),
|
|
31
|
-
NestJSRouteAnalyzer: () => new NestJSRouteAnalyzer(),
|
|
32
|
-
SocketIOAnalyzer: () => new SocketIOAnalyzer(),
|
|
33
|
-
DatabaseAnalyzer: () => new DatabaseAnalyzer(),
|
|
34
|
-
FetchAnalyzer: () => new FetchAnalyzer(),
|
|
35
|
-
ServiceLayerAnalyzer: () => new ServiceLayerAnalyzer(),
|
|
36
|
-
ReactAnalyzer: () => new ReactAnalyzer(),
|
|
37
|
-
RustAnalyzer: () => new RustAnalyzer(),
|
|
38
|
-
// Enrichment
|
|
39
|
-
MethodCallResolver: () => new MethodCallResolver(),
|
|
40
|
-
ArgumentParameterLinker: () => new ArgumentParameterLinker(),
|
|
41
|
-
AliasTracker: () => new AliasTracker(),
|
|
42
|
-
ValueDomainAnalyzer: () => new ValueDomainAnalyzer(),
|
|
43
|
-
MountPointResolver: () => new MountPointResolver(),
|
|
44
|
-
ExpressHandlerLinker: () => new ExpressHandlerLinker(),
|
|
45
|
-
PrefixEvaluator: () => new PrefixEvaluator(),
|
|
46
|
-
InstanceOfResolver: () => new InstanceOfResolver(),
|
|
47
|
-
ImportExportLinker: () => new ImportExportLinker(),
|
|
48
|
-
FunctionCallResolver: () => new FunctionCallResolver(),
|
|
49
|
-
HTTPConnectionEnricher: () => new HTTPConnectionEnricher(),
|
|
50
|
-
ConfigRoutingMapBuilder: () => new ConfigRoutingMapBuilder(),
|
|
51
|
-
ServiceConnectionEnricher: () => new ServiceConnectionEnricher(),
|
|
52
|
-
RustFFIEnricher: () => new RustFFIEnricher(),
|
|
53
|
-
RejectionPropagationEnricher: () => new RejectionPropagationEnricher(),
|
|
54
|
-
CallbackCallResolver: () => new CallbackCallResolver(),
|
|
55
|
-
// Validation
|
|
56
|
-
CallResolverValidator: () => new CallResolverValidator(),
|
|
57
|
-
EvalBanValidator: () => new EvalBanValidator(),
|
|
58
|
-
SQLInjectionValidator: () => new SQLInjectionValidator(),
|
|
59
|
-
AwaitInLoopValidator: () => new AwaitInLoopValidator(),
|
|
60
|
-
ShadowingDetector: () => new ShadowingDetector(),
|
|
61
|
-
GraphConnectivityValidator: () => new GraphConnectivityValidator(),
|
|
62
|
-
DataFlowValidator: () => new DataFlowValidator(),
|
|
63
|
-
TypeScriptDeadCodeValidator: () => new TypeScriptDeadCodeValidator(),
|
|
64
|
-
BrokenImportValidator: () => new BrokenImportValidator(),
|
|
65
|
-
UnconnectedRouteValidator: () => new UnconnectedRouteValidator(),
|
|
66
|
-
PackageCoverageValidator: () => new PackageCoverageValidator(),
|
|
67
|
-
};
|
|
1
|
+
export {};
|
|
2
|
+
// Deleted: plugin registration moved to grafema-orchestrator (Rust).
|
|
68
3
|
//# sourceMappingURL=builtinPlugins.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtinPlugins.js","sourceRoot":"","sources":["../../src/plugins/builtinPlugins.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"builtinPlugins.js","sourceRoot":"","sources":["../../src/plugins/builtinPlugins.ts"],"names":[],"mappings":";AAAA,qEAAqE"}
|
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* Plugin loading — resolves built-in and custom plugins from config.
|
|
3
|
-
*
|
|
4
|
-
* Handles:
|
|
5
|
-
* - ESM resolve hook for custom plugin @grafema/* imports
|
|
6
|
-
* - Loading custom plugins from .grafema/plugins/
|
|
7
|
-
* - Creating plugin instances from config phases
|
|
8
|
-
*/
|
|
9
|
-
import type { Plugin, GrafemaConfig } from '@grafema/core';
|
|
10
|
-
export declare function registerPluginResolver(): void;
|
|
11
|
-
/**
|
|
12
|
-
* Load custom plugins from .grafema/plugins/ directory
|
|
13
|
-
*/
|
|
14
|
-
export declare function loadCustomPlugins(projectPath: string, log: (msg: string) => void): Promise<Record<string, () => Plugin>>;
|
|
15
|
-
export declare function createPlugins(config: GrafemaConfig['plugins'], customPlugins?: Record<string, () => Plugin>, verbose?: boolean): Plugin[];
|
|
1
|
+
export {};
|
|
16
2
|
//# sourceMappingURL=pluginLoader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/plugins/pluginLoader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/plugins/pluginLoader.ts"],"names":[],"mappings":""}
|
|
@@ -1,101 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Handles:
|
|
5
|
-
* - ESM resolve hook for custom plugin @grafema/* imports
|
|
6
|
-
* - Loading custom plugins from .grafema/plugins/
|
|
7
|
-
* - Creating plugin instances from config phases
|
|
8
|
-
*/
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
import { existsSync, readdirSync } from 'fs';
|
|
11
|
-
import { pathToFileURL } from 'url';
|
|
12
|
-
import { register } from 'node:module';
|
|
13
|
-
import { BUILTIN_PLUGINS } from './builtinPlugins.js';
|
|
14
|
-
/**
|
|
15
|
-
* Register ESM resolve hook so custom plugins can import @grafema/* packages.
|
|
16
|
-
*
|
|
17
|
-
* Plugins in .grafema/plugins/ do `import { Plugin } from '@grafema/core'`,
|
|
18
|
-
* but @grafema/core isn't in the target project's node_modules/.
|
|
19
|
-
* This hook redirects those imports to the CLI's bundled packages.
|
|
20
|
-
*
|
|
21
|
-
* Uses module.register() (stable Node.js 20.6+ API).
|
|
22
|
-
* Safe to call multiple times — subsequent calls add redundant hooks
|
|
23
|
-
* that short-circuit on the same specifiers.
|
|
24
|
-
*/
|
|
25
|
-
let pluginResolverRegistered = false;
|
|
26
|
-
export function registerPluginResolver() {
|
|
27
|
-
if (pluginResolverRegistered)
|
|
28
|
-
return;
|
|
29
|
-
pluginResolverRegistered = true;
|
|
30
|
-
const grafemaPackages = {};
|
|
31
|
-
for (const pkg of ['@grafema/core', '@grafema/types']) {
|
|
32
|
-
try {
|
|
33
|
-
grafemaPackages[pkg] = import.meta.resolve(pkg);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
// Package not available from CLI context — skip
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
register(new URL('./pluginResolver.js', import.meta.url), { data: { grafemaPackages } });
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Load custom plugins from .grafema/plugins/ directory
|
|
43
|
-
*/
|
|
44
|
-
export async function loadCustomPlugins(projectPath, log) {
|
|
45
|
-
const pluginsDir = join(projectPath, '.grafema', 'plugins');
|
|
46
|
-
if (!existsSync(pluginsDir)) {
|
|
47
|
-
return {};
|
|
48
|
-
}
|
|
49
|
-
// Ensure @grafema/* imports resolve for custom plugins (REG-380)
|
|
50
|
-
registerPluginResolver();
|
|
51
|
-
const customPlugins = {};
|
|
52
|
-
try {
|
|
53
|
-
const files = readdirSync(pluginsDir).filter((f) => f.endsWith('.js') || f.endsWith('.mjs') || f.endsWith('.cjs'));
|
|
54
|
-
for (const file of files) {
|
|
55
|
-
try {
|
|
56
|
-
const pluginPath = join(pluginsDir, file);
|
|
57
|
-
const pluginUrl = pathToFileURL(pluginPath).href;
|
|
58
|
-
const module = await import(pluginUrl);
|
|
59
|
-
const PluginClass = module.default || module[file.replace(/\.[cm]?js$/, '')];
|
|
60
|
-
if (PluginClass && typeof PluginClass === 'function') {
|
|
61
|
-
const pluginName = PluginClass.name || file.replace(/\.[cm]?js$/, '');
|
|
62
|
-
customPlugins[pluginName] = () => {
|
|
63
|
-
const instance = new PluginClass();
|
|
64
|
-
instance.config.sourceFile = pluginPath;
|
|
65
|
-
return instance;
|
|
66
|
-
};
|
|
67
|
-
log(`Loaded custom plugin: ${pluginName}`);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
72
|
-
console.warn(`Failed to load plugin ${file}: ${message}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
78
|
-
console.warn(`Error loading custom plugins: ${message}`);
|
|
79
|
-
}
|
|
80
|
-
return customPlugins;
|
|
81
|
-
}
|
|
82
|
-
export function createPlugins(config, customPlugins = {}, verbose = false) {
|
|
83
|
-
const plugins = [];
|
|
84
|
-
const phases = ['discovery', 'indexing', 'analysis', 'enrichment', 'validation'];
|
|
85
|
-
for (const phase of phases) {
|
|
86
|
-
const names = config[phase] || [];
|
|
87
|
-
for (const name of names) {
|
|
88
|
-
// Check built-in first, then custom
|
|
89
|
-
const factory = BUILTIN_PLUGINS[name] || customPlugins[name];
|
|
90
|
-
if (factory) {
|
|
91
|
-
plugins.push(factory());
|
|
92
|
-
}
|
|
93
|
-
else if (verbose) {
|
|
94
|
-
// Only show plugin warning in verbose mode
|
|
95
|
-
console.warn(`Plugin not found: ${name} (skipping). Check .grafema/config.yaml or add to .grafema/plugins/`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return plugins;
|
|
100
|
-
}
|
|
1
|
+
export {};
|
|
2
|
+
// Deleted: plugin loading moved to grafema-orchestrator (Rust).
|
|
101
3
|
//# sourceMappingURL=pluginLoader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluginLoader.js","sourceRoot":"","sources":["../../src/plugins/pluginLoader.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pluginLoader.js","sourceRoot":"","sources":["../../src/plugins/pluginLoader.ts"],"names":[],"mappings":";AAAA,gEAAgE"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ESM resolve hook for custom Grafema plugins.
|
|
3
3
|
*
|
|
4
|
-
* Allows plugins in .grafema/plugins/ to `import { Plugin } from '@grafema/
|
|
5
|
-
* without requiring @grafema/
|
|
4
|
+
* Allows plugins in .grafema/plugins/ to `import { Plugin } from '@grafema/util'`
|
|
5
|
+
* without requiring @grafema/util in the target project's node_modules/.
|
|
6
6
|
*
|
|
7
7
|
* The hook maps @grafema/* bare specifiers to the actual package URLs
|
|
8
8
|
* within the CLI's dependency tree.
|
|
@@ -26,7 +26,7 @@ export function initialize(data) {
|
|
|
26
26
|
* Resolve hook — intercepts bare specifier imports for @grafema/* packages
|
|
27
27
|
* and redirects them to the CLI's bundled versions.
|
|
28
28
|
*
|
|
29
|
-
* Only exact package name matches are handled (e.g. '@grafema/
|
|
29
|
+
* Only exact package name matches are handled (e.g. '@grafema/util').
|
|
30
30
|
* All other specifiers pass through to the default resolver.
|
|
31
31
|
*/
|
|
32
32
|
export function resolve(specifier, context, next) {
|
|
@@ -14,7 +14,21 @@
|
|
|
14
14
|
* console.log(renderer.finish(elapsed));
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Progress information from the analysis pipeline.
|
|
19
|
+
* Defined locally to avoid dependency on @grafema/util.
|
|
20
|
+
*/
|
|
21
|
+
export interface ProgressInfo {
|
|
22
|
+
phase: string;
|
|
23
|
+
currentPlugin?: string;
|
|
24
|
+
message?: string;
|
|
25
|
+
servicesDiscovered?: number;
|
|
26
|
+
servicesAnalyzed?: number;
|
|
27
|
+
totalServices?: number;
|
|
28
|
+
totalFiles?: number;
|
|
29
|
+
processedFiles?: number;
|
|
30
|
+
currentService?: string;
|
|
31
|
+
}
|
|
18
32
|
/**
|
|
19
33
|
* Options for creating a ProgressRenderer instance.
|
|
20
34
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressRenderer.d.ts","sourceRoot":"","sources":["../../src/utils/progressRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,
|
|
1
|
+
{"version":3,"file":"progressRenderer.d.ts","sourceRoot":"","sources":["../../src/utils/progressRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAA+E;IAC7F,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,aAAa,CAAsD;IAC3E,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,SAAS,CAAa;gBAElB,OAAO,CAAC,EAAE,uBAAuB;IAO7C;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IA0DhC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpD;;OAEG;IACH,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,iBAAiB;IAWzB,OAAO,CAAC,oBAAoB;IAK5B;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4C3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;;;OAIG;IACH,MAAM,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM;IAIvC;;;OAGG;IACH,QAAQ,IAAI;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,gBAAgB,EAAE,MAAM,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACnB;CAeF"}
|
|
@@ -62,6 +62,11 @@ export class ProgressRenderer {
|
|
|
62
62
|
}
|
|
63
63
|
// Reset phase-specific state
|
|
64
64
|
this.activePlugins = [];
|
|
65
|
+
this.currentService = '';
|
|
66
|
+
this.servicesAnalyzed = 0;
|
|
67
|
+
this.totalServices = 0;
|
|
68
|
+
this.processedFiles = 0;
|
|
69
|
+
this.totalFiles = 0;
|
|
65
70
|
}
|
|
66
71
|
// Update state from progress info
|
|
67
72
|
if (info.currentPlugin !== undefined) {
|
|
@@ -198,14 +203,12 @@ export class ProgressRenderer {
|
|
|
198
203
|
return ` ${this.servicesAnalyzed} services found`;
|
|
199
204
|
}
|
|
200
205
|
return '';
|
|
201
|
-
case 'indexing':
|
|
202
|
-
case 'analysis': {
|
|
206
|
+
case 'indexing': {
|
|
203
207
|
const parts = [];
|
|
204
208
|
if (this.totalServices > 0) {
|
|
205
209
|
parts.push(`${this.servicesAnalyzed}/${this.totalServices} services`);
|
|
206
210
|
}
|
|
207
211
|
if (this.currentService) {
|
|
208
|
-
// Truncate long service names
|
|
209
212
|
const name = this.currentService.length > 30
|
|
210
213
|
? '...' + this.currentService.slice(-27)
|
|
211
214
|
: this.currentService;
|
|
@@ -213,6 +216,19 @@ export class ProgressRenderer {
|
|
|
213
216
|
}
|
|
214
217
|
return parts.length > 0 ? ` ${parts.join(' | ')}` : '';
|
|
215
218
|
}
|
|
219
|
+
case 'analysis': {
|
|
220
|
+
const parts = [];
|
|
221
|
+
if (this.totalFiles > 0) {
|
|
222
|
+
parts.push(`${this.processedFiles}/${this.totalFiles} files`);
|
|
223
|
+
}
|
|
224
|
+
if (this.currentService) {
|
|
225
|
+
const name = this.currentService.length > 40
|
|
226
|
+
? '...' + this.currentService.slice(-37)
|
|
227
|
+
: this.currentService;
|
|
228
|
+
parts.push(name);
|
|
229
|
+
}
|
|
230
|
+
return parts.length > 0 ? ` ${parts.join(' | ')}` : '';
|
|
231
|
+
}
|
|
216
232
|
case 'enrichment':
|
|
217
233
|
case 'validation':
|
|
218
234
|
if (this.activePlugins.length > 0) {
|