gitnexus 1.1.8 → 1.2.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 (76) hide show
  1. package/README.md +50 -59
  2. package/dist/cli/ai-context.js +9 -9
  3. package/dist/cli/analyze.js +139 -47
  4. package/dist/cli/augment.d.ts +13 -0
  5. package/dist/cli/augment.js +33 -0
  6. package/dist/cli/claude-hooks.d.ts +22 -0
  7. package/dist/cli/claude-hooks.js +97 -0
  8. package/dist/cli/eval-server.d.ts +30 -0
  9. package/dist/cli/eval-server.js +372 -0
  10. package/dist/cli/index.js +56 -1
  11. package/dist/cli/mcp.js +9 -0
  12. package/dist/cli/setup.js +184 -5
  13. package/dist/cli/tool.d.ts +37 -0
  14. package/dist/cli/tool.js +91 -0
  15. package/dist/cli/wiki.d.ts +13 -0
  16. package/dist/cli/wiki.js +199 -0
  17. package/dist/core/augmentation/engine.d.ts +26 -0
  18. package/dist/core/augmentation/engine.js +213 -0
  19. package/dist/core/embeddings/embedder.d.ts +2 -2
  20. package/dist/core/embeddings/embedder.js +11 -11
  21. package/dist/core/embeddings/embedding-pipeline.d.ts +2 -1
  22. package/dist/core/embeddings/embedding-pipeline.js +13 -5
  23. package/dist/core/embeddings/types.d.ts +2 -2
  24. package/dist/core/ingestion/call-processor.d.ts +7 -0
  25. package/dist/core/ingestion/call-processor.js +61 -23
  26. package/dist/core/ingestion/community-processor.js +34 -26
  27. package/dist/core/ingestion/filesystem-walker.js +15 -10
  28. package/dist/core/ingestion/heritage-processor.d.ts +6 -0
  29. package/dist/core/ingestion/heritage-processor.js +68 -5
  30. package/dist/core/ingestion/import-processor.d.ts +22 -0
  31. package/dist/core/ingestion/import-processor.js +215 -20
  32. package/dist/core/ingestion/parsing-processor.d.ts +8 -1
  33. package/dist/core/ingestion/parsing-processor.js +66 -25
  34. package/dist/core/ingestion/pipeline.js +104 -40
  35. package/dist/core/ingestion/process-processor.js +1 -1
  36. package/dist/core/ingestion/workers/parse-worker.d.ts +58 -0
  37. package/dist/core/ingestion/workers/parse-worker.js +451 -0
  38. package/dist/core/ingestion/workers/worker-pool.d.ts +22 -0
  39. package/dist/core/ingestion/workers/worker-pool.js +65 -0
  40. package/dist/core/kuzu/kuzu-adapter.d.ts +15 -1
  41. package/dist/core/kuzu/kuzu-adapter.js +177 -63
  42. package/dist/core/kuzu/schema.d.ts +1 -1
  43. package/dist/core/kuzu/schema.js +3 -0
  44. package/dist/core/search/bm25-index.js +13 -15
  45. package/dist/core/wiki/generator.d.ts +96 -0
  46. package/dist/core/wiki/generator.js +674 -0
  47. package/dist/core/wiki/graph-queries.d.ts +80 -0
  48. package/dist/core/wiki/graph-queries.js +238 -0
  49. package/dist/core/wiki/html-viewer.d.ts +10 -0
  50. package/dist/core/wiki/html-viewer.js +297 -0
  51. package/dist/core/wiki/llm-client.d.ts +36 -0
  52. package/dist/core/wiki/llm-client.js +111 -0
  53. package/dist/core/wiki/prompts.d.ts +53 -0
  54. package/dist/core/wiki/prompts.js +174 -0
  55. package/dist/mcp/core/embedder.js +4 -2
  56. package/dist/mcp/core/kuzu-adapter.d.ts +2 -1
  57. package/dist/mcp/core/kuzu-adapter.js +35 -15
  58. package/dist/mcp/local/local-backend.d.ts +54 -1
  59. package/dist/mcp/local/local-backend.js +716 -171
  60. package/dist/mcp/resources.d.ts +1 -1
  61. package/dist/mcp/resources.js +111 -73
  62. package/dist/mcp/server.d.ts +1 -1
  63. package/dist/mcp/server.js +91 -22
  64. package/dist/mcp/tools.js +80 -61
  65. package/dist/storage/git.d.ts +0 -1
  66. package/dist/storage/git.js +1 -8
  67. package/dist/storage/repo-manager.d.ts +17 -0
  68. package/dist/storage/repo-manager.js +26 -0
  69. package/hooks/claude/gitnexus-hook.cjs +135 -0
  70. package/hooks/claude/pre-tool-use.sh +78 -0
  71. package/hooks/claude/session-start.sh +42 -0
  72. package/package.json +4 -2
  73. package/skills/debugging.md +24 -22
  74. package/skills/exploring.md +26 -24
  75. package/skills/impact-analysis.md +19 -13
  76. package/skills/refactoring.md +37 -26
