@probelabs/visor 0.1.131 → 0.1.132
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 +460 -596
- package/action.yml +2 -2
- package/dist/ai-review-service.d.ts +3 -0
- package/dist/ai-review-service.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/config/config-watcher.d.ts +15 -1
- package/dist/config/config-watcher.d.ts.map +1 -1
- package/dist/enterprise/policy/policy-input-builder.d.ts +2 -0
- package/dist/enterprise/policy/policy-input-builder.d.ts.map +1 -1
- package/dist/frontends/slack-frontend.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +404 -96
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +2875 -0
- package/dist/index.js +23064 -8507
- package/dist/{traces/run-2026-02-15T19-14-20-379Z.ndjson → output/traces/run-2026-02-18T11-06-48-673Z.ndjson} +84 -84
- package/dist/{traces/run-2026-02-15T19-15-09-410Z.ndjson → output/traces/run-2026-02-18T11-07-37-310Z.ndjson} +1017 -1017
- package/dist/providers/ai-check-provider.d.ts +12 -0
- package/dist/providers/ai-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-check-provider.d.ts.map +1 -1
- package/dist/providers/workflow-tool-executor.d.ts +5 -1
- package/dist/providers/workflow-tool-executor.d.ts.map +1 -1
- package/dist/sdk/{check-provider-registry-S7BMQ2FC.mjs → check-provider-registry-4WLTLPMU.mjs} +6 -6
- package/dist/sdk/{check-provider-registry-ZOLEYDKM.mjs → check-provider-registry-7TCA3NSG.mjs} +6 -6
- package/dist/sdk/{check-provider-registry-AAPPJ4CP.mjs → check-provider-registry-RRUZHGJI.mjs} +6 -6
- package/dist/sdk/{chunk-OMFPM576.mjs → chunk-27RV5RR2.mjs} +2 -2
- package/dist/sdk/{chunk-6ZZ4DPAA.mjs → chunk-5VY5QJTY.mjs} +231 -42
- package/dist/sdk/chunk-5VY5QJTY.mjs.map +1 -0
- package/dist/sdk/{chunk-2GCSK3PD.mjs → chunk-BGBXLPLL.mjs} +3 -3
- package/dist/sdk/{chunk-LDFUW34H.mjs → chunk-BOGVSF57.mjs} +231 -42
- package/dist/sdk/chunk-BOGVSF57.mjs.map +1 -0
- package/dist/sdk/{chunk-EBTD2D4L.mjs → chunk-FAKITJ3J.mjs} +2 -2
- package/dist/sdk/{chunk-RI77TA6V.mjs → chunk-LMJNI6RM.mjs} +4 -4
- package/dist/sdk/chunk-LMJNI6RM.mjs.map +1 -0
- package/dist/sdk/{chunk-LQ5B4T6L.mjs → chunk-U3BLLEW3.mjs} +431 -82
- package/dist/sdk/chunk-U3BLLEW3.mjs.map +1 -0
- package/dist/sdk/{chunk-VO4N6TEL.mjs → chunk-UBDHAGYY.mjs} +3 -3
- package/dist/sdk/{chunk-N4I6ZDCJ.mjs → chunk-VG7FWDC2.mjs} +3 -3
- package/dist/sdk/{chunk-RI77TA6V.mjs.map → chunk-VG7FWDC2.mjs.map} +1 -1
- package/dist/sdk/{chunk-MQ57AB4U.mjs → chunk-XGI47XIH.mjs} +260 -55
- package/dist/sdk/chunk-XGI47XIH.mjs.map +1 -0
- package/dist/sdk/{config-4EG7IQIU.mjs → config-FMIIATKX.mjs} +2 -2
- package/dist/sdk/{failure-condition-evaluator-GLHZZF47.mjs → failure-condition-evaluator-MUUAK7MN.mjs} +3 -3
- package/dist/sdk/{failure-condition-evaluator-KN55WXRO.mjs → failure-condition-evaluator-PNONVBXD.mjs} +3 -3
- package/dist/sdk/{github-frontend-F4TE2JY7.mjs → github-frontend-DWF6BLZH.mjs} +3 -3
- package/dist/sdk/{github-frontend-HCOKL53D.mjs → github-frontend-WR4S3NG5.mjs} +3 -3
- package/dist/sdk/{host-SAT6RHDX.mjs → host-S3LSWESP.mjs} +3 -3
- package/dist/sdk/{host-VA3ET7N6.mjs → host-U7V54J2H.mjs} +3 -3
- package/dist/sdk/{routing-KFYQGOYU.mjs → routing-F4FOWVKF.mjs} +4 -4
- package/dist/sdk/{routing-OXQKETSA.mjs → routing-MVDVJDYJ.mjs} +4 -4
- package/dist/sdk/{schedule-tool-handler-OQF57URO.mjs → schedule-tool-handler-7DNEGDZC.mjs} +6 -6
- package/dist/sdk/{schedule-tool-handler-PJVKWSYX.mjs → schedule-tool-handler-FRN3KKRM.mjs} +6 -6
- package/dist/sdk/{schedule-tool-handler-G353DHS6.mjs → schedule-tool-handler-VFES42DD.mjs} +6 -6
- package/dist/sdk/sdk.d.mts +56 -38
- package/dist/sdk/sdk.d.ts +56 -38
- package/dist/sdk/sdk.js +744 -115
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +5 -5
- package/dist/sdk/{slack-frontend-LAY45IBR.mjs → slack-frontend-JS2VAZWB.mjs} +95 -4
- package/dist/sdk/slack-frontend-JS2VAZWB.mjs.map +1 -0
- package/dist/sdk/{trace-helpers-R2ETIEC2.mjs → trace-helpers-KSPGA24B.mjs} +2 -2
- package/dist/sdk/{trace-helpers-LOPBHYYX.mjs → trace-helpers-RDPXIN4S.mjs} +2 -2
- package/dist/sdk/{workflow-check-provider-LRWD52WN.mjs → workflow-check-provider-4NFWH6YO.mjs} +6 -6
- package/dist/sdk/{workflow-check-provider-N2DRFQDB.mjs → workflow-check-provider-BMVJ6X7N.mjs} +6 -6
- package/dist/sdk/{workflow-check-provider-57KAR4Y4.mjs → workflow-check-provider-CPGIRZMH.mjs} +6 -6
- package/dist/slack/adapter.d.ts +2 -0
- package/dist/slack/adapter.d.ts.map +1 -1
- package/dist/slack/client.d.ts +3 -0
- package/dist/slack/client.d.ts.map +1 -1
- package/dist/slack/markdown.d.ts +29 -0
- package/dist/slack/markdown.d.ts.map +1 -1
- package/dist/slack/socket-runner.d.ts +2 -0
- package/dist/slack/socket-runner.d.ts.map +1 -1
- package/dist/{output/traces/run-2026-02-15T19-14-20-379Z.ndjson → traces/run-2026-02-18T11-06-48-673Z.ndjson} +84 -84
- package/dist/{output/traces/run-2026-02-15T19-15-09-410Z.ndjson → traces/run-2026-02-18T11-07-37-310Z.ndjson} +1017 -1017
- package/dist/tui/chat-tui.d.ts +7 -0
- package/dist/tui/chat-tui.d.ts.map +1 -1
- package/dist/tui/components/input-bar.d.ts +11 -0
- package/dist/tui/components/input-bar.d.ts.map +1 -1
- package/dist/tui/components/trace-viewer.d.ts +25 -1
- package/dist/tui/components/trace-viewer.d.ts.map +1 -1
- package/dist/types/bot.d.ts +12 -0
- package/dist/types/bot.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -1
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/defaults/.visor.yaml +0 -420
- package/dist/sdk/chunk-6ZZ4DPAA.mjs.map +0 -1
- package/dist/sdk/chunk-LDFUW34H.mjs.map +0 -1
- package/dist/sdk/chunk-LQ5B4T6L.mjs.map +0 -1
- package/dist/sdk/chunk-MQ57AB4U.mjs.map +0 -1
- package/dist/sdk/chunk-N4I6ZDCJ.mjs.map +0 -1
- package/dist/sdk/slack-frontend-LAY45IBR.mjs.map +0 -1
- /package/dist/sdk/{check-provider-registry-AAPPJ4CP.mjs.map → check-provider-registry-4WLTLPMU.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-S7BMQ2FC.mjs.map → check-provider-registry-7TCA3NSG.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-ZOLEYDKM.mjs.map → check-provider-registry-RRUZHGJI.mjs.map} +0 -0
- /package/dist/sdk/{chunk-EBTD2D4L.mjs.map → chunk-27RV5RR2.mjs.map} +0 -0
- /package/dist/sdk/{chunk-2GCSK3PD.mjs.map → chunk-BGBXLPLL.mjs.map} +0 -0
- /package/dist/sdk/{chunk-OMFPM576.mjs.map → chunk-FAKITJ3J.mjs.map} +0 -0
- /package/dist/sdk/{chunk-VO4N6TEL.mjs.map → chunk-UBDHAGYY.mjs.map} +0 -0
- /package/dist/sdk/{config-4EG7IQIU.mjs.map → config-FMIIATKX.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-GLHZZF47.mjs.map → failure-condition-evaluator-MUUAK7MN.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-KN55WXRO.mjs.map → failure-condition-evaluator-PNONVBXD.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-F4TE2JY7.mjs.map → github-frontend-DWF6BLZH.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-HCOKL53D.mjs.map → github-frontend-WR4S3NG5.mjs.map} +0 -0
- /package/dist/sdk/{host-SAT6RHDX.mjs.map → host-S3LSWESP.mjs.map} +0 -0
- /package/dist/sdk/{host-VA3ET7N6.mjs.map → host-U7V54J2H.mjs.map} +0 -0
- /package/dist/sdk/{routing-KFYQGOYU.mjs.map → routing-F4FOWVKF.mjs.map} +0 -0
- /package/dist/sdk/{routing-OXQKETSA.mjs.map → routing-MVDVJDYJ.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-G353DHS6.mjs.map → schedule-tool-handler-7DNEGDZC.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-OQF57URO.mjs.map → schedule-tool-handler-FRN3KKRM.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-PJVKWSYX.mjs.map → schedule-tool-handler-VFES42DD.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-LOPBHYYX.mjs.map → trace-helpers-KSPGA24B.mjs.map} +0 -0
- /package/dist/sdk/{trace-helpers-R2ETIEC2.mjs.map → trace-helpers-RDPXIN4S.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-57KAR4Y4.mjs.map → workflow-check-provider-4NFWH6YO.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-LRWD52WN.mjs.map → workflow-check-provider-BMVJ6X7N.mjs.map} +0 -0
- /package/dist/sdk/{workflow-check-provider-N2DRFQDB.mjs.map → workflow-check-provider-CPGIRZMH.mjs.map} +0 -0
package/dist/sdk/sdk.js
CHANGED
|
@@ -646,7 +646,7 @@ var require_package = __commonJS({
|
|
|
646
646
|
"package.json"(exports2, module2) {
|
|
647
647
|
module2.exports = {
|
|
648
648
|
name: "@probelabs/visor",
|
|
649
|
-
version: "0.1.
|
|
649
|
+
version: "0.1.132",
|
|
650
650
|
main: "dist/index.js",
|
|
651
651
|
bin: {
|
|
652
652
|
visor: "./dist/index.js"
|
|
@@ -731,7 +731,7 @@ var require_package = __commonJS({
|
|
|
731
731
|
],
|
|
732
732
|
author: "Probe Labs",
|
|
733
733
|
license: "MIT",
|
|
734
|
-
description: "AI
|
|
734
|
+
description: "AI workflow engine for code review, assistants, and automation \u2014 orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines",
|
|
735
735
|
repository: {
|
|
736
736
|
type: "git",
|
|
737
737
|
url: "git+https://github.com/probelabs/visor.git"
|
|
@@ -748,7 +748,7 @@ var require_package = __commonJS({
|
|
|
748
748
|
"@octokit/auth-app": "^8.1.0",
|
|
749
749
|
"@octokit/core": "^7.0.3",
|
|
750
750
|
"@octokit/rest": "^22.0.0",
|
|
751
|
-
"@probelabs/probe": "^0.6.0-
|
|
751
|
+
"@probelabs/probe": "^0.6.0-rc245",
|
|
752
752
|
"@types/commander": "^2.12.0",
|
|
753
753
|
"@types/uuid": "^10.0.0",
|
|
754
754
|
ajv: "^8.17.1",
|
|
@@ -7739,7 +7739,7 @@ ${this.escapeXml(processedFallbackDiff)}
|
|
|
7739
7739
|
<user>${this.escapeXml(String(m.user || ""))}</user>
|
|
7740
7740
|
<text>${this.escapeXml(String(m.text || ""))}</text>
|
|
7741
7741
|
<timestamp>${this.escapeXml(String(m.timestamp || ""))}</timestamp>
|
|
7742
|
-
<origin>${this.escapeXml(String(m.origin || ""))}</origin
|
|
7742
|
+
<origin>${this.escapeXml(String(m.origin || ""))}</origin>${this.formatFilesXml(m.files)}
|
|
7743
7743
|
</message>`;
|
|
7744
7744
|
}
|
|
7745
7745
|
xml += `
|
|
@@ -7751,7 +7751,7 @@ ${this.escapeXml(processedFallbackDiff)}
|
|
|
7751
7751
|
<user>${this.escapeXml(String(current.user || ""))}</user>
|
|
7752
7752
|
<text>${this.escapeXml(String(current.text || ""))}</text>
|
|
7753
7753
|
<timestamp>${this.escapeXml(String(current.timestamp || ""))}</timestamp>
|
|
7754
|
-
<origin>${this.escapeXml(String(current.origin || ""))}</origin
|
|
7754
|
+
<origin>${this.escapeXml(String(current.origin || ""))}</origin>${this.formatFilesXml(current.files)}
|
|
7755
7755
|
</current>
|
|
7756
7756
|
</slack_context>`;
|
|
7757
7757
|
return xml;
|
|
@@ -7759,6 +7759,25 @@ ${this.escapeXml(processedFallbackDiff)}
|
|
|
7759
7759
|
return "";
|
|
7760
7760
|
}
|
|
7761
7761
|
}
|
|
7762
|
+
/** Render file attachment metadata as XML fragment for a message. */
|
|
7763
|
+
formatFilesXml(files) {
|
|
7764
|
+
if (!Array.isArray(files) || files.length === 0) return "";
|
|
7765
|
+
let xml = `
|
|
7766
|
+
<files>`;
|
|
7767
|
+
for (const f of files) {
|
|
7768
|
+
xml += `
|
|
7769
|
+
<file>
|
|
7770
|
+
<name>${this.escapeXml(String(f.name || ""))}</name>
|
|
7771
|
+
<mimetype>${this.escapeXml(String(f.mimetype || ""))}</mimetype>
|
|
7772
|
+
<filetype>${this.escapeXml(String(f.filetype || ""))}</filetype>
|
|
7773
|
+
<url>${this.escapeXml(String(f.url_private || f.permalink || ""))}</url>
|
|
7774
|
+
<size>${f.size || 0}</size>
|
|
7775
|
+
</file>`;
|
|
7776
|
+
}
|
|
7777
|
+
xml += `
|
|
7778
|
+
</files>`;
|
|
7779
|
+
return xml;
|
|
7780
|
+
}
|
|
7762
7781
|
/**
|
|
7763
7782
|
* Build a normalized ConversationContext for GitHub (PR/issue + comments)
|
|
7764
7783
|
* using the same contract as Slack's ConversationContext. This is exposed
|
|
@@ -8264,6 +8283,9 @@ ${"=".repeat(60)}
|
|
|
8264
8283
|
if (this.config.enableTasks !== void 0) {
|
|
8265
8284
|
options.enableTasks = this.config.enableTasks;
|
|
8266
8285
|
}
|
|
8286
|
+
if (this.config.enableExecutePlan !== void 0) {
|
|
8287
|
+
options.enableExecutePlan = this.config.enableExecutePlan;
|
|
8288
|
+
}
|
|
8267
8289
|
if (this.config.retry) {
|
|
8268
8290
|
options.retry = this.config.retry;
|
|
8269
8291
|
}
|
|
@@ -8711,7 +8733,22 @@ ${"=".repeat(60)}
|
|
|
8711
8733
|
log("\u{1F4CB} Full response preview:", response);
|
|
8712
8734
|
}
|
|
8713
8735
|
try {
|
|
8714
|
-
let reviewData;
|
|
8736
|
+
let reviewData = void 0;
|
|
8737
|
+
const RAW_OUTPUT_RE = /\n<<<RAW_OUTPUT>>>\n([\s\S]*?)\n<<<END_RAW_OUTPUT>>>/g;
|
|
8738
|
+
const rawOutputBlocks = [];
|
|
8739
|
+
let responseForParsing = response;
|
|
8740
|
+
{
|
|
8741
|
+
let rawMatch;
|
|
8742
|
+
while ((rawMatch = RAW_OUTPUT_RE.exec(response)) !== null) {
|
|
8743
|
+
rawOutputBlocks.push(rawMatch[1]);
|
|
8744
|
+
}
|
|
8745
|
+
if (rawOutputBlocks.length > 0) {
|
|
8746
|
+
responseForParsing = response.replace(RAW_OUTPUT_RE, "");
|
|
8747
|
+
log(
|
|
8748
|
+
`\u{1F4E6} Extracted ${rawOutputBlocks.length} RAW_OUTPUT blocks (${rawOutputBlocks.reduce((s, b) => s + b.length, 0)} chars) from response`
|
|
8749
|
+
);
|
|
8750
|
+
}
|
|
8751
|
+
}
|
|
8715
8752
|
if (_schema === "plain" || !_schema) {
|
|
8716
8753
|
log(
|
|
8717
8754
|
`\u{1F4CB} ${_schema === "plain" ? "Plain" : "No"} schema detected - treating raw response as text output`
|
|
@@ -8728,7 +8765,7 @@ ${"=".repeat(60)}
|
|
|
8728
8765
|
}
|
|
8729
8766
|
{
|
|
8730
8767
|
log("\u{1F50D} Extracting JSON from AI response...");
|
|
8731
|
-
const sanitizedResponse =
|
|
8768
|
+
const sanitizedResponse = responseForParsing.replace(/^\uFEFF/, "").replace(/[\u200B-\u200D\uFEFF\u00A0]/g, "").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "").trim();
|
|
8732
8769
|
try {
|
|
8733
8770
|
reviewData = JSON.parse(sanitizedResponse);
|
|
8734
8771
|
log("\u2705 Successfully parsed direct JSON response");
|
|
@@ -8736,22 +8773,48 @@ ${"=".repeat(60)}
|
|
|
8736
8773
|
} catch (parseErr) {
|
|
8737
8774
|
const errMsg = parseErr instanceof Error ? parseErr.message : String(parseErr);
|
|
8738
8775
|
log(`\u{1F50D} Direct JSON parsing failed: ${errMsg}`);
|
|
8739
|
-
|
|
8740
|
-
|
|
8741
|
-
|
|
8776
|
+
let recovered = false;
|
|
8777
|
+
const trailingMatch = errMsg.match(/after JSON at position (\d+)/);
|
|
8778
|
+
if (trailingMatch) {
|
|
8779
|
+
const pos = parseInt(trailingMatch[1], 10);
|
|
8780
|
+
try {
|
|
8781
|
+
reviewData = JSON.parse(sanitizedResponse.substring(0, pos));
|
|
8782
|
+
const trailing = sanitizedResponse.substring(pos).trim();
|
|
8783
|
+
if (trailing && reviewData && typeof reviewData === "object" && typeof reviewData.text === "string") {
|
|
8784
|
+
reviewData.text = reviewData.text + "\n\n" + trailing;
|
|
8785
|
+
log(
|
|
8786
|
+
`\u2705 Recovered JSON and appended ${trailing.length} chars of trailing content to text field`
|
|
8787
|
+
);
|
|
8788
|
+
} else {
|
|
8789
|
+
log(`\u2705 Recovered JSON by trimming trailing content at position ${pos}`);
|
|
8790
|
+
}
|
|
8791
|
+
if (debugInfo) debugInfo.jsonParseSuccess = true;
|
|
8792
|
+
recovered = true;
|
|
8793
|
+
} catch {
|
|
8794
|
+
}
|
|
8795
|
+
}
|
|
8796
|
+
if (!recovered) {
|
|
8797
|
+
if (response.toLowerCase().includes("i cannot") || response.toLowerCase().includes("unable to")) {
|
|
8798
|
+
console.error("\u{1F6AB} AI refused to analyze - returning refusal as output");
|
|
8799
|
+
const trimmed2 = responseForParsing.trim();
|
|
8800
|
+
const out = trimmed2 ? { text: trimmed2 } : {};
|
|
8801
|
+
if (rawOutputBlocks.length > 0) out._rawOutput = rawOutputBlocks.join("\n\n");
|
|
8802
|
+
return {
|
|
8803
|
+
issues: [],
|
|
8804
|
+
output: out,
|
|
8805
|
+
debug: debugInfo
|
|
8806
|
+
};
|
|
8807
|
+
}
|
|
8808
|
+
log("\u{1F527} Treating response as plain text (no JSON extraction)");
|
|
8809
|
+
const trimmed = responseForParsing.trim();
|
|
8810
|
+
const fallbackOut = { text: trimmed };
|
|
8811
|
+
if (rawOutputBlocks.length > 0) fallbackOut._rawOutput = rawOutputBlocks.join("\n\n");
|
|
8742
8812
|
return {
|
|
8743
8813
|
issues: [],
|
|
8744
|
-
output:
|
|
8814
|
+
output: fallbackOut,
|
|
8745
8815
|
debug: debugInfo
|
|
8746
8816
|
};
|
|
8747
8817
|
}
|
|
8748
|
-
log("\u{1F527} Treating response as plain text (no JSON extraction)");
|
|
8749
|
-
const trimmed = response.trim();
|
|
8750
|
-
return {
|
|
8751
|
-
issues: [],
|
|
8752
|
-
output: { text: trimmed },
|
|
8753
|
-
debug: debugInfo
|
|
8754
|
-
};
|
|
8755
8818
|
}
|
|
8756
8819
|
}
|
|
8757
8820
|
const looksLikeTextOutput = reviewData && typeof reviewData === "object" && typeof reviewData.text === "string" && String(reviewData.text).trim().length > 0;
|
|
@@ -8799,6 +8862,9 @@ ${"=".repeat(60)}
|
|
|
8799
8862
|
out.text = fallbackText;
|
|
8800
8863
|
}
|
|
8801
8864
|
}
|
|
8865
|
+
if (rawOutputBlocks.length > 0) {
|
|
8866
|
+
out._rawOutput = rawOutputBlocks.join("\n\n");
|
|
8867
|
+
}
|
|
8802
8868
|
const result2 = {
|
|
8803
8869
|
// Keep issues empty for custom-schema rendering; consumers read from output.*
|
|
8804
8870
|
issues: [],
|
|
@@ -11112,6 +11178,10 @@ var init_config_schema = __esm({
|
|
|
11112
11178
|
type: "number",
|
|
11113
11179
|
description: "Maximum number of checks to run in parallel (default: 3)"
|
|
11114
11180
|
},
|
|
11181
|
+
max_ai_concurrency: {
|
|
11182
|
+
type: "number",
|
|
11183
|
+
description: "Maximum total concurrent AI API calls across all checks (default: unlimited). When set, creates a shared concurrency limiter that gates every LLM request across all ProbeAgent instances in this run."
|
|
11184
|
+
},
|
|
11115
11185
|
fail_fast: {
|
|
11116
11186
|
type: "boolean",
|
|
11117
11187
|
description: "Stop execution when any check fails (default: false)"
|
|
@@ -11158,6 +11228,18 @@ var init_config_schema = __esm({
|
|
|
11158
11228
|
$ref: "#/definitions/WorkspaceConfig",
|
|
11159
11229
|
description: "Workspace isolation configuration for sandboxed execution"
|
|
11160
11230
|
},
|
|
11231
|
+
sandbox: {
|
|
11232
|
+
type: "string",
|
|
11233
|
+
description: "Workspace-level default sandbox name (all checks use this unless overridden)"
|
|
11234
|
+
},
|
|
11235
|
+
sandboxes: {
|
|
11236
|
+
$ref: "#/definitions/Record%3Cstring%2CSandboxConfig%3E",
|
|
11237
|
+
description: "Named sandbox environment definitions"
|
|
11238
|
+
},
|
|
11239
|
+
sandbox_defaults: {
|
|
11240
|
+
$ref: "#/definitions/SandboxDefaults",
|
|
11241
|
+
description: "Workspace-level sandbox defaults (env allowlist, etc.)"
|
|
11242
|
+
},
|
|
11161
11243
|
slack: {
|
|
11162
11244
|
$ref: "#/definitions/SlackConfig",
|
|
11163
11245
|
description: "Slack configuration"
|
|
@@ -11168,7 +11250,7 @@ var init_config_schema = __esm({
|
|
|
11168
11250
|
},
|
|
11169
11251
|
policy: {
|
|
11170
11252
|
$ref: "#/definitions/PolicyConfig",
|
|
11171
|
-
description: "Enterprise policy engine configuration
|
|
11253
|
+
description: "Enterprise policy engine configuration"
|
|
11172
11254
|
}
|
|
11173
11255
|
},
|
|
11174
11256
|
required: ["version"],
|
|
@@ -11471,7 +11553,7 @@ var init_config_schema = __esm({
|
|
|
11471
11553
|
},
|
|
11472
11554
|
ai_bash_config_js: {
|
|
11473
11555
|
type: "string",
|
|
11474
|
-
description: "JavaScript expression to dynamically compute bash configuration for this AI check. Expression has access to: outputs, inputs, pr, files, env, memory
|
|
11556
|
+
description: "JavaScript expression to dynamically compute bash configuration for this AI check. Expression has access to: outputs, inputs, pr, files, env, memory Must return a BashConfig object with allow/deny arrays.\n\nExample: ``` return outputs['build-config']?.bash_config ?? {}; ```"
|
|
11475
11557
|
},
|
|
11476
11558
|
claude_code: {
|
|
11477
11559
|
$ref: "#/definitions/ClaudeCodeConfig",
|
|
@@ -11737,7 +11819,7 @@ var init_config_schema = __esm({
|
|
|
11737
11819
|
description: "Arguments/inputs for the workflow"
|
|
11738
11820
|
},
|
|
11739
11821
|
overrides: {
|
|
11740
|
-
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
11822
|
+
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E%3E",
|
|
11741
11823
|
description: "Override specific step configurations in the workflow"
|
|
11742
11824
|
},
|
|
11743
11825
|
output_mapping: {
|
|
@@ -11753,7 +11835,7 @@ var init_config_schema = __esm({
|
|
|
11753
11835
|
description: "Config file path - alternative to workflow ID (loads a Visor config file as workflow)"
|
|
11754
11836
|
},
|
|
11755
11837
|
workflow_overrides: {
|
|
11756
|
-
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
11838
|
+
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E%3E",
|
|
11757
11839
|
description: "Alias for overrides - workflow step overrides (backward compatibility)"
|
|
11758
11840
|
},
|
|
11759
11841
|
ref: {
|
|
@@ -11823,6 +11905,10 @@ var init_config_schema = __esm({
|
|
|
11823
11905
|
type: "boolean",
|
|
11824
11906
|
description: "Keep worktree after workflow completion (default: false)"
|
|
11825
11907
|
},
|
|
11908
|
+
sandbox: {
|
|
11909
|
+
type: "string",
|
|
11910
|
+
description: "Sandbox name to use for this check (overrides workspace-level default)"
|
|
11911
|
+
},
|
|
11826
11912
|
policy: {
|
|
11827
11913
|
$ref: "#/definitions/StepPolicyOverride",
|
|
11828
11914
|
description: "Per-step policy override (enterprise)"
|
|
@@ -11967,6 +12053,14 @@ var init_config_schema = __esm({
|
|
|
11967
12053
|
completion_prompt: {
|
|
11968
12054
|
type: "string",
|
|
11969
12055
|
description: "Completion prompt for post-completion validation/review (runs after attempt_completion)"
|
|
12056
|
+
},
|
|
12057
|
+
enable_scheduler: {
|
|
12058
|
+
type: "boolean",
|
|
12059
|
+
description: "Enable the schedule tool for scheduling workflow executions (requires scheduler configuration)"
|
|
12060
|
+
},
|
|
12061
|
+
enableExecutePlan: {
|
|
12062
|
+
type: "boolean",
|
|
12063
|
+
description: "Enable the execute_plan DSL orchestration tool (replaces analyze_all when enabled)"
|
|
11970
12064
|
}
|
|
11971
12065
|
},
|
|
11972
12066
|
additionalProperties: false,
|
|
@@ -12429,7 +12523,7 @@ var init_config_schema = __esm({
|
|
|
12429
12523
|
description: "Custom output name (defaults to workflow name)"
|
|
12430
12524
|
},
|
|
12431
12525
|
overrides: {
|
|
12432
|
-
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-
|
|
12526
|
+
$ref: "#/definitions/Record%3Cstring%2CPartial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E%3E",
|
|
12433
12527
|
description: "Step overrides"
|
|
12434
12528
|
},
|
|
12435
12529
|
output_mapping: {
|
|
@@ -12444,13 +12538,13 @@ var init_config_schema = __esm({
|
|
|
12444
12538
|
"^x-": {}
|
|
12445
12539
|
}
|
|
12446
12540
|
},
|
|
12447
|
-
"Record<string,Partial<interface-src_types_config.ts-
|
|
12541
|
+
"Record<string,Partial<interface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381>>": {
|
|
12448
12542
|
type: "object",
|
|
12449
12543
|
additionalProperties: {
|
|
12450
|
-
$ref: "#/definitions/Partial%3Cinterface-src_types_config.ts-
|
|
12544
|
+
$ref: "#/definitions/Partial%3Cinterface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381%3E"
|
|
12451
12545
|
}
|
|
12452
12546
|
},
|
|
12453
|
-
"Partial<interface-src_types_config.ts-
|
|
12547
|
+
"Partial<interface-src_types_config.ts-13489-27516-src_types_config.ts-0-51381>": {
|
|
12454
12548
|
type: "object",
|
|
12455
12549
|
additionalProperties: false
|
|
12456
12550
|
},
|
|
@@ -12564,9 +12658,9 @@ var init_config_schema = __esm({
|
|
|
12564
12658
|
run: {
|
|
12565
12659
|
type: "array",
|
|
12566
12660
|
items: {
|
|
12567
|
-
|
|
12661
|
+
$ref: "#/definitions/OnSuccessRunItem"
|
|
12568
12662
|
},
|
|
12569
|
-
description: "Post-success steps to run"
|
|
12663
|
+
description: "Post-success steps to run - can be step names or rich invocations with arguments"
|
|
12570
12664
|
},
|
|
12571
12665
|
goto: {
|
|
12572
12666
|
type: "string",
|
|
@@ -12598,6 +12692,20 @@ var init_config_schema = __esm({
|
|
|
12598
12692
|
"^x-": {}
|
|
12599
12693
|
}
|
|
12600
12694
|
},
|
|
12695
|
+
OnSuccessRunItem: {
|
|
12696
|
+
anyOf: [
|
|
12697
|
+
{
|
|
12698
|
+
type: "string"
|
|
12699
|
+
},
|
|
12700
|
+
{
|
|
12701
|
+
$ref: "#/definitions/OnInitStepInvocation"
|
|
12702
|
+
},
|
|
12703
|
+
{
|
|
12704
|
+
$ref: "#/definitions/OnInitWorkflowInvocation"
|
|
12705
|
+
}
|
|
12706
|
+
],
|
|
12707
|
+
description: "Success routing run item - can be step name, step with args, or workflow with args"
|
|
12708
|
+
},
|
|
12601
12709
|
OnFinishConfig: {
|
|
12602
12710
|
type: "object",
|
|
12603
12711
|
properties: {
|
|
@@ -12638,6 +12746,40 @@ var init_config_schema = __esm({
|
|
|
12638
12746
|
"^x-": {}
|
|
12639
12747
|
}
|
|
12640
12748
|
},
|
|
12749
|
+
StepPolicyOverride: {
|
|
12750
|
+
type: "object",
|
|
12751
|
+
properties: {
|
|
12752
|
+
require: {
|
|
12753
|
+
anyOf: [
|
|
12754
|
+
{
|
|
12755
|
+
type: "string"
|
|
12756
|
+
},
|
|
12757
|
+
{
|
|
12758
|
+
type: "array",
|
|
12759
|
+
items: {
|
|
12760
|
+
type: "string"
|
|
12761
|
+
}
|
|
12762
|
+
}
|
|
12763
|
+
],
|
|
12764
|
+
description: "Required role(s) - any of these roles suffices"
|
|
12765
|
+
},
|
|
12766
|
+
deny: {
|
|
12767
|
+
type: "array",
|
|
12768
|
+
items: {
|
|
12769
|
+
type: "string"
|
|
12770
|
+
},
|
|
12771
|
+
description: "Explicit deny for roles"
|
|
12772
|
+
},
|
|
12773
|
+
rule: {
|
|
12774
|
+
type: "string",
|
|
12775
|
+
description: "Custom OPA rule path for this step"
|
|
12776
|
+
}
|
|
12777
|
+
},
|
|
12778
|
+
additionalProperties: false,
|
|
12779
|
+
patternProperties: {
|
|
12780
|
+
"^x-": {}
|
|
12781
|
+
}
|
|
12782
|
+
},
|
|
12641
12783
|
OutputConfig: {
|
|
12642
12784
|
type: "object",
|
|
12643
12785
|
properties: {
|
|
@@ -13044,6 +13186,141 @@ var init_config_schema = __esm({
|
|
|
13044
13186
|
"^x-": {}
|
|
13045
13187
|
}
|
|
13046
13188
|
},
|
|
13189
|
+
"Record<string,SandboxConfig>": {
|
|
13190
|
+
type: "object",
|
|
13191
|
+
additionalProperties: {
|
|
13192
|
+
$ref: "#/definitions/SandboxConfig"
|
|
13193
|
+
}
|
|
13194
|
+
},
|
|
13195
|
+
SandboxConfig: {
|
|
13196
|
+
type: "object",
|
|
13197
|
+
properties: {
|
|
13198
|
+
image: {
|
|
13199
|
+
type: "string",
|
|
13200
|
+
description: 'Docker image to use (e.g., "node:20-alpine")'
|
|
13201
|
+
},
|
|
13202
|
+
dockerfile: {
|
|
13203
|
+
type: "string",
|
|
13204
|
+
description: "Path to Dockerfile (relative to config file or absolute)"
|
|
13205
|
+
},
|
|
13206
|
+
dockerfile_inline: {
|
|
13207
|
+
type: "string",
|
|
13208
|
+
description: "Inline Dockerfile content"
|
|
13209
|
+
},
|
|
13210
|
+
compose: {
|
|
13211
|
+
type: "string",
|
|
13212
|
+
description: "Path to docker-compose file"
|
|
13213
|
+
},
|
|
13214
|
+
service: {
|
|
13215
|
+
type: "string",
|
|
13216
|
+
description: "Service name within the compose file"
|
|
13217
|
+
},
|
|
13218
|
+
workdir: {
|
|
13219
|
+
type: "string",
|
|
13220
|
+
description: "Working directory inside container (default: /workspace)"
|
|
13221
|
+
},
|
|
13222
|
+
env_passthrough: {
|
|
13223
|
+
type: "array",
|
|
13224
|
+
items: {
|
|
13225
|
+
type: "string"
|
|
13226
|
+
},
|
|
13227
|
+
description: "Glob patterns for host env vars to forward into sandbox"
|
|
13228
|
+
},
|
|
13229
|
+
network: {
|
|
13230
|
+
type: "boolean",
|
|
13231
|
+
description: "Enable/disable network access (default: true)"
|
|
13232
|
+
},
|
|
13233
|
+
read_only: {
|
|
13234
|
+
type: "boolean",
|
|
13235
|
+
description: "Mount repo as read-only (default: false)"
|
|
13236
|
+
},
|
|
13237
|
+
resources: {
|
|
13238
|
+
$ref: "#/definitions/SandboxResourceConfig",
|
|
13239
|
+
description: "Resource limits"
|
|
13240
|
+
},
|
|
13241
|
+
visor_path: {
|
|
13242
|
+
type: "string",
|
|
13243
|
+
description: "Where visor is mounted inside container (default: /opt/visor)"
|
|
13244
|
+
},
|
|
13245
|
+
cache: {
|
|
13246
|
+
$ref: "#/definitions/SandboxCacheConfig",
|
|
13247
|
+
description: "Cache volume configuration"
|
|
13248
|
+
}
|
|
13249
|
+
},
|
|
13250
|
+
additionalProperties: false,
|
|
13251
|
+
description: "Configuration for a single sandbox environment",
|
|
13252
|
+
patternProperties: {
|
|
13253
|
+
"^x-": {}
|
|
13254
|
+
}
|
|
13255
|
+
},
|
|
13256
|
+
SandboxResourceConfig: {
|
|
13257
|
+
type: "object",
|
|
13258
|
+
properties: {
|
|
13259
|
+
memory: {
|
|
13260
|
+
type: "string",
|
|
13261
|
+
description: 'Memory limit (e.g., "512m", "2g")'
|
|
13262
|
+
},
|
|
13263
|
+
cpu: {
|
|
13264
|
+
type: "number",
|
|
13265
|
+
description: "CPU limit (e.g., 1.0, 0.5)"
|
|
13266
|
+
}
|
|
13267
|
+
},
|
|
13268
|
+
additionalProperties: false,
|
|
13269
|
+
description: "Resource limits for sandbox containers",
|
|
13270
|
+
patternProperties: {
|
|
13271
|
+
"^x-": {}
|
|
13272
|
+
}
|
|
13273
|
+
},
|
|
13274
|
+
SandboxCacheConfig: {
|
|
13275
|
+
type: "object",
|
|
13276
|
+
properties: {
|
|
13277
|
+
prefix: {
|
|
13278
|
+
type: "string",
|
|
13279
|
+
description: "Liquid template for cache scope prefix (default: git branch)"
|
|
13280
|
+
},
|
|
13281
|
+
fallback_prefix: {
|
|
13282
|
+
type: "string",
|
|
13283
|
+
description: "Fallback prefix when current prefix has no cache"
|
|
13284
|
+
},
|
|
13285
|
+
paths: {
|
|
13286
|
+
type: "array",
|
|
13287
|
+
items: {
|
|
13288
|
+
type: "string"
|
|
13289
|
+
},
|
|
13290
|
+
description: "Paths inside the container to cache"
|
|
13291
|
+
},
|
|
13292
|
+
ttl: {
|
|
13293
|
+
type: "string",
|
|
13294
|
+
description: 'Time-to-live for cache volumes (e.g., "7d", "24h")'
|
|
13295
|
+
},
|
|
13296
|
+
max_scopes: {
|
|
13297
|
+
type: "number",
|
|
13298
|
+
description: "Maximum number of cache scopes to keep"
|
|
13299
|
+
}
|
|
13300
|
+
},
|
|
13301
|
+
required: ["paths"],
|
|
13302
|
+
additionalProperties: false,
|
|
13303
|
+
description: "Cache configuration for sandbox volumes",
|
|
13304
|
+
patternProperties: {
|
|
13305
|
+
"^x-": {}
|
|
13306
|
+
}
|
|
13307
|
+
},
|
|
13308
|
+
SandboxDefaults: {
|
|
13309
|
+
type: "object",
|
|
13310
|
+
properties: {
|
|
13311
|
+
env_passthrough: {
|
|
13312
|
+
type: "array",
|
|
13313
|
+
items: {
|
|
13314
|
+
type: "string"
|
|
13315
|
+
},
|
|
13316
|
+
description: "Base env var patterns for all sandboxes (replaces hardcoded defaults when set)"
|
|
13317
|
+
}
|
|
13318
|
+
},
|
|
13319
|
+
additionalProperties: false,
|
|
13320
|
+
patternProperties: {
|
|
13321
|
+
"^x-": {}
|
|
13322
|
+
}
|
|
13323
|
+
},
|
|
13047
13324
|
SlackConfig: {
|
|
13048
13325
|
type: "object",
|
|
13049
13326
|
properties: {
|
|
@@ -13103,7 +13380,16 @@ var init_config_schema = __esm({
|
|
|
13103
13380
|
properties: {
|
|
13104
13381
|
path: {
|
|
13105
13382
|
type: "string",
|
|
13106
|
-
description: "Path to schedules JSON file (
|
|
13383
|
+
description: "Path to schedules JSON file (legacy, triggers auto-migration)"
|
|
13384
|
+
},
|
|
13385
|
+
driver: {
|
|
13386
|
+
type: "string",
|
|
13387
|
+
enum: ["sqlite", "postgresql", "mysql", "mssql"],
|
|
13388
|
+
description: "Database driver (default: 'sqlite')"
|
|
13389
|
+
},
|
|
13390
|
+
connection: {
|
|
13391
|
+
$ref: "#/definitions/SchedulerStorageConnectionConfig",
|
|
13392
|
+
description: "Database connection configuration"
|
|
13107
13393
|
}
|
|
13108
13394
|
},
|
|
13109
13395
|
additionalProperties: false,
|
|
@@ -13112,6 +13398,10 @@ var init_config_schema = __esm({
|
|
|
13112
13398
|
"^x-": {}
|
|
13113
13399
|
}
|
|
13114
13400
|
},
|
|
13401
|
+
ha: {
|
|
13402
|
+
$ref: "#/definitions/SchedulerHAConfig",
|
|
13403
|
+
description: "High-availability configuration for multi-node deployments"
|
|
13404
|
+
},
|
|
13115
13405
|
limits: {
|
|
13116
13406
|
$ref: "#/definitions/SchedulerLimitsConfig",
|
|
13117
13407
|
description: "Limits for dynamic schedules"
|
|
@@ -13139,44 +13429,123 @@ var init_config_schema = __esm({
|
|
|
13139
13429
|
"^x-": {}
|
|
13140
13430
|
}
|
|
13141
13431
|
},
|
|
13142
|
-
|
|
13432
|
+
SchedulerStorageConnectionConfig: {
|
|
13143
13433
|
type: "object",
|
|
13144
13434
|
properties: {
|
|
13145
|
-
|
|
13435
|
+
filename: {
|
|
13146
13436
|
type: "string",
|
|
13147
|
-
|
|
13148
|
-
description: "Policy engine mode: 'local' (WASM), 'remote' (HTTP OPA server), or 'disabled'"
|
|
13437
|
+
description: "SQLite database file path (default: '.visor/schedules.db')"
|
|
13149
13438
|
},
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
description: "
|
|
13439
|
+
host: {
|
|
13440
|
+
type: "string",
|
|
13441
|
+
description: "Database host (PostgreSQL/MySQL/MSSQL)"
|
|
13153
13442
|
},
|
|
13154
|
-
|
|
13443
|
+
port: {
|
|
13444
|
+
type: "number",
|
|
13445
|
+
description: "Database port (PostgreSQL/MySQL/MSSQL)"
|
|
13446
|
+
},
|
|
13447
|
+
database: {
|
|
13155
13448
|
type: "string",
|
|
13156
|
-
description: "
|
|
13449
|
+
description: "Database name (PostgreSQL/MySQL/MSSQL)"
|
|
13157
13450
|
},
|
|
13158
|
-
|
|
13451
|
+
user: {
|
|
13159
13452
|
type: "string",
|
|
13160
|
-
description: "
|
|
13453
|
+
description: "Database user (PostgreSQL/MySQL/MSSQL)"
|
|
13161
13454
|
},
|
|
13162
|
-
|
|
13455
|
+
password: {
|
|
13163
13456
|
type: "string",
|
|
13164
|
-
|
|
13165
|
-
description: "Default decision when policy evaluation fails (default: 'deny'). Use 'warn' for audit mode: violations are logged but not enforced."
|
|
13457
|
+
description: "Database password (PostgreSQL/MySQL/MSSQL)"
|
|
13166
13458
|
},
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13459
|
+
ssl: {
|
|
13460
|
+
anyOf: [
|
|
13461
|
+
{
|
|
13462
|
+
type: "boolean"
|
|
13463
|
+
},
|
|
13464
|
+
{
|
|
13465
|
+
$ref: "#/definitions/SchedulerSslConfig"
|
|
13466
|
+
}
|
|
13467
|
+
],
|
|
13468
|
+
description: "SSL/TLS configuration (PostgreSQL/MySQL/MSSQL)"
|
|
13170
13469
|
},
|
|
13171
|
-
|
|
13470
|
+
connection_string: {
|
|
13471
|
+
type: "string",
|
|
13472
|
+
description: "Connection string URL (e.g., postgresql://user:pass@host/db)"
|
|
13473
|
+
},
|
|
13474
|
+
pool: {
|
|
13172
13475
|
type: "object",
|
|
13173
|
-
|
|
13174
|
-
|
|
13476
|
+
properties: {
|
|
13477
|
+
min: {
|
|
13478
|
+
type: "number"
|
|
13479
|
+
},
|
|
13480
|
+
max: {
|
|
13481
|
+
type: "number"
|
|
13482
|
+
}
|
|
13175
13483
|
},
|
|
13176
|
-
|
|
13484
|
+
additionalProperties: false,
|
|
13485
|
+
description: "Connection pool configuration",
|
|
13486
|
+
patternProperties: {
|
|
13487
|
+
"^x-": {}
|
|
13488
|
+
}
|
|
13489
|
+
}
|
|
13490
|
+
},
|
|
13491
|
+
additionalProperties: false,
|
|
13492
|
+
description: "Scheduler storage connection configuration",
|
|
13493
|
+
patternProperties: {
|
|
13494
|
+
"^x-": {}
|
|
13495
|
+
}
|
|
13496
|
+
},
|
|
13497
|
+
SchedulerSslConfig: {
|
|
13498
|
+
type: "object",
|
|
13499
|
+
properties: {
|
|
13500
|
+
enabled: {
|
|
13501
|
+
type: "boolean",
|
|
13502
|
+
description: "Enable SSL (default: true when SslConfig object is provided)"
|
|
13503
|
+
},
|
|
13504
|
+
reject_unauthorized: {
|
|
13505
|
+
type: "boolean",
|
|
13506
|
+
description: "Reject unauthorized certificates (default: true)"
|
|
13507
|
+
},
|
|
13508
|
+
ca: {
|
|
13509
|
+
type: "string",
|
|
13510
|
+
description: "Path to CA certificate PEM file"
|
|
13511
|
+
},
|
|
13512
|
+
cert: {
|
|
13513
|
+
type: "string",
|
|
13514
|
+
description: "Path to client certificate PEM file"
|
|
13515
|
+
},
|
|
13516
|
+
key: {
|
|
13517
|
+
type: "string",
|
|
13518
|
+
description: "Path to client key PEM file"
|
|
13177
13519
|
}
|
|
13178
13520
|
},
|
|
13179
13521
|
additionalProperties: false,
|
|
13522
|
+
description: "SSL/TLS configuration for scheduler database connections",
|
|
13523
|
+
patternProperties: {
|
|
13524
|
+
"^x-": {}
|
|
13525
|
+
}
|
|
13526
|
+
},
|
|
13527
|
+
SchedulerHAConfig: {
|
|
13528
|
+
type: "object",
|
|
13529
|
+
properties: {
|
|
13530
|
+
enabled: {
|
|
13531
|
+
type: "boolean",
|
|
13532
|
+
description: "Enable distributed locking for multi-node deployments (default: false)"
|
|
13533
|
+
},
|
|
13534
|
+
node_id: {
|
|
13535
|
+
type: "string",
|
|
13536
|
+
description: "Unique node identifier (default: hostname-pid)"
|
|
13537
|
+
},
|
|
13538
|
+
lock_ttl: {
|
|
13539
|
+
type: "number",
|
|
13540
|
+
description: "Lock time-to-live in seconds (default: 60)"
|
|
13541
|
+
},
|
|
13542
|
+
heartbeat_interval: {
|
|
13543
|
+
type: "number",
|
|
13544
|
+
description: "Heartbeat interval for lock renewal in seconds (default: 15)"
|
|
13545
|
+
}
|
|
13546
|
+
},
|
|
13547
|
+
additionalProperties: false,
|
|
13548
|
+
description: "Scheduler high-availability configuration",
|
|
13180
13549
|
patternProperties: {
|
|
13181
13550
|
"^x-": {}
|
|
13182
13551
|
}
|
|
@@ -13239,45 +13608,6 @@ var init_config_schema = __esm({
|
|
|
13239
13608
|
"^x-": {}
|
|
13240
13609
|
}
|
|
13241
13610
|
},
|
|
13242
|
-
PolicyRoleConfig: {
|
|
13243
|
-
type: "object",
|
|
13244
|
-
properties: {
|
|
13245
|
-
author_association: {
|
|
13246
|
-
type: "array",
|
|
13247
|
-
items: { type: "string" },
|
|
13248
|
-
description: "GitHub author associations that map to this role"
|
|
13249
|
-
},
|
|
13250
|
-
teams: {
|
|
13251
|
-
type: "array",
|
|
13252
|
-
items: { type: "string" },
|
|
13253
|
-
description: "GitHub team slugs"
|
|
13254
|
-
},
|
|
13255
|
-
users: {
|
|
13256
|
-
type: "array",
|
|
13257
|
-
items: { type: "string" },
|
|
13258
|
-
description: "Explicit GitHub usernames"
|
|
13259
|
-
},
|
|
13260
|
-
slack_users: {
|
|
13261
|
-
type: "array",
|
|
13262
|
-
items: { type: "string" },
|
|
13263
|
-
description: "Slack user IDs (e.g., U0123ABC)"
|
|
13264
|
-
},
|
|
13265
|
-
emails: {
|
|
13266
|
-
type: "array",
|
|
13267
|
-
items: { type: "string" },
|
|
13268
|
-
description: "Email addresses for identity matching"
|
|
13269
|
-
},
|
|
13270
|
-
slack_channels: {
|
|
13271
|
-
type: "array",
|
|
13272
|
-
items: { type: "string" },
|
|
13273
|
-
description: "Slack channel IDs \u2014 role only applies when triggered from these channels"
|
|
13274
|
-
}
|
|
13275
|
-
},
|
|
13276
|
-
additionalProperties: false,
|
|
13277
|
-
patternProperties: {
|
|
13278
|
-
"^x-": {}
|
|
13279
|
-
}
|
|
13280
|
-
},
|
|
13281
13611
|
"Record<string,StaticCronJob>": {
|
|
13282
13612
|
type: "object",
|
|
13283
13613
|
additionalProperties: {
|
|
@@ -13343,21 +13673,106 @@ var init_config_schema = __esm({
|
|
|
13343
13673
|
"^x-": {}
|
|
13344
13674
|
}
|
|
13345
13675
|
},
|
|
13346
|
-
|
|
13676
|
+
PolicyConfig: {
|
|
13347
13677
|
type: "object",
|
|
13348
13678
|
properties: {
|
|
13349
|
-
|
|
13350
|
-
|
|
13351
|
-
|
|
13679
|
+
engine: {
|
|
13680
|
+
type: "string",
|
|
13681
|
+
enum: ["local", "remote", "disabled"],
|
|
13682
|
+
description: "Policy engine mode"
|
|
13352
13683
|
},
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
13356
|
-
|
|
13684
|
+
rules: {
|
|
13685
|
+
anyOf: [
|
|
13686
|
+
{
|
|
13687
|
+
type: "string"
|
|
13688
|
+
},
|
|
13689
|
+
{
|
|
13690
|
+
type: "array",
|
|
13691
|
+
items: {
|
|
13692
|
+
type: "string"
|
|
13693
|
+
}
|
|
13694
|
+
}
|
|
13695
|
+
],
|
|
13696
|
+
description: "Path to .rego files or .wasm bundle (local mode)"
|
|
13357
13697
|
},
|
|
13358
|
-
|
|
13698
|
+
data: {
|
|
13359
13699
|
type: "string",
|
|
13360
|
-
description: "
|
|
13700
|
+
description: "Path to a JSON file to load as OPA data document"
|
|
13701
|
+
},
|
|
13702
|
+
url: {
|
|
13703
|
+
type: "string",
|
|
13704
|
+
description: "OPA server URL (remote mode)"
|
|
13705
|
+
},
|
|
13706
|
+
fallback: {
|
|
13707
|
+
type: "string",
|
|
13708
|
+
enum: ["allow", "deny", "warn"],
|
|
13709
|
+
description: "Default decision when policy evaluation fails"
|
|
13710
|
+
},
|
|
13711
|
+
timeout: {
|
|
13712
|
+
type: "number",
|
|
13713
|
+
description: "Evaluation timeout in ms (default: 5000)"
|
|
13714
|
+
},
|
|
13715
|
+
roles: {
|
|
13716
|
+
$ref: "#/definitions/Record%3Cstring%2CPolicyRoleConfig%3E",
|
|
13717
|
+
description: "Role definitions: map role names to conditions"
|
|
13718
|
+
}
|
|
13719
|
+
},
|
|
13720
|
+
required: ["engine"],
|
|
13721
|
+
additionalProperties: false,
|
|
13722
|
+
patternProperties: {
|
|
13723
|
+
"^x-": {}
|
|
13724
|
+
}
|
|
13725
|
+
},
|
|
13726
|
+
"Record<string,PolicyRoleConfig>": {
|
|
13727
|
+
type: "object",
|
|
13728
|
+
additionalProperties: {
|
|
13729
|
+
$ref: "#/definitions/PolicyRoleConfig"
|
|
13730
|
+
}
|
|
13731
|
+
},
|
|
13732
|
+
PolicyRoleConfig: {
|
|
13733
|
+
type: "object",
|
|
13734
|
+
properties: {
|
|
13735
|
+
author_association: {
|
|
13736
|
+
type: "array",
|
|
13737
|
+
items: {
|
|
13738
|
+
type: "string"
|
|
13739
|
+
},
|
|
13740
|
+
description: "GitHub author associations that map to this role"
|
|
13741
|
+
},
|
|
13742
|
+
teams: {
|
|
13743
|
+
type: "array",
|
|
13744
|
+
items: {
|
|
13745
|
+
type: "string"
|
|
13746
|
+
},
|
|
13747
|
+
description: "GitHub team slugs (requires GitHub API)"
|
|
13748
|
+
},
|
|
13749
|
+
users: {
|
|
13750
|
+
type: "array",
|
|
13751
|
+
items: {
|
|
13752
|
+
type: "string"
|
|
13753
|
+
},
|
|
13754
|
+
description: "Explicit GitHub usernames"
|
|
13755
|
+
},
|
|
13756
|
+
slack_users: {
|
|
13757
|
+
type: "array",
|
|
13758
|
+
items: {
|
|
13759
|
+
type: "string"
|
|
13760
|
+
},
|
|
13761
|
+
description: 'Slack user IDs (e.g., ["U0123ABC"])'
|
|
13762
|
+
},
|
|
13763
|
+
emails: {
|
|
13764
|
+
type: "array",
|
|
13765
|
+
items: {
|
|
13766
|
+
type: "string"
|
|
13767
|
+
},
|
|
13768
|
+
description: 'Email addresses for identity matching (e.g., ["alice@co.com"])'
|
|
13769
|
+
},
|
|
13770
|
+
slack_channels: {
|
|
13771
|
+
type: "array",
|
|
13772
|
+
items: {
|
|
13773
|
+
type: "string"
|
|
13774
|
+
},
|
|
13775
|
+
description: "Slack channel IDs \u2014 role only applies when triggered from these channels"
|
|
13361
13776
|
}
|
|
13362
13777
|
},
|
|
13363
13778
|
additionalProperties: false,
|
|
@@ -15517,6 +15932,20 @@ var init_workflow_check_provider = __esm({
|
|
|
15517
15932
|
`[WorkflowProvider] Workflow '${workflow.id}' has null/undefined outputs: [${nullOutputs.join(", ")}]. This may indicate value_js expressions are not finding expected data.`
|
|
15518
15933
|
);
|
|
15519
15934
|
}
|
|
15935
|
+
if (!outputs._rawOutput) {
|
|
15936
|
+
const rawParts = [];
|
|
15937
|
+
for (const stepOutput of Object.values(outputsMap)) {
|
|
15938
|
+
if (stepOutput && typeof stepOutput === "object" && typeof stepOutput._rawOutput === "string") {
|
|
15939
|
+
rawParts.push(stepOutput._rawOutput);
|
|
15940
|
+
}
|
|
15941
|
+
}
|
|
15942
|
+
if (rawParts.length > 0) {
|
|
15943
|
+
outputs._rawOutput = rawParts.join("\n\n");
|
|
15944
|
+
logger.debug(
|
|
15945
|
+
`[WorkflowProvider] Propagated _rawOutput from steps (${rawParts.length} blocks, ${outputs._rawOutput.length} chars)`
|
|
15946
|
+
);
|
|
15947
|
+
}
|
|
15948
|
+
}
|
|
15520
15949
|
return outputs;
|
|
15521
15950
|
}
|
|
15522
15951
|
/**
|
|
@@ -15689,7 +16118,7 @@ function workflowInputsToJsonSchema(inputs) {
|
|
|
15689
16118
|
required: required.length > 0 ? required : void 0
|
|
15690
16119
|
};
|
|
15691
16120
|
}
|
|
15692
|
-
function createWorkflowToolDefinition(workflow, argsOverrides) {
|
|
16121
|
+
function createWorkflowToolDefinition(workflow, argsOverrides, nameOverride) {
|
|
15693
16122
|
const baseSchema = workflowInputsToJsonSchema(workflow.inputs);
|
|
15694
16123
|
let inputSchema = baseSchema;
|
|
15695
16124
|
if (argsOverrides && baseSchema && typeof baseSchema === "object") {
|
|
@@ -15707,7 +16136,7 @@ function createWorkflowToolDefinition(workflow, argsOverrides) {
|
|
|
15707
16136
|
};
|
|
15708
16137
|
}
|
|
15709
16138
|
return {
|
|
15710
|
-
name: workflow.id,
|
|
16139
|
+
name: nameOverride || workflow.id,
|
|
15711
16140
|
description: workflow.description || `Execute the ${workflow.name} workflow`,
|
|
15712
16141
|
inputSchema,
|
|
15713
16142
|
// Workflow tools don't have an exec command - they're executed specially
|
|
@@ -15757,6 +16186,16 @@ async function executeWorkflowAsTool(workflowId, args, context2, argsOverrides)
|
|
|
15757
16186
|
);
|
|
15758
16187
|
logger.debug(`[WorkflowToolExecutor] Workflow '${workflowId}' output preview: ${outputPreview}`);
|
|
15759
16188
|
if (output !== void 0) {
|
|
16189
|
+
if (output && typeof output === "object" && typeof output._rawOutput === "string") {
|
|
16190
|
+
const rawOutput = output._rawOutput;
|
|
16191
|
+
const cleanOutput = { ...output };
|
|
16192
|
+
delete cleanOutput._rawOutput;
|
|
16193
|
+
const jsonStr = JSON.stringify(cleanOutput, null, 2);
|
|
16194
|
+
logger.debug(
|
|
16195
|
+
`[WorkflowToolExecutor] Wrapping _rawOutput (${rawOutput.length} chars) in RAW_OUTPUT delimiters for '${workflowId}'`
|
|
16196
|
+
);
|
|
16197
|
+
return jsonStr + "\n<<<RAW_OUTPUT>>>\n" + rawOutput + "\n<<<END_RAW_OUTPUT>>>";
|
|
16198
|
+
}
|
|
15760
16199
|
return output;
|
|
15761
16200
|
}
|
|
15762
16201
|
if (result.content) {
|
|
@@ -15781,7 +16220,7 @@ function resolveWorkflowToolFromItem(item) {
|
|
|
15781
16220
|
logger.warn(`[WorkflowToolExecutor] Workflow '${item.workflow}' not found in registry`);
|
|
15782
16221
|
return void 0;
|
|
15783
16222
|
}
|
|
15784
|
-
return createWorkflowToolDefinition(workflow, item.args);
|
|
16223
|
+
return createWorkflowToolDefinition(workflow, item.args, item.name);
|
|
15785
16224
|
}
|
|
15786
16225
|
return void 0;
|
|
15787
16226
|
}
|
|
@@ -18162,7 +18601,7 @@ var init_ai_check_provider = __esm({
|
|
|
18162
18601
|
init_sandbox();
|
|
18163
18602
|
init_schedule_tool();
|
|
18164
18603
|
init_schedule_tool_handler();
|
|
18165
|
-
AICheckProvider = class extends CheckProvider {
|
|
18604
|
+
AICheckProvider = class _AICheckProvider extends CheckProvider {
|
|
18166
18605
|
aiReviewService;
|
|
18167
18606
|
liquidEngine;
|
|
18168
18607
|
sandbox = null;
|
|
@@ -18744,6 +19183,9 @@ ${preview}`);
|
|
|
18744
19183
|
if (aiAny2.enableTasks !== void 0) {
|
|
18745
19184
|
aiConfig.enableTasks = aiAny2.enableTasks;
|
|
18746
19185
|
}
|
|
19186
|
+
if (aiAny2.enableExecutePlan !== void 0) {
|
|
19187
|
+
aiConfig.enableExecutePlan = aiAny2.enableExecutePlan;
|
|
19188
|
+
}
|
|
18747
19189
|
if (aiAny2.allowEdit !== void 0) {
|
|
18748
19190
|
aiConfig.allowEdit = aiAny2.allowEdit;
|
|
18749
19191
|
}
|
|
@@ -18889,13 +19331,10 @@ ${preview}`);
|
|
|
18889
19331
|
if (decision.capabilities.allowEdit === false) aiConfig.allowEdit = false;
|
|
18890
19332
|
if (decision.capabilities.allowBash === false) aiConfig.allowBash = false;
|
|
18891
19333
|
if (decision.capabilities.allowedTools) {
|
|
18892
|
-
|
|
18893
|
-
aiConfig.allowedTools
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
} else {
|
|
18897
|
-
aiConfig.allowedTools = decision.capabilities.allowedTools;
|
|
18898
|
-
}
|
|
19334
|
+
aiConfig.allowedTools = _AICheckProvider.intersectAllowedTools(
|
|
19335
|
+
aiConfig.allowedTools,
|
|
19336
|
+
decision.capabilities.allowedTools
|
|
19337
|
+
);
|
|
18899
19338
|
}
|
|
18900
19339
|
}
|
|
18901
19340
|
} catch (err) {
|
|
@@ -19016,7 +19455,8 @@ ${preview}`);
|
|
|
19016
19455
|
if (cfg.workflow && typeof cfg.workflow === "string") {
|
|
19017
19456
|
workflowEntriesFromMcp.push({
|
|
19018
19457
|
workflow: cfg.workflow,
|
|
19019
|
-
args: cfg.inputs
|
|
19458
|
+
args: cfg.inputs,
|
|
19459
|
+
name: serverName
|
|
19020
19460
|
});
|
|
19021
19461
|
mcpEntriesToRemove.push(serverName);
|
|
19022
19462
|
logger.debug(
|
|
@@ -19157,6 +19597,27 @@ ${preview}`);
|
|
|
19157
19597
|
);
|
|
19158
19598
|
}
|
|
19159
19599
|
}
|
|
19600
|
+
const allowedToolsJsExpr = config.ai_allowed_tools_js;
|
|
19601
|
+
if (allowedToolsJsExpr && _dependencyResults) {
|
|
19602
|
+
try {
|
|
19603
|
+
const dynamicAllowedTools = this.evaluateAllowedToolsJs(
|
|
19604
|
+
allowedToolsJsExpr,
|
|
19605
|
+
prInfo,
|
|
19606
|
+
_dependencyResults,
|
|
19607
|
+
config
|
|
19608
|
+
);
|
|
19609
|
+
if (dynamicAllowedTools !== null) {
|
|
19610
|
+
aiConfig.allowedTools = dynamicAllowedTools;
|
|
19611
|
+
this.logDebug(
|
|
19612
|
+
`[AI Provider] ai_allowed_tools_js evaluated to: ${JSON.stringify(dynamicAllowedTools)}`
|
|
19613
|
+
);
|
|
19614
|
+
}
|
|
19615
|
+
} catch (error) {
|
|
19616
|
+
logger.error(
|
|
19617
|
+
`[AICheckProvider] Failed to evaluate ai_allowed_tools_js: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
19618
|
+
);
|
|
19619
|
+
}
|
|
19620
|
+
}
|
|
19160
19621
|
const templateContext = {
|
|
19161
19622
|
pr: {
|
|
19162
19623
|
number: prInfo.number,
|
|
@@ -19660,6 +20121,65 @@ ${processedPrompt}` : processedPrompt;
|
|
|
19660
20121
|
return {};
|
|
19661
20122
|
}
|
|
19662
20123
|
}
|
|
20124
|
+
/**
|
|
20125
|
+
* Evaluate ai_allowed_tools_js expression to dynamically compute allowed tools list.
|
|
20126
|
+
* Returns a string array of tool names, or null if the expression returns a non-array.
|
|
20127
|
+
*/
|
|
20128
|
+
evaluateAllowedToolsJs(expression, prInfo, dependencyResults, config) {
|
|
20129
|
+
if (!this.sandbox) {
|
|
20130
|
+
this.sandbox = createSecureSandbox();
|
|
20131
|
+
}
|
|
20132
|
+
const outputs = {};
|
|
20133
|
+
for (const [checkId, result] of dependencyResults.entries()) {
|
|
20134
|
+
const summary = result;
|
|
20135
|
+
outputs[checkId] = summary.output !== void 0 ? summary.output : summary;
|
|
20136
|
+
}
|
|
20137
|
+
const jsContext = {
|
|
20138
|
+
outputs,
|
|
20139
|
+
inputs: config.inputs || {},
|
|
20140
|
+
pr: {
|
|
20141
|
+
number: prInfo.number,
|
|
20142
|
+
title: prInfo.title,
|
|
20143
|
+
description: prInfo.body,
|
|
20144
|
+
author: prInfo.author,
|
|
20145
|
+
branch: prInfo.head,
|
|
20146
|
+
base: prInfo.base,
|
|
20147
|
+
authorAssociation: prInfo.authorAssociation
|
|
20148
|
+
},
|
|
20149
|
+
files: prInfo.files?.map((f) => ({
|
|
20150
|
+
filename: f.filename,
|
|
20151
|
+
status: f.status,
|
|
20152
|
+
additions: f.additions,
|
|
20153
|
+
deletions: f.deletions,
|
|
20154
|
+
changes: f.changes
|
|
20155
|
+
})) || [],
|
|
20156
|
+
env: this.buildSafeEnv(),
|
|
20157
|
+
memory: config.__memoryAccessor || {}
|
|
20158
|
+
};
|
|
20159
|
+
try {
|
|
20160
|
+
const result = compileAndRun(this.sandbox, expression, jsContext, {
|
|
20161
|
+
injectLog: true,
|
|
20162
|
+
wrapFunction: true,
|
|
20163
|
+
logPrefix: "[ai_allowed_tools_js]"
|
|
20164
|
+
});
|
|
20165
|
+
if (!Array.isArray(result)) {
|
|
20166
|
+
logger.warn(
|
|
20167
|
+
`[AICheckProvider] ai_allowed_tools_js must return an array, got ${typeof result}`
|
|
20168
|
+
);
|
|
20169
|
+
return null;
|
|
20170
|
+
}
|
|
20171
|
+
const tools = result.filter((item) => typeof item === "string");
|
|
20172
|
+
logger.debug(
|
|
20173
|
+
`[AICheckProvider] ai_allowed_tools_js evaluated to ${tools.length} tools: ${tools.join(", ")}`
|
|
20174
|
+
);
|
|
20175
|
+
return tools;
|
|
20176
|
+
} catch (error) {
|
|
20177
|
+
logger.error(
|
|
20178
|
+
`[AICheckProvider] Failed to evaluate ai_allowed_tools_js: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
20179
|
+
);
|
|
20180
|
+
return null;
|
|
20181
|
+
}
|
|
20182
|
+
}
|
|
19663
20183
|
/**
|
|
19664
20184
|
* Build a safe subset of environment variables for sandbox access.
|
|
19665
20185
|
* Excludes sensitive keys like API keys, secrets, tokens.
|
|
@@ -19721,6 +20241,22 @@ ${processedPrompt}` : processedPrompt;
|
|
|
19721
20241
|
}
|
|
19722
20242
|
return tools;
|
|
19723
20243
|
}
|
|
20244
|
+
/**
|
|
20245
|
+
* Intersect config-level allowedTools with policy-level allowedTools.
|
|
20246
|
+
* When the config list contains glob patterns ("*", "!" exclusions),
|
|
20247
|
+
* it is passed through unchanged — ProbeAgent resolves those patterns.
|
|
20248
|
+
* Literal tool name lists are intersected normally.
|
|
20249
|
+
*/
|
|
20250
|
+
static intersectAllowedTools(configTools, policyTools) {
|
|
20251
|
+
if (!configTools) {
|
|
20252
|
+
return policyTools;
|
|
20253
|
+
}
|
|
20254
|
+
const hasGlobs = configTools.some((t) => t === "*" || t.startsWith("!"));
|
|
20255
|
+
if (hasGlobs) {
|
|
20256
|
+
return configTools;
|
|
20257
|
+
}
|
|
20258
|
+
return configTools.filter((t) => policyTools.includes(t));
|
|
20259
|
+
}
|
|
19724
20260
|
getSupportedConfigKeys() {
|
|
19725
20261
|
return [
|
|
19726
20262
|
"type",
|
|
@@ -19736,6 +20272,7 @@ ${processedPrompt}` : processedPrompt;
|
|
|
19736
20272
|
"ai.mcpServers",
|
|
19737
20273
|
"ai.enableDelegate",
|
|
19738
20274
|
"ai.enableTasks",
|
|
20275
|
+
"ai.enableExecutePlan",
|
|
19739
20276
|
// legacy persona/prompt keys supported in config
|
|
19740
20277
|
"ai_persona",
|
|
19741
20278
|
"ai_prompt_type",
|
|
@@ -19757,6 +20294,7 @@ ${processedPrompt}` : processedPrompt;
|
|
|
19757
20294
|
"ai_custom_tools",
|
|
19758
20295
|
"ai_custom_tools_js",
|
|
19759
20296
|
"ai_bash_config_js",
|
|
20297
|
+
"ai_allowed_tools_js",
|
|
19760
20298
|
"env"
|
|
19761
20299
|
];
|
|
19762
20300
|
}
|
|
@@ -47344,7 +47882,7 @@ async function renderTemplateContent2(checkId, checkConfig, reviewSummary) {
|
|
|
47344
47882
|
const fs21 = await import("fs/promises");
|
|
47345
47883
|
const path25 = await import("path");
|
|
47346
47884
|
const schemaRaw = checkConfig.schema || "plain";
|
|
47347
|
-
const schema = typeof schemaRaw === "string" ? schemaRaw : "code-review";
|
|
47885
|
+
const schema = typeof schemaRaw === "string" && !schemaRaw.includes("{{") && !schemaRaw.includes("{%") ? schemaRaw : typeof schemaRaw === "object" ? "code-review" : "plain";
|
|
47348
47886
|
let templateContent;
|
|
47349
47887
|
if (checkConfig.template && checkConfig.template.content) {
|
|
47350
47888
|
templateContent = String(checkConfig.template.content);
|
|
@@ -51281,7 +51819,8 @@ var init_client = __esm({
|
|
|
51281
51819
|
user: m.user,
|
|
51282
51820
|
text: m.text,
|
|
51283
51821
|
bot_id: m.bot_id,
|
|
51284
|
-
thread_ts: m.thread_ts
|
|
51822
|
+
thread_ts: m.thread_ts,
|
|
51823
|
+
files: Array.isArray(m.files) ? m.files : void 0
|
|
51285
51824
|
}));
|
|
51286
51825
|
} catch (e) {
|
|
51287
51826
|
console.warn(
|
|
@@ -51304,9 +51843,9 @@ var init_client = __esm({
|
|
|
51304
51843
|
initial_comment
|
|
51305
51844
|
}) => {
|
|
51306
51845
|
try {
|
|
51307
|
-
const getUrlResp = await this.
|
|
51846
|
+
const getUrlResp = await this.apiForm("files.getUploadURLExternal", {
|
|
51308
51847
|
filename,
|
|
51309
|
-
length: content.length
|
|
51848
|
+
length: String(content.length)
|
|
51310
51849
|
});
|
|
51311
51850
|
if (!getUrlResp || getUrlResp.ok !== true || !getUrlResp.upload_url) {
|
|
51312
51851
|
console.warn(
|
|
@@ -51364,6 +51903,19 @@ var init_client = __esm({
|
|
|
51364
51903
|
});
|
|
51365
51904
|
return await res.json();
|
|
51366
51905
|
}
|
|
51906
|
+
/** Send a Slack API request as application/x-www-form-urlencoded (required by some file methods). */
|
|
51907
|
+
async apiForm(method, params) {
|
|
51908
|
+
const body = new URLSearchParams(params);
|
|
51909
|
+
const res = await fetch(`https://slack.com/api/${method}`, {
|
|
51910
|
+
method: "POST",
|
|
51911
|
+
headers: {
|
|
51912
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
51913
|
+
Authorization: `Bearer ${this.token}`
|
|
51914
|
+
},
|
|
51915
|
+
body: body.toString()
|
|
51916
|
+
});
|
|
51917
|
+
return await res.json();
|
|
51918
|
+
}
|
|
51367
51919
|
};
|
|
51368
51920
|
}
|
|
51369
51921
|
});
|
|
@@ -51528,6 +52080,47 @@ function markdownToSlack(text) {
|
|
|
51528
52080
|
out = lines.join("\n");
|
|
51529
52081
|
return out;
|
|
51530
52082
|
}
|
|
52083
|
+
function extractFileSections(text) {
|
|
52084
|
+
const sections = [];
|
|
52085
|
+
const delimRegex = /^--- ([\w][\w.\-]*\.\w+) ---$/gm;
|
|
52086
|
+
const delimiters = [];
|
|
52087
|
+
let m;
|
|
52088
|
+
while ((m = delimRegex.exec(text)) !== null) {
|
|
52089
|
+
delimiters.push({
|
|
52090
|
+
filename: m[1],
|
|
52091
|
+
start: m.index,
|
|
52092
|
+
end: m.index + m[0].length
|
|
52093
|
+
});
|
|
52094
|
+
}
|
|
52095
|
+
if (delimiters.length === 0) return sections;
|
|
52096
|
+
for (let i = 0; i < delimiters.length; i++) {
|
|
52097
|
+
const open = delimiters[i];
|
|
52098
|
+
const contentStart = open.end < text.length && text[open.end] === "\n" ? open.end + 1 : open.end;
|
|
52099
|
+
const sectionEnd = i + 1 < delimiters.length ? delimiters[i + 1].start : text.length;
|
|
52100
|
+
const content = text.substring(contentStart, sectionEnd).trim();
|
|
52101
|
+
if (content.length > 0) {
|
|
52102
|
+
sections.push({
|
|
52103
|
+
fullMatch: text.substring(open.start, sectionEnd),
|
|
52104
|
+
filename: open.filename,
|
|
52105
|
+
content,
|
|
52106
|
+
startIndex: open.start,
|
|
52107
|
+
endIndex: sectionEnd
|
|
52108
|
+
});
|
|
52109
|
+
}
|
|
52110
|
+
}
|
|
52111
|
+
return sections;
|
|
52112
|
+
}
|
|
52113
|
+
function replaceFileSections(text, sections, replacement = (idx) => `_(See file: ${sections[idx].filename} above)_`) {
|
|
52114
|
+
if (sections.length === 0) return text;
|
|
52115
|
+
const sorted = [...sections].sort((a, b) => b.startIndex - a.startIndex);
|
|
52116
|
+
let result = text;
|
|
52117
|
+
sorted.forEach((section, sortedIndex) => {
|
|
52118
|
+
const originalIndex = sections.length - 1 - sortedIndex;
|
|
52119
|
+
const rep = typeof replacement === "function" ? replacement(originalIndex) : replacement;
|
|
52120
|
+
result = result.slice(0, section.startIndex) + rep + result.slice(section.endIndex);
|
|
52121
|
+
});
|
|
52122
|
+
return result;
|
|
52123
|
+
}
|
|
51531
52124
|
function formatSlackText(text) {
|
|
51532
52125
|
return markdownToSlack(text);
|
|
51533
52126
|
}
|
|
@@ -51956,6 +52549,9 @@ ${message}`;
|
|
|
51956
52549
|
text = String(out);
|
|
51957
52550
|
}
|
|
51958
52551
|
}
|
|
52552
|
+
if (out && typeof out._rawOutput === "string" && out._rawOutput.trim().length > 0) {
|
|
52553
|
+
text = (text || "") + "\n\n" + out._rawOutput.trim();
|
|
52554
|
+
}
|
|
51959
52555
|
if (!text) {
|
|
51960
52556
|
ctx.logger.info(
|
|
51961
52557
|
`[slack-frontend] skip posting AI reply for ${checkId}: no renderable text in check output`
|
|
@@ -52014,6 +52610,39 @@ ${message}`;
|
|
|
52014
52610
|
);
|
|
52015
52611
|
}
|
|
52016
52612
|
}
|
|
52613
|
+
processedText = processedText.replace(/\\n/g, "\n");
|
|
52614
|
+
const fileSections = extractFileSections(processedText);
|
|
52615
|
+
if (fileSections.length > 0) {
|
|
52616
|
+
const uploadedFileIndices = [];
|
|
52617
|
+
for (let i = 0; i < fileSections.length; i++) {
|
|
52618
|
+
const section = fileSections[i];
|
|
52619
|
+
try {
|
|
52620
|
+
const buffer = Buffer.from(section.content, "utf-8");
|
|
52621
|
+
const uploadResult = await slack.files.uploadV2({
|
|
52622
|
+
content: buffer,
|
|
52623
|
+
filename: section.filename,
|
|
52624
|
+
channel,
|
|
52625
|
+
thread_ts: threadTs,
|
|
52626
|
+
title: section.filename
|
|
52627
|
+
});
|
|
52628
|
+
if (uploadResult.ok) {
|
|
52629
|
+
uploadedFileIndices.push(i);
|
|
52630
|
+
ctx.logger.info(`[slack-frontend] uploaded file ${section.filename} to ${channel}`);
|
|
52631
|
+
} else {
|
|
52632
|
+
ctx.logger.warn(`[slack-frontend] upload failed for file ${section.filename}`);
|
|
52633
|
+
}
|
|
52634
|
+
} catch (e) {
|
|
52635
|
+
ctx.logger.warn(
|
|
52636
|
+
`[slack-frontend] failed to upload file ${section.filename}: ${e instanceof Error ? e.message : String(e)}`
|
|
52637
|
+
);
|
|
52638
|
+
}
|
|
52639
|
+
}
|
|
52640
|
+
processedText = replaceFileSections(
|
|
52641
|
+
processedText,
|
|
52642
|
+
fileSections,
|
|
52643
|
+
(idx) => uploadedFileIndices.includes(idx) ? `_(See file: ${fileSections[idx].filename} above)_` : `_(File upload failed: ${fileSections[idx].filename})_`
|
|
52644
|
+
);
|
|
52645
|
+
}
|
|
52017
52646
|
let decoratedText = processedText;
|
|
52018
52647
|
const telemetryEnabled = telemetryCfg === true || telemetryCfg && typeof telemetryCfg === "object" && telemetryCfg.enabled === true;
|
|
52019
52648
|
if (telemetryEnabled) {
|