@probelabs/visor 0.1.94 → 0.1.96

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.
Files changed (44) hide show
  1. package/README.md +4 -4
  2. package/defaults/.visor.yaml +86 -6
  3. package/dist/ai-review-service.d.ts +1 -1
  4. package/dist/ai-review-service.d.ts.map +1 -1
  5. package/dist/cli-main.d.ts +1 -0
  6. package/dist/cli-main.d.ts.map +1 -1
  7. package/dist/cli.d.ts +1 -0
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/commands.d.ts.map +1 -1
  10. package/dist/config.d.ts +6 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/defaults/.visor.yaml +86 -6
  13. package/dist/failure-condition-evaluator.d.ts.map +1 -1
  14. package/dist/footer.d.ts +25 -0
  15. package/dist/footer.d.ts.map +1 -0
  16. package/dist/github-check-service.d.ts.map +1 -1
  17. package/dist/github-comments.d.ts.map +1 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1968 -521
  21. package/dist/output/code-review/schema.json +0 -23
  22. package/dist/reviewer.d.ts +5 -2
  23. package/dist/reviewer.d.ts.map +1 -1
  24. package/dist/sdk/{check-execution-engine-YBRPVUWD.mjs → check-execution-engine-NMPXJ7FQ.mjs} +2 -2
  25. package/dist/sdk/{chunk-DQRFOQAP.mjs → chunk-Q4S5A5TO.mjs} +199 -113
  26. package/dist/sdk/chunk-Q4S5A5TO.mjs.map +1 -0
  27. package/dist/sdk/sdk.js +249 -149
  28. package/dist/sdk/sdk.js.map +1 -1
  29. package/dist/sdk/sdk.mjs +23 -19
  30. package/dist/sdk/sdk.mjs.map +1 -1
  31. package/dist/traces/{run-2025-10-16T11-33-32-682Z.ndjson → run-2025-10-18T20-24-27-886Z.ndjson} +8 -1
  32. package/dist/traces/{run-2025-10-16T11-33-43-618Z.ndjson → run-2025-10-18T20-24-38-817Z.ndjson} +8 -1
  33. package/dist/traces/{run-2025-10-16T11-33-44-157Z.ndjson → run-2025-10-18T20-24-39-361Z.ndjson} +8 -1
  34. package/dist/traces/{run-2025-10-16T11-33-44-647Z.ndjson → run-2025-10-18T20-24-39-852Z.ndjson} +8 -1
  35. package/dist/types/cli.d.ts +3 -2
  36. package/dist/types/cli.d.ts.map +1 -1
  37. package/dist/types/config.d.ts +0 -2
  38. package/dist/types/config.d.ts.map +1 -1
  39. package/dist/utils/diff-processor.d.ts +6 -0
  40. package/dist/utils/diff-processor.d.ts.map +1 -0
  41. package/package.json +3 -2
  42. package/dist/sdk/chunk-DQRFOQAP.mjs.map +0 -1
  43. /package/dist/sdk/{check-execution-engine-YBRPVUWD.mjs.map → check-execution-engine-NMPXJ7FQ.mjs.map} +0 -0
  44. /package/dist/traces/{run-2025-10-16T11-33-45-128Z.ndjson → run-2025-10-18T20-24-40-335Z.ndjson} +0 -0
package/dist/sdk/sdk.js CHANGED
@@ -136,6 +136,33 @@ var init_logger = __esm({
136
136
  }
137
137
  });
138
138
 
139
+ // src/footer.ts
140
+ function generateFooter(options = {}) {
141
+ const { includeMetadata, includeSeparator = true } = options;
142
+ const parts = [];
143
+ if (includeSeparator) {
144
+ parts.push("---");
145
+ parts.push("");
146
+ }
147
+ parts.push(
148
+ "*Powered by [Visor](https://probelabs.com/visor) from [Probelabs](https://probelabs.com)*"
149
+ );
150
+ if (includeMetadata) {
151
+ const { lastUpdated, triggeredBy, commitSha } = includeMetadata;
152
+ const commitInfo = commitSha ? ` | Commit: ${commitSha.substring(0, 7)}` : "";
153
+ parts.push("");
154
+ parts.push(`*Last updated: ${lastUpdated} | Triggered by: ${triggeredBy}${commitInfo}*`);
155
+ }
156
+ parts.push("");
157
+ parts.push("\u{1F4A1} **TIP:** You can chat with Visor using `/visor ask <your question>`");
158
+ return parts.join("\n");
159
+ }
160
+ var init_footer = __esm({
161
+ "src/footer.ts"() {
162
+ "use strict";
163
+ }
164
+ });
165
+
139
166
  // src/github-comments.ts
140
167
  var import_uuid, CommentManager;
