gitnexus 1.4.10 → 1.5.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/README.md +6 -5
- package/dist/cli/ai-context.d.ts +4 -1
- package/dist/cli/ai-context.js +19 -11
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +105 -251
- package/dist/cli/eval-server.js +20 -11
- package/dist/cli/index-repo.js +20 -22
- package/dist/cli/index.js +8 -7
- package/dist/cli/mcp.js +1 -1
- package/dist/cli/serve.js +29 -1
- package/dist/cli/setup.js +9 -9
- package/dist/cli/skill-gen.js +15 -9
- package/dist/cli/wiki.d.ts +2 -0
- package/dist/cli/wiki.js +141 -26
- package/dist/config/ignore-service.js +102 -22
- package/dist/config/supported-languages.d.ts +8 -42
- package/dist/config/supported-languages.js +8 -43
- package/dist/core/augmentation/engine.js +19 -7
- package/dist/core/embeddings/embedder.js +19 -15
- package/dist/core/embeddings/embedding-pipeline.js +6 -6
- package/dist/core/embeddings/http-client.js +3 -3
- package/dist/core/embeddings/text-generator.js +9 -24
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/embeddings/types.js +1 -7
- package/dist/core/graph/graph.js +6 -2
- package/dist/core/graph/types.d.ts +9 -59
- package/dist/core/ingestion/ast-cache.js +3 -3
- package/dist/core/ingestion/call-processor.d.ts +20 -2
- package/dist/core/ingestion/call-processor.js +347 -144
- package/dist/core/ingestion/call-routing.js +10 -4
- package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +10 -0
- package/dist/core/ingestion/call-sites/extract-language-call-site.js +22 -0
- package/dist/core/ingestion/call-sites/java.d.ts +9 -0
- package/dist/core/ingestion/call-sites/java.js +30 -0
- package/dist/core/ingestion/cluster-enricher.js +6 -8
- package/dist/core/ingestion/cobol/cobol-copy-expander.js +10 -3
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +287 -81
- package/dist/core/ingestion/cobol/jcl-parser.js +1 -1
- package/dist/core/ingestion/cobol/jcl-processor.js +1 -1
- package/dist/core/ingestion/cobol-processor.js +102 -56
- package/dist/core/ingestion/community-processor.js +21 -15
- package/dist/core/ingestion/entry-point-scoring.d.ts +1 -1
- package/dist/core/ingestion/entry-point-scoring.js +5 -6
- package/dist/core/ingestion/export-detection.js +32 -9
- package/dist/core/ingestion/field-extractor.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/configs/c-cpp.js +8 -12
- package/dist/core/ingestion/field-extractors/configs/csharp.js +45 -2
- package/dist/core/ingestion/field-extractors/configs/dart.js +5 -3
- package/dist/core/ingestion/field-extractors/configs/go.js +3 -7
- package/dist/core/ingestion/field-extractors/configs/helpers.d.ts +5 -0
- package/dist/core/ingestion/field-extractors/configs/helpers.js +14 -0
- package/dist/core/ingestion/field-extractors/configs/jvm.js +7 -7
- package/dist/core/ingestion/field-extractors/configs/php.js +9 -11
- package/dist/core/ingestion/field-extractors/configs/python.js +1 -1
- package/dist/core/ingestion/field-extractors/configs/ruby.js +4 -3
- package/dist/core/ingestion/field-extractors/configs/rust.js +2 -5
- package/dist/core/ingestion/field-extractors/configs/swift.js +9 -7
- package/dist/core/ingestion/field-extractors/configs/typescript-javascript.js +2 -6
- package/dist/core/ingestion/field-extractors/generic.d.ts +5 -2
- package/dist/core/ingestion/field-extractors/generic.js +6 -0
- package/dist/core/ingestion/field-extractors/typescript.d.ts +1 -1
- package/dist/core/ingestion/field-extractors/typescript.js +1 -1
- package/dist/core/ingestion/field-types.d.ts +4 -2
- package/dist/core/ingestion/filesystem-walker.js +3 -3
- package/dist/core/ingestion/framework-detection.d.ts +1 -1
- package/dist/core/ingestion/framework-detection.js +355 -85
- package/dist/core/ingestion/heritage-processor.d.ts +24 -0
- package/dist/core/ingestion/heritage-processor.js +99 -8
- package/dist/core/ingestion/import-processor.js +44 -15
- package/dist/core/ingestion/import-resolvers/csharp.js +7 -3
- package/dist/core/ingestion/import-resolvers/dart.js +1 -1
- package/dist/core/ingestion/import-resolvers/go.js +4 -2
- package/dist/core/ingestion/import-resolvers/jvm.js +4 -4
- package/dist/core/ingestion/import-resolvers/php.js +4 -4
- package/dist/core/ingestion/import-resolvers/python.js +1 -1
- package/dist/core/ingestion/import-resolvers/rust.js +9 -3
- package/dist/core/ingestion/import-resolvers/standard.d.ts +1 -1
- package/dist/core/ingestion/import-resolvers/standard.js +6 -5
- package/dist/core/ingestion/import-resolvers/swift.js +2 -1
- package/dist/core/ingestion/import-resolvers/utils.js +26 -7
- package/dist/core/ingestion/language-config.js +5 -4
- package/dist/core/ingestion/language-provider.d.ts +7 -2
- package/dist/core/ingestion/languages/c-cpp.js +106 -21
- package/dist/core/ingestion/languages/cobol.js +1 -1
- package/dist/core/ingestion/languages/csharp.js +96 -19
- package/dist/core/ingestion/languages/dart.js +23 -7
- package/dist/core/ingestion/languages/go.js +1 -1
- package/dist/core/ingestion/languages/index.d.ts +1 -1
- package/dist/core/ingestion/languages/index.js +2 -3
- package/dist/core/ingestion/languages/java.js +4 -1
- package/dist/core/ingestion/languages/kotlin.js +60 -13
- package/dist/core/ingestion/languages/php.js +102 -25
- package/dist/core/ingestion/languages/python.js +28 -5
- package/dist/core/ingestion/languages/ruby.js +56 -14
- package/dist/core/ingestion/languages/rust.js +55 -11
- package/dist/core/ingestion/languages/swift.js +112 -27
- package/dist/core/ingestion/languages/typescript.js +95 -19
- package/dist/core/ingestion/markdown-processor.js +5 -5
- package/dist/core/ingestion/method-extractors/configs/csharp.d.ts +2 -0
- package/dist/core/ingestion/method-extractors/configs/csharp.js +283 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.d.ts +3 -0
- package/dist/core/ingestion/method-extractors/configs/jvm.js +326 -0
- package/dist/core/ingestion/method-extractors/generic.d.ts +5 -0
- package/dist/core/ingestion/method-extractors/generic.js +137 -0
- package/dist/core/ingestion/method-types.d.ts +61 -0
- package/dist/core/ingestion/method-types.js +2 -0
- package/dist/core/ingestion/mro-processor.d.ts +1 -1
- package/dist/core/ingestion/mro-processor.js +12 -8
- package/dist/core/ingestion/named-binding-processor.js +2 -2
- package/dist/core/ingestion/named-bindings/rust.js +3 -1
- package/dist/core/ingestion/parsing-processor.js +74 -24
- package/dist/core/ingestion/pipeline.d.ts +2 -1
- package/dist/core/ingestion/pipeline.js +208 -102
- package/dist/core/ingestion/process-processor.js +12 -10
- package/dist/core/ingestion/resolution-context.js +3 -3
- package/dist/core/ingestion/route-extractors/middleware.js +31 -7
- package/dist/core/ingestion/route-extractors/php.js +2 -1
- package/dist/core/ingestion/route-extractors/response-shapes.js +8 -4
- package/dist/core/ingestion/structure-processor.d.ts +1 -1
- package/dist/core/ingestion/structure-processor.js +4 -4
- package/dist/core/ingestion/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/symbol-table.js +22 -6
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +1 -1
- package/dist/core/ingestion/type-env.d.ts +2 -2
- package/dist/core/ingestion/type-env.js +75 -50
- package/dist/core/ingestion/type-extractors/c-cpp.js +33 -30
- package/dist/core/ingestion/type-extractors/csharp.js +24 -14
- package/dist/core/ingestion/type-extractors/dart.js +6 -8
- package/dist/core/ingestion/type-extractors/go.js +7 -6
- package/dist/core/ingestion/type-extractors/jvm.js +10 -21
- package/dist/core/ingestion/type-extractors/php.js +26 -13
- package/dist/core/ingestion/type-extractors/python.js +11 -15
- package/dist/core/ingestion/type-extractors/ruby.js +8 -3
- package/dist/core/ingestion/type-extractors/rust.js +6 -8
- package/dist/core/ingestion/type-extractors/shared.js +134 -50
- package/dist/core/ingestion/type-extractors/swift.js +16 -13
- package/dist/core/ingestion/type-extractors/typescript.js +23 -15
- package/dist/core/ingestion/utils/ast-helpers.d.ts +8 -8
- package/dist/core/ingestion/utils/ast-helpers.js +72 -35
- package/dist/core/ingestion/utils/call-analysis.d.ts +2 -0
- package/dist/core/ingestion/utils/call-analysis.js +96 -49
- package/dist/core/ingestion/utils/event-loop.js +1 -1
- package/dist/core/ingestion/workers/parse-worker.d.ts +7 -2
- package/dist/core/ingestion/workers/parse-worker.js +364 -84
- package/dist/core/ingestion/workers/worker-pool.js +5 -10
- package/dist/core/lbug/csv-generator.js +54 -15
- package/dist/core/lbug/lbug-adapter.d.ts +5 -0
- package/dist/core/lbug/lbug-adapter.js +86 -23
- package/dist/core/lbug/schema.d.ts +3 -6
- package/dist/core/lbug/schema.js +6 -30
- package/dist/core/run-analyze.d.ts +49 -0
- package/dist/core/run-analyze.js +257 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -1
- package/dist/core/tree-sitter/parser-loader.js +1 -1
- package/dist/core/wiki/cursor-client.js +2 -7
- package/dist/core/wiki/generator.js +38 -23
- package/dist/core/wiki/graph-queries.js +10 -10
- package/dist/core/wiki/html-viewer.js +7 -3
- package/dist/core/wiki/llm-client.d.ts +23 -2
- package/dist/core/wiki/llm-client.js +96 -26
- package/dist/core/wiki/prompts.js +7 -6
- package/dist/mcp/core/embedder.js +1 -1
- package/dist/mcp/core/lbug-adapter.d.ts +4 -1
- package/dist/mcp/core/lbug-adapter.js +17 -7
- package/dist/mcp/local/local-backend.js +247 -95
- package/dist/mcp/resources.js +14 -6
- package/dist/mcp/server.js +13 -5
- package/dist/mcp/staleness.js +5 -1
- package/dist/mcp/tools.js +100 -23
- package/dist/server/analyze-job.d.ts +53 -0
- package/dist/server/analyze-job.js +146 -0
- package/dist/server/analyze-worker.d.ts +13 -0
- package/dist/server/analyze-worker.js +59 -0
- package/dist/server/api.js +795 -44
- package/dist/server/git-clone.d.ts +25 -0
- package/dist/server/git-clone.js +91 -0
- package/dist/storage/git.js +1 -3
- package/dist/storage/repo-manager.d.ts +5 -2
- package/dist/storage/repo-manager.js +4 -4
- package/dist/types/pipeline.d.ts +1 -21
- package/dist/types/pipeline.js +1 -18
- package/hooks/claude/gitnexus-hook.cjs +52 -22
- package/package.json +3 -2
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Clone Utility
|
|
3
|
+
*
|
|
4
|
+
* Shallow-clones repositories into ~/.gitnexus/repos/{name}/.
|
|
5
|
+
* If already cloned, does git pull instead.
|
|
6
|
+
*/
|
|
7
|
+
/** Extract the repository name from a git URL (HTTPS or SSH). */
|
|
8
|
+
export declare function extractRepoName(url: string): string;
|
|
9
|
+
/** Get the clone target directory for a repo name. */
|
|
10
|
+
export declare function getCloneDir(repoName: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Validate a git URL to prevent SSRF attacks.
|
|
13
|
+
* Only allows https:// and http:// schemes. Blocks private/internal addresses.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateGitUrl(url: string): void;
|
|
16
|
+
export interface CloneProgress {
|
|
17
|
+
phase: 'cloning' | 'pulling';
|
|
18
|
+
message: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Clone or pull a git repository.
|
|
22
|
+
* If targetDir doesn't exist: git clone --depth 1
|
|
23
|
+
* If targetDir exists with .git: git pull --ff-only
|
|
24
|
+
*/
|
|
25
|
+
export declare function cloneOrPull(url: string, targetDir: string, onProgress?: (progress: CloneProgress) => void): Promise<string>;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git Clone Utility
|
|
3
|
+
*
|
|
4
|
+
* Shallow-clones repositories into ~/.gitnexus/repos/{name}/.
|
|
5
|
+
* If already cloned, does git pull instead.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import os from 'os';
|
|
10
|
+
import fs from 'fs/promises';
|
|
11
|
+
/** Extract the repository name from a git URL (HTTPS or SSH). */
|
|
12
|
+
export function extractRepoName(url) {
|
|
13
|
+
const cleaned = url.replace(/\/+$/, '');
|
|
14
|
+
const lastSegment = cleaned.split(/[/:]/).pop() || 'unknown';
|
|
15
|
+
return lastSegment.replace(/\.git$/, '');
|
|
16
|
+
}
|
|
17
|
+
/** Get the clone target directory for a repo name. */
|
|
18
|
+
export function getCloneDir(repoName) {
|
|
19
|
+
return path.join(os.homedir(), '.gitnexus', 'repos', repoName);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validate a git URL to prevent SSRF attacks.
|
|
23
|
+
* Only allows https:// and http:// schemes. Blocks private/internal addresses.
|
|
24
|
+
*/
|
|
25
|
+
export function validateGitUrl(url) {
|
|
26
|
+
let parsed;
|
|
27
|
+
try {
|
|
28
|
+
parsed = new URL(url);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error('Invalid URL');
|
|
32
|
+
}
|
|
33
|
+
if (!['https:', 'http:'].includes(parsed.protocol)) {
|
|
34
|
+
throw new Error('Only https:// and http:// git URLs are allowed');
|
|
35
|
+
}
|
|
36
|
+
const host = parsed.hostname.toLowerCase();
|
|
37
|
+
if (host === 'localhost' ||
|
|
38
|
+
host === '[::1]' ||
|
|
39
|
+
/^127\./.test(host) ||
|
|
40
|
+
/^10\./.test(host) ||
|
|
41
|
+
/^172\.(1[6-9]|2\d|3[01])\./.test(host) ||
|
|
42
|
+
/^192\.168\./.test(host) ||
|
|
43
|
+
/^169\.254\./.test(host) ||
|
|
44
|
+
/^0\./.test(host)) {
|
|
45
|
+
throw new Error('Cloning from private/internal addresses is not allowed');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Clone or pull a git repository.
|
|
50
|
+
* If targetDir doesn't exist: git clone --depth 1
|
|
51
|
+
* If targetDir exists with .git: git pull --ff-only
|
|
52
|
+
*/
|
|
53
|
+
export async function cloneOrPull(url, targetDir, onProgress) {
|
|
54
|
+
const exists = await fs.access(path.join(targetDir, '.git')).then(() => true, () => false);
|
|
55
|
+
if (exists) {
|
|
56
|
+
onProgress?.({ phase: 'pulling', message: 'Pulling latest changes...' });
|
|
57
|
+
await runGit(['pull', '--ff-only'], targetDir);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
validateGitUrl(url);
|
|
61
|
+
await fs.mkdir(path.dirname(targetDir), { recursive: true });
|
|
62
|
+
onProgress?.({ phase: 'cloning', message: `Cloning ${url}...` });
|
|
63
|
+
await runGit(['clone', '--depth', '1', url, targetDir]);
|
|
64
|
+
}
|
|
65
|
+
return targetDir;
|
|
66
|
+
}
|
|
67
|
+
function runGit(args, cwd) {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
const proc = spawn('git', args, {
|
|
70
|
+
cwd,
|
|
71
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
72
|
+
});
|
|
73
|
+
let stderr = '';
|
|
74
|
+
proc.stderr.on('data', (chunk) => {
|
|
75
|
+
stderr += chunk;
|
|
76
|
+
});
|
|
77
|
+
proc.on('close', (code) => {
|
|
78
|
+
if (code === 0)
|
|
79
|
+
resolve();
|
|
80
|
+
else {
|
|
81
|
+
// Log full stderr internally but don't expose it to API callers (SSRF mitigation)
|
|
82
|
+
if (stderr.trim())
|
|
83
|
+
console.error(`git ${args[0]} stderr: ${stderr.trim()}`);
|
|
84
|
+
reject(new Error(`git ${args[0]} failed (exit code ${code})`));
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
proc.on('error', (err) => {
|
|
88
|
+
reject(new Error(`Failed to spawn git: ${err.message}`));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
package/dist/storage/git.js
CHANGED
|
@@ -24,9 +24,7 @@ export const getCurrentCommit = (repoPath) => {
|
|
|
24
24
|
*/
|
|
25
25
|
export const getGitRoot = (fromPath) => {
|
|
26
26
|
try {
|
|
27
|
-
const raw = execSync('git rev-parse --show-toplevel', { cwd: fromPath })
|
|
28
|
-
.toString()
|
|
29
|
-
.trim();
|
|
27
|
+
const raw = execSync('git rev-parse --show-toplevel', { cwd: fromPath }).toString().trim();
|
|
30
28
|
// On Windows, git returns /d/Projects/Foo — path.resolve normalizes to D:\Projects\Foo
|
|
31
29
|
return path.resolve(raw);
|
|
32
30
|
}
|
|
@@ -119,13 +119,16 @@ export declare const unregisterRepo: (repoPath: string) => Promise<void>;
|
|
|
119
119
|
export declare const listRegisteredRepos: (opts?: {
|
|
120
120
|
validate?: boolean;
|
|
121
121
|
}) => Promise<RegistryEntry[]>;
|
|
122
|
-
export type LLMProvider = 'openai' | 'cursor';
|
|
123
122
|
export interface CLIConfig {
|
|
124
123
|
apiKey?: string;
|
|
125
124
|
model?: string;
|
|
126
125
|
baseUrl?: string;
|
|
127
|
-
provider?:
|
|
126
|
+
provider?: 'openai' | 'openrouter' | 'azure' | 'custom' | 'cursor';
|
|
128
127
|
cursorModel?: string;
|
|
128
|
+
/** Azure api-version query param (e.g. '2024-10-21'). Only used when provider is 'azure'. */
|
|
129
|
+
apiVersion?: string;
|
|
130
|
+
/** Set true when the deployment is a reasoning model (o1, o3, o4-mini). Auto-detected for OpenAI; must be set for Azure deployments. */
|
|
131
|
+
isReasoningModel?: boolean;
|
|
129
132
|
}
|
|
130
133
|
/**
|
|
131
134
|
* Get the path to the global CLI config file
|
|
@@ -208,9 +208,7 @@ export const registerRepo = async (repoPath, meta) => {
|
|
|
208
208
|
const existing = entries.findIndex((e) => {
|
|
209
209
|
const a = path.resolve(e.path);
|
|
210
210
|
const b = resolved;
|
|
211
|
-
return process.platform === 'win32'
|
|
212
|
-
? a.toLowerCase() === b.toLowerCase()
|
|
213
|
-
: a === b;
|
|
211
|
+
return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
214
212
|
});
|
|
215
213
|
const entry = {
|
|
216
214
|
name,
|
|
@@ -294,6 +292,8 @@ export const saveCLIConfig = async (config) => {
|
|
|
294
292
|
try {
|
|
295
293
|
await fs.chmod(configPath, 0o600);
|
|
296
294
|
}
|
|
297
|
-
catch {
|
|
295
|
+
catch {
|
|
296
|
+
/* best-effort */
|
|
297
|
+
}
|
|
298
298
|
}
|
|
299
299
|
};
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { KnowledgeGraph } from '../core/graph/types.js';
|
|
2
2
|
import { CommunityDetectionResult } from '../core/ingestion/community-processor.js';
|
|
3
3
|
import { ProcessDetectionResult } from '../core/ingestion/process-processor.js';
|
|
4
|
-
export type PipelinePhase = 'idle' | 'extracting' | 'structure' | 'parsing' | 'imports' | 'calls' | 'heritage' | 'communities' | 'processes' | 'enriching' | 'complete' | 'error';
|
|
5
|
-
export interface PipelineProgress {
|
|
6
|
-
phase: PipelinePhase;
|
|
7
|
-
percent: number;
|
|
8
|
-
message: string;
|
|
9
|
-
detail?: string;
|
|
10
|
-
stats?: {
|
|
11
|
-
filesProcessed: number;
|
|
12
|
-
totalFiles: number;
|
|
13
|
-
nodesCreated: number;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
4
|
export interface PipelineResult {
|
|
17
5
|
graph: KnowledgeGraph;
|
|
18
6
|
/** Absolute path to the repo root — used for lazy file reads during LadybugDB loading */
|
|
@@ -22,11 +10,3 @@ export interface PipelineResult {
|
|
|
22
10
|
communityResult?: CommunityDetectionResult;
|
|
23
11
|
processResult?: ProcessDetectionResult;
|
|
24
12
|
}
|
|
25
|
-
export interface SerializablePipelineResult {
|
|
26
|
-
nodes: GraphNode[];
|
|
27
|
-
relationships: GraphRelationship[];
|
|
28
|
-
repoPath: string;
|
|
29
|
-
totalFileCount: number;
|
|
30
|
-
}
|
|
31
|
-
export declare const serializePipelineResult: (result: PipelineResult) => SerializablePipelineResult;
|
|
32
|
-
export declare const deserializePipelineResult: (serialized: SerializablePipelineResult, createGraph: () => KnowledgeGraph) => PipelineResult;
|
package/dist/types/pipeline.js
CHANGED
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export const serializePipelineResult = (result) => ({
|
|
3
|
-
nodes: [...result.graph.iterNodes()],
|
|
4
|
-
relationships: [...result.graph.iterRelationships()],
|
|
5
|
-
repoPath: result.repoPath,
|
|
6
|
-
totalFileCount: result.totalFileCount,
|
|
7
|
-
});
|
|
8
|
-
// Helper to reconstruct from serializable format (used in main thread)
|
|
9
|
-
export const deserializePipelineResult = (serialized, createGraph) => {
|
|
10
|
-
const graph = createGraph();
|
|
11
|
-
serialized.nodes.forEach(node => graph.addNode(node));
|
|
12
|
-
serialized.relationships.forEach(rel => graph.addRelationship(rel));
|
|
13
|
-
return {
|
|
14
|
-
graph,
|
|
15
|
-
repoPath: serialized.repoPath,
|
|
16
|
-
totalFileCount: serialized.totalFileCount,
|
|
17
|
-
};
|
|
18
|
-
};
|
|
1
|
+
export {};
|
|
@@ -64,10 +64,26 @@ function extractPattern(toolName, toolInput) {
|
|
|
64
64
|
const tokens = cmd.split(/\s+/);
|
|
65
65
|
let foundCmd = false;
|
|
66
66
|
let skipNext = false;
|
|
67
|
-
const flagsWithValues = new Set([
|
|
67
|
+
const flagsWithValues = new Set([
|
|
68
|
+
'-e',
|
|
69
|
+
'-f',
|
|
70
|
+
'-m',
|
|
71
|
+
'-A',
|
|
72
|
+
'-B',
|
|
73
|
+
'-C',
|
|
74
|
+
'-g',
|
|
75
|
+
'--glob',
|
|
76
|
+
'-t',
|
|
77
|
+
'--type',
|
|
78
|
+
'--include',
|
|
79
|
+
'--exclude',
|
|
80
|
+
]);
|
|
68
81
|
|
|
69
82
|
for (const token of tokens) {
|
|
70
|
-
if (skipNext) {
|
|
83
|
+
if (skipNext) {
|
|
84
|
+
skipNext = false;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
71
87
|
if (!foundCmd) {
|
|
72
88
|
if (/\brg$|\bgrep$/.test(token)) foundCmd = true;
|
|
73
89
|
continue;
|
|
@@ -110,18 +126,20 @@ function resolveCliPath() {
|
|
|
110
126
|
function runGitNexusCli(cliPath, args, cwd, timeout) {
|
|
111
127
|
const isWin = process.platform === 'win32';
|
|
112
128
|
if (cliPath) {
|
|
113
|
-
return spawnSync(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
129
|
+
return spawnSync(process.execPath, [cliPath, ...args], {
|
|
130
|
+
encoding: 'utf-8',
|
|
131
|
+
timeout,
|
|
132
|
+
cwd,
|
|
133
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
134
|
+
});
|
|
118
135
|
}
|
|
119
136
|
// On Windows, invoke npx.cmd directly (no shell needed)
|
|
120
|
-
return spawnSync(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
137
|
+
return spawnSync(isWin ? 'npx.cmd' : 'npx', ['-y', 'gitnexus', ...args], {
|
|
138
|
+
encoding: 'utf-8',
|
|
139
|
+
timeout: timeout + 5000,
|
|
140
|
+
cwd,
|
|
141
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
142
|
+
});
|
|
125
143
|
}
|
|
126
144
|
|
|
127
145
|
/**
|
|
@@ -147,7 +165,9 @@ function handlePreToolUse(input) {
|
|
|
147
165
|
if (!child.error && child.status === 0) {
|
|
148
166
|
result = child.stderr || '';
|
|
149
167
|
}
|
|
150
|
-
} catch {
|
|
168
|
+
} catch {
|
|
169
|
+
/* graceful failure */
|
|
170
|
+
}
|
|
151
171
|
|
|
152
172
|
if (result && result.trim()) {
|
|
153
173
|
sendHookResponse('PreToolUse', result.trim());
|
|
@@ -158,9 +178,11 @@ function handlePreToolUse(input) {
|
|
|
158
178
|
* Emit a PostToolUse hook response with additional context for the agent.
|
|
159
179
|
*/
|
|
160
180
|
function sendHookResponse(hookEventName, message) {
|
|
161
|
-
console.log(
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
console.log(
|
|
182
|
+
JSON.stringify({
|
|
183
|
+
hookSpecificOutput: { hookEventName, additionalContext: message },
|
|
184
|
+
}),
|
|
185
|
+
);
|
|
164
186
|
}
|
|
165
187
|
|
|
166
188
|
/**
|
|
@@ -192,10 +214,15 @@ function handlePostToolUse(input) {
|
|
|
192
214
|
let currentHead = '';
|
|
193
215
|
try {
|
|
194
216
|
const headResult = spawnSync('git', ['rev-parse', 'HEAD'], {
|
|
195
|
-
encoding: 'utf-8',
|
|
217
|
+
encoding: 'utf-8',
|
|
218
|
+
timeout: 3000,
|
|
219
|
+
cwd,
|
|
220
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
196
221
|
});
|
|
197
222
|
currentHead = (headResult.stdout || '').trim();
|
|
198
|
-
} catch {
|
|
223
|
+
} catch {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
199
226
|
|
|
200
227
|
if (!currentHead) return;
|
|
201
228
|
|
|
@@ -204,16 +231,19 @@ function handlePostToolUse(input) {
|
|
|
204
231
|
try {
|
|
205
232
|
const meta = JSON.parse(fs.readFileSync(path.join(gitNexusDir, 'meta.json'), 'utf-8'));
|
|
206
233
|
lastCommit = meta.lastCommit || '';
|
|
207
|
-
hadEmbeddings =
|
|
208
|
-
} catch {
|
|
234
|
+
hadEmbeddings = meta.stats && meta.stats.embeddings > 0;
|
|
235
|
+
} catch {
|
|
236
|
+
/* no meta — treat as stale */
|
|
237
|
+
}
|
|
209
238
|
|
|
210
239
|
// If HEAD matches last indexed commit, no reindex needed
|
|
211
240
|
if (currentHead && currentHead === lastCommit) return;
|
|
212
241
|
|
|
213
242
|
const analyzeCmd = `npx gitnexus analyze${hadEmbeddings ? ' --embeddings' : ''}`;
|
|
214
|
-
sendHookResponse(
|
|
243
|
+
sendHookResponse(
|
|
244
|
+
'PostToolUse',
|
|
215
245
|
`GitNexus index is stale (last indexed: ${lastCommit ? lastCommit.slice(0, 7) : 'never'}). ` +
|
|
216
|
-
|
|
246
|
+
`Run \`${analyzeCmd}\` to update the knowledge graph.`,
|
|
217
247
|
);
|
|
218
248
|
}
|
|
219
249
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitnexus",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
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,7 @@
|
|
|
39
39
|
],
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc",
|
|
42
|
+
"serve": "tsx src/cli/index.ts serve",
|
|
42
43
|
"dev": "tsx watch src/cli/index.ts",
|
|
43
44
|
"test": "vitest run",
|
|
44
45
|
"test:unit": "vitest run test/unit",
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"prepack": "npm run build && chmod +x dist/cli/index.js"
|
|
50
51
|
},
|
|
51
52
|
"dependencies": {
|
|
53
|
+
"gitnexus-shared": "file:../gitnexus-shared",
|
|
52
54
|
"@huggingface/transformers": "^3.0.0",
|
|
53
55
|
"@ladybugdb/core": "^0.15.2",
|
|
54
56
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
@@ -91,7 +93,6 @@
|
|
|
91
93
|
"@types/node": "^20.0.0",
|
|
92
94
|
"@types/uuid": "^10.0.0",
|
|
93
95
|
"@vitest/coverage-v8": "^4.0.18",
|
|
94
|
-
"husky": "^9.1.7",
|
|
95
96
|
"tsx": "^4.0.0",
|
|
96
97
|
"typescript": "^5.4.5",
|
|
97
98
|
"vitest": "^4.0.18"
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language Detection — maps file paths to SupportedLanguages enum values.
|
|
3
|
-
*/
|
|
4
|
-
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
5
|
-
/**
|
|
6
|
-
* Map file extension to SupportedLanguage enum.
|
|
7
|
-
* Returns null if the file extension is not recognized.
|
|
8
|
-
*/
|
|
9
|
-
export declare const getLanguageFromFilename: (filename: string) => SupportedLanguages | null;
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Language Detection — maps file paths to SupportedLanguages enum values.
|
|
3
|
-
*/
|
|
4
|
-
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
|
5
|
-
/** Ruby extensionless filenames recognised as Ruby source */
|
|
6
|
-
const RUBY_EXTENSIONLESS_FILES = new Set(['Rakefile', 'Gemfile', 'Guardfile', 'Vagrantfile', 'Brewfile']);
|
|
7
|
-
/**
|
|
8
|
-
* Map file extension to SupportedLanguage enum.
|
|
9
|
-
* Returns null if the file extension is not recognized.
|
|
10
|
-
*/
|
|
11
|
-
export const getLanguageFromFilename = (filename) => {
|
|
12
|
-
// TypeScript (including TSX)
|
|
13
|
-
if (filename.endsWith('.tsx'))
|
|
14
|
-
return SupportedLanguages.TypeScript;
|
|
15
|
-
if (filename.endsWith('.ts'))
|
|
16
|
-
return SupportedLanguages.TypeScript;
|
|
17
|
-
// JavaScript (including JSX)
|
|
18
|
-
if (filename.endsWith('.jsx'))
|
|
19
|
-
return SupportedLanguages.JavaScript;
|
|
20
|
-
if (filename.endsWith('.js'))
|
|
21
|
-
return SupportedLanguages.JavaScript;
|
|
22
|
-
// Python
|
|
23
|
-
if (filename.endsWith('.py'))
|
|
24
|
-
return SupportedLanguages.Python;
|
|
25
|
-
// Java
|
|
26
|
-
if (filename.endsWith('.java'))
|
|
27
|
-
return SupportedLanguages.Java;
|
|
28
|
-
// C source files
|
|
29
|
-
if (filename.endsWith('.c'))
|
|
30
|
-
return SupportedLanguages.C;
|
|
31
|
-
// C++ (all common extensions, including .h)
|
|
32
|
-
// .h is parsed as C++ because tree-sitter-cpp is a strict superset of C, so pure-C
|
|
33
|
-
// headers parse correctly, and C++ headers (classes, templates) are handled properly.
|
|
34
|
-
if (filename.endsWith('.cpp') || filename.endsWith('.cc') || filename.endsWith('.cxx') ||
|
|
35
|
-
filename.endsWith('.h') || filename.endsWith('.hpp') || filename.endsWith('.hxx') || filename.endsWith('.hh'))
|
|
36
|
-
return SupportedLanguages.CPlusPlus;
|
|
37
|
-
// C#
|
|
38
|
-
if (filename.endsWith('.cs'))
|
|
39
|
-
return SupportedLanguages.CSharp;
|
|
40
|
-
// Go
|
|
41
|
-
if (filename.endsWith('.go'))
|
|
42
|
-
return SupportedLanguages.Go;
|
|
43
|
-
// Rust
|
|
44
|
-
if (filename.endsWith('.rs'))
|
|
45
|
-
return SupportedLanguages.Rust;
|
|
46
|
-
// Kotlin
|
|
47
|
-
if (filename.endsWith('.kt') || filename.endsWith('.kts'))
|
|
48
|
-
return SupportedLanguages.Kotlin;
|
|
49
|
-
// PHP (all common extensions)
|
|
50
|
-
if (filename.endsWith('.php') || filename.endsWith('.phtml') ||
|
|
51
|
-
filename.endsWith('.php3') || filename.endsWith('.php4') ||
|
|
52
|
-
filename.endsWith('.php5') || filename.endsWith('.php8')) {
|
|
53
|
-
return SupportedLanguages.PHP;
|
|
54
|
-
}
|
|
55
|
-
// Ruby (extensions)
|
|
56
|
-
if (filename.endsWith('.rb') || filename.endsWith('.rake') || filename.endsWith('.gemspec')) {
|
|
57
|
-
return SupportedLanguages.Ruby;
|
|
58
|
-
}
|
|
59
|
-
// Ruby (extensionless files)
|
|
60
|
-
const basename = filename.split('/').pop() || filename;
|
|
61
|
-
if (RUBY_EXTENSIONLESS_FILES.has(basename)) {
|
|
62
|
-
return SupportedLanguages.Ruby;
|
|
63
|
-
}
|
|
64
|
-
// Swift (extensions)
|
|
65
|
-
if (filename.endsWith('.swift'))
|
|
66
|
-
return SupportedLanguages.Swift;
|
|
67
|
-
if (filename.endsWith('.dart'))
|
|
68
|
-
return SupportedLanguages.Dart;
|
|
69
|
-
return null;
|
|
70
|
-
};
|