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