@@ -20,7 +20,7 @@ export interface ResourceTemplate {
20
20
  /**
21
21
  * Static resources — includes per-repo resources and the global repos list
22
22
  */
23
- export declare function getResourceDefinitions(backend: LocalBackend): ResourceDefinition[];
23
+ export declare function getResourceDefinitions(): ResourceDefinition[];
24
24
  /**
25
25
  * Dynamic resource templates
26
26
  */
@@ -8,54 +8,55 @@ import { checkStaleness } from './staleness.js';
8
8
  /**
9
9
  * Static resources — includes per-repo resources and the global repos list
10
10
  */
11
- export function getResourceDefinitions(backend) {
12
- const resources = [
11
+ export function getResourceDefinitions() {
12
+ return [
13
13
  {
14
14
  uri: 'gitnexus://repos',
15
15
  name: 'All Indexed Repositories',
16
16
  description: 'List of all indexed repos with stats. Read this first to discover available repos.',
17
17
  mimeType: 'text/yaml',
18
18
  },
19
+ {
20
+ uri: 'gitnexus://setup',
21
+ name: 'GitNexus Setup Content',
22
+ description: 'Returns AGENTS.md content for all indexed repos. Useful for setup/onboarding.',
23
+ mimeType: 'text/markdown',
24
+ },
19
25
  ];
20
- // Add per-repo context resources
21
- const repos = backend.listRepos();
22
- for (const repo of repos) {
23
- resources.push({
24
- uri: `gitnexus://repo/${repo.name}/context`,
25
- name: `${repo.name} Overview`,
26
- description: `Codebase stats and available tools for ${repo.name}`,
27
- mimeType: 'text/yaml',
28
- });
29
- resources.push({
30
- uri: `gitnexus://repo/${repo.name}/clusters`,
31
- name: `${repo.name} Clusters`,
32
- description: `All functional clusters for ${repo.name}`,
33
- mimeType: 'text/yaml',
34
- });
35
- resources.push({
36
- uri: `gitnexus://repo/${repo.name}/processes`,
37
- name: `${repo.name} Processes`,
38
- description: `All execution flows for ${repo.name}`,
39
- mimeType: 'text/yaml',
40
- });
41
- resources.push({
42
- uri: `gitnexus://repo/${repo.name}/schema`,
43
- name: `${repo.name} Schema`,
44
- description: `Graph schema for Cypher queries on ${repo.name}`,
45
- mimeType: 'text/yaml',
46
- });
47
- }
48
- return resources;
49
26
  }
50
27
  /**
51
28
  * Dynamic resource templates
52
29
  */
53
30
  export function getResourceTemplates() {
54
31
  return [
32
+ {
33
+ uriTemplate: 'gitnexus://repo/{name}/context',
34
+ name: 'Repo Overview',
35
+ description: 'Codebase stats, staleness check, and available tools',
36
+ mimeType: 'text/yaml',
37
+ },
38
+ {
39
+ uriTemplate: 'gitnexus://repo/{name}/clusters',
40
+ name: 'Repo Modules',
41
+ description: 'All functional areas (Leiden clusters)',
42
+ mimeType: 'text/yaml',
43
+ },
44
+ {
45
+ uriTemplate: 'gitnexus://repo/{name}/processes',
46
+ name: 'Repo Processes',
47
+ description: 'All execution flows',
48
+ mimeType: 'text/yaml',
49
+ },
50
+ {
51
+ uriTemplate: 'gitnexus://repo/{name}/schema',
52
+ name: 'Graph Schema',
53
+ description: 'Node/edge schema for Cypher queries',
54
+ mimeType: 'text/yaml',
55
+ },
55
56
  {
56
57
  uriTemplate: 'gitnexus://repo/{name}/cluster/{clusterName}',
57
- name: 'Cluster Detail',
58
- description: 'Deep dive into a specific cluster',
58
+ name: 'Module Detail',
59
+ description: 'Deep dive into a specific functional area',
59
60
  mimeType: 'text/yaml',
60
61
  },
61
62
  {
@@ -72,6 +73,8 @@ export function getResourceTemplates() {
72
73
  function parseUri(uri) {
73
74
  if (uri === 'gitnexus://repos')
74
75
  return { resourceType: 'repos' };
76
+ if (uri === 'gitnexus://setup')
77
+ return { resourceType: 'setup' };
75
78
  // Repo-scoped: gitnexus://repo/{name}/context
76
79
  const repoMatch = uri.match(/^gitnexus:\/\/repo\/([^/]+)\/(.+)$/);
77
80
  if (repoMatch) {
@@ -96,6 +99,10 @@ export async function readResource(uri, backend) {
96
99
  if (parsed.resourceType === 'repos') {
97
100
  return getReposResource(backend);
98
101
  }
102
+ // Setup resource — returns AGENTS.md content for all repos
103
+ if (parsed.resourceType === 'setup') {
104
+ return getSetupResource(backend);
105
+ }
99
106
  const repoName = parsed.repoName;
100
107
  switch (parsed.resourceType) {
101
108
  case 'context':
@@ -157,15 +164,6 @@ async function getContextResource(backend, repoName) {
157
164
  const repoPath = repo.repoPath;
158
165
  const lastCommit = repo.lastCommit || 'HEAD';
159
166
  const staleness = repoPath ? checkStaleness(repoPath, lastCommit) : { isStale: false, commitsBehind: 0 };
160
- // Get aggregated cluster count (matches what overview/clusters resource shows)
161
- let clusterCount = context.stats.communityCount;
162
- try {
163
- const overview = await backend.callTool('overview', { showClusters: true, showProcesses: false, limit: 100, repo: repoName });
164
- if (overview.clusters) {
165
- clusterCount = overview.clusters.length;
166
- }
167
- }
168
- catch { /* fall back to raw count */ }
169
167
  const lines = [
170
168
  `project: ${context.projectName}`,
171
169
  ];
@@ -177,39 +175,38 @@ async function getContextResource(backend, repoName) {
177
175
  lines.push('stats:');
178
176
  lines.push(` files: ${context.stats.fileCount}`);
179
177
  lines.push(` symbols: ${context.stats.functionCount}`);
180
- lines.push(` clusters: ${clusterCount}`);
181
178
  lines.push(` processes: ${context.stats.processCount}`);
182
179
  lines.push('');
183
180
  lines.push('tools_available:');
184
- lines.push(' - list_repos: Discover all indexed repositories');
185
- lines.push(' - search: Hybrid semantic + keyword search');
186
- lines.push(' - explore: Deep dive on symbol/cluster/process');
187
- lines.push(' - impact: Blast radius analysis');
188
- lines.push(' - overview: List all clusters and processes');
181
+ lines.push(' - query: Process-grouped code intelligence (execution flows related to a concept)');
182
+ lines.push(' - context: 360-degree symbol view (categorized refs, process participation)');
183
+ lines.push(' - impact: Blast radius analysis (what breaks if you change a symbol)');
184
+ lines.push(' - detect_changes: Git-diff impact analysis (what do your changes affect)');
185
+ lines.push(' - rename: Multi-file coordinated rename with confidence tags');
189
186
  lines.push(' - cypher: Raw graph queries');
187
+ lines.push(' - list_repos: Discover all indexed repositories');
190
188
  lines.push('');
191
189
  lines.push('re_index: Run `npx gitnexus analyze` in terminal if data is stale');
192
190
  lines.push('');
193
191
  lines.push('resources_available:');
194
192
  lines.push(' - gitnexus://repos: All indexed repositories');
195
- lines.push(` - gitnexus://repo/${context.projectName}/clusters: All clusters`);
196
- lines.push(` - gitnexus://repo/${context.projectName}/processes: All processes`);
197
- lines.push(` - gitnexus://repo/${context.projectName}/cluster/{name}: Cluster details`);
193
+ lines.push(` - gitnexus://repo/${context.projectName}/clusters: All functional areas`);
194
+ lines.push(` - gitnexus://repo/${context.projectName}/processes: All execution flows`);
195
+ lines.push(` - gitnexus://repo/${context.projectName}/cluster/{name}: Module details`);
198
196
  lines.push(` - gitnexus://repo/${context.projectName}/process/{name}: Process trace`);
199
197
  return lines.join('\n');
200
198
  }
201
199
  /**
202
- * Clusters resource
200
+ * Clusters resource — queries graph directly via backend.queryClusters()
203
201
  */
204
202
  async function getClustersResource(backend, repoName) {
205
203
  try {
206
- // Request more than we display so aggregation has enough raw data
207
- const result = await backend.callTool('overview', { showClusters: true, showProcesses: false, limit: 100, repo: repoName });
204
+ const result = await backend.queryClusters(repoName, 100);
208
205
  if (!result.clusters || result.clusters.length === 0) {
209
- return 'clusters: []\n# No clusters detected. Run: gitnexus analyze';
206
+ return 'modules: []\n# No functional areas detected. Run: gitnexus analyze';
210
207
  }
211
208
  const displayLimit = 20;
212
- const lines = ['clusters:'];
209
+ const lines = ['modules:'];
213
210
  const toShow = result.clusters.slice(0, displayLimit);
214
211
  for (const cluster of toShow) {
215
212
  const label = cluster.heuristicLabel || cluster.label || cluster.id;
@@ -218,12 +215,9 @@ async function getClustersResource(backend, repoName) {
218
215
  if (cluster.cohesion) {
219
216
  lines.push(` cohesion: ${(cluster.cohesion * 100).toFixed(0)}%`);
220
217
  }
221
- if (cluster.subCommunities && cluster.subCommunities > 1) {
222
- lines.push(` sub_clusters: ${cluster.subCommunities}`);
223
- }
224
218
  }
225
219
  if (result.clusters.length > displayLimit) {
226
- lines.push(`\n# Showing top ${displayLimit} of ${result.clusters.length} clusters. Use gitnexus_search or gitnexus_explore for more.`);
220
+ lines.push(`\n# Showing top ${displayLimit} of ${result.clusters.length} modules. Use gitnexus_query for deeper search.`);
227
221
  }
228
222
  return lines.join('\n');
229
223
  }
@@ -232,11 +226,11 @@ async function getClustersResource(backend, repoName) {
232
226
  }
233
227
  }
234
228
  /**
235
- * Processes resource
229
+ * Processes resource — queries graph directly via backend.queryProcesses()
236
230
  */
237
231
  async function getProcessesResource(backend, repoName) {
238
232
  try {
239
- const result = await backend.callTool('overview', { showClusters: false, showProcesses: true, limit: 50, repo: repoName });
233
+ const result = await backend.queryProcesses(repoName, 50);
240
234
  if (!result.processes || result.processes.length === 0) {
241
235
  return 'processes: []\n# No processes detected. Run: gitnexus analyze';
242
236
  }
@@ -250,7 +244,7 @@ async function getProcessesResource(backend, repoName) {
250
244
  lines.push(` steps: ${proc.stepCount || 0}`);
251
245
  }
252
246
  if (result.processes.length > displayLimit) {
253
- lines.push(`\n# Showing top ${displayLimit} of ${result.processes.length} processes. Use gitnexus_explore for more.`);
247
+ lines.push(`\n# Showing top ${displayLimit} of ${result.processes.length} processes. Use gitnexus_query for deeper search.`);
254
248
  }
255
249
  return lines.join('\n');
256
250
  }
@@ -266,22 +260,29 @@ function getSchemaResource() {
266
260
 
267
261
  nodes:
268
262
  - File: Source code files
263
+ - Folder: Directory containers
269
264
  - Function: Functions and arrow functions
270
265
  - Class: Class definitions
271
266
  - Interface: Interface/type definitions
272
267
  - Method: Class methods
273
- - Community: Functional cluster (Leiden algorithm)
268
+ - CodeElement: Catch-all for other code elements
269
+ - Community: Auto-detected functional area (Leiden algorithm)
274
270
  - Process: Execution flow trace
275
271
 
272
+ additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Namespace, Trait, Impl, TypeAlias, Const, Static, Property, Record, Delegate, Annotation, Constructor, Template, Module (use backticks in queries: \`Struct\`, \`Enum\`, etc.)"
273
+
276
274
  relationships:
275
+ - CONTAINS: File/Folder contains child
276
+ - DEFINES: File defines a symbol
277
277
  - CALLS: Function/method invocation
278
278
  - IMPORTS: Module imports
279
279
  - EXTENDS: Class inheritance
280
280
  - IMPLEMENTS: Interface implementation
281
- - DEFINES: File defines symbol
282
281
  - MEMBER_OF: Symbol belongs to community
283
282
  - STEP_IN_PROCESS: Symbol is step N in process
284
283
 
284
+ relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
285
+
285
286
  example_queries:
286
287
  find_callers: |
287
288
  MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
@@ -300,26 +301,23 @@ example_queries:
300
301
  `;
301
302
  }
302
303
  /**
303
- * Cluster detail resource
304
+ * Cluster detail resource — queries graph directly via backend.queryClusterDetail()
304
305
  */
305
306
  async function getClusterDetailResource(name, backend, repoName) {
306
307
  try {
307
- const result = await backend.callTool('explore', { name, type: 'cluster', repo: repoName });
308
+ const result = await backend.queryClusterDetail(name, repoName);
308
309
  if (result.error) {
309
310
  return `error: ${result.error}`;
310
311
  }
311
312
  const cluster = result.cluster;
312
313
  const members = result.members || [];
313
314
  const lines = [
314
- `name: "${cluster.heuristicLabel || cluster.label || cluster.id}"`,
315
+ `module: "${cluster.heuristicLabel || cluster.label || cluster.id}"`,
315
316
  `symbols: ${cluster.symbolCount || members.length}`,
316
317
  ];
317
318
  if (cluster.cohesion) {
318
319
  lines.push(`cohesion: ${(cluster.cohesion * 100).toFixed(0)}%`);
319
320
  }
320
- if (cluster.subCommunities && cluster.subCommunities > 1) {
321
- lines.push(`sub_clusters: ${cluster.subCommunities}`);
322
- }
323
321
  if (members.length > 0) {
324
322
  lines.push('');
325
323
  lines.push('members:');
@@ -339,11 +337,11 @@ async function getClusterDetailResource(name, backend, repoName) {
339
337
  }
340
338
  }
341
339
  /**
342
- * Process detail resource
340
+ * Process detail resource — queries graph directly via backend.queryProcessDetail()
343
341
  */
344
342
  async function getProcessDetailResource(name, backend, repoName) {
345
343
  try {
346
- const result = await backend.callTool('explore', { name, type: 'process', repo: repoName });
344
+ const result = await backend.queryProcessDetail(name, repoName);
347
345
  if (result.error) {
348
346
  return `error: ${result.error}`;
349
347
  }
@@ -367,3 +365,43 @@ async function getProcessDetailResource(name, backend, repoName) {
367
365
  return `error: ${err.message}`;
368
366
  }
369
367
  }
368
+ /**
369
+ * Setup resource — generates AGENTS.md content for all indexed repos.
370
+ * Useful for `gitnexus setup` onboarding or dynamic content injection.
371
+ */
372
+ async function getSetupResource(backend) {
373
+ const repos = backend.listRepos();
374
+ if (repos.length === 0) {
375
+ return '# GitNexus\n\nNo repositories indexed. Run: `npx gitnexus analyze` in a repository.';
376
+ }
377
+ const sections = [];
378
+ for (const repo of repos) {
379
+ const stats = repo.stats || {};
380
+ const lines = [
381
+ `# GitNexus MCP — ${repo.name}`,
382
+ '',
383
+ `This project is indexed by GitNexus as **${repo.name}** (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows).`,
384
+ '',
385
+ '## Tools',
386
+ '',
387
+ '| Tool | What it gives you |',
388
+ '|------|-------------------|',
389
+ '| `query` | Process-grouped code intelligence — execution flows related to a concept |',
390
+ '| `context` | 360-degree symbol view — categorized refs, processes it participates in |',
391
+ '| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |',
392
+ '| `detect_changes` | Git-diff impact — what do your current changes affect |',
393
+ '| `rename` | Multi-file coordinated rename with confidence-tagged edits |',
394
+ '| `cypher` | Raw graph queries |',
395
+ '| `list_repos` | Discover indexed repos |',
396
+ '',
397
+ '## Resources',
398
+ '',
399
+ `- \`gitnexus://repo/${repo.name}/context\` — Stats, staleness check`,
400
+ `- \`gitnexus://repo/${repo.name}/clusters\` — All functional areas`,
401
+ `- \`gitnexus://repo/${repo.name}/processes\` — All execution flows`,
402
+ `- \`gitnexus://repo/${repo.name}/schema\` — Graph schema for Cypher`,
403
+ ];
404
+ sections.push(lines.join('\n'));
405
+ }
406
+ return sections.join('\n\n---\n\n');
407
+ }
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Supports multiple indexed repositories via the global registry.
9
9
  *
10
- * Tools: list_repos, search, cypher, overview, explore, impact, analyze
10
+ * Tools: list_repos, query, cypher, context, impact, detect_changes, rename
11
11
  * Resources: repos, repo/{name}/context, repo/{name}/clusters, ...
12
12
  */
13
13
  import type { LocalBackend } from './local/local-backend.js';
@@ -7,12 +7,12 @@
7
7
  *
8
8
  * Supports multiple indexed repositories via the global registry.
9
9
  *
10
- * Tools: list_repos, search, cypher, overview, explore, impact, analyze
10
+ * Tools: list_repos, query, cypher, context, impact, detect_changes, rename
11
11
  * Resources: repos, repo/{name}/context, repo/{name}/clusters, ...
12
12
  */
13
13
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
14
14
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
15
- import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
15
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
16
16
  import { GITNEXUS_TOOLS } from './tools.js';
17
17
  import { getResourceDefinitions, getResourceTemplates, readResource } from './resources.js';
18
18
  /**
@@ -31,27 +31,25 @@ function getNextStepHint(toolName, args) {
31
31
  switch (toolName) {
32
32
  case 'list_repos':
33
33
  return `\n\n---\n**Next:** READ gitnexus://repo/{name}/context for any repo above to get its overview and check staleness.`;
34
- case 'search':
35
- return `\n\n---\n**Next:** To understand a result in context, use explore({name: "<symbol_name>", type: "symbol"${repoParam}}) to see its callers, callees, and cluster membership.`;
36
- case 'explore': {
37
- const exploreType = args?.type || 'symbol';
38
- if (exploreType === 'symbol') {
39
- return `\n\n---\n**Next:** If planning changes, use impact({target: "${args?.name || '<name>'}", direction: "upstream"${repoParam}}) to check blast radius. To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
40
- }
41
- if (exploreType === 'cluster') {
42
- return `\n\n---\n**Next:** To drill into a specific symbol, use explore({name: "<symbol_name>", type: "symbol"${repoParam}}). To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
43
- }
44
- if (exploreType === 'process') {
45
- return `\n\n---\n**Next:** To explore any step in detail, use explore({name: "<step_name>", type: "symbol"${repoParam}}).`;
46
- }
47
- return '';
48
- }
49
- case 'overview':
50
- return `\n\n---\n**Next:** To drill into a cluster, READ gitnexus://repo/${repoPath}/cluster/{name} or use explore({name: "<cluster_name>", type: "cluster"${repoParam}}).`;
34
+ case 'query':
35
+ return `\n\n---\n**Next:** To understand a specific symbol in depth, use context({name: "<symbol_name>"${repoParam}}) to see categorized refs and process participation.`;
36
+ case 'context':
37
+ return `\n\n---\n**Next:** If planning changes, use impact({target: "${args?.name || '<name>'}", direction: "upstream"${repoParam}}) to check blast radius. To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
51
38
  case 'impact':
52
39
  return `\n\n---\n**Next:** Review d=1 items first (WILL BREAK). To check affected execution flows, READ gitnexus://repo/${repoPath}/processes.`;
40
+ case 'detect_changes':
41
+ return `\n\n---\n**Next:** Review affected processes. Use context() on high-risk changed symbols. READ gitnexus://repo/${repoPath}/process/{name} for full execution traces.`;
42
+ case 'rename':
43
+ return `\n\n---\n**Next:** Run detect_changes(${repoParam ? `{repo: "${repo}"}` : ''}) to verify no unexpected side effects from the rename.`;
53
44
  case 'cypher':
54
- return `\n\n---\n**Next:** To explore a result symbol, use explore({name: "<name>", type: "symbol"${repoParam}}). For schema reference, READ gitnexus://repo/${repoPath}/schema.`;
45
+ return `\n\n---\n**Next:** To explore a result symbol, use context({name: "<name>"${repoParam}}). For schema reference, READ gitnexus://repo/${repoPath}/schema.`;
46
+ // Legacy tool names — still return useful hints
47
+ case 'search':
48
+ return `\n\n---\n**Next:** To understand a result in context, use context({name: "<symbol_name>"${repoParam}}).`;
49
+ case 'explore':
50
+ return `\n\n---\n**Next:** If planning changes, use impact({target: "<name>", direction: "upstream"${repoParam}}).`;
51
+ case 'overview':
52
+ return `\n\n---\n**Next:** To drill into an area, READ gitnexus://repo/${repoPath}/cluster/{name}. To see execution flows, READ gitnexus://repo/${repoPath}/processes.`;
55
53
  default:
56
54
  return '';
57
55
  }
@@ -59,16 +57,17 @@ function getNextStepHint(toolName, args) {
59
57
  export async function startMCPServer(backend) {
60
58
  const server = new Server({
61
59
  name: 'gitnexus',
62
- version: '1.1.0',
60
+ version: '1.1.9',
63
61
  }, {
64
62
  capabilities: {
65
63
  tools: {},
66
64
  resources: {},
65
+ prompts: {},
67
66
  },
68
67
  });
69
68
  // Handle list resources request
70
69
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
71
- const resources = getResourceDefinitions(backend);
70
+ const resources = getResourceDefinitions();
72
71
  return {
73
72
  resources: resources.map(r => ({
74
73
  uri: r.uri,
@@ -154,6 +153,76 @@ export async function startMCPServer(backend) {
154
153
  };
155
154
  }
156
155
  });
156
+ // Handle list prompts request
157
+ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
158
+ prompts: [
159
+ {
160
+ name: 'detect_impact',
161
+ description: 'Analyze the impact of your current changes before committing. Guides through scope selection, change detection, process analysis, and risk assessment.',
162
+ arguments: [
163
+ { name: 'scope', description: 'What to analyze: unstaged, staged, all, or compare', required: false },
164
+ { name: 'base_ref', description: 'Branch/commit for compare scope', required: false },
165
+ ],
166
+ },
167
+ {
168
+ name: 'generate_map',
169
+ description: 'Generate architecture documentation from the knowledge graph. Creates a codebase overview with execution flows and mermaid diagrams.',
170
+ arguments: [
171
+ { name: 'repo', description: 'Repository name (omit if only one indexed)', required: false },
172
+ ],
173
+ },
174
+ ],
175
+ }));
176
+ // Handle get prompt request
177
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
178
+ const { name, arguments: args } = request.params;
179
+ if (name === 'detect_impact') {
180
+ const scope = args?.scope || 'all';
181
+ const baseRef = args?.base_ref || '';
182
+ return {
183
+ messages: [
184
+ {
185
+ role: 'user',
186
+ content: {
187
+ type: 'text',
188
+ text: `Analyze the impact of my current code changes before committing.
189
+
190
+ Follow these steps:
191
+ 1. Run \`detect_changes(${JSON.stringify({ scope, ...(baseRef ? { base_ref: baseRef } : {}) })})\` to find what changed and affected processes
192
+ 2. For each changed symbol in critical processes, run \`context({name: "<symbol>"})\` to see its full reference graph
193
+ 3. For any high-risk items (many callers or cross-process), run \`impact({target: "<symbol>", direction: "upstream"})\` for blast radius
194
+ 4. Summarize: changes, affected processes, risk level, and recommended actions
195
+
196
+ Present the analysis as a clear risk report.`,
197
+ },
198
+ },
199
+ ],
200
+ };
201
+ }
202
+ if (name === 'generate_map') {
203
+ const repo = args?.repo || '';
204
+ return {
205
+ messages: [
206
+ {
207
+ role: 'user',
208
+ content: {
209
+ type: 'text',
210
+ text: `Generate architecture documentation for this codebase using the knowledge graph.
211
+
212
+ Follow these steps:
213
+ 1. READ \`gitnexus://repo/${repo || '{name}'}/context\` for codebase stats
214
+ 2. READ \`gitnexus://repo/${repo || '{name}'}/clusters\` to see all functional areas
215
+ 3. READ \`gitnexus://repo/${repo || '{name}'}/processes\` to see all execution flows
216
+ 4. For the top 5 most important processes, READ \`gitnexus://repo/${repo || '{name}'}/process/{name}\` for step-by-step traces
217
+ 5. Generate a mermaid architecture diagram showing the major areas and their connections
218
+ 6. Write an ARCHITECTURE.md file with: overview, functional areas, key execution flows, and the mermaid diagram`,
219
+ },
220
+ },
221
+ ],
222
+ };
223
+ }
224
+ throw new Error(`Unknown prompt: ${name}`);
225
+ });
157
226
  // Connect to stdio transport
158
227
  const transport = new StdioServerTransport();
159
228
  await server.connect(transport);