graph-indexer 1.0.1 → 1.0.3
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/PROMPT.md +143 -35
- package/README.md +227 -862
- package/core-engine.mjs +363 -159
- package/indexer.mjs +8 -8
- package/init.mjs +179 -68
- package/mcp-server.mjs +397 -150
- package/package.json +13 -13
- package/parser-utils.mjs +94 -23
- package/watch-daemon.mjs +2 -2
package/indexer.mjs
CHANGED
|
@@ -61,7 +61,7 @@ async function main() {
|
|
|
61
61
|
for (const absolutePath of files) {
|
|
62
62
|
totalCheckedFiles++;
|
|
63
63
|
const relPath = path.relative(PROJECT_ROOT, absolutePath).replace(/\\/g, '/');
|
|
64
|
-
process.stdout.write(`\r⚡ Parsing AST: [${totalCheckedFiles}/${files.length}]
|
|
64
|
+
process.stdout.write(`\r⚡ Parsing AST: [${totalCheckedFiles}/${files.length}] Processing: ${relPath.slice(-40)} `);
|
|
65
65
|
|
|
66
66
|
if (relPath.includes('.bundle.') || relPath.includes('.min.')) continue;
|
|
67
67
|
|
|
@@ -92,14 +92,14 @@ async function main() {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
} catch (err) {
|
|
95
|
-
console.error(`\n💥 Error
|
|
95
|
+
console.error(`\n💥 Error in ${relPath}: ${err.message}`);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
const pendingChunks = indexData.chunksToEmbed || [];
|
|
100
100
|
console.log(`\n\n🧠 Embedding Generation (Ollama)`);
|
|
101
|
-
console.log(`Chunks
|
|
102
|
-
console.log(`
|
|
101
|
+
console.log(`Chunks reused from cache: ${indexData.chunks.length}`);
|
|
102
|
+
console.log(`New chunks to process: ${pendingChunks.length}`);
|
|
103
103
|
|
|
104
104
|
if (pendingChunks.length > 0) {
|
|
105
105
|
const BATCH_SIZE = 64;
|
|
@@ -124,11 +124,11 @@ async function main() {
|
|
|
124
124
|
? `This code architectural neighborhood connects with: ${cleanDeps.join(', ')}.`
|
|
125
125
|
: '';
|
|
126
126
|
|
|
127
|
-
// 🥇 BLEED PROTECTION: Flattened linear payload for Ollama without hidden indentation
|
|
128
127
|
return [
|
|
129
128
|
`File Location: ${c.file_path}`,
|
|
130
129
|
`Symbol Name: ${c.node_type} -> ${c.name}`,
|
|
131
130
|
c.docstring ? `Developer Documentation: ${c.docstring}` : '',
|
|
131
|
+
c.type_refs?.length ? `Type References: ${c.type_refs.join(', ')}` : '',
|
|
132
132
|
topologicalContext,
|
|
133
133
|
`--- Source Code ---`,
|
|
134
134
|
c.code_snippet
|
|
@@ -146,12 +146,12 @@ async function main() {
|
|
|
146
146
|
for (const chunk of batch) indexData.chunks.push(chunk);
|
|
147
147
|
}
|
|
148
148
|
completedChunksCount += batch.length;
|
|
149
|
-
process.stdout.write(`\r🤖 Embedding Progress: [${completedChunksCount}/${pendingChunks.length}] Chunks
|
|
149
|
+
process.stdout.write(`\r🤖 Embedding Progress: [${completedChunksCount}/${pendingChunks.length}] Chunks processed...`);
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
for (let i = 0; i < batches.length; i += CONCURRENCY) {
|
|
153
|
-
const
|
|
154
|
-
await Promise.all(
|
|
153
|
+
const batchGroup = batches.slice(i, i + CONCURRENCY);
|
|
154
|
+
await Promise.all(batchGroup.map(batch => worker(batch)));
|
|
155
155
|
}
|
|
156
156
|
console.timeEnd("Embedding Generation Duration");
|
|
157
157
|
}
|
package/init.mjs
CHANGED
|
@@ -18,18 +18,42 @@
|
|
|
18
18
|
import fs from 'fs';
|
|
19
19
|
import path from 'path';
|
|
20
20
|
import os from 'os';
|
|
21
|
+
import readline from 'readline';
|
|
21
22
|
import { fileURLToPath } from 'url';
|
|
22
23
|
|
|
23
24
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
24
25
|
const isDryRun = process.argv.includes('--dry-run');
|
|
26
|
+
const isAllLanguages = process.argv.includes('--all-languages');
|
|
25
27
|
const PROJECT_ROOT = process.cwd();
|
|
26
28
|
|
|
27
|
-
// ───
|
|
29
|
+
// ─── Language Registry ────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
const LANGUAGES = [
|
|
32
|
+
{ key: 'typescript', label: 'TypeScript / TSX', exts: '.ts, .tsx' },
|
|
33
|
+
{ key: 'javascript', label: 'JavaScript', exts: '.js, .jsx, .mjs, .cjs' },
|
|
34
|
+
{ key: 'python', label: 'Python', exts: '.py' },
|
|
35
|
+
{ key: 'go', label: 'Go', exts: '.go' },
|
|
36
|
+
{ key: 'rust', label: 'Rust', exts: '.rs' },
|
|
37
|
+
{ key: 'php', label: 'PHP', exts: '.php' },
|
|
38
|
+
{ key: 'java', label: 'Java', exts: '.java' },
|
|
39
|
+
{ key: 'kotlin', label: 'Kotlin', exts: '.kt, .kts' },
|
|
40
|
+
{ key: 'csharp', label: 'C#', exts: '.cs' },
|
|
41
|
+
{ key: 'ruby', label: 'Ruby', exts: '.rb' },
|
|
42
|
+
{ key: 'css', label: 'CSS / SCSS', exts: '.css, .scss' },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
// ─── MCP Server config blocks ─────────────────────────────────────────────────
|
|
28
46
|
|
|
29
47
|
const SERVER_CONFIG = {
|
|
30
|
-
command: '
|
|
31
|
-
args: [
|
|
32
|
-
env: { MCP_PROJECT_ROOT: PROJECT_ROOT }
|
|
48
|
+
command: 'npm',
|
|
49
|
+
args: ['run', 'mcp:start'],
|
|
50
|
+
env: { MCP_PROJECT_ROOT: PROJECT_ROOT },
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const SERVER_CONFIG_GLOBAL = {
|
|
54
|
+
command: 'npm',
|
|
55
|
+
args: ['run', '--prefix', PROJECT_ROOT, 'mcp:start'],
|
|
56
|
+
env: { MCP_PROJECT_ROOT: PROJECT_ROOT },
|
|
33
57
|
};
|
|
34
58
|
|
|
35
59
|
// ─── Utilities ────────────────────────────────────────────────────────────────
|
|
@@ -37,44 +61,120 @@ const SERVER_CONFIG = {
|
|
|
37
61
|
function log(msg) { process.stdout.write(msg + '\n'); }
|
|
38
62
|
|
|
39
63
|
function writeFile(filePath, content) {
|
|
40
|
-
if (isDryRun) {
|
|
41
|
-
log(` [dry-run] Would write: ${filePath}`);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
64
|
+
if (isDryRun) { log(` [dry-run] Would write: ${filePath}`); return; }
|
|
44
65
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
45
66
|
fs.writeFileSync(filePath, content, 'utf-8');
|
|
46
67
|
}
|
|
47
68
|
|
|
48
69
|
function readJsonSafe(filePath) {
|
|
49
70
|
try {
|
|
50
|
-
if (fs.existsSync(filePath))
|
|
51
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
52
|
-
}
|
|
71
|
+
if (fs.existsSync(filePath)) return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
53
72
|
} catch { /* malformed JSON — start fresh */ }
|
|
54
73
|
return null;
|
|
55
74
|
}
|
|
56
75
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
// ─── Interactive Language Selection ───────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
function selectLanguages() {
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
if (isAllLanguages || !process.stdin.isTTY) return resolve(null);
|
|
81
|
+
|
|
82
|
+
const { stdin, stdout } = process;
|
|
83
|
+
readline.emitKeypressEvents(stdin);
|
|
84
|
+
stdin.setRawMode(true);
|
|
85
|
+
stdout.write('\x1B[?25l');
|
|
86
|
+
|
|
87
|
+
let cursorIndex = 0;
|
|
88
|
+
const selected = new Set();
|
|
89
|
+
let hasRendered = false;
|
|
90
|
+
|
|
91
|
+
const render = () => {
|
|
92
|
+
if (hasRendered) {
|
|
93
|
+
readline.moveCursor(stdout, 0, -(LANGUAGES.length + 2));
|
|
94
|
+
readline.cursorTo(stdout, 0);
|
|
95
|
+
readline.clearScreenDown(stdout);
|
|
96
|
+
}
|
|
97
|
+
hasRendered = true;
|
|
98
|
+
|
|
99
|
+
stdout.write('⚙️ Select languages (Arrows/Tab: move, Space: toggle, Enter: confirm):\n\n');
|
|
100
|
+
|
|
101
|
+
LANGUAGES.forEach((lang, i) => {
|
|
102
|
+
const isHovered = i === cursorIndex;
|
|
103
|
+
const isSelected = selected.has(i);
|
|
104
|
+
|
|
105
|
+
const prefix = isHovered ? '❯' : ' ';
|
|
106
|
+
const checkbox = isSelected ? '◉' : '◯';
|
|
107
|
+
|
|
108
|
+
const line = ` ${prefix} ${checkbox} ${lang.label.padEnd(20)} ${lang.exts}\n`;
|
|
109
|
+
stdout.write(isHovered ? `\x1b[36m${line}\x1b[0m` : line);
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const cleanup = () => {
|
|
114
|
+
stdin.setRawMode(false);
|
|
115
|
+
stdout.write('\x1B[?25h');
|
|
116
|
+
stdin.removeListener('keypress', onKeypress);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const onKeypress = (str, key) => {
|
|
120
|
+
if (key.ctrl && key.name === 'c') {
|
|
121
|
+
cleanup();
|
|
122
|
+
process.exit(0);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (key.name === 'up' || (key.name === 'tab' && key.shift)) {
|
|
126
|
+
cursorIndex = (cursorIndex - 1 + LANGUAGES.length) % LANGUAGES.length;
|
|
127
|
+
render();
|
|
128
|
+
} else if (key.name === 'down' || (key.name === 'tab' && !key.shift)) {
|
|
129
|
+
cursorIndex = (cursorIndex + 1) % LANGUAGES.length;
|
|
130
|
+
render();
|
|
131
|
+
} else if (key.name === 'space') {
|
|
132
|
+
if (selected.has(cursorIndex)) selected.delete(cursorIndex);
|
|
133
|
+
else selected.add(cursorIndex);
|
|
134
|
+
render();
|
|
135
|
+
} else if (key.name === 'return') {
|
|
136
|
+
cleanup();
|
|
137
|
+
readline.moveCursor(stdout, 0, -(LANGUAGES.length + 2));
|
|
138
|
+
readline.cursorTo(stdout, 0);
|
|
139
|
+
readline.clearScreenDown(stdout);
|
|
140
|
+
|
|
141
|
+
if (selected.size === 0) {
|
|
142
|
+
resolve(null); // Enable all languages by default
|
|
143
|
+
} else {
|
|
144
|
+
resolve(Array.from(selected).map(i => LANGUAGES[i].key));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
stdin.on('keypress', onKeypress);
|
|
150
|
+
render();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function saveLanguageConfig(languages) {
|
|
155
|
+
const configPath = path.join(PROJECT_ROOT, '.graph-indexer.json');
|
|
156
|
+
if (isDryRun) {
|
|
157
|
+
if (languages) log(` [dry-run] Would write: ${configPath}`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const existing = readJsonSafe(configPath) || {};
|
|
161
|
+
if (!languages) {
|
|
162
|
+
delete existing.languages;
|
|
163
|
+
} else {
|
|
164
|
+
existing.languages = languages;
|
|
165
|
+
}
|
|
166
|
+
if (languages || Object.keys(existing).length > 0) {
|
|
167
|
+
fs.writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\n', 'utf-8');
|
|
65
168
|
}
|
|
66
|
-
return dst;
|
|
67
169
|
}
|
|
68
170
|
|
|
69
171
|
// ─── IDE Detectors & Configurators ───────────────────────────────────────────
|
|
70
172
|
|
|
71
173
|
function configureVSCode() {
|
|
72
|
-
const
|
|
73
|
-
const configPath = path.join(vscodeDir, 'mcp.json');
|
|
74
|
-
|
|
174
|
+
const configPath = path.join(PROJECT_ROOT, '.vscode', 'mcp.json');
|
|
75
175
|
const existing = readJsonSafe(configPath) || {};
|
|
76
176
|
if (!existing.servers) existing.servers = {};
|
|
77
|
-
if (existing.servers['graph-indexer']) return false;
|
|
177
|
+
if (existing.servers['graph-indexer']) return false;
|
|
78
178
|
|
|
79
179
|
existing.servers['graph-indexer'] = SERVER_CONFIG;
|
|
80
180
|
writeFile(configPath, JSON.stringify(existing, null, 2) + '\n');
|
|
@@ -82,15 +182,7 @@ function configureVSCode() {
|
|
|
82
182
|
}
|
|
83
183
|
|
|
84
184
|
function configureCursor() {
|
|
85
|
-
|
|
86
|
-
const candidates = [
|
|
87
|
-
path.join(PROJECT_ROOT, '.cursor', 'mcp.json'),
|
|
88
|
-
path.join(os.homedir(), '.cursor', 'mcp.json'),
|
|
89
|
-
];
|
|
90
|
-
const detected = candidates.some(p => fs.existsSync(path.dirname(p)));
|
|
91
|
-
|
|
92
|
-
// Prefer project-level config
|
|
93
|
-
const configPath = candidates[0];
|
|
185
|
+
const configPath = path.join(PROJECT_ROOT, '.cursor', 'mcp.json');
|
|
94
186
|
const existing = readJsonSafe(configPath) || {};
|
|
95
187
|
if (!existing.mcpServers) existing.mcpServers = {};
|
|
96
188
|
if (existing.mcpServers['graph-indexer']) return false;
|
|
@@ -108,34 +200,28 @@ function configureClaudeDesktop() {
|
|
|
108
200
|
configPath = path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
109
201
|
}
|
|
110
202
|
|
|
111
|
-
if (!fs.existsSync(path.dirname(configPath))) return false;
|
|
203
|
+
if (!fs.existsSync(path.dirname(configPath))) return false;
|
|
112
204
|
|
|
113
205
|
const existing = readJsonSafe(configPath) || {};
|
|
114
206
|
if (!existing.mcpServers) existing.mcpServers = {};
|
|
115
207
|
if (existing.mcpServers['graph-indexer']) return false;
|
|
116
208
|
|
|
117
|
-
existing.mcpServers['graph-indexer'] =
|
|
209
|
+
existing.mcpServers['graph-indexer'] = SERVER_CONFIG_GLOBAL;
|
|
118
210
|
writeFile(configPath, JSON.stringify(existing, null, 2) + '\n');
|
|
119
211
|
return true;
|
|
120
212
|
}
|
|
121
213
|
|
|
122
214
|
function configureClaudeCode() {
|
|
123
|
-
// Claude Code stores MCP config in .mcp.json or .claude/settings.json at project root
|
|
124
|
-
const candidates = [
|
|
125
|
-
path.join(PROJECT_ROOT, '.claude', 'settings.json'),
|
|
126
|
-
path.join(PROJECT_ROOT, '.mcp.json'),
|
|
127
|
-
];
|
|
128
|
-
|
|
129
|
-
// Prefer .claude/settings.json if directory exists, else .mcp.json
|
|
130
215
|
const hasClaudeDir = fs.existsSync(path.join(PROJECT_ROOT, '.claude'));
|
|
131
|
-
const configPath = hasClaudeDir
|
|
216
|
+
const configPath = hasClaudeDir
|
|
217
|
+
? path.join(PROJECT_ROOT, '.claude', 'settings.json')
|
|
218
|
+
: path.join(PROJECT_ROOT, '.mcp.json');
|
|
132
219
|
|
|
133
220
|
const existing = readJsonSafe(configPath) || {};
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
if (existing[serverKey]['graph-indexer']) return false;
|
|
221
|
+
if (!existing.mcpServers) existing.mcpServers = {};
|
|
222
|
+
if (existing.mcpServers['graph-indexer']) return false;
|
|
137
223
|
|
|
138
|
-
existing[
|
|
224
|
+
existing.mcpServers['graph-indexer'] = SERVER_CONFIG;
|
|
139
225
|
writeFile(configPath, JSON.stringify(existing, null, 2) + '\n');
|
|
140
226
|
return true;
|
|
141
227
|
}
|
|
@@ -174,7 +260,13 @@ function updateGitignore() {
|
|
|
174
260
|
const gitignorePath = path.join(PROJECT_ROOT, '.gitignore');
|
|
175
261
|
const existing = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf-8') : '';
|
|
176
262
|
|
|
177
|
-
const entries = [
|
|
263
|
+
const entries = [
|
|
264
|
+
'code-index.json',
|
|
265
|
+
'code-index.embeddings.bin',
|
|
266
|
+
'.idx-daemon.pid',
|
|
267
|
+
'.idx-daemon.log'
|
|
268
|
+
];
|
|
269
|
+
|
|
178
270
|
const toAdd = entries.filter(e => !existing.includes(e));
|
|
179
271
|
if (toAdd.length === 0) return false;
|
|
180
272
|
|
|
@@ -185,13 +277,23 @@ function updateGitignore() {
|
|
|
185
277
|
|
|
186
278
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
187
279
|
|
|
188
|
-
log('\n
|
|
189
|
-
log(
|
|
280
|
+
log('\n🚀 graph-indexer init' + (isDryRun ? ' [dry-run]' : '') + '\n');
|
|
281
|
+
log(`Project: ${PROJECT_ROOT}`);
|
|
282
|
+
|
|
283
|
+
// Language selection (interactive menu).
|
|
284
|
+
const selectedLanguages = await selectLanguages();
|
|
285
|
+
saveLanguageConfig(selectedLanguages);
|
|
286
|
+
|
|
287
|
+
if (selectedLanguages) {
|
|
288
|
+
const names = selectedLanguages.map(k => LANGUAGES.find(l => l.key === k)?.label || k);
|
|
289
|
+
log(`\n✅ Enabled languages: ${names.join(', ')}\n`);
|
|
290
|
+
} else {
|
|
291
|
+
log('\n✅ Enabled languages: all (default)\n');
|
|
292
|
+
}
|
|
190
293
|
|
|
191
294
|
const configured = [];
|
|
192
295
|
const skipped = [];
|
|
193
296
|
|
|
194
|
-
// IDE configuration
|
|
195
297
|
const ides = [
|
|
196
298
|
{ name: 'VS Code', fn: configureVSCode },
|
|
197
299
|
{ name: 'Cursor', fn: configureCursor },
|
|
@@ -199,43 +301,52 @@ const ides = [
|
|
|
199
301
|
{ name: 'Claude Code', fn: configureClaudeCode },
|
|
200
302
|
];
|
|
201
303
|
|
|
202
|
-
log('
|
|
304
|
+
log('Detecting IDEs / agents...\n');
|
|
203
305
|
for (const { name, fn } of ides) {
|
|
204
306
|
try {
|
|
205
307
|
const result = fn();
|
|
206
|
-
if (result === false)
|
|
207
|
-
|
|
208
|
-
} else {
|
|
209
|
-
configured.push(name);
|
|
210
|
-
}
|
|
308
|
+
if (result === false) skipped.push(name + ' (already configured or not installed)');
|
|
309
|
+
else configured.push(name);
|
|
211
310
|
} catch (e) {
|
|
212
311
|
skipped.push(name + ' (error: ' + e.message + ')');
|
|
213
312
|
}
|
|
214
313
|
}
|
|
215
314
|
|
|
216
|
-
// Package scripts
|
|
217
315
|
const scriptsAdded = addPackageScripts();
|
|
218
316
|
if (scriptsAdded) configured.push('package.json scripts (mcp:index, mcp:watch, mcp:start)');
|
|
219
317
|
else skipped.push('package.json scripts (already present)');
|
|
220
318
|
|
|
221
|
-
// .gitignore
|
|
222
319
|
const gitignoreUpdated = updateGitignore();
|
|
223
|
-
if (gitignoreUpdated) configured.push('.gitignore (code-index
|
|
224
|
-
else skipped.push('.gitignore (already contains index entries)');
|
|
320
|
+
if (gitignoreUpdated) configured.push('.gitignore (code-index, daemon artifacts)');
|
|
321
|
+
else skipped.push('.gitignore (already contains index/daemon entries)');
|
|
225
322
|
|
|
226
323
|
// ─── Summary ─────────────────────────────────────────────────────────────────
|
|
227
324
|
|
|
228
|
-
log('\
|
|
229
|
-
if (configured.length) configured.forEach(c => log('
|
|
325
|
+
log('\nConfigured:\n');
|
|
326
|
+
if (configured.length) configured.forEach(c => log(' * ' + c));
|
|
230
327
|
else log(' (nothing new to configure)');
|
|
231
328
|
|
|
232
329
|
if (skipped.length) {
|
|
233
|
-
log('\
|
|
234
|
-
skipped.forEach(s => log('
|
|
330
|
+
log('\nSkipped:\n');
|
|
331
|
+
skipped.forEach(s => log(' - ' + s));
|
|
235
332
|
}
|
|
236
333
|
|
|
237
|
-
log('\
|
|
334
|
+
log('\nNext steps:\n');
|
|
238
335
|
log(' 1. Run `npm run mcp:index` to index this project');
|
|
239
|
-
log(' 2. Restart your IDE to activate MCP
|
|
336
|
+
log(' 2. Restart your IDE to activate the MCP server');
|
|
240
337
|
log(' 3. Run `npm run mcp:start` if your IDE needs the server started manually');
|
|
241
|
-
|
|
338
|
+
|
|
339
|
+
// Mensaje final de agradecimiento
|
|
340
|
+
log('\n─────────────────────────────────────────────────────────────────');
|
|
341
|
+
log('✨ Thank you for setting up graph-indexer!');
|
|
342
|
+
log(' Enjoy your blazing-fast, AST-precise codebase search.');
|
|
343
|
+
log('─────────────────────────────────────────────────────────────────\n');
|
|
344
|
+
log('');
|
|
345
|
+
log('🤖 Agent Instructions:');
|
|
346
|
+
log(' To teach your AI agent how to use graph-indexer effectively,');
|
|
347
|
+
log(' copy the system prompt from our repository:');
|
|
348
|
+
log(' https://github.com/MaquinaTech/graph-indexer/blob/main/PROMPT.md?plain=1');
|
|
349
|
+
log('─────────────────────────────────────────────────────────────────\n');
|
|
350
|
+
|
|
351
|
+
// Cierre limpio de la ejecución para devolver el control a la terminal
|
|
352
|
+
process.exit(0);
|