project-graph-mcp 1.5.0 → 2.1.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 (125) hide show
  1. package/README.md +171 -31
  2. package/docs/img/explorer-compact.jpg +0 -0
  3. package/docs/img/explorer-expanded.jpg +0 -0
  4. package/package.json +12 -8
  5. package/src/.project-graph-cache.json +1 -1
  6. package/src/analysis/analysis-cache.js +7 -0
  7. package/src/analysis/complexity.js +14 -0
  8. package/src/analysis/custom-rules.js +36 -0
  9. package/src/analysis/db-analysis.js +9 -0
  10. package/src/analysis/dead-code.js +19 -0
  11. package/src/analysis/full-analysis.js +18 -0
  12. package/src/analysis/jsdoc-checker.js +24 -0
  13. package/src/analysis/jsdoc-generator.js +10 -0
  14. package/src/analysis/large-files.js +11 -0
  15. package/src/analysis/outdated-patterns.js +12 -0
  16. package/src/analysis/similar-functions.js +16 -0
  17. package/src/analysis/test-annotations.js +21 -0
  18. package/src/analysis/type-checker.js +8 -0
  19. package/src/analysis/undocumented.js +14 -0
  20. package/src/cli/cli-handlers.js +4 -0
  21. package/src/cli/cli.js +5 -0
  22. package/src/compact/.project-graph-cache.json +1 -0
  23. package/src/compact/ai-context.js +7 -0
  24. package/src/compact/compact-migrate.js +17 -0
  25. package/src/compact/compact.js +18 -0
  26. package/src/compact/compress.js +14 -0
  27. package/src/compact/ctx-to-jsdoc.js +29 -0
  28. package/src/compact/doc-dialect.js +30 -0
  29. package/src/compact/expand.js +37 -0
  30. package/src/compact/framework-references.js +5 -0
  31. package/src/compact/instructions.js +3 -0
  32. package/src/compact/mode-config.js +8 -0
  33. package/src/compact/validate-pipeline.js +9 -0
  34. package/src/core/event-bus.js +9 -0
  35. package/src/core/filters.js +14 -0
  36. package/src/core/graph-builder.js +12 -0
  37. package/src/core/parser.js +31 -0
  38. package/src/core/workspace.js +8 -0
  39. package/src/lang/lang-go.js +17 -0
  40. package/src/lang/lang-python.js +12 -0
  41. package/src/lang/lang-sql.js +23 -0
  42. package/src/lang/lang-typescript.js +9 -0
  43. package/src/lang/lang-utils.js +4 -0
  44. package/src/mcp/mcp-server.js +17 -0
  45. package/src/mcp/tool-defs.js +3 -0
  46. package/src/mcp/tools.js +25 -0
  47. package/src/network/backend-lifecycle.js +19 -0
  48. package/src/network/backend.js +5 -0
  49. package/src/network/local-gateway.js +23 -0
  50. package/src/network/mdns.js +13 -0
  51. package/src/network/server.js +10 -0
  52. package/src/network/web-server.js +34 -0
  53. package/web/.project-graph-cache.json +1 -0
  54. package/web/app.js +17 -0
  55. package/web/components/code-block.js +3 -0
  56. package/web/components/quick-open.js +5 -0
  57. package/web/dashboard-state.js +3 -0
  58. package/web/dashboard.html +27 -0
  59. package/web/dashboard.js +8 -0
  60. package/web/highlight.js +13 -0
  61. package/web/index.html +35 -0
  62. package/web/panels/ActionBoard/ActionBoard.css.js +1 -0
  63. package/web/panels/ActionBoard/ActionBoard.js +4 -0
  64. package/web/panels/ActionBoard/ActionBoard.tpl.js +1 -0
  65. package/web/panels/EventItem/EventItem.css.js +1 -0
  66. package/web/panels/EventItem/EventItem.js +4 -0
  67. package/web/panels/EventItem/EventItem.tpl.js +1 -0
  68. package/web/panels/ProjectItem/ProjectItem.css.js +1 -0
  69. package/web/panels/ProjectItem/ProjectItem.js +5 -0
  70. package/web/panels/ProjectItem/ProjectItem.tpl.js +1 -0
  71. package/web/panels/ProjectList/ProjectList.css.js +1 -0
  72. package/web/panels/ProjectList/ProjectList.js +4 -0
  73. package/web/panels/ProjectList/ProjectList.tpl.js +1 -0
  74. package/web/panels/SettingsPanel/.project-graph-cache.json +1 -0
  75. package/web/panels/SettingsPanel/SettingsPanel.css.js +1 -0
  76. package/web/panels/SettingsPanel/SettingsPanel.js +7 -0
  77. package/web/panels/SettingsPanel/SettingsPanel.tpl.js +1 -0
  78. package/web/panels/code-viewer.js +5 -0
  79. package/web/panels/ctx-panel.js +4 -0
  80. package/web/panels/dep-graph.js +6 -0
  81. package/web/panels/file-tree.js +188 -0
  82. package/web/panels/health-panel.js +3 -0
  83. package/web/panels/live-monitor.js +3 -0
  84. package/web/state.js +17 -0
  85. package/web/style.css +157 -0
  86. package/references/symbiote-3x.md +0 -834
  87. package/src/ai-context.js +0 -113
  88. package/src/analysis-cache.js +0 -155
  89. package/src/cli-handlers.js +0 -271
  90. package/src/cli.js +0 -95
  91. package/src/compact.js +0 -207
  92. package/src/complexity.js +0 -237
  93. package/src/compress.js +0 -319
  94. package/src/ctx-to-jsdoc.js +0 -514
  95. package/src/custom-rules.js +0 -584
  96. package/src/db-analysis.js +0 -194
  97. package/src/dead-code.js +0 -468
  98. package/src/doc-dialect.js +0 -716
  99. package/src/filters.js +0 -227
  100. package/src/framework-references.js +0 -177
  101. package/src/full-analysis.js +0 -470
  102. package/src/graph-builder.js +0 -299
  103. package/src/instructions.js +0 -73
  104. package/src/jsdoc-checker.js +0 -351
  105. package/src/jsdoc-generator.js +0 -203
  106. package/src/lang-go.js +0 -285
  107. package/src/lang-python.js +0 -197
  108. package/src/lang-sql.js +0 -309
  109. package/src/lang-typescript.js +0 -190
  110. package/src/lang-utils.js +0 -124
  111. package/src/large-files.js +0 -163
  112. package/src/mcp-server.js +0 -675
  113. package/src/mode-config.js +0 -127
  114. package/src/outdated-patterns.js +0 -296
  115. package/src/parser.js +0 -662
  116. package/src/server.js +0 -28
  117. package/src/similar-functions.js +0 -279
  118. package/src/test-annotations.js +0 -323
  119. package/src/tool-defs.js +0 -793
  120. package/src/tools.js +0 -470
  121. package/src/type-checker.js +0 -188
  122. package/src/undocumented.js +0 -259
  123. package/src/workspace.js +0 -70
  124. /package/{AGENT_ROLE.md → docs/examples/AGENT_ROLE.md} +0 -0
  125. /package/{AGENT_ROLE_MINIMAL.md → docs/examples/AGENT_ROLE_MINIMAL.md} +0 -0
