vigthoria-cli 1.10.36 → 1.10.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-session-menu.d.ts +19 -0
- package/dist/commands/agent-session-menu.js +155 -0
- package/dist/commands/auth.js +68 -51
- package/dist/commands/bridge.js +19 -12
- package/dist/commands/cancel.js +22 -15
- package/dist/commands/chat.d.ts +0 -22
- package/dist/commands/chat.js +402 -1084
- package/dist/commands/config.js +73 -33
- package/dist/commands/deploy.js +123 -83
- package/dist/commands/device.js +61 -21
- package/dist/commands/edit.js +39 -32
- package/dist/commands/explain.js +25 -18
- package/dist/commands/generate.js +44 -37
- package/dist/commands/hub.js +102 -95
- package/dist/commands/index.js +46 -41
- package/dist/commands/legion.js +186 -146
- package/dist/commands/review.js +36 -29
- package/dist/commands/security.js +12 -5
- package/dist/commands/wallet.js +35 -28
- package/dist/commands/workflow.js +20 -13
- package/dist/utils/brain-hub-client.d.ts +32 -0
- package/dist/utils/brain-hub-client.js +52 -0
- package/dist/utils/bridge-client.js +52 -11
- package/dist/utils/codebase-indexer.d.ts +59 -0
- package/dist/utils/codebase-indexer.js +351 -0
- package/dist/utils/context-ranker.js +21 -15
- package/dist/utils/files.js +42 -5
- package/dist/utils/logger.js +50 -42
- package/dist/utils/persona.js +8 -3
- package/dist/utils/post-write-validator.js +29 -22
- package/dist/utils/project-memory.js +23 -16
- package/dist/utils/task-display.js +20 -13
- package/dist/utils/workspace-brain-service.d.ts +43 -0
- package/dist/utils/workspace-brain-service.js +158 -0
- package/dist/utils/workspace-cache.js +26 -18
- package/dist/utils/workspace-stream.js +63 -21
- package/package.json +3 -6
- package/scripts/release/validate-no-go-gates.sh +1 -1
- package/dist/commands/fork.d.ts +0 -17
- package/dist/commands/fork.js +0 -164
- package/dist/commands/history.d.ts +0 -17
- package/dist/commands/history.js +0 -113
- package/dist/commands/preview.d.ts +0 -55
- package/dist/commands/preview.js +0 -467
- package/dist/commands/replay.d.ts +0 -18
- package/dist/commands/replay.js +0 -156
- package/dist/commands/repo.d.ts +0 -97
- package/dist/commands/repo.js +0 -773
- package/dist/commands/update.d.ts +0 -9
- package/dist/commands/update.js +0 -201
- package/dist/index.d.ts +0 -21
- package/dist/index.js +0 -1823
- package/dist/utils/api.d.ts +0 -572
- package/dist/utils/api.js +0 -6548
- package/dist/utils/cli-state.d.ts +0 -54
- package/dist/utils/cli-state.js +0 -185
- package/dist/utils/config.d.ts +0 -85
- package/dist/utils/config.js +0 -267
- package/dist/utils/session.d.ts +0 -118
- package/dist/utils/session.js +0 -423
- package/dist/utils/tools.d.ts +0 -274
- package/dist/utils/tools.js +0 -3502
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Local TF-IDF codebase indexer for CLI (mirrors Vigthoria Code extension indexer).
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.CodebaseIndexer = void 0;
|
|
40
|
+
const crypto = __importStar(require("crypto"));
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
class CodebaseIndexer {
|
|
44
|
+
workspaceRoot;
|
|
45
|
+
index = new Map();
|
|
46
|
+
invertedIndex = new Map();
|
|
47
|
+
chunkStore = new Map();
|
|
48
|
+
fileHashes = new Map();
|
|
49
|
+
indexedFileCount = 0;
|
|
50
|
+
totalChunks = 0;
|
|
51
|
+
isIndexing = false;
|
|
52
|
+
maxFileSize = 1024 * 1024;
|
|
53
|
+
chunkSize = 50;
|
|
54
|
+
chunkOverlap = 5;
|
|
55
|
+
maxResults = 10;
|
|
56
|
+
ignorePatterns = [
|
|
57
|
+
'node_modules', '.git', 'dist', 'build', 'out', '.next',
|
|
58
|
+
'__pycache__', '.pytest_cache', '.mypy_cache', 'venv', 'env',
|
|
59
|
+
'.DS_Store', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml',
|
|
60
|
+
'.vsix', '.map', '.min.js', '.min.css', 'coverage',
|
|
61
|
+
'.cache', '.tmp', 'tmp', 'temp', '.idea', '.vscode',
|
|
62
|
+
];
|
|
63
|
+
supportedExtensions = new Set([
|
|
64
|
+
'.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.go', '.rs',
|
|
65
|
+
'.c', '.cpp', '.h', '.hpp', '.cs', '.rb', '.php', '.swift',
|
|
66
|
+
'.kt', '.scala', '.vue', '.svelte', '.astro',
|
|
67
|
+
'.html', '.css', '.scss', '.less', '.sass',
|
|
68
|
+
'.json', '.yaml', '.yml', '.toml', '.xml',
|
|
69
|
+
'.md', '.txt', '.rst', '.sh', '.bash', '.zsh',
|
|
70
|
+
'.sql', '.graphql', '.prisma', '.env',
|
|
71
|
+
'.dockerfile', '.tf', '.hcl',
|
|
72
|
+
]);
|
|
73
|
+
constructor(workspaceRoot) {
|
|
74
|
+
this.workspaceRoot = path.resolve(workspaceRoot);
|
|
75
|
+
}
|
|
76
|
+
getStatus() {
|
|
77
|
+
return {
|
|
78
|
+
indexedFileCount: this.indexedFileCount,
|
|
79
|
+
totalChunks: this.totalChunks,
|
|
80
|
+
isIndexing: this.isIndexing,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
static metaPath(workspaceRoot) {
|
|
84
|
+
return path.join(workspaceRoot, '.vigthoria', 'index', 'meta.json');
|
|
85
|
+
}
|
|
86
|
+
static loadMeta(workspaceRoot) {
|
|
87
|
+
try {
|
|
88
|
+
const metaPath = CodebaseIndexer.metaPath(workspaceRoot);
|
|
89
|
+
if (fs.existsSync(metaPath)) {
|
|
90
|
+
return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// fresh workspace
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
saveMeta(meta) {
|
|
99
|
+
const dir = path.join(this.workspaceRoot, '.vigthoria', 'index');
|
|
100
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
101
|
+
fs.writeFileSync(CodebaseIndexer.metaPath(this.workspaceRoot), `${JSON.stringify(meta, null, 2)}\n`);
|
|
102
|
+
}
|
|
103
|
+
hasLocalIndex() {
|
|
104
|
+
const meta = CodebaseIndexer.loadMeta(this.workspaceRoot);
|
|
105
|
+
return !!(meta && meta.indexedFileCount > 0) || this.totalChunks > 0;
|
|
106
|
+
}
|
|
107
|
+
countCandidateFiles() {
|
|
108
|
+
return this.findFiles(this.workspaceRoot).length;
|
|
109
|
+
}
|
|
110
|
+
countIndexableFiles() {
|
|
111
|
+
return this.findFiles(this.workspaceRoot).length;
|
|
112
|
+
}
|
|
113
|
+
async indexWorkspace() {
|
|
114
|
+
if (this.isIndexing) {
|
|
115
|
+
return {
|
|
116
|
+
indexedFileCount: this.indexedFileCount,
|
|
117
|
+
totalChunks: this.totalChunks,
|
|
118
|
+
indexHash: '',
|
|
119
|
+
topFiles: [],
|
|
120
|
+
indexedAt: new Date().toISOString(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
this.isIndexing = true;
|
|
124
|
+
this.index.clear();
|
|
125
|
+
this.invertedIndex.clear();
|
|
126
|
+
this.chunkStore.clear();
|
|
127
|
+
this.fileHashes.clear();
|
|
128
|
+
this.indexedFileCount = 0;
|
|
129
|
+
this.totalChunks = 0;
|
|
130
|
+
try {
|
|
131
|
+
const files = this.findFiles(this.workspaceRoot);
|
|
132
|
+
for (const filePath of files) {
|
|
133
|
+
this.indexFile(filePath);
|
|
134
|
+
}
|
|
135
|
+
const indexHash = crypto.createHash('sha256')
|
|
136
|
+
.update(`${this.indexedFileCount}:${this.totalChunks}:${files.length}`)
|
|
137
|
+
.digest('hex')
|
|
138
|
+
.slice(0, 16);
|
|
139
|
+
const topFiles = files.slice(0, 12).map((filePath) => path.relative(this.workspaceRoot, filePath));
|
|
140
|
+
const meta = {
|
|
141
|
+
indexedFileCount: this.indexedFileCount,
|
|
142
|
+
totalChunks: this.totalChunks,
|
|
143
|
+
indexHash,
|
|
144
|
+
topFiles,
|
|
145
|
+
indexedAt: new Date().toISOString(),
|
|
146
|
+
};
|
|
147
|
+
this.saveMeta(meta);
|
|
148
|
+
return meta;
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
this.isIndexing = false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
search(query, maxResults = this.maxResults) {
|
|
155
|
+
if (this.totalChunks === 0) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
const queryTerms = this.tokenize(query.toLowerCase());
|
|
159
|
+
const scores = new Map();
|
|
160
|
+
for (const term of queryTerms) {
|
|
161
|
+
const matchingChunks = this.invertedIndex.get(term);
|
|
162
|
+
if (!matchingChunks)
|
|
163
|
+
continue;
|
|
164
|
+
const idf = Math.log(this.totalChunks / matchingChunks.size);
|
|
165
|
+
for (const chunkId of matchingChunks) {
|
|
166
|
+
const chunk = this.chunkStore.get(chunkId);
|
|
167
|
+
if (!chunk)
|
|
168
|
+
continue;
|
|
169
|
+
const tf = (chunk.terms.get(term) || 0) / chunk.totalTerms;
|
|
170
|
+
scores.set(chunkId, (scores.get(chunkId) || 0) + tf * idf);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
for (const [chunkId, score] of scores) {
|
|
174
|
+
const chunk = this.chunkStore.get(chunkId);
|
|
175
|
+
if (!chunk)
|
|
176
|
+
continue;
|
|
177
|
+
const fileName = path.basename(chunk.filePath).toLowerCase();
|
|
178
|
+
for (const term of queryTerms) {
|
|
179
|
+
if (fileName.includes(term)) {
|
|
180
|
+
scores.set(chunkId, score * 1.5);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return Array.from(scores.entries())
|
|
185
|
+
.sort((a, b) => b[1] - a[1])
|
|
186
|
+
.slice(0, maxResults)
|
|
187
|
+
.map(([chunkId, score]) => {
|
|
188
|
+
const chunk = this.chunkStore.get(chunkId);
|
|
189
|
+
return {
|
|
190
|
+
filePath: chunk.filePath,
|
|
191
|
+
relativePath: chunk.relativePath,
|
|
192
|
+
startLine: chunk.startLine,
|
|
193
|
+
endLine: chunk.endLine,
|
|
194
|
+
content: chunk.content,
|
|
195
|
+
language: chunk.language,
|
|
196
|
+
score: Math.round(score * 1000) / 1000,
|
|
197
|
+
symbol: chunk.symbol,
|
|
198
|
+
};
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
getContextForQuery(query, maxTokens = 4000) {
|
|
202
|
+
const results = this.search(query, 15);
|
|
203
|
+
if (results.length === 0) {
|
|
204
|
+
return '';
|
|
205
|
+
}
|
|
206
|
+
let context = '### Relevant code from workspace:\n\n';
|
|
207
|
+
let currentTokens = 0;
|
|
208
|
+
const avgCharsPerToken = 4;
|
|
209
|
+
for (const result of results) {
|
|
210
|
+
const entry = `**${result.relativePath}** (lines ${result.startLine}-${result.endLine}):\n\`\`\`${result.language}\n${result.content}\n\`\`\`\n\n`;
|
|
211
|
+
const entryTokens = Math.ceil(entry.length / avgCharsPerToken);
|
|
212
|
+
if (currentTokens + entryTokens > maxTokens)
|
|
213
|
+
break;
|
|
214
|
+
context += entry;
|
|
215
|
+
currentTokens += entryTokens;
|
|
216
|
+
}
|
|
217
|
+
return context;
|
|
218
|
+
}
|
|
219
|
+
formatSearchResults(query, maxResults = 30) {
|
|
220
|
+
const results = this.search(query, Math.min(maxResults, 20));
|
|
221
|
+
if (results.length === 0) {
|
|
222
|
+
return 'No indexed codebase matches found. Run /index or wait for workspace indexing to finish.';
|
|
223
|
+
}
|
|
224
|
+
return results.map((result) => (`[indexed:${result.score}] ${result.relativePath}:${result.startLine}-${result.endLine}`
|
|
225
|
+
+ (result.symbol ? ` (${result.symbol})` : '')
|
|
226
|
+
+ `\n${result.content.split('\n').slice(0, 8).join('\n')}`)).join('\n\n');
|
|
227
|
+
}
|
|
228
|
+
findFiles(rootPath) {
|
|
229
|
+
const files = [];
|
|
230
|
+
const walk = (currentDir, depth) => {
|
|
231
|
+
if (depth > 14 || files.length >= 10000)
|
|
232
|
+
return;
|
|
233
|
+
let entries;
|
|
234
|
+
try {
|
|
235
|
+
entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
for (const entry of entries) {
|
|
241
|
+
if (this.shouldIgnore(entry.name, path.join(currentDir, entry.name)))
|
|
242
|
+
continue;
|
|
243
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
244
|
+
if (entry.isDirectory()) {
|
|
245
|
+
walk(fullPath, depth + 1);
|
|
246
|
+
}
|
|
247
|
+
else if (entry.isFile()) {
|
|
248
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
249
|
+
if (this.supportedExtensions.has(ext)) {
|
|
250
|
+
files.push(fullPath);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
walk(rootPath, 0);
|
|
256
|
+
return files;
|
|
257
|
+
}
|
|
258
|
+
indexFile(filePath) {
|
|
259
|
+
try {
|
|
260
|
+
const stat = fs.statSync(filePath);
|
|
261
|
+
if (!stat.isFile() || stat.size > this.maxFileSize || stat.size === 0)
|
|
262
|
+
return;
|
|
263
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
264
|
+
const hash = crypto.createHash('md5').update(content).digest('hex');
|
|
265
|
+
if (this.fileHashes.get(filePath) === hash)
|
|
266
|
+
return;
|
|
267
|
+
this.fileHashes.set(filePath, hash);
|
|
268
|
+
const relativePath = path.relative(this.workspaceRoot, filePath);
|
|
269
|
+
const language = this.getLanguage(filePath);
|
|
270
|
+
const lines = content.split('\n');
|
|
271
|
+
const chunks = this.chunkFile(lines, filePath, relativePath, language);
|
|
272
|
+
const chunkIds = [];
|
|
273
|
+
for (const chunk of chunks) {
|
|
274
|
+
const chunkId = `${relativePath}:${chunk.startLine}-${chunk.endLine}`;
|
|
275
|
+
const terms = new Map();
|
|
276
|
+
const tokens = this.tokenize(chunk.content.toLowerCase());
|
|
277
|
+
let totalTerms = 0;
|
|
278
|
+
for (const token of tokens) {
|
|
279
|
+
terms.set(token, (terms.get(token) || 0) + 1);
|
|
280
|
+
totalTerms += 1;
|
|
281
|
+
if (!this.invertedIndex.has(token)) {
|
|
282
|
+
this.invertedIndex.set(token, new Set());
|
|
283
|
+
}
|
|
284
|
+
this.invertedIndex.get(token).add(chunkId);
|
|
285
|
+
}
|
|
286
|
+
this.chunkStore.set(chunkId, { ...chunk, terms, totalTerms });
|
|
287
|
+
chunkIds.push(chunkId);
|
|
288
|
+
this.totalChunks += 1;
|
|
289
|
+
}
|
|
290
|
+
this.index.set(filePath, chunkIds);
|
|
291
|
+
this.indexedFileCount += 1;
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// skip unreadable files
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
chunkFile(lines, filePath, relativePath, language) {
|
|
298
|
+
const chunks = [];
|
|
299
|
+
for (let i = 0; i < lines.length; i += this.chunkSize - this.chunkOverlap) {
|
|
300
|
+
const endLine = Math.min(i + this.chunkSize, lines.length);
|
|
301
|
+
const chunkLines = lines.slice(i, endLine);
|
|
302
|
+
if (chunkLines.join('').trim().length === 0)
|
|
303
|
+
continue;
|
|
304
|
+
chunks.push({
|
|
305
|
+
filePath,
|
|
306
|
+
relativePath,
|
|
307
|
+
startLine: i + 1,
|
|
308
|
+
endLine,
|
|
309
|
+
content: chunkLines.join('\n'),
|
|
310
|
+
language,
|
|
311
|
+
symbol: null,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return chunks;
|
|
315
|
+
}
|
|
316
|
+
tokenize(text) {
|
|
317
|
+
return text
|
|
318
|
+
.replace(/[^a-zA-Z0-9_$]/g, ' ')
|
|
319
|
+
.split(/\s+/)
|
|
320
|
+
.filter((token) => token.length > 2)
|
|
321
|
+
.filter((token) => !this.isStopWord(token));
|
|
322
|
+
}
|
|
323
|
+
isStopWord(word) {
|
|
324
|
+
const stopWords = new Set([
|
|
325
|
+
'the', 'and', 'for', 'that', 'this', 'with', 'from', 'are',
|
|
326
|
+
'was', 'were', 'been', 'have', 'has', 'had', 'not', 'but',
|
|
327
|
+
'its', 'can', 'will', 'would', 'could', 'should', 'may',
|
|
328
|
+
'var', 'let', 'const', 'function', 'return', 'true', 'false',
|
|
329
|
+
'null', 'undefined', 'new', 'class', 'import', 'export',
|
|
330
|
+
'require', 'module', 'exports', 'default', 'async', 'await',
|
|
331
|
+
]);
|
|
332
|
+
return stopWords.has(word);
|
|
333
|
+
}
|
|
334
|
+
getLanguage(filePath) {
|
|
335
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
336
|
+
const map = {
|
|
337
|
+
'.js': 'javascript', '.jsx': 'javascript',
|
|
338
|
+
'.ts': 'typescript', '.tsx': 'typescript',
|
|
339
|
+
'.py': 'python', '.html': 'html', '.css': 'css', '.json': 'json',
|
|
340
|
+
'.md': 'markdown', '.sh': 'shell', '.go': 'go', '.rs': 'rust',
|
|
341
|
+
};
|
|
342
|
+
return map[ext] || 'text';
|
|
343
|
+
}
|
|
344
|
+
shouldIgnore(name, fullPath) {
|
|
345
|
+
if (name.startsWith('.') && name !== '.env')
|
|
346
|
+
return true;
|
|
347
|
+
const lowerPath = fullPath.toLowerCase();
|
|
348
|
+
return this.ignorePatterns.some((pattern) => lowerPath.includes(pattern));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
exports.CodebaseIndexer = CodebaseIndexer;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Vigthoria CLI — Semantic Context Ranker
|
|
3
4
|
*
|
|
@@ -7,8 +8,13 @@
|
|
|
7
8
|
*
|
|
8
9
|
* No external dependencies — uses only Node.js built-ins.
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.buildSemanticContext = buildSemanticContext;
|
|
16
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
17
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
18
|
const IGNORED_DIRS = new Set([
|
|
13
19
|
'.git', 'node_modules', 'dist', '.next', '__pycache__',
|
|
14
20
|
'.vigthoria', 'coverage', '.cache', '.turbo', 'build', 'out',
|
|
@@ -39,8 +45,8 @@ function extractKeywords(prompt) {
|
|
|
39
45
|
function scoreFile(filePath, keywords) {
|
|
40
46
|
if (keywords.length === 0)
|
|
41
47
|
return 0;
|
|
42
|
-
const filename =
|
|
43
|
-
const parentDir =
|
|
48
|
+
const filename = node_path_1.default.basename(filePath).toLowerCase();
|
|
49
|
+
const parentDir = node_path_1.default.basename(node_path_1.default.dirname(filePath)).toLowerCase();
|
|
44
50
|
let score = 0;
|
|
45
51
|
for (const kw of keywords) {
|
|
46
52
|
// Filename match (high weight)
|
|
@@ -51,7 +57,7 @@ function scoreFile(filePath, keywords) {
|
|
|
51
57
|
score += 6;
|
|
52
58
|
}
|
|
53
59
|
try {
|
|
54
|
-
const content =
|
|
60
|
+
const content = node_fs_1.default.readFileSync(filePath, 'utf-8').slice(0, 300000);
|
|
55
61
|
const lower = content.toLowerCase();
|
|
56
62
|
for (const kw of keywords) {
|
|
57
63
|
const escaped = kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -67,14 +73,14 @@ function scoreFile(filePath, keywords) {
|
|
|
67
73
|
function walkWorkspace(dir, maxFiles = 800) {
|
|
68
74
|
const results = [];
|
|
69
75
|
const stack = [dir];
|
|
70
|
-
const workspaceRoot =
|
|
76
|
+
const workspaceRoot = node_path_1.default.resolve(dir);
|
|
71
77
|
while (stack.length > 0 && results.length < maxFiles) {
|
|
72
78
|
const current = stack.pop();
|
|
73
79
|
if (!current)
|
|
74
80
|
continue;
|
|
75
81
|
let entries;
|
|
76
82
|
try {
|
|
77
|
-
entries =
|
|
83
|
+
entries = node_fs_1.default.readdirSync(current, { withFileTypes: true });
|
|
78
84
|
}
|
|
79
85
|
catch {
|
|
80
86
|
continue;
|
|
@@ -85,12 +91,12 @@ function walkWorkspace(dir, maxFiles = 800) {
|
|
|
85
91
|
break;
|
|
86
92
|
if (IGNORED_DIRS.has(entry.name))
|
|
87
93
|
continue;
|
|
88
|
-
const fullPath =
|
|
94
|
+
const fullPath = node_path_1.default.join(current, entry.name);
|
|
89
95
|
// Security: skip symlinks that escape workspace root (fixes 8.2)
|
|
90
96
|
if (entry.isSymbolicLink()) {
|
|
91
97
|
try {
|
|
92
|
-
const real =
|
|
93
|
-
if (!real.startsWith(workspaceRoot +
|
|
98
|
+
const real = node_fs_1.default.realpathSync(fullPath);
|
|
99
|
+
if (!real.startsWith(workspaceRoot + node_path_1.default.sep) && real !== workspaceRoot)
|
|
94
100
|
continue;
|
|
95
101
|
}
|
|
96
102
|
catch {
|
|
@@ -100,7 +106,7 @@ function walkWorkspace(dir, maxFiles = 800) {
|
|
|
100
106
|
if (entry.isDirectory()) {
|
|
101
107
|
stack.push(fullPath);
|
|
102
108
|
}
|
|
103
|
-
else if (entry.isFile() && TEXT_EXTENSIONS.has(
|
|
109
|
+
else if (entry.isFile() && TEXT_EXTENSIONS.has(node_path_1.default.extname(entry.name).toLowerCase())) {
|
|
104
110
|
results.push(fullPath);
|
|
105
111
|
}
|
|
106
112
|
}
|
|
@@ -111,8 +117,8 @@ function walkWorkspace(dir, maxFiles = 800) {
|
|
|
111
117
|
* Score and rank workspace files by relevance to the given prompt.
|
|
112
118
|
* Returns the top N files with path, score, and content snippet.
|
|
113
119
|
*/
|
|
114
|
-
|
|
115
|
-
if (!workspacePath || !
|
|
120
|
+
function buildSemanticContext(workspacePath, prompt, topN = 12) {
|
|
121
|
+
if (!workspacePath || !node_fs_1.default.existsSync(workspacePath)) {
|
|
116
122
|
return { topFiles: [], totalFilesScanned: 0, keywords: [] };
|
|
117
123
|
}
|
|
118
124
|
const keywords = extractKeywords(prompt);
|
|
@@ -128,11 +134,11 @@ export function buildSemanticContext(workspacePath, prompt, topN = 12) {
|
|
|
128
134
|
const topFiles = scored.map(({ filePath, score }) => {
|
|
129
135
|
let snippet = '';
|
|
130
136
|
try {
|
|
131
|
-
snippet =
|
|
137
|
+
snippet = node_fs_1.default.readFileSync(filePath, 'utf-8').slice(0, 600);
|
|
132
138
|
}
|
|
133
139
|
catch { /* ignore */ }
|
|
134
140
|
return {
|
|
135
|
-
path:
|
|
141
|
+
path: node_path_1.default.relative(workspacePath, filePath).replace(/\\/g, '/'),
|
|
136
142
|
score,
|
|
137
143
|
snippet,
|
|
138
144
|
};
|
package/dist/utils/files.js
CHANGED
|
@@ -1,10 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* File utilities for Vigthoria CLI
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.FileUtils = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const glob_1 = require("glob");
|
|
43
|
+
class FileUtils {
|
|
8
44
|
projectRoot;
|
|
9
45
|
ignorePatterns;
|
|
10
46
|
constructor(projectRoot, ignorePatterns = []) {
|
|
@@ -94,7 +130,7 @@ export class FileUtils {
|
|
|
94
130
|
if (!fs.existsSync(this.projectRoot)) {
|
|
95
131
|
return [];
|
|
96
132
|
}
|
|
97
|
-
const files = await glob(pattern, {
|
|
133
|
+
const files = await (0, glob_1.glob)(pattern, {
|
|
98
134
|
cwd: this.projectRoot,
|
|
99
135
|
ignore: this.ignorePatterns,
|
|
100
136
|
nodir: true,
|
|
@@ -239,3 +275,4 @@ export class FileUtils {
|
|
|
239
275
|
return { added, removed };
|
|
240
276
|
}
|
|
241
277
|
}
|
|
278
|
+
exports.FileUtils = FileUtils;
|