gitnexus 1.0.0 → 1.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 CHANGED
@@ -13,41 +13,46 @@ Works with **Cursor**, **Claude Code**, **Windsurf**, **Cline**, **OpenCode**, a
13
13
 
14
14
  AI coding tools don't understand your codebase structure. They edit a function without knowing 47 other functions depend on it. GitNexus fixes this by **precomputing every dependency, call chain, and relationship** into a queryable graph.
15
15
 
16
- **One command to index. One MCP connection to give your AI agent full codebase awareness.**
16
+ **Three commands to give your AI agent full codebase awareness.**
17
17
 
18
18
  ## Quick Start
19
19
 
20
20
  ```bash
21
- # Index your repository
22
- npx gitnexus analyze
21
+ # Install
22
+ npm install -g gitnexus
23
+
24
+ # One-time: configure MCP for your editors
25
+ gitnexus setup
26
+
27
+ # Index your repository (run from repo root)
28
+ gitnexus analyze
23
29
 
24
- # Start MCP server (for Cursor, Claude Code, etc.)
25
- npx gitnexus mcp
30
+ # Done! Open your editor MCP connects automatically.
26
31
  ```
27
32
 
28
- Or install globally:
33
+ Or without installing globally:
29
34
 
30
35
  ```bash
31
- npm install -g gitnexus
32
- gitnexus analyze
33
- gitnexus mcp
36
+ npx gitnexus setup # one-time
37
+ npx gitnexus analyze # per repo
34
38
  ```
35
39
 
36
- ## MCP Setup
40
+ The `setup` command auto-detects Cursor, Claude Code, and OpenCode, then writes the correct global MCP config. You only run it once.
41
+
42
+ ## MCP Setup (manual)
43
+
44
+ If you prefer to configure manually instead of using `gitnexus setup`:
37
45
 
38
46
  ### Cursor / Windsurf
39
47
 
40
- Add to your MCP config (`.cursor/mcp.json` or equivalent):
48
+ Add to `~/.cursor/mcp.json` (global — works for all projects):
41
49
 
42
50
  ```json
43
51
  {
44
52
  "mcpServers": {
45
53
  "gitnexus": {
46
54
  "command": "npx",
47
- "args": ["-y", "gitnexus", "mcp"],
48
- "env": {
49
- "GITNEXUS_CWD": "/path/to/your/repo"
50
- }
55
+ "args": ["-y", "gitnexus", "mcp"]
51
56
  }
52
57
  }
53
58
  }
@@ -61,7 +66,7 @@ claude mcp add gitnexus -- npx -y gitnexus mcp
61
66
 
62
67
  ### OpenCode
63
68
 
64
- Add to your `opencode.json`:
69
+ Add to `~/.config/opencode/config.json`:
65
70
 
66
71
  ```json