141
168
  var init_github_comments = __esm({
@@ -143,6 +170,7 @@ var init_github_comments = __esm({
143
170
  "use strict";
144
171
  import_uuid = require("uuid");
145
172
  init_logger();
173
+ init_footer();
146
174
  CommentManager = class {
147
175
  octokit;
148
176
  retryConfig;
@@ -244,15 +272,17 @@ var init_github_comments = __esm({
244
272
  */
245
273
  formatCommentWithMetadata(content, metadata) {
246
274
  const { commentId, lastUpdated, triggeredBy, commitSha } = metadata;
247
- const commitInfo = commitSha ? ` | Commit: ${commitSha.substring(0, 7)}` : "";
275
+ const footer = generateFooter({
276
+ includeMetadata: {
277
+ lastUpdated,
278
+ triggeredBy,
279
+ commitSha
280
+ }
281
+ });
248
282
  return `<!-- visor-comment-id:${commentId} -->
249
283
  ${content}
250
284
 
251
- ---
252
-
253
- *Powered by [Visor](https://probelabs.com/visor) from [Probelabs](https://probelabs.com)*
254
-
255
- *Last updated: ${lastUpdated} | Triggered by: ${triggeredBy}${commitInfo}*
285
+ ${footer}
256
286
  <!-- /visor-comment-id:${commentId} -->`;
257
287
  }
258
288
  /**
@@ -718,18 +748,81 @@ var init_session_registry = __esm({
718
748
  }
719
749
  });
720
750
 
751
+ // src/utils/diff-processor.ts
752
+ async function processDiffWithOutline(diffContent) {
753
+ if (!diffContent || diffContent.trim().length === 0) {
754
+ return diffContent;
755
+ }
756
+ try {
757
+ const originalProbePath = process.env.PROBE_PATH;
758
+ const fs12 = require("fs");
759
+ const possiblePaths = [
760
+ // Relative to current working directory (most common in production)
761
+ path2.join(process.cwd(), "node_modules/@probelabs/probe/bin/probe-binary"),
762
+ // Relative to __dirname (for unbundled development)
763
+ path2.join(__dirname, "../..", "node_modules/@probelabs/probe/bin/probe-binary"),
764
+ // Relative to dist directory (for bundled CLI)
765
+ path2.join(__dirname, "node_modules/@probelabs/probe/bin/probe-binary")
766
+ ];
767
+ let probeBinaryPath;
768
+ for (const candidatePath of possiblePaths) {
769
+ if (fs12.existsSync(candidatePath)) {
770
+ probeBinaryPath = candidatePath;
771
+ break;
772
+ }
773
+ }
774
+ if (!probeBinaryPath) {
775
+ if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
776
+ console.error("Probe binary not found. Tried:", possiblePaths);
777
+ }
778
+ return diffContent;
779
+ }
780
+ process.env.PROBE_PATH = probeBinaryPath;
781
+ const extractPromise = (0, import_probe2.extract)({
782
+ content: diffContent,
783
+ format: "outline-diff",
784
+ allowTests: true
785
+ // Allow test files and test code blocks in extraction results
786
+ });
787
+ const timeoutPromise = new Promise((_, reject) => {
788
+ setTimeout(() => reject(new Error("Extract timeout after 30s")), 3e4);
789
+ });
790
+ const result = await Promise.race([extractPromise, timeoutPromise]);
791
+ if (originalProbePath !== void 0) {
792
+ process.env.PROBE_PATH = originalProbePath;
793
+ } else {
794
+ delete process.env.PROBE_PATH;
795
+ }
796
+ return typeof result === "string" ? result : JSON.stringify(result);
797
+ } catch (error) {
798
+ if (process.env.DEBUG === "1" || process.env.VERBOSE === "1") {
799
+ console.error("Failed to process diff with outline-diff format:", error);
800
+ }
801
+ return diffContent;
802
+ }
803
+ }
804
+ var import_probe2, path2;
805
+ var init_diff_processor = __esm({
806
+ "src/utils/diff-processor.ts"() {
807
+ "use strict";
808
+ import_probe2 = require("@probelabs/probe");
809
+ path2 = __toESM(require("path"));
810
+ }
811
+ });
812
+
721
813
  // src/ai-review-service.ts
722
814
  function log(...args) {
723
815
  logger.debug(args.join(" "));
724
816
  }
725
- var import_probe2, AIReviewService;
817
+ var import_probe3, AIReviewService;
726
818
  var init_ai_review_service = __esm({
727
819
  "src/ai-review-service.ts"() {
728
820
  "use strict";
729
- import_probe2 = require("@probelabs/probe");
821
+ import_probe3 = require("@probelabs/probe");
730
822
  init_session_registry();
731
823
  init_logger();
732
824
  init_tracer_init();
825
+ init_diff_processor();
733
826
  AIReviewService = class {
734
827
  config;
735
828
  sessionRegistry;
@@ -768,7 +861,7 @@ var init_ai_review_service = __esm({
768
861
  /**
769
862
  * Execute AI review using probe agent
770
863
  */
771
- async executeReview(prInfo, customPrompt, schema, _checkName, sessionId) {
864
+ async executeReview(prInfo, customPrompt, schema, checkName, sessionId) {
772
865
  const startTime = Date.now();
773
866
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
774
867
  const prompt = await this.buildCustomPrompt(prInfo, customPrompt, schema);
@@ -825,7 +918,7 @@ var init_ai_review_service = __esm({
825
918
  prompt,
826
919
  schema,
827
920
  debugInfo,
828
- _checkName,
921
+ checkName,
829
922
  sessionId
830
923
  );
831
924
  const processingTime = Date.now() - startTime;
@@ -985,9 +1078,9 @@ var init_ai_review_service = __esm({
985
1078
  */
986
1079
  async buildCustomPrompt(prInfo, customInstructions, schema, options) {
987
1080
  const skipPRContext = options?.skipPRContext === true;
988
- const prContext = skipPRContext ? "" : this.formatPRContext(prInfo);
989
- const isIssue = prInfo.isIssue === true;
990
1081
  const isCodeReviewSchema = schema === "code-review";
1082
+ const prContext = skipPRContext ? "" : await this.formatPRContext(prInfo, isCodeReviewSchema);
1083
+ const isIssue = prInfo.isIssue === true;
991
1084
  if (isIssue) {
992
1085
  if (skipPRContext) {
993
1086
  return `<instructions>
@@ -1076,7 +1169,7 @@ ${prContext}
1076
1169
  /**
1077
1170
  * Format PR or Issue context for the AI using XML structure
1078
1171
  */
1079
- formatPRContext(prInfo) {
1172
+ async formatPRContext(prInfo, isCodeReviewSchema) {
1080
1173
  const prContextInfo = prInfo;
1081
1174
  const isIssue = prContextInfo.isIssue === true;
1082
1175
  const isPRContext = prContextInfo.isPRContext === true;
@@ -1158,7 +1251,12 @@ ${this.escapeXml(prInfo.body)}
1158
1251
  }
1159
1252
  const issueComments = prInfo.comments;
1160
1253
  if (issueComments && issueComments.length > 0) {
1161
- const historicalComments = triggeringComment2 ? issueComments.filter((c) => c.id !== triggeringComment2.id) : issueComments;
1254
+ let historicalComments = triggeringComment2 ? issueComments.filter((c) => c.id !== triggeringComment2.id) : issueComments;
1255
+ if (isCodeReviewSchema) {
1256
+ historicalComments = historicalComments.filter(
1257
+ (c) => !c.body || !c.body.includes("visor-comment-id:pr-review-")
1258
+ );
1259
+ }
1162
1260
  if (historicalComments.length > 0) {
1163
1261
  context3 += `
1164
1262
  <!-- Previous comments in chronological order (excluding triggering comment) -->
@@ -1200,24 +1298,27 @@ ${this.escapeXml(prInfo.body)}
1200
1298
  }
1201
1299
  if (includeCodeContext) {
1202
1300
  if (prInfo.fullDiff) {
1301
+ const processedFullDiff = await processDiffWithOutline(prInfo.fullDiff);
1203
1302
  context2 += `
1204
- <!-- Complete unified diff showing all changes in the pull request -->
1303
+ <!-- Complete unified diff showing all changes in the pull request (processed with outline-diff) -->
1205
1304
  <full_diff>
1206
- ${this.escapeXml(prInfo.fullDiff)}
1305
+ ${this.escapeXml(processedFullDiff)}
1207
1306
  </full_diff>`;
1208
1307
  }
1209
1308
  if (prInfo.isIncremental) {
1210
1309
  if (prInfo.commitDiff && prInfo.commitDiff.length > 0) {
1310
+ const processedCommitDiff = await processDiffWithOutline(prInfo.commitDiff);
1211
1311
  context2 += `
1212
- <!-- Diff of only the latest commit for incremental analysis -->
1312
+ <!-- Diff of only the latest commit for incremental analysis (processed with outline-diff) -->
1213
1313
  <commit_diff>
1214
- ${this.escapeXml(prInfo.commitDiff)}
1314
+ ${this.escapeXml(processedCommitDiff)}
1215
1315
  </commit_diff>`;
1216
1316
  } else {
1317
+ const processedFallbackDiff = prInfo.fullDiff ? await processDiffWithOutline(prInfo.fullDiff) : "";
1217
1318
  context2 += `
1218
- <!-- Commit diff could not be retrieved - falling back to full diff analysis -->
1319
+ <!-- Commit diff could not be retrieved - falling back to full diff analysis (processed with outline-diff) -->
1219
1320
  <commit_diff>
1220
- ${prInfo.fullDiff ? this.escapeXml(prInfo.fullDiff) : ""}
1321
+ ${this.escapeXml(processedFallbackDiff)}
1221
1322
  </commit_diff>`;
1222
1323
  }
1223
1324
  }
@@ -1253,7 +1354,12 @@ ${prInfo.fullDiff ? this.escapeXml(prInfo.fullDiff) : ""}
1253
1354
  }
1254
1355
  const prComments = prInfo.comments;
1255
1356
  if (prComments && prComments.length > 0) {
1256
- const historicalComments = triggeringComment ? prComments.filter((c) => c.id !== triggeringComment.id) : prComments;
1357
+ let historicalComments = triggeringComment ? prComments.filter((c) => c.id !== triggeringComment.id) : prComments;
1358
+ if (isCodeReviewSchema) {
1359
+ historicalComments = historicalComments.filter(
1360
+ (c) => !c.body || !c.body.includes("visor-comment-id:pr-review-")
1361
+ );
1362
+ }
1257
1363
  if (historicalComments.length > 0) {
1258
1364
  context2 += `
1259
1365
  <!-- Previous PR comments in chronological order (excluding triggering comment) -->
@@ -1324,7 +1430,7 @@ ${schemaString}`);
1324
1430
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1325
1431
  try {
1326
1432
  const fs12 = require("fs");
1327
- const path12 = require("path");
1433
+ const path13 = require("path");
1328
1434
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1329
1435
  const provider = this.config.provider || "auto";
1330
1436
  const model = this.config.model || "default";
@@ -1438,16 +1544,16 @@ ${"=".repeat(60)}
1438
1544
  `;
1439
1545
  readableVersion += `${"=".repeat(60)}
1440
1546
  `;
1441
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1547
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path13.join(process.cwd(), "debug-artifacts");
1442
1548
  if (!fs12.existsSync(debugArtifactsDir)) {
1443
1549
  fs12.mkdirSync(debugArtifactsDir, { recursive: true });
1444
1550
  }
1445
- const debugFile = path12.join(
1551
+ const debugFile = path13.join(
1446
1552
  debugArtifactsDir,
1447
1553
  `prompt-${_checkName || "unknown"}-${timestamp}.json`
1448
1554
  );
1449
1555
  fs12.writeFileSync(debugFile, debugJson, "utf-8");
1450
- const readableFile = path12.join(
1556
+ const readableFile = path13.join(
1451
1557
  debugArtifactsDir,
1452
1558
  `prompt-${_checkName || "unknown"}-${timestamp}.txt`
1453
1559
  );
@@ -1484,7 +1590,7 @@ ${"=".repeat(60)}
1484
1590
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1485
1591
  try {
1486
1592
  const fs12 = require("fs");
1487
- const path12 = require("path");
1593
+ const path13 = require("path");
1488
1594
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1489
1595
  const agentAny2 = agent;
1490
1596
  let fullHistory = [];
@@ -1495,8 +1601,8 @@ ${"=".repeat(60)}
1495
1601
  } else if (agentAny2._messages) {
1496
1602
  fullHistory = agentAny2._messages;
1497
1603
  }
1498
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1499
- const sessionFile = path12.join(
1604
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path13.join(process.cwd(), "debug-artifacts");
1605
+ const sessionFile = path13.join(
1500
1606
  debugArtifactsDir,
1501
1607
  `session-${_checkName || "unknown"}-${timestamp}.json`
1502
1608
  );
@@ -1511,7 +1617,7 @@ ${"=".repeat(60)}
1511
1617
  latestResponse: response
1512
1618
  };
1513
1619
  fs12.writeFileSync(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
1514
- const sessionTxtFile = path12.join(
1620
+ const sessionTxtFile = path13.join(
1515
1621
  debugArtifactsDir,
1516
1622
  `session-${_checkName || "unknown"}-${timestamp}.txt`
1517
1623
  );
@@ -1555,10 +1661,10 @@ ${"=".repeat(60)}
1555
1661
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1556
1662
  try {
1557
1663
  const fs12 = require("fs");
1558
- const path12 = require("path");
1664
+ const path13 = require("path");
1559
1665
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1560
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1561
- const responseFile = path12.join(
1666
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path13.join(process.cwd(), "debug-artifacts");
1667
+ const responseFile = path13.join(
1562
1668
  debugArtifactsDir,
1563
1669
  `response-${_checkName || "unknown"}-${timestamp}.txt`
1564
1670
  );
@@ -1696,7 +1802,7 @@ ${"=".repeat(60)}
1696
1802
  if (this.config.model) {
1697
1803
  options.model = this.config.model;
1698
1804
  }
1699
- const agent = new import_probe2.ProbeAgent(options);
1805
+ const agent = new import_probe3.ProbeAgent(options);
1700
1806
  log("\u{1F680} Calling ProbeAgent...");
1701
1807
  let schemaString = void 0;
1702
1808
  let effectiveSchema = typeof schema === "object" ? "custom" : schema;
@@ -1730,7 +1836,7 @@ ${schemaString}`);
1730
1836
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1731
1837
  try {
1732
1838
  const fs12 = require("fs");
1733
- const path12 = require("path");
1839
+ const path13 = require("path");
1734
1840
  const os = require("os");
1735
1841
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1736
1842
  const debugData = {
@@ -1804,21 +1910,21 @@ ${"=".repeat(60)}
1804
1910
  readableVersion += `${"=".repeat(60)}
1805
1911
  `;
1806
1912
  const tempDir = os.tmpdir();
1807
- const promptFile = path12.join(tempDir, `visor-prompt-${timestamp}.txt`);
1913
+ const promptFile = path13.join(tempDir, `visor-prompt-${timestamp}.txt`);
1808
1914
  fs12.writeFileSync(promptFile, prompt, "utf-8");
1809
1915
  log(`
1810
1916
  \u{1F4BE} Prompt saved to: ${promptFile}`);
1811
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1917
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path13.join(process.cwd(), "debug-artifacts");
1812
1918
  try {
1813
1919
  if (!fs12.existsSync(debugArtifactsDir)) {
1814
1920
  fs12.mkdirSync(debugArtifactsDir, { recursive: true });
1815
1921
  }
1816
- const debugFile = path12.join(
1922
+ const debugFile = path13.join(
1817
1923
  debugArtifactsDir,
1818
1924
  `prompt-${_checkName || "unknown"}-${timestamp}.json`
1819
1925
  );
1820
1926
  fs12.writeFileSync(debugFile, debugJson, "utf-8");
1821
- const readableFile = path12.join(
1927
+ const readableFile = path13.join(
1822
1928
  debugArtifactsDir,
1823
1929
  `prompt-${_checkName || "unknown"}-${timestamp}.txt`
1824
1930
  );
@@ -1871,7 +1977,7 @@ $ ${cliCommand}
1871
1977
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1872
1978
  try {
1873
1979
  const fs12 = require("fs");
1874
- const path12 = require("path");
1980
+ const path13 = require("path");
1875
1981
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1876
1982
  const agentAny = agent;
1877
1983
  let fullHistory = [];
@@ -1882,8 +1988,8 @@ $ ${cliCommand}
1882
1988
  } else if (agentAny._messages) {
1883
1989
  fullHistory = agentAny._messages;
1884
1990
  }
1885
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1886
- const sessionFile = path12.join(
1991
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path13.join(process.cwd(), "debug-artifacts");
1992
+ const sessionFile = path13.join(
1887
1993
  debugArtifactsDir,
1888
1994
  `session-${_checkName || "unknown"}-${timestamp}.json`
1889
1995
  );
@@ -1898,7 +2004,7 @@ $ ${cliCommand}
1898
2004
  latestResponse: response
1899
2005
  };
1900
2006
  fs12.writeFileSync(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
1901
- const sessionTxtFile = path12.join(
2007
+ const sessionTxtFile = path13.join(
1902
2008
  debugArtifactsDir,
1903
2009
  `session-${_checkName || "unknown"}-${timestamp}.txt`
1904
2010
  );
@@ -1942,10 +2048,10 @@ ${"=".repeat(60)}
1942
2048
  if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
1943
2049
  try {
1944
2050
  const fs12 = require("fs");
1945
- const path12 = require("path");
2051
+ const path13 = require("path");
1946
2052
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1947
- const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path12.join(process.cwd(), "debug-artifacts");
1948
- const responseFile = path12.join(
2053
+ const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path13.join(process.cwd(), "debug-artifacts");
2054
+ const responseFile = path13.join(
1949
2055
  debugArtifactsDir,
1950
2056
  `response-${_checkName || "unknown"}-${timestamp}.txt`
1951
2057
  );
@@ -2035,7 +2141,7 @@ ${"=".repeat(60)}
2035
2141
  */
2036
2142
  async loadSchemaContent(schema) {
2037
2143
  const fs12 = require("fs").promises;
2038
- const path12 = require("path");
2144
+ const path13 = require("path");
2039
2145
  if (typeof schema === "object" && schema !== null) {
2040
2146
  log("\u{1F4CB} Using inline schema object from configuration");
2041
2147
  return JSON.stringify(schema);
@@ -2048,12 +2154,12 @@ ${"=".repeat(60)}
2048
2154
  }
2049
2155
  } catch {
2050
2156
  }
2051
- if ((schema.startsWith("./") || schema.includes(".json")) && !path12.isAbsolute(schema)) {
2157
+ if ((schema.startsWith("./") || schema.includes(".json")) && !path13.isAbsolute(schema)) {
2052
2158
  if (schema.includes("..") || schema.includes("\0")) {
2053
2159
  throw new Error("Invalid schema path: path traversal not allowed");
2054
2160
  }
2055
2161
  try {
2056
- const schemaPath2 = path12.resolve(process.cwd(), schema);
2162
+ const schemaPath2 = path13.resolve(process.cwd(), schema);
2057
2163
  log(`\u{1F4CB} Loading custom schema from file: ${schemaPath2}`);
2058
2164
  const schemaContent = await fs12.readFile(schemaPath2, "utf-8");
2059
2165
  return schemaContent.trim();
@@ -2067,7 +2173,7 @@ ${"=".repeat(60)}
2067
2173
  if (!sanitizedSchemaName || sanitizedSchemaName !== schema) {
2068
2174
  throw new Error("Invalid schema name");
2069
2175
  }
2070
- const schemaPath = path12.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
2176
+ const schemaPath = path13.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
2071
2177
  try {
2072
2178
  const schemaContent = await fs12.readFile(schemaPath, "utf-8");
2073
2179
  return schemaContent.trim();
@@ -2425,30 +2531,36 @@ var init_reviewer = __esm({
2425
2531
  );
2426
2532
  }
2427
2533
  /**
2428
- * Helper to check if a schema definition has a "text" field in its properties
2534
+ * Helper to check if a schema is comment-generating
2535
+ * Comment-generating schemas include:
2536
+ * - Built-in schemas: code-review, overview, plain, text
2537
+ * - Custom schemas with a "text" field in properties
2429
2538
  */
2430
- async schemaHasTextField(schema) {
2539
+ async isCommentGeneratingSchema(schema) {
2431
2540
  try {
2432
- let schemaObj;
2433
- if (typeof schema === "object") {
2434
- schemaObj = schema;
2435
- } else {
2541
+ if (typeof schema === "string") {
2542
+ if (["code-review", "overview", "plain", "text"].includes(schema)) {
2543
+ return true;
2544
+ }
2436
2545
  const fs12 = require("fs").promises;
2437
- const path12 = require("path");
2546
+ const path13 = require("path");
2438
2547
  const sanitizedSchemaName = schema.replace(/[^a-zA-Z0-9-]/g, "");
2439
2548
  if (!sanitizedSchemaName || sanitizedSchemaName !== schema) {
2440
2549
  return false;
2441
2550
  }
2442
- const schemaPath = path12.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
2551
+ const schemaPath = path13.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
2443
2552
  try {
2444
2553
  const schemaContent = await fs12.readFile(schemaPath, "utf-8");
2445
- schemaObj = JSON.parse(schemaContent);
2554
+ const schemaObj = JSON.parse(schemaContent);
2555
+ const properties = schemaObj.properties;
2556
+ return !!(properties && "text" in properties);
2446
2557
  } catch {
2447
2558
  return false;
2448
2559
  }
2560
+ } else {
2561
+ const properties = schema.properties;
2562
+ return !!(properties && "text" in properties);
2449
2563
  }
2450
- const properties = schemaObj.properties;
2451
- return !!(properties && "text" in properties);
2452
2564
  } catch {
2453
2565
  return false;
2454
2566
  }
@@ -2466,14 +2578,8 @@ var init_reviewer = __esm({
2466
2578
  const isAICheck = type === "ai" || type === "claude-code";
2467
2579
  if (!schema || schema === "") {
2468
2580
  shouldPostComment = isAICheck;
2469
- } else if (typeof schema === "string") {
2470
- if (schema === "text" || schema === "plain") {
2471
- shouldPostComment = true;
2472
- } else {
2473
- shouldPostComment = await this.schemaHasTextField(schema);
2474
- }
2475
- } else if (typeof schema === "object") {
2476
- shouldPostComment = await this.schemaHasTextField(schema);
2581
+ } else {
2582
+ shouldPostComment = await this.isCommentGeneratingSchema(schema);
2477
2583
  }
2478
2584
  if (shouldPostComment) {
2479
2585
  filtered.push(r);
@@ -2616,14 +2722,14 @@ var init_reviewer = __esm({
2616
2722
  saveDebugArtifact(debug) {
2617
2723
  try {
2618
2724
  const fs12 = require("fs");
2619
- const path12 = require("path");
2620
- const debugDir = path12.join(process.cwd(), "debug-artifacts");
2725
+ const path13 = require("path");
2726
+ const debugDir = path13.join(process.cwd(), "debug-artifacts");
2621
2727
  if (!fs12.existsSync(debugDir)) {
2622
2728
  fs12.mkdirSync(debugDir, { recursive: true });
2623
2729
  }
2624
2730
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2625
2731
  const filename = `visor-debug-${timestamp}.md`;
2626
- const filepath = path12.join(debugDir, filename);
2732
+ const filepath = path13.join(debugDir, filename);
2627
2733
  const content = [
2628
2734
  `# Visor Debug Information`,
2629
2735
  ``,
@@ -2656,12 +2762,12 @@ var init_reviewer = __esm({
2656
2762
  });
2657
2763
 
2658
2764
  // src/git-repository-analyzer.ts
2659
- var import_simple_git, path2, fs2, MAX_PATCH_SIZE, GitRepositoryAnalyzer;
2765
+ var import_simple_git, path3, fs2, MAX_PATCH_SIZE, GitRepositoryAnalyzer;
2660
2766
  var init_git_repository_analyzer = __esm({
2661
2767
  "src/git-repository-analyzer.ts"() {
2662
2768
  "use strict";
2663
2769
  import_simple_git = require("simple-git");
2664
- path2 = __toESM(require("path"));
2770
+ path3 = __toESM(require("path"));
2665
2771
  fs2 = __toESM(require("fs"));
2666
2772
  MAX_PATCH_SIZE = 50 * 1024;
2667
2773
  GitRepositoryAnalyzer = class {
@@ -2876,7 +2982,7 @@ ${file.patch}`).join("\n\n");
2876
2982
  console.error(`\u23ED\uFE0F Skipping excluded file: ${file}`);
2877
2983
  continue;
2878
2984
  }
2879
- const filePath = path2.join(this.cwd, file);
2985
+ const filePath = path3.join(this.cwd, file);
2880
2986
  const fileChange = await this.analyzeFileChange(file, status2, filePath, includeContext);
2881
2987
  changes.push(fileChange);
2882
2988
  }
@@ -3356,12 +3462,12 @@ var init_env_resolver = __esm({
3356
3462
  });
3357
3463
 
3358
3464
  // src/issue-filter.ts
3359
- var fs3, path3, IssueFilter;
3465
+ var fs3, path4, IssueFilter;
3360
3466
  var init_issue_filter = __esm({
3361
3467
  "src/issue-filter.ts"() {
3362
3468
  "use strict";
3363
3469
  fs3 = __toESM(require("fs"));
3364
- path3 = __toESM(require("path"));
3470
+ path4 = __toESM(require("path"));
3365
3471
  IssueFilter = class {
3366
3472
  fileCache = /* @__PURE__ */ new Map();
3367
3473
  suppressionEnabled;
@@ -3429,7 +3535,7 @@ var init_issue_filter = __esm({
3429
3535
  return this.fileCache.get(filePath);
3430
3536
  }
3431
3537
  try {
3432
- const resolvedPath = path3.isAbsolute(filePath) ? filePath : path3.join(workingDir, filePath);
3538
+ const resolvedPath = path4.isAbsolute(filePath) ? filePath : path4.join(workingDir, filePath);
3433
3539
  if (!fs3.existsSync(resolvedPath)) {
3434
3540
  if (fs3.existsSync(filePath)) {
3435
3541
  const content2 = fs3.readFileSync(filePath, "utf8");
@@ -9306,7 +9412,7 @@ function resolveTargetPath(outDir) {
9306
9412
  }
9307
9413
  if (CURRENT_FILE) return CURRENT_FILE;
9308
9414
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9309
- CURRENT_FILE = path8.join(outDir, `${ts}.ndjson`);
9415
+ CURRENT_FILE = path9.join(outDir, `${ts}.ndjson`);
9310
9416
  return CURRENT_FILE;
9311
9417
  }
9312
9418
  function isEnabled() {
@@ -9336,7 +9442,7 @@ async function flushNdjson() {
9336
9442
  function emitNdjsonFallback(name, attrs) {
9337
9443
  try {
9338
9444
  if (!isEnabled()) return;
9339
- const outDir = process.env.VISOR_TRACE_DIR || path8.join(process.cwd(), "output", "traces");
9445
+ const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
9340
9446
  const line = JSON.stringify({ name, attributes: attrs }) + "\n";
9341
9447
  appendAsync(outDir, line);
9342
9448
  } catch {
@@ -9345,18 +9451,18 @@ function emitNdjsonFallback(name, attrs) {
9345
9451
  function emitNdjsonSpanWithEvents(name, attrs, events) {
9346
9452
  try {
9347
9453
  if (!isEnabled()) return;
9348
- const outDir = process.env.VISOR_TRACE_DIR || path8.join(process.cwd(), "output", "traces");
9454
+ const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
9349
9455
  const line = JSON.stringify({ name, attributes: attrs, events }) + "\n";
9350
9456
  appendAsync(outDir, line);
9351
9457
  } catch {
9352
9458
  }
9353
9459
  }
9354
- var fs8, path8, CURRENT_FILE, dirReady, writeChain;
9460
+ var fs8, path9, CURRENT_FILE, dirReady, writeChain;
9355
9461
  var init_fallback_ndjson = __esm({
9356
9462
  "src/telemetry/fallback-ndjson.ts"() {
9357
9463
  "use strict";
9358
9464
  fs8 = __toESM(require("fs"));
9359
- path8 = __toESM(require("path"));
9465
+ path9 = __toESM(require("path"));
9360
9466
  CURRENT_FILE = null;
9361
9467
  dirReady = false;
9362
9468
  writeChain = Promise.resolve();
@@ -9832,10 +9938,6 @@ var init_failure_condition_evaluator = __esm({
9832
9938
  if (!Array.isArray(issues2)) return false;
9833
9939
  return issues2.some((issue) => issue.file?.includes(pattern));
9834
9940
  };
9835
- const hasSuggestion = (suggestions2, text) => {
9836
- if (!Array.isArray(suggestions2)) return false;
9837
- return suggestions2.some((s) => s.toLowerCase().includes(text.toLowerCase()));
9838
- };
9839
9941
  const hasIssueWith = hasIssue;
9840
9942
  const hasFileWith = hasFileMatching;
9841
9943
  const permissionHelpers = createPermissionHelpers(
@@ -9850,7 +9952,6 @@ var init_failure_condition_evaluator = __esm({
9850
9952
  const isFirstTimer2 = permissionHelpers.isFirstTimer;
9851
9953
  const output = context2.output || {};
9852
9954
  const issues = output.issues || [];
9853
- const suggestions = [];
9854
9955
  const metadata = context2.metadata || {
9855
9956
  checkName: context2.checkName || "",
9856
9957
  schema: context2.schema || "",
@@ -9894,7 +9995,6 @@ var init_failure_condition_evaluator = __esm({
9894
9995
  memory: memoryAccessor,
9895
9996
  // Legacy compatibility variables
9896
9997
  issues,
9897
- suggestions,
9898
9998
  metadata,
9899
9999
  criticalIssues,
9900
10000
  errorIssues,
@@ -9923,7 +10023,6 @@ var init_failure_condition_evaluator = __esm({
9923
10023
  hasIssue,
9924
10024
  countIssues,
9925
10025
  hasFileMatching,
9926
- hasSuggestion,
9927
10026
  hasIssueWith,
9928
10027
  hasFileWith,
9929
10028
  // Permission helpers
@@ -10193,6 +10292,7 @@ var GitHubCheckService;
10193
10292
  var init_github_check_service = __esm({
10194
10293
  "src/github-check-service.ts"() {
10195
10294
  "use strict";
10295
+ init_footer();
10196
10296
  GitHubCheckService = class {
10197
10297
  octokit;
10198
10298
  maxAnnotations = 50;
@@ -10433,11 +10533,7 @@ Please check your configuration and try again.`
10433
10533
  });
10434
10534
  }
10435
10535
  sections.push("");
10436
- sections.push("---");
10437
- sections.push("");
10438
- sections.push(
10439
- "*Powered by [Visor](https://probelabs.com/visor) from [Probelabs](https://probelabs.com)*"
10440
- );
10536
+ sections.push(generateFooter());
10441
10537
  return sections.join("\n");
10442
10538
  }
10443
10539
  /**
@@ -10655,12 +10751,12 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
10655
10751
  addEvent("diagram.block", { check: checkName, origin, code });
10656
10752
  addDiagramBlock(origin);
10657
10753
  if (process.env.VISOR_TRACE_REPORT === "true") {
10658
- const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
10754
+ const outDir = process.env.VISOR_TRACE_DIR || path10.join(process.cwd(), "output", "traces");
10659
10755
  try {
10660
10756
  if (!fs9.existsSync(outDir)) fs9.mkdirSync(outDir, { recursive: true });
10661
10757
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
10662
- const jsonPath = path9.join(outDir, `${ts}.trace.json`);
10663
- const htmlPath = path9.join(outDir, `${ts}.report.html`);
10758
+ const jsonPath = path10.join(outDir, `${ts}.trace.json`);
10759
+ const htmlPath = path10.join(outDir, `${ts}.report.html`);
10664
10760
  let data = { spans: [] };
10665
10761
  if (fs9.existsSync(jsonPath)) {
10666
10762
  try {
@@ -10690,14 +10786,14 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
10690
10786
  }
10691
10787
  return count;
10692
10788
  }
10693
- var fs9, path9, MERMAID_RE;
10789
+ var fs9, path10, MERMAID_RE;
10694
10790
  var init_mermaid_telemetry = __esm({
10695
10791
  "src/utils/mermaid-telemetry.ts"() {
10696
10792
  "use strict";
10697
10793
  init_trace_helpers();
10698
10794
  init_metrics2();
10699
10795
  fs9 = __toESM(require("fs"));
10700
- path9 = __toESM(require("path"));
10796
+ path10 = __toESM(require("path"));
10701
10797
  MERMAID_RE = /```mermaid\s*\n([\s\S]*?)\n```/gi;
10702
10798
  }
10703
10799
  });
@@ -12063,7 +12159,7 @@ ${expr}
12063
12159
  * - Enforcing .liquid file extension
12064
12160
  */
12065
12161
  async validateTemplatePath(templatePath) {
12066
- const path12 = await import("path");
12162
+ const path13 = await import("path");
12067
12163
  if (!templatePath || typeof templatePath !== "string" || templatePath.trim() === "") {
12068
12164
  throw new Error("Template path must be a non-empty string");
12069
12165
  }
@@ -12073,7 +12169,7 @@ ${expr}
12073
12169
  if (!templatePath.endsWith(".liquid")) {
12074
12170
  throw new Error("Template file must have .liquid extension");
12075
12171
  }
12076
- if (path12.isAbsolute(templatePath)) {
12172
+ if (path13.isAbsolute(templatePath)) {
12077
12173
  throw new Error("Template path must be relative to project directory");
12078
12174
  }
12079
12175
  if (templatePath.includes("..")) {
@@ -12087,14 +12183,14 @@ ${expr}
12087
12183
  if (!projectRoot || typeof projectRoot !== "string") {
12088
12184
  throw new Error("Unable to determine project root directory");
12089
12185
  }
12090
- const resolvedPath = path12.resolve(projectRoot, templatePath);
12091
- const resolvedProjectRoot = path12.resolve(projectRoot);
12186
+ const resolvedPath = path13.resolve(projectRoot, templatePath);
12187
+ const resolvedProjectRoot = path13.resolve(projectRoot);
12092
12188
  if (!resolvedPath || !resolvedProjectRoot || resolvedPath === "" || resolvedProjectRoot === "") {
12093
12189
  throw new Error(
12094
12190
  `Unable to resolve template path: projectRoot="${projectRoot}", templatePath="${templatePath}", resolvedPath="${resolvedPath}", resolvedProjectRoot="${resolvedProjectRoot}"`
12095
12191
  );
12096
12192
  }
12097
- if (!resolvedPath.startsWith(resolvedProjectRoot + path12.sep) && resolvedPath !== resolvedProjectRoot) {
12193
+ if (!resolvedPath.startsWith(resolvedProjectRoot + path13.sep) && resolvedPath !== resolvedProjectRoot) {
12098
12194
  throw new Error("Template path escapes project directory");
12099
12195
  }
12100
12196
  return resolvedPath;
@@ -12139,7 +12235,7 @@ ${expr}
12139
12235
  }
12140
12236
  const { createExtendedLiquid: createExtendedLiquid2 } = await Promise.resolve().then(() => (init_liquid_extensions(), liquid_extensions_exports));
12141
12237
  const fs12 = await import("fs/promises");
12142
- const path12 = await import("path");
12238
+ const path13 = await import("path");
12143
12239
  const liquid = createExtendedLiquid2({
12144
12240
  trimTagLeft: false,
12145
12241
  trimTagRight: false,
@@ -12173,7 +12269,7 @@ ${expr}
12173
12269
  if (!sanitizedSchema) {
12174
12270
  throw new Error("Invalid schema name");
12175
12271
  }
12176
- const templatePath = path12.join(__dirname, `../output/${sanitizedSchema}/template.liquid`);
12272
+ const templatePath = path13.join(__dirname, `../output/${sanitizedSchema}/template.liquid`);
12177
12273
  templateContent = await fs12.readFile(templatePath, "utf-8");
12178
12274
  if (sanitizedSchema === "issue-assistant") {
12179
12275
  enrichAssistantContext = true;
@@ -16342,13 +16438,13 @@ init_check_execution_engine();
16342
16438
  // src/config.ts
16343
16439
  var yaml2 = __toESM(require("js-yaml"));
16344
16440
  var fs11 = __toESM(require("fs"));
16345
- var path11 = __toESM(require("path"));
16441
+ var path12 = __toESM(require("path"));
16346
16442
  init_logger();
16347
16443
  var import_simple_git2 = __toESM(require("simple-git"));
16348
16444
 
16349
16445
  // src/utils/config-loader.ts
16350
16446
  var fs10 = __toESM(require("fs"));
16351
- var path10 = __toESM(require("path"));
16447
+ var path11 = __toESM(require("path"));
16352
16448
  var yaml = __toESM(require("js-yaml"));
16353
16449
  var ConfigLoader = class {
16354
16450
  constructor(options = {}) {
@@ -16429,7 +16525,7 @@ var ConfigLoader = class {
16429
16525
  return source.toLowerCase();
16430
16526
  case "local" /* LOCAL */:
16431
16527
  const basePath = this.options.baseDir || process.cwd();
16432
- return path10.resolve(basePath, source);
16528
+ return path11.resolve(basePath, source);
16433
16529
  default:
16434
16530
  return source;
16435
16531
  }
@@ -16439,7 +16535,7 @@ var ConfigLoader = class {
16439
16535
  */
16440
16536
  async fetchLocalConfig(filePath) {
16441
16537
  const basePath = this.options.baseDir || process.cwd();
16442
- const resolvedPath = path10.resolve(basePath, filePath);
16538
+ const resolvedPath = path11.resolve(basePath, filePath);
16443
16539
  this.validateLocalPath(resolvedPath);
16444
16540
  if (!fs10.existsSync(resolvedPath)) {
16445
16541
  throw new Error(`Configuration file not found: ${resolvedPath}`);
@@ -16451,7 +16547,7 @@ var ConfigLoader = class {
16451
16547
  throw new Error(`Invalid YAML in configuration file: ${resolvedPath}`);
16452
16548
  }
16453
16549
  const previousBaseDir = this.options.baseDir;
16454
- this.options.baseDir = path10.dirname(resolvedPath);
16550
+ this.options.baseDir = path11.dirname(resolvedPath);
16455
16551
  try {
16456
16552
  if (config.extends) {
16457
16553
  const processedConfig = await this.processExtends(config);
@@ -16531,14 +16627,14 @@ var ConfigLoader = class {
16531
16627
  async fetchDefaultConfig() {
16532
16628
  const possiblePaths = [
16533
16629
  // When running as GitHub Action (bundled in dist/)
16534
- path10.join(__dirname, "defaults", ".visor.yaml"),
16630
+ path11.join(__dirname, "defaults", ".visor.yaml"),
16535
16631
  // When running from source
16536
- path10.join(__dirname, "..", "..", "defaults", ".visor.yaml"),
16632
+ path11.join(__dirname, "..", "..", "defaults", ".visor.yaml"),
16537
16633
  // Try via package root
16538
- this.findPackageRoot() ? path10.join(this.findPackageRoot(), "defaults", ".visor.yaml") : "",
16634
+ this.findPackageRoot() ? path11.join(this.findPackageRoot(), "defaults", ".visor.yaml") : "",
16539
16635
  // GitHub Action environment variable
16540
- process.env.GITHUB_ACTION_PATH ? path10.join(process.env.GITHUB_ACTION_PATH, "defaults", ".visor.yaml") : "",
16541
- process.env.GITHUB_ACTION_PATH ? path10.join(process.env.GITHUB_ACTION_PATH, "dist", "defaults", ".visor.yaml") : ""
16636
+ process.env.GITHUB_ACTION_PATH ? path11.join(process.env.GITHUB_ACTION_PATH, "defaults", ".visor.yaml") : "",
16637
+ process.env.GITHUB_ACTION_PATH ? path11.join(process.env.GITHUB_ACTION_PATH, "dist", "defaults", ".visor.yaml") : ""
16542
16638
  ].filter((p) => p);
16543
16639
  let defaultConfigPath;
16544
16640
  for (const possiblePath of possiblePaths) {
@@ -16628,8 +16724,8 @@ var ConfigLoader = class {
16628
16724
  */
16629
16725
  validateLocalPath(resolvedPath) {
16630
16726
  const projectRoot = this.options.projectRoot || process.cwd();
16631
- const normalizedPath = path10.normalize(resolvedPath);
16632
- const normalizedRoot = path10.normalize(projectRoot);
16727
+ const normalizedPath = path11.normalize(resolvedPath);
16728
+ const normalizedRoot = path11.normalize(projectRoot);
16633
16729
  if (!normalizedPath.startsWith(normalizedRoot)) {
16634
16730
  throw new Error(
16635
16731
  `Security error: Path traversal detected. Cannot access files outside project root: ${projectRoot}`
@@ -16655,9 +16751,9 @@ var ConfigLoader = class {
16655
16751
  */
16656
16752
  findPackageRoot() {
16657
16753
  let currentDir = __dirname;
16658
- const root = path10.parse(currentDir).root;
16754
+ const root = path11.parse(currentDir).root;
16659
16755
  while (currentDir !== root) {
16660
- const packageJsonPath = path10.join(currentDir, "package.json");
16756
+ const packageJsonPath = path11.join(currentDir, "package.json");
16661
16757
  if (fs10.existsSync(packageJsonPath)) {
16662
16758
  try {
16663
16759
  const packageJson = JSON.parse(fs10.readFileSync(packageJsonPath, "utf8"));
@@ -16667,7 +16763,7 @@ var ConfigLoader = class {
16667
16763
  } catch {
16668
16764
  }
16669
16765
  }
16670
- currentDir = path10.dirname(currentDir);
16766
+ currentDir = path11.dirname(currentDir);
16671
16767
  }
16672
16768
  return null;
16673
16769
  }
@@ -16690,6 +16786,16 @@ var ConfigLoader = class {
16690
16786
  init_config_merger();
16691
16787
  var import_ajv = __toESM(require("ajv"));
16692
16788
  var import_ajv_formats = __toESM(require("ajv-formats"));
16789
+ var VALID_EVENT_TRIGGERS = [
16790
+ "pr_opened",
16791
+ "pr_updated",
16792
+ "pr_closed",
16793
+ "issue_opened",
16794
+ "issue_comment",
16795
+ "manual",
16796
+ "schedule",
16797
+ "webhook_received"
16798
+ ];
16693
16799
  var ConfigManager = class {
16694
16800
  validCheckTypes = [
16695
16801
  "ai",
@@ -16698,20 +16804,13 @@ var ConfigManager = class {
16698
16804
  "http",
16699
16805
  "http_input",
16700
16806
  "http_client",
16807
+ "memory",
16701
16808
  "noop",
16702
16809
  "log",
16810
+ "memory",
16703
16811
  "github"
16704
16812
  ];
16705
- validEventTriggers = [
16706
- "pr_opened",
16707
- "pr_updated",
16708
- "pr_closed",
16709
- "issue_opened",
16710
- "issue_comment",
16711
- "manual",
16712
- "schedule",
16713
- "webhook_received"
16714
- ];
16813
+ validEventTriggers = [...VALID_EVENT_TRIGGERS];
16715
16814
  validOutputFormats = ["table", "json", "markdown", "sarif"];
16716
16815
  validGroupByOptions = ["check", "file", "severity", "group"];
16717
16816
  /**
@@ -16719,24 +16818,25 @@ var ConfigManager = class {
16719
16818
  */
16720
16819
  async loadConfig(configPath, options = {}) {
16721
16820
  const { validate = true, mergeDefaults = true, allowedRemotePatterns } = options;
16821
+ const resolvedPath = path12.isAbsolute(configPath) ? configPath : path12.resolve(process.cwd(), configPath);
16722
16822
  try {
16723
- if (!fs11.existsSync(configPath)) {
16724
- throw new Error(`Configuration file not found: ${configPath}`);
16823
+ if (!fs11.existsSync(resolvedPath)) {
16824
+ throw new Error(`Configuration file not found: ${resolvedPath}`);
16725
16825
  }
16726
- const configContent = fs11.readFileSync(configPath, "utf8");
16826
+ const configContent = fs11.readFileSync(resolvedPath, "utf8");
16727
16827
  let parsedConfig;
16728
16828
  try {
16729
16829
  parsedConfig = yaml2.load(configContent);
16730
16830
  } catch (yamlError) {
16731
16831
  const errorMessage = yamlError instanceof Error ? yamlError.message : String(yamlError);
16732
- throw new Error(`Invalid YAML syntax in ${configPath}: ${errorMessage}`);
16832
+ throw new Error(`Invalid YAML syntax in ${resolvedPath}: ${errorMessage}`);
16733
16833
  }
16734
16834
  if (!parsedConfig || typeof parsedConfig !== "object") {
16735
16835
  throw new Error("Configuration file must contain a valid YAML object");
16736
16836
  }
16737
16837
  if (parsedConfig.extends) {
16738
16838
  const loaderOptions = {
16739
- baseDir: path11.dirname(configPath),
16839
+ baseDir: path12.dirname(resolvedPath),
16740
16840
  allowRemote: this.isRemoteExtendsAllowed(),
16741
16841
  maxDepth: 10,
16742
16842
  allowedRemotePatterns
@@ -16768,12 +16868,12 @@ var ConfigManager = class {
16768
16868
  throw error;
16769
16869
  }
16770
16870
  if (error.message.includes("ENOENT")) {
16771
- throw new Error(`Configuration file not found: ${configPath}`);
16871
+ throw new Error(`Configuration file not found: ${resolvedPath}`);
16772
16872
  }
16773
16873
  if (error.message.includes("EPERM")) {
16774
- throw new Error(`Permission denied reading configuration file: ${configPath}`);
16874
+ throw new Error(`Permission denied reading configuration file: ${resolvedPath}`);
16775
16875
  }
16776
- throw new Error(`Failed to read configuration file ${configPath}: ${error.message}`);
16876
+ throw new Error(`Failed to read configuration file ${resolvedPath}: ${error.message}`);
16777
16877
  }
16778
16878
  throw error;
16779
16879
  }
@@ -16785,7 +16885,7 @@ var ConfigManager = class {
16785
16885
  const gitRoot = await this.findGitRepositoryRoot();
16786
16886
  const searchDirs = [gitRoot, process.cwd()].filter(Boolean);
16787
16887
  for (const baseDir of searchDirs) {
16788
- const possiblePaths = [path11.join(baseDir, ".visor.yaml"), path11.join(baseDir, ".visor.yml")];
16888
+ const possiblePaths = [path12.join(baseDir, ".visor.yaml"), path12.join(baseDir, ".visor.yml")];
16789
16889
  for (const configPath of possiblePaths) {
16790
16890
  if (fs11.existsSync(configPath)) {
16791
16891
  return this.loadConfig(configPath, options);
@@ -16839,18 +16939,18 @@ var ConfigManager = class {
16839
16939
  const possiblePaths = [];
16840
16940
  if (typeof __dirname !== "undefined") {
16841
16941
  possiblePaths.push(
16842
- path11.join(__dirname, "defaults", ".visor.yaml"),
16843
- path11.join(__dirname, "..", "defaults", ".visor.yaml")
16942
+ path12.join(__dirname, "defaults", ".visor.yaml"),
16943
+ path12.join(__dirname, "..", "defaults", ".visor.yaml")
16844
16944
  );
16845
16945
  }
16846
16946
  const pkgRoot = this.findPackageRoot();
16847
16947
  if (pkgRoot) {
16848
- possiblePaths.push(path11.join(pkgRoot, "defaults", ".visor.yaml"));
16948
+ possiblePaths.push(path12.join(pkgRoot, "defaults", ".visor.yaml"));
16849
16949
  }
16850
16950
  if (process.env.GITHUB_ACTION_PATH) {
16851
16951
  possiblePaths.push(
16852
- path11.join(process.env.GITHUB_ACTION_PATH, "defaults", ".visor.yaml"),
16853
- path11.join(process.env.GITHUB_ACTION_PATH, "dist", "defaults", ".visor.yaml")
16952
+ path12.join(process.env.GITHUB_ACTION_PATH, "defaults", ".visor.yaml"),
16953
+ path12.join(process.env.GITHUB_ACTION_PATH, "dist", "defaults", ".visor.yaml")
16854
16954
  );
16855
16955
  }
16856
16956
  let bundledConfigPath;
@@ -16883,8 +16983,8 @@ var ConfigManager = class {
16883
16983
  */
16884
16984
  findPackageRoot() {
16885
16985
  let currentDir = __dirname;
16886
- while (currentDir !== path11.dirname(currentDir)) {
16887
- const packageJsonPath = path11.join(currentDir, "package.json");
16986
+ while (currentDir !== path12.dirname(currentDir)) {
16987
+ const packageJsonPath = path12.join(currentDir, "package.json");
16888
16988
  if (fs11.existsSync(packageJsonPath)) {
16889
16989
  try {
16890
16990
  const packageJson = JSON.parse(fs11.readFileSync(packageJsonPath, "utf8"));
@@ -16894,7 +16994,7 @@ var ConfigManager = class {
16894
16994
  } catch {
16895
16995
  }
16896
16996
  }
16897
- currentDir = path11.dirname(currentDir);
16997
+ currentDir = path12.dirname(currentDir);
16898
16998
  }
16899
16999
  return null;
16900
17000
  }
@@ -17279,7 +17379,7 @@ var ConfigManager = class {
17279
17379
  try {
17280
17380
  if (!__ajvValidate) {
17281
17381
  try {
17282
- const jsonPath = path11.resolve(__dirname, "generated", "config-schema.json");
17382
+ const jsonPath = path12.resolve(__dirname, "generated", "config-schema.json");
17283
17383
  const jsonSchema = require(jsonPath);
17284
17384
  if (jsonSchema) {
17285
17385
  const ajv = new import_ajv.default({ allErrors: true, allowUnionTypes: true, strict: false });