project-graph-mcp 1.5.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.
Files changed (121) hide show
  1. package/README.md +128 -8
  2. package/package.json +12 -8
  3. package/src/.project-graph-cache.json +1 -1
  4. package/src/analysis/analysis-cache.js +7 -0
  5. package/src/analysis/complexity.js +14 -0
  6. package/src/analysis/custom-rules.js +36 -0
  7. package/src/analysis/db-analysis.js +9 -0
  8. package/src/analysis/dead-code.js +19 -0
  9. package/src/analysis/full-analysis.js +18 -0
  10. package/src/analysis/jsdoc-checker.js +24 -0
  11. package/src/analysis/jsdoc-generator.js +10 -0
  12. package/src/analysis/large-files.js +11 -0
  13. package/src/analysis/outdated-patterns.js +12 -0
  14. package/src/analysis/similar-functions.js +16 -0
  15. package/src/analysis/test-annotations.js +21 -0
  16. package/src/analysis/type-checker.js +8 -0
  17. package/src/analysis/undocumented.js +14 -0
  18. package/src/cli/cli-handlers.js +4 -0
  19. package/src/cli/cli.js +5 -0
  20. package/src/compact/ai-context.js +7 -0
  21. package/src/compact/compact.js +18 -0
  22. package/src/compact/compress.js +13 -0
  23. package/src/compact/ctx-to-jsdoc.js +29 -0
  24. package/src/compact/doc-dialect.js +30 -0
  25. package/src/compact/expand.js +37 -0
  26. package/src/compact/framework-references.js +5 -0
  27. package/src/compact/instructions.js +3 -0
  28. package/src/compact/mode-config.js +8 -0
  29. package/src/compact/validate-pipeline.js +9 -0
  30. package/src/core/event-bus.js +9 -0
  31. package/src/core/filters.js +14 -0
  32. package/src/core/graph-builder.js +12 -0
  33. package/src/core/parser.js +31 -0
  34. package/src/core/workspace.js +8 -0
  35. package/src/lang/lang-go.js +17 -0
  36. package/src/lang/lang-python.js +12 -0
  37. package/src/lang/lang-sql.js +23 -0
  38. package/src/lang/lang-typescript.js +9 -0
  39. package/src/lang/lang-utils.js +4 -0
  40. package/src/mcp/mcp-server.js +17 -0
  41. package/src/mcp/tool-defs.js +3 -0
  42. package/src/mcp/tools.js +25 -0
  43. package/src/network/backend-lifecycle.js +19 -0
  44. package/src/network/backend.js +5 -0
  45. package/src/network/local-gateway.js +23 -0
  46. package/src/network/mdns.js +13 -0
  47. package/src/network/server.js +10 -0
  48. package/src/network/web-server.js +34 -0
  49. package/web/.project-graph-cache.json +1 -0
  50. package/web/app.js +16 -0
  51. package/web/components/code-block.js +3 -0
  52. package/web/components/quick-open.js +5 -0
  53. package/web/dashboard-state.js +3 -0
  54. package/web/dashboard.html +27 -0
  55. package/web/dashboard.js +8 -0
  56. package/web/highlight.js +13 -0
  57. package/web/index.html +35 -0
  58. package/web/panels/ActionBoard/ActionBoard.css.js +1 -0
  59. package/web/panels/ActionBoard/ActionBoard.js +4 -0
  60. package/web/panels/ActionBoard/ActionBoard.tpl.js +1 -0
  61. package/web/panels/EventItem/EventItem.css.js +1 -0
  62. package/web/panels/EventItem/EventItem.js +4 -0
  63. package/web/panels/EventItem/EventItem.tpl.js +1 -0
  64. package/web/panels/ProjectItem/ProjectItem.css.js +1 -0
  65. package/web/panels/ProjectItem/ProjectItem.js +5 -0
  66. package/web/panels/ProjectItem/ProjectItem.tpl.js +1 -0
  67. package/web/panels/ProjectList/ProjectList.css.js +1 -0
  68. package/web/panels/ProjectList/ProjectList.js +4 -0
  69. package/web/panels/ProjectList/ProjectList.tpl.js +1 -0
  70. package/web/panels/SettingsPanel/.project-graph-cache.json +1 -0
  71. package/web/panels/SettingsPanel/SettingsPanel.css.js +1 -0
  72. package/web/panels/SettingsPanel/SettingsPanel.js +7 -0
  73. package/web/panels/SettingsPanel/SettingsPanel.tpl.js +1 -0
  74. package/web/panels/code-viewer.js +5 -0
  75. package/web/panels/ctx-panel.js +4 -0
  76. package/web/panels/dep-graph.js +6 -0
  77. package/web/panels/file-tree.js +188 -0
  78. package/web/panels/health-panel.js +3 -0
  79. package/web/panels/live-monitor.js +3 -0
  80. package/web/state.js +17 -0
  81. package/web/style.css +157 -0
  82. package/references/symbiote-3x.md +0 -834
  83. package/src/ai-context.js +0 -113
  84. package/src/analysis-cache.js +0 -155
  85. package/src/cli-handlers.js +0 -271
  86. package/src/cli.js +0 -95
  87. package/src/compact.js +0 -207
  88. package/src/complexity.js +0 -237
  89. package/src/compress.js +0 -319
  90. package/src/ctx-to-jsdoc.js +0 -514
  91. package/src/custom-rules.js +0 -584
  92. package/src/db-analysis.js +0 -194
  93. package/src/dead-code.js +0 -468
  94. package/src/doc-dialect.js +0 -716
  95. package/src/filters.js +0 -227
  96. package/src/framework-references.js +0 -177
  97. package/src/full-analysis.js +0 -470
  98. package/src/graph-builder.js +0 -299
  99. package/src/instructions.js +0 -73
  100. package/src/jsdoc-checker.js +0 -351
  101. package/src/jsdoc-generator.js +0 -203
  102. package/src/lang-go.js +0 -285
  103. package/src/lang-python.js +0 -197
  104. package/src/lang-sql.js +0 -309
  105. package/src/lang-typescript.js +0 -190
  106. package/src/lang-utils.js +0 -124
  107. package/src/large-files.js +0 -163
  108. package/src/mcp-server.js +0 -675
  109. package/src/mode-config.js +0 -127
  110. package/src/outdated-patterns.js +0 -296
  111. package/src/parser.js +0 -662
  112. package/src/server.js +0 -28
  113. package/src/similar-functions.js +0 -279
  114. package/src/test-annotations.js +0 -323
  115. package/src/tool-defs.js +0 -793
  116. package/src/tools.js +0 -470
  117. package/src/type-checker.js +0 -188
  118. package/src/undocumented.js +0 -259
  119. package/src/workspace.js +0 -70
  120. /package/{AGENT_ROLE.md → docs/examples/AGENT_ROLE.md} +0 -0
  121. /package/{AGENT_ROLE_MINIMAL.md → docs/examples/AGENT_ROLE_MINIMAL.md} +0 -0
