@probelabs/visor 0.1.93 → 0.1.95
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/README.md +4 -4
- package/defaults/.visor.yaml +86 -6
- package/dist/ai-review-service.d.ts +1 -1
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/check-execution-engine.d.ts +5 -0
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/config.d.ts +9 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/defaults/.visor.yaml +86 -6
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/footer.d.ts +25 -0
- package/dist/footer.d.ts.map +1 -0
- package/dist/github-check-service.d.ts.map +1 -1
- package/dist/github-comments.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1074 -472
- package/dist/output/code-review/schema.json +0 -23
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/providers/log-check-provider.d.ts.map +1 -1
- package/dist/providers/memory-check-provider.d.ts.map +1 -1
- package/dist/reviewer.d.ts +11 -0
- package/dist/reviewer.d.ts.map +1 -1
- package/dist/sdk/{check-execution-engine-RORGGGGP.mjs → check-execution-engine-NMPXJ7FQ.mjs} +2 -2
- package/dist/sdk/{chunk-Z47UECAT.mjs → chunk-Q4S5A5TO.mjs} +314 -111
- package/dist/sdk/chunk-Q4S5A5TO.mjs.map +1 -0
- package/dist/sdk/sdk.d.mts +11 -2
- package/dist/sdk/sdk.d.ts +11 -2
- package/dist/sdk/sdk.js +398 -152
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +57 -24
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/sdk.d.ts +11 -2
- package/dist/sdk.d.ts.map +1 -1
- package/dist/traces/{run-2025-10-15T11-54-04-087Z.ndjson → run-2025-10-18T18-27-25-085Z.ndjson} +8 -1
- package/dist/traces/{run-2025-10-15T11-54-14-046Z.ndjson → run-2025-10-18T18-27-35-400Z.ndjson} +8 -1
- package/dist/traces/{run-2025-10-15T11-54-14-575Z.ndjson → run-2025-10-18T18-27-35-937Z.ndjson} +8 -1
- package/dist/traces/{run-2025-10-15T11-54-15-082Z.ndjson → run-2025-10-18T18-27-36-428Z.ndjson} +8 -1
- package/dist/types/cli.d.ts +3 -2
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts +0 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/diff-processor.d.ts +6 -0
- package/dist/utils/diff-processor.d.ts.map +1 -0
- package/package.json +2 -2
- package/dist/sdk/chunk-Z47UECAT.mjs.map +0 -1
- /package/dist/sdk/{check-execution-engine-RORGGGGP.mjs.map → check-execution-engine-NMPXJ7FQ.mjs.map} +0 -0
- /package/dist/traces/{run-2025-10-15T11-54-15-561Z.ndjson → run-2025-10-18T18-27-36-917Z.ndjson} +0 -0
|
@@ -217,6 +217,30 @@ var init_session_registry = __esm({
|
|
|
217
217
|
// src/github-comments.ts
|
|
218
218
|
init_logger();
|
|
219
219
|
import { v4 as uuidv4 } from "uuid";
|
|
220
|
+
|
|
221
|
+
// src/footer.ts
|
|
222
|
+
function generateFooter(options = {}) {
|
|
223
|
+
const { includeMetadata, includeSeparator = true } = options;
|
|
224
|
+
const parts = [];
|
|
225
|
+
if (includeSeparator) {
|
|
226
|
+
parts.push("---");
|
|
227
|
+
parts.push("");
|
|
228
|
+
}
|
|
229
|
+
parts.push(
|
|
230
|
+
"*Powered by [Visor](https://probelabs.com/visor) from [Probelabs](https://probelabs.com)*"
|
|
231
|
+
);
|
|
232
|
+
if (includeMetadata) {
|
|
233
|
+
const { lastUpdated, triggeredBy, commitSha } = includeMetadata;
|
|
234
|
+
const commitInfo = commitSha ? ` | Commit: ${commitSha.substring(0, 7)}` : "";
|
|
235
|
+
parts.push("");
|
|
236
|
+
parts.push(`*Last updated: ${lastUpdated} | Triggered by: ${triggeredBy}${commitInfo}*`);
|
|
237
|
+
}
|
|
238
|
+
parts.push("");
|
|
239
|
+
parts.push("\u{1F4A1} **TIP:** You can chat with Visor using `/visor ask <your question>`");
|
|
240
|
+
return parts.join("\n");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/github-comments.ts
|
|
220
244
|
var CommentManager = class {
|
|
221
245
|
octokit;
|
|
222
246
|
retryConfig;
|
|
@@ -318,15 +342,17 @@ var CommentManager = class {
|
|
|
318
342
|
*/
|
|
319
343
|
formatCommentWithMetadata(content, metadata) {
|
|
320
344
|
const { commentId, lastUpdated, triggeredBy, commitSha } = metadata;
|
|
321
|
-
const
|
|
345
|
+
const footer = generateFooter({
|
|
346
|
+
includeMetadata: {
|
|
347
|
+
lastUpdated,
|
|
348
|
+
triggeredBy,
|
|
349
|
+
commitSha
|
|
350
|
+
}
|
|
351
|
+
});
|
|
322
352
|
return `<!-- visor-comment-id:${commentId} -->
|
|
323
353
|
${content}
|
|
324
354
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
*Powered by [Visor](https://probelabs.com/visor) from [Probelabs](https://probelabs.com)*
|
|
328
|
-
|
|
329
|
-
*Last updated: ${lastUpdated} | Triggered by: ${triggeredBy}${commitInfo}*
|
|
355
|
+
${footer}
|
|
330
356
|
<!-- /visor-comment-id:${commentId} -->`;
|
|
331
357
|
}
|
|
332
358
|
/**
|
|
@@ -508,6 +534,64 @@ init_session_registry();
|
|
|
508
534
|
init_logger();
|
|
509
535
|
init_tracer_init();
|
|
510
536
|
import { ProbeAgent } from "@probelabs/probe";
|
|
537
|
+
|
|
538
|
+
// src/utils/diff-processor.ts
|
|
539
|
+
import { extract } from "@probelabs/probe";
|
|
540
|
+
import * as path from "path";
|
|
541
|
+
async function processDiffWithOutline(diffContent) {
|
|
542
|
+
if (!diffContent || diffContent.trim().length === 0) {
|
|
543
|
+
return diffContent;
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
const originalProbePath = process.env.PROBE_PATH;
|
|
547
|
+
const fs5 = __require("fs");
|
|
548
|
+
const possiblePaths = [
|
|
549
|
+
// Relative to current working directory (most common in production)
|
|
550
|
+
path.join(process.cwd(), "node_modules/@probelabs/probe/bin/probe-binary"),
|
|
551
|
+
// Relative to __dirname (for unbundled development)
|
|
552
|
+
path.join(__dirname, "../..", "node_modules/@probelabs/probe/bin/probe-binary"),
|
|
553
|
+
// Relative to dist directory (for bundled CLI)
|
|
554
|
+
path.join(__dirname, "node_modules/@probelabs/probe/bin/probe-binary")
|
|
555
|
+
];
|
|
556
|
+
let probeBinaryPath;
|
|
557
|
+
for (const candidatePath of possiblePaths) {
|
|
558
|
+
if (fs5.existsSync(candidatePath)) {
|
|
559
|
+
probeBinaryPath = candidatePath;
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (!probeBinaryPath) {
|
|
564
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
565
|
+
console.error("Probe binary not found. Tried:", possiblePaths);
|
|
566
|
+
}
|
|
567
|
+
return diffContent;
|
|
568
|
+
}
|
|
569
|
+
process.env.PROBE_PATH = probeBinaryPath;
|
|
570
|
+
const extractPromise = extract({
|
|
571
|
+
content: diffContent,
|
|
572
|
+
format: "outline-diff",
|
|
573
|
+
allowTests: true
|
|
574
|
+
// Allow test files and test code blocks in extraction results
|
|
575
|
+
});
|
|
576
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
577
|
+
setTimeout(() => reject(new Error("Extract timeout after 30s")), 3e4);
|
|
578
|
+
});
|
|
579
|
+
const result = await Promise.race([extractPromise, timeoutPromise]);
|
|
580
|
+
if (originalProbePath !== void 0) {
|
|
581
|
+
process.env.PROBE_PATH = originalProbePath;
|
|
582
|
+
} else {
|
|
583
|
+
delete process.env.PROBE_PATH;
|
|
584
|
+
}
|
|
585
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
|
|
588
|
+
console.error("Failed to process diff with outline-diff format:", error);
|
|
589
|
+
}
|
|
590
|
+
return diffContent;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// src/ai-review-service.ts
|
|
511
595
|
function log(...args) {
|
|
512
596
|
logger.debug(args.join(" "));
|
|
513
597
|
}
|
|
@@ -549,7 +633,7 @@ var AIReviewService = class {
|
|
|
549
633
|
/**
|
|
550
634
|
* Execute AI review using probe agent
|
|
551
635
|
*/
|
|
552
|
-
async executeReview(prInfo, customPrompt, schema,
|
|
636
|
+
async executeReview(prInfo, customPrompt, schema, checkName, sessionId) {
|
|
553
637
|
const startTime = Date.now();
|
|
554
638
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
555
639
|
const prompt = await this.buildCustomPrompt(prInfo, customPrompt, schema);
|
|
@@ -606,7 +690,7 @@ var AIReviewService = class {
|
|
|
606
690
|
prompt,
|
|
607
691
|
schema,
|
|
608
692
|
debugInfo,
|
|
609
|
-
|
|
693
|
+
checkName,
|
|
610
694
|
sessionId
|
|
611
695
|
);
|
|
612
696
|
const processingTime = Date.now() - startTime;
|
|
@@ -766,9 +850,9 @@ var AIReviewService = class {
|
|
|
766
850
|
*/
|
|
767
851
|
async buildCustomPrompt(prInfo, customInstructions, schema, options) {
|
|
768
852
|
const skipPRContext = options?.skipPRContext === true;
|
|
769
|
-
const prContext = skipPRContext ? "" : this.formatPRContext(prInfo);
|
|
770
|
-
const isIssue = prInfo.isIssue === true;
|
|
771
853
|
const isCodeReviewSchema = schema === "code-review";
|
|
854
|
+
const prContext = skipPRContext ? "" : await this.formatPRContext(prInfo, isCodeReviewSchema);
|
|
855
|
+
const isIssue = prInfo.isIssue === true;
|
|
772
856
|
if (isIssue) {
|
|
773
857
|
if (skipPRContext) {
|
|
774
858
|
return `<instructions>
|
|
@@ -857,7 +941,7 @@ ${prContext}
|
|
|
857
941
|
/**
|
|
858
942
|
* Format PR or Issue context for the AI using XML structure
|
|
859
943
|
*/
|
|
860
|
-
formatPRContext(prInfo) {
|
|
944
|
+
async formatPRContext(prInfo, isCodeReviewSchema) {
|
|
861
945
|
const prContextInfo = prInfo;
|
|
862
946
|
const isIssue = prContextInfo.isIssue === true;
|
|
863
947
|
const isPRContext = prContextInfo.isPRContext === true;
|
|
@@ -939,7 +1023,12 @@ ${this.escapeXml(prInfo.body)}
|
|
|
939
1023
|
}
|
|
940
1024
|
const issueComments = prInfo.comments;
|
|
941
1025
|
if (issueComments && issueComments.length > 0) {
|
|
942
|
-
|
|
1026
|
+
let historicalComments = triggeringComment2 ? issueComments.filter((c) => c.id !== triggeringComment2.id) : issueComments;
|
|
1027
|
+
if (isCodeReviewSchema) {
|
|
1028
|
+
historicalComments = historicalComments.filter(
|
|
1029
|
+
(c) => !c.body || !c.body.includes("visor-comment-id:pr-review-")
|
|
1030
|
+
);
|
|
1031
|
+
}
|
|
943
1032
|
if (historicalComments.length > 0) {
|
|
944
1033
|
context2 += `
|
|
945
1034
|
<!-- Previous comments in chronological order (excluding triggering comment) -->
|
|
@@ -981,24 +1070,27 @@ ${this.escapeXml(prInfo.body)}
|
|
|
981
1070
|
}
|
|
982
1071
|
if (includeCodeContext) {
|
|
983
1072
|
if (prInfo.fullDiff) {
|
|
1073
|
+
const processedFullDiff = await processDiffWithOutline(prInfo.fullDiff);
|
|
984
1074
|
context += `
|
|
985
|
-
<!-- Complete unified diff showing all changes in the pull request -->
|
|
1075
|
+
<!-- Complete unified diff showing all changes in the pull request (processed with outline-diff) -->
|
|
986
1076
|
<full_diff>
|
|
987
|
-
${this.escapeXml(
|
|
1077
|
+
${this.escapeXml(processedFullDiff)}
|
|
988
1078
|
</full_diff>`;
|
|
989
1079
|
}
|
|
990
1080
|
if (prInfo.isIncremental) {
|
|
991
1081
|
if (prInfo.commitDiff && prInfo.commitDiff.length > 0) {
|
|
1082
|
+
const processedCommitDiff = await processDiffWithOutline(prInfo.commitDiff);
|
|
992
1083
|
context += `
|
|
993
|
-
<!-- Diff of only the latest commit for incremental analysis -->
|
|
1084
|
+
<!-- Diff of only the latest commit for incremental analysis (processed with outline-diff) -->
|
|
994
1085
|
<commit_diff>
|
|
995
|
-
${this.escapeXml(
|
|
1086
|
+
${this.escapeXml(processedCommitDiff)}
|
|
996
1087
|
</commit_diff>`;
|
|
997
1088
|
} else {
|
|
1089
|
+
const processedFallbackDiff = prInfo.fullDiff ? await processDiffWithOutline(prInfo.fullDiff) : "";
|
|
998
1090
|
context += `
|
|
999
|
-
<!-- Commit diff could not be retrieved - falling back to full diff analysis -->
|
|
1091
|
+
<!-- Commit diff could not be retrieved - falling back to full diff analysis (processed with outline-diff) -->
|
|
1000
1092
|
<commit_diff>
|
|
1001
|
-
${
|
|
1093
|
+
${this.escapeXml(processedFallbackDiff)}
|
|
1002
1094
|
</commit_diff>`;
|
|
1003
1095
|
}
|
|
1004
1096
|
}
|
|
@@ -1034,7 +1126,12 @@ ${prInfo.fullDiff ? this.escapeXml(prInfo.fullDiff) : ""}
|
|
|
1034
1126
|
}
|
|
1035
1127
|
const prComments = prInfo.comments;
|
|
1036
1128
|
if (prComments && prComments.length > 0) {
|
|
1037
|
-
|
|
1129
|
+
let historicalComments = triggeringComment ? prComments.filter((c) => c.id !== triggeringComment.id) : prComments;
|
|
1130
|
+
if (isCodeReviewSchema) {
|
|
1131
|
+
historicalComments = historicalComments.filter(
|
|
1132
|
+
(c) => !c.body || !c.body.includes("visor-comment-id:pr-review-")
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1038
1135
|
if (historicalComments.length > 0) {
|
|
1039
1136
|
context += `
|
|
1040
1137
|
<!-- Previous PR comments in chronological order (excluding triggering comment) -->
|
|
@@ -1105,7 +1202,7 @@ ${schemaString}`);
|
|
|
1105
1202
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1106
1203
|
try {
|
|
1107
1204
|
const fs5 = __require("fs");
|
|
1108
|
-
const
|
|
1205
|
+
const path6 = __require("path");
|
|
1109
1206
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1110
1207
|
const provider = this.config.provider || "auto";
|
|
1111
1208
|
const model = this.config.model || "default";
|
|
@@ -1219,16 +1316,16 @@ ${"=".repeat(60)}
|
|
|
1219
1316
|
`;
|
|
1220
1317
|
readableVersion += `${"=".repeat(60)}
|
|
1221
1318
|
`;
|
|
1222
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1319
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path6.join(process.cwd(), "debug-artifacts");
|
|
1223
1320
|
if (!fs5.existsSync(debugArtifactsDir)) {
|
|
1224
1321
|
fs5.mkdirSync(debugArtifactsDir, { recursive: true });
|
|
1225
1322
|
}
|
|
1226
|
-
const debugFile =
|
|
1323
|
+
const debugFile = path6.join(
|
|
1227
1324
|
debugArtifactsDir,
|
|
1228
1325
|
`prompt-${_checkName || "unknown"}-${timestamp}.json`
|
|
1229
1326
|
);
|
|
1230
1327
|
fs5.writeFileSync(debugFile, debugJson, "utf-8");
|
|
1231
|
-
const readableFile =
|
|
1328
|
+
const readableFile = path6.join(
|
|
1232
1329
|
debugArtifactsDir,
|
|
1233
1330
|
`prompt-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1234
1331
|
);
|
|
@@ -1265,7 +1362,7 @@ ${"=".repeat(60)}
|
|
|
1265
1362
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1266
1363
|
try {
|
|
1267
1364
|
const fs5 = __require("fs");
|
|
1268
|
-
const
|
|
1365
|
+
const path6 = __require("path");
|
|
1269
1366
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1270
1367
|
const agentAny2 = agent;
|
|
1271
1368
|
let fullHistory = [];
|
|
@@ -1276,8 +1373,8 @@ ${"=".repeat(60)}
|
|
|
1276
1373
|
} else if (agentAny2._messages) {
|
|
1277
1374
|
fullHistory = agentAny2._messages;
|
|
1278
1375
|
}
|
|
1279
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1280
|
-
const sessionFile =
|
|
1376
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path6.join(process.cwd(), "debug-artifacts");
|
|
1377
|
+
const sessionFile = path6.join(
|
|
1281
1378
|
debugArtifactsDir,
|
|
1282
1379
|
`session-${_checkName || "unknown"}-${timestamp}.json`
|
|
1283
1380
|
);
|
|
@@ -1292,7 +1389,7 @@ ${"=".repeat(60)}
|
|
|
1292
1389
|
latestResponse: response
|
|
1293
1390
|
};
|
|
1294
1391
|
fs5.writeFileSync(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
1295
|
-
const sessionTxtFile =
|
|
1392
|
+
const sessionTxtFile = path6.join(
|
|
1296
1393
|
debugArtifactsDir,
|
|
1297
1394
|
`session-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1298
1395
|
);
|
|
@@ -1336,10 +1433,10 @@ ${"=".repeat(60)}
|
|
|
1336
1433
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1337
1434
|
try {
|
|
1338
1435
|
const fs5 = __require("fs");
|
|
1339
|
-
const
|
|
1436
|
+
const path6 = __require("path");
|
|
1340
1437
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1341
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1342
|
-
const responseFile =
|
|
1438
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path6.join(process.cwd(), "debug-artifacts");
|
|
1439
|
+
const responseFile = path6.join(
|
|
1343
1440
|
debugArtifactsDir,
|
|
1344
1441
|
`response-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1345
1442
|
);
|
|
@@ -1511,7 +1608,7 @@ ${schemaString}`);
|
|
|
1511
1608
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1512
1609
|
try {
|
|
1513
1610
|
const fs5 = __require("fs");
|
|
1514
|
-
const
|
|
1611
|
+
const path6 = __require("path");
|
|
1515
1612
|
const os = __require("os");
|
|
1516
1613
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1517
1614
|
const debugData = {
|
|
@@ -1585,21 +1682,21 @@ ${"=".repeat(60)}
|
|
|
1585
1682
|
readableVersion += `${"=".repeat(60)}
|
|
1586
1683
|
`;
|
|
1587
1684
|
const tempDir = os.tmpdir();
|
|
1588
|
-
const promptFile =
|
|
1685
|
+
const promptFile = path6.join(tempDir, `visor-prompt-${timestamp}.txt`);
|
|
1589
1686
|
fs5.writeFileSync(promptFile, prompt, "utf-8");
|
|
1590
1687
|
log(`
|
|
1591
1688
|
\u{1F4BE} Prompt saved to: ${promptFile}`);
|
|
1592
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1689
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path6.join(process.cwd(), "debug-artifacts");
|
|
1593
1690
|
try {
|
|
1594
1691
|
if (!fs5.existsSync(debugArtifactsDir)) {
|
|
1595
1692
|
fs5.mkdirSync(debugArtifactsDir, { recursive: true });
|
|
1596
1693
|
}
|
|
1597
|
-
const debugFile =
|
|
1694
|
+
const debugFile = path6.join(
|
|
1598
1695
|
debugArtifactsDir,
|
|
1599
1696
|
`prompt-${_checkName || "unknown"}-${timestamp}.json`
|
|
1600
1697
|
);
|
|
1601
1698
|
fs5.writeFileSync(debugFile, debugJson, "utf-8");
|
|
1602
|
-
const readableFile =
|
|
1699
|
+
const readableFile = path6.join(
|
|
1603
1700
|
debugArtifactsDir,
|
|
1604
1701
|
`prompt-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1605
1702
|
);
|
|
@@ -1652,7 +1749,7 @@ $ ${cliCommand}
|
|
|
1652
1749
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1653
1750
|
try {
|
|
1654
1751
|
const fs5 = __require("fs");
|
|
1655
|
-
const
|
|
1752
|
+
const path6 = __require("path");
|
|
1656
1753
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1657
1754
|
const agentAny = agent;
|
|
1658
1755
|
let fullHistory = [];
|
|
@@ -1663,8 +1760,8 @@ $ ${cliCommand}
|
|
|
1663
1760
|
} else if (agentAny._messages) {
|
|
1664
1761
|
fullHistory = agentAny._messages;
|
|
1665
1762
|
}
|
|
1666
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1667
|
-
const sessionFile =
|
|
1763
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path6.join(process.cwd(), "debug-artifacts");
|
|
1764
|
+
const sessionFile = path6.join(
|
|
1668
1765
|
debugArtifactsDir,
|
|
1669
1766
|
`session-${_checkName || "unknown"}-${timestamp}.json`
|
|
1670
1767
|
);
|
|
@@ -1679,7 +1776,7 @@ $ ${cliCommand}
|
|
|
1679
1776
|
latestResponse: response
|
|
1680
1777
|
};
|
|
1681
1778
|
fs5.writeFileSync(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
1682
|
-
const sessionTxtFile =
|
|
1779
|
+
const sessionTxtFile = path6.join(
|
|
1683
1780
|
debugArtifactsDir,
|
|
1684
1781
|
`session-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1685
1782
|
);
|
|
@@ -1723,10 +1820,10 @@ ${"=".repeat(60)}
|
|
|
1723
1820
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1724
1821
|
try {
|
|
1725
1822
|
const fs5 = __require("fs");
|
|
1726
|
-
const
|
|
1823
|
+
const path6 = __require("path");
|
|
1727
1824
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1728
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1729
|
-
const responseFile =
|
|
1825
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path6.join(process.cwd(), "debug-artifacts");
|
|
1826
|
+
const responseFile = path6.join(
|
|
1730
1827
|
debugArtifactsDir,
|
|
1731
1828
|
`response-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1732
1829
|
);
|
|
@@ -1816,7 +1913,7 @@ ${"=".repeat(60)}
|
|
|
1816
1913
|
*/
|
|
1817
1914
|
async loadSchemaContent(schema) {
|
|
1818
1915
|
const fs5 = __require("fs").promises;
|
|
1819
|
-
const
|
|
1916
|
+
const path6 = __require("path");
|
|
1820
1917
|
if (typeof schema === "object" && schema !== null) {
|
|
1821
1918
|
log("\u{1F4CB} Using inline schema object from configuration");
|
|
1822
1919
|
return JSON.stringify(schema);
|
|
@@ -1829,12 +1926,12 @@ ${"=".repeat(60)}
|
|
|
1829
1926
|
}
|
|
1830
1927
|
} catch {
|
|
1831
1928
|
}
|
|
1832
|
-
if ((schema.startsWith("./") || schema.includes(".json")) && !
|
|
1929
|
+
if ((schema.startsWith("./") || schema.includes(".json")) && !path6.isAbsolute(schema)) {
|
|
1833
1930
|
if (schema.includes("..") || schema.includes("\0")) {
|
|
1834
1931
|
throw new Error("Invalid schema path: path traversal not allowed");
|
|
1835
1932
|
}
|
|
1836
1933
|
try {
|
|
1837
|
-
const schemaPath2 =
|
|
1934
|
+
const schemaPath2 = path6.resolve(process.cwd(), schema);
|
|
1838
1935
|
log(`\u{1F4CB} Loading custom schema from file: ${schemaPath2}`);
|
|
1839
1936
|
const schemaContent = await fs5.readFile(schemaPath2, "utf-8");
|
|
1840
1937
|
return schemaContent.trim();
|
|
@@ -1848,7 +1945,7 @@ ${"=".repeat(60)}
|
|
|
1848
1945
|
if (!sanitizedSchemaName || sanitizedSchemaName !== schema) {
|
|
1849
1946
|
throw new Error("Invalid schema name");
|
|
1850
1947
|
}
|
|
1851
|
-
const schemaPath =
|
|
1948
|
+
const schemaPath = path6.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
|
|
1852
1949
|
try {
|
|
1853
1950
|
const schemaContent = await fs5.readFile(schemaPath, "utf-8");
|
|
1854
1951
|
return schemaContent.trim();
|
|
@@ -2178,7 +2275,7 @@ var PRReviewer = class {
|
|
|
2178
2275
|
async reviewPR(owner, repo, prNumber, prInfo, options = {}) {
|
|
2179
2276
|
const { debug = false, config, checks } = options;
|
|
2180
2277
|
if (config && checks && checks.length > 0) {
|
|
2181
|
-
const { CheckExecutionEngine: CheckExecutionEngine2 } = await import("./check-execution-engine-
|
|
2278
|
+
const { CheckExecutionEngine: CheckExecutionEngine2 } = await import("./check-execution-engine-NMPXJ7FQ.mjs");
|
|
2182
2279
|
const engine = new CheckExecutionEngine2();
|
|
2183
2280
|
const { results } = await engine.executeGroupedChecks(
|
|
2184
2281
|
prInfo,
|
|
@@ -2197,14 +2294,66 @@ var PRReviewer = class {
|
|
|
2197
2294
|
"No configuration provided. Please create a .visor.yaml file with check definitions. Built-in prompts have been removed - all checks must be explicitly configured."
|
|
2198
2295
|
);
|
|
2199
2296
|
}
|
|
2297
|
+
/**
|
|
2298
|
+
* Helper to check if a schema is comment-generating
|
|
2299
|
+
* Comment-generating schemas include:
|
|
2300
|
+
* - Built-in schemas: code-review, overview, plain, text
|
|
2301
|
+
* - Custom schemas with a "text" field in properties
|
|
2302
|
+
*/
|
|
2303
|
+
async isCommentGeneratingSchema(schema) {
|
|
2304
|
+
try {
|
|
2305
|
+
if (typeof schema === "string") {
|
|
2306
|
+
if (["code-review", "overview", "plain", "text"].includes(schema)) {
|
|
2307
|
+
return true;
|
|
2308
|
+
}
|
|
2309
|
+
const fs5 = __require("fs").promises;
|
|
2310
|
+
const path6 = __require("path");
|
|
2311
|
+
const sanitizedSchemaName = schema.replace(/[^a-zA-Z0-9-]/g, "");
|
|
2312
|
+
if (!sanitizedSchemaName || sanitizedSchemaName !== schema) {
|
|
2313
|
+
return false;
|
|
2314
|
+
}
|
|
2315
|
+
const schemaPath = path6.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
|
|
2316
|
+
try {
|
|
2317
|
+
const schemaContent = await fs5.readFile(schemaPath, "utf-8");
|
|
2318
|
+
const schemaObj = JSON.parse(schemaContent);
|
|
2319
|
+
const properties = schemaObj.properties;
|
|
2320
|
+
return !!(properties && "text" in properties);
|
|
2321
|
+
} catch {
|
|
2322
|
+
return false;
|
|
2323
|
+
}
|
|
2324
|
+
} else {
|
|
2325
|
+
const properties = schema.properties;
|
|
2326
|
+
return !!(properties && "text" in properties);
|
|
2327
|
+
}
|
|
2328
|
+
} catch {
|
|
2329
|
+
return false;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
/**
|
|
2333
|
+
* Filter check results to only include those that should post GitHub comments
|
|
2334
|
+
*/
|
|
2335
|
+
async filterCommentGeneratingChecks(checkResults, config) {
|
|
2336
|
+
const filtered = [];
|
|
2337
|
+
for (const r of checkResults) {
|
|
2338
|
+
const cfg = config.checks?.[r.checkName];
|
|
2339
|
+
const type = cfg?.type || "ai";
|
|
2340
|
+
const schema = cfg?.schema;
|
|
2341
|
+
let shouldPostComment = false;
|
|
2342
|
+
const isAICheck = type === "ai" || type === "claude-code";
|
|
2343
|
+
if (!schema || schema === "") {
|
|
2344
|
+
shouldPostComment = isAICheck;
|
|
2345
|
+
} else {
|
|
2346
|
+
shouldPostComment = await this.isCommentGeneratingSchema(schema);
|
|
2347
|
+
}
|
|
2348
|
+
if (shouldPostComment) {
|
|
2349
|
+
filtered.push(r);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
return filtered;
|
|
2353
|
+
}
|
|
2200
2354
|
async postReviewComment(owner, repo, prNumber, groupedResults, options = {}) {
|
|
2201
2355
|
for (const [groupName, checkResults] of Object.entries(groupedResults)) {
|
|
2202
|
-
const filteredResults = options.config ? checkResults.
|
|
2203
|
-
const cfg = options.config.checks?.[r.checkName];
|
|
2204
|
-
const t = cfg?.type || "";
|
|
2205
|
-
const isGitHubOps = t === "github" || r.group === "github" || t === "noop" || t === "command";
|
|
2206
|
-
return !isGitHubOps;
|
|
2207
|
-
}) : checkResults;
|
|
2356
|
+
const filteredResults = options.config ? await this.filterCommentGeneratingChecks(checkResults, options.config) : checkResults;
|
|
2208
2357
|
if (!filteredResults || filteredResults.length === 0) {
|
|
2209
2358
|
continue;
|
|
2210
2359
|
}
|
|
@@ -2337,14 +2486,14 @@ var PRReviewer = class {
|
|
|
2337
2486
|
saveDebugArtifact(debug) {
|
|
2338
2487
|
try {
|
|
2339
2488
|
const fs5 = __require("fs");
|
|
2340
|
-
const
|
|
2341
|
-
const debugDir =
|
|
2489
|
+
const path6 = __require("path");
|
|
2490
|
+
const debugDir = path6.join(process.cwd(), "debug-artifacts");
|
|
2342
2491
|
if (!fs5.existsSync(debugDir)) {
|
|
2343
2492
|
fs5.mkdirSync(debugDir, { recursive: true });
|
|
2344
2493
|
}
|
|
2345
2494
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2346
2495
|
const filename = `visor-debug-${timestamp}.md`;
|
|
2347
|
-
const filepath =
|
|
2496
|
+
const filepath = path6.join(debugDir, filename);
|
|
2348
2497
|
const content = [
|
|
2349
2498
|
`# Visor Debug Information`,
|
|
2350
2499
|
``,
|
|
@@ -2376,7 +2525,7 @@ var PRReviewer = class {
|
|
|
2376
2525
|
|
|
2377
2526
|
// src/git-repository-analyzer.ts
|
|
2378
2527
|
import { simpleGit } from "simple-git";
|
|
2379
|
-
import * as
|
|
2528
|
+
import * as path2 from "path";
|
|
2380
2529
|
import * as fs from "fs";
|
|
2381
2530
|
var MAX_PATCH_SIZE = 50 * 1024;
|
|
2382
2531
|
var GitRepositoryAnalyzer = class {
|
|
@@ -2591,7 +2740,7 @@ ${file.patch}`).join("\n\n");
|
|
|
2591
2740
|
console.error(`\u23ED\uFE0F Skipping excluded file: ${file}`);
|
|
2592
2741
|
continue;
|
|
2593
2742
|
}
|
|
2594
|
-
const filePath =
|
|
2743
|
+
const filePath = path2.join(this.cwd, file);
|
|
2595
2744
|
const fileChange = await this.analyzeFileChange(file, status2, filePath, includeContext);
|
|
2596
2745
|
changes.push(fileChange);
|
|
2597
2746
|
}
|
|
@@ -3052,7 +3201,7 @@ var EnvironmentResolver = class {
|
|
|
3052
3201
|
|
|
3053
3202
|
// src/issue-filter.ts
|
|
3054
3203
|
import * as fs2 from "fs";
|
|
3055
|
-
import * as
|
|
3204
|
+
import * as path3 from "path";
|
|
3056
3205
|
var IssueFilter = class {
|
|
3057
3206
|
fileCache = /* @__PURE__ */ new Map();
|
|
3058
3207
|
suppressionEnabled;
|
|
@@ -3120,7 +3269,7 @@ var IssueFilter = class {
|
|
|
3120
3269
|
return this.fileCache.get(filePath);
|
|
3121
3270
|
}
|
|
3122
3271
|
try {
|
|
3123
|
-
const resolvedPath =
|
|
3272
|
+
const resolvedPath = path3.isAbsolute(filePath) ? filePath : path3.join(workingDir, filePath);
|
|
3124
3273
|
if (!fs2.existsSync(resolvedPath)) {
|
|
3125
3274
|
if (fs2.existsSync(filePath)) {
|
|
3126
3275
|
const content2 = fs2.readFileSync(filePath, "utf8");
|
|
@@ -3148,7 +3297,7 @@ var IssueFilter = class {
|
|
|
3148
3297
|
|
|
3149
3298
|
// src/providers/ai-check-provider.ts
|
|
3150
3299
|
import fs3 from "fs/promises";
|
|
3151
|
-
import
|
|
3300
|
+
import path4 from "path";
|
|
3152
3301
|
var AICheckProvider = class extends CheckProvider {
|
|
3153
3302
|
aiReviewService;
|
|
3154
3303
|
liquidEngine;
|
|
@@ -3265,7 +3414,7 @@ var AICheckProvider = class extends CheckProvider {
|
|
|
3265
3414
|
const hasFileExtension = /\.[a-zA-Z0-9]{1,10}$/i.test(str);
|
|
3266
3415
|
const hasPathSeparators = /[\/\\]/.test(str);
|
|
3267
3416
|
const isRelativePath = /^\.{1,2}\//.test(str);
|
|
3268
|
-
const isAbsolutePath =
|
|
3417
|
+
const isAbsolutePath = path4.isAbsolute(str);
|
|
3269
3418
|
const hasTypicalFileChars = /^[a-zA-Z0-9._\-\/\\:~]+$/.test(str);
|
|
3270
3419
|
if (!(hasFileExtension || isRelativePath || isAbsolutePath || hasPathSeparators)) {
|
|
3271
3420
|
return false;
|
|
@@ -3275,10 +3424,10 @@ var AICheckProvider = class extends CheckProvider {
|
|
|
3275
3424
|
}
|
|
3276
3425
|
try {
|
|
3277
3426
|
let resolvedPath;
|
|
3278
|
-
if (
|
|
3279
|
-
resolvedPath =
|
|
3427
|
+
if (path4.isAbsolute(str)) {
|
|
3428
|
+
resolvedPath = path4.normalize(str);
|
|
3280
3429
|
} else {
|
|
3281
|
-
resolvedPath =
|
|
3430
|
+
resolvedPath = path4.resolve(process.cwd(), str);
|
|
3282
3431
|
}
|
|
3283
3432
|
const fs5 = __require("fs").promises;
|
|
3284
3433
|
try {
|
|
@@ -3299,14 +3448,14 @@ var AICheckProvider = class extends CheckProvider {
|
|
|
3299
3448
|
throw new Error("Prompt file must have .liquid extension");
|
|
3300
3449
|
}
|
|
3301
3450
|
let resolvedPath;
|
|
3302
|
-
if (
|
|
3451
|
+
if (path4.isAbsolute(promptPath)) {
|
|
3303
3452
|
resolvedPath = promptPath;
|
|
3304
3453
|
} else {
|
|
3305
|
-
resolvedPath =
|
|
3454
|
+
resolvedPath = path4.resolve(process.cwd(), promptPath);
|
|
3306
3455
|
}
|
|
3307
|
-
if (!
|
|
3308
|
-
const normalizedPath =
|
|
3309
|
-
const currentDir =
|
|
3456
|
+
if (!path4.isAbsolute(promptPath)) {
|
|
3457
|
+
const normalizedPath = path4.normalize(resolvedPath);
|
|
3458
|
+
const currentDir = path4.resolve(process.cwd());
|
|
3310
3459
|
if (!normalizedPath.startsWith(currentDir)) {
|
|
3311
3460
|
throw new Error("Invalid prompt file path: path traversal detected");
|
|
3312
3461
|
}
|
|
@@ -4167,7 +4316,8 @@ var LogCheckProvider = class extends CheckProvider {
|
|
|
4167
4316
|
dependencyResults,
|
|
4168
4317
|
includePrContext,
|
|
4169
4318
|
includeDependencies,
|
|
4170
|
-
includeMetadata
|
|
4319
|
+
includeMetadata,
|
|
4320
|
+
config.__outputHistory
|
|
4171
4321
|
);
|
|
4172
4322
|
const renderedMessage = await this.liquid.parseAndRender(message, templateContext);
|
|
4173
4323
|
const logOutput = this.formatLogOutput(
|
|
@@ -4188,7 +4338,7 @@ var LogCheckProvider = class extends CheckProvider {
|
|
|
4188
4338
|
logOutput
|
|
4189
4339
|
};
|
|
4190
4340
|
}
|
|
4191
|
-
buildTemplateContext(prInfo, dependencyResults, _includePrContext = true, _includeDependencies = true, includeMetadata = true) {
|
|
4341
|
+
buildTemplateContext(prInfo, dependencyResults, _includePrContext = true, _includeDependencies = true, includeMetadata = true, outputHistory) {
|
|
4192
4342
|
const context = {};
|
|
4193
4343
|
context.pr = {
|
|
4194
4344
|
number: prInfo.number,
|
|
@@ -4212,6 +4362,7 @@ var LogCheckProvider = class extends CheckProvider {
|
|
|
4212
4362
|
if (dependencyResults) {
|
|
4213
4363
|
const dependencies = {};
|
|
4214
4364
|
const outputs = {};
|
|
4365
|
+
const history = {};
|
|
4215
4366
|
context.dependencyCount = dependencyResults.size;
|
|
4216
4367
|
for (const [checkName, result] of dependencyResults.entries()) {
|
|
4217
4368
|
dependencies[checkName] = {
|
|
@@ -4222,6 +4373,12 @@ var LogCheckProvider = class extends CheckProvider {
|
|
|
4222
4373
|
const summary = result;
|
|
4223
4374
|
outputs[checkName] = summary.output !== void 0 ? summary.output : summary;
|
|
4224
4375
|
}
|
|
4376
|
+
if (outputHistory) {
|
|
4377
|
+
for (const [checkName, historyArray] of outputHistory) {
|
|
4378
|
+
history[checkName] = historyArray;
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
outputs.history = history;
|
|
4225
4382
|
context.dependencies = dependencies;
|
|
4226
4383
|
context.outputs = outputs;
|
|
4227
4384
|
}
|
|
@@ -4581,7 +4738,7 @@ ${cfg.value_js}
|
|
|
4581
4738
|
|
|
4582
4739
|
// src/providers/claude-code-check-provider.ts
|
|
4583
4740
|
import fs4 from "fs/promises";
|
|
4584
|
-
import
|
|
4741
|
+
import path5 from "path";
|
|
4585
4742
|
|
|
4586
4743
|
// src/providers/claude-code-types.ts
|
|
4587
4744
|
async function safeImport(moduleName) {
|
|
@@ -4742,7 +4899,7 @@ var ClaudeCodeCheckProvider = class extends CheckProvider {
|
|
|
4742
4899
|
const hasFileExtension = /\.[a-zA-Z0-9]{1,10}$/i.test(str);
|
|
4743
4900
|
const hasPathSeparators = /[\/\\]/.test(str);
|
|
4744
4901
|
const isRelativePath = /^\.{1,2}\//.test(str);
|
|
4745
|
-
const isAbsolutePath =
|
|
4902
|
+
const isAbsolutePath = path5.isAbsolute(str);
|
|
4746
4903
|
const hasTypicalFileChars = /^[a-zA-Z0-9._\-\/\\:~]+$/.test(str);
|
|
4747
4904
|
if (!(hasFileExtension || isRelativePath || isAbsolutePath || hasPathSeparators)) {
|
|
4748
4905
|
return false;
|
|
@@ -4752,10 +4909,10 @@ var ClaudeCodeCheckProvider = class extends CheckProvider {
|
|
|
4752
4909
|
}
|
|
4753
4910
|
try {
|
|
4754
4911
|
let resolvedPath;
|
|
4755
|
-
if (
|
|
4756
|
-
resolvedPath =
|
|
4912
|
+
if (path5.isAbsolute(str)) {
|
|
4913
|
+
resolvedPath = path5.normalize(str);
|
|
4757
4914
|
} else {
|
|
4758
|
-
resolvedPath =
|
|
4915
|
+
resolvedPath = path5.resolve(process.cwd(), str);
|
|
4759
4916
|
}
|
|
4760
4917
|
try {
|
|
4761
4918
|
const stat = await fs4.stat(resolvedPath);
|
|
@@ -4775,14 +4932,14 @@ var ClaudeCodeCheckProvider = class extends CheckProvider {
|
|
|
4775
4932
|
throw new Error("Prompt file must have .liquid extension");
|
|
4776
4933
|
}
|
|
4777
4934
|
let resolvedPath;
|
|
4778
|
-
if (
|
|
4935
|
+
if (path5.isAbsolute(promptPath)) {
|
|
4779
4936
|
resolvedPath = promptPath;
|
|
4780
4937
|
} else {
|
|
4781
|
-
resolvedPath =
|
|
4938
|
+
resolvedPath = path5.resolve(process.cwd(), promptPath);
|
|
4782
4939
|
}
|
|
4783
|
-
if (!
|
|
4784
|
-
const normalizedPath =
|
|
4785
|
-
const currentDir =
|
|
4940
|
+
if (!path5.isAbsolute(promptPath)) {
|
|
4941
|
+
const normalizedPath = path5.normalize(resolvedPath);
|
|
4942
|
+
const currentDir = path5.resolve(process.cwd());
|
|
4786
4943
|
if (!normalizedPath.startsWith(currentDir)) {
|
|
4787
4944
|
throw new Error("Invalid prompt file path: path traversal detected");
|
|
4788
4945
|
}
|
|
@@ -5093,7 +5250,10 @@ var CommandCheckProvider = class extends CheckProvider {
|
|
|
5093
5250
|
},
|
|
5094
5251
|
files: prInfo.files,
|
|
5095
5252
|
fileCount: prInfo.files.length,
|
|
5096
|
-
outputs: this.buildOutputContext(
|
|
5253
|
+
outputs: this.buildOutputContext(
|
|
5254
|
+
dependencyResults,
|
|
5255
|
+
config.__outputHistory
|
|
5256
|
+
),
|
|
5097
5257
|
env: this.getSafeEnvironmentVariables()
|
|
5098
5258
|
};
|
|
5099
5259
|
logger.debug(
|
|
@@ -5819,16 +5979,23 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
5819
5979
|
};
|
|
5820
5980
|
}
|
|
5821
5981
|
}
|
|
5822
|
-
buildOutputContext(dependencyResults) {
|
|
5982
|
+
buildOutputContext(dependencyResults, outputHistory) {
|
|
5823
5983
|
if (!dependencyResults) {
|
|
5824
5984
|
return {};
|
|
5825
5985
|
}
|
|
5826
5986
|
const outputs = {};
|
|
5987
|
+
const history = {};
|
|
5827
5988
|
for (const [checkName, result] of dependencyResults) {
|
|
5828
5989
|
const summary = result;
|
|
5829
5990
|
const value = summary.output !== void 0 ? summary.output : summary;
|
|
5830
5991
|
outputs[checkName] = this.makeJsonSmart(value);
|
|
5831
5992
|
}
|
|
5993
|
+
if (outputHistory) {
|
|
5994
|
+
for (const [checkName, historyArray] of outputHistory) {
|
|
5995
|
+
history[checkName] = historyArray.map((val) => this.makeJsonSmart(val));
|
|
5996
|
+
}
|
|
5997
|
+
}
|
|
5998
|
+
outputs.history = history;
|
|
5832
5999
|
return outputs;
|
|
5833
6000
|
}
|
|
5834
6001
|
/**
|
|
@@ -6377,7 +6544,12 @@ var MemoryCheckProvider = class extends CheckProvider {
|
|
|
6377
6544
|
const key = config.key;
|
|
6378
6545
|
const namespace = config.namespace;
|
|
6379
6546
|
const memoryStore = MemoryStore.getInstance();
|
|
6380
|
-
const templateContext = this.buildTemplateContext(
|
|
6547
|
+
const templateContext = this.buildTemplateContext(
|
|
6548
|
+
prInfo,
|
|
6549
|
+
dependencyResults,
|
|
6550
|
+
memoryStore,
|
|
6551
|
+
config.__outputHistory
|
|
6552
|
+
);
|
|
6381
6553
|
let result;
|
|
6382
6554
|
try {
|
|
6383
6555
|
switch (operation) {
|
|
@@ -6660,7 +6832,7 @@ var MemoryCheckProvider = class extends CheckProvider {
|
|
|
6660
6832
|
/**
|
|
6661
6833
|
* Build template context for Liquid and JS evaluation
|
|
6662
6834
|
*/
|
|
6663
|
-
buildTemplateContext(prInfo, dependencyResults, memoryStore) {
|
|
6835
|
+
buildTemplateContext(prInfo, dependencyResults, memoryStore, outputHistory) {
|
|
6664
6836
|
const context = {};
|
|
6665
6837
|
context.pr = {
|
|
6666
6838
|
number: prInfo.number,
|
|
@@ -6679,14 +6851,21 @@ var MemoryCheckProvider = class extends CheckProvider {
|
|
|
6679
6851
|
changes: f.changes
|
|
6680
6852
|
}))
|
|
6681
6853
|
};
|
|
6854
|
+
const outputs = {};
|
|
6855
|
+
const history = {};
|
|
6682
6856
|
if (dependencyResults) {
|
|
6683
|
-
const outputs = {};
|
|
6684
6857
|
for (const [checkName, result] of dependencyResults.entries()) {
|
|
6685
6858
|
const summary = result;
|
|
6686
6859
|
outputs[checkName] = summary.output !== void 0 ? summary.output : summary;
|
|
6687
6860
|
}
|
|
6688
|
-
context.outputs = outputs;
|
|
6689
6861
|
}
|
|
6862
|
+
if (outputHistory) {
|
|
6863
|
+
for (const [checkName, historyArray] of outputHistory) {
|
|
6864
|
+
history[checkName] = historyArray;
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
outputs.history = history;
|
|
6868
|
+
context.outputs = outputs;
|
|
6690
6869
|
if (memoryStore) {
|
|
6691
6870
|
context.memory = {
|
|
6692
6871
|
get: (key, ns) => memoryStore.get(key, ns),
|
|
@@ -7424,10 +7603,6 @@ var FailureConditionEvaluator = class _FailureConditionEvaluator {
|
|
|
7424
7603
|
if (!Array.isArray(issues2)) return false;
|
|
7425
7604
|
return issues2.some((issue) => issue.file?.includes(pattern));
|
|
7426
7605
|
};
|
|
7427
|
-
const hasSuggestion = (suggestions2, text) => {
|
|
7428
|
-
if (!Array.isArray(suggestions2)) return false;
|
|
7429
|
-
return suggestions2.some((s) => s.toLowerCase().includes(text.toLowerCase()));
|
|
7430
|
-
};
|
|
7431
7606
|
const hasIssueWith = hasIssue;
|
|
7432
7607
|
const hasFileWith = hasFileMatching;
|
|
7433
7608
|
const permissionHelpers = createPermissionHelpers(
|
|
@@ -7442,7 +7617,6 @@ var FailureConditionEvaluator = class _FailureConditionEvaluator {
|
|
|
7442
7617
|
const isFirstTimer = permissionHelpers.isFirstTimer;
|
|
7443
7618
|
const output = context.output || {};
|
|
7444
7619
|
const issues = output.issues || [];
|
|
7445
|
-
const suggestions = [];
|
|
7446
7620
|
const metadata = context.metadata || {
|
|
7447
7621
|
checkName: context.checkName || "",
|
|
7448
7622
|
schema: context.schema || "",
|
|
@@ -7486,7 +7660,6 @@ var FailureConditionEvaluator = class _FailureConditionEvaluator {
|
|
|
7486
7660
|
memory: memoryAccessor,
|
|
7487
7661
|
// Legacy compatibility variables
|
|
7488
7662
|
issues,
|
|
7489
|
-
suggestions,
|
|
7490
7663
|
metadata,
|
|
7491
7664
|
criticalIssues,
|
|
7492
7665
|
errorIssues,
|
|
@@ -7515,7 +7688,6 @@ var FailureConditionEvaluator = class _FailureConditionEvaluator {
|
|
|
7515
7688
|
hasIssue,
|
|
7516
7689
|
countIssues,
|
|
7517
7690
|
hasFileMatching,
|
|
7518
|
-
hasSuggestion,
|
|
7519
7691
|
hasIssueWith,
|
|
7520
7692
|
hasFileWith,
|
|
7521
7693
|
// Permission helpers
|
|
@@ -8019,11 +8191,7 @@ Please check your configuration and try again.`
|
|
|
8019
8191
|
});
|
|
8020
8192
|
}
|
|
8021
8193
|
sections.push("");
|
|
8022
|
-
sections.push(
|
|
8023
|
-
sections.push("");
|
|
8024
|
-
sections.push(
|
|
8025
|
-
"*Powered by [Visor](https://probelabs.com/visor) from [Probelabs](https://probelabs.com)*"
|
|
8026
|
-
);
|
|
8194
|
+
sections.push(generateFooter());
|
|
8027
8195
|
return sections.join("\n");
|
|
8028
8196
|
}
|
|
8029
8197
|
/**
|
|
@@ -8263,6 +8431,8 @@ var CheckExecutionEngine = class _CheckExecutionEngine {
|
|
|
8263
8431
|
webhookContext;
|
|
8264
8432
|
routingSandbox;
|
|
8265
8433
|
executionStats = /* @__PURE__ */ new Map();
|
|
8434
|
+
// Track history of all outputs for each check (useful for loops and goto)
|
|
8435
|
+
outputHistory = /* @__PURE__ */ new Map();
|
|
8266
8436
|
// Event override to simulate alternate event (used during routing goto)
|
|
8267
8437
|
routingEventOverride;
|
|
8268
8438
|
// Cached GitHub context for context elevation when running in Actions
|
|
@@ -8506,6 +8676,8 @@ ${expr}
|
|
|
8506
8676
|
transform_js: targetCfg.transform_js,
|
|
8507
8677
|
env: targetCfg.env,
|
|
8508
8678
|
forEach: targetCfg.forEach,
|
|
8679
|
+
// Pass output history for loop/goto scenarios
|
|
8680
|
+
__outputHistory: this.outputHistory,
|
|
8509
8681
|
// Include provider-specific keys (e.g., op/values for github)
|
|
8510
8682
|
...targetCfg,
|
|
8511
8683
|
ai: {
|
|
@@ -8573,6 +8745,10 @@ ${expr}
|
|
|
8573
8745
|
timestamp: Date.now()
|
|
8574
8746
|
}));
|
|
8575
8747
|
const enriched = { ...r, issues: enrichedIssues };
|
|
8748
|
+
const enrichedWithOutput = enriched;
|
|
8749
|
+
if (enrichedWithOutput.output !== void 0) {
|
|
8750
|
+
this.trackOutputHistory(target, enrichedWithOutput.output);
|
|
8751
|
+
}
|
|
8576
8752
|
resultsMap?.set(target, enriched);
|
|
8577
8753
|
if (debug) log2(`\u{1F527} Debug: inline executed '${target}', issues: ${enrichedIssues.length}`);
|
|
8578
8754
|
return enriched;
|
|
@@ -9341,6 +9517,8 @@ ${expr}
|
|
|
9341
9517
|
ai_model: checkConfig.ai_model || config.ai_model,
|
|
9342
9518
|
// Pass claude_code config if present
|
|
9343
9519
|
claude_code: checkConfig.claude_code,
|
|
9520
|
+
// Pass output history for loop/goto scenarios
|
|
9521
|
+
__outputHistory: this.outputHistory,
|
|
9344
9522
|
// Pass any provider-specific config
|
|
9345
9523
|
...checkConfig
|
|
9346
9524
|
};
|
|
@@ -9377,10 +9555,14 @@ ${expr}
|
|
|
9377
9555
|
}
|
|
9378
9556
|
}
|
|
9379
9557
|
const content = await this.renderCheckContent(checkName, result, checkConfig, prInfo);
|
|
9558
|
+
let group = checkConfig.group || "default";
|
|
9559
|
+
if (config?.output?.pr_comment?.group_by === "check" && !checkConfig.group) {
|
|
9560
|
+
group = checkName;
|
|
9561
|
+
}
|
|
9380
9562
|
return {
|
|
9381
9563
|
checkName,
|
|
9382
9564
|
content,
|
|
9383
|
-
group
|
|
9565
|
+
group,
|
|
9384
9566
|
output: result.output,
|
|
9385
9567
|
debug: result.debug,
|
|
9386
9568
|
issues: result.issues
|
|
@@ -9519,16 +9701,19 @@ ${expr}
|
|
|
9519
9701
|
}
|
|
9520
9702
|
];
|
|
9521
9703
|
}
|
|
9704
|
+
let group = checkConfig.group || "default";
|
|
9705
|
+
if (config?.output?.pr_comment?.group_by === "check" && !checkConfig.group) {
|
|
9706
|
+
group = checkName;
|
|
9707
|
+
}
|
|
9522
9708
|
const checkResult = {
|
|
9523
9709
|
checkName,
|
|
9524
9710
|
content,
|
|
9525
|
-
group
|
|
9711
|
+
group,
|
|
9526
9712
|
output: checkSummary.output,
|
|
9527
9713
|
debug: reviewSummary.debug,
|
|
9528
9714
|
issues: issuesForCheck
|
|
9529
9715
|
// Include structured issues + rendering error if any
|
|
9530
9716
|
};
|
|
9531
|
-
const group = checkResult.group;
|
|
9532
9717
|
if (!groupedResults[group]) {
|
|
9533
9718
|
groupedResults[group] = [];
|
|
9534
9719
|
}
|
|
@@ -9546,7 +9731,7 @@ ${expr}
|
|
|
9546
9731
|
* - Enforcing .liquid file extension
|
|
9547
9732
|
*/
|
|
9548
9733
|
async validateTemplatePath(templatePath) {
|
|
9549
|
-
const
|
|
9734
|
+
const path6 = await import("path");
|
|
9550
9735
|
if (!templatePath || typeof templatePath !== "string" || templatePath.trim() === "") {
|
|
9551
9736
|
throw new Error("Template path must be a non-empty string");
|
|
9552
9737
|
}
|
|
@@ -9556,7 +9741,7 @@ ${expr}
|
|
|
9556
9741
|
if (!templatePath.endsWith(".liquid")) {
|
|
9557
9742
|
throw new Error("Template file must have .liquid extension");
|
|
9558
9743
|
}
|
|
9559
|
-
if (
|
|
9744
|
+
if (path6.isAbsolute(templatePath)) {
|
|
9560
9745
|
throw new Error("Template path must be relative to project directory");
|
|
9561
9746
|
}
|
|
9562
9747
|
if (templatePath.includes("..")) {
|
|
@@ -9570,14 +9755,14 @@ ${expr}
|
|
|
9570
9755
|
if (!projectRoot || typeof projectRoot !== "string") {
|
|
9571
9756
|
throw new Error("Unable to determine project root directory");
|
|
9572
9757
|
}
|
|
9573
|
-
const resolvedPath =
|
|
9574
|
-
const resolvedProjectRoot =
|
|
9758
|
+
const resolvedPath = path6.resolve(projectRoot, templatePath);
|
|
9759
|
+
const resolvedProjectRoot = path6.resolve(projectRoot);
|
|
9575
9760
|
if (!resolvedPath || !resolvedProjectRoot || resolvedPath === "" || resolvedProjectRoot === "") {
|
|
9576
9761
|
throw new Error(
|
|
9577
9762
|
`Unable to resolve template path: projectRoot="${projectRoot}", templatePath="${templatePath}", resolvedPath="${resolvedPath}", resolvedProjectRoot="${resolvedProjectRoot}"`
|
|
9578
9763
|
);
|
|
9579
9764
|
}
|
|
9580
|
-
if (!resolvedPath.startsWith(resolvedProjectRoot +
|
|
9765
|
+
if (!resolvedPath.startsWith(resolvedProjectRoot + path6.sep) && resolvedPath !== resolvedProjectRoot) {
|
|
9581
9766
|
throw new Error("Template path escapes project directory");
|
|
9582
9767
|
}
|
|
9583
9768
|
return resolvedPath;
|
|
@@ -9622,7 +9807,7 @@ ${expr}
|
|
|
9622
9807
|
}
|
|
9623
9808
|
const { createExtendedLiquid: createExtendedLiquid2 } = await import("./liquid-extensions-GMEGEGC3.mjs");
|
|
9624
9809
|
const fs5 = await import("fs/promises");
|
|
9625
|
-
const
|
|
9810
|
+
const path6 = await import("path");
|
|
9626
9811
|
const liquid = createExtendedLiquid2({
|
|
9627
9812
|
trimTagLeft: false,
|
|
9628
9813
|
trimTagRight: false,
|
|
@@ -9656,7 +9841,7 @@ ${expr}
|
|
|
9656
9841
|
if (!sanitizedSchema) {
|
|
9657
9842
|
throw new Error("Invalid schema name");
|
|
9658
9843
|
}
|
|
9659
|
-
const templatePath =
|
|
9844
|
+
const templatePath = path6.join(__dirname, `../output/${sanitizedSchema}/template.liquid`);
|
|
9660
9845
|
templateContent = await fs5.readFile(templatePath, "utf-8");
|
|
9661
9846
|
if (sanitizedSchema === "issue-assistant") {
|
|
9662
9847
|
enrichAssistantContext = true;
|
|
@@ -10429,6 +10614,10 @@ ${expr}
|
|
|
10429
10614
|
itemResult.issues || [],
|
|
10430
10615
|
itemResult.output
|
|
10431
10616
|
);
|
|
10617
|
+
const itemOutput = itemResult.output;
|
|
10618
|
+
if (itemOutput !== void 0) {
|
|
10619
|
+
this.trackOutputHistory(checkName, itemOutput);
|
|
10620
|
+
}
|
|
10432
10621
|
const descendantSet = (() => {
|
|
10433
10622
|
const visited = /* @__PURE__ */ new Set();
|
|
10434
10623
|
const stack = [checkName];
|
|
@@ -11059,6 +11248,10 @@ ${error.stack || ""}` : String(error);
|
|
|
11059
11248
|
]);
|
|
11060
11249
|
} catch {
|
|
11061
11250
|
}
|
|
11251
|
+
const reviewResultWithOutput = reviewResult;
|
|
11252
|
+
if (reviewResultWithOutput.output !== void 0) {
|
|
11253
|
+
this.trackOutputHistory(checkName, reviewResultWithOutput.output);
|
|
11254
|
+
}
|
|
11062
11255
|
results.set(checkName, reviewResult);
|
|
11063
11256
|
} else {
|
|
11064
11257
|
const errorSummary = {
|
|
@@ -12302,6 +12495,16 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
12302
12495
|
stats.outputsProduced = (stats.outputsProduced || 0) + 1;
|
|
12303
12496
|
}
|
|
12304
12497
|
}
|
|
12498
|
+
/**
|
|
12499
|
+
* Track output in history for loop/goto scenarios
|
|
12500
|
+
*/
|
|
12501
|
+
trackOutputHistory(checkName, output) {
|
|
12502
|
+
if (output === void 0) return;
|
|
12503
|
+
if (!this.outputHistory.has(checkName)) {
|
|
12504
|
+
this.outputHistory.set(checkName, []);
|
|
12505
|
+
}
|
|
12506
|
+
this.outputHistory.get(checkName).push(output);
|
|
12507
|
+
}
|
|
12305
12508
|
/**
|
|
12306
12509
|
* Record that a check was skipped
|
|
12307
12510
|
*/
|
|
@@ -12494,4 +12697,4 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
12494
12697
|
export {
|
|
12495
12698
|
CheckExecutionEngine
|
|
12496
12699
|
};
|
|
12497
|
-
//# sourceMappingURL=chunk-
|
|
12700
|
+
//# sourceMappingURL=chunk-Q4S5A5TO.mjs.map
|