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
@@ -1,299 +0,0 @@
1
- /**
2
- * Graph Builder - Creates minified project graph from parsed data
3
- */
4
-
5
- /**
6
- * @typedef {Object} GraphNode
7
- * @property {string} t - type (class/func)
8
- * @property {string} [x] - extends
9
- * @property {string[]} [m] - methods
10
- * @property {string[]} [$] - properties (init$)
11
- * @property {string[]} [i] - imports
12
- * @property {string[]} [→] - calls (outgoing)
13
- * @property {string[]} [←] - usedBy (incoming)
14
- * @property {string} [f] - source file path
15
- * @property {boolean} [e] - exported flag (functions)
16
- */
17
-
18
- /**
19
- * @typedef {Object} Graph
20
- * @property {number} v - version
21
- * @property {Object<string, string>} legend - minified name → full name
22
- * @property {Object<string, string>} reverseLegend - full name → minified
23
- * @property {Object} stats - { files, classes, functions, tables }
24
- * @property {Object<string, GraphNode>} nodes
25
- * @property {Array<[string, string, string]>} edges - [from, type, to] where type is →, R→, or W→
26
- * @property {string[]} orphans
27
- * @property {Object<string, string[]>} duplicates
28
- * @property {string[]} files - list of parsed file paths
29
- */
30
-
31
- /**
32
- * Create minified legend from names
33
- * Strategy: Use camelCase initials + suffix if collision
34
- * @param {string[]} names
35
- * @returns {Object<string, string>}
36
- */
37
- export function minifyLegend(names) {
38
- const legend = {};
39
- const used = new Set();
40
-
41
- for (const name of names) {
42
- let short = createShortName(name);
43
- let suffix = 1;
44
-
45
- while (used.has(short)) {
46
- short = createShortName(name) + suffix;
47
- suffix++;
48
- }
49
-
50
- used.add(short);
51
- legend[name] = short;
52
- }
53
-
54
- return legend;
55
- }
56
-
57
- /**
58
- * Create short name from full name
59
- * SymNode → SN, togglePin → tP, autoArrange → aA
60
- * @param {string} name
61
- * @returns {string}
62
- */
63
- function createShortName(name) {
64
- // For PascalCase: extract uppercase letters
65
- const upperOnly = name.replace(/[a-z]/g, '');
66
- if (upperOnly.length >= 2) {
67
- return upperOnly.slice(0, 3);
68
- }
69
-
70
- // For camelCase: first letter + next uppercase
71
- const firstUpper = name.match(/[A-Z]/g);
72
- if (firstUpper && firstUpper.length > 0) {
73
- return name[0].toLowerCase() + firstUpper[0];
74
- }
75
-
76
- // Fallback: first 2 letters
77
- return name.slice(0, 2);
78
- }
79
-
80
- /**
81
- * Build graph from parsed project data
82
- * @param {import('./parser.js').ParseResult} parsed
83
- * @returns {Graph}
84
- */
85
- export function buildGraph(parsed) {
86
- // Collect all names for legend
87
- const classes = parsed.classes || [];
88
- const functions = parsed.functions || [];
89
-
90
- const allNames = [
91
- ...classes.map(c => c.name),
92
- ...functions.map(f => f.name),
93
- ...classes.flatMap(c => c.methods || []),
94
- ];
95
-
96
- const legend = minifyLegend([...new Set(allNames)]);
97
- const reverseLegend = Object.fromEntries(
98
- Object.entries(legend).map(([k, v]) => [v, k])
99
- );
100
-
101
- const graph = {
102
- v: 1,
103
- legend,
104
- reverseLegend,
105
- stats: {
106
- files: (parsed.files || []).length,
107
- classes: classes.length,
108
- functions: functions.length,
109
- tables: (parsed.tables || []).length,
110
- },
111
- nodes: {},
112
- edges: [],
113
- orphans: [],
114
- duplicates: {},
115
- files: parsed.files || [],
116
- };
117
-
118
- // Build class nodes
119
- for (const cls of classes) {
120
- const shortName = legend[cls.name];
121
- graph.nodes[shortName] = {
122
- t: 'C',
123
- x: cls.extends || undefined,
124
- m: (cls.methods || []).map(m => legend[m] || m),
125
- $: (cls.properties || []).length ? cls.properties : undefined,
126
- i: cls.imports?.length ? cls.imports : undefined,
127
- f: cls.file || undefined,
128
- };
129
-
130
- // Build edges from calls
131
- for (const call of cls.calls || []) {
132
- if (call.includes('.')) {
133
- // Class.method() pattern
134
- const [target, method] = call.split('.');
135
- if (legend[target]) {
136
- const edge = [shortName, '→', `${legend[target]}.${legend[method] || method}`];
137
- graph.edges.push(edge);
138
- }
139
- } else {
140
- // Standalone function call
141
- if (legend[call]) {
142
- const edge = [shortName, '→', legend[call]];
143
- graph.edges.push(edge);
144
- }
145
- }
146
- }
147
- }
148
-
149
- // Build function nodes
150
- for (const func of functions) {
151
- const shortName = legend[func.name];
152
- graph.nodes[shortName] = {
153
- t: 'F',
154
- e: func.exported,
155
- f: func.file || undefined,
156
- };
157
-
158
- // Build DB edges from function SQL reads/writes
159
- for (const table of func.dbReads || []) {
160
- graph.edges.push([shortName, 'R→', table]);
161
- }
162
- for (const table of func.dbWrites || []) {
163
- graph.edges.push([shortName, 'W→', table]);
164
- }
165
- }
166
-
167
- // Build DB edges from class SQL reads/writes
168
- for (const cls of classes) {
169
- const shortName = legend[cls.name];
170
- for (const table of cls.dbReads || []) {
171
- graph.edges.push([shortName, 'R→', table]);
172
- }
173
- for (const table of cls.dbWrites || []) {
174
- graph.edges.push([shortName, 'W→', table]);
175
- }
176
- }
177
-
178
- // Build table nodes from parsed SQL files
179
- for (const table of parsed.tables || []) {
180
- graph.nodes[table.name] = {
181
- t: 'T',
182
- cols: table.columns.map(c => c.name),
183
- f: table.file || undefined,
184
- };
185
- }
186
-
187
- // Detect orphans (nodes with no incoming edges)
188
- const hasIncoming = new Set();
189
- for (const edge of graph.edges) {
190
- const target = edge[2].split('.')[0];
191
- hasIncoming.add(target);
192
- }
193
-
194
- for (const name of Object.keys(graph.nodes)) {
195
- if (!hasIncoming.has(name) && graph.nodes[name].t === 'F' && !graph.nodes[name].e) {
196
- graph.orphans.push(reverseLegend[name]);
197
- }
198
- }
199
-
200
- // Detect duplicates (same method name in multiple classes)
201
- const methodLocations = Object.create(null);
202
- for (const cls of classes) {
203
- for (const method of cls.methods || []) {
204
- if (!methodLocations[method]) {
205
- methodLocations[method] = [];
206
- }
207
- methodLocations[method].push(`${cls.name}:${cls.line}`);
208
- }
209
- }
210
-
211
- for (const [method, locations] of Object.entries(methodLocations)) {
212
- if (locations.length > 1) {
213
- graph.duplicates[method] = locations;
214
- }
215
- }
216
-
217
- return graph;
218
- }
219
-
220
- /**
221
- * Create compact skeleton (minimal tokens)
222
- * @param {Graph} graph
223
- * @returns {Object}
224
- */
225
- export function createSkeleton(graph) {
226
- const legend = {};
227
- const nodes = {};
228
-
229
- // Build class nodes with file path
230
- // graph.legend = {fullName → shortName}
231
- for (const [full, short] of Object.entries(graph.legend)) {
232
- const node = graph.nodes[short];
233
- if (!node) continue;
234
-
235
- if (node.t === 'C') {
236
- // Skip empty classes (0 methods, 0 props)
237
- const methodCount = node.m?.length || 0;
238
- const propCount = node.$?.length || 0;
239
- if (methodCount === 0 && propCount === 0) continue;
240
-
241
- legend[short] = full;
242
- const entry = { m: methodCount };
243
- if (propCount > 0) entry.$ = propCount;
244
- if (node.f) entry.f = node.f;
245
- nodes[short] = entry;
246
- }
247
- // Skip Table nodes (T) — they only appear in dedicated DB tools
248
- }
249
-
250
- // Build exported functions grouped by file: { "file.js": ["shortName1", ...] }
251
- // Also add function names to legend
252
- const exportsByFile = {};
253
- for (const [full, short] of Object.entries(graph.legend)) {
254
- const node = graph.nodes[short];
255
- if (node?.t === 'F' && node.e) {
256
- legend[short] = full;
257
- const file = node.f || '?';
258
- if (!exportsByFile[file]) exportsByFile[file] = [];
259
- exportsByFile[file].push(short);
260
- }
261
- }
262
-
263
- // Build file tree grouped by directory (only files not covered by n/X)
264
- const coveredFiles = new Set();
265
- for (const v of Object.values(nodes)) {
266
- if (v.f) coveredFiles.add(v.f);
267
- }
268
- for (const file of Object.keys(exportsByFile)) {
269
- coveredFiles.add(file);
270
- }
271
-
272
- const fileTree = {};
273
- for (const filePath of graph.files || []) {
274
- if (coveredFiles.has(filePath)) continue;
275
- const lastSlash = filePath.lastIndexOf('/');
276
- const dir = lastSlash >= 0 ? filePath.slice(0, lastSlash + 1) : './';
277
- const file = lastSlash >= 0 ? filePath.slice(lastSlash + 1) : filePath;
278
- if (!fileTree[dir]) fileTree[dir] = [];
279
- fileTree[dir].push(file);
280
- }
281
-
282
- const result = {
283
- v: graph.v,
284
- L: legend,
285
- s: graph.stats,
286
- n: nodes,
287
- X: exportsByFile,
288
- e: graph.edges.length,
289
- o: graph.orphans.length,
290
- d: Object.keys(graph.duplicates).length,
291
- };
292
-
293
- // Only add uncovered files if there are any
294
- if (Object.keys(fileTree).length > 0) {
295
- result.f = fileTree;
296
- }
297
-
298
- return result;
299
- }
@@ -1,73 +0,0 @@
1
- /**
2
- * Project Guidelines and Instructions for AI Agents
3
- */
4
-
5
- export const AGENT_INSTRUCTIONS = `
6
- # 🤖 Project Guidelines for AI Agents
7
-
8
- ## 1. Architecture Standards (Symbiote.js)
9
- - **Component Structure**: Always use Triple-File Partitioning for components:
10
- - \`MyComponent.js\`: Class logic (extends Symbiote)
11
- - \`MyComponent.tpl.js\`: HTML template (export template)
12
- - \`MyComponent.css.js\`: CSS styles (export rootStyles/shadowStyles)
13
- - **State Management**: Use \`this.init$\` for local state and \`this.sub()\` for reactivity.
14
- - **Directives**: Use \`itemize\` for lists, \`js-d-kit\` for static generation.
15
-
16
- ## 2. General Coding Rules
17
- - **ESM Only**: Use \`import\` / \`export\`. No \`require\`.
18
- - **No Dependencies**: Avoid adding new npm packages unless critical.
19
- - **Comments**: Write clear JSDoc for all public methods.
20
- - **Async/Await**: Prefer async/await over promises.
21
-
22
- ## 3. MCP Tools Usage
23
- - **Graph**: Use \`get_skeleton\` first to map the codebase.
24
- - **Deep Dive**: Use \`expand\` to read class details.
25
- - **Tests**: Use \`get_pending_tests\` to see what needs verification.
26
- - **Guidelines**: Use \`get_agent_instructions\` to refresh these rules.
27
-
28
- ## 4. Custom Rules System
29
- Configurable code analysis with auto-detection.
30
-
31
- ### Available Tools
32
- - \`get_custom_rules\`: List all rulesets and their rules
33
- - \`set_custom_rule\`: Add or update a rule in a ruleset
34
- - \`check_custom_rules\`: Run analysis (auto-detects applicable rulesets)
35
-
36
- ### Auto-Detection
37
- Rulesets are applied automatically based on:
38
- 1. \`package.json\` dependencies
39
- 2. Import patterns in source code
40
- 3. Code patterns (e.g., \`extends Symbiote\`)
41
-
42
- ### Creating New Rules
43
- Use \`set_custom_rule\` to add framework-specific rules:
44
- \`\`\`json
45
- {
46
- "ruleSet": "my-framework-2x",
47
- "rule": {
48
- "id": "my-rule-id",
49
- "name": "Rule Name",
50
- "description": "What this rule checks",
51
- "pattern": "badPattern",
52
- "patternType": "string",
53
- "replacement": "Use goodPattern instead",
54
- "severity": "warning",
55
- "filePattern": "*.js",
56
- "docs": "https://docs.example.com/rule"
57
- }
58
- }
59
- \`\`\`
60
-
61
- ### Severity Levels
62
- - \`error\`: Critical issues that must be fixed
63
- - \`warning\`: Important but not blocking
64
- - \`info\`: Suggestions and best practices
65
- `;
66
-
67
- /**
68
- * Get agent instructions
69
- * @returns {string}
70
- */
71
- export function getInstructions() {
72
- return AGENT_INSTRUCTIONS;
73
- }