gitnexus 1.3.6 → 1.3.8
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/dist/cli/ai-context.js +77 -23
- package/dist/cli/analyze.js +4 -11
- package/dist/cli/eval-server.d.ts +7 -0
- package/dist/cli/eval-server.js +16 -7
- package/dist/cli/index.js +2 -20
- package/dist/cli/mcp.js +2 -0
- package/dist/cli/setup.js +6 -1
- package/dist/config/supported-languages.d.ts +1 -0
- package/dist/config/supported-languages.js +1 -0
- package/dist/core/ingestion/call-processor.d.ts +5 -1
- package/dist/core/ingestion/call-processor.js +78 -0
- package/dist/core/ingestion/framework-detection.d.ts +1 -0
- package/dist/core/ingestion/framework-detection.js +49 -2
- package/dist/core/ingestion/import-processor.js +90 -39
- package/dist/core/ingestion/parsing-processor.d.ts +12 -1
- package/dist/core/ingestion/parsing-processor.js +92 -51
- package/dist/core/ingestion/pipeline.js +21 -2
- package/dist/core/ingestion/process-processor.js +0 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -0
- package/dist/core/ingestion/tree-sitter-queries.js +80 -0
- package/dist/core/ingestion/utils.d.ts +5 -0
- package/dist/core/ingestion/utils.js +20 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +11 -0
- package/dist/core/ingestion/workers/parse-worker.js +473 -51
- package/dist/core/kuzu/csv-generator.d.ts +4 -0
- package/dist/core/kuzu/csv-generator.js +23 -9
- package/dist/core/kuzu/kuzu-adapter.js +9 -3
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -0
- package/dist/core/tree-sitter/parser-loader.js +3 -0
- package/dist/mcp/core/kuzu-adapter.d.ts +4 -3
- package/dist/mcp/core/kuzu-adapter.js +79 -16
- package/dist/mcp/local/local-backend.d.ts +13 -0
- package/dist/mcp/local/local-backend.js +148 -105
- package/dist/mcp/server.js +26 -11
- package/dist/storage/git.js +4 -1
- package/dist/storage/repo-manager.js +16 -2
- package/hooks/claude/gitnexus-hook.cjs +28 -8
- package/hooks/claude/pre-tool-use.sh +2 -1
- package/package.json +11 -3
- package/dist/cli/claude-hooks.d.ts +0 -22
- package/dist/cli/claude-hooks.js +0 -97
- package/dist/cli/view.d.ts +0 -13
- package/dist/cli/view.js +0 -59
- package/dist/core/graph/html-graph-viewer.d.ts +0 -15
- package/dist/core/graph/html-graph-viewer.js +0 -542
- package/dist/core/graph/html-graph-viewer.test.d.ts +0 -1
- package/dist/core/graph/html-graph-viewer.test.js +0 -67
|
@@ -151,7 +151,13 @@ export const registerRepo = async (repoPath, meta) => {
|
|
|
151
151
|
const name = path.basename(resolved);
|
|
152
152
|
const { storagePath } = getStoragePaths(resolved);
|
|
153
153
|
const entries = await readRegistry();
|
|
154
|
-
const existing = entries.findIndex((e) =>
|
|
154
|
+
const existing = entries.findIndex((e) => {
|
|
155
|
+
const a = path.resolve(e.path);
|
|
156
|
+
const b = resolved;
|
|
157
|
+
return process.platform === 'win32'
|
|
158
|
+
? a.toLowerCase() === b.toLowerCase()
|
|
159
|
+
: a === b;
|
|
160
|
+
});
|
|
155
161
|
const entry = {
|
|
156
162
|
name,
|
|
157
163
|
path: resolved,
|
|
@@ -227,5 +233,13 @@ export const loadCLIConfig = async () => {
|
|
|
227
233
|
export const saveCLIConfig = async (config) => {
|
|
228
234
|
const dir = getGlobalDir();
|
|
229
235
|
await fs.mkdir(dir, { recursive: true });
|
|
230
|
-
|
|
236
|
+
const configPath = getGlobalConfigPath();
|
|
237
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
238
|
+
// Restrict file permissions on Unix (config may contain API keys)
|
|
239
|
+
if (process.platform !== 'win32') {
|
|
240
|
+
try {
|
|
241
|
+
await fs.chmod(configPath, 0o600);
|
|
242
|
+
}
|
|
243
|
+
catch { /* best-effort */ }
|
|
244
|
+
}
|
|
231
245
|
};
|
|
@@ -101,20 +101,40 @@ function main() {
|
|
|
101
101
|
const pattern = extractPattern(toolName, toolInput);
|
|
102
102
|
if (!pattern || pattern.length < 3) return;
|
|
103
103
|
|
|
104
|
-
// Resolve CLI path
|
|
105
|
-
//
|
|
106
|
-
|
|
104
|
+
// Resolve CLI path — try multiple strategies:
|
|
105
|
+
// 1. Relative path (works when script is inside npm package)
|
|
106
|
+
// 2. require.resolve (works when gitnexus is globally installed)
|
|
107
|
+
// 3. Fall back to npx (works when neither is available)
|
|
108
|
+
let cliPath = path.resolve(__dirname, '..', '..', 'dist', 'cli', 'index.js');
|
|
109
|
+
if (!fs.existsSync(cliPath)) {
|
|
110
|
+
try {
|
|
111
|
+
cliPath = require.resolve('gitnexus/dist/cli/index.js');
|
|
112
|
+
} catch {
|
|
113
|
+
cliPath = ''; // will use npx fallback
|
|
114
|
+
}
|
|
115
|
+
}
|
|
107
116
|
|
|
108
117
|
// augment CLI writes result to stderr (KuzuDB's native module captures
|
|
109
118
|
// stdout fd at OS level, making it unusable in subprocess contexts).
|
|
110
119
|
const { spawnSync } = require('child_process');
|
|
111
120
|
let result = '';
|
|
112
121
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
122
|
+
let child;
|
|
123
|
+
if (cliPath) {
|
|
124
|
+
child = spawnSync(
|
|
125
|
+
process.execPath,
|
|
126
|
+
[cliPath, 'augment', pattern],
|
|
127
|
+
{ encoding: 'utf-8', timeout: 8000, cwd, stdio: ['pipe', 'pipe', 'pipe'] }
|
|
128
|
+
);
|
|
129
|
+
} else {
|
|
130
|
+
// npx fallback
|
|
131
|
+
const cmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
132
|
+
child = spawnSync(
|
|
133
|
+
cmd,
|
|
134
|
+
['-y', 'gitnexus', 'augment', pattern],
|
|
135
|
+
{ encoding: 'utf-8', timeout: 15000, cwd, stdio: ['pipe', 'pipe', 'pipe'] }
|
|
136
|
+
);
|
|
137
|
+
}
|
|
118
138
|
result = child.stderr || '';
|
|
119
139
|
} catch { /* graceful failure */ }
|
|
120
140
|
|
|
@@ -63,7 +63,8 @@ if [ "$found" = false ]; then
|
|
|
63
63
|
fi
|
|
64
64
|
|
|
65
65
|
# Run gitnexus augment — must be fast (<500ms target)
|
|
66
|
-
|
|
66
|
+
# augment writes to stderr (KuzuDB captures stdout at OS level), so capture stderr and discard stdout
|
|
67
|
+
RESULT=$(cd "$CWD" && npx -y gitnexus augment "$PATTERN" 2>&1 1>/dev/null)
|
|
67
68
|
|
|
68
69
|
if [ -n "$RESULT" ]; then
|
|
69
70
|
ESCAPED=$(echo "$RESULT" | jq -Rs .)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitnexus",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
@@ -39,6 +39,11 @@
|
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsc",
|
|
41
41
|
"dev": "tsx watch src/cli/index.ts",
|
|
42
|
+
"test": "vitest run test/unit",
|
|
43
|
+
"test:integration": "vitest run test/integration",
|
|
44
|
+
"test:all": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"test:coverage": "vitest run --coverage",
|
|
42
47
|
"prepare": "npm run build",
|
|
43
48
|
"postinstall": "node scripts/patch-tree-sitter-swift.cjs"
|
|
44
49
|
},
|
|
@@ -64,11 +69,11 @@
|
|
|
64
69
|
"tree-sitter-go": "^0.21.0",
|
|
65
70
|
"tree-sitter-java": "^0.21.0",
|
|
66
71
|
"tree-sitter-javascript": "^0.21.0",
|
|
72
|
+
"tree-sitter-kotlin": "^0.3.8",
|
|
67
73
|
"tree-sitter-php": "^0.23.12",
|
|
68
74
|
"tree-sitter-python": "^0.21.0",
|
|
69
75
|
"tree-sitter-rust": "^0.21.0",
|
|
70
76
|
"tree-sitter-typescript": "^0.21.0",
|
|
71
|
-
"typescript": "^5.4.5",
|
|
72
77
|
"uuid": "^13.0.0"
|
|
73
78
|
},
|
|
74
79
|
"optionalDependencies": {
|
|
@@ -80,7 +85,10 @@
|
|
|
80
85
|
"@types/express": "^4.17.21",
|
|
81
86
|
"@types/node": "^20.0.0",
|
|
82
87
|
"@types/uuid": "^10.0.0",
|
|
83
|
-
"
|
|
88
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
89
|
+
"tsx": "^4.0.0",
|
|
90
|
+
"typescript": "^5.4.5",
|
|
91
|
+
"vitest": "^4.0.18"
|
|
84
92
|
},
|
|
85
93
|
"engines": {
|
|
86
94
|
"node": ">=18.0.0"
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Hook Registration
|
|
3
|
-
*
|
|
4
|
-
* Registers the GitNexus PreToolUse hook in ~/.claude/hooks.json
|
|
5
|
-
* so that grep/glob/bash calls are automatically augmented with
|
|
6
|
-
* knowledge graph context.
|
|
7
|
-
*
|
|
8
|
-
* Idempotent — safe to call multiple times.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Register (or verify) the GitNexus hook in Claude Code's global hooks.json.
|
|
12
|
-
*
|
|
13
|
-
* - Creates ~/.claude/ and hooks.json if they don't exist
|
|
14
|
-
* - Preserves existing hooks from other tools
|
|
15
|
-
* - Skips if GitNexus hook is already registered
|
|
16
|
-
*
|
|
17
|
-
* Returns a status message for the CLI output.
|
|
18
|
-
*/
|
|
19
|
-
export declare function registerClaudeHook(): Promise<{
|
|
20
|
-
registered: boolean;
|
|
21
|
-
message: string;
|
|
22
|
-
}>;
|
package/dist/cli/claude-hooks.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude Code Hook Registration
|
|
3
|
-
*
|
|
4
|
-
* Registers the GitNexus PreToolUse hook in ~/.claude/hooks.json
|
|
5
|
-
* so that grep/glob/bash calls are automatically augmented with
|
|
6
|
-
* knowledge graph context.
|
|
7
|
-
*
|
|
8
|
-
* Idempotent — safe to call multiple times.
|
|
9
|
-
*/
|
|
10
|
-
import fs from 'fs/promises';
|
|
11
|
-
import path from 'path';
|
|
12
|
-
import os from 'os';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
-
const __dirname = path.dirname(__filename);
|
|
16
|
-
/**
|
|
17
|
-
* Get the absolute path to the gitnexus-hook.js file.
|
|
18
|
-
* Works for both local dev and npm-installed packages.
|
|
19
|
-
*/
|
|
20
|
-
function getHookScriptPath() {
|
|
21
|
-
// From dist/cli/claude-hooks.js → hooks/claude/gitnexus-hook.js
|
|
22
|
-
const packageRoot = path.resolve(__dirname, '..', '..');
|
|
23
|
-
return path.join(packageRoot, 'hooks', 'claude', 'gitnexus-hook.cjs');
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Register (or verify) the GitNexus hook in Claude Code's global hooks.json.
|
|
27
|
-
*
|
|
28
|
-
* - Creates ~/.claude/ and hooks.json if they don't exist
|
|
29
|
-
* - Preserves existing hooks from other tools
|
|
30
|
-
* - Skips if GitNexus hook is already registered
|
|
31
|
-
*
|
|
32
|
-
* Returns a status message for the CLI output.
|
|
33
|
-
*/
|
|
34
|
-
export async function registerClaudeHook() {
|
|
35
|
-
const claudeDir = path.join(os.homedir(), '.claude');
|
|
36
|
-
const hooksFile = path.join(claudeDir, 'hooks.json');
|
|
37
|
-
const hookScript = getHookScriptPath();
|
|
38
|
-
// Check if the hook script exists
|
|
39
|
-
try {
|
|
40
|
-
await fs.access(hookScript);
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
return { registered: false, message: 'Hook script not found (package may be incomplete)' };
|
|
44
|
-
}
|
|
45
|
-
// Build the hook command — use node + absolute path for reliability
|
|
46
|
-
const hookCommand = `node "${hookScript}"`;
|
|
47
|
-
// Check if ~/.claude/ exists (user has Claude Code installed)
|
|
48
|
-
try {
|
|
49
|
-
await fs.access(claudeDir);
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// No Claude Code installation — skip silently
|
|
53
|
-
return { registered: false, message: 'Claude Code not detected (~/.claude/ not found)' };
|
|
54
|
-
}
|
|
55
|
-
// Read existing hooks.json or start fresh
|
|
56
|
-
let hooksConfig = {};
|
|
57
|
-
try {
|
|
58
|
-
const existing = await fs.readFile(hooksFile, 'utf-8');
|
|
59
|
-
hooksConfig = JSON.parse(existing);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
// File doesn't exist or is invalid — we'll create it
|
|
63
|
-
}
|
|
64
|
-
// Ensure the hooks structure exists
|
|
65
|
-
if (!hooksConfig.hooks) {
|
|
66
|
-
hooksConfig.hooks = {};
|
|
67
|
-
}
|
|
68
|
-
if (!Array.isArray(hooksConfig.hooks.PreToolUse)) {
|
|
69
|
-
hooksConfig.hooks.PreToolUse = [];
|
|
70
|
-
}
|
|
71
|
-
// Check if GitNexus hook is already registered
|
|
72
|
-
const existingEntry = hooksConfig.hooks.PreToolUse.find((entry) => {
|
|
73
|
-
if (!entry.hooks || !Array.isArray(entry.hooks))
|
|
74
|
-
return false;
|
|
75
|
-
return entry.hooks.some((h) => h.command && (h.command.includes('gitnexus-hook') ||
|
|
76
|
-
h.command.includes('gitnexus augment')));
|
|
77
|
-
});
|
|
78
|
-
if (existingEntry) {
|
|
79
|
-
return { registered: true, message: 'Claude Code hook already registered' };
|
|
80
|
-
}
|
|
81
|
-
// Add the GitNexus hook entry
|
|
82
|
-
hooksConfig.hooks.PreToolUse.push({
|
|
83
|
-
matcher: {
|
|
84
|
-
tool_name: "Grep|Glob|Bash"
|
|
85
|
-
},
|
|
86
|
-
hooks: [
|
|
87
|
-
{
|
|
88
|
-
type: "command",
|
|
89
|
-
command: hookCommand,
|
|
90
|
-
timeout: 8000
|
|
91
|
-
}
|
|
92
|
-
]
|
|
93
|
-
});
|
|
94
|
-
// Write back
|
|
95
|
-
await fs.writeFile(hooksFile, JSON.stringify(hooksConfig, null, 2) + '\n', 'utf-8');
|
|
96
|
-
return { registered: true, message: 'Claude Code hook registered' };
|
|
97
|
-
}
|
package/dist/cli/view.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* View Command
|
|
3
|
-
*
|
|
4
|
-
* Generates a self-contained graph.html from the KuzuDB index and
|
|
5
|
-
* opens it in the default browser.
|
|
6
|
-
*
|
|
7
|
-
* Usage: gitnexus view [path] [--no-open]
|
|
8
|
-
*/
|
|
9
|
-
export interface ViewCommandOptions {
|
|
10
|
-
noOpen?: boolean;
|
|
11
|
-
output?: string;
|
|
12
|
-
}
|
|
13
|
-
export declare const viewCommand: (inputPath?: string, options?: ViewCommandOptions) => Promise<void>;
|
package/dist/cli/view.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* View Command
|
|
3
|
-
*
|
|
4
|
-
* Generates a self-contained graph.html from the KuzuDB index and
|
|
5
|
-
* opens it in the default browser.
|
|
6
|
-
*
|
|
7
|
-
* Usage: gitnexus view [path] [--no-open]
|
|
8
|
-
*/
|
|
9
|
-
import path from 'path';
|
|
10
|
-
import fs from 'fs/promises';
|
|
11
|
-
import { exec } from 'child_process';
|
|
12
|
-
import { findRepo } from '../storage/repo-manager.js';
|
|
13
|
-
import { initKuzu } from '../core/kuzu/kuzu-adapter.js';
|
|
14
|
-
import { buildGraph } from '../server/api.js';
|
|
15
|
-
import { generateHTMLGraphViewer } from '../core/graph/html-graph-viewer.js';
|
|
16
|
-
import { getCurrentCommit } from '../storage/git.js';
|
|
17
|
-
function openInBrowser(filePath) {
|
|
18
|
-
const url = `file://${filePath}`;
|
|
19
|
-
let cmd;
|
|
20
|
-
if (process.platform === 'darwin') {
|
|
21
|
-
cmd = `open "${url}"`;
|
|
22
|
-
}
|
|
23
|
-
else if (process.platform === 'win32') {
|
|
24
|
-
cmd = `start "" "${url}"`;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
cmd = `xdg-open "${url}"`;
|
|
28
|
-
}
|
|
29
|
-
exec(cmd, (err) => {
|
|
30
|
-
if (err)
|
|
31
|
-
console.error('Failed to open browser:', err.message);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
export const viewCommand = async (inputPath, options) => {
|
|
35
|
-
console.log('⚠ Experimental: gitnexus view is under active development.\n');
|
|
36
|
-
const repoPath = inputPath ? path.resolve(inputPath) : process.cwd();
|
|
37
|
-
const repo = await findRepo(repoPath);
|
|
38
|
-
if (!repo) {
|
|
39
|
-
console.error('No index found. Run: gitnexus analyze');
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
const currentCommit = getCurrentCommit(repo.repoPath);
|
|
43
|
-
if (currentCommit !== repo.meta.lastCommit) {
|
|
44
|
-
console.warn('Index is stale — showing last indexed state. Run: gitnexus analyze\n');
|
|
45
|
-
}
|
|
46
|
-
await initKuzu(repo.kuzuPath);
|
|
47
|
-
const { nodes, relationships } = await buildGraph();
|
|
48
|
-
const projectName = path.basename(repo.repoPath);
|
|
49
|
-
const outputPath = options?.output
|
|
50
|
-
? path.resolve(options.output)
|
|
51
|
-
: path.join(repo.storagePath, 'graph.html');
|
|
52
|
-
const html = generateHTMLGraphViewer(nodes, relationships, projectName);
|
|
53
|
-
await fs.writeFile(outputPath, html, 'utf-8');
|
|
54
|
-
console.log(`Graph written to: ${outputPath}`);
|
|
55
|
-
console.log(`Nodes: ${nodes.length} Edges: ${relationships.length}`);
|
|
56
|
-
if (!options?.noOpen) {
|
|
57
|
-
openInBrowser(outputPath);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTML Graph Viewer Generator
|
|
3
|
-
*
|
|
4
|
-
* Produces a self-contained graph.html that renders the knowledge graph
|
|
5
|
-
* using Sigma.js v2 + graphology (both from CDN).
|
|
6
|
-
*
|
|
7
|
-
* Critical: node `content` fields are stripped before embedding to prevent
|
|
8
|
-
* </script> injection from source code breaking the HTML parser.
|
|
9
|
-
*/
|
|
10
|
-
import { GraphNode, GraphRelationship } from './types.js';
|
|
11
|
-
/**
|
|
12
|
-
* Generate a self-contained HTML file that renders the knowledge graph.
|
|
13
|
-
* Strips large/unsafe fields from nodes before embedding.
|
|
14
|
-
*/
|
|
15
|
-
export declare function generateHTMLGraphViewer(nodes: GraphNode[], relationships: GraphRelationship[], projectName: string): string;
|