@vortex-ai/cli 0.1.50 → 0.1.55
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 +7 -7
- package/dist/index.js +482 -272
- package/dist/index.mjs +482 -272
- package/package.json +1 -1
- package/src/commands/cache.ts +2 -2
- package/src/commands/review.ts +5 -5
- package/src/commands/search.ts +19 -7
- package/src/commands/solve-issue.ts +2 -1
- package/src/commands/solve.ts +7 -3
- package/src/index.ts +3 -0
package/dist/index.js
CHANGED
|
@@ -211002,19 +211002,16 @@ var require_dist3 = __commonJS({
|
|
|
211002
211002
|
module2.exports = __toCommonJS(index_exports);
|
|
211003
211003
|
var Prompts = {
|
|
211004
211004
|
// ── Engine / Intelligence Agent Prompts ──
|
|
211005
|
-
extractSearchQueries: (diff) => `
|
|
211006
|
-
You are an expert code analyzer.
|
|
211007
|
-
Analyze the following git diff and extract exactly 3 short search queries.
|
|
211008
|
-
These queries should be the names of the most important functions, classes, or architectural concepts that are modified or referenced in this PR.
|
|
211009
|
-
Your goal is to extract queries that can be used in a vector search engine to find the relevant codebase context.
|
|
211005
|
+
extractSearchQueries: (diff) => `You must return ONLY a valid JSON array of exactly 3 strings. Example: ["auth flow", "DatabaseService", "user login"]
|
|
211010
211006
|
|
|
211011
|
-
|
|
211007
|
+
You are an expert code analyzer.
|
|
211008
|
+
Analyze the following git diff and extract 3 short search queries.
|
|
211009
|
+
These queries should be the names of the most important functions, classes, or architectural concepts modified or referenced in this PR.
|
|
211012
211010
|
|
|
211013
211011
|
Diff:
|
|
211014
211012
|
\`\`\`diff
|
|
211015
211013
|
${diff}
|
|
211016
|
-
|
|
211017
|
-
`,
|
|
211014
|
+
\`\`\``,
|
|
211018
211015
|
ragReview: (diff, contextStr) => `
|
|
211019
211016
|
You are an expert Principal Software Engineer reviewing a pull request.
|
|
211020
211017
|
You have been provided with the git diff of the pull request, AND some relevant code chunks from the existing codebase for context.
|
|
@@ -211075,34 +211072,33 @@ Your answer must follow these strict guidelines:
|
|
|
211075
211072
|
4. **Professional Tone**: Sound like a highly experienced senior engineer mentoring a junior. Use emojis sparingly but effectively (e.g., \u{1F4A1} for tips, \u26A0\uFE0F for warnings).
|
|
211076
211073
|
5. If the provided chunks do not contain enough information to answer fully, explicitly state what is missing.
|
|
211077
211074
|
`,
|
|
211078
|
-
executionPlan: (task, contextStr) => `You
|
|
211079
|
-
|
|
211080
|
-
|
|
211081
|
-
|
|
211082
|
-
|
|
211083
|
-
|
|
211084
|
-
|
|
211085
|
-
|
|
211086
|
-
|
|
211075
|
+
executionPlan: (task, contextStr) => `You must return ONLY a structured JSON object matching this schema:
|
|
211076
|
+
{
|
|
211077
|
+
"summary": "A deep, 3-4 sentence explanation of the architectural approach.",
|
|
211078
|
+
"filesToRead": ["src/index.ts", "package.json"],
|
|
211079
|
+
"steps": [
|
|
211080
|
+
{
|
|
211081
|
+
"action": "create" | "modify" | "delete" | "test",
|
|
211082
|
+
"file": "src/App.js",
|
|
211083
|
+
"description": "A very detailed, multi-sentence explanation of exactly what code needs to be written or changed, including specific variables, functions, or UI elements to touch."
|
|
211084
|
+
}
|
|
211085
|
+
]
|
|
211086
|
+
}
|
|
211087
211087
|
|
|
211088
|
-
|
|
211088
|
+
You are a Principal AI Software Architect. Analyze the task and the extensive codebase context provided below to create a highly detailed execution plan.
|
|
211089
211089
|
|
|
211090
211090
|
Rules:
|
|
211091
|
-
|
|
211092
|
-
|
|
211093
|
-
|
|
211094
|
-
|
|
211095
|
-
|
|
211096
|
-
* Do not list speculative edge cases.
|
|
211097
|
-
* Do not create documentation-style plans and DO NOT commit anything.
|
|
211098
|
-
* Prefer concrete actions such as inspect, modify, implement, test, validate.
|
|
211091
|
+
- Make the plan EXTREMELY detailed. Do not skip steps.
|
|
211092
|
+
- Explain the 'why' and the 'how' for each step.
|
|
211093
|
+
- Include precise implementation details, such as variable names, function signatures, and logic flows.
|
|
211094
|
+
- Make sure to identify all related files that need to be read or modified.
|
|
211095
|
+
- Output ONLY valid JSON.
|
|
211099
211096
|
|
|
211100
|
-
|
|
211101
|
-
{
|
|
211102
|
-
|
|
211103
|
-
|
|
211104
|
-
}
|
|
211105
|
-
`,
|
|
211097
|
+
# Task
|
|
211098
|
+
${task}
|
|
211099
|
+
|
|
211100
|
+
# Extensive Codebase Context
|
|
211101
|
+
${contextStr}`,
|
|
211106
211102
|
// ── Multi-Agent PR Review Prompts ──
|
|
211107
211103
|
securitySystemPrompt: `You are a world-class Application Security Engineer conducting a security-focused code review.
|
|
211108
211104
|
Your ONLY job is to find GENUINE, HIGH-IMPACT security vulnerabilities in the PR diff. You do NOT care about code style, architecture, performance, or nit-picks.
|
|
@@ -211164,6 +211160,53 @@ Severity Guide:
|
|
|
211164
211160
|
|
|
211165
211161
|
If the PR does not contain any breaking or major structural issues, return an empty findings array with consistencyScore "excellent".
|
|
211166
211162
|
Return ONLY the JSON object. No markdown. No explanation outside the JSON.`,
|
|
211163
|
+
combinedReviewSystemPrompt: `You must return your findings as a valid JSON object matching this EXACT schema:
|
|
211164
|
+
{
|
|
211165
|
+
"securityFindings": [
|
|
211166
|
+
{
|
|
211167
|
+
"title": "Short title",
|
|
211168
|
+
"severity": "critical" | "high" | "medium" | "low" | "info",
|
|
211169
|
+
"description": "Detailed explanation",
|
|
211170
|
+
"file": "filename or N/A",
|
|
211171
|
+
"lineHint": "approximate line",
|
|
211172
|
+
"recommendation": "How to fix"
|
|
211173
|
+
}
|
|
211174
|
+
],
|
|
211175
|
+
"securitySummary": "1-2 sentence overall security assessment",
|
|
211176
|
+
"securityRiskLevel": "safe" | "low_risk" | "medium_risk" | "high_risk" | "critical_risk",
|
|
211177
|
+
"architectureFindings": [
|
|
211178
|
+
{
|
|
211179
|
+
"title": "Short title",
|
|
211180
|
+
"severity": "breaking" | "major" | "minor" | "suggestion",
|
|
211181
|
+
"description": "Detailed explanation",
|
|
211182
|
+
"affectedPattern": "Which existing pattern is affected",
|
|
211183
|
+
"recommendation": "How to align with existing architecture"
|
|
211184
|
+
}
|
|
211185
|
+
],
|
|
211186
|
+
"architectureSummary": "1-2 sentence overall architecture assessment",
|
|
211187
|
+
"architectureConsistencyScore": "excellent" | "good" | "fair" | "poor"
|
|
211188
|
+
}
|
|
211189
|
+
|
|
211190
|
+
You are a Principal Software Architect and Security Engineer conducting a unified code review.
|
|
211191
|
+
Your ONLY job is to analyze the PR diff for BOTH Security Vulnerabilities and Architectural Consistency.
|
|
211192
|
+
|
|
211193
|
+
RULES:
|
|
211194
|
+
- ONLY use the provided PR Diff and Codebase Context. Do not invent code.
|
|
211195
|
+
- Ignore code style, nit-picks, and low severity issues.
|
|
211196
|
+
- Do NOT flag "Prompt Injection" or "Data Exfiltration" in local CLI code.
|
|
211197
|
+
- Do NOT flag imports from \`@vortex/shared\`.
|
|
211198
|
+
|
|
211199
|
+
Example valid output:
|
|
211200
|
+
{
|
|
211201
|
+
"securityFindings": [],
|
|
211202
|
+
"securitySummary": "No high-risk vulnerabilities found.",
|
|
211203
|
+
"securityRiskLevel": "safe",
|
|
211204
|
+
"architectureFindings": [],
|
|
211205
|
+
"architectureSummary": "Architecture remains highly cohesive.",
|
|
211206
|
+
"architectureConsistencyScore": "excellent"
|
|
211207
|
+
}
|
|
211208
|
+
|
|
211209
|
+
Return ONLY valid JSON. No markdown fences.`,
|
|
211167
211210
|
synthesizerSystemPrompt: `You are a Staff Engineer writing the FINAL code review report for a pull request.
|
|
211168
211211
|
You have received analysis from two specialist agents:
|
|
211169
211212
|
1. **SecurityAgent** \u2014 found security vulnerabilities
|
|
@@ -211504,17 +211547,20 @@ var require_dist4 = __commonJS({
|
|
|
211504
211547
|
parent
|
|
211505
211548
|
} = params;
|
|
211506
211549
|
const actualContentNode = contentNode ?? node;
|
|
211507
|
-
|
|
211508
|
-
|
|
211509
|
-
);
|
|
211510
|
-
|
|
211511
|
-
|
|
211512
|
-
|
|
211513
|
-
)
|
|
211514
|
-
|
|
211515
|
-
|
|
211516
|
-
|
|
211517
|
-
|
|
211550
|
+
let content = actualContentNode.getText(sourceFile);
|
|
211551
|
+
const startLine = getLine(actualContentNode.getStart(sourceFile));
|
|
211552
|
+
const endLine = getLine(actualContentNode.getEnd());
|
|
211553
|
+
if (startLine > 1) {
|
|
211554
|
+
const allLines = source.split("\n");
|
|
211555
|
+
const startIdx = Math.max(0, startLine - 1 - 30);
|
|
211556
|
+
const prepended = allLines.slice(startIdx, startLine - 1).join("\n");
|
|
211557
|
+
if (prepended.trim().length > 0) {
|
|
211558
|
+
content = `// Context Overlap:
|
|
211559
|
+
${prepended}
|
|
211560
|
+
// End Overlap
|
|
211561
|
+
${content}`;
|
|
211562
|
+
}
|
|
211563
|
+
}
|
|
211518
211564
|
const kind = getChunkKind(node);
|
|
211519
211565
|
const symbolPath = parent ? `${parent}.${name}` : name;
|
|
211520
211566
|
const hash = getHash(content);
|
|
@@ -224913,6 +224959,7 @@ var require_dist5 = __commonJS({
|
|
|
224913
224959
|
ArchitectureSeverity: () => ArchitectureSeverity,
|
|
224914
224960
|
AutonomousAgent: () => AutonomousAgent2,
|
|
224915
224961
|
BaseAgent: () => BaseAgent,
|
|
224962
|
+
CombinedReviewOutputSchema: () => CombinedReviewOutputSchema,
|
|
224916
224963
|
FileEditTool: () => FileEditTool2,
|
|
224917
224964
|
FileReadTool: () => FileReadTool4,
|
|
224918
224965
|
FileWriteTool: () => FileWriteTool2,
|
|
@@ -224939,11 +224986,11 @@ var require_dist5 = __commonJS({
|
|
|
224939
224986
|
module2.exports = __toCommonJS(index_exports);
|
|
224940
224987
|
var import_git4 = require_dist();
|
|
224941
224988
|
var import_retrieval5 = require_dist4();
|
|
224942
|
-
var
|
|
224989
|
+
var import_shared9 = require_dist3();
|
|
224943
224990
|
var path42 = __toESM2(require("path"));
|
|
224944
224991
|
var fs4 = __toESM2(require("fs"));
|
|
224945
224992
|
var import_db3 = require_dist2();
|
|
224946
|
-
var
|
|
224993
|
+
var import_genai4 = require("@google/genai");
|
|
224947
224994
|
var import_retrieval3 = require_dist4();
|
|
224948
224995
|
var import_genai2 = require("@google/genai");
|
|
224949
224996
|
var import_genai = require("@google/genai");
|
|
@@ -224952,6 +224999,7 @@ var require_dist5 = __commonJS({
|
|
|
224952
224999
|
var import_db4 = require_dist2();
|
|
224953
225000
|
var crypto2 = __toESM2(require("crypto"));
|
|
224954
225001
|
var LLMCacheManager2 = class {
|
|
225002
|
+
static sessionCache = /* @__PURE__ */ new Map();
|
|
224955
225003
|
/**
|
|
224956
225004
|
* Generates a deterministic SHA-256 cache key.
|
|
224957
225005
|
*/
|
|
@@ -224964,7 +225012,6 @@ var require_dist5 = __commonJS({
|
|
|
224964
225012
|
model: params.model,
|
|
224965
225013
|
promptHash,
|
|
224966
225014
|
contextHash,
|
|
224967
|
-
commitHash: params.commitHash || null,
|
|
224968
225015
|
temperature: params.temperature || 0
|
|
224969
225016
|
})
|
|
224970
225017
|
).digest("hex");
|
|
@@ -224975,11 +225022,15 @@ var require_dist5 = __commonJS({
|
|
|
224975
225022
|
* Updates lastAccessedAt and hitCount on cache hit.
|
|
224976
225023
|
*/
|
|
224977
225024
|
static async getCache(key) {
|
|
225025
|
+
if (this.sessionCache.has(key)) {
|
|
225026
|
+
return this.sessionCache.get(key) || null;
|
|
225027
|
+
}
|
|
224978
225028
|
try {
|
|
224979
225029
|
const entry = await import_db4.prisma.lLMCache.findUnique({
|
|
224980
225030
|
where: { key }
|
|
224981
225031
|
});
|
|
224982
225032
|
if (!entry) return null;
|
|
225033
|
+
this.sessionCache.set(key, Promise.resolve(entry.response));
|
|
224983
225034
|
import_db4.prisma.lLMCache.update({
|
|
224984
225035
|
where: { key },
|
|
224985
225036
|
data: {
|
|
@@ -225013,6 +225064,7 @@ var require_dist5 = __commonJS({
|
|
|
225013
225064
|
lastAccessedAt: /* @__PURE__ */ new Date()
|
|
225014
225065
|
}
|
|
225015
225066
|
});
|
|
225067
|
+
this.sessionCache.set(data.key, Promise.resolve(data.response));
|
|
225016
225068
|
this.cleanupOldCache().catch(() => {
|
|
225017
225069
|
});
|
|
225018
225070
|
} catch (err) {
|
|
@@ -225023,6 +225075,7 @@ var require_dist5 = __commonJS({
|
|
|
225023
225075
|
* Clears all entries from the cache.
|
|
225024
225076
|
*/
|
|
225025
225077
|
static async clearCache() {
|
|
225078
|
+
this.sessionCache.clear();
|
|
225026
225079
|
await import_db4.prisma.lLMCache.deleteMany();
|
|
225027
225080
|
}
|
|
225028
225081
|
/**
|
|
@@ -225105,21 +225158,24 @@ var require_dist5 = __commonJS({
|
|
|
225105
225158
|
}
|
|
225106
225159
|
};
|
|
225107
225160
|
var DEFAULT_MODEL_PRIORITY = [
|
|
225161
|
+
// Gemini
|
|
225162
|
+
"gemini-2.5-flash",
|
|
225163
|
+
"gemini-3.1-flash-lite",
|
|
225164
|
+
"gemini-2.5-flash-lite",
|
|
225165
|
+
// Groq
|
|
225166
|
+
"llama-3.3-70b-versatile",
|
|
225167
|
+
"llama-3.1-8b-instant",
|
|
225168
|
+
"allam-2-7b",
|
|
225169
|
+
// OpenRouter
|
|
225108
225170
|
"nvidia/nemotron-3-ultra-550b-a55b:free",
|
|
225109
225171
|
"nex-agi/nex-n2-pro:free",
|
|
225110
225172
|
"openrouter/owl-alpha",
|
|
225111
225173
|
"nvidia/nemotron-3-super-120b-a12b:free",
|
|
225112
225174
|
"openai/gpt-oss-20b:free",
|
|
225113
225175
|
"openai/gpt-oss-120b:free",
|
|
225114
|
-
"gemini-2.5-flash",
|
|
225115
225176
|
"openai/gpt-oss-120b",
|
|
225116
|
-
"llama-3.3-70b-versatile",
|
|
225117
225177
|
"qwen/qwen3.6-27b",
|
|
225118
|
-
"qwen/qwen3-32b"
|
|
225119
|
-
"gemini-3.1-flash-lite",
|
|
225120
|
-
"gemini-2.5-flash-lite",
|
|
225121
|
-
"llama-3.1-8b-instant",
|
|
225122
|
-
"allam-2-7b"
|
|
225178
|
+
"qwen/qwen3-32b"
|
|
225123
225179
|
];
|
|
225124
225180
|
var getApiKeys = (prefix) => {
|
|
225125
225181
|
const keys = [];
|
|
@@ -225483,20 +225539,42 @@ OBSERVATIONS (${toolCalls.length} results):${toolResultsPrompts}`;
|
|
|
225483
225539
|
extractToolCalls(response) {
|
|
225484
225540
|
const cleanResponse = response.replace(/<think>[\s\S]*?<\/think>/g, "").replace(/<state_update>[\s\S]*?<\/state_update>/ig, "").trim();
|
|
225485
225541
|
const calls = [];
|
|
225486
|
-
const xmlRegex = /<([a-zA-Z0-9_]+_)?tool_call
|
|
225542
|
+
const xmlRegex = /<([a-zA-Z0-9_]+_)?tool_call>([\s\S]*?)<\/\1tool_call>/g;
|
|
225487
225543
|
let xmlMatch;
|
|
225488
225544
|
while ((xmlMatch = xmlRegex.exec(cleanResponse)) !== null) {
|
|
225489
225545
|
const prefix = xmlMatch[1] || "";
|
|
225490
|
-
const
|
|
225546
|
+
const blockContent = xmlMatch[2] || "";
|
|
225547
|
+
let name = "";
|
|
225548
|
+
const nameMatch = blockContent.match(/^\s*([a-zA-Z0-9_]+)/);
|
|
225549
|
+
const tagMatch = blockContent.match(/<([a-zA-Z0-9_]*_)?(tool_)?name>\s*([a-zA-Z0-9_]+)\s*<\/\1\2name>/);
|
|
225550
|
+
if (tagMatch && tagMatch[3]) {
|
|
225551
|
+
name = tagMatch[3].trim();
|
|
225552
|
+
} else if (nameMatch && nameMatch[1]) {
|
|
225553
|
+
name = nameMatch[1].trim();
|
|
225554
|
+
}
|
|
225491
225555
|
const args = {};
|
|
225492
225556
|
const argRegex = new RegExp(`<(${prefix})?arg_key>\\s*([^<]+)\\s*<\\/\\1?arg_key>\\s*<(${prefix})?arg_value>\\s*([\\s\\S]*?)\\s*<\\/\\3?arg_value>`, "g");
|
|
225493
225557
|
let match;
|
|
225494
|
-
while ((match = argRegex.exec(
|
|
225558
|
+
while ((match = argRegex.exec(blockContent)) !== null) {
|
|
225495
225559
|
if (match[2] && match[4]) {
|
|
225496
225560
|
args[match[2].trim()] = match[4].trim();
|
|
225497
225561
|
}
|
|
225498
225562
|
}
|
|
225499
|
-
|
|
225563
|
+
if (Object.keys(args).length === 0 || name === "write_file" && (!args.path || !args.content) || name === "replace_in_file" && (!args.path || !args.target && !args.replacement)) {
|
|
225564
|
+
const directTagRegex = /<([a-zA-Z0-9_]+)>\s*([\s\S]*?)\s*<\/\1>/g;
|
|
225565
|
+
let directMatch;
|
|
225566
|
+
while ((directMatch = directTagRegex.exec(blockContent)) !== null) {
|
|
225567
|
+
if (directMatch[1] && directMatch[2]) {
|
|
225568
|
+
const key = directMatch[1].trim();
|
|
225569
|
+
if (key !== "tool_call" && key !== "tool_name" && key !== "name" && key !== "arg_key" && key !== "arg_value") {
|
|
225570
|
+
args[key] = directMatch[2].trim();
|
|
225571
|
+
}
|
|
225572
|
+
}
|
|
225573
|
+
}
|
|
225574
|
+
}
|
|
225575
|
+
if (name) {
|
|
225576
|
+
calls.push({ name, args, isXml: true, prefix });
|
|
225577
|
+
}
|
|
225500
225578
|
}
|
|
225501
225579
|
if (calls.length > 0) return calls;
|
|
225502
225580
|
const jsonBlockMatch = cleanResponse.match(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/);
|
|
@@ -225653,6 +225731,14 @@ OBSERVATIONS (${toolCalls.length} results):${toolResultsPrompts}`;
|
|
|
225653
225731
|
summary: import_zod.z.string().describe("1-2 sentence overall architecture assessment"),
|
|
225654
225732
|
consistencyScore: import_zod.z.enum(["excellent", "good", "fair", "poor"])
|
|
225655
225733
|
});
|
|
225734
|
+
var CombinedReviewOutputSchema = import_zod.z.object({
|
|
225735
|
+
securityFindings: import_zod.z.array(SecurityFindingSchema),
|
|
225736
|
+
securitySummary: import_zod.z.string().describe("1-2 sentence overall security assessment"),
|
|
225737
|
+
securityRiskLevel: import_zod.z.enum(["safe", "low_risk", "medium_risk", "high_risk", "critical_risk"]),
|
|
225738
|
+
architectureFindings: import_zod.z.array(ArchitectureFindingSchema),
|
|
225739
|
+
architectureSummary: import_zod.z.string().describe("1-2 sentence overall architecture assessment"),
|
|
225740
|
+
architectureConsistencyScore: import_zod.z.enum(["excellent", "good", "fair", "poor"])
|
|
225741
|
+
});
|
|
225656
225742
|
var ReviewVerdictSchema = import_zod.z.enum(["SAFE_TO_MERGE", "REQUIRES_CHANGES", "NEEDS_DISCUSSION"]);
|
|
225657
225743
|
var SynthesisOutputSchema = import_zod.z.object({
|
|
225658
225744
|
verdict: ReviewVerdictSchema,
|
|
@@ -225662,128 +225748,9 @@ OBSERVATIONS (${toolCalls.length} results):${toolResultsPrompts}`;
|
|
|
225662
225748
|
markdownReport: import_zod.z.string().describe("Full beautifully formatted markdown review report")
|
|
225663
225749
|
});
|
|
225664
225750
|
var import_shared2 = require_dist3();
|
|
225665
|
-
var SecurityAgent = class extends BaseAgent {
|
|
225666
|
-
name = "SecurityAgent";
|
|
225667
|
-
systemPrompt = import_shared2.Prompts.securitySystemPrompt;
|
|
225668
|
-
buildPrompt(input) {
|
|
225669
|
-
let prompt = `## PR Diff to Review
|
|
225670
|
-
\`\`\`diff
|
|
225671
|
-
${input.diff}
|
|
225672
|
-
\`\`\`
|
|
225673
|
-
`;
|
|
225674
|
-
if (input.contextChunks.length > 0) {
|
|
225675
|
-
prompt += `
|
|
225676
|
-
## Existing Codebase Context
|
|
225677
|
-
Use this to understand what security patterns the codebase already uses:
|
|
225678
|
-
`;
|
|
225679
|
-
input.contextChunks.forEach((chunk, i) => {
|
|
225680
|
-
prompt += `
|
|
225681
|
-
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath}
|
|
225682
|
-
\`\`\`${chunk.kind}
|
|
225683
|
-
${chunk.content}
|
|
225684
|
-
\`\`\`
|
|
225685
|
-
`;
|
|
225686
|
-
});
|
|
225687
|
-
}
|
|
225688
|
-
if (input.memories && input.memories.length > 0) {
|
|
225689
|
-
prompt += `
|
|
225690
|
-
## Historical Security Context
|
|
225691
|
-
These are relevant findings from past reviews:
|
|
225692
|
-
`;
|
|
225693
|
-
input.memories.forEach((mem, i) => {
|
|
225694
|
-
prompt += `- Memory ${i + 1}: ${mem}
|
|
225695
|
-
`;
|
|
225696
|
-
});
|
|
225697
|
-
}
|
|
225698
|
-
return prompt;
|
|
225699
|
-
}
|
|
225700
|
-
parseOutput(rawResponse) {
|
|
225701
|
-
const parsed = this.extractJSON(rawResponse);
|
|
225702
|
-
if (parsed) {
|
|
225703
|
-
const validated = SecurityOutputSchema.safeParse(parsed);
|
|
225704
|
-
if (validated.success) {
|
|
225705
|
-
return {
|
|
225706
|
-
agentName: this.name,
|
|
225707
|
-
findings: validated.data.findings,
|
|
225708
|
-
summary: validated.data.summary,
|
|
225709
|
-
riskLevel: validated.data.riskLevel
|
|
225710
|
-
};
|
|
225711
|
-
}
|
|
225712
|
-
}
|
|
225713
|
-
return {
|
|
225714
|
-
agentName: this.name,
|
|
225715
|
-
findings: [],
|
|
225716
|
-
summary: rawResponse.slice(0, 500),
|
|
225717
|
-
riskLevel: "low_risk"
|
|
225718
|
-
};
|
|
225719
|
-
}
|
|
225720
|
-
};
|
|
225721
|
-
var import_shared3 = require_dist3();
|
|
225722
|
-
var ArchitectureAgent = class extends BaseAgent {
|
|
225723
|
-
name = "ArchitectureAgent";
|
|
225724
|
-
systemPrompt = import_shared3.Prompts.architectureSystemPrompt;
|
|
225725
|
-
buildPrompt(input) {
|
|
225726
|
-
let prompt = `## PR Diff to Review
|
|
225727
|
-
\`\`\`diff
|
|
225728
|
-
${input.diff}
|
|
225729
|
-
\`\`\`
|
|
225730
|
-
`;
|
|
225731
|
-
if (input.contextChunks.length > 0) {
|
|
225732
|
-
prompt += `
|
|
225733
|
-
## Existing Codebase Architecture (Retrieved Context)
|
|
225734
|
-
These are the most relevant code chunks from the existing codebase. Compare the PR diff against these patterns:
|
|
225735
|
-
`;
|
|
225736
|
-
input.contextChunks.forEach((chunk, i) => {
|
|
225737
|
-
prompt += `
|
|
225738
|
-
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath} (${chunk.kind})
|
|
225739
|
-
\`\`\`
|
|
225740
|
-
${chunk.content}
|
|
225741
|
-
\`\`\`
|
|
225742
|
-
`;
|
|
225743
|
-
});
|
|
225744
|
-
} else {
|
|
225745
|
-
prompt += `
|
|
225746
|
-
## Note
|
|
225747
|
-
No existing codebase context was retrieved. Evaluate the PR diff on its own merits, focusing on internal consistency and general best practices.
|
|
225748
|
-
`;
|
|
225749
|
-
}
|
|
225750
|
-
if (input.memories && input.memories.length > 0) {
|
|
225751
|
-
prompt += `
|
|
225752
|
-
## Historical Architecture Context
|
|
225753
|
-
These are relevant findings from past reviews:
|
|
225754
|
-
`;
|
|
225755
|
-
input.memories.forEach((mem, i) => {
|
|
225756
|
-
prompt += `- Memory ${i + 1}: ${mem}
|
|
225757
|
-
`;
|
|
225758
|
-
});
|
|
225759
|
-
}
|
|
225760
|
-
return prompt;
|
|
225761
|
-
}
|
|
225762
|
-
parseOutput(rawResponse) {
|
|
225763
|
-
const parsed = this.extractJSON(rawResponse);
|
|
225764
|
-
if (parsed) {
|
|
225765
|
-
const validated = ArchitectureOutputSchema.safeParse(parsed);
|
|
225766
|
-
if (validated.success) {
|
|
225767
|
-
return {
|
|
225768
|
-
agentName: this.name,
|
|
225769
|
-
findings: validated.data.findings,
|
|
225770
|
-
summary: validated.data.summary,
|
|
225771
|
-
consistencyScore: validated.data.consistencyScore
|
|
225772
|
-
};
|
|
225773
|
-
}
|
|
225774
|
-
}
|
|
225775
|
-
return {
|
|
225776
|
-
agentName: this.name,
|
|
225777
|
-
findings: [],
|
|
225778
|
-
summary: rawResponse.slice(0, 500),
|
|
225779
|
-
consistencyScore: "good"
|
|
225780
|
-
};
|
|
225781
|
-
}
|
|
225782
|
-
};
|
|
225783
|
-
var import_shared4 = require_dist3();
|
|
225784
225751
|
var SynthesizerAgent = class extends BaseAgent {
|
|
225785
225752
|
name = "SynthesizerAgent";
|
|
225786
|
-
systemPrompt =
|
|
225753
|
+
systemPrompt = import_shared2.Prompts.synthesizerSystemPrompt;
|
|
225787
225754
|
buildPrompt(input) {
|
|
225788
225755
|
const securityOutput = input.previousOutputs?.security;
|
|
225789
225756
|
const architectureOutput = input.previousOutputs?.architecture;
|
|
@@ -225888,57 +225855,127 @@ ${JSON.stringify(parsed, null, 2)}
|
|
|
225888
225855
|
};
|
|
225889
225856
|
}
|
|
225890
225857
|
};
|
|
225858
|
+
async function generateStructured(client, prompt, schema, options) {
|
|
225859
|
+
const maxRetries = options?.maxValidationRetries ?? 3;
|
|
225860
|
+
let currentPrompt = prompt;
|
|
225861
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
225862
|
+
const responseText = await generateWithRetry(client, currentPrompt, options);
|
|
225863
|
+
try {
|
|
225864
|
+
let cleanText = responseText.trim();
|
|
225865
|
+
if (cleanText.startsWith("```json")) {
|
|
225866
|
+
cleanText = cleanText.replace(/^```json/, "").replace(/```$/, "").trim();
|
|
225867
|
+
} else if (cleanText.startsWith("```")) {
|
|
225868
|
+
cleanText = cleanText.replace(/^```/, "").replace(/```$/, "").trim();
|
|
225869
|
+
}
|
|
225870
|
+
const parsedJson = JSON.parse(cleanText);
|
|
225871
|
+
const result = schema.safeParse(parsedJson);
|
|
225872
|
+
if (result.success) {
|
|
225873
|
+
return result.data;
|
|
225874
|
+
}
|
|
225875
|
+
const errorMsg = result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("\n");
|
|
225876
|
+
if (process.env.DEBUG) {
|
|
225877
|
+
console.warn(`[Structured LLM] Validation failed (Attempt ${attempt}/${maxRetries}):
|
|
225878
|
+
${errorMsg}`);
|
|
225879
|
+
}
|
|
225880
|
+
if (attempt === maxRetries) {
|
|
225881
|
+
throw new Error(`Failed to generate valid structured output after ${maxRetries} attempts. Last error: ${errorMsg}`);
|
|
225882
|
+
}
|
|
225883
|
+
currentPrompt += `
|
|
225884
|
+
|
|
225885
|
+
Your previous JSON response was invalid. Please fix the following errors and try again:
|
|
225886
|
+
${errorMsg}
|
|
225887
|
+
Make sure to output ONLY valid JSON matching the exact schema requested.`;
|
|
225888
|
+
} catch (e) {
|
|
225889
|
+
if (process.env.DEBUG) {
|
|
225890
|
+
console.warn(`[Structured LLM] JSON Parsing failed (Attempt ${attempt}/${maxRetries}):
|
|
225891
|
+
${e.message}`);
|
|
225892
|
+
}
|
|
225893
|
+
if (attempt === maxRetries) {
|
|
225894
|
+
throw new Error(`Failed to parse JSON after ${maxRetries} attempts. Last response: ${responseText.slice(0, 200)}...`);
|
|
225895
|
+
}
|
|
225896
|
+
currentPrompt += `
|
|
225897
|
+
|
|
225898
|
+
Your previous response was not valid JSON. Error: ${e.message}
|
|
225899
|
+
Please output ONLY valid JSON.`;
|
|
225900
|
+
}
|
|
225901
|
+
}
|
|
225902
|
+
throw new Error("Unreachable");
|
|
225903
|
+
}
|
|
225904
|
+
var import_genai3 = require("@google/genai");
|
|
225905
|
+
var import_shared3 = require_dist3();
|
|
225891
225906
|
var ReviewOrchestrator = class {
|
|
225892
|
-
securityAgent;
|
|
225893
|
-
architectureAgent;
|
|
225894
225907
|
synthesizerAgent;
|
|
225908
|
+
client;
|
|
225895
225909
|
constructor(apiKey) {
|
|
225896
|
-
|
|
225897
|
-
|
|
225910
|
+
const key = apiKey || process.env.GEMINI_API_KEY;
|
|
225911
|
+
if (!key) {
|
|
225912
|
+
throw new Error("GEMINI_API_KEY is not set.");
|
|
225913
|
+
}
|
|
225914
|
+
this.client = new import_genai3.GoogleGenAI({ apiKey: key });
|
|
225898
225915
|
this.synthesizerAgent = new SynthesizerAgent(apiKey);
|
|
225899
225916
|
}
|
|
225900
225917
|
/**
|
|
225901
225918
|
* Register tools across all agents that support self-verification.
|
|
225902
225919
|
*/
|
|
225903
225920
|
registerTools(tools) {
|
|
225904
|
-
this.
|
|
225905
|
-
this.architectureAgent.registerTools(tools);
|
|
225921
|
+
this.synthesizerAgent.registerTools(tools);
|
|
225906
225922
|
}
|
|
225907
225923
|
/**
|
|
225908
225924
|
* Runs the full multi-agent review pipeline.
|
|
225909
|
-
*
|
|
225910
|
-
* @param diff - The raw PR diff text
|
|
225911
|
-
* @param contextChunks - Relevant codebase chunks from hybrid retrieval
|
|
225912
|
-
* @param memories - Optional relevant memories from past reviews
|
|
225913
|
-
* @returns Comprehensive OrchestratedReview with all agent outputs
|
|
225914
225925
|
*/
|
|
225915
225926
|
async runReview(diff, contextChunks, memories) {
|
|
225916
225927
|
const startTime = Date.now();
|
|
225917
|
-
|
|
225918
|
-
|
|
225919
|
-
|
|
225920
|
-
|
|
225921
|
-
|
|
225922
|
-
|
|
225923
|
-
|
|
225924
|
-
|
|
225925
|
-
|
|
225926
|
-
|
|
225927
|
-
|
|
225928
|
-
|
|
225929
|
-
|
|
225930
|
-
|
|
225931
|
-
|
|
225932
|
-
|
|
225928
|
+
if (process.env.DEBUG) console.log("\nRunning Batched Security + Architecture Review...");
|
|
225929
|
+
let combinedPrompt = `## PR Diff to Review
|
|
225930
|
+
\`\`\`diff
|
|
225931
|
+
${diff}
|
|
225932
|
+
\`\`\`
|
|
225933
|
+
`;
|
|
225934
|
+
if (contextChunks.length > 0) {
|
|
225935
|
+
combinedPrompt += `
|
|
225936
|
+
## Existing Codebase Context
|
|
225937
|
+
Use this to understand what patterns the codebase already uses:
|
|
225938
|
+
`;
|
|
225939
|
+
contextChunks.forEach((chunk, i) => {
|
|
225940
|
+
combinedPrompt += `
|
|
225941
|
+
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath}
|
|
225942
|
+
\`\`\`${chunk.kind}
|
|
225943
|
+
${chunk.content}
|
|
225944
|
+
\`\`\`
|
|
225945
|
+
`;
|
|
225946
|
+
});
|
|
225947
|
+
}
|
|
225948
|
+
if (memories && memories.length > 0) {
|
|
225949
|
+
combinedPrompt += `
|
|
225950
|
+
## Historical Context
|
|
225951
|
+
These are relevant findings from past reviews:
|
|
225952
|
+
`;
|
|
225953
|
+
memories.forEach((mem, i) => {
|
|
225954
|
+
combinedPrompt += `- Memory ${i + 1}: ${mem}
|
|
225955
|
+
`;
|
|
225956
|
+
});
|
|
225957
|
+
}
|
|
225958
|
+
combinedPrompt = import_shared3.Prompts.combinedReviewSystemPrompt + "\n\n" + combinedPrompt;
|
|
225959
|
+
let combinedResult = null;
|
|
225960
|
+
try {
|
|
225961
|
+
combinedResult = await generateStructured(
|
|
225962
|
+
this.client,
|
|
225963
|
+
combinedPrompt,
|
|
225964
|
+
CombinedReviewOutputSchema,
|
|
225965
|
+
{ label: "ReviewOrchestrator (Batched)", maxValidationRetries: 3 }
|
|
225966
|
+
);
|
|
225967
|
+
} catch (err) {
|
|
225968
|
+
console.error("\nBatched Review failed:", err);
|
|
225969
|
+
}
|
|
225933
225970
|
const securityOutput = {
|
|
225934
|
-
findings:
|
|
225935
|
-
summary:
|
|
225936
|
-
riskLevel:
|
|
225971
|
+
findings: combinedResult?.securityFindings ?? [],
|
|
225972
|
+
summary: combinedResult?.securitySummary ?? "Security analysis encountered an error.",
|
|
225973
|
+
riskLevel: combinedResult?.securityRiskLevel ?? "low_risk"
|
|
225937
225974
|
};
|
|
225938
225975
|
const architectureOutput = {
|
|
225939
|
-
findings:
|
|
225940
|
-
summary:
|
|
225941
|
-
consistencyScore:
|
|
225976
|
+
findings: combinedResult?.architectureFindings ?? [],
|
|
225977
|
+
summary: combinedResult?.architectureSummary ?? "Architecture analysis encountered an error.",
|
|
225978
|
+
consistencyScore: combinedResult?.architectureConsistencyScore ?? "good"
|
|
225942
225979
|
};
|
|
225943
225980
|
if (process.env.DEBUG) {
|
|
225944
225981
|
console.log(` Security: ${securityOutput.riskLevel} (${securityOutput.findings.length} findings)`);
|
|
@@ -226002,7 +226039,7 @@ ${agentName} failed:`, err);
|
|
|
226002
226039
|
};
|
|
226003
226040
|
var import_child_process2 = require("child_process");
|
|
226004
226041
|
var crypto22 = __toESM2(require("crypto"));
|
|
226005
|
-
var
|
|
226042
|
+
var import_shared4 = require_dist3();
|
|
226006
226043
|
var IntelligenceAgent5 = class {
|
|
226007
226044
|
client;
|
|
226008
226045
|
embedder;
|
|
@@ -226013,7 +226050,7 @@ ${agentName} failed:`, err);
|
|
|
226013
226050
|
if (!key) {
|
|
226014
226051
|
throw new Error("GEMINI_API_KEY is not set.");
|
|
226015
226052
|
}
|
|
226016
|
-
this.client = new
|
|
226053
|
+
this.client = new import_genai4.GoogleGenAI({ apiKey: key });
|
|
226017
226054
|
this.embedder = new import_retrieval3.LocalEmbedder();
|
|
226018
226055
|
this.store = new import_retrieval3.VectorStore();
|
|
226019
226056
|
this.orchestrator = new ReviewOrchestrator(key);
|
|
@@ -226031,8 +226068,8 @@ ${agentName} failed:`, err);
|
|
|
226031
226068
|
}
|
|
226032
226069
|
getCurrentCommitHash() {
|
|
226033
226070
|
try {
|
|
226034
|
-
const hash = (0, import_child_process2.execSync)("git rev-parse HEAD").toString().trim();
|
|
226035
|
-
const isDirty = (0, import_child_process2.execSync)("git status --porcelain").toString().trim().length > 0;
|
|
226071
|
+
const hash = (0, import_child_process2.execSync)("git rev-parse HEAD", { stdio: ["pipe", "pipe", "ignore"] }).toString().trim();
|
|
226072
|
+
const isDirty = (0, import_child_process2.execSync)("git status --porcelain", { stdio: ["pipe", "pipe", "ignore"] }).toString().trim().length > 0;
|
|
226036
226073
|
return isDirty ? `${hash}-dirty` : hash;
|
|
226037
226074
|
} catch {
|
|
226038
226075
|
return "unknown";
|
|
@@ -226046,7 +226083,7 @@ ${agentName} failed:`, err);
|
|
|
226046
226083
|
* Extracts search queries (keywords, function names, classes) from a PR diff.
|
|
226047
226084
|
*/
|
|
226048
226085
|
async extractSearchQueriesFromDiff(diff) {
|
|
226049
|
-
const prompt =
|
|
226086
|
+
const prompt = import_shared4.Prompts.extractSearchQueries(diff);
|
|
226050
226087
|
try {
|
|
226051
226088
|
let result = await this.callLLM(prompt, { bypassCache: true });
|
|
226052
226089
|
if (result.startsWith("```")) {
|
|
@@ -226062,6 +226099,29 @@ ${agentName} failed:`, err);
|
|
|
226062
226099
|
return [];
|
|
226063
226100
|
}
|
|
226064
226101
|
}
|
|
226102
|
+
/**
|
|
226103
|
+
* Expands a single query into 3-5 variants for better retrieval recall.
|
|
226104
|
+
*/
|
|
226105
|
+
async expandQuery(query) {
|
|
226106
|
+
const prompt = `You are a search query expansion assistant.
|
|
226107
|
+
Given the user query, generate 3-5 distinct, highly relevant search queries that capture different keywords or ways to express the intent.
|
|
226108
|
+
Return ONLY a valid JSON array of strings.
|
|
226109
|
+
Query: "${query}"`;
|
|
226110
|
+
try {
|
|
226111
|
+
let result = await this.callLLM(prompt, { bypassCache: false });
|
|
226112
|
+
if (result.startsWith("```")) {
|
|
226113
|
+
result = result.replace(/^\`\`\`[a-z]*\n/, "").replace(/\n\`\`\`$/, "");
|
|
226114
|
+
}
|
|
226115
|
+
const queries = JSON.parse(result);
|
|
226116
|
+
if (Array.isArray(queries)) {
|
|
226117
|
+
return Array.from(/* @__PURE__ */ new Set([query, ...queries])).slice(0, 5);
|
|
226118
|
+
}
|
|
226119
|
+
return [query];
|
|
226120
|
+
} catch (err) {
|
|
226121
|
+
console.warn("Failed to expand query:", err);
|
|
226122
|
+
return [query];
|
|
226123
|
+
}
|
|
226124
|
+
}
|
|
226065
226125
|
/**
|
|
226066
226126
|
* Generates a context-aware RAG code review for a given PR diff.
|
|
226067
226127
|
*/
|
|
@@ -226071,7 +226131,7 @@ ${agentName} failed:`, err);
|
|
|
226071
226131
|
Code:
|
|
226072
226132
|
${c.content}`;
|
|
226073
226133
|
}).join("\n\n---\n\n");
|
|
226074
|
-
const prompt =
|
|
226134
|
+
const prompt = import_shared4.Prompts.ragReview(diff, contextStr);
|
|
226075
226135
|
const result = await this.callLLM(prompt, {
|
|
226076
226136
|
commitHash: this.getCurrentCommitHash(),
|
|
226077
226137
|
retrievalContextHash: this.computeChunksHash(chunks)
|
|
@@ -226082,7 +226142,7 @@ ${c.content}`;
|
|
|
226082
226142
|
const contextStr = relevantContext.map((c, i) => `--- Chunk ${i + 1} (${c.file} - ${c.symbolPath || "anonymous"}) ---
|
|
226083
226143
|
${c.content}`).join("\n\n");
|
|
226084
226144
|
const commentsStr = comments.map((c, i) => `Comment ${i + 1} (@${c.user?.login}): ${c.body}`).join("\n");
|
|
226085
|
-
const prompt =
|
|
226145
|
+
const prompt = import_shared4.Prompts.issueAnalysis(issueTitle, issueBody, commentsStr, contextStr);
|
|
226086
226146
|
return this.callLLM(prompt, {
|
|
226087
226147
|
commitHash: this.getCurrentCommitHash(),
|
|
226088
226148
|
retrievalContextHash: this.computeChunksHash(relevantContext)
|
|
@@ -226094,7 +226154,7 @@ ${c.content}`).join("\n\n");
|
|
|
226094
226154
|
Code:
|
|
226095
226155
|
${c.content}`;
|
|
226096
226156
|
}).join("\n\n---\n\n");
|
|
226097
|
-
const prompt =
|
|
226157
|
+
const prompt = import_shared4.Prompts.answerQuery(query, contextStr);
|
|
226098
226158
|
return await this.callLLM(prompt, {
|
|
226099
226159
|
commitHash: this.getCurrentCommitHash(),
|
|
226100
226160
|
retrievalContextHash: this.computeChunksHash(chunks)
|
|
@@ -226110,7 +226170,7 @@ ${c.content}`;
|
|
|
226110
226170
|
Code:
|
|
226111
226171
|
${c.content}`;
|
|
226112
226172
|
}).join("\n\n---\n\n");
|
|
226113
|
-
const prompt =
|
|
226173
|
+
const prompt = import_shared4.Prompts.executionPlan(task, contextStr);
|
|
226114
226174
|
let result = await this.callLLM(prompt, {
|
|
226115
226175
|
commitHash: this.getCurrentCommitHash(),
|
|
226116
226176
|
retrievalContextHash: this.computeChunksHash(contextChunks)
|
|
@@ -226143,12 +226203,131 @@ ${c.content}`;
|
|
|
226143
226203
|
return this.orchestrator.runReview(diff, contextChunks, memories);
|
|
226144
226204
|
}
|
|
226145
226205
|
};
|
|
226206
|
+
var import_shared5 = require_dist3();
|
|
226207
|
+
var SecurityAgent = class extends BaseAgent {
|
|
226208
|
+
name = "SecurityAgent";
|
|
226209
|
+
systemPrompt = import_shared5.Prompts.securitySystemPrompt;
|
|
226210
|
+
buildPrompt(input) {
|
|
226211
|
+
let prompt = `## PR Diff to Review
|
|
226212
|
+
\`\`\`diff
|
|
226213
|
+
${input.diff}
|
|
226214
|
+
\`\`\`
|
|
226215
|
+
`;
|
|
226216
|
+
if (input.contextChunks.length > 0) {
|
|
226217
|
+
prompt += `
|
|
226218
|
+
## Existing Codebase Context
|
|
226219
|
+
Use this to understand what security patterns the codebase already uses:
|
|
226220
|
+
`;
|
|
226221
|
+
input.contextChunks.forEach((chunk, i) => {
|
|
226222
|
+
prompt += `
|
|
226223
|
+
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath}
|
|
226224
|
+
\`\`\`${chunk.kind}
|
|
226225
|
+
${chunk.content}
|
|
226226
|
+
\`\`\`
|
|
226227
|
+
`;
|
|
226228
|
+
});
|
|
226229
|
+
}
|
|
226230
|
+
if (input.memories && input.memories.length > 0) {
|
|
226231
|
+
prompt += `
|
|
226232
|
+
## Historical Security Context
|
|
226233
|
+
These are relevant findings from past reviews:
|
|
226234
|
+
`;
|
|
226235
|
+
input.memories.forEach((mem, i) => {
|
|
226236
|
+
prompt += `- Memory ${i + 1}: ${mem}
|
|
226237
|
+
`;
|
|
226238
|
+
});
|
|
226239
|
+
}
|
|
226240
|
+
return prompt;
|
|
226241
|
+
}
|
|
226242
|
+
parseOutput(rawResponse) {
|
|
226243
|
+
const parsed = this.extractJSON(rawResponse);
|
|
226244
|
+
if (parsed) {
|
|
226245
|
+
const validated = SecurityOutputSchema.safeParse(parsed);
|
|
226246
|
+
if (validated.success) {
|
|
226247
|
+
return {
|
|
226248
|
+
agentName: this.name,
|
|
226249
|
+
findings: validated.data.findings,
|
|
226250
|
+
summary: validated.data.summary,
|
|
226251
|
+
riskLevel: validated.data.riskLevel
|
|
226252
|
+
};
|
|
226253
|
+
}
|
|
226254
|
+
}
|
|
226255
|
+
return {
|
|
226256
|
+
agentName: this.name,
|
|
226257
|
+
findings: [],
|
|
226258
|
+
summary: rawResponse.slice(0, 500),
|
|
226259
|
+
riskLevel: "low_risk"
|
|
226260
|
+
};
|
|
226261
|
+
}
|
|
226262
|
+
};
|
|
226146
226263
|
var import_shared6 = require_dist3();
|
|
226264
|
+
var ArchitectureAgent = class extends BaseAgent {
|
|
226265
|
+
name = "ArchitectureAgent";
|
|
226266
|
+
systemPrompt = import_shared6.Prompts.architectureSystemPrompt;
|
|
226267
|
+
buildPrompt(input) {
|
|
226268
|
+
let prompt = `## PR Diff to Review
|
|
226269
|
+
\`\`\`diff
|
|
226270
|
+
${input.diff}
|
|
226271
|
+
\`\`\`
|
|
226272
|
+
`;
|
|
226273
|
+
if (input.contextChunks.length > 0) {
|
|
226274
|
+
prompt += `
|
|
226275
|
+
## Existing Codebase Architecture (Retrieved Context)
|
|
226276
|
+
These are the most relevant code chunks from the existing codebase. Compare the PR diff against these patterns:
|
|
226277
|
+
`;
|
|
226278
|
+
input.contextChunks.forEach((chunk, i) => {
|
|
226279
|
+
prompt += `
|
|
226280
|
+
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath} (${chunk.kind})
|
|
226281
|
+
\`\`\`
|
|
226282
|
+
${chunk.content}
|
|
226283
|
+
\`\`\`
|
|
226284
|
+
`;
|
|
226285
|
+
});
|
|
226286
|
+
} else {
|
|
226287
|
+
prompt += `
|
|
226288
|
+
## Note
|
|
226289
|
+
No existing codebase context was retrieved. Evaluate the PR diff on its own merits, focusing on internal consistency and general best practices.
|
|
226290
|
+
`;
|
|
226291
|
+
}
|
|
226292
|
+
if (input.memories && input.memories.length > 0) {
|
|
226293
|
+
prompt += `
|
|
226294
|
+
## Historical Architecture Context
|
|
226295
|
+
These are relevant findings from past reviews:
|
|
226296
|
+
`;
|
|
226297
|
+
input.memories.forEach((mem, i) => {
|
|
226298
|
+
prompt += `- Memory ${i + 1}: ${mem}
|
|
226299
|
+
`;
|
|
226300
|
+
});
|
|
226301
|
+
}
|
|
226302
|
+
return prompt;
|
|
226303
|
+
}
|
|
226304
|
+
parseOutput(rawResponse) {
|
|
226305
|
+
const parsed = this.extractJSON(rawResponse);
|
|
226306
|
+
if (parsed) {
|
|
226307
|
+
const validated = ArchitectureOutputSchema.safeParse(parsed);
|
|
226308
|
+
if (validated.success) {
|
|
226309
|
+
return {
|
|
226310
|
+
agentName: this.name,
|
|
226311
|
+
findings: validated.data.findings,
|
|
226312
|
+
summary: validated.data.summary,
|
|
226313
|
+
consistencyScore: validated.data.consistencyScore
|
|
226314
|
+
};
|
|
226315
|
+
}
|
|
226316
|
+
}
|
|
226317
|
+
return {
|
|
226318
|
+
agentName: this.name,
|
|
226319
|
+
findings: [],
|
|
226320
|
+
summary: rawResponse.slice(0, 500),
|
|
226321
|
+
consistencyScore: "good"
|
|
226322
|
+
};
|
|
226323
|
+
}
|
|
226324
|
+
};
|
|
226325
|
+
var import_shared7 = require_dist3();
|
|
226147
226326
|
var AutonomousAgent2 = class extends BaseAgent {
|
|
226148
226327
|
name = "Vortex";
|
|
226149
226328
|
maxToolIterations = 30;
|
|
226150
226329
|
// overridden by maxSteps if provided
|
|
226151
|
-
systemPrompt =
|
|
226330
|
+
systemPrompt = import_shared7.Prompts.autonomousSystemPrompt;
|
|
226152
226331
|
buildPrompt(input) {
|
|
226153
226332
|
const { diff, contextChunks } = input;
|
|
226154
226333
|
let prompt = `USER TASK:
|
|
@@ -226177,7 +226356,7 @@ ${chunk.content}
|
|
|
226177
226356
|
};
|
|
226178
226357
|
var import_db22 = require_dist2();
|
|
226179
226358
|
var import_retrieval22 = require_dist4();
|
|
226180
|
-
var
|
|
226359
|
+
var import_shared8 = require_dist3();
|
|
226181
226360
|
var MemoryService3 = class {
|
|
226182
226361
|
embedder;
|
|
226183
226362
|
constructor() {
|
|
@@ -226206,7 +226385,7 @@ ${chunk.content}
|
|
|
226206
226385
|
let embedding;
|
|
226207
226386
|
try {
|
|
226208
226387
|
const embeddings = await this.embedder.embedChunks([
|
|
226209
|
-
(0,
|
|
226388
|
+
(0, import_shared8.createQueryChunk)(memoryContent, "memory")
|
|
226210
226389
|
]);
|
|
226211
226390
|
if (embeddings[0]) {
|
|
226212
226391
|
embedding = JSON.stringify(embeddings[0]);
|
|
@@ -226231,7 +226410,7 @@ ${chunk.content}
|
|
|
226231
226410
|
let embedding;
|
|
226232
226411
|
try {
|
|
226233
226412
|
const embeddings = await this.embedder.embedChunks([
|
|
226234
|
-
(0,
|
|
226413
|
+
(0, import_shared8.createQueryChunk)(content, "memory")
|
|
226235
226414
|
]);
|
|
226236
226415
|
if (embeddings[0]) {
|
|
226237
226416
|
embedding = JSON.stringify(embeddings[0]);
|
|
@@ -226253,7 +226432,7 @@ ${chunk.content}
|
|
|
226253
226432
|
let queryEmbedding = null;
|
|
226254
226433
|
try {
|
|
226255
226434
|
const embeddings = await this.embedder.embedChunks([
|
|
226256
|
-
(0,
|
|
226435
|
+
(0, import_shared8.createQueryChunk)(query)
|
|
226257
226436
|
]);
|
|
226258
226437
|
queryEmbedding = embeddings[0] ?? null;
|
|
226259
226438
|
} catch {
|
|
@@ -226273,7 +226452,7 @@ ${chunk.content}
|
|
|
226273
226452
|
if (mem.embedding) {
|
|
226274
226453
|
try {
|
|
226275
226454
|
const memEmbedding = JSON.parse(mem.embedding);
|
|
226276
|
-
similarity = (0,
|
|
226455
|
+
similarity = (0, import_shared8.cosineSimilarity)(queryEmbedding, memEmbedding);
|
|
226277
226456
|
} catch {
|
|
226278
226457
|
}
|
|
226279
226458
|
}
|
|
@@ -226793,33 +226972,50 @@ URL: ${r.url}
|
|
|
226793
226972
|
* Builds both the vector store (for semantic search) and the BM25 index (for keyword search).
|
|
226794
226973
|
*/
|
|
226795
226974
|
async indexRepository(cwd) {
|
|
226796
|
-
|
|
226797
|
-
|
|
226975
|
+
let root = cwd;
|
|
226976
|
+
if ((0, import_git4.isGitRepo)(cwd)) {
|
|
226977
|
+
try {
|
|
226978
|
+
root = (0, import_git4.getGitRoot)(cwd);
|
|
226979
|
+
} catch {
|
|
226980
|
+
}
|
|
226798
226981
|
}
|
|
226799
|
-
const root = (0, import_git4.getGitRoot)(cwd);
|
|
226800
226982
|
await (0, import_db3.initDatabase)();
|
|
226801
|
-
|
|
226802
|
-
|
|
226803
|
-
|
|
226804
|
-
|
|
226805
|
-
|
|
226806
|
-
|
|
226807
|
-
|
|
226808
|
-
|
|
226809
|
-
|
|
226810
|
-
|
|
226811
|
-
|
|
226812
|
-
|
|
226813
|
-
|
|
226814
|
-
|
|
226815
|
-
|
|
226816
|
-
|
|
226817
|
-
|
|
226818
|
-
|
|
226819
|
-
|
|
226820
|
-
|
|
226821
|
-
|
|
226822
|
-
|
|
226983
|
+
let files = [];
|
|
226984
|
+
if ((0, import_git4.isGitRepo)(cwd)) {
|
|
226985
|
+
try {
|
|
226986
|
+
const tracked = (0, import_git4.listTrackedFiles)(root).filter((file) => {
|
|
226987
|
+
const ext = path42.extname(file);
|
|
226988
|
+
const supportedExts = [
|
|
226989
|
+
".ts",
|
|
226990
|
+
".tsx",
|
|
226991
|
+
".js",
|
|
226992
|
+
".jsx",
|
|
226993
|
+
".py",
|
|
226994
|
+
".go",
|
|
226995
|
+
".rs",
|
|
226996
|
+
".java",
|
|
226997
|
+
".cpp",
|
|
226998
|
+
".hpp",
|
|
226999
|
+
".c",
|
|
227000
|
+
".h",
|
|
227001
|
+
".rb",
|
|
227002
|
+
".php",
|
|
227003
|
+
".html",
|
|
227004
|
+
".css"
|
|
227005
|
+
];
|
|
227006
|
+
return supportedExts.includes(ext) && !file.includes("node_modules");
|
|
227007
|
+
});
|
|
227008
|
+
if (tracked.length > 0) {
|
|
227009
|
+
files = tracked;
|
|
227010
|
+
}
|
|
227011
|
+
} catch (e) {
|
|
227012
|
+
}
|
|
227013
|
+
}
|
|
227014
|
+
if (files.length === 0) {
|
|
227015
|
+
for await (const file of (0, import_retrieval5.scanFiles)(root)) {
|
|
227016
|
+
files.push(file);
|
|
227017
|
+
}
|
|
227018
|
+
}
|
|
226823
227019
|
let totalChunks = 0;
|
|
226824
227020
|
for (const file of files) {
|
|
226825
227021
|
try {
|
|
@@ -226855,7 +227051,7 @@ URL: ${r.url}
|
|
|
226855
227051
|
console.log(`Generating embedding for query: "${query}"...`);
|
|
226856
227052
|
await (0, import_db3.initDatabase)();
|
|
226857
227053
|
const queryEmbedding = await this.embedder.embedChunks([
|
|
226858
|
-
(0,
|
|
227054
|
+
(0, import_shared9.createQueryChunk)(query)
|
|
226859
227055
|
]);
|
|
226860
227056
|
if (queryEmbedding.length === 0) {
|
|
226861
227057
|
return [];
|
|
@@ -227138,7 +227334,7 @@ var require_package = __commonJS({
|
|
|
227138
227334
|
"package.json"(exports2, module2) {
|
|
227139
227335
|
module2.exports = {
|
|
227140
227336
|
name: "@vortex-ai/cli",
|
|
227141
|
-
version: "0.1.
|
|
227337
|
+
version: "0.1.50",
|
|
227142
227338
|
description: "Vortex CLI - The main entry point",
|
|
227143
227339
|
main: "./dist/index.js",
|
|
227144
227340
|
bin: {
|
|
@@ -227255,17 +227451,25 @@ async function searchCommand(options) {
|
|
|
227255
227451
|
const spinner = ora2(`Searching codebase for: "${options.query}"...`).start();
|
|
227256
227452
|
const indexer = new import_engine2.Indexer();
|
|
227257
227453
|
try {
|
|
227258
|
-
spinner.text = "Running hybrid search (vector + BM25 + cross-encoder)...";
|
|
227259
|
-
|
|
227260
|
-
|
|
227454
|
+
spinner.text = options.expandQuery ? "Expanding query and running parallel hybrid search..." : "Running hybrid search (vector + BM25 + cross-encoder)...";
|
|
227455
|
+
let queriesToSearch = [options.query];
|
|
227456
|
+
const agent = new import_engine2.IntelligenceAgent();
|
|
227457
|
+
if (options.expandQuery) {
|
|
227458
|
+
queriesToSearch = await agent.expandQuery(options.query);
|
|
227459
|
+
}
|
|
227460
|
+
const allResults = await Promise.all(
|
|
227461
|
+
queriesToSearch.map((q) => indexer.hybridSearch(q, parseInt(options.limit, 10)))
|
|
227462
|
+
);
|
|
227463
|
+
const flatResults = allResults.flat();
|
|
227464
|
+
const uniqueResults = Array.from(new Map(flatResults.map((c) => [c.id, c])).values()).sort((a, b) => b.score - a.score).slice(0, parseInt(options.limit, 10));
|
|
227465
|
+
if (uniqueResults.length === 0) {
|
|
227261
227466
|
spinner.fail("No relevant code found.");
|
|
227262
227467
|
return;
|
|
227263
227468
|
}
|
|
227264
|
-
spinner.text = `Found ${
|
|
227469
|
+
spinner.text = `Found ${uniqueResults.length} relevant code chunks. Analyzing with AI engine...`;
|
|
227265
227470
|
const memoryService = new import_engine2.MemoryService();
|
|
227266
227471
|
const memories = await memoryService.recallRelevantMemories(options.query, 3);
|
|
227267
|
-
const
|
|
227268
|
-
const answer = await agent.answerQueryWithContext(options.query, results);
|
|
227472
|
+
const answer = await agent.answerQueryWithContext(options.query, uniqueResults);
|
|
227269
227473
|
spinner.succeed("Analysis complete!\n");
|
|
227270
227474
|
const parsedAnswer = await marked.parse(answer);
|
|
227271
227475
|
const formatted = boxen(parsedAnswer.trim(), {
|
|
@@ -227278,7 +227482,7 @@ async function searchCommand(options) {
|
|
|
227278
227482
|
});
|
|
227279
227483
|
console.log(formatted);
|
|
227280
227484
|
console.log(chalk2.cyan.dim(" Reference Material (Hybrid Retrieval)"));
|
|
227281
|
-
|
|
227485
|
+
uniqueResults.forEach((res, i) => {
|
|
227282
227486
|
const sources = res.sources ? res.sources.join("+") : "vector";
|
|
227283
227487
|
const scoreStr = res.score ? (res.score * 100).toFixed(1) + "%" : "N/A";
|
|
227284
227488
|
console.log(chalk2.gray(` \u2502 [${i + 1}] ${res.file.replace(process.cwd(), "")} \u2794 ${res.symbolPath || "(anonymous)"} (${scoreStr}) [${sources}]`));
|
|
@@ -227357,11 +227561,11 @@ async function reviewCommand(options) {
|
|
|
227357
227561
|
const queries = await agent.extractSearchQueriesFromDiff(diff);
|
|
227358
227562
|
const allChunks = [];
|
|
227359
227563
|
if (queries.length > 0) {
|
|
227360
|
-
spinner.text = `Hybrid searching for context...`;
|
|
227361
|
-
|
|
227362
|
-
|
|
227363
|
-
|
|
227364
|
-
|
|
227564
|
+
spinner.text = `Hybrid searching for context (parallel)...`;
|
|
227565
|
+
const allResults = await Promise.all(
|
|
227566
|
+
queries.map((query) => indexer.hybridSearch(query, 3))
|
|
227567
|
+
);
|
|
227568
|
+
allChunks.push(...allResults.flat());
|
|
227365
227569
|
}
|
|
227366
227570
|
const uniqueChunks = Array.from(
|
|
227367
227571
|
new Map(allChunks.map((c) => [c.id, c])).values()
|
|
@@ -227614,7 +227818,7 @@ Created new project folder: ${projectPath}`));
|
|
|
227614
227818
|
if (!options.contextChunks || options.contextChunks.length === 0) {
|
|
227615
227819
|
try {
|
|
227616
227820
|
const indexer = new import_engine5.Indexer();
|
|
227617
|
-
const relevantContext = await indexer.hybridSearch(prompt,
|
|
227821
|
+
const relevantContext = await indexer.hybridSearch(prompt, 15);
|
|
227618
227822
|
options.contextChunks = relevantContext.map((c) => ({
|
|
227619
227823
|
file: c.file,
|
|
227620
227824
|
symbolPath: c.symbolPath || "anonymous",
|
|
@@ -227637,7 +227841,11 @@ Created new project folder: ${projectPath}`));
|
|
|
227637
227841
|
const parsedPlan = JSON.parse(executionPlanStr);
|
|
227638
227842
|
planSummary = parsedPlan.summary || planSummary;
|
|
227639
227843
|
stepCount = parsedPlan.steps ? parsedPlan.steps.length : 0;
|
|
227640
|
-
executionPlan = parsedPlan.steps ? parsedPlan.steps.map((s, i) =>
|
|
227844
|
+
executionPlan = parsedPlan.steps ? parsedPlan.steps.map((s, i) => {
|
|
227845
|
+
if (typeof s === "string") return `${i + 1}. ${s}`;
|
|
227846
|
+
return `${i + 1}. [${(s.action || "MODIFY").toUpperCase()}] ${s.file || "General"}
|
|
227847
|
+
${s.description}`;
|
|
227848
|
+
}).join("\n\n") : executionPlanStr;
|
|
227641
227849
|
filesToRead = parsedPlan.filesToRead || [];
|
|
227642
227850
|
} catch {
|
|
227643
227851
|
executionPlan = executionPlanStr;
|
|
@@ -227734,6 +227942,7 @@ Allow? (y/N) `;
|
|
|
227734
227942
|
},
|
|
227735
227943
|
{
|
|
227736
227944
|
initialState,
|
|
227945
|
+
verifyCommand: options.verify,
|
|
227737
227946
|
onToolCall: (toolName, args) => {
|
|
227738
227947
|
if (toolName === "write_file") {
|
|
227739
227948
|
spinner.text = `Writing ${args.path}...`;
|
|
@@ -227869,7 +228078,8 @@ Please fix this issue in the codebase.`;
|
|
|
227869
228078
|
await solveCommand(prompt, {
|
|
227870
228079
|
autoApprove: options.autoApprove,
|
|
227871
228080
|
maxSteps: options.maxSteps,
|
|
227872
|
-
contextChunks
|
|
228081
|
+
contextChunks,
|
|
228082
|
+
verify: options.verify
|
|
227873
228083
|
});
|
|
227874
228084
|
} catch (err) {
|
|
227875
228085
|
spinner.fail("Failed to setup solve-issue");
|
|
@@ -227886,9 +228096,9 @@ cacheCommand.command("stats").description("View LLM cache statistics").action(as
|
|
|
227886
228096
|
const stats = await import_engine7.LLMCacheManager.getStats();
|
|
227887
228097
|
console.log("\nLLM Cache Statistics\n");
|
|
227888
228098
|
console.log(`Entries: ${stats.entries.toLocaleString()}`);
|
|
227889
|
-
console.log(`
|
|
228099
|
+
console.log(`Saved API Calls: ${stats.hits.toLocaleString()}`);
|
|
227890
228100
|
const storageMB = (stats.storage / 1024 / 1024).toFixed(2);
|
|
227891
|
-
console.log(`Storage: ${storageMB} MB
|
|
228101
|
+
console.log(`Storage Used: ${storageMB} MB
|
|
227892
228102
|
`);
|
|
227893
228103
|
} catch (err) {
|
|
227894
228104
|
console.error("Failed to retrieve cache stats:", err);
|
|
@@ -227953,12 +228163,12 @@ program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
|
227953
228163
|
}
|
|
227954
228164
|
});
|
|
227955
228165
|
program.command("init").description("Initialize repository intelligence, embeddings, and PR history").option("--reindex", "Rebuild repository embeddings while preserving historical PR intelligence").action(initCommand);
|
|
227956
|
-
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);
|
|
228166
|
+
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("--expand-query", "Expand the search query using the LLM for better recall").option("--no-cache", "Disable LLM response caching").action(searchCommand);
|
|
227957
228167
|
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);
|
|
227958
228168
|
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);
|
|
227959
228169
|
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);
|
|
227960
|
-
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));
|
|
227961
|
-
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);
|
|
228170
|
+
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").option("--verify [command]", "Run a verification command after completion (e.g., 'npm run check-types'). Agent will self-correct on failure.").action((prompt, options) => solveCommand(prompt, options));
|
|
228171
|
+
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).option("--verify [command]", "Run a verification command after completion. Agent will self-correct on failure.").action(solveIssueCommand);
|
|
227962
228172
|
program.addCommand(cacheCommand);
|
|
227963
228173
|
program.parse();
|
|
227964
228174
|
/*! Bundled license information:
|