gitnexus 1.4.10 → 1.5.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 +6 -5
- package/dist/_shared/graph/types.d.ts +65 -0
- package/dist/_shared/graph/types.d.ts.map +1 -0
- package/dist/_shared/graph/types.js +8 -0
- package/dist/_shared/graph/types.js.map +1 -0
- package/dist/_shared/index.d.ts +7 -0
- package/dist/_shared/index.d.ts.map +1 -0
- package/dist/_shared/index.js +6 -0
- package/dist/_shared/index.js.map +1 -0
- package/dist/_shared/language-detection.d.ts +23 -0
- package/dist/_shared/language-detection.d.ts.map +1 -0
- package/dist/_shared/language-detection.js +137 -0
- package/dist/_shared/language-detection.js.map +1 -0
- package/dist/_shared/languages.d.ts +25 -0
- package/dist/_shared/languages.d.ts.map +1 -0
- package/dist/_shared/languages.js +26 -0
- package/dist/_shared/languages.js.map +1 -0
- package/dist/_shared/lbug/schema-constants.d.ts +16 -0
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -0
- package/dist/_shared/lbug/schema-constants.js +64 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -0
- package/dist/_shared/pipeline.d.ts +16 -0
- package/dist/_shared/pipeline.d.ts.map +1 -0
- package/dist/_shared/pipeline.js +5 -0
- package/dist/_shared/pipeline.js.map +1 -0
- 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 +5 -4
- package/scripts/build.js +69 -0
- package/dist/core/ingestion/utils/language-detection.d.ts +0 -9
- package/dist/core/ingestion/utils/language-detection.js +0 -70
package/dist/cli/analyze.js
CHANGED
|
@@ -2,21 +2,19 @@
|
|
|
2
2
|
* Analyze Command
|
|
3
3
|
*
|
|
4
4
|
* Indexes a repository and stores the knowledge graph in .gitnexus/
|
|
5
|
+
*
|
|
6
|
+
* Delegates core analysis to the shared runFullAnalysis orchestrator.
|
|
7
|
+
* This CLI wrapper handles: heap management, progress bar, SIGINT,
|
|
8
|
+
* skill generation (--skills), summary output, and process.exit().
|
|
5
9
|
*/
|
|
6
10
|
import path from 'path';
|
|
7
11
|
import { execFileSync } from 'child_process';
|
|
8
12
|
import v8 from 'v8';
|
|
9
13
|
import cliProgress from 'cli-progress';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// versions whose ABI is not yet supported by the native binary (#89).
|
|
15
|
-
// disposeEmbedder intentionally not called — ONNX Runtime segfaults on cleanup (see #38)
|
|
16
|
-
import { getStoragePaths, saveMeta, loadMeta, addToGitignore, registerRepo, getGlobalRegistryPath, cleanupOldKuzuFiles } from '../storage/repo-manager.js';
|
|
17
|
-
import { getCurrentCommit, getGitRoot, hasGitDir } from '../storage/git.js';
|
|
18
|
-
import { generateAIContextFiles } from './ai-context.js';
|
|
19
|
-
import { generateSkillFiles } from './skill-gen.js';
|
|
14
|
+
import { closeLbug } from '../core/lbug/lbug-adapter.js';
|
|
15
|
+
import { getStoragePaths, getGlobalRegistryPath } from '../storage/repo-manager.js';
|
|
16
|
+
import { getGitRoot, hasGitDir } from '../storage/git.js';
|
|
17
|
+
import { runFullAnalysis } from '../core/run-analyze.js';
|
|
20
18
|
import fs from 'fs/promises';
|
|
21
19
|
const HEAP_MB = 8192;
|
|
22
20
|
const HEAP_FLAG = `--max-old-space-size=${HEAP_MB}`;
|
|
@@ -39,23 +37,6 @@ function ensureHeap() {
|
|
|
39
37
|
}
|
|
40
38
|
return true;
|
|
41
39
|
}
|
|
42
|
-
/** Threshold: auto-skip embeddings for repos with more nodes than this */
|
|
43
|
-
const EMBEDDING_NODE_LIMIT = 50_000;
|
|
44
|
-
const PHASE_LABELS = {
|
|
45
|
-
extracting: 'Scanning files',
|
|
46
|
-
structure: 'Building structure',
|
|
47
|
-
parsing: 'Parsing code',
|
|
48
|
-
imports: 'Resolving imports',
|
|
49
|
-
calls: 'Tracing calls',
|
|
50
|
-
heritage: 'Extracting inheritance',
|
|
51
|
-
communities: 'Detecting communities',
|
|
52
|
-
processes: 'Detecting processes',
|
|
53
|
-
complete: 'Pipeline complete',
|
|
54
|
-
lbug: 'Loading into LadybugDB',
|
|
55
|
-
fts: 'Creating search indexes',
|
|
56
|
-
embeddings: 'Generating embeddings',
|
|
57
|
-
done: 'Done',
|
|
58
|
-
};
|
|
59
40
|
export const analyzeCommand = async (inputPath, options) => {
|
|
60
41
|
if (ensureHeap())
|
|
61
42
|
return;
|
|
@@ -91,26 +72,12 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
91
72
|
if (!repoHasGit) {
|
|
92
73
|
console.log(' Warning: no .git directory found \u2014 commit-tracking and incremental updates disabled.\n');
|
|
93
74
|
}
|
|
94
|
-
|
|
95
|
-
//
|
|
96
|
-
// If kuzu existed but lbug doesn't, we're doing a migration re-index — say so.
|
|
97
|
-
const kuzuResult = await cleanupOldKuzuFiles(storagePath);
|
|
98
|
-
if (kuzuResult.found && kuzuResult.needsReindex) {
|
|
99
|
-
console.log(' Migrating from KuzuDB to LadybugDB — rebuilding index...\n');
|
|
100
|
-
}
|
|
101
|
-
const currentCommit = repoHasGit ? getCurrentCommit(repoPath) : '';
|
|
102
|
-
const existingMeta = await loadMeta(storagePath);
|
|
103
|
-
if (existingMeta && !options?.force && !options?.skills && existingMeta.lastCommit === currentCommit) {
|
|
104
|
-
// Non-git folders have currentCommit = '' — always rebuild since we can't detect changes
|
|
105
|
-
if (currentCommit !== '') {
|
|
106
|
-
console.log(' Already up to date\n');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
75
|
+
// KuzuDB migration cleanup is handled by runFullAnalysis internally.
|
|
76
|
+
// Note: --skills is handled after runFullAnalysis using the returned pipelineResult.
|
|
110
77
|
if (process.env.GITNEXUS_NO_GITIGNORE) {
|
|
111
78
|
console.log(' GITNEXUS_NO_GITIGNORE is set — skipping .gitignore (still reading .gitnexusignore)\n');
|
|
112
79
|
}
|
|
113
|
-
//
|
|
80
|
+
// ── CLI progress bar setup ─────────────────────────────────────────
|
|
114
81
|
const bar = new cliProgress.SingleBar({
|
|
115
82
|
format: ' {bar} {percentage}% | {phase}',
|
|
116
83
|
barCompleteChar: '\u2588',
|
|
@@ -122,35 +89,33 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
122
89
|
stopOnComplete: false,
|
|
123
90
|
}, cliProgress.Presets.shades_grey);
|
|
124
91
|
bar.start(100, 0, { phase: 'Initializing...' });
|
|
125
|
-
// Graceful SIGINT handling
|
|
92
|
+
// Graceful SIGINT handling
|
|
126
93
|
let aborted = false;
|
|
127
94
|
const sigintHandler = () => {
|
|
128
95
|
if (aborted)
|
|
129
|
-
process.exit(1);
|
|
96
|
+
process.exit(1);
|
|
130
97
|
aborted = true;
|
|
131
98
|
bar.stop();
|
|
132
99
|
console.log('\n Interrupted — cleaning up...');
|
|
133
|
-
closeLbug()
|
|
100
|
+
closeLbug()
|
|
101
|
+
.catch(() => { })
|
|
102
|
+
.finally(() => process.exit(130));
|
|
134
103
|
};
|
|
135
104
|
process.on('SIGINT', sigintHandler);
|
|
136
|
-
// Route
|
|
137
|
-
// multiple times when other code writes to stdout/stderr mid-render.
|
|
105
|
+
// Route console output through bar.log() to prevent progress bar corruption
|
|
138
106
|
const origLog = console.log.bind(console);
|
|
139
107
|
const origWarn = console.warn.bind(console);
|
|
140
108
|
const origError = console.error.bind(console);
|
|
141
109
|
const barLog = (...args) => {
|
|
142
|
-
// Clear the bar line, print the message, then let the next bar.update redraw
|
|
143
110
|
process.stdout.write('\x1b[2K\r');
|
|
144
|
-
origLog(args.map(a => (typeof a === 'string' ? a : String(a))).join(' '));
|
|
111
|
+
origLog(args.map((a) => (typeof a === 'string' ? a : String(a))).join(' '));
|
|
145
112
|
};
|
|
146
113
|
console.log = barLog;
|
|
147
114
|
console.warn = barLog;
|
|
148
115
|
console.error = barLog;
|
|
149
|
-
// Track elapsed time per phase
|
|
150
|
-
// same format so they don't flicker against each other.
|
|
116
|
+
// Track elapsed time per phase
|
|
151
117
|
let lastPhaseLabel = 'Initializing...';
|
|
152
118
|
let phaseStart = Date.now();
|
|
153
|
-
/** Update bar with phase label + elapsed seconds (shown after 3s). */
|
|
154
119
|
const updateBar = (value, phaseLabel) => {
|
|
155
120
|
if (phaseLabel !== lastPhaseLabel) {
|
|
156
121
|
lastPhaseLabel = phaseLabel;
|
|
@@ -160,217 +125,106 @@ export const analyzeCommand = async (inputPath, options) => {
|
|
|
160
125
|
const display = elapsed >= 3 ? `${phaseLabel} (${elapsed}s)` : phaseLabel;
|
|
161
126
|
bar.update(value, { phase: display });
|
|
162
127
|
};
|
|
163
|
-
// Tick elapsed seconds for phases with infrequent progress callbacks
|
|
164
|
-
// (e.g. CSV streaming, FTS indexing). Uses the same display format as
|
|
165
|
-
// updateBar so there's no flickering.
|
|
166
128
|
const elapsedTimer = setInterval(() => {
|
|
167
129
|
const elapsed = Math.round((Date.now() - phaseStart) / 1000);
|
|
168
130
|
if (elapsed >= 3) {
|
|
169
131
|
bar.update({ phase: `${lastPhaseLabel} (${elapsed}s)` });
|
|
170
132
|
}
|
|
171
133
|
}, 1000);
|
|
172
|
-
const
|
|
173
|
-
// ──
|
|
174
|
-
let cachedEmbeddingNodeIds = new Set();
|
|
175
|
-
let cachedEmbeddings = [];
|
|
176
|
-
if (options?.embeddings && existingMeta && !options?.force) {
|
|
177
|
-
try {
|
|
178
|
-
updateBar(0, 'Caching embeddings...');
|
|
179
|
-
await initLbug(lbugPath);
|
|
180
|
-
const cached = await loadCachedEmbeddings();
|
|
181
|
-
cachedEmbeddingNodeIds = cached.embeddingNodeIds;
|
|
182
|
-
cachedEmbeddings = cached.embeddings;
|
|
183
|
-
await closeLbug();
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
try {
|
|
187
|
-
await closeLbug();
|
|
188
|
-
}
|
|
189
|
-
catch { }
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
// ── Phase 1: Full Pipeline (0–60%) ─────────────────────────────────
|
|
193
|
-
const pipelineResult = await runPipelineFromRepo(repoPath, (progress) => {
|
|
194
|
-
const phaseLabel = PHASE_LABELS[progress.phase] || progress.phase;
|
|
195
|
-
const scaled = Math.round(progress.percent * 0.6);
|
|
196
|
-
updateBar(scaled, phaseLabel);
|
|
197
|
-
});
|
|
198
|
-
// ── Phase 2: LadybugDB (60–85%) ──────────────────────────────────────
|
|
199
|
-
updateBar(60, 'Loading into LadybugDB...');
|
|
200
|
-
await closeLbug();
|
|
201
|
-
const lbugFiles = [lbugPath, `${lbugPath}.wal`, `${lbugPath}.lock`];
|
|
202
|
-
for (const f of lbugFiles) {
|
|
203
|
-
try {
|
|
204
|
-
await fs.rm(f, { recursive: true, force: true });
|
|
205
|
-
}
|
|
206
|
-
catch { }
|
|
207
|
-
}
|
|
208
|
-
const t0Lbug = Date.now();
|
|
209
|
-
await initLbug(lbugPath);
|
|
210
|
-
let lbugMsgCount = 0;
|
|
211
|
-
const lbugResult = await loadGraphToLbug(pipelineResult.graph, pipelineResult.repoPath, storagePath, (msg) => {
|
|
212
|
-
lbugMsgCount++;
|
|
213
|
-
const progress = Math.min(84, 60 + Math.round((lbugMsgCount / (lbugMsgCount + 10)) * 24));
|
|
214
|
-
updateBar(progress, msg);
|
|
215
|
-
});
|
|
216
|
-
const lbugTime = ((Date.now() - t0Lbug) / 1000).toFixed(1);
|
|
217
|
-
const lbugWarnings = lbugResult.warnings;
|
|
218
|
-
// ── Phase 3: FTS (85–90%) ─────────────────────────────────────────
|
|
219
|
-
updateBar(85, 'Creating search indexes...');
|
|
220
|
-
const t0Fts = Date.now();
|
|
134
|
+
const t0 = Date.now();
|
|
135
|
+
// ── Run shared analysis orchestrator ───────────────────────────────
|
|
221
136
|
try {
|
|
222
|
-
await
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
137
|
+
const result = await runFullAnalysis(repoPath, {
|
|
138
|
+
force: options?.force || options?.skills,
|
|
139
|
+
embeddings: options?.embeddings,
|
|
140
|
+
skipGit: options?.skipGit,
|
|
141
|
+
skipAgentsMd: options?.skipAgentsMd,
|
|
142
|
+
}, {
|
|
143
|
+
onProgress: (_phase, percent, message) => {
|
|
144
|
+
updateBar(percent, message);
|
|
145
|
+
},
|
|
146
|
+
onLog: barLog,
|
|
147
|
+
});
|
|
148
|
+
if (result.alreadyUpToDate) {
|
|
149
|
+
clearInterval(elapsedTimer);
|
|
150
|
+
process.removeListener('SIGINT', sigintHandler);
|
|
151
|
+
console.log = origLog;
|
|
152
|
+
console.warn = origWarn;
|
|
153
|
+
console.error = origError;
|
|
154
|
+
bar.stop();
|
|
155
|
+
console.log(' Already up to date\n');
|
|
156
|
+
// Safe to return without process.exit(0) — the early-return path in
|
|
157
|
+
// runFullAnalysis never opens LadybugDB, so no native handles prevent exit.
|
|
158
|
+
return;
|
|
242
159
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
160
|
+
// Skill generation (CLI-only, uses pipeline result from analysis)
|
|
161
|
+
if (options?.skills && result.pipelineResult) {
|
|
162
|
+
updateBar(99, 'Generating skill files...');
|
|
163
|
+
try {
|
|
164
|
+
const { generateSkillFiles } = await import('./skill-gen.js');
|
|
165
|
+
const { generateAIContextFiles } = await import('./ai-context.js');
|
|
166
|
+
const skillResult = await generateSkillFiles(repoPath, result.repoName, result.pipelineResult);
|
|
167
|
+
if (skillResult.skills.length > 0) {
|
|
168
|
+
barLog(` Generated ${skillResult.skills.length} skill files`);
|
|
169
|
+
// Re-generate AI context files now that we have skill info
|
|
170
|
+
const s = result.stats;
|
|
171
|
+
const communityResult = result.pipelineResult?.communityResult;
|
|
172
|
+
let aggregatedClusterCount = 0;
|
|
173
|
+
if (communityResult?.communities) {
|
|
174
|
+
const groups = new Map();
|
|
175
|
+
for (const c of communityResult.communities) {
|
|
176
|
+
const label = c.heuristicLabel || c.label || 'Unknown';
|
|
177
|
+
groups.set(label, (groups.get(label) || 0) + c.symbolCount);
|
|
178
|
+
}
|
|
179
|
+
aggregatedClusterCount = Array.from(groups.values()).filter((count) => count >= 5).length;
|
|
180
|
+
}
|
|
181
|
+
const { storagePath: sp } = getStoragePaths(repoPath);
|
|
182
|
+
await generateAIContextFiles(repoPath, sp, result.repoName, {
|
|
183
|
+
files: s.files ?? 0,
|
|
184
|
+
nodes: s.nodes ?? 0,
|
|
185
|
+
edges: s.edges ?? 0,
|
|
186
|
+
communities: s.communities,
|
|
187
|
+
clusters: aggregatedClusterCount,
|
|
188
|
+
processes: s.processes,
|
|
189
|
+
}, skillResult.skills, { skipAgentsMd: options?.skipAgentsMd });
|
|
251
190
|
}
|
|
252
|
-
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
/* best-effort */
|
|
253
194
|
}
|
|
254
195
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
196
|
+
const totalTime = ((Date.now() - t0) / 1000).toFixed(1);
|
|
197
|
+
clearInterval(elapsedTimer);
|
|
198
|
+
process.removeListener('SIGINT', sigintHandler);
|
|
199
|
+
console.log = origLog;
|
|
200
|
+
console.warn = origWarn;
|
|
201
|
+
console.error = origError;
|
|
202
|
+
bar.update(100, { phase: 'Done' });
|
|
203
|
+
bar.stop();
|
|
204
|
+
// ── Summary ────────────────────────────────────────────────────
|
|
205
|
+
const s = result.stats;
|
|
206
|
+
console.log(`\n Repository indexed successfully (${totalTime}s)\n`);
|
|
207
|
+
console.log(` ${(s.nodes ?? 0).toLocaleString()} nodes | ${(s.edges ?? 0).toLocaleString()} edges | ${s.communities ?? 0} clusters | ${s.processes ?? 0} flows`);
|
|
208
|
+
console.log(` ${repoPath}`);
|
|
209
|
+
try {
|
|
210
|
+
await fs.access(getGlobalRegistryPath());
|
|
267
211
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const { isHttpMode } = await import('../core/embeddings/http-client.js');
|
|
271
|
-
const httpMode = isHttpMode();
|
|
272
|
-
updateBar(90, httpMode ? 'Connecting to embedding endpoint...' : 'Loading embedding model...');
|
|
273
|
-
const t0Emb = Date.now();
|
|
274
|
-
const { runEmbeddingPipeline } = await import('../core/embeddings/embedding-pipeline.js');
|
|
275
|
-
await runEmbeddingPipeline(executeQuery, executeWithReusedStatement, (progress) => {
|
|
276
|
-
const scaled = 90 + Math.round((progress.percent / 100) * 8);
|
|
277
|
-
const label = progress.phase === 'loading-model'
|
|
278
|
-
? (httpMode ? 'Connecting to embedding endpoint...' : 'Loading embedding model...')
|
|
279
|
-
: `Embedding ${progress.nodesProcessed || 0}/${progress.totalNodes || '?'}`;
|
|
280
|
-
updateBar(scaled, label);
|
|
281
|
-
}, {}, cachedEmbeddingNodeIds.size > 0 ? cachedEmbeddingNodeIds : undefined);
|
|
282
|
-
embeddingTime = ((Date.now() - t0Emb) / 1000).toFixed(1);
|
|
283
|
-
}
|
|
284
|
-
// ── Phase 5: Finalize (98–100%) ───────────────────────────────────
|
|
285
|
-
updateBar(98, 'Saving metadata...');
|
|
286
|
-
// Count embeddings in the index (cached + newly generated)
|
|
287
|
-
let embeddingCount = 0;
|
|
288
|
-
try {
|
|
289
|
-
const embResult = await executeQuery(`MATCH (e:CodeEmbedding) RETURN count(e) AS cnt`);
|
|
290
|
-
embeddingCount = embResult?.[0]?.cnt ?? 0;
|
|
291
|
-
}
|
|
292
|
-
catch { /* table may not exist if embeddings never ran */ }
|
|
293
|
-
const meta = {
|
|
294
|
-
repoPath,
|
|
295
|
-
lastCommit: currentCommit,
|
|
296
|
-
indexedAt: new Date().toISOString(),
|
|
297
|
-
stats: {
|
|
298
|
-
files: pipelineResult.totalFileCount,
|
|
299
|
-
nodes: stats.nodes,
|
|
300
|
-
edges: stats.edges,
|
|
301
|
-
communities: pipelineResult.communityResult?.stats.totalCommunities,
|
|
302
|
-
processes: pipelineResult.processResult?.stats.totalProcesses,
|
|
303
|
-
embeddings: embeddingCount,
|
|
304
|
-
},
|
|
305
|
-
};
|
|
306
|
-
await saveMeta(storagePath, meta);
|
|
307
|
-
await registerRepo(repoPath, meta);
|
|
308
|
-
// Only attempt to update .gitignore when a .git directory is present.
|
|
309
|
-
// Use hasGitDir (filesystem check) rather than git CLI subprocess
|
|
310
|
-
// so we skip correctly for --skip-git folders even if git CLI is available.
|
|
311
|
-
if (hasGitDir(repoPath)) {
|
|
312
|
-
await addToGitignore(repoPath);
|
|
313
|
-
}
|
|
314
|
-
const projectName = path.basename(repoPath);
|
|
315
|
-
let aggregatedClusterCount = 0;
|
|
316
|
-
if (pipelineResult.communityResult?.communities) {
|
|
317
|
-
const groups = new Map();
|
|
318
|
-
for (const c of pipelineResult.communityResult.communities) {
|
|
319
|
-
const label = c.heuristicLabel || c.label || 'Unknown';
|
|
320
|
-
groups.set(label, (groups.get(label) || 0) + c.symbolCount);
|
|
212
|
+
catch {
|
|
213
|
+
console.log('\n Tip: Run `gitnexus setup` to configure MCP for your editor.');
|
|
321
214
|
}
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
communities: pipelineResult.communityResult?.stats.totalCommunities,
|
|
335
|
-
clusters: aggregatedClusterCount,
|
|
336
|
-
processes: pipelineResult.processResult?.stats.totalProcesses,
|
|
337
|
-
}, generatedSkills);
|
|
338
|
-
await closeLbug();
|
|
339
|
-
// Note: we intentionally do NOT call disposeEmbedder() here.
|
|
340
|
-
// ONNX Runtime's native cleanup segfaults on macOS and some Linux configs.
|
|
341
|
-
// Since the process exits immediately after, Node.js reclaims everything.
|
|
342
|
-
const totalTime = ((Date.now() - t0Global) / 1000).toFixed(1);
|
|
343
|
-
clearInterval(elapsedTimer);
|
|
344
|
-
process.removeListener('SIGINT', sigintHandler);
|
|
345
|
-
console.log = origLog;
|
|
346
|
-
console.warn = origWarn;
|
|
347
|
-
console.error = origError;
|
|
348
|
-
bar.update(100, { phase: 'Done' });
|
|
349
|
-
bar.stop();
|
|
350
|
-
// ── Summary ───────────────────────────────────────────────────────
|
|
351
|
-
const embeddingsCached = cachedEmbeddings.length > 0;
|
|
352
|
-
console.log(`\n Repository indexed successfully (${totalTime}s)${embeddingsCached ? ` [${cachedEmbeddings.length} embeddings cached]` : ''}\n`);
|
|
353
|
-
console.log(` ${stats.nodes.toLocaleString()} nodes | ${stats.edges.toLocaleString()} edges | ${pipelineResult.communityResult?.stats.totalCommunities || 0} clusters | ${pipelineResult.processResult?.stats.totalProcesses || 0} flows`);
|
|
354
|
-
console.log(` LadybugDB ${lbugTime}s | FTS ${ftsTime}s | Embeddings ${embeddingSkipped ? embeddingSkipReason : embeddingTime + 's'}`);
|
|
355
|
-
console.log(` ${repoPath}`);
|
|
356
|
-
if (aiContext.files.length > 0) {
|
|
357
|
-
console.log(` Context: ${aiContext.files.join(', ')}`);
|
|
358
|
-
}
|
|
359
|
-
// Show a quiet summary if some edge types needed fallback insertion
|
|
360
|
-
if (lbugWarnings.length > 0) {
|
|
361
|
-
const totalFallback = lbugWarnings.reduce((sum, w) => {
|
|
362
|
-
const m = w.match(/\((\d+) edges\)/);
|
|
363
|
-
return sum + (m ? parseInt(m[1]) : 0);
|
|
364
|
-
}, 0);
|
|
365
|
-
console.log(` Note: ${totalFallback} edges across ${lbugWarnings.length} types inserted via fallback (schema will be updated in next release)`);
|
|
366
|
-
}
|
|
367
|
-
try {
|
|
368
|
-
await fs.access(getGlobalRegistryPath());
|
|
369
|
-
}
|
|
370
|
-
catch {
|
|
371
|
-
console.log('\n Tip: Run `gitnexus setup` to configure MCP for your editor.');
|
|
215
|
+
console.log('');
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
clearInterval(elapsedTimer);
|
|
219
|
+
process.removeListener('SIGINT', sigintHandler);
|
|
220
|
+
console.log = origLog;
|
|
221
|
+
console.warn = origWarn;
|
|
222
|
+
console.error = origError;
|
|
223
|
+
bar.stop();
|
|
224
|
+
console.error(`\n Analysis failed: ${err.message}\n`);
|
|
225
|
+
process.exitCode = 1;
|
|
226
|
+
return;
|
|
372
227
|
}
|
|
373
|
-
console.log('');
|
|
374
228
|
// LadybugDB's native module holds open handles that prevent Node from exiting.
|
|
375
229
|
// ONNX Runtime also registers native atexit hooks that segfault on some
|
|
376
230
|
// platforms (#38, #40). Force-exit to ensure clean termination.
|
package/dist/cli/eval-server.js
CHANGED
|
@@ -68,7 +68,9 @@ export function formatContextResult(result) {
|
|
|
68
68
|
if (result.error)
|
|
69
69
|
return `Error: ${result.error}`;
|
|
70
70
|
if (result.status === 'ambiguous') {
|
|
71
|
-
const lines = [
|
|
71
|
+
const lines = [
|
|
72
|
+
`Multiple symbols named '${result.candidates?.[0]?.name || '?'}'. Disambiguate with file path:\n`,
|
|
73
|
+
];
|
|
72
74
|
for (const c of result.candidates || []) {
|
|
73
75
|
lines.push(` ${c.kind} ${c.name} → ${c.filePath}:${c.line || '?'} (uid: ${c.uid})`);
|
|
74
76
|
}
|
|
@@ -171,7 +173,7 @@ export function formatCypherResult(result) {
|
|
|
171
173
|
const keys = Object.keys(result[0]);
|
|
172
174
|
const lines = [`${result.length} row(s):\n`];
|
|
173
175
|
for (const row of result.slice(0, 30)) {
|
|
174
|
-
const parts = keys.map(k => `${k}: ${row[k]}`);
|
|
176
|
+
const parts = keys.map((k) => `${k}: ${row[k]}`);
|
|
175
177
|
lines.push(` ${parts.join(' | ')}`);
|
|
176
178
|
}
|
|
177
179
|
if (result.length > 30) {
|
|
@@ -230,13 +232,20 @@ export function formatListReposResult(result) {
|
|
|
230
232
|
*/
|
|
231
233
|
function formatToolResult(toolName, result) {
|
|
232
234
|
switch (toolName) {
|
|
233
|
-
case 'query':
|
|
234
|
-
|
|
235
|
-
case '
|
|
236
|
-
|
|
237
|
-
case '
|
|
238
|
-
|
|
239
|
-
|
|
235
|
+
case 'query':
|
|
236
|
+
return formatQueryResult(result);
|
|
237
|
+
case 'context':
|
|
238
|
+
return formatContextResult(result);
|
|
239
|
+
case 'impact':
|
|
240
|
+
return formatImpactResult(result);
|
|
241
|
+
case 'cypher':
|
|
242
|
+
return formatCypherResult(result);
|
|
243
|
+
case 'detect_changes':
|
|
244
|
+
return formatDetectChangesResult(result);
|
|
245
|
+
case 'list_repos':
|
|
246
|
+
return formatListReposResult(result);
|
|
247
|
+
default:
|
|
248
|
+
return typeof result === 'string' ? result : JSON.stringify(result, null, 2);
|
|
240
249
|
}
|
|
241
250
|
}
|
|
242
251
|
// ─── Next-Step Hints ──────────────────────────────────────────────────
|
|
@@ -269,7 +278,7 @@ export async function evalServerCommand(options) {
|
|
|
269
278
|
process.exit(1);
|
|
270
279
|
}
|
|
271
280
|
const repos = await backend.listRepos();
|
|
272
|
-
console.error(`GitNexus eval-server: ${repos.length} repo(s) loaded: ${repos.map(r => r.name).join(', ')}`);
|
|
281
|
+
console.error(`GitNexus eval-server: ${repos.length} repo(s) loaded: ${repos.map((r) => r.name).join(', ')}`);
|
|
273
282
|
let idleTimer = null;
|
|
274
283
|
function resetIdleTimer() {
|
|
275
284
|
if (idleTimeoutSec <= 0)
|
|
@@ -289,7 +298,7 @@ export async function evalServerCommand(options) {
|
|
|
289
298
|
if (req.method === 'GET' && req.url === '/health') {
|
|
290
299
|
res.setHeader('Content-Type', 'application/json');
|
|
291
300
|
res.writeHead(200);
|
|
292
|
-
res.end(JSON.stringify({ status: 'ok', repos: repos.map(r => r.name) }));
|
|
301
|
+
res.end(JSON.stringify({ status: 'ok', repos: repos.map((r) => r.name) }));
|
|
293
302
|
return;
|
|
294
303
|
}
|
|
295
304
|
// Shutdown
|
package/dist/cli/index-repo.js
CHANGED
|
@@ -8,25 +8,23 @@
|
|
|
8
8
|
* cloning a repo that ships its index, restoring from backup, or using a
|
|
9
9
|
* shared team index).
|
|
10
10
|
*/
|
|
11
|
-
import path from
|
|
12
|
-
import fs from
|
|
13
|
-
import { getStoragePaths, loadMeta, addToGitignore, registerRepo, } from
|
|
14
|
-
import { getGitRoot, isGitRepo } from
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import fs from 'fs/promises';
|
|
13
|
+
import { getStoragePaths, loadMeta, addToGitignore, registerRepo, } from '../storage/repo-manager.js';
|
|
14
|
+
import { getGitRoot, isGitRepo } from '../storage/git.js';
|
|
15
15
|
export const indexCommand = async (inputPathParts, options) => {
|
|
16
|
-
console.log(
|
|
17
|
-
const inputPath = inputPathParts?.length
|
|
18
|
-
? inputPathParts.join(" ")
|
|
19
|
-
: undefined;
|
|
16
|
+
console.log('\n GitNexus Index\n');
|
|
17
|
+
const inputPath = inputPathParts?.length ? inputPathParts.join(' ') : undefined;
|
|
20
18
|
if (inputPathParts && inputPathParts.length > 1) {
|
|
21
19
|
const resolvedCombinedPath = path.resolve(inputPath);
|
|
22
20
|
try {
|
|
23
21
|
await fs.access(resolvedCombinedPath);
|
|
24
22
|
}
|
|
25
23
|
catch {
|
|
26
|
-
console.log(
|
|
27
|
-
console.log(
|
|
28
|
-
console.log(` Received multiple path parts: ${inputPathParts.join(
|
|
29
|
-
console.log(
|
|
24
|
+
console.log(' The `index` command accepts a single path only.');
|
|
25
|
+
console.log(' If your path contains spaces, wrap it in quotes.');
|
|
26
|
+
console.log(` Received multiple path parts: ${inputPathParts.join(', ')}`);
|
|
27
|
+
console.log('');
|
|
30
28
|
process.exitCode = 1;
|
|
31
29
|
return;
|
|
32
30
|
}
|
|
@@ -38,7 +36,7 @@ export const indexCommand = async (inputPathParts, options) => {
|
|
|
38
36
|
else {
|
|
39
37
|
const gitRoot = getGitRoot(process.cwd());
|
|
40
38
|
if (!gitRoot) {
|
|
41
|
-
console.log(
|
|
39
|
+
console.log(' Not inside a git repository, try to run git init\n');
|
|
42
40
|
process.exitCode = 1;
|
|
43
41
|
return;
|
|
44
42
|
}
|
|
@@ -46,8 +44,8 @@ export const indexCommand = async (inputPathParts, options) => {
|
|
|
46
44
|
}
|
|
47
45
|
if (!options?.allowNonGit && !isGitRepo(repoPath)) {
|
|
48
46
|
console.log(` Not a git repository: ${repoPath}`);
|
|
49
|
-
console.log(
|
|
50
|
-
console.log(
|
|
47
|
+
console.log(' Initialize one with `git init` or choose a valid repo path.\n');
|
|
48
|
+
console.log(' Or use --allow-non-git to register an existing .gitnexus index anyway.\n');
|
|
51
49
|
process.exitCode = 1;
|
|
52
50
|
return;
|
|
53
51
|
}
|
|
@@ -58,7 +56,7 @@ export const indexCommand = async (inputPathParts, options) => {
|
|
|
58
56
|
}
|
|
59
57
|
catch {
|
|
60
58
|
console.log(` No .gitnexus/ folder found at: ${storagePath}`);
|
|
61
|
-
console.log(
|
|
59
|
+
console.log(' Run `gitnexus analyze` to build the index first.\n');
|
|
62
60
|
process.exitCode = 1;
|
|
63
61
|
return;
|
|
64
62
|
}
|
|
@@ -68,7 +66,7 @@ export const indexCommand = async (inputPathParts, options) => {
|
|
|
68
66
|
}
|
|
69
67
|
catch {
|
|
70
68
|
console.log(` .gitnexus/ folder exists but contains no LadybugDB index.`);
|
|
71
|
-
console.log(
|
|
69
|
+
console.log(' Run `gitnexus analyze` to build the index.\n');
|
|
72
70
|
process.exitCode = 1;
|
|
73
71
|
return;
|
|
74
72
|
}
|
|
@@ -77,15 +75,15 @@ export const indexCommand = async (inputPathParts, options) => {
|
|
|
77
75
|
if (!meta) {
|
|
78
76
|
if (!options?.force) {
|
|
79
77
|
console.log(` .gitnexus/ exists but meta.json is missing.`);
|
|
80
|
-
console.log(
|
|
81
|
-
console.log(
|
|
78
|
+
console.log(' Use --force to register anyway (stats will be empty),');
|
|
79
|
+
console.log(' or run `gitnexus analyze` to rebuild properly.\n');
|
|
82
80
|
process.exitCode = 1;
|
|
83
81
|
return;
|
|
84
82
|
}
|
|
85
83
|
// --force: build a minimal meta so the repo can be registered
|
|
86
84
|
meta = {
|
|
87
85
|
repoPath,
|
|
88
|
-
lastCommit:
|
|
86
|
+
lastCommit: '',
|
|
89
87
|
indexedAt: new Date().toISOString(),
|
|
90
88
|
};
|
|
91
89
|
}
|
|
@@ -108,8 +106,8 @@ export const indexCommand = async (inputPathParts, options) => {
|
|
|
108
106
|
if (stats.processes != null)
|
|
109
107
|
parts.push(`${stats.processes} flows`);
|
|
110
108
|
if (parts.length)
|
|
111
|
-
console.log(` ${parts.join(
|
|
109
|
+
console.log(` ${parts.join(' | ')}`);
|
|
112
110
|
}
|
|
113
111
|
console.log(` ${repoPath}`);
|
|
114
|
-
console.log(
|
|
112
|
+
console.log('');
|
|
115
113
|
};
|
package/dist/cli/index.js
CHANGED
|
@@ -7,10 +7,7 @@ import { createLazyAction } from './lazy-action.js';
|
|
|
7
7
|
const _require = createRequire(import.meta.url);
|
|
8
8
|
const pkg = _require('../../package.json');
|
|
9
9
|
const program = new Command();
|
|
10
|
-
program
|
|
11
|
-
.name('gitnexus')
|
|
12
|
-
.description('GitNexus local CLI and MCP server')
|
|
13
|
-
.version(pkg.version);
|
|
10
|
+
program.name('gitnexus').description('GitNexus local CLI and MCP server').version(pkg.version);
|
|
14
11
|
program
|
|
15
12
|
.command('setup')
|
|
16
13
|
.description('One-time setup: configure MCP for Cursor, Claude Code, OpenCode, Codex')
|
|
@@ -21,6 +18,7 @@ program
|
|
|
21
18
|
.option('-f, --force', 'Force full re-index even if up to date')
|
|
22
19
|
.option('--embeddings', 'Enable embedding generation for semantic search (off by default)')
|
|
23
20
|
.option('--skills', 'Generate repo-specific skill files from detected communities')
|
|
21
|
+
.option('--skip-agents-md', 'Skip updating the gitnexus section in AGENTS.md and CLAUDE.md')
|
|
24
22
|
.option('--skip-git', 'Index a folder without requiring a .git directory')
|
|
25
23
|
.option('-v, --verbose', 'Enable verbose ingestion warnings (default: false)')
|
|
26
24
|
.addHelpText('after', '\nEnvironment variables:\n GITNEXUS_NO_GITIGNORE=1 Skip .gitignore parsing (still reads .gitnexusignore)')
|
|
@@ -60,9 +58,12 @@ program
|
|
|
60
58
|
.description('Generate repository wiki from knowledge graph')
|
|
61
59
|
.option('-f, --force', 'Force full regeneration even if up to date')
|
|
62
60
|
.option('--provider <provider>', 'LLM provider: openai or cursor (default: openai)')
|
|
63
|
-
.option('--model <model>', 'LLM model name (default
|
|
64
|
-
.option('--base-url <url>', 'LLM API base URL
|
|
65
|
-
.option('--api-key <key>', 'LLM API key (saved to ~/.gitnexus/config.json)')
|
|
61
|
+
.option('--model <model>', 'LLM model or Azure deployment name (default: minimax/minimax-m2.5)')
|
|
62
|
+
.option('--base-url <url>', 'LLM API base URL. Azure v1: https://{resource}.openai.azure.com/openai/v1')
|
|
63
|
+
.option('--api-key <key>', 'LLM API key or Azure api-key (saved to ~/.gitnexus/config.json)')
|
|
64
|
+
.option('--api-version <version>', 'Azure api-version query param, e.g. 2024-10-21 (legacy Azure API only)')
|
|
65
|
+
.option('--reasoning-model', 'Mark deployment as reasoning model (o1/o3/o4-mini) — strips temperature, uses max_completion_tokens')
|
|
66
|
+
.option('--no-reasoning-model', 'Disable reasoning model mode (overrides saved config)')
|
|
66
67
|
.option('--concurrency <n>', 'Parallel LLM calls (default: 3)', '3')
|
|
67
68
|
.option('--gist', 'Publish wiki as a public GitHub Gist after generation')
|
|
68
69
|
.option('-v, --verbose', 'Enable verbose output (show LLM commands and responses)')
|
package/dist/cli/mcp.js
CHANGED
|
@@ -29,7 +29,7 @@ export const mcpCommand = async () => {
|
|
|
29
29
|
console.error('GitNexus: No indexed repos yet. Run `gitnexus analyze` in a git repo — the server will pick it up automatically.');
|
|
30
30
|
}
|
|
31
31
|
else {
|
|
32
|
-
console.error(`GitNexus: MCP server starting with ${repos.length} repo(s): ${repos.map(r => r.name).join(', ')}`);
|
|
32
|
+
console.error(`GitNexus: MCP server starting with ${repos.length} repo(s): ${repos.map((r) => r.name).join(', ')}`);
|
|
33
33
|
}
|
|
34
34
|
// Start MCP server (serves all repos, discovers new ones lazily)
|
|
35
35
|
await startMCPServer(backend);
|