@codragraph/cli 2.1.0 → 2.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 +58 -20
- package/dist/_shared/cgdb/schema-constants.d.ts +2 -2
- package/dist/_shared/cgdb/schema-constants.d.ts.map +1 -1
- package/dist/_shared/cgdb/schema-constants.js +3 -0
- package/dist/_shared/cgdb/schema-constants.js.map +1 -1
- package/dist/_shared/feature-clusters.d.ts +99 -0
- package/dist/_shared/feature-clusters.d.ts.map +1 -0
- package/dist/_shared/feature-clusters.js +2 -0
- package/dist/_shared/feature-clusters.js.map +1 -0
- package/dist/_shared/graph/types.d.ts +16 -2
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +1 -0
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/pipeline.d.ts +1 -1
- package/dist/_shared/pipeline.d.ts.map +1 -1
- package/dist/cli/ai-context.js +4 -0
- package/dist/cli/analyze.js +27 -24
- package/dist/cli/index.js +37 -0
- package/dist/cli/setup.js +9 -5
- package/dist/cli/tool.d.ts +25 -0
- package/dist/cli/tool.js +74 -0
- package/dist/config/supported-languages.d.ts +3 -3
- package/dist/config/supported-languages.js +3 -3
- package/dist/core/cgdb/cgdb-adapter.js +19 -3
- package/dist/core/cgdb/csv-generator.js +33 -2
- package/dist/core/cgdb/schema.d.ts +2 -1
- package/dist/core/cgdb/schema.js +55 -0
- package/dist/core/embeddings/embedder.js +4 -2
- package/dist/core/graphstore/index.d.ts +1 -1
- package/dist/core/graphstore/index.js +1 -1
- package/dist/core/group/service.d.ts +16 -0
- package/dist/core/group/service.js +360 -0
- package/dist/core/ingestion/emit-references.d.ts +1 -1
- package/dist/core/ingestion/emit-references.js +1 -1
- package/dist/core/ingestion/feature-cluster-processor.d.ts +62 -0
- package/dist/core/ingestion/feature-cluster-processor.js +626 -0
- package/dist/core/ingestion/finalize-orchestrator.js +1 -1
- package/dist/core/ingestion/model/registration-table.js +1 -0
- package/dist/core/ingestion/model/resolve.d.ts +2 -2
- package/dist/core/ingestion/model/resolve.js +3 -3
- package/dist/core/ingestion/model/semantic-model.d.ts +1 -1
- package/dist/core/ingestion/model/semantic-model.js +1 -1
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/model/symbol-table.js +1 -1
- package/dist/core/ingestion/pipeline-phases/feature-clusters.d.ts +17 -0
- package/dist/core/ingestion/pipeline-phases/feature-clusters.js +88 -0
- package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/index.js +1 -0
- package/dist/core/ingestion/pipeline.d.ts +4 -0
- package/dist/core/ingestion/pipeline.js +9 -5
- package/dist/core/run-analyze.d.ts +1 -0
- package/dist/core/run-analyze.js +12 -6
- package/dist/mcp/core/embedder.js +5 -2
- package/dist/mcp/local/local-backend.d.ts +12 -0
- package/dist/mcp/local/local-backend.js +381 -3
- package/dist/mcp/resources.js +139 -0
- package/dist/mcp/tools.js +174 -2
- package/dist/server/api.js +116 -0
- package/dist/storage/repo-manager.d.ts +6 -1
- package/dist/storage/repo-manager.js +5 -1
- package/dist/types/pipeline.d.ts +2 -0
- package/package.json +13 -4
- package/scripts/build.js +13 -12
- package/skills/codragraph-cli.md +17 -1
- package/skills/codragraph-guide.md +6 -2
- package/skills/codragraph-onboarding.md +2 -2
package/dist/mcp/tools.js
CHANGED
|
@@ -84,6 +84,177 @@ SERVICE: optional monorepo path prefix (POSIX-style, case-sensitive segments). W
|
|
|
84
84
|
required: ['query'],
|
|
85
85
|
},
|
|
86
86
|
},
|
|
87
|
+
{
|
|
88
|
+
name: 'feature_clusters',
|
|
89
|
+
description: `List human-facing feature clusters such as Settings, AI, Auth, Billing, MCP, or Ingestion.
|
|
90
|
+
|
|
91
|
+
WHEN TO USE: First step for targeted implementation/refactoring when you need the functional area map before loading files. This is the product/domain layer above algorithmic Community nodes.
|
|
92
|
+
AFTER THIS: Use feature_context(name) for members with file paths and line ranges, then context() or impact() on specific symbols.`,
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
query: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
description: 'Optional cluster owner search term (e.g. "settings", "AI", "billing").',
|
|
99
|
+
},
|
|
100
|
+
repo: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
103
|
+
},
|
|
104
|
+
limit: {
|
|
105
|
+
type: 'number',
|
|
106
|
+
description: 'Max feature clusters to return (default: 100)',
|
|
107
|
+
default: 100,
|
|
108
|
+
minimum: 1,
|
|
109
|
+
maximum: 500,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
required: [],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'feature_context',
|
|
117
|
+
description: `Get a complete context pack for one FeatureCluster.
|
|
118
|
+
|
|
119
|
+
Returns the cluster metadata, member symbols/files with line ranges, outgoing/incoming feature dependencies, and related execution processes.
|
|
120
|
+
|
|
121
|
+
WHEN TO USE: Before editing a feature area like Settings or AI. This narrows exploration to the exact files and symbols in that feature cluster.`,
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
name: {
|
|
126
|
+
type: 'string',
|
|
127
|
+
description: 'Feature cluster name, slug, or id (e.g. "Settings", "settings").',
|
|
128
|
+
},
|
|
129
|
+
repo: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
132
|
+
},
|
|
133
|
+
limit: {
|
|
134
|
+
type: 'number',
|
|
135
|
+
description: 'Max members to return (default: 100)',
|
|
136
|
+
default: 100,
|
|
137
|
+
minimum: 1,
|
|
138
|
+
maximum: 500,
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
required: ['name'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'cluster_query',
|
|
146
|
+
description: `Cluster-first alias for feature_clusters.
|
|
147
|
+
|
|
148
|
+
WHEN TO USE: Ask which product/domain cluster owns an area like Settings, AI, Auth, or Billing before loading files.`,
|
|
149
|
+
inputSchema: {
|
|
150
|
+
type: 'object',
|
|
151
|
+
properties: {
|
|
152
|
+
query: {
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'Optional cluster owner search term (e.g. "settings", "AI", "billing").',
|
|
155
|
+
},
|
|
156
|
+
repo: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
159
|
+
},
|
|
160
|
+
limit: {
|
|
161
|
+
type: 'number',
|
|
162
|
+
description: 'Max feature clusters to return (default: 100)',
|
|
163
|
+
default: 100,
|
|
164
|
+
minimum: 1,
|
|
165
|
+
maximum: 500,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: [],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: 'cluster_context',
|
|
173
|
+
description: `Cluster-first alias for feature_context.
|
|
174
|
+
|
|
175
|
+
Returns a FeatureCluster context pack with members, entry points, routes, tools, tests, docs, dependencies, and safe edit surface.`,
|
|
176
|
+
inputSchema: {
|
|
177
|
+
type: 'object',
|
|
178
|
+
properties: {
|
|
179
|
+
name: {
|
|
180
|
+
type: 'string',
|
|
181
|
+
description: 'Feature cluster name, slug, or id (e.g. "Settings", "settings").',
|
|
182
|
+
},
|
|
183
|
+
repo: {
|
|
184
|
+
type: 'string',
|
|
185
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
186
|
+
},
|
|
187
|
+
limit: {
|
|
188
|
+
type: 'number',
|
|
189
|
+
description: 'Max members to return (default: 100)',
|
|
190
|
+
default: 100,
|
|
191
|
+
minimum: 1,
|
|
192
|
+
maximum: 500,
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
required: ['name'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'context_pack',
|
|
200
|
+
description: `Get the compact agent context pack for a FeatureCluster.
|
|
201
|
+
|
|
202
|
+
WHEN TO USE: Before a refactor or implementation task where the agent should avoid re-exploring the full repo.`,
|
|
203
|
+
inputSchema: {
|
|
204
|
+
type: 'object',
|
|
205
|
+
properties: {
|
|
206
|
+
name: {
|
|
207
|
+
type: 'string',
|
|
208
|
+
description: 'Feature cluster name, slug, or id (e.g. "AI", "ai").',
|
|
209
|
+
},
|
|
210
|
+
repo: {
|
|
211
|
+
type: 'string',
|
|
212
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
213
|
+
},
|
|
214
|
+
limit: {
|
|
215
|
+
type: 'number',
|
|
216
|
+
description: 'Max members to return (default: 100)',
|
|
217
|
+
default: 100,
|
|
218
|
+
minimum: 1,
|
|
219
|
+
maximum: 500,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
required: ['name'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: 'cluster_impact',
|
|
227
|
+
description: `Assess feature-level blast radius for a FeatureCluster.
|
|
228
|
+
|
|
229
|
+
Returns upstream/downstream cluster dependencies plus the same context pack and safe edit surface used for targeted edits.`,
|
|
230
|
+
inputSchema: {
|
|
231
|
+
type: 'object',
|
|
232
|
+
properties: {
|
|
233
|
+
name: {
|
|
234
|
+
type: 'string',
|
|
235
|
+
description: 'Feature cluster name, slug, or id.',
|
|
236
|
+
},
|
|
237
|
+
direction: {
|
|
238
|
+
type: 'string',
|
|
239
|
+
enum: ['upstream', 'downstream', 'both'],
|
|
240
|
+
description: 'Dependency direction to inspect.',
|
|
241
|
+
default: 'upstream',
|
|
242
|
+
},
|
|
243
|
+
repo: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: 'Repository name or path. Omit if only one repo is indexed.',
|
|
246
|
+
},
|
|
247
|
+
limit: {
|
|
248
|
+
type: 'number',
|
|
249
|
+
description: 'Max members to include in the context pack (default: 100)',
|
|
250
|
+
default: 100,
|
|
251
|
+
minimum: 1,
|
|
252
|
+
maximum: 500,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
required: ['name'],
|
|
256
|
+
},
|
|
257
|
+
},
|
|
87
258
|
{
|
|
88
259
|
name: 'cypher',
|
|
89
260
|
description: `Execute Cypher query against the code knowledge graph.
|
|
@@ -92,10 +263,10 @@ WHEN TO USE: Complex structural queries that search/explore can't answer. READ c
|
|
|
92
263
|
AFTER THIS: Use context() on result symbols for deeper context.
|
|
93
264
|
|
|
94
265
|
SCHEMA:
|
|
95
|
-
- Nodes: File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process, Route, Tool
|
|
266
|
+
- Nodes: File, Folder, Function, Class, Interface, Method, CodeElement, Community, Process, FeatureCluster, Route, Tool
|
|
96
267
|
- Multi-language nodes (use backticks): \`Struct\`, \`Enum\`, \`Trait\`, \`Impl\`, etc.
|
|
97
268
|
- All edges via single CodeRelation table with 'type' property
|
|
98
|
-
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES, METHOD_OVERRIDES, METHOD_IMPLEMENTS, MEMBER_OF, STEP_IN_PROCESS, HANDLES_ROUTE, FETCHES, HANDLES_TOOL, ENTRY_POINT_OF
|
|
269
|
+
- Edge types: CONTAINS, DEFINES, CALLS, IMPORTS, EXTENDS, IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES, METHOD_OVERRIDES, METHOD_IMPLEMENTS, MEMBER_OF, STEP_IN_PROCESS, HANDLES_ROUTE, FETCHES, HANDLES_TOOL, ENTRY_POINT_OF, WRAPS, QUERIES, FEATURE_MEMBER_OF, FEATURE_DEPENDS_ON
|
|
99
270
|
- Edge properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)
|
|
100
271
|
|
|
101
272
|
EXAMPLES:
|
|
@@ -129,6 +300,7 @@ TIPS:
|
|
|
129
300
|
- All relationships use single CodeRelation table — filter with {type: 'CALLS'} etc.
|
|
130
301
|
- Community = auto-detected functional area (Leiden algorithm). Properties: heuristicLabel, cohesion, symbolCount, keywords, description, enrichedBy
|
|
131
302
|
- Process = execution flow trace from entry point to terminal. Properties: heuristicLabel, processType, stepCount, communities, entryPointId, terminalId
|
|
303
|
+
- FeatureCluster = product/domain area for targeted context packs. Properties: name, slug, featureKind, summary, repo, service, memberCount, entryPointIds, routes, tools, testCoverageHints, lastIndexedCommit, confidence, signals
|
|
132
304
|
- Use heuristicLabel (not label) for human-readable community/process names`,
|
|
133
305
|
inputSchema: {
|
|
134
306
|
type: 'object',
|
package/dist/server/api.js
CHANGED
|
@@ -202,6 +202,9 @@ const getNodeQuery = (table, includeContent) => {
|
|
|
202
202
|
if (table === 'Process') {
|
|
203
203
|
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.label AS label, n.heuristicLabel AS heuristicLabel, n.processType AS processType, n.stepCount AS stepCount, n.communities AS communities, n.entryPointId AS entryPointId, n.terminalId AS terminalId`;
|
|
204
204
|
}
|
|
205
|
+
if (table === 'FeatureCluster') {
|
|
206
|
+
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.slug AS slug, n.featureKind AS featureKind, n.summary AS summary, n.description AS description, n.repo AS repo, n.service AS service, n.signals AS signals, n.memberCount AS memberCount, n.entryPointIds AS entryPointIds, n.routes AS routes, n.tools AS tools, n.testCoverageHints AS testCoverageHints, n.lastIndexedCommit AS lastIndexedCommit, n.confidence AS confidence, n.source AS source`;
|
|
207
|
+
}
|
|
205
208
|
if (table === 'Route') {
|
|
206
209
|
return `MATCH (n:${tableLabel}) RETURN n.id AS id, n.name AS name, n.filePath AS filePath, n.responseKeys AS responseKeys, n.errorKeys AS errorKeys, n.middleware AS middleware`;
|
|
207
210
|
}
|
|
@@ -233,6 +236,20 @@ const mapGraphNodeRow = (table, row, includeContent) => ({
|
|
|
233
236
|
communities: row.communities,
|
|
234
237
|
entryPointId: row.entryPointId,
|
|
235
238
|
terminalId: row.terminalId,
|
|
239
|
+
slug: row.slug,
|
|
240
|
+
featureKind: row.featureKind,
|
|
241
|
+
summary: row.summary,
|
|
242
|
+
repo: row.repo,
|
|
243
|
+
service: row.service,
|
|
244
|
+
signals: row.signals,
|
|
245
|
+
memberCount: row.memberCount,
|
|
246
|
+
entryPointIds: row.entryPointIds,
|
|
247
|
+
routes: row.routes,
|
|
248
|
+
tools: row.tools,
|
|
249
|
+
testCoverageHints: row.testCoverageHints,
|
|
250
|
+
lastIndexedCommit: row.lastIndexedCommit,
|
|
251
|
+
confidence: row.confidence,
|
|
252
|
+
source: row.source,
|
|
236
253
|
},
|
|
237
254
|
});
|
|
238
255
|
const mapGraphRelationshipRow = (row) => ({
|
|
@@ -1017,6 +1034,45 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1017
1034
|
res.status(500).json({ error: err.message || 'Query failed' });
|
|
1018
1035
|
}
|
|
1019
1036
|
});
|
|
1037
|
+
// Symbol context through the same LocalBackend path as MCP `context`
|
|
1038
|
+
app.post('/api/context', async (req, res) => {
|
|
1039
|
+
try {
|
|
1040
|
+
const name = String(req.body?.name ?? '').trim();
|
|
1041
|
+
if (!name) {
|
|
1042
|
+
res.status(400).json({ error: 'Missing "name" in request body' });
|
|
1043
|
+
return;
|
|
1044
|
+
}
|
|
1045
|
+
const result = await backend.callTool('context', {
|
|
1046
|
+
...req.body,
|
|
1047
|
+
name,
|
|
1048
|
+
repo: requestedRepo(req),
|
|
1049
|
+
});
|
|
1050
|
+
res.json(result);
|
|
1051
|
+
}
|
|
1052
|
+
catch (err) {
|
|
1053
|
+
res.status(statusFromError(err)).json({ error: err.message || 'Context query failed' });
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
// Symbol impact through the same LocalBackend path as MCP `impact`
|
|
1057
|
+
app.post('/api/impact', async (req, res) => {
|
|
1058
|
+
try {
|
|
1059
|
+
const target = String(req.body?.target ?? '').trim();
|
|
1060
|
+
if (!target) {
|
|
1061
|
+
res.status(400).json({ error: 'Missing "target" in request body' });
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
const result = await backend.callTool('impact', {
|
|
1065
|
+
...req.body,
|
|
1066
|
+
target,
|
|
1067
|
+
direction: req.body?.direction ?? 'upstream',
|
|
1068
|
+
repo: requestedRepo(req),
|
|
1069
|
+
});
|
|
1070
|
+
res.json(result);
|
|
1071
|
+
}
|
|
1072
|
+
catch (err) {
|
|
1073
|
+
res.status(statusFromError(err)).json({ error: err.message || 'Impact query failed' });
|
|
1074
|
+
}
|
|
1075
|
+
});
|
|
1020
1076
|
// Search (supports mode: 'hybrid' | 'semantic' | 'bm25', and optional enrichment)
|
|
1021
1077
|
app.post('/api/search', async (req, res) => {
|
|
1022
1078
|
try {
|
|
@@ -1326,6 +1382,66 @@ export const createServer = async (port, host = '127.0.0.1') => {
|
|
|
1326
1382
|
.json({ error: err.message || 'Failed to query cluster detail' });
|
|
1327
1383
|
}
|
|
1328
1384
|
});
|
|
1385
|
+
// List all feature clusters
|
|
1386
|
+
app.get('/api/feature-clusters', async (req, res) => {
|
|
1387
|
+
try {
|
|
1388
|
+
const limit = req.query.limit ? Number.parseInt(String(req.query.limit), 10) : undefined;
|
|
1389
|
+
const query = String(req.query.query ?? '');
|
|
1390
|
+
const result = await backend.queryFeatureClusters(requestedRepo(req), limit, query);
|
|
1391
|
+
res.json(result);
|
|
1392
|
+
}
|
|
1393
|
+
catch (err) {
|
|
1394
|
+
res
|
|
1395
|
+
.status(statusFromError(err))
|
|
1396
|
+
.json({ error: err.message || 'Failed to query feature clusters' });
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
// Feature cluster detail
|
|
1400
|
+
app.get('/api/feature-cluster', async (req, res) => {
|
|
1401
|
+
try {
|
|
1402
|
+
const name = String(req.query.name ?? '').trim();
|
|
1403
|
+
if (!name) {
|
|
1404
|
+
res.status(400).json({ error: 'Missing "name" query parameter' });
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
const limit = req.query.limit ? Number.parseInt(String(req.query.limit), 10) : undefined;
|
|
1408
|
+
const result = await backend.queryFeatureContext(name, requestedRepo(req), limit);
|
|
1409
|
+
if (result?.error) {
|
|
1410
|
+
res.status(404).json({ error: result.error });
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
res.json(result);
|
|
1414
|
+
}
|
|
1415
|
+
catch (err) {
|
|
1416
|
+
res
|
|
1417
|
+
.status(statusFromError(err))
|
|
1418
|
+
.json({ error: err.message || 'Failed to query feature cluster detail' });
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
// Feature cluster impact/context pack
|
|
1422
|
+
app.get(['/api/feature-impact', '/api/cluster-impact'], async (req, res) => {
|
|
1423
|
+
try {
|
|
1424
|
+
const name = String(req.query.name ?? '').trim();
|
|
1425
|
+
if (!name) {
|
|
1426
|
+
res.status(400).json({ error: 'Missing "name" query parameter' });
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
const limit = req.query.limit ? Number.parseInt(String(req.query.limit), 10) : undefined;
|
|
1430
|
+
const directionText = String(req.query.direction ?? 'upstream');
|
|
1431
|
+
const direction = directionText === 'downstream' || directionText === 'both' ? directionText : 'upstream';
|
|
1432
|
+
const result = await backend.queryFeatureImpact(name, requestedRepo(req), direction, limit);
|
|
1433
|
+
if (result?.error) {
|
|
1434
|
+
res.status(404).json({ error: result.error });
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
res.json(result);
|
|
1438
|
+
}
|
|
1439
|
+
catch (err) {
|
|
1440
|
+
res
|
|
1441
|
+
.status(statusFromError(err))
|
|
1442
|
+
.json({ error: err.message || 'Failed to query feature cluster impact' });
|
|
1443
|
+
}
|
|
1444
|
+
});
|
|
1329
1445
|
// ── Analyze API ──────────────────────────────────────────────────────
|
|
1330
1446
|
// POST /api/analyze — start a new analysis job
|
|
1331
1447
|
app.post('/api/analyze', async (req, res) => {
|
|
@@ -47,6 +47,10 @@ export declare const canonicalizePath: (p: string) => string;
|
|
|
47
47
|
* opt into compression via `--compress brotli|zstd` (compression
|
|
48
48
|
* is OFF by default, so existing readers keep working). Readers
|
|
49
49
|
* decode based on the per-row encoding tag.
|
|
50
|
+
* 3 - FeatureCluster layer: adds FeatureCluster nodes plus
|
|
51
|
+
* FEATURE_MEMBER_OF / FEATURE_DEPENDS_ON relation rows.
|
|
52
|
+
* 4 - FeatureCluster context-pack metadata: summary, repo/service,
|
|
53
|
+
* routes, tools, test coverage hints, and indexed commit fields.
|
|
50
54
|
*
|
|
51
55
|
* Bumping this is the migration trigger: `runFullAnalysis` forces a
|
|
52
56
|
* full re-analyze when an existing index has a missing or older
|
|
@@ -54,7 +58,7 @@ export declare const canonicalizePath: (p: string) => string;
|
|
|
54
58
|
* LadybugDB table via ALTER is not validated end-to-end yet — fresh
|
|
55
59
|
* `CREATE NODE TABLE` is the supported path.
|
|
56
60
|
*/
|
|
57
|
-
export declare const INDEX_SCHEMA_VERSION:
|
|
61
|
+
export declare const INDEX_SCHEMA_VERSION: 4;
|
|
58
62
|
export interface RepoMeta {
|
|
59
63
|
repoPath: string;
|
|
60
64
|
lastCommit: string;
|
|
@@ -103,6 +107,7 @@ export interface RepoMeta {
|
|
|
103
107
|
nodes?: number;
|
|
104
108
|
edges?: number;
|
|
105
109
|
communities?: number;
|
|
110
|
+
featureClusters?: number;
|
|
106
111
|
processes?: number;
|
|
107
112
|
embeddings?: number;
|
|
108
113
|
};
|
|
@@ -60,6 +60,10 @@ export const canonicalizePath = (p) => {
|
|
|
60
60
|
* opt into compression via `--compress brotli|zstd` (compression
|
|
61
61
|
* is OFF by default, so existing readers keep working). Readers
|
|
62
62
|
* decode based on the per-row encoding tag.
|
|
63
|
+
* 3 - FeatureCluster layer: adds FeatureCluster nodes plus
|
|
64
|
+
* FEATURE_MEMBER_OF / FEATURE_DEPENDS_ON relation rows.
|
|
65
|
+
* 4 - FeatureCluster context-pack metadata: summary, repo/service,
|
|
66
|
+
* routes, tools, test coverage hints, and indexed commit fields.
|
|
63
67
|
*
|
|
64
68
|
* Bumping this is the migration trigger: `runFullAnalysis` forces a
|
|
65
69
|
* full re-analyze when an existing index has a missing or older
|
|
@@ -67,7 +71,7 @@ export const canonicalizePath = (p) => {
|
|
|
67
71
|
* LadybugDB table via ALTER is not validated end-to-end yet — fresh
|
|
68
72
|
* `CREATE NODE TABLE` is the supported path.
|
|
69
73
|
*/
|
|
70
|
-
export const INDEX_SCHEMA_VERSION =
|
|
74
|
+
export const INDEX_SCHEMA_VERSION = 4;
|
|
71
75
|
const CODRAGRAPH_DIR = '.codragraph';
|
|
72
76
|
// ─── Local Storage Helpers ─────────────────────────────────────────────
|
|
73
77
|
/**
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KnowledgeGraph } from '../core/graph/types.js';
|
|
2
2
|
import { CommunityDetectionResult } from '../core/ingestion/community-processor.js';
|
|
3
|
+
import { FeatureClusterDetectionResult } from '../core/ingestion/feature-cluster-processor.js';
|
|
3
4
|
import { ProcessDetectionResult } from '../core/ingestion/process-processor.js';
|
|
4
5
|
export interface PipelineResult {
|
|
5
6
|
graph: KnowledgeGraph;
|
|
@@ -9,6 +10,7 @@ export interface PipelineResult {
|
|
|
9
10
|
totalFileCount: number;
|
|
10
11
|
communityResult?: CommunityDetectionResult;
|
|
11
12
|
processResult?: ProcessDetectionResult;
|
|
13
|
+
featureClusterResult?: FeatureClusterDetectionResult;
|
|
12
14
|
/**
|
|
13
15
|
* True if the parse phase spawned a worker pool for this run. False means
|
|
14
16
|
* the sequential fallback handled every chunk. Primarily a test affordance
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codragraph/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": {
|
|
6
|
-
"name": "
|
|
7
|
-
"email": "
|
|
8
|
-
"url": "https://
|
|
6
|
+
"name": "Thinqmesh Technologies",
|
|
7
|
+
"email": "hello@thinqmesh.com",
|
|
8
|
+
"url": "https://thinqmesh.com"
|
|
9
9
|
},
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"keywords": [
|
|
@@ -123,5 +123,14 @@
|
|
|
123
123
|
"publishConfig": {
|
|
124
124
|
"access": "public",
|
|
125
125
|
"registry": "https://registry.npmjs.org/"
|
|
126
|
+
},
|
|
127
|
+
"homepage": "https://github.com/AnitChaudhry/CodraGraph#readme",
|
|
128
|
+
"repository": {
|
|
129
|
+
"type": "git",
|
|
130
|
+
"url": "git+https://github.com/AnitChaudhry/CodraGraph.git",
|
|
131
|
+
"directory": "packages/core"
|
|
132
|
+
},
|
|
133
|
+
"bugs": {
|
|
134
|
+
"url": "https://github.com/AnitChaudhry/CodraGraph/issues"
|
|
126
135
|
}
|
|
127
136
|
}
|
package/scripts/build.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Build script that compiles codragraph and inlines codragraph
|
|
3
|
+
* Build script that compiles @codragraph/cli and inlines @codragraph/shared
|
|
4
|
+
* into the published dist.
|
|
4
5
|
*
|
|
5
6
|
* Steps:
|
|
6
|
-
* 1. Build codragraph
|
|
7
|
-
* 2. Build codragraph
|
|
7
|
+
* 1. Build @codragraph/shared (tsc)
|
|
8
|
+
* 2. Build @codragraph/graphstore (tsc) — @codragraph/cli imports it; without
|
|
8
9
|
* a populated dist/ here, step 3 fails to resolve types.
|
|
9
|
-
* 3. Build codragraph (tsc)
|
|
10
|
-
* 4. Copy
|
|
10
|
+
* 3. Build @codragraph/cli (tsc)
|
|
11
|
+
* 4. Copy packages/shared/dist → dist/_shared
|
|
11
12
|
* 5. Rewrite bare '@codragraph/shared' specifiers → relative paths
|
|
12
13
|
*/
|
|
13
14
|
import { execSync } from 'node:child_process';
|
|
@@ -35,20 +36,20 @@ execSync('npx tsc', { cwd: SHARED_ROOT, stdio: 'inherit' });
|
|
|
35
36
|
// `@codragraph/graphstore` imports. Skip gracefully if the workspace
|
|
36
37
|
// is not present (e.g. someone pinned an older monorepo layout).
|
|
37
38
|
if (fs.existsSync(GRAPHSTORE_ROOT)) {
|
|
38
|
-
console.log('[build] compiling codragraph
|
|
39
|
+
console.log('[build] compiling @codragraph/graphstore…');
|
|
39
40
|
execSync('npx tsc', { cwd: GRAPHSTORE_ROOT, stdio: 'inherit' });
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
// ── 3. Build codragraph
|
|
43
|
-
console.log('[build] compiling codragraph…');
|
|
43
|
+
// ── 3. Build @codragraph/cli ─────────────────────────────────────────
|
|
44
|
+
console.log('[build] compiling @codragraph/cli…');
|
|
44
45
|
execSync('npx tsc', { cwd: ROOT, stdio: 'inherit' });
|
|
45
46
|
|
|
46
|
-
// ──
|
|
47
|
+
// ── 4. Copy shared dist ────────────────────────────────────────────
|
|
47
48
|
console.log('[build] copying shared module into dist/_shared…');
|
|
48
49
|
fs.cpSync(path.join(SHARED_ROOT, 'dist'), SHARED_DEST, { recursive: true });
|
|
49
50
|
|
|
50
|
-
// ──
|
|
51
|
-
console.log('[build] rewriting codragraph
|
|
51
|
+
// ── 5. Rewrite imports ─────────────────────────────────────────────
|
|
52
|
+
console.log('[build] rewriting @codragraph/shared imports…');
|
|
52
53
|
let rewritten = 0;
|
|
53
54
|
|
|
54
55
|
function rewriteFile(filePath) {
|
|
@@ -82,7 +83,7 @@ function walk(dir, extensions, cb) {
|
|
|
82
83
|
|
|
83
84
|
walk(DIST, ['.js', '.d.ts'], rewriteFile);
|
|
84
85
|
|
|
85
|
-
// ──
|
|
86
|
+
// ── 6. Make CLI entry executable ────────────────────────────────────
|
|
86
87
|
const cliEntry = path.join(DIST, 'cli', 'index.js');
|
|
87
88
|
if (fs.existsSync(cliEntry)) fs.chmodSync(cliEntry, 0o755);
|
|
88
89
|
|
package/skills/codragraph-cli.md
CHANGED
|
@@ -5,7 +5,7 @@ description: "Use when the user needs to run CodraGraph CLI commands like analyz
|
|
|
5
5
|
|
|
6
6
|
# CodraGraph CLI Commands
|
|
7
7
|
|
|
8
|
-
All commands work via `npx` — no global install required.
|
|
8
|
+
All commands work via `npx` — no global install required. The examples are safe in Windows PowerShell, macOS bash/zsh, and Linux shells; prefer `npm --prefix <package> <script>` from the repo root when running package-local checks.
|
|
9
9
|
|
|
10
10
|
## Commands
|
|
11
11
|
|
|
@@ -32,6 +32,22 @@ npx @codragraph/cli status
|
|
|
32
32
|
|
|
33
33
|
Shows whether the current repo has a CodraGraph index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed.
|
|
34
34
|
|
|
35
|
+
### feature-clusters — List product/domain areas
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @codragraph/cli feature-clusters
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Shows the human-facing feature clusters CodraGraph detected: areas like Settings, Auth, AI, Billing, or Admin, with member counts and confidence. Use this before asking an agent to work on a product area.
|
|
42
|
+
|
|
43
|
+
### feature-context — Load one focused context pack
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx @codragraph/cli feature-context Settings
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Returns the members, file paths, line ranges, dependencies, and flows for one feature cluster so an agent can edit the right files without re-exploring the whole repo.
|
|
50
|
+
|
|
35
51
|
### clean — Delete the index
|
|
36
52
|
|
|
37
53
|
```bash
|
|
@@ -37,6 +37,8 @@ For any task involving code understanding, debugging, impact analysis, or refact
|
|
|
37
37
|
| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
|
|
38
38
|
| `detect_changes` | Git-diff impact — what do your current changes affect |
|
|
39
39
|
| `rename` | Multi-file coordinated rename with confidence-tagged edits |
|
|
40
|
+
| `feature_clusters` | Product/domain feature map for targeted context |
|
|
41
|
+
| `feature_context` | Members, line ranges, dependencies, and flows for one feature |
|
|
40
42
|
| `cypher` | Raw graph queries (read `codragraph://repo/{name}/schema` first) |
|
|
41
43
|
| `list_repos` | Discover indexed repos |
|
|
42
44
|
|
|
@@ -48,6 +50,8 @@ Lightweight reads (~100-500 tokens) for navigation:
|
|
|
48
50
|
| ---------------------------------------------- | ----------------------------------------- |
|
|
49
51
|
| `codragraph://repo/{name}/context` | Stats, staleness check |
|
|
50
52
|
| `codragraph://repo/{name}/clusters` | All functional areas with cohesion scores |
|
|
53
|
+
| `codragraph://repo/{name}/feature-clusters` | Product/domain feature areas |
|
|
54
|
+
| `codragraph://repo/{name}/feature/{featureName}` | Focused files, line ranges, flows, deps |
|
|
51
55
|
| `codragraph://repo/{name}/cluster/{clusterName}` | Area members |
|
|
52
56
|
| `codragraph://repo/{name}/processes` | All execution flows |
|
|
53
57
|
| `codragraph://repo/{name}/process/{processName}` | Step-by-step trace |
|
|
@@ -55,8 +59,8 @@ Lightweight reads (~100-500 tokens) for navigation:
|
|
|
55
59
|
|
|
56
60
|
## Graph Schema
|
|
57
61
|
|
|
58
|
-
**Nodes:** File, Function, Class, Interface, Method, Community, Process
|
|
59
|
-
**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS
|
|
62
|
+
**Nodes:** File, Function, Class, Interface, Method, Community, Process, FeatureCluster
|
|
63
|
+
**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS, FEATURE_MEMBER_OF, FEATURE_DEPENDS_ON
|
|
60
64
|
|
|
61
65
|
```cypher
|
|
62
66
|
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
|
|
@@ -89,7 +89,7 @@ running through it."
|
|
|
89
89
|
|
|
90
90
|
3. READ .claude/skills/generated/ingestion/SKILL.md
|
|
91
91
|
→ Entry points: runFullAnalysis, IngestionPipeline.run
|
|
92
|
-
→ Key files:
|
|
92
|
+
→ Key files: packages/core/src/core/ingestion/
|
|
93
93
|
|
|
94
94
|
4. READ codragraph://repo/CodraGraph/processes
|
|
95
95
|
→ Top flows: AnalyzeFlow, McpQueryFlow, GraphstoreCommitFlow
|
|
@@ -101,7 +101,7 @@ running through it."
|
|
|
101
101
|
→ orchestrator that takes (repoPath, options, hooks) and runs the pipeline.
|
|
102
102
|
→ Called by: analyzeCommand (CLI), eval-server, augment hook
|
|
103
103
|
|
|
104
|
-
Tour result: "Start at runFullAnalysis (
|
|
104
|
+
Tour result: "Start at runFullAnalysis (packages/core/src/core/run-analyze.ts).
|
|
105
105
|
That's the orchestrator. The 12-stage pipeline lives under
|
|
106
106
|
src/core/ingestion/. Phase 4 graphstore is in src/core/graphstore/."
|
|
107
107
|
```
|