project-graph-mcp 1.3.0 → 2.0.0
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/README.md +223 -17
- package/{AGENT_ROLE.md → docs/examples/AGENT_ROLE.md} +87 -30
- package/{AGENT_ROLE_MINIMAL.md → docs/examples/AGENT_ROLE_MINIMAL.md} +23 -8
- package/package.json +12 -8
- package/src/.project-graph-cache.json +1 -0
- package/src/analysis/analysis-cache.js +7 -0
- package/src/analysis/complexity.js +14 -0
- package/src/analysis/custom-rules.js +36 -0
- package/src/analysis/db-analysis.js +9 -0
- package/src/analysis/dead-code.js +19 -0
- package/src/analysis/full-analysis.js +18 -0
- package/src/analysis/jsdoc-checker.js +24 -0
- package/src/analysis/jsdoc-generator.js +10 -0
- package/src/analysis/large-files.js +11 -0
- package/src/analysis/outdated-patterns.js +12 -0
- package/src/analysis/similar-functions.js +16 -0
- package/src/analysis/test-annotations.js +21 -0
- package/src/analysis/type-checker.js +8 -0
- package/src/analysis/undocumented.js +14 -0
- package/src/cli/cli-handlers.js +4 -0
- package/src/cli/cli.js +5 -0
- package/src/compact/ai-context.js +7 -0
- package/src/compact/compact.js +18 -0
- package/src/compact/compress.js +13 -0
- package/src/compact/ctx-to-jsdoc.js +29 -0
- package/src/compact/doc-dialect.js +30 -0
- package/src/compact/expand.js +37 -0
- package/src/compact/framework-references.js +5 -0
- package/src/compact/instructions.js +3 -0
- package/src/compact/mode-config.js +8 -0
- package/src/compact/validate-pipeline.js +9 -0
- package/src/core/event-bus.js +9 -0
- package/src/core/filters.js +14 -0
- package/src/core/graph-builder.js +12 -0
- package/src/core/parser.js +31 -0
- package/src/core/workspace.js +8 -0
- package/src/lang/lang-go.js +17 -0
- package/src/lang/lang-python.js +12 -0
- package/src/lang/lang-sql.js +23 -0
- package/src/lang/lang-typescript.js +9 -0
- package/src/lang/lang-utils.js +4 -0
- package/src/mcp/mcp-server.js +17 -0
- package/src/mcp/tool-defs.js +3 -0
- package/src/mcp/tools.js +25 -0
- package/src/network/backend-lifecycle.js +19 -0
- package/src/network/backend.js +5 -0
- package/src/network/local-gateway.js +23 -0
- package/src/network/mdns.js +13 -0
- package/src/network/server.js +10 -0
- package/src/network/web-server.js +34 -0
- package/vendor/terser.mjs +49 -0
- package/web/.project-graph-cache.json +1 -0
- package/web/app.js +16 -0
- package/web/components/code-block.js +3 -0
- package/web/components/quick-open.js +5 -0
- package/web/dashboard-state.js +3 -0
- package/web/dashboard.html +27 -0
- package/web/dashboard.js +8 -0
- package/web/highlight.js +13 -0
- package/web/index.html +35 -0
- package/web/panels/ActionBoard/ActionBoard.css.js +1 -0
- package/web/panels/ActionBoard/ActionBoard.js +4 -0
- package/web/panels/ActionBoard/ActionBoard.tpl.js +1 -0
- package/web/panels/EventItem/EventItem.css.js +1 -0
- package/web/panels/EventItem/EventItem.js +4 -0
- package/web/panels/EventItem/EventItem.tpl.js +1 -0
- package/web/panels/ProjectItem/ProjectItem.css.js +1 -0
- package/web/panels/ProjectItem/ProjectItem.js +5 -0
- package/web/panels/ProjectItem/ProjectItem.tpl.js +1 -0
- package/web/panels/ProjectList/ProjectList.css.js +1 -0
- package/web/panels/ProjectList/ProjectList.js +4 -0
- package/web/panels/ProjectList/ProjectList.tpl.js +1 -0
- package/web/panels/SettingsPanel/.project-graph-cache.json +1 -0
- package/web/panels/SettingsPanel/SettingsPanel.css.js +1 -0
- package/web/panels/SettingsPanel/SettingsPanel.js +7 -0
- package/web/panels/SettingsPanel/SettingsPanel.tpl.js +1 -0
- package/web/panels/code-viewer.js +5 -0
- package/web/panels/ctx-panel.js +4 -0
- package/web/panels/dep-graph.js +6 -0
- package/web/panels/file-tree.js +188 -0
- package/web/panels/health-panel.js +3 -0
- package/web/panels/live-monitor.js +3 -0
- package/web/state.js +17 -0
- package/web/style.css +157 -0
- package/references/symbiote-3x.md +0 -834
- package/src/cli-handlers.js +0 -140
- package/src/cli.js +0 -83
- package/src/complexity.js +0 -223
- package/src/custom-rules.js +0 -583
- package/src/db-analysis.js +0 -194
- package/src/dead-code.js +0 -468
- package/src/filters.js +0 -227
- package/src/framework-references.js +0 -177
- package/src/full-analysis.js +0 -174
- package/src/graph-builder.js +0 -299
- package/src/instructions.js +0 -175
- package/src/jsdoc-generator.js +0 -214
- package/src/lang-go.js +0 -285
- package/src/lang-python.js +0 -197
- package/src/lang-sql.js +0 -309
- package/src/lang-typescript.js +0 -190
- package/src/lang-utils.js +0 -124
- package/src/large-files.js +0 -162
- package/src/mcp-server.js +0 -468
- package/src/outdated-patterns.js +0 -295
- package/src/parser.js +0 -452
- package/src/server.js +0 -28
- package/src/similar-functions.js +0 -278
- package/src/test-annotations.js +0 -301
- package/src/tool-defs.js +0 -525
- package/src/tools.js +0 -470
- package/src/undocumented.js +0 -260
- package/src/workspace.js +0 -70
package/src/outdated-patterns.js
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Outdated Patterns Detector
|
|
3
|
-
* Finds legacy code patterns and redundant npm dependencies
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { readFileSync, readdirSync, statSync, existsSync } from 'fs';
|
|
7
|
-
import { join, relative, resolve } from 'path';
|
|
8
|
-
import { parse } from '../vendor/acorn.mjs';
|
|
9
|
-
import * as walk from '../vendor/walk.mjs';
|
|
10
|
-
import { shouldExcludeDir, shouldExcludeFile, parseGitignore } from './filters.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Redundant npm packages that are now built into Node.js 18+
|
|
14
|
-
*/
|
|
15
|
-
const REDUNDANT_DEPS = {
|
|
16
|
-
'node-fetch': { replacement: 'fetch()', since: 'Node 18' },
|
|
17
|
-
'cross-fetch': { replacement: 'fetch()', since: 'Node 18' },
|
|
18
|
-
'isomorphic-fetch': { replacement: 'fetch()', since: 'Node 18' },
|
|
19
|
-
'uuid': { replacement: 'crypto.randomUUID()', since: 'Node 19' },
|
|
20
|
-
'deep-clone': { replacement: 'structuredClone()', since: 'Node 17' },
|
|
21
|
-
'lodash.clonedeep': { replacement: 'structuredClone()', since: 'Node 17' },
|
|
22
|
-
'abort-controller': { replacement: 'AbortController (global)', since: 'Node 15' },
|
|
23
|
-
'form-data': { replacement: 'FormData (global)', since: 'Node 18' },
|
|
24
|
-
'web-streams-polyfill': { replacement: 'ReadableStream (global)', since: 'Node 18' },
|
|
25
|
-
'url-parse': { replacement: 'URL (global)', since: 'Node 10' },
|
|
26
|
-
'querystring': { replacement: 'URLSearchParams', since: 'Node 10' },
|
|
27
|
-
'rimraf': { replacement: 'fs.rm({ recursive: true })', since: 'Node 14' },
|
|
28
|
-
'mkdirp': { replacement: 'fs.mkdir({ recursive: true })', since: 'Node 10' },
|
|
29
|
-
'recursive-readdir': { replacement: 'fs.readdir({ recursive: true })', since: 'Node 20' },
|
|
30
|
-
'glob': { replacement: 'fs.glob()', since: 'Node 22' },
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Legacy code patterns to detect
|
|
35
|
-
*/
|
|
36
|
-
const CODE_PATTERNS = [
|
|
37
|
-
{
|
|
38
|
-
name: 'var-usage',
|
|
39
|
-
description: 'Use const/let instead of var',
|
|
40
|
-
check: (node) => node.type === 'VariableDeclaration' && node.kind === 'var',
|
|
41
|
-
severity: 'warning',
|
|
42
|
-
replacement: 'const/let',
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'require-usage',
|
|
46
|
-
description: 'Use ESM import instead of require()',
|
|
47
|
-
check: (node) => node.type === 'CallExpression' &&
|
|
48
|
-
node.callee.type === 'Identifier' && node.callee.name === 'require',
|
|
49
|
-
severity: 'info',
|
|
50
|
-
replacement: 'import ... from',
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'module-exports',
|
|
54
|
-
description: 'Use ESM export instead of module.exports',
|
|
55
|
-
check: (node) => node.type === 'AssignmentExpression' &&
|
|
56
|
-
node.left.type === 'MemberExpression' &&
|
|
57
|
-
node.left.object.type === 'Identifier' && node.left.object.name === 'module' &&
|
|
58
|
-
node.left.property.type === 'Identifier' && node.left.property.name === 'exports',
|
|
59
|
-
severity: 'info',
|
|
60
|
-
replacement: 'export default/export',
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
name: 'buffer-constructor',
|
|
64
|
-
description: 'new Buffer() is deprecated',
|
|
65
|
-
check: (node) => node.type === 'NewExpression' &&
|
|
66
|
-
node.callee.type === 'Identifier' && node.callee.name === 'Buffer',
|
|
67
|
-
severity: 'error',
|
|
68
|
-
replacement: 'Buffer.from() / Buffer.alloc()',
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
name: 'arguments-usage',
|
|
72
|
-
description: 'Use rest parameters instead of arguments',
|
|
73
|
-
check: (node) => node.type === 'Identifier' && node.name === 'arguments',
|
|
74
|
-
severity: 'warning',
|
|
75
|
-
replacement: '...args',
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: 'promisify-usage',
|
|
79
|
-
description: 'Use fs/promises instead of util.promisify',
|
|
80
|
-
check: (node) => node.type === 'CallExpression' &&
|
|
81
|
-
node.callee.type === 'MemberExpression' &&
|
|
82
|
-
node.callee.object.type === 'Identifier' && node.callee.object.name === 'util' &&
|
|
83
|
-
node.callee.property.type === 'Identifier' && node.callee.property.name === 'promisify',
|
|
84
|
-
severity: 'info',
|
|
85
|
-
replacement: 'fs/promises module',
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
name: 'sync-in-async',
|
|
89
|
-
description: 'Avoid sync methods in async context (readFileSync, etc.)',
|
|
90
|
-
check: (node, context) => {
|
|
91
|
-
if (node.type !== 'CallExpression') return false;
|
|
92
|
-
const callee = node.callee;
|
|
93
|
-
if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
|
|
94
|
-
const name = callee.property.name;
|
|
95
|
-
return name.endsWith('Sync') && context.inAsync;
|
|
96
|
-
}
|
|
97
|
-
return false;
|
|
98
|
-
},
|
|
99
|
-
severity: 'warning',
|
|
100
|
-
replacement: 'async fs/promises methods',
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* @typedef {Object} PatternMatch
|
|
106
|
-
* @property {string} pattern
|
|
107
|
-
* @property {string} description
|
|
108
|
-
* @property {string} file
|
|
109
|
-
* @property {number} line
|
|
110
|
-
* @property {string} severity
|
|
111
|
-
* @property {string} replacement
|
|
112
|
-
*/
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* @typedef {Object} RedundantDep
|
|
116
|
-
* @property {string} name
|
|
117
|
-
* @property {string} replacement
|
|
118
|
-
* @property {string} since
|
|
119
|
-
*/
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Find all JS files
|
|
123
|
-
* @param {string} dir
|
|
124
|
-
* @param {string} rootDir
|
|
125
|
-
* @returns {string[]}
|
|
126
|
-
*/
|
|
127
|
-
function findJSFiles(dir, rootDir = dir) {
|
|
128
|
-
if (dir === rootDir) parseGitignore(rootDir);
|
|
129
|
-
const files = [];
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
for (const entry of readdirSync(dir)) {
|
|
133
|
-
const fullPath = join(dir, entry);
|
|
134
|
-
const relativePath = relative(rootDir, fullPath);
|
|
135
|
-
const stat = statSync(fullPath);
|
|
136
|
-
|
|
137
|
-
if (stat.isDirectory()) {
|
|
138
|
-
if (!shouldExcludeDir(entry, relativePath)) {
|
|
139
|
-
files.push(...findJSFiles(fullPath, rootDir));
|
|
140
|
-
}
|
|
141
|
-
} else if (entry.endsWith('.js') && !entry.endsWith('.css.js') && !entry.endsWith('.tpl.js')) {
|
|
142
|
-
if (!shouldExcludeFile(entry, relativePath)) {
|
|
143
|
-
files.push(fullPath);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
} catch (e) { }
|
|
148
|
-
|
|
149
|
-
return files;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Analyze file for outdated patterns
|
|
154
|
-
* @param {string} filePath
|
|
155
|
-
* @returns {PatternMatch[]}
|
|
156
|
-
*/
|
|
157
|
-
function analyzeFilePatterns(filePath, rootDir) {
|
|
158
|
-
const code = readFileSync(filePath, 'utf-8');
|
|
159
|
-
const relPath = relative(rootDir, filePath);
|
|
160
|
-
const matches = [];
|
|
161
|
-
|
|
162
|
-
let ast;
|
|
163
|
-
try {
|
|
164
|
-
ast = parse(code, { ecmaVersion: 'latest', sourceType: 'module', locations: true });
|
|
165
|
-
} catch (e) {
|
|
166
|
-
return matches;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Track async context
|
|
170
|
-
const context = { inAsync: false };
|
|
171
|
-
|
|
172
|
-
walk.simple(ast, {
|
|
173
|
-
FunctionDeclaration(node) {
|
|
174
|
-
context.inAsync = node.async;
|
|
175
|
-
},
|
|
176
|
-
ArrowFunctionExpression(node) {
|
|
177
|
-
context.inAsync = node.async;
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// Reset and check patterns
|
|
182
|
-
context.inAsync = false;
|
|
183
|
-
|
|
184
|
-
walk.ancestor(ast, {
|
|
185
|
-
'*'(node, ancestors) {
|
|
186
|
-
// Update async context
|
|
187
|
-
for (const anc of ancestors) {
|
|
188
|
-
if ((anc.type === 'FunctionDeclaration' || anc.type === 'ArrowFunctionExpression' ||
|
|
189
|
-
anc.type === 'FunctionExpression') && anc.async) {
|
|
190
|
-
context.inAsync = true;
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
for (const pattern of CODE_PATTERNS) {
|
|
196
|
-
if (pattern.check(node, context)) {
|
|
197
|
-
matches.push({
|
|
198
|
-
pattern: pattern.name,
|
|
199
|
-
description: pattern.description,
|
|
200
|
-
file: relPath,
|
|
201
|
-
line: node.loc?.start?.line || 0,
|
|
202
|
-
severity: pattern.severity,
|
|
203
|
-
replacement: pattern.replacement,
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
return matches;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Analyze package.json for redundant dependencies
|
|
215
|
-
* @param {string} dir
|
|
216
|
-
* @returns {RedundantDep[]}
|
|
217
|
-
*/
|
|
218
|
-
function analyzePackageJson(dir) {
|
|
219
|
-
const pkgPath = join(dir, 'package.json');
|
|
220
|
-
const redundant = [];
|
|
221
|
-
|
|
222
|
-
if (!existsSync(pkgPath)) return redundant;
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
226
|
-
const allDeps = {
|
|
227
|
-
...pkg.dependencies,
|
|
228
|
-
...pkg.devDependencies,
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
for (const depName of Object.keys(allDeps)) {
|
|
232
|
-
if (REDUNDANT_DEPS[depName]) {
|
|
233
|
-
redundant.push({
|
|
234
|
-
name: depName,
|
|
235
|
-
...REDUNDANT_DEPS[depName],
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
} catch (e) { }
|
|
240
|
-
|
|
241
|
-
return redundant;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Get outdated patterns analysis
|
|
246
|
-
* @param {string} dir
|
|
247
|
-
* @param {Object} [options]
|
|
248
|
-
* @param {boolean} [options.codeOnly=false] - Only check code patterns
|
|
249
|
-
* @param {boolean} [options.depsOnly=false] - Only check dependencies
|
|
250
|
-
* @returns {Promise<{codePatterns: PatternMatch[], redundantDeps: RedundantDep[], stats: Object}>}
|
|
251
|
-
*/
|
|
252
|
-
export async function getOutdatedPatterns(dir, options = {}) {
|
|
253
|
-
const codeOnly = options.codeOnly || false;
|
|
254
|
-
const depsOnly = options.depsOnly || false;
|
|
255
|
-
const resolvedDir = resolve(dir);
|
|
256
|
-
|
|
257
|
-
let codePatterns = [];
|
|
258
|
-
let redundantDeps = [];
|
|
259
|
-
|
|
260
|
-
if (!depsOnly) {
|
|
261
|
-
const files = findJSFiles(dir);
|
|
262
|
-
for (const file of files) {
|
|
263
|
-
codePatterns.push(...analyzeFilePatterns(file, resolvedDir));
|
|
264
|
-
}
|
|
265
|
-
// Sort by severity
|
|
266
|
-
const severityOrder = { error: 0, warning: 1, info: 2 };
|
|
267
|
-
codePatterns.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (!codeOnly) {
|
|
271
|
-
redundantDeps = analyzePackageJson(dir);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const stats = {
|
|
275
|
-
totalPatterns: codePatterns.length,
|
|
276
|
-
byPattern: {},
|
|
277
|
-
bySeverity: {
|
|
278
|
-
error: codePatterns.filter(p => p.severity === 'error').length,
|
|
279
|
-
warning: codePatterns.filter(p => p.severity === 'warning').length,
|
|
280
|
-
info: codePatterns.filter(p => p.severity === 'info').length,
|
|
281
|
-
},
|
|
282
|
-
redundantDeps: redundantDeps.length,
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
// Group by pattern name
|
|
286
|
-
for (const p of codePatterns) {
|
|
287
|
-
stats.byPattern[p.pattern] = (stats.byPattern[p.pattern] || 0) + 1;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return {
|
|
291
|
-
codePatterns: codePatterns.slice(0, 50),
|
|
292
|
-
redundantDeps,
|
|
293
|
-
stats,
|
|
294
|
-
};
|
|
295
|
-
}
|