@duytransipher/gitnexus 1.4.6-sipher.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.
- package/LICENSE +73 -0
- package/README.md +261 -0
- package/dist/cli/ai-context.d.ts +23 -0
- package/dist/cli/ai-context.js +265 -0
- package/dist/cli/analyze.d.ts +12 -0
- package/dist/cli/analyze.js +345 -0
- package/dist/cli/augment.d.ts +13 -0
- package/dist/cli/augment.js +33 -0
- package/dist/cli/clean.d.ts +10 -0
- package/dist/cli/clean.js +60 -0
- package/dist/cli/eval-server.d.ts +37 -0
- package/dist/cli/eval-server.js +389 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +137 -0
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +30 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +36 -0
- package/dist/cli/serve.d.ts +4 -0
- package/dist/cli/serve.js +6 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +367 -0
- package/dist/cli/sipher-patched.d.ts +2 -0
- package/dist/cli/sipher-patched.js +77 -0
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +549 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +36 -0
- package/dist/cli/tool.d.ts +60 -0
- package/dist/cli/tool.js +180 -0
- package/dist/cli/wiki.d.ts +15 -0
- package/dist/cli/wiki.js +365 -0
- package/dist/config/ignore-service.d.ts +26 -0
- package/dist/config/ignore-service.js +284 -0
- package/dist/config/supported-languages.d.ts +15 -0
- package/dist/config/supported-languages.js +16 -0
- package/dist/core/augmentation/engine.d.ts +26 -0
- package/dist/core/augmentation/engine.js +240 -0
- package/dist/core/embeddings/embedder.d.ts +60 -0
- package/dist/core/embeddings/embedder.js +251 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
- package/dist/core/embeddings/embedding-pipeline.js +356 -0
- package/dist/core/embeddings/index.d.ts +9 -0
- package/dist/core/embeddings/index.js +9 -0
- package/dist/core/embeddings/text-generator.d.ts +24 -0
- package/dist/core/embeddings/text-generator.js +182 -0
- package/dist/core/embeddings/types.d.ts +87 -0
- package/dist/core/embeddings/types.js +32 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +66 -0
- package/dist/core/graph/types.d.ts +66 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/ingestion/ast-cache.d.ts +11 -0
- package/dist/core/ingestion/ast-cache.js +35 -0
- package/dist/core/ingestion/call-processor.d.ts +23 -0
- package/dist/core/ingestion/call-processor.js +793 -0
- package/dist/core/ingestion/call-routing.d.ts +68 -0
- package/dist/core/ingestion/call-routing.js +129 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +170 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +312 -0
- package/dist/core/ingestion/constants.d.ts +16 -0
- package/dist/core/ingestion/constants.js +16 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +40 -0
- package/dist/core/ingestion/entry-point-scoring.js +353 -0
- package/dist/core/ingestion/export-detection.d.ts +18 -0
- package/dist/core/ingestion/export-detection.js +231 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
- package/dist/core/ingestion/filesystem-walker.js +81 -0
- package/dist/core/ingestion/framework-detection.d.ts +54 -0
- package/dist/core/ingestion/framework-detection.js +411 -0
- package/dist/core/ingestion/heritage-processor.d.ts +28 -0
- package/dist/core/ingestion/heritage-processor.js +251 -0
- package/dist/core/ingestion/import-processor.d.ts +34 -0
- package/dist/core/ingestion/import-processor.js +398 -0
- package/dist/core/ingestion/language-config.d.ts +46 -0
- package/dist/core/ingestion/language-config.js +167 -0
- package/dist/core/ingestion/mro-processor.d.ts +45 -0
- package/dist/core/ingestion/mro-processor.js +369 -0
- package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
- package/dist/core/ingestion/named-binding-extraction.js +363 -0
- package/dist/core/ingestion/parsing-processor.d.ts +19 -0
- package/dist/core/ingestion/parsing-processor.js +315 -0
- package/dist/core/ingestion/pipeline.d.ts +6 -0
- package/dist/core/ingestion/pipeline.js +401 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +315 -0
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
- package/dist/core/ingestion/resolvers/csharp.js +109 -0
- package/dist/core/ingestion/resolvers/go.d.ts +19 -0
- package/dist/core/ingestion/resolvers/go.js +42 -0
- package/dist/core/ingestion/resolvers/index.d.ts +18 -0
- package/dist/core/ingestion/resolvers/index.js +13 -0
- package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
- package/dist/core/ingestion/resolvers/jvm.js +87 -0
- package/dist/core/ingestion/resolvers/php.d.ts +15 -0
- package/dist/core/ingestion/resolvers/php.js +35 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
- package/dist/core/ingestion/resolvers/rust.js +73 -0
- package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
- package/dist/core/ingestion/resolvers/standard.js +123 -0
- package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
- package/dist/core/ingestion/resolvers/utils.js +122 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/symbol-table.d.ts +63 -0
- package/dist/core/ingestion/symbol-table.js +85 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +15 -0
- package/dist/core/ingestion/tree-sitter-queries.js +888 -0
- package/dist/core/ingestion/type-env.d.ts +49 -0
- package/dist/core/ingestion/type-env.js +613 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +383 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +467 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
- package/dist/core/ingestion/type-extractors/index.js +31 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +681 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +549 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +455 -0
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +456 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +145 -0
- package/dist/core/ingestion/type-extractors/shared.js +810 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +137 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
- package/dist/core/ingestion/type-extractors/types.js +1 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +494 -0
- package/dist/core/ingestion/utils.d.ts +138 -0
- package/dist/core/ingestion/utils.js +1290 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +122 -0
- package/dist/core/ingestion/workers/parse-worker.js +1126 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
- package/dist/core/ingestion/workers/worker-pool.js +128 -0
- package/dist/core/lbug/csv-generator.d.ts +33 -0
- package/dist/core/lbug/csv-generator.js +366 -0
- package/dist/core/lbug/lbug-adapter.d.ts +103 -0
- package/dist/core/lbug/lbug-adapter.js +769 -0
- package/dist/core/lbug/schema.d.ts +53 -0
- package/dist/core/lbug/schema.js +430 -0
- package/dist/core/search/bm25-index.d.ts +23 -0
- package/dist/core/search/bm25-index.js +96 -0
- package/dist/core/search/hybrid-search.d.ts +49 -0
- package/dist/core/search/hybrid-search.js +118 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +5 -0
- package/dist/core/tree-sitter/parser-loader.js +63 -0
- package/dist/core/wiki/generator.d.ts +120 -0
- package/dist/core/wiki/generator.js +939 -0
- package/dist/core/wiki/graph-queries.d.ts +80 -0
- package/dist/core/wiki/graph-queries.js +238 -0
- package/dist/core/wiki/html-viewer.d.ts +10 -0
- package/dist/core/wiki/html-viewer.js +297 -0
- package/dist/core/wiki/llm-client.d.ts +43 -0
- package/dist/core/wiki/llm-client.js +186 -0
- package/dist/core/wiki/prompts.d.ts +53 -0
- package/dist/core/wiki/prompts.js +174 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +200 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +108 -0
- package/dist/mcp/core/lbug-adapter.d.ts +57 -0
- package/dist/mcp/core/lbug-adapter.js +455 -0
- package/dist/mcp/local/local-backend.d.ts +181 -0
- package/dist/mcp/local/local-backend.js +1722 -0
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +411 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +296 -0
- package/dist/mcp/staleness.d.ts +15 -0
- package/dist/mcp/staleness.js +29 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.js +292 -0
- package/dist/server/api.d.ts +10 -0
- package/dist/server/api.js +344 -0
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +100 -0
- package/dist/storage/git.d.ts +6 -0
- package/dist/storage/git.js +35 -0
- package/dist/storage/repo-manager.d.ts +138 -0
- package/dist/storage/repo-manager.js +299 -0
- package/dist/types/pipeline.d.ts +32 -0
- package/dist/types/pipeline.js +18 -0
- package/dist/unreal/bridge.d.ts +4 -0
- package/dist/unreal/bridge.js +113 -0
- package/dist/unreal/config.d.ts +6 -0
- package/dist/unreal/config.js +55 -0
- package/dist/unreal/types.d.ts +105 -0
- package/dist/unreal/types.js +1 -0
- package/hooks/claude/gitnexus-hook.cjs +238 -0
- package/hooks/claude/pre-tool-use.sh +79 -0
- package/hooks/claude/session-start.sh +42 -0
- package/package.json +100 -0
- package/scripts/ensure-cli-executable.cjs +21 -0
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/scripts/setup-unreal-gitnexus.ps1 +191 -0
- package/skills/gitnexus-cli.md +82 -0
- package/skills/gitnexus-debugging.md +89 -0
- package/skills/gitnexus-exploring.md +78 -0
- package/skills/gitnexus-guide.md +64 -0
- package/skills/gitnexus-impact-analysis.md +97 -0
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/gitnexus-refactoring.md +121 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resources (Multi-Repo)
|
|
3
|
+
*
|
|
4
|
+
* Provides structured on-demand data to AI agents.
|
|
5
|
+
* All resources use repo-scoped URIs: gitnexus://repo/{name}/context
|
|
6
|
+
*/
|
|
7
|
+
import type { LocalBackend } from './local/local-backend.js';
|
|
8
|
+
export interface ResourceDefinition {
|
|
9
|
+
uri: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ResourceTemplate {
|
|
15
|
+
uriTemplate: string;
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
mimeType: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Static resources — includes per-repo resources and the global repos list
|
|
22
|
+
*/
|
|
23
|
+
export declare function getResourceDefinitions(): ResourceDefinition[];
|
|
24
|
+
/**
|
|
25
|
+
* Dynamic resource templates
|
|
26
|
+
*/
|
|
27
|
+
export declare function getResourceTemplates(): ResourceTemplate[];
|
|
28
|
+
/**
|
|
29
|
+
* Read a resource and return its content
|
|
30
|
+
*/
|
|
31
|
+
export declare function readResource(uri: string, backend: LocalBackend): Promise<string>;
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resources (Multi-Repo)
|
|
3
|
+
*
|
|
4
|
+
* Provides structured on-demand data to AI agents.
|
|
5
|
+
* All resources use repo-scoped URIs: gitnexus://repo/{name}/context
|
|
6
|
+
*/
|
|
7
|
+
import { checkStaleness } from './staleness.js';
|
|
8
|
+
/**
|
|
9
|
+
* Static resources — includes per-repo resources and the global repos list
|
|
10
|
+
*/
|
|
11
|
+
export function getResourceDefinitions() {
|
|
12
|
+
return [
|
|
13
|
+
{
|
|
14
|
+
uri: 'gitnexus://repos',
|
|
15
|
+
name: 'All Indexed Repositories',
|
|
16
|
+
description: 'List of all indexed repos with stats. Read this first to discover available repos.',
|
|
17
|
+
mimeType: 'text/yaml',
|
|
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
|
+
},
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Dynamic resource templates
|
|
29
|
+
*/
|
|
30
|
+
export function getResourceTemplates() {
|
|
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
|
+
},
|
|
56
|
+
{
|
|
57
|
+
uriTemplate: 'gitnexus://repo/{name}/cluster/{clusterName}',
|
|
58
|
+
name: 'Module Detail',
|
|
59
|
+
description: 'Deep dive into a specific functional area',
|
|
60
|
+
mimeType: 'text/yaml',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
uriTemplate: 'gitnexus://repo/{name}/process/{processName}',
|
|
64
|
+
name: 'Process Trace',
|
|
65
|
+
description: 'Step-by-step execution trace',
|
|
66
|
+
mimeType: 'text/yaml',
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse a resource URI to extract the repo name and resource type.
|
|
72
|
+
*/
|
|
73
|
+
function parseUri(uri) {
|
|
74
|
+
if (uri === 'gitnexus://repos')
|
|
75
|
+
return { resourceType: 'repos' };
|
|
76
|
+
if (uri === 'gitnexus://setup')
|
|
77
|
+
return { resourceType: 'setup' };
|
|
78
|
+
// Repo-scoped: gitnexus://repo/{name}/context
|
|
79
|
+
const repoMatch = uri.match(/^gitnexus:\/\/repo\/([^/]+)\/(.+)$/);
|
|
80
|
+
if (repoMatch) {
|
|
81
|
+
const repoName = decodeURIComponent(repoMatch[1]);
|
|
82
|
+
const rest = repoMatch[2];
|
|
83
|
+
if (rest.startsWith('cluster/')) {
|
|
84
|
+
return { repoName, resourceType: 'cluster', param: decodeURIComponent(rest.replace('cluster/', '')) };
|
|
85
|
+
}
|
|
86
|
+
if (rest.startsWith('process/')) {
|
|
87
|
+
return { repoName, resourceType: 'process', param: decodeURIComponent(rest.replace('process/', '')) };
|
|
88
|
+
}
|
|
89
|
+
return { repoName, resourceType: rest };
|
|
90
|
+
}
|
|
91
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Read a resource and return its content
|
|
95
|
+
*/
|
|
96
|
+
export async function readResource(uri, backend) {
|
|
97
|
+
const parsed = parseUri(uri);
|
|
98
|
+
// Global repos list — no repo context needed
|
|
99
|
+
if (parsed.resourceType === 'repos') {
|
|
100
|
+
return getReposResource(backend);
|
|
101
|
+
}
|
|
102
|
+
// Setup resource — returns AGENTS.md content for all repos
|
|
103
|
+
if (parsed.resourceType === 'setup') {
|
|
104
|
+
return getSetupResource(backend);
|
|
105
|
+
}
|
|
106
|
+
const repoName = parsed.repoName;
|
|
107
|
+
switch (parsed.resourceType) {
|
|
108
|
+
case 'context':
|
|
109
|
+
return getContextResource(backend, repoName);
|
|
110
|
+
case 'clusters':
|
|
111
|
+
return getClustersResource(backend, repoName);
|
|
112
|
+
case 'processes':
|
|
113
|
+
return getProcessesResource(backend, repoName);
|
|
114
|
+
case 'schema':
|
|
115
|
+
return getSchemaResource();
|
|
116
|
+
case 'cluster':
|
|
117
|
+
return getClusterDetailResource(parsed.param, backend, repoName);
|
|
118
|
+
case 'process':
|
|
119
|
+
return getProcessDetailResource(parsed.param, backend, repoName);
|
|
120
|
+
default:
|
|
121
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// ─── Resource Implementations ─────────────────────────────────────────
|
|
125
|
+
/**
|
|
126
|
+
* Repos resource — list all indexed repositories
|
|
127
|
+
*/
|
|
128
|
+
async function getReposResource(backend) {
|
|
129
|
+
const repos = await backend.listRepos();
|
|
130
|
+
if (repos.length === 0) {
|
|
131
|
+
return 'repos: []\n# No repositories indexed. Run: gitnexus analyze';
|
|
132
|
+
}
|
|
133
|
+
const lines = ['repos:'];
|
|
134
|
+
for (const repo of repos) {
|
|
135
|
+
lines.push(` - name: "${repo.name}"`);
|
|
136
|
+
lines.push(` path: "${repo.path}"`);
|
|
137
|
+
lines.push(` indexed: "${repo.indexedAt}"`);
|
|
138
|
+
lines.push(` commit: "${repo.lastCommit?.slice(0, 7) || 'unknown'}"`);
|
|
139
|
+
if (repo.stats) {
|
|
140
|
+
lines.push(` files: ${repo.stats.files || 0}`);
|
|
141
|
+
lines.push(` symbols: ${repo.stats.nodes || 0}`);
|
|
142
|
+
lines.push(` processes: ${repo.stats.processes || 0}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (repos.length > 1) {
|
|
146
|
+
lines.push('');
|
|
147
|
+
lines.push('# Multiple repos indexed. Use repo parameter in tool calls:');
|
|
148
|
+
lines.push(`# gitnexus_search({query: "auth", repo: "${repos[0].name}"})`);
|
|
149
|
+
}
|
|
150
|
+
return lines.join('\n');
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Context resource — codebase overview for a specific repo
|
|
154
|
+
*/
|
|
155
|
+
async function getContextResource(backend, repoName) {
|
|
156
|
+
// Resolve repo
|
|
157
|
+
const repo = await backend.resolveRepo(repoName);
|
|
158
|
+
const repoId = repo.name.toLowerCase();
|
|
159
|
+
const context = backend.getContext(repoId) || backend.getContext();
|
|
160
|
+
if (!context) {
|
|
161
|
+
return 'error: No codebase loaded. Run: gitnexus analyze';
|
|
162
|
+
}
|
|
163
|
+
// Check staleness
|
|
164
|
+
const repoPath = repo.repoPath;
|
|
165
|
+
const lastCommit = repo.lastCommit || 'HEAD';
|
|
166
|
+
const staleness = repoPath ? checkStaleness(repoPath, lastCommit) : { isStale: false, commitsBehind: 0 };
|
|
167
|
+
const lines = [
|
|
168
|
+
`project: ${context.projectName}`,
|
|
169
|
+
];
|
|
170
|
+
if (staleness.isStale && staleness.hint) {
|
|
171
|
+
lines.push('');
|
|
172
|
+
lines.push(`staleness: "${staleness.hint}"`);
|
|
173
|
+
}
|
|
174
|
+
lines.push('');
|
|
175
|
+
lines.push('stats:');
|
|
176
|
+
lines.push(` files: ${context.stats.fileCount}`);
|
|
177
|
+
lines.push(` symbols: ${context.stats.functionCount}`);
|
|
178
|
+
lines.push(` processes: ${context.stats.processCount}`);
|
|
179
|
+
lines.push('');
|
|
180
|
+
lines.push('tools_available:');
|
|
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');
|
|
186
|
+
lines.push(' - cypher: Raw graph queries');
|
|
187
|
+
lines.push(' - list_repos: Discover all indexed repositories');
|
|
188
|
+
lines.push('');
|
|
189
|
+
lines.push('re_index: Run `npx gitnexus analyze` in terminal if data is stale');
|
|
190
|
+
lines.push('');
|
|
191
|
+
lines.push('resources_available:');
|
|
192
|
+
lines.push(' - gitnexus://repos: All indexed repositories');
|
|
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`);
|
|
196
|
+
lines.push(` - gitnexus://repo/${context.projectName}/process/{name}: Process trace`);
|
|
197
|
+
return lines.join('\n');
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Clusters resource — queries graph directly via backend.queryClusters()
|
|
201
|
+
*/
|
|
202
|
+
async function getClustersResource(backend, repoName) {
|
|
203
|
+
try {
|
|
204
|
+
const result = await backend.queryClusters(repoName, 100);
|
|
205
|
+
if (!result.clusters || result.clusters.length === 0) {
|
|
206
|
+
return 'modules: []\n# No functional areas detected. Run: gitnexus analyze';
|
|
207
|
+
}
|
|
208
|
+
const displayLimit = 20;
|
|
209
|
+
const lines = ['modules:'];
|
|
210
|
+
const toShow = result.clusters.slice(0, displayLimit);
|
|
211
|
+
for (const cluster of toShow) {
|
|
212
|
+
const label = cluster.heuristicLabel || cluster.label || cluster.id;
|
|
213
|
+
lines.push(` - name: "${label}"`);
|
|
214
|
+
lines.push(` symbols: ${cluster.symbolCount || 0}`);
|
|
215
|
+
if (cluster.cohesion) {
|
|
216
|
+
lines.push(` cohesion: ${(cluster.cohesion * 100).toFixed(0)}%`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (result.clusters.length > displayLimit) {
|
|
220
|
+
lines.push(`\n# Showing top ${displayLimit} of ${result.clusters.length} modules. Use gitnexus_query for deeper search.`);
|
|
221
|
+
}
|
|
222
|
+
return lines.join('\n');
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
return `error: ${err.message}`;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Processes resource — queries graph directly via backend.queryProcesses()
|
|
230
|
+
*/
|
|
231
|
+
async function getProcessesResource(backend, repoName) {
|
|
232
|
+
try {
|
|
233
|
+
const result = await backend.queryProcesses(repoName, 50);
|
|
234
|
+
if (!result.processes || result.processes.length === 0) {
|
|
235
|
+
return 'processes: []\n# No processes detected. Run: gitnexus analyze';
|
|
236
|
+
}
|
|
237
|
+
const displayLimit = 20;
|
|
238
|
+
const lines = ['processes:'];
|
|
239
|
+
const toShow = result.processes.slice(0, displayLimit);
|
|
240
|
+
for (const proc of toShow) {
|
|
241
|
+
const label = proc.heuristicLabel || proc.label || proc.id;
|
|
242
|
+
lines.push(` - name: "${label}"`);
|
|
243
|
+
lines.push(` type: ${proc.processType || 'unknown'}`);
|
|
244
|
+
lines.push(` steps: ${proc.stepCount || 0}`);
|
|
245
|
+
}
|
|
246
|
+
if (result.processes.length > displayLimit) {
|
|
247
|
+
lines.push(`\n# Showing top ${displayLimit} of ${result.processes.length} processes. Use gitnexus_query for deeper search.`);
|
|
248
|
+
}
|
|
249
|
+
return lines.join('\n');
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
return `error: ${err.message}`;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Schema resource — graph structure for Cypher queries
|
|
257
|
+
*/
|
|
258
|
+
function getSchemaResource() {
|
|
259
|
+
return `# GitNexus Graph Schema
|
|
260
|
+
|
|
261
|
+
nodes:
|
|
262
|
+
- File: Source code files
|
|
263
|
+
- Folder: Directory containers
|
|
264
|
+
- Function: Functions and arrow functions
|
|
265
|
+
- Class: Class definitions
|
|
266
|
+
- Interface: Interface/type definitions
|
|
267
|
+
- Method: Class methods
|
|
268
|
+
- CodeElement: Catch-all for other code elements
|
|
269
|
+
- Community: Auto-detected functional area (Leiden algorithm)
|
|
270
|
+
- Process: Execution flow trace
|
|
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
|
+
|
|
274
|
+
relationships:
|
|
275
|
+
- CONTAINS: File/Folder contains child
|
|
276
|
+
- DEFINES: File defines a symbol
|
|
277
|
+
- CALLS: Function/method invocation
|
|
278
|
+
- IMPORTS: Module imports
|
|
279
|
+
- EXTENDS: Class inheritance
|
|
280
|
+
- IMPLEMENTS: Interface implementation
|
|
281
|
+
- HAS_METHOD: Class/Struct/Interface owns a Method
|
|
282
|
+
- HAS_PROPERTY: Class/Struct/Interface owns a Property (field)
|
|
283
|
+
- ACCESSES: Function/Method reads or writes a Property (reason: 'read' or 'write')
|
|
284
|
+
- OVERRIDES: Method overrides another Method (MRO)
|
|
285
|
+
- MEMBER_OF: Symbol belongs to community
|
|
286
|
+
- STEP_IN_PROCESS: Symbol is step N in process
|
|
287
|
+
|
|
288
|
+
relationship_table: "All relationships use a single CodeRelation table with a 'type' property. Properties: type (STRING), confidence (DOUBLE), reason (STRING), step (INT32)"
|
|
289
|
+
|
|
290
|
+
example_queries:
|
|
291
|
+
find_callers: |
|
|
292
|
+
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
|
|
293
|
+
RETURN caller.name, caller.filePath
|
|
294
|
+
|
|
295
|
+
find_community_members: |
|
|
296
|
+
MATCH (s)-[:CodeRelation {type: 'MEMBER_OF'}]->(c:Community)
|
|
297
|
+
WHERE c.heuristicLabel = "Auth"
|
|
298
|
+
RETURN s.name, labels(s)[0] AS type
|
|
299
|
+
|
|
300
|
+
trace_process: |
|
|
301
|
+
MATCH (s)-[r:CodeRelation {type: 'STEP_IN_PROCESS'}]->(p:Process)
|
|
302
|
+
WHERE p.heuristicLabel = "LoginFlow"
|
|
303
|
+
RETURN s.name, r.step
|
|
304
|
+
ORDER BY r.step
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Cluster detail resource — queries graph directly via backend.queryClusterDetail()
|
|
309
|
+
*/
|
|
310
|
+
async function getClusterDetailResource(name, backend, repoName) {
|
|
311
|
+
try {
|
|
312
|
+
const result = await backend.queryClusterDetail(name, repoName);
|
|
313
|
+
if (result.error) {
|
|
314
|
+
return `error: ${result.error}`;
|
|
315
|
+
}
|
|
316
|
+
const cluster = result.cluster;
|
|
317
|
+
const members = result.members || [];
|
|
318
|
+
const lines = [
|
|
319
|
+
`module: "${cluster.heuristicLabel || cluster.label || cluster.id}"`,
|
|
320
|
+
`symbols: ${cluster.symbolCount || members.length}`,
|
|
321
|
+
];
|
|
322
|
+
if (cluster.cohesion) {
|
|
323
|
+
lines.push(`cohesion: ${(cluster.cohesion * 100).toFixed(0)}%`);
|
|
324
|
+
}
|
|
325
|
+
if (members.length > 0) {
|
|
326
|
+
lines.push('');
|
|
327
|
+
lines.push('members:');
|
|
328
|
+
for (const member of members.slice(0, 20)) {
|
|
329
|
+
lines.push(` - name: ${member.name}`);
|
|
330
|
+
lines.push(` type: ${member.type}`);
|
|
331
|
+
lines.push(` file: ${member.filePath}`);
|
|
332
|
+
}
|
|
333
|
+
if (members.length > 20) {
|
|
334
|
+
lines.push(` # ... and ${members.length - 20} more`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return lines.join('\n');
|
|
338
|
+
}
|
|
339
|
+
catch (err) {
|
|
340
|
+
return `error: ${err.message}`;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Process detail resource — queries graph directly via backend.queryProcessDetail()
|
|
345
|
+
*/
|
|
346
|
+
async function getProcessDetailResource(name, backend, repoName) {
|
|
347
|
+
try {
|
|
348
|
+
const result = await backend.queryProcessDetail(name, repoName);
|
|
349
|
+
if (result.error) {
|
|
350
|
+
return `error: ${result.error}`;
|
|
351
|
+
}
|
|
352
|
+
const proc = result.process;
|
|
353
|
+
const steps = result.steps || [];
|
|
354
|
+
const lines = [
|
|
355
|
+
`name: "${proc.heuristicLabel || proc.label || proc.id}"`,
|
|
356
|
+
`type: ${proc.processType || 'unknown'}`,
|
|
357
|
+
`step_count: ${proc.stepCount || steps.length}`,
|
|
358
|
+
];
|
|
359
|
+
if (steps.length > 0) {
|
|
360
|
+
lines.push('');
|
|
361
|
+
lines.push('trace:');
|
|
362
|
+
for (const step of steps) {
|
|
363
|
+
lines.push(` ${step.step}: ${step.name} (${step.filePath})`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return lines.join('\n');
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
return `error: ${err.message}`;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Setup resource — generates AGENTS.md content for all indexed repos.
|
|
374
|
+
* Useful for `gitnexus setup` onboarding or dynamic content injection.
|
|
375
|
+
*/
|
|
376
|
+
async function getSetupResource(backend) {
|
|
377
|
+
const repos = await backend.listRepos();
|
|
378
|
+
if (repos.length === 0) {
|
|
379
|
+
return '# GitNexus\n\nNo repositories indexed. Run: `npx gitnexus analyze` in a repository.';
|
|
380
|
+
}
|
|
381
|
+
const sections = [];
|
|
382
|
+
for (const repo of repos) {
|
|
383
|
+
const stats = repo.stats || {};
|
|
384
|
+
const lines = [
|
|
385
|
+
`# GitNexus MCP — ${repo.name}`,
|
|
386
|
+
'',
|
|
387
|
+
`This project is indexed by GitNexus as **${repo.name}** (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows).`,
|
|
388
|
+
'',
|
|
389
|
+
'## Tools',
|
|
390
|
+
'',
|
|
391
|
+
'| Tool | What it gives you |',
|
|
392
|
+
'|------|-------------------|',
|
|
393
|
+
'| `query` | Process-grouped code intelligence — execution flows related to a concept |',
|
|
394
|
+
'| `context` | 360-degree symbol view — categorized refs, processes it participates in |',
|
|
395
|
+
'| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |',
|
|
396
|
+
'| `detect_changes` | Git-diff impact — what do your current changes affect |',
|
|
397
|
+
'| `rename` | Multi-file coordinated rename with confidence-tagged edits |',
|
|
398
|
+
'| `cypher` | Raw graph queries |',
|
|
399
|
+
'| `list_repos` | Discover indexed repos |',
|
|
400
|
+
'',
|
|
401
|
+
'## Resources',
|
|
402
|
+
'',
|
|
403
|
+
`- \`gitnexus://repo/${repo.name}/context\` — Stats, staleness check`,
|
|
404
|
+
`- \`gitnexus://repo/${repo.name}/clusters\` — All functional areas`,
|
|
405
|
+
`- \`gitnexus://repo/${repo.name}/processes\` — All execution flows`,
|
|
406
|
+
`- \`gitnexus://repo/${repo.name}/schema\` — Graph schema for Cypher`,
|
|
407
|
+
];
|
|
408
|
+
sections.push(lines.join('\n'));
|
|
409
|
+
}
|
|
410
|
+
return sections.join('\n\n---\n\n');
|
|
411
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server (Multi-Repo)
|
|
3
|
+
*
|
|
4
|
+
* Model Context Protocol server that runs on stdio.
|
|
5
|
+
* External AI tools (Cursor, Claude) spawn this process and
|
|
6
|
+
* communicate via stdin/stdout using the MCP protocol.
|
|
7
|
+
*
|
|
8
|
+
* Supports multiple indexed repositories via the global registry.
|
|
9
|
+
*
|
|
10
|
+
* Tools: list_repos, query, cypher, context, impact, detect_changes, rename
|
|
11
|
+
* Resources: repos, repo/{name}/context, repo/{name}/clusters, ...
|
|
12
|
+
*/
|
|
13
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
14
|
+
import type { LocalBackend } from './local/local-backend.js';
|
|
15
|
+
/**
|
|
16
|
+
* Create a configured MCP Server with all handlers registered.
|
|
17
|
+
* Transport-agnostic — caller connects the desired transport.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createMCPServer(backend: LocalBackend): Server;
|
|
20
|
+
/**
|
|
21
|
+
* Start the MCP server on stdio transport (for CLI use).
|
|
22
|
+
*/
|
|
23
|
+
export declare function startMCPServer(backend: LocalBackend): Promise<void>;
|