@probelabs/visor 0.1.97 → 0.1.100
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 +16 -15
- package/action.yml +7 -2
- package/defaults/.visor.yaml +7 -6
- package/dist/action-cli-bridge.d.ts +1 -0
- package/dist/action-cli-bridge.d.ts.map +1 -1
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/check-execution-engine.d.ts +8 -2
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/debug-visualizer/debug-span-exporter.d.ts +47 -0
- package/dist/debug-visualizer/debug-span-exporter.d.ts.map +1 -0
- package/dist/debug-visualizer/trace-reader.d.ts +117 -0
- package/dist/debug-visualizer/trace-reader.d.ts.map +1 -0
- package/dist/debug-visualizer/ui/index.html +2568 -0
- package/dist/debug-visualizer/ws-server.d.ts +99 -0
- package/dist/debug-visualizer/ws-server.d.ts.map +1 -0
- package/dist/defaults/.visor.yaml +7 -6
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +7 -3
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +7 -3
- package/dist/git-repository-analyzer.d.ts +1 -7
- package/dist/git-repository-analyzer.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17668 -1760
- package/dist/liquid-extensions.d.ts +1 -1
- package/dist/liquid-extensions.d.ts.map +1 -1
- package/dist/output/code-review/schema.json +2 -2
- package/dist/output/traces/run-2025-10-22T10-40-34-055Z.ndjson +218 -0
- package/dist/pr-analyzer.d.ts +2 -1
- package/dist/pr-analyzer.d.ts.map +1 -1
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/check-provider-registry.d.ts.map +1 -1
- package/dist/providers/check-provider.interface.d.ts +17 -6
- package/dist/providers/check-provider.interface.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/providers/github-ops-provider.d.ts.map +1 -1
- package/dist/providers/http-check-provider.d.ts.map +1 -1
- package/dist/providers/human-input-check-provider.d.ts +78 -0
- package/dist/providers/human-input-check-provider.d.ts.map +1 -0
- package/dist/providers/index.d.ts +2 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/mcp-check-provider.d.ts.map +1 -1
- package/dist/providers/memory-check-provider.d.ts.map +1 -1
- package/dist/sdk/check-execution-engine-F3662LY7.mjs +11 -0
- package/dist/sdk/{chunk-I3GQJIR7.mjs → chunk-B5QBV2QJ.mjs} +2 -2
- package/dist/sdk/chunk-B5QBV2QJ.mjs.map +1 -0
- package/dist/sdk/{chunk-IG3BFIIN.mjs → chunk-FVS5CJ5S.mjs} +30 -1
- package/dist/sdk/chunk-FVS5CJ5S.mjs.map +1 -0
- package/dist/sdk/{chunk-YXOWIDEF.mjs → chunk-TUTOLSFV.mjs} +15 -3
- package/dist/sdk/chunk-TUTOLSFV.mjs.map +1 -0
- package/dist/sdk/{chunk-4VK6WTYU.mjs → chunk-X2JKUOE5.mjs} +1375 -570
- package/dist/sdk/chunk-X2JKUOE5.mjs.map +1 -0
- package/dist/sdk/{liquid-extensions-GMEGEGC3.mjs → liquid-extensions-KVL4MKRH.mjs} +2 -2
- package/dist/sdk/{mermaid-telemetry-4DUEYCLE.mjs → mermaid-telemetry-FBF6D35S.mjs} +2 -2
- package/dist/sdk/sdk.d.mts +62 -4
- package/dist/sdk/sdk.d.ts +62 -4
- package/dist/sdk/sdk.js +1658 -723
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +60 -15
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/sdk/{tracer-init-RJGAIOBP.mjs → tracer-init-WC75N5NW.mjs} +2 -2
- package/dist/sdk.d.ts +5 -2
- package/dist/sdk.d.ts.map +1 -1
- package/dist/telemetry/file-span-exporter.d.ts.map +1 -1
- package/dist/telemetry/opentelemetry.d.ts +2 -0
- package/dist/telemetry/opentelemetry.d.ts.map +1 -1
- package/dist/telemetry/state-capture.d.ts +53 -0
- package/dist/telemetry/state-capture.d.ts.map +1 -0
- package/dist/telemetry/trace-helpers.d.ts.map +1 -1
- package/dist/traces/run-2025-10-22T10-40-34-055Z.ndjson +218 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/cli.d.ts.map +1 -1
- package/dist/types/config.d.ts +44 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/config-loader.d.ts +5 -0
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/file-exclusion.d.ts +50 -0
- package/dist/utils/file-exclusion.d.ts.map +1 -0
- package/dist/utils/interactive-prompt.d.ts +26 -0
- package/dist/utils/interactive-prompt.d.ts.map +1 -0
- package/dist/utils/sandbox.d.ts +26 -0
- package/dist/utils/sandbox.d.ts.map +1 -0
- package/dist/utils/stdin-reader.d.ts +22 -0
- package/dist/utils/stdin-reader.d.ts.map +1 -0
- package/dist/utils/tracer-init.d.ts +0 -5
- package/dist/utils/tracer-init.d.ts.map +1 -1
- package/package.json +8 -4
- package/dist/output/traces/run-2025-10-19T14-24-36-341Z.ndjson +0 -40
- package/dist/output/traces/run-2025-10-19T14-24-48-674Z.ndjson +0 -40
- package/dist/output/traces/run-2025-10-19T14-24-49-238Z.ndjson +0 -40
- package/dist/output/traces/run-2025-10-19T14-24-49-761Z.ndjson +0 -40
- package/dist/output/traces/run-2025-10-19T14-24-50-279Z.ndjson +0 -12
- package/dist/sdk/check-execution-engine-S7BFPVWA.mjs +0 -11
- package/dist/sdk/chunk-4VK6WTYU.mjs.map +0 -1
- package/dist/sdk/chunk-I3GQJIR7.mjs.map +0 -1
- package/dist/sdk/chunk-IG3BFIIN.mjs.map +0 -1
- package/dist/sdk/chunk-YXOWIDEF.mjs.map +0 -1
- package/dist/traces/run-2025-10-19T14-24-36-341Z.ndjson +0 -40
- package/dist/traces/run-2025-10-19T14-24-48-674Z.ndjson +0 -40
- package/dist/traces/run-2025-10-19T14-24-49-238Z.ndjson +0 -40
- package/dist/traces/run-2025-10-19T14-24-49-761Z.ndjson +0 -40
- package/dist/traces/run-2025-10-19T14-24-50-279Z.ndjson +0 -12
- /package/dist/sdk/{check-execution-engine-S7BFPVWA.mjs.map → check-execution-engine-F3662LY7.mjs.map} +0 -0
- /package/dist/sdk/{liquid-extensions-GMEGEGC3.mjs.map → liquid-extensions-KVL4MKRH.mjs.map} +0 -0
- /package/dist/sdk/{mermaid-telemetry-4DUEYCLE.mjs.map → mermaid-telemetry-FBF6D35S.mjs.map} +0 -0
- /package/dist/sdk/{tracer-init-RJGAIOBP.mjs.map → tracer-init-WC75N5NW.mjs.map} +0 -0
package/dist/sdk/sdk.js
CHANGED
|
@@ -406,7 +406,7 @@ ${content}
|
|
|
406
406
|
* Sleep utility
|
|
407
407
|
*/
|
|
408
408
|
sleep(ms) {
|
|
409
|
-
return new Promise((
|
|
409
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
410
410
|
}
|
|
411
411
|
/**
|
|
412
412
|
* Group results by specified criteria
|
|
@@ -468,7 +468,19 @@ __export(tracer_init_exports, {
|
|
|
468
468
|
});
|
|
469
469
|
async function initializeTracer(sessionId, checkName) {
|
|
470
470
|
try {
|
|
471
|
-
|
|
471
|
+
let ProbeLib;
|
|
472
|
+
try {
|
|
473
|
+
ProbeLib = await import("@probelabs/probe");
|
|
474
|
+
} catch {
|
|
475
|
+
try {
|
|
476
|
+
ProbeLib = require("@probelabs/probe");
|
|
477
|
+
} catch {
|
|
478
|
+
ProbeLib = {};
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const SimpleTelemetry = ProbeLib?.SimpleTelemetry;
|
|
482
|
+
const SimpleAppTracer = ProbeLib?.SimpleAppTracer;
|
|
483
|
+
if (SimpleTelemetry && SimpleAppTracer) {
|
|
472
484
|
const sanitizedCheckName = checkName ? path.basename(checkName) : "check";
|
|
473
485
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
474
486
|
const traceDir = process.env.GITHUB_WORKSPACE ? path.join(process.env.GITHUB_WORKSPACE, "debug-artifacts") : path.join(process.cwd(), "debug-artifacts");
|
|
@@ -484,12 +496,12 @@ async function initializeTracer(sessionId, checkName) {
|
|
|
484
496
|
);
|
|
485
497
|
return null;
|
|
486
498
|
}
|
|
487
|
-
const telemetry = new
|
|
499
|
+
const telemetry = new SimpleTelemetry({
|
|
488
500
|
enableFile: true,
|
|
489
501
|
filePath: traceFilePath,
|
|
490
502
|
enableConsole: false
|
|
491
503
|
});
|
|
492
|
-
const tracer = new
|
|
504
|
+
const tracer = new SimpleAppTracer(telemetry, sessionId);
|
|
493
505
|
console.error(`\u{1F4CA} Simple tracing enabled, will save to: ${traceFilePath}`);
|
|
494
506
|
if (process.env.GITHUB_ACTIONS) {
|
|
495
507
|
console.log(`::notice title=AI Trace::Trace will be saved to ${traceFilePath}`);
|
|
@@ -508,13 +520,12 @@ async function initializeTracer(sessionId, checkName) {
|
|
|
508
520
|
return null;
|
|
509
521
|
}
|
|
510
522
|
}
|
|
511
|
-
var path, fs
|
|
523
|
+
var path, fs;
|
|
512
524
|
var init_tracer_init = __esm({
|
|
513
525
|
"src/utils/tracer-init.ts"() {
|
|
514
526
|
"use strict";
|
|
515
527
|
path = __toESM(require("path"));
|
|
516
528
|
fs = __toESM(require("fs"));
|
|
517
|
-
import_probe = require("@probelabs/probe");
|
|
518
529
|
}
|
|
519
530
|
});
|
|
520
531
|
|
|
@@ -712,7 +723,7 @@ async function processDiffWithOutline(diffContent) {
|
|
|
712
723
|
}
|
|
713
724
|
try {
|
|
714
725
|
const originalProbePath = process.env.PROBE_PATH;
|
|
715
|
-
const
|
|
726
|
+
const fs14 = require("fs");
|
|
716
727
|
const possiblePaths = [
|
|
717
728
|
// Relative to current working directory (most common in production)
|
|
718
729
|
path2.join(process.cwd(), "node_modules/@probelabs/probe/bin/probe-binary"),
|
|
@@ -723,7 +734,7 @@ async function processDiffWithOutline(diffContent) {
|
|
|
723
734
|
];
|
|
724
735
|
let probeBinaryPath;
|
|
725
736
|
for (const candidatePath of possiblePaths) {
|
|
726
|
-
if (
|
|
737
|
+
if (fs14.existsSync(candidatePath)) {
|
|
727
738
|
probeBinaryPath = candidatePath;
|
|
728
739
|
break;
|
|
729
740
|
}
|
|
@@ -735,7 +746,7 @@ async function processDiffWithOutline(diffContent) {
|
|
|
735
746
|
return diffContent;
|
|
736
747
|
}
|
|
737
748
|
process.env.PROBE_PATH = probeBinaryPath;
|
|
738
|
-
const extractPromise = (0,
|
|
749
|
+
const extractPromise = (0, import_probe.extract)({
|
|
739
750
|
content: diffContent,
|
|
740
751
|
format: "outline-diff",
|
|
741
752
|
allowTests: true
|
|
@@ -758,11 +769,11 @@ async function processDiffWithOutline(diffContent) {
|
|
|
758
769
|
return diffContent;
|
|
759
770
|
}
|
|
760
771
|
}
|
|
761
|
-
var
|
|
772
|
+
var import_probe, path2;
|
|
762
773
|
var init_diff_processor = __esm({
|
|
763
774
|
"src/utils/diff-processor.ts"() {
|
|
764
775
|
"use strict";
|
|
765
|
-
|
|
776
|
+
import_probe = require("@probelabs/probe");
|
|
766
777
|
path2 = __toESM(require("path"));
|
|
767
778
|
}
|
|
768
779
|
});
|
|
@@ -771,11 +782,11 @@ var init_diff_processor = __esm({
|
|
|
771
782
|
function log(...args) {
|
|
772
783
|
logger.debug(args.join(" "));
|
|
773
784
|
}
|
|
774
|
-
var
|
|
785
|
+
var import_probe2, AIReviewService;
|
|
775
786
|
var init_ai_review_service = __esm({
|
|
776
787
|
"src/ai-review-service.ts"() {
|
|
777
788
|
"use strict";
|
|
778
|
-
|
|
789
|
+
import_probe2 = require("@probelabs/probe");
|
|
779
790
|
init_session_registry();
|
|
780
791
|
init_logger();
|
|
781
792
|
init_tracer_init();
|
|
@@ -815,6 +826,7 @@ var init_ai_review_service = __esm({
|
|
|
815
826
|
this.config.model = process.env.MODEL_NAME;
|
|
816
827
|
}
|
|
817
828
|
}
|
|
829
|
+
// NOTE: per request, no additional redaction/encryption helpers are used.
|
|
818
830
|
/**
|
|
819
831
|
* Execute AI review using probe agent
|
|
820
832
|
*/
|
|
@@ -1131,14 +1143,12 @@ ${prContext}
|
|
|
1131
1143
|
const isIssue = prContextInfo.isIssue === true;
|
|
1132
1144
|
const isPRContext = prContextInfo.isPRContext === true;
|
|
1133
1145
|
const includeCodeContext = isPRContext || prContextInfo.includeCodeContext !== false;
|
|
1134
|
-
const log2 = this.config.debug ? console.error : () => {
|
|
1135
|
-
};
|
|
1136
1146
|
if (isPRContext) {
|
|
1137
|
-
|
|
1147
|
+
log("\u{1F50D} Including full code diffs in AI context (PR mode)");
|
|
1138
1148
|
} else if (!includeCodeContext) {
|
|
1139
|
-
|
|
1149
|
+
log("\u{1F4CA} Including only file summary in AI context (no diffs)");
|
|
1140
1150
|
} else {
|
|
1141
|
-
|
|
1151
|
+
log("\u{1F50D} Including code diffs in AI context");
|
|
1142
1152
|
}
|
|
1143
1153
|
if (isIssue) {
|
|
1144
1154
|
let context2 = `<issue>
|
|
@@ -1386,8 +1396,8 @@ ${schemaString}`);
|
|
|
1386
1396
|
}
|
|
1387
1397
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1388
1398
|
try {
|
|
1389
|
-
const
|
|
1390
|
-
const
|
|
1399
|
+
const fs14 = require("fs");
|
|
1400
|
+
const path16 = require("path");
|
|
1391
1401
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1392
1402
|
const provider = this.config.provider || "auto";
|
|
1393
1403
|
const model = this.config.model || "default";
|
|
@@ -1501,20 +1511,20 @@ ${"=".repeat(60)}
|
|
|
1501
1511
|
`;
|
|
1502
1512
|
readableVersion += `${"=".repeat(60)}
|
|
1503
1513
|
`;
|
|
1504
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1505
|
-
if (!
|
|
1506
|
-
|
|
1514
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path16.join(process.cwd(), "debug-artifacts");
|
|
1515
|
+
if (!fs14.existsSync(debugArtifactsDir)) {
|
|
1516
|
+
fs14.mkdirSync(debugArtifactsDir, { recursive: true });
|
|
1507
1517
|
}
|
|
1508
|
-
const debugFile =
|
|
1518
|
+
const debugFile = path16.join(
|
|
1509
1519
|
debugArtifactsDir,
|
|
1510
1520
|
`prompt-${_checkName || "unknown"}-${timestamp}.json`
|
|
1511
1521
|
);
|
|
1512
|
-
|
|
1513
|
-
const readableFile =
|
|
1522
|
+
fs14.writeFileSync(debugFile, debugJson, "utf-8");
|
|
1523
|
+
const readableFile = path16.join(
|
|
1514
1524
|
debugArtifactsDir,
|
|
1515
1525
|
`prompt-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1516
1526
|
);
|
|
1517
|
-
|
|
1527
|
+
fs14.writeFileSync(readableFile, readableVersion, "utf-8");
|
|
1518
1528
|
log(`
|
|
1519
1529
|
\u{1F4BE} Full debug info saved to:`);
|
|
1520
1530
|
log(` JSON: ${debugFile}`);
|
|
@@ -1546,8 +1556,8 @@ ${"=".repeat(60)}
|
|
|
1546
1556
|
log(`\u{1F4E4} Response length: ${response.length} characters`);
|
|
1547
1557
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1548
1558
|
try {
|
|
1549
|
-
const
|
|
1550
|
-
const
|
|
1559
|
+
const fs14 = require("fs");
|
|
1560
|
+
const path16 = require("path");
|
|
1551
1561
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1552
1562
|
const agentAny2 = agent;
|
|
1553
1563
|
let fullHistory = [];
|
|
@@ -1558,10 +1568,10 @@ ${"=".repeat(60)}
|
|
|
1558
1568
|
} else if (agentAny2._messages) {
|
|
1559
1569
|
fullHistory = agentAny2._messages;
|
|
1560
1570
|
}
|
|
1561
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1562
|
-
const
|
|
1571
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path16.join(process.cwd(), "debug-artifacts");
|
|
1572
|
+
const sessionBase = path16.join(
|
|
1563
1573
|
debugArtifactsDir,
|
|
1564
|
-
`session-${_checkName || "unknown"}-${timestamp}
|
|
1574
|
+
`session-${_checkName || "unknown"}-${timestamp}`
|
|
1565
1575
|
);
|
|
1566
1576
|
const sessionData = {
|
|
1567
1577
|
timestamp,
|
|
@@ -1569,15 +1579,9 @@ ${"=".repeat(60)}
|
|
|
1569
1579
|
provider: this.config.provider || "auto",
|
|
1570
1580
|
model: this.config.model || "default",
|
|
1571
1581
|
schema: effectiveSchema,
|
|
1572
|
-
|
|
1573
|
-
totalMessages: fullHistory.length,
|
|
1574
|
-
latestResponse: response
|
|
1582
|
+
totalMessages: fullHistory.length
|
|
1575
1583
|
};
|
|
1576
|
-
|
|
1577
|
-
const sessionTxtFile = path13.join(
|
|
1578
|
-
debugArtifactsDir,
|
|
1579
|
-
`session-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1580
|
-
);
|
|
1584
|
+
fs14.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
|
|
1581
1585
|
let readable = `=============================================================
|
|
1582
1586
|
`;
|
|
1583
1587
|
readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
|
|
@@ -1594,22 +1598,18 @@ ${"=".repeat(60)}
|
|
|
1594
1598
|
|
|
1595
1599
|
`;
|
|
1596
1600
|
fullHistory.forEach((msg, idx) => {
|
|
1601
|
+
const role = msg.role || "unknown";
|
|
1602
|
+
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content, null, 2);
|
|
1597
1603
|
readable += `
|
|
1598
1604
|
${"=".repeat(60)}
|
|
1605
|
+
MESSAGE ${idx + 1}/${fullHistory.length}
|
|
1606
|
+
Role: ${role}
|
|
1607
|
+
${"=".repeat(60)}
|
|
1599
1608
|
`;
|
|
1600
|
-
readable += `MESSAGE ${idx + 1}/${fullHistory.length}
|
|
1601
|
-
`;
|
|
1602
|
-
readable += `Role: ${msg.role || "unknown"}
|
|
1603
|
-
`;
|
|
1604
|
-
readable += `${"=".repeat(60)}
|
|
1605
|
-
`;
|
|
1606
|
-
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content, null, 2);
|
|
1607
1609
|
readable += content + "\n";
|
|
1608
1610
|
});
|
|
1609
|
-
|
|
1611
|
+
fs14.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
|
|
1610
1612
|
log(`\u{1F4BE} Complete session history saved:`);
|
|
1611
|
-
log(` JSON: ${sessionFile}`);
|
|
1612
|
-
log(` TXT: ${sessionTxtFile}`);
|
|
1613
1613
|
log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
|
|
1614
1614
|
} catch (error) {
|
|
1615
1615
|
log(`\u26A0\uFE0F Could not save complete session history: ${error}`);
|
|
@@ -1617,11 +1617,11 @@ ${"=".repeat(60)}
|
|
|
1617
1617
|
}
|
|
1618
1618
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1619
1619
|
try {
|
|
1620
|
-
const
|
|
1621
|
-
const
|
|
1620
|
+
const fs14 = require("fs");
|
|
1621
|
+
const path16 = require("path");
|
|
1622
1622
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1623
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1624
|
-
const responseFile =
|
|
1623
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path16.join(process.cwd(), "debug-artifacts");
|
|
1624
|
+
const responseFile = path16.join(
|
|
1625
1625
|
debugArtifactsDir,
|
|
1626
1626
|
`response-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1627
1627
|
);
|
|
@@ -1654,7 +1654,7 @@ ${"=".repeat(60)}
|
|
|
1654
1654
|
`;
|
|
1655
1655
|
responseContent += `${"=".repeat(60)}
|
|
1656
1656
|
`;
|
|
1657
|
-
|
|
1657
|
+
fs14.writeFileSync(responseFile, responseContent, "utf-8");
|
|
1658
1658
|
log(`\u{1F4BE} Response saved to: ${responseFile}`);
|
|
1659
1659
|
} catch (error) {
|
|
1660
1660
|
log(`\u26A0\uFE0F Could not save response file: ${error}`);
|
|
@@ -1670,9 +1670,9 @@ ${"=".repeat(60)}
|
|
|
1670
1670
|
await agentAny._telemetryConfig.shutdown();
|
|
1671
1671
|
log(`\u{1F4CA} OpenTelemetry trace saved to: ${agentAny._traceFilePath}`);
|
|
1672
1672
|
if (process.env.GITHUB_ACTIONS) {
|
|
1673
|
-
const
|
|
1674
|
-
if (
|
|
1675
|
-
const stats =
|
|
1673
|
+
const fs14 = require("fs");
|
|
1674
|
+
if (fs14.existsSync(agentAny._traceFilePath)) {
|
|
1675
|
+
const stats = fs14.statSync(agentAny._traceFilePath);
|
|
1676
1676
|
console.log(
|
|
1677
1677
|
`::notice title=AI Trace Saved::${agentAny._traceFilePath} (${stats.size} bytes)`
|
|
1678
1678
|
);
|
|
@@ -1683,12 +1683,14 @@ ${"=".repeat(60)}
|
|
|
1683
1683
|
log(`\u{1F4CA} Trace saved to: ${agentAny._traceFilePath}`);
|
|
1684
1684
|
}
|
|
1685
1685
|
} catch (exportError) {
|
|
1686
|
-
|
|
1686
|
+
logger.warn(`\u26A0\uFE0F Warning: Failed to export trace for cloned session: ${exportError}`);
|
|
1687
1687
|
}
|
|
1688
1688
|
}
|
|
1689
1689
|
return { response, effectiveSchema };
|
|
1690
1690
|
} catch (error) {
|
|
1691
|
-
|
|
1691
|
+
logger.error(
|
|
1692
|
+
`\u274C ProbeAgent session reuse failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1693
|
+
);
|
|
1692
1694
|
throw new Error(
|
|
1693
1695
|
`ProbeAgent session reuse failed: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1694
1696
|
);
|
|
@@ -1759,7 +1761,7 @@ ${"=".repeat(60)}
|
|
|
1759
1761
|
if (this.config.model) {
|
|
1760
1762
|
options.model = this.config.model;
|
|
1761
1763
|
}
|
|
1762
|
-
const agent = new
|
|
1764
|
+
const agent = new import_probe2.ProbeAgent(options);
|
|
1763
1765
|
log("\u{1F680} Calling ProbeAgent...");
|
|
1764
1766
|
let schemaString = void 0;
|
|
1765
1767
|
let effectiveSchema = typeof schema === "object" ? "custom" : schema;
|
|
@@ -1792,8 +1794,8 @@ ${schemaString}`);
|
|
|
1792
1794
|
const model = this.config.model || "default";
|
|
1793
1795
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1794
1796
|
try {
|
|
1795
|
-
const
|
|
1796
|
-
const
|
|
1797
|
+
const fs14 = require("fs");
|
|
1798
|
+
const path16 = require("path");
|
|
1797
1799
|
const os = require("os");
|
|
1798
1800
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1799
1801
|
const debugData = {
|
|
@@ -1867,30 +1869,20 @@ ${"=".repeat(60)}
|
|
|
1867
1869
|
readableVersion += `${"=".repeat(60)}
|
|
1868
1870
|
`;
|
|
1869
1871
|
const tempDir = os.tmpdir();
|
|
1870
|
-
const promptFile =
|
|
1871
|
-
|
|
1872
|
+
const promptFile = path16.join(tempDir, `visor-prompt-${timestamp}.txt`);
|
|
1873
|
+
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
1872
1874
|
log(`
|
|
1873
1875
|
\u{1F4BE} Prompt saved to: ${promptFile}`);
|
|
1874
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1876
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path16.join(process.cwd(), "debug-artifacts");
|
|
1875
1877
|
try {
|
|
1876
|
-
|
|
1877
|
-
fs12.mkdirSync(debugArtifactsDir, { recursive: true });
|
|
1878
|
-
}
|
|
1879
|
-
const debugFile = path13.join(
|
|
1880
|
-
debugArtifactsDir,
|
|
1881
|
-
`prompt-${_checkName || "unknown"}-${timestamp}.json`
|
|
1882
|
-
);
|
|
1883
|
-
fs12.writeFileSync(debugFile, debugJson, "utf-8");
|
|
1884
|
-
const readableFile = path13.join(
|
|
1878
|
+
const base = path16.join(
|
|
1885
1879
|
debugArtifactsDir,
|
|
1886
|
-
`prompt-${_checkName || "unknown"}-${timestamp}
|
|
1880
|
+
`prompt-${_checkName || "unknown"}-${timestamp}`
|
|
1887
1881
|
);
|
|
1888
|
-
|
|
1882
|
+
fs14.writeFileSync(base + ".json", debugJson, "utf-8");
|
|
1883
|
+
fs14.writeFileSync(base + ".summary.txt", readableVersion, "utf-8");
|
|
1889
1884
|
log(`
|
|
1890
|
-
\u{1F4BE} Full debug info saved to
|
|
1891
|
-
log(` JSON: ${debugFile}`);
|
|
1892
|
-
log(` TXT: ${readableFile}`);
|
|
1893
|
-
log(` - Includes: prompt, schema, provider, model, and schema options`);
|
|
1885
|
+
\u{1F4BE} Full debug info saved to directory: ${debugArtifactsDir}`);
|
|
1894
1886
|
} catch {
|
|
1895
1887
|
}
|
|
1896
1888
|
log(`
|
|
@@ -1933,8 +1925,8 @@ $ ${cliCommand}
|
|
|
1933
1925
|
log(`\u{1F4E4} Response length: ${response.length} characters`);
|
|
1934
1926
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
1935
1927
|
try {
|
|
1936
|
-
const
|
|
1937
|
-
const
|
|
1928
|
+
const fs14 = require("fs");
|
|
1929
|
+
const path16 = require("path");
|
|
1938
1930
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1939
1931
|
const agentAny = agent;
|
|
1940
1932
|
let fullHistory = [];
|
|
@@ -1945,10 +1937,10 @@ $ ${cliCommand}
|
|
|
1945
1937
|
} else if (agentAny._messages) {
|
|
1946
1938
|
fullHistory = agentAny._messages;
|
|
1947
1939
|
}
|
|
1948
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
1949
|
-
const
|
|
1940
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path16.join(process.cwd(), "debug-artifacts");
|
|
1941
|
+
const sessionBase = path16.join(
|
|
1950
1942
|
debugArtifactsDir,
|
|
1951
|
-
`session-${_checkName || "unknown"}-${timestamp}
|
|
1943
|
+
`session-${_checkName || "unknown"}-${timestamp}`
|
|
1952
1944
|
);
|
|
1953
1945
|
const sessionData = {
|
|
1954
1946
|
timestamp,
|
|
@@ -1956,15 +1948,9 @@ $ ${cliCommand}
|
|
|
1956
1948
|
provider: this.config.provider || "auto",
|
|
1957
1949
|
model: this.config.model || "default",
|
|
1958
1950
|
schema: effectiveSchema,
|
|
1959
|
-
|
|
1960
|
-
totalMessages: fullHistory.length,
|
|
1961
|
-
latestResponse: response
|
|
1951
|
+
totalMessages: fullHistory.length
|
|
1962
1952
|
};
|
|
1963
|
-
|
|
1964
|
-
const sessionTxtFile = path13.join(
|
|
1965
|
-
debugArtifactsDir,
|
|
1966
|
-
`session-${_checkName || "unknown"}-${timestamp}.txt`
|
|
1967
|
-
);
|
|
1953
|
+
fs14.writeFileSync(sessionBase + ".json", JSON.stringify(sessionData, null, 2), "utf-8");
|
|
1968
1954
|
let readable = `=============================================================
|
|
1969
1955
|
`;
|
|
1970
1956
|
readable += `COMPLETE AI SESSION HISTORY (AFTER RESPONSE)
|
|
@@ -1981,22 +1967,18 @@ $ ${cliCommand}
|
|
|
1981
1967
|
|
|
1982
1968
|
`;
|
|
1983
1969
|
fullHistory.forEach((msg, idx) => {
|
|
1970
|
+
const role = msg.role || "unknown";
|
|
1971
|
+
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content, null, 2);
|
|
1984
1972
|
readable += `
|
|
1985
1973
|
${"=".repeat(60)}
|
|
1974
|
+
MESSAGE ${idx + 1}/${fullHistory.length}
|
|
1975
|
+
Role: ${role}
|
|
1976
|
+
${"=".repeat(60)}
|
|
1986
1977
|
`;
|
|
1987
|
-
readable += `MESSAGE ${idx + 1}/${fullHistory.length}
|
|
1988
|
-
`;
|
|
1989
|
-
readable += `Role: ${msg.role || "unknown"}
|
|
1990
|
-
`;
|
|
1991
|
-
readable += `${"=".repeat(60)}
|
|
1992
|
-
`;
|
|
1993
|
-
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content, null, 2);
|
|
1994
1978
|
readable += content + "\n";
|
|
1995
1979
|
});
|
|
1996
|
-
|
|
1980
|
+
fs14.writeFileSync(sessionBase + ".summary.txt", readable, "utf-8");
|
|
1997
1981
|
log(`\u{1F4BE} Complete session history saved:`);
|
|
1998
|
-
log(` JSON: ${sessionFile}`);
|
|
1999
|
-
log(` TXT: ${sessionTxtFile}`);
|
|
2000
1982
|
log(` - Contains ALL ${fullHistory.length} messages (prompts + responses)`);
|
|
2001
1983
|
} catch (error) {
|
|
2002
1984
|
log(`\u26A0\uFE0F Could not save complete session history: ${error}`);
|
|
@@ -2004,11 +1986,11 @@ ${"=".repeat(60)}
|
|
|
2004
1986
|
}
|
|
2005
1987
|
if (process.env.VISOR_DEBUG_AI_SESSIONS === "true") {
|
|
2006
1988
|
try {
|
|
2007
|
-
const
|
|
2008
|
-
const
|
|
1989
|
+
const fs14 = require("fs");
|
|
1990
|
+
const path16 = require("path");
|
|
2009
1991
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2010
|
-
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS ||
|
|
2011
|
-
const responseFile =
|
|
1992
|
+
const debugArtifactsDir = process.env.VISOR_DEBUG_ARTIFACTS || path16.join(process.cwd(), "debug-artifacts");
|
|
1993
|
+
const responseFile = path16.join(
|
|
2012
1994
|
debugArtifactsDir,
|
|
2013
1995
|
`response-${_checkName || "unknown"}-${timestamp}.txt`
|
|
2014
1996
|
);
|
|
@@ -2041,7 +2023,7 @@ ${"=".repeat(60)}
|
|
|
2041
2023
|
`;
|
|
2042
2024
|
responseContent += `${"=".repeat(60)}
|
|
2043
2025
|
`;
|
|
2044
|
-
|
|
2026
|
+
fs14.writeFileSync(responseFile, responseContent, "utf-8");
|
|
2045
2027
|
log(`\u{1F4BE} Response saved to: ${responseFile}`);
|
|
2046
2028
|
} catch (error) {
|
|
2047
2029
|
log(`\u26A0\uFE0F Could not save response file: ${error}`);
|
|
@@ -2059,9 +2041,9 @@ ${"=".repeat(60)}
|
|
|
2059
2041
|
await telemetry.shutdown();
|
|
2060
2042
|
log(`\u{1F4CA} OpenTelemetry trace saved to: ${traceFilePath}`);
|
|
2061
2043
|
if (process.env.GITHUB_ACTIONS) {
|
|
2062
|
-
const
|
|
2063
|
-
if (
|
|
2064
|
-
const stats =
|
|
2044
|
+
const fs14 = require("fs");
|
|
2045
|
+
if (fs14.existsSync(traceFilePath)) {
|
|
2046
|
+
const stats = fs14.statSync(traceFilePath);
|
|
2065
2047
|
console.log(
|
|
2066
2048
|
`::notice title=AI Trace Saved::OpenTelemetry trace file size: ${stats.size} bytes`
|
|
2067
2049
|
);
|
|
@@ -2072,7 +2054,7 @@ ${"=".repeat(60)}
|
|
|
2072
2054
|
log(`\u{1F4CA} Trace saved to: ${traceFilePath}`);
|
|
2073
2055
|
}
|
|
2074
2056
|
} catch (exportError) {
|
|
2075
|
-
|
|
2057
|
+
logger.warn(`\u26A0\uFE0F Warning: Failed to export trace: ${exportError}`);
|
|
2076
2058
|
}
|
|
2077
2059
|
}
|
|
2078
2060
|
if (_checkName) {
|
|
@@ -2099,8 +2081,8 @@ ${"=".repeat(60)}
|
|
|
2099
2081
|
* Load schema content from schema files or inline definitions
|
|
2100
2082
|
*/
|
|
2101
2083
|
async loadSchemaContent(schema) {
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2084
|
+
const fs14 = require("fs").promises;
|
|
2085
|
+
const path16 = require("path");
|
|
2104
2086
|
if (typeof schema === "object" && schema !== null) {
|
|
2105
2087
|
log("\u{1F4CB} Using inline schema object from configuration");
|
|
2106
2088
|
return JSON.stringify(schema);
|
|
@@ -2113,14 +2095,14 @@ ${"=".repeat(60)}
|
|
|
2113
2095
|
}
|
|
2114
2096
|
} catch {
|
|
2115
2097
|
}
|
|
2116
|
-
if ((schema.startsWith("./") || schema.includes(".json")) && !
|
|
2098
|
+
if ((schema.startsWith("./") || schema.includes(".json")) && !path16.isAbsolute(schema)) {
|
|
2117
2099
|
if (schema.includes("..") || schema.includes("\0")) {
|
|
2118
2100
|
throw new Error("Invalid schema path: path traversal not allowed");
|
|
2119
2101
|
}
|
|
2120
2102
|
try {
|
|
2121
|
-
const schemaPath2 =
|
|
2103
|
+
const schemaPath2 = path16.resolve(process.cwd(), schema);
|
|
2122
2104
|
log(`\u{1F4CB} Loading custom schema from file: ${schemaPath2}`);
|
|
2123
|
-
const schemaContent = await
|
|
2105
|
+
const schemaContent = await fs14.readFile(schemaPath2, "utf-8");
|
|
2124
2106
|
return schemaContent.trim();
|
|
2125
2107
|
} catch (error) {
|
|
2126
2108
|
throw new Error(
|
|
@@ -2132,9 +2114,9 @@ ${"=".repeat(60)}
|
|
|
2132
2114
|
if (!sanitizedSchemaName || sanitizedSchemaName !== schema) {
|
|
2133
2115
|
throw new Error("Invalid schema name");
|
|
2134
2116
|
}
|
|
2135
|
-
const schemaPath =
|
|
2117
|
+
const schemaPath = path16.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
|
|
2136
2118
|
try {
|
|
2137
|
-
const schemaContent = await
|
|
2119
|
+
const schemaContent = await fs14.readFile(schemaPath, "utf-8");
|
|
2138
2120
|
return schemaContent.trim();
|
|
2139
2121
|
} catch (error) {
|
|
2140
2122
|
throw new Error(
|
|
@@ -2244,6 +2226,25 @@ ${"=".repeat(60)}
|
|
|
2244
2226
|
}
|
|
2245
2227
|
}
|
|
2246
2228
|
const isCustomSchema = _schema === "custom" || _schema && (_schema.startsWith("./") || _schema.endsWith(".json")) || _schema && _schema !== "code-review" && !_schema.includes("output/");
|
|
2229
|
+
const _debugSchemaLogging = this.config.debug === true || process.env.VISOR_DEBUG_AI_SESSIONS === "true";
|
|
2230
|
+
if (_debugSchemaLogging) {
|
|
2231
|
+
const details = {
|
|
2232
|
+
schema: _schema,
|
|
2233
|
+
isCustomSchema,
|
|
2234
|
+
isCustomLiteral: _schema === "custom",
|
|
2235
|
+
startsWithDotSlash: typeof _schema === "string" ? _schema.startsWith("./") : false,
|
|
2236
|
+
endsWithJson: typeof _schema === "string" ? _schema.endsWith(".json") : false,
|
|
2237
|
+
notCodeReview: _schema !== "code-review",
|
|
2238
|
+
noOutputPrefix: typeof _schema === "string" ? !_schema.includes("output/") : false
|
|
2239
|
+
};
|
|
2240
|
+
try {
|
|
2241
|
+
log(`\u{1F50D} Schema detection: ${JSON.stringify(details)}`);
|
|
2242
|
+
} catch {
|
|
2243
|
+
log(
|
|
2244
|
+
`\u{1F50D} Schema detection: _schema="${String(_schema)}", isCustomSchema=${isCustomSchema}`
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2247
2248
|
if (isCustomSchema) {
|
|
2248
2249
|
log("\u{1F4CB} Custom schema detected - preserving all fields from parsed JSON");
|
|
2249
2250
|
log(`\u{1F4CA} Schema: ${_schema}`);
|
|
@@ -2289,33 +2290,39 @@ ${"=".repeat(60)}
|
|
|
2289
2290
|
log("\u2705 Successfully created ReviewSummary");
|
|
2290
2291
|
return result;
|
|
2291
2292
|
} catch (error) {
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2293
|
+
const detailed = this.config.debug === true || process.env.VISOR_DEBUG_AI_SESSIONS === "true";
|
|
2294
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2295
|
+
if (detailed) {
|
|
2296
|
+
logger.debug(`\u274C Failed to parse AI response: ${message}`);
|
|
2297
|
+
logger.debug("\u{1F4C4} FULL RAW RESPONSE:");
|
|
2298
|
+
logger.debug("=".repeat(80));
|
|
2299
|
+
logger.debug(response);
|
|
2300
|
+
logger.debug("=".repeat(80));
|
|
2301
|
+
logger.debug(`\u{1F4CF} Response length: ${response.length} characters`);
|
|
2302
|
+
if (error instanceof SyntaxError) {
|
|
2303
|
+
logger.debug("\u{1F50D} JSON parsing error - the response may not be valid JSON");
|
|
2304
|
+
logger.debug(`\u{1F50D} Error details: ${error.message}`);
|
|
2305
|
+
const errorMatch = error.message.match(/position (\d+)/);
|
|
2306
|
+
if (errorMatch) {
|
|
2307
|
+
const position = parseInt(errorMatch[1]);
|
|
2308
|
+
logger.debug(`\u{1F50D} Error at position ${position}:`);
|
|
2309
|
+
const start = Math.max(0, position - 50);
|
|
2310
|
+
const end = Math.min(response.length, position + 50);
|
|
2311
|
+
logger.debug(`\u{1F50D} Context: "${response.substring(start, end)}"`);
|
|
2312
|
+
logger.debug(`\u{1F50D} Response beginning: "${response.substring(0, 100)}"`);
|
|
2313
|
+
}
|
|
2314
|
+
if (response.includes("I cannot")) {
|
|
2315
|
+
logger.debug("\u{1F50D} Response appears to be a refusal/explanation rather than JSON");
|
|
2316
|
+
}
|
|
2317
|
+
if (response.includes("```")) {
|
|
2318
|
+
logger.debug("\u{1F50D} Response appears to contain markdown code blocks");
|
|
2319
|
+
}
|
|
2320
|
+
if (response.startsWith("<")) {
|
|
2321
|
+
logger.debug("\u{1F50D} Response appears to start with XML/HTML");
|
|
2322
|
+
}
|
|
2318
2323
|
}
|
|
2324
|
+
} else {
|
|
2325
|
+
logger.error(`\u274C Failed to parse AI response: ${message}`);
|
|
2319
2326
|
}
|
|
2320
2327
|
throw new Error(
|
|
2321
2328
|
`Invalid AI response format: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
@@ -2380,7 +2387,7 @@ ${"=".repeat(60)}
|
|
|
2380
2387
|
* Generate mock response for testing
|
|
2381
2388
|
*/
|
|
2382
2389
|
async generateMockResponse(_prompt) {
|
|
2383
|
-
await new Promise((
|
|
2390
|
+
await new Promise((resolve7) => setTimeout(resolve7, 500));
|
|
2384
2391
|
const mockResponse = {
|
|
2385
2392
|
content: JSON.stringify({
|
|
2386
2393
|
issues: [
|
|
@@ -2501,15 +2508,15 @@ var init_reviewer = __esm({
|
|
|
2501
2508
|
if (["code-review", "overview", "plain", "text"].includes(schema)) {
|
|
2502
2509
|
return true;
|
|
2503
2510
|
}
|
|
2504
|
-
const
|
|
2505
|
-
const
|
|
2511
|
+
const fs14 = require("fs").promises;
|
|
2512
|
+
const path16 = require("path");
|
|
2506
2513
|
const sanitizedSchemaName = schema.replace(/[^a-zA-Z0-9-]/g, "");
|
|
2507
2514
|
if (!sanitizedSchemaName || sanitizedSchemaName !== schema) {
|
|
2508
2515
|
return false;
|
|
2509
2516
|
}
|
|
2510
|
-
const schemaPath =
|
|
2517
|
+
const schemaPath = path16.join(process.cwd(), "output", sanitizedSchemaName, "schema.json");
|
|
2511
2518
|
try {
|
|
2512
|
-
const schemaContent = await
|
|
2519
|
+
const schemaContent = await fs14.readFile(schemaPath, "utf-8");
|
|
2513
2520
|
const schemaObj = JSON.parse(schemaContent);
|
|
2514
2521
|
const properties = schemaObj.properties;
|
|
2515
2522
|
return !!(properties && "text" in properties);
|
|
@@ -2575,16 +2582,16 @@ var init_reviewer = __esm({
|
|
|
2575
2582
|
}
|
|
2576
2583
|
}
|
|
2577
2584
|
async formatGroupComment(checkResults, _options, _githubContext) {
|
|
2578
|
-
const
|
|
2585
|
+
const normalize3 = (s) => s.replace(/\\n/g, "\n");
|
|
2579
2586
|
const checkContents = checkResults.map((result) => {
|
|
2580
2587
|
const trimmed = result.content?.trim();
|
|
2581
|
-
if (trimmed) return
|
|
2588
|
+
if (trimmed) return normalize3(trimmed);
|
|
2582
2589
|
const out = result.output;
|
|
2583
2590
|
if (out) {
|
|
2584
|
-
if (typeof out === "string" && out.trim()) return
|
|
2591
|
+
if (typeof out === "string" && out.trim()) return normalize3(out.trim());
|
|
2585
2592
|
if (typeof out === "object") {
|
|
2586
2593
|
const txt = out.text || out.response || out.message;
|
|
2587
|
-
if (typeof txt === "string" && txt.trim()) return
|
|
2594
|
+
if (typeof txt === "string" && txt.trim()) return normalize3(txt.trim());
|
|
2588
2595
|
}
|
|
2589
2596
|
}
|
|
2590
2597
|
return "";
|
|
@@ -2680,15 +2687,15 @@ var init_reviewer = __esm({
|
|
|
2680
2687
|
}
|
|
2681
2688
|
saveDebugArtifact(debug) {
|
|
2682
2689
|
try {
|
|
2683
|
-
const
|
|
2684
|
-
const
|
|
2685
|
-
const debugDir =
|
|
2686
|
-
if (!
|
|
2687
|
-
|
|
2690
|
+
const fs14 = require("fs");
|
|
2691
|
+
const path16 = require("path");
|
|
2692
|
+
const debugDir = path16.join(process.cwd(), "debug-artifacts");
|
|
2693
|
+
if (!fs14.existsSync(debugDir)) {
|
|
2694
|
+
fs14.mkdirSync(debugDir, { recursive: true });
|
|
2688
2695
|
}
|
|
2689
2696
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
2690
2697
|
const filename = `visor-debug-${timestamp}.md`;
|
|
2691
|
-
const filepath =
|
|
2698
|
+
const filepath = path16.join(debugDir, filename);
|
|
2692
2699
|
const content = [
|
|
2693
2700
|
`# Visor Debug Information`,
|
|
2694
2701
|
``,
|
|
@@ -2709,7 +2716,7 @@ var init_reviewer = __esm({
|
|
|
2709
2716
|
debug.rawResponse,
|
|
2710
2717
|
"```"
|
|
2711
2718
|
].join("\n");
|
|
2712
|
-
|
|
2719
|
+
fs14.writeFileSync(filepath, content, "utf8");
|
|
2713
2720
|
return filename;
|
|
2714
2721
|
} catch (error) {
|
|
2715
2722
|
console.error("Failed to save debug artifact:", error);
|
|
@@ -2720,21 +2727,101 @@ var init_reviewer = __esm({
|
|
|
2720
2727
|
}
|
|
2721
2728
|
});
|
|
2722
2729
|
|
|
2730
|
+
// src/utils/file-exclusion.ts
|
|
2731
|
+
var import_ignore, fs2, path3, DEFAULT_EXCLUSION_PATTERNS, FileExclusionHelper;
|
|
2732
|
+
var init_file_exclusion = __esm({
|
|
2733
|
+
"src/utils/file-exclusion.ts"() {
|
|
2734
|
+
"use strict";
|
|
2735
|
+
import_ignore = __toESM(require("ignore"));
|
|
2736
|
+
fs2 = __toESM(require("fs"));
|
|
2737
|
+
path3 = __toESM(require("path"));
|
|
2738
|
+
DEFAULT_EXCLUSION_PATTERNS = [
|
|
2739
|
+
"dist/",
|
|
2740
|
+
"build/",
|
|
2741
|
+
".next/",
|
|
2742
|
+
"out/",
|
|
2743
|
+
"node_modules/",
|
|
2744
|
+
"coverage/",
|
|
2745
|
+
".turbo/",
|
|
2746
|
+
"bundled/"
|
|
2747
|
+
];
|
|
2748
|
+
FileExclusionHelper = class {
|
|
2749
|
+
gitignore = null;
|
|
2750
|
+
workingDirectory;
|
|
2751
|
+
/**
|
|
2752
|
+
* @param workingDirectory - Directory to search for .gitignore
|
|
2753
|
+
* @param additionalPatterns - Additional patterns to include (optional, defaults to common build artifacts)
|
|
2754
|
+
*/
|
|
2755
|
+
constructor(workingDirectory = process.cwd(), additionalPatterns = DEFAULT_EXCLUSION_PATTERNS) {
|
|
2756
|
+
const normalizedPath = path3.resolve(workingDirectory);
|
|
2757
|
+
if (normalizedPath.includes("\0")) {
|
|
2758
|
+
throw new Error("Invalid workingDirectory: contains null bytes");
|
|
2759
|
+
}
|
|
2760
|
+
this.workingDirectory = normalizedPath;
|
|
2761
|
+
this.loadGitignore(additionalPatterns);
|
|
2762
|
+
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Load .gitignore patterns from the working directory (called once in constructor)
|
|
2765
|
+
* @param additionalPatterns - Additional patterns to add to gitignore rules
|
|
2766
|
+
*/
|
|
2767
|
+
loadGitignore(additionalPatterns) {
|
|
2768
|
+
const gitignorePath = path3.resolve(this.workingDirectory, ".gitignore");
|
|
2769
|
+
const resolvedWorkingDir = path3.resolve(this.workingDirectory);
|
|
2770
|
+
try {
|
|
2771
|
+
const relativePath = path3.relative(resolvedWorkingDir, gitignorePath);
|
|
2772
|
+
if (relativePath.startsWith("..") || path3.isAbsolute(relativePath)) {
|
|
2773
|
+
throw new Error("Invalid gitignore path: path traversal detected");
|
|
2774
|
+
}
|
|
2775
|
+
if (relativePath !== ".gitignore") {
|
|
2776
|
+
throw new Error("Invalid gitignore path: must be .gitignore in working directory");
|
|
2777
|
+
}
|
|
2778
|
+
this.gitignore = (0, import_ignore.default)();
|
|
2779
|
+
if (additionalPatterns && additionalPatterns.length > 0) {
|
|
2780
|
+
this.gitignore.add(additionalPatterns);
|
|
2781
|
+
}
|
|
2782
|
+
if (fs2.existsSync(gitignorePath)) {
|
|
2783
|
+
const rawContent = fs2.readFileSync(gitignorePath, "utf8");
|
|
2784
|
+
const gitignoreContent = rawContent.replace(/[\r\n]+/g, "\n").replace(/[\x00-\x09\x0B-\x1F\x7F]/g, "").split("\n").filter((line) => line.length < 1e3).join("\n").trim();
|
|
2785
|
+
this.gitignore.add(gitignoreContent);
|
|
2786
|
+
console.error("\u2705 Loaded .gitignore patterns for file filtering");
|
|
2787
|
+
} else if (additionalPatterns && additionalPatterns.length > 0) {
|
|
2788
|
+
console.error("\u26A0\uFE0F No .gitignore found, using default exclusion patterns");
|
|
2789
|
+
}
|
|
2790
|
+
} catch (error) {
|
|
2791
|
+
console.warn("\u26A0\uFE0F Failed to load .gitignore:", error instanceof Error ? error.message : error);
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
/**
|
|
2795
|
+
* Check if a file should be excluded based on .gitignore patterns
|
|
2796
|
+
*/
|
|
2797
|
+
shouldExcludeFile(filename) {
|
|
2798
|
+
if (this.gitignore) {
|
|
2799
|
+
return this.gitignore.ignores(filename);
|
|
2800
|
+
}
|
|
2801
|
+
return false;
|
|
2802
|
+
}
|
|
2803
|
+
};
|
|
2804
|
+
}
|
|
2805
|
+
});
|
|
2806
|
+
|
|
2723
2807
|
// src/git-repository-analyzer.ts
|
|
2724
|
-
var import_simple_git,
|
|
2808
|
+
var import_simple_git, path4, fs3, MAX_PATCH_SIZE, GitRepositoryAnalyzer;
|
|
2725
2809
|
var init_git_repository_analyzer = __esm({
|
|
2726
2810
|
"src/git-repository-analyzer.ts"() {
|
|
2727
2811
|
"use strict";
|
|
2728
2812
|
import_simple_git = require("simple-git");
|
|
2729
|
-
|
|
2730
|
-
|
|
2813
|
+
path4 = __toESM(require("path"));
|
|
2814
|
+
fs3 = __toESM(require("fs"));
|
|
2815
|
+
init_file_exclusion();
|
|
2731
2816
|
MAX_PATCH_SIZE = 50 * 1024;
|
|
2732
2817
|
GitRepositoryAnalyzer = class {
|
|
2733
2818
|
git;
|
|
2734
2819
|
cwd;
|
|
2820
|
+
fileExclusionHelper;
|
|
2735
2821
|
constructor(workingDirectory = process.cwd()) {
|
|
2736
2822
|
this.cwd = workingDirectory;
|
|
2737
2823
|
this.git = (0, import_simple_git.simpleGit)(workingDirectory);
|
|
2824
|
+
this.fileExclusionHelper = new FileExclusionHelper(workingDirectory);
|
|
2738
2825
|
}
|
|
2739
2826
|
/**
|
|
2740
2827
|
* Analyze the current git repository state and return data compatible with PRInfo interface
|
|
@@ -2869,34 +2956,6 @@ ${file.patch}`).join("\n\n");
|
|
|
2869
2956
|
return "main";
|
|
2870
2957
|
}
|
|
2871
2958
|
}
|
|
2872
|
-
/**
|
|
2873
|
-
* Check if a file should be excluded from analysis
|
|
2874
|
-
* This includes:
|
|
2875
|
-
* - Files in .gitignore (even if force-added)
|
|
2876
|
-
* - Built/generated files (dist/, build/, .next/, etc.)
|
|
2877
|
-
*/
|
|
2878
|
-
async shouldExcludeFile(filename) {
|
|
2879
|
-
const excludePatterns = [
|
|
2880
|
-
/^dist\//,
|
|
2881
|
-
/^build\//,
|
|
2882
|
-
/^\.next\//,
|
|
2883
|
-
/^out\//,
|
|
2884
|
-
/^node_modules\//,
|
|
2885
|
-
/^coverage\//,
|
|
2886
|
-
/^\.turbo\//
|
|
2887
|
-
];
|
|
2888
|
-
for (const pattern of excludePatterns) {
|
|
2889
|
-
if (pattern.test(filename)) {
|
|
2890
|
-
return true;
|
|
2891
|
-
}
|
|
2892
|
-
}
|
|
2893
|
-
try {
|
|
2894
|
-
const result = await this.git.raw(["check-ignore", filename]);
|
|
2895
|
-
return result.trim().length > 0;
|
|
2896
|
-
} catch {
|
|
2897
|
-
return false;
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
2959
|
/**
|
|
2901
2960
|
* Truncate a patch if it exceeds MAX_PATCH_SIZE
|
|
2902
2961
|
*/
|
|
@@ -2937,11 +2996,11 @@ ${file.patch}`).join("\n\n");
|
|
|
2937
2996
|
}))
|
|
2938
2997
|
];
|
|
2939
2998
|
for (const { file, status: status2 } of fileChanges) {
|
|
2940
|
-
if (
|
|
2999
|
+
if (this.fileExclusionHelper.shouldExcludeFile(file)) {
|
|
2941
3000
|
console.error(`\u23ED\uFE0F Skipping excluded file: ${file}`);
|
|
2942
3001
|
continue;
|
|
2943
3002
|
}
|
|
2944
|
-
const filePath =
|
|
3003
|
+
const filePath = path4.join(this.cwd, file);
|
|
2945
3004
|
const fileChange = await this.analyzeFileChange(file, status2, filePath, includeContext);
|
|
2946
3005
|
changes.push(fileChange);
|
|
2947
3006
|
}
|
|
@@ -2962,7 +3021,7 @@ ${file.patch}`).join("\n\n");
|
|
|
2962
3021
|
return [];
|
|
2963
3022
|
}
|
|
2964
3023
|
for (const file of diffSummary.files) {
|
|
2965
|
-
if (
|
|
3024
|
+
if (this.fileExclusionHelper.shouldExcludeFile(file.file)) {
|
|
2966
3025
|
console.error(`\u23ED\uFE0F Skipping excluded file: ${file.file}`);
|
|
2967
3026
|
continue;
|
|
2968
3027
|
}
|
|
@@ -3017,7 +3076,7 @@ ${file.patch}`).join("\n\n");
|
|
|
3017
3076
|
let content;
|
|
3018
3077
|
let truncated = false;
|
|
3019
3078
|
try {
|
|
3020
|
-
if (includeContext && status !== "added" &&
|
|
3079
|
+
if (includeContext && status !== "added" && fs3.existsSync(filePath)) {
|
|
3021
3080
|
const diff = await this.git.diff(["--", filename]).catch(() => "");
|
|
3022
3081
|
if (diff) {
|
|
3023
3082
|
const result = this.truncatePatch(diff, filename);
|
|
@@ -3027,7 +3086,7 @@ ${file.patch}`).join("\n\n");
|
|
|
3027
3086
|
additions = lines.filter((line) => line.startsWith("+")).length;
|
|
3028
3087
|
deletions = lines.filter((line) => line.startsWith("-")).length;
|
|
3029
3088
|
}
|
|
3030
|
-
} else if (status !== "added" &&
|
|
3089
|
+
} else if (status !== "added" && fs3.existsSync(filePath)) {
|
|
3031
3090
|
const diff = await this.git.diff(["--", filename]).catch(() => "");
|
|
3032
3091
|
if (diff) {
|
|
3033
3092
|
const lines = diff.split("\n");
|
|
@@ -3035,17 +3094,17 @@ ${file.patch}`).join("\n\n");
|
|
|
3035
3094
|
deletions = lines.filter((line) => line.startsWith("-")).length;
|
|
3036
3095
|
}
|
|
3037
3096
|
}
|
|
3038
|
-
if (status === "added" &&
|
|
3097
|
+
if (status === "added" && fs3.existsSync(filePath)) {
|
|
3039
3098
|
try {
|
|
3040
|
-
const stats =
|
|
3099
|
+
const stats = fs3.statSync(filePath);
|
|
3041
3100
|
if (stats.isFile() && stats.size < 1024 * 1024) {
|
|
3042
3101
|
if (includeContext) {
|
|
3043
|
-
content =
|
|
3102
|
+
content = fs3.readFileSync(filePath, "utf8");
|
|
3044
3103
|
const result = this.truncatePatch(content, filename);
|
|
3045
3104
|
patch = result.patch;
|
|
3046
3105
|
truncated = result.truncated;
|
|
3047
3106
|
}
|
|
3048
|
-
const fileContent = includeContext ? content :
|
|
3107
|
+
const fileContent = includeContext ? content : fs3.readFileSync(filePath, "utf8");
|
|
3049
3108
|
additions = fileContent.split("\n").length;
|
|
3050
3109
|
}
|
|
3051
3110
|
} catch {
|
|
@@ -3130,15 +3189,19 @@ ${file.patch}`).join("\n\n");
|
|
|
3130
3189
|
});
|
|
3131
3190
|
|
|
3132
3191
|
// src/pr-analyzer.ts
|
|
3133
|
-
var PRAnalyzer;
|
|
3192
|
+
var path5, PRAnalyzer;
|
|
3134
3193
|
var init_pr_analyzer = __esm({
|
|
3135
3194
|
"src/pr-analyzer.ts"() {
|
|
3136
3195
|
"use strict";
|
|
3196
|
+
path5 = __toESM(require("path"));
|
|
3197
|
+
init_file_exclusion();
|
|
3137
3198
|
PRAnalyzer = class {
|
|
3138
|
-
constructor(octokit, maxRetries = 3) {
|
|
3199
|
+
constructor(octokit, maxRetries = 3, workingDirectory = path5.resolve(process.cwd())) {
|
|
3139
3200
|
this.octokit = octokit;
|
|
3140
3201
|
this.maxRetries = maxRetries;
|
|
3202
|
+
this.fileExclusionHelper = new FileExclusionHelper(workingDirectory);
|
|
3141
3203
|
}
|
|
3204
|
+
fileExclusionHelper;
|
|
3142
3205
|
/**
|
|
3143
3206
|
* Fetch commit diff for incremental analysis
|
|
3144
3207
|
*/
|
|
@@ -3194,14 +3257,25 @@ ${file.patch}`).join("\n\n");
|
|
|
3194
3257
|
const authorAssociation = pr.author_association && typeof pr.author_association === "string" ? pr.author_association : void 0;
|
|
3195
3258
|
const base = pr.base && typeof pr.base === "object" && pr.base.ref ? typeof pr.base.ref === "string" ? pr.base.ref : String(pr.base.ref) : "main";
|
|
3196
3259
|
const head = pr.head && typeof pr.head === "object" && pr.head.ref ? typeof pr.head.ref === "string" ? pr.head.ref : String(pr.head.ref) : "feature";
|
|
3197
|
-
|
|
3260
|
+
let skippedCount = 0;
|
|
3261
|
+
const validFiles = files ? files.filter((file) => file && typeof file === "object" && file.filename).filter((file) => {
|
|
3262
|
+
const filename = typeof file.filename === "string" ? file.filename : String(file.filename || "unknown");
|
|
3263
|
+
if (!filename || this.fileExclusionHelper.shouldExcludeFile(filename)) {
|
|
3264
|
+
skippedCount++;
|
|
3265
|
+
return false;
|
|
3266
|
+
}
|
|
3267
|
+
return true;
|
|
3268
|
+
}).map((file) => ({
|
|
3198
3269
|
filename: typeof file.filename === "string" ? file.filename : String(file.filename || "unknown"),
|
|
3199
3270
|
additions: typeof file.additions === "number" ? Math.max(0, file.additions) : 0,
|
|
3200
3271
|
deletions: typeof file.deletions === "number" ? Math.max(0, file.deletions) : 0,
|
|
3201
3272
|
changes: typeof file.changes === "number" ? Math.max(0, file.changes) : 0,
|
|
3202
3273
|
patch: typeof file.patch === "string" ? file.patch : void 0,
|
|
3203
3274
|
status: ["added", "removed", "modified", "renamed"].includes(file.status) ? file.status : "modified"
|
|
3204
|
-
}))
|
|
3275
|
+
})) : [];
|
|
3276
|
+
if (skippedCount > 0) {
|
|
3277
|
+
console.log(`\u23ED\uFE0F Skipped ${skippedCount} excluded file(s)`);
|
|
3278
|
+
}
|
|
3205
3279
|
const prInfo = {
|
|
3206
3280
|
number: typeof pr.number === "number" ? pr.number : parseInt(String(pr.number || 1), 10),
|
|
3207
3281
|
title,
|
|
@@ -3280,7 +3354,7 @@ ${file.patch}`).join("\n\n");
|
|
|
3280
3354
|
}
|
|
3281
3355
|
if (this.isRetryableError(error)) {
|
|
3282
3356
|
const delay = Math.min(1e3 * Math.pow(2, attempt), 5e3);
|
|
3283
|
-
await new Promise((
|
|
3357
|
+
await new Promise((resolve7) => setTimeout(resolve7, delay));
|
|
3284
3358
|
} else {
|
|
3285
3359
|
throw error;
|
|
3286
3360
|
}
|
|
@@ -3421,12 +3495,12 @@ var init_env_resolver = __esm({
|
|
|
3421
3495
|
});
|
|
3422
3496
|
|
|
3423
3497
|
// src/issue-filter.ts
|
|
3424
|
-
var
|
|
3498
|
+
var fs4, path6, IssueFilter;
|
|
3425
3499
|
var init_issue_filter = __esm({
|
|
3426
3500
|
"src/issue-filter.ts"() {
|
|
3427
3501
|
"use strict";
|
|
3428
|
-
|
|
3429
|
-
|
|
3502
|
+
fs4 = __toESM(require("fs"));
|
|
3503
|
+
path6 = __toESM(require("path"));
|
|
3430
3504
|
IssueFilter = class {
|
|
3431
3505
|
fileCache = /* @__PURE__ */ new Map();
|
|
3432
3506
|
suppressionEnabled;
|
|
@@ -3494,17 +3568,17 @@ var init_issue_filter = __esm({
|
|
|
3494
3568
|
return this.fileCache.get(filePath);
|
|
3495
3569
|
}
|
|
3496
3570
|
try {
|
|
3497
|
-
const resolvedPath =
|
|
3498
|
-
if (!
|
|
3499
|
-
if (
|
|
3500
|
-
const content2 =
|
|
3571
|
+
const resolvedPath = path6.isAbsolute(filePath) ? filePath : path6.join(workingDir, filePath);
|
|
3572
|
+
if (!fs4.existsSync(resolvedPath)) {
|
|
3573
|
+
if (fs4.existsSync(filePath)) {
|
|
3574
|
+
const content2 = fs4.readFileSync(filePath, "utf8");
|
|
3501
3575
|
const lines2 = content2.split("\n");
|
|
3502
3576
|
this.fileCache.set(filePath, lines2);
|
|
3503
3577
|
return lines2;
|
|
3504
3578
|
}
|
|
3505
3579
|
return null;
|
|
3506
3580
|
}
|
|
3507
|
-
const content =
|
|
3581
|
+
const content = fs4.readFileSync(resolvedPath, "utf8");
|
|
3508
3582
|
const lines = content.split("\n");
|
|
3509
3583
|
this.fileCache.set(filePath, lines);
|
|
3510
3584
|
return lines;
|
|
@@ -4047,7 +4121,7 @@ __export(liquid_extensions_exports, {
|
|
|
4047
4121
|
function sanitizeLabel(value) {
|
|
4048
4122
|
if (value == null) return "";
|
|
4049
4123
|
const s = String(value);
|
|
4050
|
-
return s.replace(/[^A-Za-z0-9
|
|
4124
|
+
return s.replace(/[^A-Za-z0-9:\/\- ]/g, "").replace(/\/{2,}/g, "/").trim();
|
|
4051
4125
|
}
|
|
4052
4126
|
function sanitizeLabelList(labels) {
|
|
4053
4127
|
if (!Array.isArray(labels)) return [];
|
|
@@ -4174,8 +4248,209 @@ var init_liquid_extensions = __esm({
|
|
|
4174
4248
|
}
|
|
4175
4249
|
});
|
|
4176
4250
|
|
|
4251
|
+
// src/telemetry/state-capture.ts
|
|
4252
|
+
function safeSerialize(value, maxLength = MAX_ATTRIBUTE_LENGTH) {
|
|
4253
|
+
try {
|
|
4254
|
+
if (value === void 0 || value === null) return String(value);
|
|
4255
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
4256
|
+
const json = JSON.stringify(value, (key, val) => {
|
|
4257
|
+
if (typeof val === "object" && val !== null) {
|
|
4258
|
+
if (seen.has(val)) return "[Circular]";
|
|
4259
|
+
seen.add(val);
|
|
4260
|
+
}
|
|
4261
|
+
if (typeof val === "string" && val.length > maxLength) {
|
|
4262
|
+
return val.substring(0, maxLength) + "...[truncated]";
|
|
4263
|
+
}
|
|
4264
|
+
return val;
|
|
4265
|
+
});
|
|
4266
|
+
if (json.length > maxLength) {
|
|
4267
|
+
return json.substring(0, maxLength) + "...[truncated]";
|
|
4268
|
+
}
|
|
4269
|
+
return json;
|
|
4270
|
+
} catch (err) {
|
|
4271
|
+
return `[Error serializing: ${err instanceof Error ? err.message : String(err)}]`;
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
function captureCheckInputContext(span, context) {
|
|
4275
|
+
try {
|
|
4276
|
+
const keys = Object.keys(context);
|
|
4277
|
+
span.setAttribute("visor.check.input.keys", keys.join(","));
|
|
4278
|
+
span.setAttribute("visor.check.input.count", keys.length);
|
|
4279
|
+
span.setAttribute("visor.check.input.context", safeSerialize(context));
|
|
4280
|
+
if (context.pr) {
|
|
4281
|
+
span.setAttribute("visor.check.input.pr", safeSerialize(context.pr, 1e3));
|
|
4282
|
+
}
|
|
4283
|
+
if (context.outputs) {
|
|
4284
|
+
span.setAttribute("visor.check.input.outputs", safeSerialize(context.outputs, 5e3));
|
|
4285
|
+
}
|
|
4286
|
+
if (context.env) {
|
|
4287
|
+
span.setAttribute("visor.check.input.env_keys", Object.keys(context.env).join(","));
|
|
4288
|
+
}
|
|
4289
|
+
} catch (err) {
|
|
4290
|
+
try {
|
|
4291
|
+
span.setAttribute("visor.check.input.error", String(err));
|
|
4292
|
+
} catch {
|
|
4293
|
+
}
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
function captureCheckOutput(span, output) {
|
|
4297
|
+
try {
|
|
4298
|
+
span.setAttribute("visor.check.output.type", typeof output);
|
|
4299
|
+
if (Array.isArray(output)) {
|
|
4300
|
+
span.setAttribute("visor.check.output.length", output.length);
|
|
4301
|
+
const preview = output.slice(0, 10);
|
|
4302
|
+
span.setAttribute("visor.check.output.preview", safeSerialize(preview, 2e3));
|
|
4303
|
+
}
|
|
4304
|
+
span.setAttribute("visor.check.output", safeSerialize(output));
|
|
4305
|
+
} catch (err) {
|
|
4306
|
+
try {
|
|
4307
|
+
span.setAttribute("visor.check.output.error", String(err));
|
|
4308
|
+
} catch {
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
}
|
|
4312
|
+
function captureForEachState(span, items, index, currentItem) {
|
|
4313
|
+
try {
|
|
4314
|
+
span.setAttribute("visor.foreach.total", items.length);
|
|
4315
|
+
span.setAttribute("visor.foreach.index", index);
|
|
4316
|
+
span.setAttribute("visor.foreach.current_item", safeSerialize(currentItem, 500));
|
|
4317
|
+
if (items.length <= MAX_ARRAY_ITEMS) {
|
|
4318
|
+
span.setAttribute("visor.foreach.items", safeSerialize(items));
|
|
4319
|
+
} else {
|
|
4320
|
+
span.setAttribute(
|
|
4321
|
+
"visor.foreach.items.preview",
|
|
4322
|
+
safeSerialize(items.slice(0, MAX_ARRAY_ITEMS))
|
|
4323
|
+
);
|
|
4324
|
+
span.setAttribute("visor.foreach.items.truncated", true);
|
|
4325
|
+
}
|
|
4326
|
+
} catch (err) {
|
|
4327
|
+
span.setAttribute("visor.foreach.error", String(err));
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
function captureTransformJS(span, code, input, output) {
|
|
4331
|
+
try {
|
|
4332
|
+
const codePreview = code.length > 2e3 ? code.substring(0, 2e3) + "...[truncated]" : code;
|
|
4333
|
+
span.setAttribute("visor.transform.code", codePreview);
|
|
4334
|
+
span.setAttribute("visor.transform.code.length", code.length);
|
|
4335
|
+
span.setAttribute("visor.transform.input", safeSerialize(input, 2e3));
|
|
4336
|
+
span.setAttribute("visor.transform.output", safeSerialize(output, 2e3));
|
|
4337
|
+
} catch (err) {
|
|
4338
|
+
span.setAttribute("visor.transform.error", String(err));
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
function captureProviderCall(span, providerType, request, response) {
|
|
4342
|
+
try {
|
|
4343
|
+
span.setAttribute("visor.provider.type", providerType);
|
|
4344
|
+
if (request.model) span.setAttribute("visor.provider.request.model", String(request.model));
|
|
4345
|
+
if (request.prompt) {
|
|
4346
|
+
span.setAttribute("visor.provider.request.prompt.length", request.prompt.length);
|
|
4347
|
+
span.setAttribute("visor.provider.request.prompt.preview", request.prompt.substring(0, 500));
|
|
4348
|
+
}
|
|
4349
|
+
if (response.content) {
|
|
4350
|
+
span.setAttribute("visor.provider.response.length", response.content.length);
|
|
4351
|
+
span.setAttribute("visor.provider.response.preview", response.content.substring(0, 500));
|
|
4352
|
+
}
|
|
4353
|
+
if (response.tokens) {
|
|
4354
|
+
span.setAttribute("visor.provider.response.tokens", response.tokens);
|
|
4355
|
+
}
|
|
4356
|
+
} catch (err) {
|
|
4357
|
+
span.setAttribute("visor.provider.error", String(err));
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
function captureStateSnapshot(span, checkId, outputs, memory) {
|
|
4361
|
+
try {
|
|
4362
|
+
span.addEvent("state.snapshot", {
|
|
4363
|
+
"visor.snapshot.check_id": checkId,
|
|
4364
|
+
"visor.snapshot.outputs": safeSerialize(outputs, 5e3),
|
|
4365
|
+
"visor.snapshot.memory": safeSerialize(memory, 5e3),
|
|
4366
|
+
"visor.snapshot.timestamp": (/* @__PURE__ */ new Date()).toISOString()
|
|
4367
|
+
});
|
|
4368
|
+
} catch (err) {
|
|
4369
|
+
span.setAttribute("visor.snapshot.error", String(err));
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
var MAX_ATTRIBUTE_LENGTH, MAX_ARRAY_ITEMS;
|
|
4373
|
+
var init_state_capture = __esm({
|
|
4374
|
+
"src/telemetry/state-capture.ts"() {
|
|
4375
|
+
"use strict";
|
|
4376
|
+
MAX_ATTRIBUTE_LENGTH = 1e4;
|
|
4377
|
+
MAX_ARRAY_ITEMS = 100;
|
|
4378
|
+
}
|
|
4379
|
+
});
|
|
4380
|
+
|
|
4381
|
+
// src/telemetry/fallback-ndjson.ts
|
|
4382
|
+
var fallback_ndjson_exports = {};
|
|
4383
|
+
__export(fallback_ndjson_exports, {
|
|
4384
|
+
emitNdjsonFallback: () => emitNdjsonFallback,
|
|
4385
|
+
emitNdjsonSpanWithEvents: () => emitNdjsonSpanWithEvents,
|
|
4386
|
+
flushNdjson: () => flushNdjson
|
|
4387
|
+
});
|
|
4388
|
+
function resolveTargetPath(outDir) {
|
|
4389
|
+
if (process.env.VISOR_FALLBACK_TRACE_FILE) {
|
|
4390
|
+
CURRENT_FILE = process.env.VISOR_FALLBACK_TRACE_FILE;
|
|
4391
|
+
return CURRENT_FILE;
|
|
4392
|
+
}
|
|
4393
|
+
if (CURRENT_FILE) return CURRENT_FILE;
|
|
4394
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4395
|
+
CURRENT_FILE = path9.join(outDir, `${ts}.ndjson`);
|
|
4396
|
+
return CURRENT_FILE;
|
|
4397
|
+
}
|
|
4398
|
+
function isEnabled() {
|
|
4399
|
+
if (process.env.VISOR_FALLBACK_TRACE_FILE) return true;
|
|
4400
|
+
return process.env.VISOR_TELEMETRY_ENABLED === "true" && (process.env.VISOR_TELEMETRY_SINK || "file") === "file";
|
|
4401
|
+
}
|
|
4402
|
+
function appendAsync(outDir, line) {
|
|
4403
|
+
writeChain = writeChain.then(async () => {
|
|
4404
|
+
if (!dirReady) {
|
|
4405
|
+
try {
|
|
4406
|
+
await fs7.promises.mkdir(outDir, { recursive: true });
|
|
4407
|
+
} catch {
|
|
4408
|
+
}
|
|
4409
|
+
dirReady = true;
|
|
4410
|
+
}
|
|
4411
|
+
const target = resolveTargetPath(outDir);
|
|
4412
|
+
await fs7.promises.appendFile(target, line, "utf8");
|
|
4413
|
+
}).catch(() => {
|
|
4414
|
+
});
|
|
4415
|
+
}
|
|
4416
|
+
async function flushNdjson() {
|
|
4417
|
+
try {
|
|
4418
|
+
await writeChain;
|
|
4419
|
+
} catch {
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
function emitNdjsonFallback(name, attrs) {
|
|
4423
|
+
try {
|
|
4424
|
+
if (!isEnabled()) return;
|
|
4425
|
+
const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
|
|
4426
|
+
const line = JSON.stringify({ name, attributes: attrs }) + "\n";
|
|
4427
|
+
appendAsync(outDir, line);
|
|
4428
|
+
} catch {
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
function emitNdjsonSpanWithEvents(name, attrs, events) {
|
|
4432
|
+
try {
|
|
4433
|
+
if (!isEnabled()) return;
|
|
4434
|
+
const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
|
|
4435
|
+
const line = JSON.stringify({ name, attributes: attrs, events }) + "\n";
|
|
4436
|
+
appendAsync(outDir, line);
|
|
4437
|
+
} catch {
|
|
4438
|
+
}
|
|
4439
|
+
}
|
|
4440
|
+
var fs7, path9, CURRENT_FILE, dirReady, writeChain;
|
|
4441
|
+
var init_fallback_ndjson = __esm({
|
|
4442
|
+
"src/telemetry/fallback-ndjson.ts"() {
|
|
4443
|
+
"use strict";
|
|
4444
|
+
fs7 = __toESM(require("fs"));
|
|
4445
|
+
path9 = __toESM(require("path"));
|
|
4446
|
+
CURRENT_FILE = null;
|
|
4447
|
+
dirReady = false;
|
|
4448
|
+
writeChain = Promise.resolve();
|
|
4449
|
+
}
|
|
4450
|
+
});
|
|
4451
|
+
|
|
4177
4452
|
// src/providers/ai-check-provider.ts
|
|
4178
|
-
var import_promises3, import_path3, AICheckProvider;
|
|
4453
|
+
var import_promises3, import_path3, import_api, AICheckProvider;
|
|
4179
4454
|
var init_ai_check_provider = __esm({
|
|
4180
4455
|
"src/providers/ai-check-provider.ts"() {
|
|
4181
4456
|
"use strict";
|
|
@@ -4186,6 +4461,8 @@ var init_ai_check_provider = __esm({
|
|
|
4186
4461
|
init_liquid_extensions();
|
|
4187
4462
|
import_promises3 = __toESM(require("fs/promises"));
|
|
4188
4463
|
import_path3 = __toESM(require("path"));
|
|
4464
|
+
import_api = require("@opentelemetry/api");
|
|
4465
|
+
init_state_capture();
|
|
4189
4466
|
AICheckProvider = class extends CheckProvider {
|
|
4190
4467
|
aiReviewService;
|
|
4191
4468
|
liquidEngine;
|
|
@@ -4317,9 +4594,9 @@ var init_ai_check_provider = __esm({
|
|
|
4317
4594
|
} else {
|
|
4318
4595
|
resolvedPath = import_path3.default.resolve(process.cwd(), str);
|
|
4319
4596
|
}
|
|
4320
|
-
const
|
|
4597
|
+
const fs14 = require("fs").promises;
|
|
4321
4598
|
try {
|
|
4322
|
-
const stat = await
|
|
4599
|
+
const stat = await fs14.stat(resolvedPath);
|
|
4323
4600
|
return stat.isFile();
|
|
4324
4601
|
} catch {
|
|
4325
4602
|
return hasFileExtension && (isRelativePath || isAbsolutePath || hasPathSeparators);
|
|
@@ -4525,6 +4802,40 @@ var init_ai_check_provider = __esm({
|
|
|
4525
4802
|
);
|
|
4526
4803
|
}
|
|
4527
4804
|
}
|
|
4805
|
+
const templateContext = {
|
|
4806
|
+
pr: {
|
|
4807
|
+
number: prInfo.number,
|
|
4808
|
+
title: prInfo.title,
|
|
4809
|
+
author: prInfo.author,
|
|
4810
|
+
branch: prInfo.head,
|
|
4811
|
+
base: prInfo.base
|
|
4812
|
+
},
|
|
4813
|
+
files: prInfo.files,
|
|
4814
|
+
outputs: _dependencyResults ? Object.fromEntries(
|
|
4815
|
+
Array.from(_dependencyResults.entries()).map(([checkName, result]) => [
|
|
4816
|
+
checkName,
|
|
4817
|
+
result.output !== void 0 ? result.output : result
|
|
4818
|
+
])
|
|
4819
|
+
) : {}
|
|
4820
|
+
};
|
|
4821
|
+
try {
|
|
4822
|
+
const span = import_api.trace.getSpan(import_api.context.active());
|
|
4823
|
+
if (span) {
|
|
4824
|
+
captureCheckInputContext(span, templateContext);
|
|
4825
|
+
}
|
|
4826
|
+
} catch {
|
|
4827
|
+
}
|
|
4828
|
+
try {
|
|
4829
|
+
const checkId = config.checkName || config.id || "unknown";
|
|
4830
|
+
const ctxJson = JSON.stringify(templateContext);
|
|
4831
|
+
const { emitNdjsonSpanWithEvents: emitNdjsonSpanWithEvents2 } = (init_fallback_ndjson(), __toCommonJS(fallback_ndjson_exports));
|
|
4832
|
+
emitNdjsonSpanWithEvents2(
|
|
4833
|
+
"visor.check",
|
|
4834
|
+
{ "visor.check.id": checkId, "visor.check.input.context": ctxJson },
|
|
4835
|
+
[]
|
|
4836
|
+
);
|
|
4837
|
+
} catch {
|
|
4838
|
+
}
|
|
4528
4839
|
const processedPrompt = await this.processPrompt(
|
|
4529
4840
|
customPrompt,
|
|
4530
4841
|
prInfo,
|
|
@@ -4577,10 +4888,43 @@ var init_ai_check_provider = __esm({
|
|
|
4577
4888
|
const suppressionEnabled = config.suppressionEnabled !== false;
|
|
4578
4889
|
const issueFilter = new IssueFilter(suppressionEnabled);
|
|
4579
4890
|
const filteredIssues = issueFilter.filterIssues(result.issues || [], process.cwd());
|
|
4580
|
-
|
|
4891
|
+
const finalResult = {
|
|
4581
4892
|
...result,
|
|
4582
4893
|
issues: filteredIssues
|
|
4583
4894
|
};
|
|
4895
|
+
try {
|
|
4896
|
+
const span = import_api.trace.getSpan(import_api.context.active());
|
|
4897
|
+
if (span) {
|
|
4898
|
+
captureProviderCall(
|
|
4899
|
+
span,
|
|
4900
|
+
"ai",
|
|
4901
|
+
{
|
|
4902
|
+
prompt: processedPrompt.substring(0, 500),
|
|
4903
|
+
// Preview only
|
|
4904
|
+
model: aiConfig.model
|
|
4905
|
+
},
|
|
4906
|
+
{
|
|
4907
|
+
content: JSON.stringify(finalResult).substring(0, 500),
|
|
4908
|
+
tokens: result.usage?.totalTokens
|
|
4909
|
+
}
|
|
4910
|
+
);
|
|
4911
|
+
const outputForSpan = finalResult.output ?? finalResult;
|
|
4912
|
+
captureCheckOutput(span, outputForSpan);
|
|
4913
|
+
}
|
|
4914
|
+
} catch {
|
|
4915
|
+
}
|
|
4916
|
+
try {
|
|
4917
|
+
const checkId = config.checkName || config.id || "unknown";
|
|
4918
|
+
const outJson = JSON.stringify(finalResult.output ?? finalResult);
|
|
4919
|
+
const { emitNdjsonSpanWithEvents: emitNdjsonSpanWithEvents2 } = (init_fallback_ndjson(), __toCommonJS(fallback_ndjson_exports));
|
|
4920
|
+
emitNdjsonSpanWithEvents2(
|
|
4921
|
+
"visor.check",
|
|
4922
|
+
{ "visor.check.id": checkId, "visor.check.output": outJson },
|
|
4923
|
+
[]
|
|
4924
|
+
);
|
|
4925
|
+
} catch {
|
|
4926
|
+
}
|
|
4927
|
+
return finalResult;
|
|
4584
4928
|
} catch (error) {
|
|
4585
4929
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4586
4930
|
console.error(`\u274C AI Check Provider Error for check: ${errorMessage}`);
|
|
@@ -4627,13 +4971,15 @@ var init_ai_check_provider = __esm({
|
|
|
4627
4971
|
});
|
|
4628
4972
|
|
|
4629
4973
|
// src/providers/http-check-provider.ts
|
|
4630
|
-
var HttpCheckProvider;
|
|
4974
|
+
var import_api2, HttpCheckProvider;
|
|
4631
4975
|
var init_http_check_provider = __esm({
|
|
4632
4976
|
"src/providers/http-check-provider.ts"() {
|
|
4633
4977
|
"use strict";
|
|
4634
4978
|
init_check_provider_interface();
|
|
4635
4979
|
init_issue_filter();
|
|
4636
4980
|
init_liquid_extensions();
|
|
4981
|
+
import_api2 = require("@opentelemetry/api");
|
|
4982
|
+
init_state_capture();
|
|
4637
4983
|
HttpCheckProvider = class extends CheckProvider {
|
|
4638
4984
|
liquid;
|
|
4639
4985
|
constructor() {
|
|
@@ -4695,6 +5041,13 @@ var init_http_check_provider = __esm({
|
|
|
4695
5041
|
outputs: dependencyResults ? Object.fromEntries(dependencyResults) : {},
|
|
4696
5042
|
metadata: config.metadata || {}
|
|
4697
5043
|
};
|
|
5044
|
+
try {
|
|
5045
|
+
const span = import_api2.trace.getSpan(import_api2.context.active());
|
|
5046
|
+
if (span) {
|
|
5047
|
+
captureCheckInputContext(span, templateContext);
|
|
5048
|
+
}
|
|
5049
|
+
} catch {
|
|
5050
|
+
}
|
|
4698
5051
|
let payload;
|
|
4699
5052
|
try {
|
|
4700
5053
|
const renderedBody = await this.liquid.parseAndRender(bodyTemplate, templateContext);
|
|
@@ -4717,10 +5070,31 @@ var init_http_check_provider = __esm({
|
|
|
4717
5070
|
const suppressionEnabled = config.suppressionEnabled !== false;
|
|
4718
5071
|
const issueFilter = new IssueFilter(suppressionEnabled);
|
|
4719
5072
|
const filteredIssues = issueFilter.filterIssues(result.issues || [], process.cwd());
|
|
4720
|
-
|
|
5073
|
+
const finalResult = {
|
|
4721
5074
|
...result,
|
|
4722
5075
|
issues: filteredIssues
|
|
4723
5076
|
};
|
|
5077
|
+
try {
|
|
5078
|
+
const span = import_api2.trace.getSpan(import_api2.context.active());
|
|
5079
|
+
if (span) {
|
|
5080
|
+
captureProviderCall(
|
|
5081
|
+
span,
|
|
5082
|
+
"http",
|
|
5083
|
+
{
|
|
5084
|
+
url,
|
|
5085
|
+
method,
|
|
5086
|
+
body: JSON.stringify(payload).substring(0, 500)
|
|
5087
|
+
},
|
|
5088
|
+
{
|
|
5089
|
+
content: JSON.stringify(response).substring(0, 500)
|
|
5090
|
+
}
|
|
5091
|
+
);
|
|
5092
|
+
const outputForSpan = finalResult.output ?? finalResult;
|
|
5093
|
+
captureCheckOutput(span, outputForSpan);
|
|
5094
|
+
}
|
|
5095
|
+
} catch {
|
|
5096
|
+
}
|
|
5097
|
+
return finalResult;
|
|
4724
5098
|
} catch (error) {
|
|
4725
5099
|
return this.createErrorResult(url, error);
|
|
4726
5100
|
}
|
|
@@ -5402,13 +5776,123 @@ var init_log_check_provider = __esm({
|
|
|
5402
5776
|
}
|
|
5403
5777
|
});
|
|
5404
5778
|
|
|
5779
|
+
// src/utils/sandbox.ts
|
|
5780
|
+
function createSecureSandbox() {
|
|
5781
|
+
const globals = {
|
|
5782
|
+
...import_sandboxjs.default.SAFE_GLOBALS,
|
|
5783
|
+
Math,
|
|
5784
|
+
JSON,
|
|
5785
|
+
// Provide console with limited surface. Calls are harmless in CI logs and
|
|
5786
|
+
// help with debugging value_js / transform_js expressions.
|
|
5787
|
+
console: {
|
|
5788
|
+
log: console.log,
|
|
5789
|
+
warn: console.warn,
|
|
5790
|
+
error: console.error
|
|
5791
|
+
}
|
|
5792
|
+
};
|
|
5793
|
+
const prototypeWhitelist = new Map(import_sandboxjs.default.SAFE_PROTOTYPES);
|
|
5794
|
+
const arrayMethods = /* @__PURE__ */ new Set([
|
|
5795
|
+
"some",
|
|
5796
|
+
"every",
|
|
5797
|
+
"filter",
|
|
5798
|
+
"map",
|
|
5799
|
+
"reduce",
|
|
5800
|
+
"find",
|
|
5801
|
+
"includes",
|
|
5802
|
+
"indexOf",
|
|
5803
|
+
"length",
|
|
5804
|
+
"slice",
|
|
5805
|
+
"concat",
|
|
5806
|
+
"join",
|
|
5807
|
+
"push",
|
|
5808
|
+
"pop",
|
|
5809
|
+
"shift",
|
|
5810
|
+
"unshift",
|
|
5811
|
+
"sort",
|
|
5812
|
+
"reverse",
|
|
5813
|
+
"flat",
|
|
5814
|
+
"flatMap"
|
|
5815
|
+
]);
|
|
5816
|
+
prototypeWhitelist.set(Array.prototype, arrayMethods);
|
|
5817
|
+
const stringMethods = /* @__PURE__ */ new Set([
|
|
5818
|
+
"toLowerCase",
|
|
5819
|
+
"toUpperCase",
|
|
5820
|
+
"includes",
|
|
5821
|
+
"indexOf",
|
|
5822
|
+
"startsWith",
|
|
5823
|
+
"endsWith",
|
|
5824
|
+
"slice",
|
|
5825
|
+
"substring",
|
|
5826
|
+
"length",
|
|
5827
|
+
"trim",
|
|
5828
|
+
"split",
|
|
5829
|
+
"replace",
|
|
5830
|
+
"match",
|
|
5831
|
+
"padStart",
|
|
5832
|
+
"padEnd"
|
|
5833
|
+
]);
|
|
5834
|
+
prototypeWhitelist.set(String.prototype, stringMethods);
|
|
5835
|
+
const objectMethods = /* @__PURE__ */ new Set([
|
|
5836
|
+
"hasOwnProperty",
|
|
5837
|
+
"toString",
|
|
5838
|
+
"valueOf",
|
|
5839
|
+
"keys",
|
|
5840
|
+
"values"
|
|
5841
|
+
]);
|
|
5842
|
+
prototypeWhitelist.set(Object.prototype, objectMethods);
|
|
5843
|
+
return new import_sandboxjs.default({ globals, prototypeWhitelist });
|
|
5844
|
+
}
|
|
5845
|
+
function compileAndRun(sandbox, userCode, scope, opts = { injectLog: true, wrapFunction: true, logPrefix: "[sandbox]" }) {
|
|
5846
|
+
const inject = opts?.injectLog === true;
|
|
5847
|
+
let safePrefix = String(opts?.logPrefix ?? "[sandbox]");
|
|
5848
|
+
safePrefix = safePrefix.replace(/[\r\n\t\0]/g, "").replace(/[`$\\]/g, "").replace(/\$\{/g, "").slice(0, 64);
|
|
5849
|
+
const header = inject ? `const __lp = ${JSON.stringify(safePrefix)}; const log = (...a) => { try { console.log(__lp, ...a); } catch {} };
|
|
5850
|
+
` : "";
|
|
5851
|
+
const body = opts.wrapFunction ? `const __fn = () => {
|
|
5852
|
+
${userCode}
|
|
5853
|
+
};
|
|
5854
|
+
return __fn();
|
|
5855
|
+
` : `${userCode}`;
|
|
5856
|
+
const code = `${header}${body}`;
|
|
5857
|
+
let exec;
|
|
5858
|
+
try {
|
|
5859
|
+
exec = sandbox.compile(code);
|
|
5860
|
+
} catch (e) {
|
|
5861
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
5862
|
+
throw new Error(`sandbox_compile_error: ${msg}`);
|
|
5863
|
+
}
|
|
5864
|
+
let out;
|
|
5865
|
+
try {
|
|
5866
|
+
out = exec(scope);
|
|
5867
|
+
} catch (e) {
|
|
5868
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
5869
|
+
throw new Error(`sandbox_execution_error: ${msg}`);
|
|
5870
|
+
}
|
|
5871
|
+
if (out && typeof out.run === "function") {
|
|
5872
|
+
try {
|
|
5873
|
+
return out.run();
|
|
5874
|
+
} catch (e) {
|
|
5875
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
5876
|
+
throw new Error(`sandbox_runner_error: ${msg}`);
|
|
5877
|
+
}
|
|
5878
|
+
}
|
|
5879
|
+
return out;
|
|
5880
|
+
}
|
|
5881
|
+
var import_sandboxjs;
|
|
5882
|
+
var init_sandbox = __esm({
|
|
5883
|
+
"src/utils/sandbox.ts"() {
|
|
5884
|
+
"use strict";
|
|
5885
|
+
import_sandboxjs = __toESM(require("@nyariv/sandboxjs"));
|
|
5886
|
+
}
|
|
5887
|
+
});
|
|
5888
|
+
|
|
5405
5889
|
// src/providers/github-ops-provider.ts
|
|
5406
|
-
var
|
|
5890
|
+
var GitHubOpsProvider;
|
|
5407
5891
|
var init_github_ops_provider = __esm({
|
|
5408
5892
|
"src/providers/github-ops-provider.ts"() {
|
|
5409
5893
|
"use strict";
|
|
5410
5894
|
init_check_provider_interface();
|
|
5411
|
-
|
|
5895
|
+
init_sandbox();
|
|
5412
5896
|
init_liquid_extensions();
|
|
5413
5897
|
GitHubOpsProvider = class extends CheckProvider {
|
|
5414
5898
|
sandbox;
|
|
@@ -5436,25 +5920,20 @@ var init_github_ops_provider = __esm({
|
|
|
5436
5920
|
}
|
|
5437
5921
|
async execute(prInfo, config, dependencyResults) {
|
|
5438
5922
|
const cfg = config;
|
|
5439
|
-
|
|
5923
|
+
const octokit = config.eventContext?.octokit;
|
|
5440
5924
|
if (!octokit) {
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
]
|
|
5454
|
-
};
|
|
5455
|
-
}
|
|
5456
|
-
const { Octokit } = await import("@octokit/rest");
|
|
5457
|
-
octokit = new Octokit({ auth: token });
|
|
5925
|
+
return {
|
|
5926
|
+
issues: [
|
|
5927
|
+
{
|
|
5928
|
+
file: "system",
|
|
5929
|
+
line: 0,
|
|
5930
|
+
ruleId: "github/missing_octokit",
|
|
5931
|
+
message: "No authenticated Octokit instance available in event context. GitHub operations require proper authentication context.",
|
|
5932
|
+
severity: "error",
|
|
5933
|
+
category: "logic"
|
|
5934
|
+
}
|
|
5935
|
+
]
|
|
5936
|
+
};
|
|
5458
5937
|
}
|
|
5459
5938
|
const repoEnv = process.env.GITHUB_REPOSITORY || "";
|
|
5460
5939
|
const [owner, repo] = repoEnv.split("/");
|
|
@@ -5532,14 +6011,19 @@ var init_github_ops_provider = __esm({
|
|
|
5532
6011
|
if (cfg.value_js && cfg.value_js.trim()) {
|
|
5533
6012
|
try {
|
|
5534
6013
|
const sandbox = this.getSecureSandbox();
|
|
5535
|
-
const
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
const res =
|
|
6014
|
+
const depOutputs = {};
|
|
6015
|
+
if (dependencyResults) {
|
|
6016
|
+
for (const [name, result] of dependencyResults.entries()) {
|
|
6017
|
+
const summary = result;
|
|
6018
|
+
depOutputs[name] = summary.output !== void 0 ? summary.output : summary;
|
|
6019
|
+
}
|
|
6020
|
+
}
|
|
6021
|
+
const res = compileAndRun(
|
|
6022
|
+
sandbox,
|
|
6023
|
+
cfg.value_js,
|
|
6024
|
+
{ pr: prInfo, values, outputs: depOutputs },
|
|
6025
|
+
{ injectLog: true, wrapFunction: true, logPrefix: "[github:value_js]" }
|
|
6026
|
+
);
|
|
5543
6027
|
if (typeof res === "string") values = [res];
|
|
5544
6028
|
else if (Array.isArray(res)) values = res.map((v) => String(v));
|
|
5545
6029
|
} catch (e) {
|
|
@@ -5630,44 +6114,7 @@ ${cfg.value_js}
|
|
|
5630
6114
|
*/
|
|
5631
6115
|
getSecureSandbox() {
|
|
5632
6116
|
if (this.sandbox) return this.sandbox;
|
|
5633
|
-
|
|
5634
|
-
...import_sandboxjs.default.SAFE_GLOBALS,
|
|
5635
|
-
Math
|
|
5636
|
-
};
|
|
5637
|
-
const prototypeWhitelist = new Map(import_sandboxjs.default.SAFE_PROTOTYPES);
|
|
5638
|
-
const arrayMethods = /* @__PURE__ */ new Set([
|
|
5639
|
-
"some",
|
|
5640
|
-
"every",
|
|
5641
|
-
"filter",
|
|
5642
|
-
"map",
|
|
5643
|
-
"reduce",
|
|
5644
|
-
"find",
|
|
5645
|
-
"includes",
|
|
5646
|
-
"indexOf",
|
|
5647
|
-
"length",
|
|
5648
|
-
"slice",
|
|
5649
|
-
"concat",
|
|
5650
|
-
"join"
|
|
5651
|
-
]);
|
|
5652
|
-
prototypeWhitelist.set(Array.prototype, arrayMethods);
|
|
5653
|
-
const stringMethods = /* @__PURE__ */ new Set([
|
|
5654
|
-
"toLowerCase",
|
|
5655
|
-
"toUpperCase",
|
|
5656
|
-
"includes",
|
|
5657
|
-
"indexOf",
|
|
5658
|
-
"startsWith",
|
|
5659
|
-
"endsWith",
|
|
5660
|
-
"slice",
|
|
5661
|
-
"substring",
|
|
5662
|
-
"length",
|
|
5663
|
-
"trim",
|
|
5664
|
-
"split",
|
|
5665
|
-
"replace"
|
|
5666
|
-
]);
|
|
5667
|
-
prototypeWhitelist.set(String.prototype, stringMethods);
|
|
5668
|
-
const objectMethods = /* @__PURE__ */ new Set(["hasOwnProperty", "toString", "valueOf"]);
|
|
5669
|
-
prototypeWhitelist.set(Object.prototype, objectMethods);
|
|
5670
|
-
this.sandbox = new import_sandboxjs.default({ globals, prototypeWhitelist });
|
|
6117
|
+
this.sandbox = createSecureSandbox();
|
|
5671
6118
|
return this.sandbox;
|
|
5672
6119
|
}
|
|
5673
6120
|
};
|
|
@@ -6142,15 +6589,17 @@ var init_claude_code_check_provider = __esm({
|
|
|
6142
6589
|
});
|
|
6143
6590
|
|
|
6144
6591
|
// src/providers/command-check-provider.ts
|
|
6145
|
-
var
|
|
6592
|
+
var import_api3, CommandCheckProvider;
|
|
6146
6593
|
var init_command_check_provider = __esm({
|
|
6147
6594
|
"src/providers/command-check-provider.ts"() {
|
|
6148
6595
|
"use strict";
|
|
6149
6596
|
init_check_provider_interface();
|
|
6150
|
-
|
|
6597
|
+
init_sandbox();
|
|
6151
6598
|
init_liquid_extensions();
|
|
6152
6599
|
init_logger();
|
|
6153
6600
|
init_author_permissions();
|
|
6601
|
+
import_api3 = require("@opentelemetry/api");
|
|
6602
|
+
init_state_capture();
|
|
6154
6603
|
CommandCheckProvider = class extends CheckProvider {
|
|
6155
6604
|
liquid;
|
|
6156
6605
|
sandbox;
|
|
@@ -6163,13 +6612,7 @@ var init_command_check_provider = __esm({
|
|
|
6163
6612
|
});
|
|
6164
6613
|
}
|
|
6165
6614
|
createSecureSandbox() {
|
|
6166
|
-
|
|
6167
|
-
...import_sandboxjs2.default.SAFE_GLOBALS,
|
|
6168
|
-
console,
|
|
6169
|
-
JSON
|
|
6170
|
-
};
|
|
6171
|
-
const prototypeWhitelist = new Map(import_sandboxjs2.default.SAFE_PROTOTYPES);
|
|
6172
|
-
return new import_sandboxjs2.default({ globals, prototypeWhitelist });
|
|
6615
|
+
return createSecureSandbox();
|
|
6173
6616
|
}
|
|
6174
6617
|
getName() {
|
|
6175
6618
|
return "command";
|
|
@@ -6218,6 +6661,24 @@ var init_command_check_provider = __esm({
|
|
|
6218
6661
|
logger.debug(
|
|
6219
6662
|
`\u{1F527} Debug: Template outputs keys: ${Object.keys(templateContext.outputs || {}).join(", ")}`
|
|
6220
6663
|
);
|
|
6664
|
+
try {
|
|
6665
|
+
const span = import_api3.trace.getSpan(import_api3.context.active());
|
|
6666
|
+
if (span) {
|
|
6667
|
+
captureCheckInputContext(span, templateContext);
|
|
6668
|
+
}
|
|
6669
|
+
} catch {
|
|
6670
|
+
}
|
|
6671
|
+
try {
|
|
6672
|
+
const checkId = config.checkName || config.id || "unknown";
|
|
6673
|
+
const ctxJson = JSON.stringify(templateContext);
|
|
6674
|
+
const { emitNdjsonSpanWithEvents: emitNdjsonSpanWithEvents2 } = (init_fallback_ndjson(), __toCommonJS(fallback_ndjson_exports));
|
|
6675
|
+
emitNdjsonSpanWithEvents2(
|
|
6676
|
+
"visor.check",
|
|
6677
|
+
{ "visor.check.id": checkId, "visor.check.input.context": ctxJson },
|
|
6678
|
+
[{ name: "check.started" }, { name: "check.completed" }]
|
|
6679
|
+
);
|
|
6680
|
+
} catch {
|
|
6681
|
+
}
|
|
6221
6682
|
try {
|
|
6222
6683
|
let renderedCommand = command;
|
|
6223
6684
|
if (command.includes("{{") || command.includes("{%")) {
|
|
@@ -6412,8 +6873,12 @@ ${bodyWithReturn}
|
|
|
6412
6873
|
if (parsedFromSandboxJson !== void 0) {
|
|
6413
6874
|
finalOutput = parsedFromSandboxJson;
|
|
6414
6875
|
} else {
|
|
6415
|
-
|
|
6416
|
-
|
|
6876
|
+
finalOutput = compileAndRun(
|
|
6877
|
+
this.sandbox,
|
|
6878
|
+
code,
|
|
6879
|
+
{ scope: jsContext },
|
|
6880
|
+
{ injectLog: false, wrapFunction: false }
|
|
6881
|
+
);
|
|
6417
6882
|
}
|
|
6418
6883
|
try {
|
|
6419
6884
|
if (finalOutput && typeof finalOutput === "object" && !Array.isArray(finalOutput) && (finalOutput.error === void 0 || finalOutput.issues === void 0)) {
|
|
@@ -6824,6 +7289,27 @@ ${bodyWithReturn}
|
|
|
6824
7289
|
...content ? { content } : {},
|
|
6825
7290
|
...promoted
|
|
6826
7291
|
};
|
|
7292
|
+
try {
|
|
7293
|
+
const span = import_api3.trace.getSpan(import_api3.context.active());
|
|
7294
|
+
if (span) {
|
|
7295
|
+
captureCheckOutput(span, outputForDependents);
|
|
7296
|
+
if (transformJs && output !== finalOutput) {
|
|
7297
|
+
captureTransformJS(span, transformJs, output, finalOutput);
|
|
7298
|
+
}
|
|
7299
|
+
}
|
|
7300
|
+
} catch {
|
|
7301
|
+
}
|
|
7302
|
+
try {
|
|
7303
|
+
const checkId = config.checkName || config.id || "unknown";
|
|
7304
|
+
const outJson = JSON.stringify(result.output ?? result);
|
|
7305
|
+
const { emitNdjsonSpanWithEvents: emitNdjsonSpanWithEvents2 } = (init_fallback_ndjson(), __toCommonJS(fallback_ndjson_exports));
|
|
7306
|
+
emitNdjsonSpanWithEvents2(
|
|
7307
|
+
"visor.check",
|
|
7308
|
+
{ "visor.check.id": checkId, "visor.check.output": outJson },
|
|
7309
|
+
[{ name: "check.started" }, { name: "check.completed" }]
|
|
7310
|
+
);
|
|
7311
|
+
} catch {
|
|
7312
|
+
}
|
|
6827
7313
|
try {
|
|
6828
7314
|
if (transformJs) {
|
|
6829
7315
|
const rawObj = snapshotForExtraction || finalOutput;
|
|
@@ -7389,7 +7875,7 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
7389
7875
|
});
|
|
7390
7876
|
|
|
7391
7877
|
// src/providers/memory-check-provider.ts
|
|
7392
|
-
var
|
|
7878
|
+
var MemoryCheckProvider;
|
|
7393
7879
|
var init_memory_check_provider = __esm({
|
|
7394
7880
|
"src/providers/memory-check-provider.ts"() {
|
|
7395
7881
|
"use strict";
|
|
@@ -7397,7 +7883,7 @@ var init_memory_check_provider = __esm({
|
|
|
7397
7883
|
init_memory_store();
|
|
7398
7884
|
init_liquid_extensions();
|
|
7399
7885
|
init_logger();
|
|
7400
|
-
|
|
7886
|
+
init_sandbox();
|
|
7401
7887
|
MemoryCheckProvider = class extends CheckProvider {
|
|
7402
7888
|
liquid;
|
|
7403
7889
|
sandbox;
|
|
@@ -7412,61 +7898,7 @@ var init_memory_check_provider = __esm({
|
|
|
7412
7898
|
* Create a secure sandbox for JavaScript execution
|
|
7413
7899
|
*/
|
|
7414
7900
|
createSecureSandbox() {
|
|
7415
|
-
|
|
7416
|
-
...import_sandboxjs3.default.SAFE_GLOBALS,
|
|
7417
|
-
Math,
|
|
7418
|
-
console: {
|
|
7419
|
-
log: console.log,
|
|
7420
|
-
warn: console.warn,
|
|
7421
|
-
error: console.error
|
|
7422
|
-
}
|
|
7423
|
-
};
|
|
7424
|
-
const prototypeWhitelist = new Map(import_sandboxjs3.default.SAFE_PROTOTYPES);
|
|
7425
|
-
const arrayMethods = /* @__PURE__ */ new Set([
|
|
7426
|
-
"some",
|
|
7427
|
-
"every",
|
|
7428
|
-
"filter",
|
|
7429
|
-
"map",
|
|
7430
|
-
"reduce",
|
|
7431
|
-
"find",
|
|
7432
|
-
"includes",
|
|
7433
|
-
"indexOf",
|
|
7434
|
-
"length",
|
|
7435
|
-
"slice",
|
|
7436
|
-
"concat",
|
|
7437
|
-
"join",
|
|
7438
|
-
"push",
|
|
7439
|
-
"pop",
|
|
7440
|
-
"shift",
|
|
7441
|
-
"unshift",
|
|
7442
|
-
"sort",
|
|
7443
|
-
"reverse"
|
|
7444
|
-
]);
|
|
7445
|
-
prototypeWhitelist.set(Array.prototype, arrayMethods);
|
|
7446
|
-
const stringMethods = /* @__PURE__ */ new Set([
|
|
7447
|
-
"toLowerCase",
|
|
7448
|
-
"toUpperCase",
|
|
7449
|
-
"includes",
|
|
7450
|
-
"indexOf",
|
|
7451
|
-
"startsWith",
|
|
7452
|
-
"endsWith",
|
|
7453
|
-
"slice",
|
|
7454
|
-
"substring",
|
|
7455
|
-
"length",
|
|
7456
|
-
"trim",
|
|
7457
|
-
"split",
|
|
7458
|
-
"replace",
|
|
7459
|
-
"match",
|
|
7460
|
-
"padStart",
|
|
7461
|
-
"padEnd"
|
|
7462
|
-
]);
|
|
7463
|
-
prototypeWhitelist.set(String.prototype, stringMethods);
|
|
7464
|
-
const objectMethods = /* @__PURE__ */ new Set(["hasOwnProperty", "toString", "valueOf"]);
|
|
7465
|
-
prototypeWhitelist.set(Object.prototype, objectMethods);
|
|
7466
|
-
return new import_sandboxjs3.default({
|
|
7467
|
-
globals,
|
|
7468
|
-
prototypeWhitelist
|
|
7469
|
-
});
|
|
7901
|
+
return createSecureSandbox();
|
|
7470
7902
|
}
|
|
7471
7903
|
getName() {
|
|
7472
7904
|
return "memory";
|
|
@@ -7758,15 +8190,12 @@ var init_memory_check_provider = __esm({
|
|
|
7758
8190
|
this.sandbox = this.createSecureSandbox();
|
|
7759
8191
|
}
|
|
7760
8192
|
try {
|
|
7761
|
-
const
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
};
|
|
7768
|
-
const exec = this.sandbox.compile(`return (${expression});`);
|
|
7769
|
-
return exec(scope).run();
|
|
8193
|
+
const scope = { ...context };
|
|
8194
|
+
return compileAndRun(this.sandbox, `return (${expression});`, scope, {
|
|
8195
|
+
injectLog: true,
|
|
8196
|
+
wrapFunction: false,
|
|
8197
|
+
logPrefix: "[memory:value_js]"
|
|
8198
|
+
});
|
|
7770
8199
|
} catch (error) {
|
|
7771
8200
|
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
7772
8201
|
throw new Error(`Failed to evaluate value_js: ${errorMsg}`);
|
|
@@ -7781,16 +8210,12 @@ var init_memory_check_provider = __esm({
|
|
|
7781
8210
|
this.sandbox = this.createSecureSandbox();
|
|
7782
8211
|
}
|
|
7783
8212
|
try {
|
|
7784
|
-
const
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
};
|
|
7791
|
-
const exec = this.sandbox.compile(script);
|
|
7792
|
-
const result = exec(scope).run();
|
|
7793
|
-
return result;
|
|
8213
|
+
const scope = { ...context };
|
|
8214
|
+
return compileAndRun(this.sandbox, script, scope, {
|
|
8215
|
+
injectLog: true,
|
|
8216
|
+
wrapFunction: false,
|
|
8217
|
+
logPrefix: "[memory:exec_js]"
|
|
8218
|
+
});
|
|
7794
8219
|
} catch (error) {
|
|
7795
8220
|
const errorMsg = error instanceof Error ? error.message : "Unknown error";
|
|
7796
8221
|
logger.error(`[memory-js] Script execution error: ${errorMsg}`);
|
|
@@ -7879,7 +8304,7 @@ var init_memory_check_provider = __esm({
|
|
|
7879
8304
|
});
|
|
7880
8305
|
|
|
7881
8306
|
// src/providers/mcp-check-provider.ts
|
|
7882
|
-
var import_client, import_stdio, import_sse, import_streamableHttp,
|
|
8307
|
+
var import_client, import_stdio, import_sse, import_streamableHttp, McpCheckProvider;
|
|
7883
8308
|
var init_mcp_check_provider = __esm({
|
|
7884
8309
|
"src/providers/mcp-check-provider.ts"() {
|
|
7885
8310
|
"use strict";
|
|
@@ -7890,7 +8315,7 @@ var init_mcp_check_provider = __esm({
|
|
|
7890
8315
|
import_stdio = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
7891
8316
|
import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
7892
8317
|
import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
7893
|
-
|
|
8318
|
+
init_sandbox();
|
|
7894
8319
|
McpCheckProvider = class extends CheckProvider {
|
|
7895
8320
|
liquid;
|
|
7896
8321
|
sandbox;
|
|
@@ -7909,67 +8334,7 @@ var init_mcp_check_provider = __esm({
|
|
|
7909
8334
|
* - No access to filesystem, network, or system resources
|
|
7910
8335
|
*/
|
|
7911
8336
|
createSecureSandbox() {
|
|
7912
|
-
|
|
7913
|
-
logger.debug(`[transform_js] ${args.map((a) => JSON.stringify(a)).join(" ")}`);
|
|
7914
|
-
};
|
|
7915
|
-
const globals = {
|
|
7916
|
-
...import_sandboxjs4.default.SAFE_GLOBALS,
|
|
7917
|
-
// Excludes Function, eval, require, process, etc.
|
|
7918
|
-
Math,
|
|
7919
|
-
JSON,
|
|
7920
|
-
console: {
|
|
7921
|
-
log: log2
|
|
7922
|
-
}
|
|
7923
|
-
};
|
|
7924
|
-
const prototypeWhitelist = new Map(import_sandboxjs4.default.SAFE_PROTOTYPES);
|
|
7925
|
-
const arrayMethods = /* @__PURE__ */ new Set([
|
|
7926
|
-
"some",
|
|
7927
|
-
"every",
|
|
7928
|
-
"filter",
|
|
7929
|
-
"map",
|
|
7930
|
-
"reduce",
|
|
7931
|
-
"find",
|
|
7932
|
-
"includes",
|
|
7933
|
-
"indexOf",
|
|
7934
|
-
"length",
|
|
7935
|
-
"slice",
|
|
7936
|
-
"concat",
|
|
7937
|
-
"join",
|
|
7938
|
-
"push",
|
|
7939
|
-
"pop",
|
|
7940
|
-
"shift",
|
|
7941
|
-
"unshift",
|
|
7942
|
-
"sort",
|
|
7943
|
-
"reverse",
|
|
7944
|
-
"flat",
|
|
7945
|
-
"flatMap"
|
|
7946
|
-
]);
|
|
7947
|
-
prototypeWhitelist.set(Array.prototype, arrayMethods);
|
|
7948
|
-
const stringMethods = /* @__PURE__ */ new Set([
|
|
7949
|
-
"toLowerCase",
|
|
7950
|
-
"toUpperCase",
|
|
7951
|
-
"includes",
|
|
7952
|
-
"indexOf",
|
|
7953
|
-
"startsWith",
|
|
7954
|
-
"endsWith",
|
|
7955
|
-
"slice",
|
|
7956
|
-
"substring",
|
|
7957
|
-
"length",
|
|
7958
|
-
"trim",
|
|
7959
|
-
"split",
|
|
7960
|
-
"replace",
|
|
7961
|
-
// String.prototype.replace for text manipulation (e.g., "hello".replace("h", "H"))
|
|
7962
|
-
"match",
|
|
7963
|
-
"padStart",
|
|
7964
|
-
"padEnd"
|
|
7965
|
-
]);
|
|
7966
|
-
prototypeWhitelist.set(String.prototype, stringMethods);
|
|
7967
|
-
const objectMethods = /* @__PURE__ */ new Set(["hasOwnProperty", "toString", "valueOf", "keys", "values"]);
|
|
7968
|
-
prototypeWhitelist.set(Object.prototype, objectMethods);
|
|
7969
|
-
return new import_sandboxjs4.default({
|
|
7970
|
-
globals,
|
|
7971
|
-
prototypeWhitelist
|
|
7972
|
-
});
|
|
8337
|
+
return createSecureSandbox();
|
|
7973
8338
|
}
|
|
7974
8339
|
getName() {
|
|
7975
8340
|
return "mcp";
|
|
@@ -8098,8 +8463,12 @@ var init_mcp_check_provider = __esm({
|
|
|
8098
8463
|
outputs: templateContext.outputs,
|
|
8099
8464
|
env: templateContext.env
|
|
8100
8465
|
};
|
|
8101
|
-
|
|
8102
|
-
|
|
8466
|
+
finalOutput = compileAndRun(
|
|
8467
|
+
this.sandbox,
|
|
8468
|
+
`return (${cfg.transform_js});`,
|
|
8469
|
+
scope,
|
|
8470
|
+
{ injectLog: true, wrapFunction: false, logPrefix: "[mcp:transform_js]" }
|
|
8471
|
+
);
|
|
8103
8472
|
} catch (error) {
|
|
8104
8473
|
logger.error(`Failed to apply JavaScript transform: ${error}`);
|
|
8105
8474
|
return {
|
|
@@ -8412,44 +8781,538 @@ var init_mcp_check_provider = __esm({
|
|
|
8412
8781
|
replacement: replacement || void 0
|
|
8413
8782
|
};
|
|
8414
8783
|
}
|
|
8415
|
-
toTrimmedString(value) {
|
|
8416
|
-
if (typeof value === "string") {
|
|
8417
|
-
const trimmed = value.trim();
|
|
8418
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
8784
|
+
toTrimmedString(value) {
|
|
8785
|
+
if (typeof value === "string") {
|
|
8786
|
+
const trimmed = value.trim();
|
|
8787
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
8788
|
+
}
|
|
8789
|
+
if (value !== null && value !== void 0 && typeof value.toString === "function") {
|
|
8790
|
+
const converted = String(value).trim();
|
|
8791
|
+
return converted.length > 0 ? converted : null;
|
|
8792
|
+
}
|
|
8793
|
+
return null;
|
|
8794
|
+
}
|
|
8795
|
+
toNumber(value) {
|
|
8796
|
+
if (value === null || value === void 0) {
|
|
8797
|
+
return null;
|
|
8798
|
+
}
|
|
8799
|
+
const num = Number(value);
|
|
8800
|
+
if (Number.isFinite(num)) {
|
|
8801
|
+
return Math.trunc(num);
|
|
8802
|
+
}
|
|
8803
|
+
return null;
|
|
8804
|
+
}
|
|
8805
|
+
getSupportedConfigKeys() {
|
|
8806
|
+
return [
|
|
8807
|
+
"type",
|
|
8808
|
+
"transport",
|
|
8809
|
+
"command",
|
|
8810
|
+
"args",
|
|
8811
|
+
"env",
|
|
8812
|
+
"workingDirectory",
|
|
8813
|
+
"url",
|
|
8814
|
+
"headers",
|
|
8815
|
+
"sessionId",
|
|
8816
|
+
"method",
|
|
8817
|
+
"methodArgs",
|
|
8818
|
+
"argsTransform",
|
|
8819
|
+
"transform",
|
|
8820
|
+
"transform_js",
|
|
8821
|
+
"timeout",
|
|
8822
|
+
"depends_on",
|
|
8823
|
+
"on",
|
|
8824
|
+
"if",
|
|
8825
|
+
"group"
|
|
8826
|
+
];
|
|
8827
|
+
}
|
|
8828
|
+
async isAvailable() {
|
|
8829
|
+
return true;
|
|
8830
|
+
}
|
|
8831
|
+
getRequirements() {
|
|
8832
|
+
return ["MCP method name specified", "Transport configuration (stdio: command, sse/http: url)"];
|
|
8833
|
+
}
|
|
8834
|
+
};
|
|
8835
|
+
}
|
|
8836
|
+
});
|
|
8837
|
+
|
|
8838
|
+
// src/utils/interactive-prompt.ts
|
|
8839
|
+
function formatTime(ms) {
|
|
8840
|
+
const seconds = Math.ceil(ms / 1e3);
|
|
8841
|
+
const mins = Math.floor(seconds / 60);
|
|
8842
|
+
const secs = seconds % 60;
|
|
8843
|
+
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
8844
|
+
}
|
|
8845
|
+
function drawLine(char, width) {
|
|
8846
|
+
return char.repeat(width);
|
|
8847
|
+
}
|
|
8848
|
+
function wrapText(text, width) {
|
|
8849
|
+
const words = text.split(" ");
|
|
8850
|
+
const lines = [];
|
|
8851
|
+
let currentLine = "";
|
|
8852
|
+
for (const word of words) {
|
|
8853
|
+
if (currentLine.length + word.length + 1 <= width) {
|
|
8854
|
+
currentLine += (currentLine ? " " : "") + word;
|
|
8855
|
+
} else {
|
|
8856
|
+
if (currentLine) lines.push(currentLine);
|
|
8857
|
+
currentLine = word;
|
|
8858
|
+
}
|
|
8859
|
+
}
|
|
8860
|
+
if (currentLine) lines.push(currentLine);
|
|
8861
|
+
return lines;
|
|
8862
|
+
}
|
|
8863
|
+
function displayPromptUI(options, remainingMs) {
|
|
8864
|
+
const width = Math.min(process.stdout.columns || 80, 80) - 4;
|
|
8865
|
+
const icon = supportsUnicode ? "\u{1F4AC}" : ">";
|
|
8866
|
+
console.log("\n");
|
|
8867
|
+
console.log(`${box.topLeft}${drawLine(box.horizontal, width + 2)}${box.topRight}`);
|
|
8868
|
+
console.log(
|
|
8869
|
+
`${box.vertical} ${colors.bold}${icon} Human Input Required${colors.reset}${" ".repeat(
|
|
8870
|
+
width - 22
|
|
8871
|
+
)} ${box.vertical}`
|
|
8872
|
+
);
|
|
8873
|
+
console.log(`${box.leftT}${drawLine(box.horizontal, width + 2)}${box.rightT}`);
|
|
8874
|
+
console.log(`${box.vertical} ${" ".repeat(width)} ${box.vertical}`);
|
|
8875
|
+
const promptLines = wrapText(options.prompt, width - 2);
|
|
8876
|
+
for (const line of promptLines) {
|
|
8877
|
+
console.log(
|
|
8878
|
+
`${box.vertical} ${colors.cyan}${line}${colors.reset}${" ".repeat(
|
|
8879
|
+
width - line.length
|
|
8880
|
+
)} ${box.vertical}`
|
|
8881
|
+
);
|
|
8882
|
+
}
|
|
8883
|
+
console.log(`${box.vertical} ${" ".repeat(width)} ${box.vertical}`);
|
|
8884
|
+
const instruction = options.multiline ? "(Type your response, press Ctrl+D when done)" : "(Type your response and press Enter)";
|
|
8885
|
+
console.log(
|
|
8886
|
+
`${box.vertical} ${colors.dim}${instruction}${colors.reset}${" ".repeat(
|
|
8887
|
+
width - instruction.length
|
|
8888
|
+
)} ${box.vertical}`
|
|
8889
|
+
);
|
|
8890
|
+
if (options.placeholder && !options.multiline) {
|
|
8891
|
+
console.log(
|
|
8892
|
+
`${box.vertical} ${colors.dim}${options.placeholder}${colors.reset}${" ".repeat(
|
|
8893
|
+
width - options.placeholder.length
|
|
8894
|
+
)} ${box.vertical}`
|
|
8895
|
+
);
|
|
8896
|
+
}
|
|
8897
|
+
console.log(`${box.vertical} ${" ".repeat(width)} ${box.vertical}`);
|
|
8898
|
+
if (remainingMs !== void 0 && options.timeout) {
|
|
8899
|
+
const timeIcon = supportsUnicode ? "\u23F1 " : "Time: ";
|
|
8900
|
+
const timeStr = `${timeIcon} ${formatTime(remainingMs)} remaining`;
|
|
8901
|
+
console.log(
|
|
8902
|
+
`${box.vertical} ${colors.yellow}${timeStr}${colors.reset}${" ".repeat(
|
|
8903
|
+
width - timeStr.length
|
|
8904
|
+
)} ${box.vertical}`
|
|
8905
|
+
);
|
|
8906
|
+
}
|
|
8907
|
+
console.log(`${box.bottomLeft}${drawLine(box.horizontal, width + 2)}${box.bottomRight}`);
|
|
8908
|
+
console.log("");
|
|
8909
|
+
process.stdout.write(`${colors.green}>${colors.reset} `);
|
|
8910
|
+
}
|
|
8911
|
+
async function interactivePrompt(options) {
|
|
8912
|
+
return new Promise((resolve7, reject) => {
|
|
8913
|
+
let input = "";
|
|
8914
|
+
let timeoutId;
|
|
8915
|
+
let countdownInterval;
|
|
8916
|
+
let remainingMs = options.timeout;
|
|
8917
|
+
const rl = readline.createInterface({
|
|
8918
|
+
input: process.stdin,
|
|
8919
|
+
output: process.stdout,
|
|
8920
|
+
terminal: true
|
|
8921
|
+
});
|
|
8922
|
+
displayPromptUI(options, remainingMs);
|
|
8923
|
+
const cleanup = () => {
|
|
8924
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
8925
|
+
if (countdownInterval) clearInterval(countdownInterval);
|
|
8926
|
+
rl.close();
|
|
8927
|
+
};
|
|
8928
|
+
const finish = (value) => {
|
|
8929
|
+
cleanup();
|
|
8930
|
+
console.log("");
|
|
8931
|
+
resolve7(value);
|
|
8932
|
+
};
|
|
8933
|
+
if (options.timeout) {
|
|
8934
|
+
timeoutId = setTimeout(() => {
|
|
8935
|
+
cleanup();
|
|
8936
|
+
console.log(`
|
|
8937
|
+
${colors.yellow}\u23F1 Timeout reached${colors.reset}`);
|
|
8938
|
+
if (options.defaultValue !== void 0) {
|
|
8939
|
+
console.log(
|
|
8940
|
+
`${colors.gray}Using default value: ${options.defaultValue}${colors.reset}
|
|
8941
|
+
`
|
|
8942
|
+
);
|
|
8943
|
+
resolve7(options.defaultValue);
|
|
8944
|
+
} else {
|
|
8945
|
+
reject(new Error("Input timeout"));
|
|
8946
|
+
}
|
|
8947
|
+
}, options.timeout);
|
|
8948
|
+
if (remainingMs) {
|
|
8949
|
+
countdownInterval = setInterval(() => {
|
|
8950
|
+
remainingMs = remainingMs - 1e3;
|
|
8951
|
+
if (remainingMs <= 0) {
|
|
8952
|
+
if (countdownInterval) clearInterval(countdownInterval);
|
|
8953
|
+
}
|
|
8954
|
+
}, 1e3);
|
|
8955
|
+
}
|
|
8956
|
+
}
|
|
8957
|
+
if (options.multiline) {
|
|
8958
|
+
rl.on("line", (line) => {
|
|
8959
|
+
input += (input ? "\n" : "") + line;
|
|
8960
|
+
});
|
|
8961
|
+
rl.on("close", () => {
|
|
8962
|
+
cleanup();
|
|
8963
|
+
const trimmed = input.trim();
|
|
8964
|
+
if (!trimmed && !options.allowEmpty) {
|
|
8965
|
+
console.log(`${colors.yellow}\u26A0 Empty input not allowed${colors.reset}`);
|
|
8966
|
+
reject(new Error("Empty input not allowed"));
|
|
8967
|
+
} else {
|
|
8968
|
+
finish(trimmed);
|
|
8969
|
+
}
|
|
8970
|
+
});
|
|
8971
|
+
} else {
|
|
8972
|
+
rl.question("", (answer) => {
|
|
8973
|
+
const trimmed = answer.trim();
|
|
8974
|
+
if (!trimmed && !options.allowEmpty && !options.defaultValue) {
|
|
8975
|
+
cleanup();
|
|
8976
|
+
console.log(`${colors.yellow}\u26A0 Empty input not allowed${colors.reset}`);
|
|
8977
|
+
reject(new Error("Empty input not allowed"));
|
|
8978
|
+
} else {
|
|
8979
|
+
finish(trimmed || options.defaultValue || "");
|
|
8980
|
+
}
|
|
8981
|
+
});
|
|
8982
|
+
}
|
|
8983
|
+
rl.on("SIGINT", () => {
|
|
8984
|
+
cleanup();
|
|
8985
|
+
console.log("\n\n" + colors.yellow + "\u26A0 Cancelled by user" + colors.reset);
|
|
8986
|
+
reject(new Error("Cancelled by user"));
|
|
8987
|
+
});
|
|
8988
|
+
});
|
|
8989
|
+
}
|
|
8990
|
+
async function simplePrompt(prompt) {
|
|
8991
|
+
return new Promise((resolve7) => {
|
|
8992
|
+
const rl = readline.createInterface({
|
|
8993
|
+
input: process.stdin,
|
|
8994
|
+
output: process.stdout
|
|
8995
|
+
});
|
|
8996
|
+
rl.question(`${prompt}
|
|
8997
|
+
> `, (answer) => {
|
|
8998
|
+
rl.close();
|
|
8999
|
+
resolve7(answer.trim());
|
|
9000
|
+
});
|
|
9001
|
+
});
|
|
9002
|
+
}
|
|
9003
|
+
var readline, colors, supportsUnicode, box;
|
|
9004
|
+
var init_interactive_prompt = __esm({
|
|
9005
|
+
"src/utils/interactive-prompt.ts"() {
|
|
9006
|
+
"use strict";
|
|
9007
|
+
readline = __toESM(require("readline"));
|
|
9008
|
+
colors = {
|
|
9009
|
+
reset: "\x1B[0m",
|
|
9010
|
+
dim: "\x1B[2m",
|
|
9011
|
+
bold: "\x1B[1m",
|
|
9012
|
+
cyan: "\x1B[36m",
|
|
9013
|
+
green: "\x1B[32m",
|
|
9014
|
+
yellow: "\x1B[33m",
|
|
9015
|
+
gray: "\x1B[90m"
|
|
9016
|
+
};
|
|
9017
|
+
supportsUnicode = process.env.LANG?.includes("UTF-8") || process.platform === "darwin";
|
|
9018
|
+
box = supportsUnicode ? {
|
|
9019
|
+
topLeft: "\u250C",
|
|
9020
|
+
topRight: "\u2510",
|
|
9021
|
+
bottomLeft: "\u2514",
|
|
9022
|
+
bottomRight: "\u2518",
|
|
9023
|
+
horizontal: "\u2500",
|
|
9024
|
+
vertical: "\u2502",
|
|
9025
|
+
leftT: "\u251C",
|
|
9026
|
+
rightT: "\u2524"
|
|
9027
|
+
} : {
|
|
9028
|
+
topLeft: "+",
|
|
9029
|
+
topRight: "+",
|
|
9030
|
+
bottomLeft: "+",
|
|
9031
|
+
bottomRight: "+",
|
|
9032
|
+
horizontal: "-",
|
|
9033
|
+
vertical: "|",
|
|
9034
|
+
leftT: "+",
|
|
9035
|
+
rightT: "+"
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
9038
|
+
});
|
|
9039
|
+
|
|
9040
|
+
// src/utils/stdin-reader.ts
|
|
9041
|
+
function isStdinAvailable() {
|
|
9042
|
+
return !process.stdin.isTTY;
|
|
9043
|
+
}
|
|
9044
|
+
async function readStdin(timeout, maxSize = 1024 * 1024) {
|
|
9045
|
+
return new Promise((resolve7, reject) => {
|
|
9046
|
+
let data = "";
|
|
9047
|
+
let timeoutId;
|
|
9048
|
+
if (timeout) {
|
|
9049
|
+
timeoutId = setTimeout(() => {
|
|
9050
|
+
cleanup();
|
|
9051
|
+
reject(new Error(`Stdin read timeout after ${timeout}ms`));
|
|
9052
|
+
}, timeout);
|
|
9053
|
+
}
|
|
9054
|
+
const cleanup = () => {
|
|
9055
|
+
if (timeoutId) {
|
|
9056
|
+
clearTimeout(timeoutId);
|
|
9057
|
+
}
|
|
9058
|
+
process.stdin.removeListener("data", onData);
|
|
9059
|
+
process.stdin.removeListener("end", onEnd);
|
|
9060
|
+
process.stdin.removeListener("error", onError);
|
|
9061
|
+
process.stdin.pause();
|
|
9062
|
+
};
|
|
9063
|
+
const onData = (chunk) => {
|
|
9064
|
+
data += chunk.toString();
|
|
9065
|
+
if (data.length > maxSize) {
|
|
9066
|
+
cleanup();
|
|
9067
|
+
reject(new Error(`Input exceeds maximum size of ${maxSize} bytes`));
|
|
9068
|
+
}
|
|
9069
|
+
};
|
|
9070
|
+
const onEnd = () => {
|
|
9071
|
+
cleanup();
|
|
9072
|
+
resolve7(data.trim());
|
|
9073
|
+
};
|
|
9074
|
+
const onError = (err) => {
|
|
9075
|
+
cleanup();
|
|
9076
|
+
reject(err);
|
|
9077
|
+
};
|
|
9078
|
+
process.stdin.setEncoding("utf8");
|
|
9079
|
+
process.stdin.on("data", onData);
|
|
9080
|
+
process.stdin.on("end", onEnd);
|
|
9081
|
+
process.stdin.on("error", onError);
|
|
9082
|
+
process.stdin.resume();
|
|
9083
|
+
});
|
|
9084
|
+
}
|
|
9085
|
+
async function tryReadStdin(timeout, maxSize = 1024 * 1024) {
|
|
9086
|
+
if (!isStdinAvailable()) {
|
|
9087
|
+
return null;
|
|
9088
|
+
}
|
|
9089
|
+
try {
|
|
9090
|
+
return await readStdin(timeout, maxSize);
|
|
9091
|
+
} catch {
|
|
9092
|
+
return null;
|
|
9093
|
+
}
|
|
9094
|
+
}
|
|
9095
|
+
var init_stdin_reader = __esm({
|
|
9096
|
+
"src/utils/stdin-reader.ts"() {
|
|
9097
|
+
"use strict";
|
|
9098
|
+
}
|
|
9099
|
+
});
|
|
9100
|
+
|
|
9101
|
+
// src/providers/human-input-check-provider.ts
|
|
9102
|
+
var fs10, path12, HumanInputCheckProvider;
|
|
9103
|
+
var init_human_input_check_provider = __esm({
|
|
9104
|
+
"src/providers/human-input-check-provider.ts"() {
|
|
9105
|
+
"use strict";
|
|
9106
|
+
init_check_provider_interface();
|
|
9107
|
+
init_interactive_prompt();
|
|
9108
|
+
init_stdin_reader();
|
|
9109
|
+
fs10 = __toESM(require("fs"));
|
|
9110
|
+
path12 = __toESM(require("path"));
|
|
9111
|
+
HumanInputCheckProvider = class _HumanInputCheckProvider extends CheckProvider {
|
|
9112
|
+
/**
|
|
9113
|
+
* @deprecated Use ExecutionContext.cliMessage instead
|
|
9114
|
+
* Kept for backward compatibility
|
|
9115
|
+
*/
|
|
9116
|
+
static cliMessage;
|
|
9117
|
+
/**
|
|
9118
|
+
* @deprecated Use ExecutionContext.hooks instead
|
|
9119
|
+
* Kept for backward compatibility
|
|
9120
|
+
*/
|
|
9121
|
+
static hooks = {};
|
|
9122
|
+
/**
|
|
9123
|
+
* Set the CLI message value (from --message argument)
|
|
9124
|
+
* @deprecated Use ExecutionContext.cliMessage instead
|
|
9125
|
+
*/
|
|
9126
|
+
static setCLIMessage(message) {
|
|
9127
|
+
_HumanInputCheckProvider.cliMessage = message;
|
|
9128
|
+
}
|
|
9129
|
+
/**
|
|
9130
|
+
* Get the current CLI message value
|
|
9131
|
+
* @deprecated Use ExecutionContext.cliMessage instead
|
|
9132
|
+
*/
|
|
9133
|
+
static getCLIMessage() {
|
|
9134
|
+
return _HumanInputCheckProvider.cliMessage;
|
|
9135
|
+
}
|
|
9136
|
+
/**
|
|
9137
|
+
* Set hooks for SDK mode
|
|
9138
|
+
* @deprecated Use ExecutionContext.hooks instead
|
|
9139
|
+
*/
|
|
9140
|
+
static setHooks(hooks) {
|
|
9141
|
+
_HumanInputCheckProvider.hooks = hooks;
|
|
9142
|
+
}
|
|
9143
|
+
getName() {
|
|
9144
|
+
return "human-input";
|
|
9145
|
+
}
|
|
9146
|
+
getDescription() {
|
|
9147
|
+
return "Prompts for human input during workflow execution (CLI interactive or SDK hook)";
|
|
9148
|
+
}
|
|
9149
|
+
async validateConfig(config) {
|
|
9150
|
+
if (!config || typeof config !== "object") {
|
|
9151
|
+
return false;
|
|
9152
|
+
}
|
|
9153
|
+
const cfg = config;
|
|
9154
|
+
if (cfg.type !== "human-input") {
|
|
9155
|
+
return false;
|
|
9156
|
+
}
|
|
9157
|
+
if (!cfg.prompt || typeof cfg.prompt !== "string") {
|
|
9158
|
+
console.error('human-input check requires a "prompt" field');
|
|
9159
|
+
return false;
|
|
9160
|
+
}
|
|
9161
|
+
return true;
|
|
9162
|
+
}
|
|
9163
|
+
/**
|
|
9164
|
+
* Check if a string looks like a file path
|
|
9165
|
+
*/
|
|
9166
|
+
looksLikePath(str) {
|
|
9167
|
+
return str.includes("/") || str.includes("\\");
|
|
9168
|
+
}
|
|
9169
|
+
/**
|
|
9170
|
+
* Sanitize user input to prevent injection attacks in dependent checks
|
|
9171
|
+
* Removes potentially dangerous characters while preserving useful input
|
|
9172
|
+
*/
|
|
9173
|
+
sanitizeInput(input) {
|
|
9174
|
+
let sanitized = input.replace(/\0/g, "");
|
|
9175
|
+
sanitized = sanitized.replace(/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/g, "");
|
|
9176
|
+
const maxLength = 100 * 1024;
|
|
9177
|
+
if (sanitized.length > maxLength) {
|
|
9178
|
+
sanitized = sanitized.substring(0, maxLength);
|
|
8419
9179
|
}
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
9180
|
+
return sanitized;
|
|
9181
|
+
}
|
|
9182
|
+
/**
|
|
9183
|
+
* Try to read message from file if it exists
|
|
9184
|
+
* Validates path to prevent directory traversal attacks
|
|
9185
|
+
*/
|
|
9186
|
+
async tryReadFile(filePath) {
|
|
9187
|
+
try {
|
|
9188
|
+
const absolutePath = path12.isAbsolute(filePath) ? filePath : path12.resolve(process.cwd(), filePath);
|
|
9189
|
+
const normalizedPath = path12.normalize(absolutePath);
|
|
9190
|
+
const cwd = process.cwd();
|
|
9191
|
+
if (!normalizedPath.startsWith(cwd + path12.sep) && normalizedPath !== cwd) {
|
|
9192
|
+
return null;
|
|
9193
|
+
}
|
|
9194
|
+
try {
|
|
9195
|
+
await fs10.promises.access(normalizedPath, fs10.constants.R_OK);
|
|
9196
|
+
const stats = await fs10.promises.stat(normalizedPath);
|
|
9197
|
+
if (!stats.isFile()) {
|
|
9198
|
+
return null;
|
|
9199
|
+
}
|
|
9200
|
+
const content = await fs10.promises.readFile(normalizedPath, "utf-8");
|
|
9201
|
+
return content.trim();
|
|
9202
|
+
} catch {
|
|
9203
|
+
return null;
|
|
9204
|
+
}
|
|
9205
|
+
} catch {
|
|
8423
9206
|
}
|
|
8424
9207
|
return null;
|
|
8425
9208
|
}
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
9209
|
+
/**
|
|
9210
|
+
* Get user input through various methods
|
|
9211
|
+
*/
|
|
9212
|
+
async getUserInput(checkName, config, context) {
|
|
9213
|
+
const prompt = config.prompt || "Please provide input:";
|
|
9214
|
+
const placeholder = config.placeholder || "Enter your response...";
|
|
9215
|
+
const allowEmpty = config.allow_empty ?? false;
|
|
9216
|
+
const multiline = config.multiline ?? false;
|
|
9217
|
+
const timeout = config.timeout ? config.timeout * 1e3 : void 0;
|
|
9218
|
+
const defaultValue = config.default;
|
|
9219
|
+
const cliMessage = context?.cliMessage ?? _HumanInputCheckProvider.cliMessage;
|
|
9220
|
+
if (cliMessage !== void 0) {
|
|
9221
|
+
const message = cliMessage;
|
|
9222
|
+
if (this.looksLikePath(message)) {
|
|
9223
|
+
const fileContent = await this.tryReadFile(message);
|
|
9224
|
+
if (fileContent !== null) {
|
|
9225
|
+
return fileContent;
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9228
|
+
return message;
|
|
8429
9229
|
}
|
|
8430
|
-
const
|
|
8431
|
-
if (
|
|
8432
|
-
return
|
|
9230
|
+
const stdinInput = await tryReadStdin(timeout);
|
|
9231
|
+
if (stdinInput !== null && stdinInput.length > 0) {
|
|
9232
|
+
return stdinInput;
|
|
9233
|
+
}
|
|
9234
|
+
const hooks = context?.hooks ?? _HumanInputCheckProvider.hooks;
|
|
9235
|
+
if (hooks?.onHumanInput) {
|
|
9236
|
+
const request = {
|
|
9237
|
+
checkId: checkName,
|
|
9238
|
+
prompt,
|
|
9239
|
+
placeholder,
|
|
9240
|
+
allowEmpty,
|
|
9241
|
+
multiline,
|
|
9242
|
+
timeout,
|
|
9243
|
+
default: defaultValue
|
|
9244
|
+
};
|
|
9245
|
+
try {
|
|
9246
|
+
const result = await hooks.onHumanInput(request);
|
|
9247
|
+
return result;
|
|
9248
|
+
} catch (error) {
|
|
9249
|
+
throw new Error(
|
|
9250
|
+
`Hook onHumanInput failed: ${error instanceof Error ? error.message : String(error)}`
|
|
9251
|
+
);
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
if (process.stdin.isTTY) {
|
|
9255
|
+
try {
|
|
9256
|
+
const result = await interactivePrompt({
|
|
9257
|
+
prompt,
|
|
9258
|
+
placeholder,
|
|
9259
|
+
multiline,
|
|
9260
|
+
timeout,
|
|
9261
|
+
defaultValue,
|
|
9262
|
+
allowEmpty
|
|
9263
|
+
});
|
|
9264
|
+
return result;
|
|
9265
|
+
} catch (error) {
|
|
9266
|
+
throw new Error(
|
|
9267
|
+
`Interactive prompt failed: ${error instanceof Error ? error.message : String(error)}`
|
|
9268
|
+
);
|
|
9269
|
+
}
|
|
9270
|
+
}
|
|
9271
|
+
try {
|
|
9272
|
+
const result = await simplePrompt(prompt);
|
|
9273
|
+
if (!result && !allowEmpty && !defaultValue) {
|
|
9274
|
+
throw new Error("Empty input not allowed");
|
|
9275
|
+
}
|
|
9276
|
+
return result || defaultValue || "";
|
|
9277
|
+
} catch (error) {
|
|
9278
|
+
throw new Error(
|
|
9279
|
+
`Simple prompt failed: ${error instanceof Error ? error.message : String(error)}`
|
|
9280
|
+
);
|
|
9281
|
+
}
|
|
9282
|
+
}
|
|
9283
|
+
async execute(_prInfo, config, _dependencyResults, context) {
|
|
9284
|
+
const checkName = config.checkName || "human-input";
|
|
9285
|
+
try {
|
|
9286
|
+
const userInput = await this.getUserInput(checkName, config, context);
|
|
9287
|
+
const sanitizedInput = this.sanitizeInput(userInput);
|
|
9288
|
+
return {
|
|
9289
|
+
issues: [],
|
|
9290
|
+
output: sanitizedInput
|
|
9291
|
+
};
|
|
9292
|
+
} catch (error) {
|
|
9293
|
+
return {
|
|
9294
|
+
issues: [
|
|
9295
|
+
{
|
|
9296
|
+
file: "",
|
|
9297
|
+
line: 0,
|
|
9298
|
+
ruleId: "human-input-error",
|
|
9299
|
+
message: `Failed to get user input: ${error instanceof Error ? error.message : String(error)}`,
|
|
9300
|
+
severity: "error",
|
|
9301
|
+
category: "logic"
|
|
9302
|
+
}
|
|
9303
|
+
]
|
|
9304
|
+
};
|
|
8433
9305
|
}
|
|
8434
|
-
return null;
|
|
8435
9306
|
}
|
|
8436
9307
|
getSupportedConfigKeys() {
|
|
8437
9308
|
return [
|
|
8438
9309
|
"type",
|
|
8439
|
-
"
|
|
8440
|
-
"
|
|
8441
|
-
"
|
|
8442
|
-
"
|
|
8443
|
-
"workingDirectory",
|
|
8444
|
-
"url",
|
|
8445
|
-
"headers",
|
|
8446
|
-
"sessionId",
|
|
8447
|
-
"method",
|
|
8448
|
-
"methodArgs",
|
|
8449
|
-
"argsTransform",
|
|
8450
|
-
"transform",
|
|
8451
|
-
"transform_js",
|
|
9310
|
+
"prompt",
|
|
9311
|
+
"placeholder",
|
|
9312
|
+
"allow_empty",
|
|
9313
|
+
"multiline",
|
|
8452
9314
|
"timeout",
|
|
9315
|
+
"default",
|
|
8453
9316
|
"depends_on",
|
|
8454
9317
|
"on",
|
|
8455
9318
|
"if",
|
|
@@ -8460,7 +9323,11 @@ var init_mcp_check_provider = __esm({
|
|
|
8460
9323
|
return true;
|
|
8461
9324
|
}
|
|
8462
9325
|
getRequirements() {
|
|
8463
|
-
return [
|
|
9326
|
+
return [
|
|
9327
|
+
"No external dependencies required",
|
|
9328
|
+
"Works in CLI mode with --message argument, piped stdin, or interactive prompts",
|
|
9329
|
+
"SDK mode requires onHumanInput hook to be configured"
|
|
9330
|
+
];
|
|
8464
9331
|
}
|
|
8465
9332
|
};
|
|
8466
9333
|
}
|
|
@@ -8482,6 +9349,7 @@ var init_check_provider_registry = __esm({
|
|
|
8482
9349
|
init_command_check_provider();
|
|
8483
9350
|
init_memory_check_provider();
|
|
8484
9351
|
init_mcp_check_provider();
|
|
9352
|
+
init_human_input_check_provider();
|
|
8485
9353
|
CheckProviderRegistry = class _CheckProviderRegistry {
|
|
8486
9354
|
providers = /* @__PURE__ */ new Map();
|
|
8487
9355
|
static instance;
|
|
@@ -8510,6 +9378,7 @@ var init_check_provider_registry = __esm({
|
|
|
8510
9378
|
this.register(new LogCheckProvider());
|
|
8511
9379
|
this.register(new MemoryCheckProvider());
|
|
8512
9380
|
this.register(new GitHubOpsProvider());
|
|
9381
|
+
this.register(new HumanInputCheckProvider());
|
|
8513
9382
|
try {
|
|
8514
9383
|
this.register(new ClaudeCodeCheckProvider());
|
|
8515
9384
|
} catch (error) {
|
|
@@ -8821,80 +9690,37 @@ var init_dependency_resolver = __esm({
|
|
|
8821
9690
|
}
|
|
8822
9691
|
});
|
|
8823
9692
|
|
|
8824
|
-
// src/telemetry/
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
emitNdjsonFallback: () => emitNdjsonFallback,
|
|
8828
|
-
emitNdjsonSpanWithEvents: () => emitNdjsonSpanWithEvents,
|
|
8829
|
-
flushNdjson: () => flushNdjson
|
|
8830
|
-
});
|
|
8831
|
-
function resolveTargetPath(outDir) {
|
|
8832
|
-
if (process.env.VISOR_FALLBACK_TRACE_FILE) {
|
|
8833
|
-
CURRENT_FILE = process.env.VISOR_FALLBACK_TRACE_FILE;
|
|
8834
|
-
return CURRENT_FILE;
|
|
8835
|
-
}
|
|
8836
|
-
if (CURRENT_FILE) return CURRENT_FILE;
|
|
8837
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
8838
|
-
CURRENT_FILE = path9.join(outDir, `${ts}.ndjson`);
|
|
8839
|
-
return CURRENT_FILE;
|
|
8840
|
-
}
|
|
8841
|
-
function isEnabled() {
|
|
8842
|
-
if (process.env.VISOR_FALLBACK_TRACE_FILE) return true;
|
|
8843
|
-
return process.env.VISOR_TELEMETRY_ENABLED === "true" && (process.env.VISOR_TELEMETRY_SINK || "file") === "file";
|
|
9693
|
+
// src/telemetry/trace-helpers.ts
|
|
9694
|
+
function getTracer() {
|
|
9695
|
+
return import_api4.trace.getTracer("visor");
|
|
8844
9696
|
}
|
|
8845
|
-
function
|
|
8846
|
-
|
|
8847
|
-
|
|
9697
|
+
async function withActiveSpan(name, attrs, fn) {
|
|
9698
|
+
const tracer = getTracer();
|
|
9699
|
+
return await new Promise((resolve7, reject) => {
|
|
9700
|
+
const callback = async (span) => {
|
|
8848
9701
|
try {
|
|
8849
|
-
|
|
8850
|
-
|
|
9702
|
+
const res = await fn(span);
|
|
9703
|
+
resolve7(res);
|
|
9704
|
+
} catch (err) {
|
|
9705
|
+
try {
|
|
9706
|
+
if (err instanceof Error) span.recordException(err);
|
|
9707
|
+
span.setStatus({ code: import_api4.SpanStatusCode.ERROR });
|
|
9708
|
+
} catch {
|
|
9709
|
+
}
|
|
9710
|
+
reject(err);
|
|
9711
|
+
} finally {
|
|
9712
|
+
try {
|
|
9713
|
+
span.end();
|
|
9714
|
+
} catch {
|
|
9715
|
+
}
|
|
8851
9716
|
}
|
|
8852
|
-
|
|
8853
|
-
}
|
|
8854
|
-
|
|
8855
|
-
await fs8.promises.appendFile(target, line, "utf8");
|
|
8856
|
-
}).catch(() => {
|
|
9717
|
+
};
|
|
9718
|
+
const options = attrs ? { attributes: attrs } : {};
|
|
9719
|
+
tracer.startActiveSpan(name, options, callback);
|
|
8857
9720
|
});
|
|
8858
9721
|
}
|
|
8859
|
-
async function flushNdjson() {
|
|
8860
|
-
try {
|
|
8861
|
-
await writeChain;
|
|
8862
|
-
} catch {
|
|
8863
|
-
}
|
|
8864
|
-
}
|
|
8865
|
-
function emitNdjsonFallback(name, attrs) {
|
|
8866
|
-
try {
|
|
8867
|
-
if (!isEnabled()) return;
|
|
8868
|
-
const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
|
|
8869
|
-
const line = JSON.stringify({ name, attributes: attrs }) + "\n";
|
|
8870
|
-
appendAsync(outDir, line);
|
|
8871
|
-
} catch {
|
|
8872
|
-
}
|
|
8873
|
-
}
|
|
8874
|
-
function emitNdjsonSpanWithEvents(name, attrs, events) {
|
|
8875
|
-
try {
|
|
8876
|
-
if (!isEnabled()) return;
|
|
8877
|
-
const outDir = process.env.VISOR_TRACE_DIR || path9.join(process.cwd(), "output", "traces");
|
|
8878
|
-
const line = JSON.stringify({ name, attributes: attrs, events }) + "\n";
|
|
8879
|
-
appendAsync(outDir, line);
|
|
8880
|
-
} catch {
|
|
8881
|
-
}
|
|
8882
|
-
}
|
|
8883
|
-
var fs8, path9, CURRENT_FILE, dirReady, writeChain;
|
|
8884
|
-
var init_fallback_ndjson = __esm({
|
|
8885
|
-
"src/telemetry/fallback-ndjson.ts"() {
|
|
8886
|
-
"use strict";
|
|
8887
|
-
fs8 = __toESM(require("fs"));
|
|
8888
|
-
path9 = __toESM(require("path"));
|
|
8889
|
-
CURRENT_FILE = null;
|
|
8890
|
-
dirReady = false;
|
|
8891
|
-
writeChain = Promise.resolve();
|
|
8892
|
-
}
|
|
8893
|
-
});
|
|
8894
|
-
|
|
8895
|
-
// src/telemetry/trace-helpers.ts
|
|
8896
9722
|
function addEvent(name, attrs) {
|
|
8897
|
-
const span =
|
|
9723
|
+
const span = import_api4.trace.getSpan(import_api4.context.active());
|
|
8898
9724
|
if (span) {
|
|
8899
9725
|
try {
|
|
8900
9726
|
span.addEvent(name, attrs);
|
|
@@ -8913,11 +9739,11 @@ function addEvent(name, attrs) {
|
|
|
8913
9739
|
} catch {
|
|
8914
9740
|
}
|
|
8915
9741
|
}
|
|
8916
|
-
var
|
|
9742
|
+
var import_api4;
|
|
8917
9743
|
var init_trace_helpers = __esm({
|
|
8918
9744
|
"src/telemetry/trace-helpers.ts"() {
|
|
8919
9745
|
"use strict";
|
|
8920
|
-
|
|
9746
|
+
import_api4 = require("@opentelemetry/api");
|
|
8921
9747
|
}
|
|
8922
9748
|
});
|
|
8923
9749
|
|
|
@@ -8972,26 +9798,26 @@ function addDiagramBlock(origin) {
|
|
|
8972
9798
|
} catch {
|
|
8973
9799
|
}
|
|
8974
9800
|
}
|
|
8975
|
-
var
|
|
9801
|
+
var import_api5, initialized, meter, TEST_ENABLED, TEST_SNAPSHOT, checkDurationHist, providerDurationHist, foreachDurationHist, issuesCounter, activeChecks, failIfCounter, diagramBlocks;
|
|
8976
9802
|
var init_metrics = __esm({
|
|
8977
9803
|
"src/telemetry/metrics.ts"() {
|
|
8978
9804
|
"use strict";
|
|
8979
|
-
|
|
9805
|
+
import_api5 = require("@opentelemetry/api");
|
|
8980
9806
|
initialized = false;
|
|
8981
|
-
meter =
|
|
9807
|
+
meter = import_api5.metrics.getMeter("visor");
|
|
8982
9808
|
TEST_ENABLED = process.env.VISOR_TEST_METRICS === "true";
|
|
8983
9809
|
TEST_SNAPSHOT = { fail_if_triggered: 0 };
|
|
8984
9810
|
}
|
|
8985
9811
|
});
|
|
8986
9812
|
|
|
8987
9813
|
// src/failure-condition-evaluator.ts
|
|
8988
|
-
var
|
|
9814
|
+
var FailureConditionEvaluator;
|
|
8989
9815
|
var init_failure_condition_evaluator = __esm({
|
|
8990
9816
|
"src/failure-condition-evaluator.ts"() {
|
|
8991
9817
|
"use strict";
|
|
8992
9818
|
init_trace_helpers();
|
|
8993
9819
|
init_metrics();
|
|
8994
|
-
|
|
9820
|
+
init_sandbox();
|
|
8995
9821
|
init_author_permissions();
|
|
8996
9822
|
init_memory_store();
|
|
8997
9823
|
FailureConditionEvaluator = class _FailureConditionEvaluator {
|
|
@@ -9002,54 +9828,7 @@ var init_failure_condition_evaluator = __esm({
|
|
|
9002
9828
|
* Create a secure sandbox with whitelisted functions and globals
|
|
9003
9829
|
*/
|
|
9004
9830
|
createSecureSandbox() {
|
|
9005
|
-
|
|
9006
|
-
...import_sandboxjs5.default.SAFE_GLOBALS,
|
|
9007
|
-
// Allow Math for calculations
|
|
9008
|
-
Math,
|
|
9009
|
-
// Allow console for debugging (in controlled environment)
|
|
9010
|
-
console: {
|
|
9011
|
-
log: console.log,
|
|
9012
|
-
warn: console.warn,
|
|
9013
|
-
error: console.error
|
|
9014
|
-
}
|
|
9015
|
-
};
|
|
9016
|
-
const prototypeWhitelist = new Map(import_sandboxjs5.default.SAFE_PROTOTYPES);
|
|
9017
|
-
const arrayMethods = /* @__PURE__ */ new Set([
|
|
9018
|
-
"some",
|
|
9019
|
-
"every",
|
|
9020
|
-
"filter",
|
|
9021
|
-
"map",
|
|
9022
|
-
"reduce",
|
|
9023
|
-
"find",
|
|
9024
|
-
"includes",
|
|
9025
|
-
"indexOf",
|
|
9026
|
-
"length",
|
|
9027
|
-
"slice",
|
|
9028
|
-
"concat",
|
|
9029
|
-
"join"
|
|
9030
|
-
]);
|
|
9031
|
-
prototypeWhitelist.set(Array.prototype, arrayMethods);
|
|
9032
|
-
const stringMethods = /* @__PURE__ */ new Set([
|
|
9033
|
-
"toLowerCase",
|
|
9034
|
-
"toUpperCase",
|
|
9035
|
-
"includes",
|
|
9036
|
-
"indexOf",
|
|
9037
|
-
"startsWith",
|
|
9038
|
-
"endsWith",
|
|
9039
|
-
"slice",
|
|
9040
|
-
"substring",
|
|
9041
|
-
"length",
|
|
9042
|
-
"trim",
|
|
9043
|
-
"split",
|
|
9044
|
-
"replace"
|
|
9045
|
-
]);
|
|
9046
|
-
prototypeWhitelist.set(String.prototype, stringMethods);
|
|
9047
|
-
const objectMethods = /* @__PURE__ */ new Set(["hasOwnProperty", "toString", "valueOf"]);
|
|
9048
|
-
prototypeWhitelist.set(Object.prototype, objectMethods);
|
|
9049
|
-
return new import_sandboxjs5.default({
|
|
9050
|
-
globals,
|
|
9051
|
-
prototypeWhitelist
|
|
9052
|
-
});
|
|
9831
|
+
return createSecureSandbox();
|
|
9053
9832
|
}
|
|
9054
9833
|
/**
|
|
9055
9834
|
* Evaluate simple fail_if condition
|
|
@@ -9322,7 +10101,7 @@ var init_failure_condition_evaluator = __esm({
|
|
|
9322
10101
|
*/
|
|
9323
10102
|
evaluateExpression(condition, context) {
|
|
9324
10103
|
try {
|
|
9325
|
-
const
|
|
10104
|
+
const normalize3 = (expr) => {
|
|
9326
10105
|
const trimmed = expr.trim();
|
|
9327
10106
|
if (!/[\n;]/.test(trimmed)) return trimmed;
|
|
9328
10107
|
const parts = trimmed.split(/[\n;]+/).map((s) => s.trim()).filter((s) => s.length > 0 && !s.startsWith("//"));
|
|
@@ -9465,7 +10244,7 @@ var init_failure_condition_evaluator = __esm({
|
|
|
9465
10244
|
try {
|
|
9466
10245
|
exec = this.sandbox.compile(`return (${raw});`);
|
|
9467
10246
|
} catch {
|
|
9468
|
-
const normalizedExpr =
|
|
10247
|
+
const normalizedExpr = normalize3(condition);
|
|
9469
10248
|
exec = this.sandbox.compile(`return (${normalizedExpr});`);
|
|
9470
10249
|
}
|
|
9471
10250
|
const result = exec(scope).run();
|
|
@@ -10175,16 +10954,16 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
|
|
|
10175
10954
|
addEvent("diagram.block", { check: checkName, origin, code });
|
|
10176
10955
|
addDiagramBlock(origin);
|
|
10177
10956
|
if (process.env.VISOR_TRACE_REPORT === "true") {
|
|
10178
|
-
const outDir = process.env.VISOR_TRACE_DIR ||
|
|
10957
|
+
const outDir = process.env.VISOR_TRACE_DIR || path13.join(process.cwd(), "output", "traces");
|
|
10179
10958
|
try {
|
|
10180
|
-
if (!
|
|
10959
|
+
if (!fs11.existsSync(outDir)) fs11.mkdirSync(outDir, { recursive: true });
|
|
10181
10960
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
10182
|
-
const jsonPath =
|
|
10183
|
-
const htmlPath =
|
|
10961
|
+
const jsonPath = path13.join(outDir, `${ts}.trace.json`);
|
|
10962
|
+
const htmlPath = path13.join(outDir, `${ts}.report.html`);
|
|
10184
10963
|
let data = { spans: [] };
|
|
10185
|
-
if (
|
|
10964
|
+
if (fs11.existsSync(jsonPath)) {
|
|
10186
10965
|
try {
|
|
10187
|
-
data = JSON.parse(
|
|
10966
|
+
data = JSON.parse(fs11.readFileSync(jsonPath, "utf8"));
|
|
10188
10967
|
} catch {
|
|
10189
10968
|
data = { spans: [] };
|
|
10190
10969
|
}
|
|
@@ -10192,9 +10971,9 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
|
|
|
10192
10971
|
data.spans.push({
|
|
10193
10972
|
events: [{ name: "diagram.block", attrs: { check: checkName, origin, code } }]
|
|
10194
10973
|
});
|
|
10195
|
-
|
|
10196
|
-
if (!
|
|
10197
|
-
|
|
10974
|
+
fs11.writeFileSync(jsonPath, JSON.stringify(data, null, 2), "utf8");
|
|
10975
|
+
if (!fs11.existsSync(htmlPath)) {
|
|
10976
|
+
fs11.writeFileSync(
|
|
10198
10977
|
htmlPath,
|
|
10199
10978
|
'<!doctype html><html><head><meta charset="utf-8"/><title>Visor Trace Report</title></head><body><h2>Visor Trace Report</h2></body></html>',
|
|
10200
10979
|
"utf8"
|
|
@@ -10210,14 +10989,14 @@ function emitMermaidFromMarkdown(checkName, markdown, origin) {
|
|
|
10210
10989
|
}
|
|
10211
10990
|
return count;
|
|
10212
10991
|
}
|
|
10213
|
-
var
|
|
10992
|
+
var fs11, path13, MERMAID_RE;
|
|
10214
10993
|
var init_mermaid_telemetry = __esm({
|
|
10215
10994
|
"src/utils/mermaid-telemetry.ts"() {
|
|
10216
10995
|
"use strict";
|
|
10217
10996
|
init_trace_helpers();
|
|
10218
10997
|
init_metrics();
|
|
10219
|
-
|
|
10220
|
-
|
|
10998
|
+
fs11 = __toESM(require("fs"));
|
|
10999
|
+
path13 = __toESM(require("path"));
|
|
10221
11000
|
MERMAID_RE = /```mermaid\s*\n([\s\S]*?)\n```/gi;
|
|
10222
11001
|
}
|
|
10223
11002
|
});
|
|
@@ -10250,7 +11029,7 @@ function getSafeEnvironmentVariables() {
|
|
|
10250
11029
|
}
|
|
10251
11030
|
return safeEnv;
|
|
10252
11031
|
}
|
|
10253
|
-
var
|
|
11032
|
+
var import_api6, CheckExecutionEngine;
|
|
10254
11033
|
var init_check_execution_engine = __esm({
|
|
10255
11034
|
"src/check-execution-engine.ts"() {
|
|
10256
11035
|
"use strict";
|
|
@@ -10263,12 +11042,14 @@ var init_check_execution_engine = __esm({
|
|
|
10263
11042
|
init_github_check_service();
|
|
10264
11043
|
init_issue_filter();
|
|
10265
11044
|
init_logger();
|
|
10266
|
-
|
|
11045
|
+
init_sandbox();
|
|
10267
11046
|
init_author_permissions();
|
|
10268
11047
|
init_memory_store();
|
|
10269
11048
|
init_fallback_ndjson();
|
|
10270
11049
|
init_trace_helpers();
|
|
10271
11050
|
init_metrics();
|
|
11051
|
+
import_api6 = require("@opentelemetry/api");
|
|
11052
|
+
init_state_capture();
|
|
10272
11053
|
CheckExecutionEngine = class _CheckExecutionEngine {
|
|
10273
11054
|
gitAnalyzer;
|
|
10274
11055
|
mockOctokit;
|
|
@@ -10287,6 +11068,8 @@ var init_check_execution_engine = __esm({
|
|
|
10287
11068
|
outputHistory = /* @__PURE__ */ new Map();
|
|
10288
11069
|
// Event override to simulate alternate event (used during routing goto)
|
|
10289
11070
|
routingEventOverride;
|
|
11071
|
+
// Execution context for providers (CLI message, hooks, etc.)
|
|
11072
|
+
executionContext;
|
|
10290
11073
|
// Cached GitHub context for context elevation when running in Actions
|
|
10291
11074
|
actionContext;
|
|
10292
11075
|
constructor(workingDirectory, octokit) {
|
|
@@ -10316,19 +11099,19 @@ var init_check_execution_engine = __esm({
|
|
|
10316
11099
|
}
|
|
10317
11100
|
return baseContext;
|
|
10318
11101
|
}
|
|
11102
|
+
/**
|
|
11103
|
+
* Set execution context for providers (CLI message, hooks, etc.)
|
|
11104
|
+
* This allows passing state without using static properties
|
|
11105
|
+
*/
|
|
11106
|
+
setExecutionContext(context) {
|
|
11107
|
+
this.executionContext = context;
|
|
11108
|
+
}
|
|
10319
11109
|
/**
|
|
10320
11110
|
* Lazily create a secure sandbox for routing JS (goto_js, run_js)
|
|
10321
11111
|
*/
|
|
10322
11112
|
getRoutingSandbox() {
|
|
10323
11113
|
if (this.routingSandbox) return this.routingSandbox;
|
|
10324
|
-
|
|
10325
|
-
...import_sandboxjs6.default.SAFE_GLOBALS,
|
|
10326
|
-
Math,
|
|
10327
|
-
JSON,
|
|
10328
|
-
console: { log: console.log }
|
|
10329
|
-
};
|
|
10330
|
-
const prototypeWhitelist = new Map(import_sandboxjs6.default.SAFE_PROTOTYPES);
|
|
10331
|
-
this.routingSandbox = new import_sandboxjs6.default({ globals, prototypeWhitelist });
|
|
11114
|
+
this.routingSandbox = createSecureSandbox();
|
|
10332
11115
|
return this.routingSandbox;
|
|
10333
11116
|
}
|
|
10334
11117
|
redact(str, limit = 200) {
|
|
@@ -10340,7 +11123,7 @@ var init_check_execution_engine = __esm({
|
|
|
10340
11123
|
}
|
|
10341
11124
|
}
|
|
10342
11125
|
async sleep(ms) {
|
|
10343
|
-
return new Promise((
|
|
11126
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
10344
11127
|
}
|
|
10345
11128
|
deterministicJitter(baseMs, seedStr) {
|
|
10346
11129
|
let h = 2166136261;
|
|
@@ -10401,16 +11184,16 @@ var init_check_execution_engine = __esm({
|
|
|
10401
11184
|
),
|
|
10402
11185
|
event: eventObj
|
|
10403
11186
|
};
|
|
10404
|
-
const
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
const res =
|
|
11187
|
+
const prelude = `const step = scope.step; const attempt = scope.attempt; const loop = scope.loop; const error = scope.error; const foreach = scope.foreach; const outputs = scope.outputs; const output = scope.output; const pr = scope.pr; const files = scope.files; const env = scope.env; const event = scope.event; const hasMinPermission = scope.permissions.hasMinPermission; const isOwner = scope.permissions.isOwner; const isMember = scope.permissions.isMember; const isCollaborator = scope.permissions.isCollaborator; const isContributor = scope.permissions.isContributor; const isFirstTimer = scope.permissions.isFirstTimer;`;
|
|
11188
|
+
const code = `${prelude}
|
|
11189
|
+
${expr}`;
|
|
11190
|
+
const result = compileAndRun(
|
|
11191
|
+
sandbox,
|
|
11192
|
+
code,
|
|
11193
|
+
{ scope },
|
|
11194
|
+
{ injectLog: false, wrapFunction: true }
|
|
11195
|
+
);
|
|
11196
|
+
const res = Array.isArray(result) ? result : result ? [result] : [];
|
|
10414
11197
|
if (debug) {
|
|
10415
11198
|
log2(`\u{1F527} Debug: run_js evaluated \u2192 [${this.redact(res)}]`);
|
|
10416
11199
|
}
|
|
@@ -10454,16 +11237,15 @@ ${expr}
|
|
|
10454
11237
|
),
|
|
10455
11238
|
event: eventObj
|
|
10456
11239
|
};
|
|
10457
|
-
const
|
|
10458
|
-
|
|
10459
|
-
|
|
10460
|
-
|
|
10461
|
-
|
|
10462
|
-
|
|
10463
|
-
|
|
10464
|
-
|
|
10465
|
-
|
|
10466
|
-
const res = exec({ scope }).run();
|
|
11240
|
+
const prelude2 = `const step = scope.step; const attempt = scope.attempt; const loop = scope.loop; const error = scope.error; const foreach = scope.foreach; const outputs = scope.outputs; const output = scope.output; const pr = scope.pr; const files = scope.files; const env = scope.env; const event = scope.event; const hasMinPermission = scope.permissions.hasMinPermission; const isOwner = scope.permissions.isOwner; const isMember = scope.permissions.isMember; const isCollaborator = scope.permissions.isCollaborator; const isContributor = scope.permissions.isContributor; const isFirstTimer = scope.permissions.isFirstTimer;`;
|
|
11241
|
+
const code2 = `${prelude2}
|
|
11242
|
+
${expr}`;
|
|
11243
|
+
const res = compileAndRun(
|
|
11244
|
+
sandbox,
|
|
11245
|
+
code2,
|
|
11246
|
+
{ scope },
|
|
11247
|
+
{ injectLog: false, wrapFunction: true }
|
|
11248
|
+
);
|
|
10467
11249
|
if (debug) {
|
|
10468
11250
|
log2(`\u{1F527} Debug: goto_js evaluated \u2192 ${this.redact(res)}`);
|
|
10469
11251
|
}
|
|
@@ -10583,7 +11365,11 @@ ${expr}
|
|
|
10583
11365
|
}
|
|
10584
11366
|
let r;
|
|
10585
11367
|
try {
|
|
10586
|
-
|
|
11368
|
+
const inlineContext = {
|
|
11369
|
+
...sessionInfo,
|
|
11370
|
+
...this.executionContext
|
|
11371
|
+
};
|
|
11372
|
+
r = await prov.execute(prInfoForInline, provCfg, depResults, inlineContext);
|
|
10587
11373
|
} finally {
|
|
10588
11374
|
this.routingEventOverride = prevEventOverride;
|
|
10589
11375
|
}
|
|
@@ -10614,7 +11400,31 @@ ${expr}
|
|
|
10614
11400
|
});
|
|
10615
11401
|
} catch {
|
|
10616
11402
|
}
|
|
10617
|
-
const
|
|
11403
|
+
const context = {
|
|
11404
|
+
...sessionInfo,
|
|
11405
|
+
...this.executionContext
|
|
11406
|
+
};
|
|
11407
|
+
const res = await withActiveSpan(
|
|
11408
|
+
`visor.check.${checkName}`,
|
|
11409
|
+
{
|
|
11410
|
+
"visor.check.id": checkName,
|
|
11411
|
+
"visor.check.type": providerConfig.type || "ai",
|
|
11412
|
+
"visor.check.attempt": attempt
|
|
11413
|
+
},
|
|
11414
|
+
async () => {
|
|
11415
|
+
try {
|
|
11416
|
+
return await provider.execute(prInfo, providerConfig, dependencyResults, context);
|
|
11417
|
+
} finally {
|
|
11418
|
+
try {
|
|
11419
|
+
emitNdjsonSpanWithEvents("visor.check", { "visor.check.id": checkName }, [
|
|
11420
|
+
{ name: "check.started" },
|
|
11421
|
+
{ name: "check.completed" }
|
|
11422
|
+
]);
|
|
11423
|
+
} catch {
|
|
11424
|
+
}
|
|
11425
|
+
}
|
|
11426
|
+
}
|
|
11427
|
+
);
|
|
10618
11428
|
try {
|
|
10619
11429
|
currentRouteOutput = res?.output;
|
|
10620
11430
|
} catch {
|
|
@@ -11242,7 +12052,7 @@ ${expr}
|
|
|
11242
12052
|
/**
|
|
11243
12053
|
* Execute review checks and return grouped results with statistics for new architecture
|
|
11244
12054
|
*/
|
|
11245
|
-
async executeGroupedChecks(prInfo, checks, timeout, config, outputFormat, debug, maxParallelism, failFast, tagFilter) {
|
|
12055
|
+
async executeGroupedChecks(prInfo, checks, timeout, config, outputFormat, debug, maxParallelism, failFast, tagFilter, _pauseGate) {
|
|
11246
12056
|
const logFn = outputFormat === "json" || outputFormat === "sarif" ? debug ? console.error : () => {
|
|
11247
12057
|
} : console.log;
|
|
11248
12058
|
if (debug) {
|
|
@@ -11315,7 +12125,8 @@ ${expr}
|
|
|
11315
12125
|
logFn,
|
|
11316
12126
|
debug,
|
|
11317
12127
|
maxParallelism,
|
|
11318
|
-
failFast
|
|
12128
|
+
failFast,
|
|
12129
|
+
_pauseGate
|
|
11319
12130
|
);
|
|
11320
12131
|
}
|
|
11321
12132
|
if (checks.length === 1) {
|
|
@@ -11328,7 +12139,8 @@ ${expr}
|
|
|
11328
12139
|
timeout,
|
|
11329
12140
|
config,
|
|
11330
12141
|
logFn,
|
|
11331
|
-
debug
|
|
12142
|
+
debug,
|
|
12143
|
+
_pauseGate
|
|
11332
12144
|
);
|
|
11333
12145
|
const groupedResults = {};
|
|
11334
12146
|
groupedResults[checkResult.group] = [checkResult];
|
|
@@ -11345,7 +12157,7 @@ ${expr}
|
|
|
11345
12157
|
/**
|
|
11346
12158
|
* Execute single check and return grouped result
|
|
11347
12159
|
*/
|
|
11348
|
-
async executeSingleGroupedCheck(prInfo, checkName, timeout, config, logFn, debug) {
|
|
12160
|
+
async executeSingleGroupedCheck(prInfo, checkName, timeout, config, logFn, debug, _pauseGate) {
|
|
11349
12161
|
if (!config?.checks?.[checkName]) {
|
|
11350
12162
|
throw new Error(`No configuration found for check: ${checkName}`);
|
|
11351
12163
|
}
|
|
@@ -11359,6 +12171,8 @@ ${expr}
|
|
|
11359
12171
|
focus: checkConfig.focus || this.mapCheckNameToFocus(checkName),
|
|
11360
12172
|
schema: checkConfig.schema,
|
|
11361
12173
|
group: checkConfig.group,
|
|
12174
|
+
checkName,
|
|
12175
|
+
// propagate for fallback NDJSON attribution
|
|
11362
12176
|
eventContext: this.enrichEventContext(prInfo.eventContext),
|
|
11363
12177
|
ai: {
|
|
11364
12178
|
timeout: timeout || 6e5,
|
|
@@ -11473,7 +12287,7 @@ ${expr}
|
|
|
11473
12287
|
/**
|
|
11474
12288
|
* Execute multiple checks with dependency awareness - return grouped results with statistics
|
|
11475
12289
|
*/
|
|
11476
|
-
async executeGroupedDependencyAwareChecks(prInfo, checks, timeout, config, logFn, debug, maxParallelism, failFast) {
|
|
12290
|
+
async executeGroupedDependencyAwareChecks(prInfo, checks, timeout, config, logFn, debug, maxParallelism, failFast, pauseGate) {
|
|
11477
12291
|
const reviewSummary = await this.executeDependencyAwareChecks(
|
|
11478
12292
|
prInfo,
|
|
11479
12293
|
checks,
|
|
@@ -11482,7 +12296,8 @@ ${expr}
|
|
|
11482
12296
|
logFn,
|
|
11483
12297
|
debug,
|
|
11484
12298
|
maxParallelism,
|
|
11485
|
-
failFast
|
|
12299
|
+
failFast,
|
|
12300
|
+
pauseGate
|
|
11486
12301
|
);
|
|
11487
12302
|
const executionStatistics = this.buildExecutionStatistics();
|
|
11488
12303
|
const groupedResults = await this.convertReviewSummaryToGroupedResults(
|
|
@@ -11583,7 +12398,7 @@ ${expr}
|
|
|
11583
12398
|
* - Enforcing .liquid file extension
|
|
11584
12399
|
*/
|
|
11585
12400
|
async validateTemplatePath(templatePath) {
|
|
11586
|
-
const
|
|
12401
|
+
const path16 = await import("path");
|
|
11587
12402
|
if (!templatePath || typeof templatePath !== "string" || templatePath.trim() === "") {
|
|
11588
12403
|
throw new Error("Template path must be a non-empty string");
|
|
11589
12404
|
}
|
|
@@ -11593,7 +12408,7 @@ ${expr}
|
|
|
11593
12408
|
if (!templatePath.endsWith(".liquid")) {
|
|
11594
12409
|
throw new Error("Template file must have .liquid extension");
|
|
11595
12410
|
}
|
|
11596
|
-
if (
|
|
12411
|
+
if (path16.isAbsolute(templatePath)) {
|
|
11597
12412
|
throw new Error("Template path must be relative to project directory");
|
|
11598
12413
|
}
|
|
11599
12414
|
if (templatePath.includes("..")) {
|
|
@@ -11607,14 +12422,14 @@ ${expr}
|
|
|
11607
12422
|
if (!projectRoot || typeof projectRoot !== "string") {
|
|
11608
12423
|
throw new Error("Unable to determine project root directory");
|
|
11609
12424
|
}
|
|
11610
|
-
const resolvedPath =
|
|
11611
|
-
const resolvedProjectRoot =
|
|
12425
|
+
const resolvedPath = path16.resolve(projectRoot, templatePath);
|
|
12426
|
+
const resolvedProjectRoot = path16.resolve(projectRoot);
|
|
11612
12427
|
if (!resolvedPath || !resolvedProjectRoot || resolvedPath === "" || resolvedProjectRoot === "") {
|
|
11613
12428
|
throw new Error(
|
|
11614
12429
|
`Unable to resolve template path: projectRoot="${projectRoot}", templatePath="${templatePath}", resolvedPath="${resolvedPath}", resolvedProjectRoot="${resolvedProjectRoot}"`
|
|
11615
12430
|
);
|
|
11616
12431
|
}
|
|
11617
|
-
if (!resolvedPath.startsWith(resolvedProjectRoot +
|
|
12432
|
+
if (!resolvedPath.startsWith(resolvedProjectRoot + path16.sep) && resolvedPath !== resolvedProjectRoot) {
|
|
11618
12433
|
throw new Error("Template path escapes project directory");
|
|
11619
12434
|
}
|
|
11620
12435
|
return resolvedPath;
|
|
@@ -11658,8 +12473,8 @@ ${expr}
|
|
|
11658
12473
|
return directContent.trim();
|
|
11659
12474
|
}
|
|
11660
12475
|
const { createExtendedLiquid: createExtendedLiquid2 } = await Promise.resolve().then(() => (init_liquid_extensions(), liquid_extensions_exports));
|
|
11661
|
-
const
|
|
11662
|
-
const
|
|
12476
|
+
const fs14 = await import("fs/promises");
|
|
12477
|
+
const path16 = await import("path");
|
|
11663
12478
|
const liquid = createExtendedLiquid2({
|
|
11664
12479
|
trimTagLeft: false,
|
|
11665
12480
|
trimTagRight: false,
|
|
@@ -11682,7 +12497,7 @@ ${expr}
|
|
|
11682
12497
|
templateContent = checkConfig.template.content;
|
|
11683
12498
|
} else if (checkConfig.template.file) {
|
|
11684
12499
|
const validatedPath = await this.validateTemplatePath(checkConfig.template.file);
|
|
11685
|
-
templateContent = await
|
|
12500
|
+
templateContent = await fs14.readFile(validatedPath, "utf-8");
|
|
11686
12501
|
} else {
|
|
11687
12502
|
throw new Error('Custom template must specify either "file" or "content"');
|
|
11688
12503
|
}
|
|
@@ -11693,8 +12508,8 @@ ${expr}
|
|
|
11693
12508
|
if (!sanitizedSchema) {
|
|
11694
12509
|
throw new Error("Invalid schema name");
|
|
11695
12510
|
}
|
|
11696
|
-
const templatePath =
|
|
11697
|
-
templateContent = await
|
|
12511
|
+
const templatePath = path16.join(__dirname, `output/${sanitizedSchema}/template.liquid`);
|
|
12512
|
+
templateContent = await fs14.readFile(templatePath, "utf-8");
|
|
11698
12513
|
if (sanitizedSchema === "issue-assistant") {
|
|
11699
12514
|
enrichAssistantContext = true;
|
|
11700
12515
|
}
|
|
@@ -11802,7 +12617,7 @@ ${expr}
|
|
|
11802
12617
|
/**
|
|
11803
12618
|
* Execute multiple checks with dependency awareness - intelligently parallel and sequential
|
|
11804
12619
|
*/
|
|
11805
|
-
async executeDependencyAwareChecks(prInfo, checks, timeout, config, logFn, debug, maxParallelism, failFast) {
|
|
12620
|
+
async executeDependencyAwareChecks(prInfo, checks, timeout, config, logFn, debug, maxParallelism, failFast, pauseGate) {
|
|
11806
12621
|
const log2 = logFn || console.error;
|
|
11807
12622
|
if (debug) {
|
|
11808
12623
|
log2(`\u{1F527} Debug: Starting dependency-aware execution of ${checks.length} checks`);
|
|
@@ -11937,6 +12752,13 @@ ${expr}
|
|
|
11937
12752
|
}
|
|
11938
12753
|
const levelChecks = executionGroup.parallel.filter((name) => !results.has(name));
|
|
11939
12754
|
const levelTaskFunctions = levelChecks.map((checkName) => async () => {
|
|
12755
|
+
if (pauseGate) {
|
|
12756
|
+
try {
|
|
12757
|
+
await pauseGate();
|
|
12758
|
+
} catch {
|
|
12759
|
+
return { checkName, error: "__STOP__", result: null, skipped: true };
|
|
12760
|
+
}
|
|
12761
|
+
}
|
|
11940
12762
|
if (results.has(checkName)) {
|
|
11941
12763
|
if (debug) log2(`\u{1F527} Debug: Skipping ${checkName} (already satisfied earlier)`);
|
|
11942
12764
|
return { checkName, error: null, result: results.get(checkName) };
|
|
@@ -12025,7 +12847,7 @@ ${expr}
|
|
|
12025
12847
|
});
|
|
12026
12848
|
if (!hasFatalFailure && config && (config.fail_if || config.checks[depId]?.fail_if)) {
|
|
12027
12849
|
try {
|
|
12028
|
-
hasFatalFailure = await this.failIfTriggered(depId, depRes, config);
|
|
12850
|
+
hasFatalFailure = await this.failIfTriggered(depId, depRes, config, results);
|
|
12029
12851
|
} catch {
|
|
12030
12852
|
}
|
|
12031
12853
|
}
|
|
@@ -12258,7 +13080,9 @@ ${expr}
|
|
|
12258
13080
|
const fRes = await this.evaluateFailureConditions(
|
|
12259
13081
|
childName,
|
|
12260
13082
|
childItemRes,
|
|
12261
|
-
config
|
|
13083
|
+
config,
|
|
13084
|
+
prInfo,
|
|
13085
|
+
results
|
|
12262
13086
|
);
|
|
12263
13087
|
if (fRes.length > 0) {
|
|
12264
13088
|
const fIssues = fRes.filter((f) => f.failed).map((f) => ({
|
|
@@ -12301,6 +13125,13 @@ ${expr}
|
|
|
12301
13125
|
}
|
|
12302
13126
|
};
|
|
12303
13127
|
const itemTasks = forEachItems.map((item, itemIndex) => async () => {
|
|
13128
|
+
if (pauseGate) {
|
|
13129
|
+
try {
|
|
13130
|
+
await pauseGate();
|
|
13131
|
+
} catch {
|
|
13132
|
+
throw new Error("__STOP__");
|
|
13133
|
+
}
|
|
13134
|
+
}
|
|
12304
13135
|
try {
|
|
12305
13136
|
emitNdjsonSpanWithEvents(
|
|
12306
13137
|
"visor.foreach.item",
|
|
@@ -12313,6 +13144,13 @@ ${expr}
|
|
|
12313
13144
|
);
|
|
12314
13145
|
} catch {
|
|
12315
13146
|
}
|
|
13147
|
+
try {
|
|
13148
|
+
const span = import_api6.trace.getSpan(import_api6.context.active());
|
|
13149
|
+
if (span) {
|
|
13150
|
+
captureForEachState(span, forEachItems, itemIndex, item);
|
|
13151
|
+
}
|
|
13152
|
+
} catch {
|
|
13153
|
+
}
|
|
12316
13154
|
const forEachDependencyResults = /* @__PURE__ */ new Map();
|
|
12317
13155
|
for (const [depName, depResult] of dependencyResults) {
|
|
12318
13156
|
if (forEachParents.includes(depName)) {
|
|
@@ -12363,7 +13201,9 @@ ${expr}
|
|
|
12363
13201
|
const depFailures = await this.evaluateFailureConditions(
|
|
12364
13202
|
depId,
|
|
12365
13203
|
depItemRes,
|
|
12366
|
-
config
|
|
13204
|
+
config,
|
|
13205
|
+
prInfo,
|
|
13206
|
+
results
|
|
12367
13207
|
);
|
|
12368
13208
|
hasFatalDepFailure = depFailures.some((f) => f.failed);
|
|
12369
13209
|
} catch {
|
|
@@ -12439,7 +13279,9 @@ ${expr}
|
|
|
12439
13279
|
const itemFailures = await this.evaluateFailureConditions(
|
|
12440
13280
|
checkName,
|
|
12441
13281
|
itemResult,
|
|
12442
|
-
config
|
|
13282
|
+
config,
|
|
13283
|
+
prInfo,
|
|
13284
|
+
results
|
|
12443
13285
|
);
|
|
12444
13286
|
if (itemFailures.length > 0) {
|
|
12445
13287
|
const failureIssues = itemFailures.filter((f) => f.failed).map((f) => ({
|
|
@@ -12609,7 +13451,13 @@ ${expr}
|
|
|
12609
13451
|
{ index: itemIndex, total: forEachItems.length, parent: forEachParentName }
|
|
12610
13452
|
);
|
|
12611
13453
|
if (config && (config.fail_if || nodeCfg.fail_if)) {
|
|
12612
|
-
const fRes = await this.evaluateFailureConditions(
|
|
13454
|
+
const fRes = await this.evaluateFailureConditions(
|
|
13455
|
+
node,
|
|
13456
|
+
nodeItemRes,
|
|
13457
|
+
config,
|
|
13458
|
+
prInfo,
|
|
13459
|
+
results
|
|
13460
|
+
);
|
|
12613
13461
|
if (fRes.length > 0) {
|
|
12614
13462
|
const fIssues = fRes.filter((f) => f.failed).map((f) => ({
|
|
12615
13463
|
file: "system",
|
|
@@ -12704,7 +13552,13 @@ ${expr}
|
|
|
12704
13552
|
rForEval = { ...r, output: parsed };
|
|
12705
13553
|
}
|
|
12706
13554
|
}
|
|
12707
|
-
const failures = await this.evaluateFailureConditions(
|
|
13555
|
+
const failures = await this.evaluateFailureConditions(
|
|
13556
|
+
parent,
|
|
13557
|
+
rForEval,
|
|
13558
|
+
config,
|
|
13559
|
+
prInfo,
|
|
13560
|
+
results
|
|
13561
|
+
);
|
|
12708
13562
|
if (failures.some((f) => f.failed)) {
|
|
12709
13563
|
}
|
|
12710
13564
|
if (failures.some((f) => f.failed)) return true;
|
|
@@ -12823,7 +13677,9 @@ ${expr}
|
|
|
12823
13677
|
const failures = await this.evaluateFailureConditions(
|
|
12824
13678
|
checkName,
|
|
12825
13679
|
r,
|
|
12826
|
-
config
|
|
13680
|
+
config,
|
|
13681
|
+
prInfo,
|
|
13682
|
+
results
|
|
12827
13683
|
);
|
|
12828
13684
|
hadFatal = failures.some((f) => f.failed);
|
|
12829
13685
|
} catch {
|
|
@@ -12930,7 +13786,9 @@ ${expr}
|
|
|
12930
13786
|
const failureResults = await this.evaluateFailureConditions(
|
|
12931
13787
|
checkName,
|
|
12932
13788
|
finalResult,
|
|
12933
|
-
config
|
|
13789
|
+
config,
|
|
13790
|
+
prInfo,
|
|
13791
|
+
results
|
|
12934
13792
|
);
|
|
12935
13793
|
if (failureResults.length > 0) {
|
|
12936
13794
|
const failureIssues = failureResults.filter((f) => f.failed).map((f) => ({
|
|
@@ -13045,6 +13903,14 @@ ${error.stack || ""}` : String(error);
|
|
|
13045
13903
|
const checkName = levelChecksList[i];
|
|
13046
13904
|
const result = levelResults[i];
|
|
13047
13905
|
const checkConfig = config.checks[checkName];
|
|
13906
|
+
if (result.status === "fulfilled" && result.value?.error === "__STOP__") {
|
|
13907
|
+
shouldStopExecution = true;
|
|
13908
|
+
break;
|
|
13909
|
+
}
|
|
13910
|
+
if (result.status === "rejected" && result.reason instanceof Error && result.reason.message === "__STOP__") {
|
|
13911
|
+
shouldStopExecution = true;
|
|
13912
|
+
break;
|
|
13913
|
+
}
|
|
13048
13914
|
if (result.status === "fulfilled" && result.value.result && !result.value.error) {
|
|
13049
13915
|
if (result.value.skipped) {
|
|
13050
13916
|
if (debug) {
|
|
@@ -13105,6 +13971,21 @@ ${error.stack || ""}` : String(error);
|
|
|
13105
13971
|
this.trackOutputHistory(checkName, reviewResultWithOutput.output);
|
|
13106
13972
|
}
|
|
13107
13973
|
results.set(checkName, reviewResult);
|
|
13974
|
+
try {
|
|
13975
|
+
const span = import_api6.trace.getSpan(import_api6.context.active());
|
|
13976
|
+
if (span) {
|
|
13977
|
+
const allOutputs = {};
|
|
13978
|
+
results.forEach((result2, name) => {
|
|
13979
|
+
if (result2.output !== void 0) {
|
|
13980
|
+
allOutputs[name] = result2.output;
|
|
13981
|
+
}
|
|
13982
|
+
});
|
|
13983
|
+
const memoryStore = MemoryStore.getInstance();
|
|
13984
|
+
const memoryData = await memoryStore.getAll();
|
|
13985
|
+
captureStateSnapshot(span, checkName, allOutputs, memoryData);
|
|
13986
|
+
}
|
|
13987
|
+
} catch {
|
|
13988
|
+
}
|
|
13108
13989
|
} else {
|
|
13109
13990
|
const errorSummary = {
|
|
13110
13991
|
issues: [
|
|
@@ -13823,13 +14704,14 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
13823
14704
|
/**
|
|
13824
14705
|
* Evaluate failure conditions for a check result
|
|
13825
14706
|
*/
|
|
13826
|
-
async evaluateFailureConditions(checkName, reviewSummary, config, prInfo) {
|
|
14707
|
+
async evaluateFailureConditions(checkName, reviewSummary, config, prInfo, previousOutputs) {
|
|
13827
14708
|
if (!config) {
|
|
13828
14709
|
return [];
|
|
13829
14710
|
}
|
|
13830
14711
|
const checkConfig = config.checks[checkName];
|
|
13831
14712
|
const checkSchema = typeof checkConfig?.schema === "object" ? "custom" : checkConfig?.schema || "";
|
|
13832
14713
|
const checkGroup = checkConfig?.group || "";
|
|
14714
|
+
const outputsRecord = previousOutputs ? previousOutputs instanceof Map ? Object.fromEntries(previousOutputs.entries()) : previousOutputs : void 0;
|
|
13833
14715
|
const globalFailIf = config.fail_if;
|
|
13834
14716
|
const checkFailIf = checkConfig?.fail_if;
|
|
13835
14717
|
if (globalFailIf || checkFailIf) {
|
|
@@ -13840,7 +14722,8 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
13840
14722
|
checkSchema,
|
|
13841
14723
|
checkGroup,
|
|
13842
14724
|
reviewSummary,
|
|
13843
|
-
globalFailIf
|
|
14725
|
+
globalFailIf,
|
|
14726
|
+
outputsRecord
|
|
13844
14727
|
);
|
|
13845
14728
|
try {
|
|
13846
14729
|
addEvent("fail_if.evaluated", {
|
|
@@ -13905,7 +14788,8 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
13905
14788
|
checkSchema,
|
|
13906
14789
|
checkGroup,
|
|
13907
14790
|
reviewSummary,
|
|
13908
|
-
checkFailIf
|
|
14791
|
+
checkFailIf,
|
|
14792
|
+
outputsRecord
|
|
13909
14793
|
);
|
|
13910
14794
|
try {
|
|
13911
14795
|
addEvent("fail_if.evaluated", {
|
|
@@ -14434,9 +15318,15 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
14434
15318
|
if (!issues || issues.length === 0) return false;
|
|
14435
15319
|
return issues.some((i) => this.isFatalRule(i.ruleId || "", i.severity));
|
|
14436
15320
|
}
|
|
14437
|
-
async failIfTriggered(checkName, result, config) {
|
|
15321
|
+
async failIfTriggered(checkName, result, config, previousOutputs) {
|
|
14438
15322
|
if (!config) return false;
|
|
14439
|
-
const failures = await this.evaluateFailureConditions(
|
|
15323
|
+
const failures = await this.evaluateFailureConditions(
|
|
15324
|
+
checkName,
|
|
15325
|
+
result,
|
|
15326
|
+
config,
|
|
15327
|
+
void 0,
|
|
15328
|
+
previousOutputs
|
|
15329
|
+
);
|
|
14440
15330
|
return failures.some((f) => f.failed);
|
|
14441
15331
|
}
|
|
14442
15332
|
/**
|
|
@@ -14834,9 +15724,13 @@ var init_config_schema = __esm({
|
|
|
14834
15724
|
],
|
|
14835
15725
|
description: 'Extends from other configurations - can be file path, HTTP(S) URL, or "default"'
|
|
14836
15726
|
},
|
|
15727
|
+
steps: {
|
|
15728
|
+
$ref: "#/definitions/Record%3Cstring%2CCheckConfig%3E",
|
|
15729
|
+
description: "Step configurations (recommended)"
|
|
15730
|
+
},
|
|
14837
15731
|
checks: {
|
|
14838
15732
|
$ref: "#/definitions/Record%3Cstring%2CCheckConfig%3E",
|
|
14839
|
-
description: "Check configurations"
|
|
15733
|
+
description: "Check configurations (legacy, use 'steps' instead) - always populated after normalization"
|
|
14840
15734
|
},
|
|
14841
15735
|
output: {
|
|
14842
15736
|
$ref: "#/definitions/OutputConfig",
|
|
@@ -14891,7 +15785,7 @@ var init_config_schema = __esm({
|
|
|
14891
15785
|
description: "Optional routing defaults for retry/goto/run policies"
|
|
14892
15786
|
}
|
|
14893
15787
|
},
|
|
14894
|
-
required: ["version", "
|
|
15788
|
+
required: ["version", "output"],
|
|
14895
15789
|
additionalProperties: false,
|
|
14896
15790
|
description: "Main Visor configuration",
|
|
14897
15791
|
patternProperties: {
|
|
@@ -15175,7 +16069,8 @@ var init_config_schema = __esm({
|
|
|
15175
16069
|
"memory",
|
|
15176
16070
|
"github",
|
|
15177
16071
|
"claude-code",
|
|
15178
|
-
"mcp"
|
|
16072
|
+
"mcp",
|
|
16073
|
+
"human-input"
|
|
15179
16074
|
],
|
|
15180
16075
|
description: "Valid check types in configuration"
|
|
15181
16076
|
},
|
|
@@ -15879,14 +16774,14 @@ init_check_execution_engine();
|
|
|
15879
16774
|
|
|
15880
16775
|
// src/config.ts
|
|
15881
16776
|
var yaml2 = __toESM(require("js-yaml"));
|
|
15882
|
-
var
|
|
15883
|
-
var
|
|
16777
|
+
var fs13 = __toESM(require("fs"));
|
|
16778
|
+
var path15 = __toESM(require("path"));
|
|
15884
16779
|
init_logger();
|
|
15885
16780
|
var import_simple_git2 = __toESM(require("simple-git"));
|
|
15886
16781
|
|
|
15887
16782
|
// src/utils/config-loader.ts
|
|
15888
|
-
var
|
|
15889
|
-
var
|
|
16783
|
+
var fs12 = __toESM(require("fs"));
|
|
16784
|
+
var path14 = __toESM(require("path"));
|
|
15890
16785
|
var yaml = __toESM(require("js-yaml"));
|
|
15891
16786
|
var ConfigLoader = class {
|
|
15892
16787
|
constructor(options = {}) {
|
|
@@ -15967,7 +16862,7 @@ var ConfigLoader = class {
|
|
|
15967
16862
|
return source.toLowerCase();
|
|
15968
16863
|
case "local" /* LOCAL */:
|
|
15969
16864
|
const basePath = this.options.baseDir || process.cwd();
|
|
15970
|
-
return
|
|
16865
|
+
return path14.resolve(basePath, source);
|
|
15971
16866
|
default:
|
|
15972
16867
|
return source;
|
|
15973
16868
|
}
|
|
@@ -15977,19 +16872,19 @@ var ConfigLoader = class {
|
|
|
15977
16872
|
*/
|
|
15978
16873
|
async fetchLocalConfig(filePath) {
|
|
15979
16874
|
const basePath = this.options.baseDir || process.cwd();
|
|
15980
|
-
const resolvedPath =
|
|
16875
|
+
const resolvedPath = path14.resolve(basePath, filePath);
|
|
15981
16876
|
this.validateLocalPath(resolvedPath);
|
|
15982
|
-
if (!
|
|
16877
|
+
if (!fs12.existsSync(resolvedPath)) {
|
|
15983
16878
|
throw new Error(`Configuration file not found: ${resolvedPath}`);
|
|
15984
16879
|
}
|
|
15985
16880
|
try {
|
|
15986
|
-
const content =
|
|
16881
|
+
const content = fs12.readFileSync(resolvedPath, "utf8");
|
|
15987
16882
|
const config = yaml.load(content);
|
|
15988
16883
|
if (!config || typeof config !== "object") {
|
|
15989
16884
|
throw new Error(`Invalid YAML in configuration file: ${resolvedPath}`);
|
|
15990
16885
|
}
|
|
15991
16886
|
const previousBaseDir = this.options.baseDir;
|
|
15992
|
-
this.options.baseDir =
|
|
16887
|
+
this.options.baseDir = path14.dirname(resolvedPath);
|
|
15993
16888
|
try {
|
|
15994
16889
|
if (config.extends) {
|
|
15995
16890
|
const processedConfig = await this.processExtends(config);
|
|
@@ -16069,29 +16964,30 @@ var ConfigLoader = class {
|
|
|
16069
16964
|
async fetchDefaultConfig() {
|
|
16070
16965
|
const possiblePaths = [
|
|
16071
16966
|
// When running as GitHub Action (bundled in dist/)
|
|
16072
|
-
|
|
16967
|
+
path14.join(__dirname, "defaults", ".visor.yaml"),
|
|
16073
16968
|
// When running from source
|
|
16074
|
-
|
|
16969
|
+
path14.join(__dirname, "..", "..", "defaults", ".visor.yaml"),
|
|
16075
16970
|
// Try via package root
|
|
16076
|
-
this.findPackageRoot() ?
|
|
16971
|
+
this.findPackageRoot() ? path14.join(this.findPackageRoot(), "defaults", ".visor.yaml") : "",
|
|
16077
16972
|
// GitHub Action environment variable
|
|
16078
|
-
process.env.GITHUB_ACTION_PATH ?
|
|
16079
|
-
process.env.GITHUB_ACTION_PATH ?
|
|
16973
|
+
process.env.GITHUB_ACTION_PATH ? path14.join(process.env.GITHUB_ACTION_PATH, "defaults", ".visor.yaml") : "",
|
|
16974
|
+
process.env.GITHUB_ACTION_PATH ? path14.join(process.env.GITHUB_ACTION_PATH, "dist", "defaults", ".visor.yaml") : ""
|
|
16080
16975
|
].filter((p) => p);
|
|
16081
16976
|
let defaultConfigPath;
|
|
16082
16977
|
for (const possiblePath of possiblePaths) {
|
|
16083
|
-
if (
|
|
16978
|
+
if (fs12.existsSync(possiblePath)) {
|
|
16084
16979
|
defaultConfigPath = possiblePath;
|
|
16085
16980
|
break;
|
|
16086
16981
|
}
|
|
16087
16982
|
}
|
|
16088
|
-
if (defaultConfigPath &&
|
|
16983
|
+
if (defaultConfigPath && fs12.existsSync(defaultConfigPath)) {
|
|
16089
16984
|
console.error(`\u{1F4E6} Loading bundled default configuration from ${defaultConfigPath}`);
|
|
16090
|
-
const content =
|
|
16091
|
-
|
|
16985
|
+
const content = fs12.readFileSync(defaultConfigPath, "utf8");
|
|
16986
|
+
let config = yaml.load(content);
|
|
16092
16987
|
if (!config || typeof config !== "object") {
|
|
16093
16988
|
throw new Error("Invalid default configuration");
|
|
16094
16989
|
}
|
|
16990
|
+
config = this.normalizeStepsAndChecks(config);
|
|
16095
16991
|
if (config.extends) {
|
|
16096
16992
|
return await this.processExtends(config);
|
|
16097
16993
|
}
|
|
@@ -16166,8 +17062,8 @@ var ConfigLoader = class {
|
|
|
16166
17062
|
*/
|
|
16167
17063
|
validateLocalPath(resolvedPath) {
|
|
16168
17064
|
const projectRoot = this.options.projectRoot || process.cwd();
|
|
16169
|
-
const normalizedPath =
|
|
16170
|
-
const normalizedRoot =
|
|
17065
|
+
const normalizedPath = path14.normalize(resolvedPath);
|
|
17066
|
+
const normalizedRoot = path14.normalize(projectRoot);
|
|
16171
17067
|
if (!normalizedPath.startsWith(normalizedRoot)) {
|
|
16172
17068
|
throw new Error(
|
|
16173
17069
|
`Security error: Path traversal detected. Cannot access files outside project root: ${projectRoot}`
|
|
@@ -16193,19 +17089,19 @@ var ConfigLoader = class {
|
|
|
16193
17089
|
*/
|
|
16194
17090
|
findPackageRoot() {
|
|
16195
17091
|
let currentDir = __dirname;
|
|
16196
|
-
const root =
|
|
17092
|
+
const root = path14.parse(currentDir).root;
|
|
16197
17093
|
while (currentDir !== root) {
|
|
16198
|
-
const packageJsonPath =
|
|
16199
|
-
if (
|
|
17094
|
+
const packageJsonPath = path14.join(currentDir, "package.json");
|
|
17095
|
+
if (fs12.existsSync(packageJsonPath)) {
|
|
16200
17096
|
try {
|
|
16201
|
-
const packageJson = JSON.parse(
|
|
17097
|
+
const packageJson = JSON.parse(fs12.readFileSync(packageJsonPath, "utf8"));
|
|
16202
17098
|
if (packageJson.name === "@probelabs/visor") {
|
|
16203
17099
|
return currentDir;
|
|
16204
17100
|
}
|
|
16205
17101
|
} catch {
|
|
16206
17102
|
}
|
|
16207
17103
|
}
|
|
16208
|
-
currentDir =
|
|
17104
|
+
currentDir = path14.dirname(currentDir);
|
|
16209
17105
|
}
|
|
16210
17106
|
return null;
|
|
16211
17107
|
}
|
|
@@ -16222,6 +17118,20 @@ var ConfigLoader = class {
|
|
|
16222
17118
|
this.loadedConfigs.clear();
|
|
16223
17119
|
this.clearCache();
|
|
16224
17120
|
}
|
|
17121
|
+
/**
|
|
17122
|
+
* Normalize 'checks' and 'steps' keys for backward compatibility
|
|
17123
|
+
* Ensures both keys are present and contain the same data
|
|
17124
|
+
*/
|
|
17125
|
+
normalizeStepsAndChecks(config) {
|
|
17126
|
+
if (config.steps && config.checks) {
|
|
17127
|
+
config.checks = config.steps;
|
|
17128
|
+
} else if (config.steps && !config.checks) {
|
|
17129
|
+
config.checks = config.steps;
|
|
17130
|
+
} else if (config.checks && !config.steps) {
|
|
17131
|
+
config.steps = config.checks;
|
|
17132
|
+
}
|
|
17133
|
+
return config;
|
|
17134
|
+
}
|
|
16225
17135
|
};
|
|
16226
17136
|
|
|
16227
17137
|
// src/config.ts
|
|
@@ -16242,6 +17152,7 @@ var ConfigManager = class {
|
|
|
16242
17152
|
validCheckTypes = [
|
|
16243
17153
|
"ai",
|
|
16244
17154
|
"claude-code",
|
|
17155
|
+
"mcp",
|
|
16245
17156
|
"command",
|
|
16246
17157
|
"http",
|
|
16247
17158
|
"http_input",
|
|
@@ -16250,7 +17161,8 @@ var ConfigManager = class {
|
|
|
16250
17161
|
"noop",
|
|
16251
17162
|
"log",
|
|
16252
17163
|
"memory",
|
|
16253
|
-
"github"
|
|
17164
|
+
"github",
|
|
17165
|
+
"human-input"
|
|
16254
17166
|
];
|
|
16255
17167
|
validEventTriggers = [...VALID_EVENT_TRIGGERS];
|
|
16256
17168
|
validOutputFormats = ["table", "json", "markdown", "sarif"];
|
|
@@ -16260,12 +17172,12 @@ var ConfigManager = class {
|
|
|
16260
17172
|
*/
|
|
16261
17173
|
async loadConfig(configPath, options = {}) {
|
|
16262
17174
|
const { validate = true, mergeDefaults = true, allowedRemotePatterns } = options;
|
|
16263
|
-
const resolvedPath =
|
|
17175
|
+
const resolvedPath = path15.isAbsolute(configPath) ? configPath : path15.resolve(process.cwd(), configPath);
|
|
16264
17176
|
try {
|
|
16265
|
-
if (!
|
|
17177
|
+
if (!fs13.existsSync(resolvedPath)) {
|
|
16266
17178
|
throw new Error(`Configuration file not found: ${resolvedPath}`);
|
|
16267
17179
|
}
|
|
16268
|
-
const configContent =
|
|
17180
|
+
const configContent = fs13.readFileSync(resolvedPath, "utf8");
|
|
16269
17181
|
let parsedConfig;
|
|
16270
17182
|
try {
|
|
16271
17183
|
parsedConfig = yaml2.load(configContent);
|
|
@@ -16278,7 +17190,7 @@ var ConfigManager = class {
|
|
|
16278
17190
|
}
|
|
16279
17191
|
if (parsedConfig.extends) {
|
|
16280
17192
|
const loaderOptions = {
|
|
16281
|
-
baseDir:
|
|
17193
|
+
baseDir: path15.dirname(resolvedPath),
|
|
16282
17194
|
allowRemote: this.isRemoteExtendsAllowed(),
|
|
16283
17195
|
maxDepth: 10,
|
|
16284
17196
|
allowedRemotePatterns
|
|
@@ -16296,6 +17208,7 @@ var ConfigManager = class {
|
|
|
16296
17208
|
parsedConfig = merger.merge(mergedConfig, configWithoutExtends);
|
|
16297
17209
|
parsedConfig = merger.removeDisabledChecks(parsedConfig);
|
|
16298
17210
|
}
|
|
17211
|
+
parsedConfig = this.normalizeStepsAndChecks(parsedConfig);
|
|
16299
17212
|
if (validate) {
|
|
16300
17213
|
this.validateConfig(parsedConfig);
|
|
16301
17214
|
}
|
|
@@ -16327,9 +17240,9 @@ var ConfigManager = class {
|
|
|
16327
17240
|
const gitRoot = await this.findGitRepositoryRoot();
|
|
16328
17241
|
const searchDirs = [gitRoot, process.cwd()].filter(Boolean);
|
|
16329
17242
|
for (const baseDir of searchDirs) {
|
|
16330
|
-
const possiblePaths = [
|
|
17243
|
+
const possiblePaths = [path15.join(baseDir, ".visor.yaml"), path15.join(baseDir, ".visor.yml")];
|
|
16331
17244
|
for (const configPath of possiblePaths) {
|
|
16332
|
-
if (
|
|
17245
|
+
if (fs13.existsSync(configPath)) {
|
|
16333
17246
|
return this.loadConfig(configPath, options);
|
|
16334
17247
|
}
|
|
16335
17248
|
}
|
|
@@ -16362,7 +17275,9 @@ var ConfigManager = class {
|
|
|
16362
17275
|
async getDefaultConfig() {
|
|
16363
17276
|
return {
|
|
16364
17277
|
version: "1.0",
|
|
17278
|
+
steps: {},
|
|
16365
17279
|
checks: {},
|
|
17280
|
+
// Keep for backward compatibility
|
|
16366
17281
|
max_parallelism: 3,
|
|
16367
17282
|
output: {
|
|
16368
17283
|
pr_comment: {
|
|
@@ -16381,34 +17296,35 @@ var ConfigManager = class {
|
|
|
16381
17296
|
const possiblePaths = [];
|
|
16382
17297
|
if (typeof __dirname !== "undefined") {
|
|
16383
17298
|
possiblePaths.push(
|
|
16384
|
-
|
|
16385
|
-
|
|
17299
|
+
path15.join(__dirname, "defaults", ".visor.yaml"),
|
|
17300
|
+
path15.join(__dirname, "..", "defaults", ".visor.yaml")
|
|
16386
17301
|
);
|
|
16387
17302
|
}
|
|
16388
17303
|
const pkgRoot = this.findPackageRoot();
|
|
16389
17304
|
if (pkgRoot) {
|
|
16390
|
-
possiblePaths.push(
|
|
17305
|
+
possiblePaths.push(path15.join(pkgRoot, "defaults", ".visor.yaml"));
|
|
16391
17306
|
}
|
|
16392
17307
|
if (process.env.GITHUB_ACTION_PATH) {
|
|
16393
17308
|
possiblePaths.push(
|
|
16394
|
-
|
|
16395
|
-
|
|
17309
|
+
path15.join(process.env.GITHUB_ACTION_PATH, "defaults", ".visor.yaml"),
|
|
17310
|
+
path15.join(process.env.GITHUB_ACTION_PATH, "dist", "defaults", ".visor.yaml")
|
|
16396
17311
|
);
|
|
16397
17312
|
}
|
|
16398
17313
|
let bundledConfigPath;
|
|
16399
17314
|
for (const possiblePath of possiblePaths) {
|
|
16400
|
-
if (
|
|
17315
|
+
if (fs13.existsSync(possiblePath)) {
|
|
16401
17316
|
bundledConfigPath = possiblePath;
|
|
16402
17317
|
break;
|
|
16403
17318
|
}
|
|
16404
17319
|
}
|
|
16405
|
-
if (bundledConfigPath &&
|
|
17320
|
+
if (bundledConfigPath && fs13.existsSync(bundledConfigPath)) {
|
|
16406
17321
|
console.error(`\u{1F4E6} Loading bundled default configuration from ${bundledConfigPath}`);
|
|
16407
|
-
const configContent =
|
|
16408
|
-
|
|
17322
|
+
const configContent = fs13.readFileSync(bundledConfigPath, "utf8");
|
|
17323
|
+
let parsedConfig = yaml2.load(configContent);
|
|
16409
17324
|
if (!parsedConfig || typeof parsedConfig !== "object") {
|
|
16410
17325
|
return null;
|
|
16411
17326
|
}
|
|
17327
|
+
parsedConfig = this.normalizeStepsAndChecks(parsedConfig);
|
|
16412
17328
|
this.validateConfig(parsedConfig);
|
|
16413
17329
|
return this.mergeWithDefaults(parsedConfig);
|
|
16414
17330
|
}
|
|
@@ -16425,21 +17341,35 @@ var ConfigManager = class {
|
|
|
16425
17341
|
*/
|
|
16426
17342
|
findPackageRoot() {
|
|
16427
17343
|
let currentDir = __dirname;
|
|
16428
|
-
while (currentDir !==
|
|
16429
|
-
const packageJsonPath =
|
|
16430
|
-
if (
|
|
17344
|
+
while (currentDir !== path15.dirname(currentDir)) {
|
|
17345
|
+
const packageJsonPath = path15.join(currentDir, "package.json");
|
|
17346
|
+
if (fs13.existsSync(packageJsonPath)) {
|
|
16431
17347
|
try {
|
|
16432
|
-
const packageJson = JSON.parse(
|
|
17348
|
+
const packageJson = JSON.parse(fs13.readFileSync(packageJsonPath, "utf8"));
|
|
16433
17349
|
if (packageJson.name === "@probelabs/visor") {
|
|
16434
17350
|
return currentDir;
|
|
16435
17351
|
}
|
|
16436
17352
|
} catch {
|
|
16437
17353
|
}
|
|
16438
17354
|
}
|
|
16439
|
-
currentDir =
|
|
17355
|
+
currentDir = path15.dirname(currentDir);
|
|
16440
17356
|
}
|
|
16441
17357
|
return null;
|
|
16442
17358
|
}
|
|
17359
|
+
/**
|
|
17360
|
+
* Normalize 'checks' and 'steps' keys for backward compatibility
|
|
17361
|
+
* Ensures both keys are present and contain the same data
|
|
17362
|
+
*/
|
|
17363
|
+
normalizeStepsAndChecks(config) {
|
|
17364
|
+
if (config.steps && config.checks) {
|
|
17365
|
+
config.checks = config.steps;
|
|
17366
|
+
} else if (config.steps && !config.checks) {
|
|
17367
|
+
config.checks = config.steps;
|
|
17368
|
+
} else if (config.checks && !config.steps) {
|
|
17369
|
+
config.steps = config.checks;
|
|
17370
|
+
}
|
|
17371
|
+
return config;
|
|
17372
|
+
}
|
|
16443
17373
|
/**
|
|
16444
17374
|
* Merge configuration with CLI options
|
|
16445
17375
|
*/
|
|
@@ -16495,13 +17425,15 @@ var ConfigManager = class {
|
|
|
16495
17425
|
message: "Missing required field: version"
|
|
16496
17426
|
});
|
|
16497
17427
|
}
|
|
16498
|
-
if (!config.checks) {
|
|
17428
|
+
if (!config.checks && !config.steps) {
|
|
16499
17429
|
errors.push({
|
|
16500
|
-
field: "checks",
|
|
16501
|
-
message:
|
|
17430
|
+
field: "checks/steps",
|
|
17431
|
+
message: 'Missing required field: either "checks" or "steps" must be defined. "steps" is recommended for new configurations.'
|
|
16502
17432
|
});
|
|
16503
|
-
}
|
|
16504
|
-
|
|
17433
|
+
}
|
|
17434
|
+
const checksToValidate = config.checks || config.steps;
|
|
17435
|
+
if (checksToValidate) {
|
|
17436
|
+
for (const [checkName, checkConfig] of Object.entries(checksToValidate)) {
|
|
16505
17437
|
if (!checkConfig.type) {
|
|
16506
17438
|
checkConfig.type = "ai";
|
|
16507
17439
|
}
|
|
@@ -16821,7 +17753,7 @@ var ConfigManager = class {
|
|
|
16821
17753
|
try {
|
|
16822
17754
|
if (!__ajvValidate) {
|
|
16823
17755
|
try {
|
|
16824
|
-
const jsonPath =
|
|
17756
|
+
const jsonPath = path15.resolve(__dirname, "generated", "config-schema.json");
|
|
16825
17757
|
const jsonSchema = require(jsonPath);
|
|
16826
17758
|
if (jsonSchema) {
|
|
16827
17759
|
const ajv = new import_ajv.default({ allErrors: true, allowUnionTypes: true, strict: false });
|
|
@@ -17110,6 +18042,9 @@ async function runChecks(opts = {}) {
|
|
|
17110
18042
|
}
|
|
17111
18043
|
const checks = opts.checks && opts.checks.length > 0 ? resolveChecks(opts.checks, config) : Object.keys(config.checks || {});
|
|
17112
18044
|
const engine = new CheckExecutionEngine(opts.cwd);
|
|
18045
|
+
if (opts.executionContext) {
|
|
18046
|
+
engine.setExecutionContext(opts.executionContext);
|
|
18047
|
+
}
|
|
17113
18048
|
const result = await engine.executeChecks({
|
|
17114
18049
|
checks,
|
|
17115
18050
|
workingDirectory: opts.cwd,
|