@optave/codegraph 3.1.0 → 3.1.1
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 +5 -5
- package/grammars/tree-sitter-go.wasm +0 -0
- package/package.json +8 -9
- package/src/ast-analysis/rules/csharp.js +201 -0
- package/src/ast-analysis/rules/go.js +182 -0
- package/src/ast-analysis/rules/index.js +82 -0
- package/src/ast-analysis/rules/java.js +175 -0
- package/src/ast-analysis/rules/javascript.js +246 -0
- package/src/ast-analysis/rules/php.js +219 -0
- package/src/ast-analysis/rules/python.js +196 -0
- package/src/ast-analysis/rules/ruby.js +204 -0
- package/src/ast-analysis/rules/rust.js +173 -0
- package/src/ast-analysis/shared.js +223 -0
- package/src/ast.js +15 -28
- package/src/audit.js +4 -5
- package/src/boundaries.js +1 -1
- package/src/branch-compare.js +84 -79
- package/src/builder.js +0 -5
- package/src/cfg.js +106 -338
- package/src/check.js +3 -3
- package/src/cli.js +99 -179
- package/src/cochange.js +1 -1
- package/src/communities.js +13 -16
- package/src/complexity.js +196 -1239
- package/src/cycles.js +1 -1
- package/src/dataflow.js +269 -694
- package/src/db/connection.js +88 -0
- package/src/db/migrations.js +312 -0
- package/src/db/query-builder.js +280 -0
- package/src/db/repository.js +134 -0
- package/src/db.js +19 -399
- package/src/embedder.js +145 -141
- package/src/export.js +1 -1
- package/src/flow.js +161 -162
- package/src/index.js +34 -1
- package/src/kinds.js +49 -0
- package/src/manifesto.js +3 -8
- package/src/mcp.js +37 -20
- package/src/owners.js +132 -132
- package/src/queries-cli.js +866 -0
- package/src/queries.js +1323 -2267
- package/src/result-formatter.js +21 -0
- package/src/sequence.js +177 -182
- package/src/structure.js +200 -199
- package/src/test-filter.js +7 -0
- package/src/triage.js +120 -162
- package/src/viewer.js +1 -1
package/src/flow.js
CHANGED
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { openReadonlyOrFail } from './db.js';
|
|
9
|
-
import { paginateResult
|
|
10
|
-
import {
|
|
9
|
+
import { paginateResult } from './paginate.js';
|
|
10
|
+
import { CORE_SYMBOL_KINDS, findMatchingNodes, kindIcon } from './queries.js';
|
|
11
|
+
import { outputResult } from './result-formatter.js';
|
|
11
12
|
import { FRAMEWORK_ENTRY_PREFIXES } from './structure.js';
|
|
13
|
+
import { isTestFile } from './test-filter.js';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Determine the entry point type from a node name based on framework prefixes.
|
|
@@ -35,46 +37,49 @@ export function entryPointType(name) {
|
|
|
35
37
|
*/
|
|
36
38
|
export function listEntryPointsData(dbPath, opts = {}) {
|
|
37
39
|
const db = openReadonlyOrFail(dbPath);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
40
|
+
try {
|
|
41
|
+
const noTests = opts.noTests || false;
|
|
42
|
+
|
|
43
|
+
// Find all framework-prefixed nodes
|
|
44
|
+
const prefixConditions = FRAMEWORK_ENTRY_PREFIXES.map(() => 'n.name LIKE ?').join(' OR ');
|
|
45
|
+
const prefixParams = FRAMEWORK_ENTRY_PREFIXES.map((p) => `${p}%`);
|
|
46
|
+
|
|
47
|
+
let rows = db
|
|
48
|
+
.prepare(
|
|
49
|
+
`SELECT n.name, n.kind, n.file, n.line, n.role
|
|
50
|
+
FROM nodes n
|
|
51
|
+
WHERE (
|
|
52
|
+
(${prefixConditions})
|
|
53
|
+
OR n.role = 'entry'
|
|
54
|
+
)
|
|
55
|
+
AND n.kind NOT IN ('file', 'directory')
|
|
56
|
+
ORDER BY n.name`,
|
|
57
|
+
)
|
|
58
|
+
.all(...prefixParams);
|
|
59
|
+
|
|
60
|
+
if (noTests) rows = rows.filter((r) => !isTestFile(r.file));
|
|
61
|
+
|
|
62
|
+
const entries = rows.map((r) => ({
|
|
63
|
+
name: r.name,
|
|
64
|
+
kind: r.kind,
|
|
65
|
+
file: r.file,
|
|
66
|
+
line: r.line,
|
|
67
|
+
role: r.role,
|
|
68
|
+
type: entryPointType(r.name) || (r.role === 'entry' ? 'exported' : null),
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
const byType = {};
|
|
72
|
+
for (const e of entries) {
|
|
73
|
+
const t = e.type || 'other';
|
|
74
|
+
if (!byType[t]) byType[t] = [];
|
|
75
|
+
byType[t].push(e);
|
|
76
|
+
}
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
const base = { entries, byType, count: entries.length };
|
|
79
|
+
return paginateResult(base, 'entries', { limit: opts.limit, offset: opts.offset });
|
|
80
|
+
} finally {
|
|
81
|
+
db.close();
|
|
82
|
+
}
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
@@ -91,132 +96,136 @@ export function listEntryPointsData(dbPath, opts = {}) {
|
|
|
91
96
|
*/
|
|
92
97
|
export function flowData(name, dbPath, opts = {}) {
|
|
93
98
|
const db = openReadonlyOrFail(dbPath);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
try {
|
|
100
|
+
const maxDepth = opts.depth || 10;
|
|
101
|
+
const noTests = opts.noTests || false;
|
|
102
|
+
const flowOpts = { ...opts, kinds: opts.kind ? [opts.kind] : CORE_SYMBOL_KINDS };
|
|
103
|
+
|
|
104
|
+
// Phase 1: Direct LIKE match on full name (use all 10 core symbol kinds,
|
|
105
|
+
// not just FUNCTION_KINDS, so flow can trace from interfaces/types/structs/etc.)
|
|
106
|
+
let matchNode = findMatchingNodes(db, name, flowOpts)[0] ?? null;
|
|
107
|
+
|
|
108
|
+
// Phase 2: Prefix-stripped matching — try adding framework prefixes
|
|
109
|
+
if (!matchNode) {
|
|
110
|
+
for (const prefix of FRAMEWORK_ENTRY_PREFIXES) {
|
|
111
|
+
matchNode = findMatchingNodes(db, `${prefix}${name}`, flowOpts)[0] ?? null;
|
|
112
|
+
if (matchNode) break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
99
115
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
if (!matchNode) {
|
|
117
|
+
return {
|
|
118
|
+
entry: null,
|
|
119
|
+
depth: maxDepth,
|
|
120
|
+
steps: [],
|
|
121
|
+
leaves: [],
|
|
122
|
+
cycles: [],
|
|
123
|
+
totalReached: 0,
|
|
124
|
+
truncated: false,
|
|
125
|
+
};
|
|
105
126
|
}
|
|
106
|
-
}
|
|
107
127
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
totalReached: 0,
|
|
117
|
-
truncated: false,
|
|
128
|
+
const epType = entryPointType(matchNode.name);
|
|
129
|
+
const entry = {
|
|
130
|
+
name: matchNode.name,
|
|
131
|
+
kind: matchNode.kind,
|
|
132
|
+
file: matchNode.file,
|
|
133
|
+
line: matchNode.line,
|
|
134
|
+
type: epType || 'exported',
|
|
135
|
+
role: matchNode.role,
|
|
118
136
|
};
|
|
119
|
-
}
|
|
120
137
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
for (const c of callees) {
|
|
157
|
-
if (noTests && isTestFile(c.file)) continue;
|
|
158
|
-
|
|
159
|
-
if (visited.has(c.id)) {
|
|
160
|
-
// Cycle detected
|
|
161
|
-
const fromNode = idToNode.get(fid);
|
|
162
|
-
if (fromNode) {
|
|
163
|
-
cycles.push({ from: fromNode.name, to: c.name, depth: d });
|
|
138
|
+
// Forward BFS through callees
|
|
139
|
+
const visited = new Set([matchNode.id]);
|
|
140
|
+
let frontier = [matchNode.id];
|
|
141
|
+
const steps = [];
|
|
142
|
+
const cycles = [];
|
|
143
|
+
let truncated = false;
|
|
144
|
+
|
|
145
|
+
// Track which nodes are at each depth and their depth for leaf detection
|
|
146
|
+
const nodeDepths = new Map();
|
|
147
|
+
const idToNode = new Map();
|
|
148
|
+
idToNode.set(matchNode.id, entry);
|
|
149
|
+
|
|
150
|
+
for (let d = 1; d <= maxDepth; d++) {
|
|
151
|
+
const nextFrontier = [];
|
|
152
|
+
const levelNodes = [];
|
|
153
|
+
|
|
154
|
+
for (const fid of frontier) {
|
|
155
|
+
const callees = db
|
|
156
|
+
.prepare(
|
|
157
|
+
`SELECT DISTINCT n.id, n.name, n.kind, n.file, n.line, n.role
|
|
158
|
+
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
159
|
+
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
160
|
+
)
|
|
161
|
+
.all(fid);
|
|
162
|
+
|
|
163
|
+
for (const c of callees) {
|
|
164
|
+
if (noTests && isTestFile(c.file)) continue;
|
|
165
|
+
|
|
166
|
+
if (visited.has(c.id)) {
|
|
167
|
+
// Cycle detected
|
|
168
|
+
const fromNode = idToNode.get(fid);
|
|
169
|
+
if (fromNode) {
|
|
170
|
+
cycles.push({ from: fromNode.name, to: c.name, depth: d });
|
|
171
|
+
}
|
|
172
|
+
continue;
|
|
164
173
|
}
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
visited.add(c.id);
|
|
176
|
+
nextFrontier.push(c.id);
|
|
177
|
+
const nodeInfo = { name: c.name, kind: c.kind, file: c.file, line: c.line };
|
|
178
|
+
levelNodes.push(nodeInfo);
|
|
179
|
+
nodeDepths.set(c.id, d);
|
|
180
|
+
idToNode.set(c.id, nodeInfo);
|
|
181
|
+
}
|
|
174
182
|
}
|
|
175
|
-
}
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
if (levelNodes.length > 0) {
|
|
185
|
+
steps.push({ depth: d, nodes: levelNodes });
|
|
186
|
+
}
|
|
180
187
|
|
|
181
|
-
|
|
182
|
-
|
|
188
|
+
frontier = nextFrontier;
|
|
189
|
+
if (frontier.length === 0) break;
|
|
183
190
|
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
if (d === maxDepth && frontier.length > 0) {
|
|
192
|
+
truncated = true;
|
|
193
|
+
}
|
|
186
194
|
}
|
|
187
|
-
}
|
|
188
195
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
// Identify leaves: visited nodes that have no outgoing 'calls' edges to other visited nodes
|
|
197
|
+
// (or no outgoing calls at all)
|
|
198
|
+
const leaves = [];
|
|
199
|
+
for (const [id, depth] of nodeDepths) {
|
|
200
|
+
const outgoing = db
|
|
201
|
+
.prepare(
|
|
202
|
+
`SELECT DISTINCT n.id
|
|
203
|
+
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
204
|
+
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
205
|
+
)
|
|
206
|
+
.all(id);
|
|
200
207
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
208
|
+
if (outgoing.length === 0) {
|
|
209
|
+
const node = idToNode.get(id);
|
|
210
|
+
if (node) {
|
|
211
|
+
leaves.push({ ...node, depth });
|
|
212
|
+
}
|
|
205
213
|
}
|
|
206
214
|
}
|
|
207
|
-
}
|
|
208
215
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
const base = {
|
|
217
|
+
entry,
|
|
218
|
+
depth: maxDepth,
|
|
219
|
+
steps,
|
|
220
|
+
leaves,
|
|
221
|
+
cycles,
|
|
222
|
+
totalReached: visited.size - 1, // exclude the entry node itself
|
|
223
|
+
truncated,
|
|
224
|
+
};
|
|
225
|
+
return paginateResult(base, 'steps', { limit: opts.limit, offset: opts.offset });
|
|
226
|
+
} finally {
|
|
227
|
+
db.close();
|
|
228
|
+
}
|
|
220
229
|
}
|
|
221
230
|
|
|
222
231
|
/**
|
|
@@ -229,14 +238,7 @@ export function flow(name, dbPath, opts = {}) {
|
|
|
229
238
|
limit: opts.limit,
|
|
230
239
|
offset: opts.offset,
|
|
231
240
|
});
|
|
232
|
-
if (opts
|
|
233
|
-
printNdjson(data, 'entries');
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
if (opts.json) {
|
|
237
|
-
console.log(JSON.stringify(data, null, 2));
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
241
|
+
if (outputResult(data, 'entries', opts)) return;
|
|
240
242
|
if (data.count === 0) {
|
|
241
243
|
console.log('No entry points found. Run "codegraph build" first.');
|
|
242
244
|
return;
|
|
@@ -253,10 +255,7 @@ export function flow(name, dbPath, opts = {}) {
|
|
|
253
255
|
}
|
|
254
256
|
|
|
255
257
|
const data = flowData(name, dbPath, opts);
|
|
256
|
-
if (opts
|
|
257
|
-
console.log(JSON.stringify(data, null, 2));
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
258
|
+
if (outputResult(data, 'steps', opts)) return;
|
|
260
259
|
|
|
261
260
|
if (!data.entry) {
|
|
262
261
|
console.log(`No matching entry point or function found for "${name}".`);
|
package/src/index.js
CHANGED
|
@@ -77,12 +77,24 @@ export {
|
|
|
77
77
|
} from './dataflow.js';
|
|
78
78
|
// Database utilities
|
|
79
79
|
export {
|
|
80
|
+
countEdges,
|
|
81
|
+
countFiles,
|
|
82
|
+
countNodes,
|
|
83
|
+
fanInJoinSQL,
|
|
84
|
+
fanOutJoinSQL,
|
|
80
85
|
findDbPath,
|
|
86
|
+
findNodesForTriage,
|
|
87
|
+
findNodesWithFanIn,
|
|
81
88
|
getBuildMeta,
|
|
82
89
|
initSchema,
|
|
90
|
+
iterateFunctionNodes,
|
|
91
|
+
kindInClause,
|
|
92
|
+
listFunctionNodes,
|
|
93
|
+
NodeQuery,
|
|
83
94
|
openDb,
|
|
84
95
|
openReadonlyOrFail,
|
|
85
96
|
setBuildMeta,
|
|
97
|
+
testFilterSQL,
|
|
86
98
|
} from './db.js';
|
|
87
99
|
// Embeddings
|
|
88
100
|
export {
|
|
@@ -140,7 +152,6 @@ export {
|
|
|
140
152
|
FALSE_POSITIVE_CALLER_THRESHOLD,
|
|
141
153
|
FALSE_POSITIVE_NAMES,
|
|
142
154
|
fileDepsData,
|
|
143
|
-
fileExports,
|
|
144
155
|
fnDepsData,
|
|
145
156
|
fnImpactData,
|
|
146
157
|
impactAnalysisData,
|
|
@@ -158,6 +169,24 @@ export {
|
|
|
158
169
|
VALID_ROLES,
|
|
159
170
|
whereData,
|
|
160
171
|
} from './queries.js';
|
|
172
|
+
// Query CLI display wrappers
|
|
173
|
+
export {
|
|
174
|
+
children,
|
|
175
|
+
context,
|
|
176
|
+
diffImpact,
|
|
177
|
+
explain,
|
|
178
|
+
fileDeps,
|
|
179
|
+
fileExports,
|
|
180
|
+
fnDeps,
|
|
181
|
+
fnImpact,
|
|
182
|
+
impactAnalysis,
|
|
183
|
+
moduleMap,
|
|
184
|
+
queryName,
|
|
185
|
+
roles,
|
|
186
|
+
stats,
|
|
187
|
+
symbolPath,
|
|
188
|
+
where,
|
|
189
|
+
} from './queries-cli.js';
|
|
161
190
|
// Registry (multi-repo)
|
|
162
191
|
export {
|
|
163
192
|
listRepos,
|
|
@@ -169,6 +198,8 @@ export {
|
|
|
169
198
|
saveRegistry,
|
|
170
199
|
unregisterRepo,
|
|
171
200
|
} from './registry.js';
|
|
201
|
+
// Result formatting
|
|
202
|
+
export { outputResult } from './result-formatter.js';
|
|
172
203
|
// Sequence diagram generation
|
|
173
204
|
export { sequence, sequenceData, sequenceToMermaid } from './sequence.js';
|
|
174
205
|
// Snapshot management
|
|
@@ -192,6 +223,8 @@ export {
|
|
|
192
223
|
moduleBoundariesData,
|
|
193
224
|
structureData,
|
|
194
225
|
} from './structure.js';
|
|
226
|
+
// Test file detection
|
|
227
|
+
export { isTestFile, TEST_PATTERN } from './test-filter.js';
|
|
195
228
|
// Triage — composite risk audit
|
|
196
229
|
export { triage, triageData } from './triage.js';
|
|
197
230
|
// Interactive HTML viewer
|
package/src/kinds.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// ── Symbol kind constants ───────────────────────────────────────────
|
|
2
|
+
// Original 10 kinds — used as default query scope
|
|
3
|
+
export const CORE_SYMBOL_KINDS = [
|
|
4
|
+
'function',
|
|
5
|
+
'method',
|
|
6
|
+
'class',
|
|
7
|
+
'interface',
|
|
8
|
+
'type',
|
|
9
|
+
'struct',
|
|
10
|
+
'enum',
|
|
11
|
+
'trait',
|
|
12
|
+
'record',
|
|
13
|
+
'module',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
// Sub-declaration kinds (Phase 1)
|
|
17
|
+
export const EXTENDED_SYMBOL_KINDS = [
|
|
18
|
+
'parameter',
|
|
19
|
+
'property',
|
|
20
|
+
'constant',
|
|
21
|
+
// Phase 2 (reserved, not yet extracted):
|
|
22
|
+
// 'constructor', 'namespace', 'decorator', 'getter', 'setter',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// Full set for --kind validation and MCP enum
|
|
26
|
+
export const EVERY_SYMBOL_KIND = [...CORE_SYMBOL_KINDS, ...EXTENDED_SYMBOL_KINDS];
|
|
27
|
+
|
|
28
|
+
// Backward compat: ALL_SYMBOL_KINDS stays as the core 10
|
|
29
|
+
export const ALL_SYMBOL_KINDS = CORE_SYMBOL_KINDS;
|
|
30
|
+
|
|
31
|
+
// ── Edge kind constants ─────────────────────────────────────────────
|
|
32
|
+
// Core edge kinds — coupling and dependency relationships
|
|
33
|
+
export const CORE_EDGE_KINDS = [
|
|
34
|
+
'imports',
|
|
35
|
+
'imports-type',
|
|
36
|
+
'reexports',
|
|
37
|
+
'calls',
|
|
38
|
+
'extends',
|
|
39
|
+
'implements',
|
|
40
|
+
'contains',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// Structural edge kinds — parent/child and type relationships
|
|
44
|
+
export const STRUCTURAL_EDGE_KINDS = ['parameter_of', 'receiver'];
|
|
45
|
+
|
|
46
|
+
// Full set for MCP enum and validation
|
|
47
|
+
export const EVERY_EDGE_KIND = [...CORE_EDGE_KINDS, ...STRUCTURAL_EDGE_KINDS];
|
|
48
|
+
|
|
49
|
+
export const VALID_ROLES = ['entry', 'core', 'utility', 'adapter', 'dead', 'leaf'];
|
package/src/manifesto.js
CHANGED
|
@@ -3,7 +3,8 @@ import { loadConfig } from './config.js';
|
|
|
3
3
|
import { findCycles } from './cycles.js';
|
|
4
4
|
import { openReadonlyOrFail } from './db.js';
|
|
5
5
|
import { debug } from './logger.js';
|
|
6
|
-
import { paginateResult
|
|
6
|
+
import { paginateResult } from './paginate.js';
|
|
7
|
+
import { outputResult } from './result-formatter.js';
|
|
7
8
|
|
|
8
9
|
// ─── Rule Definitions ─────────────────────────────────────────────────
|
|
9
10
|
|
|
@@ -434,13 +435,7 @@ export function manifestoData(customDbPath, opts = {}) {
|
|
|
434
435
|
export function manifesto(customDbPath, opts = {}) {
|
|
435
436
|
const data = manifestoData(customDbPath, opts);
|
|
436
437
|
|
|
437
|
-
if (opts
|
|
438
|
-
printNdjson(data, 'violations');
|
|
439
|
-
if (!data.passed) process.exit(1);
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
if (opts.json) {
|
|
443
|
-
console.log(JSON.stringify(data, null, 2));
|
|
438
|
+
if (outputResult(data, 'violations', opts)) {
|
|
444
439
|
if (!data.passed) process.exit(1);
|
|
445
440
|
return;
|
|
446
441
|
}
|
package/src/mcp.js
CHANGED
|
@@ -836,26 +836,27 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
836
836
|
process.exit(1);
|
|
837
837
|
}
|
|
838
838
|
|
|
839
|
-
//
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
fnDepsData,
|
|
846
|
-
fnImpactData,
|
|
847
|
-
pathData,
|
|
848
|
-
contextData,
|
|
849
|
-
childrenData,
|
|
850
|
-
explainData,
|
|
851
|
-
whereData,
|
|
852
|
-
diffImpactData,
|
|
853
|
-
listFunctionsData,
|
|
854
|
-
rolesData,
|
|
855
|
-
} = await import('./queries.js');
|
|
839
|
+
// Connect transport FIRST so the server can receive the client's
|
|
840
|
+
// `initialize` request while heavy modules (queries, better-sqlite3)
|
|
841
|
+
// are still loading. These are lazy-loaded on the first tool call
|
|
842
|
+
// and cached for subsequent calls.
|
|
843
|
+
let _queries;
|
|
844
|
+
let _Database;
|
|
856
845
|
|
|
857
|
-
|
|
858
|
-
|
|
846
|
+
async function getQueries() {
|
|
847
|
+
if (!_queries) {
|
|
848
|
+
_queries = await import('./queries.js');
|
|
849
|
+
}
|
|
850
|
+
return _queries;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function getDatabase() {
|
|
854
|
+
if (!_Database) {
|
|
855
|
+
const require = createRequire(import.meta.url);
|
|
856
|
+
_Database = require('better-sqlite3');
|
|
857
|
+
}
|
|
858
|
+
return _Database;
|
|
859
|
+
}
|
|
859
860
|
|
|
860
861
|
const server = new Server(
|
|
861
862
|
{ name: 'codegraph', version: '1.0.0' },
|
|
@@ -868,8 +869,24 @@ export async function startMCPServer(customDbPath, options = {}) {
|
|
|
868
869
|
|
|
869
870
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
870
871
|
const { name, arguments: args } = request.params;
|
|
871
|
-
|
|
872
872
|
try {
|
|
873
|
+
const {
|
|
874
|
+
impactAnalysisData,
|
|
875
|
+
moduleMapData,
|
|
876
|
+
fileDepsData,
|
|
877
|
+
exportsData,
|
|
878
|
+
fnDepsData,
|
|
879
|
+
fnImpactData,
|
|
880
|
+
pathData,
|
|
881
|
+
contextData,
|
|
882
|
+
childrenData,
|
|
883
|
+
explainData,
|
|
884
|
+
whereData,
|
|
885
|
+
diffImpactData,
|
|
886
|
+
listFunctionsData,
|
|
887
|
+
rolesData,
|
|
888
|
+
} = await getQueries();
|
|
889
|
+
const Database = getDatabase();
|
|
873
890
|
if (!multiRepo && args.repo) {
|
|
874
891
|
throw new Error(
|
|
875
892
|
'Multi-repo access is disabled. Restart with `codegraph mcp --multi-repo` to access other repositories.',
|