@veewo/gitnexus 1.3.4
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 +234 -0
- package/dist/benchmark/agent-context/evaluators.d.ts +9 -0
- package/dist/benchmark/agent-context/evaluators.js +196 -0
- package/dist/benchmark/agent-context/evaluators.test.d.ts +1 -0
- package/dist/benchmark/agent-context/evaluators.test.js +39 -0
- package/dist/benchmark/agent-context/io.d.ts +2 -0
- package/dist/benchmark/agent-context/io.js +23 -0
- package/dist/benchmark/agent-context/io.test.d.ts +1 -0
- package/dist/benchmark/agent-context/io.test.js +19 -0
- package/dist/benchmark/agent-context/report.d.ts +2 -0
- package/dist/benchmark/agent-context/report.js +59 -0
- package/dist/benchmark/agent-context/report.test.d.ts +1 -0
- package/dist/benchmark/agent-context/report.test.js +85 -0
- package/dist/benchmark/agent-context/runner.d.ts +46 -0
- package/dist/benchmark/agent-context/runner.js +111 -0
- package/dist/benchmark/agent-context/runner.test.d.ts +1 -0
- package/dist/benchmark/agent-context/runner.test.js +79 -0
- package/dist/benchmark/agent-context/tool-runner.d.ts +7 -0
- package/dist/benchmark/agent-context/tool-runner.js +18 -0
- package/dist/benchmark/agent-context/tool-runner.test.d.ts +1 -0
- package/dist/benchmark/agent-context/tool-runner.test.js +11 -0
- package/dist/benchmark/agent-context/types.d.ts +40 -0
- package/dist/benchmark/agent-context/types.js +1 -0
- package/dist/benchmark/analyze-runner.d.ts +16 -0
- package/dist/benchmark/analyze-runner.js +51 -0
- package/dist/benchmark/analyze-runner.test.d.ts +1 -0
- package/dist/benchmark/analyze-runner.test.js +37 -0
- package/dist/benchmark/evaluators.d.ts +6 -0
- package/dist/benchmark/evaluators.js +10 -0
- package/dist/benchmark/evaluators.test.d.ts +1 -0
- package/dist/benchmark/evaluators.test.js +12 -0
- package/dist/benchmark/io.d.ts +7 -0
- package/dist/benchmark/io.js +25 -0
- package/dist/benchmark/io.test.d.ts +1 -0
- package/dist/benchmark/io.test.js +35 -0
- package/dist/benchmark/neonspark-candidates.d.ts +19 -0
- package/dist/benchmark/neonspark-candidates.js +94 -0
- package/dist/benchmark/neonspark-candidates.test.d.ts +1 -0
- package/dist/benchmark/neonspark-candidates.test.js +43 -0
- package/dist/benchmark/neonspark-materialize.d.ts +19 -0
- package/dist/benchmark/neonspark-materialize.js +111 -0
- package/dist/benchmark/neonspark-materialize.test.d.ts +1 -0
- package/dist/benchmark/neonspark-materialize.test.js +124 -0
- package/dist/benchmark/neonspark-sync.d.ts +3 -0
- package/dist/benchmark/neonspark-sync.js +53 -0
- package/dist/benchmark/neonspark-sync.test.d.ts +1 -0
- package/dist/benchmark/neonspark-sync.test.js +20 -0
- package/dist/benchmark/report.d.ts +1 -0
- package/dist/benchmark/report.js +7 -0
- package/dist/benchmark/runner.d.ts +48 -0
- package/dist/benchmark/runner.js +302 -0
- package/dist/benchmark/runner.test.d.ts +1 -0
- package/dist/benchmark/runner.test.js +50 -0
- package/dist/benchmark/scoring.d.ts +16 -0
- package/dist/benchmark/scoring.js +27 -0
- package/dist/benchmark/scoring.test.d.ts +1 -0
- package/dist/benchmark/scoring.test.js +24 -0
- package/dist/benchmark/tool-runner.d.ts +6 -0
- package/dist/benchmark/tool-runner.js +17 -0
- package/dist/benchmark/types.d.ts +36 -0
- package/dist/benchmark/types.js +1 -0
- package/dist/cli/ai-context.d.ts +22 -0
- package/dist/cli/ai-context.js +184 -0
- package/dist/cli/ai-context.test.d.ts +1 -0
- package/dist/cli/ai-context.test.js +30 -0
- package/dist/cli/analyze-multi-scope-regression.test.d.ts +1 -0
- package/dist/cli/analyze-multi-scope-regression.test.js +22 -0
- package/dist/cli/analyze-options.d.ts +7 -0
- package/dist/cli/analyze-options.js +56 -0
- package/dist/cli/analyze-options.test.d.ts +1 -0
- package/dist/cli/analyze-options.test.js +36 -0
- package/dist/cli/analyze.d.ts +14 -0
- package/dist/cli/analyze.js +384 -0
- package/dist/cli/augment.d.ts +13 -0
- package/dist/cli/augment.js +33 -0
- package/dist/cli/benchmark-agent-context.d.ts +29 -0
- package/dist/cli/benchmark-agent-context.js +61 -0
- package/dist/cli/benchmark-agent-context.test.d.ts +1 -0
- package/dist/cli/benchmark-agent-context.test.js +80 -0
- package/dist/cli/benchmark-unity.d.ts +15 -0
- package/dist/cli/benchmark-unity.js +31 -0
- package/dist/cli/benchmark-unity.test.d.ts +1 -0
- package/dist/cli/benchmark-unity.test.js +18 -0
- package/dist/cli/claude-hooks.d.ts +22 -0
- package/dist/cli/claude-hooks.js +97 -0
- package/dist/cli/clean.d.ts +10 -0
- package/dist/cli/clean.js +60 -0
- package/dist/cli/eval-server.d.ts +30 -0
- package/dist/cli/eval-server.js +372 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +182 -0
- package/dist/cli/list.d.ts +6 -0
- package/dist/cli/list.js +33 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +34 -0
- package/dist/cli/repo-manager-alias.test.d.ts +1 -0
- package/dist/cli/repo-manager-alias.test.js +40 -0
- package/dist/cli/scope-filter.test.d.ts +1 -0
- package/dist/cli/scope-filter.test.js +49 -0
- package/dist/cli/serve.d.ts +4 -0
- package/dist/cli/serve.js +6 -0
- package/dist/cli/setup.d.ts +8 -0
- package/dist/cli/setup.js +311 -0
- package/dist/cli/setup.test.d.ts +1 -0
- package/dist/cli/setup.test.js +31 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.js +27 -0
- package/dist/cli/tool.d.ts +40 -0
- package/dist/cli/tool.js +94 -0
- package/dist/cli/version.test.d.ts +1 -0
- package/dist/cli/version.test.js +19 -0
- package/dist/cli/wiki.d.ts +15 -0
- package/dist/cli/wiki.js +361 -0
- package/dist/config/ignore-service.d.ts +1 -0
- package/dist/config/ignore-service.js +210 -0
- package/dist/config/supported-languages.d.ts +12 -0
- package/dist/config/supported-languages.js +15 -0
- package/dist/core/augmentation/engine.d.ts +26 -0
- package/dist/core/augmentation/engine.js +213 -0
- package/dist/core/embeddings/embedder.d.ts +60 -0
- package/dist/core/embeddings/embedder.js +251 -0
- package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
- package/dist/core/embeddings/embedding-pipeline.js +329 -0
- package/dist/core/embeddings/index.d.ts +9 -0
- package/dist/core/embeddings/index.js +9 -0
- package/dist/core/embeddings/text-generator.d.ts +24 -0
- package/dist/core/embeddings/text-generator.js +182 -0
- package/dist/core/embeddings/types.d.ts +87 -0
- package/dist/core/embeddings/types.js +32 -0
- package/dist/core/graph/graph.d.ts +2 -0
- package/dist/core/graph/graph.js +66 -0
- package/dist/core/graph/types.d.ts +61 -0
- package/dist/core/graph/types.js +1 -0
- package/dist/core/ingestion/ast-cache.d.ts +11 -0
- package/dist/core/ingestion/ast-cache.js +34 -0
- package/dist/core/ingestion/call-processor.d.ts +15 -0
- package/dist/core/ingestion/call-processor.js +327 -0
- package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
- package/dist/core/ingestion/cluster-enricher.js +170 -0
- package/dist/core/ingestion/community-processor.d.ts +39 -0
- package/dist/core/ingestion/community-processor.js +312 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +39 -0
- package/dist/core/ingestion/entry-point-scoring.js +260 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
- package/dist/core/ingestion/filesystem-walker.js +80 -0
- package/dist/core/ingestion/framework-detection.d.ts +39 -0
- package/dist/core/ingestion/framework-detection.js +235 -0
- package/dist/core/ingestion/heritage-processor.d.ts +20 -0
- package/dist/core/ingestion/heritage-processor.js +197 -0
- package/dist/core/ingestion/import-processor.d.ts +38 -0
- package/dist/core/ingestion/import-processor.js +778 -0
- package/dist/core/ingestion/parsing-processor.d.ts +15 -0
- package/dist/core/ingestion/parsing-processor.js +291 -0
- package/dist/core/ingestion/pipeline.d.ts +5 -0
- package/dist/core/ingestion/pipeline.js +323 -0
- package/dist/core/ingestion/process-processor.d.ts +51 -0
- package/dist/core/ingestion/process-processor.js +309 -0
- package/dist/core/ingestion/scope-filter.d.ts +25 -0
- package/dist/core/ingestion/scope-filter.js +100 -0
- package/dist/core/ingestion/structure-processor.d.ts +2 -0
- package/dist/core/ingestion/structure-processor.js +36 -0
- package/dist/core/ingestion/symbol-table.d.ts +33 -0
- package/dist/core/ingestion/symbol-table.js +38 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -0
- package/dist/core/ingestion/tree-sitter-queries.js +398 -0
- package/dist/core/ingestion/utils.d.ts +10 -0
- package/dist/core/ingestion/utils.js +50 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +59 -0
- package/dist/core/ingestion/workers/parse-worker.js +672 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
- package/dist/core/ingestion/workers/worker-pool.js +120 -0
- package/dist/core/kuzu/csv-generator.d.ts +29 -0
- package/dist/core/kuzu/csv-generator.js +336 -0
- package/dist/core/kuzu/kuzu-adapter.d.ts +101 -0
- package/dist/core/kuzu/kuzu-adapter.js +753 -0
- package/dist/core/kuzu/schema.d.ts +53 -0
- package/dist/core/kuzu/schema.js +407 -0
- package/dist/core/search/bm25-index.d.ts +23 -0
- package/dist/core/search/bm25-index.js +95 -0
- package/dist/core/search/hybrid-search.d.ts +49 -0
- package/dist/core/search/hybrid-search.js +118 -0
- package/dist/core/tree-sitter/parser-loader.d.ts +4 -0
- package/dist/core/tree-sitter/parser-loader.js +44 -0
- package/dist/core/wiki/generator.d.ts +110 -0
- package/dist/core/wiki/generator.js +786 -0
- package/dist/core/wiki/graph-queries.d.ts +80 -0
- package/dist/core/wiki/graph-queries.js +238 -0
- package/dist/core/wiki/html-viewer.d.ts +10 -0
- package/dist/core/wiki/html-viewer.js +297 -0
- package/dist/core/wiki/llm-client.d.ts +40 -0
- package/dist/core/wiki/llm-client.js +162 -0
- package/dist/core/wiki/prompts.d.ts +53 -0
- package/dist/core/wiki/prompts.js +174 -0
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.js +3 -0
- package/dist/mcp/core/embedder.d.ts +27 -0
- package/dist/mcp/core/embedder.js +108 -0
- package/dist/mcp/core/kuzu-adapter.d.ts +34 -0
- package/dist/mcp/core/kuzu-adapter.js +231 -0
- package/dist/mcp/local/local-backend.d.ts +160 -0
- package/dist/mcp/local/local-backend.js +1646 -0
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +407 -0
- package/dist/mcp/server.d.ts +23 -0
- package/dist/mcp/server.js +251 -0
- package/dist/mcp/staleness.d.ts +15 -0
- package/dist/mcp/staleness.js +29 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.js +195 -0
- package/dist/server/api.d.ts +10 -0
- package/dist/server/api.js +344 -0
- package/dist/server/mcp-http.d.ts +13 -0
- package/dist/server/mcp-http.js +100 -0
- package/dist/storage/git.d.ts +6 -0
- package/dist/storage/git.js +32 -0
- package/dist/storage/repo-manager.d.ts +125 -0
- package/dist/storage/repo-manager.js +257 -0
- package/dist/types/pipeline.d.ts +34 -0
- package/dist/types/pipeline.js +18 -0
- package/hooks/claude/gitnexus-hook.cjs +135 -0
- package/hooks/claude/pre-tool-use.sh +78 -0
- package/hooks/claude/session-start.sh +42 -0
- package/package.json +92 -0
- package/skills/gitnexus-cli.md +82 -0
- package/skills/gitnexus-debugging.md +89 -0
- package/skills/gitnexus-exploring.md +78 -0
- package/skills/gitnexus-guide.md +64 -0
- package/skills/gitnexus-impact-analysis.md +97 -0
- package/skills/gitnexus-refactoring.md +121 -0
- package/vendor/leiden/index.cjs +355 -0
- package/vendor/leiden/utils.cjs +392 -0
package/dist/cli/wiki.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wiki Command
|
|
3
|
+
*
|
|
4
|
+
* Generates repository documentation from the knowledge graph.
|
|
5
|
+
* Usage: gitnexus wiki [path] [options]
|
|
6
|
+
*/
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import readline from 'readline';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import cliProgress from 'cli-progress';
|
|
11
|
+
import { getGitRoot, isGitRepo } from '../storage/git.js';
|
|
12
|
+
import { getStoragePaths, loadMeta, loadCLIConfig, saveCLIConfig } from '../storage/repo-manager.js';
|
|
13
|
+
import { WikiGenerator } from '../core/wiki/generator.js';
|
|
14
|
+
import { resolveLLMConfig } from '../core/wiki/llm-client.js';
|
|
15
|
+
/**
|
|
16
|
+
* Prompt the user for input via stdin.
|
|
17
|
+
*/
|
|
18
|
+
function prompt(question, hide = false) {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const rl = readline.createInterface({
|
|
21
|
+
input: process.stdin,
|
|
22
|
+
output: process.stdout,
|
|
23
|
+
});
|
|
24
|
+
if (hide && process.stdin.isTTY) {
|
|
25
|
+
// Mask input for API keys
|
|
26
|
+
process.stdout.write(question);
|
|
27
|
+
let input = '';
|
|
28
|
+
process.stdin.setRawMode(true);
|
|
29
|
+
process.stdin.resume();
|
|
30
|
+
process.stdin.setEncoding('utf-8');
|
|
31
|
+
const onData = (char) => {
|
|
32
|
+
if (char === '\n' || char === '\r' || char === '\u0004') {
|
|
33
|
+
process.stdin.setRawMode(false);
|
|
34
|
+
process.stdin.removeListener('data', onData);
|
|
35
|
+
process.stdout.write('\n');
|
|
36
|
+
rl.close();
|
|
37
|
+
resolve(input);
|
|
38
|
+
}
|
|
39
|
+
else if (char === '\u0003') {
|
|
40
|
+
// Ctrl+C
|
|
41
|
+
process.stdin.setRawMode(false);
|
|
42
|
+
rl.close();
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
else if (char === '\u007F' || char === '\b') {
|
|
46
|
+
// Backspace
|
|
47
|
+
if (input.length > 0) {
|
|
48
|
+
input = input.slice(0, -1);
|
|
49
|
+
process.stdout.write('\b \b');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
input += char;
|
|
54
|
+
process.stdout.write('*');
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
process.stdin.on('data', onData);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
rl.question(question, (answer) => {
|
|
61
|
+
rl.close();
|
|
62
|
+
resolve(answer.trim());
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export const wikiCommand = async (inputPath, options) => {
|
|
68
|
+
console.log('\n GitNexus Wiki Generator\n');
|
|
69
|
+
// ── Resolve repo path ───────────────────────────────────────────────
|
|
70
|
+
let repoPath;
|
|
71
|
+
if (inputPath) {
|
|
72
|
+
repoPath = path.resolve(inputPath);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
const gitRoot = getGitRoot(process.cwd());
|
|
76
|
+
if (!gitRoot) {
|
|
77
|
+
console.log(' Error: Not inside a git repository\n');
|
|
78
|
+
process.exitCode = 1;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
repoPath = gitRoot;
|
|
82
|
+
}
|
|
83
|
+
if (!isGitRepo(repoPath)) {
|
|
84
|
+
console.log(' Error: Not a git repository\n');
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// ── Check for existing index ────────────────────────────────────────
|
|
89
|
+
const { storagePath, kuzuPath } = getStoragePaths(repoPath);
|
|
90
|
+
const meta = await loadMeta(storagePath);
|
|
91
|
+
if (!meta) {
|
|
92
|
+
console.log(' Error: No GitNexus index found.');
|
|
93
|
+
console.log(' Run `gitnexus analyze` first to index this repository.\n');
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// ── Resolve LLM config (with interactive fallback) ─────────────────
|
|
98
|
+
// Save any CLI overrides immediately
|
|
99
|
+
if (options?.apiKey || options?.model || options?.baseUrl) {
|
|
100
|
+
const existing = await loadCLIConfig();
|
|
101
|
+
const updates = {};
|
|
102
|
+
if (options.apiKey)
|
|
103
|
+
updates.apiKey = options.apiKey;
|
|
104
|
+
if (options.model)
|
|
105
|
+
updates.model = options.model;
|
|
106
|
+
if (options.baseUrl)
|
|
107
|
+
updates.baseUrl = options.baseUrl;
|
|
108
|
+
await saveCLIConfig({ ...existing, ...updates });
|
|
109
|
+
console.log(' Config saved to ~/.gitnexus/config.json\n');
|
|
110
|
+
}
|
|
111
|
+
const savedConfig = await loadCLIConfig();
|
|
112
|
+
const hasSavedConfig = !!(savedConfig.apiKey && savedConfig.baseUrl);
|
|
113
|
+
const hasCLIOverrides = !!(options?.apiKey || options?.model || options?.baseUrl);
|
|
114
|
+
let llmConfig = await resolveLLMConfig({
|
|
115
|
+
model: options?.model,
|
|
116
|
+
baseUrl: options?.baseUrl,
|
|
117
|
+
apiKey: options?.apiKey,
|
|
118
|
+
});
|
|
119
|
+
// Run interactive setup if no saved config and no CLI flags provided
|
|
120
|
+
// (even if env vars exist — let user explicitly choose their provider)
|
|
121
|
+
if (!hasSavedConfig && !hasCLIOverrides) {
|
|
122
|
+
if (!process.stdin.isTTY) {
|
|
123
|
+
if (!llmConfig.apiKey) {
|
|
124
|
+
console.log(' Error: No LLM API key found.');
|
|
125
|
+
console.log(' Set OPENAI_API_KEY or GITNEXUS_API_KEY environment variable,');
|
|
126
|
+
console.log(' or pass --api-key <key>.\n');
|
|
127
|
+
process.exitCode = 1;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
// Non-interactive with env var — just use it
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
console.log(' No LLM configured. Let\'s set it up.\n');
|
|
134
|
+
console.log(' Supports OpenAI, OpenRouter, or any OpenAI-compatible API.\n');
|
|
135
|
+
// Provider selection
|
|
136
|
+
console.log(' [1] OpenAI (api.openai.com)');
|
|
137
|
+
console.log(' [2] OpenRouter (openrouter.ai)');
|
|
138
|
+
console.log(' [3] Custom endpoint\n');
|
|
139
|
+
const choice = await prompt(' Select provider (1/2/3): ');
|
|
140
|
+
let baseUrl;
|
|
141
|
+
let defaultModel;
|
|
142
|
+
if (choice === '2') {
|
|
143
|
+
baseUrl = 'https://openrouter.ai/api/v1';
|
|
144
|
+
defaultModel = 'minimax/minimax-m2.5';
|
|
145
|
+
}
|
|
146
|
+
else if (choice === '3') {
|
|
147
|
+
baseUrl = await prompt(' Base URL (e.g. http://localhost:11434/v1): ');
|
|
148
|
+
if (!baseUrl) {
|
|
149
|
+
console.log('\n No URL provided. Aborting.\n');
|
|
150
|
+
process.exitCode = 1;
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
defaultModel = 'gpt-4o-mini';
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
baseUrl = 'https://api.openai.com/v1';
|
|
157
|
+
defaultModel = 'gpt-4o-mini';
|
|
158
|
+
}
|
|
159
|
+
// Model
|
|
160
|
+
const modelInput = await prompt(` Model (default: ${defaultModel}): `);
|
|
161
|
+
const model = modelInput || defaultModel;
|
|
162
|
+
// API key — pre-fill hint if env var exists
|
|
163
|
+
const envKey = process.env.GITNEXUS_API_KEY || process.env.OPENAI_API_KEY || '';
|
|
164
|
+
let key;
|
|
165
|
+
if (envKey) {
|
|
166
|
+
const masked = envKey.slice(0, 6) + '...' + envKey.slice(-4);
|
|
167
|
+
const useEnv = await prompt(` Use existing env key (${masked})? (Y/n): `);
|
|
168
|
+
if (!useEnv || useEnv.toLowerCase() === 'y' || useEnv.toLowerCase() === 'yes') {
|
|
169
|
+
key = envKey;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
key = await prompt(' API key: ', true);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
key = await prompt(' API key: ', true);
|
|
177
|
+
}
|
|
178
|
+
if (!key) {
|
|
179
|
+
console.log('\n No key provided. Aborting.\n');
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Save
|
|
184
|
+
await saveCLIConfig({ apiKey: key, baseUrl, model });
|
|
185
|
+
console.log(' Config saved to ~/.gitnexus/config.json\n');
|
|
186
|
+
llmConfig = { ...llmConfig, apiKey: key, baseUrl, model };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// ── Setup progress bar with elapsed timer ──────────────────────────
|
|
190
|
+
const bar = new cliProgress.SingleBar({
|
|
191
|
+
format: ' {bar} {percentage}% | {phase}',
|
|
192
|
+
barCompleteChar: '\u2588',
|
|
193
|
+
barIncompleteChar: '\u2591',
|
|
194
|
+
hideCursor: true,
|
|
195
|
+
barGlue: '',
|
|
196
|
+
autopadding: true,
|
|
197
|
+
clearOnComplete: false,
|
|
198
|
+
stopOnComplete: false,
|
|
199
|
+
}, cliProgress.Presets.shades_grey);
|
|
200
|
+
bar.start(100, 0, { phase: 'Initializing...' });
|
|
201
|
+
const t0 = Date.now();
|
|
202
|
+
let lastPhase = '';
|
|
203
|
+
let phaseStart = t0;
|
|
204
|
+
// Tick elapsed time every second while stuck on the same phase
|
|
205
|
+
const elapsedTimer = setInterval(() => {
|
|
206
|
+
if (lastPhase) {
|
|
207
|
+
const elapsed = Math.round((Date.now() - phaseStart) / 1000);
|
|
208
|
+
if (elapsed >= 3) {
|
|
209
|
+
bar.update({ phase: `${lastPhase} (${elapsed}s)` });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}, 1000);
|
|
213
|
+
// ── Run generator ───────────────────────────────────────────────────
|
|
214
|
+
const wikiOptions = {
|
|
215
|
+
force: options?.force,
|
|
216
|
+
model: options?.model,
|
|
217
|
+
baseUrl: options?.baseUrl,
|
|
218
|
+
concurrency: options?.concurrency ? parseInt(options.concurrency, 10) : undefined,
|
|
219
|
+
};
|
|
220
|
+
const generator = new WikiGenerator(repoPath, storagePath, kuzuPath, llmConfig, wikiOptions, (phase, percent, detail) => {
|
|
221
|
+
const label = detail || phase;
|
|
222
|
+
if (label !== lastPhase) {
|
|
223
|
+
lastPhase = label;
|
|
224
|
+
phaseStart = Date.now();
|
|
225
|
+
}
|
|
226
|
+
bar.update(percent, { phase: label });
|
|
227
|
+
});
|
|
228
|
+
try {
|
|
229
|
+
const result = await generator.run();
|
|
230
|
+
clearInterval(elapsedTimer);
|
|
231
|
+
bar.update(100, { phase: 'Done' });
|
|
232
|
+
bar.stop();
|
|
233
|
+
const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
|
|
234
|
+
const wikiDir = path.join(storagePath, 'wiki');
|
|
235
|
+
const viewerPath = path.join(wikiDir, 'index.html');
|
|
236
|
+
if (result.mode === 'up-to-date' && !options?.force) {
|
|
237
|
+
console.log('\n Wiki is already up to date.');
|
|
238
|
+
console.log(` Viewer: ${viewerPath}\n`);
|
|
239
|
+
await maybePublishGist(viewerPath, options?.gist);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
console.log(`\n Wiki generated successfully (${elapsed}s)\n`);
|
|
243
|
+
console.log(` Mode: ${result.mode}`);
|
|
244
|
+
console.log(` Pages: ${result.pagesGenerated}`);
|
|
245
|
+
console.log(` Output: ${wikiDir}`);
|
|
246
|
+
console.log(` Viewer: ${viewerPath}`);
|
|
247
|
+
if (result.failedModules && result.failedModules.length > 0) {
|
|
248
|
+
console.log(`\n Failed modules (${result.failedModules.length}):`);
|
|
249
|
+
for (const mod of result.failedModules) {
|
|
250
|
+
console.log(` - ${mod}`);
|
|
251
|
+
}
|
|
252
|
+
console.log(' Re-run to retry failed modules (pages will be regenerated).');
|
|
253
|
+
}
|
|
254
|
+
console.log('');
|
|
255
|
+
await maybePublishGist(viewerPath, options?.gist);
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
clearInterval(elapsedTimer);
|
|
259
|
+
bar.stop();
|
|
260
|
+
if (err.message?.includes('No source files')) {
|
|
261
|
+
console.log(`\n ${err.message}\n`);
|
|
262
|
+
}
|
|
263
|
+
else if (err.message?.includes('API key') || err.message?.includes('API error')) {
|
|
264
|
+
console.log(`\n LLM Error: ${err.message}\n`);
|
|
265
|
+
// Offer to reconfigure on auth-related failures
|
|
266
|
+
const isAuthError = err.message?.includes('401') || err.message?.includes('403')
|
|
267
|
+
|| err.message?.includes('502') || err.message?.includes('authenticate')
|
|
268
|
+
|| err.message?.includes('Unauthorized');
|
|
269
|
+
if (isAuthError && process.stdin.isTTY) {
|
|
270
|
+
const answer = await new Promise((resolve) => {
|
|
271
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
272
|
+
rl.question(' Reconfigure LLM settings? (Y/n): ', (ans) => { rl.close(); resolve(ans.trim().toLowerCase()); });
|
|
273
|
+
});
|
|
274
|
+
if (!answer || answer === 'y' || answer === 'yes') {
|
|
275
|
+
// Clear saved config so next run triggers interactive setup
|
|
276
|
+
await saveCLIConfig({});
|
|
277
|
+
console.log(' Config cleared. Run `gitnexus wiki` again to reconfigure.\n');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
console.log(`\n Error: ${err.message}\n`);
|
|
283
|
+
if (process.env.DEBUG) {
|
|
284
|
+
console.error(err);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
process.exitCode = 1;
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
// ─── Gist Publishing ───────────────────────────────────────────────────
|
|
291
|
+
function hasGhCLI() {
|
|
292
|
+
try {
|
|
293
|
+
execSync('gh --version', { stdio: 'ignore' });
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function publishGist(htmlPath) {
|
|
301
|
+
try {
|
|
302
|
+
const output = execSync(`gh gist create "${htmlPath}" --desc "Repository Wiki — generated by GitNexus" --public`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
303
|
+
// gh gist create prints the gist URL as the last line
|
|
304
|
+
const lines = output.split('\n');
|
|
305
|
+
const gistUrl = lines.find(l => l.includes('gist.github.com')) || lines[lines.length - 1];
|
|
306
|
+
if (!gistUrl || !gistUrl.includes('gist.github.com'))
|
|
307
|
+
return null;
|
|
308
|
+
// Build a raw viewer URL via gist.githack.com
|
|
309
|
+
// gist URL format: https://gist.github.com/{user}/{id}
|
|
310
|
+
const match = gistUrl.match(/gist\.github\.com\/([^/]+)\/([a-f0-9]+)/);
|
|
311
|
+
let rawUrl = gistUrl;
|
|
312
|
+
if (match) {
|
|
313
|
+
rawUrl = `https://gistcdn.githack.com/${match[1]}/${match[2]}/raw/index.html`;
|
|
314
|
+
}
|
|
315
|
+
return { url: gistUrl.trim(), rawUrl };
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async function maybePublishGist(htmlPath, gistFlag) {
|
|
322
|
+
if (gistFlag === false)
|
|
323
|
+
return;
|
|
324
|
+
// Check that the HTML file exists
|
|
325
|
+
try {
|
|
326
|
+
const fs = await import('fs/promises');
|
|
327
|
+
await fs.access(htmlPath);
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (!hasGhCLI()) {
|
|
333
|
+
if (gistFlag) {
|
|
334
|
+
console.log(' GitHub CLI (gh) is not installed. Cannot publish gist.');
|
|
335
|
+
console.log(' Install it: https://cli.github.com\n');
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
let shouldPublish = !!gistFlag;
|
|
340
|
+
if (!shouldPublish && process.stdin.isTTY) {
|
|
341
|
+
const answer = await new Promise((resolve) => {
|
|
342
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
343
|
+
rl.question(' Publish wiki as a GitHub Gist for easy viewing? (Y/n): ', (ans) => {
|
|
344
|
+
rl.close();
|
|
345
|
+
resolve(ans.trim().toLowerCase());
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
shouldPublish = !answer || answer === 'y' || answer === 'yes';
|
|
349
|
+
}
|
|
350
|
+
if (!shouldPublish)
|
|
351
|
+
return;
|
|
352
|
+
console.log('\n Publishing to GitHub Gist...');
|
|
353
|
+
const result = publishGist(htmlPath);
|
|
354
|
+
if (result) {
|
|
355
|
+
console.log(` Gist: ${result.url}`);
|
|
356
|
+
console.log(` Viewer: ${result.rawUrl}\n`);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
console.log(' Failed to publish gist. Make sure `gh auth login` is configured.\n');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const shouldIgnorePath: (filePath: string) => boolean;
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
const DEFAULT_IGNORE_LIST = new Set([
|
|
2
|
+
// Version Control
|
|
3
|
+
'.git',
|
|
4
|
+
'.svn',
|
|
5
|
+
'.hg',
|
|
6
|
+
'.bzr',
|
|
7
|
+
// IDEs & Editors
|
|
8
|
+
'.idea',
|
|
9
|
+
'.vscode',
|
|
10
|
+
'.vs',
|
|
11
|
+
'.eclipse',
|
|
12
|
+
'.settings',
|
|
13
|
+
'.DS_Store',
|
|
14
|
+
'Thumbs.db',
|
|
15
|
+
// Dependencies
|
|
16
|
+
'node_modules',
|
|
17
|
+
'bower_components',
|
|
18
|
+
'jspm_packages',
|
|
19
|
+
'vendor', // PHP/Go
|
|
20
|
+
// 'packages' removed - commonly used for monorepo source code (lerna, pnpm, yarn workspaces)
|
|
21
|
+
'venv',
|
|
22
|
+
'.venv',
|
|
23
|
+
'env',
|
|
24
|
+
'.env',
|
|
25
|
+
'__pycache__',
|
|
26
|
+
'.pytest_cache',
|
|
27
|
+
'.mypy_cache',
|
|
28
|
+
'site-packages',
|
|
29
|
+
'.tox',
|
|
30
|
+
'eggs',
|
|
31
|
+
'.eggs',
|
|
32
|
+
'lib64',
|
|
33
|
+
'parts',
|
|
34
|
+
'sdist',
|
|
35
|
+
'wheels',
|
|
36
|
+
// Build Outputs
|
|
37
|
+
'dist',
|
|
38
|
+
'build',
|
|
39
|
+
'out',
|
|
40
|
+
'output',
|
|
41
|
+
'bin',
|
|
42
|
+
'obj',
|
|
43
|
+
'target', // Java/Rust
|
|
44
|
+
'.next',
|
|
45
|
+
'.nuxt',
|
|
46
|
+
'.output',
|
|
47
|
+
'.vercel',
|
|
48
|
+
'.netlify',
|
|
49
|
+
'.serverless',
|
|
50
|
+
'_build',
|
|
51
|
+
'public/build',
|
|
52
|
+
'.parcel-cache',
|
|
53
|
+
'.turbo',
|
|
54
|
+
'.svelte-kit',
|
|
55
|
+
// Test & Coverage
|
|
56
|
+
'coverage',
|
|
57
|
+
'.nyc_output',
|
|
58
|
+
'htmlcov',
|
|
59
|
+
'.coverage',
|
|
60
|
+
'__tests__', // Often just test files
|
|
61
|
+
'__mocks__',
|
|
62
|
+
'.jest',
|
|
63
|
+
// Logs & Temp
|
|
64
|
+
'logs',
|
|
65
|
+
'log',
|
|
66
|
+
'tmp',
|
|
67
|
+
'temp',
|
|
68
|
+
'cache',
|
|
69
|
+
'.cache',
|
|
70
|
+
'.tmp',
|
|
71
|
+
'.temp',
|
|
72
|
+
// Generated/Compiled
|
|
73
|
+
'.generated',
|
|
74
|
+
'generated',
|
|
75
|
+
'auto-generated',
|
|
76
|
+
'.terraform',
|
|
77
|
+
'.serverless',
|
|
78
|
+
// Documentation (optional - might want to keep)
|
|
79
|
+
// 'docs',
|
|
80
|
+
// 'documentation',
|
|
81
|
+
// Misc
|
|
82
|
+
'.husky',
|
|
83
|
+
'.github', // GitHub config, not code
|
|
84
|
+
'.circleci',
|
|
85
|
+
'.gitlab',
|
|
86
|
+
'fixtures', // Test fixtures
|
|
87
|
+
'snapshots', // Jest snapshots
|
|
88
|
+
'__snapshots__',
|
|
89
|
+
]);
|
|
90
|
+
const IGNORED_EXTENSIONS = new Set([
|
|
91
|
+
// Images
|
|
92
|
+
'.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.webp', '.bmp', '.tiff', '.tif',
|
|
93
|
+
'.psd', '.ai', '.sketch', '.fig', '.xd',
|
|
94
|
+
// Archives
|
|
95
|
+
'.zip', '.tar', '.gz', '.rar', '.7z', '.bz2', '.xz', '.tgz',
|
|
96
|
+
// Binary/Compiled
|
|
97
|
+
'.exe', '.dll', '.so', '.dylib', '.a', '.lib', '.o', '.obj',
|
|
98
|
+
'.class', '.jar', '.war', '.ear',
|
|
99
|
+
'.pyc', '.pyo', '.pyd',
|
|
100
|
+
'.beam', // Erlang
|
|
101
|
+
'.wasm', // WebAssembly - important!
|
|
102
|
+
'.node', // Native Node addons
|
|
103
|
+
// Documents
|
|
104
|
+
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
|
|
105
|
+
'.odt', '.ods', '.odp',
|
|
106
|
+
// Media
|
|
107
|
+
'.mp4', '.mp3', '.wav', '.mov', '.avi', '.mkv', '.flv', '.wmv',
|
|
108
|
+
'.ogg', '.webm', '.flac', '.aac', '.m4a',
|
|
109
|
+
// Fonts
|
|
110
|
+
'.woff', '.woff2', '.ttf', '.eot', '.otf',
|
|
111
|
+
// Databases
|
|
112
|
+
'.db', '.sqlite', '.sqlite3', '.mdb', '.accdb',
|
|
113
|
+
// Minified/Bundled files
|
|
114
|
+
'.min.js', '.min.css', '.bundle.js', '.chunk.js',
|
|
115
|
+
// Source maps (debug files, not source)
|
|
116
|
+
'.map',
|
|
117
|
+
// Lock files (handled separately, but also here)
|
|
118
|
+
'.lock',
|
|
119
|
+
// Certificates & Keys (security - don't index!)
|
|
120
|
+
'.pem', '.key', '.crt', '.cer', '.p12', '.pfx',
|
|
121
|
+
// Data files (often large/binary)
|
|
122
|
+
'.csv', '.tsv', '.parquet', '.avro', '.feather',
|
|
123
|
+
'.npy', '.npz', '.pkl', '.pickle', '.h5', '.hdf5',
|
|
124
|
+
// Misc binary
|
|
125
|
+
'.bin', '.dat', '.data', '.raw',
|
|
126
|
+
'.iso', '.img', '.dmg',
|
|
127
|
+
// Unity metadata assets
|
|
128
|
+
'.meta',
|
|
129
|
+
]);
|
|
130
|
+
// Files to ignore by exact name
|
|
131
|
+
const IGNORED_FILES = new Set([
|
|
132
|
+
'package-lock.json',
|
|
133
|
+
'yarn.lock',
|
|
134
|
+
'pnpm-lock.yaml',
|
|
135
|
+
'composer.lock',
|
|
136
|
+
'Gemfile.lock',
|
|
137
|
+
'poetry.lock',
|
|
138
|
+
'Cargo.lock',
|
|
139
|
+
'go.sum',
|
|
140
|
+
'.gitignore',
|
|
141
|
+
'.gitattributes',
|
|
142
|
+
'.npmrc',
|
|
143
|
+
'.yarnrc',
|
|
144
|
+
'.editorconfig',
|
|
145
|
+
'.prettierrc',
|
|
146
|
+
'.prettierignore',
|
|
147
|
+
'.eslintignore',
|
|
148
|
+
'.dockerignore',
|
|
149
|
+
'Thumbs.db',
|
|
150
|
+
'.DS_Store',
|
|
151
|
+
'LICENSE',
|
|
152
|
+
'LICENSE.md',
|
|
153
|
+
'LICENSE.txt',
|
|
154
|
+
'CHANGELOG.md',
|
|
155
|
+
'CHANGELOG',
|
|
156
|
+
'CONTRIBUTING.md',
|
|
157
|
+
'CODE_OF_CONDUCT.md',
|
|
158
|
+
'SECURITY.md',
|
|
159
|
+
'.env',
|
|
160
|
+
'.env.local',
|
|
161
|
+
'.env.development',
|
|
162
|
+
'.env.production',
|
|
163
|
+
'.env.test',
|
|
164
|
+
'.env.example',
|
|
165
|
+
]);
|
|
166
|
+
export const shouldIgnorePath = (filePath) => {
|
|
167
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
168
|
+
const parts = normalizedPath.split('/');
|
|
169
|
+
const fileName = parts[parts.length - 1];
|
|
170
|
+
const fileNameLower = fileName.toLowerCase();
|
|
171
|
+
// Check if any path segment is in ignore list
|
|
172
|
+
for (const part of parts) {
|
|
173
|
+
if (DEFAULT_IGNORE_LIST.has(part)) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Check exact filename matches
|
|
178
|
+
if (IGNORED_FILES.has(fileName) || IGNORED_FILES.has(fileNameLower)) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
// Check extension
|
|
182
|
+
const lastDotIndex = fileNameLower.lastIndexOf('.');
|
|
183
|
+
if (lastDotIndex !== -1) {
|
|
184
|
+
const ext = fileNameLower.substring(lastDotIndex);
|
|
185
|
+
if (IGNORED_EXTENSIONS.has(ext))
|
|
186
|
+
return true;
|
|
187
|
+
// Handle compound extensions like .min.js, .bundle.js
|
|
188
|
+
const secondLastDot = fileNameLower.lastIndexOf('.', lastDotIndex - 1);
|
|
189
|
+
if (secondLastDot !== -1) {
|
|
190
|
+
const compoundExt = fileNameLower.substring(secondLastDot);
|
|
191
|
+
if (IGNORED_EXTENSIONS.has(compoundExt))
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Ignore hidden files (starting with .)
|
|
196
|
+
if (fileName.startsWith('.') && fileName !== '.') {
|
|
197
|
+
// But allow some important config files
|
|
198
|
+
const allowedDotFiles = ['.env', '.gitignore']; // Already in IGNORED_FILES, so this is redundant
|
|
199
|
+
// Actually, let's NOT ignore all dot files - many are important configs
|
|
200
|
+
// Just rely on the explicit lists above
|
|
201
|
+
}
|
|
202
|
+
// Ignore files that look like generated/bundled code
|
|
203
|
+
if (fileNameLower.includes('.bundle.') ||
|
|
204
|
+
fileNameLower.includes('.chunk.') ||
|
|
205
|
+
fileNameLower.includes('.generated.') ||
|
|
206
|
+
fileNameLower.endsWith('.d.ts')) { // TypeScript declaration files
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
return false;
|
|
210
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export var SupportedLanguages;
|
|
2
|
+
(function (SupportedLanguages) {
|
|
3
|
+
SupportedLanguages["JavaScript"] = "javascript";
|
|
4
|
+
SupportedLanguages["TypeScript"] = "typescript";
|
|
5
|
+
SupportedLanguages["Python"] = "python";
|
|
6
|
+
SupportedLanguages["Java"] = "java";
|
|
7
|
+
SupportedLanguages["C"] = "c";
|
|
8
|
+
SupportedLanguages["CPlusPlus"] = "cpp";
|
|
9
|
+
SupportedLanguages["CSharp"] = "csharp";
|
|
10
|
+
SupportedLanguages["Go"] = "go";
|
|
11
|
+
SupportedLanguages["Rust"] = "rust";
|
|
12
|
+
SupportedLanguages["PHP"] = "php";
|
|
13
|
+
// Ruby = 'ruby',
|
|
14
|
+
// Swift = 'swift',
|
|
15
|
+
})(SupportedLanguages || (SupportedLanguages = {}));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Augmentation Engine
|
|
3
|
+
*
|
|
4
|
+
* Lightweight, fast-path enrichment of search patterns with knowledge graph context.
|
|
5
|
+
* Designed to be called from platform hooks (Claude Code PreToolUse, Cursor beforeShellExecution)
|
|
6
|
+
* when an agent runs grep/glob/search.
|
|
7
|
+
*
|
|
8
|
+
* Performance target: <500ms cold start, <200ms warm.
|
|
9
|
+
*
|
|
10
|
+
* Design decisions:
|
|
11
|
+
* - Uses only BM25 search (no semantic/embedding) for speed
|
|
12
|
+
* - Clusters used internally for ranking, NEVER in output
|
|
13
|
+
* - Output is pure relationships: callers, callees, process participation
|
|
14
|
+
* - Graceful failure: any error → return empty string
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Augment a search pattern with knowledge graph context.
|
|
18
|
+
*
|
|
19
|
+
* 1. BM25 search for the pattern
|
|
20
|
+
* 2. For top matches, fetch callers/callees/processes
|
|
21
|
+
* 3. Rank by internal cluster cohesion (not exposed)
|
|
22
|
+
* 4. Format as structured text block
|
|
23
|
+
*
|
|
24
|
+
* Returns empty string on any error (graceful failure).
|
|
25
|
+
*/
|
|
26
|
+
export declare function augment(pattern: string, cwd?: string): Promise<string>;
|