67
72
  {
@@ -92,39 +97,48 @@ The result is a **KuzuDB graph database** stored locally in `.gitnexus/` with fu
92
97
 
93
98
  Your AI agent gets these tools automatically:
94
99
 
95
- | Tool | What It Does | Example |
96
- |------|-------------|---------|
97
- | `search` | Hybrid search (BM25 + semantic) with cluster context | "Find authentication logic" |
98
- | `overview` | List all clusters and processes | "Show me the codebase structure" |
99
- | `explore` | Deep dive on a symbol, cluster, or process | "Tell me about UserService" |
100
- | `impact` | Blast radius analysis | "What breaks if I change validateUser?" |
101
- | `cypher` | Raw Cypher graph queries | Complex relationship queries |
102
- | `read` | Smart file reader with fuzzy path matching | Read specific files |
103
- | `grep` | Regex pattern search | Find TODOs, error codes |
100
+ | Tool | What It Does | `repo` Param |
101
+ |------|-------------|--------------|
102
+ | `list_repos` | Discover all indexed repositories | |
103
+ | `search` | Hybrid search (BM25 + semantic) with cluster context | Optional |
104
+ | `overview` | List all clusters and processes | Optional |
105
+ | `explore` | Deep dive on a symbol, cluster, or process | Optional |
106
+ | `impact` | Blast radius analysis | Optional |
107
+ | `cypher` | Raw Cypher graph queries | Optional |
108
+ | `analyze` | Index or re-index a repository | Optional |
109
+
110
+ > With one indexed repo, the `repo` param is optional. With multiple, specify which: `search({query: "auth", repo: "my-app"})`.
104
111
 
105
112
  ## MCP Resources
106
113
 
107
114
  | Resource | Purpose |
108
115
  |----------|---------|
109
- | `gitnexus://context` | Codebase stats and overview |
110
- | `gitnexus://clusters` | All functional clusters |
111
- | `gitnexus://cluster/{name}` | Cluster members and details |
112
- | `gitnexus://processes` | All execution flows |
113
- | `gitnexus://process/{name}` | Full process trace |
114
- | `gitnexus://schema` | Graph schema for Cypher queries |
116
+ | `gitnexus://repos` | List all indexed repositories (read first) |
117
+ | `gitnexus://repo/{name}/context` | Codebase stats and overview |
118
+ | `gitnexus://repo/{name}/clusters` | All functional clusters |
119
+ | `gitnexus://repo/{name}/cluster/{name}` | Cluster members and details |
120
+ | `gitnexus://repo/{name}/processes` | All execution flows |
121
+ | `gitnexus://repo/{name}/process/{name}` | Full process trace |
122
+ | `gitnexus://repo/{name}/schema` | Graph schema for Cypher queries |
115
123
 
116
124
  ## CLI Commands
117
125
 
118
126
  ```bash
119
- gitnexus analyze [path] # Index a repository (or update stale index)
120
- gitnexus analyze --force # Force full re-index
121
- gitnexus mcp # Start MCP server (stdio)
122
- gitnexus serve # Start HTTP server for web UI
123
- gitnexus list # List all indexed repositories
124
- gitnexus status # Show index status for current repo
125
- gitnexus clean # Delete index for current repo
127
+ gitnexus setup # Configure MCP for your editors (one-time)
128
+ gitnexus analyze [path] # Index a repository (or update stale index)
129
+ gitnexus analyze --force # Force full re-index
130
+ gitnexus mcp # Start MCP server (stdio) serves all indexed repos
131
+ gitnexus serve # Start HTTP server for web UI
132
+ gitnexus list # List all indexed repositories
133
+ gitnexus status # Show index status for current repo
134
+ gitnexus clean # Delete index for current repo
135
+ gitnexus clean --all # Delete all indexes
126
136
  ```
127
137
 
138
+ ## Multi-Repo Support
139
+
140
+ GitNexus supports indexing multiple repositories. Each `gitnexus analyze` registers the repo in a global registry (`~/.gitnexus/registry.json`). The MCP server serves all indexed repos automatically with lazy KuzuDB connections.
141
+
128
142
  ## Supported Languages
129
143
 
130
144
  TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust
@@ -132,7 +146,7 @@ TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust
132
146
  ## How Impact Analysis Works
133
147
 
134
148
  ```
135
- gitnexus_impact("UserService", "upstream")
149
+ gitnexus_impact({target: "UserService", direction: "upstream", repo: "my-app"})
136
150
 
137
151
  TARGET: Class UserService (src/services/user.ts)
138
152
 
@@ -169,6 +183,7 @@ These are installed automatically to `.claude/skills/` when you run `gitnexus an
169
183
  - All processing happens locally on your machine
170
184
  - No code is sent to any server
171
185
  - Index stored in `.gitnexus/` inside your repo (gitignored)
186
+ - Global registry at `~/.gitnexus/` stores only paths and metadata
172
187
 
173
188
  ## Web UI
174
189
 
@@ -20,7 +20,7 @@ function generateGitNexusContent(projectName, stats) {
20
20
  return `${GITNEXUS_START_MARKER}
21
21
  # GitNexus MCP
22
22
 
23
- This project is indexed by GitNexus, providing AI agents with deep code intelligence.
23
+ This project is indexed as **${projectName}** by GitNexus, providing AI agents with deep code intelligence.
24
24
 
25
25
  ## Project: ${projectName}
26
26
 
@@ -35,48 +35,53 @@ This project is indexed by GitNexus, providing AI agents with deep code intellig
35
35
  ## Quick Start
36
36
 
37
37
  \`\`\`
38
- 1. READ gitnexus://context Get codebase overview (~150 tokens)
39
- 2. READ gitnexus://clusters See all functional clusters
40
- 3. READ gitnexus://cluster/{name} Deep dive on specific cluster
41
- 4. gitnexus_search(query) → Find code by query
38
+ 1. READ gitnexus://repos Discover all indexed repos
39
+ 2. READ gitnexus://repo/${projectName}/context Get codebase overview (~150 tokens)
40
+ 3. READ gitnexus://repo/${projectName}/clusters See all functional clusters
41
+ 4. gitnexus_search({query: "...", repo: "${projectName}"}) → Find code by query
42
42
  \`\`\`
43
43
 
44
44
  ## Available Resources
45
45
 
46
46
  | Resource | Purpose |
47
47
  |----------|---------|
48
- | \`gitnexus://context\` | Codebase stats, tools, and resources overview |
49
- | \`gitnexus://clusters\` | All clusters with symbol counts and cohesion |
50
- | \`gitnexus://cluster/{name}\` | Cluster members and details |
51
- | \`gitnexus://processes\` | All execution flows with types |
52
- | \`gitnexus://process/{name}\` | Full process trace with steps |
53
- | \`gitnexus://schema\` | Graph schema for Cypher queries |
48
+ | \`gitnexus://repos\` | List all indexed repositories |
49
+ | \`gitnexus://repo/${projectName}/context\` | Codebase stats, tools, and resources overview |
50
+ | \`gitnexus://repo/${projectName}/clusters\` | All clusters with symbol counts and cohesion |
51
+ | \`gitnexus://repo/${projectName}/cluster/{name}\` | Cluster members and details |
52
+ | \`gitnexus://repo/${projectName}/processes\` | All execution flows with types |
53
+ | \`gitnexus://repo/${projectName}/process/{name}\` | Full process trace with steps |
54
+ | \`gitnexus://repo/${projectName}/schema\` | Graph schema for Cypher queries |
54
55
 
55
56
  ## Available Tools
56
57
 
57
58
  | Tool | Purpose | When to Use |
58
59
  |------|---------|-------------|
60
+ | \`list_repos\` | Discover indexed repos | First step with multiple repos |
59
61
  | \`search\` | Semantic + keyword search | Finding code by query |
60
62
  | \`overview\` | List clusters & processes | Understanding architecture |
61
63
  | \`explore\` | Deep dive on symbol/cluster/process | Detailed investigation |
62
64
  | \`impact\` | Blast radius analysis | Before making changes |
63
65
  | \`cypher\` | Raw graph queries | Complex analysis |
64
66
 
67
+ > **Multi-repo:** When multiple repos are indexed, pass \`repo: "${projectName}"\` to target this project.
68
+
65
69
  ## Workflow Examples
66
70
 
67
71
  ### Exploring the Codebase
68
72
  \`\`\`
69
- READ gitnexus://context Stats and overview
70
- READ gitnexus://clusters Find relevant cluster
71
- READ gitnexus://cluster/AuthExplore Auth cluster
72
- gitnexus_explore("validateUser", "symbol") Detailed symbol info
73
+ READ gitnexus://repos Discover repos
74
+ READ gitnexus://repo/${projectName}/context Stats and overview
75
+ READ gitnexus://repo/${projectName}/clustersFind relevant cluster
76
+ READ gitnexus://repo/${projectName}/cluster/Auth Explore Auth cluster
77
+ gitnexus_explore({name: "validateUser", type: "symbol", repo: "${projectName}"})
73
78
  \`\`\`
74
79
 
75
80
  ### Planning a Change
76
81
  \`\`\`
77
- gitnexus_impact("UserService", "upstream") See what breaks
78
- READ gitnexus://processes → Check affected flows
79
- gitnexus_explore("LoginFlow", "process") Trace execution
82
+ gitnexus_impact({target: "UserService", direction: "upstream", repo: "${projectName}"})
83
+ READ gitnexus://repo/${projectName}/processes → Check affected flows
84
+ gitnexus_explore({name: "LoginFlow", type: "process", repo: "${projectName}"})
80
85
  \`\`\`
81
86
 
82
87
  ## Graph Schema
@@ -8,9 +8,10 @@ import ora from 'ora';
8
8
  import { runPipelineFromRepo } from '../core/ingestion/pipeline.js';
9
9
  import { initKuzu, loadGraphToKuzu, getKuzuStats, executeQuery, executeWithReusedStatement, closeKuzu, createFTSIndex } from '../core/kuzu/kuzu-adapter.js';
10
10
  import { runEmbeddingPipeline } from '../core/embeddings/embedding-pipeline.js';
11
- import { getStoragePaths, saveMeta, loadMeta, addToGitignore } from '../storage/repo-manager.js';
11
+ import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath } from '../storage/repo-manager.js';
12
12
  import { getCurrentCommit, isGitRepo, getGitRoot } from '../storage/git.js';
13
13
  import { generateAIContextFiles } from './ai-context.js';
14
+ import fs from 'fs/promises';
14
15
  export const analyzeCommand = async (inputPath, options) => {
15
16
  const spinner = ora('Checking repository...').start();
16
17
  // If path provided, use it directly. Otherwise, find git root from cwd.
@@ -83,7 +84,7 @@ export const analyzeCommand = async (inputPath, options) => {
83
84
  }
84
85
  // Save metadata
85
86
  const stats = await getKuzuStats();
86
- await saveMeta(storagePath, {
87
+ const meta = {
87
88
  repoPath,
88
89
  lastCommit: currentCommit,
89
90
  indexedAt: new Date().toISOString(),
@@ -94,7 +95,10 @@ export const analyzeCommand = async (inputPath, options) => {
94
95
  communities: pipelineResult.communityResult?.stats.totalCommunities,
95
96
  processes: pipelineResult.processResult?.stats.totalProcesses,
96
97
  },
97
- });
98
+ };
99
+ await saveMeta(storagePath, meta);
100
+ // Register in global registry
101
+ await registerRepo(repoPath, meta);
98
102
  // Add .gitnexus to .gitignore
99
103
  await addToGitignore(repoPath);
100
104
  // Generate AI context files
@@ -115,4 +119,13 @@ export const analyzeCommand = async (inputPath, options) => {
115
119
  if (aiContext.files.length > 0) {
116
120
  console.log(` AI Context: ${aiContext.files.join(', ')}`);
117
121
  }
122
+ // Hint about setup if it hasn't been run
123
+ try {
124
+ await fs.access(getGlobalRegistryPath());
125
+ }
126
+ catch {
127
+ // Registry didn't exist before this run — suggest setup
128
+ console.log('');
129
+ console.log(' Tip: Run `gitnexus setup` to configure MCP for your editor.');
130
+ }
118
131
  };
@@ -2,7 +2,9 @@
2
2
  * Clean Command
3
3
  *
4
4
  * Removes the .gitnexus index from the current repository.
5
+ * Also unregisters it from the global registry.
5
6
  */
6
7
  export declare const cleanCommand: (options?: {
7
8
  force?: boolean;
9
+ all?: boolean;
8
10
  }) => Promise<void>;
package/dist/cli/clean.js CHANGED
@@ -2,10 +2,40 @@
2
2
  * Clean Command
3
3
  *
4
4
  * Removes the .gitnexus index from the current repository.
5
+ * Also unregisters it from the global registry.
5
6
  */
6
7
  import fs from 'fs/promises';
7
- import { findRepo } from '../storage/repo-manager.js';
8
+ import { findRepo, unregisterRepo, listRegisteredRepos } from '../storage/repo-manager.js';
8
9
  export const cleanCommand = async (options) => {
10
+ // --all flag: clean all indexed repos
11
+ if (options?.all) {
12
+ if (!options?.force) {
13
+ const entries = await listRegisteredRepos();
14
+ if (entries.length === 0) {
15
+ console.log('No indexed repositories found.');
16
+ return;
17
+ }
18
+ console.log(`This will delete GitNexus indexes for ${entries.length} repo(s):`);
19
+ for (const entry of entries) {
20
+ console.log(` - ${entry.name} (${entry.path})`);
21
+ }
22
+ console.log('\nRun with --force to confirm deletion.');
23
+ return;
24
+ }
25
+ const entries = await listRegisteredRepos();
26
+ for (const entry of entries) {
27
+ try {
28
+ await fs.rm(entry.storagePath, { recursive: true, force: true });
29
+ await unregisterRepo(entry.path);
30
+ console.log(`Deleted: ${entry.name} (${entry.storagePath})`);
31
+ }
32
+ catch (err) {
33
+ console.error(`Failed to delete ${entry.name}:`, err);
34
+ }
35
+ }
36
+ return;
37
+ }
38
+ // Default: clean current repo
9
39
  const cwd = process.cwd();
10
40
  const repo = await findRepo(cwd);
11
41
  if (!repo) {
@@ -14,14 +44,15 @@ export const cleanCommand = async (options) => {
14
44
  }
15
45
  const repoName = repo.repoPath.split(/[/\\]/).pop() || repo.repoPath;
16
46
  if (!options?.force) {
17
- console.log(`⚠️ This will delete the GitNexus index for: ${repoName}`);
47
+ console.log(`This will delete the GitNexus index for: ${repoName}`);
18
48
  console.log(` Path: ${repo.storagePath}`);
19
49
  console.log('\nRun with --force to confirm deletion.');
20
50
  return;
21
51
  }
22
52
  try {
23
53
  await fs.rm(repo.storagePath, { recursive: true, force: true });
24
- console.log(`🗑️ Deleted: ${repo.storagePath}`);
54
+ await unregisterRepo(repo.repoPath);
55
+ console.log(`Deleted: ${repo.storagePath}`);
25
56
  }
26
57
  catch (err) {
27
58
  console.error('Failed to delete:', err);
package/dist/cli/index.js CHANGED
@@ -6,11 +6,16 @@ import { listCommand } from './list.js';
6
6
  import { statusCommand } from './status.js';
7
7
  import { mcpCommand } from './mcp.js';
8
8
  import { cleanCommand } from './clean.js';
9
+ import { setupCommand } from './setup.js';
9
10
  const program = new Command();
10
11
  program
11
12
  .name('gitnexus')
12
13
  .description('GitNexus local CLI and MCP server')
13
- .version('1.0.0');
14
+ .version('1.1.1');
15
+ program
16
+ .command('setup')
17
+ .description('One-time setup: configure MCP for Cursor, Claude Code, OpenCode')
18
+ .action(setupCommand);
14
19
  program
15
20
  .command('analyze [path]')
16
21
  .description('Index a repository (full analysis)')
@@ -24,11 +29,11 @@ program
24
29
  .action(serveCommand);
25
30
  program
26
31
  .command('mcp')
27
- .description('Start MCP server (stdio)')
32
+ .description('Start MCP server (stdio) — serves all indexed repos')
28
33
  .action(mcpCommand);
29
34
  program
30
35
  .command('list')
31
- .description('List indexed repositories')
36
+ .description('List all indexed repositories')
32
37
  .action(listCommand);
33
38
  program
34
39
  .command('status')
@@ -38,5 +43,6 @@ program
38
43
  .command('clean')
39
44
  .description('Delete GitNexus index for current repo')
40
45
  .option('-f, --force', 'Skip confirmation prompt')
46
+ .option('--all', 'Clean all indexed repos')
41
47
  .action(cleanCommand);
42
48
  program.parse(process.argv);
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * List Command
3
3
  *
4
- * Shows info about the indexed repo in the current directory.
4
+ * Shows all indexed repositories from the global registry.
5
5
  */
6
6
  export declare const listCommand: () => Promise<void>;
package/dist/cli/list.js CHANGED
@@ -1,27 +1,30 @@
1
1
  /**
2
2
  * List Command
3
3
  *
4
- * Shows info about the indexed repo in the current directory.
4
+ * Shows all indexed repositories from the global registry.
5
5
  */
6
- import { findRepo } from '../storage/repo-manager.js';
6
+ import { listRegisteredRepos } from '../storage/repo-manager.js';
7
7
  export const listCommand = async () => {
8
- const cwd = process.cwd();
9
- const repo = await findRepo(cwd);
10
- if (!repo) {
11
- console.log('No indexed repository found in this directory.');
12
- console.log('Run `gitnexus analyze` to index your codebase.');
8
+ const entries = await listRegisteredRepos({ validate: true });
9
+ if (entries.length === 0) {
10
+ console.log('No indexed repositories found.');
11
+ console.log('Run `gitnexus analyze` in a git repo to index it.');
13
12
  return;
14
13
  }
15
- const stats = repo.meta.stats || {};
16
- const repoName = repo.repoPath.split(/[/\\]/).pop() || repo.repoPath;
17
- const indexedDate = new Date(repo.meta.indexedAt).toLocaleString();
18
- console.log(`\n📁 ${repoName}`);
19
- console.log(` Path: ${repo.repoPath}`);
20
- console.log(` Indexed: ${indexedDate}`);
21
- console.log(` Stats: ${stats.files ?? 0} files, ${stats.nodes ?? 0} nodes, ${stats.edges ?? 0} edges`);
22
- console.log(` Commit: ${repo.meta.lastCommit?.slice(0, 7) || 'unknown'}`);
23
- if (stats.communities)
24
- console.log(` Communities: ${stats.communities}`);
25
- if (stats.processes)
26
- console.log(` Processes: ${stats.processes}`);
14
+ console.log(`\n Indexed Repositories (${entries.length})\n`);
15
+ for (const entry of entries) {
16
+ const indexedDate = new Date(entry.indexedAt).toLocaleString();
17
+ const stats = entry.stats || {};
18
+ const commitShort = entry.lastCommit?.slice(0, 7) || 'unknown';
19
+ console.log(` ${entry.name}`);
20
+ console.log(` Path: ${entry.path}`);
21
+ console.log(` Indexed: ${indexedDate}`);
22
+ console.log(` Commit: ${commitShort}`);
23
+ console.log(` Stats: ${stats.files ?? 0} files, ${stats.nodes ?? 0} symbols, ${stats.edges ?? 0} edges`);
24
+ if (stats.communities)
25
+ console.log(` Clusters: ${stats.communities}`);
26
+ if (stats.processes)
27
+ console.log(` Processes: ${stats.processes}`);
28
+ console.log('');
29
+ }
27
30
  };
package/dist/cli/mcp.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * MCP Command
3
3
  *
4
- * Starts the MCP server in standalone mode using local .gitnexus/ index.
5
- * Auto-detects repository by searching for .gitnexus/ folder.
4
+ * Starts the MCP server in standalone mode.
5
+ * Loads all indexed repos from the global registry.
6
+ * No longer depends on cwd — works from any directory.
6
7
  */
7
8
  export declare const mcpCommand: () => Promise<void>;
package/dist/cli/mcp.js CHANGED
@@ -1,85 +1,36 @@
1
1
  /**
2
2
  * MCP Command
3
3
  *
4
- * Starts the MCP server in standalone mode using local .gitnexus/ index.
5
- * Auto-detects repository by searching for .gitnexus/ folder.
4
+ * Starts the MCP server in standalone mode.
5
+ * Loads all indexed repos from the global registry.
6
+ * No longer depends on cwd — works from any directory.
6
7
  */
7
- import path from 'path';
8
- import fs from 'fs/promises';
9
8
  import { startMCPServer } from '../mcp/server.js';
10
- import { LocalBackend, findRepo } from '../mcp/local/local-backend.js';
11
- /**
12
- * Get candidate paths to search for .gitnexus/ folder
13
- */
14
- function getCandidatePaths() {
15
- const candidates = [];
16
- // 1. Explicit override (highest priority)
17
- if (process.env.GITNEXUS_CWD) {
18
- candidates.push(process.env.GITNEXUS_CWD);
19
- }
20
- // 2. Current working directory
21
- candidates.push(process.cwd());
22
- // 3. VS Code workspace folders (if available via env)
23
- if (process.env.VSCODE_WORKSPACE_FOLDER) {
24
- candidates.push(process.env.VSCODE_WORKSPACE_FOLDER);
25
- }
26
- // Deduplicate while preserving order
27
- return [...new Set(candidates.map(p => path.resolve(p)))];
28
- }
29
- /**
30
- * Find a git repository root by walking up the directory tree
31
- */
32
- async function findGitRoot(startPath) {
33
- let current = path.resolve(startPath);
34
- const root = path.parse(current).root;
35
- while (current !== root) {
36
- try {
37
- const gitPath = path.join(current, '.git');
38
- const stat = await fs.stat(gitPath);
39
- if (stat.isDirectory())
40
- return current;
41
- }
42
- catch { }
43
- current = path.dirname(current);
44
- }
45
- return null;
46
- }
9
+ import { LocalBackend } from '../mcp/local/local-backend.js';
10
+ import { listRegisteredRepos } from '../storage/repo-manager.js';
47
11
  export const mcpCommand = async () => {
48
- // Try multiple candidate paths to find .gitnexus/
49
- const candidates = getCandidatePaths();
50
- for (const candidate of candidates) {
51
- const repo = await findRepo(candidate);
52
- if (repo) {
53
- const local = new LocalBackend();
54
- await local.init(candidate);
55
- console.error(`GitNexus: Found index at ${repo.storagePath}`);
56
- // Start MCP server (no watcher daemon - staleness hints guide LLM to call analyze)
57
- await startMCPServer(local);
58
- return;
59
- }
12
+ // Load all registered repos
13
+ const entries = await listRegisteredRepos({ validate: true });
14
+ if (entries.length === 0) {
15
+ console.error('');
16
+ console.error(' GitNexus: No indexed repositories found.');
17
+ console.error('');
18
+ console.error(' To get started:');
19
+ console.error(' 1. cd into a git repository');
20
+ console.error(' 2. Run: gitnexus analyze');
21
+ console.error(' 3. Restart your editor');
22
+ console.error('');
23
+ process.exit(1);
60
24
  }
61
- // No index found - give helpful error message
62
- for (const candidate of candidates) {
63
- const gitRoot = await findGitRoot(candidate);
64
- if (gitRoot) {
65
- console.error('');
66
- console.error('╔════════════════════════════════════════════════════╗');
67
- console.error('║ GitNexus: Repository Not Indexed ║');
68
- console.error('╠════════════════════════════════════════════════════╣');
69
- console.error(`║ Found git repo: ${gitRoot.slice(0, 35).padEnd(35)} ║`);
70
- console.error('║ ║');
71
- console.error('║ To enable AI code understanding, run: ║');
72
- console.error('║ ║');
73
- console.error('║ npx gitnexus analyze ║');
74
- console.error('║ ║');
75
- console.error('║ Then restart your IDE. ║');
76
- console.error('╚════════════════════════════════════════════════════╝');
77
- console.error('');
78
- process.exit(1);
79
- }
25
+ // Initialize multi-repo backend from registry
26
+ const backend = new LocalBackend();
27
+ const ok = await backend.init();
28
+ if (!ok) {
29
+ console.error('GitNexus: Failed to initialize backend from registry.');
30
+ process.exit(1);
80
31
  }
81
- // No git repo found
82
- console.error('GitNexus: No git repository found.');
83
- console.error(`Searched: ${candidates.join(', ')}`);
84
- process.exit(1);
32
+ const repoNames = backend.listRepos().map(r => r.name);
33
+ console.error(`GitNexus: MCP server starting with ${repoNames.length} repo(s): ${repoNames.join(', ')}`);
34
+ // Start MCP server (serves all repos)
35
+ await startMCPServer(backend);
85
36
  };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Setup Command
3
+ *
4
+ * One-time global MCP configuration writer.
5
+ * Detects installed AI editors and writes the appropriate MCP config
6
+ * so the GitNexus MCP server is available in all projects.
7
+ */
8
+ export declare const setupCommand: () => Promise<void>;