package/src/filters.js DELETED
@@ -1,227 +0,0 @@
1
- /**
2
- * Filter Configuration for Project Graph
3
- * Manages excludes, includes, and gitignore parsing
4
- */
5
-
6
- import { readFileSync, existsSync } from 'fs';
7
- import { join, relative } from 'path';
8
-
9
- /**
10
- * Default directories to exclude
11
- */
12
- const DEFAULT_EXCLUDES = [
13
- 'node_modules',
14
- 'dist',
15
- 'build',
16
- 'coverage',
17
- '.next',
18
- '.nuxt',
19
- '.output',
20
- '__pycache__',
21
- '.cache',
22
- '.turbo',
23
- 'out',
24
- ];
25
-
26
- /**
27
- * Default file patterns to exclude
28
- */
29
- const DEFAULT_EXCLUDE_PATTERNS = [
30
- '*.test.js',
31
- '*.spec.js',
32
- '*.min.js',
33
- '*.bundle.js',
34
- '*.d.ts',
35
- '.project-graph-cache.json',
36
- ];
37
-
38
- // Current filter configuration (mutable via MCP)
39
- let config = {
40
- excludeDirs: [...DEFAULT_EXCLUDES],
41
- excludePatterns: [...DEFAULT_EXCLUDE_PATTERNS],
42
- includeHidden: false,
43
- useGitignore: true,
44
- gitignorePatterns: [],
45
- };
46
-
47
- /**
48
- * Get current filter configuration
49
- * @returns {Object}
50
- */
51
- export function getFilters() {
52
- return { ...config };
53
- }
54
-
55
- /**
56
- * Update filter configuration
57
- * @param {Object} updates
58
- * @returns {Object}
59
- */
60
- export function setFilters(updates) {
61
- if (updates.excludeDirs !== undefined) {
62
- config.excludeDirs = updates.excludeDirs;
63
- }
64
- if (updates.excludePatterns !== undefined) {
65
- config.excludePatterns = updates.excludePatterns;
66
- }
67
- if (updates.includeHidden !== undefined) {
68
- config.includeHidden = updates.includeHidden;
69
- }
70
- if (updates.useGitignore !== undefined) {
71
- config.useGitignore = updates.useGitignore;
72
- }
73
- return getFilters();
74
- }
75
-
76
- /**
77
- * Add directories to exclude list
78
- * @param {string[]} dirs
79
- * @returns {Object}
80
- */
81
- export function addExcludes(dirs) {
82
- config.excludeDirs = [...new Set([...config.excludeDirs, ...dirs])];
83
- return getFilters();
84
- }
85
-
86
- /**
87
- * Remove directories from exclude list
88
- * @param {string[]} dirs
89
- * @returns {Object}
90
- */
91
- export function removeExcludes(dirs) {
92
- config.excludeDirs = config.excludeDirs.filter(d => !dirs.includes(d));
93
- return getFilters();
94
- }
95
-
96
- /**
97
- * Reset filters to defaults
98
- * @returns {Object}
99
- */
100
- export function resetFilters() {
101
- config = {
102
- excludeDirs: [...DEFAULT_EXCLUDES],
103
- excludePatterns: [...DEFAULT_EXCLUDE_PATTERNS],
104
- includeHidden: false,
105
- useGitignore: true,
106
- gitignorePatterns: [],
107
- };
108
- return getFilters();
109
- }
110
-
111
- /**
112
- * Parse .gitignore file
113
- * @param {string} rootDir
114
- * @returns {string[]}
115
- */
116
- export function parseGitignore(rootDir) {
117
- const gitignorePath = join(rootDir, '.gitignore');
118
-
119
- if (!existsSync(gitignorePath)) {
120
- return [];
121
- }
122
-
123
- try {
124
- const content = readFileSync(gitignorePath, 'utf-8');
125
- const patterns = content
126
- .split('\n')
127
- .map(line => line.trim())
128
- .filter(line => line && !line.startsWith('#'))
129
- .map(line => line.replace(/\/$/, '')); // Remove trailing slashes
130
-
131
- config.gitignorePatterns = patterns;
132
- return patterns;
133
- } catch (e) {
134
- return [];
135
- }
136
- }
137
-
138
- /**
139
- * Check if a directory should be excluded
140
- * @param {string} dirName - Directory name (not path)
141
- * @param {string} relativePath - Relative path from root
142
- * @returns {boolean}
143
- */
144
- export function shouldExcludeDir(dirName, relativePath = '') {
145
- // Check hidden directories
146
- if (!config.includeHidden && dirName.startsWith('.')) {
147
- return true;
148
- }
149
-
150
- // Check default excludes
151
- if (config.excludeDirs.includes(dirName)) {
152
- return true;
153
- }
154
-
155
- // Check gitignore patterns
156
- if (config.useGitignore) {
157
- for (const pattern of config.gitignorePatterns) {
158
- if (matchGitignorePattern(pattern, dirName, relativePath)) {
159
- return true;
160
- }
161
- }
162
- }
163
-
164
- return false;
165
- }
166
-
167
- /**
168
- * Check if a file should be excluded
169
- * @param {string} fileName
170
- * @param {string} relativePath
171
- * @returns {boolean}
172
- */
173
- export function shouldExcludeFile(fileName, relativePath = '') {
174
- // Check exclude patterns
175
- for (const pattern of config.excludePatterns) {
176
- if (matchWildcard(pattern, fileName)) {
177
- return true;
178
- }
179
- }
180
-
181
- // Check gitignore patterns
182
- if (config.useGitignore) {
183
- for (const pattern of config.gitignorePatterns) {
184
- if (matchGitignorePattern(pattern, fileName, relativePath)) {
185
- return true;
186
- }
187
- }
188
- }
189
-
190
- return false;
191
- }
192
-
193
- /**
194
- * Match simple wildcard pattern (*.js, *.test.js)
195
- * @param {string} pattern
196
- * @param {string} str
197
- * @returns {boolean}
198
- */
199
- function matchWildcard(pattern, str) {
200
- const regex = pattern
201
- .replace(/\./g, '\\.')
202
- .replace(/\*/g, '.*');
203
- return new RegExp(`^${regex}$`).test(str);
204
- }
205
-
206
- /**
207
- * Match gitignore pattern
208
- * @param {string} pattern
209
- * @param {string} name
210
- * @param {string} relativePath
211
- * @returns {boolean}
212
- */
213
- function matchGitignorePattern(pattern, name, relativePath) {
214
- // Simple matching: exact name or wildcard
215
- if (pattern === name) return true;
216
-
217
- // Pattern with wildcard
218
- if (pattern.includes('*')) {
219
- return matchWildcard(pattern, name);
220
- }
221
-
222
- // Pattern in path
223
- const fullPath = relativePath ? `${relativePath}/${name}` : name;
224
- if (fullPath.includes(pattern)) return true;
225
-
226
- return false;
227
- }
@@ -1,177 +0,0 @@
1
- /**
2
- * Framework Reference System
3
- * Loads framework-specific AI references from GitHub (with caching) or local files
4
- */
5
-
6
- import { readFileSync, readdirSync, existsSync, writeFileSync } from 'fs';
7
- import { join, basename, dirname } from 'path';
8
- import { fileURLToPath } from 'url';
9
- import { detectProjectRuleSets } from './custom-rules.js';
10
-
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
- const REFERENCES_DIR = join(__dirname, '..', 'references');
13
-
14
- /**
15
- * Remote sources for framework references
16
- * Maps reference name to raw GitHub URL
17
- */
18
- const REMOTE_SOURCES = {
19
- 'symbiote-3x': 'https://raw.githubusercontent.com/symbiotejs/symbiote.js/main/AI_REFERENCE.md',
20
- };
21
-
22
- /** @type {Map<string, {content: string, fetchedAt: number}>} */
23
- const cache = new Map();
24
-
25
- /** Cache TTL: 1 hour */
26
- const CACHE_TTL = 60 * 60 * 1000;
27
-
28
- /**
29
- * Fetch reference from GitHub with caching
30
- * Falls back to local file if fetch fails
31
- * @param {string} name - Reference name
32
- * @returns {Promise<{content: string, source: string}>}
33
- */
34
- async function fetchReference(name) {
35
- const url = REMOTE_SOURCES[name];
36
- const localPath = join(REFERENCES_DIR, `${name}.md`);
37
-
38
- // Check in-memory cache
39
- const cached = cache.get(name);
40
- if (cached && Date.now() - cached.fetchedAt < CACHE_TTL) {
41
- return { content: cached.content, source: 'cache' };
42
- }
43
-
44
- // Try fetching from GitHub
45
- if (url) {
46
- try {
47
- const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
48
- if (response.ok) {
49
- const content = await response.text();
50
- cache.set(name, { content, fetchedAt: Date.now() });
51
-
52
- // Update local file as backup
53
- try {
54
- writeFileSync(localPath, content, 'utf-8');
55
- } catch (e) {
56
- // Write failure is non-critical
57
- }
58
-
59
- return { content, source: `github (${url})` };
60
- }
61
- } catch (e) {
62
- // Fetch failed — fall back to local
63
- }
64
- }
65
-
66
- // Fall back to local file
67
- if (existsSync(localPath)) {
68
- const content = readFileSync(localPath, 'utf-8');
69
- cache.set(name, { content, fetchedAt: Date.now() });
70
- return { content, source: 'local' };
71
- }
72
-
73
- return { content: '', source: 'not_found' };
74
- }
75
-
76
- /**
77
- * Map ruleset names to reference names
78
- */
79
- const RULESET_TO_REFERENCE = {
80
- 'symbiote-3x': 'symbiote-3x',
81
- 'symbiote-2x': 'symbiote-3x',
82
- };
83
-
84
- /**
85
- * List available framework references (local + remote)
86
- * @returns {string[]}
87
- */
88
- function listAvailable() {
89
- const names = new Set(Object.keys(REMOTE_SOURCES));
90
-
91
- if (existsSync(REFERENCES_DIR)) {
92
- for (const f of readdirSync(REFERENCES_DIR)) {
93
- if (f.endsWith('.md')) {
94
- names.add(basename(f, '.md'));
95
- }
96
- }
97
- }
98
-
99
- return [...names];
100
- }
101
-
102
- /**
103
- * Get framework reference content
104
- * @param {Object} options
105
- * @param {string} [options.framework] - Explicit framework name
106
- * @param {string} [options.path] - Project path for auto-detection
107
- * @returns {Promise<Object>}
108
- */
109
- export async function getFrameworkReference(options = {}) {
110
- const available = listAvailable();
111
-
112
- // Explicit framework requested
113
- if (options.framework) {
114
- if (!available.includes(options.framework)) {
115
- return {
116
- error: `Framework reference '${options.framework}' not found`,
117
- available,
118
- };
119
- }
120
-
121
- const { content, source } = await fetchReference(options.framework);
122
- if (!content) {
123
- return { error: `Failed to load reference '${options.framework}'`, available };
124
- }
125
-
126
- return {
127
- framework: options.framework,
128
- source,
129
- lines: content.split('\n').length,
130
- content,
131
- };
132
- }
133
-
134
- // Auto-detect from project path
135
- if (options.path) {
136
- const { detected, reasons } = detectProjectRuleSets(options.path);
137
-
138
- const matchedRefs = [];
139
- for (const ruleset of detected) {
140
- const refName = RULESET_TO_REFERENCE[ruleset];
141
- if (refName && available.includes(refName) && !matchedRefs.includes(refName)) {
142
- matchedRefs.push(refName);
143
- }
144
- }
145
-
146
- if (matchedRefs.length === 0) {
147
- return {
148
- error: 'No framework references found for this project',
149
- detected,
150
- reasons,
151
- available,
152
- };
153
- }
154
-
155
- const results = await Promise.all(matchedRefs.map(fetchReference));
156
- const contents = results.map(r => r.content).filter(Boolean);
157
- const sources = results.map(r => r.source);
158
-
159
- return {
160
- frameworks: matchedRefs,
161
- sources,
162
- detected: { rulesets: detected, reasons },
163
- lines: contents.reduce((sum, c) => sum + c.split('\n').length, 0),
164
- content: contents.join('\n\n---\n\n'),
165
- };
166
- }
167
-
168
- // No framework specified — list available
169
- return {
170
- error: 'Specify framework name or path for auto-detection',
171
- available: available.map(name => ({
172
- name,
173
- remote: !!REMOTE_SOURCES[name],
174
- url: REMOTE_SOURCES[name] ?? null,
175
- })),
176
- };
177
- }