@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.mjs
CHANGED
|
@@ -210765,19 +210765,16 @@ var require_dist3 = __commonJS({
|
|
|
210765
210765
|
module.exports = __toCommonJS(index_exports);
|
|
210766
210766
|
var Prompts = {
|
|
210767
210767
|
// ── Engine / Intelligence Agent Prompts ──
|
|
210768
|
-
extractSearchQueries: (diff) => `
|
|
210769
|
-
You are an expert code analyzer.
|
|
210770
|
-
Analyze the following git diff and extract exactly 3 short search queries.
|
|
210771
|
-
These queries should be the names of the most important functions, classes, or architectural concepts that are modified or referenced in this PR.
|
|
210772
|
-
Your goal is to extract queries that can be used in a vector search engine to find the relevant codebase context.
|
|
210768
|
+
extractSearchQueries: (diff) => `You must return ONLY a valid JSON array of exactly 3 strings. Example: ["auth flow", "DatabaseService", "user login"]
|
|
210773
210769
|
|
|
210774
|
-
|
|
210770
|
+
You are an expert code analyzer.
|
|
210771
|
+
Analyze the following git diff and extract 3 short search queries.
|
|
210772
|
+
These queries should be the names of the most important functions, classes, or architectural concepts modified or referenced in this PR.
|
|
210775
210773
|
|
|
210776
210774
|
Diff:
|
|
210777
210775
|
\`\`\`diff
|
|
210778
210776
|
${diff}
|
|
210779
|
-
|
|
210780
|
-
`,
|
|
210777
|
+
\`\`\``,
|
|
210781
210778
|
ragReview: (diff, contextStr) => `
|
|
210782
210779
|
You are an expert Principal Software Engineer reviewing a pull request.
|
|
210783
210780
|
You have been provided with the git diff of the pull request, AND some relevant code chunks from the existing codebase for context.
|
|
@@ -210838,34 +210835,33 @@ Your answer must follow these strict guidelines:
|
|
|
210838
210835
|
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).
|
|
210839
210836
|
5. If the provided chunks do not contain enough information to answer fully, explicitly state what is missing.
|
|
210840
210837
|
`,
|
|
210841
|
-
executionPlan: (task, contextStr) => `You
|
|
210842
|
-
|
|
210843
|
-
|
|
210844
|
-
|
|
210845
|
-
|
|
210846
|
-
|
|
210847
|
-
|
|
210848
|
-
|
|
210849
|
-
|
|
210838
|
+
executionPlan: (task, contextStr) => `You must return ONLY a structured JSON object matching this schema:
|
|
210839
|
+
{
|
|
210840
|
+
"summary": "A deep, 3-4 sentence explanation of the architectural approach.",
|
|
210841
|
+
"filesToRead": ["src/index.ts", "package.json"],
|
|
210842
|
+
"steps": [
|
|
210843
|
+
{
|
|
210844
|
+
"action": "create" | "modify" | "delete" | "test",
|
|
210845
|
+
"file": "src/App.js",
|
|
210846
|
+
"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."
|
|
210847
|
+
}
|
|
210848
|
+
]
|
|
210849
|
+
}
|
|
210850
210850
|
|
|
210851
|
-
|
|
210851
|
+
You are a Principal AI Software Architect. Analyze the task and the extensive codebase context provided below to create a highly detailed execution plan.
|
|
210852
210852
|
|
|
210853
210853
|
Rules:
|
|
210854
|
-
|
|
210855
|
-
|
|
210856
|
-
|
|
210857
|
-
|
|
210858
|
-
|
|
210859
|
-
* Do not list speculative edge cases.
|
|
210860
|
-
* Do not create documentation-style plans and DO NOT commit anything.
|
|
210861
|
-
* Prefer concrete actions such as inspect, modify, implement, test, validate.
|
|
210854
|
+
- Make the plan EXTREMELY detailed. Do not skip steps.
|
|
210855
|
+
- Explain the 'why' and the 'how' for each step.
|
|
210856
|
+
- Include precise implementation details, such as variable names, function signatures, and logic flows.
|
|
210857
|
+
- Make sure to identify all related files that need to be read or modified.
|
|
210858
|
+
- Output ONLY valid JSON.
|
|
210862
210859
|
|
|
210863
|
-
|
|
210864
|
-
{
|
|
210865
|
-
|
|
210866
|
-
|
|
210867
|
-
}
|
|
210868
|
-
`,
|
|
210860
|
+
# Task
|
|
210861
|
+
${task}
|
|
210862
|
+
|
|
210863
|
+
# Extensive Codebase Context
|
|
210864
|
+
${contextStr}`,
|
|
210869
210865
|
// ── Multi-Agent PR Review Prompts ──
|
|
210870
210866
|
securitySystemPrompt: `You are a world-class Application Security Engineer conducting a security-focused code review.
|
|
210871
210867
|
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.
|
|
@@ -210927,6 +210923,53 @@ Severity Guide:
|
|
|
210927
210923
|
|
|
210928
210924
|
If the PR does not contain any breaking or major structural issues, return an empty findings array with consistencyScore "excellent".
|
|
210929
210925
|
Return ONLY the JSON object. No markdown. No explanation outside the JSON.`,
|
|
210926
|
+
combinedReviewSystemPrompt: `You must return your findings as a valid JSON object matching this EXACT schema:
|
|
210927
|
+
{
|
|
210928
|
+
"securityFindings": [
|
|
210929
|
+
{
|
|
210930
|
+
"title": "Short title",
|
|
210931
|
+
"severity": "critical" | "high" | "medium" | "low" | "info",
|
|
210932
|
+
"description": "Detailed explanation",
|
|
210933
|
+
"file": "filename or N/A",
|
|
210934
|
+
"lineHint": "approximate line",
|
|
210935
|
+
"recommendation": "How to fix"
|
|
210936
|
+
}
|
|
210937
|
+
],
|
|
210938
|
+
"securitySummary": "1-2 sentence overall security assessment",
|
|
210939
|
+
"securityRiskLevel": "safe" | "low_risk" | "medium_risk" | "high_risk" | "critical_risk",
|
|
210940
|
+
"architectureFindings": [
|
|
210941
|
+
{
|
|
210942
|
+
"title": "Short title",
|
|
210943
|
+
"severity": "breaking" | "major" | "minor" | "suggestion",
|
|
210944
|
+
"description": "Detailed explanation",
|
|
210945
|
+
"affectedPattern": "Which existing pattern is affected",
|
|
210946
|
+
"recommendation": "How to align with existing architecture"
|
|
210947
|
+
}
|
|
210948
|
+
],
|
|
210949
|
+
"architectureSummary": "1-2 sentence overall architecture assessment",
|
|
210950
|
+
"architectureConsistencyScore": "excellent" | "good" | "fair" | "poor"
|
|
210951
|
+
}
|
|
210952
|
+
|
|
210953
|
+
You are a Principal Software Architect and Security Engineer conducting a unified code review.
|
|
210954
|
+
Your ONLY job is to analyze the PR diff for BOTH Security Vulnerabilities and Architectural Consistency.
|
|
210955
|
+
|
|
210956
|
+
RULES:
|
|
210957
|
+
- ONLY use the provided PR Diff and Codebase Context. Do not invent code.
|
|
210958
|
+
- Ignore code style, nit-picks, and low severity issues.
|
|
210959
|
+
- Do NOT flag "Prompt Injection" or "Data Exfiltration" in local CLI code.
|
|
210960
|
+
- Do NOT flag imports from \`@vortex/shared\`.
|
|
210961
|
+
|
|
210962
|
+
Example valid output:
|
|
210963
|
+
{
|
|
210964
|
+
"securityFindings": [],
|
|
210965
|
+
"securitySummary": "No high-risk vulnerabilities found.",
|
|
210966
|
+
"securityRiskLevel": "safe",
|
|
210967
|
+
"architectureFindings": [],
|
|
210968
|
+
"architectureSummary": "Architecture remains highly cohesive.",
|
|
210969
|
+
"architectureConsistencyScore": "excellent"
|
|
210970
|
+
}
|
|
210971
|
+
|
|
210972
|
+
Return ONLY valid JSON. No markdown fences.`,
|
|
210930
210973
|
synthesizerSystemPrompt: `You are a Staff Engineer writing the FINAL code review report for a pull request.
|
|
210931
210974
|
You have received analysis from two specialist agents:
|
|
210932
210975
|
1. **SecurityAgent** \u2014 found security vulnerabilities
|
|
@@ -211267,17 +211310,20 @@ var require_dist4 = __commonJS({
|
|
|
211267
211310
|
parent
|
|
211268
211311
|
} = params;
|
|
211269
211312
|
const actualContentNode = contentNode ?? node;
|
|
211270
|
-
|
|
211271
|
-
|
|
211272
|
-
);
|
|
211273
|
-
|
|
211274
|
-
|
|
211275
|
-
|
|
211276
|
-
)
|
|
211277
|
-
|
|
211278
|
-
|
|
211279
|
-
|
|
211280
|
-
|
|
211313
|
+
let content = actualContentNode.getText(sourceFile);
|
|
211314
|
+
const startLine = getLine(actualContentNode.getStart(sourceFile));
|
|
211315
|
+
const endLine = getLine(actualContentNode.getEnd());
|
|
211316
|
+
if (startLine > 1) {
|
|
211317
|
+
const allLines = source.split("\n");
|
|
211318
|
+
const startIdx = Math.max(0, startLine - 1 - 30);
|
|
211319
|
+
const prepended = allLines.slice(startIdx, startLine - 1).join("\n");
|
|
211320
|
+
if (prepended.trim().length > 0) {
|
|
211321
|
+
content = `// Context Overlap:
|
|
211322
|
+
${prepended}
|
|
211323
|
+
// End Overlap
|
|
211324
|
+
${content}`;
|
|
211325
|
+
}
|
|
211326
|
+
}
|
|
211281
211327
|
const kind = getChunkKind(node);
|
|
211282
211328
|
const symbolPath = parent ? `${parent}.${name}` : name;
|
|
211283
211329
|
const hash = getHash(content);
|
|
@@ -224676,6 +224722,7 @@ var require_dist5 = __commonJS({
|
|
|
224676
224722
|
ArchitectureSeverity: () => ArchitectureSeverity,
|
|
224677
224723
|
AutonomousAgent: () => AutonomousAgent2,
|
|
224678
224724
|
BaseAgent: () => BaseAgent,
|
|
224725
|
+
CombinedReviewOutputSchema: () => CombinedReviewOutputSchema,
|
|
224679
224726
|
FileEditTool: () => FileEditTool2,
|
|
224680
224727
|
FileReadTool: () => FileReadTool4,
|
|
224681
224728
|
FileWriteTool: () => FileWriteTool2,
|
|
@@ -224702,11 +224749,11 @@ var require_dist5 = __commonJS({
|
|
|
224702
224749
|
module.exports = __toCommonJS(index_exports);
|
|
224703
224750
|
var import_git4 = require_dist();
|
|
224704
224751
|
var import_retrieval5 = require_dist4();
|
|
224705
|
-
var
|
|
224752
|
+
var import_shared9 = require_dist3();
|
|
224706
224753
|
var path42 = __toESM2(__require("path"));
|
|
224707
224754
|
var fs4 = __toESM2(__require("fs"));
|
|
224708
224755
|
var import_db3 = require_dist2();
|
|
224709
|
-
var
|
|
224756
|
+
var import_genai4 = __require("@google/genai");
|
|
224710
224757
|
var import_retrieval3 = require_dist4();
|
|
224711
224758
|
var import_genai2 = __require("@google/genai");
|
|
224712
224759
|
var import_genai = __require("@google/genai");
|
|
@@ -224715,6 +224762,7 @@ var require_dist5 = __commonJS({
|
|
|
224715
224762
|
var import_db4 = require_dist2();
|
|
224716
224763
|
var crypto2 = __toESM2(__require("crypto"));
|
|
224717
224764
|
var LLMCacheManager2 = class {
|
|
224765
|
+
static sessionCache = /* @__PURE__ */ new Map();
|
|
224718
224766
|
/**
|
|
224719
224767
|
* Generates a deterministic SHA-256 cache key.
|
|
224720
224768
|
*/
|
|
@@ -224727,7 +224775,6 @@ var require_dist5 = __commonJS({
|
|
|
224727
224775
|
model: params.model,
|
|
224728
224776
|
promptHash,
|
|
224729
224777
|
contextHash,
|
|
224730
|
-
commitHash: params.commitHash || null,
|
|
224731
224778
|
temperature: params.temperature || 0
|
|
224732
224779
|
})
|
|
224733
224780
|
).digest("hex");
|
|
@@ -224738,11 +224785,15 @@ var require_dist5 = __commonJS({
|
|
|
224738
224785
|
* Updates lastAccessedAt and hitCount on cache hit.
|
|
224739
224786
|
*/
|
|
224740
224787
|
static async getCache(key) {
|
|
224788
|
+
if (this.sessionCache.has(key)) {
|
|
224789
|
+
return this.sessionCache.get(key) || null;
|
|
224790
|
+
}
|
|
224741
224791
|
try {
|
|
224742
224792
|
const entry = await import_db4.prisma.lLMCache.findUnique({
|
|
224743
224793
|
where: { key }
|
|
224744
224794
|
});
|
|
224745
224795
|
if (!entry) return null;
|
|
224796
|
+
this.sessionCache.set(key, Promise.resolve(entry.response));
|
|
224746
224797
|
import_db4.prisma.lLMCache.update({
|
|
224747
224798
|
where: { key },
|
|
224748
224799
|
data: {
|
|
@@ -224776,6 +224827,7 @@ var require_dist5 = __commonJS({
|
|
|
224776
224827
|
lastAccessedAt: /* @__PURE__ */ new Date()
|
|
224777
224828
|
}
|
|
224778
224829
|
});
|
|
224830
|
+
this.sessionCache.set(data.key, Promise.resolve(data.response));
|
|
224779
224831
|
this.cleanupOldCache().catch(() => {
|
|
224780
224832
|
});
|
|
224781
224833
|
} catch (err) {
|
|
@@ -224786,6 +224838,7 @@ var require_dist5 = __commonJS({
|
|
|
224786
224838
|
* Clears all entries from the cache.
|
|
224787
224839
|
*/
|
|
224788
224840
|
static async clearCache() {
|
|
224841
|
+
this.sessionCache.clear();
|
|
224789
224842
|
await import_db4.prisma.lLMCache.deleteMany();
|
|
224790
224843
|
}
|
|
224791
224844
|
/**
|
|
@@ -224868,21 +224921,24 @@ var require_dist5 = __commonJS({
|
|
|
224868
224921
|
}
|
|
224869
224922
|
};
|
|
224870
224923
|
var DEFAULT_MODEL_PRIORITY = [
|
|
224924
|
+
// Gemini
|
|
224925
|
+
"gemini-2.5-flash",
|
|
224926
|
+
"gemini-3.1-flash-lite",
|
|
224927
|
+
"gemini-2.5-flash-lite",
|
|
224928
|
+
// Groq
|
|
224929
|
+
"llama-3.3-70b-versatile",
|
|
224930
|
+
"llama-3.1-8b-instant",
|
|
224931
|
+
"allam-2-7b",
|
|
224932
|
+
// OpenRouter
|
|
224871
224933
|
"nvidia/nemotron-3-ultra-550b-a55b:free",
|
|
224872
224934
|
"nex-agi/nex-n2-pro:free",
|
|
224873
224935
|
"openrouter/owl-alpha",
|
|
224874
224936
|
"nvidia/nemotron-3-super-120b-a12b:free",
|
|
224875
224937
|
"openai/gpt-oss-20b:free",
|
|
224876
224938
|
"openai/gpt-oss-120b:free",
|
|
224877
|
-
"gemini-2.5-flash",
|
|
224878
224939
|
"openai/gpt-oss-120b",
|
|
224879
|
-
"llama-3.3-70b-versatile",
|
|
224880
224940
|
"qwen/qwen3.6-27b",
|
|
224881
|
-
"qwen/qwen3-32b"
|
|
224882
|
-
"gemini-3.1-flash-lite",
|
|
224883
|
-
"gemini-2.5-flash-lite",
|
|
224884
|
-
"llama-3.1-8b-instant",
|
|
224885
|
-
"allam-2-7b"
|
|
224941
|
+
"qwen/qwen3-32b"
|
|
224886
224942
|
];
|
|
224887
224943
|
var getApiKeys = (prefix) => {
|
|
224888
224944
|
const keys = [];
|
|
@@ -225246,20 +225302,42 @@ OBSERVATIONS (${toolCalls.length} results):${toolResultsPrompts}`;
|
|
|
225246
225302
|
extractToolCalls(response) {
|
|
225247
225303
|
const cleanResponse = response.replace(/<think>[\s\S]*?<\/think>/g, "").replace(/<state_update>[\s\S]*?<\/state_update>/ig, "").trim();
|
|
225248
225304
|
const calls = [];
|
|
225249
|
-
const xmlRegex = /<([a-zA-Z0-9_]+_)?tool_call
|
|
225305
|
+
const xmlRegex = /<([a-zA-Z0-9_]+_)?tool_call>([\s\S]*?)<\/\1tool_call>/g;
|
|
225250
225306
|
let xmlMatch;
|
|
225251
225307
|
while ((xmlMatch = xmlRegex.exec(cleanResponse)) !== null) {
|
|
225252
225308
|
const prefix = xmlMatch[1] || "";
|
|
225253
|
-
const
|
|
225309
|
+
const blockContent = xmlMatch[2] || "";
|
|
225310
|
+
let name = "";
|
|
225311
|
+
const nameMatch = blockContent.match(/^\s*([a-zA-Z0-9_]+)/);
|
|
225312
|
+
const tagMatch = blockContent.match(/<([a-zA-Z0-9_]*_)?(tool_)?name>\s*([a-zA-Z0-9_]+)\s*<\/\1\2name>/);
|
|
225313
|
+
if (tagMatch && tagMatch[3]) {
|
|
225314
|
+
name = tagMatch[3].trim();
|
|
225315
|
+
} else if (nameMatch && nameMatch[1]) {
|
|
225316
|
+
name = nameMatch[1].trim();
|
|
225317
|
+
}
|
|
225254
225318
|
const args = {};
|
|
225255
225319
|
const argRegex = new RegExp(`<(${prefix})?arg_key>\\s*([^<]+)\\s*<\\/\\1?arg_key>\\s*<(${prefix})?arg_value>\\s*([\\s\\S]*?)\\s*<\\/\\3?arg_value>`, "g");
|
|
225256
225320
|
let match;
|
|
225257
|
-
while ((match = argRegex.exec(
|
|
225321
|
+
while ((match = argRegex.exec(blockContent)) !== null) {
|
|
225258
225322
|
if (match[2] && match[4]) {
|
|
225259
225323
|
args[match[2].trim()] = match[4].trim();
|
|
225260
225324
|
}
|
|
225261
225325
|
}
|
|
225262
|
-
|
|
225326
|
+
if (Object.keys(args).length === 0 || name === "write_file" && (!args.path || !args.content) || name === "replace_in_file" && (!args.path || !args.target && !args.replacement)) {
|
|
225327
|
+
const directTagRegex = /<([a-zA-Z0-9_]+)>\s*([\s\S]*?)\s*<\/\1>/g;
|
|
225328
|
+
let directMatch;
|
|
225329
|
+
while ((directMatch = directTagRegex.exec(blockContent)) !== null) {
|
|
225330
|
+
if (directMatch[1] && directMatch[2]) {
|
|
225331
|
+
const key = directMatch[1].trim();
|
|
225332
|
+
if (key !== "tool_call" && key !== "tool_name" && key !== "name" && key !== "arg_key" && key !== "arg_value") {
|
|
225333
|
+
args[key] = directMatch[2].trim();
|
|
225334
|
+
}
|
|
225335
|
+
}
|
|
225336
|
+
}
|
|
225337
|
+
}
|
|
225338
|
+
if (name) {
|
|
225339
|
+
calls.push({ name, args, isXml: true, prefix });
|
|
225340
|
+
}
|
|
225263
225341
|
}
|
|
225264
225342
|
if (calls.length > 0) return calls;
|
|
225265
225343
|
const jsonBlockMatch = cleanResponse.match(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/);
|
|
@@ -225416,6 +225494,14 @@ OBSERVATIONS (${toolCalls.length} results):${toolResultsPrompts}`;
|
|
|
225416
225494
|
summary: import_zod.z.string().describe("1-2 sentence overall architecture assessment"),
|
|
225417
225495
|
consistencyScore: import_zod.z.enum(["excellent", "good", "fair", "poor"])
|
|
225418
225496
|
});
|
|
225497
|
+
var CombinedReviewOutputSchema = import_zod.z.object({
|
|
225498
|
+
securityFindings: import_zod.z.array(SecurityFindingSchema),
|
|
225499
|
+
securitySummary: import_zod.z.string().describe("1-2 sentence overall security assessment"),
|
|
225500
|
+
securityRiskLevel: import_zod.z.enum(["safe", "low_risk", "medium_risk", "high_risk", "critical_risk"]),
|
|
225501
|
+
architectureFindings: import_zod.z.array(ArchitectureFindingSchema),
|
|
225502
|
+
architectureSummary: import_zod.z.string().describe("1-2 sentence overall architecture assessment"),
|
|
225503
|
+
architectureConsistencyScore: import_zod.z.enum(["excellent", "good", "fair", "poor"])
|
|
225504
|
+
});
|
|
225419
225505
|
var ReviewVerdictSchema = import_zod.z.enum(["SAFE_TO_MERGE", "REQUIRES_CHANGES", "NEEDS_DISCUSSION"]);
|
|
225420
225506
|
var SynthesisOutputSchema = import_zod.z.object({
|
|
225421
225507
|
verdict: ReviewVerdictSchema,
|
|
@@ -225425,128 +225511,9 @@ OBSERVATIONS (${toolCalls.length} results):${toolResultsPrompts}`;
|
|
|
225425
225511
|
markdownReport: import_zod.z.string().describe("Full beautifully formatted markdown review report")
|
|
225426
225512
|
});
|
|
225427
225513
|
var import_shared2 = require_dist3();
|
|
225428
|
-
var SecurityAgent = class extends BaseAgent {
|
|
225429
|
-
name = "SecurityAgent";
|
|
225430
|
-
systemPrompt = import_shared2.Prompts.securitySystemPrompt;
|
|
225431
|
-
buildPrompt(input) {
|
|
225432
|
-
let prompt = `## PR Diff to Review
|
|
225433
|
-
\`\`\`diff
|
|
225434
|
-
${input.diff}
|
|
225435
|
-
\`\`\`
|
|
225436
|
-
`;
|
|
225437
|
-
if (input.contextChunks.length > 0) {
|
|
225438
|
-
prompt += `
|
|
225439
|
-
## Existing Codebase Context
|
|
225440
|
-
Use this to understand what security patterns the codebase already uses:
|
|
225441
|
-
`;
|
|
225442
|
-
input.contextChunks.forEach((chunk, i) => {
|
|
225443
|
-
prompt += `
|
|
225444
|
-
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath}
|
|
225445
|
-
\`\`\`${chunk.kind}
|
|
225446
|
-
${chunk.content}
|
|
225447
|
-
\`\`\`
|
|
225448
|
-
`;
|
|
225449
|
-
});
|
|
225450
|
-
}
|
|
225451
|
-
if (input.memories && input.memories.length > 0) {
|
|
225452
|
-
prompt += `
|
|
225453
|
-
## Historical Security Context
|
|
225454
|
-
These are relevant findings from past reviews:
|
|
225455
|
-
`;
|
|
225456
|
-
input.memories.forEach((mem, i) => {
|
|
225457
|
-
prompt += `- Memory ${i + 1}: ${mem}
|
|
225458
|
-
`;
|
|
225459
|
-
});
|
|
225460
|
-
}
|
|
225461
|
-
return prompt;
|
|
225462
|
-
}
|
|
225463
|
-
parseOutput(rawResponse) {
|
|
225464
|
-
const parsed = this.extractJSON(rawResponse);
|
|
225465
|
-
if (parsed) {
|
|
225466
|
-
const validated = SecurityOutputSchema.safeParse(parsed);
|
|
225467
|
-
if (validated.success) {
|
|
225468
|
-
return {
|
|
225469
|
-
agentName: this.name,
|
|
225470
|
-
findings: validated.data.findings,
|
|
225471
|
-
summary: validated.data.summary,
|
|
225472
|
-
riskLevel: validated.data.riskLevel
|
|
225473
|
-
};
|
|
225474
|
-
}
|
|
225475
|
-
}
|
|
225476
|
-
return {
|
|
225477
|
-
agentName: this.name,
|
|
225478
|
-
findings: [],
|
|
225479
|
-
summary: rawResponse.slice(0, 500),
|
|
225480
|
-
riskLevel: "low_risk"
|
|
225481
|
-
};
|
|
225482
|
-
}
|
|
225483
|
-
};
|
|
225484
|
-
var import_shared3 = require_dist3();
|
|
225485
|
-
var ArchitectureAgent = class extends BaseAgent {
|
|
225486
|
-
name = "ArchitectureAgent";
|
|
225487
|
-
systemPrompt = import_shared3.Prompts.architectureSystemPrompt;
|
|
225488
|
-
buildPrompt(input) {
|
|
225489
|
-
let prompt = `## PR Diff to Review
|
|
225490
|
-
\`\`\`diff
|
|
225491
|
-
${input.diff}
|
|
225492
|
-
\`\`\`
|
|
225493
|
-
`;
|
|
225494
|
-
if (input.contextChunks.length > 0) {
|
|
225495
|
-
prompt += `
|
|
225496
|
-
## Existing Codebase Architecture (Retrieved Context)
|
|
225497
|
-
These are the most relevant code chunks from the existing codebase. Compare the PR diff against these patterns:
|
|
225498
|
-
`;
|
|
225499
|
-
input.contextChunks.forEach((chunk, i) => {
|
|
225500
|
-
prompt += `
|
|
225501
|
-
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath} (${chunk.kind})
|
|
225502
|
-
\`\`\`
|
|
225503
|
-
${chunk.content}
|
|
225504
|
-
\`\`\`
|
|
225505
|
-
`;
|
|
225506
|
-
});
|
|
225507
|
-
} else {
|
|
225508
|
-
prompt += `
|
|
225509
|
-
## Note
|
|
225510
|
-
No existing codebase context was retrieved. Evaluate the PR diff on its own merits, focusing on internal consistency and general best practices.
|
|
225511
|
-
`;
|
|
225512
|
-
}
|
|
225513
|
-
if (input.memories && input.memories.length > 0) {
|
|
225514
|
-
prompt += `
|
|
225515
|
-
## Historical Architecture Context
|
|
225516
|
-
These are relevant findings from past reviews:
|
|
225517
|
-
`;
|
|
225518
|
-
input.memories.forEach((mem, i) => {
|
|
225519
|
-
prompt += `- Memory ${i + 1}: ${mem}
|
|
225520
|
-
`;
|
|
225521
|
-
});
|
|
225522
|
-
}
|
|
225523
|
-
return prompt;
|
|
225524
|
-
}
|
|
225525
|
-
parseOutput(rawResponse) {
|
|
225526
|
-
const parsed = this.extractJSON(rawResponse);
|
|
225527
|
-
if (parsed) {
|
|
225528
|
-
const validated = ArchitectureOutputSchema.safeParse(parsed);
|
|
225529
|
-
if (validated.success) {
|
|
225530
|
-
return {
|
|
225531
|
-
agentName: this.name,
|
|
225532
|
-
findings: validated.data.findings,
|
|
225533
|
-
summary: validated.data.summary,
|
|
225534
|
-
consistencyScore: validated.data.consistencyScore
|
|
225535
|
-
};
|
|
225536
|
-
}
|
|
225537
|
-
}
|
|
225538
|
-
return {
|
|
225539
|
-
agentName: this.name,
|
|
225540
|
-
findings: [],
|
|
225541
|
-
summary: rawResponse.slice(0, 500),
|
|
225542
|
-
consistencyScore: "good"
|
|
225543
|
-
};
|
|
225544
|
-
}
|
|
225545
|
-
};
|
|
225546
|
-
var import_shared4 = require_dist3();
|
|
225547
225514
|
var SynthesizerAgent = class extends BaseAgent {
|
|
225548
225515
|
name = "SynthesizerAgent";
|
|
225549
|
-
systemPrompt =
|
|
225516
|
+
systemPrompt = import_shared2.Prompts.synthesizerSystemPrompt;
|
|
225550
225517
|
buildPrompt(input) {
|
|
225551
225518
|
const securityOutput = input.previousOutputs?.security;
|
|
225552
225519
|
const architectureOutput = input.previousOutputs?.architecture;
|
|
@@ -225651,57 +225618,127 @@ ${JSON.stringify(parsed, null, 2)}
|
|
|
225651
225618
|
};
|
|
225652
225619
|
}
|
|
225653
225620
|
};
|
|
225621
|
+
async function generateStructured(client, prompt, schema, options) {
|
|
225622
|
+
const maxRetries = options?.maxValidationRetries ?? 3;
|
|
225623
|
+
let currentPrompt = prompt;
|
|
225624
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
225625
|
+
const responseText = await generateWithRetry(client, currentPrompt, options);
|
|
225626
|
+
try {
|
|
225627
|
+
let cleanText = responseText.trim();
|
|
225628
|
+
if (cleanText.startsWith("```json")) {
|
|
225629
|
+
cleanText = cleanText.replace(/^```json/, "").replace(/```$/, "").trim();
|
|
225630
|
+
} else if (cleanText.startsWith("```")) {
|
|
225631
|
+
cleanText = cleanText.replace(/^```/, "").replace(/```$/, "").trim();
|
|
225632
|
+
}
|
|
225633
|
+
const parsedJson = JSON.parse(cleanText);
|
|
225634
|
+
const result = schema.safeParse(parsedJson);
|
|
225635
|
+
if (result.success) {
|
|
225636
|
+
return result.data;
|
|
225637
|
+
}
|
|
225638
|
+
const errorMsg = result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join("\n");
|
|
225639
|
+
if (process.env.DEBUG) {
|
|
225640
|
+
console.warn(`[Structured LLM] Validation failed (Attempt ${attempt}/${maxRetries}):
|
|
225641
|
+
${errorMsg}`);
|
|
225642
|
+
}
|
|
225643
|
+
if (attempt === maxRetries) {
|
|
225644
|
+
throw new Error(`Failed to generate valid structured output after ${maxRetries} attempts. Last error: ${errorMsg}`);
|
|
225645
|
+
}
|
|
225646
|
+
currentPrompt += `
|
|
225647
|
+
|
|
225648
|
+
Your previous JSON response was invalid. Please fix the following errors and try again:
|
|
225649
|
+
${errorMsg}
|
|
225650
|
+
Make sure to output ONLY valid JSON matching the exact schema requested.`;
|
|
225651
|
+
} catch (e) {
|
|
225652
|
+
if (process.env.DEBUG) {
|
|
225653
|
+
console.warn(`[Structured LLM] JSON Parsing failed (Attempt ${attempt}/${maxRetries}):
|
|
225654
|
+
${e.message}`);
|
|
225655
|
+
}
|
|
225656
|
+
if (attempt === maxRetries) {
|
|
225657
|
+
throw new Error(`Failed to parse JSON after ${maxRetries} attempts. Last response: ${responseText.slice(0, 200)}...`);
|
|
225658
|
+
}
|
|
225659
|
+
currentPrompt += `
|
|
225660
|
+
|
|
225661
|
+
Your previous response was not valid JSON. Error: ${e.message}
|
|
225662
|
+
Please output ONLY valid JSON.`;
|
|
225663
|
+
}
|
|
225664
|
+
}
|
|
225665
|
+
throw new Error("Unreachable");
|
|
225666
|
+
}
|
|
225667
|
+
var import_genai3 = __require("@google/genai");
|
|
225668
|
+
var import_shared3 = require_dist3();
|
|
225654
225669
|
var ReviewOrchestrator = class {
|
|
225655
|
-
securityAgent;
|
|
225656
|
-
architectureAgent;
|
|
225657
225670
|
synthesizerAgent;
|
|
225671
|
+
client;
|
|
225658
225672
|
constructor(apiKey) {
|
|
225659
|
-
|
|
225660
|
-
|
|
225673
|
+
const key = apiKey || process.env.GEMINI_API_KEY;
|
|
225674
|
+
if (!key) {
|
|
225675
|
+
throw new Error("GEMINI_API_KEY is not set.");
|
|
225676
|
+
}
|
|
225677
|
+
this.client = new import_genai3.GoogleGenAI({ apiKey: key });
|
|
225661
225678
|
this.synthesizerAgent = new SynthesizerAgent(apiKey);
|
|
225662
225679
|
}
|
|
225663
225680
|
/**
|
|
225664
225681
|
* Register tools across all agents that support self-verification.
|
|
225665
225682
|
*/
|
|
225666
225683
|
registerTools(tools) {
|
|
225667
|
-
this.
|
|
225668
|
-
this.architectureAgent.registerTools(tools);
|
|
225684
|
+
this.synthesizerAgent.registerTools(tools);
|
|
225669
225685
|
}
|
|
225670
225686
|
/**
|
|
225671
225687
|
* Runs the full multi-agent review pipeline.
|
|
225672
|
-
*
|
|
225673
|
-
* @param diff - The raw PR diff text
|
|
225674
|
-
* @param contextChunks - Relevant codebase chunks from hybrid retrieval
|
|
225675
|
-
* @param memories - Optional relevant memories from past reviews
|
|
225676
|
-
* @returns Comprehensive OrchestratedReview with all agent outputs
|
|
225677
225688
|
*/
|
|
225678
225689
|
async runReview(diff, contextChunks, memories) {
|
|
225679
225690
|
const startTime = Date.now();
|
|
225680
|
-
|
|
225681
|
-
|
|
225682
|
-
|
|
225683
|
-
|
|
225684
|
-
|
|
225685
|
-
|
|
225686
|
-
|
|
225687
|
-
|
|
225688
|
-
|
|
225689
|
-
|
|
225690
|
-
|
|
225691
|
-
|
|
225692
|
-
|
|
225693
|
-
|
|
225694
|
-
|
|
225695
|
-
|
|
225691
|
+
if (process.env.DEBUG) console.log("\nRunning Batched Security + Architecture Review...");
|
|
225692
|
+
let combinedPrompt = `## PR Diff to Review
|
|
225693
|
+
\`\`\`diff
|
|
225694
|
+
${diff}
|
|
225695
|
+
\`\`\`
|
|
225696
|
+
`;
|
|
225697
|
+
if (contextChunks.length > 0) {
|
|
225698
|
+
combinedPrompt += `
|
|
225699
|
+
## Existing Codebase Context
|
|
225700
|
+
Use this to understand what patterns the codebase already uses:
|
|
225701
|
+
`;
|
|
225702
|
+
contextChunks.forEach((chunk, i) => {
|
|
225703
|
+
combinedPrompt += `
|
|
225704
|
+
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath}
|
|
225705
|
+
\`\`\`${chunk.kind}
|
|
225706
|
+
${chunk.content}
|
|
225707
|
+
\`\`\`
|
|
225708
|
+
`;
|
|
225709
|
+
});
|
|
225710
|
+
}
|
|
225711
|
+
if (memories && memories.length > 0) {
|
|
225712
|
+
combinedPrompt += `
|
|
225713
|
+
## Historical Context
|
|
225714
|
+
These are relevant findings from past reviews:
|
|
225715
|
+
`;
|
|
225716
|
+
memories.forEach((mem, i) => {
|
|
225717
|
+
combinedPrompt += `- Memory ${i + 1}: ${mem}
|
|
225718
|
+
`;
|
|
225719
|
+
});
|
|
225720
|
+
}
|
|
225721
|
+
combinedPrompt = import_shared3.Prompts.combinedReviewSystemPrompt + "\n\n" + combinedPrompt;
|
|
225722
|
+
let combinedResult = null;
|
|
225723
|
+
try {
|
|
225724
|
+
combinedResult = await generateStructured(
|
|
225725
|
+
this.client,
|
|
225726
|
+
combinedPrompt,
|
|
225727
|
+
CombinedReviewOutputSchema,
|
|
225728
|
+
{ label: "ReviewOrchestrator (Batched)", maxValidationRetries: 3 }
|
|
225729
|
+
);
|
|
225730
|
+
} catch (err) {
|
|
225731
|
+
console.error("\nBatched Review failed:", err);
|
|
225732
|
+
}
|
|
225696
225733
|
const securityOutput = {
|
|
225697
|
-
findings:
|
|
225698
|
-
summary:
|
|
225699
|
-
riskLevel:
|
|
225734
|
+
findings: combinedResult?.securityFindings ?? [],
|
|
225735
|
+
summary: combinedResult?.securitySummary ?? "Security analysis encountered an error.",
|
|
225736
|
+
riskLevel: combinedResult?.securityRiskLevel ?? "low_risk"
|
|
225700
225737
|
};
|
|
225701
225738
|
const architectureOutput = {
|
|
225702
|
-
findings:
|
|
225703
|
-
summary:
|
|
225704
|
-
consistencyScore:
|
|
225739
|
+
findings: combinedResult?.architectureFindings ?? [],
|
|
225740
|
+
summary: combinedResult?.architectureSummary ?? "Architecture analysis encountered an error.",
|
|
225741
|
+
consistencyScore: combinedResult?.architectureConsistencyScore ?? "good"
|
|
225705
225742
|
};
|
|
225706
225743
|
if (process.env.DEBUG) {
|
|
225707
225744
|
console.log(` Security: ${securityOutput.riskLevel} (${securityOutput.findings.length} findings)`);
|
|
@@ -225765,7 +225802,7 @@ ${agentName} failed:`, err);
|
|
|
225765
225802
|
};
|
|
225766
225803
|
var import_child_process2 = __require("child_process");
|
|
225767
225804
|
var crypto22 = __toESM2(__require("crypto"));
|
|
225768
|
-
var
|
|
225805
|
+
var import_shared4 = require_dist3();
|
|
225769
225806
|
var IntelligenceAgent5 = class {
|
|
225770
225807
|
client;
|
|
225771
225808
|
embedder;
|
|
@@ -225776,7 +225813,7 @@ ${agentName} failed:`, err);
|
|
|
225776
225813
|
if (!key) {
|
|
225777
225814
|
throw new Error("GEMINI_API_KEY is not set.");
|
|
225778
225815
|
}
|
|
225779
|
-
this.client = new
|
|
225816
|
+
this.client = new import_genai4.GoogleGenAI({ apiKey: key });
|
|
225780
225817
|
this.embedder = new import_retrieval3.LocalEmbedder();
|
|
225781
225818
|
this.store = new import_retrieval3.VectorStore();
|
|
225782
225819
|
this.orchestrator = new ReviewOrchestrator(key);
|
|
@@ -225794,8 +225831,8 @@ ${agentName} failed:`, err);
|
|
|
225794
225831
|
}
|
|
225795
225832
|
getCurrentCommitHash() {
|
|
225796
225833
|
try {
|
|
225797
|
-
const hash = (0, import_child_process2.execSync)("git rev-parse HEAD").toString().trim();
|
|
225798
|
-
const isDirty = (0, import_child_process2.execSync)("git status --porcelain").toString().trim().length > 0;
|
|
225834
|
+
const hash = (0, import_child_process2.execSync)("git rev-parse HEAD", { stdio: ["pipe", "pipe", "ignore"] }).toString().trim();
|
|
225835
|
+
const isDirty = (0, import_child_process2.execSync)("git status --porcelain", { stdio: ["pipe", "pipe", "ignore"] }).toString().trim().length > 0;
|
|
225799
225836
|
return isDirty ? `${hash}-dirty` : hash;
|
|
225800
225837
|
} catch {
|
|
225801
225838
|
return "unknown";
|
|
@@ -225809,7 +225846,7 @@ ${agentName} failed:`, err);
|
|
|
225809
225846
|
* Extracts search queries (keywords, function names, classes) from a PR diff.
|
|
225810
225847
|
*/
|
|
225811
225848
|
async extractSearchQueriesFromDiff(diff) {
|
|
225812
|
-
const prompt =
|
|
225849
|
+
const prompt = import_shared4.Prompts.extractSearchQueries(diff);
|
|
225813
225850
|
try {
|
|
225814
225851
|
let result = await this.callLLM(prompt, { bypassCache: true });
|
|
225815
225852
|
if (result.startsWith("```")) {
|
|
@@ -225825,6 +225862,29 @@ ${agentName} failed:`, err);
|
|
|
225825
225862
|
return [];
|
|
225826
225863
|
}
|
|
225827
225864
|
}
|
|
225865
|
+
/**
|
|
225866
|
+
* Expands a single query into 3-5 variants for better retrieval recall.
|
|
225867
|
+
*/
|
|
225868
|
+
async expandQuery(query) {
|
|
225869
|
+
const prompt = `You are a search query expansion assistant.
|
|
225870
|
+
Given the user query, generate 3-5 distinct, highly relevant search queries that capture different keywords or ways to express the intent.
|
|
225871
|
+
Return ONLY a valid JSON array of strings.
|
|
225872
|
+
Query: "${query}"`;
|
|
225873
|
+
try {
|
|
225874
|
+
let result = await this.callLLM(prompt, { bypassCache: false });
|
|
225875
|
+
if (result.startsWith("```")) {
|
|
225876
|
+
result = result.replace(/^\`\`\`[a-z]*\n/, "").replace(/\n\`\`\`$/, "");
|
|
225877
|
+
}
|
|
225878
|
+
const queries = JSON.parse(result);
|
|
225879
|
+
if (Array.isArray(queries)) {
|
|
225880
|
+
return Array.from(/* @__PURE__ */ new Set([query, ...queries])).slice(0, 5);
|
|
225881
|
+
}
|
|
225882
|
+
return [query];
|
|
225883
|
+
} catch (err) {
|
|
225884
|
+
console.warn("Failed to expand query:", err);
|
|
225885
|
+
return [query];
|
|
225886
|
+
}
|
|
225887
|
+
}
|
|
225828
225888
|
/**
|
|
225829
225889
|
* Generates a context-aware RAG code review for a given PR diff.
|
|
225830
225890
|
*/
|
|
@@ -225834,7 +225894,7 @@ ${agentName} failed:`, err);
|
|
|
225834
225894
|
Code:
|
|
225835
225895
|
${c.content}`;
|
|
225836
225896
|
}).join("\n\n---\n\n");
|
|
225837
|
-
const prompt =
|
|
225897
|
+
const prompt = import_shared4.Prompts.ragReview(diff, contextStr);
|
|
225838
225898
|
const result = await this.callLLM(prompt, {
|
|
225839
225899
|
commitHash: this.getCurrentCommitHash(),
|
|
225840
225900
|
retrievalContextHash: this.computeChunksHash(chunks)
|
|
@@ -225845,7 +225905,7 @@ ${c.content}`;
|
|
|
225845
225905
|
const contextStr = relevantContext.map((c, i) => `--- Chunk ${i + 1} (${c.file} - ${c.symbolPath || "anonymous"}) ---
|
|
225846
225906
|
${c.content}`).join("\n\n");
|
|
225847
225907
|
const commentsStr = comments.map((c, i) => `Comment ${i + 1} (@${c.user?.login}): ${c.body}`).join("\n");
|
|
225848
|
-
const prompt =
|
|
225908
|
+
const prompt = import_shared4.Prompts.issueAnalysis(issueTitle, issueBody, commentsStr, contextStr);
|
|
225849
225909
|
return this.callLLM(prompt, {
|
|
225850
225910
|
commitHash: this.getCurrentCommitHash(),
|
|
225851
225911
|
retrievalContextHash: this.computeChunksHash(relevantContext)
|
|
@@ -225857,7 +225917,7 @@ ${c.content}`).join("\n\n");
|
|
|
225857
225917
|
Code:
|
|
225858
225918
|
${c.content}`;
|
|
225859
225919
|
}).join("\n\n---\n\n");
|
|
225860
|
-
const prompt =
|
|
225920
|
+
const prompt = import_shared4.Prompts.answerQuery(query, contextStr);
|
|
225861
225921
|
return await this.callLLM(prompt, {
|
|
225862
225922
|
commitHash: this.getCurrentCommitHash(),
|
|
225863
225923
|
retrievalContextHash: this.computeChunksHash(chunks)
|
|
@@ -225873,7 +225933,7 @@ ${c.content}`;
|
|
|
225873
225933
|
Code:
|
|
225874
225934
|
${c.content}`;
|
|
225875
225935
|
}).join("\n\n---\n\n");
|
|
225876
|
-
const prompt =
|
|
225936
|
+
const prompt = import_shared4.Prompts.executionPlan(task, contextStr);
|
|
225877
225937
|
let result = await this.callLLM(prompt, {
|
|
225878
225938
|
commitHash: this.getCurrentCommitHash(),
|
|
225879
225939
|
retrievalContextHash: this.computeChunksHash(contextChunks)
|
|
@@ -225906,12 +225966,131 @@ ${c.content}`;
|
|
|
225906
225966
|
return this.orchestrator.runReview(diff, contextChunks, memories);
|
|
225907
225967
|
}
|
|
225908
225968
|
};
|
|
225969
|
+
var import_shared5 = require_dist3();
|
|
225970
|
+
var SecurityAgent = class extends BaseAgent {
|
|
225971
|
+
name = "SecurityAgent";
|
|
225972
|
+
systemPrompt = import_shared5.Prompts.securitySystemPrompt;
|
|
225973
|
+
buildPrompt(input) {
|
|
225974
|
+
let prompt = `## PR Diff to Review
|
|
225975
|
+
\`\`\`diff
|
|
225976
|
+
${input.diff}
|
|
225977
|
+
\`\`\`
|
|
225978
|
+
`;
|
|
225979
|
+
if (input.contextChunks.length > 0) {
|
|
225980
|
+
prompt += `
|
|
225981
|
+
## Existing Codebase Context
|
|
225982
|
+
Use this to understand what security patterns the codebase already uses:
|
|
225983
|
+
`;
|
|
225984
|
+
input.contextChunks.forEach((chunk, i) => {
|
|
225985
|
+
prompt += `
|
|
225986
|
+
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath}
|
|
225987
|
+
\`\`\`${chunk.kind}
|
|
225988
|
+
${chunk.content}
|
|
225989
|
+
\`\`\`
|
|
225990
|
+
`;
|
|
225991
|
+
});
|
|
225992
|
+
}
|
|
225993
|
+
if (input.memories && input.memories.length > 0) {
|
|
225994
|
+
prompt += `
|
|
225995
|
+
## Historical Security Context
|
|
225996
|
+
These are relevant findings from past reviews:
|
|
225997
|
+
`;
|
|
225998
|
+
input.memories.forEach((mem, i) => {
|
|
225999
|
+
prompt += `- Memory ${i + 1}: ${mem}
|
|
226000
|
+
`;
|
|
226001
|
+
});
|
|
226002
|
+
}
|
|
226003
|
+
return prompt;
|
|
226004
|
+
}
|
|
226005
|
+
parseOutput(rawResponse) {
|
|
226006
|
+
const parsed = this.extractJSON(rawResponse);
|
|
226007
|
+
if (parsed) {
|
|
226008
|
+
const validated = SecurityOutputSchema.safeParse(parsed);
|
|
226009
|
+
if (validated.success) {
|
|
226010
|
+
return {
|
|
226011
|
+
agentName: this.name,
|
|
226012
|
+
findings: validated.data.findings,
|
|
226013
|
+
summary: validated.data.summary,
|
|
226014
|
+
riskLevel: validated.data.riskLevel
|
|
226015
|
+
};
|
|
226016
|
+
}
|
|
226017
|
+
}
|
|
226018
|
+
return {
|
|
226019
|
+
agentName: this.name,
|
|
226020
|
+
findings: [],
|
|
226021
|
+
summary: rawResponse.slice(0, 500),
|
|
226022
|
+
riskLevel: "low_risk"
|
|
226023
|
+
};
|
|
226024
|
+
}
|
|
226025
|
+
};
|
|
225909
226026
|
var import_shared6 = require_dist3();
|
|
226027
|
+
var ArchitectureAgent = class extends BaseAgent {
|
|
226028
|
+
name = "ArchitectureAgent";
|
|
226029
|
+
systemPrompt = import_shared6.Prompts.architectureSystemPrompt;
|
|
226030
|
+
buildPrompt(input) {
|
|
226031
|
+
let prompt = `## PR Diff to Review
|
|
226032
|
+
\`\`\`diff
|
|
226033
|
+
${input.diff}
|
|
226034
|
+
\`\`\`
|
|
226035
|
+
`;
|
|
226036
|
+
if (input.contextChunks.length > 0) {
|
|
226037
|
+
prompt += `
|
|
226038
|
+
## Existing Codebase Architecture (Retrieved Context)
|
|
226039
|
+
These are the most relevant code chunks from the existing codebase. Compare the PR diff against these patterns:
|
|
226040
|
+
`;
|
|
226041
|
+
input.contextChunks.forEach((chunk, i) => {
|
|
226042
|
+
prompt += `
|
|
226043
|
+
### Context ${i + 1}: ${chunk.file} \u2192 ${chunk.symbolPath} (${chunk.kind})
|
|
226044
|
+
\`\`\`
|
|
226045
|
+
${chunk.content}
|
|
226046
|
+
\`\`\`
|
|
226047
|
+
`;
|
|
226048
|
+
});
|
|
226049
|
+
} else {
|
|
226050
|
+
prompt += `
|
|
226051
|
+
## Note
|
|
226052
|
+
No existing codebase context was retrieved. Evaluate the PR diff on its own merits, focusing on internal consistency and general best practices.
|
|
226053
|
+
`;
|
|
226054
|
+
}
|
|
226055
|
+
if (input.memories && input.memories.length > 0) {
|
|
226056
|
+
prompt += `
|
|
226057
|
+
## Historical Architecture Context
|
|
226058
|
+
These are relevant findings from past reviews:
|
|
226059
|
+
`;
|
|
226060
|
+
input.memories.forEach((mem, i) => {
|
|
226061
|
+
prompt += `- Memory ${i + 1}: ${mem}
|
|
226062
|
+
`;
|
|
226063
|
+
});
|
|
226064
|
+
}
|
|
226065
|
+
return prompt;
|
|
226066
|
+
}
|
|
226067
|
+
parseOutput(rawResponse) {
|
|
226068
|
+
const parsed = this.extractJSON(rawResponse);
|
|
226069
|
+
if (parsed) {
|
|
226070
|
+
const validated = ArchitectureOutputSchema.safeParse(parsed);
|
|
226071
|
+
if (validated.success) {
|
|
226072
|
+
return {
|
|
226073
|
+
agentName: this.name,
|
|
226074
|
+
findings: validated.data.findings,
|
|
226075
|
+
summary: validated.data.summary,
|
|
226076
|
+
consistencyScore: validated.data.consistencyScore
|
|
226077
|
+
};
|
|
226078
|
+
}
|
|
226079
|
+
}
|
|
226080
|
+
return {
|
|
226081
|
+
agentName: this.name,
|
|
226082
|
+
findings: [],
|
|
226083
|
+
summary: rawResponse.slice(0, 500),
|
|
226084
|
+
consistencyScore: "good"
|
|
226085
|
+
};
|
|
226086
|
+
}
|
|
226087
|
+
};
|
|
226088
|
+
var import_shared7 = require_dist3();
|
|
225910
226089
|
var AutonomousAgent2 = class extends BaseAgent {
|
|
225911
226090
|
name = "Vortex";
|
|
225912
226091
|
maxToolIterations = 30;
|
|
225913
226092
|
// overridden by maxSteps if provided
|
|
225914
|
-
systemPrompt =
|
|
226093
|
+
systemPrompt = import_shared7.Prompts.autonomousSystemPrompt;
|
|
225915
226094
|
buildPrompt(input) {
|
|
225916
226095
|
const { diff, contextChunks } = input;
|
|
225917
226096
|
let prompt = `USER TASK:
|
|
@@ -225940,7 +226119,7 @@ ${chunk.content}
|
|
|
225940
226119
|
};
|
|
225941
226120
|
var import_db22 = require_dist2();
|
|
225942
226121
|
var import_retrieval22 = require_dist4();
|
|
225943
|
-
var
|
|
226122
|
+
var import_shared8 = require_dist3();
|
|
225944
226123
|
var MemoryService3 = class {
|
|
225945
226124
|
embedder;
|
|
225946
226125
|
constructor() {
|
|
@@ -225969,7 +226148,7 @@ ${chunk.content}
|
|
|
225969
226148
|
let embedding;
|
|
225970
226149
|
try {
|
|
225971
226150
|
const embeddings = await this.embedder.embedChunks([
|
|
225972
|
-
(0,
|
|
226151
|
+
(0, import_shared8.createQueryChunk)(memoryContent, "memory")
|
|
225973
226152
|
]);
|
|
225974
226153
|
if (embeddings[0]) {
|
|
225975
226154
|
embedding = JSON.stringify(embeddings[0]);
|
|
@@ -225994,7 +226173,7 @@ ${chunk.content}
|
|
|
225994
226173
|
let embedding;
|
|
225995
226174
|
try {
|
|
225996
226175
|
const embeddings = await this.embedder.embedChunks([
|
|
225997
|
-
(0,
|
|
226176
|
+
(0, import_shared8.createQueryChunk)(content, "memory")
|
|
225998
226177
|
]);
|
|
225999
226178
|
if (embeddings[0]) {
|
|
226000
226179
|
embedding = JSON.stringify(embeddings[0]);
|
|
@@ -226016,7 +226195,7 @@ ${chunk.content}
|
|
|
226016
226195
|
let queryEmbedding = null;
|
|
226017
226196
|
try {
|
|
226018
226197
|
const embeddings = await this.embedder.embedChunks([
|
|
226019
|
-
(0,
|
|
226198
|
+
(0, import_shared8.createQueryChunk)(query)
|
|
226020
226199
|
]);
|
|
226021
226200
|
queryEmbedding = embeddings[0] ?? null;
|
|
226022
226201
|
} catch {
|
|
@@ -226036,7 +226215,7 @@ ${chunk.content}
|
|
|
226036
226215
|
if (mem.embedding) {
|
|
226037
226216
|
try {
|
|
226038
226217
|
const memEmbedding = JSON.parse(mem.embedding);
|
|
226039
|
-
similarity = (0,
|
|
226218
|
+
similarity = (0, import_shared8.cosineSimilarity)(queryEmbedding, memEmbedding);
|
|
226040
226219
|
} catch {
|
|
226041
226220
|
}
|
|
226042
226221
|
}
|
|
@@ -226556,33 +226735,50 @@ URL: ${r.url}
|
|
|
226556
226735
|
* Builds both the vector store (for semantic search) and the BM25 index (for keyword search).
|
|
226557
226736
|
*/
|
|
226558
226737
|
async indexRepository(cwd) {
|
|
226559
|
-
|
|
226560
|
-
|
|
226738
|
+
let root = cwd;
|
|
226739
|
+
if ((0, import_git4.isGitRepo)(cwd)) {
|
|
226740
|
+
try {
|
|
226741
|
+
root = (0, import_git4.getGitRoot)(cwd);
|
|
226742
|
+
} catch {
|
|
226743
|
+
}
|
|
226561
226744
|
}
|
|
226562
|
-
const root = (0, import_git4.getGitRoot)(cwd);
|
|
226563
226745
|
await (0, import_db3.initDatabase)();
|
|
226564
|
-
|
|
226565
|
-
|
|
226566
|
-
|
|
226567
|
-
|
|
226568
|
-
|
|
226569
|
-
|
|
226570
|
-
|
|
226571
|
-
|
|
226572
|
-
|
|
226573
|
-
|
|
226574
|
-
|
|
226575
|
-
|
|
226576
|
-
|
|
226577
|
-
|
|
226578
|
-
|
|
226579
|
-
|
|
226580
|
-
|
|
226581
|
-
|
|
226582
|
-
|
|
226583
|
-
|
|
226584
|
-
|
|
226585
|
-
|
|
226746
|
+
let files = [];
|
|
226747
|
+
if ((0, import_git4.isGitRepo)(cwd)) {
|
|
226748
|
+
try {
|
|
226749
|
+
const tracked = (0, import_git4.listTrackedFiles)(root).filter((file) => {
|
|
226750
|
+
const ext = path42.extname(file);
|
|
226751
|
+
const supportedExts = [
|
|
226752
|
+
".ts",
|
|
226753
|
+
".tsx",
|
|
226754
|
+
".js",
|
|
226755
|
+
".jsx",
|
|
226756
|
+
".py",
|
|
226757
|
+
".go",
|
|
226758
|
+
".rs",
|
|
226759
|
+
".java",
|
|
226760
|
+
".cpp",
|
|
226761
|
+
".hpp",
|
|
226762
|
+
".c",
|
|
226763
|
+
".h",
|
|
226764
|
+
".rb",
|
|
226765
|
+
".php",
|
|
226766
|
+
".html",
|
|
226767
|
+
".css"
|
|
226768
|
+
];
|
|
226769
|
+
return supportedExts.includes(ext) && !file.includes("node_modules");
|
|
226770
|
+
});
|
|
226771
|
+
if (tracked.length > 0) {
|
|
226772
|
+
files = tracked;
|
|
226773
|
+
}
|
|
226774
|
+
} catch (e) {
|
|
226775
|
+
}
|
|
226776
|
+
}
|
|
226777
|
+
if (files.length === 0) {
|
|
226778
|
+
for await (const file of (0, import_retrieval5.scanFiles)(root)) {
|
|
226779
|
+
files.push(file);
|
|
226780
|
+
}
|
|
226781
|
+
}
|
|
226586
226782
|
let totalChunks = 0;
|
|
226587
226783
|
for (const file of files) {
|
|
226588
226784
|
try {
|
|
@@ -226618,7 +226814,7 @@ URL: ${r.url}
|
|
|
226618
226814
|
console.log(`Generating embedding for query: "${query}"...`);
|
|
226619
226815
|
await (0, import_db3.initDatabase)();
|
|
226620
226816
|
const queryEmbedding = await this.embedder.embedChunks([
|
|
226621
|
-
(0,
|
|
226817
|
+
(0, import_shared9.createQueryChunk)(query)
|
|
226622
226818
|
]);
|
|
226623
226819
|
if (queryEmbedding.length === 0) {
|
|
226624
226820
|
return [];
|
|
@@ -226901,7 +227097,7 @@ var require_package = __commonJS({
|
|
|
226901
227097
|
"package.json"(exports, module) {
|
|
226902
227098
|
module.exports = {
|
|
226903
227099
|
name: "@vortex-ai/cli",
|
|
226904
|
-
version: "0.1.
|
|
227100
|
+
version: "0.1.50",
|
|
226905
227101
|
description: "Vortex CLI - The main entry point",
|
|
226906
227102
|
main: "./dist/index.js",
|
|
226907
227103
|
bin: {
|
|
@@ -227018,17 +227214,25 @@ async function searchCommand(options) {
|
|
|
227018
227214
|
const spinner = ora2(`Searching codebase for: "${options.query}"...`).start();
|
|
227019
227215
|
const indexer = new import_engine2.Indexer();
|
|
227020
227216
|
try {
|
|
227021
|
-
spinner.text = "Running hybrid search (vector + BM25 + cross-encoder)...";
|
|
227022
|
-
|
|
227023
|
-
|
|
227217
|
+
spinner.text = options.expandQuery ? "Expanding query and running parallel hybrid search..." : "Running hybrid search (vector + BM25 + cross-encoder)...";
|
|
227218
|
+
let queriesToSearch = [options.query];
|
|
227219
|
+
const agent = new import_engine2.IntelligenceAgent();
|
|
227220
|
+
if (options.expandQuery) {
|
|
227221
|
+
queriesToSearch = await agent.expandQuery(options.query);
|
|
227222
|
+
}
|
|
227223
|
+
const allResults = await Promise.all(
|
|
227224
|
+
queriesToSearch.map((q) => indexer.hybridSearch(q, parseInt(options.limit, 10)))
|
|
227225
|
+
);
|
|
227226
|
+
const flatResults = allResults.flat();
|
|
227227
|
+
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));
|
|
227228
|
+
if (uniqueResults.length === 0) {
|
|
227024
227229
|
spinner.fail("No relevant code found.");
|
|
227025
227230
|
return;
|
|
227026
227231
|
}
|
|
227027
|
-
spinner.text = `Found ${
|
|
227232
|
+
spinner.text = `Found ${uniqueResults.length} relevant code chunks. Analyzing with AI engine...`;
|
|
227028
227233
|
const memoryService = new import_engine2.MemoryService();
|
|
227029
227234
|
const memories = await memoryService.recallRelevantMemories(options.query, 3);
|
|
227030
|
-
const
|
|
227031
|
-
const answer = await agent.answerQueryWithContext(options.query, results);
|
|
227235
|
+
const answer = await agent.answerQueryWithContext(options.query, uniqueResults);
|
|
227032
227236
|
spinner.succeed("Analysis complete!\n");
|
|
227033
227237
|
const parsedAnswer = await marked.parse(answer);
|
|
227034
227238
|
const formatted = boxen(parsedAnswer.trim(), {
|
|
@@ -227041,7 +227245,7 @@ async function searchCommand(options) {
|
|
|
227041
227245
|
});
|
|
227042
227246
|
console.log(formatted);
|
|
227043
227247
|
console.log(chalk2.cyan.dim(" Reference Material (Hybrid Retrieval)"));
|
|
227044
|
-
|
|
227248
|
+
uniqueResults.forEach((res, i) => {
|
|
227045
227249
|
const sources = res.sources ? res.sources.join("+") : "vector";
|
|
227046
227250
|
const scoreStr = res.score ? (res.score * 100).toFixed(1) + "%" : "N/A";
|
|
227047
227251
|
console.log(chalk2.gray(` \u2502 [${i + 1}] ${res.file.replace(process.cwd(), "")} \u2794 ${res.symbolPath || "(anonymous)"} (${scoreStr}) [${sources}]`));
|
|
@@ -227120,11 +227324,11 @@ async function reviewCommand(options) {
|
|
|
227120
227324
|
const queries = await agent.extractSearchQueriesFromDiff(diff);
|
|
227121
227325
|
const allChunks = [];
|
|
227122
227326
|
if (queries.length > 0) {
|
|
227123
|
-
spinner.text = `Hybrid searching for context...`;
|
|
227124
|
-
|
|
227125
|
-
|
|
227126
|
-
|
|
227127
|
-
|
|
227327
|
+
spinner.text = `Hybrid searching for context (parallel)...`;
|
|
227328
|
+
const allResults = await Promise.all(
|
|
227329
|
+
queries.map((query) => indexer.hybridSearch(query, 3))
|
|
227330
|
+
);
|
|
227331
|
+
allChunks.push(...allResults.flat());
|
|
227128
227332
|
}
|
|
227129
227333
|
const uniqueChunks = Array.from(
|
|
227130
227334
|
new Map(allChunks.map((c) => [c.id, c])).values()
|
|
@@ -227377,7 +227581,7 @@ Created new project folder: ${projectPath}`));
|
|
|
227377
227581
|
if (!options.contextChunks || options.contextChunks.length === 0) {
|
|
227378
227582
|
try {
|
|
227379
227583
|
const indexer = new import_engine5.Indexer();
|
|
227380
|
-
const relevantContext = await indexer.hybridSearch(prompt,
|
|
227584
|
+
const relevantContext = await indexer.hybridSearch(prompt, 15);
|
|
227381
227585
|
options.contextChunks = relevantContext.map((c) => ({
|
|
227382
227586
|
file: c.file,
|
|
227383
227587
|
symbolPath: c.symbolPath || "anonymous",
|
|
@@ -227400,7 +227604,11 @@ Created new project folder: ${projectPath}`));
|
|
|
227400
227604
|
const parsedPlan = JSON.parse(executionPlanStr);
|
|
227401
227605
|
planSummary = parsedPlan.summary || planSummary;
|
|
227402
227606
|
stepCount = parsedPlan.steps ? parsedPlan.steps.length : 0;
|
|
227403
|
-
executionPlan = parsedPlan.steps ? parsedPlan.steps.map((s, i) =>
|
|
227607
|
+
executionPlan = parsedPlan.steps ? parsedPlan.steps.map((s, i) => {
|
|
227608
|
+
if (typeof s === "string") return `${i + 1}. ${s}`;
|
|
227609
|
+
return `${i + 1}. [${(s.action || "MODIFY").toUpperCase()}] ${s.file || "General"}
|
|
227610
|
+
${s.description}`;
|
|
227611
|
+
}).join("\n\n") : executionPlanStr;
|
|
227404
227612
|
filesToRead = parsedPlan.filesToRead || [];
|
|
227405
227613
|
} catch {
|
|
227406
227614
|
executionPlan = executionPlanStr;
|
|
@@ -227497,6 +227705,7 @@ Allow? (y/N) `;
|
|
|
227497
227705
|
},
|
|
227498
227706
|
{
|
|
227499
227707
|
initialState,
|
|
227708
|
+
verifyCommand: options.verify,
|
|
227500
227709
|
onToolCall: (toolName, args) => {
|
|
227501
227710
|
if (toolName === "write_file") {
|
|
227502
227711
|
spinner.text = `Writing ${args.path}...`;
|
|
@@ -227632,7 +227841,8 @@ Please fix this issue in the codebase.`;
|
|
|
227632
227841
|
await solveCommand(prompt, {
|
|
227633
227842
|
autoApprove: options.autoApprove,
|
|
227634
227843
|
maxSteps: options.maxSteps,
|
|
227635
|
-
contextChunks
|
|
227844
|
+
contextChunks,
|
|
227845
|
+
verify: options.verify
|
|
227636
227846
|
});
|
|
227637
227847
|
} catch (err) {
|
|
227638
227848
|
spinner.fail("Failed to setup solve-issue");
|
|
@@ -227649,9 +227859,9 @@ cacheCommand.command("stats").description("View LLM cache statistics").action(as
|
|
|
227649
227859
|
const stats = await import_engine7.LLMCacheManager.getStats();
|
|
227650
227860
|
console.log("\nLLM Cache Statistics\n");
|
|
227651
227861
|
console.log(`Entries: ${stats.entries.toLocaleString()}`);
|
|
227652
|
-
console.log(`
|
|
227862
|
+
console.log(`Saved API Calls: ${stats.hits.toLocaleString()}`);
|
|
227653
227863
|
const storageMB = (stats.storage / 1024 / 1024).toFixed(2);
|
|
227654
|
-
console.log(`Storage: ${storageMB} MB
|
|
227864
|
+
console.log(`Storage Used: ${storageMB} MB
|
|
227655
227865
|
`);
|
|
227656
227866
|
} catch (err) {
|
|
227657
227867
|
console.error("Failed to retrieve cache stats:", err);
|
|
@@ -227716,12 +227926,12 @@ program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
|
227716
227926
|
}
|
|
227717
227927
|
});
|
|
227718
227928
|
program.command("init").description("Initialize repository intelligence, embeddings, and PR history").option("--reindex", "Rebuild repository embeddings while preserving historical PR intelligence").action(initCommand);
|
|
227719
|
-
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);
|
|
227929
|
+
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);
|
|
227720
227930
|
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);
|
|
227721
227931
|
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);
|
|
227722
227932
|
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);
|
|
227723
|
-
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));
|
|
227724
|
-
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);
|
|
227933
|
+
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));
|
|
227934
|
+
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);
|
|
227725
227935
|
program.addCommand(cacheCommand);
|
|
227726
227936
|
program.parse();
|
|
227727
227937
|
/*! Bundled license information:
|