@vortex-ai/cli 0.1.2
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/.turbo/turbo-build.log +15 -0
- package/.turbo/turbo-check-types.log +5 -0
- package/.vortex-bm25.json +1 -0
- package/.vortex.db +0 -0
- package/README.md +155 -0
- package/dist/chunk-C6P2IO65.mjs +41 -0
- package/dist/chunk-FC2JQ4EC.mjs +119 -0
- package/dist/chunk-PNFSQC3M.mjs +4792 -0
- package/dist/chunk-PXYQG752.mjs +99 -0
- package/dist/dist-2OLJAZT5.mjs +1244 -0
- package/dist/dist-BPCHQHDN.mjs +5 -0
- package/dist/dist-DAPSACZG.mjs +5 -0
- package/dist/index.js +886 -0
- package/dist/index.mjs +880 -0
- package/dist/multipart-parser-DVTUXEEQ.mjs +371 -0
- package/dist/src-IOKO4UCP.mjs +1408 -0
- package/package.json +43 -0
- package/src/commands/analyze.ts +74 -0
- package/src/commands/cache.ts +33 -0
- package/src/commands/fix-nitbits.ts +63 -0
- package/src/commands/graph.ts +59 -0
- package/src/commands/init.ts +37 -0
- package/src/commands/issue.ts +79 -0
- package/src/commands/review.ts +218 -0
- package/src/commands/search.ts +67 -0
- package/src/commands/solve-issue.ts +69 -0
- package/src/commands/solve.ts +177 -0
- package/src/commands/suggest.ts +54 -0
- package/src/commands/watch.ts +56 -0
- package/src/index.ts +147 -0
- package/tsconfig.json +5 -0
- package/vortex-ai-0.1.0.tgz +0 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,886 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_commander2 = require("commander");
|
|
28
|
+
var path3 = __toESM(require("path"));
|
|
29
|
+
var dotenv = __toESM(require("dotenv"));
|
|
30
|
+
var os = __toESM(require("os"));
|
|
31
|
+
|
|
32
|
+
// src/commands/init.ts
|
|
33
|
+
var import_engine = require("@vortex/engine");
|
|
34
|
+
async function initCommand(options) {
|
|
35
|
+
const { default: ora2 } = await import("ora");
|
|
36
|
+
const { default: chalk2 } = await import("chalk");
|
|
37
|
+
console.log(chalk2.blue.bold("\nInitializing Vortex Intelligence Layer\n"));
|
|
38
|
+
if (options.reindex) {
|
|
39
|
+
console.log(chalk2.yellow(" Reindex mode: Rebuilding embeddings and BM25 index"));
|
|
40
|
+
console.log(chalk2.yellow(" Historical review memory will be preserved\n"));
|
|
41
|
+
}
|
|
42
|
+
const spinner = ora2("Scanning repository and building indices...").start();
|
|
43
|
+
const indexer = new import_engine.Indexer();
|
|
44
|
+
try {
|
|
45
|
+
const stats = await indexer.indexRepository(process.cwd());
|
|
46
|
+
spinner.succeed(chalk2.green("Initialization complete!\n"));
|
|
47
|
+
console.log(chalk2.white.bold(" Index Statistics:"));
|
|
48
|
+
console.log(chalk2.gray(` Files processed: ${stats.filesProcessed}`));
|
|
49
|
+
console.log(chalk2.gray(` Chunks indexed: ${stats.chunksIndexed}`));
|
|
50
|
+
console.log(chalk2.cyan(` BM25 documents: ${stats.bm25Documents}`));
|
|
51
|
+
console.log(chalk2.gray(` Vector store: SQLite (Prisma)`));
|
|
52
|
+
console.log(chalk2.gray(` BM25 index: .vortex-bm25.json
|
|
53
|
+
`));
|
|
54
|
+
console.log(chalk2.green(" Ready for:"));
|
|
55
|
+
console.log(chalk2.gray(' \u2022 vortex search -q "your query" (hybrid search)'));
|
|
56
|
+
console.log(chalk2.gray(" \u2022 vortex review --pr <number> (multi-agent review)"));
|
|
57
|
+
console.log(chalk2.gray(" \u2022 vortex issue --id <number> (issue analysis)\n"));
|
|
58
|
+
} catch (err) {
|
|
59
|
+
spinner.fail(chalk2.red("Failed to initialize"));
|
|
60
|
+
console.error(err);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/commands/search.ts
|
|
65
|
+
var import_engine2 = require("@vortex/engine");
|
|
66
|
+
async function searchCommand(options) {
|
|
67
|
+
const { default: ora2 } = await import("ora");
|
|
68
|
+
const { default: chalk2 } = await import("chalk");
|
|
69
|
+
const { default: boxen } = await import("boxen");
|
|
70
|
+
const { marked } = await import("marked");
|
|
71
|
+
const { default: TerminalRenderer } = await import("marked-terminal");
|
|
72
|
+
marked.setOptions({
|
|
73
|
+
renderer: new TerminalRenderer()
|
|
74
|
+
});
|
|
75
|
+
const spinner = ora2(`Searching codebase for: "${options.query}"...`).start();
|
|
76
|
+
const indexer = new import_engine2.Indexer();
|
|
77
|
+
try {
|
|
78
|
+
spinner.text = "Running hybrid search (vector + BM25 + cross-encoder)...";
|
|
79
|
+
const results = await indexer.hybridSearch(options.query, parseInt(options.limit, 10));
|
|
80
|
+
if (results.length === 0) {
|
|
81
|
+
spinner.fail("No relevant code found.");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
spinner.text = `Found ${results.length} relevant code chunks. Analyzing with Gemini...`;
|
|
85
|
+
const memoryService = new import_engine2.MemoryService();
|
|
86
|
+
const memories = await memoryService.recallRelevantMemories(options.query, 3);
|
|
87
|
+
const agent = new import_engine2.IntelligenceAgent();
|
|
88
|
+
const answer = await agent.answerQueryWithContext(options.query, results);
|
|
89
|
+
spinner.succeed("Analysis complete!\n");
|
|
90
|
+
const parsedAnswer = await marked.parse(answer);
|
|
91
|
+
const formatted = boxen(parsedAnswer.trim(), {
|
|
92
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
93
|
+
margin: { top: 1, bottom: 1 },
|
|
94
|
+
borderStyle: "double",
|
|
95
|
+
borderColor: "cyan",
|
|
96
|
+
title: chalk2.cyan.bold(" Vortex AI Engine (Hybrid Search) "),
|
|
97
|
+
titleAlignment: "center"
|
|
98
|
+
});
|
|
99
|
+
console.log(formatted);
|
|
100
|
+
console.log(chalk2.cyan.dim(" Reference Material (Hybrid Retrieval)"));
|
|
101
|
+
results.forEach((res, i) => {
|
|
102
|
+
const sources = res.sources ? res.sources.join("+") : "vector";
|
|
103
|
+
const scoreStr = res.score ? (res.score * 100).toFixed(1) + "%" : "N/A";
|
|
104
|
+
console.log(chalk2.gray(` \u2502 [${i + 1}] ${res.file.replace(process.cwd(), "")} \u2794 ${res.symbolPath || "(anonymous)"} (${scoreStr}) [${sources}]`));
|
|
105
|
+
});
|
|
106
|
+
if (memories.length > 0) {
|
|
107
|
+
console.log(chalk2.yellow.dim("\n Relevant Memories"));
|
|
108
|
+
memories.forEach((mem, i) => {
|
|
109
|
+
console.log(chalk2.gray(` \u2502 [${i + 1}] ${mem.slice(0, 120)}...`));
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
} catch (err) {
|
|
113
|
+
spinner.fail("Search failed");
|
|
114
|
+
console.error(err);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/commands/review.ts
|
|
119
|
+
var import_engine3 = require("@vortex/engine");
|
|
120
|
+
var import_github = require("@vortex/github");
|
|
121
|
+
async function reviewCommand(options) {
|
|
122
|
+
const { default: ora2 } = await import("ora");
|
|
123
|
+
const { default: chalk2 } = await import("chalk");
|
|
124
|
+
const { default: boxen } = await import("boxen");
|
|
125
|
+
const { marked } = await import("marked");
|
|
126
|
+
const { default: TerminalRenderer } = await import("marked-terminal");
|
|
127
|
+
marked.setOptions({
|
|
128
|
+
renderer: new TerminalRenderer()
|
|
129
|
+
});
|
|
130
|
+
if (options.pr) {
|
|
131
|
+
console.log(chalk2.blue.bold(`
|
|
132
|
+
Multi-Agent Review for PR #${options.pr}
|
|
133
|
+
`));
|
|
134
|
+
} else {
|
|
135
|
+
console.log(chalk2.blue.bold(`
|
|
136
|
+
Multi-Agent Review for Local Changes
|
|
137
|
+
`));
|
|
138
|
+
}
|
|
139
|
+
if (!process.env.GITHUB_TOKEN) {
|
|
140
|
+
console.log(
|
|
141
|
+
chalk2.yellow(
|
|
142
|
+
"\u26A0\uFE0F No GITHUB_TOKEN found. Using anonymous access (subject to rate limits)."
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
const repoInfo = await import("@vortex/git").then(
|
|
147
|
+
(m) => m.getGithubRepoInfo(process.cwd())
|
|
148
|
+
);
|
|
149
|
+
const owner = process.env.GITHUB_OWNER || repoInfo?.owner;
|
|
150
|
+
const repo = process.env.GITHUB_REPO || repoInfo?.repo;
|
|
151
|
+
if (!owner || !repo) {
|
|
152
|
+
console.error(
|
|
153
|
+
chalk2.red(
|
|
154
|
+
"Could not determine GitHub repository. Please run this command inside a git repository or set GITHUB_OWNER and GITHUB_REPO."
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const spinner = ora2(
|
|
160
|
+
options.pr ? `Fetching diff for ${owner}/${repo}#${options.pr}...` : `Fetching local git diff...`
|
|
161
|
+
).start();
|
|
162
|
+
try {
|
|
163
|
+
let diff;
|
|
164
|
+
if (options.pr) {
|
|
165
|
+
const github = (0, import_github.createGithubClient)(process.env.GITHUB_TOKEN);
|
|
166
|
+
diff = await github.fetchPullRequestDiff(owner, repo, options.pr);
|
|
167
|
+
} else {
|
|
168
|
+
const { execSync: execSync2 } = await import("child_process");
|
|
169
|
+
diff = execSync2("git diff HEAD").toString();
|
|
170
|
+
if (!diff.trim()) {
|
|
171
|
+
spinner.fail("No local changes found to review. Make some changes or specify a --pr.");
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
spinner.text = "Extracting architectural queries from diff...";
|
|
176
|
+
const agent = new import_engine3.IntelligenceAgent();
|
|
177
|
+
const indexer = new import_engine3.Indexer();
|
|
178
|
+
const queries = await agent.extractSearchQueriesFromDiff(diff);
|
|
179
|
+
const allChunks = [];
|
|
180
|
+
if (queries.length > 0) {
|
|
181
|
+
spinner.text = `Hybrid searching for: ${queries.join(", ")}...`;
|
|
182
|
+
for (const query of queries) {
|
|
183
|
+
const results = await indexer.hybridSearch(query, 3);
|
|
184
|
+
allChunks.push(...results);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const uniqueChunks = Array.from(
|
|
188
|
+
new Map(allChunks.map((c) => [c.id, c])).values()
|
|
189
|
+
);
|
|
190
|
+
spinner.text = "Checking memory for relevant past reviews...";
|
|
191
|
+
const memoryService = new import_engine3.MemoryService();
|
|
192
|
+
const memories = await memoryService.recallRelevantMemories(
|
|
193
|
+
`PR review ${queries.join(" ")}`,
|
|
194
|
+
3
|
|
195
|
+
);
|
|
196
|
+
spinner.text = `Running multi-agent review (Security + Architecture + Synthesis)...`;
|
|
197
|
+
const review = await agent.generateMultiAgentReview(
|
|
198
|
+
diff,
|
|
199
|
+
uniqueChunks,
|
|
200
|
+
memories
|
|
201
|
+
);
|
|
202
|
+
spinner.succeed(
|
|
203
|
+
chalk2.green(
|
|
204
|
+
`Review complete in ${(review.durationMs / 1e3).toFixed(1)}s!
|
|
205
|
+
`
|
|
206
|
+
)
|
|
207
|
+
);
|
|
208
|
+
const parsedReview = await marked.parse(review.markdownReport);
|
|
209
|
+
const verdictColor = review.verdict === "SAFE_TO_MERGE" ? chalk2.green : review.verdict === "REQUIRES_CHANGES" ? chalk2.red : chalk2.yellow;
|
|
210
|
+
const borderColor = review.verdict === "SAFE_TO_MERGE" ? "green" : review.verdict === "REQUIRES_CHANGES" ? "red" : "yellow";
|
|
211
|
+
const formatted = boxen(parsedReview.trim(), {
|
|
212
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
213
|
+
margin: { top: 1, bottom: 1 },
|
|
214
|
+
borderStyle: "double",
|
|
215
|
+
borderColor,
|
|
216
|
+
title: chalk2.bold(` Multi-Agent Code Review `),
|
|
217
|
+
titleAlignment: "center"
|
|
218
|
+
});
|
|
219
|
+
console.log(formatted);
|
|
220
|
+
console.log(
|
|
221
|
+
boxen(verdictColor.bold(` ${review.verdict} `), {
|
|
222
|
+
padding: { left: 2, right: 2 },
|
|
223
|
+
borderStyle: "round",
|
|
224
|
+
borderColor,
|
|
225
|
+
textAlignment: "center"
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
const { security, architecture } = review.agentOutputs;
|
|
229
|
+
console.log(
|
|
230
|
+
chalk2.dim(
|
|
231
|
+
`
|
|
232
|
+
Security: ${security.riskLevel} (${security.findings.length} findings)`
|
|
233
|
+
)
|
|
234
|
+
);
|
|
235
|
+
security.findings.forEach((f, i) => {
|
|
236
|
+
const severityColor = f.severity === "critical" || f.severity === "high" ? chalk2.red : f.severity === "medium" ? chalk2.yellow : chalk2.gray;
|
|
237
|
+
console.log(severityColor(` [${f.severity.toUpperCase()}] ${f.title}`));
|
|
238
|
+
});
|
|
239
|
+
console.log(
|
|
240
|
+
chalk2.dim(
|
|
241
|
+
`
|
|
242
|
+
Architecture: ${architecture.consistencyScore} (${architecture.findings.length} findings)`
|
|
243
|
+
)
|
|
244
|
+
);
|
|
245
|
+
architecture.findings.forEach((f, i) => {
|
|
246
|
+
const severityColor = f.severity === "breaking" ? chalk2.red : f.severity === "major" ? chalk2.yellow : chalk2.gray;
|
|
247
|
+
console.log(severityColor(` [${f.severity.toUpperCase()}] ${f.title}`));
|
|
248
|
+
});
|
|
249
|
+
if (uniqueChunks.length > 0) {
|
|
250
|
+
console.log(chalk2.cyan.dim("\n Cross-Referenced Architecture:"));
|
|
251
|
+
uniqueChunks.forEach((res, i) => {
|
|
252
|
+
const sources = res.sources ? res.sources.join("+") : "vector";
|
|
253
|
+
console.log(
|
|
254
|
+
chalk2.gray(
|
|
255
|
+
` \u2502 [${i + 1}] ${res.file.replace(process.cwd(), "")} \u2794 ${res.symbolPath || "(anonymous)"} [${sources}]`
|
|
256
|
+
)
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
if (memories.length > 0) {
|
|
261
|
+
console.log(chalk2.yellow.dim("\n Past Review Memories Used:"));
|
|
262
|
+
memories.forEach((mem, i) => {
|
|
263
|
+
console.log(chalk2.gray(` \u2502 [${i + 1}] ${mem.slice(0, 120)}...`));
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (options.pr) {
|
|
267
|
+
try {
|
|
268
|
+
await memoryService.storeReviewMemory(options.pr, owner, repo, review);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
console.warn(chalk2.yellow("\n\u26A0\uFE0F Failed to store review in memory:"), err);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
console.log("");
|
|
274
|
+
} catch (err) {
|
|
275
|
+
spinner.fail("Failed to review PR");
|
|
276
|
+
console.error(err);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/commands/issue.ts
|
|
281
|
+
var import_engine4 = require("@vortex/engine");
|
|
282
|
+
var import_github2 = require("@vortex/github");
|
|
283
|
+
var import_git = require("@vortex/git");
|
|
284
|
+
async function issueCommand(options) {
|
|
285
|
+
const { default: ora2 } = await import("ora");
|
|
286
|
+
const { default: chalk2 } = await import("chalk");
|
|
287
|
+
const { default: boxen } = await import("boxen");
|
|
288
|
+
const { marked } = await import("marked");
|
|
289
|
+
const { default: TerminalRenderer } = await import("marked-terminal");
|
|
290
|
+
marked.setOptions({
|
|
291
|
+
renderer: new TerminalRenderer()
|
|
292
|
+
});
|
|
293
|
+
console.log(chalk2.blue(`
|
|
294
|
+
Analyzing Issue #${options.id}`));
|
|
295
|
+
if (!process.env.GITHUB_TOKEN) {
|
|
296
|
+
console.log(chalk2.yellow("\u26A0\uFE0F No GITHUB_TOKEN found. Using anonymous access (subject to rate limits)."));
|
|
297
|
+
}
|
|
298
|
+
const repoInfo = (0, import_git.getGithubRepoInfo)(process.cwd());
|
|
299
|
+
const owner = process.env.GITHUB_OWNER || repoInfo?.owner;
|
|
300
|
+
const repo = process.env.GITHUB_REPO || repoInfo?.repo;
|
|
301
|
+
if (!owner || !repo) {
|
|
302
|
+
console.error(chalk2.red("Could not determine GitHub repository. Please run this command inside a git repository or set GITHUB_OWNER and GITHUB_REPO."));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const spinner = ora2(`Fetching Issue #${options.id} from ${owner}/${repo}...`).start();
|
|
306
|
+
try {
|
|
307
|
+
const github = (0, import_github2.createGithubClient)(process.env.GITHUB_TOKEN);
|
|
308
|
+
const issue = await github.fetchIssue(owner, repo, options.id);
|
|
309
|
+
const comments = await github.fetchIssueComments(owner, repo, options.id);
|
|
310
|
+
spinner.text = `Issue fetched. Searching local vector database for relevant code...`;
|
|
311
|
+
const indexer = new import_engine4.Indexer();
|
|
312
|
+
const relevantContext = await indexer.search(issue.title, 5);
|
|
313
|
+
spinner.text = "Analyzing issue and relevant codebase context with Vortex Intelligence...";
|
|
314
|
+
const agent = new import_engine4.IntelligenceAgent();
|
|
315
|
+
const analysis = await agent.generateIssueAnalysis(
|
|
316
|
+
issue.title,
|
|
317
|
+
issue.body,
|
|
318
|
+
comments,
|
|
319
|
+
relevantContext
|
|
320
|
+
);
|
|
321
|
+
spinner.succeed("Issue Analysis complete!\n");
|
|
322
|
+
const parsedAnalysis = await marked.parse(analysis);
|
|
323
|
+
const formatted = boxen(parsedAnalysis.trim(), {
|
|
324
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
325
|
+
margin: { top: 1, bottom: 1 },
|
|
326
|
+
borderStyle: "double",
|
|
327
|
+
borderColor: "green",
|
|
328
|
+
title: chalk2.green.bold(" AI Issue Analyzer "),
|
|
329
|
+
titleAlignment: "center"
|
|
330
|
+
});
|
|
331
|
+
console.log(formatted);
|
|
332
|
+
if (relevantContext.length > 0) {
|
|
333
|
+
console.log(chalk2.cyan.dim(" Relevant Code Files Discovered"));
|
|
334
|
+
relevantContext.forEach((res, i) => {
|
|
335
|
+
console.log(chalk2.gray(` \u2502 [${i + 1}] ${res.file.replace(process.cwd(), "")} \u2794 ${res.symbolPath || "(anonymous)"} (${res.score ? (res.score * 100).toFixed(1) + "%" : "N/A"})`));
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
} catch (err) {
|
|
339
|
+
spinner.fail("Failed to analyze issue");
|
|
340
|
+
console.error(err);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/commands/graph.ts
|
|
345
|
+
var import_retrieval = require("@vortex/retrieval");
|
|
346
|
+
var import_db = require("@vortex/db");
|
|
347
|
+
var path = __toESM(require("path"));
|
|
348
|
+
async function graphCommand(options) {
|
|
349
|
+
const { default: chalk2 } = await import("chalk");
|
|
350
|
+
const { default: boxen } = await import("boxen");
|
|
351
|
+
console.log(chalk2.blue.bold("\nGenerating Dependency Graph...\n"));
|
|
352
|
+
try {
|
|
353
|
+
await (0, import_db.initDatabase)();
|
|
354
|
+
const graphRetriever = new import_retrieval.GraphRetriever();
|
|
355
|
+
let fileFilter = options.file;
|
|
356
|
+
if (!fileFilter) {
|
|
357
|
+
const projectRoot = (0, import_db.findProjectRoot)(process.cwd());
|
|
358
|
+
const relPath = path.relative(projectRoot, process.cwd());
|
|
359
|
+
if (relPath && relPath !== ".") {
|
|
360
|
+
fileFilter = relPath;
|
|
361
|
+
console.log(chalk2.dim(`Directory filter auto-applied: ${fileFilter}`));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const asciiTree = await graphRetriever.generateAsciiTree(fileFilter);
|
|
365
|
+
const mermaidCode = await graphRetriever.generateMermaidGraph(fileFilter, options.detailed);
|
|
366
|
+
console.log(
|
|
367
|
+
boxen(asciiTree.trim(), {
|
|
368
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
369
|
+
margin: { top: 1, bottom: 1 },
|
|
370
|
+
borderStyle: "round",
|
|
371
|
+
borderColor: "cyan",
|
|
372
|
+
title: chalk2.bold(` Dependency Graph `),
|
|
373
|
+
titleAlignment: "center"
|
|
374
|
+
})
|
|
375
|
+
);
|
|
376
|
+
if (options.file) {
|
|
377
|
+
console.log(chalk2.green(`\u2705 Graph generated successfully for file: ${options.file}`));
|
|
378
|
+
} else {
|
|
379
|
+
console.log(chalk2.green("\u2705 Project dependency graph generated successfully."));
|
|
380
|
+
}
|
|
381
|
+
const mermaidConfig = {
|
|
382
|
+
theme: "dark",
|
|
383
|
+
maxTextSize: 9e5
|
|
384
|
+
};
|
|
385
|
+
const state = { code: mermaidCode, mermaid: JSON.stringify(mermaidConfig, null, 2), autoSync: true, updateDiagram: true };
|
|
386
|
+
const base64 = Buffer.from(JSON.stringify(state)).toString("base64");
|
|
387
|
+
const liveUrl = `https://mermaid.live/edit#base64:${base64}`;
|
|
388
|
+
console.log(chalk2.dim(`
|
|
389
|
+
Want a visual flowchart? Open this URL:
|
|
390
|
+
${liveUrl}`));
|
|
391
|
+
} catch (err) {
|
|
392
|
+
console.error(chalk2.red("Failed to generate graph:"), err);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/commands/suggest.ts
|
|
397
|
+
var import_engine5 = require("@vortex/engine");
|
|
398
|
+
var fs = __toESM(require("fs"));
|
|
399
|
+
async function suggestCommand(options) {
|
|
400
|
+
const { default: ora2 } = await import("ora");
|
|
401
|
+
const { default: chalk2 } = await import("chalk");
|
|
402
|
+
const { default: boxen } = await import("boxen");
|
|
403
|
+
const { marked } = await import("marked");
|
|
404
|
+
const { default: TerminalRenderer } = await import("marked-terminal");
|
|
405
|
+
marked.setOptions({
|
|
406
|
+
renderer: new TerminalRenderer()
|
|
407
|
+
});
|
|
408
|
+
console.log(
|
|
409
|
+
chalk2.blue.bold(`
|
|
410
|
+
Generating Suggestions for: ${options.file}
|
|
411
|
+
`)
|
|
412
|
+
);
|
|
413
|
+
if (!fs.existsSync(options.file)) {
|
|
414
|
+
console.error(chalk2.red(`File not found: ${options.file}`));
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
const spinner = ora2("Analyzing file...").start();
|
|
418
|
+
try {
|
|
419
|
+
const content = fs.readFileSync(options.file, "utf8");
|
|
420
|
+
const agent = new import_engine5.IntelligenceAgent();
|
|
421
|
+
const suggestions = await agent.generateSuggestions(content);
|
|
422
|
+
spinner.succeed(chalk2.green("Analysis complete!\n"));
|
|
423
|
+
const parsedSuggestions = await marked.parse(suggestions);
|
|
424
|
+
const formatted = boxen(parsedSuggestions.trim(), {
|
|
425
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
426
|
+
margin: { top: 1, bottom: 1 },
|
|
427
|
+
borderStyle: "double",
|
|
428
|
+
borderColor: "cyan",
|
|
429
|
+
title: chalk2.cyan.bold(" AI Code Suggestions "),
|
|
430
|
+
titleAlignment: "center"
|
|
431
|
+
});
|
|
432
|
+
console.log(formatted);
|
|
433
|
+
} catch (err) {
|
|
434
|
+
spinner.fail(chalk2.red("Failed to generate suggestions"));
|
|
435
|
+
console.error(err);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// src/commands/fix-nitbits.ts
|
|
440
|
+
var import_engine6 = require("@vortex/engine");
|
|
441
|
+
var fs2 = __toESM(require("fs"));
|
|
442
|
+
async function fixNitbitsCommand(options) {
|
|
443
|
+
const { default: ora2 } = await import("ora");
|
|
444
|
+
const { default: chalk2 } = await import("chalk");
|
|
445
|
+
console.log(chalk2.blue.bold("\nFixing Repository Nitbits\n"));
|
|
446
|
+
if (!options.files) {
|
|
447
|
+
console.error(
|
|
448
|
+
chalk2.red("Please provide --files to fix (comma-separated list).")
|
|
449
|
+
);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const files = options.files.split(",").map((file) => file.trim());
|
|
453
|
+
const agent = new import_engine6.IntelligenceAgent();
|
|
454
|
+
let fixedCount = 0;
|
|
455
|
+
let failedCount = 0;
|
|
456
|
+
for (const file of files) {
|
|
457
|
+
if (!fs2.existsSync(file)) {
|
|
458
|
+
console.warn(chalk2.yellow(`\u26A0\uFE0F File not found: ${file}`));
|
|
459
|
+
failedCount++;
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
const spinner = ora2(`Auto-fixing ${file}...`).start();
|
|
463
|
+
try {
|
|
464
|
+
const content = fs2.readFileSync(file, "utf8");
|
|
465
|
+
const fixedContent = await agent.autoFix(content);
|
|
466
|
+
if (options.dryRun) {
|
|
467
|
+
spinner.succeed(chalk2.cyan(`[DRY RUN] ${file}`));
|
|
468
|
+
console.log(chalk2.gray(`
|
|
469
|
+
--- FIXED OUTPUT ---
|
|
470
|
+
`));
|
|
471
|
+
console.log(fixedContent);
|
|
472
|
+
console.log(chalk2.gray(`
|
|
473
|
+
--- END ---
|
|
474
|
+
`));
|
|
475
|
+
} else {
|
|
476
|
+
fs2.writeFileSync(file, fixedContent, "utf8");
|
|
477
|
+
spinner.succeed(chalk2.green(`Fixed and saved ${file}`));
|
|
478
|
+
}
|
|
479
|
+
fixedCount++;
|
|
480
|
+
} catch (err) {
|
|
481
|
+
spinner.fail(chalk2.red(`Failed to fix ${file}`));
|
|
482
|
+
console.error(err);
|
|
483
|
+
failedCount++;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
console.log(
|
|
487
|
+
chalk2.dim(
|
|
488
|
+
`
|
|
489
|
+
Summary: ${fixedCount} fixed, ${failedCount} failed out of ${files.length} files
|
|
490
|
+
`
|
|
491
|
+
)
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// src/commands/analyze.ts
|
|
496
|
+
var import_engine7 = require("@vortex/engine");
|
|
497
|
+
var import_github3 = require("@vortex/github");
|
|
498
|
+
var import_git2 = require("@vortex/git");
|
|
499
|
+
async function analyzeCommand(options) {
|
|
500
|
+
const { default: ora2 } = await import("ora");
|
|
501
|
+
const { default: chalk2 } = await import("chalk");
|
|
502
|
+
const { default: boxen } = await import("boxen");
|
|
503
|
+
const { marked } = await import("marked");
|
|
504
|
+
const { default: TerminalRenderer } = await import("marked-terminal");
|
|
505
|
+
marked.setOptions({
|
|
506
|
+
renderer: new TerminalRenderer()
|
|
507
|
+
});
|
|
508
|
+
console.log(
|
|
509
|
+
chalk2.blue.bold(`
|
|
510
|
+
Analyzing External PR #${options.pr}
|
|
511
|
+
`)
|
|
512
|
+
);
|
|
513
|
+
if (!process.env.GITHUB_TOKEN) {
|
|
514
|
+
console.error(
|
|
515
|
+
chalk2.red("Please set GITHUB_TOKEN environment variable.")
|
|
516
|
+
);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const repoInfo = (0, import_git2.getGithubRepoInfo)(process.cwd());
|
|
520
|
+
const owner = process.env.GITHUB_OWNER || repoInfo?.owner;
|
|
521
|
+
const repo = process.env.GITHUB_REPO || repoInfo?.repo;
|
|
522
|
+
if (!owner || !repo) {
|
|
523
|
+
console.error(
|
|
524
|
+
chalk2.red(
|
|
525
|
+
"Could not determine GitHub repository. Please run this command inside a git repository or set GITHUB_OWNER and GITHUB_REPO."
|
|
526
|
+
)
|
|
527
|
+
);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const spinner = ora2(
|
|
531
|
+
`Fetching diff for ${owner}/${repo}#${options.pr}...`
|
|
532
|
+
).start();
|
|
533
|
+
try {
|
|
534
|
+
const github = (0, import_github3.createGithubClient)(process.env.GITHUB_TOKEN);
|
|
535
|
+
const diff = await github.fetchPullRequestDiff(owner, repo, options.pr);
|
|
536
|
+
spinner.text = "Generating AI analysis...";
|
|
537
|
+
const agent = new import_engine7.IntelligenceAgent();
|
|
538
|
+
const review = await agent.generateReview(diff);
|
|
539
|
+
spinner.succeed(chalk2.green("Analysis complete!\n"));
|
|
540
|
+
const parsedReview = await marked.parse(review);
|
|
541
|
+
const formatted = boxen(parsedReview.trim(), {
|
|
542
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 },
|
|
543
|
+
margin: { top: 1, bottom: 1 },
|
|
544
|
+
borderStyle: "double",
|
|
545
|
+
borderColor: "magenta",
|
|
546
|
+
title: chalk2.magenta.bold(" External PR Analysis "),
|
|
547
|
+
titleAlignment: "center"
|
|
548
|
+
});
|
|
549
|
+
console.log(formatted);
|
|
550
|
+
} catch (err) {
|
|
551
|
+
spinner.fail(chalk2.red("Failed to analyze PR"));
|
|
552
|
+
console.error(err);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// src/commands/watch.ts
|
|
557
|
+
var import_engine8 = require("@vortex/engine");
|
|
558
|
+
var fs3 = __toESM(require("fs"));
|
|
559
|
+
var chokidar = __toESM(require("chokidar"));
|
|
560
|
+
async function watchCommand(options) {
|
|
561
|
+
const { default: chalk2 } = await import("chalk");
|
|
562
|
+
console.log(
|
|
563
|
+
chalk2.blue.bold("\nVortex Live Watcher\n")
|
|
564
|
+
);
|
|
565
|
+
console.log(
|
|
566
|
+
chalk2.gray(" Watching repository changes for live AI feedback...")
|
|
567
|
+
);
|
|
568
|
+
if (options.deep) {
|
|
569
|
+
console.log(
|
|
570
|
+
chalk2.yellow(
|
|
571
|
+
" \u26A0\uFE0F Deep live analysis enabled (may consume more API tokens).\n"
|
|
572
|
+
)
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
const watcher = chokidar.watch(process.cwd(), {
|
|
576
|
+
ignored: /(^|[\/\\])\\..|node_modules|dist/,
|
|
577
|
+
persistent: true
|
|
578
|
+
});
|
|
579
|
+
const agent = new import_engine8.IntelligenceAgent();
|
|
580
|
+
let isProcessing = false;
|
|
581
|
+
watcher.on("change", async (filePath) => {
|
|
582
|
+
if (isProcessing) return;
|
|
583
|
+
console.log(
|
|
584
|
+
chalk2.cyan(`
|
|
585
|
+
Detected change in ${filePath}. Analyzing...`)
|
|
586
|
+
);
|
|
587
|
+
isProcessing = true;
|
|
588
|
+
try {
|
|
589
|
+
const content = fs3.readFileSync(filePath, "utf8");
|
|
590
|
+
const feedback = await agent.generateSuggestions(content);
|
|
591
|
+
console.log(
|
|
592
|
+
chalk2.green(`
|
|
593
|
+
--- LIVE AI FEEDBACK FOR ${filePath} ---
|
|
594
|
+
`)
|
|
595
|
+
);
|
|
596
|
+
console.log(feedback);
|
|
597
|
+
} catch (err) {
|
|
598
|
+
console.error(chalk2.red("Analysis failed:"), err);
|
|
599
|
+
} finally {
|
|
600
|
+
isProcessing = false;
|
|
601
|
+
console.log(chalk2.gray("\n Watching for more changes..."));
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
console.log(chalk2.green(" Watcher started. Press Ctrl+C to exit.\n"));
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// src/commands/solve.ts
|
|
608
|
+
var import_ora = __toESM(require("ora"));
|
|
609
|
+
var readline = __toESM(require("readline/promises"));
|
|
610
|
+
var import_child_process = require("child_process");
|
|
611
|
+
var import_chalk = __toESM(require("chalk"));
|
|
612
|
+
var fs4 = __toESM(require("fs"));
|
|
613
|
+
var path2 = __toESM(require("path"));
|
|
614
|
+
var import_engine9 = require("@vortex/engine");
|
|
615
|
+
var import_db2 = require("@vortex/db");
|
|
616
|
+
var import_git3 = require("@vortex/git");
|
|
617
|
+
var import_retrieval2 = require("@vortex/retrieval");
|
|
618
|
+
async function solveCommand(prompt, options = {}) {
|
|
619
|
+
let cwd = process.cwd();
|
|
620
|
+
if (options.newProject) {
|
|
621
|
+
const projectPath = path2.resolve(cwd, options.newProject);
|
|
622
|
+
if (!fs4.existsSync(projectPath)) {
|
|
623
|
+
fs4.mkdirSync(projectPath, { recursive: true });
|
|
624
|
+
console.log(import_chalk.default.green(`
|
|
625
|
+
Created new project folder: ${projectPath}`));
|
|
626
|
+
}
|
|
627
|
+
cwd = projectPath;
|
|
628
|
+
process.chdir(cwd);
|
|
629
|
+
if (!fs4.existsSync(path2.join(cwd, ".git"))) {
|
|
630
|
+
try {
|
|
631
|
+
(0, import_child_process.execSync)("git init", { cwd, stdio: "ignore" });
|
|
632
|
+
console.log(import_chalk.default.green(`Initialized empty Git repository in ${cwd}`));
|
|
633
|
+
} catch (e) {
|
|
634
|
+
console.error(import_chalk.default.red("Failed to initialize git repository."));
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
let rootPath = cwd;
|
|
639
|
+
if ((0, import_git3.isGitRepo)(cwd)) {
|
|
640
|
+
rootPath = (0, import_git3.getGitRoot)(cwd);
|
|
641
|
+
}
|
|
642
|
+
console.log(`
|
|
643
|
+
Vortex Autonomous Agent activated`);
|
|
644
|
+
console.log(`Task: "${prompt}"
|
|
645
|
+
`);
|
|
646
|
+
await (0, import_db2.initDatabase)();
|
|
647
|
+
const spinner = (0, import_ora.default)("Initializing Vector Store for Project Memory...").start();
|
|
648
|
+
try {
|
|
649
|
+
const vectorStore = new import_retrieval2.VectorStore();
|
|
650
|
+
const bm25Index = new import_retrieval2.BM25Index();
|
|
651
|
+
const embedder = new import_retrieval2.LocalEmbedder();
|
|
652
|
+
const hybridRetriever = new import_retrieval2.HybridRetriever(vectorStore, bm25Index, embedder);
|
|
653
|
+
const agent = new import_engine9.AutonomousAgent();
|
|
654
|
+
if (options.maxSteps !== void 0) {
|
|
655
|
+
agent.maxToolIterations = options.maxSteps;
|
|
656
|
+
}
|
|
657
|
+
spinner.text = "Thinking...";
|
|
658
|
+
const approvalCallback = async (action, description) => {
|
|
659
|
+
if (options.autoApprove) return true;
|
|
660
|
+
const currentText = spinner.text;
|
|
661
|
+
spinner.stop();
|
|
662
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
663
|
+
let question = "";
|
|
664
|
+
if (action === "shell_execute") {
|
|
665
|
+
question = `
|
|
666
|
+
${import_chalk.default.yellow("\u26A0\uFE0F Agent wants to execute command:")}
|
|
667
|
+
> ${description}
|
|
668
|
+
Allow? (y/N) `;
|
|
669
|
+
} else if (action === "write_file") {
|
|
670
|
+
question = `
|
|
671
|
+
${import_chalk.default.yellow("\u26A0\uFE0F Agent wants to overwrite file:")} ${description}
|
|
672
|
+
Allow? (y/N) `;
|
|
673
|
+
} else {
|
|
674
|
+
question = `
|
|
675
|
+
${import_chalk.default.yellow("\u26A0\uFE0F Agent wants to perform action:")} ${action} on ${description}
|
|
676
|
+
Allow? (y/N) `;
|
|
677
|
+
}
|
|
678
|
+
const answer = await rl.question(question);
|
|
679
|
+
rl.close();
|
|
680
|
+
spinner.start(currentText);
|
|
681
|
+
return answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
682
|
+
};
|
|
683
|
+
agent.registerTools([
|
|
684
|
+
new import_engine9.FileReadTool(rootPath),
|
|
685
|
+
new import_engine9.FileWriteTool(rootPath, vectorStore, embedder, approvalCallback),
|
|
686
|
+
new import_engine9.ShellExecuteTool(rootPath, approvalCallback),
|
|
687
|
+
new import_engine9.GrepTool(rootPath),
|
|
688
|
+
new import_engine9.RagSearchTool(hybridRetriever)
|
|
689
|
+
]);
|
|
690
|
+
const result = await agent.run(
|
|
691
|
+
{
|
|
692
|
+
diff: prompt,
|
|
693
|
+
contextChunks: options.contextChunks || []
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
onToolCall: (toolName, args) => {
|
|
697
|
+
if (toolName === "write_file") {
|
|
698
|
+
spinner.text = `Writing file: ${args.path}...`;
|
|
699
|
+
} else if (toolName === "shell_execute") {
|
|
700
|
+
spinner.text = `Executing shell command...`;
|
|
701
|
+
} else if (toolName === "rag_search") {
|
|
702
|
+
spinner.text = `Searching project memory for context...`;
|
|
703
|
+
} else {
|
|
704
|
+
spinner.text = `Agent is using tool: ${toolName}...`;
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
onToolResult: (toolName, toolResult) => {
|
|
708
|
+
if (toolName === "write_file" && toolResult.startsWith("Success")) {
|
|
709
|
+
spinner.stop();
|
|
710
|
+
try {
|
|
711
|
+
const match = toolResult.match(/Wrote to (.*) successfully/);
|
|
712
|
+
if (match && match[1]) {
|
|
713
|
+
const filePath = match[1];
|
|
714
|
+
console.log(`
|
|
715
|
+
${import_chalk.default.green("\u2713 File updated:")} ${filePath}`);
|
|
716
|
+
const diffOut = (0, import_child_process.execSync)(`git diff --unified=1 ${filePath}`, { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] });
|
|
717
|
+
if (diffOut) {
|
|
718
|
+
console.log(import_chalk.default.gray(diffOut));
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
} catch (e) {
|
|
722
|
+
}
|
|
723
|
+
spinner.start("Thinking...");
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
);
|
|
728
|
+
spinner.succeed("Task completed");
|
|
729
|
+
try {
|
|
730
|
+
const statOut = (0, import_child_process.execSync)(`git diff --stat`, { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] });
|
|
731
|
+
if (statOut.trim()) {
|
|
732
|
+
console.log(`
|
|
733
|
+
${import_chalk.default.cyan("=== Changed Files Summary ===")}`);
|
|
734
|
+
console.log(statOut);
|
|
735
|
+
}
|
|
736
|
+
} catch (e) {
|
|
737
|
+
}
|
|
738
|
+
console.log(`
|
|
739
|
+
${import_chalk.default.cyan("=== Final Output ===")}
|
|
740
|
+
`);
|
|
741
|
+
console.log(result.summary);
|
|
742
|
+
const packageJsonPath = path2.join(cwd, "package.json");
|
|
743
|
+
if (fs4.existsSync(packageJsonPath)) {
|
|
744
|
+
try {
|
|
745
|
+
const pkg = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
|
|
746
|
+
if (pkg.scripts && pkg.scripts.build) {
|
|
747
|
+
console.log(`
|
|
748
|
+
${import_chalk.default.cyan("=== Verification ===")}`);
|
|
749
|
+
const buildSpinner = (0, import_ora.default)("Running build command...").start();
|
|
750
|
+
try {
|
|
751
|
+
const env = { ...process.env };
|
|
752
|
+
delete env.NODE_ENV;
|
|
753
|
+
(0, import_child_process.execSync)("npm run build", { stdio: "pipe", cwd, env });
|
|
754
|
+
buildSpinner.succeed("Build completed successfully.");
|
|
755
|
+
} catch (e) {
|
|
756
|
+
buildSpinner.fail("Build failed.");
|
|
757
|
+
console.error(import_chalk.default.red(e.stdout ? e.stdout.toString() : e.message));
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
} catch (e) {
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
} catch (err) {
|
|
764
|
+
spinner.fail("Agent encountered an error");
|
|
765
|
+
console.error(err.message);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// src/commands/solve-issue.ts
|
|
770
|
+
var import_engine10 = require("@vortex/engine");
|
|
771
|
+
var import_github4 = require("@vortex/github");
|
|
772
|
+
var import_git4 = require("@vortex/git");
|
|
773
|
+
async function solveIssueCommand(options) {
|
|
774
|
+
const { default: ora2 } = await import("ora");
|
|
775
|
+
const { default: chalk2 } = await import("chalk");
|
|
776
|
+
console.log(chalk2.blue(`
|
|
777
|
+
Autonomous Agent solving Issue #${options.id}`));
|
|
778
|
+
if (!process.env.GITHUB_TOKEN) {
|
|
779
|
+
console.log(chalk2.yellow("\u26A0\uFE0F No GITHUB_TOKEN found. Using anonymous access (subject to rate limits)."));
|
|
780
|
+
}
|
|
781
|
+
const repoInfo = (0, import_git4.getGithubRepoInfo)(process.cwd());
|
|
782
|
+
const owner = process.env.GITHUB_OWNER || repoInfo?.owner;
|
|
783
|
+
const repo = process.env.GITHUB_REPO || repoInfo?.repo;
|
|
784
|
+
if (!owner || !repo) {
|
|
785
|
+
console.error(chalk2.red("Could not determine GitHub repository. Please run this command inside a git repository or set GITHUB_OWNER and GITHUB_REPO."));
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
const spinner = ora2(`Fetching Issue #${options.id} from ${owner}/${repo}...`).start();
|
|
789
|
+
try {
|
|
790
|
+
const github = (0, import_github4.createGithubClient)(process.env.GITHUB_TOKEN);
|
|
791
|
+
const issue = await github.fetchIssue(owner, repo, options.id);
|
|
792
|
+
const comments = await github.fetchIssueComments(owner, repo, options.id);
|
|
793
|
+
spinner.text = `Issue fetched. Searching local vector database for relevant code...`;
|
|
794
|
+
const indexer = new import_engine10.Indexer();
|
|
795
|
+
const relevantContext = await indexer.hybridSearch(issue.title, 5);
|
|
796
|
+
spinner.succeed("Issue and Context fetched successfully!\n");
|
|
797
|
+
const prompt = `Solve the following GitHub issue:
|
|
798
|
+
# ${issue.title}
|
|
799
|
+
|
|
800
|
+
${issue.body || "No description provided."}
|
|
801
|
+
|
|
802
|
+
## Discussion Comments
|
|
803
|
+
${comments.map((c, i) => `Comment ${i + 1} (@${c.user?.login}): ${c.body}`).join("\n")}
|
|
804
|
+
|
|
805
|
+
Please fix this issue in the codebase.`;
|
|
806
|
+
const contextChunks = relevantContext.map((c) => ({
|
|
807
|
+
file: c.file,
|
|
808
|
+
symbolPath: c.symbolPath || "anonymous",
|
|
809
|
+
content: c.content,
|
|
810
|
+
kind: c.kind || "unknown"
|
|
811
|
+
}));
|
|
812
|
+
await solveCommand(prompt, {
|
|
813
|
+
autoApprove: options.autoApprove,
|
|
814
|
+
maxSteps: options.maxSteps,
|
|
815
|
+
contextChunks
|
|
816
|
+
});
|
|
817
|
+
} catch (err) {
|
|
818
|
+
spinner.fail("Failed to setup solve-issue");
|
|
819
|
+
console.error(err);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// src/commands/cache.ts
|
|
824
|
+
var import_commander = require("commander");
|
|
825
|
+
var import_engine11 = require("@vortex/engine");
|
|
826
|
+
var cacheCommand = new import_commander.Command("cache").description("Manage the LLM response cache");
|
|
827
|
+
cacheCommand.command("stats").description("View LLM cache statistics").action(async () => {
|
|
828
|
+
try {
|
|
829
|
+
const stats = await import_engine11.LLMCacheManager.getStats();
|
|
830
|
+
console.log("\nLLM Cache Statistics\n");
|
|
831
|
+
console.log(`Entries: ${stats.entries.toLocaleString()}`);
|
|
832
|
+
console.log(`Hits: ${stats.hits.toLocaleString()}`);
|
|
833
|
+
const storageMB = (stats.storage / 1024 / 1024).toFixed(2);
|
|
834
|
+
console.log(`Storage: ${storageMB} MB
|
|
835
|
+
`);
|
|
836
|
+
} catch (err) {
|
|
837
|
+
console.error("Failed to retrieve cache stats:", err);
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
cacheCommand.command("clear").description("Clear all entries from the LLM cache").action(async () => {
|
|
841
|
+
try {
|
|
842
|
+
await import_engine11.LLMCacheManager.clearCache();
|
|
843
|
+
console.log("\u2705 LLM Cache cleared successfully.");
|
|
844
|
+
} catch (err) {
|
|
845
|
+
console.error("Failed to clear LLM cache:", err);
|
|
846
|
+
}
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
// src/index.ts
|
|
850
|
+
var monorepoEnv = path3.resolve(__dirname, "../../../.env");
|
|
851
|
+
if (require("fs").existsSync(monorepoEnv)) {
|
|
852
|
+
const envConfig = dotenv.parse(require("fs").readFileSync(monorepoEnv));
|
|
853
|
+
for (const k in envConfig) {
|
|
854
|
+
if (k === "NODE_ENV") continue;
|
|
855
|
+
if (!process.env[k]) process.env[k] = envConfig[k];
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
dotenv.config({ path: path3.resolve(os.homedir(), ".vortexenv"), override: true });
|
|
859
|
+
var cwdEnv = path3.resolve(process.cwd(), ".env");
|
|
860
|
+
if (require("fs").existsSync(cwdEnv)) {
|
|
861
|
+
const envConfig = dotenv.parse(require("fs").readFileSync(cwdEnv));
|
|
862
|
+
for (const k in envConfig) {
|
|
863
|
+
if (k === "NODE_ENV") continue;
|
|
864
|
+
process.env[k] = envConfig[k];
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
var program = new import_commander2.Command();
|
|
868
|
+
program.name("vortex").description("Developer Intelligence & PR Review Engine").version("0.1.0");
|
|
869
|
+
program.hook("preAction", (thisCommand, actionCommand) => {
|
|
870
|
+
if (actionCommand.opts().cache === false) {
|
|
871
|
+
process.env.VORTEX_DISABLE_CACHE = "true";
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
program.command("init").description("Initialize repository intelligence, embeddings, and PR history").option("--reindex", "Rebuild repository embeddings while preserving historical PR intelligence").action(initCommand);
|
|
875
|
+
program.command("search").description("Search the indexed codebase semantically and get an AI explanation").requiredOption("-q, --query <text>", "Search query").option("-l, --limit <number>", "Number of results to consider", "5").option("--no-cache", "Disable LLM response caching").action(searchCommand);
|
|
876
|
+
program.command("review").description("Review your changes using repository intelligence and historical PR patterns").option("--pr <number>", "Pull request number", Number).option("--deep", "Enable deep review analysis").option("--no-cache", "Disable LLM response caching").action(reviewCommand);
|
|
877
|
+
program.command("issue").description("Analyze a GitHub issue, locate relevant codebase files, and propose a fix").requiredOption("--id <number>", "Issue number", Number).option("--no-cache", "Disable LLM response caching").action(issueCommand);
|
|
878
|
+
program.command("graph").description("Generate a Mermaid JS dependency graph of the project or a specific file").option("--file <path>", "Filter graph to only include dependencies for a specific file").option("--detailed", "Include individual functions and classes in the graph instead of just files").action(graphCommand);
|
|
879
|
+
program.command("solve").description("Autonomously solve a task by writing code and executing commands").argument("<prompt>", "The task you want the autonomous agent to solve").option("--auto-approve", "Skip interactive prompts for file writes and shell commands").option("--max-steps <number>", "Maximum number of agent loop iterations", Number, 30).option("--new-project <folder>", "Create a new project folder and initialize git before solving").action((prompt, options) => solveCommand(prompt, options));
|
|
880
|
+
program.command("solve-issue").description("Autonomously solve a GitHub issue using local RAG context").requiredOption("--id <number>", "Issue number", Number).option("--auto-approve", "Skip interactive prompts for file writes and shell commands").option("--max-steps <number>", "Maximum number of agent loop iterations", Number, 30).action(solveIssueCommand);
|
|
881
|
+
program.command("suggest").description("Generate AI-powered code suggestions using repository patterns and historical intelligence").requiredOption("--file <path>", "Target file path").option("--apply", "Apply suggestions automatically").option("--deep", "Enable advanced contextual suggestions").option("--no-cache", "Disable LLM response caching").action(suggestCommand);
|
|
882
|
+
program.command("fix-nitbits").description("Automatically fix formatting, comments, tests, CI issues, and repository-specific patterns").option("--safe", "Apply only deterministic safe fixes").option("--dry-run", "Preview fixes without modifying files").option("--files <paths>", "Comma-separated list of target files").action(fixNitbitsCommand);
|
|
883
|
+
program.command("analyze").description("Analyze other contributors' PRs using repository history and architectural intelligence").requiredOption("--pr <number>", "Pull request number", Number).option("--deep", "Enable advanced PR intelligence analysis").option("--no-cache", "Disable LLM response caching").action(analyzeCommand);
|
|
884
|
+
program.command("watch").description("Continuously monitor local changes and provide live review feedback").option("--deep", "Enable deep live analysis").action(watchCommand);
|
|
885
|
+
program.addCommand(cacheCommand);
|
|
886
|
+
program.parse();
|