@@ -1,259 +0,0 @@
1
- /**
2
- * Undocumented Code Finder (AST-based)
3
- * Finds methods/functions missing JSDoc annotations using Acorn AST parser
4
- */
5
-
6
- import { readFileSync, readdirSync, statSync } 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
- * @typedef {Object} UndocumentedItem
14
- * @property {string} name - ClassName.methodName or functionName
15
- * @property {string} type - 'method' | 'function' | 'class'
16
- * @property {string} file
17
- * @property {number} line
18
- * @property {string} reason - What's missing
19
- */
20
-
21
- /**
22
- * Find all JS files in directory
23
- * @param {string} dir
24
- * @param {string} rootDir
25
- * @returns {string[]}
26
- */
27
- function findJSFiles(dir, rootDir = dir) {
28
- if (dir === rootDir) {
29
- parseGitignore(rootDir);
30
- }
31
-
32
- const files = [];
33
-
34
- try {
35
- for (const entry of readdirSync(dir)) {
36
- const fullPath = join(dir, entry);
37
- const relativePath = relative(rootDir, fullPath);
38
- const stat = statSync(fullPath);
39
-
40
- if (stat.isDirectory()) {
41
- if (!shouldExcludeDir(entry, relativePath)) {
42
- files.push(...findJSFiles(fullPath, rootDir));
43
- }
44
- } else if (entry.endsWith('.js') && !entry.endsWith('.css.js') && !entry.endsWith('.tpl.js')) {
45
- if (!shouldExcludeFile(entry, relativePath)) {
46
- files.push(fullPath);
47
- }
48
- }
49
- }
50
- } catch (e) {
51
- // Directory not found
52
- }
53
-
54
- return files;
55
- }
56
-
57
- /**
58
- * Extract JSDoc comments from code with their positions
59
- * @param {string} code
60
- * @returns {Array<{text: string, endLine: number}>}
61
- */
62
- function extractComments(code) {
63
- const comments = [];
64
- const regex = /\/\*\*[\s\S]*?\*\//g;
65
- let match;
66
-
67
- while ((match = regex.exec(code)) !== null) {
68
- const endLine = code.slice(0, match.index + match[0].length).split('\n').length;
69
- comments.push({ text: match[0], endLine });
70
- }
71
-
72
- return comments;
73
- }
74
-
75
- /**
76
- * Find JSDoc comment before a target line
77
- * @param {Array<{text: string, endLine: number}>} comments - Extracted JSDoc comments
78
- * @param {number} targetLine - Line number to search before
79
- * @returns {string|null}
80
- */
81
- function findJSDocBefore(comments, targetLine) {
82
- for (const comment of comments) {
83
- const gap = targetLine - comment.endLine;
84
- if (gap >= 0 && gap <= 2) {
85
- return comment.text;
86
- }
87
- }
88
- return null;
89
- }
90
-
91
- /**
92
- * Check what's missing from JSDoc based on level
93
- * @param {string|null} jsdoc
94
- * @param {'tests'|'params'|'all'} level
95
- * @returns {string[]}
96
- */
97
- function checkMissing(jsdoc, level) {
98
- const missing = [];
99
-
100
- if (!jsdoc) {
101
- if (level === 'all') missing.push('description');
102
- if (level === 'params' || level === 'all') missing.push('@param', '@returns');
103
- return missing;
104
- }
105
-
106
- if (level === 'params' || level === 'all') {
107
- if (!jsdoc.includes('@param')) missing.push('@param');
108
- if (!jsdoc.includes('@returns') && !jsdoc.includes('@return')) missing.push('@returns');
109
- }
110
-
111
- return missing;
112
- }
113
-
114
- /** Skip list for methods */
115
- const SKIP_METHODS = [
116
- 'constructor', 'connectedCallback', 'disconnectedCallback',
117
- 'attributeChangedCallback', 'renderCallback',
118
- ];
119
-
120
- /**
121
- * Parse file using AST and find undocumented items (per-file export for cache integration)
122
- * @param {string} code
123
- * @param {string} filePath
124
- * @param {'tests'|'params'|'all'} level
125
- * @returns {UndocumentedItem[]}
126
- */
127
- export function checkUndocumentedFile(code, filePath, level) {
128
- const results = [];
129
-
130
- let ast;
131
- try {
132
- ast = parse(code, { ecmaVersion: 'latest', sourceType: 'module', locations: true });
133
- } catch (e) {
134
- return results;
135
- }
136
-
137
- const comments = extractComments(code);
138
-
139
- walk.simple(ast, {
140
- ClassDeclaration(node) {
141
- const className = node.id?.name || 'Anonymous';
142
-
143
- // Check class itself (only for 'all' level)
144
- if (level === 'all') {
145
- const classJsdoc = findJSDocBefore(comments, node.loc.start.line);
146
- if (!classJsdoc) {
147
- results.push({
148
- name: className,
149
- type: 'class',
150
- file: filePath,
151
- line: node.loc.start.line,
152
- reason: 'No JSDoc',
153
- });
154
- }
155
- }
156
-
157
- // Check methods
158
- for (const element of node.body.body) {
159
- if (element.type === 'MethodDefinition') {
160
- const methodName = element.key.name || element.key.value;
161
-
162
- // Skip: constructor, private, getters/setters, lifecycle
163
- if (element.kind === 'get' || element.kind === 'set') continue;
164
- if (methodName?.startsWith('_')) continue;
165
- if (SKIP_METHODS.includes(methodName)) continue;
166
-
167
- const jsdoc = findJSDocBefore(comments, element.loc.start.line);
168
- const missing = checkMissing(jsdoc, level);
169
-
170
- if (missing.length > 0) {
171
- results.push({
172
- name: `${className}.${methodName}`,
173
- type: 'method',
174
- file: filePath,
175
- line: element.loc.start.line,
176
- reason: missing.join(', '),
177
- });
178
- }
179
- }
180
- }
181
- },
182
-
183
- FunctionDeclaration(node) {
184
- if (!node.id) return;
185
- const funcName = node.id.name;
186
-
187
- // Skip private functions
188
- if (funcName.startsWith('_')) return;
189
-
190
- const jsdoc = findJSDocBefore(comments, node.loc.start.line);
191
- const missing = checkMissing(jsdoc, level);
192
-
193
- if (missing.length > 0) {
194
- results.push({
195
- name: funcName,
196
- type: 'function',
197
- file: filePath,
198
- line: node.loc.start.line,
199
- reason: missing.join(', '),
200
- });
201
- }
202
- },
203
- });
204
-
205
- return results;
206
- }
207
-
208
- /**
209
- * Get undocumented items from directory
210
- * @param {string} dir
211
- * @param {'tests'|'params'|'all'} level
212
- * @returns {UndocumentedItem[]}
213
- */
214
- export function getUndocumented(dir, level = 'tests') {
215
- const resolvedDir = resolve(dir);
216
- const files = findJSFiles(dir);
217
- const results = [];
218
-
219
- for (const file of files) {
220
- let content;
221
- try {
222
- content = readFileSync(file, 'utf-8');
223
- } catch (e) {
224
- continue; // File deleted between findJSFiles and read
225
- }
226
- const items = checkUndocumentedFile(content, relative(resolvedDir, file), level);
227
- results.push(...items);
228
- }
229
-
230
- return results;
231
- }
232
-
233
- /**
234
- * Get summary of undocumented items
235
- * @param {string} dir
236
- * @param {'tests'|'params'|'all'} level
237
- * @returns {Object}
238
- */
239
- export function getUndocumentedSummary(dir, level = 'tests') {
240
- const items = getUndocumented(dir, level);
241
-
242
- const byType = {
243
- class: items.filter(i => i.type === 'class').length,
244
- function: items.filter(i => i.type === 'function').length,
245
- method: items.filter(i => i.type === 'method').length,
246
- };
247
-
248
- const byReason = {};
249
- for (const item of items) {
250
- byReason[item.reason] = (byReason[item.reason] || 0) + 1;
251
- }
252
-
253
- return {
254
- total: items.length,
255
- byType,
256
- byReason,
257
- items: items.slice(0, 20),
258
- };
259
- }
package/src/workspace.js DELETED
@@ -1,70 +0,0 @@
1
- /**
2
- * Workspace Root Resolution
3
- *
4
- * Resolves relative paths against the correct workspace root.
5
- * Priority: MCP initialize roots → --workspace arg → PROJECT_ROOT env → process.cwd()
6
- */
7
-
8
- import { resolve, isAbsolute } from 'path';
9
-
10
- /** @type {string|null} */
11
- let workspaceRoot = null;
12
-
13
- // Auto-detect --workspace arg at module load
14
- const wsArg = process.argv.find(a => a.startsWith('--workspace='));
15
- if (wsArg) {
16
- workspaceRoot = wsArg.split('=')[1];
17
- console.error(`[project-graph] Workspace from arg: ${workspaceRoot}`);
18
- }
19
-
20
- /**
21
- * Set workspace root from MCP initialize roots
22
- * @param {Array<{uri: string, name?: string}>} roots
23
- */
24
- export function setRoots(roots) {
25
- if (roots && roots.length > 0) {
26
- let uri = roots[0].uri;
27
- // Strip file:// protocol if present
28
- if (uri.startsWith('file://')) {
29
- uri = uri.slice(7);
30
- }
31
- workspaceRoot = uri;
32
- console.error(`[project-graph] Workspace root: ${workspaceRoot}`);
33
- }
34
- }
35
-
36
- /**
37
- * Get current workspace root
38
- * @returns {string}
39
- */
40
- export function getWorkspaceRoot() {
41
- if (workspaceRoot) {
42
- return workspaceRoot;
43
- }
44
- if (process.env.PROJECT_ROOT) {
45
- return process.env.PROJECT_ROOT;
46
- }
47
- return process.cwd();
48
- }
49
-
50
- /**
51
- * Resolve a path argument against workspace root.
52
- * Absolute paths are returned as-is.
53
- * Relative paths are resolved against the workspace root.
54
- * @param {string} inputPath
55
- * @returns {string}
56
- */
57
- export function resolvePath(inputPath) {
58
- if (!inputPath) {
59
- return getWorkspaceRoot();
60
- }
61
- const root = getWorkspaceRoot();
62
- const resolved = isAbsolute(inputPath) ? inputPath : resolve(root, inputPath);
63
-
64
- // Prevent path traversal — resolved path must stay within workspace
65
- if (!resolved.startsWith(root)) {
66
- throw new Error(`Path traversal blocked: '${inputPath}' resolves outside workspace root '${root}'`);
67
- }
68
-
69
- return resolved;
70
- }
File without changes